Feat: Suchfilter für TreeNodes und XSL-Dateien im Hauptfenster (v1.3.0)
Neues Suchfeld über dem Baum filtert Knoten und XSL-Dateien per case-insensitive Textsuche. Übergeordnete Knoten bleiben bei Kind-Treffern sichtbar und werden automatisch expandiert. Der gespeicherte Expand-Status wird beim Leeren der Suche wiederhergestellt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -484,9 +484,112 @@ class TreeManagerMixin:
|
||||
# Stelle Expand-Status wieder her
|
||||
self._restore_expanded_state()
|
||||
|
||||
# Suchfilter erneut anwenden, falls aktiv
|
||||
search_text = self.ui.searchEdit.text()
|
||||
if search_text:
|
||||
self._filter_tree(search_text)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Laden der Nodes in TreeWidget: {e}")
|
||||
|
||||
def _filter_tree(self, text: str):
|
||||
"""
|
||||
Filtert das TreeWidget nach TreeNode- und XslFile-Bezeichnungen.
|
||||
|
||||
Sichtbarkeitsregeln:
|
||||
- TreeNode/XslFile wird angezeigt, wenn .bez den Suchtext enthält (case-insensitive)
|
||||
- Wenn ein Kind matcht, bleibt der übergeordnete Knoten sichtbar und wird expandiert
|
||||
- Wenn ein TreeNode matcht, bleiben alle Kinder sichtbar
|
||||
- XmlFile-Items folgen der Sichtbarkeit ihres Eltern-XslFile
|
||||
- Leerer Suchtext blendet alles ein und stellt den Expand-Status wieder her
|
||||
|
||||
Args:
|
||||
text: Suchtext für den Filter
|
||||
"""
|
||||
search_lower = text.strip().lower()
|
||||
|
||||
if not search_lower:
|
||||
# Alles einblenden, kollabieren und gespeicherten Expand-Status wiederherstellen
|
||||
for i in range(self.ui.treeWidget.topLevelItemCount()):
|
||||
item = self.ui.treeWidget.topLevelItem(i)
|
||||
self._reset_filter_recursive(item)
|
||||
self._restore_expanded_state()
|
||||
logger.debug("Baumfilter zurückgesetzt")
|
||||
return
|
||||
|
||||
for i in range(self.ui.treeWidget.topLevelItemCount()):
|
||||
item = self.ui.treeWidget.topLevelItem(i)
|
||||
self._apply_filter_recursive(item, search_lower)
|
||||
|
||||
logger.debug(f"Baumfilter angewendet: '{text}'")
|
||||
|
||||
def _apply_filter_recursive(self, item: QTreeWidgetItem, search_lower: str) -> bool:
|
||||
"""
|
||||
Wendet den Suchfilter rekursiv auf ein Item und seine Kinder an.
|
||||
|
||||
Args:
|
||||
item: Das zu prüfende TreeWidgetItem
|
||||
search_lower: Suchtext in Kleinbuchstaben
|
||||
|
||||
Returns:
|
||||
bool: True wenn dieses Item oder ein Kind den Suchtext enthält
|
||||
"""
|
||||
node = item.data(0, Qt.ItemDataRole.UserRole)
|
||||
|
||||
# Prüfe ob dieses Item selbst matcht (nur TreeNode und XslFile haben .bez)
|
||||
self_matches = False
|
||||
if isinstance(node, (TreeNode, XslFile)):
|
||||
bez_text = str(node.bez).lower() if node.bez else ""
|
||||
self_matches = search_lower in bez_text
|
||||
|
||||
# Wenn dieses Item matcht, sichtbar machen und alle Kinder einblenden
|
||||
if self_matches:
|
||||
item.setHidden(False)
|
||||
self._set_item_visible_recursive(item, True)
|
||||
item.setExpanded(True)
|
||||
return True
|
||||
|
||||
# Prüfe Kinder rekursiv
|
||||
any_child_matches = False
|
||||
for child_idx in range(item.childCount()):
|
||||
child = item.child(child_idx)
|
||||
if self._apply_filter_recursive(child, search_lower):
|
||||
any_child_matches = True
|
||||
|
||||
# Item sichtbar lassen wenn ein Kind matcht, expandieren für Übersicht
|
||||
if any_child_matches:
|
||||
item.setHidden(False)
|
||||
item.setExpanded(True)
|
||||
else:
|
||||
item.setHidden(True)
|
||||
|
||||
return any_child_matches
|
||||
|
||||
def _set_item_visible_recursive(self, item: QTreeWidgetItem, visible: bool):
|
||||
"""
|
||||
Setzt die Sichtbarkeit eines Items und aller seiner Kinder.
|
||||
|
||||
Args:
|
||||
item: Das TreeWidgetItem
|
||||
visible: Ob das Item sichtbar sein soll
|
||||
"""
|
||||
item.setHidden(not visible)
|
||||
for child_idx in range(item.childCount()):
|
||||
self._set_item_visible_recursive(item.child(child_idx), visible)
|
||||
|
||||
def _reset_filter_recursive(self, item: QTreeWidgetItem):
|
||||
"""
|
||||
Blendet ein Item und alle Kinder ein und kollabiert sie.
|
||||
Kombiniert Sichtbarkeit und Expand-Reset in einem Durchlauf.
|
||||
|
||||
Args:
|
||||
item: Das TreeWidgetItem
|
||||
"""
|
||||
item.setHidden(False)
|
||||
item.setExpanded(False)
|
||||
for child_idx in range(item.childCount()):
|
||||
self._reset_filter_recursive(item.child(child_idx))
|
||||
|
||||
def _create_tree_item_from_node(self, node):
|
||||
"""
|
||||
Erstellt ein QTreeWidgetItem aus einem TreeNode oder XslFile.
|
||||
@@ -1622,8 +1725,10 @@ class TreeManagerMixin:
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
# Speichere Expand-Status der Tree-Knoten vor dem Schreiben
|
||||
self._save_expanded_state()
|
||||
# Expand-Status nur speichern, wenn kein Suchfilter aktiv ist
|
||||
# (sonst werden die durch die Suche erzwungenen Expansionen gespeichert)
|
||||
if not self.ui.searchEdit.text().strip():
|
||||
self._save_expanded_state()
|
||||
|
||||
# Speichere in project.yaml im Projekt-Verzeichnis
|
||||
self.pdf_project.writeSettings(project_dir=self.project.project_dir)
|
||||
|
||||
Reference in New Issue
Block a user