1 package com.billkuker.rocketry.motorsim.visual.workbench;
\r
3 import java.awt.BorderLayout;
\r
4 import java.awt.Dimension;
\r
5 import java.awt.FileDialog;
\r
6 import java.awt.event.ActionEvent;
\r
7 import java.awt.event.ActionListener;
\r
8 import java.beans.PropertyChangeEvent;
\r
9 import java.beans.PropertyChangeListener;
\r
10 import java.io.File;
\r
11 import java.util.HashMap;
\r
12 import java.util.List;
\r
13 import java.util.Vector;
\r
15 import javax.swing.ButtonGroup;
\r
16 import javax.swing.DefaultComboBoxModel;
\r
17 import javax.swing.JFrame;
\r
18 import javax.swing.JMenu;
\r
19 import javax.swing.JMenuBar;
\r
20 import javax.swing.JMenuItem;
\r
21 import javax.swing.JOptionPane;
\r
22 import javax.swing.JPanel;
\r
23 import javax.swing.JRadioButtonMenuItem;
\r
24 import javax.swing.JScrollPane;
\r
25 import javax.swing.JSeparator;
\r
26 import javax.swing.JSplitPane;
\r
27 import javax.swing.JTabbedPane;
\r
28 import javax.swing.JTree;
\r
29 import javax.swing.WindowConstants;
\r
30 import javax.swing.event.TreeSelectionEvent;
\r
31 import javax.swing.event.TreeSelectionListener;
\r
32 import javax.swing.tree.DefaultMutableTreeNode;
\r
33 import javax.swing.tree.TreePath;
\r
34 import javax.swing.tree.TreeSelectionModel;
\r
36 import com.billkuker.rocketry.motorsim.Burn;
\r
37 import com.billkuker.rocketry.motorsim.Fuel;
\r
38 import com.billkuker.rocketry.motorsim.Motor;
\r
39 import com.billkuker.rocketry.motorsim.RocketScience.UnitPreference;
\r
40 import com.billkuker.rocketry.motorsim.fuel.KNDX;
\r
41 import com.billkuker.rocketry.motorsim.fuel.KNER;
\r
42 import com.billkuker.rocketry.motorsim.fuel.KNSB;
\r
43 import com.billkuker.rocketry.motorsim.fuel.KNSU;
\r
44 import com.billkuker.rocketry.motorsim.io.ENGExporter;
\r
45 import com.billkuker.rocketry.motorsim.io.MotorIO;
\r
46 import com.billkuker.rocketry.motorsim.visual.FuelPanel;
\r
47 import com.billkuker.rocketry.motorsim.visual.workbench.WorkbenchTreeModel.FuelEditNode;
\r
48 import com.billkuker.rocketry.motorsim.visual.workbench.WorkbenchTreeModel.FuelNode;
\r
50 public class MotorWorkbench extends JFrame implements TreeSelectionListener {
\r
51 private static final long serialVersionUID = 1L;
\r
53 private List<Class<? extends Fuel>> fuelTypes = new Vector<Class<? extends Fuel>>();
\r
55 fuelTypes.add(KNSB.class);
\r
56 fuelTypes.add(KNSU.class);
\r
57 fuelTypes.add(KNER.class);
\r
58 fuelTypes.add(KNDX.class);
\r
62 private JSplitPane split;
\r
64 private JTabbedPane motors;
\r
65 private WorkbenchTreeModel tm;
\r
66 private MultiBurnChart mb;
\r
67 private JFrame allBurns;
\r
69 private HashMap<MotorEditor, File> e2f = new HashMap<MotorEditor, File>();
\r
70 private HashMap<File, MotorEditor> f2e = new HashMap<File, MotorEditor>();
\r
72 private HashMap<Motor, MotorEditor> m2e = new HashMap<Motor, MotorEditor>();
\r
74 private DefaultComboBoxModel fuels = new DefaultComboBoxModel();
\r
76 public MotorWorkbench() {
\r
77 setTitle("MotorSim 1.0 RC1");
\r
80 top = new JPanel(new BorderLayout());
\r
81 setContentPane(top);
\r
83 mb = new MultiBurnChart();
\r
84 allBurns = new JFrame();
\r
85 allBurns.setTitle("All Burns");
\r
86 allBurns.setSize(800, 600);
\r
87 setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
\r
90 motors = new JTabbedPane();
\r
92 tree = new JTree(tm = new WorkbenchTreeModel());
\r
93 tree.setCellRenderer(new WorkbenchTreeCellRenderer());
\r
94 tree.getSelectionModel().setSelectionMode(
\r
95 TreeSelectionModel.SINGLE_TREE_SELECTION);
\r
96 tree.setMinimumSize(new Dimension(200, 100));
\r
98 // Listen for when the selection changes.
\r
99 tree.addTreeSelectionListener(this);
\r
101 split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(
\r
103 split.setDividerLocation(200);
\r
104 split.setResizeWeight(0);
\r
105 split.resetToPreferredSizes();
\r
106 split.revalidate();
\r
108 top.add(split, BorderLayout.CENTER);
\r
110 for ( Class<? extends Fuel> f : fuelTypes){
\r
112 addFuel(f.newInstance());
\r
113 } catch (InstantiationException e) {
\r
114 // TODO Auto-generated catch block
\r
115 e.printStackTrace();
\r
116 } catch (IllegalAccessException e) {
\r
117 // TODO Auto-generated catch block
\r
118 e.printStackTrace();
\r
122 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
\r
127 private void addMenu() {
\r
129 setJMenuBar(new JMenuBar() {
\r
130 private static final long serialVersionUID = 1L;
\r
133 add(new JMenu("File") {
\r
134 private static final long serialVersionUID = 1L;
\r
137 add(new JMenuItem("New Motor") {
\r
138 private static final long serialVersionUID = 1L;
\r
140 addActionListener(new ActionListener() {
\r
143 public void actionPerformed(ActionEvent arg0) {
\r
144 Motor m = MotorEditor.defaultMotor();
\r
145 addFuel(m.getFuel());
\r
152 add(new JMenuItem("Open...") {
\r
153 private static final long serialVersionUID = 1L;
\r
155 addActionListener(new ActionListener() {
\r
157 public void actionPerformed(ActionEvent arg0) {
\r
159 final FileDialog fd = new FileDialog(MotorWorkbench.this, "Open Motor", FileDialog.LOAD);
\r
160 fd.setVisible(true);
\r
161 if ( fd.getFile() != null ) {
\r
162 File file = new File(fd.getDirectory() + fd.getFile());
\r
163 if (f2e.get(file) != null) {
\r
164 motors.setSelectedComponent(f2e
\r
171 addFuel(m.getFuel());
\r
174 } catch (Exception e) {
\r
175 JOptionPane.showMessageDialog(
\r
176 MotorWorkbench.this, e
\r
185 add(new JSeparator());
\r
187 add(new JMenuItem("Close Motor") {
\r
188 private static final long serialVersionUID = 1L;
\r
190 addActionListener(new ActionListener() {
\r
192 public void actionPerformed(ActionEvent ev) {
\r
193 MotorEditor e = (MotorEditor) motors
\r
194 .getSelectedComponent();
\r
195 tm.removeMotor(e.getMotor());
\r
197 f2e.remove(e2f.get(e));
\r
199 m2e.remove(e.getMotor());
\r
200 mb.removeBurn(e.burn);
\r
206 add(new JMenuItem("Save Motor") {
\r
207 private static final long serialVersionUID = 1L;
\r
209 addActionListener(new ActionListener() {
\r
211 public void actionPerformed(ActionEvent e) {
\r
212 MotorEditor m = (MotorEditor) motors
\r
213 .getSelectedComponent();
\r
214 File f = e2f.get(m);
\r
216 save(m.getMotor(), f);
\r
222 add(new JMenuItem("Save Motor As...") {
\r
223 private static final long serialVersionUID = 1L;
\r
225 addActionListener(new ActionListener() {
\r
227 public void actionPerformed(ActionEvent arg0) {
\r
229 final FileDialog fd = new FileDialog(MotorWorkbench.this, "Save Motor As", FileDialog.SAVE);
\r
230 fd.setVisible(true);
\r
231 if (fd.getFile() != null ) {
\r
232 File file = new File(fd.getDirectory() + fd.getFile());
\r
233 MotorEditor m = (MotorEditor) motors
\r
234 .getSelectedComponent();
\r
236 save(m.getMotor(), file);
\r
239 motors.setTitleAt(motors
\r
240 .getSelectedIndex(),
\r
242 // TODO Set tab title
\r
243 } catch (Exception e) {
\r
244 JOptionPane.showMessageDialog(
\r
245 MotorWorkbench.this, e
\r
255 add(new JSeparator());
\r
256 add(new JMenuItem("New Fuel") {
\r
257 private static final long serialVersionUID = 1L;
\r
259 addActionListener(new ActionListener() {
\r
261 public void actionPerformed(ActionEvent arg0) {
\r
268 add(new JMenuItem("Save Fuel") {
\r
269 private static final long serialVersionUID = 1L;
\r
271 add(new JSeparator());
\r
272 add(new JMenuItem("Export .ENG"){
\r
273 private static final long serialVersionUID = 1L;
\r
276 addActionListener(new ActionListener() {
\r
278 public void actionPerformed(ActionEvent arg0) {
\r
280 final FileDialog fd = new FileDialog(MotorWorkbench.this, "Export .ENG File", FileDialog.SAVE);
\r
281 fd.setFile("motorsim.eng");
\r
282 fd.setVisible(true);
\r
283 if (fd.getFile() != null ) {
\r
284 File file = new File(fd.getDirectory() + fd.getFile());
\r
285 Vector<Burn> bb = new Vector<Burn>();
\r
286 for( MotorEditor me : m2e.values() )
\r
289 ENGExporter.export(bb, file);
\r
290 } catch ( Exception e ){
\r
291 e.printStackTrace();
\r
300 add(new JMenu("Settings") {
\r
301 private static final long serialVersionUID = 1L;
\r
303 ButtonGroup units = new ButtonGroup();
\r
304 JRadioButtonMenuItem sci = new JRadioButtonMenuItem(
\r
306 JRadioButtonMenuItem nonsci = new JRadioButtonMenuItem(
\r
310 sci.setSelected(UnitPreference.getUnitPreference() == UnitPreference.SI);
\r
311 nonsci.setSelected(UnitPreference.getUnitPreference() == UnitPreference.NONSI);
\r
312 sci.addActionListener(new ActionListener() {
\r
313 public void actionPerformed(ActionEvent arg0) {
\r
315 .setUnitPreference(UnitPreference.SI);
\r
318 nonsci.addActionListener(new ActionListener() {
\r
319 public void actionPerformed(ActionEvent arg0) {
\r
321 .setUnitPreference(UnitPreference.NONSI);
\r
328 add(new JMenu("View") {
\r
329 private static final long serialVersionUID = 1L;
\r
331 add(new JMenuItem("Show All Motors Graph") {
\r
332 private static final long serialVersionUID = 1L;
\r
334 addActionListener(new ActionListener() {
\r
336 public void actionPerformed(ActionEvent arg0) {
\r
337 allBurns.setVisible(true);
\r
338 allBurns.toFront();
\r
349 private void addFuel(Fuel f){
\r
351 fuels.addElement(f);
\r
352 FuelPanel fp = new FuelPanel(f);
\r
353 FuelNode fn = tm.new FuelNode(fp, f);
\r
354 tm.getFuels().add(fn);
\r
355 tm.nodeStructureChanged(tm.getFuels());
\r
356 motors.addTab(f.getName(), fp);
\r
359 private void newFuel(){
\r
360 final SRFuelEditor ed = new SRFuelEditor();
\r
361 fuels.addElement(ed.getFuel());
\r
362 final FuelEditNode node = tm.new FuelEditNode(ed);
\r
363 tm.getFuels().add(node);
\r
364 tm.nodeStructureChanged(tm.getFuels());
\r
365 motors.addTab(ed.getFuel().getName(), ed);
\r
366 ed.getFuel().addPropertyChangeListener(new PropertyChangeListener(){
\r
368 public void propertyChange(PropertyChangeEvent evt) {
\r
369 if ( evt.getPropertyName().equals("Name")){
\r
370 for ( int i = 0; i < motors.getTabCount(); i++ ){
\r
371 if ( motors.getComponent(i) == ed ){
\r
372 motors.setTitleAt(i, ed.getFuel().getName());
\r
373 tm.nodeChanged(node);
\r
380 private void save(Motor m, File f) {
\r
382 MotorIO.writeMotor(m, f);
\r
383 } catch (Throwable t) {
\r
384 JOptionPane.showMessageDialog(MotorWorkbench.this, t.getMessage());
\r
388 public void addMotor(Motor m, File f) {
\r
390 MotorEditor e = new MotorEditor(m, fuels);
\r
391 e.addBurnWatcher(mb);
\r
394 title = "New Motor";
\r
396 title = f.getName();
\r
401 motors.addTab(title, e);
\r
405 public void valueChanged(TreeSelectionEvent e) {
\r
406 if ( e.getPath().getLastPathComponent() instanceof FuelNode ){
\r
407 FuelNode fen = ((FuelNode)e.getPath().getLastPathComponent());
\r
408 motors.setSelectedComponent(fen.getUserObject());
\r
411 Motor m = getMotor(e.getPath());
\r
416 motors.setSelectedComponent(m2e.get(m));
\r
418 if (e.getPath().getLastPathComponent() instanceof DefaultMutableTreeNode) {
\r
419 Object o = ((DefaultMutableTreeNode) e.getPath()
\r
420 .getLastPathComponent()).getUserObject();
\r
421 m2e.get(m).focusOnObject(o);
\r
427 private Motor getMotor(TreePath p) {
\r
428 if (p.getLastPathComponent() instanceof WorkbenchTreeModel.MotorNode) {
\r
429 return ((WorkbenchTreeModel.MotorNode) p.getLastPathComponent())
\r
431 } else if (p.getPath().length > 1)
\r
432 return getMotor(p.getParentPath());
\r