Index: trunk/src/org/openstreetmap/josm/data/preferences/BooleanProperty.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/BooleanProperty.java	(revision 3246)
+++ trunk/src/org/openstreetmap/josm/data/preferences/BooleanProperty.java	(revision 3246)
@@ -0,0 +1,24 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences;
+
+import org.openstreetmap.josm.Main;
+
+public class BooleanProperty {
+
+    private final String key;
+    private final boolean defaultValue;
+
+    public BooleanProperty(String key, boolean defaultValue) {
+        this.key = key;
+        this.defaultValue = defaultValue;
+    }
+
+    public boolean get() {
+        return Main.pref.getBoolean(key, defaultValue);
+    }
+
+    public boolean put(boolean value) {
+        return Main.pref.put(key, value);
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/CollectionProperty.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/CollectionProperty.java	(revision 3246)
+++ trunk/src/org/openstreetmap/josm/data/preferences/CollectionProperty.java	(revision 3246)
@@ -0,0 +1,25 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences;
+
+import java.util.Collection;
+
+import org.openstreetmap.josm.Main;
+
+public class CollectionProperty {
+    private final String key;
+    private final Collection<String> defaultValue;
+
+    public CollectionProperty(String key, Collection<String> defaultValue) {
+        this.key = key;
+        this.defaultValue = defaultValue;
+    }
+
+    public Collection<String> get() {
+        return Main.pref.getCollection(key, defaultValue);
+    }
+
+    public boolean put(Collection<String> value) {
+        return Main.pref.putCollection(key, value);
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/IntegerProperty.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/IntegerProperty.java	(revision 3246)
+++ trunk/src/org/openstreetmap/josm/data/preferences/IntegerProperty.java	(revision 3246)
@@ -0,0 +1,24 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences;
+
+import org.openstreetmap.josm.Main;
+
+public class IntegerProperty {
+
+    private final String key;
+    private final int defaultValue;
+
+    public IntegerProperty(String key, int defaultValue) {
+        this.key = key;
+        this.defaultValue = defaultValue;
+    }
+
+    public int get() {
+        return Main.pref.getInteger(key, defaultValue);
+    }
+
+    public boolean put(int value) {
+        return Main.pref.putInteger(key, value);
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/ParametrizedCollectionProperty.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/ParametrizedCollectionProperty.java	(revision 3246)
+++ trunk/src/org/openstreetmap/josm/data/preferences/ParametrizedCollectionProperty.java	(revision 3246)
@@ -0,0 +1,26 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences;
+
+import java.util.Collection;
+
+import org.openstreetmap.josm.Main;
+
+public abstract class ParametrizedCollectionProperty {
+
+    private final Collection<String> defaultValue;
+
+    public ParametrizedCollectionProperty(Collection<String> defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    protected abstract String getKey(String... params);
+
+    public Collection<String> get(String... params) {
+        return Main.pref.getCollection(getKey(params), defaultValue);
+    }
+
+    public boolean put(Collection<String> value, String... params) {
+        return Main.pref.putCollection(getKey(params), value);
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/StringProperty.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/StringProperty.java	(revision 3246)
+++ trunk/src/org/openstreetmap/josm/data/preferences/StringProperty.java	(revision 3246)
@@ -0,0 +1,24 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences;
+
+import org.openstreetmap.josm.Main;
+
+public class StringProperty {
+
+    private final String key;
+    private final String defaultValue;
+
+    public StringProperty(String key, String defaultValue) {
+        this.key = key;
+        this.defaultValue = defaultValue;
+    }
+
+    public String get() {
+        return Main.pref.get(key, defaultValue);
+    }
+
+    public boolean put(String value) {
+        return Main.pref.put(key, value);
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java	(revision 3245)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java	(revision 3246)
@@ -8,4 +8,5 @@
 import java.awt.event.ActionListener;
 import java.util.Collection;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.swing.BorderFactory;
@@ -19,4 +20,7 @@
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.CoordinateFormat;
+import org.openstreetmap.josm.data.preferences.CollectionProperty;
+import org.openstreetmap.josm.data.preferences.ParametrizedCollectionProperty;
+import org.openstreetmap.josm.data.preferences.StringProperty;
 import org.openstreetmap.josm.data.projection.Mercator;
 import org.openstreetmap.josm.data.projection.Projection;
@@ -32,4 +36,38 @@
     }
 
+    public interface ProjectionChangedListener {
+        void projectionChanged();
+    }
+
+    private static final StringProperty PROP_PROJECTION = new StringProperty("projection", Mercator.class.getName());
+    private static final StringProperty PROP_COORDINATES = new StringProperty("coordinates", null);
+    private static final CollectionProperty PROP_SUB_PROJECTION = new CollectionProperty("projection.sub", null);
+    private static final ParametrizedCollectionProperty PROP_PROJECTION_SUBPROJECTION = new ParametrizedCollectionProperty(null) {
+        @Override
+        protected String getKey(String... params) {
+            String name = params[0];
+            String sname = name.substring(name.lastIndexOf(".")+1);
+            return "projection.sub."+sname;
+        }
+    };
+
+    //TODO This is not nice place for a listener code but probably only Dataset will want to listen for projection changes so it's acceptable
+    private static CopyOnWriteArrayList<ProjectionChangedListener> listeners = new CopyOnWriteArrayList<ProjectionChangedListener>();
+
+    public static void addProjectionChangedListener(ProjectionChangedListener listener) {
+        listeners.addIfAbsent(listener);
+    }
+
+    public static void removeProjectionChangedListener(ProjectionChangedListener listener) {
+        listeners.remove(listener);
+    }
+
+    private static void fireProjectionChanged() {
+        for (ProjectionChangedListener listener: listeners) {
+            listener.projectionChanged();
+        }
+    }
+
+
     /**
      * Combobox with all projections available
@@ -68,5 +106,5 @@
 
         for (int i = 0; i < coordinatesCombo.getItemCount(); ++i) {
-            if (((CoordinateFormat)coordinatesCombo.getItemAt(i)).name().equals(Main.pref.get("coordinates"))) {
+            if (((CoordinateFormat)coordinatesCombo.getItemAt(i)).name().equals(PROP_COORDINATES.get())) {
                 coordinatesCombo.setSelectedIndex(i);
                 break;
@@ -113,9 +151,8 @@
         }
 
-        Main.pref.put("projection", projname);
+        PROP_PROJECTION.put(projname);
         setProjection(projname, prefs);
 
-        if(Main.pref.put("coordinates",
-                ((CoordinateFormat)coordinatesCombo.getSelectedItem()).name())) {
+        if(PROP_COORDINATES.put(((CoordinateFormat)coordinatesCombo.getSelectedItem()).name())) {
             CoordinateFormat.setCoordinateFormat((CoordinateFormat)coordinatesCombo.getSelectedItem());
         }
@@ -126,6 +163,5 @@
     static public void setProjection()
     {
-        setProjection(Main.pref.get("projection", Mercator.class.getName()),
-                Main.pref.getCollection("projection.sub", null));
+        setProjection(PROP_PROJECTION.get(), PROP_SUB_PROJECTION.get());
     }
 
@@ -148,10 +184,10 @@
             name = Main.proj.getClass().getName();
         }
-        Main.pref.putCollection("projection.sub", coll);
-        String sname = name.substring(name.lastIndexOf(".")+1);
-        Main.pref.putCollection("projection.sub."+sname, coll);
+        PROP_SUB_PROJECTION.put(coll);
+        PROP_PROJECTION_SUBPROJECTION.put(coll, name);
         if(Main.proj instanceof ProjectionSubPrefs) {
             ((ProjectionSubPrefs) Main.proj).setPreferences(coll);
         }
+        fireProjectionChanged(); // This should be probably called from the if bellow, but hashCode condition doesn't look sure enough
         if(b != null && (!Main.proj.getClass().getName().equals(oldProj.getClass().getName()) || Main.proj.hashCode() != oldProj.hashCode()))
         {
@@ -212,9 +248,8 @@
             Projection proj = (Projection)projectionCombo.getItemAt(i);
             String name = proj.getClass().getName();
-            String sname = name.substring(name.lastIndexOf(".")+1);
             if(proj instanceof ProjectionSubPrefs) {
-                ((ProjectionSubPrefs) proj).setPreferences(Main.pref.getCollection("projection.sub."+sname, null));
-            }
-            if (name.equals(Main.pref.get("projection", Mercator.class.getName()))) {
+                ((ProjectionSubPrefs) proj).setPreferences(PROP_PROJECTION_SUBPROJECTION.get(name));
+            }
+            if (name.equals(PROP_PROJECTION.get())) {
                 projectionCombo.setSelectedIndex(i);
                 selectedProjectionChanged(proj);
