source: osm/applications/editors/josm/plugins/merge-overlap/src/mergeoverlap/MergeOverlapAction.java@ 26575

Last change on this file since 26575 was 26575, checked in by sbrunner, 13 years ago

initial version

File size: 28.1 KB
Line 
1package mergeoverlap;
2
3import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.combineTigerTags;
4import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.completeTagCollectionForEditing;
5import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.normalizeTagCollectionBeforeEditing;
6import static org.openstreetmap.josm.tools.I18n.tr;
7
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.rmi.server.RMIClassLoader;
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.HashMap;
16import java.util.HashSet;
17import java.util.Iterator;
18import java.util.LinkedHashSet;
19import java.util.LinkedList;
20import java.util.List;
21import java.util.Map;
22import java.util.Set;
23
24import javax.swing.JOptionPane;
25
26import org.openstreetmap.josm.Main;
27import org.openstreetmap.josm.actions.JosmAction;
28import org.openstreetmap.josm.actions.SplitWayAction;
29import org.openstreetmap.josm.actions.CombineWayAction.NodeGraph;
30import org.openstreetmap.josm.actions.SplitWayAction.SplitWayResult;
31import org.openstreetmap.josm.command.AddCommand;
32import org.openstreetmap.josm.command.ChangeCommand;
33import org.openstreetmap.josm.command.Command;
34import org.openstreetmap.josm.command.DeleteCommand;
35import org.openstreetmap.josm.command.SequenceCommand;
36import org.openstreetmap.josm.corrector.ReverseWayTagCorrector;
37import org.openstreetmap.josm.corrector.UserCancelException;
38import org.openstreetmap.josm.data.osm.Node;
39import org.openstreetmap.josm.data.osm.OsmPrimitive;
40import org.openstreetmap.josm.data.osm.Relation;
41import org.openstreetmap.josm.data.osm.RelationMember;
42import org.openstreetmap.josm.data.osm.TagCollection;
43import org.openstreetmap.josm.data.osm.Way;
44import org.openstreetmap.josm.gui.layer.OsmDataLayer;
45import org.openstreetmap.josm.tools.Pair;
46import org.openstreetmap.josm.tools.Shortcut;
47
48/**
49 * Merge overlapping part of ways.
50 */
51@SuppressWarnings("serial")
52public class MergeOverlapAction extends JosmAction {
53
54 public MergeOverlapAction() {
55 super(tr("Merge overlap"), "merge_overlap",
56 tr("Merge overlap of ways."), Shortcut.registerShortcut(
57 "tools:mergeoverlap", tr("Tool: {0}",
58 tr("Merge overlap")), KeyEvent.VK_O,
59 Shortcut.GROUP_EDIT, Shortcut.SHIFT_DEFAULT), true);
60 }
61
62 Map<Way, List<Relation>> relations = new HashMap<Way, List<Relation>>();
63 Map<Way, Way> oldWays = new HashMap<Way, Way>();
64 Map<Relation, Relation> newRelations = new HashMap<Relation, Relation>();
65 Set<Way> deletes = new HashSet<Way>();
66
67 /**
68 * The action button has been clicked
69 *
70 * @param e Action Event
71 */
72 public void actionPerformed(ActionEvent e) {
73
74 // List of selected ways
75 List<Way> ways = new ArrayList<Way>();
76 relations.clear();
77 newRelations.clear();
78
79 // For every selected way
80 for (OsmPrimitive osm : Main.main.getCurrentDataSet().getSelected()) {
81 if (osm instanceof Way && !osm.isDeleted()) {
82 Way way = (Way)osm;
83 ways.add(way);
84 List<Relation> rels = new ArrayList<Relation>();
85 for (Relation r: OsmPrimitive.getFilteredList(way.getReferrers(), Relation.class)) {
86 rels.add(r);
87 }
88 relations.put(way, rels);
89 }
90 }
91
92 List<Way> sel = new ArrayList<Way>(ways);
93 Collection<Command> cmds = new LinkedList<Command>();
94
95 // *****
96 // split
97 // *****
98 for (Way way : ways) {
99 Set<Node> nodes = new HashSet<Node>();
100 for (Way opositWay : ways) {
101 if (way != opositWay) {
102 List<NodePos> nodesPos = new LinkedList<NodePos>();
103
104 int pos = 0;
105 for (Node node : way.getNodes()) {
106 int opositPos = 0;
107 for (Node opositNode : opositWay.getNodes()) {
108 if (node == opositNode) {
109 if (opositWay.isClosed()) {
110 opositPos %= opositWay.getNodesCount() - 1;
111 }
112 nodesPos.add(new NodePos(node, pos, opositPos));
113 break;
114 }
115 opositPos++;
116 }
117 pos++;
118 }
119
120 NodePos start = null;
121 NodePos end = null;
122 int increment = 0;
123
124 boolean hasFirst = false;
125 for (NodePos node : nodesPos) {
126 if (start == null) {
127 start = node;
128 }
129 else {
130 if (end == null) {
131 if (follows(way, opositWay, start, node, 1)) {
132 end = node;
133 increment = +1;
134 }
135 else if (follows(way, opositWay, start, node, -1)) {
136 end = node;
137 increment = -1;
138 }
139 else {
140 start = node;
141 end = null;
142 }
143 }
144 else {
145 if (follows(way, opositWay, end, node, increment)) {
146 end = node;
147 }
148 else {
149 hasFirst = addNodes(start, end, way, nodes, hasFirst);
150 start = node;
151 end = null;
152 }
153 }
154 }
155 }
156
157 if (start != null && end != null) {
158 hasFirst = addNodes(start, end, way, nodes, hasFirst);
159 start = null;
160 end = null;
161 }
162 }
163 }
164 if (!nodes.isEmpty() && !way.isClosed() || nodes.size() >= 2) {
165 List<List<Node>> wayChunks = SplitWayAction.buildSplitChunks(way, new ArrayList<Node>(nodes));
166 SplitWayResult result = splitWay(getEditLayer(), way, wayChunks);
167
168 cmds.add(result.getCommand());
169 sel.remove(way);
170 sel.add(result.getOriginalWay());
171 sel.addAll(result.getNewWays());
172 List<Relation> rels = relations.remove(way);
173 relations.put(result.getOriginalWay(), rels);
174 for (Way w: result.getNewWays()) {
175 relations.put(w, rels);
176 }
177 }
178 }
179
180 // *****
181 // merge
182 // *****
183 ways = new ArrayList<Way>(sel);
184 while (!ways.isEmpty()) {
185 Way way = ways.get(0);
186 List<Way> combine = new ArrayList<Way>();
187 combine.add(way);
188 for (Way opositWay : ways) {
189 if (way != opositWay && way.getNodesCount() == opositWay.getNodesCount()) {
190 boolean equals1 = true;
191 for (int i = 0 ; i < way.getNodesCount() ; i++) {
192 if (way.getNode(i) != opositWay.getNode(i)) {
193 equals1 = false;
194 break;
195 }
196 }
197 boolean equals2 = true;
198 for (int i = 0 ; i < way.getNodesCount() ; i++) {
199 if (way.getNode(i) != opositWay.getNode(way.getNodesCount() - i -1)) {
200 equals2 = false;
201 break;
202 }
203 }
204 if (equals1 || equals2) {
205 combine.add(opositWay);
206 }
207 }
208 }
209 ways.removeAll(combine);
210 if (combine.size() > 1) {
211 sel.removeAll(combine);
212 // combine
213 Pair<Way, List<Command>> combineResult;
214 try {
215 combineResult = combineWaysWorker(combine);
216 } catch (UserCancelException e1) {
217 return;
218 }
219 sel.add(combineResult.a);
220 cmds.addAll(combineResult.b);
221 }
222 }
223
224 for (Relation old: newRelations.keySet()) {
225 System.out.println("+++++++++++++");
226 System.out.println("old");
227 System.out.println(old.getDataSet());
228 System.out.println("new");
229 System.out.println(newRelations.get(old).getDataSet());
230
231// for (int i=0; i < old.getMembersCount(); i++) {
232 for (int i=0; i < newRelations.get(old).getMembersCount(); i++) {
233 RelationMember rm = newRelations.get(old).getMember(i);
234// RelationMember rm = old.getMember(i);
235 System.out.println("***********");
236 System.out.println("old");
237 // System.out.println(rm.getMember());
238 System.out.println(rm.getWay().getId());
239 System.out.println(rm.getWay().getDataSet());
240/* System.out.println("new");
241 Way w = newWays.get(rm.getWay());
242// System.out.println(w);
243 if (w == null) {
244 System.out.println(w);
245 }
246 else {
247 System.out.println(w.getDataSet());
248 }*/
249 }
250 cmds.add(new ChangeCommand(old, newRelations.get(old)));
251 }
252
253 List<Way> del = new LinkedList<Way>();
254 for (Way w: deletes) {
255 if (!w.isDeleted()) {
256 del.add(w);
257 }
258 }
259 if (!del.isEmpty()) {
260 cmds.add(new DeleteCommand(del));
261 }
262
263 // Commit
264 Main.main.undoRedo.add(new SequenceCommand(tr("Merge Overlap (combine)"), cmds));
265 getCurrentDataSet().setSelected(sel);
266 Main.map.repaint();
267
268 relations.clear();
269 newRelations.clear();
270 oldWays.clear();
271 }
272
273 private class NodePos {
274 Node node;
275 int pos;
276 int opositPos;
277 NodePos (Node n, int p, int op) {
278 node = n;
279 pos = p;
280 opositPos = op;
281 }
282 public String toString() {
283 return "NodePos: " + pos + ", " + opositPos + ", " + node;
284 }
285 }
286
287 private boolean addNodes(NodePos start, NodePos end, Way way, Set<Node> nodes,
288 boolean hasFirst) {
289 if (way.isClosed() || (start.node != way.getNode(0)
290 && start.node != way.getNode(way.getNodesCount() - 1))) {
291 hasFirst = hasFirst || start.node == way.getNode(0);
292 nodes.add(start.node);
293 }
294 if (way.isClosed() || (end.node != way.getNode(0)
295 && end.node != way.getNode(way.getNodesCount() - 1))) {
296 if (hasFirst && (end.node == way.getNode(way.getNodesCount() - 1))) {
297 nodes.remove(way.getNode(0));
298 }
299 else {
300 nodes.add(end.node);
301 }
302 }
303 return hasFirst;
304 }
305
306 private boolean follows(Way way1, Way way2, NodePos np1, NodePos np2, int incr) {
307 if (way2.isClosed() && incr == 1 && np1.opositPos == way2.getNodesCount() - 2) {
308 return np2.pos == np1.pos + 1 && np2.opositPos == 0;
309 }
310 else if (way2.isClosed() && incr == 1 && np1.opositPos == 0) {
311 return np2.pos == np1.pos && np2.opositPos == 0
312 || np2.pos == np1.pos + 1 && np2.opositPos == 1;
313 }
314 else if (way2.isClosed() && incr == -1 && np1.opositPos == 0) {
315 return np2.pos == np1.pos && np2.opositPos == 0
316 || np2.pos == np1.pos + 1 && np2.opositPos == way2.getNodesCount() - 2;
317 }
318 else {
319 return np2.pos == np1.pos + 1 && np2.opositPos == np1.opositPos + incr;
320 }
321 }
322
323 /**
324 * Splits a way
325 *
326 * @param layer
327 * @param way
328 * @param wayChunks
329 * @return
330 */
331 private SplitWayResult splitWay(OsmDataLayer layer, Way way, List<List<Node>> wayChunks) {
332 // build a list of commands, and also a new selection list
333 Collection<Command> commandList = new ArrayList<Command>(wayChunks.size());
334
335 Iterator<List<Node>> chunkIt = wayChunks.iterator();
336 Collection<String> nowarnroles = Main.pref.getCollection(
337 "way.split.roles.nowarn", Arrays.asList(new String[] {
338 "outer", "inner", "forward", "backward" }));
339
340 // First, change the original way
341 Way changedWay = new Way(way);
342 oldWays.put(changedWay, way);
343 changedWay.setNodes(chunkIt.next());
344 commandList.add(new ChangeCommand(way, changedWay));
345
346 List<Way> newWays = new ArrayList<Way>();
347 // Second, create new ways
348 while (chunkIt.hasNext()) {
349 Way wayToAdd = new Way();
350 wayToAdd.setKeys(way.getKeys());
351 newWays.add(wayToAdd);
352 wayToAdd.setNodes(chunkIt.next());
353 commandList.add(new AddCommand(layer, wayToAdd));
354 }
355 boolean warnmerole = false;
356 boolean warnme = false;
357 // now copy all relations to new way also
358
359 for (Relation r : getParentRelations(way)) {
360 if (!r.isUsable()) {
361 continue;
362 }
363 Relation c = null;
364 String type = r.get("type");
365 if (type == null) {
366 type = "";
367 }
368
369 int i_c = 0, i_r = 0;
370 List<RelationMember> relationMembers = r.getMembers();
371 for (RelationMember rm : relationMembers) {
372 if (rm.isWay() && rm.getMember() == way) {
373 boolean insert = true;
374 if ("restriction".equals(type)) {
375 /*
376 * this code assumes the restriction is correct. No real
377 * error checking done
378 */
379 String role = rm.getRole();
380 if ("from".equals(role) || "to".equals(role)) {
381 OsmPrimitive via = null;
382 for (RelationMember rmv : r.getMembers()) {
383 if ("via".equals(rmv.getRole())) {
384 via = rmv.getMember();
385 }
386 }
387 List<Node> nodes = new ArrayList<Node>();
388 if (via != null) {
389 if (via instanceof Node) {
390 nodes.add((Node) via);
391 } else if (via instanceof Way) {
392 nodes.add(((Way) via).lastNode());
393 nodes.add(((Way) via).firstNode());
394 }
395 }
396 Way res = null;
397 for (Node n : nodes) {
398 if (changedWay.isFirstLastNode(n)) {
399 res = way;
400 }
401 }
402 if (res == null) {
403 for (Way wayToAdd : newWays) {
404 for (Node n : nodes) {
405 if (wayToAdd.isFirstLastNode(n)) {
406 res = wayToAdd;
407 }
408 }
409 }
410 if (res != null) {
411 if (c == null) {
412 c = getNew(r);
413 }
414 c.addMember(new RelationMember(role, res));
415 c.removeMembersFor(way);
416 insert = false;
417 }
418 } else {
419 insert = false;
420 }
421 } else if (!"via".equals(role)) {
422 warnme = true;
423 }
424 } else if (!("route".equals(type))
425 && !("multipolygon".equals(type))) {
426 warnme = true;
427 }
428 if (c == null) {
429 c = getNew(r);
430 }
431
432 if (insert) {
433 if (rm.hasRole() && !nowarnroles.contains(rm.getRole())) {
434 warnmerole = true;
435 }
436
437 Boolean backwards = null;
438 int k = 1;
439 while (i_r - k >= 0 || i_r + k < relationMembers.size()) {
440 if ((i_r - k >= 0)
441 && relationMembers.get(i_r - k).isWay()) {
442 Way w = relationMembers.get(i_r - k).getWay();
443 if ((w.lastNode() == way.firstNode())
444 || w.firstNode() == way.firstNode()) {
445 backwards = false;
446 } else if ((w.firstNode() == way.lastNode())
447 || w.lastNode() == way.lastNode()) {
448 backwards = true;
449 }
450 break;
451 }
452 if ((i_r + k < relationMembers.size())
453 && relationMembers.get(i_r + k).isWay()) {
454 Way w = relationMembers.get(i_r + k).getWay();
455 if ((w.lastNode() == way.firstNode())
456 || w.firstNode() == way.firstNode()) {
457 backwards = true;
458 } else if ((w.firstNode() == way.lastNode())
459 || w.lastNode() == way.lastNode()) {
460 backwards = false;
461 }
462 break;
463 }
464 k++;
465 }
466
467 int j = i_c;
468 for (Way wayToAdd : newWays) {
469 RelationMember em = new RelationMember(
470 rm.getRole(), wayToAdd);
471 j++;
472 if ((backwards != null) && backwards) {
473 c.addMember(i_c, em);
474 } else {
475 c.addMember(j, em);
476 }
477 }
478 i_c = j;
479 }
480 }
481 i_c++;
482 i_r++;
483 }
484
485 if (c != null) {
486 //commandList.add(new ChangeCommand(layer, r, c));
487 newRelations.put(r, c);
488 }
489 }
490 if (warnmerole) {
491 JOptionPane
492 .showMessageDialog(
493 Main.parent,
494 tr("<html>A role based relation membership was copied to all new ways.<br>You should verify this and correct it when necessary.</html>"),
495 tr("Warning"), JOptionPane.WARNING_MESSAGE);
496 } else if (warnme) {
497 JOptionPane
498 .showMessageDialog(
499 Main.parent,
500 tr("<html>A relation membership was copied to all new ways.<br>You should verify this and correct it when necessary.</html>"),
501 tr("Warning"), JOptionPane.WARNING_MESSAGE);
502 }
503
504 return new SplitWayResult(new SequenceCommand("Split way", commandList), null, changedWay, newWays);
505 }
506
507 /**
508 * @param ways
509 * @return null if ways cannot be combined. Otherwise returns the combined
510 * ways and the commands to combine
511 * @throws UserCancelException
512 */
513 private Pair<Way, List<Command>> combineWaysWorker(Collection<Way> ways) throws UserCancelException {
514
515 // prepare and clean the list of ways to combine
516 if (ways == null || ways.isEmpty())
517 return null;
518 ways.remove(null); // just in case - remove all null ways from the collection
519
520 // remove duplicates, preserving order
521 ways = new LinkedHashSet<Way>(ways);
522
523 // try to build a new way which includes all the combined ways
524 NodeGraph graph = NodeGraph.createUndirectedGraphFromNodeWays(ways);
525 List<Node> path = graph.buildSpanningPath();
526
527 // check whether any ways have been reversed in the process
528 // and build the collection of tags used by the ways to combine
529 TagCollection wayTags = TagCollection.unionOfAllPrimitives(ways);
530
531 List<Way> reversedWays = new LinkedList<Way>();
532 List<Way> unreversedWays = new LinkedList<Way>();
533 for (Way w: ways) {
534 if ((path.indexOf(w.getNode(0)) + 1) == path.lastIndexOf(w.getNode(1))) {
535 unreversedWays.add(w);
536 } else {
537 reversedWays.add(w);
538 }
539 }
540 // reverse path if all ways have been reversed
541 if (unreversedWays.isEmpty()) {
542 Collections.reverse(path);
543 unreversedWays = reversedWays;
544 reversedWays = null;
545 }
546 if ((reversedWays != null) && !reversedWays.isEmpty()) {
547 // filter out ways that have no direction-dependent tags
548 unreversedWays = ReverseWayTagCorrector.irreversibleWays(unreversedWays);
549 reversedWays = ReverseWayTagCorrector.irreversibleWays(reversedWays);
550 // reverse path if there are more reversed than unreversed ways with direction-dependent tags
551 if (reversedWays.size() > unreversedWays.size()) {
552 Collections.reverse(path);
553 List<Way> tempWays = unreversedWays;
554 unreversedWays = reversedWays;
555 reversedWays = tempWays;
556 }
557 // if there are still reversed ways with direction-dependent tags, reverse their tags
558 if (!reversedWays.isEmpty()) {
559 List<Way> unreversedTagWays = new ArrayList<Way>(ways);
560 unreversedTagWays.removeAll(reversedWays);
561 ReverseWayTagCorrector reverseWayTagCorrector = new ReverseWayTagCorrector();
562 List<Way> reversedTagWays = new ArrayList<Way>();
563 Collection<Command> changePropertyCommands = null;
564 for (Way w : reversedWays) {
565 Way wnew = new Way(w);
566 reversedTagWays.add(wnew);
567 changePropertyCommands = reverseWayTagCorrector.execute(w, wnew);
568 }
569 if ((changePropertyCommands != null) && !changePropertyCommands.isEmpty()) {
570 for (Command c : changePropertyCommands) {
571 c.executeCommand();
572 }
573 }
574 wayTags = TagCollection.unionOfAllPrimitives(reversedTagWays);
575 wayTags.add(TagCollection.unionOfAllPrimitives(unreversedTagWays));
576 }
577 }
578
579 // create the new way and apply the new node list
580 Way targetWay = getTargetWay(ways);
581 Way modifiedTargetWay = new Way(targetWay);
582 modifiedTargetWay.setNodes(path);
583
584 TagCollection completeWayTags = new TagCollection(wayTags);
585 combineTigerTags(completeWayTags);
586 normalizeTagCollectionBeforeEditing(completeWayTags, ways);
587 TagCollection tagsToEdit = new TagCollection(completeWayTags);
588 completeTagCollectionForEditing(tagsToEdit);
589
590 MyCombinePrimitiveResolverDialog dialog = MyCombinePrimitiveResolverDialog.getInstance();
591 dialog.getTagConflictResolverModel().populate(tagsToEdit, completeWayTags.getKeysWithMultipleValues());
592 dialog.setTargetPrimitive(targetWay);
593 Set<Relation> parentRelations = getParentRelations(ways);
594 dialog.getRelationMemberConflictResolverModel().populate(parentRelations, ways, oldWays);
595 dialog.prepareDefaultDecisions();
596
597 // resolve tag conflicts if necessary
598 if (askForMergeTag(ways) || duplicateParentRelations(ways)) {
599 dialog.setVisible(true);
600 if (dialog.isCancelled())
601 throw new UserCancelException();
602 }
603
604 LinkedList<Command> cmds = new LinkedList<Command>();
605 deletes.addAll(ways);
606 deletes.remove(targetWay);
607
608 cmds.add(new ChangeCommand(targetWay, modifiedTargetWay));
609 cmds.addAll(dialog.buildWayResolutionCommands());
610 dialog.buildRelationCorrespondance(newRelations, oldWays);
611
612 return new Pair<Way, List<Command>>(targetWay, cmds);
613 }
614
615 private static Way getTargetWay(Collection<Way> combinedWays) {
616 // init with an arbitrary way
617 Way targetWay = combinedWays.iterator().next();
618
619 // look for the first way already existing on
620 // the server
621 for (Way w : combinedWays) {
622 targetWay = w;
623 if (!w.isNew()) {
624 break;
625 }
626 }
627 return targetWay;
628 }
629
630 /**
631 * @return has tag to be merged (=> ask)
632 */
633 private static boolean askForMergeTag(Collection<Way> ways) {
634 for (Way way: ways) {
635 for (Way oposite: ways) {
636 for (String key: way.getKeys().keySet()) {
637 if (!"source".equals(key) && oposite.hasKey(key)
638 && !way.get(key).equals(oposite.get(key))) {
639 return true;
640 }
641 }
642 }
643 }
644 return false;
645 }
646
647 /**
648 * @return has duplicate parent relation
649 */
650 private boolean duplicateParentRelations(Collection<Way> ways) {
651 Set<Relation> relations = new HashSet<Relation>();
652 for (Way w: ways) {
653 List<Relation> rs = getParentRelations(w);
654 for (Relation r: rs) {
655 if (relations.contains(r)) {
656 return true;
657 }
658 }
659 relations.addAll(rs);
660 }
661 return false;
662 }
663
664 /**
665 * Replies the set of referring relations
666 *
667 * @return the set of referring relations
668 */
669 private List<Relation> getParentRelations(Way way) {
670 List<Relation> rels = new ArrayList<Relation>();
671 for (Relation r: relations.get(way)) {
672 if (newRelations.containsKey(r)) {
673 rels.add(newRelations.get(r));
674 }
675 else {
676 rels.add(r);
677 }
678 }
679 return rels;
680 }
681
682 private Relation getNew(Relation r) {
683 return getNew(r, newRelations);
684 }
685
686 public static Relation getNew(Relation r, Map<Relation, Relation> newRelations) {
687 if (newRelations.containsValue(r)) {
688 return r;
689 }
690 else {
691 Relation c = new Relation(r);
692 newRelations.put(r, c);
693 return c;
694 }
695 }
696
697 private Way getOld(Way r) {
698 return getOld(r, oldWays);
699 }
700
701 public static Way getOld(Way w, Map<Way, Way> oldWays) {
702 if (oldWays.containsKey(w)) {
703 return oldWays.get(w);
704 }
705 else {
706 return w;
707 }
708 }
709
710 /**
711 * Replies the set of referring relations
712 *
713 * @return the set of referring relations
714 */
715 private Set<Relation> getParentRelations(Collection<Way> ways) {
716 HashSet<Relation> ret = new HashSet<Relation>();
717 for (Way w: ways) {
718 ret.addAll(getParentRelations(w));
719 }
720 return ret;
721 }
722
723 /** Enable this action only if something is selected */
724 @Override
725 protected void updateEnabledState() {
726 if (getCurrentDataSet() == null) {
727 setEnabled(false);
728 } else {
729 updateEnabledState(getCurrentDataSet().getSelected());
730 }
731 }
732
733 /** Enable this action only if something is selected */
734 @Override
735 protected void updateEnabledState(
736 Collection<? extends OsmPrimitive> selection) {
737 if (selection == null) {
738 setEnabled(false);
739 return;
740 }
741 for (OsmPrimitive primitive: selection) {
742 if (!(primitive instanceof Way) || primitive.isDeleted()) {
743 setEnabled(false);
744 return;
745 }
746 }
747 setEnabled(selection.size() >= 2);
748 }
749}
Note: See TracBrowser for help on using the repository browser.