//License: GPL. For details, see LICENSE file. 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.Iterator; import java.util.List; import javax.swing.JOptionPane; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.command.RemoveNodesCommand; 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; /** * Disconnect nodes from a way they currently belong to. * @since 6253 */ public class UnJoinNodeWayAction extends JosmAction { /** * Constructs a new {@code UnJoinNodeWayAction}. */ 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 selection = getCurrentDataSet().getSelected(); List selectedNodes = OsmPrimitive.getFilteredList(selection, Node.class); List selectedWays = OsmPrimitive.getFilteredList(selection, Way.class); List 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 getApplicableWays(List selectedWays, List selectedNodes) { if (selectedNodes.isEmpty()) return null; // List of ways shared by all nodes List result = new ArrayList<>(OsmPrimitive.getFilteredList(selectedNodes.get(0).getReferrers(), Way.class)); for (int i=1; i ref = selectedNodes.get(i).getReferrers(); for (Iterator it = result.iterator(); it.hasNext(); ) { if (!ref.contains(it.next())) { it.remove(); } } } // Remove broken ways for (Iterator it = result.iterator(); it.hasNext(); ) { if (it.next().getNodesCount() <= 2) { it.remove(); } } if (selectedWays.isEmpty()) return result; else { // Return only selected ways for (Iterator 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 selection) { setEnabled(selection != null && !selection.isEmpty()); } }