FR/Documentation/Fichiers IDL et C++

From Apache OpenOffice Wiki
Jump to: navigation, search

(Cette introduction est faite avec l'aide de :http://udk.openoffice.org/cpp/man/component_tutorial.html ) Vous devez commencer à être habitué si vous êtes parvenus jusqu'ici en lisant tous les chapitres précédents à la terminologie service/interface qui prévaut pour la programmation UNO. Cette terminologie n'étant pas universelle, je me permet d'en rappeler quelques éléments.


Services et Interfaces

Introduction

Voir Introduction à l'API StarOffice pour une introduction à UNO (ou Introducing the OpenOffice.org API). Dans l'API OpenOffice, un "service" est un concept abstrait qui fournit certaines interfaces et propriétés/attributs. Comme le souligne le Guide du développeur : “les propriétés sont des données dans un objet qui sont triées par nom sur une interface générique pour un accès de la propriété”. Il serait mieux de distinguer attribut et propriété. Mais nous ne le faisons pas pour le moment.

Un service possède plusieurs propriétés et une interface correspond à plusieurs méthodes qui trouvent un moyen de changer les propriétés. Prenons une voiture pour illustrer ces concepts. La voiture fournit deux interfaces concrètes : XAccelerationControl et XDrivingDirection. Deux méthodes d'exportation d'interface, la première pour accélérer et ralentir, la seconde pour faire tourner la voiture à droite ou à gauche (voir Figure 9). Pourquoi deux (ou plusieurs) interfaces ? C'est seulement pour réunir des fonctionnalités caractéristiques. Pensez à une vraie voiture où ces interfaces sont séparées (le volant d'un côté et les pédales de l'autre) et ce qui se passerait si seulement les pieds dirigeaient ces deux interfaces ?

Dans l'API OpenOffice, les modules groupent des services, des interfaces, des types, des énumérations et autres structures données (voir Figure 10). C'est impossible de comprendre un tel dessin sans se poser un certain nombre de questions et, en particulier, comment est-ce que nous voyons ce module quand il est utilisé dans un programme ?


Pour répondre à cette question, nous choisissons le langage OOoBasic :

'Listing 1
REM  *****  BASIC  *****
'en premier, créez le service
oSimpleComponent = CreateUnoService( "my_module.MyService1" )
'call the unique method
oSimpleComponent.methodOne()
....
'first create the service
oSimpleComponent2 = CreateUnoService( "my_module.MyService2" )
'call one of both method
oSimpleComponent.methodTwo()
...

Les règles de Danny Brewer

Les services sont similaires aux objets en java.

  1. Un service peut hériter de rien ou d'un autre service. (auquel on peut appliquer récursivement cette règle)
  2. Un service peut inclure zéro ou plusieurs services. (auxquels on peut appliquer récursivement ces règles)
  3. Un service peut exporter des interfaces.
  4. Un service peut avoir des propriétés.
  5. Une interface peut hériter d'aucune ou d'une autre interface (à laquelle on peut appliquer récursivement cette règle).
  6. Une interface peut inclure zéro ou plusieurs interfaces (auxquelles on peut appliquer récursivement ces règles).
  7. Une interface peut exécuter des méthodes.
  8. Une interface est toujours nommées par un nom commençant par un X.

De ces règles vous pouvez déduire que les méthodes sont TOUJOURS trouvées dans des interfaces, et les propriétés sont TOUJOURS trouvées dans des services.

Arbres IDL et programmation UNO

J'ai déjà eu l'occasion d'aborder la notion d'arbre IDL dans un chapitre précédent (voir Aller plus loin avec l'inspector Java). Ce chapitre me semble toutefois l'endroit tout indiqué pour aller plus loin dans les explications.

Nous avons suffisamment programmé l'API UNO pour en déduire un certain nombre de règles pour le langage C++.

Règle 1 : le langace C++ nous permet de "naviguer" d'une interface à une autre. Nous aborderons le problème de l'obtention de ces interfaces plus loin.

Documentation note.png Note : cette règle n'est vrai que pour le langage C++ et à ma connaissance pour le langage Java. Mais le langage OOoBasic permet quant à lui d'utiliser des variables pour stocker des services. C'est beaucoup plus pratique et donne des programmes beaucoup plus lisibles.

Règle 2 : si pour une raison ou une autre on est obligé de manipuler un service, il faudra le faire dans une variable de type com.sun.star.uno.XInterface. Ce type est une interface puisque son nom commence par un X, et mettre une variable d'un type dans une variable d'un autre type s'appelle transtyper. Nous aborderons plus loin le problème de l'obtention de ces services en C++.

Nous pouvons déduire de ces deux règles que le programmeur C++ devra, d'une manière ou d'une autre, retrouver des chemins pour aller d'une interface vers une autre. Si je pars d'une interface XTruc, vous pouvez appeler toutes ses méthodes ou chercher d'autres interfaces me conduisant à utiliser d'autres méthodes. Toutes les possibilités à partir de l'interface XTruc peuvent être représentées par un arbre : c'est cela que j'appelle arbre-IDL. Mon travail de programmeur va consister à trouver un chemin dans cet arbre et ce n'est pas toujours facile. J'ai déjà présenté les arbres-IDL (ou plus exactement les chemins dans cet arbre) dans ce document sous plusieurs formes :

  1. Représentation textuelle d'un arbre IDL.
  2. Représentation avec un outil d'introspection d'un arbre IDL.
  3. Représentation schématique d'un arbre IDL.

Avant d'aborder la manière dont on réalise les chemins au travers des arbres en C++ on va déjà revenir sur les fichiers IDL permettant de spécifier des modules, des interfaces et des services.

Specification IDL

Les interfaces sont spécifiées à l'aide d'un langage spécial, le langage IDL. UNO utilise UNO-IDL comme le langage de définition de l'interface. Le Langage de définition de l'Interface (IDL) est un langage descriptif (et non un langage de programmation) décrivant l'existence des interfaces qui seront rendues effectives par les objets. Avec IDL, vous définissez le nom de l'interface, les noms de chacun des attributs et méthodes. Une fois que vous avez créé les fichiers IDL, vous pouvez utiliser un compilateur IDL pour générer les fichiers d'en-tête dans le langage de programmation C++. La façon de spécifier des modules simples avec IDL est si claire que nous choisissons de commencer en premier seulement par des exemples.

Specifier une interface

Nous prenons comme exemple, l'interface XdrivingDirection de la Figure ci-dessous.

Service&Interface.png

//Listing 2 Interface imaginaire XDrivingDirection
// IDL
interface XDrivingDirection
	{
		void turnLeft();
		void turnRight();
	};

Spécifier un service

L'exemple de la Figure ci-dessus est toujours utilisé, voici la spécification IDL correspondante :

//Listing 3 Spécification d'un service « car »
// IDL
interface XDrivingDirection
	{
		void turnLeft();
		void turnRight();
	};
interface XaccelerationControl
	{
		void speedUp();
		void slowDown();
	};
service car
	{
		// exported interfaces:
		interface XdrivingDirection;
		interface XaccelerationControl;
		[attribute] float speed; 
		[attribute] float angle;
	};

Nous voyons apparaître un type float et nous donnons d'autres types IDL plus loin.

Spécifier un module

Les modules sont un moyen de regrouper des services. Cette notion correspond plutôt à une bibliothèque et n'a que peu d'importance pour le programmeur C++ (sauf s'il désire réaliser des extensions composants ou addin par exemple). Nous donnons quand même ici la spécification IDL correspondant à un module :

//Listing 4 Spécification IDL du module my_module
// IDL
module my_module
	{
	interface Xsomething
		{
			void methodone();
		};
	service my_service1
		{
			// exported interfaces:
			interface Xsomething;
		};
	interface XsomethingElse
		{
			void methodTwo();
			void methodThree();
		};
	service my_service2
		{
			// exported interfaces:
			interface XsomethingElse;
		};
};

Plus loin avec IDL

Les types IDL sont décrits dans le tableau ci-dessous :

char

16-bit unicode character type

boolean

boolean type; true and false

byte

8-bit ordinal integer type

short

signed 16-bit ordinal integer type

unsigned short

unsigned 16-bit ordinal integer type

long

signed 32-bit ordinal integer type

unsigned long

unsigned 32-bit integer type

hyper

signed 64-bit ordinal integer type

unsigned hyper

unsigned 64-bit ordinal integer type

float

processor dependent float

double

processor dependent double

string

string of 16-bit unicode characters

any

universal type, takes every fundamental or compound UNO type, similar to Variant in other environments or Object in Java

void

Indicates that a method does not provide a return value

Les méthodes peuvent avoir des arguments. Chaque argument dans la liste des arguments doit commencer avec un des drapeaux de direction [in], [out] ou [inout] avant qu'un type connu et identificateur pour l'argument soit donné. Nous donnons un exemple que nous rencontrerons souvent dans ce document , un compteur :

//Listing 5 Module IDL décrivant un compteur
// IDL
module my_module
{
  interface XSomething 
  {
	long getCount();
	void setCount( [in] long nCount );
	long increment();
	long decrement();
  };
  service MyService
  {
    interface XSomething;
  };
};

Une interface peut être dérivée à partir d'une interface de base. Une interface dérivée peut déclarer ses propres attributs et ses méthodes. Les attributs et méthodes hérités ne peuvent pas être redéfinies dans l'interface dérivée. Un exemple d'héritage de l'interface :

//Listing 6 Héritage dog de annimal
//IDL
interface animal {
	attribute long age;
};
interface dog : animal {
	attribute short leg;
}

L'héritage multiple est aussi possible

interface dog : animal, friend {

L'héritage dans le service est présenté dans le prochain chapitre. Dans la terminologie objet OOo, il y a une différence entre attribut et propriété, différence qui se manifeste par leurs façons respectives d'y accéder. On accède aux propriétés avec setPropertyValue(PropertyName,Any) alors qu'on accède aux attributs avec la méthode set/get(AttributeName). Nous avons déjà rencontré la manipulation des propriétés lors de l'examen des formes.

Collecter de l'information UNO avec les fichiers IDL

Il y a plusieurs possibilités pour trouver de l'information sur UNO. La première est d'utiliser OOoBasic et l'outil XRay de Bernard Marcelly, voir les Tutoriels Basic. Point négatif : OOoBasic ne montre pas les propriétés et les méthodes exactes, quelques unes sont rajoutées parce qu'elles sont disponibles en OooBasic. L'autre possibilité est d'aller à l'adresse internet suivante : http://api.openoffice.org/docs/common/ref/index-files/index-1.html qui fournit la même information mais probablement de manière plus lisible. Nous avons fourni des exemples dans les chapitres antérieurs (en particulier chapitre 7...) et normalement le lecteur a des compétences sur le sujet.

Le point de vue de Danny Brewer

Néanmoins, il est important de comprendre le concept d'un "service" dans les documents sur l'API. Un service est juste une façon de grouper...

  1. d'autres services encore
  2. des interfaces

La partie (1) “d'autres services encore”, signifie bien sûr, qu'il y a même plus d'interfaces disponibles au service original. Laissez moi vous montrer différents exemples.

com.sun.star.sheet.SpreadsheetDocument est un service. SpreadsheetDocument contient le service com.sun.star.document.OfficeDocument et l'interface com.sun.star.sheet.XSpreadsheetDocument comme le montre le fichier IDL ci-dessous :

//Listing 7 Interface Specification
//IDL
service SpreadsheetDocument
{
	//-------------------------------------------------------------------------
 
	/** common service for all types of documents.
	 */
	service com::sun::star::document::OfficeDocument;
 
	..........
 
	//-------------------------------------------------------------------------
 
	/** provides access to the collection of spreadsheets.
	 */
	interface com::sun::star::sheet::XSpreadsheetDocument;
 
	//-------------------------------------------------------------------------

Par conséquent, l'ensemble combiné d'interfaces de com.sun.star.sheet.SpreadsheetDocument et com.sun.star.document.OfficeDocument est accessible à un document de la Feuille de calcul (qui est bien sûr un com.sun.star.sheet.SpreadsheetDocument).

Donc, bien que le composant chargé depuis l'URL retourne une interface, cette interface représente un service sous-jacent qui est un SpreadsheetDocument. En regardant les documents de l'API, vous pouvez dire quelles interfaces valides vous pouvez mettre en oeuvre.

SpreadsheetDocument possède une interface com.sun.star.sheet.XSpreadsheetDocument.

Le service com.sun.star.document.OfficeDocument possède les interfaces com.sun.star.view.XPrintable et com.sun.star.frame.XStorable.

Comme SpreadsheetDocument hérite de OfficeDocument, il est aussi valide de demander soit l'interface com.sun.star.view.XPrintable soit l'interface com.sun.star.frame.XStorable à partir de ce service com.sun.star.sheet.SpreadsheetDocument.

Maintenant, remplaçons dans le paragraphe précédent, les documents tableurs par les documents textes et tout le discours précédent est encore valide. Comment expliquer ce qu'est un service sous-jacent ?

Il n'y a pas de formules magique pour cela. En principe, c'est évident. Si vous démarrez un tableur, par exemple, alors vous avez le service com.sun.star.sheet.SpreadsheetDocument.

De la même façon, si je crée un objet par son nom de service.....

' obtention d'un service en OOoBasic
oShape = oDoc.createUnoService( "com.sun.star.drawing.EllipseShape" )

alors je sais quel service c'est, parce que j'ai donné le nom du service dans l'instruction.

Oui, vous pouvez toujours dire quelles interfaces sont disponibles si vous savez le nom du service, et ce, seulement en regardant la documentation de l'API. Aucune hypothèse. Aucun besoin de XRay. C'est une science absolue. Les multiples interfaces valides sont les interfaces du service lui-même, et de tous les services qui seront hérités de ce service.

Dans certains cas, il est évident de savoir quels services vous avez.

Si vous appelez getCellRangeByName(), alors vous obtenez un service com.sun.star.sheet.SheetCellRange. Si vous appelez getCellByPosition(), alors vous avez un service com.sun.star.sheet.SheetCell. Beaucoup de choses identiques sont disponibles dans ces deux services com.sun.star.sheet.SheetCell et com.sun.star.sheet.SheetCellRange, mais ils sont de nature différents. Le service com.sun.star.sheet.SheetCellRange représente un groupe rectangulaire de cellules tandis que le service com.sun.star.sheet.SheetCell concerne une cellule unique. Il y a évidemment des choses que l'on peut faire avec une cellule unique mais pas avec un groupe de cellule.

Il y a aussi d'autres possibilités. Si vous obtenez un service com.sun.star.table.CellRange à partir d'une table sous OOoWriter ce sera différent que si vous l'obtenez depuis une feuille de calcul, puisque ce sera un com.sun.star.sheet.SheetCellRange. Le service SheetCellRange est une version étendue du service CellRange. Lequel des deux services est obtenu dépend donc si votre demande getCellRangeByName() est réalisée à partir d'une table ou à partir d'une feuille de calcul.

Parfois, spécialement pour l'application OooWriter, seul le guide du développeur est une aide précieuse, donnant des informations sur les services obtenus à partir d'autres services et des appels API. Mais il est toujours vrai que lorsque l'on connaît le service que l'on a, on peut en déduire directement, seulement à partir de la documentation de l'API toutes les interfaces qu'il est possible de demander. Pas d'essais inutiles, c'est une science exacte.

Un autre exemple concret

Les fichiers IDL sont disponibles dans le dossier <OpenOffice.org1.1_SDK>/idl/. Évidemment, le problème avec cette solution est que nous voyons uniquement l'API UNO du SDK installé, lequel peut être légèrement différent de notre Openoffice.org. Cependant, nous expliquerons cette possibilité après avoir mentionné juste une autre solution : l'exploration de la base de registres.

On veut maintenant montrer un exemple. On commence à partir d'un

com::sun::star::document::OfficeDocument et du nom du service, on en déduit sa position dans l'arborescence <OpenOffice.org1.1_SDK>/idl/com/sun/star/document/OfficeDocument.idl

Ce fichier est présenté ci-dessous, en ayant pris soin de retirer les commentaires (voir com.sun.star.document.OfficeDocument) :

//Listing 7
//IDL
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 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;
};

Si on examine maintenant le service "com.sun.star.text.TextDocument" on trouve dans <OpenOffice.org1.1_SDK>/idl/com/sun/star/text/TextDocument.idl

//Listing 8
service TextDocument
{
	service com::sun::star::document::OfficeDocument;
	interface com::sun::star::text::XTextDocument;
	interface com::sun::star::util::XSearchable;
	interface com::sun::star::util::XRefreshable;
	....
};

Comme on peut voir, ce service com.sun.star.text.TextDocument contient le service com.sun.star.document.OfficeDocument. Cette dépendance est en fait un héritage. La représentation complète UML de cet exemple peut être trouvée dans le guide de développeur :

Figure tirée du Developer's Guide.

Tout paraît simple jusqu'ici parce qu'on est resté très vague et que l'on ne s'est pas déplacé très profondément dans l'arbre IDL. Voyons ces complications d'un peu plus près.

Services et C++, c'est pas simple

Tip.png

Si vous voulez bien comprendre le titre de cette section, lisez-là en vous posant systématiquement la question de savoir à tout moment quels sont les services disponibles.


Il est grand temps maintenant d'aller plus loin dans notre exemple et de fournir du code avec commentaires. Pour cela nous allons prendre du code déjà abordé (voir le code correspondant pour OOoWriter).

 
//Listing 9 Writer Example
//C++
    OUString sDocUrl;
    osl::FileBase::getFileURLFromSystemPath(
                 OUString::createFromAscii("/home/smoutou/Documents/demo.sxw"),sDocUrl);
 
    Reference< XComponent > xWriterComponent = 
                    rComponentLoader->loadComponentFromURL(
	    sDocUrl,
        OUString::createFromAscii("_blank"),
        0,
        Sequence < ::com::sun::star::beans::PropertyValue >());
 
   Reference < XTextDocument > xTextDocument (xWriterComponent,UNO_QUERY);

Le code nous montre que la variable xWriterComponent est de type com.sun.star.lang.XComponent, c'est une interface qui nous donne le service com.sun.star.text.TextDocument et ainsi aussi le service com.sun.star.document.OfficeDocument comme déjà expliqué.

com.sun.star.text.XTextDocument est une Interface du service TextDocument, cela est une chose facile à retenir parce que les deux noms ne diffèrent que par la lettre X. Mais allons encore plus loin.

Le fichier IDL com.sun.star.text.XTextDocument nous montre la méthode getText mais nous ne savons pas quels sont les nouveaux services disponibles dans la variable retournée par getText. Si l'on veut le savoir, il y a deux moyens :

A partir de

//Listing 10 Writer Example (continuation)
//C++
    Reference< XText > xText = xTextDocument->getText();

on essaie d'obtenir l'interface com.sun.star.text.XTextCursor

//Listing 11 Writer Example (continuation)
//C++
Reference< XTextCursor> xTextCursor = xText->createTextCursor();

Mais comment expliquer ce code ? Cherchant dans le fichier com.sun.star.text.XText nous trouvons seulement deux méthodes :

//Listing 12 XText Interface IDL file
// IDL
module com {  module sun {  module star {  module text {  
interface XText: com::sun::star::text::XSimpleText
{ 
	void insertTextContent( [in] com::sun::star::text::XTextRange xRange, 
			 [in] com::sun::star::text::XTextContent xContent, 
			 [in] boolean bAbsorb ) 
			raises( com::sun::star::lang::IllegalArgumentException ); 
	void removeTextContent( [in] com::sun::star::text::XTextContent xContent ) 
			raises( com::sun::star::container::NoSuchElementException ); 
 
}; 
}; }; }; };

Mais si vous regardez plus en détail dans ce fichier IDL, vous verrez que com.sun.star.text.XText hérite de com.sun.star.text.XSimpleText. Est-ce que la méthode createTextCursor est ici ? Oui, comme vous pouvez le voir.

 
//Listing 13 XSimpleText Interface IDL file
// IDL
module com {  module sun {  module star {  module text {  
interface XSimpleText: com::sun::star::text::XTextRange
{ 
	com::sun::star::text::XTextCursor createTextCursor(); 
	com::sun::star::text::XTextCursor createTextCursorByRange( [in] com::sun::star::text::XTextRange aTextPosition ); 
    [oneway] void insertString( [in] com::sun::star::text::XTextRange xRange, 
			 [in] string aString, 
			 [in] boolean bAbsorb ); 
 	void insertControlCharacter( [in] com::sun::star::text::XTextRange xRange, 
			 [in] short nControlCharacter, 
			 [in] boolean bAbsorb ) 
			raises( com::sun::star::lang::IllegalArgumentException ); 
 
};
}; }; }; };
Tip.png Si avant de lire la suite vous savez répondre à la question : quels sont les services disponibles dans la variable xTextCursor du listing 11, alors Bravo.


Quels sont les services disponibles ici ? J'ai utilisé un outil d'introspection pour la réponse, qui me donne :

******** Services : 8
com.sun.star.text.TextSortable
com.sun.star.style.ParagraphPropertiesComplex
com.sun.star.style.ParagraphPropertiesAsian
com.sun.star.style.ParagraphProperties
com.sun.star.style.CharacterPropertiesComplex
com.sun.star.style.CharacterPropertiesAsian
com.sun.star.style.CharacterProperties
com.sun.star.text.TextCursor

Vous pouvez probablement trouver chacun d'entre eux via internet mais ce sera une tâche longue et fastidieuse : de bonnes raisons d'expliquer les services d'introspection plus loin dans ce chapitre.

Documentation note.png A noter que c'est l'utilisation des méthodes retournant un type donné qui sont absolument difficiles à déchiffrer. Trouver les services accessibles est alors très difficile et, personnellement, je ne m'y aventure pas sans outil d'instrospection (voir un exemple ici). Bonne nouvelle quand même, il y a quand même une exception avec les méthodes createInstance et createInstanceWithContext pour lesquelles le service retourné est complètement déterminé.

Oui, voila décrit très superficiellement le travail du programmeur. Vous devez parcourir de tels chemins dans l'arbre IDL, pour trouver quoi faire en programmant. Heureusement il y a plus court en utilisant les exemples du SDK. Mais la plupart d'entre eux sont en Java, mais je dois avouer avoir trouvé beaucoup d'inspiration dans ces exemples même si je ne suis pas un programmeur Java.

IDL et C++

Ce problème est développé dans le guide du développeur ici.

Obtention d'une interface en C++

En C++, vous avez seulement des variables de type interface. Un des problèmes les plus souvent rencontrés met en oeuvre une interface. Ce problème se produit très rarement dans OooBasic mais très souvent dans C++/Java. On peut trouver des exemples divers à partir du chapitre 3 régulièrement jusqu'à ce chapitre.

Obtention d'une interface avec une fonction de la librairie

L'obtention d'une interface par une fonction de la librairie a déjà été rencontrée dans le code de démarrage. Nous le présentons ici sous forme schématique.

Obtention de l'interface XComponentContext

On part de nulle part mais utilisons une fonction toute prête, ici c'est defaultBootstrap_IntitialComponentContext() qui nous permet d'obtenir une interface de type com.sun.star.uno.XComponentContext.

Obtention d'une interface avec la macro UNO_QUERY

Comme exemple, on suppose qu'on a obtenu une interface com.sun.star.text.XTextDocument. En général, c'est fait par quelque chose comme :

//Listing 14
//C++
// Impossible à faire en C++ comme cela : il faut transtyper OfDoc en Interface
Reference<com::sun::star::text::XTextDocument> OfDoc = something_to_get_this_interface();

ou

//Listing 15
//C++
using namespace com::sun::star::text;
....
Reference<XTextDocument> OfDoc = something_to_get_this_interface();

et nous voulons mettre en oeuvre l'interface com.sun.star.frame.XStorable pour sauver notre document. La figure ci-dessous nous montre toutes les interfaces que l'on peut obtenir à partir de com.sun.star.text.XTextDocument.

SimpleUNOQUERY.png

Il s'agit des interfaces com.sun.star.util.XRefreshable, com.sun.star.util.XSearchable, com.sun.star.frame.XModel, com.sun.star.util.XModifiable, com.sun.star.frame.XStorable et com.sun.star.view.XPrintable même si l'on n'a pas représenté les flèches rouges correspondantes sur le dessin.

Les trois étapes pour l'obtention d'une interface

Trois étapes sont impliquées pour l'obtention d'une de ses interfaces :

1) Ajoutez la ligne de votre code pour la demande de l'interface

// C++
// query from com::sun::star::frame::XStorable interface
	Reference< XStorable > oToStore (OfDoc, UNO_QUERY);

Il s'agit d'une déclaration de variable avec initialisation. Si la variable est déjà déclarée, utilisez alors une version un peu différente :

// C++
// query from com::sun::star::frame::XStorable interface
	oToStore = Reference< XStorable > (OfDoc, UNO_QUERY);

2) Ajouter à l'aide d'une directive d'inclusion les fichiers hpp correspondants. Il faut ajouter aussi les espaces de nommage correspondants. L'inclusion est faite par :

//C++
	#include <com/sun/star/frame/XStorable.hpp>

et la gestion des espaces de nommage par :

//C++
	using namespace com::sun::star::frame;

3) Ajouter les types correspondants dans le makefile comme montré ci-dessous dans la ligne com.sun.star.frame.XStorable \ qui est ajoutée

# Listing 16 Makefile 
# makefile
# added com.sun.star.frame.XStorable
TYPES := \
	com.sun.star.uno.XNamingService \
	....
	com.sun.star.uno.XAggregation \
	com.sun.star.frame.XStorable \
	com.sun.star.lang.XMain \ 
    ...
    com.sun.star.container.XHierarchicalNameAccess
Documentation note.png

Apprendre à réaliser ces trois étapes est essentiel pour une programmation en C++ : il vous sera impossible de réaliser un programme sans demander à un moment donné une interface (ou un service, comme traité plus loin).

Exemple concret

Appliquons les trois étapes sur un exemple concret. On peut schématiser tout cela simplement comme un chemin simple dans un arbre IDL :

Obtention d'une interface à partir d'une autre

Et voici un exemple de code correspondant.

//Listing 19 Simple UNO_QUERY call
// C++
OUString sDocUrl;
    osl::FileBase::getFileURLFromSystemPath(
                 OUString::createFromAscii("/home/smoutou/Documents/demo.sxw"),sDocUrl);
    Reference< XComponent > xWriterComponent = rComponentLoader->loadComponentFromURL(
	sDocUrl,
        OUString::createFromAscii("_blank"),
        0,
        Sequence < ::com::sun::star::beans::PropertyValue >());
 
    Reference < XTextDocument > xTextDocument (xWriterComponent,UNO_QUERY);
// Ne pas oublier la direcive : #include <com/sun/star/frame/XStorable.hpp>
// ligne suivante correspond au schéma ci-dessus
    Reference < XStorable > xStorable (xTextDocument,UNO_QUERY);
    xStorable->store();

qui utilise les interfaces com.sun.star.text.XTextDocument et com.sun.star.frame.XStorable.

Quand pour obtenir une interface il faut passer par un service et par XMultiServiceFactory

On a déjà rencontré cela plusieurs fois, ainsi cela doit vous être familier. Mais, puisque nous n'avons pas discuté toutes les étapes en détail, je vais maintenant m'y consacrer et montrer comment cela fonctionne.

Le problème

Comment pouvez-vous obtenir une interface si le service correspondant n'est pas directement disponible ? Schématiquement le problème peut se représenter par :

Deux services indépendants

où les deux services com.sun.star.text.TextDocument et com.sun.star.text.TextTable n'ont pas de dépendance soit par héritage, soit par inclusion (un des deux services contient l'autre).

Les solutions

Premier cas : une méthode de votre interface vous permet d'obtenir directement la nouvelle interface. C'était le cas du Listing 11 de ce chapitre. Dans ce cas le fichier hdl correpondant n'est pas requis et je n'ai pas trouvé de moyen simple pour trouver les nouveaux services disponibles sans outil d'introspection ! Voici comment ceci sera noté schématiquement dans les chemins des arbres IDL :

Méthode pour l'obtention d'une interface

Règle 3 : lorsque vous obtenez une interface à partir d'une fonction membre vous ne devez pas construire les fichiers hdl en partant des fichiers IDL comme on doit le faire dans la méthode en trois étapes.

Second cas : aucune méthode de votre interface ne peut vous aider. Il vous faut demander un service avant d'obtenir l'interface. Cela peut être fait en deux ou trois instructions. J'ai déjà utilisé ces deux styles. Regardez dans le listing :

//Listing 20 Getting an Interface with XMultiServiceFacory
// C++
    Reference < XTextDocument > xTextDocument (xWriterComponent,UNO_QUERY);
// deux instructions à partir d'ici
    Reference<XMultiServiceFactory> oDocMSF (xTextDocument,UNO_QUERY);
// Ne pas oublier la directive d'inclusion : #include <com/sun/star/text/XTextTable.hpp>
    Reference <XTextTable> xTable (oDocMSF->createInstance(
			OUString::createFromAscii("com.sun.star.text.TextTable")),UNO_QUERY);

qui utilise le style "deux instructions" et les interfaces com.sun.star.text.XTextDocument et com.sun.star.text.XTextTable. Avec le style "trois instructions", on obtient l'interface comme présenté ci-dessous :

//Listing 21 Inserting a Table in a OOoWriter Document
// C++
    Reference<XMultiServiceFactory> oDocMSF (xTextDocument,UNO_QUERY);
 
	Reference< XInterface > textTable = oDocMSF->createInstance(
	               OUString::createFromAscii("com.sun.star.text.TextTable") );
// Ne pas oublier la directive d'inclusion : #include <com/sun/star/text/XTextTable.hpp>
	Reference< XTextTable > xTable(textTable, UNO_QUERY);

Notez que ces deux méthodes nécessitent une directive d'inclusion (et donc la construction) du fichier hpp correspondant (ici XtextTable.hpp) en travaillant comme pour l'obtention d'une interface en trois étapes. Mais le service ne nécessite pas de fichier d'inclusion car il est obtenu par une méthode (nommée «createInstance» dans ce cas) et de toute façon il est transtypé dans une com.sun.star.uno.XInterface (voir la règle 3 ci-dessus).

Nous donnons un schéma du chemin dans l'arbre IDL pour résumer ce dont nous venons de parler. Remarquez que dans ce chemin on repère très vite la situation par la présence de l'interface com.sun.star.uno.XInterface qui n'aurait aucune autre raison d'être présente.

Obtention d'un service

Dernière question : est-il possible de partir de l'interface XMultiServiceFactory pour obtenir n'importe quelle interface ? La réponse est non. Regardez le code ci-dessous où j'ai pris rOfficeServiceManager au lieu de oDocMSF parceque c'est une interface XmultiServiceFactory aussi.

//Listing 22 Wrong code
// C++
//  Reference<XMultiServiceFactory> oDocMSF (xTextDocument,UNO_QUERY);
// using rOfficeServiceManager instead oDocMSF
	Reference< XInterface > textTable = rOfficeServiceManager->createInstance(
	               OUString::createFromAscii("com.sun.star.text.TextTable") );
	Reference< XTextTable > xTable(textTable, UNO_QUERY);
	if (!xTable.is()) {
		printf("Erreur creation XTextTable interface !\n");
	return 1;
    }

Ce code se compile mais donne une erreur d'exécution. Cela signifie que l'on ne peut pas utiliser n'importe quelle interface com.sun.star.lang.XMultiServiceFactory pour obtenir n'importe quelle autre Interface.

Documentation caution.png Si vous travaillez avec un document demandez son interface XMultiServiceFactory correspondante avant d'envisager l'obtention d'un service particulier pour ce document.


Un autre exemple déjà présenté

Avant d'aller plus en avant, notez qu'un code utilisé plusieurs fois jusqu'ici, peut trouver des explications même si l'interface XMultiServiceFactory n'est pas encore associée à un document à ce stade du code :

//Listing 23 code de démarrage (bootstrap)
// C++
int main( ) {
//retrieve an instance of the remote service manager
    Reference< XMultiServiceFactory > rOfficeServiceManager;
    rOfficeServiceManager = ooConnect();
 
//get the desktop service using createInstance returns an XInterface type
    Reference< XInterface  > Desktop = rOfficeServiceManager->createInstance(
    OUString::createFromAscii( "com.sun.star.frame.Desktop" ));
 
//query for the XComponentLoader interface
    Reference< XComponentLoader > rComponentLoader (Desktop, UNO_QUERY);

Facile de retrouver le style "trois instructions" pou obtenir l'interface com.sun.star.frame.XComponentLoader en passant par le service com.sun.star.frame.Desktop n'est-ce pas ?

Voici en résumé de manière schématique, le chemin dans l'arbre IDL correspondant au code ci-dessus :

Obtention de l'interface XComponentLoader
Documentation note.png

Je ferai l'effort, dans la suite du document, de systématiquement montrer le changement de type du service en interface com.sun.star.uno.XInterface dans mes schémas. Il n'y a aucune autre raison de trouver cette interface dans un arbre IDL, et cela rendra plus facile le repérage de cette opération.

Correspondances pour les modules et interfaces

On aborde très simplement, sans entrer dans les détails, la correspondance entre fichier IDL et le code C++ généré. Ce problème a été partiellement traité dans des cas très particuliers :

Voir le Developer's Guide pour un traitement plus complet.

Continuons donc par d'autres exemples :

//Listing 153
// IDL 
module M 
{ struct E { long L; 
  }; 
};

est compilé en C++ comme

 
//Listing 154
// C++ 
namespace M 
{ struct E 
  { Long L; }; 
}

et on peut faire référence à E en dehors de M par M::E. D'autre part une instruction de nommage peut être utilisée pour référer cette structure simplement comme E :

//Listing 155
// C++ 
using namespace M; 
E e;
  e.L = 3;

Une autre alternative est d'employer la directive de nommage seulement pour M::E :

//Listing 156
// C++ 
using M::E;
  E e;
  e.L = 3;

Une interface est réalisée à l'aide d'une classe C++ qui contient les définitions des types, constantes et exceptions définies dans l'interface. L'exemple ci-dessous montre le comportement de cette correspondance pour une interface :

//Listing 157
// IDL
interface A{
  struct S {
    short field;
   };
 };

est compilée en :

 
//Listing 158
// C++
class SAL_NO_VTABLE A {
  struct S {
    short fiel;
  };
}; //A

On peut utiliser aussi :

//Listing 159
// Conformant uses
 A::S s; // declare a struct variable 
s.field = 3; // field access
// Non-conformant uses: 
// one cannot declare an instance of an interface class... 
A a; // ...nor declare a pointer to an interface class... 
A *p; // ...nor declare a reference to an interface class. 
void f(A &r);

Le service de Core reflection et son interface XIdlReflection

Beaucoup de points d'entrée pour l'introspection sont décrits dans le Developer's Guide. On en donne quelques uns et montrons le moyen d'en utiliser en C++.

Avant d'aborder le problème technique, rappelons l'intérêt des outils d'introspection. Nous avons sans cesse répété dans ce chapitre que la grande difficulté de la programmation UNO est de savoir à tout moment, quels sont les services et interfaces disponibles. Cette information est contenue dans les fichiers IDL, mais, de mon point de vue, partiellement seulement. C'est pour cela qu'un outil d'introspection est intéressant : il peut à tout moment vous fournir l'information tant convoitée.

L'introspection et OOoBasic

Documentation caution.png Cette section n'a pas pour vocation de remplacer l'inestimable outil de Bernard Marcelly, a savoir, XRay. Voir pour cela une description dans ce wiki.


OooBasic permet beaucoup de choses et en particulier l'introspection. Le code de Danny Brewer présenté ici : http://www.oooforum.org/forum/viewtopic.php?t=8737 nous montre comment ? Examinons un peu plus en détail ce code :

'Listing 160 Code d'exploration de la base de registre en OOoBasic
REM  *****  BASIC  *****
Sub Main 
  oReflection = createUnoService( "com.sun.star.reflection.CoreReflection" ) 
  oInfo = oReflection.forName( "nom.dannybrewer.test.XDannysCalcFunctions1" ) 
  aMethods = oInfo.getMethods() 
  For i = 0 To UBound( aMethods ) 
    oMethod = aMethods( i ) 
    Print oMethod.getName() 
  Next 
End Sub

puis nous créons un fichier IDL :

//Listing 161 Fichier IDL d'exemple
// IDL
#include <com/sun/star/uno/XInterface.idl>
#include <com/sun/star/lang/XInitialization.idl>
 
module my_module
{
 
interface XSomething : com::sun::star::uno::XInterface
{
	long getCount();
	void setCount( [in] long nCount );
	long increment();
	long decrement();
};
 
service MyService
{
    interface XSomething;
};
};

Avec ce fichier IDL il nous est possible de créer un fichier rdb et de l'enregistrer dans la base de registre. Maintenant OpenOffice.org fonctionne comme si nous avions une interface supplémentaire même si l'on n'a pas encore écrit le code correspondant. Evidemment, il nous est impossible d'utiliser ce service puis qu'il n'y a pas de code correspondant, mais on peut le voir. Pour cela on modifie légèrement le code de Danny :

'Listing 162
REM  *****  BASIC  *****
'From Danny : http://www.oooforum.org/forum/viewtopic.php?t=8737 
Sub Main
  oReflection = createUnoService( "com.sun.star.reflection.CoreReflection" )
  oInfo = oReflection.forName( "my_module.XSomething" )
  aMethods = oInfo.getMethods()
  'XRay.XRay oInfo
  print  UBound( aMethods )+1 & " methods :  ****"
  For i = 0 To UBound( aMethods )
    oMethod = aMethods( i )
    Print oMethod.getName()
  Next
 
  aTypes = oInfo.getTypes()
  print  UBound( aTypes )+1 & " types :  ****"
  For i = 0 To UBound( aTypes )
    oType = aTypes( i )
    Print "Types : " + oType.getName()
  Next
 
  aInterfaces = oInfo.getInterfaces()
  print  UBound( aInterfaces )+1 & " interfaces :  ****"
  For i = 0 To UBound( aInterfaces )
    oInterface = aInterfaces( i )
    Print "Interfaces : " + oInterface.getName()
  Next
End Sub

qui lancé, produit l'affichage suivant :

7 methods : ****
queryInterface acquire release getCount setCount increment decrement
3 types : ****
Types : com.sun.star.reflection.XIdlClass
Types : com.sun.star.lang.XTypeProvider
Types : com.sun.star.uno.XWeak
0 Interfaces : ****

où l'on peut voir parmi d'autres choses les quatre méthodes données dans le fichier IDL.

Il est possible de retrouver un peu plus d'information sur les méthodes par exemple. Si vous voulez retrouver tout ce que vous avez dans les fichiers IDL, y compris le nom et type des paramètres, l'extrait de code OOoBasic suivant fait l'affaire :

 For i = LBound( oMethods ) To UBound( oMethods )
      oMethod = oMethods( i )
      ' Check the method's interface to see if
      '  these aren't the droids you're looking for.
      sString = oMethod.getReturnType().getName() & " " & oMethod.getName() & "("
      parametersInfo = oMethod.getParameterInfos()
      if  UBound(parametersInfo) > 0 then
      for ii=0 to UBound(parametersInfo)
        if parametersInfo(ii).aMode = com.sun.star.reflection.ParamMode.IN Then
          stringType = "IN "
          elseif  parametersInfo(ii).aMode = com.sun.star.reflection.ParamMode.OUT Then
            stringType = "OUT "
        else
          stringType = "INOUT "
        end if      
        sString = sString & stringType  & ParametersInfo(ii).aType.getName() & " " & parametersInfo(ii).aName
        if ii < UBound(parametersInfo) Then sString = sString & ", "
      Next
      end if
      sString = sString & ")"
      ' Faire quelquechose avec sString ici, par exemple l'afficher
 Next

Pour aller plus loin en C++ voyez la section suivante sur l'interface XdlRefection.

Documentation note.png

Vous pouvez modifier la base de registre d'Openoffice sans écrire aucun code. Pour cela vous avez besoin d'un fichier IDL et son fichier rdb correspondant. Ajouter le fichier rdb dans le répertoire Unix “<Ooo>/program/unorc” ou le répertoire windows “<Ooo>/program/uno.ini”.

L'interface XIdlReflection

L'interface com.sun.star.reflection.XIdlReflection est décrite dans la section CoreReflection Service in Developer's Guide. Cette interface est aussi décrite ici et en français et avec en prime du code C++.

The XIntrospection Interface

Cette interface com.sun.star.beans.XIntrospection est décrite ici avec des exemples de code. Un autre exemple de code est donné dans la section Utilitaires C++. Voir aussi Introducing the OpenOffice.org_API et OOoBasic Introspection et Developer's Guide.

Utilisation de l'Inspecteur Java

Pour une introduction de la programmation en Java pour OOo, voir Java and Eclipse tutorial. Ce point n'est pas abordé dans ce tutorial : nous sommes seulement intéressé ici dans l'utilisation d'un composant Java à partir d'un programme C++.

Il est possible, en principe, d'utiliser l'Inspector Java à partir de n'importe quel langaga parcequ'il s'agit justement d'un composant. La méthode d'utilisation est très simple :

1°) Compiler l'exemple Java dans <OpenOffice.org_SDK>/examples/java/Inspector après ajout de SDK_AUTO_DEPLOYMENT = YES au début du makefile.

2°) Créer un exemple OOoBasic, par exemple (OOo1.1.X) :

'Listing 17 Simple OOoBasic example to call the Java Inspector
 
REM  *****  BASIC  *****
Sub JavaInspector           
	o = createUnoService("org.OpenOffice.InstanceInspector")
	'XRay o
	oReflection = createUnoService( "com.sun.star.reflection.CoreReflection" )
	o.inspect(oReflection)	
End Sub
Documentation note.png

Pour une utilisation du Java Inspector plus récent, voir Calling from a Basic Macro

.

Si Java n'est pas correctement intallé l'exécution de ce programme déclenchera l'ouverture d'une boîte de dialogue qui vous permettra de définir votre machine virtuelle JRE à condition de savoir où elle se trouve.

Nous voyons ci-dessous le résultat de l'exécution de ce programme.

Old Java Object Inspector

Notre problème est d'utiliser l'Inspecteur java à partir du C++. J'ai rencontré plusieurs problème pour faire cela et je présente la voie que j'ai choisie :

  1. construction d'un fichier urd à partir du fichier IDL (dans le makefile)
  2. Ne pas oublier d'enregistrer le fichier urd dans la base de registres (avec le makefile)
  3. ajouter org.OpenOffice.XInstanceInspector dans les TYPES du makefile
  4. copie du fichier IDL de <OpenOffice.org1.1_SDK>/examples/java/Inspector/XInstanceInspector.idl vers <OpenOffice.org1.1_SDK>/idl/org/OpenOffice/ XInstanceInspector.idl
  5. ajout de l'inclusion #include <org/OpenOffice/XInstanceInspector.hpp> et de l'espace de nommage namespace org::OpenOffice;
  6. ajout de ce code
	// C++
	Any toInspect;
	toInspect <<= rDesktop;
	Reference< XInstanceInspector > xinspect (rOfficeServiceManager->createInstance(
    OUString::createFromAscii( "org.OpenOffice.InstanceInspector" )),UNO_QUERY);
    xinspect->inspect(toInspect);

Et cela fonctionne comme en OOoBasic. Le makefile correspondant pour Linix est :

#Listing 18 Simple Makefile to compile a Java Inspector C++ call
# very simple makefile
HELPER = ReflectionHelper
CXXFILE = office_connect.cxx
OBJFILE = office_connect.o
OUTBIN = office_connect
OUT_COMP_INC = ../../../../LINUXexample.out/inc
OUT_COMP_OBJ = ../../../../LINUXexample.out/obj
OUT_COMP_BIN = ../../../../LINUXexample.out/bin
# added for Inspector
OUT_COMP_URD = $(OUT_COMP_BIN)
# end added
COMPONENT_RDB = $(OUT_COMP_BIN)/office_connect.rdb
CC_FLAGS = -c -O -fpic -fno-rtti
CC_DEFINES = -DUNX -DGCC -DLINUX -DCPPU_ENV=gcc3
PS = /
TYPES := \
	com.sun.star.uno.XNamingService \
	....
	com.sun.star.container.XHierarchicalNameAccess \
	org.OpenOffice.XInstanceInspector
# last line added

TYPESLIST = $(foreach t,$(TYPES),-T$(t))
GENHPPFILES = $(foreach t,$(TYPES),$(OUT_COMP_INC)/$(subst .,/,$(t)).hpp)

ALL : \
    ProUNOCppBindingExample

# added for Inspector
#building urd file
$(OUT_COMP_URD)/XInstanceInspector.urd : ../../../../idl/org/OpenOffice/XInstanceInspector.idl
	-mkdir -p $(OUT_COMP_URD)
	idlc -I. -I../../../../idl -O$(OUT_COMP_URD)  ../../../../idl/org/OpenOffice/XInstanceInspector.idl

# end added

#office_connectrc is provided with SDK
$(OUT_COMP_BIN)/office_connectrc : office_connectrc
	-mkdir -p $(OUT_COMP_BIN)
	cp office_connectrc $(OUT_COMP_BIN)/office_connectrc

$(COMPONENT_RDB) : $(OUT_COMP_URD)/XInstanceInspector.urd
	-mkdir -p $(OUT_COMP_BIN)
# added for Inspector
	regmerge $(COMPONENT_RDB) /UCR $(OUT_COMP_URD)/XInstanceInspector.urd
# end added
	regmerge $(COMPONENT_RDB) / "/usr/lib/openoffice/program/types.rdb"
	@echo --------------------------------------------------------------------------------
	@echo   Register necessary runtime components in $(COMPONENT_RDB)
	@echo --------------------------------------------------------------------------------
	regcomp -register -r $(COMPONENT_RDB) -c connector.uno.so
	regcomp -register -r $(COMPONENT_RDB) -c remotebridge.uno.so
	regcomp -register -r $(COMPONENT_RDB) -c bridgefac.uno.so
	regcomp -register -r $(COMPONENT_RDB) -c uuresolver.uno.so
#	@echo bla > $@

$(GENHPPFILES) :  $(subst /,$(PS),$(@D))
	mkdir -p $(subst /,$(PS),$(@D))
# modified for Inspector	cppumaker -Gc -BUCR -O$(OUT_COMP_INC) $(TYPESLIST) "/usr/lib/openoffice/program/types.rdb"
	cppumaker -Gc -BUCR -O$(OUT_COMP_INC) $(TYPESLIST) $(COMPONENT_RDB)

$(OUT_COMP_OBJ)/$(OBJFILE) : $(CXXFILE) $(GENHPPFILES) $(HELPER).hpp
	-mkdir -p $(subst /,$(PS),$(@D))
	gcc $(CC_FLAGS) $(CC_INCLUDES) -I. -I/usr/include -I$(OUT_COMP_INC)/examples \
	-I../../../../include -I$(OUT_COMP_INC) $(CC_DEFINES) -o$(OUT_COMP_OBJ)/$(OBJFILE) $(CXXFILE)

$(OUT_COMP_OBJ)/$(HELPER).o : $(HELPER).cxx $(HELPER).hpp
	-mkdir -p $(OUT_COMP_OBJ)/
	gcc $(CC_FLAGS) $(CC_INCLUDES) -I. -I/usr/include -I$(OUT_COMP_INC)/examples \
	-I../../../../include -I$(OUT_COMP_INC) $(CC_DEFINES) -o$(OUT_COMP_OBJ)/$(HELPER).o $(HELPER).cxx


$(OUT_COMP_BIN)/$(OUTBIN) : $(OUT_COMP_OBJ)/$(OBJFILE) $(OUT_COMP_OBJ)/$(HELPER).o
	-mkdir -p $(OUT_COMP_BIN)
	gcc -Wl -export-dynamic -L../../../../LINUXexample.out/lib -L../../../../linux/lib -L/usr/lib/openoffice/program \
	$(OUT_COMP_OBJ)/$(HELPER).o \
	-o$(OUT_COMP_BIN)/$(OUTBIN) $(OUT_COMP_OBJ)/$(OBJFILE) -lcppuhelpergcc3 -lcppu -lsalhelpergcc3 -lsal -lstlport_gcc


ProUNOCppBindingExample : $(COMPONENT_RDB) $(OUT_COMP_BIN)/$(OUTBIN) $(OUT_COMP_BIN)/office_connectrc
	@echo --------------------------------------------------------------------------------
	@echo Please use one of the following commands to execute the examples!
	@echo
	@echo make office_connect.run
	@echo --------------------------------------------------------------------------------

office_connect.run : $(OUT_COMP_BIN)/$(OUTBIN) $(OUT_COMP_BIN)/office_connectrc
	cd $(OUT_COMP_BIN) && $(OUTBIN)
Documentation note.png Note 1 : The New Object Inspector apparaît dans le SDK après la version 2.0. Il est plus complexe et capable de générer du code Java, C++ ou OOoBasic. Je n'ai pas testé le code ci-dessus avec the new object inspector mais ne vois pas pourquoi cela ne fonctionnerait pas correctement.
Documentation note.png Note 2 : Un petit exemple avec the new object inspector peut être trouvé dans ce document.
Documentation caution.png Je pense qu'il y a bien plus simple pour utiliser l'inspecteur Java, en particulier qu'il n'y a pas lieu de modifier le makefile (sauf pour l'interface org.OpenOffice.XInstanceInspector). Il doit en effet pouvoir s'utiliser comme n'importe quel autre service et ne nécessite donc pas la céation d'un fichier URD à partir d'un fichier IDL. Je pense avoir manqué de recul sur ce coup là et qu'il me faudra un jour ou l'autre reprendre ce problème à zéro.


Traduire des programmes OooBasic en C++

La traduction des programmes OooBasic en C++ n'est pas si immédiate que cela. Les interfaces et attributs vus par les programmes OooBasic sont construits à travers un pont (bridge) pour des questions de facilité. Alors ce qui est vu en OooBasic ne sera pas forcément vu en C++. Une des conséquences de tout cela est qu'il est impossible de réaliser cette traduction sans passer un peu de temps avec les fichiers IDL.

Quand j'ai abordé Writer, j'ai laissé le lecteur résoudre un certain nombre de problèmes (particulièrement les problèmes de curseurs). Nous choisissons ces problèmes ici comme exemple. Nous commençons par donner le programme OOoBasic de départ.

'Listing 36 Simple OOoBasic program to translate
REM ****  OOoBasic
Dim MyDocument As Object, MyText As Object
Dim MyCursor As Object
MyDocument = ThisComponent
MyText = MyDocument.Text
MyCurseur= MyTexte.createTextCursor
MyCurseur.goRight(1, false) ' move right one character
MyCurseur.goLeft(2, true) ' select the two previous characters

Toutes les instructions OOoBasic pour bouger le curseur sont résumées dans le tableau ci-dessous :

OOoBasic instructions
Méthode Signification
goRight(n, false) bouge le curseur d'un nombre spécifié de caractères vers la droite
goLeft(n, false) bouge le curseur d'un nombre spécifié de caractères vers la gauche
gotoStart(false) bouge le curseur au début du texte
gotoEnd(false) bouge le curseur à la fin du texte
gotoStartOfParagraph(false) bouge le curseur au début du paragraphe courant
gotoEndOfParagraph(false) bouge le curseur à la fin du paragraphe courant
gotoNextParagraph(false) bouge le curseur au prochain paragraphe
gotoPreviousParagraph(false) bouge le curseur au précédent paragraphe
gotoNextWord(false) bouge le curseur au prochain mot
gotoPreviousWord(false) bouge le curseur au précédent mot
gotoStartOfWord(false) bouge le curseur au début du mot courant
gotoEndOfWord(false) bouge le curseur à la fin du mot courant
gotoNextSentence(false) bouge le curseur au début de la prochaine phrase
gotoPreviousSentence(false) bouge le curseur au début de la précédente phrase
gotoStartOfSentence(false) bouge le curseur au début de la phrase courante
gotoEndOfSentence(false) bouge le curseur à la fin de la phrase courante

Mais si vous voulez traduire l'utilisation de ces fonctions en C++, il vous faut obtenir les interfaces en partant de l'interface XtextCursor interface (voir plus bas en Listing 41). Cela rend la traduction difficile. Par exemple trois interfaces curseur différentes en utilisant les méthodes OOoBasic du programme de départ. Il est grand temps de montrer les fichiers IDL correspondants.

Commençons par la première de toutes, l'interface com.sun.star.text.XWordCursor est montrée maintenant :

//Listing 37 XWordCursor interface (IDL file)
// IDL
module com {  module sun {  module star {  module text {  
interface XWordCursor: com::sun::star::text::XTextCursor
{ 
	boolean isStartOfWord(); 
	boolean isEndOfWord(); 
	boolean gotoNextWord( [in] boolean bExpand ); 
	boolean gotoPreviousWord( [in] boolean bExpand ); 
	boolean gotoEndOfWord( [in] boolean bExpand ); 
	boolean gotoStartOfWord( [in] boolean bExpand );  
}; 
}; }; }; };

L'interface com.sun.star.text.XParagraphCursor est montrée maintenant :

//Listing 38 XParagraphCursor interface (IDL file)
// IDL
module com {  module sun {  module star {  module text {  
interface XParagraphCursor: com::sun::star::text::XTextCursor
{ 
    com::sun::star::text::XParagraphCursor::isStartOfParagraph
	boolean isStartOfParagraph(); 
	boolean isEndOfParagraph(); 
    com::sun::star::text::XParagraphCursor::gotoStartOfParagraph
	boolean gotoStartOfParagraph( [in] boolean bExpand ); 
    com::sun::star::text::XParagraphCursor::gotoEndOfParagraph
	boolean gotoEndOfParagraph( [in] boolean bExpand ); 
	boolean gotoNextParagraph( [in] boolean bExpand ); 
    com::sun::star::text::XParagraphCursor::gotoPreviousParagraph
	boolean gotoPreviousParagraph( [in] boolean bExpand ); 
 
}; 
}; }; }; };

et pour finir l'interface com.sun.star.text.XSentenceCursor :

// Listing 39 XSentenceCursor interface (IDL file)
// IDL
module com {  module sun {  module star {  module text {  
interface XSentenceCursor: com::sun::star::text::XTextCursor
{ 
	boolean isStartOfSentence(); 
	boolean isEndOfSentence(); 
	boolean gotoNextSentence( [in] boolean Expand ); 
	boolean gotoPreviousSentence( [in] boolean Expand ); 
	boolean gotoStartOfSentence( [in] boolean Expand ); 
	boolean gotoEndOfSentence( [in] boolean Expand );  
}; 
 
//============================================================================= 
 
}; }; }; };

Si vous voulez savoir quelles interfaces vous pouvez demander il vous faut retrouver le service. Pour notre exemple c'est le service com.sun.star.text.TextCursor. Voici son fichier IDL où vous voyez les interfaces que vous pouvez demander.

//Listing 40 TextCursor service (IDL file)
// IDL
module com {  module sun {  module star {  module text {
service TextCursor
{
	service com::sun::star::text::TextRange;
    interface com::sun::star::text::XTextCursor;
	[optional] interface com::sun::star::text::XWordCursor;
	[optional] interface com::sun::star::text::XSentenceCursor;
	[optional] interface com::sun::star::text::XParagraphCursor;
	interface com::sun::star::beans::XPropertySet;
	interface com::sun::star::beans::XPropertyState;
	interface com::sun::star::beans::XMultiPropertyStates;
	[optional] interface com::sun::star::document::XDocumentInsertable;
	[optional] interface com::sun::star::util::XSortable;
};
}; }; }; };

Si vous partez de nouveau du Listing 11 il vous faudra un UNO_QUERY pour obtenir l'interface com.sun.star.text.XWordCursor.

//Listing 41 Using XwordCursor Interface
// C++
// Don't forget to add : #include <com/sun/star/text/XWordCursor.hpp>
// Don't forget to add "com.sun.star.text.XWordCursor \" in the makefile    
    Reference < XWordCursor > xWordCursor (xTextCursor,UNO_QUERY);
    xWordCursor->gotoNextWord(false); 
    xWordCursor->gotoNextWord(false); 
    xWordCursor->gotoNextWord(true);

La traduction peut probablement se faire automatiquement, mais un tel traducteur aurait besoin de connaissances sur les fichiers IDL.

En passant nous avons encore les huit services disponibles :

******** Services : 8
com.sun.star.text.TextSortable
com.sun.star.style.ParagraphPropertiesComplex
com.sun.star.style.ParagraphPropertiesAsian
com.sun.star.style.ParagraphProperties
com.sun.star.style.CharacterPropertiesComplex
com.sun.star.style.CharacterPropertiesAsian
com.sun.star.style.CharacterProperties
com.sun.star.text.TextCursor

La traduction de OOoBasic en C++ nécessite donc une bonne connaissance des services. Par exemple, le code

Dim Obj As Object Obj = createUnoService("com.sun.star.frame.Desktop")

est différent de

Dim RectangleShape As Object
RectangleShape = _ 
   Spreadsheet.createInstance("com.sun.star.drawing.RectangleShape")

Le deuxième dénote un objet contextuel.

Les objets contextuels sont généralement créés par une méthode d'objet dont dépend l'objet. La méthode createInstance, définie dans l'interface XMultiServiceFactory, est notamment utilisée dans les objets Document.

Voir Introduction à l'API StarOffice pour plus d'informations.

J'ai eu aussi l'occasion de traduire des programmes OOoBasic dans les chapitres Composants et boîte de dialogue et Plus loin avec les composants et les boîtes de dialogue.

Retour à la page d'accueil

Page d'accueil du développement C++ à l'aide du SDK

Voir aussi

Personal tools