source: josm/trunk/src/org/openstreetmap/josm/Main.java@ 5509

Last change on this file since 5509 was 5481, checked in by stoecker, 12 years ago

some cleanup, mainly javadoc

  • Property svn:eol-style set to native
File size: 34.7 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm;
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.BorderLayout;
6import java.awt.Component;
7import java.awt.GridBagConstraints;
8import java.awt.GridBagLayout;
9import java.awt.event.ComponentEvent;
10import java.awt.event.ComponentListener;
11import java.awt.event.KeyEvent;
12import java.awt.event.WindowAdapter;
13import java.awt.event.WindowEvent;
14import java.io.File;
15import java.lang.ref.WeakReference;
16import java.net.URI;
17import java.net.URISyntaxException;
18import java.text.MessageFormat;
19import java.util.ArrayList;
20import java.util.Collection;
21import java.util.Iterator;
22import java.util.List;
23import java.util.Map;
24import java.util.StringTokenizer;
25import java.util.concurrent.Callable;
26import java.util.concurrent.ExecutorService;
27import java.util.concurrent.Executors;
28import java.util.concurrent.Future;
29
30import javax.swing.Action;
31import javax.swing.InputMap;
32import javax.swing.JComponent;
33import javax.swing.JFrame;
34import javax.swing.JLabel;
35import javax.swing.JOptionPane;
36import javax.swing.JPanel;
37import javax.swing.JTextArea;
38import javax.swing.KeyStroke;
39import javax.swing.UIManager;
40
41import org.openstreetmap.gui.jmapviewer.FeatureAdapter;
42import org.openstreetmap.josm.actions.JosmAction;
43import org.openstreetmap.josm.actions.OpenFileAction;
44import org.openstreetmap.josm.actions.downloadtasks.DownloadGpsTask;
45import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
46import org.openstreetmap.josm.actions.downloadtasks.DownloadTask;
47import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
48import org.openstreetmap.josm.actions.mapmode.MapMode;
49import org.openstreetmap.josm.actions.search.SearchAction;
50import org.openstreetmap.josm.data.Bounds;
51import org.openstreetmap.josm.data.Preferences;
52import org.openstreetmap.josm.data.UndoRedoHandler;
53import org.openstreetmap.josm.data.coor.CoordinateFormat;
54import org.openstreetmap.josm.data.coor.LatLon;
55import org.openstreetmap.josm.data.osm.DataSet;
56import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
57import org.openstreetmap.josm.data.projection.Projection;
58import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
59import org.openstreetmap.josm.data.validation.OsmValidator;
60import org.openstreetmap.josm.gui.GettingStarted;
61import org.openstreetmap.josm.gui.MainApplication.Option;
62import org.openstreetmap.josm.gui.MainMenu;
63import org.openstreetmap.josm.gui.MapFrame;
64import org.openstreetmap.josm.gui.MapView;
65import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
66import org.openstreetmap.josm.gui.io.SaveLayersDialog;
67import org.openstreetmap.josm.gui.layer.Layer;
68import org.openstreetmap.josm.gui.layer.OsmDataLayer;
69import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
70import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
71import org.openstreetmap.josm.gui.preferences.imagery.ImageryPreference;
72import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference;
73import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
74import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
75import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
76import org.openstreetmap.josm.gui.progress.ProgressMonitorExecutor;
77import org.openstreetmap.josm.gui.util.RedirectInputMap;
78import org.openstreetmap.josm.io.OsmApi;
79import org.openstreetmap.josm.plugins.PluginHandler;
80import org.openstreetmap.josm.tools.CheckParameterUtil;
81import org.openstreetmap.josm.tools.I18n;
82import org.openstreetmap.josm.tools.ImageProvider;
83import org.openstreetmap.josm.tools.OpenBrowser;
84import org.openstreetmap.josm.tools.OsmUrlToBounds;
85import org.openstreetmap.josm.tools.PlatformHook;
86import org.openstreetmap.josm.tools.PlatformHookOsx;
87import org.openstreetmap.josm.tools.PlatformHookUnixoid;
88import org.openstreetmap.josm.tools.PlatformHookWindows;
89import org.openstreetmap.josm.tools.Shortcut;
90import org.openstreetmap.josm.tools.Utils;
91import org.openstreetmap.josm.tools.WindowGeometry;
92
93abstract public class Main {
94
95 /**
96 * Replies true if JOSM currently displays a map view. False, if it doesn't, i.e. if
97 * it only shows the MOTD panel.
98 *
99 * @return <code>true</code> if JOSM currently displays a map view
100 */
101 static public boolean isDisplayingMapView() {
102 if (map == null) return false;
103 if (map.mapView == null) return false;
104 return true;
105 }
106 /**
107 * Global parent component for all dialogs and message boxes
108 */
109 public static Component parent;
110 /**
111 * Global application.
112 */
113 public static Main main;
114 /**
115 * The worker thread slave. This is for executing all long and intensive
116 * calculations. The executed runnables are guaranteed to be executed separately
117 * and sequential.
118 */
119 public final static ExecutorService worker = new ProgressMonitorExecutor();
120 /**
121 * Global application preferences
122 */
123 public static Preferences pref;
124
125 /**
126 * The global paste buffer.
127 */
128 public static final PrimitiveDeepCopy pasteBuffer = new PrimitiveDeepCopy();
129 public static Layer pasteSource;
130
131 /**
132 * The MapFrame. Use setMapFrame to set or clear it.
133 */
134 public static MapFrame map;
135 /**
136 * Set to <code>true</code>, when in applet mode
137 */
138 public static boolean applet = false;
139
140 /**
141 * The toolbar preference control to register new actions.
142 */
143 public static ToolbarPreferences toolbar;
144
145 public UndoRedoHandler undoRedo = new UndoRedoHandler();
146
147 public static PleaseWaitProgressMonitor currentProgressMonitor;
148
149 /**
150 * The main menu bar at top of screen.
151 */
152 public MainMenu menu;
153
154 /**
155 * The data validation handler.
156 */
157 public OsmValidator validator;
158 /**
159 * The MOTD Layer.
160 */
161 private GettingStarted gettingStarted = new GettingStarted();
162
163 /**
164 * Logging level (3 = debug, 2 = info, 1 = warn, 0 = none).
165 */
166 static public int log_level = 2;
167 /**
168 * Print a warning message if logging is on.
169 * @param msg The message to print.
170 */
171 static public void warn(String msg) {
172 if (log_level < 1)
173 return;
174 System.out.println(msg);
175 }
176 /**
177 * Print an informational message if logging is on.
178 * @param msg The message to print.
179 */
180 static public void info(String msg) {
181 if (log_level < 2)
182 return;
183 System.out.println(msg);
184 }
185 /**
186 * Print an debug message if logging is on.
187 * @param msg The message to print.
188 */
189 static public void debug(String msg) {
190 if (log_level < 3)
191 return;
192 System.out.println(msg);
193 }
194 /**
195 * Print a formated warning message if logging is on. Calls {@link MessageFormat#format}
196 * function to format text.
197 * @param msg The formated message to print.
198 * @param objects The objects to insert into format string.
199 */
200 static public void warn(String msg, Object... objects) {
201 warn(MessageFormat.format(msg, objects));
202 }
203 /**
204 * Print a formated informational message if logging is on. Calls {@link MessageFormat#format}
205 * function to format text.
206 * @param msg The formated message to print.
207 * @param objects The objects to insert into format string.
208 */
209 static public void info(String msg, Object... objects) {
210 info(MessageFormat.format(msg, objects));
211 }
212 /**
213 * Print a formated debug message if logging is on. Calls {@link MessageFormat#format}
214 * function to format text.
215 * @param msg The formated message to print.
216 * @param objects The objects to insert into format string.
217 */
218 static public void debug(String msg, Object... objects) {
219 debug(MessageFormat.format(msg, objects));
220 }
221
222 /**
223 * Platform specific code goes in here.
224 * Plugins may replace it, however, some hooks will be called before any plugins have been loeaded.
225 * So if you need to hook into those early ones, split your class and send the one with the early hooks
226 * to the JOSM team for inclusion.
227 */
228 public static PlatformHook platform;
229
230 /**
231 * Whether or not the java vm is openjdk
232 * We use this to work around openjdk bugs
233 */
234 public static boolean isOpenjdk;
235
236 /**
237 * Set or clear (if passed <code>null</code>) the map.
238 */
239 public final void setMapFrame(final MapFrame map) {
240 MapFrame old = Main.map;
241 panel.setVisible(false);
242 panel.removeAll();
243 if (map != null) {
244 map.fillPanel(panel);
245 } else {
246 old.destroy();
247 panel.add(gettingStarted, BorderLayout.CENTER);
248 }
249 panel.setVisible(true);
250 redoUndoListener.commandChanged(0,0);
251
252 Main.map = map;
253
254 PluginHandler.notifyMapFrameChanged(old, map);
255 if (map == null && currentProgressMonitor != null) {
256 currentProgressMonitor.showForegroundDialog();
257 }
258 }
259
260 /**
261 * Remove the specified layer from the map. If it is the last layer,
262 * remove the map as well.
263 */
264 public final void removeLayer(final Layer layer) {
265 if (map != null) {
266 map.mapView.removeLayer(layer);
267 if (map != null && map.mapView.getAllLayers().isEmpty()) {
268 setMapFrame(null);
269 }
270 }
271 }
272
273 private static InitStatusListener initListener = null;
274
275 public static interface InitStatusListener {
276
277 void updateStatus(String event);
278 }
279
280 public static void setInitStatusListener(InitStatusListener listener) {
281 initListener = listener;
282 }
283
284 public Main() {
285 main = this;
286 isOpenjdk = System.getProperty("java.vm.name").toUpperCase().indexOf("OPENJDK") != -1;
287
288 if (initListener != null) {
289 initListener.updateStatus(tr("Executing platform startup hook"));
290 }
291 platform.startupHook();
292
293 if (initListener != null) {
294 initListener.updateStatus(tr("Building main menu"));
295 }
296 contentPanePrivate.add(panel, BorderLayout.CENTER);
297 panel.add(gettingStarted, BorderLayout.CENTER);
298 menu = new MainMenu();
299
300 undoRedo.addCommandQueueListener(redoUndoListener);
301
302 // creating toolbar
303 contentPanePrivate.add(toolbar.control, BorderLayout.NORTH);
304
305 registerActionShortcut(menu.help, Shortcut.registerShortcut("system:help", tr("Help"),
306 KeyEvent.VK_F1, Shortcut.DIRECT));
307
308 // contains several initialization tasks to be executed (in parallel) by a ExecutorService
309 List<Callable<Void>> tasks = new ArrayList<Callable<Void>>();
310
311 tasks.add(new Callable<Void>() {
312
313 @Override
314 public Void call() throws Exception {
315 // We try to establish an API connection early, so that any API
316 // capabilities are already known to the editor instance. However
317 // if it goes wrong that's not critical at this stage.
318 if (initListener != null) {
319 initListener.updateStatus(tr("Initializing OSM API"));
320 }
321 try {
322 OsmApi.getOsmApi().initialize(null, true);
323 } catch (Exception x) {
324 // ignore any exception here.
325 }
326 return null;
327 }
328 });
329
330 tasks.add(new Callable<Void>() {
331
332 @Override
333 public Void call() throws Exception {
334 if (initListener != null) {
335 initListener.updateStatus(tr("Initializing presets"));
336 }
337 TaggingPresetPreference.initialize();
338 // some validator tests require the presets to be initialized
339 // TODO remove this dependency for parallel initialization
340 if (initListener != null) {
341 initListener.updateStatus(tr("Initializing validator"));
342 }
343 validator = new OsmValidator();
344 MapView.addLayerChangeListener(validator);
345 return null;
346 }
347 });
348
349 tasks.add(new Callable<Void>() {
350
351 @Override
352 public Void call() throws Exception {
353 if (initListener != null) {
354 initListener.updateStatus(tr("Initializing map styles"));
355 }
356 MapPaintPreference.initialize();
357 return null;
358 }
359 });
360
361 tasks.add(new Callable<Void>() {
362
363 @Override
364 public Void call() throws Exception {
365 if (initListener != null) {
366 initListener.updateStatus(tr("Loading imagery preferences"));
367 }
368 ImageryPreference.initialize();
369 return null;
370 }
371 });
372
373 try {
374 for (Future<Void> i : Executors.newFixedThreadPool(
375 Runtime.getRuntime().availableProcessors()).invokeAll(tasks)) {
376 i.get();
377 }
378 } catch (Exception ex) {
379 throw new RuntimeException(ex);
380 }
381
382 // hooks for the jmapviewer component
383 FeatureAdapter.registerBrowserAdapter(new FeatureAdapter.BrowserAdapter() {
384 @Override
385 public void openLink(String url) {
386 OpenBrowser.displayUrl(url);
387 }
388 });
389 FeatureAdapter.registerTranslationAdapter(I18n.getTranslationAdapter());
390
391 if (initListener != null) {
392 initListener.updateStatus(tr("Updating user interface"));
393 }
394
395 toolbar.refreshToolbarControl();
396
397 toolbar.control.updateUI();
398 contentPanePrivate.updateUI();
399
400 }
401
402 /**
403 * Add a new layer to the map. If no map exists, create one.
404 */
405 public final synchronized void addLayer(final Layer layer) {
406 if (map == null) {
407 final MapFrame mapFrame = new MapFrame(contentPanePrivate);
408 setMapFrame(mapFrame);
409 mapFrame.selectMapMode((MapMode)mapFrame.getDefaultButtonAction(), layer);
410 mapFrame.setVisible(true);
411 mapFrame.initializeDialogsPane();
412 // bootstrapping problem: make sure the layer list dialog is going to
413 // listen to change events of the very first layer
414 //
415 layer.addPropertyChangeListener(LayerListDialog.getInstance().getModel());
416 }
417 layer.hookUpMapView();
418 map.mapView.addLayer(layer);
419 }
420
421 /**
422 * Replies <code>true</code> if there is an edit layer
423 *
424 * @return <code>true</code> if there is an edit layer
425 */
426 public boolean hasEditLayer() {
427 if (getEditLayer() == null) return false;
428 return true;
429 }
430
431 /**
432 * Replies the current edit layer
433 *
434 * @return the current edit layer. <code>null</code>, if no current edit layer exists
435 */
436 public OsmDataLayer getEditLayer() {
437 if (map == null) return null;
438 if (map.mapView == null) return null;
439 return map.mapView.getEditLayer();
440 }
441
442 /**
443 * Replies the current data set.
444 *
445 * @return the current data set. <code>null</code>, if no current data set exists
446 */
447 public DataSet getCurrentDataSet() {
448 if (!hasEditLayer()) return null;
449 return getEditLayer().data;
450 }
451
452 /**
453 * Returns the currently active layer
454 *
455 * @return the currently active layer. <code>null</code>, if currently no active layer exists
456 */
457 public Layer getActiveLayer() {
458 if (map == null) return null;
459 if (map.mapView == null) return null;
460 return map.mapView.getActiveLayer();
461 }
462
463 protected static final JPanel contentPanePrivate = new JPanel(new BorderLayout());
464
465 public static void redirectToMainContentPane(JComponent source) {
466 RedirectInputMap.redirect(source, contentPanePrivate);
467 }
468
469 public static void registerActionShortcut(JosmAction action) {
470 registerActionShortcut(action, action.getShortcut());
471 }
472
473 public static void registerActionShortcut(Action action, Shortcut shortcut) {
474 KeyStroke keyStroke = shortcut.getKeyStroke();
475 if (keyStroke == null)
476 return;
477
478 InputMap inputMap = contentPanePrivate.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
479 Object existing = inputMap.get(keyStroke);
480 if (existing != null && !existing.equals(action)) {
481 System.out.println(String.format("Keystroke %s is already assigned to %s, will be overridden by %s", keyStroke, existing, action));
482 }
483 inputMap.put(keyStroke, action);
484
485 contentPanePrivate.getActionMap().put(action, action);
486 }
487
488 public static void unregisterShortcut(Shortcut shortcut) {
489 contentPanePrivate.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(shortcut.getKeyStroke());
490 }
491
492 public static void unregisterActionShortcut(JosmAction action) {
493 unregisterActionShortcut(action, action.getShortcut());
494 }
495
496 public static void unregisterActionShortcut(Action action, Shortcut shortcut) {
497 unregisterShortcut(shortcut);
498 contentPanePrivate.getActionMap().remove(action);
499 }
500
501 ///////////////////////////////////////////////////////////////////////////
502 // Implementation part
503 ///////////////////////////////////////////////////////////////////////////
504
505 public static final JPanel panel = new JPanel(new BorderLayout());
506
507 protected static WindowGeometry geometry;
508 protected static int windowState = JFrame.NORMAL;
509
510 private final CommandQueueListener redoUndoListener = new CommandQueueListener(){
511 public void commandChanged(final int queueSize, final int redoSize) {
512 menu.undo.setEnabled(queueSize > 0);
513 menu.redo.setEnabled(redoSize > 0);
514 }
515 };
516
517 /**
518 * Should be called before the main constructor to setup some parameter stuff
519 * @param args The parsed argument list.
520 */
521 public static void preConstructorInit(Map<Option, Collection<String>> args) {
522 ProjectionPreference.setProjection();
523
524 try {
525 String defaultlaf = platform.getDefaultStyle();
526 String laf = Main.pref.get("laf", defaultlaf);
527 try {
528 UIManager.setLookAndFeel(laf);
529 }
530 catch (final java.lang.ClassNotFoundException e) {
531 System.out.println("Look and Feel not found: " + laf);
532 Main.pref.put("laf", defaultlaf);
533 }
534 catch (final javax.swing.UnsupportedLookAndFeelException e) {
535 System.out.println("Look and Feel not supported: " + laf);
536 Main.pref.put("laf", defaultlaf);
537 }
538 toolbar = new ToolbarPreferences();
539 contentPanePrivate.updateUI();
540 panel.updateUI();
541 } catch (final Exception e) {
542 e.printStackTrace();
543 }
544 UIManager.put("OptionPane.okIcon", ImageProvider.get("ok"));
545 UIManager.put("OptionPane.yesIcon", UIManager.get("OptionPane.okIcon"));
546 UIManager.put("OptionPane.cancelIcon", ImageProvider.get("cancel"));
547 UIManager.put("OptionPane.noIcon", UIManager.get("OptionPane.cancelIcon"));
548
549 I18n.translateJavaInternalMessages();
550
551 // init default coordinate format
552 //
553 try {
554 //CoordinateFormat format = CoordinateFormat.valueOf(Main.pref.get("coordinates"));
555 CoordinateFormat.setCoordinateFormat(CoordinateFormat.valueOf(Main.pref.get("coordinates")));
556 } catch (IllegalArgumentException iae) {
557 CoordinateFormat.setCoordinateFormat(CoordinateFormat.DECIMAL_DEGREES);
558 }
559
560 geometry = WindowGeometry.mainWindow("gui.geometry",
561 (args.containsKey(Option.GEOMETRY) ? args.get(Option.GEOMETRY).iterator().next() : null),
562 !args.containsKey(Option.NO_MAXIMIZE) && Main.pref.getBoolean("gui.maximized", false));
563 }
564
565 public void postConstructorProcessCmdLine(Map<Option, Collection<String>> args) {
566 if (args.containsKey(Option.DOWNLOAD)) {
567 List<File> fileList = new ArrayList<File>();
568 for (String s : args.get(Option.DOWNLOAD)) {
569 File f = null;
570 switch(paramType(s)) {
571 case httpUrl:
572 downloadFromParamHttp(false, s);
573 break;
574 case bounds:
575 downloadFromParamBounds(false, s);
576 break;
577 case fileUrl:
578 try {
579 f = new File(new URI(s));
580 } catch (URISyntaxException e) {
581 JOptionPane.showMessageDialog(
582 Main.parent,
583 tr("Ignoring malformed file URL: \"{0}\"", s),
584 tr("Warning"),
585 JOptionPane.WARNING_MESSAGE
586 );
587 }
588 if (f!=null) {
589 fileList.add(f);
590 }
591 break;
592 case fileName:
593 f = new File(s);
594 fileList.add(f);
595 break;
596 }
597 }
598 if(!fileList.isEmpty())
599 {
600 OpenFileAction.openFiles(fileList, true);
601 }
602 }
603 if (args.containsKey(Option.DOWNLOADGPS)) {
604 for (String s : args.get(Option.DOWNLOADGPS)) {
605 switch(paramType(s)) {
606 case httpUrl:
607 downloadFromParamHttp(true, s);
608 break;
609 case bounds:
610 downloadFromParamBounds(true, s);
611 break;
612 case fileUrl:
613 case fileName:
614 JOptionPane.showMessageDialog(
615 Main.parent,
616 tr("Parameter \"downloadgps\" does not accept file names or file URLs"),
617 tr("Warning"),
618 JOptionPane.WARNING_MESSAGE
619 );
620 }
621 }
622 }
623 if (args.containsKey(Option.SELECTION)) {
624 for (String s : args.get(Option.SELECTION)) {
625 SearchAction.search(s, SearchAction.SearchMode.add);
626 }
627 }
628 }
629
630 public static boolean saveUnsavedModifications() {
631 if (map == null) return true;
632 SaveLayersDialog dialog = new SaveLayersDialog(Main.parent);
633 List<OsmDataLayer> layersWithUnmodifiedChanges = new ArrayList<OsmDataLayer>();
634 for (OsmDataLayer l: Main.map.mapView.getLayersOfType(OsmDataLayer.class)) {
635 if ((l.requiresSaveToFile() || l.requiresUploadToServer()) && l.data.isModified()) {
636 layersWithUnmodifiedChanges.add(l);
637 }
638 }
639 dialog.prepareForSavingAndUpdatingLayersBeforeExit();
640 if (!layersWithUnmodifiedChanges.isEmpty()) {
641 dialog.getModel().populate(layersWithUnmodifiedChanges);
642 dialog.setVisible(true);
643 switch(dialog.getUserAction()) {
644 case CANCEL: return false;
645 case PROCEED: return true;
646 default: return false;
647 }
648 }
649
650 return true;
651 }
652
653 public static boolean exitJosm(boolean exit) {
654 if (Main.saveUnsavedModifications()) {
655 geometry.remember("gui.geometry");
656 if (map != null) {
657 map.rememberToggleDialogWidth();
658 }
659 pref.put("gui.maximized", (windowState & JFrame.MAXIMIZED_BOTH) != 0);
660 // Remove all layers because somebody may rely on layerRemoved events (like AutosaveTask)
661 if (Main.isDisplayingMapView()) {
662 Collection<Layer> layers = new ArrayList<Layer>(Main.map.mapView.getAllLayers());
663 for (Layer l: layers) {
664 Main.map.mapView.removeLayer(l);
665 }
666 }
667 if (exit) {
668 System.exit(0);
669 return true;
670 } else
671 return true;
672 } else
673 return false;
674 }
675
676 /**
677 * The type of a command line parameter, to be used in switch statements.
678 * @see #paramType
679 */
680 private enum DownloadParamType { httpUrl, fileUrl, bounds, fileName }
681
682 /**
683 * Guess the type of a parameter string specified on the command line with --download= or --downloadgps.
684 * @param s A parameter string
685 * @return The guessed parameter type
686 */
687 private DownloadParamType paramType(String s) {
688 if(s.startsWith("http:")) return DownloadParamType.httpUrl;
689 if(s.startsWith("file:")) return DownloadParamType.fileUrl;
690 String coorPattern = "\\s*[+-]?[0-9]+(\\.[0-9]+)?\\s*";
691 if(s.matches(coorPattern+"(,"+coorPattern+"){3}")) return DownloadParamType.bounds;
692 // everything else must be a file name
693 return DownloadParamType.fileName;
694 }
695
696 /**
697 * Download area specified on the command line as OSM URL.
698 * @param rawGps Flag to download raw GPS tracks
699 * @param s The URL parameter
700 */
701 private static void downloadFromParamHttp(final boolean rawGps, String s) {
702 final Bounds b = OsmUrlToBounds.parse(s);
703 if (b == null) {
704 JOptionPane.showMessageDialog(
705 Main.parent,
706 tr("Ignoring malformed URL: \"{0}\"", s),
707 tr("Warning"),
708 JOptionPane.WARNING_MESSAGE
709 );
710 } else {
711 downloadFromParamBounds(rawGps, b);
712 }
713 }
714
715 /**
716 * Download area specified on the command line as bounds string.
717 * @param rawGps Flag to download raw GPS tracks
718 * @param s The bounds parameter
719 */
720 private static void downloadFromParamBounds(final boolean rawGps, String s) {
721 final StringTokenizer st = new StringTokenizer(s, ",");
722 if (st.countTokens() == 4) {
723 Bounds b = new Bounds(
724 new LatLon(Double.parseDouble(st.nextToken()),Double.parseDouble(st.nextToken())),
725 new LatLon(Double.parseDouble(st.nextToken()),Double.parseDouble(st.nextToken()))
726 );
727 downloadFromParamBounds(rawGps, b);
728 }
729 }
730
731 /**
732 * Download area specified as Bounds value.
733 * @param rawGps Flag to download raw GPS tracks
734 * @param b The bounds value
735 * @see #downloadFromParamBounds(boolean, String)
736 * @see #downloadFromParamHttp
737 */
738 private static void downloadFromParamBounds(final boolean rawGps, Bounds b) {
739 DownloadTask task = rawGps ? new DownloadGpsTask() : new DownloadOsmTask();
740 // asynchronously launch the download task ...
741 Future<?> future = task.download(true, b, null);
742 // ... and the continuation when the download is finished (this will wait for the download to finish)
743 Main.worker.execute(new PostDownloadHandler(task, future));
744 }
745
746 public static void determinePlatformHook() {
747 String os = System.getProperty("os.name");
748 if (os == null) {
749 System.err.println("Your operating system has no name, so I'm guessing its some kind of *nix.");
750 platform = new PlatformHookUnixoid();
751 } else if (os.toLowerCase().startsWith("windows")) {
752 platform = new PlatformHookWindows();
753 } else if (os.equals("Linux") || os.equals("Solaris") ||
754 os.equals("SunOS") || os.equals("AIX") ||
755 os.equals("FreeBSD") || os.equals("NetBSD") || os.equals("OpenBSD")) {
756 platform = new PlatformHookUnixoid();
757 } else if (os.toLowerCase().startsWith("mac os x")) {
758 platform = new PlatformHookOsx();
759 } else {
760 System.err.println("I don't know your operating system '"+os+"', so I'm guessing its some kind of *nix.");
761 platform = new PlatformHookUnixoid();
762 }
763 }
764
765 private static class WindowPositionSizeListener extends WindowAdapter implements
766 ComponentListener {
767 @Override
768 public void windowStateChanged(WindowEvent e) {
769 Main.windowState = e.getNewState();
770 }
771
772 @Override
773 public void componentHidden(ComponentEvent e) {
774 }
775
776 @Override
777 public void componentMoved(ComponentEvent e) {
778 handleComponentEvent(e);
779 }
780
781 @Override
782 public void componentResized(ComponentEvent e) {
783 handleComponentEvent(e);
784 }
785
786 @Override
787 public void componentShown(ComponentEvent e) {
788 }
789
790 private void handleComponentEvent(ComponentEvent e) {
791 Component c = e.getComponent();
792 if (c instanceof JFrame && c.isVisible() && Main.windowState == JFrame.NORMAL) {
793 Main.geometry = new WindowGeometry((JFrame) c);
794 }
795 }
796 }
797 public static void addListener() {
798 parent.addComponentListener(new WindowPositionSizeListener());
799 ((JFrame)parent).addWindowStateListener(new WindowPositionSizeListener());
800 }
801
802 public static void checkJava6() {
803 String version = System.getProperty("java.version");
804 if (version != null) {
805 if (version.startsWith("1.6") || version.startsWith("6") ||
806 version.startsWith("1.7") || version.startsWith("7"))
807 return;
808 if (version.startsWith("1.5") || version.startsWith("5")) {
809 JLabel ho = new JLabel("<html>"+
810 tr("<h2>JOSM requires Java version 6.</h2>"+
811 "Detected Java version: {0}.<br>"+
812 "You can <ul><li>update your Java (JRE) or</li>"+
813 "<li>use an earlier (Java 5 compatible) version of JOSM.</li></ul>"+
814 "More Info:", version)+"</html>");
815 JTextArea link = new JTextArea("http://josm.openstreetmap.de/wiki/Help/SystemRequirements");
816 link.setEditable(false);
817 link.setBackground(panel.getBackground());
818 JPanel panel = new JPanel(new GridBagLayout());
819 GridBagConstraints gbc = new GridBagConstraints();
820 gbc.gridwidth = GridBagConstraints.REMAINDER;
821 gbc.anchor = GridBagConstraints.WEST;
822 gbc.weightx = 1.0;
823 panel.add(ho, gbc);
824 panel.add(link, gbc);
825 final String EXIT = tr("Exit JOSM");
826 final String CONTINUE = tr("Continue, try anyway");
827 int ret = JOptionPane.showOptionDialog(null, panel, tr("Error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, new String[] {EXIT, CONTINUE}, EXIT);
828 if (ret == 0) {
829 System.exit(0);
830 }
831 return;
832 }
833 }
834 System.err.println("Error: Could not recognize Java Version: "+version);
835 }
836
837 /* ----------------------------------------------------------------------------------------- */
838 /* projection handling - Main is a registry for a single, global projection instance */
839 /* */
840 /* TODO: For historical reasons the registry is implemented by Main. An alternative approach */
841 /* would be a singleton org.openstreetmap.josm.data.projection.ProjectionRegistry class. */
842 /* ----------------------------------------------------------------------------------------- */
843 /**
844 * The projection method used.
845 * use {@link #getProjection()} and {@link #setProjection(Projection)} for access.
846 * Use {@link #setProjection(Projection)} in order to trigger a projection change event.
847 */
848 private static Projection proj;
849
850 /**
851 * Replies the current projection.
852 *
853 * @return the currently active projection
854 */
855 public static Projection getProjection() {
856 return proj;
857 }
858
859 /**
860 * Sets the current projection
861 *
862 * @param p the projection
863 */
864 public static void setProjection(Projection p) {
865 CheckParameterUtil.ensureParameterNotNull(p);
866 Projection oldValue = proj;
867 Bounds b = isDisplayingMapView() ? map.mapView.getRealBounds() : null;
868 proj = p;
869 fireProjectionChanged(oldValue, proj, b);
870 }
871
872 /*
873 * Keep WeakReferences to the listeners. This relieves clients from the burden of
874 * explicitly removing the listeners and allows us to transparently register every
875 * created dataset as projection change listener.
876 */
877 private static final ArrayList<WeakReference<ProjectionChangeListener>> listeners = new ArrayList<WeakReference<ProjectionChangeListener>>();
878
879 private static void fireProjectionChanged(Projection oldValue, Projection newValue, Bounds oldBounds) {
880 if (newValue == null ^ oldValue == null
881 || (newValue != null && oldValue != null && !Utils.equal(newValue.toCode(), oldValue.toCode()))) {
882
883 synchronized(Main.class) {
884 Iterator<WeakReference<ProjectionChangeListener>> it = listeners.iterator();
885 while(it.hasNext()){
886 WeakReference<ProjectionChangeListener> wr = it.next();
887 ProjectionChangeListener listener = wr.get();
888 if (listener == null) {
889 it.remove();
890 continue;
891 }
892 listener.projectionChanged(oldValue, newValue);
893 }
894 }
895 if (newValue != null && oldBounds != null) {
896 Main.map.mapView.zoomTo(oldBounds);
897 }
898 /* TODO - remove layers with fixed projection */
899 }
900 }
901
902 /**
903 * Register a projection change listener
904 *
905 * @param listener the listener. Ignored if <code>null</code>.
906 */
907 public static void addProjectionChangeListener(ProjectionChangeListener listener) {
908 if (listener == null) return;
909 synchronized (Main.class) {
910 for (WeakReference<ProjectionChangeListener> wr : listeners) {
911 // already registered ? => abort
912 if (wr.get() == listener) return;
913 }
914 listeners.add(new WeakReference<ProjectionChangeListener>(listener));
915 }
916 }
917
918 /**
919 * Removes a projection change listener
920 *
921 * @param listener the listener. Ignored if <code>null</code>.
922 */
923 public static void removeProjectionChangeListener(ProjectionChangeListener listener) {
924 if (listener == null) return;
925 synchronized(Main.class){
926 Iterator<WeakReference<ProjectionChangeListener>> it = listeners.iterator();
927 while(it.hasNext()){
928 WeakReference<ProjectionChangeListener> wr = it.next();
929 // remove the listener - and any other listener which god garbage
930 // collected in the meantime
931 if (wr.get() == null || wr.get() == listener) {
932 it.remove();
933 }
934 }
935 }
936 }
937}
Note: See TracBrowser for help on using the repository browser.