Kontextmenü: Neue Aktion "Alle Änderungen übernehmen" für TreeNode und XslFile
Neue Kontextmenü-Funktionalität zum Batch-Akzeptieren von Diff-PDFs: - Neue Aktion "Alle Änderungen übernehmen" für TreeNode und XslFile - Wird nur aktiviert, wenn mindestens eine Diff-PDF unter dem Knoten existiert - Akzeptiert alle Diff-PDFs unter dem ausgewählten Knoten mit einem Klick Verhalten: - Verschiebt alle new-PDFs nach ref (alte ref-PDFs werden gelöscht) - Löscht alle diff-PDFs - Entfernt Diff-Icons bei allen betroffenen XML-Knoten - Aktualisiert Diff-PDF-Zähler auf allen übergeordneten Ebenen - Zeigt Bestätigungsdialog mit Anzahl der zu akzeptierenden Änderungen - Zeigt Erfolgsmeldung nach Abschluss Viewer-Behandlung: - KEINE Diff-PDF wird in den Viewer geladen - Falls eine akzeptierte Diff-PDF gerade im Viewer angezeigt wird, wird der Viewer geleert - Kein XML-Knoten wird im TreeWidget ausgewählt Bugfixes: - XSL-ID wird korrekt als "2002_1_128" statt "(2002, 1, 128)" formatiert - Relative Pfade werden für xml_item_map verwendet (statt absolute Pfade) - Diff-Icons werden jetzt korrekt entfernt Implementierungsdetails: - _collect_all_diff_pdfs_under_node(): Sammelt alle Diff-PDFs unter TreeNode oder XslFile - _accept_single_diff_pdf(): Akzeptiert eine einzelne Diff-PDF ohne Viewer-Update - _accept_all_changes_under_node(): Handler für Batch-Accept-Operation - Kontextmenü-Integration in _create_context_menu_for_type() - Logging-Konfiguration in main.py hinzugefügt (DEBUG-Level) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -989,6 +989,18 @@ class MainWindow(QMainWindow):
|
||||
|
||||
menu.addSeparator()
|
||||
|
||||
# Aktion "Alle Änderungen übernehmen" (nur aktiv wenn Diff-PDFs vorhanden)
|
||||
diff_pdfs = self._collect_all_diff_pdfs_under_node(tree_node_obj, item) if tree_node_obj else []
|
||||
has_diff_pdfs = len(diff_pdfs) > 0
|
||||
|
||||
action_accept_all = QAction("Alle Änderungen übernehmen", self)
|
||||
action_accept_all.setIcon(QIcon(QIcon.fromTheme("emblem-default")))
|
||||
action_accept_all.triggered.connect(lambda: self._accept_all_changes_under_node(item))
|
||||
action_accept_all.setEnabled(has_diff_pdfs)
|
||||
menu.addAction(action_accept_all)
|
||||
|
||||
menu.addSeparator()
|
||||
|
||||
action_edit = QAction("Bearbeiten", self)
|
||||
action_edit.setIcon(QIcon(QIcon.fromTheme(QIcon.ThemeIcon.DocumentProperties)))
|
||||
action_edit.triggered.connect(lambda: self._edit_tree_node(item))
|
||||
@@ -1026,6 +1038,18 @@ class MainWindow(QMainWindow):
|
||||
|
||||
menu.addSeparator()
|
||||
|
||||
# Aktion "Alle Änderungen übernehmen" (nur aktiv wenn Diff-PDFs vorhanden)
|
||||
diff_pdfs = self._collect_all_diff_pdfs_under_node(xsl_file_obj, item) if xsl_file_obj else []
|
||||
has_diff_pdfs = len(diff_pdfs) > 0
|
||||
|
||||
action_accept_all = QAction("Alle Änderungen übernehmen", self)
|
||||
action_accept_all.setIcon(QIcon(QIcon.fromTheme("emblem-default")))
|
||||
action_accept_all.triggered.connect(lambda: self._accept_all_changes_under_node(item))
|
||||
action_accept_all.setEnabled(has_diff_pdfs)
|
||||
menu.addAction(action_accept_all)
|
||||
|
||||
menu.addSeparator()
|
||||
|
||||
action_edit = QAction("Bearbeiten", self)
|
||||
action_edit.setIcon(QIcon(QIcon.fromTheme(QIcon.ThemeIcon.DocumentProperties)))
|
||||
action_edit.triggered.connect(lambda: self._edit_xsl_file(item))
|
||||
@@ -3643,6 +3667,74 @@ class MainWindow(QMainWindow):
|
||||
f"{successful_count} von {total_count} Transformationen erfolgreich\n{failed_count} fehlgeschlagen",
|
||||
)
|
||||
|
||||
def _collect_all_diff_pdfs_under_node(
|
||||
self, node_obj, item: QTreeWidgetItem
|
||||
) -> list[tuple[Path, str, Path, Path, Path]]:
|
||||
"""
|
||||
Sammelt alle Diff-PDFs unter einem TreeNode oder XslFile.
|
||||
|
||||
Args:
|
||||
node_obj: TreeNode oder XslFile Objekt
|
||||
item: Das TreeWidgetItem des Knotens
|
||||
|
||||
Returns:
|
||||
list[tuple]: Liste von (xml_file_path, xsl_id_str, diff_pdf_path, ref_pdf_path, new_pdf_path)
|
||||
"""
|
||||
diff_pdfs = []
|
||||
|
||||
if not self.project:
|
||||
return diff_pdfs
|
||||
|
||||
diff_dir = self.project.project_dir / "diff"
|
||||
ref_dir = self.project.project_dir / "ref"
|
||||
new_dir = self.project.project_dir / "new"
|
||||
|
||||
if not diff_dir.exists():
|
||||
return diff_pdfs
|
||||
|
||||
if isinstance(node_obj, TreeNode):
|
||||
# Sammle alle XSL/XML-Paare rekursiv
|
||||
xsl_xml_pairs = self._collect_all_xsl_xml_pairs_recursive(node_obj, item)
|
||||
|
||||
for xsl_file_obj, xml_file_obj, xsl_file_item in xsl_xml_pairs:
|
||||
# Baue XML-Pfad auf
|
||||
xml_file_path = self.project.project_dir / xml_file_obj.xml
|
||||
|
||||
# Baue PDF-Namen
|
||||
xml_stem = xml_file_path.stem
|
||||
xsl_id_str = "_".join(str(x) for x in xsl_file_obj.id) if xsl_file_obj.id else ""
|
||||
pdf_basename = f"{xml_stem}_xsl_{xsl_id_str}.pdf"
|
||||
|
||||
diff_pdf_path = diff_dir / pdf_basename
|
||||
ref_pdf_path = ref_dir / pdf_basename
|
||||
new_pdf_path = new_dir / pdf_basename
|
||||
|
||||
# Prüfe ob Diff-PDF existiert
|
||||
if diff_pdf_path.exists():
|
||||
diff_pdfs.append((xml_file_path, xsl_id_str, diff_pdf_path, ref_pdf_path, new_pdf_path))
|
||||
|
||||
elif isinstance(node_obj, XslFile):
|
||||
# Sammle alle XML-Dateien dieser XslFile
|
||||
xsl_id_str = "_".join(str(x) for x in node_obj.id) if node_obj.id else ""
|
||||
|
||||
for xml_file_obj in node_obj.xmls:
|
||||
# Baue XML-Pfad auf
|
||||
xml_file_path = self.project.project_dir / xml_file_obj.xml
|
||||
|
||||
# Baue PDF-Namen
|
||||
xml_stem = xml_file_path.stem
|
||||
pdf_basename = f"{xml_stem}_xsl_{xsl_id_str}.pdf"
|
||||
|
||||
diff_pdf_path = diff_dir / pdf_basename
|
||||
ref_pdf_path = ref_dir / pdf_basename
|
||||
new_pdf_path = new_dir / pdf_basename
|
||||
|
||||
# Prüfe ob Diff-PDF existiert
|
||||
if diff_pdf_path.exists():
|
||||
diff_pdfs.append((xml_file_path, xsl_id_str, diff_pdf_path, ref_pdf_path, new_pdf_path))
|
||||
|
||||
return diff_pdfs
|
||||
|
||||
def _find_next_diff_pdf(self) -> tuple[Path, str] | None:
|
||||
"""
|
||||
Findet die nächste Diff-PDF im Projekt.
|
||||
@@ -3680,6 +3772,138 @@ class MainWindow(QMainWindow):
|
||||
|
||||
return None
|
||||
|
||||
def _accept_single_diff_pdf(
|
||||
self, xml_file_path: Path, xsl_id_str: str, diff_pdf_path: Path, ref_pdf_path: Path, new_pdf_path: Path
|
||||
) -> bool:
|
||||
"""
|
||||
Akzeptiert eine einzelne Diff-PDF ohne Viewer-Update.
|
||||
|
||||
Args:
|
||||
xml_file_path: Pfad zur XML-Datei
|
||||
xsl_id_str: XSL-ID als String
|
||||
diff_pdf_path: Pfad zur Diff-PDF
|
||||
ref_pdf_path: Pfad zur Ref-PDF
|
||||
new_pdf_path: Pfad zur New-PDF
|
||||
|
||||
Returns:
|
||||
bool: True wenn erfolgreich, False bei Fehler
|
||||
"""
|
||||
try:
|
||||
pdf_basename = diff_pdf_path.name
|
||||
|
||||
# Prüfe ob new-PDF existiert
|
||||
if not new_pdf_path.exists():
|
||||
logger.warning(f"New-PDF nicht gefunden: {pdf_basename}")
|
||||
return False
|
||||
|
||||
# Lösche alte ref-PDF falls vorhanden
|
||||
if ref_pdf_path.exists():
|
||||
ref_pdf_path.unlink()
|
||||
logger.debug(f"Alte Ref-PDF gelöscht: {ref_pdf_path}")
|
||||
|
||||
# Verschiebe new-PDF nach ref
|
||||
shutil.move(str(new_pdf_path), str(ref_pdf_path))
|
||||
logger.debug(f"New-PDF verschoben nach Ref: {new_pdf_path} -> {ref_pdf_path}")
|
||||
|
||||
# Lösche diff-PDF
|
||||
if diff_pdf_path.exists():
|
||||
diff_pdf_path.unlink()
|
||||
logger.debug(f"Diff-PDF gelöscht: {diff_pdf_path}")
|
||||
|
||||
# Diff-Icon beim XML-Knoten entfernen
|
||||
# WICHTIG: xml_item_map verwendet relative Pfade, nicht absolute!
|
||||
xml_relative_path = xml_file_path.relative_to(self.project.project_dir)
|
||||
map_key = f"{xml_relative_path}|{xsl_id_str}"
|
||||
if map_key in self.xml_item_map:
|
||||
tree_item = self.xml_item_map[map_key]
|
||||
# Entferne Icon-Widget aus Spalte 2
|
||||
tree_item.setData(2, Qt.ItemDataRole.UserRole, None)
|
||||
self.ui.treeWidget.setItemWidget(tree_item, 2, None)
|
||||
|
||||
logger.info(f"Änderungen akzeptiert für: {pdf_basename}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Akzeptieren von {pdf_basename}: {e}")
|
||||
return False
|
||||
|
||||
def _accept_all_changes_under_node(self, item: QTreeWidgetItem):
|
||||
"""
|
||||
Akzeptiert alle Diff-PDFs unter einem TreeNode oder XslFile.
|
||||
Leert den Viewer, falls eine der akzeptierten PDFs gerade angezeigt wird.
|
||||
|
||||
Args:
|
||||
item: Das TreeWidgetItem des TreeNode oder XslFile
|
||||
"""
|
||||
try:
|
||||
# Hole Node-Objekt
|
||||
node_obj = item.data(0, Qt.ItemDataRole.UserRole)
|
||||
if not node_obj:
|
||||
logger.warning("Kein Node-Objekt gefunden")
|
||||
return
|
||||
|
||||
# Sammle alle Diff-PDFs unter diesem Knoten
|
||||
diff_pdfs = self._collect_all_diff_pdfs_under_node(node_obj, item)
|
||||
|
||||
if not diff_pdfs:
|
||||
QMessageBox.information(self, "Info", "Keine Diff-PDFs unter diesem Knoten gefunden")
|
||||
return
|
||||
|
||||
# Frage Benutzer um Bestätigung
|
||||
node_name = node_obj.bez if hasattr(node_obj, "bez") else "Unbekannt"
|
||||
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"Alle Änderungen übernehmen",
|
||||
f"Möchten Sie wirklich alle {len(diff_pdfs)} Änderungen unter '{node_name}' übernehmen?\n\n"
|
||||
f"Dies verschiebt alle new-PDFs nach ref und löscht die diff-PDFs.",
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
|
||||
if reply != QMessageBox.StandardButton.Yes:
|
||||
return
|
||||
|
||||
# Merke, ob eine der zu akzeptierenden PDFs gerade im Viewer angezeigt wird
|
||||
viewer_needs_clearing = False
|
||||
if self.current_diff_xml_path and self.current_diff_xsl_id:
|
||||
for xml_file_path, xsl_id_str, diff_pdf_path, ref_pdf_path, new_pdf_path in diff_pdfs:
|
||||
if xml_file_path == self.current_diff_xml_path and xsl_id_str == self.current_diff_xsl_id:
|
||||
viewer_needs_clearing = True
|
||||
break
|
||||
|
||||
# Akzeptiere alle Diff-PDFs
|
||||
successful_count = 0
|
||||
for xml_file_path, xsl_id_str, diff_pdf_path, ref_pdf_path, new_pdf_path in diff_pdfs:
|
||||
if self._accept_single_diff_pdf(xml_file_path, xsl_id_str, diff_pdf_path, ref_pdf_path, new_pdf_path):
|
||||
successful_count += 1
|
||||
|
||||
# Aktualisiere Diff-PDF-Anzahl auf übergeordneten Ebenen
|
||||
self._update_all_diff_pdf_counts()
|
||||
|
||||
# Leere Viewer falls nötig
|
||||
if viewer_needs_clearing:
|
||||
self._clear_pdf_viewer()
|
||||
|
||||
# Zeige Erfolgsmeldung
|
||||
if successful_count == len(diff_pdfs):
|
||||
logger.info(f"Alle {successful_count} Änderungen erfolgreich übernommen")
|
||||
QMessageBox.information(
|
||||
self, "Erfolg", f"Alle {successful_count} Änderungen wurden erfolgreich übernommen"
|
||||
)
|
||||
else:
|
||||
failed_count = len(diff_pdfs) - successful_count
|
||||
logger.warning(f"{successful_count}/{len(diff_pdfs)} Änderungen übernommen, {failed_count} fehlgeschlagen")
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"Teilweise erfolgreich",
|
||||
f"{successful_count} von {len(diff_pdfs)} Änderungen übernommen\n{failed_count} fehlgeschlagen",
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Übernehmen aller Änderungen: {e}")
|
||||
QMessageBox.critical(self, "Fehler", f"Fehler beim Übernehmen der Änderungen:\n{str(e)}")
|
||||
|
||||
def _clear_pdf_viewer(self):
|
||||
"""Leert den PDF-Viewer und alle Thumbnails."""
|
||||
# Entferne Widgets aus Layouts
|
||||
|
||||
Reference in New Issue
Block a user