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

Last change on this file since 14134 was 14134, checked in by Don-vip, 4 months ago

see #15229 - deprecate Main*.undoRedo - make UndoRedoHandler a singleton

  • Property svn:eol-style set to native
File size: 17.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.io.IOException;
8import java.net.URL;
9import java.nio.file.InvalidPathException;
10import java.util.Collection;
11import java.util.Collections;
12import java.util.List;
13import java.util.Map;
14import java.util.Set;
15import java.util.concurrent.Callable;
16import java.util.concurrent.ExecutionException;
17import java.util.concurrent.ExecutorService;
18import java.util.concurrent.Executors;
19import java.util.concurrent.Future;
20
21import org.openstreetmap.josm.data.Preferences;
22import org.openstreetmap.josm.data.UndoRedoHandler;
23import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
24import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
25import org.openstreetmap.josm.data.coor.conversion.ICoordinateFormat;
26import org.openstreetmap.josm.data.osm.DataSet;
27import org.openstreetmap.josm.data.osm.IPrimitive;
28import org.openstreetmap.josm.data.osm.OsmData;
29import org.openstreetmap.josm.data.osm.OsmPrimitive;
30import org.openstreetmap.josm.data.preferences.JosmBaseDirectories;
31import org.openstreetmap.josm.data.projection.Projection;
32import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
33import org.openstreetmap.josm.data.projection.ProjectionRegistry;
34import org.openstreetmap.josm.io.FileWatcher;
35import org.openstreetmap.josm.io.NetworkManager;
36import org.openstreetmap.josm.io.OnlineResource;
37import org.openstreetmap.josm.spi.lifecycle.InitializationTask;
38import org.openstreetmap.josm.spi.preferences.Config;
39import org.openstreetmap.josm.spi.preferences.IUrls;
40import org.openstreetmap.josm.tools.ImageProvider;
41import org.openstreetmap.josm.tools.JosmRuntimeException;
42import org.openstreetmap.josm.tools.Logging;
43import org.openstreetmap.josm.tools.Platform;
44import org.openstreetmap.josm.tools.PlatformHook;
45import org.openstreetmap.josm.tools.PlatformHookOsx;
46import org.openstreetmap.josm.tools.PlatformHookWindows;
47import org.openstreetmap.josm.tools.Utils;
48import org.openstreetmap.josm.tools.bugreport.BugReport;
49
50/**
51 * Abstract class holding various static global variables and methods used in large parts of JOSM application.
52 * @since 98
53 */
54public abstract class Main {
55
56    /**
57     * Global parent component for all dialogs and message boxes
58     */
59    public static Component parent;
60
61    /**
62     * Global application.
63     */
64    public static volatile Main main;
65
66    /**
67     * Global application preferences
68     */
69    public static final Preferences pref = new Preferences(JosmBaseDirectories.getInstance());
70
71    /**
72     * The commands undo/redo handler.
73     * @deprecated Use {@link UndoRedoHandler#getInstance}
74     */
75    @Deprecated
76    public final UndoRedoHandler undoRedo = UndoRedoHandler.getInstance();
77
78    /**
79     * The file watcher service.
80     * @deprecated Use {@link FileWatcher#getDefaultInstance}
81     */
82    @Deprecated
83    public static final FileWatcher fileWatcher = FileWatcher.getDefaultInstance();
84
85    /**
86     * Platform specific code goes in here.
87     * Plugins may replace it, however, some hooks will be called before any plugins have been loaded.
88     * So if you need to hook into those early ones, split your class and send the one with the early hooks
89     * to the JOSM team for inclusion.
90     */
91    public static volatile PlatformHook platform;
92
93    /**
94     * Constructs new {@code Main} object.
95     * @see #initialize()
96     */
97    protected Main() {
98        setInstance(this);
99    }
100
101    private static void setInstance(Main instance) {
102        main = instance;
103    }
104
105    /**
106     * Initializes the main object. A lot of global variables are initialized here.
107     * @since 10340
108     */
109    public void initialize() {
110        // Initializes tasks that must be run before parallel tasks
111        runInitializationTasks(beforeInitializationTasks());
112
113        // Initializes tasks to be executed (in parallel) by a ExecutorService
114        try {
115            ExecutorService service = Executors.newFixedThreadPool(
116                    Runtime.getRuntime().availableProcessors(), Utils.newThreadFactory("main-init-%d", Thread.NORM_PRIORITY));
117            for (Future<Void> i : service.invokeAll(parallelInitializationTasks())) {
118                i.get();
119            }
120            // asynchronous initializations to be completed eventually
121            asynchronousRunnableTasks().forEach(service::submit);
122            asynchronousCallableTasks().forEach(service::submit);
123            try {
124                service.shutdown();
125            } catch (SecurityException e) {
126                Logging.log(Logging.LEVEL_ERROR, "Unable to shutdown executor service", e);
127            }
128        } catch (InterruptedException | ExecutionException ex) {
129            throw new JosmRuntimeException(ex);
130        }
131
132        // Initializes tasks that must be run after parallel tasks
133        runInitializationTasks(afterInitializationTasks());
134    }
135
136    private static void runInitializationTasks(List<InitializationTask> tasks) {
137        for (InitializationTask task : tasks) {
138            try {
139                task.call();
140            } catch (JosmRuntimeException e) {
141                // Can happen if the current projection needs NTV2 grid which is not available
142                // In this case we want the user be able to change his projection
143                BugReport.intercept(e).warn();
144            }
145        }
146    }
147
148    /**
149     * Returns tasks that must be run before parallel tasks.
150     * @return tasks that must be run before parallel tasks
151     * @see #afterInitializationTasks
152     * @see #parallelInitializationTasks
153     */
154    protected List<InitializationTask> beforeInitializationTasks() {
155        return Collections.emptyList();
156    }
157
158    /**
159     * Returns tasks to be executed (in parallel) by a ExecutorService.
160     * @return tasks to be executed (in parallel) by a ExecutorService
161     */
162    protected Collection<InitializationTask> parallelInitializationTasks() {
163        return Collections.emptyList();
164    }
165
166    /**
167     * Returns asynchronous callable initializations to be completed eventually
168     * @return asynchronous callable initializations to be completed eventually
169     */
170    protected List<Callable<?>> asynchronousCallableTasks() {
171        return Collections.emptyList();
172    }
173
174    /**
175     * Returns asynchronous runnable initializations to be completed eventually
176     * @return asynchronous runnable initializations to be completed eventually
177     */
178    protected List<Runnable> asynchronousRunnableTasks() {
179        return Collections.emptyList();
180    }
181
182    /**
183     * Returns tasks that must be run after parallel tasks.
184     * @return tasks that must be run after parallel tasks
185     * @see #beforeInitializationTasks
186     * @see #parallelInitializationTasks
187     */
188    protected List<InitializationTask> afterInitializationTasks() {
189        return Collections.emptyList();
190    }
191
192    /**
193     * Replies the current selected OSM primitives, from a end-user point of view.
194     * It is not always technically the same collection of primitives than {@link DataSet#getSelected()}.
195     * @return The current selected OSM primitives, from a end-user point of view. Can be {@code null}.
196     * @since 6546
197     */
198    public Collection<OsmPrimitive> getInProgressSelection() {
199        return Collections.emptyList();
200    }
201
202    /**
203     * Replies the current selected primitives, from a end-user point of view.
204     * It is not always technically the same collection of primitives than {@link OsmData#getSelected()}.
205     * @return The current selected primitives, from a end-user point of view. Can be {@code null}.
206     * @since 13926
207     */
208    public Collection<? extends IPrimitive> getInProgressISelection() {
209        return Collections.emptyList();
210    }
211
212    /**
213     * Gets the active edit data set (not read-only).
214     * @return That data set, <code>null</code>.
215     * @see #getActiveDataSet
216     * @since 12691
217     */
218    public abstract DataSet getEditDataSet();
219
220    /**
221     * Gets the active data set (can be read-only).
222     * @return That data set, <code>null</code>.
223     * @see #getEditDataSet
224     * @since 13434
225     */
226    public abstract DataSet getActiveDataSet();
227
228    /**
229     * Sets the active data set (and also edit data set if not read-only).
230     * @param ds New data set, or <code>null</code>
231     * @since 13434
232     */
233    public abstract void setActiveDataSet(DataSet ds);
234
235    /**
236     * Determines if the list of data sets managed by JOSM contains {@code ds}.
237     * @param ds the data set to look for
238     * @return {@code true} if the list of data sets managed by JOSM contains {@code ds}
239     * @since 12718
240     */
241    public abstract boolean containsDataSet(DataSet ds);
242
243    ///////////////////////////////////////////////////////////////////////////
244    //  Implementation part
245    ///////////////////////////////////////////////////////////////////////////
246
247    /**
248     * Should be called before the main constructor to setup some parameter stuff
249     */
250    public static void preConstructorInit() {
251        // init default coordinate format
252        ICoordinateFormat fmt = CoordinateFormatManager.getCoordinateFormat(Config.getPref().get("coordinates"));
253        if (fmt == null) {
254            fmt = DecimalDegreesCoordinateFormat.INSTANCE;
255        }
256        CoordinateFormatManager.setCoordinateFormat(fmt);
257    }
258
259    /**
260     * Closes JOSM and optionally terminates the Java Virtual Machine (JVM).
261     * @param exit If {@code true}, the JVM is terminated by running {@link System#exit} with a given return code.
262     * @param exitCode The return code
263     * @return {@code true}
264     * @since 12636
265     */
266    public static boolean exitJosm(boolean exit, int exitCode) {
267        if (Main.main != null) {
268            Main.main.shutdown();
269        }
270
271        if (exit) {
272            System.exit(exitCode);
273        }
274        return true;
275    }
276
277    /**
278     * Shutdown JOSM.
279     */
280    protected void shutdown() {
281        ImageProvider.shutdown(false);
282        try {
283            pref.saveDefaults();
284        } catch (IOException | InvalidPathException ex) {
285            Logging.log(Logging.LEVEL_WARN, tr("Failed to save default preferences."), ex);
286        }
287        ImageProvider.shutdown(true);
288    }
289
290    /**
291     * Identifies the current operating system family and initializes the platform hook accordingly.
292     * @since 1849
293     */
294    public static void determinePlatformHook() {
295        platform = Platform.determinePlatform().accept(PlatformHook.CONSTRUCT_FROM_PLATFORM);
296    }
297
298    /**
299     * Replies the current projection.
300     *
301     * @return the currently active projection
302     * @deprecated Use {@link ProjectionRegistry#getProjection}
303     */
304    @Deprecated
305    public static Projection getProjection() {
306        return ProjectionRegistry.getProjection();
307    }
308
309    /**
310     * Sets the current projection
311     *
312     * @param p the projection
313     * @deprecated Use {@link ProjectionRegistry#setProjection}
314     */
315    @Deprecated
316    public static void setProjection(Projection p) {
317        ProjectionRegistry.setProjection(p);
318    }
319
320    /**
321     * Register a projection change listener.
322     * The listener is registered to be weak, so keep a reference of it if you want it to be preserved.
323     *
324     * @param listener the listener. Ignored if <code>null</code>.
325     * @deprecated Use {@link ProjectionRegistry#addProjectionChangeListener}
326     */
327    @Deprecated
328    public static void addProjectionChangeListener(ProjectionChangeListener listener) {
329        ProjectionRegistry.addProjectionChangeListener(listener);
330    }
331
332    /**
333     * Removes a projection change listener.
334     *
335     * @param listener the listener. Ignored if <code>null</code>.
336     * @deprecated Use {@link ProjectionRegistry#removeProjectionChangeListener}
337     */
338    @Deprecated
339    public static void removeProjectionChangeListener(ProjectionChangeListener listener) {
340        ProjectionRegistry.removeProjectionChangeListener(listener);
341    }
342
343    /**
344     * Remove all projection change listeners. For testing purposes only.
345     * @since 13322
346     * @deprecated Use {@link ProjectionRegistry#clearProjectionChangeListeners}
347     */
348    @Deprecated
349    public static void clearProjectionChangeListeners() {
350        ProjectionRegistry.clearProjectionChangeListeners();
351    }
352
353    /**
354     * Adds a new network error that occur to give a hint about broken Internet connection.
355     * Do not use this method for errors known for sure thrown because of a bad proxy configuration.
356     *
357     * @param url The accessed URL that caused the error
358     * @param t The network error
359     * @return The previous error associated to the given resource, if any. Can be {@code null}
360     * @deprecated Use {@link NetworkManager#addNetworkError(URL, Throwable)}
361     * @since 6642
362     */
363    @Deprecated
364    public static Throwable addNetworkError(URL url, Throwable t) {
365        return NetworkManager.addNetworkError(url, t);
366    }
367
368    /**
369     * Adds a new network error that occur to give a hint about broken Internet connection.
370     * Do not use this method for errors known for sure thrown because of a bad proxy configuration.
371     *
372     * @param url The accessed URL that caused the error
373     * @param t The network error
374     * @return The previous error associated to the given resource, if any. Can be {@code null}
375     * @deprecated Use {@link NetworkManager#addNetworkError(String, Throwable)}
376     * @since 6642
377     */
378    @Deprecated
379    public static Throwable addNetworkError(String url, Throwable t) {
380        return NetworkManager.addNetworkError(url, t);
381    }
382
383    /**
384     * Returns the network errors that occured until now.
385     * @return the network errors that occured until now, indexed by URL
386     * @deprecated Use {@link NetworkManager#getNetworkErrors}
387     * @since 6639
388     */
389    @Deprecated
390    public static Map<String, Throwable> getNetworkErrors() {
391        return NetworkManager.getNetworkErrors();
392    }
393
394    /**
395     * Clears the network errors cache.
396     * @deprecated Use {@link NetworkManager#clearNetworkErrors}
397     * @since 12011
398     */
399    @Deprecated
400    public static void clearNetworkErrors() {
401        NetworkManager.clearNetworkErrors();
402    }
403
404    /**
405     * Returns the JOSM website URL.
406     * @return the josm website URL
407     * @deprecated Use {@link IUrls#getJOSMWebsite}
408     * @since 6897
409     */
410    @Deprecated
411    public static String getJOSMWebsite() {
412        return Config.getUrls().getJOSMWebsite();
413    }
414
415    /**
416     * Returns the JOSM XML URL.
417     * @return the josm XML URL
418     * @deprecated Use {@link IUrls#getXMLBase}
419     * @since 6897
420     */
421    @Deprecated
422    public static String getXMLBase() {
423        return Config.getUrls().getXMLBase();
424    }
425
426    /**
427     * Returns the OSM website URL.
428     * @return the OSM website URL
429     * @deprecated Use {@link IUrls#getOSMWebsite}
430     * @since 6897
431     */
432    @Deprecated
433    public static String getOSMWebsite() {
434        return Config.getUrls().getOSMWebsite();
435    }
436
437    /**
438     * Replies the base URL for browsing information about a primitive.
439     * @return the base URL, i.e. https://www.openstreetmap.org
440     * @deprecated Use {@link IUrls#getBaseBrowseUrl}
441     * @since 7678
442     */
443    @Deprecated
444    public static String getBaseBrowseUrl() {
445        return Config.getUrls().getBaseBrowseUrl();
446    }
447
448    /**
449     * Replies the base URL for browsing information about a user.
450     * @return the base URL, i.e. https://www.openstreetmap.org/user
451     * @deprecated Use {@link IUrls#getBaseUserUrl}
452     * @since 7678
453     */
454    @Deprecated
455    public static String getBaseUserUrl() {
456        return Config.getUrls().getBaseUserUrl();
457    }
458
459    /**
460     * Determines if we are currently running on OSX.
461     * @return {@code true} if we are currently running on OSX
462     * @since 6957
463     */
464    public static boolean isPlatformOsx() {
465        return Main.platform instanceof PlatformHookOsx;
466    }
467
468    /**
469     * Determines if we are currently running on Windows.
470     * @return {@code true} if we are currently running on Windows
471     * @since 7335
472     */
473    public static boolean isPlatformWindows() {
474        return Main.platform instanceof PlatformHookWindows;
475    }
476
477    /**
478     * Determines if the given online resource is currently offline.
479     * @param r the online resource
480     * @return {@code true} if {@code r} is offline and should not be accessed
481     * @deprecated Use {@link NetworkManager#isOffline}
482     * @since 7434
483     */
484    @Deprecated
485    public static boolean isOffline(OnlineResource r) {
486        return NetworkManager.isOffline(r);
487    }
488
489    /**
490     * Sets the given online resource to offline state.
491     * @param r the online resource
492     * @return {@code true} if {@code r} was not already offline
493     * @deprecated Use {@link NetworkManager#setOffline}
494     * @since 7434
495     */
496    @Deprecated
497    public static boolean setOffline(OnlineResource r) {
498        return NetworkManager.setOffline(r);
499    }
500
501    /**
502     * Sets the given online resource to online state.
503     * @param r the online resource
504     * @return {@code true} if {@code r} was offline
505     * @deprecated Use {@link NetworkManager#setOnline}
506     * @since 8506
507     */
508    @Deprecated
509    public static boolean setOnline(OnlineResource r) {
510        return NetworkManager.setOnline(r);
511    }
512
513    /**
514     * Replies the set of online resources currently offline.
515     * @return the set of online resources currently offline
516     * @deprecated Use {@link NetworkManager#getOfflineResources}
517     * @since 7434
518     */
519    @Deprecated
520    public static Set<OnlineResource> getOfflineResources() {
521        return NetworkManager.getOfflineResources();
522    }
523}
Note: See TracBrowser for help on using the repository browser.