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}