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