From 89c2a84598d65b851e9f2bef3edddb0d6dca4a07 Mon Sep 17 00:00:00 2001
From: Riegel <alexander.riegel@hft-stuttgart.de>
Date: Wed, 13 Nov 2024 11:26:34 +0100
Subject: [PATCH] Expand ContextMenu functionality for FeatureTabs

---
 .../datastructure/CompositeCollection.java    |   1 +
 .../CityDoctorLocalization.properties         |   8 +-
 .../CityDoctorLocalization_de.properties      |   8 +-
 .../citydoctor2/gui/CityDoctorController.java |   6 +-
 .../stuttgart/citydoctor2/gui/MainWindow.java | 157 +++++++++++++++++-
 5 files changed, 169 insertions(+), 11 deletions(-)

diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/CompositeCollection.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/CompositeCollection.java
index 25dd97b..852349a 100644
--- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/CompositeCollection.java
+++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/CompositeCollection.java
@@ -32,6 +32,7 @@ public final class CompositeCollection implements Serializable {
         return childComposites;
     }
 
+    //TODO stream
     public List<ConcretePolygon> getCompositeMembers() {
         List<ConcretePolygon> copy = new ArrayList<>(compositeMembers);
         for (CompositeCollection c : childComposites) {
diff --git a/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization.properties b/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization.properties
index ddba244..353fd02 100644
--- a/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization.properties
+++ b/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization.properties
@@ -18,6 +18,7 @@ CheckDialog.parameterValue=Value
 CheckDialog.parameterUnit=Unit
 CityDoctorController.noDatamodel=Datamodel is null, no checks could be done
 CityDoctorController.noSourceFile=Source file is null, no checks could be done
+CityDoctorController.exportSuccess=Successfully exported feature
 ExceptionDialog.stacktrace=The exception stacktrace was:
 FilterPane.buildings=Buildings
 FilterPane.bridges=Bridges
@@ -43,7 +44,12 @@ MainWindow.finishedPdf=Finished pdf report
 MainWindow.loadFailed=Failed to load given gml file: {}
 MainWindow.all=All
 MainWindow.withErrors=With errors
-MainWindow.export=Export
+MainWindow.export=Export feature
+MainWindow.copyId=Copy GML-ID
+MainWindow.delete=Delete feature
+MainWindow.infoTopLevelExport=Only top-level object can be exported!
+MainWindow.infoTopLevelCopyID=GML-ID can only be copied from top-level object!
+mainWindow.warnCopyIdFailed=Could not copy GML-ID!
 OpenFileDialog.select=Select CityGML file
 MainWindow.languageChange=For the change in language to apply, restart CityDoctor2.
 MainWindow.buildingsTab=Buildings
diff --git a/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization_de.properties b/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization_de.properties
index b93a141..58c4a4c 100644
--- a/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization_de.properties
+++ b/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization_de.properties
@@ -16,6 +16,7 @@ CheckDialog.parameterValue=Wert
 CheckDialog.parameterUnit=Einheit
 CityDoctorController.noDatamodel=Datenmodell ist null, keine Pr\u00fcfungen konnten ausgef\u00fchrt werden
 CityDoctorController.noSourceFile=Quelldatei ist null, keine Pr\u00fcfungen konnten ausgef\u00fchrt werden
+CityDoctorController.exportSuccess=Feature export erfolgreich abgeschlossen
 ExceptionDialog.stacktrace=Der Stacktrace des Fehlers war:
 FilterPane.buildings=Geb\u00e4ude
 FilterPane.bridges=Br\u00fccken
@@ -41,7 +42,12 @@ MainWindow.finishedPdf=Pdf Report abgeschlossen
 MainWindow.loadFailed=Konnte GML-Datei nicht laden: {}
 MainWindow.all=Alle
 MainWindow.withErrors=Mit Fehlern
-MainWindow.export=Exportieren
+MainWindow.export=Feature Exportieren
+MainWindow.copyId=GML-ID kopieren
+MainWindow.delete=Feature L\u00f6schen
+MainWindow.infoTopLevelExport=Export ist nur f\u00fcr Featureobjekt basis m\u00f6glich!
+MainWindow.infoTopLevelCopyID=GML-ID kann nur von Featureobjekt basis kopiert werden!
+mainWindow.warnCopyIdFailed=Kopieren der ID fehlgeschlagen!
 OpenFileDialog.select=W\u00e4hle CityGML Datei aus
 MainWindow.languageChange=Um die Spracheinstellung zu \u00fcbernehmen muss CityDoctor2 neugestartet werden.
 MainWindow.buildingsTab=Geb\u00e4ude
diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java
index 0f7be6b..3c89ad0 100644
--- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java
+++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java
@@ -798,13 +798,14 @@ public class CityDoctorController {
         }
     }
 
-    public void export(Building b) {
+    public void export(CityObject co) {
         if (model == null) {
             return;
         }
         CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile());
         newModel.setCityModel(new CityModel());
-        newModel.addBuilding(b);
+        newModel.addCityObject(co);
+        newModel.setParsedCityGMLVersion(model.getCityGMLVersion());
 
         FileChooser fc = new FileChooser();
         fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml"));
@@ -819,7 +820,6 @@ public class CityDoctorController {
         if (f != null) {
             Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
             try {
-
                 newModel.saveAs(f.getAbsolutePath(), true);
             } catch (CityDoctorWriteException e) {
                 logger.error(e);
diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainWindow.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainWindow.java
index d6f77f6..dcac59b 100644
--- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainWindow.java
+++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainWindow.java
@@ -5,7 +5,7 @@ import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
 import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox;
 import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
 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.RenderableTreeCell;
 import de.hft.stuttgart.citydoctor2.parameter.ArgumentParser;
@@ -25,10 +25,7 @@ import javafx.scene.control.Alert.AlertType;
 import javafx.scene.image.Image;
 import javafx.scene.image.ImageView;
 import javafx.scene.image.WritableImage;
-import javafx.scene.input.Dragboard;
-import javafx.scene.input.MouseButton;
-import javafx.scene.input.MouseEvent;
-import javafx.scene.input.TransferMode;
+import javafx.scene.input.*;
 import javafx.scene.layout.BorderPane;
 import javafx.scene.layout.HBox;
 import javafx.scene.layout.Pane;
@@ -46,6 +43,8 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.*;
 
+import static javafx.scene.input.Clipboard.getSystemClipboard;
+
 public class MainWindow extends Application {
 
     private static final Logger logger = LogManager.getLogger(MainWindow.class);
@@ -734,6 +733,8 @@ public class MainWindow extends Application {
         buildingsView.setShowRoot(true);
         setupSelectListener(buildingsView);
         buildingsView.setCellFactory(param -> new RenderableTreeCell());
+        setupBuildingTabContextMenu();
+        /*
         ContextMenu cMenu = new ContextMenu();
         MenuItem mi = new MenuItem(Localization.getText("MainWindow.export"));
         mi.setOnAction(ea -> {
@@ -743,29 +744,44 @@ public class MainWindow extends Application {
             }
         });
         cMenu.getItems().add(mi);
+        MenuItem clipMi = new MenuItem(Localization.getText("MainWindow.copyId"));
+        clipMi.setOnAction(ea -> {
+            Renderable render = buildingsView.getSelectionModel().getSelectedItem().getValue();
+            if (render instanceof BuildingNode node) {
+                Clipboard clipboard = getSystemClipboard();
+                ClipboardContent content = new ClipboardContent();
+                content.putString(node.getBuilding().getGmlId().toString());
+                clipboard.setContent(content);
+            }
+        });
+        cMenu.getItems().add(clipMi);
 
         MenuItem deleteMi = new MenuItem("Delete");
         deleteMi.setOnAction(ae -> controller.delete(buildingsView.getSelectionModel().getSelectedItem()));
         cMenu.getItems().add(deleteMi);
 
         buildingsView.setContextMenu(cMenu);
+        */
 
         vegetationView.setShowRoot(true);
         setupSelectListener(vegetationView);
         vegetationView.setCellFactory(param -> new RenderableTreeCell());
-        vegetationView.setContextMenu(cMenu);
+        setupVegetationTabContextMenu();
 
         transView.setShowRoot(true);
         setupSelectListener(transView);
         transView.setCellFactory(param -> new RenderableTreeCell());
 
+
         tunnelView.setShowRoot(true);
         setupSelectListener(tunnelView);
         tunnelView.setCellFactory(param -> new RenderableTreeCell());
+        setupFeatureTabContextMenu(tunnelView);
 
         bridgeView.setShowRoot(true);
         setupSelectListener(bridgeView);
         bridgeView.setCellFactory(param -> new RenderableTreeCell());
+        setupFeatureTabContextMenu(bridgeView);
 
         waterView.setShowRoot(true);
         setupSelectListener(waterView);
@@ -778,10 +794,12 @@ public class MainWindow extends Application {
         cityFurnitureView.setShowRoot(true);
         setupSelectListener(cityFurnitureView);
         cityFurnitureView.setCellFactory(param -> new RenderableTreeCell());
+        setupFeatureTabContextMenu(cityFurnitureView);
 
         otherObjectsView.setShowRoot(true);
         setupSelectListener(otherObjectsView);
         otherObjectsView.setCellFactory(param -> new RenderableTreeCell());
+        setupFeatureTabContextMenu(otherObjectsView);
 
         setupSelectListener(vertexView);
         vertexView.setRoot(new TreeItem<>());
@@ -798,6 +816,133 @@ public class MainWindow extends Application {
         setupSelectListener(attributeView);
         attributeView.setRoot(new TreeItem<>());
         attributeView.setCellFactory(param -> new RenderableTreeCell());
+
+    }
+
+    private void setupBuildingTabContextMenu() {
+        ContextMenu menu = new ContextMenu();
+        MenuItem mi = new MenuItem(Localization.getText("MainWindow.export"));
+        mi.setOnAction(ea -> {
+            Renderable render = buildingsView.getSelectionModel().getSelectedItem().getValue();
+            if (render instanceof FeatureNode node) {
+                try {
+                    controller.export(node.getFeature());
+                    logger.info(Localization.getText("CityDoctorController.export"));
+                } 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 = buildingsView.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(buildingsView.getSelectionModel().getSelectedItem()));
+        menu.getItems().add(deleteMi);
+        buildingsView.setContextMenu(menu);
+    }
+
+    private void setupVegetationTabContextMenu() {
+        ContextMenu menu = new ContextMenu();
+        MenuItem mi = new MenuItem(Localization.getText("MainWindow.export"));
+        mi.setOnAction(ea -> {
+            Renderable render = vegetationView.getSelectionModel().getSelectedItem().getValue();
+            if (render instanceof FeatureNode node) {
+                try {
+                    controller.export(node.getFeature());
+                    logger.info(Localization.getText("CityDoctorController.export"));
+                } 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 = vegetationView.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(vegetationView.getSelectionModel().getSelectedItem()));
+        menu.getItems().add(deleteMi);
+        vegetationView.setContextMenu(menu);
+    }
+
+    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.export"));
+                } 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) {
-- 
GitLab