From 7746b6eae02518323b2a44ec8a1bf41174a4614e Mon Sep 17 00:00:00 2001 From: Bill Kuker Date: Tue, 14 Jul 2009 01:04:13 +0000 Subject: [PATCH] Better editor Made grain panel layout overridable by subclass --- .../rocketry/motorsim/visual/BurnPanel.java | 8 +- .../rocketry/motorsim/visual/GrainPanel.java | 48 +++- .../rocketry/motorsim/visual/MotorEditor.java | 264 +++++++++++------- .../motorsim/visual/MotorWorkbench.java | 91 ++++-- .../workbench/WorkbenchTreeCellRenderer.java | 33 +++ .../visual/workbench/WorkbenchTreeModel.java | 102 +++++++ 6 files changed, 410 insertions(+), 136 deletions(-) create mode 100644 src/com/billkuker/rocketry/motorsim/visual/workbench/WorkbenchTreeCellRenderer.java create mode 100644 src/com/billkuker/rocketry/motorsim/visual/workbench/WorkbenchTreeModel.java diff --git a/src/com/billkuker/rocketry/motorsim/visual/BurnPanel.java b/src/com/billkuker/rocketry/motorsim/visual/BurnPanel.java index 4fb45af..4715257 100644 --- a/src/com/billkuker/rocketry/motorsim/visual/BurnPanel.java +++ b/src/com/billkuker/rocketry/motorsim/visual/BurnPanel.java @@ -71,7 +71,13 @@ public class BurnPanel extends JPanel { tp.setDividerLocation(.5); tp.setResizeWeight(.5); - grain = new GrainPanel(burn.getMotor().getGrain()); + grain = new GrainPanel(burn.getMotor().getGrain()){ + @Override protected void addComponents(java.awt.Component crossSection, java.awt.Component slider, java.awt.Component label, java.awt.Component area, java.awt.Component volume) { + JSplitPane h = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, crossSection, area); + add(h, BorderLayout.CENTER); + h.resetToPreferredSizes(); + }; + }; JSplitPane grains = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, grain, burnRate); grains.setDividerLocation(.5); diff --git a/src/com/billkuker/rocketry/motorsim/visual/GrainPanel.java b/src/com/billkuker/rocketry/motorsim/visual/GrainPanel.java index 6fa3b34..5ace339 100644 --- a/src/com/billkuker/rocketry/motorsim/visual/GrainPanel.java +++ b/src/com/billkuker/rocketry/motorsim/visual/GrainPanel.java @@ -2,6 +2,7 @@ package com.billkuker.rocketry.motorsim.visual; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; @@ -82,20 +83,39 @@ public class GrainPanel extends JPanel { e.printStackTrace(); } + addComponents( + xc = new XC(grain), + new SL(), + l, + area, + volume + ); + } + + protected void addComponents( + Component crossSection, + Component slider, + Component label, + Component area, + Component volume + ){ - JSplitPane charts = new JSplitPane(JSplitPane.VERTICAL_SPLIT, area, volume); - charts.setDividerLocation(.5); - charts.setResizeWeight(.5); - - JPanel left = new JPanel(new BorderLayout()); + JSplitPane v = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + JSplitPane h = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); - add(xc = new XC(grain), BorderLayout.CENTER); - left.add(xc); - - left.add(l, BorderLayout.NORTH); - left.add( new SL(), BorderLayout.SOUTH); + JPanel graphics = new JPanel(new BorderLayout()); + graphics.add(crossSection, BorderLayout.CENTER); + graphics.add(label, BorderLayout.NORTH); + graphics.add(slider, BorderLayout.SOUTH); - add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, charts)); + v.setTopComponent(h); + v.setBottomComponent(area); + h.setLeftComponent(graphics); + h.setRightComponent(volume); + add(v); + + h.resetToPreferredSizes(); + v.resetToPreferredSizes(); } @@ -127,8 +147,10 @@ public class GrainPanel extends JPanel { if ( w < 40 ) w = 40; - setMinimumSize(new Dimension(240+w,250)); - + Dimension sz = new Dimension(240+w, 250); + setMinimumSize(sz); + setPreferredSize(sz); + setMaximumSize(sz); } public void paint(Graphics g){ super.paint(g); diff --git a/src/com/billkuker/rocketry/motorsim/visual/MotorEditor.java b/src/com/billkuker/rocketry/motorsim/visual/MotorEditor.java index 7c75b24..5044bf5 100644 --- a/src/com/billkuker/rocketry/motorsim/visual/MotorEditor.java +++ b/src/com/billkuker/rocketry/motorsim/visual/MotorEditor.java @@ -1,5 +1,6 @@ package com.billkuker.rocketry.motorsim.visual; +import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; @@ -26,6 +27,7 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.jscience.physics.amount.Amount; +import com.billkuker.rocketry.motorsim.Burn; import com.billkuker.rocketry.motorsim.Chamber; import com.billkuker.rocketry.motorsim.ConvergentDivergentNozzle; import com.billkuker.rocketry.motorsim.CylindricalChamber; @@ -34,6 +36,10 @@ import com.billkuker.rocketry.motorsim.Grain; import com.billkuker.rocketry.motorsim.Motor; import com.billkuker.rocketry.motorsim.MotorPart; import com.billkuker.rocketry.motorsim.Nozzle; +import com.billkuker.rocketry.motorsim.fuel.EditableFuel; +import com.billkuker.rocketry.motorsim.fuel.KNDX; +import com.billkuker.rocketry.motorsim.fuel.KNER; +import com.billkuker.rocketry.motorsim.fuel.KNSB; import com.billkuker.rocketry.motorsim.fuel.KNSU; import com.billkuker.rocketry.motorsim.grain.CoredCylindricalGrain; import com.billkuker.rocketry.motorsim.grain.Finocyl; @@ -42,31 +48,40 @@ import com.billkuker.rocketry.motorsim.grain.MultiGrain; import com.billkuker.rocketry.motorsim.grain.RodAndTubeGrain; import com.billkuker.rocketry.motorsim.io.MotorIO; -public class MotorEditor extends JTabbedPane implements PropertyChangeListener, DocumentListener{ +public class MotorEditor extends JTabbedPane implements PropertyChangeListener, + DocumentListener { private static final long serialVersionUID = 1L; RSyntaxTextArea text = new RSyntaxTextArea(); Motor motor; GrainEditor grainEditor; - - private class GrainChooser extends JPanel{ + BurnTab bt; + + private static final int XML_TAB = 0; + private static final int CASING_TAB = 1; + private static final int GRAIN_TAB = 2; + private static final int FUEL_TAB = 3; + private static final int BURN_TAB = 4; + + private Class[] grainTypes = { CoredCylindricalGrain.class, Finocyl.class, + Moonburner.class, RodAndTubeGrain.class }; + + private Class[] fuelTypes = { KNSB.class, KNSU.class, KNER.class, + KNDX.class, EditableFuel.class }; + + private abstract class Chooser extends JPanel { private static final long serialVersionUID = 1L; - @SuppressWarnings("unchecked") - private Class[] types = { - CoredCylindricalGrain.class, - Finocyl.class, - Moonburner.class, - RodAndTubeGrain.class - }; - @SuppressWarnings("unchecked") - public GrainChooser(){ + private Class[] types; + + public Chooser(Class... ts) { + types = ts; setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - for ( final Class c : types ){ + for (final Class c : types) { JButton b = new JButton(c.getSimpleName()); add(b); - b.addActionListener(new ActionListener(){ + b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { - grainChosen((Grain)c.newInstance()); + choiceMade(c.newInstance()); } catch (InstantiationException e1) { e1.printStackTrace(); } catch (IllegalAccessException e1) { @@ -76,152 +91,184 @@ public class MotorEditor extends JTabbedPane implements PropertyChangeListener, }); } } - protected void grainChosen(Grain g){ - System.out.println(g); + + protected abstract void choiceMade(T o); + } + + private class BurnTab extends JPanel { + public BurnTab() { + setLayout(new BorderLayout()); + setName("Burn"); + reBurn(); + } + + public void reBurn() { + removeAll(); + new Thread() { + public void run() { + final Burn b = new Burn(motor); + final BurnPanel bp = new BurnPanel(b); + SwingUtilities.invokeLater(new Thread() { + public void run() { + add(bp, BorderLayout.CENTER); + } + }); + } + }.start(); } } - - private class GrainEditor extends JSplitPane{ + + private class GrainEditor extends JSplitPane { private static final long serialVersionUID = 1L; - public GrainEditor(final Grain g){ + public GrainEditor(final Grain g) { super(JSplitPane.HORIZONTAL_SPLIT); + setName("Grain"); setRightComponent(new GrainPanel(g)); - if ( g instanceof Grain.Composite ){ + if (g instanceof Grain.Composite) { final JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); p.add(new Editor(g)); - for ( Grain gg : ((Grain.Composite)g).getGrains() ){ + for (Grain gg : ((Grain.Composite) g).getGrains()) { final int grainEditorIndex = p.getComponentCount() + 1; - p.add(new GrainChooser(){ - /** - * - */ + p.add(new Chooser(grainTypes) { private static final long serialVersionUID = 1L; @Override - protected void grainChosen(Grain ng){ - if ( g instanceof MultiGrain ){ + protected void choiceMade(Grain ng) { + if (g instanceof MultiGrain) { ((MultiGrain) g).setGrain(ng); p.remove(grainEditorIndex); p.add(new Editor(ng), grainEditorIndex); p.remove(0); p.add(new Editor(g), 0); - //System.out.println("Chose new grain"); + // System.out.println("Chose new grain"); } } }); p.add(new Editor(gg)); - if ( gg instanceof MotorPart ){ - ((MotorPart)gg).addPropertyChangeListener(MotorEditor.this); + if (gg instanceof MotorPart) { + ((MotorPart) gg) + .addPropertyChangeListener(MotorEditor.this); } } setLeftComponent(p); } else { setLeftComponent(new Editor(g)); } - setDividerLocation(.25); - setResizeWeight(.25); - if ( g instanceof MotorPart ){ - ((MotorPart)g).addPropertyChangeListener(MotorEditor.this); + // setDividerLocation(.25); + // setResizeWeight(.25); + if (g instanceof MotorPart) { + ((MotorPart) g).addPropertyChangeListener(MotorEditor.this); } } } - - private class FuelEditor extends JSplitPane{ - /** - * - */ + + private class FuelEditor extends JSplitPane { private static final long serialVersionUID = 1L; - public FuelEditor(Fuel f){ + public FuelEditor(Fuel f) { super(JSplitPane.HORIZONTAL_SPLIT); + setName("Fuel"); Chart burnRate; try { - burnRate = new Chart( - SI.MEGA(SI.PASCAL), - SI.METERS_PER_SECOND, - f, - "burnRate"); + burnRate = new Chart(SI.MEGA(SI.PASCAL), + SI.METERS_PER_SECOND, f, "burnRate"); } catch (NoSuchMethodException e) { throw new Error(e); } - burnRate.setDomain( - burnRate.new IntervalDomain( - Amount.valueOf(0, SI.MEGA(SI.PASCAL)), - Amount.valueOf(11, SI.MEGA(SI.PASCAL)), - 20 - )); - - setLeftComponent(new Editor(f)); + burnRate.setDomain(burnRate.new IntervalDomain(Amount.valueOf(0, SI + .MEGA(SI.PASCAL)), Amount.valueOf(11, SI.MEGA(SI.PASCAL)), + 20)); + + final JPanel p = new JPanel(); + p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); + + p.add(new Chooser(fuelTypes) { + @Override + protected void choiceMade(Fuel o) { + motor.setFuel(o); + removeTabAt(FUEL_TAB); + MotorEditor.this.add(new FuelEditor(motor.getFuel()), + FUEL_TAB); + setSelectedIndex(FUEL_TAB); + } + }); + p.add(new Editor(f)); + try { + p.add(new Editor(f.getCombustionProduct())); + } catch (Exception e) { + + } + + setLeftComponent(p); setRightComponent(burnRate); - setDividerLocation(.25); - setResizeWeight(.25); - if ( f instanceof MotorPart ){ - ((MotorPart)f).addPropertyChangeListener(MotorEditor.this); + // setDividerLocation(.25); + // setResizeWeight(.25); + if (f instanceof MotorPart) { + ((MotorPart) f).addPropertyChangeListener(MotorEditor.this); } } } - - private class CaseEditor extends JSplitPane{ - /** - * - */ + private class CaseEditor extends JSplitPane { private static final long serialVersionUID = 1L; - public CaseEditor(Nozzle n, Chamber c){ - super(JSplitPane.HORIZONTAL_SPLIT, - new JSplitPane(JSplitPane.VERTICAL_SPLIT, - new Editor(n), new Editor(c)), new NozzlePanel(n)); - JSplitPane parts = (JSplitPane)getLeftComponent(); - parts.setDividerLocation(.5); - parts.setResizeWeight(.5); - setDividerLocation(.25); - setResizeWeight(.25); - - if ( n instanceof MotorPart ){ - ((MotorPart)n).addPropertyChangeListener(MotorEditor.this); + public CaseEditor(Nozzle n, Chamber c) { + super(JSplitPane.HORIZONTAL_SPLIT); + setName("Casing"); + JPanel parts = new JPanel(); + parts.setLayout(new BoxLayout(parts, BoxLayout.Y_AXIS)); + setLeftComponent(parts); + setRightComponent(new NozzlePanel(n)); + + parts.add(new Editor(c)); + parts.add(new Editor(n)); + + if (n instanceof MotorPart) { + ((MotorPart) n).addPropertyChangeListener(MotorEditor.this); } - if ( c instanceof MotorPart ){ - ((MotorPart)c).addPropertyChangeListener(MotorEditor.this); + if (c instanceof MotorPart) { + ((MotorPart) c).addPropertyChangeListener(MotorEditor.this); } } } - + { text.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML); } - - public MotorEditor(Motor m){ + + public MotorEditor(Motor m) { super(JTabbedPane.BOTTOM); text.getDocument().addDocumentListener(this); - addTab("XML", text); + text.setName("XML"); + add(text, XML_TAB); setMotor(m, true); } - - private void reText(){ + + private void reText() { try { text.setText(MotorIO.writeMotor(motor)); } catch (IOException e) { throw new Error(e); } } - - private void setMotor(Motor m, boolean retext){ + + private void setMotor(Motor m, boolean retext) { motor = m; - if ( retext ) + if (retext) reText(); - if ( grainEditor != null) + if (grainEditor != null) remove(grainEditor); - while ( getTabCount() > 1 ) - removeTabAt(1); - add("Casing", new CaseEditor(motor.getNozzle(), motor.getChamber())); - add("Grain", new GrainEditor(motor.getGrain())); - add("Fuel", new FuelEditor(motor.getFuel())); + while (getTabCount() > 1) + removeTabAt(1); + add(new CaseEditor(motor.getNozzle(), motor.getChamber()), CASING_TAB); + add(new GrainEditor(motor.getGrain()), GRAIN_TAB); + add(new FuelEditor(motor.getFuel()), FUEL_TAB); + add(bt = new BurnTab(), BURN_TAB); } - + @Deprecated public static Motor defaultMotor() { Motor m = new Motor(); @@ -242,8 +289,7 @@ public class MotorEditor extends JTabbedPane implements PropertyChangeListener, throw new Error(v); } - m.setGrain(new MultiGrain(g,2)); - + m.setGrain(new MultiGrain(g, 2)); ConvergentDivergentNozzle n = new ConvergentDivergentNozzle(); n.setThroatDiameter(Amount.valueOf(7.962, SI.MILLIMETER)); @@ -253,17 +299,26 @@ public class MotorEditor extends JTabbedPane implements PropertyChangeListener, return m; } - + + public void focusOnObject(Object o) { + if (o instanceof Grain) + setSelectedIndex(GRAIN_TAB); + if (o instanceof Chamber || o instanceof Nozzle) + setSelectedIndex(CASING_TAB); + if (o instanceof Fuel || o instanceof Fuel.CombustionProduct) + setSelectedIndex(FUEL_TAB); + } + @Deprecated - public void showAsWindow(){ + public void showAsWindow() { JFrame f = new JFrame(); - f.setSize(1024,768); + f.setSize(1024, 768); f.setContentPane(this); f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); f.setVisible(true); } - - public static void main(String args[]) throws Exception{ + + public static void main(String args[]) throws Exception { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e1) { @@ -274,19 +329,20 @@ public class MotorEditor extends JTabbedPane implements PropertyChangeListener, public void propertyChange(PropertyChangeEvent evt) { reText(); + bt.reBurn(); } - public void changedUpdate(DocumentEvent e) { try { final Motor m = MotorIO.readMotor(text.getText()); - SwingUtilities.invokeLater(new Runnable(){ + SwingUtilities.invokeLater(new Runnable() { public void run() { setMotor(m, false); - }}); + } + }); System.out.println("Motor Updated"); } catch (Throwable e1) { - //Leave blank, motor might be broken + // Leave blank, motor might be broken } } diff --git a/src/com/billkuker/rocketry/motorsim/visual/MotorWorkbench.java b/src/com/billkuker/rocketry/motorsim/visual/MotorWorkbench.java index 0158dcd..d497e2d 100644 --- a/src/com/billkuker/rocketry/motorsim/visual/MotorWorkbench.java +++ b/src/com/billkuker/rocketry/motorsim/visual/MotorWorkbench.java @@ -1,49 +1,83 @@ package com.billkuker.rocketry.motorsim.visual; import java.awt.BorderLayout; +import java.awt.Dimension; +import java.util.HashMap; -import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; +import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JToolBar; import javax.swing.JTree; import javax.swing.UIManager; import javax.swing.WindowConstants; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; -public class MotorWorkbench extends JFrame { +import com.billkuker.rocketry.motorsim.Motor; +import com.billkuker.rocketry.motorsim.visual.workbench.WorkbenchTreeCellRenderer; +import com.billkuker.rocketry.motorsim.visual.workbench.WorkbenchTreeModel; + +public class MotorWorkbench extends JFrame implements TreeSelectionListener { + private static final long serialVersionUID = 1L; private JPanel top; private JSplitPane split; private JTree tree; private JTabbedPane motors; private JToolBar bar; - public MotorWorkbench(){ - setSize(1024,768); - top = new JPanel( new BorderLayout()); + private WorkbenchTreeModel tm; + + private HashMap m2e = new HashMap(); + + public MotorWorkbench() { + setSize(1024, 768); + top = new JPanel(new BorderLayout()); setContentPane(top); - + bar = new JToolBar(); bar.add(new JButton("Burn")); top.add(bar, BorderLayout.PAGE_START); - + motors = new JTabbedPane(); - motors.addTab("Motor 1", new MotorEditor(MotorEditor.defaultMotor())); - motors.addTab("Motor 2", new MotorEditor(MotorEditor.defaultMotor())); - - tree = new JTree(); - - split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, tree, motors); - split.setDividerLocation(.25); - split.setResizeWeight(.25); + + tree = new JTree(tm = new WorkbenchTreeModel()); + tree.setCellRenderer(new WorkbenchTreeCellRenderer()); + tree.getSelectionModel().setSelectionMode( + TreeSelectionModel.SINGLE_TREE_SELECTION); + tree.setPreferredSize(new Dimension(200, 100)); + + // Listen for when the selection changes. + tree.addTreeSelectionListener(this); + + split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane( + tree), motors); + //split.setDividerLocation(.25); + //split.setResizeWeight(.25); top.add(split, BorderLayout.CENTER); - + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); setVisible(true); + + Motor mot = MotorEditor.defaultMotor(); + addMotor(mot); + //mot = MotorEditor.defaultMotor(); + //addMotor(mot); + } + + public void addMotor(Motor m) { + tm.addMotor(m); + MotorEditor e = new MotorEditor(m); + m2e.put(m, e); + motors.addTab("Motor", e); } - - public static void main(String args[]) throws Exception{ + + public static void main(String args[]) throws Exception { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e1) { @@ -51,4 +85,25 @@ public class MotorWorkbench extends JFrame { } new MotorWorkbench().show(); } + + @Override + public void valueChanged(TreeSelectionEvent e) { + Motor m = getMotor(e.getPath()); + + motors.setSelectedComponent(m2e.get(m)); + + if ( e.getPath().getLastPathComponent() instanceof DefaultMutableTreeNode ){ + Object o = ((DefaultMutableTreeNode)e.getPath().getLastPathComponent()).getUserObject(); + m2e.get(m).focusOnObject(o); + } + } + + private Motor getMotor(TreePath p) { + if (p.getLastPathComponent() instanceof WorkbenchTreeModel.MotorNode) { + return ((WorkbenchTreeModel.MotorNode) p.getLastPathComponent()) + .getUserObject(); + } else if (p.getPath().length > 1) + return getMotor(p.getParentPath()); + return null; + } } diff --git a/src/com/billkuker/rocketry/motorsim/visual/workbench/WorkbenchTreeCellRenderer.java b/src/com/billkuker/rocketry/motorsim/visual/workbench/WorkbenchTreeCellRenderer.java new file mode 100644 index 0000000..4157d1b --- /dev/null +++ b/src/com/billkuker/rocketry/motorsim/visual/workbench/WorkbenchTreeCellRenderer.java @@ -0,0 +1,33 @@ +package com.billkuker.rocketry.motorsim.visual.workbench; + +import java.awt.Component; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; + +import com.billkuker.rocketry.motorsim.Motor; + +public class WorkbenchTreeCellRenderer extends DefaultTreeCellRenderer { + private static final long serialVersionUID = 1L; + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, + boolean sel, boolean expanded, boolean leaf, int row, + boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, + row, hasFocus); + if (value instanceof DefaultMutableTreeNode) { + value = ((DefaultMutableTreeNode) value).getUserObject(); + } + if (value instanceof Motor) { + setText(((Motor) value).getName()); + } else if ( value == null ) { + setText(""); + } else { + setText(value.getClass().getSimpleName()); + } + + return this; + } +} diff --git a/src/com/billkuker/rocketry/motorsim/visual/workbench/WorkbenchTreeModel.java b/src/com/billkuker/rocketry/motorsim/visual/workbench/WorkbenchTreeModel.java new file mode 100644 index 0000000..1bb769e --- /dev/null +++ b/src/com/billkuker/rocketry/motorsim/visual/workbench/WorkbenchTreeModel.java @@ -0,0 +1,102 @@ +package com.billkuker.rocketry.motorsim.visual.workbench; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +import com.billkuker.rocketry.motorsim.Motor; +import com.billkuker.rocketry.motorsim.MotorPart; +import com.billkuker.rocketry.motorsim.grain.MultiGrain; + +public class WorkbenchTreeModel extends DefaultTreeModel { + + private static final long serialVersionUID = 1L; + + public class MultiGrainNode extends PartNode{ + private static final long serialVersionUID = 1L; + public MultiGrainNode(MultiGrain part) { + super(part); + setAllowsChildren(true); + add(new PartNode(part.getGrain())); + } + @Override + public void propertyChange(PropertyChangeEvent e) { + if ( e.getPropertyName().equals("Grain")){ + remove(0); + add(new PartNode(((MultiGrain)getUserObject()).getGrain())); + nodesChanged(this, new int[]{0}); + } + super.propertyChange(e); + } + } + + public class PartNode extends DefaultMutableTreeNode implements PropertyChangeListener { + private static final long serialVersionUID = 1L; + + public PartNode(Object part) { + super(part, false); + if (part instanceof MotorPart) { + ((MotorPart) part).addPropertyChangeListener(this); + } + } + + @Override + public void propertyChange(PropertyChangeEvent e) { + nodeChanged(this); + } + + } + + public class MotorNode extends DefaultMutableTreeNode implements PropertyChangeListener { + private static final long serialVersionUID = 1L; + Motor motor; + PartNode cn, nn, gn, fn; + + public MotorNode(Motor m) { + super(m); + motor = m; + add( cn = new PartNode(m.getChamber())); + add( nn = new PartNode(m.getNozzle())); + if ( m.getGrain() instanceof MultiGrain ){ + gn = new MultiGrainNode(((MultiGrain)m.getGrain())); + } else { + gn = new PartNode(m.getGrain()); + } + add(gn); + add( fn = new PartNode(m.getFuel())); + if (m instanceof MotorPart) { + ((MotorPart) m).addPropertyChangeListener(this); + } + } + + @Override + public Motor getUserObject(){ + return (Motor)super.getUserObject(); + } + + @Override + public void propertyChange(PropertyChangeEvent e) { + if ( e.getPropertyName().equals("Fuel")){ + fn = new PartNode(motor.getFuel()); + remove(3); + add(fn); + nodesChanged(this, new int[]{3}); + } + } + + } + + public WorkbenchTreeModel() { + super(new DefaultMutableTreeNode(), true); + } + + public void addMotor(Motor m){ + DefaultMutableTreeNode root = (DefaultMutableTreeNode)getRoot(); + root.add(new MotorNode(m)); + nodesWereInserted(root, new int[]{root.getChildCount()-1}); + + } + +} -- 2.47.2