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.
This commit is contained in:
parent
fad20af879
commit
12f8802cd3
@ -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("<warning>");
|
||||
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("</warning>");
|
||||
}
|
||||
|
||||
// Check whether to store data
|
||||
@ -579,16 +596,21 @@ public class OpenRocketSaver extends RocketSaver {
|
||||
// Write events
|
||||
for (FlightEvent event : branch.getEvents()) {
|
||||
String eventStr = "<event time=\"" + TextUtil.doubleToString(event.getTime())
|
||||
+ "\" type=\"" + enumToXMLName(event.getType());
|
||||
+ "\" type=\"" + enumToXMLName(event.getType()) + "\"";
|
||||
|
||||
if (event.getSource() != null) {
|
||||
eventStr += "\" source=\"" + TextUtil.escapeXML(event.getSource().getID());
|
||||
eventStr += " source=\"" + TextUtil.escapeXML(event.getSource().getID()) + "\"";
|
||||
}
|
||||
|
||||
if (event.getType() == FlightEvent.Type.SIM_WARN) {
|
||||
eventStr += " id=\"" + TextUtil.escapeXML(((Warning) event.getData()).getID()) + "\"";
|
||||
}
|
||||
|
||||
if (event.getType() == FlightEvent.Type.SIM_ABORT) {
|
||||
eventStr += "\" cause=\"" + enumToXMLName(((SimulationAbort)(event.getData())).getCause());
|
||||
eventStr += " cause=\"" + enumToXMLName(((SimulationAbort)(event.getData())).getCause()) + "\"";
|
||||
}
|
||||
|
||||
eventStr += "\"/>";
|
||||
eventStr += "/>";
|
||||
writeln(eventStr);
|
||||
}
|
||||
|
||||
@ -649,14 +671,6 @@ public class OpenRocketSaver extends RocketSaver {
|
||||
content = "";
|
||||
writeln("<" + element + ">" + TextUtil.escapeXML(content) + "</" + element + ">");
|
||||
}
|
||||
|
||||
private void writeElementWithAttribute(String element, String attributeName, String attribute, Object content) throws IOException {
|
||||
content = content == null ? "" : content;
|
||||
|
||||
writeln("<" + element + " " + attributeName + " = \"" + attribute + "\">" + TextUtil.escapeXML(content) + "</" + element + ">");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void writeln(String str) throws IOException {
|
||||
if (str.length() == 0) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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<RocketComponent> 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<String, String> attributes,
|
||||
WarningSet warnings) {
|
||||
return PlainTextHandler.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeElement(String element, HashMap<String, String> 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<String, String> 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);
|
||||
}
|
||||
}
|
@ -80,4 +80,4 @@ public interface ElementHandler {
|
||||
public abstract void endHandler(String element, HashMap<String, String> attributes,
|
||||
String content, WarningSet warnings) throws SAXException;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 <code>Message</code>s. 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<E extends Message> extends AbstractSet<E> 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<E extends Message> extends AbstractSet<E> imple
|
||||
}
|
||||
m.setSources(sources);
|
||||
return add(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a <code>Message</code> of the specified type with the specified discriminator to the
|
||||
@ -149,6 +150,14 @@ public abstract class MessageSet<E extends Message> extends AbstractSet<E> 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();
|
||||
}
|
||||
|
@ -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 /////////////
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user