297f2e7c2ecda462745afa4cb06b60b27cb5d387
[sw/motorsim] / src / com / billkuker / rocketry / motorsim / visual / MotorEditor.java
1 package com.billkuker.rocketry.motorsim.visual;\r
2 \r
3 import java.awt.event.ActionEvent;\r
4 import java.awt.event.ActionListener;\r
5 import java.awt.event.TextEvent;\r
6 import java.awt.event.TextListener;\r
7 import java.beans.PropertyChangeEvent;\r
8 import java.beans.PropertyChangeListener;\r
9 import java.beans.PropertyVetoException;\r
10 import java.io.IOException;\r
11 \r
12 import javax.measure.quantity.Pressure;\r
13 import javax.measure.quantity.Velocity;\r
14 import javax.measure.unit.SI;\r
15 import javax.swing.BoxLayout;\r
16 import javax.swing.JButton;\r
17 import javax.swing.JFrame;\r
18 import javax.swing.JPanel;\r
19 import javax.swing.JSplitPane;\r
20 import javax.swing.JTabbedPane;\r
21 import javax.swing.SwingUtilities;\r
22 import javax.swing.UIManager;\r
23 import javax.swing.WindowConstants;\r
24 import javax.swing.event.DocumentEvent;\r
25 import javax.swing.event.DocumentListener;\r
26 \r
27 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;\r
28 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;\r
29 import org.jscience.physics.amount.Amount;\r
30 \r
31 import com.billkuker.rocketry.motorsim.Chamber;\r
32 import com.billkuker.rocketry.motorsim.ConvergentDivergentNozzle;\r
33 import com.billkuker.rocketry.motorsim.CylindricalChamber;\r
34 import com.billkuker.rocketry.motorsim.Fuel;\r
35 import com.billkuker.rocketry.motorsim.Grain;\r
36 import com.billkuker.rocketry.motorsim.Motor;\r
37 import com.billkuker.rocketry.motorsim.MotorPart;\r
38 import com.billkuker.rocketry.motorsim.Nozzle;\r
39 import com.billkuker.rocketry.motorsim.fuel.KNSU;\r
40 import com.billkuker.rocketry.motorsim.grain.CoredCylindricalGrain;\r
41 import com.billkuker.rocketry.motorsim.grain.Finocyl;\r
42 import com.billkuker.rocketry.motorsim.grain.GrainSet;\r
43 import com.billkuker.rocketry.motorsim.grain.Moonburner;\r
44 import com.billkuker.rocketry.motorsim.grain.MultiGrain;\r
45 import com.billkuker.rocketry.motorsim.grain.RodAndTubeGrain;\r
46 import com.billkuker.rocketry.motorsim.io.MotorIO;\r
47 import com.billkuker.rocketry.motorsim.visual.Chart.IntervalDomain;\r
48 \r
49 public class MotorEditor extends JTabbedPane implements PropertyChangeListener, DocumentListener{\r
50         RSyntaxTextArea text = new RSyntaxTextArea();\r
51         Motor motor;\r
52         GrainEditor grainEditor;\r
53         \r
54         private class GrainChooser extends JPanel{\r
55                 private Class[] types = {\r
56                                         CoredCylindricalGrain.class,\r
57                                         Finocyl.class,\r
58                                         Moonburner.class,\r
59                                         RodAndTubeGrain.class\r
60                                 };\r
61                 public GrainChooser(){\r
62                         setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
63                         for ( final Class c : types ){\r
64                                 JButton b = new JButton(c.getSimpleName());\r
65                                 add(b);\r
66                                 b.addActionListener(new ActionListener(){\r
67                                         public void actionPerformed(ActionEvent e) {\r
68                                                 try {\r
69                                                         grainChosen((Grain)c.newInstance());\r
70                                                 } catch (InstantiationException e1) {\r
71                                                         e1.printStackTrace();\r
72                                                 } catch (IllegalAccessException e1) {\r
73                                                         e1.printStackTrace();\r
74                                                 }\r
75                                         }\r
76                                 });\r
77                         }\r
78                 }\r
79                 protected void grainChosen(Grain g){\r
80                         System.out.println(g);\r
81                 }\r
82         }\r
83         \r
84         private class GrainEditor extends JSplitPane{\r
85                 public GrainEditor(final Grain g){\r
86                         super(JSplitPane.HORIZONTAL_SPLIT);\r
87                         setRightComponent(new GrainPanel(g));\r
88                         if ( g instanceof Grain.Composite ){\r
89                                 final JPanel p = new JPanel();\r
90                                 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));\r
91                                 p.add(new Editor(g));\r
92                                 for ( Grain gg : ((Grain.Composite)g).getGrains() ){\r
93                                         final int grainEditorIndex = p.getComponentCount() + 1;\r
94                                         p.add(new GrainChooser(){\r
95                                                 @Override\r
96                                                 protected void grainChosen(Grain ng){\r
97                                                         if ( g instanceof MultiGrain ){\r
98                                                                 ((MultiGrain) g).setGrain(ng);\r
99                                                                 p.remove(grainEditorIndex);\r
100                                                                 p.add(new Editor(ng), grainEditorIndex);\r
101                                                                 System.out.println("Chose new grain");\r
102                                                         }\r
103                                                 }\r
104                                         });\r
105                                         p.add(new Editor(gg));\r
106                                         if ( gg instanceof MotorPart ){\r
107                                                 ((MotorPart)gg).addPropertyChangeListener(MotorEditor.this);\r
108                                         }\r
109                                 }\r
110                                 setLeftComponent(p);\r
111                         } else {\r
112                                 setLeftComponent(new Editor(g));\r
113                         }\r
114                         setDividerLocation(.25);\r
115                         setResizeWeight(.25);\r
116                         if ( g instanceof MotorPart ){\r
117                                 ((MotorPart)g).addPropertyChangeListener(MotorEditor.this);\r
118                         }\r
119                 }\r
120         }\r
121         \r
122         private class FuelEditor extends JSplitPane{\r
123                 public FuelEditor(Fuel f){\r
124                         super(JSplitPane.HORIZONTAL_SPLIT);\r
125                         Chart<Pressure, Velocity> burnRate;\r
126                         try {\r
127                                 burnRate = new Chart<Pressure, Velocity>(\r
128                                                 SI.MEGA(SI.PASCAL),\r
129                                                 SI.METERS_PER_SECOND,\r
130                                                 f,\r
131                                                 "burnRate");\r
132                         } catch (NoSuchMethodException e) {\r
133                                 throw new Error(e);\r
134                         }\r
135                         burnRate.setDomain(\r
136                                         burnRate.new IntervalDomain(\r
137                                                         Amount.valueOf(0, SI.MEGA(SI.PASCAL)),\r
138                                                         Amount.valueOf(11, SI.MEGA(SI.PASCAL)),\r
139                                                         20\r
140                                                         ));\r
141 \r
142                         setLeftComponent(new Editor(f));\r
143                         setRightComponent(burnRate);\r
144                         setDividerLocation(.25);\r
145                         setResizeWeight(.25);\r
146                         if ( f instanceof MotorPart ){\r
147                                 ((MotorPart)f).addPropertyChangeListener(MotorEditor.this);\r
148                         }\r
149                 }\r
150         }\r
151         \r
152         private class CaseEditor extends JSplitPane{\r
153 \r
154                 public CaseEditor(Nozzle n, Chamber c){\r
155                         super(JSplitPane.HORIZONTAL_SPLIT, \r
156                                         new JSplitPane(JSplitPane.VERTICAL_SPLIT,\r
157                                                         new Editor(n), new Editor(c)), new NozzlePanel(n));\r
158                         JSplitPane parts = (JSplitPane)getLeftComponent();\r
159                         parts.setDividerLocation(.5);\r
160                         parts.setResizeWeight(.5);\r
161                         setDividerLocation(.25);\r
162                         setResizeWeight(.25);\r
163 \r
164                         if ( n instanceof MotorPart ){\r
165                                 ((MotorPart)n).addPropertyChangeListener(MotorEditor.this);\r
166                         }\r
167                         if ( c instanceof MotorPart ){\r
168                                 ((MotorPart)c).addPropertyChangeListener(MotorEditor.this);\r
169                         }\r
170                 }\r
171         }\r
172         \r
173         {\r
174                 text.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);\r
175 \r
176         }\r
177         \r
178         public MotorEditor(Motor m){\r
179                 super(JTabbedPane.BOTTOM);\r
180                 text.getDocument().addDocumentListener(this);\r
181                 addTab("XML", text);\r
182                 setMotor(m, true);\r
183         }\r
184         \r
185         private void reText(){\r
186                 try {\r
187                         text.setText(MotorIO.writeMotor(motor));\r
188                 } catch (IOException e) {\r
189                         throw new Error(e);\r
190                 }\r
191         }\r
192         \r
193         private void setMotor(Motor m, boolean retext){\r
194                 motor = m;\r
195                 if ( retext )\r
196                         reText();\r
197                 if ( grainEditor != null)\r
198                         remove(grainEditor);\r
199         while ( getTabCount() > 1       )\r
200                 removeTabAt(1);\r
201                 add("Casing", new CaseEditor(motor.getNozzle(), motor.getChamber()));\r
202                 add("Grain", new GrainEditor(motor.getGrain()));\r
203                 add("Fuel", new FuelEditor(motor.getFuel()));\r
204         }\r
205         \r
206         @Deprecated\r
207         private static Motor defaultMotor() {\r
208                 Motor m = new Motor();\r
209                 m.setName("Example Motor");\r
210                 m.setFuel(new KNSU());\r
211 \r
212                 CylindricalChamber c = new CylindricalChamber();\r
213                 c.setLength(Amount.valueOf(200, SI.MILLIMETER));\r
214                 c.setID(Amount.valueOf(25, SI.MILLIMETER));\r
215                 m.setChamber(c);\r
216 \r
217                 CoredCylindricalGrain g = new CoredCylindricalGrain();\r
218                 try {\r
219                         g.setLength(Amount.valueOf(70, SI.MILLIMETER));\r
220                         g.setOD(Amount.valueOf(23.5, SI.MILLIMETER));\r
221                         g.setID(Amount.valueOf(7.9375, SI.MILLIMETER));\r
222                 } catch (PropertyVetoException v) {\r
223                         throw new Error(v);\r
224                 }\r
225 \r
226                 m.setGrain(new MultiGrain(g,2));\r
227 \r
228 \r
229                 ConvergentDivergentNozzle n = new ConvergentDivergentNozzle();\r
230                 n.setThroatDiameter(Amount.valueOf(7.962, SI.MILLIMETER));\r
231                 n.setExitDiameter(Amount.valueOf(13.79, SI.MILLIMETER));\r
232                 n.setEfficiency(.85);\r
233                 m.setNozzle(n);\r
234 \r
235                 return m;\r
236         }\r
237         \r
238         @Deprecated\r
239         public void showAsWindow(){\r
240                 JFrame f = new JFrame();\r
241                 f.setSize(1024,768);\r
242                 f.setContentPane(this);\r
243                 f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);\r
244                 f.setVisible(true);\r
245         }\r
246         \r
247         public static void main(String args[]) throws Exception{\r
248                 try {\r
249                         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\r
250                 } catch (Exception e1) {\r
251                         e1.printStackTrace();\r
252                 }\r
253                 new MotorEditor(defaultMotor()).showAsWindow();\r
254         }\r
255 \r
256         public void propertyChange(PropertyChangeEvent evt) {\r
257                 reText();\r
258         }\r
259 \r
260 \r
261         public void changedUpdate(DocumentEvent e) {\r
262                 try {\r
263                         final Motor m = MotorIO.readMotor(text.getText());\r
264                         SwingUtilities.invokeLater(new Runnable(){\r
265                                 public void run() {\r
266                                         setMotor(m, false);\r
267                                 }});\r
268                         System.out.println("Motor Updated");\r
269                 } catch (Throwable e1) {\r
270                         //Leave blank, motor might be broken\r
271                 }\r
272         }\r
273 \r
274         public void insertUpdate(DocumentEvent e) {\r
275                 // TODO Auto-generated method stub\r
276         }\r
277 \r
278         public void removeUpdate(DocumentEvent e) {\r
279                 // TODO Auto-generated method stub\r
280         }\r
281 }\r