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

Last change on this file since 13037 was 13023, checked in by bastiK, 7 years ago

see #15451 - fix initialization

  • Property svn:eol-style set to native
File size: 37.7 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[626]2package org.openstreetmap.josm;
[5670]3
[301]4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
[11106]7import java.awt.GraphicsEnvironment;
[9821]8import java.io.IOException;
[4126]9import java.lang.ref.WeakReference;
[6471]10import java.net.URL;
[5481]11import java.text.MessageFormat;
[2025]12import java.util.ArrayList;
[301]13import java.util.Collection;
[11986]14import java.util.Collections;
[10044]15import java.util.EnumSet;
[6642]16import java.util.HashMap;
[4126]17import java.util.Iterator;
[2025]18import java.util.List;
[301]19import java.util.Map;
[7083]20import java.util.Objects;
[7434]21import java.util.Set;
[5134]22import java.util.concurrent.Callable;
[10212]23import java.util.concurrent.ExecutionException;
[1465]24import java.util.concurrent.ExecutorService;
[5134]25import java.util.concurrent.Executors;
[2322]26import java.util.concurrent.Future;
[301]27
[3252]28import javax.swing.Action;
[301]29
[3444]30import org.openstreetmap.josm.actions.JosmAction;
[301]31import org.openstreetmap.josm.data.Bounds;
32import org.openstreetmap.josm.data.Preferences;
33import org.openstreetmap.josm.data.UndoRedoHandler;
[12735]34import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
35import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
36import org.openstreetmap.josm.data.coor.conversion.ICoordinateFormat;
[301]37import org.openstreetmap.josm.data.osm.DataSet;
[6546]38import org.openstreetmap.josm.data.osm.OsmPrimitive;
[13023]39import org.openstreetmap.josm.data.preferences.JosmBaseDirectories;
[301]40import org.openstreetmap.josm.data.projection.Projection;
[4126]41import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
[12630]42import org.openstreetmap.josm.gui.MainApplication;
[301]43import org.openstreetmap.josm.gui.MainMenu;
[10432]44import org.openstreetmap.josm.gui.MainPanel;
[301]45import org.openstreetmap.josm.gui.MapFrame;
[5957]46import org.openstreetmap.josm.gui.MapFrameListener;
[10279]47import org.openstreetmap.josm.gui.layer.MainLayerManager;
[301]48import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
[7185]49import org.openstreetmap.josm.io.FileWatcher;
[7434]50import org.openstreetmap.josm.io.OnlineResource;
[3934]51import org.openstreetmap.josm.io.OsmApi;
[12846]52import org.openstreetmap.josm.spi.preferences.Config;
[4126]53import org.openstreetmap.josm.tools.CheckParameterUtil;
[301]54import org.openstreetmap.josm.tools.ImageProvider;
[11374]55import org.openstreetmap.josm.tools.JosmRuntimeException;
[10899]56import org.openstreetmap.josm.tools.Logging;
[12776]57import org.openstreetmap.josm.tools.Platform;
[1023]58import org.openstreetmap.josm.tools.PlatformHook;
[1465]59import org.openstreetmap.josm.tools.PlatformHookOsx;
[1023]60import org.openstreetmap.josm.tools.PlatformHookWindows;
[1084]61import org.openstreetmap.josm.tools.Shortcut;
[4288]62import org.openstreetmap.josm.tools.Utils;
[11642]63import org.openstreetmap.josm.tools.bugreport.BugReport;
[626]64
[5829]65/**
66 * Abstract class holding various static global variables and methods used in large parts of JOSM application.
67 * @since 98
68 */
[6883]69public abstract class Main {
[2485]70
[1104]71 /**
[6143]72 * The JOSM website URL.
[6897]73 * @since 6897 (was public from 6143 to 6896)
[6143]74 */
[6920]75 private static final String JOSM_WEBSITE = "https://josm.openstreetmap.de";
[6453]76
[6143]77 /**
[6453]78 * The OSM website URL.
[6897]79 * @since 6897 (was public from 6453 to 6896)
[6453]80 */
[6920]81 private static final String OSM_WEBSITE = "https://www.openstreetmap.org";
[6453]82
83 /**
[2343]84 * Replies true if JOSM currently displays a map view. False, if it doesn't, i.e. if
85 * it only shows the MOTD panel.
[10288]86 * <p>
87 * You do not need this when accessing the layer manager. The layer manager will be empty if no map view is shown.
[2512]88 *
[5357]89 * @return <code>true</code> if JOSM currently displays a map view
[12630]90 * @deprecated use {@link org.openstreetmap.josm.gui.MainApplication#isDisplayingMapView()}
[2343]91 */
[12630]92 @Deprecated
[6883]93 public static boolean isDisplayingMapView() {
[12631]94 return MainApplication.isDisplayingMapView();
[2343]95 }
[6070]96
[2343]97 /**
[1104]98 * Global parent component for all dialogs and message boxes
99 */
100 public static Component parent;
[6070]101
[1104]102 /**
103 * Global application.
104 */
[8126]105 public static volatile Main main;
[6070]106
[1104]107 /**
108 * The worker thread slave. This is for executing all long and intensive
[12634]109 * calculations. The executed runnables are guaranteed to be executed separately and sequential.
110 * @deprecated use {@link MainApplication#worker} instead
[1104]111 */
[12634]112 @Deprecated
[12665]113 public static ExecutorService worker;
[6070]114
[1104]115 /**
116 * Global application preferences
117 */
[13023]118 public static final Preferences pref = new Preferences(JosmBaseDirectories.getInstance());
[1814]119
[1104]120 /**
[10975]121 * The MapFrame.
[10271]122 * <p>
[12637]123 * There should be no need to access this to access any map data. Use {@link MainApplication#getLayerManager} instead.
[10432]124 *
[12637]125 * @deprecated Use {@link MainApplication#getMap()} instead
[10432]126 * @see MainPanel
[1104]127 */
[12630]128 @Deprecated
[1104]129 public static MapFrame map;
[6070]130
[1104]131 /**
132 * The toolbar preference control to register new actions.
[12637]133 * @deprecated Use {@link MainApplication#getToolbar} instead
[1104]134 */
[12637]135 @Deprecated
[8126]136 public static volatile ToolbarPreferences toolbar;
[626]137
[5829]138 /**
139 * The commands undo/redo handler.
140 */
[12718]141 public final UndoRedoHandler undoRedo = new UndoRedoHandler();
[626]142
[5831]143 /**
[1104]144 * The main menu bar at top of screen.
[12643]145 * @deprecated Use {@link MainApplication#getMenu} instead
[1104]146 */
[12643]147 @Deprecated
[5134]148 public MainMenu menu;
[626]149
[5481]150 /**
[12125]151 * The main panel.
[12642]152 * @deprecated Use {@link MainApplication#getMainPanel} instead
[12125]153 * @since 12125
154 */
[12642]155 @Deprecated
[12125]156 public MainPanel panel;
157
158 /**
[7185]159 * The file watcher service.
160 */
161 public static final FileWatcher fileWatcher = new FileWatcher();
162
[11650]163 private static final Map<String, Throwable> NETWORK_ERRORS = new HashMap<>();
[6642]164
[10044]165 private static final Set<OnlineResource> OFFLINE_RESOURCES = EnumSet.noneOf(OnlineResource.class);
[7434]166
[1356]167 /**
[6730]168 * Logging level (5 = trace, 4 = debug, 3 = info, 2 = warn, 1 = error, 0 = none).
[6248]169 * @since 6248
[10899]170 * @deprecated Use {@link Logging} class.
[1104]171 */
[10899]172 @Deprecated
[6248]173 public static int logLevel = 3;
[6474]174
[10432]175 /**
[8857]176 * Replies the first lines of last 5 error and warning messages, used for bug reports
177 * @return the first lines of last 5 error and warning messages
[7420]178 * @since 7420
[12620]179 * @deprecated Use {@link Logging#getLastErrorAndWarnings}.
[7420]180 */
[12620]181 @Deprecated
[7420]182 public static final Collection<String> getLastErrorAndWarnings() {
[10899]183 return Logging.getLastErrorAndWarnings();
[7420]184 }
185
186 /**
[8959]187 * Clears the list of last error and warning messages.
188 * @since 8959
[12620]189 * @deprecated Use {@link Logging#clearLastErrorAndWarnings}.
[8959]190 */
[12620]191 @Deprecated
[8959]192 public static void clearLastErrorAndWarnings() {
[10899]193 Logging.clearLastErrorAndWarnings();
[8959]194 }
195
196 /**
[6248]197 * Prints an error message if logging is on.
[5481]198 * @param msg The message to print.
[6248]199 * @since 6248
[12620]200 * @deprecated Use {@link Logging#error(String)}.
[5481]201 */
[12620]202 @Deprecated
[6248]203 public static void error(String msg) {
[10899]204 Logging.error(msg);
[6248]205 }
[6474]206
[6248]207 /**
208 * Prints a warning message if logging is on.
209 * @param msg The message to print.
[12620]210 * @deprecated Use {@link Logging#warn(String)}.
[6248]211 */
[12620]212 @Deprecated
[6248]213 public static void warn(String msg) {
[10899]214 Logging.warn(msg);
[4190]215 }
[6474]216
[5481]217 /**
[6248]218 * Prints an informational message if logging is on.
[5481]219 * @param msg The message to print.
[12620]220 * @deprecated Use {@link Logging#info(String)}.
[5481]221 */
[12620]222 @Deprecated
[6248]223 public static void info(String msg) {
[10899]224 Logging.info(msg);
[4190]225 }
[6474]226
[5481]227 /**
[6248]228 * Prints a debug message if logging is on.
[5481]229 * @param msg The message to print.
[12620]230 * @deprecated Use {@link Logging#debug(String)}.
[5481]231 */
[12620]232 @Deprecated
[6248]233 public static void debug(String msg) {
[10899]234 Logging.debug(msg);
[1104]235 }
[6474]236
[5481]237 /**
[6730]238 * Prints a trace message if logging is on.
239 * @param msg The message to print.
[12620]240 * @deprecated Use {@link Logging#trace(String)}.
[6730]241 */
[12620]242 @Deprecated
[6730]243 public static void trace(String msg) {
[10899]244 Logging.trace(msg);
[6730]245 }
246
247 /**
[6852]248 * Determines if debug log level is enabled.
249 * Useful to avoid costly construction of debug messages when not enabled.
250 * @return {@code true} if log level is at least debug, {@code false} otherwise
251 * @since 6852
[12620]252 * @deprecated Use {@link Logging#isDebugEnabled}.
[6852]253 */
[12620]254 @Deprecated
[6852]255 public static boolean isDebugEnabled() {
[12620]256 return Logging.isDebugEnabled();
[6852]257 }
258
259 /**
260 * Determines if trace log level is enabled.
261 * Useful to avoid costly construction of trace messages when not enabled.
262 * @return {@code true} if log level is at least trace, {@code false} otherwise
263 * @since 6852
[12620]264 * @deprecated Use {@link Logging#isTraceEnabled}.
[6852]265 */
[12620]266 @Deprecated
[6852]267 public static boolean isTraceEnabled() {
[12620]268 return Logging.isTraceEnabled();
[6852]269 }
270
271 /**
[6535]272 * Prints a formatted error message if logging is on. Calls {@link MessageFormat#format}
[5481]273 * function to format text.
[6535]274 * @param msg The formatted message to print.
[5481]275 * @param objects The objects to insert into format string.
[6248]276 * @since 6248
[12620]277 * @deprecated Use {@link Logging#error(String, Object...)}.
[5481]278 */
[12620]279 @Deprecated
[6248]280 public static void error(String msg, Object... objects) {
[10899]281 Logging.error(msg, objects);
[6248]282 }
[6474]283
[6248]284 /**
[6535]285 * Prints a formatted warning message if logging is on. Calls {@link MessageFormat#format}
[6248]286 * function to format text.
[6535]287 * @param msg The formatted message to print.
[6248]288 * @param objects The objects to insert into format string.
[12620]289 * @deprecated Use {@link Logging#warn(String, Object...)}.
[6248]290 */
[12620]291 @Deprecated
[6248]292 public static void warn(String msg, Object... objects) {
[10899]293 Logging.warn(msg, objects);
[5481]294 }
[6474]295
[5481]296 /**
[6535]297 * Prints a formatted informational message if logging is on. Calls {@link MessageFormat#format}
[5481]298 * function to format text.
[6535]299 * @param msg The formatted message to print.
[5481]300 * @param objects The objects to insert into format string.
[12620]301 * @deprecated Use {@link Logging#info(String, Object...)}.
[5481]302 */
[12620]303 @Deprecated
[6248]304 public static void info(String msg, Object... objects) {
[10899]305 Logging.info(msg, objects);
[5481]306 }
[6474]307
[5481]308 /**
[6535]309 * Prints a formatted debug message if logging is on. Calls {@link MessageFormat#format}
[5481]310 * function to format text.
[6535]311 * @param msg The formatted message to print.
[5481]312 * @param objects The objects to insert into format string.
[12620]313 * @deprecated Use {@link Logging#debug(String, Object...)}.
[5481]314 */
[12620]315 @Deprecated
[6248]316 public static void debug(String msg, Object... objects) {
[10899]317 Logging.debug(msg, objects);
[5481]318 }
[6474]319
[6248]320 /**
[8015]321 * Prints a formatted trace message if logging is on. Calls {@link MessageFormat#format}
322 * function to format text.
323 * @param msg The formatted message to print.
324 * @param objects The objects to insert into format string.
[12620]325 * @deprecated Use {@link Logging#trace(String, Object...)}.
[8015]326 */
[12620]327 @Deprecated
[8015]328 public static void trace(String msg, Object... objects) {
[10899]329 Logging.trace(msg, objects);
[8015]330 }
331
332 /**
[6248]333 * Prints an error message for the given Throwable.
334 * @param t The throwable object causing the error
335 * @since 6248
[12620]336 * @deprecated Use {@link Logging#error(Throwable)}.
[6248]337 */
[12620]338 @Deprecated
[6248]339 public static void error(Throwable t) {
[12620]340 Logging.error(t);
[6248]341 }
[6474]342
[6248]343 /**
344 * Prints a warning message for the given Throwable.
345 * @param t The throwable object causing the error
346 * @since 6248
[12620]347 * @deprecated Use {@link Logging#warn(Throwable)}.
[6248]348 */
[12620]349 @Deprecated
[6248]350 public static void warn(Throwable t) {
[12620]351 Logging.warn(t);
[6642]352 }
353
354 /**
[10420]355 * Prints a debug message for the given Throwable. Useful for exceptions usually ignored
356 * @param t The throwable object causing the error
[10421]357 * @since 10420
[12620]358 * @deprecated Use {@link Logging#debug(Throwable)}.
[10420]359 */
[12620]360 @Deprecated
[10420]361 public static void debug(Throwable t) {
[12620]362 Logging.debug(t);
[10420]363 }
364
365 /**
366 * Prints a trace message for the given Throwable. Useful for exceptions usually ignored
367 * @param t The throwable object causing the error
[10421]368 * @since 10420
[12620]369 * @deprecated Use {@link Logging#trace(Throwable)}.
[10420]370 */
[12620]371 @Deprecated
[10420]372 public static void trace(Throwable t) {
[12620]373 Logging.trace(t);
[10420]374 }
375
376 /**
[6642]377 * Prints an error message for the given Throwable.
378 * @param t The throwable object causing the error
379 * @param stackTrace {@code true}, if the stacktrace should be displayed
[6643]380 * @since 6642
[12620]381 * @deprecated Use {@link Logging#log(java.util.logging.Level, Throwable)}
382 * or {@link Logging#logWithStackTrace(java.util.logging.Level, Throwable)}.
[6642]383 */
[12620]384 @Deprecated
[6642]385 public static void error(Throwable t, boolean stackTrace) {
386 if (stackTrace) {
[10899]387 Logging.log(Logging.LEVEL_ERROR, t);
388 } else {
389 Logging.logWithStackTrace(Logging.LEVEL_ERROR, t);
[6642]390 }
391 }
392
393 /**
[10420]394 * Prints an error message for the given Throwable.
395 * @param t The throwable object causing the error
396 * @param message additional error message
[10421]397 * @since 10420
[12620]398 * @deprecated Use {@link Logging#log(java.util.logging.Level, String, Throwable)}.
[10420]399 */
[12620]400 @Deprecated
[10420]401 public static void error(Throwable t, String message) {
[10899]402 Logging.log(Logging.LEVEL_ERROR, message, t);
[10420]403 }
404
405 /**
[6642]406 * Prints a warning message for the given Throwable.
407 * @param t The throwable object causing the error
408 * @param stackTrace {@code true}, if the stacktrace should be displayed
[6643]409 * @since 6642
[12620]410 * @deprecated Use {@link Logging#log(java.util.logging.Level, Throwable)}
411 * or {@link Logging#logWithStackTrace(java.util.logging.Level, Throwable)}.
[6642]412 */
[12620]413 @Deprecated
[6642]414 public static void warn(Throwable t, boolean stackTrace) {
415 if (stackTrace) {
[10899]416 Logging.log(Logging.LEVEL_WARN, t);
417 } else {
418 Logging.logWithStackTrace(Logging.LEVEL_WARN, t);
[6642]419 }
[6248]420 }
[6474]421
[6642]422 /**
[10420]423 * Prints a warning message for the given Throwable.
424 * @param t The throwable object causing the error
425 * @param message additional error message
[10421]426 * @since 10420
[12620]427 * @deprecated Use {@link Logging#log(java.util.logging.Level, String, Throwable)}.
[10420]428 */
[12620]429 @Deprecated
[10420]430 public static void warn(Throwable t, String message) {
[10899]431 Logging.log(Logging.LEVEL_WARN, message, t);
[10420]432 }
433
434 /**
[6642]435 * Returns a human-readable message of error, also usable for developers.
436 * @param t The error
437 * @return The human-readable error message
438 * @since 6642
[12620]439 * @deprecated Use {@link Logging#getErrorMessage}.
[6642]440 */
[12620]441 @Deprecated
[6642]442 public static String getErrorMessage(Throwable t) {
[6783]443 if (t == null) {
444 return null;
[10899]445 } else {
446 return Logging.getErrorMessage(t);
[6783]447 }
[6311]448 }
[301]449
[1104]450 /**
451 * Platform specific code goes in here.
[12641]452 * Plugins may replace it, however, some hooks will be called before any plugins have been loaded.
[1104]453 * So if you need to hook into those early ones, split your class and send the one with the early hooks
454 * to the JOSM team for inclusion.
455 */
[8126]456 public static volatile PlatformHook platform;
[1023]457
[8840]458 private static volatile InitStatusListener initListener;
[4681]459
[11352]460 /**
461 * Initialization task listener.
462 */
[8512]463 public interface InitStatusListener {
[4681]464
[11352]465 /**
466 * Called when an initialization task updates its status.
467 * @param event task name
468 * @return new status
469 */
[8497]470 Object updateStatus(String event);
[8510]471
[11352]472 /**
473 * Called when an initialization task completes.
474 * @param status final status
475 */
[8497]476 void finish(Object status);
[4681]477 }
478
[11352]479 /**
480 * Sets initialization task listener.
481 * @param listener initialization task listener
482 */
[4681]483 public static void setInitStatusListener(InitStatusListener listener) {
[8497]484 CheckParameterUtil.ensureParameterNotNull(listener);
[4681]485 initListener = listener;
486 }
487
[6523]488 /**
[10340]489 * Constructs new {@code Main} object.
490 * @see #initialize()
[6523]491 */
[11656]492 protected Main() {
493 setInstance(this);
[10340]494 }
495
[11656]496 private static void setInstance(Main instance) {
497 main = instance;
498 }
499
[10340]500 /**
501 * Initializes the main object. A lot of global variables are initialized here.
502 * @since 10340
503 */
504 public void initialize() {
[12629]505 // Initializes tasks that must be run before parallel tasks
506 runInitializationTasks(beforeInitializationTasks());
[4681]507
[12629]508 // Initializes tasks to be executed (in parallel) by a ExecutorService
[11642]509 try {
[10899]510 ExecutorService service = Executors.newFixedThreadPool(
[8734]511 Runtime.getRuntime().availableProcessors(), Utils.newThreadFactory("main-init-%d", Thread.NORM_PRIORITY));
[12629]512 for (Future<Void> i : service.invokeAll(parallelInitializationTasks())) {
[5195]513 i.get();
514 }
[11092]515 // asynchronous initializations to be completed eventually
[12629]516 asynchronousRunnableTasks().forEach(service::submit);
517 asynchronousCallableTasks().forEach(service::submit);
[8738]518 service.shutdown();
[10212]519 } catch (InterruptedException | ExecutionException ex) {
[11374]520 throw new JosmRuntimeException(ex);
[4718]521 }
[3669]522
[12629]523 // Initializes tasks that must be run after parallel tasks
524 runInitializationTasks(afterInitializationTasks());
525 }
[4489]526
[12629]527 private static void runInitializationTasks(List<InitializationTask> tasks) {
528 for (InitializationTask task : tasks) {
529 try {
530 task.call();
531 } catch (JosmRuntimeException e) {
532 // Can happen if the current projection needs NTV2 grid which is not available
533 // In this case we want the user be able to change his projection
534 BugReport.intercept(e).warn();
535 }
536 }
[1104]537 }
[626]538
[10340]539 /**
[12629]540 * Returns tasks that must be run before parallel tasks.
541 * @return tasks that must be run before parallel tasks
542 * @see #afterInitializationTasks
543 * @see #parallelInitializationTasks
544 */
545 protected List<InitializationTask> beforeInitializationTasks() {
546 return Collections.emptyList();
547 }
548
549 /**
550 * Returns tasks to be executed (in parallel) by a ExecutorService.
551 * @return tasks to be executed (in parallel) by a ExecutorService
552 */
553 protected Collection<InitializationTask> parallelInitializationTasks() {
554 return Collections.emptyList();
555 }
556
557 /**
558 * Returns asynchronous callable initializations to be completed eventually
559 * @return asynchronous callable initializations to be completed eventually
560 */
561 protected List<Callable<?>> asynchronousCallableTasks() {
562 return Collections.emptyList();
563 }
564
565 /**
566 * Returns asynchronous runnable initializations to be completed eventually
567 * @return asynchronous runnable initializations to be completed eventually
568 */
569 protected List<Runnable> asynchronousRunnableTasks() {
570 return Collections.emptyList();
571 }
572
573 /**
574 * Returns tasks that must be run after parallel tasks.
575 * @return tasks that must be run after parallel tasks
576 * @see #beforeInitializationTasks
577 * @see #parallelInitializationTasks
578 */
579 protected List<InitializationTask> afterInitializationTasks() {
580 return Collections.emptyList();
581 }
582
583 protected static final class InitializationTask implements Callable<Void> {
[6779]584
585 private final String name;
[10936]586 private final Runnable task;
[6779]587
[12629]588 /**
589 * Constructs a new {@code InitializationTask}.
590 * @param name translated name to be displayed to user
591 * @param task runnable initialization task
592 */
593 public InitializationTask(String name, Runnable task) {
[6779]594 this.name = name;
[10899]595 this.task = task;
[6779]596 }
597
598 @Override
[8497]599 public Void call() {
600 Object status = null;
[6779]601 if (initListener != null) {
[8497]602 status = initListener.updateStatus(name);
[6779]603 }
[10899]604 task.run();
[8497]605 if (initListener != null) {
606 initListener.finish(status);
[6852]607 }
[6779]608 return null;
609 }
610 }
611
[1104]612 /**
[10271]613 * Returns the main layer manager that is used by the map view.
614 * @return The layer manager. The value returned will never change.
[10279]615 * @since 10279
[12636]616 * @deprecated use {@link MainApplication#getLayerManager} instead
[10271]617 */
[12636]618 @Deprecated
[10279]619 public static MainLayerManager getLayerManager() {
[12636]620 return MainApplication.getLayerManager();
[10271]621 }
622
623 /**
[6546]624 * Replies the current selected primitives, from a end-user point of view.
625 * It is not always technically the same collection of primitives than {@link DataSet#getSelected()}.
626 * @return The current selected primitives, from a end-user point of view. Can be {@code null}.
627 * @since 6546
628 */
629 public Collection<OsmPrimitive> getInProgressSelection() {
[12636]630 return Collections.emptyList();
[6546]631 }
[1750]632
[11352]633 /**
[12718]634 * Gets the active edit data set.
635 * @return That data set, <code>null</code>.
[12691]636 * @since 12691
637 */
[12718]638 public abstract DataSet getEditDataSet();
[12691]639
640 /**
[12718]641 * Sets the active data set.
642 * @param ds New edit data set, or <code>null</code>
643 * @since 12718
644 */
645 public abstract void setEditDataSet(DataSet ds);
646
647 /**
648 * Determines if the list of data sets managed by JOSM contains {@code ds}.
649 * @param ds the data set to look for
650 * @return {@code true} if the list of data sets managed by JOSM contains {@code ds}
651 * @since 12718
652 */
653 public abstract boolean containsDataSet(DataSet ds);
654
655 /**
[11352]656 * Registers a {@code JosmAction} and its shortcut.
657 * @param action action defining its own shortcut
[12639]658 * @deprecated use {@link MainApplication#registerActionShortcut(JosmAction)} instead
[11352]659 */
[12639]660 @Deprecated
[5278]661 public static void registerActionShortcut(JosmAction action) {
[12639]662 MainApplication.registerActionShortcut(action);
[5278]663 }
664
[11352]665 /**
666 * Registers an action and its shortcut.
667 * @param action action to register
668 * @param shortcut shortcut to associate to {@code action}
[12639]669 * @deprecated use {@link MainApplication#registerActionShortcut(Action, Shortcut)} instead
[11352]670 */
[12639]671 @Deprecated
[3252]672 public static void registerActionShortcut(Action action, Shortcut shortcut) {
[12639]673 MainApplication.registerActionShortcut(action, shortcut);
[3252]674 }
675
[11352]676 /**
677 * Unregisters a shortcut.
678 * @param shortcut shortcut to unregister
[12639]679 * @deprecated use {@link MainApplication#unregisterShortcut(Shortcut)} instead
[11352]680 */
[12639]681 @Deprecated
[5382]682 public static void unregisterShortcut(Shortcut shortcut) {
[12639]683 MainApplication.unregisterShortcut(shortcut);
[3252]684 }
685
[11352]686 /**
687 * Unregisters a {@code JosmAction} and its shortcut.
688 * @param action action to unregister
[12639]689 * @deprecated use {@link MainApplication#unregisterActionShortcut(JosmAction)} instead
[11352]690 */
[12639]691 @Deprecated
[3444]692 public static void unregisterActionShortcut(JosmAction action) {
[12639]693 MainApplication.unregisterActionShortcut(action);
[3444]694 }
695
[11352]696 /**
697 * Unregisters an action and its shortcut.
698 * @param action action to unregister
699 * @param shortcut shortcut to unregister
[12639]700 * @deprecated use {@link MainApplication#unregisterActionShortcut(Action, Shortcut)} instead
[11352]701 */
[12639]702 @Deprecated
[3444]703 public static void unregisterActionShortcut(Action action, Shortcut shortcut) {
[12639]704 MainApplication.unregisterActionShortcut(action, shortcut);
[3444]705 }
[6070]706
[5696]707 /**
708 * Replies the registered action for the given shortcut
709 * @param shortcut The shortcut to look for
710 * @return the registered action for the given shortcut
[12639]711 * @deprecated use {@link MainApplication#getRegisteredActionShortcut(Shortcut)} instead
[5696]712 * @since 5696
713 */
[12639]714 @Deprecated
[5696]715 public static Action getRegisteredActionShortcut(Shortcut shortcut) {
[12639]716 return MainApplication.getRegisteredActionShortcut(shortcut);
[5696]717 }
[3444]718
[1104]719 ///////////////////////////////////////////////////////////////////////////
720 // Implementation part
721 ///////////////////////////////////////////////////////////////////////////
[626]722
[5829]723 /**
[1104]724 * Should be called before the main constructor to setup some parameter stuff
725 */
[10962]726 public static void preConstructorInit() {
[1990]727 // init default coordinate format
[12846]728 ICoordinateFormat fmt = CoordinateFormatManager.getCoordinateFormat(Config.getPref().get("coordinates"));
[12735]729 if (fmt == null) {
730 fmt = DecimalDegreesCoordinateFormat.INSTANCE;
[1990]731 }
[12735]732 CoordinateFormatManager.setCoordinateFormat(fmt);
[1104]733 }
[626]734
[11986]735 /**
[8412]736 * Closes JOSM and optionally terminates the Java Virtual Machine (JVM).
[6342]737 * @param exit If {@code true}, the JVM is terminated by running {@link System#exit} with a given return code.
738 * @param exitCode The return code
[12636]739 * @return {@code true}
740 * @since 12636
[5829]741 */
[12636]742 public static boolean exitJosm(boolean exit, int exitCode) {
743 if (Main.main != null) {
744 Main.main.shutdown();
745 }
[8412]746
[12636]747 if (exit) {
748 System.exit(exitCode);
[5829]749 }
[12636]750 return true;
[3378]751 }
752
[11986]753 /**
754 * Shutdown JOSM.
755 */
[10340]756 protected void shutdown() {
[11106]757 if (!GraphicsEnvironment.isHeadless()) {
758 ImageProvider.shutdown(false);
759 }
[10340]760 try {
761 pref.saveDefaults();
762 } catch (IOException ex) {
[12620]763 Logging.log(Logging.LEVEL_WARN, tr("Failed to save default preferences."), ex);
[10340]764 }
[11106]765 if (!GraphicsEnvironment.isHeadless()) {
766 ImageProvider.shutdown(true);
767 }
[10340]768 }
769
[2798]770 /**
[5829]771 * Identifies the current operating system family and initializes the platform hook accordingly.
772 * @since 1849
773 */
[1849]774 public static void determinePlatformHook() {
[12776]775 platform = Platform.determinePlatform().accept(PlatformHook.CONSTRUCT_FROM_PLATFORM);
[1104]776 }
[1023]777
[4126]778 /* ----------------------------------------------------------------------------------------- */
779 /* projection handling - Main is a registry for a single, global projection instance */
780 /* */
781 /* TODO: For historical reasons the registry is implemented by Main. An alternative approach */
782 /* would be a singleton org.openstreetmap.josm.data.projection.ProjectionRegistry class. */
783 /* ----------------------------------------------------------------------------------------- */
784 /**
785 * The projection method used.
[12631]786 * Use {@link #getProjection()} and {@link #setProjection(Projection)} for access.
[4897]787 * Use {@link #setProjection(Projection)} in order to trigger a projection change event.
[4126]788 */
[8126]789 private static volatile Projection proj;
[4126]790
791 /**
792 * Replies the current projection.
[4489]793 *
[5357]794 * @return the currently active projection
[4126]795 */
796 public static Projection getProjection() {
797 return proj;
798 }
799
800 /**
801 * Sets the current projection
[4489]802 *
[4126]803 * @param p the projection
804 */
805 public static void setProjection(Projection p) {
806 CheckParameterUtil.ensureParameterNotNull(p);
807 Projection oldValue = proj;
[12631]808 Bounds b = main != null ? main.getRealBounds() : null;
[4126]809 proj = p;
[5234]810 fireProjectionChanged(oldValue, proj, b);
[4126]811 }
812
[12631]813 /**
814 * Returns the bounds for the current projection. Used for projection events.
815 * @return the bounds for the current projection
816 * @see #restoreOldBounds
817 */
818 protected Bounds getRealBounds() {
819 // To be overriden
820 return null;
821 }
822
823 /**
824 * Restore clean state corresponding to old bounds after a projection change event.
825 * @param oldBounds bounds previously returned by {@link #getRealBounds}, before the change of projection
826 * @see #getRealBounds
827 */
828 protected void restoreOldBounds(Bounds oldBounds) {
829 // To be overriden
830 }
831
[4126]832 /*
833 * Keep WeakReferences to the listeners. This relieves clients from the burden of
834 * explicitly removing the listeners and allows us to transparently register every
835 * created dataset as projection change listener.
836 */
[7005]837 private static final List<WeakReference<ProjectionChangeListener>> listeners = new ArrayList<>();
[4126]838
[5234]839 private static void fireProjectionChanged(Projection oldValue, Projection newValue, Bounds oldBounds) {
[10655]840 if ((newValue == null ^ oldValue == null)
[7083]841 || (newValue != null && oldValue != null && !Objects.equals(newValue.toCode(), oldValue.toCode()))) {
[8510]842 synchronized (Main.class) {
[4126]843 Iterator<WeakReference<ProjectionChangeListener>> it = listeners.iterator();
[8510]844 while (it.hasNext()) {
[4126]845 WeakReference<ProjectionChangeListener> wr = it.next();
[4724]846 ProjectionChangeListener listener = wr.get();
847 if (listener == null) {
[4126]848 it.remove();
849 continue;
850 }
[4724]851 listener.projectionChanged(oldValue, newValue);
[4126]852 }
853 }
[12631]854 if (newValue != null && oldBounds != null && main != null) {
855 main.restoreOldBounds(oldBounds);
[4126]856 }
857 /* TODO - remove layers with fixed projection */
858 }
859 }
860
861 /**
[5538]862 * Register a projection change listener.
[12119]863 * The listener is registered to be weak, so keep a reference of it if you want it to be preserved.
[4489]864 *
[5357]865 * @param listener the listener. Ignored if <code>null</code>.
[4126]866 */
867 public static void addProjectionChangeListener(ProjectionChangeListener listener) {
868 if (listener == null) return;
869 synchronized (Main.class) {
870 for (WeakReference<ProjectionChangeListener> wr : listeners) {
871 // already registered ? => abort
872 if (wr.get() == listener) return;
873 }
[7005]874 listeners.add(new WeakReference<>(listener));
[4126]875 }
876 }
877
878 /**
[5538]879 * Removes a projection change listener.
[4489]880 *
[5357]881 * @param listener the listener. Ignored if <code>null</code>.
[4126]882 */
883 public static void removeProjectionChangeListener(ProjectionChangeListener listener) {
884 if (listener == null) return;
[8510]885 synchronized (Main.class) {
[11339]886 // remove the listener - and any other listener which got garbage
887 // collected in the meantime
888 listeners.removeIf(wr -> wr.get() == null || wr.get() == listener);
[4126]889 }
890 }
[5538]891
892 /**
893 * Listener for window switch events.
[6070]894 *
[5538]895 * These are events, when the user activates a window of another application
896 * or comes back to JOSM. Window switches from one JOSM window to another
897 * are not reported.
898 */
[8512]899 public interface WindowSwitchListener {
[5538]900 /**
901 * Called when the user activates a window of another application.
902 */
903 void toOtherApplication();
[9059]904
[5538]905 /**
[9059]906 * Called when the user comes from a window of another application back to JOSM.
[5538]907 */
908 void fromOtherApplication();
909 }
910
911 /**
[11904]912 * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes.
913 * <p>
914 * It will fire an initial mapFrameInitialized event when the MapFrame is present.
915 * Otherwise will only fire when the MapFrame is created or destroyed.
[5957]916 * @param listener The MapFrameListener
917 * @return {@code true} if the listeners collection changed as a result of the call
[11904]918 * @see #addMapFrameListener
[12639]919 * @deprecated use {@link MainApplication#addAndFireMapFrameListener} instead
[11904]920 * @since 11904
[8020]921 */
[12639]922 @Deprecated
[11904]923 public static boolean addAndFireMapFrameListener(MapFrameListener listener) {
[12639]924 return MainApplication.addAndFireMapFrameListener(listener);
[8020]925 }
926
927 /**
928 * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes
929 * @param listener The MapFrameListener
930 * @return {@code true} if the listeners collection changed as a result of the call
[11904]931 * @see #addAndFireMapFrameListener
[12639]932 * @deprecated use {@link MainApplication#addMapFrameListener} instead
[5957]933 * @since 5957
934 */
[12639]935 @Deprecated
[5957]936 public static boolean addMapFrameListener(MapFrameListener listener) {
[12639]937 return MainApplication.addMapFrameListener(listener);
[5957]938 }
939
940 /**
941 * Unregisters the given {@code MapFrameListener} from MapFrame changes
942 * @param listener The MapFrameListener
943 * @return {@code true} if the listeners collection changed as a result of the call
[12639]944 * @deprecated use {@link MainApplication#removeMapFrameListener} instead
[5957]945 * @since 5957
946 */
[12639]947 @Deprecated
[5957]948 public static boolean removeMapFrameListener(MapFrameListener listener) {
[12639]949 return MainApplication.removeMapFrameListener(listener);
[5957]950 }
[6642]951
952 /**
953 * Adds a new network error that occur to give a hint about broken Internet connection.
954 * Do not use this method for errors known for sure thrown because of a bad proxy configuration.
[6852]955 *
[6642]956 * @param url The accessed URL that caused the error
957 * @param t The network error
958 * @return The previous error associated to the given resource, if any. Can be {@code null}
[6643]959 * @since 6642
[6642]960 */
961 public static Throwable addNetworkError(URL url, Throwable t) {
962 if (url != null && t != null) {
963 Throwable old = addNetworkError(url.toExternalForm(), t);
964 if (old != null) {
[12620]965 Logging.warn("Already here "+old);
[6642]966 }
967 return old;
968 }
969 return null;
970 }
971
972 /**
973 * Adds a new network error that occur to give a hint about broken Internet connection.
974 * Do not use this method for errors known for sure thrown because of a bad proxy configuration.
[6852]975 *
[6642]976 * @param url The accessed URL that caused the error
977 * @param t The network error
978 * @return The previous error associated to the given resource, if any. Can be {@code null}
[6643]979 * @since 6642
[6642]980 */
981 public static Throwable addNetworkError(String url, Throwable t) {
982 if (url != null && t != null) {
[6806]983 return NETWORK_ERRORS.put(url, t);
[6642]984 }
985 return null;
986 }
987
988 /**
989 * Returns the network errors that occured until now.
990 * @return the network errors that occured until now, indexed by URL
991 * @since 6639
992 */
993 public static Map<String, Throwable> getNetworkErrors() {
[7005]994 return new HashMap<>(NETWORK_ERRORS);
[6642]995 }
[6897]996
997 /**
[12011]998 * Clears the network errors cache.
999 * @since 12011
1000 */
1001 public static void clearNetworkErrors() {
1002 NETWORK_ERRORS.clear();
1003 }
1004
1005 /**
[6897]1006 * Returns the JOSM website URL.
1007 * @return the josm website URL
1008 * @since 6897
1009 */
1010 public static String getJOSMWebsite() {
[12846]1011 if (Config.getPref() != null)
1012 return Config.getPref().get("josm.url", JOSM_WEBSITE);
[6897]1013 return JOSM_WEBSITE;
1014 }
1015
1016 /**
1017 * Returns the JOSM XML URL.
1018 * @return the josm XML URL
1019 * @since 6897
1020 */
1021 public static String getXMLBase() {
[6920]1022 // Always return HTTP (issues reported with HTTPS)
[6900]1023 return "http://josm.openstreetmap.de";
[6897]1024 }
1025
1026 /**
1027 * Returns the OSM website URL.
1028 * @return the OSM website URL
1029 * @since 6897
1030 */
1031 public static String getOSMWebsite() {
[12846]1032 if (Config.getPref() != null)
1033 return Config.getPref().get("osm.url", OSM_WEBSITE);
[6897]1034 return OSM_WEBSITE;
1035 }
[6957]1036
1037 /**
[11262]1038 * Returns the OSM website URL depending on the selected {@link OsmApi}.
1039 * @return the OSM website URL depending on the selected {@link OsmApi}
1040 */
1041 private static String getOSMWebsiteDependingOnSelectedApi() {
1042 final String api = OsmApi.getOsmApi().getServerUrl();
1043 if (OsmApi.DEFAULT_API_URL.equals(api)) {
1044 return getOSMWebsite();
1045 } else {
1046 return api.replaceAll("/api$", "");
1047 }
1048 }
1049
1050 /**
[7678]1051 * Replies the base URL for browsing information about a primitive.
1052 * @return the base URL, i.e. https://www.openstreetmap.org
1053 * @since 7678
1054 */
1055 public static String getBaseBrowseUrl() {
[12846]1056 if (Config.getPref() != null)
1057 return Config.getPref().get("osm-browse.url", getOSMWebsiteDependingOnSelectedApi());
[11262]1058 return getOSMWebsiteDependingOnSelectedApi();
[7678]1059 }
1060
1061 /**
1062 * Replies the base URL for browsing information about a user.
1063 * @return the base URL, i.e. https://www.openstreetmap.org/user
1064 * @since 7678
1065 */
1066 public static String getBaseUserUrl() {
[12846]1067 if (Config.getPref() != null)
1068 return Config.getPref().get("osm-user.url", getOSMWebsiteDependingOnSelectedApi() + "/user");
[11262]1069 return getOSMWebsiteDependingOnSelectedApi() + "/user";
[7678]1070 }
1071
1072 /**
[6957]1073 * Determines if we are currently running on OSX.
1074 * @return {@code true} if we are currently running on OSX
1075 * @since 6957
1076 */
1077 public static boolean isPlatformOsx() {
1078 return Main.platform instanceof PlatformHookOsx;
1079 }
[7335]1080
1081 /**
1082 * Determines if we are currently running on Windows.
1083 * @return {@code true} if we are currently running on Windows
1084 * @since 7335
1085 */
1086 public static boolean isPlatformWindows() {
1087 return Main.platform instanceof PlatformHookWindows;
1088 }
[7434]1089
1090 /**
1091 * Determines if the given online resource is currently offline.
1092 * @param r the online resource
1093 * @return {@code true} if {@code r} is offline and should not be accessed
1094 * @since 7434
1095 */
1096 public static boolean isOffline(OnlineResource r) {
1097 return OFFLINE_RESOURCES.contains(r) || OFFLINE_RESOURCES.contains(OnlineResource.ALL);
1098 }
1099
1100 /**
1101 * Sets the given online resource to offline state.
1102 * @param r the online resource
1103 * @return {@code true} if {@code r} was not already offline
1104 * @since 7434
1105 */
1106 public static boolean setOffline(OnlineResource r) {
1107 return OFFLINE_RESOURCES.add(r);
1108 }
1109
1110 /**
[8506]1111 * Sets the given online resource to online state.
1112 * @param r the online resource
1113 * @return {@code true} if {@code r} was offline
1114 * @since 8506
1115 */
1116 public static boolean setOnline(OnlineResource r) {
1117 return OFFLINE_RESOURCES.remove(r);
1118 }
1119
1120 /**
[7434]1121 * Replies the set of online resources currently offline.
1122 * @return the set of online resources currently offline
1123 * @since 7434
1124 */
1125 public static Set<OnlineResource> getOfflineResources() {
[10044]1126 return EnumSet.copyOf(OFFLINE_RESOURCES);
[7434]1127 }
[626]1128}
Note: See TracBrowser for help on using the repository browser.