0a5e62b94e0441a75d7124e6976d7ab281a1f87c
[debian/openrocket] / core / src / net / sf / openrocket / startup / Preferences.java
1 package net.sf.openrocket.startup;\r
2 \r
3 import java.util.HashMap;\r
4 import java.util.Map;\r
5 import java.util.Set;\r
6 \r
7 import net.sf.openrocket.database.Databases;\r
8 import net.sf.openrocket.l10n.Translator;\r
9 import net.sf.openrocket.material.Material;\r
10 import net.sf.openrocket.rocketcomponent.BodyComponent;\r
11 import net.sf.openrocket.rocketcomponent.FinSet;\r
12 import net.sf.openrocket.rocketcomponent.InternalComponent;\r
13 import net.sf.openrocket.rocketcomponent.LaunchLug;\r
14 import net.sf.openrocket.rocketcomponent.MassObject;\r
15 import net.sf.openrocket.rocketcomponent.RecoveryDevice;\r
16 import net.sf.openrocket.rocketcomponent.RocketComponent;\r
17 import net.sf.openrocket.util.BugException;\r
18 import net.sf.openrocket.util.BuildProperties;\r
19 import net.sf.openrocket.util.Color;\r
20 import net.sf.openrocket.util.LineStyle;\r
21 import net.sf.openrocket.util.MathUtil;\r
22 import net.sf.openrocket.util.UniqueID;\r
23 \r
24 public abstract class Preferences {\r
25 \r
26         /*\r
27          * Well known string keys to preferences.\r
28          * There are other strings out there in the source as well.\r
29          */\r
30         public static final String BODY_COMPONENT_INSERT_POSITION_KEY = "BodyComponentInsertPosition";\r
31         public static final String USER_THRUST_CURVES_KEY = "UserThrustCurves";\r
32         public static final String CONFIRM_DELETE_SIMULATION = "ConfirmDeleteSimulation";\r
33         // Preferences related to data export\r
34         public static final String EXPORT_FIELD_SEPARATOR = "ExportFieldSeparator";\r
35         public static final String EXPORT_SIMULATION_COMMENT = "ExportSimulationComment";\r
36         public static final String EXPORT_FIELD_NAME_COMMENT = "ExportFieldDescriptionComment";\r
37         public static final String EXPORT_EVENT_COMMENTS = "ExportEventComments";\r
38         public static final String EXPORT_COMMENT_CHARACTER = "ExportCommentCharacter";\r
39         public static final String USER_LOCAL = "locale";\r
40         \r
41         public static final String PLOT_SHOW_POINTS = "ShowPlotPoints";\r
42         \r
43         private static final String CHECK_UPDATES = "CheckUpdates";\r
44         public static final String LAST_UPDATE = "LastUpdateVersion";\r
45         \r
46         public static final String MOTOR_DIAMETER_FILTER = "MotorDiameterMatch";\r
47         public static final String MOTOR_HIDE_SIMILAR = "MotorHideSimilar";\r
48 \r
49         // Node names\r
50         public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors";\r
51 \r
52         /*\r
53          * ******************************************************************************************\r
54          * \r
55          * Abstract methods which must be implemented by any derived class.\r
56          */\r
57         public abstract boolean getBoolean( String key, boolean defaultValue );\r
58         public abstract void putBoolean( String key, boolean value );\r
59 \r
60         public abstract int getInt( String key, int defaultValue);\r
61         public abstract void putInt( String key, int value );\r
62 \r
63         public abstract double getDouble( String key, double defaultValue );\r
64         public abstract void putDouble( String key, double value );\r
65 \r
66         public abstract String getString( String key, String defaultValue );\r
67         public abstract void putString( String key, String value );\r
68         \r
69         /**\r
70          * Directory represents a way to collect multiple keys together.  Implementors may\r
71          * choose to concatenate the directory with the key using some special character.\r
72          * @param directory\r
73          * @param key\r
74          * @param defaultValue\r
75          * @return\r
76          */\r
77         public abstract String getString( String directory, String key, String defaultValue);\r
78 \r
79         public abstract void putString( String directory, String key, String value );\r
80 \r
81         /*\r
82          * ******************************************************************************************\r
83          */\r
84         public final boolean getCheckUpdates() {\r
85                 return this.getBoolean(CHECK_UPDATES, BuildProperties.getDefaultCheckUpdates());\r
86         }\r
87         \r
88         public final void setCheckUpdates(boolean check) {\r
89                 this.putBoolean(CHECK_UPDATES, check);\r
90         }\r
91         \r
92         public final double getDefaultMach() {\r
93                 // TODO: HIGH: implement custom default mach number\r
94                 return 0.3;\r
95         }\r
96         \r
97         /**\r
98          * Return the OpenRocket unique ID.\r
99          * \r
100          * @return      a random ID string that stays constant between OpenRocket executions\r
101          */\r
102         public final String getUniqueID() {\r
103                 String id = this.getString("id", null);\r
104                 if (id == null) {\r
105                         id = UniqueID.uuid();\r
106                         this.putString("id", id);\r
107                 }\r
108                 return id;\r
109         }\r
110         \r
111         /**\r
112          * Returns a limited-range integer value from the preferences.  If the value \r
113          * in the preferences is negative or greater than max, then the default value \r
114          * is returned.\r
115          * \r
116          * @param key  The preference to retrieve.\r
117          * @param max  Maximum allowed value for the choice.\r
118          * @param def  Default value.\r
119          * @return   The preference value.\r
120          */\r
121         public final int getChoice(String key, int max, int def) {\r
122                 int v = this.getInt(key, def);\r
123                 if ((v < 0) || (v > max))\r
124                         return def;\r
125                 return v;\r
126         }\r
127         \r
128         /**\r
129          * Helper method that puts an integer choice value into the preferences.\r
130          * \r
131          * @param key     the preference key.\r
132          * @param value   the value to store.\r
133          */\r
134         public final void putChoice(String key, int value) {\r
135                 this.putInt(key, value);\r
136         }\r
137         \r
138         /**\r
139          * Retrieve an enum value from the user preferences.\r
140          * \r
141          * @param <T>   the enum type\r
142          * @param key   the key\r
143          * @param def   the default value, cannot be null\r
144          * @return              the value in the preferences, or the default value\r
145          */\r
146         public final <T extends Enum<T>> T getEnum(String key, T def) {\r
147                 if (def == null) {\r
148                         throw new BugException("Default value cannot be null");\r
149                 }\r
150                 \r
151                 String value = getString(key, null);\r
152                 if (value == null) {\r
153                         return def;\r
154                 }\r
155                 \r
156                 try {\r
157                         return Enum.valueOf(def.getDeclaringClass(), value);\r
158                 } catch (IllegalArgumentException e) {\r
159                         return def;\r
160                 }\r
161         }\r
162         \r
163         /**\r
164          * Store an enum value to the user preferences.\r
165          * \r
166          * @param key           the key\r
167          * @param value         the value to store, or null to remove the value\r
168          */\r
169         public final void putEnum(String key, Enum<?> value) {\r
170                 if (value == null) {\r
171                         putString(key, null);\r
172                 } else {\r
173                         putString(key, value.name());\r
174                 }\r
175         }\r
176 \r
177         public Color getDefaultColor(Class<? extends RocketComponent> c) {\r
178                 String color = get("componentColors", c, DEFAULT_COLORS);\r
179                 if (color == null)\r
180                         return Color.BLACK;\r
181                 \r
182                 Color clr = parseColor(color);\r
183                 if (clr != null) {\r
184                         return clr;\r
185                 } else {\r
186                         return Color.BLACK;\r
187                 }\r
188         }\r
189         \r
190         public final void setDefaultColor(Class<? extends RocketComponent> c, Color color) {\r
191                 if (color == null)\r
192                         return;\r
193                 putString("componentColors", c.getSimpleName(), stringifyColor(color));\r
194         }\r
195 \r
196 \r
197         /**\r
198          * Retrieve a Line style for the given component.\r
199          * @param c\r
200          * @return\r
201          */\r
202         public final LineStyle getDefaultLineStyle(Class<? extends RocketComponent> c) {\r
203                 String value = get("componentStyle", c, DEFAULT_LINE_STYLES);\r
204                 try {\r
205                         return LineStyle.valueOf(value);\r
206                 } catch (Exception e) {\r
207                         return LineStyle.SOLID;\r
208                 }\r
209         }\r
210         \r
211         /**\r
212          * Set a default line style for the given component.\r
213          * @param c\r
214          * @param style\r
215          */\r
216         public final void setDefaultLineStyle(Class<? extends RocketComponent> c,\r
217                         LineStyle style) {\r
218                 if (style == null)\r
219                         return;\r
220                 putString("componentStyle", c.getSimpleName(), style.name());\r
221         }\r
222         \r
223         /**\r
224          * Get the default material type for the given component.\r
225          * @param componentClass\r
226          * @param type the Material.Type to return.\r
227          * @return\r
228          */\r
229         public Material getDefaultComponentMaterial(\r
230                         Class<? extends RocketComponent> componentClass,\r
231                         Material.Type type) {\r
232                 \r
233                 String material = get("componentMaterials", componentClass, null);\r
234                 if (material != null) {\r
235                         try {\r
236                                 Material m = Material.fromStorableString(material, false);\r
237                                 if (m.getType() == type)\r
238                                         return m;\r
239                         } catch (IllegalArgumentException ignore) {\r
240                         }\r
241                 }\r
242                 \r
243                 switch (type) {\r
244                 case LINE:\r
245                         return DefaultMaterialHolder.DEFAULT_LINE_MATERIAL;\r
246                 case SURFACE:\r
247                         return DefaultMaterialHolder.DEFAULT_SURFACE_MATERIAL;\r
248                 case BULK:\r
249                         return DefaultMaterialHolder.DEFAULT_BULK_MATERIAL;\r
250                 }\r
251                 throw new IllegalArgumentException("Unknown material type: " + type);\r
252         }\r
253         \r
254         /**\r
255          * Set the default material for a component type.\r
256          * @param componentClass\r
257          * @param material\r
258          */\r
259         public void setDefaultComponentMaterial(\r
260                         Class<? extends RocketComponent> componentClass, Material material) {\r
261                 \r
262                 putString("componentMaterials", componentClass.getSimpleName(),\r
263                                 material == null ? null : material.toStorableString());\r
264         }\r
265 \r
266         /**\r
267          * get a net.sf.openrocket.util.Color object for the given key.\r
268          * @param key\r
269          * @param defaultValue\r
270          * @return\r
271          */\r
272         public final Color getColor( String key, Color defaultValue ) {\r
273                 Color c = parseColor( getString(key,null) );\r
274                 if ( c == null ) {\r
275                         return defaultValue;\r
276                 }\r
277                 return c;\r
278         }\r
279         \r
280         /**\r
281          * set a net.sf.openrocket.util.Color preference value for the given key.\r
282          * @param key\r
283          * @param value\r
284          */\r
285         public final void putColor( String key, Color value ) {\r
286                 putString( key, stringifyColor(value) );\r
287         }\r
288 \r
289         /**\r
290          * Helper function to convert a string representation into a net.sf.openrocket.util.Color object.\r
291          * @param color\r
292          * @return\r
293          */\r
294         protected static Color parseColor(String color) {\r
295                 if (color == null) {\r
296                         return null;\r
297                 }\r
298                 \r
299                 String[] rgb = color.split(",");\r
300                 if (rgb.length == 3) {\r
301                         try {\r
302                                 int red = MathUtil.clamp(Integer.parseInt(rgb[0]), 0, 255);\r
303                                 int green = MathUtil.clamp(Integer.parseInt(rgb[1]), 0, 255);\r
304                                 int blue = MathUtil.clamp(Integer.parseInt(rgb[2]), 0, 255);\r
305                                 return new Color(red, green, blue);\r
306                         } catch (NumberFormatException ignore) {\r
307                         }\r
308                 }\r
309                 return null;\r
310         }\r
311         \r
312         /**\r
313          * Helper function to convert a net.sf.openrocket.util.Color object into a\r
314          * String before storing in a preference.\r
315          * @param color\r
316          * @return\r
317          */\r
318         protected static String stringifyColor(Color color) {\r
319                 String string = color.getRed() + "," + color.getGreen() + "," + color.getBlue();\r
320                 return string;\r
321         }\r
322 \r
323         /**\r
324          * Special helper function which allows for a map of default values.\r
325          * \r
326          * First getString(directory,componentClass.getSimpleName(), null) is invoked,\r
327          * if the returned value is null, the defaultMap is consulted for a value.\r
328          * \r
329          * @param directory\r
330          * @param componentClass\r
331          * @param defaultMap\r
332          * @return\r
333          */\r
334         protected String get(String directory,\r
335                         Class<? extends RocketComponent> componentClass,\r
336                         Map<Class<?>, String> defaultMap) {\r
337                 \r
338                 // Search preferences\r
339                 Class<?> c = componentClass;\r
340                 while (c != null && RocketComponent.class.isAssignableFrom(c)) {\r
341                         String value = this.getString(directory, c.getSimpleName(), null);\r
342                         if (value != null)\r
343                                 return value;\r
344                         c = c.getSuperclass();\r
345                 }\r
346                 \r
347                 if (defaultMap == null)\r
348                         return null;\r
349                 \r
350                 // Search defaults\r
351                 c = componentClass;\r
352                 while (RocketComponent.class.isAssignableFrom(c)) {\r
353                         String value = defaultMap.get(c);\r
354                         if (value != null)\r
355                                 return value;\r
356                         c = c.getSuperclass();\r
357                 }\r
358                 \r
359                 return null;\r
360         }\r
361 \r
362         public abstract void addUserMaterial(Material m);\r
363         public abstract Set<Material> getUserMaterials();\r
364         public abstract void removeUserMaterial(Material m);\r
365 \r
366         /*\r
367          * Map of default line styles\r
368          */\r
369         private static final HashMap<Class<?>, String> DEFAULT_LINE_STYLES =\r
370                         new HashMap<Class<?>, String>();\r
371         static {\r
372                 DEFAULT_LINE_STYLES.put(RocketComponent.class, LineStyle.SOLID.name());\r
373                 DEFAULT_LINE_STYLES.put(MassObject.class, LineStyle.DASHED.name());\r
374         }\r
375         \r
376         /*\r
377          * Within a holder class so they will load only when needed.\r
378          */\r
379         private static class DefaultMaterialHolder {\r
380                 private static final Translator trans = Application.getTranslator();\r
381                 \r
382                 //// Elastic cord (round 2mm, 1/16 in)\r
383                 private static final Material DEFAULT_LINE_MATERIAL =\r
384                                 Databases.findMaterial(Material.Type.LINE, trans.get("Databases.materials.Elasticcordround2mm"),\r
385                                                 0.0018, false);\r
386                 //// Ripstop nylon\r
387                 private static final Material DEFAULT_SURFACE_MATERIAL =\r
388                                 Databases.findMaterial(Material.Type.SURFACE, trans.get("Databases.materials.Ripstopnylon"), 0.067, false);\r
389                 //// Cardboard\r
390                 private static final Material DEFAULT_BULK_MATERIAL =\r
391                                 Databases.findMaterial(Material.Type.BULK, trans.get("Databases.materials.Cardboard"), 680, false);\r
392         }\r
393         \r
394         private static final HashMap<Class<?>, String> DEFAULT_COLORS =\r
395                         new HashMap<Class<?>, String>();\r
396         static {\r
397                 DEFAULT_COLORS.put(BodyComponent.class, "0,0,240");\r
398                 DEFAULT_COLORS.put(FinSet.class, "0,0,200");\r
399                 DEFAULT_COLORS.put(LaunchLug.class, "0,0,180");\r
400                 DEFAULT_COLORS.put(InternalComponent.class, "170,0,100");\r
401                 DEFAULT_COLORS.put(MassObject.class, "0,0,0");\r
402                 DEFAULT_COLORS.put(RecoveryDevice.class, "255,0,0");\r
403         }\r
404         \r
405 \r
406 \r
407 }\r