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