From 4e24cecfeba3c0dd71435e4b9eb3a784354b01a6 Mon Sep 17 00:00:00 2001 From: Hallvard Traetteberg <hal@ntnu.no> Date: Wed, 3 Jan 2018 22:49:08 +0100 Subject: [PATCH] Limitied support for issue #5. Text field and file chooser for loading GeoLocations. Currently shows all GeoLocations. Separate zoom slider. No selection support, yet. --- .../tdt4140/gr1800/app/core/geoLocations.json | 17 ++ .../java/tdt4140/gr1800/app/ui/FxApp.java | 26 +++ .../gr1800/app/ui/FxAppController.java | 183 ++++++++++++++++++ .../tdt4140/gr1800/app/ui/FxApp.fxml | 44 +++++ .../java/tdt4140/gr1800/app/ui/FxAppTest.java | 33 ++++ 5 files changed, 303 insertions(+) create mode 100644 tdt4140-gr1800/app.core/src/main/resources/tdt4140/gr1800/app/core/geoLocations.json create mode 100644 tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FxApp.java create mode 100644 tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FxAppController.java create mode 100644 tdt4140-gr1800/app.ui/src/main/resources/tdt4140/gr1800/app/ui/FxApp.fxml create mode 100644 tdt4140-gr1800/app.ui/src/test/java/tdt4140/gr1800/app/ui/FxAppTest.java diff --git a/tdt4140-gr1800/app.core/src/main/resources/tdt4140/gr1800/app/core/geoLocations.json b/tdt4140-gr1800/app.core/src/main/resources/tdt4140/gr1800/app/core/geoLocations.json new file mode 100644 index 0000000..2561822 --- /dev/null +++ b/tdt4140-gr1800/app.core/src/main/resources/tdt4140/gr1800/app/core/geoLocations.json @@ -0,0 +1,17 @@ +[ + { + "id" : "1", + "locations" : [ + { "latitude" : "63", "longitude" : "10" }, + [ "63.1", "10.1" ] + ] + }, + { + "id" : "2", + "path" : "true", + "locations" : [ + { "latitude" : "64", "longitude" : "11" }, + [ "64.1", "11.1" ] + ] + } +] diff --git a/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FxApp.java b/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FxApp.java new file mode 100644 index 0000000..1fe7537 --- /dev/null +++ b/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FxApp.java @@ -0,0 +1,26 @@ +package tdt4140.gr1800.app.ui; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; + + +public class FxApp extends Application { + + @Override + public void start(Stage stage) throws Exception { + Parent root = FXMLLoader.load(getClass().getResource("FxApp.fxml")); + + Scene scene = new Scene(root); + + stage.setTitle("JavaFX and Maven"); + stage.setScene(scene); + stage.show(); + } + + public static void main(String[] args) { + launch(args); + } +} diff --git a/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FxAppController.java b/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FxAppController.java new file mode 100644 index 0000000..753b0ca --- /dev/null +++ b/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FxAppController.java @@ -0,0 +1,183 @@ +package tdt4140.gr1800.app.ui; + +import java.io.File; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import com.lynden.gmapsfx.GoogleMapView; +import com.lynden.gmapsfx.MapComponentInitializedListener; +import com.lynden.gmapsfx.javascript.event.UIEventType; +import com.lynden.gmapsfx.javascript.object.GoogleMap; +import com.lynden.gmapsfx.javascript.object.MVCArray; +import com.lynden.gmapsfx.javascript.object.MapOptions; +import com.lynden.gmapsfx.javascript.object.MapShape; +import com.lynden.gmapsfx.javascript.object.MapTypeIdEnum; +import com.lynden.gmapsfx.javascript.object.Marker; +import com.lynden.gmapsfx.javascript.object.MarkerOptions; +import com.lynden.gmapsfx.shapes.Polyline; +import com.lynden.gmapsfx.shapes.PolylineOptions; + +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Slider; +import javafx.scene.control.TextField; +import javafx.stage.DirectoryChooser; +import javafx.stage.FileChooser; +import tdt4140.gr1800.app.core.App; +import tdt4140.gr1800.app.core.GeoLocations; +import tdt4140.gr1800.app.core.LatLong; + +public class FxAppController implements MapComponentInitializedListener { + + @FXML + private TextField geolocationsFileText; + + @FXML + private ComboBox<String> geoLocationsSelector; + + @FXML + private GoogleMapView mapView; + private GoogleMap map; + + @FXML + private Slider zoomSlider; + + private App app; + + @FXML + public void initialize() { + mapView.addMapInializedListener(this); + app = new App(); + geoLocationsSelector.getSelectionModel().selectedItemProperty().addListener((stringProperty, oldValue, newValue) -> updateGeoLocations()); + zoomSlider.valueProperty().addListener((doubleProperty, oldValue, newValue) -> map.setZoom((int) zoomSlider.getValue())); + } + + private Object updateGeoLocations() { + return null; + } + + private Map<GeoLocations, MapShape> shapes = new HashMap<GeoLocations, MapShape>(); + private Map<GeoLocations, Collection<Marker>> markers = new HashMap<GeoLocations, Collection<Marker>>(); + + private void initMapMarkers() { + map.clearMarkers(); + for (String geoLocationName : app.getGeoLocationNames()) { + GeoLocations geoLocations = app.getGeoLocations(geoLocationName); + if (geoLocations.isPath()) { + Collection<com.lynden.gmapsfx.javascript.object.LatLong> latLongs = new ArrayList<com.lynden.gmapsfx.javascript.object.LatLong>(); + for (LatLong latLong : geoLocations) { + double lat = latLong.latitude, lon = latLong.longitude; + latLongs.add(new com.lynden.gmapsfx.javascript.object.LatLong(lat, lon)); + } + MVCArray mvc = new MVCArray(latLongs.toArray(new com.lynden.gmapsfx.javascript.object.LatLong[latLongs.size()])); + PolylineOptions options = new PolylineOptions() + .path(mvc) + .strokeColor("red") + .strokeWeight(2); + Polyline polyline = new Polyline(options); + map.addMapShape(polyline); + this.shapes.put(geoLocations, polyline); + } else { + Collection<Marker> markers = new ArrayList<Marker>(); + for (LatLong latLong : geoLocations) { + double lat = latLong.latitude, lon = latLong.longitude; + MarkerOptions options = new MarkerOptions().label(geoLocationName) + .position(new com.lynden.gmapsfx.javascript.object.LatLong(lat, lon)); + Marker marker = new Marker(options); + map.addMarker(marker); + markers.add(marker); + } + this.markers.put(geoLocations, markers); + } + geoLocationsSelector.getItems().add(geoLocationName); + } + map.setCenter(getCenter(null)); + map.addMouseEventHandler(UIEventType.click, (event) -> { + com.lynden.gmapsfx.javascript.object.LatLong latLong = event.getLatLong(); + System.out.println("Latitude: " + latLong.getLatitude()); + System.out.println("Longitude: " + latLong.getLongitude()); + }); + System.out.println("Map markers initialized"); + } + + private com.lynden.gmapsfx.javascript.object.LatLong getCenter(GeoLocations geoLocations) { + double latSum = 0.0, lonSum = 0.0; + int num = 0; + if (geoLocations == null) { + for (String geoLocationName : app.getGeoLocationNames()) { + geoLocations = app.getGeoLocations(geoLocationName); + for (LatLong latLong : geoLocations) { + double lat = latLong.latitude, lon = latLong.longitude; + latSum += lat; + lonSum += lon; + num++; + } + } + } else { + for (LatLong latLong : geoLocations) { + double lat = latLong.latitude, lon = latLong.longitude; + latSum += lat; + lonSum += lon; + num++; + } + } + return new com.lynden.gmapsfx.javascript.object.LatLong(latSum / num, lonSum / num); + } + + @Override + public void mapInitialized() { + // Set the initial properties of the map. + MapOptions mapOptions = new MapOptions(); + + mapOptions + .mapType(MapTypeIdEnum.ROADMAP) + .center(new com.lynden.gmapsfx.javascript.object.LatLong(63.0, 10.0)) + .overviewMapControl(false) + .panControl(false) + .rotateControl(false) + .scaleControl(false) + .streetViewControl(false) + .zoomControl(false) + .zoom(zoomSlider.getValue()); + map = mapView.createMap(mapOptions); + System.out.println("Map initialized: " + map); + if (app.getGeoLocationNames().iterator().hasNext()) { + initMapMarkers(); + } + } + + @FXML + public void loadGeolocationsFile() { + try { + URI fileUri = new URI(geolocationsFileText.getText()); + app.loadGeoLocations(fileUri); + System.out.println("GeoLocations initialized: " + app.getGeoLocationNames()); + if (map != null) { + initMapMarkers(); + } + } catch (Exception e) { + Alert alert = new Alert(AlertType.ERROR); + alert.setTitle("Exception when loading from " + geolocationsFileText.getText() + ": " + e.getMessage()); + alert.setContentText(e.getMessage()); + alert.show(); + } + } + + @FXML + public void handleBrowseGeolocationsFile() { + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("Select geo-locations file"); + + File file = fileChooser.showOpenDialog(mapView.getScene().getWindow()); + if (file == null) { + file = new File("."); + } + geolocationsFileText.setText(file.toURI().toString()); + geolocationsFileText.getOnAction().handle(null); + } +} diff --git a/tdt4140-gr1800/app.ui/src/main/resources/tdt4140/gr1800/app/ui/FxApp.fxml b/tdt4140-gr1800/app.ui/src/main/resources/tdt4140/gr1800/app/ui/FxApp.fxml new file mode 100644 index 0000000..bbefa50 --- /dev/null +++ b/tdt4140-gr1800/app.ui/src/main/resources/tdt4140/gr1800/app/ui/FxApp.fxml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import java.lang.*?> +<?import javafx.collections.*?> +<?import javafx.geometry.*?> +<?import javafx.scene.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.layout.*?> + +<?import com.lynden.gmapsfx.GoogleMapView?> +<?import javafx.scene.control.ComboBox?> +<?import javafx.scene.layout.VBox?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.control.TextField?> +<?import javafx.scene.control.Button?> + +<BorderPane xmlns:fx="http://javafx.com/fxml" + fx:controller="tdt4140.gr1800.app.ui.FxAppController" + prefHeight="750" prefWidth="1000"> + <top> + <VBox> + <HBox> + <TextField fx:id="geolocationsFileText" promptText="Geo-locations file" onAction="#loadGeolocationsFile"/> + <Button text="Browse..." onAction="#handleBrowseGeolocationsFile"/> + </HBox> + <ComboBox fx:id="geoLocationsSelector"> + <BorderPane.margin> + <Insets left="5" right="5" top="5" bottom="5" /> + </BorderPane.margin> + </ComboBox> + </VBox> + </top> + <center> + <GoogleMapView fx:id="mapView"> + </GoogleMapView> + </center> + <bottom> + <Slider fx:id="zoomSlider" min="1" max="20" value="9"> + <BorderPane.margin> + <Insets left="5" right="5" top="5" bottom="5" /> + </BorderPane.margin> + </Slider> + </bottom> +</BorderPane> diff --git a/tdt4140-gr1800/app.ui/src/test/java/tdt4140/gr1800/app/ui/FxAppTest.java b/tdt4140-gr1800/app.ui/src/test/java/tdt4140/gr1800/app/ui/FxAppTest.java new file mode 100644 index 0000000..18951d0 --- /dev/null +++ b/tdt4140-gr1800/app.ui/src/test/java/tdt4140/gr1800/app/ui/FxAppTest.java @@ -0,0 +1,33 @@ +package tdt4140.gr1800.app.ui; + +import org.junit.Assert; +import org.junit.Test; +import org.testfx.framework.junit.ApplicationTest; + +import com.lynden.gmapsfx.GoogleMapView; + +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; + +public class FxAppTest extends ApplicationTest { + + @Override + public void start(Stage stage) throws Exception { + Parent root = FXMLLoader.load(getClass().getResource("FxApp.fxml")); + + Scene scene = new Scene(root); + + stage.setTitle("JavaFX and Maven"); + stage.setScene(scene); + stage.show(); + } + + @Test + public void testMapExists() { + Node map = lookup("#mapView").query(); + Assert.assertTrue(map instanceof GoogleMapView); + } +} -- GitLab