2019-03-17

12: Execute UNO Dispatch Command and Get All Information in Java

<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: The Java programming language

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 Java.
Stage Direction
Here are Hypothesizer 7, Objector 12A, and Objector 12B 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 Java.

Objector 12A
I don't understand what "execute any UNO dispatch command ~ , in Java" means. . . . Do you mean that I can write some Java code in a LibreOffice macro?

Hypothesizer 7
Sir, no, I do not mean that. You can create an external console Java UNO client, an external GUI Java UNO client, or a LibreOffice extension that contains some Java code, and such an artifact can execute the UNO dispatch command.

Objector 12A
I don't understand well . . .

Hypothesizer 7
You may not understand it unless you understand what UNO is and how it is related to LibreOffice.

Objector 12A
I just want to execute some UNO dispatch commands from my macro . . .

Hypothesizer 7
As your UNO components in your LibreOffice extension can be used in your macro, being able to execute any UNO dispatch command in the UNO components means being able to execute any UNO dispatch command in your macro.

Objector 12A
Oh, . . . but creating what you call "LibreOffice extension" (whatever that is) is just a nuisance . . .

Hypothesizer 7
It is not particularly a nuisance once you have an environment to create your LibreOffice extension (how to do so is here for Linux and here for Windows) and you understand how to create it (how to do so is here). The reason why creating a LibreOffice extension is advantageous is that it frees you from the pains of doing things in a not-well-documented macro language and from the limitations of the macro language. . . . If you can command Java all right, it will be a profitable deal, I think.

Objector 12A
. . . Certainly, I can command Java all right . . .

Hypothesizer 7
Congratulations! You will be able to incorporate whatever Java allows you into your UNO extension, once you build the development environment and learn how to create your UNO extensions.

Objector 12A
. . . Doing such preliminaries is a pain in the ass . . .

Hypothesizer 7
You have a sensitive ass . . .. Although there are some people who shun some things just because those things require some preliminaries, taking little pains (if they are really pains) of doing the preliminaries, first, will save them greater pains and give them free hands, afterward.

Objector 12A
My ass is my concern!

Hypothesizer 7
Certainly.

Objector 12B
Your "the related information" is quite vague; what, the hell, is it, exactly?

Hypothesizer 7
Madam, it is something called "status changes information", and I, too, used to call it so, but now, I call it 'related information', because "status changes information" is a misnomer in my opinion.

Objector 12B
Being told "something called "status changes information"", I have never heard of such a term . . .

Hypothesizer 7
For example, there is a Calc UNO dispatch command, '.uno:GoToCell', which offers the related information that is the position of the previous current cell and the position of the new current cell.

Objector 12B
So?

Hypothesizer 7
Such information seems to be called "status changes information" because it is supposed to be used for changing the status of a GUI element, but how the information is used is entirely up to you, the programmer: someone's dictating how you use the information is utterly gratuitous.

Objector 12B
Doesn't "status changes information" mean that the status of the current cell has changed, not that I have to use the information in order to change the status of a GUI element?

Hypothesizer 7
No, it does not seem to mean that. A proof is that, for example, a Calc UNO dispatch command, '.uno:FontNameList', offers the related information that is the list of the recognized font names, which is not any change of any status in that meaning.

Objector 12B
Well, if no font is added or removed, certainly, the list doesn't represent any change of any status.

Hypothesizer 7
As each UNO dispatch command offers its related information or no such information at its own discretion, the comprehensive term, 'related information', is the best I have come up with.

Objector 12A
What if I say that I'm not interested in such 'related information'?

Hypothesizer 7
Then, you can use an easier way of executing the UNO dispatch command. However, as some commands offer some useful information as the related information, the knowledge on how to get the related information may be valuable.


Main Body


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


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 are an article on how to do it for any external console Java program, an article on how to do it for any external GUI Java program, and an article (an old article of an old series, which is being replaced by this series) on how to do it for any LibreOffice or Apache OpenOffice extension that contains some Java code).

Objector 12A
Being told "It is presupposed" . . .

Hypothesizer 7
Sir, please understand that I cannot repeat the same explanation again and again.

Objector 12A
. . .

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

Objector 12A
"the document UNO object"? Which "document UNO object"?

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

Objector 12A
Um?

Hypothesizer 7
As the UNO dispatch command is executed on a frame, the document that is contained in the frame is the document.

If the UNO dispatch command is not about any document, the UNO desktop should be the frame to be gotten.

Objector 12A
So, in that case, I don't need to do this step?

Hypothesizer 7
Well, you can tweak the first execution line of this step 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.

Objector 12A
Anyway, how can I 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 12A
If not?

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.

@Java Source Code
import com.sun.star.frame.XDesktop2;
import com.sun.star.frame.XModel;
import com.sun.star.uno.UnoRuntime;
import theBiasPlanet.unoUtilities.stringsHandling.UnoExtendedStringHandler;

				XDesktop2 l_unoDesktopInXDesktop2 = UnoRuntime.queryInterface (XDesktop2.class, l_unoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.frame.Desktop", l_unoObjectsContext));
				XModel l_unoDocumentInXModel = UnoRuntime.queryInterface (XModel.class, l_unoDesktopInXDesktop2.getCurrentComponent ());

Objector 12A
Hmm.

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

@Java Source Code
import com.sun.star.frame.XController;
import com.sun.star.frame.XDispatchProvider;

				XController l_controllerInXController = UnoRuntime.queryInterface (XController.class, l_unoDocumentInXModel.getCurrentController ());
				XDispatchProvider l_frameInXDispatchProvider = UnoRuntime.queryInterface (XDispatchProvider.class, l_controllerInXController.getFrame ());

Objector 12A
Well, . . . whatever. And then?

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

@Java Source Code
import com.sun.star.frame.XDispatchHelper;

				XDispatchHelper l_dispatchHelperInXDispatchHelper = UnoRuntime.queryInterface (XDispatchHelper.class, l_unoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.frame.DispatchHelper", l_unoObjectsContext));

Objector 12A
"UNO dispatch helper" is a . . . helper, isn't it?

Hypothesizer 7
Certainly, it is a helper that makes 'UNO dispatching' easy.

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

@Java Source Code
import com.sun.star.beans.PropertyValue;

				PropertyValue [] l_dispatchArgumentPropertiesArray = new PropertyValue [1];
				l_dispatchArgumentPropertiesArray [0] = new PropertyValue ();
				l_dispatchArgumentPropertiesArray [0].Name = "ToPoint";
				l_dispatchArgumentPropertiesArray [0].Value = "$B$2";
				Object l_commandResult = l_dispatchHelperInXDispatchHelper.executeDispatch (l_frameInXDispatchProvider, ".uno:GoToCell", "_self", -1, l_dispatchArgumentPropertiesArray);

Objector 12A
What are those "_self" and "-1"?

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

Objector 12A
What does "_self" exactly mean?

Hypothesizer 7
That is a special frame name that means the concerned frame itself, which is 'l_frameInXDispatchProvider' in this case.

Objector 12A
Then, what does "-1" exactly mean?

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

Objector 12A
Are there other options than '_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.

Objector 12A
. . .

Hypothesizer 7
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 12A
Ah, so, the top frame has the parent, which is the desktop frame . . .

Hypothesizer 7
Yes.

Objector 12A
I don't understand what the hierarchy of the Calc document is exactly like.

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

Objector 12A
So, specifying '_top' instead of '_self' doesn't make any difference?

Hypothesizer 7
That does not.

Objector 12A
I can use also non-special frame names, can't I?

Hypothesizer 7
Yes, you can, but . . .

Objector 12A
but I don't know any name.

Hypothesizer 7
In fact, any frame's name is blank unless you give it a name.

Objector 12A
I see . . .

What can I get as the result information of the command execution?

Hypothesizer 7
That 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 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.

@Java Source Code
import com.sun.star.frame.XDispatchResultListener;
import com.sun.star.frame.XStatusListener;
import com.sun.star.lang.EventObject;
import com.sun.star.frame.DispatchResultEvent;
import com.sun.star.frame.FeatureStateEvent;

	static class ResultInformationListener implements XDispatchResultListener {
		public ResultInformationListener () {
		}
		
		@Override
		public void dispatchFinished (DispatchResultEvent a_dispatchResultEvent) {
			System.out.println ("### The dispatch execution is finished.");
		}
		
		@Override
		public void disposing (com.sun.star.lang.EventObject a_source) {
		}
	}
	
	static class RelatedInformationListener implements XStatusListener {
		public RelatedInformationListener () {
		}
		
		@Override
		public void statusChanged (FeatureStateEvent a_featureStateEvent) {
			System.out.println ("### A dispatch execution related information piece is offered.");
		}
		
		@Override
		public void disposing (com.sun.star.lang.EventObject a_source) {
		}
	}
	
				ResultInformationListener l_resultInformationListener = new ResultInformationListener ();
				RelatedInformationListener l_relatedInformationListener = new RelatedInformationListener ();

Objector 12B
What are those argument types of the methods?

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

Objector 12B
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.

@Java Source Code
import com.sun.star.util.XURLTransformer;

				com.sun.star.util.URL [] l_urlInURLs = new com.sun.star.util.URL [1];
				l_urlInURLs [0] = new com.sun.star.util.URL ();
				l_urlInURLs [0].Complete = ".uno:GoToCell";
				XURLTransformer l_urlTransformerInXURLTransformer = UnoRuntime.queryInterface (XURLTransformer.class, l_unoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.util.URLTransformer", l_unoObjectsContext));
				l_urlTransformerInXURLTransformer.parseStrict (l_urlInURLs);

Objector 12B
It is tiresome just in order to prepare the URL . . .

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

@Java Source Code
import com.sun.star.frame.XNotifyingDispatch;

				XNotifyingDispatch l_dispatcherInXNotifyingDispatch = UnoRuntime.queryInterface (XNotifyingDispatch.class, l_frameInXDispatchProvider.queryDispatch (l_urlInURLs [0], "_self", (short) -1));

Objector 12B
It seems that I get a different dispatcher for a different URL.

Hypothesizer 7
That is a possibility; the dispatchers provider decides what is the dispatcher for the specified URL.

Objector 12B
Do those "_self" and "-1" mean the same things as in the previous section?

Hypothesizer 7
Yes, they do.

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

@Java Source Code
import com.sun.star.beans.PropertyValue;

				l_dispatcherInXNotifyingDispatch.addStatusListener (l_relatedInformationListener, l_urlInURLs [0]);
				PropertyValue [] l_dispatchArgumentPropertiesArray = new PropertyValue [2];
				l_dispatchArgumentPropertiesArray [0] = new PropertyValue ();
				l_dispatchArgumentPropertiesArray [0].Name = "SynchronMode";
				l_dispatchArgumentPropertiesArray [0].Value = Boolean.valueOf (true);
				l_dispatchArgumentPropertiesArray [1] = new PropertyValue ();
				l_dispatchArgumentPropertiesArray [1].Name = "ToPoint";
				l_dispatchArgumentPropertiesArray [1].Value = "$B$2";
				l_dispatcherInXNotifyingDispatch.dispatchWithNotification (l_urlInURLs [0], l_dispatchArgumentPropertiesArray, l_resultInformationListener);
				l_dispatcherInXNotifyingDispatch.removeStatusListener (l_relatedInformationListener, l_urlInURLs [0]);

Objector 12B
Does the 'dispatchWithNotification' wait until the command execution has finished?

Hypothesizer 7
Yes, it does because the synchronous mode is explicitly set by the 'SynchronMode' argument.

Objector 12B
Hmm . . .

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 Java UNO client, a GUI Java 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 12B
I don't understand what 'UnoDispatchSlotsConstantsGroup.BaseDispatchSlot a_dispatchSlot' as the first argument of the 'dispatch' method is . . .

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' interface 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 Java.

Of course, we can execute any UNO dispatch command also in other programming languages (C++, Microsoft .NET Framework (C# and Visual Basic.NET), Python, LibreOffice Basic or Apache OpenOffice Basic, BeanShell, and JavaScript), and we will learn how to do so in them in future articles (for C++, 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>