Ticket #5604: LatLonDialog.java.2.patch

File LatLonDialog.java.2.patch, 10.6 KB (added by *Martin*, 14 years ago)

FIXED PATCH (v2)

  • src/org/openstreetmap/josm/gui/dialogs/LatLonDialog.java

     
    1616import java.awt.event.WindowEvent;
    1717import java.text.NumberFormat;
    1818import java.text.ParsePosition;
     19import java.util.ArrayList;
     20import java.util.List;
    1921import java.util.Locale;
     22import java.util.regex.Matcher;
     23import java.util.regex.Pattern;
    2024
    2125import javax.swing.AbstractAction;
    2226import javax.swing.BorderFactory;
     
    4448public class LatLonDialog extends JDialog {
    4549    private static final Color BG_COLOR_ERROR = new Color(255,224,224);
    4650
    47     private JTextField tfLat;
    48     private JTextField tfLon;
     51    private JTextField tfLatLon;
    4952    private String help;
    5053    private boolean canceled = false;
    5154    private LatLon coordinates;
     
    5659        JPanel pnl = new JPanel(new GridBagLayout());
    5760        pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    5861        pnl.add(new JLabel("<html>"+
    59                 tr("Enter the coordinates for the new node.") +
    60                 "<br>" + tr("Use decimal degrees.") +
    61                 "<br>" + tr("Negative values denote Western/Southern hemisphere.")),
     62                tr("Enter the coordinates for the new node.")),
    6263                GBC.eol());
    6364
    64         pnl.add(new JLabel(tr("Latitude")), GBC.std().insets(0,10,5,0));
    65         tfLat = new JTextField(12);
    66         pnl.add(tfLat, GBC.eol().insets(0,10,0,0));
    67         pnl.add(new JLabel(tr("Longitude")), GBC.std().insets(0,0,5,10));
    68         tfLon = new JTextField(12);
    69         pnl.add(tfLon, GBC.eol().insets(0,0,0,10));
     65        pnl.add(new JLabel(tr("Coordinates")), GBC.std().insets(0,10,5,0));
     66        tfLatLon = new JTextField(24);
     67        pnl.add(tfLatLon, GBC.eol().insets(0,10,0,0));
    7068
    7169        // parse and verify input on the fly
    7270        //
    7371        LatLonInputVerifier inputVerifier = new LatLonInputVerifier();
    74         tfLat.getDocument().addDocumentListener(inputVerifier);
    75         tfLon.getDocument().addDocumentListener(inputVerifier);
     72        tfLatLon.getDocument().addDocumentListener(inputVerifier);
    7673
    7774        // select the text in the field on focus
    7875        //
    7976        TextFieldFocusHandler focusHandler = new TextFieldFocusHandler();
    80         tfLat.addFocusListener(focusHandler);
    81         tfLon.addFocusListener(focusHandler);
     77        tfLatLon.addFocusListener(focusHandler);
    8278        return pnl;
    8379    }
    8480
     
    130126            coordinates = new LatLon(0,0);
    131127        }
    132128        this.coordinates = coordinates;
    133         tfLat.setText(coordinates.latToString(CoordinateFormat.DECIMAL_DEGREES));
    134         tfLon.setText(coordinates.lonToString(CoordinateFormat.DECIMAL_DEGREES));
     129        tfLatLon.setText(coordinates.latToString(CoordinateFormat.DEGREES_MINUTES_SECONDS) + " " + coordinates.lonToString(CoordinateFormat.DEGREES_MINUTES_SECONDS));
    135130        actOK.setEnabled(true);
    136131    }
    137132
     
    176171        return n== null ? null : n.doubleValue();
    177172    }
    178173
    179     protected Double parseLatFromUserInput() {
    180         Double d = parseDoubleFromUserInput(tfLat.getText());
    181         if (d == null || ! LatLon.isValidLat(d)) {
    182             setErrorFeedback(tfLat, tr("Please enter a valid latitude in the range -90..90"));
    183             return null;
    184         } else {
    185             clearErrorFeedback(tfLat,tr("Please enter a latitude in the range -90..90"));
     174    protected void parseUserInput() {
     175        LatLon latLon;
     176        try {
     177            latLon = parse(tfLatLon.getText());
     178            if (!LatLon.isValidLat(latLon.lat()) || !LatLon.isValidLon(latLon.lon())) {
     179                latLon = null;
     180            }
     181        } catch (IllegalArgumentException e) {
     182            latLon = null;
    186183        }
    187         return d;
    188     }
    189 
    190     protected Double parseLonFromUserInput() {
    191         Double d = parseDoubleFromUserInput(tfLon.getText());
    192         if (d == null || ! LatLon.isValidLon(d)) {
    193             setErrorFeedback(tfLon, tr("Please enter a valid longitude in the range -180..180"));
    194             return null;
    195         } else {
    196             clearErrorFeedback(tfLon,tr("Please enter a longitude in the range -180..180"));
    197         }
    198         return d;
    199     }
    200 
    201     protected void parseUserInput() {
    202         Double lat = parseLatFromUserInput();
    203         Double lon = parseLonFromUserInput();
    204         if (lat == null || lon == null) {
     184        if (latLon == null) {
     185            setErrorFeedback(tfLatLon, tr("Please enter a GPS coordinates"));
    205186            coordinates = null;
    206187            actOK.setEnabled(false);
    207188        } else {
    208             coordinates = new LatLon(lat,lon);
     189            clearErrorFeedback(tfLatLon,tr("Please enter a GPS coordinates"));
     190            coordinates = latLon;
    209191            actOK.setEnabled(true);
    210192        }
    211193    }
     
    287269
    288270        @Override
    289271        public void windowOpened(WindowEvent e) {
    290             tfLat.requestFocusInWindow();
     272            tfLatLon.requestFocusInWindow();
    291273        }
    292274    }
    293275
     276
     277
     278    private static final double ZERO = 0.0;
     279
     280    private static final Pattern p = Pattern.compile("([+|-]?\\d+\\.\\d*)|([+|-]?\\d+)|(°|o|deg)|('|′|min)|(\"|″|sec)|(,|;)|([NSEW])|\\s+|(.+)", Pattern.CASE_INSENSITIVE);
     281
     282
     283    private static LatLon parse(final String coord) {
     284        final Matcher m = p.matcher(coord);
     285
     286        final StringBuilder sb = new StringBuilder();
     287        final List<Object> list = new ArrayList<Object>();
     288
     289        while (m.find()) {
     290            if (m.group(1) != null) {
     291                sb.append('R');
     292                list.add(Double.parseDouble(m.group(1)));
     293            } else if (m.group(2) != null) {
     294                sb.append('Z');
     295                list.add(Double.parseDouble(m.group(2)));
     296            } else if (m.group(3) != null) {
     297                sb.append('°');
     298            } else if (m.group(4) != null) {
     299                sb.append('\'');
     300            } else if (m.group(5) != null) {
     301                sb.append('"');
     302            } else if (m.group(6) != null) {
     303                sb.append(',');
     304            } else if (m.group(7) != null) {
     305                sb.append("x");
     306                list.add(m.group(7).toUpperCase());
     307            } else if (m.group(8) != null) {
     308                throw new IllegalArgumentException("invalid token: " + m.group(8));
     309            }
     310        }
     311
     312        final String pattern = sb.toString();
     313
     314        final Object[] params = list.toArray();
     315        final LatLonHolder latLon = new LatLonHolder();
     316
     317        if (pattern.matches("R°?,?R°?")) {
     318            setLatLon(latLon,
     319                    params[0], ZERO, ZERO, "N",
     320                    params[1], ZERO, ZERO, "E");
     321        } else if (pattern.matches("xR°?,?xR°?")) {
     322            setLatLon(latLon,
     323                    params[1], ZERO, ZERO, params[0],
     324                    params[3], ZERO, ZERO, params[2]);
     325        } else if (pattern.matches("R°?x,?R°?x")) {
     326            setLatLon(latLon,
     327                    params[0], ZERO, ZERO, params[1],
     328                    params[2], ZERO, ZERO, params[3]);
     329        } else if (pattern.matches("Z°[RZ]'?,?Z°[RZ]'?|Z[RZ],?Z[RZ]")) {
     330            setLatLon(latLon,
     331                    params[0], params[1], ZERO, "N",
     332                    params[2], params[3], ZERO, "E");
     333        } else if (pattern.matches("xZ°[RZ]'?,?xZ°[RZ]'?|xZ°?[RZ],?xZ°?[RZ]")) {
     334            setLatLon(latLon,
     335                    params[1], params[2], ZERO, params[0],
     336                    params[4], params[5], ZERO, params[3]);
     337        } else if (pattern.matches("Z°[RZ]'?x,?Z°[RZ]'?x|Z°?[RZ]x,?Z°?[RZ]x")) {
     338            setLatLon(latLon,
     339                    params[0], params[1], ZERO, params[2],
     340                    params[3], params[4], ZERO, params[5]);
     341        } else if (pattern.matches("Z°Z'[RZ]\"?x,?Z°Z'[RZ]\"?x|ZZ[RZ]x,?ZZ[RZ]x")) {
     342            setLatLon(latLon,
     343                    params[0], params[1], params[2], params[3],
     344                    params[4], params[5], params[6], params[7]);
     345        } else if (pattern.matches("xZ°Z'[RZ]\"?,?xZ°Z'[RZ]\"?|xZZ[RZ],?xZZ[RZ]")) {
     346            setLatLon(latLon,
     347                    params[1], params[2], params[3], params[0],
     348                    params[5], params[6], params[7], params[4]);
     349        } else if (pattern.matches("ZZ[RZ],?ZZ[RZ]")) {
     350            setLatLon(latLon,
     351                    params[0], params[1], params[2], "N",
     352                    params[3], params[4], params[5], "E");
     353        } else {
     354            throw new IllegalArgumentException("invalid format: " + pattern);
     355        }
     356
     357        return new LatLon(latLon.lat, latLon.lon);
     358    }
     359
     360
     361    private static class LatLonHolder {
     362        double lat, lon;
     363    }
     364
     365
     366    private static void setLatLon(final LatLonHolder latLon,
     367            final Object coord1deg, final Object coord1min, final Object coord1sec, final Object card1,
     368            final Object coord2deg, final Object coord2min, final Object coord2sec, final Object card2) {
     369
     370        setLatLon(latLon,
     371                (double) (Double) coord1deg, (double) (Double) coord1min, (double) (Double) coord1sec, (String) card1,
     372                (double) (Double) coord2deg, (double) (Double) coord2min, (double) (Double) coord2sec, (String) card2);
     373    }
     374
     375
     376    private static void setLatLon(final LatLonHolder latLon,
     377            final double coord1deg, final double coord1min, final double coord1sec, final String card1,
     378            final double coord2deg, final double coord2min, final double coord2sec, final String card2) {
     379
     380        setLatLon(latLon, coord1deg, coord1min, coord1sec, card1);
     381        setLatLon(latLon, coord2deg, coord2min, coord2sec, card2);
     382    }
     383
     384
     385    private static void setLatLon(final LatLonHolder latLon, final double coordDeg, final double coordMin, final double coordSec, final String card) {
     386        if (coordDeg < -180 || coordDeg > 180 || coordMin < 0 || coordMin >= 60 || coordSec < 0 || coordSec > 60) {
     387            throw new IllegalArgumentException("out of range");
     388        }
     389
     390        double coord = (coordDeg < 0 ? -1 : 1) * (Math.abs(coordDeg) + coordMin / 60 + coordSec / 3600);
     391        coord = card.equals("N") || card.equals("E") ? coord : -coord;
     392        if (card.equals("N") || card.equals("S")) {
     393            latLon.lat = coord;
     394        } else {
     395            latLon.lon = coord;
     396        }
     397    }
     398
    294399}