Files
libreoffice-synopse-builder/README.md
2026-09-11 12:47:00 +02:00

228 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Synopse aus Änderungsverfolgung (LibreOffice Writer)
Erzeugt aus einem Writer-Dokument mit nachverfolgten Änderungen ein neues
Dokument mit einer Synopse-Tabelle.
* **Spalte links:** Ursprungsfassung (alle Änderungen verworfen)
* **Rechte Seite:** wahlweise in drei Darstellungen
| Modus | Aufbau | geeignet für |
|---|---|---|
| **kumuliert** | eine Spalte mit der Endfassung | Abnahme einer konsolidierten Fassung |
| **gestapelt** | eine Spalte, darin die Personen untereinander, optional mit Endfassung als Abschluss | viele Beteiligte |
| **getrennt** | je Person eine eigene Spalte, optional gefolgt von der Endfassung | zwei bis drei Beteiligte |
Optional wird in beiden mehrspaltigen Modi zusätzlich die **Endfassung**
ausgewiesen: im gestapelten Modus als letzter Eintrag jeder Zelle, bei
getrennter Darstellung als zusätzliche Spalte ganz rechts. Sie zeigt den
Wortlaut, der beschlossen werden soll — ungekürzt und ohne Streichungen, da
diese in derselben Zeile ohnehin sichtbar sind. Einfügungen bleiben markiert,
damit erkennbar ist, was gegenüber der Ursprungsfassung neu ist.
Im gestapelten Modus erscheint pro Zeile nur, wer dort tatsächlich etwas
geändert oder kommentiert hat. Jeder Eintrag beginnt mit einer dünnen
Trennlinie und dem Namen in der Autorenfarbe. Wer an einer Stelle nur
kommentiert hat, wird mit dem Zusatz „nur Anmerkung“ geführt und bekommt
keine Textfassung sie wäre mit der Ursprungsfassung identisch.
## Streichungen in der Endfassung
Die Endfassung zeigt keinen durchgestrichenen Text — sonst wäre sie kein
lesbarer Beschlusstext. Damit Streichungen trotzdem erkennbar bleiben, wird
nach Fall unterschieden:
| Fall | Darstellung |
|---|---|
| Text unmittelbar ersetzt | nur die Neufassung, hervorgehoben |
| Abschnitt ersatzlos gestrichen | kursiver Hinweis „ersatzlos gestrichen" |
| Teil eines Satzes gestrichen | letztes verbliebenes Wort davor und erstes danach fett hervorgehoben |
Der dritte Fall macht die Nahtstelle sichtbar, ohne den Satz zu zerreißen:
Ursprung Bei diesem Satz wird der Mittelteil, der eigentlich nicht
gebraucht wird, weggelassen.
Endfassung Bei diesem Satz wird der **Mittelteil weggelassen.**
Die Logik steckt in `_clean_runs()`. „Unmittelbar ersetzt" heißt dabei: der
nächste vorhandene Nachbar der Streichung ist eine Einfügung — dann trägt
diese bereits die Markierung und es wird nichts zusätzlich hervorgehoben.
## Kürzung unveränderter Passagen
Damit die Zellen auch bei langen Absätzen lesbar bleiben, lassen sich
unveränderte Passagen auf den Kontext um die Änderung kürzen (voreingestellt
40 Zeichen je Seite, an der Wortgrenze geschnitten, gekennzeichnet mit `…`).
Die Kürzung wirkt auf die Änderungsseite; die Spalte „Ursprungsfassung“ bleibt
vollständig, damit der Bezugstext nachlesbar ist.
Ursprung Die Feuerwehr … hält für den Grundschutz … bereit, die
regelmäßig geprüft werden. rückt aus. Die Feuerwehr …
Anna … die regelmäßig geprüft werden. r̶ü̶c̶k̶t̶ fährt aus. Die …
Die Fassung einer Person ist dabei jeweils diejenige, die entstünde, wenn
ausschließlich deren Änderungen übernommen würden. Einfügungen sind
unterstrichen und in der Autorenfarbe dargestellt, Löschungen optional
durchgestrichen.
## Anmerkungen
Erklärungsbedürftige Änderungen lassen sich kommentieren. Berücksichtigt werden
beide Quellen, die Writer dafür anbietet:
* **Kommentare** (`Einfügen ▸ Kommentar`, `Strg+Alt+C`) wahlweise an einer
Stelle oder über einen markierten Bereich
* **Kommentare zu einer Änderung** (`Bearbeiten ▸ Änderungsverwaltung ▸
Verwalten ▸ Bearbeiten…`), also das Feld `RedlineComment` der Redline
Die Anmerkung erscheint **unterhalb** des Textes in derselben Zelle, bei
getrennter Darstellung in der Spalte der jeweiligen Person, im gestapelten
Modus unter deren Eintrag, bei kumulierter Darstellung gesammelt in der
Spalte „Endfassung“. Die Spalte
„Ursprungsfassung“ bleibt frei von Anmerkungen.
Optisch abgesetzt wird über vier gleichzeitig wirkende Merkmale, damit die
Unterscheidung auch im Schwarzweißdruck trägt:
| Merkmal | Wirkung |
|---|---|
| senkrechter Balken links | Absatzrahmen `LeftBorder` in Autorenfarbe |
| flächige Hinterlegung | `ParaBackColor`, auf 10 % aufgehellte Autorenfarbe |
| Einzug und Abstand | `ParaLeftMargin`, `ParaTopMargin` |
| kleinerer Schriftgrad | 8,5 pt gegenüber 10 pt im Fließtext |
Zur Abgrenzung davon nutzt die Personen-Überschrift im gestapelten Modus eine
**waagerechte** Linie (`TopBorder`) ohne Hinterlegung Balken links bedeutet
also stets „Anmerkung“, Linie oben „neue Person“.
Der Kopf der Anmerkung nennt in Autorenfarbe und fett den Namen, bei
Änderungskommentaren ergänzt um „– zur Änderung“, bei erledigten Kommentaren um
„(erledigt)“. Bei Kommentaren über einen Textbereich wird die kommentierte
Stelle optional als kursives Zitat (gekürzt auf 80 Zeichen) vorangestellt.
## Zweite Funktion: zwei Dokumente vergleichen
**Synopse ▸ Zwei Dokumente vergleichen…** listet alle geöffneten
Writer-Dokumente auf. Auszuwählen sind Quellfassung und Endfassung; das
gerade aktive Dokument ist als Endfassung vorbelegt.
| Spalte | Inhalt |
|---|---|
| links | Textstellen der Quellfassung, entfallene Wörter durchgestrichen (rot) |
| Mitte | Textstellen der Endfassung, neue Wörter unterstrichen (blau) |
| rechts | Kommentare aus der Endfassung |
Die dritte Spalte entfällt automatisch, wenn die Endfassung keine Kommentare
enthält. Alternativ lassen sich die Kommentare unter die Textstelle in der
mittleren Spalte setzen, dann bleibt es bei zwei Spalten.
Enthält eines der Dokumente selbst nachverfolgte Änderungen, wird dessen
Fassung „alle Änderungen übernommen" verglichen.
### Zuordnung
Anders als bei der Änderungsverfolgung gibt es hier keine Redlines, aus denen
sich die Zuordnung ablesen ließe sie wird in zwei Stufen berechnet:
1. **Absatzebene** `difflib.SequenceMatcher` über die normalisierten
Absatztexte. Innerhalb geänderter Abschnitte werden Absätze über ihre
Ähnlichkeit gepaart (`MATCH_MIN = 0.30`, Suchfenster `LOOKAHEAD = 3`);
was darunter bleibt, gilt als entfallener bzw. neuer Absatz und bekommt
eine einseitige Zeile.
2. **Wortebene** ein zweiter Durchlauf innerhalb jedes Absatzpaares
markiert die abweichenden Wörter.
Die beiden Schwellwerte stehen am Kopf von `compare.py`. Bei stark
umformulierten Texten kann `MATCH_MIN` zu senken sinnvoll sein, bei stark
wiederholenden Texten (Formulare, Tabellen) eher zu erhöhen.
## Bauen und Installieren
./build.sh
unopkg add --force synopse-0.6.1.oxt
Danach im Writer: Menü **Synopse ▸ Synopse erzeugen…**
Zum Entfernen:
unopkg remove de.example.synopse
## Aufbau
| Datei | Zweck |
|---|---|
| `synopse_handler.py` | UNO-Komponente (Protocol Handler), Einstiegspunkt |
| `pythonpath/synopse/redline_model.py` | Extraktion von Segmenten und Anmerkungen |
| `pythonpath/synopse/builder.py` | Aufbau des Zieldokuments (Tabelle, Formatierung) |
| `pythonpath/synopse/compare.py` | Vergleich zweier Dokumente (difflib, zweistufig) |
| `pythonpath/synopse/dialog.py` | Optionsdialog |
| `Addons.xcu`, `ProtocolHandler.xcu` | Menüeintrag und Registrierung |
## Modell
Der Text wird einmal linear durchlaufen. Dabei wird ein Stack der gerade
offenen Redlines geführt; jedes Textstück (`Segment`) merkt sich diesen Stack.
Aus dem Stack lässt sich jede Fassung ableiten:
| Zustand des Segments | Ursprung | Endfassung | Fassung von *X* |
|---|---|---|---|
| unverändert | ja | ja | ja |
| eingefügt von X | nein | ja | ja |
| eingefügt von Y | nein | ja | nein |
| gelöscht von X | ja | nein | nein |
| gelöscht von Y | ja | nein | **ja** |
| von Y eingefügt, von X gelöscht | nein | nein | nein |
Absätze werden zu einer Tabellenzeile zusammengefasst, wenn die Absatzmarke
selbst Teil einer Änderung ist. Dadurch bleiben linke und rechte Spalte auch
bei zusammengeführten oder geteilten Absätzen auf gleicher Höhe.
## Das Quelldokument bleibt unverändert
Für die Extraktion muss `RedlineDisplayType` kurzzeitig auf „Einfügungen und
Löschungen anzeigen" stehen nur dann liefert die Portion-Enumeration auch
den gelöschten Text. `extract_blocks()` merkt sich deshalb den vorherigen Wert
sowie `isModified()` und stellt beides in einem `finally`-Block wieder her.
Der Zahlenwert dieser Anzeigeart wird **gemessen, nicht geraten**: Liefert der
Typmanager die Konstante nicht, probiert `_display_all_value()` die Werte 0 bis
3 durch und nimmt den, bei dem `getText().getString()` am längsten ist denn
nur die Anzeige mit Einfügungen *und* Löschungen enthält beides. Das Ergebnis
wird für die Sitzung gemerkt.
Hintergrund: Die Reihenfolge der Konstanten ist nicht über alle Versionen
gleich. Ein geratener Wert kann `REMOVED` treffen, und dann werden
stillschweigend alle Einfügungen ausgeblendet samt der Kommentaranker, die
darin liegen.
## Hinweis zu UNO-Konstanten
Alle UNO-Konstanten werden über `redline_model.const()` aufgelöst, das bei
einem Fehlschlag auf den dokumentierten Zahlenwert zurückfällt. Grund: löst
`uno.getConstantByName()` beim Import eines Moduls eine `RuntimeException`
aus, bricht der Python-Loader die Registrierung der gesamten Erweiterung ab
sichtbar als „Couldn't load … for reason com.sun.star.text.RedlineDisplayType
.INSERTED_AND_REMOVED". Zur Importzeit darf deshalb nichts stehen, das den
Typmanager zwingend braucht. Gleiches gilt für `uno.Enum()` und
`uno.createUnoStruct()`, die über `enum()` bzw. `_line_struct()` laufen.
## Bekannte Grenzen
* Reine Formatänderungen (`RedlineType == "Format"`) werden ignoriert.
* Antworten auf Kommentare erscheinen als eigenständige Anmerkungen; die
Verkettung über `ParentName` wird nicht ausgewertet.
* Personen, die ausschließlich kommentiert haben, erhalten bei getrennter
Darstellung eine eigene Spalte. Deren Textfassung entspricht dann der
Ursprungsfassung.
* Absätze aus Tabellenzellen des Quelldokuments werden in die Zeilenfolge
eingereiht, die Tabellenstruktur geht dabei verloren.
* Kopf-/Fußzeilen, Fußnoten und Rahmen werden nicht durchlaufen.
* Beim Dokumentvergleich werden reine Formatunterschiede nicht erkannt
verglichen wird der Text.
* Verschobene Absätze erscheinen beim Dokumentvergleich als entfallen und neu,
nicht als Verschiebung.
* Absatzformate (Überschriftenebene, Nummerierung) werden nicht übernommen.
* Verschachtelte Redlines über `RedlineSuccessorData` werden nur insoweit
berücksichtigt, wie LibreOffice sie als überlappende Portions ausliefert.