Added persistence of ComponentPresets in the ORK file. Bumped ORK file version number to 1.5 when saving designs containing ComponentPresets. Added a digest string to ComponentPreset which is used during reading and writing ORK files to verify the correct ComponentPreset is used.
This commit is contained in:
		
							parent
							
								
									68eaf21ef0
								
							
						
					
					
						commit
						edcd0008b1
					
				| @ -38,3 +38,5 @@ The following file format versions exist: | ||||
|       deploymentvelocity attributes to <flightdata> element.  The motor | ||||
|       digesting algorithm was changed.  Adds <separationevent> and | ||||
|       <separationdelay> elements to stage components (except sustainer). | ||||
| 
 | ||||
| 1.5:  Introduced with OpenRocket 12.xx.  Added ComponentPresets. | ||||
| @ -26,4 +26,6 @@ public interface ComponentPresetDao { | ||||
| 
 | ||||
| 	public void setFavorite( ComponentPreset preset, boolean favorite ); | ||||
| 	 | ||||
| 	public List<ComponentPreset> find( String manufacturer, String partNo ); | ||||
| 	 | ||||
| } | ||||
| @ -129,6 +129,17 @@ public class ComponentPresetDatabase extends Database<ComponentPreset> implement | ||||
| 		return result; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public List<ComponentPreset> find(String manufacturer, String partNo) { | ||||
| 		List<ComponentPreset> presets = new ArrayList<ComponentPreset>(); | ||||
| 		for( ComponentPreset preset : list ) { | ||||
| 			if ( preset.getManufacturer().getSimpleName().equals(manufacturer) && preset.getPartNo().equals(partNo) ) { | ||||
| 				presets.add(preset); | ||||
| 			} | ||||
| 		} | ||||
| 		return presets; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void setFavorite( ComponentPreset preset, boolean favorite ) { | ||||
| 		preset.setFavorite(favorite); | ||||
|  | ||||
| @ -184,6 +184,9 @@ public class OpenRocketSaver extends RocketSaver { | ||||
| 	 */ | ||||
| 	private int calculateNecessaryFileVersion(OpenRocketDocument document, StorageOptions opts) { | ||||
| 		/* | ||||
| 		 * File version 1.5 is requires for: | ||||
| 		 *  - saving designs using ComponentPrests | ||||
| 		 *   | ||||
| 		 * File version 1.4 is required for: | ||||
| 		 *  - saving simulation data | ||||
| 		 *  - saving motor data | ||||
| @ -195,6 +198,22 @@ public class OpenRocketSaver extends RocketSaver { | ||||
| 		 * Otherwise use version 1.0. | ||||
| 		 */ | ||||
| 		 | ||||
| 		// Search the rocket for any ComponentPrests | ||||
| 		{ | ||||
| 			Rocket r = document.getRocket(); | ||||
| 			Iterator<RocketComponent> componentIterator = r.iterator(); | ||||
| 			boolean usesComponentPreset = false; | ||||
| 			while ( !usesComponentPreset && componentIterator.hasNext() ) { | ||||
| 				RocketComponent c = componentIterator.next(); | ||||
| 				if ( c.getPresetComponent() != null ) { | ||||
| 					usesComponentPreset = true; | ||||
| 				} | ||||
| 			} | ||||
| 			if ( usesComponentPreset ) { | ||||
| 				return FILE_VERSION_DIVISOR + 5; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		// Check if design has simulations defined (version 1.4) | ||||
| 		if (document.getSimulationCount() > 0) { | ||||
| 			return FILE_VERSION_DIVISOR + 4; | ||||
|  | ||||
| @ -28,6 +28,7 @@ import net.sf.openrocket.file.simplesax.SimpleSAX; | ||||
| 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; | ||||
| @ -164,7 +165,7 @@ public class OpenRocketLoader extends AbstractRocketLoader { | ||||
| 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. | ||||
| @ -236,6 +237,8 @@ class DocumentConfig { | ||||
| 				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>( | ||||
| @ -1934,8 +1937,72 @@ class ColorSetter implements Setter { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ////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) { | ||||
| // FIXME - probably need more data in the warning messages - like what component preset... | ||||
| 		String manufacturerName = attributes.get("manufacturer"); | ||||
| 		if ( manufacturerName == null ) { | ||||
| 			warnings.add(Warning.fromString("Invalid ComponentPreset, no manufacturer specified.  Ignored")); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		String productNo = attributes.get("partno"); | ||||
| 		if ( productNo == null ) { | ||||
| 			warnings.add(Warning.fromString("Invalid ComponentPreset, no partno specified.  Ignored")); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		String digest = attributes.get("digest"); | ||||
| 		if ( digest == null ) { | ||||
| 			warnings.add(Warning.fromString("Invalid ComponentPreset, no digest specified.")); | ||||
| 		} | ||||
| 
 | ||||
| 		String type = attributes.get("type"); | ||||
| 		if ( type == null ) { | ||||
| 			warnings.add(Warning.fromString("Invalid ComponentPreset, 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 found")); | ||||
| 			return; | ||||
| 		} | ||||
| 		 | ||||
| 		if ( digest != null && !matchingPreset.getDigest().equals(digest) ) { | ||||
| 			warnings.add(Warning.fromString("ComponentPreset 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; | ||||
|  | ||||
| @ -9,6 +9,7 @@ import net.sf.openrocket.file.RocketSaver; | ||||
| import net.sf.openrocket.material.Material; | ||||
| import net.sf.openrocket.motor.Motor; | ||||
| import net.sf.openrocket.motor.ThrustCurveMotor; | ||||
| import net.sf.openrocket.preset.ComponentPreset; | ||||
| import net.sf.openrocket.rocketcomponent.ComponentAssembly; | ||||
| import net.sf.openrocket.rocketcomponent.MotorMount; | ||||
| import net.sf.openrocket.rocketcomponent.Rocket; | ||||
| @ -27,6 +28,13 @@ public class RocketComponentSaver { | ||||
| 	protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) { | ||||
| 		elements.add("<name>" + RocketSaver.escapeXML(c.getName()) + "</name>"); | ||||
| 
 | ||||
| 		ComponentPreset preset = c.getPresetComponent(); | ||||
| 		if ( preset != null ) { | ||||
| 			elements.add("<preset type=\"" + preset.getType() + | ||||
| 					"\" manufacturer=\"" + preset.getManufacturer().getSimpleName() + | ||||
| 					"\" partno=\"" + preset.getPartNo() + "\" digest=\"" + preset.getDigest() +"\"/>"); | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		// Save color and line style if significant | ||||
| 		if (!(c instanceof Rocket || c instanceof ComponentAssembly)) { | ||||
|  | ||||
| @ -1,6 +1,13 @@ | ||||
| package net.sf.openrocket.preset; | ||||
| 
 | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.DataOutputStream; | ||||
| import java.security.MessageDigest; | ||||
| import java.util.ArrayList; | ||||
| 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; | ||||
| @ -9,6 +16,7 @@ import net.sf.openrocket.rocketcomponent.BodyTube; | ||||
| import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish; | ||||
| import net.sf.openrocket.unit.UnitGroup; | ||||
| import net.sf.openrocket.util.BugException; | ||||
| import net.sf.openrocket.util.TextUtil; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
| @ -25,6 +33,7 @@ public class ComponentPreset implements Comparable<ComponentPreset> { | ||||
| 	private final TypedPropertyMap properties = new TypedPropertyMap(); | ||||
| 
 | ||||
| 	private boolean favorite = false; | ||||
| 	private String digest = ""; | ||||
| 
 | ||||
| 	public enum Type { | ||||
| 		BODY_TUBE, | ||||
| @ -158,23 +167,45 @@ public class ComponentPreset implements Comparable<ComponentPreset> { | ||||
| 		} | ||||
| 		} | ||||
| 
 | ||||
| 		preset.computeDigest(); | ||||
| 
 | ||||
| 		return preset; | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	// Private constructor to encourage use of factory. | ||||
| 	private ComponentPreset() { | ||||
| 		 | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Convenience method to retrieve the Type of this ComponentPreset. | ||||
| 	 *  | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	public Type getType() { | ||||
| 		return properties.get(TYPE); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Convenience method to retrieve the Manufacturer of this ComponentPreset. | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	public Manufacturer getManufacturer() { | ||||
| 		return properties.get(MANUFACTURER); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Convenience method to retrieve the PartNo of this ComponentPreset. | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	public String getPartNo() { | ||||
| 		return properties.get(PARTNO); | ||||
| 	} | ||||
| 
 | ||||
| 	public String getDigest() { | ||||
| 		return digest; | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean has(Object key) { | ||||
| 		return properties.containsKey(key); | ||||
| 	} | ||||
| @ -214,4 +245,58 @@ public class ComponentPreset implements Comparable<ComponentPreset> { | ||||
| 		return get(MANUFACTURER).toString() + "|" + get(PARTNO); | ||||
| 	} | ||||
| 
 | ||||
| 	private void computeDigest() { | ||||
| 
 | ||||
| 		try { | ||||
| 			ByteArrayOutputStream bos = new ByteArrayOutputStream(); | ||||
| 			DataOutputStream os = new DataOutputStream(bos); | ||||
| 
 | ||||
| 			List<TypedKey<?>> keys = new ArrayList<TypedKey<?>>( properties.keySet()); | ||||
| 
 | ||||
| 			Collections.sort(keys, new Comparator<TypedKey<?>>() { | ||||
| 				@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); | ||||
| 				} | ||||
| 
 | ||||
| 			} | ||||
| 
 | ||||
| 			MessageDigest md5 = MessageDigest.getInstance("MD5"); | ||||
| 			digest = TextUtil.hexString(md5.digest( bos.toByteArray() )); | ||||
| 		} | ||||
| 		catch ( Exception e ) { | ||||
| 			throw new BugException(e); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user