001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs.relation;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.BorderLayout;
007import java.awt.FlowLayout;
008import java.awt.event.ActionEvent;
009import java.awt.event.MouseAdapter;
010import java.awt.event.MouseEvent;
011
012import javax.swing.AbstractAction;
013import javax.swing.JCheckBox;
014import javax.swing.JList;
015import javax.swing.JPanel;
016import javax.swing.JScrollPane;
017import javax.swing.ListSelectionModel;
018import javax.swing.event.ListDataEvent;
019import javax.swing.event.ListDataListener;
020import javax.swing.event.ListSelectionEvent;
021import javax.swing.event.ListSelectionListener;
022
023import org.openstreetmap.josm.Main;
024import org.openstreetmap.josm.data.osm.Relation;
025import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
026import org.openstreetmap.josm.gui.SideButton;
027import org.openstreetmap.josm.gui.layer.OsmDataLayer;
028import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
029import org.openstreetmap.josm.tools.ImageProvider;
030
031/**
032 * This is browser for a list of relations which refer to another relations.
033 * @since 1806
034 */
035public class ReferringRelationsBrowser extends JPanel {
036
037    /** the list of relations */
038    private JList<Relation> referrers;
039    private final ReferringRelationsBrowserModel model;
040    private final transient OsmDataLayer layer;
041    private final JCheckBox cbReadFull = new JCheckBox(tr("including immediate children of parent relations"));
042    private EditAction editAction;
043
044    /**
045     * Constructs a new {@code ReferringRelationsBrowser}.
046     * @param layer OSM data layer
047     * @param model referrinf relations browser model
048     */
049    public ReferringRelationsBrowser(OsmDataLayer layer, ReferringRelationsBrowserModel model) {
050        this.model = model;
051        this.layer = layer;
052        build();
053    }
054
055    /**
056     * build the GUI
057     */
058    protected void build() {
059        setLayout(new BorderLayout());
060        referrers = new JList<>(model);
061        referrers.setCellRenderer(new OsmPrimitivRenderer());
062        add(new JScrollPane(referrers), BorderLayout.CENTER);
063        referrers.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
064        referrers.addMouseListener(new DblClickMouseAdapter());
065
066        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
067
068        ReloadAction reloadAction = new ReloadAction();
069        referrers.getModel().addListDataListener(reloadAction);
070        pnl.add(new SideButton(reloadAction));
071        pnl.add(cbReadFull);
072
073        editAction = new EditAction();
074        referrers.getSelectionModel().addListSelectionListener(editAction);
075        pnl.add(new SideButton(editAction));
076        add(pnl, BorderLayout.SOUTH);
077    }
078
079    public void init() {
080        model.populate(getLayer().data);
081    }
082
083    protected OsmDataLayer getLayer() {
084        return layer;
085    }
086
087    /**
088     * Action for loading the parent relations of a relation
089     *
090     */
091    class ReloadAction extends AbstractAction implements ListDataListener {
092        ReloadAction() {
093            putValue(SHORT_DESCRIPTION, tr("Load parent relations"));
094            putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
095            putValue(NAME, tr("Reload"));
096            refreshEnabled();
097        }
098
099        protected void refreshEnabled() {
100            setEnabled(model.canReload());
101        }
102
103        @Override
104        public void actionPerformed(ActionEvent e) {
105            boolean full = cbReadFull.isSelected();
106            final ParentRelationLoadingTask task = new ParentRelationLoadingTask(
107                    model.getRelation(),
108                    getLayer(),
109                    full,
110                    new PleaseWaitProgressMonitor(tr("Loading parent relations"))
111            );
112            task.setContinuation(
113                    new Runnable() {
114                        @Override
115                        public void run() {
116                            if (task.isCanceled() || task.hasError())
117                                return;
118                            model.populate(task.getParents());
119                        }
120                    }
121            );
122            Main.worker.submit(task);
123        }
124
125        @Override
126        public void contentsChanged(ListDataEvent e) {
127            refreshEnabled();
128        }
129
130        @Override
131        public void intervalAdded(ListDataEvent e) {
132            refreshEnabled();
133        }
134
135        @Override
136        public void intervalRemoved(ListDataEvent e) {
137            refreshEnabled();
138        }
139    }
140
141    /**
142     * Action for editing the currently selected relation
143     *
144     */
145    class EditAction extends AbstractAction implements ListSelectionListener {
146        EditAction() {
147            putValue(SHORT_DESCRIPTION, tr("Edit the currently selected relation"));
148            putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));
149            putValue(NAME, tr("Edit"));
150            refreshEnabled();
151        }
152
153        protected void refreshEnabled() {
154            setEnabled(referrers.getSelectionModel().getMinSelectionIndex() >= 0);
155        }
156
157        @Override
158        public void actionPerformed(ActionEvent e) {
159            run();
160        }
161
162        public void run() {
163            int idx = referrers.getSelectedIndex();
164            if (idx < 0)
165                return;
166            Relation r = model.getElementAt(idx);
167            if (r == null)
168                return;
169            RelationEditor editor = RelationEditor.getEditor(getLayer(), r, null);
170            editor.setVisible(true);
171        }
172
173        @Override
174        public void valueChanged(ListSelectionEvent e) {
175            refreshEnabled();
176        }
177    }
178
179    class DblClickMouseAdapter extends MouseAdapter {
180        @Override
181        public void mouseClicked(MouseEvent e) {
182            if (e.getClickCount() == 2)  {
183                editAction.run();
184            }
185        }
186    }
187}