Отслеживание событий документа

Содержимое

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

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

- Идентификация документа в момент открытия как нового (чтобы отличить от уже существующих) для выполнения специализированной настройки.

- Контроль обработки запросов на сохранение, копирование и печать документа, а также на выполнение рассылки писем.

- Обновление оглавлений, указателей или элементов таблицы документа Writer перед его закрытием

- Импорт математических пакетов Python перед открытием документа Calc. Отключение этих пакетов после закрытия документа.

После назначения макросов событиям можно отслеживать события, возникающие в документах 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

См. также

Создание слушателей событий

Импорт модулей Python

Создание обработчика диалогового окна

Примеры кода на Python

Программирование с использованием сценариев Python

Вызов макросов Basic из Python