Feat: XML-Knoten-Bearbeiten-Dialog implementiert (v1.6.0)
Neuer Dialog ermöglicht es, einem XML-Knoten XSL-Zuordnungen hinzuzufügen oder zu entfernen. XmlToXslAssignDialog wiederverwendet mit edit_mode, Vorauswahl per preselected_xsl_ids und get_selection_diff(). Beim Entfernen werden zugehörige PDF-Dateien gelöscht; bei verbleibend leerer Zuordnung wird das physische Löschen der XML-Datei angeboten. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+101
-16
@@ -13,14 +13,23 @@ 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):
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
xml_file_path=None,
|
||||
project_nodes=None,
|
||||
preselected_xsl_ids: set | None = None,
|
||||
edit_mode: bool = False,
|
||||
):
|
||||
"""
|
||||
Initialisiert den Dialog.
|
||||
|
||||
|
||||
Args:
|
||||
parent: Übergeordnetes Widget
|
||||
xml_file_path: Pfad zur XML-Datei
|
||||
project_nodes: Liste der Projekt-Knoten
|
||||
preselected_xsl_ids: Set von XslFile-IDs (tuple), deren Checkbox initial angehakt sein soll
|
||||
edit_mode: True = Bearbeiten-Modus (Zuordnungen ändern), False = Neu-Zuordnen
|
||||
"""
|
||||
super().__init__(parent)
|
||||
|
||||
@@ -31,9 +40,23 @@ class XmlToXslAssignDialog(QDialog):
|
||||
# Parameter speichern
|
||||
self.xml_file_path = Path(xml_file_path) if xml_file_path else None
|
||||
self.project_nodes = project_nodes or []
|
||||
self.preselected_xsl_ids: set = set(preselected_xsl_ids) if preselected_xsl_ids else set()
|
||||
self.edit_mode = edit_mode
|
||||
|
||||
# Dictionary zum Speichern der Checkbox-Referenzen
|
||||
self.xsl_checkboxes = {} # {xsl_node_id: checkbox}
|
||||
self.xsl_checkboxes = {} # {python_id(node): checkbox}
|
||||
self.xsl_nodes = {} # {python_id(node): XslFile}
|
||||
# Initial ausgewählte XslFile-IDs (tuple), um Diff beim Accept zu berechnen
|
||||
self._initial_selected_ids: set = set()
|
||||
|
||||
# Edit-Modus: UI anpassen
|
||||
if self.edit_mode:
|
||||
self.setWindowTitle("XML-Zuordnungen bearbeiten")
|
||||
self.ui.infoLabel.setText(
|
||||
"Passen Sie die Zuordnungen der XML-Datei an. Hinzufügen per Haken, "
|
||||
"Entfernen durch Abhaken (zugehörige PDFs werden gelöscht):"
|
||||
)
|
||||
self.ui.alle_xml.setVisible(False)
|
||||
|
||||
# Signale verbinden
|
||||
self.ui.selectAllButton.clicked.connect(self.select_all)
|
||||
@@ -45,6 +68,10 @@ class XmlToXslAssignDialog(QDialog):
|
||||
# Daten laden
|
||||
self._load_data()
|
||||
|
||||
# Duplikat-Warnung nur im Edit-Modus (um bestehende Aufrufer nicht bei jeder XML zu stören)
|
||||
if self.edit_mode:
|
||||
self._warn_on_duplicate_xsl_ids()
|
||||
|
||||
def _setup_tree(self):
|
||||
"""Konfiguriert das TreeWidget."""
|
||||
# Spaltenbreiten setzen
|
||||
@@ -110,13 +137,19 @@ class XmlToXslAssignDialog(QDialog):
|
||||
if isinstance(node, XslFile):
|
||||
# Erstelle zentrierte Checkbox für XSL-Knoten
|
||||
checkbox_widget, checkbox = self._create_centered_checkbox()
|
||||
|
||||
|
||||
# Vorauswahl setzen, wenn ID in preselected_xsl_ids
|
||||
if node.id in self.preselected_xsl_ids:
|
||||
checkbox.setChecked(True)
|
||||
self._initial_selected_ids.add(node.id)
|
||||
|
||||
# Setze das Widget in Spalte 2
|
||||
self.ui.xslNodesTree.setItemWidget(item, 2, checkbox_widget)
|
||||
|
||||
# Speichere Checkbox-Referenz
|
||||
|
||||
# Speichere Checkbox- und Node-Referenzen (id() als Key, da XSL-IDs theoretisch doppelt sein können)
|
||||
self.xsl_checkboxes[id(node)] = checkbox
|
||||
|
||||
self.xsl_nodes[id(node)] = node
|
||||
|
||||
logger.debug(f"Checkbox für XSL-Knoten '{node.bez}' hinzugefügt")
|
||||
|
||||
# Rekursiv für Kinder
|
||||
@@ -141,6 +174,8 @@ class XmlToXslAssignDialog(QDialog):
|
||||
# TreeWidget leeren
|
||||
self.ui.xslNodesTree.clear()
|
||||
self.xsl_checkboxes.clear()
|
||||
self.xsl_nodes.clear()
|
||||
self._initial_selected_ids.clear()
|
||||
|
||||
# Sortiere Root-Nodes alphabetisch nach ID
|
||||
sorted_nodes = sorted(self.project_nodes, key=lambda node: node.id)
|
||||
@@ -295,16 +330,66 @@ class XmlToXslAssignDialog(QDialog):
|
||||
"""
|
||||
return self.ui.alle_xml.isChecked()
|
||||
|
||||
def get_selection_diff(self) -> tuple[list, list]:
|
||||
"""
|
||||
Gibt die Änderungen der Auswahl gegenüber der Vorauswahl zurück.
|
||||
Nützlich im Edit-Modus, um nur die tatsächlich geänderten Zuordnungen zu verarbeiten.
|
||||
|
||||
Returns:
|
||||
tuple[list[XslFile], list[XslFile]]: (added_nodes, removed_nodes)
|
||||
- added_nodes: XslFile-Objekte, die neu angehakt wurden
|
||||
- removed_nodes: XslFile-Objekte, deren Haken entfernt wurde
|
||||
"""
|
||||
added_nodes = []
|
||||
removed_nodes = []
|
||||
|
||||
for py_id, checkbox in self.xsl_checkboxes.items():
|
||||
node = self.xsl_nodes.get(py_id)
|
||||
if node is None:
|
||||
continue
|
||||
|
||||
was_selected = node.id in self._initial_selected_ids
|
||||
is_selected = checkbox.isChecked()
|
||||
|
||||
if is_selected and not was_selected:
|
||||
added_nodes.append(node)
|
||||
elif not is_selected and was_selected:
|
||||
removed_nodes.append(node)
|
||||
|
||||
return added_nodes, removed_nodes
|
||||
|
||||
def _warn_on_duplicate_xsl_ids(self):
|
||||
"""
|
||||
Zeigt eine Warnung, wenn im Projekt mehrere XslFile-Instanzen mit identischer ID existieren.
|
||||
Die ID soll eindeutig sein - Duplikate weisen auf einen Datenfehler hin.
|
||||
"""
|
||||
id_to_nodes: dict = {}
|
||||
for py_id, node in self.xsl_nodes.items():
|
||||
id_to_nodes.setdefault(node.id, []).append(node)
|
||||
|
||||
duplicates = {xsl_id: nodes for xsl_id, nodes in id_to_nodes.items() if len(nodes) > 1}
|
||||
if not duplicates:
|
||||
return
|
||||
|
||||
dup_lines = [f" - ID {xsl_id}: {len(nodes)}× ({', '.join(n.bez for n in nodes)})" for xsl_id, nodes in duplicates.items()]
|
||||
logger.warning(f"Doppelte XSL-IDs im Projekt gefunden:\n{chr(10).join(dup_lines)}")
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"Doppelte XSL-IDs",
|
||||
"Im Projekt existieren XSL-Knoten mit identischer ID. "
|
||||
"Die IDs sollten eindeutig sein:\n\n" + "\n".join(dup_lines),
|
||||
)
|
||||
|
||||
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."
|
||||
)
|
||||
# Im Edit-Modus: 0 Auswahlen erlauben (bedeutet: XML überall entfernen)
|
||||
if self.edit_mode:
|
||||
super().accept()
|
||||
return
|
||||
|
||||
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user