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.List; 011import java.util.Objects; 012import java.util.concurrent.Callable; 013 014import org.openstreetmap.gui.jmapviewer.FeatureAdapter; 015import org.openstreetmap.gui.jmapviewer.FeatureAdapter.SettingsAdapter; 016import org.openstreetmap.josm.data.UndoRedoHandler; 017import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager; 018import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat; 019import org.openstreetmap.josm.data.coor.conversion.ICoordinateFormat; 020import org.openstreetmap.josm.data.validation.OsmValidator; 021import org.openstreetmap.josm.gui.layer.ImageryLayer; 022import org.openstreetmap.josm.gui.layer.Layer; 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.spi.lifecycle.InitializationSequence; 033import org.openstreetmap.josm.spi.lifecycle.InitializationTask; 034import org.openstreetmap.josm.spi.preferences.Config; 035import org.openstreetmap.josm.tools.I18n; 036import org.openstreetmap.josm.tools.ImageProvider; 037import org.openstreetmap.josm.tools.Logging; 038import org.openstreetmap.josm.tools.OpenBrowser; 039import org.openstreetmap.josm.tools.OverpassTurboQueryWizard; 040import org.openstreetmap.josm.tools.PlatformManager; 041import org.openstreetmap.josm.tools.RightAndLefthandTraffic; 042import org.openstreetmap.josm.tools.Shortcut; 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)), 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"), KeyEvent.VK_F1, Shortcut.DIRECT)); 083 }), 084 // This needs to be done before RightAndLefthandTraffic::initialize is called 085 new InitializationTask(tr("Initializing internal boundaries data"), Territories::initialize) 086 ); 087 } 088 089 @Override 090 public Collection<InitializationTask> parallelInitializationTasks() { 091 return Arrays.asList( 092 new InitializationTask(tr("Initializing OSM API"), () -> { 093 OsmApi.addOsmApiInitializationListener(api -> { 094 // This checks if there are any layers currently displayed that are now on the blacklist, and removes them. 095 // This is a rare situation - probably only occurs if the user changes the API URL in the preferences menu. 096 // Otherwise they would not have been able to load the layers in the first place because they would have been disabled 097 if (MainApplication.isDisplayingMapView()) { 098 for (Layer l : MainApplication.getLayerManager().getLayersOfType(ImageryLayer.class)) { 099 if (((ImageryLayer) l).getInfo().isBlacklisted()) { 100 Logging.info(tr("Removed layer {0} because it is not allowed by the configured API.", l.getName())); 101 MainApplication.getLayerManager().removeLayer(l); 102 } 103 } 104 } 105 }); 106 // We try to establish an API connection early, so that any API 107 // capabilities are already known to the editor instance. However 108 // if it goes wrong that's not critical at this stage. 109 try { 110 OsmApi.getOsmApi().initialize(null, true); 111 } catch (OsmTransferCanceledException | OsmApiInitializationException | SecurityException e) { 112 Logging.warn(Logging.getErrorMessage(Utils.getRootCause(e))); 113 } 114 }), 115 new InitializationTask(tr("Initializing internal traffic data"), RightAndLefthandTraffic::initialize), 116 new InitializationTask(tr("Initializing validator"), OsmValidator::initialize), 117 new InitializationTask(tr("Initializing presets"), TaggingPresets::initialize), 118 new InitializationTask(tr("Initializing map styles"), MapPaintPreference::initialize), 119 new InitializationTask(tr("Loading imagery preferences"), ImageryPreference::initialize) 120 ); 121 } 122 123 @Override 124 public List<Callable<?>> asynchronousCallableTasks() { 125 return Arrays.asList( 126 OverpassTurboQueryWizard::getInstance 127 ); 128 } 129 130 @Override 131 public List<Runnable> asynchronousRunnableTasks() { 132 return Arrays.asList( 133 TMSLayer::getCache, 134 OsmValidator::initializeTests 135 ); 136 } 137 138 @Override 139 public List<InitializationTask> afterInitializationTasks() { 140 return Arrays.asList( 141 new InitializationTask(tr("Updating user interface"), () -> GuiHelper.runInEDTAndWait(() -> { 142 // hooks for the jmapviewer component 143 FeatureAdapter.registerBrowserAdapter(OpenBrowser::displayUrl); 144 FeatureAdapter.registerImageAdapter(ImageProvider::read); 145 FeatureAdapter.registerTranslationAdapter(I18n::tr); 146 FeatureAdapter.registerLoggingAdapter(name -> Logging.getLogger()); 147 FeatureAdapter.registerSettingsAdapter(new JosmSettingsAdapter()); 148 // UI update 149 MainApplication.toolbar.refreshToolbarControl(); 150 MainApplication.toolbar.control.updateUI(); 151 MainApplication.contentPanePrivate.updateUI(); 152 })) 153 ); 154 } 155 156 private static class JosmSettingsAdapter implements SettingsAdapter { 157 158 @Override 159 public String get(String key, String def) { 160 return Config.getPref().get(key, def); 161 } 162 163 @Override 164 public boolean put(String key, String value) { 165 return Config.getPref().put(key, value); 166 } 167 } 168}