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

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

fix #8885 (see #4614) - add offline mode with new command line argument --offline which can take one of several of these values (comma separated):

  • josm_website: to disable all accesses to JOSM website (when not cached, disables Getting Started page, help, plugin list, styles, imagery, presets, rules)
  • osm_api: to disable all accesses to OSM API (disables download, upload, changeset queries, history, user message notification)
  • all: alias to disable all values. Currently equivalent to "josm_website,osm_api"

Plus improved javadoc, fixed EDT violations, and fixed a bug with HTTP redirection sent without "Location" header

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