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

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

removed OptionPaneUtil
cleanup of deprecated Layer API
cleanup of deprecated APIs in OsmPrimitive and Way
cleanup of imports

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