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

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

refactor duplicated code

  • Property svn:eol-style set to native
File size: 7.3 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 = getCurrentDataSet().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 Main.map.repaint();
94 }
95
96 /**
97 * Send a notification message.
98 * @param msg Message to be sent.
99 * @param messageType Nature of the message.
100 */
101 public void notify(String msg, int messageType) {
102 new Notification(msg).setIcon(messageType).show();
103 }
104
105 /**
106 * Removes irrelevant nodes from user selection.
107 *
108 * The action can be performed reliably even if we remove :
109 * * Nodes not referenced by any ways
110 * * When only one way is selected, nodes not part of this way (#10396).
111 *
112 * @param selectedWays List of user selected way.
113 * @param selectedNodes List of user selected nodes.
114 * @return New list of nodes cleaned of irrelevant nodes.
115 */
116 private List<Node> cleanSelectedNodes(List<Way> selectedWays,
117 List<Node> selectedNodes) {
118 List<Node> resultingNodes = new LinkedList<>();
119
120 // List of node referenced by a route
121 for (Node n: selectedNodes) {
122 if (n.isReferredByWays(1)) {
123 resultingNodes.add(n);
124 }
125 }
126 // If exactly one selected way, remove node not referencing par this way.
127 if (selectedWays.size() == 1) {
128 Way w = selectedWays.get(0);
129 for (Node n: new ArrayList<Node>(resultingNodes)) {
130 if (!w.containsNode(n)) {
131 resultingNodes.remove(n);
132 }
133 }
134 }
135 // Warn if nodes were removed
136 if (resultingNodes.size() != selectedNodes.size()) {
137 notify(tr("Some irrelevant nodes have been removed from the selection"),
138 JOptionPane.INFORMATION_MESSAGE);
139 }
140 return resultingNodes;
141 }
142
143 /**
144 * Find ways to which the disconnect can be applied. This is the list of ways
145 * with more than two nodes which pass through all the given nodes, intersected
146 * with the selected ways (if any)
147 * @param selectedWays List of user selected ways.
148 * @param selectedNodes List of user selected nodes.
149 * @return List of relevant ways
150 */
151 static List<Way> getApplicableWays(List<Way> selectedWays, List<Node> selectedNodes) {
152 if (selectedNodes.isEmpty())
153 return null;
154
155 // List of ways shared by all nodes
156 List<Way> result = new ArrayList<>(OsmPrimitive.getFilteredList(selectedNodes.get(0).getReferrers(), Way.class));
157 for (int i = 1; i < selectedNodes.size(); i++) {
158 List<OsmPrimitive> ref = selectedNodes.get(i).getReferrers();
159 for (Iterator<Way> it = result.iterator(); it.hasNext();) {
160 if (!ref.contains(it.next())) {
161 it.remove();
162 }
163 }
164 }
165
166 // Remove broken ways
167 for (Iterator<Way> it = result.iterator(); it.hasNext();) {
168 if (it.next().getNodesCount() <= 2) {
169 it.remove();
170 }
171 }
172
173 if (selectedWays.isEmpty())
174 return result;
175 else {
176 // Return only selected ways
177 for (Iterator<Way> it = result.iterator(); it.hasNext();) {
178 if (!selectedWays.contains(it.next())) {
179 it.remove();
180 }
181 }
182 return result;
183 }
184 }
185
186 @Override
187 protected void updateEnabledState() {
188 if (getCurrentDataSet() == null) {
189 setEnabled(false);
190 } else {
191 updateEnabledState(getCurrentDataSet().getSelected());
192 }
193 }
194
195 @Override
196 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
197 setEnabled(selection != null && !selection.isEmpty());
198 }
199}
Note: See TracBrowser for help on using the repository browser.