diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java index bdb8102ab..dd033566c 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java @@ -1421,6 +1421,67 @@ 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(boolean freezeRocket) { + final RocketComponent root = getRoot(); + RocketComponent parent = getParent(); + int index = parent.getChildPosition(this); + int count = getFinCount(); + double base = getBaseRotation(); + + List splitFins = null; // List of all the split fins + + try { + // Freeze rocket + if (freezeRocket && root instanceof Rocket) { + ((Rocket) root).freeze(); + } + + // 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){ return getPointDescr(Arrays.asList(points), name, indent); diff --git a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java index 94a4f80b9..99d901e93 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); + finset.removeConfigListener(listener); + freeform.addConfigListener(listenerSet); + } + } } 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. * diff --git a/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java index 42e231cd8..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; @@ -104,32 +105,25 @@ 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()); - + + // 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 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); + for (RocketComponent listener : listeners) { + component.addConfigListener(listener); } + ((FinSet) component).splitFins(); + component.clearConfigListeners(); } }); - - ComponentConfigDialog.disposeDialog(); } }); split.setEnabled(((FinSet) component).getFinCount() > 1);