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

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

sonar - squid:S1186 - Methods should not be empty

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