From 12f8802cd3e6c773296788e597dc06c6e62376cb Mon Sep 17 00:00:00 2001 From: JoePfeiffer Date: Mon, 9 Sep 2024 06:27:53 -0600 Subject: [PATCH] Load and store SIM_WARN flight events This requires substantial changes to Warnings in .ork files. Instead of Warnings consisting of a text string with id and priority as attributes, it is now a mixed content element with id, priority, description, and possibly sources as subelements and the original text string still present to provide backward compatibility. If a .ork file with a warning is saved with this PR and then loaded also with this PR, the warning is reconstructed from the subelements and is available if there is a SIM_WARN flight event. If at some point we want to highlight the components referenced in a Warning, we now have references to them. If a .ork file with a warning is saved with 23.09 and then loaded with this PR, none of the subelements are present, so the Warning is reconstructed from the text. It won't have actual references to the components mentioned in the Warning, and there won't be a SIM_WARN event needing reference the Warning. If a .ork file with a warning is saved with this PR and then loaded in 23.09, there will be .ork loading warnings for all the elements defined in this PR, and then the Warning will be constructed from the text content just as for a .ork saved in 23.09. --- .../core/file/openrocket/OpenRocketSaver.java | 40 ++++++---- .../importt/FlightDataBranchHandler.java | 22 ++++-- .../openrocket/importt/FlightDataHandler.java | 17 +++-- .../importt/SingleSimulationHandler.java | 7 ++ .../openrocket/importt/WarningHandler.java | 73 +++++++++++++++++++ .../core/file/simplesax/ElementHandler.java | 2 +- .../info/openrocket/core/logging/Message.java | 7 ++ .../openrocket/core/logging/MessageSet.java | 21 ++++-- .../info/openrocket/core/logging/Warning.java | 5 +- 9 files changed, 158 insertions(+), 36 deletions(-) create mode 100644 core/src/main/java/info/openrocket/core/file/openrocket/importt/WarningHandler.java diff --git a/core/src/main/java/info/openrocket/core/file/openrocket/OpenRocketSaver.java b/core/src/main/java/info/openrocket/core/file/openrocket/OpenRocketSaver.java index cc841799d..982df34bc 100644 --- a/core/src/main/java/info/openrocket/core/file/openrocket/OpenRocketSaver.java +++ b/core/src/main/java/info/openrocket/core/file/openrocket/OpenRocketSaver.java @@ -403,7 +403,24 @@ public class OpenRocketSaver extends RocketSaver { indent++; for (Warning w : data.getWarningSet()) { - writeElementWithAttribute("warning", "priority", w.getPriority().getExportLabel(), TextUtil.escapeXML(w.toString())); + writeln(""); + indent++; + + writeElement("id", w.getID().toString()); + writeElement("description", w.getMessageDescription()); + writeElement("priority", w.getPriority()); + + if (null != w.getSources()) { + for (RocketComponent c : w.getSources()) { + writeElement("source", c.getID()); + } + } + + // We write the whole string content for backwards compatibility with old versions + writeln(TextUtil.escapeXML(w.toString())); + + indent--; + writeln(""); } // Check whether to store data @@ -579,16 +596,21 @@ public class OpenRocketSaver extends RocketSaver { // Write events for (FlightEvent event : branch.getEvents()) { String eventStr = ""; + eventStr += "/>"; writeln(eventStr); } @@ -649,14 +671,6 @@ public class OpenRocketSaver extends RocketSaver { content = ""; writeln("<" + element + ">" + TextUtil.escapeXML(content) + ""); } - - private void writeElementWithAttribute(String element, String attributeName, String attribute, Object content) throws IOException { - content = content == null ? "" : content; - - writeln("<" + element + " " + attributeName + " = \"" + attribute + "\">" + TextUtil.escapeXML(content) + ""); - } - - private void writeln(String str) throws IOException { if (str.length() == 0) { diff --git a/core/src/main/java/info/openrocket/core/file/openrocket/importt/FlightDataBranchHandler.java b/core/src/main/java/info/openrocket/core/file/openrocket/importt/FlightDataBranchHandler.java index 7ba4088b8..2b2277ce1 100644 --- a/core/src/main/java/info/openrocket/core/file/openrocket/importt/FlightDataBranchHandler.java +++ b/core/src/main/java/info/openrocket/core/file/openrocket/importt/FlightDataBranchHandler.java @@ -3,6 +3,7 @@ package info.openrocket.core.file.openrocket.importt; import java.util.HashMap; import java.util.UUID; +import info.openrocket.core.logging.Message; import info.openrocket.core.logging.SimulationAbort; import info.openrocket.core.logging.SimulationAbort.Cause; import info.openrocket.core.logging.WarningSet; @@ -132,15 +133,14 @@ class FlightDataBranchHandler extends AbstractElementHandler { if (element.equals("event")) { double time; FlightEvent.Type type; - SimulationAbort abort = null; - SimulationAbort.Cause cause = null; + Message data = null; RocketComponent source = null; String sourceID; try { time = DocumentConfig.stringToDouble(attributes.get("time")); } catch (NumberFormatException e) { - warnings.add("Illegal event specification, ignoring."); + warnings.add("Illegal event time specification, ignoring: " + e.getMessage()); return; } @@ -157,13 +157,23 @@ class FlightDataBranchHandler extends AbstractElementHandler { source = rocket.findComponent(UUID.fromString(sourceID)); } + // For warning events, get the warning + if (type == FlightEvent.Type.SIM_WARN) { + data = simHandler.getWarningSet().findById(UUID.fromString(attributes.get("id"))); + } + // For aborts, get the cause - cause = (Cause) DocumentConfig.findEnum(attributes.get("cause"), SimulationAbort.Cause.class); + Cause cause = (Cause) DocumentConfig.findEnum(attributes.get("cause"), SimulationAbort.Cause.class); if (cause != null) { - abort = new SimulationAbort(cause); + data = new SimulationAbort(cause); } - branch.addEvent(new FlightEvent(type, time, source, abort)); + try { + branch.addEvent(new FlightEvent(type, time, source, data)); + } catch (Exception e) { + warnings.add("Illegal parameters for FlightEvent: " + e.getMessage()); + } + return; } diff --git a/core/src/main/java/info/openrocket/core/file/openrocket/importt/FlightDataHandler.java b/core/src/main/java/info/openrocket/core/file/openrocket/importt/FlightDataHandler.java index 6ce1573f1..1c6ad1b89 100644 --- a/core/src/main/java/info/openrocket/core/file/openrocket/importt/FlightDataHandler.java +++ b/core/src/main/java/info/openrocket/core/file/openrocket/importt/FlightDataHandler.java @@ -39,7 +39,7 @@ class FlightDataHandler extends AbstractElementHandler { WarningSet warnings) { if (element.equals("warning")) { - return PlainTextHandler.INSTANCE; + return new WarningHandler(context.getOpenRocketDocument().getRocket(), warningSet); } if (element.equals("databranch")) { if (attributes.get("name") == null || attributes.get("types") == null) { @@ -83,10 +83,10 @@ class FlightDataHandler extends AbstractElementHandler { if (branch.getLength() > 0) { branches.add(branch); } - } else if (element.equals("warning")) { - String priorityStr = attributes.get("priority"); - MessagePriority priority = MessagePriority.fromExportLabel(priorityStr); - warningSet.add(Warning.fromString(content, priority)); + // } else if (element.equals("warning")) { + // String priorityStr = attributes.get("priority"); + // MessagePriority priority = MessagePriority.fromExportLabel(priorityStr); + // warningSet.add(Warning.fromString(content, priority)); } } @@ -157,6 +157,9 @@ class FlightDataHandler extends AbstractElementHandler { data.getWarningSet().addAll(warningSet); data.immute(); } - - + + + public WarningSet getWarningSet() { + return warningSet; + } } diff --git a/core/src/main/java/info/openrocket/core/file/openrocket/importt/SingleSimulationHandler.java b/core/src/main/java/info/openrocket/core/file/openrocket/importt/SingleSimulationHandler.java index f283144f1..80e062b03 100644 --- a/core/src/main/java/info/openrocket/core/file/openrocket/importt/SingleSimulationHandler.java +++ b/core/src/main/java/info/openrocket/core/file/openrocket/importt/SingleSimulationHandler.java @@ -156,6 +156,13 @@ class SingleSimulationHandler extends AbstractElementHandler { doc.addSimulation(simulation); } + /** + * @return the warning set associated with this simulation + */ + public WarningSet getWarningSet() { + return dataHandler.getWarningSet(); + } + private SimulationExtension compatibilityExtension(String className) { JavaCode extension = Application.getInjector().getInstance(JavaCode.class); extension.setClassName(className); diff --git a/core/src/main/java/info/openrocket/core/file/openrocket/importt/WarningHandler.java b/core/src/main/java/info/openrocket/core/file/openrocket/importt/WarningHandler.java new file mode 100644 index 000000000..edfde5bc5 --- /dev/null +++ b/core/src/main/java/info/openrocket/core/file/openrocket/importt/WarningHandler.java @@ -0,0 +1,73 @@ +package info.openrocket.core.file.openrocket.importt; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.UUID; + +import info.openrocket.core.file.simplesax.AbstractElementHandler; +import info.openrocket.core.file.simplesax.ElementHandler; +import info.openrocket.core.file.simplesax.PlainTextHandler; +import info.openrocket.core.logging.MessagePriority; +import info.openrocket.core.logging.Warning; +import info.openrocket.core.logging.WarningSet; +import info.openrocket.core.rocketcomponent.Rocket; +import info.openrocket.core.rocketcomponent.RocketComponent; + +class WarningHandler extends AbstractElementHandler { + private Rocket rocket; + private WarningSet warningSet; + private Warning warning; + private UUID id = UUID.randomUUID(); + private MessagePriority priority = MessagePriority.NORMAL; + private ArrayList sources = new ArrayList<>(); + private String warningText; + + public WarningHandler(Rocket rocket, WarningSet warningSet) { + this.rocket = rocket; + this.warningSet = warningSet; + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, + WarningSet warnings) { + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, + String content, WarningSet warnings) { + if (element.equals("id")) { + id = UUID.fromString(content); + } else if (element.equals("description")) { + warning = Warning.fromString(content); + } else if (element.equals("priority")) { + priority = MessagePriority.fromExportLabel(content); + } else if (element.equals("source")) { + RocketComponent component = rocket.findComponent(UUID.fromString(content)); + sources.add(component); + } else { + warnings.add("Unknown element '" + element + "', ignoring."); + } + } + + @Override + public void endHandler(String element, HashMap attributes, + String content, WarningSet warnings) { + + // If we didn't already create a warning, this came from an old version + if (null == warning) { + warning = Warning.fromString(content.trim()); + } + if (null != id) { + warning.setID(id); + } + if (null != priority) { + warning.setPriority(priority); + } + if (null != sources) { + warning.setSources(sources.toArray(new RocketComponent[0])); + } + + warningSet.add(warning); + } +} diff --git a/core/src/main/java/info/openrocket/core/file/simplesax/ElementHandler.java b/core/src/main/java/info/openrocket/core/file/simplesax/ElementHandler.java index 3f4e13326..38bb894ec 100644 --- a/core/src/main/java/info/openrocket/core/file/simplesax/ElementHandler.java +++ b/core/src/main/java/info/openrocket/core/file/simplesax/ElementHandler.java @@ -80,4 +80,4 @@ public interface ElementHandler { public abstract void endHandler(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException; -} \ No newline at end of file +} diff --git a/core/src/main/java/info/openrocket/core/logging/Message.java b/core/src/main/java/info/openrocket/core/logging/Message.java index 8de8254c9..e7b9b46a1 100644 --- a/core/src/main/java/info/openrocket/core/logging/Message.java +++ b/core/src/main/java/info/openrocket/core/logging/Message.java @@ -73,6 +73,13 @@ public abstract class Message implements Cloneable { public UUID getID() { return id; } + + /** + * Set the ID + **/ + public void setID(UUID id) { + this.id = id; + } /** * Return the rocket component(s) that are the source of this warning. diff --git a/core/src/main/java/info/openrocket/core/logging/MessageSet.java b/core/src/main/java/info/openrocket/core/logging/MessageSet.java index be11b51d7..f71c8c039 100644 --- a/core/src/main/java/info/openrocket/core/logging/MessageSet.java +++ b/core/src/main/java/info/openrocket/core/logging/MessageSet.java @@ -1,5 +1,10 @@ package info.openrocket.core.logging; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + import info.openrocket.core.rocketcomponent.RocketComponent; import info.openrocket.core.util.ArrayList; import info.openrocket.core.util.BugException; @@ -7,10 +12,6 @@ import info.openrocket.core.util.ModID; import info.openrocket.core.util.Monitorable; import info.openrocket.core.util.Mutable; -import java.util.AbstractSet; -import java.util.Iterator; -import java.util.List; - /** * A set that contains multiple Messages. When adding a * {@link Message} to this set, the contents is checked for a message of the @@ -69,7 +70,7 @@ public abstract class MessageSet extends AbstractSet imple * @param sources the sources of the message (rocket components that caused the message) * */ - public boolean add(E m, RocketComponent... sources) { + public boolean add(E m, RocketComponent... sources) { mutable.check(); try { m = (E) m.clone(); @@ -78,7 +79,7 @@ public abstract class MessageSet extends AbstractSet imple } m.setSources(sources); return add(m); - } + } /** * Add a Message of the specified type with the specified discriminator to the @@ -149,6 +150,14 @@ public abstract class MessageSet extends AbstractSet imple return list; } + public Message findById(UUID id) { + for (Message m : messages) { + if (m.id.equals(id)) + return m; + } + throw new BugException("Message with id " + id + " not found"); + } + public void immute() { mutable.immute(); } diff --git a/core/src/main/java/info/openrocket/core/logging/Warning.java b/core/src/main/java/info/openrocket/core/logging/Warning.java index 30bd9364b..7361f7180 100644 --- a/core/src/main/java/info/openrocket/core/logging/Warning.java +++ b/core/src/main/java/info/openrocket/core/logging/Warning.java @@ -18,7 +18,8 @@ public abstract class Warning extends Message { * @return a Message with the specific text and priority. */ public static Warning fromString(String text, MessagePriority priority) { - return new Warning.Other(text, priority); + Warning.Other warn = new Warning.Other(text, priority); + return warn; } /** @@ -27,8 +28,6 @@ public abstract class Warning extends Message { public static Warning fromString(String text) { return fromString(text, MessagePriority.NORMAL); } - - ///////////// Specific warning classes /////////////