Index: trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 5417)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 5418)
@@ -120,4 +120,8 @@
     private Point startingDraggingPos;
     /**
+     * point where user pressed the mouse to start movement
+     */
+    EastNorth startEN;
+    /**
      * The last known position of the mouse.
      */
@@ -198,4 +202,6 @@
     }
 
+    int previousModifiers;
+    
      /**
      * This is called whenever the keyboard modifier status changes
@@ -206,4 +212,8 @@
         // We don't have a mouse event, so we pass the old mouse event but the
         // new modifiers.
+        int modif = ((InputEvent) e).getModifiers();
+        if (previousModifiers == modif)
+            return;
+        previousModifiers = modif;
         if(giveUserFeedback(oldEvent, ((InputEvent) e).getModifiers())) {
             mv.repaint();
@@ -397,4 +407,5 @@
         mouseDownTime = System.currentTimeMillis();
         lastMousePos = e.getPoint();
+        startEN = mv.getEastNorth(lastMousePos.x,lastMousePos.y);
 
         // primitives under cursor are stored in c collection
@@ -424,4 +435,5 @@
             }
             selectPrims(cycleManager.cycleSetup(nearestPrimitive, e.getPoint()), false, false);
+            useLastMoveCommandIfPossible();
             break;
         case select:
@@ -509,7 +521,5 @@
 
         if (!initialMoveThresholdExceeded) {
-            int dxp = lastMousePos.x - e.getX();
-            int dyp = lastMousePos.y - e.getY();
-            int dp = (int) Math.sqrt(dxp * dxp + dyp * dyp);
+            int dp = (int) lastMousePos.distance(e.getX(), e.getY());
             if (dp < initialMoveThreshold)
                 return;
@@ -518,15 +528,11 @@
 
         EastNorth currentEN = mv.getEastNorth(e.getX(), e.getY());
-        EastNorth lastEN = mv.getEastNorth(lastMousePos.x, lastMousePos.y);
-        //EastNorth startEN = mv.getEastNorth(startingDraggingPos.x, startingDraggingPos.y);
-        double dx = currentEN.east() - lastEN.east();
-        double dy = currentEN.north() - lastEN.north();
-        if (dx == 0 && dy == 0)
-            return;
-
+        if (e.getPoint().equals(lastMousePos))
+            return;
+        
         if (virtualManager.hasVirtualWays()) {
-            virtualManager.processVirtualNodeMovements(dx, dy);
+            virtualManager.processVirtualNodeMovements(currentEN);
         } else {
-            if (!updateCommandWhileDragging(dx, dy, currentEN)) return;
+            if (!updateCommandWhileDragging(currentEN)) return;
         }
 
@@ -561,5 +567,5 @@
 
             // Select Draw Tool if no selection has been made
-            if (getCurrentDataSet().getSelected().size() == 0 && !cancelDrawMode) {
+            if (getCurrentDataSet().getSelected().isEmpty() && !cancelDrawMode) {
                 Main.map.selectDrawTool(true);
                 return;
@@ -646,9 +652,8 @@
      * Create or update data modfication command whle dragging mouse - implementation of 
      * continuous moving, scaling and rotation
-     * @param dx, @param dy - mouse displacement
-     * @param currentEN -
+     * @param currentEN - mouse position
      * @return 
      */
-    private boolean updateCommandWhileDragging(double dx, double dy, EastNorth currentEN) {
+    private boolean updateCommandWhileDragging(EastNorth currentEN) {
         // Currently we support only transformations which do not affect relations.
         // So don't add them in the first place to make handling easier
@@ -659,22 +664,18 @@
             return false;
         }
-        Command c = !Main.main.undoRedo.commands.isEmpty()
-                ? Main.main.undoRedo.commands.getLast() : null;
-        if (c instanceof SequenceCommand) {
-            c = ((SequenceCommand) c).getLastCommand();
-        }
+        Command c = getLastCommand();
         if (mode == Mode.move) {
             getCurrentDataSet().beginUpdate();
             if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand) c).getParticipatingPrimitives())) {
-                ((MoveCommand) c).moveAgain(dx, dy);
+                ((MoveCommand) c).saveCheckpoint();
+                ((MoveCommand) c).applyVectorTo(currentEN);
             } else {
                 Main.main.undoRedo.add(
-                        c = new MoveCommand(selection, dx, dy));
-            }
-            getCurrentDataSet().endUpdate();
+                        c = new MoveCommand(selection, startEN, currentEN));
+            }
             for (Node n : affectedNodes) {
                 if (n.getCoor().isOutSideWorld()) {
                     // Revert move
-                    ((MoveCommand) c).moveAgain(-dx, -dy);
+                    ((MoveCommand) c).resetToCheckpoint();
                     JOptionPane.showMessageDialog(
                             Main.parent,
@@ -686,4 +687,5 @@
                 }
             }
+            getCurrentDataSet().endUpdate();
         } else if (mode == Mode.rotate) {
             getCurrentDataSet().beginUpdate();
@@ -704,4 +706,28 @@
         }
         return true;
+    }
+    
+    /**
+     * Adapt last move command (if it is suitabble) to work with next drag, startedd at point startEN
+     */
+    private void useLastMoveCommandIfPossible() {
+        Command c = getLastCommand();
+        Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(getCurrentDataSet().getSelected());
+        if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand) c).getParticipatingPrimitives())) {
+            // old command was created with different base point of movement, we need to recalculate it
+            ((MoveCommand) c).changeStartPoint(startEN);
+        }
+    }
+       
+    /**
+     * Obtain command in undoRedo stack to "continue" when dragging
+     */
+    private Command getLastCommand() {
+        Command c = !Main.main.undoRedo.commands.isEmpty()
+                ? Main.main.undoRedo.commands.getLast() : null;
+        if (c instanceof SequenceCommand) {
+            c = ((SequenceCommand) c).getLastCommand();
+        }
+        return c;
     }
     
@@ -1036,5 +1062,5 @@
         }
 
-        private void processVirtualNodeMovements(double dx, double dy) {
+        private void processVirtualNodeMovements(EastNorth currentEN) {
             Collection<Command> virtualCmds = new LinkedList<Command>();
             virtualCmds.add(new AddCommand(virtualNode));
@@ -1045,5 +1071,5 @@
                 virtualCmds.add(new ChangeCommand(w, wnew));
             }
-            virtualCmds.add(new MoveCommand(virtualNode, dx, dy));
+            virtualCmds.add(new MoveCommand(virtualNode, startEN, currentEN));
             String text = trn("Add and move a virtual new node to way",
                     "Add and move a virtual new node to {0} ways", virtualWays.size(),
Index: trunk/src/org/openstreetmap/josm/command/MoveCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/MoveCommand.java	(revision 5417)
+++ trunk/src/org/openstreetmap/josm/command/MoveCommand.java	(revision 5418)
@@ -33,4 +33,9 @@
     private Collection<Node> nodes = new LinkedList<Node>();
     /**
+     * Starting position, base command point, current (mouse-drag) position = startEN + (x,y) = 
+     */
+    private EastNorth startEN;
+
+    /**
      * x difference movement. Coordinates are in northern/eastern
      */
@@ -40,4 +45,7 @@
      */
     private double y;
+
+    private double backupX;
+    private double backupY;
 
     /**
@@ -47,4 +55,5 @@
     public static class OldState {
         LatLon latlon;
+        EastNorth en; // cached EastNorth to be used for applying exact displacenment
         boolean modified;
     }
@@ -66,5 +75,5 @@
         this(objects, offset.getX(), offset.getY());
     }
-
+    
     /**
      * Create a MoveCommand and assign the initial object set and movement vector.
@@ -72,4 +81,6 @@
     public MoveCommand(Collection<OsmPrimitive> objects, double x, double y) {
         super();
+        startEN = null;
+        saveCheckpoint(); // (0,0) displacement will be saved
         this.x = x;
         this.y = y;
@@ -78,4 +89,5 @@
             OldState os = new OldState();
             os.latlon = new LatLon(n.getCoor());
+            os.en = n.getEastNorth();
             os.modified = n.isModified();
             oldState.add(os);
@@ -83,4 +95,14 @@
     }
 
+     public MoveCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {
+         this(objects, end.getX()-start.getX(), end.getY()-start.getY());
+         startEN =  start;
+     }
+
+     public MoveCommand(OsmPrimitive p, EastNorth start, EastNorth end) {
+         this(Collections.singleton(p), end.getX()-start.getX(), end.getY()-start.getY());
+         startEN =  start;
+     }
+     
     /**
      * Move the same set of objects again by the specified vector. The vectors
@@ -102,4 +124,49 @@
         moveAgain(x - this.x, y - this.y);
     }
+    
+    /**
+     * Change the displacement vector to have endpoint @param currentEN 
+     * starting point is  startEN
+     */
+    public void applyVectorTo(EastNorth currentEN) {
+        if (startEN == null) 
+            return;
+        x = currentEN.getX() - startEN.getX();
+        y = currentEN.getY() - startEN.getY();
+        updateCoordinates();
+    }
+
+     /**
+     * Changes base point of movement
+     * @param newDraggedStartPoint - new starting point after movement (where user clicks to start new drag)
+     */
+    public void changeStartPoint(EastNorth newDraggedStartPoint) {
+        startEN = new EastNorth(newDraggedStartPoint.getX()-x, newDraggedStartPoint.getY()-y);
+     }
+
+    /**
+     * Save curent displacement to restore in case of some problems
+     */
+    public void saveCheckpoint() {
+        backupX = x;
+        backupY = y;
+    }
+
+    /**
+     * Restore old displacement in case of some problems
+     */
+    public void resetToCheckpoint() {
+        x = backupX;
+        y = backupY;
+        updateCoordinates();
+    }
+
+    private void updateCoordinates() {
+        Iterator<OldState> it = oldState.iterator();
+        for (Node n : nodes) {
+            OldState os = it.next();
+            n.setEastNorth(os.en.add(x, y));
+        }
+    }
 
     @Override public boolean executeCommand() {
