<The previous article in this series | The table of contents of this series | The next article in this series>
To Know How to Handle (Read or Write) LibreOffice or Apache OpenOffice Writer or Calc Documents via Extensions from Java or Macro Programs
Now that we have learned basic concepts of UNO, we can understand the details of our sample UNO extension. Unless we understand the sample UNO extension well, we won't be able to put the sample to practical use for the purpose of developing our future UNO extensions.
That would be so.
We will understand the sample UNO extension by experiencing the making of it.
All right.
We are going to create the project.
Under the directory that contains the common Gradle build scripts or the common Ant build files, we create a directory, 'hiUnoExtensionsUnoExtension', which is the project root directory. The directory name is arbitrary.
It's a long name . . .
Ah, I warn this at this opportunity: I use long names with few scruples. That isn't because I like long names, but because I don't like abbreviations very much. An abbreviation seems handy when I name something, but it can be confusing when I look at it when I have forgotten much about it after some time. For example, if I name it 'hiExtExt', what does 'Ext' mean? Extended? Exterior? External? Extinct? Extra? Extract? Extreme? Extinguisher? If I successfully understand it as 'Extension', what extension is it? Firefox extension? Eclipse extension? Java extension? . . . If someone has an excellent memory that remembers after a while what each abbreviation meant, it's fine: go ahead with abbreviations. Regrettably, I have a poor memory, which makes me avoid abbreviations as much as possible. So, don't worry about my long names: if someone likes them short, he or she can shorten them themselves.
Fair enough.
Then, we create the Gradle build script or the Ant build file of the project.
As for the Gradle build script, we write like this.
// # Change the target name
ext.TARGET_NAME = "thebiasplanet.hiunoextensionsunoextension.uno"
apply ("from": "../commonBuild01.gradle")
// # Change the default task
defaultTasks ("registerUnoExtension")
ext ({
// Add this if necessary
//CHECKSTYLE = "ON"
// Add this if necessary
//JAR_DEPLOY_DIRECTORY_NAME = "?"
// Add this if necessary
//WAR_DEPLOY_DIRECTORY_NAME = "?"
// # Change this if necessary
INCLUDED_JAR_FILE_NAMES = ["../unoUtilitiesToDisclose/target/thebiasplanet.unoutilities.jar"]
// # Change this if necessary
OTHER_CLASSES_PATHS = [JAVA_FILES_BASE_DIRECTORY_NAME, CLASSES_BASE_DIRECTORY_NAME, LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME + "/unoil.jar", LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME + "/jurt.jar", LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME + "/ridl.jar", LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME + "/juh.jar"]
REFERENCED_PROJECT_DIRECTORY_NAMES = ["../unoUtilitiesToDisclose"]
})
apply ("from": "../commonBuild02.gradle")
We specify the target name, here 'thebiasplanet.hiunoextensionsunoextension.uno' and the default task, 'registerUnoExtension'. And we include the Jar file name of the UNO utilities project in the 'INCLUDED_JAR_FILE_NAMES' array, which makes the contents of that Jar file included in the Jar file of this sample UNO extension project.
What is the target name used for?
It's used for the name of the UNO data types merged registry file, the name of the Jar file, the name of the UNO extension file, and the name of the UNO components setting file.
Hmm, I guess that those files will be explained later.
As for including the Jar file name of the UNO utilities project in the 'INCLUDED_JAR_FILE_NAMES' array, do you mean that the Jar file of the UNO utilities project is expanded in the Jar file of this sample UNO extension project?
Yes.
I guess, that makes the contents of the Jar file of the UNO utilities project duplicated when we register other UNO extensions.
Yes. Actually, that doesn't cause particular troubles, but, honestly, that isn't beautiful. We can make Jar files shared by multiple UNO extensions, but that necessitates some settings in LibreOffice. We will do those settings in future articles.
OK.
And note Jar files under the 'LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME' directory included in the 'OTHER_CLASSES_PATHS' array. Those Jar files are UNO libraries. We need them to compile our Java sources, but aren't included in our Jar file because they are loaded by default at runtime.
I see.
As for the Ant build file, we write like this.
<?xml version="1.0" encoding="UTF-8"?>
<!-- # Change the project name and the default target -->
<project basedir="." name="thebiasplanet.hiunoextensionsunoextension.uno" default="registerUnoExtension">
<import file="../commonBuild01.xml"/>
<!-- Add this if necessary
<property name="CHECKSTYLE" value="ON"/>
-->
<!-- Add this if necessary
<property name="JAR_DEPLOY_DIRECTORY_NAME" value="?"/>
-->
<!-- Add this if necessary
<property name="WAR_DEPLOY_DIRECTORY_NAME" value="?"/>
-->
<path id="INCLUDED_JAR_FILE_NAMES">
<!-- # Add the pathelement if necessary
<pathelement path="?"/>
-->
<pathelement path="../unoUtilitiesToDisclose/target/thebiasplanet.unoutilities.jar"/>
</path>
<path id="OTHER_CLASSES_PATHS">
<!-- # Change the path if necessary -->
<pathelement path="${JAVA_FILES_BASE_DIRECTORY_NAME}:${CLASSES_BASE_DIRECTORY_NAME}:${LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME}/unoil.jar:${LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME}/jurt.jar:${LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME}/ridl.jar:${LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME}/juh.jar"/>
</path>
<import file="../commonBuild02.xml"/>
</project>
We specify the project name, here 'thebiasplanet.hiunoextensionsunoextension.uno' and the default target, 'registerUnoExtension'. And we include the Jar file name of the UNO utilities project in the 'INCLUDED_JAR_FILE_NAMES' path, which makes the contents of that Jar file included in the Jar file of this sample UNO extension project.
And note Jar files under the 'LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME' directory included in the 'OTHER_CLASSES_PATHS' path. Those Jar files are UNO libraries. We need them to compile our Java sources, but aren't included in our Jar file because they are loaded by default at runtime.
OK.
Then, we create this directories hierarchy under the project directory.
/source
/java
/resource
/unoIdl
All right.
As we want to create a UNO component that implements a specific UNO interface, we will create the UNO interface. If our UNO component needs to implement only existing UNO interfaces, that isn't necessary, but in many cases, we would want to create our own UNO interfaces.
We name our UNO interface 'thebiasplanet.uno.hiunoextensionsunoextension.XHiUnoExtensions', which means we have to create the UNOIDL file, 'thebiasplanet/uno/hiunoextensionsunoextension/XHiUnoExtensions.idl', under the 'unoIdl' directory.
And we write this in the 'XHiUnoExtensions.idl' file.
// # Change the defined variable name START
#ifndef __thebiasplanet_uno_hiunoextensionsunoextension_XHiUnoExtensions_idl__
#define __thebiasplanet_uno_hiunoextensionsunoextension_XHiUnoExtensions_idl__
// # Change the defined variable name END
#include <com/sun/star/uno/XInterface.idl>
// # Add necessary idls START
#include <com/sun/star/lang/IllegalArgumentException.idl>
// # Add necessary idls END
// # Change the module name
module thebiasplanet { module uno { module hiunoextensionsunoextension {
// # Change the interface name and the parent interface
interface XHiUnoExtensions: com::sun::star::uno::XInterface
{
// # Add methods START
string sayHi( [in] string p_name)
raises (com::sun::star::lang::IllegalArgumentException);
// # Add methods END
};
}; }; };
#endif
Hmm, . . .
'#ifndef' ~ '#endif' block is for the code inside it not to be executed multiple times. The name defined can be anything if it's unique from other defined names.
In '#include' directives, <> is used when the included file is under the system include directory, but "" is used when the included file is under a user specific directory.
'com::sun::star::uno::XInterface' is the base UNO interface of our UNO interface. Our UNO interface inherits only one UNO interface, but if necessary, it can inherit multiple UNO interfaces. Note the '::' notation: in UNOIDL, modules are delimited by '::'.
The 'sayHi' method is the method of our UNO interface. Of course, our UNO interface can contain multiple methods, if necessary.
The '[in]' specification means that the argument is passed into the method, and the change to the argument from inside the method can't be seen from outside of the method.
I understand that, but what if we specify it as '[out]'? I guess, Java can't handle '[out]' arguments.
Actually, the '[out]' or '[inout]' argument is mapped to an array in Java. If the argument is '[out] string p_argument1', it's mapped to 'String [] p_argument1'.
Oh, so, we set a value in 'p_argument1 [0]' inside the method.
Yes.
The data type, 'string' is mapped to 'java.lang.String' in Java, I presume?
Yes. As for mappings of data types, refer the reference documents here.
Oh, null isn't allowed for UNO strings.
So, it seems.
And exceptions except 'RuntimeException's, that UNO components of the UNO interface may throw have to be declared in the 'raises' clause. 'RuntimeException's are instances of 'com.sun.star.uno.RuntimeException' or its descendants'.
I see.
- Apache OpenOffice Wiki. (2014/01/02). Apache OpenOffice Developer's Guide. Retrieved from https://wiki.openoffice.org/wiki/Documentation/DevGuide/OpenOffice.org_Developers_Guide
<The previous article in this series | The table of contents of this series | The next article in this series>