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