Index: /trunk/src/org/openstreetmap/josm/data/imagery/OffsetBookmark.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/imagery/OffsetBookmark.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/data/imagery/OffsetBookmark.java	(revision 3779)
@@ -14,4 +14,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.data.projection.ProjectionInfo;
 import org.openstreetmap.josm.gui.layer.ImageryLayer;
 
@@ -26,6 +27,7 @@
 
     public boolean isUsable(ImageryLayer layer) {
-        return Main.proj.getClass() == proj.getClass() &&
-        layer.getInfo().getName().equals(layerName);
+        if (proj == null) return false;
+        if (!Main.proj.toCode().equals(proj.toCode())) return false;
+        return layer.getInfo().getName().equals(layerName);
     }
 
@@ -46,13 +48,14 @@
     public OffsetBookmark(Collection<String> list) {
         ArrayList<String> array = new ArrayList<String>(list);
-        String projectionName = array.get(0);
-        for (Projection proj : Projection.allProjections) {
-            if (proj.getCacheDirectoryName().equals(projectionName)) {
-                this.proj = proj;
-                break;
+        String projectionStr = array.get(0);
+        proj = ProjectionInfo.getProjectionByCode(projectionStr);
+        if (proj == null) {
+            for (Projection proj : Projection.allProjections) {
+                if (proj.getCacheDirectoryName().equals(projectionStr)) {
+                    this.proj = proj;
+                    break;
+                }
             }
         }
-        if (this.proj == null)
-            throw new IllegalStateException(tr("Projection ''{0}'' not found", projectionName));
         this.layerName = array.get(1);
         this.name = array.get(2);
@@ -63,9 +66,16 @@
             this.centerY = Double.valueOf(array.get(6));
         }
+        if (proj == null) {
+            System.err.println(tr("Projection ''{0}'' is not found, bookmark ''{1}'' is not usable", projectionStr, name));
+        }
     }
 
     public ArrayList<String> getInfoArray() {
-        ArrayList<String> res = new ArrayList<String>(5);
-        res.add(proj.getCacheDirectoryName()); // we should use non-localized projection name
+        ArrayList<String> res = new ArrayList<String>(7);
+        if (proj != null) {
+            res.add(proj.toCode());
+        } else {
+            res.add("");
+        }
         res.add(layerName);
         res.add(name);
Index: /trunk/src/org/openstreetmap/josm/data/projection/Lambert.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/projection/Lambert.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/data/projection/Lambert.java	(revision 3779)
@@ -5,4 +5,5 @@
 
 import java.awt.GridBagLayout;
+import java.awt.event.ActionListener;
 import java.io.IOException;
 import java.io.InputStream;
@@ -254,5 +255,6 @@
     };
 
-    public void setupPreferencePanel(JPanel p) {
+    @Override
+    public void setupPreferencePanel(JPanel p, ActionListener listener) {
         JComboBox prefcb = new JComboBox(lambert4zones);
 
@@ -265,4 +267,8 @@
         p.add(new JLabel(ImageProvider.get("data/projection", "Departements_Lambert4Zones.png")), GBC.eol().fill(GBC.HORIZONTAL));
         p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
+
+        if (listener != null) {
+            prefcb.addActionListener(listener);
+        }
     }
 
@@ -291,6 +297,15 @@
     }
 
+    @Override
+    public String[] allCodes() {
+        String[] zones = new String[4];
+        for (int zone = 0; zone < 4; zone++) {
+            zones[zone] = "EPSG:"+(27561+zone);
+        }
+        return zones;
+    }
+
     public Collection<String> getPreferencesFromCode(String code) {
-        if (code.startsWith("EPSG:2756") && code.length() == 9) {
+        if (code.startsWith("EPSG:2756") && code.length() == 10) {
             try {
                 String zonestring = code.substring(9);
Index: /trunk/src/org/openstreetmap/josm/data/projection/LambertCC9Zones.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/projection/LambertCC9Zones.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/data/projection/LambertCC9Zones.java	(revision 3779)
@@ -5,4 +5,5 @@
 
 import java.awt.GridBagLayout;
+import java.awt.event.ActionListener;
 import java.util.Collection;
 import java.util.Collections;
@@ -15,6 +16,4 @@
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.projection.Projection;
-import org.openstreetmap.josm.data.projection.Ellipsoid;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -186,5 +185,6 @@
     };
 
-    public void setupPreferencePanel(JPanel p) {
+    @Override
+    public void setupPreferencePanel(JPanel p, ActionListener listener) {
         JComboBox prefcb = new JComboBox(lambert9zones);
 
@@ -197,4 +197,8 @@
         p.add(new JLabel(ImageProvider.get("data/projection", "LambertCC9Zones.png")), GBC.eol().fill(GBC.HORIZONTAL));
         p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
+
+        if (listener != null) {
+            prefcb.addActionListener(listener);
+        }
     }
 
@@ -224,4 +228,13 @@
     }
 
+    @Override
+    public String[] allCodes() {
+        String[] zones = new String[9];
+        for (int zone = 0; zone < 9; zone++) {
+            zones[zone] = "EPSG:" + (3942 + zone);
+        }
+        return zones;
+    }
+
     public Collection<String> getPreferencesFromCode(String code)
     {
@@ -229,8 +242,8 @@
         if (code.startsWith("EPSG:39") && code.length() == 9) {
             try {
-                String zonestring = code.substring(5,4);
+                String zonestring = code.substring(5,9);
                 int zoneval = Integer.parseInt(zonestring)-3942;
                 if(zoneval >= 0 && zoneval <= 8)
-                    return Collections.singleton(zonestring);
+                    return Collections.singleton(String.valueOf(zoneval+1));
             } catch(NumberFormatException e) {}
         }
Index: /trunk/src/org/openstreetmap/josm/data/projection/ProjectionInfo.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/projection/ProjectionInfo.java	(revision 3779)
+++ /trunk/src/org/openstreetmap/josm/data/projection/ProjectionInfo.java	(revision 3779)
@@ -0,0 +1,55 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.projection;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collection;
+import java.util.HashMap;
+
+public class ProjectionInfo {
+    private static HashMap<String, Projection> allCodes;
+
+    private static ProjectionSubPrefs recreateProj(ProjectionSubPrefs proj) {
+        try {
+            return proj.getClass().newInstance();
+        } catch (Exception e) {
+            throw new IllegalStateException(
+                    tr("Cannot instantiate projection ''{0}''", proj.getClass().toString()), e);
+        }
+    }
+
+    static {
+        allCodes = new HashMap<String, Projection>();
+        for (Projection proj : Projection.allProjections) {
+            if (proj instanceof ProjectionSubPrefs) {
+                ProjectionSubPrefs projSub = recreateProj((ProjectionSubPrefs)proj);
+                for (String code : projSub.allCodes()) {
+                    allCodes.put(code, projSub);
+                }
+            } else {
+                allCodes.put(proj.toCode(), proj);
+            }
+        }
+    }
+
+    public static Projection getProjectionByCode(String code) {
+        Projection proj = allCodes.get(code);
+        if (proj == null) return null;
+        if (code.equals(proj.toCode())) return proj;
+        if (!(proj instanceof ProjectionSubPrefs))
+            throw new IllegalStateException(tr(
+                    "Projection code mismatch in '{0}': toCode() returns ''{1}'', expected ''{2}''",
+                    proj.getClass().toString(), proj.toCode(), code));
+        ProjectionSubPrefs projSub = recreateProj((ProjectionSubPrefs)proj);
+        Collection<String> prefs = projSub.getPreferencesFromCode(code);
+        if (prefs != null) {
+            projSub.setPreferences(prefs);
+        }
+        if (!code.equals(projSub.toCode()))
+            throw new IllegalStateException(tr(
+                    "Bad implementation of '{0}' projection class: cannot set preferences to match code ''{1}''",
+                    projSub.getClass().toString(), code));
+        allCodes.put(code, projSub);
+        return projSub;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/data/projection/ProjectionSubPrefs.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/projection/ProjectionSubPrefs.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/data/projection/ProjectionSubPrefs.java	(revision 3779)
@@ -2,14 +2,17 @@
 package org.openstreetmap.josm.data.projection;
 
+import java.awt.event.ActionListener;
 import java.util.Collection;
 
 import javax.swing.JPanel;
 
-public interface ProjectionSubPrefs {
+public interface ProjectionSubPrefs extends Projection {
     /**
      * Generates the GUI for the given preference and packs them in a JPanel
      * so they may be displayed if the projection is selected.
+     * 
+     * @param listener   listener for any change of preferences
      */
-    public void setupPreferencePanel(JPanel p);
+    public void setupPreferencePanel(JPanel p, ActionListener listener);
 
     /**
@@ -17,4 +20,9 @@
      */
     public Collection<String> getPreferences(JPanel p);
+
+    /**
+     * Return all projection codes supported by this projection class.
+     */
+    public String[] allCodes();
 
     /**
Index: /trunk/src/org/openstreetmap/josm/data/projection/Puwg.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/projection/Puwg.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/data/projection/Puwg.java	(revision 3779)
@@ -6,4 +6,5 @@
 
 import java.awt.GridBagLayout;
+import java.awt.event.ActionListener;
 import java.text.DecimalFormat;
 import java.util.Collection;
@@ -99,5 +100,5 @@
 
     @Override
-    public void setupPreferencePanel(JPanel p) {
+    public void setupPreferencePanel(JPanel p, ActionListener listener) {
         JComboBox prefcb = new JComboBox(Puwg.Zones);
 
@@ -109,4 +110,8 @@
         p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL));
         p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
+
+        if (listener != null) {
+            prefcb.addActionListener(listener);
+        }
     }
 
@@ -118,4 +123,13 @@
         int zone = ((JComboBox)prefcb).getSelectedIndex();
         return Collections.singleton((Puwg.Zones[zone]).toCode());
+    }
+
+    @Override
+    public String[] allCodes() {
+        String[] zones = new String[Zones.length];
+        for (int zone = 0; zone < Zones.length; zone++) {
+            zones[zone] = Zones[zone].toCode();
+        }
+        return zones;
     }
 
Index: /trunk/src/org/openstreetmap/josm/data/projection/SwissGrid.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/projection/SwissGrid.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/data/projection/SwissGrid.java	(revision 3779)
@@ -4,6 +4,8 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.event.ActionListener;
 import java.util.Collection;
 import java.util.Collections;
+
 import javax.swing.Box;
 import javax.swing.JPanel;
@@ -36,6 +38,6 @@
     private static final double b0 = Math.asin(Math.sin(phi0) / alpha);
     private static final double K = Math.log(Math.tan(Math.PI / 4 + b0 / 2)) - alpha
-            * Math.log(Math.tan(Math.PI / 4 + phi0 / 2)) + alpha * Ellipsoid.Bessel1841.e / 2
-            * Math.log((1 + Ellipsoid.Bessel1841.e * Math.sin(phi0)) / (1 - Ellipsoid.Bessel1841.e * Math.sin(phi0)));
+    * Math.log(Math.tan(Math.PI / 4 + phi0 / 2)) + alpha * Ellipsoid.Bessel1841.e / 2
+    * Math.log((1 + Ellipsoid.Bessel1841.e * Math.sin(phi0)) / (1 - Ellipsoid.Bessel1841.e * Math.sin(phi0)));
 
     private static final double xTrans = 200000;
@@ -71,5 +73,5 @@
 
         double S = alpha * Math.log(Math.tan(Math.PI / 4 + phi / 2)) - alpha * Ellipsoid.Bessel1841.e / 2
-                * Math.log((1 + Ellipsoid.Bessel1841.e * Math.sin(phi)) / (1 - Ellipsoid.Bessel1841.e * Math.sin(phi))) + K;
+        * Math.log((1 + Ellipsoid.Bessel1841.e * Math.sin(phi)) / (1 - Ellipsoid.Bessel1841.e * Math.sin(phi))) + K;
         double b = 2 * (Math.atan(Math.exp(S)) - Math.PI / 4);
         double l = alpha * (lambda - lambda0);
@@ -107,10 +109,9 @@
         // iteration to finds S and phi
         while (Math.abs(phi - prevPhi) > DELTA_PHI) {
-            if (++iteration > 30) {
+            if (++iteration > 30)
                 throw new RuntimeException("Two many iterations");
-            }
             prevPhi = phi;
             S = 1 / alpha * (Math.log(Math.tan(Math.PI / 4 + b / 2)) - K) + Ellipsoid.Bessel1841.e
-                    * Math.log(Math.tan(Math.PI / 4 + Math.asin(Ellipsoid.Bessel1841.e * Math.sin(phi)) / 2));
+            * Math.log(Math.tan(Math.PI / 4 + Math.asin(Ellipsoid.Bessel1841.e * Math.sin(phi)) / 2));
             phi = 2 * Math.atan(Math.exp(S)) - Math.PI / 2;
         }
@@ -152,5 +153,5 @@
 
     @Override
-    public void setupPreferencePanel(JPanel p) {
+    public void setupPreferencePanel(JPanel p, ActionListener listener) {
         p.add(new HtmlPanel("<i>CH1903 / LV03 (without local corrections)</i>"), GBC.eol().fill(GBC.HORIZONTAL));
         p.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
@@ -167,4 +168,9 @@
 
     @Override
+    public String[] allCodes() {
+        return new String[] { "EPSG:21781" };
+    }
+
+    @Override
     public Collection<String> getPreferencesFromCode(String code) {
         if ("EPSG:21781".equals(code))
Index: /trunk/src/org/openstreetmap/josm/data/projection/UTM.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/projection/UTM.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/data/projection/UTM.java	(revision 3779)
@@ -5,4 +5,6 @@
 
 import java.awt.GridBagLayout;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -112,5 +114,6 @@
     }
 
-    public void setupPreferencePanel(JPanel p) {
+    @Override
+    public void setupPreferencePanel(JPanel p, ActionListener listener) {
         //Zone
         JComboBox zonecb = new JComboBox();
@@ -161,4 +164,11 @@
         p.add(offsetBox, GBC.eop().fill(GBC.HORIZONTAL));
         p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
+
+        if (listener != null) {
+            north.addActionListener(listener);
+            south.addActionListener(listener);
+            zonecb.addActionListener(listener);
+            offsetBox.addActionListener(listener);
+        }
     }
 
@@ -214,4 +224,17 @@
         }
         updateParameters();
+    }
+
+    public String[] allCodes() {
+        ArrayList<String> projections = new ArrayList<String>(60*4);
+        for (int zone = 1;zone <= 60; zone++) {
+            for (boolean offset : new boolean[] { false, true }) {
+                for (Hemisphere hemisphere : Hemisphere.values()) {
+                    projections.add("EPSG:" + ((offset?325800:32600) + zone + (hemisphere == Hemisphere.South?100:0)));
+                }
+            }
+        }
+        return projections.toArray(new String[0]);
+
     }
 
Index: /trunk/src/org/openstreetmap/josm/data/projection/UTM_France_DOM.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/projection/UTM_France_DOM.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/data/projection/UTM_France_DOM.java	(revision 3779)
@@ -9,4 +9,5 @@
 
 import java.awt.GridBagLayout;
+import java.awt.event.ActionListener;
 import java.util.Collection;
 import java.util.Collections;
@@ -410,5 +411,6 @@
     }
 
-    public void setupPreferencePanel(JPanel p) {
+    @Override
+    public void setupPreferencePanel(JPanel p, ActionListener listener) {
         JComboBox prefcb = new JComboBox(utmGeodesicsNames);
 
@@ -419,4 +421,7 @@
         p.add(prefcb, GBC.eop().fill(GBC.HORIZONTAL));
         p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
+        if (listener != null) {
+            prefcb.addActionListener(listener);
+        }
     }
 
@@ -430,8 +435,13 @@
     }
 
+    @Override
+    public String[] allCodes() {
+        return utmEPSGs;
+    }
+
     public Collection<String> getPreferencesFromCode(String code) {
         for (int i=0; i < utmEPSGs.length; i++ )
             if (utmEPSGs[i].endsWith(code))
-                return Collections.singleton(Integer.toString(i));
+                return Collections.singleton(Integer.toString(i+1));
         return null;
     }
@@ -444,5 +454,5 @@
                 {
                     currentGeodesic = Integer.parseInt(s)-1;
-                    if(currentGeodesic < 0 || currentGeodesic > 4) {
+                    if(currentGeodesic < 0 || currentGeodesic >= utmEPSGs.length) {
                         currentGeodesic = DEFAULT_GEODESIC;
                     }
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java	(revision 3779)
@@ -708,4 +708,5 @@
                 switch (column) {
                 case 0:
+                    if (info.proj == null) return "";
                     return info.proj.toString();
                 case 1:
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java	(revision 3778)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java	(revision 3779)
@@ -228,17 +228,16 @@
     }
 
-    private class SBPanel extends JPanel
-    {
-        private Projection p;
-        public SBPanel(Projection pr)
+    private class SBPanel extends JPanel implements ActionListener
+    {
+        private ProjectionSubPrefs p;
+        public SBPanel(ProjectionSubPrefs pr)
         {
             super();
             p = pr;
         }
+
         @Override
-        public void paint(java.awt.Graphics g)
-        {
-            super.paint(g);
-            ((ProjectionSubPrefs) p).setPreferences(((ProjectionSubPrefs) p).getPreferences(this));
+        public void actionPerformed(ActionEvent e) {
+            p.setPreferences(p.getPreferences(this));
             updateMeta(p);
         }
@@ -255,6 +254,6 @@
         } else {
             ProjectionSubPrefs projPref = (ProjectionSubPrefs) proj;
-            projSubPrefPanel = new SBPanel(proj);
-            projPref.setupPreferencePanel(projSubPrefPanel);
+            projSubPrefPanel = new SBPanel(projPref);
+            projPref.setupPreferencePanel(projSubPrefPanel, (SBPanel)projSubPrefPanel);
         }
 
