source: josm/trunk/src/org/openstreetmap/josm/gui/download/DownloadDialog.java@ 8470

Last change on this file since 8470 was 8470, checked in by Don-vip, 9 years ago

javadoc fixes. Removed one duplicated method in exception handling

  • Property svn:eol-style set to native
File size: 19.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.download;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.BorderLayout;
8import java.awt.Color;
9import java.awt.Component;
10import java.awt.Dimension;
11import java.awt.FlowLayout;
12import java.awt.Font;
13import java.awt.Graphics;
14import java.awt.GridBagLayout;
15import java.awt.event.ActionEvent;
16import java.awt.event.ActionListener;
17import java.awt.event.InputEvent;
18import java.awt.event.KeyEvent;
19import java.awt.event.WindowAdapter;
20import java.awt.event.WindowEvent;
21import java.util.ArrayList;
22import java.util.List;
23
24import javax.swing.AbstractAction;
25import javax.swing.JCheckBox;
26import javax.swing.JComponent;
27import javax.swing.JDialog;
28import javax.swing.JLabel;
29import javax.swing.JOptionPane;
30import javax.swing.JPanel;
31import javax.swing.JTabbedPane;
32import javax.swing.KeyStroke;
33import javax.swing.event.ChangeEvent;
34import javax.swing.event.ChangeListener;
35
36import org.openstreetmap.josm.Main;
37import org.openstreetmap.josm.actions.ExpertToggleAction;
38import org.openstreetmap.josm.data.Bounds;
39import org.openstreetmap.josm.gui.MapView;
40import org.openstreetmap.josm.gui.SideButton;
41import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
42import org.openstreetmap.josm.gui.help.HelpUtil;
43import org.openstreetmap.josm.io.OnlineResource;
44import org.openstreetmap.josm.plugins.PluginHandler;
45import org.openstreetmap.josm.tools.GBC;
46import org.openstreetmap.josm.tools.ImageProvider;
47import org.openstreetmap.josm.tools.InputMapUtils;
48import org.openstreetmap.josm.tools.OsmUrlToBounds;
49import org.openstreetmap.josm.tools.Utils;
50import org.openstreetmap.josm.tools.WindowGeometry;
51
52/**
53 * Dialog displayed to download OSM and/or GPS data from OSM server.
54 */
55public class DownloadDialog extends JDialog {
56 /** the unique instance of the download dialog */
57 private static DownloadDialog instance;
58
59 /**
60 * Replies the unique instance of the download dialog
61 *
62 * @return the unique instance of the download dialog
63 */
64 public static synchronized DownloadDialog getInstance() {
65 if (instance == null) {
66 instance = new DownloadDialog(Main.parent);
67 }
68 return instance;
69 }
70
71 protected SlippyMapChooser slippyMapChooser;
72 protected final transient List<DownloadSelection> downloadSelections = new ArrayList<>();
73 protected final JTabbedPane tpDownloadAreaSelectors = new JTabbedPane();
74 protected JCheckBox cbNewLayer;
75 protected JCheckBox cbStartup;
76 protected final JLabel sizeCheck = new JLabel();
77 protected transient Bounds currentBounds = null;
78 protected boolean canceled;
79
80 protected JCheckBox cbDownloadOsmData;
81 protected JCheckBox cbDownloadGpxData;
82 protected JCheckBox cbDownloadNotes;
83 /** the download action and button */
84 private DownloadAction actDownload;
85 protected SideButton btnDownload;
86
87 private void makeCheckBoxRespondToEnter(JCheckBox cb) {
88 cb.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "doDownload");
89 cb.getActionMap().put("doDownload", actDownload);
90 }
91
92 protected final JPanel buildMainPanel() {
93 JPanel pnl = new JPanel();
94 pnl.setLayout(new GridBagLayout());
95
96 final ChangeListener checkboxChangeListener = new ChangeListener() {
97 @Override
98 public void stateChanged(ChangeEvent e) {
99 // size check depends on selected data source
100 updateSizeCheck();
101 }
102 };
103
104 // adding the download tasks
105 pnl.add(new JLabel(tr("Data Sources and Types:")), GBC.std().insets(5,5,1,5));
106 cbDownloadOsmData = new JCheckBox(tr("OpenStreetMap data"), true);
107 cbDownloadOsmData.setToolTipText(tr("Select to download OSM data in the selected download area."));
108 cbDownloadOsmData.getModel().addChangeListener(checkboxChangeListener);
109 pnl.add(cbDownloadOsmData, GBC.std().insets(1, 5, 1, 5));
110 cbDownloadGpxData = new JCheckBox(tr("Raw GPS data"));
111 cbDownloadGpxData.setToolTipText(tr("Select to download GPS traces in the selected download area."));
112 cbDownloadGpxData.getModel().addChangeListener(checkboxChangeListener);
113 pnl.add(cbDownloadGpxData, GBC.std().insets(5, 5, 1, 5));
114 cbDownloadNotes = new JCheckBox(tr("Notes"));
115 cbDownloadNotes.setToolTipText(tr("Select to download notes in the selected download area."));
116 cbDownloadNotes.getModel().addChangeListener(checkboxChangeListener);
117 pnl.add(cbDownloadNotes, GBC.eol().insets(50, 5, 1, 5));
118
119 // hook for subclasses
120 buildMainPanelAboveDownloadSelections(pnl);
121
122 slippyMapChooser = new SlippyMapChooser();
123
124 // predefined download selections
125 downloadSelections.add(slippyMapChooser);
126 downloadSelections.add(new BookmarkSelection());
127 downloadSelections.add(new BoundingBoxSelection());
128 downloadSelections.add(new PlaceSelection());
129 downloadSelections.add(new TileSelection());
130
131 // add selections from plugins
132 PluginHandler.addDownloadSelection(downloadSelections);
133
134 // now everybody may add their tab to the tabbed pane
135 // (not done right away to allow plugins to remove one of
136 // the default selectors!)
137 for (DownloadSelection s : downloadSelections) {
138 s.addGui(this);
139 }
140
141 pnl.add(tpDownloadAreaSelectors, GBC.eol().fill());
142
143 try {
144 tpDownloadAreaSelectors.setSelectedIndex(Main.pref.getInteger("download.tab", 0));
145 } catch (Exception ex) {
146 Main.pref.putInteger("download.tab", 0);
147 }
148
149 Font labelFont = sizeCheck.getFont();
150 sizeCheck.setFont(labelFont.deriveFont(Font.PLAIN, labelFont.getSize()));
151
152 cbNewLayer = new JCheckBox(tr("Download as new layer"));
153 cbNewLayer.setToolTipText(tr("<html>Select to download data into a new data layer.<br>"
154 +"Unselect to download into the currently active data layer.</html>"));
155
156 cbStartup = new JCheckBox(tr("Open this dialog on startup"));
157 cbStartup.setToolTipText(tr("<html>Autostart ''Download from OSM'' dialog every time JOSM is started.<br>You can open it manually from File menu or toolbar.</html>"));
158 cbStartup.addActionListener(new ActionListener() {
159 @Override
160 public void actionPerformed(ActionEvent e) {
161 Main.pref.put("download.autorun", cbStartup.isSelected());
162 }});
163
164 pnl.add(cbNewLayer, GBC.std().anchor(GBC.WEST).insets(5,5,5,5));
165 pnl.add(cbStartup, GBC.std().anchor(GBC.WEST).insets(15,5,5,5));
166
167 pnl.add(sizeCheck, GBC.eol().anchor(GBC.EAST).insets(5,5,5,2));
168
169 if (!ExpertToggleAction.isExpert()) {
170 JLabel infoLabel = new JLabel(tr("Use left click&drag to select area, arrows or right mouse button to scroll map, wheel or +/- to zoom."));
171 pnl.add(infoLabel,GBC.eol().anchor(GBC.SOUTH).insets(0,0,0,0));
172 }
173 return pnl;
174 }
175
176 /* This should not be necessary, but if not here, repaint is not always correct in SlippyMap! */
177 @Override
178 public void paint(Graphics g) {
179 tpDownloadAreaSelectors.getSelectedComponent().paint(g);
180 super.paint(g);
181 }
182
183 protected final JPanel buildButtonPanel() {
184 JPanel pnl = new JPanel();
185 pnl.setLayout(new FlowLayout());
186
187 // -- download button
188 pnl.add(btnDownload = new SideButton(actDownload = new DownloadAction()));
189 InputMapUtils.enableEnter(btnDownload);
190
191 makeCheckBoxRespondToEnter(cbDownloadGpxData);
192 makeCheckBoxRespondToEnter(cbDownloadOsmData);
193 makeCheckBoxRespondToEnter(cbDownloadNotes);
194 makeCheckBoxRespondToEnter(cbNewLayer);
195
196 // -- cancel button
197 SideButton btnCancel;
198 CancelAction actCancel = new CancelAction();
199 pnl.add(btnCancel = new SideButton(actCancel));
200 InputMapUtils.enableEnter(btnCancel);
201
202 // -- cancel on ESC
203 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0), "cancel");
204 getRootPane().getActionMap().put("cancel", actCancel);
205
206 // -- help button
207 SideButton btnHelp;
208 pnl.add(btnHelp = new SideButton(new ContextSensitiveHelpAction(ht("/Action/Download"))));
209 InputMapUtils.enableEnter(btnHelp);
210
211 return pnl;
212 }
213
214 /**
215 * Constructs a new {@code DownloadDialog}.
216 * @param parent the parent component
217 */
218 public DownloadDialog(Component parent) {
219 super(JOptionPane.getFrameForComponent(parent),tr("Download"), ModalityType.DOCUMENT_MODAL);
220 getContentPane().setLayout(new BorderLayout());
221 getContentPane().add(buildMainPanel(), BorderLayout.CENTER);
222 getContentPane().add(buildButtonPanel(), BorderLayout.SOUTH);
223
224 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
225 KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK), "checkClipboardContents");
226
227 getRootPane().getActionMap().put("checkClipboardContents", new AbstractAction() {
228 @Override
229 public void actionPerformed(ActionEvent e) {
230 String clip = Utils.getClipboardContent();
231 if (clip == null) {
232 return;
233 }
234 Bounds b = OsmUrlToBounds.parse(clip);
235 if (b != null) {
236 boundingBoxChanged(new Bounds(b), null);
237 }
238 }
239 });
240 HelpUtil.setHelpContext(getRootPane(), ht("/Action/Download"));
241 addWindowListener(new WindowEventHandler());
242 restoreSettings();
243 }
244
245 private void updateSizeCheck() {
246 boolean isAreaTooLarge = false;
247 if (currentBounds == null) {
248 sizeCheck.setText(tr("No area selected yet"));
249 sizeCheck.setForeground(Color.darkGray);
250 } else if (isDownloadNotes() && !isDownloadOsmData() && !isDownloadGpxData()) {
251 // see max_note_request_area in https://github.com/openstreetmap/openstreetmap-website/blob/master/config/example.application.yml
252 isAreaTooLarge = currentBounds.getArea() > Main.pref.getDouble("osm-server.max-request-area-notes", 25);
253 } else {
254 // see max_request_area in https://github.com/openstreetmap/openstreetmap-website/blob/master/config/example.application.yml
255 isAreaTooLarge = currentBounds.getArea() > Main.pref.getDouble("osm-server.max-request-area", 0.25);
256 }
257 if (isAreaTooLarge) {
258 sizeCheck.setText(tr("Download area too large; will probably be rejected by server"));
259 sizeCheck.setForeground(Color.red);
260 } else {
261 sizeCheck.setText(tr("Download area ok, size probably acceptable to server"));
262 sizeCheck.setForeground(Color.darkGray);
263 }
264 }
265
266 /**
267 * Distributes a "bounding box changed" from one DownloadSelection
268 * object to the others, so they may update or clear their input fields.
269 *
270 * @param eventSource - the DownloadSelection object that fired this notification.
271 */
272 public void boundingBoxChanged(Bounds b, DownloadSelection eventSource) {
273 this.currentBounds = b;
274 for (DownloadSelection s : downloadSelections) {
275 if (s != eventSource) {
276 s.setDownloadArea(currentBounds);
277 }
278 }
279 updateSizeCheck();
280 }
281
282 /**
283 * Starts download for the given bounding box
284 * @param b bounding box to download
285 */
286 public void startDownload(Bounds b) {
287 this.currentBounds = b;
288 actDownload.run();
289 }
290
291 /**
292 * Replies true if the user selected to download OSM data
293 *
294 * @return true if the user selected to download OSM data
295 */
296 public boolean isDownloadOsmData() {
297 return cbDownloadOsmData.isSelected();
298 }
299
300 /**
301 * Replies true if the user selected to download GPX data
302 *
303 * @return true if the user selected to download GPX data
304 */
305 public boolean isDownloadGpxData() {
306 return cbDownloadGpxData.isSelected();
307 }
308
309 /**
310 * Replies true if user selected to download notes
311 *
312 * @return true if user selected to download notes
313 */
314 public boolean isDownloadNotes() {
315 return cbDownloadNotes.isSelected();
316 }
317
318 /**
319 * Replies true if the user requires to download into a new layer
320 *
321 * @return true if the user requires to download into a new layer
322 */
323 public boolean isNewLayerRequired() {
324 return cbNewLayer.isSelected();
325 }
326
327 /**
328 * Adds a new download area selector to the download dialog
329 *
330 * @param selector the download are selector
331 * @param displayName the display name of the selector
332 */
333 public void addDownloadAreaSelector(JPanel selector, String displayName) {
334 tpDownloadAreaSelectors.add(displayName, selector);
335 }
336
337 /**
338 * Refreshes the tile sources
339 * @since 6364
340 */
341 public final void refreshTileSources() {
342 if (slippyMapChooser != null) {
343 slippyMapChooser.refreshTileSources();
344 }
345 }
346
347 /**
348 * Remembers the current settings in the download dialog.
349 */
350 public void rememberSettings() {
351 Main.pref.put("download.tab", Integer.toString(tpDownloadAreaSelectors.getSelectedIndex()));
352 Main.pref.put("download.osm", cbDownloadOsmData.isSelected());
353 Main.pref.put("download.gps", cbDownloadGpxData.isSelected());
354 Main.pref.put("download.notes", cbDownloadNotes.isSelected());
355 Main.pref.put("download.newlayer", cbNewLayer.isSelected());
356 if (currentBounds != null) {
357 Main.pref.put("osm-download.bounds", currentBounds.encodeAsString(";"));
358 }
359 }
360
361 /**
362 * Restores the previous settings in the download dialog.
363 */
364 public void restoreSettings() {
365 cbDownloadOsmData.setSelected(Main.pref.getBoolean("download.osm", true));
366 cbDownloadGpxData.setSelected(Main.pref.getBoolean("download.gps", false));
367 cbDownloadNotes.setSelected(Main.pref.getBoolean("download.notes", false));
368 cbNewLayer.setSelected(Main.pref.getBoolean("download.newlayer", false));
369 cbStartup.setSelected(isAutorunEnabled());
370 int idx = Main.pref.getInteger("download.tab", 0);
371 if (idx < 0 || idx > tpDownloadAreaSelectors.getTabCount()) {
372 idx = 0;
373 }
374 tpDownloadAreaSelectors.setSelectedIndex(idx);
375
376 if (Main.isDisplayingMapView()) {
377 MapView mv = Main.map.mapView;
378 currentBounds = new Bounds(
379 mv.getLatLon(0, mv.getHeight()),
380 mv.getLatLon(mv.getWidth(), 0)
381 );
382 boundingBoxChanged(currentBounds,null);
383 } else {
384 Bounds bounds = getSavedDownloadBounds();
385 if (bounds != null) {
386 currentBounds = bounds;
387 boundingBoxChanged(currentBounds, null);
388 }
389 }
390 }
391
392 /**
393 * Returns the previously saved bounding box from preferences.
394 * @return The bounding box saved in preferences if any, {@code null} otherwise
395 * @since 6509
396 */
397 public static Bounds getSavedDownloadBounds() {
398 String value = Main.pref.get("osm-download.bounds");
399 if (!value.isEmpty()) {
400 try {
401 return new Bounds(value, ";");
402 } catch (IllegalArgumentException e) {
403 Main.warn(e);
404 }
405 }
406 return null;
407 }
408
409 /**
410 * Determines if the dialog autorun is enabled in preferences.
411 * @return {@code true} if the download dialog must be open at startup, {@code false} otherwise
412 */
413 public static boolean isAutorunEnabled() {
414 return Main.pref.getBoolean("download.autorun",false);
415 }
416
417 public static void autostartIfNeeded() {
418 if (isAutorunEnabled()) {
419 Main.main.menu.download.actionPerformed(null);
420 }
421 }
422
423 /**
424 * Replies the currently selected download area.
425 * @return the currently selected download area. May be {@code null}, if no download area is selected yet.
426 */
427 public Bounds getSelectedDownloadArea() {
428 return currentBounds;
429 }
430
431 @Override
432 public void setVisible(boolean visible) {
433 if (visible) {
434 new WindowGeometry(
435 getClass().getName() + ".geometry",
436 WindowGeometry.centerInWindow(
437 getParent(),
438 new Dimension(1000,600)
439 )
440 ).applySafe(this);
441 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775
442 new WindowGeometry(this).remember(getClass().getName() + ".geometry");
443 }
444 super.setVisible(visible);
445 }
446
447 /**
448 * Replies true if the dialog was canceled
449 *
450 * @return true if the dialog was canceled
451 */
452 public boolean isCanceled() {
453 return canceled;
454 }
455
456 protected void setCanceled(boolean canceled) {
457 this.canceled = canceled;
458 }
459
460 protected void buildMainPanelAboveDownloadSelections(JPanel pnl) {
461 }
462
463 class CancelAction extends AbstractAction {
464 public CancelAction() {
465 putValue(NAME, tr("Cancel"));
466 putValue(SMALL_ICON, ImageProvider.get("cancel"));
467 putValue(SHORT_DESCRIPTION, tr("Click to close the dialog and to abort downloading"));
468 }
469
470 public void run() {
471 setCanceled(true);
472 setVisible(false);
473 }
474
475 @Override
476 public void actionPerformed(ActionEvent e) {
477 run();
478 }
479 }
480
481 class DownloadAction extends AbstractAction {
482 public DownloadAction() {
483 putValue(NAME, tr("Download"));
484 putValue(SMALL_ICON, ImageProvider.get("download"));
485 putValue(SHORT_DESCRIPTION, tr("Click to download the currently selected area"));
486 setEnabled(!Main.isOffline(OnlineResource.OSM_API));
487 }
488
489 public void run() {
490 if (currentBounds == null) {
491 JOptionPane.showMessageDialog(
492 DownloadDialog.this,
493 tr("Please select a download area first."),
494 tr("Error"),
495 JOptionPane.ERROR_MESSAGE
496 );
497 return;
498 }
499 if (!isDownloadOsmData() && !isDownloadGpxData() && !isDownloadNotes()) {
500 JOptionPane.showMessageDialog(
501 DownloadDialog.this,
502 tr("<html>Neither <strong>{0}</strong> nor <strong>{1}</strong> nor <strong>{2}</strong> is enabled.<br>"
503 + "Please choose to either download OSM data, or GPX data, or Notes, or all.</html>",
504 cbDownloadOsmData.getText(),
505 cbDownloadGpxData.getText(),
506 cbDownloadNotes.getText()
507 ),
508 tr("Error"),
509 JOptionPane.ERROR_MESSAGE
510 );
511 return;
512 }
513 setCanceled(false);
514 setVisible(false);
515 }
516
517 @Override
518 public void actionPerformed(ActionEvent e) {
519 run();
520 }
521 }
522
523 class WindowEventHandler extends WindowAdapter {
524 @Override
525 public void windowClosing(WindowEvent e) {
526 new CancelAction().run();
527 }
528
529 @Override
530 public void windowActivated(WindowEvent e) {
531 btnDownload.requestFocusInWindow();
532 }
533 }
534}
Note: See TracBrowser for help on using the repository browser.