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 javax.swing.JOptionPane; 012 013import org.openstreetmap.josm.Main; 014import org.openstreetmap.josm.command.Command; 015import org.openstreetmap.josm.command.MoveCommand; 016import org.openstreetmap.josm.data.coor.EastNorth; 017import org.openstreetmap.josm.data.osm.Node; 018import org.openstreetmap.josm.data.osm.OsmPrimitive; 019import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor; 020import org.openstreetmap.josm.tools.Shortcut; 021 022/** 023 * Moves the selection 024 * 025 * @author Frederik Ramm 026 */ 027public class MoveAction extends JosmAction { 028 029 public enum Direction { UP, LEFT, RIGHT, DOWN } 030 031 private Direction myDirection; 032 033 // any better idea? 034 private static String calltosupermustbefirststatementinconstructortext(Direction dir) { 035 String directiontext; 036 if (dir == Direction.UP) { 037 directiontext = tr("up"); 038 } else if (dir == Direction.DOWN) { 039 directiontext = tr("down"); 040 } else if (dir == Direction.LEFT) { 041 directiontext = tr("left"); 042 } else { 043 directiontext = tr("right"); 044 } 045 return directiontext; 046 } 047 048 // any better idea? 049 private static Shortcut calltosupermustbefirststatementinconstructor(Direction dir) { 050 Shortcut sc; 051 if (dir == Direction.UP) { 052 sc = Shortcut.registerShortcut("core:moveup", tr("Move objects {0}", tr("up")), KeyEvent.VK_UP, Shortcut.SHIFT); 053 } else if (dir == Direction.DOWN) { 054 sc = Shortcut.registerShortcut("core:movedown", tr("Move objects {0}", tr("down")), KeyEvent.VK_DOWN, Shortcut.SHIFT); 055 } else if (dir == Direction.LEFT) { 056 sc = Shortcut.registerShortcut("core:moveleft", tr("Move objects {0}", tr("left")), KeyEvent.VK_LEFT, Shortcut.SHIFT); 057 } else { //dir == Direction.RIGHT 058 sc = Shortcut.registerShortcut("core:moveright", tr("Move objects {0}", tr("right")), KeyEvent.VK_RIGHT, Shortcut.SHIFT); 059 } 060 return sc; 061 } 062 063 /** 064 * Constructs a new {@code MoveAction}. 065 * @param dir direction 066 */ 067 public MoveAction(Direction dir) { 068 super(tr("Move {0}", calltosupermustbefirststatementinconstructortext(dir)), null, 069 tr("Moves Objects {0}", calltosupermustbefirststatementinconstructortext(dir)), 070 calltosupermustbefirststatementinconstructor(dir), false); 071 myDirection = dir; 072 putValue("help", ht("/Action/Move")); 073 if (dir == Direction.UP) { 074 putValue("toolbar", "action/move/up"); 075 } else if (dir == Direction.DOWN) { 076 putValue("toolbar", "action/move/down"); 077 } else if (dir == Direction.LEFT) { 078 putValue("toolbar", "action/move/left"); 079 } else { //dir == Direction.RIGHT 080 putValue("toolbar", "action/move/right"); 081 } 082 Main.toolbar.register(this); 083 } 084 085 @Override 086 public void actionPerformed(ActionEvent event) { 087 088 if (!Main.isDisplayingMapView()) 089 return; 090 091 // find out how many "real" units the objects have to be moved in order to 092 // achive an 1-pixel movement 093 094 EastNorth en1 = Main.map.mapView.getEastNorth(100, 100); 095 EastNorth en2 = Main.map.mapView.getEastNorth(101, 101); 096 097 double distx = en2.east() - en1.east(); 098 double disty = en2.north() - en1.north(); 099 100 switch (myDirection) { 101 case UP: 102 distx = 0; 103 disty = -disty; 104 break; 105 case DOWN: 106 distx = 0; 107 break; 108 case LEFT: 109 disty = 0; 110 distx = -distx; 111 break; 112 default: 113 disty = 0; 114 } 115 116 Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected(); 117 Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection); 118 119 Command c = !Main.main.undoRedo.commands.isEmpty() 120 ? Main.main.undoRedo.commands.getLast() : null; 121 122 getCurrentDataSet().beginUpdate(); 123 if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand) c).getParticipatingPrimitives())) { 124 ((MoveCommand) c).moveAgain(distx, disty); 125 } else { 126 c = new MoveCommand(selection, distx, disty); 127 Main.main.undoRedo.add(c); 128 } 129 getCurrentDataSet().endUpdate(); 130 131 for (Node n : affectedNodes) { 132 if (n.getCoor().isOutSideWorld()) { 133 // Revert move 134 ((MoveCommand) c).moveAgain(-distx, -disty); 135 JOptionPane.showMessageDialog( 136 Main.parent, 137 tr("Cannot move objects outside of the world."), 138 tr("Warning"), 139 JOptionPane.WARNING_MESSAGE 140 ); 141 return; 142 } 143 } 144 145 Main.map.mapView.repaint(); 146 } 147 148 @Override 149 protected void updateEnabledState() { 150 if (getCurrentDataSet() == null) { 151 setEnabled(false); 152 } else { 153 updateEnabledState(getCurrentDataSet().getSelected()); 154 } 155 } 156 157 @Override 158 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) { 159 setEnabled(selection != null && !selection.isEmpty()); 160 } 161}