Für viele Anwender gehören Textverarbeitung und Tabellenkalkulation zu den wichtigsten Desktop-Programmen. Zu deren Aufgabengebiet gehört es auch, Dokumente automatisch zu erzeugen oder programmgesteuert Teile zu überarbeiten. Hier wäre es praktisch, statt des eingebauten Basic bei der gewohnten Skriptsprache zu bleiben.
Office aus der Ferne
Dank Arnulf Wiedman und Wolfgang Großer klappt dies auch: Ihre Tcl-Erweiterung Tcluno [1] gibt Skripten Zugriff auf den vollen Funktionsumfang von Open Office, um zum Beispiel Dokumente zu erstellen oder ihren Inhalt zu ändern. Das mächtige Uno-Komponentenmodell (siehe Kasten "Universal Network Objects") bringt die notwendige Unterstützung mit, um Open Office von anderen Programmen aus fernzusteuern. Das Ergebnis ist ein Open-Office-Dokument, bei Bedarf auch exportiert nach Winword, Excel und PDF oder ausgedruckt.
Universal Network Objects
|
|
Als die Hamburger Star Division in den 90er Jahren die ersten Versionen von Star Office entwickelte, war die Programmiersprache der Wahl C++. Damals fehlte aber ein plattformübergreifendes Komponentenmodell, um die komplexe Anwendung in überschaubare Teile zu zerlegen. In Anlehnung an Ideen aus Microsofts OLE (Object Linking and Embedding) und OMG Corba (Object Management Group, Common Object Request Broker, [4]) entwickelte Star Division ihr Uno-Komponentenmodell. Der Name steht für Universal Network Objects. Interface-Beschreibung
Ähnlich wie bei Corba nutzt Uno eine eigene Sprache, um die Methoden und Eigenschaften der verfügbaren Klassen zu beschreiben. Vergleichbar zu OLE unterstützen die Objekte gleichzeitig mehrere Schnittstellen, die ein Client zur Laufzeit abfragt und sich für eine entscheidet. Zum Beispiel kennt die Implementation für ein Blatt in der Tabellenkalkulation (Abbildung 1) mehrere Schnittstellen, die ein Java-Programm wie folgt abfragen würde:
XStorable xStorable = (XStorable)UnoRuntime.queryInterface(XStorable.class, spreadsheet);
xStorable.storeAsUrl( ... );
XPrintable xPrintable = (XPrintable)UnoRuntime.queryInterface(XPrintable.class, spreadsheet);
xPrintable.print( ... );
Der Vorteil des Komponentenmodells: Beim Implementieren kann der Entwickler frei entscheiden, über welche Schnittstellen ein neues Objekt verfügt. Das Prinzip ähnelt den Interfaces von Java. Im Gegensatz zu C++ verhindert es unübersichtliche Mehrfachvererbungen. Ändert sich die Implementation eines Objekts, bleibt das ohne Folgen für den restlichen Quelltext, da der nur die verfügbaren Schnittstellen, nicht jedoch das Objekt selber nutzt. Gruppenbildung sorgt für Übersicht
Damit auch viele Schnittstellen überschaubar bleiben, lassen sie sich zu größeren Einheiten gruppieren, den so genannten Services. Zum Erzeugen eines Objekts genügt bei Uno kein einfacher Konstruktor, das Programm muss dies vielmehr bei einem Servicemanager (Factory) anfordern. Interessanterweise verwendet die französische Firma Dassault Systèmes ein fast identisches Framework in Catia V5. Leider ist die Linux-Version dieses CAD-Systems noch nicht erhältlich.
Wie das Wort Network in Uno andeutet, funktioniert der Zugriff auf die Komponenten-Interfaces auch übers Netzwerk. Das ist der einfachste Weg, um Open Office von fremden Programmiersprachen aus zu steuern. Wer selber Uno-Objekte schreiben möchte, muss hierfür derzeit C++ oder Java verwenden. Wer nur den bestehenden Funktionsumfang von Open Office nutzen will, kann auch weitere Sprachen wie Tcl, Python, Dotnet oder Open Office Basic verwenden. Einblick zur Laufzeit
Besonders praktisch für Skriptsprachen: Per Introspektion können sie die verfügbaren Schnittstellen zur Laufzeit abfragen. Tcluno nutzt dies und fordert selbst die nötigen Interfaces an. Java- oder C++-Programmierer müssen sich selbst mit diesem Schritt plagen, bevor sie Methoden auf ein Objekt anwenden dürfen. Kennen Tcl-Programmierer die Schnittstellen einer Implementation, dann wenden sie diese ohne Umweg an.
Abbildung 1: Dank Uno sind Implementation und Schnittstelle getrennt, ein Objekt unterstützt meist mehrere Schnittstellen.
|
Die Tcluno-Quellen sind auf Sourceforge [2] zu finden. Die Entwickler arbeiten recht rege an ihrem Projekt; während die ersten Versionen noch auf den C++-Bibliotheken von Open Office basierten, ist die aktuelle Version eine reine Skript-Erweiterung, die ohne Kompilieren auskommt. Es genügt daher auch, die Erweiterung an beliebiger Stelle auf dem Rechner abzulegen und den Tcl-Suchpfad entsprechend zu erweitern. Ein fertiges Paket mit den Beispielen aus diesem Artikel und einer erprobten Version der Erweiterung ist auf dem Linux-Magazin-FTP-Server zu finden [3].
Vernetzte Prozesse
Die Kommunikation zwischen Open Office und Tcluno findet über das Netzwerk statt, selbst wenn beide Prozesse auf derselben Maschine laufen. Open Office arbeitet dabei als Server. Das Programm muss gestartet sein, damit Tcl darauf zugreifen kann. Per Default startet Open Office leider ohne Netzwerkunterstützung. Ein Aufruf mit der »accept«-Optionen ändert dies:
ooffice "-accept=socket,host=localhost,port=2002;urp;"
Nur Clients (also Tcl-Skripte), die auf demselben Rechner laufen, erhalten bei diesen Einstellungen Zugriff auf Open Office. Wer diese Funktionalität häufiger braucht, kann die Netzwerkunterstützung auch dauerhaft in der Konfigurationsdatei eintragen. In »Setup.xcu« sind dazu im XML-Ast »node oor:name="Office"« drei Zeilen zu ergänzen, in Listing 1 sind das die Zeilen 9 bis 11 mit einer »ooSetupConnectionURL«-Property.
Listing 1: Netzwerkunterstützung
|
01 <?xml version="1.0" encoding="UTF-8"?>
02 <oor:component-data xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" oor:name="Setup" oor:package="org.openoffice">
03 <node oor:name="L10N">
04 <prop oor:name="ooLocale" oor:type="xs:string">
05 <value>en-US</value>
06 </prop>
07 </node>
08 <node oor:name="Office">
09 <prop oor:name="ooSetupConnectionURL" oor:type="xs:string">
10 <value>socket,host=localhost,port=2002;urp</value>
11 </prop>
12 <prop oor:name="ooSetupInstCompleted" oor:type="xs:boolean">
13 [...]
Zugriff erlaubt
|
Je nach verwendeter Version, Distribution und Installation liegt die Konfigurationsdatei an unterschiedlichen Orten. Bei Open Office 2.0 findet sich die benutzerspezifische Konfigurationsdatei unter »~/.openoffice.org2/user/registry/data/org/openoffice/Setup.xcu«, die systemweite Konfigurationsdatei zum Beispiel unter »/usr/lib/ooo-2.0/share/registry/data/org/openoffice/Setup.xcu«. Bei der älteren Version 1.1 heißt das benutzerspezifische File »~/OpenOffice.org1.1/user/registry/data/org/openoffice/Setup.xcu«, das systemweite ist »/usr/lib/ooo-1.1/share/registry/data/org/openoffice/Setup.xcu«.
Für Tcl-Programmierer funktionieren die Open-Office-Objekte genau so wie von Tk oder Itcl gewohnt. Sie stehen in Tcl als Objekte bereit, die in den Schnittstellenbeschreibungen definierten Methoden übergibt das Skript in bester Tk-Tradition an das Objekt. Listing 2 nutzt ein paar der 2600 Klassen von Open Office, um ein Blatt der Tabellenkalkulation mit Daten zu füllen und im Excel-Format zu exportieren.
Listing 2: Tcluno
|
01 #!/usr/bin/tclsh
02
03 lappend auto_path [file join [pwd] tclurtp]
04 lappend auto_path [file join [pwd] tcluno ]
05
06 # Tcl-Only-Version von Tcluno anfordern
07 set ::argv "-urtp"
08 # Erweiterung laden
09 package require tcluno_scalc
10
11 # Kontakt mit Open Office herstellen
12 if {[catch {::tcluno_soffice::initDesktop} desktop]} {
13 puts stderr "Verbindung mit Open Office fehlgeschlagen!"
14 puts stderr "Fehler war:"
15 puts stderr $desktop
16 puts stderr ""
17 puts stderr "Bitte Open Office mit Netzwerkunterstützung starten:"
18 puts stderr "ooffice "-accept=socket,host=localhost,port=2002;urp;""
19 exit 1
20 }
21
22 # Schnittstellen anzeigen
23 puts "»desktop« hat folgende Schnittstellen:"
24 puts [join [$desktop getTypes] "n"]
25 puts "n»desktop« ist folgender Service:"
26 puts [$desktop getSupportedServiceNames]
27
28 # leere Liste erstellen
29 set filterSequence [$desktop tcluno::createUnoSequence Any]
30
31 # neues Dokument in Tabellenkalkulation
32 set spreadsheet [$desktop loadComponentFromURL
33 "private:factory/scalc" "_blank" 0 $filterSequence]
34
35 # erste Seite finden
36 set sheets [$spreadsheet getSheets]
37 set sheet [$sheets getByIndex 0]
38 puts "nDer Tabellenname lautet: [$sheet getName]"
39 $sheet setName "Zufallszahlen"
40
41 # Tabelle mit Zufallszahlen füllen
42 for {set col 0} {$col < 10} {incr col} {
43 for {set row 0} {$row < 10} {incr row} {
44 set cell [$sheet getCellByPosition $col $row]
45 set value [expr {rand() * 100}]
46 $cell setValue $value
47 }
48 }
49
50 # Zellenadresse
51 set cell [$sheet getCellRangeByName "A12"]
52 puts "nKomplette Adresse: [$cell getCellAddress]"
53
54 # Formeln und Texte
55 set cell [$sheet getCellRangeByName "A12"]
56 $cell setFormula "Summe:"
57 set cell [$sheet getCellRangeByName "B12"]
58 $cell setFormula "=sum(B1:B10)"
59 set cell [$sheet getCellRangeByName "A13"]
60 $cell setFormula "Mittelwert:"
61 set cell [$sheet getCellRangeByName "B13"]
62 $cell setFormula "=median(B1:B10)"
63
64 # Als Excel-Tabelle exportieren
65 set filterSequence [$::desktop tcluno::createUnoSequence Any]
66 set msExcelFilter [$::desktop tcluno::createUnoStructHelper
67 com.sun.star.beans.PropertyValue
68 {FilterName -1 {MS Excel 97} 0}]
69 $::desktop tcluno::appendUnoSequence $filterSequence $msExcelFilter
70
71 $spreadsheet storeAsURL "file:[file normalize ~/test.xls]" $filterSequence
|
Die »lappend«-Anweisungen in den Zeilen 3 und 4 erweitern den Suchpfad von Tcl um die Installation von Tclurtp und Tcluno. Die Beispiele arbeiten mit der reinen Skriptlösung Tclurtp für die Kommunikation mit Open Office. In der aktuellen Version verwendet Tcluno die Tclurtp-Variante aber nur, wenn das Skript mit der Option »-urtp« läuft. Zeile 7 sorgt dafür, dass die Variable »::argv« den String immer enthält, egal was der Anwender in der Kommandozeile angegeben hat.
Anschließend beginnt der Code damit, die Erweiterung für die Tabellenkalkulation anzufordern. Mit »::tcluno_soffice::initDesktop« versucht Zeile 12 den Kontakt zu Open Office herzustellen. Schlägt dies fehl, geben die darauf folgenden »puts stderr«-Aufrufe eine ausführliche Fehlermeldung aus. Im Erfolgsfall enthält die Variable »desktop« das zentrale Startobjekt.
Zwar muss sich bei Tcluno der Programmierer nicht wie bei Java oder C++ darum kümmern, die gewünschte Objektreferenz für eine Methode erst abzufragen, bevor er sie verwenden darf. Dennoch sind solche Abfragen möglich und sinnvoll, um sich über die unterstützten Schnittstellen eines Objekts zu informieren. Die Zeilen 23 bis 26 machen es vor; das Ergebnis zeigt Abbildung 2a.
Abbildung 2a: Das Tcluno-Beispiel aus Listing 2 beginnt mit der Ausgabe aller Schnittstellen des Desktop-Objekts von Open Office. Über diesen Service öffnet das Tcl-Programm die Tabellenkalkulation.