+++ /dev/null
-package com.billkuker.rocketry.motorsim.visual;\r
-\r
-import java.awt.BorderLayout;\r
-import java.awt.event.ActionEvent;\r
-import java.awt.event.ActionListener;\r
-import java.beans.PropertyChangeEvent;\r
-import java.beans.PropertyChangeListener;\r
-import java.beans.PropertyVetoException;\r
-import java.io.IOException;\r
-\r
-import javax.measure.quantity.Pressure;\r
-import javax.measure.quantity.Velocity;\r
-import javax.measure.unit.SI;\r
-import javax.swing.BoxLayout;\r
-import javax.swing.JButton;\r
-import javax.swing.JFrame;\r
-import javax.swing.JPanel;\r
-import javax.swing.JSplitPane;\r
-import javax.swing.JTabbedPane;\r
-import javax.swing.SwingUtilities;\r
-import javax.swing.UIManager;\r
-import javax.swing.WindowConstants;\r
-import javax.swing.event.DocumentEvent;\r
-import javax.swing.event.DocumentListener;\r
-\r
-import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;\r
-import org.fife.ui.rsyntaxtextarea.SyntaxConstants;\r
-import org.jscience.physics.amount.Amount;\r
-\r
-import com.billkuker.rocketry.motorsim.Burn;\r
-import com.billkuker.rocketry.motorsim.Chamber;\r
-import com.billkuker.rocketry.motorsim.ConvergentDivergentNozzle;\r
-import com.billkuker.rocketry.motorsim.CylindricalChamber;\r
-import com.billkuker.rocketry.motorsim.Fuel;\r
-import com.billkuker.rocketry.motorsim.Grain;\r
-import com.billkuker.rocketry.motorsim.Motor;\r
-import com.billkuker.rocketry.motorsim.MotorPart;\r
-import com.billkuker.rocketry.motorsim.Nozzle;\r
-import com.billkuker.rocketry.motorsim.fuel.EditableFuel;\r
-import com.billkuker.rocketry.motorsim.fuel.KNDX;\r
-import com.billkuker.rocketry.motorsim.fuel.KNER;\r
-import com.billkuker.rocketry.motorsim.fuel.KNSB;\r
-import com.billkuker.rocketry.motorsim.fuel.KNSU;\r
-import com.billkuker.rocketry.motorsim.grain.CoredCylindricalGrain;\r
-import com.billkuker.rocketry.motorsim.grain.Finocyl;\r
-import com.billkuker.rocketry.motorsim.grain.Moonburner;\r
-import com.billkuker.rocketry.motorsim.grain.MultiGrain;\r
-import com.billkuker.rocketry.motorsim.grain.RodAndTubeGrain;\r
-import com.billkuker.rocketry.motorsim.io.MotorIO;\r
-\r
-public class MotorEditor extends JTabbedPane implements PropertyChangeListener,\r
- DocumentListener {\r
- private static final long serialVersionUID = 1L;\r
- RSyntaxTextArea text = new RSyntaxTextArea();\r
- Motor motor;\r
- GrainEditor grainEditor;\r
- BurnTab bt;\r
-\r
- private static final int XML_TAB = 0;\r
- private static final int CASING_TAB = 1;\r
- private static final int GRAIN_TAB = 2;\r
- private static final int FUEL_TAB = 3;\r
- private static final int BURN_TAB = 4;\r
-\r
- private Class[] grainTypes = { CoredCylindricalGrain.class, Finocyl.class,\r
- Moonburner.class, RodAndTubeGrain.class };\r
-\r
- private Class[] fuelTypes = { KNSB.class, KNSU.class, KNER.class,\r
- KNDX.class, EditableFuel.class };\r
-\r
- private abstract class Chooser<T> extends JPanel {\r
- private static final long serialVersionUID = 1L;\r
- private Class<? extends T>[] types;\r
-\r
- public Chooser(Class<? extends T>... ts) {\r
- types = ts;\r
- setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
- for (final Class<? extends T> c : types) {\r
- JButton b = new JButton(c.getSimpleName());\r
- add(b);\r
- b.addActionListener(new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- try {\r
- choiceMade(c.newInstance());\r
- } catch (InstantiationException e1) {\r
- e1.printStackTrace();\r
- } catch (IllegalAccessException e1) {\r
- e1.printStackTrace();\r
- }\r
- }\r
- });\r
- }\r
- }\r
-\r
- protected abstract void choiceMade(T o);\r
- }\r
-\r
- private class BurnTab extends JPanel {\r
- public BurnTab() {\r
- setLayout(new BorderLayout());\r
- setName("Burn");\r
- reBurn();\r
- }\r
-\r
- public void reBurn() {\r
- removeAll();\r
- new Thread() {\r
- public void run() {\r
- final Burn b = new Burn(motor);\r
- final BurnPanel bp = new BurnPanel(b);\r
- SwingUtilities.invokeLater(new Thread() {\r
- public void run() {\r
- add(bp, BorderLayout.CENTER);\r
- }\r
- });\r
- }\r
- }.start();\r
- }\r
- }\r
-\r
- private class GrainEditor extends JSplitPane {\r
- private static final long serialVersionUID = 1L;\r
-\r
- public GrainEditor(final Grain g) {\r
- super(JSplitPane.HORIZONTAL_SPLIT);\r
- setName("Grain");\r
- setRightComponent(new GrainPanel(g));\r
- if (g instanceof Grain.Composite) {\r
- final JPanel p = new JPanel();\r
- p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));\r
- p.add(new Editor(g));\r
- for (Grain gg : ((Grain.Composite) g).getGrains()) {\r
- final int grainEditorIndex = p.getComponentCount() + 1;\r
- p.add(new Chooser<Grain>(grainTypes) {\r
- private static final long serialVersionUID = 1L;\r
-\r
- @Override\r
- protected void choiceMade(Grain ng) {\r
- if (g instanceof MultiGrain) {\r
- ((MultiGrain) g).setGrain(ng);\r
- p.remove(grainEditorIndex);\r
- p.add(new Editor(ng), grainEditorIndex);\r
- p.remove(0);\r
- p.add(new Editor(g), 0);\r
- // System.out.println("Chose new grain");\r
- }\r
- }\r
- });\r
- p.add(new Editor(gg));\r
- if (gg instanceof MotorPart) {\r
- ((MotorPart) gg)\r
- .addPropertyChangeListener(MotorEditor.this);\r
- }\r
- }\r
- setLeftComponent(p);\r
- } else {\r
- setLeftComponent(new Editor(g));\r
- }\r
- // setDividerLocation(.25);\r
- // setResizeWeight(.25);\r
- if (g instanceof MotorPart) {\r
- ((MotorPart) g).addPropertyChangeListener(MotorEditor.this);\r
- }\r
- }\r
- }\r
-\r
- private class FuelEditor extends JSplitPane {\r
- private static final long serialVersionUID = 1L;\r
-\r
- public FuelEditor(Fuel f) {\r
- super(JSplitPane.HORIZONTAL_SPLIT);\r
- setName("Fuel");\r
- Chart<Pressure, Velocity> burnRate;\r
- try {\r
- burnRate = new Chart<Pressure, Velocity>(SI.MEGA(SI.PASCAL),\r
- SI.METERS_PER_SECOND, f, "burnRate");\r
- } catch (NoSuchMethodException e) {\r
- throw new Error(e);\r
- }\r
- burnRate.setDomain(burnRate.new IntervalDomain(Amount.valueOf(0, SI\r
- .MEGA(SI.PASCAL)), Amount.valueOf(11, SI.MEGA(SI.PASCAL)),\r
- 20));\r
-\r
- final JPanel p = new JPanel();\r
- p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));\r
-\r
- p.add(new Chooser<Fuel>(fuelTypes) {\r
- @Override\r
- protected void choiceMade(Fuel o) {\r
- motor.setFuel(o);\r
- removeTabAt(FUEL_TAB);\r
- MotorEditor.this.add(new FuelEditor(motor.getFuel()),\r
- FUEL_TAB);\r
- setSelectedIndex(FUEL_TAB);\r
- }\r
- });\r
- p.add(new Editor(f));\r
- try {\r
- p.add(new Editor(f.getCombustionProduct()));\r
- } catch (Exception e) {\r
-\r
- }\r
-\r
- setLeftComponent(p);\r
- setRightComponent(burnRate);\r
- // setDividerLocation(.25);\r
- // setResizeWeight(.25);\r
- if (f instanceof MotorPart) {\r
- ((MotorPart) f).addPropertyChangeListener(MotorEditor.this);\r
- }\r
- }\r
- }\r
-\r
- private class CaseEditor extends JSplitPane {\r
- private static final long serialVersionUID = 1L;\r
-\r
- public CaseEditor(Nozzle n, Chamber c) {\r
- super(JSplitPane.HORIZONTAL_SPLIT);\r
- setName("Casing");\r
- JPanel parts = new JPanel();\r
- parts.setLayout(new BoxLayout(parts, BoxLayout.Y_AXIS));\r
- setLeftComponent(parts);\r
- setRightComponent(new NozzlePanel(n));\r
-\r
- parts.add(new Editor(c));\r
- parts.add(new Editor(n));\r
-\r
- if (n instanceof MotorPart) {\r
- ((MotorPart) n).addPropertyChangeListener(MotorEditor.this);\r
- }\r
- if (c instanceof MotorPart) {\r
- ((MotorPart) c).addPropertyChangeListener(MotorEditor.this);\r
- }\r
- }\r
- }\r
-\r
- {\r
- text.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);\r
-\r
- }\r
-\r
- public MotorEditor(Motor m) {\r
- super(JTabbedPane.BOTTOM);\r
- text.getDocument().addDocumentListener(this);\r
- text.setName("XML");\r
- add(text, XML_TAB);\r
- setMotor(m, true);\r
- }\r
-\r
- private void reText() {\r
- try {\r
- text.setText(MotorIO.writeMotor(motor));\r
- } catch (IOException e) {\r
- throw new Error(e);\r
- }\r
- }\r
-\r
- private void setMotor(Motor m, boolean retext) {\r
- motor = m;\r
- if (retext)\r
- reText();\r
- if (grainEditor != null)\r
- remove(grainEditor);\r
- while (getTabCount() > 1)\r
- removeTabAt(1);\r
- add(new CaseEditor(motor.getNozzle(), motor.getChamber()), CASING_TAB);\r
- add(new GrainEditor(motor.getGrain()), GRAIN_TAB);\r
- add(new FuelEditor(motor.getFuel()), FUEL_TAB);\r
- add(bt = new BurnTab(), BURN_TAB);\r
- }\r
-\r
- @Deprecated\r
- public static Motor defaultMotor() {\r
- Motor m = new Motor();\r
- m.setName("Example Motor");\r
- m.setFuel(new KNSU());\r
-\r
- CylindricalChamber c = new CylindricalChamber();\r
- c.setLength(Amount.valueOf(200, SI.MILLIMETER));\r
- c.setID(Amount.valueOf(25, SI.MILLIMETER));\r
- m.setChamber(c);\r
-\r
- CoredCylindricalGrain g = new CoredCylindricalGrain();\r
- try {\r
- g.setLength(Amount.valueOf(70, SI.MILLIMETER));\r
- g.setOD(Amount.valueOf(23.5, SI.MILLIMETER));\r
- g.setID(Amount.valueOf(7.9375, SI.MILLIMETER));\r
- } catch (PropertyVetoException v) {\r
- throw new Error(v);\r
- }\r
-\r
- m.setGrain(new MultiGrain(g, 2));\r
-\r
- ConvergentDivergentNozzle n = new ConvergentDivergentNozzle();\r
- n.setThroatDiameter(Amount.valueOf(7.962, SI.MILLIMETER));\r
- n.setExitDiameter(Amount.valueOf(13.79, SI.MILLIMETER));\r
- n.setEfficiency(.85);\r
- m.setNozzle(n);\r
-\r
- return m;\r
- }\r
-\r
- public void focusOnObject(Object o) {\r
- if (o instanceof Grain)\r
- setSelectedIndex(GRAIN_TAB);\r
- if (o instanceof Chamber || o instanceof Nozzle)\r
- setSelectedIndex(CASING_TAB);\r
- if (o instanceof Fuel || o instanceof Fuel.CombustionProduct)\r
- setSelectedIndex(FUEL_TAB);\r
- }\r
-\r
- @Deprecated\r
- public void showAsWindow() {\r
- JFrame f = new JFrame();\r
- f.setSize(1024, 768);\r
- f.setContentPane(this);\r
- f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);\r
- f.setVisible(true);\r
- }\r
-\r
- public static void main(String args[]) throws Exception {\r
- try {\r
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\r
- } catch (Exception e1) {\r
- e1.printStackTrace();\r
- }\r
- new MotorEditor(defaultMotor()).showAsWindow();\r
- }\r
-\r
- public void propertyChange(PropertyChangeEvent evt) {\r
- reText();\r
- bt.reBurn();\r
- }\r
-\r
- public void changedUpdate(DocumentEvent e) {\r
- try {\r
- final Motor m = MotorIO.readMotor(text.getText());\r
- SwingUtilities.invokeLater(new Runnable() {\r
- public void run() {\r
- setMotor(m, false);\r
- }\r
- });\r
- System.out.println("Motor Updated");\r
- } catch (Throwable e1) {\r
- // Leave blank, motor might be broken\r
- }\r
- }\r
-\r
- public void insertUpdate(DocumentEvent e) {\r
- // TODO Auto-generated method stub\r
- }\r
-\r
- public void removeUpdate(DocumentEvent e) {\r
- // TODO Auto-generated method stub\r
- }\r
-}\r
+++ /dev/null
-package com.billkuker.rocketry.motorsim.visual;\r
-\r
-import java.awt.BorderLayout;\r
-import java.awt.Dimension;\r
-import java.util.HashMap;\r
-\r
-import javax.swing.JButton;\r
-import javax.swing.JFrame;\r
-import javax.swing.JPanel;\r
-import javax.swing.JScrollPane;\r
-import javax.swing.JSplitPane;\r
-import javax.swing.JTabbedPane;\r
-import javax.swing.JToolBar;\r
-import javax.swing.JTree;\r
-import javax.swing.UIManager;\r
-import javax.swing.WindowConstants;\r
-import javax.swing.event.TreeSelectionEvent;\r
-import javax.swing.event.TreeSelectionListener;\r
-import javax.swing.tree.DefaultMutableTreeNode;\r
-import javax.swing.tree.TreePath;\r
-import javax.swing.tree.TreeSelectionModel;\r
-\r
-import com.billkuker.rocketry.motorsim.Motor;\r
-import com.billkuker.rocketry.motorsim.visual.workbench.WorkbenchTreeCellRenderer;\r
-import com.billkuker.rocketry.motorsim.visual.workbench.WorkbenchTreeModel;\r
-\r
-public class MotorWorkbench extends JFrame implements TreeSelectionListener {\r
- private static final long serialVersionUID = 1L;\r
- private JPanel top;\r
- private JSplitPane split;\r
- private JTree tree;\r
- private JTabbedPane motors;\r
- private JToolBar bar;\r
- private WorkbenchTreeModel tm;\r
-\r
- private HashMap<Motor, MotorEditor> m2e = new HashMap<Motor, MotorEditor>();\r
-\r
- public MotorWorkbench() {\r
- setSize(1024, 768);\r
- top = new JPanel(new BorderLayout());\r
- setContentPane(top);\r
-\r
- bar = new JToolBar();\r
- bar.add(new JButton("Burn"));\r
- top.add(bar, BorderLayout.PAGE_START);\r
-\r
- motors = new JTabbedPane();\r
-\r
- tree = new JTree(tm = new WorkbenchTreeModel());\r
- tree.setCellRenderer(new WorkbenchTreeCellRenderer());\r
- tree.getSelectionModel().setSelectionMode(\r
- TreeSelectionModel.SINGLE_TREE_SELECTION);\r
- tree.setPreferredSize(new Dimension(200, 100));\r
-\r
- // Listen for when the selection changes.\r
- tree.addTreeSelectionListener(this);\r
-\r
- split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(\r
- tree), motors);\r
- //split.setDividerLocation(.25);\r
- //split.setResizeWeight(.25);\r
- top.add(split, BorderLayout.CENTER);\r
-\r
- setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);\r
- setVisible(true);\r
-\r
- Motor mot = MotorEditor.defaultMotor();\r
- addMotor(mot);\r
- //mot = MotorEditor.defaultMotor();\r
- //addMotor(mot);\r
- }\r
-\r
- public void addMotor(Motor m) {\r
- tm.addMotor(m);\r
- MotorEditor e = new MotorEditor(m);\r
- m2e.put(m, e);\r
- motors.addTab("Motor", e);\r
- }\r
-\r
- public static void main(String args[]) throws Exception {\r
- try {\r
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\r
- } catch (Exception e1) {\r
- e1.printStackTrace();\r
- }\r
- new MotorWorkbench().show();\r
- }\r
-\r
- @Override\r
- public void valueChanged(TreeSelectionEvent e) {\r
- Motor m = getMotor(e.getPath());\r
-\r
- motors.setSelectedComponent(m2e.get(m));\r
- \r
- if ( e.getPath().getLastPathComponent() instanceof DefaultMutableTreeNode ){\r
- Object o = ((DefaultMutableTreeNode)e.getPath().getLastPathComponent()).getUserObject();\r
- m2e.get(m).focusOnObject(o);\r
- }\r
- }\r
-\r
- private Motor getMotor(TreePath p) {\r
- if (p.getLastPathComponent() instanceof WorkbenchTreeModel.MotorNode) {\r
- return ((WorkbenchTreeModel.MotorNode) p.getLastPathComponent())\r
- .getUserObject();\r
- } else if (p.getPath().length > 1)\r
- return getMotor(p.getParentPath());\r
- return null;\r
- }\r
-}\r
--- /dev/null
+package com.billkuker.rocketry.motorsim.visual.workbench;\r
+\r
+import java.awt.BorderLayout;\r
+import java.awt.event.ActionEvent;\r
+import java.awt.event.ActionListener;\r
+import java.beans.PropertyChangeEvent;\r
+import java.beans.PropertyChangeListener;\r
+import java.beans.PropertyVetoException;\r
+import java.io.IOException;\r
+\r
+import javax.measure.quantity.Pressure;\r
+import javax.measure.quantity.Velocity;\r
+import javax.measure.unit.SI;\r
+import javax.swing.BoxLayout;\r
+import javax.swing.JButton;\r
+import javax.swing.JFrame;\r
+import javax.swing.JPanel;\r
+import javax.swing.JSplitPane;\r
+import javax.swing.JTabbedPane;\r
+import javax.swing.SwingUtilities;\r
+import javax.swing.UIManager;\r
+import javax.swing.WindowConstants;\r
+import javax.swing.event.DocumentEvent;\r
+import javax.swing.event.DocumentListener;\r
+\r
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;\r
+import org.fife.ui.rsyntaxtextarea.SyntaxConstants;\r
+import org.jscience.physics.amount.Amount;\r
+\r
+import com.billkuker.rocketry.motorsim.Burn;\r
+import com.billkuker.rocketry.motorsim.Chamber;\r
+import com.billkuker.rocketry.motorsim.ConvergentDivergentNozzle;\r
+import com.billkuker.rocketry.motorsim.CylindricalChamber;\r
+import com.billkuker.rocketry.motorsim.Fuel;\r
+import com.billkuker.rocketry.motorsim.Grain;\r
+import com.billkuker.rocketry.motorsim.Motor;\r
+import com.billkuker.rocketry.motorsim.MotorPart;\r
+import com.billkuker.rocketry.motorsim.Nozzle;\r
+import com.billkuker.rocketry.motorsim.fuel.EditableFuel;\r
+import com.billkuker.rocketry.motorsim.fuel.KNDX;\r
+import com.billkuker.rocketry.motorsim.fuel.KNER;\r
+import com.billkuker.rocketry.motorsim.fuel.KNSB;\r
+import com.billkuker.rocketry.motorsim.fuel.KNSU;\r
+import com.billkuker.rocketry.motorsim.grain.CoredCylindricalGrain;\r
+import com.billkuker.rocketry.motorsim.grain.Finocyl;\r
+import com.billkuker.rocketry.motorsim.grain.Moonburner;\r
+import com.billkuker.rocketry.motorsim.grain.MultiGrain;\r
+import com.billkuker.rocketry.motorsim.grain.RodAndTubeGrain;\r
+import com.billkuker.rocketry.motorsim.io.MotorIO;\r
+import com.billkuker.rocketry.motorsim.visual.BurnPanel;\r
+import com.billkuker.rocketry.motorsim.visual.Chart;\r
+import com.billkuker.rocketry.motorsim.visual.Editor;\r
+import com.billkuker.rocketry.motorsim.visual.GrainPanel;\r
+import com.billkuker.rocketry.motorsim.visual.NozzlePanel;\r
+import com.billkuker.rocketry.motorsim.visual.Chart.IntervalDomain;\r
+\r
+public class MotorEditor extends JTabbedPane implements PropertyChangeListener,\r
+ DocumentListener {\r
+ private static final long serialVersionUID = 1L;\r
+ RSyntaxTextArea text = new RSyntaxTextArea();\r
+ Motor motor;\r
+ GrainEditor grainEditor;\r
+ BurnTab bt;\r
+\r
+ private static final int XML_TAB = 0;\r
+ private static final int CASING_TAB = 1;\r
+ private static final int GRAIN_TAB = 2;\r
+ private static final int FUEL_TAB = 3;\r
+ private static final int BURN_TAB = 4;\r
+\r
+ private Class[] grainTypes = { CoredCylindricalGrain.class, Finocyl.class,\r
+ Moonburner.class, RodAndTubeGrain.class };\r
+\r
+ private Class[] fuelTypes = { KNSB.class, KNSU.class, KNER.class,\r
+ KNDX.class, EditableFuel.class };\r
+\r
+ private abstract class Chooser<T> extends JPanel {\r
+ private static final long serialVersionUID = 1L;\r
+ private Class<? extends T>[] types;\r
+\r
+ public Chooser(Class<? extends T>... ts) {\r
+ types = ts;\r
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
+ for (final Class<? extends T> c : types) {\r
+ JButton b = new JButton(c.getSimpleName());\r
+ add(b);\r
+ b.addActionListener(new ActionListener() {\r
+ public void actionPerformed(ActionEvent e) {\r
+ try {\r
+ choiceMade(c.newInstance());\r
+ } catch (InstantiationException e1) {\r
+ e1.printStackTrace();\r
+ } catch (IllegalAccessException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+\r
+ protected abstract void choiceMade(T o);\r
+ }\r
+\r
+ private class BurnTab extends JPanel {\r
+ public BurnTab() {\r
+ setLayout(new BorderLayout());\r
+ setName("Burn");\r
+ reBurn();\r
+ }\r
+\r
+ public void reBurn() {\r
+ removeAll();\r
+ new Thread() {\r
+ public void run() {\r
+ final Burn b = new Burn(motor);\r
+ final BurnPanel bp = new BurnPanel(b);\r
+ SwingUtilities.invokeLater(new Thread() {\r
+ public void run() {\r
+ add(bp, BorderLayout.CENTER);\r
+ }\r
+ });\r
+ }\r
+ }.start();\r
+ }\r
+ }\r
+\r
+ private class GrainEditor extends JSplitPane {\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ public GrainEditor(final Grain g) {\r
+ super(JSplitPane.HORIZONTAL_SPLIT);\r
+ setName("Grain");\r
+ setRightComponent(new GrainPanel(g));\r
+ if (g instanceof Grain.Composite) {\r
+ final JPanel p = new JPanel();\r
+ p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));\r
+ p.add(new Editor(g));\r
+ for (Grain gg : ((Grain.Composite) g).getGrains()) {\r
+ final int grainEditorIndex = p.getComponentCount() + 1;\r
+ p.add(new Chooser<Grain>(grainTypes) {\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ @Override\r
+ protected void choiceMade(Grain ng) {\r
+ if (g instanceof MultiGrain) {\r
+ ((MultiGrain) g).setGrain(ng);\r
+ p.remove(grainEditorIndex);\r
+ p.add(new Editor(ng), grainEditorIndex);\r
+ p.remove(0);\r
+ p.add(new Editor(g), 0);\r
+ // System.out.println("Chose new grain");\r
+ }\r
+ }\r
+ });\r
+ p.add(new Editor(gg));\r
+ if (gg instanceof MotorPart) {\r
+ ((MotorPart) gg)\r
+ .addPropertyChangeListener(MotorEditor.this);\r
+ }\r
+ }\r
+ setLeftComponent(p);\r
+ } else {\r
+ setLeftComponent(new Editor(g));\r
+ }\r
+ // setDividerLocation(.25);\r
+ // setResizeWeight(.25);\r
+ if (g instanceof MotorPart) {\r
+ ((MotorPart) g).addPropertyChangeListener(MotorEditor.this);\r
+ }\r
+ }\r
+ }\r
+\r
+ private class FuelEditor extends JSplitPane {\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ public FuelEditor(Fuel f) {\r
+ super(JSplitPane.HORIZONTAL_SPLIT);\r
+ setName("Fuel");\r
+ Chart<Pressure, Velocity> burnRate;\r
+ try {\r
+ burnRate = new Chart<Pressure, Velocity>(SI.MEGA(SI.PASCAL),\r
+ SI.METERS_PER_SECOND, f, "burnRate");\r
+ } catch (NoSuchMethodException e) {\r
+ throw new Error(e);\r
+ }\r
+ burnRate.setDomain(burnRate.new IntervalDomain(Amount.valueOf(0, SI\r
+ .MEGA(SI.PASCAL)), Amount.valueOf(11, SI.MEGA(SI.PASCAL)),\r
+ 20));\r
+\r
+ final JPanel p = new JPanel();\r
+ p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));\r
+\r
+ p.add(new Chooser<Fuel>(fuelTypes) {\r
+ @Override\r
+ protected void choiceMade(Fuel o) {\r
+ motor.setFuel(o);\r
+ removeTabAt(FUEL_TAB);\r
+ MotorEditor.this.add(new FuelEditor(motor.getFuel()),\r
+ FUEL_TAB);\r
+ setSelectedIndex(FUEL_TAB);\r
+ }\r
+ });\r
+ p.add(new Editor(f));\r
+ try {\r
+ p.add(new Editor(f.getCombustionProduct()));\r
+ } catch (Exception e) {\r
+\r
+ }\r
+\r
+ setLeftComponent(p);\r
+ setRightComponent(burnRate);\r
+ // setDividerLocation(.25);\r
+ // setResizeWeight(.25);\r
+ if (f instanceof MotorPart) {\r
+ ((MotorPart) f).addPropertyChangeListener(MotorEditor.this);\r
+ }\r
+ }\r
+ }\r
+\r
+ private class CaseEditor extends JSplitPane {\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ public CaseEditor(Nozzle n, Chamber c) {\r
+ super(JSplitPane.HORIZONTAL_SPLIT);\r
+ setName("Casing");\r
+ JPanel parts = new JPanel();\r
+ parts.setLayout(new BoxLayout(parts, BoxLayout.Y_AXIS));\r
+ setLeftComponent(parts);\r
+ setRightComponent(new NozzlePanel(n));\r
+\r
+ parts.add(new Editor(c));\r
+ parts.add(new Editor(n));\r
+\r
+ if (n instanceof MotorPart) {\r
+ ((MotorPart) n).addPropertyChangeListener(MotorEditor.this);\r
+ }\r
+ if (c instanceof MotorPart) {\r
+ ((MotorPart) c).addPropertyChangeListener(MotorEditor.this);\r
+ }\r
+ }\r
+ }\r
+\r
+ {\r
+ text.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);\r
+\r
+ }\r
+\r
+ public MotorEditor(Motor m) {\r
+ super(JTabbedPane.BOTTOM);\r
+ text.getDocument().addDocumentListener(this);\r
+ text.setName("XML");\r
+ add(text, XML_TAB);\r
+ setMotor(m, true);\r
+ }\r
+\r
+ private void reText() {\r
+ try {\r
+ text.setText(MotorIO.writeMotor(motor));\r
+ } catch (IOException e) {\r
+ throw new Error(e);\r
+ }\r
+ }\r
+\r
+ private void setMotor(Motor m, boolean retext) {\r
+ motor = m;\r
+ if (retext)\r
+ reText();\r
+ if (grainEditor != null)\r
+ remove(grainEditor);\r
+ while (getTabCount() > 1)\r
+ removeTabAt(1);\r
+ add(new CaseEditor(motor.getNozzle(), motor.getChamber()), CASING_TAB);\r
+ add(new GrainEditor(motor.getGrain()), GRAIN_TAB);\r
+ add(new FuelEditor(motor.getFuel()), FUEL_TAB);\r
+ add(bt = new BurnTab(), BURN_TAB);\r
+ }\r
+\r
+ @Deprecated\r
+ public static Motor defaultMotor() {\r
+ Motor m = new Motor();\r
+ m.setName("Example Motor");\r
+ m.setFuel(new KNSU());\r
+\r
+ CylindricalChamber c = new CylindricalChamber();\r
+ c.setLength(Amount.valueOf(200, SI.MILLIMETER));\r
+ c.setID(Amount.valueOf(25, SI.MILLIMETER));\r
+ m.setChamber(c);\r
+\r
+ CoredCylindricalGrain g = new CoredCylindricalGrain();\r
+ try {\r
+ g.setLength(Amount.valueOf(70, SI.MILLIMETER));\r
+ g.setOD(Amount.valueOf(23.5, SI.MILLIMETER));\r
+ g.setID(Amount.valueOf(7.9375, SI.MILLIMETER));\r
+ } catch (PropertyVetoException v) {\r
+ throw new Error(v);\r
+ }\r
+\r
+ m.setGrain(new MultiGrain(g, 2));\r
+\r
+ ConvergentDivergentNozzle n = new ConvergentDivergentNozzle();\r
+ n.setThroatDiameter(Amount.valueOf(7.962, SI.MILLIMETER));\r
+ n.setExitDiameter(Amount.valueOf(13.79, SI.MILLIMETER));\r
+ n.setEfficiency(.85);\r
+ m.setNozzle(n);\r
+\r
+ return m;\r
+ }\r
+\r
+ public void focusOnObject(Object o) {\r
+ if (o instanceof Grain)\r
+ setSelectedIndex(GRAIN_TAB);\r
+ if (o instanceof Chamber || o instanceof Nozzle)\r
+ setSelectedIndex(CASING_TAB);\r
+ if (o instanceof Fuel || o instanceof Fuel.CombustionProduct)\r
+ setSelectedIndex(FUEL_TAB);\r
+ }\r
+\r
+ @Deprecated\r
+ public void showAsWindow() {\r
+ JFrame f = new JFrame();\r
+ f.setSize(1024, 768);\r
+ f.setContentPane(this);\r
+ f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);\r
+ f.setVisible(true);\r
+ }\r
+\r
+ public static void main(String args[]) throws Exception {\r
+ try {\r
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\r
+ } catch (Exception e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ new MotorEditor(defaultMotor()).showAsWindow();\r
+ }\r
+\r
+ public void propertyChange(PropertyChangeEvent evt) {\r
+ reText();\r
+ bt.reBurn();\r
+ }\r
+\r
+ public void changedUpdate(DocumentEvent e) {\r
+ try {\r
+ final Motor m = MotorIO.readMotor(text.getText());\r
+ SwingUtilities.invokeLater(new Runnable() {\r
+ public void run() {\r
+ setMotor(m, false);\r
+ }\r
+ });\r
+ System.out.println("Motor Updated");\r
+ } catch (Throwable e1) {\r
+ // Leave blank, motor might be broken\r
+ }\r
+ }\r
+\r
+ public void insertUpdate(DocumentEvent e) {\r
+ // TODO Auto-generated method stub\r
+ }\r
+\r
+ public void removeUpdate(DocumentEvent e) {\r
+ // TODO Auto-generated method stub\r
+ }\r
+}\r
--- /dev/null
+package com.billkuker.rocketry.motorsim.visual.workbench;\r
+\r
+import java.awt.BorderLayout;\r
+import java.awt.Dimension;\r
+import java.util.HashMap;\r
+\r
+import javax.swing.JButton;\r
+import javax.swing.JFrame;\r
+import javax.swing.JPanel;\r
+import javax.swing.JScrollPane;\r
+import javax.swing.JSplitPane;\r
+import javax.swing.JTabbedPane;\r
+import javax.swing.JToolBar;\r
+import javax.swing.JTree;\r
+import javax.swing.UIManager;\r
+import javax.swing.WindowConstants;\r
+import javax.swing.event.TreeSelectionEvent;\r
+import javax.swing.event.TreeSelectionListener;\r
+import javax.swing.tree.DefaultMutableTreeNode;\r
+import javax.swing.tree.TreePath;\r
+import javax.swing.tree.TreeSelectionModel;\r
+\r
+import com.billkuker.rocketry.motorsim.Motor;\r
+\r
+public class MotorWorkbench extends JFrame implements TreeSelectionListener {\r
+ private static final long serialVersionUID = 1L;\r
+ private JPanel top;\r
+ private JSplitPane split;\r
+ private JTree tree;\r
+ private JTabbedPane motors;\r
+ private JToolBar bar;\r
+ private WorkbenchTreeModel tm;\r
+\r
+ private HashMap<Motor, MotorEditor> m2e = new HashMap<Motor, MotorEditor>();\r
+\r
+ public MotorWorkbench() {\r
+ setSize(1024, 768);\r
+ top = new JPanel(new BorderLayout());\r
+ setContentPane(top);\r
+\r
+ bar = new JToolBar();\r
+ bar.add(new JButton("Burn"));\r
+ top.add(bar, BorderLayout.PAGE_START);\r
+\r
+ motors = new JTabbedPane();\r
+\r
+ tree = new JTree(tm = new WorkbenchTreeModel());\r
+ tree.setCellRenderer(new WorkbenchTreeCellRenderer());\r
+ tree.getSelectionModel().setSelectionMode(\r
+ TreeSelectionModel.SINGLE_TREE_SELECTION);\r
+ tree.setPreferredSize(new Dimension(200, 100));\r
+\r
+ // Listen for when the selection changes.\r
+ tree.addTreeSelectionListener(this);\r
+\r
+ split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(\r
+ tree), motors);\r
+ //split.setDividerLocation(.25);\r
+ //split.setResizeWeight(.25);\r
+ top.add(split, BorderLayout.CENTER);\r
+\r
+ setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);\r
+ setVisible(true);\r
+\r
+ Motor mot = MotorEditor.defaultMotor();\r
+ addMotor(mot);\r
+ //mot = MotorEditor.defaultMotor();\r
+ //addMotor(mot);\r
+ }\r
+\r
+ public void addMotor(Motor m) {\r
+ tm.addMotor(m);\r
+ MotorEditor e = new MotorEditor(m);\r
+ m2e.put(m, e);\r
+ motors.addTab("Motor", e);\r
+ }\r
+\r
+ public static void main(String args[]) throws Exception {\r
+ try {\r
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\r
+ } catch (Exception e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ new MotorWorkbench().show();\r
+ }\r
+\r
+ @Override\r
+ public void valueChanged(TreeSelectionEvent e) {\r
+ Motor m = getMotor(e.getPath());\r
+\r
+ motors.setSelectedComponent(m2e.get(m));\r
+ \r
+ if ( e.getPath().getLastPathComponent() instanceof DefaultMutableTreeNode ){\r
+ Object o = ((DefaultMutableTreeNode)e.getPath().getLastPathComponent()).getUserObject();\r
+ m2e.get(m).focusOnObject(o);\r
+ }\r
+ }\r
+\r
+ private Motor getMotor(TreePath p) {\r
+ if (p.getLastPathComponent() instanceof WorkbenchTreeModel.MotorNode) {\r
+ return ((WorkbenchTreeModel.MotorNode) p.getLastPathComponent())\r
+ .getUserObject();\r
+ } else if (p.getPath().length > 1)\r
+ return getMotor(p.getParentPath());\r
+ return null;\r
+ }\r
+}\r