Package slash.navigation.converter.gui.mapview

Source Code of slash.navigation.converter.gui.mapview.JavaFXWebViewMapView

/*
    This file is part of RouteConverter.

    RouteConverter is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    RouteConverter is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with RouteConverter; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Copyright (C) 2007 Christian Pesch. All Rights Reserved.
*/

package slash.navigation.converter.gui.mapview;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.web.WebView;
import slash.common.io.TokenResolver;
import slash.navigation.common.NavigationPosition;

import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;
import java.util.Locale;
import java.util.logging.Logger;

import static java.lang.Boolean.parseBoolean;
import static java.lang.Math.max;
import static java.lang.System.currentTimeMillis;
import static javafx.application.Platform.isFxApplicationThread;
import static javafx.application.Platform.runLater;
import static javafx.concurrent.Worker.State;
import static javafx.concurrent.Worker.State.SUCCEEDED;
import static slash.common.io.Externalization.extractFile;
import static slash.common.io.Transfer.parseDouble;

/**
* Implementation for a component that displays the positions of a position list on a map
* using the JavaFX WebView.
*
* @author Christian Pesch
*/

public class JavaFXWebViewMapView extends BaseMapView {
    private static final Logger log = Logger.getLogger(JavaFXWebViewMapView.class.getName());
    private static final String GOOGLE_MAPS_SERVER_PREFERENCE = "mapServer"// TODO push up?
    private static final String DEBUG_PREFERENCE = "debug"; // TODO push up?

    private JFXPanel panel;
    private WebView webView;
    private boolean debug = preferences.getBoolean(DEBUG_PREFERENCE, false); // TODO push up?

    public boolean isSupportedPlatform() {
        return true;
    }

    public Component getComponent() {
        return panel;
    }

    // initialization

    private WebView createWebView() {
        try {
            final WebView webView = new WebView();
            Group group = new Group();
            group.getChildren().add(webView);
            panel.setScene(new Scene(group));
            panel.addComponentListener(new ComponentAdapter() {
                public void componentResized(ComponentEvent e) {
                    Dimension size = panel.getSize();
                    webView.setMinSize(size.getWidth(), size.getHeight());
                }
            });
            return webView;
        } catch (Throwable t) {
            log.severe("Cannot create WebView: " + t.getMessage());
            setInitializationCause(t);
            return null;
        }
    }

    private boolean loadWebPage() { // TODO unify with EclipseSWTMapView?
        try {
            final String language = Locale.getDefault().getLanguage().toLowerCase();
            final String country = Locale.getDefault().getCountry().toLowerCase();
            File html = extractFile("slash/navigation/converter/gui/mapview/routeconverter.html", country, new TokenResolver() {
                public String resolveToken(String tokenName) {
                    if (tokenName.equals("language"))
                        return language;
                    if (tokenName.equals("country"))
                        return country;
                    if (tokenName.equals("mapserver"))
                        return preferences.get(GOOGLE_MAPS_SERVER_PREFERENCE, "maps.google.com");
                    if (tokenName.equals("maptype"))
                        return preferences.get(MAP_TYPE_PREFERENCE, "roadmap");
                    return tokenName;
                }
            });
            if (html == null)
                throw new IllegalArgumentException("Cannot extract routeconverter.html");
            extractFile("slash/navigation/converter/gui/mapview/contextmenu.js");
            extractFile("slash/navigation/converter/gui/mapview/keydragzoom.js");
            extractFile("slash/navigation/converter/gui/mapview/label.js");
            extractFile("slash/navigation/converter/gui/mapview/latlngcontrol.js");

            final String url = html.toURI().toURL().toExternalForm();
            webView.getEngine().load(url);
            log.fine(currentTimeMillis() + " loadWebPage thread " + Thread.currentThread());
        } catch (Throwable t) {
            log.severe("Cannot create WebBrowser: " + t.getMessage());
            setInitializationCause(t);
            return false;
        }
        return true;
    }

    protected void initializeBrowser() {
        panel = new JFXPanel();

        runLater(new Runnable() {
            public void run() {
                webView = createWebView();
                if (webView == null)
                    return;

                log.info("Using JavaFX WebView to create map view");

                webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
                    private int startCount = 0;

                    public void changed(ObservableValue<? extends State> observableValue, State oldState, State newState) {
                        // log.fine("WebView changed observableValue " + observableValue + " oldState " + oldState + " newState " + newState + " thread " + Thread.currentThread());
                        if (newState == SUCCEEDED) {
                            tryToInitialize(startCount++, currentTimeMillis());
                        }
                    }
                });

                if (!loadWebPage())
                    dispose();
            }
        });
    }

    private void tryToInitialize(int count, long start) { // TODO unify with EclipseSWTMapView?
        boolean initialized = getComponent() != null && isMapInitialized();
        synchronized (this) {
            this.initialized = initialized;
        }
        log.fine("Initialized map: " + initialized);

        if (isInitialized()) {
            runBrowserInteractionCallbacksAndTests(start);
        } else {
            long end = currentTimeMillis();
            int timeout = count++ * 100;
            if (timeout > 3000)
                timeout = 3000;
            log.info("Failed to initialize map since " + (end - start) + " ms, sleeping for " + timeout + " ms");

            try {
                Thread.sleep(timeout);
            } catch (InterruptedException e) {
                // intentionally left empty
            }
            tryToInitialize(count, start);
        }
    }

    private void runBrowserInteractionCallbacksAndTests(long start) { // TODO unify with EclipseSWTMapView?
        long end = currentTimeMillis();
        log.fine("Starting browser interaction, callbacks and tests after " + (end - start) + " ms");
        initializeAfterLoading();
        initializeBrowserInteraction();
        initializeCallbackListener();
        checkLocalhostResolution();
        checkCallback();
        end = currentTimeMillis();
        log.fine("Browser interaction is running after " + (end - start) + " ms");
    }

    private boolean isMapInitialized() {   // TODO unify with EclipseSWTMapView?
        String result = executeScriptWithResult("isInitialized();");
        return parseBoolean(result);
    }

    private void initializeAfterLoading() { // TODO unify with EclipseSWTMapView?
        resize();
        update(true);
    }

    // resizing

    private boolean hasBeenResizedToInvisible = false;

    public void resize() { // TODO unify with EclipseSWTMapView?
        if (!isInitialized() || !getComponent().isShowing())
            return;

        synchronized (notificationMutex) {
            // if map is not visible remember to update and resize it again
            // once the map becomes visible again
            if (!isVisible()) {
                hasBeenResizedToInvisible = true;
            } else if (hasBeenResizedToInvisible) {
                hasBeenResizedToInvisible = false;
                update(true);
            }
            resizeMap();
        }
    }

    private int lastWidth = -1, lastHeight = -1;

    private void resizeMap() { // TODO unify with EclipseSWTMapView?
        synchronized (notificationMutex) {
            int width = max(getComponent().getWidth(), 0);
            int height = max(getComponent().getHeight(), 0);
            if (width != lastWidth || height != lastHeight) {
                executeScript("resize(" + width + "," + height + ");");
            }
            lastWidth = width;
            lastHeight = height;
        }
    }

    // bounds and center

    protected NavigationPosition getNorthEastBounds() {
        return extractLatLng("getNorthEastBounds();");
    }

    protected NavigationPosition getSouthWestBounds() {
        return extractLatLng("getSouthWestBounds();");
    }

    protected NavigationPosition getCurrentMapCenter() {
        return extractLatLng("getCenter();");
    }

    protected Integer getCurrentZoom() {
        Double zoom = parseDouble(executeScriptWithResult("getZoom();"));
        return zoom != null ? zoom.intValue() : null;
    }

    protected String getCallbacks() {
        return executeScriptWithResult("getCallbacks();");
    }

    // script execution

    protected void executeScript(final String script) {
        if (webView == null || script.length() == 0)
            return;

        if (!isFxApplicationThread()) {
            runLater(new Runnable() {
                public void run() {
                    webView.getEngine().executeScript(script);
                    logJavaScript(script, null);
                }
            });
        } else {
            webView.getEngine().executeScript(script);
            logJavaScript(script, null);
        }
    }

    protected String executeScriptWithResult(final String script) {
        if (script.length() == 0)
            return null;

        final boolean pollingCallback = !script.contains("getCallbacks");
        final Object[] result = new Object[1];
        if (!isFxApplicationThread()) {
            runLater(new Runnable() {
                public void run() {
                    result[0] = webView.getEngine().executeScript(script);
                    if (debug && pollingCallback) {
                        log.info("After invokeLater, executeScript with result " + result[0]);
                    }
                }
            });
        } else {
            result[0] = webView.getEngine().executeScript(script);
            if (debug && pollingCallback) {
                log.info("After executeScript with result " + result[0]);
            }
        }

        if (pollingCallback) {
            logJavaScript(script, result[0]);
        }
        return result[0] != null ? result[0].toString() : null;
    }
}
TOP

Related Classes of slash.navigation.converter.gui.mapview.JavaFXWebViewMapView

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.