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:
@@ -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):
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user