Using uno to connect to an ODT

LibreOffice on Raspberry Pi (Debian / buster).

Shortcut on desktop correctly opens Base form (ODT), ideal because this presents the end user with the minimal information necessary.

ODT form shows data in fields and has a search field and search button.

A separate python3 script (not a macro with LibreOffice) listens to incoming data from the network and the plan was for that script to send the data into the input field in the form and then push the search button (which does a RecFind) on the same form.

However, am I right in thinking that –

  1. This cant be made to work because uno cannot connect to an ODT and the whole LibreOffice suite has to be opened first?

  2. Uno requires LibreOffice to be running on a port as otherwise uno cannot connect.

  3. The only feasible way this may have worked is to have LibreOffice automatically open the most recent ‘file’ when LibreOffice starts.

However, the example macro provided here (Is it possible to automatically open most recent document on start? doesn’t work (nothing opens).

Is there any solution for this, I see only one python example which shows uno use (and the few C examples which exist only mention StarOffice)?

My knowledge of uno is mostly non-existent.

This is what I eventually ended up with, very messy / confusing (to me) but seems to work.

#Open socket to LibraOffice with delay to allow program to wait for connection
    os.popen('/usr/lib/libreoffice/program/soffice /home/pi/Desktop/Access --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"')

    time.sleep(8)  # Sleep for 5 seconds

# get the uno component context from the PyUNO runtime
localContext = uno.getComponentContext()

# create the UnoUrlResolver
resolver = localContext.ServiceManager.createInstanceWithContext(
     "com.sun.star.bridge.UnoUrlResolver", localContext)

# connect to the running office
global ctx
ctx = resolver.resolve(
     "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
smgr = ctx.ServiceManager

And then I attempted to ‘push’ the button on the form using python script to ‘simulate button press’ or to run the macro which the button would normally call, both attempts failed. I found this code but I suspect it is only for Windows.

def causeKeyPressedEventToBeFired(oEvent=None):
    oDoc = XSCRIPTCONTEXT.getDocument()
    oController = oDoc.getCurrentController()
    oForm = oDoc.getDrawPage().getForms().getByName("Form")
    oTextBox = oForm.getByName("Search")
    oControlView = oController.getControl(oTextBox)
    oControlView.setFocus()
    oEvent = uno.createUnoStruct("com.sun.star.awt.KeyEvent")
    oEvent.Source = oControlView
    from com.sun.star.awt.Key import A
    oEvent.KeyCode = A
    oEvent.KeyChar = "a"       # works in Python but strangely not in Basic
    simulate_KeyPress(oEvent)

def simulate_KeyPress(oKeyEvent):
    oDoc = XSCRIPTCONTEXT.getDocument()
    oWindow = oDoc.CurrentController.Frame.getContainerWindow()
    oKeyEvent.Source = oWindow      
    oToolkit = oWindow.getToolkit()
    oToolkit.keyPress(oKeyEvent)
    oToolkit.keyRelease(oKeyEvent)

Two steps forward, 10 back.

Thanks

Hello,

Don’t have specific answer for you. Not certain why LO is even involved. Using Python you can access a database directly. Send a query and get the result. No need for LO unless there is something you have not specified.

As for examples (and not saying they are relative to what you want) there are many posted which use Uno. Use of Uno in all languages is typical once you need to accomplish more complexity.

Thanks for the prompt reply. Has to be via the form (and not direct to the database) because the end user only sees the form, and the form should update automatically as data is coming in from the network, a matching record ‘automatically’ pops up. Have managed to open just the ODT by specifying it in the open LO commands in python but see no methods / uno help as to how to to ‘post’ data from python into the text box named ‘input’ or to action the search button (both on the opened form).

Hello,

If you have opened the form you should be able to connect/access the form and fields from Python.

You question actually cover a lot of ground so here are some links to hopefully give you some direction:

LibreOffice Python Scripts Help

Designing & Developing Python Applications

Base macro that opens a new/clean record in another form using python

And a Basic routine to simulate a key stroke (for use in executing the push button):

Libreoffice Base - how to call a control event from a macro?

There are samples (some in the links above) which show access to forms and fields within forms.

Edit:

Have used PyCharm in past for interaction. This site may help → LibreOffice(4) Move LibreOffice from PyCharm (Automation)

Although it’s been a while, on Ubuntu 20.04 Mate with LO v6.4.4.5 and fresh install of PyCharm Community 2020.1, was able to interact with Calc. In past have done so with Writer and Base also. Last link in my answer is connection used.

Thanks, taking your example doc.getText().setString(“Hello World!”) how would I do the same thing with a specific field (a text box named ‘Input’) on my form. doc.getText().setString(“Hello World!”) seems to imply there is only one Text property for the whole xls or form. Or am I just confused?

@active,

First, that is not my sample. It is a link I provided. Also, code does not need to include all fields - just what you are accessing. Believe it is for a Writer interface. I have used that general code for Base before.

Currently having issues with PyCharm but this is tested python code for what you have asked:

desktop = XSCRIPTCONTEXT.getDesktop()
thisComponent = desktop.getCurrentComponent()
oform = thisComponent.getDrawPage().Forms.getByName("YOUR_INTERNAL_FORM_NAME")
oform["Input"].Text = 'My Text Here'

There of course is a lot of ifs, ands, and wherebys!

Much appreciated. I edited my original post to show the code I eventually used, very close to yours (pop matching database record) but then ran into issues with trying to press the button on the form. Sadly I dont think there is a fix for that part.

@active,

The code you posted for pressing a button does not do that. That code inserts an a into a text box.

Yes, the simulate keypress part misled me. Inserting an A would have been much simpler using the code I already have to insert ‘personalid’.(and which is working). Do you know if it is possible to actually press the Search button on the same Base form using python, without loading third party tools or having to code hundreds of lines?

@active,

Have resolved most of my PyCharm problems. Again using the code in the last link of my answer all works.

doc.getText().setString(“Hello World!”)

simply places text @ the cursor.

With what you request, first set focus on the button:

oDoc = XSCRIPTCONTEXT.getDocument()
oController = oDoc.getCurrentController()
oForm = oDoc.getDrawPage().getForms().getByName("Form")
oPB = oForm.getByName("PB1")
oControlView = oController.getControl(oPB)
oControlView.setFocus()

Also replaced:

oEvent = uno.createUnoStruct("com.sun.star.awt.KeyEvent")
oEvent.Source = oControlView
from com.sun.star.awt.Key import A
oEvent.KeyCode = A
oEvent.KeyChar = "a"       # works in Python but strangely not in Basic

with:

from com.sun.star.awt.Key import RETURN
oEvent = uno.createUnoStruct("com.sun.star.awt.KeyEvent")
oEvent.Source = oControlView
oEvent.Modifiers = 0
oEvent.KeyCode = RETURN
oEvent.KeyChar = chr(13)

With specified code changes the push button was pressed and the attached macro was executed.

Thanks again, though oForm = oDoc.getDrawPage().getForms().getByName(“Form”) causes a NoSuchElementException, so I replaced it with oForm = oDoc.getDrawPage().getForms().getByIndex( 0 ) The focus is set and the button appears to being pushed (it flickers) but the macro (record lookup) doesn’t run. If I click the button manually (whilst the script is running) the macro does run. This is bizarre, I will investigate further today.

Eventually worked when I assigned the same macro to key pressed. Thank you again.
However major issues with macros running in stand-alone ODT’s. If I open the form in Base, design mode, assign the macro to the key pressed action, then save the form as ODT the macro breaks. If I copy the existing ODT (on the dekstop) and alter that in design mode then the macro works. These types of bugs make me very wary of LibreOffice.

@active,

It appears much of your problem may be due to a lack of understanding of the code. For example, getByName("Form") is most likely giving you an error because the name of your internal form is different than Form. Accessing by index is not recommended since this can change but likely the name will not. The same may be true of the button control. The form naming was shown in my second comment above.

These are not bugs as you call them. The code I have presented works for me without the issues you mention. There are many items (eluded to in earlier comments) which you have not even disclosed and may be a factor. What events you use are an example. For my push button it is the Execute action event (this is typically the event I use for this control).

All testing I have done is with the Standalone form (Writer).

. Did actually try ‘Access’ (the name of my form) instead of Form but it made no deifference. Partially working now (thanks mostly to your help) except for macros which break if you try and produce additional ODT’s (instead of copying / editing an existing one) but ther are various support posts which mention this issue. Perhaps a later release may fix them but I will have stop at this point as this has already taken too much time. Anyway, thanks again for your help.

Access is unusual for an internal name - usually it is Form or MainForm unless you actually entered that as the internal form name. But according to your code, that seems to be the name of the document.

And again, not experiencing any of the problems you seem to be having. Don’t believe a different release will change anything.

Don’t know what posts you may be referring to but have not seen this breaking of macros on a post or any of my testing to my current recollection.