Feature: Automatische PDF-Bereinigung beim Entfernen von XML-Dateien

Implementiert intelligente Löschlogik die zugehörige PDF-Dateien (new/ref/diff) automatisch entfernt wenn eine XML-Datei aus einem XSL-Knoten gelöscht wird. PDFs werden nur gelöscht wenn die XML+XSL-Kombination nicht mehr anderswo im Projektbaum verwendet wird.
This commit is contained in:
2026-02-07 19:47:02 +01:00
parent 0fd0703dbb
commit 9e58b3a9a1
+106
View File
@@ -1031,6 +1031,23 @@ class TreeManagerMixin:
logger.info(f"XML-Datei '{xml_filename}' aus XSL-Datei '{xsl_file_obj.bez}' entfernt") logger.info(f"XML-Datei '{xml_filename}' aus XSL-Datei '{xsl_file_obj.bez}' entfernt")
# Prüfe ob die XML+XSL-Kombination noch woanders verwendet wird
# Wenn nicht, lösche die zugehörigen PDF-Dateien
xsl_id = xsl_file_obj.id
is_combination_used_elsewhere = self._is_xml_xsl_combination_used_elsewhere(
xml_file_obj.xml, xsl_id, xsl_file_obj
)
if not is_combination_used_elsewhere:
# Lösche alle PDF-Dateien für diese XML+XSL-Kombination
deleted_pdfs = self._delete_pdf_files_for_xml_xsl_combination(xml_file_obj.xml, xsl_id)
if deleted_pdfs > 0:
logger.info(f"{deleted_pdfs} PDF-Datei(en) für '{xml_filename}' (XSL: {xsl_file_obj.bez}) gelöscht")
else:
logger.debug(
f"XML+XSL-Kombination '{xml_filename}' + XSL-ID {xsl_id} wird noch anderswo verwendet - PDFs nicht gelöscht"
)
# Frage ob die physische Datei auch gelöscht werden soll # Frage ob die physische Datei auch gelöscht werden soll
xml_file_path = Path(self.project.project_dir) / xml_file_obj.xml xml_file_path = Path(self.project.project_dir) / xml_file_obj.xml
if xml_file_path.exists(): if xml_file_path.exists():
@@ -1117,6 +1134,95 @@ class TreeManagerMixin:
return False return False
def _is_xml_xsl_combination_used_elsewhere(self, xml_path: Path, xsl_id: tuple, exclude_xsl_file) -> bool:
"""
Prüft ob eine XML+XSL-Kombination noch in anderen XSL-Dateien verwendet wird.
Args:
xml_path: Pfad zur XML-Datei (relativ)
xsl_id: Tuple der XSL-ID
exclude_xsl_file: XSL-Datei die ausgeschlossen werden soll
Returns:
bool: True wenn die Kombination noch anderswo verwendet wird
"""
try:
if not self.pdf_project or not self.pdf_project.nodes:
return False
return self._check_xml_xsl_combination_recursive(self.pdf_project.nodes, xml_path, xsl_id, exclude_xsl_file)
except Exception as e:
logger.error(f"Fehler beim Prüfen der XML+XSL-Kombination: {e}")
return True # Im Zweifelsfall annehmen, dass sie verwendet wird
def _check_xml_xsl_combination_recursive(self, nodes, xml_path: Path, xsl_id: tuple, exclude_xsl_file) -> bool:
"""
Prüft rekursiv ob eine XML+XSL-Kombination in den Nodes verwendet wird.
Args:
nodes: Liste der zu prüfenden Nodes
xml_path: Pfad zur XML-Datei (relativ)
xsl_id: Tuple der XSL-ID
exclude_xsl_file: XSL-Datei die ausgeschlossen werden soll
Returns:
bool: True wenn die Kombination gefunden wird
"""
for node in nodes:
if isinstance(node, XslFile) and node != exclude_xsl_file:
# Prüfe ob diese XSL-Datei die gleiche ID hat UND die XML-Datei verwendet
if node.id == xsl_id:
for xml_file in node.xmls:
if xml_file.xml == xml_path:
return True
elif isinstance(node, TreeNode) and node.children:
# Rekursiv in Knoten suchen
if self._check_xml_xsl_combination_recursive(node.children, xml_path, xsl_id, exclude_xsl_file):
return True
return False
def _delete_pdf_files_for_xml_xsl_combination(self, xml_path: Path, xsl_id: tuple) -> int:
"""
Löscht alle PDF-Dateien (new, ref, diff) für eine XML+XSL-Kombination.
Args:
xml_path: Pfad zur XML-Datei (relativ)
xsl_id: Tuple der XSL-ID
Returns:
int: Anzahl der gelöschten PDF-Dateien
"""
deleted_count = 0
try:
# Erzeuge den PDF-Dateinamen basierend auf XML und XSL-ID
base_name = xml_path.stem
xsl_id_str = "_".join(str(x) for x in xsl_id)
pdf_filename = f"{base_name}_xsl_{xsl_id_str}.pdf"
# Lösche PDFs in allen drei Verzeichnissen
pdf_dirs = ["new", "ref", "diff"]
for dir_name in pdf_dirs:
pdf_path = self.project.project_dir / dir_name / pdf_filename
if pdf_path.exists():
try:
pdf_path.unlink()
logger.info(f"PDF-Datei gelöscht: {pdf_path}")
deleted_count += 1
except Exception as e:
logger.warning(f"Konnte PDF-Datei nicht löschen: {pdf_path} - {e}")
if deleted_count > 0:
logger.info(f"{deleted_count} PDF-Datei(en) für {xml_path.name} (XSL-ID: {xsl_id}) gelöscht")
else:
logger.debug(f"Keine PDF-Dateien für {xml_path.name} (XSL-ID: {xsl_id}) gefunden")
except Exception as e:
logger.error(f"Fehler beim Löschen der PDF-Dateien: {e}")
return deleted_count
# Kontextmenü-Aktionen für Root-Elemente (Unbekannter Typ) # Kontextmenü-Aktionen für Root-Elemente (Unbekannter Typ)
def _add_root_tree_node(self): def _add_root_tree_node(self):
"""Fügt einen neuen TreeNode als Root-Element hinzu.""" """Fügt einen neuen TreeNode als Root-Element hinzu."""