Make getMenu non-final
[sw/motorsim] / gui / com / billkuker / rocketry / motorsim / visual / MultiObjectEditor.java
1 package com.billkuker.rocketry.motorsim.visual;\r
2 import java.awt.Component;\r
3 import java.awt.FileDialog;\r
4 import java.awt.Frame;\r
5 import java.awt.event.ActionEvent;\r
6 import java.awt.event.ActionListener;\r
7 import java.io.File;\r
8 import java.io.IOException;\r
9 import java.util.HashMap;\r
10 import java.util.HashSet;\r
11 import java.util.List;\r
12 import java.util.Map;\r
13 import java.util.Set;\r
14 import java.util.Vector;\r
15 \r
16 import javax.swing.JMenu;\r
17 import javax.swing.JMenuItem;\r
18 import javax.swing.JOptionPane;\r
19 import javax.swing.JTabbedPane;\r
20 \r
21 import org.apache.log4j.Logger;\r
22 \r
23 \r
24 public abstract class MultiObjectEditor<OBJECT, EDITOR extends Component> extends JTabbedPane {\r
25 \r
26         private static final long serialVersionUID = 1L;\r
27 \r
28         private static final Logger log = Logger.getLogger(MultiObjectEditor.class);\r
29         \r
30         protected abstract class ObjectCreator {\r
31                 public abstract OBJECT newObject();\r
32                 public abstract String getName();\r
33         }\r
34         \r
35         private final Frame frame;\r
36         \r
37         private final String noun;\r
38         \r
39         private List<ObjectCreator> creators = new Vector<ObjectCreator>();\r
40         \r
41         private final Map<OBJECT, EDITOR> objectToEditor = new HashMap<OBJECT, EDITOR>();\r
42         private final Map<EDITOR, OBJECT> editorToObject = new HashMap<EDITOR, OBJECT>();\r
43         private final Map<File, EDITOR> fileToEditor = new HashMap<File, EDITOR>();\r
44         private final Map<EDITOR, File> editorToFile = new HashMap<EDITOR, File>();\r
45         \r
46         \r
47         private final Set<OBJECT> dirty = new HashSet<OBJECT>();\r
48         \r
49         public MultiObjectEditor(final Frame frame, final String noun){\r
50                 this.frame = frame;\r
51                 this.noun = " " + noun.trim();\r
52         }\r
53         \r
54         protected final void addCreator(ObjectCreator c){\r
55                 creators.add(c);\r
56         }\r
57         \r
58         public final void dirty(final OBJECT o){\r
59                 if ( !dirty.contains(o) )\r
60                         setTitleAt(indexOfComponent(objectToEditor.get(o)), "*" + getTitleAt(indexOfComponent(objectToEditor.get(o))));\r
61                 dirty.add(o);\r
62         }\r
63         \r
64         public final void dirty(final EDITOR e){\r
65                 dirty(editorToObject.get(e));\r
66         }\r
67         \r
68         private final void undirty(final OBJECT o){\r
69                 if ( dirty.contains(o) )\r
70                         setTitleAt(indexOfComponent(objectToEditor.get(o)), getTitleAt(indexOfComponent(objectToEditor.get(o))).replaceAll("^\\*", ""));\r
71                 dirty.remove(o);\r
72         }\r
73         \r
74         public JMenu getMenu(){\r
75                 JMenu ret = new JMenu("File");\r
76                 for ( JMenuItem i : getMenuItems() )\r
77                         ret.add(i);\r
78                 return ret;\r
79         }\r
80         \r
81         private void menuNew(ObjectCreator c){\r
82                 add(c.newObject());\r
83         }\r
84         \r
85         @SuppressWarnings("unchecked")\r
86         public EDITOR getSelectedEditor(){\r
87                 try {\r
88                         return (EDITOR)super.getSelectedComponent();\r
89                 } catch ( ClassCastException e ){\r
90                         return null;\r
91                 }\r
92         }\r
93         \r
94         private void close(){\r
95                 EDITOR e = getSelectedEditor();\r
96                 OBJECT o = editorToObject.get(e);\r
97                 File f = editorToFile.get(e);\r
98                 \r
99                 if ( dirty.contains(o) ){\r
100                          int response = JOptionPane.showConfirmDialog(this, "Object is unsaved. Save Before Closing?", "Confirm", JOptionPane.YES_NO_CANCEL_OPTION);\r
101                          if ( response == JOptionPane.YES_OPTION ){\r
102                                  saveDialog();\r
103                          } else if ( response == JOptionPane.CANCEL_OPTION ){\r
104                                  return;\r
105                          }\r
106                 }\r
107                 \r
108                 objectToEditor.remove(o);\r
109                 editorToObject.remove(e);\r
110                 fileToEditor.remove(f);\r
111                 editorToFile.remove(e);\r
112                 remove(e);\r
113         }\r
114         \r
115         private void saveDialog(){\r
116                 EDITOR e = getSelectedEditor();\r
117                 if ( !editorToFile.containsKey(e) ){\r
118                         log.debug("Editor has no file, saving as...");\r
119                         saveAsDialog();\r
120                         return;\r
121                 }\r
122                 File file = editorToFile.get(e);\r
123                 log.debug("Saving to " + file.getAbsolutePath());\r
124                 try {\r
125                         saveToFile(editorToObject.get(e), file);\r
126                         undirty(editorToObject.get(e));\r
127                 } catch (IOException e1) {\r
128                         errorDialog(e1);\r
129                 }\r
130         }\r
131         private void saveAsDialog(){\r
132                 EDITOR e = getSelectedEditor();\r
133                 final FileDialog fd = new FileDialog(frame, "Save" + noun + " As", FileDialog.SAVE);\r
134                 fd.setVisible(true);\r
135                 if (fd.getFile() != null ) {\r
136                         File file = new File(fd.getDirectory() + fd.getFile());\r
137                         try {\r
138                                 OBJECT o = editorToObject.get(e);\r
139                                 saveToFile(o, file);\r
140                                 undirty(o);\r
141                                 objectToEditor.put(o, e);\r
142                                 editorToObject.put(e, o);\r
143                                 fileToEditor.put(file, e);\r
144                                 editorToFile.put(e, file);\r
145                                 setTitleAt(\r
146                                                 getSelectedIndex(),\r
147                                                 file.getName());\r
148                         } catch (Exception e1) {\r
149                                 errorDialog(e1);\r
150                         }\r
151                 }\r
152         }\r
153         \r
154         private void openDialog(){\r
155                 final FileDialog fd = new FileDialog(frame, "Open" + noun + "...", FileDialog.LOAD);\r
156                 fd.setVisible(true);\r
157                 if ( fd.getFile() != null ) {\r
158                         File file = new File(fd.getDirectory() + fd.getFile());\r
159                         log.debug("Opening File " + file.getAbsolutePath());\r
160                         if ( fileToEditor.containsKey(file) ){\r
161                                 log.debug("File " + file.getAbsolutePath() + "Already open, focusing");\r
162                                 setSelectedComponent(fileToEditor.get(file));\r
163                                 return;\r
164                         }\r
165                         try {\r
166                                 OBJECT o = loadFromFile(file);\r
167                                 EDITOR e = createEditor(o);\r
168                                 objectToEditor.put(o, e);\r
169                                 editorToObject.put(e, o);\r
170                                 fileToEditor.put(file, e);\r
171                                 editorToFile.put(e, file);\r
172                                 addTab(file.getName(), e);                                                                      \r
173                         } catch (Exception e) {\r
174                                 errorDialog(e);\r
175                         }\r
176                 }\r
177         }\r
178         \r
179         public final List<JMenuItem> getMenuItems(){\r
180                 List<JMenuItem> ret = new Vector<JMenuItem>();\r
181                 if ( creators.size() == 1 ){\r
182                         final ObjectCreator c = creators.get(0);\r
183                         ret.add(new JMenuItem("New " + c.getName()){\r
184                                 private static final long serialVersionUID = 1L;\r
185                                 {\r
186                                         addActionListener(new ActionListener() {\r
187                                                 @Override\r
188                                                 public void actionPerformed(ActionEvent ae) {\r
189                                                         log.debug("New");\r
190                                                         menuNew(c);\r
191                                                 }\r
192                                         });\r
193                                 }\r
194                         });\r
195                 } else {\r
196                         ret.add(new JMenu("New"){\r
197                                 private static final long serialVersionUID = 1L;\r
198                                 {\r
199                                         for (final ObjectCreator c : creators ){\r
200                                                 add(new JMenuItem("New " + c.getName()){\r
201                                                         private static final long serialVersionUID = 1L;\r
202                                                         {\r
203                                                                 addActionListener(new ActionListener() {\r
204                                                                         @Override\r
205                                                                         public void actionPerformed(ActionEvent ae) {\r
206                                                                                 log.debug("New");\r
207                                                                                 menuNew(c);\r
208                                                                         }\r
209                                                                 });\r
210                                                         }\r
211                                                 });\r
212                                         }\r
213                                 }\r
214                         });\r
215                 }\r
216                 ret.add(new JMenuItem("Open" + noun + "..."){\r
217                                 private static final long serialVersionUID = 1L;\r
218                                 {\r
219                                         addActionListener(new ActionListener() {\r
220                                                 @Override\r
221                                                 public void actionPerformed(ActionEvent ae) {\r
222                                                         log.debug("Open...");\r
223                                                         openDialog();\r
224                                                 }\r
225                                         });\r
226                                 }\r
227                         });\r
228                 ret.add(new JMenuItem("Close" + noun){\r
229                         private static final long serialVersionUID = 1L;\r
230                         {\r
231                                 addActionListener(new ActionListener() {\r
232                                         @Override\r
233                                         public void actionPerformed(ActionEvent ae) {\r
234                                                 log.debug("Close");\r
235                                                 close();\r
236                                         }\r
237                                 });\r
238                         }\r
239                 });\r
240                 ret.add(new JMenuItem("Save" + noun){\r
241                         private static final long serialVersionUID = 1L;\r
242                         {\r
243                                 addActionListener(new ActionListener() {\r
244                                         @Override\r
245                                         public void actionPerformed(ActionEvent ae) {\r
246                                                 log.debug("Save");\r
247                                                 saveDialog();\r
248                                         }\r
249                                 });\r
250                         }\r
251                 });\r
252                 ret.add(new JMenuItem("Save" + noun + " As..."){\r
253                         private static final long serialVersionUID = 1L;\r
254                         {\r
255                                 addActionListener(new ActionListener() {\r
256                                         @Override\r
257                                         public void actionPerformed(ActionEvent ae) {\r
258                                                 log.debug("Save As...");\r
259                                                 saveAsDialog();\r
260                                         }\r
261                                 });\r
262                         }\r
263                 });\r
264                 return ret;\r
265         }\r
266 \r
267         protected final void add(final OBJECT o){\r
268                 EDITOR e = createEditor(o);\r
269                 objectToEditor.put(o, e);\r
270                 editorToObject.put(e, o);\r
271                 addTab("new", e);\r
272                 dirty(o);\r
273         }\r
274         \r
275         public final void load(final File f) throws IOException{\r
276                 OBJECT o = loadFromFile(f);\r
277                 EDITOR e = createEditor(o);\r
278                 objectToEditor.put(o, e);\r
279                 editorToObject.put(e, o);\r
280                 fileToEditor.put(f, e);\r
281                 editorToFile.put(e, f);\r
282                 addTab(f.getName(), e);\r
283         }\r
284         \r
285         public abstract EDITOR createEditor(final OBJECT o);\r
286         \r
287         protected abstract OBJECT loadFromFile(final File f) throws IOException;\r
288         \r
289         protected abstract void saveToFile(final OBJECT o, final File f) throws IOException;\r
290 \r
291         \r
292         private final void errorDialog(final Throwable t){\r
293                 t.printStackTrace();\r
294                 JOptionPane.showMessageDialog(MultiObjectEditor.this, t.getClass().getSimpleName() + ": " + t.getMessage());\r
295         }\r
296 }\r