Прослушивание событий документа

Прослушивание событий документа может помочь в следующих ситуациях:

После назначения макросов событиям можно отслеживать события, возникающие в документах LibreOffice. За вызов сценариев обработки событий отвечают источники событий API. В отличие от слушателей, требующих определения всех поддерживаемых методов (даже неиспользуемых), обработчики событий документа требуют наличия лишь двух методов помимо самих сценариев обработки событий.

Обработка событий документа

Отслеживание событий показано здесь на языках Basic и Python с применением объектно ориентированного программирования. Для запуска и завершения процесса отслеживания событий документа достаточно назначить сценарий OnLoad событию Открытие файла. Назначение события какому-либо сценарию выполняется в меню Сервис - Настройка на вкладке События.

Перехват событий помогает настраивать сценарии пред- и постусловия, например, загрузка и выгрузка библиотек или фоновое отслеживание выполнения сценариев. Использование модуля Access2Base.Trace служит иллюстрацией последнего из указанных вариантов.

С помощью Python

Отслеживание событий начинается с создания экземпляра документа и окончательно завершается после автоматического удаления объекта средствами Python. Возникающие события регистрируются в консоли Access2Base.

Значок примечания

События OnLoad и OnUnload можно использовать, соответственно, для установки и сброса путей к программам Python. Они называются Открытие файла и Документ закрыт.



         # -*- coding: utf-8 -*-
         from __future__ import unicode_literals
             
         import os.path, uno, unohelper
         from com.sun.star.document import DocumentEvent, \
             XDocumentEventListener as AdapterPattern
         from com.sun.star.lang import EventObject
             
         class UiDocument(unohelper.Base, AdapterPattern):
             """ Отслеживание событий документа """
             '''
             Основано на примере «Сценарий Python для отслеживания события OnSave» на
             https://forum.openoffice.org/en/forum/viewtopic.php?t=68887
             '''
             def __init__(self):
                 """ Обработчик событий документа """
                 ''' Отчёт выводится в консоли Access2Base.Trace ИЛИ
                 в первом столбце первого листа документа Calc '''
                 ctx = uno.getComponentContext()
                 smgr = ctx.getServiceManager()
                 desktop = smgr.createInstanceWithContext(
                 'com.sun.star.frame.Desktop' , ctx)
                 self.doc = desktop.CurrentComponent
                 #self.row = 0  # раскомментируйте для вывода только в документ Calc
                 Console.setLevel("DEBUG")
                 self.listen()  # Начать отслеживание событий док-та
             
             @property
             def Filename(self) -> str:
                 sys_filename = uno.fileUrlToSystemPath(self.doc.URL)
                 return os.path.basename(sys_filename)
             
             def setCell(self, calcDoc, txt: str):
                 """ Вывод событий док-та в первом столбце электронной таблицы Calc """
                 sheet = calcDoc.getSheets().getByIndex(0)
                 sheet.getCellByPosition(0,self.row).setString(txt)
                 self.row = self.row + 1
             
             def listen(self, *args):  # OnLoad/OnNew в первую очередь
                 """ Запуск отслеживания событий док-та """
                 self.doc.addDocumentEventListener(self)
                 Console.log("INFO", "Выполняется регистрация событий документа", True)
             
             def sleep(self, *args):  # OnUnload в последнюю очередь (необязательно)
                 """ Остановка отслеживания событий док-та """
                 self.doc.removeDocumentEventListener(self)
                 Console.log("INFO", "События документа записаны", True)
             
             def documentEventOccured(self, event: DocumentEvent):
                 """ Перехватывает все события док-та """
                 #self.setCell(event.Source, event.EventName) # только для документов Calc
                 Console.log("DEBUG",
                     event.EventName+" in "+self.Filename,
                     False)
             
             def disposing(self, event: EventObject):
                 """ Освобождение всех ресурсов """
                 self.sleep()
                 Console.show()
             
         def OnLoad(*args):  # Событие 'Открытие файла'
             listener = UiDocument()  # Инициализирует прослушивание
             
         def OnUnload(*args):  # Событие 'Документ закрыт'
             pass  # (необязательно) выполняется при вызове метода disposed
             
         g_exportedScripts = (OnLoad,)
             
         from com.sun.star.script.provider import XScript
         class Console():
             """
             Вывод консоли на (передний/задний) план для создания отчёта/вывода журнала выполнения программы.
             """
             @staticmethod
             def trace(*args,**kwargs):
                 """ Вывод произвольного списка элементов в консоль """
                 scr = Console._a2bScript(script='DebugPrint', module='Compatible')
                 scr.invoke((args),(),())
             @staticmethod
             def log(level: str, text: str, msgBox=False):
                 """ Добавление сообщения в консоль, возможен вывод уведомления пользователю """
                 scr = Console._a2bScript(script='TraceLog')
                 scr.invoke((level,text,msgBox),(),())
             @staticmethod
             def setLevel(logLevel: str):
                 """ Задание нижнего порога уровня важности сообщений """
                 scr = Console._a2bScript(script='TraceLevel')
                 scr.invoke((logLevel,),(),())
             @staticmethod
             def show():
                 """ Отображение содержимого консоли/диалогового окна """
                 scr = Console._a2bScript(script='TraceConsole')
                 scr.invoke((),(),())
             @staticmethod
             def _a2bScript(script: str, library='Access2Base',
                 module='Trace') -> XScript:
                 ''' Получение сценария Basic из общей библиотеки'''
                 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 xScript
      
Значок предупреждения

Обратите внимание на грамматическую ошибку в названии метода documentEventOccured, в котором опечатка наследуется из LibreOffice API.


Значок подсказки

События Запуск приложения и Закрытие приложения могут использоваться, соответственно, для установки и сброса путей к программам Python для пользовательских сценариев или сценариев LibreOffice. Таким же образом можно загружать и выгружать встроенные библиотеки или модули Python с помощью событий Открытие файла и Документ закрыт. Более подробную информацию см. в разделе Импорт модулей Python.


С помощью LibreOffice Basic

При помощи меню Сервис - Настройка вкладка События, событие Открытие файла запускает инициализацию ConsoleLogger. Процедура _documentEventOccured, которую запускает ConsoleLogger, служит единой точкой входа для перехвата всех событий документа.

Модуль controller.Events


        Option Explicit
        
        Global _obj As Object ' экземпляр controller.ConsoleLogger
        
        Sub OnLoad(evt As com.sun.star.document.DocumentEvent) ' >> Открытие файла <<
            _obj = New ConsoleLogger : _obj.StartAdapter(evt)
        End Sub ' controller.OnLoad
        Sub _documentEventOccured(evt As com.sun.star.document.DocumentEvent)
            ''' Единая точка входа ConsoleLogger '''
             _obj.DocumentEventOccurs(evt)
        End Sub ' controller._documentEventOccured
      

Модуль класса controller.ConsoleLogger

Отслеживание событий начинается с момента инициализации объекта ConsoleLogger и окончательно завершается при закрытии документа. Процедура StartAdapter загружает необходимые библиотеки Basic, а перехваченные события регистрируются при помощи модуля Access2Base.Trace.


          Option Explicit
          Option Compatible
          Option ClassModule
              
          ' Объект шаблона проектирования ADAPTER, экземпляр которого необходимо создать при событии «Открытие файла»
          Private Const UI_PROMPT = True
          Private Const UI_NOPROMPT = False ' Установите значение True для визуализации событий документа
              
          ' ЭЛЕМЕНТЫ КЛАССА
          Private _evtAdapter As Object ' com.sun.star.document.XDocumentEventBroadcaster
          Private _txtMsg As String ' текстовое сообщение для записи в консоль
              
          ' СВОЙСТВА
          Private Property Get FileName As String
              ''' Системно-зависимое имя файла '''
              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
              
          ' МЕТОДЫ
          Public Sub DocumentEventOccurs(evt As com.sun.star.document.DocumentEvent)
              ''' Отслеживание событий документа '''
              Access2Base.Trace.TraceLog("DEBUG", _
                  evt.EventName &" in "& Filename(evt.Source.URL), _
                  UI_NOPROMPT)
              Select Case evt.EventName
                  Case "OnUnload" : _StopAdapter(evt)
              End Select
          End Sub ' controller.ConsoleLogger.DocumentEventOccurs
              
          Public Sub StartAdapter(Optional evt As com.sun.star.document.DocumentEvent)
              ''' Инициализация журналирования событий документа '''
              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 & "Выполняется регистрация событий документа", UI_PROMPT)
              _evtAdapter = CreateUnoListener( "_", "com.sun.star.document.XDocumentEventListener" )
              ThisComponent.addDocumentEventListener( _evtAdapter )
          End Sub ' controller.ConsoleLogger.StartAdapter
              
          Private Sub _StopAdapter(Optional evt As com.sun.star.document.DocumentEvent)
              ''' Завершение регистрации событий документа '''
              ThisComponent.removeDocumentEventListener( _evtAdapter )
              If IsMissing(evt) Then _txtMsg = "" Else _txtMsg = evt.EventName & "-"
              Access2Base.Trace.TraceLog("INFO", _txtMsg & "События документа записаны", UI_PROMPT)
              Access2Base.Trace.TraceConsole() ' Диалоговое окно перехваченных событий
          End Sub ' controller.ConsoleLogger._StopAdapter
              
          ' СОБЫТИЯ
          ' Собственный код для обработки событий можно вставить здесь
      
Значок предупреждения

Обратите внимание на грамматическую ошибку в названии метода _documentEventOccured, в котором опечатка наследуется из LibreOffice API.


Изучение событий документа

Объект рассылки событий предоставляет список событий, за которые он отвечает:

С помощью Python


         # -*- coding: utf-8 -*-
         from __future__ import unicode_literals
             
         import uno, apso_utils as ui
             
         def displayAvailableEvents():
             """ Отображение событий документа """
             '''
             Основано на DisplayAvailableEvents() от 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,)
      
Значок примечания

Расширение Alternative Python Script Organizer (APSO) используется для вывода информации о событиях на экран.


С помощью LibreOffice Basic


         Sub DisplayAvailableEvents
             ''' Отображение событий документа '''
             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
      
Пожалуйста, поддержите нас!

Пожалуйста, поддержите нас!