1 package com.billkuker.rocketry.motorsim.visual;
\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
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
27 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
\r
28 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
\r
29 import org.jscience.physics.amount.Amount;
\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
49 public class MotorEditor extends JTabbedPane implements PropertyChangeListener, DocumentListener{
\r
50 RSyntaxTextArea text = new RSyntaxTextArea();
\r
52 GrainEditor grainEditor;
\r
54 private class GrainChooser extends JPanel{
\r
55 private Class[] types = {
\r
56 CoredCylindricalGrain.class,
\r
59 RodAndTubeGrain.class
\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
66 b.addActionListener(new ActionListener(){
\r
67 public void actionPerformed(ActionEvent e) {
\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
79 protected void grainChosen(Grain g){
\r
80 System.out.println(g);
\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
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
105 p.add(new Editor(gg));
\r
106 if ( gg instanceof MotorPart ){
\r
107 ((MotorPart)gg).addPropertyChangeListener(MotorEditor.this);
\r
110 setLeftComponent(p);
\r
112 setLeftComponent(new Editor(g));
\r
114 setDividerLocation(.25);
\r
115 setResizeWeight(.25);
\r
116 if ( g instanceof MotorPart ){
\r
117 ((MotorPart)g).addPropertyChangeListener(MotorEditor.this);
\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
127 burnRate = new Chart<Pressure, Velocity>(
\r
128 SI.MEGA(SI.PASCAL),
\r
129 SI.METERS_PER_SECOND,
\r
132 } catch (NoSuchMethodException e) {
\r
133 throw new Error(e);
\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
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
152 private class CaseEditor extends JSplitPane{
\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
164 if ( n instanceof MotorPart ){
\r
165 ((MotorPart)n).addPropertyChangeListener(MotorEditor.this);
\r
167 if ( c instanceof MotorPart ){
\r
168 ((MotorPart)c).addPropertyChangeListener(MotorEditor.this);
\r
174 text.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
\r
178 public MotorEditor(Motor m){
\r
179 super(JTabbedPane.BOTTOM);
\r
180 text.getDocument().addDocumentListener(this);
\r
181 addTab("XML", text);
\r
185 private void reText(){
\r
187 text.setText(MotorIO.writeMotor(motor));
\r
188 } catch (IOException e) {
\r
189 throw new Error(e);
\r
193 private void setMotor(Motor m, boolean retext){
\r
197 if ( grainEditor != null)
\r
198 remove(grainEditor);
\r
199 while ( getTabCount() > 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
207 private static Motor defaultMotor() {
\r
208 Motor m = new Motor();
\r
209 m.setName("Example Motor");
\r
210 m.setFuel(new KNSU());
\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
217 CoredCylindricalGrain g = new CoredCylindricalGrain();
\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
226 m.setGrain(new MultiGrain(g,2));
\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
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
247 public static void main(String args[]) throws Exception{
\r
249 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
\r
250 } catch (Exception e1) {
\r
251 e1.printStackTrace();
\r
253 new MotorEditor(defaultMotor()).showAsWindow();
\r
256 public void propertyChange(PropertyChangeEvent evt) {
\r
261 public void changedUpdate(DocumentEvent e) {
\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
268 System.out.println("Motor Updated");
\r
269 } catch (Throwable e1) {
\r
270 //Leave blank, motor might be broken
\r
274 public void insertUpdate(DocumentEvent e) {
\r
275 // TODO Auto-generated method stub
\r
278 public void removeUpdate(DocumentEvent e) {
\r
279 // TODO Auto-generated method stub
\r