Aus Linux-Magazin 07/2002

Tipps zur Programmierung von Star Office 6, Teil 2

Bisherige VBA- und Star-Basic-4-Aktivisten, die leistungsfähige Makros für Star Office 6 schreiben wollen, benötigen Informationen. Was die Office-Dokumentation nicht bietet, liefert das Linux-Magazin. Dieses Mal: Zugriff auf Textdokumente.

Das Ableben von Star Office 4 änderte den Ansatz für die Entwicklung von Makros vollkommen: An die Stelle einer geschlossenen Welt von Star-Basic-Befehlen trat ein Kosmos von Modulen und Services, die das so genannte Star-Office-API bilden.

Nachdem aufmerksame Leser in [1] bereits die Grundlagen für die Zusammenarbeit zwischen Star Basic und dem Star-Office-API vermittelt bekommen haben, liefert dieser Beitrag nützliche Tipps für den programmierten Zugriff auf Star-Writer-Dokumente. Das beginnt bei einfachen Vorgängen wie dem Öffnen der Dateien und dem Zugriff auf den Dokumenten-Inhalt, geht weiter bei der Handhabung der relativ komplexen Textmarkierungen und endet mit dem Einfügen von Steuerzeichen in Texte und diversen Suchen-und-Ersetzen-Funktionen.

Tipp 1: Ein neues Dokument

Die »loadComponentFromURL«-Methode des »Desktop«-Service ermöglicht das Anlegen von neuen Dokumenten. Das Verfahren, das in [1] auf Seite 27 beschrieben ist, erfordert allerdings einige Arbeitsschritte, weshalb es zwecks Wiederverwendung in einer benutzerdefinierten Funktion namens »NeuesDokument« (Listing 1) zu kapseln ist. Sie bekommt als einziges Argument eine Zahl zwischen 1 und 3 übergeben, die den Typ des anzulegenden Dokuments bestimmt. Eine »1« steht für ein Textdokument, »2« für eine Kalkulationstabelle und »3« für eine neue Zeichnung.

Ohne Argument oder bei einer Zahl kleiner 1 respektive größer 3 legt die Routine automatisch ein neues Textdokument an. Als Ergebnis liefert »NeuesDokument« ein Objekt zurück, das das Dokument repräsentiert. Es ist in einer Variablen vom Typ »Object« zu speichern, über die das Makro im weiteren Verlauf auf das Dokument zugreifen kann. Das Beispiel

Dim objDokument As Object
objDokument = NeuesDokument(2)

legt ein neues Tabellendokument an und speichert den Verweis darauf in der Variablen »objDokument«.

Listing 1: Funktion zum Anlegen eines Dokumentes

01 Function NeuesDokument(Optional intTyp As Integer) As Object
02    Dim objDesktop As Object
03    Dim objDokument As Object
04    Dim strModul As String
05 
06    If IsMissing(intTyp) Then
07       intTyp = 1
08    End If
09 
10    Select Case intTyp
11    Case 2
12       strModul = "scalc"
13    Case 3
14       strModul = "sdraw"
15    Case Else
16       strModul = "swriter"
17    End Select
18 
19    objDesktop = createUnoService("com.sun.star.frame.Desktop")
20    NeuesDokument = objDesktop.loadComponentFromURL _
21    ("private:factory/" & strModul, "_blank", 0, mNoArgs())
22 End Function

Tipp 2: Auf das aktuelle Dokument verweisen

Die Arbeit eines Makros richtet sich zumeist auf das aktuelle Dokument. Allerdings ist die Definition dieses Begriffs keineswegs eindeutig. Aus Sicht des Makros kann es sich dabei um das Dokument handeln, in dem es selbst gespeichert ist. Ein Zugriff auf diese Art eines aktuellen Dokuments ist mit dem Star-Basic-Bezeichner »ThisComponent« möglich, wie es das folgende Beispiel demonstriert:

Dim objDokument As Object
 objDokument = ThisComponent
MsgBox objDokument.URL

Der Entwickler versteht unter dem aktuellen Dokument aber in der Regel jenes, das der Anwender gerade bearbeitet. Falls sich das Interesse eines Makros darauf richten soll, muss er den Bezeichner »GlobalScope.ThisComponent« verwenden, um einen entsprechenden Verweis zu erhalten. Beispiel:

Dim objDokument As Object

objDokument = GlobalScope.ThisComponent
MsgBox objDokument.URL

VBA-Kenner wissen: »GlobalScope.ThisComponent« entspricht dem »ActiveDocument«-Objekt von Microsoft Word, während »ThisComponent« das Star- Basic-Pendant des »ThisDocument«-Objekts darstellt.

Abbildung 1: Wenn sich das gerade aktive Makro in einem anderen Dokument (hier: »MeineMakros.sxw«) als dem aktuellen befindet, müssen Zugriffe auf das aktuelle Dokument (hier: »Hussel2.sxw«) über den Bezeichner »GlobalScope.ThisComponent« erfolgen.

Abbildung 1: Wenn sich das gerade aktive Makro in einem anderen Dokument (hier: »MeineMakros.sxw«) als dem aktuellen befindet, müssen Zugriffe auf das aktuelle Dokument (hier: »Hussel2.sxw«) über den Bezeichner »GlobalScope.ThisComponent« erfolgen.

Tipp 3: Auf den Inhalt eines Dokuments zugreifen

Jedes Star-Writer-Dokument besitzt einen Service namens »Text«, der seinen gesamten Textinhalt repräsentiert. Wer »Text« nutzen will, weist ihm zunächst einer Variablen vom Typ »Object« zu. Das Beispiel speichert einen Verweis auf den Inhalt des aktuellen Dokuments in der Variablen »objText«:

Dim objDokument As Object
Dim objText As Object

objDokument = GlobalScope.ThisComponent
objText = objDokument.Text

Die Objektvariable »objText« stellt diverse Methoden zur Verfügung, um auf den Dokumentinhalt zuzugreifen. Ein Beispiel ist die »getString«-Methode, die den Text des Dokuments als Zeichenkette zurückliefert und per »MsgBox«-Anweisung angezeigt wird:

MsgBox objText.getString

Tipp 4: Auf Absätze zugreifen

Leider verfügen weder das Textdokument noch dessen »Text«-Service über eine Kollektion ( [1], Seite 29), die Absätze zusammenfasst und über einen Namen oder eine Indexzahl unmittelbar zugänglich macht. Der programmierte Zugriff auf Absätze erfordert daher einen Umweg wie ihn das folgende Beispiel zeigt:

Dim objDokument as Object
Dim objText As Object
Dim objAufzaehlung As Object
Dim objAbsatz As Object

objDokument = GlobalScope.ThisComponent
objText = objDokument.Text

objAufzaehlung = objText.createEnumeration
While objAufzaehlung.hasMoreElements
   objAbsatz = objAufzaehlung.nextElement
   MsgBox objAbsatz.getString
Wend

Das Makro richtet einen Verweis auf den Inhalt des aktuellen (Text-)Dokuments ein und speichert ihn dann in der Variablen »objText«. Der Aufruf der »createEnumeration«-Methode in der siebten Zeile legt ein temporäres Aufzählungsobjekt an, das alle Bestandteile (in diesem Fall Absätze) enthält, aus denen das Objekt besteht.

Die While-Wend-Schleife am Ende des Beispiel-Makros durchläuft sämtliche Elemente des Aufzählungsobjekts und prüft jeweils mit Hilfe der »hasMoreElements«-Methode, ob noch weitere Elemente folgen.

Ist das der Fall, speichert die Schleife den von »nextElement« gelieferten Verweis auf den nächsten Absatz in der Variablen »objAbsatz« und zeigt dessen von der »getString«-Methode (siehe Tipp 3) bereit gestellten Inhalt per »MsgBox«-Meldung an.

Tipp 5: Einen virtuellen Cursor anlegen

Der »TextCursor«-Service liefert einen virtuellen Cursor, der im Unterschied zum echten (siehe Tipp 13) unsichtbar ist. Er dient als Zielmarkierung für den programmierten Zugriff auf beliebige Textbereiche. Zum Anlegen dieses Cursors eignet sich die »createTextCursor«-Methode des »Text«-Service:

Dim objDokument as Object
Dim objText As Object
Dim objCursor As Object

objDokument = GlobalScope.ThisComponent
objText = objDokument.Text
objCursor = objText.createTextCursor

Tipp 6: Den virtuellen Cursor verschieben

In der Praxis ist das neu angelegte »TextCursor«-Objekt zunächst an die gewünschte Dokumentposition zu setzen, wozu auch ein ansehnliches Arsenal von Methoden zur Verfügung steht (siehe Tabelle 1).

Um einen definierten Ausgangspunkt zu erhalten, positioniert der Programmierer den Cursor mit

objCursor.gotoStart(False)

an den Anfang des Dokuments. Die Zeile

objCursor.goRight(10, False)

verschiebt die Marke um zehn Zeichen nach rechts.

Tabelle 1: Bewegen eines virtuelle Text-Cursors

Tabelle 1: Bewegen eines virtuelle Text-Cursors

Tipp 7: Texte mit dem virtuellen Cursor markieren

Jede Bewegungsmethode des »TextCursor«-Objekts besitzt ein Argument vom Typ Boolean (in Tabelle 1 als »blnExp« bezeichnet). Es legt fest, ob der Cursor nur verschoben (»False«) oder ob er sich über den gesamten Text zwischen der letzten und der aktuellen Position ausdehnt (»True«). Die Zeile

objCursor.goRight(10, True)

würde »objCursor« folglich also auf die ersten zehn Zeichen des aktuellen Dokuments erweitern und somit eine unsichtbaren Bereichsmarkierung produzieren, zu deren Inhalt die »getString«-Methode den Zugriff verschafft:

MsgBox objCursor.getString

Wird der erweiterte Cursor nicht mehr gebraucht, ist ihm schnell eine Diät verordnet, denn

objCursor.CollapseToStart

reduziert ihn auf einen (gedachten) Strich am Anfang der ehemaligen Markierung. Bei

objCursor.CollapseToEnd

dagegen schnurrt der Cursor am Ende der ehemaligen Markierung zusammen.

Tipp 8: Mit mehreren Markierungen arbeiten

Wenn ein Makro mit mehreren Textstellen arbeiten muss (siehe Abbildung 3), lässt sich jede in einer eigenen Bereichsmarkierung speichern. Dazu legt man jeweils ein »TextCursor«-Objekt an, dehnt es auf die gewünschte Textportion aus und kopiert seinen Inhalt schließlich in ein »TextRange«-Objekt. Das Beispiel sichert den aktuellen Inhalt von »objCursor« in das »TextRange«-Objekt »objRange1«:

Dim objRange1 As Object
objRange1 = objCursor

Die Variable »objRange1« macht den Inhalt der Bereichsmarkierung verfügbar.

Abbildung 3: Star-Writer-Dokumente können eine Vielzahl von Markierungen enthalten, auf die man über die »CurrentController.Selection«-Eigenschaft des Dokuments zugreifen kann.

Abbildung 3: Star-Writer-Dokumente können eine Vielzahl von Markierungen enthalten, auf die man über die »CurrentController.Selection«-Eigenschaft des Dokuments zugreifen kann.

Tipp 9: Wörter zählen und anzeigen

Während man an die Absätze eines Dokuments noch halbwegs elegant mit einem selbst gebauten Aufzählungsobjekt herankommt (siehe Tipp 4), gibt es keine direkte Zugriffsmöglichkeit auf einzelne Wörter (wie sie etwa die »Words«-Auflistung in Word-VBA bietet). Hier hilft nur der Einsatz eines »TextCursor«-Objekts, das sich Wort für Wort durch den Dokumenttext bewegt.

Wie so etwas genau funktioniert, zeigt das Makro in Listing 2, das sämtliche Wörter des aktuellen Dokuments zählt und anzeigt. Die aktive Arbeit des Makros beginnt mit einer »gotoStart«-Anweisung, die die virtuelle Schreibmarke »objCursor« an den Anfang des Dokuments verschiebt.

Die Do-Loop-Schleife erweitert den Cursor bis ans Ende des aktuellen Worts (»gotoEndOfWord«-Anweisung) und speichert dessen Inhalt in der Variablen »strWort«. Sofern die Zeichenkette nicht leer ist, erhöht das Makro die Zählvariable »intZaehler« um 1 und zeigt den Inhalt von »strWort« per »MsgBox«-Dialog an. Danach navigiert die »gotoNextWord«-Zeile den Cursor an den Anfang des nächsten Worts. Das wiederholt sich so lange, bis »strWort« leer ist, also keine weiteren Wörter mehr vorhanden sind. Die »MsgBox«-Anweisung unterhalb der Schleife nennt schließlich den aktuellen Wert der Zählvariablen.

Abbildung 2: Das makrogesteuerte Durchsuchen von Textdokumenten ermöglicht viele Anwendungen, zum Beispiel auch das Auszählen von Worthäufigkeiten.

Abbildung 2: Das makrogesteuerte Durchsuchen von Textdokumenten ermöglicht viele Anwendungen, zum Beispiel auch das Auszählen von Worthäufigkeiten.

Listing 2: Zeigt und zählt Wörter

01 Sub WoerterZaehlenUndAnzeigen
02    Dim objDokument as Object
03    Dim objText As Object
04    Dim objCursor As Object
05    Dim strWort As String
06    Dim intZaehler As Integer
07 
08    objDokument = GlobalScope.ThisComponent
09    objText = objDokument.Text
10    objCursor = objText.createTextCursor
11 
12    objCursor.gotoStart(False)
13    Do
14       objCursor.gotoEndOfWord(True)
15       strWort = Trim(objCursor.getString())
16       If strWort > "" Then
17          intZaehler = intZaehler + 1
18          MsgBox strWort
19       End If
20       objCursor.gotoNextWord(False)
21    Loop Until strWort = ""
22    MsgBox "Dokument hat " & intZaehler & " Wörter."
23 End Sub

Tipp 10: Neuen Text einfügen

Der »Text«-Service von Star-Writer-Dokumenten verfügt über die Methode »insertString«, mit der Makros beliebigen Text in Dokumente einfügen beziehungsweise vorhandenen Text verändern können. Dazu braucht es wieder ein »TextCursor«-Objekt, wie es das folgende Beispiel – unter aktiver Beihilfe der Funktion »NeuesDokument« aus Listing 1 – am Anfang eines neuen Textdokuments anlegt:

Dim objDokument as Object
Dim objText As Object
Dim objCursor As Object

objDokument = NeuesDokument(1)
objText = objDokument.Text
objCursor = objText.createTextCursor

Die »insertString«-Methode bekommt als erstes Argument das »TextCursor«-Objekt übergeben, das die gewünschte Einfügeposition markiert. Das zweite Argument übermittelt den einzufügenden Text. Das dritte Argument bestimmt, ob »insertString« den von »objCursor« gegebenenfalls repräsentierten Text überschreiben soll (»True«) oder nicht (»False«). Soll einfach nur Text eingefügt werden, ist eine Anweisung wie diese richtig:

objText.insertString(objCursor, "Dieser Text ist neu.", False)

Tipp 11: Vorhandenen Text verändern

Möchte der Star-Basic-Programmierer die »insertString«-Methode nutzen, um vorhandenen Text zu verändern, muss er das im ersten Argument übergebene »TextCursor«-Objekt zunächst so erweitern, dass es den zu ändernden Text vollständig markiert. Das Beispiel

With objCursor
   .gotoStart(False)
   .gotoNextWord(False)
   .gotoNextWord(False)
   .gotoNextWord(False)
   .gotoEndOfWord(True)
End With

arbeitet sich bis zum vierten Wort des Dokuments vor und legt das »TextCursor«-Objekt »objCursor« sozusagen darüber. Das dritte Argument der »insertString«-Methode mit »True« ersetzt den gesamten Inhalt des Objekts mit dem im zweiten Argument genannten Text. Die Zeile

objText.insertString(objCursor, "geändert",True)

überschreibt also das vierte Wort des Dokuments (»neu«) mit dem Wort »geändert«.

Tipp 12: Steuerzeichen einfügen

»insertString« kann ausschließlich darstellbare Textzeichen in ein Star-Writer-Dokument schreiben. Für das Einfügen von Steuerzeichen ist die Methode »insertControlCharacter« zuständig. Sie erwartet beim Aufruf ein »TextCursor«-Objekt, das die Einfügeposition markiert, sowie eine Konstante aus dem »ControlCharacter«-Fundus des API-Moduls »com.sun.star.text«, die das gewünschte Steuerzeichen definiert.

Das in Tabelle 2 aufgeführte Angebot umfasst je eine Zeilen- und Absatzschaltung, einen geschützten und bedingten Trennstrich sowie ein geschütztes Leerzeichen. Ein geschützter Trennstrich hindert die Silbentrennung daran, ein Wort an der vorgegebenen Position zu trennen, während die bedingte Variante die Trennstelle vorgibt. Das geschützte Leerzeichen verhindert, dass zwei damit verbundene Wörter getrennt werden. Die Beispielzeile

objText.insertControlCharacter (objCursor, com.sun.star.text.ControlCharacter.LINE_BREAK, False)

fügt der einfachen Logik von Tabelle 2 folgend an der aktuellen Position von »objCursor« eine Zeilenschaltung in das Textdokument ein.

Tabelle 2: Konstanten für Steuerzeichen

Tabelle 2: Konstanten für Steuerzeichen

Tipp 15: Suchen und ersetzen

Lautet die Aufgabe, die gefundenen Textstellen nicht nur zu zählen, sondern deren Inhalt zu ersetzen, muss die »Do-Loop«-Schleife aus dem letzten Tipp nur geringfügig umgebaut werden:

Do While Not IsNull(objFundstelle)
   objFundstelle.String = "StarBasic"
   objFundstelle = objDokument.findNext(objFundstelle.End, objBeschreibung)
Loop

Der Trick besteht darin, dem »TextRange«-Objekt »objFundstelle« via »String«- Eigenschaft einen neuen Inhalt (»StarBasic«) zuzuweisen. Diese Form des Suchens und Ersetzens hat den Vorteil, den Schleifendurchlauf jederzeit per »Exit-Do«-Anweisung beenden zu können, um etwa nur die ersten drei Vorkommen eines Begriffs zu ersetzen.

Zum Austausch sämtlicher Vorkommen gibt es eine deutlich einfachere Methode: Man legt statt eines »SearchDescriptor«-Objekts ein »ReplaceDescriptor«-Objekt an, dessen zusätzliche »replaceString«-Eigenschaft den Austauschtext definiert. Das »ReplaceDescriptor«-Objekt wird dann für den kollektiven Austausch der »replaceAll«-Methode des Dokuments übergeben, wie das Beispiel demonstriert:

Dim objDokument as Object
Dim objBeschreibung As Object
 
objDokument = GlobalScope.ThisComponent
objBeschreibung = objDokument.createReplaceDescriptor
 
With objBeschreibung
        .searchString = "VBA"
        .searchWords = True
        .searchCaseSensitive = True
        .replaceString = "StarBasic"
End With

objDokument.replaceAll(objBeschreibung)
Abbildung 4: Schematischer Aufbau der wesentlichen API-Services für das Suchen und Ersetzen in Textdokumenten. (Quelle: Sun Microsystems)

Abbildung 4: Schematischer Aufbau der wesentlichen API-Services für das Suchen und Ersetzen in Textdokumenten. (Quelle: Sun Microsystems)

Tipp 16: Star-Office-API-Dokumentation besorgen

Die ehemals nur online zugängliche API-Dokumentation steht nun zum Download [2] bereit. Obwohl es sich bei diesem Sammelsurium von HTML-Dateien um eine reine Referenz ohne Beispiele handelt, ist es doch ein unverzichtbares Hilfsmittel für Makroprogrammierer. Größtes Manko der Download-Version ist das Fehlen einer Suchfunktion. Dafür gibt es aber immerhin einen Global Index, der den alphabetischen Zugriff auf sämtliche Schlagworte ermöglicht (siehe Abbildung 5). (jk)

Abbildung 5: In der Download-Version der Star-Office-API-Referenz fehlt die Suchfunktion. Mit dem Global Index ist aber trotzdem jedes Schlüsselwort relativ schnell zu erreichen.

Abbildung 5: In der Download-Version der Star-Office-API-Referenz fehlt die Suchfunktion. Mit dem Global Index ist aber trotzdem jedes Schlüsselwort relativ schnell zu erreichen.

Infos:

[1] Ralf Nebelo: “Tschüss, VBA – Tipps zur Programmierung von Star Office 6”; erster Teil. Linux-Magazin 5/02, S. 26ff.

[2] Download der Star-Office-API-Dokumentation: [http://api.openoffice.org]

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben