source: josm/trunk/src/org/openstreetmap/josm/gui/MainApplication.java@ 8644

Last change on this file since 8644 was 8562, checked in by bastiK, 9 years ago

fixed splash deadlock for java 7 (fixes #11591, see #11355)

  • Property svn:eol-style set to native
File size: 30.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6import gnu.getopt.Getopt;
7import gnu.getopt.LongOpt;
8
9import java.awt.Dimension;
10import java.awt.Image;
11import java.awt.Toolkit;
12import java.awt.event.WindowAdapter;
13import java.awt.event.WindowEvent;
14import java.io.File;
15import java.io.IOException;
16import java.io.InputStream;
17import java.net.Authenticator;
18import java.net.Inet6Address;
19import java.net.InetAddress;
20import java.net.ProxySelector;
21import java.net.URL;
22import java.security.AllPermission;
23import java.security.CodeSource;
24import java.security.KeyStoreException;
25import java.security.NoSuchAlgorithmException;
26import java.security.PermissionCollection;
27import java.security.Permissions;
28import java.security.Policy;
29import java.security.cert.CertificateException;
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.Collection;
33import java.util.EnumMap;
34import java.util.LinkedList;
35import java.util.List;
36import java.util.Locale;
37import java.util.Map;
38import java.util.Set;
39import java.util.TreeSet;
40import java.util.concurrent.Callable;
41
42import javax.swing.JFrame;
43import javax.swing.JOptionPane;
44import javax.swing.RepaintManager;
45import javax.swing.SwingUtilities;
46
47import org.jdesktop.swinghelper.debug.CheckThreadViolationRepaintManager;
48import org.openstreetmap.josm.Main;
49import org.openstreetmap.josm.actions.PreferencesAction;
50import org.openstreetmap.josm.data.AutosaveTask;
51import org.openstreetmap.josm.data.CustomConfigurator;
52import org.openstreetmap.josm.data.Version;
53import org.openstreetmap.josm.gui.download.DownloadDialog;
54import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder;
55import org.openstreetmap.josm.gui.preferences.server.ProxyPreference;
56import org.openstreetmap.josm.gui.util.GuiHelper;
57import org.openstreetmap.josm.io.DefaultProxySelector;
58import org.openstreetmap.josm.io.MessageNotifier;
59import org.openstreetmap.josm.io.OnlineResource;
60import org.openstreetmap.josm.io.auth.CredentialsManager;
61import org.openstreetmap.josm.io.auth.DefaultAuthenticator;
62import org.openstreetmap.josm.io.remotecontrol.RemoteControl;
63import org.openstreetmap.josm.plugins.PluginHandler;
64import org.openstreetmap.josm.plugins.PluginInformation;
65import org.openstreetmap.josm.tools.BugReportExceptionHandler;
66import org.openstreetmap.josm.tools.FontsManager;
67import org.openstreetmap.josm.tools.I18n;
68import org.openstreetmap.josm.tools.ImageProvider;
69import org.openstreetmap.josm.tools.OsmUrlToBounds;
70import org.openstreetmap.josm.tools.PlatformHookWindows;
71import org.openstreetmap.josm.tools.Utils;
72
73/**
74 * Main window class application.
75 *
76 * @author imi
77 */
78public class MainApplication extends Main {
79
80 /**
81 * Constructs a new {@code MainApplication}.
82 */
83 public MainApplication() {
84 // Allow subclassing (see JOSM.java)
85 }
86
87 /**
88 * Constructs a main frame, ready sized and operating. Does not display the frame.
89 * @param mainFrame The main JFrame of the application
90 */
91 public MainApplication(JFrame mainFrame) {
92 addListener();
93 mainFrame.setContentPane(contentPanePrivate);
94 mainFrame.setJMenuBar(menu);
95 geometry.applySafe(mainFrame);
96 List<Image> l = new LinkedList<>();
97 l.add(ImageProvider.get("logo_16x16x32").getImage());
98 l.add(ImageProvider.get("logo_16x16x8").getImage());
99 l.add(ImageProvider.get("logo_32x32x32").getImage());
100 l.add(ImageProvider.get("logo_32x32x8").getImage());
101 l.add(ImageProvider.get("logo_48x48x32").getImage());
102 l.add(ImageProvider.get("logo_48x48x8").getImage());
103 l.add(ImageProvider.get("logo").getImage());
104 mainFrame.setIconImages(l);
105 mainFrame.addWindowListener(new WindowAdapter() {
106 @Override
107 public void windowClosing(final WindowEvent arg0) {
108 Main.exitJosm(true, 0);
109 }
110 });
111 mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
112 }
113
114 /**
115 * Displays help on the console
116 * @since 2748
117 */
118 public static void showHelp() {
119 // TODO: put in a platformHook for system that have no console by default
120 System.out.println(tr("Java OpenStreetMap Editor")+" ["
121 +Version.getInstance().getAgentString()+"]\n\n"+
122 tr("usage")+":\n"+
123 "\tjava -jar josm.jar <options>...\n\n"+
124 tr("options")+":\n"+
125 "\t--help|-h "+tr("Show this help")+"\n"+
126 "\t--geometry=widthxheight(+|-)x(+|-)y "+tr("Standard unix geometry argument")+"\n"+
127 "\t[--download=]minlat,minlon,maxlat,maxlon "+tr("Download the bounding box")+"\n"+
128 "\t[--download=]<URL> "+tr("Download the location at the URL (with lat=x&lon=y&zoom=z)")+"\n"+
129 "\t[--download=]<filename> "+tr("Open a file (any file type that can be opened with File/Open)")+"\n"+
130 "\t--downloadgps=minlat,minlon,maxlat,maxlon "+tr("Download the bounding box as raw GPS")+"\n"+
131 "\t--downloadgps=<URL> "+tr("Download the location at the URL (with lat=x&lon=y&zoom=z) as raw GPS")+"\n"+
132 "\t--selection=<searchstring> "+tr("Select with the given search")+"\n"+
133 "\t--[no-]maximize "+tr("Launch in maximized mode")+"\n"+
134 "\t--reset-preferences "+tr("Reset the preferences to default")+"\n\n"+
135 "\t--load-preferences=<url-to-xml> "+tr("Changes preferences according to the XML file")+"\n\n"+
136 "\t--set=<key>=<value> "+tr("Set preference key to value")+"\n\n"+
137 "\t--language=<language> "+tr("Set the language")+"\n\n"+
138 "\t--version "+tr("Displays the JOSM version and exits")+"\n\n"+
139 "\t--debug "+tr("Print debugging messages to console")+"\n\n"+
140 "\t--skip-plugins "+tr("Skip loading plugins")+"\n\n"+
141 "\t--offline=<osm_api|josm_website|all> "+tr("Disable access to the given resource(s), separated by comma")+"\n\n"+
142 tr("options provided as Java system properties")+":\n"+
143 "\t-Djosm.pref=" +tr("/PATH/TO/JOSM/PREF ")+tr("Set the preferences directory")+"\n\n"+
144 "\t-Djosm.userdata="+tr("/PATH/TO/JOSM/USERDATA")+tr("Set the user data directory")+"\n\n"+
145 "\t-Djosm.cache=" +tr("/PATH/TO/JOSM/CACHE ")+tr("Set the cache directory")+"\n\n"+
146 "\t-Djosm.home=" +tr("/PATH/TO/JOSM/HOMEDIR ")+
147 tr("Relocate all 3 directories to homedir. Cache directory will be in homedir/cache")+"\n\n"+
148 tr("-Djosm.home has lower precedence, i.e. the specific setting overrides the general one")+"\n\n"+
149 tr("note: For some tasks, JOSM needs a lot of memory. It can be necessary to add the following\n" +
150 " Java option to specify the maximum size of allocated memory in megabytes")+":\n"+
151 "\t-Xmx...m\n\n"+
152 tr("examples")+":\n"+
153 "\tjava -jar josm.jar track1.gpx track2.gpx london.osm\n"+
154 "\tjava -jar josm.jar "+OsmUrlToBounds.getURL(43.2, 11.1, 13)+"\n"+
155 "\tjava -jar josm.jar london.osm --selection=http://www.ostertag.name/osm/OSM_errors_node-duplicate.xml\n"+
156 "\tjava -jar josm.jar 43.2,11.1,43.4,11.4\n"+
157 "\tjava -Djosm.pref=$XDG_CONFIG_HOME -Djosm.userdata=$XDG_DATA_HOME -Djosm.cache=$XDG_CACHE_HOME -jar josm.jar\n"+
158 "\tjava -Djosm.home=/home/user/.josm_dev -jar josm.jar\n"+
159 "\tjava -Xmx1024m -jar josm.jar\n\n"+
160 tr("Parameters --download, --downloadgps, and --selection are processed in this order.")+"\n"+
161 tr("Make sure you load some data if you use --selection.")+"\n"
162 );
163 }
164
165 /**
166 * JOSM command line options.
167 * @see <a href="https://josm.openstreetmap.de/wiki/Help/CommandLineOptions">Help/CommandLineOptions</a>
168 * @since 5279
169 */
170 public enum Option {
171 /** --help|-h Show this help */
172 HELP(false),
173 /** --version Displays the JOSM version and exits */
174 VERSION(false),
175 /** --debug Print debugging messages to console */
176 DEBUG(false),
177 /** --trace Print detailed debugging messages to console */
178 TRACE(false),
179 /** --language=&lt;language&gt; Set the language */
180 LANGUAGE(true),
181 /** --reset-preferences Reset the preferences to default */
182 RESET_PREFERENCES(false),
183 /** --load-preferences=&lt;url-to-xml&gt; Changes preferences according to the XML file */
184 LOAD_PREFERENCES(true),
185 /** --set=&lt;key&gt;=&lt;value&gt; Set preference key to value */
186 SET(true),
187 /** --geometry=widthxheight(+|-)x(+|-)y Standard unix geometry argument */
188 GEOMETRY(true),
189 /** --no-maximize Do not launch in maximized mode */
190 NO_MAXIMIZE(false),
191 /** --maximize Launch in maximized mode */
192 MAXIMIZE(false),
193 /** --download=minlat,minlon,maxlat,maxlon Download the bounding box <br>
194 * --download=&lt;URL&gt; Download the location at the URL (with lat=x&amp;lon=y&amp;zoom=z) <br>
195 * --download=&lt;filename&gt; Open a file (any file type that can be opened with File/Open) */
196 DOWNLOAD(true),
197 /** --downloadgps=minlat,minlon,maxlat,maxlon Download the bounding box as raw GPS <br>
198 * --downloadgps=&lt;URL&gt; Download the location at the URL (with lat=x&amp;lon=y&amp;zoom=z) as raw GPS */
199 DOWNLOADGPS(true),
200 /** --selection=&lt;searchstring&gt; Select with the given search */
201 SELECTION(true),
202 /** --offline=&lt;osm_api|josm_website|all&gt; Disable access to the given resource(s), delimited by comma */
203 OFFLINE(true),
204 /** --skip-plugins */
205 SKIP_PLUGINS(false);
206
207 private final String name;
208 private final boolean requiresArg;
209
210 private Option(boolean requiresArgument) {
211 this.name = name().toLowerCase(Locale.ENGLISH).replace("_", "-");
212 this.requiresArg = requiresArgument;
213 }
214
215 /**
216 * Replies the option name
217 * @return The option name, in lowercase
218 */
219 public String getName() {
220 return name;
221 }
222
223 /**
224 * Determines if this option requires an argument.
225 * @return {@code true} if this option requires an argument, {@code false} otherwise
226 */
227 public boolean requiresArgument() {
228 return requiresArg;
229 }
230 }
231
232 private static Map<Option, Collection<String>> buildCommandLineArgumentMap(String[] args) {
233
234 List<LongOpt> los = new ArrayList<>();
235 for (Option o : Option.values()) {
236 los.add(new LongOpt(o.getName(), o.requiresArgument() ? LongOpt.REQUIRED_ARGUMENT : LongOpt.NO_ARGUMENT, null, 0));
237 }
238
239 Getopt g = new Getopt("JOSM", args, "hv", los.toArray(new LongOpt[los.size()]));
240
241 Map<Option, Collection<String>> argMap = new EnumMap<>(Option.class);
242
243 int c;
244 while ((c = g.getopt()) != -1) {
245 Option opt = null;
246 switch (c) {
247 case 'h':
248 opt = Option.HELP;
249 break;
250 case 'v':
251 opt = Option.VERSION;
252 break;
253 case 0:
254 opt = Option.values()[g.getLongind()];
255 break;
256 }
257 if (opt != null) {
258 Collection<String> values = argMap.get(opt);
259 if (values == null) {
260 values = new ArrayList<>();
261 argMap.put(opt, values);
262 }
263 values.add(g.getOptarg());
264 } else
265 throw new IllegalArgumentException("Invalid option: "+c);
266 }
267 // positional arguments are a shortcut for the --download ... option
268 for (int i = g.getOptind(); i < args.length; ++i) {
269 Collection<String> values = argMap.get(Option.DOWNLOAD);
270 if (values == null) {
271 values = new ArrayList<>();
272 argMap.put(Option.DOWNLOAD, values);
273 }
274 values.add(args[i]);
275 }
276
277 return argMap;
278 }
279
280 /**
281 * Main application Startup
282 * @param argArray Command-line arguments
283 */
284 public static void main(final String[] argArray) {
285 I18n.init();
286 Main.checkJavaVersion();
287
288 // construct argument table
289 Map<Option, Collection<String>> args = null;
290 try {
291 args = buildCommandLineArgumentMap(argArray);
292 } catch (IllegalArgumentException e) {
293 System.exit(1);
294 return;
295 }
296
297 final boolean languageGiven = args.containsKey(Option.LANGUAGE);
298
299 if (languageGiven) {
300 I18n.set(args.get(Option.LANGUAGE).iterator().next());
301 }
302
303 initApplicationPreferences();
304
305 Policy.setPolicy(new Policy() {
306 // Permissions for plug-ins loaded when josm is started via webstart
307 private PermissionCollection pc;
308
309 {
310 pc = new Permissions();
311 pc.add(new AllPermission());
312 }
313
314 @Override
315 public PermissionCollection getPermissions(CodeSource codesource) {
316 return pc;
317 }
318 });
319
320 Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler());
321
322 // initialize the platform hook, and
323 Main.determinePlatformHook();
324 // call the really early hook before we do anything else
325 Main.platform.preStartupHook();
326
327 Main.COMMAND_LINE_ARGS.addAll(Arrays.asList(argArray));
328
329 if (args.containsKey(Option.VERSION)) {
330 System.out.println(Version.getInstance().getAgentString());
331 System.exit(0);
332 }
333
334 if (args.containsKey(Option.DEBUG) || args.containsKey(Option.TRACE)) {
335 // Enable JOSM debug level
336 logLevel = 4;
337 Main.info(tr("Printing debugging messages to console"));
338 }
339
340 boolean skipLoadingPlugins = false;
341 if (args.containsKey(Option.SKIP_PLUGINS)) {
342 skipLoadingPlugins = true;
343 Main.info(tr("Plugin loading skipped"));
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 (args.containsKey(Option.SET)) {
357 for (String i : args.get(Option.SET)) {
358 String[] kv = i.split("=", 2);
359 Main.pref.put(kv[0], "null".equals(kv[1]) ? null : kv[1]);
360 }
361 }
362
363 if (!languageGiven) {
364 I18n.set(Main.pref.get("language", null));
365 }
366 Main.pref.updateSystemProperties();
367
368 checkIPv6();
369
370 // asking for help? show help and exit
371 if (args.containsKey(Option.HELP)) {
372 showHelp();
373 System.exit(0);
374 }
375
376 processOffline(args);
377
378 Main.platform.afterPrefStartupHook();
379
380 FontsManager.initialize();
381
382 I18n.setupLanguageFonts();
383
384 final JFrame mainFrame = new JFrame(tr("Java OpenStreetMap Editor"));
385 Main.parent = mainFrame;
386
387 if (args.containsKey(Option.LOAD_PREFERENCES)) {
388 CustomConfigurator.XMLCommandProcessor config = new CustomConfigurator.XMLCommandProcessor(Main.pref);
389 for (String i : args.get(Option.LOAD_PREFERENCES)) {
390 info("Reading preferences from " + i);
391 try (InputStream is = Utils.openURL(new URL(i))) {
392 config.openAndReadXML(is);
393 } catch (Exception ex) {
394 throw new RuntimeException(ex);
395 }
396 }
397 }
398
399 DefaultAuthenticator.createInstance();
400 Authenticator.setDefault(DefaultAuthenticator.getInstance());
401 DefaultProxySelector proxySelector = new DefaultProxySelector(ProxySelector.getDefault());
402 ProxySelector.setDefault(proxySelector);
403 OAuthAccessTokenHolder.getInstance().init(Main.pref, CredentialsManager.getInstance());
404
405 final SplashScreen splash = GuiHelper.runInEDTAndWaitAndReturn(new Callable<SplashScreen>() {
406 @Override
407 public SplashScreen call() {
408 return new SplashScreen();
409 }
410 });
411 final SplashScreen.SplashProgressMonitor monitor = splash.getProgressMonitor();
412 monitor.beginTask(tr("Initializing"));
413 GuiHelper.runInEDT(new Runnable() {
414 @Override
415 public void run() {
416 splash.setVisible(Main.pref.getBoolean("draw.splashscreen", true));
417 }
418 });
419 Main.setInitStatusListener(new InitStatusListener() {
420
421 @Override
422 public Object updateStatus(String event) {
423 monitor.beginTask(event);
424 return event;
425 }
426
427 @Override
428 public void finish(Object status) {
429 if (status instanceof String) {
430 monitor.finishTask((String) status);
431 }
432 }
433 });
434
435 Collection<PluginInformation> pluginsToLoad = null;
436
437
438 if (!skipLoadingPlugins) {
439 pluginsToLoad = PluginHandler.buildListOfPluginsToLoad(splash, monitor.createSubTaskMonitor(1, false));
440 if (!pluginsToLoad.isEmpty() && PluginHandler.checkAndConfirmPluginUpdate(splash)) {
441 monitor.subTask(tr("Updating plugins"));
442 pluginsToLoad = PluginHandler.updatePlugins(splash, null, monitor.createSubTaskMonitor(1, false), false);
443 }
444
445 monitor.indeterminateSubTask(tr("Installing updated plugins"));
446 PluginHandler.installDownloadedPlugins(true);
447
448 monitor.indeterminateSubTask(tr("Loading early plugins"));
449 PluginHandler.loadEarlyPlugins(splash, pluginsToLoad, monitor.createSubTaskMonitor(1, false));
450 }
451
452 monitor.indeterminateSubTask(tr("Setting defaults"));
453 preConstructorInit(args);
454
455 monitor.indeterminateSubTask(tr("Creating main GUI"));
456 final Main main = new MainApplication(mainFrame);
457
458 if (!skipLoadingPlugins) {
459 monitor.indeterminateSubTask(tr("Loading plugins"));
460 PluginHandler.loadLatePlugins(splash, pluginsToLoad, monitor.createSubTaskMonitor(1, false));
461 toolbar.refreshToolbarControl();
462 }
463
464 // Wait for splash disappearance (fix #9714)
465 GuiHelper.runInEDTAndWait(new Runnable() {
466 @Override
467 public void run() {
468 splash.setVisible(false);
469 splash.dispose();
470 mainFrame.setVisible(true);
471 main.gettingStarted.requestFocusInWindow();
472 }
473 });
474
475 Main.MasterWindowListener.setup();
476
477 boolean maximized = Main.pref.getBoolean("gui.maximized", false);
478 if ((!args.containsKey(Option.NO_MAXIMIZE) && maximized) || args.containsKey(Option.MAXIMIZE)) {
479 if (Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH)) {
480 Main.windowState = JFrame.MAXIMIZED_BOTH;
481 mainFrame.setExtendedState(Main.windowState);
482 } else {
483 Main.debug("Main window: maximizing not supported");
484 }
485 }
486 if (main.menu.fullscreenToggleAction != null) {
487 main.menu.fullscreenToggleAction.initial();
488 }
489
490 SwingUtilities.invokeLater(new GuiFinalizationWorker(args, proxySelector));
491
492 if (Main.isPlatformWindows()) {
493 try {
494 // Check for insecure certificates to remove.
495 // This is Windows-dependant code but it can't go to preStartupHook (need i18n)
496 // neither startupHook (need to be called before remote control)
497 PlatformHookWindows.removeInsecureCertificates();
498 } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | IOException e) {
499 error(e);
500 }
501 }
502
503 if (RemoteControl.PROP_REMOTECONTROL_ENABLED.get()) {
504 RemoteControl.start();
505 }
506
507 if (MessageNotifier.PROP_NOTIFIER_ENABLED.get()) {
508 MessageNotifier.start();
509 }
510
511 if (Main.pref.getBoolean("debug.edt-checker.enable", Version.getInstance().isLocalBuild())) {
512 // Repaint manager is registered so late for a reason - there is lots of violation during startup process
513 // but they don't seem to break anything and are difficult to fix
514 info("Enabled EDT checker, wrongful access to gui from non EDT thread will be printed to console");
515 RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());
516 }
517 }
518
519 private static void processOffline(Map<Option, Collection<String>> args) {
520 if (args.containsKey(Option.OFFLINE)) {
521 for (String s : args.get(Option.OFFLINE).iterator().next().split(",")) {
522 try {
523 Main.setOffline(OnlineResource.valueOf(s.toUpperCase(Locale.ENGLISH)));
524 } catch (IllegalArgumentException e) {
525 Main.error(tr("''{0}'' is not a valid value for argument ''{1}''. Possible values are {2}, possibly delimited by commas.",
526 s.toUpperCase(Locale.ENGLISH), Option.OFFLINE.getName(), Arrays.toString(OnlineResource.values())));
527 System.exit(1);
528 return;
529 }
530 }
531 Set<OnlineResource> offline = Main.getOfflineResources();
532 if (!offline.isEmpty()) {
533 Main.warn(trn("JOSM is running in offline mode. This resource will not be available: {0}",
534 "JOSM is running in offline mode. These resources will not be available: {0}",
535 offline.size(), offline.size() == 1 ? offline.iterator().next() : Arrays.toString(offline.toArray())));
536 }
537 }
538 }
539
540 /**
541 * Check if IPv6 can be safely enabled and do so. Because this cannot be done after network activation,
542 * disabling or enabling IPV6 may only be done with next start.
543 */
544 private static void checkIPv6() {
545 if ("auto".equals(Main.pref.get("prefer.ipv6", "auto"))) {
546 new Thread(new Runnable() { /* this may take some time (DNS, Connect) */
547 public void run() {
548 boolean hasv6 = false;
549 boolean wasv6 = Main.pref.getBoolean("validated.ipv6", false);
550 try {
551 /* Use the check result from last run of the software, as after the test, value
552 changes have no effect anymore */
553 if (wasv6) {
554 Utils.updateSystemProperty("java.net.preferIPv6Addresses", "true");
555 }
556 for (InetAddress a : InetAddress.getAllByName("josm.openstreetmap.de")) {
557 if (a instanceof Inet6Address) {
558 if (a.isReachable(1000)) {
559 Utils.updateSystemProperty("java.net.preferIPv6Addresses", "true");
560 if (!wasv6) {
561 Main.info(tr("Detected useable IPv6 network, prefering IPv6 over IPv4 after next restart."));
562 } else {
563 Main.info(tr("Detected useable IPv6 network, prefering IPv6 over IPv4."));
564 }
565 hasv6 = true;
566 }
567 break; /* we're done */
568 }
569 }
570 } catch (IOException | SecurityException e) {
571 if (Main.isDebugEnabled()) {
572 Main.debug("Exception while checking IPv6 connectivity: "+e);
573 }
574 }
575 if (wasv6 && !hasv6) {
576 Main.info(tr("Detected no useable IPv6 network, prefering IPv4 over IPv6 after next restart."));
577 }
578 Main.pref.put("validated.ipv6", hasv6);
579 }
580 }).start();
581 }
582 }
583
584 private static class GuiFinalizationWorker implements Runnable {
585
586 private final Map<Option, Collection<String>> args;
587 private final DefaultProxySelector proxySelector;
588
589 public GuiFinalizationWorker(Map<Option, Collection<String>> args, DefaultProxySelector proxySelector) {
590 this.args = args;
591 this.proxySelector = proxySelector;
592 }
593
594 @Override
595 public void run() {
596
597 // Handle proxy/network errors early to inform user he should change settings to be able to use JOSM correctly
598 if (!handleProxyErrors()) {
599 handleNetworkErrors();
600 }
601
602 // Restore autosave layers after crash and start autosave thread
603 handleAutosave();
604
605 // Handle command line instructions
606 postConstructorProcessCmdLine(args);
607
608 // Show download dialog if autostart is enabled
609 DownloadDialog.autostartIfNeeded();
610 }
611
612 private void handleAutosave() {
613 if (AutosaveTask.PROP_AUTOSAVE_ENABLED.get()) {
614 AutosaveTask autosaveTask = new AutosaveTask();
615 List<File> unsavedLayerFiles = autosaveTask.getUnsavedLayersFiles();
616 if (!unsavedLayerFiles.isEmpty()) {
617 ExtendedDialog dialog = new ExtendedDialog(
618 Main.parent,
619 tr("Unsaved osm data"),
620 new String[] {tr("Restore"), tr("Cancel"), tr("Discard")}
621 );
622 dialog.setContent(
623 trn("JOSM found {0} unsaved osm data layer. ",
624 "JOSM found {0} unsaved osm data layers. ", unsavedLayerFiles.size(), unsavedLayerFiles.size()) +
625 tr("It looks like JOSM crashed last time. Would you like to restore the data?"));
626 dialog.setButtonIcons(new String[] {"ok", "cancel", "dialogs/delete"});
627 int selection = dialog.showDialog().getValue();
628 if (selection == 1) {
629 autosaveTask.recoverUnsavedLayers();
630 } else if (selection == 3) {
631 autosaveTask.discardUnsavedLayers();
632 }
633 }
634 autosaveTask.schedule();
635 }
636 }
637
638 private boolean handleNetworkOrProxyErrors(boolean hasErrors, String title, String message) {
639 if (hasErrors) {
640 ExtendedDialog ed = new ExtendedDialog(
641 Main.parent, title,
642 new String[]{tr("Change proxy settings"), tr("Cancel")});
643 ed.setButtonIcons(new String[]{"dialogs/settings", "cancel"}).setCancelButton(2);
644 ed.setMinimumSize(new Dimension(460, 260));
645 ed.setIcon(JOptionPane.WARNING_MESSAGE);
646 ed.setContent(message);
647
648 if (ed.showDialog().getValue() == 1) {
649 PreferencesAction.forPreferenceSubTab(null, null, ProxyPreference.class).run();
650 }
651 }
652 return hasErrors;
653 }
654
655 private boolean handleProxyErrors() {
656 return handleNetworkOrProxyErrors(proxySelector.hasErrors(), tr("Proxy errors occurred"),
657 tr("JOSM tried to access the following resources:<br>" +
658 "{0}" +
659 "but <b>failed</b> to do so, because of the following proxy errors:<br>" +
660 "{1}" +
661 "Would you like to change your proxy settings now?",
662 Utils.joinAsHtmlUnorderedList(proxySelector.getErrorResources()),
663 Utils.joinAsHtmlUnorderedList(proxySelector.getErrorMessages())
664 ));
665 }
666
667 private boolean handleNetworkErrors() {
668 boolean condition = !NETWORK_ERRORS.isEmpty();
669 if (condition) {
670 Set<String> errors = new TreeSet<>();
671 for (Throwable t : NETWORK_ERRORS.values()) {
672 errors.add(t.toString());
673 }
674 return handleNetworkOrProxyErrors(condition, tr("Network errors occurred"),
675 tr("JOSM tried to access the following resources:<br>" +
676 "{0}" +
677 "but <b>failed</b> to do so, because of the following network errors:<br>" +
678 "{1}" +
679 "It may be due to a missing proxy configuration.<br>" +
680 "Would you like to change your proxy settings now?",
681 Utils.joinAsHtmlUnorderedList(NETWORK_ERRORS.keySet()),
682 Utils.joinAsHtmlUnorderedList(errors)
683 ));
684 }
685 return false;
686 }
687 }
688}
Note: See TracBrowser for help on using the repository browser.