Difference between revisions of "UNO component packaging"

From Apache OpenOffice Wiki
Jump to: navigation, search
m
(More information on scripts, reorganization of the page)
Line 1: Line 1:
=Python UNO component=
+
{{Documentation/DevGuide/ScriptingTOC
This page shows you how to pack and deploy already written UNO component. I'm using my ''Wavelet'' class as an example of a very simple component.  
+
|ShowPrevNext=block
 +
|PrevPage=Documentation/DevGuide/Scripting/Macro Recording
 +
|NextPage=Documentation/DevGuide/Scripting/How the Scripting Framework Works
 +
}}
 +
{{Documentation/DevGuideLanguages|Documentation/DevGuide/Scripting/{{SUBPAGENAME}}}}
 +
{{DISPLAYTITLE:Writing Macros}}
 +
__NOTOC__
 +
=== The HelloWorld macro ===
 +
Here is a comparison of HelloWorld macros in the different script languages available in {{PRODUCTNAME}}.
  
More detailed info is in the [[http://api.openoffice.org/docs/DevelopersGuide/Components/Components.htm Developers Guide]].
+
==== Basic ====
 +
<source lang="oobas">
 +
Sub writeHelloWorld()
 +
Dim oDoc As Object, xText As Object, xTextRange As Object
  
=Python loader=
+
oDoc = ThisComponent
The Python loader is not able load classes that are not it its own path. Thus it's necessary to copy any classes or modules you will use into the OPenOffice Python lib directory, and it may be necessary to restart OOo before they are picked up.
+
xText = oDoc.getText()
 +
xTextRange = xText.getEnd()
 +
xTextRange.CharBackColor = 1234567
 +
xTextRange.CharHeight = 16.0
 +
' CharUnderline receives a group constant
 +
xTextRange.CharUnderline = com.sun.star.awt.FontUnderline.WAVE
 +
' CharPosture receives an enum
 +
xTextRange.CharPosture = com.sun.star.awt.FontSlant.ITALIC
 +
xTextRange.setString( "Hello World (in Basic)" )
 +
End Sub
 +
</source>
 +
Basic interprets pairs of get and set methods at UNO objects as object properties if they follow this pattern:
  
=Sample Python component=
+
  SomeType getSomeProperty()
 +
  void setSomeProperty(SomeType aValue)
  
==Wavelet class==
+
Using these facilities some lines can be simplified:
We will use my sample ''Wavelet'' class which replaces space with non breaking space before the Czech prepositions. Put the following code in the ''Wavelet.py'' file.
+
<source lang="oobas">
 +
xText = oDoc.Text
 +
xTextRange = xText.End
 +
xTextRange.String = "Hello World (in Basic)"
 +
</source>
  
<source lang=python>
+
Service properties can be directly accessed in Basic, it is not necessary to use <code>getPropertyValue</code> or <code>setPropertyValue</code> methods.
  
import uno
+
==== BeanShell ====
import unohelper
+
As BeanShell accepts typeless variables, the code is simplified compared to Java.
from com.sun.star.task import XJobExecutor
+
<source lang="java">
 +
import com.sun.star.uno.UnoRuntime;
 +
import com.sun.star.text.XTextDocument;
 +
import com.sun.star.text.XText;
 +
import com.sun.star.text.XTextRange;
 +
import com.sun.star.beans.XPropertySet;
 +
import com.sun.star.awt.FontSlant;
 +
import com.sun.star.awt.FontUnderline;
  
class Wavelet( unohelper.Base, XJobExecutor ):
+
oDoc = XSCRIPTCONTEXT.getDocument();
    def __init__( self, ctx ):
+
        self.ctx = ctx
+
+
    def trigger( self, args ):
+
        desktop = self.ctx.ServiceManager.createInstanceWithContext(
+
            "com.sun.star.frame.Desktop", self.ctx )
+
+
        doc = desktop.getCurrentComponent()
+
+
        try:
+
            search = doc.createSearchDescriptor()
+
            search.SearchRegularExpression = True
+
            search.SearchString = "\\<(k|s|v|z|o|u|i|a) "
+
           
+
            found = doc.findFirst( search )
+
            while found:
+
                found.String = found.String.replace( " ", u"\xa0" )
+
                found = doc.findNext( found.End, search)
+
+
        except:
+
            pass
+
</source>
+
  
 +
xTextDoc = UnoRuntime.queryInterface(XTextDocument.class,oDoc);
 +
xText = xTextDoc.getText();
 +
xTextRange = xText.getEnd();
 +
pv = UnoRuntime.queryInterface(XPropertySet.class, xTextRange);
  
 +
pv.setPropertyValue("CharBackColor", 1234567);
 +
pv.setPropertyValue("CharHeight", 16.0);
 +
// CharUnderline receives a group constant
 +
pv.setPropertyValue("CharUnderline", com.sun.star.awt.FontUnderline.WAVE);
 +
// CharPosture receives an enum
 +
pv.setPropertyValue("CharPosture", com.sun.star.awt.FontSlant.ITALIC) ;
  
==Wavelet class registration==
+
xTextRange.setString( "Hello World (in BeanShell)" );
You have to tell the OpenOffice.org what is the main class of your component. Put the following code at the end of your ''Wavelet.py'' file.
+
return 0;
 +
</source>
  
<source lang=python>
+
BeanShell interprets pairs of get and set methods at UNO objects as object properties if they follow this pattern:
g_ImplementationHelper = unohelper.ImplementationHelper()
+
g_ImplementationHelper.addImplementation(
+
        Wavelet,
+
        "name.vojta.openoffice.Wavelet",
+
        ("com.sun.star.task.Job",),)
+
</source>
+
  
 +
  SomeType getSomeProperty()
 +
  void setSomeProperty(SomeType aValue)
  
 +
Using these facilities some lines can be simplified:
  
=Component integration=
+
<source lang="java">
 +
  xText = xTextDoc.Text;
 +
  xTextRange = xText.End;
 +
  xTextRange.String = "Hello World (in BeanShell)";
 +
</source>
  
==Icons==
+
Service properties are only accessed with <code>getPropertyValue</code> or <code>setPropertyValue</code>.
You can create your own icons for the Menu item or the Toolbar button. The easiest way is to create two true color BMP files - the first one should be 26×26 and the second one should be 16×16.  
+
  
If you want to use alpha (transparent color), use ''#FF00FF'' (RGB) color.  
+
==== JavaScript ====
 +
As JavaScript accepts typeless variables, the code is simplified compared to Java.
 +
<source lang="javascript">
 +
importClass(Packages.com.sun.star.uno.UnoRuntime)
 +
importClass(Packages.com.sun.star.text.XTextDocument)
 +
importClass(Packages.com.sun.star.text.XText)
 +
importClass(Packages.com.sun.star.text.XTextRange)
 +
importClass(Packages.com.sun.star.beans.XPropertySet)
 +
importClass(Packages.com.sun.star.awt.FontSlant)
 +
importClass(Packages.com.sun.star.awt.FontUnderline)
  
This possibility is optional and you're not forced to create icons.  
+
oDoc = XSCRIPTCONTEXT.getDocument()
 +
xTextDoc = UnoRuntime.queryInterface(XTextDocument,oDoc)
 +
xText = xTextDoc.getText()
 +
xTextRange = xText.getEnd()
 +
pv = UnoRuntime.queryInterface(XPropertySet, xTextRange)
  
==Addons.xcu==
+
pv.setPropertyValue("CharHeight", 16.0) // Double
Component integration configuration is in the ''Addons.xcu'' file.  
+
// CharBackColor receives an Integer
 +
pv.setPropertyValue("CharBackColor", new java.lang.Integer(1234567))
 +
// CharUnderline receives a group constant
 +
pv.setPropertyValue("CharUnderline",
 +
  new java.lang.Short(Packages.com.sun.star.awt.FontUnderline.WAVE))
 +
// CharPosture receives an enum
 +
pv.setPropertyValue("CharPosture", Packages.com.sun.star.awt.FontSlant.ITALIC)
 +
xTextRange.setString( "Hello World (in JavaScript)" )
 +
</source>
  
===Header===
+
JavaScript does not accept the simplifications seen in Basic and BeanShell.
The header of this file should contain:
+
  
<source lang=xml>
+
Setting an integer value to a property requires to use a java class.
<?xml version="1.0" encoding="UTF-8"?>
+
<oor:component-data xmlns:oor="http://openoffice.org/2001/registry"
+
  xmlns:xs="http://www.w3.org/2001/XMLSchema" oor:name="Addons"
+
  oor:package="org.openoffice.Office">
+
+
    <node oor:name="AddonUI">
+
</source>
+
  
 +
==== Java ====
 +
Other sections of this document provide numerous Java examples. Here is the HelloWorld provided in {{PRODUCTNAME}}
 +
<source lang="java">
 +
  import com.sun.star.uno.UnoRuntime;
 +
  import com.sun.star.frame.XModel;
 +
  import com.sun.star.text.XTextDocument;
 +
  import com.sun.star.text.XTextRange;
 +
  import com.sun.star.text.XText;
 +
  import com.sun.star.script.provider.XScriptContext;
 +
 
 +
  public class HelloWorld {
 +
      public static void printHW(XScriptContext xScriptContext)
 +
      {
 +
          XModel xDocModel = xScriptContext.getDocument();
 +
   
 +
          // getting the text document object
 +
          XTextDocument xtextdocument = (XTextDocument) UnoRuntime.queryInterface(
 +
              XTextDocument.class, xDocModel);
 +
     
 +
          XText xText = xtextdocument.getText();
 +
          XTextRange xTextRange = xText.getEnd();
 +
          xTextRange.setString( "Hello World (in Java)" );
 +
      }
 +
  }
 +
</source>
  
 +
===== Compiling and Deploying Java macros =====
  
===Office Menu Bar===
+
Because Java is a compiled language it is not possible to execute Java source code as a macro directly from within {{PRODUCTNAME}}. The code must first be compiled and then deployed within a {{PRODUCTNAME}} installation or document. The following steps show how to create a Java macro using the HelloWorld example code:
Following part creates new menu item ''Czech'' (or ''Cestina'', depends on the UI language) and the ''Wavelet'' menu item.  
+
  
This menu item is associated with the ''name.vojta.openoffice.Wavelet?execute'' ''URL''. It means, that when you click on the menuitem, ''Wavelet.trigger'' method will be executed with the ''execute'' as an argument.  
+
* Create a ''HelloWorld'' directory for your macro
 +
* Create a ''HelloWorld.java'' file using the HelloWorld source code
 +
* Compile the ''HelloWorld.java'' file. The following jar files from the ''program/classes'' directory of a {{PRODUCTNAME}} installation must be in the classpath: ''ridl.jar'', ''unoil.jar'', ''jurt.jar''
 +
* Create a ''HelloWorld.jar'' file containing the ''HelloWorld.class'' file
 +
* Create a ''parcel-descriptor.xml'' file for your macro
 +
<source lang="xml">
 +
  <?xml version="1.0" encoding="UTF-8"?>
 +
 
 +
  <parcel language="Java" xmlns:parcel="scripting.dtd">
 +
    <script language="Java">
 +
      <locale lang="en">
 +
        <displayname value="HelloWorld"/>
 +
        <description>
 +
          Prints "Hello World".
 +
        </description>
 +
      </locale>
 +
      <functionname value="HelloWorld.printHW"/>
 +
      <logicalname value="HelloWorld.printHW"/>
 +
      <languagedepprops>
 +
          <prop name="classpath" value="HelloWorld.jar"/>
 +
      </languagedepprops>
 +
    </script>
 +
  </parcel>
 +
</source>
 +
The ''parcel-descriptor.xml'' file is used by the Scripting Framework to find macros. The functionname element indicates the name of the Java method which should be executed as a macro. The classpath element can be used to indicate any jar or class files which are used by the macro. If the classpath element is not included, then the directory in which the ''parcel-desciptor.xml'' file is found and any jar files in that directory will be used as the classpath. The necessary Java UNO classes are available automatically.
  
This menu will be visible in the OpenOffice.org Writer only.  
+
* Copy the HelloWorld directory into the ''share/Scripts/java'' directory of a {{PRODUCTNAME}} installation or into the ''user/Scripts/java'' directory of a user installation. If you want to deploy the macro to a document you need to place it in a ''Scripts/java'' directory within the document zip file.
 +
* If {{PRODUCTNAME}} is running, you will need to restart it in order for the macro to appear in the Macro Selector dialog.
  
<source lang=xml>
+
{{Documentation/Note|The ''parcel-descriptor.xml'' file is also used to detect BeanShell and JavaScript macros. It is created automatically when creating macros using the Organizer dialogs for BeanShell and JavaScript.}}
        <node oor:name="OfficeMenuBar">
+
            <node oor:name="name.vojta.openoffice.Wavelet" oor:op="replace">
+
                <prop oor:name="Title" oor:type="xs:string">
+
                    <value/>
+
                    <value xml:lang="en-US">Czech</value>
+
                    <value xml:lang="cs">Cestina</value>
+
                </prop>
+
                <prop oor:name="Target" oor:type="xs:string">
+
                    <value>_self</value>
+
                </prop>
+
                <prop oor:name="ImageIdentifier" oor:type="xs:string">
+
                    <value/>
+
                </prop>
+
                <node oor:name="Submenu">
+
                    <node oor:name="m1" oor:op="replace">
+
                        <prop oor:name="URL" oor:type="xs:string">
+
                            <value>service:name.vojta.openoffice.Wavelet?execute</value>
+
                        </prop>
+
                        <prop oor:name="Title" oor:type="xs:string">
+
                            <value/>
+
                            <value xml:lang="en-US">Wavelet</value>
+
                            <value xml:lang="cs">Vlnka</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>
+
</source>
+
  
 +
==== Python ====
  
 +
A Python module may contain several scripts.
 +
<source lang="python">
 +
def HelloPython( ):
 +
import uno
  
===Office Toolbar===
+
def HelloPython( ):
Following part creates new toolbar (with name ''Add-on 1'', ''Add-on 2'', …) and one button. This button is associated with the ''name.vojta.openoffice.Wavelet?execute'' ''URL''. It means that the ''Wavelet.trigger'' method will be executed when you click on the button on the toolbar. ''execute'' will be passed as an argument.  
+
    oDoc = XSCRIPTCONTEXT.getDocument()
 +
    xText = oDoc.getText()
 +
    xTextRange = xText.getEnd()
 +
   
 +
    xTextRange.CharHeight = 16.0
 +
    xTextRange.CharBackColor = 1234567
 +
    # CharUnderline receives a group constant
 +
    xTextRange.CharUnderline = uno.getConstantByName("com.sun.star.awt.FontUnderline.WAVE")
 +
    # CharPosture receives an enum
 +
    xTextRange.CharPosture = uno.getConstantByName("com.sun.star.awt.FontSlant.ITALIC")
 +
   
 +
    xTextRange.setString( "Hello World (in Python)" )
 +
    return None
 +
</source>
 +
Python interprets pairs of get and set methods at UNO objects as object properties if they follow this pattern:
  
'''Note:''' You can't rename the toolbar. It's due to the backwards compatibility with the 1.1.x version.
+
  SomeType getSomeProperty()
 +
  void setSomeProperty(SomeType aValue)
  
<source lang=xml>
+
Using these facilities some lines can be simplified:
        <node oor:name="OfficeToolBar">
+
<source lang="python">
            <node oor:name="name.vojta.openoffice.Wavelet" oor:op="replace">
+
    xText = oDoc.Text
                <node oor:name="m1" oor:op="replace">
+
    xTextRange = xText.End
                    <prop oor:name="URL" oor:type="xs:string">
+
    xTextRange.String = "Hello World (in Python)"
                        <value>service:name.vojta.openoffice.Wavelet?execute</value>
+
                    </prop>
+
                    <prop oor:name="ImageIdentifier" oor:type="xs:string">
+
                        <value/>
+
                    </prop>
+
                    <prop oor:name="Title" oor:type="xs:string">
+
                        <value/>
+
                        <value xml:lang="en-US">Wavelet</value>
+
                        <value xml:lang="cs">Vlnka</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>
+
 
</source>
 
</source>
 +
Service properties can be directly accessed in Python, no need to use <code>getPropertyValue</code> or <code>setPropertyValue</code>.
  
 +
=== Features of script languages supported by {{PRODUCTNAME}} ===
  
 +
{|border="1" cellpadding=4 style="border-collapse:collapse;"
 +
|-bgcolor=#EDEDED
 +
!Language feature
 +
!Basic
 +
!BeanShell
 +
!JavaScript
 +
!Java macro
 +
!Python
 +
|-
 +
|Interpreted
 +
|Yes
 +
|Yes
 +
|Yes
 +
|No
 +
|Yes
 +
|-
 +
|Integrated editor
 +
|Yes, colored
 +
|Yes
 +
|Yes
 +
|No
 +
|No
 +
|-
 +
|Integrated debugger
 +
|Yes
 +
|No
 +
|Yes
 +
|No
 +
|No
 +
|-
 +
|Script organizer
 +
|Yes
 +
|Yes
 +
|Yes
 +
|No
 +
|No
 +
|-
 +
|Script encryption
 +
|Possible
 +
|No
 +
|No
 +
|No
 +
|No
 +
|-
 +
|Typeless variables
 +
|Yes: Variant
 +
|Yes
 +
|Yes
 +
|No
 +
|Yes
 +
|-
 +
|Getter/Setter
 +
|Yes
 +
|Yes
 +
|No
 +
|No
 +
|Yes
 +
|-
 +
|Direct property access
 +
|Yes
 +
|No
 +
|No
 +
|No
 +
|Yes
 +
|-
 +
|Function for Calc formula
 +
|Yes
 +
|No
 +
|No
 +
|No
 +
|No
 +
|-
 +
|UNO component creation
 +
|No
 +
|No
 +
|No
 +
|Yes
 +
|Yes
 +
|}
  
===Icons===
 
You can associate your icons with any ''URL''. We will associate our icons with ''name.vojta.openoffice.Wavelet?execute'' ''URL''. It means that all controls (menu item, button, …) associated with the same ''URL'' will use these icons.
 
  
'''Note:''' %origin% is the UNO component package. We will explain it later.
+
=== Using the {{PRODUCTNAME}} API from macros ===
  
<source lang=xml>
+
BeanShell, JavaScript, Java, Python macros are supplied with a variable of type <idl>com.sun.star.script.provider.XScriptContext</idl> which can be used to access the {{PRODUCTNAME}} API. This interface has three methods:
        <node oor:name="Images">
+
            <node oor:name="name.vojta.openoffice.Wavelet.image1" oor:op="replace">
+
                <prop oor:name="URL">
+
                    <value>service:name.vojta.openoffice.Wavelet?execute</value>
+
                </prop>
+
                <node oor:name="UserDefinedImages">
+
                    <prop oor:name="ImageSmallURL" oor:type="xs:string">
+
                        <value>%origin%/images/WaveletSmall.bmp</value>
+
                    </prop>
+
                    <prop oor:name="ImageBigURL" oor:type="xs:string">
+
                        <value>%origin%/images/WaveletBig.bmp</value>
+
                    </prop>
+
                </node>
+
            </node>
+
</node>
+
</source>
+
  
 +
* <idl>com.sun.star.frame.XModel</idl> <code>getDocument( )</code>
 +
:Returns the <code>XModel</code> interface of the document for which the macro was invoked (see [[Documentation/DevGuide/OfficeDev/Using the Component Framework|Using the Component Framework]])
 +
* <idl>com.sun.star.frame.XDesktop</idl> <code>getDesktop( )</code>
 +
:Returns the <code>XDesktop</code> interface for the application which can be used to access open document, and load documents (see [[Documentation/DevGuide/OfficeDev/Using the Desktop|Using the Desktop]])
 +
* <idl>com.sun.star.uno.XComponentContext</idl> <code>getComponentContext( )</code>
 +
:Returns the <code>XComponentContext</code> interface which is used to create instances of services (see [[Documentation/DevGuide/ProUNO/Service Manager and Component Context|Service Manager and Component Context]])
  
 +
Depending on the language the macro accesses <code>XScriptContext</code> in different ways:
  
===Footer===
+
* '''BeanShell''': Using the global variable <code>XSCRIPTCONTEXT</code>
Close all opened sections.  
+
  oDoc = XSCRIPTCONTEXT.getDocument();
  
<source lang=xml>
+
* '''JavaScript''': Using the global variable <code>XSCRIPTCONTEXT</code>
    </node>
+
  oDoc = XSCRIPTCONTEXT.getDocument();
</oor:component-data>
+
</source>
+
  
=UNO component package=
+
* '''Java''': The first parameter passed to the macro method is always of type <code>XScriptContext</code>
UNO component package is a simple ZIP file. Obviously it contains the ''Addons.xcu'' file, ''images'' directory with icons and the Python component implementation.  
+
  Xmodel xDocModel = xScriptContext.getDocument();
  
==Packing==
+
* '''Python''': Using the global variable <code>XSCRIPTCONTEXT</code>
You can pack our sample package with the following command:
+
  oDoc = XSCRIPTCONTEXT.getDocument()
  
<source lang=bash>
+
=== Handling arguments passed to macros ===
zip -r Wavelet.uno.zip Addons.xcu Wavelet.py images
+
</source>
+
The final ''Wavelet.uno.zip'' package should contain these files:
+
  
<source lang=bash>
+
In certain cases arguments may be passed to macros, for example, when a macro is assigned to a button in a document. In this case the arguments are passed to the macro as follows:
Wavelet.uno.zip
+
  Addons.xcu
+
  Wavelet.py
+
  images/WaveletBig.bmp
+
  images/WaveletSmall.bmp
+
</source>
+
'''Note:''' The ''%origin%'' is ''Wavelet.uno.zip'', thus the ''%origin%/images/WaveletBig.bmp'' points to the ''WaveletBig.bmp'' file in your ''Wavelet.uno.zip'' file.
+
  
==Installation==
+
* '''BeanShell''': In the global <code>Object[]</code> variable <code>ARGUMENTS</code>
You can install your UNO component with the Extension manager (somewhere in the ''Tools'' menu) or with the ''unopkg'' tool.
+
  event = (ActionEvent) ARGUMENTS[0];
  
<source lang=bash>
+
* '''JavaScript''': In the global <code>Object[]</code> variable <code>ARGUMENTS</code>
/opt/openoffice.org1.9.103/program/unopkg add Wavelet.uno.zip
+
  event = ARGUMENTS[0];
</source>
+
  
==Uninstallation==
+
* '''Java''': The arguments are passed as an <code>Object[]</code> in the second parameter to the macro method
You can uninstall your UNO component with the Extension manager (somewhere in the ''Tools'' menu) or with the ''unopkg'' tool.
+
  public void handleButtonPress(
 +
      XScriptContext xScriptContext, Object[] args)
  
<source lang=bash>
+
Each of the arguments in the <code>Object[]</code> are of the UNO type Any. For more information on how the Any type is used in Java see [[Documentation/DevGuide/ProUNO/Java/Type Mappings|Type Mappings]].
/opt/openoffice.org1.9.103/program/unopkg remove Wavelet.uno.zip
+
</source>
+
  
=Python component testing=
+
The ButtonPressHandler macros in the Highlight library of a {{PRODUCTNAME}} installation show how a macro can handle arguments.
It's not necessary to install the Python UNO component to test it. You can connect to the running OpenOffice.org instance and test your UNO component directly.  
+
  
==Code==
+
* '''Python''': The arguments are passed as parameters of the called function.
Append the following code at the end of the ''Wavelet.py'' file.  
+
  
<source lang=python>
 
if __name__ == "__main__":
 
    import os
 
 
    # Start OpenOffice.org, listen for connections and open testing document
 
    os.system( "/etc/openoffice.org-1.9/program/soffice '-accept=socket,host=localhost,port=2002;urp;' -writer ./WaveletTest.odt &" )
 
 
    # Get local context info
 
    localContext = uno.getComponentContext()
 
    resolver = localContext.ServiceManager.createInstanceWithContext(
 
        "com.sun.star.bridge.UnoUrlResolver", localContext )
 
 
    ctx = None
 
 
    # Wait until the OO.o starts and connection is established
 
    while ctx == None:
 
        try:
 
            ctx = resolver.resolve(
 
                "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
 
        except:
 
            pass
 
 
    # Trigger our job
 
    wavelet = Wavelet( ctx )
 
    wavelet.trigger( () )
 
</source>
 
  
 +
=== Creating dialogs from macros ===
  
 +
Dialogs which have been built in the Dialog Editor can be loaded by macros using the <idl>com.sun.star.awt.XDialogProvider</idl> API. The method <code>createDialog()</code> from interface <code>XDialogProvider</code> uses a string as a parameter. This string is the URL to the dialog. It is formed as follows:
  
==Testing==
+
  vnd.sun.star.script:DIALOGREF?location=[application|document]
To test your UNO component, just run your ''Wavelet.py'' in the Python interpreter.  
+
  
<source lang=bash>
+
where <code>DIALOGREF</code> is the name of the dialog that you want to create, and location is either application or document depending on where the dialog is stored.
/opt/openoffice.org1.9.103/program/python ./Wavelet.py
+
 
</source>
+
For example if you wanted to load dialog called MyDialog, which is in a Dialog Library called MyDialogLibrary in the {{PRODUCTNAME}} dialogs area of your installation then the URL would be:
 +
 
 +
  vnd.sun.star.script:MyDialogLibrary.MyDialog?location=application
 +
 
 +
If you wanted to load a dialog called MyDocumentDialog which in a library called MyDocumentLibrary which is located in a document then the URL would be:
 +
 
 +
  vnd.sun.star.script:MyDocumentLibrary.MyDocumentDialog?location=document
 +
 
 +
The following code shows how to create a dialog from a Java macro:
 +
<source lang="java">
 +
  public XDialog getDialog(XScriptContext context)
 +
  {
 +
      XDialog theDialog;
 +
 
 +
      // We must pass the XModel of the current document when creating a DialogProvider object
 +
      Object[] args = { context.getDocument() };
 +
   
 +
      Object obj;
 +
      try {
 +
          obj = xmcf.createInstanceWithArgumentsAndContext(
 +
              "com.sun.star.awt.DialogProvider", args, context.getComponentContext());
 +
      }
 +
      catch (com.sun.star.uno.Exception e) {
 +
          System.err.println("Error getting DialogProvider object");
 +
          return null;
 +
      }
 +
 
 +
      XDialogProvider xDialogProvider = (XDialogProvider)
 +
          UnoRuntime.queryInterface(XDialogProvider.class, obj);
 +
     
 +
      // Got DialogProvider, now get dialog
 +
      try {
 +
          theDialog = xDialogProvider.createDialog(
 +
              "vnd.sun.star.script:MyDialogLibrary.MyDialog?location=application");
 +
      }
 +
      catch (java.lang.Exception e) {
 +
          System.err.println("Got exception on first creating dialog: " + e.getMessage());
 +
      }
 +
      return theDialog;
 +
  }
 +
</source>
  
==Resume==
+
=== Calling a macro with the Scripting Framework ===
This part does this:
+
  
starts OpenOffice.org and opens the ''WaveletTest.odt'' file
+
The service <idl>com.sun.star.script.provider.ScriptProvider</idl> exports interface <idls>com.sun.star.script.provider.XScriptProvider</idls> which offers method <code>getScript( )</code>. This method returns an interface <idls>com.sun.star.script.provider.XScript</idls> which offers the method <code>invoke( )</code> which will call the script with parameters if necessary.
  
loop until the connection will be established
+
The identity and location of the called script is contained in an URI, which follows a [[Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification|particular syntax]].
  
start your component in the running OpenOffice.org context
 
  
'''Note:''' Do not forget to remove this part before real UNO component packaging. Or comment it out.
+
Here are links to some code examples written by the community:
 +
* [http://codesnippets.services.openoffice.org/Office/Office.HowToCallJavaProgramUsingScriptingFramework.snip Java calling a Java script]
 +
* [http://www.oooforum.org/forum/viewtopic.phtml?t=69328 Java calling a Basic macro]
 +
* [http://www.oooforum.org/forum/viewtopic.phtml?t=59534 Basic macro calling a Python script]
 +
* [http://www.oooforum.org/forum/viewtopic.phtml?t=69350 Python script calling a Basic macro]
  
  
=See also=
 
* [http://api.openoffice.org/docs/DevelopersGuide/Extensions/Extensions.xhtml Extensions] chapter of the Developers Guide
 
* Using C++ with OOo SDK : [[Constructing_Components| Constructing Component in C++]]
 
*[[Tutorial_UNO_Library|UNO tutorial]]
 
*[[Tutorial_UNO_IDL|UNO IDL]]
 
* [[Uno/Article/Types%26Reflection]]
 
* Daniel Bölzle's [http://udk.openoffice.org/cpp/man/component_tutorial.html tutorial] : Writing a simple UNO component.
 
* [[UNO_component_packaging|Component with Python]]
 
  
 +
{{PDL1}}
  
[[Category:Uno]]
+
[[Category:Documentation/Developer's Guide/Scripting]]
[[Category:Extensions]]
+

Revision as of 12:23, 16 September 2010



The HelloWorld macro

Here is a comparison of HelloWorld macros in the different script languages available in OpenOffice.org.

Basic

Sub writeHelloWorld()
Dim oDoc As Object, xText As Object, xTextRange As Object
 
oDoc = ThisComponent
xText = oDoc.getText()
xTextRange = xText.getEnd()
xTextRange.CharBackColor = 1234567
xTextRange.CharHeight = 16.0
' CharUnderline receives a group constant
xTextRange.CharUnderline = com.sun.star.awt.FontUnderline.WAVE
' CharPosture receives an enum
xTextRange.CharPosture = com.sun.star.awt.FontSlant.ITALIC
xTextRange.setString( "Hello World (in Basic)" )
End Sub

Basic interprets pairs of get and set methods at UNO objects as object properties if they follow this pattern:

 SomeType getSomeProperty()
 void setSomeProperty(SomeType aValue)

Using these facilities some lines can be simplified:

xText = oDoc.Text
xTextRange = xText.End
xTextRange.String = "Hello World (in Basic)"

Service properties can be directly accessed in Basic, it is not necessary to use getPropertyValue or setPropertyValue methods.

BeanShell

As BeanShell accepts typeless variables, the code is simplified compared to Java.

import com.sun.star.uno.UnoRuntime;
import com.sun.star.text.XTextDocument;
import com.sun.star.text.XText;
import com.sun.star.text.XTextRange;
import com.sun.star.beans.XPropertySet;
import com.sun.star.awt.FontSlant;
import com.sun.star.awt.FontUnderline;
 
oDoc = XSCRIPTCONTEXT.getDocument();
 
xTextDoc = UnoRuntime.queryInterface(XTextDocument.class,oDoc);
xText = xTextDoc.getText();
xTextRange = xText.getEnd();
pv = UnoRuntime.queryInterface(XPropertySet.class, xTextRange);
 
pv.setPropertyValue("CharBackColor", 1234567);
pv.setPropertyValue("CharHeight", 16.0);
// CharUnderline receives a group constant
pv.setPropertyValue("CharUnderline", com.sun.star.awt.FontUnderline.WAVE);
// CharPosture receives an enum
pv.setPropertyValue("CharPosture", com.sun.star.awt.FontSlant.ITALIC) ;
 
xTextRange.setString( "Hello World (in BeanShell)" );
return 0;

BeanShell interprets pairs of get and set methods at UNO objects as object properties if they follow this pattern:

 SomeType getSomeProperty()
 void setSomeProperty(SomeType aValue)

Using these facilities some lines can be simplified:

  xText = xTextDoc.Text;
  xTextRange = xText.End;
  xTextRange.String = "Hello World (in BeanShell)";

Service properties are only accessed with getPropertyValue or setPropertyValue.

JavaScript

As JavaScript accepts typeless variables, the code is simplified compared to Java.

importClass(Packages.com.sun.star.uno.UnoRuntime)
importClass(Packages.com.sun.star.text.XTextDocument)
importClass(Packages.com.sun.star.text.XText)
importClass(Packages.com.sun.star.text.XTextRange)
importClass(Packages.com.sun.star.beans.XPropertySet)
importClass(Packages.com.sun.star.awt.FontSlant)
importClass(Packages.com.sun.star.awt.FontUnderline)
 
oDoc = XSCRIPTCONTEXT.getDocument()
xTextDoc = UnoRuntime.queryInterface(XTextDocument,oDoc)
xText = xTextDoc.getText()
xTextRange = xText.getEnd()
pv = UnoRuntime.queryInterface(XPropertySet, xTextRange)
 
pv.setPropertyValue("CharHeight", 16.0) // Double
// CharBackColor receives an Integer
pv.setPropertyValue("CharBackColor", new java.lang.Integer(1234567))
// CharUnderline receives a group constant
pv.setPropertyValue("CharUnderline",
   new java.lang.Short(Packages.com.sun.star.awt.FontUnderline.WAVE))
// CharPosture receives an enum
pv.setPropertyValue("CharPosture", Packages.com.sun.star.awt.FontSlant.ITALIC) 
xTextRange.setString( "Hello World (in JavaScript)" )

JavaScript does not accept the simplifications seen in Basic and BeanShell.

Setting an integer value to a property requires to use a java class.

Java

Other sections of this document provide numerous Java examples. Here is the HelloWorld provided in OpenOffice.org

  import com.sun.star.uno.UnoRuntime;
  import com.sun.star.frame.XModel;
  import com.sun.star.text.XTextDocument;
  import com.sun.star.text.XTextRange;
  import com.sun.star.text.XText;
  import com.sun.star.script.provider.XScriptContext;
 
  public class HelloWorld {
      public static void printHW(XScriptContext xScriptContext)
      {
          XModel xDocModel = xScriptContext.getDocument();
 
          // getting the text document object
          XTextDocument xtextdocument = (XTextDocument) UnoRuntime.queryInterface(
              XTextDocument.class, xDocModel);
 
          XText xText = xtextdocument.getText();
          XTextRange xTextRange = xText.getEnd();
          xTextRange.setString( "Hello World (in Java)" );
      }
  }
Compiling and Deploying Java macros

Because Java is a compiled language it is not possible to execute Java source code as a macro directly from within OpenOffice.org. The code must first be compiled and then deployed within a OpenOffice.org installation or document. The following steps show how to create a Java macro using the HelloWorld example code:

  • Create a HelloWorld directory for your macro
  • Create a HelloWorld.java file using the HelloWorld source code
  • Compile the HelloWorld.java file. The following jar files from the program/classes directory of a OpenOffice.org installation must be in the classpath: ridl.jar, unoil.jar, jurt.jar
  • Create a HelloWorld.jar file containing the HelloWorld.class file
  • Create a parcel-descriptor.xml file for your macro
  <?xml version="1.0" encoding="UTF-8"?>
 
  <parcel language="Java" xmlns:parcel="scripting.dtd">
    <script language="Java">
      <locale lang="en">
        <displayname value="HelloWorld"/>
        <description>
          Prints "Hello World".
        </description>
      </locale>
      <functionname value="HelloWorld.printHW"/>
      <logicalname value="HelloWorld.printHW"/>
      <languagedepprops>
          <prop name="classpath" value="HelloWorld.jar"/>
      </languagedepprops>
    </script>
  </parcel>

The parcel-descriptor.xml file is used by the Scripting Framework to find macros. The functionname element indicates the name of the Java method which should be executed as a macro. The classpath element can be used to indicate any jar or class files which are used by the macro. If the classpath element is not included, then the directory in which the parcel-desciptor.xml file is found and any jar files in that directory will be used as the classpath. The necessary Java UNO classes are available automatically.

  • Copy the HelloWorld directory into the share/Scripts/java directory of a OpenOffice.org installation or into the user/Scripts/java directory of a user installation. If you want to deploy the macro to a document you need to place it in a Scripts/java directory within the document zip file.
  • If OpenOffice.org is running, you will need to restart it in order for the macro to appear in the Macro Selector dialog.

Template:Documentation/Note

Python

A Python module may contain several scripts.

def HelloPython( ):
import uno
 
def HelloPython( ):
    oDoc = XSCRIPTCONTEXT.getDocument()
    xText = oDoc.getText()
    xTextRange = xText.getEnd()
 
    xTextRange.CharHeight = 16.0
    xTextRange.CharBackColor = 1234567
    # CharUnderline receives a group constant
    xTextRange.CharUnderline = uno.getConstantByName("com.sun.star.awt.FontUnderline.WAVE")
    # CharPosture receives an enum
    xTextRange.CharPosture = uno.getConstantByName("com.sun.star.awt.FontSlant.ITALIC")
 
    xTextRange.setString( "Hello World (in Python)" )
    return None

Python interprets pairs of get and set methods at UNO objects as object properties if they follow this pattern:

 SomeType getSomeProperty()
 void setSomeProperty(SomeType aValue)

Using these facilities some lines can be simplified:

    xText = oDoc.Text
    xTextRange = xText.End
    xTextRange.String = "Hello World (in Python)"

Service properties can be directly accessed in Python, no need to use getPropertyValue or setPropertyValue.

Features of script languages supported by OpenOffice.org

Language feature Basic BeanShell JavaScript Java macro Python
Interpreted Yes Yes Yes No Yes
Integrated editor Yes, colored Yes Yes No No
Integrated debugger Yes No Yes No No
Script organizer Yes Yes Yes No No
Script encryption Possible No No No No
Typeless variables Yes: Variant Yes Yes No Yes
Getter/Setter Yes Yes No No Yes
Direct property access Yes No No No Yes
Function for Calc formula Yes No No No No
UNO component creation No No No Yes Yes


Using the OpenOffice.org API from macros

BeanShell, JavaScript, Java, Python macros are supplied with a variable of type com.sun.star.script.provider.XScriptContext which can be used to access the OpenOffice.org API. This interface has three methods:

Returns the XModel interface of the document for which the macro was invoked (see Using the Component Framework)
Returns the XDesktop interface for the application which can be used to access open document, and load documents (see Using the Desktop)
Returns the XComponentContext interface which is used to create instances of services (see Service Manager and Component Context)

Depending on the language the macro accesses XScriptContext in different ways:

  • BeanShell: Using the global variable XSCRIPTCONTEXT
 oDoc = XSCRIPTCONTEXT.getDocument();
  • JavaScript: Using the global variable XSCRIPTCONTEXT
 oDoc = XSCRIPTCONTEXT.getDocument();
  • Java: The first parameter passed to the macro method is always of type XScriptContext
 Xmodel xDocModel = xScriptContext.getDocument();
  • Python: Using the global variable XSCRIPTCONTEXT
 oDoc = XSCRIPTCONTEXT.getDocument()

Handling arguments passed to macros

In certain cases arguments may be passed to macros, for example, when a macro is assigned to a button in a document. In this case the arguments are passed to the macro as follows:

  • BeanShell: In the global Object[] variable ARGUMENTS
 event = (ActionEvent) ARGUMENTS[0];
  • JavaScript: In the global Object[] variable ARGUMENTS
 event = ARGUMENTS[0];
  • Java: The arguments are passed as an Object[] in the second parameter to the macro method
 public void handleButtonPress(
     XScriptContext xScriptContext, Object[] args)

Each of the arguments in the Object[] are of the UNO type Any. For more information on how the Any type is used in Java see Type Mappings.

The ButtonPressHandler macros in the Highlight library of a OpenOffice.org installation show how a macro can handle arguments.

  • Python: The arguments are passed as parameters of the called function.


Creating dialogs from macros

Dialogs which have been built in the Dialog Editor can be loaded by macros using the com.sun.star.awt.XDialogProvider API. The method createDialog() from interface XDialogProvider uses a string as a parameter. This string is the URL to the dialog. It is formed as follows:

 vnd.sun.star.script:DIALOGREF?location=[application|document]

where DIALOGREF is the name of the dialog that you want to create, and location is either application or document depending on where the dialog is stored.

For example if you wanted to load dialog called MyDialog, which is in a Dialog Library called MyDialogLibrary in the OpenOffice.org dialogs area of your installation then the URL would be:

 vnd.sun.star.script:MyDialogLibrary.MyDialog?location=application

If you wanted to load a dialog called MyDocumentDialog which in a library called MyDocumentLibrary which is located in a document then the URL would be:

 vnd.sun.star.script:MyDocumentLibrary.MyDocumentDialog?location=document

The following code shows how to create a dialog from a Java macro:

  public XDialog getDialog(XScriptContext context)
  {
      XDialog theDialog;
 
      // We must pass the XModel of the current document when creating a DialogProvider object
      Object[] args = { context.getDocument() };
 
      Object obj;
      try {
          obj = xmcf.createInstanceWithArgumentsAndContext(
              "com.sun.star.awt.DialogProvider", args, context.getComponentContext());
      }
      catch (com.sun.star.uno.Exception e) {
          System.err.println("Error getting DialogProvider object");
          return null;
      }
 
      XDialogProvider xDialogProvider = (XDialogProvider)
          UnoRuntime.queryInterface(XDialogProvider.class, obj);
 
      // Got DialogProvider, now get dialog 
      try {
          theDialog = xDialogProvider.createDialog(
              "vnd.sun.star.script:MyDialogLibrary.MyDialog?location=application");
      }
      catch (java.lang.Exception e) {
          System.err.println("Got exception on first creating dialog: " + e.getMessage());
      }
      return theDialog;
  }

Calling a macro with the Scripting Framework

The service com.sun.star.script.provider.ScriptProvider exports interface XScriptProvider which offers method getScript( ). This method returns an interface XScript which offers the method invoke( ) which will call the script with parameters if necessary.

The identity and location of the called script is contained in an URI, which follows a particular syntax.


Here are links to some code examples written by the community:


Content on this page is licensed under the Public Documentation License (PDL).
Personal tools
In other languages