228 lines
10 KiB
Markdown
228 lines
10 KiB
Markdown
# 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.
|