Index: trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 5869)
+++ trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 5870)
@@ -1236,8 +1236,19 @@
      */
     public static class SystemOfMeasurement {
+        
+        /** First value, in meters, used to translate unit according to above formula. */
         public final double aValue;
+        /** Second value, in meters, used to translate unit according to above formula. */
         public final double bValue;
+        /** First unit used to format text. */
         public final String aName;
+        /** Second unit used to format text. */
         public final String bName;
+        /** Specific optional area value, in squared meters, between {@code aValue*aValue} and {@code bValue*bValue}. Set to {@code -1} if not used.
+         *  @since 5870 */
+        public final double areaCustomValue;
+        /** Specific optional area unit. Set to {@code null} if not used. 
+         *  @since 5870 */
+        public final String areaCustomName;
 
         /**
@@ -1246,10 +1257,37 @@
          * If a quantity x is given in m (x_m) and in unit a (x_a) then it translates as
          * x_a == x_m / aValue
+         * 
+         * @param aValue First value, in meters, used to translate unit according to above formula.
+         * @param aName First unit used to format text.
+         * @param bValue Second value, in meters, used to translate unit according to above formula.
+         * @param bName Second unit used to format text.
          */
         public SystemOfMeasurement(double aValue, String aName, double bValue, String bName) {
+            this(aValue, aName, bValue, bName, -1, null);
+        }
+        
+        /**
+         * System of measurement. Currently covers only length (and area) units.
+         *
+         * If a quantity x is given in m (x_m) and in unit a (x_a) then it translates as
+         * x_a == x_m / aValue
+         * 
+         * @param aValue First value, in meters, used to translate unit according to above formula.
+         * @param aName First unit used to format text.
+         * @param bValue Second value, in meters, used to translate unit according to above formula.
+         * @param bName Second unit used to format text.
+         * @param areaCustomValue Specific optional area value, in squared meters, between {@code aValue*aValue} and {@code bValue*bValue}. 
+         *                        Set to {@code -1} if not used.
+         * @param areaCustomName Specific optional area unit. Set to {@code null} if not used.
+         * 
+         * @since 5870
+         */
+        public SystemOfMeasurement(double aValue, String aName, double bValue, String bName, double areaCustomValue, String areaCustomName) {
             this.aValue = aValue;
             this.aName = aName;
             this.bValue = bValue;
             this.bName = bName;
+            this.areaCustomValue = areaCustomValue;
+            this.areaCustomName = areaCustomName;
         }
 
@@ -1261,11 +1299,10 @@
         public String getDistText(double dist) {
             double a = dist / aValue;
-            if (!Main.pref.getBoolean("system_of_measurement.use_only_lower_unit", false) && a > bValue / aValue) {
-                double b = dist / bValue;
-                return String.format(Locale.US, "%." + (b<10 ? 2 : 1) + "f %s", b, bName);
-            } else if (a < 0.01)
+            if (!Main.pref.getBoolean("system_of_measurement.use_only_lower_unit", false) && a > bValue / aValue)
+                return formatText(dist / bValue, bName);
+            else if (a < 0.01)
                 return "< 0.01 " + aName;
             else
-                return String.format(Locale.US, "%." + (a<10 ? 2 : 1) + "f %s", a, aName);
+                return formatText(a, aName);
         }
 
@@ -1278,11 +1315,17 @@
         public String getAreaText(double area) {
             double a = area / (aValue*aValue);
-            if (!Main.pref.getBoolean("system_of_measurement.use_only_lower_unit", false) && a > bValue / aValue) {
-                double b = area / (bValue*bValue);
-                return String.format(Locale.US, "%." + (b<10 ? 2 : 1) + "f %s", b, bName+"\u00b2");
-            } else if (a < 0.01)
-                return "< 0.01 " + aName;
+            boolean lowerOnly = Main.pref.getBoolean("system_of_measurement.use_only_lower_unit", false);
+            if (!lowerOnly && areaCustomValue > 0 && a > areaCustomValue / aValue*aValue && a < bValue*bValue / aValue*aValue)
+                return formatText(area / areaCustomValue, areaCustomName);
+            else if (!lowerOnly && a >= bValue*bValue / aValue*aValue)
+                return formatText(area / (bValue*bValue), bName+"\u00b2");
+            else if (a < 0.01)
+                return "< 0.01 " + aName+"\u00b2";
             else
-                return String.format(Locale.US, "%." + (a<10 ? 2 : 1) + "f %s", a, aName+"\u00b2");
+                return formatText(a, aName+"\u00b2");
+        }
+        
+        private static String formatText(double v, String unit) {
+            return String.format(Locale.US, "%." + (v<9.999999 ? 2 : 1) + "f %s", v, unit);
         }
     }
@@ -1292,5 +1335,5 @@
      * @since 3406
      */
-    public static final SystemOfMeasurement METRIC_SOM = new SystemOfMeasurement(1, "m", 1000, "km");
+    public static final SystemOfMeasurement METRIC_SOM = new SystemOfMeasurement(1, "m", 1000, "km", 10000, "ha");
     
     /**
Index: trunk/test/unit/org/openstreetmap/josm/gui/SystemOfMeasurementTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/SystemOfMeasurementTest.java	(revision 5870)
+++ trunk/test/unit/org/openstreetmap/josm/gui/SystemOfMeasurementTest.java	(revision 5870)
@@ -0,0 +1,112 @@
+package org.openstreetmap.josm.gui;
+
+import static org.junit.Assert.*;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.gui.NavigatableComponent.SystemOfMeasurement;
+
+/**
+ * Unit tests of {@link SystemOfMeasurement} class.
+ */
+public class SystemOfMeasurementTest {
+
+    /**
+     * Setup test.
+     */
+    @BeforeClass
+    public static void setUp() {
+        Main.pref = new Preferences();
+    }
+    
+    /**
+     * Test of {@link SystemOfMeasurement#getDistText} method.
+     */
+    @Test
+    public void testGetDistText() {
+        
+        assertEquals("< 0.01 m", NavigatableComponent.METRIC_SOM.getDistText(-1));
+        assertEquals("< 0.01 m", NavigatableComponent.METRIC_SOM.getDistText(-0.99));
+        assertEquals("< 0.01 m", NavigatableComponent.METRIC_SOM.getDistText(-0));
+        assertEquals("< 0.01 m", NavigatableComponent.METRIC_SOM.getDistText(0));
+
+        assertEquals("0.01 m", NavigatableComponent.METRIC_SOM.getDistText(0.01));
+        
+        assertEquals("0.99 m", NavigatableComponent.METRIC_SOM.getDistText(0.99));
+        assertEquals("1.00 m", NavigatableComponent.METRIC_SOM.getDistText(1.0));
+        assertEquals("1.01 m", NavigatableComponent.METRIC_SOM.getDistText(1.01));
+
+        assertEquals("9.99 m", NavigatableComponent.METRIC_SOM.getDistText(9.99));
+        assertEquals("10.0 m", NavigatableComponent.METRIC_SOM.getDistText(10.0));
+        assertEquals("10.0 m", NavigatableComponent.METRIC_SOM.getDistText(10.01));
+        assertEquals("10.0 m", NavigatableComponent.METRIC_SOM.getDistText(10.049));
+        assertEquals("10.1 m", NavigatableComponent.METRIC_SOM.getDistText(10.050));
+        assertEquals("10.1 m", NavigatableComponent.METRIC_SOM.getDistText(10.051));
+
+        assertEquals("100.0 m", NavigatableComponent.METRIC_SOM.getDistText(99.99));
+        assertEquals("100.0 m", NavigatableComponent.METRIC_SOM.getDistText(100.0));
+        assertEquals("100.0 m", NavigatableComponent.METRIC_SOM.getDistText(100.01));
+
+        assertEquals("1000.0 m", NavigatableComponent.METRIC_SOM.getDistText(999.99)); // TODO ? 1.00 km should be better
+        assertEquals("1000.0 m", NavigatableComponent.METRIC_SOM.getDistText(1000.0)); // TODO ? 1.00 km should be better
+        assertEquals("1.00 km", NavigatableComponent.METRIC_SOM.getDistText(1000.01));
+
+        assertEquals("10.00 km", NavigatableComponent.METRIC_SOM.getDistText(9999.99)); // TODO ? 10.0 km should be better
+        assertEquals("10.0 km", NavigatableComponent.METRIC_SOM.getDistText(10000.0));
+        assertEquals("10.0 km", NavigatableComponent.METRIC_SOM.getDistText(10000.01));
+
+        assertEquals("100.0 km", NavigatableComponent.METRIC_SOM.getDistText(99999.99));
+        assertEquals("100.0 km", NavigatableComponent.METRIC_SOM.getDistText(100000.0));
+        assertEquals("100.0 km", NavigatableComponent.METRIC_SOM.getDistText(100000.01));
+    }
+
+    /**
+     * Test of {@link SystemOfMeasurement#getAreaText} method.
+     */
+    @Test
+    public void testGetAreaText() {
+        assertEquals("< 0.01 m²", NavigatableComponent.METRIC_SOM.getAreaText(-1));
+        assertEquals("< 0.01 m²", NavigatableComponent.METRIC_SOM.getAreaText(-0.99));
+        assertEquals("< 0.01 m²", NavigatableComponent.METRIC_SOM.getAreaText(-0));
+        assertEquals("< 0.01 m²", NavigatableComponent.METRIC_SOM.getAreaText(0));
+
+        assertEquals("0.01 m²", NavigatableComponent.METRIC_SOM.getAreaText(0.01));
+        
+        assertEquals("0.99 m²", NavigatableComponent.METRIC_SOM.getAreaText(0.99));
+        assertEquals("1.00 m²", NavigatableComponent.METRIC_SOM.getAreaText(1.0));
+        assertEquals("1.01 m²", NavigatableComponent.METRIC_SOM.getAreaText(1.01));
+
+        assertEquals("9.99 m²", NavigatableComponent.METRIC_SOM.getAreaText(9.99));
+        assertEquals("10.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(10.0));
+        assertEquals("10.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(10.01));
+        assertEquals("10.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(10.049));
+        assertEquals("10.1 m²", NavigatableComponent.METRIC_SOM.getAreaText(10.050));
+        assertEquals("10.1 m²", NavigatableComponent.METRIC_SOM.getAreaText(10.051));
+
+        assertEquals("100.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(99.99));
+        assertEquals("100.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(100.0));
+        assertEquals("100.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(100.01));
+
+        assertEquals("1000.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(999.99));
+        assertEquals("1000.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(1000.0));
+        assertEquals("1000.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(1000.01));
+
+        assertEquals("10000.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(9999.99)); // TODO ? 1.00 ha should be better
+        assertEquals("10000.0 m²", NavigatableComponent.METRIC_SOM.getAreaText(10000.0)); // TODO ? 1.00 ha should be better
+        assertEquals("1.00 ha", NavigatableComponent.METRIC_SOM.getAreaText(10000.01));
+
+        assertEquals("10.0 ha", NavigatableComponent.METRIC_SOM.getAreaText(99999.99));
+        assertEquals("10.0 ha", NavigatableComponent.METRIC_SOM.getAreaText(100000.0));
+        assertEquals("10.0 ha", NavigatableComponent.METRIC_SOM.getAreaText(100000.01));
+
+        assertEquals("100.0 ha", NavigatableComponent.METRIC_SOM.getAreaText(999999.99)); // TODO ? 1.00 km² should be better
+        assertEquals("1.00 km²", NavigatableComponent.METRIC_SOM.getAreaText(1000000.0));
+        assertEquals("1.00 km²", NavigatableComponent.METRIC_SOM.getAreaText(1000000.01));
+
+        assertEquals("10.0 km²", NavigatableComponent.METRIC_SOM.getAreaText(9999999.99));
+        assertEquals("10.0 km²", NavigatableComponent.METRIC_SOM.getAreaText(10000000.0));
+        assertEquals("10.0 km²", NavigatableComponent.METRIC_SOM.getAreaText(10000000.01));
+    }
+}
