source: josm/trunk/src/org/openstreetmap/josm/actions/UnJoinNodeWayAction.java@ 12288

Last change on this file since 12288 was 12031, checked in by Don-vip, 7 years ago

add Node.getParentWays()

  • Property svn:eol-style set to native
File size: 6.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
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.LinkedList;
13import java.util.List;
14
15import javax.swing.JOptionPane;
16
17import org.openstreetmap.josm.Main;
18import org.openstreetmap.josm.command.RemoveNodesCommand;
19import org.openstreetmap.josm.data.osm.Node;
20import org.openstreetmap.josm.data.osm.OsmPrimitive;
21import org.openstreetmap.josm.data.osm.Way;
22import org.openstreetmap.josm.gui.Notification;
23import org.openstreetmap.josm.tools.Shortcut;
24
25/**
26 * Disconnect nodes from a way they currently belong to.
27 * @since 6253
28 */
29public class UnJoinNodeWayAction extends JosmAction {
30
31 /**
32 * Constructs a new {@code UnJoinNodeWayAction}.
33 */
34 public UnJoinNodeWayAction() {
35 super(tr("Disconnect Node from Way"), "unjoinnodeway",
36 tr("Disconnect nodes from a way they currently belong to"),
37 Shortcut.registerShortcut("tools:unjoinnodeway",
38 tr("Tool: {0}", tr("Disconnect Node from Way")), KeyEvent.VK_J, Shortcut.ALT), true);
39 putValue("help", ht("/Action/UnJoinNodeWay"));
40 }
41
42 /**
43 * Called when the action is executed.
44 */
45 @Override
46 public void actionPerformed(ActionEvent e) {
47
48 Collection<OsmPrimitive> selection = getLayerManager().getEditDataSet().getSelected();
49
50 List<Node> selectedNodes = OsmPrimitive.getFilteredList(selection, Node.class);
51 List<Way> selectedWays = OsmPrimitive.getFilteredList(selection, Way.class);
52
53 selectedNodes = cleanSelectedNodes(selectedWays, selectedNodes);
54
55 List<Way> applicableWays = getApplicableWays(selectedWays, selectedNodes);
56
57 if (applicableWays == null) {
58 notify(tr("Select at least one node to be disconnected."),
59 JOptionPane.WARNING_MESSAGE);
60 return;
61 } else if (applicableWays.isEmpty()) {
62 notify(trn("Selected node cannot be disconnected from anything.",
63 "Selected nodes cannot be disconnected from anything.",
64 selectedNodes.size()),
65 JOptionPane.WARNING_MESSAGE);
66 return;
67 } else if (applicableWays.size() > 1) {
68 notify(trn("There is more than one way using the node you selected. "
69 + "Please select the way also.",
70 "There is more than one way using the nodes you selected. "
71 + "Please select the way also.",
72 selectedNodes.size()),
73 JOptionPane.WARNING_MESSAGE);
74 return;
75 } else if (applicableWays.get(0).getRealNodesCount() < selectedNodes.size() + 2) {
76 // there is only one affected way, but removing the selected nodes would only leave it
77 // with less than 2 nodes
78 notify(trn("The affected way would disappear after disconnecting the "
79 + "selected node.",
80 "The affected way would disappear after disconnecting the "
81 + "selected nodes.",
82 selectedNodes.size()),
83 JOptionPane.WARNING_MESSAGE);
84 return;
85 }
86
87 // Finally, applicableWays contains only one perfect way
88 Way selectedWay = applicableWays.get(0);
89
90 // I'm sure there's a better way to handle this
91 Main.main.undoRedo.add(new RemoveNodesCommand(selectedWay, selectedNodes));
92 }
93
94 /**
95 * Send a notification message.
96 * @param msg Message to be sent.
97 * @param messageType Nature of the message.
98 */
99 public void notify(String msg, int messageType) {
100 new Notification(msg).setIcon(messageType).show();
101 }
102
103 /**
104 * Removes irrelevant nodes from user selection.
105 *
106 * The action can be performed reliably even if we remove :
107 * * Nodes not referenced by any ways
108 * * When only one way is selected, nodes not part of this way (#10396).
109 *
110 * @param selectedWays List of user selected way.
111 * @param selectedNodes List of user selected nodes.
112 * @return New list of nodes cleaned of irrelevant nodes.
113 */
114 private List<Node> cleanSelectedNodes(List<Way> selectedWays,
115 List<Node> selectedNodes) {
116 List<Node> resultingNodes = new LinkedList<>();
117
118 // List of node referenced by a route
119 for (Node n: selectedNodes) {
120 if (n.isReferredByWays(1)) {
121 resultingNodes.add(n);
122 }
123 }
124 // If exactly one selected way, remove node not referencing par this way.
125 if (selectedWays.size() == 1) {
126 Way w = selectedWays.get(0);
127 for (Node n: new ArrayList<Node>(resultingNodes)) {
128 if (!w.containsNode(n)) {
129 resultingNodes.remove(n);
130 }
131 }
132 }
133 // Warn if nodes were removed
134 if (resultingNodes.size() != selectedNodes.size()) {
135 notify(tr("Some irrelevant nodes have been removed from the selection"),
136 JOptionPane.INFORMATION_MESSAGE);
137 }
138 return resultingNodes;
139 }
140
141 /**
142 * Find ways to which the disconnect can be applied. This is the list of ways
143 * with more than two nodes which pass through all the given nodes, intersected
144 * with the selected ways (if any)
145 * @param selectedWays List of user selected ways.
146 * @param selectedNodes List of user selected nodes.
147 * @return List of relevant ways
148 */
149 static List<Way> getApplicableWays(List<Way> selectedWays, List<Node> selectedNodes) {
150 if (selectedNodes.isEmpty())
151 return null;
152
153 // List of ways shared by all nodes
154 List<Way> result = new ArrayList<>(selectedNodes.get(0).getParentWays());
155 for (int i = 1; i < selectedNodes.size(); i++) {
156 List<Way> ref = selectedNodes.get(i).getParentWays();
157 result.removeIf(way -> !ref.contains(way));
158 }
159
160 // Remove broken ways
161 result.removeIf(way -> way.getNodesCount() <= 2);
162
163 if (selectedWays.isEmpty())
164 return result;
165 else {
166 // Return only selected ways
167 result.removeIf(way -> !selectedWays.contains(way));
168 return result;
169 }
170 }
171
172 @Override
173 protected void updateEnabledState() {
174 updateEnabledStateOnCurrentSelection();
175 }
176
177 @Override
178 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
179 setEnabled(selection != null && !selection.isEmpty());
180 }
181}
Note: See TracBrowser for help on using the repository browser.