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.JButton;
014import javax.swing.JCheckBox;
015import javax.swing.JList;
016import javax.swing.JPanel;
017import javax.swing.JScrollPane;
018import javax.swing.ListSelectionModel;
019import javax.swing.event.ListDataEvent;
020import javax.swing.event.ListDataListener;
021import javax.swing.event.ListSelectionEvent;
022import javax.swing.event.ListSelectionListener;
023
024import org.openstreetmap.josm.Main;
025import org.openstreetmap.josm.data.osm.Relation;
026import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
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 JButton(reloadAction));
071        pnl.add(cbReadFull);
072
073        editAction = new EditAction();
074        referrers.getSelectionModel().addListSelectionListener(editAction);
075        pnl.add(new JButton(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            new ImageProvider("dialogs", "refresh").getResource().attachImageIcon(this);
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                    if (task.isCanceled() || task.hasError())
114                        return;
115                    model.populate(task.getParents());
116                });
117            Main.worker.submit(task);
118        }
119
120        @Override
121        public void contentsChanged(ListDataEvent e) {
122            refreshEnabled();
123        }
124
125        @Override
126        public void intervalAdded(ListDataEvent e) {
127            refreshEnabled();
128        }
129
130        @Override
131        public void intervalRemoved(ListDataEvent e) {
132            refreshEnabled();
133        }
134    }
135
136    /**
137     * Action for editing the currently selected relation
138     *
139     */
140    class EditAction extends AbstractAction implements ListSelectionListener {
141        EditAction() {
142            putValue(SHORT_DESCRIPTION, tr("Edit the currently selected relation"));
143            new ImageProvider("dialogs", "edit").getResource().attachImageIcon(this);
144            putValue(NAME, tr("Edit"));
145            refreshEnabled();
146        }
147
148        protected void refreshEnabled() {
149            setEnabled(referrers.getSelectionModel().getMinSelectionIndex() >= 0);
150        }
151
152        @Override
153        public void actionPerformed(ActionEvent e) {
154            run();
155        }
156
157        public void run() {
158            int idx = referrers.getSelectedIndex();
159            if (idx < 0)
160                return;
161            Relation r = model.getElementAt(idx);
162            if (r == null)
163                return;
164            RelationEditor editor = RelationEditor.getEditor(getLayer(), r, null);
165            editor.setVisible(true);
166        }
167
168        @Override
169        public void valueChanged(ListSelectionEvent e) {
170            refreshEnabled();
171        }
172    }
173
174    class DblClickMouseAdapter extends MouseAdapter {
175        @Override
176        public void mouseClicked(MouseEvent e) {
177            if (e.getClickCount() == 2) {
178                editAction.run();
179            }
180        }
181    }
182}