--- /dev/null
+package com.billkuker.rocketry.motorsim.visual;\r
+import java.awt.Component;\r
+import java.awt.FileDialog;\r
+import java.awt.Frame;\r
+import java.awt.event.ActionEvent;\r
+import java.awt.event.ActionListener;\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.Vector;\r
+\r
+import javax.swing.JMenu;\r
+import javax.swing.JMenuItem;\r
+import javax.swing.JOptionPane;\r
+import javax.swing.JTabbedPane;\r
+\r
+import org.apache.log4j.Logger;\r
+\r
+\r
+public abstract class MultiObjectEditor<OBJECT, EDITOR extends Component> extends JTabbedPane {\r
+\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ private static final Logger log = Logger.getLogger(MultiObjectEditor.class);\r
+ \r
+ private final Frame frame;\r
+ \r
+ private final String noun;\r
+ \r
+ private final Map<OBJECT, EDITOR> objectToEditor = new HashMap<OBJECT, EDITOR>();\r
+ private final Map<EDITOR, OBJECT> editorToObject = new HashMap<EDITOR, OBJECT>();\r
+ private final Map<File, EDITOR> fileToEditor = new HashMap<File, EDITOR>();\r
+ private final Map<EDITOR, File> editorToFile = new HashMap<EDITOR, File>();\r
+ \r
+ private final Set<OBJECT> dirty = new HashSet<OBJECT>();\r
+ \r
+ public MultiObjectEditor(final Frame frame, final String noun){\r
+ this.frame = frame;\r
+ this.noun = " " + noun.trim();\r
+ }\r
+ \r
+ public final void dirty(final OBJECT o){\r
+ if ( !dirty.contains(o) )\r
+ setTitleAt(indexOfComponent(objectToEditor.get(o)), "*" + getTitleAt(indexOfComponent(objectToEditor.get(o))));\r
+ dirty.add(o);\r
+ }\r
+ \r
+ public final void dirty(final EDITOR e){\r
+ dirty(editorToObject.get(e));\r
+ }\r
+ \r
+ private final void undirty(final OBJECT o){\r
+ if ( dirty.contains(o) )\r
+ setTitleAt(indexOfComponent(objectToEditor.get(o)), getTitleAt(indexOfComponent(objectToEditor.get(o))).replaceAll("^\\*", ""));\r
+ dirty.remove(o);\r
+ }\r
+ \r
+ public final JMenu getMenu(){\r
+ JMenu ret = new JMenu("File");\r
+ for ( JMenuItem i : getMenuItems() )\r
+ ret.add(i);\r
+ return ret;\r
+ }\r
+ \r
+ private void menuNew(){\r
+ add(newObject());\r
+ }\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public EDITOR getSelectedComponent(){\r
+ return (EDITOR)super.getSelectedComponent();\r
+ }\r
+ \r
+ private void close(){\r
+ EDITOR e = getSelectedComponent();\r
+ OBJECT o = editorToObject.get(e);\r
+ File f = editorToFile.get(e);\r
+ \r
+ if ( dirty.contains(o) ){\r
+ int response = JOptionPane.showConfirmDialog(this, "Object is unsaved. Save Before Closing?", "Confirm", JOptionPane.YES_NO_CANCEL_OPTION);\r
+ if ( response == JOptionPane.YES_OPTION ){\r
+ saveDialog();\r
+ } else if ( response == JOptionPane.CANCEL_OPTION ){\r
+ return;\r
+ }\r
+ }\r
+ \r
+ objectToEditor.remove(o);\r
+ editorToObject.remove(e);\r
+ fileToEditor.remove(f);\r
+ editorToFile.remove(e);\r
+ remove(e);\r
+ }\r
+ \r
+ private void saveDialog(){\r
+ EDITOR e = getSelectedComponent();\r
+ if ( !editorToFile.containsKey(e) ){\r
+ log.debug("Editor has no file, saving as...");\r
+ saveAsDialog();\r
+ return;\r
+ }\r
+ File file = editorToFile.get(e);\r
+ log.debug("Saving to " + file.getAbsolutePath());\r
+ try {\r
+ saveToFile(editorToObject.get(e), file);\r
+ undirty(editorToObject.get(e));\r
+ } catch (IOException e1) {\r
+ errorDialog(e1);\r
+ }\r
+ }\r
+ private void saveAsDialog(){\r
+ EDITOR e = getSelectedComponent();\r
+ final FileDialog fd = new FileDialog(frame, "Save" + noun + " As", FileDialog.SAVE);\r
+ fd.setVisible(true);\r
+ if (fd.getFile() != null ) {\r
+ File file = new File(fd.getDirectory() + fd.getFile());\r
+ try {\r
+ OBJECT o = editorToObject.get(e);\r
+ saveToFile(o, file);\r
+ undirty(o);\r
+ objectToEditor.put(o, e);\r
+ editorToObject.put(e, o);\r
+ fileToEditor.put(file, e);\r
+ editorToFile.put(e, file);\r
+ setTitleAt(\r
+ getSelectedIndex(),\r
+ file.getName());\r
+ } catch (Exception e1) {\r
+ errorDialog(e1);\r
+ }\r
+ }\r
+ }\r
+ \r
+ private void openDialog(){\r
+ final FileDialog fd = new FileDialog(frame, "Open" + noun + "...", FileDialog.LOAD);\r
+ fd.setVisible(true);\r
+ if ( fd.getFile() != null ) {\r
+ File file = new File(fd.getDirectory() + fd.getFile());\r
+ log.debug("Opening File " + file.getAbsolutePath());\r
+ if ( fileToEditor.containsKey(file) ){\r
+ log.debug("File " + file.getAbsolutePath() + "Already open, focusing");\r
+ setSelectedComponent(fileToEditor.get(file));\r
+ return;\r
+ }\r
+ try {\r
+ OBJECT o = loadFromFile(file);\r
+ EDITOR e = createEditor(o);\r
+ objectToEditor.put(o, e);\r
+ editorToObject.put(e, o);\r
+ fileToEditor.put(file, e);\r
+ editorToFile.put(e, file);\r
+ addTab(file.getName(), e); \r
+ } catch (Exception e) {\r
+ errorDialog(e);\r
+ }\r
+ }\r
+ }\r
+ \r
+ public final List<JMenuItem> getMenuItems(){\r
+ List<JMenuItem> ret = new Vector<JMenuItem>();\r
+ ret.add(new JMenuItem("New" + noun){\r
+ private static final long serialVersionUID = 1L;\r
+ {\r
+ addActionListener(new ActionListener() {\r
+ @Override\r
+ public void actionPerformed(ActionEvent ae) {\r
+ log.debug("New");\r
+ menuNew();\r
+ }\r
+ });\r
+ }\r
+ });\r
+ ret.add(new JMenuItem("Open" + noun + "..."){\r
+ private static final long serialVersionUID = 1L;\r
+ {\r
+ addActionListener(new ActionListener() {\r
+ @Override\r
+ public void actionPerformed(ActionEvent ae) {\r
+ log.debug("Open...");\r
+ openDialog();\r
+ }\r
+ });\r
+ }\r
+ });\r
+ ret.add(new JMenuItem("Close" + noun){\r
+ private static final long serialVersionUID = 1L;\r
+ {\r
+ addActionListener(new ActionListener() {\r
+ @Override\r
+ public void actionPerformed(ActionEvent ae) {\r
+ log.debug("Close");\r
+ close();\r
+ }\r
+ });\r
+ }\r
+ });\r
+ ret.add(new JMenuItem("Save" + noun){\r
+ private static final long serialVersionUID = 1L;\r
+ {\r
+ addActionListener(new ActionListener() {\r
+ @Override\r
+ public void actionPerformed(ActionEvent ae) {\r
+ log.debug("Save");\r
+ saveDialog();\r
+ }\r
+ });\r
+ }\r
+ });\r
+ ret.add(new JMenuItem("Save" + noun + " As..."){\r
+ private static final long serialVersionUID = 1L;\r
+ {\r
+ addActionListener(new ActionListener() {\r
+ @Override\r
+ public void actionPerformed(ActionEvent ae) {\r
+ log.debug("Save As...");\r
+ saveAsDialog();\r
+ }\r
+ });\r
+ }\r
+ });\r
+ return ret;\r
+ }\r
+\r
+ protected final void add(final OBJECT o){\r
+ EDITOR e = createEditor(o);\r
+ objectToEditor.put(o, e);\r
+ editorToObject.put(e, o);\r
+ addTab("new", e);\r
+ dirty(o);\r
+ }\r
+ \r
+ public final void load(final File f) throws IOException{\r
+ OBJECT o = loadFromFile(f);\r
+ EDITOR e = createEditor(o);\r
+ objectToEditor.put(o, e);\r
+ editorToObject.put(e, o);\r
+ fileToEditor.put(f, e);\r
+ editorToFile.put(e, f);\r
+ addTab(f.getName(), e);\r
+ }\r
+ \r
+ public abstract EDITOR createEditor(final OBJECT o);\r
+ \r
+ public abstract OBJECT newObject();\r
+ \r
+ protected abstract OBJECT loadFromFile(final File f) throws IOException;\r
+ \r
+ protected abstract void saveToFile(final OBJECT o, final File f) throws IOException;\r
+\r
+ \r
+ private final void errorDialog(final Throwable t){\r
+ t.printStackTrace();\r
+ JOptionPane.showMessageDialog(MultiObjectEditor.this, t.getClass().getSimpleName() + ": " + t.getMessage());\r
+ }\r
+}\r
--- /dev/null
+package com.billkuker.rocketry.motorsim.visual.workbench;\r
+\r
+import java.awt.Frame;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+\r
+import javax.swing.JFrame;\r
+import javax.swing.JMenuBar;\r
+\r
+import com.billkuker.rocketry.motorsim.Fuel;\r
+import com.billkuker.rocketry.motorsim.fuel.EditableFuel;\r
+import com.billkuker.rocketry.motorsim.fuel.PiecewiseLinearFuel;\r
+import com.billkuker.rocketry.motorsim.fuel.SaintRobertFuel;\r
+import com.billkuker.rocketry.motorsim.io.MotorIO;\r
+import com.billkuker.rocketry.motorsim.visual.FuelPanel;\r
+import com.billkuker.rocketry.motorsim.visual.MultiObjectEditor;\r
+import com.billkuker.rocketry.motorsim.visual.workbench.AbstractFuelEditor.EditablePSRFuel;\r
+\r
+public class FuelsEditor extends MultiObjectEditor<Fuel, AbstractFuelEditor> {\r
+\r
+ public FuelsEditor(Frame frame) {\r
+ super(frame, "Fuel");\r
+ }\r
+\r
+ @Override\r
+ public AbstractFuelEditor createEditor(Fuel o) {\r
+ if ( o instanceof PiecewiseLinearFuel ){\r
+ return new LinearFuelEditor((PiecewiseLinearFuel)o);\r
+ } else if ( o instanceof EditableFuel ){\r
+ return new SRFuelEditor(new EditablePSRFuel(SaintRobertFuel.Type.SI));\r
+ }\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public Fuel newObject() {\r
+ return new PiecewiseLinearFuel();\r
+ }\r
+\r
+ @Override\r
+ protected Fuel loadFromFile(File f) throws IOException {\r
+ return MotorIO.readFuel(new FileInputStream(f));\r
+ }\r
+\r
+ @Override\r
+ protected void saveToFile(Fuel o, File f) throws IOException {\r
+ MotorIO.writeFuel(o, new FileOutputStream(f));\r
+ }\r
+ \r
+ public static void main(String args[]){\r
+ JFrame f = new JFrame();\r
+ f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\r
+ FuelsEditor fe;\r
+ f.add(fe = new FuelsEditor(f));\r
+ JMenuBar b;\r
+ f.setJMenuBar(b = new JMenuBar());\r
+ b.add(fe.getMenu());\r
+ f.setSize(1024, 768);\r
+ f.show();\r
+ }\r
+\r
+}\r