source: josm/trunk/src/org/openstreetmap/josm/data/Preferences.java@ 1857

Last change on this file since 1857 was 1857, checked in by Gubaer, 15 years ago

replaced JOptionDialog.show... by OptionPaneUtil.show....
improved relation editor

  • Property svn:eol-style set to native
File size: 20.6 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.data;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.io.BufferedReader;
8import java.io.File;
9import java.io.FileInputStream;
10import java.io.FileOutputStream;
11import java.io.IOException;
12import java.io.InputStreamReader;
13import java.io.OutputStreamWriter;
14import java.io.PrintWriter;
15import java.util.ArrayList;
16import java.util.Arrays;
17import java.util.Collection;
18import java.util.Collections;
19import java.util.LinkedList;
20import java.util.Map;
21import java.util.Properties;
22import java.util.SortedMap;
23import java.util.TreeMap;
24import java.util.Map.Entry;
25import java.util.regex.Matcher;
26import java.util.regex.Pattern;
27
28import javax.swing.JOptionPane;
29
30import org.openstreetmap.josm.Main;
31import org.openstreetmap.josm.actions.AboutAction;
32import org.openstreetmap.josm.data.projection.Mercator;
33import org.openstreetmap.josm.gui.OptionPaneUtil;
34import org.openstreetmap.josm.gui.preferences.ProxyPreferences;
35import org.openstreetmap.josm.tools.ColorHelper;
36
37/**
38 * This class holds all preferences for JOSM.
39 *
40 * Other classes can register their beloved properties here. All properties will be
41 * saved upon set-access.
42 *
43 * @author imi
44 */
45public class Preferences {
46
47 /**
48 * Internal storage for the preferenced directory.
49 * Do not access this variable directly!
50 * @see #getPreferencesDirFile()
51 */
52 private File preferencesDirFile = null;
53
54 public static interface PreferenceChangedListener {
55 void preferenceChanged(String key, String newValue);
56 }
57
58 /**
59 * Class holding one bookmarkentry.
60 * @author imi
61 */
62 public static class Bookmark implements Comparable<Bookmark> {
63 public String name;
64 public double[] latlon = new double[4]; // minlat, minlon, maxlat, maxlon
65 @Override public String toString() {
66 return name;
67 }
68 public int compareTo(Bookmark b) {
69 return name.toLowerCase().compareTo(b.name.toLowerCase());
70 }
71 }
72
73 public final ArrayList<PreferenceChangedListener> listener = new ArrayList<PreferenceChangedListener>();
74
75 /**
76 * Map the property name to the property object.
77 */
78 protected final SortedMap<String, String> properties = new TreeMap<String, String>();
79 protected final SortedMap<String, String> defaults = new TreeMap<String, String>();
80
81 /**
82 * Override some values on read. This is intended to be used for technology previews
83 * where we want to temporarily modify things without changing the user's preferences
84 * file.
85 */
86 protected static final SortedMap<String, String> override = new TreeMap<String, String>();
87 static {
88 //override.put("osm-server.version", "0.5");
89 //override.put("osm-server.additional-versions", "");
90 //override.put("osm-server.url", "http://openstreetmap.gryph.de/api");
91 //override.put("plugins", null);
92 }
93
94 /**
95 * Return the location of the user defined preferences file
96 */
97 public String getPreferencesDir() {
98 final String path = getPreferencesDirFile().getPath();
99 if (path.endsWith(File.separator))
100 return path;
101 return path + File.separator;
102 }
103
104 public File getPreferencesDirFile() {
105 if (preferencesDirFile != null)
106 return preferencesDirFile;
107 String path;
108 path = System.getProperty("josm.home");
109 if (path != null) {
110 preferencesDirFile = new File(path);
111 } else {
112 path = System.getenv("APPDATA");
113 if (path != null) {
114 preferencesDirFile = new File(path, "JOSM");
115 } else {
116 preferencesDirFile = new File(System.getProperty("user.home"), ".josm");
117 }
118 }
119 return preferencesDirFile;
120 }
121
122 public File getPluginsDirFile() {
123 return new File(getPreferencesDirFile(), "plugins");
124 }
125
126 /**
127 * @return A list of all existing directories where resources could be stored.
128 */
129 public Collection<String> getAllPossiblePreferenceDirs() {
130 LinkedList<String> locations = new LinkedList<String>();
131 locations.add(Main.pref.getPreferencesDir());
132 String s;
133 if ((s = System.getenv("JOSM_RESOURCES")) != null) {
134 if (!s.endsWith(File.separator)) {
135 s = s + File.separator;
136 }
137 locations.add(s);
138 }
139 if ((s = System.getProperty("josm.resources")) != null) {
140 if (!s.endsWith(File.separator)) {
141 s = s + File.separator;
142 }
143 locations.add(s);
144 }
145 String appdata = System.getenv("APPDATA");
146 if (System.getenv("ALLUSERSPROFILE") != null && appdata != null
147 && appdata.lastIndexOf(File.separator) != -1) {
148 appdata = appdata.substring(appdata.lastIndexOf(File.separator));
149 locations.add(new File(new File(System.getenv("ALLUSERSPROFILE"),
150 appdata), "JOSM").getPath());
151 }
152 locations.add("/usr/local/share/josm/");
153 locations.add("/usr/local/lib/josm/");
154 locations.add("/usr/share/josm/");
155 locations.add("/usr/lib/josm/");
156 return locations;
157 }
158
159 synchronized public boolean hasKey(final String key) {
160 return override.containsKey(key) ? override.get(key) != null : properties.containsKey(key);
161 }
162
163 synchronized public String get(final String key) {
164 putDefault(key, null);
165 if (override.containsKey(key))
166 return override.get(key);
167 if (!properties.containsKey(key))
168 return "";
169 return properties.get(key);
170 }
171
172 synchronized public String get(final String key, final String def) {
173 putDefault(key, def);
174 if (override.containsKey(key))
175 return override.get(key);
176 final String prop = properties.get(key);
177 if (prop == null || prop.equals(""))
178 return def;
179 return prop;
180 }
181
182 synchronized public Map<String, String> getAllPrefix(final String prefix) {
183 final Map<String,String> all = new TreeMap<String,String>();
184 for (final Entry<String,String> e : properties.entrySet())
185 if (e.getKey().startsWith(prefix)) {
186 all.put(e.getKey(), e.getValue());
187 }
188 for (final Entry<String,String> e : override.entrySet())
189 if (e.getKey().startsWith(prefix))
190 if (e.getValue() == null) {
191 all.remove(e.getKey());
192 } else {
193 all.put(e.getKey(), e.getValue());
194 }
195 return all;
196 }
197
198 synchronized public TreeMap<String, String> getAllColors() {
199 final TreeMap<String,String> all = new TreeMap<String,String>();
200 for (final Entry<String,String> e : defaults.entrySet())
201 if (e.getKey().startsWith("color.") && e.getValue() != null) {
202 all.put(e.getKey().substring(6), e.getValue());
203 }
204 for (final Entry<String,String> e : properties.entrySet())
205 if (e.getKey().startsWith("color.")) {
206 all.put(e.getKey().substring(6), e.getValue());
207 }
208 for (final Entry<String,String> e : override.entrySet())
209 if (e.getKey().startsWith("color."))
210 if (e.getValue() == null) {
211 all.remove(e.getKey().substring(6));
212 } else {
213 all.put(e.getKey().substring(6), e.getValue());
214 }
215 return all;
216 }
217
218 synchronized public Map<String, String> getDefaults() {
219 return defaults;
220 }
221
222 synchronized public void putDefault(final String key, final String def) {
223 if(!defaults.containsKey(key) || defaults.get(key) == null) {
224 defaults.put(key, def);
225 } else if(def != null && !defaults.get(key).equals(def)) {
226 System.out.println("Defaults for " + key + " differ: " + def + " != " + defaults.get(key));
227 }
228 }
229
230 synchronized public boolean getBoolean(final String key) {
231 putDefault(key, null);
232 if (override.containsKey(key))
233 return override.get(key) == null ? false : Boolean.parseBoolean(override.get(key));
234 return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : false;
235 }
236
237 synchronized public boolean getBoolean(final String key, final boolean def) {
238 putDefault(key, Boolean.toString(def));
239 if (override.containsKey(key))
240 return override.get(key) == null ? def : Boolean.parseBoolean(override.get(key));
241 return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : def;
242 }
243
244 synchronized public boolean put(final String key, String value) {
245 String oldvalue = properties.get(key);
246 if(value != null && value.length() == 0) {
247 value = null;
248 }
249 if(!((oldvalue == null && (value == null || value.equals(defaults.get(key))))
250 || (value != null && oldvalue != null && oldvalue.equals(value))))
251 {
252 if (value == null) {
253 properties.remove(key);
254 } else {
255 properties.put(key, value);
256 }
257 save();
258 firePreferenceChanged(key, value);
259 return true;
260 }
261 return false;
262 }
263
264 synchronized public boolean put(final String key, final boolean value) {
265 return put(key, Boolean.toString(value));
266 }
267
268 synchronized public boolean putInteger(final String key, final Integer value) {
269 return put(key, Integer.toString(value));
270 }
271
272 synchronized public boolean putDouble(final String key, final Double value) {
273 return put(key, Double.toString(value));
274 }
275
276 synchronized public boolean putLong(final String key, final Long value) {
277 return put(key, Long.toString(value));
278 }
279
280 private final void firePreferenceChanged(final String key, final String value) {
281 for (final PreferenceChangedListener l : listener) {
282 l.preferenceChanged(key, value);
283 }
284 }
285
286 /**
287 * Called after every put. In case of a problem, do nothing but output the error
288 * in log.
289 */
290 public void save() {
291 /* currently unused, but may help to fix configuration issues in future */
292 properties.put("josm.version", AboutAction.getVersionString());
293 try {
294 setSystemProperties();
295 final PrintWriter out = new PrintWriter(new OutputStreamWriter(
296 new FileOutputStream(getPreferencesDir() + "preferences"), "utf-8"), false);
297 for (final Entry<String, String> e : properties.entrySet()) {
298 String s = defaults.get(e.getKey());
299 /* don't save default values */
300 if(s == null || !s.equals(e.getValue())) {
301 out.println(e.getKey() + "=" + e.getValue());
302 }
303 }
304 out.close();
305 } catch (final IOException e) {
306 e.printStackTrace();
307 // do not message anything, since this can be called from strange
308 // places.
309 }
310 }
311
312 public void load() throws IOException {
313 properties.clear();
314 final BufferedReader in = new BufferedReader(new InputStreamReader(
315 new FileInputStream(getPreferencesDir()+"preferences"), "utf-8"));
316 int lineNumber = 0;
317 ArrayList<Integer> errLines = new ArrayList<Integer>();
318 for (String line = in.readLine(); line != null; line = in.readLine(), lineNumber++) {
319 final int i = line.indexOf('=');
320 if (i == -1 || i == 0) {
321 errLines.add(lineNumber);
322 continue;
323 }
324 properties.put(line.substring(0,i), line.substring(i+1));
325 }
326 if (!errLines.isEmpty())
327 throw new IOException(tr("Malformed config file at lines {0}", errLines));
328 setSystemProperties();
329 }
330
331 public void init(Boolean reset)
332 {
333 // get the preferences.
334 File prefDir = getPreferencesDirFile();
335 if (prefDir.exists()) {
336 if(!prefDir.isDirectory()) {
337 OptionPaneUtil.showMessageDialog(
338 Main.parent,
339 tr("Cannot open preferences directory: {0}",Main.pref.getPreferencesDir()),
340 tr("Error"),
341 JOptionPane.ERROR_MESSAGE
342 );
343 return;
344 }
345 } else {
346 prefDir.mkdirs();
347 }
348
349 if (!new File(getPreferencesDir()+"preferences").exists()) {
350 resetToDefault();
351 }
352
353 try {
354 if (reset) {
355 resetToDefault();
356 } else {
357 load();
358 }
359 } catch (final IOException e1) {
360 e1.printStackTrace();
361 String backup = getPreferencesDir() + "preferences.bak";
362 OptionPaneUtil.showMessageDialog(
363 Main.parent,
364 tr("Preferences file had errors. Making backup of old one to {0}.", backup),
365 tr("Error"),
366 JOptionPane.ERROR_MESSAGE
367 );
368 new File(getPreferencesDir() + "preferences").renameTo(new File(backup));
369 save();
370 }
371 }
372
373 public final void resetToDefault() {
374 properties.clear();
375 put("layerlist.visible", true);
376 put("propertiesdialog.visible", true);
377 put("selectionlist.visible", true);
378 put("commandstack.visible", true);
379 if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") == -1) {
380 put("laf", "javax.swing.plaf.metal.MetalLookAndFeel");
381 } else {
382 put("laf", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
383 }
384 save();
385 }
386
387 public Collection<Bookmark> loadBookmarks() throws IOException {
388 File bookmarkFile = new File(getPreferencesDir()+"bookmarks");
389 if (!bookmarkFile.exists()) {
390 bookmarkFile.createNewFile();
391 }
392 BufferedReader in = new BufferedReader(new InputStreamReader(
393 new FileInputStream(bookmarkFile), "utf-8"));
394
395 LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>();
396 for (String line = in.readLine(); line != null; line = in.readLine()) {
397 // FIXME: legacy code using ',' sign, should be \u001e only
398 Matcher m = Pattern.compile("^(.+)[,\u001e](-?\\d+.\\d+)[,\u001e](-?\\d+.\\d+)[,\u001e](-?\\d+.\\d+)[,\u001e](-?\\d+.\\d+)$").matcher(line);
399 if(m.matches())
400 {
401 Bookmark b = new Bookmark();
402 b.name = m.group(1);
403 for (int i = 0; i < b.latlon.length; ++i) {
404 b.latlon[i] = Double.parseDouble(m.group(i+2));
405 }
406 bookmarks.add(b);
407 }
408 }
409 in.close();
410 Collections.sort(bookmarks);
411 return bookmarks;
412 }
413
414 public void saveBookmarks(Collection<Bookmark> bookmarks) throws IOException {
415 File bookmarkFile = new File(Main.pref.getPreferencesDir()+"bookmarks");
416 if (!bookmarkFile.exists()) {
417 bookmarkFile.createNewFile();
418 }
419 PrintWriter out = new PrintWriter(new OutputStreamWriter(
420 new FileOutputStream(bookmarkFile), "utf-8"));
421 for (Bookmark b : bookmarks) {
422 out.print(b.name+"\u001e");
423 for (int i = 0; i < b.latlon.length; ++i) {
424 out.print(b.latlon[i]+(i<b.latlon.length-1?"\u001e":""));
425 }
426 out.println();
427 }
428 out.close();
429 }
430
431 /**
432 * Convenience method for accessing colour preferences.
433 *
434 * @param colName name of the colour
435 * @param def default value
436 * @return a Color object for the configured colour, or the default value if none configured.
437 */
438 synchronized public Color getColor(String colName, Color def) {
439 return getColor(colName, null, def);
440 }
441
442 /**
443 * Convenience method for accessing colour preferences.
444 *
445 * @param colName name of the colour
446 * @param specName name of the special colour settings
447 * @param def default value
448 * @return a Color object for the configured colour, or the default value if none configured.
449 */
450 synchronized public Color getColor(String colName, String specName, Color def) {
451 putDefault("color."+colName, ColorHelper.color2html(def));
452 String colStr = specName != null ? get("color."+specName) : "";
453 if(colStr.equals("")) {
454 colStr = get("color."+colName);
455 }
456 return colStr.equals("") ? def : ColorHelper.html2color(colStr);
457 }
458
459 synchronized public Color getDefaultColor(String colName) {
460 String colStr = defaults.get("color."+colName);
461 return colStr.equals("") ? null : ColorHelper.html2color(colStr);
462 }
463
464 synchronized public boolean putColor(String colName, Color val) {
465 return put("color."+colName, val != null ? ColorHelper.color2html(val) : null);
466 }
467
468 synchronized public int getInteger(String key, int def) {
469 putDefault(key, Integer.toString(def));
470 String v = get(key);
471 if(null == v)
472 return def;
473
474 try {
475 return Integer.parseInt(v);
476 } catch(NumberFormatException e) {
477 // fall out
478 }
479 return def;
480 }
481
482 synchronized public long getLong(String key, long def) {
483 putDefault(key, Long.toString(def));
484 String v = get(key);
485 if(null == v)
486 return def;
487
488 try {
489 return Long.parseLong(v);
490 } catch(NumberFormatException e) {
491 // fall out
492 }
493 return def;
494 }
495
496 synchronized public double getDouble(String key, double def) {
497 putDefault(key, Double.toString(def));
498 String v = get(key);
499 if(null == v)
500 return def;
501
502 try {
503 return Double.parseDouble(v);
504 } catch(NumberFormatException e) {
505 // fall out
506 }
507 return def;
508 }
509
510 synchronized public double getDouble(String key, String def) {
511 putDefault(key, def);
512 String v = get(key);
513 if(v != null && v.length() != 0) {
514 try { return Double.parseDouble(v); } catch(NumberFormatException e) {}
515 }
516 try { return Double.parseDouble(def); } catch(NumberFormatException e) {}
517 return 0.0;
518 }
519
520 synchronized public Collection<String> getCollection(String key, Collection<String> def) {
521 String s = get(key);
522 if(def != null)
523 {
524 String d = null;
525 for(String a : def)
526 {
527 if(d != null) {
528 d += "\u001e" + a;
529 } else {
530 d = a;
531 }
532 }
533 putDefault(key, d);
534 }
535 if(s != null && s.length() != 0)
536 {
537 if(s.indexOf("\u001e") < 0) /* FIXME: legacy code, remove later */
538 {
539 String r =s;
540 if(r.indexOf("§§§") > 0) {
541 r = r.replaceAll("§§§","\u001e");
542 } else {
543 r = r.replace(';','\u001e');
544 }
545 if(!r.equals(s)) /* save the converted string */
546 {
547 put(key,r);
548 s = r;
549 }
550 }
551 return Arrays.asList(s.split("\u001e"));
552 }
553 return def;
554 }
555 synchronized public void removeFromCollection(String key, String value) {
556 ArrayList<String> a = new ArrayList<String>(getCollection(key, null));
557 if(a != null)
558 {
559 a.remove(value);
560 putCollection(key, a);
561 }
562 }
563 synchronized public boolean putCollection(String key, Collection<String> val) {
564 String s = null;
565 if(val != null)
566 {
567 for(String a : val)
568 {
569 if(s != null) {
570 s += "\u001e" + a;
571 } else {
572 s = a;
573 }
574 }
575 }
576
577 return put(key, s);
578 }
579
580 private void setSystemProperties() {
581 if (getBoolean(ProxyPreferences.PROXY_ENABLE)) {
582 Properties sysProp = System.getProperties();
583 sysProp.put("proxySet", "true");
584 sysProp.put("http.proxyHost", get(ProxyPreferences.PROXY_HOST));
585 sysProp.put("proxyPort", get(ProxyPreferences.PROXY_PORT));
586 if (!getBoolean(ProxyPreferences.PROXY_ANONYMOUS)) {
587 sysProp.put("proxyUser", get(ProxyPreferences.PROXY_USER));
588 sysProp.put("proxyPassword", get(ProxyPreferences.PROXY_PASS));
589 }
590 System.setProperties(sysProp);
591 }
592 AboutAction.setUserAgent();
593 }
594}
Note: See TracBrowser for help on using the repository browser.