Spremljanje dogodkov dokumenta v Pythonu

Vsebina
Kazalo 🔎︎

# Spremljanje dogodkov dokumenta

Poleg dodeljevanja makrov dogodkom lahko spremljamo dogodke, ki jih prožijo dokumenti LibreOffice. Oddajniki API (Application Programming Interface) so odgovorni za klicanje skriptov dogodkov. Za razliko od poslušalcev, ki zahtevajo določitev vseh podprtih metod, tudi če ostanejo neuporabljene, zahtevajo spremljevalniki dokumentov le dve metodi poleg skriptov, vezanih na dogodke.

## Poslušanje dogodkov dokumenta

Spremljanje je tu ilustrirano z jezikoma Basic in Python z uporabo objektnega programiranja. Za dodeljevanje skripta OnLoad dogodku Open Document zadostuje, da iniciirate in zaključite spremljanje dogodka dokumenta. Prek menijskega ukaza Orodja – Prilagodi in zavihka Dogodki lahko dodelite posamične skripte.

Prestrezanje dogodkov pomaga pri nastavljanju pred- in po-pogojev skriptov, kot je nalaganje in odlaganje knjižnic ali sledenje obdelovanja skripta v ozadju. Uporaba modula Access2Base.Trace ilustrira ta drugi kontekst.

### S Pythonom

Sledenje dogodkom se prične z instanciranjem predmeta in se konča, ko Python predmet sprosti. Poročanje o povzročenih dogodkih poteka prek konzole Access2Base.

Dogodke OnLoad in OnUnload lahko uporabimo za določitev oz. oddoločitev poti programov Python. Opisani sta kot Dokument odprt (ang. Open document) in Dokument zaprt (ang. Document closed).

             # -*- 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):
                 """ Spremljaj dogodke dokumenta """
                 '''
                 prilagojeno iz »Skript Python za spremljanje dogodka OnSave« v
                 https://forum.openoffice.org/en/forum/viewtopic.php?t=68887
                 '''
                 def __init__(self):
                     """ Spremljevalnik dogodkov dokumenta """
                     ''' poročaj z uporabo konzole Access2Base.Trace ALI
                     poročaj v 1. delovnem listu, 1. stolpcu v dokumentih Calc '''
                     ctx = uno.getComponentContext()
                     smgr = ctx.getServiceManager()
                     desktop = smgr.createInstanceWithContext(
                     'com.sun.star.frame.Desktop' , ctx)
                     self.doc = desktop.CurrentComponent
                     #self.row = 0  # odstrani znak komentarja le za dokumente Calc
                     Console.setLevel("DEBUG")
                     self.listen()  # Začni spremljati dogodke dokumenta

                 @property
                 def Filename(self) -> str:
                     sys_filename = uno.fileUrlToSystemPath(self.doc.URL)
                     return os.path.basename(sys_filename)

                 def setCell(self, calcDoc, txt: str):
                     """ Dogodki dokumenta se izpišejo v 1. stolpec preglednice Calc """
                     sheet = calcDoc.getSheets().getByIndex(0)
                     sheet.getCellByPosition(0,self.row).setString(txt)
                     self.row = self.row + 1

                 def listen(self, *args):  # Čimprej OnLoad/OnNew
                     """ Začni spremljati dogodke dokumenta """
                     self.doc.addDocumentEventListener(self)
                     Console.log("INFO", "Dogodki dokumenta se beležijo", True)

                 def sleep(self, *args):  # Čim kasneje OnUnload (neobvezno)
                     """ Prenehaj spremljati dogodke dokumenta """
                     self.doc.removeDocumentEventListener(self)
                     Console.log("INFO", "Dogodki dokumenta so zabeleženi", True)

                 def documentEventOccured(self, event: DocumentEvent):
                     """ Prestrezi vse dogodke dokumenta """
                     #self.setCell(event.Source, event.EventName) # samo za dokumente Calc
                     Console.log("DEBUG",
                         event.EventName+" in "+self.Filename,
                         False)

                 def disposing(self, event: EventObject):
                     """ Sprosti vse dejavnosti """
                     self.sleep()
                     Console.show()

             def OnLoad(*args):  # Dogodek »Odpri dokument«
                 listener = UiDocument()  # Initiates listening

             def OnUnload(*args):  # Dogodek »Dokument se je zaprl«
                 pass  # (neobvezno) izvršeno, ko je zavržen

             g_exportedScripts = (OnLoad,)

             from com.sun.star.script.provider import XScript
             class Console():
                 """
                 konzola v ospredju/ozadju za poročanje/beleženje izvajanja programa.
                 """
                 @staticmethod
                 def trace(*args,**kwargs):
                     """ Izpiši seznam prostih elementov v konzoli """
                     scr = Console._a2bScript(script='DebugPrint', module='Compatible')
                     scr.invoke((args),(),())
                 @staticmethod
                 def log(level: str, text: str, msgBox=False):
                     """ Pripni sporočilo dnevnika v konzolo, neobvezno pobaraj uporabnika """
                     scr = Console._a2bScript(script='TraceLog')
                     scr.invoke((level,text,msgBox),(),())
                 @staticmethod
                 def setLevel(logLevel: str):
                     """ Določi spodnjo mejo beleženja sporočil """
                     scr = Console._a2bScript(script='TraceLevel')
                     scr.invoke((logLevel,),(),())
                 @staticmethod
                 def show():
                     """ Prikaži vsebino/pogovorno okno konzole """
                     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

Bodite pozorni na napačno črkovanje metode documentEventOccured, ki deduje tipkarsko napako iz vmesnika API LibreOffice.

Dogodka Zaženi program (angl. Start application) in Zapri program (angl. Close application) lahko uporabljamo za določitev oz. preklic poti Python za skripte uporabnika ali LibreOffice. Na analogen način lahko knjižnice ali module Python na temelju dokumenta naložimo in sprostimo z uporabo dogodkov Odpri dokument (angl. Open document) in Zapri dokument (angl. Document closed). Za podrobnosti glejte Uvažanje modulov Python.

### Z LibreOffice Basicom

Skript Onload je dodeljen dogodku Open document prek menijskega ukaza Orodja – Prilagodi, zavihka Dogodki. Spremljanje dogodkov se prične s trenutkom, ko je inicializiran predmet ConsoleLogger, in se povsem konča, ko ga pogon Basic sprosti. Dogodek OnLoad naloži potrebne knjižnice Basic, medtem ko o ujetih dogodkih poroča z uporabo modula Access2Base.Trace.

              REM Modul controller.Events
              Option Explicit
              Private _obj As Object ' instanca controller.ConsoleLogger

              	Sub OnLoad(evt As com.sun.star.document.DocumentEvent) ' >> Odpri dokument <<
                  _obj = New ConsoleLogger : _obj.Start(evt)
              End Sub ' controller.OnLoad
              ' ----
              REM Modul razredov controller.ConsoleLogger
              Option Explicit
              Option Compatible
              Option ClassModule

              ' predmet vzorca oblikovanja ADAPTER, ki bo instanciiran v dogodku »Odpri dokument«
              Private Const UI_PROMPT = True
              Private Const UI_NOPROMPT = False ' Set it to True to visualise documents events

              ' KONSTRUKTOR/DESTRUKTOR
              Private Sub Class_Initialize()
              End Sub ' controller.ConsoleLogger.Initialize
              Private Sub Class_Terminate()
              End Sub ' controller.ConsoleLogger.Terminate

              ' ČLANI
              Private _evtAdapter As Object ' com.sun.star.document.XDocumentEventBroadcaster

              ' PROPERTIES
              Private Property Get FileName As String
                  ''' Sistemsko-odvisno ime datoteke '''
                  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

              ' METODE
              Private Sub _documentEventOccured(evt As com.sun.star.document.DocumentEvent)
                  ''' Spremljaj dogodke dokumenta '''
                  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)
                  ''' Inicializiraj beleženje dogodkov dokumenta '''
                  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 & "-") & "Dogodki dokumenta se beležijo", _
                      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)
                  ''' Zaključi beleženje dogodkov dokumenta '''
                  ThisComponent.removeDocumentEventListener( _evtAdapter )
                  Access2Base.Trace.TraceLog("INFO", _
                      IIf(IsMissing(evt),"",evt.EventName & "-") & "Dogodki dokumenta so zabeleženi", _
                      UI_PROMPT)
                  Access2Base.Trace.TraceConsole() ' Captured events dialog
              End Sub ' controller.ConsoleLogger._Stop

              ' EVENTS
              ' Tukaj sledi vaša koda za obravnavane dogodke

Bodite pozorni na napačno črkovanje metode documentEventOccured, ki deduje tipkarsko napako iz vmesnika API LibreOffice.

## Odkrivanje dogodkov dokumentov

Predmet oddajalnika API ponuja seznam dogodkov, za katere je odgovoren:

### S Pythonom

             # -*- coding: utf-8 -*-
             from __future__ import unicode_literals

             import uno, apso_utils as ui

             def displayAvailableEvents():
                 """ Pokaži dogodke dokumenta """
                 '''
                 prirejeno po DisplayAvailableEvents(), ki ga je napisal 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,)

Razširitev APSO (Alternative Python Script Organizer) se uporablja za upodobitev podatkov o dogodkih na zaslonu.

### Z LibreOffice Basicom

             Sub DisplayAvailableEvents
                 ''' Pokaži dogodke dokumenta '''
                 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

Podobne teme

Ustvarjanje poslušalcev dogodkov

Uvažanje modulov Python

Ustvarjanje krmilnikov pogovornih oken

Primeri programov v Pythonu

Programiranje s skripti Python

Klicanje makrov Basic s Pythonom