Files
info 4733ea6b82 chore: OpenWiki-Dokumentation einrichten, AGENTS.md ergänzen
Fügt OpenWiki-Setup (Workflow, Seiten, CLAUDE.md-Verweis) und AGENTS.md
hinzu, damit wiederkehrende Code-Dokumentation automatisch gepflegt wird.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 14:22:57 +02:00

6.1 KiB
Raw Permalink Blame History

type, title, description, tags
type title description tags
Architecture Overview Architektur-Überblick PySide6-Mixin-Architektur, UI-Pattern (generierte UI vs. Implementierung), Thread-Modell und Konfigurationssystem von DocuMentor.
architektur
pyside6
mixins
threads
konfiguration

Architektur-Überblick

Technologie-Stack

Schicht Technologie Zweck
GUI PySide6 (Qt 6) Native Desktop-Oberfläche
Konfiguration Pydantic + pydantic-settings Typsichere Datenmodelle, JSON/YAML-Persistenz
Datenverarbeitung Polars + ConnectorX PostgreSQL-Abfragen, DataFrames
XSL-Parsing lxml XSL-Abhängigkeitsgraph
Hashing hashlib (blake2b) Duplikatserkennung
Build PyInstaller + WiX/Inno Setup Windows-Distribution
Paketverwaltung uv Dependency-Management

Einstiegspunkt

Die Anwendung startet in src/main.py:

  1. Logging konfigurieren (Datei + Konsole, 24h Auto-Cleanup)
  2. QApplication erstellen, App-Icon setzen
  3. MainWindow instanziieren und anzeigen
  4. Bei fehlender Tool-Konfiguration AppSettingsDlg modal öffnen
  5. Qt-Event-Loop starten

MainWindow Mixin-Architektur

MainWindow (src/ui/MainWindow.py) ist die zentrale Klasse und erbt von mehreren Mixins, um Funktionalität zu trennen:

MainWindow
├── IconRefreshMixin          (src/icons.py)          Theme-Wechsel → Icons neu einfärben
├── QMainWindow               (PySide6)               Qt-Basisfenster
├── TreeManagerMixin          (mixins/tree_manager.py)     Baum-Widget, Kontextmenüs, Node-Operationen
├── PdfViewerMixin            (mixins/pdf_viewer.py)       PDF-Rendering, Alpha-Blending, Zoom
├── WorkerPoolMixin           (mixins/worker_pool.py)      Saxon/FOP Worker-Pool Lebenszyklus
├── DatabaseMixin             (mixins/database.py)         PostgreSQL-Abfragen, Obsolete-Erkennung
├── DragDropMixin             (mixins/drag_drop.py)        Drag-and-Drop für XML-Dateien
├── HashCalculationMixin      (mixins/hash_calculation.py)  blake2b-Hash-Berechnung, Duplikatserkennung
└── TransformationMixin       (mixins/transformation.py)    XSL-Transformations-Ausführung

Jedes Mixin erwartet bestimmte Attribute (self.ui, self.project, self.pdf_project) und Methoden von anderen Mixins. Die Mixins sind in src/ui/mixins/__init__.py gebündelt.

Mixin-Abhängigkeiten

TransformationMixin benötigt Methoden aus WorkerPoolMixin (_initialize_saxon_worker_pool, _shutdown_saxon_worker_pool) und TreeManagerMixin (_collect_parent_params, _create_centered_progress_bar). HashCalculationMixin und DragDropMixin benötigen _save_project_settings() und _load_nodes_to_tree() von MainWindow.

UI-Pattern: Generierte UI vs. Implementierung

DocuMentor folgt einem strikten PySide6-Pattern:

  1. UI-Definitionsdateien (*_ui.py, z.B. MainWinddow_ui.py): Aus .ui-Dateien von einer VS Code Extension generiert. Enthalten nur Widget-Layout-Definitionen als Klasse (Ui_MainWindow). Nicht manuell bearbeiten.

  2. Implementierungsdateien (ohne _ui-Suffix, z.B. MainWindow.py): Importieren die UI-Klasse, instanziieren sie als self.ui und fügen Business-Logik hinzu.

class JavaVmConfigDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_JavaVmConfigDialog()
        self.ui.setupUi(self)
        # Signale NACH setupUi() verbinden
        self.ui.browseButton.clicked.connect(self._browse_file)

Regeln:

  • UI-Klassen niemals direkt erben, nur als self.ui-Member verwenden
  • Alle Widgets über self.ui.widgetName zugreifen
  • Signal-Verbindungen immer nach setupUi()

Thread-Modell

Asynchrone Operationen verwenden QThread-Subklassen aus src/ui/threads.py:

Thread-Klasse Zweck Signale
XmlHashCalculatorThread blake2b-Hash-Berechnung für XML-Dateien hash_calculated, calculation_finished, error_occurred
XmlBatchProcessingThread Batch-Verarbeitung: Hash + Duplikatserkennung + Dateikopieren progress_update, file_processed, processing_finished
TransformationThread Ausführung der XSL-Transformations-Pipeline Fortschritts- und Abschluss-Signale
DatabaseQueryThread Asynchrone PostgreSQL-Abfragen (in mixins/database.py) query_completed (DataFrame), query_failed

Wichtig: Threads immer mit .start() starten, nie .run() direkt aufrufen.

Konfigurationssystem

Die Konfiguration ist in Datenmodelle & Konfiguration detailliert beschrieben. Zusammenfassung:

  • AppSettings (src/conf.py): Globales Singleton (app_settings), gespeichert als JSON. Enthält Tool-Listen, UI-Zustand, Worker-Pool-Einstellungen.
  • ProjectData (src/conf.py): Projektspezifisch, gespeichert als project.yaml im Projektverzeichnis. Enthält die Baumstruktur (TreeNode → XslFile → XmlFile).

Icon-System

Icons werden über src/icons.py verwaltet:

  • Feather Icons aus dem Qt-Ressource-System (:/icons/<name>.svg)
  • Einmaliges Rendern bei 64px, Qt skaliert für 16/24/32px
  • Theme-reactiv: Färbung nach QPalette.WindowText, Cache-Schlüssel enthält Theme-Farbe
  • IconRefreshMixin erlaubt Theme-Wechsel zur Laufzeit ohne manuellen Cache-Reset

XSL-Abhängigkeitsgraph

src/xsl_dependencies.py (XslDependencyGraph) parst XSL-Dateien mit lxml und baut einen Abhängigkeitsgraph für <xsl:import/> und <xsl:include/>. Der Graph wird über Datei-mtime automatisch invalidiert. Visualisiert wird er im Dialog src/ui/XslDependencyDialog.py via vis.js.

Der Abhängigkeitsgraph ist auch für die Transformations-Pipeline relevant: wenn eine importierte XSL-Datei neuer ist als das Output-PDF, gilt die Transformation als veraltet.

Obsolete-Erkennung

src/obsolete_detector.py enthält reine Analyselogik (ohne Qt-Abhängigkeit) zum Finden veralteter XslFile-Einträge nach Datenbank-Import. Wird vom DatabaseMixin nach dem DB-Laden aufgerufen und im ObsoleteEntriesDialog (src/ui/ObsoleteEntriesDialog.py) angezeigt.