SafetyMutex and rocket optimization updates
[debian/openrocket] / src / net / sf / openrocket / gui / configdialog / RocketComponentConfig.java
index 4bca3bd6433da6400877c3b3caa753d27cdd45ed..d6d607463ebfec9e5cdb30ddc5f17b976e740bb6 100644 (file)
@@ -8,7 +8,9 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 
 import javax.swing.BorderFactory;
 import javax.swing.Icon;
@@ -32,54 +34,57 @@ import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.MaterialModel;
 import net.sf.openrocket.gui.components.BasicSlider;
 import net.sf.openrocket.gui.components.StyledLabel;
-import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.components.StyledLabel.Style;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.ComponentAssembly;
 import net.sf.openrocket.rocketcomponent.ExternalComponent;
+import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
 import net.sf.openrocket.rocketcomponent.NoseCone;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.GUIUtil;
+import net.sf.openrocket.util.Invalidatable;
 import net.sf.openrocket.util.LineStyle;
 import net.sf.openrocket.util.Prefs;
 
 public class RocketComponentConfig extends JPanel {
-
+       
        protected final RocketComponent component;
        protected final JTabbedPane tabbedPane;
        
+       private final List<Invalidatable> invalidatables = new ArrayList<Invalidatable>();
        
+
        protected final JTextField componentNameField;
        protected JTextArea commentTextArea;
        private final TextFieldListener textFieldListener;
        private JButton colorButton;
        private JCheckBox colorDefault;
        private JPanel buttonPanel;
-
+       
        private JLabel massLabel;
        
        
        public RocketComponentConfig(RocketComponent component) {
-               setLayout(new MigLayout("fill","[grow, fill]"));
+               setLayout(new MigLayout("fill", "[grow, fill]"));
                this.component = component;
                
                JLabel label = new JLabel("Component name:");
                label.setToolTipText("The component name.");
-               this.add(label,"split, gapright 10");
+               this.add(label, "split, gapright 10");
                
                componentNameField = new JTextField(15);
                textFieldListener = new TextFieldListener();
                componentNameField.addActionListener(textFieldListener);
                componentNameField.addFocusListener(textFieldListener);
                componentNameField.setToolTipText("The component name.");
-               this.add(componentNameField,"growx, growy 0, wrap");
-               
+               this.add(componentNameField, "growx, growy 0, wrap");
                
+
                tabbedPane = new JTabbedPane();
-               this.add(tabbedPane,"growx, growy 1, wrap");
+               this.add(tabbedPane, "growx, growy 1, wrap");
                
                tabbedPane.addTab("Override", null, overrideTab(), "Mass and CG override options");
                if (component.isMassive())
@@ -102,7 +107,7 @@ public class RocketComponentConfig extends JPanel {
                massLabel = new StyledLabel("Mass: ", -1);
                buttonPanel.add(massLabel, "growx");
                
-               for (JButton b: buttons) {
+               for (JButton b : buttons) {
                        buttonPanel.add(b, "right, gap para");
                }
                
@@ -132,9 +137,9 @@ public class RocketComponentConfig extends JPanel {
                // Component color and "Use default color" checkbox
                if (colorButton != null && colorDefault != null) {
                        colorButton.setIcon(new ColorIcon(component.getColor()));
-               
-                       if ((component.getColor()==null) != colorDefault.isSelected())
-                               colorDefault.setSelected(component.getColor()==null);
+                       
+                       if ((component.getColor() == null) != colorDefault.isSelected())
+                               colorDefault.setSelected(component.getColor() == null);
                }
                
                // Mass label
@@ -146,7 +151,7 @@ public class RocketComponentConfig extends JPanel {
                        String overridetext = null;
                        if (component.isMassOverridden()) {
                                overridetext = "(overridden to " + UnitGroup.UNITS_MASS.getDefaultUnit().
-                                       toStringUnit(component.getOverrideMass()) + ")";
+                                               toStringUnit(component.getOverrideMass()) + ")";
                        }
                        
                        for (RocketComponent c = component.getParent(); c != null; c = c.getParent()) {
@@ -173,31 +178,31 @@ public class RocketComponentConfig extends JPanel {
                        String materialString, String finishString) {
                JLabel label = new JLabel(materialString);
                label.setToolTipText("The component material affects the weight of the component.");
-               panel.add(label,"spanx 4, wrap rel");
+               panel.add(label, "spanx 4, wrap rel");
                
                JComboBox combo = new JComboBox(new MaterialModel(panel, component, type));
                combo.setToolTipText("The component material affects the weight of the component.");
-               panel.add(combo,"spanx 4, growx, wrap paragraph");
-               
+               panel.add(combo, "spanx 4, growx, wrap paragraph");
                
+
                if (component instanceof ExternalComponent) {
                        label = new JLabel(finishString);
-                       String tip = "<html>The component finish affects the aerodynamic drag of the " 
-                               +"component.<br>" 
-                               + "The value indicated is the average roughness height of the surface.";
+                       String tip = "<html>The component finish affects the aerodynamic drag of the "
+                                       + "component.<br>"
+                                       + "The value indicated is the average roughness height of the surface.";
                        label.setToolTipText(tip);
-                       panel.add(label,"spanx 4, wmin 220lp, wrap rel");
+                       panel.add(label, "spanx 4, wmin 220lp, wrap rel");
                        
-                       combo = new JComboBox(new EnumModel<ExternalComponent.Finish>(component,"Finish"));
+                       combo = new JComboBox(new EnumModel<ExternalComponent.Finish>(component, "Finish"));
                        combo.setToolTipText(tip);
-                       panel.add(combo,"spanx 4, growx, split");
+                       panel.add(combo, "spanx 4, growx, split");
                        
                        JButton button = new JButton("Set for all");
                        button.setToolTipText("Set this finish for all components of the rocket.");
                        button.addActionListener(new ActionListener() {
                                @Override
                                public void actionPerformed(ActionEvent e) {
-                                       Finish f = ((ExternalComponent)component).getFinish();
+                                       Finish f = ((ExternalComponent) component).getFinish();
                                        Rocket rocket = component.getRocket();
                                        try {
                                                rocket.freeze();
@@ -205,11 +210,11 @@ public class RocketComponentConfig extends JPanel {
                                                String desc = ComponentConfigDialog.getUndoDescription();
                                                ComponentConfigDialog.addUndoPosition("Set rocket finish");
                                                // Do changes
-                                               Iterator<RocketComponent> iter = rocket.deepIterator();
+                                               Iterator<RocketComponent> iter = rocket.iterator();
                                                while (iter.hasNext()) {
                                                        RocketComponent c = iter.next();
                                                        if (c instanceof ExternalComponent) {
-                                                               ((ExternalComponent)c).setFinish(f);
+                                                               ((ExternalComponent) c).setFinish(f);
                                                        }
                                                }
                                                // Restore undo description
@@ -228,51 +233,51 @@ public class RocketComponentConfig extends JPanel {
        
        private JPanel overrideTab() {
                JPanel panel = new JPanel(new MigLayout("align 50% 20%, fillx, gap rel unrel",
-                               "[][65lp::][30lp::][]",""));
+                               "[][65lp::][30lp::][]", ""));
                
                panel.add(new StyledLabel("Override the mass or center of gravity of the " +
-                               component.getComponentName() + ":", Style.BOLD),"spanx, wrap 20lp");
-
+                               component.getComponentName() + ":", Style.BOLD), "spanx, wrap 20lp");
+               
                JCheckBox check;
                BooleanModel bm;
                UnitSelector us;
                BasicSlider bs;
-
+               
                ////  Mass
                bm = new BooleanModel(component, "MassOverridden");
                check = new JCheckBox(bm);
                check.setText("Override mass:");
                panel.add(check, "growx 1, gapright 20lp");
                
-               DoubleModel m = new DoubleModel(component,"OverrideMass",UnitGroup.UNITS_MASS,0);
+               DoubleModel m = new DoubleModel(component, "OverrideMass", UnitGroup.UNITS_MASS, 0);
                
                JSpinner spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
                bm.addEnableComponent(spin, true);
-               panel.add(spin,"growx 1");
+               panel.add(spin, "growx 1");
                
                us = new UnitSelector(m);
                bm.addEnableComponent(us, true);
-               panel.add(us,"growx 1");
+               panel.add(us, "growx 1");
                
                bs = new BasicSlider(m.getSliderModel(0, 0.03, 1.0));
                bm.addEnableComponent(bs);
-               panel.add(bs,"growx 5, w 100lp, wrap");
-               
+               panel.add(bs, "growx 5, w 100lp, wrap");
                
+
                ////  CG override
                bm = new BooleanModel(component, "CGOverridden");
                check = new JCheckBox(bm);
                check.setText("Override center of gravity:");
                panel.add(check, "growx 1, gapright 20lp");
                
-               m = new DoubleModel(component,"OverrideCGX",UnitGroup.UNITS_LENGTH,0);
+               m = new DoubleModel(component, "OverrideCGX", UnitGroup.UNITS_LENGTH, 0);
                // Calculate suitable length for slider
                DoubleModel length;
                if (component instanceof ComponentAssembly) {
-                       double l=0;
+                       double l = 0;
                        
-                       Iterator<RocketComponent> iterator = component.deepIterator();
+                       Iterator<RocketComponent> iterator = component.iterator(false);
                        while (iterator.hasNext()) {
                                RocketComponent c = iterator.next();
                                if (c.getRelativePosition() == RocketComponent.Position.AFTER)
@@ -280,23 +285,23 @@ public class RocketComponentConfig extends JPanel {
                        }
                        length = new DoubleModel(l);
                } else {
-                       length = new DoubleModel(component, "Length", UnitGroup.UNITS_LENGTH,0);
+                       length = new DoubleModel(component, "Length", UnitGroup.UNITS_LENGTH, 0);
                }
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
                bm.addEnableComponent(spin, true);
-               panel.add(spin,"growx 1");
+               panel.add(spin, "growx 1");
                
                us = new UnitSelector(m);
                bm.addEnableComponent(us, true);
-               panel.add(us,"growx 1");
+               panel.add(us, "growx 1");
                
                bs = new BasicSlider(m.getSliderModel(new DoubleModel(0), length));
                bm.addEnableComponent(bs);
-               panel.add(bs,"growx 5, w 100lp, wrap 35lp");
-               
+               panel.add(bs, "growx 5, w 100lp, wrap 35lp");
                
+
                // Override subcomponents checkbox
                bm = new BooleanModel(component, "OverrideSubcomponents");
                check = new JCheckBox(bm);
@@ -306,7 +311,7 @@ public class RocketComponentConfig extends JPanel {
 
                panel.add(new StyledLabel("<html>The overridden mass does not include motors.<br>" +
                                "The center of gravity is measured from the front end of the " +
-                               component.getComponentName().toLowerCase()+".", -1),
+                               component.getComponentName().toLowerCase() + ".", -1),
                                "spanx, wrap, gap para, height 0::30lp");
                
                return panel;
@@ -316,7 +321,7 @@ public class RocketComponentConfig extends JPanel {
        private JPanel commentTab() {
                JPanel panel = new JPanel(new MigLayout("fill"));
                
-               panel.add(new StyledLabel("Comments on the "+component.getComponentName()+":", 
+               panel.add(new StyledLabel("Comments on the " + component.getComponentName() + ":",
                                Style.BOLD), "wrap");
                
                // TODO: LOW:  Changes in comment from other sources not reflected in component
@@ -332,18 +337,19 @@ public class RocketComponentConfig extends JPanel {
                return panel;
        }
        
-
+       
 
        private JPanel figureTab() {
                JPanel panel = new JPanel(new MigLayout("align 20% 20%"));
                
                panel.add(new StyledLabel("Figure style:", Style.BOLD), "wrap para");
                
-               
+
                panel.add(new JLabel("Component color:"), "gapleft para, gapright 10lp");
                
                colorButton = new JButton(new ColorIcon(component.getColor()));
                colorButton.addActionListener(new ActionListener() {
+                       @Override
                        public void actionPerformed(ActionEvent e) {
                                Color c = component.getColor();
                                if (c == null) {
@@ -351,7 +357,7 @@ public class RocketComponentConfig extends JPanel {
                                }
                                
                                c = JColorChooser.showDialog(tabbedPane, "Choose color", c);
-                               if (c!=null) {
+                               if (c != null) {
                                        component.setColor(c);
                                }
                        }
@@ -359,7 +365,7 @@ public class RocketComponentConfig extends JPanel {
                panel.add(colorButton, "gapright 10lp");
                
                colorDefault = new JCheckBox("Use default color");
-               if (component.getColor()==null)
+               if (component.getColor() == null)
                        colorDefault.setSelected(true);
                colorDefault.addActionListener(new ActionListener() {
                        @Override
@@ -372,17 +378,17 @@ public class RocketComponentConfig extends JPanel {
                });
                panel.add(colorDefault, "wrap para");
                
-               
-               panel.add(new JLabel("Component line style:"), "gapleft para, gapright 10lp");
 
-               LineStyle[] list = new LineStyle[LineStyle.values().length+1];
+               panel.add(new JLabel("Component line style:"), "gapleft para, gapright 10lp");
+               
+               LineStyle[] list = new LineStyle[LineStyle.values().length + 1];
                System.arraycopy(LineStyle.values(), 0, list, 1, LineStyle.values().length);
-
+               
                JComboBox combo = new JComboBox(new EnumModel<LineStyle>(component, "LineStyle",
                                list, "Default style"));
                panel.add(combo, "spanx 2, growx, wrap 50lp");
                
-               
+
                JButton button = new JButton("Save as default style");
                button.addActionListener(new ActionListener() {
                        @Override
@@ -401,10 +407,10 @@ public class RocketComponentConfig extends JPanel {
                
                return panel;
        }
-
        
        
 
+
        protected JPanel shoulderTab() {
                JPanel panel = new JPanel(new MigLayout("fill"));
                JPanel sub;
@@ -414,146 +420,153 @@ public class RocketComponentConfig extends JPanel {
                JCheckBox check;
                JSpinner spin;
                
-               
+
                ////  Fore shoulder, not for NoseCone
                
                if (!(component instanceof NoseCone)) {
-                       sub = new JPanel(new MigLayout("gap rel unrel","[][65lp::][30lp::]",""));
+                       sub = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
                        
                        sub.setBorder(BorderFactory.createTitledBorder("Fore shoulder"));
-
                        
+
                        ////  Radius
                        sub.add(new JLabel("Diameter:"));
                        
-                       m = new DoubleModel(component,"ForeShoulderRadius",2,UnitGroup.UNITS_LENGTH,0);
-                       m2 = new DoubleModel(component,"ForeRadius",2,UnitGroup.UNITS_LENGTH);
+                       m = new DoubleModel(component, "ForeShoulderRadius", 2, UnitGroup.UNITS_LENGTH, 0);
+                       m2 = new DoubleModel(component, "ForeRadius", 2, UnitGroup.UNITS_LENGTH);
                        
                        spin = new JSpinner(m.getSpinnerModel());
                        spin.setEditor(new SpinnerEditor(spin));
-                       sub.add(spin,"growx");
-                       
-                       sub.add(new UnitSelector(m),"growx");
-                       sub.add(new BasicSlider(m.getSliderModel(m0, m2)),"w 100lp, wrap");
+                       sub.add(spin, "growx");
                        
+                       sub.add(new UnitSelector(m), "growx");
+                       sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
                        
+
                        ////  Length
                        sub.add(new JLabel("Length:"));
                        
-                       m = new DoubleModel(component,"ForeShoulderLength",UnitGroup.UNITS_LENGTH,0);
+                       m = new DoubleModel(component, "ForeShoulderLength", UnitGroup.UNITS_LENGTH, 0);
                        
                        spin = new JSpinner(m.getSpinnerModel());
                        spin.setEditor(new SpinnerEditor(spin));
-                       sub.add(spin,"growx");
+                       sub.add(spin, "growx");
                        
-                       sub.add(new UnitSelector(m),"growx");
-                       sub.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.2)),"w 100lp, wrap");
+                       sub.add(new UnitSelector(m), "growx");
+                       sub.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.2)), "w 100lp, wrap");
                        
 
                        ////  Thickness
                        sub.add(new JLabel("Thickness:"));
                        
-                       m = new DoubleModel(component,"ForeShoulderThickness",UnitGroup.UNITS_LENGTH,0);
-                       m2 = new DoubleModel(component,"ForeShoulderRadius",UnitGroup.UNITS_LENGTH);
-
+                       m = new DoubleModel(component, "ForeShoulderThickness", UnitGroup.UNITS_LENGTH, 0);
+                       m2 = new DoubleModel(component, "ForeShoulderRadius", UnitGroup.UNITS_LENGTH);
+                       
                        spin = new JSpinner(m.getSpinnerModel());
                        spin.setEditor(new SpinnerEditor(spin));
-                       sub.add(spin,"growx");
-                       
-                       sub.add(new UnitSelector(m),"growx");
-                       sub.add(new BasicSlider(m.getSliderModel(m0, m2)),"w 100lp, wrap");
+                       sub.add(spin, "growx");
                        
+                       sub.add(new UnitSelector(m), "growx");
+                       sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
                        
+
                        ////  Capped
                        bm = new BooleanModel(component, "ForeShoulderCapped");
                        check = new JCheckBox(bm);
                        check.setText("End capped");
                        check.setToolTipText("Whether the end of the shoulder is capped.");
                        sub.add(check, "spanx");
-
                        
+
                        panel.add(sub);
                }
                
-               
+
                ////  Aft shoulder
-               sub = new JPanel(new MigLayout("gap rel unrel","[][65lp::][30lp::]",""));
+               sub = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
                
                if (component instanceof NoseCone)
                        sub.setBorder(BorderFactory.createTitledBorder("Nose cone shoulder"));
                else
                        sub.setBorder(BorderFactory.createTitledBorder("Aft shoulder"));
-
                
+
                ////  Radius
                sub.add(new JLabel("Diameter:"));
                
-               m = new DoubleModel(component,"AftShoulderRadius",2,UnitGroup.UNITS_LENGTH,0);
-               m2 = new DoubleModel(component,"AftRadius",2,UnitGroup.UNITS_LENGTH);
+               m = new DoubleModel(component, "AftShoulderRadius", 2, UnitGroup.UNITS_LENGTH, 0);
+               m2 = new DoubleModel(component, "AftRadius", 2, UnitGroup.UNITS_LENGTH);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
-               sub.add(spin,"growx");
-               
-               sub.add(new UnitSelector(m),"growx");
-               sub.add(new BasicSlider(m.getSliderModel(m0, m2)),"w 100lp, wrap");
+               sub.add(spin, "growx");
                
+               sub.add(new UnitSelector(m), "growx");
+               sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
                
+
                ////  Length
                sub.add(new JLabel("Length:"));
                
-               m = new DoubleModel(component,"AftShoulderLength",UnitGroup.UNITS_LENGTH,0);
+               m = new DoubleModel(component, "AftShoulderLength", UnitGroup.UNITS_LENGTH, 0);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
-               sub.add(spin,"growx");
+               sub.add(spin, "growx");
                
-               sub.add(new UnitSelector(m),"growx");
-               sub.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.2)),"w 100lp, wrap");
+               sub.add(new UnitSelector(m), "growx");
+               sub.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.2)), "w 100lp, wrap");
                
 
                ////  Thickness
                sub.add(new JLabel("Thickness:"));
                
-               m = new DoubleModel(component,"AftShoulderThickness",UnitGroup.UNITS_LENGTH,0);
-               m2 = new DoubleModel(component,"AftShoulderRadius",UnitGroup.UNITS_LENGTH);
-
+               m = new DoubleModel(component, "AftShoulderThickness", UnitGroup.UNITS_LENGTH, 0);
+               m2 = new DoubleModel(component, "AftShoulderRadius", UnitGroup.UNITS_LENGTH);
+               
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
-               sub.add(spin,"growx");
-               
-               sub.add(new UnitSelector(m),"growx");
-               sub.add(new BasicSlider(m.getSliderModel(m0, m2)),"w 100lp, wrap");
+               sub.add(spin, "growx");
                
+               sub.add(new UnitSelector(m), "growx");
+               sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
                
+
                ////  Capped
                bm = new BooleanModel(component, "AftShoulderCapped");
                check = new JCheckBox(bm);
                check.setText("End capped");
                check.setToolTipText("Whether the end of the shoulder is capped.");
                sub.add(check, "spanx");
-
                
-               panel.add(sub);
 
+               panel.add(sub);
                
+
                return panel;
        }
        
        
-       
-       
+
+
        /*
         * Private inner class to handle events in componentNameField.
         */
        private class TextFieldListener implements ActionListener, FocusListener {
+               @Override
                public void actionPerformed(ActionEvent e) {
                        setName();
                }
-               public void focusGained(FocusEvent e) { }
+               
+               @Override
+               public void focusGained(FocusEvent e) {
+               }
+               
+               @Override
                public void focusLost(FocusEvent e) {
                        setName();
                }
+               
                private void setName() {
                        if (!component.getName().equals(componentNameField.getText())) {
                                component.setName(componentNameField.getText());
@@ -576,15 +589,15 @@ public class RocketComponentConfig extends JPanel {
                public int getIconHeight() {
                        return 15;
                }
-
+               
                @Override
                public int getIconWidth() {
                        return 25;
                }
-
+               
                @Override
                public void paintIcon(Component c, Graphics g, int x, int y) {
-                       if (color==null) {
+                       if (color == null) {
                                g.setColor(Prefs.getDefaultColor(component.getClass()));
                        } else {
                                g.setColor(color);
@@ -594,4 +607,14 @@ public class RocketComponentConfig extends JPanel {
                
        }
        
+       protected void register(Invalidatable model) {
+               this.invalidatables.add(model);
+       }
+       
+       public void invalidateModels() {
+               for (Invalidatable i : invalidatables) {
+                       i.invalidate();
+               }
+       }
+       
 }