Feat: XSL-Abhängigkeitsgraph für import/include-Erkennung in Transformations-Pipeline
is_up_to_date() prüft nun auch transitiv importierte/inkludierte XSL-Dateien. Abhängigkeiten werden per Tooltip und Kontextmenü-Aktion im TreeWidget angezeigt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -389,6 +389,13 @@ class TreeManagerMixin:
|
||||
|
||||
menu.addSeparator()
|
||||
|
||||
action_deps = QAction("Abhängigkeiten anzeigen", self)
|
||||
action_deps.setIcon(QIcon(QIcon.fromTheme("view-list-tree")))
|
||||
action_deps.triggered.connect(lambda: self._show_xsl_dependencies(item))
|
||||
menu.addAction(action_deps)
|
||||
|
||||
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))
|
||||
@@ -567,6 +574,9 @@ class TreeManagerMixin:
|
||||
item.setDisabled(True)
|
||||
item.setToolTip(0, f"XSL-Datei nicht gefunden: {xsl_file_abs}")
|
||||
logger.warning(f"XSL-Datei nicht vorhanden: {xsl_file_abs}")
|
||||
else:
|
||||
# Tooltip mit Abhängigkeiten (import/include) setzen
|
||||
self._set_xsl_dependency_tooltip(item, xsl_file_abs)
|
||||
|
||||
# Lade XML-Dateien als Knoten
|
||||
if node.xmls:
|
||||
@@ -1189,6 +1199,105 @@ class TreeManagerMixin:
|
||||
logger.error(error_msg)
|
||||
QMessageBox.critical(self, "Fehler", error_msg)
|
||||
|
||||
def _get_xsl_abs_path(self, xsl_file_obj: XslFile) -> Path | None:
|
||||
"""
|
||||
Ermittelt den absoluten Pfad einer XSL-Datei anhand der Projekt-Konfiguration.
|
||||
|
||||
Args:
|
||||
xsl_file_obj: Das XslFile-Objekt
|
||||
|
||||
Returns:
|
||||
Absoluter Pfad oder None wenn nicht ermittelbar
|
||||
"""
|
||||
if not hasattr(self, "project") or not self.project:
|
||||
return None
|
||||
|
||||
from conf import app_settings
|
||||
|
||||
xsl_dir = next((xd for xd in app_settings.xsl_dirs if xd.id == self.project.xsl_dir_id), None)
|
||||
if not xsl_dir:
|
||||
return None
|
||||
|
||||
return xsl_dir.path_to_root_dir / xsl_file_obj.xsl_file
|
||||
|
||||
def _ensure_xsl_dependency_graph(self):
|
||||
"""Stellt sicher, dass der XSL-Abhängigkeitsgraph initialisiert ist."""
|
||||
if not hasattr(self, "xsl_dependency_graph") or self.xsl_dependency_graph is None:
|
||||
from xsl_dependencies import XslDependencyGraph
|
||||
|
||||
self.xsl_dependency_graph = XslDependencyGraph()
|
||||
|
||||
def _set_xsl_dependency_tooltip(self, item: QTreeWidgetItem, xsl_file_abs: Path):
|
||||
"""
|
||||
Setzt einen Tooltip mit den Abhängigkeiten (import/include) einer XSL-Datei.
|
||||
|
||||
Args:
|
||||
item: Das TreeWidgetItem der XSL-Datei
|
||||
xsl_file_abs: Absoluter Pfad zur XSL-Datei
|
||||
"""
|
||||
self._ensure_xsl_dependency_graph()
|
||||
|
||||
deps = self.xsl_dependency_graph.get_dependencies(xsl_file_abs)
|
||||
if not deps:
|
||||
item.setToolTip(0, f"{xsl_file_abs.name}\nKeine Abhängigkeiten (import/include)")
|
||||
return
|
||||
|
||||
# Sortierte Liste der Abhängigkeiten (nur Dateinamen)
|
||||
dep_names = sorted(dep.name for dep in deps)
|
||||
dep_list = "\n".join(f" - {name}" for name in dep_names)
|
||||
tooltip = f"{xsl_file_abs.name}\n{len(deps)} Abhängigkeit(en):\n{dep_list}"
|
||||
item.setToolTip(0, tooltip)
|
||||
|
||||
def _show_xsl_dependencies(self, item: QTreeWidgetItem):
|
||||
"""
|
||||
Zeigt einen Dialog mit den Abhängigkeiten einer XSL-Datei.
|
||||
|
||||
Args:
|
||||
item: Das TreeWidgetItem der XSL-Datei
|
||||
"""
|
||||
xsl_file_obj = item.data(0, Qt.ItemDataRole.UserRole)
|
||||
if not isinstance(xsl_file_obj, XslFile):
|
||||
return
|
||||
|
||||
xsl_file_abs = self._get_xsl_abs_path(xsl_file_obj)
|
||||
if not xsl_file_abs or not xsl_file_abs.exists():
|
||||
QMessageBox.warning(self, "Fehler", f"XSL-Datei nicht gefunden: {xsl_file_abs}")
|
||||
return
|
||||
|
||||
self._ensure_xsl_dependency_graph()
|
||||
deps = self.xsl_dependency_graph.get_dependencies(xsl_file_abs)
|
||||
|
||||
if not deps:
|
||||
QMessageBox.information(
|
||||
self,
|
||||
f"Abhängigkeiten: {xsl_file_obj.bez}",
|
||||
f"Die XSL-Datei '{xsl_file_abs.name}' hat keine Abhängigkeiten (import/include).",
|
||||
)
|
||||
return
|
||||
|
||||
# Sortierte Liste mit relativen Pfaden (relativ zum XSL-Verzeichnis)
|
||||
xsl_root = xsl_file_abs.parent
|
||||
from conf import app_settings
|
||||
|
||||
xsl_dir = next((xd for xd in app_settings.xsl_dirs if xd.id == self.project.xsl_dir_id), None)
|
||||
if xsl_dir:
|
||||
xsl_root = xsl_dir.path_to_root_dir
|
||||
|
||||
dep_lines = []
|
||||
for dep in sorted(deps, key=lambda p: p.name):
|
||||
try:
|
||||
rel_path = dep.relative_to(xsl_root)
|
||||
except ValueError:
|
||||
rel_path = dep.name
|
||||
dep_lines.append(f" - {rel_path}")
|
||||
|
||||
dep_text = "\n".join(dep_lines)
|
||||
QMessageBox.information(
|
||||
self,
|
||||
f"Abhängigkeiten: {xsl_file_obj.bez}",
|
||||
f"Die XSL-Datei '{xsl_file_abs.name}' importiert/inkludiert {len(deps)} Datei(en):\n\n{dep_text}",
|
||||
)
|
||||
|
||||
# Kontextmenü-Aktionen für XmlFile
|
||||
def _edit_xml_file(self, item):
|
||||
"""Bearbeitet eine XML-Datei."""
|
||||
|
||||
Reference in New Issue
Block a user