diff --git a/core/src/net/sf/openrocket/rocketcomponent/RecoveryDevice.java b/core/src/net/sf/openrocket/rocketcomponent/RecoveryDevice.java index 9fc15a8e4..572778387 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RecoveryDevice.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RecoveryDevice.java @@ -30,8 +30,7 @@ public abstract class RecoveryDevice extends MassObject implements FlightConfigu private FlightConfigurableParameterSet deploymentConfigurations; public RecoveryDevice() { - this.deploymentConfigurations = - new FlightConfigurableParameterSet( new DeploymentConfiguration()); + this.deploymentConfigurations = new FlightConfigurableParameterSet<>( new DeploymentConfiguration()); defaultMaterial = (Material.Surface) Application.getPreferences().getDefaultComponentMaterial(RecoveryDevice.class, Material.Type.SURFACE); setMaterial(Application.getPreferences().getDefaultComponentMaterial(RecoveryDevice.class, Material.Type.SURFACE)); } @@ -148,7 +147,7 @@ public abstract class RecoveryDevice extends MassObject implements FlightConfigu @Override protected RocketComponent copyWithOriginalID() { RecoveryDevice copy = (RecoveryDevice) super.copyWithOriginalID(); - copy.deploymentConfigurations = new FlightConfigurableParameterSet(deploymentConfigurations); + copy.deploymentConfigurations = new FlightConfigurableParameterSet<>(deploymentConfigurations); return copy; } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/DeploymentSelectionDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/DeploymentSelectionDialog.java index 24d1750d1..225e58947 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/DeploymentSelectionDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/DeploymentSelectionDialog.java @@ -4,6 +4,7 @@ import java.awt.Dialog; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; import javax.swing.ButtonGroup; import javax.swing.JButton; @@ -46,12 +47,12 @@ public class DeploymentSelectionDialog extends JDialog { private final JSpinner altSpinner; private final UnitSelector altUnit; private final JSlider altSlider; + + private boolean isOverrideDefault; - public DeploymentSelectionDialog(Window parent, final Rocket rocket, final RecoveryDevice component) { + public DeploymentSelectionDialog(Window parent, final Rocket rocket, final FlightConfigurationId id, final RecoveryDevice component) { super(parent, trans.get("edtmotorconfdlg.title.Selectdeploymentconf"), Dialog.ModalityType.APPLICATION_MODAL); - - final FlightConfigurationId id = rocket.getSelectedConfiguration().getFlightConfigurationID(); - + newConfiguration = component.getDeploymentConfigurations().get(id).clone(); JPanel panel = new JPanel(new MigLayout("fill")); @@ -61,15 +62,16 @@ public class DeploymentSelectionDialog extends JDialog { panel.add(defaultButton, "span, gapleft para, wrap rel"); String str = trans.get("DeploymentSelectionDialog.opt.override"); str = str.replace("{0}", descriptor.format(rocket, id)); - final JRadioButton overrideButton = new JRadioButton(str, false); + final JRadioButton overrideButton = new JRadioButton(str); + overrideButton.addItemListener(e -> isOverrideDefault = e.getStateChange() == ItemEvent.SELECTED); + overrideButton.setSelected(false); panel.add(overrideButton, "span, gapleft para, wrap para"); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(defaultButton); buttonGroup.add(overrideButton); - // Select the button based on current configuration. If the configuration is overridden - // The the overrideButton is selected. + // Select the button based on current configuration. If the configuration is overridden, the overrideButton is selected. boolean isOverridden = !component.getDeploymentConfigurations().isDefault(id); if (isOverridden) { overrideButton.setSelected(true); @@ -79,7 +81,7 @@ public class DeploymentSelectionDialog extends JDialog { //// Deploys at: panel.add(new JLabel(trans.get("ParachuteCfg.lbl.Deploysat")), ""); - final JComboBox deployEvent = new JComboBox(new EnumModel(newConfiguration, "DeployEvent")); + final JComboBox deployEvent = new JComboBox(new EnumModel<>(newConfiguration, "DeployEvent")); if( (component.getStageNumber() + 1 ) == rocket.getStageCount() ){ // This is the bottom stage: Restrict deployment options. deployEvent.removeItem( DeployEvent.LOWER_STAGE_SEPARATION ); @@ -149,6 +151,7 @@ public class DeploymentSelectionDialog extends JDialog { this.setContentPane(panel); GUIUtil.setDisposableDialogOptions(this, okButton); + GUIUtil.installEscapeCloseButtonOperation(this, okButton); } private void updateState() { @@ -158,6 +161,12 @@ public class DeploymentSelectionDialog extends JDialog { altUnit.setEnabled(enabled); altSlider.setEnabled(enabled); } - - + + /** + * Returns true if this dialog was used to override the default configuration. + * @return true if this dialog was used to override the default configuration. + */ + public boolean isOverrideDefault() { + return isOverrideDefault; + } } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/IgnitionSelectionDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/IgnitionSelectionDialog.java index 41ea1a34a..3c0c4129f 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/IgnitionSelectionDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/IgnitionSelectionDialog.java @@ -4,6 +4,7 @@ import java.awt.Dialog; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; import java.util.Iterator; import javax.swing.ButtonGroup; @@ -44,6 +45,8 @@ public class IgnitionSelectionDialog extends JDialog { private IgnitionEvent startIgnitionEvent; private double startIgnitionDelay; + + private boolean isOverrideDefault; public IgnitionSelectionDialog(Window parent, final FlightConfigurationId curFCID, MotorMount _mount) { super(parent, trans.get("edtmotorconfdlg.title.Selectignitionconf"), Dialog.ModalityType.APPLICATION_MODAL); @@ -62,15 +65,16 @@ public class IgnitionSelectionDialog extends JDialog { Rocket rkt = ((RocketComponent)_mount).getRocket(); str = str.replace("{0}", descriptor.format(rkt, curFCID)); - final JRadioButton overrideButton = new JRadioButton(str, !isDefault); + final JRadioButton overrideButton = new JRadioButton(str); + overrideButton.addItemListener(e -> isOverrideDefault = e.getStateChange() == ItemEvent.SELECTED); + overrideButton.setSelected(!isDefault); panel.add(overrideButton, "span, gapleft para, wrap para"); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(defaultButton); buttonGroup.add(overrideButton); - // Select the button based on current configuration. If the configuration is overridden - // The the overrideButton is selected. + // Select the button based on current configuration. If the configuration is overridden the overrideButton is selected. boolean isOverridden = !isDefault; if (isOverridden) { overrideButton.setSelected(true); @@ -114,18 +118,11 @@ public class IgnitionSelectionDialog extends JDialog { // and change all remaining configs // this seems like odd behavior to me, but it matches the text on the UI dialog popup. -teyrana (equipoise@gmail.com) Iterator iter = curMount.getMotorIterator(); - while( iter.hasNext() ){ + while(iter.hasNext() ) { MotorConfiguration next = iter.next(); - next.setIgnitionDelay( cid); - next.setIgnitionEvent( cie); + next.setIgnitionDelay(cid); + next.setIgnitionEvent(cie); } - -// System.err.println("setting default motor ignition ("+defaultMotorInstance.getMotorID().toString()+") to: "); -// System.err.println(" event: "+defaultMotorInstance.getIgnitionEvent().name+" w/delay: "+defaultMotorInstance.getIgnitionDelay()); -// }else { -// System.err.println("setting motor ignition to.... new values: "); -// //destMotorInstance.setIgnitionEvent((IgnitionEvent)eventBox.getSelectedItem()); -// System.err.println(" "+curMotorInstance.getIgnitionEvent()+" w/ "+curMotorInstance.getIgnitionDelay()); } IgnitionSelectionDialog.this.setVisible(false); } @@ -150,5 +147,14 @@ public class IgnitionSelectionDialog extends JDialog { this.setContentPane(panel); GUIUtil.setDisposableDialogOptions(this, okButton); + GUIUtil.installEscapeCloseButtonOperation(this, okButton); + } + + /** + * Returns true if this dialog was used to override the default configuration. + * @return true if this dialog was used to override the default configuration. + */ + public boolean isOverrideDefault() { + return isOverrideDefault; } } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java index f1040931d..bd90c2617 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java @@ -4,6 +4,7 @@ import java.awt.Dialog; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; import javax.swing.ButtonGroup; import javax.swing.JButton; @@ -38,11 +39,12 @@ public class SeparationSelectionDialog extends JDialog { private RocketDescriptor descriptor = Application.getInjector().getInstance(RocketDescriptor.class); private StageSeparationConfiguration newConfiguration; + + private boolean isOverrideDefault; - public SeparationSelectionDialog(Window parent, final Rocket rocket, final AxialStage stage) { + public SeparationSelectionDialog(Window parent, final Rocket rocket, final AxialStage stage, FlightConfigurationId id) { super(parent, trans.get("edtmotorconfdlg.title.Selectseparationconf"), Dialog.ModalityType.APPLICATION_MODAL); - final FlightConfigurationId id = rocket.getSelectedConfiguration().getFlightConfigurationID(); - + newConfiguration = stage.getSeparationConfigurations().get(id); if( stage.getSeparationConfigurations().isDefault( newConfiguration )){ newConfiguration = newConfiguration.clone(); @@ -59,7 +61,9 @@ public class SeparationSelectionDialog extends JDialog { panel.add(defaultButton, "span, gapleft para, wrap rel"); String str = trans.get("SeparationSelectionDialog.opt.override"); str = str.replace("{0}", descriptor.format(rocket, id)); - final JRadioButton overrideButton = new JRadioButton(str, false); + final JRadioButton overrideButton = new JRadioButton(str); + overrideButton.addItemListener(e -> isOverrideDefault = e.getStateChange() == ItemEvent.SELECTED); + overrideButton.setSelected(false); panel.add(overrideButton, "span, gapleft para, wrap para"); ButtonGroup buttonGroup = new ButtonGroup(); @@ -123,5 +127,14 @@ public class SeparationSelectionDialog extends JDialog { this.setContentPane(panel); GUIUtil.setDisposableDialogOptions(this, okButton); + GUIUtil.installEscapeCloseButtonOperation(this, okButton); + } + + /** + * Returns true if this dialog was used to override the default configuration. + * @return true if this dialog was used to override the default configuration. + */ + public boolean isOverrideDefault() { + return isOverrideDefault; } } diff --git a/swing/src/net/sf/openrocket/gui/main/FlightConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/main/FlightConfigurationPanel.java index 878300b37..9bc567177 100644 --- a/swing/src/net/sf/openrocket/gui/main/FlightConfigurationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/FlightConfigurationPanel.java @@ -88,15 +88,15 @@ public class FlightConfigurationPanel extends JPanel implements StateChangeListe tabs = new JTabbedPane(); //// Motor tabs - motorConfigurationPanel = new MotorConfigurationPanel(this, rocket); + motorConfigurationPanel = new MotorConfigurationPanel(this, document, rocket); tabs.add(trans.get("edtmotorconfdlg.lbl.Motortab"), motorConfigurationPanel); //// Recovery tab - recoveryConfigurationPanel = new RecoveryConfigurationPanel(this, rocket); + recoveryConfigurationPanel = new RecoveryConfigurationPanel(this, document, rocket); tabs.add(trans.get("edtmotorconfdlg.lbl.Recoverytab"), recoveryConfigurationPanel); //// Stage tab - separationConfigurationPanel = new SeparationConfigurationPanel(this, rocket); + separationConfigurationPanel = new SeparationConfigurationPanel(this, document, rocket); tabs.add(trans.get("edtmotorconfdlg.lbl.Stagetab"), separationConfigurationPanel); //// New configuration @@ -237,12 +237,29 @@ public class FlightConfigurationPanel extends JPanel implements StateChangeListe List fcIds = getSelectedConfigurationIds(); if (fcIds == null) return; FlightConfigurationId initFcId = fcIds.get(0); - new RenameConfigDialog(SwingUtilities.getWindowAncestor(this), rocket, initFcId).setVisible(true); + String initName = rocket.getFlightConfiguration(initFcId).getNameRaw(); + + document.addUndoPosition("Rename configuration(s)"); + + // Launch the rename dialog + RenameConfigDialog dialog = new RenameConfigDialog(SwingUtilities.getWindowAncestor(this), rocket, initFcId); + dialog.setVisible(true); + + // Get the name of the (potentially renamed) config String newName = rocket.getFlightConfiguration(initFcId).getNameRaw(); + + boolean update = !newName.equals(initName); for (int i = 1; i < fcIds.size(); i++) { - rocket.getFlightConfiguration(fcIds.get(i)).setName(newName); + FlightConfiguration config = rocket.getFlightConfiguration(fcIds.get(i)); + if (!config.getNameRaw().equals(newName)) { + update = true; + config.setName(newName); + } + } + + if (update) { + configurationChanged(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); } - configurationChanged(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); } private void removeConfigurationAction() { @@ -250,6 +267,8 @@ public class FlightConfigurationPanel extends JPanel implements StateChangeListe if (fcIds == null || fcIds.size() == 0) return; + document.addUndoPosition("Remove configuration(s)"); + for (FlightConfigurationId fcId : fcIds) { document.removeFlightConfigurationAndSimulations(fcId); } diff --git a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/FlightConfigurablePanel.java b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/FlightConfigurablePanel.java index ee9e53dec..ee6cb3b80 100644 --- a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/FlightConfigurablePanel.java +++ b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/FlightConfigurablePanel.java @@ -22,6 +22,7 @@ import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; +import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.gui.main.FlightConfigurationPanel; import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.util.ArrayList; @@ -51,12 +52,14 @@ public abstract class FlightConfigurablePanel selectedComponent = (Pair) tableValue; - components.add(selectedComponent.getV()); + T comp = selectedComponent.getV(); + if (!components.contains(comp)) { + components.add(comp); + } } } } @@ -289,11 +295,17 @@ public abstract class FlightConfigurablePanel selectedComponent = (Pair) tableValue; FlightConfigurationId fcid = selectedComponent.getU(); - Ids.add(fcid); + if (!Ids.contains(fcid)) { + Ids.add(fcid); + } } else if (tableValue instanceof FlightConfigurationId) { - Ids.add((FlightConfigurationId) tableValue); + if (!Ids.contains(tableValue)) { + Ids.add((FlightConfigurationId) tableValue); + } } else { - Ids.add(FlightConfigurationId.ERROR_FCID); + if (!Ids.contains(FlightConfigurationId.ERROR_FCID)) { + Ids.add(FlightConfigurationId.ERROR_FCID); + } } } diff --git a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java index 8f87a56f2..dbb180428 100644 --- a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java @@ -28,6 +28,7 @@ import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.gui.dialogs.flightconfiguration.IgnitionSelectionDialog; import net.sf.openrocket.gui.dialogs.flightconfiguration.MotorMountConfigurationPanel; import net.sf.openrocket.gui.dialogs.motor.MotorChooserDialog; @@ -49,7 +50,7 @@ import net.sf.openrocket.util.Chars; @SuppressWarnings("serial") public class MotorConfigurationPanel extends FlightConfigurablePanel { - + private static final String NONE = trans.get("edtmotorconfdlg.tbl.None"); private final JButton selectMotorButton, deleteMotorButton, selectIgnitionButton, resetIgnitionButton; @@ -64,8 +65,8 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel private final JPopupMenu popupMenuFull; // popup menu containing all the options - public MotorConfigurationPanel(final FlightConfigurationPanel flightConfigurationPanel, Rocket rocket) { - super(flightConfigurationPanel, rocket); + public MotorConfigurationPanel(final FlightConfigurationPanel flightConfigurationPanel, OpenRocketDocument document, Rocket rocket) { + super(flightConfigurationPanel, document, rocket); motorChooserDialog = new MotorChooserDialog(SwingUtilities.getWindowAncestor(flightConfigurationPanel)); @@ -306,6 +307,9 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel double initDelay = initMount.getMotorConfig(initFcId).getEjectionDelay(); + document.addUndoPosition("Select motor"); + + // Open the motor chooser dialog motorChooserDialog.setMotorMountAndConfig(initFcId, initMount); motorChooserDialog.open(); @@ -343,6 +347,8 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel return; } + document.addUndoPosition("Delete motor(s)"); + for (MotorMount mount : mounts) { for (FlightConfigurationId fcId : fcIds) { mount.setMotorConfig(null, fcId); @@ -359,7 +365,6 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel return; } - boolean update = false; MotorMount initMount = mounts.get(0); FlightConfigurationId initFcId = fcIds.get(0); @@ -367,31 +372,42 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel IgnitionEvent initialIgnitionEvent = initConfig.getIgnitionEvent(); double initialIgnitionDelay = initConfig.getIgnitionDelay(); + document.addUndoPosition("Select ignition"); + // this call also performs the update changes IgnitionSelectionDialog ignitionDialog = new IgnitionSelectionDialog( SwingUtilities.getWindowAncestor(this.flightConfigurationPanel), initFcId, initMount); ignitionDialog.setVisible(true); + boolean isOverrideDefault = ignitionDialog.isOverrideDefault(); - if (!initialIgnitionEvent.equals(initConfig.getIgnitionEvent()) || (initialIgnitionDelay != initConfig.getIgnitionDelay())) { - update = true; - } + boolean update = !initialIgnitionEvent.equals(initConfig.getIgnitionEvent()) || + (initialIgnitionDelay != initConfig.getIgnitionDelay()); - for (int i = 0; i < mounts.size(); i++) { - for (int j = 0; j < fcIds.size(); j++) { - if ((i == 0) && (j == 0)) break; + for (MotorMount mount : mounts) { + for (FlightConfigurationId fcId : fcIds) { + if ((mount == initMount) && (fcId == initFcId)) + continue; - MotorConfiguration config = mounts.get(i).getMotorConfig(fcIds.get(j)); - initialIgnitionEvent = config.getIgnitionEvent(); - initialIgnitionDelay = config.getIgnitionDelay(); + MotorConfiguration currentConfig = mount.getMotorConfig(fcId); - config.setIgnitionEvent(initConfig.getIgnitionEvent()); - config.setIgnitionDelay(initConfig.getIgnitionDelay()); - - if (!initialIgnitionEvent.equals(config.getIgnitionEvent()) || (initialIgnitionDelay != config.getIgnitionDelay())) { - update = true; + // It could be that the current config is the default config, but the user has selected to override it. + if (isOverrideDefault && !mount.getMotorConfigurationSet().containsId(fcId)) { + mount.getMotorConfigurationSet().set(fcId, mount.getMotorConfigurationSet().getDefault().clone()); } + + initialIgnitionEvent = currentConfig.getIgnitionEvent(); + initialIgnitionDelay = currentConfig.getIgnitionDelay(); + + if (initialIgnitionEvent.equals(currentConfig.getIgnitionEvent()) && (initialIgnitionDelay != currentConfig.getIgnitionDelay())) { + continue; + } + + update = true; + + currentConfig.setIgnitionEvent(initConfig.getIgnitionEvent()); + currentConfig.setIgnitionDelay(initConfig.getIgnitionDelay()); } } @@ -410,6 +426,8 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel return; } + document.addUndoPosition("Reset ignition"); + boolean update = false; for (MotorMount mount : mounts) { for (FlightConfigurationId fcId : fcIds) { diff --git a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/RecoveryConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/RecoveryConfigurationPanel.java index 3b272018b..46d19db3c 100644 --- a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/RecoveryConfigurationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/RecoveryConfigurationPanel.java @@ -21,6 +21,7 @@ import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; +import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.formatting.RocketDescriptor; import net.sf.openrocket.gui.dialogs.flightconfiguration.DeploymentSelectionDialog; import net.sf.openrocket.gui.main.FlightConfigurationPanel; @@ -42,8 +43,8 @@ public class RecoveryConfigurationPanel extends FlightConfigurablePanel