Documentation/DevGuide/Extensions

An extension is a file intended for the distribution of code and / or data which is to be used by LibreOffice. The file has the file extension “oxt” (formerly .uno.pkg and .zip), and it acts as a container for various items, such as libraries, JARs, configuration data, type libraries, Basic libraries, Basic dialogs, etc. Before LibreOffice can use any content of the extension, it needs to be installed by the Extension Manager.

Extension Manager
The Extension Manager is a tool for managing extensions and other deployable items, such as separate libraries, JARs, configuration data files. This includes adding, removing, enabling and disabling of these items.

The Extension Manager can be started from within the office by pressing the menu item or by running the unopkg executable, which is contained in the program directory of the office installation.

When an extension is installed, a copy is created, which is kept either in the user installation or the shared installation (/share). The original extension can therefore be (re)moved after installation.

Extension Repositories
(As of OpenOffice.org 3.3)

LibreOffice stores extensions in different places, the so-called repositories. This mostly does not matter for users because this has no influence on the extension's functionality. There are three repositories: user, shared and bundled. An extension can be part of every repository at the same time, but one repository can only hold one version of an extension. That is, assuming one has version one and version two of an extension, which also may be contained in different files, then only one of them can be installed per repository. The extension manager enforces this by checking the extension identifier which is stored within an extension. The repositories are prioritized, meaning that an extension in a repository with a high priority is preferred over the same extension in a repository with a lower priority. The user repository has the highest and the bundled repository has the lowest priority. An extension repository consists basically of two parts, the extensions and additional data, which is produced by the extension manager. In order to easier refer to the locations where these are stored, we name the location containing the extensions the extensions folder and the place where the other data is stored the registration data folder. Both folders may not necessarily be within the same parent folder. The registration data folder for all repositories are within the user installation (user data).

User repository
This repository contains extensions, aka user extensions, which can only be used by the user who installs them. Users can manage the user extensions themselves. That is, they can add, remove, disable and update them.

Shared repository
The extensions in this repository, which are also referred to as shared extension, can be used by all users - that's where the name “shared” comes from. Therefore, they need to be located in a place accessible by all users, which is currently within the office installation. This place is usually restricted in terms of who is allowed to modify (write, delete) files. Therefore, only people with the proper file access rights, who usually have an administrator or root account, can add, remove, update (disabling is not supported) extensions in the shared repository.

Bundled repository
This repository holds the bundled extensions. They resemble to a certain degree the shared extensions. That is, they are usable by all users. But only those with the proper file access rights, can add and remove them. Bundled extensions are, as the name suggest, bundled with LibreOffice. That is, they are part of the installation set and are already available after installation. Contrary to shared and user extensions, they are exclusively maintained by the installation program (aka setup) of LibreOffice. Although they are visible in the extension manager's dialog, they cannot be modified by the extension manager, even by administrators. The setup program may offer to choose which extensions are to be installed. To later add or remove a bundled extension, one needs to restart the setup program and determine the wanted extensions. Before running the setup program one must make sure that all LibreOffice processes are shut down. When the office is being uninstalled then all bundled extensions are removed.

The Active Extension
(As of OpenOffice.org 3.3)

If the same extension is installed in the user and shared repository, then it is expected that only the one in the user repository is used. In other words it "hides" the one in the shared repository. This, however, was never the case (until now). It only worked if both extensions contained exactly the same items, such as services, configuration items, etc. However, two different versions of an extension often have different contents. For example, they may have different menu entries. Then the entries from both extensions would be displayed.

In case of having the same contents, one could rely on the underlying facilities, such as configuration manager, service manager, type description provider, to prefer the respective contents of the user extension over those of the shared extension. However, these facilities have no notion of an extension. For example, if the user and shared extension (having the same extension identifier) contain a service Foo, then the service manager will provide the service Foo of the user extension. If the shared extension also contained the service Bar, which is not in the user extension, then the service manager must not offer this service. To do this, the service manager would need the information, which extension contains the service. Similar all other facilities which process extension contents, like the configuration manager, need the association between a particular item and the respective extension.

The active extension solves this "hiding problem". It makes sure that an extension in a repository with a higher priority completely hides the same extension in a repository with a lower priority. This is done without extending all those facilities in a way so that they can deal with extensions. Instead, the extension manager determines which extension may be used an which not. And this is how it works exactly:

There is a fixed hierarchy of repositories:
 * 1) user (highest priority)
 * 2) shared
 * 3) bundled (lowest priority)

This means that there can be three extensions with the same identifier. But only the one in the repository with the highest priority can be the active extension, unless it is disabled. Only disabling of user extensions is supported.

Only the active extension can be used in LibreOffice. For example, if one extension is in all repositories, then only the services from the active extension will be used. In the following explanation we assume that extensions have the same identifier, when speaking of extensions in different repositories, unless otherwise noted.

A user extension hides the shared extension, which in turn hides the bundled extension. If there is a user extension then it is always the active extension independent of its version and if there are extensions in the shared or bundled repository.

A shared extension can only be an active extension if there is no or a disabled user extension. Again, the version of the shared extension and the fact that there may be a bundled extension do not matter. A bundled extension can only be an active extension if there are no shared or user extension. There may be, however, a disabled user extension.

An extension becomes active if it is registered ( com.sun.star.deployment.XPackage:registerPackage ) after having revoked ( com.sun.star.deployment.XPackage:revokePackage ) those extensions with the same identifier in other repositories. This means that of all the extensions with the same identifier in the different repositories, there is at most one registered at a time. For example: or or
 * 1) user extension: registered
 * 2) shared extension: revoked
 * 3) bundled extension: revoked
 * 1) no user extension
 * 2) shared extension: registered
 * 3) bundled extension: revoked
 * 1) no user extension
 * 2) no shared extension
 * 3) bundled extension: registered

Updating Extensions
(As of OpenOffice.org 3.3)

An extension can be updated by either explicitly installing the extension or by running the update function in the extension manager. Updating an extension consisted originally in removing the installed extension and then installing the new version of the extension in the same repository. This meant that it was necessary to have write permission for the extensions folder of the shared repository for updating shared extensions.

Updating shared extensions is now possible. If the user has no write permission, then the update will be installed in the user repository. The actual shared extension will then remain unchanged, but it will be superseded by the update, because it has a higher priority.

Bundled extensions cannot be updated by the extension manager (see Setup - Bundled Extensions). However, users can still download and install these extension themselves.

Users will be informed if there are newer versions of extensions, which they currently use, are available. It does not matter if the currently used extensions are from the user or shared repository. If there is a better version, then it is offered as an update. This allows users to always obtain the latest versions of their extensions.

The updates, that is, the extensions with a newer version, will either be obtained from an online repository or locally, depending on which ones have the highest versions. In the latter case, the newer version will come from the shared or bundled repository if there is one available. If the version of an extension in a local repository is the same as the one from the online repository, then the local one is used.

Using a local repository (bundled or shared) as update source is useful for the case when a user has installed an user extension and then a more current version is installed in the shared or bundled repository. The user would then use the "old" version, although a better one is already available.

The following tables show scenarios where the user can update extensions. If a cell contains a “1” then this simple means there is an extensions installed. If it contains a “2” then this represents an extension with the same identifier then “1” but with a higher version. If there are several “2”s under each other, then it is sufficient if just one of them has a higher version than “1”.

The first table shows the case where a user has no write permission in the shared folder. In all cases the update is installed in the user repository. The new version comes either from the shared, bundled or online repository, depending on which has the best version.

In words: An update (installing in the user repository) is possible, if
 * 1) there is shared extension (no user) and the bundled or online repository contains a higher version
 * 2) there is a user extension and the shared, bundled or online repository contains a higher version

The next table shows the case where the user has write permission in the shared folder. In all those cases the update/installation will happen in the shared repository. If a user extension exists does not matter.

In words: An update (installing in shared repository) is possible, if there is shared extension and the bundled or online repository contains a higher version

This also means that, if there is only a user extension (no shared, no bundled) and there is one with a higher version in the online repository, then no update is done in the shared repository.

The next table shows the case where the user has write permission in the shared folder. In all those cases the update/installation will happen in the user repository.

In words: An update (installing in user repository) is possible, if there is a user extension and the shared, bundled, or online repository contains a higher version.

Processing Extensions
(As of OpenOffice.org 3.3)

Checking for modification during start-up
Every time LibreOffice is started it needs to check if extensions were removed from or added to the shared or bundled repository. If this is the case, then the registration data of the repository must be updated accordingly and LibreOffice is restarted.

Because LibreOffice checks for added or removed extensions at start-up, this must be very quick. To achieve this, LibreOffice compares the modification time of extension folders of the repositories with the time of the most recently performed check. This time is “saved” in the file lastsynchronized in the registration data folder of the repositories. In fact, the modification time of the file is used rather then a value is written into the file. If the modification time of the extension folder is more recent, then the extension manager will check if extensions were added or removed and update its database accordingly. This is of course an implementation detail and may change at any time.

Restarting LibreOffice
The restart is necessary to avoid that users use removed shared extensions. Removing a shared extensions does not entail the immediate removal of the the extension files. This is necessary to allow live deployment. For details see Adding a shared extension and Removing a shared extension.

The extension manager updates its databases during start-up of LibreOffice an removes entries of removed extension, so that they cannot be used anymore. However, until this has happened services from the removed extension may have been started and menus added to the menu bar.

Even if the extensions are completely removed from the disk, as is the case with removed bundled extensions, remnants can still be visible for the user. This applies particularly for configuration data. The extension manager processes them and creates additional data (registration data), that is configuration data containing expanded URLs. LibreOffice only uses the registration data, which is stored in the user data. Removing the bundled extension, which is done by the installer, does not remove the registration data. This is only done during the start-up when the extension manager runs. But by this time, the configuration manager has already loaded the registration data of the removed extension. Live removal of menu entries does not work yet. Therefore artifacts of removed extensions may still be seen when LibreOffice is run the first after removing the extension.

There are also extensions which do not work well right after they are installed. In other words, they do not support live deployment. This is typically caused by issues in LibreOffice and/or the extension. After restarting LibreOffice, the extensions perform as expected.

Although live deployment issues can be fixed, there is still the problem of removed shared extensions. This could only be solved if one would not allow live deployment of shared extensions.

Adding a user extension
A user extension is extracted into a folder with a unique name which in turn is contained in the extensions folder. The additional folder with the unique name is necessary to make live deployment possible. When removing an extension, it is only marked as “unusable” and the extension is not deleted, because it may still be in use. If now the same extension is installed again in the same process, then it will be extracted to another folder with a unique name. This prevents a name clash with the folder name of the previously “removed” extension. The user can now repeat to remove and install the extension in the same process. This results in having the same extension multiple times in the extensions folder of the repository, but everyone is contained in a folder with a unique name. The folders of the “removed” extensions, as well as the folders which contain them, are only removed after running the extension manager after restarting LibreOffice.

The extension database of repository is updated and the new active extension is determined.

Adding a shared extension
For the user who adds a shared extension, the extension is processed the same way as a user extension.

For all other users, the extension manager processes the extension the next time they start LibreOffice. The extension database of repository is updated and the new active extension is determined.

Adding a bundled extension
A bundled extension is installed by the installation program of LibreOffice. The folder of the extension, including all files contained therein, is copied into the extensions folder of the bundled repository. Only when a user starts LibreOffice, then the extension manager processes the extension. The extension database of repository is updated and the new active extension is determined.

Removing a user extension
The entry in the extension database of the repository referring to this extension will be deleted and the active extension will be determined. The extension will be deleted when the user runs the extension manager after restarting LibreOffice.

Removing a shared extension
The extension will be revoked if it was registered. To prevent other users from using the extension it is marked to be deleted. This is done by creating a tag file, the "extension removed file", next to the folder with the unique name. This way, the information that the extension was deleted can be accessed by all users. If this file does not exist and there is no entry in the extensions database, then it is assumed that the extension was added. The file will be deleted when the extension is deleted. The file also contains the name of the user who removed the extension. If the same user runs the extension manager after restarting LibreOffice, then the extension, the unique folder, temp file and the "extensions removed file are deleted. Why it must be the same user shows the following scenario:

A user starts LibreOffice and uses the extension. The extension will then be removed and LibreOffice keeps running. Now a second user, who also has write access to the extensions folder, starts LibreOffice. When the extension manager starts it would properly delete extensions which were previously removed. However in this case this would affect the office of the first user which still uses that extension. The same user cannot start another instance, because this is prevented by the lock file.

For all other users, the extension manager processes the extension the next time they start LibreOffice. This includes the detection of the removed extensions. An extension is regarded as removed if:
 * The unique folder, tmp file, extension folder do not exist anymore.
 * There is a "extension removed file"
 * The extension exists but has a different identifier or version than the one which was previously at the same location. This may happen when the extension was updated, or a previous office update removed the extension and another with the same name was added in the latest office update.

The extension could also have the same file name. The entry in the extension database of the repository referring to this extension will be deleted and the active extension will be determined.

Removing a bundled extension
A bundled extension can only be removed by the set-up. The folder of the extension, including all files contained in it, is deleted from the extension folder of the bundled repository.

If a user starts LibreOffice, then the extension manager processes the removed extension. This includes the detection of the removed extensions. An extension is regarded as removed if:
 * The extension folder do not exist anymore.
 * The extension exists but has a different identifier or version than the one which was previously at the same location.

The entry in the extension database of the repository referring to this extension will be deleted and the active extension will be determined.

Updating
An update consists of first removing the extension and then adding the new extension. That is, this is already covered by these two scenarios.

Packaging Notes For Bundled Extensions
(As of OOo 3.3)

Bundled extensions are installed during LibreOffice's setup, and only the setup can install or remove them. That is, they cannot be modified by the extension manager, which would change the installation. The installer copies the extensions into the extensions directory of the "share" folder. For example,  on Windows. Contrary to versions previous to OpenOffice.org 3.3, unopkg need NOT be run as a post install step. To uninstall the extensions, the installer can simply delete the directories of the respective extensions.

Extensions are packaged as directories instead of ".oxt" files. For example, there is an extension Foo.oxt containing the files f1 and f2. The installer package must then contain the "unzipped" extension, that is a directory Foo (oxt can be ommitted). After installation, the file structure must be:

+ Office/share/extensions + Foo |- f1 |- f2

During the packaging process one must make sure that all bundled extensions have different directory names, so as to prevent overwriting other extensions. In case of a name clash, one needs to modify the directory name of the extension appropriately.

The name of the folder should still reflect the name of the original extension file. This makes it easier to locate the extension in the file system. This name will also be used by the extension manager dialog if the extension does not provide a display name. Further details can be found here: Extensions_Integration_into_Installation_Set.

Bundled extension MUST have an identifier and version, otherwise LibreOffice cannot determine reliably if a bundled extension was removed.

Executables contained in the extension must have the executable flag set. This is usually done by the extension manager, but not in case of bundled extensions.

Deployment Items
The Extension Manager can be used to deploy various types of files. It is primarily used for extensions. The latest incarnation of an extensions is the .oxt file, which has superseded .uno.pkg and .zip.

Apart from extensions the Extension Manager can also manage these types:


 * Configuration data (.xcu, .xcs)
 * UNO Libraries (.dll / .so)
 * JARs (.jar)
 * Type libraries (.rdb)

Installing Extensions for All or a Single User
When installing an extension, one has to decide if all possible users can use it (shared extension) or only oneself (user extension). In the first case, users cannot modify (enable, disable, remove) the extension unless they have write access to the share directory in the office installation.

A shared extension may change the appearance of the GUI (toolbars, menu bar, etc.) for all users. They can, however, configure their office so that particular menu or toolbar items are not shown. There is currently no way to centrally install an extension for particular user groups.

Whether an extension is to be installed for all users, or only for the single user, is determined during installation. The person performing the install must select, in the Extension Manager dialog, either My Extensions or LibreOffice Extensions before pressing the Add... button. In the first case, the extension will only be installed for the current user, whereas in the latter case it will be installed for all users.

When running unopkg in a windowless mode, the option --shared determines if an extension can be used by all users. For example:

[/program] $ unopkg add --shared my_extension.oxt

would install my_extension so that it can be used by all users.

Extension Manager in LibreOffice
Within a running office, the Extension Manager is started through the menu item. When started in this way, extensions can only be installed as user extensions. All items deployed under LibreOffice Extensions cannot be modified. But it is possible to export them.

unopkg
The unopkg executable offers another way to start the Extension Manager. It supersedes the pkgchk executable which was used in OpenOffice.org 1.1.0 and older versions and which no longer works.

In contrast to the Extension Manager in LibreOffice unopkg can also manage shared extensions. For example:

[/program] $ unopkg add --shared my_extension.oxt

installs my_extension.oxt for all users.

unopkg offers a windowless mode in which all interactions occurs through the console. This is the default. If unopkg is started with the subcommand gui then the Extension Manager dialog appears which is exactly the same as the one in LibreOffice.

[/program] $ unopkg gui

The difference is that in the dialog all items deployed under LibreOffice Extensions can be modified and new items can be added there as well. All actions, that is, adding, removing, etc. can be done in the dialog. Therefore unopkg gui does not require any more parameters.

Following is a short overview of what can be done with unopkg. Since there are many more commands, have a look at the help text that can be obtained by calling unopkg -h.

First of all, open a console and change into the program directory of the office installation.

Adding an extension for a single user:

[/program] $ unopkg add my_extension.oxt

Adding an extension for all users:

[/program] $ unopkg add --shared my_extension.oxt

Removing a user extension is done via the identifier of the extension (see Extension Identifiers):

[/program] $ unopkg remove my.domain.my_extension-id

Remove a shared extension:

[/program] $ unopkg remove --shared my.domain.my_extension-id

Before you install an extension or other item for all users, make absolutely sure there are no running instances of LibreOffice. unopkg cannot recognize if there are running instances of LibreOffice from different users. Installing into a running office installation might cause inconsistencies and destroy your installation!

When a user starts LibreOffice and then starts unopkg, then the Extension Manager from the office is used and unopkg terminates. Then, however, no shared extensions and other shared items can be modified.

Location of Installed Extensions
Sometimes an extension developer needs to know the path to the root of his installed extension e.g. to load some additional data. You can use the singleton PackageInformationProvider to get an URL for an installed extension with a given Extension Identifier. For more information about Extension Identifiers see Extension Identifiers. For more information see the singleton com.sun.star.deployment.PackageInformationProvider and its interface com.sun.star.deployment.XPackageInformationProvider.

Here is a C++ example:

You will find a Java example at page : ReadFilesFromOxt

Here is an example in Basic:

Extension Layers
The Extension Manager uses two extension layers, the user and the shared layer. Extensions installed in the shared layer can be used by all users whereas those in the user layer can only be used by the user who installed them. An extension can be installed in either layer or both.

This system was developed many years ago. Since then new features were added, such as extension versioning, online update, bundled extensions, etc. During that time it became obvious that there are some problems with the original design. This document tries to explain them.

Hiding
The idea of layers is that extensions in the top layer hide the same extensions in the layer below. In other words, the extension in the highest layer will be given preference, when resources from the extension are requested. Because the user layer is the top layer, a shared extension is only used when the same extension does not exist in the user layer. The version of the extension has no influence.

This, however, is only a simplified model. An extension is never used as a whole. Instead clients access the particular contents, such as components, configuration data, etc. And it is also these contents which obscure the same content in a lower layer. For example, an extension contains a UNO service, which is installed in both layers. When the client instantiates it then the one from the top layer is used.

There are situations where contents of the shared extensions are still used, although they should be hidden and therefore not usable. Assuming there are version 1 and version 2 of an extension. Then the different versions may have different content. For example, version 1 may contain a service foo which is not contained in version 2. If now version 1 is installed in the shared layer and version 2 in the user layer then foo is still around and can be instantiated. Foo may access resources which are also delivered with this extension and are also available in version 2 which is in the user layer. Resources in version 2, which hide those from version 1 (same node in xcu or same service), can be incompatible, so that foo fails.

A service may also need files which are part of the same extension and which are only directly accessible. That is there is no API, such as the registry or service manager, which can provide the content. A "running" service does not know from which layer it comes from. To get the install location it can use the PackageInformationProvider. This service will first look into user layer and if the extension cannot be found, then it will look into the shared layer. If now the service from the shared layer needs some file from its extension, then it may accidentally use the one from a different version of the extension in the user layer. This file can be incompatible or not even exist and make the service fail.

Another example can be constructed using registry values, which are contained in xcu files. Let's assume that version 1 of an extension adds a menu foo and version 2 adds menu bar. If one extension is installed in the share and the other in the user layer, then both menus appear. This is because the nodes of the configuration files are merged into the configuration and not the xcu files itself. That is, if the extensions contain an xcu file with the same name, then the xcu file of the last installed extension will NOT replace the one from the other extension. The second xcu file can, however, change the values for nodes which have been defined by the first xcu.

These examples prove that the layering (in terms of hiding the items from the layer below) on extension level does not work, although it does for the respective deployment items. And it may be safe to say, that this goes against the user's expectation.

Unclear behavior
It may be unclear to users how the behavior is when the same extension is installed as user and shared extension. If there is a shared extension and the same extension is installed as user extension, then the user should be informed that the currently installed extension will become 'inactive'. Then, when the user extension is uninstalled, the user should be informed that the shared extension will become 'active' again.

Extension versions
As already observed, the version of an extension has no influence on the decision if the extension from the user or the shared layer is used. At the time of developing the extension framework there was no support for versioned extensions, so one did not have to care about them. Later, we recognized that an extension version is useful for users. For example, if one has an extension installed and is installing the same extension again, then one is being informed about what extension has the later version (so one can decide which is the best for them).

I think the general expectation is that the latest version is the best. Therefore it should be natural that LibreOffice uses always that one. However, this is not the case and users may unintentionally prevent, that they use the latest extension. For example, LibreOffice comes with a bundled English dictionary. Now a user installs, intentionally or not, the same extension and forgets about it. The administrator updates LibreOffice regularly, which also updates the dictionary with the latest version. But the user would still use the old dictionary, because that is the one from the user layer which hides the one from the shared layer.

One could think now of a notification for the user but there are some questions: The first question, is easily answered: At every start-up.
 * when does LibreOffice check for this situation?
 * how can this be explained to the user?

The second question is more difficult.Think about a message, such as: "Dear user. You cannot use the latest version of the French dictionary, which is installed in the shared/bundled layer. Instead, the dictionary which you installed earlier is used. You need to uninstall it, if you want the new version ...." Many users would probably not understand this. So the easiest and natural way is simply to use the latest version of the extension independent of what layer it is installed in. The term layer should then be replaced, by repository, indicating that the location does not include a preference – just think about the picture of one layer above the other compared to repositories which are arranged in one row.

Layer location
The shared layer is located within the LibreOffice installation. The benefit is that normal users cannot modify it. The layer will be modified after installation of OOo when an extensions is added, deleted, enabled or disabled. Depending on the operation system, this may be against the system guidelines. For example, it would be not allowed on Windows Vista/ 7. However, to allow “legacy application” to work Microsoft invented the virtual store.

Clean uninstallation
Modification of the shared layer will also prevent the clean uninstallation of LibreOffice. This is because the native installer does not “own” the files/folder which were added by the extension manager. For example, on Linux the path /opt/openoffice.org3/share/uno_packages will remain on the system. On OpenSolaris the shared extensions (with the same directory structure) will be copied to /var/lost+found on uninstallation.

No Separation of shared and bundled extensions
The rule is, whatever a user installed should not be removed by LibreOffice. This is also valid for shared extensions. Today a bundled extension is nothing else than a shared extension and therefore can be modified by users, provided they have sufficient file access rights. They can install the same extension as one, which was installed as bundled extension, in the shared layer. This means that the original bundled extension is replaced by the recently installed shared extension. This can happen in two scenarios. The first one is during an online update of the extension and the second is when the extension is “manually” installed. In these cases users intentionally choose to replace the original extension. Therefore this extension may not be deleted when uninstalling LibreOffice. This, however, requires to know that the bundled extension was replaced, but there is currently no way to recognize this.

Selection of extensions in setup
Like many other features, bundled extensions should be selectable in the dialog of the installer. The installer can also be invoked later to add or remove particular features. The problem is, that the extensions which the installer “sees” are not the same as “seen” by the extension manager. The setup copies an oxt file to ../share/extension/install and then invokes a post-install script (Unix) or a custom action (Windows) which runs unopkg to install the extension properly. The extension is then unzipped to ../share/uno_packages/cache/uno_packages and some data are added to the extension manager database. The installer only knows the file that it copied to the ../share/extension/install folder. If it is there then it is regarded as installed – otherwise not.

For an extension to show up in the dialog of the extension manager, there are two conditions which need to be met. First, it must be unpacked in the uno_packages folder. And second, there must be an appropriate entry in the extension manager database, indicating that it is installed. Therefore it would be possible that the installer displayed an extension as being installed but the extension manager did not. This may of course happen the other way round as well.

Even if the installer would copy the uncompressed extension directly to ../share/uno_packages/cache/uno_packages, both dialogs could show a different status. One could assume that the installer and extension manager regard an extension as installed if the the respective folder exists. But this does not work, because the extension manager does not remove immediately the extension when it is being uninstalled. The reason is, that files from the extension can still be in use  in the process. Only after restarting OOo and the extension manager, the extension's folder will be finally removed.

Code execution during installation
Copying extensions into the office installation during setup is not sufficient to make them usable. Only after the extension manager has processed them, OOo can make use of them. Therefore the installer invokes the extension manager after an extension has been copied. Unfortunately this requires different solutions for different platforms. RPM (Linux) and PKG (Solaris) use post-install/pre-install scripts which are executed after the copying step. But there are installation scenarios on Solaris, where code execution is not allowed during the setup. For example, the installer is running on Solaris Sparc and installs LibreOffice on a Solaris Intel Machine machine. Therefore LibreOffice uses a “postrun” service which invokes the extension manager when the system is rebooted. OpenSolaris prohibits code execution completely. The setup needs to install an SMF service which is triggered after the setup. Windows needs a 'custom action' which is compiled native code. The Mac dmg file already contains the processed extensions. That is, the extension manager processes the extension while building the dmg file.

It is obvious that the current situation is complex and one understands why testing and bug finding are rather difficult.

Extension Manager database
The database is created when the extension manager is started for the first time. The database contains different files and folders which are completely unknown to the installer. Therefore the installer will not remove them. This is another reason why the OpenOffice.org folder remains on the system after uninstalling LibreOffice.

License of shared extension cannot be displayed to users
Only the one who installs the extension can see the license.

Checklist for Writing Extensions
This page gives a brief overview about what is important when developing an extension.


 * 1) Use the .oxt file extension and provide description.xml. Look here why you should use.
 * 2) Provide an extension identifier. [go to XML description]
 * 3) Provide a version. [go to XML description]
 * 4) Provide a display name.  [go to XML description]
 * 5) Provide an icon. [go to XML description]
 * 6) Provide a description. [go to XML description]
 * 7) Specify the target platforms. [go to XML description]
 * 8) You may provide dependencies. [go to XML description]. For example, if your extension requires a 'minimal version' of LibreOffice then use the OpenOffice.org-minimal-version dependency.
 * 9) You may provide a license.  [go to XML description]
 * 10) You may customize the 'online update' of your extension unless the update facility of the LibreOffice extension repository does not fit your needs. [go to XML description].
 * 11) You may provide options pages in case the extension needs to be configured. [go to XML description].
 * 12) Provide publisher information. [go to XML description].
 * 13) Provide links to release notes (TODO: more documentation) in the description.xml. Currently, only used within the 'update dialog'. When using the LibreOffice extension repository, then the link to the release notes is automatically generated from the information entered on the web site. That is, when using the repository, one does not need to provide this information in the description.xml.
 * 14) Provide content for help system if necessary.

File Format
An extension is a zip file having a name that ends in .oxt (formerly .uno.pkg or .zip). The file extension .oxt is associated with the MIME / media type vnd.openofficeorg.extension. The .oxt file serves as a wrapper for all the items of an extension, and contains files which list and describe those items. An extension can contain UNO components, type libraries, configuration files, dialog or basic libraries, etc.

An extension should contain a description.xml (see description.xml) and must contain a directory META-INF (all uppercase). The META-INF directory contains a manifest.xml which lists all items and their media-type.

Depending on its media-type, the respective file needs to be treated particularly. For example a UNO component needs to be registered before it can be used. All media types which do not require a particular handling of the file are ignored currently (and actually need not be contained in the manifest.xml).

Runtime Libraries
The extensions need to bring their own runtime libraries, such as C or C++, when it is not guaranteed that these libraries are shipped with LibreOffice or are installed on the users' systems. They typically need to reside in the same directory as the libraries containing the UNO components.

Please note that there is a peculiarity of libraries build with MS Visual Studio 2008. The runtime libraries (C, C++) need either be installed in the system or must reside next to the library in order to be found. It does not matter if the runtime libraries are contained in the LibreOffice installation ( /OpenOffice.org/Basis/program). As a consequence extensions need always contain the runtime libraries which they use.

The runtime libraries must not be referenced by the manifest.xml.

Shared Library UNO Components
The media-type for a shared library UNO component is application/vnd.sun.star.uno-component;type=native, for example,

Shared Library UNO Components for particular Platforms
When you implement a UNO native component, for example, a .dll or .so file, then this file is only deployable on that specific platform. It is often convenient to package a bundle for different platforms. For instance, you compile your component for x86 Linux, Solaris SPARC and Windows. You have to tell the Extension Manager which version of your component file corresponds to which platform via a platform attribute supplied with the media-type, for example,

Uno Jar Components
The media-type for a UNO Jar component is application/vnd.sun.star.uno-component;type=Java, for example,

UNO Python Components
unopkg now supports registration of Python components (.py files). Those files are registered using the  loader. For details concerning Python-UNO, please refer to https://www.openoffice.org/udk/python/python-bridge.html. The media-type for a UNO Python component is application/vnd.sun.star.uno-component;type=Python, for example,

Passively Registered UNO Components
Beginning with LibreOffice 3.4, UNO components can use passive registration, see Passive_Component_Registration. Components written that way are no longer individually listed in the  file. Instead, one or more XML files (with root element ) containing the relevant information are registered in the   file with media type , optionally giving a   attribute. For an example extension containing passively registered UNO components, see.

RDB Type Library
The media-type for a UNO RDB type library is application/vnd.sun.star.uno-typelibrary;type=RDB, for example,

Jar Type Library
The media-type for a UNO Jar typelibrary is application/vnd.sun.star.uno-typelibrary;type=Java, for example,

Keep in mind that the RDB variant of that type library must be deployed also. This is currently necessary, because your Java UNO types may be referenced from native UNO code.

LibreOffice Basic Libraries
LibreOffice Basic libraries are linked to the basic library container files. Refer to LibreOffice Basic for additional information. The media-type for a LibreOffice Basic Library is "application/vnd.sun.star.basic-library", for example,

Dialog Libraries
Dialog libraries are linked to the basic dialog library container files. Refer to LibreOffice Basic for additional information. The media-type for a dialog library is application/vnd.sun.star.dialog-library, for example,

Configuration Data Files
The media-type for a configuration data file is application/vnd.sun.star.configuration-data, for example,

Configuration Schema Files
The media-type for a configuration schema file is application/vnd.sun.star.configuration-schema, for example,

Be careful not to install schemata (.xcs files) which contain the same elements but have different definitions.

Extension Tooltip Description
Deprecated as of OopenOffice.org 3.1. See Extension Description for details.

If you want to add a tooltip description (which shows up in the balloon help of a bundle node in the Extension Manager dialog), then you can do so by specifying localized UTF-8 files, for example,

The best matching locale (against the current installation's locale) is taken. The locale is of the form locale=language-country-variant.

Executable Files
The media type for an executable is application/vnd.sun.star.executable. This media type is new since OpenOffice.org 2.4. If an extension uses it then it should also use the dependency OpenOffice.org-minimal-version set to 2.4.

This media type was introduced to work-around the problem that the executable attribute (Unix files, does not apply for Windows files) will not be preserved when LibreOffice extracts a zipped extension. Also, when an extension was zipped on Windows, then the attribute is lost. Using the media type for a Windows executable does not have an effect since there is no such file attribute on Windows. On Unix the executable attribute is set when the extension is being installed. If it is installed for the current user then the user executable flag is set and if it is installed for all users, that is as shared extension, then the executable flag is set for user,group and other.

Example:

All other contents of the extension are simply copied into the Extension Manager cache. You can, for instance, deploy an image for add-on menus within a package, or any other file needed by your component. The LibreOffice configuration is used to find out in which path this file is located in a particular installation. When you define a package containing additional files, include an .xcu configuration data file, which points to your files. Use a variable %origin% as a placeholder for the exact path where the file will be copied by the Extension Manager. When unopkg installs the data, it replaces the path with an URL containing a macro and writes into the configuration. This URL has to be expanded before it is a valid file URL. This can be done using the com.sun.star.util.MacroExpander service. The %origin% variable is, for instance, used by the  property of add-on menus and toolbar items, which is described in the Configuration section.

description.xml
The description.xml is a means to provide additional useful information, such as dependencies, license and update information. It will be extended to support new features in the future. The file must be located in the root of the extension and the name is case sensitive.

Element

 * Parent element: document root
 * Children:
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4

is the root element of the description.xml.

Element

 * Parent:
 * Children: none
 * Since: OpenOffice.org 2.2

See also
 * Extension Identifiers
 * Example of description.xml

Element

 * Parent:
 * Children: none
 * Since: OpenOffice.org 2.1

See also
 * Extension Versions
 * Example of description.xml

Element

 * Parent:
 * Children: none
 * Since: OpenOffice.org 3.0

See also
 * Target Platform
 * Example of description.xml

Element
The registration element currently only contains the  element. If the  element exists, then it must have a child element.
 * Parent:
 * Children:
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4

See also
 * Simple License
 * Example of description.xml

Element
Parent: The element contains the  elements, determines if all user must agree to the license, or just the person who installs it, and determines a default   element. The mechanism for determining a "default" has changed in OpenOffice.org 2.4. See Documentation/DevGuide/Extensions for details. This element is disregarded for bundled extensions.
 * Children:
 * Since: OpenOffice.org 2.0.4
 * Since: OpenOffice.org 2.0.4

If the  element exists, then it must have at least one child element.

See also
 * Simple License
 * Example of description.xml

Element

 * Parent:
 * Child elements: none
 * Since: OpenOffice.org 2.0.4

The element contains information about where to find the file containing the license text, which language it uses, and if this element is the “default”. The mechanism for determining a "default" has changed in OOo 2.4. See Documentation/DevGuide/Extensions for details.

See also
 * Simple License
 * Example of description.xml

Element

 * Parent:
 * Children:
 * others
 * Since: OpenOffice.org 2.0.4
 * others
 * Since: OpenOffice.org 2.0.4

See also
 * Dependencies
 * Example of description.xml

Element

 * Parent:
 * Children: none
 * Since: OpenOffice.org 2.1

See also
 * Dependencies
 * Example of description.xml

Element

 * Parent:
 * Children: none
 * Since: OpenOffice.org 3.1

See also
 * Dependencies

Element

 * Parent:
 * Children:
 * Since: OpenOffice.org 2.2
 * Since: OpenOffice.org 2.2

must have at least one  child element. The second, third, etc. element are regarded as fallback, that is, the elements provide URLs to mirrors. The Extension Manager will try to get update information by using a URL and only use a different URL if an error occurred. That is, if for example the first URL references an atom feed that does not contain any references at all, but is a valid feed, then the Extension Manager assumes that there are no update information available. Then URLs from other  elements are not examined. Therefore the update information referenced by every URL must be identical.

See also
 * Online Update of Extensions
 * Example of description.xml

Element

 * Parent:
 * Children: none
 * Since: OpenOffice.org 2.2

See also
 * Online Update of Extensions
 * Example of description.xml

Element

 * Parent:
 * Children:
 * Since: OpenOffice.org 2.4
 * Since: OpenOffice.org 2.4

must have at least one  child element. The children of this element provide a localized publisher name together with a URL.

See also
 * Publisher Information
 * Example of description.xml

Element

 * Parent:
 * Children: Text
 * Since: OpenOffice.org 2.4

The text value of this element is the publisher name.

See also
 * Publisher Information
 * Example of description.xml

Element

 * Parent:
 * Children:
 * Since: OpenOffice.org 2.4
 * Since: OpenOffice.org 2.4

must have at least one  child element. The children provide URLs to localized release-notes.

Currently this element and its children are not used by the Extension Manager.

See also
 * Example of description.xml

Element

 * Parent:
 * Children: none
 * Since: OpenOffice.org 2.4

The element contains a URL to the release notes.

See also
 * Example of description.xml

Element

 * Parent:
 * Children:
 * Since: OpenOffice.org 2.4
 * Since: OpenOffice.org 2.4

must have at least one  child element. The children of this element provide a localized display name. The name will be used in the GUI instead of the file name.

See also
 * Display Name
 * Example of description.xml

Element

 * Parent:
 * Children: Text
 * Since: OpenOffice.org 2.4

The text value of this element is the display name of the extension. The string length must be greater then null and must not only contain white space characters.

See also
 * Display Name
 * Example of description.xml

Element

 * Parent:
 * Children:
 * Since: OpenOffice.org 3.0
 * Since: OpenOffice.org 3.0
 * Since: OpenOffice.org 3.0

See also
 * Icon
 * Example of description.xml

Element

 * Parent:
 * Children: none
 * Since: OpenOffice.org 3.0

See also
 * Example of description.xml

Element

 * Parent:
 * Children: none
 * Since: OpenOffice.org 3.0

See also
 * Example of description.xml

Element
Parent:  must have at least on  child element. Every child references a localized description. See Documentation/DevGuide/Extensions for details.
 * Children:
 * Since: OpenOffice.org 3.1
 * Since: OpenOffice.org 3.1

See also
 * Extension Description
 * Example of description.xml

Element

 * Parent:
 * Child elements: none
 * Since: OpenOffice.org 3.1

The element contains information about where to find the file containing the description text and which language it uses.

See also
 * Extension Description
 * Example of description.xml

Localized XML Elements
Some information contained in the description.xml are localized. When the Extension Manager uses them then it picks out the part which matches best the locale of LibreOffice. Localized data is used for


 * License files (simple license, since OpenOffice.org 2.0.4)
 * Publisher name and URL for publisher homepage (since OpenOffice.org 2.4)
 * URL for release notes (since OpenOffice.org 2.4)

Localized data is typically expressed in this format:

The children of have all a lang attribute, which have a language string according to RFC 3066. The following restrictions currently apply:
 * LibreOffice uses only lang-country
 * the language string can only have one variant, for example de-DE-mitte
 * LibreOffice uses uppercase letters for the country. The language strings must also use uppercase letters for the country. That is, the comparison between the LibreOffice's locale and the locale strings of the elements is case-sensitive.

Let's assume that LibreOffice uses British English (en-GB) end the extension has two license text files, one in German (de) and the other in English from New Zealand (en-NZ). Obviously there is no perfect match, since en-GB is not en-NZ. We would then probably prefer en-NZ over de. The algorithm tries to find a locale which is closest to the office's locale. Here is the algorithm:

Input to the algorithm:


 * The element
 * The locale of the office

Requirements:


 * The element has at least on child
 * All children have the same element name and namespace
 * All children have a lang attribute

Output of the algorithm:


 * A child element (immediate child) of parent.

Algorithm:


 * 1) The language, country and variant part of the office's locale are used to find a matching child element. If there is an exact match then the respective child element is selected as output, and we are done. Only the first match is used.
 * 2) The language and country part of the office's locale are used to find a matching license-text. If there is an exact match then the respective child element is selected as output, and we are done.
 * 3) The language and country part of the office's locale are used to find a matching child element. This time, we try to match only the language and country parts. For example, the office locale strings “en-US”, “en-US-east” match the   attribute with the values “en-US-north”, “en-US-south”, etc. The first child element with a matching   attribute is selected as output. If there is a match then we are done.
 * 4) Only the language part of the office's locale is used to find a matching child element. If there is an exact match then the respective child element is selected as output, and we are done. Only the first match is used.
 * 5) Only the language part of the office's locale is used to find a matching child element. This time, we try to match only the language part. For example, the office locale strings “en”, “en-US”, “en-US-east” match the   attribute with the values “en-GB”,“en-GB-north”, etc. The first child element with a matching   attributed is selected as output. If there is a match then we are done.
 * 6) The first child element will be selected as output.

Please note that before OpenOffice.org 2.4 the algorithm for determining the default child element for the  element was different. Then the parent element, which was  had the attribute default-license-id (type IDREF)and one child, that is a  element, must have had a license-id (type ID) attribute. Both attributes needed to have the same value. While this was easy to be verified with a schema it was quite cumbersome to write. With OOo 2.4 the first child element is the default in case there was no other child with a matching locale. The old "style" will still be supported but it should not be used anymore for new extensions. It is also recommended using the new "style" when providing a new version of an extension, where the previous version used the old "style".

The following examples show what values would match with a piece of a description.xml. The locale of LibreOffice is assumed to be en-US.

Example 1:

The  with lang=”en-US” will be selected. This is a perfect match.

Example 2:

The  with lang="en-US-region1" will be selected. There is no "en-US" and the algorithm looks for any variant of "en-US" and takes the first one it finds.

Example 3:

The  with lang="en" will be selected. There is no "en-US" nor the same locale with a variant, for example "en-US-region1". The next step is to compare only the language part. Then there is a match with lang="en".

Example 4:

The  with lang="en-GB" will be selected. There is no "en-US" nor the same locale with a variant, for example "en-US-region1". There is also no match when using only the language part. Then we look for a value that matches at least the language no matter what country or variant is used. The first locale that matches is "en-GB".

Example 5:

The  with lang="de" will be selected. There is no locale which even has "en" as language, so we just use the first entry as a default.

Example 6:

The  with lang="de" will be selected. This example uses the old method of determining the default locale. Starting with OpenOffice.org 2.4 one should not use the default-license-id and license-id anymore.

Example
This description.xml contains:


 * The version is 1.0. [go to XML description].
 * The identifier is: com.mycompany.extensions.my_extension. [go to XML description]
 * The platforms on which the extension can be installed only are Windows (x86 CPU) and Solaris (SPARC CPU). [go to XML description]
 * There is a dependency for OpenOffice.org 3.3 and higher. That is, the minimum version with which the extension works is 3.3.[go to XML description]
 * It supports the update feature and update information can be obtained at the specified address. [go to XML description]
 * A license text is displayed during installation. Different localizations of the license text are available. [go to XML description]
 * There are two localized versions of a publisher name and URL. [go to XML description]
 * There are two links to release notes in different languages. [go to XML description]
 * There is a localized display name. That is, in an English version of LibreOffice the Extension Manager will show the string: My great extension. [go to XML description]
 * The extension contains icons which are used by the Extensions Manager when displaying the extension. [go to XML description]
 * A localized description is displayed in the Extension Manager's dialog. [go to XML description]

Please note that the and  elements in a description.xml are currently not used by the Extension Manager. However, when uploading the extension to the extensions repository (https://extensions.openoffice.org) then these elements are used for generating update information. When the Extension Manager looks for updates then it displays this information (since OpenOffice.org 2.4).

Display Name
An extension can have a display name. This name is defined in the description.xml. The name is optional. If it is provided then the Extension Manager will show it in the dialog, otherwise the file name will be displayed.

The display name is localized. The description.xml may provide additional names in different languages. The Extension Manager will then choose a language which matches most closely the locale of the office. How this exactly works is explained at Localized XML Elements.

See also
 * XML description for description.xml
 * Example of description.xml

Icon
The Extension Manager displays a default icon for each extension, unless an extension provides its own icon. The icon must be declared in the description.xml.

The icon must be provided as png or jpeg and it should have a size of 42x42 pixels.

See also
 * XML description for description.xml
 * Example of description.xml

Extension Description
The Extension Manager can display a small text for each extension in the dialog. The full text will become visible when the extension is being selected. Originally, this text was displayed in a 'tool tip' in versions of OpenOffice.org previous v3.0.

Versions of LibreOffice, earlier than 3.1, use the "Tooltip Description" of an extension which is kept in the manifest.xml. Using the "Tooltip Description" is deprecated as of OpenOffice.org 3.1 and that functionality will not be maintained. Since then the description is specified in the description.xml. OOo 3.1 and later will first try to get the description from the description.xml. If there is none then it will try to get the tooltip description. That is, extensions can start to use this feature and need not necessarily require OpenOffice.org 3.1. However, developers should be aware that the tooltip description may be removed in the future.

Using a description is similar to the use of a license. One can put a couple of localized description files into the extension and reference them in the description.xml. The description using a locale which matches that of the office will be displayed. See Documentation/DevGuide/Extensions for how the localization works. The description files must contain UTF-8 encoded text.

See also
 * XML description for description.xml
 * Example of description.xml

Extension Identifiers
Extensions now have unique identifiers. This removes the previous restriction that no two extensions with identical file names can be deployed. That is, two extensions with same file name but different identifiers can be installed but two extensions with the same identifiers cannot be installed at the same time.

The identifier plays also an important role for the on-line update. When running the on-line update, then the Extension Manager downloads a list of available extensions from the extension repository or from the location determined by the installed extension. The Extension Manager then tries to find an extension with a newer version in this list by comparing the identifier of the installed extensions with the identifier contained in the update information. Therefore the identifier MUST be unique. This is also the case when two extensions are logically the same but support different platforms. In this case one can achieve this uniqueness by adding a platform string to identifier. The 'Target Platform' section describes how this string can be generated in the build environment.

Technically, an extension identifier is a finite sequence of Unicode scalar values. Identifier identity is element-by-element identity of the sequences (no case folding, no normalization, etc.). It is assumed that extension writers cooperate to keep extension identifiers unique. By convention, use lowercase reversed-domain-name syntax (e.g., org.openoffice.) prefixes to generate unique (but still humanly comprehensible) identifiers. When you write an extension, use the reversed domain name of a site you control (and not org.openoffice.) as prefix. Identifiers starting with the prefix org.openoffice.legacy. are reserved for legacy extensions (see next). The same procedure used to avoid name clashes for extension identifier applies to all unique names in configuration files of extensions (configuration nodes in extendable lists etc.).

The extension identifier is obtained from the description.xml contained in the extension. If the extension does not specify such an explicit identifier, then an implicit identifier is generated by prepending org.openoffice.legacy. to the (obvious sequence of Unicode scalar values representing the) file name of the extension. (Uniqueness of identifiers is then guaranteed by the assumption underlying legacy extension management that no two legacy extensions have the same file name.)

As of OOo 3.3 providing an identifier is necessary for bundled and shared extensions (see Processing Extensions).

See also
 * XML description for description.xml
 * Example of description.xml

Extension Versions
Extensions are often improved over time. That is, publishers want to ship new versions of the same extension with added functionality and/or bug fixes. Adding extension versions allows publishers to ship new versions, and allows LibreOffice to detect and handle the case that an extension installed by the user is an update of an existing extension.

Technically, an extension version v is defined as an infinite sequence of non-negative integers v = ‹v0, v1, ...› where all but a finite number of elements have the value zero. A total order is defined on versions via lexicographical comparison. A textual representation of a version v = ‹v0, v1, ...› is a finite string built from the BNF

version ::= [element (“.” element)*] element ::= (“0” | “1” | “2” | “3” | “4” | “5” | “6” | “7” | “8” | “9”)+

of n ≥ 0 elements where each element is a decimal representation of vi for 0 ≤ i < n, and each vi = 0 for i ≥ n.

The extension version is obtained from the description.xml contained in the extension. If the extension does not specify such an explicit version, then an implicit textual version representation of the empty string (representing a version of all zeroes) is assumed.

No general semantics are prescribed to versions, other than the total order which determines whether one version is less than, equal to, or greater than another version, respectively. However, extension publishers are encouraged to use the widely accepted three-level scheme of major (incompatible changes), minor (compatible changes), micro (bug fixes) where applicable.

As of OOo 3.3 providing a version is necessary for bundled and shared extensions (see Processing Extensions).

See also
 * XML description for description.xml
 * Example of description.xml

Target Platform
[Since OpenOffice.org 3.0] It is possible to determine a target platform for an extension by providing a platform tag in the platform tag in the description.xml.

Please notice that this platform tag is ONLY used during installation in order to see if the user's platform is usable. It is NOT used for identifying an extension. Please read the identifier documentation for details.

If the platform is not present then it is assumed that all platforms are suitable. This corresponds to explicitly specifying all platforms:

The attribute value may contain one to many platform tokens separated by commas:

An extension can only be installed if one of the provided platform tokens matches the user's platform. The special 'all' platform represents all platforms. That is, the extension can be installed everywhere. Whereas

would prevent installation on all platforms.

The tokens need to be defined by LibreOffice. Every token can represent a particular platform constellation. The currently defined tokens are listed in the paragraph Platform Tokens

Do not confuse these tokens with those used to specify a native library in the manifest.xml. We will unify the use of the tokens in one of the future releases.

Platform Tokens
The tokens with the description 'Not yet supported' will be supported at a later time (see issue 88578).

Backward Compatibility of Platforms
Often an LibreOffice built for 32bit platform will run on the respective 64bit platform as well. In this case the platform element would only need the value of the 32bit platform. The reason is, that the extension manager compares the platform of the extension with the platform for which LibreOffice was built. Here are some examples:

Generating the Platform String in the Build Environment
When it is necessary to generate the description.xml and the platform string during in the build process one can utilize the rtlbootstrap.mk which is contained in the inc folder. rtlbootstrap.mk is build in module sal and contains values for the operating system and processor. For example:

These values correspond to the values of the bootstrap variable ${_OS} and ${_ARCH}. The file can be included in the makefile which generates the description.xml and use

to form the string.

See also
 * XML description for description.xml
 * Example of description.xml

Simple License
This feature is about displaying a license text to the user during installation. This is not supported for bundled extensions. Distributors of LibreOffice need to clarify license details with the publishers of extensions, which they want to bundle with LibreOffice.

The user can agree or decline the license, where in the latter case the installation will be aborted. It is called “Simple License” because there is no tamper resistant mechanism that prevents the installation in case the user does not agree to the license. It also does not do anything more than just displaying a license text. The text can be localized (see Documentation/DevGuide/Extensions).

The license text is displayed either in a dialog or in the console dependent on the way the Extension Manager was started. When it was started by the Tools - Extension Manager menu item or by invoking  in the console then a dialog is used. By using unopkg add the license text will be displayed in the console and user input has to be done through the same.

The license dialog or the license text in the console is displayed when the extension is being installed. Currently, there are two modes to install extensions, user mode and shared mode. An extension that was installed in user mode (let's call it a user extension) can only be used by just that person who installed it. If the extension was installed in shared mode (let's call it a shared extension), then it can be used by all users. Since the license text is only displayed during installation, all users who are using a shared extension will not see any license text (except the user who installed this shared extension). However, the publisher of the extension may think it necessary that everyone who wants to use it has to agree to the license first. For this purpose, he can mark the extension accordingly. This extension can then only be installed in user mode and not in shared mode. Likewise, the extension can be marked indicating that only the person who installs it needs to agree to the license. Such an extension can be installed in both modes. But when installing in user mode then every user has to agree to the license nonetheless.

As of OOo 3.3 shared extension can also require that every user accepts the license. This happens the first time a user starts LibreOffice after the shared extension was installed. If the user declines the license, then the extension is not usable for this user. It will, however, be displayed in the dialog, where the user can accept the license later. Similarly, a user can accept the license by running. For example

Here is an example of the description.xml:

In this example, the license would have to be agreed to by all users (that means no shared mode installation). This is indicated by the value  of the attribute accept-by in the   element. The attribute could also have the value, which would indicate that the license needs only be agreed to by the person who installs it.

The  elements contain information about the files which contain the text that is displayed. The content of these files must be UTF-8 encoded. It is displayed exactly as it is in the file. That is, no formatting occurs. There can be one to many  elements, where each element provides information about a different language of the license text. The attribute  contains a relative URL (relative to the root directory of the extension) which points to a file which contains the license text in exactly one language. Which language is indicated by  attribute.

If the package manager does not find a  element which matches the locale of LibreOffice then it will pick the first   element as the default. Prior to OpenOffice.org 2.4, the default entry needed to marked explicitly by  attribute.

Important Issues

 * (Obsolete as of OpenOffice.org 3.3) Using the simple license in extensions always requires user interaction. Using  in the   prevents this extension from being installed centrally, that is as shared extensions. Both issues can prevent the extension from being used by companies, which centrally maintain software.
 * (Obsolete as of OpenOffice.org 3.3. Feature is not supported, but installation will not hang when using extensions with a license) The 'simple license' does not work for bundled extensions (installation will probably hang as user input is required). If one wants to build an LibreOffice installation set with bundled extensions, then they must not use this feature.

To get around these limitations, extensions need to provide the attribute suppress-if-required="true".

See also
 * XML description for description.xml
 * Example of description.xml

Dependencies
One can imagine a large variety of dependencies an extension can have on its environment: availability of certain UNO types and services, availability of features only present since some specific version of LibreOffice, availability of other installed extensions, availability of third-party libraries, etc.

To support this, a mechanism is introduced so that extensions can bring along a specification of their dependencies. When a user wants to install an extension, the application first checks whether all dependencies are met. If not, an error dialog is displayed informing the user that the extension could not be installed.

The only actual dependencies currently defined are, where X is the required underlying OpenOffice.org version (“2.1”, “2.2”, etc.), starting with OpenOffice.org 2.1; and a corresponding, rarely needed  , introduced in OpenOffice.org 3.1. (Even if an extension is installed in a derived product like StarOffice, these dependencies are on the underlying LibreOffice version.)

OpenOffice.org 2.0.3 and earlier are not prepared to correctly handle extensions with dependencies. In OpenOffice.org 2.0.3 and earlier, if a .uno.pkg (or .zip) extension specifies any dependencies, they are effectively ignored and the extension is installed nonetheless. An .oxt extension cannot be installed at all in OpenOffice.org 2.0.3 and earlier. So, if an extension shall run in any LibreOffice version, it should be named .uno.pkg and should not specify any dependencies; if an extension shall only run in OpenOffice.org 2.0.4 and later, it should be named .oxt and should not specify any dependencies; and if an extension shall only run in a future OpenOffice.org version, it should be named .oxt and should specify the appropriate dependencies (which will be defined by the time the given LibreOffice version is available).

There is a certain dilemma: On the one hand, nothing is yet known about the kinds of dependencies that will be defined in the future. On the other hand, at least some information about the unsatisfied dependencies of a future extension must be displayed in OpenOffice.org 2.0.4. Therefore, each dependency specified by an extension must contain a human-readable (non-localized, English) name that can be displayed to the user, conveying at least rudimentary information about the nature of the unsatisfied dependency. Future versions of OpenOffice.org that already know a certain kind of dependency are expected to display more detailed information.

Likewise, when new dependencies are defined over time, old versions of LibreOffice will not know about them. Those old versions will thus reject extensions making use of those dependencies, even if the old version would actually satisfy the dependencies. Therefore, each dependency specified by an extension may optionally contain an OpenOffice.org-minimal-version attribute that specifies the minimal version of LibreOffice that would satisfy the dependency. Old versions of LibreOffice that do not know the given dependency will then check for the optional attribute and, if present, nevertheless accept the dependency if the given version is large enough. This feature is only supported since OpenOffice.org 2.3.

Within the description.xml, dependencies are recorded as follows: An XML element whose name consists of the namespace name http://openoffice.org/extensions/description/2006 and the local part dependencies may appear at most once as a child of the root element. This element has as its element content an arbitrary number of child elements that are not further constrained except for the following: Each such child element should have an attribute whose name consists of the namespace name http://openoffice.org/extensions/description/2006 and the local part name, and it may optionally have an attribute whose name consists of the namespace http://openoffice.org/extensions/description/2006 and the local part OpenOffice.org-minimal-version. Each such child element represents one dependency, and the value of its name attribute shall contain the human-readable dependency name (and the value, after normalization, should not be empty).

If an extension is either not of type .oxt, .uno.pkg, or .zip, or does not contain a description.xml, or the description.xml does not contain a dependencies' element, or the dependencies' element does not contain any child elements, then the extension does not specify any dependencies.

See also
 * XML description for description.xml
 * Example of description.xml

Publisher Information
The publisher information consists of a name and a URL. The name should be a company name and the URL should point to a website of that company. This information is currently used in two places, the Extension Manager dialog (since OpenOffice.org 3.0) and the update dialog for extensions (since OpenOffice.org 2.4).

The publisher information is specified in the description.xml of an extension. The extension repository will use the information in the update information. That is, if someone checks for extension updates, than the update dialog will show this publisher information for this extension.

See also
 * XML description for description.xml
 * Example of description.xml

System Integration
When installing LibreOffice, the installation routine is adding information to the system which can be used by other software products to install extensions. For example, double-clicking on an extension in a file browser should start the Extension Manager and install the extension. Also mail clients and web browser should offer a way of installing the extension, when it comes as an attachment of an e-mail or is the target of a link.

Extension which are installed by way of using the system integration are always installed as user extensions.

The system integration is available since OpenOffice.org 2.2.0.

Online Update of Extensions
Extensions are often improved over a period of time. That is, publishers ship new versions of the same extension with added functionality and/or bug fixes. Currently users must update their extensions manually, that is, find out where to get updates, obtain the updates, remove the old extensions, install the new extension. This feature will make updating easier. Users can run the update mechanism from the Extension Manager. A dialog will show available updates and the user will be able to choose which to install.

More particular information for this feature can be found in the specification at:

http://specs.openoffice.org/appwide/packagemanager/online_update_for_extensions.odt

Currently the update mechanism completely replaces an installed extension. That is, the update is actually a complete new extension which could also be installed separately without replacing an earlier version of this extension.

See also
 * XML description for description.xml
 * Example of description.xml

Running Online - Update
The update procedure needs to be started by the user in the Extension Manager. One can update all installed extensions by pressing the Updates button or select particular extensions, press the right mouse button and select Update in the context menu. The extension manager will then try to obtain update information for the affected extension. If it finds that a new version of an extension is available then it will be displayed in the update window.

In some cases an update cannot be installed, for example because the installed extension is shared by all users and the current user does not have permission to manage shared extensions. In this case a message to this regard is displayed in the window. To update shared extensions one needs to close LibreOffice and run. Then the user has access to all extensions.

An extension may also not be installable, because it has unfulfilled dependencies. For example, the extensions requires a particular version of LibreOffice.

The user can determine which of the updates he wants to install by checking them. When the button is pressed then, as the name suggests, the extensions are being downloaded and installed.

Concept
The actual download location of an update is contained in the update information which is typically a xml file which is hosted on a server. Every update information contains only information for exactly one extension. The most important information are the location of the update and the version of this extension.

The Extension Manager needs to get hold of the update information in order to decide if the respective extension is a valid update. For example, it only makes sense to take a version into account that is greater than the version of the already installed extension. The information where the update information is located is contained in the description.xml of each extension. In particular the children of the  element, contain URLs which reference the update information. The Extension Manager uses these URLs to download the update information and later uses the information in the update information to download the respective extension.

In case that an extension does not contain a description.xml or the description.xml does not contain the  element, the Extension Manager uses a default location to get update information. This location is build-in, and is therefore determined by the publisher of LibreOffice. Currently, this information is contained in the version.(ini|rc) of the office installation.

One piece of update information only contains the information for exactly one extension. To bundle several update information one can use an XML atom feed. For example a feed could reference multiple update information, which refer all to an extension with the same Id but have different versions. It could also contain references to update information of distinct extensions (different Id). Then the Extensions Manager will pick out the information it needs.

Not only the built-in URL can reference an atom feed but also every extension.

To find a suitable update, the Extension Manager, gathers in a first step all pieces of update information which have the same identifier as one of the installed extensions. Then it determines the latest version for an extension from those update information. If the latest version is greater than the version of the corresponding installed extension, then the respective extension is offered as an update.

Using an Atom Feed
By using an atom feed one has greater flexibility in terms of where the actual updates are hosted. For example, a company which has published many extensions, may utilize just one atom feed which are referenced by all extensions. The location of this atom feed must be well chosen, because changing it may break the automatic update. Then the Extension Manager cannot obtain update information for these extensions anymore. For this reason, the company could set up a dedicated server which is guaranteed to be available in the foreseeable future. The actual extensions can then be hosted on different servers. The atom feed file needs only be edited if an update information file is moved to a different place, or when update information for new extensions become available.

If no actual update is available, for example, there is just version 1.0, then the update information could still refer to this extension. This does not do any harm because the Extension Manager compares the version number of the installed extension and the version which is contained in the update information, in order to display only real updates.

The location of the extension used as update could be the same as the location where customers download the extension for the first time. For example, there could be a web site which contains links to extensions. Let's assume one link is:

http://mycomp/extension.oxt

The extension references a feed at:

http://openoffice.org/extensions/updatefeed.xml

The feed contains the reference to the update information:

http://mycomp/updates/extension.update.xml

and this file refers to the update which is again:

http://mycomp/extension.oxt

If now version 2.0 of the extension becomes available, then the publisher could simply replace the extension at http://mycomp/extension.oxt and change the update information so that it reflects the new version. This way, users download always the latest version from the website and the Extension Manager can use this extension as update for an older version which is already installed.

Migration of Update Information
It could become necessary to change the server which hosts the update feed or update information. If this results in a different URL for these files, then the automatic update will not work. Therefore the following procedure is recommended.


 * 1) Plan for a transition period, that is long enough for most users to get a new update.
 * 2) Set up the new server, or the locations for hosting the update information, and run both servers in parallel. That is, the same update information and updates should be available from both servers.
 * 3) Prepare new versions for extensions that contain an URL to the new server.
 * 4) Switch off the old server after the transition period. Users, which have obtained the update, will be able to use the update mechanism as before. All other users will not be able to get an update anymore.

Description of the Update Information
The update information can be contained in a file which can be directly accessed through a URL or it can be generated on demand (HTTP get request). If it is a file then it could be named according to this pattern:

.update.xml

For example, the update information file for the extension myextension.oxt is myextension.update.xml. The .oxt file extension is not used.

It follows the description of the XML structure of the update information data:

Element

 * Parent element: document root
 * Children:
 * Since: OOo 2.2
 * Since: OOo 2.2
 * Since: OOo 2.2
 * Since: OOo 2.2
 * Since: OOo 2.2
 * Since: OOo 2.2
 * Since: OOo 2.2
 * Since: OOo 2.2

is the root element of the update information XML document.

Element

 * Parent element:
 * Children: none
 * Since OOo 2.2

Element

 * Parent element:
 * Children: none
 * Since: OOo 2.2

Element
must have at least one  child element. If  is provided then there must not be a   element.
 * Parent element:
 * Children:
 * Since: OOo 2.2
 * Since: OOo 2.2

The second, third, etc. element are regarded as fallback, that is, the elements provide URLs to mirrors. The Extension Manager will try to download the extension by using the first URL and only uses the next URL if an error occurred, for example because the the connection was interrupted.

Example:

Element

 * Parent element:
 * Children: none
 * Since: OOo 2.2

Element
must have at least one  child element. If  is provided then there must not be a   element.
 * Parent:
 * Children:
 * Since: OOo 2.4
 * Since: OOo 2.4

The children of this element provide a URL to the web site where the new version of the extension can be downloaded. There can be multiple localized web sites with different URLs. Each URL can be provided by a separate    element. See Localized XML Elements about how the Extension Manager chooses the proper  element.

Example:

Element

 * Parent:
 * Children: none
 * Since: OOo 2.4

Element

 * Parent element:
 * Children:
 * others
 * Since: OOo 2.2
 * others
 * Since: OOo 2.2

Example:

Element
The namespace of this element must be http://openoffice.org/extensions/description/2006.
 * Parent element:
 * Children: none
 * Since: OOo 2.2

Element
The namespace of this element must be http://openoffice.org/extensions/description/2006.
 * Parent element:
 * Children: none
 * Since: OOo 3.1

Element

 * Parent:
 * Children:
 * Since: OOo 2.4
 * Since: OOo 2.4

The children of this element provide a localized publisher name together with a URL. must have at least one  child element.

The publisher name is displayed in the update dialog of the Extension Manager. Clicking on the name causes the web browser to be opened which navigates to the web site determined by the  element.

Example:

Element

 * Parent:
 * Children: Text
 * Since: OOo 2.4

The text value of this element is the publisher name.

Element

 * Parent:
 * Children:
 * Since: OOo 2.4
 * Since: OOo 2.4

The children of this element provide URLs to localized release-notes. must have at least one  child element.

The update dialog of the Extension Manager shows a link to the release notes if this element is provided. Clicking on it will cause a web browser to be opened which navigates to the release notes page using the URL provided by the respective  element.

Example:

Element

 * Parent:
 * Children: none
 * Since: OOo 2.4

The element contains a URL to the release notes.

Description of Atom Feed
The atom feed is described at: Update Notification Protocol

description.xml Containing Direct Reference to the Update Information
The following content of a description.xml directly references update information:

The second src element contains a URL to a mirror which will be used by the Extension Manager if the location referenced by the URL in the first src element cannot be reached.

This is the content of extension.update.xml:

The src element contains a URL to version 2.0 of extension.oxt. extension.oxt has the identifier  because it does not define an identifier in its description.xml. Otherwise the identifier would be the same as the one in the description.xml.

description.xml OpenOffice.org 3.x update information example
The following content of a description.xml directly references update information for a German Windows OpenOffice.org 3.3.0:

Using the Atom Feed
This is the content of the description.xml of feed1.oxt which references an atom feed:

The feed:

The feed contains two entry elements and each references the update information for a different extensions. It could, however, also reference the update information for two different versions of the same extension.

The update information for the version of feed1.oxt:

Options Dialog
Extensions can add options pages to LibreOffice's options dialog. They should not create their own menu or menu entries for the sole purpose of configuring the extension. This is what the options dialog is for.

It is also possible to start an options dialog from within the Extension Manager on behalf of a particular extension. An options page represents a child window that is displayed within the options dialog. An extension can provide multiple options pages. It can determine that they can be added to already existing nodes, such as “OpenOffice Writer” or “Internet Settings”. It is also possible to create completely new nodes.

The specification for this feature can be found at: http://specs.openoffice.org/appwide/packagemanager/options_dialog_for_extensions.odt

In the following paragraphs we will show what has to be done in order to add options pages to an extension. Along the way we will go into some details where necessary. It is assumed that the reader has already knowledge about extension programming and that he or she knows how the LibreOffice's registry (including xcs and xcu files) works.

A note about writing some terms. When we refer to elements from the configuration schema of LibreOffice then we use the respective uppercase names, for example Node, Module. The plural will expressed by adding a pipe symbol and the respective postfix, for example Nodes, Modules.

Available samples

 * API/Samples/Java/Office/OptionsPageDemo

Creating the GUI of the Options Page
The GUI of an options page needs to be created by the dialog editor of LibreOffice. Exporting the dialog will result in saving a .xdl file and perhaps multiple .properties files. The xdl file contains the description of the dialog in XML whereas the properties files contain localized strings. For example, if the dialog is named Dialog1 and it contains strings which are localized for German and US – English, then you will obtain these files:


 * Dialog1.xdl
 * Dialog1_de_DE.properties
 * Dialog1_en-US.properties

Please make sure that you have set the property “With title bar” to “no” for the whole dialog. Note that the maximum size that the dialog may have in the options page is a width of 260 and a height of 185.

The exported files can be anywhere in the extensions, except in META-INF. They must also be in the same directory.

The options dialog will use the service com.sun.star.awt.ContainerWindowProvider to create the options pages. The service constructors takes an URL to the xdl file and an an event handler component. The latter will be used to process events which have been defined in the dialog editor for particular controls. It is also used for saving and loading the data of the controls which are on the options pages.

Saving and Reading Data for the Options Page
An options page typically allows the user to enter some data, which of course must be saved when the user presses the OK button. When the options page is displayed it should show the data which the user entered previously. In case nothing has ever been entered, the options page could show some “default” data or nothing at all.

How the data is saved and where it is stored is not covered by the specification. It only defines the events “ok”, “initialize”, and “back” which the extension needs to process in order to save the entered data, initialize the controls with data, or restore the state of the controls with the previously saved data. The “ok” and “back” events are triggered by the “OK” and “Back” button of the options dialog. “initialize” is called before the options page is being displayed. In most cases “initialize” and “back” have the same meaning.

In order to receive these events one has to provide a service that implements the interface com.sun.star.awt.XContainerWindowEventHandler. The component is then installed like any other component. That is, one provides for example a jar file or a dll and adds the proper entries to the manifest.xml.

The action events are processed in the com.sun.star.awt.XContainerWindowEventHandler:callHandlerMethod. This method takes three parameters. The first is a com.sun.star.awt.XWindow which represents the dialog for which the event is called. The second is an, which describes the actual event. Therefore the IDL calls it the “EventObject”. The last parameter is a string which contains a “method name”. This method may not exists, but the name identifies an action which should be invoked.

In case of our previously mentioned events the method is called with the respective com.sun.star.awt.XWindow interface, a method name of “external_event”, and an any containing either “ok”, “back”, or “initialize”. For example, the java code could look like this:

The method  and   need to be implemented according to where the data actually is stored. In most cases the LibreOffice's registry is a suitable place. Then, of course, one needs to provide a configuration schema (requires an appropriate entry in the manifest.xml as well).

For example:

Please make sure that the package together with the name  for this schema are unique. For example, it should start with YOUR reversed domain name (do not use  in your code), followed by the product name and other values which together uniquely identify this registry node.

In the example I have defined a group “Leaves”, which contains several entries and which are all of the same type. Each entry holds the data for one options page. In this case, each options page may provide five different strings.

If a new version of the extension uses the same schema, then data, which have been entered by a user for the previous version, will be automatically applied for the new version. If this is not wanted then one need to provide a new schema. In our case we could just change the attribute oor:component-schema@ oor:name to a value, for example, ExtensionData2.

Now the question is, how one can access the controls on the options page in order to set the data or read from them. The following code example shows the whole service as Java implementation. Please have look at the  and   method. Please be aware that is is only an example and may need to be adapted to personal needs.

public static XSingleComponentFactory __getComponentFactory(String sImplName) { XSingleComponentFactory xFactory = null;
 * @return returns a  for creating
 * the component
 * @param sImplName the name of the implementation for which a
 * service is desired
 * @see com.sun.star.comp.loader.JavaLoader
 * @see com.sun.star.comp.loader.JavaLoader

if ( sImplName.equals( _OptionsEventHandler.class.getName ) ) xFactory = Factory.createComponentFactory(_OptionsEventHandler.class, _OptionsEventHandler.getServiceNames);

return xFactory; }

/** public static boolean __writeRegistryServiceInfo(XRegistryKey regKey) { return Factory.writeRegistryServiceInfo(_OptionsEventHandler.class.getName, _OptionsEventHandler.getServiceNames, regKey); }
 * Writes the service information into the given registry key.
 * This method is called by the
 * @return returns true if the operation succeeded
 * @param regKey the registryKey
 * @see com.sun.star.comp.loader.JavaLoader
 * @see com.sun.star.comp.loader.JavaLoader

/** This method is a member of the interface for initializing an object public void initialize( Object[] object ) throws com.sun.star.uno.Exception { }
 * directly after its creation.
 * @param object This array of arbitrary objects will be passed to the
 * component after its creation.
 * @throws Exception Every exception will not be handled, but will be
 * passed to the caller.

}

Defining the Usage of Options Pages
It needs to be defined somewhere how the options dialog shall display the options pages for particular extensions. This information needs to be provided by the extensions in form of a xcu file which contains the appropriate registry entries. The schema is already provided in the office installation. The file is: /share/registry/schema/org/openoffice/Office/OptionsDialog.xcs. Here are the relevant parts for the options pages:

Adding a Leaf to an Existing Node
Let us start with something simple and assume that we want to add a leaf under the "OpenOffice.org" writer node. The leaves and nodes, which we are talking about, appear in the tree view of the options dialog on the left side. A leaf has the meaning of an entry which cannot be expanded further. Selecting a leaf will cause the options page being displayed on the right side. Please do not confuse these node and leaves with the elements from the schema. The latter use uppercase names and the plural is indicated using a pipe symbol, such as "Node|s". There is also a xml element "node" in the xcu file. In case the meaning is unclear in the respective context, we will add small note.

The schema in the OptionsDialog.xcs defines two sets which we can add to. One contains Modules, which we do not need at the moment, and the other contains Nodes, which is the place we will add to. As the name suggest, it contains Nodes and not Leafs. But every Node contains a set of Leafs, which is named Leaves. This means, that we have to add a Leaf to the Leaves set of the writer Node. This is done by putting the following xcu file into the extension (do not forget to add the corresponding entry into the manifest.xml).

In the following examples I will leave out the xml, doctype and root element so we can focus on the relevant parts. In the previous example we see the lines:

The first line represents the set Nodes. The second line shows that we add to the writer Node. And the last line represents the Leaves set within the writer Node. The names of Node|s should be unique, as we will see later. The name is the value of the oor:name attribute of the set entry. That is, there is no special property "name". The names for already existing Node|s and Module|s are rather short and are reserved exclusively for the office. The list of those names can be found here.

Currently the already existing nodes are not defined in the registry (but may be in future versions). Therefore, the node Writer, which is a set entry, may not exist yet, unless another extension has already added to this node. To make sure that there is this node we use the operation fuse. Leaves is the set within a Node (the type defined in the templates section of the schema) to which we add our leaf:

When we add to a set then we must provide a unique name for the oor:name attribute of the node element. We did this by calling it:

It is always good to use long names to ensure uniqueness. Starting with the reversed domain name is a good practice, because most developers or companies own a domain, which is already unique. Node names must use ASCII letters and special characters must be "xml encoded". That is signs, such as "<", ">", "&", etc must be replaced by "&amp;lt;", "&amp;gt;", "&amp;amp;", etc. This is also valid for all other xml attribute values or the text between enclosing xml elements. Our leaf node also uses the fuse operator, to ensure that it is added to the set.

It is also useful to avoid "/" within oor:name. This will make it harder when using the API to access the values (see com.sun.star.container.XHierarchicalNameAccess ). Then one need to encode the name in a particular way. See chapter Configuration Management.

The value of the property  must be same as the extension identifier. The identifier is used to locate the leaves which belong to a particular extension. This happens when the options dialog is started in the Extension Manager. In this case only the entries for the selected extension are displayed.

The property  contains the string which appears in the tree view. One can provide many different localized strings. However it is good to have at least an en-US string, which will be used as default in case there is no string which locale matches that of the office.

The property  contains the URL to the xdl file of the dialog which shall appear when the user selects the corresponding entry in the tree view. Please note that it always starts with %origin% and is followed by the relative path to the file.

The property  contains the service name of the handler, which is also contained in the extension. One should take care to choose a unique name. It is not necessary to provide any IDL description or type library for the service.

Adding Several Leaves
It may be necessary to add more then one leaf. This is easily done by just writing the next leaf definition after the previous:

In the example we have also added three other Leafs to the Calc Node.

Grouping of Leaves
When we add several Leafs to the same Node then we may wish to determine in which order they appear. This is done by using the properties  and   in Leaf. The  is used to define a group. All Leafs with the same  form this group. The  determines the position of the Leaf with regard to this group. If there are multiple groups of Leafs assigned to the same Node, then it is undefined in which order the groups are displayed. However, the members of a group are always displayed contiguously.

The value for the  must be unique. One can use the same patter here as for the names of Leafs, Nodes, etc.

One special  is the one which has the same value as the Node name. This group is always displayed first under the node in the tree view. We will get to that later.

Usually, when an extension provides Leafs which are all assigned to the same Node, then one makes them belong to the same group.

Adding Nodes
Apart from Leafs one can also define one's own Nodes. First we would like to define one simple Node along with a few Leafs:

Because a Node is represented in the tree view with a string, it needs to provide a localized name the same as Leafs do. To do this we add under the property Label several localized values.

The property OptionsPage has the same meaning as the same property in Leaf. There is, however, the restriction that the options page must not take user input. Instead is should contain some explanatory words about the node.

The property AllModules needs to be set to true when one wants that the Node appears in the options dialog from all applications. Now, let me explain shortly the meaning of Module, because it will be important for the definition of Nodes. The options dialog opened from the Tools - Options... menu entry refers always to a particular Module, which depends on the current application. All Nodes can be assigned to one or multiple Modules. That is, a Node may be defined to appear only in the options dialog of the Writer and Calc application. How this is done will be explained later. However, often one wishes to have the Node displayed in every options dialog. To save the effort of assigning a Node to all existing Module|s separately, one can do this just once by setting the property of AllModules to true. This is also useful in the case where new Modules are added later, because these new Modules would not know about those Nodes.

Adding Several Nodes
As one might have imagined, adding several nodes is similar to adding various leaves. The definitions are just written one after the other:

Absolute Position of Leaves
When one defines a Node and Leaf|s for this Node at the same time then one would like to specify the position of those leaves as well. This can be done be defining group of Leafs which has the same name as the Node to which they are assigned. This group is special because its Leafs are the first which appear under the corresponding node in the tree view. Otherwise the use of GroupIndex and GroupId is identical as explained in “Grouping of Leaves”.

Grouping of Nodes
Similar to Leafs, Nodes can be grouped as well. For example, an extension would like to add three nodes to the options dialog of the Writer. Then one may want that these nodes are displayed contiguously. This will also be achieved by defining a group with the property GroupId and an index with the property GroupIndex. The index only determines the position within the group.

The ordering of Nodes within a group is basically the same as with Leafs. But there is a small difference. In contrast to Leafs, Nodes can be assigned to various Modules, whereas as Leaf can only be assigned to one Node. So actually one could define an order of Nodes per Module. The order could then differ depending on the Module. For example, we define Node A and B which are assigned to the “Writer” Module (actually the names for the modules are longer, for example, com.sun.star.text.TextDocument) and the “Calc” Module. We could define that in the options dialog of the Writer node A is before B and in the options dialog of Calc B is before A.

This would have added some more complexity to the data structures. With respect to the ease of use we decided for a compromise. One can only define one order independent of the Module. In the previous example the nodes A and B would have the same order in the Writer's and Calc's options dialog. But what if one Node is not assigned to a particular Module but the others are? For example, there are the Nodes A, B, C which have the indices 0, 1, 2. Only A and C are assigned to the “Writer” Module. Then in the options dialog of the Writer the node A would immediately followed by C.

Assigning Nodes to Modules
In the previous paragraphs we have explained what has to be done so that a node appears in the options dialog of an application no matter what the application is. Now we will explain how one can pick out the application where the node should appear.

Having a look at the schema of the OtionsDialog.xcs one notices that there is another set, named Modules, to which we can add entries which then determine where the nodes are displayed. If one does not care for a particular application then one should use the AllModules property of the Node, so that they are always displayed.

The example shows the definition of two Node|s. Both are displayed in the options dialog of the Writer but only “node 1” is displayed in the options dialog of Calc. This demonstrates also that a node can be assigned to various Modules.

The names of the application contexts defined by LibreOffice can be found here: Framework/Article/Options_Dialog_Configuration

Defining a Module
It is possible to define a Module of one's own. How an extension can provide a real module (not the type Module) is not part of this documentation. However, if this module does not exist, there won´t be an options dialog on behalf of this module and the Nodes assigned to it are not displayed. Only the options dialog from the Extension Manager may show the nodes because it does not depend on a particular module.

Here is an example of defining a Module.

Absolute Position of Nodes
If one defines an own Module, then it is possible to define an order for the Nodes which one assigns to it. These Nodes will be the first which are displayed in the options dialog followed by the Nodes which have been assigned by others.

For example:

As you can see, every Node which is assigned to a Module can be paired with an index (property Index).

The Options Dialog of the Extension Manager
The options dialog which is invoked from the Extension Manager only shows nodes with leaves which have been added by the currently selected extensions. The dialog has no particular application context, so that all nodes are displayed, independent of the application contexts which they are assigned to.

Help Content
Starting with OpenOffice.org 2.4 extensions can contain help content and extend the LibreOffice's installed help content. The feature supports:


 * Adding extension related help pages
 * Extending the help index to refer to these pages
 * Extended tool tips in UNO dialogs and menus
 * Accessing extension help content by pressing in UNO dialogs and menus.

Extension help format
The help content is located in a folder inside the extension oxt file. Usually the folder will be named “help”, but any other name can be used as long as it's assigned to the media type "application/vnd.sun.star.help" in /META-INF/manifest.xml. In this chapter the help folder name will always be “help” and all descriptions refer to the SDK sample extension DialogWithHelp.oxt developed by the fictional “Foo Corporation”.

Inside the help folder there's one folder for each supported language. The folders are named according to the common language codes en, de, fr etc. as they are also used inside the LibreOffice help folder. Inside each language folder there has to be another folder named like the extension identifier that has to be specified in the /description.xml file for each extension. As the identifier will be encoded to be used as folder name it's recommended to follow the naming scheme described in the Developers Guide Extension Identifiers,

e.g. “com.foocorp.foo-ext” to avoid differences between identifier and encoded identifier.

The identifier is part of the path to access the extension help files. The reason for this rule is to get an unique path to each help file inside the extension: a path that cannot clash with paths to help files in the installed help or in other extensions. Unfortunately – due to the design of the extension manager, the help sub package has no access to its parent package bundle – it's not possible to check at help compile time (see Deployment) if this identifier rule is violated and so no error message will be shown in this case. Nevertheless, help pages inside “illegal” folders will be suppressed at runtime, so the extension author should detect the problem when testing the extension. If a help package is not part of a parent bundle package, the identifier rule does not apply.

The following tree shows the structure of the DialogWithHelp.oxt help folder containing the languages en and de with three help pages each, one of those in a sub folder. The file / folder structure for all languages should be same, e.g. to make bookmarks pointing to extension help pages the same for all languages.

The help content will be compiled for all language when the extension is deployed. At runtime the help system tries to find the same language inside the extensions' help content that is also used to access the installed help. In case the extension's help doesn't support this language, the help system will always try to find English (en) help inside the extension and use this as a fallback.

Example:

DialogWithHelp.oxt │ ├─ DialogWithHelp │  │  │   └─ ... Dialog Library │ ├─ META-INF │  │  │   └─ manifest.xml (assigning “help” folder to media type  │                    "application/vnd.sun.star.help") ├─ help │  │  │   ├─ en  │   │   │ │  │   └─ com.foocorp.foo-ext │  │       │  │   │       ├─ page1.xhp │  │       │  │   │       ├─ page2.xhp │  │       │  │   │       └─ subfolder │  │           │  │   │           └─ anotherpage.xhp │  │  │   └─ de  │       │ │      └─ com.foocorp.foo-ext │          │  │           ├─ page1.xhp │          │  │           ├─ page2.xhp │          │  │           └─ subfolder │              │  │               └─ anotherpage.xhp │ ├─ Addons.xcu (Menu/Toolbar specification) │ └─ description.xml (contains identifier)

Deployment
Extension help content is deployed like any other extension content using the OpenOffice Extension Manager or the unopkg command line tool, usually as sub package inside a package bundle. All help files are detected automatically during extension deployment, no additional configuration file is needed to list them. The help files are compiled then similar to the installed help content being compiled during the OpenOffice.org build process. The compile process itself doesn't differ from the one in helpcontent2, but instead of referring to the main OpenOffice.org help modules like Writer, Calc etc. each extension is handled as its own small module.

All Help Compiler output is created inside the extension's cache folder. So it's guaranteed that all help content will be removed together with the extension. Help content of disabled extensions is ignored. Due to caching mechanisms used by the HelpProvider implementation changes in the extension state may not be visible before the next start of OpenOffice.

Error handling
During the deployment the extension's help files are compiled. If an error is found during compilation – usually this will be a XML parsing error - a corresponding error message will be displayed. End users shouldn't be affected by these errors as the extension developer should fix all problems before releasing the extension.

Only the first line of the error message is localized. It's followed by details in English directly using the error information provided by the Help Compiler respectively the XML parser. The following lines show an example for a XML parsing error. The first line is a localized string, the following lines are always in English.

The extension will not be installed because an error occurred in the help files: attributes construct error in file:///D:/OOo24/user_data/uno_packages/cache/uno_packages/15A7.tmp /DialogWithHelp.oxt/en/com.foocorp.foo-ext/page1.xhp, line 49

Integration into the OpenOffice help system
There are different ways to access extension help content respectively to integrate it into the installed help content.

Help module list box
Extensions don't have its own help module, neither as single extension nor for all extensions together. So the help module list box won't be affected by extension help content.

Help Viewer Contents page
Adding content to the Contents tree is supported from OpenOffice.org version 3.0.0. See specification http://specs.openoffice.org/appwide/help/ExtensibleHelp.odt

Help Viewer Index page
Adding index entries can be done in the same way as it's done in the installed help files (see File format). There's a difference concerning the way the index entries are assigned to the different help modules. In the OpenOffice.org installed help this is handled via the help file path. As extension help shouldn't be forced to use the same file naming scheme, instead a bookmark naming scheme is used here. The following example shows a bookmark defining an index entry (branch=”index”) visible for all modules:

 <bookmark_value>foo This is a single level entry</bookmark_value> <bookmark_value>foo first level;second level</bookmark_value>

If the index entries should only be visible for (a) special module(s) the module(s) it should be visible in can be added to the bookmark id using _ as separator, examples:

<bookmark xml-lang="en-US" branch="index" id="bm_foo001_swriter"> ...

will make all following bookmark_value entries only visible in the Writer index.

<bookmark xml-lang="en-US" branch="index" id="bm_foo001_scalc_sdraw"> ...

will make all following bookmark_value entries only visible in Calc and Draw index.

The module names to be used here are the same as in the installed help:

sbasic, scalc. schart, sdatabase, sdraw, simpress, smath, swriter.

Help Viewer Find page
Starting with OpenOffice.org 3.1 full text search is also supported for extension help. The extension developer doesn't have to care about this. During extension installation a help index will be created automatically. Search results found inside the extension help will be shown together with the results found in the LibreOffice help files ordered according to their score.

Help Viewer Bookmarks page
Bookmarks to extension help pages can be added. When the corresponding package is disabled or removed later the bookmark will not automatically be removed.

Context sensitive help and extended tool tips
Context sensitive help is based on Help Ids that are assigned to toolbar items, menu items and UNO Dialogs / Dialog controls. Toolbar and menu items do specify a Command URL to bind the item to an action to be taken when the item is executed. It's important to choose a unique Command URL, e.g. by following a similar scheme like for the extension identifier or to refer to a service implementing the functionality. Example Command URL:

This Command URL is also used as Help Id, both for extended tool tips as for assigning a help page to F1. Defining help Ids in xhp files is also done with the bookmark element (see File Format):

<bookmark xml-lang="en-US" branch="hid/com.foocorp.foo:DoTheFooAction" id="bm_foo02" localize="false"/> <paragraph role="paragraph" id="hd_id4711" xml-lang="en-US"><ahelp hid="com.foocorp.foo:DoTheFooAction" visibility="hidden">This is the extended tool tip for DoTheFooAction <paragraph role="paragraph" id="hd_id4712" xml-lang="en-US">This is the help Text for DoTheFooAction. …

The Command URL has to be used both for the branch value after hid/ and in the ahelp / hid value.

In the same way bookmarks can be bound to Dialogs / Controls created with the OpenOffice Dialog Editor. The user just has to assign a unique Help Id to a Dialog's or Control's Help URL property and define a corresponding bookmark as shown above. If a control has the focus, its Help URL has priority about the Dialog Help URL.

Links
Links to extension help pages are defined in the same way as in the LibreOffice help, only the path differs. Example:

<link href="com.foocorp.foo-ext/subfolder/anotherpage.xhp">Link to foo

Images
Starting with OOo 3.1 extension help can provide own pictures. In the LibreOffice help image tags always refer to a set of images distributed with the office product in the images.zip file. The following help image tag addresses an icon located there:

<image id="img_id0001" src="res/commandimagelist/sc_paralefttoright.png" width="0.222inch" height="0.222inch">

The width / height attributes are optional. The width and height attributes are currently (year 2009) ignored by the help system.

Tags like this of course also can be used in extension help files (even before OOo 3.1). To address an image inside the extension's help the src path has to start with the extension's id. So this will show the image located inside the extension's help at foo.oxt/help/en/com.foocorp.foo-ext/foo.png:

<image id="img_id0002" src="com.foocorp.foo-ext/foo.png">

Images can also be placed in subfolders:

<image id="img_id0003" src="com.foocorp.foo-ext/subfolder/foo2.png">

A consequence of this location is that you need to store an image for each language of help.

Images can be placed anywhere inside the extension package, not necessarily inside the extension's help tree. With another location, if the same image is used for different languages the help files will reference the same image file. In this example the image foo3.png is in the folder Images of the extension package.

<image id="img_id0004" src="com.foocorp.foo-ext/../../../Images/foo3.png">

File Format
The extension help content uses the XML based xhp file format that is also used for the LibreOffice installed help. A description can be found here:

http://documentation.openoffice.org/online_help/OOo2HelpAuthoring.pdf

Paths start with the Identifier folder inside the language folder. This is also reflected in the xhp files' tag, example:

<helpdocument version="1.0"> ... /com.foocorp.foo-ext/page1.xhp