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

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

Improved plugin interaction with selection and popups of Relation, Selection and Properties dialogs.

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