From 855deb11fce9b1e877e08033a4f0ef72e612935e Mon Sep 17 00:00:00 2001 From: Sibo Van Gool Date: Tue, 17 Aug 2021 17:02:57 +0200 Subject: [PATCH 1/3] [fixes #871] Disable automatic checkbox upon no reference component --- .../gui/configdialog/BodyTubeConfig.java | 27 ++++++++++++--- .../gui/configdialog/NoseConeConfig.java | 17 ++++++++++ .../gui/configdialog/TransitionConfig.java | 34 +++++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java index e0949a142..677e5778b 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java @@ -5,6 +5,8 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; @@ -15,7 +17,9 @@ import net.sf.openrocket.gui.components.BasicSlider; import net.sf.openrocket.gui.components.UnitSelector; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.BodyTube; import net.sf.openrocket.rocketcomponent.MotorMount; +import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.UnitGroup; @@ -58,9 +62,24 @@ public class BodyTubeConfig extends RocketComponentConfig { //// Automatic javax.swing.Action outerAutoAction = od.getAutomaticAction(); - JCheckBox check = new JCheckBox(outerAutoAction); - check.setText(trans.get("BodyTubecfg.checkbox.Automatic")); - panel.add(check, "skip, span 2, wrap"); + JCheckBox checkAuto = new JCheckBox(outerAutoAction); + checkAuto.setText(trans.get("BodyTubecfg.checkbox.Automatic")); + panel.add(checkAuto, "skip, span 2, wrap"); + // Disable check button if there is no component to get the diameter from + checkAuto.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + if (!(c instanceof BodyTube)) return; + if (((BodyTube) c).getPreviousSymmetricComponent() != null) { + checkAuto.setEnabled(true); + } + else { + checkAuto.setEnabled(false); + ((BodyTube) c).setOuterRadiusAutomatic(false); + } + } + }); + checkAuto.getChangeListeners()[0].stateChanged(null); //// Inner diameter panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Innerdiameter"))); @@ -87,7 +106,7 @@ public class BodyTubeConfig extends RocketComponentConfig { panel.add(new BasicSlider(thicknessModel.getSliderModel(0, 0.01)), "w 100lp, wrap 0px"); //// Filled - check = new JCheckBox(new BooleanModel(component, "Filled")); + JCheckBox check = new JCheckBox(new BooleanModel(component, "Filled")); check.setText(trans.get("BodyTubecfg.checkbox.Filled")); panel.add(check, "skip, span 2, wrap"); diff --git a/swing/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java index f4c174c79..d8f8332a7 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java @@ -10,6 +10,8 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JSpinner; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; @@ -113,6 +115,21 @@ public class NoseConeConfig extends RocketComponentConfig { //// Automatic check.setText(trans.get("NoseConeCfg.checkbox.Automatic")); panel.add(check, "skip, span 2, wrap"); + // Disable check button if there is no component to get the diameter from + check.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + if (!(c instanceof NoseCone)) return; + if (((NoseCone) c).getNextSymmetricComponent() != null) { + check.setEnabled(true); + } + else { + check.setEnabled(false); + ((NoseCone) c).setAftRadiusAutomatic(false); + } + } + }); + check.getChangeListeners()[0].stateChanged(null); } {//// Wall thickness: diff --git a/swing/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java index 5b2b11c9c..90178611f 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java @@ -9,6 +9,8 @@ import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; @@ -20,6 +22,8 @@ import net.sf.openrocket.gui.components.DescriptionArea; import net.sf.openrocket.gui.components.UnitSelector; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.startup.Application; @@ -124,6 +128,21 @@ public class TransitionConfig extends RocketComponentConfig { //// Automatic checkbox.setText(trans.get("TransitionCfg.checkbox.Automatic")); panel.add(checkbox, "skip, span 2, wrap"); + // Disable check button if there is no component to get the diameter from + checkbox.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + if (!(c instanceof Transition)) return; + if (((Transition) c).getPreviousSymmetricComponent() != null) { + checkbox.setEnabled(true); + } + else { + checkbox.setEnabled(false); + ((Transition) c).setForeRadiusAutomatic(false); + } + } + }); + checkbox.getChangeListeners()[0].stateChanged(null); } { //// Aft diameter: @@ -143,6 +162,21 @@ public class TransitionConfig extends RocketComponentConfig { //// Automatic aftRadiusCheckbox.setText(trans.get("TransitionCfg.checkbox.Automatic")); panel.add(aftRadiusCheckbox, "skip, span 2, wrap"); + // Disable check button if there is no component to get the diameter from + aftRadiusCheckbox.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + if (!(c instanceof Transition)) return; + if (((Transition) c).getNextSymmetricComponent() != null) { + aftRadiusCheckbox.setEnabled(true); + } + else { + aftRadiusCheckbox.setEnabled(false); + ((Transition) c).setAftRadiusAutomatic(false); + } + } + }); + aftRadiusCheckbox.getChangeListeners()[0].stateChanged(null); } { /// Wall thickness: From 9035284f899822428a6123d5ef979c44e557d4a7 Mon Sep 17 00:00:00 2001 From: Sibo Van Gool Date: Thu, 19 Aug 2021 15:02:13 +0200 Subject: [PATCH 2/3] [fixes #871] Don't allow multiple auto's for the same reference components --- core/resources/l10n/messages.properties | 9 ++ .../openrocket/rocketcomponent/BodyTube.java | 26 +++-- .../openrocket/rocketcomponent/NoseCone.java | 7 +- .../rocketcomponent/SymmetricComponent.java | 12 +- .../rocketcomponent/Transition.java | 8 ++ .../gui/configdialog/BodyTubeConfig.java | 56 ++++++---- .../gui/configdialog/NoseConeConfig.java | 52 +++++---- .../gui/configdialog/TransitionConfig.java | 103 +++++++++++------- 8 files changed, 182 insertions(+), 91 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 2e2e983e8..f12e187bd 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -766,6 +766,9 @@ BodyTubecfg.tab.Generalproperties = General properties BodyTubecfg.tab.Motor = Motor BodyTubecfg.tab.Motormountconf = Motor mount configuration BodyTubecfg.checkbox.Automatic = Automatic +BodyTubecfg.checkbox.ttip.Automatic = Use the diameter of the previous/next component +BodyTubecfg.checkbox.ttip.Automatic_noReferenceComponent = There is no previous/next component to take the diameter of +BodyTubecfg.checkbox.ttip.Automatic_alreadyAuto = The previous/next component already has its auto setting turned on BodyTubecfg.checkbox.Filled = Filled ! FinSetConfig @@ -1035,6 +1038,9 @@ NoseConeCfg.lbl.Shapeparam = Shape parameter: NoseConeCfg.lbl.Noseconelength = Nose cone length: NoseConeCfg.lbl.Basediam = Base diameter: NoseConeCfg.checkbox.Automatic = Automatic +NoseConeCfg.checkbox.ttip.Automatic = Use the diameter of the next component +NoseConeCfg.checkbox.ttip.Automatic_noReferenceComponent = There is no next component to take the diameter of +NoseConeCfg.checkbox.ttip.Automatic_alreadyAuto = The next component already has its auto setting turned on NoseConeCfg.lbl.Wallthickness = Wall thickness: NoseConeCfg.checkbox.Filled = Filled NoseConeCfg.tab.General = General @@ -1136,6 +1142,9 @@ TransitionCfg.lbl.Shapeparam = Shape parameter: TransitionCfg.lbl.Transitionlength = Transition length: TransitionCfg.lbl.Forediam = Fore diameter: TransitionCfg.checkbox.Automatic = Automatic +TransitionCfg.checkbox.ttip.Automatic = Use the diameter of the previous/next component +TransitionCfg.checkbox.ttip.Automatic_noReferenceComponent = There is no previous/next component to take the diameter of +TransitionCfg.checkbox.ttip.Automatic_alreadyAuto = The previous/next component already has its auto setting turned on TransitionCfg.lbl.Aftdiam = Aft diameter: TransitionCfg.lbl.Wallthickness = Wall thickness: TransitionCfg.checkbox.Filled = Filled diff --git a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java index 03b979543..684279ca5 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@ -1,10 +1,7 @@ package net.sf.openrocket.rocketcomponent; -import java.util.EventObject; import java.util.Iterator; -import net.sf.openrocket.appearance.Appearance; -import net.sf.openrocket.appearance.Decal; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.MotorConfiguration; @@ -25,6 +22,8 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou private double outerRadius = 0; private boolean autoRadius = false; // Radius chosen automatically based on parent component + + private SymmetricComponent refComp = null; // Reference component that is used for the autoRadius // When changing the inner radius, thickness is modified private double overhang = 0; @@ -79,13 +78,17 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou // Return auto radius from front or rear double r = -1; SymmetricComponent c = this.getPreviousSymmetricComponent(); - if (c != null) { + // Don't use the radius of a component who already has its auto diameter enabled + if (c != null && !c.usesNextCompAutomatic()) { r = c.getFrontAutoRadius(); + refComp = c; } if (r < 0) { c = this.getNextSymmetricComponent(); - if (c != null) { + // Don't use the radius of a component who already has its auto diameter enabled + if (c != null && !c.usesPreviousCompAutomatic()) { r = c.getRearAutoRadius(); + refComp = c; } } if (r < 0) @@ -136,8 +139,17 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); clearPreset(); } - - + + @Override + public boolean usesPreviousCompAutomatic() { + return isOuterRadiusAutomatic() && refComp == getPreviousSymmetricComponent(); + } + + @Override + public boolean usesNextCompAutomatic() { + return isOuterRadiusAutomatic() && refComp == getNextSymmetricComponent(); + } + @Override protected void loadFromPreset(ComponentPreset preset) { this.autoRadius = false; diff --git a/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java b/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java index a7316fdb3..851dfd2d5 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java +++ b/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java @@ -69,7 +69,12 @@ public class NoseCone extends Transition implements InsideColorComponent { public void setForeRadiusAutomatic(boolean b) { // No-op } - + + @Override + public boolean usesPreviousCompAutomatic() { + return false; + } + @Override public double getForeShoulderLength() { return 0; diff --git a/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java b/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java index b5d704496..aa61cd979 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java @@ -644,5 +644,15 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou } return null; } - + + /** + * Checks whether the component uses the previous symmetric component for its auto diameter. + */ + public abstract boolean usesPreviousCompAutomatic(); + + /** + * Checks whether the component uses the next symmetric component for its auto diameter. + */ + public abstract boolean usesNextCompAutomatic(); + } diff --git a/core/src/net/sf/openrocket/rocketcomponent/Transition.java b/core/src/net/sf/openrocket/rocketcomponent/Transition.java index 304750066..188a01f40 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Transition.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Transition.java @@ -192,7 +192,15 @@ public class Transition extends SymmetricComponent implements InsideColorCompone return getForeRadius(); } + @Override + public boolean usesPreviousCompAutomatic() { + return isForeRadiusAutomatic(); + } + @Override + public boolean usesNextCompAutomatic() { + return isAftRadiusAutomatic(); + } //////// Type & shape ///////// diff --git a/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java index 677e5778b..163c1002f 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java @@ -5,8 +5,6 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; @@ -19,8 +17,8 @@ import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.material.Material; import net.sf.openrocket.rocketcomponent.BodyTube; import net.sf.openrocket.rocketcomponent.MotorMount; -import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.SymmetricComponent; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.UnitGroup; @@ -28,6 +26,7 @@ import net.sf.openrocket.unit.UnitGroup; public class BodyTubeConfig extends RocketComponentConfig { private DoubleModel maxLength; + private final JCheckBox checkAutoOuterRadius; private static final Translator trans = Application.getTranslator(); public BodyTubeConfig(OpenRocketDocument d, RocketComponent c) { @@ -62,24 +61,10 @@ public class BodyTubeConfig extends RocketComponentConfig { //// Automatic javax.swing.Action outerAutoAction = od.getAutomaticAction(); - JCheckBox checkAuto = new JCheckBox(outerAutoAction); - checkAuto.setText(trans.get("BodyTubecfg.checkbox.Automatic")); - panel.add(checkAuto, "skip, span 2, wrap"); - // Disable check button if there is no component to get the diameter from - checkAuto.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (!(c instanceof BodyTube)) return; - if (((BodyTube) c).getPreviousSymmetricComponent() != null) { - checkAuto.setEnabled(true); - } - else { - checkAuto.setEnabled(false); - ((BodyTube) c).setOuterRadiusAutomatic(false); - } - } - }); - checkAuto.getChangeListeners()[0].stateChanged(null); + checkAutoOuterRadius = new JCheckBox(outerAutoAction); + checkAutoOuterRadius.setText(trans.get("BodyTubecfg.checkbox.Automatic")); + panel.add(checkAutoOuterRadius, "skip, span 2, wrap"); + updateCheckboxAutoAftRadius(); //// Inner diameter panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Innerdiameter"))); @@ -132,4 +117,33 @@ public class BodyTubeConfig extends RocketComponentConfig { super.updateFields(); } + /** + * Sets the checkAutoOuterRadius checkbox's enabled state and tooltip text, based on the state of its previous + * component. If there is no next and previous symmetric component, the checkAutoOuterRadius checkbox is disabled. + * If there is still a next or previous component which does not have its auto state enabled, meaning it can still + * serve as a reference component for this component, the auto checkbox is enabled. + */ + private void updateCheckboxAutoAftRadius() { + if (component == null || checkAutoOuterRadius == null) return; + + // Disable check button if there is no component to get the diameter from + SymmetricComponent prevComp = ((BodyTube) component).getPreviousSymmetricComponent(); + SymmetricComponent nextComp = ((BodyTube) component).getNextSymmetricComponent(); + if (prevComp == null && nextComp == null) { + checkAutoOuterRadius.setEnabled(false); + ((BodyTube) component).setOuterRadiusAutomatic(false); + checkAutoOuterRadius.setToolTipText(trans.get("BodyTubecfg.checkbox.ttip.Automatic_noReferenceComponent")); + return; + } + if (!(prevComp != null && nextComp == null && prevComp.usesNextCompAutomatic()) && + !(nextComp != null && prevComp == null && nextComp.usesPreviousCompAutomatic()) && + !(nextComp != null && prevComp != null && prevComp.usesNextCompAutomatic() && nextComp.usesPreviousCompAutomatic())) { + checkAutoOuterRadius.setEnabled(true); + checkAutoOuterRadius.setToolTipText(trans.get("BodyTubecfg.checkbox.ttip.Automatic")); + } else { + checkAutoOuterRadius.setEnabled(false); + ((BodyTube) component).setOuterRadiusAutomatic(false); + checkAutoOuterRadius.setToolTipText(trans.get("BodyTubecfg.checkbox.ttip.Automatic_alreadyAuto")); + } + } } diff --git a/swing/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java index d8f8332a7..6be83867e 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java @@ -10,8 +10,6 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JSpinner; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; @@ -25,6 +23,7 @@ import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.material.Material; import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.SymmetricComponent; import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.UnitGroup; @@ -38,6 +37,7 @@ public class NoseConeConfig extends RocketComponentConfig { private JLabel shapeLabel; private JSpinner shapeSpinner; private JSlider shapeSlider; + private final JCheckBox checkAutoAftRadius; private static final Translator trans = Application.getTranslator(); // Prepended to the description from NoseCone.DESCRIPTIONS @@ -111,25 +111,11 @@ public class NoseConeConfig extends RocketComponentConfig { panel.add(new UnitSelector(aftRadiusModel), "growx"); panel.add(new BasicSlider(aftRadiusModel.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap 0px"); - JCheckBox check = new JCheckBox(aftRadiusModel.getAutomaticAction()); + checkAutoAftRadius = new JCheckBox(aftRadiusModel.getAutomaticAction()); //// Automatic - check.setText(trans.get("NoseConeCfg.checkbox.Automatic")); - panel.add(check, "skip, span 2, wrap"); - // Disable check button if there is no component to get the diameter from - check.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (!(c instanceof NoseCone)) return; - if (((NoseCone) c).getNextSymmetricComponent() != null) { - check.setEnabled(true); - } - else { - check.setEnabled(false); - ((NoseCone) c).setAftRadiusAutomatic(false); - } - } - }); - check.getChangeListeners()[0].stateChanged(null); + checkAutoAftRadius.setText(trans.get("NoseConeCfg.checkbox.Automatic")); + panel.add(checkAutoAftRadius, "skip, span 2, wrap"); + updateCheckboxAutoAftRadius(); } {//// Wall thickness: @@ -182,6 +168,30 @@ public class NoseConeConfig extends RocketComponentConfig { shapeSpinner.setEnabled(e); shapeSlider.setEnabled(e); } - + /** + * Sets the checkAutoAftRadius checkbox's enabled state and tooltip text, based on the state of its next component. + * If there is no next symmetric component or if that component already has its auto checkbox checked, the + * checkAutoAftRadius checkbox is disabled. + */ + private void updateCheckboxAutoAftRadius() { + if (component == null || checkAutoAftRadius == null) return; + + // Disable check button if there is no component to get the diameter from + SymmetricComponent nextComp = ((NoseCone) component).getNextSymmetricComponent(); + if (nextComp == null) { + checkAutoAftRadius.setEnabled(false); + ((NoseCone) component).setAftRadiusAutomatic(false); + checkAutoAftRadius.setToolTipText(trans.get("NoseConeCfg.checkbox.ttip.Automatic_noReferenceComponent")); + return; + } + if (!nextComp.usesPreviousCompAutomatic()) { + checkAutoAftRadius.setEnabled(true); + checkAutoAftRadius.setToolTipText(trans.get("NoseConeCfg.checkbox.ttip.Automatic")); + } else { + checkAutoAftRadius.setEnabled(false); + ((NoseCone) component).setAftRadiusAutomatic(false); + checkAutoAftRadius.setToolTipText(trans.get("NoseConeCfg.checkbox.ttip.Automatic_alreadyAuto")); + } + } } diff --git a/swing/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java index 90178611f..8bd0b2181 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java @@ -9,8 +9,6 @@ import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; @@ -22,9 +20,8 @@ import net.sf.openrocket.gui.components.DescriptionArea; import net.sf.openrocket.gui.components.UnitSelector; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.material.Material; -import net.sf.openrocket.rocketcomponent.BodyTube; -import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.SymmetricComponent; import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.UnitGroup; @@ -39,6 +36,8 @@ public class TransitionConfig extends RocketComponentConfig { private JLabel shapeLabel; private JSpinner shapeSpinner; private BasicSlider shapeSlider; + private final JCheckBox checkAutoAftRadius; + private final JCheckBox checkAutoForeRadius; private DescriptionArea description; @@ -124,25 +123,11 @@ public class TransitionConfig extends RocketComponentConfig { panel.add(new UnitSelector(foreRadiusModel), "growx"); panel.add(new BasicSlider(foreRadiusModel.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap 0px"); - final JCheckBox checkbox = new JCheckBox(foreRadiusModel.getAutomaticAction()); + checkAutoForeRadius = new JCheckBox(foreRadiusModel.getAutomaticAction()); //// Automatic - checkbox.setText(trans.get("TransitionCfg.checkbox.Automatic")); - panel.add(checkbox, "skip, span 2, wrap"); - // Disable check button if there is no component to get the diameter from - checkbox.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (!(c instanceof Transition)) return; - if (((Transition) c).getPreviousSymmetricComponent() != null) { - checkbox.setEnabled(true); - } - else { - checkbox.setEnabled(false); - ((Transition) c).setForeRadiusAutomatic(false); - } - } - }); - checkbox.getChangeListeners()[0].stateChanged(null); + checkAutoForeRadius.setText(trans.get("TransitionCfg.checkbox.Automatic")); + panel.add(checkAutoForeRadius, "skip, span 2, wrap"); + updateCheckboxAutoForeRadius(); } { //// Aft diameter: @@ -158,25 +143,11 @@ public class TransitionConfig extends RocketComponentConfig { panel.add(new UnitSelector(aftRadiusModel), "growx"); panel.add(new BasicSlider(aftRadiusModel.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap 0px"); - final JCheckBox aftRadiusCheckbox = new JCheckBox(aftRadiusModel.getAutomaticAction()); + checkAutoAftRadius = new JCheckBox(aftRadiusModel.getAutomaticAction()); //// Automatic - aftRadiusCheckbox.setText(trans.get("TransitionCfg.checkbox.Automatic")); - panel.add(aftRadiusCheckbox, "skip, span 2, wrap"); - // Disable check button if there is no component to get the diameter from - aftRadiusCheckbox.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (!(c instanceof Transition)) return; - if (((Transition) c).getNextSymmetricComponent() != null) { - aftRadiusCheckbox.setEnabled(true); - } - else { - aftRadiusCheckbox.setEnabled(false); - ((Transition) c).setAftRadiusAutomatic(false); - } - } - }); - aftRadiusCheckbox.getChangeListeners()[0].stateChanged(null); + checkAutoAftRadius.setText(trans.get("TransitionCfg.checkbox.Automatic")); + panel.add(checkAutoAftRadius, "skip, span 2, wrap"); + updateCheckboxAutoAftRadius(); } { /// Wall thickness: @@ -228,5 +199,57 @@ public class TransitionConfig extends RocketComponentConfig { shapeSpinner.setEnabled(e); shapeSlider.setEnabled(e); } + + /** + * Sets the checkAutoAftRadius checkbox's enabled state and tooltip text, based on the state of its next component. + * If there is no next symmetric component or if that component already has its auto checkbox checked, the + * checkAutoAftRadius checkbox is disabled. + */ + private void updateCheckboxAutoAftRadius() { + if (component == null || checkAutoAftRadius == null) return; + + // Disable check button if there is no component to get the diameter from + SymmetricComponent nextComp = ((Transition) component).getNextSymmetricComponent(); + if (nextComp == null) { + checkAutoAftRadius.setEnabled(false); + ((Transition) component).setAftRadiusAutomatic(false); + checkAutoAftRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_noReferenceComponent")); + return; + } + if (!nextComp.usesPreviousCompAutomatic()) { + checkAutoAftRadius.setEnabled(true); + checkAutoAftRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic")); + } else { + checkAutoAftRadius.setEnabled(false); + ((Transition) component).setAftRadiusAutomatic(false); + checkAutoAftRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_alreadyAuto")); + } + } + + /** + * Sets the checkAutoForeRadius checkbox's enabled state and tooltip text, based on the state of its next component. + * If there is no next symmetric component or if that component already has its auto checkbox checked, the + * checkAutoForeRadius checkbox is disabled. + */ + private void updateCheckboxAutoForeRadius() { + if (component == null || checkAutoForeRadius == null) return; + + // Disable check button if there is no component to get the diameter from + SymmetricComponent prevComp = ((Transition) component).getPreviousSymmetricComponent(); + if (prevComp == null) { + checkAutoForeRadius.setEnabled(false); + ((Transition) component).setForeRadiusAutomatic(false); + checkAutoForeRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_noReferenceComponent")); + return; + } + if (!prevComp.usesNextCompAutomatic()) { + checkAutoForeRadius.setEnabled(true); + checkAutoForeRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic")); + } else { + checkAutoForeRadius.setEnabled(false); + ((Transition) component).setForeRadiusAutomatic(false); + checkAutoForeRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_alreadyAuto")); + } + } } From 3a5861f98816fbd9975a60972eded61bb53ab5a1 Mon Sep 17 00:00:00 2001 From: Sibo Van Gool Date: Sun, 22 Aug 2021 00:21:33 +0200 Subject: [PATCH 3/3] [fixes #871] Remember manual setting after saving with auto on --- .../openrocket/importt/DocumentConfig.java | 6 +- .../file/openrocket/importt/DoubleSetter.java | 65 ++++++++++++++----- .../file/openrocket/savers/BodyTubeSaver.java | 5 +- .../openrocket/savers/TransitionSaver.java | 4 +- .../openrocket/rocketcomponent/BodyTube.java | 8 +++ .../rocketcomponent/Transition.java | 16 ++++- 6 files changed, 80 insertions(+), 24 deletions(-) diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java index d29068f6c..97d0e4925 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java @@ -152,7 +152,7 @@ class DocumentConfig { // BodyTube setters.put("BodyTube:radius", new DoubleSetter( Reflection.findMethod(BodyTube.class, "setOuterRadius", double.class), - "auto", + "auto", " ", Reflection.findMethod(BodyTube.class, "setOuterRadiusAutomatic", boolean.class))); // Parallel Stage @@ -204,11 +204,11 @@ class DocumentConfig { setters.put("Transition:foreradius", new DoubleSetter( Reflection.findMethod(Transition.class, "setForeRadius", double.class), - "auto", + "auto", " ", Reflection.findMethod(Transition.class, "setForeRadiusAutomatic", boolean.class))); setters.put("Transition:aftradius", new DoubleSetter( Reflection.findMethod(Transition.class, "setAftRadius", double.class), - "auto", + "auto", " ", Reflection.findMethod(Transition.class, "setAftRadiusAutomatic", boolean.class))); setters.put("Transition:foreshoulderradius", new DoubleSetter( diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/DoubleSetter.java b/core/src/net/sf/openrocket/file/openrocket/importt/DoubleSetter.java index 5d553b57b..5525f8086 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/DoubleSetter.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/DoubleSetter.java @@ -1,6 +1,8 @@ package net.sf.openrocket.file.openrocket.importt; +import java.util.Arrays; import java.util.HashMap; +import java.util.Objects; import net.sf.openrocket.aerodynamics.Warning; import net.sf.openrocket.aerodynamics.WarningSet; @@ -17,6 +19,7 @@ class DoubleSetter implements Setter { private final String specialString; private final Reflection.Method specialMethod; private final double multiplier; + private String separator; /** * Set only the double value. @@ -59,6 +62,23 @@ class DoubleSetter implements Setter { this.specialMethod = specialMethod; this.multiplier = 1.0; } + + /** + * Set the double value, or if the value equals the special string, use the + * special setter and set it to true. If the input string contains more information + * besides the special string, you can specify which separator should be used for + * this extra information. The part before the separator is then the special string + * and the part after the separator is the set value. + * + * @param set double setter. + * @param special special string + * @param specialMethod boolean setter. + */ + public DoubleSetter(Reflection.Method set, String special, String separator, + Reflection.Method specialMethod) { + this(set, special, specialMethod); + this.separator = separator; + } /** @@ -80,26 +100,39 @@ class DoubleSetter implements Setter { WarningSet warnings) { s = s.trim(); - - // Check for special case - if (specialMethod != null && s.equalsIgnoreCase(specialString)) { - specialMethod.invoke(c, true); - return; + String special = s; + String data = s; + String[] args = null; + + // Extract special string and data if s contains multiple data elements, separated by separator + if (separator != null) { + args = s.split(this.separator); + if (args.length > 1) { + special = args[0]; + data = String.join(separator, Arrays.copyOfRange(args, 1, args.length)); + } } // Normal case - try { - double d = Double.parseDouble(s); - - if (configGetter == null) { - setMethod.invoke(c, d * multiplier); - } else { - FlightConfigurableParameterSet config = (FlightConfigurableParameterSet) configGetter.invoke(c); - Object obj = config.getDefault(); - setMethod.invoke(obj, d * multiplier); + if (!special.equalsIgnoreCase(specialString) || (args != null && args.length > 1)) { + try { + double d = Double.parseDouble(data); + + if (configGetter == null) { + setMethod.invoke(c, d * multiplier); + } else { + FlightConfigurableParameterSet config = (FlightConfigurableParameterSet) configGetter.invoke(c); + Object obj = config.getDefault(); + setMethod.invoke(obj, d * multiplier); + } + } catch (NumberFormatException e) { + warnings.add(Warning.FILE_INVALID_PARAMETER + " data: '" + data + "' - " + c.getName()); } - } catch (NumberFormatException e) { - warnings.add(Warning.FILE_INVALID_PARAMETER); + } + + // Check for special case + if (specialMethod != null && special.equalsIgnoreCase(specialString)) { + specialMethod.invoke(c, true); } } } \ No newline at end of file diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/BodyTubeSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/BodyTubeSaver.java index 8b1ef6a58..d6aa0c85c 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/BodyTubeSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/BodyTubeSaver.java @@ -22,8 +22,9 @@ public class BodyTubeSaver extends SymmetricComponentSaver { super.addParams(c, elements); net.sf.openrocket.rocketcomponent.BodyTube tube = (net.sf.openrocket.rocketcomponent.BodyTube) c; - if (tube.isOuterRadiusAutomatic()) - elements.add("auto"); + if (tube.isOuterRadiusAutomatic()) { + elements.add("auto " + tube.getOuterRadiusNoAutomatic() + ""); + } else elements.add("" + tube.getOuterRadius() + ""); diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/TransitionSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/TransitionSaver.java index 0a4169f9e..054506eae 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/TransitionSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/TransitionSaver.java @@ -45,13 +45,13 @@ public class TransitionSaver extends SymmetricComponentSaver { if (!nosecone) { if (trans.isForeRadiusAutomatic()) - elements.add("auto"); + elements.add("auto " + trans.getForeRadiusNoAutomatic() + ""); else elements.add("" + trans.getForeRadius() + ""); } if (trans.isAftRadiusAutomatic()) - elements.add("auto"); + elements.add("auto " + trans.getAftRadiusNoAutomatic() + ""); else elements.add("" + trans.getAftRadius() + ""); diff --git a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java index 684279ca5..eb3b6d3d6 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@ -97,6 +97,14 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou } return outerRadius; } + + /** + * Return the outer radius that was manually entered, so not the value that the component received from automatic + * outer radius. + */ + public double getOuterRadiusNoAutomatic() { + return outerRadius; + } /** * Set the outer radius of the body tube. If the radius is less than the wall thickness, diff --git a/core/src/net/sf/openrocket/rocketcomponent/Transition.java b/core/src/net/sf/openrocket/rocketcomponent/Transition.java index 188a01f40..422561119 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Transition.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Transition.java @@ -94,6 +94,14 @@ public class Transition extends SymmetricComponent implements InsideColorCompone return foreRadius; } + /** + * Return the fore radius that was manually entered, so not the value that the component received from automatic + * fore radius. + */ + public double getForeRadiusNoAutomatic() { + return foreRadius; + } + public void setForeRadius(double radius) { if ((this.foreRadius == radius) && (autoForeRadius == false)) return; @@ -142,7 +150,13 @@ public class Transition extends SymmetricComponent implements InsideColorCompone return aftRadius; } - + /** + * Return the aft radius that was manually entered, so not the value that the component received from automatic + * zft radius. + */ + public double getAftRadiusNoAutomatic() { + return aftRadius; + } public void setAftRadius(double radius) { if ((this.aftRadius == radius) && (autoAftRadius2 == false))