"...GML/git@transfer.hft-stuttgart.de:energy-ade/ade-xjc.git" did not exist on "713134ba58cde5ad32b72249283224995aede7ef"
Commit 2459496d authored by Riegel's avatar Riegel
Browse files

Merge branch 'dev_gui_features_zip_loading' into 'dev'

Add ZIP-archive support

See merge request !26
parents ca7fe768 b75c2602
Pipeline #10995 passed with stage
in 1 minute and 29 seconds
/*- /*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -18,100 +18,246 @@ ...@@ -18,100 +18,246 @@
*/ */
package de.hft.stuttgart.citydoctor2.check; package de.hft.stuttgart.citydoctor2.check;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import de.hft.stuttgart.citydoctor2.CityDoctorValidation; import de.hft.stuttgart.citydoctor2.CityDoctorValidation;
import de.hft.stuttgart.citydoctor2.checkresult.CheckReport;
import de.hft.stuttgart.citydoctor2.checkresult.GlobalErrorStatistics;
import de.hft.stuttgart.citydoctor2.checkresult.GlobalStatistics;
import de.hft.stuttgart.citydoctor2.checkresult.ModelStatistics;
import de.hft.stuttgart.citydoctor2.checkresult.utility.CheckReportParseException;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.datastructure.Building; import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException; import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/** /**
*
* @author Matthias Betz * @author Matthias Betz
*
*/ */
public class CheckerTest { public class CheckerTest {
@Rule @Rule
public TemporaryFolder folder = new TemporaryFolder(); public TemporaryFolder folder = new TemporaryFolder();
@Test @Test
public void testSchematron() throws CityGmlParseException, InvalidGmlFileException { public void testSchematron() throws CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig(); ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.getRequirements().get(Requirement.R_SE_BS_ROOF_UNFRAGMENTED.toString()).setEnabled(false); config.getRequirements().get(Requirement.R_SE_BS_ROOF_UNFRAGMENTED.toString()).setEnabled(false);
config.setSchematronFilePathInGlobalParameters("src/test/resources/schematronTest.xml"); config.setSchematronFilePathInGlobalParameters("src/test/resources/schematronTest.xml");
CityDoctorModel model = CityGmlParser.parseCityGmlFile( CityDoctorModel model = CityGmlParser.parseCityGmlFile(
"src/test/resources/SimpleSolid_SrefBS_SchematronTest.gml", config.getParserConfiguration()); "src/test/resources/SimpleSolid_SrefBS_SchematronTest.gml", config.getParserConfiguration());
Checker checker = new Checker(config, model); Checker checker = new Checker(config, model);
checker.runChecks(); checker.runChecks();
for (Building b : model.getBuildings()) { for (Building b : model.getBuildings()) {
if (b.getGmlId().getGmlString().equals("_Simple_BD.1")) { if (b.getGmlId().getGmlString().equals("_Simple_BD.1")) {
assertTrue(b.containsAnyError()); assertTrue(b.containsAnyError());
} else { } else {
assertFalse(b.containsAnyError()); assertFalse(b.containsAnyError());
} }
} }
assertFalse(model.getGlobalErrors().isEmpty()); assertFalse(model.getGlobalErrors().isEmpty());
} }
@Test @Test
public void testChecker() throws CityGmlParseException, IOException, InvalidGmlFileException, CityDoctorWriteException { public void testChecker() throws CityGmlParseException, IOException, InvalidGmlFileException, CityDoctorWriteException {
File f = folder.newFile(); File f = folder.newFile();
File f2 = folder.newFile(); File f2 = folder.newFile();
try { try {
String[] args = new String[6]; String[] args = new String[6];
args[0] = "-in"; args[0] = "-in";
args[1] = "src/test/resources/QA-CS-CONCOMP.gml"; args[1] = "src/test/resources/QA-CS-CONCOMP.gml";
args[2] = "-xmlReport"; args[2] = "-xmlReport";
args[3] = f.getAbsolutePath(); args[3] = f.getAbsolutePath();
args[4] = "-pdfReport"; args[4] = "-pdfReport";
args[5] = f2.getAbsolutePath(); args[5] = f2.getAbsolutePath();
CityDoctorValidation.main(args); CityDoctorValidation.main(args);
assertTrue(f.exists()); assertTrue(f.exists());
assertTrue(f2.exists()); assertTrue(f2.exists());
} finally { } finally {
f.delete(); f.delete();
f2.delete(); f2.delete();
} }
} }
@Test @Test
public void testStreaming() throws CityGmlParseException, IOException, InvalidGmlFileException, CityDoctorWriteException { public void testStreaming() throws CityGmlParseException, IOException, InvalidGmlFileException, CityDoctorWriteException {
File f = folder.newFile(); File f = folder.newFile();
File f2 = folder.newFile(); File f2 = folder.newFile();
File f3 = folder.newFile(); File f3 = folder.newFile();
try { try {
String[] args = new String[10]; String[] args = new String[10];
args[0] = "-in"; args[0] = "-in";
args[1] = "src/test/resources/testarea.gml"; args[1] = "src/test/resources/testarea.gml";
args[2] = "-config"; args[2] = "-config";
args[3] = "src/test/resources/testConfigWithStreaming.yml"; args[3] = "src/test/resources/testConfigWithStreaming.yml";
args[4] = "-pdfReport"; args[4] = "-pdfReport";
args[5] = f.getAbsolutePath(); args[5] = f.getAbsolutePath();
args[6] = "-xmlReport"; args[6] = "-xmlReport";
args[7] = f2.getAbsolutePath(); args[7] = f2.getAbsolutePath();
args[8] = "-out"; args[8] = "-out";
args[9] = f3.getAbsolutePath(); args[9] = f3.getAbsolutePath();
CityDoctorValidation.main(args); CityDoctorValidation.main(args);
assertTrue(f.exists()); assertTrue(f.exists());
assertTrue(f2.exists()); assertTrue(f2.exists());
assertTrue(f3.exists()); assertTrue(f3.exists());
} finally { } finally {
f.delete(); f.delete();
f2.delete(); f2.delete();
f3.delete(); f3.delete();
} }
} }
@Test
public void testCliZipChecking() throws IOException, CityDoctorWriteException, CityGmlParseException, InvalidGmlFileException {
String output = folder.getRoot().toPath() + File.separator + "test";
String pdfOutput = folder.getRoot().toPath() + File.separator + "pdf" + File.separator;
String xmlOutput = folder.getRoot().toPath() + File.separator + "xml" + File.separator;
try {
String[] args = new String[10];
args[0] = "-in";
args[1] = "src/test/resources/zipArchive.zip";
args[2] = "-config";
args[3] = "src/test/resources/testConfigWithStreaming.yml";
args[4] = "-pdfReport";
args[5] = pdfOutput;
args[6] = "-xmlReport";
args[7] = xmlOutput;
args[8] = "-out";
args[9] = output + File.separator;
CityDoctorValidation.main(args);
File zipFile = new File(output + ".zip");
File pdfDir = new File(pdfOutput);
File xmlDir = new File(xmlOutput);
assertTrue(zipFile.exists());
assertTrue(pdfDir.exists());
assertTrue(xmlDir.exists());
assertTrue(pdfDir.isDirectory());
assertTrue(xmlDir.isDirectory());
assertEquals(5, pdfDir.listFiles().length);
assertEquals(5, xmlDir.listFiles().length);
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register(output + ".zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(new ParserConfiguration(8, true));
assertEquals(5, cgmlArch.getEntries().size());
for (CityGmlZipEntry entry : cgmlArch.getEntries()) {
assertNotNull(entry);
assertNull(entry.getErrorType());
}
} catch (CityGmlParseException | IOException | InvalidGmlFileException | CityDoctorWriteException e) {
throw e;
}
}
@Test
public void testZipEntryChecking() throws CityGmlParseException, IOException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zipArchive.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(new ParserConfiguration(8, false));
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
FeatureCheckedListener l = co -> {
assertTrue(co.isValidated());
};
for (CityGmlZipEntry entry : cgmlArch.getEntries()) {
Checker.streamCheck(entry, null, null, config, l, null);
}
}
@Test
public void testZipArchiveChecking() throws CityGmlParseException, IOException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zipArchive.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(new ParserConfiguration(8, false));
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
FeatureCheckedListener l = co -> {
assertTrue(co.isValidated());
};
Checker.streamCheck(cgmlArch, null, null, config, l, null);
}
@Test
public void testReportCreation() throws IOException, CityGmlParseException, InvalidGmlFileException {
Path tmpDir = null;
try {
tmpDir = Files.createTempDirectory("testTmp");
tmpDir.toFile().deleteOnExit();
Path xmlPath = tmpDir.resolve("report.xml");
Path pdfPath = tmpDir.resolve("report.pdf");
File features = new File("src/test/resources/feature_types.gml");
CityDoctorModel model = CityGmlParser.parseCityGmlFileSilently(
features.toString(), new ParserConfiguration(8, false));
assertNotNull(model);
Checker checker = new Checker(model);
checker.runChecks();
checker.writeXmlReport(xmlPath.toString());
checker.writePdfReport(pdfPath.toString());
assertTrue(Files.exists(xmlPath));
assertTrue(Files.exists(pdfPath));
try {
CheckReport report = CheckReport.load(xmlPath.toString());
assertNotNull(report);
GlobalStatistics globalStatistics = report.getGlobalStatistics();
assertNotNull(globalStatistics);
ModelStatistics modelStats = globalStatistics.getModelStats();
assertNotNull(modelStats);
assertEquals(1, modelStats.getNumBuildings());
assertEquals(1, modelStats.getNumVegetation());
assertEquals(1, modelStats.getNumTransportation());
assertEquals(1, modelStats.getNumTunnelObjects());
assertEquals(1, modelStats.getNumBridgeObjects());
assertEquals(1, modelStats.getNumWaterObjects());
assertEquals(1, modelStats.getNumLandObjects());
assertEquals(1, modelStats.getNumCityFurniture());
assertEquals(1, modelStats.getNumGenericCityObjects());
GlobalErrorStatistics globError = globalStatistics.getGlobalErrorStats();
assertNotNull(globError);
assertEquals(0, globError.getNumErrorBuildings());
assertEquals(0, globError.getNumErrorVegetation());
assertEquals(0, globError.getNumErrorTransportation());
assertEquals(0, globError.getNumErrorTunnelObjects());
assertEquals(0, globError.getNumErrorBridgeObjects());
assertEquals(0, globError.getNumErrorWaterObjects());
assertEquals(0, globError.getNumErrorLandObjects());
assertEquals(1, globError.getNumErrorCityFurniture());
assertEquals(1, globError.getNumErrorGenericCityObjects());
} catch (CheckReportParseException e) {
fail("Report should be valid file");
}
} finally {
if (tmpDir != null) {
FileUtils.deleteDirectory(tmpDir.toFile());
}
}
}
} }
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<core:CityModel xmlns:xAL="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:wtr="http://www.opengis.net/citygml/waterbody/2.0" xmlns:app="http://www.opengis.net/citygml/appearance/2.0" xmlns:core="http://www.opengis.net/citygml/2.0" xmlns:veg="http://www.opengis.net/citygml/vegetation/2.0" xmlns:dem="http://www.opengis.net/citygml/relief/2.0" xmlns:tran="http://www.opengis.net/citygml/transportation/2.0" xmlns:bldg="http://www.opengis.net/citygml/building/2.0" xmlns:grp="http://www.opengis.net/citygml/cityobjectgroup/2.0" xmlns:tun="http://www.opengis.net/citygml/tunnel/2.0" xmlns:qual="https://transfer.hft-stuttgart.de/pages/citydoctor/qualityade/1.0.0" xmlns:frn="http://www.opengis.net/citygml/cityfurniture/2.0" xmlns:brid="http://www.opengis.net/citygml/bridge/2.0" xmlns:gen="http://www.opengis.net/citygml/generics/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:luse="http://www.opengis.net/citygml/landuse/2.0" xsi:schemaLocation="http://www.opengis.net/citygml/building/2.0 http://schemas.opengis.net/citygml/building/2.0/building.xsd http://www.opengis.net/citygml/cityobjectgroup/2.0 http://schemas.opengis.net/citygml/cityobjectgroup/2.0/cityObjectGroup.xsd http://www.opengis.net/citygml/tunnel/2.0 http://schemas.opengis.net/citygml/tunnel/2.0/tunnel.xsd http://www.opengis.net/citygml/waterbody/2.0 http://schemas.opengis.net/citygml/waterbody/2.0/waterBody.xsd http://www.opengis.net/citygml/appearance/2.0 http://schemas.opengis.net/citygml/appearance/2.0/appearance.xsd http://www.opengis.net/citygml/cityfurniture/2.0 http://schemas.opengis.net/citygml/cityfurniture/2.0/cityFurniture.xsd http://www.opengis.net/citygml/bridge/2.0 http://schemas.opengis.net/citygml/bridge/2.0/bridge.xsd http://www.opengis.net/citygml/generics/2.0 http://schemas.opengis.net/citygml/generics/2.0/generics.xsd http://www.opengis.net/citygml/vegetation/2.0 http://schemas.opengis.net/citygml/vegetation/2.0/vegetation.xsd http://www.opengis.net/citygml/relief/2.0 http://schemas.opengis.net/citygml/relief/2.0/relief.xsd http://www.opengis.net/citygml/transportation/2.0 http://schemas.opengis.net/citygml/transportation/2.0/transportation.xsd http://www.opengis.net/citygml/landuse/2.0 http://schemas.opengis.net/citygml/landuse/2.0/landUse.xsd">
<core:cityObjectMember>
<brid:Bridge gml:id="bridge">
<brid:lod1MultiSurface>
<gml:MultiSurface gml:id="CityDoctor_1737625875076_589">
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626144167_811">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626144167_810">
<gml:posList srsDimension="3">84816.978 447538.908 1.48 84816.938 447538.659 1.48 84817.016 447538.782 1.48 84816.978 447538.908 1.48</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</brid:lod1MultiSurface>
</brid:Bridge>
</core:cityObjectMember>
<core:cityObjectMember>
<wtr:WaterBody gml:id="water">
<wtr:lod1MultiSurface>
<gml:MultiSurface gml:id="CityDoctor_1737625875078_592">
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626152495_1043">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626152495_1042">
<gml:posList srsDimension="3">85012.343 447455.577 0.88 85010.804 447448.808 0.88 85013.832 447447.447 0.88 85012.343 447455.577 0.88</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</wtr:lod1MultiSurface>
</wtr:WaterBody>
</core:cityObjectMember>
<core:cityObjectMember>
<bldg:Building gml:id="building">
<bldg:lod1Solid>
<gml:Solid gml:id="CityDoctor_1737625875045_1">
<gml:exterior>
<gml:CompositeSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_761">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_760">
<gml:posList srsDimension="3">84967.573 447497.445 0.01 84967.538 447497.33 0.01 84964.343 447494.755 0.01 84962.909 447496.556 0.01 84964.913 447498.161 0.01 84964.969 447498.343 0.01 84967.602 447497.541 0.01 84967.573 447497.445 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_763">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_762">
<gml:posList srsDimension="3">84967.602 447497.541 2.36 84964.969 447498.343 2.36 84964.913 447498.161 2.36 84962.909 447496.556 2.36 84964.343 447494.755 2.36 84967.538 447497.33 2.36 84967.573 447497.445 2.36 84967.602 447497.541 2.36</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_765">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_764">
<gml:posList srsDimension="3">84967.538 447497.33 0.01 84967.573 447497.445 0.01 84967.573 447497.445 2.36 84967.538 447497.33 2.36 84967.538 447497.33 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_767">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_766">
<gml:posList srsDimension="3">84964.343 447494.755 0.01 84967.538 447497.33 0.01 84967.538 447497.33 2.36 84964.343 447494.755 2.36 84964.343 447494.755 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_769">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_768">
<gml:posList srsDimension="3">84962.909 447496.556 0.01 84964.343 447494.755 0.01 84964.343 447494.755 2.36 84962.909 447496.556 2.36 84962.909 447496.556 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_771">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_770">
<gml:posList srsDimension="3">84964.913 447498.161 0.01 84962.909 447496.556 0.01 84962.909 447496.556 2.36 84964.913 447498.161 2.36 84964.913 447498.161 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_773">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_772">
<gml:posList srsDimension="3">84964.969 447498.343 0.01 84964.913 447498.161 0.01 84964.913 447498.161 2.36 84964.969 447498.343 2.36 84964.969 447498.343 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_775">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_774">
<gml:posList srsDimension="3">84967.602 447497.541 0.01 84964.969 447498.343 0.01 84964.969 447498.343 2.36 84967.602 447497.541 2.36 84967.602 447497.541 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_777">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_776">
<gml:posList srsDimension="3">84967.573 447497.445 0.01 84967.602 447497.541 0.01 84967.602 447497.541 2.36 84967.573 447497.445 2.36 84967.573 447497.445 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:CompositeSurface>
</gml:exterior>
</gml:Solid>
</bldg:lod1Solid>
</bldg:Building>
</core:cityObjectMember>
<core:cityObjectMember>
<frn:CityFurniture gml:id="city_furniture">
<frn:lod3Geometry>
<gml:MultiSurface gml:id="CityDoctor_1737378219186_2805">
<gml:surfaceMember>
<gml:CompositeSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyIDGeo19503615">
<gml:exterior>
<gml:LinearRing gml:id="ringID19503615">
<gml:posList srsDimension="3">358506.943 5655399.912 47.06 358507.161 5655401.568 47.06 358506.943 5655403.224 47.06 358506.304 5655404.768 47.06 358505.287 5655406.093 47.06 358503.961 5655407.111 47.06 358502.418 5655407.75 47.06 358500.761 5655407.968 47.06 358499.105 5655407.75 47.06 358497.561 5655407.111 47.06 358496.236 5655406.093 47.06 358495.219 5655404.768 47.06 358494.579 5655403.224 47.06 358494.361 5655401.568 47.06 358494.579 5655399.912 47.06 358495.219 5655398.368 47.06 358496.236 5655397.043 47.06 358497.561 5655396.025 47.06 358499.105 5655395.386 47.06 358500.761 5655395.168 47.06 358502.418 5655395.386 47.06 358503.961 5655396.025 47.06 358505.287 5655397.043 47.06 358506.304 5655398.368 47.06 358506.943 5655399.912 47.06</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:CompositeSurface>
</gml:surfaceMember>
</gml:MultiSurface>
</frn:lod3Geometry>
</frn:CityFurniture>
</core:cityObjectMember>
<core:cityObjectMember>
<tran:Road gml:id="transport">
<tran:lod1MultiSurface>
<gml:MultiSurface gml:id="CityDoctor_1737625875071_446">
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626138227_779">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626138227_778">
<gml:posList srsDimension="3">85034.582 447448.556 1.27 85034.916 447449.902 1.36 85030.3 447450.585 1.18 85034.582 447448.556 1.27</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tran:lod1MultiSurface>
</tran:Road>
</core:cityObjectMember>
<core:cityObjectMember>
<veg:PlantCover gml:id="vegetation">
<veg:lod1MultiSurface>
<gml:MultiSurface gml:id="CityDoctor_1737625875066_320">
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626125400_739">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626125400_738">
<gml:posList srsDimension="3">84930.097 447481.714 0.04 84930.561 447483.073 -0.07 84929.876 447482.352 0.045 84930.097 447481.714 0.04</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</veg:lod1MultiSurface>
</veg:PlantCover>
</core:cityObjectMember>
<core:cityObjectMember>
<gen:GenericCityObject gml:id="generic_object">
<gen:lod2Geometry>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyIDGeo-5">
<gml:exterior>
<gml:LinearRing gml:id="ringID-5">
<gml:posList srsDimension="3">-0.049000 0.085000 1.162000 -0.098000 0.000000 1.162000 -0.049000 -0.085000 1.162000 0.049000 -0.085000 1.162000 0.098000 0.000000 1.162000 0.049000 0.085000 1.162000 -0.049000 0.085000 1.162000 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</gen:lod2Geometry>
</gen:GenericCityObject>
</core:cityObjectMember>
<core:cityObjectMember>
<tun:Tunnel gml:id="tunnel">
<tun:lod2Solid>
<gml:Solid>
<gml:exterior>
<gml:CompositeSurface>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.1"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.2"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.3"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.4"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.5"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.6"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.7"/>
</gml:CompositeSurface>
</gml:exterior>
</gml:Solid>
</tun:lod2Solid>
<tun:boundedBy>
<tun:WallSurface gml:id="_Simple_BD.1_WallSurface_1">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.2">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.2_LR.1">
<gml:posList srsDimension="3">
13.0 15.0 0.0
13.0 15.0 3.0
13.0 10.0 3.0
13.0 10.0 0.0
13.0 15.0 0.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:WallSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:WallSurface gml:id="_Simple_BD.1_WallSurface_2">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.3">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.3_LR.1">
<gml:posList srsDimension="3">
10.0 15.0 0.0
10.0 15.0 3.0
11.5 15.0 4.5
13.0 15.0 3.0
13.0 15.0 0.0
10.0 15.0 0.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:WallSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:WallSurface gml:id="_Simple_BD.1_WallSurface_3">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.4">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.4_LR.1">
<gml:posList srsDimension="3">
10.0 10.0 3.0
10.0 15.0 3.0
10.0 15.0 0.0
10.0 10.0 0.0
10.0 10.0 3.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:WallSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:WallSurface gml:id="_Simple_BD.1_WallSurface_4">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.5">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.5_LR.1">
<gml:posList srsDimension="3">
13.0 10.0 0.0
13.0 10.0 3.0
11.5 10.0 4.5
10.0 10.0 3.0
10.0 10.0 0.0
13.0 10.0 0.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:WallSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:RoofSurface gml:id="_Simple_BD.1_RoofSurface_1">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.6">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.6_LR.1">
<gml:posList srsDimension="3">
10.0 10.0 3.0
11.5 10.0 4.5
11.5 15.0 4.5
10.0 15.0 3.0
10.0 10.0 3.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.7">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.7_LR.1">
<gml:posList srsDimension="3">
11.5 10.0 4.5
13.0 10.0 3.0
13.0 15.0 3.0
11.5 15.0 4.5
11.5 10.0 4.5
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:RoofSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:GroundSurface gml:id="_Simple_BD.1_GroundSurface_1">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.1">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.1_LR.1">
<gml:posList srsDimension="3">
10.0 10.0 0.0
10.0 15.0 0.0
13.0 15.0 0.0
13.0 10.0 0.0
10.0 10.0 0.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:GroundSurface>
</tun:boundedBy>
</tun:Tunnel>
</core:cityObjectMember>
<core:cityObjectMember>
<luse:LandUse gml:id="terrain">
<luse:lod1MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:pos>85042.215 447482.383 0.494</gml:pos>
<gml:pos>85042.439 447481.251 0.490</gml:pos>
<gml:pos>85044.905 447482.952 0.490</gml:pos>
<gml:pos>85042.215 447482.383 0.494</gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</luse:lod1MultiSurface>
</luse:LandUse>
</core:cityObjectMember>
</core:CityModel>
\ No newline at end of file
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>de.hft.stuttgart</groupId> <groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId> <artifactId>CityDoctorParent</artifactId>
<version>3.16.0</version> <version>3.17.0</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<artifactId>CityDoctorAutoPro</artifactId> <artifactId>CityDoctorAutoPro</artifactId>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>de.hft.stuttgart</groupId> <groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId> <artifactId>CityDoctorParent</artifactId>
<version>3.16.0</version> <version>3.17.0</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<artifactId>CityDoctorGUI</artifactId> <artifactId>CityDoctorGUI</artifactId>
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
<profile> <profile>
<id>create-binaries</id> <id>create-binaries</id>
<properties> <properties>
<win-jre>jre-${jre-version-short}-full</win-jre> <win-jre>jre-${jre-version-short}</win-jre>
<lin-jre>${win-jre}</lin-jre> <lin-jre>${win-jre}</lin-jre>
<mac-jre>${win-jre}.jre</mac-jre> <mac-jre>${win-jre}.jre</mac-jre>
</properties> </properties>
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
</goals> </goals>
<configuration> <configuration>
<uri> <uri>
https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-windows-amd64-full.zip</uri> https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-windows-amd64.zip</uri>
<unpack>false</unpack> <unpack>false</unpack>
<outputDirectory> <outputDirectory>
${project.build.directory}/jre/jre-win</outputDirectory> ${project.build.directory}/jre/jre-win</outputDirectory>
...@@ -98,7 +98,7 @@ ...@@ -98,7 +98,7 @@
</goals> </goals>
<configuration> <configuration>
<uri> <uri>
https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-linux-amd64-full.tar.gz</uri> https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-linux-amd64.tar.gz</uri>
<unpack>false</unpack> <unpack>false</unpack>
<outputDirectory> <outputDirectory>
${project.build.directory}/jre/jre-lin</outputDirectory> ${project.build.directory}/jre/jre-lin</outputDirectory>
...@@ -113,7 +113,7 @@ ...@@ -113,7 +113,7 @@
</goals> </goals>
<configuration> <configuration>
<uri> <uri>
https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-macos-amd64-full.zip</uri> https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-macos-amd64.zip</uri>
<unpack>false</unpack> <unpack>false</unpack>
<outputDirectory> <outputDirectory>
${project.build.directory}/jre/jre-mac</outputDirectory> ${project.build.directory}/jre/jre-mac</outputDirectory>
......
...@@ -3,6 +3,7 @@ package de.hft.stuttgart.citydoctor2.gui; ...@@ -3,6 +3,7 @@ package de.hft.stuttgart.citydoctor2.gui;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
...@@ -10,6 +11,13 @@ import java.util.List; ...@@ -10,6 +11,13 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Alert;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Tooltip;
import javafx.stage.DirectoryChooser;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
...@@ -131,9 +139,29 @@ public class CheckDialog { ...@@ -131,9 +139,29 @@ public class CheckDialog {
@FXML @FXML
private Label schematronFileLabel; private Label schematronFileLabel;
@FXML
private VBox zipArchiveOptionsVBox;
@FXML
private CheckBox streamCheckOption;
@FXML
private Label streamCheckLabel;
@FXML
private VBox streamCheckParametersVBox;
@FXML
private Label outputPathLabel;
@FXML
private TextField outputPathTextField;
@FXML
private Button outputPathBtn;
@FXML
private CheckBox pdfReportsOption;
@FXML
private CheckBox xmlReportsOption;
private CityDoctorController controller; private CityDoctorController controller;
private FilterPane filterPane; private FilterPane filterPane;
private MainWindow window; private MainWindow window;
private boolean zipArchiveMode;
public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException { public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException {
this.window = window; this.window = window;
...@@ -153,6 +181,8 @@ public class CheckDialog { ...@@ -153,6 +181,8 @@ public class CheckDialog {
} }
public void initialize() { public void initialize() {
setupZipArchiveOptions();
createEnableColumn(geometricTable); createEnableColumn(geometricTable);
createNameColumn(geometricTable); createNameColumn(geometricTable);
createValueColumn(geometricTable); createValueColumn(geometricTable);
...@@ -256,6 +286,47 @@ public class CheckDialog { ...@@ -256,6 +286,47 @@ 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() { private void setupSelectButton() {
selectBtn.setOnAction(ae -> { selectBtn.setOnAction(ae -> {
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
...@@ -416,13 +487,33 @@ public class CheckDialog { ...@@ -416,13 +487,33 @@ public class CheckDialog {
checkBtn.setDisable(true); checkBtn.setDisable(true);
cancelBtn.setDisable(true); cancelBtn.setDisable(true);
stage.setOnCloseRequest(Event::consume); stage.setOnCloseRequest(Event::consume);
Thread t = new Thread(() -> { Thread t = new Thread(() -> {
try { try {
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
String startingChecks = Localization.getText("CheckDialog.startingChecks"); String startingChecks = Localization.getText("CheckDialog.startingChecks");
logger.info(startingChecks); logger.info(startingChecks);
} }
controller.startChecks(config, progress::setProgress); 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));
}
controller.startZipFileChecks(config, progress::setProgress, streamCheckOption.isSelected(),
outputPath, pdfReportsOption.isSelected(),
xmlReportsOption.isSelected());
} else {
controller.startChecks(config, progress::setProgress);
}
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
String checksDone = Localization.getText("CheckDialog.checksDone"); String checksDone = Localization.getText("CheckDialog.checksDone");
logger.info(checksDone); logger.info(checksDone);
...@@ -574,6 +665,7 @@ public class CheckDialog { ...@@ -574,6 +665,7 @@ public class CheckDialog {
} }
} }
public void show() { public void show() {
Platform.runLater(() -> { Platform.runLater(() -> {
if (controller.getCurrentConfig() != null) { if (controller.getCurrentConfig() != null) {
......
...@@ -11,23 +11,35 @@ import de.hft.stuttgart.citydoctor2.gui.table.ErrorStat; ...@@ -11,23 +11,35 @@ import de.hft.stuttgart.citydoctor2.gui.table.ErrorStat;
import de.hft.stuttgart.citydoctor2.gui.tree.*; import de.hft.stuttgart.citydoctor2.gui.tree.*;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler; import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.parser.*; 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.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import de.hft.stuttgart.citydoctor2.zip.MalformedZipFileException;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.scene.chart.XYChart.Data; import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series; import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog; import javafx.scene.control.Dialog;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView; import javafx.scene.control.TreeView;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter; 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.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.CityModel; import org.citygml4j.core.model.core.CityModel;
import org.xml.sax.SAXParseException; import org.xml.sax.SAXParseException;
import java.awt.*;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function; import java.util.function.Function;
...@@ -42,7 +54,9 @@ public class CityDoctorController { ...@@ -42,7 +54,9 @@ public class CityDoctorController {
private CityDoctorModel model; private CityDoctorModel model;
private ParserConfiguration currentConfig; private ParserConfiguration currentConfig;
private String sourceFile; private String sourceFile;
private CityGmlZipArchive zipArchive;
private ZipEntryManager currentZipEntryManager;
private HashMap<CityDoctorModel, Checker> previousCheckers = null;
private Checker currentChecker; private Checker currentChecker;
private HighlightController highlightController; private HighlightController highlightController;
...@@ -75,6 +89,7 @@ public class CityDoctorController { ...@@ -75,6 +89,7 @@ public class CityDoctorController {
try { try {
Platform.runLater(() -> { Platform.runLater(() -> {
mainWindow.getOpenBtn().setDisable(true); mainWindow.getOpenBtn().setDisable(true);
mainWindow.getZipManagerBtn().setDisable(true);
mainWindow.getWriteReportButton().setDisable(true); mainWindow.getWriteReportButton().setDisable(true);
mainWindow.getMeshGroup().getChildren().clear(); mainWindow.getMeshGroup().getChildren().clear();
...@@ -82,6 +97,12 @@ public class CityDoctorController { ...@@ -82,6 +97,12 @@ public class CityDoctorController {
mainWindow.resetSearchBar(); mainWindow.resetSearchBar();
mainWindow.resetFilterComboBox(); mainWindow.resetFilterComboBox();
}); });
if (path.endsWith(".zip")) {
loadCityGmlZipFile(path, numberOfRoundingPlaces, useValidation, lowMemory);
return;
}
currentZipEntryManager = null;
previousCheckers = null;
currentChecker = null; currentChecker = null;
currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory); currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory);
GMLValidationHandler handler = null; GMLValidationHandler handler = null;
...@@ -108,7 +129,7 @@ public class CityDoctorController { ...@@ -108,7 +129,7 @@ public class CityDoctorController {
} }
}; };
} }
model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler); model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler, true);
if (!validationIssues.isEmpty()) { if (!validationIssues.isEmpty()) {
StringJoiner sj = new StringJoiner("\n"); StringJoiner sj = new StringJoiner("\n");
validationIssues.stream().forEach(sj::add); validationIssues.stream().forEach(sj::add);
...@@ -128,14 +149,108 @@ public class CityDoctorController { ...@@ -128,14 +149,108 @@ public class CityDoctorController {
mainWindow.getSaveBtn().setDisable(false); mainWindow.getSaveBtn().setDisable(false);
mainWindow.getResetCameraBtn().setDisable(false); mainWindow.getResetCameraBtn().setDisable(false);
mainWindow.getHideRoofBtn().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.getNorthArrow().setVisible(true);
mainWindow.alignNorthArrow(); mainWindow.alignNorthArrow();
setupFeatureTabs(); setupFeatureTabs();
buildTrees(); buildTrees();
updateFeatureTrees();
mainWindow.getWriteReportButton().setDisable(currentChecker == null);
}); });
} finally { } finally {
Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false)); Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false));
} }
}
public void showZipManager() {
Platform.runLater(() -> currentZipEntryManager.show());
} }
private void setupFeatureTabs() { private void setupFeatureTabs() {
...@@ -155,6 +270,7 @@ public class CityDoctorController { ...@@ -155,6 +270,7 @@ public class CityDoctorController {
buildBuildings(model); buildBuildings(model);
buildVegetation(model.getVegetation()); buildVegetation(model.getVegetation());
buildTransportation(model.getTransportation()); buildTransportation(model.getTransportation());
buildTunnel(model.getTunnels());
buildBridges(model); buildBridges(model);
buildWater(model); buildWater(model);
buildLand(model); buildLand(model);
...@@ -472,18 +588,94 @@ public class CityDoctorController { ...@@ -472,18 +588,94 @@ public class CityDoctorController {
root.getChildren().add(item); root.getChildren().add(item);
createGeometryNodes(bridge, item); createGeometryNodes(bridge, item);
createBoundarySurfaceNodes(bridge.getBoundarySurfaces(), item); createBoundarySurfaceNodes(bridge.getBoundarySurfaces(), item);
createBridgeRoomNodes(bridge, item);
createBridgeInstallationNodes(bridge, item); createBridgeInstallationNodes(bridge, item);
createConstructiveElementsNodes(bridge, item); createBridgeFurnitureNodes(bridge, item);
createBridgeConstructiveElementsNodes(bridge, item);
createBridgePartNodes(bridge, item); createBridgePartNodes(bridge, item);
} }
} }
private void buildTunnelTreeFromList(List<Tunnel> list, 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);
TunnelNode node = new TunnelNode(tunnel);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(tunnel, item);
createBoundarySurfaceNodes(tunnel.getBoundarySurfaces(), item);
createTunnelHollowNodes(tunnel, item);
createTunnelInstallationNodes(tunnel, item);
createTunnelFurnitureNodes(tunnel, item);
createTunnelConstructiveElementsNodes(tunnel, item);
createTunnelPartNodes(tunnel, item);
}
}
private void createTunnelInstallationNodes(Tunnel tunnel, TreeItem<Renderable> root) {
createInstallationNodes(tunnel.getTunnelInstallations(), root);
}
private void createTunnelHollowNodes(Tunnel tunnel, TreeItem<Renderable> root) {
createRoomNodes(tunnel.getTunnelHollows(), root);
}
private void createTunnelFurnitureNodes(Tunnel tunnel, TreeItem<Renderable> root) {
createFurnitureNodes(tunnel.getTunnelFurniture(), root);
}
private void createTunnelConstructiveElementsNodes(Tunnel tunnel, TreeItem<Renderable> root){
if (tunnel.getTunnelConstructiveElements().isEmpty()){
return;
}
AllTunnelConstructiveElementsNode allTceNode = new AllTunnelConstructiveElementsNode(tunnel.getTunnelConstructiveElements());
TreeItem<Renderable> allTceNodeTextItem = new TreeItem<>(allTceNode);
root.getChildren().add(allTceNodeTextItem);
for (TunnelConstructiveElement tce : tunnel.getTunnelConstructiveElements()) {
TunnelConstructiveElementNode tceNode = new TunnelConstructiveElementNode(tce);
TreeItem<Renderable> tceNodeItem = new TreeItem<>(tceNode);
tceNodeItem.setExpanded(true);
allTceNodeTextItem.getChildren().add(tceNodeItem);
createGeometryNodes(tce, tceNodeItem);
createBoundarySurfaceNodes(tce.getBoundarySurfaces(), tceNodeItem);
}
}
private void createTunnelPartNodes(Tunnel tunnel, TreeItem<Renderable> root) {
if (tunnel.getTunnelParts().isEmpty()) {
return;
}
AllTunnelPartsNode allTpsText = new AllTunnelPartsNode(tunnel.getTunnelParts());
TreeItem<Renderable> allTpsTextItem = new TreeItem<>(allTpsText);
root.getChildren().add(allTpsTextItem);
for (TunnelPart tp : tunnel.getTunnelParts()) {
TunnelPartNode tpNode = new TunnelPartNode(tp);
TreeItem<Renderable> tpNodeItem = new TreeItem<>(tpNode);
tpNodeItem.setExpanded(true);
allTpsTextItem.getChildren().add(tpNodeItem);
createGeometryNodes(tp, tpNodeItem);
createBoundarySurfaceNodes(tp.getBoundarySurfaces(), tpNodeItem);
}
}
private void createBridgeRoomNodes(BridgeObject bridge, TreeItem<Renderable> root) {
createRoomNodes(bridge.getBridgeRooms(), root);
}
private void createBridgeInstallationNodes(BridgeObject bridge, TreeItem<Renderable> root) { private void createBridgeInstallationNodes(BridgeObject bridge, TreeItem<Renderable> root) {
createInstallationNodes(bridge.getBridgeInstallations(), root); createInstallationNodes(bridge.getBridgeInstallations(), root);
} }
private void createConstructiveElementsNodes(BridgeObject bridge, TreeItem<Renderable> item) { private void createBridgeFurnitureNodes(BridgeObject bridge, TreeItem<Renderable> root) {
createFurnitureNodes(bridge.getBridgeFurniture(), root);
}
private void createBridgeConstructiveElementsNodes(BridgeObject bridge, TreeItem<Renderable> item) {
if (bridge.getConstructiveElements().isEmpty()) { if (bridge.getConstructiveElements().isEmpty()) {
return; return;
} }
...@@ -494,11 +686,11 @@ public class CityDoctorController { ...@@ -494,11 +686,11 @@ public class CityDoctorController {
for (BridgeConstructiveElement bce : bridge.getConstructiveElements()) { for (BridgeConstructiveElement bce : bridge.getConstructiveElements()) {
BridgeConstructiveElementNode bceNode = new BridgeConstructiveElementNode(bce); BridgeConstructiveElementNode bceNode = new BridgeConstructiveElementNode(bce);
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bceNode); TreeItem<Renderable> bceNodeItem = new TreeItem<>(bceNode);
bpNodeItem.setExpanded(true); bceNodeItem.setExpanded(true);
allBceNodeTextItem.getChildren().add(bpNodeItem); allBceNodeTextItem.getChildren().add(bceNodeItem);
createGeometryNodes(bce, bpNodeItem); createGeometryNodes(bce, bceNodeItem);
createBoundarySurfaceNodes(bce.getBoundarySurfaces(), bpNodeItem); createBoundarySurfaceNodes(bce.getBoundarySurfaces(), bceNodeItem);
} }
} }
...@@ -710,6 +902,9 @@ public class CityDoctorController { ...@@ -710,6 +902,9 @@ public class CityDoctorController {
config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces()); config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces());
config.setParserConfig(currentConfig); config.setParserConfig(currentConfig);
currentChecker = new Checker(config, model); currentChecker = new Checker(config, model);
if (previousCheckers != null) {
previousCheckers.put(model, currentChecker);
}
currentChecker.runChecks(l); currentChecker.runChecks(l);
Platform.runLater(() -> { Platform.runLater(() -> {
...@@ -729,6 +924,136 @@ public class CityDoctorController { ...@@ -729,6 +924,136 @@ public class CityDoctorController {
} }
} }
public void startZipFileChecks(ValidationConfiguration config, ProgressListener l, boolean lowMemoryMode,
Path outputPath, boolean pdfReports, boolean xmlReports) {
if (zipArchive == null) {
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());
}
}
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);
}
}
}
void updateFeatureTrees() { void updateFeatureTrees() {
updateTree(mainWindow.getBuildingsView().getRoot()); updateTree(mainWindow.getBuildingsView().getRoot());
updateTree(mainWindow.getVegetationView().getRoot()); updateTree(mainWindow.getVegetationView().getRoot());
...@@ -738,6 +1063,7 @@ public class CityDoctorController { ...@@ -738,6 +1063,7 @@ public class CityDoctorController {
updateTree(mainWindow.getTransportationView().getRoot()); updateTree(mainWindow.getTransportationView().getRoot());
updateTree(mainWindow.getWaterView().getRoot()); updateTree(mainWindow.getWaterView().getRoot());
updateTree(mainWindow.getOtherObjectsView().getRoot()); updateTree(mainWindow.getOtherObjectsView().getRoot());
updateTree(mainWindow.getTunnelView().getRoot());
renderer.updateErrors(); renderer.updateErrors();
} }
...@@ -799,13 +1125,15 @@ public class CityDoctorController { ...@@ -799,13 +1125,15 @@ public class CityDoctorController {
} }
} }
public void export(Building b) { public void export(CityObject co) {
if (model == null) { if (model == null) {
return; return;
} }
CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile()); CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile());
newModel.setCityModel(new CityModel()); newModel.setCityModel(new CityModel());
newModel.addBuilding(b); newModel.addCityObject(co);
newModel.setParsedCityGMLVersion(model.getCityGMLVersion());
newModel.getCityModel().setBoundedBy(model.getCityModel().getBoundedBy());
FileChooser fc = new FileChooser(); FileChooser fc = new FileChooser();
fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml")); fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml"));
...@@ -820,7 +1148,6 @@ public class CityDoctorController { ...@@ -820,7 +1148,6 @@ public class CityDoctorController {
if (f != null) { if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent()); Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try { try {
newModel.saveAs(f.getAbsolutePath(), true); newModel.saveAs(f.getAbsolutePath(), true);
} catch (CityDoctorWriteException e) { } catch (CityDoctorWriteException e) {
logger.error(e); logger.error(e);
...@@ -831,6 +1158,7 @@ public class CityDoctorController { ...@@ -831,6 +1158,7 @@ public class CityDoctorController {
public void showWorld() { public void showWorld() {
if (model != null) { if (model != null) {
renderer.render(model); renderer.render(model);
resetSearch(mainWindow.getSelectedTab());
} }
} }
...@@ -855,7 +1183,24 @@ public class CityDoctorController { ...@@ -855,7 +1183,24 @@ public class CityDoctorController {
buildBuildingTreeFromList(foundBuildings, root); buildBuildingTreeFromList(foundBuildings, root);
updateTree(root); updateTree(root);
addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr); addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr);
} else { } else if (selectedTab == FeatureType.BRIDGE){
List<BridgeObject> foundBridges = filterFeatures(searchString, model.getBridges());
TreeView<Renderable> brigdeView = mainWindow.getBridgeView();
TreeItem<Renderable> root = brigdeView.getRoot();
root.getChildren().clear();
buildBridgeTreeFromList(foundBridges, root);
updateTree(root);
addMoreButtonIfNecessary(foundBridges, brigdeView, root, bridgeChunkNr);
} else if (selectedTab == FeatureType.TUNNEL){
List<Tunnel> foundTunnel = filterFeatures(searchString, model.getTunnels());
TreeView<Renderable> tunnelView = mainWindow.getTunnelView();
TreeItem<Renderable> root = tunnelView.getRoot();
root.getChildren().clear();
buildTunnelTreeFromList(foundTunnel, root);
updateTree(root);
addMoreButtonIfNecessary(foundTunnel, tunnelView, root, bridgeChunkNr);
}
else{
TreeView<Renderable> view; TreeView<Renderable> view;
List<? extends CityObject> cos; List<? extends CityObject> cos;
AtomicInteger chunkCounter; AtomicInteger chunkCounter;
...@@ -1136,6 +1481,9 @@ public class CityDoctorController { ...@@ -1136,6 +1481,9 @@ public class CityDoctorController {
buildTransportation(model.getTransportation()); buildTransportation(model.getTransportation());
updateTree(mainWindow.getTransportationView().getRoot()); updateTree(mainWindow.getTransportationView().getRoot());
break; break;
case TUNNEL:
buildTunnel(model.getTunnels());
updateTree(mainWindow.getTunnelView().getRoot());
case WATER: case WATER:
buildWater(model); buildWater(model);
updateTree(mainWindow.getWaterView().getRoot()); updateTree(mainWindow.getWaterView().getRoot());
......
...@@ -85,6 +85,12 @@ public class MainToolBar { ...@@ -85,6 +85,12 @@ public class MainToolBar {
@FXML @FXML
private ImageView lod4View; private ImageView lod4View;
@FXML
private Button zipManagerBtn;
@FXML
private ImageView zipManagerView;
@FXML @FXML
private Button aboutBtn; private Button aboutBtn;
...@@ -147,6 +153,7 @@ public class MainToolBar { ...@@ -147,6 +153,7 @@ public class MainToolBar {
setupReportButton(); setupReportButton();
setupResetCameraButton(); setupResetCameraButton();
setupHideRoofButton(); setupHideRoofButton();
setupZipManagerButton();
loadImages(); loadImages();
gridButton.setOnAction(ae -> renderer.showWireFrame(gridButton.isSelected())); gridButton.setOnAction(ae -> renderer.showWireFrame(gridButton.isSelected()));
...@@ -162,6 +169,7 @@ public class MainToolBar { ...@@ -162,6 +169,7 @@ public class MainToolBar {
content.getSelectionModel().clearSelection(); content.getSelectionModel().clearSelection();
} }
controller.showWorld(); controller.showWorld();
mainWindow.resetSearchBar();
}); });
showWorldBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.showWorld"))); showWorldBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.showWorld")));
} }
...@@ -224,6 +232,10 @@ public class MainToolBar { ...@@ -224,6 +232,10 @@ public class MainToolBar {
Image img = new Image(inStream); Image img = new Image(inStream);
hideRoofView.setImage(img); hideRoofView.setImage(img);
} }
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/zip.png")) {
Image img = new Image(inStream);
zipManagerView.setImage(img);
}
} catch (IOException e) { } catch (IOException e) {
// ignore close exception // ignore close exception
} }
...@@ -335,6 +347,14 @@ public class MainToolBar { ...@@ -335,6 +347,14 @@ 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() { public Button getCheckButton() {
return checkBtn; return checkBtn;
} }
...@@ -387,6 +407,10 @@ public class MainToolBar { ...@@ -387,6 +407,10 @@ public class MainToolBar {
return resetCameraBtn; return resetCameraBtn;
} }
public Button getZipManagerBtn() {
return zipManagerBtn;
}
public HBox getToolBar() { public HBox getToolBar() {
return toolBar; return toolBar;
} }
......
...@@ -3,9 +3,10 @@ package de.hft.stuttgart.citydoctor2.gui; ...@@ -3,9 +3,10 @@ package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.CityDoctorValidation; import de.hft.stuttgart.citydoctor2.CityDoctorValidation;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox; import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType; import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.gui.logger.GuiLogger; import de.hft.stuttgart.citydoctor2.gui.logger.GuiLogger;
import de.hft.stuttgart.citydoctor2.gui.tree.BuildingNode; import de.hft.stuttgart.citydoctor2.gui.tree.FeatureNode;
import de.hft.stuttgart.citydoctor2.gui.tree.Renderable; import de.hft.stuttgart.citydoctor2.gui.tree.Renderable;
import de.hft.stuttgart.citydoctor2.gui.tree.RenderableTreeCell; import de.hft.stuttgart.citydoctor2.gui.tree.RenderableTreeCell;
import de.hft.stuttgart.citydoctor2.parameter.ArgumentParser; import de.hft.stuttgart.citydoctor2.parameter.ArgumentParser;
...@@ -13,22 +14,22 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; ...@@ -13,22 +14,22 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ProgressListener; import de.hft.stuttgart.citydoctor2.parser.ProgressListener;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.utils.Pair;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.embed.swing.SwingFXUtils; import javafx.embed.swing.SwingFXUtils;
import javafx.event.Event;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.*; import javafx.scene.*;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.skin.VirtualFlow;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage; import javafx.scene.image.WritableImage;
import javafx.scene.input.Dragboard; import javafx.scene.input.*;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
...@@ -46,6 +47,8 @@ import java.io.FileNotFoundException; ...@@ -46,6 +47,8 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import static javafx.scene.input.Clipboard.getSystemClipboard;
public class MainWindow extends Application { public class MainWindow extends Application {
private static final Logger logger = LogManager.getLogger(MainWindow.class); private static final Logger logger = LogManager.getLogger(MainWindow.class);
...@@ -301,7 +304,7 @@ public class MainWindow extends Application { ...@@ -301,7 +304,7 @@ public class MainWindow extends Application {
BorderPane bp = loader.load(); BorderPane bp = loader.load();
highlightController = new HighlightController(world); highlightController = new HighlightController(world);
renderer = new Renderer(this, highlightController); renderer = new Renderer(this, highlightController);
clickHandler = new VertexClickHandler(errorView, renderer, stage); clickHandler = new VertexClickHandler(errorView, renderer, stage, this);
controller = new CityDoctorController(this, highlightController, renderer); controller = new CityDoctorController(this, highlightController, renderer);
mainToolBar = new MainToolBar(stage, controller, featurePane, renderer, this); mainToolBar = new MainToolBar(stage, controller, featurePane, renderer, this);
viewPane.getChildren().add(mainToolBar.getToolBar()); viewPane.getChildren().add(mainToolBar.getToolBar());
...@@ -727,77 +730,105 @@ public class MainWindow extends Application { ...@@ -727,77 +730,105 @@ public class MainWindow extends Application {
} }
private void setupTrees() { private void setupTrees() {
setupTreeRoot(errorView);
setupSelectListener(errorView); setupSelectListener(errorView);
errorView.setRoot(new TreeItem<>());
errorView.setCellFactory(param -> new RenderableTreeCell());
buildingsView.setShowRoot(true); setupTreeRoot(buildingsView);
setupSelectListener(buildingsView); setupSelectListener(buildingsView);
buildingsView.setCellFactory(param -> new RenderableTreeCell()); setupFeatureTabContextMenu(buildingsView);
ContextMenu cMenu = new ContextMenu();
MenuItem mi = new MenuItem(Localization.getText("MainWindow.export"));
mi.setOnAction(ea -> {
Renderable render = buildingsView.getSelectionModel().getSelectedItem().getValue();
if (render instanceof BuildingNode node) {
controller.export(node.getBuilding());
}
});
cMenu.getItems().add(mi);
MenuItem deleteMi = new MenuItem("Delete");
deleteMi.setOnAction(ae -> controller.delete(buildingsView.getSelectionModel().getSelectedItem()));
cMenu.getItems().add(deleteMi);
buildingsView.setContextMenu(cMenu); setupTreeRoot(vegetationView);
vegetationView.setShowRoot(true);
setupSelectListener(vegetationView); setupSelectListener(vegetationView);
vegetationView.setCellFactory(param -> new RenderableTreeCell()); setupFeatureTabContextMenu(vegetationView);
vegetationView.setContextMenu(cMenu);
transView.setShowRoot(true); setupTreeRoot(transView);
setupSelectListener(transView); setupSelectListener(transView);
transView.setCellFactory(param -> new RenderableTreeCell()); setupFeatureTabContextMenu(transView);
tunnelView.setShowRoot(true); setupTreeRoot(tunnelView);
setupSelectListener(tunnelView); setupSelectListener(tunnelView);
tunnelView.setCellFactory(param -> new RenderableTreeCell()); setupFeatureTabContextMenu(tunnelView);
bridgeView.setShowRoot(true); setupTreeRoot(bridgeView);
setupSelectListener(bridgeView); setupSelectListener(bridgeView);
bridgeView.setCellFactory(param -> new RenderableTreeCell()); setupFeatureTabContextMenu(bridgeView);
waterView.setShowRoot(true); setupTreeRoot(waterView);
setupSelectListener(waterView); setupSelectListener(waterView);
waterView.setCellFactory(param -> new RenderableTreeCell()); setupFeatureTabContextMenu(waterView);
terrainView.setShowRoot(true); setupTreeRoot(terrainView);
setupSelectListener(terrainView); setupSelectListener(terrainView);
terrainView.setCellFactory(param -> new RenderableTreeCell()); setupFeatureTabContextMenu(terrainView);
cityFurnitureView.setShowRoot(true); setupTreeRoot(cityFurnitureView);
setupSelectListener(cityFurnitureView); setupSelectListener(cityFurnitureView);
cityFurnitureView.setCellFactory(param -> new RenderableTreeCell()); setupFeatureTabContextMenu(cityFurnitureView);
otherObjectsView.setShowRoot(true); setupTreeRoot(otherObjectsView);
setupSelectListener(otherObjectsView); setupSelectListener(otherObjectsView);
otherObjectsView.setCellFactory(param -> new RenderableTreeCell()); setupFeatureTabContextMenu(otherObjectsView);
setupTreeRoot(vertexView);
setupSelectListener(vertexView); setupSelectListener(vertexView);
vertexView.setRoot(new TreeItem<>());
vertexView.setCellFactory(param -> new RenderableTreeCell());
setupTreeRoot(polygonView);
setupSelectListener(polygonView); setupSelectListener(polygonView);
polygonView.setRoot(new TreeItem<>());
polygonView.setCellFactory(param -> new RenderableTreeCell());
setupTreeRoot(edgeView);
setupSelectListener(edgeView); setupSelectListener(edgeView);
edgeView.setRoot(new TreeItem<>());
edgeView.setCellFactory(param -> new RenderableTreeCell());
setupTreeRoot(attributeView);
setupSelectListener(attributeView); setupSelectListener(attributeView);
attributeView.setRoot(new TreeItem<>()); }
attributeView.setCellFactory(param -> new RenderableTreeCell());
private void setupTreeRoot(TreeView<Renderable> tView){
tView.setRoot(new TreeItem<>());
tView.setCellFactory(param -> new RenderableTreeCell());
}
private void setupFeatureTabContextMenu(TreeView<Renderable> featureView) {
ContextMenu menu = new ContextMenu();
MenuItem mi = new MenuItem(Localization.getText("MainWindow.export"));
mi.setOnAction(ea -> {
Renderable render = featureView.getSelectionModel().getSelectedItem().getValue();
if (render instanceof FeatureNode node) {
try {
controller.export(node.getFeature());
logger.info(Localization.getText("CityDoctorController.exportSuccess"));
} catch (Exception e) {
logger.error("Export failed: Unexpected error occurred");
logger.error(e);
}
} else {
logger.info(Localization.getText("MainWindow.infoTopLevelExport"));
}
});
menu.getItems().add(mi);
MenuItem clipMi = new MenuItem(Localization.getText("MainWindow.copyId"));
clipMi.setOnAction(ea -> {
Renderable render = featureView.getSelectionModel().getSelectedItem().getValue();
if (render instanceof FeatureNode node) {
Clipboard clipboard = getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(node.getFeature().getGmlId().toString());
if (!clipboard.setContent(content)) {
logger.warn(Localization.getText("MainWindow.warnCopyIdFailed"));
}
} else {
logger.info(Localization.getText("MainWindow.infoTopLevelCopyID"));
}
});
menu.getItems().add(clipMi);
MenuItem deleteMi = new MenuItem(Localization.getText("MainWindow.delete"));
deleteMi.setOnAction(ae -> controller.delete(featureView.getSelectionModel().getSelectedItem()));
menu.getItems().add(deleteMi);
featureView.setContextMenu(menu);
} }
private void setupSelectListener(TreeView<Renderable> view) { private void setupSelectListener(TreeView<Renderable> view) {
...@@ -1118,6 +1149,43 @@ public class MainWindow extends Application { ...@@ -1118,6 +1149,43 @@ public class MainWindow extends Application {
controller.setOriginBB(b); controller.setOriginBB(b);
} }
public void showCityObjectDetail(CityObject co) {
Pair<Tab, TreeView<Renderable>> tabPair = getFeatureTabOf(co);
Tab featureTab = tabPair.getValue0();
TreeView<Renderable> featureView = tabPair.getValue1();
featurePane.getSelectionModel().select(featureTab);
searchField.setText(co.getGmlId().getGmlString());
searchBtn.fire();
featureView.getSelectionModel().select(0);
featureView.getSelectionModel().getSelectedItem().getValue().visit(renderer);
}
private Pair<Tab,TreeView<Renderable>> getFeatureTabOf(CityObject co) {
FeatureType coType = co.getFeatureType();
if (coType == FeatureType.BUILDING){
return new Pair<>(buildingsTab, buildingsView);
} else if (coType == FeatureType.VEGETATION){
return new Pair<>(vegetationTab, vegetationView);
} else if (coType == FeatureType.TRANSPORTATION){
return new Pair<>(transportationTab,transView);
} else if (coType == FeatureType.TUNNEL){
return new Pair<>(tunnelTab, tunnelView);
} else if (coType == FeatureType.BRIDGE){
return new Pair<>(bridgeTab, bridgeView);
} else if (coType == FeatureType.WATER){
return new Pair<>(waterTab, waterView);
} else if (coType == FeatureType.LAND){
return new Pair<>(terrainTab, terrainView);
} else if (coType == FeatureType.CITY_FURNITURE){
return new Pair<>(cityFurnitureTab, cityFurnitureView);
} else if (coType == FeatureType.GENERIC_CITY_OBJECT){
return new Pair<>(otherObjectsTab, otherObjectsView);
} else {
throw new IllegalArgumentException("unknown feature type: " + coType);
}
}
public MainToolBar getMainToolbar() { public MainToolBar getMainToolbar() {
return mainToolBar; return mainToolBar;
} }
...@@ -1134,6 +1202,14 @@ public class MainWindow extends Application { ...@@ -1134,6 +1202,14 @@ public class MainWindow extends Application {
return mainToolBar.getOpenBtn(); return mainToolBar.getOpenBtn();
} }
public void showZipManager() {
controller.showZipManager();
}
public Button getZipManagerBtn() {
return mainToolBar.getZipManagerBtn();
}
public VertexClickHandler getClickHandler() { public VertexClickHandler getClickHandler() {
return clickHandler; return clickHandler;
} }
......
...@@ -120,7 +120,7 @@ public class OpenFileDialog { ...@@ -120,7 +120,7 @@ public class OpenFileDialog {
if (fc == null) { if (fc == null) {
fc = new FileChooser(); fc = new FileChooser();
fc.setTitle(Localization.getText("OpenFileDialog.select")); fc.setTitle(Localization.getText("OpenFileDialog.select"));
fc.getExtensionFilters().add(new ExtensionFilter("GML/XML", "*.gml", "*.xml")); fc.getExtensionFilters().add(new ExtensionFilter("GML/XML/ZIP", "*.gml", "*.xml", "*.zip"));
fc.getExtensionFilters().add(new ExtensionFilter(Localization.getText("MainWindow.all"), "*.*")); fc.getExtensionFilters().add(new ExtensionFilter(Localization.getText("MainWindow.all"), "*.*"));
} }
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, "")); File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
...@@ -150,8 +150,12 @@ public class OpenFileDialog { ...@@ -150,8 +150,12 @@ public class OpenFileDialog {
pathField.setDisable(true); pathField.setDisable(true);
selectBtn.setDisable(true); selectBtn.setDisable(true);
stage.setOnCloseRequest(Event::consume); stage.setOnCloseRequest(Event::consume);
Thread t = new Thread(() -> { Thread t = new Thread(() -> {
try { try {
if (path.endsWith(".zip")) {
Platform.runLater(() -> progress.setProgress(-1));
}
controller.loadCityGml(path, numberOfRoundingPlaces, progress::setProgress, useValidation, controller.loadCityGml(path, numberOfRoundingPlaces, progress::setProgress, useValidation,
lowMemory); lowMemory);
Platform.runLater(() -> stage.close()); Platform.runLater(() -> stage.close());
......
...@@ -401,7 +401,7 @@ public class Renderer { ...@@ -401,7 +401,7 @@ public class Renderer {
addPolygons(bs, polygons); addPolygons(bs, polygons);
} }
} }
for (TunnelFurniture tf : tunnel.getTunnelFurnitureList()) { for (TunnelFurniture tf : tunnel.getTunnelFurniture()) {
addPolygons(tf, polygons); addPolygons(tf, polygons);
for (BoundarySurface bs : tf.getBoundarySurfaceList()) { for (BoundarySurface bs : tf.getBoundarySurfaceList()) {
addPolygons(bs, polygons); addPolygons(bs, polygons);
...@@ -1206,5 +1206,4 @@ public class Renderer { ...@@ -1206,5 +1206,4 @@ public class Renderer {
errorUpdater = null; errorUpdater = null;
refresher = null; refresher = null;
} }
} }
package de.hft.stuttgart.citydoctor2.gui; package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.datastructure.*;
import de.hft.stuttgart.citydoctor2.gui.tree.FeatureNode;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import org.locationtech.proj4j.ProjCoordinate; import org.locationtech.proj4j.ProjCoordinate;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.gui.tree.Renderable; import de.hft.stuttgart.citydoctor2.gui.tree.Renderable;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import javafx.scene.control.ContextMenu; import javafx.scene.control.ContextMenu;
...@@ -15,17 +18,21 @@ import javafx.scene.input.MouseButton; ...@@ -15,17 +18,21 @@ import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import javafx.stage.Stage; import javafx.stage.Stage;
import static javafx.scene.input.Clipboard.getSystemClipboard;
public class VertexClickHandler implements ClickHandler { public class VertexClickHandler implements ClickHandler {
private TreeView<Renderable> errorView; private TreeView<Renderable> errorView;
private Renderer renderer; private Renderer renderer;
private Stage stage; private Stage stage;
private MainWindow mainWindow;
private ParserConfiguration config; private ParserConfiguration config;
public VertexClickHandler(TreeView<Renderable> errorView, Renderer renderer, Stage stage) { public VertexClickHandler(TreeView<Renderable> errorView, Renderer renderer, Stage stage, MainWindow mainWindow) {
this.errorView = errorView; this.errorView = errorView;
this.renderer = renderer; this.renderer = renderer;
this.stage = stage; this.stage = stage;
this.mainWindow = mainWindow;
} }
public void setConfig(ParserConfiguration config) { public void setConfig(ParserConfiguration config) {
...@@ -38,8 +45,26 @@ public class VertexClickHandler implements ClickHandler { ...@@ -38,8 +45,26 @@ public class VertexClickHandler implements ClickHandler {
errorView.getSelectionModel().clearSelection(); errorView.getSelectionModel().clearSelection();
renderer.highlight(p); renderer.highlight(p);
} else if (me.getButton() == MouseButton.SECONDARY) { } else if (me.getButton() == MouseButton.SECONDARY) {
MenuItem mi = new MenuItem(p.getGmlId().getGmlString()); ContextMenu cMenu = new ContextMenu();
ContextMenu cMenu = new ContextMenu(mi);
MenuItem clipMi = new MenuItem(Localization.getText("MainWindow.copyId"));
clipMi.setOnAction(ea -> {
CityObject topLevelCityObject = p.getParent().getParent().getTopLevelCityObject();
Clipboard clipboard = getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(topLevelCityObject.getGmlId().toString());
clipboard.setContent(content);
});
cMenu.getItems().add(clipMi);
MenuItem detailMi = new MenuItem(Localization.getText("MainWindow.focusCityObject"));
detailMi.setOnAction(ea -> {
CityObject topLevelCityObject = p.getParent().getParent().getTopLevelCityObject();
mainWindow.showCityObjectDetail(topLevelCityObject);
});
cMenu.getItems().add(detailMi);
cMenu.show(stage, me.getScreenX(), me.getScreenY()); cMenu.show(stage, me.getScreenX(), me.getScreenY());
} }
} }
......
package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.gui.tree.ZipEntryListCell;
import de.hft.stuttgart.citydoctor2.gui.tree.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.TunnelConstructiveElement;
import de.hft.stuttgart.citydoctor2.gui.CheckStatus;
import de.hft.stuttgart.citydoctor2.gui.Renderer;
import java.util.List;
public class AllTunnelConstructiveElementsNode extends Renderable{
private final List<TunnelConstructiveElement> constructiveElements;
public AllTunnelConstructiveElementsNode(List<TunnelConstructiveElement> constructiveElements) {
this.constructiveElements = constructiveElements;
}
@Override
public String getText() {
return "Constructive Elements";
}
@Override
public void visit(Renderer renderer) {
renderer.clearCurrentRender();
}
@Override
public void refreshTextColor() {
boolean isValidated = false;
for (TunnelConstructiveElement bce : constructiveElements) {
if (bce.isValidated()) {
isValidated = true;
}
if (bce.containsAnyError()) {
setStatus(CheckStatus.ERROR);
return;
}
}
if (isValidated) {
setStatus(CheckStatus.OK);
} else {
setStatus(CheckStatus.NOT_CHECKED);
}
}
}
...@@ -19,10 +19,11 @@ ...@@ -19,10 +19,11 @@
package de.hft.stuttgart.citydoctor2.gui.tree; package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject; import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.gui.CheckStatus; import de.hft.stuttgart.citydoctor2.gui.CheckStatus;
import de.hft.stuttgart.citydoctor2.gui.Renderer; import de.hft.stuttgart.citydoctor2.gui.Renderer;
public class BridgeNode extends Renderable { public class BridgeNode extends Renderable implements FeatureNode {
private final BridgeObject bridge; private final BridgeObject bridge;
...@@ -52,4 +53,8 @@ public class BridgeNode extends Renderable { ...@@ -52,4 +53,8 @@ public class BridgeNode extends Renderable {
} }
@Override
public CityObject getFeature() {
return bridge;
}
} }
package de.hft.stuttgart.citydoctor2.gui.tree; package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.Building; import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.gui.CheckStatus; import de.hft.stuttgart.citydoctor2.gui.CheckStatus;
import de.hft.stuttgart.citydoctor2.gui.Renderer; import de.hft.stuttgart.citydoctor2.gui.Renderer;
public class BuildingNode extends Renderable { public class BuildingNode extends Renderable implements FeatureNode {
private final Building building; private final Building building;
...@@ -37,4 +38,8 @@ public class BuildingNode extends Renderable { ...@@ -37,4 +38,8 @@ public class BuildingNode extends Renderable {
} }
} }
@Override
public CityObject getFeature() {
return building;
}
} }
package de.hft.stuttgart.citydoctor2.gui.tree; package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.CityFurniture; import de.hft.stuttgart.citydoctor2.datastructure.CityFurniture;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.gui.CheckStatus; import de.hft.stuttgart.citydoctor2.gui.CheckStatus;
import de.hft.stuttgart.citydoctor2.gui.Renderer; import de.hft.stuttgart.citydoctor2.gui.Renderer;
public class CityFurnitureNode extends Renderable{ public class CityFurnitureNode extends Renderable implements FeatureNode {
private final CityFurniture cityFurniture; private final CityFurniture cityFurniture;
...@@ -33,4 +34,9 @@ public class CityFurnitureNode extends Renderable{ ...@@ -33,4 +34,9 @@ public class CityFurnitureNode extends Renderable{
setStatus(CheckStatus.OK); setStatus(CheckStatus.OK);
} }
} }
@Override
public CityObject getFeature() {
return cityFurniture;
}
} }
...@@ -4,7 +4,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.CityObject; ...@@ -4,7 +4,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.gui.CheckStatus; import de.hft.stuttgart.citydoctor2.gui.CheckStatus;
import de.hft.stuttgart.citydoctor2.gui.Renderer; import de.hft.stuttgart.citydoctor2.gui.Renderer;
public class CityObjectNode extends Renderable { public class CityObjectNode extends Renderable implements FeatureNode{
private final CityObject co; private final CityObject co;
...@@ -33,4 +33,9 @@ public class CityObjectNode extends Renderable { ...@@ -33,4 +33,9 @@ public class CityObjectNode extends Renderable {
renderer.render(co); renderer.render(co);
} }
@Override
public CityObject getFeature() {
return co;
}
} }
package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
public interface FeatureNode {
public CityObject getFeature();
}
package de.hft.stuttgart.citydoctor2.gui.tree; package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GenericCityObject; import de.hft.stuttgart.citydoctor2.datastructure.GenericCityObject;
import de.hft.stuttgart.citydoctor2.gui.CheckStatus; import de.hft.stuttgart.citydoctor2.gui.CheckStatus;
import de.hft.stuttgart.citydoctor2.gui.Renderer; import de.hft.stuttgart.citydoctor2.gui.Renderer;
public class GenericCityObjectsNode extends Renderable{ public class GenericCityObjectsNode extends Renderable implements FeatureNode {
private final GenericCityObject gcobject; private final GenericCityObject gcobject;
...@@ -33,4 +34,9 @@ public class GenericCityObjectsNode extends Renderable{ ...@@ -33,4 +34,9 @@ public class GenericCityObjectsNode extends Renderable{
setStatus(CheckStatus.OK); setStatus(CheckStatus.OK);
} }
} }
@Override
public CityObject getFeature() {
return gcobject;
}
} }
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