Programmare OpenOffice in Python
posted in python, openoffice, programmazione |OpenOffice permette la programmazione di semplici macro per automatizzare compiti ripetitivi fino ad arrivare allo sviluppo di componenti complessi; tutto questo con i linguaggi più disparati, dall’OOoBasic (linguaggio che ricorda il VBA di Office) a Java e C++, o con linguaggi di scripting come Python e JavaScript. Vediamo come realizzare in Python una semplice macro per Writer che evidenzi in grassetto tutte le occorrenze di una parola selezionata dall’utente nel testo.
Il nostro sistema di riferimento sarà Kubuntu Edgy, ma i concetti espressi restano validi per tutte le distribuzioni GNU/Linux e anche per i sistemi Windows.
Assumendo che sul sistema siano già installati sia OpenOffice che Python, sarà sufficiente installare il pacchetto per lo sviluppo di componenti UNO in Python insieme ad eventuali dipendenze:
sudo apt-get install python-uno
Grazie a Python-UNO è possibile utilizzare lo scripting framework di OpenOffice, ma sfortunatamente non con l’ambiente di sviluppo integrato. E’ quindi necessario lavorare agli script Python con un editor a scelta e soprattutto piazzare gli script dove OpenOffice possa vederli. Attualmente sono disponibili 3 opzioni:
- nella home dell’utente e precisamente in
~/.openoffice.org2/user/Scripts/python - nella share directory di OpenOffice,
/usr/lib/openoffice/share/Scripts/python - all’interno di un documento di OpenOffice
Sorvolando per brevità sulla terza opzione, possiamo indifferentemente scegliere una delle altre: in un caso la macro sarà disponibile solo per il possessore, nel secondo per tutti gli utenti del sistema.
Creiamo quindi lo script bolder.py, per esempio in ~/.openoffice.org2/user/Scripts/python.
# importa il simbolo per il testo in grassetto from com.sun.star.awt.FontWeight import BOLD def bolder(): “”"Trasforma in grassetto tutte le occorrenze del testo selezionato”"” # ottieni il documento dallo script context xModel = XSCRIPTCONTEXT.getDocument() # recupera il controller xSelectionSupplier = xModel.getCurrentController() # ottieni l’elenco delle selezioni xIndexAccess = xSelectionSupplier.getSelection() # se l’utente ha selezionato del testo, # la selezione di interesse e’ la prima if xIndexAccess.getCount() > 0: xTextRange = xIndexAccess.getByIndex(0) # salva la parola selezionata selString = xTextRange.getString() # crea un descrittore per la ricerca delle parole if selString is not None: # istanzia un descrittore di ricerca search = xModel.createSearchDescriptor() # imposta la stringa da cercare search.SearchString = selString # imposta la ricerca di parole intere search.SearchWords = True # ciclo di modifica if search is not None: # trova la prima occorrenza found = xModel.findFirst(search) while found is not None: # imposta lo spessore dei caratteri sul testo trovato found.CharWeight = BOLD # cerca l’occorrenza successiva found = xModel.findNext(found.End, search) return None
Lo script consiste nella definizione di una funzione, bolder(). La docstring della funzione verrà visualizzata come descrizione della macro nell’apposito menu. Un’operazione preliminare è l’importazione del simbolo BOLD, necessario ad impostare il testo in grassetto.
All’interno della funzione la prima operazione da compiere è ottenere il documento, che nel gergo di OpenOffice è chiamato modello. XSCRIPTCONTEXT è un oggetto globale, definito per tutte le macro, che fornisce accesso al contesto di scripting. Invocandone il metodo getDocument() si ottiene l’handler al documento corrente.
Il documento è associato ad un controller. I controller sono componenti che conoscono e manipolano la presentazione corrente del documento. Il controller in questione implementa, fra le altre, l’interfaccia XSelectionSupplier: tramite questa interfaccia è possibile ottenere dal controller il testo selezionato dall’utente nel documento. In questo caso sarebbe stato possibile ottenere la selezione in modo più semplice invocando il metodo xModel.getCurrentSelection(), che restituisce la selezione corrente nel documento attivo.
Il metodo getSelection() di xSelectionSupplier fornisce l’indice delle selezioni; il perché di un indice anziché direttamente la selezione stessa sta nel fatto che l’utente può effettuare selezioni multiple. Per semplicità utilizziamo la prima selezione, ma solo dopo aver controllato che ne esista almeno una, con il metodo getCount(). Poiché la numerazione delle selezioni parte da 0, il metodo xIndexAccess.getByIndex(0) restituisce la prima selezione, in forma di un TextRange, il cui metodo getString() restituisce finalmente la parola selezionata.
Il passo successivo consiste nell’istanziare un descrittore di ricerca invocando il factory method createSearchDescriptor() del modello del documento, su cui vengono impostate la stringa di ricerca e la modalità per la ricerca di intere parole.
Non rimane che trovare le occorrenze della parola e renderle in grassetto. Il metodo findFirst() del modello trova la prima occorrenza del testo con le modalità definite nel descrittore. Sull’occorrenza trovata viene impostato un attributo, CharWeight, che è quello che determina il corpo del carattere: impostando CharWeight a BOLD raggiungiamo l’obiettivo, evidenziare in grassetto la parola. Il corpo del ciclo termina cercando l’occorrenza successiva, a partire dalla fine dell’occorrenza corrente, con il metodo findNext() del modello.

Una volta salvato lo script si può avviare OpenOffice Writer e riempire in documento vuoto con del testo. Dopo aver selezionato una parola, dal menu principale scegliamo la voce “Strumenti/Macro/Esegui Macro…” dove troveremo fra le macro personali il nostro bolder pronto a trasformare in grassetto tutte le occorrenze della parola prescelta. Per semplificare l’esecuzione della macro possiamo assegnarla ad una combinazione di tasti, con “Strumenti/Personalizza…”.

Purtroppo appare immediatamente evidente quanto lo stile delle API di OpenOffice sia poco “pythonic”. Ciò è dovuto al fatto che le API Python in realtà sono semplicemente un binding alle API native di OpenOffice, per cui non abbiamo una lista Python di selezioni da cui ricavare la cardinalità con la funzione len() e da cui estrarre il primo elemento con l’indicizzazione diretta. Questo stile di programmazione è tuttavia circoscritto all’interazione diretta con il motore di OpenOffice e non è imposto ad eventuali classi sviluppate ad hoc, il che rende lo sviluppo di script complessi più rapido grazie alle feature del linguaggio Python.
Il vero problema è piuttosto una documentazione prolissa e poco chiara, soprattutto per quanto riguarda le API. Gli unici riferimenti per orientarsi nel mondo della programmazione di OpenOffice sono la Developer’s Guide e la IDL Reference.
