001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005import static org.openstreetmap.josm.tools.I18n.trn; 006import gnu.getopt.Getopt; 007import gnu.getopt.LongOpt; 008 009import java.awt.Dimension; 010import java.awt.GraphicsEnvironment; 011import java.awt.Image; 012import java.awt.Toolkit; 013import java.awt.event.WindowAdapter; 014import java.awt.event.WindowEvent; 015import java.io.File; 016import java.io.IOException; 017import java.io.InputStream; 018import java.net.Authenticator; 019import java.net.ProxySelector; 020import java.net.URL; 021import java.security.AllPermission; 022import java.security.CodeSource; 023import java.security.KeyStoreException; 024import java.security.NoSuchAlgorithmException; 025import java.security.PermissionCollection; 026import java.security.Permissions; 027import java.security.Policy; 028import java.security.cert.CertificateException; 029import java.util.ArrayList; 030import java.util.Arrays; 031import java.util.Collection; 032import java.util.HashMap; 033import java.util.LinkedList; 034import java.util.List; 035import java.util.Map; 036import java.util.Set; 037import java.util.TreeSet; 038 039import javax.swing.JFrame; 040import javax.swing.JOptionPane; 041import javax.swing.RepaintManager; 042import javax.swing.SwingUtilities; 043 044import org.jdesktop.swinghelper.debug.CheckThreadViolationRepaintManager; 045import org.openstreetmap.josm.Main; 046import org.openstreetmap.josm.actions.PreferencesAction; 047import org.openstreetmap.josm.data.AutosaveTask; 048import org.openstreetmap.josm.data.CustomConfigurator; 049import org.openstreetmap.josm.data.Version; 050import org.openstreetmap.josm.gui.download.DownloadDialog; 051import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder; 052import org.openstreetmap.josm.gui.preferences.server.ProxyPreference; 053import org.openstreetmap.josm.gui.progress.ProgressMonitor; 054import org.openstreetmap.josm.gui.util.GuiHelper; 055import org.openstreetmap.josm.io.DefaultProxySelector; 056import org.openstreetmap.josm.io.MessageNotifier; 057import org.openstreetmap.josm.io.OnlineResource; 058import org.openstreetmap.josm.io.auth.CredentialsManager; 059import org.openstreetmap.josm.io.auth.DefaultAuthenticator; 060import org.openstreetmap.josm.io.remotecontrol.RemoteControl; 061import org.openstreetmap.josm.plugins.PluginHandler; 062import org.openstreetmap.josm.plugins.PluginInformation; 063import org.openstreetmap.josm.tools.BugReportExceptionHandler; 064import org.openstreetmap.josm.tools.FontsManager; 065import org.openstreetmap.josm.tools.I18n; 066import org.openstreetmap.josm.tools.ImageProvider; 067import org.openstreetmap.josm.tools.OsmUrlToBounds; 068import org.openstreetmap.josm.tools.PlatformHookWindows; 069import org.openstreetmap.josm.tools.Utils; 070 071/** 072 * Main window class application. 073 * 074 * @author imi 075 */ 076public class MainApplication extends Main { 077 /** 078 * Allow subclassing (see JOSM.java) 079 */ 080 public MainApplication() {} 081 082 /** 083 * Constructs a main frame, ready sized and operating. Does not display the frame. 084 * @param mainFrame The main JFrame of the application 085 */ 086 public MainApplication(JFrame mainFrame) { 087 addListener(); 088 mainFrame.setContentPane(contentPanePrivate); 089 mainFrame.setJMenuBar(menu); 090 geometry.applySafe(mainFrame); 091 List<Image> l = new LinkedList<>(); 092 l.add(ImageProvider.get("logo_16x16x32").getImage()); 093 l.add(ImageProvider.get("logo_16x16x8").getImage()); 094 l.add(ImageProvider.get("logo_32x32x32").getImage()); 095 l.add(ImageProvider.get("logo_32x32x8").getImage()); 096 l.add(ImageProvider.get("logo_48x48x32").getImage()); 097 l.add(ImageProvider.get("logo_48x48x8").getImage()); 098 l.add(ImageProvider.get("logo").getImage()); 099 mainFrame.setIconImages(l); 100 mainFrame.addWindowListener(new WindowAdapter(){ 101 @Override 102 public void windowClosing(final WindowEvent arg0) { 103 Main.exitJosm(true, 0); 104 } 105 }); 106 mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 107 } 108 109 /** 110 * Displays help on the console 111 * @since 2748 112 */ 113 public static void showHelp() { 114 // TODO: put in a platformHook for system that have no console by default 115 System.out.println(tr("Java OpenStreetMap Editor")+" [" 116 +Version.getInstance().getAgentString()+"]\n\n"+ 117 tr("usage")+":\n"+ 118 "\tjava -jar josm.jar <options>...\n\n"+ 119 tr("options")+":\n"+ 120 "\t--help|-h "+tr("Show this help")+"\n"+ 121 "\t--geometry=widthxheight(+|-)x(+|-)y "+tr("Standard unix geometry argument")+"\n"+ 122 "\t[--download=]minlat,minlon,maxlat,maxlon "+tr("Download the bounding box")+"\n"+ 123 "\t[--download=]<URL> "+tr("Download the location at the URL (with lat=x&lon=y&zoom=z)")+"\n"+ 124 "\t[--download=]<filename> "+tr("Open a file (any file type that can be opened with File/Open)")+"\n"+ 125 "\t--downloadgps=minlat,minlon,maxlat,maxlon "+tr("Download the bounding box as raw GPS")+"\n"+ 126 "\t--downloadgps=<URL> "+tr("Download the location at the URL (with lat=x&lon=y&zoom=z) as raw GPS")+"\n"+ 127 "\t--selection=<searchstring> "+tr("Select with the given search")+"\n"+ 128 "\t--[no-]maximize "+tr("Launch in maximized mode")+"\n"+ 129 "\t--reset-preferences "+tr("Reset the preferences to default")+"\n\n"+ 130 "\t--load-preferences=<url-to-xml> "+tr("Changes preferences according to the XML file")+"\n\n"+ 131 "\t--set=<key>=<value> "+tr("Set preference key to value")+"\n\n"+ 132 "\t--language=<language> "+tr("Set the language")+"\n\n"+ 133 "\t--version "+tr("Displays the JOSM version and exits")+"\n\n"+ 134 "\t--debug "+tr("Print debugging messages to console")+"\n\n"+ 135 "\t--offline=<osm_api|josm_website|all> "+tr("Disable access to the given resource(s), separated by comma")+"\n\n"+ 136 tr("options provided as Java system properties")+":\n"+ 137 "\t-Djosm.pref=" +tr("/PATH/TO/JOSM/PREF ")+tr("Set the preferences directory")+"\n\n"+ 138 "\t-Djosm.userdata="+tr("/PATH/TO/JOSM/USERDATA")+tr("Set the user data directory")+"\n\n"+ 139 "\t-Djosm.cache=" +tr("/PATH/TO/JOSM/CACHE ")+tr("Set the cache directory")+"\n\n"+ 140 "\t-Djosm.home=" +tr("/PATH/TO/JOSM/HOMEDIR ")+ 141 tr("Relocate all 3 directories to homedir. Cache directory will be in homedir/cache")+"\n\n"+ 142 tr("-Djosm.home has lower precedence, i.e. the specific setting overrides the general one")+"\n\n"+ 143 tr("note: For some tasks, JOSM needs a lot of memory. It can be necessary to add the following\n" + 144 " Java option to specify the maximum size of allocated memory in megabytes")+":\n"+ 145 "\t-Xmx...m\n\n"+ 146 tr("examples")+":\n"+ 147 "\tjava -jar josm.jar track1.gpx track2.gpx london.osm\n"+ 148 "\tjava -jar josm.jar "+OsmUrlToBounds.getURL(43.2, 11.1, 13)+"\n"+ 149 "\tjava -jar josm.jar london.osm --selection=http://www.ostertag.name/osm/OSM_errors_node-duplicate.xml\n"+ 150 "\tjava -jar josm.jar 43.2,11.1,43.4,11.4\n"+ 151 "\tjava -Djosm.pref=$XDG_CONFIG_HOME -Djosm.userdata=$XDG_DATA_HOME -Djosm.cache=$XDG_CACHE_HOME -jar josm.jar\n"+ 152 "\tjava -Djosm.home=/home/user/.josm_dev -jar josm.jar\n"+ 153 "\tjava -Xmx1024m -jar josm.jar\n\n"+ 154 tr("Parameters --download, --downloadgps, and --selection are processed in this order.")+"\n"+ 155 tr("Make sure you load some data if you use --selection.")+"\n" 156 ); 157 } 158 159 /** 160 * JOSM command line options. 161 * @see <a href="https://josm.openstreetmap.de/wiki/Help/CommandLineOptions">Help/CommandLineOptions</a> 162 * @since 5279 163 */ 164 public enum Option { 165 /** --help|-h Show this help */ 166 HELP(false), 167 /** --version Displays the JOSM version and exits */ 168 VERSION(false), 169 /** --debug Print debugging messages to console */ 170 DEBUG(false), 171 /** --trace Print detailed debugging messages to console */ 172 TRACE(false), 173 /** --language=<language> Set the language */ 174 LANGUAGE(true), 175 /** --reset-preferences Reset the preferences to default */ 176 RESET_PREFERENCES(false), 177 /** --load-preferences=<url-to-xml> Changes preferences according to the XML file */ 178 LOAD_PREFERENCES(true), 179 /** --set=<key>=<value> Set preference key to value */ 180 SET(true), 181 /** --geometry=widthxheight(+|-)x(+|-)y Standard unix geometry argument */ 182 GEOMETRY(true), 183 /** --no-maximize Do not launch in maximized mode */ 184 NO_MAXIMIZE(false), 185 /** --maximize Launch in maximized mode */ 186 MAXIMIZE(false), 187 /** --download=minlat,minlon,maxlat,maxlon Download the bounding box <br> 188 * --download=<URL> Download the location at the URL (with lat=x&lon=y&zoom=z) <br> 189 * --download=<filename> Open a file (any file type that can be opened with File/Open) */ 190 DOWNLOAD(true), 191 /** --downloadgps=minlat,minlon,maxlat,maxlon Download the bounding box as raw GPS <br> 192 * --downloadgps=<URL> Download the location at the URL (with lat=x&lon=y&zoom=z) as raw GPS */ 193 DOWNLOADGPS(true), 194 /** --selection=<searchstring> Select with the given search */ 195 SELECTION(true), 196 /** --offline=<osm_api|josm_website|all> Disable access to the given resource(s), delimited by comma */ 197 OFFLINE(true); 198 199 private String name; 200 private boolean requiresArgument; 201 202 private Option(boolean requiresArgument) { 203 this.name = name().toLowerCase().replace("_", "-"); 204 this.requiresArgument = requiresArgument; 205 } 206 207 /** 208 * Replies the option name 209 * @return The option name, in lowercase 210 */ 211 public String getName() { 212 return name; 213 } 214 215 /** 216 * Determines if this option requires an argument. 217 * @return {@code true} if this option requires an argument, {@code false} otherwise 218 */ 219 public boolean requiresArgument() { 220 return requiresArgument; 221 } 222 223 public static Map<Option, Collection<String>> fromStringMap(Map<String, Collection<String>> opts) { 224 Map<Option, Collection<String>> res = new HashMap<>(); 225 for (Map.Entry<String, Collection<String>> e : opts.entrySet()) { 226 Option o = Option.valueOf(e.getKey().toUpperCase().replace("-", "_")); 227 if (o != null) { 228 res.put(o, e.getValue()); 229 } 230 } 231 return res; 232 } 233 } 234 235 private static Map<Option, Collection<String>> buildCommandLineArgumentMap(String[] args) { 236 237 List<LongOpt> los = new ArrayList<>(); 238 for (Option o : Option.values()) { 239 los.add(new LongOpt(o.getName(), o.requiresArgument() ? LongOpt.REQUIRED_ARGUMENT : LongOpt.NO_ARGUMENT, null, 0)); 240 } 241 242 Getopt g = new Getopt("JOSM", args, "hv", los.toArray(new LongOpt[los.size()])); 243 244 Map<Option, Collection<String>> argMap = new HashMap<>(); 245 246 int c; 247 while ((c = g.getopt()) != -1 ) { 248 Option opt = null; 249 switch (c) { 250 case 'h': 251 opt = Option.HELP; 252 break; 253 case 'v': 254 opt = Option.VERSION; 255 break; 256 case 0: 257 opt = Option.values()[g.getLongind()]; 258 break; 259 } 260 if (opt != null) { 261 Collection<String> values = argMap.get(opt); 262 if (values == null) { 263 values = new ArrayList<>(); 264 argMap.put(opt, values); 265 } 266 values.add(g.getOptarg()); 267 } else 268 throw new IllegalArgumentException("Invalid option: "+c); 269 } 270 // positional arguments are a shortcut for the --download ... option 271 for (int i = g.getOptind(); i < args.length; ++i) { 272 Collection<String> values = argMap.get(Option.DOWNLOAD); 273 if (values == null) { 274 values = new ArrayList<>(); 275 argMap.put(Option.DOWNLOAD, values); 276 } 277 values.add(args[i]); 278 } 279 280 return argMap; 281 } 282 283 /** 284 * Main application Startup 285 * @param argArray Command-line arguments 286 */ 287 public static void main(final String[] argArray) { 288 I18n.init(); 289 Main.checkJavaVersion(); 290 291 // construct argument table 292 Map<Option, Collection<String>> args = null; 293 try { 294 args = buildCommandLineArgumentMap(argArray); 295 } catch (IllegalArgumentException e) { 296 System.exit(1); 297 return; 298 } 299 300 final boolean languageGiven = args.containsKey(Option.LANGUAGE); 301 302 if (languageGiven) { 303 I18n.set(args.get(Option.LANGUAGE).iterator().next()); 304 } 305 306 initApplicationPreferences(); 307 308 Policy.setPolicy(new Policy() { 309 // Permissions for plug-ins loaded when josm is started via webstart 310 private PermissionCollection pc; 311 312 { 313 pc = new Permissions(); 314 pc.add(new AllPermission()); 315 } 316 317 @Override 318 public void refresh() { } 319 320 @Override 321 public PermissionCollection getPermissions(CodeSource codesource) { 322 return pc; 323 } 324 }); 325 326 Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler()); 327 328 // initialize the platform hook, and 329 Main.determinePlatformHook(); 330 // call the really early hook before we do anything else 331 Main.platform.preStartupHook(); 332 333 Main.commandLineArgs = Utils.copyArray(argArray); 334 335 if (args.containsKey(Option.VERSION)) { 336 System.out.println(Version.getInstance().getAgentString()); 337 System.exit(0); 338 } 339 340 if (args.containsKey(Option.DEBUG) || args.containsKey(Option.TRACE)) { 341 // Enable JOSM debug level 342 logLevel = 4; 343 Main.info(tr("Printing debugging messages to console")); 344 } 345 346 if (args.containsKey(Option.TRACE)) { 347 // Enable JOSM debug level 348 logLevel = 5; 349 // Enable debug in OAuth signpost via system preference, but only at trace level 350 Utils.updateSystemProperty("debug", "true"); 351 Main.info(tr("Enabled detailed debug level (trace)")); 352 } 353 354 Main.pref.init(args.containsKey(Option.RESET_PREFERENCES)); 355 356 if (!languageGiven) { 357 I18n.set(Main.pref.get("language", null)); 358 } 359 Main.pref.updateSystemProperties(); 360 361 // asking for help? show help and exit 362 if (args.containsKey(Option.HELP)) { 363 showHelp(); 364 System.exit(0); 365 } 366 367 processOffline(args); 368 369 Main.platform.afterPrefStartupHook(); 370 371 FontsManager.initialize(); 372 373 handleSpecialLanguages(); 374 375 final JFrame mainFrame = new JFrame(tr("Java OpenStreetMap Editor")); 376 Main.parent = mainFrame; 377 378 if (args.containsKey(Option.LOAD_PREFERENCES)) { 379 CustomConfigurator.XMLCommandProcessor config = new CustomConfigurator.XMLCommandProcessor(Main.pref); 380 for (String i : args.get(Option.LOAD_PREFERENCES)) { 381 info("Reading preferences from " + i); 382 try (InputStream is = Utils.openURL(new URL(i))) { 383 config.openAndReadXML(is); 384 } catch (Exception ex) { 385 throw new RuntimeException(ex); 386 } 387 } 388 } 389 390 if (args.containsKey(Option.SET)) { 391 for (String i : args.get(Option.SET)) { 392 String[] kv = i.split("=", 2); 393 Main.pref.put(kv[0], "null".equals(kv[1]) ? null : kv[1]); 394 } 395 } 396 397 DefaultAuthenticator.createInstance(); 398 Authenticator.setDefault(DefaultAuthenticator.getInstance()); 399 DefaultProxySelector proxySelector = new DefaultProxySelector(ProxySelector.getDefault()); 400 ProxySelector.setDefault(proxySelector); 401 OAuthAccessTokenHolder.getInstance().init(Main.pref, CredentialsManager.getInstance()); 402 403 final SplashScreen splash = new SplashScreen(); 404 final ProgressMonitor monitor = splash.getProgressMonitor(); 405 monitor.beginTask(tr("Initializing")); 406 splash.setVisible(Main.pref.getBoolean("draw.splashscreen", true)); 407 Main.setInitStatusListener(new InitStatusListener() { 408 409 @Override 410 public void updateStatus(String event) { 411 monitor.indeterminateSubTask(event); 412 } 413 }); 414 415 Collection<PluginInformation> pluginsToLoad = PluginHandler.buildListOfPluginsToLoad(splash, monitor.createSubTaskMonitor(1, false)); 416 if (!pluginsToLoad.isEmpty() && PluginHandler.checkAndConfirmPluginUpdate(splash)) { 417 monitor.subTask(tr("Updating plugins")); 418 pluginsToLoad = PluginHandler.updatePlugins(splash, null, monitor.createSubTaskMonitor(1, false), false); 419 } 420 421 monitor.indeterminateSubTask(tr("Installing updated plugins")); 422 PluginHandler.installDownloadedPlugins(true); 423 424 monitor.indeterminateSubTask(tr("Loading early plugins")); 425 PluginHandler.loadEarlyPlugins(splash, pluginsToLoad, monitor.createSubTaskMonitor(1, false)); 426 427 monitor.indeterminateSubTask(tr("Setting defaults")); 428 preConstructorInit(args); 429 430 monitor.indeterminateSubTask(tr("Creating main GUI")); 431 final Main main = new MainApplication(mainFrame); 432 433 monitor.indeterminateSubTask(tr("Loading plugins")); 434 PluginHandler.loadLatePlugins(splash, pluginsToLoad, monitor.createSubTaskMonitor(1, false)); 435 toolbar.refreshToolbarControl(); 436 437 // Wait for splash disappearance (fix #9714) 438 GuiHelper.runInEDTAndWait(new Runnable() { 439 @Override 440 public void run() { 441 splash.setVisible(false); 442 splash.dispose(); 443 mainFrame.setVisible(true); 444 main.gettingStarted.requestFocusInWindow(); 445 } 446 }); 447 448 Main.MasterWindowListener.setup(); 449 450 boolean maximized = Main.pref.getBoolean("gui.maximized", false); 451 if ((!args.containsKey(Option.NO_MAXIMIZE) && maximized) || args.containsKey(Option.MAXIMIZE)) { 452 if (Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH)) { 453 Main.windowState = JFrame.MAXIMIZED_BOTH; 454 mainFrame.setExtendedState(Main.windowState); 455 } else { 456 Main.debug("Main window: maximizing not supported"); 457 } 458 } 459 if (main.menu.fullscreenToggleAction != null) { 460 main.menu.fullscreenToggleAction.initial(); 461 } 462 463 SwingUtilities.invokeLater(new GuiFinalizationWorker(args, proxySelector)); 464 465 if (Main.isPlatformWindows()) { 466 try { 467 // Check for insecure certificates to remove. 468 // This is Windows-dependant code but it can't go to preStartupHook (need i18n) neither startupHook (need to be called before remote control) 469 PlatformHookWindows.removeInsecureCertificates(); 470 } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | IOException e) { 471 error(e); 472 } 473 } 474 475 if (RemoteControl.PROP_REMOTECONTROL_ENABLED.get()) { 476 RemoteControl.start(); 477 } 478 479 if (MessageNotifier.PROP_NOTIFIER_ENABLED.get()) { 480 MessageNotifier.start(); 481 } 482 483 if (Main.pref.getBoolean("debug.edt-checker.enable", Version.getInstance().isLocalBuild())) { 484 // Repaint manager is registered so late for a reason - there is lots of violation during startup process but they don't seem to break anything and are difficult to fix 485 info("Enabled EDT checker, wrongful access to gui from non EDT thread will be printed to console"); 486 RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager()); 487 } 488 } 489 490 private static void handleSpecialLanguages() { 491 // Use special font for Khmer script, as the default Java font do not display these characters 492 if ("km".equals(Main.pref.get("language"))) { 493 Collection<String> fonts = Arrays.asList( 494 GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()); 495 for (String f : new String[]{"Khmer UI", "DaunPenh", "MoolBoran"}) { 496 if (fonts.contains(f)) { 497 GuiHelper.setUIFont(f); 498 break; 499 } 500 } 501 } 502 } 503 504 private static void processOffline(Map<Option, Collection<String>> args) { 505 if (args.containsKey(Option.OFFLINE)) { 506 for (String s : args.get(Option.OFFLINE).iterator().next().split(",")) { 507 try { 508 Main.setOffline(OnlineResource.valueOf(s.toUpperCase())); 509 } catch (IllegalArgumentException e) { 510 Main.error(tr("''{0}'' is not a valid value for argument ''{1}''. Possible values are {2}, possibly delimited by commas.", 511 s.toUpperCase(), Option.OFFLINE.getName(), Arrays.toString(OnlineResource.values()))); 512 System.exit(1); 513 return; 514 } 515 } 516 Set<OnlineResource> offline = Main.getOfflineResources(); 517 if (!offline.isEmpty()) { 518 Main.warn(trn("JOSM is running in offline mode. This resource will not be available: {0}", 519 "JOSM is running in offline mode. These resources will not be available: {0}", 520 offline.size(), offline.size() == 1 ? offline.iterator().next() : Arrays.toString(offline.toArray()))); 521 } 522 } 523 } 524 525 private static class GuiFinalizationWorker implements Runnable { 526 527 private final Map<Option, Collection<String>> args; 528 private final DefaultProxySelector proxySelector; 529 530 public GuiFinalizationWorker(Map<Option, Collection<String>> args, DefaultProxySelector proxySelector) { 531 this.args = args; 532 this.proxySelector = proxySelector; 533 } 534 535 @Override 536 public void run() { 537 538 // Handle proxy/network errors early to inform user he should change settings to be able to use JOSM correctly 539 if (!handleProxyErrors()) { 540 handleNetworkErrors(); 541 } 542 543 // Restore autosave layers after crash and start autosave thread 544 handleAutosave(); 545 546 // Handle command line instructions 547 postConstructorProcessCmdLine(args); 548 549 // Show download dialog if autostart is enabled 550 DownloadDialog.autostartIfNeeded(); 551 } 552 553 private void handleAutosave() { 554 if (AutosaveTask.PROP_AUTOSAVE_ENABLED.get()) { 555 AutosaveTask autosaveTask = new AutosaveTask(); 556 List<File> unsavedLayerFiles = autosaveTask.getUnsavedLayersFiles(); 557 if (!unsavedLayerFiles.isEmpty()) { 558 ExtendedDialog dialog = new ExtendedDialog( 559 Main.parent, 560 tr("Unsaved osm data"), 561 new String[] {tr("Restore"), tr("Cancel"), tr("Discard")} 562 ); 563 dialog.setContent( 564 trn("JOSM found {0} unsaved osm data layer. ", 565 "JOSM found {0} unsaved osm data layers. ", unsavedLayerFiles.size(), unsavedLayerFiles.size()) + 566 tr("It looks like JOSM crashed last time. Would you like to restore the data?")); 567 dialog.setButtonIcons(new String[] {"ok", "cancel", "dialogs/delete"}); 568 int selection = dialog.showDialog().getValue(); 569 if (selection == 1) { 570 autosaveTask.recoverUnsavedLayers(); 571 } else if (selection == 3) { 572 autosaveTask.discardUnsavedLayers(); 573 } 574 } 575 autosaveTask.schedule(); 576 } 577 } 578 579 private boolean handleNetworkOrProxyErrors(boolean hasErrors, String title, String message) { 580 if (hasErrors) { 581 ExtendedDialog ed = new ExtendedDialog( 582 Main.parent, title, 583 new String[]{tr("Change proxy settings"), tr("Cancel")}); 584 ed.setButtonIcons(new String[]{"dialogs/settings", "cancel"}).setCancelButton(2); 585 ed.setMinimumSize(new Dimension(460, 260)); 586 ed.setIcon(JOptionPane.WARNING_MESSAGE); 587 ed.setContent(message); 588 589 if (ed.showDialog().getValue() == 1) { 590 PreferencesAction.forPreferenceSubTab(null, null, ProxyPreference.class).run(); 591 } 592 } 593 return hasErrors; 594 } 595 596 private boolean handleProxyErrors() { 597 return handleNetworkOrProxyErrors(proxySelector.hasErrors(), tr("Proxy errors occurred"), 598 tr("JOSM tried to access the following resources:<br>" + 599 "{0}" + 600 "but <b>failed</b> to do so, because of the following proxy errors:<br>" + 601 "{1}" + 602 "Would you like to change your proxy settings now?", 603 Utils.joinAsHtmlUnorderedList(proxySelector.getErrorResources()), 604 Utils.joinAsHtmlUnorderedList(proxySelector.getErrorMessages()) 605 )); 606 } 607 608 private boolean handleNetworkErrors() { 609 boolean condition = !NETWORK_ERRORS.isEmpty(); 610 if (condition) { 611 Set<String> errors = new TreeSet<>(); 612 for (Throwable t : NETWORK_ERRORS.values()) { 613 errors.add(t.toString()); 614 } 615 return handleNetworkOrProxyErrors(condition, tr("Network errors occurred"), 616 tr("JOSM tried to access the following resources:<br>" + 617 "{0}" + 618 "but <b>failed</b> to do so, because of the following network errors:<br>" + 619 "{1}" + 620 "It may be due to a missing proxy configuration.<br>" + 621 "Would you like to change your proxy settings now?", 622 Utils.joinAsHtmlUnorderedList(NETWORK_ERRORS.keySet()), 623 Utils.joinAsHtmlUnorderedList(errors) 624 )); 625 } 626 return false; 627 } 628 } 629}