Index: trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java	(revision 14319)
+++ trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java	(revision 14320)
@@ -6,5 +6,4 @@
 import static org.openstreetmap.josm.tools.I18n.trn;
 
-import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
@@ -19,10 +18,6 @@
 import java.util.Set;
 
-import javax.swing.AbstractButton;
-import javax.swing.ButtonGroup;
-import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
-import javax.swing.JToggleButton;
 
 import org.openstreetmap.josm.command.AddCommand;
@@ -38,10 +33,9 @@
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.gui.Notification;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.gui.dialogs.PropertiesMembershipChoiceDialog;
+import org.openstreetmap.josm.gui.dialogs.PropertiesMembershipChoiceDialog.ExistingBothNewChoice;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Shortcut;
@@ -181,106 +175,26 @@
     }
 
-    /**
-     * Provides toggle buttons to allow the user choose the existing node, the new nodes, or all of them.
-     */
-    private static class ExistingBothNewChoice {
-        final AbstractButton oldNode = new JToggleButton(tr("Existing node"), ImageProvider.get("dialogs/conflict/tagkeeptheir"));
-        final AbstractButton bothNodes = new JToggleButton(tr("Both nodes"), ImageProvider.get("dialogs/conflict/tagundecide"));
-        final AbstractButton newNode = new JToggleButton(tr("New node"), ImageProvider.get("dialogs/conflict/tagkeepmine"));
-
-        ExistingBothNewChoice(final boolean preselectNew) {
-            final ButtonGroup tagsGroup = new ButtonGroup();
-            tagsGroup.add(oldNode);
-            tagsGroup.add(bothNodes);
-            tagsGroup.add(newNode);
-            tagsGroup.setSelected((preselectNew ? newNode : oldNode).getModel(), true);
-        }
-    }
-
-    /**
-     * A dialog allowing 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.
-     */
-    static final class PropertiesMembershipDialog extends ExtendedDialog {
-
-        final transient ExistingBothNewChoice tags;
-        final transient ExistingBothNewChoice memberships;
-
-        private PropertiesMembershipDialog(boolean preselectNew, boolean queryTags, boolean queryMemberships) {
-            super(MainApplication.getMainFrame(), tr("Tags/Memberships"), tr("Unglue"), tr("Cancel"));
-            setButtonIcons("unglueways", "cancel");
-
-            final JPanel content = new JPanel(new GridBagLayout());
-
-            if (queryTags) {
-                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));
-                tags = new ExistingBothNewChoice(preselectNew);
-                content.add(tags.oldNode, GBC.std(1, 2));
-                content.add(tags.bothNodes, GBC.std(2, 2));
-                content.add(tags.newNode, GBC.std(3, 2));
-            } else {
-                tags = null;
-            }
-
-            if (queryMemberships) {
-                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));
-                memberships = new ExistingBothNewChoice(preselectNew);
-                content.add(memberships.oldNode, GBC.std(1, 4));
-                content.add(memberships.bothNodes, GBC.std(2, 4));
-                content.add(memberships.newNode, GBC.std(3, 4));
-            } else {
-                memberships = null;
-            }
-
-            setContent(content);
-            setResizable(false);
-        }
-
-        static PropertiesMembershipDialog showIfNecessary(Collection<Node> selectedNodes, boolean preselectNew) throws UserCancelException {
-            final boolean tagged = isTagged(selectedNodes);
-            final boolean usedInRelations = isUsedInRelations(selectedNodes);
-            if (tagged || usedInRelations) {
-                final PropertiesMembershipDialog dialog = new PropertiesMembershipDialog(preselectNew, tagged, usedInRelations);
-                dialog.showDialog();
-                if (dialog.getValue() != 1) {
-                    throw new UserCancelException();
-                }
-                return dialog;
-            }
-            return null;
-        }
-
-        private static boolean isTagged(final Collection<Node> existingNodes) {
-            return existingNodes.stream().anyMatch(Node::hasKeys);
-        }
-
-        private static boolean isUsedInRelations(final Collection<Node> existingNodes) {
-            return existingNodes.stream().anyMatch(
-                    selectedNode -> selectedNode.getReferrers().stream().anyMatch(Relation.class::isInstance));
-        }
-
-        void update(final Node existingNode, final List<Node> newNodes, final Collection<Command> cmds) {
-            updateMemberships(existingNode, newNodes, cmds);
-            updateProperties(existingNode, newNodes, cmds);
-        }
-
-        private void updateProperties(final Node existingNode, final Iterable<Node> newNodes, final Collection<Command> cmds) {
-            if (tags != null && tags.newNode.isSelected()) {
-                final Node newSelectedNode = new Node(existingNode);
-                newSelectedNode.removeAll();
-                cmds.add(new ChangeCommand(existingNode, newSelectedNode));
-            } else if (tags != null && tags.oldNode.isSelected()) {
-                for (Node newNode : newNodes) {
-                    newNode.removeAll();
-                }
-            }
-        }
-
-        private void updateMemberships(final Node existingNode, final List<Node> newNodes, final Collection<Command> cmds) {
-            if (memberships != null && memberships.bothNodes.isSelected()) {
-                fixRelations(existingNode, cmds, newNodes, false);
-            } else if (memberships != null && memberships.newNode.isSelected()) {
-                fixRelations(existingNode, cmds, newNodes, true);
-            }
+    void update(PropertiesMembershipChoiceDialog dialog, Node existingNode, List<Node> newNodes, Collection<Command> cmds) {
+        updateMemberships(dialog.getMemberships(), existingNode, newNodes, cmds);
+        updateProperties(dialog.getTags(), existingNode, newNodes, cmds);
+    }
+
+    private void updateProperties(ExistingBothNewChoice tags, Node existingNode, Iterable<Node> newNodes, Collection<Command> cmds) {
+        if (tags != null && tags.newNode.isSelected()) {
+            final Node newSelectedNode = new Node(existingNode);
+            newSelectedNode.removeAll();
+            cmds.add(new ChangeCommand(existingNode, newSelectedNode));
+        } else if (tags != null && tags.oldNode.isSelected()) {
+            for (Node newNode : newNodes) {
+                newNode.removeAll();
+            }
+        }
+    }
+
+    private void updateMemberships(ExistingBothNewChoice memberships, Node existingNode, List<Node> newNodes, Collection<Command> cmds) {
+        if (memberships != null && memberships.bothNodes.isSelected()) {
+            fixRelations(existingNode, cmds, newNodes, false);
+        } else if (memberships != null && memberships.newNode.isSelected()) {
+            fixRelations(existingNode, cmds, newNodes, true);
         }
     }
@@ -292,7 +206,7 @@
      */
     private void unglueOneNodeAtMostOneWay(ActionEvent e) {
-        final PropertiesMembershipDialog dialog;
+        final PropertiesMembershipChoiceDialog dialog;
         try {
-            dialog = PropertiesMembershipDialog.showIfNecessary(Collections.singleton(selectedNode), true);
+            dialog = PropertiesMembershipChoiceDialog.showIfNecessary(Collections.singleton(selectedNode), true);
         } catch (UserCancelException ex) {
             Logging.trace(ex);
@@ -305,5 +219,5 @@
         cmds.add(new AddCommand(selectedNode.getDataSet(), n));
         if (dialog != null) {
-            dialog.update(selectedNode, Collections.singletonList(n), cmds);
+            update(dialog, selectedNode, Collections.singletonList(n), cmds);
         }
 
@@ -505,7 +419,7 @@
      */
     private void unglueWays() {
-        final PropertiesMembershipDialog dialog;
+        final PropertiesMembershipChoiceDialog dialog;
         try {
-            dialog = PropertiesMembershipDialog.showIfNecessary(Collections.singleton(selectedNode), false);
+            dialog = PropertiesMembershipChoiceDialog.showIfNecessary(Collections.singleton(selectedNode), false);
         } catch (UserCancelException e) {
             Logging.trace(e);
@@ -541,5 +455,5 @@
 
         if (dialog != null) {
-            dialog.update(selectedNode, newNodes, cmds);
+            update(dialog, selectedNode, newNodes, cmds);
         }
 
@@ -601,7 +515,8 @@
         notifyWayPartOfRelation(Collections.singleton(way));
         try {
-            final PropertiesMembershipDialog dialog = PropertiesMembershipDialog.showIfNecessary(Collections.singleton(selectedNode), false);
+            final PropertiesMembershipChoiceDialog dialog = PropertiesMembershipChoiceDialog.showIfNecessary(
+                    Collections.singleton(selectedNode), false);
             if (dialog != null) {
-                dialog.update(selectedNode, addNodes, cmds);
+                update(dialog, selectedNode, addNodes, cmds);
             }
             execCommands(cmds, addNodes);
@@ -620,7 +535,7 @@
         Way tmpWay = selectedWay;
 
-        final PropertiesMembershipDialog dialog;
+        final PropertiesMembershipChoiceDialog dialog;
         try {
-            dialog = PropertiesMembershipDialog.showIfNecessary(selectedNodes, false);
+            dialog = PropertiesMembershipChoiceDialog.showIfNecessary(selectedNodes, false);
         } catch (UserCancelException e) {
             Logging.trace(e);
@@ -634,5 +549,5 @@
             tmpWay = modifyWay(n, tmpWay, cmds, newNodes);
             if (dialog != null) {
-                dialog.update(n, newNodes, cmds);
+                update(dialog, n, newNodes, cmds);
             }
             allNewNodes.addAll(newNodes);
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesMembershipChoiceDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesMembershipChoiceDialog.java	(revision 14320)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesMembershipChoiceDialog.java	(revision 14320)
@@ -0,0 +1,129 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.util.Collection;
+
+import javax.swing.AbstractButton;
+import javax.swing.ButtonGroup;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JToggleButton;
+
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.UserCancelException;
+
+/**
+ * A dialog allowing 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.
+ * @since 14320 (extracted from UnglueAction)
+ */
+public final class PropertiesMembershipChoiceDialog extends ExtendedDialog {
+
+    private final transient ExistingBothNewChoice tags;
+    private final transient ExistingBothNewChoice memberships;
+
+    /**
+     * Provides toggle buttons to allow the user choose the existing node, the new nodes, or all of them.
+     */
+    public static class ExistingBothNewChoice {
+        /** The "Existing node" button */
+        public final AbstractButton oldNode = new JToggleButton(tr("Existing node"), ImageProvider.get("dialogs/conflict/tagkeeptheir"));
+        /** The "Both nodes" button */
+        public final AbstractButton bothNodes = new JToggleButton(tr("Both nodes"), ImageProvider.get("dialogs/conflict/tagundecide"));
+        /** The "New node" button */
+        public final AbstractButton newNode = new JToggleButton(tr("New node"), ImageProvider.get("dialogs/conflict/tagkeepmine"));
+
+        ExistingBothNewChoice(final boolean preselectNew) {
+            final ButtonGroup tagsGroup = new ButtonGroup();
+            tagsGroup.add(oldNode);
+            tagsGroup.add(bothNodes);
+            tagsGroup.add(newNode);
+            tagsGroup.setSelected((preselectNew ? newNode : oldNode).getModel(), true);
+        }
+    }
+
+    private PropertiesMembershipChoiceDialog(boolean preselectNew, boolean queryTags, boolean queryMemberships) {
+        super(MainApplication.getMainFrame(), tr("Tags/Memberships"), tr("Unglue"), tr("Cancel"));
+        setButtonIcons("unglueways", "cancel");
+
+        final JPanel content = new JPanel(new GridBagLayout());
+
+        if (queryTags) {
+            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));
+            tags = new ExistingBothNewChoice(preselectNew);
+            content.add(tags.oldNode, GBC.std(1, 2));
+            content.add(tags.bothNodes, GBC.std(2, 2));
+            content.add(tags.newNode, GBC.std(3, 2));
+        } else {
+            tags = null;
+        }
+
+        if (queryMemberships) {
+            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));
+            memberships = new ExistingBothNewChoice(preselectNew);
+            content.add(memberships.oldNode, GBC.std(1, 4));
+            content.add(memberships.bothNodes, GBC.std(2, 4));
+            content.add(memberships.newNode, GBC.std(3, 4));
+        } else {
+            memberships = null;
+        }
+
+        setContent(content);
+        setResizable(false);
+    }
+
+    /**
+     * Returns the tags choice.
+     * @return the tags choice (can be null)
+     */
+    public ExistingBothNewChoice getTags() {
+        return tags;
+    }
+
+    /**
+     * Returns the memberships choice.
+     * @return the memberships choice (can be null)
+     */
+    public ExistingBothNewChoice getMemberships() {
+        return memberships;
+    }
+
+    /**
+     * Creates and shows a new {@code PropertiesMembershipChoiceDialog} if necessary. Otherwise does nothing.
+     * @param selectedNodes selected nodes
+     * @param preselectNew if {@code true}, pre-select "new node" as default choice
+     * @return A new {@code PropertiesMembershipChoiceDialog} that has been shown to user, or {@code null}
+     * @throws UserCancelException if user cancels choice
+     */
+    public static PropertiesMembershipChoiceDialog showIfNecessary(Collection<Node> selectedNodes, boolean preselectNew)
+            throws UserCancelException {
+        final boolean queryTags = isTagged(selectedNodes);
+        final boolean queryMemberships = isUsedInRelations(selectedNodes);
+        if (queryTags || queryMemberships) {
+            final PropertiesMembershipChoiceDialog dialog = new PropertiesMembershipChoiceDialog(preselectNew, queryTags, queryMemberships);
+            dialog.showDialog();
+            if (dialog.getValue() != 1) {
+                throw new UserCancelException();
+            }
+            return dialog;
+        }
+        return null;
+    }
+
+    private static boolean isTagged(final Collection<Node> existingNodes) {
+        return existingNodes.stream().anyMatch(Node::hasKeys);
+    }
+
+    private static boolean isUsedInRelations(final Collection<Node> existingNodes) {
+        return existingNodes.stream().anyMatch(
+                selectedNode -> selectedNode.getReferrers().stream().anyMatch(Relation.class::isInstance));
+    }
+}
