Files
xsl-validator/src/ui/XmlToXslAssignDialog.py
T

302 lines
10 KiB
Python
Raw Normal View History

import logging
2025-08-31 17:37:51 +02:00
from PySide6.QtWidgets import QDialog, QTreeWidgetItem, QCheckBox, QMessageBox, QWidget, QHBoxLayout
from PySide6.QtCore import Qt
from pathlib import Path
from ui.XmlToXslAssignDialog_ui import Ui_XmlToXslAssignDialog
2025-08-31 17:06:24 +02:00
from conf import TreeNode, XslFile
logger = logging.getLogger(__name__)
class XmlToXslAssignDialog(QDialog):
"""Dialog zur Zuordnung einer XML-Datei zu XSL-Knoten."""
def __init__(self, parent=None, xml_file_path=None, project_nodes=None):
"""
Initialisiert den Dialog.
Args:
parent: Übergeordnetes Widget
xml_file_path: Pfad zur XML-Datei
project_nodes: Liste der Projekt-Knoten
"""
super().__init__(parent)
# UI einrichten
self.ui = Ui_XmlToXslAssignDialog()
self.ui.setupUi(self)
# Parameter speichern
self.xml_file_path = Path(xml_file_path) if xml_file_path else None
self.project_nodes = project_nodes or []
# Dictionary zum Speichern der Checkbox-Referenzen
self.xsl_checkboxes = {} # {xsl_node_id: checkbox}
# Signale verbinden
self.ui.selectAllButton.clicked.connect(self.select_all)
self.ui.deselectAllButton.clicked.connect(self.deselect_all)
# Baum konfigurieren
self._setup_tree()
# Daten laden
self._load_data()
def _setup_tree(self):
"""Konfiguriert das TreeWidget."""
# Spaltenbreiten setzen
self.ui.xslNodesTree.setColumnWidth(0, 300) # XSL-Knoten
self.ui.xslNodesTree.setColumnWidth(1, 200) # Details
self.ui.xslNodesTree.setColumnWidth(2, 100) # Auswählen
# Header-Eigenschaften
self.ui.xslNodesTree.header().setStretchLastSection(False)
2025-08-31 17:37:51 +02:00
def _create_centered_checkbox(self):
"""
Erstellt eine zentrierte Checkbox in einem Widget.
Returns:
tuple: (widget, checkbox) - Das Container-Widget und die Checkbox
"""
# Erstelle Container-Widget
widget = QWidget()
# Erstelle horizontales Layout
layout = QHBoxLayout(widget)
layout.setContentsMargins(0, 0, 0, 0)
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Erstelle Checkbox
checkbox = QCheckBox()
checkbox.setChecked(False)
# Füge Checkbox zum Layout hinzu
layout.addWidget(checkbox)
return widget, checkbox
def _add_checkboxes_to_tree(self):
"""
Fügt Checkboxen zu allen XSL-Knoten im Tree hinzu.
Diese Methode wird nach dem Hinzufügen aller Items aufgerufen.
"""
try:
# Durchlaufe alle Items im Tree rekursiv
root = self.ui.xslNodesTree.invisibleRootItem()
self._add_checkboxes_recursive(root)
logger.debug(f"Checkboxen zu {len(self.xsl_checkboxes)} XSL-Knoten hinzugefügt")
2025-08-31 17:37:51 +02:00
except Exception as e:
logger.error(f"Fehler beim Hinzufügen der Checkboxen: {e}")
2025-08-31 17:37:51 +02:00
def _add_checkboxes_recursive(self, parent_item):
"""
Fügt rekursiv Checkboxen zu XSL-Knoten hinzu.
Args:
parent_item: Das Eltern-Item
"""
for i in range(parent_item.childCount()):
item = parent_item.child(i)
# Hole das Node-Objekt
node = item.data(0, Qt.ItemDataRole.UserRole)
if isinstance(node, XslFile):
# Erstelle zentrierte Checkbox für XSL-Knoten
checkbox_widget, checkbox = self._create_centered_checkbox()
# Setze das Widget in Spalte 2
self.ui.xslNodesTree.setItemWidget(item, 2, checkbox_widget)
# Speichere Checkbox-Referenz
self.xsl_checkboxes[id(node)] = checkbox
logger.debug(f"Checkbox für XSL-Knoten '{node.bez}' hinzugefügt")
2025-08-31 17:37:51 +02:00
# Rekursiv für Kinder
if item.childCount() > 0:
self._add_checkboxes_recursive(item)
def _load_data(self):
"""Lädt die Daten in den Dialog."""
# XML-Datei-Label setzen
if self.xml_file_path:
self.ui.xmlFileLabel.setText(f"XML-Datei: {self.xml_file_path.name}")
# Projekt-Knoten in Baum laden
self._load_project_nodes()
def _load_project_nodes(self):
2025-09-19 20:29:56 +02:00
"""Lädt die Projekt-Knoten in das TreeWidget (ohne XML-Knoten).
Sortiert die Items alphabetisch nach ihrer ID."""
if not self.project_nodes:
return
# TreeWidget leeren
self.ui.xslNodesTree.clear()
self.xsl_checkboxes.clear()
2025-09-19 20:29:56 +02:00
# Sortiere Root-Nodes alphabetisch nach ID
sorted_nodes = sorted(self.project_nodes, key=lambda node: node.id)
# Alle Root-Nodes laden (sortiert)
for node in sorted_nodes:
tree_item = self._create_tree_item_from_node(node)
if tree_item: # Nur hinzufügen wenn Item erstellt wurde
self.ui.xslNodesTree.addTopLevelItem(tree_item)
# Baum expandieren
self.ui.xslNodesTree.expandAll()
2025-08-31 17:37:51 +02:00
# Checkboxen nach dem Hinzufügen der Items erstellen
self._add_checkboxes_to_tree()
def _create_tree_item_from_node(self, node):
"""
Erstellt ein QTreeWidgetItem aus einem TreeNode oder XslFile.
XML-Knoten werden ausgeschlossen.
Args:
node: TreeNode oder XslFile Objekt
Returns:
QTreeWidgetItem: Das erstellte Tree-Item oder None wenn ausgeschlossen
"""
try:
# Erstelle Tree-Item
item = QTreeWidgetItem()
# Setze die Bezeichnung in Spalte 0
bez_text = str(node.bez) if node.bez else ""
item.setText(0, bez_text)
# Speichere das komplette Node-Objekt
item.setData(0, Qt.ItemDataRole.UserRole, node)
if isinstance(node, TreeNode):
# TreeNode: Zeige Anzahl der Knoten
child_count = len(node.children) if node.children else 0
item.setText(1, f"{child_count} Knoten")
2025-09-19 20:29:56 +02:00
# Lade Knoten rekursiv (sortiert nach ID, nur TreeNode und XslFile, keine XML)
if node.children:
2025-09-19 20:29:56 +02:00
# Filtere und sortiere Kinder
valid_children = [child for child in node.children if isinstance(child, (TreeNode, XslFile))]
sorted_children = sorted(valid_children, key=lambda child: child.id)
for child in sorted_children:
child_item = self._create_tree_item_from_node(child)
if child_item:
item.addChild(child_item)
elif isinstance(node, XslFile):
2025-08-31 17:37:51 +02:00
# XslFile: Zeige XSL-Datei-Pfad
item.setText(1, str(node.xsl_file))
2025-08-31 17:37:51 +02:00
# Checkbox wird später in _add_checkboxes_to_tree() hinzugefügt
# Keine Knoten für XslFile hinzufügen (XML-Dateien werden ausgeschlossen)
return item
except Exception as e:
logger.error(f"Fehler beim Erstellen des Tree-Items: {e}")
return None
def select_all(self):
"""Wählt alle XSL-Knoten aus."""
2025-08-31 17:37:51 +02:00
for checkbox in self.xsl_checkboxes.values():
checkbox.setChecked(True)
def deselect_all(self):
"""Wählt alle XSL-Knoten ab."""
2025-08-31 17:37:51 +02:00
for checkbox in self.xsl_checkboxes.values():
checkbox.setChecked(False)
def get_selected_xsl_nodes(self):
"""
Gibt die ausgewählten XSL-Knoten zurück.
Returns:
list[XslFile]: Liste der ausgewählten XSL-Knoten
"""
selected_nodes = []
try:
2025-08-31 17:37:51 +02:00
# Durchlaufe alle XSL-Checkboxes
for node_id, checkbox in self.xsl_checkboxes.items():
if checkbox.isChecked():
# Finde den entsprechenden XSL-Knoten
xsl_node = self._find_xsl_node_by_id(node_id)
if xsl_node:
selected_nodes.append(xsl_node)
return selected_nodes
except Exception as e:
logger.error(f"Fehler beim Sammeln der ausgewählten XSL-Knoten: {e}")
return []
def _find_xsl_node_by_id(self, node_id):
"""
Findet einen XSL-Knoten anhand seiner ID.
Args:
node_id: Die ID des Knotens (Python id())
Returns:
XslFile: Der gefundene XSL-Knoten oder None
"""
return self._find_xsl_node_recursive(self.project_nodes, node_id)
def _find_xsl_node_recursive(self, nodes, target_id):
"""
Sucht rekursiv nach einem XSL-Knoten mit der angegebenen ID.
Args:
nodes: Liste der Nodes zum Durchsuchen
target_id: Die zu suchende ID
Returns:
XslFile: Der gefundene XSL-Knoten oder None
"""
for node in nodes:
if isinstance(node, XslFile) and id(node) == target_id:
return node
# Rekursiv in Knoten suchen (nur bei TreeNode)
if isinstance(node, TreeNode) and node.children:
found = self._find_xsl_node_recursive(node.children, target_id)
if found:
return found
return None
def get_xml_file_path(self):
"""
Gibt den Pfad zur XML-Datei zurück.
Returns:
Path: Pfad zur XML-Datei
"""
return self.xml_file_path
def accept(self):
"""Überschreibt accept() um Validierung durchzuführen."""
selected_nodes = self.get_selected_xsl_nodes()
if not selected_nodes:
QMessageBox.warning(
self,
"Warnung",
"Bitte wählen Sie mindestens einen XSL-Knoten aus."
)
return
super().accept()