[#1454] Fix stackoverflow error

Make sure the InsideColorComponentHandler is cloned when a RocketComponent is cloned + don't clone the configListeners
This commit is contained in:
SiboVG 2022-06-17 10:52:23 +02:00
parent f1a203ea6c
commit 00fcc34509
11 changed files with 67 additions and 11 deletions

View File

@ -555,7 +555,7 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @return true if listener was successfully added, false if not
*/
public boolean addConfigListener(RocketComponent component, AppearanceBuilder ab) {
if (component == null || ab == null) {
if (component == null || ab == null || configListeners.values().contains(ab) || ab == this) {
return false;
}
configListeners.put(component, ab);

View File

@ -31,7 +31,7 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou
private MotorConfigurationSet motors;
private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
public BodyTube() {
this(8 * DEFAULT_RADIUS, DEFAULT_RADIUS);
@ -521,6 +521,11 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou
return this.insideColorComponentHandler;
}
@Override
public void setInsideColorComponentHandler(InsideColorComponentHandler handler) {
this.insideColorComponentHandler = handler;
}
@Override
public boolean addConfigListener(RocketComponent listener) {
boolean success = super.addConfigListener(listener);

View File

@ -123,7 +123,7 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
private double totalVolume = Double.NaN;
private Coordinate centerOfMass = Coordinate.NaN;
private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
/**
* New FinSet with given number of fins and given base rotation angle.
@ -1369,4 +1369,9 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
public InsideColorComponentHandler getInsideColorComponentHandler() {
return this.insideColorComponentHandler;
}
@Override
public void setInsideColorComponentHandler(InsideColorComponentHandler handler) {
this.insideColorComponentHandler = handler;
}
}

View File

@ -22,4 +22,6 @@ public interface InsideColorComponent {
* @return the InsideColorComponentHandler
*/
InsideColorComponentHandler getInsideColorComponentHandler();
void setInsideColorComponentHandler(InsideColorComponentHandler handler);
}

View File

@ -30,7 +30,7 @@ public class LaunchLug extends Tube implements AnglePositionable, BoxBounded, Li
private int instanceCount = 1;
private double instanceSeparation = 0; // front-front along the positive rocket axis. i.e. [1,0,0];
private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
public LaunchLug() {
super(AxialMethod.MIDDLE);
@ -333,4 +333,9 @@ public class LaunchLug extends Tube implements AnglePositionable, BoxBounded, Li
public InsideColorComponentHandler getInsideColorComponentHandler() {
return this.insideColorComponentHandler;
}
@Override
public void setInsideColorComponentHandler(InsideColorComponentHandler handler) {
this.insideColorComponentHandler = handler;
}
}

View File

@ -20,7 +20,7 @@ import java.util.EventObject;
public class NoseCone extends Transition implements InsideColorComponent {
private static final Translator trans = Application.getTranslator();
private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
/********* Constructors **********/
public NoseCone() {
@ -155,4 +155,9 @@ public class NoseCone extends Transition implements InsideColorComponent {
public InsideColorComponentHandler getInsideColorComponentHandler() {
return this.insideColorComponentHandler;
}
@Override
public void setInsideColorComponentHandler(InsideColorComponentHandler handler) {
this.insideColorComponentHandler = handler;
}
}

View File

@ -134,7 +134,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
/**
* List of components that will set their properties to the same as the current component
*/
protected final List<RocketComponent> configListeners = new LinkedList<>();
protected List<RocketComponent> configListeners = new LinkedList<>();
/**
@ -427,6 +427,20 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
}
}
@Override
public RocketComponent clone() throws CloneNotSupportedException {
RocketComponent clone = (RocketComponent) super.clone();
// Make sure the InsideColorComponentHandler is cloned
if (clone instanceof InsideColorComponent && this instanceof InsideColorComponent) {
InsideColorComponentHandler icch = new InsideColorComponentHandler(clone);
icch.copyFrom(((InsideColorComponent) this).getInsideColorComponentHandler());
((InsideColorComponent) clone).setInsideColorComponentHandler(icch);
}
// Make sure the config listeners aren't cloned
clone.configListeners = new LinkedList<>();
return clone;
}
/**
* Return true if any of this component's children are a RecoveryDevice
*/
@ -1983,7 +1997,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
* @return true if listener was successfully added, false if not
*/
public boolean addConfigListener(RocketComponent listener) {
if (listener == null) {
if (listener == null || configListeners.contains(listener) || listener == this) {
return false;
}
configListeners.add(listener);
@ -2247,6 +2261,12 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
this.id = src.id;
this.displayOrder_side = src.displayOrder_side;
this.displayOrder_back = src.displayOrder_back;
this.configListeners = new LinkedList<>();
if (this instanceof InsideColorComponent && src instanceof InsideColorComponent) {
InsideColorComponentHandler icch = new InsideColorComponentHandler(this);
icch.copyFrom(((InsideColorComponent) src).getInsideColorComponentHandler());
((InsideColorComponent) this).setInsideColorComponentHandler(icch);
}
// Add source components to invalidation tree
for (RocketComponent c : src) {

View File

@ -44,7 +44,7 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
// Used to cache the clip length
private double clipLength = -1;
private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
public Transition() {
super();
@ -732,6 +732,11 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
return this.insideColorComponentHandler;
}
@Override
public void setInsideColorComponentHandler(InsideColorComponentHandler handler) {
this.insideColorComponentHandler = handler;
}
/**
* An enumeration listing the possible shapes of transitions.
*

View File

@ -28,7 +28,7 @@ public class TubeFinSet extends Tube implements AxialPositionable, BoxBounded, R
private AngleMethod angleMethod = AngleMethod.FIXED;
protected RadiusMethod radiusMethod = RadiusMethod.RELATIVE;
private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
/**
* Rotation angle of the first fin. Zero corresponds to the positive y-axis.
@ -523,4 +523,9 @@ public class TubeFinSet extends Tube implements AxialPositionable, BoxBounded, R
public InsideColorComponentHandler getInsideColorComponentHandler() {
return this.insideColorComponentHandler;
}
@Override
public void setInsideColorComponentHandler(InsideColorComponentHandler handler) {
this.insideColorComponentHandler = handler;
}
}

View File

@ -345,6 +345,7 @@ public class BasicFrame extends JFrame {
c.clearConfigListeners();
for (int i = 1; i < paths.length; i++) {
RocketComponent listener = (RocketComponent) paths[i].getLastPathComponent();
listener.clearConfigListeners();
c.addConfigListener(listener);
}
ComponentConfigDialog.showDialog(BasicFrame.this, BasicFrame.this.document, c);

View File

@ -791,6 +791,7 @@ public class RocketActions {
Simulation[] sims = selectionModel.getSelectedSimulations();
if (isCopyable(components)) {
if (ComponentConfigDialog.isDialogVisible())
ComponentConfigDialog.disposeDialog();
List<RocketComponent> copiedComponents = copyComponentsMaintainParent(components);
@ -885,7 +886,9 @@ public class RocketActions {
RocketComponent component = components.get(0);
if (components.size() > 1) {
for (int i = 1; i < components.size(); i++) {
component.addConfigListener(components.get(i));
RocketComponent listener = components.get(i);
listener.clearConfigListeners(); // Make sure all the listeners are cleared (should not be possible, but just in case)
component.addConfigListener(listener);
}
}
ComponentConfigDialog.showDialog(parentFrame, document, component);