1 package net.sf.openrocket.startup;
\r
3 import java.util.HashMap;
\r
4 import java.util.Map;
\r
5 import java.util.Set;
\r
7 import net.sf.openrocket.database.Databases;
\r
8 import net.sf.openrocket.material.Material;
\r
9 import net.sf.openrocket.preset.ComponentPreset;
\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
24 public abstract class Preferences {
\r
27 * Well known string keys to preferences.
\r
28 * There are other strings out there in the source as well.
\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
41 public static final String PLOT_SHOW_POINTS = "ShowPlotPoints";
\r
43 private static final String CHECK_UPDATES = "CheckUpdates";
\r
44 public static final String LAST_UPDATE = "LastUpdateVersion";
\r
46 public static final String MOTOR_DIAMETER_FILTER = "MotorDiameterMatch";
\r
47 public static final String MOTOR_HIDE_SIMILAR = "MotorHideSimilar";
\r
50 public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors";
\r
53 * ******************************************************************************************
\r
55 * Abstract methods which must be implemented by any derived class.
\r
57 public abstract boolean getBoolean(String key, boolean defaultValue);
\r
59 public abstract void putBoolean(String key, boolean value);
\r
61 public abstract int getInt(String key, int defaultValue);
\r
63 public abstract void putInt(String key, int value);
\r
65 public abstract double getDouble(String key, double defaultValue);
\r
67 public abstract void putDouble(String key, double value);
\r
69 public abstract String getString(String key, String defaultValue);
\r
71 public abstract void putString(String key, String value);
\r
74 * Directory represents a way to collect multiple keys together. Implementors may
\r
75 * choose to concatenate the directory with the key using some special character.
\r
78 * @param defaultValue
\r
81 public abstract String getString(String directory, String key, String defaultValue);
\r
83 public abstract void putString(String directory, String key, String value);
\r
86 * ******************************************************************************************
\r
88 public final boolean getCheckUpdates() {
\r
89 return this.getBoolean(CHECK_UPDATES, BuildProperties.getDefaultCheckUpdates());
\r
92 public final void setCheckUpdates(boolean check) {
\r
93 this.putBoolean(CHECK_UPDATES, check);
\r
96 public final double getDefaultMach() {
\r
97 // TODO: HIGH: implement custom default mach number
\r
102 * Return the OpenRocket unique ID.
\r
104 * @return a random ID string that stays constant between OpenRocket executions
\r
106 public final String getUniqueID() {
\r
107 String id = this.getString("id", null);
\r
109 id = UniqueID.uuid();
\r
110 this.putString("id", id);
\r
116 * Returns a limited-range integer value from the preferences. If the value
\r
117 * in the preferences is negative or greater than max, then the default value
\r
120 * @param key The preference to retrieve.
\r
121 * @param max Maximum allowed value for the choice.
\r
122 * @param def Default value.
\r
123 * @return The preference value.
\r
125 public final int getChoice(String key, int max, int def) {
\r
126 int v = this.getInt(key, def);
\r
127 if ((v < 0) || (v > max))
\r
133 * Helper method that puts an integer choice value into the preferences.
\r
135 * @param key the preference key.
\r
136 * @param value the value to store.
\r
138 public final void putChoice(String key, int value) {
\r
139 this.putInt(key, value);
\r
143 * Retrieve an enum value from the user preferences.
\r
145 * @param <T> the enum type
\r
146 * @param key the key
\r
147 * @param def the default value, cannot be null
\r
148 * @return the value in the preferences, or the default value
\r
150 public final <T extends Enum<T>> T getEnum(String key, T def) {
\r
152 throw new BugException("Default value cannot be null");
\r
155 String value = getString(key, null);
\r
156 if (value == null) {
\r
161 return Enum.valueOf(def.getDeclaringClass(), value);
\r
162 } catch (IllegalArgumentException e) {
\r
168 * Store an enum value to the user preferences.
\r
170 * @param key the key
\r
171 * @param value the value to store, or null to remove the value
\r
173 public final void putEnum(String key, Enum<?> value) {
\r
174 if (value == null) {
\r
175 putString(key, null);
\r
177 putString(key, value.name());
\r
181 public Color getDefaultColor(Class<? extends RocketComponent> c) {
\r
182 String color = get("componentColors", c, DEFAULT_COLORS);
\r
184 return Color.BLACK;
\r
186 Color clr = parseColor(color);
\r
190 return Color.BLACK;
\r
194 public final void setDefaultColor(Class<? extends RocketComponent> c, Color color) {
\r
197 putString("componentColors", c.getSimpleName(), stringifyColor(color));
\r
202 * Retrieve a Line style for the given component.
\r
206 public final LineStyle getDefaultLineStyle(Class<? extends RocketComponent> c) {
\r
207 String value = get("componentStyle", c, DEFAULT_LINE_STYLES);
\r
209 return LineStyle.valueOf(value);
\r
210 } catch (Exception e) {
\r
211 return LineStyle.SOLID;
\r
216 * Set a default line style for the given component.
\r
220 public final void setDefaultLineStyle(Class<? extends RocketComponent> c,
\r
224 putString("componentStyle", c.getSimpleName(), style.name());
\r
228 * Get the default material type for the given component.
\r
229 * @param componentClass
\r
230 * @param type the Material.Type to return.
\r
233 public Material getDefaultComponentMaterial(
\r
234 Class<? extends RocketComponent> componentClass,
\r
235 Material.Type type) {
\r
237 String material = get("componentMaterials", componentClass, null);
\r
238 if (material != null) {
\r
240 Material m = Material.fromStorableString(material, false);
\r
241 if (m.getType() == type)
\r
243 } catch (IllegalArgumentException ignore) {
\r
249 return DefaultMaterialHolder.DEFAULT_LINE_MATERIAL;
\r
251 return DefaultMaterialHolder.DEFAULT_SURFACE_MATERIAL;
\r
253 return DefaultMaterialHolder.DEFAULT_BULK_MATERIAL;
\r
255 throw new IllegalArgumentException("Unknown material type: " + type);
\r
259 * Set the default material for a component type.
\r
260 * @param componentClass
\r
263 public void setDefaultComponentMaterial(
\r
264 Class<? extends RocketComponent> componentClass, Material material) {
\r
266 putString("componentMaterials", componentClass.getSimpleName(),
\r
267 material == null ? null : material.toStorableString());
\r
271 * get a net.sf.openrocket.util.Color object for the given key.
\r
273 * @param defaultValue
\r
276 public final Color getColor(String key, Color defaultValue) {
\r
277 Color c = parseColor(getString(key, null));
\r
279 return defaultValue;
\r
285 * set a net.sf.openrocket.util.Color preference value for the given key.
\r
289 public final void putColor(String key, Color value) {
\r
290 putString(key, stringifyColor(value));
\r
294 * Helper function to convert a string representation into a net.sf.openrocket.util.Color object.
\r
298 protected static Color parseColor(String color) {
\r
299 if (color == null) {
\r
303 String[] rgb = color.split(",");
\r
304 if (rgb.length == 3) {
\r
306 int red = MathUtil.clamp(Integer.parseInt(rgb[0]), 0, 255);
\r
307 int green = MathUtil.clamp(Integer.parseInt(rgb[1]), 0, 255);
\r
308 int blue = MathUtil.clamp(Integer.parseInt(rgb[2]), 0, 255);
\r
309 return new Color(red, green, blue);
\r
310 } catch (NumberFormatException ignore) {
\r
317 * Helper function to convert a net.sf.openrocket.util.Color object into a
\r
318 * String before storing in a preference.
\r
322 protected static String stringifyColor(Color color) {
\r
323 String string = color.getRed() + "," + color.getGreen() + "," + color.getBlue();
\r
328 * Special helper function which allows for a map of default values.
\r
330 * First getString(directory,componentClass.getSimpleName(), null) is invoked,
\r
331 * if the returned value is null, the defaultMap is consulted for a value.
\r
334 * @param componentClass
\r
335 * @param defaultMap
\r
338 protected String get(String directory,
\r
339 Class<? extends RocketComponent> componentClass,
\r
340 Map<Class<?>, String> defaultMap) {
\r
342 // Search preferences
\r
343 Class<?> c = componentClass;
\r
344 while (c != null && RocketComponent.class.isAssignableFrom(c)) {
\r
345 String value = this.getString(directory, c.getSimpleName(), null);
\r
348 c = c.getSuperclass();
\r
351 if (defaultMap == null)
\r
355 c = componentClass;
\r
356 while (RocketComponent.class.isAssignableFrom(c)) {
\r
357 String value = defaultMap.get(c);
\r
360 c = c.getSuperclass();
\r
366 public abstract void addUserMaterial(Material m);
\r
368 public abstract Set<Material> getUserMaterials();
\r
370 public abstract void removeUserMaterial(Material m);
\r
372 public abstract void setComponentFavorite(ComponentPreset preset, ComponentPreset.Type type, boolean favorite);
\r
374 public abstract Set<String> getComponentFavorites(ComponentPreset.Type type);
\r
377 * Map of default line styles
\r
379 private static final HashMap<Class<?>, String> DEFAULT_LINE_STYLES =
\r
380 new HashMap<Class<?>, String>();
\r
382 DEFAULT_LINE_STYLES.put(RocketComponent.class, LineStyle.SOLID.name());
\r
383 DEFAULT_LINE_STYLES.put(MassObject.class, LineStyle.DASHED.name());
\r
387 * Within a holder class so they will load only when needed.
\r
389 private static class DefaultMaterialHolder {
\r
390 private static final Material DEFAULT_LINE_MATERIAL = Databases.findMaterial(Material.Type.LINE, "Elastic cord (round 2 mm, 1/16 in)");
\r
391 private static final Material DEFAULT_SURFACE_MATERIAL = Databases.findMaterial(Material.Type.SURFACE, "Ripstop nylon");
\r
392 private static final Material DEFAULT_BULK_MATERIAL = Databases.findMaterial(Material.Type.BULK, "Cardboard");
\r
395 private static final HashMap<Class<?>, String> DEFAULT_COLORS =
\r
396 new HashMap<Class<?>, String>();
\r
398 DEFAULT_COLORS.put(BodyComponent.class, "0,0,240");
\r
399 DEFAULT_COLORS.put(FinSet.class, "0,0,200");
\r
400 DEFAULT_COLORS.put(LaunchLug.class, "0,0,180");
\r
401 DEFAULT_COLORS.put(InternalComponent.class, "170,0,100");
\r
402 DEFAULT_COLORS.put(MassObject.class, "0,0,0");
\r
403 DEFAULT_COLORS.put(RecoveryDevice.class, "255,0,0");
\r