From 2822e0ec275225d91b1e31c58c3bdc1bdbceb47c Mon Sep 17 00:00:00 2001 From: SiboVG Date: Mon, 20 Mar 2023 16:45:31 +0100 Subject: [PATCH 1/5] [#2126] Apply freeform conversion to config listeners --- .../rocketcomponent/FreeformFinSet.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java index 94a4f80b9..518433a6c 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java @@ -45,15 +45,16 @@ public class FreeformFinSet extends FinSet { * The specified fin set should not be used after the call! * * @param finset the fin set to convert. + * @param freezeRocket whether to freeze the rocket before conversion. * @return the new freeform fin set. */ - public static FreeformFinSet convertFinSet(FinSet finset) { + public static FreeformFinSet convertFinSet(FinSet finset, boolean freezeRocket) { final RocketComponent root = finset.getRoot(); FreeformFinSet freeform; List toInvalidate = new ArrayList<>(); try { - if (root instanceof Rocket) { + if (freezeRocket && root instanceof Rocket) { ((Rocket) root).freeze(); } @@ -91,9 +92,18 @@ public class FreeformFinSet extends FinSet { if (parent != null) { parent.addChild(freeform, position); } + + // Convert config listeners + for (RocketComponent listener : finset.configListeners) { + if (listener instanceof FinSet) { + FreeformFinSet listenerSet = FreeformFinSet.convertFinSet((FinSet) listener, false); + freeform.addConfigListener(listenerSet); + finset.removeConfigListener(listener); + } + } } finally { - if (root instanceof Rocket) { + if (freezeRocket && root instanceof Rocket) { ((Rocket) root).thaw(); } // Invalidate components after events have been fired @@ -101,9 +111,24 @@ public class FreeformFinSet extends FinSet { c.invalidate(); } } + return freeform; } + /** + * Convert an existing fin set into a freeform fin set. The specified + * fin set is taken out of the rocket tree (if any) and the new component + * inserted in its stead. + *

+ * The specified fin set should not be used after the call! + * + * @param finset the fin set to convert. + * @return the new freeform fin set. + */ + public static FreeformFinSet convertFinSet(FinSet finset) { + return convertFinSet(finset, true); + } + /** * Converts a point of this fin set to edit into a point for a config listener to edit. * From 0e93ca7c25d24a5fbad8abc32e7cb895d6dcb177 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Mon, 20 Mar 2023 23:48:03 +0100 Subject: [PATCH 2/5] Use multi-comp fin splitting --- .../sf/openrocket/rocketcomponent/FinSet.java | 39 +++++++++++++++++++ .../gui/configdialog/FinSetConfig.java | 17 +------- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java index 83bc3b553..ece537bcd 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java @@ -1421,6 +1421,45 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } + /** + * Split the fin set into individual fins. + * @return A list of the new fin sets. + */ + public List splitFins() { + RocketComponent parent = getParent(); + int index = parent.getChildPosition(this); + int count = getFinCount(); + double base = getBaseRotation(); + + List splitFins = null; // List of all the split fins + + if (count > 1) { + parent.removeChild(index); + splitFins = new ArrayList<>(); + for (int i = 0; i < count; i++) { + FinSet copy = (FinSet) this.copy(); + copy.setFinCount(1); + copy.setBaseRotation(base + i * 2 * Math.PI / count); + copy.setName(copy.getName() + " #" + (i + 1)); + copy.setOverrideMass(getOverrideMass() / getFinCount()); + parent.addChild(copy, index + i); + + splitFins.add(copy); + } + } + + // Split fins for children + for (RocketComponent listener : configListeners) { + if (listener instanceof FinSet) { + ((FinSet) listener).splitFins(); + this.removeConfigListener(listener); + } + } + + return splitFins; + } + + // for debugging. You can safely delete this method public static String getPointDescr( final Coordinate[] points, final String name, final String indent){ return getPointDescr(Arrays.asList(points), name, indent); diff --git a/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java index 42e231cd8..f4455bef6 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java @@ -109,23 +109,8 @@ public abstract class FinSetConfig extends RocketComponentConfig { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - RocketComponent parent = component.getParent(); - int index = parent.getChildPosition(component); - int count = ((FinSet) component).getFinCount(); - double base = ((FinSet) component).getBaseRotation(); - if (count <= 1) - return; - document.addUndoPosition("Split fin set"); - parent.removeChild(index); - for (int i = 0; i < count; i++) { - FinSet copy = (FinSet) component.copy(); - copy.setFinCount(1); - copy.setBaseRotation(base + i * 2 * Math.PI / count); - copy.setName(copy.getName() + " #" + (i + 1)); - copy.setOverrideMass(((FinSet) component).getOverrideMass()/((FinSet) component).getFinCount()); - parent.addChild(copy, index + i); - } + ((FinSet) component).splitFins(); } }); From 62506eced0990e32eed11196e56e694c279aeeae Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 21 Mar 2023 22:52:29 +0100 Subject: [PATCH 3/5] Use rocket freezing for split fins --- .../sf/openrocket/rocketcomponent/FinSet.java | 60 +++++++++++++------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java index ece537bcd..00eefcb68 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java @@ -1425,7 +1425,8 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona * Split the fin set into individual fins. * @return A list of the new fin sets. */ - public List splitFins() { + public List splitFins(boolean freezeRocket) { + final RocketComponent root = getRoot(); RocketComponent parent = getParent(); int index = parent.getChildPosition(this); int count = getFinCount(); @@ -1433,32 +1434,53 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona List splitFins = null; // List of all the split fins - if (count > 1) { - parent.removeChild(index); - splitFins = new ArrayList<>(); - for (int i = 0; i < count; i++) { - FinSet copy = (FinSet) this.copy(); - copy.setFinCount(1); - copy.setBaseRotation(base + i * 2 * Math.PI / count); - copy.setName(copy.getName() + " #" + (i + 1)); - copy.setOverrideMass(getOverrideMass() / getFinCount()); - parent.addChild(copy, index + i); - - splitFins.add(copy); + try { + // Freeze rocket + if (freezeRocket && root instanceof Rocket) { + ((Rocket) root).freeze(); } - } - // Split fins for children - for (RocketComponent listener : configListeners) { - if (listener instanceof FinSet) { - ((FinSet) listener).splitFins(); - this.removeConfigListener(listener); + // Split the fins + if (count > 1) { + parent.removeChild(index); + splitFins = new ArrayList<>(); + for (int i = 0; i < count; i++) { + FinSet copy = (FinSet) this.copy(); + copy.setFinCount(1); + copy.setBaseRotation(base + i * 2 * Math.PI / count); + copy.setName(copy.getName() + " #" + (i + 1)); + copy.setOverrideMass(getOverrideMass() / getFinCount()); + parent.addChild(copy, index + i); + + splitFins.add(copy); + } + } + + // Split fins for children + for (RocketComponent listener : configListeners) { + if (listener instanceof FinSet) { + ((FinSet) listener).splitFins(false); + this.removeConfigListener(listener); + } + } + } finally { + // Unfreeze rocket + if (freezeRocket && root instanceof Rocket) { + ((Rocket) root).thaw(); } } return splitFins; } + /** + * Split the fin set into individual fins. + * @return A list of the new fin sets. + */ + public List splitFins() { + return splitFins(true); + } + // for debugging. You can safely delete this method public static String getPointDescr( final Coordinate[] points, final String name, final String indent){ From ee8dbffd983f06dd123de0a30ea1f651f6ae8372 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 21 Mar 2023 22:58:21 +0100 Subject: [PATCH 4/5] Dispose dialog before splitting fins This fixes a NullPointerException (see #2127) --- .../net/sf/openrocket/gui/configdialog/FinSetConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java index f4455bef6..52653c5ba 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java @@ -104,7 +104,9 @@ public abstract class FinSetConfig extends RocketComponentConfig { public void actionPerformed(ActionEvent e) { log.info(Markers.USER_MARKER, "Splitting " + component.getComponentName() + " into separate fins, fin count=" + ((FinSet) component).getFinCount()); - + + ComponentConfigDialog.disposeDialog(); + // Do change in future for overall safety SwingUtilities.invokeLater(new Runnable() { @Override @@ -113,8 +115,6 @@ public abstract class FinSetConfig extends RocketComponentConfig { ((FinSet) component).splitFins(); } }); - - ComponentConfigDialog.disposeDialog(); } }); split.setEnabled(((FinSet) component).getFinCount() > 1); From 4b525611ce9352bd6828b72d0f754422c07612b5 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 21 Mar 2023 23:06:01 +0100 Subject: [PATCH 5/5] Fix split not working on config listeners --- .../sf/openrocket/rocketcomponent/FreeformFinSet.java | 2 +- .../net/sf/openrocket/gui/configdialog/FinSetConfig.java | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java index 518433a6c..99d901e93 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java @@ -97,8 +97,8 @@ public class FreeformFinSet extends FinSet { for (RocketComponent listener : finset.configListeners) { if (listener instanceof FinSet) { FreeformFinSet listenerSet = FreeformFinSet.convertFinSet((FinSet) listener, false); - freeform.addConfigListener(listenerSet); finset.removeConfigListener(listener); + freeform.addConfigListener(listenerSet); } } diff --git a/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java index 52653c5ba..eb45a473f 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java @@ -1,5 +1,6 @@ package net.sf.openrocket.gui.configdialog; +import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; @@ -105,6 +106,10 @@ public abstract class FinSetConfig extends RocketComponentConfig { log.info(Markers.USER_MARKER, "Splitting " + component.getComponentName() + " into separate fins, fin count=" + ((FinSet) component).getFinCount()); + // This is a bit awkward, we need to store the listeners before closing the dialog, because closing it + // will remove them. We then add them back before the split and remove them afterwards. + List listeners = new ArrayList<>(component.getConfigListeners()); + ComponentConfigDialog.disposeDialog(); // Do change in future for overall safety @@ -112,7 +117,11 @@ public abstract class FinSetConfig extends RocketComponentConfig { @Override public void run() { document.addUndoPosition("Split fin set"); + for (RocketComponent listener : listeners) { + component.addConfigListener(listener); + } ((FinSet) component).splitFins(); + component.clearConfigListeners(); } }); }