Create TextViewCursor without Human Interaction

Create TextViewCursor without Human Interaction

I’m on Fedora 27 with XFCE, trying to run JUnit tests in Eclipse on Java code for a Writer extension. The tests ran fine in LibreOffice 5.2 with LO SDK version 5.2, but not in LO 5.4 with LO SDK 5.4.

After much poking at my code and eliminating the impossible, I found that the code for obtaining the TextViewCursor returns null unless and until Writer receives input focus.

So, if I put a command such as Thread.sleep(5000) into the test code after the code starts Writer and then click in the Writer window during the sleep so it has focus, the test runs fine.

This is obviously just a wee bit less than ideal.

I’ve already considered automating a click in the Writer window from outside the program, but I was hoping to avoid such a kludge.

Has anyone had any experience with this issue? Maybe even have a programmatic workaround?

Does the problem occur when you run an ordinary Java program from Eclipse, rather than a JUnit test?

It may help to post a short example of how the view cursor is created from the test. Perhaps something like document = loadComponentFromUrl(...); viewcursor = document .getCurrentController().getViewCursor();.

Or does it do desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop"); document = desktop.getCurrentComponent(); instead?

I once successfully ran similar tests on Fedora using PyUnit, although that was before LO 5.4, so perhaps my tests do not work on the new version.

One more question: Does the code successfully get the controller? That is, does document.getCurrentController(); return null.

Hi @jimk,

The next two comments show my code for getting the ViewCursor. After some checking in the debugger, it turns out I’m getting a null from xDesktop.getCurrentComponent. :frowning:

The problem does also occur when running a normal Java program from Eclipse.

// First part…

XComponentContext xContext = com.sun.star.comp.helper.Bootstrap.bootstrap();

XMultiComponentFactory mcFactory = xContext.getServiceManager();

Object oDesktop = mcFactory.createInstanceWithContext("com.sun.star.frame.Desktop", xContext);

XDesktop xDesktop = UnoRuntime.queryInterface(XDesktop.class, oDesktop);

com.sun.star.lang.XComponent xCurrentComponent = xDesktop.getCurrentComponent();

// Second part…

XModel xModel = UnoRuntime.queryInterface(XModel.class,xCurrentComponent);

com.sun.star.frame.XController xController = xModel.getCurrentController();

XTextViewCursorSupplier xViewCursorSupplier = UnoRuntime.queryInterface(XTextViewCursorSupplier.class, xController);

xViewCursor = xViewCursorSupplier.getViewCursor();

My PyUnit code never calls xDesktop.getCurrentComponent(), and I am not surprised to hear that it fails under some circumstances. Instead, do it this way.

desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx);
document = desktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, ());
controller = document.getCurrentController();
viewcursor = controller.getViewCursor();

Before this, my code also does:

oComponents = desktop.getComponents()
oDocs = oComponents.createEnumeration()
while oDocs.hasMoreElements():
    document = oDocs.nextElement()
    document.close(True)

Close enough! Thanks!
Here’s my Java, derived from your Python…

... // code to get oDesktop
XComponentLoader xCLoader = UnoRuntime.queryInterface(XComponentLoader.class,oDesktop);
PropertyValue [] szEmptyArgs = new PropertyValue [0];
XComponent xComp = xCLoader.loadComponentFromURL("private:factory/swriter", "_blank", 0, szEmptyArgs);
XModel xModel = UnoRuntime.queryInterface(XModel.class,xComp);
... // code to get xController, xViewCursorSupplier, & xViewCursor

Hello @techsquirrel,

The ViewCursor only works if the window has the focus.

There is no need to generate a click, you could just set the window focus like so:

ThisComponent.CurrentController.Frame.ComponentWindow.setFocus()

For unfocused cursor movements, you might use a TextCursor instead:

oTextCursor = oViewCursor.Text.createTextCursor()

HTH, lib

Hi @librebel,

Unfortunately, the setFocus() line wouldn’t work directly for me, as “ThisComponent” is a BASIC object; it doesn’t exist in the Java API. However, I did follow up on your suggestion by looking at the Java equivalent.

Hi @librebel,

Unfortunately, the setFocus() line wouldn’t work directly for me, as “ThisComponent” is a BASIC object; it doesn’t exist in the Java API. However, I did follow up on your suggestion by looking at the Java equivalent.

As I understand it, “ThisComponent” is identical to the current component that can also be accessed through “StarDesktop.CurrentComponent” (OOo Dev Guide, p.1154), and this would be analogous to the Java interface’s XDesktop.getCurrentComponent. I was already using that in my code leading up to getting the CurrentController and, subsequently, the ViewCursor. Checking a couple of values in the debugger, I’m getting a null from XDesktop.getCurrentComponent. :frowning:

With regard to use of TextCursor, that’s not really an option. The code I’m testing normally works on the user’s selection through the GUI, which it obtains through the ViewCursor, so ignoring the ViewCursor would amount to an invalid test of the code.