Implement persistence of ComponentPreset favorites to preferences. Implement favorit...
[debian/openrocket] / core / src / net / sf / openrocket / preset / ComponentPreset.java
1 package net.sf.openrocket.preset;
2
3 import java.util.HashMap;
4 import java.util.Map;
5
6 import net.sf.openrocket.material.Material;
7 import net.sf.openrocket.motor.Manufacturer;
8 import net.sf.openrocket.rocketcomponent.BodyTube;
9 import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
10 import net.sf.openrocket.unit.UnitGroup;
11 import net.sf.openrocket.util.BugException;
12
13
14 /**
15  * A model for a preset component.
16  * <p>
17  * A preset component contains a component class type, manufacturer information,
18  * part information, and a method that returns a prototype of the preset component.
19  * 
20  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
21  */
22 // FIXME - Implement clone.
23 public class ComponentPreset {
24         
25         private final TypedPropertyMap properties = new TypedPropertyMap();
26         
27         private boolean favorite = false;
28         
29         public enum Type {
30                 BODY_TUBE,
31                 NOSE_CONE;
32
33                 Type[] compatibleTypes;
34                 
35                 Type () {
36                         compatibleTypes = new Type[1];
37                         compatibleTypes[0] = this;
38                 }
39                 
40                 Type( Type ... t ) {
41                         
42                         compatibleTypes = new Type[t.length+1];
43                         compatibleTypes[0] = this;
44                         for( int i=0; i<t.length; i++ ) {
45                                 compatibleTypes[i+1] = t[i];
46                         }
47                 }
48                 
49                 public Type[] getCompatibleTypes() {
50                         return compatibleTypes;
51                 }
52                 
53         }
54         
55         public final static TypedKey<Manufacturer> MANUFACTURER = new TypedKey<Manufacturer>("Manufacturer", Manufacturer.class);
56         public final static TypedKey<String> PARTNO = new TypedKey<String>("PartNo",String.class);
57         public final static TypedKey<Type> TYPE = new TypedKey<Type>("Type",Type.class);
58         public final static TypedKey<Double> LENGTH = new TypedKey<Double>("Length", Double.class, UnitGroup.UNITS_LENGTH);
59         public final static TypedKey<Double> INNER_DIAMETER = new TypedKey<Double>("InnerDiameter", Double.class, UnitGroup.UNITS_LENGTH);
60         public final static TypedKey<Double> OUTER_DIAMETER = new TypedKey<Double>("OuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
61         public final static TypedKey<Material> MATERIAL = new TypedKey<Material>("Material", Material.class);
62         public final static TypedKey<Finish> FINISH = new TypedKey<Finish>("Finish", Finish.class);
63         public final static TypedKey<Double> THICKNESS = new TypedKey<Double>("Thickness", Double.class, UnitGroup.UNITS_LENGTH);
64         public final static TypedKey<Boolean> FILLED = new TypedKey<Boolean>("Filled", Boolean.class);
65         public final static TypedKey<Double> MASS = new TypedKey<Double>("Mass", Double.class, UnitGroup.UNITS_MASS);
66         
67         public final static Map<String, TypedKey<?>> keyMap = new HashMap<String, TypedKey<?>>();
68         static {
69                 keyMap.put(MANUFACTURER.getName(), MANUFACTURER);
70                 keyMap.put(PARTNO.getName(), PARTNO);
71                 keyMap.put(TYPE.getName(), TYPE);
72                 keyMap.put(LENGTH.getName(), LENGTH);
73                 keyMap.put(INNER_DIAMETER.getName(), INNER_DIAMETER);
74                 keyMap.put(OUTER_DIAMETER.getName(), OUTER_DIAMETER);
75                 keyMap.put(MATERIAL.getName(), MATERIAL);
76                 keyMap.put(FINISH.getName(), FINISH);
77                 keyMap.put(THICKNESS.getName(), THICKNESS);
78                 keyMap.put(FILLED.getName(), FILLED);
79                 keyMap.put(MASS.getName(), MASS);
80         }
81         
82         public static ComponentPreset create( TypedPropertyMap props ) throws InvalidComponentPresetException {
83                 
84                 ComponentPreset preset = new ComponentPreset();
85                 // First do validation.
86                 if ( !props.containsKey(TYPE)) {
87                         throw new InvalidComponentPresetException("No Type specified " + props.toString() );
88                 }
89                 
90                 if (!props.containsKey(MANUFACTURER)) {
91                         throw new InvalidComponentPresetException("No Manufacturer specified " + props.toString() );
92                 }
93
94                 if (!props.containsKey(PARTNO)) {
95                         throw new InvalidComponentPresetException("No PartNo specified " + props.toString() );
96                 }
97
98                 preset.properties.putAll(props);
99                 
100                 // Should check for various bits of each of the types.
101                 Type t = props.get(TYPE);
102                 switch ( t ) {
103                 case BODY_TUBE: {
104                         
105                         if ( !props.containsKey(LENGTH) ) {
106                                 throw new InvalidComponentPresetException( "No Length specified for body tube preset " + props.toString());
107                         }
108                         
109                         BodyTube bt = new BodyTube();
110                         
111                         bt.setLength(props.get(LENGTH));
112                         
113                         // Need to verify contains 2 of OD, thickness, ID.  Compute the third.
114                         boolean hasOd = props.containsKey(OUTER_DIAMETER);
115                         boolean hasId = props.containsKey(INNER_DIAMETER);
116                         boolean hasThickness = props.containsKey(THICKNESS);
117                         
118                         if ( hasOd ) {
119                                 double outerRadius = props.get(OUTER_DIAMETER)/2.0;
120                                 double thickness = 0;
121                                 bt.setOuterRadius( outerRadius );
122                                 if ( hasId ) {
123                                         thickness = outerRadius - props.get(INNER_DIAMETER)/2.0;
124                                 } else if ( hasThickness ) {
125                                         thickness = props.get(THICKNESS);
126                                 } else {
127                                         throw new InvalidComponentPresetException("Body tube preset underspecified " + props.toString());
128                                 }
129                                 bt.setThickness( thickness );
130                         } else {
131                                 if ( ! hasId && ! hasThickness ) {
132                                         throw new InvalidComponentPresetException("Body tube preset underspecified " + props.toString());
133                                 }
134                                 double innerRadius = props.get(INNER_DIAMETER)/2.0;
135                                 double thickness = props.get(THICKNESS);
136                                 bt.setOuterRadius(innerRadius + thickness);
137                                 bt.setThickness(thickness);
138                         }
139
140                         preset.properties.put(OUTER_DIAMETER, bt.getOuterRadius() *2.0);
141                         preset.properties.put(INNER_DIAMETER, bt.getInnerRadius() *2.0);
142                         preset.properties.put(THICKNESS, bt.getThickness());
143                         
144                         // Need to translate Mass to Density.
145                         if ( props.containsKey(MASS) ) {
146                                 String materialName = "TubeCustom";
147                                 if ( props.containsKey(MATERIAL) ) {
148                                         materialName = props.get(MATERIAL).getName();
149                                 }
150                                 Material m = Material.newMaterial(Material.Type.BULK, materialName, props.get(MASS)/bt.getComponentVolume(), false);
151                                 preset.properties.put(MATERIAL, m);
152                         }
153                         
154                         break;
155                 }
156                 case NOSE_CONE: {
157                         break;
158                 }
159                 }
160                 
161                 return preset;
162
163         }
164
165         // Private constructor to encourage use of factory.
166         private ComponentPreset() {
167                 
168         }
169         
170         public boolean has(Object key) {
171                 return properties.containsKey(key);
172         }
173         
174         public <T> T get(TypedKey<T> key) {
175                 T value = properties.get(key);
176                 if (value == null) {
177                         throw new BugException("Preset did not contain key " + key + " " + properties.toString());
178                 }
179                 return (T) value;
180         }
181         
182         public boolean isFavorite() {
183                 return favorite;
184         }
185
186         public void setFavorite(boolean favorite) {
187                 this.favorite = favorite;
188         }
189
190         @Override
191         public String toString() {
192                 return get(MANUFACTURER).toString() + " " + get(PARTNO);
193         }
194         
195         public String preferenceKey() {
196                 return get(MANUFACTURER).toString() + "|" + get(PARTNO);
197         }
198 }