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

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.

sqlite3 is a built in package of python. The issues is (on Windows) when installing the search tool in a vritual environment set for LibreOffice the sqlite package is missing. This is a LibreOffice thing, LibreOffice does not ship with complete python. See bug 116412. If you install the search tool in a normal python environment it should work fine.

A possible answer. But I think it’s a workaround, not the real answer.

When I click on the form icon and the form opens, I have found that a listener is indeed triggered, but not on the form itself:

    doc = Base.open_doc('test_db.odb', loader)
    GUI.set_visible(is_visible=True, odoc=doc)
    class DocEventListener(unohelper.Base, XDocumentEventListener):
        def documentEventOccured(self, event):
            print_out_element(event, 'doc event')
    doc.addDocumentEventListener(DocEventListener())

… one possible hypothesis is thus that the “property” “When loading” which you can use to attach a macro to the event of a form being opened is in fact a sort of pseudo-property: this event is actually attached to the object at the top of the hierarchy, which I shall refer to as the “ODB document”, with the following spec: implementationName=com.sun.star.comp.dba.ODatabaseDocument, supportedServices={com.sun.star.sdb.OfficeDatabaseDocument,com.sun.star.document.OfficeDocument}

Interestingly, before a form is opened, although it implements the interface XComponent, actually getComponent() returns None. After a form is opened, however, this returns an object, which is essentially a Writer document, since Base forms are obviously modelled on Writer documents. This might explain why form objects implement XCloseListener, but (apparently) nothing to listen in on the event of opening.

I tentatively call it a “pseudo property”, because the user who edits the form, and attaches a macro to this event, is no doubt tempted to think that they are configuring an event of the form itself. Which then begs the question, are all these form events pseudo properties, or just this one: for example, what about the event “After record change”, which I also need to configure?

A bit later: I now don’t think this is right. Clearly the Writer document which is used to make the component when a form is loaded must be stored somewhere inside the .odb file. Having examined the component after opening, this has a method getEvents, one of which is OnLoad (however, there is nothing there which corresponds to the form’s “After record change” event: maybe this can be found from the form’s data provider objects …).

So the question is: how to obtain a reference to this Writer document, before the form is loaded? It must be present in some storage location.

Embedded form opening can be listened to with database document event OnSubComponentOpened.
Interface XDatabaseDocumentUI provides access to the user interface of a database document.

Thanks. I saw from exploration that doc.getEvents() includes OnSubComponentOpened (type str)… but I don’t know how you set up a listener on that. This doesn’t work:

    def on_sub_opened(*args, **kwargs):
        print(f'args {args} kwargs {kwargs}')
    doc.getEvents().OnSubComponentOpened = on_sub_opened

uno.RuntimeException: Couldn’t convert <function main..on_sub_opened at 0x00000125C29F99D0> to a UNO type; caught exception: <class ‘AttributeError’>: ‘function’ object has no attribute ‘getTypes’

I’ve previously added a function-attribute (in the Python sense) getTypes to the function here. But then I get a fail with

uno.RuntimeException: Couldn’t convert <function main..on_sub_opened at 0x00000275E415C9D0> to a UNO type

… could you show what I’m meant to do?


Re your other point, could you illustrate how I obtain an object which implements that interface? The com.sun.star.comp.dba.ODatabaseDocument object doesn’t appear to do so.

This is because you start with the most complicated (and underdeveloped and unexplored) component of all. IMHO, whatever you try to do here, will turn out as virtually impossible to do.

@Villeroy
That’s the 3rd pointless post you’ve made here. Perhaps you could just not post a fourth?

In the standard way.
Open the database document and Menu / Tools / Customize… / Events.
Event: “Loaded a sub component”.

@sokol92
Oh dear. From your previous answer I thought you had understood. Please review the posts in this thread, and read the question thoroughly. I am trying to do this programmatically.

You may be the first person ever who wants to do that programmatically. Go ahead and don’t forget to tell us what you found out.

@Villeroy
I’ve already shown one way of doing this, using XDocumentEventListener.


I don’t know why someone who seems to have no interest in programming UNO using Python, and without the courtesy to have read the question in the first place, would want to contaminate a thread with pointless posts. I’ve heard your opinion. Could you stop posting now? Thanks.

There are many similar examples on the forum.
I stop posting now, Thanks.
For future readers of the topic:

Sub OnSubFormOpened(oEvent)
  Msgbox "OnSubFormOpened"
End Sub

Sub AddEventListener
  Dim oEvents
  Dim mEventProps(1) as new com.sun.star.beans.PropertyValue
  mEventProps(0).Name = "EventType"
  mEventProps(0).Value = "Script"
  mEventProps(1).Name = "Script"
  mEventProps(1).Value = "vnd.sun.star.script:Standard.Module1.OnSubFormOpened?language=Basic&location=document"
  oEvents=ThisComponent.Events
  oEvents.replaceByName "OnSubComponentOpened", mEventProps
End Sub

@sokol92

Thank you for showing how to attach a function to events designated by strings.

But in Python … hmmm! Very intriguing. I’ve just looked at the API and searching to see how a com.sun.star.beans.PropertyValue is created in Python UNO… and the gist seems to be

event_props = PropertyValue(Name='EventType', Value='Script')

… but as yet I haven’t found an example where, seemingly, you have TWO entries involved in a single PropertyValue. …

Again, you start at the wrong end. How to create UNO structs in your preferred language should be known before solving esoteric issues.
import uno
prop = uno.createUnoStruct(whatever)