Index: trunk/src/org/openstreetmap/josm/actions/UnJoinNodeWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UnJoinNodeWayAction.java	(revision 6253)
+++ trunk/src/org/openstreetmap/josm/actions/UnJoinNodeWayAction.java	(revision 6253)
@@ -0,0 +1,138 @@
+//License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.actions;
+
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trn;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.RemoveNodesCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.tools.Shortcut;
+
+public class UnJoinNodeWayAction extends JosmAction {
+    public UnJoinNodeWayAction() {
+        super(tr("Disconnect Node from Way"), "unjoinnodeway",
+                tr("Disconnect nodes from a way they currently belong to"),
+                Shortcut.registerShortcut("tools:unjoinnodeway",
+                    tr("Tool: {0}", tr("Disconnect Node from Way")), KeyEvent.VK_J, Shortcut.ALT), true);
+        putValue("help", ht("/Action/UnJoinNodeWay"));
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+
+        Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected();
+
+        List<Node> selectedNodes = OsmPrimitive.getFilteredList(selection, Node.class);
+        List<Way> selectedWays = OsmPrimitive.getFilteredList(selection, Way.class);
+        List<Way> applicableWays = getApplicableWays(selectedWays, selectedNodes);
+
+        if (applicableWays == null) {
+            JOptionPane.showMessageDialog(
+                    Main.parent,
+                    tr("Select at least one node to be disconnected."),
+                    tr("Warning"),
+                    JOptionPane.WARNING_MESSAGE);
+            return;
+        } else if (applicableWays.isEmpty()) {
+            JOptionPane.showMessageDialog(Main.parent,
+                    trn("Selected node cannot be disconnected from anything.",
+                        "Selected nodes cannot be disconnected from anything.",
+                        selectedNodes.size()),
+                    tr("Warning"),
+                    JOptionPane.WARNING_MESSAGE);
+            return;
+        } else if (applicableWays.size() > 1) {
+            JOptionPane.showMessageDialog(Main.parent,
+                    trn("There is more than one way using the node you selected. Please select the way also.",
+                        "There is more than one way using the nodes you selected. Please select the way also.",
+                        selectedNodes.size()),
+                    tr("Warning"),
+                    JOptionPane.WARNING_MESSAGE);
+            return;
+        } else if (applicableWays.get(0).getRealNodesCount() < selectedNodes.size() + 2) {
+            // there is only one affected way, but removing the selected nodes would only leave it
+            // with less than 2 nodes
+            JOptionPane.showMessageDialog(Main.parent,
+                    trn("The affected way would disappear after disconnecting the selected node.",
+                        "The affected way would disappear after disconnecting the selected nodes.",
+                        selectedNodes.size()),
+                    tr("Warning"),
+                    JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+
+
+        // Finally, applicableWays contains only one perfect way
+        Way selectedWay = applicableWays.get(0);
+
+        // I'm sure there's a better way to handle this
+        Main.main.undoRedo.add(new RemoveNodesCommand(selectedWay, selectedNodes));
+        Main.map.repaint();
+    }
+
+    // Find ways to which the disconnect can be applied. This is the list of ways with more
+    // than two nodes which pass through all the given nodes, intersected with the selected ways (if any)
+    private List<Way> getApplicableWays(List<Way> selectedWays, List<Node> selectedNodes) {
+        if (selectedNodes.isEmpty())
+            return null;
+
+        // List of ways shared by all nodes
+        List<Way> result = new ArrayList<Way>(OsmPrimitive.getFilteredList(selectedNodes.get(0).getReferrers(), Way.class));
+        for (int i=1; i<selectedNodes.size(); i++) {
+            List<OsmPrimitive> ref = selectedNodes.get(i).getReferrers();
+            for (Iterator<Way> it = result.iterator(); it.hasNext(); ) {
+                if (!ref.contains(it.next())) {
+                    it.remove();
+                }
+            }
+        }
+
+        // Remove broken ways
+        for (Iterator<Way> it = result.iterator(); it.hasNext(); ) {
+            if (it.next().getNodesCount() <= 2) {
+                it.remove();
+            }
+        }
+
+        if (selectedWays.isEmpty())
+            return result;
+        else {
+            // Return only selected ways
+            for (Iterator<Way> it = result.iterator(); it.hasNext(); ) {
+                if (!selectedWays.contains(it.next())) {
+                    it.remove();
+                }
+            }
+            return result;
+        }
+    }
+
+    @Override
+    protected void updateEnabledState() {
+        if (getCurrentDataSet() == null) {
+            setEnabled(false);
+        } else {
+            updateEnabledState(getCurrentDataSet().getSelected());
+        }
+    }
+
+    @Override
+    protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
+        setEnabled(selection != null && !selection.isEmpty());
+    }
+}
Index: trunk/src/org/openstreetmap/josm/command/RemoveNodesCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/RemoveNodesCommand.java	(revision 6253)
+++ trunk/src/org/openstreetmap/josm/command/RemoveNodesCommand.java	(revision 6253)
@@ -0,0 +1,56 @@
+// License: GPL. See LICENSE file for details.
+package org.openstreetmap.josm.command;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import javax.swing.Icon;
+
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.gui.DefaultNameFormatter;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * Command that removes a set of nodes from a way.
+ * The same can be done with ChangeNodesCommand, but this is more
+ * efficient. (Needed for the tool to disconnect nodes from ways.)
+ *
+ * @author Giuseppe Bilotta
+ */
+public class RemoveNodesCommand extends Command {
+
+    private final Way way;
+    private final HashSet<Node> rmNodes;
+
+    public RemoveNodesCommand(Way way, List<Node> rmNodes) {
+        super();
+        this.way = way;
+        this.rmNodes = new HashSet<Node>(rmNodes);
+    }
+
+    @Override public boolean executeCommand() {
+        super.executeCommand();
+        way.removeNodes(rmNodes);
+        way.setModified(true);
+        return true;
+    }
+
+    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+        modified.add(way);
+    }
+
+    @Override
+    public String getDescriptionText() {
+        return tr("Removed nodes from {0}", way.getDisplayName(DefaultNameFormatter.getInstance()));
+    }
+
+    @Override
+    public Icon getDescriptionIcon() {
+        return ImageProvider.get(OsmPrimitiveType.WAY);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 6252)
+++ trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 6253)
@@ -85,4 +85,5 @@
 import org.openstreetmap.josm.actions.ToggleGPXLinesAction;
 import org.openstreetmap.josm.actions.UnGlueAction;
+import org.openstreetmap.josm.actions.UnJoinNodeWayAction;
 import org.openstreetmap.josm.actions.UndoAction;
 import org.openstreetmap.josm.actions.UnselectAllAction;
@@ -225,4 +226,5 @@
     public final JosmAction mergeNodes = new MergeNodesAction();
     public final JosmAction joinNodeWay = new JoinNodeWayAction();
+    public final JosmAction unJoinNodeWay = new UnJoinNodeWayAction();
     public final JosmAction unglueNodes = new UnGlueAction();
     public final JosmAction joinAreas = new JoinAreasAction();
@@ -686,4 +688,5 @@
         add(toolsMenu, mergeNodes);
         add(toolsMenu, joinNodeWay);
+        add(toolsMenu, unJoinNodeWay);
         add(toolsMenu, unglueNodes);
         toolsMenu.addSeparator();
