001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.data.osm;
003
004 import java.util.ArrayList;
005 import java.util.Collection;
006 import java.util.HashSet;
007 import java.util.List;
008 import java.util.Set;
009 import java.util.concurrent.CopyOnWriteArrayList;
010
011 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
012
013 /**
014 * This class allows to create and keep a deep copy of primitives. Provides methods to access directly added
015 * primitives and reference primitives
016 *
017 */
018 public class PrimitiveDeepCopy {
019
020 public interface PasteBufferChangedListener {
021 void pasteBufferChanged(PrimitiveDeepCopy pasteBuffer);
022 }
023
024 private final List<PrimitiveData> directlyAdded = new ArrayList<PrimitiveData>();
025 private final List<PrimitiveData> referenced = new ArrayList<PrimitiveData>();
026 private final CopyOnWriteArrayList<PasteBufferChangedListener> listeners = new CopyOnWriteArrayList<PasteBufferChangedListener>();
027
028 public PrimitiveDeepCopy() {
029
030 }
031
032 public PrimitiveDeepCopy(final Collection<OsmPrimitive> primitives) {
033 makeCopy(primitives);
034 }
035
036 /**
037 * Replace content of the object with copy of provided primitives
038 * @param primitives
039 */
040 public final void makeCopy(final Collection<OsmPrimitive> primitives) {
041 directlyAdded.clear();
042 referenced.clear();
043
044 final Set<Long> visitedNodeIds = new HashSet<Long>();
045 final Set<Long> visitedWayIds = new HashSet<Long>();
046 final Set<Long> visitedRelationIds = new HashSet<Long>();
047
048 new AbstractVisitor() {
049 boolean firstIteration;
050
051 public void visit(Node n) {
052 if (!visitedNodeIds.add(n.getUniqueId()))
053 return;
054 (firstIteration ? directlyAdded : referenced).add(n.save());
055 }
056 public void visit(Way w) {
057 if (!visitedWayIds.add(w.getUniqueId()))
058 return;
059 (firstIteration ? directlyAdded : referenced).add(w.save());
060 firstIteration = false;
061 for (Node n : w.getNodes()) {
062 visit(n);
063 }
064 }
065 public void visit(Relation r) {
066 if (!visitedRelationIds.add(r.getUniqueId()))
067 return;
068 (firstIteration ? directlyAdded : referenced).add(r.save());
069 firstIteration = false;
070 for (RelationMember m : r.getMembers()) {
071 m.getMember().visit(this);
072 }
073 }
074
075 public void visitAll() {
076 for (OsmPrimitive osm : primitives) {
077 firstIteration = true;
078 osm.visit(this);
079 }
080 }
081 }.visitAll();
082
083 firePasteBufferChanged();
084 }
085
086 public List<PrimitiveData> getDirectlyAdded() {
087 return directlyAdded;
088 }
089
090 public List<PrimitiveData> getReferenced() {
091 return referenced;
092 }
093
094 public List<PrimitiveData> getAll() {
095 List<PrimitiveData> result = new ArrayList<PrimitiveData>(directlyAdded.size() + referenced.size());
096 result.addAll(directlyAdded);
097 result.addAll(referenced);
098 return result;
099 }
100
101 public boolean isEmpty() {
102 return directlyAdded.isEmpty() && referenced.isEmpty();
103 }
104
105 private void firePasteBufferChanged() {
106 for (PasteBufferChangedListener listener: listeners) {
107 listener.pasteBufferChanged(this);
108 }
109 }
110
111 public void addPasteBufferChangedListener(PasteBufferChangedListener listener) {
112 listeners.addIfAbsent(listener);
113 }
114
115 public void removePasteBufferChangedListener(PasteBufferChangedListener listener) {
116 listeners.remove(listener);
117 }
118
119 }