Index: trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- trunk/src/org/openstreetmap/josm/Main.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/Main.java	(revision 12735)
@@ -34,5 +34,7 @@
 import org.openstreetmap.josm.data.UndoRedoHandler;
 import org.openstreetmap.josm.data.cache.JCSCacheManager;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
+import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.ICoordinateFormat;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -724,10 +726,9 @@
     public static void preConstructorInit() {
         // init default coordinate format
-        try {
-            CoordinateFormat.setCoordinateFormat(CoordinateFormat.valueOf(Main.pref.get("coordinates")));
-        } catch (IllegalArgumentException iae) {
-            Logging.trace(iae);
-            CoordinateFormat.setCoordinateFormat(CoordinateFormat.DECIMAL_DEGREES);
-        }
+        ICoordinateFormat fmt = CoordinateFormatManager.getCoordinateFormat(Main.pref.get("coordinates"));
+        if (fmt == null) {
+            fmt = DecimalDegreesCoordinateFormat.INSTANCE;
+        }
+        CoordinateFormatManager.setCoordinateFormat(fmt);
     }
 
Index: trunk/src/org/openstreetmap/josm/data/coor/CoordinateFormat.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/CoordinateFormat.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/data/coor/CoordinateFormat.java	(revision 12735)
@@ -4,8 +4,17 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
+import org.openstreetmap.josm.data.coor.conversion.DMSCoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.ICoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.NauticalCoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.ProjectedCoordinateFormat;
+
 /**
  * An enumeration  of coordinate formats
  * @since 1990
+ * @deprecated use {@link CoordinateFormatManager}
  */
+@Deprecated
 public enum CoordinateFormat {
 
@@ -13,25 +22,27 @@
      * the decimal format 999.999
      */
-    DECIMAL_DEGREES(tr("Decimal Degrees")),
+    DECIMAL_DEGREES(tr("Decimal Degrees"), DecimalDegreesCoordinateFormat.INSTANCE),
 
     /**
      * the degrees/minutes/seconds format 9 deg 99 min 99 sec
      */
-    DEGREES_MINUTES_SECONDS(tr("deg\u00B0 min'' sec\"")),
+    DEGREES_MINUTES_SECONDS(tr("deg\u00B0 min'' sec\""), DMSCoordinateFormat.INSTANCE),
 
     /**
      * the nautical format
      */
-    NAUTICAL(tr("deg\u00B0 min'' (Nautical)")),
+    NAUTICAL(tr("deg\u00B0 min'' (Nautical)"), NauticalCoordinateFormat.INSTANCE),
 
     /**
      * coordinates East/North
      */
-    EAST_NORTH(tr("Projected Coordinates"));
+    EAST_NORTH(tr("Projected Coordinates"), ProjectedCoordinateFormat.INSTANCE);
 
     private final String displayName;
+    private final ICoordinateFormat migration;
 
-    CoordinateFormat(String displayName) {
+    CoordinateFormat(String displayName, ICoordinateFormat migration) {
         this.displayName = displayName;
+        this.migration = migration;
     }
 
@@ -43,4 +54,14 @@
     public String getDisplayName() {
         return displayName;
+    }
+
+    /**
+     * Returns the corresponding {@link ICoordinateFormat} instance for
+     * migration.
+     * @return the corresponding {@link ICoordinateFormat} instance for
+     * migration
+     */
+    public ICoordinateFormat getICoordinateFormat() {
+        return migration;
     }
 
Index: trunk/src/org/openstreetmap/josm/data/coor/LatLon.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 12735)
@@ -25,4 +25,7 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.conversion.DMSCoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.NauticalCoordinateFormat;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
@@ -69,9 +72,4 @@
     public static final LatLon SOUTH_POLE = new LatLon(-90, 0);
 
-    private static DecimalFormat cDmsMinuteFormatter = new DecimalFormat("00");
-    private static DecimalFormat cDmsSecondFormatter = new DecimalFormat(
-            Main.pref == null ? "00.0" : Main.pref.get("latlon.dms.decimal-format", "00.0"));
-    private static DecimalFormat cDmMinuteFormatter = new DecimalFormat(
-            Main.pref == null ? "00.000" : Main.pref.get("latlon.dm.decimal-format", "00.000"));
     /**
      * The normal number format for server precision coordinates
@@ -90,9 +88,4 @@
         cDdHighPecisionFormatter.applyPattern("###0.0##########");
     }
-
-    private static final String cDms60 = cDmsSecondFormatter.format(60.0);
-    private static final String cDms00 = cDmsSecondFormatter.format(0.0);
-    private static final String cDm60 = cDmMinuteFormatter.format(60.0);
-    private static final String cDm00 = cDmMinuteFormatter.format(0.0);
 
     /** Character denoting South, as string */
@@ -217,27 +210,9 @@
      * @return The coordinate in degrees/minutes/seconds format
      * @since 12561
-     */
+     * @deprecated use {@link DMSCoordinateFormat#degreesMinutesSeconds(double)}
+     */
+    @Deprecated
     public static String degreesMinutesSeconds(double pCoordinate) {
-
-        double tAbsCoord = Math.abs(pCoordinate);
-        int tDegree = (int) tAbsCoord;
-        double tTmpMinutes = (tAbsCoord - tDegree) * 60;
-        int tMinutes = (int) tTmpMinutes;
-        double tSeconds = (tTmpMinutes - tMinutes) * 60;
-
-        String sDegrees = Integer.toString(tDegree);
-        String sMinutes = cDmsMinuteFormatter.format(tMinutes);
-        String sSeconds = cDmsSecondFormatter.format(tSeconds);
-
-        if (cDms60.equals(sSeconds)) {
-            sSeconds = cDms00;
-            sMinutes = cDmsMinuteFormatter.format(tMinutes+1L);
-        }
-        if ("60".equals(sMinutes)) {
-            sMinutes = "00";
-            sDegrees = Integer.toString(tDegree+1);
-        }
-
-        return sDegrees + '\u00B0' + sMinutes + '\'' + sSeconds + '\"';
+        return DMSCoordinateFormat.degreesMinutesSeconds(pCoordinate);
     }
 
@@ -247,20 +222,9 @@
      * @return The coordinate in degrees/minutes format
      * @since 12537
-     */
+     * @deprecated use {@link NauticalCoordinateFormat#degreesMinutes(double)}
+     */
+    @Deprecated
     public static String degreesMinutes(double pCoordinate) {
-
-        double tAbsCoord = Math.abs(pCoordinate);
-        int tDegree = (int) tAbsCoord;
-        double tMinutes = (tAbsCoord - tDegree) * 60;
-
-        String sDegrees = Integer.toString(tDegree);
-        String sMinutes = cDmMinuteFormatter.format(tMinutes);
-
-        if (sMinutes.equals(cDm60)) {
-            sMinutes = cDm00;
-            sDegrees = Integer.toString(tDegree+1);
-        }
-
-        return sDegrees + '\u00B0' + sMinutes + '\'';
+        return NauticalCoordinateFormat.degreesMinutes(pCoordinate);
     }
 
@@ -302,13 +266,9 @@
      * @param d the coordinate format to use
      * @return the formatted latitude
-     */
+     * @deprecated use {@link org.openstreetmap.josm.data.coor.format.ICoordinateFormat#latToString(ILatLon)
+     */
+    @Deprecated
     public String latToString(CoordinateFormat d) {
-        switch(d) {
-        case DECIMAL_DEGREES: return cDdFormatter.format(y);
-        case DEGREES_MINUTES_SECONDS: return degreesMinutesSeconds(y) + ((y < 0) ? SOUTH : NORTH);
-        case NAUTICAL: return degreesMinutes(y) + ((y < 0) ? SOUTH : NORTH);
-        case EAST_NORTH: return cDdFormatter.format(this.getEastNorth(Main.getProjection()).north());
-        default: return "ERR";
-        }
+        return d.getICoordinateFormat().latToString(this);
     }
 
@@ -322,13 +282,9 @@
      * @param d the coordinate format to use
      * @return the formatted longitude
-     */
+     * @deprecated use {@link org.openstreetmap.josm.data.coor.format.ICoordinateFormat#lonToString(ILatLon)
+     */
+    @Deprecated
     public String lonToString(CoordinateFormat d) {
-        switch(d) {
-        case DECIMAL_DEGREES: return cDdFormatter.format(x);
-        case DEGREES_MINUTES_SECONDS: return degreesMinutesSeconds(x) + ((x < 0) ? WEST : EAST);
-        case NAUTICAL: return degreesMinutes(x) + ((x < 0) ? WEST : EAST);
-        case EAST_NORTH: return cDdFormatter.format(this.getEastNorth(Main.getProjection()).east());
-        default: return "ERR";
-        }
+        return d.getICoordinateFormat().lonToString(this);
     }
 
@@ -469,6 +425,6 @@
     public String toStringCSV(String separator) {
         return Utils.join(separator, Arrays.asList(
-                latToString(CoordinateFormat.DECIMAL_DEGREES),
-                lonToString(CoordinateFormat.DECIMAL_DEGREES)
+                DecimalDegreesCoordinateFormat.INSTANCE.latToString(this),
+                DecimalDegreesCoordinateFormat.INSTANCE.lonToString(this)
         ));
     }
Index: trunk/src/org/openstreetmap/josm/data/coor/conversion/AbstractCoordinateFormat.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/conversion/AbstractCoordinateFormat.java	(revision 12735)
+++ trunk/src/org/openstreetmap/josm/data/coor/conversion/AbstractCoordinateFormat.java	(revision 12735)
@@ -0,0 +1,58 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.coor.conversion;
+
+import static org.openstreetmap.josm.tools.I18n.trc;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+/**
+ * Abstract base class for {@link ICoordinateFormat} implementations.
+ * @since 12735
+ */
+public abstract class AbstractCoordinateFormat implements ICoordinateFormat {
+
+    protected final String id;
+    protected final String displayName;
+
+    /**
+     * The normal number format for server precision coordinates
+     */
+    protected static final DecimalFormat cDdFormatter;
+    static {
+        // Don't use the localized decimal separator. This way we can present
+        // a comma separated list of coordinates.
+        cDdFormatter = (DecimalFormat) NumberFormat.getInstance(Locale.UK);
+        cDdFormatter.applyPattern("###0.0######");
+    }
+
+    /** Character denoting South, as string */
+    protected static final String SOUTH = trc("compass", "S");
+    /** Character denoting North, as string */
+    protected static final String NORTH = trc("compass", "N");
+    /** Character denoting West, as string */
+    protected static final String WEST = trc("compass", "W");
+    /** Character denoting East, as string */
+    protected static final String EAST = trc("compass", "E");
+
+    protected AbstractCoordinateFormat(String id, String displayName) {
+        this.id = id;
+        this.displayName = displayName;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    @Override
+    public String toString() {
+        return getDisplayName();
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/coor/conversion/CoordinateFormatManager.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/conversion/CoordinateFormatManager.java	(revision 12735)
+++ trunk/src/org/openstreetmap/josm/data/coor/conversion/CoordinateFormatManager.java	(revision 12735)
@@ -0,0 +1,76 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.coor.conversion;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * Class that manages the available coordinate formats.
+ * @since 12735
+ */
+public class CoordinateFormatManager {
+
+    private final static List<ICoordinateFormat> formats = new ArrayList<>();
+
+    static {
+        registerCoordinateFormat(DecimalDegreesCoordinateFormat.INSTANCE);
+        registerCoordinateFormat(DMSCoordinateFormat.INSTANCE);
+        registerCoordinateFormat(NauticalCoordinateFormat.INSTANCE);
+        registerCoordinateFormat(ProjectedCoordinateFormat.INSTANCE);
+    }
+
+    /**
+     * Register a coordinate format.
+     * <p>
+     * It will be available as a choice in the preferences.
+     * @param format the coordinate format
+     */
+    public static void registerCoordinateFormat(ICoordinateFormat format) {
+        formats.add(format);
+    }
+
+    /**
+     * Get the list of all registered coordinate formats.
+     * @return the list of all registered coordinate formats
+     */
+    public static List<ICoordinateFormat> getCoordinateFormats() {
+        return Collections.unmodifiableList(formats);
+    }
+
+    private static volatile ICoordinateFormat defaultCoordinateFormat = DecimalDegreesCoordinateFormat.INSTANCE;
+
+    /**
+     * Replies the default coordinate format to be use
+     *
+     * @return the default coordinate format
+     */
+    public static ICoordinateFormat getDefaultFormat() {
+        return defaultCoordinateFormat;
+    }
+
+    /**
+     * Sets the default coordinate format
+     *
+     * @param format the default coordinate format
+     */
+    public static void setCoordinateFormat(ICoordinateFormat format) {
+        if (format != null) {
+            defaultCoordinateFormat = format;
+        }
+    }
+
+    /**
+     * Get registered coordinate format by id
+     *
+     * @param id id of the coordinate format to get
+     * @return the registered {@link ICoordinateFormat} with given id, or <code>null</code>
+     * if no match is found
+     */
+    public static ICoordinateFormat getCoordinateFormat(String id) {
+        CheckParameterUtil.ensureParameterNotNull(id, "id");
+        return formats.stream().filter(format -> id.equals(format.getId())).findFirst().orElse(null);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/coor/conversion/DMSCoordinateFormat.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/conversion/DMSCoordinateFormat.java	(revision 12735)
+++ trunk/src/org/openstreetmap/josm/data/coor/conversion/DMSCoordinateFormat.java	(revision 12735)
@@ -0,0 +1,69 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.coor.conversion;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.text.DecimalFormat;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.ILatLon;
+
+/**
+ * Coordinate format that converts a coordinate to degrees, minutes and seconds.
+ * @since 12735
+ */
+public class DMSCoordinateFormat extends AbstractCoordinateFormat {
+
+    private static final DecimalFormat DMS_MINUTE_FORMATTER = new DecimalFormat("00");
+    private static final DecimalFormat DMS_SECOND_FORMATTER = new DecimalFormat(
+            Main.pref == null ? "00.0" : Main.pref.get("latlon.dms.decimal-format", "00.0"));
+    private static final String DMS60 = DMS_SECOND_FORMATTER.format(60.0);
+    private static final String DMS00 = DMS_SECOND_FORMATTER.format(0.0);
+
+    public static DMSCoordinateFormat INSTANCE = new DMSCoordinateFormat();
+
+    private DMSCoordinateFormat() {
+        super("DEGREES_MINUTES_SECONDS", tr("deg\u00B0 min'' sec\""));
+    }
+
+    @Override
+    public String latToString(ILatLon ll) {
+        return degreesMinutesSeconds(ll.lat()) + ((ll.lat() < 0) ? SOUTH : NORTH);
+    }
+
+    @Override
+    public String lonToString(ILatLon ll) {
+       return degreesMinutesSeconds(ll.lon()) + ((ll.lon() < 0) ? WEST : EAST);
+    }
+
+    /**
+     * Replies the coordinate in degrees/minutes/seconds format
+     * @param pCoordinate The coordinate to convert
+     * @return The coordinate in degrees/minutes/seconds format
+     * @since 12561
+     */
+    public static String degreesMinutesSeconds(double pCoordinate) {
+
+        double tAbsCoord = Math.abs(pCoordinate);
+        int tDegree = (int) tAbsCoord;
+        double tTmpMinutes = (tAbsCoord - tDegree) * 60;
+        int tMinutes = (int) tTmpMinutes;
+        double tSeconds = (tTmpMinutes - tMinutes) * 60;
+
+        String sDegrees = Integer.toString(tDegree);
+        String sMinutes = DMS_MINUTE_FORMATTER.format(tMinutes);
+        String sSeconds = DMS_SECOND_FORMATTER.format(tSeconds);
+
+        if (DMS60.equals(sSeconds)) {
+            sSeconds = DMS00;
+            sMinutes = DMS_MINUTE_FORMATTER.format(tMinutes+1L);
+        }
+        if ("60".equals(sMinutes)) {
+            sMinutes = "00";
+            sDegrees = Integer.toString(tDegree+1);
+        }
+
+        return sDegrees + '\u00B0' + sMinutes + '\'' + sSeconds + '\"';
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/data/coor/conversion/DecimalDegreesCoordinateFormat.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/conversion/DecimalDegreesCoordinateFormat.java	(revision 12735)
+++ trunk/src/org/openstreetmap/josm/data/coor/conversion/DecimalDegreesCoordinateFormat.java	(revision 12735)
@@ -0,0 +1,29 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.coor.conversion;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import org.openstreetmap.josm.data.coor.ILatLon;
+
+/**
+ * Coordinate format that converts coordinates to simple floating point decimal format.
+ * @since 12735
+ */
+public class DecimalDegreesCoordinateFormat extends AbstractCoordinateFormat {
+
+    public static DecimalDegreesCoordinateFormat INSTANCE = new DecimalDegreesCoordinateFormat();
+
+    private DecimalDegreesCoordinateFormat() {
+        super("DECIMAL_DEGREES", tr("Decimal Degrees"));
+    }
+
+    @Override
+    public String latToString(ILatLon ll) {
+        return cDdFormatter.format(ll.lat());
+    }
+
+    @Override
+    public String lonToString(ILatLon ll) {
+        return cDdFormatter.format(ll.lon());
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/coor/conversion/ICoordinateFormat.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/conversion/ICoordinateFormat.java	(revision 12735)
+++ trunk/src/org/openstreetmap/josm/data/coor/conversion/ICoordinateFormat.java	(revision 12735)
@@ -0,0 +1,37 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.coor.conversion;
+
+import org.openstreetmap.josm.data.coor.ILatLon;
+
+/**
+ * A class that converts lat/lon coordinates to string.
+ *
+ * @since 12735
+ */
+public interface ICoordinateFormat {
+    /**
+     * Get unique id for this coordinate format.
+     * @return unique id
+     */
+    String getId();
+
+    /**
+     * Get display name for this coordinate format
+     * @return display name (localized)
+     */
+    String getDisplayName();
+
+    /**
+     * Convert latitude to string.
+     * @param ll the coordinate
+     * @return formatted latitude
+     */
+    String latToString(ILatLon ll);
+
+    /**
+     * Convert longitude to string.
+     * @param ll the coordinate
+     * @return formatted longitude
+     */
+    String lonToString(ILatLon ll);
+}
Index: trunk/src/org/openstreetmap/josm/data/coor/conversion/NauticalCoordinateFormat.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/conversion/NauticalCoordinateFormat.java	(revision 12735)
+++ trunk/src/org/openstreetmap/josm/data/coor/conversion/NauticalCoordinateFormat.java	(revision 12735)
@@ -0,0 +1,59 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.coor.conversion;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.text.DecimalFormat;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.ILatLon;
+
+/**
+ * Coordinate format that converts a coordinate to degrees and minutes (nautical format).
+ * @since 12735
+ */
+public class NauticalCoordinateFormat extends AbstractCoordinateFormat {
+    private static final DecimalFormat DM_MINUTE_FORMATTER = new DecimalFormat(
+            Main.pref == null ? "00.000" : Main.pref.get("latlon.dm.decimal-format", "00.000"));
+    private static final String DM60 = DM_MINUTE_FORMATTER.format(60.0);
+    private static final String DM00 = DM_MINUTE_FORMATTER.format(0.0);
+
+    public static NauticalCoordinateFormat INSTANCE = new NauticalCoordinateFormat();
+
+    private NauticalCoordinateFormat() {
+        super("NAUTICAL", tr("deg\u00B0 min'' (Nautical)"));
+    }
+
+    @Override
+    public String latToString(ILatLon ll) {
+        return degreesMinutes(ll.lat()) + ((ll.lat() < 0) ? SOUTH : NORTH);
+    }
+
+    @Override
+    public String lonToString(ILatLon ll) {
+        return degreesMinutes(ll.lon()) + ((ll.lon() < 0) ? WEST : EAST);
+    }
+
+    /**
+     * Replies the coordinate in degrees/minutes format
+     * @param pCoordinate The coordinate to convert
+     * @return The coordinate in degrees/minutes format
+     * @since 12537
+     */
+    public static String degreesMinutes(double pCoordinate) {
+
+        double tAbsCoord = Math.abs(pCoordinate);
+        int tDegree = (int) tAbsCoord;
+        double tMinutes = (tAbsCoord - tDegree) * 60;
+
+        String sDegrees = Integer.toString(tDegree);
+        String sMinutes = DM_MINUTE_FORMATTER.format(tMinutes);
+
+        if (sMinutes.equals(DM60)) {
+            sMinutes = DM00;
+            sDegrees = Integer.toString(tDegree+1);
+        }
+
+        return sDegrees + '\u00B0' + sMinutes + '\'';
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/coor/conversion/ProjectedCoordinateFormat.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/conversion/ProjectedCoordinateFormat.java	(revision 12735)
+++ trunk/src/org/openstreetmap/josm/data/coor/conversion/ProjectedCoordinateFormat.java	(revision 12735)
@@ -0,0 +1,31 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.coor.conversion;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.ILatLon;
+
+/**
+ * Coordinate format that projects a coordinate and returns northing and easting in
+ * decimal format.
+ * @since 12735
+ */
+public class ProjectedCoordinateFormat extends AbstractCoordinateFormat {
+
+    public static ProjectedCoordinateFormat INSTANCE = new ProjectedCoordinateFormat();
+
+    private ProjectedCoordinateFormat() {
+        super("EAST_NORTH", tr("Projected Coordinates"));
+    }
+
+    @Override
+    public String latToString(ILatLon ll) {
+        return cDdFormatter.format(ll.getEastNorth(Main.getProjection()).north());
+    }
+
+    @Override
+    public String lonToString(ILatLon ll) {
+        return cDdFormatter.format(ll.getEastNorth(Main.getProjection()).east());
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/DefaultNameFormatter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DefaultNameFormatter.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/data/osm/DefaultNameFormatter.java	(revision 12735)
@@ -22,6 +22,6 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
 import org.openstreetmap.josm.data.osm.history.HistoryNameFormatter;
 import org.openstreetmap.josm.data.osm.history.HistoryNode;
@@ -187,6 +187,6 @@
             }
             if (node.getCoor() != null) {
-                name.append(" \u200E(").append(node.getCoor().latToString(CoordinateFormat.getDefaultFormat())).append(", ")
-                    .append(node.getCoor().lonToString(CoordinateFormat.getDefaultFormat())).append(')');
+                name.append(" \u200E(").append(CoordinateFormatManager.getDefaultFormat().latToString(node)).append(", ")
+                    .append(CoordinateFormatManager.getDefaultFormat().lonToString(node)).append(')');
             }
         }
@@ -541,7 +541,7 @@
         if (coord != null) {
             sb.append(" (")
-            .append(coord.latToString(CoordinateFormat.getDefaultFormat()))
+            .append(CoordinateFormatManager.getDefaultFormat().latToString(coord))
             .append(", ")
-            .append(coord.lonToString(CoordinateFormat.getDefaultFormat()))
+            .append(CoordinateFormatManager.getDefaultFormat().lonToString(coord))
             .append(')');
         }
Index: trunk/src/org/openstreetmap/josm/gui/MapStatus.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 12735)
@@ -60,6 +60,9 @@
 import org.openstreetmap.josm.data.SystemOfMeasurement;
 import org.openstreetmap.josm.data.SystemOfMeasurement.SoMChangeListener;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
+import org.openstreetmap.josm.data.coor.conversion.DMSCoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.ICoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.ProjectedCoordinateFormat;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
@@ -210,10 +213,10 @@
     }
 
-    /** The {@link CoordinateFormat} set in the previous update */
-    private transient CoordinateFormat previousCoordinateFormat;
+    /** The {@link ICoordinateFormat} set in the previous update */
+    private transient ICoordinateFormat previousCoordinateFormat;
     private final ImageLabel latText = new ImageLabel("lat",
-            null, LatLon.SOUTH_POLE.latToString(CoordinateFormat.DEGREES_MINUTES_SECONDS).length(), PROP_BACKGROUND_COLOR.get());
+            null, DMSCoordinateFormat.INSTANCE.latToString(LatLon.SOUTH_POLE).length(), PROP_BACKGROUND_COLOR.get());
     private final ImageLabel lonText = new ImageLabel("lon",
-            null, new LatLon(0, 180).lonToString(CoordinateFormat.DEGREES_MINUTES_SECONDS).length(), PROP_BACKGROUND_COLOR.get());
+            null, DMSCoordinateFormat.INSTANCE.lonToString(new LatLon(0, 180)).length(), PROP_BACKGROUND_COLOR.get());
     private final ImageLabel headingText = new ImageLabel("heading",
             tr("The (compass) heading of the line segment being drawn."),
@@ -763,5 +766,5 @@
         /** Icons for selecting {@link SystemOfMeasurement} */
         private final Collection<JCheckBoxMenuItem> somItems = new ArrayList<>();
-        /** Icons for selecting {@link CoordinateFormat}  */
+        /** Icons for selecting {@link ICoordinateFormat}  */
         private final Collection<JCheckBoxMenuItem> coordinateFormatItems = new ArrayList<>();
 
@@ -787,9 +790,9 @@
                 add(item);
             }
-            for (final CoordinateFormat format : CoordinateFormat.values()) {
+            for (final ICoordinateFormat format : CoordinateFormatManager.getCoordinateFormats()) {
                 JCheckBoxMenuItem item = new JCheckBoxMenuItem(new AbstractAction(format.getDisplayName()) {
                     @Override
                     public void actionPerformed(ActionEvent e) {
-                        CoordinateFormat.setCoordinateFormat(format);
+                        CoordinateFormatManager.setCoordinateFormat(format);
                     }
                 });
@@ -811,5 +814,5 @@
                         item.setVisible(distText.equals(invoker));
                     }
-                    final String currentCorrdinateFormat = CoordinateFormat.getDefaultFormat().getDisplayName();
+                    final String currentCorrdinateFormat = CoordinateFormatManager.getDefaultFormat().getDisplayName();
                     for (JMenuItem item : coordinateFormatItems) {
                         item.setSelected(currentCorrdinateFormat.equals(item.getText()));
@@ -873,11 +876,11 @@
                 // Do not update the view if ctrl is pressed.
                 if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == 0) {
-                    CoordinateFormat mCord = CoordinateFormat.getDefaultFormat();
+                    ICoordinateFormat mCord = CoordinateFormatManager.getDefaultFormat();
                     LatLon p = mv.getLatLon(e.getX(), e.getY());
-                    latText.setText(p.latToString(mCord));
-                    lonText.setText(p.lonToString(mCord));
+                    latText.setText(mCord.latToString(p));
+                    lonText.setText(mCord.lonToString(p));
                     if (Objects.equals(previousCoordinateFormat, mCord)) {
                         // do nothing
-                    } else if (CoordinateFormat.EAST_NORTH.equals(mCord)) {
+                    } else if (ProjectedCoordinateFormat.INSTANCE.equals(mCord)) {
                         latText.setIcon("northing");
                         lonText.setIcon("easting");
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/LatLonDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/LatLonDialog.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/LatLonDialog.java	(revision 12735)
@@ -24,7 +24,7 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.util.WindowGeometry;
@@ -191,6 +191,6 @@
     public void setCoordinates(LatLon ll) {
         LatLon llc = Optional.ofNullable(ll).orElse(LatLon.ZERO);
-        tfLatLon.setText(llc.latToString(CoordinateFormat.getDefaultFormat()) + ' ' +
-                         llc.lonToString(CoordinateFormat.getDefaultFormat()));
+        tfLatLon.setText(CoordinateFormatManager.getDefaultFormat().latToString(llc) + ' ' +
+                         CoordinateFormatManager.getDefaultFormat().lonToString(llc));
         EastNorth en = Main.getProjection().latlon2eastNorth(llc);
         tfEastNorth.setText(Double.toString(en.east()) + ' ' + Double.toString(en.north()));
Index: trunk/src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java	(revision 12735)
@@ -25,6 +25,6 @@
 
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
 import org.openstreetmap.josm.gui.widgets.JosmTextArea;
 import org.openstreetmap.josm.gui.widgets.JosmTextField;
@@ -163,8 +163,8 @@
     private void updateBboxFields(Bounds area) {
         if (area == null) return;
-        latlon[0].setText(area.getMin().latToString(CoordinateFormat.DECIMAL_DEGREES));
-        latlon[1].setText(area.getMin().lonToString(CoordinateFormat.DECIMAL_DEGREES));
-        latlon[2].setText(area.getMax().latToString(CoordinateFormat.DECIMAL_DEGREES));
-        latlon[3].setText(area.getMax().lonToString(CoordinateFormat.DECIMAL_DEGREES));
+        latlon[0].setText(DecimalDegreesCoordinateFormat.INSTANCE.latToString(area.getMin()));
+        latlon[1].setText(DecimalDegreesCoordinateFormat.INSTANCE.lonToString(area.getMin()));
+        latlon[2].setText(DecimalDegreesCoordinateFormat.INSTANCE.latToString(area.getMax()));
+        latlon[3].setText(DecimalDegreesCoordinateFormat.INSTANCE.lonToString(area.getMax()));
         for (JosmTextField tf: latlon) {
             resetErrorMessage(tf);
Index: trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java	(revision 12735)
@@ -20,6 +20,6 @@
 import org.openstreetmap.gui.jmapviewer.MapMarkerDot;
 import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
 import org.openstreetmap.josm.data.osm.history.HistoryNode;
 import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
@@ -308,6 +308,6 @@
 
             // display the coordinates
-            lblLat.setText(coord != null ? coord.latToString(CoordinateFormat.DECIMAL_DEGREES) : tr("(none)"));
-            lblLon.setText(coord != null ? coord.lonToString(CoordinateFormat.DECIMAL_DEGREES) : tr("(none)"));
+            lblLat.setText(coord != null ? DecimalDegreesCoordinateFormat.INSTANCE.latToString(coord) : tr("(none)"));
+            lblLon.setText(coord != null ? DecimalDegreesCoordinateFormat.INSTANCE.lonToString(coord) : tr("(none)"));
 
             // update background color to reflect differences in the coordinates
Index: trunk/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java	(revision 12735)
@@ -26,5 +26,6 @@
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.SystemOfMeasurement;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
+import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
+import org.openstreetmap.josm.data.coor.conversion.ICoordinateFormat;
 import org.openstreetmap.josm.data.preferences.CollectionProperty;
 import org.openstreetmap.josm.data.preferences.StringProperty;
@@ -288,11 +289,10 @@
      * Combobox with all projections available
      */
-    private final JosmComboBox<ProjectionChoice> projectionCombo = new JosmComboBox<>(
-            projectionChoices.toArray(new ProjectionChoice[projectionChoices.size()]));
+    private final JosmComboBox<ProjectionChoice> projectionCombo;
 
     /**
      * Combobox with all coordinate display possibilities
      */
-    private final JosmComboBox<CoordinateFormat> coordinatesCombo = new JosmComboBox<>(CoordinateFormat.values());
+    private final JosmComboBox<ICoordinateFormat> coordinatesCombo;
 
     private final JosmComboBox<String> unitsCombo = new JosmComboBox<>(unitsValuesTr);
@@ -326,4 +326,11 @@
     private static final GBC projSubPrefPanelGBC = GBC.std().fill(GBC.BOTH).weight(1.0, 1.0);
 
+    public ProjectionPreference() {
+        this.projectionCombo = new JosmComboBox<>(
+            projectionChoices.toArray(new ProjectionChoice[projectionChoices.size()]));
+        this.coordinatesCombo = new JosmComboBox<>(
+                CoordinateFormatManager.getCoordinateFormats().toArray(new ICoordinateFormat[0]));
+    }
+
     @Override
     public void addGui(PreferenceTabbedPane gui) {
@@ -331,5 +338,5 @@
 
         for (int i = 0; i < coordinatesCombo.getItemCount(); ++i) {
-            if (coordinatesCombo.getItemAt(i).name().equals(PROP_COORDINATES.get())) {
+            if (coordinatesCombo.getItemAt(i).getId().equals(PROP_COORDINATES.get())) {
                 coordinatesCombo.setSelectedIndex(i);
                 break;
@@ -399,7 +406,7 @@
         projectionName.setText(proj.toString());
         Bounds b = proj.getWorldBoundsLatLon();
-        CoordinateFormat cf = CoordinateFormat.getDefaultFormat();
-        bounds.setText(b.getMin().lonToString(cf) + ", " + b.getMin().latToString(cf) + " : " +
-                b.getMax().lonToString(cf) + ", " + b.getMax().latToString(cf));
+        ICoordinateFormat cf = CoordinateFormatManager.getDefaultFormat();
+        bounds.setText(cf.lonToString(b.getMin()) + ", " + cf.latToString(b.getMin()) + " : " +
+                cf.lonToString(b.getMax()) + ", " + cf.latToString(b.getMax()));
         boolean showCode = true;
         boolean showName = false;
@@ -425,6 +432,6 @@
         setProjection(id, prefs, false);
 
-        if (PROP_COORDINATES.put(((CoordinateFormat) coordinatesCombo.getSelectedItem()).name())) {
-            CoordinateFormat.setCoordinateFormat((CoordinateFormat) coordinatesCombo.getSelectedItem());
+        if (PROP_COORDINATES.put(((ICoordinateFormat) coordinatesCombo.getSelectedItem()).getId())) {
+            CoordinateFormatManager.setCoordinateFormat((ICoordinateFormat) coordinatesCombo.getSelectedItem());
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/widgets/BoundingBoxSelectionPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/widgets/BoundingBoxSelectionPanel.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/gui/widgets/BoundingBoxSelectionPanel.java	(revision 12735)
@@ -17,6 +17,6 @@
 
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.OsmUrlToBounds;
@@ -125,8 +125,8 @@
     private void updateBboxFields(Bounds area) {
         if (area == null) return;
-        tfLatLon[0].setText(area.getMin().latToString(CoordinateFormat.DECIMAL_DEGREES));
-        tfLatLon[1].setText(area.getMin().lonToString(CoordinateFormat.DECIMAL_DEGREES));
-        tfLatLon[2].setText(area.getMax().latToString(CoordinateFormat.DECIMAL_DEGREES));
-        tfLatLon[3].setText(area.getMax().lonToString(CoordinateFormat.DECIMAL_DEGREES));
+        tfLatLon[0].setText(DecimalDegreesCoordinateFormat.INSTANCE.latToString(area.getMin()));
+        tfLatLon[1].setText(DecimalDegreesCoordinateFormat.INSTANCE.lonToString(area.getMin()));
+        tfLatLon[2].setText(DecimalDegreesCoordinateFormat.INSTANCE.latToString(area.getMax()));
+        tfLatLon[3].setText(DecimalDegreesCoordinateFormat.INSTANCE.lonToString(area.getMax()));
     }
 
Index: trunk/src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 12734)
+++ trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 12735)
@@ -13,6 +13,6 @@
 
 import org.openstreetmap.josm.data.DataSource;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
 import org.openstreetmap.josm.data.osm.AbstractPrimitive;
 import org.openstreetmap.josm.data.osm.Changeset;
@@ -194,11 +194,11 @@
         for (DataSource s : ds.getDataSources()) {
             out.println("  <bounds minlat='"
-                    + s.bounds.getMin().latToString(CoordinateFormat.DECIMAL_DEGREES)
+                    + DecimalDegreesCoordinateFormat.INSTANCE.latToString(s.bounds.getMin())
                     +"' minlon='"
-                    + s.bounds.getMin().lonToString(CoordinateFormat.DECIMAL_DEGREES)
+                    + DecimalDegreesCoordinateFormat.INSTANCE.lonToString(s.bounds.getMin())
                     +"' maxlat='"
-                    + s.bounds.getMax().latToString(CoordinateFormat.DECIMAL_DEGREES)
+                    + DecimalDegreesCoordinateFormat.INSTANCE.latToString(s.bounds.getMax())
                     +"' maxlon='"
-                    + s.bounds.getMax().lonToString(CoordinateFormat.DECIMAL_DEGREES)
+                    + DecimalDegreesCoordinateFormat.INSTANCE.lonToString(s.bounds.getMax())
                     +"' origin='"+XmlWriter.encode(s.origin)+"' />");
         }
@@ -273,10 +273,10 @@
         out.print(" open='"+ (cs.isOpen() ? "true" : "false") +'\'');
         if (cs.getMin() != null) {
-            out.print(" min_lon='"+ cs.getMin().lonToString(CoordinateFormat.DECIMAL_DEGREES) +'\'');
-            out.print(" min_lat='"+ cs.getMin().latToString(CoordinateFormat.DECIMAL_DEGREES) +'\'');
+            out.print(" min_lon='"+ DecimalDegreesCoordinateFormat.INSTANCE.lonToString(cs.getMin()) +'\'');
+            out.print(" min_lat='"+ DecimalDegreesCoordinateFormat.INSTANCE.latToString(cs.getMin()) +'\'');
         }
         if (cs.getMax() != null) {
-            out.print(" max_lon='"+ cs.getMin().lonToString(CoordinateFormat.DECIMAL_DEGREES) +'\'');
-            out.print(" max_lat='"+ cs.getMin().latToString(CoordinateFormat.DECIMAL_DEGREES) +'\'');
+            out.print(" max_lon='"+ DecimalDegreesCoordinateFormat.INSTANCE.lonToString(cs.getMin()) +'\'');
+            out.print(" max_lat='"+ DecimalDegreesCoordinateFormat.INSTANCE.latToString(cs.getMin()) +'\'');
         }
         out.println(">");
