All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.calendarfx.view.popover.EntryMapView Maven / Gradle / Ivy

There is a newer version: 8.5.0
Show newest version
/*
 *  Copyright (C) 2017 Dirk Lemmermann Software & Consulting (dlsc.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.calendarfx.view.popover;

import com.calendarfx.model.Entry;
import com.calendarfx.util.LoggingDomain;
import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.image.Image;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundImage;
import javafx.scene.layout.BackgroundPosition;
import javafx.scene.layout.BackgroundRepeat;
import javafx.scene.layout.BackgroundSize;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;

import java.awt.Desktop;
import java.awt.Desktop.Action;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.logging.Level;

/**
 * Pane that shows in a map the location of the entry.
 */
public class EntryMapView extends EntryPopOverPane {

    private final Entry entry;

    private final ImageLoader imageLoader = new ImageLoader();

    private final InvalidationListener invalidationListener = it -> imageLoader.restart();

    private final WeakInvalidationListener weakInvalidationListener = new WeakInvalidationListener(invalidationListener);

    public EntryMapView(Entry entry) {
        this.entry = Objects.requireNonNull(entry);

        StackPane mapViewPane = new StackPane();
        mapViewPane.setPrefSize(340, 240);
        mapViewPane.setPadding(new Insets(1));
        mapViewPane.setStyle("-fx-border-color: gray; -fx-border-radius: 4px;");
        mapViewPane.backgroundProperty().bind(Bindings.createObjectBinding(() -> {
            Image image = imageLoader.getValue();
            if (image != null) {
                return new Background(new BackgroundImage(image, BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, new BackgroundSize(100, 100, true, true, false, true)));
            }
            return null;
        }, imageLoader.valueProperty()));

        if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Action.BROWSE)) {
            mapViewPane.setCursor(Cursor.HAND);
            mapViewPane.setOnMouseClicked(evt -> {
                Desktop desktop = Desktop.getDesktop();
                try {
                    desktop.browse(new URL("https://www.google.com/maps/search/?api=1&query=" + URLEncoder.encode(entry.getLocation(), StandardCharsets.UTF_8)).toURI());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                } catch (URISyntaxException e) {
                    throw new RuntimeException(e);
                }
            });
        }

        Rectangle clip = new Rectangle();
        clip.widthProperty().bind(mapViewPane.widthProperty());
        clip.heightProperty().bind(mapViewPane.heightProperty());
        clip.setArcHeight(4);
        clip.setArcWidth(4);
        mapViewPane.setClip(clip);

        getChildren().add(mapViewPane);

        entry.locationProperty().addListener(weakInvalidationListener);

        visibleProperty().bind(entry.locationProperty().isNotNull().and(googleApiKeyProperty().isNotNull()));
        managedProperty().bind(entry.locationProperty().isNotNull().and(googleApiKeyProperty().isNotNull()));

        imageLoader.restart();
    }

    private class ImageLoader extends Service {
        public ImageLoader() {
        }

        @Override
        protected Task createTask() {
            return new ImageTask(entry.getLocation());
        }
    }

    private class ImageTask extends Task {

        private final String location;

        public ImageTask(String location) {
            this.location = location;
        }

        @Override
        protected Image call() throws Exception {
            Thread.sleep(500);

            if (isCancelled() || getGoogleApiKey().isBlank() || location == null || location.trim().equals("")) {
                return null;
            }

            return loadMapImage(location);
        }

    }

    public Image loadMapImage(String address) {
        if (address != null) {
            try {
                String encodedAddress = URLEncoder.encode(address, StandardCharsets.UTF_8);
                String key = getGoogleApiKey();
                String url = "https://maps.googleapis.com/maps/api/staticmap?center=" + encodedAddress + "&markers=color:0xE94B35%7C" + encodedAddress + "&scale=2&zoom=16&size=340x240&key=" + key;
                LoggingDomain.VIEW.fine("google map call (static image): " + url);
                Image image = new Image(url);
                return image;
            } catch (Exception ex) {
                LoggingDomain.VIEW.log(Level.SEVERE, "error when trying to load google maps static image", ex);
            }
        }

        return null;
    }

    private final StringProperty googleApiKey = new SimpleStringProperty(this, "googleApiKey", System.getProperty("calendarfx.google.api.key"));

    public final String getGoogleApiKey() {
        return googleApiKey.get();
    }

    public final StringProperty googleApiKeyProperty() {
        return googleApiKey;
    }

    public final void setGoogleApiKey(String googleApiKey) {
        this.googleApiKey.set(googleApiKey);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy