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

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

see #8465 - global use of try-with-resources, according to

  • Property svn:eol-style set to native
File size: 23.5 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.InputStream;
16import java.net.Authenticator;
17import java.net.ProxySelector;
18import java.net.URL;
19import java.security.AllPermission;
20import java.security.CodeSource;
21import java.security.PermissionCollection;
22import java.security.Permissions;
23import java.security.Policy;
24import java.util.ArrayList;
25import java.util.Collection;
26import java.util.HashMap;
27import java.util.LinkedList;
28import java.util.List;
29import java.util.Map;
30import java.util.Set;
31import java.util.TreeSet;
32
33import javax.swing.JFrame;
34import javax.swing.JOptionPane;
35import javax.swing.RepaintManager;
36import javax.swing.SwingUtilities;
37
38import org.jdesktop.swinghelper.debug.CheckThreadViolationRepaintManager;
39import org.openstreetmap.josm.Main;
40import org.openstreetmap.josm.actions.PreferencesAction;
41import org.openstreetmap.josm.data.AutosaveTask;
42import org.openstreetmap.josm.data.CustomConfigurator;
43import org.openstreetmap.josm.data.Preferences;
44import org.openstreetmap.josm.data.Version;
45import org.openstreetmap.josm.gui.download.DownloadDialog;
46import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder;
47import org.openstreetmap.josm.gui.preferences.server.ProxyPreference;
48import org.openstreetmap.josm.gui.progress.ProgressMonitor;
49import org.openstreetmap.josm.gui.util.GuiHelper;
50import org.openstreetmap.josm.io.DefaultProxySelector;
51import org.openstreetmap.josm.io.MessageNotifier;
52import org.openstreetmap.josm.io.auth.CredentialsManager;
53import org.openstreetmap.josm.io.auth.DefaultAuthenticator;
54import org.openstreetmap.josm.io.remotecontrol.RemoteControl;
55import org.openstreetmap.josm.plugins.PluginHandler;
56import org.openstreetmap.josm.plugins.PluginInformation;
57import org.openstreetmap.josm.tools.BugReportExceptionHandler;
58import org.openstreetmap.josm.tools.I18n;
59import org.openstreetmap.josm.tools.ImageProvider;
60import org.openstreetmap.josm.tools.OsmUrlToBounds;
61import org.openstreetmap.josm.tools.Utils;
62
63/**
64 * Main window class application.
65 *
66 * @author imi
67 */
68public class MainApplication extends Main {
69 /**
70 * Allow subclassing (see JOSM.java)
71 */
72 public MainApplication() {}
73
74 /**
75 * Constructs a main frame, ready sized and operating. Does not display the frame.
76 * @param mainFrame The main JFrame of the application
77 */
78 public MainApplication(JFrame mainFrame) {
79 addListener();
80 mainFrame.setContentPane(contentPanePrivate);
81 mainFrame.setJMenuBar(menu);
82 geometry.applySafe(mainFrame);
83 LinkedList<Image> l = new LinkedList<>();
84 l.add(ImageProvider.get("logo_16x16x32").getImage());
85 l.add(ImageProvider.get("logo_16x16x8").getImage());
86 l.add(ImageProvider.get("logo_32x32x32").getImage());
87 l.add(ImageProvider.get("logo_32x32x8").getImage());
88 l.add(ImageProvider.get("logo_48x48x32").getImage());
89 l.add(ImageProvider.get("logo_48x48x8").getImage());
90 l.add(ImageProvider.get("logo").getImage());
91 mainFrame.setIconImages(l);
92 mainFrame.addWindowListener(new WindowAdapter(){
93 @Override
94 public void windowClosing(final WindowEvent arg0) {
95 Main.exitJosm(true, 0);
96 }
97 });
98 mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
99 }
100
101 /**
102 * Displays help on the console
103 * @since 2748
104 */
105 public static void showHelp() {
106 // TODO: put in a platformHook for system that have no console by default
107 System.out.println(tr("Java OpenStreetMap Editor")+" ["
108 +Version.getInstance().getAgentString()+"]\n\n"+
109 tr("usage")+":\n"+
110 "\tjava -jar josm.jar <options>...\n\n"+
111 tr("options")+":\n"+
112 "\t--help|-h "+tr("Show this help")+"\n"+
113 "\t--geometry=widthxheight(+|-)x(+|-)y "+tr("Standard unix geometry argument")+"\n"+
114 "\t[--download=]minlat,minlon,maxlat,maxlon "+tr("Download the bounding box")+"\n"+
115 "\t[--download=]<URL> "+tr("Download the location at the URL (with lat=x&lon=y&zoom=z)")+"\n"+
116 "\t[--download=]<filename> "+tr("Open a file (any file type that can be opened with File/Open)")+"\n"+
117 "\t--downloadgps=minlat,minlon,maxlat,maxlon "+tr("Download the bounding box as raw GPS")+"\n"+
118 "\t--downloadgps=<URL> "+tr("Download the location at the URL (with lat=x&lon=y&zoom=z) as raw GPS")+"\n"+
119 "\t--selection=<searchstring> "+tr("Select with the given search")+"\n"+
120 "\t--[no-]maximize "+tr("Launch in maximized mode")+"\n"+
121 "\t--reset-preferences "+tr("Reset the preferences to default")+"\n\n"+
122 "\t--load-preferences=<url-to-xml> "+tr("Changes preferences according to the XML file")+"\n\n"+
123 "\t--set=<key>=<value> "+tr("Set preference key to value")+"\n\n"+
124 "\t--language=<language> "+tr("Set the language")+"\n\n"+
125 "\t--version "+tr("Displays the JOSM version and exits")+"\n\n"+
126 "\t--debug "+tr("Print debugging messages to console")+"\n\n"+
127 tr("options provided as Java system properties")+":\n"+
128 "\t-Djosm.home="+tr("/PATH/TO/JOSM/FOLDER/ ")+tr("Change the folder for all user settings")+"\n\n"+
129 tr("note: For some tasks, JOSM needs a lot of memory. It can be necessary to add the following\n" +
130 " Java option to specify the maximum size of allocated memory in megabytes")+":\n"+
131 "\t-Xmx...m\n\n"+
132 tr("examples")+":\n"+
133 "\tjava -jar josm.jar track1.gpx track2.gpx london.osm\n"+
134 "\tjava -jar josm.jar "+OsmUrlToBounds.getURL(43.2, 11.1, 13)+"\n"+
135 "\tjava -jar josm.jar london.osm --selection=http://www.ostertag.name/osm/OSM_errors_node-duplicate.xml\n"+
136 "\tjava -jar josm.jar 43.2,11.1,43.4,11.4\n"+
137 "\tjava -Djosm.home=/home/user/.josm_dev -jar josm.jar\n"+
138 "\tjava -Xmx1024m -jar josm.jar\n\n"+
139 tr("Parameters --download, --downloadgps, and --selection are processed in this order.")+"\n"+
140 tr("Make sure you load some data if you use --selection.")+"\n"
141 );
142 }
143
144 /**
145 * JOSM command line options.
146 * @see <a href="https://josm.openstreetmap.de/wiki/Help/CommandLineOptions">Help/CommandLineOptions</a>
147 * @since 5279
148 */
149 public enum Option {
150 /** --help|-h Show this help */
151 HELP(false),
152 /** --version Displays the JOSM version and exits */
153 VERSION(false),
154 /** --debug Print debugging messages to console */
155 DEBUG(false),
156 /** --language=&lt;language&gt; Set the language */
157 LANGUAGE(true),
158 /** --reset-preferences Reset the preferences to default */
159 RESET_PREFERENCES(false),
160 /** --load-preferences=&lt;url-to-xml&gt; Changes preferences according to the XML file */
161 LOAD_PREFERENCES(true),
162 /** --set=&lt;key&gt;=&lt;value&gt; Set preference key to value */
163 SET(true),
164 /** --geometry=widthxheight(+|-)x(+|-)y Standard unix geometry argument */
165 GEOMETRY(true),
166 /** --no-maximize Do not launch in maximized mode */
167 NO_MAXIMIZE(false),
168 /** --maximize Launch in maximized mode */
169 MAXIMIZE(false),
170 /** --download=minlat,minlon,maxlat,maxlon Download the bounding box <br>
171 * --download=&lt;URL&gt; Download the location at the URL (with lat=x&amp;lon=y&amp;zoom=z) <br>
172 * --download=&lt;filename&gt; Open a file (any file type that can be opened with File/Open) */
173 DOWNLOAD(true),
174 /** --downloadgps=minlat,minlon,maxlat,maxlon Download the bounding box as raw GPS <br>
175 * --downloadgps=&lt;URL&gt; Download the location at the URL (with lat=x&amp;lon=y&amp;zoom=z) as raw GPS */
176 DOWNLOADGPS(true),
177 /** --selection=&lt;searchstring&gt; Select with the given search */
178 SELECTION(true);
179
180 private String name;
181 private boolean requiresArgument;
182
183 private Option(boolean requiresArgument) {
184 this.name = name().toLowerCase().replace("_", "-");
185 this.requiresArgument = requiresArgument;
186 }
187
188 /**
189 * Replies the option name
190 * @return The option name, in lowercase
191 */
192 public String getName() {
193 return name;
194 }
195
196 /**
197 * Determines if this option requires an argument.
198 * @return {@code true} if this option requires an argument, {@code false} otherwise
199 */
200 public boolean requiresArgument() {
201 return requiresArgument;
202 }
203
204 public static Map<Option, Collection<String>> fromStringMap(Map<String, Collection<String>> opts) {
205 Map<Option, Collection<String>> res = new HashMap<>();
206 for (Map.Entry<String, Collection<String>> e : opts.entrySet()) {
207 Option o = Option.valueOf(e.getKey().toUpperCase().replace("-", "_"));
208 if (o != null) {
209 res.put(o, e.getValue());
210 }
211 }
212 return res;
213 }
214 }
215
216 private static Map<Option, Collection<String>> buildCommandLineArgumentMap(String[] args) {
217
218 List<LongOpt> los = new ArrayList<>();
219 for (Option o : Option.values()) {
220 los.add(new LongOpt(o.getName(), o.requiresArgument() ? LongOpt.REQUIRED_ARGUMENT : LongOpt.NO_ARGUMENT, null, 0));
221 }
222
223 Getopt g = new Getopt("JOSM", args, "hv", los.toArray(new LongOpt[los.size()]));
224
225 Map<Option, Collection<String>> argMap = new HashMap<>();
226
227 int c;
228 while ((c = g.getopt()) != -1 ) {
229 Option opt = null;
230 switch (c) {
231 case 'h':
232 opt = Option.HELP;
233 break;
234 case 'v':
235 opt = Option.VERSION;
236 break;
237 case 0:
238 opt = Option.values()[g.getLongind()];
239 break;
240 }
241 if (opt != null) {
242 Collection<String> values = argMap.get(opt);
243 if (values == null) {
244 values = new ArrayList<>();
245 argMap.put(opt, values);
246 }
247 values.add(g.getOptarg());
248 } else
249 throw new IllegalArgumentException();
250 }
251 // positional arguments are a shortcut for the --download ... option
252 for (int i = g.getOptind(); i < args.length; ++i) {
253 Collection<String> values = argMap.get(Option.DOWNLOAD);
254 if (values == null) {
255 values = new ArrayList<>();
256 argMap.put(Option.DOWNLOAD, values);
257 }
258 values.add(args[i]);
259 }
260
261 return argMap;
262 }
263
264 /**
265 * Main application Startup
266 * @param argArray Command-line arguments
267 */
268 public static void main(final String[] argArray) {
269 I18n.init();
270 Main.checkJavaVersion();
271
272 // construct argument table
273 Map<Option, Collection<String>> args = null;
274 try {
275 args = buildCommandLineArgumentMap(argArray);
276 } catch (IllegalArgumentException e) {
277 System.exit(1);
278 }
279
280 final boolean languageGiven = args.containsKey(Option.LANGUAGE);
281
282 if (languageGiven) {
283 I18n.set(args.get(Option.LANGUAGE).iterator().next());
284 }
285
286 initApplicationPreferences();
287
288 Policy.setPolicy(new Policy() {
289 // Permissions for plug-ins loaded when josm is started via webstart
290 private PermissionCollection pc;
291
292 {
293 pc = new Permissions();
294 pc.add(new AllPermission());
295 }
296
297 @Override
298 public void refresh() { }
299
300 @Override
301 public PermissionCollection getPermissions(CodeSource codesource) {
302 return pc;
303 }
304 });
305
306 Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler());
307
308 // initialize the platform hook, and
309 Main.determinePlatformHook();
310 // call the really early hook before we do anything else
311 Main.platform.preStartupHook();
312
313 Main.commandLineArgs = Utils.copyArray(argArray);
314
315 if (args.containsKey(Option.VERSION)) {
316 System.out.println(Version.getInstance().getAgentString());
317 System.exit(0);
318 }
319
320 if (args.containsKey(Option.DEBUG)) {
321 // Enable JOSM debug level
322 logLevel = 4;
323 // Enable debug in OAuth signpost
324 Preferences.updateSystemProperty("debug", "true");
325 Main.debug(tr("Print debugging messages to console"));
326 }
327
328 Main.pref.init(args.containsKey(Option.RESET_PREFERENCES));
329
330 if (!languageGiven) {
331 I18n.set(Main.pref.get("language", null));
332 }
333 Main.pref.updateSystemProperties();
334
335 final JFrame mainFrame = new JFrame(tr("Java OpenStreetMap Editor"));
336 Main.parent = mainFrame;
337
338 if (args.containsKey(Option.LOAD_PREFERENCES)) {
339 CustomConfigurator.XMLCommandProcessor config = new CustomConfigurator.XMLCommandProcessor(Main.pref);
340 for (String i : args.get(Option.LOAD_PREFERENCES)) {
341 info("Reading preferences from " + i);
342 try (InputStream is = Utils.openURL(new URL(i))) {
343 config.openAndReadXML(is);
344 } catch (Exception ex) {
345 throw new RuntimeException(ex);
346 }
347 }
348 }
349
350 if (args.containsKey(Option.SET)) {
351 for (String i : args.get(Option.SET)) {
352 String[] kv = i.split("=", 2);
353 Main.pref.put(kv[0], "null".equals(kv[1]) ? null : kv[1]);
354 }
355 }
356
357 DefaultAuthenticator.createInstance();
358 Authenticator.setDefault(DefaultAuthenticator.getInstance());
359 DefaultProxySelector proxySelector = new DefaultProxySelector(ProxySelector.getDefault());
360 ProxySelector.setDefault(proxySelector);
361 OAuthAccessTokenHolder.getInstance().init(Main.pref, CredentialsManager.getInstance());
362
363 // asking for help? show help and exit
364 if (args.containsKey(Option.HELP)) {
365 showHelp();
366 System.exit(0);
367 }
368
369 final SplashScreen splash = new SplashScreen();
370 final ProgressMonitor monitor = splash.getProgressMonitor();
371 monitor.beginTask(tr("Initializing"));
372 splash.setVisible(Main.pref.getBoolean("draw.splashscreen", true));
373 Main.setInitStatusListener(new InitStatusListener() {
374
375 @Override
376 public void updateStatus(String event) {
377 monitor.indeterminateSubTask(event);
378 }
379 });
380
381 Collection<PluginInformation> pluginsToLoad = PluginHandler.buildListOfPluginsToLoad(splash,monitor.createSubTaskMonitor(1, false));
382 if (!pluginsToLoad.isEmpty() && PluginHandler.checkAndConfirmPluginUpdate(splash)) {
383 monitor.subTask(tr("Updating plugins"));
384 pluginsToLoad = PluginHandler.updatePlugins(splash, null, monitor.createSubTaskMonitor(1, false), false);
385 }
386
387 monitor.indeterminateSubTask(tr("Installing updated plugins"));
388 PluginHandler.installDownloadedPlugins(true);
389
390 monitor.indeterminateSubTask(tr("Loading early plugins"));
391 PluginHandler.loadEarlyPlugins(splash,pluginsToLoad, monitor.createSubTaskMonitor(1, false));
392
393 monitor.indeterminateSubTask(tr("Setting defaults"));
394 preConstructorInit(args);
395
396 monitor.indeterminateSubTask(tr("Creating main GUI"));
397 final Main main = new MainApplication(mainFrame);
398
399 monitor.indeterminateSubTask(tr("Loading plugins"));
400 PluginHandler.loadLatePlugins(splash,pluginsToLoad, monitor.createSubTaskMonitor(1, false));
401 toolbar.refreshToolbarControl();
402
403 // Wait for splash disappearance (fix #9714)
404 GuiHelper.runInEDTAndWait(new Runnable() {
405 @Override
406 public void run() {
407 splash.setVisible(false);
408 splash.dispose();
409 mainFrame.setVisible(true);
410 }
411 });
412
413 Main.MasterWindowListener.setup();
414
415 boolean maximized = Main.pref.getBoolean("gui.maximized", false);
416 if ((!args.containsKey(Option.NO_MAXIMIZE) && maximized) || args.containsKey(Option.MAXIMIZE)) {
417 if (Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH)) {
418 Main.windowState = JFrame.MAXIMIZED_BOTH;
419 mainFrame.setExtendedState(Main.windowState);
420 } else {
421 Main.debug("Main window: maximizing not supported");
422 }
423 }
424 if (main.menu.fullscreenToggleAction != null) {
425 main.menu.fullscreenToggleAction.initial();
426 }
427
428 SwingUtilities.invokeLater(new GuiFinalizationWorker(args, proxySelector));
429
430 if (RemoteControl.PROP_REMOTECONTROL_ENABLED.get()) {
431 RemoteControl.start();
432 }
433
434 if (MessageNotifier.PROP_NOTIFIER_ENABLED.get()) {
435 MessageNotifier.start();
436 }
437
438 if (Main.pref.getBoolean("debug.edt-checker.enable", Version.getInstance().isLocalBuild())) {
439 // 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
440 info("Enabled EDT checker, wrongful access to gui from non EDT thread will be printed to console");
441 RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());
442 }
443 }
444
445 private static class GuiFinalizationWorker implements Runnable {
446
447 private final Map<Option, Collection<String>> args;
448 private final DefaultProxySelector proxySelector;
449
450 public GuiFinalizationWorker(Map<Option, Collection<String>> args, DefaultProxySelector proxySelector) {
451 this.args = args;
452 this.proxySelector = proxySelector;
453 }
454
455 @Override
456 public void run() {
457
458 // Handle proxy/network errors early to inform user he should change settings to be able to use JOSM correctly
459 if (!handleProxyErrors()) {
460 handleNetworkErrors();
461 }
462
463 // Restore autosave layers after crash and start autosave thread
464 handleAutosave();
465
466 // Handle command line instructions
467 postConstructorProcessCmdLine(args);
468
469 // Show download dialog if autostart is enabled
470 DownloadDialog.autostartIfNeeded();
471 }
472
473 private void handleAutosave() {
474 if (AutosaveTask.PROP_AUTOSAVE_ENABLED.get()) {
475 AutosaveTask autosaveTask = new AutosaveTask();
476 List<File> unsavedLayerFiles = autosaveTask.getUnsavedLayersFiles();
477 if (!unsavedLayerFiles.isEmpty()) {
478 ExtendedDialog dialog = new ExtendedDialog(
479 Main.parent,
480 tr("Unsaved osm data"),
481 new String[] {tr("Restore"), tr("Cancel"), tr("Discard")}
482 );
483 dialog.setContent(
484 trn("JOSM found {0} unsaved osm data layer. ",
485 "JOSM found {0} unsaved osm data layers. ", unsavedLayerFiles.size(), unsavedLayerFiles.size()) +
486 tr("It looks like JOSM crashed last time. Would you like to restore the data?"));
487 dialog.setButtonIcons(new String[] {"ok", "cancel", "dialogs/delete"});
488 int selection = dialog.showDialog().getValue();
489 if (selection == 1) {
490 autosaveTask.recoverUnsavedLayers();
491 } else if (selection == 3) {
492 autosaveTask.discardUnsavedLayers();
493 }
494 }
495 autosaveTask.schedule();
496 }
497 }
498
499 private boolean handleNetworkOrProxyErrors(boolean hasErrors, String title, String message) {
500 if (hasErrors) {
501 ExtendedDialog ed = new ExtendedDialog(
502 Main.parent, title,
503 new String[]{tr("Change proxy settings"), tr("Cancel")});
504 ed.setButtonIcons(new String[]{"dialogs/settings.png", "cancel.png"}).setCancelButton(2);
505 ed.setMinimumSize(new Dimension(460, 260));
506 ed.setIcon(JOptionPane.WARNING_MESSAGE);
507 ed.setContent(message);
508
509 if (ed.showDialog().getValue() == 1) {
510 PreferencesAction.forPreferenceSubTab(null, null, ProxyPreference.class).run();
511 }
512 }
513 return hasErrors;
514 }
515
516 private boolean handleProxyErrors() {
517 return handleNetworkOrProxyErrors(proxySelector.hasErrors(), tr("Proxy errors occurred"),
518 tr("JOSM tried to access the following resources:<br>" +
519 "{0}" +
520 "but <b>failed</b> to do so, because of the following proxy errors:<br>" +
521 "{1}" +
522 "Would you like to change your proxy settings now?",
523 Utils.joinAsHtmlUnorderedList(proxySelector.getErrorResources()),
524 Utils.joinAsHtmlUnorderedList(proxySelector.getErrorMessages())
525 ));
526 }
527
528 private boolean handleNetworkErrors() {
529 boolean condition = !NETWORK_ERRORS.isEmpty();
530 if (condition) {
531 Set<String> errors = new TreeSet<>();
532 for (Throwable t : NETWORK_ERRORS.values()) {
533 errors.add(t.toString());
534 }
535 return handleNetworkOrProxyErrors(condition, tr("Network errors occurred"),
536 tr("JOSM tried to access the following resources:<br>" +
537 "{0}" +
538 "but <b>failed</b> to do so, because of the following network errors:<br>" +
539 "{1}" +
540 "It may result of a missing proxy configuration.<br>" +
541 "Would you like to change your proxy settings now?",
542 Utils.joinAsHtmlUnorderedList(NETWORK_ERRORS.keySet()),
543 Utils.joinAsHtmlUnorderedList(errors)
544 ));
545 }
546 return false;
547 }
548 }
549}
Note: See TracBrowser for help on using the repository browser.