Diferencia entre revisiones de «Usuario:Luis.perez/pyunoaytozgz/pyuno»

De WikiEducator
Saltar a: navegación, buscar
m (Página creada con '{{MiTitulo|PyUNO: Macros y componentes para OpenOffice/LibreOffice con Python}} {{Recursos de la Web |Title=Documentación y recursos generales| === Documentación === * Guía …')
 
 
(No se muestran 10 ediciones intermedias de 2 usuarios)
Línea 1: Línea 1:
 
{{MiTitulo|PyUNO: Macros y componentes para OpenOffice/LibreOffice con Python}}
 
{{MiTitulo|PyUNO: Macros y componentes para OpenOffice/LibreOffice con Python}}
  
 +
<br />
 +
== Documentación ==
 
{{Recursos de la Web |Title=Documentación y recursos generales|
 
{{Recursos de la Web |Title=Documentación y recursos generales|
=== Documentación ===
+
;Documentación
 
* Guía oficial de desarrollo de OpenOffice: http://wiki.openoffice.org/wiki/Documentation/DevGuide
 
* Guía oficial de desarrollo de OpenOffice: http://wiki.openoffice.org/wiki/Documentation/DevGuide
 
* Recopilación de enlaces a docs sobre PyUNO http://wiki.openoffice.org/wiki/Python
 
* Recopilación de enlaces a docs sobre PyUNO http://wiki.openoffice.org/wiki/Python
 +
* Información del bridge para python http://wiki.openoffice.org/wiki/PyUNO_bridge
 
* En castellano: http://wiki.openoffice.org/wiki/OOoES/Desarrollo/PyUNO_ES
 
* En castellano: http://wiki.openoffice.org/wiki/OOoES/Desarrollo/PyUNO_ES
  
=== Api ===
+
;Api
 
* Libreoffice: http://api.libreoffice.org/docs/common/ref/com/sun/star/module-ix.html
 
* Libreoffice: http://api.libreoffice.org/docs/common/ref/com/sun/star/module-ix.html
 
* Openoffice: http://www.openoffice.org/api/docs/common/ref/com/sun/star/text/module-ix.html
 
* Openoffice: http://www.openoffice.org/api/docs/common/ref/com/sun/star/text/module-ix.html
  
=== Ejemplos ===
+
;Ejemplos
 
* Ejemplos de la guia de desarrollo: http://api.libreoffice.org/examples/DevelopersGuide/examples.html
 
* Ejemplos de la guia de desarrollo: http://api.libreoffice.org/examples/DevelopersGuide/examples.html
 
* Snippets de código: http://codesnippets.services.openoffice.org/index.xml
 
* Snippets de código: http://codesnippets.services.openoffice.org/index.xml
 +
* Ejemplos de macros: http://www.pitonyak.org/oo.php
  
 
}}
 
}}
 +
 +
== 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
 +
<source lang="bash">
 +
$ apt-get install libreoffice-dev
 +
</source>
 +
* Vamos a utilizar libreoffice 3.5, que usa python 2.7
 +
 +
== 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:
 +
<source lang="python">
 +
  desktop = serviceManager.createInstanceWithContext("com.sun.star.frame.Desktop", context)
 +
</source>
 +
'' Más adelante se hablará del serviceManager y del component context''
 +
 +
Obtener los nombres de servicio que soporta un objeto
 +
 +
<source lang="python">
 +
obj.getSupportedServiceNames()
 +
</source>
 +
 +
 +
{{Reflexion|
 +
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):
 +
<source lang="python">
 +
sheet.getPropertyValue("IsVisible")
 +
</source>
 +
 +
Establecer propiedad:
 +
<source lang="python">
 +
sheet.setPropertyValue("IsVisible", False)
 +
</source>
 +
 +
Obtener propiedades de un objeto:
 +
<source lang="python">
 +
propsinfo = sheet.getPropertySetInfo()
 +
props = propsinfo.getProperties()
 +
for prop in props:
 +
    print(prop)
 +
</source>
 +
 +
==== 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:
 +
<source lang="python">
 +
  import uno
 +
  uno.createUnoStruct("com.sun.star.beans.PropertyValue")
 +
</source>
 +
* Constants: tipo que agrupa varios valores constantes
 +
:Obteniendo el valor de una constante
 +
<source lang="python">
 +
  import uno
 +
  uno.getConstantByName("com.sun.star.sheet.ConditionOperator.GREATER")
 +
</source>
 +
* Enum: Similar a una enumeración en c++
 +
<source lang="python">
 +
</source>
 +
 +
==== 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
 +
<source lang="python">
 +
serviceManager = ctx.ServiceManager
 +
</source>
 +
 +
 +
== Macros ==
 +
 +
Son pequeños programas que usan el api UNO para automatizar tareas en documentos
 +
 +
Ejemplo:
 +
 +
<source lang="python">
 +
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
 +
</source>
 +
 +
* 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:
 +
<source lang="python">
 +
  g_exportedScripts = (holaMundoCalc, ) # solo expondrá holaMundoCalc, aunque haya otras funciones
 +
</source>
 +
* 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:
 +
# Descomprimir documento con unzip
 +
# Incluir el script en cualquier ruta bajo el directorio Scripts
 +
# Modificar META-INF/manifest.mf, incluyendo referencia al script:<source lang="xml"><manifest:file-entry manifest:media-type="" manifest:full-path="Scripts/python/mostrarversion.py"/></source>
 +
# Volver a comprimir el documento
 +
* Empaquetado
 +
:Se creará una estructura de archivos:
 +
<source lang="bash">
 +
  /description.xml
 +
  /Scripts/python/holamundo.py
 +
  /META-INF/manifest.xml
 +
</source>
 +
 +
: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:
 +
<source lang="xml">
 +
<manifest:manifest>
 +
<manifest:file-entry manifest:media-type="application/vnd.sun.star.framework-script" manifest:full-path="Scripts"/>
 +
</manifest:manifest>
 +
</source>
 +
 +
== 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:
 +
<source lang="java">
 +
  // doc es un objeto documento
 +
  XSpreadsheetDocument xSpreadsheetDocument = (XSpreadsheetDocument)
 +
UnoRuntime.queryInterface(XSpreadsheetDocument.class, doc);
 +
 +
  XSpreadsheets xSpreadsheets = xSpreadsheetDocument.getSheets();
 +
  xSpreadsheets.insertNewByName("MySheet", (short)0);
 +
</source>
 +
Esto se traduce a:
 +
<source lang="python">
 +
  xSpreadsheets = doc.getSheets()
 +
  xSpreadsheets.insertNewByName("MySheet", 0)
 +
</source>
 +
 +
* Los arrays y listas se transforman de y hacia python como tuplas, NO como listas!.
 +
<source lang="java">
 +
  com.sun.star.beans.PropertyValue[] conditions = new com.sun.star.beans.PropertyValue[1];
 +
  conditions[0] = condition1
 +
  conditions[1] = condition2
 +
  obj.metodoquerecibeprops(conditions)
 +
</source>
 +
: Lo anterior en python sería:
 +
<source lang="python">
 +
  conditions = (condition1, condition2)
 +
  obj.metodoquerecibeprops(conditions)
 +
</source>
 +
 +
== Conectando con libreoffice ==
 +
 +
Podemos ejecutar scripts python para que se conecten a libreoffice.
 +
 +
; Arrancar libreoffice escuchando en un puerto
 +
<source lang="bash">
 +
  $ soffice --norestore "-accept=socket,host=localhost,port=2002;urp;"
 +
</source>
 +
 +
; Conectarse a libreoffice y obtener objetos necesarios
 +
 +
<source lang="python">
 +
  localContext = uno.getComponentContext()
 +
  resolver = localContext.ServiceManager.createInstanceWithContext(
 +
                "com.sun.star.bridge.UnoUrlResolver", localContext )
 +
  ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
 +
  smgr = ctx.ServiceManager
 +
  desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
 +
 
 +
  model = desktop.getCurrentComponent()
 +
  text = model.Text
 +
  cursor = text.createTextCursor()
 +
  text.insertString( cursor, "Hello World", 0 )
 +
</source>
 +
 +
== Calc: Api ==
 +
:
 +
{{Recursos de la Web |Title=Documentación|
 +
* http://wiki.openoffice.org/wiki/Documentation/DevGuide/Spreadsheets/Spreadsheet_Documents
 +
* http://wiki.openoffice.org/w/images/thumb/b/be/SpreadsheetOverview.png/800px-SpreadsheetOverview.png
 +
 +
}}
 +
 +
* La mayor parte del api que nos interesa está bajo:
 +
** com.sun.star.sheet
 +
** com.sun.star.table
 +
 +
{{Ejemplo|Title=Ejemplos del api de calc|
 +
Leer y ejecutar paso a paso la macro del ejemplo 5_calc_api.
 +
}}
 +
; Filtros de exportación / Importacion:
 +
* http://wiki.openoffice.org/wiki/Documentation/DevGuide/Spreadsheets/Filter_Options
 +
 +
 +
 +
== Componentes y extensiones en PyUNO ==
 +
* Se encuentra en: /usr/lib/libreoffice/program/unopkg
 +
 +
:
 +
{{Recursos de la Web |Title=Documentación|
 +
;Documentación
 +
http://wiki.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Writing_UNO_Components
 +
http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/
 +
http://wiki.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Writing_the_Specification -> especificación de UNO IDL
 +
;Ejemplo
 +
http://www.biochemfusion.com/doc/Calc_addin_howto.html
 +
}}
 +
 +
* Los componentes pueden crearse en python extendiendo de unohelper.Base, e implementando los interfaces necesarios.
 +
* Pueden implementar interfaces ya existentes en el api de UNO, o crear nuevos
 +
* Los nuevos interfaces y servicios se declaran mediante UNOIDL en un fichero .idl
 +
 +
=== Herramienta unopkg ===
 +
 +
Es la herramienta con la que se pueden instalar, listar, y desinstalar paquetes
 +
 +
; Instalar extensión:
 +
<source lang="bash">
 +
$ unopkg add myextension.oxt
 +
</source>
 +
 +
; Instalar extensión para todos los usuarios:
 +
<source lang="bash">
 +
$ unopkg add --shared myextension.oxt
 +
</source>
 +
 +
; Listar las extensiones instaladas
 +
<source lang="bash">
 +
$ unopkg list
 +
</source>
 +
 +
; Eliminar una extensión
 +
<source lang="bash">
 +
$ unopkg remove <identifier>
 +
</source>
 +
 +
 +
=== Creación de extensión que exponga algún servicio/interfaz ===
 +
 +
# Compilar .idl a .urd: <source lang="bash">/usr/lib/libreoffice/sdk/bin/idlc -w -I /usr/lib/libreoffice/sdk/idl XMyComp.idl</source>
 +
# meter .urd en .rdb con regmerge <source lang="bash">/usr/lib/ure/bin/regmerge XMyComp.rdb /UCR XMyComp.urd</source>
 +
# Implementación del servicio/interfaz en python
 +
# Crear description.xml
 +
# crear .xcu
 +
# crear META-INF/MANIFEST.MF
 +
# Empaquetar todo en zip, nombrandolo como myextension.oxt
 +
# Instalar con unopkg <source lang="bash">/usr/lib/libreoffice/program/unopkg add myextension.oxt</source>, ó abriendo la extensión con libreoffice.
 +
 +
{{Ejemplo|Title=Añadiendo fórmulas a Calc|
 +
Empaquetar la extensión del ejemplo 6_calc_formulas_addin
 +
}}
 +
 +
== Interacción con componentes ==
 +
 +
:
 +
{{Recursos de la Web |Title=Documentación|
 +
;Documentación
 +
http://wiki.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Accessing_Dialogs
 +
http://wiki.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Using_Dialogs_in_Components
 +
http://wiki.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Jobs
 +
}}
 +
 +
=== Jobs ===
 +
 +
* Componentes que pueden ser ejecutados como respuesta a un evento en el sistema, o también directamente
 +
* Han de implementar com.sun.star.task.XJob
 +
* Son ejecutados por el servicio com.sun.star.task.JobExecutor
 +
* Pueden ejecutarse mediante eventos estandar del sistema, o mediante eventos personalizados
 +
 +
; Lista de eventos estándar del sistema
 +
http://wiki.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Jobs/List_of_Supported_Events
 +
 +
{{Ejemplo|Title=Ejecutando un job|
 +
Empaquetar y ejecutar el componente del ejemplo 8_writer_menutoolbar_job
 +
}}
 +
 +
=== Dialogos ===
 +
 +
Se pueden crear de dos modos:
 +
* Directamente con el api de com.sun.star.awt
 +
* Usando diálogos creados con el IDE básico de dialogos de openoffice, e instanciandolos desde el componente o macro python:
 +
<source lang="python">
 +
    args = (doc,)
 +
    dialogprov = serviceManager.createInstanceWithArgumentsAndContext("com.sun.star.awt.DialogProvider2", args, ctx)
 +
    #dialog = dialogprov.createDialogWithHandler("file:///tmp/NameDialog.xdl", Handler()) # También se puede referenciar el archivo del diálogo
 +
    dialog = dialogprov.createDialogWithHandler("vnd.sun.star.script:NeoLibrary.NameDialog?location=application", Handler())
 +
    dialog.execute()
 +
</source>
 +
 +
{{Ejemplo|Title=Un diálogo para insertar texto|
 +
Instalar y ejecutar como macro el ejemplo 11_using_basicdialog
 +
}}
 +
 +
== Tips ==
 +
 +
===== Aumentar nivel de logs =====
 +
* Modificar:
 +
/usr/lib/libreoffice/share/extensions/script-provider-for-python/pythonscript.py
 +
<source lang="python">
 +
LogLevel.use = LogLevel.NONE                # alternavly use LogLevel.ERROR or LogLevel.DEBUG
 +
LOG_STDOUT = False                          # True, writes to stdout
 +
                                            # False, writes to user/Scripts/python/log.txt
 +
</source>
 +
 +
===== Obtener ruta de un paquete desplegado =====
 +
* útil para acceder a ficheros de la extensión desplegada, ver ejemplo de toolpanel
 +
<source lang="python">
 +
  pip = self.ctx.getValueByName("/singletons/com.sun.star.deployment.PackageInformationProvider" )
 +
  s = pip.getPackageLocation(extensionID) # s es una string con la ruta absoluta al paquete
 +
</source>

Última revisión de 22:00 5 feb 2013



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
  • Vamos a utilizar libreoffice 3.5, que usa python 2.7

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.xml
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)

Conectando con libreoffice

Podemos ejecutar scripts python para que se conecten a libreoffice.

Arrancar libreoffice escuchando en un puerto
  $ soffice --norestore "-accept=socket,host=localhost,port=2002;urp;"
Conectarse a libreoffice y obtener objetos necesarios
  localContext = uno.getComponentContext()
  resolver = localContext.ServiceManager.createInstanceWithContext(
                "com.sun.star.bridge.UnoUrlResolver", localContext )
  ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
  smgr = ctx.ServiceManager
  desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
 
  model = desktop.getCurrentComponent()
  text = model.Text
  cursor = text.createTextCursor()
  text.insertString( cursor, "Hello World", 0 )

Calc: Api




  • La mayor parte del api que nos interesa está bajo:
    • com.sun.star.sheet
    • com.sun.star.table



Icon casestudy.gif

Ejemplos del api de calc

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



Filtros de exportación / Importacion


Componentes y extensiones en PyUNO

  • Se encuentra en: /usr/lib/libreoffice/program/unopkg




  • Los componentes pueden crearse en python extendiendo de unohelper.Base, e implementando los interfaces necesarios.
  • Pueden implementar interfaces ya existentes en el api de UNO, o crear nuevos
  • Los nuevos interfaces y servicios se declaran mediante UNOIDL en un fichero .idl

Herramienta unopkg

Es la herramienta con la que se pueden instalar, listar, y desinstalar paquetes

Instalar extensión
$ unopkg add myextension.oxt
Instalar extensión para todos los usuarios
$ unopkg add --shared myextension.oxt
Listar las extensiones instaladas
$ unopkg list
Eliminar una extensión
$ unopkg remove <identifier>


Creación de extensión que exponga algún servicio/interfaz

  1. Compilar .idl a .urd:
    /usr/lib/libreoffice/sdk/bin/idlc -w -I /usr/lib/libreoffice/sdk/idl XMyComp.idl
  2. meter .urd en .rdb con regmerge
    /usr/lib/ure/bin/regmerge XMyComp.rdb /UCR XMyComp.urd
  3. Implementación del servicio/interfaz en python
  4. Crear description.xml
  5. crear .xcu
  6. crear META-INF/MANIFEST.MF
  7. Empaquetar todo en zip, nombrandolo como myextension.oxt
  8. Instalar con unopkg
    /usr/lib/libreoffice/program/unopkg add myextension.oxt
    , ó abriendo la extensión con libreoffice.



Icon casestudy.gif

Añadiendo fórmulas a Calc

Empaquetar la extensión del ejemplo 6_calc_formulas_addin




Interacción con componentes




Jobs

  • Componentes que pueden ser ejecutados como respuesta a un evento en el sistema, o también directamente
  • Han de implementar com.sun.star.task.XJob
  • Son ejecutados por el servicio com.sun.star.task.JobExecutor
  • Pueden ejecutarse mediante eventos estandar del sistema, o mediante eventos personalizados
Lista de eventos estándar del sistema

http://wiki.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Jobs/List_of_Supported_Events



Icon casestudy.gif

Ejecutando un job

Empaquetar y ejecutar el componente del ejemplo 8_writer_menutoolbar_job




Dialogos

Se pueden crear de dos modos:

  • Directamente con el api de com.sun.star.awt
  • Usando diálogos creados con el IDE básico de dialogos de openoffice, e instanciandolos desde el componente o macro python:
    args = (doc,)
    dialogprov = serviceManager.createInstanceWithArgumentsAndContext("com.sun.star.awt.DialogProvider2", args, ctx)
    #dialog = dialogprov.createDialogWithHandler("file:///tmp/NameDialog.xdl", Handler()) # También se puede referenciar el archivo del diálogo
    dialog = dialogprov.createDialogWithHandler("vnd.sun.star.script:NeoLibrary.NameDialog?location=application", Handler())
    dialog.execute()



Icon casestudy.gif

Un diálogo para insertar texto

Instalar y ejecutar como macro el ejemplo 11_using_basicdialog




Tips

Aumentar nivel de logs
  • Modificar:

/usr/lib/libreoffice/share/extensions/script-provider-for-python/pythonscript.py

	LogLevel.use = LogLevel.NONE                # alternavly use LogLevel.ERROR or LogLevel.DEBUG
	LOG_STDOUT = False                          # True, writes to stdout
        	                                    # False, writes to user/Scripts/python/log.txt
Obtener ruta de un paquete desplegado
  • útil para acceder a ficheros de la extensión desplegada, ver ejemplo de toolpanel
   pip = self.ctx.getValueByName("/singletons/com.sun.star.deployment.PackageInformationProvider" )
   s = pip.getPackageLocation(extensionID) # s es una string con la ruta absoluta al paquete