Listening to document events can help in the following situations:Identify a new document at opening time, as opposed to existing ones, and perform a dedicated setup.Control the processing of document save, document copy, print or mailmerge requests.Recalculate table of contents, indexes or table entries of a Writer document when document is going to be closedImport math Python packages before opening a Calc document. Release these packages when the document closes.Next to assigning macros to events, one can monitor events raised by %PRODUCTNAME documents. Application Programming Interface (API) broadcasters are responsible for calling event scripts. Unlike listeners that require to define all supported methods, even if unused, document monitors require only two methods next to hooked event scripts.
Monitoring Document Events
Monitoring is illustrated herewith for Basic and Python languages using object-oriented programming. Assigning OnLoad script, to the event, suffices to initiate and terminate document event monitoring. menu tab is used to assign either scripts.Intercepting events helps setting scripts pre- and post-conditions such as loading and unloading libraries or track script processing in the background. Access2Base.Trace module usage is illustrating that second context.
With Python
API;frame.Desktop: Monitoring Document EventAPI;script.provider.MasterScriptProviderFactory: Monitoring Document EventAPI;script.provider.XScript: Monitoring Document EventEvents monitoring starts from object instantiation and ultimately stops when Python releases the object. Raised events are reported using Access2Base console.OnLoad and OnUnload events can be used to respectively set and unset Python programs path. They are described as and .# -*- coding: utf-8 -*-from __future__ import unicode_literalsimport os.path, uno, unohelperfrom com.sun.star.document import DocumentEvent, \ XDocumentEventListener as AdapterPatternfrom com.sun.star.lang import EventObjectclass UiDocument(unohelper.Base, AdapterPattern): """ Monitor document events """ ''' adapted from 'Python script to monitor OnSave event' at https://forum.openoffice.org/en/forum/viewtopic.php?t=68887 ''' def __init__(self): """ Document events monitor """ ''' report using Access2Base.Trace console OR report in 1st sheet, 1st column for Calc docs ''' ctx = uno.getComponentContext() smgr = ctx.getServiceManager() desktop = smgr.createInstanceWithContext( 'com.sun.star.frame.Desktop' , ctx) self.doc = desktop.CurrentComponent #self.row = 0 # uncomment for Calc documents only Console.setLevel("DEBUG") 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 setCell(self, calcDoc, txt: str): """ Output doc. events on 1st column of a Calc spreadsheet """ sheet = calcDoc.getSheets().getByIndex(0) sheet.getCellByPosition(0,self.row).setString(txt) self.row = self.row + 1 def listen(self, *args): # OnLoad/OnNew at the earliest """ Start doc. events monitoring """ self.doc.addDocumentEventListener(self) Console.log("INFO", "Document events are being logged", True) def sleep(self, *args): # OnUnload at the latest (optional) """ Stop doc. events monitoring """ self.doc.removeDocumentEventListener(self) Console.log("INFO", "Document events have been logged", True) def documentEventOccured(self, event: DocumentEvent): """ Intercepts all doc. events """ #self.setCell(event.Source, event.EventName) # only for Calc docs Console.log("DEBUG", event.EventName+" in "+self.Filename, False) def disposing(self, event: EventObject): """ Release all activities """ self.sleep() Console.show()def OnLoad(*args): # 'Open Document' event listener = UiDocument() # Initiates listeningdef OnUnload(*args): # 'Document has been closed' event pass # (optional) performed when disposedg_exportedScripts = (OnLoad,)from com.sun.star.script.provider import XScriptclass Console(): """ (Back/Fore)ground console to report/log program execution. """ @staticmethod def trace(*args,**kwargs): """ Print free item list to console """ scr = Console._a2bScript(script='DebugPrint', module='Compatible') scr.invoke((args),(),()) @staticmethod def log(level: str, text: str, msgBox=False): """ Append log message to console, optional user prompt """ scr = Console._a2bScript(script='TraceLog') scr.invoke((level,text,msgBox),(),()) @staticmethod def setLevel(logLevel: str): """ Set log messages lower limit """ scr = Console._a2bScript(script='TraceLevel') scr.invoke((logLevel,),(),()) @staticmethod def show(): """ Display console content/dialog """ scr = Console._a2bScript(script='TraceConsole') scr.invoke((),(),()) @staticmethod def _a2bScript(script: str, library='Access2Base', module='Trace') -> XScript: ''' Grab application-based Basic script ''' sm = uno.getComponentContext().ServiceManager mspf = sm.createInstanceWithContext( "com.sun.star.script.provider.MasterScriptProviderFactory", uno.getComponentContext()) scriptPro = mspf.createScriptProvider("") scriptName = "vnd.sun.star.script:"+library+"."+module+"."+script+"?language=Basic&location=application" xScript = scriptPro.getScript(scriptName) return xScriptMind the misspelled documentEventOccured method that inherits a typo from %PRODUCTNAME Application Programming Interface (API). and events can respectively be used to set and to unset Python path for user scripts or %PRODUCTNAME scripts. In a similar fashion, document based Python libraries or modules can be loaded and released using and events. Refer to Importing Python Modules for more information.
With %PRODUCTNAME Basic
API;GlobalScope.BasicLibrariesTools;StringsUsing menu tab, the event fires a ConsoleLogger initialisation. _documentEventOccured routine - set by ConsoleLogger - serves as a unique entry point to trap all document events.
controller.Events module
Option ExplicitGlobal _obj As Object ' controller.ConsoleLogger instanceSub OnLoad(evt As com.sun.star.document.DocumentEvent) ' >> Open Document << _obj = New ConsoleLogger : _obj.StartAdapter(evt)End Sub ' controller.OnLoadSub _documentEventOccured(evt As com.sun.star.document.DocumentEvent) ''' ConsoleLogger unique entry point ''' _obj.DocumentEventOccurs(evt)End Sub ' controller._documentEventOccured
controller.ConsoleLogger class module
Events monitoring starts from the moment a ConsoleLogger object is instantiated and ultimately stops upon document closure. StartAdapter routine loads necessary Basic libraries, while caught events are reported using Access2Base.Trace module.Option ExplicitOption CompatibleOption ClassModule' ADAPTER design pattern object to be instantiated in the "Open Document" eventPrivate Const UI_PROMPT = TruePrivate Const UI_NOPROMPT = False ' Set it to True to visualise documents events' MEMBERSPrivate _evtAdapter As Object ' com.sun.star.document.XDocumentEventBroadcasterPrivate _txtMsg As String ' text message to log in console' PROPERTIESPrivate Property Get FileName As String ''' System-dependent filename ''' Const _LIBRARY = "Tools" : With GlobalScope.BasicLibraries If Not .IsLibraryLoaded(_LIBRARY) Then .LoadLibrary(_LIBRARY) End With Filename = Tools.Strings.FilenameOutofPath(ThisComponent.URL)End Property ' controller.ConsoleLogger.Filename' METHODSPublic Sub DocumentEventOccurs(evt As com.sun.star.document.DocumentEvent) ''' Monitor document events ''' Access2Base.Trace.TraceLog("DEBUG", _ evt.EventName &" in "& Filename(evt.Source.URL), _ UI_NOPROMPT) Select Case evt.EventName Case "OnUnload" : _StopAdapter(evt) End SelectEnd Sub ' controller.ConsoleLogger.DocumentEventOccursPublic Sub StartAdapter(Optional evt As com.sun.star.document.DocumentEvent) ''' Initialize document events logging ''' Const _LIBRARY = "Access2Base" : With GlobalScope.BasicLibraries If Not .IsLibraryLoaded(_LIBRARY) Then .LoadLibrary(_LIBRARY) End With : Access2Base.Trace.TraceLevel("DEBUG") If IsMissing(evt) Then _txtMsg = "" Else _txtMsg = evt.EventName & "-" Access2Base.Trace.TraceLog("INFO", _txtMsg & "Document events are being logged", UI_PROMPT) _evtAdapter = CreateUnoListener( "_", "com.sun.star.document.XDocumentEventListener" ) ThisComponent.addDocumentEventListener( _evtAdapter )End Sub ' controller.ConsoleLogger.StartAdapterPrivate Sub _StopAdapter(Optional evt As com.sun.star.document.DocumentEvent) ''' Terminate document events logging ''' ThisComponent.removeDocumentEventListener( _evtAdapter ) If IsMissing(evt) Then _txtMsg = "" Else _txtMsg = evt.EventName & "-" Access2Base.Trace.TraceLog("INFO", _txtMsg & "Document events have been logged", UI_PROMPT) Access2Base.Trace.TraceConsole() ' Captured events dialogEnd Sub ' controller.ConsoleLogger._StopAdapter' EVENTS' Your code for handled events goes hereMind the misspelled _documentEventOccured method that inherits a typo from %PRODUCTNAME Application Programming Interface (API).
Discovering Documents Events
API;frame.GlobalEventBroadcaster: Monitoring Document EventThe broadcaster API object provides the list of events it is responsible for:
With Python
# -*- coding: utf-8 -*-from __future__ import unicode_literalsimport uno, apso_utils as uidef displayAvailableEvents(): """ Display document events """ ''' adapted from DisplayAvailableEvents() by A. Pitonyak https://forum.openoffice.org/en/forum/viewtopic.php?&t=43689 ''' ctx = XSCRIPTCONTEXT.getComponentContext() smgr = ctx.ServiceManager geb = smgr.createInstanceWithContext( "com.sun.star.frame.GlobalEventBroadcaster", ctx) events = geb.Events.getElementNames() ui.msgbox('; '.join(events))g_exportedScripts = (displayAvailableEvents,)The Alternative Python Script Organizer (APSO) extension is used to render events information on screen.
With %PRODUCTNAME Basic
Sub DisplayAvailableEvents ''' Display document events ''' Dim geb As Object ' com.sun.star.frame.GlobalEventBroadcaster Dim events() As String geb = CreateUnoService("com.sun.star.frame.GlobalEventBroadcaster") events = geb.Events.ElementNames() MsgBox Join(events, "; ")End Sub