How do I find programmatically (Python) the "when loading" event for a Form in a Base document?

I’m experimenting with the python ooodev project created by user “vib” here.

He/she hasn’t yet covered Base in any great depth, but this is the app I want to automate.

Tweaking one or two of his files and cobbling something together I have managed to open an .mdb file and then get a reference to a form in this dbase document.

with Lo.Loader(Lo.ConnectSocket()) as loader:
    doc = Base.open_doc('test_db.odb', loader)
    GUI.set_visible(is_visible=True, odoc=doc)
    form_0 = doc.FormDocuments[0]
    print(f'form_0 {form_0}')

But I’m struggling with how to implement a listener on the “open form” event (in fact the event is called “When loading” if you do it manually). The print command shows the UNO interfaces implemented:

form_0 pyuno object (com.sun.star.ucb.XContent)0x1eb77dc0c68{implementationName=com.sun.star.comp.sdb.Content, supportedServices={com.sun.star.ucb.Content}, supportedInterfaces={com.sun.star.ucb.XContent,com.sun.star.ucb.XCommandProcessor,com.sun.star.lang.XServiceInfo,com.sun.star.beans.XPropertiesChangeNotifier,com.sun.star.beans.XPropertyContainer,com.sun.star.lang.XInitialization,com.sun.star.lang.XUnoTunnel,com.sun.star.container.XChild,com.sun.star.sdbcx.XRename,com.sun.star.lang.XTypeProvider,com.sun.star.uno.XWeak,com.sun.star.lang.XComponent,com.sun.star.beans.XPropertySet,com.sun.star.beans.XMultiPropertySet,com.sun.star.beans.XFastPropertySet,com.sun.star.beans.XPropertyState,com.sun.star.lang.XTypeProvider,com.sun.star.embed.XComponentSupplier,com.sun.star.sdb.XSubDocument,com.sun.star.util.XCloseListener,com.sun.star.container.XHierarchicalName,com.sun.star.lang.XTypeProvider}}

… but none of these seems to contain a suitable addXXXListener method whose Listener class has a method which will fire when the form is opened (by user action or programmatically).

For that matter, I wanted to do this even previously, when using “standard” embedded macros: it got to be tiresome to have to connect up the events to the macros manually each time I changed my code and rebuilt the .odb file.

The closest answer I’ve found is this thread, which talks about firing events on form controls (which I’d also like to do and to be able to find listeners for)… but it all seems to be about VB, and I can’t understand what to do in Python.

Take a look at Python LibreOffice Programming Part 1: Basics Chapter 4. Listening, and Other Techniques

I am not sure which listener you need but I suspect that is how you accomplish the task.

Using my LibreOffice Developer Search Tool I was able to find 139 Listeners.
Here is a link to pastbin
I ran the command loapi comp -a -m 150 -t interface -s listener to find this list.

Also the Build Form example shows one way of how to attach events to buttons and controls.

Hope that helps.

P.S.
“He” is just fine for me.

I just noticed the DocWindowAdapter of Listening, and Other Techniques is not up to date. I will correct this. Mean while you can see the DocWindowAdapter code here

@mrodent
I believe your question here should be limited to what is within the LO suite. Seems you are more into this add on software and that should be discussed on their site.
.

While there is little capability of VB in the LO suite you are probably referring to Star Office Basic. However, I have posted a number of listener routines in python in various places on this site - for controls in forms dialogs and more. Unfortunately I am not going to weed out your third party references so being more specific about what you want in with regard to LO would be helpful.
.
I have nothing against third party add ons with the exception that it presents another piece of overhead, prone to attention when LO changes and some are just smoke & mirrors. So I now tend to stay away from these. This includes Script Forge which I find to be a waste of time.

You can listen to the loading event of every single logical form in the hierarchy of forms and subforms.

@Ratslinger
Can’t disagree about add-ons being often unnecessary.
However, as discussed in my previous question, the limitations for Python of the “embedded macro” possibilities offered are so severe that it may make sense to look for something better. Crucially, vib’s framework means that you can run and automate LO apps within a Python virtual environment.

I’ll try finding your examples. To be perfectly fair, I don’t think it is possible to be more specific than my question: I have asked how to have a Python listener which responds when a LO Base form gets opened.

@Villeroy

Seems like you may not have read the question thoroughly. I am programming in Python. I want to “set up” or “connect” the Event “When loading” programmatically, using Python. I know how to do what you illustrate, and specifically said in my question “it got to be tiresome to have to connect up the events to the macros manually”.

You have shown how to do this manually. I know how to do this manually.

Don’t get why attaching to open document event would not satisfy this.
.
Have programmatically been able to insert on the fly listener changes in a Calc file. Will look for that. Still not really sure what you are attempting here. Sounds a bit of over complication.

@Ratslinger
Thanks. Do you mean doing something like this:

    real_open = form_0.open
    def overridden_open(*args, **kwargs):
        print(f'args {args} kwargs {kwargs}')
        real_open(*args, **kwargs)
    form_0.open = overridden_open

… this failed with

Traceback (most recent call last):

File “start_base_auto.py”, line 84, in main
form_0.open = overridden_open
uno.RuntimeException: Couldn’t convert <function main..overridden_open at 0x000001CACC3A5040> to a UNO type; caught exception: <class ‘AttributeError’>: ‘function’ object has no attribute ‘getTypes’, traceback follows
no traceback available

… it may be obvious to you why this is. Or it may be that this framework is missing certain environmental elements. For example, XSCRIPTCONTEXT is not available.


… or you may mean something entirely different by “attaching to open document event”. What does this mean to you, if not substituting a method Pythonically as in the above snippet? (I really want to know!). However, please note that this is NOT an “open document” event. A Form is not the document. LO Base files can contain multiple Forms. They implement (for example) the interface XSubDocument, among many others…

I may be completely off track here, but if you are steering LibreOffice over socket/pipe, why do you need a listener? It should be your program, wich opens a form, so there is no need to be notified, when the form opens. (You may get an error-code, if it isn’t opening)
.
This is different from the approach of internal macros, wich are triggered by buttons or events, when user interacts with the program. So we don’t know, what user is doing, and react to events.

@Wanderer
Thanks.


No, the Form is not opened programmatically (or not necessarily).


The Base file displays as normal on running the Python script, and the user is free to click on a form (of which there can be many in one Base file) at will, to open it. There IS DEFINITELY a mechanism to listen into that event, otherwise it would not be possible to connect up the event, for a specific form, “When loading”, which you can do manually.


If you can do it manually there must be a way to listen for and respond to that event programmatically.

Not sure where you are looking. I find it but not certain where or what you are looking at. Again, is this what you are looking for → How to use macro to open form in Base? - #14 by Ratslinger
.
Each comment you present seems to be more confusion as to what is actually needed.
.
Edit:
Also unclear is:

.
Then what is it? Another wonderful situation which has been present since long, long ago. Same title for two different items. Base can have tables, queries reports and forms. These forms are documents within Base. Now in that Form are internal forms which contain controls. There can be many forms within the form document and sub forms for each and sub sub forms… and these internal forms do not get opened or closed.
.
So have unclear picture as to what this means:

.
Second edit:
.
So here is a link which shows how to set events(listeners) in controls programmatically. Yes the code is in Basic but that should not be any problem to convert. I am still trying to figure out just what it is you actually want.
.

@vib
Thanks.
Regarding your search tool, I installed this, but it failed because of an attempt to import sqlite3, which is a notorious package. In theory it should be possible to install module pysqlite3, but on this occasion this also failed.


Concerning your window listener class: interesting, but this is about loading the initial window. I’m not sure how applicable it is to something like a form, which starts like this:

pyuno object (com.sun.star.ucb.XContent)0x1eb8928e018{implementationName=com.sun.star.comp.sdb.Content, supportedServices={com.sun.star.ucb.Content}, supportedInterfaces={ ...

Note that, strangely, the API docs do not contain a section on com.sun.star.comp.


I have found that there is an interface XLoadListener, and also an interface XLoadable, which has a method addLoadListener(XLoadListener listener). I would bet that these are the things I need to find but the question is how to find this interface from the form object: the object itself does not implement XLoadable.


Having done some searching it appears that “script events” may be the key here, see this answer in a forum thread.

I don’t understand much yet about “property change listeners” either: is it possible to get a list of listenable properties for an object?

https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1form_1_1XLoadable.html#a2664eb513cdbb9cd90b615bdeb5596e9
https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1form_1_1XLoadListener.html

@Ratslinger

Let me try and clarify. It’s VERY simple. Using the script framework ooo dev tools developed by vib, I have managed, by running the script, to open an .odb document which contains 1 form, so this opens Base as normal. I confirm that in this arrangement, XSCRIPTCONTEXT is not available: this is not the situation where a macro is connected normally to an event, by editing an .odb file.


So I simply want, programmatically, in this script, and having obtained a reference to the form object in my Python code, to set up a listener on it, one method of which will fire when the form is loaded (opened): whether programmatically, or more likely when the user clicks on the form. This is equivalent to the “When loading” event which you can find under “Events” when you edit a form.


PS it may be that this form is a “document” for you, or by convention of UNO terminology. I had assumed that when we talk about “documents” here this means, essentially, the .ods file, .odt file or .odb file (in the case of Base). Obviously an .odb file can contain multiple forms, and they are loaded by the user double-clicking on one of them.

@Villeroy
Thanks, but I had already provided those links to the API documents in my last post. Why did you list them?

As stated earlier, this is not part of LibreOffice but rather a third party add on. Questions on this should be asked of that author and not here on the LO Ask site.

@Ratslinger

My question is in no way specific to the framework. This is so apparent it is hardly worth saying.


It seems like you are unable to answer the question "set up a listener on [the Form object], one method of which will fire when the form is loaded (opened)", but for some reason don’t want to say so. Such an object can be obtained in a normal macro, as you must be aware.


As you can see from the tentative answer I have given, there is a way of detecting, using a listener, when a form is opened.

No. The problem I have is trying to figure out just what you are trying to accomplish. Have one more post for you → Base macro that opens a new/clean record in another form using python
.
Also did present Calc file showing methods to modify listeners using code. Have come at various angles with this and have no idea why none of this is seemingly near to shat is wanted.

With OooDev, in script mode, after a document is loaded the Lo.XSCRIPTCONTEXT is available (or Lo.xscript_context).
The same is true for Lo.this_component.

In Macro Mode Lo.XSCRIPTCONTEXT and Lo.this_component are available when the document is opened.

Usually these properties are not needed because OooDev gives you access to what you need via it various modules such as Calc, Write, Char2 etc.