source: josm/trunk/src/org/openstreetmap/josm/command/DeleteCommand.java@ 1101

Last change on this file since 1101 was 1047, checked in by cbrill, 16 years ago

[Cleanup] Remove unused imports and unused variables, part 2

This cleanup does not include static imports for translation

  • Property svn:eol-style set to native
File size: 13.3 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
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.awt.GridBagLayout;
8import java.awt.geom.Area;
9import java.util.ArrayList;
10import java.util.Collection;
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Iterator;
15import java.util.LinkedList;
16import java.util.List;
17
18import javax.swing.JLabel;
19import javax.swing.JOptionPane;
20import javax.swing.JPanel;
21import javax.swing.tree.DefaultMutableTreeNode;
22import javax.swing.tree.MutableTreeNode;
23
24import org.openstreetmap.josm.Main;
25import org.openstreetmap.josm.data.osm.Node;
26import org.openstreetmap.josm.data.osm.OsmPrimitive;
27import org.openstreetmap.josm.data.osm.Relation;
28import org.openstreetmap.josm.data.osm.RelationMember;
29import org.openstreetmap.josm.data.osm.Way;
30import org.openstreetmap.josm.data.osm.WaySegment;
31import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
32import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
33import org.openstreetmap.josm.tools.DontShowAgainInfo;
34import org.openstreetmap.josm.tools.ImageProvider;
35
36/**
37 * A command to delete a number of primitives from the dataset.
38 * @author imi
39 */
40public class DeleteCommand extends Command {
41
42 /**
43 * The primitive that get deleted.
44 */
45 private final Collection<? extends OsmPrimitive> data;
46
47 /**
48 * Constructor for a collection of data
49 */
50 public DeleteCommand(Collection<? extends OsmPrimitive> data) {
51 this.data = data;
52 }
53
54 /**
55 * Constructor for a single data item. Use the collection constructor to delete multiple
56 * objects.
57 */
58 public DeleteCommand(OsmPrimitive data) {
59 this.data = Collections.singleton(data);
60 }
61
62 @Override public boolean executeCommand() {
63 super.executeCommand();
64 for (OsmPrimitive osm : data) {
65 osm.delete(true);
66 }
67 return true;
68 }
69
70 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted,
71 Collection<OsmPrimitive> added) {
72 deleted.addAll(data);
73 }
74
75 @Override public MutableTreeNode description() {
76 NameVisitor v = new NameVisitor();
77
78 if (data.size() == 1) {
79 data.iterator().next().visit(v);
80 return new DefaultMutableTreeNode(new JLabel(tr("Delete {1} {0}", v.name, tr(v.className)), v.icon,
81 JLabel.HORIZONTAL));
82 }
83
84 String cname = null;
85 String cnamem = null;
86 for (OsmPrimitive osm : data) {
87 osm.visit(v);
88 if (cname == null) {
89 cname = v.className;
90 cnamem = v.classNamePlural;
91 } else if (!cname.equals(v.className)) {
92 cname = "object";
93 cnamem = trn("object", "objects", 2);
94 }
95 }
96 DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(tr("Delete {0} {1}", data.size(), trn(
97 cname, cnamem, data.size())), ImageProvider.get("data", cname), JLabel.HORIZONTAL));
98 for (OsmPrimitive osm : data) {
99 osm.visit(v);
100 root.add(new DefaultMutableTreeNode(v.toLabel()));
101 }
102 return root;
103 }
104
105 /**
106 * Delete the primitives and everything they reference.
107 *
108 * If a node is deleted, the node and all ways and relations the node is part of are deleted as
109 * well.
110 *
111 * If a way is deleted, all relations the way is member of are also deleted.
112 *
113 * If a way is deleted, only the way and no nodes are deleted.
114 *
115 * @param selection The list of all object to be deleted.
116 * @return command A command to perform the deletions, or null of there is nothing to delete.
117 */
118 public static Command deleteWithReferences(Collection<? extends OsmPrimitive> selection) {
119 CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.ds);
120 for (OsmPrimitive osm : selection)
121 osm.visit(v);
122 v.data.addAll(selection);
123 if (v.data.isEmpty())
124 return null;
125 if (!checkAndConfirmOutlyingDeletes(v.data))
126 return null;
127 return new DeleteCommand(v.data);
128 }
129
130 /**
131 * Try to delete all given primitives.
132 *
133 * If a node is used by a way, it's removed from that way. If a node or a way is used by a
134 * relation, inform the user and do not delete.
135 *
136 * If this would cause ways with less than 2 nodes to be created, delete these ways instead. If
137 * they are part of a relation, inform the user and do not delete.
138 *
139 * @param selection The objects to delete.
140 * @param alsoDeleteNodesInWay <code>true</code> if nodes should be deleted as well
141 * @return command A command to perform the deletions, or null of there is nothing to delete.
142 */
143 private static int testRelation(Relation ref, OsmPrimitive osm) {
144 NameVisitor n = new NameVisitor();
145 ref.visit(n);
146 NameVisitor s = new NameVisitor();
147 osm.visit(s);
148 String role = new String();
149 for (RelationMember m : ref.members) {
150 if (m.member == osm) {
151 role = m.role;
152 break;
153 }
154 }
155 if (role.length() > 0) {
156 return JOptionPane.showConfirmDialog(Main.parent, tr(
157 "Selection \"{0}\" is used by relation \"{1}\" with role {2}.\nDelete from relation?", s.name,
158 n.name, role), tr("Conflicting relation"), JOptionPane.YES_NO_OPTION);
159 } else {
160 return JOptionPane.showConfirmDialog(Main.parent, tr(
161 "Selection \"{0}\" is used by relation \"{1}\".\nDelete from relation?", s.name, n.name),
162 tr("Conflicting relation"), JOptionPane.YES_NO_OPTION);
163 }
164 }
165
166 public static Command delete(Collection<? extends OsmPrimitive> selection) {
167 return delete(selection, true);
168 }
169
170 public static Command delete(Collection<? extends OsmPrimitive> selection, boolean alsoDeleteNodesInWay) {
171 if (selection.isEmpty())
172 return null;
173
174 Collection<OsmPrimitive> del = new HashSet<OsmPrimitive>(selection);
175 Collection<Way> waysToBeChanged = new HashSet<Way>();
176 HashMap<OsmPrimitive, Collection<OsmPrimitive>> relationsToBeChanged = new HashMap<OsmPrimitive, Collection<OsmPrimitive>>();
177
178 if (alsoDeleteNodesInWay) {
179 // Delete untagged nodes that are to be unreferenced.
180 Collection<OsmPrimitive> delNodes = new HashSet<OsmPrimitive>();
181 for (OsmPrimitive osm : del) {
182 if (osm instanceof Way) {
183 for (Node n : ((Way) osm).nodes) {
184 if (!n.tagged) {
185 CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.ds, false);
186 n.visit(v);
187 v.data.removeAll(del);
188 if (v.data.isEmpty()) {
189 delNodes.add(n);
190 }
191 }
192 }
193 }
194 }
195 del.addAll(delNodes);
196 }
197
198 if (!checkAndConfirmOutlyingDeletes(del))
199 return null;
200
201 for (OsmPrimitive osm : del) {
202 CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.ds, false);
203 osm.visit(v);
204 for (OsmPrimitive ref : v.data) {
205 if (del.contains(ref))
206 continue;
207 if (ref instanceof Way) {
208 waysToBeChanged.add((Way) ref);
209 } else if (ref instanceof Relation) {
210 if (testRelation((Relation) ref, osm) == JOptionPane.YES_OPTION) {
211 Collection<OsmPrimitive> relset = relationsToBeChanged.get(ref);
212 if (relset == null)
213 relset = new HashSet<OsmPrimitive>();
214 relset.add(osm);
215 relationsToBeChanged.put(ref, relset);
216 } else
217 return null;
218 } else {
219 return null;
220 }
221 }
222 }
223
224 Collection<Command> cmds = new LinkedList<Command>();
225 for (Way w : waysToBeChanged) {
226 Way wnew = new Way(w);
227 wnew.nodes.removeAll(del);
228 if (wnew.nodes.size() < 2) {
229 del.add(w);
230
231 CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.ds, false);
232 w.visit(v);
233 for (OsmPrimitive ref : v.data) {
234 if (del.contains(ref))
235 continue;
236 if (ref instanceof Relation) {
237 Boolean found = false;
238 Collection<OsmPrimitive> relset = relationsToBeChanged.get(ref);
239 if (relset == null)
240 relset = new HashSet<OsmPrimitive>();
241 else {
242 for (OsmPrimitive m : relset) {
243 if (m == w) {
244 found = true;
245 break;
246 }
247 }
248 }
249 if (!found) {
250 if (testRelation((Relation) ref, w) == JOptionPane.YES_OPTION) {
251 relset.add(w);
252 relationsToBeChanged.put(ref, relset);
253 } else
254 return null;
255 }
256 } else {
257 return null;
258 }
259 }
260 } else {
261 cmds.add(new ChangeCommand(w, wnew));
262 }
263 }
264
265 Iterator<OsmPrimitive> iterator = relationsToBeChanged.keySet().iterator();
266 while (iterator.hasNext()) {
267 Relation cur = (Relation) iterator.next();
268 Relation rel = new Relation(cur);
269 for (OsmPrimitive osm : relationsToBeChanged.get(cur)) {
270 for (RelationMember rm : rel.members) {
271 if (rm.member == osm) {
272 RelationMember mem = new RelationMember();
273 mem.role = rm.role;
274 mem.member = rm.member;
275 rel.members.remove(mem);
276 break;
277 }
278 }
279 }
280 cmds.add(new ChangeCommand(cur, rel));
281 }
282
283 if (!del.isEmpty())
284 cmds.add(new DeleteCommand(del));
285
286 return new SequenceCommand(tr("Delete"), cmds);
287 }
288
289 public static Command deleteWaySegment(WaySegment ws) {
290 List<Node> n1 = new ArrayList<Node>(), n2 = new ArrayList<Node>();
291
292 n1.addAll(ws.way.nodes.subList(0, ws.lowerIndex + 1));
293 n2.addAll(ws.way.nodes.subList(ws.lowerIndex + 1, ws.way.nodes.size()));
294
295 if (n1.size() < 2 && n2.size() < 2) {
296 return new DeleteCommand(Collections.singleton(ws.way));
297 }
298
299 Way wnew = new Way(ws.way);
300 wnew.nodes.clear();
301
302 if (n1.size() < 2) {
303 wnew.nodes.addAll(n2);
304 return new ChangeCommand(ws.way, wnew);
305 } else if (n2.size() < 2) {
306 wnew.nodes.addAll(n1);
307 return new ChangeCommand(ws.way, wnew);
308 } else {
309 Collection<Command> cmds = new LinkedList<Command>();
310
311 wnew.nodes.addAll(n1);
312 cmds.add(new ChangeCommand(ws.way, wnew));
313
314 Way wnew2 = new Way();
315 if (wnew.keys != null) {
316 wnew2.keys = new HashMap<String, String>(wnew.keys);
317 wnew2.checkTagged();
318 wnew2.checkDirectionTagged();
319 }
320 wnew2.nodes.addAll(n2);
321 cmds.add(new AddCommand(wnew2));
322
323 return new SequenceCommand(tr("Split way segment"), cmds);
324 }
325 }
326
327 /**
328 * Check whether user is about to delete data outside of the download area.
329 * Request confirmation if he is.
330 */
331 private static boolean checkAndConfirmOutlyingDeletes(Collection<OsmPrimitive> del) {
332 Area a = Main.ds.getDataSourceArea();
333 if (a != null) {
334 for (OsmPrimitive osm : del) {
335 if (osm instanceof Node && osm.id != 0) {
336 Node n = (Node) osm;
337 if (!a.contains(n.coor)) {
338 JPanel msg = new JPanel(new GridBagLayout());
339 msg.add(new JLabel(
340 "<html>" +
341 // leave message in one tr() as there is a grammatical connection.
342 tr("You are about to delete nodes outside of the area you have downloaded." +
343 "<br>" +
344 "This can cause problems because other objects (that you don't see) might use them." +
345 "<br>" +
346 "Do you really want to delete?") + "</html>"));
347 return DontShowAgainInfo.show("delete_outside_nodes", msg, false, JOptionPane.YES_NO_OPTION, JOptionPane.YES_OPTION);
348 }
349
350 }
351 }
352 }
353 return true;
354 }
355}
Note: See TracBrowser for help on using the repository browser.