source: josm/trunk/src/org/openstreetmap/josm/command/PurgePrimitivesCommand.java@ 3142

Last change on this file since 3142 was 3089, checked in by mjulius, 14 years ago

In PurgePrimitivesCommand remove all instances of a node to be purged from parent ways

  • Property svn:eol-style set to native
File size: 7.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.command;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.util.Collection;
8import java.util.Collections;
9import java.util.HashSet;
10import java.util.Set;
11import java.util.logging.Logger;
12
13import javax.swing.JLabel;
14import javax.swing.tree.DefaultMutableTreeNode;
15import javax.swing.tree.MutableTreeNode;
16
17import org.openstreetmap.josm.Main;
18import org.openstreetmap.josm.data.conflict.ConflictCollection;
19import org.openstreetmap.josm.data.osm.Node;
20import org.openstreetmap.josm.data.osm.OsmPrimitive;
21import org.openstreetmap.josm.data.osm.Relation;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.gui.DefaultNameFormatter;
24import org.openstreetmap.josm.gui.layer.OsmDataLayer;
25import org.openstreetmap.josm.tools.ImageProvider;
26
27/**
28 * Physically removes an {@see OsmPrimitive} from the dataset of the edit
29 * layer and disconnects any references from {@see Way}s or {@see Relation}s
30 * to this primitive.
31 *
32 * This command is necessary if a local {@see OsmPrimitive} has been deleted on
33 * the server by another user and if the local user decides to delete his version
34 * too. If he only deleted it "logically" JOSM would try to delete it on the server
35 * which would result in an non resolvable conflict.
36 *
37 */
38public class PurgePrimitivesCommand extends ConflictResolveCommand{
39
40 static private final Logger logger = Logger.getLogger(PurgePrimitivesCommand.class.getName());
41
42 /** the primitives to purge */
43 private Collection<OsmPrimitive> toPurge;
44
45 /** the set of primitives to purge as consequence of purging
46 * {@see #primitive}, including {@see #primitive}
47 */
48 private Set<OsmPrimitive> purgedPrimitives;
49
50 private Set<OsmPrimitive> origVersionsOfTouchedPrimitives;
51
52 protected void init(Collection<OsmPrimitive> toPurge) {
53 this.toPurge = toPurge;
54 this.purgedPrimitives = new HashSet<OsmPrimitive>();
55 this.origVersionsOfTouchedPrimitives = new HashSet<OsmPrimitive>();
56 }
57
58 /**
59 * constructor
60 * @param primitive the primitive to purge
61 *
62 */
63 public PurgePrimitivesCommand(OsmPrimitive primitive) {
64 init(Collections.singleton(primitive));
65 }
66
67 /**
68 * constructor
69 * @param layer the OSM data layer
70 * @param primitive the primitive to purge
71 *
72 */
73 public PurgePrimitivesCommand(OsmDataLayer layer, OsmPrimitive primitive) {
74 super(layer);
75 init(Collections.singleton(primitive));
76 }
77
78 /**
79 * constructor
80 * @param layer the OSM data layer
81 * @param primitives the primitives to purge
82 *
83 */
84 public PurgePrimitivesCommand(OsmDataLayer layer, Collection<OsmPrimitive> primitives) {
85 super(layer);
86 init(primitives);
87 }
88
89 /**
90 * Replies a collection with the purged primitives
91 *
92 * @return a collection with the purged primitives
93 */
94 public Collection<OsmPrimitive> getPurgedPrimitives() {
95 return purgedPrimitives;
96 }
97
98 protected MutableTreeNode getDescription(OsmPrimitive primitive) {
99 return new DefaultMutableTreeNode(
100 new JLabel(
101 tr("Purged object ''{0}''", primitive.getDisplayName(DefaultNameFormatter.getInstance())),
102 ImageProvider.get("data", "object"),
103 JLabel.HORIZONTAL
104 )
105 );
106 }
107
108 protected MutableTreeNode getDescription(Collection<OsmPrimitive> primitives) {
109
110 DefaultMutableTreeNode root = new DefaultMutableTreeNode(
111 trn("Purged {0} object", "Purged {0} objects", primitives.size(), primitives.size())
112 );
113 for (OsmPrimitive p : primitives) {
114 root.add(getDescription(p));
115 }
116 return root;
117 }
118
119 @Override
120 public MutableTreeNode description() {
121 if (purgedPrimitives.size() == 1)
122 return getDescription(purgedPrimitives.iterator().next());
123 else
124 return getDescription(purgedPrimitives);
125 }
126
127 /**
128 * Purges an {@see OsmPrimitive} <code>child</code> from a {@see DataSet}.
129 *
130 * @param child the primitive to purge
131 * @param hive the hive of {@see OsmPrimitive}s we remember other {@see OsmPrimitive}
132 * we have to purge because we purge <code>child</code>.
133 *
134 */
135 protected void removeReferecesToPrimitive(OsmPrimitive child, Set<OsmPrimitive> hive) {
136 hive.remove(child);
137 for (OsmPrimitive parent: child.getReferrers()) {
138 if (toPurge.contains(parent))
139 // parent itself is to be purged. This method is going to be
140 // invoked for parent later
141 return;
142 if (parent instanceof Way) {
143 Way w = (Way)parent;
144 if (!origVersionsOfTouchedPrimitives.contains(w)) {
145 origVersionsOfTouchedPrimitives.add(w);
146 }
147 w.removeNode((Node)child);
148 // if a way ends up with less than two nodes we
149 // remember it on the "hive"
150 //
151 if (w.getNodesCount() < 2) {
152 System.out.println(tr("Warning: Purging way {0} because number of nodes dropped below 2. Current is {1}",
153 w.getId(),w.getNodesCount()));
154 hive.add(w);
155 }
156 } else if (parent instanceof Relation) {
157 Relation r = (Relation)parent;
158 if (!origVersionsOfTouchedPrimitives.contains(r)) {
159 origVersionsOfTouchedPrimitives.add(r);
160 }
161 System.out.println(tr("Removing reference from relation {0}",r.getId()));
162 r.removeMembersFor(child);
163 } else {
164 // should not happen. parent can't be a node
165 }
166 }
167 }
168
169 @Override
170 public boolean executeCommand() {
171 HashSet<OsmPrimitive> hive = new HashSet<OsmPrimitive>();
172
173 // iteratively purge the primitive and all primitives
174 // which violate invariants after they lose a reference to
175 // the primitive (i.e. ways which end up with less than two
176 // nodes)
177 hive.addAll(toPurge);
178 while(! hive.isEmpty()) {
179 OsmPrimitive p = hive.iterator().next();
180 removeReferecesToPrimitive(p, hive);
181 getLayer().data.removePrimitive(p);
182 purgedPrimitives.add(p);
183 ConflictCollection conflicts = getLayer().getConflicts();
184 if (conflicts.hasConflictForMy(p)) {
185 rememberConflict(conflicts.getConflictForMy(p));
186 conflicts.remove(p);
187 }
188 }
189 return super.executeCommand();
190 }
191
192 @Override
193 public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted,
194 Collection<OsmPrimitive> added) {
195 modified.addAll(origVersionsOfTouchedPrimitives);
196 }
197
198 @Override
199 public void undoCommand() {
200 if (! Main.map.mapView.hasLayer(getLayer())) {
201 logger.warning(tr("Cannot undo command ''{0}'' because layer ''{1}'' is not present any more",
202 this.toString(),
203 getLayer().toString()
204 ));
205 return;
206 }
207 Main.map.mapView.setActiveLayer(getLayer());
208
209 // restore purged primitives
210 //
211 for (OsmPrimitive purged : purgedPrimitives) {
212 getLayer().data.addPrimitive(purged);
213 }
214 reconstituteConflicts();
215
216 // will restore the primitives referring to one
217 // of the purged primitives
218 super.undoCommand();
219 }
220}
Note: See TracBrowser for help on using the repository browser.