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