001    //License: GPL. Copyright 2007 by Immanuel Scholz and others
002    package org.openstreetmap.josm.actions;
003    
004    import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005    import static org.openstreetmap.josm.tools.I18n.tr;
006    
007    import java.awt.event.ActionEvent;
008    import java.awt.event.KeyEvent;
009    import java.util.Collection;
010    
011    import javax.swing.JOptionPane;
012    
013    import org.openstreetmap.josm.Main;
014    import org.openstreetmap.josm.command.Command;
015    import org.openstreetmap.josm.command.MoveCommand;
016    import org.openstreetmap.josm.data.coor.EastNorth;
017    import org.openstreetmap.josm.data.osm.Node;
018    import org.openstreetmap.josm.data.osm.OsmPrimitive;
019    import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
020    import org.openstreetmap.josm.tools.Shortcut;
021    
022    /**
023     * Moves the selection
024     *
025     * @author Frederik Ramm
026     */
027    public 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 calltosupermustbefirststatementinconstructor_text(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 { //dir == Direction.RIGHT) {
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        public MoveAction(Direction dir) {
064            super(tr("Move {0}", calltosupermustbefirststatementinconstructor_text(dir)), null,
065                    tr("Moves Objects {0}", calltosupermustbefirststatementinconstructor_text(dir)),
066                    calltosupermustbefirststatementinconstructor(dir), false);
067            myDirection = dir;
068            putValue("help", ht("/Action/Move"));
069            if        (dir == Direction.UP)   {
070                putValue("toolbar", "action/move/up");
071            } else if (dir == Direction.DOWN)  {
072                putValue("toolbar", "action/move/down");
073            } else if (dir == Direction.LEFT)  {
074                putValue("toolbar", "action/move/left");
075            } else { //dir == Direction.RIGHT) {
076                putValue("toolbar", "action/move/right");
077            }
078            Main.toolbar.register(this);
079        }
080    
081        public void actionPerformed(ActionEvent event) {
082    
083            if (!Main.isDisplayingMapView())
084                return;
085    
086            // find out how many "real" units the objects have to be moved in order to
087            // achive an 1-pixel movement
088    
089            EastNorth en1 = Main.map.mapView.getEastNorth(100, 100);
090            EastNorth en2 = Main.map.mapView.getEastNorth(101, 101);
091    
092            double distx = en2.east() - en1.east();
093            double disty = en2.north() - en1.north();
094    
095            switch (myDirection) {
096            case UP:
097                distx = 0;
098                disty = -disty;
099                break;
100            case DOWN:
101                distx = 0;
102                break;
103            case LEFT:
104                disty = 0;
105                distx = -distx;
106                break;
107            default:
108                disty = 0;
109            }
110    
111            Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected();
112            Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection);
113    
114            Command c = !Main.main.undoRedo.commands.isEmpty()
115            ? Main.main.undoRedo.commands.getLast() : null;
116    
117            getCurrentDataSet().beginUpdate(); 
118            if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).getParticipatingPrimitives())) {
119                ((MoveCommand)c).moveAgain(distx, disty);
120            } else {
121                Main.main.undoRedo.add(
122                        c = new MoveCommand(selection, distx, disty));
123            }
124            getCurrentDataSet().endUpdate(); 
125            
126            for (Node n : affectedNodes) {
127                if (n.getCoor().isOutSideWorld()) {
128                    // Revert move
129                    ((MoveCommand) c).moveAgain(-distx, -disty);
130                    JOptionPane.showMessageDialog(
131                            Main.parent,
132                            tr("Cannot move objects outside of the world."),
133                            tr("Warning"),
134                            JOptionPane.WARNING_MESSAGE
135                    );
136                    return;
137                }
138            }
139    
140            Main.map.mapView.repaint();
141        }
142    
143        @Override
144        protected void updateEnabledState() {
145            if (getCurrentDataSet() == null) {
146                setEnabled(false);
147            } else {
148                updateEnabledState(getCurrentDataSet().getSelected());
149            }
150        }
151    
152        @Override
153        protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
154            setEnabled(selection != null && !selection.isEmpty());
155        }
156    }