diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/App.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/App.java
index b7bd765c637941a2965d97c3e204df5e4c2230a7..defe620ce876081d95e6852dc0e453bc1a830285 100644
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/App.java
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/App.java
@@ -9,6 +9,11 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.stream.Collectors;
 
+import tdt4140.gr1800.app.doc.DocumentStorageImpl;
+import tdt4140.gr1800.app.doc.IDocumentImporter;
+import tdt4140.gr1800.app.doc.IDocumentLoader;
+import tdt4140.gr1800.app.doc.IDocumentPersistence;
+import tdt4140.gr1800.app.doc.IDocumentStorage;
 import tdt4140.gr1800.app.gpx.GpxDocumentConverter;
 import tdt4140.gr1800.app.json.GeoLocationsJsonPersistence;
 
@@ -67,40 +72,6 @@ public class App {
 		return result;
 	}
 
-	public void setGeoLocations(Collection<GeoLocations> geoLocations) {
-		this.geoLocations = new ArrayList<>(geoLocations);
-		fireGeoLocationsUpdated(null);
-	}
-
-	public void addGeoLocations(GeoLocations geoLocations) {
-		if (hasGeoLocations(geoLocations.getName())) {
-			throw new IllegalArgumentException("Duplicate geo-locations name: " + geoLocations.getName());
-		}
-		this.geoLocations.add(geoLocations);
-		fireGeoLocationsUpdated(geoLocations);
-	}
-	
-	public void removeGeoLocations(GeoLocations geoLocations) {
-		this.geoLocations.remove(geoLocations);
-		fireGeoLocationsUpdated(geoLocations);
-	}
-
-	private Collection<IGeoLocationsListener> geoLocationsListeners = new ArrayList<>();
-	
-	public void addGeoLocationsListener(IGeoLocationsListener listener) {
-		geoLocationsListeners.add(listener);
-	}
-
-	public void removeGeoLocationsListener(IGeoLocationsListener listener) {
-		geoLocationsListeners.remove(listener);
-	}
-
-	protected void fireGeoLocationsUpdated(GeoLocations geoLocations) {
-		for (IGeoLocationsListener listener : geoLocationsListeners) {
-			listener.geoLocationsUpdated(geoLocations);
-		}
-	}
-
 	// 
 
 	private IDocumentPersistence<Collection<GeoLocations>, File> documentPersistence = new IDocumentPersistence<Collection<GeoLocations>, File>() {
@@ -125,7 +96,9 @@ public class App {
 
 		@Override
 		protected void setDocument(Collection<GeoLocations> document) {
-			setGeoLocations(document);
+			Collection<GeoLocations> oldDocument = getDocument();
+			App.this.geoLocations = document;
+			fireDocumentChanged(oldDocument);
 		}
 
 		@Override
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IGeoLocationsListener.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IGeoLocationsListener.java
deleted file mode 100644
index 787f85d1d559a80439f2690f1ea04b5f782932ca..0000000000000000000000000000000000000000
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IGeoLocationsListener.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package tdt4140.gr1800.app.core;
-
-public interface IGeoLocationsListener {
-
-	public void geoLocationsUpdated(GeoLocations geoLocations);
-}
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/DocumentStorageImpl.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/DocumentStorageImpl.java
similarity index 56%
rename from tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/DocumentStorageImpl.java
rename to tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/DocumentStorageImpl.java
index b673c877d7fde81b765da55190e1a93347ccc816..6a104a6bd96db82210a2bbad3a8fd39625bd10ca 100644
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/DocumentStorageImpl.java
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/DocumentStorageImpl.java
@@ -1,6 +1,8 @@
-package tdt4140.gr1800.app.core;
+package tdt4140.gr1800.app.doc;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
 
 public abstract class DocumentStorageImpl<D, L> implements IDocumentStorage<L>, IDocumentPersistence<D, L> {
 
@@ -13,17 +15,45 @@ public abstract class DocumentStorageImpl<D, L> implements IDocumentStorage<L>,
 
 	@Override
 	public void setDocumentLocation(L documentLocation) {
+		L oldDocumentLocation = this.documentLocation;
 		this.documentLocation = documentLocation;
+		fireDocumentLocationChanged(oldDocumentLocation);
 	}
 
 	protected void setDocumentAndLocation(D document, L documentLocation) {
 		setDocument(document);
 		setDocumentLocation(documentLocation);
 	}
-	
+
 	protected abstract D getDocument();
 	protected abstract void setDocument(D document);
 
+	//
+	
+	private Collection<IDocumentStorageListener<L>> documentListeners = new ArrayList<IDocumentStorageListener<L>>();
+	
+	public void addDocumentStorageListener(IDocumentStorageListener<L> documentStorageListener) {
+		documentListeners.add(documentStorageListener);
+	}
+
+	public void removeDocumentStorageListener(IDocumentStorageListener<L> documentStorageListener) {
+		documentListeners.remove(documentStorageListener);
+	}
+	
+	protected void fireDocumentLocationChanged(L oldDocumentLocation) {
+		for (IDocumentStorageListener<L> documentStorageListener : documentListeners) {
+			documentStorageListener.documentLocationChanged(documentLocation, oldDocumentLocation);
+		}
+	}
+
+	protected void fireDocumentChanged(D oldDocument) {
+		for (IDocumentStorageListener<L> documentListener : documentListeners) {
+			if (documentListener instanceof IDocumentListener) {
+				((IDocumentListener<D, L>) documentListener).documentChanged(getDocument(), oldDocument);
+			}
+		}
+	}
+	
 	protected abstract D createDocument();
 	
 	@Override
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentImporter.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentImporter.java
similarity index 80%
rename from tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentImporter.java
rename to tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentImporter.java
index c37c4c56d4786538644974664c932a578ddac800..ba8b8ec2aa68702c1400a09032ab41c6f6140b23 100644
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentImporter.java
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentImporter.java
@@ -1,4 +1,4 @@
-package tdt4140.gr1800.app.core;
+package tdt4140.gr1800.app.doc;
 
 import java.io.IOException;
 
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentListener.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..62b8ce211c1ca51449ef015efba9afabff903737
--- /dev/null
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentListener.java
@@ -0,0 +1,5 @@
+package tdt4140.gr1800.app.doc;
+
+public interface IDocumentListener<D, L> extends IDocumentStorageListener<L>{
+	public void documentChanged(D document, D oldDocument);
+}
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentLoader.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentLoader.java
similarity index 76%
rename from tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentLoader.java
rename to tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentLoader.java
index 928fd9b860ee6cfa3050917c5fb8037634bcb2af..ecb029b5d7668f17d9024a2599c94d70475689f8 100644
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentLoader.java
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentLoader.java
@@ -1,4 +1,4 @@
-package tdt4140.gr1800.app.core;
+package tdt4140.gr1800.app.doc;
 
 public interface IDocumentLoader<D, L> {
 	public D loadDocument(L documentLocation) throws Exception;
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentPersistence.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentPersistence.java
similarity index 75%
rename from tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentPersistence.java
rename to tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentPersistence.java
index 756f85d04ea4dd06618798eeab05c01f549fa913..9fbd23a7f7d04405e7b678fc7ab2ce448c46f9f8 100644
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentPersistence.java
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentPersistence.java
@@ -1,4 +1,4 @@
-package tdt4140.gr1800.app.core;
+package tdt4140.gr1800.app.doc;
 
 public interface IDocumentPersistence<D, L> extends IDocumentLoader<D, L>, IDocumentSaver<D, L> {
 }
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentSaver.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentSaver.java
similarity index 78%
rename from tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentSaver.java
rename to tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentSaver.java
index 4d2ee0a3807554f6f4868f669ec3621007d82d24..b9a5d9264be304554845f6c5592c5aec9a79d741 100644
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentSaver.java
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentSaver.java
@@ -1,4 +1,4 @@
-package tdt4140.gr1800.app.core;
+package tdt4140.gr1800.app.doc;
 
 public interface IDocumentSaver<D, L> {
 	public void saveDocument(D document, L documentLocation) throws Exception;
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentStorage.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentStorage.java
similarity index 63%
rename from tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentStorage.java
rename to tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentStorage.java
index 147bd16774ed90ac6e98643484c1392fd5e842bb..a037c42a38494ed0736c191f44a40f0e1dd03661 100644
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/IDocumentStorage.java
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentStorage.java
@@ -1,4 +1,4 @@
-package tdt4140.gr1800.app.core;
+package tdt4140.gr1800.app.doc;
 
 import java.io.IOException;
 import java.util.Collection;
@@ -7,6 +7,9 @@ public interface IDocumentStorage<L> {
 	public L getDocumentLocation();
 	public void setDocumentLocation(L documentLocation);
 
+	public void addDocumentStorageListener(IDocumentStorageListener<L> documentStorageListener);
+	public void removeDocumentStorageListener(IDocumentStorageListener<L> documentStorageListener);
+
 	public void newDocument();
 	public void openDocument(L documentLocation) throws IOException;
 	public void saveDocument() throws IOException;
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentStorageListener.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentStorageListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a21cdc63a83391fae9c7d1dd13abcce47e807d1
--- /dev/null
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/doc/IDocumentStorageListener.java
@@ -0,0 +1,5 @@
+package tdt4140.gr1800.app.doc;
+
+public interface IDocumentStorageListener<L> {
+	public void documentLocationChanged(L documentLocation, L oldDocumentLocation);
+}
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/gpx/GpxDocumentConverter.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/gpx/GpxDocumentConverter.java
index 55550bf54b9be9daba07ae3c71bb12ae3de6f396..7324eb5c112618c1ebbc5413155c696d727b8858 100644
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/gpx/GpxDocumentConverter.java
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/gpx/GpxDocumentConverter.java
@@ -11,8 +11,8 @@ import io.jenetics.jpx.Track;
 import io.jenetics.jpx.TrackSegment;
 import io.jenetics.jpx.WayPoint;
 import tdt4140.gr1800.app.core.GeoLocations;
-import tdt4140.gr1800.app.core.IDocumentLoader;
 import tdt4140.gr1800.app.core.LatLong;
+import tdt4140.gr1800.app.doc.IDocumentLoader;
 
 public class GpxDocumentConverter implements IDocumentLoader<Collection<GeoLocations>, File> {
 
diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/gpx/GpxDocumentLoader.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/gpx/GpxDocumentLoader.java
index 28e971d9f84e2f2a13c9e5b73843603d80cdcd0f..b7dcb43a46239d18a34e3b1dce828ce2a803d0b0 100644
--- a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/gpx/GpxDocumentLoader.java
+++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/gpx/GpxDocumentLoader.java
@@ -4,7 +4,7 @@ import java.io.InputStream;
 import java.net.URL;
 
 import io.jenetics.jpx.GPX;
-import tdt4140.gr1800.app.core.IDocumentLoader;
+import tdt4140.gr1800.app.doc.IDocumentLoader;
 
 public class GpxDocumentLoader implements IDocumentLoader<GPX, URL> {
 	
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
index 25618224e011d14864f98f9bf4b26cce72be8960..bfda7a4524d5419067f9a0dba069740402aff30d 100644
--- 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
@@ -1,13 +1,13 @@
 [
   {
-    "id" : "1",
+    "name" : "1",
     "locations" : [
       { "latitude" : "63", "longitude" : "10" },
       [ "63.1", "10.1" ]
     ]
   },
   {
-    "id" : "2",
+    "name" : "2",
     "path" : "true",
     "locations" : [
       { "latitude" : "64", "longitude" : "11" },
diff --git a/tdt4140-gr1800/app.core/src/test/java/tdt4140/gr1800/app/core/AppTest.java b/tdt4140-gr1800/app.core/src/test/java/tdt4140/gr1800/app/core/AppTest.java
index 8add30329d13176bfa9a549f2d4defd5304112d8..60baab304af770ab0be1412a37b19e277ae35556 100644
--- a/tdt4140-gr1800/app.core/src/test/java/tdt4140/gr1800/app/core/AppTest.java
+++ b/tdt4140-gr1800/app.core/src/test/java/tdt4140/gr1800/app/core/AppTest.java
@@ -8,6 +8,8 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import tdt4140.gr1800.app.doc.IDocumentStorage;
+
 public class AppTest {
 
 	private App app;
diff --git a/tdt4140-gr1800/app.core/src/test/resources/tdt4140/gr1800/app/core/Achterbroek-route.gpx b/tdt4140-gr1800/app.core/src/test/resources/tdt4140/gr1800/app/core/Achterbroek-route.gpx
index e6ce49689300ce2b5c2b424e55bebbf697b36718..a006258ea21c91c5dedcb385650ec4abbee0ae9e 100644
--- a/tdt4140-gr1800/app.core/src/test/resources/tdt4140/gr1800/app/core/Achterbroek-route.gpx
+++ b/tdt4140-gr1800/app.core/src/test/resources/tdt4140/gr1800/app/core/Achterbroek-route.gpx
@@ -6,6 +6,10 @@
   xmlns="http://www.topografix.com/GPX/1/0"
   xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
 
+<metadata>
+	<bounds minlat="51.396017" minlon="4.498043" maxlat="51.430402" maxlon="4.556108"/>
+</metadata>
+
 <wpt lat="51.39709" lon="4.501519">
    <name>START</name>
 </wpt>
diff --git a/tdt4140-gr1800/app.core/src/test/resources/tdt4140/gr1800/app/core/Achterbroek-track.gpx b/tdt4140-gr1800/app.core/src/test/resources/tdt4140/gr1800/app/core/Achterbroek-track.gpx
index 279b657067b2ff6c9d7a6e326e94dad918644b5a..755f740e02199462cfa12b8a5243c73f49258786 100644
--- a/tdt4140-gr1800/app.core/src/test/resources/tdt4140/gr1800/app/core/Achterbroek-track.gpx
+++ b/tdt4140-gr1800/app.core/src/test/resources/tdt4140/gr1800/app/core/Achterbroek-track.gpx
@@ -6,6 +6,10 @@
   xmlns="http://www.topografix.com/GPX/1/0"
   xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
 
+<metadata>
+	<bounds minlat="51.396017" minlon="4.498043" maxlat="51.430402" maxlon="4.556108"/>
+</metadata>
+
 <wpt lat="51.39709" lon="4.501519">
    <name>START</name>
 </wpt>
diff --git a/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FileMenuController.java b/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FileMenuController.java
index 8575711352c784bd9b29449bb148e06a556dbf81..e7566ea1b6288baf620f609be92f57361fe51cfe 100644
--- a/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FileMenuController.java
+++ b/tdt4140-gr1800/app.ui/src/main/java/tdt4140/gr1800/app/ui/FileMenuController.java
@@ -4,40 +4,26 @@ import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.function.Consumer;
 
 import javafx.event.ActionEvent;
 import javafx.fxml.FXML;
 import javafx.scene.control.Menu;
 import javafx.scene.control.MenuItem;
 import javafx.stage.FileChooser;
-import tdt4140.gr1800.app.core.IDocumentImporter;
-import tdt4140.gr1800.app.core.IDocumentStorage;
+import tdt4140.gr1800.app.doc.IDocumentImporter;
+import tdt4140.gr1800.app.doc.IDocumentStorage;
 
 public class FileMenuController {
 
-	private IDocumentStorage<File> documentStorage;
+	IDocumentStorage<File> documentStorage;
 
 	public void setDocumentStorage(IDocumentStorage<File> documentStorage) {
 		this.documentStorage = documentStorage;
 	}
-
-	private Consumer<IDocumentStorage<File>> onDocumentChanged;
-	
-	public void setOnDocumentChanged(Consumer<IDocumentStorage<File>> onDocumentChanged) {
-		this.onDocumentChanged = onDocumentChanged;
-	}
 	
 	@FXML
 	public void handleNewAction() {
 		documentStorage.newDocument();
-		fireDocumentChanged();
-	}
-
-	private void fireDocumentChanged() {
-		if (onDocumentChanged != null) {
-			onDocumentChanged.accept(documentStorage);
-		}
 	}
 
 	private List<File> recentFiles = new ArrayList<File>();
@@ -59,7 +45,7 @@ public class FileMenuController {
 	
 	private FileChooser fileChooser;
 
-	protected FileChooser getFileChooser() {
+	FileChooser getFileChooser() {
 		if (fileChooser == null) {
 			fileChooser = new FileChooser();
 		}
@@ -80,13 +66,16 @@ public class FileMenuController {
 			selection = fileChooser.showOpenDialog(null);
 		}
 		if (selection != null) {
-			try {
-				documentStorage.openDocument(selection);
-				updateRecentMenu(selection);
-				fireDocumentChanged();
-			} catch (IOException e) {
-				// TODO
-			}
+			handleOpenAction(selection);
+		}
+	}
+
+	void handleOpenAction(File selection) {
+		try {
+			documentStorage.openDocument(selection);
+			updateRecentMenu(selection);
+		} catch (IOException e) {
+			// TODO
 		}
 	}
 	
@@ -103,6 +92,10 @@ public class FileMenuController {
 	public void handleSaveAsAction() {
 		FileChooser fileChooser = getFileChooser();
 		File selection = fileChooser.showSaveDialog(null);
+		handleSaveAsAction(selection);
+	}
+
+	void handleSaveAsAction(File selection) {
 		File oldStorage = documentStorage.getDocumentLocation();
 		try {
 			documentStorage.setDocumentLocation(selection);
@@ -117,6 +110,10 @@ public class FileMenuController {
 	public void handleSaveCopyAsAction() {
 		FileChooser fileChooser = getFileChooser();
 		File selection = fileChooser.showSaveDialog(null);
+		handleSaveCopyAsAction(selection);
+	}
+
+	void handleSaveCopyAsAction(File selection) {
 		File oldStorage = documentStorage.getDocumentLocation();
 		try {
 			documentStorage.setDocumentLocation(selection);
@@ -135,6 +132,10 @@ public class FileMenuController {
 //		String path = selection.getPath();
 //		int pos = path.lastIndexOf('.');
 //		String ext = (pos > 0 ? path.substring(pos + 1) : null);
+		handleImportAction(selection);
+	}
+
+	void handleImportAction(File selection) {
 		for (IDocumentImporter<File> importer : documentStorage.getDocumentImporters()) {
 			try {
 				importer.importDocument(selection);
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
index 20c656259f1cb4765d8656bcfba0925eb30fdfcd..060a5a45fd0561d8bf17cf8d5a90b1a10a97c8aa 100644
--- 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
@@ -1,5 +1,7 @@
 package tdt4140.gr1800.app.ui;
 
+import java.io.File;
+import java.util.Collection;
 import java.util.Iterator;
 
 import fxmapcontrol.Location;
@@ -7,27 +9,29 @@ import fxmapcontrol.MapBase;
 import fxmapcontrol.MapItemsControl;
 import fxmapcontrol.MapNode;
 import fxmapcontrol.MapTileLayer;
+import javafx.application.Platform;
 import javafx.fxml.FXML;
 import javafx.scene.control.ComboBox;
 import javafx.scene.control.Slider;
 import tdt4140.gr1800.app.core.App;
 import tdt4140.gr1800.app.core.GeoLocated;
 import tdt4140.gr1800.app.core.GeoLocations;
-import tdt4140.gr1800.app.core.IGeoLocationsListener;
 import tdt4140.gr1800.app.core.LatLong;
+import tdt4140.gr1800.app.doc.IDocumentListener;
+import tdt4140.gr1800.app.doc.IDocumentStorage;
 
-public class FxAppController implements IGeoLocationsListener {
+public class FxAppController implements IDocumentListener<Collection<GeoLocations>, File> {
 
 	@FXML
-	private FileMenuController fileMenuController;
+	FileMenuController fileMenuController;
 
 	@FXML
 	private ComboBox<String> geoLocationsSelector;
 
 	@FXML
-	private MapBase mapView;
+	MapBase mapView;
 	
-	private MapItemsControl<MapNode> markersParent;
+	MapItemsControl<MapNode> markersParent;
 	
 	@FXML
 	private Slider zoomSlider;
@@ -37,8 +41,9 @@ public class FxAppController implements IGeoLocationsListener {
 	@FXML
 	public void initialize() {
 		app = new App();
-		fileMenuController.setDocumentStorage(app.getDocumentStorage());
-		fileMenuController.setOnDocumentChanged(documentStorage -> initMapMarkers());
+		IDocumentStorage<File> documentStorage = app.getDocumentStorage();
+		fileMenuController.setDocumentStorage(documentStorage);
+		documentStorage.addDocumentStorageListener(this);
 
 		geoLocationsSelector.getSelectionModel().selectedItemProperty().addListener((stringProperty, oldValue, newValue) -> updateGeoLocations());
 
@@ -48,10 +53,24 @@ public class FxAppController implements IGeoLocationsListener {
 		});
 		markersParent = new MapItemsControl<MapNode>();
 		mapView.getChildren().add(markersParent);
-		
-		app.addGeoLocationsListener(this);
 	}
 
+	//
+
+	@Override
+	public void documentLocationChanged(File documentLocation, File oldDocumentLocation) {
+	}
+	@Override
+	public void documentChanged(Collection<GeoLocations> document, Collection<GeoLocations> oldDocument) {
+		if (Platform.isFxApplicationThread()) {
+			initMapMarkers();
+		} else {
+			Platform.runLater(() -> initMapMarkers());
+		}
+	}
+
+	//
+
 	private Object updateGeoLocations() {
 		return null;
 	}
@@ -100,9 +119,4 @@ public class FxAppController implements IGeoLocationsListener {
 		}
 		return new LatLong(latSum / num, lonSum / num);
 	}
-
-	@Override
-	public void geoLocationsUpdated(GeoLocations geoLocations) {
-		initMapMarkers();
-	}
 }
diff --git a/tdt4140-gr1800/app.ui/src/main/resources/tdt4140/gr1800/app/ui/FileMenu.fxml b/tdt4140-gr1800/app.ui/src/main/resources/tdt4140/gr1800/app/ui/FileMenu.fxml
index 9515c49930b7552d21d2adf531bdd4dd09a54afb..5de3493684996e64d7318ffeb16707366da68b04 100644
--- a/tdt4140-gr1800/app.ui/src/main/resources/tdt4140/gr1800/app/ui/FileMenu.fxml
+++ b/tdt4140-gr1800/app.ui/src/main/resources/tdt4140/gr1800/app/ui/FileMenu.fxml
@@ -7,14 +7,14 @@
 
 <Menu xmlns:fx="http://javafx.com/fxml" text="File" fx:controller="tdt4140.gr1800.app.ui.FileMenuController">
 	<items>
-		<MenuItem text="New" onAction="#handleNewAction"/>
-		<MenuItem text="Open..." onAction="#handleOpenAction"/>
+		<MenuItem text="New" 		accelerator="Meta+N" 	onAction="#handleNewAction"/>
+		<MenuItem text="Open..."  	accelerator="Meta+O"		onAction="#handleOpenAction"/>
 		<Menu fx:id="recentMenu" text="Open Recent"/>
 		<SeparatorMenuItem/>
-		<MenuItem text="Save" onAction="#handleSaveAction"/>
-		<MenuItem text="Save As..." onAction="#handleSaveAsAction"/>
-		<MenuItem text="Save Copy As..." onAction="#handleSaveCopyAsAction"/>
+		<MenuItem text="Save"		accelerator="Meta+S"		onAction="#handleSaveAction"/>
+		<MenuItem text="Save As..." 							onAction="#handleSaveAsAction"/>
+		<MenuItem text="Save Copy As..." 					onAction="#handleSaveCopyAsAction"/>
 		<SeparatorMenuItem/>
-		<MenuItem text="Import..." onAction="#handleImportAction"/>
+		<MenuItem text="Import..." 							onAction="#handleImportAction"/>
 	</items>
 </Menu>
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
index 5bded2b5f54d04a93d671277315385eaaaf1a542..b31cb41137d1c57885ba42e7d64391ea1828eaee 100644
--- 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
@@ -1,16 +1,37 @@
 package tdt4140.gr1800.app.ui;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.testfx.framework.junit.ApplicationTest;
+import org.testfx.util.WaitForAsyncUtils;
 
 import fxmapcontrol.MapBase;
+import fxmapcontrol.MapItemsControl;
+import javafx.collections.ObservableList;
 import javafx.fxml.FXMLLoader;
 import javafx.scene.Node;
 import javafx.scene.Parent;
 import javafx.scene.Scene;
+import javafx.scene.control.ComboBox;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyCodeCombination;
+import javafx.scene.input.KeyCombination;
+import javafx.stage.FileChooser;
 import javafx.stage.Stage;
+import tdt4140.gr1800.app.core.GeoLocations;
+import tdt4140.gr1800.app.doc.IDocumentStorageListener;
 
 public class FxAppTest extends ApplicationTest {
 
@@ -21,20 +42,122 @@ public class FxAppTest extends ApplicationTest {
     		}
     }
 
+    private FxAppController controller;
+    
 	@Override
     public void start(Stage stage) throws Exception {
-        Parent root = FXMLLoader.load(getClass().getResource("FxApp.fxml"));
-        
+		FXMLLoader loader = new FXMLLoader(getClass().getResource("FxApp.fxml"));
+        Parent root = loader.load();
+        this.controller = loader.getController();
         Scene scene = new Scene(root);
         
         stage.setTitle("JavaFX and Maven");
         stage.setScene(scene);
         stage.show();
     }
+	
+	private File geoLocationsDotJson = null;
 
+	@Before
+	public void ensureGeoLocationsDotJson() {
+		openGeoLocationsDotJson();
+		WaitForAsyncUtils.waitForFxEvents();
+	}
+	
+	protected void openGeoLocationsDotJson() {
+		Assert.assertNotNull(this.controller);
+		InputStream inputStream = GeoLocations.class.getResourceAsStream("geoLocations.json");
+		try {
+			geoLocationsDotJson = File.createTempFile("geoLocations", ".json");
+			geoLocationsDotJson.deleteOnExit();
+			Files.copy(inputStream, geoLocationsDotJson.toPath(), StandardCopyOption.REPLACE_EXISTING);
+		} catch (IOException e) {
+			Assert.fail(e.getMessage());
+		}
+		try {
+			controller.fileMenuController.documentStorage.openDocument(geoLocationsDotJson);
+		} catch (IOException e) {
+			Assert.fail(e.getMessage());			
+		}
+	}
+	
+	@Test
+	public void testMapExists() {
+		Node map = lookup("#mapView").query();
+		Assert.assertTrue(map instanceof MapBase);
+	}
+
+	private <T> T getItem(Iterable<?> items, Class<T> clazz, int num) {
+		for (Object child : items) {
+			if (clazz.isInstance(child)) {
+				num--;
+				if (num <= 0) {
+					return (T) child;					
+				}
+			}
+		}
+		return null;
+	}
+	
+	private <T> Collection<T> getItems(Iterable<?> items, Class<T> clazz, int count) {
+		Collection<T> result = new ArrayList<T>();
+		for (Object child : items) {
+			if (clazz.isInstance(child)) {
+				result.add((T) child);
+				count--;
+				if (count <= 0) {
+					return result;					
+				}
+			}
+		}
+		return null;
+	}
+	
     @Test
-    public void testMapExists() {
-    		Node map = lookup("#mapView").query();
-    		Assert.assertTrue(map instanceof MapBase);
+    public void testMapHasMarkers() {
+    		Assert.assertNotNull(getItems(controller.markersParent.getItems(), MapMarker.class, 4));
+    }
+
+    @Test
+    public void testGeoLocationsSelector() {
+	    	Node combo = lookup("#geoLocationsSelector").query();
+	    	Assert.assertTrue(combo instanceof ComboBox);
+	    	ObservableList<?> items = ((ComboBox<?>) combo).getItems();
+	    	Assert.assertEquals(2, items.size());
+	    	Assert.assertEquals("1 (2)", items.get(0));
+	    	Assert.assertEquals("2 (2)", items.get(1));	    	
+    }
+    
+//    @Test
+    public void testOpenTestDocument() {
+    		try {
+    			InputStream inputStream = GeoLocations.class.getResourceAsStream("geoLocations.json");
+			File tempFile = File.createTempFile("geoLocations", ".json");
+			tempFile.deleteOnExit();
+    			Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+    			FileChooser fileChooser = controller.fileMenuController.getFileChooser();
+    			fileChooser.setInitialDirectory(tempFile.getParentFile());
+//    			fileChooser.setInitialFileName(tempFile.getName());
+    			KeyCodeCombination openKeys = new KeyCodeCombination(KeyCode.O, KeyCombination.META_DOWN);
+    			push(openKeys);
+    			sleep(1, TimeUnit.SECONDS);
+    			String name = tempFile.getName().substring(0, 1);
+    			for (int i = 0; i < name.length(); i++) {
+    				push(KeyCode.getKeyCode(String.valueOf(name.charAt(i)).toUpperCase()));
+    			}
+    			final File[] documentLocations = new File[1];
+    			controller.fileMenuController.documentStorage.addDocumentStorageListener(new IDocumentStorageListener<File>() {
+    				@Override
+    				public void documentLocationChanged(File documentLocation, File oldDocumentLocation) {
+    					documentLocations[0] = documentLocation;
+    				}
+    			});
+    			push(KeyCode.ENTER);
+    			sleep(1, TimeUnit.SECONDS);
+    			Assert.assertEquals(tempFile.getCanonicalPath(), String.valueOf(documentLocations[0]));
+    		} catch (IOException e) {
+    			System.out.println(e);
+			Assert.fail(e.getMessage());
+		}
     }
 }