What are UNO commands, and why would you need them? If you want to add some feature to the LibreOffice UI, you may need to add or modify a UNO command, so it would be help much to learn more about these commands, and in general, the dispatch framework. So, stay tuned!
UNO Dispatch Framework and UNO Commands
The UNO dispatch framework is an internal mechanism of LibreOffice to dispatch the commands from the UI to the actual code that handles it, and also send data back to the user interface. For example, a dispatch command updates the list of recent files in the menu after you save a file.
Let’s considering a single action like loading or saving a file. This action is available from several places in the UI, from the menu bar to the toolbar, and possibly other places.
The UNO dispatch command is a text in the form of .uno:About, and its name implies what it does. This specific command opens the “About LibreOffice” dialog. As another example, .uno:Quit, make LibreOffice application shut down. These commands do not take arguments, but there are other commands that take some argument, or return useful data.
This list is generated and updated regularly using the bin/list-dispatch-commands.py script inside LibreOffice core source, that scans the source code. This description is from bin/list-dispatch-commands.py‘s documentation:
3 types of source files are scanned to identify and describe a list of relevant UNO commands:
hxx files: containing the symbolic and numeric id’s, and the respective modes and groups
.xcu files: containing several English labels as they appear in menus or tool-tips
.sdi files: containing a list of potential arguments for the commands, and their types
Invoking UNO Commands
There are several ways to test a UNO command. One is to use internal Basic language. For example, using the command .uno:SheetRightToLeft with this BASIC code snippet, it is possible to reverse the the direction of an open Calc document.
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dim args(0) as new com.sun.star.beans.PropertyValue
args(0).Name = "RightToLeft"
args(0).Value = "true"
dispatcher.executeDispatch(document, ".uno:SheetRightToLeft", "", 0, args())
You can edit and run this script from the menu item “Tools > Macros > Edit Macros…”.
Creating a New UNO Command
Let’s consider a real world example. Recently, Rafael Lima raised the good point that we need a “duplicate sheet” option in the Calc. The idea was discussed in the UX/design meeting, and the decision was that this option would be good, and we need to introduce a .uno:DuplicateSheet command. In this way, one can invoke the command from the tab bar, or elsewhere.
The starting point for adding such a command was to take a look at the currently implemented commands. The .uno:Move is a command invoked from the tab bar, and has many similar properties.
More information about this command, and also other Calc commands is available here:
In fact, one can go on and start from copying parts of code for the move command, and then try to be specific on this command. As you may see, the ScViewFunc::MoveTable() is invoked in the switch case inside tabvwshf.cxx.
Also in sc/source/ui/view/tabcont.cxx, we add this part which is similar to previous definitions:
rBind.Invalidate( FID_TAB_DUPLICATE );
The main part of code is in sc/source/ui/view/tabvwshf.cxx, which is partly similar to the code that is done by the .uno:Move command:
// Get info about current document and selected tab
SCTAB nTab = rViewData.GetTabNo();
OUString aDocName = GetViewData().GetDocShell()->GetTitle();
sal_uInt16 nDoc = 0;
bool bCpy = true;
SfxObjectShell* pSh = SfxObjectShell::GetFirst();
ScDocShell* pScSh = nullptr;
sal_uInt16 i = 0;
// Determine the index of the current document
while ( pSh )
pScSh = dynamic_cast<ScDocShell*>( pSh );
if( pScSh )
if (aDocName == pScSh->GetTitle())
nDoc = i;
// Only count ScDocShell
pSh = SfxObjectShell::GetNext( *pSh );
MoveTable( nDoc, nTab + 1, bCpy );
Then, we add this part in the same .cxx file, which is similar to the parts from other commands:
if ( !rDoc.IsDocEditable()
|| rDoc.GetChangeTrack() != nullptr
|| nTabCount > MAXTAB)
rSet.DisableItem( nWhich );
This would complete the creation of the new command. The next step would be using this new command.
Editing Menus, Tabs and Other UI Elements
To be able to use the defined UNO command, you should also change the UI elements. This specific command is invoked from the menu bar and also tab bar, so just like the .uno:Move, .uno:Duplicate sheet should be added to the sc/uiconfig/scalc/menubar/menubar.xml (menu bar):
and also sc/uiconfig/scalc/popupmenu/sheettab.xml (tab bar):
The code is actually written by the LibreOffice community member Rafael Lima, and it is now merged in LibreOffice: