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

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

fix #5395 - add "Add selection to relation" to popup menu of relation toggle dialog

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