[fixes #871] Don't allow multiple auto's for the same reference components

This commit is contained in:
Sibo Van Gool 2021-08-19 15:02:13 +02:00
parent 855deb11fc
commit 9035284f89
8 changed files with 182 additions and 91 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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();
}

View File

@ -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 /////////

View File

@ -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"));
}
}
}

View File

@ -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"));
}
}
}

View File

@ -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"));
}
}
}