From 253e4fa01dc79968e35a816b6f78312c9f55adc3 Mon Sep 17 00:00:00 2001 From: Vitali Graf Date: Sun, 3 Aug 2025 16:31:38 +0200 Subject: [PATCH] =?UTF-8?q?Kontextmen=C3=BC=20f=C3=BCr=20Baum=20erstellt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/MainWindow.py | 245 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 243 insertions(+), 2 deletions(-) diff --git a/src/ui/MainWindow.py b/src/ui/MainWindow.py index 1b8c9cc..5007822 100644 --- a/src/ui/MainWindow.py +++ b/src/ui/MainWindow.py @@ -10,7 +10,7 @@ from PySide6.QtPdf import QPdfDocument from ui.MainWinddow_ui import Ui_MainWindow from ui.AppSettings import AppSettingsDlg from ui.PdfProject import PdfProjectDlg -from conf import app_settings, PdfProject, PdfProjectSettings, TreeNode, XslFile +from conf import app_settings, PdfProject, PdfProjectSettings, TreeNode, XslFile, XmlFile from pathlib import Path @@ -71,6 +71,9 @@ class MainWindow(QMainWindow): # Signale und Slots verbinden self._connect_signals() + + # Kontextmenü für TreeWidget einrichten + self._setup_tree_context_menu() def _setup_theme_menu(self): """Initialisiert das Theme-Menü mit verfügbaren Themes.""" @@ -536,6 +539,196 @@ class MainWindow(QMainWindow): self.ui.actionNeu.triggered.connect(self.open_new_project_dialog) self.ui.actionEinstellungen.triggered.connect(self.open_settings_dialog) + def _setup_tree_context_menu(self): + """Richtet das Kontextmenü für das TreeWidget ein.""" + # Aktiviere Kontextmenü für das TreeWidget + self.ui.treeWidget.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) + self.ui.treeWidget.customContextMenuRequested.connect(self._show_tree_context_menu) + print("Kontextmenü für TreeWidget eingerichtet") + + def _show_tree_context_menu(self, position): + """ + Zeigt das Kontextmenü für das TreeWidget an. + + Args: + position: Position des Rechtsklicks + """ + # Hole das Item an der Position + item = self.ui.treeWidget.itemAt(position) + if not item: + return + + # Bestimme den Node-Typ basierend auf dem Item + node_type = self._get_node_type_from_item(item) + + # Erstelle das entsprechende Kontextmenü + context_menu = self._create_context_menu_for_type(node_type, item) + + if context_menu: + # Zeige das Kontextmenü an der globalen Position + global_pos = self.ui.treeWidget.mapToGlobal(position) + context_menu.exec(global_pos) + + def _get_node_type_from_item(self, item): + """ + Bestimmt den Node-Typ basierend auf dem TreeWidgetItem. + + Args: + item: Das TreeWidgetItem + + Returns: + str: Der Node-Typ ('TreeNode', 'XslFile', 'XmlFile' oder 'Unknown') + """ + try: + # Prüfe ob das Item ein Parent hat (dann ist es ein Child-Item) + parent_item = item.parent() + + if parent_item: + # Child-Item - prüfe ob es ein XML-File ist + text = item.text(0) + if text.startswith("XML:"): + return "XmlFile" + else: + # Könnte ein TreeNode-Child oder XslFile-Child sein + # Prüfe den Parent-Typ + parent_type = self._get_node_type_from_item(parent_item) + if parent_type == "XslFile": + return "XmlFile" + else: + # Rekursiv bestimmen basierend auf gespeicherten Daten + return self._determine_node_type_from_data(item) + else: + # Root-Item - bestimme Typ basierend auf gespeicherten Daten + return self._determine_node_type_from_data(item) + + except Exception as e: + print(f"Fehler beim Bestimmen des Node-Typs: {e}") + return "Unknown" + + def _determine_node_type_from_data(self, item): + """ + Bestimmt den Node-Typ basierend auf den gespeicherten Daten im Item. + + Args: + item: Das TreeWidgetItem + + Returns: + str: Der Node-Typ ('TreeNode', 'XslFile' oder 'Unknown') + """ + try: + # Hole die gespeicherte Node-ID + node_id = item.data(0, Qt.ItemDataRole.UserRole) + if not node_id: + return "Unknown" + + # Suche in den Projekt-Nodes nach der ID + if hasattr(self, 'pdf_project') and self.pdf_project and self.pdf_project.nodes: + node = self._find_node_by_id(self.pdf_project.nodes, node_id) + if node: + if isinstance(node, TreeNode): + return "TreeNode" + elif isinstance(node, XslFile): + return "XslFile" + + return "Unknown" + + except Exception as e: + print(f"Fehler beim Bestimmen des Node-Typs aus Daten: {e}") + return "Unknown" + + def _find_node_by_id(self, nodes, target_id): + """ + Sucht rekursiv nach einem Node mit der angegebenen ID. + + Args: + nodes: Liste der Nodes zum Durchsuchen + target_id: Die zu suchende ID + + Returns: + TreeNode|XslFile|None: Der gefundene Node oder None + """ + for node in nodes: + if node.id == target_id: + return node + + # Rekursiv in Kindern suchen (nur bei TreeNode) + if isinstance(node, TreeNode) and node.children: + found = self._find_node_by_id(node.children, target_id) + if found: + return found + + return None + + def _create_context_menu_for_type(self, node_type, item): + """ + Erstellt das Kontextmenü für den angegebenen Node-Typ. + + Args: + node_type: Der Typ des Nodes ('TreeNode', 'XslFile', 'XmlFile') + item: Das TreeWidgetItem + + Returns: + QMenu: Das erstellte Kontextmenü oder None + """ + try: + menu = QMenu(self) + + if node_type == "TreeNode": + # Kontextmenü für TreeNode + action_add_child = QAction("Unterknoten hinzufügen", self) + action_add_child.triggered.connect(lambda: self._add_tree_node_child(item)) + menu.addAction(action_add_child) + + action_add_xsl = QAction("XSL-Datei hinzufügen", self) + action_add_xsl.triggered.connect(lambda: self._add_xsl_file_to_node(item)) + menu.addAction(action_add_xsl) + + menu.addSeparator() + + action_edit = QAction("Bearbeiten", self) + action_edit.triggered.connect(lambda: self._edit_tree_node(item)) + menu.addAction(action_edit) + + action_delete = QAction("Löschen", self) + action_delete.triggered.connect(lambda: self._delete_tree_node(item)) + menu.addAction(action_delete) + + elif node_type == "XslFile": + # Kontextmenü für XslFile + action_add_xml = QAction("XML-Datei hinzufügen", self) + action_add_xml.triggered.connect(lambda: self._add_xml_file_to_xsl(item)) + menu.addAction(action_add_xml) + + menu.addSeparator() + + action_edit = QAction("Bearbeiten", self) + action_edit.triggered.connect(lambda: self._edit_xsl_file(item)) + menu.addAction(action_edit) + + action_delete = QAction("Löschen", self) + action_delete.triggered.connect(lambda: self._delete_xsl_file(item)) + menu.addAction(action_delete) + + elif node_type == "XmlFile": + # Kontextmenü für XmlFile + action_edit = QAction("Bearbeiten", self) + action_edit.triggered.connect(lambda: self._edit_xml_file(item)) + menu.addAction(action_edit) + + action_delete = QAction("Löschen", self) + action_delete.triggered.connect(lambda: self._delete_xml_file(item)) + menu.addAction(action_delete) + + else: + # Unbekannter Typ - kein Menü + return None + + return menu + + except Exception as e: + print(f"Fehler beim Erstellen des Kontextmenüs: {e}") + return None + def on_alpha_changed(self, alpha_value): """ Wird ausgeführt, wenn der Alpha-Slider geändert wird. @@ -755,7 +948,7 @@ class MainWindow(QMainWindow): # Erstelle Tree-Item item = QTreeWidgetItem() - # Setze die Bezeichnung in Spalte 0 (mit expliziter UTF-8 Behandlung) + # Setze die Bezeichnung in Spalte 0 bez_text = str(node.bez) if node.bez else "" item.setText(0, bez_text) @@ -799,6 +992,54 @@ class MainWindow(QMainWindow): fallback_item.setText(1, str(e)) return fallback_item + # Kontextmenü-Aktionen für TreeNode + def _add_tree_node_child(self, parent_item): + """Fügt einen Unterknoten zu einem TreeNode hinzu.""" + print(f"Unterknoten zu TreeNode hinzufügen: {parent_item.text(0)}") + # TODO: Dialog zum Eingeben der Node-Daten öffnen + + def _add_xsl_file_to_node(self, parent_item): + """Fügt eine XSL-Datei zu einem TreeNode hinzu.""" + print(f"XSL-Datei zu TreeNode hinzufügen: {parent_item.text(0)}") + # TODO: Dialog zum Auswählen der XSL-Datei öffnen + + def _edit_tree_node(self, item): + """Bearbeitet einen TreeNode.""" + print(f"TreeNode bearbeiten: {item.text(0)}") + # TODO: Dialog zum Bearbeiten der Node-Daten öffnen + + def _delete_tree_node(self, item): + """Löscht einen TreeNode.""" + print(f"TreeNode löschen: {item.text(0)}") + # TODO: Bestätigungsdialog und Löschung implementieren + + # Kontextmenü-Aktionen für XslFile + def _add_xml_file_to_xsl(self, parent_item): + """Fügt eine XML-Datei zu einer XSL-Datei hinzu.""" + print(f"XML-Datei zu XslFile hinzufügen: {parent_item.text(0)}") + # TODO: Dialog zum Auswählen der XML-Datei öffnen + + def _edit_xsl_file(self, item): + """Bearbeitet eine XSL-Datei.""" + print(f"XslFile bearbeiten: {item.text(0)}") + # TODO: Dialog zum Bearbeiten der XSL-Datei öffnen + + def _delete_xsl_file(self, item): + """Löscht eine XSL-Datei.""" + print(f"XslFile löschen: {item.text(0)}") + # TODO: Bestätigungsdialog und Löschung implementieren + + # Kontextmenü-Aktionen für XmlFile + def _edit_xml_file(self, item): + """Bearbeitet eine XML-Datei.""" + print(f"XmlFile bearbeiten: {item.text(0)}") + # TODO: Dialog zum Bearbeiten der XML-Datei öffnen + + def _delete_xml_file(self, item): + """Löscht eine XML-Datei.""" + print(f"XmlFile löschen: {item.text(0)}") + # TODO: Bestätigungsdialog und Löschung implementieren + def closeEvent(self, event): """Wird beim Schließen der Anwendung aufgerufen.""" # PDF-Dokumente schließen ist bei QtPdf automatisch durch Garbage Collection