import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.rocketcomponent.BodyComponent;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.Bulkhead;
import net.sf.openrocket.simulation.FlightEvent;
import net.sf.openrocket.simulation.FlightEvent.Type;
import net.sf.openrocket.simulation.SimulationOptions;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.BugException;
class DocumentConfig {
/* Remember to update OpenRocketSaver as well! */
- public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4" };
+ public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4", "1.5" };
/**
* Divisor used in converting an integer version to the point-represented version.
Reflection.findMethod(RocketComponent.class, "setOverrideSubcomponents", boolean.class)));
setters.put("RocketComponent:comment", new StringSetter(
Reflection.findMethod(RocketComponent.class, "setComment", String.class)));
+ setters.put("RocketComponent:preset", new ComponentPresetSetter(
+ Reflection.findMethod(RocketComponent.class, "loadPreset", ComponentPreset.class)));
// ExternalComponent
setters.put("ExternalComponent:finish", new EnumSetter<Finish>(
private boolean rocketDefined = false;
private boolean simulationsDefined = false;
+ private boolean datatypesDefined = false;
public OpenRocketContentHandler(DocumentLoadingContext context) {
this.context = context;
this.doc = new OpenRocketDocument(rocket);
}
-
public OpenRocketDocument getDocument() {
if (!rocketDefined)
return null;
return new ComponentParameterHandler(rocket, context);
}
+ if (element.equals("datatypes")) {
+ if (datatypesDefined) {
+ warnings.add(Warning.fromString("Multiple datatype blocks. Ignoring later ones."));
+ return null;
+ }
+ datatypesDefined = true;
+ return new DatatypeHandler(this, context);
+ }
+
if (element.equals("simulations")) {
if (simulationsDefined) {
warnings.add(Warning
}
}
+class DatatypeHandler extends AbstractElementHandler {
+ private final DocumentLoadingContext context;
+ private final OpenRocketContentHandler contentHandler;
+ private CustomExpressionHandler customExpressionHandler = null;
+
+ public DatatypeHandler(OpenRocketContentHandler contentHandler, DocumentLoadingContext context) {
+ this.context = context;
+ this.contentHandler = contentHandler;
+ }
+
+ @Override
+ public ElementHandler openElement(String element,
+ HashMap<String, String> attributes, WarningSet warnings)
+ throws SAXException {
+
+ if (element.equals("type") && attributes.get("source").equals("customexpression")) {
+ customExpressionHandler = new CustomExpressionHandler(contentHandler, context);
+ return customExpressionHandler;
+ }
+ else {
+ warnings.add(Warning.fromString("Unknown datatype " + element + " defined, ignoring"));
+ }
+
+ return this;
+ }
+
+ @Override
+ public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
+ attributes.remove("source");
+ super.closeElement(element, attributes, content, warnings);
+
+ if (customExpressionHandler != null) {
+ contentHandler.getDocument().addCustomExpression(customExpressionHandler.currentExpression);
+ }
+
+ }
+
+}
-
+class CustomExpressionHandler extends AbstractElementHandler {
+ private final DocumentLoadingContext context;
+ private final OpenRocketContentHandler contentHandler;
+ public CustomExpression currentExpression;
+
+ public CustomExpressionHandler(OpenRocketContentHandler contentHandler, DocumentLoadingContext context) {
+ this.context = context;
+ this.contentHandler = contentHandler;
+ currentExpression = new CustomExpression(contentHandler.getDocument());
+
+ }
+
+ @Override
+ public ElementHandler openElement(String element,
+ HashMap<String, String> attributes, WarningSet warnings)
+ throws SAXException {
+
+ return this;
+ }
+
+ @Override
+ public void closeElement(String element, HashMap<String, String> attributes,
+ String content, WarningSet warnings) throws SAXException {
+
+ if (element.equals("type")) {
+ contentHandler.getDocument().addCustomExpression(currentExpression);
+ }
+
+ if (element.equals("name")) {
+ currentExpression.setName(content);
+ }
+
+ if (element.equals("symbol")) {
+ currentExpression.setSymbol(content);
+ }
+
+ if (element.equals("unit") && attributes.get("unittype").equals("auto")) {
+ currentExpression.setUnit(content);
+ }
+
+ if (element.equals("expression")) {
+ currentExpression.setExpression(content);
+ }
+ }
+}
/**
* A handler that creates components from the corresponding elements. The control of the
public void closeElement(String element, HashMap<String, String> attributes,
String content, WarningSet warnings) throws SAXException {
attributes.remove("status");
+
+ //Finished loading. Rebuilding custom expressions in case something has changed such as listener variable come available.
+ for (CustomExpression exp : doc.getCustomExpressions()){
+ exp.setExpression(exp.getExpressionString());
+ }
+
super.closeElement(element, attributes, content, warnings);
}
-
-
}
class SingleSimulationHandler extends AbstractElementHandler {
+
private final DocumentLoadingContext context;
private final OpenRocketDocument doc;
this.context = context;
}
-
+ public OpenRocketDocument getDocument() {
+ return doc;
+ }
@Override
public ElementHandler openElement(String element, HashMap<String, String> attributes,
conditionHandler = new SimulationConditionsHandler(doc.getRocket(), context);
return conditionHandler;
} else if (element.equals("flightdata")) {
- dataHandler = new FlightDataHandler(context);
+ dataHandler = new FlightDataHandler(this, context);
return dataHandler;
} else {
warnings.add("Unknown element '" + element + "', ignoring.");
}
}
-
-
class SimulationConditionsHandler extends AbstractElementHandler {
private final DocumentLoadingContext context;
private SimulationOptions conditions;
private WarningSet warningSet = new WarningSet();
private List<FlightDataBranch> branches = new ArrayList<FlightDataBranch>();
+ private SingleSimulationHandler simHandler;
private FlightData data;
- public FlightDataHandler(DocumentLoadingContext context) {
+ public FlightDataHandler(SingleSimulationHandler simHandler, DocumentLoadingContext context) {
this.context = context;
+ this.simHandler = simHandler;
}
public FlightData getFlightData() {
return null;
}
dataHandler = new FlightDataBranchHandler(attributes.get("name"),
- attributes.get("types"), context);
+ attributes.get("types"),
+ simHandler, context);
return dataHandler;
}
private final FlightDataType[] types;
private final FlightDataBranch branch;
- public FlightDataBranchHandler(String name, String typeList, DocumentLoadingContext context) {
+ private static final LogHelper log = Application.getLogger();
+ private final SingleSimulationHandler simHandler;
+
+ public FlightDataBranchHandler(String name, String typeList, SingleSimulationHandler simHandler, DocumentLoadingContext context) {
+ this.simHandler = simHandler;
this.context = context;
String[] split = typeList.split(",");
types = new FlightDataType[split.length];
for (int i = 0; i < split.length; i++) {
- types[i] = FlightDataType.getType(split[i], UnitGroup.UNITS_NONE);
+ String typeName = split[i];
+ FlightDataType matching = findFlightDataType(typeName);
+ types[i] = matching;
+ //types[i] = FlightDataType.getType(typeName, matching.getSymbol(), matching.getUnitGroup());
}
// TODO: LOW: May throw an IllegalArgumentException
branch = new FlightDataBranch(name, types);
}
+ // Find the full flight data type given name only
+ // Note: this way of doing it requires that custom expressions always come before flight data in the file,
+ // not the nicest but this is always the case anyway.
+ private FlightDataType findFlightDataType(String name) {
+
+ // Kevins version with lookup by key. Not using right now
+ /*
+ if ( key != null ) {
+ for (FlightDataType t : FlightDataType.ALL_TYPES){
+ if (t.getKey().equals(key) ){
+ return t;
+ }
+ }
+ }
+ */
+
+ // Look in built in types
+ for (FlightDataType t : FlightDataType.ALL_TYPES) {
+ if (t.getName().equals(name)) {
+ return t;
+ }
+ }
+
+ // Look in custom expressions
+ for (CustomExpression exp : simHandler.getDocument().getCustomExpressions()) {
+ if (exp.getName().equals(name)) {
+ return exp.getType();
+ }
+ }
+
+ log.warn("Could not find the flight data type '" + name + "' used in the XML file. Substituted type with unknown symbol and units.");
+ return FlightDataType.getType(name, "Unknown", UnitGroup.UNITS_NONE);
+ }
+
public FlightDataBranch getBranch() {
branch.immute();
return branch;
}
}
+////ComponentPresetSetter - sets a ComponentPreset value
+class ComponentPresetSetter implements Setter {
+ private final Reflection.Method setMethod;
+
+ public ComponentPresetSetter(Reflection.Method set) {
+ this.setMethod = set;
+ }
+
+ @Override
+ public void set(RocketComponent c, String name, HashMap<String, String> attributes,
+ WarningSet warnings) {
+ String manufacturerName = attributes.get("manufacturer");
+ if (manufacturerName == null) {
+ warnings.add(Warning.fromString("Invalid ComponentPreset for component " + c.getName() + ", no manufacturer specified. Ignored"));
+ return;
+ }
+
+ String productNo = attributes.get("partno");
+ if (productNo == null) {
+ warnings.add(Warning.fromString("Invalid ComponentPreset for component " + c.getName() + ", no partno specified. Ignored"));
+ return;
+ }
+
+ String digest = attributes.get("digest");
+ if (digest == null) {
+ warnings.add(Warning.fromString("Invalid ComponentPreset for component " + c.getName() + ", no digest specified."));
+ }
+
+ String type = attributes.get("type");
+ if (type == null) {
+ warnings.add(Warning.fromString("Invalid ComponentPreset for component " + c.getName() + ", no type specified."));
+ }
+
+ List<ComponentPreset> presets = Application.getComponentPresetDao().find(manufacturerName, productNo);
+
+ ComponentPreset matchingPreset = null;
+
+ for (ComponentPreset preset : presets) {
+ if (digest != null && preset.getDigest().equals(digest)) {
+ // Found one with matching digest. Take it.
+ matchingPreset = preset;
+ break;
+ }
+ if (type != null && preset.getType().name().equals(type) && matchingPreset != null) {
+ // Found the first one with matching type.
+ matchingPreset = preset;
+ }
+ }
+
+ // Was any found?
+ if (matchingPreset == null) {
+ warnings.add(Warning.fromString("No matching ComponentPreset for component " + c.getName() + " found matching " + manufacturerName + " " + productNo));
+ return;
+ }
+
+ if (digest != null && !matchingPreset.getDigest().equals(digest)) {
+ warnings.add(Warning.fromString("ComponentPreset for component " + c.getName() + " has wrong digest"));
+ }
+
+ setMethod.invoke(c, matchingPreset);
+ }
+}
+////MaterialSetter - sets a Material value
class MaterialSetter implements Setter {
private final Reflection.Method setMethod;
private final Material.Type type;
return;
}
- mat = Databases.findMaterial(type, name, density, false);
+ mat = Databases.findMaterial(type, name, density);
setMethod.invoke(c, mat);
}
+
class PositionSetter implements Setter {
@Override