source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java@ 4932

Last change on this file since 4932 was 4885, checked in by simon04, 12 years ago

#fix #7344 - Deleting multiple relations ends in failure

  • Property svn:eol-style set to native
File size: 30.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Point;
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.awt.event.MouseAdapter;
11import java.awt.event.MouseEvent;
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.Collections;
16import java.util.HashSet;
17import java.util.Iterator;
18import java.util.LinkedList;
19import java.util.List;
20import java.util.Set;
21
22import javax.swing.AbstractAction;
23import javax.swing.AbstractListModel;
24import javax.swing.Action;
25import javax.swing.DefaultListSelectionModel;
26import javax.swing.JList;
27import javax.swing.JMenuItem;
28import javax.swing.KeyStroke;
29import javax.swing.ListSelectionModel;
30import javax.swing.SwingUtilities;
31import javax.swing.event.ListSelectionEvent;
32import javax.swing.event.ListSelectionListener;
33import javax.swing.event.PopupMenuListener;
34
35import org.openstreetmap.josm.Main;
36import org.openstreetmap.josm.data.osm.OsmPrimitive;
37import org.openstreetmap.josm.data.osm.Relation;
38import org.openstreetmap.josm.data.osm.RelationMember;
39import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
40import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
41import org.openstreetmap.josm.data.osm.event.DataSetListener;
42import org.openstreetmap.josm.data.osm.event.DatasetEventManager;
43import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
44import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
45import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
46import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
47import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
48import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
49import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
50import org.openstreetmap.josm.gui.DefaultNameFormatter;
51import org.openstreetmap.josm.gui.MapView;
52import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
53import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
54import org.openstreetmap.josm.gui.SideButton;
55import org.openstreetmap.josm.gui.dialogs.relation.DownloadRelationMemberTask;
56import org.openstreetmap.josm.gui.dialogs.relation.DownloadRelationTask;
57import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
58import org.openstreetmap.josm.gui.layer.Layer;
59import org.openstreetmap.josm.gui.layer.OsmDataLayer;
60import org.openstreetmap.josm.gui.widgets.ListPopupMenu;
61import org.openstreetmap.josm.tools.ImageProvider;
62import org.openstreetmap.josm.tools.Shortcut;
63
64/**
65 * A dialog showing all known relations, with buttons to add, edit, and
66 * delete them.
67 *
68 * We don't have such dialogs for nodes, segments, and ways, because those
69 * objects are visible on the map and can be selected there. Relations are not.
70 */
71public class RelationListDialog extends ToggleDialog implements DataSetListener {
72 /** The display list. */
73 private JList displaylist;
74 /** the list model used */
75 private RelationListModel model;
76
77 /** the edit action */
78 private EditAction editAction;
79 /** the delete action */
80 private DeleteAction deleteAction;
81 private NewAction newAction;
82 /** the popup menu */
83 private RelationDialogPopupMenu popupMenu;
84
85 /**
86 * constructor
87 */
88 public RelationListDialog() {
89 super(tr("Relations"), "relationlist", tr("Open a list of all relations."),
90 Shortcut.registerShortcut("subwindow:relations", tr("Toggle: {0}", tr("Relations")), KeyEvent.VK_R,
91 Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
92
93 // create the list of relations
94 //
95 DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
96 model = new RelationListModel(selectionModel);
97 displaylist = new JList(model);
98 displaylist.setSelectionModel(selectionModel);
99 displaylist.setCellRenderer(new OsmPrimitivRenderer() {
100 /**
101 * Don't show the default tooltip in the relation list.
102 */
103 @Override
104 protected String getComponentToolTipText(OsmPrimitive value) {
105 return null;
106 }
107 });
108 displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
109 displaylist.addMouseListener(new MouseEventHandler());
110
111 // the new action
112 //
113 newAction = new NewAction();
114
115 // the edit action
116 //
117 editAction = new EditAction();
118 displaylist.addListSelectionListener(editAction);
119
120 // the duplicate action
121 //
122 DuplicateAction duplicateAction = new DuplicateAction();
123 displaylist.addListSelectionListener(duplicateAction);
124
125 // the delete action
126 //
127 deleteAction = new DeleteAction();
128 displaylist.addListSelectionListener(deleteAction);
129
130 // the select action
131 //
132 SelectAction selectAction = new SelectAction(false);
133 displaylist.addListSelectionListener(selectAction);
134
135 createLayout(displaylist, true, Arrays.asList(new SideButton[] {
136 new SideButton(newAction, false),
137 new SideButton(editAction, false),
138 new SideButton(duplicateAction, false),
139 new SideButton(deleteAction, false),
140 new SideButton(selectAction, false)
141 }));
142
143 // activate DEL in the list of relations
144 displaylist.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0), "deleteRelation");
145 displaylist.getActionMap().put("deleteRelation", deleteAction);
146
147 popupMenu = new RelationDialogPopupMenu(displaylist);
148 }
149
150 @Override public void showNotify() {
151 MapView.addLayerChangeListener(newAction);
152 newAction.updateEnabledState();
153 DatasetEventManager.getInstance().addDatasetListener(this, FireMode.IN_EDT);
154 dataChanged(null);
155 }
156
157 @Override public void hideNotify() {
158 MapView.removeLayerChangeListener(newAction);
159 DatasetEventManager.getInstance().removeDatasetListener(this);
160 }
161
162 /**
163 * Initializes the relation list dialog from a layer. If <code>layer</code> is null
164 * or if it isn't an {@see OsmDataLayer} the dialog is reset to an empty dialog.
165 * Otherwise it is initialized with the list of non-deleted and visible relations
166 * in the layer's dataset.
167 *
168 * @param layer the layer. May be null.
169 */
170 protected void initFromLayer(Layer layer) {
171 if (layer == null || ! (layer instanceof OsmDataLayer)) {
172 model.setRelations(null);
173 return;
174 }
175 OsmDataLayer l = (OsmDataLayer)layer;
176 model.setRelations(l.data.getRelations());
177 model.updateTitle();
178 }
179
180 /**
181 * Adds a selection listener to the relation list.
182 *
183 * @param listener the listener to add
184 */
185 public void addListSelectionListener(ListSelectionListener listener) {
186 displaylist.addListSelectionListener(listener);
187 }
188
189 /**
190 * Removes a selection listener from the relation list.
191 *
192 * @param listener the listener to remove
193 */
194 public void removeListSelectionListener(ListSelectionListener listener) {
195 displaylist.removeListSelectionListener(listener);
196 }
197
198 /**
199 * @return The selected relation in the list
200 */
201 private Relation getSelected() {
202 if(model.getSize() == 1) {
203 displaylist.setSelectedIndex(0);
204 }
205 return (Relation) displaylist.getSelectedValue();
206 }
207
208 /**
209 * Selects the relation <code>relation</code> in the list of relations.
210 *
211 * @param relation the relation
212 */
213 public void selectRelation(Relation relation) {
214 selectRelations(Collections.singleton(relation));
215 }
216
217 /**
218 * Selects the relations in the list of relations.
219 * @param relations the relations to be selected
220 */
221 public void selectRelations(Collection<Relation> relations) {
222 if (relations == null || relations.isEmpty()) {
223 model.setSelectedRelations(null);
224 } else {
225 model.setSelectedRelations(relations);
226 Integer i = model.getRelationIndex(relations.iterator().next());
227 if (i != null) { // Not all relations have to be in the list (for example when the relation list is hidden, it's not updated with new relations)
228 displaylist.scrollRectToVisible(displaylist.getCellBounds(i, i));
229 }
230 }
231 }
232
233 class MouseEventHandler extends MouseAdapter {
234 protected void setCurrentRelationAsSelection() {
235 Main.main.getCurrentDataSet().setSelected((Relation)displaylist.getSelectedValue());
236 }
237
238 protected void editCurrentRelation() {
239 new EditAction().launchEditor(getSelected());
240 }
241
242 @Override public void mouseClicked(MouseEvent e) {
243 if (Main.main.getEditLayer() == null) return;
244 if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
245 if (e.isControlDown()) {
246 editCurrentRelation();
247 } else {
248 setCurrentRelationAsSelection();
249 }
250 }
251 }
252 private void openPopup(MouseEvent e) {
253 Point p = e.getPoint();
254 int index = displaylist.locationToIndex(p);
255 if (index < 0) return;
256 if (!displaylist.getCellBounds(index, index).contains(e.getPoint()))
257 return;
258 if (! displaylist.isSelectedIndex(index)) {
259 displaylist.setSelectedIndex(index);
260 }
261 popupMenu.show(displaylist, p.x, p.y-3);
262 }
263 @Override public void mousePressed(MouseEvent e) {
264 if (Main.main.getEditLayer() == null) return;
265 if (e.isPopupTrigger()) {
266 openPopup(e);
267 }
268 }
269 @Override public void mouseReleased(MouseEvent e) {
270 if (Main.main.getEditLayer() == null) return;
271 if (e.isPopupTrigger()) {
272 openPopup(e);
273 }
274 }
275 }
276
277 /**
278 * The edit action
279 *
280 */
281 class EditAction extends AbstractAction implements ListSelectionListener{
282 public EditAction() {
283 putValue(SHORT_DESCRIPTION,tr( "Open an editor for the selected relation"));
284 //putValue(NAME, tr("Edit"));
285 putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));
286 setEnabled(false);
287 }
288 protected Collection<RelationMember> getMembersForCurrentSelection(Relation r) {
289 Collection<RelationMember> members = new HashSet<RelationMember>();
290 Collection<OsmPrimitive> selection = Main.map.mapView.getEditLayer().data.getSelected();
291 for (RelationMember member: r.getMembers()) {
292 if (selection.contains(member.getMember())) {
293 members.add(member);
294 }
295 }
296 return members;
297 }
298
299 public void launchEditor(Relation toEdit) {
300 if (toEdit == null)
301 return;
302 RelationEditor.getEditor(Main.map.mapView.getEditLayer(),toEdit, getMembersForCurrentSelection(toEdit)).setVisible(true);
303 }
304
305 public void actionPerformed(ActionEvent e) {
306 if (!isEnabled())
307 return;
308 launchEditor(getSelected());
309 }
310
311 public void valueChanged(ListSelectionEvent e) {
312 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length == 1);
313 }
314 }
315
316 /**
317 * The delete action
318 *
319 */
320 class DeleteAction extends AbstractAction implements ListSelectionListener {
321 class AbortException extends Exception {}
322
323 public DeleteAction() {
324 putValue(SHORT_DESCRIPTION,tr("Delete the selected relation"));
325 //putValue(NAME, tr("Delete"));
326 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
327 setEnabled(false);
328 }
329
330 protected void deleteRelation(Relation toDelete) {
331 if (toDelete == null)
332 return;
333 org.openstreetmap.josm.actions.mapmode.DeleteAction.deleteRelation(
334 Main.main.getEditLayer(),
335 toDelete
336 );
337 }
338
339 public void actionPerformed(ActionEvent e) {
340 if (!isEnabled()) {
341 return;
342 }
343 List<Relation> toDelete = new LinkedList<Relation>();
344 for (int i : displaylist.getSelectedIndices()) {
345 toDelete.add(model.getRelation(i));
346 }
347 for (Relation r : toDelete) {
348 deleteRelation(r);
349 }
350 displaylist.clearSelection();
351 }
352
353 public void valueChanged(ListSelectionEvent e) {
354 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
355 }
356 }
357
358 /**
359 * The action for creating a new relation
360 *
361 */
362 static class NewAction extends AbstractAction implements LayerChangeListener{
363 public NewAction() {
364 putValue(SHORT_DESCRIPTION,tr("Create a new relation"));
365 //putValue(NAME, tr("New"));
366 putValue(SMALL_ICON, ImageProvider.get("dialogs", "addrelation"));
367 updateEnabledState();
368 }
369
370 public void run() {
371 RelationEditor.getEditor(Main.main.getEditLayer(),null, null).setVisible(true);
372 }
373
374 public void actionPerformed(ActionEvent e) {
375 run();
376 }
377
378 protected void updateEnabledState() {
379 setEnabled(Main.main != null && Main.main.getEditLayer() != null);
380 }
381
382 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
383 updateEnabledState();
384 }
385
386 public void layerAdded(Layer newLayer) {
387 updateEnabledState();
388 }
389
390 public void layerRemoved(Layer oldLayer) {
391 updateEnabledState();
392 }
393 }
394
395 /**
396 * Creates a new relation with a copy of the current editor state
397 *
398 */
399 class DuplicateAction extends AbstractAction implements ListSelectionListener {
400 public DuplicateAction() {
401 putValue(SHORT_DESCRIPTION, tr("Create a copy of this relation and open it in another editor window"));
402 putValue(SMALL_ICON, ImageProvider.get("duplicate"));
403 //putValue(NAME, tr("Duplicate"));
404 updateEnabledState();
405 }
406
407 public void launchEditorForDuplicate(Relation original) {
408 Relation copy = new Relation(original, true);
409 copy.setModified(true);
410 RelationEditor editor = RelationEditor.getEditor(
411 Main.main.getEditLayer(),
412 copy,
413 null /* no selected members */
414 );
415 editor.setVisible(true);
416 }
417
418 public void actionPerformed(ActionEvent e) {
419 if (!isEnabled())
420 return;
421 launchEditorForDuplicate(getSelected());
422 }
423
424 protected void updateEnabledState() {
425 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length == 1);
426 }
427
428 public void valueChanged(ListSelectionEvent e) {
429 updateEnabledState();
430 }
431 }
432
433 /**
434 * Sets the current selection to the list of relations selected in this dialog
435 *
436 */
437 class SelectAction extends AbstractAction implements ListSelectionListener{
438 boolean add;
439 public SelectAction(boolean add) {
440 putValue(SHORT_DESCRIPTION, add ? tr("Add the selected relations to the current selection")
441 : tr("Set the current selection to the list of selected relations"));
442 putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
443 putValue(NAME, add ? tr("Select relation (add)") : tr("Select relation"));
444 this.add = add;
445 updateEnabledState();
446 }
447
448 public void actionPerformed(ActionEvent e) {
449 if (!isEnabled()) return;
450 int [] idx = displaylist.getSelectedIndices();
451 if (idx == null || idx.length == 0) return;
452 ArrayList<OsmPrimitive> selection = new ArrayList<OsmPrimitive>(idx.length);
453 for (int i: idx) {
454 selection.add(model.getRelation(i));
455 }
456 if(add) {
457 Main.map.mapView.getEditLayer().data.addSelected(selection);
458 } else {
459 Main.map.mapView.getEditLayer().data.setSelected(selection);
460 }
461 }
462
463 protected void updateEnabledState() {
464 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
465 }
466
467 public void valueChanged(ListSelectionEvent e) {
468 updateEnabledState();
469 }
470 }
471
472 /**
473 * Sets the current selection to the list of relations selected in this dialog
474 *
475 */
476 class SelectMembersAction extends AbstractAction implements ListSelectionListener{
477 boolean add;
478 public SelectMembersAction(boolean add) {
479 putValue(SHORT_DESCRIPTION,add ? tr("Add the members of all selected relations to current selection")
480 : tr("Select the members of all selected relations"));
481 putValue(SMALL_ICON, ImageProvider.get("selectall"));
482 putValue(NAME, add ? tr("Select members (add)") : tr("Select members"));
483 this.add = add;
484 updateEnabledState();
485 }
486
487 public void actionPerformed(ActionEvent e) {
488 if (!isEnabled()) return;
489 List<Relation> relations = model.getSelectedRelations();
490 HashSet<OsmPrimitive> members = new HashSet<OsmPrimitive>();
491 for(Relation r: relations) {
492 members.addAll(r.getMemberPrimitives());
493 }
494 if(add) {
495 Main.map.mapView.getEditLayer().data.addSelected(members);
496 } else {
497 Main.map.mapView.getEditLayer().data.setSelected(members);
498 }
499 }
500
501 protected void updateEnabledState() {
502 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
503 }
504
505 public void valueChanged(ListSelectionEvent e) {
506 updateEnabledState();
507 }
508 }
509
510 /**
511 * The action for downloading members of all selected relations
512 *
513 */
514 class DownloadMembersAction extends AbstractAction implements ListSelectionListener{
515
516 public DownloadMembersAction() {
517 putValue(SHORT_DESCRIPTION,tr("Download all members of the selected relations"));
518 putValue(NAME, tr("Download members"));
519 putValue(SMALL_ICON, ImageProvider.get("dialogs", "downloadincomplete"));
520 putValue("help", ht("/Dialog/RelationList#DownloadMembers"));
521 updateEnabledState();
522 }
523
524 protected void updateEnabledState() {
525 setEnabled(! model.getSelectedNonNewRelations().isEmpty());
526 }
527
528 public void valueChanged(ListSelectionEvent e) {
529 updateEnabledState();
530 }
531
532 public void actionPerformed(ActionEvent e) {
533 List<Relation> relations = model.getSelectedNonNewRelations();
534 if (relations.isEmpty())
535 return;
536 Main.worker.submit(new DownloadRelationTask(
537 model.getSelectedNonNewRelations(),
538 Main.map.mapView.getEditLayer())
539 );
540 }
541 }
542
543 /**
544 * Action for downloading incomplete members of selected relations
545 *
546 */
547 class DownloadSelectedIncompleteMembersAction extends AbstractAction implements ListSelectionListener{
548 public DownloadSelectedIncompleteMembersAction() {
549 putValue(SHORT_DESCRIPTION, tr("Download incomplete members of selected relations"));
550 putValue(SMALL_ICON, ImageProvider.get("dialogs/relation", "downloadincompleteselected"));
551 putValue(NAME, tr("Download incomplete members"));
552 updateEnabledState();
553 }
554
555 public Set<OsmPrimitive> buildSetOfIncompleteMembers(List<Relation> rels) {
556 Set<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
557 for(Relation r: rels) {
558 ret.addAll(r.getIncompleteMembers());
559 }
560 return ret;
561 }
562
563 public void actionPerformed(ActionEvent e) {
564 if (!isEnabled())
565 return;
566 List<Relation> rels = model.getSelectedRelationsWithIncompleteMembers();
567 if (rels.isEmpty()) return;
568 Main.worker.submit(new DownloadRelationMemberTask(
569 rels,
570 buildSetOfIncompleteMembers(rels),
571 Main.map.mapView.getEditLayer()
572 ));
573 }
574
575 protected void updateEnabledState() {
576 setEnabled(!model.getSelectedRelationsWithIncompleteMembers().isEmpty());
577 }
578
579 public void valueChanged(ListSelectionEvent e) {
580 updateEnabledState();
581 }
582 }
583
584 /**
585 * The list model for the list of relations displayed in the relation list
586 * dialog.
587 *
588 */
589 private class RelationListModel extends AbstractListModel {
590 private final ArrayList<Relation> relations = new ArrayList<Relation>();
591 private DefaultListSelectionModel selectionModel;
592
593 public RelationListModel(DefaultListSelectionModel selectionModel) {
594 this.selectionModel = selectionModel;
595 }
596
597 public Relation getRelation(int idx) {
598 return relations.get(idx);
599 }
600
601 public void sort() {
602 Collections.sort(
603 relations,
604 DefaultNameFormatter.getInstance().getRelationComparator()
605 );
606 }
607
608 private boolean isValid(Relation r) {
609 return !r.isDeleted() && r.isVisible() && !r.isIncomplete();
610 }
611
612 public void setRelations(Collection<Relation> relations) {
613 List<Relation> sel = getSelectedRelations();
614 this.relations.clear();
615 if (relations == null) {
616 selectionModel.clearSelection();
617 fireContentsChanged(this,0,getSize());
618 return;
619
620 }
621 for (Relation r: relations) {
622 if (isValid(r)) {
623 this.relations.add(r);
624 }
625 }
626 sort();
627 fireIntervalAdded(this, 0, getSize());
628 setSelectedRelations(sel);
629 }
630
631 /**
632 * Add all relations in <code>addedPrimitives</code> to the model for the
633 * relation list dialog
634 *
635 * @param addedPrimitives the collection of added primitives. May include nodes,
636 * ways, and relations.
637 */
638 public void addRelations(Collection<? extends OsmPrimitive> addedPrimitives) {
639 boolean added = false;
640 for (OsmPrimitive p: addedPrimitives) {
641 if (! (p instanceof Relation)) {
642 continue;
643 }
644
645 Relation r = (Relation)p;
646 if (relations.contains(r)) {
647 continue;
648 }
649 if (isValid(r)) {
650 relations.add(r);
651 added = true;
652 }
653 }
654 if (added) {
655 List<Relation> sel = getSelectedRelations();
656 sort();
657 fireIntervalAdded(this, 0, getSize());
658 setSelectedRelations(sel);
659 }
660 }
661
662 /**
663 * Removes all relations in <code>removedPrimitives</code> from the model
664 *
665 * @param removedPrimitives the removed primitives. May include nodes, ways,
666 * and relations
667 */
668 public void removeRelations(Collection<? extends OsmPrimitive> removedPrimitives) {
669 if (removedPrimitives == null) return;
670 // extract the removed relations
671 //
672 Set<Relation> removedRelations = new HashSet<Relation>();
673 for (OsmPrimitive p: removedPrimitives) {
674 if (! (p instanceof Relation)) {
675 continue;
676 }
677 removedRelations.add((Relation)p);
678 }
679 if (removedRelations.isEmpty())
680 return;
681 int size = relations.size();
682 relations.removeAll(removedRelations);
683 if (size != relations.size()) {
684 List<Relation> sel = getSelectedRelations();
685 sort();
686 fireContentsChanged(this, 0, getSize());
687 setSelectedRelations(sel);
688 }
689 }
690
691 /**
692 * Replies the list of selected relations with incomplete members
693 *
694 * @return the list of selected relations with incomplete members
695 */
696 public List<Relation> getSelectedRelationsWithIncompleteMembers() {
697 List<Relation> ret = getSelectedNonNewRelations();
698 Iterator<Relation> it = ret.iterator();
699 while(it.hasNext()) {
700 Relation r = it.next();
701 if (!r.hasIncompleteMembers()) {
702 it.remove();
703 }
704 }
705 return ret;
706 }
707
708 public Object getElementAt(int index) {
709 return relations.get(index);
710 }
711
712 public int getSize() {
713 return relations.size();
714 }
715
716 /**
717 * Replies the list of selected, non-new relations. Empty list,
718 * if there are no selected, non-new relations.
719 *
720 * @return the list of selected, non-new relations.
721 */
722 public List<Relation> getSelectedNonNewRelations() {
723 ArrayList<Relation> ret = new ArrayList<Relation>();
724 for (int i=0; i<getSize();i++) {
725 if (!selectionModel.isSelectedIndex(i)) {
726 continue;
727 }
728 if (relations.get(i).isNew()) {
729 continue;
730 }
731 ret.add(relations.get(i));
732 }
733 return ret;
734 }
735
736 /**
737 * Replies the list of selected relations. Empty list,
738 * if there are no selected relations.
739 *
740 * @return the list of selected, non-new relations.
741 */
742 public List<Relation> getSelectedRelations() {
743 ArrayList<Relation> ret = new ArrayList<Relation>();
744 for (int i=0; i<getSize();i++) {
745 if (!selectionModel.isSelectedIndex(i)) {
746 continue;
747 }
748 ret.add(relations.get(i));
749 }
750 return ret;
751 }
752
753 /**
754 * Sets the selected relations.
755 *
756 * @return sel the list of selected relations
757 */
758 public void setSelectedRelations(Collection<Relation> sel) {
759 selectionModel.clearSelection();
760 if (sel == null || sel.isEmpty())
761 return;
762 for (Relation r: sel) {
763 int i = relations.indexOf(r);
764 if (i<0) {
765 continue;
766 }
767 selectionModel.addSelectionInterval(i,i);
768 }
769 }
770
771 /**
772 * Returns the index of the relation
773 *
774 * @return index of relation (null if it cannot be found)
775 */
776 public Integer getRelationIndex(Relation rel) {
777 int i = relations.indexOf(rel);
778 if (i<0)
779 return null;
780 return i;
781 }
782
783 public void updateTitle() {
784 if (getSize() > 0) {
785 RelationListDialog.this.setTitle(tr("Relations: {0}", getSize()));
786 } else {
787 RelationListDialog.this.setTitle(tr("Relations"));
788 }
789 }
790 }
791
792 class RelationDialogPopupMenu extends ListPopupMenu {
793
794 public RelationDialogPopupMenu(JList list) {
795 super(list);
796
797 // -- download members action
798 //
799 add(new DownloadMembersAction());
800
801 // -- download incomplete members action
802 //
803 add(new DownloadSelectedIncompleteMembersAction());
804
805 addSeparator();
806
807 // -- select members action
808 //
809 add(new SelectMembersAction(false));
810 add(new SelectMembersAction(true));
811
812 // -- select action
813 //
814 add(new SelectAction(false));
815 add(new SelectAction(true));
816 }
817 }
818
819 public void addPopupMenuSeparator() {
820 popupMenu.addSeparator();
821 }
822
823 public JMenuItem addPopupMenuAction(Action a) {
824 return popupMenu.add(a);
825 }
826
827 public void addPopupMenuListener(PopupMenuListener l) {
828 popupMenu.addPopupMenuListener(l);
829 }
830
831 public void removePopupMenuListener(PopupMenuListener l) {
832 popupMenu.addPopupMenuListener(l);
833 }
834
835 public Collection<Relation> getSelectedRelations() {
836 return model.getSelectedRelations();
837 }
838
839 /* ---------------------------------------------------------------------------------- */
840 /* DataSetListener */
841 /* ---------------------------------------------------------------------------------- */
842
843 public void nodeMoved(NodeMovedEvent event) {/* irrelevant in this context */}
844
845 public void wayNodesChanged(WayNodesChangedEvent event) {/* irrelevant in this context */}
846
847 public void primitivesAdded(final PrimitivesAddedEvent event) {
848 model.addRelations(event.getPrimitives());
849 model.updateTitle();
850 }
851
852 public void primitivesRemoved(final PrimitivesRemovedEvent event) {
853 model.removeRelations(event.getPrimitives());
854 model.updateTitle();
855 }
856
857 public void relationMembersChanged(final RelationMembersChangedEvent event) {
858 List<Relation> sel = model.getSelectedRelations();
859 model.sort();
860 model.setSelectedRelations(sel);
861 displaylist.repaint();
862 }
863
864 public void tagsChanged(TagsChangedEvent event) {
865 OsmPrimitive prim = event.getPrimitive();
866 if (prim == null || ! (prim instanceof Relation))
867 return;
868 // trigger a sort of the relation list because the display name may
869 // have changed
870 //
871 List<Relation> sel = model.getSelectedRelations();
872 model.sort();
873 model.setSelectedRelations(sel);
874 displaylist.repaint();
875 }
876
877 public void dataChanged(DataChangedEvent event) {
878 initFromLayer(Main.main.getEditLayer());
879 }
880
881 public void otherDatasetChange(AbstractDatasetChangedEvent event) {/* ignore */}
882}
Note: See TracBrowser for help on using the repository browser.