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

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

fix #6707 - Removing a empty polygon (removed shape first, then on validation error try to remove polygon)

  • Property svn:eol-style set to native
File size: 29.6 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            for (int i: displaylist.getSelectedIndices()) {
332                deleteRelation(model.getRelation(i));
333            }
334        }
335
336        public void valueChanged(ListSelectionEvent e) {
337            setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
338        }
339    }
340
341    /**
342     * The action for creating a new relation
343     *
344     */
345    static class NewAction extends AbstractAction implements LayerChangeListener{
346        public NewAction() {
347            putValue(SHORT_DESCRIPTION,tr("Create a new relation"));
348            //putValue(NAME, tr("New"));
349            putValue(SMALL_ICON, ImageProvider.get("dialogs", "addrelation"));
350            updateEnabledState();
351        }
352
353        public void run() {
354            RelationEditor.getEditor(Main.main.getEditLayer(),null, null).setVisible(true);
355        }
356
357        public void actionPerformed(ActionEvent e) {
358            run();
359        }
360
361        protected void updateEnabledState() {
362            setEnabled(Main.main != null && Main.main.getEditLayer() != null);
363        }
364
365        public void activeLayerChange(Layer oldLayer, Layer newLayer) {
366            updateEnabledState();
367        }
368
369        public void layerAdded(Layer newLayer) {
370            updateEnabledState();
371        }
372
373        public void layerRemoved(Layer oldLayer) {
374            updateEnabledState();
375        }
376    }
377
378    /**
379     * Creates a new relation with a copy of the current editor state
380     *
381     */
382    class DuplicateAction extends AbstractAction implements ListSelectionListener {
383        public DuplicateAction() {
384            putValue(SHORT_DESCRIPTION, tr("Create a copy of this relation and open it in another editor window"));
385            putValue(SMALL_ICON, ImageProvider.get("duplicate"));
386            //putValue(NAME, tr("Duplicate"));
387            updateEnabledState();
388        }
389
390        public void launchEditorForDuplicate(Relation original) {
391            Relation copy = new Relation(original, true);
392            copy.setModified(true);
393            RelationEditor editor = RelationEditor.getEditor(
394                    Main.main.getEditLayer(),
395                    copy,
396                    null /* no selected members */
397            );
398            editor.setVisible(true);
399        }
400
401        public void actionPerformed(ActionEvent e) {
402            if (!isEnabled())
403                return;
404            launchEditorForDuplicate(getSelected());
405        }
406
407        protected void updateEnabledState() {
408            setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length == 1);
409        }
410
411        public void valueChanged(ListSelectionEvent e) {
412            updateEnabledState();
413        }
414    }
415
416    /**
417     * Sets the current selection to the list of relations selected in this dialog
418     *
419     */
420    class SelectAction extends AbstractAction implements ListSelectionListener{
421        boolean add;
422        public SelectAction(boolean add) {
423            putValue(SHORT_DESCRIPTION, add ? tr("Add the selected relations to the current selection")
424                    : tr("Set the current selection to the list of selected relations"));
425            putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
426            putValue(NAME, add ? tr("Select relation (add)") : tr("Select relation"));
427            this.add = add;
428            updateEnabledState();
429        }
430
431        public void actionPerformed(ActionEvent e) {
432            if (!isEnabled()) return;
433            int [] idx = displaylist.getSelectedIndices();
434            if (idx == null || idx.length == 0) return;
435            ArrayList<OsmPrimitive> selection = new ArrayList<OsmPrimitive>(idx.length);
436            for (int i: idx) {
437                selection.add(model.getRelation(i));
438            }
439            if(add) {
440                Main.map.mapView.getEditLayer().data.addSelected(selection);
441            } else {
442                Main.map.mapView.getEditLayer().data.setSelected(selection);
443            }
444        }
445
446        protected void updateEnabledState() {
447            setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
448        }
449
450        public void valueChanged(ListSelectionEvent e) {
451            updateEnabledState();
452        }
453    }
454
455    /**
456     * Sets the current selection to the list of relations selected in this dialog
457     *
458     */
459    class SelectMembersAction extends AbstractAction implements ListSelectionListener{
460        boolean add;
461        public SelectMembersAction(boolean add) {
462            putValue(SHORT_DESCRIPTION,add ? tr("Add the members of all selected relations to current selection")
463                    : tr("Select the members of all selected relations"));
464            putValue(SMALL_ICON, ImageProvider.get("selectall"));
465            putValue(NAME, add ? tr("Select members (add)") : tr("Select members"));
466            this.add = add;
467            updateEnabledState();
468        }
469
470        public void actionPerformed(ActionEvent e) {
471            if (!isEnabled()) return;
472            List<Relation> relations = model.getSelectedRelations();
473            HashSet<OsmPrimitive> members = new HashSet<OsmPrimitive>();
474            for(Relation r: relations) {
475                members.addAll(r.getMemberPrimitives());
476            }
477            if(add) {
478                Main.map.mapView.getEditLayer().data.addSelected(members);
479            } else {
480                Main.map.mapView.getEditLayer().data.setSelected(members);
481            }
482        }
483
484        protected void updateEnabledState() {
485            setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
486        }
487
488        public void valueChanged(ListSelectionEvent e) {
489            updateEnabledState();
490        }
491    }
492
493    /**
494     * The action for downloading members of all selected relations
495     *
496     */
497    class DownloadMembersAction extends AbstractAction implements ListSelectionListener{
498
499        public DownloadMembersAction() {
500            putValue(SHORT_DESCRIPTION,tr("Download all members of the selected relations"));
501            putValue(NAME, tr("Download members"));
502            putValue(SMALL_ICON, ImageProvider.get("dialogs", "downloadincomplete"));
503            putValue("help", ht("/Dialog/RelationList#DownloadMembers"));
504            updateEnabledState();
505        }
506
507        protected void updateEnabledState() {
508            setEnabled(! model.getSelectedNonNewRelations().isEmpty());
509        }
510
511        public void valueChanged(ListSelectionEvent e) {
512            updateEnabledState();
513        }
514
515        public void actionPerformed(ActionEvent e) {
516            List<Relation> relations = model.getSelectedNonNewRelations();
517            if (relations.isEmpty())
518                return;
519            Main.worker.submit(new DownloadRelationTask(
520                    model.getSelectedNonNewRelations(),
521                    Main.map.mapView.getEditLayer())
522            );
523        }
524    }
525
526    /**
527     * Action for downloading incomplete members of selected relations
528     *
529     */
530    class DownloadSelectedIncompleteMembersAction extends AbstractAction implements ListSelectionListener{
531        public DownloadSelectedIncompleteMembersAction() {
532            putValue(SHORT_DESCRIPTION, tr("Download incomplete members of selected relations"));
533            putValue(SMALL_ICON, ImageProvider.get("dialogs/relation", "downloadincompleteselected"));
534            putValue(NAME, tr("Download incomplete members"));
535            updateEnabledState();
536        }
537
538        public Set<OsmPrimitive> buildSetOfIncompleteMembers(List<Relation> rels) {
539            Set<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
540            for(Relation r: rels) {
541                ret.addAll(r.getIncompleteMembers());
542            }
543            return ret;
544        }
545
546        public void actionPerformed(ActionEvent e) {
547            if (!isEnabled())
548                return;
549            List<Relation> rels = model.getSelectedRelationsWithIncompleteMembers();
550            if (rels.isEmpty()) return;
551            Main.worker.submit(new DownloadRelationMemberTask(
552                    rels,
553                    buildSetOfIncompleteMembers(rels),
554                    Main.map.mapView.getEditLayer()
555            ));
556        }
557
558        protected void updateEnabledState() {
559            setEnabled(!model.getSelectedRelationsWithIncompleteMembers().isEmpty());
560        }
561
562        public void valueChanged(ListSelectionEvent e) {
563            updateEnabledState();
564        }
565    }
566
567    /**
568     * The list model for the list of relations displayed in the relation list
569     * dialog.
570     *
571     */
572    private class RelationListModel extends AbstractListModel {
573        private final ArrayList<Relation> relations = new ArrayList<Relation>();
574        private DefaultListSelectionModel selectionModel;
575
576        public RelationListModel(DefaultListSelectionModel selectionModel) {
577            this.selectionModel = selectionModel;
578        }
579
580        public Relation getRelation(int idx) {
581            return relations.get(idx);
582        }
583
584        public void sort() {
585            Collections.sort(
586                    relations,
587                    DefaultNameFormatter.getInstance().getRelationComparator()
588            );
589        }
590
591        private boolean isValid(Relation r) {
592            return !r.isDeleted() && r.isVisible() && !r.isIncomplete();
593        }
594
595        public void setRelations(Collection<Relation> relations) {
596            List<Relation> sel =  getSelectedRelations();
597            this.relations.clear();
598            if (relations == null) {
599                selectionModel.clearSelection();
600                fireContentsChanged(this,0,getSize());
601                return;
602
603            }
604            for (Relation r: relations) {
605                if (isValid(r)) {
606                    this.relations.add(r);
607                }
608            }
609            sort();
610            fireIntervalAdded(this, 0, getSize());
611            setSelectedRelations(sel);
612        }
613
614        /**
615         * Add all relations in <code>addedPrimitives</code> to the model for the
616         * relation list dialog
617         *
618         * @param addedPrimitives the collection of added primitives. May include nodes,
619         * ways, and relations.
620         */
621        public void addRelations(Collection<? extends OsmPrimitive> addedPrimitives) {
622            boolean added = false;
623            for (OsmPrimitive p: addedPrimitives) {
624                if (! (p instanceof Relation)) {
625                    continue;
626                }
627
628                Relation r = (Relation)p;
629                if (relations.contains(r)) {
630                    continue;
631                }
632                if (isValid(r)) {
633                    relations.add(r);
634                    added = true;
635                }
636            }
637            if (added) {
638                List<Relation> sel = getSelectedRelations();
639                sort();
640                fireIntervalAdded(this, 0, getSize());
641                setSelectedRelations(sel);
642            }
643        }
644
645        /**
646         * Removes all relations in <code>removedPrimitives</code> from the model
647         *
648         * @param removedPrimitives the removed primitives. May include nodes, ways,
649         *   and relations
650         */
651        public void removeRelations(Collection<? extends OsmPrimitive> removedPrimitives) {
652            if (removedPrimitives == null) return;
653            // extract the removed relations
654            //
655            Set<Relation> removedRelations = new HashSet<Relation>();
656            for (OsmPrimitive p: removedPrimitives) {
657                if (! (p instanceof Relation)) {
658                    continue;
659                }
660                removedRelations.add((Relation)p);
661            }
662            if (removedRelations.isEmpty())
663                return;
664            int size = relations.size();
665            relations.removeAll(removedRelations);
666            if (size != relations.size()) {
667                List<Relation> sel = getSelectedRelations();
668                sort();
669                fireContentsChanged(this, 0, getSize());
670                setSelectedRelations(sel);
671            }
672        }
673
674        /**
675         * Replies the list of selected relations with incomplete members
676         *
677         * @return the list of selected relations with incomplete members
678         */
679        public List<Relation> getSelectedRelationsWithIncompleteMembers() {
680            List<Relation> ret = getSelectedNonNewRelations();
681            Iterator<Relation> it = ret.iterator();
682            while(it.hasNext()) {
683                Relation r = it.next();
684                if (!r.hasIncompleteMembers()) {
685                    it.remove();
686                }
687            }
688            return ret;
689        }
690
691        public Object getElementAt(int index) {
692            return relations.get(index);
693        }
694
695        public int getSize() {
696            return relations.size();
697        }
698
699        /**
700         * Replies the list of selected, non-new relations. Empty list,
701         * if there are no selected, non-new relations.
702         *
703         * @return the list of selected, non-new relations.
704         */
705        public List<Relation> getSelectedNonNewRelations() {
706            ArrayList<Relation> ret = new ArrayList<Relation>();
707            for (int i=0; i<getSize();i++) {
708                if (!selectionModel.isSelectedIndex(i)) {
709                    continue;
710                }
711                if (relations.get(i).isNew()) {
712                    continue;
713                }
714                ret.add(relations.get(i));
715            }
716            return ret;
717        }
718
719        /**
720         * Replies the list of selected relations. Empty list,
721         * if there are no selected relations.
722         *
723         * @return the list of selected, non-new relations.
724         */
725        public List<Relation> getSelectedRelations() {
726            ArrayList<Relation> ret = new ArrayList<Relation>();
727            for (int i=0; i<getSize();i++) {
728                if (!selectionModel.isSelectedIndex(i)) {
729                    continue;
730                }
731                ret.add(relations.get(i));
732            }
733            return ret;
734        }
735
736        /**
737         * Sets the selected relations.
738         *
739         * @return sel the list of selected relations
740         */
741        public void setSelectedRelations(List<Relation> sel) {
742            selectionModel.clearSelection();
743            if (sel == null || sel.isEmpty())
744                return;
745            for (Relation r: sel) {
746                int i = relations.indexOf(r);
747                if (i<0) {
748                    continue;
749                }
750                selectionModel.addSelectionInterval(i,i);
751            }
752        }
753
754        /**
755         * Returns the index of the relation
756         *
757         * @return index of relation (null if it cannot be found)
758         */
759        public Integer getRelationIndex(Relation rel) {
760            int i = relations.indexOf(rel);
761            if (i<0)
762                return null;
763            return i;
764        }
765
766        public void updateTitle() {
767            if (getSize() > 0) {
768                RelationListDialog.this.setTitle(tr("Relations: {0}", getSize()));
769            } else {
770                RelationListDialog.this.setTitle(tr("Relations"));
771            }
772        }
773    }
774
775    class RelationDialogPopupMenu extends ListPopupMenu {
776
777        public RelationDialogPopupMenu(JList list) {
778            super(list);
779           
780            // -- download members action
781            //
782            add(new DownloadMembersAction());
783
784            // -- download incomplete members action
785            //
786            add(new DownloadSelectedIncompleteMembersAction());
787
788            addSeparator();
789
790            // -- select members action
791            //
792            add(new SelectMembersAction(false));
793            add(new SelectMembersAction(true));
794
795            // -- select action
796            //
797            add(new SelectAction(false));
798            add(new SelectAction(true));
799        }
800    }
801
802    public void addPopupMenuSeparator() {
803        popupMenu.addSeparator();
804    }
805
806    public JMenuItem addPopupMenuAction(Action a) {
807        return popupMenu.add(a);
808    }
809
810    /* ---------------------------------------------------------------------------------- */
811    /* DataSetListener                                                                    */
812    /* ---------------------------------------------------------------------------------- */
813
814    public void nodeMoved(NodeMovedEvent event) {/* irrelevant in this context */}
815
816    public void wayNodesChanged(WayNodesChangedEvent event) {/* irrelevant in this context */}
817
818    public void primitivesAdded(final PrimitivesAddedEvent event) {
819        model.addRelations(event.getPrimitives());
820        model.updateTitle();
821    }
822
823    public void primitivesRemoved(final PrimitivesRemovedEvent event) {
824        model.removeRelations(event.getPrimitives());
825        model.updateTitle();
826    }
827
828    public void relationMembersChanged(final RelationMembersChangedEvent event) {
829        List<Relation> sel = model.getSelectedRelations();
830        model.sort();
831        model.setSelectedRelations(sel);
832        displaylist.repaint();
833    }
834
835    public void tagsChanged(TagsChangedEvent event) {
836        OsmPrimitive prim = event.getPrimitive();
837        if (prim == null || ! (prim instanceof Relation))
838            return;
839        // trigger a sort of the relation list because the display name may
840        // have changed
841        //
842        List<Relation> sel = model.getSelectedRelations();
843        model.sort();
844        model.setSelectedRelations(sel);
845        displaylist.repaint();
846    }
847
848    public void dataChanged(DataChangedEvent event) {
849        initFromLayer(Main.main.getEditLayer());
850    }
851
852    public void otherDatasetChange(AbstractDatasetChangedEvent event) {/* ignore */}
853}
Note: See TracBrowser for help on using the repository browser.