Changeset 9292 in josm


Ignore:
Timestamp:
2016-01-04T00:17:06+01:00 (8 years ago)
Author:
simon04
Message:

see #8838 - Unglue: ask the user about tags/membership

Let the user decide whether the tags/memberships of the existing node should afterwards be at
the existing node, the new nodes, or all of them.

File:
1 edited

Legend:

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

    r9291 r9292  
    66import static org.openstreetmap.josm.tools.I18n.trn;
    77
     8import java.awt.GridBagLayout;
    89import java.awt.event.ActionEvent;
    910import java.awt.event.KeyEvent;
     
    1819import java.util.Set;
    1920
     21import javax.swing.AbstractButton;
     22import javax.swing.ButtonGroup;
     23import javax.swing.JLabel;
    2024import javax.swing.JOptionPane;
    2125import javax.swing.JPanel;
     26import javax.swing.JToggleButton;
    2227
    2328import org.openstreetmap.josm.Main;
     
    3237import org.openstreetmap.josm.data.osm.RelationMember;
    3338import org.openstreetmap.josm.data.osm.Way;
     39import org.openstreetmap.josm.gui.ExtendedDialog;
    3440import org.openstreetmap.josm.gui.MapView;
    3541import org.openstreetmap.josm.gui.Notification;
     42import org.openstreetmap.josm.tools.GBC;
     43import org.openstreetmap.josm.tools.ImageProvider;
     44import org.openstreetmap.josm.tools.Predicate;
    3645import org.openstreetmap.josm.tools.Shortcut;
     46import org.openstreetmap.josm.tools.UserCancelException;
     47import org.openstreetmap.josm.tools.Utils;
    3748
    3849/**
     
    163174
    164175    /**
     176     * Provides toggle buttons to allow the user choose the existing node, the new nodes, or all of them.
     177     */
     178    private static class ExistingBothNewChoice {
     179        final AbstractButton oldNode = new JToggleButton(tr("Existing node"), ImageProvider.get("dialogs/conflict/tagkeeptheir"));
     180        final AbstractButton bothNodes = new JToggleButton(tr("Both nodes"), ImageProvider.get("dialogs/conflict/tagundecide"));
     181        final AbstractButton newNode = new JToggleButton(tr("New node"), ImageProvider.get("dialogs/conflict/tagkeepmine"));
     182
     183        ExistingBothNewChoice(final boolean preselectNew) {
     184            final ButtonGroup tagsGroup = new ButtonGroup();
     185            tagsGroup.add(oldNode);
     186            tagsGroup.add(bothNodes);
     187            tagsGroup.add(newNode);
     188            tagsGroup.setSelected((preselectNew ? newNode : oldNode).getModel(), true);
     189        }
     190    }
     191
     192    /**
     193     * A dialog allowing the user decide whether the tags/memberships of the existing node should afterwards be at
     194     * the existing node, the new nodes, or all of them.
     195     */
     196    static final class PropertiesMembershipDialog extends ExtendedDialog {
     197
     198        final ExistingBothNewChoice tags;
     199        final ExistingBothNewChoice memberships;
     200
     201        private PropertiesMembershipDialog(boolean preselectNew, boolean queryTags, boolean queryMemberships) {
     202            super(Main.parent, tr("Tags / Memberships"), new String[]{tr("Unglue"), tr("Cancel")});
     203            setButtonIcons(new String[]{"unglueways", "cancel"});
     204
     205            final JPanel content = new JPanel(new GridBagLayout());
     206
     207            if (queryTags) {
     208                content.add(new JLabel(tr("Where should the tags of the node be put?")), GBC.std(1, 1).span(3).insets(0, 20, 0, 0));
     209                tags = new ExistingBothNewChoice(preselectNew);
     210                content.add(tags.oldNode, GBC.std(1, 2));
     211                content.add(tags.bothNodes, GBC.std(2, 2));
     212                content.add(tags.newNode, GBC.std(3, 2));
     213            } else {
     214                tags = null;
     215            }
     216
     217            if (queryMemberships) {
     218                content.add(new JLabel(tr("Where should the memberships of this node be put?")), GBC.std(1, 3).span(3).insets(0, 20, 0, 0));
     219                memberships = new ExistingBothNewChoice(preselectNew);
     220                content.add(memberships.oldNode, GBC.std(1, 4));
     221                content.add(memberships.bothNodes, GBC.std(2, 4));
     222                content.add(memberships.newNode, GBC.std(3, 4));
     223            } else {
     224                memberships = null;
     225            }
     226
     227            setContent(content);
     228            setResizable(false);
     229        }
     230
     231        static PropertiesMembershipDialog showIfNecessary(Iterable<Node> selectedNodes, boolean preselectNew) throws UserCancelException {
     232            final boolean tagged = isTagged(selectedNodes);
     233            final boolean usedInRelations = isUsedInRelations(selectedNodes);
     234            if (tagged || usedInRelations) {
     235                final PropertiesMembershipDialog dialog = new PropertiesMembershipDialog(preselectNew, tagged, usedInRelations);
     236                dialog.showDialog();
     237                if (dialog.getValue() != 1) {
     238                    throw new UserCancelException();
     239                }
     240                return dialog;
     241            }
     242            return null;
     243        }
     244
     245        private static boolean isTagged(final Iterable<Node> existingNodes) {
     246            return Utils.exists(existingNodes, new Predicate<Node>() {
     247                @Override
     248                public boolean evaluate(final Node selectedNode) {
     249                    return selectedNode.hasKeys();
     250                }
     251            });
     252        }
     253
     254        private static boolean isUsedInRelations(final Iterable<Node> existingNodes) {
     255            return Utils.exists(existingNodes, new Predicate<Node>() {
     256                @Override
     257                public boolean evaluate(final Node selectedNode) {
     258                    return Utils.exists(selectedNode.getReferrers(), OsmPrimitive.relationPredicate);
     259                }
     260            });
     261        }
     262
     263        void update(final Node existingNode, final List<Node> newNodes, final Collection<Command> cmds) {
     264            updateMemberships(existingNode, newNodes, cmds);
     265            updateProperties(existingNode, newNodes, cmds);
     266        }
     267
     268        private void updateProperties(final Node existingNode, final Iterable<Node> newNodes, final Collection<Command> cmds) {
     269            if (tags != null && tags.newNode.isSelected()) {
     270                final Node newSelectedNode = new Node(existingNode);
     271                newSelectedNode.removeAll();
     272                cmds.add(new ChangeCommand(existingNode, newSelectedNode));
     273            } else if (tags != null && tags.oldNode.isSelected()) {
     274                for (Node newNode : newNodes) {
     275                    newNode.removeAll();
     276                }
     277            }
     278        }
     279
     280        private void updateMemberships(final Node existingNode, final List<Node> newNodes, final Collection<Command> cmds) {
     281            if (memberships != null && memberships.bothNodes.isSelected()) {
     282                fixRelations(existingNode, cmds, newNodes, false);
     283            } else if (memberships != null && memberships.newNode.isSelected()) {
     284                fixRelations(existingNode, cmds, newNodes, true);
     285            }
     286        }
     287    }
     288
     289    /**
    165290     * Assumes there is one tagged Node stored in selectedNode that it will try to unglue.
    166291     * (i.e. copy node and remove all tags from the old one. Relations will not be removed)
     
    170295        List<Command> cmds = new LinkedList<>();
    171296
    172         Node c = new Node(selectedNode);
    173         c.removeAll();
    174         getCurrentDataSet().clearSelection(c);
    175         cmds.add(new ChangeCommand(selectedNode, c));
    176 
    177         Node n = new Node(selectedNode, true);
     297        final PropertiesMembershipDialog dialog;
     298        try {
     299            dialog = PropertiesMembershipDialog.showIfNecessary(Collections.singleton(selectedNode), true);
     300        } catch (UserCancelException e1) {
     301            return;
     302        }
     303
     304        final Node n = new Node(selectedNode, true);
     305
     306        cmds.add(new AddCommand(n));
     307        if (dialog != null) {
     308            dialog.update(selectedNode, Collections.singletonList(n), cmds);
     309        }
    178310
    179311        // If this wasn't called from menu, place it where the cursor is/was
     
    182314            n.setCoor(mv.getLatLon(mv.lastMEvent.getX(), mv.lastMEvent.getY()));
    183315        }
    184 
    185         cmds.add(new AddCommand(n));
    186 
    187         fixRelations(selectedNode, cmds, Collections.singletonList(n));
    188316
    189317        Main.main.undoRedo.add(new SequenceCommand(tr("Unglued Node"), cmds));
     
    334462     * @param newNodes List of nodes that contain the new node
    335463     */
    336     private void fixRelations(Node originalNode, List<Command> cmds, List<Node> newNodes) {
     464    private static void fixRelations(Node originalNode, Collection<Command> cmds, List<Node> newNodes, boolean removeOldMember) {
    337465        // modify all relations containing the node
    338466        for (Relation r : OsmPrimitive.getFilteredList(originalNode.getReferrers(), Relation.class)) {
     
    357485            if (newRel != null) {
    358486                if (rolesToReAdd != null) {
    359                     for (Node n : newNodes) {
    360                         for (Map.Entry<String, Integer> role : rolesToReAdd.entrySet()) {
     487                    for (Map.Entry<String, Integer> role : rolesToReAdd.entrySet()) {
     488                        for (Node n : newNodes) {
    361489                            newRel.addMember(role.getValue() + 1, new RelationMember(role.getKey(), n));
     490                        }
     491                        if (removeOldMember) {
     492                            newRel.removeMember(role.getValue());
    362493                        }
    363494                    }
     
    376507        List<Command> cmds = new LinkedList<>();
    377508        List<Node> newNodes = new LinkedList<>();
     509
     510        final PropertiesMembershipDialog dialog;
     511        try {
     512            dialog = PropertiesMembershipDialog.showIfNecessary(Collections.singleton(selectedNode), false);
     513        } catch (UserCancelException e) {
     514            return;
     515        }
    378516
    379517        if (selectedWay == null) {
     
    400538        }
    401539
    402         fixRelations(selectedNode, cmds, newNodes);
     540        if (dialog != null) {
     541            dialog.update(selectedNode, newNodes, cmds);
     542        }
     543
    403544        execCommands(cmds, newNodes);
    404545    }
     
    457598        }
    458599        cmds.add(new ChangeNodesCommand(way, newNodes));
    459         // Update relation
    460         fixRelations(selectedNode, cmds, addNodes);
    461         execCommands(cmds, addNodes);
    462         return true;
    463      }
     600        try {
     601            final PropertiesMembershipDialog dialog = PropertiesMembershipDialog.showIfNecessary(Collections.singleton(selectedNode), false);
     602            if (dialog != null) {
     603                dialog.update(selectedNode, addNodes, cmds);
     604            }
     605            execCommands(cmds, addNodes);
     606            return true;
     607        } catch (UserCancelException ignore) {
     608            Main.debug(ignore.getMessage());
     609        }
     610        return false;
     611    }
    464612
    465613    /**
     
    472620        Way tmpWay = selectedWay;
    473621
     622        final PropertiesMembershipDialog dialog;
     623        try {
     624            dialog = PropertiesMembershipDialog.showIfNecessary(selectedNodes, false);
     625        } catch (UserCancelException e) {
     626            return;
     627        }
     628
    474629        for (Node n : selectedNodes) {
    475630            List<Node> newNodes = new LinkedList<>();
    476631            tmpWay = modifyWay(n, tmpWay, cmds, newNodes);
    477             fixRelations(n, cmds, newNodes);
     632            if (dialog != null) {
     633                dialog.update(n, newNodes, cmds);
     634            }
    478635            allNewNodes.addAll(newNodes);
    479636        }
Note: See TracChangeset for help on using the changeset viewer.