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

Last change on this file since 11124 was 10467, checked in by Don-vip, 8 years ago

fix #13037 - Small fixes for unit tests (patch by michael2402) - gsoc-core

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