| 1 | // License: GPL. For details, see LICENSE file.
|
|---|
| 2 | package org.openstreetmap.josm.actions;
|
|---|
| 3 |
|
|---|
| 4 | import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
|
|---|
| 5 | import static org.openstreetmap.josm.tools.I18n.tr;
|
|---|
| 6 |
|
|---|
| 7 | import java.awt.event.ActionEvent;
|
|---|
| 8 | import java.awt.event.KeyEvent;
|
|---|
| 9 | import java.util.Collection;
|
|---|
| 10 | import java.util.Locale;
|
|---|
| 11 |
|
|---|
| 12 | import javax.swing.JOptionPane;
|
|---|
| 13 |
|
|---|
| 14 | import org.openstreetmap.josm.command.MoveCommand;
|
|---|
| 15 | import org.openstreetmap.josm.data.UndoRedoHandler;
|
|---|
| 16 | import org.openstreetmap.josm.data.coor.EastNorth;
|
|---|
| 17 | import org.openstreetmap.josm.data.osm.DataSet;
|
|---|
| 18 | import org.openstreetmap.josm.data.osm.Node;
|
|---|
| 19 | import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
|---|
| 20 | import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
|
|---|
| 21 | import org.openstreetmap.josm.gui.MainApplication;
|
|---|
| 22 | import org.openstreetmap.josm.gui.MapView;
|
|---|
| 23 | import org.openstreetmap.josm.tools.Shortcut;
|
|---|
| 24 |
|
|---|
| 25 | /**
|
|---|
| 26 | * Moves the selection
|
|---|
| 27 | *
|
|---|
| 28 | * @author Frederik Ramm
|
|---|
| 29 | */
|
|---|
| 30 | public class MoveAction extends JosmAction {
|
|---|
| 31 |
|
|---|
| 32 | /**
|
|---|
| 33 | * Move direction.
|
|---|
| 34 | */
|
|---|
| 35 | public enum Direction {
|
|---|
| 36 | /** Move up */
|
|---|
| 37 | UP(tr("up"), "up", KeyEvent.VK_UP),
|
|---|
| 38 | /* SHORTCUT(Move objects up, core:moveup, SHIFT, UP) */
|
|---|
| 39 | /** Move left */
|
|---|
| 40 | LEFT(tr("left"), "previous", KeyEvent.VK_LEFT),
|
|---|
| 41 | /* SHORTCUT(Move objects left, core:moveleft, SHIFT, LEFT) */
|
|---|
| 42 | /** Move right */
|
|---|
| 43 | RIGHT(tr("right"), "next", KeyEvent.VK_RIGHT),
|
|---|
| 44 | /* SHORTCUT(Move objects right, core:moveright, SHIFT, RIGHT) */
|
|---|
| 45 | /** Move down */
|
|---|
| 46 | DOWN(tr("down"), "down", KeyEvent.VK_DOWN);
|
|---|
| 47 | /* SHORTCUT(Move objects down, core:movedown, SHIFT, DOWN) */
|
|---|
| 48 |
|
|---|
| 49 | private final String localizedName;
|
|---|
| 50 | private final String icon;
|
|---|
| 51 | private final int shortcutKey;
|
|---|
| 52 |
|
|---|
| 53 | Direction(String localizedName, String icon, int shortcutKey) {
|
|---|
| 54 | this.localizedName = localizedName;
|
|---|
| 55 | this.icon = icon;
|
|---|
| 56 | this.shortcutKey = shortcutKey;
|
|---|
| 57 | }
|
|---|
| 58 |
|
|---|
| 59 | String getId() {
|
|---|
| 60 | return name().toLowerCase(Locale.ENGLISH);
|
|---|
| 61 | }
|
|---|
| 62 |
|
|---|
| 63 | String getLocalizedName() {
|
|---|
| 64 | return localizedName;
|
|---|
| 65 | }
|
|---|
| 66 |
|
|---|
| 67 | String getIcon() {
|
|---|
| 68 | return "dialogs/" + icon;
|
|---|
| 69 | }
|
|---|
| 70 |
|
|---|
| 71 | String getToolbarName() {
|
|---|
| 72 | return "action/move/" + getId();
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | int getShortcutKey() {
|
|---|
| 76 | return shortcutKey;
|
|---|
| 77 | }
|
|---|
| 78 |
|
|---|
| 79 | Shortcut getShortcut() {
|
|---|
| 80 | return Shortcut.registerShortcut(/* NO-SHORTCUT - adapt definition above when modified */
|
|---|
| 81 | "core:move" + getId(), tr("Move objects {0}", getLocalizedName()), getShortcutKey(), Shortcut.SHIFT);
|
|---|
| 82 | }
|
|---|
| 83 | }
|
|---|
| 84 |
|
|---|
| 85 | private final Direction myDirection;
|
|---|
| 86 |
|
|---|
| 87 | /**
|
|---|
| 88 | * Constructs a new {@code MoveAction}.
|
|---|
| 89 | * @param dir direction
|
|---|
| 90 | */
|
|---|
| 91 | public MoveAction(Direction dir) {
|
|---|
| 92 | super(tr("Move {0}", dir.getLocalizedName()), dir.getIcon(),
|
|---|
| 93 | tr("Moves Objects {0}", dir.getLocalizedName()),
|
|---|
| 94 | dir.getShortcut(), true, dir.getToolbarName(), true);
|
|---|
| 95 | myDirection = dir;
|
|---|
| 96 | setHelpId(ht("/Action/Move"));
|
|---|
| 97 | }
|
|---|
| 98 |
|
|---|
| 99 | /**
|
|---|
| 100 | * Find out how many "real" units the objects have to be moved in order to achieve an 1-pixel movement
|
|---|
| 101 | * @param mapView map view
|
|---|
| 102 | * @return move offset
|
|---|
| 103 | */
|
|---|
| 104 | private EastNorth getOffset(MapView mapView) {
|
|---|
| 105 | EastNorth en1 = mapView.getEastNorth(100, 100);
|
|---|
| 106 | EastNorth en2 = mapView.getEastNorth(101, 101);
|
|---|
| 107 |
|
|---|
| 108 | double distx = en2.east() - en1.east();
|
|---|
| 109 | double disty = en2.north() - en1.north();
|
|---|
| 110 |
|
|---|
| 111 | switch (myDirection) {
|
|---|
| 112 | case UP:
|
|---|
| 113 | distx = 0;
|
|---|
| 114 | disty = -disty;
|
|---|
| 115 | break;
|
|---|
| 116 | case DOWN:
|
|---|
| 117 | distx = 0;
|
|---|
| 118 | break;
|
|---|
| 119 | case LEFT:
|
|---|
| 120 | disty = 0;
|
|---|
| 121 | distx = -distx;
|
|---|
| 122 | break;
|
|---|
| 123 | default:
|
|---|
| 124 | disty = 0;
|
|---|
| 125 | }
|
|---|
| 126 |
|
|---|
| 127 | return new EastNorth(distx, disty);
|
|---|
| 128 | }
|
|---|
| 129 |
|
|---|
| 130 | @Override
|
|---|
| 131 | public void actionPerformed(ActionEvent event) {
|
|---|
| 132 | DataSet ds = getLayerManager().getEditDataSet();
|
|---|
| 133 |
|
|---|
| 134 | if (!MainApplication.isDisplayingMapView() || ds == null)
|
|---|
| 135 | return;
|
|---|
| 136 |
|
|---|
| 137 | MapView mapView = MainApplication.getMap().mapView;
|
|---|
| 138 | final EastNorth dist = getOffset(mapView);
|
|---|
| 139 |
|
|---|
| 140 | Collection<OsmPrimitive> selection = ds.getSelected();
|
|---|
| 141 | Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection);
|
|---|
| 142 |
|
|---|
| 143 | MoveCommand cmd = ds.update(c -> {
|
|---|
| 144 | MoveCommand moveCmd;
|
|---|
| 145 | if (c instanceof MoveCommand && ds.equals(c.getAffectedDataSet())
|
|---|
| 146 | && affectedNodes.equals(((MoveCommand) c).getParticipatingPrimitives())) {
|
|---|
| 147 | moveCmd = (MoveCommand) c;
|
|---|
| 148 | moveCmd.moveAgain(dist.east(), dist.north());
|
|---|
| 149 | } else {
|
|---|
| 150 | moveCmd = new MoveCommand(ds, selection, dist.east(), dist.north());
|
|---|
| 151 | UndoRedoHandler.getInstance().add(moveCmd);
|
|---|
| 152 | }
|
|---|
| 153 | return moveCmd;
|
|---|
| 154 | }, UndoRedoHandler.getInstance().getLastCommand());
|
|---|
| 155 |
|
|---|
| 156 | for (Node n : affectedNodes) {
|
|---|
| 157 | if (n.isLatLonKnown() && n.isOutSideWorld()) {
|
|---|
| 158 | // Revert move
|
|---|
| 159 | cmd.moveAgain(-dist.east(), -dist.north());
|
|---|
| 160 | JOptionPane.showMessageDialog(
|
|---|
| 161 | MainApplication.getMainFrame(),
|
|---|
| 162 | tr("Cannot move objects outside of the world."),
|
|---|
| 163 | tr("Warning"),
|
|---|
| 164 | JOptionPane.WARNING_MESSAGE
|
|---|
| 165 | );
|
|---|
| 166 | return;
|
|---|
| 167 | }
|
|---|
| 168 | }
|
|---|
| 169 |
|
|---|
| 170 | mapView.repaint();
|
|---|
| 171 | }
|
|---|
| 172 |
|
|---|
| 173 | @Override
|
|---|
| 174 | protected void updateEnabledState() {
|
|---|
| 175 | updateEnabledStateOnCurrentSelection();
|
|---|
| 176 | }
|
|---|
| 177 |
|
|---|
| 178 | @Override
|
|---|
| 179 | protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
|
|---|
| 180 | updateEnabledStateOnModifiableSelection(selection);
|
|---|
| 181 | }
|
|---|
| 182 | }
|
|---|