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 FontsManager.initialize(); 370 371 handleSpecialLanguages(); 372 373 final JFrame mainFrame = new JFrame(tr("Java OpenStreetMap Editor")); 374 Main.parent = mainFrame; 375 376 if (args.containsKey(Option.LOAD_PREFERENCES)) { 377 CustomConfigurator.XMLCommandProcessor config = new CustomConfigurator.XMLCommandProcessor(Main.pref); 378 for (String i : args.get(Option.LOAD_PREFERENCES)) { 379 info("Reading preferences from " + i); 380 try (InputStream is = Utils.openURL(new URL(i))) { 381 config.openAndReadXML(is); 382 } catch (Exception ex) { 383 throw new RuntimeException(ex); 384 } 385 } 386 } 387 388 if (args.containsKey(Option.SET)) { 389 for (String i : args.get(Option.SET)) { 390 String[] kv = i.split("=", 2); 391 Main.pref.put(kv[0], "null".equals(kv[1]) ? null : kv[1]); 392 } 393 } 394 395 DefaultAuthenticator.createInstance(); 396 Authenticator.setDefault(DefaultAuthenticator.getInstance()); 397 DefaultProxySelector proxySelector = new DefaultProxySelector(ProxySelector.getDefault()); 398 ProxySelector.setDefault(proxySelector); 399 OAuthAccessTokenHolder.getInstance().init(Main.pref, CredentialsManager.getInstance()); 400 401 final SplashScreen splash = new SplashScreen(); 402 final ProgressMonitor monitor = splash.getProgressMonitor(); 403 monitor.beginTask(tr("Initializing")); 404 splash.setVisible(Main.pref.getBoolean("draw.splashscreen", true)); 405 Main.setInitStatusListener(new InitStatusListener() { 406 407 @Override 408 public void updateStatus(String event) { 409 monitor.indeterminateSubTask(event); 410 } 411 }); 412 413 Collection<PluginInformation> pluginsToLoad = PluginHandler.buildListOfPluginsToLoad(splash,monitor.createSubTaskMonitor(1, false)); 414 if (!pluginsToLoad.isEmpty() && PluginHandler.checkAndConfirmPluginUpdate(splash)) { 415 monitor.subTask(tr("Updating plugins")); 416 pluginsToLoad = PluginHandler.updatePlugins(splash, null, monitor.createSubTaskMonitor(1, false), false); 417 } 418 419 monitor.indeterminateSubTask(tr("Installing updated plugins")); 420 PluginHandler.installDownloadedPlugins(true); 421 422 monitor.indeterminateSubTask(tr("Loading early plugins")); 423 PluginHandler.loadEarlyPlugins(splash,pluginsToLoad, monitor.createSubTaskMonitor(1, false)); 424 425 monitor.indeterminateSubTask(tr("Setting defaults")); 426 preConstructorInit(args); 427 428 monitor.indeterminateSubTask(tr("Creating main GUI")); 429 final Main main = new MainApplication(mainFrame); 430 431 monitor.indeterminateSubTask(tr("Loading plugins")); 432 PluginHandler.loadLatePlugins(splash,pluginsToLoad, monitor.createSubTaskMonitor(1, false)); 433 toolbar.refreshToolbarControl(); 434 435 // Wait for splash disappearance (fix #9714) 436 GuiHelper.runInEDTAndWait(new Runnable() { 437 @Override 438 public void run() { 439 splash.setVisible(false); 440 splash.dispose(); 441 mainFrame.setVisible(true); 442 } 443 }); 444 445 Main.MasterWindowListener.setup(); 446 447 boolean maximized = Main.pref.getBoolean("gui.maximized", false); 448 if ((!args.containsKey(Option.NO_MAXIMIZE) && maximized) || args.containsKey(Option.MAXIMIZE)) { 449 if (Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH)) { 450 Main.windowState = JFrame.MAXIMIZED_BOTH; 451 mainFrame.setExtendedState(Main.windowState); 452 } else { 453 Main.debug("Main window: maximizing not supported"); 454 } 455 } 456 if (main.menu.fullscreenToggleAction != null) { 457 main.menu.fullscreenToggleAction.initial(); 458 } 459 460 SwingUtilities.invokeLater(new GuiFinalizationWorker(args, proxySelector)); 461 462 if (Main.isPlatformWindows()) { 463 try { 464 // Check for insecure certificates to remove. 465 // This is Windows-dependant code but it can't go to preStartupHook (need i18n) neither startupHook (need to be called before remote control) 466 PlatformHookWindows.removeInsecureCertificates(); 467 } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | IOException e) { 468 error(e); 469 } 470 } 471 472 if (RemoteControl.PROP_REMOTECONTROL_ENABLED.get()) { 473 RemoteControl.start(); 474 } 475 476 if (MessageNotifier.PROP_NOTIFIER_ENABLED.get()) { 477 MessageNotifier.start(); 478 } 479 480 if (Main.pref.getBoolean("debug.edt-checker.enable", Version.getInstance().isLocalBuild())) { 481 // 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 482 info("Enabled EDT checker, wrongful access to gui from non EDT thread will be printed to console"); 483 RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager()); 484 } 485 } 486 487 private static void handleSpecialLanguages() { 488 // Use special font for Khmer script, as the default Java font do not display these characters 489 if ("km".equals(Main.pref.get("language"))) { 490 Collection<String> fonts = Arrays.asList( 491 GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()); 492 for (String f : new String[]{"Khmer UI", "DaunPenh", "MoolBoran"}) { 493 if (fonts.contains(f)) { 494 GuiHelper.setUIFont(f); 495 break; 496 } 497 } 498 } 499 } 500 501 private static void processOffline(Map<Option, Collection<String>> args) { 502 if (args.containsKey(Option.OFFLINE)) { 503 for (String s : args.get(Option.OFFLINE).iterator().next().split(",")) { 504 try { 505 Main.setOffline(OnlineResource.valueOf(s.toUpperCase())); 506 } catch (IllegalArgumentException e) { 507 Main.error(tr("''{0}'' is not a valid value for argument ''{1}''. Possible values are {2}, possibly delimited by commas.", 508 s.toUpperCase(), Option.OFFLINE.getName(), Arrays.toString(OnlineResource.values()))); 509 System.exit(1); 510 return; 511 } 512 } 513 Set<OnlineResource> offline = Main.getOfflineResources(); 514 if (!offline.isEmpty()) { 515 Main.warn(trn("JOSM is running in offline mode. This resource will not be available: {0}", 516 "JOSM is running in offline mode. These resources will not be available: {0}", 517 offline.size(), offline.size() == 1 ? offline.iterator().next() : Arrays.toString(offline.toArray()))); 518 } 519 } 520 } 521 522 private static class GuiFinalizationWorker implements Runnable { 523 524 private final Map<Option, Collection<String>> args; 525 private final DefaultProxySelector proxySelector; 526 527 public GuiFinalizationWorker(Map<Option, Collection<String>> args, DefaultProxySelector proxySelector) { 528 this.args = args; 529 this.proxySelector = proxySelector; 530 } 531 532 @Override 533 public void run() { 534 535 // Handle proxy/network errors early to inform user he should change settings to be able to use JOSM correctly 536 if (!handleProxyErrors()) { 537 handleNetworkErrors(); 538 } 539 540 // Restore autosave layers after crash and start autosave thread 541 handleAutosave(); 542 543 // Handle command line instructions 544 postConstructorProcessCmdLine(args); 545 546 // Show download dialog if autostart is enabled 547 DownloadDialog.autostartIfNeeded(); 548 } 549 550 private void handleAutosave() { 551 if (AutosaveTask.PROP_AUTOSAVE_ENABLED.get()) { 552 AutosaveTask autosaveTask = new AutosaveTask(); 553 List<File> unsavedLayerFiles = autosaveTask.getUnsavedLayersFiles(); 554 if (!unsavedLayerFiles.isEmpty()) { 555 ExtendedDialog dialog = new ExtendedDialog( 556 Main.parent, 557 tr("Unsaved osm data"), 558 new String[] {tr("Restore"), tr("Cancel"), tr("Discard")} 559 ); 560 dialog.setContent( 561 trn("JOSM found {0} unsaved osm data layer. ", 562 "JOSM found {0} unsaved osm data layers. ", unsavedLayerFiles.size(), unsavedLayerFiles.size()) + 563 tr("It looks like JOSM crashed last time. Would you like to restore the data?")); 564 dialog.setButtonIcons(new String[] {"ok", "cancel", "dialogs/delete"}); 565 int selection = dialog.showDialog().getValue(); 566 if (selection == 1) { 567 autosaveTask.recoverUnsavedLayers(); 568 } else if (selection == 3) { 569 autosaveTask.discardUnsavedLayers(); 570 } 571 } 572 autosaveTask.schedule(); 573 } 574 } 575 576 private boolean handleNetworkOrProxyErrors(boolean hasErrors, String title, String message) { 577 if (hasErrors) { 578 ExtendedDialog ed = new ExtendedDialog( 579 Main.parent, title, 580 new String[]{tr("Change proxy settings"), tr("Cancel")}); 581 ed.setButtonIcons(new String[]{"dialogs/settings.png", "cancel.png"}).setCancelButton(2); 582 ed.setMinimumSize(new Dimension(460, 260)); 583 ed.setIcon(JOptionPane.WARNING_MESSAGE); 584 ed.setContent(message); 585 586 if (ed.showDialog().getValue() == 1) { 587 PreferencesAction.forPreferenceSubTab(null, null, ProxyPreference.class).run(); 588 } 589 } 590 return hasErrors; 591 } 592 593 private boolean handleProxyErrors() { 594 return handleNetworkOrProxyErrors(proxySelector.hasErrors(), tr("Proxy errors occurred"), 595 tr("JOSM tried to access the following resources:<br>" + 596 "{0}" + 597 "but <b>failed</b> to do so, because of the following proxy errors:<br>" + 598 "{1}" + 599 "Would you like to change your proxy settings now?", 600 Utils.joinAsHtmlUnorderedList(proxySelector.getErrorResources()), 601 Utils.joinAsHtmlUnorderedList(proxySelector.getErrorMessages()) 602 )); 603 } 604 605 private boolean handleNetworkErrors() { 606 boolean condition = !NETWORK_ERRORS.isEmpty(); 607 if (condition) { 608 Set<String> errors = new TreeSet<>(); 609 for (Throwable t : NETWORK_ERRORS.values()) { 610 errors.add(t.toString()); 611 } 612 return handleNetworkOrProxyErrors(condition, tr("Network errors occurred"), 613 tr("JOSM tried to access the following resources:<br>" + 614 "{0}" + 615 "but <b>failed</b> to do so, because of the following network errors:<br>" + 616 "{1}" + 617 "It may be due to a missing proxy configuration.<br>" + 618 "Would you like to change your proxy settings now?", 619 Utils.joinAsHtmlUnorderedList(NETWORK_ERRORS.keySet()), 620 Utils.joinAsHtmlUnorderedList(errors) 621 )); 622 } 623 return false; 624 } 625 } 626}