FR/Documentation/OpenOffice Writer
Dans ce chapitre, nous utilisons encore le code initial décrit dans chapitre 3.3. Il consiste en un sous-programme “ooConnect ()” et un programme principal main(). Travailler avec ce code consiste à ajouter le nouveau code dans le programme principal. Nous donnons pour la troisième fois le programme principal :
//Listing 1
// C++
// adapted for OOoWriter
int main( ) {
//retrieve an instance of the remote service manager
Reference< XMultiServiceFactory > rOfficeServiceManager;
rOfficeServiceManager = ooConnect();
if( rOfficeServiceManager.is() ){
printf( "Connected sucessfully to the office\n" );
}
//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);
if( rComponentLoader.is() ){
printf( "XComponentloader successfully instanciated\n" );
}
//get an instance of the OOowriter document
Reference< XComponent > xWriterComponent = rComponentLoader->loadComponentFromURL(
OUString::createFromAscii("private:factory/swriter"),
OUString::createFromAscii("_blank"),
0,
Sequence < ::com::sun::star::beans::PropertyValue >());
// AJOUTER votre code ici
return 0;
}
Nous rappelons au lecteur que les exemples ci-dessous, prennent comme code de départ l'exemple “<OpenOffice.org1.1_SDK>/examples/DevelopersGuide/ProfUNO/CppBinding”. Notre code est mis dans “office_connect.cxx” et nous ajoutons ce que vous trouvez comme commentaires dans le code (directives d'inclusions et définitions des espaces de nommage) ainsi que dans le makefile (en général pour créer les fichiers hpp et hxx).
Utiliser le Dispatcher et enregistrer des Macros
La première chose que nous voulons examiner est l'utilisation du dispatcher avant l'utilisation directe des appels UNO dans la prochaine section. Si vous enregistrez des macros, vous obtenez du code OOoBasic qui utilise le dispatcher plutôt que les appels UNO directs. Voir la section The OpenOffice.org recorder and UNO dispatch calls pour une discussion sur l'enregistrement des commandes du dispatcher par rapport aux appels API.
Introduction
Par exemple si vous avez un document OOoWriter et que vous déclenchez l'enregistrement d'une macro pendant que vous insérez du texte et que vous le formatez, cela vous donne quelque chose qui doit ressembler à :
'Listing 2 OOoBasic and the Dispatcher with Macro Recorder
REM ***** BASIC *****
sub Main
rem ----------------------------------------------------------------------
rem define variables
dim document as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem ----------------------------------------------------------------------
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Text"
args1(0).Value = "demo de macro"
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args1())
rem ----------------------------------------------------------------------
dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Bold"
args2(0).Value = true
dispatcher.executeDispatch(document, ".uno:Bold", "", 0, args2())
rem ----------------------------------------------------------------------
dim args4(2) as new com.sun.star.beans.PropertyValue
args4(0).Name = "FontHeight.Height"
args4(0).Value = 14
args4(1).Name = "FontHeight.Prop"
args4(1).Value = 100
args4(2).Name = "FontHeight.Diff"
args4(2).Value = 0
dispatcher.executeDispatch(document, ".uno:FontHeight", "", 0, args4())
end sub
Ce code est très caractéristique de l'utilisation du dispatcher. Comment traduire ce code en C++ ? Le problème est de prendre en compte le dispatcher.
La première étape est d'obtenir l'interface XDispatcherHelper.
//Listing 3 Demande de l'interface XDispatchHelper
// C++
Reference< XDispatchHelper > rDispatchHelper = Reference< XDispatchHelper >
( rOfficeServiceManager->createInstance(
OUString( RTL_CONSTASCII_USTRINGPARAM(
"com.sun.star.frame.DispatchHelper" ))), UNO_QUERY );
Vous pouvez trouver plus d'explications ici (en anglais) (si vous n'êtes pas débutant) et vous comprendrez alors ce listing.
La deuxième étape est d'obtenir l'interface XFrame en partant de la variable Desktop (bureau) et après d'obtenir l'interface XDispatchProvider starting en partant de la variable frame qui contient le service XFrame (cela semble très important de partir de la variable frame).
//Listing 4 Obtenir une interface XFrame
// C++
Reference< XFrame > rFrame=rDesktop->getCurrentFrame();
Reference< XDispatchProvider > rDispatchProvider(rFrame,UNO_QUERY);
La troisième étape est de déclarer votre tableau (Sequence en C++) de “PropertValue” et de donner les valeurs :
//Listing 5 Les couples Name/Value des propriétés
// C++
Sequence < PropertyValue > args1(1);
args1[0].Name = OUString::createFromAscii("Text");
args1[0].Value <<= OUString::createFromAscii("demo de macro");
et l'étape finale est d'appeler le dispatcher :
//Listing 6 Appel du Dispatcher
// C++
rDispatchHelper->executeDispatch(rDispatchProvider,
OUString::createFromAscii(".uno:InsertText"),
OUString::createFromAscii(""),
0,
args1);
Le reste du code OOoBasic peut être facilement traduit comme montré ci-dessous :
//Listing 7 Autres appels du Dispatch
// C++
args1[0].Name = OUString::createFromAscii("Bold");
args1[0].Value <<=(sal_Bool)true;
rDispatchHelper->executeDispatch(rDispatchProvider,
OUString::createFromAscii(".uno:Bold"),
OUString::createFromAscii(""),
0,
args1);
args1.realloc(3);
args1[0].Name = OUString::createFromAscii("FontHeight.Height");
args1[0].Value <<= (sal_Int32)14;
args1[1].Name = OUString::createFromAscii("FontHeight.Prop");
args1[1].Value <<= (sal_Int32)100;
args1[2].Name = OUString::createFromAscii("FontHeight.Diff");
args1[2].Value <<= (sal_Int32)0;
rDispatchHelper->executeDispatch(rDispatchProvider,
OUString::createFromAscii( ".uno:FontHeight"),
OUString::createFromAscii(""),
0,
args1);
Le Dispatcher et l'Internationalization
Un des problèmes que vous rencontrerez avec ce style de programmation est : comment puis-je écrire de tels programmes pouvant tourner sur n'importe quelle machine dans le monde entier ? Si vous travaillez en français, comme je le fais, et que vous enregistrez une macro, vous allez rencontrer des valeur de propriétés en français. Par exemple, si j'enregistre une insertion d'image, j'obtiens le code OOoBasic :
'Listing 8 Inserting an Image (OOoBasic)
REM ***** BASIC *****
sub Main
rem ----------------------------------------------------------------------
rem define variables
dim document as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem ----------------------------------------------------------------------
dim args1(3) as new com.sun.star.beans.PropertyValue
args1(0).Name = "FileName"
args1(0).Value = "file:///home/smoutou/PhotoPCB2.jpg"
args1(1).Name = "FilterName"
args1(1).Value = "<Tous les formats>"
args1(2).Name = "AsLink"
args1(2).Value = false
args1(3).Name = "Style"
args1(3).Value = "Image"
dispatcher.executeDispatch(document, ".uno:InsertGraphic", "", 0, args1())
end sub
qui montre clairement du français. Si vous traduisez directement ce code comme expliqué plus haut, vous obtenez :
//Listing 9 Insertion d'une Image (C++ French Version)
// C++
....
Sequence < PropertyValue > args1(4);
args1[0].Name = OUString::createFromAscii("FileName");
args1[0].Value <<= OUString::createFromAscii("file:///home/smoutou/PhotoPCB2.jpg");
args1[1].Name = OUString::createFromAscii("FilterName");
args1[1].Value <<= OUString::createFromAscii("<Tous les formats>");
args1[2].Name = OUString::createFromAscii("AsLink");
args1[2].Value <<=(sal_Bool)false;
args1[3].Name = OUString::createFromAscii("Style");
args1[3].Value <<= OUString::createFromAscii("Image");
rDispatchHelper->executeDispatch(rDispatchProvider,
OUString::createFromAscii(".uno:InsertGraphic"),
OUString::createFromAscii(""),
0,
args1);
qui fonctionne correctement. Si je traduis le français du programme en anglais, cela fonctionne aussi sur ma version française d'OpenOffice :
//Listing 10 Inserting an Image (C++ English Version)
// C++
args1[1].Name = OUString::createFromAscii("FilterName");
args1[1].Value <<= OUString::createFromAscii("<All formats>");
....
args1[3].Name = OUString::createFromAscii("Style");
args1[3].Value <<= OUString::createFromAscii("Graphics");
....
Mais nous ne pouvons pas éviter la question : est-ce que la première version en français marche sur tous les ordinateurs ? Je n'ai pas de réponse. Je suppose que la version anglaise fonctionne partout. Il m'est impossible aussi d'éviter cette seconde question : comment puis-je savoir que « <tous les Formats> » est traduit par « <All Formats> » en anglais ?
Créer, ouvrir un document writer
On commence par ouvrir un nouveau document OOowriter. Cela peut être fait avec le code ci-dessous :
//Listing 11 Obtaining a blank OOoWriter Document
// C++
//get an instance of the OOowriter document
Reference< XComponent > xWriterComponent = rComponentLoader->loadComponentFromURL(
OUString::createFromAscii("private:factory/swriter"),
OUString::createFromAscii("_blank"),
0,
Sequence < ::com::sun::star::beans::PropertyValue >());
tandis que l'ouverture d'un document existant se fait par :
//Listing 12 Obtaining a blank OOoWriter Document
// C++
//get an instance of the OOowriter document
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 >());
Gestion du texte
Trouver le texte
Nous commençons par montrer comment on peut trouver le texte ouplus exactement l'interface XText.
//Listing 13 Obtenir l'interface XText
// C++
// Don't forget to add : using namespace com::sun::star::text;
// Don't forget to add : #include <com/sun/star/text/XTextDocument.hpp>
// Don't forget to add "com.sun.star.text.XTextDocument \" in the makefile
// Don't forget to add : #include <com/sun/star/text/XText.hpp>
// Don't forget to add "com.sun.star.text.XText \" in the makefile
//get an instance of the OOowriter document
Reference< XComponent > xWriterComponent = rComponentLoader->loadComponentFromURL(
OUString::createFromAscii("private:factory/swriter"),
OUString::createFromAscii("_blank"),
0,
Sequence < ::com::sun::star::beans::PropertyValue >());
Reference < XTextDocument > xTextDocument (xWriterComponent,UNO_QUERY);
Reference< XText > xText = xTextDocument->getText();
La chose la plus intéressante est de faire des choses visibles (je veux dire ajouter ou retirer du texte).
Voir aussi com.sun.star.text.XTextDocument et com.sun.star.text.XText.
Ecrire du texte dans le document
La manière la plus simple pour écrire du texte dans un document et la méthode setString de l'interface XText interface. Cela nous donne en l'occurrence ce code :
//Listing 14 Ecrire du texte dans un document OOoWriter
// C++
// Don't forget to add : using namespace com::sun::star::text;
// Don't forget to add : #include <com/sun/star/text/XTextDocument.hpp>
// Don't forget to add "com.sun.star.text.XTextDocument \" in the makefile
// Don't forget to add : #include <com/sun/star/text/XText.hpp>
// Don't forget to add "com.sun.star.text.XText \" in the makefile
//get an instance of the OOowriter document
Reference< XComponent > xWriterComponent = rComponentLoader->loadComponentFromURL(
OUString::createFromAscii("private:factory/swriter"),
OUString::createFromAscii("_blank"),
0,
Sequence < ::com::sun::star::beans::PropertyValue >());
Reference < XTextDocument > xTextDocument (xWriterComponent,UNO_QUERY);
Reference< XText > xText = xTextDocument->getText();
xText->setString(OUString::createFromAscii("Hello"));
Qu'arrive-t-il si l'on remplace la dernière ligne par les deux ci-dessous :
//Listing 15 More on setString Method (XText Interface)
// C++
xText->setString(OUString::createFromAscii("Hello"));
xText->setString(OUString::createFromAscii(" All around the world"));
Réponse : seulement : only « All around the world » est écrit. Cela fonctionne donc comme attendu : setString est setString. Ainsi si vous voulez mettre du texte derrière un autre texte une autre méthode doit être découverte.
Voir aussi com.sun.star.text.XTextDocument et com.sun.star.text.XText.
Gérer du texte avec l'interface XTextRange
L'interface XTextRange est capable de gérer le texte avec une méthode setString mais en gardant l'ancien texte. Par exemple si vous voulez ouvrir un document (contenant du texte) et ajouter du texte au tout début, faites comme ceci :
//Listing 16 Using the XTextRange Interface
// 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);
Reference< XText > xText = xTextDocument->getText();
Reference<XTextRange> xTextRange = xText->getStart();
xTextRange->setString(OUString::createFromAscii("Start here "));
La méthode getEnd() peut être aussi utilisée.
Voir aussi com.sun.star.text.TextRange.
Nous voyons ainsi comment insérer du texte au tout début et devinons comment l'insérer à la fin. Mais si vous voulez gérer la place exacte où vous voulez insérer votre texte alors l'interface XCursorText est votre amie.
L'interface XTextCursor
Le Developer's Guide indique : le code ci-dessus n'est pas flexible. Si vous voulez gagner en flexibilité, créez un curseur de texte qui est une zone de texte (text range) mouvante. Comme l'interface XTextCursor hérite de l'interface XTextRange, un curseur est un XTextRange et incorpore donc les méthodes d'un XTextRange:
com::sun::star::text::XText getText() com::sun::star::text::XTextRange getStart() com::sun::star::text::XTextRange getEnd() string getString() void setString( [in] string aString)
Comme déjà vu, la méthode setString est aussi disponible et fonctionne toujours de la même manière.
//Listing 17 More on setString Method (XTextCursor Interface)
// C++
//get an instance of the OOowriter document
Reference< XComponent > xWriterComponent = rComponentLoader->loadComponentFromURL(
OUString::createFromAscii("private:factory/swriter"),
OUString::createFromAscii("_blank"),
0,
Sequence < ::com::sun::star::beans::PropertyValue >());
Reference < XTextDocument > xTextDocument (xWriterComponent,UNO_QUERY);
Reference< XText > xText = xTextDocument->getText();
Reference< XTextCursor> xTextCursor = xText->createTextCursor();
xTextCursor->setString(OUString::createFromAscii("Hello"));
xTextCursor->setString(OUString::createFromAscii(" All around the world"));
Voir aussi com.sun.star.text.XTextCursor.
Une nouvelle question : qu'arrive-t-il si l'on utilise ce code mais sans instancier une deuxième fois la variable cursor entre deux appels setString ?
//Listing 18 More on setString Method (XTextCursor interface)
// C++
//get an instance of the OOowriter document
Reference< XComponent > xWriterComponent = rComponentLoader->loadComponentFromURL(
OUString::createFromAscii("private:factory/swriter"),
OUString::createFromAscii("_blank"),
0,
Sequence < ::com::sun::star::beans::PropertyValue >());
Reference < XTextDocument > xTextDocument (xWriterComponent,UNO_QUERY);
Reference< XText > xText = xTextDocument->getText();
Reference< XTextCursor> xTextCursor = xText->createTextCursor();
xTextCursor->setString(OUString::createFromAscii("Hello "));
xTextCursor = xText->createTextCursor(); // added
xTextCursor->setString(OUString::createFromAscii("All around the world"));
Réponse : « all around the worldHello » est écrit montrant que quand vous initialisez une interface XTextCursor, le curseur est toujours au début du document.
Voir aussi com.sun.star.text.XTextCursor, com.sun.star.text.XText et com.sun.star.text.XTextDocument.
Si vous voulez votre texte à la place adéquate, vous pouvez utiliser ce code :
//Listing 19 More on goRight Method (XTextCursor Interface)
// C++
//get an instance of the OOowriter document
Reference< XComponent > xWriterComponent = rComponentLoader->loadComponentFromURL(
OUString::createFromAscii("private:factory/swriter"),
OUString::createFromAscii("_blank"),
0,
Sequence < ::com::sun::star::beans::PropertyValue >());
Reference < XTextDocument > xTextDocument (xWriterComponent,UNO_QUERY);
Reference< XText > xText = xTextDocument->getText();
Reference< XTextCursor> xTextCursor = xText->createTextCursor();
xTextCursor->setString(OUString::createFromAscii("Hello "));
xTextCursor = xText->createTextCursor();
xTextCursor ->goRight(6,0); // added to move the cursor
xTextCursor->setString(OUString::createFromAscii("All around the world"));
où la méthode goRight est utilisée. Ce n'est pas la bonne façon de faire, instancier deux fois la variable xTextCursor. Mais ce code nous montrece que l'on peut faire avec un curseur : le déplacer. Bien sûr la méthode goLeft existe aussi. Le fichier IDL correspondant est montré maintenant :
//Listing 20 XTextCursor Interface
// IDL
module com { module sun { module star { module text {
interface XTextCursor: com::sun::star::text::XTextRange
{
/** sets the end of the position to the start.*/
[oneway] void collapseToStart();
/** sets the start of the position to the end.*/
[oneway] void collapseToEnd();
/** determines if the start and end positions are the same.*/
boolean isCollapsed();
/** moves the cursor the specified number of characters to the left.*/
boolean goLeft( [in] short nCount,
[in] boolean bExpand );
/** moves the cursor the specified number of characters to the right.*/
boolean goRight( [in] short nCount,
[in] boolean bExpand );
/** moves the cursor to the start of the text.*/
void gotoStart( [in] boolean bExpand );
/** moves the cursor to the end of the text.*/
void gotoEnd( [in] boolean bExpand );
/** moves or expands the cursor to a specified <type>TextRange</type>.*/
void gotoRange( [in] com::sun::star::text::XTextRange xRange,
[in] boolean bExpand );
};
}; }; }; };
Ce qui peut être réellement fait avec cette interface est donné dans le service <OpenOffice.org1.1_SDK>/idl/com/sun/star/text/TextCursor.idl. En fait l' introspection de XTextCursor me montre que les méthodes ci-dessous sont disponibles :
... boolean gotoPreviousParagraph([IN]boolean) boolean gotoNextParagraph([IN]boolean) boolean gotoEndOfParagraph([IN]boolean) boolean gotoStartOfParagraph([IN]boolean) boolean isEndOfParagraph() boolean isStartOfParagraph() boolean gotoStartOfWord([IN]boolean) boolean gotoEndOfWord([IN]boolean) boolean gotoPreviousWord([IN]boolean) boolean gotoNextWord([IN]boolean) boolean isEndOfWord() boolean isStartOfWord() boolean gotoEndOfSentence([IN]boolean) boolean gotoStartOfSentence([IN]boolean) boolean gotoPreviousSentence([IN]boolean) boolean gotoNextSentence([IN]boolean) boolean isEndOfSentence() boolean isStartOfSentence() void gotoRange([IN]com.sun.star.text.XTextRange,[IN]boolean) void gotoEnd([IN]boolean) void gotoStart([IN]boolean) boolean goRight([IN]short,[IN]boolean) boolean goLeft([IN]short,[IN]boolean) ...
Mais comme d'habitude tout n'est pas disponible d'un coup, il vous faudra des requêtes UNO_QUERY. Pour donner un exemple utilisant la méthode gotoEndOfWord, on commence par modifier le programme pour lire un fichier existant plutôt que de partir d'un fichier vierge et demandons une interface XWordCursor :
//Listing 21 Using the XWordCursor Service when loading a File
// C++
// Don't forget to add : using namespace com::sun::star::text;
// Don't forget to add : #include <com/sun/star/text/XTextDocument.hpp>
// Don't forget to add "com.sun.star.text.XTextDocument \" in the makefile
// 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
// Don't forget to add : #include <osl/file.hxx>
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);
Reference< XText > xText = xTextDocument->getText();
Reference< XTextCursor> xTextCursor = xText->createTextCursor();
Reference < XWordCursor > xWordCursor (xTextCursor,UNO_QUERY);
xWordCursor->gotoEndOfWord(0);
xWordCursor->setString(OUString::createFromAscii(" OK"));
Jetez un coup d'oeil sur le fichier XWordCursor.idl file pour apprendre ce qui est possible de faire avec la variable xWordCursor de l'exemple précédent. Pour aller plus loin aller à Translating OOoBasic programs into C++.
See also com.sun.star.text.XTextDocument and com.sun.star.text.XWordCursor.
La méthode insertString
Le Developer's Guide indique : le curseur peut être mis où cela est nécessaire et la chaîne de caractère positionnée après. Cela n'a aucun inconvénient. Après le positionnement de la chaîne, la chaîne insérée est toujours sélectionnée. Cela indique que du nouveau texte ne peut pas être inséré sans bouger le curseur une nouvelle fois. Ainsi la méthode la plus flexible pour insérer du texte à l'aide d'un curseur est la méthode insertString() de l'interface XText. Elle prend un XTextRange comme cible de la zone qui est remplacé durant l'insertion, une chaîne à insérer et un paramètre booléen qui détermine si le texte inséré doit être absorbé par le curseur après avoir été inséré. Le XTextRange pourrait être un XTextRange. Le XTextCursor est un XTextRange, ainsi il est utilisé ici:
void insertString( [in] com::sun::star::text::XTextRange xRange, [in] string aString, [in] boolean bAbsorb)
Pour insérer du texte séquentiellement le paramètre bAbsorb doit être positionné à false, ainsi le XTextRange se rétrécit à la fin de l'insertion. Si bAbsorb est true, la zone de texte sélectionne le nouveau texte inséré. La chaîne qui était sélectionnée par la zone de texte avant l'insertion est effacé..
Considerez l'utilisation de insertString() ci-dessosu :
//Listing 22 The insertString Method
//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);
Reference< XText > xText = xTextDocument->getText();
Reference< XTextCursor> xTextCursor = xText->createTextCursor();
// 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);
// Use the XSimpleText interface to insert a word at the current cursor
// location, over-writing
// the current selection (the third word selected above)
// a UNO query because xTextRange = xWordCursor->getStart(); doesn't work
Reference<XTextRange> xTextRange (xWordCursor,UNO_QUERY);
xText->insertString(xTextRange,OUString::createFromAscii("We are here "),true);
Ce programme prend le troisième mot et le remplace par «We are here». En premier lieu, je voulais utiliser quelque chose comme
xTextRange = xWordCursor->getStart();
pour retrouver l'interface XTextRange dont j'avais besoin pour le insertString. Cela fonctionnait seulement de manière partielle parceque l'information de sélection était perdue et je n'étais pas capable de remplacer le mot sélectionné à l'aide de l'instruction :
xWordCursor->gotoNextWord(true);
Accéder aux propriétés du curseur
Si l'on veut aller plus en avant et utiliser des caractères gras par exemple, on doit accéder aux propriétés des curseurs. Nous donnons un exemple qui part du code précédent et met le texte ajouter en gras. Cela peut être fait en remarquant que le code précédent insert un texte avec le dernier paramètre positionné à true. Cela signifie que la chaîne insérée est marquée. Si l'n change simplement une propriété du curseur, cela changera le texte. Ainsi seulement ajouter le code ci-dessous au listing 22 :
//Listing 23 Setting Text in bold
//C++
// Don't forget to add : using namespace com::sun::star::beans;
// Don't forget to add : #include <com/sun/star/beans/XPropertySet.hpp>
// Don't forget to add "com.sun.star.beans.XPropertySet \" in the makefile
Reference< XPropertySet> xCursorProps (xTextCursor,UNO_QUERY);
Any cw;
// Don't forget to add : using namespace com::sun::star::awt::FontWeight;
// Don't forget to add : #include <com/sun/star/awt/FontWeight.hpp>
// Don't forget to add "com.sun.star.awt.FontWeight \" in the makefile
cw <<= BOLD;
xCursorProps->setPropertyValue(OUString::createFromAscii("CharWeight"),cw);
met « we are here » en gras. Comme déjà vu ici nous sommes de nouveau confontés à des constantes. BOLD est une constante. Elle provient du fichier IDL suivant :
//Listing 24 Constants to set the Font Weight
//IDL
module com { module sun { module star { module awt {
constants FontWeight
{
/** The font weight is not specified/known. */
const float DONTKNOW = 0.000000;
/** specifies a 50% font weight. */
const float THIN = 50.000000;
/** specifies a 60% font weight. */
const float ULTRALIGHT = 60.000000;
/** specifies a 75% font weight. */
const float LIGHT = 75.000000;
/** specifies a 90% font weight. */
const float SEMILIGHT = 90.000000;
/** specifies a normal font weight. */
const float NORMAL = 100.000000;
/** specifies a 110% font weight. */
const float SEMIBOLD = 110.000000;
/** specifies a 150% font weight. */
const float BOLD = 150.000000;
/** specifies a 175% font weight. */
const float ULTRABOLD = 175.000000;
/** specifies a 200% font weight. */
const float BLACK = 200.000000;
};
}; }; }; };
Et les commentaires dans le programme indiquent comment utiliser ces constantes.
Voir aussi com.sun.star.beans.XPropertySet et com.sun.star.awt.FontWeight
Accéder à un signet
Si dans un document je met (avec les menus) un signet nommé « Signet1 ». Ensuite, j'essaie d'atteindre ce signet avec un programme et d'ajouter du text à cette place. Cela peut être fait avec ce morceau de code :
//Listing 25 Atteindre un signet nommé
// C++
// Don't forget to add : #include <com/sun/star/text/XBookmarksSupplier.hpp>
// Don't forget to add "com.sun.star.text.XBookmarksSupplier \" in the makefile
Reference< XBookmarksSupplier> xBookmarksSupplier (xTextDocument,UNO_QUERY);
// Don't forget to add : using namespace com::sun::star::container;
Reference< XNameAccess > xNameAccess = xBookmarksSupplier->getBookmarks();
Any bookmark = xNameAccess->getByName(OUString::createFromAscii("Signet1"));
// Don't forget to add : #include <com/sun/star/text/XTextContent.hpp>
// Don't forget to add "com.sun.star.text.XTextContent \" in the makefile
Reference< XTextContent >xTextContent (bookmark,UNO_QUERY);
Reference< XTextRange > xTextRange2 = xTextContent->getAnchor();
xText->insertString(xTextRange2,
OUString::createFromAscii("My bookmark is here "),true);
Notez que Robert MEAILLE a posté une procédure pour réaliser cette tâche ici : oooforum
Voir aussi com.sun.star.text.XBookmarksSupplier et com.sun.star.text.XTextContent.
J'explique comment utiliser cette procédure en commençant par l'expliquer et ensuite en l'utilisant.
//Listing 26 Procedure pour atteindre un signet nommé
// C++
/*****************************************************************************
*****************************************************************************
*
* Simple client application for MailMerge, acces Boomark, print and close file.
* by Robert MEAILLE 01/12/2005
*
*****************************************************************************
*****************************************************************************/
void signet( OUString nameBookmark, OUString texte, Reference< XComponent > xComponent , long type )
{
Reference< XBookmarksSupplier > xBookmarksSupplier (xComponent, UNO_QUERY);
if( !xBookmarksSupplier.is() )
{
printf( "XBookmarksSupplier Not successfully instanciated\n" );
}
Reference< XNameAccess > xNamedBookmarks = xBookmarksSupplier->getBookmarks();
Any xBookmark = xNamedBookmarks->getByName( nameBookmark ) ;
Reference< XTextContent > rBookmark (xBookmark, UNO_QUERY);
Reference< XTextRange > xTextRange = rBookmark->getAnchor() ; //->getStart() ;
Reference< XText > xText = xTextRange->getText() ;
Reference< XTextCursor > xTextCursor = xText->createTextCursorByRange( xTextRange ) ;
if( type == 0 ) // Insertion d'un texte au niveau d'un signet
xText->insertString( xTextRange, texte, 1 ) ;
else // Insertion d'un fichier niveau d'un signet
{
Reference< XDocumentInsertable > xDocumentInsertable (xTextCursor, UNO_QUERY);
// Don't forget to add : #include <com/sun/star/document/XDocumentInsertable.hpp>
// Don't forget to add "com.sun.star.document.XDocumentInsertable \" in the makefile
// Don't forget to add : using namespace com::sun::star::document;
xDocumentInsertable->insertDocumentFromURL( texte,
Sequence < :: com::sun::star::beans::PropertyValue >() ) ;
}
}
(Voir aussi com.sun.star.text.XTextContent, com.sun.star.text.XTextRange, com.sun.star.text.XText, com.sun.star.text.XTextCursor et com.sun.star.document.XDocumentInsertable).
Remplacez le Listing 25 avec le Listing 26 et le Listing 27 ci-après, et cela fonctionne comme le premier code présenté :
//Listing 27 Using a Bookmark with R. MEAILLE's Code
// C++
....
signet( OUString::createFromAscii("Signet1"),
OUString::createFromAscii("My bookmark is here "),
xWriterComponent , 0);
....
Tableaux dans un document Writer
Pour insérer un tableau dans un document Writer supposé ouvert, avec un curseur d'écriture positionné où vous voulez insérer ce tableau, nous montrons maintenant comment insérer un tableau de 4 lignes et 4 colonnes :
//Listing 28 Insérer un Tableau dans un document OOoWriter
// C++
// Saut à la fin du texte
xTextCursor->gotoEnd(false);
// Create a new text table from the document's factory
// Don't forget to add : #include <com/sun/star/text/XTextTable.hpp>
// Don't forget to add "com.sun.star.text.XTextTable \" in the makefile
// getting MSF of the document
Reference<XMultiServiceFactory> oDocMSF (xTextDocument,UNO_QUERY);
Reference <XTextTable> xTable (oDocMSF->createInstance(
OUString::createFromAscii("com.sun.star.text.TextTable")),UNO_QUERY);
if (!xTable.is()) {
printf("Erreur creation XTextTable interface !\n");
return 1;
}
// Specify that we want the table to have 4 rows and 4 columns
xTable->initialize(4, 4);
xTextRange = xText->getEnd();
// Don't forget to add : #include <com/sun/star/text/XTextContent.hpp>
// Don't forget to add "com.sun.star.text.XTextContent \" in the makefile
Reference <XTextContent>xTextContent (xTable,UNO_QUERY);
// Insert the table into the document
xText->insertTextContent(xTextRange, xTextContent,(unsigned char) 0);
Vous pouvez voir ci-dessous le tableau vide qui sera inséré dans votre document :
|
|
|
|
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Comme vous pouvez le constater l'interface XTextTable est votre ami. Voyons en détail les méthodes fournies par cette interface à travers le fichier IDL correspondant :
//Listing 29 The XTextTable Service
// IDL
module com { module sun { module star { module text {
interface XTextTable: com::sun::star::text::XTextContent
{
void initialize( [in] long nRows,
[in] long nColumns );
com::sun::star::table::XTableRows getRows();
com::sun::star::table::XTableColumns getColumns();
com::sun::star::table::XCell getCellByName( [in] string aCellName );
sequence<string> getCellNames();
com::sun::star::text::XTextTableCursor createCursorByCellName( [in] string aCellName );
};
}; }; }; };
En lisant ce listing, on voit au moins deux autres interfaces intéressantes : XCell et XTextTableCursor.
//Listing 30 The XTextTableCursor Service
// IDL
module com { module sun { module star { module text {
interface XTextTableCursor: com::sun::star::uno::XInterface
{
string getRangeName();
boolean gotoCellByName( [in] string aCellName,
[in] boolean bExpand );
boolean goLeft( [in] short nCount,
[in] boolean bExpand );
boolean goRight( [in] short nCount,
[in] boolean bExpand );
boolean goUp( [in] short nCount,
[in] boolean bExpand );
boolean goDown( [in] short nCount,
[in] boolean bExpand );
void gotoStart( [in] boolean bExpand );
void gotoEnd( [in] boolean bExpand );
boolean mergeRange();
boolean splitRange( [in] short nCount,
[in] boolean bHorizontal );
};
}; }; }; };
On sait maintenant comment naviguer à travers le tableau. Dans notre exemple ci-dessous, on va utiliser la méthode getCellByName pour atteindre une cellule particulière et obtenir l'interface XCell correspondante.
//Listing 31 The XCell Service
// IDL
module com { module sun { module star { module table {
interface XCell: com::sun::star::uno::XInterface
{
string getFormula();
void setFormula( [in] string aFormula );
double getValue();
void setValue( [in] double nValue );
com::sun::star::table::CellContentType getType();
long getError();
};
}; }; }; };
Nous donnons maintenant un programme pour changer les couleurs de fond dans le tableau et pour écrire quelque chose dans les cellules. Il est nécessaire d'ajouter le code du Listing 28 si vous désirez un fonctionnement complet.
//Listing 32 Changer les couleurs de fond et écrire dans les cellules
// C++
// Get the property set of the text table
// Don't forget to add : using namespace com::sun::star::beans;
// Don't forget to add : #include <com/sun/star/beans/XPropertySet.hpp>
// Don't forget to add "com.sun.star.beans.XPropertySet \" in the makefile
Reference<XPropertySet> xTableProps (xTable,UNO_QUERY);
Any prop;
prop <<= (sal_Bool)false;
xTableProps->setPropertyValue(OUString::createFromAscii("BackTransparent"),prop);
prop <<= (long)0x0000FF; // color blue
xTableProps->setPropertyValue(OUString::createFromAscii("BackColor"),prop);
// I want to change the first row color
// Don't forget to add : using namespace com::sun::star::table;
// Don't forget to add : #include <com/sun/star/table/XTableRows.hpp>
// Don't forget to add "com.sun.star.table.XTableRows \" in the makefile
Reference<XTableRows> xTableRows = xTable->getRows();
Reference<XIndexAccess> theRows (xTableRows,UNO_QUERY);
Reference<XPropertySet> xRowProps (theRows->getByIndex((short)0),UNO_QUERY);
prop <<= (sal_Bool)false;
xRowProps->setPropertyValue(OUString::createFromAscii("BackTransparent"),prop);
prop <<= (long)0x000099;
xRowProps->setPropertyValue(OUString::createFromAscii("BackColor"),prop);
// it's time to add some text now
Reference<XCell> xCell = xTable->getCellByName(OUString::createFromAscii("A1"));
xText = Reference<XText>(xCell,UNO_QUERY);
xTextCursor = xText->createTextCursor();
xTextCursor->setString(OUString::createFromAscii("Titre1"));
xCell = xTable->getCellByName(OUString::createFromAscii("A2"));
xCell->setValue(17);
xCell = xTable->getCellByName(OUString::createFromAscii("A3"));
xCell->setValue(14);
xCell = xTable->getCellByName(OUString::createFromAscii("A4"));
xCell->setFormula(OUString::createFromAscii("=sum(<A2>|<A3>)"));
xCell = xTable->getCellByName(OUString::createFromAscii("B1"));
xText = Reference<XText>(xCell,UNO_QUERY);
xTextCursor = xText->createTextCursor();
Reference<XPropertySet> oCPS(xTextCursor,UNO_QUERY);
prop <<= (long)0xFF0000; // color red
oCPS->setPropertyValue(OUString::createFromAscii("CharColor"),prop);
xTextCursor->setString(OUString::createFromAscii("Titre2"));
xCell = xTable->getCellByName(OUString::createFromAscii("B2"));
xCell->setValue(20);
xCell = xTable->getCellByName(OUString::createFromAscii("B3"));
xCell->setValue(5);
xCell = xTable->getCellByName(OUString::createFromAscii("B4"));
xCell->setFormula(OUString::createFromAscii("=<B2>*<B3>"));
Le tableau ci-dessous nous montre le résultat correspondant avec un tel code :
Titre1 |
Titre2 |
|
|
---|---|---|---|
17 |
20 |
|
|
14 |
5 |
|
|
31 |
100 |
|
|
Voir aussi com.sun.star.beans.XPropertySet et com.sun.star.table.XTableRows.
Traduire le code Java en C++
On commence avec un exemple trouvé dans un OOoForum sous le nom : Setting the page properties/margins directly from java Voici le code java :
//Listing 114
// Java
// create new writer document and get text, then manipulate text
XComponent xWriterComponent = newDocComponent("swriter");
XTextDocument xTextDocument = (XTextDocument)UnoRuntime.queryInterface(XTextDocument.class,xWriterComponent);
// Access the text document's multi service factory, which we will need for most of the
// following examples
mxDocFactory = (XMultiServiceFactory) UnoRuntime.queryInterface
(XMultiServiceFactory.class,xTextDocument);
XText xText = xTextDocument.getText();
// create a text cursor from the cells XText interface
XTextCursor xTextCursor = xText.createTextCursor();
// Get the property set of the cell's TextCursor
XPropertySet xTextCursorProps = (XPropertySet)UnoRuntime.queryInterface
(XPropertySet.class,xTextCursor);
// Page Style name
String pageStyleName= xTextCursorProps.getPropertyValue("PageStyleName").toString();
// Get the StyleFamiliesSupplier interface of the document
XStyleFamiliesSupplier xSupplier = (XStyleFamiliesSupplier) UnoRuntime.queryInterface
(XStyleFamiliesSupplier.class,xTextDocument);
// Use the StyleFamiliesSupplier interface to get the XNameAccess interface of the
// actual style families
XNameAccess xFamilies = (XNameAccess)UnoRuntime.queryInterface(XNameAccess.class,
xSupplier.getStyleFamilies());
// Access the 'PageStyles' Family
XNameContainer xFamily = (XNameContainer) UnoRuntime.queryInterface
(XNameContainer.class,xFamilies.getByName("PageStyles"));
// Insert the newly created style into the PageStyles family
XStyle xStyle= (XStyle) UnoRuntime.queryInterface(XStyle.class,xFamily.getByName
(pageStyleName));
// Get the property set of the TextCursor
XPropertySet xStyleProps = (XPropertySet)UnoRuntime.queryInterface
(XPropertySet.class,xStyle);
xStyleProps.setPropertyValue("LeftMargin",new Short((short)1200));
xStyleProps.setPropertyValue("RightMargin",new Short((short)1200));
xStyleProps.setPropertyValue("BottomMargin",new Short((short)1200));
En C++ cela donne :
//Listing 115
// C++
// create new writer document and get text, then manipulate text
// N'oubliez pas d'ajouter : using namespace com::sun::star::text;
// N'oubliez pas d'ajouter : #include <com/sun/star/text/XTextDocument.hpp>
// N'oubliez pas d'ajouter "com.sun.star.text.XTextDocument \" in the makefile
// N'oubliez pas d'ajouter : using namespace com::sun::star::beans;
// N'oubliez pas d'ajouter : #include <com/sun/star/beans/XPropertySet.hpp>
// N'oubliez pas d'ajouter "com.sun.star.beans.XPropertySet \" in the makefile
// N'oubliez pas d'ajouter : using namespace com::sun::star::style;
// N'oubliez pas d'ajouter : #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
// N'oubliez pas d'ajouter "com.sun.star.style.XStyleFamiliesSupplier \" in the makefile
// N'oubliez pas d'ajouter : using namespace com::sun::star::container;
// N'oubliez pas d'ajouter : #include <com/sun/star/container/XNameContainer.hpp>
// N'oubliez pas d'ajouter "com.sun.star.container.XNameContainer \" in the makefile
// N'oubliez pas d'ajouter : #include <com/sun/star/style/XStyle.hpp>
// N'oubliez pas d'ajouter "com.sun.star.style.XStyle \" in the makefile
// the first line cannot be translated : already done in our main()
// XComponent xWriterComponent = newDocComponent("swriter");
Reference < XTextDocument > xTextDocument (xWriterComponent,UNO_QUERY);
// Access the text document's multi service factory, which we will need for most of the
// following examples
Reference< XMultiServiceFactory > mxDocFactory(xTextDocument,UNO_QUERY);
Reference< XText > xText = xTextDocument->getText();
// create a text cursor from the cells XText interface
Reference< XTextCursor > xTextCursor = xText->createTextCursor();
// Get the property set of the cell's TextCursor
Reference< XPropertySet > xTextCursorProps(xTextCursor,UNO_QUERY);
// Page Style name
//*** I add a intermediate variable because of Any type returned by getPropertyValue
Any pageStyleName2 = xTextCursorProps->getPropertyValue
(OUString::createFromAscii("PageStyleName"));
OUString pageStyleName;
pageStyleName2 >>= pageStyleName ;
// Get the StyleFamiliesSupplier interface of the document
Reference< XStyleFamiliesSupplier > xSupplier(xTextDocument,UNO_QUERY);
// Use the StyleFamiliesSupplier interface to get the XNameAccess interface of the
// actual style families
Reference< XNameAccess > xFamilies(xSupplier->getStyleFamilies(),UNO_QUERY);
// Access the 'PageStyles' Family
Reference< XNameContainer > xFamily(xFamilies->getByName
(OUString::createFromAscii("PageStyles")),UNO_QUERY);
// Insert the newly created style into the PageStyles family
Reference< XStyle > xStyle(xFamily->getByName(pageStyleName),UNO_QUERY);
// Get the property set of the TextCursor
Reference< XPropertySet > xStyleProps(xStyle,UNO_QUERY);
Any lm, rm, bm;
lm<<=(short)1200; rm<<=(short)1200; bm<<=(short)1200;
xStyleProps->setPropertyValue(OUString::createFromAscii("LeftMargin"),lm);
xStyleProps->setPropertyValue(OUString::createFromAscii("RightMargin"),rm);
xStyleProps->setPropertyValue(OUString::createFromAscii("BottomMargin"),bm);
Ma compétence sur le type "ANY" n'est pas assez complète, alors je ne trouve pas de moyen direct d'utiliser "Any" autre qu'en utilisant des variables intermédiaires. Voyez les trois dernières lignes par exemple.
Aller plus loin avec l'Inspector Java
The new object inspector est capable de générer du code Java, C++ ou OOoBasic. Dans le but de tester son aptitude à générer du code C++, nous allons l'utiliser dans le problème suivant : obtenir le texte sélectionné d'un document Writer. Voici une copie d'écran :
Voir aussi le problème correspondant en OOoBasic ici (en anglais).
Arbre IDL : J'appellerai un arbre IDL dans ce document l'arbre de parcours à travers les methods/properties/interfaces/services. En d'autres termes, le new object inspector nous permet de traverser un arbre IDL de haut en bas. Le haut est en général le document (mais pas forcément), et le bas est la méthode que l'on veut invoquer (invoke).
Après lancement du new object inspector, on peut traverser l'arbre IDL comme décrit ci-dessous et aussi montré (en partie) dans la copie d'écran juste après.
MyDocument ->methods ->com.sun.star.frame.XController getCurrentController() ->xController->methods -> Any getSelection ->XInterface ->methods -> Any getByIndex -> XTextRange ->getString
Voici en partie une copie d'écran pour l'arbre IDL :
Le code C++ correspondant automatiquement généré est :
#include "com/sun/star/view/XSelectionSupplier.hpp"
#include "rtl/ustring.hxx"
#include "sal/config.h"
#include "sal/types.h"
namespace css = com::sun::star;
using namespace rtl;
//...
void codesnippet(const css::uno::Reference<css::uno::XInterface>& _oUnoEntryObject ){{
css::uno::Reference<css::frame::XModel> xModel( _oUnoEntryObject, css::uno::UNO_QUERY_THROW);
css::uno::Reference<css::frame::XController> xController = xModel->getCurrentController();
css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier( xController, css::uno::UNO_QUERY_THROW);
css::uno::Reference<XInterface> oSelection = xSelectionSupplier->getSelection();
css::uno::Reference<css::container::XIndexAccess> xIndexAccess( oSelection, css::uno::UNO_QUERY_THROW);
css::uno::Reference<XInterface> oIndex = xIndexAccess->getByIndex(0);
css::uno::Reference<css::text::XTextRange> xTextRange( oIndex, css::uno::UNO_QUERY_THROW);
OUString sString = xTextRange->getString();
}
//...
Ce code ne fonctionne malheureusement pas correctement à cause de la mauvaise façon de gérer le type "Any" dans l'Inspcteur Java (c'est un code Java en développement qui est destiné à être porté en C++ un jour) :
void codesnippet(const css::uno::Reference<css::uno::XInterface>& _oUnoEntryObject ){
css::uno::Reference<css::frame::XModel> xModel( _oUnoEntryObject, css::uno::UNO_QUERY_THROW);
css::uno::Reference<css::frame::XController> xController = xModel->getCurrentController();
css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier( xController, css::uno::UNO_QUERY_THROW);
// css::uno::Reference<XInterface> oSelection = xSelectionSupplier->getSelection();
Any Selection = xSelectionSupplier->getSelection();
Reference<XInterface> oSelection(Selection,css::uno::UNO_QUERY_THROW);
css::uno::Reference<css::container::XIndexAccess> xIndexAccess( oSelection, css::uno::UNO_QUERY_THROW);
// css::uno::Reference<XInterface> oIndex = xIndexAccess->getByIndex(0);
Any Index = xIndexAccess->getByIndex(0);
css::uno::Reference<XInterface> oIndex(Index,css::uno::UNO_QUERY_THROW);
css::uno::Reference<css::text::XTextRange> xTextRange( oIndex, css::uno::UNO_QUERY_THROW);
OUString sString = xTextRange->getString();
OString OStr = OUStringToOString( sString, RTL_TEXTENCODING_ASCII_US );
printf( "OUStr was : %s\n", OStr.pData->buffer );
}
Vous pouvez voir comment le type Any est géré en deux étapes. J'ai mis le vieux code en commentaire et ajouté un peu de code pour afficher le résultat du texte sélectionné. Pour retrouver le document ouvert par défaut, on ajoute simplement ce code :
main( ) {
//retrieve an instance of the remote service manager
Reference< XMultiServiceFactory > xServiceManager;
xServiceManager = ooConnect();
if( xServiceManager.is() ){
printf( "Connected sucessfully to the office\n" );
}
//get the desktop service using createInstance returns an XInterface type
Reference< XInterface > Desktop = xServiceManager->createInstance(
OUString::createFromAscii( "com.sun.star.frame.Desktop" ));
//query the XDesktop Interface
Reference< XDesktop > xDesktop (Desktop, UNO_QUERY);
Reference< XComponent > xcomponent = xDesktop->getCurrentComponent();
// call Inspector code
codesnippet(xcomponent);
return 0;
}
Tous les problèmes rencontrés dans cette section m'ont décidé d'écrire un chapitre séparé sur the new object inspector et le C++.
Retour à la page d'accueil
Page d'accueil du développement C++ à l'aide du SDK
Voir aussi
- Text Documents in Developer's Guide
- C++ and UNO tutorial
- Using OOoBasic
- Writing a Program to Control OpenOffice.org, by Franco Pingiori — Part 1 and Part 2, Linux Journal
- Text cursor in OOoBasic
- The new Object Inspector
- Discussion_of_Bibliographic_-_Writer_proposals