Index: src/org/openstreetmap/josm/actions/mapmode/SelectAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 3329)
+++ 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;
@@ -31,6 +32,8 @@
 import org.openstreetmap.josm.command.RotateCommand;
 import org.openstreetmap.josm.command.SequenceCommand;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.BBox;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -55,7 +58,6 @@
  * If an selected object is under the mouse when dragging, move all selected objects.
  * If an unselected object is under the mouse when dragging, it becomes selected
  * and will be moved.
- * If no object is under the mouse, move all selected objects (if any)
  *
  * @author imi
  */
@@ -73,6 +75,7 @@
     }
 
     enum Mode { move, rotate, select }
+    public enum Intersection {INSIDE, OUTSIDE, CROSSING}
     private Mode mode = null;
     private long mouseDownTime = 0;
     private boolean didMove = false;
@@ -102,6 +105,7 @@
      */
     private int initialMoveThreshold;
     private boolean initialMoveThresholdExceeded = false;
+    private int selectWaysRecursions = 0;
     /**
      * Create a new SelectAction
      * @param mapFrame The MapFrame this action belongs to.
@@ -336,7 +340,8 @@
     }
 
     /**
-     * Look, whether any object is selected. If not, select the nearest node.
+     * Look, whether any object is selected. If not, select the nearest node
+     * within snap distance.
      * If there are no nodes in the dataset, do nothing.
      *
      * If the user did not press the left mouse button, do nothing.
@@ -345,7 +350,7 @@
      * cursor to movement.
      */
     @Override public void mousePressed(MouseEvent e) {
-        if(!Main.map.mapView.isActiveLayerVisible())
+        if (!Main.map.mapView.isActiveLayerVisible())
             return;
         // request focus in order to enable the expected keyboard shortcuts
         //
@@ -361,7 +366,7 @@
 
         // We don't want to change to draw tool if the user tries to (de)select
         // stuff but accidentally clicks in an empty area when selection is empty
-        if(shift || ctrl) {
+        if (shift || ctrl) {
             cancelDrawMode = true;
         }
 
@@ -386,13 +391,77 @@
                     shift || getCurrentDataSet().getSelected().containsAll(osmColl),
                     ctrl, false, false);
             mode = Mode.move;
+        } else if (alt) {
+            Collection<Way> ways = getCurrentDataSet().getWays();
+            LatLon latlon = Main.map.mapView.getLatLon(e.getX(), e.getY());
+            double x = latlon.lon();
+            double y = latlon.lat();
+            BBox mbox = new BBox(latlon, latlon);
+
+            long start = System.currentTimeMillis();
+            int polies = 0;
+            List<Way> polygons = new LinkedList<Way>();
+            for (Way way : ways)
+            {
+                // we're only looking for polygons
+                if (!way.isClosed()) {
+                    continue;
+                }
+                polies++;
+                if (pointInPoly(way, mbox, x, y)) {
+                    polygons.add(way);
+                }
+            }
+            long end = System.currentTimeMillis();
+            long time = end - start;
+            System.out.println("processing " + polies + " polygons took " + time + " ms and found " + polygons.size() + " polygons");
+
+            start = System.currentTimeMillis();
+            if (polygons.size() > 1)
+            {
+                // have to figure out which is the tighter one
+                boolean removedOne = false;
+                do {
+                    removedOne = false;
+                    Iterator<Way> it = polygons.iterator();
+                    Way firstEntry = it.next();
+                    while (it.hasNext()){
+                        Way way = it.next();
+                        Intersection res = polyInPoly(way, firstEntry);
+                        if (res == Intersection.INSIDE) {
+                            System.out.println("1 removing polygon " + polygons.get(0).getUniqueId());
+                            polygons.remove(0);
+                            removedOne = true;
+                            break;
+                        }
+                        else
+                            if (res == Intersection.OUTSIDE) {
+                                System.out.println("2 removing polygon " + way.getUniqueId());
+                                it.remove();
+                                removedOne = true;
+                            }
+                    }
+                } while (removedOne && polygons.size() > 1);
+            }
+            end = System.currentTimeMillis();
+            time = end - start;
+            System.out.println("determining the inner polygontook " + time + " ms and found " + polygons.size() + " polygons");
+
+            // Now we've only one polygon or multiple intersecting ones.
+            // The first case is ok and for the second one I lack criteria to
+            // say which one is the better fit, so take them all.
+            selectPrims(new ArrayList<OsmPrimitive>(polygons), shift, false, false, false);
+
+            mode = Mode.select;
+            oldCursor = Main.map.mapView.getCursor();
+            selectionManager.register(Main.map.mapView);
         } else {
             mode = Mode.select;
             oldCursor = Main.map.mapView.getCursor();
             selectionManager.register(Main.map.mapView);
             selectionManager.mousePressed(e);
         }
-        if(mode != Mode.move || shift || ctrl)
+        if (mode != Mode.move || shift || ctrl)
         {
             virtualNode = null;
             virtualWays.clear();
@@ -402,7 +471,7 @@
         // Mode.select redraws when selectPrims is called
         // Mode.move   redraws when mouseDragged is called
         // Mode.rotate redraws here
-        if(mode == Mode.rotate) {
+        if (mode == Mode.rotate) {
             Main.map.mapView.repaint();
         }
 
@@ -410,6 +479,149 @@
     }
 
     /**
+     * Tests if the first polygon lies within the second polygon or not.
+     * "Lies within" is defined as all its points lie within, though that
+     * could still mean the borders intersect.
+     * This should be sufficient for our needs though.
+     *
+     * @param poly the way of the first polygon
+     * @param poly the way of the second polygon
+     * @return INSIDE if the first lies completely within the second polygon,
+     *   OUTSIDE it lies completely outside of it and CROSSING if it partially
+     *   lies within.
+     */
+    private Intersection polyInPoly(Way poly1, Way poly2)
+    {
+        int contains = 0;
+        List <Node> nodes = poly1.getNodes();
+        for (Node node : nodes) {
+            double x = node.getCoor().lon();
+            double y = node.getCoor().lat();
+            if (pointInPoly(poly2, node.getBBox(), x, y)) {
+                contains++;
+            }
+        }
+
+        if (contains == nodes.size()) return Intersection.INSIDE;
+        if (contains == 0) return Intersection.OUTSIDE;
+        return Intersection.CROSSING;
+    }
+
+    /**
+     * Tests if the given point is within the polygon or not.
+     * The source of this code is http://www.visibone.com/inpoly/
+     *
+     * @param poly the way of the polygon
+     * @param mbox bounding box of the mouse point
+     * @param xt X coordinate of the mouse cursor
+     * @param yt Y coordinate of the mouse cursor
+     * @return true if the point is within the polygon, false otherwise
+     */
+    private boolean pointInPoly(Way poly, BBox mbox, double xt, double yt)
+    {
+        List <Node> nodes = poly.getNodes();
+        int npoints = nodes.size();
+        double xnew, ynew;
+        double xold, yold;
+        double x1, y1;
+        double x2, y2;
+
+        if (npoints < 4)
+            return(false);
+
+        // in this case intersects is a test for "is contained"
+        if (!poly.getBBox().intersects(mbox))
+            return false;
+
+        LatLon old_ = nodes.get(npoints - 1).getCoor();
+        xold = old_.getX();
+        yold = old_.getY();
+        boolean inside = false;
+        for (Node node : nodes) {
+            LatLon new_ = node.getCoor();
+            xnew = new_.getX();
+            ynew = new_.getY();
+            if (xnew > xold) {
+                x1 = xold;
+                x2 = xnew;
+                y1 = yold;
+                y2 = ynew;
+            }
+            else {
+                x1 = xnew;
+                x2 = xold;
+                y1 = ynew;
+                y2 = yold;
+            }
+
+            if ((xnew < xt) == (xt <= xold)          /* edge "open" at one end */
+                    && (yt - y1) * (x2 - x1)
+                    < (y2 - y1) * (xt - x1)) {
+                inside = !inside;
+            }
+
+            xold = xnew;
+            yold = ynew;
+        }
+
+        return(inside);
+    }
+
+
+    /**
+     * Handle left double clicks for selecting connected ways
+     */
+    @Override public void mouseClicked(MouseEvent e) {
+        if (!Main.map.mapView.isActiveLayerVisible())
+            return;
+        // request focus in order to enable the expected keyboard shortcuts
+        //
+        Main.map.mapView.requestFocus();
+
+        cancelDrawMode = false;
+        if (! (Boolean)this.getValue("active")) return;
+        if (e.getButton() != MouseEvent.BUTTON1 ||
+                e.getClickCount() != 2)
+            return;
+
+        Collection<Way> sel = getCurrentDataSet().getSelectedWays();
+        selectWaysRecursions = 0;
+        // remove selection for the initial input to not fall prey
+        // to the first condition in selectWays
+        getCurrentDataSet().clearSelection(sel);
+        selectWays(sel);
+    }
+
+    /**
+     * This is method recursively calls itself
+     * 
+     * @param ways all selected ways
+     */
+    private void selectWays(Collection<Way> ways)
+    {
+        // limit the number of recursions to a reasonable amount
+        if (selectWaysRecursions++ < 10) {
+            for (Way way : ways) {
+                // this way may have been selected already in a deeper recursion
+                if (way.isSelected()) {
+                    continue;
+                }
+                getCurrentDataSet().addSelected(way);
+                for (Node node : way.getNodes())
+                {
+                    Collection<Way> newways = OsmPrimitive.getFilteredList(node.getReferrers(), Way.class);
+                    newways.removeAll(getCurrentDataSet().getSelectedWays());
+
+                    if (!newways.isEmpty()) {
+                        selectWays(newways);
+                    }
+                }
+            }
+        }
+        selectWaysRecursions--;
+    }
+
+    /**
      * Restore the old mouse cursor.
      */
     @Override public void mouseReleased(MouseEvent e) {
@@ -489,8 +701,9 @@
                         nodesToMerge.add(targetNode);
                         if (!nodesToMerge.isEmpty()) {
                             Command cmd = MergeNodesAction.mergeNodes(Main.main.getEditLayer(),nodesToMerge, targetNode);
-                            if(cmd != null)
+                            if(cmd != null) {
                                 Main.main.undoRedo.add(cmd);
+                            }
                         }
                     }
                 }
