Python : Наблюдение на събития в документите

Съдържание
Индекс 🔎︎

# Наблюдение на събития в документите

Освен да приписвате макроси на събития, може също така да наблюдавате събитията, породени от документи на LibreOffice. Скриптовете за събития се извикват от разпространители (broadcasters) в приложния програмен интерфейс (API). За разлика от слушателите (listeners), които изискват дефиниране на всички поддържани методи, наблюдателите на документи (document monitors) изискват само два метода плюс закачените скриптове за събития.

## Чакане на събития в документ

Наблюдението е илюстрирано тук с обектноориентирано програмиране за езиците 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 ИЛИ
                     в лист 1, колона 1 за документи на 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):
                     """ Извеждане събитията в колона 1 на ел. таблица в 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("ИНФОРМАЦИЯ", "Събитията в документа се регистрират", True)

                 def sleep(self, *args):  # OnUnload най-късно (незадължително)
                     """ Спиране наблюдението на събития """
                     self.doc.removeDocumentEventListener(self)
                     Console.log("ИНФОРМАЦИЯ", "Регистрирането на събития приключи", 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()  # Initiates listening

             def OnUnload(*args):  # Събитие „Документът е затворен“
                 pass  # (незадължително) изпълнявано при освобождаване

             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:
                     ''' 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 xScript

Имайте предвид правописната грешка в името на метода documentEventOccured, наследена от програмния интерфейс (API) на LibreOffice.

Събитията Стартиране на приложение и Затваряне на приложение могат да се използват съответно за задаване и изчистване на пътя на Python за потребителски скриптове или скриптове на LibreOffice. По подобен начин базираните на документи библиотеки или модули на Python могат да се зареждат и освобождават чрез събитията Отваряне на документ и Документът е затворен. За повече информация вижте Импортиране на модули на Python.

### С LibreOffice Basic

Скриптът Onload се приписва на събитието Отваряне на документ с командата Инструменти - Персонализиране, раздел Събития. Наблюдението на събития започва от момента, когато се създаде обект от клас ConsoleLogger и приключва, когато средата на Basic освободи обекта. Събитието OnLoad зарежда необходимите библиотеки на Basic, а уловените събития се докладват чрез модула Access2Base.Trace.

              REM Модул controller.Events
              Option Explicit
              Private _obj As Object ' Екземпляр на controller.ConsoleLogger

              Sub OnLoad(evt As com.sun.star.document.DocumentEvent) ' >> Отваряне на документ <<
                  _obj = New ConsoleLogger : _obj.Start(evt)
              End Sub ' controller.OnLoad
              ' ----
              REM Модул на класа controller.ConsoleLogger
              Option Explicit
              Option Compatible
              Option ClassModule

              ' АДАПТЕР – обект, който се създава при събитието „Отваряне на документ“
              Private Const UI_PROMPT = True
              Private Const UI_NOPROMPT = False ' Set it to True to visualise documents events

              ' КОНСТРУКТОР/ДЕСТРУКТОР
              Private Sub Class_Initialize()
              End Sub ' controller.ConsoleLogger.Initialize
              Private Sub Class_Terminate()
              End Sub ' controller.ConsoleLogger.Terminate

              ' ЧЛЕНОВЕ
              Private _evtAdapter As Object ' com.sun.star.document.XDocumentEventBroadcaster

              ' PROPERTIES
              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

              ' МЕТОДИ
              Private Sub _documentEventOccured(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" : _Stop(evt)
                  End Select
              End Sub ' controller.ConsoleLogger._documentEventOccured

              Private Sub _disposing(evt As com.sun.star.lang.EventObject)
              End Sub ' controller.ConsoleLogger.disposing

              Public Sub Start(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")
                  Access2Base.Trace.TraceLog("INFO", _
                      IIf(IsMissing(evt),"",evt.EventName & "-") & "Събитията в документа се регистрират", _
                      UI_PROMPT)

                  _evtAdapter = CreateUnoListener( "_", "com.sun.star.document.XDocumentEventListener" )
                  ThisComponent.addDocumentEventListener( _evtAdapter )
              End Sub ' controller.ConsoleLogger.Start

              Private Sub _Stop(Optional evt As com.sun.star.document.DocumentEvent)
                  ''' Прекратяване регистрирането на събития '''
                  ThisComponent.removeDocumentEventListener( _evtAdapter )
                  Access2Base.Trace.TraceLog("INFO", _
                      IIf(IsMissing(evt),"",evt.EventName & "-") & "Регистрирането на събития приключи", _
                      UI_PROMPT)
                  Access2Base.Trace.TraceConsole() ' Captured events dialog
              End Sub ' controller.ConsoleLogger._Stop

              ' EVENTS
              ' Тук ще бъде вашият код за обработка на събития

Имайте предвид правописната грешка в името на метода _documentEventOccured, наследена от програмния интерфейс (API) на 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