X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=core%2Fsrc%2Fnet%2Fsf%2Fopenrocket%2Fpreset%2FComponentPreset.java;h=6e7bd7aaf4a4d60047609da7d6b56fca2f60318d;hb=9349577cdfdff682b2aabd6daa24fdc3a7449b58;hp=87343e9351b9734992abe645c9776e969d592763;hpb=da1c2a7f13fc0e3e84f36981a3bb996f2254f766;p=debian%2Fopenrocket diff --git a/core/src/net/sf/openrocket/preset/ComponentPreset.java b/core/src/net/sf/openrocket/preset/ComponentPreset.java index 87343e93..6e7bd7aa 100644 --- a/core/src/net/sf/openrocket/preset/ComponentPreset.java +++ b/core/src/net/sf/openrocket/preset/ComponentPreset.java @@ -1,73 +1,377 @@ package net.sf.openrocket.preset; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.sf.openrocket.material.Material; import net.sf.openrocket.motor.Manufacturer; -import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish; +import net.sf.openrocket.rocketcomponent.Transition.Shape; +import net.sf.openrocket.unit.UnitGroup; +import net.sf.openrocket.util.BugException; +import net.sf.openrocket.util.TextUtil; + /** * A model for a preset component. *

* A preset component contains a component class type, manufacturer information, * part information, and a method that returns a prototype of the preset component. - * + * * @author Sampo Niskanen */ -public abstract class ComponentPreset { +public class ComponentPreset implements Comparable { - private final Manufacturer manufacturer; - private final String partNo; - private final String partDescription; - private final RocketComponent prototype; + private final TypedPropertyMap properties = new TypedPropertyMap(); + private String digest = ""; - public ComponentPreset(Manufacturer manufacturer, String partNo, String partDescription, - RocketComponent prototype) { - this.manufacturer = manufacturer; - this.partNo = partNo; - this.partDescription = partDescription; - this.prototype = prototype.copy(); + public enum Type { + BODY_TUBE(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.INNER_DIAMETER, + ComponentPreset.OUTER_DIAMETER, + ComponentPreset.LENGTH }), + + NOSE_CONE(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.SHAPE, + ComponentPreset.AFT_OUTER_DIAMETER, + ComponentPreset.AFT_SHOULDER_DIAMETER, + ComponentPreset.AFT_SHOULDER_LENGTH, + ComponentPreset.LENGTH }), + + TRANSITION(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.SHAPE, + ComponentPreset.FORE_OUTER_DIAMETER, + ComponentPreset.FORE_SHOULDER_DIAMETER, + ComponentPreset.FORE_SHOULDER_LENGTH, + ComponentPreset.AFT_OUTER_DIAMETER, + ComponentPreset.AFT_SHOULDER_DIAMETER, + ComponentPreset.AFT_SHOULDER_LENGTH, + ComponentPreset.LENGTH }), + + TUBE_COUPLER(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.OUTER_DIAMETER, + ComponentPreset.INNER_DIAMETER, + ComponentPreset.LENGTH }), + + BULK_HEAD(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.OUTER_DIAMETER, + ComponentPreset.LENGTH }), + + CENTERING_RING(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.INNER_DIAMETER, + ComponentPreset.OUTER_DIAMETER, + ComponentPreset.LENGTH }), - if (prototype.getParent() != null) { - throw new IllegalArgumentException("Prototype component cannot have a parent"); + ENGINE_BLOCK(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.INNER_DIAMETER, + ComponentPreset.OUTER_DIAMETER, + ComponentPreset.LENGTH }), + + LAUNCH_LUG(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.INNER_DIAMETER, + ComponentPreset.OUTER_DIAMETER, + ComponentPreset.LENGTH }), + + STREAMER(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.LENGTH, + ComponentPreset.WIDTH, + ComponentPreset.THICKNESS, + ComponentPreset.MATERIAL }), + + PARACHUTE(new TypedKey[] { + ComponentPreset.MANUFACTURER, + ComponentPreset.PARTNO, + ComponentPreset.DESCRIPTION, + ComponentPreset.DIAMETER, + ComponentPreset.SIDES, + ComponentPreset.LINE_COUNT, + ComponentPreset.LINE_LENGTH, + ComponentPreset.LINE_MATERIAL, + ComponentPreset.MATERIAL }); + + TypedKey[] displayedColumns; + + Type(TypedKey[] displayedColumns) { + this.displayedColumns = displayedColumns; } - if (prototype.getChildCount() > 0) { - throw new IllegalArgumentException("Prototype component cannot have children"); + + public List getCompatibleTypes() { + return compatibleTypeMap.get(Type.this); } + + public TypedKey[] getDisplayedColumns() { + return displayedColumns; + } + + private static Map> compatibleTypeMap = new HashMap>(); + + static { + compatibleTypeMap.put(BODY_TUBE, Arrays.asList(BODY_TUBE, TUBE_COUPLER, LAUNCH_LUG)); + compatibleTypeMap.put(TUBE_COUPLER, Arrays.asList(BODY_TUBE, TUBE_COUPLER, LAUNCH_LUG)); + compatibleTypeMap.put(LAUNCH_LUG, Arrays.asList(BODY_TUBE, TUBE_COUPLER, LAUNCH_LUG)); + compatibleTypeMap.put(CENTERING_RING, Arrays.asList(CENTERING_RING, ENGINE_BLOCK)); + compatibleTypeMap.put(NOSE_CONE, Arrays.asList(NOSE_CONE, TRANSITION)); + } + } + public final static TypedKey MANUFACTURER = new TypedKey("Manufacturer", Manufacturer.class); + public final static TypedKey PARTNO = new TypedKey("PartNo", String.class); + public final static TypedKey DESCRIPTION = new TypedKey("Description", String.class); + public final static TypedKey TYPE = new TypedKey("Type", Type.class); + public final static TypedKey LENGTH = new TypedKey("Length", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey WIDTH = new TypedKey("Width", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey INNER_DIAMETER = new TypedKey("InnerDiameter", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey OUTER_DIAMETER = new TypedKey("OuterDiameter", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey FORE_SHOULDER_LENGTH = new TypedKey("ForeShoulderLength", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey FORE_SHOULDER_DIAMETER = new TypedKey("ForeShoulderDiameter", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey FORE_OUTER_DIAMETER = new TypedKey("ForeOuterDiameter", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey AFT_SHOULDER_LENGTH = new TypedKey("AftShoulderLength", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey AFT_SHOULDER_DIAMETER = new TypedKey("AftShoulderDiameter", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey AFT_OUTER_DIAMETER = new TypedKey("AftOuterDiameter", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey SHAPE = new TypedKey("Shape", Shape.class); + public final static TypedKey MATERIAL = new TypedKey("Material", Material.class); + public final static TypedKey FINISH = new TypedKey("Finish", Finish.class); + public final static TypedKey THICKNESS = new TypedKey("Thickness", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey FILLED = new TypedKey("Filled", Boolean.class); + public final static TypedKey MASS = new TypedKey("Mass", Double.class, UnitGroup.UNITS_MASS); + public final static TypedKey DIAMETER = new TypedKey("Diameter", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey SIDES = new TypedKey("Sides", Integer.class); + public final static TypedKey LINE_COUNT = new TypedKey("LineCount", Integer.class); + public final static TypedKey LINE_LENGTH = new TypedKey("LineLength", Double.class, UnitGroup.UNITS_LENGTH); + public final static TypedKey LINE_MATERIAL = new TypedKey("LineMaterial", Material.class); + public final static TypedKey IMAGE = new TypedKey("Image", byte[].class); + + public final static List> ORDERED_KEY_LIST = Collections.unmodifiableList(Arrays.> asList( + MANUFACTURER, + PARTNO, + DESCRIPTION, + OUTER_DIAMETER, + FORE_OUTER_DIAMETER, + AFT_OUTER_DIAMETER, + INNER_DIAMETER, + LENGTH, + WIDTH, + AFT_SHOULDER_DIAMETER, + AFT_SHOULDER_LENGTH, + FORE_SHOULDER_DIAMETER, + FORE_SHOULDER_LENGTH, + SHAPE, + THICKNESS, + FILLED, + DIAMETER, + SIDES, + LINE_COUNT, + LINE_LENGTH, + LINE_MATERIAL, + MASS, + FINISH, + MATERIAL + )); + + + // package scope constructor to encourage use of factory. + ComponentPreset() { + } /** - * Return the component class that this preset defines. + * Convenience method to retrieve the Type of this ComponentPreset. + * + * @return */ - public Class getComponentClass() { - return prototype.getClass(); + public Type getType() { + return properties.get(TYPE); } /** - * Return the manufacturer of this preset component. + * Convenience method to retrieve the Manufacturer of this ComponentPreset. + * @return */ public Manufacturer getManufacturer() { - return manufacturer; + return properties.get(MANUFACTURER); } /** - * Return the part number. This is the part identifier (e.g. "BT-50"). + * Convenience method to retrieve the PartNo of this ComponentPreset. + * @return */ public String getPartNo() { - return partNo; + return properties.get(PARTNO); + } + + public String getDigest() { + return digest; + } + + public boolean has(Object key) { + return properties.containsKey(key); } /** - * Return the part description. This is a longer description of the component. + * Package scope so the ComponentPresetFactory can call it. + * @param other */ - public String getPartDescription() { - return partDescription; + void putAll(TypedPropertyMap other) { + if (other == null) { + return; + } + properties.putAll(other); } /** - * Return a prototype component. This component may be modified freely. + * Package scope so the ComponentPresetFactory can call it. + * @param key + * @param value */ - public RocketComponent getPrototype() { - return prototype.copy(); + void put(TypedKey key, T value) { + properties.put(key, value); + } + + public T get(TypedKey key) { + T value = properties.get(key); + if (value == null) { + throw new BugException("Preset did not contain key " + key + " " + properties.toString()); + } + return value; + } + + @Override + public int compareTo(ComponentPreset p2) { + int manuCompare = this.getManufacturer().getSimpleName().compareTo(p2.getManufacturer().getSimpleName()); + if (manuCompare != 0) + return manuCompare; + + int partNoCompare = this.getPartNo().compareTo(p2.getPartNo()); + return partNoCompare; + } + + @Override + public String toString() { + return get(PARTNO); + } + + public String preferenceKey() { + return get(MANUFACTURER).toString() + "|" + get(PARTNO); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ComponentPreset that = (ComponentPreset) o; + + if (digest != null ? !digest.equals(that.digest) : that.digest != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return digest != null ? digest.hashCode() : 0; + } + + /** + * Package scope so the factory can call it. + */ + void computeDigest() { + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(bos); + + List> keys = new ArrayList>(properties.keySet()); + + Collections.sort(keys, new Comparator>() { + @Override + public int compare(TypedKey a, TypedKey b) { + return a.getName().compareTo(b.getName()); + } + }); + + for (TypedKey key : keys) { + + Object value = properties.get(key); + + os.writeBytes(key.getName()); + + if (key.getType() == Double.class) { + Double d = (Double) value; + os.writeDouble(d); + } else if (key.getType() == String.class) { + String s = (String) value; + os.writeBytes(s); + } else if (key.getType() == Manufacturer.class) { + String s = ((Manufacturer) value).getSimpleName(); + os.writeBytes(s); + } else if (key.getType() == Finish.class) { + String s = ((Finish) value).name(); + os.writeBytes(s); + } else if (key.getType() == Type.class) { + String s = ((Type) value).name(); + os.writeBytes(s); + } else if (key.getType() == Boolean.class) { + Boolean b = (Boolean) value; + os.writeBoolean(b); + } else if (key.getType() == Material.class) { + double d = ((Material) value).getDensity(); + os.writeDouble(d); + } else if (key.getType() == Shape.class) { + // this is ugly to use the ordinal but what else? + int i = ((Shape) value).ordinal(); + os.writeInt(i); + } + + } + + MessageDigest md5 = MessageDigest.getInstance("MD5"); + digest = TextUtil.hexString(md5.digest(bos.toByteArray())); + } catch (Exception e) { + e.printStackTrace(); + throw new BugException(e); + } } }