Index: /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3413)
+++ /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3414)
@@ -81,4 +81,5 @@
 
     private final ReadWriteLock lock = new ReentrantReadWriteLock();
+    private final Object selectionLock = new Object();
 
     public Lock getReadLock() {
@@ -301,5 +302,8 @@
                 relations.remove(primitive);
             }
-            selectedPrimitives.remove(primitive);
+            synchronized (selectionLock) {
+                selectedPrimitives.remove(primitive);
+                selectionSnapshot = null;
+            }
             allPrimitives.remove(primitive);
             primitive.setDataset(null);
@@ -329,5 +333,5 @@
     public void fireSelectionChanged(){
         synchronized (selListeners) {
-            List<? extends OsmPrimitive> currentSelection = Collections.unmodifiableList(new ArrayList<OsmPrimitive>(selectedPrimitives));
+            Collection<? extends OsmPrimitive> currentSelection = getSelected();
             for (SelectionChangedListener l : selListeners) {
                 l.selectionChanged(currentSelection);
@@ -336,15 +340,14 @@
     }
 
-    LinkedHashSet<OsmPrimitive> selectedPrimitives = new LinkedHashSet<OsmPrimitive>();
+    private LinkedHashSet<OsmPrimitive> selectedPrimitives = new LinkedHashSet<OsmPrimitive>();
+    private Collection<OsmPrimitive> selectionSnapshot;
 
     public Collection<OsmPrimitive> getSelectedNodesAndWays() {
-        Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
-        for (OsmPrimitive osm : selectedPrimitives) {
-            if (osm instanceof Way ||
-                    osm instanceof Node) {
-                sel.add(osm);
-            }
-        }
-        return sel;
+        return new DatasetCollection<OsmPrimitive>(getSelected(), new Predicate<OsmPrimitive>() {
+            @Override
+            public boolean evaluate(OsmPrimitive primitive) {
+                return primitive instanceof Node || primitive instanceof Way;
+            }
+        });
     }
 
@@ -356,5 +359,12 @@
      */
     public Collection<OsmPrimitive> getSelected() {
-        return Collections.unmodifiableSet(selectedPrimitives);
+        Collection<OsmPrimitive> currentList;
+        synchronized (selectionLock) {
+            if (selectionSnapshot == null) {
+                selectionSnapshot = Collections.unmodifiableList(new ArrayList<OsmPrimitive>(selectedPrimitives));
+            }
+            currentList = selectionSnapshot;
+        }
+        return currentList;
     }
 
@@ -363,11 +373,5 @@
      */
     public Collection<Node> getSelectedNodes() {
-        List<Node> result = new ArrayList<Node>(selectedPrimitives.size());
-        for (OsmPrimitive primitive:selectedPrimitives) {
-            if (primitive instanceof Node) {
-                result.add((Node)primitive);
-            }
-        }
-        return result;
+        return new DatasetCollection<Node>(getSelected(), OsmPrimitive.nodePredicate);
     }
 
@@ -376,11 +380,5 @@
      */
     public Collection<Way> getSelectedWays() {
-        List<Way> result = new ArrayList<Way>(selectedPrimitives.size());
-        for (OsmPrimitive primitive:selectedPrimitives) {
-            if (primitive instanceof Way) {
-                result.add((Way)primitive);
-            }
-        }
-        return result;
+        return new DatasetCollection<Way>(getSelected(), OsmPrimitive.wayPredicate);
     }
 
@@ -389,11 +387,5 @@
      */
     public Collection<Relation> getSelectedRelations() {
-        List<Relation> result = new ArrayList<Relation>(selectedPrimitives.size() / 10);
-        for (OsmPrimitive primitive:selectedPrimitives) {
-            if (primitive instanceof Relation) {
-                result.add((Relation)primitive);
-            }
-        }
-        return result;
+        return new DatasetCollection<Relation>(getSelected(), OsmPrimitive.relationPredicate);
     }
 
@@ -404,6 +396,11 @@
     public void toggleSelected(Collection<? extends PrimitiveId> osm) {
         boolean changed = false;
-        for (PrimitiveId o : osm) {
-            changed = changed | this.__toggleSelected(o);
+        synchronized (selectionLock) {
+            for (PrimitiveId o : osm) {
+                changed = changed | this.__toggleSelected(o);
+            }
+            if (changed) {
+                selectionSnapshot = null;
+            }
         }
         if (changed) {
@@ -421,4 +418,5 @@
             selectedPrimitives.add(primitive);
         }
+        selectionSnapshot = null;
         return true;
     }
@@ -432,8 +430,16 @@
      */
     public void setSelected(Collection<? extends PrimitiveId> selection, boolean fireSelectionChangeEvent) {
-        boolean wasEmpty = selectedPrimitives.isEmpty();
-        selectedPrimitives = new LinkedHashSet<OsmPrimitive>();
-        addSelected(selection, fireSelectionChangeEvent);
+        boolean wasEmpty;
+        synchronized (selectionLock) {
+            wasEmpty = selectedPrimitives.isEmpty();
+            selectedPrimitives = new LinkedHashSet<OsmPrimitive>();
+            addSelected(selection, fireSelectionChangeEvent);
+            if (!wasEmpty && selectedPrimitives.isEmpty()) {
+                selectionSnapshot = null;
+            }
+        }
+
         if (!wasEmpty && selectedPrimitives.isEmpty() && fireSelectionChangeEvent) {
+            // If selection is not empty then event was already fired in addSelecteds
             fireSelectionChanged();
         }
@@ -482,8 +488,13 @@
     public void addSelected(Collection<? extends PrimitiveId> selection, boolean fireSelectionChangeEvent) {
         boolean changed = false;
-        for (PrimitiveId id: selection) {
-            OsmPrimitive primitive = getPrimitiveByIdChecked(id);
-            if (primitive != null) {
-                changed = changed | selectedPrimitives.add(primitive);
+        synchronized (selectionLock) {
+            for (PrimitiveId id: selection) {
+                OsmPrimitive primitive = getPrimitiveByIdChecked(id);
+                if (primitive != null) {
+                    changed = changed | selectedPrimitives.add(primitive);
+                }
+            }
+            if (changed) {
+                selectionSnapshot = null;
             }
         }
@@ -502,8 +513,13 @@
     public void clearSelection(Collection<? extends PrimitiveId> list) {
         boolean changed = false;
-        for (PrimitiveId id:list) {
-            OsmPrimitive primitive = getPrimitiveById(id);
-            if (primitive != null) {
-                changed = changed | selectedPrimitives.remove(primitive);
+        synchronized (selectionLock) {
+            for (PrimitiveId id:list) {
+                OsmPrimitive primitive = getPrimitiveById(id);
+                if (primitive != null) {
+                    changed = changed | selectedPrimitives.remove(primitive);
+                }
+            }
+            if (changed) {
+                selectionSnapshot = null;
             }
         }
@@ -514,5 +530,8 @@
     public void clearSelection() {
         if (!selectedPrimitives.isEmpty()) {
-            selectedPrimitives.clear();
+            synchronized (selectionLock) {
+                selectedPrimitives.clear();
+                selectionSnapshot = null;
+            }
             fireSelectionChanged();
         }
@@ -887,12 +906,18 @@
     private boolean cleanupDeleted(Iterator<? extends OsmPrimitive> it) {
         boolean changed = false;
-        while (it.hasNext()) {
-            OsmPrimitive primitive = it.next();
-            if (primitive.isDeleted()) {
-                selectedPrimitives.remove(primitive);
-                allPrimitives.remove(primitive);
-                primitive.setDataset(null);
-                changed = true;
-                it.remove();
+        synchronized (selectionLock) {
+            while (it.hasNext()) {
+                OsmPrimitive primitive = it.next();
+                if (primitive.isDeleted()) {
+                    selectedPrimitives.remove(primitive);
+                    selectionSnapshot = null;
+                    allPrimitives.remove(primitive);
+                    primitive.setDataset(null);
+                    changed = true;
+                    it.remove();
+                }
+            }
+            if (changed) {
+                selectionSnapshot = null;
             }
         }
