Commit 5571f382 authored by Luna Riegel's avatar Luna Riegel
Browse files

Merge branch 'dev' into 'master'

CityDoctor Version 3.18.0

See merge request !37
parents 87dba3fa 61859d4f
Pipeline #12247 passed with stage
in 2 minutes and 31 seconds
......@@ -101,7 +101,7 @@ public class RingSelfIntersectionTest {
@Test
public void testSelfIntPoints4() throws CityGmlParseException, IOException, InvalidGmlFileException {
CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml");
for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) {
for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) {
LinearRing r = p.getExteriorRing();
CheckResult cr = r.getCheckResult(CheckId.C_GE_R_SELF_INTERSECTION);
assertEquals(ResultStatus.OK, cr.getResultStatus());
......@@ -131,7 +131,7 @@ public class RingSelfIntersectionTest {
@Test
public void testSelfIntPoints7() throws CityGmlParseException, IOException, InvalidGmlFileException {
CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0005.gml", 2);
for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) {
for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) {
LinearRing r = p.getExteriorRing();
CheckResult cr = r.getCheckResult(CheckId.C_GE_R_SELF_INTERSECTION);
assertEquals(ResultStatus.OK, cr.getResultStatus());
......
......@@ -43,7 +43,7 @@ public class ShellNotClosedSystemTest {
@Test
public void testShellNotClosed1() throws CityGmlParseException, IOException, InvalidGmlFileException {
CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml");
Geometry g = c.getBuildings().get(0).getGeometries().get(0);
Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0);
CheckResult cr = g.getCheckResult(CheckId.C_GE_S_NOT_CLOSED);
assertEquals(ResultStatus.OK, cr.getResultStatus());
}
......@@ -51,7 +51,7 @@ public class ShellNotClosedSystemTest {
@Test
public void testShellNotClosed2() throws CityGmlParseException, IOException, InvalidGmlFileException {
CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0002-T0001.gml");
Geometry g = c.getBuildings().get(0).getGeometries().get(0);
Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0);
CheckResult cr = g.getCheckResult(CheckId.C_GE_S_NOT_CLOSED);
assertEquals(ResultStatus.ERROR, cr.getResultStatus());
assertEquals(ErrorId.GE_S_NOT_CLOSED, cr.getError().getErrorId());
......
......@@ -22,6 +22,7 @@ import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
......@@ -89,15 +90,16 @@ public class TestUtil {
if (gmlId == null) {
return null;
}
Polygon result = getPolygonById(gmlId, model.getBuildings());
Polygon result = getPolygonById(gmlId, model.getBuildings().toList());
if (result != null) {
return result;
}
result = getPolygonById(gmlId, model.getVegetation());
result = getPolygonById(gmlId, model.getVegetation().toList());
if (result != null) {
return result;
}
return getPolygonById(gmlId, model.getTransportation());
return getPolygonById(gmlId, model.getTransportation().toList());
}
private static Polygon getPolygonById(String gmlId, List<? extends CityObject> features) {
......@@ -136,22 +138,17 @@ public class TestUtil {
if (featureId == null) {
return null;
}
for (CityObject co : model.getBuildings()) {
if (featureId.equals(co.getGmlId().getGmlString())) {
return co;
}
Optional<? extends CityObject> result = null;
result = model.getBuildings().filter(b -> featureId.equals(b.getGmlId().toString())).findFirst();
if (result.isPresent()){
return result.get();
}
for (CityObject co : model.getTransportation()) {
if (featureId.equals(co.getGmlId().getGmlString())) {
return co;
}
result = model.getTransportation().filter(t-> featureId.equals(t.getGmlId().toString())).findFirst();
if (result.isPresent()){
return result.get();
}
for (CityObject co : model.getVegetation()) {
if (featureId.equals(co.getGmlId().getGmlString())) {
return co;
}
}
return null;
}
result = model.getVegetation().filter(t-> featureId.equals(t.getGmlId().toString())).findFirst();
return result.orElse(null);
}
}
......@@ -43,7 +43,7 @@ public class TooFewPolygonsSystemTest {
@Test
public void testTooFewPolygons1() throws CityGmlParseException, IOException, InvalidGmlFileException {
CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml");
Geometry g = c.getBuildings().get(0).getGeometries().get(0);
Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0);
CheckResult cr = g.getCheckResult(CheckId.C_GE_S_TOO_FEW_POLYGONS);
assertEquals(ResultStatus.OK, cr.getResultStatus());
}
......@@ -51,7 +51,7 @@ public class TooFewPolygonsSystemTest {
@Test
public void testTooFewPolygons2() throws CityGmlParseException, IOException, InvalidGmlFileException {
CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0001-T0001.gml");
Geometry g = c.getBuildings().get(0).getGeometries().get(0);
Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0);
CheckResult cr = g.getCheckResult(CheckId.C_GE_S_TOO_FEW_POLYGONS);
assertEquals(ResultStatus.ERROR, cr.getResultStatus());
assertEquals(ErrorId.GE_S_TOO_FEW_POLYGONS, cr.getError().getErrorId());
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId>
<version>3.17.3</version>
<version>3.18.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>CityDoctorAutoPro</artifactId>
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId>
<version>3.17.3</version>
<version>3.18.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>CityDoctorGUI</artifactId>
......
#!/bin/sh
./runtime/bin/java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
\ No newline at end of file
#! /usr/bin/env sh
java -classpath "app/*:plugin/*" de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
......@@ -11,6 +11,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import de.hft.stuttgart.citydoctor2.parser.ProgressListener;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Alert;
......@@ -139,8 +140,6 @@ public class CheckDialog {
@FXML
private Label schematronFileLabel;
@FXML
private VBox zipArchiveOptionsVBox;
@FXML
private CheckBox streamCheckOption;
@FXML
......@@ -161,7 +160,6 @@ public class CheckDialog {
private CityDoctorController controller;
private FilterPane filterPane;
private MainWindow window;
private boolean zipArchiveMode;
public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException {
this.window = window;
......@@ -181,7 +179,6 @@ public class CheckDialog {
}
public void initialize() {
setupZipArchiveOptions();
createEnableColumn(geometricTable);
createNameColumn(geometricTable);
......@@ -286,46 +283,6 @@ public class CheckDialog {
});
}
private void setupZipArchiveOptions() {
streamCheckOption.selectedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
streamCheckParametersVBox.setDisable(!streamCheckOption.isSelected());
}
});
outputPathBtn.setOnAction(e -> {
DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setInitialDirectory(Path.of(Settings.get(Settings.LAST_OPEN_FOLDER)).getParent().toFile());
File f = directoryChooser.showDialog(stage.getOwner());
if (f != null) {
outputPathTextField.setText(f.getAbsolutePath());
Settings.set(Settings.LAST_OPEN_FOLDER, f.getAbsolutePath());
}
});
streamCheckOption.setText(Localization.getText("CheckDialog.streamCheckOption"));
streamCheckLabel.setTooltip(new Tooltip(Localization.getText("CheckDialog.streamCheckLabel")));
outputPathLabel.setText(Localization.getText("CheckDialog.outputPathLabel"));
outputPathBtn.setText(Localization.getText("CheckDialog.outputPathBtn"));
pdfReportsOption.setText(Localization.getText("CheckDialog.pdfReportsOption"));
xmlReportsOption.setText(Localization.getText("CheckDialog.xmlReportsOption"));
showZipArchiveOptions(false);
}
/**
* Shows the option panel for ZIP-Archive checking and enables the ZIP-Archive checking mode for this dialog.
*
* @param enabled
*/
public void showZipArchiveOptions(boolean enabled) {
zipArchiveOptionsVBox.setDisable(!enabled);
zipArchiveOptionsVBox.setVisible(enabled);
zipArchiveMode = enabled;
}
private void setupSelectButton() {
selectBtn.setOnAction(ae -> {
......@@ -494,25 +451,13 @@ public class CheckDialog {
String startingChecks = Localization.getText("CheckDialog.startingChecks");
logger.info(startingChecks);
}
if (zipArchiveMode) {
Path outputPath = null;
if (streamCheckOption.isSelected()) {
if (outputPathTextField.getText().isEmpty()) {
Alert warning = new Alert(Alert.AlertType.ERROR);
warning.setTitle("Error");
warning.setContentText(Localization.getText("CheckDialog.noPathError"));
warning.showAndWait();
return;
}
outputPath = Path.of(outputPathTextField.getText());
Platform.runLater(() -> progress.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS));
ProgressListener l = new ProgressListener() {
@Override
public void updateProgress(float state) {
Platform.runLater(() -> progress.setProgress(state));
}
controller.startZipFileChecks(config, progress::setProgress, streamCheckOption.isSelected(),
outputPath, pdfReportsOption.isSelected(),
xmlReportsOption.isSelected());
} else {
controller.startChecks(config, progress::setProgress);
}
};
controller.startChecks(config, l);
if (logger.isInfoEnabled()) {
String checksDone = Localization.getText("CheckDialog.checksDone");
......
......@@ -5,6 +5,7 @@ import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.database.UnconnectedCache;
import de.hft.stuttgart.citydoctor2.datastructure.*;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.gui.table.ErrorStat;
......@@ -16,15 +17,11 @@ import de.hft.stuttgart.citydoctor2.gui.tree.node.OpeningNode;
import de.hft.stuttgart.citydoctor2.gui.tree.node.TopLevelCityObjectNode;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.parser.*;
import de.hft.stuttgart.citydoctor2.utils.ArchivePacker;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import de.hft.stuttgart.citydoctor2.zip.MalformedZipFileException;
import de.hft.stuttgart.quality.adapter.types.ErrorAdapter;
import javafx.application.Platform;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.TreeItem;
......@@ -32,22 +29,18 @@ import javafx.scene.control.TreeView;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.CityModel;
import org.xml.sax.SAXParseException;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class CityDoctorController {
......@@ -60,9 +53,7 @@ public class CityDoctorController {
private CityDoctorModel model;
private ParserConfiguration currentConfig;
private String sourceFile;
private CityGmlZipArchive zipArchive;
private ZipEntryManager currentZipEntryManager;
private HashMap<CityDoctorModel, Checker> previousCheckers = null;
private Checker currentChecker;
private HighlightController highlightController;
......@@ -77,7 +68,9 @@ public class CityDoctorController {
private AtomicInteger waterChunkNr = new AtomicInteger(0);
private AtomicInteger landChunkNr = new AtomicInteger(0);
private AtomicInteger cityFurnitureChunkNr = new AtomicInteger(0);
private AtomicInteger genericCityObjectsChunkNr = new AtomicInteger(0);
private AtomicInteger otherCityObjectsChunkNr = new AtomicInteger(0);
public CityDoctorController(MainWindow mainWindow, HighlightController highlightController, Renderer renderer) {
this.mainWindow = mainWindow;
......@@ -95,7 +88,7 @@ public class CityDoctorController {
try {
Platform.runLater(() -> {
mainWindow.getOpenBtn().setDisable(true);
mainWindow.getZipManagerBtn().setDisable(true);
mainWindow.getWriteReportButton().setDisable(true);
mainWindow.getMeshGroup().getChildren().clear();
......@@ -103,12 +96,6 @@ public class CityDoctorController {
mainWindow.resetSearchBar();
mainWindow.resetFilterComboBox();
});
if (path.endsWith(".zip")) {
loadCityGmlZipFile(path, numberOfRoundingPlaces, useValidation, lowMemory);
return;
}
currentZipEntryManager = null;
previousCheckers = null;
currentChecker = null;
currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory);
GMLValidationHandler handler = null;
......@@ -135,7 +122,7 @@ public class CityDoctorController {
}
};
}
model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler, true);
model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler);
if (!validationIssues.isEmpty()) {
StringJoiner sj = new StringJoiner("\n");
validationIssues.stream().forEach(sj::add);
......@@ -155,120 +142,30 @@ public class CityDoctorController {
mainWindow.getSaveBtn().setDisable(false);
mainWindow.getResetCameraBtn().setDisable(false);
mainWindow.getHideRoofBtn().setDisable(false);
mainWindow.getZipManagerBtn().setDisable(true);
mainWindow.getNorthArrow().setVisible(true);
mainWindow.alignNorthArrow();
setupFeatureTabs();
buildTrees();
});
} finally {
Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false));
}
}
private void loadCityGmlZipFile(String path, int numberOfRoundingPlaces, boolean useValidation,
boolean lowMemory) {
currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory);
try {
zipArchive = CityGmlZipArchive.register(path);
} catch (MalformedZipFileException e) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
alert.showAndWait();
});
} catch (Exception e) {
Platform.runLater(() -> {
ExceptionDialog exDialog = new ExceptionDialog();
exDialog.show(e);
});
}
if (zipArchive != null) {
previousCheckers = new HashMap<>();
Platform.runLater(() -> {
try {
currentZipEntryManager = new ZipEntryManager(mainWindow.getMainStage(), this);
currentZipEntryManager.show();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
}
public void decompressZipEntry(CityGmlZipEntry entry, ProgressListener l) {
entry.loadEntry(currentConfig, l);
}
public CityGmlZipArchive getZipArchive() {
return zipArchive;
}
public void loadZipEntry(CityGmlZipEntry entry) {
if (!entry.isLoaded()) {
entry.loadEntry(currentConfig);
}
if (entry.getErrorType() != null) {
throw new IllegalArgumentException("Attempted to load erroneous zip entry");
}
try {
Platform.runLater(() -> {
mainWindow.getOpenBtn().setDisable(true);
mainWindow.getZipManagerBtn().setDisable(true);
mainWindow.getWriteReportButton().setDisable(true);
mainWindow.getMeshGroup().getChildren().clear();
clearTrees();
mainWindow.resetSearchBar();
mainWindow.resetFilterComboBox();
});
model = entry.getModel();
currentChecker = previousCheckers.getOrDefault(model, null);
mainWindow.getClickHandler().setConfig(currentConfig);
sourceFile = entry.getArchive().getArchivePath().toString();
renderer.reset();
Platform.runLater(() -> {
mainWindow.addFileNameToTitle(entry.getArchive().getArchivePath().toString());
mainWindow.getCheckButton().setDisable(false);
mainWindow.getLod1Btn().setDisable(false);
mainWindow.getLod2Btn().setDisable(false);
mainWindow.getLod3Btn().setDisable(false);
mainWindow.getLod4Btn().setDisable(false);
mainWindow.getWorldBtn().setDisable(false);
mainWindow.getSaveBtn().setDisable(false);
mainWindow.getResetCameraBtn().setDisable(false);
mainWindow.getHideRoofBtn().setDisable(false);
mainWindow.getZipManagerBtn().setDisable(false);
mainWindow.getNorthArrow().setVisible(true);
mainWindow.alignNorthArrow();
setupFeatureTabs();
buildTrees();
updateFeatureTrees();
mainWindow.getWriteReportButton().setDisable(currentChecker == null);
});
} finally {
Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false));
}
}
public void showZipManager() {
Platform.runLater(() -> currentZipEntryManager.show());
public static int getMaxFeaturesPerChunk(){
return MAX_FEATURES_PER_CHUNK;
}
private void setupFeatureTabs() {
mainWindow.setDisableOfFeatureTab(FeatureType.BUILDING, model.getBuildings().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.VEGETATION, model.getVegetation().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.TRANSPORTATION, model.getTransportation().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.TUNNEL, model.getTunnels().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.BRIDGE, model.getBridges().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.WATER, model.getWater().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.LAND, model.getLand().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.CITY_FURNITURE, model.getCityFurniture().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.GENERIC_CITY_OBJECT, model.getGenericCityObjects().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.BUILDING, model.getBuildingCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.VEGETATION, model.getVegetationCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.TRANSPORTATION, model.getTransportationCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.TUNNEL, model.getTunnelCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.BRIDGE, model.getBridgeCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.WATER, model.getWaterCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.LAND, model.getLandCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.CITY_FURNITURE, model.getCityFurnitureCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.OTHER_CITY_OBJECT, model.getOtherCityObjectsCount() == 0);
}
public void buildTrees() {
......@@ -281,7 +178,7 @@ public class CityDoctorController {
buildWater(model);
buildLand(model);
buildCityFurniture(model);
buildOtherCityObjects(model);
buildGenericCityObjects(model);
buildTunnel(model);
}
......@@ -294,126 +191,134 @@ public class CityDoctorController {
waterChunkNr.set(0);
landChunkNr.set(0);
cityFurnitureChunkNr.set(0);
genericCityObjectsChunkNr.set(0);
otherCityObjectsChunkNr.set(0);
}
private void buildLand(CityDoctorModel model) {
if (model.getLand().isEmpty()) {
if (model.getLandCount() == 0) {
return;
}
TreeView<Renderable> landView = mainWindow.getTerrainView();
TreeItem<Renderable> landRoot = new TreeItem<>(new CityObjectGroupNode(model.getLand(), "Land",
TreeItem<Renderable> landRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Land",
Color.BROWN));
landRoot.setExpanded(true);
landView.setRoot(landRoot);
buildLandFromList(model.getLand(), landView.getRoot());
addMoreButtonIfNecessary(model.getLand(), landView, landRoot, landChunkNr);
Supplier<Stream<CityObject>> supply = model::getLand;
buildLandTreeFromList(supply, landView.getRoot());
addMoreButtonForLand(landView, landRoot, landChunkNr, supply, model.getLandCount());
}
private void buildLandFromList(List<CityObject> list, TreeItem<Renderable> root) {
private void buildLandTreeFromList(Supplier<Stream<CityObject>> supply, TreeItem<Renderable> root) {
int landChunk = landChunkNr.get();
for (int i = landChunk * MAX_FEATURES_PER_CHUNK; i < (landChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
CityObject land = list.get(i);
supply.get().skip((long) landChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(land ->{
CityObjectNode node = new CityObjectNode(land);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(land, item);
}
});
}
private void buildCityFurniture(CityDoctorModel model) {
if (model.getCityFurniture().isEmpty()) {
if (model.getCityFurnitureCount() == 0) {
return;
}
TreeView<Renderable> cityFurnitureView = mainWindow.getCityFurnitureView();
TreeItem<Renderable> cityFurnitureRoot = new TreeItem<>(new CityObjectGroupNode(model.getCityFurniture(),
TreeItem<Renderable> cityFurnitureRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(),
"City Furniture", Color.BLUEVIOLET));
cityFurnitureRoot.setExpanded(true);
cityFurnitureView.setRoot(cityFurnitureRoot);
buildCityFurnitureTreeFromList(model.getCityFurniture(), cityFurnitureView.getRoot());
addMoreButtonIfNecessary(model.getCityFurniture(), cityFurnitureView, cityFurnitureRoot, cityFurnitureChunkNr);
Supplier<Stream<CityFurniture>> supply = model::getCityFurniture;
buildCityFurnitureTreeFromList(supply, cityFurnitureView.getRoot());
addMoreButtonForCityFurniture(cityFurnitureView, cityFurnitureRoot, cityFurnitureChunkNr, supply,
model.getCityFurnitureCount());
}
private void buildOtherCityObjects(CityDoctorModel model) {
if (model.getGenericCityObjects().isEmpty()) {
private void buildGenericCityObjects(CityDoctorModel model) {
if (model.getOtherCityObjectsCount() == 0) {
return;
}
TreeView<Renderable> otherObjectsView = mainWindow.getGenericCityObjectView();
TreeItem<Renderable> otherObjectsRoot = new TreeItem<>(new CityObjectGroupNode(model.getGenericCityObjects(),
TreeView<Renderable> otherObjectsView = mainWindow.getOtherCityObjectView();
TreeItem<Renderable> otherObjectsRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(),
"Generic CityObjects", Color.DARKGRAY));
otherObjectsRoot.setExpanded(true);
otherObjectsView.setRoot(otherObjectsRoot);
buildGenericCityObjectTreeFromList(model.getGenericCityObjects(), otherObjectsView.getRoot());
addMoreButtonIfNecessary(model.getGenericCityObjects(), otherObjectsView, otherObjectsRoot, genericCityObjectsChunkNr);
Supplier<Stream<CityObject>> supply = model::getOtherCityObjects;
buildOtherCityObjectsTreeFromList(supply, otherObjectsView.getRoot());
addMoreButtonForOtherCityObjects( otherObjectsView, otherObjectsRoot, otherCityObjectsChunkNr, supply,
model.getOtherCityObjectsCount());
}
private void buildWater(CityDoctorModel model) {
if (model.getWater().isEmpty()) {
if (model.getWaterCount() == 0) {
return;
}
TreeView<Renderable> waterView = mainWindow.getWaterView();
TreeItem<Renderable> waterRoot = new TreeItem<>(new CityObjectGroupNode(model.getWater(), "Water",
TreeItem<Renderable> waterRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Water",
Color.LIGHTSKYBLUE));
waterRoot.setExpanded(true);
waterView.setRoot(waterRoot);
buildWaterTreeFromList(model.getWater(), waterRoot);
addMoreButtonIfNecessary(model.getWater(), waterView, waterRoot, waterChunkNr);
Supplier<Stream<WaterObject>> supply = model::getWater;
buildWaterTreeFromList(supply, waterRoot);
addMoreButtonForWater(waterView, waterRoot, waterChunkNr, supply, model.getWaterCount());
}
private void buildBridges(CityDoctorModel model) {
if (model.getBridges().isEmpty()) {
if (model.getBridgeCount() == 0) {
return;
}
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> bridgeRoot = new TreeItem<>(new CityObjectGroupNode(model.getBridges(), "Bridges",
TreeItem<Renderable> bridgeRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Bridges",
Color.CORAL));
bridgeRoot.setExpanded(true);
bridgeView.setRoot(bridgeRoot);
buildBridgeTreeFromList(model.getBridges(), bridgeView.getRoot());
addMoreButtonIfNecessary(model.getBridges(), bridgeView, bridgeRoot, bridgeChunkNr);
Supplier<Stream<BridgeObject>> supply = model::getBridges;
buildBridgeTreeFromList(supply, bridgeView.getRoot());
addMoreButtonForBridges(bridgeView, bridgeRoot, bridgeChunkNr, supply, model.getBridgeCount());
}
private void buildTransportation(CityDoctorModel model) {
if (model.getTransportation().isEmpty()) {
if (model.getTransportationCount() == 0) {
return;
}
TreeView<Renderable> transView = mainWindow.getTransportationView();
TreeItem<Renderable> transRoot = new TreeItem<>(new CityObjectGroupNode(model.getTransportation(),
TreeItem<Renderable> transRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(),
"Transportation", Color.YELLOW));
transRoot.setExpanded(true);
transView.setRoot(transRoot);
buildTransportationTreeFromList(model.getTransportation(), transView.getRoot());
addMoreButtonIfNecessary(model.getTransportation(), transView, transRoot, transportationChunkNr);
Supplier<Stream<TransportationObject>> supply = model::getTransportation;
buildTransportationTreeFromList(supply, transView.getRoot());
addMoreButtonForTransportation(transView, transRoot, transportationChunkNr, supply,
model.getTransportationCount());
}
private void buildTunnel(CityDoctorModel model) {
if (model.getTunnels().isEmpty()) {
if (model.getTunnelCount() == 0) {
return;
}
TreeView<Renderable> tunnelView = mainWindow.getTunnelView();
TreeItem<Renderable> tunnelRoot = new TreeItem<>(new CityObjectGroupNode(model.getTunnels(), "Tunnel",
TreeItem<Renderable> tunnelRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Tunnel",
Color.SLATEGRAY));
tunnelRoot.setExpanded(true);
tunnelView.setRoot(tunnelRoot);
buildTunnelTreeFromList(model.getTunnels(), tunnelRoot);
addMoreButtonIfNecessary(model.getTunnels(), tunnelView, tunnelRoot, tunnelChunkNr);
Supplier<Stream<Tunnel>> supply = model::getTunnels;
buildTunnelTreeFromList(supply, tunnelRoot);
addMoreButtonForTunnel(tunnelView, tunnelRoot, tunnelChunkNr, supply, model.getTunnelCount());
}
private void buildVegetation(CityDoctorModel model) {
if (model.getVegetation().isEmpty()) {
if (model.getVegetationCount() == 0) {
return;
}
TreeView<Renderable> vegetationsView = mainWindow.getVegetationView();
TreeItem<Renderable> vegRoot = new TreeItem<>(new CityObjectGroupNode(model.getVegetation(),
TreeItem<Renderable> vegRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(),
"Vegetation", Color.LIGHTGREEN));
vegRoot.setExpanded(true);
vegetationsView.setRoot(vegRoot);
buildVegetationTreeFromList(model.getVegetation(), vegRoot);
addMoreButtonIfNecessary(model.getVegetation(), vegetationsView, vegRoot, vegetationChunkNr);
Supplier<Stream<Vegetation>> supply = model::getVegetation;
buildVegetationTreeFromList(supply, vegRoot);
addMoreButtonForVegetation(vegetationsView, vegRoot, vegetationChunkNr, supply, model.getVegetationCount());
}
private void addMoreButtonIfNecessary(List<? extends CityObject> list, TreeView<Renderable> view,
......@@ -429,7 +334,7 @@ public class CityDoctorController {
chunkCounter.incrementAndGet();
int visibleFeatures = countVisibleNodes(view);
buildTreeFromList(list, root, chunkCounter);
// buildTreeFromList(list, root, chunkCounter);
updateTree(root);
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
......@@ -445,17 +350,34 @@ public class CityDoctorController {
}
}
private void moreButton(CityDoctorModel model, TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<CityObject>> streamSupplier){
int featureCount = model.getBuildingCount();
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildTreeFromList(streamSupplier, root, chunkCounter);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void buildBuildings(CityDoctorModel model) {
if (model.getBuildings().isEmpty()) {
if (model.getBuildingCount() == 0) {
return;
}
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = new TreeItem<>(new CityObjectGroupNode(model.getBuildings(), "Buildings",
TreeItem<Renderable> root = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Buildings",
Color.WHITE));
root.setExpanded(true);
buildingsView.setRoot(root);
buildBuildingTreeFromList(model.getBuildings(), root);
addMoreButtonToBuildingsIfNecessary(model.getBuildings(), buildingsView, root, buildingChunkNr);
Supplier<Stream<Building>> supply = model::getBuildings;
buildBuildingTreeFromList(supply, root);
addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, supply, model.getBuildingCount());
}
......@@ -471,7 +393,7 @@ public class CityDoctorController {
root.getChildren().remove(root.getChildren().size() - 1);
chunkCounter.getAndIncrement();
int visibleFeatures = countVisibleNodes(view);
buildBuildingTreeFromList(list, root);
// buildBuildingTreeFromList(list, root);
updateTree(root);
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
......@@ -487,6 +409,141 @@ public class CityDoctorController {
}
}
private void addMoreButtonForBuildings(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<Building>> supply, int featureCount) {
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildBuildingTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForBridges(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<BridgeObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildBridgeTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForVegetation(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<Vegetation>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildVegetationTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForTunnel(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<Tunnel>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildTunnelTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForTransportation(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<TransportationObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildTransportationTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForLand(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<CityObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildLandTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForWater(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<WaterObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildWaterTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForCityFurniture(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<CityFurniture>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildCityFurnitureTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForOtherCityObjects(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<CityObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildOtherCityObjectsTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private static int countVisibleNodes(TreeView<Renderable> view) {
return countVisibleNodes(view.getRoot()) + 1;
}
......@@ -501,17 +558,16 @@ public class CityDoctorController {
return visibleFeatures;
}
private void buildTreeFromList(List<? extends CityObject> cos, TreeItem<Renderable> root,
private void buildTreeFromList(Supplier<Stream<CityObject>> supply, TreeItem<Renderable> root,
AtomicInteger chunkCounter) {
int chunk = chunkCounter.get();
for (int i = chunk * MAX_FEATURES_PER_CHUNK; i < (chunk + 1) * MAX_FEATURES_PER_CHUNK && i < cos.size(); i++) {
CityObject co = cos.get(i);
int buildingChunk = buildingChunkNr.get();
supply.get().skip((long) buildingChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(co ->{
CityObjectNode node = new CityObjectNode(co);
TreeItem<Renderable> nodeItem = new TreeItem<>(node);
nodeItem.setExpanded(true);
root.getChildren().add(nodeItem);
createGeometryNodes(co, nodeItem);
}
});
}
private <T extends CityObject> void buildTreeFromListWithProducer(List<T> cos, TreeItem<Renderable> root,
......@@ -535,7 +591,7 @@ public class CityDoctorController {
mainWindow.getWaterView().setRoot(null);
mainWindow.getTerrainView().setRoot(null);
mainWindow.getCityFurnitureView().setRoot(null);
mainWindow.getGenericCityObjectView().setRoot(null);
mainWindow.getOtherCityObjectView().setRoot(null);
mainWindow.getErrorTree().getRoot().getChildren().clear();
mainWindow.getAttributeView().getRoot().getChildren().clear();
mainWindow.getGlobalErrorsView().getItems().clear();
......@@ -582,11 +638,9 @@ public class CityDoctorController {
return nodeItem;
}
private void buildBuildingTreeFromList(List<Building> list, TreeItem<Renderable> root) {
private void buildBuildingTreeFromList(Supplier<Stream<Building>> supply, TreeItem<Renderable> root) {
int buildingChunk = buildingChunkNr.get();
for (int i = buildingChunk * MAX_FEATURES_PER_CHUNK; i < (buildingChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
Building b = list.get(i);
supply.get().skip((long) buildingChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(b ->{
TreeItem<Renderable> item = buildTopLevelCityObjectNode(b, root, b.getBoundarySurfaces());
createBuildingInstallationNodes(b, item);
......@@ -596,14 +650,12 @@ public class CityDoctorController {
createBuildingStoreyNodes(b, item);
createBuildingUnitNodes(b, item);
createBuildingPartNodes(b, item);
}
});
}
private void buildBridgeTreeFromList(List<BridgeObject> list, TreeItem<Renderable> root) {
private void buildBridgeTreeFromList(Supplier<Stream<BridgeObject>> supply, TreeItem<Renderable> root) {
int bridgeChunk = bridgeChunkNr.get();
for (int i = bridgeChunk * MAX_FEATURES_PER_CHUNK; i < (bridgeChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
BridgeObject bridge = list.get(i);
supply.get().skip((long) bridgeChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(bridge ->{
TreeItem<Renderable> item = buildTopLevelCityObjectNode(bridge, root, bridge.getBoundarySurfaces());
createBridgeRoomNodes(bridge, item);
......@@ -611,55 +663,46 @@ public class CityDoctorController {
createBridgeFurnitureNodes(bridge, item);
createBridgeConstructiveElementsNodes(bridge, item);
createBridgePartNodes(bridge, item);
}
});
}
private void buildTransportationTreeFromList(List<TransportationObject> list, TreeItem<Renderable> root) {
private void buildTransportationTreeFromList(Supplier<Stream<TransportationObject>> supply, TreeItem<Renderable> root) {
int transportChunk = transportationChunkNr.get();
for (int i = transportChunk * MAX_FEATURES_PER_CHUNK; i < (transportChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
TransportationObject t = list.get(i);
TreeItem<Renderable> item = buildTopLevelCityObjectNode(t, root);
createTransportSectionNodes(t, item);
createTrafficSpacesNodes(t, item);
}
supply.get().skip((long) transportChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(trans ->{
TreeItem<Renderable> item = buildTopLevelCityObjectNode(trans, root);
createTransportSectionNodes(trans, item);
createTrafficSpacesNodes(trans, item);
});
}
private void buildVegetationTreeFromList(List<Vegetation> list, TreeItem<Renderable> root) {
private void buildVegetationTreeFromList(Supplier<Stream<Vegetation>> supply, TreeItem<Renderable> root) {
int vegetationChunk = vegetationChunkNr.get();
for (int i = vegetationChunk * MAX_FEATURES_PER_CHUNK; i < (vegetationChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
Vegetation v = list.get(i);
buildTopLevelCityObjectNode(v, root);
}
supply.get().skip((long) vegetationChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(veg ->{
buildTopLevelCityObjectNode(veg, root);
});
}
private void buildWaterTreeFromList(List<WaterObject> list, TreeItem<Renderable> root) {
private void buildWaterTreeFromList(Supplier<Stream<WaterObject>> supply, TreeItem<Renderable> root) {
int waterChunk = waterChunkNr.get();
for (int i = waterChunk * MAX_FEATURES_PER_CHUNK; i < (waterChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
WaterObject w = list.get(i);
buildTopLevelCityObjectNode(w, root);
}
supply.get().skip((long) waterChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(wat ->{
buildTopLevelCityObjectNode(wat, root);
});
}
private void buildCityFurnitureTreeFromList(List<CityFurniture> list, TreeItem<Renderable> root) {
private void buildCityFurnitureTreeFromList(Supplier<Stream<CityFurniture>> supply, TreeItem<Renderable> root) {
int cityFurnChunk = cityFurnitureChunkNr.get();
for (int i = cityFurnChunk * MAX_FEATURES_PER_CHUNK; i < (cityFurnChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
CityFurniture cf = list.get(i);
supply.get().skip((long) cityFurnChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(cf ->{
buildTopLevelCityObjectNode(cf, root);
}
});
}
private void buildGenericCityObjectTreeFromList(List<GenericCityObject> list, TreeItem<Renderable> root) {
int genericObjectChunk = genericCityObjectsChunkNr.get();
for (int i = genericObjectChunk * MAX_FEATURES_PER_CHUNK; i < (genericObjectChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
GenericCityObject goc = list.get(i);
buildTopLevelCityObjectNode(goc, root);
}
private void buildOtherCityObjectsTreeFromList(Supplier<Stream<CityObject>> supply, TreeItem<Renderable> root) {
int genericObjectChunk = otherCityObjectsChunkNr.get();
supply.get().skip((long) genericObjectChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(gen ->{
buildTopLevelCityObjectNode(gen, root);
});
}
private void createTransportSectionNodes(TransportationObject t, TreeItem<Renderable> root) {
......@@ -733,10 +776,9 @@ public class CityDoctorController {
}
private void buildTunnelTreeFromList(List<Tunnel> list, TreeItem<Renderable> root) {
private void buildTunnelTreeFromList(Supplier<Stream<Tunnel>> supply, TreeItem<Renderable> root) {
int tunnelChunk = tunnelChunkNr.get();
for (int i = tunnelChunk * MAX_FEATURES_PER_CHUNK; i < (tunnelChunk + 1) * MAX_FEATURES_PER_CHUNK && i < list.size(); i++) {
Tunnel tunnel = list.get(i);
supply.get().skip((long) tunnelChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(tunnel ->{
TreeItem<Renderable> item = buildTopLevelCityObjectNode(tunnel, root);
createTunnelHollowNodes(tunnel, item);
......@@ -744,7 +786,8 @@ public class CityDoctorController {
createTunnelFurnitureNodes(tunnel, item);
createTunnelConstructiveElementsNodes(tunnel, item);
createTunnelPartNodes(tunnel, item);
}
});
}
private void createTunnelInstallationNodes(Tunnel tunnel, TreeItem<Renderable> root) {
......@@ -1035,20 +1078,14 @@ public class CityDoctorController {
config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces());
config.setParserConfig(currentConfig);
currentChecker = new Checker(config, model);
if (previousCheckers != null) {
previousCheckers.put(model, currentChecker);
}
currentChecker.runChecks(l);
Platform.runLater(() -> {
// apply check results to tree views
buildTrees();
updateFeatureTrees();
updateTree(mainWindow.getPolygonsView().getRoot());
for (CheckError e : model.getGlobalErrors()) {
if (e instanceof SchematronError se) {
mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString() + " - " + se.getNameOfAttribute());
}
}
updateGlobalErrors();
renderer.refresh();
mainWindow.getWriteReportButton().setDisable(false);
});
......@@ -1057,134 +1094,10 @@ public class CityDoctorController {
}
}
public void startZipFileChecks(ValidationConfiguration config, ProgressListener l, boolean lowMemoryMode,
Path outputPath, boolean pdfReports, boolean xmlReports) {
if (zipArchive == null && logger.isWarnEnabled()) {
logger.warn(Localization.getText("CityDoctorController.noZipFile"));
}
if (lowMemoryMode) {
startZipFileCheckStream(config, outputPath, pdfReports, xmlReports);
return;
}
try {
Platform.runLater(() -> {
mainWindow.getCheckButton().setDisable(true);
mainWindow.getErrorTree().getRoot().getChildren().clear();
mainWindow.getGlobalErrorsView().getItems().clear();
});
previousCheckers = new HashMap<>();
zipArchive.mountArchive(currentConfig);
config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces());
config.setParserConfig(currentConfig);
int totalEntries = zipArchive.getEntries().size();
int checkedEntries = 0;
for (CityGmlZipEntry entry : zipArchive.getEntries()) {
if (entry.getErrorType() != null && entry.getModel() == null) {
continue;
}
model = entry.getModel();
currentChecker = new Checker(config, model);
currentChecker.runChecks();
previousCheckers.put(model, currentChecker);
checkedEntries++;
if (l != null) {
l.updateProgress((float) checkedEntries / totalEntries);
}
}
Platform.runLater(() -> {
// apply check results to tree views
updateFeatureTrees();
updateTree(mainWindow.getPolygonsView().getRoot());
for (CheckError e : model.getGlobalErrors()) {
if (e instanceof SchematronError se) {
mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString() + " - " + se.getNameOfAttribute());
}
}
renderer.refresh();
mainWindow.getWriteReportButton().setDisable(false);
currentZipEntryManager.refresh();
});
} finally {
Platform.runLater(() -> mainWindow.getCheckButton().setDisable(false));
}
}
private void startZipFileCheckStream(ValidationConfiguration valConfig, Path outputPath, boolean pdfReports,
boolean xmlReports) {
try {
Path outputZipDirectory = null;
if (outputPath.toFile().isDirectory()) {
String filename = FilenameUtils.removeExtension(zipArchive.getArchivePath().getFileName().toString());
filename = filename + "_validated";
outputZipDirectory = outputPath.resolve(filename);
Files.createDirectories(outputZipDirectory);
} else {
String filename = FilenameUtils.removeExtension(outputPath.toAbsolutePath().getFileName().toString());
outputZipDirectory = Path.of(filename);
}
String xmlReportsDirectory = null;
String pdfReportsDirectory = null;
if (xmlReports) {
xmlReportsDirectory = Files.createDirectories(
outputZipDirectory.resolve("xml_reports/")).toAbsolutePath().toString();
}
if (pdfReports) {
pdfReportsDirectory = Files.createDirectories(
outputZipDirectory.resolve("pdf_reports/")).toAbsolutePath().toString();
}
Checker.streamCheck(zipArchive, xmlReportsDirectory, pdfReportsDirectory, valConfig, outputZipDirectory.toString());
Desktop desktop = Desktop.getDesktop();
desktop.open(outputPath.toFile());
} catch (CityGmlParseException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void saveZipArchiveReports(File outputZipDirectory) {
if (zipArchive == null) {
return;
}
String directoryName = FilenameUtils.removeExtension(outputZipDirectory.getAbsolutePath());
Path tempOutput = Path.of(directoryName + File.separator);
File temp = null;
try {
temp = tempOutput.toFile();
for (CityGmlZipEntry entry : zipArchive.getEntries()) {
if (entry.getErrorType() != null || entry.getModel() == null) {
continue;
}
model = entry.getModel();
if (model.isValidated()) {
Checker checker = previousCheckers.get(model);
Files.createDirectories(tempOutput.resolve(entry.getEntrySubPath()).getParent());
checker.writeXmlReport(tempOutput.resolve(entry.getDisplayName() + "_report.xml").toString());
checker.writePdfReport(tempOutput.resolve(entry.getDisplayName() + "_report.pdf").toString());
}
}
ArchivePacker.packAndDeleteDirectory(tempOutput.toString());
temp = null;
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Export Report");
alert.setContentText(Localization.getText("CityDoctorController.saveZipArchiveReports"));
alert.showAndWait();
} catch (IOException e) {
logger.error(e);
} finally {
try {
if (temp != null) {
FileUtils.deleteDirectory(temp);
}
} catch (IOException e) {
logger.error(e);
}
private void updateGlobalErrors() {
GlobalErrorVisitor globErrVisitor = new GlobalErrorVisitor(mainWindow);
for (CheckError e : model.getGlobalErrors()) {
e.accept(globErrVisitor);
}
}
......@@ -1196,7 +1109,7 @@ public class CityDoctorController {
updateTree(mainWindow.getCityFurnitureView().getRoot());
updateTree(mainWindow.getTransportationView().getRoot());
updateTree(mainWindow.getWaterView().getRoot());
updateTree(mainWindow.getGenericCityObjectView().getRoot());
updateTree(mainWindow.getOtherCityObjectView().getRoot());
updateTree(mainWindow.getTunnelView().getRoot());
renderer.updateErrors();
}
......@@ -1236,15 +1149,13 @@ public class CityDoctorController {
private Map<ErrorId, ErrorStat> getErrorStats() {
Map<ErrorId, ErrorStat> stats = new HashMap<>();
addErrorStats(stats, model.getBridges());
addErrorStats(stats, model.getBuildings());
addErrorStats(stats, model.getLand());
addErrorStats(stats, model.getTunnels());
addErrorStats(stats, model.getTransportation());
addErrorStats(stats, model.getVegetation());
addErrorStats(stats, model.getWater());
addErrorStats(stats, model.getCityFurniture());
addErrorStats(stats, model.getGenericCityObjects());
List<CheckError> errors = new ArrayList<>();
model.createFeatureStream().forEach(co -> co.collectContainedErrors(errors));
Set<CheckError> filteredErrors = new HashSet<>(errors);
for (CheckError error : filteredErrors) {
ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new);
stat.incrementCount();
}
return stats;
}
......@@ -1258,13 +1169,15 @@ public class CityDoctorController {
ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new);
stat.incrementCount();
}
}
public void export(CityObject co) {
if (model == null) {
return;
}
CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile());
CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile(), new UnconnectedCache());
newModel.setCityModel(new CityModel());
newModel.addCityObject(co);
newModel.setParsedCityGMLVersion(model.getCityGMLVersion());
......@@ -1319,96 +1232,113 @@ public class CityDoctorController {
case WATER -> filterWaterTree(searchString);
case LAND -> filterLandTree(searchString);
case CITY_FURNITURE -> filterCityFurnitureTree(searchString);
case GENERIC_CITY_OBJECT -> filterGenericCityObjectTree(searchString);
case OTHER_CITY_OBJECT -> filterOtherCityObjectsTree(searchString);
}
}
private void filterBuildingTree(String searchString) {
List<Building> foundBuildings = filterFeatures(searchString, model.getBuildings());
Supplier<Stream<Building>> foundBuildings = () -> model.getBuildings().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundBuildings.get().count();
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = buildingsView.getRoot();
root.getChildren().clear();
buildBuildingTreeFromList(foundBuildings, root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr);
addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, foundBuildings, featureCount);
}
private void filterBridgeTree(String searchString) {
List<BridgeObject> foundBridges = filterFeatures(searchString, model.getBridges());
Supplier<Stream<BridgeObject>> foundBridges = () -> model.getBridges().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundBridges.get().count();
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> root = bridgeView.getRoot();
root.getChildren().clear();
buildBridgeTreeFromList(foundBridges, root);
updateTree(root);
addMoreButtonIfNecessary(foundBridges, bridgeView, root, bridgeChunkNr);
addMoreButtonForBridges(bridgeView, root, bridgeChunkNr, foundBridges, featureCount);
}
private void filterTunnelTree(String searchString) {
List<Tunnel> foundTunnel = filterFeatures(searchString, model.getTunnels());
Supplier<Stream<Tunnel>> foundTunnel = () -> model.getTunnels().filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundTunnel.get().count();
TreeView<Renderable> tunnelView = mainWindow.getTunnelView();
TreeItem<Renderable> root = tunnelView.getRoot();
root.getChildren().clear();
buildTunnelTreeFromList(foundTunnel, root);
updateTree(root);
addMoreButtonIfNecessary(foundTunnel, tunnelView, root, tunnelChunkNr);
addMoreButtonForTunnel(tunnelView, root, tunnelChunkNr, foundTunnel, featureCount);
}
private void filterVegetationTree(String searchString) {
List<Vegetation> foundVegetation = filterFeatures(searchString, model.getVegetation());
Supplier<Stream<Vegetation>> foundVegetation = () -> model.getVegetation().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundVegetation.get().count();
TreeView<Renderable> vegetationView = mainWindow.getVegetationView();
TreeItem<Renderable> root = vegetationView.getRoot();
root.getChildren().clear();
buildVegetationTreeFromList(foundVegetation, root);
updateTree(root);
addMoreButtonIfNecessary(foundVegetation, vegetationView, root, vegetationChunkNr);
addMoreButtonForVegetation(vegetationView, root, vegetationChunkNr, foundVegetation, featureCount);
}
private void filterTransportationTree(String searchString) {
List<TransportationObject> foundTransportation = filterFeatures(searchString, model.getTransportation());
Supplier<Stream<TransportationObject>> foundTransportation = () -> model.getTransportation().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundTransportation.get().count();
TreeView<Renderable> transportationView = mainWindow.getTransportationView();
TreeItem<Renderable> root = transportationView.getRoot();
root.getChildren().clear();
buildTransportationTreeFromList(foundTransportation, root);
updateTree(root);
addMoreButtonIfNecessary(foundTransportation, transportationView, root, transportationChunkNr);
addMoreButtonForTransportation(transportationView, root, transportationChunkNr,
foundTransportation, featureCount);
}
private void filterWaterTree(String searchString) {
List<WaterObject> foundWater = filterFeatures(searchString, model.getWater());
Supplier<Stream<WaterObject>> foundWater = () -> model.getWater().filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundWater.get().count();
TreeView<Renderable> waterView = mainWindow.getWaterView();
TreeItem<Renderable> root = waterView.getRoot();
root.getChildren().clear();
buildWaterTreeFromList(foundWater, root);
addMoreButtonIfNecessary(foundWater, waterView, root, waterChunkNr);
addMoreButtonForWater(waterView, root, waterChunkNr, foundWater, featureCount);
}
private void filterLandTree(String searchString) {
List<CityObject> foundLand = filterFeatures(searchString, model.getLand());
Supplier<Stream<CityObject>> foundLand = () -> model.getLand().filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundLand.get().count();
TreeView<Renderable> landView = mainWindow.getTerrainView();
TreeItem<Renderable> root = landView.getRoot();
root.getChildren().clear();
buildLandFromList(foundLand, root);
addMoreButtonIfNecessary(foundLand, landView, root, landChunkNr);
buildLandTreeFromList(foundLand, root);
addMoreButtonForLand(landView, root, landChunkNr, foundLand, featureCount);
}
private void filterCityFurnitureTree(String searchString) {
List<CityFurniture> foundCityFurniture = filterFeatures(searchString, model.getCityFurniture());
Supplier<Stream<CityFurniture>> foundCityFurniture = () -> model.getCityFurniture().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundCityFurniture.get().count();
TreeView<Renderable> cityFurnitureView = mainWindow.getCityFurnitureView();
TreeItem<Renderable> root = cityFurnitureView.getRoot();
root.getChildren().clear();
buildCityFurnitureTreeFromList(foundCityFurniture, root);
addMoreButtonIfNecessary(foundCityFurniture, cityFurnitureView, root, cityFurnitureChunkNr);
addMoreButtonForCityFurniture(cityFurnitureView, root, cityFurnitureChunkNr, foundCityFurniture, featureCount);
}
private void filterGenericCityObjectTree(String searchString) {
List<GenericCityObject> foundGenericCityObject = filterFeatures(searchString, model.getGenericCityObjects());
TreeView<Renderable> genericCityObjectView = mainWindow.getGenericCityObjectView();
private void filterOtherCityObjectsTree(String searchString) {
Supplier<Stream<CityObject>> foundGenericCityObject = () -> model.getOtherCityObjects().
filter(co ->featureFilter(co, searchString));
int featureCount = (int) foundGenericCityObject.get().count();
TreeView<Renderable> genericCityObjectView = mainWindow.getOtherCityObjectView();
TreeItem<Renderable> root = genericCityObjectView.getRoot();
root.getChildren().clear();
buildGenericCityObjectTreeFromList(foundGenericCityObject, root);
addMoreButtonIfNecessary(foundGenericCityObject, genericCityObjectView, root, genericCityObjectsChunkNr);
buildOtherCityObjectsTreeFromList(foundGenericCityObject, root);
addMoreButtonForOtherCityObjects(genericCityObjectView, root, otherCityObjectsChunkNr,
foundGenericCityObject, featureCount);
}
private <T extends CityObject> List<T> filterFeatures(String searchString, List<T> features) {
......@@ -1421,6 +1351,10 @@ public class CityDoctorController {
return foundFeatures;
}
private boolean featureFilter(CityObject co, String searchString) {
return co.getGmlId().getGmlString().contains(searchString);
}
public void resetSearch(FeatureType selectedTab) {
if (model == null) {
return;
......@@ -1455,141 +1389,192 @@ public class CityDoctorController {
}
mainWindow.resetSearchBar();
root.getChildren().clear();
List<Building> errorBuildings = new ArrayList<>();
for (Building b : model.getBuildings()) {
if (b.containsAnyError()) {
errorBuildings.add(b);
}
}
resetFeatureChunks();
buildBuildingTreeFromList(errorBuildings, root);
List<GmlId> foundBuildings = model.getCache().getErrorFeatureIds();
List<GmlId> idList = model.getBuildingIds();
foundBuildings.removeIf(gmlId -> (!idList.contains(gmlId)));
Supplier<Stream<Building>> supply = () -> model.getCache().getStream(foundBuildings).map(co -> (Building) co);
buildBuildingTreeFromList(supply, root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(errorBuildings, buildingsView, root, buildingChunkNr);
addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, supply, foundBuildings.size());
}
public void fillTreeViewWithErrorVegetation() {
TreeView<Renderable> vegetationView = mainWindow.getVegetationView();
TreeItem<Renderable> root = vegetationView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getVegetationView(), model.getVegetation(), vegetationChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundVegetation = model.getCache().getErrorFeatureIds();
List<GmlId> idList = model.getVegetationIds();
foundVegetation.removeIf(gmlId -> (!idList.contains(gmlId)));
Supplier<Stream<Vegetation>> supply = () -> model.getCache().getStream(foundVegetation).map(co -> (Vegetation) co);
buildVegetationTreeFromList(supply, root);
updateTree(root);
addMoreButtonForVegetation(vegetationView, root, vegetationChunkNr, supply, foundVegetation.size());
}
public void fillTreeViewWithErrorBridges() {
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> root = bridgeView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getBridgeView(), model.getBridges(), bridgeChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundBridge = model.getCache().getErrorFeatureIds();
List<GmlId> idList = model.getBridgeIds();
foundBridge.removeIf(gmlId -> (!idList.contains(gmlId)));
Supplier<Stream<BridgeObject>> supply = () -> model.getCache().getStream(foundBridge).map(co -> (BridgeObject) co);
buildBridgeTreeFromList(supply, root);
updateTree(root);
addMoreButtonForBridges(bridgeView, root, bridgeChunkNr, supply, foundBridge.size());
}
public void fillTreeViewWithErrorLand() {
TreeView<Renderable> landView = mainWindow.getTerrainView();
TreeItem<Renderable> root = landView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTerrainView(), model.getLand(), landChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundLand = model.getCache().getErrorFeatureIds();
List<GmlId> idList = model.getLandIds();
foundLand.removeIf(gmlId -> (!idList.contains(gmlId)));
Supplier<Stream<CityObject>> supply = () -> model.getCache().getStream(foundLand).map(co -> (CityObject) co);
buildLandTreeFromList(supply, root);
updateTree(root);
addMoreButtonForLand(landView, root, landChunkNr, supply, foundLand.size());
}
public void fillTreeViewWithErrorCityFurniture() {
TreeView<Renderable> cityFurnitureView = mainWindow.getCityFurnitureView();
TreeItem<Renderable> root = cityFurnitureView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getCityFurnitureView(),
model.getCityFurniture(), cityFurnitureChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundCityFurniture = model.getCache().getErrorFeatureIds();
List<GmlId> idList = model.getCityFurnitureIds();
foundCityFurniture.removeIf(gmlId -> (!idList.contains(gmlId)));
Supplier<Stream<CityFurniture>> supply = () -> model.getCache().getStream(foundCityFurniture).map(co -> (CityFurniture) co);
buildCityFurnitureTreeFromList(supply, root);
updateTree(root);
addMoreButtonForCityFurniture(cityFurnitureView, root, cityFurnitureChunkNr, supply, foundCityFurniture.size());
}
public void fillTreeViewWithErrorGenericCityObjects() {
public void fillTreeViewWithErrorOtherCityObjects() {
TreeView<Renderable> genericCityObjectsView = mainWindow.getOtherCityObjectView();
TreeItem<Renderable> root = genericCityObjectsView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getGenericCityObjectView(),
model.getGenericCityObjects(), genericCityObjectsChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundOtherCityObjects = model.getCache().getErrorFeatureIds();
List<GmlId> idList = model.getOtherCityObjectsIds();
foundOtherCityObjects.removeIf(gmlId -> (!idList.contains(gmlId)));
Supplier<Stream<CityObject>> supply = () -> model.getCache().getStream(foundOtherCityObjects).map(co -> (GenericCityObject) co);
buildOtherCityObjectsTreeFromList(supply, root);
updateTree(root);
addMoreButtonForOtherCityObjects(genericCityObjectsView, root, otherCityObjectsChunkNr, supply, foundOtherCityObjects.size());
}
public void fillTreeViewWithErrorTransportation() {
TreeView<Renderable> transportationView = mainWindow.getTransportationView();
TreeItem<Renderable> root = transportationView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTransportationView(), model.getTransportation(),
transportationChunkNr);
}
public void fillTreeViewWithErrorTunnel() {
if (model == null) {
if (root == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTunnelView(), model.getTunnels(), tunnelChunkNr);
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundTransportation = model.getCache().getErrorFeatureIds();
List<GmlId> idList = model.getTransportationIds();
foundTransportation.removeIf(gmlId -> (!idList.contains(gmlId)));
Supplier<Stream<TransportationObject>> supply = () -> model.getCache().getStream(foundTransportation).map(co -> (TransportationObject) co);
buildTransportationTreeFromList(supply, root);
updateTree(root);
addMoreButtonForTransportation(transportationView, root, transportationChunkNr, supply, foundTransportation.size());
}
public void fillTreeViewWithErrorWater() {
public void fillTreeViewWithErrorTunnel() {
TreeView<Renderable> tunnelView = mainWindow.getTunnelView();
TreeItem<Renderable> root = tunnelView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getWaterView(), model.getWater(), waterChunkNr);
}
private void fillTreeViewWithErrorCityObjects(TreeView<Renderable> treeView, List<? extends CityObject> objects,
AtomicInteger chunkCounter) {
TreeItem<Renderable> root = treeView.getRoot();
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
List<CityObject> errorObjects = new ArrayList<>();
for (CityObject co : objects) {
if (co.containsAnyError()) {
errorObjects.add(co);
}
}
buildTreeFromList(errorObjects, root, chunkCounter);
resetFeatureChunks();
List<GmlId> foundTunnel = model.getCache().getErrorFeatureIds();
List<GmlId> idList = model.getTunnelIds();
foundTunnel.removeIf(gmlId -> (!idList.contains(gmlId)));
Supplier<Stream<Tunnel>> supply = () -> model.getCache().getStream(foundTunnel).map(co -> (Tunnel) co);
buildTunnelTreeFromList(supply, root);
updateTree(root);
addMoreButtonIfNecessary(errorObjects, treeView, root, chunkCounter);
addMoreButtonForTunnel(tunnelView, root, tunnelChunkNr, supply, foundTunnel.size());
}
public void fillTreeViewFromFeatures(FeatureType selectedTab) {
public void fillTreeViewWithErrorWater() {
TreeView<Renderable> waterView = mainWindow.getWaterView();
TreeItem<Renderable> root = waterView.getRoot();
if (model == null) {
return;
}
mainWindow.resetSearchBar();
switch (selectedTab) {
case BUILDING:
buildBuildings(model);
updateTree(mainWindow.getBuildingsView().getRoot());
break;
case VEGETATION:
buildVegetation(model);
updateTree(mainWindow.getVegetationView().getRoot());
break;
case BRIDGE:
buildBridges(model);
updateTree(mainWindow.getBridgeView().getRoot());
break;
case LAND:
buildLand(model);
updateTree(mainWindow.getTerrainView().getRoot());
break;
case TRANSPORTATION:
buildTransportation(model);
updateTree(mainWindow.getTransportationView().getRoot());
break;
case TUNNEL:
buildTunnel(model);
updateTree(mainWindow.getTunnelView().getRoot());
break;
case WATER:
buildWater(model);
updateTree(mainWindow.getWaterView().getRoot());
break;
case CITY_FURNITURE:
buildCityFurniture(model);
updateTree(mainWindow.getCityFurnitureView().getRoot());
break;
case GENERIC_CITY_OBJECT:
buildOtherCityObjects(model);
updateTree(mainWindow.getGenericCityObjectView().getRoot());
break;
default:
throw new IllegalStateException();
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundWater = model.getCache().getErrorFeatureIds();
List<GmlId> idList = model.getWaterIds();
foundWater.removeIf(gmlId -> (!idList.contains(gmlId)));
Supplier<Stream<WaterObject>> supply = () -> model.getCache().getStream(foundWater).map(co -> (WaterObject) co);
buildWaterTreeFromList(supply, root);
updateTree(root);
addMoreButtonForWater(waterView, root, tunnelChunkNr, supply, foundWater.size());
}
public CityDoctorModel getModel() {
......@@ -1641,7 +1626,7 @@ public class CityDoctorController {
public void delete(TreeItem<Renderable> selectedItem) {
if (model == null) {
return;
}/* TODO: Rework this properly via Renderable implementation
}/* Old debug function, would first need a refactor due to the RenderNode and GeoDB reworks
Renderable render = selectedItem.getValue();
if (render instanceof BuildingNode node) {
model.getBuildings().remove(node.getBuilding());
......@@ -1654,37 +1639,19 @@ public class CityDoctorController {
public void errorFilterIndexChanged(Number newV) {
mainWindow.getMeshGroup().getChildren().clear();
mainWindow.unselectEverything();
if (newV.intValue() == 0) {
fillTreeViewFromFeatures(mainWindow.getSelectedTab());
} else if (newV.intValue() == 1) {
switch (mainWindow.getSelectedTab()) {
case BUILDING:
fillTreeViewWithErrorBuildings();
break;
case VEGETATION:
fillTreeViewWithErrorVegetation();
break;
case BRIDGE:
fillTreeViewWithErrorBridges();
break;
case LAND:
fillTreeViewWithErrorLand();
break;
case TRANSPORTATION:
fillTreeViewWithErrorTransportation();
break;
case WATER:
fillTreeViewWithErrorWater();
break;
case CITY_FURNITURE:
fillTreeViewWithErrorCityFurniture();
break;
case GENERIC_CITY_OBJECT:
fillTreeViewWithErrorGenericCityObjects();
break;
default:
throw new IllegalStateException("Unknown selected feature tab: " + mainWindow.getSelectedTab());
}
if (newV.intValue() == 0) { // Error filter was set to "All"
buildTrees();
updateFeatureTrees();
} else if (newV.intValue() == 1) { // Error filter was set to "With errors"
fillTreeViewWithErrorBuildings();
fillTreeViewWithErrorVegetation();
fillTreeViewWithErrorBridges();
fillTreeViewWithErrorLand();
fillTreeViewWithErrorTransportation();
fillTreeViewWithErrorTunnel();
fillTreeViewWithErrorWater();
fillTreeViewWithErrorCityFurniture();
fillTreeViewWithErrorOtherCityObjects();
} else {
throw new IllegalStateException("Unknown filter index selected: " + newV);
}
......
package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorVisitor;
import de.hft.stuttgart.citydoctor2.check.error.AllPolygonsWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeInvalidError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeValueWrongError;
import de.hft.stuttgart.citydoctor2.check.error.ConsecutivePointSameError;
import de.hft.stuttgart.citydoctor2.check.error.DegeneratedRingError;
import de.hft.stuttgart.citydoctor2.check.error.DependenciesNotMetError;
import de.hft.stuttgart.citydoctor2.check.error.MultipleConnectedComponentsError;
import de.hft.stuttgart.citydoctor2.check.error.NestedRingError;
import de.hft.stuttgart.citydoctor2.check.error.NonManifoldEdgeError;
import de.hft.stuttgart.citydoctor2.check.error.NonManifoldVertexError;
import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError;
import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonNormalsDeviation;
import de.hft.stuttgart.citydoctor2.check.error.NotCeilingError;
import de.hft.stuttgart.citydoctor2.check.error.NotFloorError;
import de.hft.stuttgart.citydoctor2.check.error.NotGroundError;
import de.hft.stuttgart.citydoctor2.check.error.NotWallError;
import de.hft.stuttgart.citydoctor2.check.error.NullAreaError;
import de.hft.stuttgart.citydoctor2.check.error.PlanarityError;
import de.hft.stuttgart.citydoctor2.check.error.PointTouchesEdgeError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonHoleOutsideError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonInteriorDisconnectedError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonIntersectingRingsError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonSameOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWithoutSurfaceError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
import de.hft.stuttgart.citydoctor2.check.error.RingError;
import de.hft.stuttgart.citydoctor2.check.error.RingNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.RingSelfIntersectionError;
import de.hft.stuttgart.citydoctor2.check.error.RingTooFewPointsError;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.check.error.SolidError;
import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
public class GlobalErrorVisitor implements ErrorVisitor {
private MainWindow mainWindow;
public GlobalErrorVisitor(MainWindow mainWindow) {
this.mainWindow = mainWindow;
}
@Override
public void visit(RingError err) {
}
@Override
public void visit(PolygonError err) {
}
@Override
public void visit(RingSelfIntersectionError err) {
}
@Override
public void visit(PlanarityError err) {
}
@Override
public void visit(PolygonHoleOutsideError err) {
}
@Override
public void visit(NonManifoldEdgeError err) {
}
@Override
public void visit(MultipleConnectedComponentsError err) {
}
@Override
public void visit(NestedRingError err) {
}
@Override
public void visit(NonManifoldVertexError err) {
}
@Override
public void visit(PolygonWrongOrientationError err) {
}
@Override
public void visit(PolygonSameOrientationError err) {
}
@Override
public void visit(SolidNotClosedError err) {
}
@Override
public void visit(DependenciesNotMetError err) {
}
@Override
public void visit(UnknownCheckError err) {
}
@Override
public void visit(RingNotClosedError err) {
}
@Override
public void visit(ConsecutivePointSameError err) {
}
@Override
public void visit(AllPolygonsWrongOrientationError err) {
}
@Override
public void visit(PolygonInteriorDisconnectedError err) {
}
@Override
public void visit(NullAreaError err) {
}
@Override
public void visit(RingTooFewPointsError err) {
}
@Override
public void visit(NonPlanarPolygonNormalsDeviation err) {
}
@Override
public void visit(NonPlanarPolygonDistancePlaneError err) {
}
@Override
public void visit(PolygonIntersectingRingsError err) {
}
@Override
public void visit(SolidSelfIntError err) {
}
@Override
public void visit(TooFewPolygonsError err) {
}
@Override
public void visit(RingDuplicatePointError err) {
}
@Override
public void visit(RingEdgeIntersectionError err) {
}
@Override
public void visit(PointTouchesEdgeError err) {
}
@Override
public void visit(NotCeilingError err) {
}
@Override
public void visit(NotFloorError err) {
}
@Override
public void visit(NotWallError err) {
}
@Override
public void visit(NotGroundError err) {
}
@Override
public void visit(SchematronError se) {
mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString() + " - " + se.getNameOfAttribute());
}
@Override
public void visit(SurfaceUnfragmentedError err) {
}
@Override
public void visit(DegeneratedRingError err) {
}
@Override
public void visit(AttributeMissingError err) {
mainWindow.getGlobalErrorsView().getItems().add(err.getErrorId().getIdString()
+ " - " + err.getNameOfAttribute());
}
@Override
public void visit(AttributeValueWrongError err) {
mainWindow.getGlobalErrorsView().getItems().add(err.getErrorId().getIdString()
+ " - " + err.getNameOfAttribute());
}
@Override
public void visit(AttributeInvalidError err) {
mainWindow.getGlobalErrorsView().getItems().add(err.getErrorId().getIdString()
+ " - " + err.getNameOfAttribute());
}
@Override
public void visit(PolygonWithoutSurfaceError err) {
}
@Override
public void visit(CheckError err) {
}
@Override
public void visit(SolidError err) {
}
}
......@@ -85,12 +85,6 @@ public class MainToolBar {
@FXML
private ImageView lod4View;
@FXML
private Button zipManagerBtn;
@FXML
private ImageView zipManagerView;
@FXML
private Button aboutBtn;
......@@ -153,7 +147,6 @@ public class MainToolBar {
setupReportButton();
setupResetCameraButton();
setupHideRoofButton();
setupZipManagerButton();
loadImages();
gridButton.setOnAction(ae -> renderer.showWireFrame(gridButton.isSelected()));
......@@ -232,10 +225,6 @@ public class MainToolBar {
Image img = new Image(inStream);
hideRoofView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/zip.png")) {
Image img = new Image(inStream);
zipManagerView.setImage(img);
}
} catch (IOException e) {
// ignore close exception
}
......@@ -347,14 +336,6 @@ public class MainToolBar {
}
private void setupZipManagerButton() {
zipManagerBtn.setDisable(true);
zipManagerBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.zip")));
zipManagerBtn.setOnAction(ae -> {
mainWindow.showZipManager();
});
}
public Button getCheckButton() {
return checkBtn;
}
......@@ -407,10 +388,6 @@ public class MainToolBar {
return resetCameraBtn;
}
public Button getZipManagerBtn() {
return zipManagerBtn;
}
public HBox getToolBar() {
return toolBar;
}
......
......@@ -453,6 +453,7 @@ public class MainWindow extends Application {
});
}
@SuppressWarnings("java:S2629")
private void checkForStartupLoading() {
if (loadFileAtStartup) {
logger.info(Localization.getText("MainWindow.loadGivenFile"));
......@@ -638,7 +639,7 @@ public class MainWindow extends Application {
selectedTab = FeatureType.CITY_FURNITURE;
break;
case 8:
selectedTab = FeatureType.GENERIC_CITY_OBJECT;
selectedTab = FeatureType.OTHER_CITY_OBJECT;
break;
default:
throw new IllegalStateException("Unknown tab index: " + index);
......@@ -672,7 +673,7 @@ public class MainWindow extends Application {
case CITY_FURNITURE:
cityFurnitureTab.setDisable(value);
break;
case GENERIC_CITY_OBJECT:
case OTHER_CITY_OBJECT:
otherObjectsTab.setDisable(value);
break;
default:
......@@ -801,10 +802,13 @@ public class MainWindow extends Application {
});
menu.getItems().add(copyToClipboardOption);
/* Was used for debugging the repair module, functionless since the RenderNode rework.
* Commented out for now, might be needed later on again
MenuItem deleteOption = new MenuItem(Localization.getText("MainWindow.delete"));
deleteOption.setOnAction(ae -> controller.delete(featureView.getSelectionModel().getSelectedItem()));
menu.getItems().add(deleteOption);
featureView.setContextMenu(menu);
*/
}
public void fetchCopyAction(Renderable node) {
......@@ -1011,7 +1015,7 @@ public class MainWindow extends Application {
return attributeView;
}
public TreeView<Renderable> getGenericCityObjectView() {
public TreeView<Renderable> getOtherCityObjectView() {
return otherObjectsView;
}
......@@ -1157,7 +1161,7 @@ public class MainWindow extends Application {
case WATER -> new Pair<>(waterTab, waterView);
case LAND -> new Pair<>(terrainTab, terrainView);
case CITY_FURNITURE -> new Pair<>(cityFurnitureTab, cityFurnitureView);
case GENERIC_CITY_OBJECT -> new Pair<>(otherObjectsTab, otherObjectsView);
case OTHER_CITY_OBJECT -> new Pair<>(otherObjectsTab, otherObjectsView);
default -> throw new IllegalArgumentException("unknown feature type: " + coType);
};
}
......@@ -1178,13 +1182,6 @@ public class MainWindow extends Application {
return mainToolBar.getOpenBtn();
}
public void showZipManager() {
controller.showZipManager();
}
public Button getZipManagerBtn() {
return mainToolBar.getZipManagerBtn();
}
public VertexClickHandler getClickHandler() {
return clickHandler;
......
......@@ -120,7 +120,7 @@ public class OpenFileDialog {
if (fc == null) {
fc = new FileChooser();
fc.setTitle(Localization.getText("OpenFileDialog.select"));
fc.getExtensionFilters().add(new ExtensionFilter("GML/XML/ZIP", "*.gml", "*.xml", "*.zip"));
fc.getExtensionFilters().add(new ExtensionFilter("GML/XML", "*.gml", "*.xml"));
fc.getExtensionFilters().add(new ExtensionFilter(Localization.getText("MainWindow.all"), "*.*"));
}
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
......@@ -153,9 +153,6 @@ public class OpenFileDialog {
Thread t = new Thread(() -> {
try {
if (path.endsWith(".zip")) {
Platform.runLater(() -> progress.setProgress(-1));
}
controller.loadCityGml(path, numberOfRoundingPlaces, progress::setProgress, useValidation,
lowMemory);
Platform.runLater(() -> stage.close());
......
......@@ -13,6 +13,7 @@ import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.*;
import java.util.*;
import java.util.stream.Stream;
public class TriangulatedGeometry {
......@@ -91,15 +92,15 @@ public class TriangulatedGeometry {
addPolygonDataFromCityObjects(model.getVegetation(), triGeom, Color.LIGHTGREEN, filters);
addPolygonDataFromCityObjects(model.getWater(), triGeom, Color.LIGHTSKYBLUE, filters);
addPolygonDataFromCityObjects(model.getCityFurniture(), triGeom, Color.BLUEVIOLET, filters);
addPolygonDataFromCityObjects(model.getGenericCityObjects(), triGeom, Color.BLACK, filters);
addPolygonDataFromCityObjects(model.getOtherCityObjects(), triGeom, Color.BLACK, filters);
return triGeom;
}
private static void addPolygonDataFromCityObjects(List<? extends CityObject> cos,
TriangulatedGeometry triGeom, Color color, List<ViewFilter> filters) {
private static void addPolygonDataFromCityObjects(Stream<? extends CityObject> cos,
TriangulatedGeometry triGeom, Color color, List<ViewFilter> filters) {
CityObjectCollector collector = new CityObjectCollector();
cos.forEach(cityObject -> cityObject.accept(collector));
collector.getCityObjects().forEach(cityObject -> addPolygonData(cityObject, triGeom, color, filters));
......
package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.gui.tree.ZipEntryListCell;
import de.hft.stuttgart.citydoctor2.gui.tree.node.ZipEntryNode;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import de.hft.stuttgart.citydoctor2.zip.ZipEntryErrorType;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.function.Predicate;
/**
* This class implements a GUI for managing a loaded {@link CityGmlZipArchive} in CityDoctor.
*/
public class ZipEntryManager {
private static final Logger logger = LogManager.getLogger(ZipEntryManager.class);
private Stage stage;
private CityGmlZipArchive archive;
@FXML
private TitledPane entriesPane;
@FXML
private TitledPane metadataPane;
@FXML
private Label subpathLbl;
@FXML
private TextField subpathValueTxt;
@FXML
private Label erroneousLbl;
@FXML
private Label erroneousValue;
@FXML
private Label filesizeLbl;
@FXML
private Label filesizeValue;
@FXML
private Label validatedLbl;
@FXML
private Label validatedValue;
@FXML
private Label objectCountLbl;
@FXML
private Label objectCountValue;
@FXML
private Button cancelBtn;
@FXML
private Button loadBtn;
@FXML
private ImageView loadImageView;
@FXML
private Button decompressBtn;
@FXML
private ImageView decompressImageView;
@FXML
private Button decompressAllBtn;
@FXML
private ImageView decompressAllImageView;
@FXML
private Button checkAllBtn;
@FXML
private ImageView checkAllImageView;
@FXML
private Button showReportBtn;
@FXML
private ImageView showReportImageView;
@FXML
private Button saveBtn;
@FXML
private ImageView saveImageView;
@FXML
private ListView<ZipEntryNode> entryList;
@FXML
private ProgressBar progress;
@FXML
private ProgressBar subProgress;
private CityDoctorController controller;
private int currentlyLoadedEntry = -1;
private CheckDialog dialog;
private final String unknownValueText = Localization.getText("ZipEntryManager.unknownValue");
private static final Predicate<ZipEntryNode> entryDecompressed = node ->
(node.getEntry().isLoaded() || node.getEntry().getErrorType() != null);
private static final Predicate<ZipEntryNode> entryValidated = entryDecompressed.and(node ->
(node.getEntry().getModel() != null && node.getEntry().getModel().isValidated()));
public ZipEntryManager(Window parent, CityDoctorController controller) throws IOException {
FXMLLoader loader = new FXMLLoader(ZipEntryManager.class.getResource("ZipEntryManager.fxml"));
loader.setController(this);
this.controller = controller;
archive = controller.getZipArchive();
VBox box = loader.load();
stage = new Stage();
stage.getIcons().add(new Image(MainWindow.class.getResourceAsStream("icons/CityDoctor-Logo-rot_klein.jpg")));
stage.setScene(new Scene(box));
stage.initOwner(parent);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle(Localization.getText("ZipEntryManager.title"));
stage.getScene().addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent event) -> {
if (event.getCode() == KeyCode.ESCAPE) {
stage.close();
}
});
dialog = new CheckDialog(null, parent, controller);
dialog.showZipArchiveOptions(true);
}
public void initialize() {
subProgress.setVisible(false);
entryList.getSelectionModel().selectedItemProperty().addListener((obs, oldI, newI) -> {
if (newI != null) {
showMetadata(newI.getEntry());
}
});
entryList.setCellFactory(param -> new ZipEntryListCell());
setupButtons();
applyLocalization();
populateZipEntryList();
}
private void setupButtons() {
try {
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/decompress_zipEntry.png")) {
Image img = new Image(inStream);
decompressImageView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/view_model.png")) {
Image img = new Image(inStream);
loadImageView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/decompress_all_zipEntries.png")) {
Image img = new Image(inStream);
decompressAllImageView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/check_all_zipEntries.png")) {
Image img = new Image(inStream);
checkAllImageView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/error_stat32x32.png")) {
Image img = new Image(inStream);
showReportImageView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/save.png")) {
Image img = new Image(inStream);
saveImageView.setImage(img);
}
} catch (IOException ignored) {
//ignore exceptions
}
decompressBtn.setOnAction(e -> {
disableTaskButtons();
setEntryListLocked(true);
Thread t = new Thread(() -> {
CityGmlZipEntry entry = entryList.getSelectionModel().getSelectedItem().getEntry();
logger.info("Decompressing entry \"{}\"", entry.getDisplayName());
controller.decompressZipEntry(entry, progressValue ->
Platform.runLater(() -> progress.setProgress(progressValue))
);
Platform.runLater(() -> {
refresh();
progress.setProgress(0);
setEntryListLocked(false);
});
});
t.setDaemon(true);
t.start();
});
loadBtn.setOnAction(e -> {
disableTaskButtons();
setEntryListLocked(true);
try {
int selectedIndex = entryList.getSelectionModel().getSelectedIndex();
if (selectedIndex == currentlyLoadedEntry) {
stage.hide();
return;
}
CityGmlZipEntry entry = entryList.getSelectionModel().getSelectedItem().getEntry();
if (entry.getErrorType() != null) {
logger.debug("IllegalState: loadBtn was pressed while an erroneous entry was selected");
populateZipEntryList(selectedIndex);
return;
}
controller.loadZipEntry(entry);
currentlyLoadedEntry = selectedIndex;
stage.hide();
} finally {
setEntryListLocked(false);
}
});
decompressAllBtn.setOnAction(e -> {
disableTaskButtons();
setEntryListLocked(true);
subProgress.setVisible(true);
subProgress.setProgress(0);
Thread t = new Thread(() -> {
progress.setProgress(0);
int count = 0;
int total = entryList.getItems().size();
for (ZipEntryNode node : entryList.getItems()) {
logger.info("Decompressing entry \"{}\"", node.getEntry().getDisplayName());
controller.decompressZipEntry(node.getEntry(), progressValue ->
Platform.runLater(() -> subProgress.setProgress(progressValue))
);
count++;
double progressValue = count * 1.0 / total;
Platform.runLater(() -> progress.setProgress(progressValue));
}
Platform.runLater(() -> {
subProgress.setVisible(false);
refresh();
progress.setProgress(0);
setEntryListLocked(false);
});
});
t.setDaemon(true);
t.start();
});
checkAllBtn.setOnAction(e -> {
disableTaskButtons();
dialog.show();
refresh();
});
showReportBtn.setOnAction(e -> {
disableTaskButtons();
setEntryListLocked(true);
try {
controller.loadZipEntry(entryList.getSelectionModel().getSelectedItem().getEntry());
if (currentlyLoadedEntry == -1) {
currentlyLoadedEntry = entryList.getSelectionModel().getSelectedIndex();
}
WriteReportDialog writeDialog = new WriteReportDialog(stage, controller, null);
writeDialog.show();
} catch (IOException ex) {
throw new RuntimeException(ex);
} finally {
controller.loadZipEntry(entryList.getItems().get(currentlyLoadedEntry).getEntry());
setEntryListLocked(false);
refresh();
}
});
showReportBtn.setDisable(true);
saveBtn.setOnAction(e -> {
disableTaskButtons();
setEntryListLocked(true);
try {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Export Zip file");
FileChooser.ExtensionFilter zipFilter = new FileChooser.ExtensionFilter("Zip File", "*.zip");
fileChooser.getExtensionFilters().add(zipFilter);
File f = fileChooser.showSaveDialog(stage.getOwner());
if (f != null) {
controller.saveZipArchiveReports(f);
}
} finally {
setEntryListLocked(false);
refresh();
}
});
saveBtn.setDisable(true);
cancelBtn.setOnAction(e -> stage.close());
}
private void applyLocalization() {
entriesPane.setText(Localization.getText("ZipEntryManager.entryListTitle"));
metadataPane.setText(Localization.getText("ZipEntryManager.metadata"));
subpathLbl.setText(Localization.getText("ZipEntryManager.subpathLbl"));
erroneousLbl.setText(Localization.getText("ZipEntryManager.erroneousLbl"));
filesizeLbl.setText(Localization.getText("ZipEntryManager.filesizeLbl"));
validatedLbl.setText(Localization.getText("ZipEntryManager.validatedLbl"));
objectCountLbl.setText(Localization.getText("ZipEntryManager.objectCountLbl"));
subpathValueTxt.setText(unknownValueText);
erroneousValue.setText(unknownValueText);
filesizeValue.setText(unknownValueText);
validatedValue.setText(unknownValueText);
objectCountValue.setText(unknownValueText);
loadBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.loadBtn")));
decompressBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.decompressBtn")));
decompressAllBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.decompressAllBtn")));
checkAllBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.checkAllBtn")));
showReportBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.showReportBtn")));
saveBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.saveBtn")));
cancelBtn.setText(Localization.getText("ZipEntryManager.cancelBtn"));
}
private void populateZipEntryList() {
populateZipEntryList(0);
}
private void populateZipEntryList(int selectionIndex) {
entryList.getItems().clear();
for (CityGmlZipEntry entry : archive.getEntries()) {
entryList.getItems().add(new ZipEntryNode(entry));
}
entryList.getSelectionModel().clearSelection();
entryList.getSelectionModel().select(selectionIndex);
showMetadata(entryList.getSelectionModel().getSelectedItem().getEntry());
decompressAllBtn.setDisable(entryList.getItems().stream().allMatch(entryDecompressed));
saveBtn.setDisable(entryList.getItems().stream().noneMatch(entryValidated));
}
private void showMetadata(CityGmlZipEntry entry) {
subpathValueTxt.setText(entry.getEntrySubPath());
if (entry.getFileSize() != -1L) {
long fileSize = entry.getFileSize();
long kb = 1024L;
long mb = kb * kb;
long gb = mb * kb;
if (fileSize < kb) {
filesizeValue.setText("< 1 KB");
} else if (fileSize < mb) {
filesizeValue.setText(String.format("%s KB", fileSize / kb));
} else if (fileSize < gb) {
filesizeValue.setText(String.format("%s MB", fileSize / mb));
} else {
double gigabytes = (double) fileSize / gb;
filesizeValue.setText(String.format("%.2f GB", gigabytes));
}
} else {
filesizeValue.setText(unknownValueText);
}
if (entry.getErrorType() != null) {
erroneousValue.setText(getErrorText(entry.getErrorType()));
validatedValue.setText(unknownValueText);
objectCountValue.setText(unknownValueText);
loadBtn.setDisable(true);
decompressBtn.setDisable(true);
showReportBtn.setDisable(true);
} else {
erroneousValue.setText(Localization.getText("ZipEntryManager.no"));
loadBtn.setDisable(!entry.isLoaded());
decompressBtn.setDisable(entry.isLoaded());
if (entry.getModel() == null) {
validatedValue.setText(unknownValueText);
objectCountValue.setText(unknownValueText);
return;
}
if (entry.getModel().isValidated()) {
validatedValue.setText(Localization.getText("ZipEntryManager.yes"));
showReportBtn.setDisable(false);
} else {
validatedValue.setText(Localization.getText("ZipEntryManager.no"));
showReportBtn.setDisable(true);
}
objectCountValue.setText(String.valueOf(entry.getModel().getNumberOfFeatures()));
}
}
private void disableTaskButtons() {
decompressBtn.setDisable(true);
loadBtn.setDisable(true);
decompressAllBtn.setDisable(true);
showReportBtn.setDisable(true);
saveBtn.setDisable(true);
}
public void refresh() {
populateZipEntryList(entryList.getSelectionModel().getSelectedIndex());
}
private String getErrorText(ZipEntryErrorType error) {
switch (error) {
case EXCESSIVE_FILESIZE -> {
return Localization.getText("ZipEntryManager.excessiveFileSize");
}
case INVALID_CITY_GML_FILE -> {
return Localization.getText("ZipEntryManager.invalidCityGml");
}
default -> {
return Localization.getText("ZipEntryManager.ioError");
}
}
}
private void setEntryListLocked(boolean locked) {
entryList.setMouseTransparent(locked);
entryList.setFocusTraversable(!locked);
}
public void show() {
Platform.runLater(() -> stage.showAndWait());
refresh();
}
}
package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.gui.CityDoctorController;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AddMoreButtonRunnable implements Runnable{
private int featureCount;
private final TreeView<Renderable> view;
private final TreeItem<Renderable> root;
private final AtomicInteger chunkCounter;
private static final int MAX_FEATURES_PER_CHUNK = CityDoctorController.getMaxFeaturesPerChunk();
protected AddMoreButtonRunnable(int featureCount, TreeView<Renderable> view,
TreeItem<Renderable> root, AtomicInteger chunkCounter){
this.featureCount = featureCount;
this.view = view;
this.root = root;
this.chunkCounter = chunkCounter;
}
@Override
public void run() {
// 29 is the height of one item
int numberOfDisplayedItems = (int) (view.getHeight() / 29);
int selectedIndex = view.getSelectionModel().getSelectedIndex();
// remove button node
root.getChildren().remove(root.getChildren().size() - 1);
chunkCounter.getAndIncrement();
int visibleFeatures = countVisibleNodes(view);
buildNodeTreeCall();
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
}
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
root.getChildren().add(new TreeItem<>(new ButtonRenderable(this)));
}
view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1);
}
/**
* Function hook for the buildTree call of the view
*/
public abstract void buildNodeTreeCall();
private static int countVisibleNodes(TreeView<Renderable> view) {
return countVisibleNodes(view.getRoot()) + 1;
}
private static int countVisibleNodes(TreeItem<Renderable> root) {
int visibleFeatures = root.getChildren().size();
for (TreeItem<Renderable> child : root.getChildren()) {
if (!child.getChildren().isEmpty() && child.isExpanded()) {
visibleFeatures += countVisibleNodes(child);
}
}
return visibleFeatures;
}
}
package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.gui.tree.node.ZipEntryNode;
import javafx.scene.control.ListCell;
public class ZipEntryListCell extends ListCell<ZipEntryNode> {
@Override
protected void updateItem(ZipEntryNode item, boolean empty) {
super.updateItem(item, empty);
if (!empty || item != null) {
setText(item.getText());
updateColor();
} else {
setText(null);
}
}
public void updateColor() {
setTextFill(getItem().getTextColor());
}
}
......@@ -12,9 +12,11 @@ public class CityObjectNode extends Renderable {
private static final Logger logger = LogManager.getLogger(CityObjectNode.class);
private final CityObject co;
private String text;
public CityObjectNode(CityObject co) {
this.co = co;
this.text = co.getDisplayText();
}
@Override
......@@ -30,7 +32,7 @@ public class CityObjectNode extends Renderable {
@Override
public String getText() {
return co.getDisplayText();
return text;
}
@Override
......
package de.hft.stuttgart.citydoctor2.gui.tree.node;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import javafx.scene.paint.Color;
public class ZipEntryNode {
private final CityGmlZipEntry entry;
public ZipEntryNode(CityGmlZipEntry entry) {
this.entry = entry;
}
public Color getTextColor() {
if (entry.getErrorType() != null) {
return Color.DARKRED;
} else if (entry.getModel() != null) {
if (entry.getModel().getNumberOfFeatures() == 0) {
return Color.GRAY;
}
if (entry.getModel().isValidated()) {
if (entry.getModel().collectErrors().isEmpty()) {
return Color.GREEN;
}
return Color.RED;
}
return Color.BLUE;
} else if (entry.isLoaded()) {
return Color.BLUE;
} else {
return Color.BLACK;
}
}
public String getText() {
return entry.getDisplayName();
}
public CityGmlZipEntry getEntry() {
return entry;
}
}
......@@ -2,7 +2,6 @@
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.control.Tab?>
......@@ -52,78 +51,6 @@
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
<VBox fx:id="zipArchiveOptionsVBox" prefHeight="176.0" prefWidth="485.0">
<children>
<HBox prefHeight="100.0" prefWidth="200.0">
<children>
<CheckBox fx:id="streamCheckOption" mnemonicParsing="false"
text="Use low memory mode">
<font>
<Font size="14.0"/>
</font>
</CheckBox>
<Label fx:id="streamCheckLabel" text="(?)" underline="true">
<opaqueInsets>
<Insets/>
</opaqueInsets>
<padding>
<Insets left="3.0"/>
</padding>
<font>
<Font size="14.0"/>
</font>
</Label>
</children>
</HBox>
<VBox fx:id="streamCheckParametersVBox" disable="true" prefHeight="200.0"
prefWidth="100.0">
<children>
<Label fx:id="outputPathLabel" text="Output path:">
<font>
<Font size="14.0"/>
</font>
</Label>
<HBox prefWidth="485.0">
<children>
<TextField fx:id="outputPathTextField" prefHeight="25.0"
prefWidth="291.0">
<font>
<Font size="14.0"/>
</font>
</TextField>
<Button fx:id="outputPathBtn" mnemonicParsing="false" prefHeight="30.0"
prefWidth="86.0" text="Select">
<font>
<Font size="14.0"/>
</font>
</Button>
</children>
</HBox>
<CheckBox fx:id="pdfReportsOption" mnemonicParsing="false"
text="Create PDF reports">
<padding>
<Insets top="10.0"/>
</padding>
<font>
<Font size="14.0"/>
</font>
</CheckBox>
<CheckBox layoutX="10.0" layoutY="60.0" mnemonicParsing="false"
text="Create XML reports" fx:id="xmlReportsOption">
<padding>
<Insets top="10.0"/>
</padding>
<font>
<Font size="14.0"/>
</font>
</CheckBox>
</children>
</VBox>
</children>
<HBox.margin>
<Insets left="30.0"/>
</HBox.margin>
</VBox>
</children>
</HBox>
<HBox spacing="5.0" VBox.vgrow="NEVER">
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment