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

2017-12-29

旧ブログ

t f B! P L
サービスとインターフェイス一覧からそれぞれのオブジェクトに対して追加できるリスナーのインターフェイスを調べました。よく理解できないものがいくつかありました。まずデスクトップに追加できるリスナーについてやります。

前の関連記事:Calc(48)ドキュメントイベントを調べる


デスクトップに追加できるリスナーの一覧


LibreOffice5(95)デスクトップのサービスとインターフェイスの一覧から探したものです。

XTerminateListener

デスクトップを終了する間際と終了時に発火するメソッドがあります(Using the Desktop - Apache OpenOffice Wiki)。

このリスナーはLibreOfficeが終了するときに除去しないと、次にLibreOfficeが起動しなくなってしまいました。

linuxBean14.04のタスクマネージャでみてみるとLibreOffice終了後にCPU使用率が100%になって、soffice.binのプロセスが残ったままになっていました。

この状態でLibreOfficeを起動しようとするとスプラッシュ画面のまま動きませんでした。

タスクマネージャではsoffice.binが二つになっていました。

終了しているはずのsoffice.binを強制終了にするとLibreOfficeが起動できるようになりました。

XFrameActionListener

enumのFrameActionにあるイベントが発生した時にframeAction()メソッドが発火します(Frames - Apache OpenOffice Wiki)。

発火させたイベントはframeAction()メソッドの引数のFrameActionEvent StructのActionアトリビュートにenumのFrameActionが入っていることで判別できます。

しかし、下のマクロでやったように、デスクトップはフレームそのものではないせいか、このリスナーのメソッドを発火させる状況は見つけられませんでした。

XPropertyChangeListener
XVetoableChangeListener

これらのインターフェイスのメソッドはそれぞれboundプロパティとconstrainedプロパティが変更された時に発火されます。

しかしboundプロパティとconstrainedプロパティが存在しないようですので使う機会はなさそうです(OOobbs2/84 - ...?)。

Defining a Service - Apache OpenOffice Wikiにプロパティの種類一覧があります。 

いまのところAPIリファレンスをみてもほとんどがoptionalプロパティかreadonlyプロパティです。

テキストカーサーのParagraphProperties Serviceにようやくmaybevoidプロパティをみつけました。

XPropertiesChangeListener

これは複数のboundプロパティの変更に応じて(or?and?order?)発火するメソッドがありますが、これもboundプロパティがないオブジェクトでは意味がありません。

以下はデスクトップ自身がリスナーになっているインターフェイスです。

XDispatchResultListener
XEventListener

リスナーをみても具体的にどのオブジェクトにリスナーとして追加されているのかはわかりません。

XDispatchResultListenerでディスパッチコマンドの結果を受け取っているようです。

XEventListenerはリスナーが実装しておかないといけない必須メソッドのdisposing()です。

デスクトップに追加できるリスナーのマクロの例

#!/opt/libreoffice5.4/program/python
# -*- coding: utf-8 -*-
import unohelper  # オートメーションには必須(必須なのはuno)。
import os
import inspect
from datetime import datetime
from com.sun.star.frame import XTerminateListener
from com.sun.star.frame import XFrameActionListener
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
def macro(documentevent=None):  # 引数は文書のイベント駆動用。OnStartAppでもDocumentEventが入る。LibreOfficeに保存する。
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 thisscriptpath = unohelper.fileUrlToSystemPath(__file__)  # __file__はfileurlで返ってくるのでシステムパスに変換。
 dirpath = os.path.dirname(thisscriptpath)  # このスクリプトのあるディレクトリのフルパスを取得。
 desktop = ctx.getByName('/singletons/com.sun.star.frame.theDesktop')  # com.sun.star.frame.Desktopはdeprecatedになっている。
 desktop_terminatelistener = TerminateListener(dirpath, "desktop_terminatelistener")  # TerminateListener
 desktop.addTerminateListener(desktop_terminatelistener)  # 使い終わったらremoveしないといけない。
 desktop_frameactionlistener = FrameActionListener(dirpath, "desktop_frameactionlistener")  # FrameActionListener
 desktop.addFrameActionListener(desktop_frameactionlistener)  # いつ呼ばれる?
class FrameActionListener(unohelper.Base, XFrameActionListener):  # FrameActionListener
 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))  # このメソッド名を取得。メソッド内で実行する必要がある。
    createLog(dirpath, methodname, "frameactionevent.FrameAction(enum): {}".format(frameactionname))  # frameactionのenum名を出力。
    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, "eventobject.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, "eventobject.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
def createLog(dirpath, methodname, txt):  # 年月日T時分秒リスナーのインスタンス名_methodname.logファイルを作成。txtはファイルに書き込むテキスト。dirpathはファイルを書き出すディレクトリ。
 timestamp = datetime.now().isoformat().split(".")[0].replace("-", "").replace(":", "")  # コピー先ファイル名に使う年月日T時分秒を結合した文字列を取得。
 filename = "".join((timestamp, methodname, ".log"))
 with open(os.path.join(dirpath, filename), "w") as f:
  f.write(txt) 
g_exportedScripts = macro,  #マクロセレクターに限定表示させる関数をタプルで指定。 
このマクロファイルをマイマクロフォルダに置きます。

XTerminateListenerXFrameActionListenerのメソッドが発火すると、マクロファイルがあるフォルダに発火した年月日T時分秒リスナーのインスタンス名_methodname.logというファイル名のテキストファイルを出力するようにしています。

リスナーのメソッドが発火するイベントが発生する前にこのマクロを起動しておくようにします。

ツール→カスタマイズ、イベントタブ。


一番最初に起動されると思われる「アプリケーションの開始時」にこのマクロを割り当てました。

保存先は「LibreOffice」にしておかないといけません。

保存先をドキュメントにすると「アプリケーションの開始時」に割り当てたマクロは実行されませんでした。

「アプリケーションの開始時」にはドキュメントはロードされていないので当然のことかもしれません。

なので、マクロの引数のDocumentEvent StructのSourceアトリビュートに入っているのもドキュメントモデルではなくNoneが入っていました。

「アプリケーションの開始時」に実行するマクロで新規作成されたドキュメントを取得しようとしましたが、そのマクロが終わってからしかドキュメントが作成されないようで、それはうまくいきませんでした。

ちなみにUNOのStructはHashableでないということで、Pythonの辞書のキーにはできませんでした。

「アプリケーションの開始時」に登録したマクロは不要になったら忘れずに削除しておかないと、永遠と動き続けることになります。

デスクトップのリスナーが発火するとき


上記の設定後LibreOfficeを起動したときからデスクトップに追加したXTerminateListenerXFrameActionListenerかのメソッドが発火するとマイマクロフォルダに置いたマクロファイルと同じフォルダに発火した年月日T時分秒リスナーのインスタンス名_methodname.logというテキストファイルが作成されます。


LibreOfficeを終了するときにXTerminateListenerのnotifyTermination、queryTerminationという順で発火していることがわかりました。

XFrameActionListenerのメソッドが発火するときはいまのところわかりませんでした。

おそらくデスクトップでは発火しないと思います。

結局デスクトップで発火するリスナーはLibreOfficeを終了するときだけのようですので、どのタイミングでこのマクロを開始しても同じ結果になります。

参考にしたサイト


Using the Desktop - Apache OpenOffice Wiki
XTerminateListenerのメソッドの解説。

Frames - Apache OpenOffice Wiki
Frame Actionsの解説。

OOobbs2/84 - ...?
XPropertyChangeListenerやXVetoableChangeListenerが発火するboundプロパティやconstrainedプロパティはデスクトップにはありませんでした。

Defining a Service - Apache OpenOffice Wiki
old-style Serviceのプロパティの種類の解説。

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

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ