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

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

sonar - squid:S3052 - Fields should not be initialized to default values

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