// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.data.osm; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor; /** * This class allows to create and keep a deep copy of primitives. Provides methods to access directly added * primitives and reference primitives * */ public class PrimitiveDeepCopy { public interface PasteBufferChangedListener { void pasteBufferChanged(PrimitiveDeepCopy pasteBuffer); } private final List directlyAdded = new ArrayList(); private final List referenced = new ArrayList(); private final CopyOnWriteArrayList listeners = new CopyOnWriteArrayList(); public PrimitiveDeepCopy() { } public PrimitiveDeepCopy(final Collection primitives) { makeCopy(primitives); } /** * Replace content of the object with copy of provided primitives * @param primitives */ public final void makeCopy(final Collection primitives) { directlyAdded.clear(); referenced.clear(); final Set visitedNodeIds = new HashSet(); final Set visitedWayIds = new HashSet(); final Set visitedRelationIds = new HashSet(); new AbstractVisitor() { boolean firstIteration; public void visit(Node n) { if (!visitedNodeIds.add(n.getUniqueId())) return; (firstIteration ? directlyAdded : referenced).add(n.save()); } public void visit(Way w) { if (!visitedWayIds.add(w.getUniqueId())) return; (firstIteration ? directlyAdded : referenced).add(w.save()); firstIteration = false; for (Node n : w.getNodes()) { visit(n); } } public void visit(Relation r) { if (!visitedRelationIds.add(r.getUniqueId())) return; (firstIteration ? directlyAdded : referenced).add(r.save()); firstIteration = false; for (RelationMember m : r.getMembers()) { m.getMember().visit(this); } } public void visitAll() { for (OsmPrimitive osm : primitives) { firstIteration = true; osm.visit(this); } } }.visitAll(); firePasteBufferChanged(); } public List getDirectlyAdded() { return directlyAdded; } public List getReferenced() { return referenced; } public List getAll() { List result = new ArrayList(directlyAdded.size() + referenced.size()); result.addAll(directlyAdded); result.addAll(referenced); return result; } public boolean isEmpty() { return directlyAdded.isEmpty() && referenced.isEmpty(); } private void firePasteBufferChanged() { for (PasteBufferChangedListener listener: listeners) { listener.pasteBufferChanged(this); } } public void addPasteBufferChangedListener(PasteBufferChangedListener listener) { listeners.addIfAbsent(listener); } public void removePasteBufferChangedListener(PasteBufferChangedListener listener) { listeners.remove(listener); } }