001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions; 003 004import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 005import static org.openstreetmap.josm.tools.I18n.tr; 006 007import java.awt.event.ActionEvent; 008import java.awt.event.KeyEvent; 009import java.util.Collection; 010 011import org.openstreetmap.josm.command.MoveCommand; 012import org.openstreetmap.josm.data.UndoRedoHandler; 013import org.openstreetmap.josm.data.coor.LatLon; 014import org.openstreetmap.josm.data.osm.Node; 015import org.openstreetmap.josm.data.osm.OsmPrimitive; 016import org.openstreetmap.josm.data.osm.OsmUtils; 017import org.openstreetmap.josm.gui.MainApplication; 018import org.openstreetmap.josm.gui.dialogs.LatLonDialog; 019import org.openstreetmap.josm.tools.Shortcut; 020 021/** 022 * This action displays a dialog with the coordinates of a node where the user can change them, 023 * and when ok is pressed, the node is relocated to the specified position. 024 */ 025public final class MoveNodeAction extends JosmAction { 026 027 /** 028 * Constructs a new {@code MoveNodeAction}. 029 */ 030 public MoveNodeAction() { 031 super(tr("Move Node..."), "movenode", tr("Edit latitude and longitude of a node."), 032 Shortcut.registerShortcut("movenode", tr("Edit: {0}", tr("Move Node...")), 033 KeyEvent.VK_M, Shortcut.NONE), true); 034 setHelpId(ht("/Action/MoveNode")); 035 } 036 037 @Override 038 public void actionPerformed(ActionEvent e) { 039 Collection<Node> selNodes = getLayerManager().getEditDataSet().getSelectedNodes(); 040 if (!isEnabled() || selNodes.size() != 1) 041 return; 042 043 LatLonDialog dialog = new LatLonDialog(MainApplication.getMainFrame(), tr("Move Node..."), ht("/Action/MoveNode")); 044 Node n = (Node) selNodes.toArray()[0]; 045 dialog.setCoordinates(n.getCoor()); 046 dialog.showDialog(); 047 if (dialog.getValue() != 1) 048 return; 049 050 LatLon coordinates = dialog.getCoordinates(); 051 if (coordinates == null) 052 return; 053 054 // move the node 055 UndoRedoHandler.getInstance().add(new MoveCommand(n, coordinates)); 056 if (n.getCoor().distance(coordinates) > 1) { 057 // see #13538: Avoid rounding error near 180 longitude which moves nodes too far 058 if (coordinates.lon() >= 180.0) { 059 coordinates = new LatLon(coordinates.lat(), Math.nextDown(180.0)); 060 } else if (coordinates.lon() <= -180.0) { 061 coordinates = new LatLon(coordinates.lat(), Math.nextUp(-180.0)); 062 } 063 UndoRedoHandler.getInstance().undo(1); 064 UndoRedoHandler.getInstance().add(new MoveCommand(n, coordinates)); 065 } 066 MainApplication.getMap().mapView.repaint(); 067 } 068 069 @Override 070 protected void updateEnabledState() { 071 updateEnabledStateOnCurrentSelection(); 072 } 073 074 @Override 075 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) { 076 setEnabled(OsmUtils.isOsmCollectionEditable(selection) && selection.size() == 1 && selection.toArray()[0] instanceof Node); 077 } 078}