LibreOffice(47)オブジェクトからメソッド名一覧を得る

2014-05-01

旧ブログ

t f B! P L

前の関連記事:LibreOffice(46)インターフェイス名からその属性とメソッド名一覧を取得


com.sun.star.beans.Introspectionサービスを使ってオブジェクトからそのメソッド一覧を得るPythonの例をLibreOfficeのprogramフォルダの中のunohelper.pyの中に見つけました。

Introspectionサービスでオブジェクトからメソッド名一覧を得るPythonの例

import uno
from com.sun.star.beans.MethodConcept import ALL as METHOD_CONCEPT_ALL
from com.sun.star.reflection.ParamMode import IN as PARAM_MODE_IN, OUT as PARAM_MODE_OUT, INOUT as PARAM_MODE_INOUT
def libreoffice47():
    obj = XSCRIPTCONTEXT.getDesktop()  # 調べたいオブジェクトをobjに取得。
    ctx = XSCRIPTCONTEXT.getComponentContext()
    introspection = ctx.ServiceManager.createInstanceWithContext("com.sun.star.beans.Introspection", ctx)
    methods = introspection.inspect(obj).getMethods(METHOD_CONCEPT_ALL)  # com.sun.star.reflection.XIDlMethod型のリストが得られる
    for ii in methods:
        txt = "  " + ii.ReturnType.Name + " " + ii.Name
        args = ii.ParameterTypes
        infos = ii.ParameterInfos
        txt = txt + "( "
        for i in range(0, len(args)):
            if i > 0:
                txt = txt + ", "
            txt = txt +  _mode_to_str(infos[i].aMode) + " " + args[i].Name + " " + infos[i].aName
        txt = txt + " )"
        print(txt)
def _mode_to_str(mode):
    ret = "[]"
    if mode == PARAM_MODE_INOUT:
        ret = "[inout]"
    elif mode == PARAM_MODE_OUT:
        ret = "[out]"
    elif mode == PARAM_MODE_IN:
        ret = "[in]"
    return ret
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    libreoffice47()
これをPyCharmから実行すると5行目で指定したオブジェクトについてのメソッド一覧が出力されます。
  any queryInterface( [in] type aType )
  void acquire(  )
  void release(  )
  string getImplementationName(  )
  boolean supportsService( [in] string ServiceName )
  []string getSupportedServiceNames(  )
  com.sun.star.frame.XDispatch queryDispatch( [in] com.sun.star.util.URL URL, [in] string TargetFrameName, [in] long SearchFlags )
  []com.sun.star.frame.XDispatch queryDispatches( [in] []com.sun.star.frame.DispatchDescriptor Requests )
  void registerDispatchProviderInterceptor( [in] com.sun.star.frame.XDispatchProviderInterceptor Interceptor )
  void releaseDispatchProviderInterceptor( [in] com.sun.star.frame.XDispatchProviderInterceptor Interceptor )
まだまだ続く、、、
先頭は戻り値の型を示しています。

「[]」はシークエンスを示し、それに続く型がシークエンスの要素の型になります。

9行目のfor文の中でii.getDeclaringClass().getName()とすると、そのメソッドがあるインターフェイス名が得られました。

さらに、型名からモジュールの部分を省き、シークエンスは[]内に型名が入るようにしたり、com.sun.star.uno.RuntimeException以外の例外も出力するようにしてみました。
import uno
from com.sun.star.beans.MethodConcept import ALL as METHOD_CONCEPT_ALL
from com.sun.star.reflection.ParamMode import IN as PARAM_MODE_IN, OUT as PARAM_MODE_OUT, INOUT as PARAM_MODE_INOUT
def libreoffice47():
    obj = XSCRIPTCONTEXT.getDesktop().getCurrentFrame().getContainerWindow().getToolkit()  # 調べたいオブジェクトをobjに取得。
    ctx = XSCRIPTCONTEXT.getComponentContext()
    introspection = ctx.ServiceManager.createInstanceWithContext("com.sun.star.beans.Introspection", ctx)
    methods = introspection.inspect(obj).getMethods(METHOD_CONCEPT_ALL)  # com.sun.star.reflection.XIDlMethod型のリストが得られる
    for ii in methods:
        txt = ii.getDeclaringClass().getName() + "\n"
        if "[]" in ii.ReturnType.Name:
            txt = txt + "  [" + ii.ReturnType.Name.replace("[]", "") + "] " + ii.Name
        else:
            txt = txt + "  " + ii.ReturnType.Name.rpartition(".")[2] + " " + ii.Name
        args = ii.ParameterTypes
        infos = ii.ParameterInfos
        txt = txt + "("
        for i in range(0, len(args)):
            if i > 0:
                txt = txt + ", "
            if "[]" in args[i].Name:
                txt = txt +  _mode_to_str(infos[i].aMode) + " [" + args[i].Name.rpartition(".")[2] + "] " + infos[i].aName
            else:
                txt = txt +  _mode_to_str(infos[i].aMode) + " " + args[i].Name.rpartition(".")[2] + " " + infos[i].aName
        txt = txt + ")"
        if ii.ExceptionTypes:  # 例外があるとき
            if not ii.ExceptionTypes[0].getName() == "com.sun.star.uno.RuntimeException":  # RuntimeException以外の例外があるとき
                txt = txt + " raises (" + ", ".join([j.Name.rpartition(".")[2] for j in ii.ExceptionTypes]) + ")"
        print(txt)
def _mode_to_str(mode):
    ret = "[]"
    if mode == PARAM_MODE_INOUT:
        ret = "[inout]"
    elif mode == PARAM_MODE_OUT:
        ret = "[out]"
    elif mode == PARAM_MODE_IN:
        ret = "[in]"
    return ret
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    libreoffice47()
今度はツールキットオブジェクトのメソッド一覧を得ています。

メソッド名一覧からオブジェクトのインターフェイス名一覧を得る

import uno
from com.sun.star.beans.MethodConcept import ALL as METHOD_CONCEPT_ALL
from com.sun.star.reflection.ParamMode import IN as PARAM_MODE_IN, OUT as PARAM_MODE_OUT, INOUT as PARAM_MODE_INOUT
def libreoffice47():
    obj = XSCRIPTCONTEXT.getDesktop().getCurrentFrame().getContainerWindow().getToolkit()  # 調べたいオブジェクトをobjに取得。
    ctx = XSCRIPTCONTEXT.getComponentContext()
    introspection = ctx.ServiceManager.createInstanceWithContext("com.sun.star.beans.Introspection", ctx)
    methods = introspection.inspect(obj).getMethods(METHOD_CONCEPT_ALL)  # com.sun.star.reflection.XIDlMethod型のリストが得られる
    output = list()
    for ii in methods:  # 各メソッドについて。
        output.append(ii.getDeclaringClass().getName())  # メソッドが属するインターフェイス名を取得。
    output = list(set(output))  # 重複したインターフェイス名を除く。
    print("\n".join(output))
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    libreoffice47()
これを実行するとobjのオブジェクトから得たメソッド名一覧が入っているインターフェイス名一覧が得られます。

このツールキットのオブジェクトのメソッド一覧から得たインターフェイス名一覧は以下になります。

com.sun.star.awt.XToolkitExperimental
com.sun.star.awt.XSystemChildFactory
com.sun.star.awt.XExtendedToolkit
com.sun.star.awt.XReschedule
com.sun.star.lang.XServiceInfo
com.sun.star.uno.XWeak
com.sun.star.uno.XInterface
com.sun.star.awt.XMessageBoxFactory
com.sun.star.awt.XDataTransferProviderAccess
com.sun.star.lang.XComponent
com.sun.star.lang.XTypeProvider
com.sun.star.awt.XToolkit

さて、このオブジェクトをLibreOffice(44)UNOオブジェクトの属性3:Writerドキュメントに出力で作ったobj_atr()でみると次のような結果になります。

継承している型
        com.sun.star.awt.XToolkit

実装名(implementationName)
        stardiv.Toolkit.VCLXToolkit

使えるサービス(supportedServices)
        com.sun.star.awt.Toolkit

使えるインターフェイス(supportedInterfaces)
com.sun.star.awt.XToolkitExperimental
com.sun.star.lang.XComponent
com.sun.star.lang.XServiceInfo
com.sun.star.lang.XTypeProvider
com.sun.star.uno.XWeak

これらのサービス名とインターフェイス名はobj.getSupportedServiceNames()とobj.getTypes()(の要素の.typeName)のタプルから得られた一覧と一致しました。

メソッド名から得たインターフェイスのうち次のものがありませんね。
com.sun.star.awt.XSystemChildFactory
com.sun.star.awt.XExtendedToolkit
com.sun.star.awt.XReschedule
com.sun.star.uno.XInterface
com.sun.star.awt.XMessageBoxFactory
com.sun.star.awt.XDataTransferProviderAccess
com.sun.star.awt.XToolkit

このオブジェクトはcom.sun.star.awt.Toolkitサービスをサポートしているので、そのAPIリファレンスをみてみるとToolkitサービスはXToolkit2インターフェイスをもっているのがわかります。

抜けていたインターフェイスはすべてXToolkit2インターフェイスに継承されているのがわかります。

なので上の結果で使えるインターフェイスのとこにXToolkit2インターフェイスがあればよいのですが、替わりにXToolkitExperimentalインターフェイスがあって、それがXToolkit2インターフェイスと同じ働きをしています。

このような場合はオブジェクトからインターフェイス名を得てAPIリファレンスをたどってメソッドを探そうと思っても迷子になってしまいそうですね。

インターフェイスを継承しているインターフェイス名やサービス名の取得方法はわからず


継承しているインターフェイスはgetSuperclasses()で得られますが、逆にそのインターフェイスを継承しているインターフェイス名やサービス名を得る方法がわかりませんでした。

うーん、メソッド名からインターフェイス名を得て、そのインターフェイスを継承しているインターフェイスを遡ろうとしたのですができませんでした。
import uno
from com.sun.star.beans.MethodConcept import ALL as METHOD_CONCEPT_ALL
def libreoffice47():
    obj = XSCRIPTCONTEXT.getDesktop().getCurrentFrame().getContainerWindow().getToolkit()  # 調べたいオブジェクトをobjに取得。
    ctx = XSCRIPTCONTEXT.getComponentContext()
    introspection = ctx.ServiceManager.createInstanceWithContext("com.sun.star.beans.Introspection", ctx)
    methods = introspection.inspect(obj).getMethods(METHOD_CONCEPT_ALL)  # com.sun.star.reflection.XIDlMethod型のリストが得られる
    interfaces_list = list()
    for ii in methods:  # 各メソッドのインターフェイス名を重複せずinterfaces_listに取得する。
        if interfaces_list:
            if interfaces_list[-1].Name != ii.getDeclaringClass().Name:  # 直前のインターフェイス名と一致しないとき
                interfaces_list.append(ii.getDeclaringClass())  # メソッドのインターフェイスを取得。
        else:
            interfaces_list.append(ii.getDeclaringClass())  # メソッドのインターフェイスを取得。
    for j in interfaces_list:  # 各インターフェイスについて
        if j.getSuperclasses():  # 継承しているインターフェイスがあるなら
            for k in j.getSuperclasses():
                print(k.Name)  # メソッドのインターフェイスが継承しているインターフェイスを出力。
        print("\t" + j.Name)  # メソッドのインターフェイス名を出力。
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    libreoffice47()
継承しているインターフェイスはこれでたどれますがcom.sun.star.uno.XInterfaceばかりでてきますね。

UNOオブジェクトのタプルはリストに変換できましたが、集合型には変換できないのでif文での重複処理が必要でした。

参考にしたサイト


LibreOffice: Namespace List
LibreOfficeのAPIリファレンス。

次の関連記事:LibreOffice(48)TypeDescriptionManagerシングルトンgetByHierarchicalName()メソッドの戻り値

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ