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