diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 96b47e1f4..984e24dc7 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -2082,8 +2082,8 @@ Warning.AIRFRAME_GAP = Gap in rocket airframe Warning.AIRFRAME_OVERLAP = Overlap in airframe components Warning.PODSET_FORWARD = In-line podset forward of parent airframe component Warning.PODSET_OVERLAP = In-line podset overlaps parent airframe component -Warning.THICK_FIN = Thick fins may not simulate accurately. -Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate. +Warning.THICK_FIN = Thick fins may not simulate accurately +Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate Warning.ZERO_AREA_FIN = Fins with zero area will not affect aerodynamics Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING = Recovery device opened while motor still burning. diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java index 22e21cf39..f31a065ad 100644 --- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java @@ -315,7 +315,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { SymmetricComponent sym = (SymmetricComponent) comp; if( null == prevComp){ if (sym.getForeRadius() - sym.getThickness() > MathUtil.EPSILON) { - warnings.add(Warning.OPEN_AIRFRAME_FORWARD, sym.toString()); + warnings.add(Warning.OPEN_AIRFRAME_FORWARD, sym); } } else { // Check for radius discontinuity @@ -324,13 +324,13 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { // present as different if the discontinuity is big enough to matter. if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*sym.getForeRadius()) .equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*prevComp.getAftRadius()))) { - warnings.add( Warning.DIAMETER_DISCONTINUITY, prevComp + ", " + sym); + warnings.add(Warning.DIAMETER_DISCONTINUITY, prevComp, sym); } // Check for phantom tube if ((sym.getLength() < MathUtil.EPSILON) || (sym.getAftRadius() < MathUtil.EPSILON && sym.getForeRadius() < MathUtil.EPSILON)) { - warnings.add(Warning.ZERO_VOLUME_BODY, sym.getName()); + warnings.add(Warning.ZERO_VOLUME_BODY, sym); } // check for gap or overlap in airframe. We'll use a textual comparison to see if there is a @@ -346,13 +346,13 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(symXfore) .equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(prevXaft))) { if (symXfore > prevXaft) { - warnings.add(Warning.AIRFRAME_GAP, prevComp + ", " + sym); + warnings.add(Warning.AIRFRAME_GAP, prevComp, sym); } else { // If we only have the component with a single forward compartment bring up // a body component overlap message if ((symXfore >= prevXfore) && ((symXaft >= prevXaft) || (null == sym.getNextSymmetricComponent()))) { - warnings.add(Warning.AIRFRAME_OVERLAP, prevComp + ", " + sym); + warnings.add(Warning.AIRFRAME_OVERLAP, prevComp, sym); } else { // We have a PodSet that is either overlapping or completely forward of its parent component. // We'll find the forward-most and aft-most components and figure out which @@ -374,9 +374,9 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { // completely forward vs. overlap if (lastCompXaft <= firstCompXfore) { - warnings.add(Warning.PODSET_FORWARD, comp.getParent().toString()); + warnings.add(Warning.PODSET_FORWARD, comp.getParent()); } else { - warnings.add(Warning.PODSET_OVERLAP, comp.getParent().toString()); + warnings.add(Warning.PODSET_OVERLAP, comp.getParent()); } } @@ -393,7 +393,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { null : prevCompParent.getChild(prevCompPos + 1); if ((compParent instanceof PodSet || compParent instanceof ParallelStage) && MathUtil.equals(symXfore, prevXaft) && (compParent.getParent() == nextComp)) { - warnings.add(Warning.PODSET_OVERLAP, comp.getParent().toString()); + warnings.add(Warning.PODSET_OVERLAP, comp.getParent()); } } } diff --git a/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java b/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java index dfd9a319f..ac13abaa0 100644 --- a/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java +++ b/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java @@ -241,7 +241,7 @@ public class FinSetCalc extends RocketComponentCalc { boolean down = false; for (int i = 1; i < points.length; i++) { if ((points[i].y > points[i - 1].y + 0.001) && down) { - geometryWarnings.add(Warning.JAGGED_EDGED_FIN, component.toString()); + geometryWarnings.add(Warning.JAGGED_EDGED_FIN, component); break; } if (points[i].y < points[i - 1].y - 0.001) { @@ -250,12 +250,12 @@ public class FinSetCalc extends RocketComponentCalc { } if (finArea < MathUtil.EPSILON) { - geometryWarnings.add(Warning.ZERO_AREA_FIN, component.toString()); + geometryWarnings.add(Warning.ZERO_AREA_FIN, component); } if ((bodyRadius > 0) && (thickness > bodyRadius / 2)){ // Add warnings (radius/2 == diameter/4) - geometryWarnings.add(Warning.THICK_FIN, component.toString()); + geometryWarnings.add(Warning.THICK_FIN, component); } // Calculate the chord lead and trail positions and length. We do need the points diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/BodyTubeExporter.java b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/BodyTubeExporter.java index f40b53d2e..c851115e9 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/BodyTubeExporter.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/BodyTubeExporter.java @@ -27,7 +27,7 @@ public class BodyTubeExporter extends RocketComponentExporter { final boolean isFilled = component.isFilled(); if (Double.compare(component.getThickness(), 0) == 0) { - warnings.add(Warning.OBJ_ZERO_THICKNESS, component.getName()); + warnings.add(Warning.OBJ_ZERO_THICKNESS, component); } // Generate the mesh diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/FinSetExporter.java b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/FinSetExporter.java index 7176857cf..4a9206b4c 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/FinSetExporter.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/FinSetExporter.java @@ -38,7 +38,7 @@ public class FinSetExporter extends RocketComponentExporter { boolean hasTabs = component.getTabLength() > 0 && component.getTabHeight() > 0; if (Float.compare(thickness, 0) == 0) { - warnings.add(Warning.OBJ_ZERO_THICKNESS, component.getName()); + warnings.add(Warning.OBJ_ZERO_THICKNESS, component); } // Generate the fin meshes diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/LaunchLugExporter.java b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/LaunchLugExporter.java index af88edcf4..ead785e6b 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/LaunchLugExporter.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/LaunchLugExporter.java @@ -27,7 +27,7 @@ public class LaunchLugExporter extends RocketComponentExporter { final float length = (float) component.getLength(); if (Double.compare(component.getThickness(), 0) == 0) { - warnings.add(Warning.OBJ_ZERO_THICKNESS, component.getName()); + warnings.add(Warning.OBJ_ZERO_THICKNESS, component); } // Generate the mesh diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/RingComponentExporter.java b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/RingComponentExporter.java index 08c3f7751..ca4c6881d 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/RingComponentExporter.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/RingComponentExporter.java @@ -27,7 +27,7 @@ public class RingComponentExporter extends RocketComponentExporter { obj.setActiveGroupNames(groupName); if (Double.compare(component.getThickness(), 0) == 0) { - warnings.add(Warning.OBJ_ZERO_THICKNESS, component.getName()); + warnings.add(Warning.OBJ_ZERO_THICKNESS, component); } // Generate the mesh diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/TubeFinSetExporter.java b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/TubeFinSetExporter.java index 68eb6a6ba..21009099b 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/TubeFinSetExporter.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/TubeFinSetExporter.java @@ -27,7 +27,7 @@ public class TubeFinSetExporter extends RocketComponentExporter { final float length = (float) component.getLength(); if (Double.compare(component.getThickness(), 0) == 0) { - warnings.add(Warning.OBJ_ZERO_THICKNESS, component.getName()); + warnings.add(Warning.OBJ_ZERO_THICKNESS, component); } // Generate the fin meshes diff --git a/core/src/net/sf/openrocket/logging/Error.java b/core/src/net/sf/openrocket/logging/Error.java index 69ba76dd6..bff1acf85 100644 --- a/core/src/net/sf/openrocket/logging/Error.java +++ b/core/src/net/sf/openrocket/logging/Error.java @@ -33,7 +33,7 @@ public abstract class Error extends Message { } @Override - public String toString() { + public String getMessageDescription() { return description; } diff --git a/core/src/net/sf/openrocket/logging/Message.java b/core/src/net/sf/openrocket/logging/Message.java index 9b813c1a8..e0b6ba3eb 100644 --- a/core/src/net/sf/openrocket/logging/Message.java +++ b/core/src/net/sf/openrocket/logging/Message.java @@ -1,9 +1,15 @@ package net.sf.openrocket.logging; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import java.util.Arrays; + /** * Baseclass for logging messages (warnings, errors...) */ -public abstract class Message { +public abstract class Message implements Cloneable { + /** The rocket component(s) that are the source of this message **/ + private RocketComponent[] sources = null; + /** * @return a Message with the specific text. */ @@ -11,6 +17,38 @@ public abstract class Message { return new Warning.Other(text); } + /** + * Returns the message text + message source objects. + * @return the message text + message source objects. + */ + @Override + public String toString() { + return addSourcesToMessageText(getMessageDescription(), getSources()); + } + + /** + * Returns the message text + message source objects. + * @param text the message text + * @param sources the message source objects + * @return the message text + message source objects. + */ + protected static String addSourcesToMessageText(String text, RocketComponent[] sources) { + if (sources != null && sources.length > 0) { + String[] sourceNames = new String[sources.length]; + for (int i = 0; i < sources.length; i++) { + sourceNames[i] = sources[i].getName(); + } + return text + ": \"" + String.join(", ", sourceNames) + "\""; + } + return text; + } + + /** + * Returns the message text (without message source information). The text should be short and descriptive. + * @return the message text. + */ + public abstract String getMessageDescription(); + /** * Return true if the other warning should replace * this message. The method should return true if the other @@ -21,6 +59,22 @@ public abstract class Message { */ public abstract boolean replaceBy(Message other); + /** + * Return the rocket component(s) that are the source of this warning. + * @return the rocket component(s) that are the source of this warning. Returns null if no sources are specified. + */ + public RocketComponent[] getSources() { + return sources; + } + + /** + * Set the rocket component(s) that are the source of this warning. + * @param sources the rocket component(s) that are the source of this warning. + */ + public void setSources(RocketComponent[] sources) { + this.sources = sources; + } + /** * Two Messages are by default considered equal if they are of @@ -30,7 +84,17 @@ public abstract class Message { */ @Override public boolean equals(Object o) { - return o != null && (o.getClass() == this.getClass()); + return o != null && (o.getClass() == this.getClass() && sourcesEqual(((Message) o).sources, sources)); + } + + /** + * Compare two arrays of rocket components for equality. + * @param a the first list of sources + * @param b the second list of sources + * @return true if the lists are equal + */ + protected boolean sourcesEqual(RocketComponent[] a, RocketComponent[] b) { + return Arrays.equals(a, b); } /** @@ -40,4 +104,11 @@ public abstract class Message { public int hashCode() { return this.getClass().hashCode(); } + + @Override + protected Object clone() throws CloneNotSupportedException { + Message clone = (Message) super.clone(); + clone.sources = this.sources; + return clone; + } } diff --git a/core/src/net/sf/openrocket/logging/MessageSet.java b/core/src/net/sf/openrocket/logging/MessageSet.java index 064c52cf5..adf490edb 100644 --- a/core/src/net/sf/openrocket/logging/MessageSet.java +++ b/core/src/net/sf/openrocket/logging/MessageSet.java @@ -1,5 +1,6 @@ package net.sf.openrocket.logging; +import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.util.ArrayList; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.Monitorable; @@ -60,6 +61,23 @@ public abstract class MessageSet extends AbstractSet imple */ public abstract boolean add(String s); + /** + * Add a Message of the specified type with the specified message sources. + * @param m the message + * @param sources the sources of the message (rocket components that caused the message) + * + */ + public boolean add(E m, RocketComponent... sources) { + mutable.check(); + try { + m = (E) m.clone(); + } catch (CloneNotSupportedException e) { + throw new BugException("CloneNotSupportedException occurred, report bug!", e); + } + m.setSources(sources); + return add(m); + } + /** * Add a Message of the specified type with the specified discriminator to the * set. @@ -67,7 +85,7 @@ public abstract class MessageSet extends AbstractSet imple * @param d the extra discriminator * */ - public boolean add (E m, String d) { + public boolean add(E m, String d) { return this.add(m.toString() + ": \"" + d + "\""); } diff --git a/core/src/net/sf/openrocket/logging/Warning.java b/core/src/net/sf/openrocket/logging/Warning.java index c3b9db1fb..3269672d7 100644 --- a/core/src/net/sf/openrocket/logging/Warning.java +++ b/core/src/net/sf/openrocket/logging/Warning.java @@ -2,6 +2,7 @@ package net.sf.openrocket.logging; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.motor.Motor; +import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; import net.sf.openrocket.simulation.FlightEvent; import net.sf.openrocket.unit.UnitGroup; @@ -32,7 +33,7 @@ public abstract class Warning extends Message { * @author Sampo Niskanen */ public static class LargeAOA extends Warning { - private final double aoa; + private double aoa; /** * Sole constructor. The argument is the AOA that caused this warning. @@ -44,7 +45,7 @@ public abstract class Warning extends Message { } @Override - public String toString() { + public String getMessageDescription() { if (Double.isNaN(aoa)) //// Large angle of attack encountered. return trans.get("Warning.LargeAOA.str1"); @@ -63,6 +64,18 @@ public abstract class Warning extends Message { return true; return (o.aoa > this.aoa); } + + @Override + public boolean equals(Object o) { + return super.equals(o) && Double.compare(((LargeAOA) o).aoa, aoa) == 0; + } + + @Override + protected Object clone() throws CloneNotSupportedException { + LargeAOA clone = (LargeAOA) super.clone(); + clone.aoa = this.aoa; + return clone; + } } /** @@ -71,7 +84,7 @@ public abstract class Warning extends Message { * @author Craig Earls */ public static class HighSpeedDeployment extends Warning { - private final double recoverySpeed; + private double recoverySpeed; /** * Sole constructor. The argument is the speed that caused this warning. @@ -83,7 +96,7 @@ public abstract class Warning extends Message { } @Override - public String toString() { + public String getMessageDescription() { if (Double.isNaN(recoverySpeed)) { return trans.get("Warning.RECOVERY_HIGH_SPEED"); } @@ -94,6 +107,18 @@ public abstract class Warning extends Message { public boolean replaceBy(Message other) { return false; } + + @Override + public boolean equals(Object o) { + return super.equals(o) && Double.compare(((HighSpeedDeployment) o).recoverySpeed, recoverySpeed) == 0; + } + + @Override + protected Object clone() throws CloneNotSupportedException { + HighSpeedDeployment clone = (HighSpeedDeployment) super.clone(); + clone.recoverySpeed = this.recoverySpeed; + return clone; + } } /** @@ -101,7 +126,7 @@ public abstract class Warning extends Message { * */ public static class EventAfterLanding extends Warning { - private final FlightEvent event; + private FlightEvent event; /** * Sole constructor. The argument is an event which has occurred after landing @@ -121,7 +146,7 @@ public abstract class Warning extends Message { @Override - public String toString() { + public String getMessageDescription() { return trans.get("Warning.EVENT_AFTER_LANDING") + event.getType(); } @@ -129,6 +154,13 @@ public abstract class Warning extends Message { public boolean replaceBy(Message other) { return false; } + + @Override + protected Object clone() throws CloneNotSupportedException { + EventAfterLanding clone = (EventAfterLanding) super.clone(); + clone.event = this.event; + return clone; + } } public static class MissingMotor extends Warning { @@ -142,7 +174,7 @@ public abstract class Warning extends Message { private double delay = Double.NaN; @Override - public String toString() { + public String getMessageDescription() { String str = "No motor with designation '" + designation + "'"; if (manufacturer != null) str += " for manufacturer '" + manufacturer + "'"; @@ -281,8 +313,24 @@ public abstract class Warning extends Message { return false; if (type != other.type) return false; + if (!sourcesEqual(other.getSources(), this.getSources())) { + return false; + } return true; } + + @Override + protected Object clone() throws CloneNotSupportedException { + MissingMotor clone = (MissingMotor) super.clone(); + clone.type = this.type; + clone.manufacturer = this.manufacturer; + clone.designation = this.designation; + clone.digest = this.digest; + clone.diameter = this.diameter; + clone.length = this.length; + clone.delay = this.delay; + return clone; + } } @@ -295,24 +343,20 @@ public abstract class Warning extends Message { * @author Sampo Niskanen */ public static class Other extends Warning { - private final String description; + private String description; public Other(String description) { this.description = description; } @Override - public String toString() { + public String getMessageDescription() { return description; } @Override public boolean equals(Object other) { - if (!(other instanceof Other)) - return false; - - Other o = (Other) other; - return (o.description.equals(this.description)); + return super.equals(other) && description.equals(((Other) other).description); } @Override @@ -324,6 +368,13 @@ public abstract class Warning extends Message { public boolean replaceBy(Message other) { return false; } + + @Override + protected Object clone() throws CloneNotSupportedException { + Other clone = (Other) super.clone(); + clone.description = this.description; + return clone; + } } diff --git a/core/src/net/sf/openrocket/logging/WarningSet.java b/core/src/net/sf/openrocket/logging/WarningSet.java index 2220904ba..d93a20d0e 100644 --- a/core/src/net/sf/openrocket/logging/WarningSet.java +++ b/core/src/net/sf/openrocket/logging/WarningSet.java @@ -1,12 +1,6 @@ package net.sf.openrocket.logging; -import java.util.AbstractSet; -import java.util.Iterator; - -import net.sf.openrocket.util.ArrayList; import net.sf.openrocket.util.BugException; -import net.sf.openrocket.util.Monitorable; -import net.sf.openrocket.util.Mutable; /** * A set that contains multiple Warnings. When adding a