Feature: Expand-Status von Tree-Knoten bei jedem Speichern persistent sichern

- ProjectData um optionales Feld 'expanded_nodes' erweitert (abwärtskompatibel)
- _save_project_settings() speichert nun automatisch den Expand-Status
- Expand-Status wird bei allen Speicheroperationen gesichert:
  * Beim Bearbeiten von TreeNodes und XslFiles
  * Bei Drag&Drop-Operationen im Tree
  * Bei Hash-Berechnungen für XML-Dateien
  * Beim Laden von Daten aus der Datenbank
  * Beim Beenden der Anwendung
- Beim Laden eines Projekts werden aufgeklappte Knoten wiederhergestellt
- Rekursive Speicherung und Wiederherstellung für TreeNode und XslFile
- Umfassendes Logging für Debugging und Fehlerbehandlung
This commit is contained in:
2026-02-01 15:44:55 +01:00
parent 0f14418749
commit e6b2743677
3 changed files with 113 additions and 0 deletions
+2
View File
@@ -75,6 +75,7 @@ class SSLMode(str, Enum):
class XsltVersion(str, Enum): class XsltVersion(str, Enum):
"""XSLT-Version für Saxon-Transformationen.""" """XSLT-Version für Saxon-Transformationen."""
XSLT_1_0 = "1.0" # JAXP API (nur XSLT 1.0) XSLT_1_0 = "1.0" # JAXP API (nur XSLT 1.0)
XSLT_2_0_3_0 = "2.0/3.0" # s9api (XSLT 2.0 und 3.0) XSLT_2_0_3_0 = "2.0/3.0" # s9api (XSLT 2.0 und 3.0)
@@ -216,6 +217,7 @@ class ProjectData(BaseModel):
""" """
nodes: list[TreeNode] = [] nodes: list[TreeNode] = []
expanded_nodes: list[tuple] | None = None # Optional: IDs der aufgeklappten Knoten (TreeNode und XslFile)
@classmethod @classmethod
def readSettings(cls, project_dir: Path): def readSettings(cls, project_dir: Path):
+8
View File
@@ -964,6 +964,14 @@ class MainWindow(
# UI-Zustände speichern # UI-Zustände speichern
self._save_ui_state() self._save_ui_state()
# Speichere Projekt-Einstellungen inkl. Expand-Status (falls Projekt geladen)
if hasattr(self, "project") and self.project and hasattr(self, "pdf_project") and self.pdf_project:
try:
self._save_project_settings()
logger.info("Projekt-Einstellungen beim Beenden gespeichert")
except Exception as e:
logger.error(f"Fehler beim Speichern der Projekt-Einstellungen: {e}")
# Stoppe Hash-Berechnungs-Thread falls noch aktiv # Stoppe Hash-Berechnungs-Thread falls noch aktiv
if ( if (
hasattr(self, "hash_calculator_thread") hasattr(self, "hash_calculator_thread")
+103
View File
@@ -519,6 +519,9 @@ class TreeManagerMixin:
self._update_all_diff_pdf_counts() self._update_all_diff_pdf_counts()
self._update_diff_icons_for_existing_pdfs() self._update_diff_icons_for_existing_pdfs()
# Stelle Expand-Status wieder her
self._restore_expanded_state()
except Exception as e: except Exception as e:
logger.error(f"Fehler beim Laden der Nodes in TreeWidget: {e}") logger.error(f"Fehler beim Laden der Nodes in TreeWidget: {e}")
@@ -1177,6 +1180,9 @@ class TreeManagerMixin:
start_time = time.time() start_time = time.time()
# Speichere Expand-Status der Tree-Knoten vor dem Schreiben
self._save_expanded_state()
# Speichere in project.yaml im Projekt-Verzeichnis # Speichere in project.yaml im Projekt-Verzeichnis
self.pdf_project.writeSettings(project_dir=self.project.project_dir) self.pdf_project.writeSettings(project_dir=self.project.project_dir)
@@ -1186,3 +1192,100 @@ class TreeManagerMixin:
except Exception as e: except Exception as e:
logger.error(f"Fehler beim Speichern der Projekt-Einstellungen: {e}") logger.error(f"Fehler beim Speichern der Projekt-Einstellungen: {e}")
raise raise
def _save_expanded_state(self):
"""
Speichert die IDs aller aufgeklappten Knoten (TreeNode und XslFile) in den Projekteinstellungen.
"""
if not hasattr(self, "pdf_project") or not self.pdf_project:
logger.warning("Keine Projekt-Einstellungen zum Speichern des Expand-Status")
return
try:
expanded_node_ids = []
# Durchlaufe alle Top-Level-Items
root_count = self.ui.treeWidget.topLevelItemCount()
for i in range(root_count):
item = self.ui.treeWidget.topLevelItem(i)
self._collect_expanded_items(item, expanded_node_ids)
# Speichere in Projekteinstellungen
self.pdf_project.expanded_nodes = expanded_node_ids
logger.info(f"Expand-Status gespeichert: {len(expanded_node_ids)} aufgeklappte Knoten")
logger.debug(f"Aufgeklappte Knoten-IDs: {expanded_node_ids}")
except Exception as e:
logger.error(f"Fehler beim Speichern des Expand-Status: {e}")
def _collect_expanded_items(self, item: QTreeWidgetItem, expanded_ids: list):
"""
Sammelt rekursiv die IDs aller aufgeklappten Items.
Args:
item: Das zu prüfende TreeWidgetItem
expanded_ids: Liste zum Sammeln der IDs
"""
# Hole Node-Objekt
node = item.data(0, Qt.ItemDataRole.UserRole)
if not node:
return
# Wenn Item aufgeklappt ist, speichere ID
if item.isExpanded() and hasattr(node, "id"):
expanded_ids.append(node.id)
# Rekursiv alle Kinder durchlaufen
child_count = item.childCount()
for i in range(child_count):
child_item = item.child(i)
self._collect_expanded_items(child_item, expanded_ids)
def _restore_expanded_state(self):
"""
Stellt den Expand-Status aller Knoten aus den Projekteinstellungen wieder her.
"""
if not hasattr(self, "pdf_project") or not self.pdf_project:
logger.warning("Keine Projekt-Einstellungen zum Wiederherstellen des Expand-Status")
return
if not self.pdf_project.expanded_nodes:
logger.debug("Keine gespeicherten Expand-Status-Informationen vorhanden")
return
try:
expanded_node_ids = set(self.pdf_project.expanded_nodes)
logger.info(f"Stelle Expand-Status wieder her: {len(expanded_node_ids)} Knoten")
logger.debug(f"Aufzuklappende Knoten-IDs: {list(expanded_node_ids)}")
# Durchlaufe alle Top-Level-Items
root_count = self.ui.treeWidget.topLevelItemCount()
for i in range(root_count):
item = self.ui.treeWidget.topLevelItem(i)
self._expand_items_by_id(item, expanded_node_ids)
except Exception as e:
logger.error(f"Fehler beim Wiederherstellen des Expand-Status: {e}")
def _expand_items_by_id(self, item: QTreeWidgetItem, expanded_ids: set):
"""
Klappt Items rekursiv auf, wenn ihre ID in expanded_ids enthalten ist.
Args:
item: Das zu prüfende TreeWidgetItem
expanded_ids: Set der IDs, die aufgeklappt werden sollen
"""
# Hole Node-Objekt
node = item.data(0, Qt.ItemDataRole.UserRole)
if not node or not hasattr(node, "id"):
return
# Wenn ID in der Liste ist, klappe Item auf
if node.id in expanded_ids:
item.setExpanded(True)
# Rekursiv alle Kinder durchlaufen
child_count = item.childCount()
for i in range(child_count):
child_item = item.child(i)
self._expand_items_by_id(child_item, expanded_ids)