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

Last change on this file since 1670 was 1670, checked in by Gubaer, 15 years ago

fixed: bug in OsmApi.getOsmApi()
cleanup: exception handling in interfacing with OSM API
new: new action for updating individual elements with the their current state on the server (including new menu item in the file menu)
new: improved user feedback in case of conflicts
new: handles 410 Gone conflicts when uploading a changeset
new: undoable command for "purging" a primitive from the current dataset (necessary if the primitive is already deleted on the server and the user wants to remove it from its local dataset)
new: undoable command for "undeleting" an already deleted primitive on the server (kind of "cloning")
new: after a full upload, checks whether there are primitives in the local dataset which might be deleted on the server.
new: data structures for history data
new: history download support in io package

File size: 8.9 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.ArrayList;
7import java.util.Collection;
8import java.util.List;
9
10import javax.swing.JLabel;
11import javax.swing.tree.DefaultMutableTreeNode;
12import javax.swing.tree.MutableTreeNode;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.data.osm.DataSet;
16import org.openstreetmap.josm.data.osm.Node;
17import org.openstreetmap.josm.data.osm.OsmPrimitive;
18import org.openstreetmap.josm.data.osm.Relation;
19import org.openstreetmap.josm.data.osm.RelationMember;
20import org.openstreetmap.josm.data.osm.Way;
21import org.openstreetmap.josm.tools.ImageProvider;
22
23/**
24 * Physically removes an {@see OsmPrimitive} from the dataset of the edit
25 * layer and disconnects any references from {@see Way}s or {@see Relation}s
26 * to this primitive.
27 *
28 * This command is necessary if a local {@see OsmPrimitive} has been deleted on
29 * the server by another user and if the local user decides to delete his version
30 * too. If he only deleted it "logically" JOSM would try to delete it on the server
31 * which would result in an non resolvable conflict.
32 *
33 */
34public class PurgePrimitivesCommand extends Command{
35
36 /**
37 * Represents a pair of {@see OsmPrimitive} where the parent referrs to
38 * the child, either because a {@see Way} includes a {@see Node} or
39 * because a {@see Relation} refers to any other {@see OsmPrimitive}
40 * via a relation member.
41 *
42 */
43 static class OsmParentChildPair {
44 private OsmPrimitive parent;
45 private OsmPrimitive child;
46
47
48 public OsmParentChildPair(OsmPrimitive parent, OsmPrimitive child) {
49 this.parent = parent;
50 this.child = child;
51 }
52
53 public OsmPrimitive getParent() {
54 return parent;
55 }
56
57 public OsmPrimitive getChild() {
58 return child;
59 }
60
61 @Override
62 public int hashCode() {
63 final int prime = 31;
64 int result = 1;
65 result = prime * result + ((child == null) ? 0 : child.hashCode());
66 result = prime * result + ((parent == null) ? 0 : parent.hashCode());
67 return result;
68 }
69
70 @Override
71 public boolean equals(Object obj) {
72 if (this == obj)
73 return true;
74 if (obj == null)
75 return false;
76 if (getClass() != obj.getClass())
77 return false;
78 OsmParentChildPair other = (OsmParentChildPair) obj;
79 if (child == null) {
80 if (other.child != null)
81 return false;
82 } else if (child != other.child)
83 return false;
84 if (parent == null) {
85 if (other.parent != null)
86 return false;
87 } else if (parent != other.parent)
88 return false;
89 return true;
90 }
91 }
92
93 /**
94 * creates a list of all {@see OsmParentChildPair}s for a given {@see OsmPrimitive}
95 * as child and given set of parents. We don't use {@see CollectBackReferencesVisitor}
96 * because it seems quite inefficient.
97 *
98 * @param parents the set of potential parents
99 * @param child the child
100 * @return the list of {@see OsmParentChildPair}
101 */
102 protected List<OsmParentChildPair> getParentChildPairs(List<OsmPrimitive> parents, OsmPrimitive child) {
103 ArrayList<OsmParentChildPair> pairs = new ArrayList<OsmParentChildPair>();
104 for (OsmPrimitive parent : parents) {
105 if (parent instanceof Way) {
106 Way w = (Way)parent;
107 for (OsmPrimitive node : w.nodes) {
108 if (node == child) {
109 OsmParentChildPair pair = new OsmParentChildPair(parent, node);
110 if (! pairs.contains(pair)) {
111 pairs.add(pair);
112 }
113 }
114 }
115 } else if (parent instanceof Relation) {
116 Relation r = (Relation)parent;
117 for (RelationMember member : r.members) {
118 if (member.member == child) {
119 OsmParentChildPair pair = new OsmParentChildPair(parent, member.member);
120 if (! pairs.contains(pair)) {
121 pairs.add(pair);
122 }
123 }
124 }
125 }
126 }
127 return pairs;
128 }
129
130 /** the primitive to purge */
131 private OsmPrimitive primitive;
132
133 /** the set of primitives to purge as consequence of purging
134 * {@see #primitive}, including {@see #primitive}
135 */
136 private ArrayList<OsmPrimitive> purgedPrimitives;
137
138 /** the set of {@see OsmParentChildPair}. We keep a reference
139 * to this set for the {@see #fillModifiedData(Collection, Collection, Collection)} operation
140 */
141 private ArrayList<OsmParentChildPair> pairs;
142
143 /**
144 * constructor
145 * @param node the node to undelete
146 */
147 public PurgePrimitivesCommand(OsmPrimitive primitive) {
148 this.primitive = primitive;
149 purgedPrimitives = new ArrayList<OsmPrimitive>();
150 pairs = new ArrayList<OsmParentChildPair>();
151 }
152
153 @Override
154 public MutableTreeNode description() {
155 return new DefaultMutableTreeNode(
156 new JLabel(
157 tr("Purging 1 primitive"),
158 ImageProvider.get("data", "object"),
159 JLabel.HORIZONTAL
160 )
161 );
162 }
163
164 /**
165 * Purges an {@see OsmPrimitive} <code>toPurge</code> from a {@see DataSet}.
166 *
167 * @param toPurge the primitive to purge
168 * @param ds the dataset to purge from
169 * @param hive the hive of {@see OsmPrimitive}s we remember other {@see OsmPrimitive}
170 * we have to purge because we purge <code>toPurge</code>.
171 *
172 */
173 protected void purge(OsmPrimitive toPurge, DataSet ds, ArrayList<OsmPrimitive> hive) {
174 ArrayList<OsmPrimitive> parents = new ArrayList<OsmPrimitive>();
175 parents.addAll(Main.ds.ways);
176 parents.addAll(Main.ds.relations);
177 List<OsmParentChildPair> pairs = getParentChildPairs(parents, primitive);
178 hive.remove(toPurge);
179 for (OsmParentChildPair pair: pairs) {
180 if (pair.getParent() instanceof Way) {
181 Way w = (Way)pair.getParent();
182 System.out.println("removing reference from way " + w.id);
183 w.nodes.remove(primitive);
184 // if a way ends up with less than two node we
185 // remember it on the "hive"
186 //
187 if (w.nodes.size() < 2) {
188 System.out.println(tr("Warning: Purging way {0} because number of nodes dropped below 2. Current is {1}",
189 w.id,w.nodes.size()));
190 if (!hive.contains(w)) {
191 hive.add(w);
192 }
193 }
194 } else if (pair.getParent() instanceof Relation) {
195 Relation r = (Relation)pair.getParent();
196 System.out.println("removing reference from relation " + r.id);
197 r.removeMembersFor(primitive);
198 }
199 }
200 }
201
202 @Override
203 public boolean executeCommand() {
204 ArrayList<OsmPrimitive> hive = new ArrayList<OsmPrimitive>();
205
206 // iteratively purge the primitive and all primitives
207 // which violate invariants after they loose a reference to
208 // the primitive (i.e. ways which end up with less than two
209 // nodes)
210 hive.add(primitive);
211 while(! hive.isEmpty()) {
212 OsmPrimitive toPurge = hive.get(0);
213 purge(toPurge, Main.ds, hive);
214 if (toPurge instanceof Node) {
215 Main.ds.nodes.remove(toPurge);
216 } else if (primitive instanceof Way) {
217 Main.ds.ways.remove(toPurge);
218 } else if (primitive instanceof Relation) {
219 Main.ds.relations.remove(toPurge);
220 }
221 purgedPrimitives.add(toPurge);
222 }
223 return super.executeCommand();
224 }
225
226 @Override
227 public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted,
228 Collection<OsmPrimitive> added) {
229 for (OsmParentChildPair pair : pairs) {
230 modified.add(pair.getParent());
231 }
232 // we don't need pairs anymore
233 pairs = null;
234 }
235
236 @Override
237 public void undoCommand() {
238 for (OsmPrimitive purged : purgedPrimitives) {
239 Main.ds.addPrimitive(purged);
240 }
241
242 // will restore the former references to the purged nodes
243 //
244 super.undoCommand();
245 }
246}
Note: See TracBrowser for help on using the repository browser.