Ticket #5604: AddNode.java.patch

File AddNode.java.patch, 13.8 KB (added by *Martin*, 14 years ago)

new patch (v3)

  • 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.<br/>You can separate longitude and latitude with space, comma or semicolon.<br/>" +
     63                                "Use positive numbers or N, E characters to indicate North or East cardinal direction.<br/>" +
     64                                "For South and West cardinal directions you can use either negative numbers or S, W characters.<br/>" +
     65                                "Coordinate value can be in one of three formats:<ul>" +
     66                        "<li><i>degrees</i><tt>&deg;</tt></li>" +
     67                        "<li><i>degrees</i><tt>&deg;</tt> <i>minutes</i><tt>&#39;</tt></li>" +
     68                        "<li><i>degrees</i><tt>&deg;</tt> <i>minutes</i><tt>&#39;</tt> <i>seconds</i><tt>&quot</tt></li>" +
     69                                "</ul>" +
     70                                "Symbols <tt>&deg;</tt>, <tt>&#39;</tt>, <tt>&prime;</tt>, <tt>&quot;</tt>, <tt>&Prime;</tt> are optional.<br/><br/>" +
     71                                "Some examples:<ul>" +
     72                        "<li>49.29918&deg; 19.24788&deg;</li>" +
     73                        "<li>N 49.29918 E 19.24788</li>" +
     74                        "<li>W 49&deg;29.918&#39; S 19&deg;24.788&#39;</li>" +
     75                        "<li>N 49&deg;29&#39;04&quot; E 19&deg;24&#39;43&quot;</li>" +
     76                        "<li>49.29918 N, 19.24788 E</li>" +
     77                        "<li>49&deg;29&#39;21&quot; N 19&deg;24&#39;38&quot; E</li>" +
     78                        "<li>49 29 51, 19 24 18</li>" +
     79                        "<li>49 29, 19 24</li>" +
     80                        "<li>E 49 29, N 19 24</li>" +
     81                        "<li>49&deg; 29; 19&deg; 24</li>" +
     82                        "<li>N 49&deg; 29, W 19&deg; 24</li>" +
     83                        "<li>49&deg; 29.5 S, 19&deg; 24.6 E</li>" +
     84                        "<li>N 49 29.918 E 19 15.88</li>" +
     85                        "<li>49 29.4 19 24.5</li>" +
     86                        "<li>-49 29.4 N -19 24.5 W</li></ul>" +
     87                        "<li>48 deg 42' 52.13\" N, 21 deg 11' 47.60\" E</li></ul>"
     88                                )),
    6289                GBC.eol());
    6390
    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));
     91        pnl.add(new JLabel(tr("Coordinates")), GBC.std().insets(0,10,5,0));
     92        tfLatLon = new JTextField(24);
     93        pnl.add(tfLatLon, GBC.eol().insets(0,10,0,0));
    7094
    7195        // parse and verify input on the fly
    7296        //
    7397        LatLonInputVerifier inputVerifier = new LatLonInputVerifier();
    74         tfLat.getDocument().addDocumentListener(inputVerifier);
    75         tfLon.getDocument().addDocumentListener(inputVerifier);
     98        tfLatLon.getDocument().addDocumentListener(inputVerifier);
    7699
    77100        // select the text in the field on focus
    78101        //
    79102        TextFieldFocusHandler focusHandler = new TextFieldFocusHandler();
    80         tfLat.addFocusListener(focusHandler);
    81         tfLon.addFocusListener(focusHandler);
     103        tfLatLon.addFocusListener(focusHandler);
    82104        return pnl;
    83105    }
    84106
     
    130152            coordinates = new LatLon(0,0);
    131153        }
    132154        this.coordinates = coordinates;
    133         tfLat.setText(coordinates.latToString(CoordinateFormat.DECIMAL_DEGREES));
    134         tfLon.setText(coordinates.lonToString(CoordinateFormat.DECIMAL_DEGREES));
     155        tfLatLon.setText(coordinates.latToString(CoordinateFormat.DEGREES_MINUTES_SECONDS) + " " + coordinates.lonToString(CoordinateFormat.DEGREES_MINUTES_SECONDS));
    135156        actOK.setEnabled(true);
    136157    }
    137158
     
    176197        return n== null ? null : n.doubleValue();
    177198    }
    178199
    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"));
     200    protected void parseUserInput() {
     201        LatLon latLon;
     202        try {
     203            latLon = parse(tfLatLon.getText());
     204            if (!LatLon.isValidLat(latLon.lat()) || !LatLon.isValidLon(latLon.lon())) {
     205                latLon = null;
     206            }
     207        } catch (IllegalArgumentException e) {
     208            latLon = null;
    186209        }
    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) {
     210        if (latLon == null) {
     211            setErrorFeedback(tfLatLon, tr("Please enter a GPS coordinates"));
    205212            coordinates = null;
    206213            actOK.setEnabled(false);
    207214        } else {
    208             coordinates = new LatLon(lat,lon);
     215            clearErrorFeedback(tfLatLon,tr("Please enter a GPS coordinates"));
     216            coordinates = latLon;
    209217            actOK.setEnabled(true);
    210218        }
    211219    }
     
    287295
    288296        @Override
    289297        public void windowOpened(WindowEvent e) {
    290             tfLat.requestFocusInWindow();
     298            tfLatLon.requestFocusInWindow();
    291299        }
    292300    }
    293301
     302
     303
     304    private static final double ZERO = 0.0;
     305
     306    private static final Pattern p = Pattern.compile("([+|-]?\\d+[.,]\\d+)|([+|-]?\\d+)|(\u00B0|o|deg)|('|\u2032|min)|(\"|\u2033|sec)|(,|;)|([NSEWO])|\\s+|(.+)", Pattern.CASE_INSENSITIVE);
     307
     308
     309    private static LatLon parse(final String coord) {
     310        final Matcher m = p.matcher(coord);
     311
     312        final StringBuilder sb = new StringBuilder();
     313        final List<Object> list = new ArrayList<Object>();
     314
     315        while (m.find()) {
     316            if (m.group(1) != null) {
     317                sb.append('R');
     318                list.add(Double.parseDouble(m.group(1).replace(',', '.')));
     319            } else if (m.group(2) != null) {
     320                sb.append('Z');
     321                list.add(Double.parseDouble(m.group(2)));
     322            } else if (m.group(3) != null) {
     323                sb.append('°');
     324            } else if (m.group(4) != null) {
     325                sb.append('\'');
     326            } else if (m.group(5) != null) {
     327                sb.append('"');
     328            } else if (m.group(6) != null) {
     329                sb.append(',');
     330            } else if (m.group(7) != null) {
     331                sb.append("x");
     332                list.add(m.group(7).toUpperCase().replace('O', 'E'));
     333            } else if (m.group(8) != null) {
     334                throw new IllegalArgumentException("invalid token: " + m.group(8));
     335            }
     336        }
     337
     338        final String pattern = sb.toString();
     339
     340        final Object[] params = list.toArray();
     341        final LatLonHolder latLon = new LatLonHolder();
     342
     343        if (pattern.matches("R°?,?R°?")) {
     344            setLatLon(latLon,
     345                    params[0], ZERO, ZERO, "N",
     346                    params[1], ZERO, ZERO, "E");
     347        } else if (pattern.matches("xR°?,?xR°?")) {
     348            setLatLon(latLon,
     349                    params[1], ZERO, ZERO, params[0],
     350                    params[3], ZERO, ZERO, params[2]);
     351        } else if (pattern.matches("R°?x,?R°?x")) {
     352            setLatLon(latLon,
     353                    params[0], ZERO, ZERO, params[1],
     354                    params[2], ZERO, ZERO, params[3]);
     355        } else if (pattern.matches("Z°[RZ]'?,?Z°[RZ]'?|Z[RZ],?Z[RZ]")) {
     356            setLatLon(latLon,
     357                    params[0], params[1], ZERO, "N",
     358                    params[2], params[3], ZERO, "E");
     359        } else if (pattern.matches("xZ°[RZ]'?,?xZ°[RZ]'?|xZ°?[RZ],?xZ°?[RZ]")) {
     360            setLatLon(latLon,
     361                    params[1], params[2], ZERO, params[0],
     362                    params[4], params[5], ZERO, params[3]);
     363        } else if (pattern.matches("Z°[RZ]'?x,?Z°[RZ]'?x|Z°?[RZ]x,?Z°?[RZ]x")) {
     364            setLatLon(latLon,
     365                    params[0], params[1], ZERO, params[2],
     366                    params[3], params[4], ZERO, params[5]);
     367        } else if (pattern.matches("Z°Z'[RZ]\"?x,?Z°Z'[RZ]\"?x|ZZ[RZ]x,?ZZ[RZ]x")) {
     368            setLatLon(latLon,
     369                    params[0], params[1], params[2], params[3],
     370                    params[4], params[5], params[6], params[7]);
     371        } else if (pattern.matches("xZ°Z'[RZ]\"?,?xZ°Z'[RZ]\"?|xZZ[RZ],?xZZ[RZ]")) {
     372            setLatLon(latLon,
     373                    params[1], params[2], params[3], params[0],
     374                    params[5], params[6], params[7], params[4]);
     375        } else if (pattern.matches("ZZ[RZ],?ZZ[RZ]")) {
     376            setLatLon(latLon,
     377                    params[0], params[1], params[2], "N",
     378                    params[3], params[4], params[5], "E");
     379        } else {
     380            throw new IllegalArgumentException("invalid format: " + pattern);
     381        }
     382
     383        return new LatLon(latLon.lat, latLon.lon);
     384    }
     385
     386
     387    private static class LatLonHolder {
     388        double lat, lon;
     389    }
     390
     391
     392    private static void setLatLon(final LatLonHolder latLon,
     393            final Object coord1deg, final Object coord1min, final Object coord1sec, final Object card1,
     394            final Object coord2deg, final Object coord2min, final Object coord2sec, final Object card2) {
     395
     396        setLatLon(latLon,
     397                (double) (Double) coord1deg, (double) (Double) coord1min, (double) (Double) coord1sec, (String) card1,
     398                (double) (Double) coord2deg, (double) (Double) coord2min, (double) (Double) coord2sec, (String) card2);
     399    }
     400
     401
     402    private static void setLatLon(final LatLonHolder latLon,
     403            final double coord1deg, final double coord1min, final double coord1sec, final String card1,
     404            final double coord2deg, final double coord2min, final double coord2sec, final String card2) {
     405
     406        setLatLon(latLon, coord1deg, coord1min, coord1sec, card1);
     407        setLatLon(latLon, coord2deg, coord2min, coord2sec, card2);
     408    }
     409
     410
     411    private static void setLatLon(final LatLonHolder latLon, final double coordDeg, final double coordMin, final double coordSec, final String card) {
     412        if (coordDeg < -180 || coordDeg > 180 || coordMin < 0 || coordMin >= 60 || coordSec < 0 || coordSec > 60) {
     413            throw new IllegalArgumentException("out of range");
     414        }
     415
     416        double coord = (coordDeg < 0 ? -1 : 1) * (Math.abs(coordDeg) + coordMin / 60 + coordSec / 3600);
     417        coord = card.equals("N") || card.equals("E") ? coord : -coord;
     418        if (card.equals("N") || card.equals("S")) {
     419            latLon.lat = coord;
     420        } else {
     421            latLon.lon = coord;
     422        }
     423    }
     424
     425
     426    public String getText() {
     427        return tfLatLon.getText();
     428    }
     429
     430
     431    public void setText(String text) {
     432        tfLatLon.setText(text);
     433    }
     434
     435
    294436}
  • src/org/openstreetmap/josm/actions/AddNodeAction.java

     
    1919 * and when ok is pressed, a new node is created at the specified position.
    2020 */
    2121public final class AddNodeAction extends JosmAction {
     22    private String text;
     23
    2224    //static private final Logger logger = Logger.getLogger(AddNodeAction.class.getName());
    2325
    2426    public AddNodeAction() {
     
    3335            return;
    3436
    3537        LatLonDialog dialog = new LatLonDialog(Main.parent, tr("Add Node..."), ht("/Action/AddNode"));
     38
     39        if (text != null) {
     40            dialog.setText(text);
     41        }
     42
    3643        dialog.setVisible(true);
    3744        if (dialog.isCanceled())
    3845            return;
     
    4047        LatLon coordinates = dialog.getCoordinates();
    4148        if (coordinates == null)
    4249            return;
     50
     51        text = dialog.getText();
     52
    4353        Node nnew = new Node(coordinates);
    4454
    4555        // add the node