001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io.remotecontrol.handler;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Point;
007import java.util.Collections;
008import java.util.Map;
009
010import org.openstreetmap.josm.actions.AutoScaleAction;
011import org.openstreetmap.josm.actions.AutoScaleAction.AutoScaleMode;
012import org.openstreetmap.josm.command.AddCommand;
013import org.openstreetmap.josm.data.UndoRedoHandler;
014import org.openstreetmap.josm.data.coor.LatLon;
015import org.openstreetmap.josm.data.osm.DataSet;
016import org.openstreetmap.josm.data.osm.Node;
017import org.openstreetmap.josm.data.osm.OsmPrimitive;
018import org.openstreetmap.josm.gui.MainApplication;
019import org.openstreetmap.josm.gui.MapView;
020import org.openstreetmap.josm.gui.util.GuiHelper;
021import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog;
022import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
023import org.openstreetmap.josm.spi.preferences.Config;
024import org.openstreetmap.josm.tools.Logging;
025
026/**
027 * Handler for add_node request.
028 */
029public class AddNodeHandler extends RequestHandler {
030
031    /**
032     * The remote control command name used to add a node.
033     */
034    public static final String command = "add_node";
035
036    private double lat;
037    private double lon;
038
039    @Override
040    protected void handleRequest() {
041        GuiHelper.runInEDTAndWait(() -> addNode(args));
042    }
043
044    @Override
045    public String[] getMandatoryParams() {
046        return new String[] {"lat", "lon"};
047    }
048
049    @Override
050    public String[] getOptionalParams() {
051        return new String[] {"addtags"};
052    }
053
054    @Override
055    public String getUsage() {
056        return "adds a node (given by its latitude and longitude) to the current dataset";
057    }
058
059    @Override
060    public String[] getUsageExamples() {
061        return new String[] {
062            "/add_node?lat=11&lon=22",
063            "/add_node?lon=13.3&lat=53.2&addtags=natural=tree|name=%20%20%20==Great%20Oak=="
064        };
065    }
066
067    @Override
068    public String getPermissionMessage() {
069        return tr("Remote Control has been asked to create a new node.") +
070                "<br>" + tr("Coordinates: ") + args.get("lat") + ", " + args.get("lon");
071    }
072
073    @Override
074    public PermissionPrefWithDefault getPermissionPref() {
075        return PermissionPrefWithDefault.CREATE_OBJECTS;
076    }
077
078    /**
079     * Adds a node, implements the GET /add_node?lon=...&amp;lat=... request.
080     * @param args request arguments
081     */
082    private void addNode(Map<String, String> args) {
083
084        // Parse the arguments
085        Logging.info("Adding node at (" + lat + ", " + lon + ')');
086
087        // Create a new node
088        LatLon ll = new LatLon(lat, lon);
089
090        Node node = null;
091
092        if (MainApplication.isDisplayingMapView()) {
093            MapView mapView = MainApplication.getMap().mapView;
094            Point p = mapView.getPoint(ll);
095            node = mapView.getNearestNode(p, OsmPrimitive::isUsable);
096            if (node != null && node.getCoor().greatCircleDistance(ll) > Config.getPref().getDouble("remotecontrol.tolerance", 0.1)) {
097                node = null; // node is too far
098            }
099        }
100
101        DataSet ds = MainApplication.getLayerManager().getEditDataSet();
102        if (node == null) {
103            node = new Node(ll);
104            // Now execute the commands to add this node.
105            UndoRedoHandler.getInstance().add(new AddCommand(ds, node));
106        }
107
108        ds.setSelected(node);
109        if (PermissionPrefWithDefault.CHANGE_VIEWPORT.isAllowed()) {
110            AutoScaleAction.autoScale(AutoScaleMode.SELECTION);
111        } else {
112            MainApplication.getMap().mapView.repaint();
113        }
114        // parse parameter addtags=tag1=value1|tag2=vlaue2
115        AddTagsDialog.addTags(args, sender, Collections.singleton(node));
116    }
117
118    @Override
119    protected void validateRequest() throws RequestHandlerBadRequestException {
120        try {
121            lat = Double.parseDouble(args != null ? args.get("lat") : "");
122            lon = Double.parseDouble(args != null ? args.get("lon") : "");
123        } catch (NumberFormatException e) {
124            throw new RequestHandlerBadRequestException("NumberFormatException ("+e.getMessage()+')', e);
125        }
126        if (MainApplication.getLayerManager().getEditLayer() == null) {
127             throw new RequestHandlerBadRequestException(tr("There is no layer opened to add node"));
128        }
129    }
130}