001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.download;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.GridBagConstraints;
007import java.awt.GridBagLayout;
008import java.awt.Insets;
009import java.awt.event.ActionEvent;
010import java.awt.event.MouseAdapter;
011import java.awt.event.MouseEvent;
012import java.util.List;
013
014import javax.swing.AbstractAction;
015import javax.swing.DefaultListModel;
016import javax.swing.JButton;
017import javax.swing.JOptionPane;
018import javax.swing.JPanel;
019import javax.swing.JScrollPane;
020import javax.swing.SwingUtilities;
021import javax.swing.event.ListSelectionEvent;
022import javax.swing.event.ListSelectionListener;
023
024import org.openstreetmap.josm.Main;
025import org.openstreetmap.josm.data.Bounds;
026import org.openstreetmap.josm.gui.download.BookmarkList.Bookmark;
027import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
028import org.openstreetmap.josm.gui.widgets.JosmTextArea;
029import org.openstreetmap.josm.tools.ImageProvider;
030
031/**
032 * DownloadAreaSelector which manages a list of "bookmarks", i.e. a list of
033 * name download areas.
034 *
035 */
036public class BookmarkSelection implements DownloadSelection {
037
038    /** the currently selected download area. One can add bookmarks for this
039     * area, if not null
040     */
041    private Bounds currentArea;
042    /** the list of bookmarks */
043    private BookmarkList bookmarks;
044
045    /** the parent download GUI */
046    private DownloadDialog parent;
047
048    /** displays information about the current download area */
049    private JMultilineLabel lblCurrentDownloadArea;
050    private final JosmTextArea bboxDisplay = new JosmTextArea();
051    /** the add action */
052    private AddAction actAdd;
053
054    /**
055     * Creates the panel with the action buttons on the left
056     *
057     * @return the panel with the action buttons on the left
058     */
059    protected JPanel buildButtonPanel() {
060        JPanel pnl = new JPanel();
061        pnl.setLayout(new GridBagLayout());
062        GridBagConstraints gc = new GridBagConstraints();
063        gc.gridy = 0;
064        RemoveAction removeAction = new RemoveAction();
065        bookmarks.addListSelectionListener(removeAction);
066        pnl.add(new JButton(removeAction), gc);
067
068        gc.gridy = 1;
069        RenameAction renameAction = new RenameAction();
070        bookmarks.addListSelectionListener(renameAction);
071        pnl.add(new JButton(renameAction), gc);
072
073        gc.fill = GridBagConstraints.BOTH;
074        gc.weightx = 1.0;
075        gc.weighty = 1.0;
076        gc.gridy = 3;
077        pnl.add(new JPanel(), gc); // just a filler
078        return pnl;
079    }
080
081    protected JPanel buildDownloadAreaAddPanel() {
082        JPanel pnl = new JPanel();
083        pnl.setLayout(new GridBagLayout());
084
085        GridBagConstraints  gc = new GridBagConstraints();
086        gc.anchor = GridBagConstraints.NORTHWEST;
087        gc.insets = new Insets(5, 5, 5, 5);
088        pnl.add(lblCurrentDownloadArea = new JMultilineLabel(""), gc);
089
090        gc.weightx = 1.0;
091        gc.weighty = 1.0;
092        bboxDisplay.setEditable(false);
093        bboxDisplay.setBackground(pnl.getBackground());
094        bboxDisplay.addFocusListener(new BoundingBoxSelection.SelectAllOnFocusHandler(bboxDisplay));
095        pnl.add(bboxDisplay, gc);
096
097        gc.anchor = GridBagConstraints.NORTHEAST;
098        gc.fill = GridBagConstraints.HORIZONTAL;
099        gc.weightx = 0.0;
100        gc.weighty = 0.0;
101        gc.insets = new Insets(5, 5, 5, 5);
102        pnl.add(new JButton(actAdd = new AddAction()), gc);
103        return pnl;
104    }
105
106    @Override
107    public void addGui(final DownloadDialog gui) {
108        JPanel dlg = new JPanel(new GridBagLayout());
109        gui.addDownloadAreaSelector(dlg, tr("Bookmarks"));
110        GridBagConstraints gc = new GridBagConstraints();
111
112        bookmarks = new BookmarkList();
113        bookmarks.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
114            @Override
115            public void valueChanged(ListSelectionEvent e) {
116                Bookmark b = bookmarks.getSelectedValue();
117                if (b != null) {
118                    gui.boundingBoxChanged(b.getArea(), BookmarkSelection.this);
119                }
120            }
121        });
122        bookmarks.addMouseListener(new DoubleClickAdapter());
123
124        gc.fill = GridBagConstraints.HORIZONTAL;
125        gc.weightx = 1.0;
126        gc.weighty = 0.0;
127        gc.gridwidth = 2;
128        dlg.add(buildDownloadAreaAddPanel(), gc);
129
130        gc.gridwidth = 1;
131        gc.gridx = 0;
132        gc.gridy = 1;
133        gc.fill = GridBagConstraints.VERTICAL;
134        gc.weightx = 0.0;
135        gc.weighty = 1.0;
136        dlg.add(buildButtonPanel(), gc);
137
138        gc.gridwidth = 1;
139        gc.gridx = 1;
140        gc.gridy = 1;
141        gc.fill = GridBagConstraints.BOTH;
142        gc.weightx = 1.0;
143        gc.weighty = 1.0;
144        gc.gridx = 1;
145        dlg.add(new JScrollPane(bookmarks), gc);
146
147        this.parent = gui;
148    }
149
150    protected void updateDownloadAreaLabel() {
151        if (currentArea == null) {
152            lblCurrentDownloadArea.setText(tr("<html>There is currently no download area selected.</html>"));
153        } else {
154            lblCurrentDownloadArea.setText(tr("<html><strong>Current download area</strong> (minlon, minlat, maxlon, maxlat): </html>"));
155            bboxDisplay.setText(currentArea.toBBox().toStringCSV(","));
156        }
157    }
158
159    /**
160     * Sets the current download area
161     *
162     * @param area the download area.
163     */
164    @Override
165    public void setDownloadArea(Bounds area) {
166        if (area == null) return;
167        this.currentArea = area;
168        bookmarks.clearSelection();
169        updateDownloadAreaLabel();
170        actAdd.setEnabled(true);
171    }
172
173    /**
174     * The action to add a new bookmark for the current download area.
175     *
176     */
177    class AddAction extends AbstractAction {
178        AddAction() {
179            putValue(NAME, tr("Create bookmark"));
180            putValue(SMALL_ICON, ImageProvider.get("dialogs", "bookmark-new"));
181            putValue(SHORT_DESCRIPTION, tr("Add a bookmark for the currently selected download area"));
182        }
183
184        @Override
185        public void actionPerformed(ActionEvent e) {
186            if (currentArea == null) {
187                JOptionPane.showMessageDialog(
188                        Main.parent,
189                        tr("Currently, there is no download area selected. Please select an area first."),
190                        tr("Information"),
191                        JOptionPane.INFORMATION_MESSAGE
192                );
193                return;
194            }
195            Bookmark b = new Bookmark();
196            b.setName(
197                    JOptionPane.showInputDialog(
198                            Main.parent, tr("Please enter a name for the bookmarked download area."),
199                            tr("Name of location"),
200                            JOptionPane.QUESTION_MESSAGE)
201            );
202            b.setArea(currentArea);
203            if (b.getName() != null && !b.getName().isEmpty()) {
204                ((DefaultListModel<BookmarkList.Bookmark>) bookmarks.getModel()).addElement(b);
205                bookmarks.save();
206            }
207        }
208    }
209
210    class RemoveAction extends AbstractAction implements ListSelectionListener {
211        /**
212         * Constructs a new {@code RemoveAction}.
213         */
214        RemoveAction() {
215            putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
216            putValue(SHORT_DESCRIPTION, tr("Remove the currently selected bookmarks"));
217            updateEnabledState();
218        }
219
220        @Override
221        public void actionPerformed(ActionEvent e) {
222            List<Bookmark> sels = bookmarks.getSelectedValuesList();
223            if (sels == null || sels.isEmpty())
224                return;
225            for (Object sel: sels) {
226                ((DefaultListModel<Bookmark>) bookmarks.getModel()).removeElement(sel);
227            }
228            bookmarks.save();
229        }
230
231        protected final void updateEnabledState() {
232            setEnabled(bookmarks.getSelectedIndices().length > 0);
233        }
234
235        @Override
236        public void valueChanged(ListSelectionEvent e) {
237            updateEnabledState();
238        }
239    }
240
241    class RenameAction extends AbstractAction implements ListSelectionListener {
242        /**
243         * Constructs a new {@code RenameAction}.
244         */
245        RenameAction() {
246            putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));
247            putValue(SHORT_DESCRIPTION, tr("Rename the currently selected bookmark"));
248            updateEnabledState();
249        }
250
251        @Override
252        public void actionPerformed(ActionEvent e) {
253            List<Bookmark> sels = bookmarks.getSelectedValuesList();
254            if (sels == null || sels.size() != 1)
255                return;
256            Bookmark b = sels.get(0);
257            Object value =
258                JOptionPane.showInputDialog(
259                        Main.parent, tr("Please enter a name for the bookmarked download area."),
260                        tr("Name of location"),
261                        JOptionPane.QUESTION_MESSAGE,
262                        null,
263                        null,
264                        b.getName()
265                );
266            if (value != null) {
267                b.setName(value.toString());
268                bookmarks.save();
269                bookmarks.repaint();
270            }
271        }
272
273        protected final void updateEnabledState() {
274            setEnabled(bookmarks.getSelectedIndices().length == 1);
275        }
276
277        @Override
278        public void valueChanged(ListSelectionEvent e) {
279            updateEnabledState();
280        }
281    }
282
283    class DoubleClickAdapter extends MouseAdapter {
284        @Override
285        public void mouseClicked(MouseEvent e) {
286            if (!(SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2))
287                return;
288            int idx = bookmarks.locationToIndex(e.getPoint());
289            if (idx < 0 || idx >= bookmarks.getModel().getSize())
290                return;
291            Bookmark b = bookmarks.getModel().getElementAt(idx);
292            parent.startDownload(b.getArea());
293        }
294    }
295}