Sie sind auf Seite 1von 95

Inhaltsverzeichnis

1 Einleitung und Vorbereitung..............................................................................................................4 1.1 Ziel dieses Dokuments...............................................................................................................4 1.2 Das StarOffice Software Development Kit (SDK)....................................................................4 2 Programmieren mit UNO...................................................................................................................6 2.1 Was ist UNO?............................................................................................................................6 2.2 Interfaces....................................................................................................................................7 2.3 Die UNO Interface Definition Language (IDL).........................................................................9 2.4 Services....................................................................................................................................11 2.5 Typen in UNO..........................................................................................................................16 Interfaces..............................................................................................................................16 Elementare Typen ................................................................................................................17 Der Datentyp type.................................................................................................................17 Der Datentyp any..................................................................................................................17 Der Datentyp sequence.........................................................................................................17 Enumerationen (enum) und Constant Groups......................................................................18 Strukturierte Datentypen (struct)..........................................................................................19 Exceptions in UNO...............................................................................................................19 Services.................................................................................................................................20 Properties..............................................................................................................................20 2.6 UNO in den verschiedenen Programmiersprachen...................................................................21 3 StarOffice Programmierung in Java.................................................................................................26 3.1 Allgemeines..............................................................................................................................26 3.2 Besonderheiten des Java UNO Language Bindings.................................................................28 Abbildung elementarer UNO-Datentypen.............................................................................28 Abbildung des UNO-Typs string..........................................................................................29 Abbildung des UNO-Typs type.............................................................................................29 Abbildung von UNO-Enumerationstypen.............................................................................29 Abbildung von UNO Constant Groups (constants)..............................................................29 Abbildung von UNO struct-Typen.......................................................................................30 Abbildung von UNO sequence ............................................................................................30 Abbildung von UNO exception.............................................................................................30 Abbildung von UNO-Interface Typen..................................................................................31 Abbildung des UNO-Typs any..............................................................................................32 Abbildung von UNO-Services..............................................................................................33 4 StarOffice-Programmierung in C++.................................................................................................34 4.1 Allgemeines..............................................................................................................................34 4.2 Besonderheiten des C++ UNO Language Bindings.................................................................37 Abbildung elementarer UNO-Datentypen.............................................................................37 Abbildung des UNO-Datentyps string..................................................................................37 Abbildung des UNO-Typs type.............................................................................................37 Abbildung von UNO Constant Groups (constants) und UNO-Enumerationstypen.............38 Abbildung von UNO struct-Typen.......................................................................................38 Abbildung von UNO sequence ............................................................................................38 Abbildung des UNO-Typs any..............................................................................................39 Abbildung von UNO-Interface Typen..................................................................................41 Abbildung von UNO-Services..............................................................................................42 Exception handling in C++ UNO..........................................................................................42 5 StarOffice Basic und UNO..............................................................................................................43 5.1 Allgemeines..............................................................................................................................43 5.2 Besonderheiten der Basic-Sprachanbindung............................................................................44

Benutzung von UNO-Objekten in Basic...............................................................................44 Abbildung von numerischen UNO Typen.............................................................................46 Abbildung von UNO sequence.............................................................................................47 Abbildung von UNO struct Typen........................................................................................49 Abbildung von UNO-Enumerationstypen und Constant Groups..........................................49 Typsichere Parameterbergabe in Basic...............................................................................50 Exception Handling in Basic.................................................................................................51 7 Spezielle Aspekte der UNO-Programmierung.................................................................................52 7.1 Lebensdauer von UNO-Objekten.............................................................................................52 7.2 WEAK References ?!...............................................................................................................54 7.3 Arbeiten mit Dokumenten........................................................................................................54 Erzeugen von Dokumenten...................................................................................................55 Der MediaDescriptor............................................................................................................56 Speichern von Dokumenten..................................................................................................60 Drucken von Dokumenten....................................................................................................62 Schlieen von Dokumenten..................................................................................................63 7.4 StarOffice Application Framework API...................................................................................65 Frames...................................................................................................................................65 StarOffice Component Framework.......................................................................................67 Der Desktop Service.............................................................................................................71 7.5 Ereignisse (Events), Listener und Broadcaster........................................................................73 7.6 Listener in Basic.......................................................................................................................74 7.7 Dokumentereignisse.................................................................................................................74 7.8 Event Bindings.........................................................................................................................77 7.9 Dokumenteigenschaften (Metadaten)......................................................................................79 8 Textdokumente................................................................................................................................83 8.1 Arbeiten mit Textdokumenten.................................................................................................83 Text, TextRanges und Cursor...............................................................................................83 Textinhalte............................................................................................................................84 Einfgen oder Lschen von Abstzen an speziellen, schwer erreichbaren Positionen..........85 Formatierung.........................................................................................................................85 Navigation.............................................................................................................................87 8.2 Tabellen....................................................................................................................................88 Tabellenarchitektur...............................................................................................................88 Benannte Tabellenzellen, Spalten und der TableCursor........................................................90 Zugriff auf bereits existierende Tabellen...............................................................................91 8.3 Weitere Aspekte von Textdokumenten....................................................................................91 Feldbefehle............................................................................................................................91 Zugriff auf existierende Feldbefehle......................................................................................92 AutoText...............................................................................................................................92 8.4 Weitere Programmierbeispiele.................................................................................................93 Beispiel Absatz, Vorlagen setzen, Text einfgen...............................................................93 Beispiel - TextCursor............................................................................................................94 Beispiel Text in Tabellenzelle einfgen.................................................................................94 Beispiel fr Feldbefehle.........................................................................................................95 9 Entwicklung von UNO-Komponenten.............................................................................................96 9.1 Was macht eine UNO-Komponente aus?.................................................................................96 9.2 Entwicklung von UNO-Komponenten.....................................................................................96 TODO: Muteces Was muss ich beachten, wenn ich UNO-Objekte implementiere/Benutze? Wann sollte ich UNO-Objekte benutzen, Vor/Nachteile

1 Einleitung und Vorbereitung


1.1 Ziel dieses Dokuments
Die Programmierung mit UNO und StarOffice ist sehr ausfhrlich im StarOffice 8 Developers Guide beschrieben, der zusammen mit der Referenzdokumentation des StarOffice API und der Java UNO Runtime Library Bestandteil der Dokumentation im StarOffice Software Development Kit (SDK) ist. Weitere Dokumentation zu diversen Fragen der UNO-Programmierung und des StarOffice API finden sich auf den Projektseiten der UDK- und API-Projekte von Openoffice.org unter http://udk.openoffice.org und http://api.openoffice.org. Insbesondere sind die dazugehrigen Mailing-Listen dev@api.openoffice.org und dev@udk.openoffice.org zu empfehlen, wo man in einen direkten Kontakt mit anderen Entwicklern, speziell auch den StarOffice/OpenOffice.org-Entwicklern treten kann. Der Developers Guide ist sehr umfangreich, da er weite Teile der StarOffice-Programmierung abdeckt und sie z.T. auch technisch sehr detailliert beschreibt. Er beschreibt auch detailliert alle Details der vorhandenen Sprachanbindungen und wie man eigene implementiert, geht also weit ber das hinaus, was man im Rahmen einer Einfhrung behandeln mchte. Nichtsdestotrotz ist er die primre Referenz fr alle Entwickler, die schon etwas Erfahrung mit der StarOffice-Programmierung gemacht haben und die UNOIDL-Referenz zu benutzen gelernt haben. Die UNOIDL-Referenz enthlt die Deklaration des kompletten StarOffice-API zusammen mit meist sehr ausfhrlicher Dokumentation der einzelnen Methoden. Sie ist der beste Weg, sich die Funktionalitt der StarOffice-Komponenten systematisch zu erschlieen. Das Ziel der vorliegenden Einfhrung ist es, die grundlegenden Kenntnisse der StarOfficeProgrammierung zu vermitteln und den Leser in die Lage zu versetzen, sich weitergehende Informationen aus den oben genannten Quellen besorgen zu knnen. Sie konzentriert sich dabei auf die Sprachen StarOffice Basic und Java, auch wenn C++ hin und wieder erwhnt wird.

1.2 Das StarOffice Software Development Kit (SDK)


Das SDK, ergnzt um ein GNU make, enthlt alles, was ein Java oder C++-Programmierer bentigt, um Komponenten fr oder Programme mit StarOffice zu entwickeln. Java-Entwickler werden in der Regel eine IDE benutzen und vom SDK nur die Dokumentation einbinden, daher soll in dieser Einfhrung das direkte Arbeiten mit dem SDK nicht weiter erlutert, sondern nur die einzelnen Bestandteile aufgefhrt und kurz beschrieben werden. Das Root-Verzeichnis des SDK enthlt neben Scripts und Batchdateien zur Konfiguration (fr die, die damit direkt programmieren wollen) einen Lizenztext und mit der Datei index.html einen Einstieg in die komplette Dokumentation, die im SDK im Unterverzeichnis doc abgelegt ist. In dessen Unterverzeichnissen befinden sich, jeweils ber index.html verlinkt: die komplette Referenzdokumentation des StarOffice Dateiformats im Unterverzeichnis common/spec im PDF-Format; die komplette API-Referenzdokumentation im HTML-Format im Unterverzeichnis common/ref; die komplette Referenzdokumentation der Java UNO Runtime Environment Klassen im HTML-Format im Unterverzeichnis java; die komplette Referenzdokumentation der C++ UNO Runtime Environment Klassen im HTML-Format im Unterverzeichnis cpp; den kompletten StarOffice8 Developers Guide sowohl im HTML-Format als auch im PDFFormat im Unterverzeichnis DevelopersGuide;

eine kurze Beschreibung der Entwicklungswerkzeuge im HTML-Format in der Datei tools.html. Im Unterverzeichnis idl befindet sich das komplette StarOffice8 API in Form von UNOIDL-Dateien. Diese werden aber nur von C++-Entwicklern zur Generierung von Header-Dateien bentigt, die dort enthaltene Dokumentation befindet sich in wesentlich besser lesbarer Form in den daraus generierten HTML-Dateien im Verzeichnis docs/common/ref. Im Verzeichnis include befinden sich alle C++-Headerdateien der C++ UNO Runtime Libraries, dazu kommt noch mindestens ein (plattformabhngiges) Verzeichnis mit den dazugehrigen Bibliotheken und den SDK-Tools (also z.B. ein Verzeichnis windows mit den Unterverzeichnissen lib und bin). In diesem Verzeichnis landen auch die beim direkten Arbeiten mit dem SDK erzeugten Binaries. Das Verzeichnis examples enthlt lauffhige Programmierbeispiele fr StarOffice Basic, Java, C++, CLI (C#, VB.NET) und OLE Automation (Delphi, VB Script, C++). Weiterhin befinden sich dort alle Beispiele aus dem Developers Guide. Die Verzeichnisse classes enthlt ein paar Java-Klassen, die fr das Simple Bootstrapping (also die komfortabelste Art, sich mit einem StarOffice-Prozess zu verbinden) bentigt wird. Wie diese eingebunden werden, ist abhngig von der verwendeten IDE. Die Dateien im Unterverzeichnis xml werden nur fr interne Zwecke verwendet.

2 Programmieren mit UNO


2.1 Was ist UNO?
UNO ist zunchst eine Technologie, die die Interoperabilitt von Objekten ermglicht, vergleichbar mit hnlichen Technologien wie CORBA, (D)COM oder .NET. Ohne eine solche Middleware knnen Objekte nur zusammenarbeiten, wenn sie innerhalb einer gemeinsamen Applikation existieren und in den allermeisten Fllen auch nur dann, wenn sie mit der gleichen Programmiersprache implementiert sind und so die zur Kommunikation notwendigen Informationen auf Quellcode-Ebene austauschen knnen (Header Files etc.). Mit einer Technologie wie UNO knnen Objekte auch dann zusammenarbeiten, wenn sie in unterschiedlichen Programmiersprachen implementiert sind oder in verschiedenen Applikationen (Prozessen) existieren, ja sogar wenn sie auf verschiedenen Rechnern laufen, sofern diese Rechner ber eine geeignete Verbindung kommunizieren knnen (UNO verwendet dafr TCP/IP). UNO erreicht das, indem es die Kommunikation der Objekte untereinander auf binrer Ebene standardisiert und klar definierte Regeln aufstellt, wie diese standardisierte Kommunikation auf die verschiedenen Programmiersprachen, Compiler und Systeme abgebildet (bersetzt) wird. Auerdem liefert UNO auch die entsprechenden Abbildungen (Bindings) fr eine Reihe von Kombinationen dieser drei Faktoren (als Beispiel: C++ mit gcc unter Linux). Wichtig zu wissen ist weiterhin, dass ein Objekt, das ber UNO mit einem anderen Objekt zusammenarbeitet, prinzipiell nicht nur nicht wei, in welchem Prozess oder auf welchem Rechner dieses luft, sondern auch von diesem Objekt nur eine externe Schnittstelle sieht, aber nichts darber wei, wie diese intern realisiert wurde. Dies ist quasi die Weiterentwicklung des Prinzips der Trennung von Implementierung und Schnittstelle, die ja ansonsten auf Quellcode-Ebene angewendet wird. Dieses Prinzip zusammen mit der garantierten Stabilitt von Schnittstellen und der Sprachunabhngigkeit sind die Essenz von UNO. Die Schnittstelle eines Objekts, sein Application Programming Interface (API) wird blicherweise durch seine Methoden (Funktionen) und Properties (Eigenschaften) beschrieben, Begriffe, die so oder in hnlicher Form nicht nur aus objektorientierten Programmiersprachen, sondern auch aus objektbasierten wie Visual Basic und StarOffice Basic bekannt sind. UNO fasst allerdings zustzlich Methoden zu sogenannten Interfaces zusammen, was im nchsten Kapitel erlutert wird. Die Schnittstelle eines Objekts ist dann gegeben durch die Summe aller untersttzten Interfaces und Properties. Die Rolle von UNO wird vielleicht klarer, wenn man sich Objekte als Bausteine vorstellt, die nach auen eine Kontaktstelle aufweisen, ber die man durch das Senden von Signalen innerhalb der Bausteine bestimmte Funktionen auslsen kann. Die Summe aller vom Objekt verstandenen Kommandos, die man ber diesen Kontakt senden kann (seine Methoden), ergnzt um die Summe aller Zustnde, die man darber abfragen oder setzen kann (seine Properties), bildet seine Schnittstelle. Intern benutzt ein solcher Baustein eine bestimmte Implementierungssprache, um auf ein ber seine Kontaktstelle eintreffendes Kommando hin Aktionen auszufhren. So kann ein Baustein intern optische Signalverarbeitung benutzen, ein anderer akustische. Damit ein Baustein eintreffende Kommandos auch versteht, mssen diese eine definierte bertragungsform verwenden, und jeder Baustein bentigt ein bersetzungsmodul, das die in dieser definierten Form bertragenen Kommandos in eine fr die Implementierungssprache verstndliche Form berfhrt. Das gleiche Modul bersetzt auch Kommandos, die der Baustein an andere sendet, in diese definierte Form, in der die Kommandos dann zu dem bersetzungsmodul des Zielbausteins bertragen und dort verarbeitet werden knnen. So kann beispielsweise die Informationsbertragung durch elektrische Signalverarbeitung erfolgen, und ein Baustein, der intern mit einer akustischen Signalverarbeitung arbeitet, wrde dann einen Akustikkoppler bentigen.

UNO ist hierbei das Medium, das nicht nur die Bausteine als Kabel miteinander verbindet, sondern auch die bertragungssprache definiert und die bersetzungsmodule von Implementierungssprache zu bertragungssprache und zurck zur Verfgung stellt. Natrlich verwendet UNO dabei eine andere Terminologie, die im Folgenden noch erlutert wird: Beispiel Baustein Kommandos und Zustnde Befehlssatz bertragungsform Technologie des internen Aufbaus Ausfhrung von Aktionen Kabelverbindung bersetzungsmodul Objekt Interfaces, Properties Schnittstelle (API) UNO Interface Definition Language (IDL) Programmiersprache der Implementierung Ausfhrung von Programmcode UNO Runtime und UNO Protokoll UNO Language Binding UNO

Der Begriff Objekt bedarf noch einer etwas nheren Erluterung. Er ist nicht deckungsgleich mit dem, was ein C++ - oder Javaprogrammierer als Objekt kennt. Er bezeichnet zunchst nur die Auensicht auf eine Softwareeinheit, wie deren innere Organisation aussieht, ist damit nicht festgelegt. Es ist durchaus mglich, dass ein UNO-Objekt intern durch mehrere C++ oder Javaobjekte implementiert ist. Dem Entwickler, der das UNO-Objekt benutzt kann das aber egal sein, er spricht das Objekt nur ber seine definierte Schnittstelle an, das Objekt ist dann einfach die gesamte Implementierung, die sich hinter dieser verbirgt. Nachdem wir bis jetzt definiert haben, wie UNO solche Objekte behandelt, macht es vielleicht mehr Sinn, den Spie umzudrehen und zu sagen, dass ein UNO-Objekt eine in ihren Ausmaen nicht nher beschriebene Einheit ist, von der andere Objekte nur eine definierte Schnittstelle wie oben beschrieben sehen. Programmierer knnen UNO einerseits verwenden, um eigene Anwendungen zu schreiben, die UNO-Objekte benutzen, sie knnen aber andererseits auch selbst UNO-Objekte implementieren, die dann wiederum von ihren oder anderen Anwendungen benutzt werden knnen. Auch StarOffice selbst ist eine solche Anwendung, die zunchst nur die eigenen UNO-Objekte benutzt, aber auch definierte Mglichkeiten bietet, durch Einbinden von als externe Komponente bereitgestellten UNOObjekten die eigene Funktionalitt zu erweitern oder zu verndern. UNO-Schnittstellen sind also gewissermaen aktiv und passiv nutzbar, ersteres, indem man Objekte einbindet, letzteres indem man vordefinierte Schnittstellen implementiert und sich so einbinden lsst. Diese beiden Anwendungsflle werden uns spter noch beschftigen.

2.2 Interfaces
Wie schon erwhnt gruppiert UNO (ebenso wie COM) die Methoden eines Objekts zustzlich zu sog. Interfaces. Das Interface ist ein Konzept, das einem Java Programmierer unter genau diesem Namen bekannt sein drfte, ein C++-Entwickler kennt es als rein abstrakte Basisklasse. Im technischen Sinne ist ein Interface einfach eine Sammlung von Methoden, die derart in einem sinnvollen Zusammenhang miteinander stehen, dass es nach Meinung des Autors dieser Methoden keinen Sinn macht, in einem Objekt nur eine dieser Methoden zu implementieren, sondern im Regelfall alle. Man sagt dann nicht, das Objekt X bietet die Methoden a,b und c an sondern das Objekt X implementiert das Interface Y, das die Methoden a,b und c umfat. Ein einfaches Beispiel dafr ist ein Objekt, das es erlaubt, andere Objekte als sog. Listener anzumelden, die dann ber bestimmte Ereignisse in dem ersten Objekt informiert werden werden knnen. Es macht berhaupt keinen Sinn, nur eine Methode zum Anmelden anzubieten, man bentigt auch automatisch eine zum Abmelden. Daher wird das Objekt ein entsprechendes Interface anbieten, das diese beiden Methoden

umfat. Im bertragenen Sinne kann ein Interface als ein spezieller Aspekt eines Objekts gesehen werden, das Ergebnis einer klassifizierenden Betrachtungsweise. Ein Objekt kann mehrere solche Aspekte aufweisen, so wie in der realen Welt z.B. eine menschliche Person die Aspekte Frau, Lehrer und Deutschsprachig aufweisen kann. Jedes dieser Interfaces ermglicht es, das gesamte Objekt jeweils nur unter dem dadurch reprsentierten Teilaspekt zu sehen und anzusprechen, wodurch einerseits weitere, hier nicht interessierende Aspekte des Objekts ausgeblendet werden knnen, andererseits andere Objekte, die das gleiche Interface aufweisen, identisch behandelt werden knnen, auch wenn sie ansonsten ganz andere Interfaces haben. Ein mnnlicher, deutschsprachiger Maurer kann also mit identischen Algorithmen behandelt werden wie die deutschsprachige Lehrerin, sofern diese nur das Deutsch-Interface ansprechen, also z.B. in einem Programm, das die Personen in deutscher Grammatik oder Rechtschreibung testet. Weiterhin wird dieses Programm auch dann immer noch funktionieren, wenn die Lehrerin spter dann auch noch zur Schachspielerin wird, da dieses neue Interface ebenso irrelevant fr den Test ist wie z.B. das bereits frher bekannte Lehrer-Interface. UNO-Objekte knnen also spter neue Interfaces hinzufgen, ohne dass Programme, die die Objekte benutzen, ihre Funktion einben. Dies gilt natrlich nicht, wenn bei einem UNO-Objekt einmal garantierte Interfaces entfernt oder die Interfaces selbst gendert werden. Solche nderungen betreffen Rckgabewerte und Parameter, aber auch die definierte Art und Weise, wie die einzelnen Methoden im Fehlerfall reagieren. Es ist aber ein Ziel von UNO, dass Anwendungen, die UNO-Objekte verwenden, ohne nderung funktionsfhig bleiben, auch wenn die Objektimplementierungen durch neuere Versionen ausgetauscht oder stark verndert werden. Daher definiert das UNO-Konzept eine Reihe von Regeln, wie mit Interfaces umgegangen werden darf. Zunchst unterscheidet UNO zwischen published und unpublished Interfaces. Fr erstere garantieren die Entwickler, dass die Interfaces in Zukunft nicht mehr verndert werden. Eine Applikation, die UNO-Objekte nur ber solche Interfaces anspricht, mu also in Zukunft weder neu kompiliert noch gendert werden, selbst wenn die Implementierungen hinter den Interfaces komplett ausgetauscht oder massiv verndert werden. Fr Interfaces der zweiten Art gibt es diese Garantie nicht. Sie knnen natrlich trotzdem auch in Anwendungen verwendet werden, allerdings besteht ein gewisses Risiko, dass es in nchster Zeit (typischerweise bis zum nchsten Major Release von StarOffice) noch ein paar nderungen geben kann, die dann den Anwendungsentwickler zwingen, seine Anwendung entweder neu zu kompilieren oder sogar seinen Code an nderungen im Interface anzupassen. Das ndern von published Interfaces ist also ein schwerwiegender Programmierfehler, das gilt aber auch fr das Entfernen von garantierten Interfaces aus der Schnittstelle eines Objekts, da der Anwendungsentwickler sich ja darauf verlt, dass das verwendete Objekt dieses untersttzt. Dies wre im obigen Beispiel das deutschsprachig Interface. Ein solches Interface ist dann ein garantiertes Interface (aus Sicht des Objekts: notwendig, mandatory). Das erwhnte Schachspieler-Interface ist ein nicht garantiertes (aus Sicht des Objekts: optionales) Interface. Das Hinzufgen solcher Interfaces zu der Schnittstelle eines Objekts oder das ihr Entfernen daraus ist erlaubt, da Anwendungsentwickler sich nicht darauf verlassen drfen, dass das Interface untersttzt wird. Falls sie ein optionales Interface dennoch benutzen wollen, mssen sie zur Laufzeit die Existenz dieses Interface in der Schnittstelle berprfen (wofr UNO entsprechende Mittel bereitstellt, die von der jeweils in der Anwendung verwendeten Programmiersprache abhngen). Welche Interfaces eines Objekts garantiert sind und welche nicht, ist ebenso Bestandteil der Schnittstelle dieses Objekts wie die Definition der Interfaces selbst. Aus dem deklarierten API kann der Anwendungsprogrammierer ganz genau entnehmen, welche Teile davon absolut verlsslich sind und welche nicht. Diese Thematik wird im Kapitel ber Services behandelt.

Vor StarOffice 8 erstellte Interfaces waren immer automatisch published im Sinne der obigen Beschreibung, ohne dass sie explizit so bezeichnet wurden. Erst ab StarOffice 8 wird diese Unterscheidung vorgenommen, wobei natrlich alle bis dahin existierenden Interfaces als published bernommen wurden. Man sollte daher immer die Dokumentation des StarOffice 8 SDK verwenden, um diesbezgliche Verwirrungen zu vermeiden. Der Basic-Programmierer muss sich (wie noch gezeigt wird) auf der Ebene seines Codes hufig gar nicht mit Interfaces befassen. Trotzdem mssen Basic-Programmierer das Konzept verstehen, damit sie die Referenzdokumentation des StarOffice API lesen und benutzen knnen, denn diese basiert auf den Interfaces. PUBLISHED/UNPUBLISHED: klarer

2.3 Die UNO Interface Definition Language (IDL)


Interfaces von UNO-Objekten werden in einer Beschreibungssprache formuliert, der Interface Definition Language (IDL). Deren Syntax hnelt der objektorientierter Programmiersprachen wie Java oder C++ und enthlt elementare (int, string, bool etc.) und strukturierte Datentypen, Konstanten, Ableitungen etc. Da sie sich nur mit der Beschreibung von Schnittstellen beschftigt, enthlt sie nur die dafr bentigten Sprachelemente, aber keine Elemente, die man zum Schreiben von Programmen bentigt (wie z.B. Control Statements). Die Definition eines Interface in dieser abstrakten, programmiersprachenunabhngigen Form knnte dann, auf das Wesentliche reduziert, wie folgt aussehen:
module com { module sun { module star { module frame { // (1) // (2) published interface XLoadable: com::sun::star::uno::XInterface { void initNew() raises( DoubleInitializationException, com::sun::star::io::IOException, com::sun::star::uno::Exception ); // (3) // (4)

void load( [in] sequence<com::sun::star::beans::PropertyValue> lArguments )// (5) raises( DoubleInitializationException, com::sun::star::io::IOException, com::sun::star::uno::Exception ); }; }; }; }; };

Dieses Interface definiert Funktionalitt, mit der ein Objekt wahlweise in einen definierten Initialisierungszustand gebracht oder aus einer nicht nher spezifizierten Quelle geladen werden kann. Ein Anwendungsbeispiel dafr wre ein Dokument, das entweder mit Datei-Neu oder mit Datei-ffnen erzeugt werden kann. Einer Konvention folgend haben alle Interface-Namen als ersten Buchstaben ein X (im Gegensatz zu allen anderen Typen der UNOIDL). Die mit Nummern in Kommentaren markierten Zeilen weisen Merkmale auf, die grundlegende Konzepte der UNOIDL benutzen. Diese werden im Folgenden erlutert: (1) UNOIDL verwendet das Konzept der name spaces (die hier als modules bezeichnet werden), das C++ oder Javaentwicklern bekannt ist (letzteren als packages), dem Basicprogrammierer aber eher fremd sein drfte. Die Motivation fr dieses Konzept ist, dass man in einem prinzipiell offenen System wie UNO die Namen von Interfaces nicht zentral vergeben kann, zufllige Namensbereinstimmungen aber vermeiden muss, da Namen von Interfaces wie die aller anderen Symbole natrlich eindeutig sein mssen. Durch die Verlngerung der Namen mit name spaces soll dies erreicht werden. So kann ein Interface MyInterface sowohl im name space module1 als auch im name space

module2 existieren, module1.MyInterface und module2.MyInterface sind verschiedene Symbole. Natrlich ist durch die bloe Verwendung von name spaces die Eindeutigkeit noch nicht garantiert, schlielich knnen Namensbereinstimmungen auch innerhalb der name spaces auftreten. Innerhalb einer geschlossenen Gruppe von Entwicklern sollte es kein Problem sein, die Verwendung der name spaces und Symbolnamen zu kontrollieren, aber UNO ist wie erwhnt prinzipiell offen, daher kann man nicht von einer geschlossenen Gruppe ausgehen. So wird ergnzend die Konvention benutzt, dass die verwendeten name spaces durch einen Prfix erweitert werden, der eine jeweils hinreichend geschlossene Gruppe von Entwicklern kennzeichnet, innerhalb derer dann eine Kontrolle sichergestellt werden kann. Die Vergabe des Prfix erfolgt dabei hnlich der von Internet Domains, d.h. die Namen der entwickelnden Organisation oder Firma ist ein Teil davon. com.sun.star ist dabei z.B. fr UNOIDL Symbole reserviert, die von der Firma Sun fr StarOffice definiert wurden. Eine Firma foo, die fr ein Projekt bar Symbole definieren will, sollte dann com.foo.bar als Prfix verwenden. Nach dem Prfix folgt dann das Package (die logische Gruppe), zu der das Symbol gehrt. So gibt es unterhalb der Hierarchie com.sun.star beispielsweise die Packages frame und text fr Symbole aus dem Framework oder der Textverarbeitung. (2) Das definierte Interface ist published, d.h. es ist ffentlich zugesichert und darf sich daher in Zukunft nicht mehr ndern, damit alle Programme, die es benutzen, auch in Zukunft ohne Neukompilationen oder gar Code-nderungen funktionieren knnen, so wie oben beschrieben. Fehlt das Wort published, handelt es sich um ein Interface, das sich evtl. in nchster Zeit noch etwas ndern kann. Man kann es verwenden, muss aber damit rechnen, dass man bis zum nchsten StarOffice Release noch Code-nderungen vornehmen muss. Weiterhin sieht man, dass in dieser Zeile hinter dem so definierten Interface noch der Name eines weiteren Interface steht. Diese Schreibweise kennzeichnet eine Ableitung, wieder ein Konzept, dass C++ und Javaprogrammierern bekannt ist, dem Basicprogrammierer aber eher nicht. Durch die Ableitung von einem anderen Interface erbt ein Interface alle Methoden des letzteren (auch als Basis-Interface bezeichnet), d.h. dessen Methoden gehren auch zu denen des abgeleiteten Interface. In unserem Beispiel hat also das Interface com::sun::star::frame::XLoadable neben den zwei oben definierten Methoden noch die des Interface com::sun::star::uno::XInterface (mehr zu diesem Interface spter). Ab StarOffice 8 sind auch Mehrfachableitungen mglich, d.h. ein Interface kann mehrere Basis-Interfaces haben. (3) Diese Zeile definiert eine Methode. Der Rckgabewert ist hier void (in Basic also: kein Rckgabewert), aber natrlich sind im allgemeinen auch andere Datentypen mglich, sowohl Basistypen wie string oder int, aber auch zusammengesetzte Typen oder Interfaces. Mehr zu den UNO-Datentypen findet sich in einem spteren Kapitel. (4) Dieser Teil gehrt mit zur Definition der Methode, er definiert die mglichen Exceptions, die ein C++ oder Javaprogrammierer von einem Objekt, das dieses Interface implementiert, beim Aufruf dieser Methode im Fehlerfalle erwarten muss. Damit ist schon gesagt: UNO verwendet Exceptions um Fehler zu melden, keine Error Codes. Viele Programmiersprachen wie Java und C++ haben eine direkte Untersttzung dafr, die UNO nutzen kann. In anderen Fllen, wo das nicht mglich ist, wie im Basic, mssen Exceptions von der UNO Runtime Library fr die jeweilige Sprache behandelt werden. In StarOffice Basic beispielsweise werden alle Exceptions grundstzlich vom Interpreter gefangen und in eine interne Fehlerbehandlung umgesetzt. Auch Exceptions sind UNO-Datentypen, die spter noch erlutert werden. (5) Die folgenden Zeilen definieren eine weitere Methode, diesmal eine, die Parameter empfngt. Unterschieden wird dabei zwischen reinen Eingabe , Ausgabe sowie Ein/Ausgabe-

Parametern, jeweils durch ein [in], [out] oder [inout] gekennzeichnet. Der bergebene Parameter hier ist vom Typ sequence, also ein Array-Parameter. Wie der auf die jeweilige Programmiersprache abgebildet wird, wird spter beschrieben. NAMEN knnen spter nicht gendert werden, sinnvolle und schne verwenden! Jede einzelne solcher in der IDL dokumentierten Einheiten wird in UNO als Typ (type) bezeichnet. Ein Typ kann also z.B. ein bestimmter struct oder ein bestimmtes Interface sein. Mehr zu den wichtigsten Typen spter. Die IDL-Dateien aller in StarOffice verwendeten Typen sind Bestandteil des StarOffice Software Development Kit (SDK). Das SDK enthlt auch Werkzeuge, um aus diesen Dateien verschiedene andere Dateien zu erzeugen, die man fr die Benutzung der Typen in den verschiedenen Programmiersprachen, aber auch in UNO selbst (Typinformationen) bentigt. Welche Dateien das im einzelnen sind, hngt natrlich von der verwendeten Sprache ab.

2.4 Services
Die UNOIDL kennt im Gegensatz zu Java oder C++ keine Klassen und Objekte, stattdessen neben den Interfaces auch das Konzept der Services. Die Idee dahinter ist, dass es Kombinationen von Interfaces gibt, die in bestimmten Zusammenhngen hufig benutzt werden. Diese Kombination stellt dann einen service dar, der auch in UNOIDL als UNO-Typ deklariert wird:
module com { module sun { module star { module document { published service OfficeDocument { interface com::sun::star::frame::XModel; interface com::sun::star::util::XModifiable; interface com::sun::star::frame::XStorable; interface com::sun::star::view::XPrintable; [optional] interface com::sun::star::frame::XLoadable; [optional] interface XEventBroadcaster; [optional] interface XEventsSupplier; [optional] interface XDocumentInfoSupplier; [optional] interface XViewDataSupplier; [optional] interface com::sun::star::view::XPrintJobBroadcaster; [property, optional] boolean AutomaticControlFocus; [property, optional] boolean ApplyFormDesignMode; [property, optional, readonly] string RuntimeUID; }; }; }; }; };

Ein derart deklarierter Service ist zunchst einmal etwas sehr abstraktes, er fasst mehrere Aspekte eines Objekts zu einem neuen, bergeordneten zusammen, der Aspekt Officedokument also die Aspekte Model, Storable, Modifiable, Printable. Jeder Aspekt fr sich kann in einem bestimmten Zusammenhang ausreichend sein, um mit dem Objekt zu arbeiten, z.B. wird sich ein Print Server nur fr den Aspekt Printable interessieren, es gibt aber offensichtlich genug Anwendungsflle, wo alle genannten Aspekte zusammen bentigt werden. Genauso wie bei Interfaces sagt man: Das Objekt O implementiert den Service S. Ein Objekt kann aber prinzipiell nicht nur mehrere Interfaces, sondern auch mehrere Services implementieren. Der Service com::sun::star::document::OfficeDocument enthlt 4 garantierte Interfaces und 5 optionale. Des weiteren enthlt er drei (optionale) Properties. Der Zugriff auf Properties ist abhngig von der verwendeten Programmiersprache und wird im Kapitel ber Typen in UNO sowie in denen zu den einzelnen Programmiersprachen erlutert. Wenn man sieht, welche Elemente optional sind und welche nicht, findet man nicht immer eine einleuchtende Begrndung. Das ist auch nicht verwunderlich, denn in vielen Fllen (so auch hier) ist das eine historische gewachsene Deklaration. So ist es durchaus sinnvoll, den Support fr Dokument Events Bindings (XEventsSupplier) und Metadaten (XDocumentInfoSupplier) optional zu

deklarieren, da das sehr einschrnkend wre, dies von allen denkbaren Dokumenten zu verlangen. Optional meint hier, dass die Untersttzung dieses Interface in einem Objekt, das den Service implementiert, unter Umstnden sinnvoll, aber nicht zwingend erforderlich ist, es hat also eine semantische Motivation. Der Support fr das XLoadable Interface ist aber nur deshalb optional, weil zum Zeitpunkt des ursprnglichen Entwurfs dieses Service ein entsprechendes Interface noch nicht existierte und das Laden eines Dokuments ber ein Hilfsobjekt vorgenommen wurde. Mittlerweile existiert nun ein Interface, mit dem man das Laden direkt am Dokument veranlassen kann, ein Hinzufgen dieses Interface als nicht-optionales wrde aber dazu fhren, dass Code, der diesen Service und dieses Interface benutzt, nur in der neueren Version von StarOffice, nicht aber in einer lteren funktioniert, obwohl die Dokumentation das Gegenteil suggeriert (denn auch die ltere Version liefert einen solchen Service, nur fehlt dem dann das Interface!). Das sieht anders aus, wenn das hinzugefgte Interface als optional deklariert wird. Wenn ein Programmierer dieses Interface an einem Objekt benutzen will, muss er erst das Objekt fragen, ob es das Interface untersttzt, und wenn das Objekt das verneint, andere Wege beschreiten. Dieser Code funktioniert natrlich auch mit der lteren Version. Optional meint hier, dass es ltere Implementierungen dieses Service geben kann, die das Interface nicht untersttzen, es hat also mehr eine versionierende Motivation. Eine andere Methode, Services um neue Interfaces zu erweitern, ist es, weitere Services zu definieren, die den zu erweiternden mit enthalten, sowie zustzlich die gewnschten Interfaces. Dadurch, dass dieser Service einen neuen Namen erhlt, sind alle Anforderungen bezglich Kompatibilitt erfllt: ein solcher Service existiert nicht in der lteren StarOffice-Version, der Programmierer muss also zunchst versuchen, den neuen Service zu bekommen und im NichtErfolgsfall mit dem alten vorlieb nehmen. Die Service-Deklaration wrde etwas so aussehen:
module com { module sun { module star { module document { published service OfficeDocument2 { service OfficeDocument; interface com::sun::star::frame::XLoadable; }; }; }; }; };

Wie man sieht, wird hier nicht wie bei Interfaces Ableitung verwendet, sondern der Basis-Service wird als Bestandteil (member) des erweiterten deklariert. Ein Service, der einen anderen enthlt, untersttzt dann auch dessen Methoden und Properties, zustzlich dazu alle Methoden der hinzugefgten Interfaces und alle hinzugefgten Properties. Man darf hier auch nicht auf irgendeine Implementationsvererbung schlieen, lediglich die Spezifikationen der beiden Services werden hier zusammengefasst. (Anmerkung: der Service OfficeDocument2 ist im Gegensatz zu den anderen hier gezeigten Beispielen hypothetisch und existiert nicht.) Aber nicht nur zu diesem Zweck kann man Services als Teil von anderen Services deklarieren, das Einbetten von Services in andere dient meistens der Spezialisierung: aus einem relativ generischen Service (hier: OfficeDocument) wird durch zustzliche Funktionalitt eine bestimmte Ausprgung geschaffen. Ein Beispiel ist der Service, der die Dokumente von StarOffice Calc charakterisiert:
module com { module sun { module star { module sheet { published service SpreadsheetDocument { service com::sun::star::document::OfficeDocument; interface com::sun::star::lang::XMultiServiceFactory; interface com::sun::star::frame::XModel; interface com::sun::star::document::XActionLockable; interface com::sun::star::document::XLinkTargetSupplier; interface com::sun::star::util::XProtectable; interface com::sun::star::sheet::XSpreadsheetDocument; interface com::sun::star::sheet::XCalculatable;

[readonly, property] com::sun::star::container::XNameAccess SheetLinks; [readonly, property] com::sun::star::container::XNameAccess DDELinks;

interface com::sun::star::sheet::XDocumentAuditing; interface com::sun::star::sheet::XConsolidatable; interface com::sun::star::sheet::XGoalSeek; interface com::sun::star::drawing::XDrawPagesSupplier; interface com::sun::star::style::XStyleFamiliesSupplier; interface com::sun::star::util::XNumberFormatsSupplier; [readonly, property] com::sun::star::sheet::XNamedRanges NamedRanges; [readonly, property] com::sun::star::sheet::XDatabaseRanges DatabaseRanges; [readonly, property] com::sun::star::sheet::XLabelRanges ColumnLabelRanges; [readonly, property] com::sun::star::sheet::XLabelRanges RowLabelRanges; [readonly, property] com::sun::star::sheet::XAreaLinks AreaLinks;

}; }; }; }; };

Analoge Services gibt es natrlich auch fr die anderen Dokumenttypen von StarOffice wie z.B. com::sun::star::text::TextDocument fr Writer-Dokumente. Das Wesen von Services und insbesondere ihre Beziehung zu Objekten wird verstndlicher, wenn man sich ansieht, wie ein Programmierer Zugriff auf sie erhlt. UNO bietet dem Programmierer einen sog. Service Manager an. Dies ist ein UNO-Objekt, ber dessen Interface com::sun::star::lang::XMultiServiceFactory man andere UNOServices erzeugen kann. Dafr mssen diese sich vorher auf irgendeine Art und Weise dem Service Manager bekannt gemacht haben, z.B. durch Erzeugen von Eintrgen in einer Service Registry beim Installieren einer UNO-Komponente. Fr die Zusammenarbeit mit der Service Registry (Registrierung) und dem Service Manager (Instantiierung) implementiert ein solcher Service das Interface com::sun::star::lang::XServiceInfo, das spter noch nher erlutert wird.
module com { module sun { module star { module lang { published interface XMultiServiceFactory: com::sun::star::uno::XInterface { com::sun::star::uno::XInterface createInstance( [in] string aServiceSpecifier ) raises( com::sun::star::uno::Exception ); com::sun::star::uno::XInterface createInstanceWithArguments( [in] string ServiceSpecifier, [in] sequence<any> Arguments ) raises( com::sun::star::uno::Exception ); sequence<string> getAvailableServiceNames(); }; }; }; }; };

Die Methode createInstance erzeugt das gewnschte Objekt und gibt eine Referenz auf ein Interfaces dieses Objekts zurck (wie das in den verschiedenen Programmiersprachen aussieht, wird im nchsten Kapitel erlutert). Damit das fr jedes beliebige Objekt funktioniert, gleich welche Interfaces dieses implementiert, muss es also ein Basis-Interface geben, das alle Objekte implementieren, nmlich com::sun::star::uno::XInterface, wie am Rckgabewert der Methode createInstance zu sehen. Fr UNO wurde die Entscheidung getroffen, dieses dadurch sicherzustellen, indem einfach alle Interfaces von com::sun::star::uno::XInterface abgeleitet werden. Dies kann man an beiden bisher gezeigten Interface-Beispielen sehen. Beginnend mit dem SDK fr StarOffice 8 muss man diese Ableitung nicht mehr explizit in die IDL-Datei schreiben, die Ableitung wird einfach automatisch ergnzt, wenn mit Hilfe der SDK-Tools die Typinformation und die sprachabhngigen Dateien erzeugt werden. Eine weitere Methode im Interface com::sun::star::lang::XMultiServiceFactory ist createInstanceWithArguments, die es erlaubt, dem Objekt bei der Erzeugung noch ein paar Parameter mitzugeben, die hier als sequence<any> bergeben werden. Was es damit auf sich hat, wird spter erlutert.

Die dritte Methode schlielich ist getAvailableServiceNames. Wie leicht zu erraten erhlt man durch sie eine Liste aller Service-Namen, fr die man von diesem Service Manager ein Objekt erhalten kann. Am Prinzip des Service Managers zeigt sich auch das eigentliche und wesentliche Element des Service-Konzepts: wenn ein Programmierer ein Objekt mit bestimmter Funktionalitt benutzen will, instantiiert er dafr dann nicht eine konkrete Implementierung (wie er es tte, wenn er ein Java oder C++ - Objekt erzeugen wrde), sondern einen Service, der ihm die gewnschte Funktionalitt garantiert. Natrlich versteckt sich dahinter dann auch eine konkrete Implementierung, diese kann aber prinzipiell gendert oder ausgetauscht werden, ohne dass der Programmierer das wissen mte. Wenn fr einen Service spter einmal eine neue, bessere Implementierung zur Verfgung steht, mu diese nur am Service Manager registriert werden, damit alle Anwendungen diese automatisch nutzen knnen. Im Falle der direkten C++ oder Java-Programmierung mten die Anwendungen dafr gendert werden. Wie man an den Service Manager selbst kommt, hngt davon ab, welche Programmiersprache man benutzt und wie der eigene Code aufgerufen wird: Ein UNO-Objekt bekommt ihn bei seiner Konstruktion bergeben Eine UNO basierte Anwendung, die zwar UNO-Objekte benutzt, aber selbst keines ist, erzeugt ihn bei der notwendigen UNO-Initialisierung (Bootstrapping) In manchen Programmiersprachen (z.B. Basic) ist er Teil des Runtime Environments. Vom Service Manager erhlt man ein Objekt, das den gewnschten Service implementiert, indem man seine Methode createInstance aufruft und dabei den Service Name bergibt (Beispiele dafr folgen spter). Der Service com::sun::star::sheet::SpreadSheetDocument ist ein solcher Service, nicht aber der Service com::sun::star::document::OfficeDocument. Dieser ist vielmehr ein abstrakter Service, der nur eine Gruppierung von Interfaces und Properties beschreibt. Einen solchen Service erhlt man immer als Rckgabewert (oder Out-Parameter) eines Methodenaufrufs, also hier z.B. einer Methode, die ein Dokument erzeugt. Der Rckgabewert einer solchen Methode ist immer ein Interface, auf der Code-Ebene hat der Begriff Service also nur dokumentarische Bedeutung: indem man beschreibt, dass eine Methode das Interface XMyInterface eines Objekts zurckgibt, das den Service MyService implementiert, kann der Programmierer der Dokumentation von MyService entnehmen, welche Interfaces er an dem erhaltenen Objekt voraussetzen darf und welche eventuell vorhanden sein knnten. Nun knnte man meinen, dass ein solcher abstrakter Service auch sehr gut (oder sogar viel besser) selbst als Interface beschrieben werden knnte, das wiederum von anderen Interfaces abgeleitet ist (nmlich von den nicht optionalen Interfaces des abstrakten Service, den das Interface ersetzen soll). Und in der Tat ist das eigentlich auch die bessere Beschreibungsweise. Da aber vor StarOffice 8 die Mehrfachableitung von Interfaces nicht erlaubt war, wurden abstrakte Services als Ersatz benutzt. In StarOffice 8 drfen Interfaces nun auch von mehreren anderen abgeleitet werden, daher ist diese Einschrnkung nicht mehr gegeben. Daher wurde mit StarOffice 8 ein neuer, klarerer Service-Begriff eingefhrt. Ein solcher neuartiger service wird immer von einem Service Manager erzeugt (ist also ein echter Service) und implementiert genau ein Interface, das dann selbst wiederum von beliebig vielen anderen Interfaces abgeleitet sein kann. Auf diese Weise wird die Trennung von Implementierung (Service) und Schnittstelle (Interfaces und Properties) noch deutlicher herausgearbeitet. Die Verwendung der mehrfach erbenden Interfaces hat den groen Vorteil, dass der Programmieraufwand bei der Benutzung der Interfaces stark verringert wird, wie im nchsten Kapitel erlutert wird. Der Nutzen wird noch dadurch erhht, dass die neuartigen Services eine alternative Art der Erzeugung anbieten, mit Methoden, die eine Referenz auf genau das implementierte Interface des Service zurckgeben und nicht nur eine Referenz auf das bliche Basis-

Interface com::sun::star::uno::XInterface (s.u.). Wenn ein Objekt in einer neuen Version neue Interfaces oder Properties untersttzt, kann man bei altmodischen Services entweder dieses neue Interface der Servicespezifikation hinzufgen, es aber als optional kennzeichnen (wie im Beispiel des OfficeDocument Service zu sehen) oder aber man kreiert einen neuen Service, der den alten umfat und zustzlich das neue Interface oder Property enthlt. Neuartige Services implementieren aber immer genau ein Interface, daher knnen sie keine optionalen Interfaces haben. Das ist aber auch im Sinne des neuen Konzepts, das mit den mehrfach erbenden Interfaces auf hhere Typsicherheit setzt. Daher steht einem bei neuartigen Service nur der zweite Weg der Erweiterung offen, wenn man neue Interfaces an einem Objekt auch per IDL dokumentieren mchte, nmlich die Erzeugung eines neuen Interface und Service. Zwar kann das Interface selbst optionale Elemente enthalten, aber diese knnen nicht nachtrglich hinzugefgt werden, sie sind integraler Bestandteil des Typs. optional wird also nur noch semantisch motiviert gebraucht, nicht versionierend. Streng genommen hat dieses Wort aber ohnehin nur dokumentarischen Charakter, insofern verliert man damit kein essentielles Feature. Zustzlich kann natrlich auch ein neuartiger Service Properties haben, diese drfen auch optional sein wie bei den altmodische Services, allerdings werden diese jetzt als attribute an dem Interface, das der Service implementiert, deklariert. Der Gedanke ist, dass Attribute zur Schnittstelle gehren und dass daher die Service-Definition der falsche Ort ist. Attribute werden ebenso wie Properties im Kapitel ber UNO-Typen nher erlutert. Eine Definition sieht dann beispielsweise so aus:
module com { module sun { module star { module mail { interface XMailMessage: com::sun::star::uno::XInterface { [attribute, readonly] string SenderAddress; [attribute] string ReplyToAddress; void addRecipient([in] string sRecipientAddress); void addCcRecipient([in] string sRecipientAddress); void addBccRecipient([in] string sRecipientAddress); sequence<string> getRecipients(); sequence<string> getCcRecipients(); sequence<string> getBccRecipients(); [attribute] string Subject; [attribute] com::sun::star::datatransfer::XTransferable Body; void addAttachment([in] MailAttachment aMailAttachment); sequence<MailAttachment> getAttachments(); }; service MailMessage: XMailMessage { create([in] string sTo, [in] string sFrom, [in] string sSubject, [in] com::sun::star::datatransfer::XTransferable xBody); createWithAttachment([in] string sTo, [in] string sFrom, [in] string sSubject, [in] com::sun::star::datatransfer::XTransferable xBody, [in] MailAttachment aMailAttachment); }; }; }; }; };

Dieses Beispiel zeigt auch, dass Services nun Methoden zu ihrer Konstruktion anbieten knnen, die, wie schon erwhnt nicht mehr einfach nur com::sun::star::uno::XInterface, sondern das implementierte Interface zurckgeben und so den Programmieraufwand bei der Benutzung des Service stark reduzieren, wie im nchsten Kapitel erlutert. Diese Konstruktoren erlauben darberhinaus auch die bergabe genau definierter Argumente bei der Erzeugung, nicht nur eine nicht-typsichere Sequence<any> wie im Falle der createInstanceWithArgumentsMethode des Service Manager. Da der neuartige Service-Begriff auerdem auch wesentlich klarer und verstndlicher ist, werden alle in Zukunft neu definierten Services ausschlielich solche des neuartigen Typs sein. Neu eingefhrte

Services, die nicht genau ein Interface implementieren, wird es in Zukunft nicht mehr geben, also vor allem auch keine zustzlichen abstrakten Services mehr, stattdessen werden mehrfach erbende Interfaces benutzt, um Interfaces zu gruppieren. Natrlich sind die neuartigen Services nicht so einfach erweiterbar, d.h. im Falle substantieller Erweiterungen wird man nicht um die Definition neuer Interfaces und Services herumkommen, aber die hhere Typsicherheit und der dadurch leichter zu schreibende und potentiell bessere Code berwiegen, auerdem bleibt das API durch die Mglichkeit, die neuen Interfaces von den alten abzuleiten, gut wartbar und ist in der Benutzbarkeit der alten Variante mit optionalen Interfaces nicht unterlegen. Leider knnen bereits existierende abstrakte Services wie der oben beschriebene Service com::sun::star::document::OfficeDocument nicht einfach durch entsprechende Interfaces, die von allen Interfaces erben, die der abstrakte Service umfasst, ersetzt werden, da UNO ja garantiert, dass published Typen nicht nachtrglich entfernt werden. Aus dem gleichen Grund knnen alle bisher existierenden altmodischen echten Services nicht durch neuartige ersetzt werden. Es wird daher ein Nebeneinander der verschiedenen Arten von Services geben, wobei z.T. einzelne Objekte neben dem altmodischen auch einen neuartigen Service bzw. ein entsprechendes mehrfach erbendes Interface anbieten werden. Auf diese Weise kann neuer Anwendungscode, der nicht mit lteren Versionen von StarOffice arbeiten muss, die neuen Service-Namen und die neuen Interfaces benutzen, alter Anwendungscode oder solcher, der auch mit bereits existierenden StarOfficeVersionen laufen soll, benutzt dann eben die alten Service-Namen.

2.5 Typen in UNO


Neben den bereits erwhnten Interfaces und Services kennt UNO noch eine ganze Reihe weitere Typen, die im Folgenden kurz erlutert werden. Mehr zu einzelnen dieser Typen findet sich dann bei der Beschreibung der Umsetzung dieser Typen in die jeweilige Programmiersprache und in der IDLReferenz im Anhang. Ebenso wie Interfaces knnen auch alle anderen benutzerdefinierten Typen published oder unpublished sein.
Interfaces

Jedes in UNOIDL deklarierte Interface stellt einen UNO-Typ dar, fr den auch Typinformation vorhanden ist. Im Gegensatz zu den Interfaces werden Werte der anderen Typen in Methodenaufrufen im RemoteFall (also ber Prozessgrenzen hinweg) immer by value bergeben, d.h. es werden Kopien davon in den anderen Prozess transportiert (und dabei ggf. in die der Sprachanbindung der jeweiligen Zielapplikation genehme Form umgewandelt), bei Interfaces wird nur eine Art Hlle (ein sogenannter Proxy) im Zielprozess erzeugt, ein Objekt in der jeweiligen Programmiersprache, das alle Methodenaufrufe an das eigentliche Objekt ber eine UNO-Verbindung weiterreicht. Ein solcher Proxy ist dabei immer nur fr das jeweilige Interface gltig und kann nicht fr einen direkten Zugriff auf Methoden von anderen Interfaces des gleichen Objekts verwendet werden. Dieser Unterschied hat Konsequenzen fr die Remote Performance der jeweiligen Typen und fr die Art und Weise, wie mit Interfaces umgegangen wird. Eine wichtige Frage in Zusammenhang mit Interfaces ist die nach der Objektidentitt. Wenn man zwei Interfaces (gleichen oder verschiedenen Typs) hat, ist es manchmal wichtig zu wissen, ob sie beide zu dem gleichen Objekt gehren. Ein Beispiel sind Methoden, mit deren Aufruf sich Listener abmelden. Das aufgerufene Objekt muss dann herausfinden, ob das Objekt, das sich hier abmeldet, mit einem der bereits angemeldeten identisch ist, damit es dieses aus seiner Liste entfernen kann. Objektidentitt wird ber Funktionen des Runtime Environments der jeweiligen Sprachanbindung geprft, Details finden sich daher in den entsprechenden Kapiteln.

Elementare Typen

Dies sind Typen wie boolean, short, long, float, string. Details dazu in der Tabelle im nchsten Kapitel.
Der Datentyp type

Ein Teil des StarOffice API bentigt die explizite Bereitstellung von Typ-Information, z.B. die im Basic-Interpreter verwendete Introspection von Objekten. Fr solcherlei Information stellt UNO den Datentyp type bereit, dessen Werte jeweils einen mglichen UNO-Datentyp reprsentieren. Auch im spter diskutierten queryInterface-Konzept findet Typ-Information Verwendung.
Der Datentyp any

Eine ganze Reihe von UNO-Interfaces sind generischen Typs, z.B. Interfaces, die Container verwalten. Damit diese Daten beliebigen Typs aufnehmen knnen, bentigt man einen UNO-Typ, der alle anderen aufnehmen kann. Hier ein Beispiel fr einen Container, dessen Elemente ber einen Index identifiziert werden:
module com { module sun { module star { module container { published interface XElementAccess: com::sun::star::uno::XInterface { type getElementType(); boolean hasElements(); };
published interface XIndexAccess: com::sun::star::container::XElementAccess

{ long getCount(); any getByIndex( [in] long Index )


raises( com::sun::star::lang::IndexOutOfBoundsException, com::sun::star::lang::WrappedTargetException ); };

}; }; }; };

Der Rckgabewert, mit dem ein Element ber die Methode getByIndex aus dem Container geholt wird, ist vom Typ any. Das ist ein Typ, der die Werte aller anderen Typen (also nicht nur Interface-Referenzen wie im obigen Beispiel, auch short, string, struct etc.) annehmen kann und zustzlich noch Information in Form eines type darber bereithlt, von welchem Typ der angenommene Wert ist. Das Basis-Interface com::sun::star::container::XElementAccess hat eine Methode getElementType, die Auskunft darber gibt, von welchem Typ ein Element dieses Containers ist (er enthlt also nur Elemente gleichen Typs). Man kann also je nach Typ entsprechenden Code schreiben, um das Element korrekt zu verarbeiten.
Der Datentyp sequence

Eine sequence ist eine homogene Zusammenstellung von Werten eines einzigen UNO-Typs mit einer variablen Anzahl von Elementen. Im Prinzip ist eine solche Sequence mit einem Container vergleichbar, der wie oben seine Element ber com::sun::star::container::XIndexAccess zugnglich macht. Der entscheidende Unterschied ist, dass man den Container implementierten muss, whrend die sequence Teil der UNOSchicht ist, und dass Container-Interfaces wie alle Interfaces immer by reference bergeben werden, whrend eine Sequence grundstzlich per value bergeben, ihre Elemente also bei einem Remote-Aufruf kopiert werden. Das hat zunchst einmal einen erhhten Aufwand zur Folge, der aber unter bestimmten Umstnden dadurch berkompensiert wird, dass dann die eigentliche Verarbeitung der Elemente komplett im Zielprozess erfolgen kann, whrend im Falle des Containers jeder einzelne Elementzugriff einen Remote Call erfordert.

In den meisten Programmiersprachen wird eine sequence als Array abgebildet. Ein Beispiel fr den Gebrauch in UNOIDL findet sich im vorherigen Kapitel in der Definition des Interface com::sun::star::mail::XMailMessage.
Enumerationen (enum) und Constant Groups

Dies sind zwei Konstrukte, die auf den ersten Blick ziemlich hnlich aussehen, da sie beide eine Gruppierung von Werten darstellen. Im Gegensatz zu den Constant Groups knnen Enumerationen aber spter nicht mehr erweitert werden. Enumerationen knnen auf jeden Fall dort zur Anwendung kommen, wo die Umstnde die mglichen Werte eines bestimmten Kontexts begrenzen, also z.B. die Namen der Wochentage oder die der Monate. In anderen Fllen wird man mglicherweise erst einmal eine Constant Group in Erwgung ziehen, sofern nicht andere berlegungen, die unten noch erlutert werden, eine Enumeration doch ratsamer erscheinen lassen. Ein Beispiel fr eine Enumeration ist die Anzahl der Werte fr die Paperorientation, also z.B. die Ausrichtung des Papiers beim Drucken:
module com { module sun { module star { module view { published enum PaperOrientation { PORTRAIT, LANDSCAPE }; }; }; }; };

Ein Beispiel fr eine Constant Group findet sich z.B. bei den verschiedenen Mglichkeiten, wie mit dem Updaten von Links in einem Dokument beim Laden verfahren werden soll:
module com { published { const const const const }; module sun { module star { module document { constants LinkUpdateModes long long long long NEVER = 0; MANUAL = 1; AUTO = 2; GLOBAL_SETTING = 3;

}; }; }; };

Die Formulierung als Constant Group lt einem die Mglichkeit, spter auch problemlos weitere Varianten anzubieten, allerdings kann man am API dann nicht erkennen, ob diese von dem Objekt auch wie erwartet verarbeitet werden. Letztendlich stellt eine Constant Group eigentlich immer das Abbild einer Implementierung dar und hat so mehr dokumentarischen Wert, whrend eine Enumeration eher eine unabhngig von mglichen Implementierungen feststehende Wertemenge ist. Das hat dann letztlich die Konsequenz, dass die Implementierung von APIs, die Werte von Constants Groups verarbeiten, hinreichend robust implementiert werden mssen (sprich: nur bekannte Werte verarbeiten und unbekannte mit einer Fehlermeldung quittieren) und der aufrufende Code damit rechnen muss, dass es bei jedem Wert theoretisch einen Fehler geben kann, denn auer per Dokumentation kann man fr keine Implementierung erfahren, welche Werte sie untersttzt. Das ist bei Enumerationen anders, hier darf der Aufrufer vertrauen, dass jeder Wert der Enumeration jeder Implementierung eines sie benutzenden API auch bekannt ist. Man kann das auch so ausdrcken: Enumerationen sind typsicher, Konstanten nicht. So kann man an eine Methode, die als Input-Parameter eine Enumeration erwartet, nur genau die Werte bergeben, die zu der Enumeration gehren, bei einem Input-Parameter, dem man Integer-Konstanten bergibt, kann prinzipiell jeder beliebige Wert bergeben werden, sodass man sich nicht sicher sein kann, dass auch sinnvolle Werte verwendet werden. Es gilt also abzuwgen, ob eher eine hhere Typsicherheit (und damit potentiell besserer Code) oder

Erweiterbarkeit das Ziel sein sollen. Da der Fokus des StarOffice API in Zukunft eher in Richtung Typsicherheit und damit besserer und einfacher zu schreibender Code geht, wird man dann auch viele Enumerationen finden, wo zumindest theoretisch in Zukunft Erweiterungen mglich sind. Sollte das tatschlich passieren, mten dann neue APIs erstellt werden.
Strukturierte Datentypen (struct)

struct-Typen sind zusammengesetzte Datentypen, deren einzelne Elemente Werte jedes vorher genannten Typs annehmen knnen. Jeder in UNOIDL deklarierte struct stellt einen UNO-Typ dar, fr den auch Typinformation vorhanden ist. Ein Beispiel:
module com { { com::sun::star::util::URL FeatureURL; string FeatureDescriptor; boolean IsEnabled; boolean Requery; any State; }; }; }; }; }; module sun { module star { module frame {
published struct FeatureStateEvent: com::sun::star::lang::EventObject

Dieser struct enthlt neben einem string und 2 boolean auch ein any und einen weiteren struct. Ab StarOffice 8 kennt UNO auch sogenannte polymorphic structs, die aber bisher kaum verwendet werden. Nheres dazu findet man im Developers Guide.
Exceptions in UNO

Der Typ exception zeigt dem Aufrufer einer Methode einen Fehler an. Sein exakter Typ ist ein erster Hinweis auf den Grund fr diesen Fehler, weitere Informationen knnen als Bestandteile der exception wie bei einem struct gegeben sein. Auch wenn Exceptions in ihrem Aufbau strukturierten Datentypen hneln, werden sie z.B. nicht als Argumente von Methoden oder als Teile von structs sondern ausschlielich im Rahmen der Fehlerbehandlung verwendet. Alle UNO-Exceptions leiten sich von der Basis com::sun::star::uno::Exception ab. Welche Exception von einer Methode geworfen werden knnen, wird in der IDL-Datei des Interface deklariert, zustzlich kann jede Methode eine com::sun::star::uno::RuntimeException werfen, auch wenn das nicht explizit deklariert wurde. Ein Beispiel:
module com { module sun { module star { module uno { published exception Exception { string Message; com::sun::star::uno::XInterface Context; }; }; }; }; }; module com { module sun { module star { module io { published exception IOException: com::sun::star::uno::Exception { };

Diese Exception zeigt einen Fehler bei einer I/O-Operation an. Da sie wie alle UNO-Exceptions von com::sun::star::uno::Exception abgeleitet ist, kann sie auch einen Text zur nheren Beschreibung der Fehlerursache und eine Referenz auf das den Fehler meldende Objekt enthalten.

Services

Siehe entsprechendes Kapitel. Services sind eigentlich kein UNO-Typ im eigentlichen Sinne, allerdings werden sie wie richtige UNO-Typen in der UNOIDL deklariert. Fr neuartige Services werden auch Daten (ber die Konstruktoren) in der Typinformationsdatei abgelegt.
Properties

Mit Properties bezeichnet man gemeinhin gewisse Elemente von Objekten, die man sich abholen oder setzen kann. UNOIDL kennt zwei Mglichkeiten, das auszudrcken: bei altmodischen Services als property und bei neuartigen Services als attribute am Interface, das der Service implementiert. Beispiele dafr wurden im Kapitel ber Services gezeigt. Das Property-Konzept wird von der Sprachanbindung in die jeweilige Programmiersprache bersetzt. ((Die blichen Implementierungssprachen fr UNO-Objekte sind Java und C++. In beiden Sprachen gibt es keine direkten Zugriffe auf UNO-Properties, sie werden vielmehr ber Methoden eines Interface angesprochen.)) Alle Objekte, die einen Service mit Properties implementieren, mssen dafr das Interface com::sun::star::beans::XPropertySet untersttzen:
module com { module sun { module star { module beans { published interface XPropertySet: com::sun::star::uno::XInterface { com::sun::star::beans::XPropertySetInfo getPropertySetInfo(); void setPropertyValue( [in] string aPropertyName, [in] any aValue ) raises( com::sun::star::beans::UnknownPropertyException, com::sun::star::beans::PropertyVetoException,
com::sun::star::lang::IllegalArgumentException, com::sun::star::lang::WrappedTargetException );

any getPropertyValue( [in] string PropertyName ) raises( com::sun::star::beans::UnknownPropertyException,


com::sun::star::lang::WrappedTargetException );

void addPropertyChangeListener( [in] string aPropertyName, [in] com::sun::star::beans::XPropertyChangeListener xListener ) raises( com::sun::star::beans::UnknownPropertyException,
com::sun::star::lang::WrappedTargetException );

void removePropertyChangeListener( [in] string aPropertyName, [in] com::sun::star::beans::XPropertyChangeListener aListener ) raises( com::sun::star::beans::UnknownPropertyException,
com::sun::star::lang::WrappedTargetException );

void addVetoableChangeListener( [in] string PropertyName, [in] com::sun::star::beans::XVetoableChangeListener aListener ) raises( com::sun::star::beans::UnknownPropertyException,
com::sun::star::lang::WrappedTargetException );

void removeVetoableChangeListener( [in] string PropertyName, [in] com::sun::star::beans::XVetoableChangeListener aListener ) raises( com::sun::star::beans::UnknownPropertyException,
com::sun::star::lang::WrappedTargetException );

}; }; }; }; };

ber dieses Interface knnen Properties gelesen und gesetzt werden sowie eine Information ber alle vorhandenen Properties und ihre Typen erfragt werden (die anderen Methoden sollen hier erst einmal auer Betracht bleiben). Bei einem attribute, das ja immer Teil eines Interface ist, wird im Java oder C++-Interface automatisch fr jedes attribute eine get und eine set Methode hinzugefgt (bzw. nur eine getMethode, wenn es readonly ist). Beispiel:

interface XMyInterface { [attribute, readonly] string FirstAttribute; [attribute] string SecondAttribute; void doSomething(); };

Dies ist aus Objektsicht analog zu folgender Deklaration:


interface XMyInterface { string getFirstAttribute(); string getSecondAttribute(); void setSecondAttribute( [in] string value ): void doSomething(); };

Im Gegensatz zum Interface XPropertySet sind die Getter- und Setter- Methoden typsicher, da sie keine Any-Parameter verwenden, es werden also eine ganze Reihe von mglichen Problemen im Zusammenhang mit diesen vermieden.

2.6 UNO in den verschiedenen Programmiersprachen


Prinzipiell ist die Verwendung UNO-basierter Typen wie bereits erwhnt nicht an eine bestimmte Programmiersprache gebunden, da UNO Mittel dafr bereitstellt, die Typen in die jeweilige Sprache zu bersetzen. Dadurch knnen z.B. die Objekte von StarOffice, die berwiegend in C++ implementiert sind, in Sprachen wie Java oder StarOffice Basic angesprochen werden. Es ist auch anders herum mglich, in Java implementierte Objekte in das weitgehend C++-basierte StarOffice einzugliedern. Wie die einzelnen Typen in die jeweilige Sprache abgebildet werden, wird spter noch im einzelnen erlutert. Damit eine bestimmte Programmiersprache aber auch tatschlich UNO-Typen benutzen kann, mu sie UNO-fhig gemacht werden. Es gibt dabei mehrere Mglichkeiten: (1) Man erstellt ein sogenanntes Language Binding fr die gewhlte Sprache. Beispiele dafr sind die Bindings fr Java und C++ (2) Man benutzt eine interpretierte Sprache, deren Interpreter in einer Programmiersprache implementiert ist, die wiederum selbst UNO-fhig ist. Beispiele dafr sind das StarOffice Basic (Interpreter in C++) und der JavaScript-Interpreter aus dem StarOffice Scripting Framework, der in Java implementiert ist. (3) Man verwendet eine andere Middleware und deren Language Bindings, sofern es eine Brcke von UNO zu dieser Technologie gibt. So gibt es eine UNO-Bridge zu .NET, wodurch UNO-Typen auch in .NET-Sprachen wie C# benutzt werden knnen. (4) Einen Sonderfall stellt die OLE Automation Bridge dar. Es gibt zwar keine allgemeine COM Bridge fr UNO, aber zumindest der fr OLE Automation ntige Teil wird untersttzt. Man kann daher auch aus allen Sprachen, die Objekte ber OLE Automation scripten knnen, UNO-Typen benutzen, komfortabel ist das aber nur in Sprachen, die die Schnittstelle von Objekten interpretierend benutzen, also z.B. Visual Basic. Ein Language Binding ermglicht es, eine UNO-Umgebung innerhalb des Prozesses einer Anwendung zu starten und dort einen eigenen Service Manager zu instantiieren und mit seiner Hilfe eigene UNO-Objekte zu erzeugen oder sich mit einer anderen UNO-Anwendung zu verbinden und ber diese Verbindung (die auch ber Rechnergrenzen hinweg funktioniert!) deren Service Manager zu empfangen und damit UNO-Objekt zu erzeugen. Je nach Sprache pat sich das Binding nahtlos durch Benutzung vorhandener Sprachkonstrukte wie z.B. Templates oder durch Zuhilfenahme einiger spezieller Runtime-Funktionen ein, entsprechend gehren zu dem Binding sowohl deklarative Elemente wie C++ Header Files als auch Libraries oder jar files, die zu der das Binding benutzenden Applikation hinzugelinkt werden mssen. Zusammen mit den bereits erwhnten vom SDK aus den IDL-Dateien erzeugten Typinformationen bersetzt

das Binding die UNOIDL Sicht in die analogen Konstrukte der jeweiligen Programmiersprache, diese Sprache mu also alle IDL-Features (z.B. Methoden, Structs und Ableitungen) abbilden knnen. In diesem Sinne wre Basic eigentlich als UNO-Programmiersprache vllig ungeeignet, allerdings ist StarOffice Basic in C++ implementiert und kann daher die UNO-Fhigkeiten dieser Sprache ausnutzen, indem die Implementierung des Interpreters die UNO-Konstrukte fr die interpretierte Sprache aufbereitet. Dabei gehen natrlich einige Dinge verloren, in erster Linie das Konzept der Interfaces (da Basic keine abstrakten Klassen und Ableitungen kennt): StarOffice Basic sieht ein Objekt immer als die Summe aller seiner Interfaces, es kennt aber weder Services noch Interfaces als Typen, sondern nur einen Typ Object. Das hat Konsequenzen fr die Art und Weise, wie der Programmierer mit Objekten umgeht. In Programmiersprachen wie Java und C++ sind UNO-Objekte wie in der IDL nicht durch Objekte reprsentiert, sondern durch Referenzen (bzw. Pointer) auf Interfaces, die wiederum in C++ durch eine abstrakte Basisklasse, in Java aber durch ein Java Interface abgebildet werden. In beiden Fllen sind diese Referenzen daher streng typisiert und man kann an ihnen nur solche Methoden aufrufen, die Bestandteil des jeweiligen Interfaces sind, der verwendete Compiler wird ansonsten den Code einfach nicht fehlerfrei bersetzen knnen. Es nutzt einem gar nichts zu wissen, dass das Objekt, von dem man eine Referenz auf sein Interface X1 hat, doch einen Service S implementiert und daher ganz sicher auch das Interface X2 untersttzt, man braucht zum erfolgreichen Aufruf der Methoden aus Interfaces X2 eine Referenz auf das Interface, um den Compiler zufrieden zu stellen. Diese Auswertung zur Compile-Zeit bezeichnet man auch als early binding. Was im Gegensatz dazu late binding ist, werden wir noch am Beispiel von Basic kennenlernen. Hat man nun eine beliebige Referenz auf ein Interface eines Objekts und will dann ein anderes Interface des gleichen Objekts benutzen, muss man es darum bitten, eine entsprechende Referenz auf dieses herauszugeben. Dafr kennt UNO das queryInterface-Konzept. Wie dieses umgesetzt wird, ist abhngig von der jeweiligen Programmiersprache, manche (wie StarOffice Basic) bentigen es gar nicht, da sie nicht mit Interfaces arbeiten, sondern immer mit Objekten. Die Essenz dieses Konzepts ist, dass die Sprachanbindung eine Funktion zur Verfgung stellt, der man eine Referenz auf das zu befragende Objekt (genauer auf eines seiner Interfaces) und die Typinformation (den UNO type) fr das gewnschte Interface zur Verfgung stellt und dann eine Referenz auf dieses gewnschte Interface zurckerhlt. Wenn das Objekt das gewnschte Interface nicht untersttzt, erhlt man eine leere Referenz. Ursprnglich wurde dieses Konzept dadurch ausgedrckt, dass eine entsprechende Methode queryInterface im Basis-Interface com::sun::star::uno::XInterface existiert, von dem ja alle anderen Interfaces abgeleitet sind, sodass man diese Methode an beliebigen Referenzen auf irgendwelche Interfaces aufrufen kann und dann als Rckgabewert die Referenz auf das gewnschte Interface erhlt. Das ist allerdings im Nachhinein betrachtet keine glckliche Wahl gewesen. Wie sich noch zeigen wird, ist die Umsetzung des Konzepts als Detail der Sprachanbindung zu sehen, daher sollte man es auch losgelst von einem UNO-Interface betrachten, das ja selbst sprachunabhngig ist. Das Interface com::sun::star::uno::XInterface hat seine Berechtigung lediglich als BasisInterface aller anderen Interfaces, seine Methoden bildet UNO nicht in allen Sprachanbindungen ab, auch wenn diese Methode in der Implementierung der Anbindungen, die diese Methode nicht prsentieren, intern verwendet werden. Durch die stndige Notwendigkeit, queryInterface fr jedes Interface eines Service, das man benutzen will, aufzurufen, wird natrlich ein erheblicher Mehraufwand an Code ntig. Zwar erlaubt das sehr flexible Entscheidungen zur Laufzeit darber was ein Objekt kann und wie man dann mit ihm arbeiten kann, es hat sich im Laufe der Zeit aber gezeigt, dass man ein queryInterface nur dort verwenden mchte, wo es wirklich ntig ist, also nach Mglichkeit nicht, wenn man die garantierten Interfaces eines Service benutzen will. Diese Erkenntnis fhrte dann auch zur Entwicklung der mehrfach erbenden Interfaces und der neuartigen Services in StarOffice 8. Wenn bei

der Erzeugung eines Service ber einen seiner Konstruktoren gleich eine Referenz auf ein Interface zurckgegeben wird, das alle Methoden umfat, die der Service ber seine Interfaces garantiert, bentigt man fr deren Benutzung berhaupt kein queryInterface mehr. Natrlich kann das Objekt immer noch mit der Zeit um andere Interfaces wachsen, die man dann per queryInterface erfragen kann. Man behlt also Flexibilitt, wo es ntig ist und gewinnt Einfachheit, wo es mglich ist. In StarBasic ist, wie bereits erwhnt, kein Pendant zu Interfaces vorhanden, und anstelle von Interface-Referenzen verwendet man Objects. Bei einem solchen Typ wird erst zur Laufzeit entschieden, welche Methoden und Properties es besitzt, man kann also beliebige Methoden an ihm aufrufen und der Code wird problemlos bersetzt. Wenn das Objekt allerdings die gewhlte Methode nicht hat, wird es einen Laufzeitfehler geben. Dies ist das, was man als late Binding bezeichnet. Um das zu erreichen, benutzt der Basic-Interpreter die Fhigkeit von UNO-Objekten, sich inspizieren zu lassen, d.h. es zur Laufzeit (am lebenden Objekt) zu befragen, was es kann. Der dazu notwendige Code ist Teil des UNO-fhigen Basic Interpreters, der natrlich auch den Code beisteuert, mit dem die Methoden des UNO-Objekts ber das C++ Language Binding ausgefhrt werden. Um Laufzeitfehler beim Aufruf optionaler Interfaces zu vermeiden, bietet Basic aber auch eine Mglichkeit, ein Objekt zu befragen, ob es ein bestimmtes Interface untersttzt, bevor man dann versucht, Methoden aus ihm zu benutzen. Dazu und zu weiteren Basic-Details spter mehr. Hier eine Tabelle der elementaren UNO-Typen und ihren Pendants in den wichtigsten von UNO untersttzten Programmiersprachen. UNO void boolean byte short unsigned short long unsigned long hyper unsigned hyper float double char string Beschreibung Leerer Typ, nur benutzt als Rckgabewert oder in einem any (s.u.) Boolscher Wert, true oder false signed 8-bit integer type signed 16-bit integer type unsigned 16-bit integer type signed 32-bit integer type unsigned 32-bit integer type signed 64-bit integer type unsigned 64-bit integer type IEC 60559 single precision floating point type IEC 60559 double precision floating point type void boolean byte short (-) int (-) long (-) float double Java void sal_Bool sal_Int8 sal_Int16 sal_uInt16 sal_Int32 sal_uInt32 sal_Int64 sal_uInt64 float double sal_Unicode C++ Boolean Integer Integer (-) Long (-) (-) (-) Single Double String Basic

16-bit Unicode character type char (genauer: UTF-16 code units) Unicode string type; String aus Unicode-Zeichen

java.lang.String rtl.OUString

Die Verwendung von unsigned Typen ist unerwnscht (deprecated), es hat sich im Nachhinein als unglcklich herausgestellt, sie anzubieten, da nicht alle Programmiersprachen damit umgehen knnen. Entfernen kann man sie allerdings aus UNOIDL nicht mehr, da sich schon in bereits vorhandenen Typen Verwendung finden. Die Benutzung von unsigned Integer Typen in Java oder Basic kann aber durchaus funktionieren, weil Integer-Typen grundstzlich ineinander umgewandelt werden knnen, sofern der Wertebereich des Zieltyps dabei nicht berschritten wird. Es ist also ohne weiteres mglich, den Wert 40000 in einem Basic-Programm an eine Methode zu bergeben, die einen unsigned short erwartet. Basic wird die Zahl zunchst in einen Long aufnehmen und beim Aufruf der UNO-Methode versuchen, sie in ein sal_uInt16 umzuwandeln (zur Erinnerung: der Interpreter ist in C++ implementiert!). Das wird hier problemlos funktionieren, whrend bei einem Wert 80000 natrlich dann ein Fehler auftritt. hnliches gilt fr die Benutzung von hyper Typen in Basic (also 64 Bit Integer). In einer weiteren Tabelle nun die nicht-elementaren UNO-Typen und ihre Pendants in den wichtigsten von UNO untersttzen Programmiersprachen. UNO enum constant group struct sequence Beschreibung Enumeration Gruppe von Konstanten class interface Java enum name space struct C++ Basic Long Long

Aus anderen Typen zusammengesetzter class Typ UNO-quivalent zu array Arrays

Object

template< class t > Array com::sun::star::uno::Sequence< t > Variant

any

java.lang.object, Container, der jeden class beliebigen Typ com::sun::star::uno::Any com.sun.star.uno. aufnehmen kann Any Meta-Typ: identifiziert einen Typ, Teil eines jeden any class com.sun.star.uno. class com::sun::star::uno::Type Type class interface class (abstract) class

type

exception interface

Einige dieser Mappings lassen sich in einer Tabelle nur sehr verkrzt wiedergeben, eine nhere Diskussion erfolgt in den Kapiteln ber die einzelnen Language Bindings. Die verschiedenen Anbindungen an Programmiersprachen bieten auch komfortable Wege, mit anyTypen umzugehen. Wenn man wei, welchen Typ in einem erhaltenen any steckt (z.B. weil es das Element eines Containers ist, den man selbst gefllt hat), mchte man gerne diesen any einfach einer Variable dieses Typs zuweisen knnen, ohne mhsam selbst Typabfragen vornehmen zu mssen. Da das any ja wie erwhnt auch die notwendige Typinformation enthlt, kann eine solche einfache Zuweisung durch das dem any entsprechende Sprachelement der jeweiligen Programmiersprache auch implementiert werden. Whrend das in C++ durch einen Operator der Any-Klasse erledigt wird, nutzt man in Java die Klasse com.sun.star.uno.AnyConverter aus dem Language

Binding. In Basic ist auer in wenigen Fllen, die mit den unterschiedlichen Typsystemen von Basic und UNO zu tun haben, berhaupt kein explizites Behandeln von Any-Typen (Variant) ntig. Services haben allerdings in keiner Programmiersprache ein quivalent. Altmodische Services dienen ausschlielich der Dokumentation und fassen einfach mehrere Aspekte eines Objekts (Interfaces, Properties) zu einem neuen, bergeordneten zusammen. Neuartige Services beschreiben nur, mit welchen Service-Namen man am Service Manager Services instantiieren kann, lediglich ihre Konstruktoren werden als statische Methoden einer Klasse abgebildet, die aber selbst nicht instantiierbar ist.

3 StarOffice Programmierung in Java


3.1 Allgemeines
Im Folgenden werden einige Java-Klassen erwhnt, die Bestandteil der Java UNO Runtime Library sind. Diese werden hier nur soweit erlutert, wie es fr das Verstndnis des Diskussionsgegenstands erforderlich ist. Eine ausfhrliche Referenz dieser Klassen findet sich im SDK. Der Java-Programmierer hat prinzipiell drei Mglichkeiten, StarOffice und seine Objekte zu benutzen: er implementiert selbst einen UNO-Service als Komponente, die sich ber gewisse Schnittstellen in StarOffice integriert; er schreibt ein Java-Programm, das sich mit StarOffice verbindet; er schreibt ein Java-Programm und bindet es ber das StarOffice Scripting Framework als Macro ein. Der erste Fall wird in einem eigenen Kapitel ber Komponentenentwicklung behandelt so wie der dritte Fall in einem solchen ber das Scripting Framework, ber das man sich im Developers Guide informieren kann. Hier soll es um den zweiten Fall gehen. Um UNO-Objekte in einem eigenen Java-Programm erzeugen zu knnen, bentigt man einen Service Manager, wie im Kapitel ber Services beschrieben. Ein Service Manager kann durch Bereitstellung einiger Konfigurations und Typinformationsdateien erzeugt werden, genauso wie es StarOffice selbst beim Starten tut. Interessanter ist es natrlich, den Service Manager des StarOffice Prozess zu verwenden, denn ber den kommt man an die Objekte heran, die das Office ausmachen. Dazu mu zunchst eine Instanz von StarOffice gestartet und/oder zur laufenden Instanz eine geeignete Verbindung (Socket oder Pipe) aufgebaut werden. ber diese Remote-Verbindung kann UNO dann eine Referenz auf den Service Manager transportieren. Seit StarOffice 8 mu der Programmierer sich um diese Details nicht mehr selbst kmmern, da es das sogenannte Simple Bootstrapping gibt. Der Zugriff auf den StarOffice Service Manager erfolgt dann prinzipiell mit einer einzigen Zeile Code:
public class FirstUnoContact { public static void main(String[] args) { try { com.sun.star.uno.XComponentContext xContext = com.sun.star.comp.helper.Bootstrap.bootstrap(); com.sun.star.lang.XMultiComponentFactory xServiceManager = xContext.getServiceManager(); } catch (java.lang.Exception e){ e.printStackTrace(); } finally { System.exit(0); } } }

(Anmerkung: in StarOffice-Versionen vor StarOffice 8 gab es das Simple Bootstrapping nicht und die Herstellung einer Verbindung war deutlich aufwendiger. Details dazu finden sich im Developers Guide im Kapitel UNO Concepts.) com.sun.star.comp.helper.Bootstrap ist eine Klasse der Java UNO Runtime, die in ihrer bootstrap-Methode folgendes tut: sucht die StarOffice-Installation (das ist systemabhngig implementiert); startet StarOffice aus dieser Installation mit einer geeigneten Kommandozeile, die es

veranlasst, eine Verbindung (named pipe) aufzumachen; sollte schon ein StarOffice laufen, wird die Kommandozeile an diese Instanz weitergereicht, sodass dann das bereits laufende Office die Verbindung ffnet; die gestartete zweite Instanz beendet sich dann; verbindet sich mit StarOffice ber die named pipe und etabliert eine UNO Remote Connection; fordert ber diese Verbindung den Component Context an und liefert einen Proxy dafr an den Aufrufer zurck. Ein Component Context stellt quasi ein Environment dar, in dem eine Komponente luft. Dieses Environment setzt sich aus einer Reihe von Objekten zusammen, die alle vom Component Context ber ihren Namen abgefragt werden knnen, der Service Manager ist eines davon. Da er von sehr zentraler Bedeutung ist, gibt es im Interface dafr eine spezialisierte und typsichere Methode, whrend alle anderen Objekte ber eine generische Schnittstelle abgefragt werden:
module com { module sun { module star { module uno { published interface XComponentContext : XInterface { any getValueByName( [in] string Name ); }; }; }; }; };

com::sun::star::lang::XMultiComponentFactory getServiceManager();

Im Prinzip kann es beliebig viele solche Komponentenkontexte geben, und jeder UNO-Service wird mit einem solchen erzeugt, das heit, er wird ihm bei der Konstruktion bergeben. Mit dem Service Manager, den das Objekt sich von seinem Kontext abholen kann, kann das Objekt dann selbst andere erzeugen. Hier knnte z.B. einem Objekt ein Kontext mit einem eingeschrnkten Service Manager bergeben werden, der nur ganz bestimmte Objekt erzeugen kann. Mehr ber Komponentenkontexte findet sich im Kapitel UNO Concepts des Developers Guide. Beim Starten von StarOffice legt dieses selbst einen Kontext an und erzeugt damit seine Objekte, und dieser Kontext ist der, der auch beim Simple Bootstrapping erhalten wird und so dem JavaProgrammierer zur Verfgung steht. Der erhaltene Service Manager kann nun zur Erzeugung von Objekten benutzt werden. Ein sehr zentrales Objekt im StarOffice API ist das Desktop-Objekt, das u.a. einen Zugriff auf alle offenen Dokumentfenster gewhrt, aber auch zum Laden und Erzeugen von Dokumenten samt Fenstern benutzt werden kann. Die Erzeugung dieses Objektes, das den Service com::sun::star::frame::Desktop implementiert, geschieht folgendermaen (Service Manager und Context aus obigem Beispielcode):
java.lang.Object desktop = xServiceManager.createInstanceWithContext( "com.sun.star.frame.Desktop", xContext);

Der Rckgabewert von createInstanceWithContext ist vom Typ java.lang.Object, die Java- Reprsentation einer Referenz auf ein com::sun::star::uno::XInterface (aus der UNOIDL). Wenn man jetzt mit diesem Objekt arbeiten will, mu man von ihm zunchst eine Referenz auf das bentigte Interface erfragen, denn der Java Compiler wird einen Aufruf der gewnschten Methoden nicht ber eine java.lang.Object-Referenz zulassen. Dafr enthlt das Java-UNO Language Binding eine entsprechende Methode an einer Runtime-Klasse, die die Implementierung des im letzten Kapitel beschriebenen queryInterface-Konzepts in Java darstellt. Als Beispiel sei der Zugriff auf das Interfaces des Desktop-Objekts gezeigt, das man zum Laden von Dokumenten verwendet:
com.sun.star.frame.XComponentLoader xLoader = (com.sun.star.frame.XComponentLoader) UnoRuntime.queryInterface(com.sun.star.frame.XComponentLoader.class, desktop);

Der Methode UnoRuntime.queryInterface wird der Typ bergeben, den man gerne htte. Dies erfolgt im Beispielcode als java.lang.Class Objekt, das die Java-Klasse bezeichnet, die das UNO-Interface in Java reprsentiert, aber es ist auch eine Variante mit einem

com.sun.star.uno.Type mglich, der direkt das Interface bezeichnet. Weiter wird die Referenz auf das Objekt bergeben, das man nach dem gewnschten Interface befragen mchte. Der erhaltene Wert ist zwar zunchst auch nur ein java.lang.Object, das dann aber mit einem Java type cast auf den gewnschten Typ in die passende Referenz berfhrt werden kann. Es stellt sich die Frage, warum man nicht einfach einen direkten Type Cast auf das gewnschte Interface machen kann. Der Grund dafr, dass das nicht funktioniert, ist, dass dafr in der JavaApplikation das komplette Objekt mit allen seinen Interfaces bekannt sein msste, so wie es bei den innerhalb der Applikation deklarierten Java-Klassen der Fall ist. Dort kann der Compiler ganz einfach am Layout der Klasse ermitteln, wie eine Referenz auf das Interface X in eine auf das Interface Y des gleichen Objekts umgewandelt werden kann. Das java.lang.Object, das eine Referenz auf ein bestimmtes UNO-Interface reprsentiert, ist nur eine Abbildung eines Aspekts des Objekts in die Java-Applikation, es ist wie bereits erwhnt nur ein Proxy fr das eigentliche Objekt. Er ist nur fr das jeweilige Interface gltig, fr das man ihn erhalten hat, UNO mappt immer nur das jeweilige Interface, nicht das komplette Objekt in den Prozess der Java-Applikation. Es ist also gar nicht bekannt, wie ein cast von einem Interface des Objekts zum anderen ausgefhrt werden knnte. Erst die sichere Gewiheit, dass das vom queryInterface-Call zurck gegebene java.lang.Object ein Proxy fr das angeforderte Interface ist, weil das ja in der Methode queryInterface so spezifiziert wurde, erlaubt es, dieses Java-Objekt auf das entsprechende Java-Interface zu casten. Ein queryInterface-Aufruf wird auch benutzt, um von einem Interface zum anderen zu gelangen, also z.B. vom com.sun.star.frame.XComponentLoader-Interface des Desktop-Objekts zu dessen com.sun.star.frame.XFramesSupplier-Interface, das Zugriff auf alle offenen Dokumentfenster gewhrt:
com.sun.star.frame.XFramesSupplier xSup = (com.sun.star.frames.XFramesSupplier) UnoRuntime.queryInterface(com.sun.star.frame.XFramesSupplier.class, xLoader);

Damit ist schon der wichtigste Teil der Java-UNO-Eigenheiten erlutert. Mit dem Wissen um die Art und Weise, wie der Java-Programmierer UNO-Objekte erzeugt und wie er an ihre Interfaces herankommt, kann er mit Hilfe der IDL-Referenz sich das API aller StarOffice-Objekt erschlieen. Im Detail wird er allerdings noch von Fall zu Fall auf Besonderheiten der Art und Weise stoen, wie die UNO-Typen auf Java-Typen abgebildet werden. Die Tabelle im letzten Kapitel gibt darber einen berblick, es folgt noch eine genauere Erluterung.

3.2 Besonderheiten des Java UNO Language Bindings


Abbildung elementarer UNO-Datentypen

Wie bereits im allgemeinen Kapitel ber Datentypen erwhnt, kennt Java keine unsigned IntegerTypen, der Programmierer muss also selbst Vorkehrungen treffen, wenn er durch UNOSchnittstellen mit unsigned-Parametern oder - Rckgabewerten konfrontiert wird. Man kann unsigned Zahlenwerte explizit auf den signed-Typ der gleichen Lnge casten, Java interpretiert dann einfach das Bitmuster der Zahl um. Bei der bergabe dieser signed-Variablen an einen unsigned-Parameter einer UNO Interface-Methode wird durch das Java UNO Runtime Environment das Bitmuster wieder als unsigned zurck interpretiert. Umgekehrt kann man bei der Implementierung einer UNO-Interface Methode in Java einen empfangenen unsigned-Parameter (der ja den Java-Programmierer als signed-Wert erreicht) explizit auf einen positiven Wert des nchstgreren Integer-Typs uminterpretieren.
Abbildung des UNO-Typs string

UNO strings werden auf java.lang.String abgebildet. Dabei gilt es zwei Details zu beachten: im Kontext von UNO drfen keine Null-Referenzen fr Strings verwendet werden

Ein Objekt vom Typ java.lang.String kann eine beliebige Folge von UTF-16 code units reprsentieren, UNO strings sind andererseits eine beliebige Folge von Unicode scalar values. Einige UTF-16 code units (die high-surrogate und low-surrogate code points im Bereich D800-DFFF) haben keine entsprechenden Unicode scalar values und sind daher im Kontext von UNO verboten. Details dazu siehe www.unicode.org.
Abbildung des UNO-Typs type

Der UNO-Typ type wird durch die Java-Klasse com.sun.star.uno.Type reprsentiert. Im UNO-Kontext sind keine null-Referenzen dafr erlaubt. Flschlicherweise wurde diese Klasse nicht als final deklariert. Man sollte sich aber trotzdem nicht von ihr ableiten. Methoden in der Java UNO runtime, die die bergabe eines com.sun.star.uno.Type erwarten, bieten meist auch ein Pendant an, das stattdessen ein java.lang.Class Objekt akzeptiert, da das fr den Java-Programmierer einfacher zu benutzen ist.
Abbildung von UNO-Enumerationstypen

Ein UNO enum -Typ wird auf eine Java Klasse desselben Namens abgebildet, die von der Java UNO Runtime-Klasse com.sun.star.uno.Enum abgeleitet und selbst wiederum final ist. NullReferenzen fr diese Klassen sind im UNO-Kontext nicht erlaubt. Alle deklarierten Werte des enums sind in der Java-Klasse als public static member verfgbar. Die folgende Enumeration:
module com { module sun { module star { module table { published enum CellVertJustify { STANDARD, TOP, CENTER, BOTTOM }; }; }; }; };

hat dann also u.a. den Wert com.sun.star.table.CellVertJustify.STANDARD. Fr eine Erklrung der Implementierungsdetails von UNO-Enumerationstypen in Java sei hier auf die Beschreibung der Java Sprachanbindung im Developers Guide verwiesen.
Abbildung von UNO Constant Groups (constants)

Eine UNO constant group wird in ein Java Interface desselben Namens abgebildet, wobei jeder Konstantenwert ein static field des Interface mit demselben Namen und dem passenden Typ ist. Die folgende UNO Constant Group:
module com { published { const const const const }; module sun { module star { module awt { constants ImageAlign short short short short LEFT = 0; TOP = 1; RIGHT = 2; BOTTOM = 3;

}; }; }; };

wird dann in Java zu:


package com.sun.star.awt; public interface ImageAlign

{ short short short short } LEFT = 0; TOP = 1; RIGHT = 2; BOTTOM = 3;

Abbildung von UNO struct-Typen

Ein UNO struct-Typ wird auf eine Java-Klasse desselben Namens abgebildet. Auch hier sind im UNO-Kontext keine NULL-Referenzen erlaubt. Alle deklarierten Elemente des UNO struct sind in der Klasse als public Fields desselben Namens und des entsprechenden Typs verfgbar. Es gibt einen Default-Konstruktor, der alle Elemente auf einen Defaultwert setzt und einen Konstruktor, der explizite Werte fr jedes Element entgegennimmt. UNO structs knnen auch voneinander abgeleitet werden, entsprechend sind dann auch die generierten Java-Klassen voneinander abgeleitet. Ab StarOffice 8 bietet UNO auch die sogenannten polymorphic structs, die aber bisher im API kaum Verwendung finden. Daher sei hier fr eine Erluterung der Abbildung dieser Typen in Java wieder auf die Beschreibung der Java Sprachanbindung im Developers Guide verwiesen.
Abbildung von UNO sequence

UNO sequence-Typen mit einem gegebenen Elementtyp werden auf Java Arrays des entsprechenden Typs abgebildet. Beispiele: UNO sequence < long > wird abgebildet auf Java int[] UNO sequence < sequence < long > > wird abgebildet auf Java int[][] Im UNO-Kontext sind keine Null-Referenzen auf Arrays erlaubt.
Abbildung von UNO exception

UNO exception-Typen werden auf Java-Klassen desselben Namens abgebildet. Auch hier sind im UNO-Kontext keine Null-Referenzen erlaubt. Alle Java-Klassen, die UNO-Exceptions reprsentieren, entweder von der Java-Klasse fr com.sun.star.uno.Exception oder fr com.sun.star.uno.RuntimeException abgeleitet. Diese beiden Klassen sind wiederum selbst von java.lang.Exception oder java.lang.RuntimeException abgeleitet. Die Exceptions transportieren einen String, der eine Beschreibung des Grunds fr die Exception enthlt sowie mglicherweise eine Referenz auf das Objekt, das die Exception geworfen hat. Ersterer wird wie in Java blich ber die getMessage-Methode der Exception-Klasse erhalten. (Anmerkung: in UNOIDL ist com::sun::star::uno::RuntimeException flschlicherweise von com::sun::star::uno::Exception abgeleitet, was aber ohne praktische Relevanz ist. )
Abbildung von UNO-Interface Typen

Ein UNO Interface Typ wird durch ein Java Interface desselben Namens abgebildet. Wie schon beschrieben stellt das sich hinter dem Interface verbergende Java-Objekt einen Proxy fr genau das zugeordnete Interface dar, der alle Methodenaufrufe an das richtige UNO-Objekt weiterleitet. Anders als bei den Java-Klassen, die UNO sequences, enums, structs etc. reprsentieren, ist eine Null-Referenz ein gltiger Wert fr ein solches Java-Interface und es entspricht einer UNO NullReferenz.

Eine Besonderheit ist das Basis-Interface com::sun::star::uno::XInterface. Dieses wird in der Java Sprachanbindung nur dann auch durch ein entsprechendes Java Interface reprsentiert, wenn es als Basis-Typ fr ein anderes Interface (also rein deklarativ) verwendet wird, ansonsten wird es auf ein java.lang.Object abgebildet, also wenn eine Referenz auf dieses Interface als Element einer sequence oder eines struct oder exception Typs verwendet wird oder wenn sie ein Parameter oder Rckgabewert einer Methode ist. Wenn man verschiedene java.lang.Object-Instanzen hat, die jeweils eine Referenz auf ein UNO-Interface reprsentieren, mchte man gelegentlich berprfen, ob die Interfaces zum gleichen Objekt gehren (Objektidentitt), wie schon im allgemeinen Kapitel ber UNO Datentypen angesprochen. Die Klasse com.sun.star.uno.UnoRuntime bietet dafr die Methode areSame, die zwei java.lang.Object-Referenzen bergeben bekommt. Interfaces enthalten Methoden und Attribute. Die Besonderheiten der letzteren wurden schon zusammen mit den Properties von Services im Kapitel ber UNO-Typen erlutert, aber auch die Abbildung von Methoden in Java weist ein paar Eigenheiten auf. UNO erlaubt es, Parameter als in, out oder inout zu deklarieren. Java untersttzt aber nur die ersteren, daher muss die Java UNO Sprachanbindung zu einem Trick greifen, um dennoch Werte aus der Methode nach auen transportieren zu knnen. Der Parameter, der innerhalb der Methode gesetzt bzw. verndert werden soll, muss gewissermaen eingepackt werden, was hier durch Hineinstecken in ein Array erfolgt. Ein out oder inout-Parameter in UNOIDL wird also auf ein einelementiges Array mit Elementen des jeweiligen Typs abgebildet, dessen einziges Element dem eigentlichen Parameter entspricht. Hier ein Beispiel, wie ein inout-Parameter eines UNO struct Typs in Java behandelt wird. Zunchst die UNOIDL Definition:
struct FooStruct { long nval; string strval; }; interface XFoo { void func1([inout] FooStruct value); void func2([out] sequence<byte> value); };

Das wird in Java zu:


public class public public public } public FooStruct(int nval, String strval) { this.nval = nval; this.strval = strval; } } public interface XFoo extends com::sun::star::uno::XInterface { void func1(FooStruct[] value); void func2(byte[][] value); } FooStruct { int nval; String strval; FooStruct() { strval="";

Man beachte, dass bei einer UNO sequence als Parameter wie in func2 der entsprechende JavaParameter dann ein Array of Arrays ist. Der Javaprogrammierer wird beim Aufruf der Methode func1 an einem Objekt obj, das das Interface XFoo implementiert, folgendermaen vorgehen:
FooStruct[] inoutstruct= new FooStruct[1]; inoutstruct[0]= new FooStruct(); obj.func1(inoutstruct);

Anders herum wird der Programmierer, der dieses Interface in Java implementiert, seinen Code

folgendermaen schreiben:
public void func1(/*inout*/ FooStruct[] value) { value[0] = new FooStruct(); } public void func2(/*out*/ byte[][] value) { value[0] = new byte[0]; }

Abbildung des UNO-Typs any

Der UNO-Typ any wird blicherweise durch ein java.lang.Object reprsentiert. Eine Object-Referenz kann benutzt werden, um sich auf alle denkbaren Java-Typen zu beziehen. Fr primitive Datentypen gibt es Java-Wrapper, die eine Benutzung dieser Typen als Objekte erlauben. Java Objects transportieren ihren eigenen Typ, den man mit ihrer Methode getClass in Form eines java.lang.Class-Objekts erhalten kann. Damit kann ein Java Object alle UNO-Typen in einem any abdecken, deren Abbildung in Java verfgbar sind, allerdings nicht alle denkbaren UNOTypen wie die in Java nicht bekannten unsigned Integer-Typen und den Typ void, und auch nicht Referenzen auf UNO-Interfaces auer com::sun::star::uno::XInterface. Um auch diese Typen typsicher aufnehmen zu knnen, empfiehlt sich die Benutzung der Java UNO Runtime-Klasse com.sun.star.uno.Any. Flschlicherweise wurde diese Klasse nicht als final deklariert. Man sollte sich aber trotzdem nicht von ihr ableiten. Im Zweifelsfall liegt man mit einem com.sun.star.uno.Any als Reprsentation eines UNO any immer richtig, auch wenn durch das Einpacken der Aufwand etwas hher ist, whrend eine unbedachte Verwendung von java.lang.Object gewisse Gefahren birgt. Wenn man eine Referenz auf ein beliebiges Interface als java.lang.Object an eine Methode bergibt, die ein any erwartet, das laut Dokumentation eine Referenz auf ein bestimmtes Interface sein muss, kann es trotzdem funktionieren, wenn die aufgerufene Methode intern einen Auruf von queryInterface benutzt, um die Korrektheit des Typs sicherzustellen. Allerdings ist ein solches Vorgehen nicht vorgeschrieben, sodass der aufrufende Code in einer spteren Implementierungsversion der aufgerufenen Methode, die aus Performancegrnden auf queryInterface verzichtet, dann einfach nicht mehr funktioniert. Null-Referenzen auf com.sun.star.uno.Any sind im UNO-Kontext nicht erlaubt. Wenn man eine Null-Referenz auf ein java.lang.Object an eine Methode bergibt, die ein Any erwartet, wird das als Null-Referenz auf ein com.sun.star.uno.XInterface interpretiert. Die Java UNO Runtime stellt noch eine Klasse namens com.sun.star.uno.AnyConverter zur Verfgung, mit deren Methoden man einfach Anys nach ihrem Typ fragen oder sie typsicher auslesen kann. Sie erhalten ein java.lang.Object als Parameter, aber natrlich knnen sie auch mit einem com.sun.star.uno.Any aufgerufen werden, da dieses ja selbst von java.lang.Object abgeleitet ist. Hier nur eine summarische Auflistung der Methoden (mehr in der Referenzdokumentation):
static static static static static static static static static static static static boolean boolean boolean boolean boolean boolean boolean boolean boolean boolean boolean boolean isArray (java.lang.Object object) isBoolean (java.lang.Object object) isByte (java.lang.Object object) isChar (java.lang.Object object) isDouble (java.lang.Object object) isFloat(java.lang.Object object) isInt(java.lang.Object object) isLong(java.lang.Object object) isObject (java.lang.Object object) isShort(java.lang.Object object) isString (java.lang.Object object) isType (java.lang.Object object)

static static static static static static static static static static static static static

boolean isVoid(java.lang.Object object) java.lang.Object toArray (java.lang.Object object) boolean toBoolean (java.lang.Object object) byte toByte (java.lang.Object object) char toChar (java.lang.Object object) double toDouble (java.lang.Object object) float toFloat(java.lang.Object object) int toInt(java.lang.Object object) long toLong(java.lang.Object object) java.lang.Object toObject (Type type, java.lang.Object object) short toShort(java.lang.Object object) java.lang.String toString(java.lang.Object object) Type toType (java.lang.Object object)

Die Methode toObject bedarf noch einer Erluterung. Der erste Parameter ist der gewnschte Typ, also z.B. ein bestimmter Interface-Typ. Dann wird sichergestellt, dass auch nur dann eine von null verschiedene Referenz zurckgegeben wird, wenn das bergebene any (also hier ein java.lang.Object) auch eine Referenz auf ein Interface genau dieses Type enthlt. Das zurckgegebene Objekt darf dann einfach auf das gewnschte Interface gecastet werden, so wie im letzten Abschnitt am Beispiel des queryInterface-Aufrufes beschrieben.
Abbildung von UNO-Services

Auch wenn Services keine UNO-Typen im eigentlichen Sinne sind, bentigen zumindest solche der neuartigen Form eine Abbildung in der jeweiligen Programmiersprache, wenn man dort die Konstruktoren der Objekt nutzen will. Daher gibt es auch in Java eine Abbildung fr neuartige Services, nicht aber fr die altmodischen. Ein neuartiger UNO service wird in Java reprsentiert durch eine Java-Klasse desselben Namens. Die Klasse hat aber nur eine oder mehrere statische Methoden, die den deklarierten Konstruktoren entsprechen. Wenn keine Konstruktoren deklariert sind, existiert immer ein impliziter Konstruktor, der in Java immer die folgende Form hat:
public static XIfc create(com.sun.star.uno.XComponentContext context) { ... }

wobei XIfc das Interface ist, das der Service implementiert. Der bergebene Parameter ist der Component Context, der im Kapitel ber Services schon erlutert wurde. Bei allen expliziten Konstruktoren wird in der Java-Sprachanbindung dieser Parameter auch automatisch als erster Parameter eingefgt. Wenn in UNOIDL also deklariert wurde:
name([in] Type1 arg1, [in] Type2 arg2) raises (Exception1);

wird daraus in Java:


public static XIfc name(com.sun.star.uno.XComponentContext context, Type1 arg1, Type2 arg2) throws Exception1 { ... }

Der bergebene Component Context darf keine Null-Referenz sein, da der generierte Code des Konstruktors den am Component Context gesetzten Service Manager verwendet, um den Service zu erzeugen. Weitere Argumente von expliziten Konstruktoren werden zur Initialisierung des Objekts verwendet. Es wird also am ServiceManager entweder createInstanceWithContext oder createInstanceWithArgumentsAndContext verwendet. Mehr zu Konstruktoren findet man im Developers Guide im Kapitel ber die Language Bindings.

4 StarOffice-Programmierung in C++
4.1 Allgemeines
Im Folgenden werden einige C++-Klassen erwhnt, die Bestandteil der C++ UNO Runtime Libraries (cppu, cppuhelper, sowie eine compiler und plattformabhngige Library wie msci_uno.dll) sind. Diese werden hier nur soweit erlutert, wie es fr das Verstndnis des Diskussionsgegenstands erforderlich ist. Eine ausfhrliche Referenz dieser Klassen findet sich im SDK.

Neben den erwhnten Libraries ist auch der Code, der fr alle verwendeten UNO-Typen generiert wird, Bestandteil des Language Bindings. All dieser Code ist inline und benutzt die Runtime Libraries. Der C++-Programmierer hat prinzipiell zwei Mglichkeiten, StarOffice und seine Objekte zu benutzen: er implementiert selbst einen UNO-Service als Komponente, die sich ber gewisse Schnittstellen in StarOffice integriert; er schreibt ein C++-Programm, das sich mit StarOffice verbindet; Der erste Fall wird in einem eigenen Kapitel ber Komponentenentwicklung behandelt , hier soll es um den zweiten Fall gehen. Um UNO-Objekte in einem eigenen C++-Programm erzeugen zu knnen, bentigt man einen Service Manager, wie im Kapitel ber Services beschrieben. Ein Service Manager kann durch Bereitstellung einiger Konfigurations und Typinformationsdateien erzeugt werden, genauso wie es StarOffice selbst beim Starten tut. Interessanter ist es natrlich, den Service Manager des StarOffice Prozess zu verwenden, denn ber den kommt man an die Objekte heran, die das Office ausmachen. Dazu mu zunchst eine Instanz von StarOffice gestartet und/oder zur laufenden Instanz eine geeignete Verbindung (Socket oder Pipe) aufgebaut werden. ber diese Remote-Verbindung kann UNO dann eine Referenz auf den Service Manager transportieren. Seit StarOffice 8 mu der Programmierer sich um diese Details nicht mehr selbst kmmern, da es das sogenannte Simple Bootstrapping gibt. Der Zugriff auf den StarOffice Service Manager erfolgt dann prinzipiell mit zwei Zeilen Code (zum Gebrauch des Templates com::sun::star::uno::Reference s.u.):
using com::sun::star::uno::Reference; Reference< com::sun::star::lang::XMultiComponentFactory > xServiceManager; Reference< com::sun::star::uno::XComponentContext > xContext; try { // get the remote office component context xContext = ::cppu::bootstrap(); // get the remote office service manager xServiceManager = xContext->getServiceManager(); } catch ( ::cppu::BootstrapException& ) { // so some error handling } catch ( Exception& ) { // so some error handling }

(Anmerkung: in StarOffice-Versionen vor StarOffice 8 gab es das Simple Bootstrapping nicht und die Herstellung einer Verbindung war deutlich aufwendiger. Details dazu finden sich im Developers Guide im Kapitel UNO Concepts.) ::cppu::bootstrap() ist eine Funktion der C++ UNO Runtime, die folgendes tut: sucht die StarOffice-Installation (das ist systemabhngig implementiert); startet StarOffice aus dieser Installation mit einer geeigneten Kommandozeile, die es veranlasst, eine Verbindung (named pipe) aufzumachen; sollte schon ein StarOffice laufen, wird die Kommandozeile an diese Instanz weitergereicht, sodass dann das bereits laufende Office die Verbindung ffnet; die gestartete zweite Instanz beendet sich dann; verbindet sich mit StarOffice ber die named pipe und etabliert eine UNO Remote Connection;

fordert ber diese Verbindung den Component Context an und liefert einen Proxy dafr an den Aufrufer zurck. Ein Component Context stellt quasi ein Environment dar, in dem eine Komponente luft. Dieses Environment setzt sich aus einer Reihe von Objekten zusammen, die alle vom Component Context ber ihren Namen abgefragt werden knnen, der Service Manager ist eines davon. Da er von sehr zentraler Bedeutung ist, gibt es im Interface dafr eine spezialisierte und typsichere Methode, whrend alle anderen Objekte ber eine generische Schnittstelle abgefragt werden:
module com { module sun { module star { module uno { published interface XComponentContext : XInterface { any getValueByName( [in] string Name ); }; }; }; }; };

com::sun::star::lang::XMultiComponentFactory getServiceManager();

Im Prinzip kann es beliebig viele solche Komponentenkontexte geben, und jeder UNO-Service wird mit einem solchen erzeugt, das heit, er wird ihm bei der Konstruktion bergeben. Mit dem Service Manager, den das Objekt sich von seinem Kontext abholen kann, kann das Objekt dann selbst andere erzeugen. Hier knnte z.B. einem Objekt ein Kontext mit einem eingeschrnkten Service Manager bergeben werden, der nur ganz bestimmte Objekt erzeugen kann. Mehr ber Komponentenkontexte findet sich im Kapitel UNO Concepts des Developers Guide. Beim Starten von StarOffice legt dieses selbst einen Kontext an und erzeugt damit seine Objekte, und dieser Kontext ist der, der auch beim Simple Bootstrapping erhalten wird und so dem JavaProgrammierer zur Verfgung steht. Dieser Service Manager wird hufig auch als Process Service Factory bezeichnet, eine bessere Bezeichnung wre aber die als Service Manager des Default Context. Der erhaltene Service Manager kann nun zur Erzeugung von Objekten benutzt werden. Ein sehr zentrales Objekt im StarOffice API ist das Desktop-Objekt, das u.a. einen Zugriff auf alle offenen Dokumentfenster gewhrt, aber auch zum Laden und Erzeugen von Dokumenten samt Fenstern benutzt werden kann. Die Erzeugung dieses Objektes, das den Service com::sun::star::container::Desktop implementiert, geschieht folgendermaen (Service Manager und Context aus obigem Beispielcode):
com::sun::star::uno::Reference < com::sun::star::uno::XInterface > xDesktop( xServiceManager->createInstanceWithContext("com.sun.star.frame.Desktop", xContext) );

Der Rckgabewert der Methode createInstanceWithContext ist vom Typ com::sun::star::uno::XInterface*, von dessen Bedeutung (und Problematik) schon in den vorhergehenden Kapiteln die Rede war. Durch das Template com::sun::star::uno::Reference (ein Bestandteil der C++ UNO Runtime, siehe folgendes im Kapitel ber Abbildung von Datentypen in C++) wird aus einem solchen Pointer eine (UNO-)Referenz auf dieses Interface erzeugt. Wenn man jetzt mit diesem Objekt arbeiten will, mu man von ihm zunchst eine Referenz auf das bentigte Interface erfragen, denn der C++ Compiler wird einen Aufruf der gewnschten Methoden nicht ber einen com::sun::star::uno::XInterface-Pointer zulassen. Dafr enthlt die Reprsentation dieses Interface im C++-UNO Language Binding die Methode queryInterface(), die die Implementierung des im vorletzten Kapitel beschriebenen queryInterface-Konzepts in C++ darstellt. Noch einmal zur Erinnerung: aus heutiger konzeptioneller Sicht ist das Interface com::sun::star::uno::XInterface nicht wirklich notwendig, es hat seine jeweilige Bedeutung nur im jeweiligen Language Binding! Die C++ UNO Runtime verpackt den Aufruf dieser Methode noch sehr elegant in einen geeigneten Reference-Konstruktor, sodass der Programmierer selbst den Aufruf von queryInterface() in

seinem Code gar nicht bentigt. Als Beispiel sei der Zugriff auf das Interfaces des Desktop-Objekts gezeigt, das man zum Laden von Dokumenten verwendet (xDesktop aus obigem Beispiel):
using com::sun::star::uno::Reference; Reference < com::sun::star::frame::XComponentLoader > xLoader( xDesktop, com::sun::star::uno::UNO_QUERY );

Es stellt sich die Frage, warum man nicht einfach einen direkten Type Cast auf das gewnschte Interface machen kann. Der Grund dafr, dass das nicht funktioniert, ist, dass dafr das komplette Objekt mit allen seinen Interfaces bekannt sein msste, so wie es bei den innerhalb der Applikation deklarierten C++-Klassen der Fall ist. Dort kann der Compiler ganz einfach am Layout der Klasse ermitteln, wie eine Referenz auf das Interface X in eine auf das Interface Y des gleichen Objekts umgewandelt werden kann. Im vorliegenden Falle ist aber immer nur ein Teilaspekt des Klassenlayouts bekannt. Noch deutlicher wird die Problematik bei der Betrachtung von Remote Calls. Die InterfaceReferenz, die eine Referenz auf ein bestimmtes UNO-Interface reprsentiert, ist nur eine Abbildung eines Aspekts des jeweiligen Objekts in die C++-Applikation, es ist im Remote-Fall wie bereits erwhnt nur ein Proxy fr das eigentliche Objekt. Dieser ist nur fr das jeweilige Interface gltig, fr das man ihn erhalten hat, UNO mappt immer nur das jeweilige Interface, nicht das komplette Objekt in den Prozess der C++-Applikation. Es ist also gar nicht bekannt, wie ein cast von einem Interface des Objekts zum anderen ausgefhrt werden knnte. Ein queryInterface-Aufruf wird auch benutzt, um von einem Interface zum anderen zu gelangen, also z.B. vom com::sun::star::frame::XComponentLoader-Interface des Desktop-Objekts zu dessen com::sun::star::frame::XFramesSupplier-Interface, das Zugriff auf alle offenen Dokumentfenster gewhrt:
using com::sun::star::uno::Reference; Reference < com::sun::star::frame::XFramesSupplier > xSup( xLoader, com::sun::star::uno::UNO_QUERY );

Das funktioniert, weil die C++-Reprsentationen aller UNO-Interfaces ber die Basisklasse com::sun::star::uno::XInterface polymorph sind und daher an jedem Interface die Methode queryInterface() aufgerufen werden kann. Wie bereits in vorhergehenden Kapiteln erwhnt ist diese Ableitungsbeziehung eigentlich als Implementierungsdetail des C++ Language Bindings anzusehen, auch wenn viele Interfaces tatschlich auch in UNO IDL von com::sun::star::uno::XInterface abgeleitet sind, was aber mittlerweile eher als Design-Unschnheit zu betrachten ist. Damit ist schon der wichtigste Teil der C++-UNO-Eigenheiten erlutert. Mit dem Wissen um die Art und Weise, wie der C++-Programmierer UNO-Objekte erzeugt und wie er an ihre Interfaces herankommt, kann er mit Hilfe der IDL-Referenz sich das API aller StarOffice-Objekt erschlieen. Im Detail wird er allerdings noch von Fall zu Fall auf Besonderheiten der Art und Weise stoen, wie die UNO-Typen auf C++-Typen abgebildet werden. Die Tabelle im letzten Kapitel gibt darber einen berblick, es folgt noch eine genauere Erluterung.

4.2 Besonderheiten des C++ UNO Language Bindings


Abbildung elementarer UNO-Datentypen

Der Typ boolean wird als sal_Bool abgebildet, mit den erlaubten Werten sal_True und sal_False. Dahinter verbirgt sich ein unsigned char, der natrlich auch andere Werte annehmen kann. Oft geht es gut und alles ungleich 0 wird als sal_True interpretiert, aber streng genommen ist es ein Programmierfehler, im UNO-Kontext irgendeinen anderen Wert als die beiden erlaubten zu verwenden und es kann theoretisch irgendwann zu Fehlern fhren. Die bereits beim Java-Binding erwhnten Probleme mit unsigned-Typen existieren im C++-Binding

nicht, trotzdem muss man um sie wissen, denn eine Implementierung, die mit solchen Typen umgeht, muss wissen, was sie zu beachten hat. Auch knnen die C++-Typen grere Wertebereiche haben als die UNO-Typen, auf die sie gemappt werden. Um Problemen mit Integertypen aus dem Weg zu gehen, sollte man sich an das folgende Vorgehen halten:

Integerwerte, die man empfngt, knnen ohne weitere Prfung verwendet werden Integerwerte, die man zurckgibt (entweder als Return Value oder als Out Parameter) sollten daraufhin berprft werden, ob sie in den UNO-Wertebereich passen, wenn der verwendete Compiler einen gemappten Type verwendet, der einen greren Bereich erlaubt. (Anmerkung: bei aktuell untersttzten Compilern nicht der Fall.) Integerwerte, die man als any erhlt (s.u.) knne auch kleinere Typen enthalten als den erwarteten. Es empfiehlt sich daher, nicht den Typ des Any abzufragen, sondern den AusleseOperator der Klasse com::sun::star::uno::Any zu verwenden, der das schon bercksichtigt. Mehr dazu bei der Beschreibung des any-Mappings.

Eine Besonderheit resultiert aus der Tatsache, dass das C++-Binding die UNO-Typen char und unsigned short auf die nominell unterschiedlichen Typen sal_UniCode und sal_uInt16 abbildet, ersterer aber auf manchen Plattformen nur ein typedef fr letzteren ist.
Abbildung des UNO-Datentyps string

UNO strings werden auf ::rtl::OUString abgebildet. Dabei gilt es zu beachten, dass ein Objekt vom Typ ::rtl::OUString eine beliebige Folge von UTF-16 code units reprsentieren kann, UNO strings sind andererseits eine beliebige Folge von Unicode scalar values. Einige UTF-16 code units (die high-surrogate und low-surrogate code points im Bereich D800-DFFF) haben keine entsprechenden Unicode scalar values und sind daher im Kontext von UNO verboten. Details dazu siehe www.unicode.org. Native Strings mssen mit entsprechenden Methoden der Klasse ::rtl::OUString konvertiret werden, wie z.B. die Methode createFromAscii().
Abbildung des UNO-Typs type

Der UNO-Typ type wird durch die C++-Klasse com::sun::star::uno::Type reprsentiert. ber diese Klasse ist der Zugriff auf alle Informationen mglich, die zu dem betreffenden Typ in der Type Registry abgelegt sind. Das Language Binding generiert fr jeden deklarierten Typ eine berladung der Funktion getCppuType(), fr Interface-Typen auch eine statische Klassenmethode static_Type(), die den Aufruf kapselt. Beispiele:
// type fr sal_Int32 com::sun::star::uno::Type intType = getCppuType(static_cast< sal_Int32 * >(0)); // type fr ::rtl::OUString com::sun::star::uno::Type stringType = getCppuType(static_cast< rtl::OUString * >(0)); // type fr XEnumeration Interface Type xEnumerationType1 = getCppuType( static_cast< Reference< com::sun::star::container::XEnumeration > * >(0)); // quivalent dazu Type xEnumerationType2 = com::sun::star::container::XEnumeration::static_type();

Da die getCppuType-Funktionen fr einige Typen ambiguous sind, gibt es spezielle Funktionen fr diese Typen: getVoidCppuType(), getBooleanCppuType(), getCharCppuType().

Alle diese Funktionen sind wie schon erwhnt inline und befinden sich (auer fr die elementaren Typen) in den generierten Header-Dateien fr den jeweiligen Typ.
Abbildung von UNO Constant Groups (constants) und UNO-Enumerationstypen

Diese Abbildung weist keine Besonderheiten auf, diese UNO-Typen werden ganz wie die normalen C++-Sprachelemente benutzt. Die Module aus UNO IDL spiegeln sich dabei in der Benutzung des scope-Operators wieder:
// xProps sei eine Referenz auf ein PropertySet xProps->setPropertyValue( ::rtl::OUString::createFromAscii( "VertJustify" ), ::com::sun::star::table::CellVertJustify.TOP);

Abbildung von UNO struct-Typen

UNO structs werden in C++ structs mit dem selben Namen abgebildet, jeder Member des UNO struct wird in einen public data member des C++ struct abgebildet. Das Language Binding generiert auch gleich zwei Konstruktoren fr den C++ struct, einen Default-Konstruktor (der alle Member mit einem Default-Wert initialisiert) und einen, der explizite Werte fr alle Member entgegennimmt. Ab StarOffice 8 bietet UNO auch die sogenannten polymorphic structs, die aber bisher im API kaum Verwendung finden. Daher sei hier fr eine Erluterung der Abbildung dieser Typen in C++ wieder auf die Beschreibung der C++ Sprachanbindung im Developers Guide verwiesen.
Abbildung von UNO sequence

UNO sequences werden abgebildet auf ein Class Template:


template < class t > com::sun::star::uno::Sequence < t >.

Die Sequence-Klassen sind eine Referenz zu einem refcounted handle, einem Array, dessen Speicher dynamisch alloziert ist. Beim Verndern von Sequences wird copy on write verwendet. Die Implementierung des Templates bentigt die Typinformation fr Konstruktion, Destruktion und Vergleich von Sequences, daher knnen nur UNO-Typen mit diesem Template verwendet werden. Beim Erzeugen einer Sequence kann eine initiale Anzahl von Elementen vorgegeben werden, die alle default-konstruiert werden, auch eine Initialisierung mit einem Array ist mglich, dabei wird aber das Array nicht bernommen, sondern kopiert. Sequences sind reine Transport-Container, daher gibt es keine Methoden zum Einfgen oder Entfernen, lediglich ein Zuweisen und Reallozieren sind mglich, neben dem selbstverstndlichen Zugriff auf einzelne Array-Elemente in lesender oder schreibender Weise. Sequences von UNO Type sind wieder UNO Types und knnen demenstprechend verwendet werden, z.B. wieder als Elemente von Sequences. Der folgende Code verdeutlicht an ein paar Beispielen die Benutzung von Sequences.
// integer sequence mit 3 Elementen, alle Elemente haben dann den Wert 0 Sequence< sal_Int32 > seqInt( 3 ); // Explizite Initialisierung der Elemente durch Schreibzugriff ber Array // Die Methode check den refcount und fhrt ggf. copy on demand aus sal_Int32 *pArray = seqInt.getArray();
pArray[0] = 4; pArray[1] = 5; pArray[2] = 3;

// sequence of Property structs, die structs werden default-konstruiert Sequence< Property > seqProperty(2); // Explizite Initialisierung der Element durch direkten Schreibzugriff // Der Zugriffsoperator check den refcount und fhrt ggf. copy on demand aus Sequence< Property > seqProperty(2);

seqProperty[0].Name = seqProperty[0].Handle seqProperty[1].Name = seqProperty[1].Handle

OUString::createFromAscii( "A" ); = 0; OUString::createFromAscii( "B" ); = 1;

// copy construction: refcount wird erhht Sequence< Property > seqProperty2 = seqProperty; // Initialisierte Sequence aus einem buffer (array) sal_Int32 sourceArray[3] = {3,5,3}; Sequence< sal_Int32 > seqInt( sourceArray , 3 ); // Lesender Zugriff auf eine Sequence for( sal_Int32 i = 0 ; i < seqProperty.getLength() ; i ++ ) printf( "%d\n" , seqProperty.getConstArray()[i].Handle ); // Lesender Zugriff auf eine const Sequence (oder eine neue Sequence) for( sal_Int32 i = 0 ; i < seqProperty.getLength() ; i ++ ) printf( "%d\n" , seqProperty[i].Handle ); // rekursive Definitionen sal_Int32 a[ ] = { 1,2,3 }, b[] = {4,5,6}, c[] = {7,8,9,10}; Sequence< Sequence< sal_Int32 > > aaSeq ( 3 ); aaSeq[0] = Sequence< sal_Int32 >( a , 3 ); aaSeq[1] = Sequence< sal_Int32 >( b , 3 ); aaSeq[2] = Sequence< sal_Int32 >( c , 4 );

Besonders hingewiesen sei hier auf die verschiedenen Zugriffsmglichkeiten. Die Methode getArray() wird bei gemeinsam genutzten Sequences (refcount>1) eine Kopie anlegen, sie sollte also zum Lesen der Sequence besser nicht verwendet werden (der RefCountCheck spielt hier unter Performance-Gesichtspunkten sicherlich keine Rolle). Das gleiche gilt fr den Operator[], zumindest sofern er nicht auf eine const sequence oder eine gerade neu angelegte Sequence (refcount==1) angewendet wird. Zum Verndern einer Sequence kann immer der Operator[] verwendet werden, die Benutzung von getArray() hat den nur marginalen Vorteil, dass der RefCount nur einmal und nicht bei jedem Zugriff gecheckt werden muss.
Abbildung des UNO-Typs any

Der UNO-Typ any wird auf die Klasse com::sun::star::uno::Any gemappt, die Instanzen von beliebigen UNO-Typen aufnehmen kann, allerdings keine Instanzen andere (C++-)Typen, da genau wie bei Sequences die UNO-Typinformation bentigt wird. Ein default-konstruierter Any enthlt den Typ void und somt keinen Wert. Werte knnen ber zwei Operatoren gelesen und gesetzt werden:
// Default-Konstruktion eines any com::sun::star::uno::Any any; sal_Int32 n = 3; // Wert ins Any bertragen any <<= n; // Wert auslesen sal_Int32 n2; any >>= n2;

Der Auslese-Operator >>= fhrt etwaige Konversionen automatisch aus, wenn sie ohne Verlust mglich sind, also z.B. Integer Upcasts (int16->int32), verweigert aber die Arbeit, wenn der Zieltyp nicht alle Werte des Quelltyps aufnehmen kann, ein Integer Downcast (in16->int8) wird also auch dann nicht vorgenommen, wenn der konkrete Wert des Any zufllig passen wrde.
com::sun::star::uno::Any any; sal_Int16 n = 3; any <<= n; sal_Int8 aByte = 0; sal_Int16 aShort = 0;

sal_Int32 aLong = 0; // Conversion von int16 in int32 ist OK -> Erfolg assert( any >>= aLong ); assert( 3 == aLong ); // Conversion von int16 in int16 ist OK -> Erfolg assert( any >>= aShort ); assert( 3 == aShort // Conversion von int16 in int8 klappt nicht, unabhngig vom tatchlichen Wert des int16 assert( any >>= aByte ); assert( 3 == aByte );

Auch Interface-Referenzen werden ggf. durch Aufruf von queryInterface konvertiert. Selbst wenn in dem Any eine Reference < com::sun::star::uno::XInterface > drinsteckt, erhlt man so immer das richtige Interface, sofern das referenzierte Objekt es untersttzt. Es ist aber guter Stil, beim Befllen des Any immer den Referenztyp zu bergeben, der laut Dokumentation erwartet wird, denn damit sorgt man dafr, dass auch schlechterer Code auf der anderen Seite evtl. noch funktioniert.
// "quick and dirty" Any any; any <<= xServiceManager->createInstance(::rtl::OUString(::createFromAscii( com.sun.star.task.InteractionHandler)); // "guter Stil" wre: Any any; Reference< ::com::sun::star::task::XStatusIndicator > xInd( xServiceManager-> createInstance(::rtl::OUString(::createFromAscii( com.sun.star.task.InteractionHandler)); Any <<= xInd; // in beiden Fllen funktioniert trotzdem Reference< ::com::sun::star::task::XStatusIndicator > xVal; rProp.Value >>= xVal;

Man kann statt des Extraktionsoperators auch den Datenpointer des Any direkt manipulieren, muss dann aber sehr genau mit den Typabfragen umgehen und verliert den Komfort der eingebauten Konvertierungen. Aber auch sonst knnte eine Typabfrage von Interesse sein, sie erfolgt ganz einfach ber die Methode getTypeClass(), aber auch eine Konstruktion eines Any mit einem bestimmten Typ ist mglich:
Any a = ...; if( a.getTypeClass() == TypeClass_LONG && 3 == { } Any foo() { sal_Int32 i = 3; if( ... ) i = ..; return Any( &i, getCppuType( &i) ); } *(sal_Int32 *)a.getValue() )

Abbildung von UNO-Interface Typen

Wie schon wiederholt gezeigt wird ein Wert eines UNO Interface Types T auf die Template Class com::sun::star::uno::Reference < t > gemappt, wobei t eine Abbildung des UNO Interface T auf die C++-Sprache ist. Dabei entspricht einem UNO Interface module1.module2.module3.XIf die abstrakte C++-Klasse namespace1::namespace2::namespace3::XIf. Wie schon mehrfach erwhnt, sind zwar alle C++-Klassen von der Basisklasse com::sun::star::uno::XInterface abgeleitet (und implementieren ber diese alle Interface-spezifischen Details des C++ Language Bindings), das bedingt aber nicht notwendigerweise eine entsprechende Beziehung in UNO IDL.

Diese ist de facto berflssig, kann aber aus Kompatibilittsgrnden nicht entfernt werden. Man sollte aber bei neuen Interfaces diese Ableitung in IDL nicht mehr hinschreiben. Diese typsicheren Referenzklassen bernehmen fr den Programmiere den grten Teil der Implementierungsdetails fr Interfaces, die sich aus dem Language Binding ergeben: Reference Counting (s. spteres Kapitel), Implementierung des queryInterface-Konzepts und typsicheres Vergleichen von Referenzen. Der ->-Operator ist fr die Referenzklassen berladen und fhrt die analog Operation auf dem verwalteten Interface-Pointer aus. Eine Interface-Referenz kann default konstruiert werden und enthlt dann eine NULL-Referenz auf das entsprechende Interface, oder man konstruiert sie mit einem Pointer auf ein passendes Interface. Da das ggf. einen queryInterface()-Call erfordern wrde, gibt es einen weiteren Konstruktor, der das gleich mit erledigt und sich daher mit dem Pointer auf ein beliebiges Interface (die ja C++technisch zumindest alle von com::sun::star::uno::XInterface abgeleitet sind) zufrieden gibt:
using com::sun::star::uno::Reference; using com::sun::star::uno::UNO_QUERY; // Anlegen einer NULL-Referenz Reference < com::sun::star::frame::XDesktop > xDesktop1; // Zuweisung xDesktop1 = xSMgr->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop") ); // alternativ: direkte Konstruktion (man beachte den Typ!) Reference < com::sun::star::uno::XInterface > xDesktop2( xSMgr->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop") ) ); // oder am einfachsten Reference < com::sun::star::uno::XInterface > xDesktop3( xSMgr->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop") ), UNO_QUERY );

Das Zurcksetzen einer Referenz kann entweder durch die Klassenmethode clear() oder durch Zuweisen einer default-konstruierten Referenz erfolgen. Auch ein Gleichheitsoperator ist definiert, der berprft, ob die verwalteten Interfaces zum selben Objekt(!) gehren, wofr natrlich wieder queryInterface() bentigt wird.
Abbildung von UNO-Services

Auch wenn Services keine UNO-Typen im eigentlichen Sinne sind, bentigen zumindest solche der neuartigen Form eine Abbildung in der jeweiligen Programmiersprache, wenn man dort die Konstruktoren der Objekt nutzen will. Daher gibt es auch in C++ eine Abbildung fr neuartige Services, nicht aber fr die altmodischen. Ein neuartiger UNO service wird in C++ reprsentiert durch eine C++-Klasse desselben Namens. Die Klasse hat aber nur eine oder mehrere statische Methoden, die den deklarierten Konstruktoren entsprechen. Wenn keine Konstruktoren deklariert sind, existiert immer ein impliziter Konstruktor, der in C++ immer die folgende Form hat:
public: static com::sun::star::uno::Reference< XIfc > create( com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > const& context) throw (com::sun::star::uno::RuntimeException) { ... }

wobei XIfc das Interface ist, das der Service implementiert. Der bergebene Parameter ist der Component Context, der im Kapitel ber Services schon erlutert wurde. Bei allen expliziten Konstruktoren wird in der C++-Sprachanbindung dieser Parameter auch automatisch als erster Parameter eingefgt. Wenn in UNO IDL also deklariert wurde:
name([in] Type1 arg1, [in] Type2 arg2) raises (Exception1);

wird daraus in C++:


public: static com::sun::star::uno::Reference< XIfc > name( com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > const& context, Type1 arg1, Type2 arg2) throw (Exception1, ..., ExceptionN, com::sun::star::uno::RuntimeException) { ... }

Es ist sogar mglich, rest parameter (any...) zu verwenden, die dann in C++ automatisch als Parameter vom Typ com::sun::star::uno::Sequence < com::sun::star::uno::Any> gemappt wird. Der bergebene Component Context darf keine Null-Referenz sein, da der generierte Code des Konstruktors den am Component Context gesetzten Service Manager verwendet, um den Service zu erzeugen. Weitere Argumente von expliziten Konstruktoren werden zur Initialisierung des Objekts verwendet. Es wird also am ServiceManager entweder createInstanceWithContext oder createInstanceWithArgumentsAndContext verwendet. Mehr zu Konstruktoren findet man im Developers Guide im Kapitel ber die Language Bindings.
Exception handling in C++ UNO

Fr das Werfen und Fangen von Exceptions in UNO-basierten Implementierungen wird der normale C++ Exception-Mechanimus verwendet. UNO Interface-Methoden drfen aber nur die Exception com::sun::star::uno::Exception und davon abgeleitete werfen. Das UNO Language Binding mappt diese dann in die gleichnamigen in UNO IDL definierten Exceptions. Andere Exceptions, z.B. die std::exception, knnen nicht von UNO gebridged werden und fhren daher bei Remote Calls zum sofortigen Programmabbruch, selbst wenn sie im C++ in-process Fall durchaus gefangen werden knnten. Bei den meisten Compilern knnen nur solche Exceptions geworfen bzw. durchgelassen werden, die auch in der Methodendefinition deklariert wurden, es kommt in anderen Fllen entweder zu Kompilierfehlern oder zu Laufzeitfehlern (std::unexpected in einem C++-Programm, das unter unixoiden Systemen zum Programmabbruch fhrt).

5 StarOffice Basic und UNO


5.1 Allgemeines
StarOffice Basic ist zunchst einmal ein Basic-Dialekt wie viele andere auch. Sprachkonstrukte, wie man sie von Visual Basic oder anderen kennt, finden sich auch hier wieder. Es ist eine objektbasierte Sprache, d.h. es enthlt Syntaxelemente fr die Benutzung der Properties und Methoden von Objekten ohne aber selbst typische Elemente objektorientierter Programmiersprachen zu untersttzen. Eine detaillierte Sprachreferenz befindet sich in der StarOffice Online-Hilfe. Durch die UNO-Fhigkeit seines Interpreters ist StarOffice Basic in der Lage, beliebige UNOObjekte zu benutzen oder, wie man auch sagt, zu scripten. Der Interpreter bereitet alle Objekte mit Hilfe des Service com::sun::star::beans::Introspection fr eine vereinfachte Benutzung auf. Dieser Service benutzt das UNO Reflection API, um alle Bestandteile eines Objekts zu inspizieren und macht Methoden, Properties und Attribute auf eine generische Art und Weise aufrufbar. Als Ergebnis lt StarOffice Basic die UNO-Objekte wie Basic-Objekte erscheinen und erlaubt einen sehr einfachen Zugriff auf die Methoden und Properties als Member des Objekts. Der Introspection Service kann ein UNO-Objekt nur inspizieren, wenn dieses das Interface com::sun::star::uno::XTypeProvider implementiert. Objekte, bei denen das vergessen wurde, lassen sich daher in StarOffice Basic nicht benutzen. Mehr zum UNO Reflection API findet man im Kapitel 5.2.3 des StarOffice Developers Guide.

Ein wichtiger Unterschied zwischen UNOIDL und Basic ist, dass Bezeichner im Basic nicht case sensitive sind. Im Allgemeinen fhrt das nicht zu Problemen, aber in manchen Situationen schon. Daher sollte man sich angewhnen, in StarOffice Basic allen UNO-bezogenen Code so zu schreiben, als wre das Basic case sensitive. So geht man allen Problemen aus dem Weg, erleichtert sich auerdem den Vergleich mit oder sogar die bertragung in andere Sprachen und macht seinen Code besser lesbar. Eine weitere Eigenart von Basic kann es erschweren, UNO-Programmierung in Basic mit der in anderen Sprachen zu vergleichen: Basic hat kein strenges Typsystem und es verlangt auch nicht, dass Variablen deklariert werden, sofern nicht das Option Explicit Kommando benutzt wird. Lediglich Arrays mssen deklariert werden, um auf ihre Element zugreifen zu knnen. Variablendeklarationen in Basic erfolgen mit dem Dim Kommando:
Dim VarName [As Type] [, VarName2 [As Type] ] ...

Wie man sieht, kann dabei einer Variablen ein Basic-Typ zugewiesen werden. Ein Dim-Kommando ohne explizite Typzuweisung weist dieser Variable den Typ Variant zu. Eine Typzuweisung fr einige Typen kann auch ber ein Variablenpostfix erfolgen: Typ Boolean Integer Long Single % & ! Postfix True, False -32768 bis 32767 -2147483648 to 2147483647 Fliekommazahlen negativ: -3.402823E38 bis -1.401298E-45 positiv: 1.401298E-45 bis 3.402823E38 Fliekommazahlen negativ: -1.79769313486232E308 bis -4.94065645841247E-324 positiv: 4.94065645841247E-324 bis 1.79769313486232E308 Festkommazahlen mit 4 Nachkommastellen -922,337,203,685,477.5808 bis 922,337,203,685,477.5807 01.01.100 bis 31.12.9999 Basic-Objekte, UNO-Objekte $ Zeichenketten Bereich

Double

Currency Date Object String

Variant Werte beliebiger anderer Typen Wenn kein bestimmter Typ bei der Deklaration einer Variablen angegeben wird (oder wenn die Variable berhaupt nicht deklariert wird) hat sie automatisch den Typ Variant. Variablen dieses Typs kann jeder beliebige Wert irgendeines Typs zugewiesen werden.

5.2 Besonderheiten der Basic-Sprachanbindung


Benutzung von UNO-Objekten in Basic

Es ist in Basic nicht ntig, die verschiedenen Interfaces eines Objekts zu benutzen, um seine Methoden aufzurufen, wie es in C++ oder Java erforderlich ist, es besteht also keine Notwendigkeit, ein queryInterface auszufhren. Die folgende Abbildung zeigt ein Beispiel fr einen (altmodischen) UNO-Service, der drei Interfaces untersttzt:

Jede der Methoden kann in Basic direkt an dem Objekt aufgerufen werden, das den Service implementiert:
oExample = getExampleObjectFromSomewhere() oExample.doNothing() ' Calls method doNothing of XFoo1 oExample.doSomething() ' Calls method doSomething of XFoo2 oExample.doSomethingElse(42) ' Calls method doSomethingElse of XFoo2

Der Basicprogrammierer hat einen sehr komfortablen Zugang zu properties und attributes, da Basic beim Inspizieren des Objekts alle Methoden der Form getX( ) als die Existenz eines Properties X interpretiert, das, falls auch eine Methode setX() existiert, auch beschreibbar ist (sonst readonly). Davon profitieren dann nicht nur Attribute, sondern natrlich auch alle lteren Interfaces, bei denen solche get/set-Methoden explizit vorhanden sind. Der Zugriff ist dann ganz einfach, fr obiges Beispiel also:
first$ = obj.FirstAttribute obj.SecondAttribute = another$

Das Interface XFoo3 enthlt ein Paar von Get/Set-Methoden. StarOffice Basic bildet diese als Property ab und erlaubt daher folgende Zugriffsarten:
Dim x as Integer x = oExample.getIt() ' is the same as x = oExample.It oExample.setIt( x ) ' is the same as oExample.It = x ' Calls getIt method of XFoo3 ' Read property It represented by Xfoo3 ' Calls setIt method of XFoo3 ' Modify property It represented by Xfoo3

Eine get...()-Methode ohne eine dazu passende set...()-Methode() wrde dann als readonly Property interpretiert. Wie schon erlutert werden auch Attribute von mehrfach vererbenden Interfaces auf solche get und set-Methoden abgebildet, daher ist jedes attribute automatisch als Property in Basic verfgbar. Basic kann aber auch die Properties von den altmodischen Services zur Verfgung stellen, da es nicht nur get und set-Methoden sondern auch das fr die Implementierung von Properties benutzte Interface com::sun::star::beans::XPropertySet inspizieren kann. Dies erfolgt dann sogar typsicher, da es sich ber die Methode getPropertySetInfo alle notwendigen Informationen besorgt und auswertet. Ein direkter Aufruf von setPropertyValue erwartet ja ein any als Parameter, was, wie im Folgenden noch gezeigt wird, manchmal zu Problemen fhrt, die durch die typsichere direkte Zuweisung vermieden werden. Eine weitere damit vergleichbare Vereinfachung wird vom Basic-Interpreter bei Objekten, die das Interface com::sun::star::container::XNameAccess implementieren, vorgenommen. StarOffice Basic bildet den (lesenden) Namenszugriff auf die Elemente eines solchen Containers syntaktisch auf ein read-only Property des Objekts ab, eine entsprechende Vereinfachung fr den schreibenden Zugriff auf die Elemente ber com::sun::star::container::XNameReplace wird aber nicht angeboten:
x = obj.getByName("elem") ' liest den Wert des Elements "elem" aus

x = obj.Value obj.replaceByName("elem", x) obj.Value = x

' identisch mit der ersten Zeile ' setzt den Wert des Elements "elem" ' Runtime Error: wird nicht untersttzt

Neben solchen syntaktischen Besonderheiten weist die Sprachanbindung von StarOffice Basic aber auch bei der Erzeugung von Services markante Unterschiede zu der Java-Anbindung auf. Im Kapitel zur Java-Sprachanbindung wurde erlutert, wie man sich einen Component Context samt Service Manager erzeugt, um damit Objekte (Services) im StarOffice zu erzeugen. Der StarOffice Basicprogrammierer kann sich Zugriff auf den Service Manager oder den Component Context verschaffen, den StarOffice selbst beim Starten angelegt hat. Dazu gibt es die Basic Runtimefunktionen GetProcessServiceManager und GetDefaultContext, man kann Services aber auch einfacher direkt ber eine weitere Runtimefunktion erzeugen, nmlich ber CreateUnoService:
oSimpleFileAccess = CreateUnoService( "com.sun.star.ucb.SimpleFileAccess" ) ' ist quivalent zu: oServiceMgr = GetProcessServiceManager() oSimpleFileAccess = oServiceMgr.createInstance( "com.sun.star.ucb.SimpleFileAccess" )

Die Erzeugung ber den ServiceManager statt ber CreateUnoService ist natrlich erforderlich, wenn man dem Service bei der Erzeugung Parameter mitgeben will, also die Methode createInstanceWithArguments benutzen will. Es gibt in der Basic Runtime noch zwei Objekt-Properties, die spezielle UNO-Objekte reprsentieren, nmlich das Property StarDesktop und das Property ThisComponent. Ersteres enthlt eine Referenz auf den Desktop Service (com::sun::star::frame::Desktop), whrend letzteres etwas komplexer ist. Basic-Makros knnen wahlweise in der StarOffice-Installation bzw. dem Benutzerprofil abgelegt oder in ein StarOffice-Dokument hinein gespeichert werden. Wird ein Makro ausgefhrt, das in einem Dokument gespeichert ist, enthlt ThisComponent eine Referenz auf das UNO-Objekt, das das Dokument reprsentiert. Was fr ein Objekt das genau ist, wird uns noch im Kapitel ber Dokumente beschftigen. Wird ein Makro ausgefhrt, das nicht in einem Dokument, sondern in der Installation gespeichert ist, zeigt ThisComponent einfach auf das gerade aktive Dokument. Dadurch, dass der Basic Interpreter alle verwendeten Objekt inspiziert, kann er natrlich auch benutzt werden, um Information ber die Objekte zur Laufzeit zu erhalten und auszuwerten. Dazu bietet die StarOffice Basic Runtime ein paar ntzliche Funktionen fr den Umgang mit Objekten: IsNull: ermittelt, ob das bergebene Basic-Objekt eine Null-Referenz auf ein UNO-Objekt enthlt HasUnoInterfaces: gibt Auskunft, ob das Objekt alle bergebenen Interfaces untersttzt EqualUnoObjects: ermittelt, ob sich hinter zwei Basic-Objekten das gleiche UNO-Objekt verbirgt (Test auf Objektidentitt) Dbg_SupportedInterfaces: gibt eine Liste aller Interfaces aus, die das Objekt untersttzt Dbg_Properties: gibt eine Liste aller Properties aus, die das Objekt hat Dbg_Methods: gibt eine Liste aller Methoden aus, die das Objekt durch seine Interfaces hat Die letzten drei Methoden werden geben ihr Ergebnis als String zurck, der so formatiert ist, dass man ihn einfach in eine Dialogbox ausgeben kann:
oServiceManager = GetProcessServiceManager() MsgBox oServiceManager.Dbg_SupportedInterfaces

Beispielausgaben finden sich im Developers Guide in Kapitel 3.4.3.

Es mag sich die Frage stellen, warum ein Basicprogrammierer die Methoden HasUnoInterfaces und Dbg_SupportedInterfaces braucht, wo er doch in seinem Code niemals auf Interfaces Bezug nimmt. Es gibt aber zwei Situationen, wo er diese Informationen bentigt. Zunchst einmal muss auch ein Basicprogrammierer die UNOIDL Referenzdokumentation benutzen, um sich die Funktionalitt eines Objekts ber die Services, die es implementiert, zu erschlieen. Diese Dokumentation gruppiert Funktionalitt aber nach Interfaces, daher muss der Basicprogrammierer dieses Konzept verstanden haben und Informationen darber besitzen, welche Interfaces er sich ansehen muss. Des weiteren gibt es ja an Services auch optionale Komponenten, die den Einsatz von Typchecks zur Laufzeit (in Java: queryInterface, hier: HasUnoInterfaces) zwingend erforderlich machen.
Abbildung von numerischen UNO Typen

Wenn Parameter von Methoden oder Properties eines UNO-Objekts zugewiesen werden, kann StarOffice Basic die dazu verwendeten Basic-Variablen automatisch in den korrekten UNO-Typ umwandeln, sofern dieser bekannt ist. Beispiele:
' Das UNO object oExample1 hat a% = 42 oExample1.Count = a% ' a% pi = 3,141593 oExample1.Count = pi ' pi s$ = "111" oExample1.Count = s$ ' s$ 111 ein Property "Count" vom Typ short hat the korrekten Typ (Integer) wird in short konvertiert, also erhlt Count den Wert 3 wird in short konvertiert, also erhlt Count den Wert

Allerdings ist der exakte Typ nicht immer bekannt, speziell dann, wenn an eine Methode ein Parameter bergeben wird, der vom Typ Any ist. StarOffice Basic konvertiert dann den gegebenen Basic-Typ automatisch in den zugeordneten UNO-Typ aus obiger Tabelle, wobei fr numerische Typen der kleinstmgliche UNO Daten-Typ gewhlt wird, der den transportierten Zahlenwert aufnehmen kann, d.h. byte fr Werte zwischen -128 und 127 short fr Werte zwischen -32768 und 32767 long fr alle anderen gltigen Integer-Werte Des weiteren werden Fliekommazahlen, die keine Nachkommastellen aufweisen, zu einem UNOGanzzahlentyp konvertiert (natrlich auch wieder in den kleinstmglichen). Beispiele:
a# = 57133.0 b%=15 c& = 157 ' wird als long an ein Any bergeben ' wird als byte an ein Any bergeben ' wird als short an ein Any bergeben

Dieses Herunterkonvertieren (Downcast) sichert dem Empfnger des Any, dass der erhaltene Wert auf jeden Fall verarbeitet werden kann, sofern er im korrekten Zahlenbereich liegt. Dazu muss der Empfnger dann einen Upcast durchfhren, der z.B. aus dem byte im obigen Beispiel einen short oder gar long macht, je nachdem, was fr einen Typ er denn gerne htte. Andersherum geht es nicht ohne die Gefahr von Fehlern, da man bei automatischen Downcasts nicht mitbekommt, wenn der Wertebereich berschritten wird. Auf der Senderseite (also im Basic) ist der Downcast ja nicht wirklich automatisch, weil der Basic-Interpreter sich die Zahlenwerte genau ansieht und nur soweit herunterkonvertiert, wie es mglich ist. Diesen Aufwand mchte man auf Empfngerseite nicht unbedingt treiben. Ein Beispiel, wo ohne Downcast auf Seiten des Basic eine UNO-Schnittstelle nicht korrekt bedient werden kann, ist ein Container, der byte-Werte speichert. Container-Interfaces benutzen eine Anybasierte Schnittstelle, daher wrde der Code in Basic so aussehen:
a%=42 oNameContainer.replaceByName(MyValue", a%)

Da Basic keinen byte-Typ kennt, wrde es den Wert 42 als short bergeben, was auf

Empfngerseite einen automatischen Downcast erforderte (da dort nur byte-Variablen verarbeitet werden).
Abbildung von UNO sequence

UNO sequences werden auf Basic Arrays abgebildet. Bei deren Benutzung tritt ein wichtiger Unterschied zu anderen UNO-Programmiersprachen zu Tage: bei der Dimensionierung des Array gibt man nicht die Anzahl der Elemente an, sondern die Nummer des hchsten Index. Beispiele:
Dim Dim Dim Dim Dim arr1(100) arr2$(0) arr3%(9,19) arr4%(3 to 5) emptyarr() ' ' ' ' ' Variant-Array mit 101 Elementen String-Array mit 1 Element zweidimensionales Integer-Array mit 10*20 = 200 Elementen Integer-Array mit 3 Elementen leeres Array (eines ohne Elemente)

Das Array arr1 erzeugt ein Array mit 101 Elementen, die mit den Indices 0,1,2,...100 angesprochen werden, entsprechendes gilt fr die anderen Beispiele. Das sollte man beachten, wenn man UNObasierende Programme, die in Basic geschrieben wurden, mit denen anderer Programmiersprachen oder mit Deklarationen in UNOIDL vergleicht. Die Deklaration von Basic-Arrays wird immer einen Zahlenwert verwenden, der um 1 niedriger ist. Das Array arr4% ist ein Sonderfall, es zeigt, dass reine Basic-Arrays (also nicht solche, die im UNO-Kontext verwendet werden) auch einen Start-Index haben knnen, der ungleich 0 ist. Die Index-Grenzen knnen mit den Basic-Funktionen UBound und LBound abgefragt werden, die Anzahl der Elemente eines Arrays arr( ) ist dann gegeben durch
elementCount% = UBound( arr() ) - LBound( arr() ) + 1

Damit diese Formel auch fr leere Arrays (also solche mit 0 Elementen) funktioniert, ergibt ein Aufruf von UBound fr ein leeres Array den Wert -1, whrend LBound den Wert 0 liefert (wie fr alle Basic-Arrays, die nicht mit der Dim (min to max)- Syntax deklariert wurden). Wird ein Array als Rckgabewert erhalten, ist es nicht nur unntig, die Variable, der der Rckgabewert zugewiesen wird, als Array zu deklarieren, sondern es wird sogar empfohlen, es nicht zu tun, vielmehr sollte man eine Variable vom Typ Variant verwenden. Da der UNO-Typ des empfangenen Rckgabewerts bekannt ist (selbst wenn es ein Any ist, denn es steckt ja etwas drin, das man inspizieren kann!), erkennt Basic von selbst, dass es ein Array ist und man kann anschlieend die empfangende Variable wie ein Array benutzen:
Dim Arr Arr = obj.getArray() dim i%, ifrom%, ito% ifrom% = LBound( Arr() ) ito% = UBound ( Arr() ) for i% = ifrom% to ito% print Arr(i%) next i%

Wenn Basic-Arrays als Parameter bergeben werden, sollten ihr Name immer mit abschlieenden Klammern geschrieben werden, das Array arr1 aus obiger Deklaration muss also als arr1( ) bergeben werden. Ein spezieller Fall ist die Abbildung von UNO sequences of sequences. Das ist nicht etwa einfach ein zweidimensionales Basic-Array, denn bei diesem haben alle Sub-Arrays die gleiche Zahl von Elementen, sondern es ist vielmehr ein eindimensionales Array von Variants, wobei jeder Variant selbst wieder ein Array ist. Entsprechendes gilt fr noch hher verschachtelte sequences. Der Gebrauch solcher Arrays wird durch ein paar Beispiele illustriert, zunchst die Verarbeitung einer sequence of sequence of short als Property eines UNO-Objekts:
Dim aArrayOfArrays ' Array deklariert als Variant, da es einen Rckgabewert aufnimmt aArrayOfArrays = oExample.ShortSequences Dim i%, NumberOfSequences% Dim j%, NumberOfElements%

Dim aElementArray

' Hilfsvariable, die jeweils ein Sub-Arry adressiert

NumberOfSequences% = UBound( aArrayOfArrays() ) + 1 For i% = 0 to NumberOfSequences% - 1 ' Schleife ber alle Sub-Arrays aElementArray = aArrayOfArrays( i% ) NumberOfElements% = UBound( aElementArray() ) + 1 For j% = 0 to NumberOfElements% - 1 ' Schleife ber alle Elemente des SubArray MsgBox aElementArray( j% ) Next j% Next i%

Der umgekehrte Fall ist die bergabe einer sequence of sequence of short an ein UNO-Property:
Dim aArrayOfArrays( 2 ) ' Declaration der Sub-Arrays Dim aArray0( 3 ) Dim aArray1( 2 ) Dim aArray2( 0 ) ' Initialisierung der aArray0( 0 ) = 0 aArray0( 1 ) = 1 aArray0( 2 ) = 2 aArray0( 3 ) = 3 aArray1( 0 ) = 42 aArray1( 1 ) = 0 aArray1( 2 ) = -42 aArray2( 0 ) = 1 ' Zuweisung der aArrayOfArrays( aArrayOfArrays( aArrayOfArrays( Sub-Arrays ' Master-Array mit 3 Sub-Arrays

Sub-Arrays zu den Elementen des Master-Array 0 ) = aArray0() 1 ) = aArray1() 2 ) = aArray2()

' bergabe des Master-Array an das Property des UNO-Objekts oExample.ShortSequences = aArrayOfArrays()

Das zweite Beispiel kann man etwas kompakter, aber vielleicht weniger lesbar gestalten, indem man die Array()-Funktion des StarOffice Basic benutzt, dies es erlaubt, ein Array schon bei der Deklaration zu initialisieren:
Dim aArrayOfArrays( 2 ) ' Declaration und aArrayOfArrays( 0 aArrayOfArrays( 1 aArrayOfArrays( 2 ' Zuweisung der aArrayOfArrays( aArrayOfArrays( aArrayOfArrays( ' Master-Array mit 3 Sub-Arrays Initialisierung der Sub-Arrays ) = Array( 0, 1, 2, 3 ) ) = Array( 42, 0, -42 ) ) = Array( 1 )

Sub-Arrays zu den Elementen des Master-Array 0 ) = aArray0() 1 ) = aArray1() 2 ) = aArray2()

' bergabe des Master-Array an das Property des UNO-Objekts oExample.ShortSequences = aArrayOfArrays() oder noch kompakter: Dim aArrayOfArrays( 2 ) ' Master-Array mit 3 Sub-Arrays

' Declaration der Sub-Array, Initialisierung der Sub-Arrays und des Master-Arrays aArrayOfArrays = Array( Array( 0, 1, 2, 3 ), Array( 42, 0, -42 ), Array( 1 ) ) ' bergabe des Master-Array an das Property des UNO-Objekts oExample.ShortSequences = aArrayOfArrays()

Abbildung von UNO struct Typen

StarOffice Basic behandelt UNO structs syntaktisch mehr oder weniger wie UNO-Objekte, ihre einzelnen Member werden angesprochen wie die Properties der Objekte, auch ein Aufruf von

Dbg_Properties funktioniert und zeigt die Member des structs an (aber natrlich funktionieren die beiden anderen Dbg-Funktionen nicht, da structs keine Methoden und Interfaces haben). Im Gegensatz zu UNO-Objekten sind UNO structs aber explizite Typen, fr die man Variablen exakt dieses Typs (und nicht nur eins generischen Object-Typs) erzeugen und initialisieren kann. Dafr kann eine Variante des Dim-Kommandos oder eine spezielle Funktion der Basic Runtime Library verwendet werden:
Dim aProp1 As New com.sun.star.beans.PropertyValue Dim aProp2 aProp2 = CreateUNOStruct("com.sun.star.beans.PropertyValue")

Ein weiterer wichtiger Unterschied zwischen structs und Objekten ist, dass erstere als Werte behandelt werden, letztere als Referenzen. Wenn eine Variable, die ein UNO-Objekt transportiert, einer anderen zugewiesen wird, zeigen beide hinterher auf das selbe Objekt, sodass man das Objekt ber beide Variablen verndern kann. Wird eine Variable, die einen UNO-struct transportiert, einer anderen Variablen zugewiesen, wird eine Kopie des structs erzeugt und nderungen am struct der einen Variablen beeinflussen nicht den struct der anderen. Ob eine Basic-Variable einen UNO struct enthlt, kann mit der Runtime-Funktion IsUNOStruct erfragt werden.
Abbildung von UNO-Enumerationstypen und Constant Groups

Konstanten aus Constant Groups und die einzelnen Werte einer Enumeration knnen in StarOffice Basic direkt durch Benutzung des vollqualifizierenden Namens verwendet werden, wobei fr den einzelnen Wert einer Enumeration automatische eine Long-Variable verwendet wird (da Basic keinen eigenen Support fr Enumerationen hat). Beispiele:
Dim EnumValue1, EnumValue2 EnumValue1 = com.sun.star.beans.PropertyState.DEFAULT_VALUE MsgBox EnumValue1 ' zeigt den Wert 1 an EnumValue2 = com.sun.star.beans.PropertyState.DIRECT_VALUE MsgBox EnumValue2 ' zeigt den Wert 0 an Dim ConstantValue1, ConstantValue2 ConstantValue1 = com.sun.star.beans.PropertyConcept.DANGEROUS MsgBox ConstantValue1 ' zeigt den Wert 1 an ConstantValue2 = com.sun.star.beans.PropertyConcept.PROPERTYSET MsgBox ConstantValue2 ' zeigt den Wert 2 an

Man kann die Schreibweise auch etwas abkrzen, indem man die Constant Group oder die Enumeration selbst einer Variablen zuweist und sie wie ein Objekt benutzt:
Dim PropConcept PropConcept = com.sun.star.beans.PropertyConcept Dim ConstantValue1, ConstantValue2 ConstantValue1 = PropConcept.DANGEROUS ConstantValue2 = PropConcept.PROPERTYSET

Das ist aber wirklich nur ein syntaktischer Trick, Basic hat nicht wirklich einen Support fr derartige Objekte. Der fehlende direkte Support fr Enumerationen wirft Probleme im Umgang mit Anys auf. Wenn an eine Methode mit einem Enumerations-Parameter ein Wert bergeben werden soll, erkennt Basic den UNO-Typ und wandelt den intern als Long abgespeicherten Wert in den passenden UNOEnumerationstyp, bevor der Wert bergeben wird. Ist der Parameter aber vom Typ Any, wird der Wert als UNO-Typ long bergeben. Wenn die Implementierung der Methode dafr keine Vorkehrungen trifft (indem sie nmlich den Any sowohl auf den erwarteten Enumerationstyp als auch auf long testet), wird es zu einem Fehler kommen. Eine spezielle Ausprgung dieses Problems findet man bei der Bedienung des Interface com::sun::star::beans::XPropertySet. Dieses bietet je eine Methode zum Auslesen und zum Setzen von Properties ber ihren Namen, wobei der Wert als Any bergeben wird und daher genau das oben beschriebene Problem verursacht. Wie bereits erklrt erkennt StarOffice Basic

dieses Interface bei der Inspektion des Objekts und bildet es auf eine einfache Property-Schnittstelle ab. Bei der Inspektion des Objekts erfhrt das Basic nicht nur, welche Properties es ber das Interfaces anbietet, sondern auch, welchen exakten Typ diese haben. Daher ist es besser, den Weg ber die Property-Schreibweise zu benutzen, der berdies auch einfacher ist:
Dim EnumValue EnumValue = object1.Status object2.Status = EnumValue ' typsicher, empfohlen object2.setPropertyValue(Status", EnumValue) ' nicht empfohlen

Typsichere Parameterbergabe in Basic

Das eben angesprochene Problem der Enumerationstyp-Behandlung bei Any-Schnittstellen ist eng verwandt mit dem ebenfalls bereits geschilderten Problem des Transports von Integer-Werten ber Any-Schnittstellen. Beide resultieren aus der Tatsache, dass im Basic die exakte Information ber einen UNO-Typ verloren geht oder erst gar nicht vorhanden ist. Weitere Beispiele fr Typen, deren bertragung ber Any-Schnittstellen problematisch ist, sind Arrays und Objekte. Wenn eine sequence<any> bedient werden soll, kann es durchaus passieren, dass Basic versuchen wird, dort eine sequence<short> zu bergeben, wenn alle Elemente des entsprechenden Basic-Arrays zufllig Integer-Werte sind. Bei Objekten entsteht ein Problem, wenn ber einen Any-Parameter ein Interface eines bestimmten Typs bertragen werden soll, nicht einfach nur ein com::sun::star::uno::XInterface, dass Basic automatisch benutzen wrde, wenn es ein UNO-Objekt bergeben soll. Dieses Problem wurde auch schon bei der Java-Sprachanbindung erwhnt, und auch die dort skizzierte Lsung wird genauso in Basic angewendet: Immer wenn Typ-Probleme an einer generischen Schnittstelle auftreten, kann man mit der RuntimeFunktion CreateUnoValue ein Variant erzeugen, dass die exakte UNO-Typinformation enthlt und bewahrt. Dadurch kann bei der bergabe der Variable an einen Any-Parameter der any exakt typisiert werden. Beispiele:
Dim arr%(10) oUNOValue = CreateUnoValue( "[]byte", arr() ) Dim value value = com.sun.star.beans.PropertyState.DEFAULT oUNOValue = CreateUnoValue("com.sun.star.beans.PropertyState", value ) Dim obj oDesktop = CreateUnoService("com.sun.star.frame.Desktop") oUNOValue = CreateUnoValue("com.sun.star.frame.XFramesSupplier", oDesktop )

Im ersten Beispiel wird ein (short) Integer-Array als sequence<byte> bergeben. Dazu ist eine Konvertierung notwendig. Die Funktion CreateUnoValue benutzt dafr den TypeConverter Service (com.sun.star.script.converter). Im vorliegenden Fall wird die Konvertierung nicht gelingen, wenn irgendeines der Elemente von arr() auerhalb des Wertebereichs des Typs byte liegt, der TypeConverter Service wird dann eine Exception werfen, die Basic in Form einer Fehlermeldung weiterreicht. Im zweiten Beispiel enthlt die Variable value zunchst einen Long-Wert, der durch Aufruf von CreateUnoValue in ein Variant berfhrt wird, der vom Basic zwar nach wie vor wie ein Long behandelt wird, aber dadurch, dass er die UNO-Typinformation mitfhrt bei bergabe an ein Any explizit in diesen Typ konvertiert werden kann. Im dritten Beispiel wird sichergestellt, dass vom Objekt oDesktop explizit eine Referenz auf das gewnschte Interface com::sun::star::frame::XFramesSupplier bergeben wird.
Exception Handling in Basic

StarOffice Basic kennt keine Exceptions, daher kann man im Code auch keine Behandlung dafr

implementieren. Stattdessen fngt der Basic-Interpreter selbst alle Exceptions und berfhrt sie in eine bliche Fehlermeldung per Dialogbox, die neben dem Typ der Exception auch etwaige Hinweistexte ausgibt, die eine Exception eventuell in ihrem Message-Property anbietet. Solche durch Exceptions verursachte Laufzeitfehler knnen wie alle anderen Basic-Laufzeitfehler mit den dazu vorgesehenen Basic-Kommandos On Error Goto und Resume behandelt und so anstelle oder zustzlich zu der Dialogbox noch anderer Code ausgefhrt werden. Es ist also prinzipiell mglich, das Programm nach dem Fangen einer Exception fortzusetzen, auch wenn das in manchen Fllen riskant ist (schlielich kann theoretisch das ganze Dokument oder Programm in einem inkonsistenten Zustand sein).

7 Spezielle Aspekte der UNO-Programmierung


Dieses Kapitel erlutert ausgewhlte Elemente des StarOffice API, Programmierbeispiele werden dabei immer in Java und StarOffice Basic angegeben. Die Java-Beispiele werden nicht als komplettes lauffhiges Programm geschrieben, sondern als Code Snippets, die den jeweiligen Aspekt erlutern. Meistens reicht es aber aus, wenn man sie um den ServiceManager und den ComponentContext aus dem Code fr das Simple Bootstrapping aus dem Kapitel ber JavaProgrammierung und ggf. um den Code zur Erzeugung eines Dokuments ergnzt. Die BasicBeispiele sollten in der Regel direkt ausfhrbar sein.

7.1 Lebensdauer von UNO-Objekten


UNO benutzt ebenso wie COM Reference Counting, um die Lebensdauer von Objekten zu steuern. Die Spezifikation des Referenzzhlers eines Objekts sieht vor, dass dann, wenn er von 1 auf 0 geht, das Objekt automatisch zerstrt wird. Ein C++-Programmierer ruft Methoden zum Erhhen und Erniedrigen des Referenzzhlers direkt auf (bzw. lsst es vom Referenz-Template erledigen), ein Java-Programmierer aber nicht, fr ihn sieht es so aus, als htten die UNO-Objekte keinen Referenzzhler, sondern wrden von der Garbage Collection der Java VM abgerumt, wenn sie nicht mehr oder nur noch zyklisch referenziert werden. Was aber tatschlich von der Garbage Collection entfernt wird, sind die bereits erwhnten Proxies, die fr jede Referenz auf ein UNO-Objekt im Java UNO Runtime Environment erzeugt werden. Diese benutzen selbst intern das UNO Reference Counting, um die Lebensdauer des eigentlichen Objekts in dessen UNO Runtime Environments zu steuern (also z.B. dem internen des StarOfficeProzesses). Der Referenzzhler eines UNO-Objekts wird also genau dann auf 0 gehen, wenn neben den internen Referenzen des eigenen UNO Runtime Environments auch alle Proxies in anderen beteiligten UNO Environments entfernt worden sind. Das sieht zunchst nach einem Implementierungsdetail aus, das den Programmierer, der die Objekte nur in jeweils einer Sprache benutzt, nicht kmmern sollte, es fhrt aber zu einem Problem, das es ntig gemacht hat ein UNO-API einzufhren, mit dem man in allen Sprachen explizit in den Lebenszyklus von Objekten eingreifen kann. Manche Objekte halten externe Resourcen wie File Handles direkt oder indirekt (ber andere referenzierte Objekte) fest, die dann zu einem definierten Zeitpunkt freigegeben werden mssen, damit sie anderweitig verwendet werden knnen. Wenn z.B. ein geffnetes Dokument geschlossen wird, muss dessen Zugriff auf die Datei dabei entfernt werden, da diese ansonsten nicht sofort wieder zum Beschreiben geffnet werden kann. Durch die Mglichkeit, dass potentiell jedes UNO-Objekt in einem UNO Environment referenziert wird, das Garbage Collection und kein explizites Reference Counting benutzt, ist es unmglich, genau vorherzusagen, wann ein Objekt zerstrt wird. Daher ist es keine Option, im Destruktor oder Finalizer eines Objekts Code auszufhren, der andere Objekte oder externe Resourcen freigibt, man bentigt dafr ein explizites UNO-API. Stream-Interfaces z.B. haben dafr close-Methoden, mit denen das erledigt wird, UNO bietet aber auch ein explizites Interface fr dieses Konzept, nmlich com::sun::star::lang::XComponent:
module com { module sun { module star { module lang { published struct EventObject { com::sun::star::uno::XInterface Source; }; published interface XEventListener: com::sun::star::uno::XInterface {
void disposing( [in] com::sun::star::lang::EventObject Source );

}; published interface XComponent: com::sun::star::uno::XInterface

{ void dispose(); void addEventListener( [in] XEventListener xListener ); void removeEventListener( [in] XEventListener aListener ); }; }; }; }; };

Mit der Methode dispose wird das Objekt angewiesen, sich selbst in einen Zustand zu bringen, in dem es keinerlei Resourcen mehr festhlt (Systemresourcen oder andere Objekte). Zustzlich mchte man, dass alle anderen Objekte, die ihrerseits eine Referenz auf das zu zerstrende halten, angewiesen werden, diese freizugeben, denn jeder weitere Call an dieses Objekt nach dem Ausfhren des dispose-Calls wird in einer com::sun::star::lang::DisposedException enden. Dafr gibt es die Methoden zum An und Abmelden von EventListenern, die das Objekt in seinem dispose-Call benachrichtigt. Dazu ruft dieses an allen angemeldeten EventListenern deren Methode disposing auf. Als Parameter erhlt der Aufruf dieser Methode in einem struct com::sun::star::lang::EventObject eine Referenz auf das aufrufende Objekt. Dadurch kann das gerufene Objekt erkennen, welches Objekt es denn jetzt loslassen soll. Ein Objekt, das ein anderes referenziert, das das XComponent-Interface untersttzt, muss sich also dort als Listener anmelden, da es jederzeit disposed werden knnte. Zu Listenern spter mehr. Durch diesen Benachrichtigungsmechanismus eignet sich die dispose-Methode auch dazu, zyklische Referenzen aufzulsen, die eine Java Garbage Collection zwar erkennen mag, die in C++ aber in der Regel ein Problem darstellen und natrlich auch dann, wenn zwar die beteiligten Objekte alle Java-Objekte sind, aber aus verschiedenen Java Virtual Machines, die ber UNO miteinander kommunizieren, kurz: nur wenn alle beteiligten Objekte in einer einzigen JVM instantiiert sind, kann man das Problem zyklischer Referenzen ignorieren, in einem offenen Environment wie UNO aber nicht. Durch den dispose-Call, den ein Objekt in der Referenzkette auf ein anderes anwendet, wird dieses seine Referenz auf das aufrufende aufgeben (und ggf. auf andere, die eine eventuell komplexere Kette aufbauen) und so die Blockade lsen. Das funktioniert soweit sehr gut, wenn entweder eine eindeutige Owner-Relation gegeben ist, also ein Objekt eindeutig einem anderen gehrt und dieses es daher jederzeit zerstren darf, oder wenn zwar mehrere Objekte ein anderes gleichberechtigt benutzen, aber keines damit ein Problem hat, wenn dieses Objekt irgendwann zerstrt wird, sofern es dann wenigstens eine Benachrichtigung erhlt. Problematisch wird es, wenn einer der gleichzeitigen Benutzer das Objekt unbedingt braucht, aber ein anderer meint, es zerstren zu wollen. Ein solcher Fall wird spter am Beispiel von Dokumenten geschildert. Dafr muss es dem Objekt mglich sein, sich (unter Mithilfe des Objekts, das es immer noch bentigt) gegen eine Zerstrung zu wehren, gleichzeitig muss aber sichergestellt werden, dass im Falle eines Widerspruchs ein anderer das Objekt spter zerstrt, da es sonst zu den eingangs erwhnten Resourcezugriffsproblemen kommen kann. Die notwendigen Verhandlungen werden ber das Interface com::sun::star::util::XCloseable ausgefhrt:
module com { { void queryClosing(
[in] com::sun::star::lang::EventObject Source,

module sun {

module star {

module util {

published interface XCloseListener: com::sun::star::lang::XEventListener

[in] boolean GetsOwnership ) raises( CloseVetoException );


void notifyClosing( [in] com::sun::star::lang::EventObject Source );

}; published interface XCloseBroadcaster: com::sun::star::uno::XInterface { [oneway] void addCloseListener( [in] XCloseListener Listener );

[oneway] void removeCloseListener( [in] XCloseListener Listener ); }; published interface XCloseable: XCloseBroadcaster { void close( [in] boolean DeliverOwnership ) raises( CloseVetoException ); }; }; }; }; };

Statt dispose ruft man bei Objekten, die dieses Interface anbieten, close auf. Es kann nun passieren, dass dieses Objekt nicht geschlossen werden kann, ohne die Stabilitt des Programms zu gefhrden, dann wird aus dem Aufruf heraus eine com::sun::star::util::CloseVetoException geworfen. Der Aufrufende kann vorher bei dem close-Aufruf dem Objekt mitteilen, wie er in diesem Fall weiter verfahren mchte: bergibt er ein false, dann nimmt er den Mierfolg zur Kenntnis und versucht ggf. spter das Ganze noch einmal. Es wre so, als wre der close-Aufruf nie erfolgt. bergibt er aber true, zeigt er damit an dass er dazu nicht in der Lage ist und dass er daher dem Objekt, dass das Werfen der Exception veranlasst hat, die Verantwortung aufbrdet, spter, wenn der Grund fr die Exception nicht mehr vorliegt, selbst close aufzurufen (diese Objekt wird so gewissermaen zum Owner). Ohne weitere Vorkehrungen ist so aber nur das Objekt selbst, an dem ein close versucht wird, in der Lage, eine Exception zu werfen, das Interface sollte aber auch anderen Objekten ermglichen, gegen ein Zerstren des Objekts zu intervenieren. Dafr knnen diese Objekte sich ber das BasisInterface com::sun::star::util::XCloseBroadcaster als CloseListener anmelden. Dann werden sie nicht nur benachrichtigt, wenn das Objekt tatschlich geschlossen wird (notifyClosing), sondern auch schon vorher gefragt, ob sie dagegen Einspruch erheben wollen (queryClosing). Das tun die Listener durch Werfen der erwhnten com::sun::star::util::CloseVetoException, die das benachrichtigende Objekt dann einfach durchlsst. Der bDeliverOwnerShip-Parameter wird im queryClosing an den Listener weitergereicht, denn der wird ja im Falle des Widerspruchs bei einem Parameterwert von true zum Owner und muss das Objekt spter, wenn es ihm genehmer ist, selbst schlieen. Dann kann natrlich ein anderer Listener intervenieren usw.

7.2 WEAK References ?! 7.3 Arbeiten mit Dokumenten


Das Hauptanwendungsgebiet der UNO-Programmierung mit StarOffice drfte es sein, Dokumente zu erzeugen oder laden, deren Inhalte zu verndern und sie dann z.B. auszudrucken oder zu speichern. Alle Dokumente von StarOffice implementieren ihren eigenen, applikationsspezifischen Service, ber den auch ein Dokument dieses Typs erzeugt werden kann (s. nchsten Abschnitt). Diese Services schlieen den Service com::sun::star::document::OfficeDocument ein, der schon im Kapitel ber Services gezeigt wurde. Das Interface com::sun::star::frame::XModel, das als Basis-Interface von Dokumenten betrachtet werden kann, wird im Kapitel ber das Framework API nher erlutert, im Folgenden werden andere Aspekte des StarOffice Dokument-API betrachtet. Weitere eigenstndige Kapitel sind den Aspekten Metadaten (DocumentInfo) und Dokument-Events gewidmet.
Erzeugen von Dokumenten

Das StarOffice API bietet grundstzlich zwei Wege, ein Dokument zu erzeugen. Der einfachste Weg ist der, das jeweilige Dokument als Service zu erzeugen:

java.lang.Object document = xServiceManager.createInstanceWithContext( DocumentServiceName, xContext); com.sun.star.frame.XLoadable xLoadable = (com.sun.star.frame.XLoadeable) UnoRuntime.queryInterface(com.sun.star.frame.XLoadable.class, document); xLoadable.initNew();

In Basic sehe das dann so aus:


doc = CreateUnoService( ServiceName$ ) doc.initNew()

Mit diesem Code erzeugt man sich ein neues, leeres Dokument. Von welchem Typ dieses Dokument ist, hngt vom Inhalte der String-Variablen DocumentServiceName ab, die an den Service Manager bergeben wurde: Dokumenttyp StarOffice Writer StarOffice Writer (Globaldokument) StarOffice Calc StarOffice Impress StarOffice Draw Service-Name com.sun.star.text.TextDocument com.sun.star.text.GlobalDocument com.sun.star.sheet.SpreadsheetDocument com.sun.star.presentation.PresentationDocument com.sun.star.drawing.DrawingDocument

StarOffice Math com.sun.star.formula.FormulaProperties ber die Service-Namen aus der Tabelle kann man mit Hilfe der UNOIDL Referenz auch erfahren, welche Interfaces und Properties das erhaltene Objekt untersttzt. Das Beispiel des Service com.sun.star.Text.TextDocument wurde ja schon in einem frheren Kapitel gezeigt. Natrlich kann man statt ein neues, leeres Dokument zu erzeugen auch ein Dokument aus einer bereits existierenden Quelle laden. Dafr ersetzt man den initNew-Aufruf aus den beiden CodeBeispielen durch einen Aufruf der Methode load aus dem gleichen Interface. Dort wird als einziger Parameter eine sequence <com::sun::star::beans::PropertyValue> bergeben, die als Implementierung des abstrakten Service com::sun::star::document::MediaDescriptor aufgefasst wird. Dieser Service fasst eine Reihe von Properties zusammen, die fr das Laden von Dokumenten aus den verschiedensten Quellen (Medien) und unter den verschiedensten Umstnden von Interesse sein knnen. Einige davon beschreiben die Dokumentquelle, einige beeinflussen nur den Ladevorgang selbst. Mehr dazu in einem eigenen Abschnitt. Eines der Properties ist natrlich eine URL, aus der man das Dokument laden kann. Der Java-Code dafr wrde dann wie folgt aussehen (das Beispiel ldt eine Datei von einem Windows-Dateisystem):
java.lang.Object document = xServiceManager.createInstanceWithContext( DocumentServiceName, xContext); com.sun.star.frame.XLoadable xLoadable = (com.sun.star.frame.XLoadeable) UnoRuntime.queryInterface(com.sun.star.frame.XLoadable.class, document); com.sun.star.beans.PropertyValue[] Properties = new com.sun.star.beans.PropertyValue[1]; Properties[0] = new com.sun.star.beans.PropertyValue(); Properties[0].Name = "URL"; Properties[0].Value = "file:///c:/myfile.odt"; xLoadable.load( Properties );

oder in Basic:
doc = CreateUnoService( ServiceName$ ) dim properties(0) as new com.sun.star.beans.PropertyValue properties(0).Name = "URL" properties(0).Value = "file:///c:/myfile.odt"; doc.load( properties() )

Die beiden Methoden des Interface com::sun::star::frame::XLoadable erzeugen ein Dokument ohne ein dazugehriges Fenster. Alle StarOffice-Dokumente untersttzen dieses Interface, auch wenn es aus historischen Grnden nur ein optionales Interface des von allen

Dokumenten implementierten Service com::sun::star::document::OfficeDocument ist, der schon im Kapitel ber Services erwhnt wurde. Mehr zu diesem Service folgt noch. Mchte man ein Dokument in ein Applikationsfenster laden, muss man ein anderes API, und zwar das Interface com::sun::star::frame::XComponentLoader benutzen. Dieses Interface wird u.a. vom Desktop-Objekt implementiert und hat nur eine einzige Methode loadComponentFromURL:
java.lang.Object desktop = xServiceManager.createInstanceWithContext( "com.sun.star.frame.Desktop", xContext); com.sun.star.frame.XComponentLoader xLoader = (com.sun.star.frame.XComponentLoader) UnoRuntime.queryInterface(com.sun.star.frame.XComponentLoader.class, desktop); com.sun.star.beans.PropertyValue[] Props = new com.sun.star.beans.PropertyValue[0]; com.sun.star.lang.XComponent document = xLoader.loadComponentFromURL( "file:///c:/myfile.odt", "_blank", 0, Props ); oder wieder in Basic: desktop = CreateUnoService( "com.sun.star.frame.Desktop" ) dim properties() doc = desktop.loadComponentFromURL( "file:///c:/myfile.odt", "_blank", 0, properties() )

Auch diese Methode benutzt den MediaDescriptor, wobei zustzlich das URL-Property als eigenstndiger Parameter bergeben wird, da dieses alleine recht hufig ausreicht und man so (wie oben gezeigt) einfach einen leeren MediaDescriptor bergeben kann, was Schreibarbeit spart. Allerdings hat diese Methode noch zwei weitere Parameter, die etwas mit der Erzeugung des Dokumentfensters zu tun haben. hnlich wie ein Browser untersttzt StarOffice bei der Erzeugung von Fenstern ein Target Property, das angibt, in welches Fenster das Dokument geladen werden soll. Dabei sind prinzipiell die gleichen Targets erlaubt wie bei einem Browser (_blank, _top etc.) und sie haben auch die gleiche Bedeutung. Ein spezielles Target _default berlsst StarOffice die Auswahl, wohin das Dokument geladen werden soll, z.B. wird StarOffice bei bergabe des Targets _default ein Dokument in ein bereits vorhandenes Fenster laden, wenn dieses das aktive ist und kein Dokument oder ein leeres, nicht modifiziertes Dokument des gleichen Typs wie das zu ladende enthlt. Das wird aber nicht gemacht, wenn (wie im Beispiel) das Target _blank verwendet wird, hier wird grundstzlich immer ein neues Fenster als System-Taskfenster angelegt. Der dritte Parameter (im Beispiel eine 0) steuert in komplizierteren Fllen die Suche von Fenstern ber ihren Namen und kann hier auen vor bleiben. Ausfhrlichere Informationen darber findet man im Developers Guide in den Kapiteln 6.1.3 und 6.1.5. Als Ergebnis dieser beiden Mglichkeiten, ein Dokument zu erzeugen oder zu laden erhlt der Basicprogrammierer ein Objekt, an dem er wie blich ber alle seine Methoden und Properties direkt verfgen kann. Der Java-Programmierer wird allerdings wie blich ausgehend von dem aus dem gezeigten Code erhaltenen Interface (com::sun::star::frame::XLoadable bzw. com::sun::star::lang::XComponent) weitere Interfaces ber queryInterface erfragen mssen, um mit dem Dokument zu arbeiten. Den verschiedenen Dokument-API sind eigene Kapitel gewidmet.
Der MediaDescriptor

Wie bereits erwhnt kommt dem Service com::sun::star::document::MediaDescriptor eine zentrale Bedeutung beim Laden (und wie spter gezeigt auch beim Speichern) von Dokumenten zu. Er beschreibt eine DokumentResource und die Art und Weise, wie von ihr geladen bzw. in sie gespeichert werden soll. Nachfolgend eine alphabetische Referenz, Properties, die ausschlielich zum Speichern verwendet werden, sind mit einem Stern (*) gekennzeichnet. Noch detailliertere Erluterungen zum

MediaDescriptor finden sich im Kapitel 6.1.5 des Developers Guide. Name und Typ des Properties AsTemplate (boolean) Mgliche Werte und Bedeutung True: Das Dokument wird als Vorlage fr ein neues, unbenanntes benutzt. False: Das Dokument wird als solches geladen. Wenn das zu ladende Dokument selbst eine Vorlage ist, wird automatisch AsTemplate als true angenommen, bei normalen Dokumenten als false. Wenn per API eine Version eines Dokuments erzeugt werden soll, wird hier der Name des Autors bergeben. StarOffice speichert diese Version zusammen mit Author und Kommentar innerhalb des Dokument-Containers ab. Fr textuelle Formate mit single byte characters: Zeichensatz, in dem das Dokument kodiert ist Wenn per API eine Version eines Dokuments erzeugt werden soll, wird hier ein Kommentar dafr bergeben. StarOffice speichert diese Version zusammen mit Author und Kommentar innerhalb des Dokument-Containers ab. Eine Art Sub-Mediadescriptor, in dem beliebige Properties, die nur fr den jeweiligen Dokumenttyp interessant sind, bergeben werden knnen. Eine Art Sub-Mediadescriptor, in dem beliebige Properties, die nur fr den jeweiligen Filter interessant sind, bergeben werden knnen. Name des Filters, mit dem geladen bzw. gespeichert werden soll. Diese entsprechen den Namen aus der FilterKonfigurationsdatei. Unbekannte Namen werden ignoriert, beim Laden werden ansonsten ausgewhlte Filter durch TypeDetection berprft. Einige ltere Filter verwenden die bergabe von FilterProperties als String. Fr neue Filter wird FilterData empfohlen. True: es wird zwar ein Dokumentfenster erzeugt, dieses wird aber nicht sichtbar gemacht. Dies erlaubt es, auch View-basierte API zu nutzen. Wird beim Laden verwendet und hat bei Existenz Vorrang vor allen anderen Properties wie URL. Der Stream geht durch das Laden in den Besitz des Dokuments ber.

Author(*) (string)

Characterset (string) Comment(*) (string)

ComponentData (any)

FilterData (any)

FilterName (string)

FilterOptions (string)

Hidden (boolean)

InputStream (com.sun.star.io.XInputStream)

InteractionHandler Objekt, das die Behandlung von Fehlern whrend des (com.sun.star.task.XInteractionHandler) Ladens und Speicherns bernimmt. Wird keines bergeben oder kann das bergebene Objekt einen bestimmten Fehler nicht behandeln, wird die aufgerufene Methode eine Exception werfen. StarOffice stellt eine Standardimplementierung mit dem Service-Namen com.sun.star.task.InteractionHandler bereit.

Name und Typ des Properties JumpMark (string) MediaType (string)

Mgliche Werte und Bedeutung Gibt den Namen einer Sprungmarke an, die nach dem Laden des Dokuments automatisch angesprungen wird. Bezeichnet den Typ der Resource, die geladen soll. Damit er sinnvoll verwendet werden kann, muss er mit einem der Werte bereinstimmen, die in der TypeDetection-Konfiguration eingetragen sind. In diesem Fall wird die sonst bliche TypeDetection zur Verifizierung eines Filters bersprungen. True: Erzwingt das ffnen eines neuen Fensters im Fall dass das zu ladende Dokument schon geladen ist und das Target _default ist. Normalerweise wrde StarOffice hier einfach ein Fenster des geladenen Dokuments nach vorne bringen. True: wenn unter der URL, die fr das Speichern eines Dokuments ausgewhlt wurde, schon eine Datei existiert, wird sie berschrieben. False: im gleichen Fall wird das Speichern mit einer Exception abgebrochen (default). Beim Speichern eines Dokuments kann direkt ein Stream bergeben werden, in den man den Inhalt des Dokuments haben mchte. Dieser hat automatisch Vorrang vor allen anderen Resource-Bezeichnern wie dem URL-Property. Kann beim Laden oder Speichern angegeben werden. Wird eine passwortgeschtzte Datei per API ohne Passwort im MediaDescriptor geladen, gibt es eine Exception. Der Standard-InteractionHandler wrde dann einen Passwortdialog anzeigen und das eingegebene Passwort im MediaDescriptor platzieren. HTTP Post request werden in StarOffice logisch als Ladevorgnge behandelt, da sie hufig ein Dokument zurckgeben. PostData wird als Stream bergeben. True: Die View des Dokuments wird fr eine PreviewFunktionalitt optimiert und es wird kein UI angezeigt. True: Das Dokument-UI erlaubt keine Editieren des Dokuments, die Datei wird beim Laden nicht gelockt. False: Es wird versucht, die Datei zum Schreiben zu ffnen und zu Locken. Schlgt das fehl, wird eine Exception geworfen. Default (Property nicht gesetzt): es wird erst ein ffnen zum Schreiben samt Locken versucht und wenn das fehlschlgt automatisch readonly geffnet. Beschreibt das Environment einer Anforderung zum Laden. Bekannt z.B. als URL des Dokuments bei einem HTTP Post Request aus dem Dokument heraus. Objekt, das Status-Informationen whrend des Ladens oder Speicherns entgegennimmt und z.B. in eine Fortschrittsanzeige umsetzt. Beim Laden eines Dokuments in einen Frame (s.u.) kann man am Frame die

OpenNewView (boolean)

Overwrite(*) (boolean)

OutputStream(*) (com.sun.star.io.XOutputStream)

Password (string)

PostData (com.sun.star.io.XInputStream) Preview (boolean) Readonly (boolean)

Referer (string)

StatusIndicator (com.sun.star.task.XStatusIndicator)

Name und Typ des Properties

Mgliche Werte und Bedeutung Methode createStatusIndicator benutzen, um ein solches Objekt zu erhalten, man kann aber natrlich auch sein eigenes Objekt implementieren.

TemplateName (string) TemplateRegionName (string)

Der logische Name einer Dokumentvorlage. Der logische Name der Gruppe einer Dokumentvorlage. Zusammen mit TemplateName identifiziert es eine Vorlage. Diese wird dann benutzt, um daraus ein unbenanntes Dokument zu erzeugen. Quelle beim Laden bzw. Ziel beim Speichern in korrekt encodeter URL-Notation. StarOffice-Dokumente erlauben es, im DokumentContainer verschiedene Versionen abzuspeichern. Die einzelnen Versionen werden beim Laden ber ihre Nummer angesprochen. Versionen werden grundstzlich readonly geladen. Eine Art Sub-MediaDescriptor, in dem beliebige Properties abgelegt werden, die die View des Dokuments interpretiert, wenn sie nach dem Erzeugen damit initialisiert wird. Damit lt sich z.B. die Cursorposition nach dem Laden restaurieren. Die meisten StarOffice-Dokumente haben verschiedene Views (wie z.B. die Print Preview zustzlich zur normalen Edit View). Diese werden ber eine ID bezeichnet und knnen so beim Laden ausgewhlt werden. Wenn dieses Property nicht angegeben ist, werden beim Laden des Dokuments oder danach keine Makros aus dem Dokument ausgefhrt. Durch Auswahl eines Werts aus der Constant Group com::sun::star::document::MacroExecMod e kann man das bersteuern (z.B. dahingehend, dass Makros immer ausgefhrt werden oder nur nach Rckfrage oder nur, wenn das Dokument signiert ist usw.).

URL (string) Version (short)

ViewData (any)

ViewId (short)

MacroExecutionMode (short)

Wenn dieses Property nicht angegeben ist, werden beim Laden des Dokuments oder danach keine Updates (z.B. von Verknpfungen oder aus Dokumentvorlagen) vorgenommen. Durch Auswahl eines Werts aus der Constant Group com::sun::star::document::UpdateDocMod e kann man das bersteuern. Fr das Property URL sind beliebige Strings erlaubt, die eine gltige URL nach RFC 2396 darstellen und fr deren Schema ein sogenannter Universal Content Provider (UCP) in StarOffice registriert ist, also z.B. Provider fr file:, ftp:, http: usw. Zustzlich untersttzt StarOffice noch ein private:-Protokoll, das u.a. fr das Erzeugen unbenannter Dokumente benutzt wird: private:factory/swriter- erzeugt ein leeres, unbenanntes StarOffice Textdokument private:factory/scalc - erzeugt ein leeres, unbenanntes StarOffice Tabellendokument private:factory/sdraw - erzeugt ein leeres, unbenanntes StarOffice Grafikdokument

UpdateDocMode (short)

private:factory/simpress private:factory/sdatabase
Speichern von Dokumenten

- erzeugt ein leeres, unbenanntes StarOffice Prsentationsdokument - erzeugt ein leeres, unbenanntes StarOffice Datenbankdokument

Der allen StarOffice-Dokumenten eigene Service com::sun::star::document::OfficeDocument enthlt u.a. auch das Interface com::sun::star::container::XStorable, mit dem ein Objekt gespeichert werden kann:
module com { module sun { module star { module frame { published interface XStorable: com::sun::star::uno::XInterface { boolean hasLocation(); string getLocation(); boolean isReadonly(); void store() raises( com.sun.star.io.IOException ); void storeAsURL( [in] string sURL, [in] sequence<com::sun::star::beans::PropertyValue> lArguments ) raises( com.sun.star.io.IOException ); void storeToURL( [in] string sURL, [in] sequence<com::sun::star::beans::PropertyValue> lArguments ) raises( com.sun.star.io.IOException ); }; //============================================================================= }; }; }; };

Mit der storeToURL-Methode kann ein Dokument in eine beliebige Resource gespeichert werden, die StarOffice durch einen UCP erreichen kann. Der zweite Parameter dieser Methode ist wieder der bereits erluterte MediaDescriptor, wobei natrlich nur die Properties verarbeitet werden, die auch Sinn machen. Die Methode storeAsURL tut genau das gleiche, allerdings bernimmt sie anschlieend noch die angegebene URL als Location des Dokuments, genauso wie nach dem Laden eines Dokuments aus einer URL diese URL die Location des Dokuments ist (auer das Laden erfolgte mit AsTemplate=true oder das Dokument ist eine Vorlage). Die Location ist der Ort, unter dem das Dokument mit einem Aufruf der store-Methode gespeichert wird. Der Dateiname (ohne Pfad) wird in der Titelzeile der Fenster angezeigt, die eine View auf das Dokument zeigen. Ob ein Dokument eine Location hat und welche das ist kann ber die Methoden hasLocation und getLocation erfragt werden. Ein weiterer wichtiger Unterschied zwischen storeToURL und den beiden anderen Methoden zum Speichern ist, das erstere auer der Location des Dokuments auch andere Zustnde nicht ndert, z.B. das Modified-Flag, das vom Interface com::sun::star::util::XModifiable verwaltet wird. Dieses Interface erlaubt es auch, ber sein Basis-Interface Listener anzumelden, die immer dann benachrichtigt werden, wenn das Dokument gendert werden:
module com { module sun { module star { module util { published interface XModifyBroadcaster: com::sun::star::uno::XInterface { void addModifyListener( [in] com::sun::star::util::XModifyListener aListener ); void removeModifyListener( [in] com::sun::star::util::XModifyListener aListener ); }; published interface XModifiable: com::sun::star::util::XModifyBroadcaster {

boolean isModified(); void setModified( [in] boolean bModified ) raises( com::sun::star::beans::PropertyVetoException ); }; }; }; }; };

Es hat sich als sinnvoll herausgestellt, dass auch bei einem store-Aufruf ein MediaDescriptor bergeben werden kann, daher gibt es seit StarOffice8 ein erweitertes Interface zum Speichern, das das erlaubt:
module com { module sun { module star { module frame { published interface XStorable2: XStorable { void storeSelf( [in] sequence<com::sun::star::beans::PropertyValue> lArguments )
raises( com::sun::star::lang::IllegalArgumentException,

com.sun.star.io.IOException ); }; }; }; }; };

Dieses ist zwar natrlich aus Sicht des Service com::sun::star::document::OfficeDocument optional, es wird aber von allen Dokumenten von StarOffice ab StarOffice8 untersttzt. Ein Beispiel, in dem ein Dokument im HTML-Format exportiert wird, soll das Speichern per API verdeutlichen:
// Annahmen: xDocument sei ebenso gegeben wie sURL // Name des Filters beim Speichern String sFilter = null; // Dokumenttyp ber den Service-Namen bestimmen com.sun.star.lang.XServiceInfo xInfo = (com.sun.star.lang.XServiceInfo) UnoRuntime.queryInterface( com.sun.star.lang.XServiceInfo.class, xDocument); // HTML filter name je nach Typ; untersttzt sind Calc, Writer, Writer/Web if(xInfo!=null) { if( xInfo.supportsService ("com.sun.star.text.TextDocument") ) sFilter = new String("HTML (StarWriter)"); else if(xInfo.supportsService ("com.sun.star.text.WebDocument") ) sFilter = new String("HTML"); else if(xInfo.supportsService ("com.sun.star.sheet.SpreadsheetDocument") ) sFilter = new String("HTML (StarCalc)"); } // Speichern mit berschreiben if(sFilter!=null) { com.sun.star.beans.PropertyValue[] lProperties = new com.sun.star.beans.PropertyValue[2]; lProperties[0] = new com.sun.star.beans.PropertyValue(); lProperties[0].Name = "FilterName"; lProperties[0].Value = sFilter; lProperties[1] = new com.sun.star.beans.PropertyValue(); lProperties[1].Name = "Overwrite"; lProperties[1].Value = new Boolean(true); com.sun.star.frame.XStorable xStore =(com.sun.star.frame.XStorable) UnoRuntime.queryInterface(com.sun.star.frame.XStorable.class, xDocument); xStore.storeAsURL (sURL, lProperties); }

In Basic sieht das dann so aus:


doc = ThisComponent dim FilterName$

URL$="file:///c:/test.html" ' Dokumenttyp ber den Service-Namen bestimmen ' HTML filter name je nach Typ; untersttzt sind Calc, Writer, Writer/Web if doc.supportsService ("com.sun.star.text.TextDocument") then FilterName$ = "HTML (StarWriter)" elseif doc.supportsService ("com.sun.star.text.WebDocument") then FilterName$ = "HTML" elseif doc.supportsService ("com.sun.star.sheet.SpreadsheetDocument") then FilterName$ = "HTML (StarCalc)" endif ' Speichern mit berschreiben if LEN(FilterName$) then dim Properties(1) as new com.sun.star.beans.PropertyValue Properties(0).Name = "FilterName" Properties(0).Value = FilterName$ Properties(1).Name = "Overwrite" Properties(1).Value = True doc.storeToURL( URL$, Properties() ) endif

Drucken von Dokumenten

Ein weiteres Interface aus dem Service com::sun::star::document::OfficeDocument ist com::sun::star::view::XPrintable:


module com { module sun { module star { module view { published interface XPrintable: com::sun::star::uno::XInterface { sequence<com::sun::star::beans::PropertyValue> getPrinter(); void setPrinter( [in] sequence<com::sun::star::beans::PropertyValue> aPrinter )
raises( com::sun::star::lang::IllegalArgumentException ); raises( com::sun::star::lang::IllegalArgumentException );

void print( [in] sequence<com::sun::star::beans::PropertyValue> xOptions ) }; }; }; }; };

Zum Drucken verwendet man die Methode print, der Druckoptionen bergeben werden knnen, die als eigenstndiger Service com::sun::star::view::PrintOptions definiert sind. Zustzlich zu den dort definierten Optionen sind auch weitere, fr das jeweilige Dokument spezifische Optionen mglich, z.B. erlaubt ein Writer-Dokument das Drucken nur linker Seiten, whrend ein Calc-Dokument es erlaubt, nur ausgewhlte Tabellen zu drucken. Die Implementierung des Service ist wie beim MediaDescriptor wieder sequence<com::sun::star::beans::PropertyValue>. Weiterhin kann ber dieses Interface der Drucker des Dokuments konfiguriert werden. Ein Drucker wird hier als Service com::sun::star::view::PrinterDescriptor gesehen, die auch wieder als eine sequence<com::sun::star::beans::PropertyValue> bergeben bzw. ausgelesen werden kann. Ein Beispiel zum Drucken, das keine applikationsspezifischen Einstellungen verwendet und daher fr alle Dokumente geeignet ist, ist das folgende:
com.sun.star.view.XPrintable xPrintable = (com.sun.star.view.XPrintable) UnoRuntime.queryInterface( com.sun.star.view.XPrintable.class, xDoc); com.sun.star.beans.PropertyValue[] printerDesc = new com.sun.star.beans.PropertyValue[1]; // Druckername setzen (=Drucker auswhlen) printerDesc[0] = new PropertyValue();

printerDesc[0].Name = "Name"; printerDesc[0].Value = "MyFavoritePrinter"; xPrintable.setPrinter(printerDesc); com.sun.star.beans.PropertyValue[] printOpts = new com.sun.star.beans.PropertyValue[1]; printOpts[0] = new com.sun.star.beans.PropertyValue(); printOpts[0].Name = "Wait"; printOpts[0].Value = new Boolean(true); xPrintable.print(printOpts);

Das Wait-Property der PrintOptions ist sehr ntzlich, da beim Setzen desselben auf true der print-Aufruf garantiert, dass das Drucken beendet ist und das Dokument problemlos geschlossen werden kann. Ohne das wird der Aufruf in der Regel schon vor der Beendigung des Druckvorgangs zurckkehren, da beim Drucken vieles im Hintergrund erledigt wird. In Basic sieht das dann so aus:
doc = ThisComponent dim PrinterDesc(0) as new com.sun.star.beans.PropertyValue ' Druckername setzen (=Drucker auswhlen) PrinterDesc(0).Name = "Name" PrinterDesc(0).Value = "MyFavoritePrinter" doc.setPrinter( PrinterDesc() ) dim PrintOpts(0) as new com.sun.star.beans.PropertyValue PrintOpts(0).Name = "Wait" PrintOpts(0).Value = True doc.print(printOpts)

Fr weitere Druckeroptionen oder Drucker-Properties sei auf die IDL-Referenz verwiesen.


Schlieen von Dokumenten

Dokumente sind typischerweise Objekte, die von mehreren anderen Objekten referenziert werden. Da sie auerdem in der Regel auch System-Resourcen wie File Handles und nicht unerhebliche Mengen Speicher belegen, wird man diese mglichst sofort freigeben wollen, wenn man das Dokument nicht mehr bentigt. Alle diese Umstnde zeigen, dass Dokumente ein typischer Anwendungsfall fr das bereits beschriebene Interface com::sun::star::util::XCloseable sind. Ein API-Programmierer, der sich ein Dokument wie beschrieben erzeugt, es dann verndert, gedruckt oder gespeichert hat, wird es dann durch einen Aufruf von close wieder schlieen wollen:
com.sun.star.frame.XModel xModel = getDocumentFromSomewhere(); com.sun.star.util.XCloseable xCloseable = (com.sun.star.util.XCloseable) UnoRuntime.queryInterface( com.sun.star.util.XCloseable.class, xDocument ); if(xCloseable!=null) { try { xCloseable.close(true); } catch(com.sun.star.util.CloseVetoException exCloseVeto) { } } else { // In StarOffice6 untersttzten Dokumente das Xcloseable-Interface noch nicht! xModel.dispose(); }

Der Beispielcode zeigt auch, dass in StarOffice6 noch kein XCloseable untersttzt wurde, sodass man theoretisch damit rechnen muss, an einem Dokument keinen Support fr das Interface zu bekommen. In StarOffice6 wurde die entsprechende Problematik intern, aber fr den APIProgrammierer nicht nachvollziehbar gelst. In Basic ist momentan der Gebrauch von close problematisch, da Exceptions nicht sicher behandelt werden knnen. Daher muss man zu einem Trick greifen oder damit leben, dass im Falle des Scheiterns eines close-Calls das Basic-Macro gestoppt wird, da das die Standardreaktion von StarOffice Basic auf das Auftreten einer Exception ist. Der Trick besteht darin, einen speziellen Error Handler fr close-Calls zu benutzen:
Sub CloseDocument( doc ) On Error Goto CloseHandler doc.close(True) ' das Macro wird hier fortgesetzt ' ... exit sub CloseHandler: Resume end sub

Eine Restunsicherheit bleibt bei diesem Konstrukt, da theoretisch auch eine andere Exception (RuntimeException) im close-Call geworfen werden kann, nach der die Fortsetzung des Programms riskant ist, allerdings ist die Wahrscheinlichkeit dafr sehr gering. Nichtsdestotrotz wird dieses Problem in einer spteren StarOffice-Version mit Basic-Sprachmitteln gelst werden. Wann ist denn bei Dokumenten zu erwarten, dass ein close scheitern kann? Die Spezifikation der Methode sieht vor, dass nur temporre Grnde oder die Gefahr eines Programmabsturzes ein Verhindern rechtfertigen. Die Tatsache, dass ein Dokument gerade modifiziert und noch nicht gespeichert ist, gehrt nicht dazu, auch ein modifiziertes Dokument wird daher einen close-Aufruf zulassen. Das Schlieen eines Dokuments ber das Men beispielsweise verwendet daher noch zustzlichen Code, um eine Benutzerinteraktion vorzuschalten. Gute Grnde treten aber auf, wenn zu einem Dokument eine oder mehrere Views existieren: eine davon knnte gerade in einem modalen Zustand sein (beispielsweise knnte innerhalb ihres Fensters ein modaler Dialog geffnet sein), der erst beendet werden muss, bevor ihr Fenster Fenster geschlossen werden kann. Da die Interaktion zwischen View und Dokument sehr komplex ist, ist es sicherer, solange auch ein Schlieen des Dokuments zu verbieten. hnliches gilt, wenn wenn im Hintergrund das Dokument gerade gedruckt wird. In beiden Fllen wird eine nicht sichtbare View nach Beendigung der Situation, die zu der Verweigerung des Schlieens gefhrt hat, gem Spezifikation automatisch versuchen, das Dokument zu schlieen. Ist die View sichtbar, ist das nicht notwendig, da das vom Benutzer gemacht werden kann, auerdem wird es von einem Benutzer wahrscheinlich auch als irritierend empfunden.

7.4 StarOffice Application Framework API


Frames

Wenn StarOffice ein Dokument in ein Fenster ldt, wird ein solches Fenster durch das Interface com::sun::star::awt::XWindow reprsentiert. Natrlich gibt es dort keine Methode, um ein Dokument an dieses zu binden, dafr wird ein weiteres Objekt verwendet, das gewissermaen die Verwaltung des Fensters bernimmt. Ein solches Objekt ist ein Frame, der in StarOffice den Service com::sun::star::frame::Frame implementiert. Das wichtigste Interface dieses Service ist das Interface com::sun::star::frame::XFrame:
module com { module sun { module star { module frame { published interface XFrameActionListener;

published interface XController; published interface XFramesSupplier;


published interface XFrame: com::sun::star::lang::XComponent

{ void initialize( [in] com::sun::star::awt::XWindow xWindow ); com::sun::star::awt::XWindow getContainerWindow(); [oneway] void setCreator( [in] XFramesSupplier Creator ); XFramesSupplier getCreator(); string getName(); [oneway] void setName( [in] string aName ); XFrame findFrame( [in] string aTargetFrameName, [in] long nSearchFlags); boolean isTop(); [oneway] void activate(); [oneway] void deactivate(); boolean isActive(); boolean setComponent( [in] com::sun::star::awt::XWindow xComponentWindow, [in] XController xController); com::sun::star::awt::XWindow getComponentWindow(); XController getController(); void contextChanged(); [oneway] void addFrameActionListener( [in]XFrameActionListener xListener ); [oneway] void removeFrameActionListener( [in] XFrameActionListener xListener ); }; }; }; }; };

Ein solcher Frame ist nur in Zusammenhang mit einem Fenster als valides Objekt zu betrachten, d.h. als allererste Methode nach seiner Erzeugung muss immer die initialize-Methode benutzt werden, um dem Frame sein Container Window zu geben. Frames werden in StarOffice auch benutzt, um Hierarchien von Dokumenten aufzubauen, also z.B. die Einbettung eines Floating Frame oder eines aktivierten OLE-Objekts in ein Writer-Dokument oder das Einblenden des Datenquellen-Fensters in ein Calc-Dokument. Der eingebettete Frame erhlt dann einen Parent Frame, der ber die get/SetCreator-Methoden (der Name ist historisch bedingt) bzw. in Basic wie blich ber das Creator-Property gelesen oder gesetzt wird. Aus Sicht des Parent Frames ist der eingebettete Frame einer seiner Child Frames, die er ber ein weiteres seiner Interfaces, nmlich com::sun::star::frame::XFramesSupplier, verwaltet. Die Trennung in zwei Interfaces verdeutlicht, dass jeder Frame prinzipiell einen Parent Frame haben kann, aber keine Child Frames zulassen muss. Anders herum knnen Objekte Child Frames haben ohne selbst ein Frame zu sein. Innerhalb einer solchen Frames-Hierarchie kann man nach Frames suchen, da diese auch Namen haben knnen (get/SetName-Methoden bzw. Name-Property). Die dafr verwendete Methode findFrame ist im Developers Guide sehr ausfhrlich beschrieben, sie untersttzt auch die bereits beim ComponentLoader erwhnten Targets _top, _parent usw. und und erlaubt es auch, neue Frames zu erzeugen. Der folgende Beispielcode verdeutlicht das Arbeiten mit Frames (Fehlerbehandlung der Krze wegen weggelassen):
// Toolkit Service fr die Erzeugung von Fenstern Object toolkit = xServiceManager.createInstanceWithContext( "com.sun.star.awt.toolkit", xContext ); com.sun.star.awt.XToolkit xtoolkit = (com.sun.star.awt.XToolkit) UnoRuntime.queryInterface( com.sun.star.awt.XToolkit.class, toolkit); // Beschreibung des gewnschten Fensters: TopWindow ohne Parent, verschiebbar,

// Gre nderbar, schliebar com.sun.star.awt.WindowDescriptor descriptor = new com.sun.star.awt.WindowDescriptor; Descriptor.Type Descriptor.WindowServiceName Descriptor.ParentIndex Descriptor.Parent Descriptor.WindowAttributes = = = = = com.sun.star.awt.WindowClass_TOP; "window"; -1; null; com.sun.star.awt.WindowAttribute.BORDER | com.sun.star.awt.WindowAttribute.MOVEABLE | com.sun.star.awt.WindowAttribute.SIZEABLE | com.sun.star.awt.WindowAttribute.CLOSEABLE; = new com.sun.star.awt.Rectangle(0,0,0,0);

Descriptor.Bounds

// Fenster mit gewnschten Eigenschaften erzeugen com.sun.star.awt.XWindowPeer xPeer = xToolkit.createWindow( Descriptor ); com.sun.star.awt.XWindow xWindow = (com.sun.star.awt.XWindow) UnoRuntime.queryInterface(com.sun.star.awt.XWindowPeer.class, xPeer ); // Fensterhintergrundfarbe transparent setzen xPeer.setBackground(0xFFFFFFFF); // Desktop-Objekt besorgen, um Frame dort als Child Frame einzuhngen Object desktop = xServiceManager.createInstanceWithContext( "com.sun.star.frame.Desktop", xContext); com.sun.star.frame.XFramesSupplier xSup = (com.sun.star.frames.XFramesSupplier) UnoRuntime.queryInterface(com.sun.star.frame.XFramesSupplier.class, desktop); com.sun.star.frame.XFrames xContainer = xSup.getFrames(); // Einen neuen Frame erzeugen Object frame = xServiceManager.createInstanceWithContext("com.sun.star.frame.Frame", xContext); com.sun.star.frame.XFrame xTask = (com.sun.star.frame.XFrame) UnoRuntime.queryInterface(com.sun.star.frame.XFrame.class, frame); // Frame mit Fenster initialisieren xTask.initialize( xWindow ); // Fertigen Frame einhngen, dabei wird der Desktop zum Parent des neuen Frames xContainer.append( xTask ); // Auch Frames untersttzen das ComponentLoader-Interface com.sun.star.frame.XComponentLoader xLoader = (com.sun.star.frame.XComponentLoader) UnoRuntime.queryInterface( com.sun.star.frame.XComponentLoader.class, xTask ); // Ein Dokument in den Frame laden com.sun.star.beans.PropertyValue[] Props = new com.sun.star.beans.PropertyValue[0]; xLoader.loadComponentFromURL("private:factory/swriter", "_self", 0, Props );

In Basic sieht das dann so aus:


' Toolkit Service fr die Erzeugung von Fenstern toolkit = CreateUnoService( "com.sun.star.awt.Toolkit") ' Beschreibung des gewnschten Fensters: TopWindow ohne Parent, verschiebbar, ' Gre nderbar, schliebar descriptor = CreateUnoStruct("com.sun.star.awt.WindowDescriptor") descriptor.Type = com.sun.star.awt.WindowClass.TOP Descriptor.WindowServiceName = "window" Descriptor.ParentIndex = -1 Descriptor.WindowAttributes = com.sun.star.awt.WindowAttribute.BORDER _ OR com.sun.star.awt.WindowAttribute.MOVEABLE _ OR com.sun.star.awt.WindowAttribute.SIZEABLE _ OR com.sun.star.awt.WindowAttribute.CLOSEABLE ' Fenster mit gewnschten Eigenschaften erzeugen window = toolkit.createWindow( descriptor ) ' Fensterhintergrundfarbe transparent setzen window.Background = &HFFFFFFFF ' Desktop-Objekt besorgen, um Frame dort als Child Frame einzuhngen

desktop = CreateUnoService("com.sun.star.frame.Desktop") container = desktop.frames ' Einen neuen Frame erzeugen frame = CreateUnoService("com.sun.star.frame.Frame") ' Frame mit Fenster initialisieren frame.initialize( Window ) ' Fertigen Frame einhngen, dabei wird der Desktop zum Parent des neuen Frames Container.append( frame ) ' Auch Frames untersttzen das ComponentLoader-Interface ' Ein Dokument in den Frame laden dim props() frame.loadComponentFromURL("private:factory/swriter", "_self", 0, Props() )

Der Frame vermittelt das Laden des Dokuments in ein Fenster. Dabei mu man nicht unbedingt (wie im Beispiel) ein Top-Level Systemfenster verwenden, der gleiche Code wie im Beispiel funktioniert auch, wenn ber einen anderen WindowDescriptor eine andere Art Fenster erzeugt wird, also z.B. ein Sub-Fenster, ein angedocktes Tool-Fenster oder ein Dialog. Frames haben fr das StarOffice API zwei zentrale Bedeutungen: sie sind Bestandteil des Dispatch API (siehe Developers Guide), das fr die Bearbeitung von UI-Kommandos verwendet wird und sie bauen zusammen mit den Dokumenten das Component API auf.
StarOffice Component Framework

In einem StarOffice-Prozess knnen mehrere Frames-Hierarchien vorliegen, eine besonders wichtige ist die, deren oberstes Objekt der com::sun::star::frame::Desktop Service ist. Sie enthlt u.a. alle Frames, die System-Taskfenster verwalten. Jeder Frame kann eine sog. Office Component enthalten, die auf jeden Fall das Interface com::sun::star::awt::XWindow muss, zustzlich optional aber auch das Interface com::sun::star::frame::XController implementieren kann, sie enthalten also ein Fenster und ggf. einen sog. Controller-Service. Durch Aufruf der Methode setComponent (s. Interface-Deklaration im vorherigen Abschnitt) wird die Office Component dem Frame bekannt gemacht und geht quasi in dessen Besitz ber. Der Frame wird sie dann, wenn eine neue Component eingesetzt oder der Frame selbst geschlossen wird, disposen. Kein anderes Objekt sonst darf das tun! Alle StarOffice-Dokumente haben einen oder mehrere solcher Controller-Implementierungen (je eine fr jede Art von View, die sie besitzen). Alle diese Service schlieen wiederum selbst den Service com::sun::star::frame::Controller ein. Jeder Controller referenziert das jeweilige Dokument (in diesem Zusammenhang auch Model genannt), dem er zugeordnet ist, genauer sein Interface com::sun::star::frame::XModel. Es gibt aber auch Controller-Objekte ohne Model, z.B. die Bibliographie-Komponente. Der Frame, sein Fenster (das ContainerWindow), der Controller, dessen Fenster (das ComponentWindow) und das vom Controller evtl. referenzierte Model bilden das StarOffice Component Framework API. Den beteiligten Objekten im Component Framework API kommen dabei die folgenden Aufgaben zu: Das Model hlt die Dokumentdaten und offeriert Methoden, um diese direkt zu verndern und abzufragen. Ein Model kann prinzipiell von beliebig vielen Controllern referenziert werden, was der Mglichkeit entspricht, mehr als ein Fenster fr ein einziges Dokument zu ffnen. ber seine Methode getCurrentController liefert es aus der Menge der es referenzierenden Controller denjenigen zurck, der den Applikationsfokus hat bzw. ihn zuletzt hatte, sofern der Fokus mittlerweile einem anderen Dokument oder gar einer anderen Applikation zugeteilt wurde.

Soll ein Dokument geschlossen werden, versucht es zunchst, alle Frames, die zu den ihm zugeordneten Controllern entsprechen, zu schlieen. Nur wenn das gelingt, fhrt es mit der eigenen Schlieung fort. Der Controller kennt den aktuellen Status der View auf sein Dokument, die in seinem Fenster prsentiert wird und kann diese View beeinflussen. Er ist ber den ihm bekannten Frame mit den Kontrollelementen des GUI verbunden, nimmt Kommandos von ihnen entgegen und steuert ihren visuellen Status (enablen/disablen etc.). ber seine Methode getModel gibt er Auskunft, welchem Dokument er zugeordnet ist. Er bietet auch ber das Interface com::sun::star::view::XSelectionSupplier einen Zugriff auf den aktuell selektierten Inhalt eines Dokumentfensters. Der genaue Inhalt ist aber applikationsspezifisch, daher wird er als any zurckgegeben. Nheres ber die genauen Ausprgungen der Selektion findet sich in den applikationsspezifischen Kapiteln des Developers Guide. Ein Controller ist immer genau einem Frame zugeordnet, den man ber seine Methode getFrame erfragen kann. Er ist ohne ihn nicht benutzbar und kann dessen Lebensdauer nicht berschreiten, da er sptestens dann automatisch zerstrt wird, wenn auch der Frame zerstrt wird. Das dem Controller zugeordnete ComponentWindow enthlt eine View auf das Model. Es ist ein Child Window des Frame Window (ContainerWindow). Es wird vom Frame unmittelbar nach dem Controller zerstrt. Der Frame kennt den Controller und dessen Fenster und kontrolliert deren Lebensdauer. Er bietet das Interface com::sun::star::util::XCloseable an, das schon im Zusammenhang mit dem Schlieen von Dokumenten oder Objekten allgemein erwhnt wurde. Die Einschrnkungen, wann ein Dokument nicht geschlossen werden kann, gelten im gleichen Mae fr die ihm ber seine Controller zugeordneten Frames. Wenn der letzte sichtbare Frame eines Dokuments geschlossen wird, versucht dieser auch das Dokument ber einen closeAufruf zu schlieen. Er verbindet sich selbst und den Controller mit den Kontrollelementen des GUI. Das dafr benutzte Dispatch Framework ist im Developers Guide ausfhrlich beschrieben. Um an ihm teilzunehmen implementieren sowohl der Frame als auch der Controller das Interface com::sun::star::frame::XDispatchProvider. Fr weitere Objekte, die dieses Interface ebenfalls implementieren und so in die Kommunikation mit dem GUI eingreifen wollen, ist der Frame der Ansprechpartner ber sein Interface com::sun::star::frame::XDispatchProviderInterception. Der Frame kontrolliert das komplette GUI innerhalb seines Fensters (aber auerhalb des ComponentWindow), so auch die Statuszeile. Er erlaubt es, ber sein Interface com::sun::star::frame::XStatusIndicatorFactory ein Objekt zu erzeugen, ber das Statusinformationen und Fortschrittsanzeigen dort ausgegeben werden knnen. Der beim Laden oder Speichern verwendete StatusIndicator (siehe Abschnitt ber den MediaDescriptor) benutzt dieses Interface. Das ContainerWindow enthlt das ComponentWindow und alle darum herum angeordneten GUI-Elemente wie Mens, Toolbars etc. Bezieht man den Desktop als typisches und wichtigstes Beispiel fr den Kopf einer Hierarchie von Frames mit ein, so ergibt sich fr das Component Framework die folgende Darstellung:

Der Desktop Service

Der Service com::sun::star::frame::Desktop wurde schon als Kopf der FramesHierarchie erwhnt, die die Task-Fenster der Office-Dokumente umfasst. Das wird dadurch implementiert, dass der Desktop Service den Frame Service einschliet, und damit auch das Interface com::sun::star::frame::XFramesSupplier. Eigentlich tritt der Desktop nicht als Frame in Erscheinung, da man keine Office Component in ihn hinein laden kann, allerdings war das in der allerersten StarOffice-Version, die das API erstmals definierte (StarOffice5) noch der Fall, und aus den blichen Kompatibilittsgrnden wurde das nicht gendert. Es ist aber nicht falsch, sich den Desktop als reinen FramesSupplier, der kein Frame ist, vorzustellen. Neben dem bereits erluterten Interfaces com::sun::star::frame::XComponentLoader und dem Interface com::sun::star::document::XEventBroadcaster, das noch im Kapitel ber Document Events besprochen wird, ist vor allem das Interface com::sun::star::frame::XDesktop von Bedeutung:
module com { module sun { module star { module frame { published interface XDesktop: com::sun::star::uno::XInterface { boolean terminate(); [oneway] void addTerminateListener( [in] XTerminateListener Listener ); [oneway] void removeTerminateListener( [in] XTerminateListener Listener );
com::sun::star::lang::XComponent getCurrentComponent();

com::sun::star::container::XEnumerationAccess getComponents(); XFrame getCurrentFrame();

}; }; }; }; };

Es deckt zusammen mit dem Interface com::sun::star::frame::XFramesSuppplier zwei Facetten des Desktops ab: den Zugriff auf die in der Hierarchie befindlichen Frames und Components sowie die zentrale Kontrolle ber die Lebensdauer des Office-Prozesses. Wenn der Benutzer den Meneintrage Datei-Beenden auswhlt, wird StarOffice ggf. unter Rckfragen die offenen Fenster schlieen und den Prozess beenden. Diese Funktionalitt wird durch die terminate-Methode ber das API zugnglich gemacht. Ein Java-Programm, das sich durch das Bootstrappen eines ComponentContext einem StarOffice-Prozess gestartet hat, kann diesen daher ber diese Methode beenden. Es kann sich aber auch als TerminateListener am DesktopService anmelden und hnlich wie im Falle der close-Methode bei Dokumenten eine Exception werfen, hier eine com::sun::star::frame::TerminationVetoException, um das Beenden zu verhindern. Tritt dieser Fall ein, wird die Methode terminate den Wert false zurckgeben, ansonsten true. Beides wird im folgenden Testprogramm demonstriert:
import com.sun.star.frame.TerminationVetoException; import com.sun.star.frame.XTerminateListener; public class TerminateListener implements XTerminateListener { public void notifyTermination (com.sun.star.lang.EventObject eventObject) { System.out.println("Beenden luft..."); } public void queryTermination (com.sun.star.lang.EventObject eventObject) throws TerminationVetoException { // test ob beendet werden kann if (TerminationTest.isAtWork() == true) { throw new TerminationVetoException() ; } }

public void disposing (com.sun.star.lang.EventObject eventObject) { } } import import import import import import import import import com.sun.star.bridge.XUnoUrlResolver; com.sun.star.uno.UnoRuntime; com.sun.star.uno.XComponentContext; com.sun.star.lang.XMultiComponentFactory; com.sun.star.beans.XPropertySet; com.sun.star.beans.PropertyValue; com.sun.star.frame.XDesktop; com.sun.star.frame.TerminationVetoException; com.sun.star.frame.XTerminateListener;

public class TerminationTest extends java.lang.Object { private static boolean atWork = false; public static void main(String[] args) { XComponentContext xRemoteContext = null; XMultiComponentFactory xRemoteServiceManager = null; XDesktop xDesktop = null; try { // SimpleBootstrap XComponentContext xRemoteContext = com.sun.star.comp.helper.Bootstrap.bootstrap(); com.sun.star.lang.XMultiComponentFactory xRemoteServiceManager = xContext.getServiceManager(); // Desktop erzeugen Object desktop = xRemoteServiceManager.createInstanceWithContext ( "com.sun.star.frame.Desktop", xRemoteContext); xDesktop = (XDesktop) UnoRuntime.queryInterface(XDesktop.class, desktop); TerminateListener terminateListener = new TerminateListener (); xDesktop.addTerminateListener (terminateListener); // Beenden, whrend noch gearbeitet werden soll atWork = true; boolean terminated = xDesktop.terminate (); System.out.println("Office (terminated == true ? "wurde beendet" : "luft noch, da noch gearbeitet wird")); // Arbeit beenden atWork = false; // Noch einmal versuchen, zu beenden terminated = xDesktop.terminate (); System.out.println("Office " + (terminated == true ? "wurde beendet" : "luft noch. Jemand anders verhindert das Beenden, z.B. der Quickstarter")); } catch (java.lang.Exception e){ e.printStackTrace(); } finally { System.exit(0); } } public static boolean isAtWork() { return atWork; } }

In Basic funktioniert der terminate-Aufruf grundstzlich nicht, was eine Implementierungsschwche des Interpreters darstellt.

Der Desktop bietet einen hierarchischen und einen nicht-hierarchischen Zugriff auf die Frames und Components an, ersteren ber seine Eigenschaft als Container fr Frames:
module com { module sun { module star { module frame { published interface XFrames: com::sun::star::container::XIndexAccess { void append( [in] XFrame xFrame ); sequence< XFrame > queryFrames( [in] long nSearchFlags ); void remove( [in] XFrame xFrame ); }; published interface XFramesSupplier: XFrame { XFrames getFrames(); XFrame getActiveFrame(); void setActiveFrame( [in] XFrame Frame ); }; }; }; }; };

Die Methode getActiveFrame liefert den direkten Child Frame, in dem sich gerade der Fokus der Applikation befindet (bzw. falls die Applikation gerade im Hintergrund liegt derjenige, in dem der Fokus zuletzt war). Das muss nicht der Frame sein, der den Fokus tatschlich hat, der aktive Frame kann auch einer sein, dessen Child Frame gerade den Fokus besitzt. Im Gegensatz dazu liefert die getCurrentFrame-Methode aus dem Interface com::sun::star::frame::XDesktop immer genau den Frame, der den Fokus auch tatschlich hat (bzw. zuletzt hatte), unabhngig davon, ob er ein direkter Child Frame des Desktop ist oder tiefer in der Hierarchie liegt. Die Methode getCurrentComponent gibt die OfficeComponent zurck, die sich in diesem Frame befindet, bei Office-Dokumenten also deren Controller. Die Methode setActiveFrame ist nicht dazu geeignet, den Fokus zu transferieren (das geht noch ber Methoden der Fenster), sie ist nur als Rckmeldung fr einen Frame an seinen Parent gedacht, wenn er gerade den Fokus erhalten hat. Die Methode getFrames liefert ein weiteres Interface zurck, das einen Container fr Frames implementiert. Dieser bietet neben Methoden zum Einfgen und Entfernen auch einen IndexAccess auf die vorhandenen Frames. Zustzlich kann es ber die Methode queryFrames eine steuerbare Teilmenge der enthaltenen Frames auch ber mehrere Hierarchieebenen zurckgeben. Die verwandte Methode getComponents im Interface com::sun::star::frame::XDesktop gibt immer alle Komponenten der kompletten Hierarchie zurck.

7.5 Ereignisse (Events), Listener und Broadcaster


Viele UNO-Objekte bieten Interfaces an, ber die andere UNO-Objekte sich anmelden (und abmelden) knnen, um ber bestimmte Vorgnge in diesem Objekt unterrichtet zu werden. Diese Vorgnge werden als Events abgebildet, die angemeldeten Objekte sind EventListener, das benachrichtigende Objekt ein EventBroadcaster. Der EventBroadcaster wird ber ein eine oder mehrere Methoden eine definierten Interface den EventListener benachrichtigen, sobald das Ereignis, fr das dieser sich angemeldet hat, eingetreten ist. Zustzlich werden alle EventListener vom EventBroadcaster benachrichtigt, wenn dieser zerstrt werden soll. In diesem Fall mssen alle Listener etwaige Referenzen auf den Broadcaster freigeben. Dieses Scenario entspricht exakt dem, das bei der Benutzung von Objekten mit dem Interface com::sun::star::lang::XComponent auftritt, daher sind alle EventListener-Interfaces von dem BasisInterface com::sun::star::lang::XEventListener abgeleitet und haben daher eine disposing-Methode.

7.6 Listener in Basic


Um ber Ereignisse benachrichtigt zu werden, muss man ein Objekt mit einem Listener-Interface implementieren. In StarOffice Basic kann man eigentlich keine Objekte implementieren, da die

Listener-Funktionalitt aber sehr wichtig ist, wurde ein Sprachmittel entwickelt, das die Entwicklung solcher speziellen Objekte auch in Basic ermglicht. Dabei handelt es sich um die Runtime-Funktion CreateUnoListener. Sie erwartet einen Prfix und den Typnamen des zu implementierenden Listeners. Alle Methoden im zu implementierenden Interface knnen dann als Basic-Prozeduren implementiert werden, die den Namen Prfix+Name der Methode haben. Es mssen aber alle Methoden implementiert werden, einschlielich der von etwaigen Basis-Interfaces, ansonsten kommt es zu einem Basic-Laufzeitfehler. Ein Beispiel, das einen Containerlistener an einem Basic-Library-Container:
Dim oListener oListener = CreateUnoListener( "ContListener_","com.sun.star.container.XContainerListener") Dim oLib oLib = BasicLibraries.Library1 oLib.addContainerListener( oListener ) ' Implementierung der Methode disposing Sub ContListener_disposing( oEvent ) MsgBox "disposing" MsgBox oEvent.Dbg_Properties End Sub ' Implementierung der Methode elementInserted Sub ContListener_elementInserted( oEvent ) MsgBox "elementInserted" MsgBox oEvent.Dbg_Properties End Sub ' Implementierung der Methode elementRemoved Sub ContListener_elementRemoved( oEvent ) MsgBox "elementRemoved" MsgBox oEvent.Dbg_Properties End Sub ' Implementierung der Methode elementReplaced Sub ContListener_elementReplaced( oEvent ) MsgBox "elementReplaced" MsgBox oEvent.Dbg_Properties End Sub

Wichtig ist, dass solcherart registrierte Listener wieder abgemeldet werden, bevor das Macro beendet wird, da sie nur ber die Basic Runtime funktionieren.

7.7 Dokumentereignisse
Auch die StarOffice Dokumente haben EventBroadcaster-Interfaces, das wichtigste davon ist das Interface, mit dem das Dokument Interessenten ber allgemeine Ereignisse informiert, wie die Tatsache, dass das Dokument gerade geladen, gedruckt oder gespeichert wurde oder dass es demnchst geschlossen werden soll. Das Interface, mit dem alle diese Ereignisse mitgeteilt werden, ist com::sun::star::document::XEventBroadcaster, das Interface fr die Listener ist com::sun::star::document::XEventListener:
module com { { string EventName; };
published interface XEventListener: com::sun::star::lang::XEventListener

module sun {

module star {

module document {

published struct EventObject: com::sun::star::lang::EventObject

{ [oneway] void notifyEvent( [in] EventObject Event ); }; published interface XEventBroadcaster: com::sun::star::uno::XInterface {

[oneway] void addEventListener( [in] XEventListener Listener ); [oneway] void removeEventListener( [in] XEventListener Listener ); }; }; }; }; };

Der struct com::sun::star::document::EventObject transportiert dabei die Information, welches Ereignis aufgetreten ist, als string. Zustzlich natrlich transportiert er ber seinen Basis-struct com::sun::star::lang::EventObject auch eine Referenz auf das Dokument. Welche Ereignisse ein Dokument auf diese Art und Weise bekannt gibt, hngt vom Typ des jeweiligen Dokuments ab. So bietet ein Textdokument z.B. MailMerge-Events an, die keines der anderen Dokument hat. Es gibt aber auch eine groe Zahl von Ereignissen, die allen Dokumenten gemeinsam sind: EventName OnCreate OnNew OnLoadFinished OnLoad (1) OnSave OnSaveDone OnSaveAs OnSaveAsDone OnCopyTo OnCopyToDone OnModifyChanged (2) OnPrint (3) OnViewCreated OnPrepareViewClosing OnViewClosed OnFocus OnUnfocus OnPrepareUnload OnUnload OnVisAreaChanged Ein paar Anmerkungen: (1) Der Name OnLoad ist eigentlich falsch und mte OnOpen heien, leider war er aus Beschreibung Ein neues, unbenanntes Dokument wurde erzeugt Ein neues, unbenanntes Dokumente wurde samt View erzeugt und angezeigt (Zustand nach Erzeugen ber UI) Ein Dokument wurde geladen Ein Dokument wurde geladen, eine View erzeugt und angezeigt (Zustand nach Laden ber UI) Das Dokument soll jetzt gespeichert werden (entspricht store oder storeSelf) Das Dokument wurde gespeichert Das Dokument soll jetzt unter einem neuen Namen gespeichert werden (entspricht storeAsURL) Das Dokument wurde unter einem neuen Namen gespeichert Es soll eine Kopie des aktuellen Status des Dokuments erzeugt werden (entspricht storeToURL) Eine Kopie des aktuellen Zustands des Dokuments wurde erzeugt Das Dokument war bisher nicht modifiziert und wird es jetzt oder das Modified-Flag wird zurckgesetzt Das Dokument soll gedruckt werden Es wurde eine View fr das Dokument erzeugt Eine View fr das Dokument soll geschlossen werden Eine View fr das Dokument wurde geschlossen Eine View des Dokuments hat den Fokus erhalten Eine View des Dokuments hat den Fokus verloren Das Dokument soll jetzt geschlossen werden Das Dokument wird jetzt sofort geschlossen (erfolgreicher close-Aufruf) Der sichtbare Bereich des Dokuments hat sich gendert (nur bei eingebetteten Dokumenten wichtig)

historischen Grnden nicht nderbar, sodass die etwas unglckliche Situation vorliegt, dass OnLoadFinished vor OnLoad gerufen wird. (2) OnModifyChanged benachrichtigt nicht bei jeder nderung des Dokuments, das wrde eine groe Anzahl von Ereignissen generieren, fr die sich vielleicht die meisten Listener gar nicht interessieren. Fr diese Benachrichtigung bieten die StarOffice-Dokumente das Interface com::sun::star::util::XModifyBroadcaster. (3) Es gibt nur ein Ereignis, das ber den Start des Druckvorgangs unterrichtet. Alle weiteren Benachrichtigungen erfordern zustzliche Parameter und laufen daher ber ein spezialisiertes Interface com::sun::star::view::XPrintJobBroadcaster. Ein wichtiges Prinzip bei allen Ereignissen ist, dass das API der Dokumente zu dem Zeitpunkt, wo es versendet wird, voll funktional ist. Man kann also z.B. auch noch in einem OnUnload oder schon direkt in einem OnLoadFinished das Dokument speichern. Ein Objekt, das ber solche Ereignisse informiert werden mchte, mchte das vielleicht nicht nur von einem einzigen, sondern von allen vorhandenen Dokumenten haben. Dafr gibt es einen Service, der das Weiterleiten der Ereignisse von allen Dokumenten bernimmt, der Service com::sun::star::frame::GlobalEventBroadcaster, der das gleiche Interface wie die Dokumente implementiert. Dieser Service kennt sogar noch zwei zustzliche Events, die nur er, aber nicht ein Dokument versendet: EventName OnStartApp Beschreibung Die StarOffice-Anwendung wurde gestartet

OnCloseApp Die StarOffice-Anwendung wird jetzt beendet Das erste Ereignis wird versendet unmittelbar bevor das erste Fenster geffnet wird, das zweite unmittelbar nach dem Schlieen aller offenen Fenster. Ein Beispiel dafr, wie ein Objekt sich als Listener anmeldet und Ereignisse empfngt, ist in Java recht einfach implementiert:
public class DocumentEventListener implements com.sun.star.document.XEventListener { public void notifyEvent (com.sun.star.document.EventObject eventObject) { } public void disposing (com.sun.star.lang.EventObject eventObject) { } }

Die Wahl der Namen der Interfaces und speziell die er Methoden hat sich aber als unglcklich erwiesen, da sie in Basic Klimmzge erfordert, um sie zu benutzen. Normalerweise wrde man denken, dass ein in Basic implementierter DocumentEventListener sich folgendermaen anmeldet:
oListener = CreateUnoListener("DocumentListener_","com.sun.star.document.XEventListener") ThisComponent.addEventListener( oListener )

Das wird auch ohne Probleme ausgefhrt, allerdings nicht mit dem gewnschten Effekt: Basic kann nicht unterscheiden, welche der beiden Methoden addEventListener benutzt werden soll, die aus com::sun::star::document::XEventBroadcaster oder die aus dem Basis-Interface com::sun::star::document::XComponent, die beide am Dokument untersttzt werden. Der angemeldete Listener passt auf beide, denn ein com::sun::star::document::XEventListener ist auch immer ein com::sun::star::lang::XEventListener. Es ist in dieser Konstellation Zufall, welches addEventListener Basic findet, hier findet es die am Basis-Interface, sodass der angemeldete Listener zwar disposing-Calls erhlt, aber kein notifyEvent. Ein Java-Programmierer hat dieses Problem natrlich nicht, da er immer explizite Interface-

Referenzen benutzt. Diese Problematik wurde leider zu spt erkannt, um die Interface und Methodennamen noch zu ndern. Glcklicherweise erlaubt es auch Basic, beim Zugriff auf Methoden explizit anzugeben, aus welchem Interface man diese stammen soll. Der folgende Aufruf funktioniert wie gewnscht:
oListener = CreateUnoListener("DocumentListener_","com.sun.star.document.XEventListener") ThisComponent.com_sun_star_document_XEventBroadcaster_addEventListener( oListener )

Die Syntax bedarf dabei wohl keiner weiteren Erklrung.

7.8 Event Bindings


StarOffice bietet die Mglichkeit, an Dokumentereignisse Makros und Scripts zu binden, d.h. StarOffice anzuweisen, die gebundenen Makros oder Scripts automatisch auszufhren, wenn das Ereignis, auf das sie gebunden sind, eingetreten ist. Dieses Binden an Ereignisse (Event Bindings) kann nicht nur ber den Dialog Extras-Anpassen, sondern auch per API vorgenommen werden. Solche EventBindings haben den Vorteil, dass man ohne die Implementierung eines Listeners BasicCode beim Eintreten von Events ausfhren kann. Sowohl die StarOffice-Dokumente als auch der erwhnte GlobalEventBroadcaster Service bieten dafr ein Interface com::sun::star::document::XEventsSupplier. Dies spiegelt sich in der Tatsache wider, dass Event Bindings im erwhnten Dialog jeweils nur fr ein Dokument oder fr alle vorgenommen werden knnen. Das Interface hat nur eine Methode, die Zugriff auf einen Container fr Event Bindings gewhrt:
module com { module sun { module star { module document { published interface XEventsSupplier: com::sun::star::uno::XInterface { com::sun::star::container::XNameReplace getEvents(); }; }; }; }; };

Das Interface com::sun::star::container::XNameReplace ist eines der generischen Container-Interfaces und reprsentiert einen Container, der eine feste Anzahl von Elementen hat, die aber ersetzt werden knnen:
module com { module sun { module star { module container { published interface XElementAccess: com::sun::star::uno::XInterface { type getElementType(); boolean hasElements(); }; published interface XNameAccess: com::sun::star::container::XElementAccess { any getByName( [in] string aName ) raises( com::sun::star::container::NoSuchElementException,
com::sun::star::lang::WrappedTargetException );

sequence<string> getElementNames(); boolean hasByName( [in] string aName ); }; published interface XNameReplace: com::sun::star::container::XNameAccess { void replaceByName( [in] string aName, [in] any aElement )
raises( com::sun::star::lang::IllegalArgumentException, com::sun::star::container::NoSuchElementException, com::sun::star::lang::WrappedTargetException );

};

}; }; }; };

Als Elementnamen werden die oben aufgelisteten Ereignisnamen verwendet, die Elemente selbst sind die Event Bindings. Jedes Event Binding ist durch eine sequence<com::sun::star::beans::PropertyValue> reprsentiert. Die einzelnen Properties sind die folgenden: Property Name EventType Script Beschreibung String. Kann die Werte StarBasic und Script annehmen. String. Beschreibt den Ort, wo das Makro/Script gefunden wird in URL-Form. Wenn EventType Script ist, benutzt die URL das vnd.sun.star.script:Protokoll, wenn es StarBasic ist, das macro:-Protokoll. Die macro-URL kann zwei Formen haben: macro:///<Library>.<Module>.<Method(args)> macro://./<Library>.<Module>.<Method(args)> Die erste Variante bezeichnet ein Makro im globalen Basic, die zweite ein Makro im aktuellen Dokument. Library, Module, Method bezeichnen die Bibliothek, das Basic-Modul und den Methodenamen des Makros. args sind durch Komma getrennte String-Argumente. Die Klammern gehren zwingend zur URL, sie drfen natrlich leer sein. Die script-URL hat die Form: vnd.sun.star.script:<name>?language=LangVal&location=LocVal <name> ist ein String, dessen Form von der Scriptsprache abhngt, bei Basic entspricht er <Library>.<Module>.<Method>. LangVal bezeichnet die Sprache, z.B. Basic, LocVal kann die Werte application oder document annehmen. Library String. Wurde fr den ScriptTyp Basic benutzt, sollte aber nicht mehr benutzt werden. In frheren Versionen konnte dieser String die Werte application oder document annehmen, je nachdem ob das Makro im aktuellen Dokument oder in der Installation gespeichert ist.

String. Wurde fr den ScriptTyp Basic benutzt, sollte aber nicht mehr benutzt werden. In frheren Versionen beschrieb dieser String wo im Dokumentbasic bzw. im globalen Basic das Makro gespeichert ist, und zwar in der Form <Library>.<MyModule>.<MyMethod>. Wenn keine Event Bindings gesetzt sind, sind die Werte des Containers leere Sequences. Das Setzen und Auslesen der Bindings zeigt folgender Java-Code:
// Voraussetzung: xDoc ist eine Referenz auf ein Dokument import com.sun.star.beans.PropertyValue; import com.sun.star.uno.AnyConverter; com.sun.star.document.XEventsSupplier xSupplier = (com.sun.star.document.XEventsSupplier) UnoRuntime.queryInterface( com.sun.star.document.XEventsSupplier.class, xDoc ); com.sun.star.container.XNameReplace xEvents = xSupplier.getEvents(); PropertyValue[] binding = new PropertyValue[2]; binding[0] = new PropertyValue(); binding[0].Name = "EventType"; binding[0].Value = "StarBasic"; binding[1] = new PropertyValue();

MacroName

binding[1].Name = "Script"; binding[1].Value = "macro:MyLib.MyModule.MyMethod()"; xEvents.replaceByName("OnLoad", binding); // wieder auslesen PropertyValue[] props = null; Object obj = xEvents.getByName("OnLoad"); if ( AnyConverter.getType(obj) == new com.sun.star.uno.Type( PropertyValue[].class ) ) props = (PropertyValue[]) AnyConverter.toArray( obj );

In Basic geht das etwas einfacher:


dim binding(1) as new com.sun.star.beans.PropertyValue binding(0).Name = "EventType" binding(0).Value = "StarBasic" binding(1).Name = "Script" binding(1).Value = "macro:MyLib.MyModule.MyMethod()" ' Setzen des Bindings ThisComponent.Events.replaceByName( "OnLoad", binding() ) ' Wieder auslesen und anzeigen arr = ThisComponent.Events.OnLoad print arr(0).Name + ";" + arr(0).Value print arr(1).Name + ";" + arr(1).Value

7.9 Dokumenteigenschaften (Metadaten)


Die in StarOffice unter Datei-Eigenschaften bearbeiteten Daten bezeichnet man auch als Dokument-Metadaten. Der Service com::sun::star::document::DocumentInfo dient dem Zugriff auf diese Daten. Er umfat das Interface com::sun::star::beans::XPropertySet, das sie als PropertyValues verwaltet und ein weiteres Interface fr die Infofelder, die in den Dokumentmetadaten als Paare von Name und String-Value behandelt werden:
module com { module sun { module star { module document { published interface XDocumentInfo: com::sun::star::uno::XInterface { short getUserFieldCount(); string getUserFieldName( [in] short Index )
raises( com::sun::star::lang::ArrayIndexOutOfBoundsException ); raises( com::sun::star::lang::ArrayIndexOutOfBoundsException );

string getUserFieldValue( [in] short Index ) void setUserFieldName( [in] short Index , [in] string Name ) void setUserFieldValue( [in] short Index , [in] string Value ) }; }; }; }; };

raises( com::sun::star::lang::ArrayIndexOutOfBoundsException );

raises( com::sun::star::lang::ArrayIndexOutOfBoundsException );

Ab StarOffice8 kommt optional das Interface com::sun::star::beans::XPropertyContainer hinzu, mit dem das PropertySet erweitert werden kann. StarOffice8 untersttzt die Speicherung beliebiger Metadaten, sofern sie als Typ einen der im Dateiformat elementaren Typen haben. Sie werden gemeinsam mit den StandardMetadaten ber das PropertySet-Interface abgefragt und gendert. Dabei knnen die ber das API eingefgten Properties natrlich jeden beliebigen UNO-Typ haben, sie knnen aber nur im Dokument abgespeichert werden, wenn sie einen Typ haben, der als elementarer Typ im Dateiformat

untersttzt wird. Der DocumentInfo-Service wird von allen StarOffice-Dokumenten implementiert, es gibt aber auch einen globalen Service com::sun::star::document::StandaloneDocumentInfo, der direkt mit einer StarOffice-Datei arbeiten kann und dort nur die Metadaten bearbeitet. Fr den Dateizugriff wird das Interface com.sun.star.documentXStandaloneDocumentInfo verwendet. Der Zugriff auf den am Dokument implementierten Service erfolgt indirekt ber dessen Interface com::sun::star::document::XDocumentInfoSupplier:
module com { module sun { module star { module document { published interface XDocumentInfoSupplier: com::sun::star::uno::XInterface { XDocumentInfo getDocumentInfo(); }; }; }; }; };

Das zurckgegebene Objekt implementiert dann den Service. Die Standard-Properties der StarOffice-Metadaten sind die folgenden, deprecated Properties, die nicht mehr verwendet werden (sollen), sind weggelassen: Property Name Author (string) Generator (string) CreationDate (com::sun::star::util::DateTime) Title (string) Subject (string) Description (string) Keywords (string) MIMEType (string, readonly) Language (com::sun::star::lang::Locale) ModifiedBy (string) PrintedBy (string) PrintDate (com::sun::star::util::DateTime) Template (string) TemplateDate (com::sun::star::util::DateTime) AutoloadURL (string) AutoloadSecs (long) DefaultTarget (string) Beschreibung Name des initialen Autors des Dokuments Name der Applikation, die das Dokument erzeugt hat Datum des ersten Speicherns des Dokuments Titel des Dokuments Thema des Dokuments Beschreibender Kommentar (mehrzeilig) Kommaseparierte Liste mit Schlsselwrtern MediaTyp des Dokuments Standard-Dokumentsprache Name des letzten Bearbeiters Name des letzten Benutzers, der das Dokument gedruckt hat (sofern danach gespeichert wurde) Datum des letzten Druckens (sofern danach gespeichert wurde) Wenn das Dokument aus einer Vorlage erzeugt wurde: logischer Name der Vorlage Datum, wann zuletzt ein Abgleich der Styles mit der Vorlage erfolgt ist (sofern danach gespeichert wurde) Fr Webseiten: URL, die das geladene Dokument nach einer bestimmten Zeit automatisch ersetzt Zeit, nach der das Dokument automatisch wieder geladen bzw. durch ein anderes ersetzt wird Fr Autoload: auch ein Autoload in andere Frames ist

ModifyDate (com::sun::star::util::DateTime) Datum des letzten Speicherns

Property Name mglich EditingCycles (short) EditingDuration (long) SaveVersionOnClose (boolean)

Beschreibung Anzahl der Edit/Save-Zyklen Gesamtzeit, die whrend der Dokumentbearbeitung verbraucht wurde

True: Wenn das Dokument beim Schlieen modifiziert ist, soll automatisch eine Version angelegt werden. Hier ein Beispiel, wie mit Metadaten in Java umgegangen wird:
// Voraussetzung: xDoc ist eine Referenz auf ein Dokument import com.sun.star.beans.PropertyValue; import com.sun.star.uno.XDocumentInfoSupplier; import com.sun.star.beans.XPropertySet; import com.sun.star.beans.XPropertyContainer; // DocumentInfo-Objekt besorgen XDocumentInfoSupplier xSupplier = (XDocumentInfoSupplier) UnoRuntime.queryInterface( XDocumentInfoSupplier.class, xDoc ); com.sun.star.document.XDocumentInfo xInfo = xSupplier.getDocumentInfo(); // Ein Property setzen XPropertySet xSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xInfo ); xSet.setPropertyValue("Author", "Me"); // Ein Property einfgen xContainer.addProperty("ANewProperty", 0, "test"); XPropertyContainer xContainer = (XPropertyContainer) UnoRuntime.queryInterface( XPropertyContainer.class, xInfo );

StarOffice Basic bietet hier wieder besonderen Komfort, da es wie bereits erwhnt das Interface com::sun::star::beans::XPropertySet direkt als einzelne Properties anspricht:
Docinfo = ThisComponent.DocumentInfo DocInfo.Author = "Me" DocInfo.Subject = "About Properties" ' Hinzufgen eines String-Property DocInfo.addProperty( "ANewStringProperty", 0, "test" ) ' long-Property: CreateUnoValue verwenden, da sonst ein short-Property eingefgt wird DocInfo.addProperty( "ANewIntProperty", 0, CreateUnoValue( "long", 42 ) ' berprfen der Properties print ThisComponent.DocumentInfo.dbg_properties ' Wieder entfernen DocInfo.removeProperty( "ANewIntProperty" ) DocInfo.removeProperty( "ANewStringProperty" ) ' und noch einmal berprfen print ThisComponent.DocumentInfo.dbg_properties

8 Textdokumente
8.1 Arbeiten mit Textdokumenten
Der Zugriff auf Textdokument mit der UNO-API erfolgt ber das Model. Die im Service com.sun.star.text.GenericTextDocument zusammengefassten Interfaces erlauben den Zugriff auf alle Elemente des Textdokumentes. Vernderungen am Textdokument werden grundstzlich ber das Model erreicht. Der Controller (com::sun::star::frame::XController) dient zur Darstellung des Dokuments. Modifikationen ber die Interfaces des Service com.sun.star.text.TextDocumentView dienen der Vernderung der Darstellung und nicht der Vernderung der Daten des Dokumentes. Im Textdokument gibt es fnf wesentliche Bereiche Text Service Manager (u.a. Erzeugung neuer Textinhalte) Zugriff auf Textinhalte (text contents) Zugriff auf Zeichenobjekte (DrawPage) Vorlagen und Nummerierungen Der wichtigste Aspekt des Textdokuments ist der flieende Text. Er ist organisiert in Abstzen, die Zeichenketten enthalten. Der Service Manager des Dokuments dient zur Erzeugung neuer Textinhalte (Tabellen, Textrahmen, Zeichenobjekte usw.). Diese erzeugten Objekte knnen im Regelfall nur in die selbe Instanz des Dokuments eingefgt werden von dem sie erzeugt wurden. Der Zugriff auf die bereits enthaltenen Textinhalte erfolgt ber diverse Supplier-Interfaces (XTextTablesSupplier, XTextFramesSupplier). Eine Ausnahme bilden Zeichenobjekte, die ber die DrawPage erreichbar sind. Zeichenobjekte sind in der DrawPage enthalten, die 'auf' dem Textinhalt liegt. Die darin enthalten Objekte knnen sich den Textfluss auswirken (Umlauf). Ihre Position kann abhngig von der Verankerung (z.B. am Absatz, am/als Zeichen) vom Textinhalt abhngig sein. Zur Vernderung der Vorlagen (Absatz-, Zeichen, Seiten, Rahmen und Nummerierungsvorlagen) gibt es den Service com.sun.star..style.StyleFamilies. Ebenso gibt es Interfaces fr den Zugriff auf Nummerierungsoptionen.
Text, TextRanges und Cursor

Der Zugang zum Text beginnt mit der Methode getText am Interface com.sun.star.text.XTextDocument. Man erhlt damit Zugriff auf ein Objekt, das den Service com.sun.star.text.Text implementiert. Das Interface com.sun.star.text.XText erlaubt die Erzeugung von Text-Cursorn sowie das Einfgen und Entfernen von Textinhalten (Rahmen, Tabellen, Felder ...). Es vereinigt die Interfaces XText, XSimpleText und XTextRange. ber das Interface com.sun.star..container.XEnumerationAccess kann man ber die Abstze des Textes iterieren. Das schliet lediglich den Haupttext des Dokumentes ein. Tabellen im Flietext werden dabei Abstzen gleichgestellt, da die Iteration Elemente mit dem Interface com.sun.star.text.XTextRange liefert.

Texte innerhalb von Tabellenzellen oder Textrahmen sowie in Sonderbereichen (Funotenbereich, Kopf- und Fuzeilen) sind in dieser Iteration nicht enthalten. Text kann komplett fr das gesamt Textobjekt verndert werden mit der Methode setText. Um Text an beliebigen Positionen innerhalb des Objektes zu ndern oder einzufgen werden Cursor verwendet. Um einen Cursor zu erzeugen werden die Methoden createTextCursor und createTextCursorByRange verwendet. Fr letztere Methode muss darauf geachtet werden, dass sich der bergebene TextRange innerhalb des gleichen Textobjektes befindet, an dem auch die Methode aufgerufen werden soll. Mit Hilfe des Cursors lt sich Text einfgen oder verndern. Ein Beispiel in Basic:
sub SetStringSample oDocument = thiscomponent oText = oDocument.getText oCursor = oText.createTextCursor oCursor.gotoEndOfParagraph( false ) oText.insertString( oCursor, "Text am Ende", false) oText.insertString( oCursor, "Weiterer Text", false) 'ebenso liesse sich folgendes schreiben oCursor.setString("Text am Ende") oCursor.collapseToEnd oCursor.setString("Weiterer Text") end sub

Die Methode insertControlCharacter wird benutzt, um Steuerzeichen einzufgen. Die Steuerzeichen sind definiert als com.sun.star.text.ControlCharacter. Folgende Zeichen sind definiert: PARAGRAPH_BREAK LINE_BREAK HARD_HYPHEN Fgt einen Absatzumbruch ein (UNICODE 0x000D). Fgt einen Zeilenumbruch ein (UNICODE 0x000A). Sog. 'hartes Trennzeichen'. Ein Bindestrich an dem keine Silbentrennung stattfindent (UNICODE 0x2011). Bindestrich, bevorzugte Position fr Silbentrennung. (UNICODE 0x00AD). Leerzeichen, das einen Umbruch unterbindet. (UNICODE 0x00A0). Hngt einen neuen Absatz nach dem aktuellen Absatz an (kein entsprechendes UNICODE-Zeichen).

SOFT_HYPHEN HARD_SPACE APPEND_PARAGRAPH

Textinhalte

Alle Objekte innerhalb der Textdokumente auer den Zeichenketten sind Objekte die den Service com.sun.star.text.TextContent implementieren. Darin enthalten ist das interface com.sun.star.text.XTextContent, das ein Objekt an einen text range innerhalb eines Textes verankert (attach(XTextRange)) und die Methode getAnchor, die die Ankerposition des Objektes liefert. Um Objekte in das Dokument einzufgen, mssen diese zunchst am Model erzeugt werden. Dazu wird die Methode createInstance aus dem Interface com.sun.star.lang.XMultiServiceFactory verwendet. Die neuen Textinhalte knnen sowohl vor als auch nach dem Einfgen attributiert werden. Der

Zugriff auf die Objekte und ihre Interfaces ist jedoch vor dem Einfgen eingeschrnkt. So kann z.B. bei einer Tabelle nicht auf die Tabellenzellen zugegriffen werden. Auch kann in einem Textrahmen zu diesem Zeitpunkt noch kein Text eingefgt werden. Alle diese Textinhalte implementieren das Interface com.sun.star..lang.XComponent. Das erlaubt die Objekte mit dem Aufruf der Methode dispose zu lschen. Im folgenden Basic-Beispiel wird eine Tabelle eingefgt
Sub Main oDocument = thiscomponent oTable = oDocument.createInstance("com.sun.star.text.TextTable") oTable.initialize(2,3) oText = oDocument.getText oCursor = oText.createTextCursor oCursor.gotoEndOfParagraph( false ) oText.insertTextContent( oCursor, oTable, false) End Sub

Einfgen oder Lschen von Abstzen an speziellen, schwer erreichbaren Positionen

Aufgrund der Struktur der Writer-Dokumente gibt es Positionen an denen sich Text nicht ohne weiteres einfgen oder lschen lt. Dies sind Positionen ab Textanfang/-ende vor/hinter Tabellen oder Bereichen sowie zwischen Tabellen und Bereichen. Um dort Abhilfe zu schaffen, wurden die Interfaces com.sun.star.text.XRelativeTextContentInsert und com.sun.star.text.XRelativeTextContentRemove eingefhrt. Die Methoden insertTextContentBefore und insertTextContentAfter knnen nur im Zusammenhang mit com.sun.star.text.XTextTable und com.sun.star.text.XTextSection als Position und neu erzeugten com.sun.star.text.Paragraph-Objekten als neue Textinhalte verwendet werden. Fr andere Konstellationen sind sie nicht erforderlich. hnliches gilt fr die Methoden removeTextContentBefore und removeTextContentAfter.
Formatierung

Um Inhalt zu formatieren, werden Properties and den entsprechenden Objekten ber das Interface com::sun::star::beans::XPropertySet gesetzt. Im Basic erlaubt die Methode dbg_Properties herauszufinden, welche Properties ein Objekt untersttzt. Der folgende Ausdruck zeigt die Properties eines TextCursor in einem Fenster an:
sub ShowProperties oDocument = thiscomponent oText = oDocument.getText oCursor = oText.createTextCursor msgbox oCursor.dbg_Properties end sub

Die Namen, Typen und Verwendungen von Properties sind in den entsprechenden ServiceBeschreibungen enthalten, so z.B. in com.sun.star.text.TextCursor der letztlich u.a. auf die Services com.sun.star.style.CharacterProperties und com.sun.star.style.ParagraphProperties verweist. Einige der Properties sind nicht unabhngig voneinander einstellbar, da sie innerhalb gemeinsame Attribute implementiert sind. Es handelt sich um die folgenden: ParaRightMargin, ParaLeftMargin, ParaFirstLineIndent, ParaIsAutoFirstLineIndent ParaTopMargin, ParaBottomMargin ParaGraphicURL/Filter/Location, ParaBackColor, ParaBackTransparent

ParaIsHyphenation, ParaHyphenationMaxLeadingChars/MaxTrailingChars/MaxHyphens Left/Right/Top/BottomBorder, Left/Right/Top/BottomBorderDistance, BorerDistance DropCapFormat, DropCapWholeWord, DropCapCharStyleName PageDescName, PageNumberOffset HyperLinkURL/Name/Target, UnvisitedCharStyleName, VisitedCharStyleName CharEscapement, CharAutoEscapement, CharEscapementHeight CharFontName, CharFontStyleName, CharFontFamily, CharFontPitch CharStrikeOut, CharCrossedOut CharUnderline, CharUnderlineColor, CharUnderlineHasColor CharCombineIsOn, CharCombinePrefix, CharCombineSuffix RubyText, RubyAdjust, RubyCharStyleName, RubyIsAbove

Auffinden von Textinhalten

Das Model des Textdokuments implementiert eine Reihe von Interfaces, um auf die im Dokument enthalten Objekte zuzugreifen. Einige davon liefern statt eines Zugriffs auf Objekte den Zugriff auf spezielle Einstellungen wie die der Fu- und Endnoten oder der Zeilennummerierung. Folgende Interfaces sind implementiert Interface XTextTablesSupplier XTextFramesSupplier XTextGraphicObjectsSupplier Methoden com.sun.star.container.XNameAccess getTextTables () com.sun.star.container.XNameAccess getTextFrames () com.sun.star.container.XNameAccess getGraphicObjects ()

XTextEmbeddedObjectsSupplier com.sun.star.container.XNameAccess getEmbeddedObjects () XTextFieldsSupplier XBookmarksSupplier XReferenceMarksSupplier com.sun.star.container.XEnumerationAccess getTextFields () com.sun.star.container.XNameAccess getTextFieldMasters () com.sun.star.container.XNameAccess getBookmarks () com.sun.star.container.XNameAccess getReferenceMarks ()

XFootnotesSupplier

com.sun.star.container.XIndexAccess getFootnotes () com.sun.star.beans.XPropertySet getFootnoteSettings () com.sun.star.container.XIndexAccess getEndnotes () com.sun.star.beans.XPropertySet getEndnoteSettings () com.sun.star.container.XNameAccess getTextSections () com.sun.star.container.XIndexAccess getDocumentIndexes () com.sun.star.container.XEnumerationAccess getRedlines ()

XEndnotesSupplier XTextSectionsSupplier XDocumentIndexesSupplier XRedlinesSupplier

Diese Interfaces liefern Objekte, die ber die angegebenen Rckgabewerte hinaus u.U. noch weitere Interfaces implementieren. Insbesondere ist neben dem Interface com.sun.star.container.XNameAccess auch das Interface com.sun.star.container.XIndexAccess implementiert. Die Textinhalte implementieren ber das Interface com.sun.star.text.XTextContent die Methode getAnchor, die ein TextRange-Objekt liefern, das die Ankerposition des Objektes zurckliefert. Um an einer gegebenen Textposition (mit TextCursor oder TextRange) herauszufinden, ob ein Textinhalt vorhanden ist, sind einige Properties implementiert.

DocumentIndexMark (Verzeichniseintrag) TextField (Feldbefehl) ReferenceMark (Referenzmarke) Footnote Endnote DocumentIndex (Verzeichnis) TextTable TextFrame Cell TextSection Tables

Navigation

Um innerhalb von Texten zu navigieren untersttzt der TextCursor eine Reihe von Interfaces, um sich nach unterschiedlichen Kriterien zu bewegen. Diese Kriterien beziehen sich ausschlielich auf den Inhalt. Der TextCursor untersttzt folgende Interfaces zur Navigation: com.sun.star.text.XSentenceCursor com.sun.star.text.XWordCursor com.sun.star.text.XParagraphCursor

com.sun.star.text.XTextCursor Der am Controller implementiert ViewCursor hingegen untersttzt Interfaces, die das Navigieren im Layout ermglichen. Er untersttzt folgende Interfaces zur Navigation: com.sun.star.text.XTextViewCursor com.sun.star.text.XPageCursor com.sun.star.view.XScreenCursor com.sun.star.view.XViewCursor com.sun.star.view.XLineCursor com.sun.star.text.XTextCursor Beide Cursor sind TextRanges, die eine Start- und Endposition im Text haben. Sind diese beiden Positionen unterschiedlich, dann markiert der Cursor den enthaltenen Text. Mit getText bzw. setText kann dieser Text ausgelesen bzw. gesetzt werden. Mit den Methoden collapseToRight und collapseToLeft kann die Markierung nach rechts bzw. links aufgehoben werden. isCollapsed zeigt an, ob der Cursor eine Markierung aufspannt. ber die Methoden der o.g. Navigations-Interfaces kann durch setzen des 'Expand'-Parameters bestimmt werden, dass eine Markierung durch den Cursor aufgespannt bzw. erweitert wird. Da die Cursor auch das Interface com.sun.star.beans.XPropertySet untersttzten, knnen die Markierungen attributiert werden bzw. die Attribute an der Markierungsposition abgefragt werden. Cursor-Objekte, die an beliebiger Stelle aufgespannt wurden, bleiben bei nderungen am Textdokument blicherweise an gleicher Textposition stehen. Wird Text an der Markierungsposition eingefgt oder gelscht, ndert sich die Markierung entsprechend. Wird das komplette Textobjekt (z.B. Tabellenzelle), in dem der Cursor enthalten ist, gelscht, dann wird der Cursor ungltig. Lediglich der ViewCursor wird, sofern an der View eine Textselektion aktiv ist, immer an eine gltige Position verschoben.

8.2 Tabellen
Tabellenarchitektur

Die Tabellen bestehen aus Zeilen. Zeilen bestehen aus einer oder mehreren Zellen. Zellen knen Text oder wiederum Zeilen enthalten. Logisch gesehen gibt es in Writer-Tabellen keine Spalten. Solange keine Zellen der Tabelle geteilt oder verbunden worden sind, kann sich die Tabelle aber so verhalten als seien Spalten vorhanden. Die Zellen einer Zeile werden alphabetisch durchgezhlt, beginnend mit A. Zeilen werden numerisch gezhlt, beginnend mit 1. Daraus ergibt sich die folgende Zellen-Zeilen-Adressierung: A1 B1 C1 D1 A2 B2 C2 D2 A3 B3 C3 D3 A4 B4 C4 D4 Wird eine Zelle vertikal geteilt, bekommt die neue Zelle den Buchstaben der rechten Nachbarzelle.

In der folgenden Tabelle wurde die Zelle B2 vertikal geteilt. Eine neue Zelle C2 wurde eingefgt und die bisherige Zelle C2 wird zu D2 usw. Werden Zellen vertikal verbunden geschieht die Adressnderung in umgekehrter Reihenfolge. Wie sich im folgenden zeigt, kann eine Spalte C nicht mehr addressiert werden, das die Zellen C1 bis C4 nicht mehr spaltig positioniert sind: A1 B1 A2 B2 vertikal geteilt A3 B3 A4 B4 verbunden mit C4 C1 D1 C2 neu eingefgt D2 E2 C3 D3 C4

Werden Zellen horizontal geteilt, wird die erforderliche Anzahl Zeilen neu eingefgt. Im folgenden Beispiel wurde C2 zunchst horizontal geteilt, danach vertikal. Damit sind vier Zellen entstanden. Der Writer behandelt den Inhalt von C2 ans zwei Zeilen und zhlt die Zellen innerhalb dieser Zeilen. Der ursprngliche Zellname wird um einen numerischen Wert fr die neue Zelle und einen fr die neue Zeile erweitert. Damit bedeutet der Zellname C2.1.2, dass aus der dritten Zelle in der zweiten Zeile eine Zelle die erste Zelle in der neuen zweiten Zeile entstanden ist. A1 B1 C2.1.1 C2.2.1 A2 B2 vertikal geteilt C2.1.2 C2.2.2 A3 B3 A4 B4 verbunden mit C4 C3 D3 C4 D2 E2 C1 D1

In gleicher Weise wird auch bei weiteren Teilungs- und Verbindungs-Operationen weiteradressiert. Der Service .com.sun.star.text.TextTable erlaubt den Zugriff auf Tabellenzellen auf zwei Wegen: - Zelladressierung ber Namen - Zugriff ber den Tabellen-Cursor (com.sun.star.text.TextTableCursor) Die Tabelle implemtiert auch das interface com.sun.star.table.XCellRange, das auch den Zugriff ber die Zeilen- und Spaltenposition erlaubt. Dadurch werden die Tabellen in gewissen Grenzen kompatibel zu Tabellen der Tabellenkalkulation. Texttabellen knnen sortiert werden, Diagramme knnen daraus erzeugt werden sowie automatische Formatierungen knnen darauf angewandt werden. Diese Fhigkeiten sind implementiert mittels der Interfaces com.sun.star.util.XSortable, com.sun.star.chart.XChartDataArray und com.sun.star.table.XAutoFormattable.

Benannte Tabellenzellen, Spalten und der TableCursor

Das Interface com.sun.star.text.XTextTable ermglichte das arbeiten mit Tabellen. Die folgenden Methoden werden damit bereitgestellt:
void initialize ( [in] long nRows, [in] long nColumns) sequence< string > getCellNames() com.sun.star.table.XCell getCellByName( [in] string aCellName) com.sun.star.table.XTableRows getRows() com.sun.star.table.XTableColumns getColumns() com.sun.star.text.XTextTableCursor createCursorByCellName( [in] string aCellName)

Die Methode initialize setzt die Anzahl der Zeilen und Spalten bevor eine neu erzeugte Tabelle in das Dokument eingefgt werden. Die Methode getCellNames liefert eine Sequence von Strings mit den Namen aller enthaltenen Zellen. Mit getCellByName kann dann auf die Zellen der Tabelle zugegriffen werden. getRows liefert eine Tabellenzeile als interface com.sun.star.table.XTableRows, das auch com.sun.star.container.XIndexAccess enthlt. Zustlich sind Methoden zum einfgen und entfernen von Zeilen enthalten:
void insertByIndex ( [in] long nIndex, [in] long nCount) void removeByIndex ( [in] long nIndex, [in] long nCount)

Die folgende Aufstellung beschreibt, unter welchen Bedingungen die Methoden angewandt werden knnen: Methode in com.sun.star.table.XTableRows getElementType() hasElements() getByIndex() getCount() insertByIndex() removeByIndex() Normale Tabelle X X X X X X Komplexe Tabelle X X X X -

Jede Zeile wird von getRows als Interface com.sun.star.text.TextTableRow bereitgestellt. Damit untersttzt es auch ein com.sun.star.beans.XPropertySet (beschrieben im Service com.sun.star.text.TextTableRow). Die Methode getColumns ist hnlich zu getRows mit gewissen Einschrnkungen. Es wird ein Interface com.sun.star.table.XTableColumns geliefert, das auch com.sun.star.container.XIndexAccess untersttzt. Zustzlich sind die folgenden Methoden enthalten:
void insertByIndex( [in] long nIndex, [in] long nCount) void removeByIndex( [in] long nIndex, [in] long nCount)

Die folgende Aufstellung beschreibt, unter welchen Bedingungen die Methoden angewandt werden knnen: Methoden von com.sun.star.table.XTableColumns Normale Tabelle Komplexe Tabelle

getElementType() hasElements() getByIndex() getCount() insertByIndex() removeByIndex()

X X X (but returned object supports XInterface only) X X X

X X -

Die Methode createCursorByCellName erzeugt einen Tabellen-Cursor, der in der angegebenen Zelle steht. Dieser Cursor kann verwendet werden und Zellbereiche zu markieren, Zellen zu teilen und zu verbinden sowie Zell/Zellbereichs-Properties zu bearbeiten.
Zugriff auf bereits existierende Tabellen

Mit dem Interface com.sun.star.text.XTextTablesSupplier, das am Model implementiert, ist erhlt man ber die Methode getTables Zugriff auf den Service com.sun.star.text.TextTablesSupplier. Man erhlt Zugriff auf com.sun.star.container.XNameAccess und ebenso auf com.sun.container.XIndexAccess.

8.3 Weitere Aspekte von Textdokumenten


Feldbefehle

Textfelder sind Textinhalte innerhalb des Flietextes. Einfache Textfelder knnen beispielsweise das aktuelle Datum, die Seitennummer und den Namen des Autors des Dokumentes beinhalten und anzeigen. Erweiterte Felder, die das Interface com.sun.star.text.XDependendTextField untersttzen, bieten den Zugriff auf Datenbanken, auf DDE-Quellen, oder knnen als Variablen verwendet werden. Einfache Felder werden and der MultiServiceFactory ber ihren Service-Namen erzeugt und knnen dann u.a. mit der Methods insertTextContent in den Text eingefgt werden. Erweiterte Felder bentigen einen sog. FieldMaster, von dem sie Ihre Daten erhalten. Dieser wird ebenfalls ber seinen Service-Namen and der MultiServiceFactory erzeugt. Beispiel zur Verwendung von Feldbefehlen mit und ohne TextFieldMaster:
Sub Main oText = thiscomponent.getText oCursor = oText.createTextCursor oDateTimeField = thiscomponent.createInstance("com.sun.star.text.TextField.DateTime") oDateTimeField.IsDate = true oText.insertTextContent( oCursor, oDateTimeField, false) oUserMaster = thiscomponent.createInstance("com.sun.star.text.FieldMaster.User") oUserField = thiscomponent.createInstance("com.sun.star.text.TextField.User") oUserMaster.Name = "User" oUserMaster.Content = "Inhalt" oUserField.attachTextFieldMaster( oUserMaster ) oText.insertTextContent( oCursor, oUserField, false) End Sub

Zugriff auf existierende Feldbefehle

Um auf Feldbefehle und ihre FieldMaster zuzugreifen wird das Interface com.sun.star.text.XTextFieldsSupplier benutzt, das am Model implementiert ist. Es bietet folgende zwei Methoden
com.sun.star.container.XEnumerationAccess getTextFields(); com.sun.star.container.XNameAccess getTextFieldMasters();

Ein leeres Dokument enthlt bereits vier FieldMaster, die die Nummernkreise fr Tabellen, Textrahmen, Grafiken und Zeichenobjekte enthalten. (com.sun.star.FieldMaster.SetExpression.Illustration/Table/Text/Drawing) Der Name des FieldMasters setzt sich blicherweise aus dem Service-Namen und dem eigentlichen Feldnamen, getrennt durch einen Punkt zusammen. Datenbank-FieldMaster weichen davon ab. Hier wird an den Service-Namen der Name der Datenquelle, der Tabelle oder Query sowie der Spalte, jeweils durch Punkt getrennt, angehngt. Basic-Beispiel:
Sub Main oFieldMasters = thiscomponent.gettextfieldmasters oNames = oFieldMasters.getElementNames ' gebe die Namen aller User-FieldMaster aus for i = 0 to ubound(oNames) if left(oNames(i), 35) = "com.sun.star.text.FieldMaster.User." then print right(oNames(i), len(oNames(i))-35) endif next i oFields = thiscomponent.gettextfields oFieldEnum = oFields.createEnumeration while oFieldEnum.hasMoreElements oField = oFieldEnum.nextElement oNames = oField.getSupportedServiceNames 'gebe den Inhalt und das Kommando aller User-Felder aus if oField.supportsService("com.sun.star.text.TextField.User") then print oField.getPresentation(false), oField.getPresentation(true) endif wend End Sub

AutoText

Die AutoText-Funktion wird verwendet, um wiederverwendbare Textabschnitte zu verwalten. Sie knnen einfache Strings wie auch komplette Textdokumente enthalten. Drei Services werden in diesem Zusammenhang verwendet:

com.sun.star.text.AutoTextContainer - beschreibt die gesamte AutoTextSammlung com.sun.star.text.AutoTextGroup Zugriff auf AutoText-Gruppe com.sun.star.text.AutoTextEntry einzelner AutoText-Eintrag

Basic-Beispiel:
sub AutoText( xTextCursor as Object) ' Fgt einen AutoText-Eintrag an der bergebenen Cursor-Position ein (mxDocCursor) oAutoTextContainer = createUnoService("com.sun.star.text.AutoTextContainer") ' Hole die Gruppe "Standard" oGroup = oAutoTextContainer.getByName("standard") ' Hole den Eintrag Blindtext (BT) oEntry = oGroup.getByName ("BT") ' Fge den Text an der bergebenen Cursor-Position ein oEntry.applyTo(xTextCursor) 'erzeuge einen neuen AutoText-Eintrag 'markiere den letzten Absatz im Dokument

xTextCursor.gotoEnd(false) xTextCursor.gotoPreviousParagraph(true) ' falls die Gruppe fr dieses Makro schon existiert, dann lsche sie if oAutoTextContainer.hasByName("APIBeispielGruppe") then oAutoTextContainer.removeByName("APIBeispielGruppe" ) endif ' erzeuge die Gruppe neu oNewGroup = oAutoTextContainer.insertNewByName ( "APIBeispielGruppe" ) ' erzeuge einen neuen Eintrag aus der Selektion des Cursors oNewEntry = oNewGroup.insertNewByName("NAE", "Neuer AutoText-Eintrag", xTextCursor) ' Fge einen String am Anfang des neuen AutoText-Eintrages ein oNewStart = oNewEntry.getStart() oNewEntry.insertString( oNewStart, "Dieser Text wurde per API eingefgt!\n\n", false ) end sub

Der vernderte AutoText-Block wird erst gespeichert, wenn das Objekt des AutoText-Eintrages zerstrt wird (Destruktor). In Java hat man keinen Einflu darauf, wann dieser Destruktor gerufen wird. Dadurch gibt es keine Mglichkeit, whrend der Programmlaufzeit sicherzustellen, dass der vernderte AutoText-Eintrag auch angewandt werden kann.

8.4 Weitere Programmierbeispiele


Beispiel Absatz, Vorlagen setzen, Text einfgen
/*Das Beispiel veraendert Absatz- und Zeichenvorlage an der momentanen Zeichenposition oder Markierung in der aktuellen Dokumentansicht. Voraussetzung: Zugriff auf den Service com.sun.star.frame.Desktop */ private void viewCursorExample() throws java.lang.Exception { Object desktop = //hier Desktop-Service beschaffen // Zugriff auf das interface com.sun.star.frame.XDesktop XDesktop xDesktop = (XDesktop)UnoRuntime.queryInterface( XDesktop.class, desktop); // ermitteln des aktuellen Contollers (vom aktiven Dokumentfenster) XComponent xCurrentComponent = xDesktop.getCurrentComponent(); // das zugehoerige Model ermitteln XModel xModel = (XModel)UnoRuntime.queryInterface(XModel.class, xCurrentComponent); // Model und Controller kennen einander XController xController = xModel.getCurrentController(); // vom Controller wird der TextViewCursor erfragt // ber das interface .com.sun.star.text.XTextViewCursorSupplier XTextViewCursorSupplier xViewCursorSupplier = (XTextViewCursorSupplier)UnoRuntime.queryInterface( XTextViewCursorSupplier.class, xController); // Zugriff auf View-Cursor XTextViewCursor xViewCursor = xViewCursorSupplier.getViewCursor(); // Zugriff auf das interface css.beans.XPropertySet um Zeichen- und Absatzeigenschaften zu veraenndern XPropertySet xCursorPropertySet = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, xViewCursor); // Zeichen- und Absatzeigenschaften aendern - hier Vorlagennamen setzen xCursorPropertySet.setPropertyValue("CharStyleName", "Quotation"); xCursorPropertySet.setPropertyValue("ParaStyleName", "Quotations"); // Um die Seitennummer zu ermitteln wird das interface .com.sun.star.text.XPageCursor benoetigt XPageCursor xPageCursor = (XPageCursor)UnoRuntime.queryInterface( XPageCursor.class, xViewCursor); System.out.println("The current page number is " + xPageCursor.getPage()); // der Cursor des Models bietet mehr Moeglichkeiten // es wird daher ein Model-Cursor an der Positwe des View-Cursors erzeugt. // dazu wird das zur aktuellen Cursor-Position passende Text-Interface ermittelt // das geschieht ueber die Methode getText des Interfaces .com.sun.star.text.XTextRange XText xDocumentText = xViewCursor.getText(); // an diesem interface wird dann ein neue Cursor erzeugt

XTextCursor xModelCursor = xDocumentText.createTextCursorByRange(xViewCursor.getStart()); // dieser Cursor-Service implementier u.a. die interfaces XWordCursor, XSentenceCursor, XParagraphCursor // XDocumentInsertable, XSortable und XContentEnumerationAccess // das interface css.beans.XPropertySet ermoeglicht den Zugriff auf die Eigenschaften die der // Service com.sun.star.text.TextCursor spezifiziert // hier wird am Endes des Absatzes Text eingefuegt XParagraphCursor xParagraphCursor = (XParagraphCursor)UnoRuntime.queryInterface( XParagraphCursor.class, xModelCursor); // goto the end of the paragraph xParagraphCursor.gotoEndOfParagraph(false); xParagraphCursor.setString(" ***** Ende des Absatzes! ******"); }

Beispiel - TextCursor
protected void TextCursorExample() { try { // beschaffe XSentenceCursor Interface des Cursors XSentenceCursor xSentenceCursor = (XSentenceCursor)UnoRuntime.queryInterface( XSentenceCursor.class, mxDocCursor); // gehe zum naechsten Satz, ohne Markierung xSentenceCursor.gotoNextSentence(false); // beschaffe das XWordCursor Interface des Cursors XWordCursor xWordCursor = (XWordCursor) UnoRuntime.queryInterface( XWordCursor.class, mxDocCursor); // springe ueber die erste fuenf Woerter, markiere das sechste xWordCursor.gotoNextWord(false); xWordCursor.gotoNextWord(false); xWordCursor.gotoNextWord(false); xWordCursor.gotoNextWord(false); xWordCursor.gotoNextWord(false); xWordCursor.gotoNextWord(true); // fuege ein Wort ein // die aktuelle Markierung wird dabei ueberschrieben // im Moment ist das fuenfte Wort markiert // mxDocText.insertString(xWordCursor, "old ", true); // setze das neue Wort auf 'Fett' //nutze dazu das Interface XPropertySet XPropertySet xCursorProps = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, mxDocCursor); xCursorProps.setPropertyValue("CharWeight", new Float(com.sun.star.awt.FontWeight.BOLD)); // ersetze den Punkt am Satzende xSentenceCursor.gotoEndOfSentence(false); xWordCursor.gotoPreviousWord(true); mxDocText.insertString(xWordCursor, ", mit dem TextCursor veraendert!", true); } catch (Exception e) { e.printStackTrace(System.out); } }

Beispiel Text in Tabellenzelle einfgen

Die folgende Hilfsfunktion fgt einen String in eine Tabellenzelle ein, von der der Name bekannt ist und setzt die Textfarber auf Wei:
public static void insertIntoCell(String sCellName, String sText, XTextTable xTable) { //Zugriff auf das .com.sun.star.text.XText Interface der Zelle, die durch den Namen referenziert wird XText xCellText = (XText) UnoRuntime.queryInterface( XText.class, xTable.getCellByName(sCellName)); // erzeuge einen Text-Cursor in der Zelle XTextCursor xCellCursor = xCellText.createTextCursor();

// XPopertySet beschaffen XPropertySet xCellCursorProps = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, xCellCursor); try { // Farbe auf Wei setzen xCellCursorProps.setPropertyValue("CharColor", new Integer(16777215)); } catch (Exception e) { e.printStackTrace(System.out); } // setzen des Zelltextes xCellText.setString(sText); }

Beispiel fr Feldbefehle
Sub Main oText = thiscomponent.getText oCursor = oText.createTextCursor oDateTimeField = thiscomponent.createInstance("com.sun.star.text.TextField.DateTime") oDateTimeField.IsDate = true oText.insertTextContent( oCursor, oDateTimeField, false) oUserMaster = thiscomponent.createInstance("com.sun.star.text.FieldMaster.User") oUserField = thiscomponent.createInstance("com.sun.star.text.TextField.User") oUserMaster.Name = "User" oUserMaster.Content = "Inhalt" oUserField.attachTextFieldMaster( oUserMaster ) oText.insertTextContent( oCursor, oUserField, false) End Sub

9 Entwicklung von UNO-Komponenten


9.1 Was macht eine UNO-Komponente aus?
Eine sehr allgemeine Definition eines UNO-Objekts besagte: Ein UNO-Objekt ist eine in ihren Ausmaen nicht nher beschriebene Einheit, von der andere Objekte nur eine definierte Schnittstelle wie oben beschrieben sehen. Nach dieser Definition ist eigentlich jede C++-Klasse ein UNO-Objekt, wenn sie von anderen UNOObjekten (und dann nur ber ihre UNO-Schnittstelle) benutzt wird, auch wenn sie selbst tief in eine der StarOffice-Klassenbibliotheken eingebunden ist. UNO-Komponenten gehen noch etwas ber diese Definition hinaus, da bei ihnen nicht nur technische Aspekte eine Rolle spielen sondern auch die Art der Entstehung und des Deployments. Eine UNOKomponente ist demnach eine Menge von einem oder mehreren UNO-Objekten, die nicht nur unabhngig von der sie verwendeten Applikation gebildet werden, sondern auch unabhngig von ihr deployed werden (knnen). Fr eine vollwertige Komponente wird also erwartet, dass sie

eine in UNO IDL definierte Schnittstelle hat andere Codeeinheiten sie nur darber ansprechen sie immer als Service erzeugt wird bzw. ber ein API eines anderen UNO-Objekts weitere Integrationen ausschlielich ber Konfigurationsdateien vornimmt sie unabhngig vom Office gebaut werden kann und nur die Libraries des SDK benutzt sie als UNO package deployed werden kann.

Es gibt eine ganze Reihe von UNO-Objekten, auf die alles bis auf die letzten beiden Punkte zutrifft, z.B. die meisten Objekte im Framework-Modul. Es spielt dabei keine Rolle, dass der StarOfficeProzess ohne sie gar nicht startet, es geht einzig und allein darum, dass sie ausschlielich ber ihre UNO-Interfaces und die Service Registry angesprochen werden. Dass sie nicht alle als eigene Komponenten deployed werden knnen, ist nur der Tatsache geschuldet, dass bei einigen von ihnen noch VCL benutzt werden muss, da das AWT Toolkit nicht die erforderliche Funktionalitt zur Verfgung stellt. Dadurch ergibt sich eine Build-Abhngigkeit und auch ein Problem im Deployment, denn die VCL muss natrlich mit dem Office-Prozess geteilt werden. Abgesehen vom Deployment gilt aber alles, was in diesem Kapitel ber UNO-Komponenten zu lesen wird, auch fr diese Komponenten zweiter Klasse. hnliches gilt fr UNO-Objekte, die innerhalb von anderen class libraries wie SFX oder SW residieren: sie knnen wie UNO-Komponenten entwickelt, aber nicht wie sie deployed werden.

9.2 Entwicklung von UNO-Komponenten


Die Entwicklung einer UNO-Komponente startet mit dem Design ihrer UNO-Schnittstelle. Dabei gilt es zunchst, geeignete Interfaces festzulegen. In einem ersten Schritt sollten dabei Aspekte herausgearbeitet werden, Gruppen von Funktionalitt, die man sich als sinnvolle Einheit vorstellen kann, die auch unabhngig von anderer Funktionalitt einsetzbar erscheint. Dabei spielt es keine Rolle, dass die angedachten Objekte mehr Funktionalitt haben sollen, dieser Design-Schritt soll in erster Linie die Wiederverwendbarkeit von Interfaces (und damit von Code, der sie benutzt) ermglichen. Natrlich ist auch die gesamte Schnittstelle eines UNO-Objekts wichtig. Zu jedem Objekt sollte immer ein Interface bereitgestellt werden, dass seine komplette per UNO zugngliche Funktionalitt zusammenfasst, also eines der seit StarOffice 8 mglichen Multiple Inheritance Interfaces.

In einem weiteren Schritt kann dann noch ein Service definiert werden, der dieses Interface implementiert, sofern das UNO-Objekt ber den Service Manager erzeugt werden soll. Es sollten hier auch Konstruktoren definiert werden, um alle Vorteile auszuschpfen, die das neue UNO bietet. Fr ein Objekt, das ausschlielich als Rckgabewert eines API calls eines anderen UNO-Objekts zugnglich ist, ist ein solcher Schritt natrlich nicht erforderlich. Aus den fertigen IDL-Dateien kann mit Hilfe eines Code Generators Java oder C++ - Code generiert werden, der fr alle Methoden des Objekts kompilierbaren Code auswirft, fr Interfaces wie com::sun::star::uno::XInterface, com.sun.star.lang.XTypeProvider etc. sogar schon die fertigen Implementierungen. Die Code-Generierung ist dabei sowohl fr Services als auch fr das Interface eines nicht als Service zugnglichen Objekts mglich. In C++ werden fr die Generierung Implementation Helper Classes benutzt, wie sie auch heute schon von den Entwicklern manuell verwendet werden. Der Code Generator erzeugt aber nicht nur Code, fr Services wird gleichzeitig auch alles erzeugt, was fr ein Deployment als UNO package erforderlich ist, also die Implementierung des Interface com.sun.star.lang.XServiceInfo, die C-Funktionen fr Registrierung und Instantiierung des Service und den parcel descriptor fr das UNO package.

#include #include #include #include #include #include #include #include #include #include #include #include

<stdio.h> <cppuhelper/bootstrap.hxx> <com/sun/star/uno/Reference.hxx> <com/sun/star/uno/Sequence.hxx> <com/sun/star/lang/XMultiComponentFactory.hpp> <com/sun/star/frame/XComponentLoader.hpp> <com/sun/star/datatransfer/XTransferable.hpp> <com/sun/star/datatransfer/DataFlavor.hpp> <com/sun/star/io/XStream.hpp> <com/sun/star/io/XOutputStream.hpp> <com/sun/star/io/XTruncate.hpp> <com/sun/star/ucb/XSimpleFileAccess.hpp>

using namespace com::sun::star; int main( ) { try { // URL of document to load ::rtl::OUSting sMyURL; // URL of stream to create ::rtl::OUSting sMyURL; // create the initial component context uno::Reference< uno::XComponentContext > rComponentContext = ::cppu::defaultBootstrap_InitialComponentContext(); // retrieve the service manager from the context uno::Reference< lang::XMultiComponentFactory > rServiceManager = rComponentContext->getServiceManager(); // create Desktop object to load the document uno::Reference < frame::XComponentLoader > xComponentLoader( xServiceManager->createInstanceWithContext( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ) ), xContext ), uno::UNO_QUERY_THROW ); // load the document uno::Reference < datatransfer::XTransferable > xTrans( xComponentLoader->loadComponentFromURL( sMyURL, RTL_CONSTASCII_USTRINGPARAM("_blank"), 0, uno::Sequence < beans::PropertyValue >() ), uno::UNO_QUERY_THROW ); // ask for representation as PNG datatransfer::DataFlavor aDataFlavor( ::rtl::OUString::createFromAscii("image/png"), ::rtl::OUString(), ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) ); uno::Any aAny = xTrans->getTransferData( aDataFlavor ); uno::Sequence < sal_Int8 > myBytes; aAny >>= myBytes; uno::Reference< ucb::XSimpleFileAccess > xSimpleFileAccess( xServiceManager->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.SimpleFileAccess") ), uno::UNO_QUERY_THROW ); uno::Reference < io::XStream > = xSimpleFileAccess->openFileReadWrite( aOutputURL ); uno::Reference< io::XOutputStream > xOutStream = xStream->getOutputStream(); uno::Reference< io::XTruncate > xTruncate( xOutStream, uno::UNO_QUERY ); if ( xTruncate.is() ) xTruncate->truncate(); xOutStream->writeBytes( myBytes.get, myBytes.getLength() ); xStream->close(); } return 0;