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

Last change on this file since 4353 was 4353, checked in by stoecker, 8 years ago

see #6731 - introduce better layout function for ToggleDialogs, changed author and relation dialog

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