Ticket #5133: 0001-Action-to-disconnect-nodes-from-ways.3.patch

File 0001-Action-to-disconnect-nodes-from-ways.3.patch, 10.9 KB (added by gbilotta <giuseppe.bilotta@…>, 6 years ago)

Feature implementation, v3

  • new file 2001

    From 87b6c43e098c34d7a3f12ce07557f991c5bfaff6 Mon Sep 17 00:00:00 2001
    From: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
    Date: Mon, 29 Jul 2013 08:29:30 +0200
    Subject: [PATCH] Action to disconnect nodes from ways
    
    A RemoveNodes command is also added to simplify undo management.
    ---
     images/unjoinnodeway.png                           | Bin 0 -> 385 bytes
     .../josm/actions/UnJoinNodeWayAction.java          | 138 +++++++++++++++++++++
     .../josm/command/RemoveNodesCommand.java           |  56 +++++++++
     src/org/openstreetmap/josm/gui/MainMenu.java       |   3 +
     4 files changed, 197 insertions(+)
     create mode 100644 images/unjoinnodeway.png
     create mode 100644 src/org/openstreetmap/josm/actions/UnJoinNodeWayAction.java
     create mode 100644 src/org/openstreetmap/josm/command/RemoveNodesCommand.java
    
    diff --git a/images/unjoinnodeway.png b/images/unjoinnodeway.png
    new file mode 100644
    index 0000000000000000000000000000000000000000..4179e6902577640d66deab6f78cab43c8b0a4786
    GIT binary patch
    literal 385
    zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE)4%caKYZ?lYt_f1s;*b
    z3=G`DAk4@xYYs>cdx@v7EBjq`Ssnvp>D3WU3=E8Xo-U3d9>?Ea-s{H{D8Tx_-@z~{
    zQbL-=Y@@jL+J&1w&#Y0FW4M3d$h{-1Nl7Lf4FegKvp1VZhPx;oS@AHWxc=Ns<Kp)p
    zOv7|H9x+*?<D`-oHu;T})$8@iElW0NEdT1~zxOitX|8JvOqjPf<X$oGu;iWdKtc5M
    zVwqjRvx1(<nF%};*nPvjr+7<Ym-UxjYj1rq@0fj6Wy+1*t1jt(rArDLPw$A#ea<8E
    zkjq~qN!|FXb4;?uTG!(h9;|K)&mVNy^}pkJPlmx9mUFvVb{fSO&gW7Q=Ha<y?WuN<
    zeM(XM>PdD13OpY_bvE99@ag*bi}z>$`QKZlmY48ZeUjL|S_|fFVharAyNW+4_gt>9
    cd3i{>Jl~Te!YJi0Ft8XrUHx3vIVCg!02-y3CIA2c
  • new file src/org/openstreetmap/josm/actions/UnJoinNodeWayAction.java

    literal 0
    HcmV?d00001
    
    diff --git a/src/org/openstreetmap/josm/actions/UnJoinNodeWayAction.java b/src/org/openstreetmap/josm/actions/UnJoinNodeWayAction.java
    new file mode 100644
    index 0000000..c1c3f14
    - +  
     1//License: GPL. Copyright 2007 by Immanuel Scholz and others
     2package org.openstreetmap.josm.actions;
     3
     4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
     5import static org.openstreetmap.josm.tools.I18n.tr;
     6import static org.openstreetmap.josm.tools.I18n.trn;
     7
     8import java.awt.event.ActionEvent;
     9import java.awt.event.KeyEvent;
     10import java.util.ArrayList;
     11import java.util.Collection;
     12import java.util.Collections;
     13import java.util.Iterator;
     14import java.util.List;
     15
     16import javax.swing.JOptionPane;
     17
     18import org.openstreetmap.josm.Main;
     19import org.openstreetmap.josm.command.RemoveNodesCommand;
     20import org.openstreetmap.josm.command.Command;
     21import org.openstreetmap.josm.data.osm.Node;
     22import org.openstreetmap.josm.data.osm.OsmPrimitive;
     23import org.openstreetmap.josm.data.osm.Way;
     24import org.openstreetmap.josm.tools.Shortcut;
     25
     26public class UnJoinNodeWayAction extends JosmAction {
     27    public UnJoinNodeWayAction() {
     28        super(tr("Disconnect Node from Way"), "unjoinnodeway",
     29                tr("Disconnect nodes from a way they currently belong to"),
     30                Shortcut.registerShortcut("tools:unjoinnodeway",
     31                    tr("Tool: {0}", tr("Disconnect Node from Way")), KeyEvent.VK_J, Shortcut.ALT), true);
     32        putValue("help", ht("/Action/UnJoinNodeWay"));
     33    }
     34
     35    @Override
     36    public void actionPerformed(ActionEvent e) {
     37
     38        Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected();
     39
     40        List<Node> selectedNodes = OsmPrimitive.getFilteredList(selection, Node.class);
     41        List<Way> selectedWays = OsmPrimitive.getFilteredList(selection, Way.class);
     42        List<Way> applicableWays = getApplicableWays(selectedWays, selectedNodes);
     43
     44        if (applicableWays == null) {
     45            JOptionPane.showMessageDialog(
     46                    Main.parent,
     47                    tr("Select at least one node to be disconnected."),
     48                    tr("Warning"),
     49                    JOptionPane.WARNING_MESSAGE);
     50            return;
     51        } else if (applicableWays.isEmpty()) {
     52            JOptionPane.showMessageDialog(Main.parent,
     53                    trn("Selected node cannot be disconnected from anything.",
     54                        "Selected nodes cannot be disconnected from anything.",
     55                        selectedNodes.size()),
     56                    tr("Warning"),
     57                    JOptionPane.WARNING_MESSAGE);
     58            return;
     59        } else if (applicableWays.size() > 1) {
     60            JOptionPane.showMessageDialog(Main.parent,
     61                    trn("There is more than one way using the node you selected. Please select the way also.",
     62                        "There is more than one way using the nodes you selected. Please select the way also.",
     63                        selectedNodes.size()),
     64                    tr("Warning"),
     65                    JOptionPane.WARNING_MESSAGE);
     66            return;
     67        } else if (applicableWays.get(0).getRealNodesCount() < selectedNodes.size() + 2) {
     68            // there is only one affected way, but removing the selected nodes would only leave it
     69            // with less than 2 nodes
     70            JOptionPane.showMessageDialog(Main.parent,
     71                    trn("The affected way would disappear after disconnecting the selected node.",
     72                        "The affected way would disappear after disconnecting the selected nodes.",
     73                        selectedNodes.size()),
     74                    tr("Warning"),
     75                    JOptionPane.WARNING_MESSAGE);
     76            return;
     77        }
     78
     79
     80        // Finally, applicableWays contains only one perfect way
     81        Way selectedWay = applicableWays.get(0);
     82
     83        // I'm sure there's a better way to handle this
     84        Main.main.undoRedo.add(new RemoveNodesCommand(selectedWay, selectedNodes));
     85        Main.map.repaint();
     86    }
     87
     88    // Find ways to which the disconnect can be applied. This is the list of ways with more
     89    // than two nodes which pass through all the given nodes, intersected with the selected ways (if any)
     90    private List<Way> getApplicableWays(List<Way> selectedWays, List<Node> selectedNodes) {
     91        if (selectedNodes.isEmpty())
     92            return null;
     93
     94        // List of ways shared by all nodes
     95        List<Way> result = new ArrayList<Way>(OsmPrimitive.getFilteredList(selectedNodes.get(0).getReferrers(), Way.class));
     96        for (int i=1; i<selectedNodes.size(); i++) {
     97            List<OsmPrimitive> ref = selectedNodes.get(i).getReferrers();
     98            for (Iterator<Way> it = result.iterator(); it.hasNext(); ) {
     99                if (!ref.contains(it.next())) {
     100                    it.remove();
     101                }
     102            }
     103        }
     104
     105        // Remove broken ways
     106        for (Iterator<Way> it = result.iterator(); it.hasNext(); ) {
     107            if (it.next().getNodesCount() <= 2) {
     108                it.remove();
     109            }
     110        }
     111
     112        if (selectedWays.isEmpty())
     113            return result;
     114        else {
     115            // Return only selected ways
     116            for (Iterator<Way> it = result.iterator(); it.hasNext(); ) {
     117                if (!selectedWays.contains(it.next())) {
     118                    it.remove();
     119                }
     120            }
     121            return result;
     122        }
     123    }
     124
     125    @Override
     126    protected void updateEnabledState() {
     127        if (getCurrentDataSet() == null) {
     128            setEnabled(false);
     129        } else {
     130            updateEnabledState(getCurrentDataSet().getSelected());
     131        }
     132    }
     133
     134    @Override
     135    protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
     136        setEnabled(selection != null && !selection.isEmpty());
     137    }
     138}
  • new file src/org/openstreetmap/josm/command/RemoveNodesCommand.java

    diff --git a/src/org/openstreetmap/josm/command/RemoveNodesCommand.java b/src/org/openstreetmap/josm/command/RemoveNodesCommand.java
    new file mode 100644
    index 0000000..5959a08
    - +  
     1// License: GPL. See LICENSE file for details.
     2package org.openstreetmap.josm.command;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.util.Collection;
     7import java.util.HashSet;
     8import java.util.List;
     9import javax.swing.Icon;
     10
     11import org.openstreetmap.josm.data.osm.Node;
     12import org.openstreetmap.josm.data.osm.Way;
     13import org.openstreetmap.josm.data.osm.OsmPrimitive;
     14import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     15import org.openstreetmap.josm.gui.DefaultNameFormatter;
     16import org.openstreetmap.josm.tools.ImageProvider;
     17
     18/**
     19 * Command that removes a set of nodes from a way.
     20 * The same can be done with ChangeNodesCommand, but this is more
     21 * efficient. (Needed for the tool to disconnect nodes from ways.)
     22 *
     23 * @author Giuseppe Bilotta
     24 */
     25public class RemoveNodesCommand extends Command {
     26
     27    private final Way way;
     28    private final HashSet<Node> rmNodes;
     29
     30    public RemoveNodesCommand(Way way, List<Node> rmNodes) {
     31        super();
     32        this.way = way;
     33        this.rmNodes = new HashSet<Node>(rmNodes);
     34    }
     35
     36    @Override public boolean executeCommand() {
     37        super.executeCommand();
     38        way.removeNodes(rmNodes);
     39        way.setModified(true);
     40        return true;
     41    }
     42
     43    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
     44        modified.add(way);
     45    }
     46
     47    @Override
     48    public String getDescriptionText() {
     49        return tr("Removed nodes from {0}", way.getDisplayName(DefaultNameFormatter.getInstance()));
     50    }
     51
     52    @Override
     53    public Icon getDescriptionIcon() {
     54        return ImageProvider.get(OsmPrimitiveType.WAY);
     55    }
     56}
  • src/org/openstreetmap/josm/gui/MainMenu.java

    diff --git a/src/org/openstreetmap/josm/gui/MainMenu.java b/src/org/openstreetmap/josm/gui/MainMenu.java
    index 7671796..ec867ba 100644
    a b import org.openstreetmap.josm.actions.SimplifyWayAction; 
    8484import org.openstreetmap.josm.actions.SplitWayAction;
    8585import org.openstreetmap.josm.actions.ToggleGPXLinesAction;
    8686import org.openstreetmap.josm.actions.UnGlueAction;
     87import org.openstreetmap.josm.actions.UnJoinNodeWayAction;
    8788import org.openstreetmap.josm.actions.UndoAction;
    8889import org.openstreetmap.josm.actions.UnselectAllAction;
    8990import org.openstreetmap.josm.actions.UpdateDataAction;
    public class MainMenu extends JMenuBar { 
    187188    public final JosmAction createCircle = new CreateCircleAction();
    188189    public final JosmAction mergeNodes = new MergeNodesAction();
    189190    public final JosmAction joinNodeWay = new JoinNodeWayAction();
     191    public final JosmAction unJoinNodeWay = new UnJoinNodeWayAction();
    190192    public final JosmAction unglueNodes = new UnGlueAction();
    191193    public final JosmAction joinAreas = new JoinAreasAction();
    192194    public final JosmAction createMultipolygon = new CreateMultipolygonAction();
    public class MainMenu extends JMenuBar { 
    607609        toolsMenu.addSeparator();
    608610        add(toolsMenu, mergeNodes);
    609611        add(toolsMenu, joinNodeWay);
     612        add(toolsMenu, unJoinNodeWay);
    610613        add(toolsMenu, unglueNodes);
    611614        toolsMenu.addSeparator();
    612615        add(toolsMenu, joinAreas);