Index: src/org/openstreetmap/josm/actions/mapmode/SelectAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 3523)
+++ src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(working copy)
@@ -15,6 +15,7 @@
 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;
@@ -372,6 +373,9 @@
             // selected object (this would break moving of selected groups).
             // We'll do that later in mouseReleased if the user didn't try to
             // move.
+            System.out.println("SelectAction:mousePressed(): id=" +
+                    osmColl.iterator().next().getId() + " in sel? " +
+                    getCurrentDataSet().getSelected().containsAll(osmColl));
             selectPrims(osmColl,
                     shift || getCurrentDataSet().getSelected().containsAll(osmColl),
                     ctrl, false, false);
@@ -422,7 +426,7 @@
             boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
             if (!didMove) {
                 selectPrims(
-                        Main.map.mapView.getNearestCollection(e.getPoint(), OsmPrimitive.isSelectablePredicate),
+                        Main.map.mapView.getAllNearest(e.getPoint(), OsmPrimitive.isSelectablePredicate),
                         shift, ctrl, true, false);
 
                 // If the user double-clicked a node, change to draw mode
@@ -500,29 +504,88 @@
         selectPrims(selectionManager.getObjectsInRectangle(r, alt), shift, ctrl, true, true);
     }
 
+    private boolean lookForMore = false;
+    private OsmPrimitive ctrlStart = 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 o = selectionList.iterator().next(), first = o, fsel = null;
+
+                for (Iterator<OsmPrimitive> i = selectionList.iterator(); i.hasNext(); ) {
+                    if (lookForMore && shift) {
+                        if (!coll.contains(o = i.next())) {
+                            break; // take first not in dsSel (or last)
+                        }
+                    } else {
+                        if (coll.contains(o = i.next())) {
+                            fsel = o;
+                            if (lookForMore || ctrl) {
+                                ds.clearSelection(o);
+                                o = i.hasNext() ? i.next() : first;
+                            }
+                            break; // take first found
+                        }
+                    }
+                }
+
+                if (ctrl) {
+                    if (fsel != null) {
+                        // fsel was found in dsSel, succ(fsel) == o holds
+                        if (ctrlStart == null) {
+                            ctrlStart = fsel;
+                        }
+                        if (o.equals(ctrlStart)) {
+                            // user clicked his way through all possible completions
+                            // now add o, so we also get a deselect step in rotation
+                            ds.addSelected(o);
+                            ctrlStart = null;
+                        }
+                    } else {
+                        // selList and dsSel were disjunct, take o (first in rotation)
+                        ctrlStart = o;
+                    }
+                } else {
+                    ctrlStart = null;
+                }
+
+                selectionList.clear();
+                selectionList.add(o);
+                System.out.println("SelectAction:selectPrims(): truncating selList to id=" + o.getId());
+            }
+        }
+
         if (ctrl) {
             // Ctrl on an item toggles its selection status,
             // but Ctrl on an *area* just clears those items
             // out of the selection.
             if (area) {
                 ds.clearSelection(selectionList);
+                System.out.println("SelectAction:selectPrims(): clearing selList from dsSel");
             } else {
                 ds.toggleSelected(selectionList);
+                System.out.println("SelectAction:selectPrims(): toggling selList in dsSel");
             }
         } else {
+            // hard-wiring to false due to performance reasons, should do w/out
+            lookForMore = (released || area) ? false : ds.getSelected().containsAll(selectionList);
+
             // plain clicks with no modifiers
             if (!shift) {
                 ds.setSelected(selectionList);
+                System.out.println("SelectAction:selectPrims(): replacing dsSel w/ selList");
             } else {
                 // add things to an
                 // existing selection.
                 ds.addSelected(selectionList);
+                System.out.println("SelectAction:selectPrims(): adding selList to dsSel");
             }
         }
     }
