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