2019-07-28

21: Execute UNO Dispatch Command and Get All Information in C++

<The previous article in this series | The table of contents of this series | The next article in this series>

Your lazy way may be missing some useful information that is available from the execution.

Topics


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: C++

The table of contents of this article


Starting Context



Target Context


  • The reader will know how to execute any UNO dispatch command and get the result information and the related information in C++.
Stage Direction
Here are Hypothesizer 7, Objector 21A, and Objector 21B in front of a computer.


Orientation


Hypothesizer 7
In this article, we will know how to execute any UNO dispatch command and get the result information and the related information, in C++.

Objector 21A
"in C++"? I thought, I can write any macro only in Basic, Python, BeanShell, or JavaScript.

Hypothesizer 7
Sir, you are right about writing any macro, but I am talking about creating any external console C++ UNO client, any external GUI C++ UNO client, or any LibreOffice or Apache OpenOffice extension that contains some C++ code.

Objector 21A
So, that doesn't concern me, who wants to write a macro.

Hypothesizer 7
You can implement your functionality in your C++ UNO components in your LibreOffice or Apache OpenOffice extension and make your tiny macro just a invoker of those UNO components.

Objector 21A
Why would I do such a thing?

Hypothesizer 7
Because each of most macro languages, especially Basic, has its critical limitations. Basic also has the defect of having no satisfactory documentation. Once you know how to create your UNO components in Java or C++, you will be able to do whatever Java or C++ allows you to do.

Objector 21A
I know that Basic sucks; so I use Python.

Hypothesizer 7
Ah, that seems better: Python is an object-oriented programming language and has some good features, although it is a shame that Python is dynamically-typed. I do not admit that being dynamically-typed is a good thing, but admit that a programming language can be rather good in spite of being dynamically-typed, not because of.

Objector 21A
. . . Do you know that some recent versions of Python allow static types checking?

Hypothesizer 7
Really?

Objector 21A
Although it isn't a built-in feature (accepting type annotations is a built-in feature), but there are some tools that do static types checking.

Hypothesizer 7
That sounds quite promising. Certainly, Python with static types checking will be great.

Objector 21A
So?

Hypothesizer 7
I will write a Python version of this article, but that does not mean this C++ version should not exist, does it?

Objector 21A
I guess not: I am also a C++ programmer, actually. Certainly, C++ has its own advantages, for example, the speed.

Objector 21B
I don't understand what "the related information" is. How is it different from "the result information"?

Hypothesizer 7
Madam, it is not useful to try to make any clear-cut distinction between them; each UNO dispatch command rather arbitrarily provides some pieces of its execution information in the result information and the other pieces in the related information.

'related information' seems to be officially called "status changes information", but I have to conclude that that is a misnomer: in many cases, "status changes information" has nothing to do with any change of any status of anything.

Objector 21B
. . .

Hypothesizer 7
What I can say is that it is good to know how to get the whole of the available information, because some useful information sometimes appears in the result information and in the other times in the related information, depending on the UNO dispatch command.


Main Body


1: An Easy Way to Execute Any UNO Dispatch Command Without Getting the Related Information


Hypothesizer 7
First, let us know a way to execute any UNO dispatch command without getting the related information.

Objector 21A
. . . I don't need to know such a way, do I? If I know a way to execute any UNO dispatch command with getting the whole available information, that will be enough, won't it?

Hypothesizer 7
Certainly. I just thought that some people who did not want any related information at all might want to know an easier way.

Well, a way to execute any UNO dispatch command with getting the whole available information will be introduced in the next section, but as the next section will be written based on this section, you are supposed to read this section (at least most of it), anyway.

Objector 21A
That's a shame . . .

Hypothesizer 7
It is presupposed that the reader has knowledge on how to get a UNO objects context to any LibreOffice or Apache OpenOffice instance (there is an article on how to do it for any external console C++ program; an article on how to do it for any external GUI C++ program and an article on how to do it for any LibreOffice or Apache OpenOffice extension that contains some C++ code will come later).

Objector 21A
I seem to be supposed variously . . .

Hypothesizer 7
First, we have to get a '::com::sun::star::frame::XModel' UNO proxy of the document UNO object.

Objector 21A
. . . What "document" do you mean?

Hypothesizer 7
The document on that you want to execute the UNO dispatch command.

Objector 21A
The UNO dispatch command may not be about any specific document, may it?

Hypothesizer 7
Ah, certainly. In that case, we can use the UNO desktop frame directly.

Objector 21A
Huh?

Hypothesizer 7
Any UNO dispatch command is executed on a frame, and we are talking about how we can get the frame. If the UNO dispatch command is not about any specific document, the frame to be gotten should be the UNO desktop.

Objector 21A
Ah, so "the UNO desktop" is a frame.

Hypothesizer 7
Yes. You can tweak the first execution line of the following code so that it gets a '::com::sun::star::frame::XDispatchProvider' UNO proxy, instead of the '::com::sun::star::frame::XDesktop2' UNO proxy. Then, you already have the UNO dispatchers provider you need.

On the other hand, when the UNO dispatch command is executed on a document, we get the frame that contains the document.

Objector 21A
Then, let's get the document UNO object!

Hypothesizer 7
If you have opened the document in your program, you should have been able to get the document UNO object when the document is opened.

Objector 21A
It's a shame that I haven't.

Hypothesizer 7
Then, there are some ways to get the UNO object of a specific document, but I will not delve into all of them here (I will do so in a future article).

Instead, I will introduce a way: getting the UNO object of the current document. Let us see this code, where 'l_objectsContext' is the UNO objects context and 'l_unoDocumentInXModel' is the '::com::sun::star::frame::XModel' UNO proxy of the document UNO object.

@C++ Source Code
#include <com/sun/star/frame/XDesktop2.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/uno/Reference.hxx>
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"

using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::uno;
using namespace ::theBiasPlanet::unoUtilities::stringsHandling;

						Reference <XDesktop2> l_unoDesktopInXDesktop2 (l_unoObjectsContext->getServiceManager ()->createInstanceWithContext (UnoExtendedStringHandler::getOustring ("com.sun.star.frame.Desktop"), l_unoObjectsContext), UNO_QUERY);
						Reference <XModel> l_unoDocumentInXModel (l_unoDesktopInXDesktop2->getCurrentComponent (), UNO_QUERY);

Objector 21A
. . . What is that 'UnoExtendedStringHandler::getOustring'?

Hypothesizer 7
It is my utility class method that creates a UNO C++ string instance from the specified UTF-8 '::std::string' instance (the class is in the 'unoUtilitiesToBeDisclosed' project, which is included in the ZIP file of any of my UNO samples, for example a files converter).

Objector 21A
Why is such a utility class necessary?

Hypothesizer 7
Because 'UNO C++ string' is not any characters array or standard string, but a UNO-specific class, and creating any UNO C++ string instance is not so simple: we have to pass a UTF-16 characters array into one of the constructors.

Objector 21A
Well . . .

Hypothesizer 7
Then, we get a '::com::sun::star::frame::XDispatchProvider' UNO proxy of the frame UNO object, like this.

@C++ Source Code
#include <com/sun/star/frame/XController.hpp>
#include <com/sun/star/frame/XDispatchProvider.hpp>

						Reference <XController> l_controllerInXController (l_unoDocumentInXModel->getCurrentController (), UNO_QUERY);
						Reference <XDispatchProvider> l_frameInXDispatchProvider (l_controllerInXController->getFrame (), UNO_QUERY);

Objector 21A
I see.

Hypothesizer 7
Then, we get a '::com::sun::star::frame::XDispatchHelper' UNO proxy of a UNO dispatch helper UNO object, like this.

@C++ Source Code
#include <com/sun/star/frame/XDispatchHelper.hpp>

						Reference <XDispatchHelper> l_dispatchHelperInXDispatchHelper (l_unoObjectsContext->getServiceManager ()->createInstanceWithContext (UnoExtendedStringHandler::getOustring ("com.sun.star.frame.DispatchHelper"), l_unoObjectsContext), UNO_QUERY);

Objector 21A
Ah-ha.

Hypothesizer 7
Finally, we execute the UNO dispatch command, specifying the command URL and the command arguments, like this.

@C++ Source Code
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Sequence.hxx>

using namespace ::com::sun::star::beans;

						Sequence <PropertyValue> l_dispatchArgumentPropertiesSequence (1);
						l_dispatchArgumentPropertiesSequence [0].Name = UnoExtendedStringHandler::getOustring ("ToPoint");
						l_dispatchArgumentPropertiesSequence [0].Value = Any (UnoExtendedStringHandler::getOustring ("$B$2"));
						Any l_commandResult = l_dispatchHelperInXDispatchHelper->executeDispatch (l_frameInXDispatchProvider, UnoExtendedStringHandler::getOustring (".uno:GoToCell"), UnoExtendedStringHandler::getOustring ("_self"), -1, l_dispatchArgumentPropertiesSequence);

Objector 21A
"_self"? "-1"?

Hypothesizer 7
They are the target frame name of the command and the search flag for finding the frame.

Objector 21A
"_self" doesn't seem to be any meaningful name: every frame calling itself "_self" doesn't distinguish any frame . . .

Hypothesizer 7
That is a special frame name that means the concerned frame itself, which is 'l_frameInXDispatchProvider' in this case. That is meaningful because the origin of being 'self' is specified.

Objector 21A
What does "-1" mean?

Hypothesizer 7
Actually, that means nothing as the argument is ignored when any special frame name is specified in the previous argument.

Objector 21A
What can I specify instead of '_self'?

Hypothesizer 7
While any frame belongs to a hierarchy of frames, '_parent' means the direct parent of the concerned frame, '_top' means the top frame of the hierarchy to which the concerned frame belongs, and '_blank' means a new top frame.

Note that any hierarchy is under the root frame (which is the desktop), and the top frame of the hierarchy is not the root frame, but the frame under the root frame.

Objector 21A
An odd terminology, I must say.

Anyway, what is the hierarchy of the Calc document like?

Hypothesizer 7
In fact, the frame we have gotten is the top frame, which has no child.

Objector 21A
So, I can specify '_top' instead of '_self' without making any difference?

Hypothesizer 7
Yes, you can.

Objector 21A
I can use also proper frame names, can't I?

Hypothesizer 7
Yes, you can, but any frame's proper name is blank unless you give it a name.

Objector 21A
That is so . . .

Hypothesizer 7
What the result information exactly is depends on the UNO dispatch command, but in many cases, the result information is not very useful.


2: The Way to Execute Any UNO Dispatch Command and Get the Result Information and the Related Information


Hypothesizer 7
In order to get the related information, we have to take the way discussed in this section.

As the result information and the related information are informed to a '::com::sun::star::frame::XDispatchResultListener' and a '::com::sun::star::frame::XStatusListener', respectively, we create a class that that implements '::com::sun::star::frame::XDispatchResultListener' and create one or more classes that implement '::com::sun::star::frame::XStatusListener', where a single class can implement both of the UNO interfaces.

For example, these are a '::com::sun::star::frame::XDispatchResultListener' implementation and a '::com::sun::star::frame::XStatusListener' implementation.

@C++ Source Code
#include <com/sun/star/frame/XDispatchResultListener.hpp>
#include <com/sun/star/frame/XStatusListener.hpp>
#include <com/sun/star/lang/EventObject.hpp>
#include <com/sun/star/frame/DispatchResultEvent.hpp>
#include <com/sun/star/frame/FeatureStateEvent.hpp>
#include <cppuhelper/compbase1.hxx>
#include <osl/mutex.hxx>

using namespace ::cppu;
using namespace ::osl;

			class ResultInformationListener : public WeakComponentImplHelper1 <XDispatchResultListener> {
				protected:
					Mutex i_mutex;
				public:
					ResultInformationListener ();
					virtual ~ResultInformationListener ();
					virtual void SAL_CALL dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent) override;
					virtual void SAL_CALL disposing (::com::sun::star::lang::EventObject const & a_source) override;
			};
			
			ResultInformationListener::ResultInformationListener () : WeakComponentImplHelper1 (i_mutex) {
			}
			
			ResultInformationListener::~ResultInformationListener () {
			}
			
			void ResultInformationListener::dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent) {
				cout << "### The dispatch execution is finished." << endl << flush;
			}
			
			void ResultInformationListener::disposing (::com::sun::star::lang::EventObject const & a_source) {
			}
			
			class RelatedInformationListener : public WeakComponentImplHelper1 <XStatusListener> {
				protected:
					Mutex i_mutex;
				public:
					RelatedInformationListener ();
					virtual ~RelatedInformationListener ();
					virtual void SAL_CALL statusChanged (FeatureStateEvent const & a_featureStateEvent) override;
					virtual void SAL_CALL disposing (::com::sun::star::lang::EventObject const & a_source) override;
			};
			
			RelatedInformationListener::RelatedInformationListener () : WeakComponentImplHelper1 (i_mutex) {
			}
			
			RelatedInformationListener::~RelatedInformationListener () {
			}
			
			void RelatedInformationListener ::statusChanged (FeatureStateEvent const & a_featureStateEvent) {
				cout << "### A dispatch execution related information piece is offered." << endl << flush;
			}
			
			void RelatedInformationListener::disposing (::com::sun::star::lang::EventObject const & a_source) {
			}
			
						Reference <ResultInformationListener> l_resultInformationListener (new ResultInformationListener ());
						Reference <RelatedInformationListener> l_relatedInformationListener (new RelatedInformationListener ());

Objector 21B
"WeakComponentImplHelper1"? "Mutex"?

Hypothesizer 7
Ah, I will not delve into the usage of them, here, but such coding is necessary in order to make the class a UNO component.

Objector 21B
"DispatchResultEvent"? "EventObject"? "FeatureStateEvent"?

Hypothesizer 7
Please look them up in the UNO API document (here for '::com::sun::star::frame::DispatchResultEvent', here for '::com::sun::star::lang::EventObject', and here for '::com::sun::star::frame::FeatureStateEvent').

Objector 21B
Hmm . . .

Hypothesizer 7
We get a '::com::sun::star::frame::XDispatchProvider' UNO proxy of the frame UNO object, in the same way explained in the previous section.

Then, we set up a '::com::sun::star::util::URL' object (a non-UNO object) like this.

@C++ Source Code
#include <com/sun/star/util/URL.hpp>
#include <com/sun/star/util/XURLTransformer.hpp>

using namespace ::com::sun::star::util;

						::com::sun::star::util::URL l_urlInURL;
						l_urlInURL.Complete = UnoExtendedStringHandler::getOustring (".uno:GoToCell");
						Reference <XURLTransformer> l_urlTransformerInXURLTransformer (l_unoObjectsContext->getServiceManager ()->createInstanceWithContext (UnoExtendedStringHandler::getOustring ("com.sun.star.util.URLTransformer"), l_unoObjectsContext), UNO_QUERY);
						l_urlTransformerInXURLTransformer->parseStrict (l_urlInURL);

Objector 21B
. . . In the way of the last section, I just specified the URL string; now, why do I have to set up the '::com::sun::star::util::URL' object?

Hypothesizer 7
The helper has taken up the work of setting up the '::com::sun::star::util::URL' object as a duty as a helper, I guess. However, our setting up the '::com::sun::star::util::URL' object can be more efficient by maximally reusing the URL transformer UNO object and the '::com::sun::star::util::URL' object.

Objector 21B
Ah, that's possible.

Hypothesizer 7
Anyway, then, we get a '::com::sun::star::frame::XNotifyingDispatch' UNO proxy of the dispatcher UNO object like this.

@C++ Source Code
#include <com/sun/star/frame/XNotifyingDispatch.hpp>

						Reference <XNotifyingDispatch> l_dispatcherInXNotifyingDispatch (l_frameInXDispatchProvider->queryDispatch (l_urlInURL, UnoExtendedStringHandler::getOustring ("_self"), (short) -1), UNO_QUERY);

Objector 21B
Can't I reuse a dispatcher for some different URLs?

Hypothesizer 7
You could, but as we do not usually know what other URLs a specific dispatcher serves, we are useally obliged to query the dispatcher for each URL.

Objector 21B
"_self" and "-1" mean the same things as in the previous section, I presume?

Hypothesizer 7
Yes, they do.

Then, we register the related information listener(s) into the dispatcher, and finally, we ask the dispatcher to dispatch our command, like this.

@C++ Source Code
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Sequence.hxx>

using namespace ::com::sun::star::beans;

						l_dispatcherInXNotifyingDispatch->addStatusListener (l_relatedInformationListener, l_urlInURL);
						Sequence <PropertyValue> l_dispatchArgumentPropertiesSequence (2);
						l_dispatchArgumentPropertiesSequence [0].Name = UnoExtendedStringHandler::getOustring ("SynchronMode");
						l_dispatchArgumentPropertiesSequence [0].Value = Any (true);
						l_dispatchArgumentPropertiesSequence [1].Name = UnoExtendedStringHandler::getOustring ("ToPoint");
						l_dispatchArgumentPropertiesSequence [1].Value = Any (UnoExtendedStringHandler::getOustring ("$B$2"));
						l_dispatcherInXNotifyingDispatch->dispatchWithNotification (l_urlInURL, l_dispatchArgumentPropertiesSequence, l_resultInformationListener);
						l_dispatcherInXNotifyingDispatch->removeStatusListener (l_relatedInformationListener, l_urlInURL);

Objector 21B
'dispatchWithNotification' looks like asynchronous.

Hypothesizer 7
Basically yes. I have made it synchronous by specifying the 'SynchronMode' argument, though.

Objector 12B
Hmm . . ., certainly, I can't imagine when I want it to be asynchronous.

Hypothesizer 7
The 'statusChanged' method can be called multiple times (or may not be called at all), and the 'dispatchFinished' method is called finally once.

In my UNO utility project, 'unoUtilitiesToBeDisclosed', which is used by my samples (a console C++ UNO client, a files converter, etc.), the UNO document wrapper class, '::theBiasPlanet::unoUtilities::documentsHandling::UnoDocument', implements both of the listener interfaces and also has a method, 'dispatch', which executes any UNO dispatch command and returns the result information and the related information packed in the return value.

Objector 21B
. . . What is that 'UnoDispatchSlotsConstantsGroup::BaseDispatchSlot a_dispatchSlot' as the first argument of the 'dispatch' method?

Hypothesizer 7
That is an object that contains the URL and the argument names of the UNO dispatch command to be executed. In fact, the '::theBiasPlanet::unoUtilities::constantsGroups::UnoDispatchSlotsConstantsGroup' class holds such objects. I thought that putting such information in one place would be more favorable than scattering such information as string literals in programs.


3: The Conclusion and Beyond


Hypothesizer 7
Now, we know how to execute any UNO dispatch command and get the result information and the related information in C++.

Of course, we can execute any UNO dispatch command also in some other programming languages (Java, Microsoft .NET Framework (C# and Visual Basic.NET), Python, LibreOffice Basic or Apache OpenOffice Basic, BeanShell, and JavaScript); we have learned how to do so in Java in a previous article, and we will learn how to do so in some other languages in future articles (for C#, for Python, and for LibreOffice or Apache OpenOffice Basic).

There are an unfinished (so far) list of UNO dispatch commands for the LibreOffice foundations and the specifications of the listed commands and an unfinished (so far) list of UNO dispatch commands for LibreOffice Calc and the specifications of the listed commands.

Although executing some UNO dispatch commands is a way to handle any LibreOffice or Apache OpenOffice instance, it does not cover all of what we can do to handle the LibreOffice or Apache OpenOffice instance: we can do more by directly handling some UNO objects (please refer to the table of contents of this series).


References


<The previous article in this series | The table of contents of this series | The next article in this series>