Index: src/org/openstreetmap/josm/gui/dialogs/LatLonDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/LatLonDialog.java	(revision 3648)
+++ src/org/openstreetmap/josm/gui/dialogs/LatLonDialog.java	(working copy)
@@ -16,7 +16,11 @@
 import java.awt.event.WindowEvent;
 import java.text.NumberFormat;
 import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
@@ -44,8 +48,8 @@
 public class LatLonDialog extends JDialog {
     private static final Color BG_COLOR_ERROR = new Color(255,224,224);
 
-    private JTextField tfLat;
-    private JTextField tfLon;
+    private JTextField tfLatLon;
+//    private JTextField tfLon;
     private String help;
     private boolean canceled = false;
     private LatLon coordinates;
@@ -56,29 +60,29 @@
         JPanel pnl = new JPanel(new GridBagLayout());
         pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
         pnl.add(new JLabel("<html>"+
-                tr("Enter the coordinates for the new node.") +
+                tr("Enter the coordinates for the new node.") /*+
                 "<br>" + tr("Use decimal degrees.") +
-                "<br>" + tr("Negative values denote Western/Southern hemisphere.")),
+                "<br>" + tr("Negative values denote Western/Southern hemisphere.")*/),
                 GBC.eol());
 
-        pnl.add(new JLabel(tr("Latitude")), GBC.std().insets(0,10,5,0));
-        tfLat = new JTextField(12);
-        pnl.add(tfLat, GBC.eol().insets(0,10,0,0));
-        pnl.add(new JLabel(tr("Longitude")), GBC.std().insets(0,0,5,10));
-        tfLon = new JTextField(12);
-        pnl.add(tfLon, GBC.eol().insets(0,0,0,10));
+        pnl.add(new JLabel(tr("Coordinates")), GBC.std().insets(0,10,5,0));
+        tfLatLon = new JTextField(24);
+        pnl.add(tfLatLon, GBC.eol().insets(0,10,0,0));
+//        pnl.add(new JLabel(tr("Longitude")), GBC.std().insets(0,0,5,10));
+//        tfLon = new JTextField(12);
+//        pnl.add(tfLon, GBC.eol().insets(0,0,0,10));
 
         // parse and verify input on the fly
         //
         LatLonInputVerifier inputVerifier = new LatLonInputVerifier();
-        tfLat.getDocument().addDocumentListener(inputVerifier);
-        tfLon.getDocument().addDocumentListener(inputVerifier);
+        tfLatLon.getDocument().addDocumentListener(inputVerifier);
+//        tfLon.getDocument().addDocumentListener(inputVerifier);
 
         // select the text in the field on focus
         //
         TextFieldFocusHandler focusHandler = new TextFieldFocusHandler();
-        tfLat.addFocusListener(focusHandler);
-        tfLon.addFocusListener(focusHandler);
+        tfLatLon.addFocusListener(focusHandler);
+//        tfLon.addFocusListener(focusHandler);
         return pnl;
     }
 
@@ -130,8 +134,8 @@
             coordinates = new LatLon(0,0);
         }
         this.coordinates = coordinates;
-        tfLat.setText(coordinates.latToString(CoordinateFormat.DECIMAL_DEGREES));
-        tfLon.setText(coordinates.lonToString(CoordinateFormat.DECIMAL_DEGREES));
+        tfLatLon.setText(coordinates.latToString(CoordinateFormat.DEGREES_MINUTES_SECONDS) + " " + coordinates.lonToString(CoordinateFormat.DEGREES_MINUTES_SECONDS));
+//        tfLon.setText(coordinates.lonToString(CoordinateFormat.DECIMAL_DEGREES));
         actOK.setEnabled(true);
     }
 
@@ -176,36 +180,35 @@
         return n== null ? null : n.doubleValue();
     }
 
-    protected Double parseLatFromUserInput() {
-        Double d = parseDoubleFromUserInput(tfLat.getText());
-        if (d == null || ! LatLon.isValidLat(d)) {
-            setErrorFeedback(tfLat, tr("Please enter a valid latitude in the range -90..90"));
-            return null;
-        } else {
-            clearErrorFeedback(tfLat,tr("Please enter a latitude in the range -90..90"));
-        }
-        return d;
-    }
 
-    protected Double parseLonFromUserInput() {
-        Double d = parseDoubleFromUserInput(tfLon.getText());
-        if (d == null || ! LatLon.isValidLon(d)) {
-            setErrorFeedback(tfLon, tr("Please enter a valid longitude in the range -180..180"));
-            return null;
-        } else {
-            clearErrorFeedback(tfLon,tr("Please enter a longitude in the range -180..180"));
-        }
-        return d;
-    }
+//    protected Double parseLonFromUserInput() {
+//        Double d = parseDoubleFromUserInput(tfLon.getText());
+//        if (d == null || ! LatLon.isValidLon(d)) {
+//            setErrorFeedback(tfLon, tr("Please enter a valid longitude in the range -180..180"));
+//            return null;
+//        } else {
+//            clearErrorFeedback(tfLon,tr("Please enter a longitude in the range -180..180"));
+//        }
+//        return d;
+//    }
 
     protected void parseUserInput() {
-        Double lat = parseLatFromUserInput();
-        Double lon = parseLonFromUserInput();
-        if (lat == null || lon == null) {
+        LatLon latLon;
+        try {
+            latLon = parse(tfLatLon.getText());
+            if (!LatLon.isValidLat(latLon.lat()) || !LatLon.isValidLon(latLon.lon())) {
+                latLon = null;
+            }
+        } catch (IllegalArgumentException e) {
+            latLon = null;
+        }
+        if (latLon == null) {
+            setErrorFeedback(tfLatLon, tr("Please enter a GPS coordinates"));
             coordinates = null;
             actOK.setEnabled(false);
         } else {
-            coordinates = new LatLon(lat,lon);
+            clearErrorFeedback(tfLatLon,tr("Please enter a GPS coordinates"));
+            coordinates = latLon;
             actOK.setEnabled(true);
         }
     }
@@ -287,8 +290,148 @@
 
         @Override
         public void windowOpened(WindowEvent e) {
-            tfLat.requestFocusInWindow();
+            tfLatLon.requestFocusInWindow();
         }
     }
 
+
+
+
+
+
+
+
+
+    private static final double ZERO = 0.0;
+
+    private static final Pattern p = Pattern.compile("([+|-]?\\d+\\.\\d*)|([+|-]?\\d+)|(°|o|deg)|('|′|min)|(\"|″|sec)|(,|;)|([NSEW])|\\s+|(.+)", Pattern.CASE_INSENSITIVE);
+
+
+    private static LatLon parse(final String coord) {
+//        System.out.println("=======================");
+//        System.out.println("Input: " + coord);
+
+        final Matcher m = p.matcher(coord);
+
+        final StringBuilder sb = new StringBuilder();
+        final List<Object> list = new ArrayList<Object>();
+
+        while (m.find()) {
+            if (m.group(1) != null) {
+                sb.append('R');
+                list.add(Double.parseDouble(m.group(1)));
+            } else if (m.group(2) != null) {
+                sb.append('Z');
+                list.add(Double.parseDouble(m.group(2)));
+            } else if (m.group(3) != null) {
+                sb.append('°');
+            } else if (m.group(4) != null) {
+                sb.append('\'');
+            } else if (m.group(5) != null) {
+                sb.append('"');
+            } else if (m.group(6) != null) {
+                sb.append(',');
+            } else if (m.group(7) != null) {
+                sb.append("x");
+                list.add(m.group(7).toUpperCase());
+            } else if (m.group(8) != null) {
+                throw new IllegalArgumentException("invalid token: " + m.group(8));
+            }
+        }
+
+        final String pattern = sb.toString();
+
+//        System.out.println("Pattern: " + sb.toString());
+
+        final Object[] params = list.toArray();
+        final LatLonHolder latLon = new LatLonHolder();
+
+        if (pattern.matches("R°?,?R°?")) {
+            setLatLon(latLon,
+                    params[0], ZERO, ZERO, "N",
+                    params[1], ZERO, ZERO, "E");
+        } else if (pattern.matches("xR°?,?xR°?")) {
+            setLatLon(latLon,
+                    params[1], ZERO, ZERO, params[0],
+                    params[3], ZERO, ZERO, params[2]);
+        } else if (pattern.matches("R°?x,?R°?x")) {
+            setLatLon(latLon,
+                    params[0], ZERO, ZERO, params[1],
+                    params[2], ZERO, ZERO, params[3]);
+        } else if (pattern.matches("Z°[RZ]'?,?Z°[RZ]'?")) {
+            setLatLon(latLon,
+                    params[0], params[1], ZERO, "N",
+                    params[2], params[3], ZERO, "E");
+        } else if (pattern.matches("Z[RZ],?Z[RZ]")) {
+            setLatLon(latLon,
+                    params[0], params[1], ZERO, "N",
+                    params[2], params[3], ZERO, "E");
+        } else if (pattern.matches("xZ°[RZ]'?,?xZ°[RZ]'?|xZ°?[RZ],?xZ°?[RZ]")) {
+            setLatLon(latLon,
+                    params[1], params[2], ZERO, params[0],
+                    params[4], params[5], ZERO, params[3]);
+        } else if (pattern.matches("Z°[RZ]'?x,?Z°[RZ]'?x|Z°?[RZ]x,?Z°?[RZ]x")) {
+            setLatLon(latLon,
+                    params[0], params[1], ZERO, params[2],
+                    params[3], params[4], ZERO, params[5]);
+        } else if (pattern.matches("Z°Z'[RZ]\"?x,?Z°Z'[RZ]\"?x|ZZ[RZ]x,?ZZ[RZ]x")) {
+            setLatLon(latLon,
+                    params[0], params[1], params[2], params[3],
+                    params[4], params[5], params[6], params[7]);
+        } else if (pattern.matches("xZ°Z'[RZ]\"?,?xZ°Z'[RZ]\"?|xZZ[RZ],?xZZ[RZ]")) {
+            setLatLon(latLon,
+                    params[1], params[2], params[3], params[0],
+                    params[5], params[6], params[7], params[4]);
+        } else if (pattern.matches("ZZ[RZ],?ZZ[RZ]")) {
+            setLatLon(latLon,
+                    params[0], params[1], params[2], "N",
+                    params[3], params[4], params[5], "E");
+        } else {
+            throw new IllegalArgumentException("invalid format: " + pattern);
+        }
+
+        return new LatLon(latLon.lat, latLon.lon);
+    }
+
+
+    private static class LatLonHolder {
+        double lat, lon;
+    }
+
+
+    private static void setLatLon(final LatLonHolder latLon,
+            final Object coord1deg, final Object coord1min, final Object coord1sec, final Object card1,
+            final Object coord2deg, final Object coord2min, final Object coord2sec, final Object card2) {
+
+        setLatLon(latLon,
+                (double) (Double) coord1deg, (double) (Double) coord1min, (double) (Double) coord1sec, (String) card1,
+                (double) (Double) coord2deg, (double) (Double) coord2min, (double) (Double) coord2sec, (String) card2);
+    }
+
+
+    private static void setLatLon(final LatLonHolder latLon,
+            final double coord1deg, final double coord1min, final double coord1sec, final String card1,
+            final double coord2deg, final double coord2min, final double coord2sec, final String card2) {
+
+        setLatLon(latLon, coord1deg, coord1min, coord1sec, card1);
+        setLatLon(latLon, coord2deg, coord2min, coord2sec, card2);
+    }
+
+
+    private static void setLatLon(final LatLonHolder latLon, final double coordDeg, final double coordMin, final double coordSec, final String card) {
+        if (coordDeg < -180 || coordDeg > 180 || coordMin < 0 || coordMin >= 60 || coordSec < 0 || coordSec > 60) {
+            throw new IllegalArgumentException("out of range");
+        }
+
+        double coord = Math.signum(coordDeg) * (Math.abs(coordDeg) + coordMin / 60 + coordSec / 3600);
+        coord = card.equals("N") || card.equals("E") ? coord : -coord;
+        if (card.equals("N") || card.equals("S")) {
+            latLon.lat = coord;
+        } else {
+            latLon.lon = coord;
+        }
+    }
+
+
+
 }
