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

Обръщения към макроси на Basic от Python