Ticket #18670: 18670.4.patch
| File 18670.4.patch, 10.1 KB (added by , 6 years ago) |
|---|
-
src/org/openstreetmap/josm/actions/UnGlueAction.java
8 8 import java.awt.event.ActionEvent; 9 9 import java.awt.event.KeyEvent; 10 10 import java.util.ArrayList; 11 import java.util.Arrays; 11 12 import java.util.Collection; 12 13 import java.util.Collections; 13 14 import java.util.HashMap; … … 108 109 } 109 110 // If there aren't enough ways, maybe the user wanted to unglue the nodes 110 111 // (= copy tags to a new node) 111 if (!selfCrossing) 112 if ( checkForUnglueNode(selection)) {112 if (!selfCrossing) { 113 if (selection.size() == 1 && selectedNode.isTagged()) { 113 114 unglueOneNodeAtMostOneWay(e); 114 115 } else { 115 116 errorTime = Notification.TIME_SHORT; 116 117 errMsg = tr("This node is not glued to anything else."); 117 118 } 119 } 118 120 } else { 119 121 // and then do the work. 120 122 unglueWays(); … … 245 247 } 246 248 247 249 /** 248 * Checks if selection is suitable for ungluing. This is the case when there's a single,249 * tagged node selected that's part of at least one way (ungluing an unconnected node does250 * not make sense. Due to the call order in actionPerformed, this is only called when the251 * node is only part of one or less ways.252 *253 * @param selection The selection to check against254 * @return {@code true} if selection is suitable255 */256 private boolean checkForUnglueNode(Collection<? extends OsmPrimitive> selection) {257 if (selection.size() != 1)258 return false;259 OsmPrimitive n = (OsmPrimitive) selection.toArray()[0];260 if (!(n instanceof Node))261 return false;262 if (((Node) n).getParentWays().isEmpty())263 return false;264 265 selectedNode = (Node) n;266 return selectedNode.isTagged();267 }268 269 /**270 250 * Checks if the selection consists of something we can work with. 271 251 * Checks only if the number and type of items selected looks good. 272 252 * … … 291 271 for (OsmPrimitive p : selection) { 292 272 if (p instanceof Node) { 293 273 selectedNode = (Node) p; 294 if (size == 1 || selectedWay != null)295 return size == 1 || selectedWay.containsNode(selectedNode);274 if (size == 1 || (selectedWay != null && selectedWay.containsNode(selectedNode))) 275 return true; 296 276 } else if (p instanceof Way) { 297 277 selectedWay = (Way) p; 298 278 if (size == 2 && selectedNode != null) … … 359 339 * @param w parent way 360 340 * @param cmds List of commands that will contain the new "add node" command 361 341 * @param newNodes List of nodes that will contain the new node 362 * @return new way The modified way. Change command mus be handled by the caller342 * @return new way The modified way. Change command must be handled by the caller 363 343 */ 364 344 private static Way modifyWay(Node originalNode, Way w, List<Command> cmds, List<Node> newNodes) { 365 345 // clone the node for the way … … 445 425 List<Command> cmds = new LinkedList<>(); 446 426 List<Node> newNodes = new LinkedList<>(); 447 427 if (selectedWay == null) { 448 Way wayWithSelectedNode = null; 449 LinkedList<Way> parentWays = new LinkedList<>(); 450 for (OsmPrimitive osm : selectedNode.getReferrers()) { 451 if (osm.isUsable() && osm instanceof Way) { 452 Way w = (Way) osm; 453 if (wayWithSelectedNode == null && !w.isFirstLastNode(selectedNode)) { 454 wayWithSelectedNode = w; 455 } else { 456 parentWays.add(w); 457 } 428 LinkedList<Way> parentWays = selectedNode.referrers(Way.class).filter(Way::isUsable) 429 .collect(Collectors.toCollection(LinkedList::new)); 430 // see #5452 and #18670 431 parentWays.sort((o1, o2) -> { 432 int d = Boolean.compare(!o1.isNew() && !o1.isModified(), !o2.isNew() && !o2.isModified()); 433 if (d == 0) { 434 d = Integer.compare(o2.getReferrers().size(), o1.getReferrers().size()); // reversed 458 435 } 459 } 460 if (wayWithSelectedNode == null) { 461 parentWays.removeFirst(); 462 } 436 if (d == 0) { 437 d = Boolean.compare(o1.isFirstLastNode(selectedNode), o2.isFirstLastNode(selectedNode)); 438 } 439 return d; 440 }); 441 // first way should not be changed, preferring older ways and those with fewer parents 442 parentWays.removeFirst(); 443 444 Set<Way> warnParents = new HashSet<>(); 463 445 for (Way w : parentWays) { 446 if (w.isFirstLastNode(selectedNode)) 447 warnParents.add(w); 464 448 cmds.add(new ChangeCommand(w, modifyWay(selectedNode, w, cmds, newNodes))); 465 449 } 466 notifyWayPartOfRelation( parentWays);450 notifyWayPartOfRelation(warnParents); 467 451 } else { 468 cmds.add(new ChangeCommand(selectedWay, modifyWay(selectedNode, selectedWay, cmds, newNodes)));469 notifyWayPartOfRelation(Collections.singleton(selectedWay));452 Way modWay = modifyWay(selectedNode, selectedWay, cmds, newNodes); 453 addCheckedChangeNodesCmd(cmds, selectedWay, modWay.getNodes()); 470 454 } 471 455 472 456 if (dialog != null) { … … 527 511 // selectedNode doesn't need unglue 528 512 return false; 529 513 } 530 cmds.add(new ChangeNodesCommand(way, newNodes)); 531 notifyWayPartOfRelation(Collections.singleton(way)); 514 addCheckedChangeNodesCmd(cmds, way, newNodes); 532 515 try { 533 516 final PropertiesMembershipChoiceDialog dialog = PropertiesMembershipChoiceDialog.showIfNecessary( 534 517 Collections.singleton(selectedNode), false); … … 568 551 } 569 552 allNewNodes.addAll(newNodes); 570 553 } 571 cmds.add(new ChangeCommand(selectedWay, tmpWay));// only one changeCommand for a way, else garbage will happen572 notifyWayPartOfRelation(Collections.singleton(selectedWay));554 // only one changeCommand for a way, else garbage will happen 555 addCheckedChangeNodesCmd(cmds, selectedWay, tmpWay.getNodes()); 573 556 574 557 UndoRedoHandler.getInstance().add(new SequenceCommand( 575 558 trn("Dupe {0} node into {1} nodes", "Dupe {0} nodes into {1} nodes", … … 577 560 getLayerManager().getEditDataSet().setSelected(allNewNodes); 578 561 } 579 562 563 private void addCheckedChangeNodesCmd(List<Command> cmds, Way w, List<Node> nodes) { 564 boolean relationCheck = w.firstNode() != nodes.get(0) || w.lastNode() != nodes.get(nodes.size() - 1); 565 cmds.add(new ChangeNodesCommand(w, nodes)); 566 if (relationCheck) { 567 notifyWayPartOfRelation(Collections.singleton(w)); 568 } 569 } 570 580 571 @Override 581 572 protected void updateEnabledState() { 582 573 updateEnabledStateOnCurrentSelection(); … … 611 602 } 612 603 613 604 protected void notifyWayPartOfRelation(final Collection<Way> ways) { 614 final Set<String> affectedRelations = ways.stream() 615 .flatMap(w -> w.getReferrers().stream()) 616 .filter(ref -> ref instanceof Relation && ref.isUsable()) 617 .map(ref -> ref.getDisplayName(DefaultNameFormatter.getInstance())) 618 .collect(Collectors.toSet()); 605 final Set<Node> affectedNodes = (selectedNodes != null) ? selectedNodes : Collections.singleton(selectedNode); 606 final Set<String> affectedRelations = new HashSet<>(); 607 for (Relation r: OsmPrimitive.getParentRelations(ways)) { 608 if (!r.isUsable()) 609 continue; 610 // see #18670: suppress notification when well known restriction types are not affected 611 if (r.hasTag("type", "restriction", "connectivity", "destination_sign")) { 612 int count = 0; 613 for (RelationMember rm : r.getMembers()) { 614 if (rm.isNode() && affectedNodes.contains(rm.getNode())) 615 count++; 616 if (rm.isWay() && ways.contains(rm.getWay())) { 617 count++; 618 if (affectedNodes.containsAll(Arrays.asList(rm.getWay().firstNode(), rm.getWay().lastNode()))) 619 count++; 620 } 621 } 622 if (count < 2) 623 continue; 624 } 625 affectedRelations.add(r.getDisplayName(DefaultNameFormatter.getInstance())); 626 } 619 627 if (affectedRelations.isEmpty()) { 620 628 return; 621 629 } 622 630 623 631 final int size = affectedRelations.size(); 624 final String msg1 = trn("Unglueing affected {0} relation: {1}", "Unglueingaffected {0} relations: {1}",632 final String msg1 = trn("Unglueing possibly affected {0} relation: {1}", "Unglueing possibly affected {0} relations: {1}", 625 633 size, size, Utils.joinAsHtmlUnorderedList(affectedRelations)); 626 634 final String msg2 = trn("Ensure that the relation has not been broken!", "Ensure that the relations have not been broken!", 627 635 size); -
test/unit/org/openstreetmap/josm/actions/UnGlueActionTest.java
30 30 */ 31 31 @Rule 32 32 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 33 public JOSMTestRules test = new JOSMTestRules().main() ;33 public JOSMTestRules test = new JOSMTestRules().main().projection().preferences(); 34 34 35 35 /** 36 36 * Setup test.
