From 1ae30084386a57f00d2e24dd00f5ca9dc86dee5c Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 29 Mar 2023 21:59:47 +0200 Subject: [PATCH 01/10] Remove unnecessary variable --- core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java index 3e9c82389..108eb5667 100644 --- a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java @@ -488,7 +488,6 @@ public class OpenRocketSaver extends RocketSaver { for (int i = 0; i < types.length; i++) { data.add(branch.get(types[i])); } - List timeData = branch.get(FlightDataType.TYPE_TIME); // Build the tag StringBuilder sb = new StringBuilder(); From 0e1cd013779d5ba7e2c87cf933c979227bce6a3b Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 29 Mar 2023 22:42:14 +0200 Subject: [PATCH 02/10] Fire change when modID is synced --- core/src/net/sf/openrocket/document/Simulation.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index 068fc91c8..23eee5016 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -349,6 +349,7 @@ public class Simulation implements ChangeSource, Cloneable { */ public void syncModID() { this.simulatedConfigurationID = getActiveConfiguration().getModID(); + fireChangeEvent(); } From 3eb513c78f4ad75cdfc76b766eb0e8d2798e4358 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 29 Mar 2023 22:44:49 +0200 Subject: [PATCH 03/10] Implement simulation & flightdata(branch) cloning --- .../sf/openrocket/document/Simulation.java | 31 +++++++++++++++++++ .../sf/openrocket/simulation/FlightData.java | 18 ++++++++++- .../simulation/FlightDataBranch.java | 15 +++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index 23eee5016..c6371b354 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -523,6 +523,37 @@ public class Simulation implements ChangeSource, Cloneable { mutex.unlock("copy"); } } + + public Simulation clone() { + mutex.lock("clone"); + try { + Simulation clone = (Simulation) super.clone(); + + clone.mutex = SafetyMutex.newInstance(); + clone.status = status; + clone.options = this.options.clone(); + clone.simulationExtensions = new ArrayList<>(); + for (SimulationExtension c : this.simulationExtensions) { + clone.simulationExtensions.add(c.clone()); + } + clone.listeners = new ArrayList<>(); + if (simulatedConditions != null) { + clone.simulatedConditions = simulatedConditions.clone(); + } else { + clone.simulatedConditions = null; + } + clone.simulatedConfigurationDescription = simulatedConfigurationDescription; + clone.simulatedData = simulatedData.clone(); + clone.simulatedConfigurationID = simulatedConfigurationID; + + return clone; + + } catch (CloneNotSupportedException e) { + throw new BugException("Clone not supported, BUG", e); + } finally { + mutex.unlock("clone"); + } + } /** diff --git a/core/src/net/sf/openrocket/simulation/FlightData.java b/core/src/net/sf/openrocket/simulation/FlightData.java index 27f6c1318..0bc41ae76 100644 --- a/core/src/net/sf/openrocket/simulation/FlightData.java +++ b/core/src/net/sf/openrocket/simulation/FlightData.java @@ -273,7 +273,23 @@ public class FlightData { return mutable.isMutable(); } - + public FlightData clone() { + FlightData clone = new FlightData(); + clone.warnings.addAll(warnings); + for (FlightDataBranch b : branches) { + clone.branches.add(b.clone()); + } + clone.maxAltitude = maxAltitude; + clone.maxVelocity = maxVelocity; + clone.maxAcceleration = maxAcceleration; + clone.maxMachNumber = maxMachNumber; + clone.timeToApogee = timeToApogee; + clone.flightTime = flightTime; + clone.groundHitVelocity = groundHitVelocity; + clone.launchRodVelocity = launchRodVelocity; + clone.deploymentVelocity = deploymentVelocity; + return clone; + } /** * Find the maximum acceleration before apogee. diff --git a/core/src/net/sf/openrocket/simulation/FlightDataBranch.java b/core/src/net/sf/openrocket/simulation/FlightDataBranch.java index 77bc60f56..e2547e4c4 100644 --- a/core/src/net/sf/openrocket/simulation/FlightDataBranch.java +++ b/core/src/net/sf/openrocket/simulation/FlightDataBranch.java @@ -363,5 +363,20 @@ public class FlightDataBranch implements Monitorable { public int getModID() { return modID; } + + public FlightDataBranch clone() { + FlightDataType[] types = getTypes(); + FlightDataBranch clone = new FlightDataBranch(branchName, types); + for (FlightDataType type : values.keySet()) { + clone.values.put(type, values.get(type).clone()); + } + clone.minValues.putAll(minValues); + clone.maxValues.putAll(maxValues); + clone.events.addAll(events); + clone.timeToOptimumAltitude = timeToOptimumAltitude; + clone.optimumAltitude = optimumAltitude; + clone.modID = modID; + return clone; + } } From 5aad8b972208519b8d1000cce97ee9c808c8ab7e Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 29 Mar 2023 22:45:06 +0200 Subject: [PATCH 04/10] Implement loadFrom sims --- .../sf/openrocket/document/Simulation.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index c6371b354..1b261669b 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -268,6 +268,18 @@ public class Simulation implements ChangeSource, Cloneable { mutex.verify(); return simulationExtensions; } + + /** + * Applies the simulation extensions to the simulation. + * @param extensions the simulation extensions to apply. + */ + public void copyExtensionsFrom(List extensions) { + if (extensions == null) { + return; + } + this.simulationExtensions.clear(); + this.simulationExtensions.addAll(extensions); + } /** @@ -554,6 +566,31 @@ public class Simulation implements ChangeSource, Cloneable { mutex.unlock("clone"); } } + + /** + * Load the data from the specified simulation into this simulation. + * @param simulation the simulation to load from. + */ + public void loadFrom(Simulation simulation) { + mutex.lock("loadFrom"); + try { + this.name = simulation.name; + this.configId = simulation.configId; + this.options.copyFrom(simulation.options); + this.simulatedConfigurationDescription = simulation.simulatedConfigurationDescription; + this.simulatedConfigurationID = simulation.simulatedConfigurationID; + if (simulation.simulatedConditions == null) { + this.simulatedConditions = null; + } else { + this.simulatedConditions = simulation.simulatedConditions.clone(); + } + this.simulatedData = simulation.simulatedData; + this.status = simulation.status; + copyExtensionsFrom(simulation.getSimulationExtensions()); + } finally { + mutex.unlock("loadFrom"); + } + } /** From 3acdda83c34abe3e210dbc15efd80bcb8aae4db2 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 30 Mar 2023 00:12:37 +0200 Subject: [PATCH 05/10] Clean up sim cloning & loading --- .../sf/openrocket/document/Simulation.java | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index 1b261669b..07fff25af 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -542,24 +542,27 @@ public class Simulation implements ChangeSource, Cloneable { Simulation clone = (Simulation) super.clone(); clone.mutex = SafetyMutex.newInstance(); - clone.status = status; + clone.name = this.name; + clone.configId = this.configId; + clone.simulatedConfigurationDescription = this.simulatedConfigurationDescription; + clone.simulatedConfigurationID = this.simulatedConfigurationID; clone.options = this.options.clone(); + clone.listeners = new ArrayList<>(); + if (this.simulatedConditions != null) { + clone.simulatedConditions = this.simulatedConditions.clone(); + } else { + clone.simulatedConditions = null; + } clone.simulationExtensions = new ArrayList<>(); for (SimulationExtension c : this.simulationExtensions) { clone.simulationExtensions.add(c.clone()); } - clone.listeners = new ArrayList<>(); - if (simulatedConditions != null) { - clone.simulatedConditions = simulatedConditions.clone(); - } else { - clone.simulatedConditions = null; - } - clone.simulatedConfigurationDescription = simulatedConfigurationDescription; - clone.simulatedData = simulatedData.clone(); - clone.simulatedConfigurationID = simulatedConfigurationID; + clone.status = this.status; + clone.simulatedData = this.simulatedData != null ? this.simulatedData.clone() : this.simulatedData; + clone.simulationStepperClass = this.simulationStepperClass; + clone.aerodynamicCalculatorClass = this.aerodynamicCalculatorClass; return clone; - } catch (CloneNotSupportedException e) { throw new BugException("Clone not supported, BUG", e); } finally { @@ -576,17 +579,25 @@ public class Simulation implements ChangeSource, Cloneable { try { this.name = simulation.name; this.configId = simulation.configId; - this.options.copyFrom(simulation.options); this.simulatedConfigurationDescription = simulation.simulatedConfigurationDescription; this.simulatedConfigurationID = simulation.simulatedConfigurationID; + this.options.copyConditionsFrom(simulation.options); if (simulation.simulatedConditions == null) { this.simulatedConditions = null; } else { - this.simulatedConditions = simulation.simulatedConditions.clone(); + this.simulatedConditions.copyConditionsFrom(simulation.simulatedConditions); + } + copyExtensionsFrom(simulation.getSimulationExtensions()); + this.status = simulation.status; + // Status change, so reset the change listeners to be sure + for (EventListener listener : this.options.getChangeListeners()) { + if (listener instanceof ConditionListener) { + ((ConditionListener) listener).reset(); + } } this.simulatedData = simulation.simulatedData; - this.status = simulation.status; - copyExtensionsFrom(simulation.getSimulationExtensions()); + this.simulationStepperClass = simulation.simulationStepperClass; + this.aerodynamicCalculatorClass = simulation.aerodynamicCalculatorClass; } finally { mutex.unlock("loadFrom"); } @@ -610,7 +621,7 @@ public class Simulation implements ChangeSource, Cloneable { final Simulation newSim = new Simulation(this.document, newRocket); newSim.name = this.name; newSim.configId = this.configId; - newSim.options.copyFrom(this.options); + newSim.options.copyConditionsFrom(this.options); newSim.simulatedConfigurationDescription = this.simulatedConfigurationDescription; for (SimulationExtension c : this.simulationExtensions) { newSim.simulationExtensions.add(c.clone()); @@ -653,16 +664,20 @@ public class Simulation implements ChangeSource, Cloneable { private class ConditionListener implements StateChangeListener { - + private boolean resetState = false; private Status oldStatus = null; @Override public void stateChanged(EventObject e) { - if (getStatus() != oldStatus) { + if (resetState || getStatus() != oldStatus) { oldStatus = getStatus(); fireChangeEvent(); } } + + public void reset() { + resetState = true; + } } } From 2535c1c4689d131142054634e17866448a3dd284 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 30 Mar 2023 00:39:30 +0200 Subject: [PATCH 06/10] Always let condition change fire a change event --- .../net/sf/openrocket/document/Simulation.java | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index 07fff25af..2eca7fd54 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -589,12 +589,6 @@ public class Simulation implements ChangeSource, Cloneable { } copyExtensionsFrom(simulation.getSimulationExtensions()); this.status = simulation.status; - // Status change, so reset the change listeners to be sure - for (EventListener listener : this.options.getChangeListeners()) { - if (listener instanceof ConditionListener) { - ((ConditionListener) listener).reset(); - } - } this.simulatedData = simulation.simulatedData; this.simulationStepperClass = simulation.simulationStepperClass; this.aerodynamicCalculatorClass = simulation.aerodynamicCalculatorClass; @@ -664,19 +658,9 @@ public class Simulation implements ChangeSource, Cloneable { private class ConditionListener implements StateChangeListener { - private boolean resetState = false; - private Status oldStatus = null; - @Override public void stateChanged(EventObject e) { - if (resetState || getStatus() != oldStatus) { - oldStatus = getStatus(); - fireChangeEvent(); - } - } - - public void reset() { - resetState = true; + fireChangeEvent(); } } From a27796b7d2ea28feef1707b87abf0b5ba7eff7d3 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 30 Mar 2023 00:46:58 +0200 Subject: [PATCH 07/10] Remove unused (and worse) copyFrom method --- .../simulation/SimulationOptions.java | 26 +++---------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/core/src/net/sf/openrocket/simulation/SimulationOptions.java b/core/src/net/sf/openrocket/simulation/SimulationOptions.java index 84c20313e..d4c3a5982 100644 --- a/core/src/net/sf/openrocket/simulation/SimulationOptions.java +++ b/core/src/net/sf/openrocket/simulation/SimulationOptions.java @@ -404,28 +404,6 @@ public class SimulationOptions implements ChangeSource, Cloneable { } } - - public void copyFrom(SimulationOptions src) { - - this.launchAltitude = src.launchAltitude; - this.launchLatitude = src.launchLatitude; - this.launchLongitude = src.launchLongitude; - this.launchPressure = src.launchPressure; - this.launchRodAngle = src.launchRodAngle; - this.launchRodDirection = src.launchRodDirection; - this.launchRodLength = src.launchRodLength; - this.launchTemperature = src.launchTemperature; - this.maximumAngle = src.maximumAngle; - this.timeStep = src.timeStep; - this.windAverage = src.windAverage; - this.windTurbulence = src.windTurbulence; - this.windDirection = src.windDirection; - this.calculateExtras = src.calculateExtras; - this.randomSeed = src.randomSeed; - - fireChangeEvent(); - } - public void copyConditionsFrom(SimulationOptions src) { // Be a little smart about triggering the change event. // only do it if one of the "important" (user specified) parameters has really changed. @@ -550,6 +528,10 @@ public class SimulationOptions implements ChangeSource, Cloneable { public void removeChangeListener(StateChangeListener listener) { listeners.remove(listener); } + + public List getChangeListeners() { + return listeners; + } private final EventObject event = new EventObject(this); From f6b932c4a7947d16a7a555549c2bd9a3f91d24fb Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 30 Mar 2023 00:47:40 +0200 Subject: [PATCH 08/10] [#2158] Add ok/cancel button for simulation editing --- core/resources/l10n/messages.properties | 8 ++ .../sf/openrocket/startup/Preferences.java | 17 +++ .../preferences/DesignPreferencesPanel.java | 13 ++ .../openrocket/gui/main/SimulationPanel.java | 10 +- .../gui/simulation/SimulationEditDialog.java | 118 ++++++++++++++++-- 5 files changed, 151 insertions(+), 15 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 88290ee6d..435a71a49 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -318,6 +318,8 @@ pref.dlg.checkbox.AlwaysOpenLeftmost = Always open leftmost tab when opening a c pref.dlg.checkbox.AlwaysOpenLeftmost.ttip = If checked, a component edit dialog will always pop up with the first tab selected.
If unchecked, the previous selected tab will be used. pref.dlg.checkbox.ShowDiscardConfirmation = Show confirmation dialog for discarding component changes pref.dlg.checkbox.ShowDiscardConfirmation.ttip = If checked, you will be asked if you want really want to discard component configuration configuration changes. +pref.dlg.checkbox.ShowDiscardSimulationConfirmation = Show confirmation dialog for discarding simulation changes +pref.dlg.checkbox.ShowDiscardSimulationConfirmation.ttip = If checked, you will be asked if you want really want to discard simulation configuration configuration changes. pref.dlg.lbl.User-definedthrust = User-defined thrust curves: pref.dlg.lbl.Windspeed = Wind speed pref.dlg.Allthrustcurvefiles = All thrust curve files (*.eng; *.rse; *.zip; directories) @@ -516,6 +518,12 @@ SimulationEditDialog.btn.export = Export SimulationEditDialog.btn.edit = Edit SimulationEditDialog.btn.simulate = Simulate SimulationEditDialog.btn.simulateAndPlot = Simulate & Plot +SimulationEditDialog.btn.OK.ttip = Keep changes and close the dialog +SimulationEditDialog.btn.Cancel.ttip = Discard changes and close the dialog +SimulationEditDialog.CancelOperation.msg.discardChanges = Are you sure you want to discard your changes to this simulation? +SimulationEditDialog.CancelOperation.msg.undoAdd = Are you sure you want to undo adding this simulation? +SimulationEditDialog.CancelOperation.title = Cancel operation +SimulationEditDialog.CancelOperation.checkbox.dontAskAgain = Don't ask me again GeodeticComputationStrategy.flat.name = Flat Earth GeodeticComputationStrategy.flat.desc = Perform computations with a flat Earth approximation. Sufficient for low-altitude flights. diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java index eac3b3642..8b7d01d13 100644 --- a/core/src/net/sf/openrocket/startup/Preferences.java +++ b/core/src/net/sf/openrocket/startup/Preferences.java @@ -77,6 +77,7 @@ public abstract class Preferences implements ChangeSource { private static final String AUTO_OPEN_LAST_DESIGN = "AUTO_OPEN_LAST_DESIGN"; private static final String OPEN_LEFTMOST_DESIGN_TAB = "OPEN_LEFTMOST_DESIGN_TAB"; private static final String SHOW_DISCARD_CONFIRMATION = "IgnoreDiscardEditingWarning"; + private static final String SHOW_DISCARD_SIMULATION_CONFIRMATION = "IgnoreDiscardSimulationEditingWarning"; public static final String MARKER_STYLE_ICON = "MARKER_STYLE_ICON"; private static final String SHOW_MARKERS = "SHOW_MARKERS"; private static final String SHOW_ROCKSIM_FORMAT_WARNING = "SHOW_ROCKSIM_FORMAT_WARNING"; @@ -537,6 +538,22 @@ public abstract class Preferences implements ChangeSource { this.putBoolean(SHOW_DISCARD_CONFIRMATION, enabled); } + /** + * Answer if a confirmation dialog should be shown when canceling a simulation config operation. + * + * @return true if the confirmation dialog should be shown. + */ + public final boolean isShowDiscardSimulationConfirmation() { + return this.getBoolean(SHOW_DISCARD_SIMULATION_CONFIRMATION, true); + } + + /** + * Enable/Disable showing a confirmation warning when canceling a simulation config operation. + */ + public final void setShowDiscardSimulationConfirmation(boolean enabled) { + this.putBoolean(SHOW_DISCARD_SIMULATION_CONFIRMATION, enabled); + } + /** * Answer if the always open leftmost tab is enabled. * diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java index c91962d7c..74dcf1580 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java @@ -115,6 +115,19 @@ public class DesignPreferencesPanel extends PreferencesPanel { }); this.add(showDiscardConfirmation, "wrap, growx, spanx"); + // // Show confirmation dialog for discarding simulation configuration changes + final JCheckBox showDiscardSimulationConfirmation = new JCheckBox( + trans.get("pref.dlg.checkbox.ShowDiscardSimulationConfirmation")); + showDiscardSimulationConfirmation.setSelected(preferences.isShowDiscardSimulationConfirmation()); + showDiscardSimulationConfirmation.setToolTipText(trans.get("pref.dlg.checkbox.ShowDiscardSimulationConfirmation.ttip")); + showDiscardSimulationConfirmation.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + preferences.setShowDiscardSimulationConfirmation(e.getStateChange() == ItemEvent.SELECTED); + } + }); + this.add(showDiscardSimulationConfirmation, "wrap, growx, spanx"); + // // Update flight estimates in the design window final JCheckBox updateEstimates = new JCheckBox( trans.get("pref.dlg.checkbox.Updateestimates")); diff --git a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java index b1a31377b..a22987392 100644 --- a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -297,7 +297,7 @@ public class SimulationPanel extends JPanel { simulationTable.addRowSelectionInterval(n, n); updatePreviousSelection(); - openDialog(false, sim); + openDialog(false, true, sim); } private void plotSimulation() { @@ -595,8 +595,8 @@ public class SimulationPanel extends JPanel { return simulationTable.getSelectionModel(); } - private void openDialog(boolean plotMode, final Simulation... sims) { - SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sims); + private void openDialog(boolean plotMode, boolean isNewSimulation, final Simulation... sims) { + SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, isNewSimulation, sims); if (plotMode) { d.setPlotMode(); } @@ -605,6 +605,10 @@ public class SimulationPanel extends JPanel { takeTheSpotlight(); } + private void openDialog(boolean plotMode, final Simulation... sims) { + openDialog(plotMode, false, sims); + } + private void openDialog(final Simulation sim) { boolean plotMode = false; if (sim.hasSimulationData() && Simulation.isStatusUpToDate(sim.getStatus())) { diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java index 32effec96..9f54e68de 100644 --- a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java +++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java @@ -5,14 +5,18 @@ import java.awt.CardLayout; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; +import java.util.EventObject; import javax.swing.JButton; -import javax.swing.JComboBox; +import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JLabel; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.JTextField; @@ -33,6 +37,8 @@ import net.sf.openrocket.rocketcomponent.FlightConfigurationId; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.simulation.extension.SimulationExtension; import net.sf.openrocket.startup.Application; +import net.sf.openrocket.startup.Preferences; +import net.sf.openrocket.util.StateChangeListener; public class SimulationEditDialog extends JDialog { @@ -41,19 +47,34 @@ public class SimulationEditDialog extends JDialog { private final Simulation[] simulationList; private final OpenRocketDocument document; private static final Translator trans = Application.getTranslator(); + private static final Preferences preferences = Application.getPreferences(); JPanel cards; private final static String EDITMODE = "EDIT"; private final static String PLOTMODE = "PLOT"; - private WindowListener applyChangesToSimsListener; + private final WindowListener applyChangesToSimsListener; + private final Simulation initialSim; + private boolean isModified = false; + private final boolean isNewSimulation; - public SimulationEditDialog(Window parent, final OpenRocketDocument document, Simulation... sims) { + public SimulationEditDialog(Window parent, final OpenRocketDocument document, boolean isNewSimulation, Simulation... sims) { //// Edit simulation super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL); this.document = document; this.parentWindow = parent; this.simulationList = sims; + this.initialSim = simulationList[0].clone(); + this.isNewSimulation = isNewSimulation; + + simulationList[0].addChangeListener(new StateChangeListener() { + @Override + public void stateChanged(EventObject e) { + isModified = true; + setTitle("* " + getTitle()); // Add component changed indicator to the title + simulationList[0].removeChangeListener(this); + } + }); this.cards = new JPanel(new CardLayout()); this.add(cards); @@ -85,6 +106,7 @@ public class SimulationEditDialog extends JDialog { } public void setEditMode() { + setTitle((isModified ? "* " : "") + trans.get("simedtdlg.title.Editsim")); CardLayout cl = (CardLayout) (cards.getLayout()); cl.show(cards, EDITMODE); cards.validate(); @@ -96,7 +118,7 @@ public class SimulationEditDialog extends JDialog { return; } this.removeWindowListener(applyChangesToSimsListener); - setTitle(trans.get("simplotpanel.title.Plotsim")); + setTitle((isModified ? "* " : "") + trans.get("simplotpanel.title.Plotsim")); CardLayout cl = (CardLayout) (cards.getLayout()); cl.show(cards, PLOTMODE); cards.validate(); @@ -150,7 +172,6 @@ public class SimulationEditDialog extends JDialog { String name = field.getText(); if (name == null || name.equals("")) return; - //System.out.println("Setting name:" + name); simulationList[0].setName(name); } @@ -208,7 +229,7 @@ public class SimulationEditDialog extends JDialog { } }); - simEditPanel.add(button, "spanx, split 3, align left"); + simEditPanel.add(button, "spanx, split 4, align left"); if (allowsPlotMode()) { button.setVisible(true); } else { @@ -231,17 +252,49 @@ public class SimulationEditDialog extends JDialog { } } }); - simEditPanel.add(button, " align right, tag ok"); - - //// Close button - JButton close = new SelectColorButton(trans.get("dlg.but.close")); - close.addActionListener(new ActionListener() { + simEditPanel.add(button, " align right, gapright 10lp, tag ok"); + + //// Cancel button + JButton cancelButton = new SelectColorButton(trans.get("dlg.but.cancel")); + cancelButton.setToolTipText(trans.get("SimulationEditDialog.btn.Cancel.ttip")); + cancelButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { + // Don't do anything on cancel if you are editing an existing simulation, and it is not modified + if (!isNewSimulation && !isModified) { + SimulationEditDialog.this.removeWindowListener(applyChangesToSimsListener); + SimulationEditDialog.this.dispose(); + return; + } + + // Apply the cancel operation if set to auto discard in preferences + if (!preferences.isShowDiscardSimulationConfirmation()) { + discardChanges(); + return; + } + + // Yes/No dialog: Are you sure you want to discard your changes? + JPanel msg = createCancelOperationContent(); + int resultYesNo = JOptionPane.showConfirmDialog(SimulationEditDialog.this, msg, + trans.get("SimulationEditDialog.CancelOperation.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (resultYesNo == JOptionPane.YES_OPTION) { + discardChanges(); + } + } + }); + simEditPanel.add(cancelButton, "tag ok"); + + //// Ok button + JButton okButton = new SelectColorButton(trans.get("dlg.but.ok")); + okButton.setToolTipText(trans.get("SimulationEditDialog.btn.OK.ttip")); + okButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + copyChangesToAllSims(); SimulationEditDialog.this.dispose(); } }); - simEditPanel.add(close, "tag ok"); + simEditPanel.add(okButton, "tag ok"); cards.add(simEditPanel, EDITMODE); } @@ -336,4 +389,45 @@ public class SimulationEditDialog extends JDialog { } } + + private JPanel createCancelOperationContent() { + JPanel panel = new JPanel(new MigLayout()); + String msg = isNewSimulation ? trans.get("SimulationEditDialog.CancelOperation.msg.undoAdd") : + trans.get("SimulationEditDialog.CancelOperation.msg.discardChanges"); + JLabel msgLabel = new JLabel(msg); + JCheckBox dontAskAgain = new JCheckBox(trans.get("SimulationEditDialog.CancelOperation.checkbox.dontAskAgain")); + dontAskAgain.setSelected(false); + dontAskAgain.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + preferences.setShowDiscardSimulationConfirmation(false); + } + // Unselected state should be not be possible and thus not be handled + } + }); + + panel.add(msgLabel, "left, wrap"); + panel.add(dontAskAgain, "left, gaptop para"); + + return panel; + } + + private void discardChanges() { + if (isNewSimulation) { + document.removeSimulation(simulationList[0]); + } else { + undoSimulationChanges(); + } + + SimulationEditDialog.this.removeWindowListener(applyChangesToSimsListener); + SimulationEditDialog.this.dispose(); + } + + private void undoSimulationChanges() { + if (simulationList == null || simulationList.length == 0) { + return; + } + simulationList[0].loadFrom(initialSim); + } } From 8cfc093433f23ff8902de846118a7ebe556bc376 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 30 Mar 2023 04:25:05 +0200 Subject: [PATCH 09/10] Restore the save state of the document --- .../gui/simulation/SimulationEditDialog.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java index 9f54e68de..5acb6eabc 100644 --- a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java +++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java @@ -28,6 +28,7 @@ import javax.swing.event.DocumentListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.document.events.DocumentChangeEvent; import net.sf.openrocket.gui.components.ConfigurationComboBox; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.gui.widgets.SelectColorButton; @@ -54,9 +55,10 @@ public class SimulationEditDialog extends JDialog { private final static String PLOTMODE = "PLOT"; private final WindowListener applyChangesToSimsListener; - private final Simulation initialSim; - private boolean isModified = false; - private final boolean isNewSimulation; + private final Simulation initialSim; // A copy of the first selected simulation before it was modified + private final boolean initialIsSaved; // Whether the document was saved before the dialog was opened + private boolean isModified = false; // Whether the simulation has been modified + private final boolean isNewSimulation; // Whether you are editing a new simulation, or an existing one public SimulationEditDialog(Window parent, final OpenRocketDocument document, boolean isNewSimulation, Simulation... sims) { //// Edit simulation @@ -65,6 +67,7 @@ public class SimulationEditDialog extends JDialog { this.parentWindow = parent; this.simulationList = sims; this.initialSim = simulationList[0].clone(); + this.initialIsSaved = document.isSaved(); this.isNewSimulation = isNewSimulation; simulationList[0].addChangeListener(new StateChangeListener() { @@ -419,6 +422,8 @@ public class SimulationEditDialog extends JDialog { } else { undoSimulationChanges(); } + document.setSaved(this.initialIsSaved); // Restore the saved state of the document + document.fireDocumentChangeEvent(new DocumentChangeEvent(this)); SimulationEditDialog.this.removeWindowListener(applyChangesToSimsListener); SimulationEditDialog.this.dispose(); From 26f6473446ea7765c7d2e25108491b21be2c7a34 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 30 Mar 2023 11:44:00 +0200 Subject: [PATCH 10/10] Fix set launch rod length & launch into wind not triggering change event --- core/src/net/sf/openrocket/simulation/SimulationOptions.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/net/sf/openrocket/simulation/SimulationOptions.java b/core/src/net/sf/openrocket/simulation/SimulationOptions.java index d4c3a5982..19c769903 100644 --- a/core/src/net/sf/openrocket/simulation/SimulationOptions.java +++ b/core/src/net/sf/openrocket/simulation/SimulationOptions.java @@ -96,6 +96,7 @@ public class SimulationOptions implements ChangeSource, Cloneable { if (MathUtil.equals(this.launchRodLength, launchRodLength)) return; this.launchRodLength = launchRodLength; + fireChangeEvent(); } @@ -104,7 +105,10 @@ public class SimulationOptions implements ChangeSource, Cloneable { } public void setLaunchIntoWind(boolean i) { + if (launchIntoWind == i) + return; launchIntoWind = i; + fireChangeEvent(); } public double getLaunchRodAngle() {