URL: https://linuxfr.org/users/pied/journaux/%C3%A9criture-dune-macro-dans-openofficeorg Title: Écriture d'une macro dans OpenOffice.org Authors: Pinaraf Date: 2010年09月22日T01:04:36+02:00 Tags: openoffice Score: 13 Cher journal Avant d'aller plus loin, je te conseille très sincèrement de prendre commande de quelques kilogrammes d'aspirine. Tu vas avoir tellement mal à la tête... À la base, je voulais écrire un journal pour montrer qu'il est simple de faire des macros dans OpenOffice.org. Je ne suis pas magicien, je ferai donc un journal pour expliquer comment j'ai écrit une macro dans OpenOffice.org... Post-scriptum : l'indentation et Linuxfr ne sont pas très copains apparemment, vous m'en voyez navré... 0) L'objectif La problématique est simple : j'ai déjà du, à plusieurs reprises, copier un tableau de calc dans writer. Et que ça soit avec un objet calc, une image ou autre, le résultat ne m'a jamais satisfait. Texte flou, mal gérable depuis le traitement de texte... Une hécatombe. La seule alternative : tout copier, cellule par cellule... Hé oui, c'est fastidieux... Ainsi, j'ai décidé de faire comme dans l'ancien temps où j'écrivais des macros Word pour contourner les restrictions d'utilisation du système au lycée : écrire une macro OpenOffice.org pour faire ce travail à ma place (et la proposer en addon sur le site des extensions d'OpenOffice.org). Le fonctionnement de la macro, d'un point de vue utilisateur, sera dans un premier temps le suivant : - sélection dans calc du tableau - lancement de la macro : un nouveau document writer est créé contenant notre beau tableau mis en forme et tout et tout... OpenOffice.org est programmable en plusieurs langages de programmation, mais je ne me focaliserai ici que sur le StarBasic, simple et surtout ne dépendant pas d'un interpréteur externe... 1) Pré-requis techniques - Savoir programmer en Basic - Avoir beaucoup de patience - Comprendre la programmation orientée objet, la notion de composants et d'interfaces - Avoir une patience incalculable - OpenOffice.org, un navigateur web, un moteur de recherche et des nerfs solides - Recommandé : le livre Programmation OpenOffice.org, éditions Eyrolles 2) Première étape : construction d'une macro basique Une fonctionnalité très très utile de Microsoft Office est l'enregistreur de macros. Essayez même pas l'enregistreur de macros d'OpenOffice.org, il est lamentable... De plus, il n'y a pas de complétion dans le code, et rien pour aider à l'exploration de l'API. Vous devriez, si vous tenez à vos neurones, installer XRay : il s'agit d'un outil permettant d'explorer à l'exécution les propriétés et méthodes d'un objet. La première étape est la réalisation d'une macro qui va créer un document writer quand la sélection de l'utilisateur sera un ensemble de cellules. Cela permet de voir des premières manipulations de l'API... Pour créer la macro, il suffit d'aller sur le menu Outils, puis Macros, Gérer les macros et sélectionner Basic. Un menu vous permettra de créer un module (c'est-à-dire une sorte de bibliothèque de macros), que vous ouvrez alors avec l'horrible éditeur Basic d'OpenOffice.org (moins horrible que l'éditeur de VBA quand même). Voici à quoi ressemble cette première macro : Sub CopyToWriter £spaces£ £/spaces£Dim document as Object £spaces£ £/spaces£Dim textDocument As Object £spaces£ £/spaces£Dim sel as Object £spaces£ £/spaces£Dim propertiesDoc() £spaces£ £/spaces£document = thisComponent £spaces£ £/spaces£sel = document.currentSelection £spaces£ £/spaces£ £spaces£ £/spaces£if sel.supportsService("com.sun.star.table.CellRange") then £spaces£ £/spaces£textDocument = StarDesktop.LoadComponentFromURL("private:factory/swriter", "_blank", 0, propertiesDoc) £spaces£ £/spaces£else £spaces£ £/spaces£MsgBox "Select a range of cells" £spaces£ £/spaces£end if End Sub Derrière le code de cette macro, pas de magie : il faut, hélas, lire la doc. Dans mon cas, j'ai utilisé le livre sur l'API d'OpenOffice.org, mais vous trouverez moultes informations sur [http://api.openoffice.org](http://api.openoffice.org) et dans des documents comme [http://api.openoffice.org/basic/man/tutorial/tutorial.pdf](http://api.openoffice.org/basic/man/tutorial/tutorial.pdf) ... La variable document est ici un objet référençant le document (Calc) courant. sel contient une référence à la sélection de l'utilisateur dans le document, textDocument est le document Writer créé, et propertiesDoc() est un tableau vide, parce qu'il faut bien donner des paramètres vides des fois... Plus sérieusement, StarDesktop est une sorte de représentation de l'instance globale d'OpenOffice.org, permettant de créer des documents, d'en ouvrir... Cet objet est document à l'adresse [http://api.openoffice.org/docs/common/ref/com/sun/star/frame(...)](http://api.openoffice.org/docs/common/ref/com/sun/star/frame/Desktop.html) mais une version plus pratique est disponible sur [http://wiki.services.openoffice.org/wiki/Documentation/BASIC(...)](http://wiki.services.openoffice.org/wiki/Documentation/BASIC_Guide/StarDesktop) . Le test sur l'objet sel illustre bien, je pense, la notion de service : l'objet sel est inconnu, il pourrait très bien être un objet image, un graphique... Dans chacun de ces cas, d'autres services se retrouveront alors supportés par l'objet. On demande donc ici une zone de cellules. Nour allons donc passer à l'étape suivante, plus amusante déjà, créer un tableau de NxM cellules dans le document texte. 3) Insérer un tableau dans du texte Pour insèrer un tableau dans du texte, il faut tout d'abord créer l'objet correspondant au tableau, puis insérer cet objet dans le texte. Décomposons donc ces deux étapes... a) Création de l'objet tableau C'est l'étape la plus simple : un tableau est «lié» au document, on le crée à partir de ce dernier à l'aide d'un appel à la fonction createInstance. On obtient alors un tableau que l'on initialise avec la fonction initialize, prenant en paramètres le nombre de lignes et de colonnes. Cela donne le code suivant, que j'ai déporté dans une fonction : function CreateTable(document As Object, columns, rows) as Object £spaces£ £/spaces£dim table As Object £spaces£ £/spaces£table = document.createInstance("com.sun.star.text.TextTable") £spaces£ £/spaces£table.initialize(rows, columns) £spaces£ £/spaces£CreateTable = table end function C'est donc un code relativement simple... b) Insertion de la table dans le document La manipulation d'un bloc texte se fait à travers un concept similaire à ce que voit l'utilisateur : le curseur. Ainsi, toute manipulation, qu'il s'agisse d'une insertion, suppression ou modification de texte, passe à travers le même objet. Nous allons donc, en toute logique, y trouver la méthode pour insérer un objet TextTable. Sub InsertTable (document As Object, table As Object) £spaces£ £/spaces£dim docText as Object £spaces£ £/spaces£dim cursor as object £spaces£ £/spaces£docText = document.Text £spaces£ £/spaces£cursor = docText.createTextCursor £spaces£ £/spaces£cursor.gotoNextParagraph(False) £spaces£ £/spaces£docText.insertTextContent(cursor, table, False) End Sub Encore une fois, cette API est documentée, mais l'éditeur de macros ne vous sera d'aucun secours... 4) Continuer le code Nous pouvons maintenant mélanger ces bouts de code et préparer la suite : copier les cellules et leur mise en forme. Voici à quoi ressemble maintenant la nouvelle version du bloc principal de la méthode CopyToWriter : if sel.supportsService("com.sun.star.table.CellRange") then £spaces£ £/spaces£textDocument = StarDesktop.LoadComponentFromURL("private:factory/swriter", "_blank", 0, propertiesDoc) £spaces£ £/spaces£textTable = CreateTable(textDocument, sel.RangeAddress.EndColumn - sel.RangeAddress.StartColumn + 1, sel.RangeAddress.EndRow - sel.RangeAddress.StartRow + 1) £spaces£ £/spaces£textTable.HeaderRowCount = 0 £spaces£ £/spaces£InsertTable(textDocument, textTable) £spaces£ £/spaces£for x = 0 to sel.RangeAddress.EndRow - sel.RangeAddress.StartRow £spaces£ £/spaces£for y = 0 to sel.RangeAddress.EndColumn - sel.RangeAddress.StartColumn £spaces£ £/spaces£textCell = textTable.getCellByPosition(y, x) £spaces£ £/spaces£calcCell = sel.getCellByPosition(y, x) £spaces£ £/spaces£copyCell(calcCell, textCell) £spaces£ £/spaces£next y £spaces£ £/spaces£next x £spaces£ £/spaces£else £spaces£ £/spaces£MsgBox "Select a range of cells" £spaces£ £/spaces£end if Nous créons et insérons le tableau dans le nouveau document texte, puis nous parcourons chaque ligne et chaque colonne : à chaque fois, on obtient deux objets correspondant aux cellules Calc et Writer, et nous appelons sur ces cellules une mystérieuse fonction copyCell, que je m'empresse de vous définir. 5) La vicieuse fonction copyCell J'ai passé beaucoup de temps dans XRay pour trouver une méthode simple et efficace pour réaliser cette copie. J'ai découvert des horreurs dans l'API d'OpenOffice.org (un service qui me semblait être parfaitement adapté pour mon besoin, mais implémenté par personne à part par une classe obscure de 2008 documentée en allemand (!)). J'ai passé énormément de temps, mais j'ai trouvé une solution relativement maintenable, que voici... - Itérer sur les paragraphes de la cellule de départ - Itérer sur les portions dans chaque paragraphe - Itérer sur les propriétés de cette portion - Si cette propriété est valide sur la cellule de destination (si elle existe), alors l'appliquer. Pour bien comprendre l'idée ici, il est nécessaire de savoir comment marche la représentation du texte dans la plupart des solutions que je connaisse (HTML, OpenDocument, OpenOffice.org, KOffice...) Pour simplifier, je vais «parler» en HTML/CSS. Un paragraphe, balise , est constitué d'un flot de texte uniforme, par défaut d'un seul style. Pour insérer un élément d'un style différent, on a recours à une balise . Au sein d'une même balise span, tout le texte aura le même style. Dans le cas du traitement de textes, les balises span ne peuvent être imbriquées. On a donc des «portions» de texte, mono-style, sur lesquelles toutes les propriétés sont à la même valeur. Exemple : te_s_t est stocké en quatre portions de texte : t, puis e souligné, puis souligné en italique et enfin t en souligné. À titre purement informatif, voici le code correspondant à ce mécanisme : sourceCursor = source.createTextCursor £spaces£ £/spaces£sourceText = sourceCursor.Text £spaces£ £/spaces£listeParag = sourceText.createEnumeration £spaces£ £/spaces£Do While listeParag.hasMoreElements £spaces£ £/spaces£parag = listeParag.nextElement £spaces£ £/spaces£listeParts = parag.createEnumeration £spaces£ £/spaces£Do While listeParts.hasMoreElements £spaces£ £/spaces£part = listeParts.nextElement £spaces£ £/spaces£sourceCursor.gotoRange(part.End, False) £spaces£ £/spaces£propsetsource() = sourceCursor.propertySetInfo.properties £spaces£ £/spaces£propsetdest() = destCursor.propertySetInfo.properties £spaces£ £/spaces£For i = 0 To UBound(propsetsource) £spaces£ £/spaces£propertyName = propsetsource(i).Name £spaces£ £/spaces£For j = 0 To UBound(propsetdest) £spaces£ £/spaces£if propsetdest(j).Name = propertyName Then £spaces£ £/spaces£destCursor.setPropertyValue(propertyName, sourceCursor.getPropertyValue(propertyName)) £spaces£ £/spaces£Goto NextProperty £spaces£ £/spaces£End If £spaces£ £/spaces£Next j £spaces£ £/spaces£NextProperty: £spaces£ £/spaces£Next i £spaces£ £/spaces£destCursor.String = part.String £spaces£ £/spaces£destCursor.gotoEnd(False) £spaces£ £/spaces£Loop £spaces£ £/spaces£Loop 6) Conclusion J'avoue, je craque, et mon canal carpien n'aidant pas, j'ai un peu «bâclé» l'explication de l'API d'OpenOffice.org. L'API en elle même n'est pas forcément compliquée, mais il y a souvent des problèmes pour trouver ce que l'on cherche. La documentation est assez complète, mais sans un bon outil pour écrire les macros, c'est une tâche réellement fastidieuse. XRay ([http://wiki.services.openoffice.org/wiki/Extensions_developm(...)](http://wiki.services.openoffice.org/wiki/Extensions_development_basic#X-Ray_tool)) est là pour vous aider un peu : on lance cet outil en lui donnant un objet, et il est capable d'en lister les propriétés et de les explorer de manière avancée... Mais cela serait tellement plus simple si c'était intégré dans l'IDE... Je m'en vais terminer ma macro et en faire un addon OpenOffice.org complet, installable aisément. Je pense que cette manipulation justifiera un journal à elle seule, ne serait-ce que pour annoncer l'addon. À venir dans de prochains épisodes : - trackball ou souris verticale, comment lutter contre le syndrome du canal carpien ? - réalisation d'addons OpenOffice.org en Java (avec des fonctionnalités inédites dans une suite bureautique, que je tenterai d'intégrer ensuite à KOffice) À la prochaine fois pour d'autres aventures donc, et en attendant, n'oubliez pas : le libre, sans développeurs du dimanche (ok, on est mardi, et alors ?), ne peut exister...

AltStyle によって変換されたページ (->オリジナル) /