# V2.9 – Integrierte PDF-Vorschau und Dateinamen-Bearbeitung **Status:** Freigegeben **Erstellt:** 2026-04-24 **Überarbeitet:** 2026-04-24 (nach zwei ChatGPT-Reviews, finale Version) **Autor:** Marcus (mit Claude als Mentor) --- ## Ziel V2.9 erweitert den Tab „Verarbeitungslauf" um zwei eng verzahnte Funktionen: 1. **Integrierte PDF-Vorschau** – beim Anklicken einer Zeile wird die erste Seite der Quelldatei direkt im Detailbereich rechts gerendert (kein separates Fenster, kein zusätzlicher Klick) 2. **Editierbarer Dateiname** – der von der KI vorgeschlagene Dateiname kann direkt in der GUI korrigiert werden, bevor er als endgültig gilt Beide Funktionen zusammen ermöglichen einen natürlichen Review-Zyklus: **KI benennt → Benutzer schaut rein → Benutzer korrigiert bei Bedarf → fertig.** --- ## Hintergrund ### Bisheriger Zustand - Der Detailbereich rechts zeigt nur KI-Begründung als TextArea - Ob der vorgeschlagene Dateiname sinnvoll ist, kann der Benutzer nur anhand des KI-Reasonings beurteilen – den tatsächlichen Dokumentinhalt sieht er nicht - Der generierte Dateiname ist nach dem Lauf nicht mehr veränderbar - Die Spike-Implementierung (PDFViewFX + jai-imageio-jpeg2000 für JBIG2-Unterstützung) hat die technische Machbarkeit bereits bestätigt; der Spike-Code wird im Rahmen von V2.9 durch produktionsreifen Code ersetzt ### Motivation - Benutzer sollen schnell beurteilen können, ob der KI-Dateiname passt, ohne ein externes Programm öffnen zu müssen - Korrekturen sollen direkt in der Anwendung möglich sein – für nicht-technische Benutzer (z. B. Familienmitglieder) ist das eine wesentliche UX-Verbesserung - Die Anwendung wird vom reinen Batch-Prozessor zum assistierten Dokumenten-Review-Werkzeug weiterentwickelt --- ## Zielbild Nach Abschluss von V2.9 kann der Benutzer: 1. Eine Zeile in der Ergebnisliste anklicken 2. Sofort die erste Seite der zugehörigen **Quelldatei** als Vorschau sehen – ohne weiteren Klick, direkt im Detailbereich 3. Weitere Seiten bei Bedarf **auf Anfrage** laden (Lazy Rendering) 4. Den vorgeschlagenen Dateinamen **direkt in der GUI bearbeiten** und speichern 5. Den headless-Betrieb unverändert nutzen – V2.9 betrifft ausschließlich die GUI --- ## Layout-Änderung im Tab „Verarbeitungslauf" ### Bisheriges Layout ``` [ Fortschrittsbalken ] [ Ergebnistabelle (~75% Breite) | KI-Begründung (~25%) ] [ Buttons ] [ Statuszeile ] ``` ### Neues Layout ``` [ Fortschrittsbalken ] [ Ergebnistabelle (~60% Breite) | Detailbereich (~40% Breite) ] [ | KI-Begründung ] [ | Dateiname (editierbar) ] [ | PDF-Vorschau (Seite X/Y) ] [ Buttons ] [ Statuszeile ] ``` - Tabelle und Detailbereich sind durch einen **verschiebbaren Splitter** (SplitPane) getrennt – der Benutzer kann das Verhältnis anpassen - Standard-Split: 60% Tabelle / 40% Detailbereich - Der Detailbereich ist vertikal aufgebaut: KI-Begründung oben (kompakt), darunter Dateiname-Feld, darunter PDF-Vorschau (nimmt verfügbaren Restplatz) - Die PDF-Vorschau rendert die erste Seite **„fit to width"** – Seitenverhältnis wird beibehalten, die Seite füllt die verfügbare Panelbreite aus --- ## Fachliche Anforderungen ### PDF-Vorschau #### Grundverhalten - Beim Anklicken einer Zeile in der Ergebnisliste wird **automatisch** Seite 1 der zugehörigen **Quelldatei** gerendert und im Vorschaubereich angezeigt - Das Rendering erfolgt **asynchron im Hintergrund** – die GUI bleibt während des Ladens reaktionsfähig - Während des Renderings wird ein **Ladeindikator** (z. B. ProgressIndicator) angezeigt - Die Vorschau zeigt immer die **Quelldatei**, nicht die umbenannte Zieldatei #### Lazy Rendering und Seitennavigation - Beim ersten Anklicken einer Zeile wird **ausschließlich Seite 1** gerendert - Unterhalb der Vorschau wird die aktuelle Seite sowie die Gesamtseitenzahl angezeigt: „Seite 1 / 12" - Navigation: - Button **„Nächste Seite"** lädt und rendert die jeweils nächste Seite on-demand - Button **„Vorherige Seite"** lädt die vorherige Seite - Bereits gerenderte Seiten werden **gecacht** – ein erneuter Wechsel auf eine bereits gerenderte Seite erfordert kein erneutes Rendering - Der Cache wird geleert wenn eine andere Zeile angeklickt wird - Die Navigations-Buttons sind bei Seite 1 (Zurück) bzw. letzter Seite (Weiter) deaktiviert #### Abbruchverhalten bei schnellem Wechsel (Latest Preview Request Wins) - Es gilt das Prinzip **„latest preview request wins"**: Wenn während eines laufenden Renderings eine neue Vorschau-Anforderung eingeht – sei es durch Selektionswechsel oder durch Seitennavigation innerhalb derselben PDF – wird das laufende Rendering abgebrochen bzw. sein Ergebnis verworfen - Nur das Ergebnis der zuletzt angeforderten Vorschau darf im Vorschaubereich landen - Veraltete Render-Ergebnisse werden niemals angezeigt #### Fehlerfälle PDF-Vorschau | Situation | Verhalten | |---|---| | Quelldatei nicht mehr vorhanden | Meldung im Vorschaubereich: „Quelldatei nicht gefunden" | | PDF nicht lesbar / korrupt | Meldung im Vorschaubereich: „PDF konnte nicht geöffnet werden" | | PDF passwortgeschützt / verschlüsselt | Meldung im Vorschaubereich: „PDF ist passwortgeschützt und kann nicht angezeigt werden" | | JBIG2-Bilder nicht vollständig dekodierbar | Seite wird teilweise gerendert; kein Fehler-Abbruch; kein Hinweis nötig | | Kein Eintrag selektiert | Vorschaubereich zeigt neutralen Platzhaltertext | #### Technische Grundlage - Bibliothek: `com.dlsc.pdfviewfx:pdfviewfx` (bereits im Spike erfolgreich getestet) - Zusatzabhängigkeit für JBIG2 und erweiterte Bildformate: `com.github.jai-imageio:jai-imageio-jpeg2000` (bereits im Spike ergänzt) - Der Spike-Code (`PdfViewerSpike.java`, Spike-Button in `GuiBatchRunTab`) wird vollständig entfernt und durch die produktive Implementierung ersetzt - Rendering läuft in einem dedizierten Background-Thread (nicht im JavaFX Application Thread) --- ### Editierbarer Dateiname #### Zustandsmodell Der Dateiname-Bereich kennt drei klar getrennte Zustände: | Zustand | Beschreibung | |---|---| | **KI-Vorschlag** | Der von der KI ursprünglich generierte Name – unveränderlich in der DB gespeichert; dient als Referenz für „Zurücksetzen auf KI-Vorschlag" | | **Letzter gespeicherter Name** | Der zuletzt per „Dateiname übernehmen" bestätigte Name (= aktueller FS- und DB-Stand); ist nach dem Batch-Lauf zunächst identisch mit dem KI-Vorschlag | | **Aktuelle Eingabe** | Der aktuell im Textfeld eingetippte, noch nicht gespeicherte Wert | **Anzeige-Regel:** Im Textfeld wird beim Selektieren einer Zeile immer der **letzte gespeicherte Name** angezeigt – nicht der KI-Vorschlag. Wurde noch nie manuell gespeichert, sind beide identisch. **Dirty-State-Regel:** Dirty-State besteht wenn die **aktuelle Eingabe** vom **letzten gespeicherten Namen** abweicht. Der KI-Vorschlag ist keine Dirty-Basis. #### Anzeige - Unterhalb der KI-Begründung und oberhalb der PDF-Vorschau befindet sich ein Bereich „Dateiname" - Der Dateiname wird in einem **editierbaren Textfeld** (TextField) angezeigt - Das Textfeld zeigt den **letzten gespeicherten Namen** ohne Dateierweiterung (`.pdf` wird separat als nicht editierbares Label daneben angezeigt) - Solange kein Eintrag selektiert ist, ist das Textfeld leer und deaktiviert - Wenn das Textfeld vom letzten gespeicherten Namen abweicht (**Dirty State**), wird dies durch eine visuelle Markierung am Textfeld angezeigt (z. B. farbiger Rand) #### Tastatur- und Schaltflächen-Verhalten | Aktion | Verhalten | |---|---| | **Enter** im Textfeld | Löst „Dateiname übernehmen" aus (sofern Validierung grün) | | **Escape** im Textfeld | Verwirft aktuelle Eingabe; stellt **letzten gespeicherten Namen** wieder her | | **„Dateiname übernehmen"** | Startet die atomare Speicher-Transaktion | | **„Zurücksetzen auf KI-Vorschlag"** | Setzt das Textfeld auf den ursprünglichen KI-Vorschlag zurück (kein Speichern – nur Textfeld-Inhalt) | Hinweis: „Zurücksetzen auf KI-Vorschlag" und Escape haben **unterschiedliche Semantik**: Escape = zurück zum letzten gespeicherten Stand; „Zurücksetzen" = zurück zum KI-Ursprung. #### Speichern-Transaktion (Alles oder Nichts) Das Speichern eines geänderten Dateinamens ist eine **atomare Operation** bestehend aus zwei Persistenzschritten: 1. Zieldatei im Dateisystem umbenennen 2. Eintrag in der SQLite-DB aktualisieren **Schlägt Schritt 1 oder 2 fehl, wird die gesamte Aktion abgebrochen:** - Bereits durchgeführte Teilschritte werden zurückgerollt - Dateisystem und DB bleiben im vorherigen Zustand - Eine Fehlermeldung im Statusbereich informiert den Benutzer - Das Textfeld behält den eingegebenen Wert – der Benutzer kann es erneut versuchen Nach erfolgreicher Transaktion (Projektionsschritt, nicht Teil der Transaktion): - Tabellenspalte „Neuer Dateiname" wird aktualisiert - Erfolgsmeldung im Statusbereich Mögliche Fehlerursachen für Schritt 1: Datei-Lock durch andere Prozesse (Scanner, AV), fehlende Schreibrechte, Read-only-Dateisystem, Netzlaufwerk nicht erreichbar. #### Konfliktsemantik bei vorhandenem Zieldateinamen Existiert im Zielordner bereits eine Datei mit dem neu eingegebenen Namen, wird anhand des **Fingerprints** (SHA-256 des Dateiinhalts) entschieden: | Situation | Verhalten | |---|---| | **Gleicher Fingerprint** | Dateien sind inhaltlich identisch → keine Aktion; Meldung im Statusbereich: „Identische Datei bereits vorhanden – keine Umbenennung nötig"; weder FS noch DB werden geändert | | **Unterschiedlicher Fingerprint** | Warnung im Statusbereich; Dateiname im FS erhält automatisch ein Suffix `(1)`, `(2)` usw.; DB wird mit dem tatsächlichen neuen Namen inkl. Suffix aktualisiert | #### Validierung des Dateinamens Folgende Prüfungen erfolgen **live während der Eingabe**: | Prüfung | Verhalten bei Verletzung | |---|---| | Dateiname ist leer oder nur Leerzeichen | Speichern-Button deaktiviert, Hinweistext unterhalb des Feldes | | Führende oder abschließende Leerzeichen | Speichern-Button deaktiviert, Hinweistext | | Unerlaubte Zeichen (`\ / : * ? " < > \|`) | Speichern-Button deaktiviert, Hinweistext | | Reservierte Windows-Namen (`CON`, `PRN`, `AUX`, `NUL`, `COM1`–`COM9`, `LPT1`–`LPT9`) | Speichern-Button deaktiviert, Hinweistext | | Dateiname endet auf Punkt | Speichern-Button deaktiviert, Hinweistext | | Dateiname + Zielpfad + `.pdf` überschreitet 259 Zeichen | Speichern-Button deaktiviert, Hinweistext | Die 259-Zeichen-Grenze ist eine **bewusste Produktregel** für maximale Windows-Kompatibilität (Windows MAX_PATH = 260 Zeichen inkl. Null-Terminator). #### Zustände des Dateiname-Bereichs | Zeilenstatus | Verhalten | |---|---| | Kein Eintrag selektiert | Textfeld leer, deaktiviert | | Eintrag mit Status `DONE` (erfolgreich) | Textfeld editierbar, letzter gespeicherter Name vorausgefüllt | | Eintrag mit Status `FAILED_*` | Textfeld leer, deaktiviert (kein Dateiname vorhanden) | | Eintrag mit Status `SKIPPED` | Textfeld deaktiviert | | Lauf aktiv | Textfeld deaktiviert, alle Buttons deaktiviert | #### Verhalten bei fehlender Zieldatei Ist die Zieldatei zum Zeitpunkt des Speicherns nicht mehr im Zielordner vorhanden: - Schritt 1 der Transaktion schlägt fehl - Gemäß Alles-oder-Nichts-Prinzip: DB wird **nicht** aktualisiert - Fehlermeldung im Statusbereich: „Zieldatei nicht gefunden – Umbenennung nicht möglich" - Das Textfeld behält den eingegebenen Wert #### Verhalten bei ungespeicherten Änderungen (Dirty State) Ein Hinweisdialog erscheint, wenn der Benutzer mit aktivem Dirty-State eine der folgenden Aktionen ausführt: - Eine andere Zeile in der Ergebnistabelle anklicken - Den Tab wechseln (Konfiguration ↔ Verarbeitungslauf) - Die Anwendung schließen - Einen neuen Lauf starten Dialog-Text: „Der Dateiname wurde geändert aber nicht gespeichert. Änderungen verwerfen?" Optionen: **„Verwerfen"** (Dirty State wird geleert, Aktion wird fortgesetzt) / **„Zurück"** (Dialog schließt, Benutzer bleibt im Textfeld) --- ## Architektur ### Manuelle Namenskorrektur als Application-Use-Case Die manuelle Dateinamen-Korrektur wird als **eigenständiger Application-Use-Case** modelliert, nicht im GUI-Adapter implementiert: - Ein neuer Use-Case `ManualFileRenameUseCase` (o. ä.) kapselt die atomare Transaktion aus FS-Rename + DB-Update - Der `GuiBatchRunCoordinator` (GUI-Adapter) delegiert ausschließlich an diesen Use-Case - Dateisystem- und DB-Zugriffe laufen ausschließlich über bestehende oder neue Ports/Adapter – kein Direktzugriff aus dem GUI-Adapter - Damit bleibt die hexagonale Architektur gewahrt und der Use-Case ist unabhängig von der GUI testbar ### Komponenten-Übersicht | Komponente | Änderung | |---|---| | `GuiBatchRunTab` | Hauptumbau: SplitPane, Detailbereich-Redesign, Spike-Code entfernen | | `GuiBatchRunResultRow` | Neues Feld: `correctedFileName` als `Optional` | | `GuiBatchRunCoordinator` | Delegiert Dateinamen-Korrektur an neuen Use-Case | | `ManualFileRenameUseCase` | Neuer Application-Use-Case: atomares FS-Rename + DB-Update | | `pom.xml` (GUI-Modul) | PDFViewFX + jai-imageio-jpeg2000 bleiben; Spike-Klasse entfernen | | Domain / Ports | Ggf. neuer Port für Datei-Rename-Operation erforderlich | | Headless-Betrieb | Unberührt | --- ## Abhängigkeiten zwischen den Funktionen - PDF-Vorschau und editierbarer Dateiname sind **unabhängig voneinander nutzbar** - Beide beziehen sich auf den in der Ergebnistabelle selektierten Eintrag - Beim Selektionswechsel mit Dirty-State: Hinweisdialog erscheint (siehe oben) - PDF-Vorschau-Cache wird beim Selektionswechsel geleert --- ## Verhalten während eines laufenden Batch-Laufs - Der Detailbereich (PDF-Vorschau + Dateinamen-Editor) ist **vollständig deaktiviert** während ein regulärer Lauf oder Mini-Lauf aktiv ist - Bereits angezeigte Vorschau bleibt sichtbar, aber Navigation und Bearbeitung sind gesperrt --- ## Nicht in V2.9 enthalten - Löschen der Quelldatei nach Bestätigung (spätere Version) - Vollständiger PDF-Viewer mit freiem Scrollen und Zoom (Issue #23: DPI-Optimierung) - Historien-Tab / SQLite-Ansicht (Issue #7, V3.0) - Automatischer Scheduler / System-Tray (Issues #20, #22) - Kompakteres Layout der Konfigurationsseite (Issue #24) - Anwendungs-Icon (Issue #21) --- ## Abnahmekriterien ### Fachliche Akzeptanz #### PDF-Vorschau - [ ] Beim Anklicken einer Zeile wird Seite 1 der Quelldatei automatisch gerendert – ohne extra Klick - [ ] Während des Renderings ist ein Ladeindikator sichtbar; die GUI bleibt reaktionsfähig - [ ] Die Vorschau rendert „fit to width" mit beibehaltenem Seitenverhältnis - [ ] Seitenanzahl wird angezeigt: „Seite 1 / X" - [ ] „Nächste Seite" / „Vorherige Seite" laden Seiten on-demand - [ ] Bereits gerenderte Seiten werden gecacht; Selektionswechsel leert den Cache - [ ] Navigations-Buttons sind korrekt deaktiviert (erste / letzte Seite) - [ ] Schneller Selektionswechsel oder Seitenwechsel während Rendering: nur das zuletzt angeforderte Ergebnis wird angezeigt (latest preview request wins) - [ ] Quelldatei nicht vorhanden → verständliche Fehlermeldung im Vorschaubereich - [ ] PDF nicht lesbar / korrupt → verständliche Fehlermeldung im Vorschaubereich - [ ] PDF passwortgeschützt → verständliche Fehlermeldung im Vorschaubereich #### Dateiname-Editor - [ ] Textfeld zeigt beim Selektieren den **letzten gespeicherten Namen** (nicht KI-Vorschlag) ohne `.pdf`-Erweiterung; `.pdf` als nicht editierbares Label daneben sichtbar - [ ] Dateiname ist direkt im Textfeld editierbar - [ ] Dirty-State (Abweichung von letztem gespeichertem Namen) wird visuell am Textfeld angezeigt - [ ] Enter im Textfeld löst „Dateiname übernehmen" aus (wenn Validierung grün) - [ ] Escape im Textfeld stellt den **letzten gespeicherten Namen** wieder her - [ ] „Zurücksetzen auf KI-Vorschlag" setzt das Textfeld auf den KI-Ursprung zurück (ohne Speichern) - [ ] Validierung prüft live: leer/nur Leerzeichen, führende/abschließende Leerzeichen, unerlaubte Zeichen, reservierte Windows-Namen, endet auf Punkt, Pfadlänge > 259 - [ ] Bei Validierungsfehler: Speichern-Button deaktiviert, Hinweistext sichtbar - [ ] „Dateiname übernehmen" ist atomar: FS und DB werden beide aktualisiert oder nichts davon - [ ] Bei Fehler in FS oder DB: kein Teilupdate, Rollback, Fehlermeldung im Statusbereich, Textfeld behält Eingabe - [ ] Nach Erfolg: Tabellenspalte und Statusbereich aktualisiert (Projektionsschritt) - [ ] Dateikonflikt mit gleichem Fingerprint → keine Aktion, Meldung „Identische Datei bereits vorhanden" - [ ] Dateikonflikt mit unterschiedlichem Fingerprint → Warnung, Suffix `(1)` usw., DB mit tatsächlichem Namen - [ ] Zieldatei fehlt → Fehlermeldung, weder FS noch DB werden geändert - [ ] Ungespeicherte Änderungen bei Selektionswechsel → Hinweisdialog erscheint - [ ] Ungespeicherte Änderungen bei Tabwechsel → Hinweisdialog erscheint - [ ] Ungespeicherte Änderungen beim App-Schließen → Hinweisdialog erscheint - [ ] Ungespeicherte Änderungen bei Laufstart → Hinweisdialog erscheint - [ ] Status `FAILED_*` und `SKIPPED` → Dateiname-Textfeld deaktiviert - [ ] Während eines aktiven Laufs: Detailbereich vollständig deaktiviert ### Technische DoD - [ ] Spike-Button und `PdfViewerSpike.java` sind vollständig entfernt - [ ] Tab „Verarbeitungslauf" zeigt Tabelle und Detailbereich nebeneinander (SplitPane, 60/40, verschiebbar) - [ ] `ManualFileRenameUseCase` ist im Application-Modul implementiert und unabhängig von der GUI testbar - [ ] headless-Betrieb ist unverändert funktionsfähig - [ ] `mvn clean verify` ist grün