divendres, 26 de novembre del 2010

L'enregistrador de macros de l'OpenOffice.org

Aquest article està basat en http://wiki.services.openoffice.org/wiki/The_OpenOffice.org_recorder_and_UNO_dispatch_calls

Des del punt de vista d'un desenvolupador, fer una macro és "escriure" una macro, o programar una macro.

Tanmateix, des del punt de vista de l'usuari, una macro es pot fer de forma molt senzilla sense més que enregistrar-la:  Eines - Macros - Enregistra una macro. Amb aquesta eina l'OpenOffice.org guarda la sequència d'accions que realitzem a la interfase de l'aplicació fins que li en diem que aturi l'enregistrament, moment en que ens demana que li donem un nom  a la macro.

Doncs bé, la macro es guarda com una seqüència d'accions d'OpenOffice.org Basic.

Ara bé, el codi que trobarem potser ens sorprendrà. Es tractarà d'una seqüència comandes UNO, és dir, d'invocacions a URL de tipus UNO mitjançant el servei DispatchHelper. Bàsicament carregarà un array de paràmetres i invocarà la URL que correspongui passant-li l'array.

En general, a cada acció que es pot realitzar des de la interfase de l'aplicació, ja sigui per menú o per barra d'eines, li correspon una URL UNO del tipus ".uno:AccioDeLaInterfase"

En aquest punt, el desenvolupador pot tornar a entrar en acció. És un exercici interessant analitzar les macros en Basic que ha generat automàticament l'OpenOffice.org.

Per exemple, poso el següent text de prova al Writer:

"A continuació escric un petit text de prova
Ara formataré el text de diverses formes.
El que faré serà enregistrar una macro per veure com es fa l'acció amb OooBasic
D'aquesta forma el mateix OpenOffice.org em fa de “mestre” de programació.
Som-hi"

Comencem, busco "text" i el reemplaço per "escrit".
Això es tradueix en aquesta macro:

sub Replace
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatchersub Replace
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------------------------------------------------------------------
dim args1(18) as new com.sun.star.beans.PropertyValue
args1(0).Name = "SearchItem.StyleFamily"
args1(0).Value = 2
args1(1).Name = "SearchItem.CellType"
args1(1).Value = 0
args1(2).Name = "SearchItem.RowDirection"
args1(2).Value = true
args1(3).Name = "SearchItem.AllTables"
args1(3).Value = false
args1(4).Name = "SearchItem.Backward"
args1(4).Value = false
args1(5).Name = "SearchItem.Pattern"
args1(5).Value = false
args1(6).Name = "SearchItem.Content"
args1(6).Value = false
args1(7).Name = "SearchItem.AsianOptions"
args1(7).Value = false
args1(8).Name = "SearchItem.AlgorithmType"
args1(8).Value = 0
args1(9).Name = "SearchItem.SearchFlags"
args1(9).Value = 65536
args1(10).Name = "SearchItem.SearchString"
args1(10).Value = "text"
args1(11).Name = "SearchItem.ReplaceString"
args1(11).Value = "escrit"
args1(12).Name = "SearchItem.Locale"
args1(12).Value = 255
args1(13).Name = "SearchItem.ChangedChars"
args1(13).Value = 2
args1(14).Name = "SearchItem.DeletedChars"
args1(14).Value = 2
args1(15).Name = "SearchItem.InsertedChars"
args1(15).Value = 2
args1(16).Name = "SearchItem.TransliterateFlags"
args1(16).Value = 1280
args1(17).Name = "SearchItem.Command"
args1(17).Value = 3
args1(18).Name = "Quiet"
args1(18).Value = true

dispatcher.executeDispatch(document, ".uno:ExecuteSearch", "", 0, args1())
end sub

Ja es veu que aquesta aproximació no és tan eficient com invocar els objectes i els components del document mitjançant la API de UNO, però pot ser útil en algunes ocasions. El que caldria fer és provar les diferents comandes a veure com les enregistra el gravador de macros.

La llista de comandes és prou llarga. Una llista de les comandes UNO la podem trobar en aquest enllaç.

dimarts, 23 de novembre del 2010

Com executar una macro de l'OpenOffice des d'una shell

Aquest és un truc que obre un ampli ventall de possibilitats.  Per a més info. mireu aquest fil del fòrum de l'OpenOffice.org.

Per a invocar una macro de l'openOffice.org, n'hi ha prou amb indicar el mètode de macro que vull executar amb una URL del tipus macro.

Per exemple, per obrir el wrapper del tesseract OCR del post anterior.

soffice macro:///tesseract.Module1.ObrirDialeg

Si la macro estigués en un document, caldria indicar el document

soffice document  macro:///mètode


Es poden passar paràmetres a la macro:

Suposem el mètode Concatena al Module1 de la llibreria Standard,

Sub Concatena(sVar1 as String, sVar2 as String)
    MsgBox sVar1 & " + " sVar2
end sub

Aleshores el podria invocar com:


soffice "macro:///Standard.Module1.Concatena(\"hola\",\"adeu\")"


El resultat és l'esperat:



Per evitar trobar-se amb un munt d'instàncies de l'OpenOffice.org obertes i consumint recursos, és una bona precaució que les macros que soguin invocades des de la línia d'ordres tanquin explícitament el document des del que és invocat, si cal,  i també la instància de l'OpenOffice.org. Això es pot aconseguir amb aquest codi:

thisComponent.close(true)   ' tanca el document
Stardesktop.terminate()    ' tanca l'OOo

diumenge, 21 de novembre del 2010

Desplegament de llibreries de macros a l'OpenOffice.org amb un add-on

Una opció per a fer el desplegament "professional" de llibreries, components o extensions per a l'OpenOffice.org són els add-on. Esl add-on són extensions a l'OOo que presenten algun tipus d'integració amb la interfase d'usuari de l'OOo, per exemple menús o barra d'eines.

Per a explicar aquest mecanisme, desenvoluparé un wrapper per a l'aplicació de consola tesseract-ocr amb OOobasic i el desplegaré com un add-on.

Tesseract-ocr és un (antic però eficient) motor d'OCR (reconeixement òptic de caràcters) desenvolupat inicialment per HP i que actualment és mantingut per Google.

Primer de tot, per tant, cal instal·lar el tesseract-ocr. En Ubuntu Lucid Lynx es pot fer des del "Centre de Programari de l'Ubuntu" i s'obté la versió 2, i s'hi poden afegir els idiomes anglès i castellà. A Windows, es pot descarregar la versió 3 des de la mateixa web de Tesseract-ocr. En la versió 3, a més del castellà i l'anglès, també es pot afegir el català.

El cas és que Tesseract-ocr és una aplicació de consola a la que cal passar-li arguments per a fer-lo treballar.

albert@atenea:~$ tesseract
tesseract:Error:Usage:tesseract imagename outputbase [-l lang] [configfile [[+|-]varfile]...]

Per a facilitar l'ús del tesseract, doncs, faré una UI que permeti construir la invocació de línia d'ordres del tesseract i l'executaré en una shell. Com que el que es pretén és obtenir un text a partir d'una imatge per a treballar amb ell, sembla que una bona idea és crear un menú nou "OCR" al Writer de l'OpenOffice.org que en fer-hi click ens obri una GUI que analitzi la imatge i que un cop obtingut el text, l'importi al processador de texts.

A més, per a facilitar-ne la distribució, el que faré serà empaquetar la macro i el diàleg en un .oxt, un add-on, de forma que per a instal·lar-lo n'hi haurà prou amb obrir el fitxer .oxt amb l'OpenOffice.org Writer (o també directament amb la utilitat unopkg, o amb el gestor d'extensions).

Dit i fet. A "Les meves macros", creo una llibreria que anomeno "tesseract" i en el "Module1" hi afegeixo el següent codi.

REM ***** BASIC *****
REM basat en codi de http://www.oooforum.org/forum/viewtopic.phtml?t=9797


Dim sCarpeta as String
Dim sCarpetaImatges as String
Dim sImatge as String
Dim sNomFitxerText as String
Dim oDialeg1 as Object


' util per a depuració
sub main
ObrirDialeg
end sub


function EsLinux as Boolean
Dim sHome
EsLinux = false
sHome = Environ("HOME")
if left(sHome,1) = "/" then
EsLinux = true
end if
end function


' aquest és el mètode que cal invocar des del menú
Sub ObrirDialeg
' carrega la llibraria de diàlegs estandard
GlobalScope.DialogLibraries.LoadLibrary("tesseract")


' carrega el Diàleg "Dialog1"
oDialeg1 = CreateUnoDialog(DialogLibraries.tesseract.TesseractWrapperDialog)
oDialeg1.Execute()
end sub


' tria la carpeta on guardarà el text obtingut
' fent servir un diàleg del tipus FolderPicker
Sub TriaCarpeta( )
Dim oFolderPickerDlg as Object
Dim sCarpetaTriada as String


' carrega el diàleg
oFolderPickerDlg = createUnoService( "com.sun.star.ui.dialogs.FolderPicker" )


' estableix valors inicials si els té
If Len( sCarpeta ) > 0 Then
oFolderPickerDlg.setDisplayDirectory( ConvertToURL( sCarpeta ) )
EndIf


' executa el diàleg
oFolderPickerDlg.execute()


' guarda el valor
sCarpeta = ConvertFromURL(oFolderPickerDlg.getDirectory())


oDialeg1.getControl("txtCarpeta").text = sCarpeta
End sub


' tria la imatge a analitzar fent servir un diàleg del tipus FilePicker
Sub TriaImatge()
Dim oFilePickerDlg as Object
Dim sFitxers() as String


' XRayTool és una eina imprescindible per al desenvolupador d'OOo!!!
' GlobalScope.BasicLibraries.loadLibrary("XrayTool")


' carrega paràmetres incials al diàleg
oFilePickerDlg = createUnoService( "com.sun.star.ui.dTriaImatgeialogs.FilePicker" )
oFilePickerDlg.setMultiSelectionMode( False )


If Len( sCarpetaImatges ) > 0 Then
oFilePickerDlg.setDisplayDirectory( ConvertToURL( sCarpetaImatges ) )
End If


If Len( sImatge ) > 0 Then
oFilePickerDlg.setDefaultName( sImatge )
End If


' executa el diàleg
oFilePickerDlg.execute()


' obté la carpeta d'imatges
sCarpetaImatges = ConvertFromURL(oFilePickerDlg.getDisplayDirectory())


' obté la imatge triada
sFitxers = oFilePickerDlg.getFiles()
If UBound( sFitxers ) - LBound( sFitxers ) + 1 > 0 Then
sImatge = ConvertFromURL( sFitxers(0) )
Else
sImatge = ""
EndIf


' ajusta el camp de text
oDialeg1.getControl("txtImatge").text = sImatge
end sub


' Fa l'anàlisi OCR
Sub OCR
Dim sParametres as String
Dim sFitxerSortida as String


' obtè els paràmetres des dels camps de text
' per si l'usuari els ha modificat a ma
sNomFitxerText = oDialeg1.getControl("txtFitxerText").text
sImatge = oDialeg1.getControl("txtImatge").text
sCarpeta = oDialeg1.getControl("txtCarpeta").text


' missatge indicant el que va a fer
msgbox "Va a analitzar la imatge " & sImatge & " de la carpeta " & chr(13) & chr(10) & _
"i guardarà l'anàlisi a " & sCarpeta & " en el fitxer " & sNomFitxerText


' de l'OpenOffice.org Wiki:
' Shell(Pathname, Windowstyle, Param, bSync) de la Wiki OooBasic RTL d'OpenOffice
' Pathname
' the path of the program to be executed.


' In MS-Windows, use ConvertToURL(Pathname) otherwise the command will not work
' if Pathname contains spaces or national characters.
'
' Windowstyle
' the window in which the program is started.
' The following values are possible:
'
' * 0 - program receives the focus and is started in a concealed window.
' * 1 - program receives the focus and is started in a normal-sized window.
' * 2 - program receives the focus and is started in a minimized window.
' * 3 - program receives the focus and is started in a maximized window.
' * 4 - program is started in a normal-sized window, without receiving the focus.
' * 6 - program is started in a minimized window, the focus remains in the current window.
' * 10 - program is started in full screen mode.
'
' Param
' command line parameters to be transferred to the program to be started.
'
' bSync
' wait for shell command to finish flag
'
' * true - wait for shell command to finish
' * false - don't wait for shell command to finish


' Tesseract
' Usage:tesseract imagename outputbase [-l lang] [configfile [[+|-]varfile]...]


' posa els paràmetres corresponents a paths de fitxers entre cometes
' una millora seria afegir el llenguatge de l'anàlisi
' ara només considera el castellà (paràmetre -l spa)
sFitxerSortida = chr(34) & sCarpeta & "/" & sNomFitxerText & chr(34)
sParametres = chr(34) & sImatge & chr(34) & " " & sFitxerSortida & " -l spa"


' depenent de si és Linux o Windows invoca per una banda o altre
' en el cas de windows, cal que tesseract.exe estigui instal·lat
' a la carpeta c:\tesseract-ocr
if EsLinux() then
Shell("/usr/bin/tesseract", 6, sParametres, true)
else
Shell("c:\tesseract-ocr\tesseract.exe", 6, sParametres, true)
end if


' cal concatenar el .txt
If FileExists(sCarpeta & "/" & sNomFitxerText & ".txt") Then
MsgBox("Fet")
' importa el fitxer
ImportaFitxer(sCarpeta & "/" & sNomFitxerText & ".txt")
else
MsgBox("No s'ha generat el fitxer de sortida")
End If
End Sub


' El fitxer generat és text pla amb encoding UTF8
' per tant, cal activar aquest filtre d'importació
sub ImportaFitxer(sFitxerSortida as String)
Dim oMediaDescriptor(1) as new com.sun.star.beans.PropertyValue
sFileUrl = convertToUrl(sFitxerSortida)
oMediaDescriptor(0).name = "FilterName"
oMediaDescriptor(0).value = "Text (encoded)"
oMediaDescriptor(1).name = "FilterOptions"
oMediaDescriptor(1).value = "UTF8"
oDoc = StarDesktop.loadComponentFromURL(sFileURL, "_blank", 0, oMediaDescriptor)
end sub


' tanca el diàleg
Sub Sortir
oDialeg1.endExecute()
End sub


La interfase gràfica serà el següent formulari. faig un nou diàleg dins de la llibreria tesseract, i l'anomeno TesseractWrapperDialog.


De dalt a baix, els camps de text els anomeno: txtImatge, txtCarpeta i txtFitxerText

I associo els botons als procediments de la macro:

Botó "imatge a analitzar", al procediment TriaImatge.
Botó "carpeta on guardarà el fitxer de text", al procediment TriaCarpeta.
Botó "Fer l'OCR", al procediment OCR.
Botó "Sortir", al procediment Sortir.

Si ara executo directament el procediment ObrirDialeg, per exemple, des del menú de macros, ja podré provar el wrapper (tesseract en la versió 2 i sense llibreries addicionals no reconeix gaires formats, proveu amb BMP o amb TIFF NO comprimit)

Però el que de debò interessa en aquest exemple és preparar un add-on per a poder desplegar el wrapper.

El procediment general està explicat en el capítol Extensions de la Developer's guide.

Crear una carpeta en la que construiré el projecte d'add-on, dins d'aquesta carpeta creo una subcarpeta "tesseract". En aquesta subcarpeta hi copio els fitxers continguts a la carpeta $HOME/.openoffice.org/3/user/basic/tesseract

Hi trobo quatre fitxers: dialog.xlb, script.xlb, Module1.xba i TesseractWrapperDialog.xdl

Module1.xba i TesseractWrapperDialog.xdl corresponen respectivament al codi de la macro i a la definició en format xml del formulari del diàleg

script.xlb és la llista, en format xml, dels mòduls de la llibreria.
dialog.xlb és,. al seu torn, la llista dels diàlegs de la llibreria.

Em situo de nou a la carpeta superior, al mateix nivell que la carpeta tesseract creo una carpeta META-INF. En aquesta carpeta hi poso el manifest.xml que conté la llista de fitxers que s'estan desplegant:


<manifest:manifest>
<manifest:file-entry manifest:full-path="tesseract/" manifest:media-type="application/vnd.sun.star.basic-library">
<manifest:file-entry manifest:full-path="addon.xcu" manifest:media-type="application/vnd.sun.star.configuration-data">
</manifest:file-entry></manifest:file-entry>
</manifest:manifest>



En aquest manifest estic declarant que la carpeta tesseract conté una llibreria de macros i diàlegs d'OOoBasic. També estic declarant que hi ha un fitxer addon.xcu que conté la configuració de l'aplicació.

Addon.xcu s'ubica en l'arrel de la carpeta de projecte, és dir al mateix nivell que les carpetes teseract i META-INF.

El fitxer addon.xcu descriu que cal modificar la interfase gràfica del context de l'OpenOffice.org Writer per afegir-hi una entrada de menú "OCR" amb un item "Wrapper Tesseract OCR" que invoca la macro que obre el diàleg (amb la URL: macro:tesseract.Module1.ObrirDialeg).



<oor:component-data oor:name="Addons" oor:package="org.openoffice.Office" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<node oor:name="AddonUI">
<node oor:name="OfficeMenuBar">
<node oor:name="com.serveisticiprogramarilliure.openoffice.ocr" oor:op="replace">
<prop oor:name="Title" oor:type="xs:string">
<value>OCR</value>
</prop>


<prop oor:name="Target" oor:type="xs:string">
<value>_self</value>
</prop>


<node oor:name="Submenu">
<node oor:name="m1" oor:op="replace">


<prop oor:name="URL" oor:type="xs:string">
<value>macro:tesseract.Module1.ObrirDialeg</value>
</prop>


<prop oor:name="Title" oor:type="xs:string">
<value>Wrapper Tesseract OCR</value>
</prop>


<prop oor:name="Target" oor:type="xs:string">
<value>_self</value>
</prop>


<prop oor:name="Context" oor:type="xs:string">
<value>com.sun.star.text.TextDocument</value>
</prop>


</node>
</node>
</node>
</node>
</node>
</oor:component-data>


Addicionalment, podríem afegir un fitxer de descripció description.xml

És dir

temporal-projecte (carpeta)
    addon.xcu
    META-INF (carpeta)
        manifest.xml
    tesseract (carpeta)
        dialog.xlb
        script.xlb
        Module1.xba
        TesseractWrapperDialog.xdl

Practicament ja està, ara només cal fer un zip amb el contingut de la carpeta temporal-projecte i renombrar aquest zip a .oxt

per provar que el .oxt es deplega correctament he d'eliminar primer la macro i el diàleg que he creat. Això puc fer-ho amb l'organitzador de macros.

Un cop eliminat els rastres, aleshores només cal obrir el fitxer .oxt amb l'OpenOffice.org. Al fer-ho s'activa el gestor d'extensions. També podria desplegar el .oxt directament des del gestor d'extensions i també des de la línia d'ordres amb l'eina unopkg.


Albert Baranguer
21/11/2010 - Barcelona 

dilluns, 8 de novembre del 2010

Neix el Col·legi d'Enginyers Tècnics i Perits de Telecomunicació de Catalunya

El passat dijous 4 de novembre es va realitzar la presentació pública del Col·legi  d'Enginyers Tècnics i Perits de Telecomunicació de Catalunya

El Col·legi neix fruit de la segregació de la demarcació territorial catalana del Col·legi estatal. 

El nou col·legi pretén ser un referent en el món professional de les TIC a Catalunya, en particular amb el relacionat amb els serveis telemàtics.

En aquest enllaç del mateix Col·legi podem trobar una petita crònica de l'esdeveniment.



Com fer un component UNO amb java

El capítol clau del Developer's Guide (DG) és http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Writing_UNO_Components
En particular: http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Simple_Component_in_Java

El procés general queda descrit en aquesta esquema extret de JavaEclipse tutorial i que ja hem presentat en un post anterior


El que faré serà seguir aquest esquema aplicant-lo al codi d'exemple inclòs a l'SDK de l'OpenOffice.org.

Desenvoluparé aquest experiment sobre un Ubuntu 10.04 Lucid Lynx amb un OpenOffice.org 3.2.

En altres plataformes i versions les ubicacions poden ser diferents.

El codi d'exemple és el MinimalComponent que es troba a /opt/openoffice.org/basis3.2/sdk/examples/java/MinimalComponent/

El contingut de la carpeta és el següent:

BuildMinimalComponent.xml: un fitxer build d'ant per a generar el component. Lamentablement les ubicacions corresponen a les d'OpenOffice.org sobre Windows i cal corregir les adreces.

Makefile: un makefile per a generar el component fent servir el tradicional make.

MinimalComponent.idl: El primer pas per a crear un component és definir-ne la seva interfase. Tots els components han d'implementar certes interfases. El que es fa en l'exemple és crear un component que implementa una d'aquestes interfases obligatòries: la com/sun/star/lang/XServiceInfo.idl la qual proporciona mètodes que informen sobre les serveis que implementa el component.

Un component útil tindria una interfase específica que es definiria al fitxer .idl i, a més, també implementarà les interfases obligatòries (XServiceInfo, XInitialize i XTypeProvider).

El llenguatge de deficició de interfases idl de UNO, el UNOIDL, es descriu en el capítol del DG: http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Using_UNOIDL_to_Specify_New_Components.
També és interessant consultar http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Generating_Source_Code_from_UNOIDL_Definitions


MinimalComponent.java: La implementació del component. He dit abans que tots els components han d'implementar obligatòriament XServiceInfo, XInitialize i XTypeProvider. El que es fa en aquesta classe és heredar de WeakBase que ja implementa XTypeProvider, de forma que només resta per implementar XServiceinfo i XInitialize. WeakBase és una de les classes que es poden fer servir de base per a implementar components (Al DG les en diuen Helper Classes).

TestMinimalComponent.java: Finalment, una classe conductora per a provar  el component que hem creat. Hi trobem codi per a instanciar el nou component i executar-ne els mètodes de la seva interfase.

El que faré serà seguir pas a pas el diagrama. Així doncs, el primer de tot és compilar la descripció de la interfase. Això es fa amb la utilitat idlc (IDL compiler) de l'SDK de l'OpenOffice.org.

En el meu cas, he creat un projecte de java nou amb l'Eclipse i hi he copiat la carpeta MinimalComponent sencera.

Observant amb atenció l'esquema, s'observa que té dues entrades possibles.
- a partir del .idl
- a partir del .java


compilar .idl (especificació)

La primera cadena, a partir de l'idl,

Em situo en aquesta carpeta i invoco l'idlc tenint en compte que em caldrà incloure la definició (amb opció -I) de la XServiceInfo.

Això últim es fa evident sense més que examinar MinimalComponent.idl

#ifndef _org_openoffice_MinimalComponent_idl_ 
#define _org_openoffice_MinimalComponent_idl_ 


#include <com/sun/star/lang/XServiceInfo.idl> 


// org
module org {
    // openoffice
    module openoffice {
        // example service, XServiceInfo is implemented here for demonstration
        // issues. XServiceInfo must be implemented by all components. But
        // here it is used to show the new code generation feature for services.
        // See the TestMinimalComponent.java how it can be used!
        service MinimalComponent: ::com::sun::star::lang::XServiceInfo;
    };
};


#endif 


Per compilar l'idl, doncs, faig servir la següent instrucció

/opt/openoffice.org/basis3.2/sdk/bin/idlc -I /opt/openoffice.org/basis3.2/sdk/idl MinimalComponent.idl

El resultat és el fitxer MinimalComponent.urd  que hauria de contenir la definició del nou tipus descrit per la interfase. Cal incloure aquesta nova definició a un Registre de tipus per a que es pugui invocar i sigui utilitzable. (per a més detalls sobre el registre, consulteu  la DG, http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/WritingUNO/Running_and_Debugging_Java_Components)

Això ho faig amb el programa regmerge.

/opt/openoffice.org/ure/bin/regmerge MinimalComponent.rdb /UCR MinimalComponent.ure

Amb el que obtinc una base de dades de registre: el fitxer MinimalComponent.rdb.

Ara bé, si observem el contingut d'aquesta base de dades de registre amb l'eina regview /opt/openoffice.org/ure/bin/regview ./MinimalComponent.rdb (suposant que estic a la mateixa carpeta que el .rdb), obtinc:


/
 / UCR
   / org
     / openoffice
       / MinimalComponent
         Value: Type = RG_VALUETYPE_BINARY
                Size = 142
                Data = version: 1
                       documentation: ""
                       file name: ""
                       type class: service
                       type name: "org/openoffice/MinimalComponent"
                       super type count: 1
                       super type name 0: "com/sun/star/lang/XServiceInfo"
                       field count: 0
                       method count: 1
                       method 0:
                           documentation: ""
                           flags: synchronous
                           name: ""
                           return type name: "void"
                           parameter count: 0
                           exception count: 0
                       reference count: 0


       Value: Type = RG_VALUETYPE_BINARY
              Size = 57
              Data = version: 0
                     documentation: ""
                     file name: ""
                     type class: module
                     type name: "org/openoffice"
                     super type count: 0
                     field count: 0
                     method count: 0
                     reference count: 0


     Value: Type = RG_VALUETYPE_BINARY
            Size = 46
            Data = version: 0
                   documentation: ""
                   file name: ""
                   type class: module
                   type name: "org"
                   super type count: 0
                   field count: 0
                   method count: 0
                   reference count: 0




El pas següent és  invocar el javamaker per a obtindre els .class corresponents al nou servei (org.openoffice.MinimalComponent)

La sintaxi d'us de javamaker és:

/opt/openoffice.org/basis3.2/sdk/bin/javamaker -BUCR -Torg.openoffice.MinimalComponent -nD /opt/openoffice.org/ure/share/misc/types.rdb ./MinimalComponent.rdb

I obtinc la classe

org.openoffice.MinimalComponent

He d'afegir la classe al classpath per a compilar la MinimalComponent de la implementació (és dir, la classe que està en Default Package) que és el segon camí d'entrada descrit en l'esquema.


compilar .java (implementació)

En el cas del MinimalComponent.java  n'hi ha prou amb afegir org.openoffice.MinimalComponent al build, compilar i empaquetar amb jar, indicant en el manifest del META-INF que la classe a registrar és MinimalComponent, això ho aconseguiré amb el següent build.xml per a l'ant. És interessant remarcar quines són les llibreries utilitzades en el classpath (en negreta): les mateixes que per a compilar una macro java  i les d'addcionals,  officebean.jar i unoloader.jar.

<project name="ComponentUNO" default="jar" basedir=".">
  <description>
  genera el zip del component UNO per a l'OpenOffice
  </description>

  <!-- estableix propietats globals -->
  <property name="src" location="src"/>
  <property name="build" location="build"/>
  <property name="dist"  location="jar"/>
  <property name="zip.dir"  location="ComponentUNO"/>
  <property name="cp-java-OOo-1" location="/opt/openoffice.org/ure/share/java/" />
  <property name="cp-java-OOo-2" location="/opt/openoffice.org/basis3.2/program/classes/" />
  <property name="OOo-user-macros" location="/home/albert/.openoffice.org/3/user/Scripts/java/" />
  <property name="OOo-shared-macros" location="/opt/openoffice.org/basis3.2/share/Scripts/java/" />



  <target name="init">
    <!-- time stap -->
    <tstamp/>
    <!-- Crea el directory build utilitzat en la compilació -->
    <mkdir dir="${build}"/>
  </target>


  <target name="compile" depends="init" description="compila els fitxers font" >
    <!-- Compila les fonts java de ${src} en ${build} -->
    <javac srcdir="${src}" destdir="${build}">
      <classpath>
       <pathelement location="${cp-java-OOo-1}/juh.jar"/>
        <pathelement location="${cp-java-OOo-1}/jurt.jar"/>
       <pathelement location="${cp-java-OOo-1}/ridl.jar"/>
       <pathelement location="${cp-java-OOo-1}/unoloader.jar"/>
       <pathelement location="${cp-java-OOo-2}/unoil.jar"/>
       <pathelement location="${cp-java-OOo-2}/officebean.jar"/>
      </classpath>
   </javac>
  </target>




  <target name="jar" depends="compile" description="genera el jar">
    <!-- Crea el directori de distribució -->
    <mkdir dir="${dist}"/>


    <jar jarfile="${dist}/MinimalComponent.1.uno.jar" basedir="${build}"> 
      <include name="**/*.class"/>
      <manifest>
        <attribute name="RegistrationClassName" value="MinimalComponent"/>
      </manifest>
    </jar>
  </target>


</project>



En compilar amb ant, obtinc el jar MinimalComponent.1.one.jar
En aquest punt, ja tinc el component. Com provar-lo? Primer cal fer-ne el desplegament. Un cop desplegat, escriuré una macro amb OOoBasic que n'invoqui un mètode.

En aquest punt  deixaré de seguir l'esquema.

L'eina per a registrar components des de les primeres versions de l'OpenOffice.org ha estat regcomp. Tanmateix, aquesta eina ha estat superada per eines posteriors i des de fa algunes versions el que es pot fer servir és l'eina unopkg.

L'eina unopkg permet desplegar  components en java (.jar), en c++ (.so o .dll), add-ons (.oxt)...  A més, és una eina que es pot fer servir des de línia d'ordres, però també es pot usar com una GUI. De fet, la GUI que activa és la mateixa que la del gestor d'extensions  de l'OpenOffice.org. El capítol de la DG que parla d'això és el de les Extensions.

Per tant,  executo '/opt/openoffice.org3/program/unopkg gui' i puc registrar el meu component fàcilment. Recordar que el path fins unopkg '/opt/openoffice.org3/program/' pot ser un de diferent a altres versions  d'Ubuntu i d'OpenOffice.org.

Se m'obre el gestor d'extensions on puc veure les extensions que tinc instal·lades:


Faig click a "Afegeix..."


Trio el tipus de fitxer  "Component Java UNO"


Obro i el meu component queda instal·lat


Si el vull desinstal·lar, puc fer-ho des del mateix gestor d'extensions.

Finalment, per acabar, provaré que el nou component es utilitzable. Creo una petita macro que l'invoca. 
Primer de tot engego l'OpenOffice.org, vaig a l'editor de macros. La macro que escric utilitza la popular  XrayTool per analitzar l'objecte UNO que he creat. A continuació invoco el mètode getImplementationName().

Sub Main
    provaComponentUNO
End Sub

sub provaComponentUNO
    Dim oMinimal as Object

    BasicLibraries.loadLibrary("XrayTool")

oMinimal = CreateUnoService("org.openoffice.MinimalComponent")
xray oMinimal
msgbox oMinimal.getImplementationName()
end sub

A  MinimalComponent.java trobem l'explicació de l'argument de CreateUnoService:

public class MinimalComponent {
    /** This class implements the component. At least the interfaces XServiceInfo,
     * XTypeProvider, and XInitialization should be provided by the service.
     */
    public static class _MinimalComponent extends WeakBase
        implements XInitialization, XServiceInfo {
        /** The service name, that must be used to get an instance of this service.
         */
        static private final String __serviceName =
        "org.openoffice.MinimalComponent";


El resultat de l'execució és:


i, finalment:



Albert Baranguer
Barcelona, 08/11/2010