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

Last change on this file since 4459 was 4459, checked in by bastiK, 8 years ago

applied #6856 - Enable plugins to add actions in popup menus (patch by Don-vip)

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