Index: /trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java	(revision 13764)
@@ -246,4 +246,5 @@
      * Fires a commands change event after adding a command.
      * @param cmd command added
+     * @since 13729
      */
     public void afterAdd(Command cmd) {
Index: /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 13764)
@@ -28,5 +28,4 @@
 import org.openstreetmap.josm.data.APIDataSet.APIOperation;
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.Data;
 import org.openstreetmap.josm.data.DataSource;
 import org.openstreetmap.josm.data.ProjectionBounds;
@@ -104,5 +103,5 @@
  * @author imi
  */
-public final class DataSet extends QuadBucketPrimitiveStore implements Data, ProjectionChangeListener, Lockable {
+public final class DataSet implements OsmData<OsmPrimitive, Node, Way, Relation>, ProjectionChangeListener, Lockable {
 
     /**
@@ -115,4 +114,6 @@
      */
     private static final int MAX_EVENTS = 1000;
+
+    private final QuadBucketPrimitiveStore<Node, Way, Relation> store = new QuadBucketPrimitiveStore<>();
 
     private final Storage<OsmPrimitive> allPrimitives = new Storage<>(new Storage.PrimitiveIdHash(), true);
@@ -273,8 +274,5 @@
     }
 
-    /**
-     * Returns the lock used for reading.
-     * @return the lock used for reading
-     */
+    @Override
     public Lock getReadLock() {
         return lock.readLock();
@@ -307,9 +305,5 @@
     private String version;
 
-    /**
-     * Replies the API version this dataset was created from. May be null.
-     *
-     * @return the API version this dataset was created from. May be null.
-     */
+    @Override
     public String getVersion() {
         return version;
@@ -327,38 +321,20 @@
     }
 
-    /**
-     * Get the download policy.
-     * @return the download policy
-     * @see #setDownloadPolicy(DownloadPolicy)
-     * @since 13453
-     */
+    @Override
     public DownloadPolicy getDownloadPolicy() {
         return this.downloadPolicy;
     }
 
-    /**
-     * Sets the download policy.
-     * @param downloadPolicy the download policy
-     * @see #getUploadPolicy()
-     * @since 13453
-     */
+    @Override
     public void setDownloadPolicy(DownloadPolicy downloadPolicy) {
         this.downloadPolicy = downloadPolicy;
     }
 
-    /**
-     * Get the upload policy.
-     * @return the upload policy
-     * @see #setUploadPolicy(UploadPolicy)
-     */
+    @Override
     public UploadPolicy getUploadPolicy() {
         return this.uploadPolicy;
     }
 
-    /**
-     * Sets the upload policy.
-     * @param uploadPolicy the upload policy
-     * @see #getUploadPolicy()
-     */
+    @Override
     public void setUploadPolicy(UploadPolicy uploadPolicy) {
         this.uploadPolicy = uploadPolicy;
@@ -389,20 +365,10 @@
     }
 
-    /**
-     * Gets a filtered collection of primitives matching the given predicate.
-     * @param <T> The primitive type.
-     * @param predicate The predicate to match
-     * @return The list of primtives.
-     * @since 10590
-     */
+    @Override
     public <T extends OsmPrimitive> Collection<T> getPrimitives(Predicate<? super OsmPrimitive> predicate) {
         return new SubclassFilteredCollection<>(allPrimitives, predicate);
     }
 
-    /**
-     * Replies an unmodifiable collection of nodes in this dataset
-     *
-     * @return an unmodifiable collection of nodes in this dataset
-     */
+    @Override
     public Collection<Node> getNodes() {
         return getPrimitives(Node.class::isInstance);
@@ -413,5 +379,5 @@
         lock.readLock().lock();
         try {
-            return super.searchNodes(bbox);
+            return store.searchNodes(bbox);
         } finally {
             lock.readLock().unlock();
@@ -419,9 +385,5 @@
     }
 
-    /**
-     * Replies an unmodifiable collection of ways in this dataset
-     *
-     * @return an unmodifiable collection of ways in this dataset
-     */
+    @Override
     public Collection<Way> getWays() {
         return getPrimitives(Way.class::isInstance);
@@ -432,5 +394,5 @@
         lock.readLock().lock();
         try {
-            return super.searchWays(bbox);
+            return store.searchWays(bbox);
         } finally {
             lock.readLock().unlock();
@@ -438,14 +400,9 @@
     }
 
-    /**
-     * Searches for relations in the given bounding box.
-     * @param bbox the bounding box
-     * @return List of relations in the given bbox. Can be empty but not null
-     */
     @Override
     public List<Relation> searchRelations(BBox bbox) {
         lock.readLock().lock();
         try {
-            return super.searchRelations(bbox);
+            return store.searchRelations(bbox);
         } finally {
             lock.readLock().unlock();
@@ -453,9 +410,5 @@
     }
 
-    /**
-     * Replies an unmodifiable collection of relations in this dataset
-     *
-     * @return an unmodifiable collection of relations in this dataset
-     */
+    @Override
     public Collection<Relation> getRelations() {
         return getPrimitives(Relation.class::isInstance);
@@ -463,58 +416,40 @@
 
     /**
-     * Returns a collection containing all primitives of the dataset.
-     * @return A collection containing all primitives of the dataset. Data is not ordered
-     */
-    public Collection<OsmPrimitive> allPrimitives() {
-        return getPrimitives(o -> true);
-    }
-
-    /**
-     * Returns a collection containing all not-deleted primitives.
-     * @return A collection containing all not-deleted primitives.
-     * @see OsmPrimitive#isDeleted
-     */
-    public Collection<OsmPrimitive> allNonDeletedPrimitives() {
-        return getPrimitives(p -> !p.isDeleted());
-    }
-
-    /**
-     * Returns a collection containing all not-deleted complete primitives.
-     * @return A collection containing all not-deleted complete primitives.
-     * @see OsmPrimitive#isDeleted
-     * @see OsmPrimitive#isIncomplete
-     */
-    public Collection<OsmPrimitive> allNonDeletedCompletePrimitives() {
-        return getPrimitives(primitive -> !primitive.isDeleted() && !primitive.isIncomplete());
-    }
-
-    /**
-     * Returns a collection containing all not-deleted complete physical primitives.
-     * @return A collection containing all not-deleted complete physical primitives (nodes and ways).
-     * @see OsmPrimitive#isDeleted
-     * @see OsmPrimitive#isIncomplete
-     */
-    public Collection<OsmPrimitive> allNonDeletedPhysicalPrimitives() {
-        return getPrimitives(
-                primitive -> !primitive.isDeleted() && !primitive.isIncomplete() && !(primitive instanceof Relation));
-    }
-
-    /**
-     * Returns a collection containing all modified primitives.
-     * @return A collection containing all modified primitives.
-     * @see OsmPrimitive#isModified
-     */
-    public Collection<OsmPrimitive> allModifiedPrimitives() {
-        return getPrimitives(OsmPrimitive::isModified);
-    }
-
-    /**
-     * Returns a collection containing all primitives preserved from filtering.
-     * @return A collection containing all primitives preserved from filtering.
-     * @see OsmPrimitive#isPreserved
-     * @since 13309
-     */
-    public Collection<OsmPrimitive> allPreservedPrimitives() {
-        return getPrimitives(OsmPrimitive::isPreserved);
+     * Determines if the given node can be retrieved in the data set through its bounding box. Useful for dataset consistency test.
+     * For efficiency reasons this method does not lock the dataset, you have to lock it manually.
+     *
+     * @param n The node to search
+     * @return {@code true} if {@code n} can be retrieved in this data set, {@code false} otherwise
+     * @since 7501
+     */
+    @Override
+    public boolean containsNode(Node n) {
+        return store.containsNode(n);
+    }
+
+    /**
+     * Determines if the given way can be retrieved in the data set through its bounding box. Useful for dataset consistency test.
+     * For efficiency reasons this method does not lock the dataset, you have to lock it manually.
+     *
+     * @param w The way to search
+     * @return {@code true} if {@code w} can be retrieved in this data set, {@code false} otherwise
+     * @since 7501
+     */
+    @Override
+    public boolean containsWay(Way w) {
+        return store.containsWay(w);
+    }
+
+    /**
+     * Determines if the given relation can be retrieved in the data set through its bounding box. Useful for dataset consistency test.
+     * For efficiency reasons this method does not lock the dataset, you have to lock it manually.
+     *
+     * @param r The relation to search
+     * @return {@code true} if {@code r} can be retrieved in this data set, {@code false} otherwise
+     * @since 7501
+     */
+    @Override
+    public boolean containsRelation(Relation r) {
+        return store.containsRelation(r);
     }
 
@@ -539,5 +474,5 @@
             primitive.setDataset(this);
             primitive.updatePosition(); // Set cached bbox for way and relation (required for reindexWay and reindexRelation to work properly)
-            super.addPrimitive(primitive);
+            store.addPrimitive(primitive);
             firePrimitivesAdded(Collections.singletonList(primitive), false);
         } finally {
@@ -549,6 +484,6 @@
      * Removes a primitive from the dataset. This method only removes the
      * primitive form the respective collection of primitives managed
-     * by this dataset, i.e. from {@link #nodes}, {@link #ways}, or
-     * {@link #relations}. References from other primitives to this
+     * by this dataset, i.e. from {@code store.nodes}, {@code store.ways}, or
+     * {@code store.relations}. References from other primitives to this
      * primitive are left unchanged.
      *
@@ -575,10 +510,9 @@
             throw new DataIntegrityProblemException("Primitive was re-selected by a selection listener: " + primitive);
         }
-        super.removePrimitive(primitive);
+        store.removePrimitive(primitive);
         allPrimitives.remove(primitive);
         primitive.setDataset(null);
     }
 
-    @Override
     protected void removePrimitive(OsmPrimitive primitive) {
         checkModifiable();
@@ -596,21 +530,10 @@
      *---------------------------------------------------*/
 
-    /**
-     * Add a listener that listens to selection changes in this specific data set.
-     * @param listener The listener.
-     * @see #removeSelectionListener(DataSelectionListener)
-     * @see SelectionEventManager#addSelectionListener(SelectionChangedListener,
-     *      org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode)
-     *      To add a global listener.
-     */
+    @Override
     public void addSelectionListener(DataSelectionListener listener) {
         selectionListeners.addListener(listener);
     }
 
-    /**
-     * Remove a listener that listens to selection changes in this specific data set.
-     * @param listener The listener.
-     * @see #addSelectionListener(DataSelectionListener)
-     */
+    @Override
     public void removeSelectionListener(DataSelectionListener listener) {
         selectionListeners.removeListener(listener);
@@ -663,113 +586,60 @@
     }
 
-    /**
-     * Returns an unmodifiable collection of *WaySegments* whose virtual
-     * nodes should be highlighted. WaySegments are used to avoid having
-     * to create a VirtualNode class that wouldn't have much purpose otherwise.
-     *
-     * @return unmodifiable collection of WaySegments
-     */
+    @Override
     public Collection<WaySegment> getHighlightedVirtualNodes() {
         return Collections.unmodifiableCollection(highlightedVirtualNodes);
     }
 
-    /**
-     * Returns an unmodifiable collection of WaySegments that should be highlighted.
-     *
-     * @return unmodifiable collection of WaySegments
-     */
+    @Override
     public Collection<WaySegment> getHighlightedWaySegments() {
         return Collections.unmodifiableCollection(highlightedWaySegments);
     }
 
-    /**
-     * Adds a listener that gets notified whenever way segment / virtual nodes highlights change.
-     * @param listener The Listener
-     * @since 12014
-     */
+    @Override
     public void addHighlightUpdateListener(HighlightUpdateListener listener) {
         highlightUpdateListeners.addListener(listener);
     }
 
-    /**
-     * Removes a listener that was added with {@link #addHighlightUpdateListener(HighlightUpdateListener)}
-     * @param listener The Listener
-     * @since 12014
-     */
+    @Override
     public void removeHighlightUpdateListener(HighlightUpdateListener listener) {
         highlightUpdateListeners.removeListener(listener);
     }
 
-    /**
-     * Replies an unmodifiable collection of primitives currently selected
-     * in this dataset, except deleted ones. May be empty, but not null.
-     *
-     * When iterating through the set it is ordered by the order in which the primitives were added to the selection.
-     *
-     * @return unmodifiable collection of primitives
-     */
+    @Override
     public Collection<OsmPrimitive> getSelected() {
         return new SubclassFilteredCollection<>(getAllSelected(), p -> !p.isDeleted());
     }
 
-    /**
-     * Replies an unmodifiable collection of primitives currently selected
-     * in this dataset, including deleted ones. May be empty, but not null.
-     *
-     * When iterating through the set it is ordered by the order in which the primitives were added to the selection.
-     *
-     * @return unmodifiable collection of primitives
-     */
+    @Override
     public Collection<OsmPrimitive> getAllSelected() {
         return currentSelectedPrimitives;
     }
 
-    /**
-     * Returns selected nodes.
-     * @return selected nodes
-     */
+    @Override
     public Collection<Node> getSelectedNodes() {
         return new SubclassFilteredCollection<>(getSelected(), Node.class::isInstance);
     }
 
-    /**
-     * Returns selected ways.
-     * @return selected ways
-     */
+    @Override
     public Collection<Way> getSelectedWays() {
         return new SubclassFilteredCollection<>(getSelected(), Way.class::isInstance);
     }
 
-    /**
-     * Returns selected relations.
-     * @return selected relations
-     */
+    @Override
     public Collection<Relation> getSelectedRelations() {
         return new SubclassFilteredCollection<>(getSelected(), Relation.class::isInstance);
     }
 
-    /**
-     * Determines whether the selection is empty or not
-     * @return whether the selection is empty or not
-     */
+    @Override
     public boolean selectionEmpty() {
         return currentSelectedPrimitives.isEmpty();
     }
 
-    /**
-     * Determines whether the given primitive is selected or not
-     * @param osm the primitive
-     * @return whether {@code osm} is selected or not
-     */
+    @Override
     public boolean isSelected(OsmPrimitive osm) {
         return currentSelectedPrimitives.contains(osm);
     }
 
-    /**
-     * set what virtual nodes should be highlighted. Requires a Collection of
-     * *WaySegments* to avoid a VirtualNode class that wouldn't have much use
-     * otherwise.
-     * @param waySegments Collection of way segments
-     */
+    @Override
     public void setHighlightedVirtualNodes(Collection<WaySegment> waySegments) {
         if (highlightedVirtualNodes.isEmpty() && waySegments.isEmpty())
@@ -780,8 +650,5 @@
     }
 
-    /**
-     * set what virtual ways should be highlighted.
-     * @param waySegments Collection of way segments
-     */
+    @Override
     public void setHighlightedWaySegments(Collection<WaySegment> waySegments) {
         if (highlightedWaySegments.isEmpty() && waySegments.isEmpty())
@@ -792,20 +659,10 @@
     }
 
-    /**
-     * Sets the current selection to the primitives in <code>selection</code>
-     * and notifies all {@link SelectionChangedListener}.
-     *
-     * @param selection the selection
-     */
+    @Override
     public void setSelected(Collection<? extends PrimitiveId> selection) {
         setSelected(selection.stream());
     }
 
-    /**
-     * Sets the current selection to the primitives in <code>osm</code>
-     * and notifies all {@link SelectionChangedListener}.
-     *
-     * @param osm the primitives to set. <code>null</code> values are ignored for now, but this may be removed in the future.
-     */
+    @Override
     public void setSelected(PrimitiveId... osm) {
         setSelected(Stream.of(osm).filter(Objects::nonNull));
@@ -817,20 +674,10 @@
     }
 
-    /**
-     * Adds the primitives in <code>selection</code> to the current selection
-     * and notifies all {@link SelectionChangedListener}.
-     *
-     * @param selection the selection
-     */
+    @Override
     public void addSelected(Collection<? extends PrimitiveId> selection) {
         addSelected(selection.stream());
     }
 
-    /**
-     * Adds the primitives in <code>osm</code> to the current selection
-     * and notifies all {@link SelectionChangedListener}.
-     *
-     * @param osm the primitives to add
-     */
+    @Override
     public void addSelected(PrimitiveId... osm) {
         addSelected(Stream.of(osm));
@@ -842,23 +689,15 @@
     }
 
-    /**
-     * Removes the selection from every value in the collection.
-     * @param osm The collection of ids to remove the selection from.
-     */
+    @Override
     public void clearSelection(PrimitiveId... osm) {
         clearSelection(Stream.of(osm));
     }
 
-    /**
-     * Removes the selection from every value in the collection.
-     * @param list The collection of ids to remove the selection from.
-     */
+    @Override
     public void clearSelection(Collection<? extends PrimitiveId> list) {
         clearSelection(list.stream());
     }
 
-    /**
-     * Clears the current selection.
-     */
+    @Override
     public void clearSelection() {
         setSelected(Stream.empty());
@@ -870,16 +709,10 @@
     }
 
-    /**
-     * Toggles the selected state of the given collection of primitives.
-     * @param osm The primitives to toggle
-     */
+    @Override
     public void toggleSelected(Collection<? extends PrimitiveId> osm) {
         toggleSelected(osm.stream());
     }
 
-    /**
-     * Toggles the selected state of the given collection of primitives.
-     * @param osm The primitives to toggle
-     */
+    @Override
     public void toggleSelected(PrimitiveId... osm) {
         toggleSelected(Stream.of(osm));
@@ -911,14 +744,10 @@
     }
 
-    /**
-     * clear all highlights of virtual nodes
-     */
+    @Override
     public void clearHighlightedVirtualNodes() {
         setHighlightedVirtualNodes(new ArrayList<WaySegment>());
     }
 
-    /**
-     * clear all highlights of way segments
-     */
+    @Override
     public void clearHighlightedWaySegments() {
         setHighlightedWaySegments(new ArrayList<WaySegment>());
@@ -928,5 +757,5 @@
     public synchronized Area getDataSourceArea() {
         if (cachedDataSourceArea == null) {
-            cachedDataSourceArea = Data.super.getDataSourceArea();
+            cachedDataSourceArea = OsmData.super.getDataSourceArea();
         }
         return cachedDataSourceArea;
@@ -936,5 +765,5 @@
     public synchronized List<Bounds> getDataSourceBounds() {
         if (cachedDataSourceBounds == null) {
-            cachedDataSourceBounds = Data.super.getDataSourceBounds();
+            cachedDataSourceBounds = OsmData.super.getDataSourceBounds();
         }
         return Collections.unmodifiableList(cachedDataSourceBounds);
@@ -946,22 +775,10 @@
     }
 
-    /**
-     * Returns a primitive with a given id from the data set. null, if no such primitive exists
-     *
-     * @param id  uniqueId of the primitive. Might be &lt; 0 for newly created primitives
-     * @param type the type of  the primitive. Must not be null.
-     * @return the primitive
-     * @throws NullPointerException if type is null
-     */
+    @Override
     public OsmPrimitive getPrimitiveById(long id, OsmPrimitiveType type) {
         return getPrimitiveById(new SimplePrimitiveId(id, type));
     }
 
-    /**
-     * Returns a primitive with a given id from the data set. null, if no such primitive exists
-     *
-     * @param primitiveId type and uniqueId of the primitive. Might be &lt; 0 for newly created primitives
-     * @return the primitive
-     */
+    @Override
     public OsmPrimitive getPrimitiveById(PrimitiveId primitiveId) {
         return primitiveId != null ? primitivesMap.get(primitiveId) : null;
@@ -1078,11 +895,5 @@
     }
 
-    /**
-     * Replies true if there is at least one primitive in this dataset with
-     * {@link OsmPrimitive#isModified()} == <code>true</code>.
-     *
-     * @return true if there is at least one primitive in this dataset with
-     * {@link OsmPrimitive#isModified()} == <code>true</code>.
-     */
+    @Override
     public boolean isModified() {
         for (OsmPrimitive p : allPrimitives) {
@@ -1216,15 +1027,15 @@
 
     void fireRelationMembersChanged(Relation r) {
-        reindexRelation(r);
+        store.reindexRelation(r, Relation::updatePosition);
         fireEvent(new RelationMembersChangedEvent(this, r));
     }
 
     void fireNodeMoved(Node node, LatLon newCoor, EastNorth eastNorth) {
-        reindexNode(node, newCoor, eastNorth);
+        store.reindexNode(node, n -> n.setCoorInternal(newCoor, eastNorth), Way::updatePosition, Relation::updatePosition);
         fireEvent(new NodeMovedEvent(this, node));
     }
 
     void fireWayNodesChanged(Way way) {
-        reindexWay(way);
+        store.reindexWay(way, Way::updatePosition, Relation::updatePosition);
         fireEvent(new WayNodesChangedEvent(this, way));
     }
@@ -1302,5 +1113,5 @@
                 primitive.setDataset(null);
             }
-            super.clear();
+            store.clear();
             allPrimitives.clear();
         } finally {
@@ -1365,18 +1176,10 @@
     }
 
-    /**
-     * Returns the name of this data set (optional).
-     * @return the name of this data set. Can be {@code null}
-     * @since 12718
-     */
+    @Override
     public String getName() {
         return name;
     }
 
-    /**
-     * Sets the name of this data set.
-     * @param name the new name of this data set. Can be {@code null} to reset it
-     * @since 12718
-     */
+    @Override
     public void setName(String name) {
         this.name = name;
@@ -1391,8 +1194,5 @@
     }
 
-    /**
-     * Returns the data sources bounding box.
-     * @return the data sources bounding box
-     */
+    @Override
     public synchronized ProjectionBounds getDataSourceBoundingBox() {
         BoundingXYVisitor bbox = new BoundingXYVisitor();
@@ -1418,8 +1218,5 @@
     }
 
-    /**
-     * Clear the mappaint cache for this DataSet.
-     * @since 13420
-     */
+    @Override
     public void clearMappaintCache() {
         mappaintCacheIdx++;
Index: /trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 13764)
@@ -3,4 +3,5 @@
 
 import java.util.Date;
+import java.util.List;
 
 import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
@@ -115,4 +116,13 @@
      */
     default boolean isDisabledAndHidden() {
+        return false;
+    }
+
+    /**
+     * Replies true, if this primitive is preserved from filtering.
+     * @return {@code true} if this object has the "preserved" flag enabled
+     * @since 13764
+     */
+    default boolean isPreserved() {
         return false;
     }
@@ -385,3 +395,17 @@
      */
     boolean reversedDirection();
+
+    /**
+     * Fetches the bounding box of the primitive.
+     * @return Bounding box of the object
+     * @since 13764
+     */
+    BBox getBBox();
+
+    /**
+     * Gets a list of all primitives in the current dataset that reference this primitive.
+     * @return The referrers
+     * @since 13764
+     */
+    List<? extends IPrimitive> getReferrers();
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/NodeData.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/NodeData.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/osm/NodeData.java	(revision 13764)
@@ -101,4 +101,9 @@
 
     @Override
+    public BBox getBBox() {
+        return new BBox(lon, lat);
+    }
+
+    @Override
     public boolean isReferredByWays(int n) {
         return false;
Index: /trunk/src/org/openstreetmap/josm/data/osm/OsmData.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/OsmData.java	(revision 13764)
+++ /trunk/src/org/openstreetmap/josm/data/osm/OsmData.java	(revision 13764)
@@ -0,0 +1,483 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.locks.Lock;
+import java.util.function.Predicate;
+
+import org.openstreetmap.josm.data.Data;
+import org.openstreetmap.josm.data.DataSource;
+import org.openstreetmap.josm.data.ProjectionBounds;
+import org.openstreetmap.josm.data.SelectionChangedListener;
+import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
+import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+
+/**
+ * Abstraction of {@link DataSet}.
+ * This class holds OSM data but does not rely on implementation types,
+ * allowing plugins to define their own representation of OSM data if needed.
+ * @param <O> the base type of OSM primitives
+ * @param <N> type representing OSM nodes
+ * @param <W> type representing OSM ways
+ * @param <R> type representing OSM relations
+ * @since 13764
+ */
+public interface OsmData<O extends IPrimitive, N extends INode, W extends IWay<N>, R extends IRelation> extends Data, Lockable {
+
+    // --------------
+    //    Metadata
+    // --------------
+
+    /**
+     * Replies the API version this dataset was created from. May be null.
+     * @return the API version this dataset was created from. May be null.
+     */
+    String getVersion();
+
+    /**
+     * Returns the name of this data set (optional).
+     * @return the name of this data set. Can be {@code null}
+     * @since 12718
+     */
+    String getName();
+
+    /**
+     * Sets the name of this data set.
+     * @param name the new name of this data set. Can be {@code null} to reset it
+     * @since 12718
+     */
+    void setName(String name);
+
+    // --------------------
+    //    OSM primitives
+    // --------------------
+
+    /**
+     * Adds a primitive.
+     * @param primitive the primitive
+     */
+    void addPrimitive(O primitive);
+
+    /**
+     * Removes all primitives.
+     */
+    void clear();
+
+    /**
+     * Searches for nodes in the given bounding box.
+     * @param bbox the bounding box
+     * @return List of nodes in the given bbox. Can be empty but not null
+     */
+    List<N> searchNodes(BBox bbox);
+
+    /**
+     * Determines if the given node can be retrieved in the data set through its bounding box. Useful for dataset consistency test.
+     * @param n The node to search
+     * @return {@code true} if {@code n} can be retrieved in this data set, {@code false} otherwise
+     */
+    boolean containsNode(N n);
+
+    /**
+     * Searches for ways in the given bounding box.
+     * @param bbox the bounding box
+     * @return List of ways in the given bbox. Can be empty but not null
+     */
+    List<W> searchWays(BBox bbox);
+
+    /**
+     * Determines if the given way can be retrieved in the data set through its bounding box. Useful for dataset consistency test.
+     * @param w The way to search
+     * @return {@code true} if {@code w} can be retrieved in this data set, {@code false} otherwise
+     */
+    boolean containsWay(W w);
+
+    /**
+     * Searches for relations in the given bounding box.
+     * @param bbox the bounding box
+     * @return List of relations in the given bbox. Can be empty but not null
+     */
+    List<R> searchRelations(BBox bbox);
+
+    /**
+     * Determines if the given relation can be retrieved in the data set through its bounding box. Useful for dataset consistency test.
+     * @param r The relation to search
+     * @return {@code true} if {@code r} can be retrieved in this data set, {@code false} otherwise
+     */
+    boolean containsRelation(R r);
+
+    /**
+     * Returns a primitive with a given id from the data set. null, if no such primitive exists
+     *
+     * @param id uniqueId of the primitive. Might be &lt; 0 for newly created primitives
+     * @param type the type of  the primitive. Must not be null.
+     * @return the primitive
+     * @throws NullPointerException if type is null
+     */
+    O getPrimitiveById(long id, OsmPrimitiveType type);
+
+    /**
+     * Returns a primitive with a given id from the data set. null, if no such primitive exists
+     *
+     * @param primitiveId type and uniqueId of the primitive. Might be &lt; 0 for newly created primitives
+     * @return the primitive
+     */
+    O getPrimitiveById(PrimitiveId primitiveId);
+
+    /**
+     * Gets a filtered collection of primitives matching the given predicate.
+     * @param <T> The primitive type.
+     * @param predicate The predicate to match
+     * @return The list of primtives.
+     * @since 10590
+     */
+    <T extends O> Collection<T> getPrimitives(Predicate<? super O> predicate);
+
+    /**
+     * Replies an unmodifiable collection of nodes in this dataset
+     *
+     * @return an unmodifiable collection of nodes in this dataset
+     */
+    Collection<N> getNodes();
+
+    /**
+     * Replies an unmodifiable collection of ways in this dataset
+     *
+     * @return an unmodifiable collection of ways in this dataset
+     */
+    Collection<W> getWays();
+
+    /**
+     * Replies an unmodifiable collection of relations in this dataset
+     *
+     * @return an unmodifiable collection of relations in this dataset
+     */
+    Collection<R> getRelations();
+
+    /**
+     * Returns a collection containing all primitives of the dataset.
+     * @return A collection containing all primitives of the dataset. Data is not ordered
+     */
+    default Collection<O> allPrimitives() {
+        return getPrimitives(o -> true);
+    }
+
+    /**
+     * Returns a collection containing all not-deleted primitives.
+     * @return A collection containing all not-deleted primitives.
+     * @see OsmPrimitive#isDeleted
+     */
+    default Collection<O> allNonDeletedPrimitives() {
+        return getPrimitives(p -> !p.isDeleted());
+    }
+
+    /**
+     * Returns a collection containing all not-deleted complete primitives.
+     * @return A collection containing all not-deleted complete primitives.
+     * @see OsmPrimitive#isDeleted
+     * @see OsmPrimitive#isIncomplete
+     */
+    default Collection<O> allNonDeletedCompletePrimitives() {
+        return getPrimitives(primitive -> !primitive.isDeleted() && !primitive.isIncomplete());
+    }
+
+    /**
+     * Returns a collection containing all not-deleted complete physical primitives.
+     * @return A collection containing all not-deleted complete physical primitives (nodes and ways).
+     * @see OsmPrimitive#isDeleted
+     * @see OsmPrimitive#isIncomplete
+     */
+    default Collection<O> allNonDeletedPhysicalPrimitives() {
+        return getPrimitives(
+                primitive -> !primitive.isDeleted() && !primitive.isIncomplete() && !(primitive instanceof IRelation));
+    }
+
+    /**
+     * Returns a collection containing all modified primitives.
+     * @return A collection containing all modified primitives.
+     * @see OsmPrimitive#isModified
+     */
+    default Collection<O> allModifiedPrimitives() {
+        return getPrimitives(IPrimitive::isModified);
+    }
+
+    /**
+     * Returns a collection containing all primitives preserved from filtering.
+     * @return A collection containing all primitives preserved from filtering.
+     * @see OsmPrimitive#isPreserved
+     * @since 13309
+     */
+    default Collection<O> allPreservedPrimitives() {
+        return getPrimitives(IPrimitive::isPreserved);
+    }
+
+    // --------------
+    //    Policies
+    // --------------
+
+    /**
+     * Get the download policy.
+     * @return the download policy
+     * @see #setDownloadPolicy(DownloadPolicy)
+     * @since 13453
+     */
+    DownloadPolicy getDownloadPolicy();
+
+    /**
+     * Sets the download policy.
+     * @param downloadPolicy the download policy
+     * @see #getUploadPolicy()
+     * @since 13453
+     */
+    void setDownloadPolicy(DownloadPolicy downloadPolicy);
+
+    /**
+     * Get the upload policy.
+     * @return the upload policy
+     * @see #setUploadPolicy(UploadPolicy)
+     */
+    UploadPolicy getUploadPolicy();
+
+    /**
+     * Sets the upload policy.
+     * @param uploadPolicy the upload policy
+     * @see #getUploadPolicy()
+     */
+    void setUploadPolicy(UploadPolicy uploadPolicy);
+
+    // --------------
+    //    Locks
+    // --------------
+
+    /**
+     * Returns the lock used for reading.
+     * @return the lock used for reading
+     */
+    Lock getReadLock();
+
+    // ---------------
+    //    Highlight
+    // ---------------
+
+    /**
+     * Returns an unmodifiable collection of *WaySegments* whose virtual
+     * nodes should be highlighted. WaySegments are used to avoid having
+     * to create a VirtualNode class that wouldn't have much purpose otherwise.
+     *
+     * @return unmodifiable collection of WaySegments
+     */
+    Collection<WaySegment> getHighlightedVirtualNodes();
+
+    /**
+     * Returns an unmodifiable collection of WaySegments that should be highlighted.
+     *
+     * @return unmodifiable collection of WaySegments
+     */
+    Collection<WaySegment> getHighlightedWaySegments();
+
+    /**
+     * clear all highlights of virtual nodes
+     */
+    void clearHighlightedVirtualNodes();
+
+    /**
+     * clear all highlights of way segments
+     */
+    void clearHighlightedWaySegments();
+
+    /**
+     * set what virtual nodes should be highlighted. Requires a Collection of
+     * *WaySegments* to avoid a VirtualNode class that wouldn't have much use otherwise.
+     * @param waySegments Collection of way segments
+     */
+    void setHighlightedVirtualNodes(Collection<WaySegment> waySegments);
+
+    /**
+     * set what virtual ways should be highlighted.
+     * @param waySegments Collection of way segments
+     */
+    void setHighlightedWaySegments(Collection<WaySegment> waySegments);
+
+    /**
+     * Adds a listener that gets notified whenever way segment / virtual nodes highlights change.
+     * @param listener The Listener
+     * @since 12014
+     */
+    void addHighlightUpdateListener(HighlightUpdateListener listener);
+
+    /**
+     * Removes a listener that was added with {@link #addHighlightUpdateListener(HighlightUpdateListener)}
+     * @param listener The Listener
+     * @since 12014
+     */
+    void removeHighlightUpdateListener(HighlightUpdateListener listener);
+
+    // ---------------
+    //    Selection
+    // ---------------
+
+    /**
+     * Replies an unmodifiable collection of primitives currently selected
+     * in this dataset, except deleted ones. May be empty, but not null.
+     *
+     * When iterating through the set it is ordered by the order in which the primitives were added to the selection.
+     *
+     * @return unmodifiable collection of primitives
+     */
+    Collection<O> getSelected();
+
+    /**
+     * Replies an unmodifiable collection of primitives currently selected
+     * in this dataset, including deleted ones. May be empty, but not null.
+     *
+     * When iterating through the set it is ordered by the order in which the primitives were added to the selection.
+     *
+     * @return unmodifiable collection of primitives
+     */
+    Collection<O> getAllSelected();
+
+    /**
+     * Returns selected nodes.
+     * @return selected nodes
+     */
+    Collection<N> getSelectedNodes();
+
+    /**
+     * Returns selected ways.
+     * @return selected ways
+     */
+    Collection<W> getSelectedWays();
+
+    /**
+     * Returns selected relations.
+     * @return selected relations
+     */
+    Collection<R> getSelectedRelations();
+
+    /**
+     * Determines whether the selection is empty or not
+     * @return whether the selection is empty or not
+     */
+    boolean selectionEmpty();
+
+    /**
+     * Determines whether the given primitive is selected or not
+     * @param osm the primitive
+     * @return whether {@code osm} is selected or not
+     */
+    boolean isSelected(O osm);
+
+    /**
+     * Toggles the selected state of the given collection of primitives.
+     * @param osm The primitives to toggle
+     */
+    void toggleSelected(Collection<? extends PrimitiveId> osm);
+
+    /**
+     * Toggles the selected state of the given collection of primitives.
+     * @param osm The primitives to toggle
+     */
+    void toggleSelected(PrimitiveId... osm);
+
+    /**
+     * Sets the current selection to the primitives in <code>selection</code>
+     * and notifies all {@link SelectionChangedListener}.
+     *
+     * @param selection the selection
+     */
+    void setSelected(Collection<? extends PrimitiveId> selection);
+
+    /**
+     * Sets the current selection to the primitives in <code>osm</code>
+     * and notifies all {@link SelectionChangedListener}.
+     *
+     * @param osm the primitives to set. <code>null</code> values are ignored for now, but this may be removed in the future.
+     */
+    void setSelected(PrimitiveId... osm);
+
+    /**
+     * Adds the primitives in <code>selection</code> to the current selection
+     * and notifies all {@link SelectionChangedListener}.
+     *
+     * @param selection the selection
+     */
+    void addSelected(Collection<? extends PrimitiveId> selection);
+
+    /**
+     * Adds the primitives in <code>osm</code> to the current selection
+     * and notifies all {@link SelectionChangedListener}.
+     *
+     * @param osm the primitives to add
+     */
+    void addSelected(PrimitiveId... osm);
+
+    /**
+     * Removes the selection from every value in the collection.
+     * @param osm The collection of ids to remove the selection from.
+     */
+    void clearSelection(PrimitiveId... osm);
+
+    /**
+     * Removes the selection from every value in the collection.
+     * @param list The collection of ids to remove the selection from.
+     */
+    void clearSelection(Collection<? extends PrimitiveId> list);
+
+    /**
+     * Clears the current selection.
+     */
+    void clearSelection();
+
+    /**
+     * Add a listener that listens to selection changes in this specific data set.
+     * @param listener The listener.
+     * @see #removeSelectionListener(DataSelectionListener)
+     * @see SelectionEventManager#addSelectionListener(SelectionChangedListener,
+     *      org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode)
+     *      To add a global listener.
+     */
+    void addSelectionListener(DataSelectionListener listener);
+
+    /**
+     * Remove a listener that listens to selection changes in this specific data set.
+     * @param listener The listener.
+     * @see #addSelectionListener(DataSelectionListener)
+     */
+    void removeSelectionListener(DataSelectionListener listener);
+
+    // -------------------
+    //    Miscellaneous
+    // -------------------
+
+    /**
+     * Returns the data sources bounding box.
+     * @return the data sources bounding box
+     */
+    default ProjectionBounds getDataSourceBoundingBox() {
+        BoundingXYVisitor bbox = new BoundingXYVisitor();
+        for (DataSource source : getDataSources()) {
+            bbox.visit(source.bounds);
+        }
+        if (bbox.hasExtend()) {
+            return bbox.getBounds();
+        }
+        return null;
+    }
+
+    /**
+     * Clear the mappaint cache for this DataSet.
+     * @since 13420
+     */
+    void clearMappaintCache();
+
+    /**
+     * Replies true if there is at least one primitive in this dataset with
+     * {@link IPrimitive#isModified()} == <code>true</code>.
+     *
+     * @return true if there is at least one primitive in this dataset with
+     * {@link IPrimitive#isModified()} == <code>true</code>.
+     */
+    default boolean isModified() {
+        return false;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 13764)
@@ -471,9 +471,5 @@
     }
 
-    /**
-     * Replies true, if this primitive is preserved from filtering.
-     * @return {@code true} if this object has the "preserved" flag enabled
-     * @since 13309
-     */
+    @Override
     public boolean isPreserved() {
         return (flags & FLAG_PRESERVED) != 0;
@@ -990,8 +986,5 @@
     }
 
-    /**
-     * Gets a list of all primitives in the current dataset that reference this primitive.
-     * @return The referrers
-     */
+    @Override
     public final List<OsmPrimitive> getReferrers() {
         return getReferrers(false);
@@ -1213,10 +1206,4 @@
 
     /**
-     * Fetch the bounding box of the primitive
-     * @return Bounding box of the object
-     */
-    public abstract BBox getBBox();
-
-    /**
      * Called by Dataset to update cached position information of primitive (bbox, cached EarthNorth, ...)
      */
Index: /trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java	(revision 13764)
@@ -9,4 +9,5 @@
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -164,4 +165,9 @@
 
     @Override
+    public final List<PrimitiveData> getReferrers() {
+        return Collections.emptyList();
+    }
+
+    @Override
     public StyleCache getCachedStyle() {
         return null;
Index: /trunk/src/org/openstreetmap/josm/data/osm/QuadBucketPrimitiveStore.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/QuadBucketPrimitiveStore.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/osm/QuadBucketPrimitiveStore.java	(revision 13764)
@@ -5,8 +5,7 @@
 import java.util.Collection;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.tools.JosmRuntimeException;
 
@@ -16,12 +15,15 @@
  * This class does not do any synchronization.
  * @author Michael Zangl
+ * @param <N> type representing OSM nodes
+ * @param <W> type representing OSM ways
+ * @param <R> type representing OSM relations
  * @since 12048
  */
-public class QuadBucketPrimitiveStore {
+public class QuadBucketPrimitiveStore<N extends INode, W extends IWay<N>, R extends IRelation> {
     /**
      * All nodes goes here, even when included in other data (ways etc). This enables the instant
      * conversion of the whole DataSet by iterating over this data structure.
      */
-    private final QuadBuckets<Node> nodes = new QuadBuckets<>();
+    private final QuadBuckets<N> nodes = new QuadBuckets<>();
 
     /**
@@ -30,10 +32,16 @@
      * The way nodes are stored only in the way list.
      */
-    private final QuadBuckets<Way> ways = new QuadBuckets<>();
+    private final QuadBuckets<W> ways = new QuadBuckets<>();
 
     /**
      * All relations/relationships
      */
-    private final Collection<Relation> relations = new ArrayList<>();
+    private final Collection<R> relations = new ArrayList<>();
+
+    /**
+     * Constructs a new {@code QuadBucketPrimitiveStore}.
+     */
+    public QuadBucketPrimitiveStore() {
+    }
 
     /**
@@ -42,17 +50,14 @@
      * @return List of nodes in the given bbox. Can be empty but not null
      */
-    public List<Node> searchNodes(BBox bbox) {
+    public List<N> searchNodes(BBox bbox) {
         return nodes.search(bbox);
     }
 
     /**
-     * Determines if the given node can be retrieved in the data set through its bounding box. Useful for dataset consistency test.
-     * For efficiency reasons this method does not lock the dataset, you have to lock it manually.
-     *
+     * Determines if the given node can be retrieved in the store through its bounding box. Useful for dataset consistency test.
      * @param n The node to search
-     * @return {@code true} if {@code n} ban be retrieved in this data set, {@code false} otherwise
-     * @since 7501
-     */
-    public boolean containsNode(Node n) {
+     * @return {@code true} if {@code n} can be retrieved in this store, {@code false} otherwise
+     */
+    public boolean containsNode(N n) {
         return nodes.contains(n);
     }
@@ -63,17 +68,14 @@
      * @return List of ways in the given bbox. Can be empty but not null
      */
-    public List<Way> searchWays(BBox bbox) {
+    public List<W> searchWays(BBox bbox) {
         return ways.search(bbox);
     }
 
     /**
-     * Determines if the given way can be retrieved in the data set through its bounding box. Useful for dataset consistency test.
-     * For efficiency reasons this method does not lock the dataset, you have to lock it manually.
-     *
+     * Determines if the given way can be retrieved in the store through its bounding box. Useful for dataset consistency test.
      * @param w The way to search
-     * @return {@code true} if {@code w} ban be retrieved in this data set, {@code false} otherwise
-     * @since 7501
-     */
-    public boolean containsWay(Way w) {
+     * @return {@code true} if {@code w} can be retrieved in this store, {@code false} otherwise
+     */
+    public boolean containsWay(W w) {
         return ways.contains(w);
     }
@@ -84,5 +86,5 @@
      * @return List of relations in the given bbox. Can be empty but not null
      */
-    public List<Relation> searchRelations(BBox bbox) {
+    public List<R> searchRelations(BBox bbox) {
         // QuadBuckets might be useful here (don't forget to do reindexing after some of rm is changed)
         return relations.stream()
@@ -92,12 +94,9 @@
 
     /**
-     * Determines if the given relation can be retrieved in the data set through its bounding box. Useful for dataset consistency test.
-     * For efficiency reasons this method does not lock the dataset, you have to lock it manually.
-     *
+     * Determines if the given relation can be retrieved in the store through its bounding box. Useful for dataset consistency test.
      * @param r The relation to search
-     * @return {@code true} if {@code r} ban be retrieved in this data set, {@code false} otherwise
-     * @since 7501
-     */
-    public boolean containsRelation(Relation r) {
+     * @return {@code true} if {@code r} can be retrieved in this store, {@code false} otherwise
+     */
+    public boolean containsRelation(R r) {
         return relations.contains(r);
     }
@@ -108,12 +107,13 @@
      * @param primitive the primitive.
      */
-    public void addPrimitive(OsmPrimitive primitive) {
+    @SuppressWarnings("unchecked")
+    public void addPrimitive(IPrimitive primitive) {
         boolean success = false;
-        if (primitive instanceof Node) {
-            success = nodes.add((Node) primitive);
-        } else if (primitive instanceof Way) {
-            success = ways.add((Way) primitive);
-        } else if (primitive instanceof Relation) {
-            success = relations.add((Relation) primitive);
+        if (primitive instanceof INode) {
+            success = nodes.add((N) primitive);
+        } else if (primitive instanceof IWay) {
+            success = ways.add((W) primitive);
+        } else if (primitive instanceof IRelation) {
+            success = relations.add((R) primitive);
         }
         if (!success) {
@@ -122,11 +122,11 @@
     }
 
-    protected void removePrimitive(OsmPrimitive primitive) {
+    protected void removePrimitive(IPrimitive primitive) {
         boolean success = false;
-        if (primitive instanceof Node) {
+        if (primitive instanceof INode) {
             success = nodes.remove(primitive);
-        } else if (primitive instanceof Way) {
+        } else if (primitive instanceof IWay) {
             success = ways.remove(primitive);
-        } else if (primitive instanceof Relation) {
+        } else if (primitive instanceof IRelation) {
             success = relations.remove(primitive);
         }
@@ -137,20 +137,22 @@
 
     /**
-     * Re-index the relation after it's position was changed.
+     * Re-index the node after it's position was changed.
      * @param node The node to re-index
-     * @param newCoor The new coordinates
-     * @param eastNorth The new east/north position
-     */
-    protected void reindexNode(Node node, LatLon newCoor, EastNorth eastNorth) {
+     * @param nUpdater update node position
+     * @param wUpdater update way position
+     * @param rUpdater update relation position
+     */
+    @SuppressWarnings("unchecked")
+    protected void reindexNode(N node, Consumer<N> nUpdater, Consumer<W> wUpdater, Consumer<R> rUpdater) {
         if (!nodes.remove(node))
             throw new JosmRuntimeException("Reindexing node failed to remove");
-        node.setCoorInternal(newCoor, eastNorth);
+        nUpdater.accept(node);
         if (!nodes.add(node))
             throw new JosmRuntimeException("Reindexing node failed to add");
-        for (OsmPrimitive primitive: node.getReferrers()) {
-            if (primitive instanceof Way) {
-                reindexWay((Way) primitive);
+        for (IPrimitive primitive: node.getReferrers()) {
+            if (primitive instanceof IWay) {
+                reindexWay((W) primitive, wUpdater, rUpdater);
             } else {
-                reindexRelation((Relation) primitive);
+                reindexRelation((R) primitive, rUpdater);
             }
         }
@@ -160,15 +162,18 @@
      * Re-index the way after it's position was changed.
      * @param way The way to re-index
-     */
-    protected void reindexWay(Way way) {
+     * @param wUpdater update way position
+     * @param rUpdater update relation position
+     */
+    @SuppressWarnings("unchecked")
+    protected void reindexWay(W way, Consumer<W> wUpdater, Consumer<R> rUpdater) {
         BBox before = way.getBBox();
         if (!ways.remove(way))
             throw new JosmRuntimeException("Reindexing way failed to remove");
-        way.updatePosition();
+        wUpdater.accept(way);
         if (!ways.add(way))
             throw new JosmRuntimeException("Reindexing way failed to add");
         if (!way.getBBox().equals(before)) {
-            for (OsmPrimitive primitive: way.getReferrers()) {
-                reindexRelation((Relation) primitive);
+            for (IPrimitive primitive: way.getReferrers()) {
+                reindexRelation((R) primitive, rUpdater);
             }
         }
@@ -178,15 +183,16 @@
      * Re-index the relation after it's position was changed.
      * @param relation The relation to re-index
-     */
-    protected static void reindexRelation(Relation relation) {
+     * @param rUpdater update relation position
+     */
+    @SuppressWarnings("unchecked")
+    protected void reindexRelation(R relation, Consumer<R> rUpdater) {
         BBox before = relation.getBBox();
-        relation.updatePosition();
+        rUpdater.accept(relation);
         if (!before.equals(relation.getBBox())) {
-            for (OsmPrimitive primitive: relation.getReferrers()) {
-                reindexRelation((Relation) primitive);
+            for (IPrimitive primitive: relation.getReferrers()) {
+                reindexRelation((R) primitive, rUpdater);
             }
         }
     }
-
 
     /**
Index: /trunk/src/org/openstreetmap/josm/data/osm/QuadBuckets.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/QuadBuckets.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/osm/QuadBuckets.java	(revision 13764)
@@ -22,5 +22,5 @@
  * @since 2165
  */
-public class QuadBuckets<T extends OsmPrimitive> implements Collection<T> {
+public class QuadBuckets<T extends IPrimitive> implements Collection<T> {
     private static final boolean CONSISTENCY_TESTING = false;
     private static final byte NW_INDEX = 1;
@@ -35,5 +35,5 @@
     private static final int MAX_OBJECTS_PER_NODE = 48;
 
-    static class QBLevel<T extends OsmPrimitive> extends BBox {
+    static class QBLevel<T extends IPrimitive> extends BBox {
         private final byte level;
         private final byte index;
Index: /trunk/src/org/openstreetmap/josm/data/osm/RelationData.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/RelationData.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/osm/RelationData.java	(revision 13764)
@@ -97,3 +97,7 @@
     }
 
+    @Override
+    public BBox getBBox() {
+        throw new UnsupportedOperationException();
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/WayData.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/WayData.java	(revision 13763)
+++ /trunk/src/org/openstreetmap/josm/data/osm/WayData.java	(revision 13764)
@@ -99,3 +99,7 @@
     }
 
+    @Override
+    public BBox getBBox() {
+        throw new UnsupportedOperationException();
+    }
 }
