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

Revision 4908, 34.8 KB checked in by simon04, 4 days ago (diff)

fix #7327 - show hint in undo-menu which action will be undone (from event stack)

  • 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.Dimension;
8import java.awt.GridBagConstraints;
9import java.awt.GridBagLayout;
10import java.awt.Rectangle;
11import java.awt.Toolkit;
12import java.awt.event.ComponentEvent;
13import java.awt.event.ComponentListener;
14import java.awt.event.KeyEvent;
15import java.awt.event.WindowAdapter;
16import java.awt.event.WindowEvent;
17import java.io.File;
18import java.lang.ref.WeakReference;
19import java.net.URI;
20import java.net.URISyntaxException;
21import java.util.ArrayList;
22import java.util.Collection;
23import java.util.Iterator;
24import java.util.List;
25import java.util.Map;
26import java.util.StringTokenizer;
27import java.util.concurrent.ExecutorService;
28import java.util.concurrent.Future;
29import java.util.regex.Matcher;
30import java.util.regex.Pattern;
31
32import javax.swing.Action;
33import javax.swing.InputMap;
34import javax.swing.JComponent;
35import javax.swing.JFrame;
36import javax.swing.JLabel;
37import javax.swing.JOptionPane;
38import javax.swing.JPanel;
39import javax.swing.JTextArea;
40import javax.swing.KeyStroke;
41import javax.swing.UIManager;
42
43import org.openstreetmap.gui.jmapviewer.FeatureAdapter;
44import org.openstreetmap.josm.actions.JosmAction;
45import org.openstreetmap.josm.actions.OpenFileAction;
46import org.openstreetmap.josm.actions.downloadtasks.DownloadGpsTask;
47import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
48import org.openstreetmap.josm.actions.downloadtasks.DownloadTask;
49import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
50import org.openstreetmap.josm.actions.mapmode.MapMode;
51import org.openstreetmap.josm.actions.search.SearchAction;
52import org.openstreetmap.josm.data.Bounds;
53import org.openstreetmap.josm.data.Preferences;
54import org.openstreetmap.josm.data.UndoRedoHandler;
55import org.openstreetmap.josm.data.coor.CoordinateFormat;
56import org.openstreetmap.josm.data.coor.LatLon;
57import org.openstreetmap.josm.data.osm.DataSet;
58import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
59import org.openstreetmap.josm.data.projection.Projection;
60import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
61import org.openstreetmap.josm.data.validation.OsmValidator;
62import org.openstreetmap.josm.gui.GettingStarted;
63import org.openstreetmap.josm.gui.MainMenu;
64import org.openstreetmap.josm.gui.MapFrame;
65import org.openstreetmap.josm.gui.MapView;
66import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
67import org.openstreetmap.josm.gui.io.SaveLayersDialog;
68import org.openstreetmap.josm.gui.layer.Layer;
69import org.openstreetmap.josm.gui.layer.OsmDataLayer;
70import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
71import org.openstreetmap.josm.gui.preferences.ImageryPreference;
72import org.openstreetmap.josm.gui.preferences.MapPaintPreference;
73import org.openstreetmap.josm.gui.preferences.ProjectionPreference;
74import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
75import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
76import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
77import org.openstreetmap.josm.gui.progress.ProgressMonitorExecutor;
78import org.openstreetmap.josm.gui.util.RedirectInputMap;
79import org.openstreetmap.josm.io.OsmApi;
80import org.openstreetmap.josm.plugins.PluginHandler;
81import org.openstreetmap.josm.tools.CheckParameterUtil;
82import org.openstreetmap.josm.tools.I18n;
83import org.openstreetmap.josm.tools.ImageProvider;
84import org.openstreetmap.josm.tools.OpenBrowser;
85import org.openstreetmap.josm.tools.OsmUrlToBounds;
86import org.openstreetmap.josm.tools.PlatformHook;
87import org.openstreetmap.josm.tools.PlatformHookOsx;
88import org.openstreetmap.josm.tools.PlatformHookUnixoid;
89import org.openstreetmap.josm.tools.PlatformHookWindows;
90import org.openstreetmap.josm.tools.Shortcut;
91import org.openstreetmap.josm.tools.Utils;
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 true 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     * True, 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 final MainMenu menu;
153
154    public final OsmValidator validator;
155    /**
156     * The MOTD Layer.
157     */
158    private GettingStarted gettingStarted = new GettingStarted();
159
160    /**
161     * Print a message if logging is on.
162     */
163    static public int log_level = 2;
164    static public void warn(String msg) {
165        if (log_level < 1)
166            return;
167        System.out.println(msg);
168    }
169    static public void info(String msg) {
170        if (log_level < 2)
171            return;
172        System.out.println(msg);
173    }
174    static public void debug(String msg) {
175        if (log_level < 3)
176            return;
177        System.out.println(msg);
178    }
179
180    /**
181     * Platform specific code goes in here.
182     * Plugins may replace it, however, some hooks will be called before any plugins have been loeaded.
183     * So if you need to hook into those early ones, split your class and send the one with the early hooks
184     * to the JOSM team for inclusion.
185     */
186    public static PlatformHook platform;
187
188    /**
189     * Wheather or not the java vm is openjdk
190     * We use this to work around openjdk bugs
191     */
192    public static boolean isOpenjdk;
193
194    /**
195     * Set or clear (if passed <code>null</code>) the map.
196     */
197    public final void setMapFrame(final MapFrame map) {
198        MapFrame old = Main.map;
199        panel.setVisible(false);
200        panel.removeAll();
201        if (map != null) {
202            map.fillPanel(panel);
203        } else {
204            old.destroy();
205            panel.add(gettingStarted, BorderLayout.CENTER);
206        }
207        panel.setVisible(true);
208        redoUndoListener.commandChanged(0,0);
209
210        Main.map = map;
211
212        PluginHandler.notifyMapFrameChanged(old, map);
213        if (map == null && currentProgressMonitor != null) {
214            currentProgressMonitor.showForegroundDialog();
215        }
216    }
217
218    /**
219     * Remove the specified layer from the map. If it is the last layer,
220     * remove the map as well.
221     */
222    public final void removeLayer(final Layer layer) {
223        if (map != null) {
224            map.mapView.removeLayer(layer);
225            if (map != null && map.mapView.getAllLayers().isEmpty()) {
226                setMapFrame(null);
227            }
228        }
229    }
230
231    private static InitStatusListener initListener = null;
232
233    public static interface InitStatusListener {
234
235        void updateStatus(String event);
236    }
237
238    public static void setInitStatusListener(InitStatusListener listener) {
239        initListener = listener;
240    }
241
242    public Main() {
243        main = this;
244        isOpenjdk = System.getProperty("java.vm.name").toUpperCase().indexOf("OPENJDK") != -1;
245
246        if (initListener != null) {
247            initListener.updateStatus(tr("Executing platform startup hook"));
248        }
249        platform.startupHook();
250
251        // We try to establish an API connection early, so that any API
252        // capabilities are already known to the editor instance. However
253        // if it goes wrong that's not critical at this stage.
254        if (initListener != null) {
255            initListener.updateStatus(tr("Initializing OSM API"));
256        }
257        try {
258            OsmApi.getOsmApi().initialize(null, true);
259        } catch (Exception x) {
260            // ignore any exception here.
261        }
262
263        if (initListener != null) {
264            initListener.updateStatus(tr("Building main menu"));
265        }
266        contentPanePrivate.add(panel, BorderLayout.CENTER);
267        panel.add(gettingStarted, BorderLayout.CENTER);
268        menu = new MainMenu();
269
270        undoRedo.addCommandQueueListener(redoUndoListener);
271
272        // creating toolbar
273        contentPanePrivate.add(toolbar.control, BorderLayout.NORTH);
274
275        registerActionShortcut(menu.help, Shortcut.registerShortcut("system:help", tr("Help"),
276                KeyEvent.VK_F1, Shortcut.GROUP_DIRECT));
277
278        if (initListener != null) {
279            initListener.updateStatus(tr("Initializing presets"));
280        }
281        TaggingPresetPreference.initialize();
282
283        if (initListener != null) {
284            initListener.updateStatus(tr("Initializing map styles"));
285        }
286        MapPaintPreference.initialize();
287
288        if (initListener != null) {
289            initListener.updateStatus(tr("Loading imagery preferences"));
290        }
291        ImageryPreference.initialize();
292
293        if (initListener != null) {
294            initListener.updateStatus(tr("Initializing validator"));
295        }
296        validator = new OsmValidator();
297        MapView.addLayerChangeListener(validator);
298
299        // hooks for the jmapviewer component
300        FeatureAdapter.registerBrowserAdapter(new FeatureAdapter.BrowserAdapter() {
301            @Override
302            public void openLink(String url) {
303                OpenBrowser.displayUrl(url);
304            }
305        });
306        FeatureAdapter.registerTranslationAdapter(I18n.getTranslationAdapter());
307
308        if (initListener != null) {
309            initListener.updateStatus(tr("Updating user interface"));
310        }
311
312        toolbar.refreshToolbarControl();
313
314        toolbar.control.updateUI();
315        contentPanePrivate.updateUI();
316
317    }
318
319    /**
320     * Add a new layer to the map. If no map exists, create one.
321     */
322    public final void addLayer(final Layer layer) {
323        if (map == null) {
324            final MapFrame mapFrame = new MapFrame(contentPanePrivate);
325            setMapFrame(mapFrame);
326            mapFrame.selectMapMode((MapMode)mapFrame.getDefaultButtonAction(), layer);
327            mapFrame.setVisible(true);
328            mapFrame.initializeDialogsPane();
329            // bootstrapping problem: make sure the layer list dialog is going to
330            // listen to change events of the very first layer
331            //
332            layer.addPropertyChangeListener(LayerListDialog.getInstance().getModel());
333        }
334        map.mapView.addLayer(layer);
335    }
336
337    /**
338     * Replies true if there is an edit layer
339     *
340     * @return true if there is an edit layer
341     */
342    public boolean hasEditLayer() {
343        if (getEditLayer() == null) return false;
344        return true;
345    }
346
347    /**
348     * Replies the current edit layer
349     *
350     * @return the current edit layer. null, if no current edit layer exists
351     */
352    public OsmDataLayer getEditLayer() {
353        if (map == null) return null;
354        if (map.mapView == null) return null;
355        return map.mapView.getEditLayer();
356    }
357
358    /**
359     * Replies the current data set.
360     *
361     * @return the current data set. null, if no current data set exists
362     */
363    public DataSet getCurrentDataSet() {
364        if (!hasEditLayer()) return null;
365        return getEditLayer().data;
366    }
367
368    /**
369     * Returns the currently active  layer
370     *
371     * @return the currently active layer. null, if currently no active layer exists
372     */
373    public Layer getActiveLayer() {
374        if (map == null) return null;
375        if (map.mapView == null) return null;
376        return map.mapView.getActiveLayer();
377    }
378
379    protected static final JPanel contentPanePrivate = new JPanel(new BorderLayout());
380
381    public static void redirectToMainContentPane(JComponent source) {
382        RedirectInputMap.redirect(source, contentPanePrivate);
383    }
384
385    public static void registerActionShortcut(Action action, Shortcut shortcut) {
386        registerActionShortcut(action, shortcut.getKeyStroke());
387    }
388
389    public static void registerActionShortcut(Action action, KeyStroke keyStroke) {
390        if (keyStroke == null)
391            return;
392
393        InputMap inputMap = contentPanePrivate.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
394        Object existing = inputMap.get(keyStroke);
395        if (existing != null && !existing.equals(action)) {
396            System.out.println(String.format("Keystroke %s is already assigned to %s, will be overridden by %s", keyStroke, existing, action));
397        }
398        inputMap.put(keyStroke, action);
399
400        contentPanePrivate.getActionMap().put(action, action);
401    }
402
403    public static void unregisterActionShortcut(Shortcut shortcut) {
404        contentPanePrivate.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(shortcut.getKeyStroke());
405    }
406
407    public static void unregisterActionShortcut(JosmAction action) {
408        unregisterActionShortcut(action, action.getShortcut());
409    }
410
411    public static void unregisterActionShortcut(Action action, Shortcut shortcut) {
412        contentPanePrivate.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(shortcut.getKeyStroke());
413        contentPanePrivate.getActionMap().remove(action);
414    }
415
416
417    ///////////////////////////////////////////////////////////////////////////
418    //  Implementation part
419    ///////////////////////////////////////////////////////////////////////////
420
421    public static final JPanel panel = new JPanel(new BorderLayout());
422
423    protected static Rectangle bounds;
424    protected static int windowState = JFrame.NORMAL;
425
426    private final CommandQueueListener redoUndoListener = new CommandQueueListener(){
427        public void commandChanged(final int queueSize, final int redoSize) {
428            menu.undo.setEnabled(queueSize > 0);
429            menu.redo.setEnabled(redoSize > 0);
430        }
431    };
432
433    /**
434     * Should be called before the main constructor to setup some parameter stuff
435     * @param args The parsed argument list.
436     */
437    public static void preConstructorInit(Map<String, Collection<String>> args) {
438        ProjectionPreference.setProjection();
439
440        try {
441            String defaultlaf = platform.getDefaultStyle();
442            String laf = Main.pref.get("laf", defaultlaf);
443            try {
444                UIManager.setLookAndFeel(laf);
445            }
446            catch (final java.lang.ClassNotFoundException e) {
447                System.out.println("Look and Feel not found: " + laf);
448                Main.pref.put("laf", defaultlaf);
449            }
450            catch (final javax.swing.UnsupportedLookAndFeelException e) {
451                System.out.println("Look and Feel not supported: " + laf);
452                Main.pref.put("laf", defaultlaf);
453            }
454            toolbar = new ToolbarPreferences();
455            contentPanePrivate.updateUI();
456            panel.updateUI();
457        } catch (final Exception e) {
458            e.printStackTrace();
459        }
460        UIManager.put("OptionPane.okIcon", ImageProvider.get("ok"));
461        UIManager.put("OptionPane.yesIcon", UIManager.get("OptionPane.okIcon"));
462        UIManager.put("OptionPane.cancelIcon", ImageProvider.get("cancel"));
463        UIManager.put("OptionPane.noIcon", UIManager.get("OptionPane.cancelIcon"));
464
465        I18n.translateJavaInternalMessages();
466
467        // init default coordinate format
468        //
469        try {
470            //CoordinateFormat format = CoordinateFormat.valueOf(Main.pref.get("coordinates"));
471            CoordinateFormat.setCoordinateFormat(CoordinateFormat.valueOf(Main.pref.get("coordinates")));
472        } catch (IllegalArgumentException iae) {
473            CoordinateFormat.setCoordinateFormat(CoordinateFormat.DECIMAL_DEGREES);
474        }
475
476        Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
477        String geometry = null;
478        if (args.containsKey("geometry")) {
479            geometry = args.get("geometry").iterator().next();
480        } else {
481            geometry = Main.pref.get("gui.geometry");
482        }
483        if (geometry.length() != 0) {
484            final Matcher m = Pattern.compile("(\\d+)x(\\d+)(([+-])(\\d+)([+-])(\\d+))?").matcher(geometry);
485            if (m.matches()) {
486                int w = Integer.valueOf(m.group(1));
487                int h = Integer.valueOf(m.group(2));
488                int x = 0, y = 0;
489                if (m.group(3) != null) {
490                    x = Integer.valueOf(m.group(5));
491                    y = Integer.valueOf(m.group(7));
492                    if (m.group(4).equals("-")) {
493                        x = screenDimension.width - x - w;
494                    }
495                    if (m.group(6).equals("-")) {
496                        y = screenDimension.height - y - h;
497                    }
498                }
499                // copied from WindowsGeometry.applySafe()
500                if (x > Toolkit.getDefaultToolkit().getScreenSize().width - 10) {
501                    x = 0;
502                }
503                if (y > Toolkit.getDefaultToolkit().getScreenSize().height - 10) {
504                    y = 0;
505                }
506                bounds = new Rectangle(x,y,w,h);
507                if(!Main.pref.get("gui.geometry").equals(geometry)) {
508                    // remember this geometry
509                    Main.pref.put("gui.geometry", geometry);
510                }
511            } else {
512                System.out.println("Ignoring malformed geometry: "+geometry);
513            }
514        }
515        if (bounds == null) {
516            bounds = !args.containsKey("no-maximize") ? new Rectangle(0,0,screenDimension.width,screenDimension.height) : new Rectangle(1000,740);
517        }
518    }
519
520    public void postConstructorProcessCmdLine(Map<String, Collection<String>> args) {
521        if (args.containsKey("download")) {
522            List<File> fileList = new ArrayList<File>();
523            for (String s : args.get("download")) {
524                File f = null;
525                switch(paramType(s)) {
526                case httpUrl:
527                    downloadFromParamHttp(false, s);
528                    break;
529                case bounds:
530                    downloadFromParamBounds(false, s);
531                    break;
532                case fileUrl:
533                    try {
534                        f = new File(new URI(s));
535                    } catch (URISyntaxException e) {
536                        JOptionPane.showMessageDialog(
537                                Main.parent,
538                                tr("Ignoring malformed file URL: \"{0}\"", s),
539                                tr("Warning"),
540                                JOptionPane.WARNING_MESSAGE
541                                );
542                    }
543                    if (f!=null) {
544                        fileList.add(f);
545                    }
546                    break;
547                case fileName:
548                    f = new File(s);
549                    fileList.add(f);
550                    break;
551                }
552            }
553            if(!fileList.isEmpty())
554            {
555                OpenFileAction.openFiles(fileList, true);
556            }
557        }
558        if (args.containsKey("downloadgps")) {
559            for (String s : args.get("downloadgps")) {
560                switch(paramType(s)) {
561                case httpUrl:
562                    downloadFromParamHttp(true, s);
563                    break;
564                case bounds:
565                    downloadFromParamBounds(true, s);
566                    break;
567                case fileUrl:
568                case fileName:
569                    JOptionPane.showMessageDialog(
570                            Main.parent,
571                            tr("Parameter \"downloadgps\" does not accept file names or file URLs"),
572                            tr("Warning"),
573                            JOptionPane.WARNING_MESSAGE
574                            );
575                }
576            }
577        }
578        if (args.containsKey("selection")) {
579            for (String s : args.get("selection")) {
580                SearchAction.search(s, SearchAction.SearchMode.add);
581            }
582        }
583    }
584
585    public static boolean saveUnsavedModifications() {
586        if (map == null) return true;
587        SaveLayersDialog dialog = new SaveLayersDialog(Main.parent);
588        List<OsmDataLayer> layersWithUnmodifiedChanges = new ArrayList<OsmDataLayer>();
589        for (OsmDataLayer l: Main.map.mapView.getLayersOfType(OsmDataLayer.class)) {
590            if (l.requiresSaveToFile() || l.requiresUploadToServer()) {
591                layersWithUnmodifiedChanges.add(l);
592            }
593        }
594        dialog.prepareForSavingAndUpdatingLayersBeforeExit();
595        if (!layersWithUnmodifiedChanges.isEmpty()) {
596            dialog.getModel().populate(layersWithUnmodifiedChanges);
597            dialog.setVisible(true);
598            switch(dialog.getUserAction()) {
599            case CANCEL: return false;
600            case PROCEED: return true;
601            default: return false;
602            }
603        }
604
605        return true;
606    }
607
608    public static boolean exitJosm(boolean exit) {
609        if (Main.saveUnsavedModifications()) {
610            Main.saveGuiGeometry();
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(final boolean rawGps, String s)
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    static public void saveGuiGeometry() {
717        // save the current window geometry and the width of the toggle dialog area
718        String newGeometry = "";
719        String newToggleDlgWidth = null;
720        try {
721            Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
722            int width = (int)bounds.getWidth();
723            int height = (int)bounds.getHeight();
724            int x = (int)bounds.getX();
725            int y = (int)bounds.getY();
726            if (width > screenDimension.width) {
727                width = screenDimension.width;
728            }
729            if (height > screenDimension.height) {
730                width = screenDimension.height;
731            }
732            if (x < 0) {
733                x = 0;
734            }
735            if (y < 0) {
736                y = 0;
737            }
738            newGeometry = width + "x" + height + "+" + x + "+" + y;
739
740            if (map  != null) {
741                newToggleDlgWidth = Integer.toString(map.getToggleDlgWidth());
742                if (newToggleDlgWidth.equals(Integer.toString(MapFrame.DEF_TOGGLE_DLG_WIDTH))) {
743                    newToggleDlgWidth = "";
744                }
745            }
746        }
747        catch (Exception e) {
748            System.out.println("Failed to get GUI geometry: " + e);
749            e.printStackTrace();
750        }
751        boolean maximized = (windowState & JFrame.MAXIMIZED_BOTH) != 0;
752        // Main.debug("Main window: saving geometry \"" + newGeometry + "\" " + (maximized?"maximized":"normal"));
753        pref.put("gui.maximized", maximized);
754        pref.put("gui.geometry", newGeometry);
755        if (newToggleDlgWidth != null) {
756            pref.put("toggleDialogs.width", newToggleDlgWidth);
757        }
758    }
759    private static class WindowPositionSizeListener extends WindowAdapter implements
760    ComponentListener {
761
762        @Override
763        public void windowStateChanged(WindowEvent e) {
764            Main.windowState = e.getNewState();
765            // Main.debug("Main window state changed to " + Main.windowState);
766        }
767
768        public void componentHidden(ComponentEvent e) {
769        }
770
771        public void componentMoved(ComponentEvent e) {
772            handleComponentEvent(e);
773        }
774
775        public void componentResized(ComponentEvent e) {
776            handleComponentEvent(e);
777        }
778
779        public void componentShown(ComponentEvent e) {
780        }
781
782        private void handleComponentEvent(ComponentEvent e) {
783            Component c = e.getComponent();
784            if (c instanceof JFrame) {
785                if (Main.windowState == JFrame.NORMAL) {
786                    Main.bounds = ((JFrame) c).getBounds();
787                    // Main.debug("Main window: new geometry " + Main.bounds);
788                } else {
789                    // Main.debug("Main window state is " + Main.windowState);
790                }
791            }
792        }
793
794    }
795    public static void addListener() {
796        parent.addComponentListener(new WindowPositionSizeListener());
797        ((JFrame)parent).addWindowStateListener(new WindowPositionSizeListener());
798    }
799
800    public static void checkJava6() {
801        String version = System.getProperty("java.version");
802        if (version != null) {
803            if (version.startsWith("1.6") || version.startsWith("6") ||
804                    version.startsWith("1.7") || version.startsWith("7"))
805                return;
806            if (version.startsWith("1.5") || version.startsWith("5")) {
807                JLabel ho = new JLabel("<html>"+
808                        tr("<h2>JOSM requires Java version 6.</h2>"+
809                                "Detected Java version: {0}.<br>"+
810                                "You can <ul><li>update your Java (JRE) or</li>"+
811                                "<li>use an earlier (Java 5 compatible) version of JOSM.</li></ul>"+
812                                "More Info:", version)+"</html>");
813                JTextArea link = new JTextArea("http://josm.openstreetmap.de/wiki/Help/SystemRequirements");
814                link.setEditable(false);
815                link.setBackground(panel.getBackground());
816                JPanel panel = new JPanel(new GridBagLayout());
817                GridBagConstraints gbc = new GridBagConstraints();
818                gbc.gridwidth = GridBagConstraints.REMAINDER;
819                gbc.anchor = GridBagConstraints.WEST;
820                gbc.weightx = 1.0;
821                panel.add(ho, gbc);
822                panel.add(link, gbc);
823                final String EXIT = tr("Exit JOSM");
824                final String CONTINUE = tr("Continue, try anyway");
825                int ret = JOptionPane.showOptionDialog(null, panel, tr("Error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, new String[] {EXIT, CONTINUE}, EXIT);
826                if (ret == 0) {
827                    System.exit(0);
828                }
829                return;
830            }
831        }
832        System.err.println("Error: Could not recognize Java Version: "+version);
833    }
834
835    /* ----------------------------------------------------------------------------------------- */
836    /* projection handling  - Main is a registry for a single, global projection instance        */
837    /*                                                                                           */
838    /* TODO: For historical reasons the registry is implemented by Main. An alternative approach */
839    /* would be a singleton org.openstreetmap.josm.data.projection.ProjectionRegistry class.     */
840    /* ----------------------------------------------------------------------------------------- */
841    /**
842     * The projection method used.
843     * use {@link #getProjection()} and {@link #setProjection(Projection)} for access.
844     * Use {@link #setProjection(Projection)} in order to trigger a projection change event.
845     */
846    private static Projection proj;
847
848    /**
849     * Replies the current projection.
850     *
851     * @return
852     */
853    public static Projection getProjection() {
854        return proj;
855    }
856
857    /**
858     * Sets the current projection
859     *
860     * @param p the projection
861     */
862    public static void setProjection(Projection p) {
863        CheckParameterUtil.ensureParameterNotNull(p);
864        Projection oldValue = proj;
865        proj = p;
866        fireProjectionChanged(oldValue, proj);
867    }
868
869    /*
870     * Keep WeakReferences to the listeners. This relieves clients from the burden of
871     * explicitly removing the listeners and allows us to transparently register every
872     * created dataset as projection change listener.
873     */
874    private static final ArrayList<WeakReference<ProjectionChangeListener>> listeners = new ArrayList<WeakReference<ProjectionChangeListener>>();
875
876    private static void fireProjectionChanged(Projection oldValue, Projection newValue) {
877        if (newValue == null ^ oldValue == null
878                || (newValue != null && oldValue != null && !Utils.equal(newValue.toCode(), oldValue.toCode()))) {
879
880            synchronized(Main.class) {
881                Iterator<WeakReference<ProjectionChangeListener>> it = listeners.iterator();
882                while(it.hasNext()){
883                    WeakReference<ProjectionChangeListener> wr = it.next();
884                    ProjectionChangeListener listener = wr.get();
885                    if (listener == null) {
886                        it.remove();
887                        continue;
888                    }
889                    listener.projectionChanged(oldValue, newValue);
890                }
891            }
892            if (newValue != null) {
893                Bounds b = (Main.map != null && Main.map.mapView != null) ? Main.map.mapView.getRealBounds() : null;
894                if (b != null){
895                    Main.map.mapView.zoomTo(b);
896                }
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 null.
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 null.
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.