Changeset 16362 in josm


Ignore:
Timestamp:
2020-04-20T09:36:29+02:00 (4 years ago)
Author:
GerdP
Message:

see #19111, #19105

  • don't ignore/reverse user input given in popup reg. tags/memberships
  • report correct number of affected relations (#19105)
  • when unglued (old) node is moved, place it either at the current mouse position (in cursor is in mapview) or 5 pixels above the original position. The old code sometimes placed it somewhere near the edge of the mapview window. The actual position depends on the input device that is used to select the node and to close the popup dialog (keyboard or mouse)
  • various code simplifications
Location:
trunk/src/org/openstreetmap/josm
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java

    r16317 r16362  
    66import static org.openstreetmap.josm.tools.I18n.trn;
    77
     8import java.awt.Point;
    89import java.awt.event.ActionEvent;
    910import java.awt.event.KeyEvent;
     
    1112import java.util.Collection;
    1213import java.util.Collections;
     14import java.util.HashMap;
    1315import java.util.HashSet;
    14 import java.util.LinkedList;
    1516import java.util.List;
     17import java.util.Map;
    1618import java.util.Set;
    1719import java.util.stream.Collectors;
    1820
    1921import javax.swing.JOptionPane;
    20 import javax.swing.JPanel;
    2122
    2223import org.openstreetmap.josm.command.AddCommand;
     
    2728import org.openstreetmap.josm.command.SequenceCommand;
    2829import org.openstreetmap.josm.data.UndoRedoHandler;
    29 import org.openstreetmap.josm.data.coor.LatLon;
    3030import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
    3131import org.openstreetmap.josm.data.osm.Node;
     
    4242import org.openstreetmap.josm.tools.Shortcut;
    4343import org.openstreetmap.josm.tools.UserCancelException;
    44 import org.openstreetmap.josm.tools.Utils;
    4544
    4645/**
    47  * Duplicate nodes that are used by multiple ways.
    48  *
    49  * Resulting nodes are identical, up to their position.
     46 * Duplicate nodes that are used by multiple ways or tagged nodes used by a single way
     47 * or nodes which referenced more than once by a single way.
    5048 *
    5149 * This is the opposite of the MergeNodesAction.
    5250 *
    53  * If a single node is selected, it will copy that node and remove all tags from the old one
    5451 */
    5552public class UnGlueAction extends JosmAction {
     
    7673    public void actionPerformed(ActionEvent e) {
    7774        try {
    78             unglue(e);
     75            unglue();
    7976        } catch (UserCancelException ignore) {
    8077            Logging.trace(ignore);
     
    8481    }
    8582
    86     protected void unglue(ActionEvent e) throws UserCancelException {
     83    protected void unglue() throws UserCancelException {
    8784
    8885        Collection<OsmPrimitive> selection = getLayerManager().getEditDataSet().getSelected();
     
    9087        String errMsg = null;
    9188        int errorTime = Notification.TIME_DEFAULT;
     89
    9290        if (checkSelectionOneNodeAtMostOneWay(selection)) {
    9391            checkAndConfirmOutlyingUnglue();
    94             int count = 0;
    95             for (Way w : selectedNode.getParentWays()) {
    96                 if (!w.isUsable() || w.getNodesCount() < 1) {
    97                     continue;
    98                 }
    99                 count++;
    100             }
    101             if (count < 2) {
    102                 boolean selfCrossing = false;
    103                 if (count == 1) {
    104                     // First try unglue self-crossing way
    105                     selfCrossing = unglueSelfCrossingWay();
    106                 }
    107                 // If there aren't enough ways, maybe the user wanted to unglue the nodes
    108                 // (= copy tags to a new node)
    109                 if (!selfCrossing)
    110                     if (checkForUnglueNode(selection)) {
    111                         unglueOneNodeAtMostOneWay(e);
    112                     } else {
    113                         errorTime = Notification.TIME_SHORT;
    114                         errMsg = tr("This node is not glued to anything else.");
     92            List<Way> parentWays = selectedNode.getParentWays().stream().filter(Way::isUsable).collect(Collectors.toList());
     93
     94            if (parentWays.size() < 2) {
     95                if (!parentWays.isEmpty()) {
     96                    // single way
     97                    Way way = selectedWay == null ? parentWays.get(0) : selectedWay;
     98                    boolean closedOrSelfCrossing = way.getNodes().stream().filter(n -> n == selectedNode).count() > 1;
     99
     100                    final PropertiesMembershipChoiceDialog dialog = PropertiesMembershipChoiceDialog.showIfNecessary(
     101                            Collections.singleton(selectedNode), !selectedNode.isTagged());
     102                    if (dialog != null) {
     103                        unglueOneNodeAtMostOneWay(way, dialog);
     104                        return;
     105                    } else if (closedOrSelfCrossing) {
     106                        unglueClosedOrSelfCrossingWay(way, dialog);
     107                        return;
    115108                    }
     109                }
     110                errorTime = Notification.TIME_SHORT;
     111                errMsg = tr("This node is not glued to anything else.");
    116112            } else {
    117113                // and then do the work.
     
    119115            }
    120116        } else if (checkSelectionOneWayAnyNodes(selection)) {
     117            selectedNodes.removeIf(n -> n.getParentWays().stream().filter(Way::isUsable).count() < 2);
    121118            checkAndConfirmOutlyingUnglue();
    122             Set<Node> tmpNodes = new HashSet<>();
    123             for (Node n : selectedNodes) {
    124                 int count = 0;
    125                 for (Way w : n.getParentWays()) {
    126                     if (!w.isUsable()) {
    127                         continue;
    128                     }
    129                     count++;
    130                 }
    131                 if (count >= 2) {
    132                     tmpNodes.add(n);
    133                 }
    134             }
    135             if (tmpNodes.isEmpty()) {
     119            if (selectedNodes.isEmpty()) {
    136120                if (selection.size() > 1) {
    137121                    errMsg = tr("None of these nodes are glued to anything else.");
     
    139123                    errMsg = tr("None of this way''s nodes are glued to anything else.");
    140124                }
     125            } else if (selectedNodes.size() == 1) {
     126                selectedNode = selectedNodes.iterator().next();
     127                unglueWays();
    141128            } else {
    142129                // and then do the work.
    143                 selectedNodes = tmpNodes;
    144130                unglueOneWayAnyNodes();
    145131            }
     
    176162    }
    177163
    178     static void update(PropertiesMembershipChoiceDialog dialog, Node existingNode, List<Node> newNodes, Collection<Command> cmds) {
     164    static void update(PropertiesMembershipChoiceDialog dialog, Node existingNode, List<Node> newNodes, List<Command> cmds) {
    179165        updateMemberships(dialog.getMemberships().orElse(null), existingNode, newNodes, cmds);
    180166        updateProperties(dialog.getTags().orElse(null), existingNode, newNodes, cmds);
    181167    }
    182168
    183     private static void updateProperties(ExistingBothNew tags, Node existingNode, Iterable<Node> newNodes, Collection<Command> cmds) {
     169    private static void updateProperties(ExistingBothNew tags, Node existingNode, Iterable<Node> newNodes, List<Command> cmds) {
    184170        if (ExistingBothNew.NEW == tags) {
    185171            final Node newSelectedNode = new Node(existingNode);
     
    195181    /**
    196182     * Assumes there is one tagged Node stored in selectedNode that it will try to unglue.
    197      * (i.e. copy node and remove all tags from the old one. Relations will not be removed)
    198      * @param e event that triggered the action
    199      */
    200     private void unglueOneNodeAtMostOneWay(ActionEvent e) {
    201         final PropertiesMembershipChoiceDialog dialog;
    202         try {
    203             dialog = PropertiesMembershipChoiceDialog.showIfNecessary(Collections.singleton(selectedNode), true);
    204         } catch (UserCancelException ex) {
    205             Logging.trace(ex);
    206             return;
    207         }
    208 
    209         final Node unglued = new Node(selectedNode, true);
    210         boolean moveSelectedNode = false;
    211 
    212         List<Command> cmds = new LinkedList<>();
    213         cmds.add(new AddCommand(selectedNode.getDataSet(), unglued));
    214         if (dialog != null && ExistingBothNew.NEW == dialog.getTags().orElse(null)) {
    215             // unglued node gets the ID and history, thus replace way node with a fresh one
    216             final Way way = selectedNode.getParentWays().get(0);
    217             final List<Node> newWayNodes = way.getNodes();
    218             newWayNodes.replaceAll(n -> selectedNode.equals(n) ? unglued : n);
    219             cmds.add(new ChangeNodesCommand(way, newWayNodes));
    220             updateMemberships(dialog.getMemberships().map(ExistingBothNew::opposite).orElse(null),
    221                     selectedNode, Collections.singletonList(unglued), cmds);
    222             updateProperties(dialog.getTags().map(ExistingBothNew::opposite).orElse(null),
    223                     selectedNode, Collections.singletonList(unglued), cmds);
    224             moveSelectedNode = true;
    225         } else if (dialog != null) {
    226             update(dialog, selectedNode, Collections.singletonList(unglued), cmds);
    227         }
    228 
    229         // If this wasn't called from menu, place it where the cursor is/was
     183     * (i.e. copy node and remove all tags from the old one.)
     184     * @param way way to modify
     185     * @param dialog the user dialog
     186     */
     187    private void unglueOneNodeAtMostOneWay(Way way, PropertiesMembershipChoiceDialog dialog) {
     188        List<Command> cmds = new ArrayList<>();
     189        List<Node> newNodes = new ArrayList<>();
     190        Way modWay = modifyWay(selectedNode, way, cmds, newNodes);
     191        cmds.add(new ChangeNodesCommand(way, modWay.getNodes()));
     192        if (dialog != null) {
     193            update(dialog, selectedNode, newNodes, cmds);
     194        }
     195
     196        // Place the selected node where the cursor is or some pixels above
    230197        MapView mv = MainApplication.getMap().mapView;
    231         if (e.getSource() instanceof JPanel) {
    232             final LatLon latLon = mv.getLatLon(mv.lastMEvent.getX(), mv.lastMEvent.getY());
    233             if (moveSelectedNode) {
    234                 cmds.add(new MoveCommand(selectedNode, latLon));
    235             } else {
    236                 unglued.setCoor(latLon);
    237             }
    238         }
    239 
     198        Point currMousePos = mv.getMousePosition();
     199        if (currMousePos != null) {
     200            cmds.add(new MoveCommand(selectedNode, mv.getLatLon(currMousePos.getX(), currMousePos.getY())));
     201        } else {
     202            cmds.add(new MoveCommand(selectedNode, 0, 5));
     203        }
    240204        UndoRedoHandler.getInstance().add(new SequenceCommand(tr("Unglued Node"), cmds));
    241         getLayerManager().getEditDataSet().setSelected(moveSelectedNode ? selectedNode : unglued);
    242         mv.repaint();
    243     }
    244 
    245     /**
    246      * Checks if selection is suitable for ungluing. This is the case when there's a single,
    247      * tagged node selected that's part of at least one way (ungluing an unconnected node does
    248      * not make sense. Due to the call order in actionPerformed, this is only called when the
    249      * node is only part of one or less ways.
    250      *
    251      * @param selection The selection to check against
    252      * @return {@code true} if selection is suitable
    253      */
    254     private boolean checkForUnglueNode(Collection<? extends OsmPrimitive> selection) {
    255         if (selection.size() != 1)
    256             return false;
    257         OsmPrimitive n = (OsmPrimitive) selection.toArray()[0];
    258         if (!(n instanceof Node))
    259             return false;
    260         if (((Node) n).getParentWays().isEmpty())
    261             return false;
    262 
    263         selectedNode = (Node) n;
    264         return selectedNode.isTagged();
     205        getLayerManager().getEditDataSet().setSelected(selectedNode);
    265206    }
    266207
     
    269210     * Checks only if the number and type of items selected looks good.
    270211     *
    271      * If this method returns "true", selectedNode and selectedWay will be set.
     212     * If this method returns "true", selectedNode will be set, selectedWay might be set
    272213     *
    273214     * Returns true if either one node is selected or one node and one
     
    362303    private static Way modifyWay(Node originalNode, Way w, List<Command> cmds, List<Node> newNodes) {
    363304        // clone the node for the way
    364         Node newNode = new Node(originalNode, true /* clear OSM ID */);
     305        Node newNode = cloneNode(originalNode, cmds);
    365306        newNodes.add(newNode);
    366         cmds.add(new AddCommand(originalNode.getDataSet(), newNode));
    367 
    368         List<Node> nn = new ArrayList<>();
    369         for (Node pushNode : w.getNodes()) {
    370             if (originalNode == pushNode) {
    371                 pushNode = newNode;
    372             }
    373             nn.add(pushNode);
    374         }
     307
     308        List<Node> nn = new ArrayList<>(w.getNodes());
     309        nn.replaceAll(n -> n == originalNode ? newNode : n);
    375310        Way newWay = new Way(w);
    376311        newWay.setNodes(nn);
    377312
    378313        return newWay;
     314    }
     315
     316    private static Node cloneNode(Node originalNode, List<Command> cmds) {
     317        Node newNode = new Node(originalNode, true /* clear OSM ID */);
     318        cmds.add(new AddCommand(originalNode.getDataSet(), newNode));
     319        return newNode;
    379320    }
    380321
     
    386327     * @param newNodes List of nodes that contain the new node
    387328     */
    388     private static void updateMemberships(ExistingBothNew memberships, Node originalNode, List<Node> newNodes, Collection<Command> cmds) {
     329    private static void updateMemberships(ExistingBothNew memberships, Node originalNode, List<Node> newNodes, List<Command> cmds) {
    389330        if (memberships == null || ExistingBothNew.OLD == memberships) {
    390331            return;
     
    422363     *
    423364     * dupe a single node once, and put the copy on the selected way
    424      */
    425     private void unglueWays() {
    426         final PropertiesMembershipChoiceDialog dialog;
    427         try {
    428             dialog = PropertiesMembershipChoiceDialog.showIfNecessary(Collections.singleton(selectedNode), false);
    429         } catch (UserCancelException e) {
    430             Logging.trace(e);
    431             return;
    432         }
    433 
    434         List<Command> cmds = new LinkedList<>();
    435         List<Node> newNodes = new LinkedList<>();
     365     * @throws UserCancelException if user cancels choice
     366     */
     367    private void unglueWays() throws UserCancelException {
     368        final PropertiesMembershipChoiceDialog dialog = PropertiesMembershipChoiceDialog
     369                .showIfNecessary(Collections.singleton(selectedNode), false);
     370        List<Command> cmds = new ArrayList<>();
     371        List<Node> newNodes = new ArrayList<>();
     372        List<Way> parentWays;
    436373        if (selectedWay == null) {
    437             LinkedList<Way> parentWays = selectedNode.referrers(Way.class).filter(Way::isUsable)
    438                     .collect(Collectors.toCollection(LinkedList::new));
     374            parentWays = selectedNode.referrers(Way.class).filter(Way::isUsable).collect(Collectors.toList());
    439375            // see #5452 and #18670
    440376            parentWays.sort((o1, o2) -> {
     
    449385            });
    450386            // first way should not be changed, preferring older ways and those with fewer parents
    451             parentWays.removeFirst();
    452 
    453             Set<Way> warnParents = new HashSet<>();
    454             for (Way w : parentWays) {
    455                 if (w.isFirstLastNode(selectedNode))
    456                     warnParents.add(w);
    457                 cmds.add(new ChangeCommand(w, modifyWay(selectedNode, w, cmds, newNodes)));
    458             }
    459             notifyWayPartOfRelation(warnParents);
     387            parentWays.remove(0);
    460388        } else {
    461             Way modWay = modifyWay(selectedNode, selectedWay, cmds, newNodes);
    462             addCheckedChangeNodesCmd(cmds, selectedWay, modWay.getNodes());
     389            parentWays = Collections.singletonList(selectedWay);
     390        }
     391        Set<Way> warnParents = new HashSet<>();
     392        for (Way w : parentWays) {
     393            if (w.isFirstLastNode(selectedNode))
     394                warnParents.add(w);
     395            cmds.add(new ChangeNodesCommand(w, modifyWay(selectedNode, w, cmds, newNodes).getNodes()));
    463396        }
    464397
     
    466399            update(dialog, selectedNode, newNodes, cmds);
    467400        }
     401        notifyWayPartOfRelation(warnParents);
    468402
    469403        execCommands(cmds, newNodes);
     
    484418    /**
    485419     * Duplicates a node used several times by the same way. See #9896.
     420     * First occurrence is kept. A closed way will be "opened" when the closing node is unglued.
     421     * @param way way to modify
     422     * @param dialog user dialog, might be null
    486423     * @return true if action is OK false if there is nothing to do
    487424     */
    488     private boolean unglueSelfCrossingWay() {
     425    private boolean unglueClosedOrSelfCrossingWay(Way way, PropertiesMembershipChoiceDialog dialog) {
    489426        // According to previous check, only one valid way through that node
    490         Way way = null;
    491         for (Way w: selectedNode.getParentWays()) {
    492             if (w.isUsable() && w.getNodesCount() >= 1) {
    493                 way = w;
    494             }
    495         }
    496         if (way == null) {
    497             return false;
    498         }
    499         List<Command> cmds = new LinkedList<>();
     427        List<Command> cmds = new ArrayList<>();
    500428        List<Node> oldNodes = way.getNodes();
    501429        List<Node> newNodes = new ArrayList<>(oldNodes.size());
    502430        List<Node> addNodes = new ArrayList<>();
    503         boolean seen = false;
     431        int count = 0;
    504432        for (Node n: oldNodes) {
    505             if (n == selectedNode) {
    506                 if (seen) {
    507                     Node newNode = new Node(n, true /* clear OSM ID */);
    508                     cmds.add(new AddCommand(selectedNode.getDataSet(), newNode));
    509                     newNodes.add(newNode);
    510                     addNodes.add(newNode);
    511                 } else {
    512                     newNodes.add(n);
    513                     seen = true;
    514                 }
    515             } else {
    516                 newNodes.add(n);
    517             }
     433            if (n == selectedNode && count++ > 0) {
     434                n = cloneNode(selectedNode, cmds);
     435                addNodes.add(n);
     436            }
     437            newNodes.add(n);
    518438        }
    519439        if (addNodes.isEmpty()) {
     
    521441            return false;
    522442        }
     443        if (dialog != null) {
     444            update(dialog, selectedNode, addNodes, cmds);
     445        }
    523446        addCheckedChangeNodesCmd(cmds, way, newNodes);
    524         try {
    525             final PropertiesMembershipChoiceDialog dialog = PropertiesMembershipChoiceDialog.showIfNecessary(
    526                     Collections.singleton(selectedNode), false);
    527             if (dialog != null) {
    528                 update(dialog, selectedNode, addNodes, cmds);
    529             }
    530             execCommands(cmds, addNodes);
    531             return true;
    532         } catch (UserCancelException ignore) {
    533             Logging.trace(ignore);
    534         }
    535         return false;
     447        execCommands(cmds, addNodes);
     448        return true;
    536449    }
    537450
    538451    /**
    539452     * dupe all nodes that are selected, and put the copies on the selected way
    540      *
    541      */
    542     private void unglueOneWayAnyNodes() {
    543         Way tmpWay = selectedWay;
    544 
    545         final PropertiesMembershipChoiceDialog dialog;
    546         try {
    547             dialog = PropertiesMembershipChoiceDialog.showIfNecessary(selectedNodes, false);
    548         } catch (UserCancelException e) {
    549             Logging.trace(e);
    550             return;
    551         }
    552 
    553         List<Command> cmds = new LinkedList<>();
    554         List<Node> allNewNodes = new LinkedList<>();
    555         for (Node n : selectedNodes) {
    556             List<Node> newNodes = new LinkedList<>();
    557             tmpWay = modifyWay(n, tmpWay, cmds, newNodes);
    558             if (dialog != null) {
    559                 update(dialog, n, newNodes, cmds);
    560             }
    561             allNewNodes.addAll(newNodes);
    562         }
     453     * @throws UserCancelException
     454     *
     455     */
     456    private void unglueOneWayAnyNodes() throws UserCancelException {
     457        final PropertiesMembershipChoiceDialog dialog =
     458            PropertiesMembershipChoiceDialog.showIfNecessary(selectedNodes, false);
     459
     460        Map<Node, Node> replaced = new HashMap<>();
     461        List<Command> cmds = new ArrayList<>();
     462
     463        selectedNodes.forEach(n -> replaced.put(n, cloneNode(n, cmds)));
     464        List<Node> modNodes = new ArrayList<>(selectedWay.getNodes());
     465        modNodes.replaceAll(n -> replaced.getOrDefault(n, n));
     466
     467        if (dialog != null) {
     468            replaced.forEach((k, v) -> update(dialog, k, Collections.singletonList(v), cmds));
     469        }
     470
    563471        // only one changeCommand for a way, else garbage will happen
    564         addCheckedChangeNodesCmd(cmds, selectedWay, tmpWay.getNodes());
    565 
     472        addCheckedChangeNodesCmd(cmds, selectedWay, modNodes);
    566473        UndoRedoHandler.getInstance().add(new SequenceCommand(
    567474                trn("Dupe {0} node into {1} nodes", "Dupe {0} nodes into {1} nodes",
    568                         selectedNodes.size(), selectedNodes.size(), selectedNodes.size()+allNewNodes.size()), cmds));
    569         getLayerManager().getEditDataSet().setSelected(allNewNodes);
    570     }
    571 
    572     private void addCheckedChangeNodesCmd(List<Command> cmds, Way w, List<Node> nodes) {
    573         boolean relationCheck = w.firstNode() != nodes.get(0) || w.lastNode() != nodes.get(nodes.size() - 1);
     475                        selectedNodes.size(), selectedNodes.size(), 2 * selectedNodes.size()), cmds));
     476        getLayerManager().getEditDataSet().setSelected(replaced.values());
     477    }
     478
     479    private boolean addCheckedChangeNodesCmd(List<Command> cmds, Way w, List<Node> nodes) {
     480        boolean relationCheck = !calcAffectedRelations(Collections.singleton(w)).isEmpty();
    574481        cmds.add(new ChangeNodesCommand(w, nodes));
    575482        if (relationCheck) {
    576483            notifyWayPartOfRelation(Collections.singleton(w));
    577484        }
     485        return relationCheck;
    578486    }
    579487
     
    612520
    613521    protected void notifyWayPartOfRelation(final Collection<Way> ways) {
    614         final Set<Node> affectedNodes = (selectedNodes != null) ? selectedNodes : Collections.singleton(selectedNode);
    615         final Set<String> affectedRelations = new HashSet<>();
    616         for (Relation r: OsmPrimitive.getParentRelations(ways)) {
    617             if (!r.isUsable())
    618                 continue;
    619             // see #18670: suppress notification when well known restriction types are not affected
    620             if (r.hasTag("type", "restriction", "connectivity", "destination_sign") && !r.hasIncompleteMembers()) {
    621                 int count = 0;
    622                 for (RelationMember rm : r.getMembers()) {
    623                     if (rm.isNode() && affectedNodes.contains(rm.getNode()))
    624                         count++;
    625                     if (rm.isWay() && ways.contains(rm.getWay())) {
    626                         count++;
    627                         if ("via".equals(rm.getRole())) {
    628                             count++;
    629                         }
    630                     }
    631                 }
    632                 if (count < 2)
    633                     continue;
    634             }
    635             affectedRelations.add(r.getDisplayName(DefaultNameFormatter.getInstance()));
    636         }
     522        Set<Relation> affectedRelations = calcAffectedRelations(ways);
    637523        if (affectedRelations.isEmpty()) {
    638524            return;
    639525        }
    640 
    641526        final int size = affectedRelations.size();
    642527        final String msg1 = trn("Unglueing possibly affected {0} relation: {1}", "Unglueing possibly affected {0} relations: {1}",
    643                 size, size, Utils.joinAsHtmlUnorderedList(affectedRelations));
     528                size, size, DefaultNameFormatter.getInstance().formatAsHtmlUnorderedList(affectedRelations, 20));
    644529        final String msg2 = trn("Ensure that the relation has not been broken!", "Ensure that the relations have not been broken!",
    645530                size);
    646         new Notification("<html>" + msg1 + msg2).setIcon(JOptionPane.WARNING_MESSAGE).show();
     531        new Notification(msg1 + msg2).setIcon(JOptionPane.WARNING_MESSAGE).show();
     532    }
     533
     534    protected Set<Relation> calcAffectedRelations(final Collection<Way> ways) {
     535        final Set<Node> affectedNodes = (selectedNodes != null) ? selectedNodes : Collections.singleton(selectedNode);
     536        return OsmPrimitive.getParentRelations(ways)
     537                .stream().filter(r -> isRelationAffected(r, affectedNodes, ways))
     538                .collect(Collectors.toSet());
     539    }
     540
     541    private static boolean isRelationAffected(Relation r, Set<Node> affectedNodes, Collection<Way> ways) {
     542        if (!r.isUsable())
     543            return false;
     544        // see #18670: suppress notification when well known restriction types are not affected
     545        if (!r.hasTag("type", "restriction", "connectivity", "destination_sign") || r.hasIncompleteMembers())
     546            return true;
     547        int count = 0;
     548        for (RelationMember rm : r.getMembers()) {
     549            if (rm.isNode() && affectedNodes.contains(rm.getNode()))
     550                count++;
     551            if (rm.isWay() && ways.contains(rm.getWay())) {
     552                count++;
     553                if ("via".equals(rm.getRole())) {
     554                    count++;
     555                }
     556            }
     557        }
     558        return count >= 2;
    647559    }
    648560}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesMembershipChoiceDialog.java

    r14662 r16362  
    3838    public enum ExistingBothNew {
    3939        OLD, BOTH, NEW;
    40 
    41         /**
    42          * Returns the opposite/inverted user choice.
    43          * @return the opposite/inverted user choice
    44          */
    45         public ExistingBothNew opposite() {
    46             return equals(OLD) ? NEW : equals(NEW) ? OLD : this;
    47         }
    4840    }
    4941
Note: See TracChangeset for help on using the changeset viewer.