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