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

Revision 5240, 32.9 KB checked in by simon04, 2 days ago (diff)

fix #7687 - make --download= work with signs in bounds

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