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
Dim document as Object
Dim textDocument As Object
Dim sel as Object
Dim propertiesDoc()
document = thisComponent
sel = document.currentSelection
if sel.supportsService("com.sun.star.table.CellRange") then
textDocument = StarDesktop.LoadComponentFromURL("private:factory/swriter", "_blank", 0, propertiesDoc)
else
MsgBox "Select a range of cells"
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 et dans des documents comme 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(...) mais une version plus pratique est disponible sur http://wiki.services.openoffice.org/wiki/Documentation/BASIC(...) .
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
dim table As Object
table = document.createInstance("com.sun.star.text.TextTable")
table.initialize(rows, columns)
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)
dim docText as Object
dim cursor as object
docText = document.Text
cursor = docText.createTextCursor
cursor.gotoNextParagraph(False)
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
textDocument = StarDesktop.LoadComponentFromURL("private:factory/swriter", "_blank", 0, propertiesDoc)
textTable = CreateTable(textDocument, sel.RangeAddress.EndColumn - sel.RangeAddress.StartColumn + 1, sel.RangeAddress.EndRow - sel.RangeAddress.StartRow + 1)
textTable.HeaderRowCount = 0
InsertTable(textDocument, textTable)
for x = 0 to sel.RangeAddress.EndRow - sel.RangeAddress.StartRow
for y = 0 to sel.RangeAddress.EndColumn - sel.RangeAddress.StartColumn
textCell = textTable.getCellByPosition(y, x)
calcCell = sel.getCellByPosition(y, x)
copyCell(calcCell, textCell)
next y
next x
else
MsgBox "Select a range of cells"
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 : test 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
sourceText = sourceCursor.Text
listeParag = sourceText.createEnumeration
Do While listeParag.hasMoreElements
parag = listeParag.nextElement
listeParts = parag.createEnumeration
Do While listeParts.hasMoreElements
part = listeParts.nextElement
sourceCursor.gotoRange(part.End, False)
propsetsource() = sourceCursor.propertySetInfo.properties
propsetdest() = destCursor.propertySetInfo.properties
For i = 0 To UBound(propsetsource)
propertyName = propsetsource(i).Name
For j = 0 To UBound(propsetdest)
if propsetdest(j).Name = propertyName Then
destCursor.setPropertyValue(propertyName, sourceCursor.getPropertyValue(propertyName))
Goto NextProperty
End If
Next j
NextProperty:
Next i
destCursor.String = part.String
destCursor.gotoEnd(False)
Loop
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(...) 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...
# 11e
Posté par tesiruna . Évalué à 1.
[^] # Re: 11e
Posté par NeoX . Évalué à 1.
[^] # Re: 11e
Posté par Lotso . Évalué à 9.
[^] # Re: 11e
Posté par bubar🦥 (Mastodon) . Évalué à 1.
sniff
# Comparaison
Posté par pasBill pasGates . Évalué à 4.
[^] # Re: Comparaison
Posté par Pinaraf . Évalué à 7.
Automatiser une tâche simple, c'est-à-dire vraiment ce qu'est une macro, ou faire une vraie extension au logiciel, ce qui ressemble plus à un "plugin" ?
Dans le cas vraiment de la macro, OpenOffice.org a une API mieux documentée, mais les outils de création de macro sont largement en dessous des outils de Microsoft Office (en tout cas de Word et d'Excel) : ils ne t'aident pas à rédiger ton code, ils ne t'aident pas à trouver à ta place les bons appels dans l'API...
Par contre, pour réaliser une extension à OpenOffice.org, cela me semble plus simple et surtout bien moins limité. Je n'ai pas d'exemple à fournir pour l'instant, mais dans un futur journal je présenterai une extension OpenOffice.org en Java dont la réalisation sous Microsoft Office me paraît largement plus délicate.
# j'ai pas bien compris
Posté par NeoX . Évalué à 2.
perso, je copie/colle un tableau openoffice, dans writer, c'et effectivement loin d'etre parfait, mais ...
à part pour avoir le resultat d'un tableau dans le document texte, pourquoi voudrais-je utiliser un tableau dans le traitement de texte ?
pour presenter un tableau dans un rapport ? mouais, y a surement moins de faire des jolis rapports en utilisant correctement les outils /polices/mise en page ?
et puis rien n'empeche d'imprimer les 2 tableaux à part, et de les inserer dans le "bouquins" papier que tu rends à la fin.
Ou alors il se fait tard, et je ne vois pas l'interet dans mon cerveau embué
[^] # Re: j'ai pas bien compris
Posté par Pinaraf . Évalué à 3.
[^] # Re: j'ai pas bien compris
Posté par freejeff . Évalué à 1.
[^] # Re: j'ai pas bien compris
Posté par Pinaraf . Évalué à 3.
[^] # Re: j'ai pas bien compris
Posté par freejeff . Évalué à 1.
Elle est de plus "explosible" pour en récupérer les infos, donc c'est moins binaire que tu m'entends ...
# Vous devez entrer un sujet dans la boîboîte.
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 4.
"Pen tablet" (une petite intuos A5 fait parfaitement l'affaire)
# le basic c'est obligatoire?
Posté par Albert_ . Évalué à 1.
http://wiki.services.openoffice.org/wiki/Python
[^] # Re: le basic c'est obligatoire?
Posté par Larry Cow . Évalué à 3.
[^] # Re: le basic c'est obligatoire?
Posté par Pinaraf . Évalué à 5.
[^] # Re: le basic c'est obligatoire?
Posté par Larry Cow . Évalué à 2.
[^] # Re: le basic c'est obligatoire?
Posté par Pinaraf . Évalué à 2.
[^] # Re: le basic c'est obligatoire?
Posté par EdLeH (site web personnel) . Évalué à 3.
de ce que j'ai compris, sous nos bonnes distributions GNU-Linux, le paquet python-uno permet à OOo de manipuler le Python installé, mais aussi de manipuler OOo depuis un programme Python.
Pas de problème puisque la distribution gère le fait que la version Python est la même.
Le Python embarqué dans OOo, c'est pour Windows, car il y est impossible de savoir si l'éventuelle version de Python installée sera la même que celle utilisée par OOo.
C'est le problème auquel je me suis trouvé confronté récemment.
Je développe un programme Python+PyQt qui a besoin de manipuler des fichiers OOo.
Sous Linux, aucun problème avec le paquet python-uno.
Sous Windows, le python embarqué n'intègre évidemment pas PyQt, ce qui fait que je ne peux pas lancer mon logiciel en passant par icelui.
Après pas mal d'essais-erreurs, j'ai trouvé comment me raccrocher à uno depuis le Python installé, et ça fonctionne.
Reste à savoir ce qui se passe si un utilisateur a un OOo et un Python de versions différentes.
Si ça intéresse, je peux indiquer la démarche que j'ai suivie.
O-
[^] # Re: le basic c'est obligatoire?
Posté par norbs . Évalué à 1.
ça serait intéressant STP. J'ai en tête un projet python de fabrication de livre photo à partir d'une collection d'image et d'une mise en page OOO et ce serait déjà une épine retirée.... Merci d'avance !
[^] # Re: le basic c'est obligatoire?
Posté par EdLeH (site web personnel) . Évalué à 2.
je rédige cela pendant le week-end et j'indiquerai ici.
O-
[^] # Re: le basic c'est obligatoire?
Posté par EdLeH (site web personnel) . Évalué à 2.
http://pascal.peter.free.fr/wiki/Programmation/PythonOOoUno
en espérant que ça puisse aider.
O-
[^] # Re: le basic c'est obligatoire?
Posté par norbs . Évalué à 1.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.