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 FeldRedlineCommentder 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:
- Absatzebene –
difflib.SequenceMatcherüber die normalisierten Absatztexte. Innerhalb geänderter Abschnitte werden Absätze über ihre Ähnlichkeit gepaart (MATCH_MIN = 0.30, SuchfensterLOOKAHEAD = 3); was darunter bleibt, gilt als entfallener bzw. neuer Absatz und bekommt eine einseitige Zeile. - 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
ParentNamewird 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
RedlineSuccessorDatawerden nur insoweit berücksichtigt, wie LibreOffice sie als überlappende Portions ausliefert.