001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.BorderLayout; 007import java.awt.event.KeyEvent; 008import java.util.Arrays; 009import java.util.Collection; 010import java.util.Collections; 011import java.util.List; 012import java.util.Objects; 013import java.util.concurrent.Callable; 014 015import org.openstreetmap.gui.jmapviewer.FeatureAdapter; 016import org.openstreetmap.gui.jmapviewer.FeatureAdapter.SettingsAdapter; 017import org.openstreetmap.josm.data.UndoRedoHandler; 018import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager; 019import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat; 020import org.openstreetmap.josm.data.coor.conversion.ICoordinateFormat; 021import org.openstreetmap.josm.data.validation.OsmValidator; 022import org.openstreetmap.josm.gui.layer.ImageryLayer; 023import org.openstreetmap.josm.gui.layer.TMSLayer; 024import org.openstreetmap.josm.gui.preferences.imagery.ImageryPreference; 025import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference; 026import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets; 027import org.openstreetmap.josm.gui.util.GuiHelper; 028import org.openstreetmap.josm.io.FileWatcher; 029import org.openstreetmap.josm.io.OsmApi; 030import org.openstreetmap.josm.io.OsmApiInitializationException; 031import org.openstreetmap.josm.io.OsmTransferCanceledException; 032import org.openstreetmap.josm.io.imagery.ApiKeyProvider; 033import org.openstreetmap.josm.spi.lifecycle.InitializationSequence; 034import org.openstreetmap.josm.spi.lifecycle.InitializationTask; 035import org.openstreetmap.josm.spi.preferences.Config; 036import org.openstreetmap.josm.tools.I18n; 037import org.openstreetmap.josm.tools.ImageProvider; 038import org.openstreetmap.josm.tools.Logging; 039import org.openstreetmap.josm.tools.OpenBrowser; 040import org.openstreetmap.josm.tools.PlatformManager; 041import org.openstreetmap.josm.tools.Shortcut; 042import org.openstreetmap.josm.tools.Tag2Link; 043import org.openstreetmap.josm.tools.Territories; 044import org.openstreetmap.josm.tools.Utils; 045 046/** 047 * JOSM initialization sequence. 048 * @since 14139 049 */ 050public class MainInitialization implements InitializationSequence { 051 052 private final MainApplication application; 053 054 /** 055 * Constructs a new {@code MainInitialization} 056 * @param application Main application. Must not be null 057 */ 058 public MainInitialization(MainApplication application) { 059 this.application = Objects.requireNonNull(application); 060 } 061 062 @Override 063 public List<InitializationTask> beforeInitializationTasks() { 064 return Arrays.asList( 065 new InitializationTask(tr("Initializing coordinate format"), () -> { 066 ICoordinateFormat fmt = CoordinateFormatManager.getCoordinateFormat(Config.getPref().get("coordinates")); 067 if (fmt == null) { 068 fmt = DecimalDegreesCoordinateFormat.INSTANCE; 069 } 070 CoordinateFormatManager.setCoordinateFormat(fmt); 071 }), 072 new InitializationTask(tr("Starting file watcher"), FileWatcher.getDefaultInstance()::start), 073 new InitializationTask(tr("Executing platform startup hook"), 074 () -> PlatformManager.getPlatform().startupHook(MainApplication::askUpdateJava, MainApplication::askMigrateWebStart)), 075 new InitializationTask(tr("Building main menu"), application::initializeMainWindow), 076 new InitializationTask(tr("Updating user interface"), () -> { 077 UndoRedoHandler.getInstance().addCommandQueueListener(application.redoUndoListener); 078 // creating toolbar 079 GuiHelper.runInEDTAndWait(() -> MainApplication.contentPanePrivate.add(MainApplication.toolbar.control, BorderLayout.NORTH)); 080 // help shortcut 081 MainApplication.registerActionShortcut(MainApplication.menu.help, 082 Shortcut.registerShortcut("system:help", tr("Help: {0}", tr("Help")), KeyEvent.VK_F1, Shortcut.DIRECT)); 083 }), 084 new InitializationTask(tr("Initializing internal boundaries data"), () -> { 085 Territories.initialize(); 086 if (Config.getPref().getBoolean("override.numbering.format", true)) { 087 I18n.initializeNumberingFormat(); 088 } 089 }) 090 ); 091 } 092 093 @Override 094 public Collection<InitializationTask> parallelInitializationTasks() { 095 return Arrays.asList( 096 new InitializationTask(tr("Initializing OSM API"), () -> { 097 OsmApi.addOsmApiInitializationListener(api -> { 098 // This checks if there are any layers currently displayed that are now on the blacklist, and removes them. 099 // This is a rare situation - probably only occurs if the user changes the API URL in the preferences menu. 100 // Otherwise they would not have been able to load the layers in the first place because they would have been disabled 101 if (MainApplication.isDisplayingMapView()) { 102 for (ImageryLayer l : MainApplication.getLayerManager().getLayersOfType(ImageryLayer.class)) { 103 if (l.getInfo().isBlacklisted()) { 104 Logging.info(tr("Removed layer {0} because it is not allowed by the configured API.", l.getName())); 105 MainApplication.getLayerManager().removeLayer(l); 106 } 107 } 108 } 109 }); 110 // We try to establish an API connection early, so that any API 111 // capabilities are already known to the editor instance. However 112 // if it goes wrong that's not critical at this stage. 113 try { 114 OsmApi.getOsmApi().initialize(null, true); 115 } catch (OsmTransferCanceledException | OsmApiInitializationException | SecurityException e) { 116 Logging.warn(Logging.getErrorMessage(Utils.getRootCause(e))); 117 } 118 }), 119 new InitializationTask(tr("Initializing validator"), OsmValidator::initialize), 120 new InitializationTask(tr("Initializing presets"), TaggingPresets::initialize), 121 new InitializationTask(tr("Initializing map styles"), MapPaintPreference::initialize), 122 new InitializationTask(tr("Initializing Tag2Link rules"), Tag2Link::initialize), 123 new InitializationTask(tr("Loading imagery preferences"), ImageryPreference::initialize) 124 ); 125 } 126 127 @Override 128 public List<Callable<?>> asynchronousCallableTasks() { 129 return Collections.emptyList(); 130 } 131 132 @Override 133 public List<Runnable> asynchronousRunnableTasks() { 134 return Arrays.asList( 135 TMSLayer::getCache, 136 OsmValidator::initializeTests 137 ); 138 } 139 140 @Override 141 public List<InitializationTask> afterInitializationTasks() { 142 return Arrays.asList( 143 new InitializationTask(tr("Updating user interface"), () -> GuiHelper.runInEDTAndWait(() -> { 144 // hooks for the jmapviewer component 145 FeatureAdapter.registerApiKeyAdapter(ApiKeyProvider::retrieveApiKey); 146 FeatureAdapter.registerBrowserAdapter(OpenBrowser::displayUrl); 147 FeatureAdapter.registerImageAdapter(ImageProvider::read); 148 FeatureAdapter.registerTranslationAdapter(I18n::tr); 149 FeatureAdapter.registerLoggingAdapter(name -> Logging.getLogger()); 150 FeatureAdapter.registerSettingsAdapter(new JosmSettingsAdapter()); 151 // UI update 152 MainApplication.toolbar.refreshToolbarControl(); 153 MainApplication.toolbar.control.updateUI(); 154 MainApplication.contentPanePrivate.updateUI(); 155 })) 156 ); 157 } 158 159 private static class JosmSettingsAdapter implements SettingsAdapter { 160 161 @Override 162 public String get(String key, String def) { 163 return Config.getPref().get(key, def); 164 } 165 166 @Override 167 public boolean put(String key, String value) { 168 return Config.getPref().put(key, value); 169 } 170 } 171}