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

Last change on this file since 1722 was 1722, checked in by stoecker, 15 years ago

Large rework in projection handling - now allows only switching and more specific projections
TODO:

  • allow subprojections (i.e. settings for projections)
  • setup preferences for subprojections
  • better support of the new projection depending world bounds (how to handle valid data outside of world)
  • do not allow to zoom out of the world - zoom should stop when whole world is displayed
  • fix Lambert and SwissGrid to handle new OutOfWorld style and subprojections
  • fix new UTM projection
  • handle layers with fixed projection on projection change
  • allow easier projection switching (e.g. in menu)

NOTE:
This checkin very likely will cause problems. Please report or fix them. Older plugins may have trouble. The SVN plugins
have been fixed but may have problems nevertheless. This is a BIG change, but will make JOSMs internal structure much cleaner
and reduce lots of projection related problems.

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