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

Last change on this file since 2484 was 2414, checked in by Gubaer, 14 years ago

Removed methods made @deprecated in r2411.

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