Calc(52)追加できるリスナー一覧: その4

2017-12-30

旧ブログ

t f B! P L
リスナーがどのタイミングで発火するのかよくわからなかったので、Calc(51)追加できるリスナー一覧: その3の各リスナーのメソッドについて発火したらログファイルを出力するマクロを作成しました。
(2018.1.3追記Calc(52)追加できるリスナー一覧: その4で作り直しました。)

前の関連記事:Calc(51)追加できるリスナー一覧: その3


リスナーのメソッドが発火したらログファイルを出力するマクロ


このマクロを起動したらその後リスナーのメソッドが発火するたびにこのマクロファイルがあるフォルダにログファイルを出力します。

埋め込みマクロをにしているときは埋め込んだドキュメントのフォルダに出力します。

20171230T113317_88doc_documenteventlistener_documentEventOccured_OnTitleChanged.log

マクロファイルの起動年月日T時分秒_発火順リスナーが追加されているオブジェクト_リスナー名_発火メソッド名_イベント名など.log

ログファイル名はこのようになっています。

発火順は桁揃えが面倒なので10番から始まるようにしています。

最後の要素の「イベント名など」はenum名やイベント名などリスナーの種類によってあったりなかったりします。

ログファイル内に書き出している内容はリスナーによってそれぞれです。
#!/opt/libreoffice5.4/program/python
# -*- coding: utf-8 -*-
import unohelper  # オートメーションには必須(必須なのはuno)。
import os
import inspect
from datetime import datetime
from com.sun.star.awt import XEnhancedMouseClickHandler
from com.sun.star.awt import XKeyHandler
from com.sun.star.view import XSelectionChangeListener
from com.sun.star.view import XPrintJobListener
from com.sun.star.view.PrintableState import JOB_STARTED, JOB_COMPLETED, JOB_SPOOLED, JOB_ABORTED, JOB_FAILED, JOB_SPOOLING_FAILED  # enum 
from com.sun.star.util import XCloseListener
from com.sun.star.util import XModifyListener
from com.sun.star.util import XChangesListener
from com.sun.star.frame import XTerminateListener
from com.sun.star.frame import XFrameActionListener
from com.sun.star.frame import XTitleChangeListener
from com.sun.star.frame import XBorderResizeListener
from com.sun.star.frame.FrameAction import COMPONENT_ATTACHED, COMPONENT_DETACHING, COMPONENT_REATTACHED, FRAME_ACTIVATED, FRAME_DEACTIVATING, CONTEXT_CHANGED, FRAME_UI_ACTIVATED, FRAME_UI_DEACTIVATING  # enum
from com.sun.star.document import XDocumentEventListener
from com.sun.star.document import XEventListener
from com.sun.star.document import XStorageChangeListener
from com.sun.star.sheet import XActivationEventListener
from com.sun.star.chart import XChartDataChangeEventListener
from com.sun.star.chart.ChartDataChangeType import ALL, DATA_RANGE, COLUMN_INSERTED, ROW_INSERTED, COLUMN_DELETED, ROW_DELETED  # enum
def macro(documentevent=None):  # 引数は文書のイベント駆動用。OnStartAppでもDocumentEventが入るがSourceはNoneになる。# import pydevd; pydevd.settrace(stdoutToServer=True, stderrToServer=True)  # デバッグサーバーを起動していた場合はここでブレークされる。import pydevdは時間がかかる。
 doc = XSCRIPTCONTEXT.getDocument() if documentevent is None else documentevent.Source  # ドキュメントのモデルを取得。 
 path = doc.getURL() if __file__.startswith("vnd.sun.star.tdoc:") else __file__  # このスクリプトのパス。fileurlで返ってくる。埋め込みマクロの時は埋め込んだドキュメントのURLで代用する。
 thisscriptpath = unohelper.fileUrlToSystemPath(path)  # fileurlをsystempathに変換。
 dirpath = os.path.dirname(thisscriptpath)  # このスクリプトのあるディレクトリのフルパスを取得。
 desktop = XSCRIPTCONTEXT.getDesktop()  # デスクトップの取得。
 desktop.addTerminateListener(TerminateListener(dirpath, "desktop_terminatelistener"))  # TerminateListenerは使い終わったらremoveしないと問題が起こる。
 desktop.addFrameActionListener(FrameActionListener(dirpath, "desktop_frameactionlistener"))  # FrameActionListener
 controller = doc.getCurrentController()  # コントローラーの取得。
 frame = controller.getFrame()  # フレームの取得。
 frame.addFrameActionListener(FrameActionListener(dirpath, "frame_frameactionlistener"))  # FrameActionListener 
 frame.addCloseListener(CloseListener(dirpath, "frame_closelistener"))  # CloseListener
 frame.addTitleChangeListener(TitleChangeListener(dirpath, "frame_titlechangelistener"))  # TitleChangeListener
 controller.addActivationEventListener(ActivationEventListener(dirpath, "controller_activationeventlistener"))  # ActivationEventListener
 controller.addEnhancedMouseClickHandler(EnhancedMouseClickHandler(dirpath, "controller_enhancedmouseclickhandler"))  # EnhancedMouseClickHandler
 controller.addSelectionChangeListener(SelectionChangeListener(dirpath, "controller_selectionchangelistener"))  # SelectionChangeListener
 controller.addBorderResizeListener(BorderResizeListener(dirpath, "controller_borderresizelistener"))  # BorderResizeListener
 controller.addTitleChangeListener(TitleChangeListener(dirpath, "controller_titlechangelistener"))  # TitleChangeListener 
 controller.addKeyHandler(KeyHandler(dirpath, "controller_keyhandler"))  # KeyHandler  
 doc.addDocumentEventListener(DocumentEventListener(dirpath, "doc_documenteventlistener"))  # DocumentEventListener 
 doc.addEventListener(EventListener(dirpath, "doc_eventlistener"))  # EventListener 
 doc.addModifyListener(ModifyListener(dirpath, "doc_modifylistener"))  # ModifyListener  
 doc.addPrintJobListener(PrintJobListener(dirpath, "doc_printjoblistener"))  # PrintJobListener 
 doc.addStorageChangeListener(StorageChangeListener(dirpath, "doc_storagechangelistener"))  # StorageChangeListener 
 doc.addTitleChangeListener(TitleChangeListener(dirpath, "doc_titlechangelistener"))  # TitleChangeListener
 doc.addChangesListener(ChangesListener(dirpath, "doc_changelistener"))  # ChangesListener 
 sheet = controller.getActiveSheet()  # アクティブシートを取得。
 sheet.addChartDataChangeEventListener(ChartDataChangeEventListener(dirpath, "sheet_chartdatachangeeventlistener"))  # ChartDataChangeEventListener 
 sheet.addModifyListener(ModifyListener(dirpath, "sheet_modifylistener"))  # ModifyListener 
 cell = sheet["A1"]  # セルの取得。
 cell.addChartDataChangeEventListener(ChartDataChangeEventListener(dirpath, "cell_chartdatachangeeventlistener"))  # ChartDataChangeEventListener  
 cell.addModifyListener(ModifyListener(dirpath, "cell_modifylistener"))  # ModifyListener
 cells = sheet["A2:C4"]  # セル範囲の取得。
 cells.addChartDataChangeEventListener(ChartDataChangeEventListener(dirpath, "cells_chartdatachangeeventlistener"))  # ChartDataChangeEventListener 
 cells.addModifyListener(ModifyListener(dirpath, "cells_modifylistener"))  # ModifyListener 
class ChartDataChangeEventListener(unohelper.Base, XChartDataChangeEventListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
  enums = ALL, DATA_RANGE, COLUMN_INSERTED, ROW_INSERTED, COLUMN_DELETED, ROW_DELETED  # enum
  chartdatachangetypenames = "ALL", "DATA_RANGE", "COLUMN_INSERTED", "ROW_INSERTED", "COLUMN_DELETED", "ROW_DELETED"
  self.args = dirpath, name, zip(enums, chartdatachangetypenames)
 def chartDataChanged(self, chartdatachangeevent):
  dirpath, name, chartdatachangetypes = self.args
  chartdatachangetype = chartdatachangeevent.Type
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  for enum, chartdatachangetypename in chartdatachangetypes:
   if chartdatachangetype==enum:
    methodname = "_".join((name, inspect.currentframe().f_code.co_name, chartdatachangetypename))  # ChartDataChangeType名を追加。
    createLog(dirpath, methodname, "ChartDataChangeType: {}".format(chartdatachangetypename))
    return
 def disposing(self, eventobject):
  pass  
class ChangesListener(unohelper.Base, XChangesListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def changesOccurred(self, changesevent):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "Changes: {}".format(changesevent.Changes)) 
 def disposing(self, eventobject):
  pass  
class StorageChangeListener(unohelper.Base, XStorageChangeListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def notifyStorageChange(self, document, storage):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "Storage: {}".format(storage)) 
 def disposing(self, eventobject):
  pass   
class PrintJobListener(unohelper.Base, XPrintJobListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
  enums = JOB_STARTED, JOB_COMPLETED, JOB_SPOOLED, JOB_ABORTED, JOB_FAILED, JOB_SPOOLING_FAILED  # enum
  printablestatenames = "JOB_STARTED", "JOB_COMPLETED", "JOB_SPOOLED", "JOB_ABORTED", "JOB_FAILED", "JOB_SPOOLING_FAILED"
  self.args = dirpath, name, zip(enums, printablestatenames)
 def printJobEvent(self, printjobevent):
  dirpath, name, printablestates = self.args
  printablestate = printjobevent.State
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  for enum, printablestatename in printablestates:
   if printablestate==enum:
    methodname = "_".join((name, inspect.currentframe().f_code.co_name, printablestatename))  # State名も追加。
    createLog(dirpath, methodname, "PrintableState: {}, Source: {}".format(printablestatename, printjobevent.Source))
    return
 def disposing(self, eventobject):
  pass  
class ModifyListener(unohelper.Base, XModifyListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def modified(self, eventobject):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "Source: {}".format(eventobject.Source)) 
 def disposing(self, eventobject):
  pass  
class EventListener(unohelper.Base, XEventListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def notifyEvent(self, eventobject):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name, eventobject.EventName))  # イベント名も追加。
  createLog(dirpath, methodname, "EventName: {}, Source: {}".format(eventobject.EventName, eventobject.Source)) 
 def disposing(self, eventobject):
  pass  
class DocumentEventListener(unohelper.Base, XDocumentEventListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def documentEventOccured(self, documentevent):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name, documentevent.EventName))  # イベント名も追加。
  createLog(dirpath, methodname, "EventName: {}, Source: {}".format(documentevent.EventName, documentevent.Source)) 
 def disposing(self, eventobject):
  pass 
class KeyHandler(unohelper.Base, XKeyHandler):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def keyPressed(self, keyevent):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "KeyCode: {}, KeyChar: {}, KeyFunc: {}, Modifiers: {}".format(keyevent.KeyCode, keyevent.KeyChar, keyevent.KeyFunc, keyevent.Modifiers))  
  return False
 def keyReleased(self, keyevent):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "KeyCode: {}, KeyChar: {}, KeyFunc: {}, Modifiers: {}".format(keyevent.KeyCode, keyevent.KeyChar, keyevent.KeyFunc, keyevent.Modifiers))  
  return False  
 def disposing(self, eventobject):
  pass   
class BorderResizeListener(unohelper.Base, XBorderResizeListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def borderWidthsChanged(self, obj, borderwidths):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "Top: {}, Left: {}, Right: {}, Bottom: {}, Object: {}".format(borderwidths.Top, borderwidths.Left, borderwidths.Right, borderwidths.Bottom, obj)) 
 def disposing(self, eventobject):
  pass  
class SelectionChangeListener(unohelper.Base, XSelectionChangeListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def selectionChanged(self, eventobject):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  source = eventobject.Source
  txt = "Selection: {}".format(source.getSelection()) if source.supportsService("com.sun.star.sheet.SpreadsheetView") else "Source: {}".format(source)  # sourceがコントローラーのときは選択しているオブジェクトを書き出す。
  createLog(dirpath, methodname, txt) 
 def disposing(self, eventobject):
  pass 
class EnhancedMouseClickHandler(unohelper.Base, XEnhancedMouseClickHandler):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def mousePressed(self, enhancedmouseevent):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "Buttons: {}, ClickCount: {}, PopupTrigger {}, Modifiers: {}, Target: {}".format(enhancedmouseevent.Buttons, enhancedmouseevent.ClickCount, enhancedmouseevent.PopupTrigger, enhancedmouseevent.Modifiers, enhancedmouseevent.Target)) 
  return True
 def mouseReleased(self, enhancedmouseevent):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "Buttons: {}, ClickCount: {}, PopupTrigger {}, Modifiers: {}, Target: {}".format(enhancedmouseevent.Buttons, enhancedmouseevent.ClickCount, enhancedmouseevent.PopupTrigger, enhancedmouseevent.Modifiers, enhancedmouseevent.Target)) 
  return True
 def disposing(self, eventobject):
  pass
class ActivationEventListener(unohelper.Base, XActivationEventListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def activeSpreadsheetChanged(self, activationevent):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  source = activationevent.Source
  txt = "Selection: {}".format(source.getSelection()) if source.supportsService("com.sun.star.sheet.SpreadsheetView") else "Source: {}".format(source)  # sourceがコントローラーのときは選択しているオブジェクトを書き出す。
  createLog(dirpath, methodname, txt) 
 def disposing(self, eventobject):
  pass
class TitleChangeListener(unohelper.Base, XTitleChangeListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def titleChanged(self, titlechangedevent):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "Title: {}, Source: {}".format(titlechangedevent.Title, titlechangedevent.Source)) 
 def disposing(self, eventobject):
  pass
class CloseListener(unohelper.Base, XCloseListener):
 def __init__(self, dirpath, name):
  self.args = dirpath, name 
 def queryClosing(self, eventobject, getsownership):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "getsownership: {}, Source: {}".format(getsownership, eventobject.Source)) 
 def notifyClosing(self, eventobject):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))
  createLog(dirpath, methodname, "Source: {}".format(eventobject.Source))
 def disposing(self, eventobject):
  pass 
class FrameActionListener(unohelper.Base, XFrameActionListener):
 def __init__(self, dirpath, name):
  enums = COMPONENT_ATTACHED, COMPONENT_DETACHING, COMPONENT_REATTACHED, FRAME_ACTIVATED, FRAME_DEACTIVATING, CONTEXT_CHANGED, FRAME_UI_ACTIVATED, FRAME_UI_DEACTIVATING  # enum
  frameactionnames = "COMPONENT_ATTACHED", "COMPONENT_DETACHING", "COMPONENT_REATTACHED", "FRAME_ACTIVATED", "FRAME_DEACTIVATING", "CONTEXT_CHANGED", "FRAME_UI_ACTIVATED", "FRAME_UI_DEACTIVATING"
  self.args = dirpath, name, zip(enums, frameactionnames)
 def frameAction(self, frameactionevent):
  dirpath, name, frameactions = self.args
  frameaction = frameactionevent.Action
  for enum, frameactionname in frameactions:
   if frameaction==enum:
    methodname = "_".join((name, inspect.currentframe().f_code.co_name, frameactionname))  # Action名も追加。
    createLog(dirpath, methodname, "FrameAction: {}, Source: {}".format(frameactionname, frameactionevent.Source))
    return
 def disposing(self, eventobject):
  pass
class TerminateListener(unohelper.Base, XTerminateListener):  # TerminateListener
 def __init__(self, dirpath, name):  # 出力先ディレクトリのパス、リスナーのインスタンス名。
  self.args = dirpath, name
 def queryTermination(self, eventobject):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))  # このメソッド名を取得。メソッド内で実行する必要がある。
  createLog(dirpath, methodname, "Source: {}".format(eventobject.Source))  # Sourceを出力。
 def notifyTermination(self, eventobject):
  dirpath, name = self.args
  methodname = "_".join((name, inspect.currentframe().f_code.co_name))  # このメソッド名を取得。メソッド内で実行する必要がある。
  createLog(dirpath, methodname, "Source: {}".format(eventobject.Source))  # Sourceを出力。
  desktop = eventobject.Source
  desktop.removeTerminateListener(self)  # TerminateListenerを除去。除去しなmethodname = inspect.currentframe().f_code.co_nameいとLibreOfficeのプロセスが残って起動できなくなる。
 def disposing(self, eventobject):
  pass
C = 10  # カウンターの初期値。
TIMESTAMP = datetime.now().isoformat().split(".")[0].replace("-", "").replace(":", "")  # コピー先ファイル名に使う年月日T時分秒を結合した文字列を取得。
def createLog(dirpath, methodname, txt):  # 年月日T時分秒リスナーのインスタンス名_methodname.logファイルを作成。txtはファイルに書き込むテキスト。dirpathはファイルを書き出すディレクトリ。
 global C
 filename = "".join((TIMESTAMP, "_", str(C), methodname, ".log"))
 C += 1
 with open(os.path.join(dirpath, filename), "w") as f:
  f.write(txt)
g_exportedScripts = macro,  #マクロセレクターに限定表示させる関数をタプルで指定。
EnhancedMouseClickHandlerを使っているので、コントローラーに追加できるリスナーのうちXMouseClickHandlerは使っていません。

ListenersForCalc.ods
このマクロを埋め込んだCalcドキュメントです。

「文書を開いた時」に埋め込みマクロを起動するようにしています。

マクロを有効化してこのドキュメントを起動してドキュメントの操作をすると、リスナーが発火するたびにドキュメントがあるフォルダにログファイルが出力されます。

リスナーのメソッド内にエラーがあってもエラーメッセージウィンドウはでてこないので、発火していないのかどうかは慎重に判断する必要があります。

次の関連記事:Calc(53)追加できるリスナー一覧: その5

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ