Commit a5a82382 authored by Riegel's avatar Riegel
Browse files

Open Source release of CityDoctor-GUI

parent 7a22ca9c
Pipeline #10028 failed with stage
in 7 seconds
GUISettings.properties
/.gradle/
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
<ns prefix="gml" uri="http://www.opengis.net/gml"/>
<ns prefix="bldg" uri="http://www.opengis.net/citygml/building/2.0"/>
<pattern>
<rule context="//*:Building">
<assert test="count(descendant::*:lod1Solid) &gt; 0 or count(descendant::*:lod2Solid) &gt; 0 or count(descendant::*:lod3Solid) &gt; 0 or count(descendant::*:lod4Solid) &gt; 0"><value-of select="@gml:id | @id"/>||||SE_ATTRIBUTE_MISSING||any solid</assert>
</rule>
<rule context="//*:BuildingPart">
<assert test="count(*:lod1Solid) = 1 or count(*:lod2Solid) = 1 or count(*:lod3Solid) = 1 or count(*:lod4Solid) = 1"><value-of select="ancestor::*:Building/@*:id"/>||<value-of select="@gml:id | @id"/>||SE_ATTRIBUTE_MISSING||any solid</assert>
</rule>
</pattern>
</schema>
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId>
<version>3.14.1</version>
<relativePath></relativePath>
</parent>
<artifactId>CityDoctorGUI</artifactId>
<name>CityDoctorGUI</name>
<description>Graphical User Interface for CityDoctor</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorModel</artifactId>
</dependency>
<dependency>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorValidation</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j18-impl</artifactId>
</dependency>
</dependencies>
<profiles>
<profile>
<id>create-binaries</id>
<properties>
<win-jre>jre-${jre-version-short}-full</win-jre>
<lin-jre>${win-jre}</lin-jre>
<mac-jre>${win-jre}.jre</mac-jre>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.googlecode.maven-download-plugin</groupId>
<artifactId>download-maven-plugin</artifactId>
<version>1.7.0</version>
<executions>
<execution>
<id>downloadWindowsJre</id>
<phase>install</phase>
<goals>
<goal>wget</goal>
</goals>
<configuration>
<uri>https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-windows-amd64-full.zip</uri>
<unpack>false</unpack>
<outputDirectory>${project.build.directory}/jre/jre-win</outputDirectory>
<outputFileName>win-runtime.zip</outputFileName>
</configuration>
</execution>
<execution>
<id>downloadLinuxJre</id>
<phase>install</phase>
<goals>
<goal>wget</goal>
</goals>
<configuration>
<uri>https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-linux-amd64-full.tar.gz</uri>
<unpack>false</unpack>
<outputDirectory>${project.build.directory}/jre/jre-lin</outputDirectory>
<outputFileName>lin-runtime.tar.gz</outputFileName>
</configuration>
</execution>
<execution>
<id>downloadMacJre</id>
<phase>install</phase>
<goals>
<goal>wget</goal>
</goals>
<configuration>
<uri>https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-macos-amd64-full.zip</uri>
<unpack>false</unpack>
<outputDirectory>${project.build.directory}/jre/jre-mac</outputDirectory>
<outputFileName>mac-runtime.zip</outputFileName>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>unpack</id>
<phase>install</phase>
<configuration>
<target name="unpack">
<untar src="${project.build.directory}/jre/jre-lin/lin-runtime.tar.gz" dest="${project.build.directory}/jre/jre-lin/runtime" compression="gzip"></untar>
<unzip src="${project.build.directory}/jre/jre-win/win-runtime.zip" dest="${project.build.directory}/jre/jre-win/runtime"></unzip>
<unzip src="${project.build.directory}/jre/jre-mac/mac-runtime.zip" dest="${project.build.directory}/jre/jre-mac/runtime"></unzip>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<id>create-archive-no-runtime</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}-no-runtime</finalName>
<descriptors>
<descriptor>${project.basedir}/src/assembly/no_runtime/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
<execution>
<id>create-archive-win</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}-win</finalName>
<descriptors>
<descriptor>${project.basedir}/src/assembly/win/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
<execution>
<id>create-archive-lin</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}-lin</finalName>
<descriptors>
<descriptor>${project.basedir}/src/assembly/lin/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
<execution>
<id>create-archive-mac</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}-mac</finalName>
<descriptors>
<descriptor>${project.basedir}/src/assembly/mac/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
<ns prefix="gml" uri="http://www.opengis.net/gml"/>
<ns prefix="bldg" uri="http://www.opengis.net/citygml/building/2.0"/>
<pattern>
<rule context="//*:Building">
<assert test="count(descendant::*:lod1Solid) &gt; 0 or count(descendant::*:lod2Solid) &gt; 0 or count(descendant::*:lod3Solid) &gt; 0 or count(descendant::*:lod4Solid) &gt; 0"><value-of select="@gml:id | @id"/>||||SE_ATTRIBUTE_MISSING||any solid</assert>
</rule>
<rule context="//*:BuildingPart">
<assert test="count(*:lod1Solid) = 1 or count(*:lod2Solid) = 1 or count(*:lod3Solid) = 1 or count(*:lod4Solid) = 1"><value-of select="ancestor::*:Building/@*:id"/>||<value-of select="@gml:id | @id"/>||SE_ATTRIBUTE_MISSING||any solid</assert>
</rule>
</pattern>
</schema>
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>zip</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>app</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/lin</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>start.sh</include>
</includes>
<filtered>true</filtered>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/assembly/common</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>checkForSolid.xml</include>
</includes>
<filtered>false</filtered>
</fileSet>
<fileSet>
<directory>${project.build.directory}/jre/jre-lin/runtime/${lin-jre}/
</directory>
<outputDirectory>/runtime</outputDirectory>
<includes>
<include>**/*</include>
</includes>
<filtered>false</filtered>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
#!/bin/sh
./runtime/bin/java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
\ No newline at end of file
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>zip</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>app</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/lin</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>start.sh</include>
</includes>
<filtered>true</filtered>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/assembly/common</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>checkForSolid.xml</include>
</includes>
<filtered>false</filtered>
</fileSet>
<fileSet>
<directory>${project.build.directory}/jre/jre-mac/runtime/${mac-jre}/
</directory>
<outputDirectory>/runtime</outputDirectory>
<includes>
<include>**/*</include>
</includes>
<filtered>false</filtered>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>zip</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>app</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/no_runtime</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>start.bat</include>
<include>start.sh</include>
</includes>
<filtered>true</filtered>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/assembly/common</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>checkForSolid.xml</include>
</includes>
<filtered>false</filtered>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
java -classpath app/*;plugins/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
pause
\ No newline at end of file
#!/bin/sh
java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
\ No newline at end of file
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>zip</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>app</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/win</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>start.bat</include>
</includes>
<filtered>true</filtered>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/assembly/common</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>checkForSolid.xml</include>
</includes>
<filtered>false</filtered>
</fileSet>
<fileSet>
<directory>${project.build.directory}/jre/jre-win/runtime/${win-jre}/
</directory>
<outputDirectory>/runtime</outputDirectory>
<includes>
<include>**/*</include>
</includes>
<filtered>false</filtered>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
"runtime/bin/java.exe" -classpath app/*;plugins/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
pause
\ No newline at end of file
package de.hft.stuttgart.citydoctor2.gui;
import java.io.IOException;
import java.io.InputStream;
import de.hft.stuttgart.citydoctor2.utils.Localization;
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.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
public class AboutDialog {
@FXML
private ImageView logoView;
@FXML
private ImageView beuthView;
@FXML
private ImageView minisView;
@FXML
private ImageView hftView;
@FXML
private Button closeBtn;
@FXML
private Label cdLabel;
private Stage stage;
public AboutDialog(Window parent) throws IOException {
FXMLLoader loader = new FXMLLoader(AboutDialog.class.getResource("AboutDialog.fxml"));
loader.setController(this);
VBox box = loader.load();
stage = new Stage(StageStyle.UTILITY);
stage.setTitle(Localization.getText("AboutDialog.title"));
stage.setResizable(false);
Scene scene = new Scene(box);
stage.setScene(scene);
stage.initOwner(parent);
stage.initModality(Modality.APPLICATION_MODAL);
}
public void initialize() {
String developedBy = Localization.getText("AboutDialog.developedBy");
String contact = Localization.getText("AboutDialog.contact");
closeBtn.setText(Localization.getText("AboutDialog.closeBtn"));
cdLabel.setText("CityDoctor Version " + Localization.getText(Localization.VERSION) + "\n\n" +
developedBy + ":\n" +
"Hochschule für Technik\n" +
"Beuth Hochschule Berlin\n\n" +
contact + ":\n" +
"Matthias Betz\n" +
"matthias.betz@hft-stuttgart.de");
closeBtn.setOnAction(ae -> hide());
try {
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/CityDoctor-Logo-rot_klein.png")) {
Image img = new Image(inStream);
logoView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/hft_logo.png")) {
Image img = new Image(inStream);
hftView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/Beuth-Logo_basis.png")) {
Image img = new Image(inStream);
beuthView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/BMBF_Logo.png")) {
Image img = new Image(inStream);
minisView.setImage(img);
}
} catch (IOException e) {
// ignore close exception
}
}
public void show() {
stage.show();
}
public void hide() {
stage.hide();
}
}
package de.hft.stuttgart.citydoctor2.gui;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.DefaultParameter;
import de.hft.stuttgart.citydoctor2.check.FilterConfiguration;
import de.hft.stuttgart.citydoctor2.check.GlobalParameters;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementConfiguration;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.Unit;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.gui.tree.TreeRequirement;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.application.Platform;
import javafx.event.Event;
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.ProgressBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.CheckBoxTreeTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.util.StringConverter;
import javafx.util.converter.DefaultStringConverter;
public class CheckDialog {
private static final String NUMBER_OF_ROUNDING_PLACES = "numberOfRoundingPlaces";
private static final Logger logger = LogManager.getLogger(CheckDialog.class);
private static final String CHECK_ENABLED = Localization.getText("CheckDialog.checkEnabled");
private static final String NAME = Localization.getText("CheckDialog.checkName");
private static final String VALUE = Localization.getText("CheckDialog.parameterValue");
private static final String UNIT = Localization.getText("CheckDialog.parameterUnit");
private Stage stage;
@FXML
private TreeTableView<TreeRequirement> geometricTable;
@FXML
private TreeTableView<TreeRequirement> semanticTable;
@FXML
private TableView<GlobalParameter> globalParametersTable;
@FXML
private ScrollPane scrollPane;
@FXML
private Button cancelBtn;
@FXML
private Button checkBtn;
@FXML
private ProgressBar progress;
@FXML
private Tab filterTab;
@FXML
private TabPane tabPane;
@FXML
private Button loadBtn;
@FXML
private ImageView loadView;
@FXML
private Button saveBtn;
@FXML
private ImageView saveView;
@FXML
private Button selectBtn;
@FXML
private TextField schematronField;
@FXML
private Tab checksTab;
@FXML
private Label globalParametersLabel;
@FXML
private Label availableChecksLabel;
@FXML
private Label geometricChecksLabel;
@FXML
private Label semanticChecksLabel;
@FXML
private Label schematronFileLabel;
private CityDoctorController controller;
private FilterPane filterPane;
private MainWindow window;
public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException {
this.window = window;
this.controller = controller;
FXMLLoader loader = new FXMLLoader(CheckDialog.class.getResource("CheckDialog.fxml"));
loader.setController(this);
VBox box = loader.load();
stage = new Stage();
stage.getIcons().add(new Image(MainWindow.class.getResourceAsStream("icons/CityDoctor-Logo-rot_klein.jpg")));
Scene scene = new Scene(box);
stage.setScene(scene);
stage.initOwner(parent);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle(Localization.getText("CheckDialog.title"));
}
public void initialize() {
createEnableColumn(geometricTable);
createNameColumn(geometricTable);
createValueColumn(geometricTable);
createUnitColumn(geometricTable);
createEnableColumn(semanticTable);
createNameColumn(semanticTable);
createValueColumn(semanticTable);
createUnitColumn(semanticTable);
checksTab.setText(Localization.getText("CheckDialog.checksTab"));
filterTab.setText(Localization.getText("CheckDialog.filterTab"));
globalParametersLabel.setText(Localization.getText("CheckDialog.globalParametersLabel"));
availableChecksLabel.setText(Localization.getText("CheckDialog.availableChecksLabel"));
geometricChecksLabel.setText(Localization.getText("CheckDialog.geometricChecksLabel"));
semanticChecksLabel.setText(Localization.getText("CheckDialog.semanticChecksLabel"));
schematronFileLabel.setText(Localization.getText("CheckDialog.schematronFileLabel"));
selectBtn.setText(Localization.getText("CheckDialog.selectBtn"));
checkBtn.setText(Localization.getText("CheckDialog.checkBtn"));
cancelBtn.setText(Localization.getText("CheckDialog.cancelBtn"));
List<TableColumn<GlobalParameter, ?>> columns = globalParametersTable.getColumns();
TableColumn<GlobalParameter, String> nameCol = new TableColumn<>(NAME);
columns.add(nameCol);
nameCol.setMinWidth(200);
nameCol.setPrefWidth(325);
nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
setupValueColumns(columns);
TableColumn<GlobalParameter, Unit> unitCol = new TableColumn<>(UNIT);
columns.add(unitCol);
unitCol.setMinWidth(50);
unitCol.setPrefWidth(75);
unitCol.setMaxWidth(100);
unitCol.setEditable(false);
unitCol.setCellValueFactory(new PropertyValueFactory<>("unit"));
unitCol.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<Unit>() {
@Override
public String toString(Unit object) {
return object.getRepresentation();
}
@Override
public Unit fromString(String string) {
return Unit.valueOf(string);
}
}));
loadImages();
setupSelectButton();
setupSaveButton();
setupLoadButton();
populateTreeWithChecks(geometricTable, RequirementType.GEOMETRY, true);
populateTreeWithChecks(semanticTable, RequirementType.SEMANTIC, false);
globalParametersTable.getItems().add(new GlobalParameter(NUMBER_OF_ROUNDING_PLACES, "8", Unit.NONE));
globalParametersTable.getItems().add(new GlobalParameter("minVertexDistance", "0.0001", Unit.METER));
cancelBtn.setOnAction(ea -> stage.close());
setupCheckButton();
tabPane.getSelectionModel().selectedIndexProperty().addListener((v, old, newV) -> {
if (newV.intValue() == 1 && filterPane == null) {
try {
getFilterPane();
} catch (IOException e) {
window.showExceptionDialog(e);
}
}
});
schematronField.setText(ValidationConfiguration.CHECK_FOR_SOLID_XML);
}
private void setupValueColumns(List<TableColumn<GlobalParameter, ?>> columns) {
TableColumn<GlobalParameter, String> valueCol = new TableColumn<>(VALUE);
columns.add(valueCol);
valueCol.setMinWidth(150);
valueCol.setPrefWidth(200);
valueCol.setEditable(true);
valueCol.setCellValueFactory(new PropertyValueFactory<>("value"));
valueCol.setCellFactory(column -> new TableEditCell<GlobalParameter, String>(new DefaultStringConverter()) {
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
GlobalParameter row = (GlobalParameter) getTableRow().getItem();
if (row == null) {
return;
}
row.setValue(item);
if (NUMBER_OF_ROUNDING_PLACES.equals(row.getName())) {
setEditable(false);
}
}
}
});
}
private void setupSelectButton() {
selectBtn.setOnAction(ae -> {
FileChooser chooser = new FileChooser();
List<String> extensions = new ArrayList<>();
extensions.add("*.xml");
String schematronFiles = Localization.getText("CheckDialog.schematronFiles");
chooser.getExtensionFilters().add(new ExtensionFilter(schematronFiles, extensions));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
chooser.setInitialDirectory(dir);
}
String schematronChooserTitle = Localization.getText("CheckDialog.schematronChooserTitle");
chooser.setTitle(schematronChooserTitle);
File file = chooser.showOpenDialog(stage);
if (file != null) {
schematronField.setText(file.getAbsolutePath());
}
});
}
private void setupLoadButton() {
loadBtn.setOnAction(ae -> {
FileChooser fc = new FileChooser();
String validationConfiguration = Localization.getText("CheckDialog.validationConfiguration");
fc.getExtensionFilters().add(new ExtensionFilter(validationConfiguration, "*.yml"));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
fc.setInitialDirectory(dir);
} else {
Settings.set(Settings.LAST_OPEN_FOLDER, "");
}
File f = fc.showOpenDialog(stage);
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
ValidationConfiguration config = ValidationConfiguration.loadValidationConfig(f.getAbsolutePath());
applyConfig(config);
} catch (IOException e) {
window.showExceptionDialog(e);
}
}
});
}
private void setupSaveButton() {
saveBtn.setOnAction(ae -> {
ValidationConfiguration config = createConfig();
FileChooser fc = new FileChooser();
fc.getExtensionFilters()
.add(new ExtensionFilter(Localization.getText("CheckDialog.validationConfiguration"), "*.yml"));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
fc.setInitialDirectory(dir);
} else {
Settings.set(Settings.LAST_OPEN_FOLDER, "");
}
File f = fc.showSaveDialog(stage);
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
config.saveAs(f);
} catch (IOException e) {
window.showExceptionDialog(e);
}
}
});
}
private void applyConfig(ValidationConfiguration config) throws IOException {
FilterConfiguration filter = config.getFilter();
if (filter != null) {
getFilterPane().applyFilterConfig(filter);
}
Map<String, RequirementConfiguration> checks = config.getRequirements();
for (Entry<String, RequirementConfiguration> e : checks.entrySet()) {
for (TreeItem<TreeRequirement> ti : geometricTable.getRoot().getChildren()) {
applyCheckConfig(e, ti);
}
}
globalParametersTable.getItems().clear();
globalParametersTable.getItems().add(new GlobalParameter(GlobalParameters.NUMBER_OF_ROUNDING_PLACES,
config.getNumberOfRoundingPlacesAsString(), Unit.NONE));
globalParametersTable.getItems().add(new GlobalParameter(GlobalParameters.MIN_VERTEX_DISTANCE,
config.getMinVertexDistanceAsString(), Unit.METER));
schematronField.setText(config.getSchematronFilePath());
}
private FilterPane getFilterPane() throws IOException {
if (filterPane == null) {
filterPane = new FilterPane();
Platform.runLater(() -> filterTab.setContent(filterPane.getPane()));
}
return filterPane;
}
private void applyCheckConfig(Entry<String, RequirementConfiguration> e, TreeItem<TreeRequirement> ti) {
Requirement r = ti.getValue().getRequirement();
RequirementConfiguration cConfig = e.getValue();
if (r.getId().equals(e.getKey())) {
ti.getValue().getEnabledProperty().set(cConfig.isEnabled());
for (Entry<String, String> paramEntry : cConfig.getParameters().entrySet()) {
String name = paramEntry.getKey();
String value = paramEntry.getValue();
for (TreeItem<TreeRequirement> configItem : ti.getChildren()) {
TreeRequirement parameterCheck = configItem.getValue();
if (name.equals(parameterCheck.getNameProperty().getValue())) {
parameterCheck.setValue(value);
}
}
}
}
}
private boolean collectCheckConfiguration(ValidationConfiguration config) {
collectCheckInformationFromTree(config, geometricTable);
collectCheckInformationFromTree(config, semanticTable);
config.setSchematronFilePathInGlobalParameters(schematronField.getText());
config.setMinVertexDistanceInGlobalParameters(
Double.parseDouble(globalParametersTable.getItems().get(1).getValue()));
// check if everything is okay with the configuration
config.validateConfiguration();
return true;
}
private void collectCheckInformationFromTree(ValidationConfiguration config, TreeTableView<TreeRequirement> table) {
for (TreeItem<TreeRequirement> ti : table.getRoot().getChildren()) {
Requirement r = ti.getValue().getRequirement();
if (ti.getValue().getEnabledProperty().getValue().booleanValue()) {
RequirementConfiguration cc = config.getRequirements().get(r.getId());
cc.setEnabled(ti.getValue().isEnabled());
// collect parameters
collectParameters(cc, ti);
} else {
config.getRequirements().get(r.getId()).setEnabled(false);
}
}
}
private void loadImages() {
try {
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/openFolderIcon.png")) {
Image img = new Image(inStream);
loadView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/save.png")) {
Image img = new Image(inStream);
saveView.setImage(img);
}
} catch (IOException e) {
// ignore close exception
}
}
private void setupCheckButton() {
checkBtn.setOnAction(ea -> {
ValidationConfiguration config = createConfig();
checkBtn.setDisable(true);
cancelBtn.setDisable(true);
stage.setOnCloseRequest(Event::consume);
Thread t = new Thread(() -> {
try {
if (logger.isInfoEnabled()) {
String startingChecks = Localization.getText("CheckDialog.startingChecks");
logger.info(startingChecks);
}
controller.startChecks(config, progress::setProgress);
if (logger.isInfoEnabled()) {
String checksDone = Localization.getText("CheckDialog.checksDone");
logger.info(checksDone);
}
} catch (Exception e) {
if (logger.isErrorEnabled()) {
String failedChecks = Localization.getText("CheckDialog.failedChecks");
logger.error(failedChecks, e);
}
Platform.runLater(() -> {
ExceptionDialog dialog = new ExceptionDialog();
dialog.show(e);
});
} finally {
Platform.runLater(() -> {
checkBtn.setDisable(false);
cancelBtn.setDisable(false);
stage.setOnCloseRequest(null);
stage.close();
});
}
});
t.start();
});
}
private ValidationConfiguration createConfig() {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.setMinVertexDistanceInGlobalParameters(
Double.parseDouble(globalParametersTable.getItems().get(1).getValue()));
if (filterPane != null) {
config.setFilter(filterPane.getConfiguration());
}
collectCheckConfiguration(config);
if (schematronField.getText().isEmpty()) {
return config;
}
File f = new File(schematronField.getText());
if (!f.exists() || f.isDirectory() && logger.isWarnEnabled()) {
String schematronFileNotExisting = Localization.getText("CheckDialog.schematronFileNotExisting");
logger.warn(schematronFileNotExisting);
} else {
config.setSchematronFilePathInGlobalParameters(schematronField.getText());
}
return config;
}
private void collectParameters(RequirementConfiguration cc, TreeItem<TreeRequirement> ti) {
Map<String, String> parameters = new HashMap<>();
for (TreeItem<TreeRequirement> paramTi : ti.getChildren()) {
String name = paramTi.getValue().getNameProperty().getValue();
String value = paramTi.getValue().getValueProperty().getValue();
parameters.put(name, value);
}
cc.setParameters(parameters);
}
private void createEnableColumn(TreeTableView<TreeRequirement> view) {
TreeTableColumn<TreeRequirement, Boolean> enableColumn = new TreeTableColumn<>(CHECK_ENABLED);
view.getColumns().add(enableColumn);
enableColumn.setCellValueFactory(param -> {
TreeRequirement check = param.getValue().getValue();
if (check != null) {
return check.getEnabledProperty();
}
return null;
});
StringConverter<Boolean> converter = new StringConverter<Boolean>() {
@Override
public String toString(Boolean object) {
return " ";
}
@Override
public Boolean fromString(String string) {
return Boolean.parseBoolean(string);
}
};
enableColumn.setCellFactory(list -> new CheckBoxTreeTableCell<TreeRequirement, Boolean>(null, converter) {
@Override
public void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
setText(null);
}
}
});
}
private void createNameColumn(TreeTableView<TreeRequirement> view) {
TreeTableColumn<TreeRequirement, String> nameColumn = new TreeTableColumn<>(NAME);
nameColumn.setEditable(false);
view.getColumns().add(nameColumn);
nameColumn.setCellValueFactory(param -> {
if (param.getValue().getValue() != null) {
return param.getValue().getValue().getNameProperty();
}
return null;
});
}
private void createValueColumn(TreeTableView<TreeRequirement> view) {
TreeTableColumn<TreeRequirement, String> valueColumn = new TreeTableColumn<>(VALUE);
view.getColumns().add(valueColumn);
valueColumn.setCellValueFactory(param -> {
if (param.getValue().getValue() != null) {
return param.getValue().getValue().getValueProperty();
}
return null;
});
valueColumn.setCellFactory(col -> new TreeEditCell<>(new DefaultStringConverter()));
valueColumn.setPrefWidth(100);
}
private void createUnitColumn(TreeTableView<TreeRequirement> view) {
TreeTableColumn<TreeRequirement, String> unitColumn = new TreeTableColumn<>(UNIT);
unitColumn.setEditable(false);
view.getColumns().add(unitColumn);
unitColumn.setCellValueFactory(param -> {
if (param.getValue().getValue() != null) {
return param.getValue().getValue().getUnitProperty();
}
return null;
});
}
private void populateTreeWithChecks(TreeTableView<TreeRequirement> view, RequirementType type, boolean enabled) {
view.setRoot(new TreeItem<>());
List<Requirement> requirements = new ArrayList<>(Checks.getAvailableRequirements().values());
Collections.sort(requirements, (r1, r2) -> r1.getId().compareTo(r2.getId()));
for (Requirement r : requirements) {
if (r.getType() != type) {
continue;
}
TreeRequirement treeCheck = new TreeRequirement(r);
treeCheck.setEnabled(enabled);
TreeItem<TreeRequirement> ti = new TreeItem<>(treeCheck);
view.getRoot().getChildren().add(ti);
for (DefaultParameter dp : r.getDefaultParameter()) {
TreeItem<TreeRequirement> dpTi = new TreeItem<>(new TreeRequirement(dp));
ti.getChildren().add(dpTi);
}
ti.setExpanded(true);
}
}
public void show() {
Platform.runLater(() -> {
if (controller.getCurrentConfig() != null) {
for (GlobalParameter parameter : globalParametersTable.getItems()) {
if (parameter.getName().equals(NUMBER_OF_ROUNDING_PLACES)) {
parameter.setValue("" + controller.getCurrentConfig().getNumberOfRoundingPlaces());
}
}
}
globalParametersTable.refresh();
progress.setProgress(0d);
stage.showAndWait();
});
}
}
package de.hft.stuttgart.citydoctor2.gui;
public enum CheckStatus {
ERROR, OK, NOT_CHECKED
}
package de.hft.stuttgart.citydoctor2.gui;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
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 de.hft.stuttgart.citydoctor2.check.CheckError;
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.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeConstructiveElement;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.Installation;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.LandObject;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.ReliefObject;
import de.hft.stuttgart.citydoctor2.datastructure.TinObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.gui.table.ErrorStat;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBoundarySurfacesNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBridgeConstructiveElementsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBridgePartsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBridgesNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllInstallationsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBuildingPartsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBuildingsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllOpeningsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllTerrainNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllTinNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllTransportationNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllVegetationNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllWaterNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BoundarySurfaceNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BridgeConstructiveElementNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BridgeNode;
import de.hft.stuttgart.citydoctor2.gui.tree.InstallationNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BuildingNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BuildingPartNode;
import de.hft.stuttgart.citydoctor2.gui.tree.ButtonRenderable;
import de.hft.stuttgart.citydoctor2.gui.tree.CityObjectNode;
import de.hft.stuttgart.citydoctor2.gui.tree.GeometryNode;
import de.hft.stuttgart.citydoctor2.gui.tree.LandUseNode;
import de.hft.stuttgart.citydoctor2.gui.tree.OpeningNode;
import de.hft.stuttgart.citydoctor2.gui.tree.ReliefNode;
import de.hft.stuttgart.citydoctor2.gui.tree.Renderable;
import de.hft.stuttgart.citydoctor2.gui.tree.TinNode;
import de.hft.stuttgart.citydoctor2.gui.tree.VegetationNode;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.parser.ProgressListener;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.application.Platform;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
public class CityDoctorController {
private static final int MAX_FEATURES_PER_CHUNK = 200;
private static final Logger logger = LogManager.getLogger(CityDoctorController.class);
private MainWindow mainWindow;
private CityDoctorModel model;
private ParserConfiguration currentConfig;
private String sourceFile;
private Checker currentChecker;
private HighlightController highlightController;
private Renderer renderer;
private AtomicInteger buildingChunkNr = new AtomicInteger(0);
private AtomicInteger vegetationChunkNr = new AtomicInteger(0);
private AtomicInteger transportationChunkNr = new AtomicInteger(0);
private AtomicInteger bridgeChunkNr = new AtomicInteger(0);
private AtomicInteger waterChunkNr = new AtomicInteger(0);
private AtomicInteger landChunkNr = new AtomicInteger(0);
public CityDoctorController(MainWindow mainWindow, HighlightController highlightController, Renderer renderer) {
this.mainWindow = mainWindow;
this.highlightController = highlightController;
this.renderer = renderer;
}
public void loadCityGml(String path, int numberOfRoundingPlaces, ProgressListener l, boolean useValidation)
throws CityGmlParseException, InvalidGmlFileException {
loadCityGml(path, numberOfRoundingPlaces, l, useValidation, false);
}
public void loadCityGml(String path, int numberOfRoundingPlaces, ProgressListener l, boolean useValidation,
boolean lowMemory) throws CityGmlParseException, InvalidGmlFileException {
try {
Platform.runLater(() -> {
mainWindow.getOpenBtn().setDisable(true);
mainWindow.getWriteReportButton().setDisable(true);
mainWindow.getMeshGroup().getChildren().clear();
clearTrees();
mainWindow.resetSearchBar();
mainWindow.resetFilterComboBox();
});
currentChecker = null;
currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory);
GMLValidationHandler handler = null;
List<String> validationIssues = new ArrayList<>();
if (useValidation) {
handler = new GMLValidationHandler() {
@Override
public void error(SAXParseException exception) {
if (exception.getLineNumber() >= 0) {
String s = "In line " + exception.getLineNumber() + ":";
validationIssues.add(s);
}
validationIssues.add(exception.getMessage());
}
@Override
public void warning(SAXParseException exception) {
error(exception);
}
@Override
public void fatalError(SAXParseException exception) {
error(exception);
}
};
}
model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler);
if (!validationIssues.isEmpty()) {
StringJoiner sj = new StringJoiner("\n");
validationIssues.stream().forEach(sj::add);
throw new InvalidGmlFileException(sj.toString());
}
mainWindow.getClickHandler().setConfig(currentConfig);
sourceFile = path;
renderer.reset();
Platform.runLater(() -> {
mainWindow.addFileNameToTitle(path);
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);
buildTrees();
});
} finally {
Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false));
}
}
public void buildTrees() {
resetFeatureChunks();
buildBuildings(model);
buildVegetation(model.getVegetation());
buildTransportation(model.getTransportation());
buildBridges(model);
buildWater(model);
buildLand(model);
}
private void resetFeatureChunks() {
buildingChunkNr.set(0);
vegetationChunkNr.set(0);
transportationChunkNr.set(0);
bridgeChunkNr.set(0);
waterChunkNr.set(0);
landChunkNr.set(0);
}
private void buildLand(CityDoctorModel model) {
if (model.getLand().isEmpty()) {
return;
}
TreeView<Renderable> landView = mainWindow.getTerrainView();
TreeItem<Renderable> landRoot = new TreeItem<>(new AllTerrainNode(model.getLand()));
landRoot.setExpanded(true);
landView.setRoot(landRoot);
buildLandFromList(model.getLand(), landView.getRoot());
addMoreButtonIfNecessary(model.getLand(), landView, landRoot, landChunkNr);
}
private void buildLandFromList(List<CityObject> list, 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);
Renderable node;
if (land instanceof ReliefObject relief) {
node = new ReliefNode(relief);
} else if (land instanceof TinObject tin) {
node = new TinNode(tin);
} else {
node = new LandUseNode((LandObject) land);
}
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(land, item);
if (land instanceof ReliefObject relief) {
createTinNodes(relief, item);
}
}
}
private void createTinNodes(ReliefObject relief, TreeItem<Renderable> item) {
if (relief.getComponents().isEmpty()) {
return;
}
AllTinNode allTinText = new AllTinNode(relief.getComponents());
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allTinText);
item.getChildren().add(allBpsTextItem);
for (TinObject tin : relief.getComponents()) {
TinNode tinNode = new TinNode(tin);
TreeItem<Renderable> tinNodeItem = new TreeItem<>(tinNode);
tinNodeItem.setExpanded(true);
allBpsTextItem.getChildren().add(tinNodeItem);
createGeometryNodes(tin, tinNodeItem);
}
}
private void buildWater(CityDoctorModel model) {
if (model.getWater().isEmpty()) {
return;
}
TreeView<Renderable> waterView = mainWindow.getWaterView();
TreeItem<Renderable> waterRoot = new TreeItem<>(new AllWaterNode(model.getWater()));
waterRoot.setExpanded(true);
waterView.setRoot(waterRoot);
buildTreeFromList(model.getWater(), waterView.getRoot(), waterChunkNr);
addMoreButtonIfNecessary(model.getWater(), waterView, waterRoot, waterChunkNr);
}
private void buildBridges(CityDoctorModel model) {
if (model.getBridges().isEmpty()) {
return;
}
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> bridgeRoot = new TreeItem<>(new AllBridgesNode(model.getBridges()));
bridgeRoot.setExpanded(true);
bridgeView.setRoot(bridgeRoot);
buildBridgeTreeFromList(model.getBridges(), bridgeView.getRoot());
addMoreButtonIfNecessary(model.getBridges(), bridgeView, bridgeRoot, bridgeChunkNr);
}
private void buildTransportation(List<TransportationObject> trans) {
if (trans.isEmpty()) {
return;
}
TreeView<Renderable> transView = mainWindow.getTransportationView();
TreeItem<Renderable> transRoot = new TreeItem<>(new AllTransportationNode(model.getTransportation()));
transRoot.setExpanded(true);
transView.setRoot(transRoot);
buildTreeFromList(trans, transView.getRoot(), transportationChunkNr);
addMoreButtonIfNecessary(trans, transView, transRoot, transportationChunkNr);
}
private void buildVegetation(List<Vegetation> veg) {
if (veg.isEmpty()) {
return;
}
TreeView<Renderable> vegetationsView = mainWindow.getVegetationView();
TreeItem<Renderable> vegRoot = new TreeItem<>(new AllVegetationNode(model.getVegetation()));
vegRoot.setExpanded(true);
vegetationsView.setRoot(vegRoot);
buildTreeFromListWithProducer(veg, vegetationsView.getRoot(), vegetationChunkNr, VegetationNode::new);
addMoreButtonIfNecessary(veg, vegetationsView, vegRoot, vegetationChunkNr);
}
private void addMoreButtonIfNecessary(List<? extends CityObject> list, TreeView<Renderable> view,
TreeItem<Renderable> root, AtomicInteger chunkCounter) {
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
Runnable run = new Runnable() {
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.incrementAndGet();
int visibleFeatures = countVisibleNodes(view);
buildTreeFromList(list, root, chunkCounter);
updateTree(root);
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
}
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
root.getChildren().add(new TreeItem<>(new ButtonRenderable(this)));
}
view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1);
}
};
// add button for expansion
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void buildBuildings(CityDoctorModel model) {
if (model.getBuildings().isEmpty()) {
return;
}
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = new TreeItem<>(new AllBuildingsNode(model.getBuildings()));
root.setExpanded(true);
buildBuildingTreeFromList(model.getBuildings(), root);
addMoreButtonToBuildingsIfNecessary(model.getBuildings(), buildingsView, root, buildingChunkNr);
buildingsView.setRoot(root);
}
private void addMoreButtonToBuildingsIfNecessary(List<Building> list, TreeView<Renderable> view,
TreeItem<Renderable> root, AtomicInteger chunkCounter) {
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
Runnable run = new Runnable() {
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);
buildBuildingTreeFromList(list, root);
updateTree(root);
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
}
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
root.getChildren().add(new TreeItem<>(new ButtonRenderable(this)));
}
view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1);
}
};
// add button for expansion
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
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;
}
private void buildTreeFromList(List<? extends CityObject> cos, 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);
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,
AtomicInteger chunkCounter, Function<T, Renderable> nodeProducer) {
int chunk = chunkCounter.get();
for (int i = chunk * MAX_FEATURES_PER_CHUNK; i < (chunk + 1) * MAX_FEATURES_PER_CHUNK && i < cos.size(); i++) {
T co = cos.get(i);
Renderable node = nodeProducer.apply(co);
TreeItem<Renderable> nodeItem = new TreeItem<>(node);
nodeItem.setExpanded(true);
root.getChildren().add(nodeItem);
createGeometryNodes(co, nodeItem);
}
}
private void clearTrees() {
mainWindow.getBuildingsView().setRoot(null);
mainWindow.getVegetationView().setRoot(null);
mainWindow.getTransportationView().setRoot(null);
mainWindow.getBridgeView().setRoot(null);
mainWindow.getWaterView().setRoot(null);
mainWindow.getTerrainView().setRoot(null);
mainWindow.getErrorTree().getRoot().getChildren().clear();
mainWindow.getGlobalErrorsView().getItems().clear();
clearGeometryTrees();
}
private void clearGeometryTrees() {
highlightController.clearHighlights();
mainWindow.getPolygonsView().getRoot().getChildren().clear();
mainWindow.getEdgeView().getRoot().getChildren().clear();
mainWindow.getVertexView().getRoot().getChildren().clear();
}
private void buildBuildingTreeFromList(List<Building> list, 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);
BuildingNode node = new BuildingNode(b);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(b, item);
createBoundarySurfaceNodes(b.getBoundarySurfaces(), item);
createBuildingInstallationNodes(b, item);
createBuildingPartNodes(b, item);
}
}
private void buildBridgeTreeFromList(List<BridgeObject> list, 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);
BridgeNode node = new BridgeNode(bridge);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(bridge, item);
createBoundarySurfaceNodes(bridge.getBoundarySurfaces(), item);
createBridgeInstallationNodes(bridge, item);
createConstructiveElementsNodes(bridge, item);
createBridgePartNodes(bridge, item);
}
}
private void createBridgeInstallationNodes(BridgeObject bridge, TreeItem<Renderable> root) {
createInstallationNodes(bridge.getBridgeInstallations(), root);
}
private void createConstructiveElementsNodes(BridgeObject bridge, TreeItem<Renderable> item) {
if (bridge.getConstructiveElements().isEmpty()) {
return;
}
AllBridgeConstructiveElementsNode allBceNode = new AllBridgeConstructiveElementsNode(
bridge.getConstructiveElements());
TreeItem<Renderable> allBceNodeTextItem = new TreeItem<>(allBceNode);
item.getChildren().add(allBceNodeTextItem);
for (BridgeConstructiveElement bce : bridge.getConstructiveElements()) {
BridgeConstructiveElementNode bceNode = new BridgeConstructiveElementNode(bce);
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bceNode);
bpNodeItem.setExpanded(true);
allBceNodeTextItem.getChildren().add(bpNodeItem);
createGeometryNodes(bce, bpNodeItem);
createBoundarySurfaceNodes(bce.getBoundarySurfaces(), bpNodeItem);
}
}
private void createBridgePartNodes(BridgeObject bridge, TreeItem<Renderable> item) {
if (bridge.getParts().isEmpty()) {
return;
}
AllBridgePartsNode allBpsText = new AllBridgePartsNode(bridge.getParts());
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBpsText);
item.getChildren().add(allBpsTextItem);
for (BridgeObject bp : bridge.getParts()) {
BridgeNode bpNode = new BridgeNode(bp);
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bpNode);
bpNodeItem.setExpanded(true);
allBpsTextItem.getChildren().add(bpNodeItem);
createGeometryNodes(bp, bpNodeItem);
createBoundarySurfaceNodes(bp.getBoundarySurfaces(), bpNodeItem);
}
}
private void createBuildingInstallationNodes(Building ab, TreeItem<Renderable> root) {
createInstallationNodes(ab.getBuildingInstallations(), root);
}
private void createInstallationNodes(List<Installation> installations, TreeItem<Renderable> root) {
if (installations.isEmpty()) {
return;
}
AllInstallationsNode allBiNode = new AllInstallationsNode(installations);
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBiNode);
root.getChildren().add(allBpsTextItem);
for (Installation bi : installations) {
InstallationNode biNode = new InstallationNode(bi);
TreeItem<Renderable> biItem = new TreeItem<>(biNode);
biItem.setExpanded(true);
allBpsTextItem.getChildren().add(biItem);
createGeometryNodes(bi, biItem);
createBoundarySurfaceNodes(bi.getBoundarySurfaces(), biItem);
}
}
private void createBoundarySurfaceNodes(List<BoundarySurface> bsList, TreeItem<Renderable> root) {
if (bsList.isEmpty()) {
return;
}
AllBoundarySurfacesNode allBsText = new AllBoundarySurfacesNode(bsList);
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBsText);
root.getChildren().add(allBpsTextItem);
allBpsTextItem.getChildren().add(new TreeItem<>());
allBpsTextItem.expandedProperty().addListener((obs, old, newV) -> {
if (Boolean.TRUE.equals(newV) && allBpsTextItem.getChildren().size() == 1) {
Platform.runLater(() -> {
allBpsTextItem.getChildren().clear();
for (BoundarySurface bs : bsList) {
BoundarySurfaceNode bsText = new BoundarySurfaceNode(bs);
TreeItem<Renderable> bsTextItem = new TreeItem<>(bsText);
bsTextItem.setExpanded(true);
allBpsTextItem.getChildren().add(bsTextItem);
createGeometryNodes(bs, bsTextItem);
createOpeningNodes(bs.getOpenings(), bsTextItem);
}
updateTree(allBpsTextItem);
});
}
});
}
private void createOpeningNodes(List<Opening> openings, TreeItem<Renderable> root) {
if (openings == null || openings.isEmpty()) {
return;
}
AllOpeningsNode allOpeningsNode = new AllOpeningsNode(openings);
TreeItem<Renderable> allOpeningsItem = new TreeItem<>(allOpeningsNode);
for (Opening o : openings) {
OpeningNode openingNode = new OpeningNode(o);
TreeItem<Renderable> openingsItem = new TreeItem<>(openingNode);
allOpeningsItem.getChildren().add(openingsItem);
}
root.getChildren().add(allOpeningsItem);
}
private void createBuildingPartNodes(Building ab, TreeItem<Renderable> item) {
if (ab.getBuildingParts().isEmpty()) {
return;
}
AllBuildingPartsNode allBpsText = new AllBuildingPartsNode(ab.getBuildingParts());
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBpsText);
item.getChildren().add(allBpsTextItem);
for (BuildingPart bp : ab.getBuildingParts()) {
BuildingPartNode bpNode = new BuildingPartNode(bp);
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bpNode);
bpNodeItem.setExpanded(true);
allBpsTextItem.getChildren().add(bpNodeItem);
createGeometryNodes(bp, bpNodeItem);
createBoundarySurfaceNodes(bp.getBoundarySurfaces(), bpNodeItem);
}
}
private void createGeometryNodes(CityObject co, TreeItem<Renderable> item) {
for (Geometry geom : co.getGeometries()) {
GeometryNode geomNode = new GeometryNode(geom);
TreeItem<Renderable> geomItem = new TreeItem<>(geomNode);
item.getChildren().add(geomItem);
}
}
public void startChecks(ValidationConfiguration config, ProgressListener l) {
if (model == null) {
logger.warn(Localization.getText("CityDoctorController.noDatamodel"));
return;
}
if (sourceFile == null) {
logger.warn(Localization.getText("CityDoctorController.noSourceFile"));
return;
}
try {
Platform.runLater(() -> {
mainWindow.getCheckButton().setDisable(true);
mainWindow.getErrorTree().getRoot().getChildren().clear();
mainWindow.getGlobalErrorsView().getItems().clear();
});
config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces());
config.setParserConfig(currentConfig);
currentChecker = new Checker(config, model);
currentChecker.runChecks(l);
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());
}
}
renderer.refresh();
mainWindow.getWriteReportButton().setDisable(false);
});
} finally {
Platform.runLater(() -> mainWindow.getCheckButton().setDisable(false));
}
}
void updateFeatureTrees() {
updateTree(mainWindow.getBuildingsView().getRoot());
updateTree(mainWindow.getVegetationView().getRoot());
updateTree(mainWindow.getBridgeView().getRoot());
updateTree(mainWindow.getTerrainView().getRoot());
updateTree(mainWindow.getTransportationView().getRoot());
updateTree(mainWindow.getWaterView().getRoot());
renderer.updateErrors();
}
private void updateTree(TreeItem<Renderable> root) {
if (root == null) {
return;
}
for (TreeItem<Renderable> item : root.getChildren()) {
updateItem(item);
}
}
private void updateItem(TreeItem<Renderable> item) {
if (item.getValue() == null) {
return;
}
item.getValue().refreshTextColor();
for (TreeItem<Renderable> child : item.getChildren()) {
updateItem(child);
}
}
public void writePdfReport(File pdfFile) {
if (currentChecker == null) {
return;
}
currentChecker.writePdfReport(pdfFile.getAbsolutePath());
}
public void writeXmlReport(File xmlFile) {
if (currentChecker == null) {
return;
}
currentChecker.writeXmlReport(xmlFile.getAbsolutePath());
}
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.getTransportation());
addErrorStats(stats, model.getVegetation());
addErrorStats(stats, model.getWater());
return stats;
}
private void addErrorStats(Map<ErrorId, ErrorStat> stats, List<? extends CityObject> cos) {
List<CheckError> errors = new ArrayList<>();
for (CityObject co : cos) {
co.collectContainedErrors(errors);
}
Set<CheckError> filteredErrors = new HashSet<>(errors);
for (CheckError error : filteredErrors) {
ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new);
stat.incrementCount();
}
}
public void export(Building b) {
if (model == null) {
return;
}
CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile());
newModel.setCityModel(new CityModel());
newModel.addBuilding(b);
FileChooser fc = new FileChooser();
fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml"));
fc.getExtensionFilters().add(new ExtensionFilter("OFF - Object File Format", "*.off"));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
fc.setInitialDirectory(dir);
} else {
Settings.set(Settings.LAST_OPEN_FOLDER, "");
}
File f = fc.showSaveDialog(mainWindow.getMainStage());
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
newModel.saveAs(f.getAbsolutePath(), true);
} catch (CityDoctorWriteException e) {
logger.error(e);
}
}
}
public void showWorld() {
if (model != null) {
renderer.render(model);
}
}
public void storeModel(File f, boolean saveQualityAde) throws CityDoctorWriteException {
if (model == null) {
return;
}
model.saveAs(f.getAbsolutePath(), saveQualityAde);
}
public void searchFeature(String searchString, FeatureType selectedTab) {
if (model == null || searchString == null || searchString.trim().isEmpty()) {
return;
}
mainWindow.unselectEverything();
resetFeatureChunks();
if (selectedTab == FeatureType.BUILDING) {
List<Building> foundBuildings = filterFeatures(searchString, model.getBuildings());
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = buildingsView.getRoot();
root.getChildren().clear();
buildBuildingTreeFromList(foundBuildings, root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr);
} else {
TreeView<Renderable> view;
List<? extends CityObject> cos;
AtomicInteger chunkCounter;
switch (selectedTab) {
case VEGETATION:
view = mainWindow.getVegetationView();
cos = filterFeatures(searchString, model.getVegetation());
chunkCounter = vegetationChunkNr;
break;
case BRIDGE:
view = mainWindow.getBridgeView();
cos = filterFeatures(searchString, model.getBridges());
chunkCounter = bridgeChunkNr;
break;
case TRANSPORTATION:
view = mainWindow.getTransportationView();
cos = filterFeatures(searchString, model.getTransportation());
chunkCounter = transportationChunkNr;
break;
case WATER:
view = mainWindow.getWaterView();
cos = filterFeatures(searchString, model.getWater());
chunkCounter = waterChunkNr;
break;
case LAND:
view = mainWindow.getTerrainView();
cos = filterFeatures(searchString, model.getLand());
chunkCounter = landChunkNr;
break;
default:
throw new IllegalStateException("Unknown selected feature tab");
}
TreeItem<Renderable> root = view.getRoot();
root.getChildren().clear();
buildTreeFromList(cos, root, chunkCounter);
updateTree(root);
addMoreButtonIfNecessary(cos, view, root, chunkCounter);
}
}
private <T extends CityObject> List<T> filterFeatures(String searchString, List<T> features) {
List<T> foundFeatures = new ArrayList<>();
for (T t : features) {
if (t.getGmlId().getGmlString().contains(searchString)) {
foundFeatures.add(t);
}
}
return foundFeatures;
}
public void resetSearch(FeatureType selectedTab) {
if (model == null) {
return;
}
resetFeatureChunks();
if (selectedTab == FeatureType.BUILDING) {
// buildings are handled differently, because of surface and building
// installations
TreeItem<Renderable> root = mainWindow.getBuildingsView().getRoot();
if (root != null) {
root.getChildren().clear();
buildBuildingTreeFromList(model.getBuildings(), root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(model.getBuildings(), mainWindow.getBuildingsView(), root,
buildingChunkNr);
}
} else {
TreeView<Renderable> view;
List<? extends CityObject> cos;
AtomicInteger chunkCounter;
switch (selectedTab) {
case VEGETATION:
view = mainWindow.getVegetationView();
cos = model.getVegetation();
chunkCounter = vegetationChunkNr;
break;
case BRIDGE:
view = mainWindow.getBridgeView();
cos = model.getBridges();
chunkCounter = bridgeChunkNr;
break;
case TRANSPORTATION:
view = mainWindow.getTransportationView();
cos = model.getTransportation();
chunkCounter = transportationChunkNr;
break;
case WATER:
view = mainWindow.getWaterView();
cos = model.getWater();
chunkCounter = waterChunkNr;
break;
case LAND:
view = mainWindow.getTerrainView();
cos = model.getLand();
chunkCounter = landChunkNr;
break;
default:
throw new IllegalStateException("Unknown selected feature tab");
}
TreeItem<Renderable> root = view.getRoot();
root.getChildren().clear();
buildTreeFromList(cos, root, chunkCounter);
updateTree(root);
addMoreButtonIfNecessary(cos, view, root, chunkCounter);
}
}
public Series<String, Number> createErrorSeries() {
Series<String, Number> series = new Series<>();
if (model == null) {
return series;
}
Map<ErrorId, ErrorStat> errorStats = getErrorStats();
for (ErrorStat es : errorStats.values()) {
series.getData().add(new Data<>(es.getErrorId().toString(), es.getCount()));
}
return series;
}
public String getFileName() {
return model.getFileName();
}
public void fillTreeViewWithErrorBuildings() {
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = buildingsView.getRoot();
if (model == null) {
return;
}
if (root == null) {
return;
}
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);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(errorBuildings, buildingsView, root, buildingChunkNr);
}
public void fillTreeViewWithErrorVegetation() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getVegetationView(), model.getVegetation(), vegetationChunkNr);
}
public void fillTreeViewWithErrorBridges() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getBridgeView(), model.getBridges(), bridgeChunkNr);
}
public void fillTreeViewWithErrorLand() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTerrainView(), model.getLand(), landChunkNr);
}
public void fillTreeViewWithErrorTransportation() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTransportationView(), model.getTransportation(),
transportationChunkNr);
}
public void fillTreeViewWithErrorWater() {
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);
updateTree(root);
addMoreButtonIfNecessary(errorObjects, treeView, root, chunkCounter);
}
public void fillTreeViewFromFeatures(FeatureType selectedTab) {
if (model == null) {
return;
}
mainWindow.resetSearchBar();
switch (selectedTab) {
case BUILDING:
buildBuildings(model);
updateTree(mainWindow.getBuildingsView().getRoot());
break;
case VEGETATION:
buildVegetation(model.getVegetation());
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.getTransportation());
updateTree(mainWindow.getTransportationView().getRoot());
break;
case WATER:
buildWater(model);
updateTree(mainWindow.getWaterView().getRoot());
break;
default:
throw new IllegalStateException();
}
}
public CityDoctorModel getModel() {
return model;
}
public void showView(View v) {
v.fireOnShowEvent(model, currentChecker, mainWindow);
}
public void askAndSave() {
boolean saveWithQualityAde = true;
if (model.isValidated()) {
ButtonType yesBtn = ButtonType.YES;
ButtonType noBtn = ButtonType.NO;
Dialog<ButtonType> dialog = new Dialog<>();
dialog.setTitle("Save with QualityADE?");
dialog.setContentText("Save with QualityADE information?");
dialog.getDialogPane().getButtonTypes().add(yesBtn);
dialog.getDialogPane().getButtonTypes().add(noBtn);
Optional<ButtonType> result = dialog.showAndWait();
if (result.isPresent() && result.get() == ButtonType.NO) {
saveWithQualityAde = false;
}
}
FileChooser fc = new FileChooser();
fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml"));
fc.getExtensionFilters().add(new ExtensionFilter("OFF - Object File Format", "*.off"));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
fc.setInitialDirectory(dir);
} else {
Settings.set(Settings.LAST_OPEN_FOLDER, "");
}
File f = fc.showSaveDialog(mainWindow.getMainStage());
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
storeModel(f, saveWithQualityAde);
} catch (CityDoctorWriteException e) {
mainWindow.showExceptionDialog(e);
}
}
}
public void delete(TreeItem<Renderable> selectedItem) {
if (model == null) {
return;
}
Renderable render = selectedItem.getValue();
if (render instanceof BuildingNode node) {
model.getBuildings().remove(node.getBuilding());
mainWindow.getBuildingsView().getRoot().getChildren().remove(selectedItem);
}
}
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;
default:
throw new IllegalStateException("Unknown selected feature tab: " + mainWindow.getSelectedTab());
}
} else {
throw new IllegalStateException("Unknown filter index selected: " + newV);
}
}
public ParserConfiguration getCurrentConfig() {
return currentConfig;
}
}
/*-
* Copyright 2022 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.gui;
public class CityDoctorGUIStarter {
public static void main(String[] args) {
MainWindow.main(args);
}
}
package de.hft.stuttgart.citydoctor2.gui;
import javafx.scene.input.MouseEvent;
public interface ClickDispatcher {
public void click(MouseEvent me, ClickHandler handler);
}
package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import javafx.scene.input.MouseEvent;
public interface ClickHandler {
public void onPolygonClick(Polygon p, MouseEvent me);
public void onVertexClick(Vertex v, MouseEvent me);
}
package de.hft.stuttgart.citydoctor2.gui;
import java.io.PrintWriter;
import java.io.StringWriter;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
public class ExceptionDialog {
private Alert alert;
private TextArea textArea;
public ExceptionDialog() {
alert = new Alert(AlertType.ERROR);
alert.setTitle("Exception Dialog");
alert.getDialogPane().setPrefWidth(800);
Label label = new Label(Localization.getText("ExceptionDialog.stacktrace"));
textArea = new TextArea();
textArea.setEditable(false);
textArea.setWrapText(true);
textArea.setMaxWidth(Double.MAX_VALUE);
textArea.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(textArea, Priority.ALWAYS);
GridPane.setHgrow(textArea, Priority.ALWAYS);
GridPane expContent = new GridPane();
expContent.setMaxWidth(Double.MAX_VALUE);
expContent.add(label, 0, 0);
expContent.add(textArea, 0, 1);
// Set expandable Exception into the dialog pane.
alert.getDialogPane().setExpandableContent(expContent);
}
public void show(Throwable ex) {
// Create expandable Exception.
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
String exceptionText = sw.toString();
textArea.setText(exceptionText);
alert.setContentText(ex.getMessage());
alert.setHeaderText(ex.getClass().getSimpleName());
alert.showAndWait();
}
}
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