Skip to content
Snippets Groups Projects
Commit d72e6349 authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

Some refactorings and improved testing.

parent 50e2bfd1
No related branches found
No related tags found
No related merge requests found
Showing
with 260 additions and 102 deletions
......@@ -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
......
package tdt4140.gr1800.app.core;
public interface IGeoLocationsListener {
public void geoLocationsUpdated(GeoLocations geoLocations);
}
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,7 +15,9 @@ 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) {
......@@ -24,6 +28,32 @@ public abstract class DocumentStorageImpl<D, L> implements IDocumentStorage<L>,
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
......
package tdt4140.gr1800.app.core;
package tdt4140.gr1800.app.doc;
import java.io.IOException;
......
package tdt4140.gr1800.app.doc;
public interface IDocumentListener<D, L> extends IDocumentStorageListener<L>{
public void documentChanged(D document, D oldDocument);
}
package tdt4140.gr1800.app.core;
package tdt4140.gr1800.app.doc;
public interface IDocumentLoader<D, L> {
public D loadDocument(L documentLocation) throws Exception;
......
package tdt4140.gr1800.app.core;
package tdt4140.gr1800.app.doc;
public interface IDocumentPersistence<D, L> extends IDocumentLoader<D, L>, IDocumentSaver<D, L> {
}
package tdt4140.gr1800.app.core;
package tdt4140.gr1800.app.doc;
public interface IDocumentSaver<D, L> {
public void saveDocument(D document, L documentLocation) throws Exception;
......
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;
......
package tdt4140.gr1800.app.doc;
public interface IDocumentStorageListener<L> {
public void documentLocationChanged(L documentLocation, L oldDocumentLocation);
}
......@@ -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> {
......
......@@ -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> {
......
[
{
"id" : "1",
"name" : "1",
"locations" : [
{ "latitude" : "63", "longitude" : "10" },
[ "63.1", "10.1" ]
]
},
{
"id" : "2",
"name" : "2",
"path" : "true",
"locations" : [
{ "latitude" : "64", "longitude" : "11" },
......
......@@ -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;
......
......@@ -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>
......
......@@ -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>
......
......@@ -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,15 +66,18 @@ public class FileMenuController {
selection = fileChooser.showOpenDialog(null);
}
if (selection != null) {
handleOpenAction(selection);
}
}
void handleOpenAction(File selection) {
try {
documentStorage.openDocument(selection);
updateRecentMenu(selection);
fireDocumentChanged();
} catch (IOException e) {
// TODO
}
}
}
@FXML
public void handleSaveAction() {
......@@ -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);
......
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,9 +53,23 @@ 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();
}
}
......@@ -7,11 +7,11 @@
<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" accelerator="Meta+S" onAction="#handleSaveAction"/>
<MenuItem text="Save As..." onAction="#handleSaveAsAction"/>
<MenuItem text="Save Copy As..." onAction="#handleSaveCopyAsAction"/>
<SeparatorMenuItem/>
......
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,10 +42,13 @@ 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");
......@@ -32,9 +56,108 @@ public class FxAppTest extends ApplicationTest {
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 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());
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment