Monitorar eventos de documentos

Sumário
Índice 🔎︎

# Acompanhar eventos de documento

Acompanhar eventos de documento pode ser útil nas seguintes situações:

- Identificar um novo documento no momento de sua abertura, em contrate a documentos existentes, e executar operações de setup dedicadas.

- Controlar o processamento de salvar, copiar e imprimir documentos, bem como requisições de mala direta.

- Recalcular conteúdos de tabelas, índices ou entradas de tabelas em um documento Writer quando o documento está prestes a ser fechado.

- Importar pacotes matemáticos Python antes de abrir um documento Calc. Descarregar tais pacotes da memória quando o documento é fechado.

Além de atribuir macros a eventos, você pode monitorar eventos ativados por documentos do LibreOffice. Os broadcasters da Application Programming Interface (API) são responsáveis pelas chamadas a macros de eventos. Diferente dos listeners que requerem a definição de todos os métodos suportados, mesmo que não utilizados, a monitoração de documentos requer somente dois métodos além dos scripts de eventos conectados.

## Monitorar eventos de documento

A monitoração é ilustrada abaixo para as linguagens Basic e Python utilizando a programação orientada a objetos. Atribuir o script OnLoad ao evento Abrir documento, é o bastante para iniciar e terminar a monitoração de eventos do documento. A aba Eventos do menu Ferramentas - Personalizar é utilizada para especificar ambos os scripts.

Interceptar eventos ajuda a definir pré e pós-condições tais como carregar e descarregar bibliotecas ou rastrear processamento de scripts que rodam em modo silencioso. O módulo Access2Base.Trace ilustra o segundo contexto.

### Com Python

A monitoração de eventos começa da instanciação do objeto e termina quando o Python libera o objeto. Eventos levantados são reportados utilizando a console do Access2Base.

Os eventos OnLoad e OnUnload podem ser utilizados, respectivamente, para definir ou desfazer a definição de caminhos de programas Python. Eles são descritos como Abrir documento e Documento fechado.

             # -*- 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):
                 """ Monitorar eventos de documento """
                 '''
                 adaptado de 'Python script to monitor OnSave event' de
                 https://forum.openoffice.org/en/forum/viewtopic.php?t=68887
                 '''
                 def __init__(self):
                     """ Monitorar eventos de documento """
                     ''' reportar utilizando a console Access2Base.Trace OU
                     reportar na 1ª planilha, 1ª coluna para documentos do Calc '''
                     ctx = uno.getComponentContext()
                     smgr = ctx.getServiceManager()
                     desktop = smgr.createInstanceWithContext(
                     'com.sun.star.frame.Desktop' , ctx)
                     self.doc = desktop.CurrentComponent
                     #self.row = 0  # descomente somente para documentos do Calc
                     Console.setLevel("DEBUG")
                     self.listen()  # Comece a monitorar eventos de documento

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

                 def setCell(self, calcDoc, txt: str):
                     """ Saída dos eventos de doc na 1ª coluna de uma planilha Calc """
                     sheet = calcDoc.getSheets().getByIndex(0)
                     sheet.getCellByPosition(0,self.row).setString(txt)
                     self.row = self.row + 1

                 def listen(self, *args):  # OnLoad/OnNew o mais cedo
                     """ Começar monitoração de eventos de documento """
                     self.doc.addDocumentEventListener(self)
                     Console.log("INFO", "Os eventos de documento estão sendo registrados", True)

                 def sleep(self, *args):  # OnUnload por último (opcional)
                     """ Encerrar monitoração de eventos de documento """
                     self.doc.removeDocumentEventListener(self)
                     Console.log("INFO", "Os eventos de documento foram registrados", True)

                 def documentEventOccured(self, event: DocumentEvent):
                     """ Interceptar todos os eventos de documento """
                     #self.setCell(event.Source, event.EventName) # somente para documentos do Calc
                     Console.log("DEBUG",
                         event.EventName+" in "+self.Filename,
                         False)

                 def disposing(self, event: EventObject):
                     """ Liberar todas as atividades """
                     self.sleep()
                     Console.show()

             def OnLoad(*args):  # evento 'Abrir documento'
                 listener = UiDocument()  # Inicialização do listener

             def OnUnload(*args):  # evento 'Documento foi fechado'
                 pass  # (opcional) executado quando dispensado

             g_exportedScripts = (OnLoad,)

             from com.sun.star.script.provider import XScript
             class Console():
                 """
                 Console de foreground ou background para reportar ou registrar execução de programa.
                 """
                 @staticmethod
                 def trace(*args,**kwargs):
                     """ Console de foreground ou background para reportar ou registrar execução de programa. """
                     scr = Console._a2bScript(script='DebugPrint', module='Compatible')
                     scr.invoke((args),(),())
                 @staticmethod
                 def log(level: str, text: str, msgBox=False):
                     """ Anexa a mensagem de registro na console, prompt de usuário opcional """
                     scr = Console._a2bScript(script='TraceLog')
                     scr.invoke((level,text,msgBox),(),())
                 @staticmethod
                 def setLevel(logLevel: str):
                     """ Define limite inferior para mensagens de registro """
                     scr = Console._a2bScript(script='TraceLevel')
                     scr.invoke((logLevel,),(),())
                 @staticmethod
                 def show():
                     """ Exibe o conteúdo ou diálogo da console """
                     scr = Console._a2bScript(script='TraceConsole')
                     scr.invoke((),(),())
                 @staticmethod
                 def _a2bScript(script: str, library='Access2Base',
                     module='Trace') -> XScript:
                     ''' Obtém o script Basic baseado na aplicação '''
                     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

Note o erro no nome do método documentEventOccured que herda um erro da LibreOffice Application Programming Interface (API).

Os eventos Inciar aplicação e Fechar aplicação podem ser respectivamente utilizados para definir e cancelar a definição de caminhos Python para scripts de usuários ou scripts do LibreOffice. De forma similar, bibliotecas ou módulos Python baseados em documentos podem ser carregados e descarregados utilizando os eventos Abrir documento e Documento fechado. Consulte Importar módulos Python para mais informações.

### Com LibreOffice Basic

Usando o menu Ferramentas - Personalizar na aba Eventos o evento Ao abrir documento dispara a inicialização do ConsoleLogger. A rotina _documentEventOccured - definida por ConsoleLogger - atua como o único ponto de entrada para capturar todos os eventos de documento.

#### Módulo controller.Events

            Option Explicit

            Global _obj As Object ' Instância de controller.ConsoleLogger

            Sub OnLoad(evt As com.sun.star.document.DocumentEvent) ' >> Abrir documento <<
                _obj = New ConsoleLogger : _obj.StartAdapter(evt)
            End Sub ' controller.OnLoad
            Sub _documentEventOccured(evt As com.sun.star.document.DocumentEvent)
                ''' Ponto de entrada único do ConsoleLogger '''
                 _obj.DocumentEventOccurs(evt)
            End Sub ' controller._documentEventOccured

#### Módulo de classe controller.ConsoleLogger

O monitoramento de eventos se inicia no momento que um objeto ConsoleLogger é instanciado e a finalização do monitoramento ocorre quando o documento é fechado. A rotina StartAdapter carrega as bibliotecas Basic necessárias e os eventos capturados são reportados usando o módulo Access2Base.Trace.

              Option Explicit
              Option Compatible
              Option ClassModule

              ' objeto de padrão de design ADAPTER a ser instanciado no evento "Abrir documento"
              Private Const UI_PROMPT = True
              Private Const UI_NOPROMPT = False ' Defina como True para visualizar os eventos de documento

              ' MEMBROS
              Private _evtAdapter As Object ' com.sun.star.document.XDocumentEventBroadcaster
              Private _txtMsg As String ' Mensagem de texto a registrar no console

              ' PROPRIEDADES
              Private Property Get FileName As String
                  ''' nome de arquivo dependente do Sistema '''
                  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

              ' MÉTODOS
              Public Sub DocumentEventOccurs(evt As com.sun.star.document.DocumentEvent)
                  ''' Monitorar eventos de documento '''
                  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)
                  ''' Inicializar registros de eventos de documento '''
                  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 & "Eventos de documento estão sendo registrados", 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)
                  ''' Encerrar registro de eventos de documento '''
                  ThisComponent.removeDocumentEventListener( _evtAdapter )
                  If IsMissing(evt) Then _txtMsg = "" Else _txtMsg = evt.EventName & "-"
                  Access2Base.Trace.TraceLog("INFO", _txtMsg & "Eventos de documento foram registrados", UI_PROMPT)
                  Access2Base.Trace.TraceConsole() ' Diálogo com os eventos capturados
              End Sub ' controller.ConsoleLogger._StopAdapter

              ' EVENTOS
              ' Seu código para tratar eventos segue aqui

Note o erro no nome do método documentEventOccured que herda um erro da LibreOffice Application Programming Interface (API).

## Descobrir eventos de documento

O objeto API broadcaster fornece a lista de eventos dos quais é responsável:

### Com Python

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

             import uno, apso_utils as ui

             def displayAvailableEvents():
                 """ Exibe eventos de documento """
                 '''
                 adaptado de DisplayAvailableEvents() por 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,)

A extensão Alternative Python Script Organizer (APSO) é utilizada para mostrar informações de eventos na tela.

### Com LibreOffice Basic

             Sub DisplayAvailableEvents
                 ''' Exibe eventos de documento '''
                 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

Tópicos relacionados

Criar listeners de evento

Importar módulos Python

Criar um manipulador de caixa de diálogo

Exemplos de programação em Python

Programando com scripts Python

Chamar macros Basic pelo Python