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

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

see #12943 - gsoc-core - fix most of deprecation warnings (static accesses must be fixed)

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