PyUNO: Macros y componentes para OpenOffice/LibreOffice con Python

De WikiEducator
Saltar a: navegación, buscar


Documentación



Instalación de Libreoffice (Ubuntu)

  • Basta con tener instalado libreoffice si solo se van a hacer macros.
  • Si se van a crear componentes instalar adicionalmente el paquete libreoffice-dev
$ apt-get install libreoffice-dev

Introducción al API de Openoffice: conceptos

Interfaces

  • Un conjunto de métodos y/o atributos que exponen funcionalidad. Aspectos de la implementación de un objeto.
  • En el api de UNO, todos los nombres de interfaces empiezan con X
  • Todos los interfaces extienden XInterface

Servicios

  • Servicios "New-style": Especifica que objetos que implementan un determinado interfaz (ej: com.sun.star.bridge.XUnoUrlResolver), estarán disponibles bajo un determinado nombre (ej: com.sun.star.bridge.UnoUrlResolver) en el service manager del component context (ver más adelante). Para que un objeto que implementa un servicio pueda implementar varios aspectos o interfaces, el interfaz que implementa heredará de varios otros interfaces.
  • Servicios "Old-style": Los servicios oldstyle pueden verse como un conjunto de interfaces y/o propiedades.
    • Pueden o no exponerse a través del service manager, servir como base de otros servicios (en el new-style, el mecanismo preferido para proporcionar servicios base es implementar interfaces que heredan de varios interfaces), o simplemente servir para agrupar un conjunto de propiedades.
    • Pueden implementar interfaces opcionales
    • Pueden incluir otros servicios, lo que significa que expondrán el conjunto de sus interfaces y de los otros servicios.

Obtener un servicio a través del serviceManager:

  desktop = serviceManager.createInstanceWithContext("com.sun.star.frame.Desktop", context)

Más adelante se hablará del serviceManager y del component context

Obtener los nombres de servicio que soporta un objeto

 obj.getSupportedServiceNames()



Icon reflection.gif

Reflexión

Debido a la existencia de servicios old-style, hay que tener cuidado a la hora de interpretar el api: Algunos servicios no pueden ser instanciados directamente con el service manager

  • Porque son conjuntos de propiedades
  • Porque solo sirven como servicios base de otros servicios
  • O necesitan un tratamiento especial. Ej: com.sun.star.text.TextDocument no puede instanciarse directamente, se obtiene a través de loadComponentFromUrl() de com.sun.star.frame.XComponentLoader




Propiedades

  • Pares de nombre-valor que expone un servicio.
  • Normalmente suelen ser utilizados para atributos no estructurales (ej: color, tamaño, pero no objetos padre o hijos)
  • Se suelen acceder mediante com.sun.star.beans.XPropertySet, pero también en algunos casos, a través de com.sun.star.beans.XPropertyAccess ó com.sun.star.beans.XMultiPropertySet

Obtener propiedad (XPropertySet):

 sheet.getPropertyValue("IsVisible")

Establecer propiedad:

 sheet.setPropertyValue("IsVisible", False)

Obtener propiedades de un objeto:

 propsinfo = sheet.getPropertySetInfo()	
 props = propsinfo.getProperties()
 for prop in props:
     print(prop)

Singletons

  • Implementación de interface del que solo existe una instancia accesible desde el component context.

Componentes / extensiones

  • Son librerías que contienen implementaciones de uno o varios servicios en cualquiera de los lenguajes que soporta UNO

Estructuras, Constantes, y Enumeraciones

  • Estructuras: Conjunto de miembros, similar a la estructuras en C. Soportan herencia simple.
Instanciando una estructura:
  import uno
  uno.createUnoStruct("com.sun.star.beans.PropertyValue")
  • Constants: tipo que agrupa varios valores constantes
Obteniendo el valor de una constante
  import uno
  uno.getConstantByName("com.sun.star.sheet.ConditionOperator.GREATER")
  • Enum: Similar a una enumeración en c++
 

Módulos

  • Espacios de nombres, similares a los namespaces de C++ o a los paquetes en Java. Agrupan servicios, interfaces, structs...

ComponentContext

  • Objeto con el que se obtene el singleton de ServiceManager
  • Puede obtenerse dependiendo de si el código a ejecutar va a ser una macro o un componente.

ServiceManager

  • Objeto con el que se instancian servicios
 serviceManager = ctx.ServiceManager


Macros

Son pequeños programas que usan el api UNO para automatizar tareas en documentos

Ejemplo:

 import uno
 
 def holaMundoCalc():
     # Accedemos al modelo del documento actual 
     model = XSCRIPTCONTEXT.getDocument()
     # Accedemos a la primer hoja del documento
     hoja = model.getSheets().getByIndex(0)
     # Accedemos a la celda A1 de la hoja
     celda = hoja.getCellRangeByName("A1")
     # Escribimos en la celda
     celda.setString("Hola Mundo en Python")
     return None
  • XSCRIPTCONTEXT: variable global en el script que contiene Document (el objeto que representa un documento), Desktop y ComponentContext
  • Por defecto todas las funciones del script se exportan como macros. Para limitarlos:
  g_exportedScripts = (holaMundoCalc, ) # solo expondrá holaMundoCalc, aunque haya otras funciones
  • El comentario de una función se muestra como descripción de la macro en el diálogo de macros


Ejecución de macros

Puede hacerse a través del díalogo tools -> macros -> run macro... o a través de tools -> macros -> organize macros -> python...

Distribución de macros

Existen varios modos de distribuir una macro

  • En directorio de usuario:
    • ~/.openoffice.org/3/:user/Scripts/python
    • ~/.config/libreoffice/3/user/Scripts/python
  • En directorio compartido (para todos los usuarios)
    • /usr/lib/libreoffice/share/Scripts/python
    • /usr/lib/openoffice/share/Scripts/python
  • Embebido en documentos:
  1. Descomprimir documento con unzip
  2. Incluir el script en cualquier ruta bajo el directorio Scripts
  3. Modificar META-INF/manifest.mf, incluyendo referencia al script:
    <manifest:file-entry manifest:media-type="" manifest:full-path="Scripts/python/mostrarversion.py"/>
  4. Volver a comprimir el documento
  • Empaquetado
Se creará una estructura de archivos:
  /description.xml
  /Scripts/python/holamundo.py
  /META-INF/manifest.mf
Donde description.xml sirve para dar información sobre el paquete (ver 2_simplemacropkg), y manifest.mf referencia la ruta base de los scripts del siguiente modo:
<manifest:manifest>
 <manifest:file-entry manifest:media-type="application/vnd.sun.star.framework-script" manifest:full-path="Scripts"/>
</manifest:manifest>

Transformando código Java a Python: diferencias

Una buena forma de aprender sobre UNO es mediante los ejemplos que hay disponibles. Lamentablemente la mayoría de código es Java o C++.

  • La primera diferencia es obvia: python no es estáticamente tipado
  • Para obtener y usar un servicio, no es necesario instanciar el servicio y luego hacer un UnoRuntime.queryInterface para obtener el interface deseado del tipo correcto. Basta con instanciar el servicio o componente, y usarlo directamente. Ej:
  // doc es un objeto documento
  XSpreadsheetDocument xSpreadsheetDocument = (XSpreadsheetDocument)
	UnoRuntime.queryInterface(XSpreadsheetDocument.class, doc);
 
  XSpreadsheets xSpreadsheets = xSpreadsheetDocument.getSheets();
  xSpreadsheets.insertNewByName("MySheet", (short)0);

Esto se traduce a:

  xSpreadsheets = doc.getSheets()
  xSpreadsheets.insertNewByName("MySheet", 0)
  • Los arrays y listas se transforman de y hacia python como tuplas, NO como listas!.
  com.sun.star.beans.PropertyValue[] conditions = new com.sun.star.beans.PropertyValue[1];
  conditions[0] = condition1
  conditions[1] = condition2
  obj.metodoquerecibeprops(conditions)
Lo anterior en python sería:
  conditions = (condition1, condition2)
  obj.metodoquerecibeprops(conditions)


Calc: Api

Icon casestudy.gif

Ejemplo

Ejemplos del api de calc

Leer y ejecutar paso a paso la macro del ejemplo 3_calc_api.




Componentes y extensiones en PyUNO