Index: src/org/openstreetmap/josm/actions/mapmode/SelectAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 3531)
+++ src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(working copy)
@@ -15,8 +15,8 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
 
@@ -337,8 +337,8 @@
     @Override public void mousePressed(MouseEvent e) {
         if(!Main.map.mapView.isActiveLayerVisible())
             return;
+
         // request focus in order to enable the expected keyboard shortcuts
-        //
         Main.map.mapView.requestFocus();
 
         cancelDrawMode = false;
@@ -346,7 +346,7 @@
         if (e.getButton() != MouseEvent.BUTTON1)
             return;
         boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-        boolean alt = (e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
+        /*boolean alt = (e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;*/
         boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
 
         // We don't want to change to draw tool if the user tries to (de)select
@@ -359,7 +359,7 @@
         didMove = false;
         initialMoveThresholdExceeded = false;
 
-        Collection<OsmPrimitive> osmColl = getNearestCollectionVirtual(e.getPoint(), alt);
+        Collection<OsmPrimitive> osmColl = getNearestCollectionVirtual(e.getPoint(), false /*, alt*/);
 
         if (ctrl && shift) {
             if (getCurrentDataSet().getSelected().isEmpty()) {
@@ -420,14 +420,31 @@
         if (mode == Mode.move) {
             boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
             boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+            boolean alt = (e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0
+            || Main.pref.getBoolean("selectaction.rotates", false);
             if (!didMove) {
-                selectPrims(
-                        Main.map.mapView.getNearestCollection(e.getPoint(), OsmPrimitive.isSelectablePredicate),
-                        shift, ctrl, true, false);
+                Collection<OsmPrimitive> c = Main.map.mapView.getNearestCollection(e.getPoint(), OsmPrimitive.isSelectablePredicate);
+                if (!c.isEmpty() && alt) {
+                    if (c.iterator().next() instanceof Node) {
+                        // there is at least one node under the cursor:
+                        //   - make sure (first element of new list) equals (result of getNearestCollection)
+                        //   - do not consider ways at all, but all nearest nodes
+                        c = new ArrayList<OsmPrimitive>(c);
+                        for (Node n : Main.map.mapView.getNearestNodes(e.getPoint(), OsmPrimitive.isSelectablePredicate)) {
+                            if (!c.contains(n)) {
+                                c.add(n);
+                            }
+                        }
+                    } else {
+                        // consider all ways..
+                        c = Main.map.mapView.getAllNearest(e.getPoint(), OsmPrimitive.isSelectablePredicate);
+                    }
+                }
+                selectPrims(c, shift, ctrl, true, false);
 
                 // If the user double-clicked a node, change to draw mode
-                List<OsmPrimitive> sel = new ArrayList<OsmPrimitive>(getCurrentDataSet().getSelected());
-                if(e.getClickCount() >=2 && sel.size() == 1 && sel.get(0) instanceof Node) {
+                c = getCurrentDataSet().getSelected();
+                if(e.getClickCount() >=2 && c.size() == 1 && c.iterator().next() instanceof Node) {
                     // We need to do it like this as otherwise drawAction will see a double
                     // click and switch back to SelectMode
                     Main.worker.execute(new Runnable(){
@@ -500,12 +517,69 @@
         selectPrims(selectionManager.getObjectsInRectangle(r, alt), shift, ctrl, true, true);
     }
 
+    private boolean selMorePrims = false;
+    private OsmPrimitive selCycleStart = null;
+
     public void selectPrims(Collection<OsmPrimitive> selectionList, boolean shift,
             boolean ctrl, boolean released, boolean area) {
         DataSet ds = getCurrentDataSet();
         if ((shift && ctrl) || (ctrl && !released))
             return; // not allowed together
 
+        // toggle through possible objects on mouse release
+        if (released && !area) {
+            if (selectionList.size() > 1) {
+                Collection<OsmPrimitive> coll = ds.getSelected();
+
+                OsmPrimitive first, foundInDS, node, nxt;
+                first = nxt = selectionList.iterator().next();
+                foundInDS = node = null;
+
+                for (Iterator<OsmPrimitive> i = selectionList.iterator(); i.hasNext(); ) {
+                    if (selMorePrims && shift) {
+                        if (!coll.contains(nxt = i.next())) {
+                            break; // take first primitive not in dsSel or last if all contained
+                        }
+                    } else {
+                        if (coll.contains(nxt = i.next())) {
+                            foundInDS = nxt;
+                            if (selMorePrims || ctrl) {
+                                ds.clearSelection(nxt);
+                                nxt = i.hasNext() ? i.next() : first;
+                            }
+                            break; // take next primitive of selList
+                        } else if (nxt instanceof Node && node == null) {
+                            node = nxt;
+                        }
+                    }
+                }
+
+                if (ctrl) {
+                    if (foundInDS != null) {
+                        // a member of selList was foundInDS
+                        if (!selectionList.contains(selCycleStart)) {
+                            selCycleStart = foundInDS;
+                        }
+                        // check if selCycleStart == prim (equals next(foundInDS))
+                        if (selCycleStart.equals(nxt)) {
+                            ds.addSelected(nxt);   // cycle complete, prim toggled below
+                            selCycleStart = null;  // check: might do w/out ??
+                        }
+                    } else {
+                        // no member of selList was foundInDS (sets were disjunct), setup for new cycle
+                        selCycleStart = nxt = (node != null) ? node : first;
+                    }
+                }
+
+                selectionList = new ArrayList<OsmPrimitive>(1); // do not modify the passed object..
+                selectionList.add(nxt);
+                System.out.println("SelectAction:selectPrims(): truncated selList to id=" + nxt.getId());
+            }
+        }
+
+        // hard-wiring to false due to performance reasons, should do w/out
+        selMorePrims = (released || area) ? false : ds.getSelected().containsAll(selectionList);
+
         if (ctrl) {
             // Ctrl on an item toggles its selection status,
             // but Ctrl on an *area* just clears those items
