Framework/Article/Addon Menu Toolbar Merging
TDF LibreOffice Document Liberation Project Community Blogs Weblate Nextcloud Redmine Ask LibreOffice Donate
Older LibreOffice versions have some ways to integrate add-on commands to the user interface. Although this approach should satisfy most developers, there are some who want to have more freedom where add-on commands should be located. Especially the menu bar is a central user interface element where developers want to have a better control. For example there are some developers who wants to implement alternative save commands, which should be placed in the
menu near the other save methods.There is an API based solution for developers who wants to integrate their commands to the user interface at defined positions, but it needs some effort to implement it correctly. Another drawback is that every developer has to do this implementation again and again which makes add-on development costly.
Solution
A declarative solution to add commands from add-ons to any position in the menu bar would make development much easier. Therefore the Addon.xcs schema configuration file must be extended to support this requirement. The following chapter describes which elements have to be added to provide a flexible and powerful merge mechanism.
<!DOCTYPE oor:component-schema SYSTEM "../../../../component-schema.dtd">
<oor:component-schema
xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
oor:name="Addons"
oor:package="org.openoffice.Office"
xml:lang="en-US">
<info>
<author>CD</author>
<desc >Contains general structures used to integrate external components into the Office user interface.</desc>
</info>
<templates>
<group oor:name="MergeMenuInstruction">
<info>
<desc>Describes a merge menu instruction of an external component. The name must be unique and should be written using a package-scheme like org.openoffice.external.applicationexecuter to minimize name clashes. A menu instruction describes how the attached menu items should be merged into the OpenOffice menubar.
</desc>
</info>
<prop oor:name="MergePoint" oor:type="xs:string">
<info>
<desc>The command that should be used as a reference point for the merge command.</desc>
</info>
</prop>
<prop oor:name="MergeCommand" oor:type="xs:string">
<info>
<desc>A command to be processed for this merge menu instruction.</desc>
</info>
</prop>
<prop oor:name="MergeCommandParameter" oor:type="xs:string">
<info>
<desc>Optional parameter(s) for a merge command. Interpretation depends on the individual command.</desc>
</info>
</prop>
<prop oor:name="MergeFallback" oor:type="xs:string">
<info>
<desc>A fallback command to be used if MergeCommand cannot be applied.</desc>
</info>
</prop>
<prop oor:name="MergeContext" oor:type="xs:string">
<info>
<desc>A property to define the context of this merge instruction. It can be empty or a colon separated list of the supported application modules.</desc>
</info>
</prop>
<set oor:name="MenuItems" oor:node-type="MenuItem">
<info>
<desc>An optional set to allow sub menus.</desc>
</info>
</set>
</group>
<group oor:name="MenuItem">
<info>
<desc>Describes a menu item representing a function of of an external component. The name must be unique and should be written using a package-scheme like org.openoffice.external.applicationexecuter to minimize name clashes.</desc>
</info>
<prop oor:name="URL" oor:type="xs:string">
<info>
<desc>A command URL which represents the function to execute.</desc>
</info>
</prop>
<prop oor:name="Title" oor:type="xs:string" oor:localized="true">
<info>
<desc>A localized string used to as the menu item title.</desc>
</info>
</prop>
<prop oor:name="ImageIdentifier" oor:type="xs:string">
<info>
<desc>A private URL used to reference an optional internal menu image. Example: private:image/3216 addresses the internal Office image with id=3216.</desc>
</info>
</prop>
<prop oor:name="Target" oor:type="xs:string">
<info>
<desc>This is the target URL which is used for the dispatch command. There are special URL's to address certain targets: _self, current frame; _default, default; _blank, create new frame.</desc>
</info>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<info>
<desc>An property to define the context of a menu item that has a sub menu. It can be empty or a colon separated list of the supported application modules.</desc>
</info>
</prop>
<set oor:name="Submenu" oor:node-type="MenuItem">
<info>
<desc>An optional set to allow sub menus.</desc>
</info>
</set>
</group>
<group oor:name="PopupMenu">
<info>
<desc>Describes a menu item/toolbar item representing a function of an external component. The name must be unique and should be written using a package-scheme like org.openoffice.external.applicationexecuter to minimize name clashes.</desc>
</info>
<prop oor:name="Title" oor:type="xs:string" oor:localized="true">
<info>
<desc>A localized string used to as the menu title.</desc>
</info>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<info>
<desc>An property to define the context of a top-level popup-menu . It can be empty or a colon separated list of the supported application modules.</desc>
</info>
</prop>
<set oor:name="Submenu" oor:node-type="MenuItem">
<info>
<desc>An optional set to allow sub menus. This property cannot be used for toolbar item definitions.</desc>
</info>
</set>
</group>
<group oor:name="ToolBarItem">
<info>
<desc>Describes a toolbar item representing a function of of an external component. The name must be unique and should be written using a package-scheme like org.openoffice.external.applicationexecuter to minimize name clashes.</desc>
</info>
<prop oor:name="URL" oor:type="xs:string">
<info>
<desc>A command URL which represents the function to execute.</desc>
</info>
</prop>
<prop oor:name="Title" oor:type="xs:string" oor:localized="true">
<info>
<desc>A localized string used to as the menu item title.</desc>
</info>
</prop>
<prop oor:name="ImageIdentifier" oor:type="xs:string">
<info>
<desc>A private URL used to reference an optional internal menu image. Example: private:image/3216 addresses the internal Office image with id=3216.</desc>
</info>
</prop>
<prop oor:name="Target" oor:type="xs:string">
<info>
<desc>This is the target URL which is used for the dispatch command. There are special URL's to address certain targets: _self, current frame; _default, default; _blank, create new frame.</desc>
</info>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<info>
<desc>An property to define the context of a toolbar item. It can be empty or a colon separated list of the supported application modules.</desc>
</info>
</prop>
</group>
<group oor:name="MergeToolBarInstruction">
<info>
<desc>Describes a merge toolbar instruction of an external component. The name must be unique and should be written using a package-scheme like org.openoffice.external.applicationexecuter to minimize name clashes. A toolbar instruction describes how the attached toolbar items should be merged into an existing toolbar.</desc>
</info>
<prop oor:name="MergeToolBar" oor:type="xs:string">
<info>
<desc>Defines the toolbar resource URL.</desc>
</info>
</prop>
<prop oor:name="MergePoint" oor:type="xs:string">
<info>
<desc>Describes the command that should be used as a reference point for the merge command.</desc>
</info>
</prop>
<prop oor:name="MergeCommand" oor:type="xs:string">
<info>
<desc>A command to be processed for this merge menu instruction.</desc>
</info>
</prop>
<prop oor:name="MergeCommandParameter" oor:type="xs:string">
<info>
<desc>Optional parameter(s) for a merge command. Interpretation depends on the individual command.</desc>
</info>
</prop>
<prop oor:name="MergeFallback" oor:type="xs:string">
<info>
<desc>A fallback command to be used if MergeCommand cannot be applied.</desc>
</info>
</prop>
<prop oor:name="MergeContext" oor:type="xs:string">
<info>
<desc>A property to define the context of this merge instruction. It can be empty or a colon separated list of the supported application modules.</desc>
</info>
</prop>
<set oor:name="ToolBarItems" oor:node-type="ToolBarItem">
<info>
<desc>Contains a list of toolbar items used by an Add-On.</desc>
</info>
</set>
</group>
<group oor:name="UserDefinedImages">
<info>
<desc>A group of optional user-defined images. There are two ways to define image - 1. Embed the image data directly into the configuration. 2. Use file URLs to address external bitmap files. Embedded image data has a higher priority than file URLs.</desc>
</info>
<prop oor:name="ImageSmall" oor:type="xs:hexBinary">
<info>
<desc>Binary bitmap data used for menu images and small toolbox buttons. Standard size of a small image is 16x16 pixel.</desc>
</info>
</prop>
<prop oor:name="ImageBig" oor:type="xs:hexBinary">
<info>
<desc>Binary bitmap data used for big toolbox buttons. Standard size of a big image is 26x26 pixel.</desc>
</info>
</prop>
<prop oor:name="ImageSmallHC" oor:type="xs:hexBinary">
<info>
<desc>Binary bitmap data used for high contrast displays. Standard size of a small image is 16x16 pixel.</desc>
</info>
</prop>
<prop oor:name="ImageBigHC" oor:type="xs:hexBinary">
<info>
<desc>Binary bitmap data used for high contrast displays. Standard size of a big image is 26x26 pixel.</desc>
</info>
</prop>
<prop oor:name="ImageSmallURL" oor:type="xs:string">
<info>
<desc>A file URL to address a external bitmap file used for menu images and/or small toolbox buttons. Standard size of an small image is 16x16 pixel.</desc>
</info>
</prop>
<prop oor:name="ImageBigURL" oor:type="xs:string">
<info>
<desc>A file URL to address a external bitmap file used for big toolbox buttons. Standard size of an big image is 26x26 pixel.</desc>
</info>
</prop>
<prop oor:name="ImageSmallHCURL" oor:type="xs:string">
<info>
<desc>A file URL to address a external bitmap file usedxfor high contrast menu images and/or toolbox buttons. Standard size of an small image is 16x16 pixel.</desc>
</info>
</prop>
<prop oor:name="ImageBigHCURL" oor:type="xs:string">
<info>
<desc>A file URL to address a external bitmap file used for big high contrast toolbox buttons. Standard size of an big image is 26x26 pixel.</desc>
</info>
</prop>
</group>
<group oor:name="Images">
<info>
<desc>A group that associates images to a command URL</desc>
</info>
<prop oor:name="URL" oor:type="xs:string">
<info>
<desc>The command URL that is bound to the defined images.</desc>
</info>
</prop>
<node-ref oor:name="UserDefinedImages" oor:node-type="UserDefinedImages">
<info>
<desc>An user-defined images group.</desc>
</info>
</node-ref>
</group>
<set oor:name="ToolBarItems" oor:node-type="ToolBarItem">
<info>
<desc>Contains a list of toolbar items used by an Add-On.</desc>
</info>
</set>
<set oor:name="MergeMenuItems" oor:node-type="MergeMenuInstruction">
<info>
<desc>Contains a list of merge menu instructions defined by an Add-On which specify how to merge menu items into the Office menubar.</desc>
</info>
</set>
</templates>
<component>
<group oor:name="AddonUI">
<info>
<desc>Contains information about the structure of addon user interface.</desc>
</info>
<set oor:name="AddonMenu" oor:node-type="MenuItem">
<info>
<desc>Contains the structure of the addon menu used by the Office. It provide functions of external components to the user.</desc>
</info>
</set>
<set oor:name="Images" oor:node-type="Images">
<info>
<desc>Contains the structure for user-defined images which can be used by menu items and toolbar buttons.</desc>
</info>
</set>
<set oor:name="OfficeMenuBar" oor:node-type="PopupMenu">
<info>
<desc>Contains the structure of addon popup-menus inserted into the Office menubar. It provide functions of external components to the user.</desc>
</info>
</set>
<set oor:name="OfficeMenuBarMerging" oor:node-type="MergeMenuItems">
<info>
<desc>Contains a list of sets of menu items which should be merged into the Office menubar.</desc>
</info>
</set>
<set oor:name="OfficeToolBar" oor:node-type="ToolBarItems">
<info>
<desc>Contains a list of add-on toolbars added to OpenOffice.org.</desc>
</info>
</set>
<set oor:name="OfficeToolbarMerging" oor:node-type="MergeToolBarItems">
<info>
<desc>Contains a list of toolbar merging instructions of different add-ons. </desc>
</info>
</set>
<set oor:name="OfficeHelp" oor:node-type="MenuItem">
<info>
<desc>Contains a list of functions inserted into the Office help menu. The optional property 'Submeno' will be ignored for this set.</desc>
</info>
</set>
</group>
</component>
</oor:component-schema>
Merge Menu Bar
The extended Addons.xcs now has a new set, called OfficeMenuBarMerging, where add-ons can add there instructions on how their commands should be merged into the Office menubar. The set has entries of the type MergeMenuItems which is a set of MergeMenuInstruction for every add-on. The merge menu instruction group uses the following properties:
Name | Description | Type |
---|---|---|
MergePoint | Describes the path to the target menu item. It can look like: .uno:ToolsMenu\.uno:AVMediaPlayer using '\' as a separator. | String |
MergeCommand | Describes the command which should be processed. I can think of the following commands (AddBefore/AddAfter/Replace/Remove). As MergeCommand is a string we can extend it to support new commands without becoming incompatible. | String |
MergeCommandParameter | Optional parameters for a merge command. Interpretation depends on the individual command. | String |
MergeFallback | Describes how the implementation should react, if the path doesn't exist. I can think of the commands (Ignore, AddPath). This property is also a string and therefore provides the same advantage as MergeCommand. MergeFallback is always interpreted in conjunction with MergeCommand. An empty string always means "Ignore" | String |
MergeContext | Defines in which application module context the merge instruction should be active. Contexts must be separated by a comma. An empty context means that the instruction is always active. The context string is identical with the module identifier accessible from the com.sun.star.frame.ModuleManager service. The following module identifiers are defined (for a complete list refer to Office modules since OpenOffice.org 2.3):
|
String |
MenuItems | Describes the menu items (with sub menus) which should be added at the merge point. | Set |
The following matrix describes the association between MergeCommand and MergeFallback.
MergeCommand/MergeFallback | Ignore | AddPath |
---|---|---|
AddBefore | Y | Y |
AddAfter | Y | Y |
Replace | Y | N |
Remove | Y | N |
The next table describe the use of the MergeCommandParameter which provides additional information for the processing of a command.
MergeCommand | MergeCommandParameter | Type |
---|---|---|
AddBefore | - | - |
AddAfter | - | - |
Replace | - | - |
Remove | Number of items | String (must contain a number) |
The menu items can use all present features within the Addon.xcs, like using associated images.
As we also want to support commands which remove/replace commands, the order of MergeMenuInstruction is important. It could be that a command references a path which has been removed by a previously processed instruction. Therefore, the developer can use the node name to have a predefined order. The MergeMenuInstruction property set also supports a fall back property, which can be used to give orders how this situation should be resolved. It should be clear that there is a minimal risk, that the instruction of more than one add-on can conflict and produce undefined changes in the menu bar.
Merge Toolbar
The extended Addons.xcs now has a new set called „OfficeToolbarMerging“ where add-ons can add there instructions how their commands should be merged into the Office toolbars. The set has entries of the type MergeToolBarItems which is a set of MergeToolBarInstruction for every add-on. The merge toolbar instruction group uses the following properties:
Name | Description | Type |
---|---|---|
MergeToolBar | Specifies the target toolbar. You have to use the name part of the toolbar resource URL. E.g. private:resource/toolbar/standardbar | String |
MergePoint | Describes the target toolbar item. It can look like: uno:AVMediaPlayer | String |
MergeCommand | Describes the command which should be processed. Currently the commands (AddBefore/AddAfter/Replace/Remove) are defined. As MergeCommand is a string we can extend it to support new command without becoming incompatible. | String |
MergeCommandParameter | Optional parameters for a merge command. Interpretation depends on the individual command. | String |
MergeFallback | Describes how the implementation should react if the MergePoint doesn't exist. The following commands are defined: Ignore, AddFirst and AddLast. This property is also a string and therefore provides the same advantage as MergeCommand. MergeFallback is always interpreted in conjunction with MergeCommand. An empty string always means "Ignore" | String |
MergeContext | Defines in which application module context the merge instruction should be active. Contexts must be separated by a comma. An empty context means that the instruction is always active. The context string is identical with the module identifier accessible from the com.sun.star.frame.ModuleManager service. The following module identifiers are defined (for a complete list refer to Office modules since OpenOffice.org 2.3):
|
String |
ToolBarItems | Describes the toolbar items which should be merged at the merge point. | Set |
The following matrix describes the association between MergeCommand and MergeFallback.
MergeCommand/MergeFallback | Ignore | AddFirst | AddLast |
---|---|---|---|
AddBefore | Y | Y | Y |
AddAfter | Y | Y | Y |
Replace | Y | N | N |
Remove | Y | N | N |
The next table describes the use of the MergeCommandParameter which provides additional information for the processing of a command.
MergeCommand | MergeCommandParameter | Type |
---|---|---|
AddBefore | - | - |
AddAfter | - | - |
Replace | - | - |
Remove | Number of items | String (must contain a number) |
The toolbar items can use all present features within the Addon.xcs, like associated images.
As we also want to support commands which remove/replace commands the order of MergeToolBarInstruction is important. It could be that a command references a path which has been removed by a previously processed instruction. Therefore the developer can use the node name to have a predefined order. The MergeToolBarInstruction property set also supports a fall back property, which can be used to give orders how this situation should be resolved. It should be clear that there is a minimal risk, that the instruction of more than one add-on can conflict and produce undefined changes on a toolbar.
Drawbacks
As the solution is very flexible it needs some amount of time to interpret the provided information. Therefore it's safe to assume that the startup performance can be noticeable decreased using this feature extensively. There also could be a non-deterministic behavior of more than one add-on, if they contain destructive instructions (remove or replace). The order of installation could result in a different behavior.
Final conclusion
The new enhancement makes add-on development much easier, if an add-on needs to integrate its functions to an arbitrary position in the OpenOffice.org menubar or any toolbar. It has a descriptive fall back solution, which should help to overcome merge problems (especially for the hierarchical menu bar). From my point of view the positive reasons clearly compensate the possible drawbacks and therefore this extension will help developers to write better extensions.
Examples
This chapter wants to describe some use cases and the corresponding Addons.xcu. It should help developers who want to start immediately using an existing configuration file.
Example 1
- A new top-level menu entry with two menu items is added after the menu.
<?xml version='1.0' encoding='UTF-8'?>
<oor:component-data
oor:name="Addons"
oor:package="org.openoffice.Office"
xmlns:install="http://openoffice.org/2004/installation"
xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<node oor:name="AddonUI">
<node oor:name="OfficeMenuBarMerging">
<node oor:name="org.openoffice.test.testcomponent" oor:op="replace">
<node oor:name="S1" oor:op="replace">
<prop oor:name="MergePoint">
<value>.uno:ToolsMenu</value>
</prop>
<prop oor:name="MergeCommand">
<value>AddAfter</value>
</prop>
<prop oor:name="MergeFallback">
<value>AddPath</value>
</prop>
<node oor:name="MenuItems">
<node oor:name="M1" oor:op="replace">
<prop oor:name="Title">
<value xml:lang="en-US">~Test</value>
</prop>
<node oor:name="Submenu">
<node oor:name="M1" oor:op="replace">
<prop oor:name="Title">
<value xml:lang="en-US">~Close</value>
</prop>
<prop oor:name="URL">
<value>.uno:CloseDoc</value>
</prop>
</node>
<node oor:name="M2" oor:op="replace">
<prop oor:name="Title">
<value xml:lang="en-US">Help</value>
</prop>
<prop oor:name="URL">
<value>.uno:HelpIndex</value>
</prop>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</oor:component-data>
Example 2
Adds a new toolbar button to the standard toolbar.
<?xml version='1.0' encoding='UTF-8'?>
<oor:component-data
xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
oor:name="Addons"
oor:package="org.openoffice.Office">
<node oor:name="AddonUI">
<node oor:name="OfficeToolbarMerging">
<node oor:name="org.openoffice.test.testcomponent" oor:op="replace">
<node oor:name="T1" oor:op="replace">
<prop oor:name="MergeToolBar">
<value>standardbar</value>
</prop>
<prop oor:name="MergePoint">
<value>.uno:Open</value>
</prop>
<prop oor:name="MergeCommand">
<value>AddAfter</value>
</prop>
<prop oor:name="MergeFallback">
<value>AddLast</value>
</prop>
<prop oor:name="MergeContext">
<value/>
</prop>
<node oor:name="ToolBarItems">
<node oor:name="B1" oor:op="replace">
<prop oor:name="URL">
<value>.uno:CloseDoc</value>
</prop>
<prop oor:name="Title">
<value>Close Document</value>
</prop>
</node>
</node>
</node>
</node>
</node>
</node>
</oor:component-data>