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

Last change on this file since 12718 was 12718, checked in by Don-vip, 7 years ago

see #13036 - see #15229 - see #15182 - make Commands depends only on a DataSet, not a Layer. This removes a lot of GUI dependencies

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