How to get save listener event to python code

Hi,

I have made a connection to libreoffice and want to do some operation through my python script when save menu option is clicked. However I am not able to get callback . I have tried adding event listener, action listener. But didn’t succeeded.
Please help where I am doing wrong.

class UnoObjs:
	def __init__(self):
		localContext = uno.getComponentContext()
		resolver = localContext.ServiceManager.createInstanceWithContext(
			"com.sun.star.bridge.UnoUrlResolver", localContext)
		initialObject = resolver.resolve(
			"uno:socket,host=localhost,port=2002;urp;"
			"StarOffice.ServiceManager")
		self.ctx = initialObject.getPropertyValue("DefaultContext")
		self.smgr = self.ctx.ServiceManager
		self.desktop = self.smgr.createInstanceWithContext(
			"com.sun.star.frame.Desktop", self.ctx)
		self.frame = self.desktop.getCurrentFrame()
		if not self.frame:
			raise Exception("Could not get frame")
		self.dispatcher = self.smgr.createInstanceWithContext(
			"com.sun.star.frame.DispatchHelper", self.ctx)
		self.transformer = self.smgr.createInstanceWithContext(
			"com.sun.star.util.URLTransformer", self.ctx)
		self.configProvider = self.smgr.createInstanceWithContext(
			"com.sun.star.configuration.ConfigurationProvider", self.ctx)
		dobj=UiDocument(self.desktop)
		#doc = self.desktop.CurrentComponent
		#doc.addDocumentEventListener(dobj)
		oDoc = self.desktop.getDocument()
		oDoc.addDocumentEventListener(dobj)


class UiDocument(unohelper.Base, AdapterPattern):

	def __init__(self, desktop):
		#self.doc = desktop.CurrentComponent
		#self.row = 0  # uncomment for Calc documents only
		#self.listen()  # Start monitoring doc. events

	@property
	def Filename(self) -> str:
		sys_filename = uno.fileUrlToSystemPath(self.doc.URL)
		return os.path.basename(sys_filename)

	def listen(self, *args):  # OnLoad/OnNew at the earliest
		""" Start doc. events monitoring """
		self.doc.addDocumentEventListener(self)

	def sleep(self, *args):  # OnUnload at the latest (optional)
		""" Stop doc. events monitoring """
		self.doc.removeDocumentEventListener(self)

	def documentEventOccured(self, event: DocumentEvent):
		""" Intercepts all doc. events """
		#self.setCell(event.Source, event.EventName) # only for Calc docs
		print("test")

	def disposing(self, event: EventObject):
		""" Release all activities """
		self.sleep()


if __name__ == '__main__':
	edit_file_path = "/desktop/test.xls"
	office_path = 'soffice'
	calc = '-o'
	pipe = "--accept=socket,host=localhost,port=2002;urp"
	subprocess.Popen([office_path, calc, pipe, edit_file_path])
	time.sleep(2)

	UnoObjs()

I followed the instructions at Python : Monitoring Document Events and it worked. Did you get it to work? Try what they suggest before making your own changes.

Yeah, I have tried that also.For me that doesn’t work. Letme try again and will post what error I am getting .

I checked again. program is not running in my case it is exiting on line( It doesnt show any error on console)
desktop = smgr.createInstanceWithContext(
‘com.sun.star.frame.Desktop’ , ctx)
Have you done something different. I just ran the script.

The code in the example is meant to be run from within LibreOffice. From the error, it sounds like you tried to run it from outside on a listening instance instead. I can’t think of a reason why you would want to listen to events while also connecting from outside, and that may be the problem. But first, see if you can run the example the normal way. Put it in a location where LibreOffice can find it, such as user/Scripts/python, and then go to Tools → Macros → Run Macro.

yeah, you are correct. I have written python script in which user will pass the libreoffice path and script will open and connect to that libreoffice calc. I just need save event back to my application so that I can save the file my own way. Is there a way? I am struggling from last 3 days to achieve the same.

To listen to events, the python script would need to keep running in some kind of unblocking process.

Instead, make a python macro call. The code at Python : Monitoring Document Events works correctly when run this way.

soffice "vnd.sun.star.script:document_events.py$OnLoad?language=Python&location=user" "Untitled 1.odt"

The call can also be made from a python script. The following example creates a new file if it doesn’t exist.

import os
open("Untitled 1.odt", 'a').close()
command = (
    'soffice "vnd.sun.star.script:document_events.py$OnLoad'
    '?language=Python&location=user" "Untitled 1.odt"')
os.system(command)

EDIT:

Connecting through a socket does work as long as the python script keeps running. The event listener will be unblocked even though the main routine is blocking.

    def disposing(self, event: EventObject):
        print("disposing")
        self.doc.removeDocumentEventListener(self)
        global time_to_go
        time_to_go = True

def getCtxFromSocket():
    localContext = uno.getComponentContext()
    resolver = localContext.ServiceManager.createInstanceWithContext(
        "com.sun.star.bridge.UnoUrlResolver", localContext)
    ctx = resolver.resolve(
        "uno:socket,host=localhost,port=2002;urp;"
        "StarOffice.ComponentContext")
    return ctx

ctx = getCtxFromSocket()
OnLoad()
print("Waiting awhile...")
time_to_go = False
for _ in range(60):
    if not time_to_go:
        time.sleep(1)
print("Done.")

Apologies for the global command. It would be better to use a class property.

This produced the following output on the command line:

Document events are being logged
Waiting awhile...
OnTitleChanged in Untitled 2.odt
OnModeChanged in Untitled 2.odt
OnSaveAsDone in Untitled 2.odt
OnPrepareViewClosing in Untitled 2.odt
OnPrepareUnload in Untitled 2.odt
OnViewClosed in Untitled 2.odt
OnUnload in Untitled 2.odt
OnUnfocus in Untitled 2.odt
disposing
Done.

thanks a lot. It worked for me, but it will only work for 60 seconds . I think I should add a condition to check whether document is still open or not and keep running the script.

To make it wait longer, change 60 in my example to a bigger number, or change that line to while True. Testing if the document is still open may also work.

sounds good. thanks a lot :slight_smile: