Skip to content

Instantly share code, notes, and snippets.

@p--q
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save p--q/be1849ca738ad4ae0c42 to your computer and use it in GitHub Desktop.
Save p--q/be1849ca738ad4ae0c42 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
def libreoffice55():
# obj = XSCRIPTCONTEXT.getDocument() # 調査対象のオブジェクトを取得。old-styleサービスの例。LibreOfficeドキュメントを開いておく必要がある。
obj = XSCRIPTCONTEXT.getDesktop().getCurrentFrame().getContainerWindow().getToolkit() # 調査対象のオブジェクトを取得。new-styleサービスの例。
# obj = XSCRIPTCONTEXT.getComponentContext() # 調査対象のオブジェクトを取得。サービスがないオブジェクトの例。
ObjInsp(obj)
class ObjInsp:
def __init__(self, obj):
self.obj = obj
from wsgiref.simple_server import make_server
import webbrowser
host, port = "localhost", 8000
server = make_server(host, port, self.app) # appへの接続を受け付けるWSGIサーバを生成。
url = "http://{}:{}".format(host, port) # 出力先のurlを取得。
webbrowser.open_new_tab(url) # デフォルトのブラウザでurlを開く。
server.handle_request() # リクエストを1回だけ受け付けたらサーバを終了させる。
def app(self, environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html; charset=utf-8')]) # start_responseを設定。
lst_html = ["<tt>"] # WSGIサーバへ返すリスト。等幅フォントで出力する開始タグを0番要素に入れておく。
from com.sun.star.uno.TypeClass import SERVICE, INTERFACE, PROPERTY, INTERFACE_METHOD, INTERFACE_ATTRIBUTE
tdm = XSCRIPTCONTEXT.getComponentContext().getByName('/singletons/com.sun.star.reflection.theTypeDescriptionManager') # TypeDescriptionManagerをシングルトンでインスタンス化。
st_omi = {'.uno.XInterface', '.uno.XWeak', '.lang.XTypeProvider'} # 結果を出力しないインターフェイス名の集合。'com.sun.star.uno.XInterface'は必ず指定が必要。
stack = list() # スタック。
if hasattr(self.obj, "getSupportedServiceNames"): # オブジェクトがサービスを持っているとき。
st_ss = set(self.obj.getSupportedServiceNames()) # オブジェクトのサポートサービス名一覧の集合を得る。
st_sups = set() # 親サービスを入れる集合。
if len(st_ss) > 1: # サポートしているサービス名が複数ある場合。
stack = [tdm.getByHierarchicalName(i) for i in st_ss] # サポートサービスのTypeDescriptionオブジェクトをスタックに取得。
while stack: # スタックがある間実行。
j = stack.pop() # サービスのTypeDescriptionオブジェクトを取得。
t_std = j.getMandatoryServices() + j.getOptionalServices() # 親サービスのタプルを取得。
lst_std = [i for i in t_std if not i.Name in st_sups] # 親サービスのTypeDescriptionオブジェクトのうち既に取得した親サービスにないものだけを取得。
stack.extend(lst_std) # スタックに新たなサービスのTypeDescriptionオブジェクトのみ追加。
st_sups.update([i.Name for i in lst_std]) # 既に取得した親サービス名の集合型に新たに取得したサービス名を追加。
st_ss.difference_update(st_sups) # オブジェクトのサポートサービスのうち親サービスにないものだけにする=これがサービスの末裔。
stack = [tdm.getByHierarchicalName(i) for i in st_ss] # TypeDescriptionオブジェクトに変換。
if stack: stack.sort(key=lambda x: x.Name, reverse=True) # Name属性で降順に並べる。
else: # サポートしているサービスがないときはインターフェイス名一覧を得る。
if hasattr(self.obj, "getTypes"): # サポートしているインターフェイスがある場合。
st_si = set([i.typeName.replace("com.sun.star", "") for i in self.obj.getTypes()]) # サポートインターフェイス名を集合型で取得。
lst_si = sorted(list(st_si.difference(st_omi)), reverse=True) # 除外するインターフェイス名を除いて降順のリストにする。
stack = [tdm.getByHierarchicalName("com.sun.star" + i) for i in lst_si] # TypeDescriptionオブジェクトに変換。"com.sun.star"が必要。
if stack: # 起点となるサービスかインターフェイスがあるとき。
lst_level = [0 for i in stack] # stackの要素すべてについて階層を取得。
indent = " " # インデントを設定。
m = 0 # 最大文字数を初期化。
inout_dic = {(True, False): "[in]", (False, True): "[out]", (True, True): "[inout]"} # メソッドの引数のinout変換辞書。
while stack: # スタックがある間実行。
j = stack.pop() # スタックからTypeDescriptionオブジェクトをpop。
level = lst_level.pop() # jの階層を取得。
typcls = j.getTypeClass() # jのタイプクラスを取得。
branch = ["", ""] # 枝をリセット。jがサービスまたはインターフェイスのときjに直接つながる枝は1番の要素に入れる。それより左の枝は0番の要素に加える。
t_itd = tuple() # インターフェイスのTypeDescriptionオブジェクトの入れ物を初期化。
t_spd = tuple() # サービス属性のTypeDescriptionオブジェクトの入れ物を初期化。
t_md = tuple() # メソッドのTypeDescriptionオブジェクトの入れ物を初期化。
if level > 1: # 階層が2以上のとき。
for i in range(1, level): # 階層iから出た枝が次行の階層i-1の枝になる。
branch[0] += "│ " if i in lst_level else indent # iは枝の階層ではなく、枝のより上の行にあるその枝がでた階層になる。
if typcls == INTERFACE or typcls == SERVICE: # jがサービスかインターフェイスのとき。
if level > 0: branch[1] = "├─" if level in lst_level else "└─" # 階層が1以上のとき。スタックに同じ階層があるときは"├─" 。
else: # jがインターフェイスかサービス以外のとき。
branch[1] = indent # 横枝は出さない。
if level in lst_level: # スタックに同じ階層があるとき。
typcls2 = stack[lst_level.index(level)].getTypeClass() # スタックにある同じ階層のものの先頭の要素のTypeClassを取得。
if typcls2 == INTERFACE or typcls2 == SERVICE: branch[1] = "│ " # サービスかインターフェイスのとき。横枝だったのを縦枝に書き換える。
if typcls == INTERFACE_METHOD: # jがメソッドのとき。
typ = j.ReturnType.Name.replace("com.sun.star", "") # 戻り値の型を取得。
if typ[1] == "]": typ = typ.replace("]", "") + "]" # 属性がシークエンスのとき[]の表記を修正。
stack2 = list(j.Parameters)[::-1] # メソッドの引数について逆順(降順ではない)にスタック2に取得。
if not stack2: # 引数がないとき。
branch.append(typ.rjust(m) + " " + j.MemberName.replace("com.sun.star", "") + "()") # 「戻り値の型(固定幅mで右寄せ) メソッド名()」をbranchの3番の要素に取得。
lst_html.append("".join(branch)) # 枝をつけてメソッドを出力。
else: # 引数があるとき。
m3 = max([len(i.Type.Name.replace("com.sun.star", "")) for i in stack2]) # 引数の型の最大文字数を取得。
k = stack2.pop() # 先頭の引数を取得。
inout = inout_dic[(k.isIn(), k.isOut())] # 引数の[in]の判定、[out]の判定
typ2 = k.Type.Name.replace("com.sun.star", "") # 引数の型を取得。
if typ2[1] == "]": typ2 = typ2.replace("]", "") + "]" # 引数の型がシークエンスのとき[]の表記を修正。
branch.append(typ.rjust(m) + " " + j.MemberName.replace("com.sun.star", "") + "( " + inout + " " + typ2.rjust(m3) + " " + k.Name.replace("com.sun.star", "")) # 「戻り値の型(固定幅で右寄せ) メソッド名(inout判定 引数の型(固定幅m3で左寄せ) 引数名」をbranchの3番の要素に取得。
m2 = len(typ.rjust(m) + " " + j.MemberName.replace("com.sun.star", "") + "( ") # メソッドの引数の部分をインデントする文字数を取得。
if stack2: # 引数が複数あるとき。
branch.append(",") # branchの4番の要素に「,」を取得。
lst_html.append("".join(branch)) # 枝をつけてメソッド名とその0番の引数を出力。
del branch[2:] # branchの2番以上の要素は破棄する。
while stack2: # 1番以降の引数があるとき。
k = stack2.pop()
inout = inout_dic[(k.isIn(), k.isOut())] # 引数の[in]の判定、[out]の判定
typ2 = k.Type.Name.replace("com.sun.star", "") # 引数の型を取得。
if typ2[1] == "]": typ2 = typ2.replace("]", "") + "]" # 引数の型がシークエンスのとき[]の表記を修正。
branch.append(" ".rjust(m2) + inout + " " + typ2.rjust(m3) + " " + k.Name.replace("com.sun.star", "")) # 「戻り値の型とメソッド名の固定幅m2 引数の型(固定幅m3で左寄せ) 引数名」をbranchの2番の要素に取得。
if stack2: # 最後の引数でないとき。
branch.append(",") # branchの3番の要素に「,」を取得。
lst_html.append("".join(branch)) # 枝をつけて引数を出力。
del branch[2:] # branchの2番以上の要素は破棄する。
t_ex = j.Exceptions # 例外を取得。
if t_ex: # 例外があるとき。
lst_html.append("".join(branch)) # 最後の引数を出力。
del branch[2:] # branchの2番以降の要素を削除。
n = ") raises ( " # 例外があるときに表示する文字列。
m4 = len(n) # nの文字数。
stack2 = list(t_ex) # 例外のタプルをリストに変換。
branch.append(" ".rjust(m2 - m4)) # 戻り値の型とメソッド名の固定幅m2からnの文字数を引いて2番の要素に取得。
branch.append(n) # nを3番要素に取得。他の要素と別にしておかないとn in branchがTrueにならない。
while stack2: # stack2があるとき
k = stack2.pop() # 例外を取得。
branch.append(k.Name.replace("com.sun.star", "")) # branchの3番(初回以外のループでは4番)の要素に例外名を取得。
if stack2: # まだ次の例外があるとき。
lst_html.append("".join(branch) + ",") # 「,」をつけて出力。
else: # 最後の要素のとき。
lst_html.append("".join(branch) + ")") # 閉じ括弧をつけて出力。
if n in branch: # nが枝にあるときはnのある3番以上のbranchの要素を削除。
del branch[3:]
branch.append(" ".rjust(m4)) # nを削った分の固定幅をbranchの3番の要素に追加。
else:
del branch[4:] # branchの4番以上の要素を削除。
else: # 例外がないとき。
lst_html.append("".join(branch) + ")") # 閉じ括弧をつけて最後の引数を出力。
else: # jがメソッド以外のとき。
if typcls == INTERFACE: # インターフェイスのとき。XInterfaceTypeDescription2インターフェイスをもつTypeDescriptionオブジェクト。
branch.append(j.Name.replace("com.sun.star", "")) # インターフェイス名をbranchの2番要素に追加。
t_itd = j.getBaseTypes() + j.getOptionalBaseTypes() # 親インターフェイスを取得。
t_md = j.getMembers() # インターフェイス属性とメソッドのTypeDescriptionオブジェクトを取得。
elif typcls == PROPERTY: # サービス属性のとき。
typ = j.getPropertyTypeDescription().Name.replace("com.sun.star", "") # 属性の型
if typ[1] == "]": typ = typ.replace("]", "") + "]" # 属性がシークエンスのとき[]の表記を修正。
branch.append(typ.rjust(m) + " " + j.Name.replace("com.sun.star", "")) # 型は最大文字数で右寄せにする。
elif typcls == INTERFACE_ATTRIBUTE: # インターフェイス属性のとき。
typ = j.Type.Name.replace("com.sun.star", "") # 戻り値の型
if typ[1] == "]": typ = typ.replace("]", "") + "]" # 属性がシークエンスのとき[]の表記を修正。
branch.append(typ.rjust(m) + " " + j.MemberName.replace("com.sun.star", "")) # 型は最大文字数で右寄せにする。
elif typcls == SERVICE: # jがサービスのときtdはXServiceTypeDescriptionインターフェイスをもつ。
branch.append(j.Name.replace("com.sun.star", "")) # サービス名をbranchの2番要素に追加。
t_std = j.getMandatoryServices() + j.getOptionalServices() # 親サービスを取得。
stack.extend(sorted(list(t_std), key=lambda x: x.Name, reverse=True)) # 親サービス名で降順に並べてサービスのTypeDescriptionオブジェクトをスタックに追加。
lst_level.extend([level + 1 for i in t_std]) # 階層を取得。
itd = j.getInterface() # new-styleサービスのインターフェイスを取得。TypeDescriptionオブジェクト。
if itd: # new-styleサービスのインターフェイスがあるとき。
t_itd = itd, # XInterfaceTypeDescription2インターフェイスをもつTypeDescriptionオブジェクト。
else: # new-styleサービスのインターフェイスがないときはold-styleサービスのインターフェイスを取得。
t_itd = j.getMandatoryInterfaces() + j.getOptionalInterfaces() # XInterfaceTypeDescriptionインターフェイスをもつTypeDescriptionオブジェクト。
t_spd = j.Properties # サービスからXPropertyTypeDescriptionインターフェイスをもつオブジェクトのタプルを取得。
lst_html.append("".join(branch)) # 枝をつけて出力。
if t_itd: # 親インターフェイスがあるとき。(TypeDescriptionオブジェクト)
lst_itd = [i for i in t_itd if not i.Name.replace("com.sun.star", "") in st_omi] # st_omiを除く。
stack.extend(sorted(lst_itd, key=lambda x: x.Name, reverse=True)) # 降順にしてスタックに追加。
lst_level.extend([level + 1 for i in lst_itd]) # 階層を取得。
st_omi.update([i.Name.replace("com.sun.star", "") for i in lst_itd]) # すでにでてきたインターフェイス名をst_omiに追加して次は使わないようにする。
if t_md: # インターフェイス属性とメソッドがあるとき。
stack.extend(sorted(t_md, key=lambda x: x.Name, reverse=True)) # 降順にしてスタックに追加。
lst_level.extend([level + 1 for i in t_md]) # 階層を取得。
m = max([len(i.ReturnType.Name.replace("com.sun.star", "")) for i in t_md if i.getTypeClass() == INTERFACE_METHOD] + [len(i.Type.Name.replace("com.sun.star", "")) for i in t_md if i.getTypeClass() == INTERFACE_ATTRIBUTE]) # インターフェイス属性とメソッドの型のうち最大文字数を取得。
if t_spd: # サービス属性があるとき。
stack.extend(sorted(list(t_spd), key=lambda x: x.Name, reverse=True)) # 降順にしてスタックに追加。
lst_level.extend([level + 1 for i in t_spd]) # 階層を取得。
m = max([len(i.getPropertyTypeDescription().Name.replace("com.sun.star", "")) for i in t_spd]) # サービス属性の型のうち最大文字数を取得。
lst_html.append("</tt>") # 等幅フォントで出力する終了タグ。
return [(i.replace(" ", "&nbsp;") + "<br>").encode() for i in lst_html] # 半角スペースをHTMLのものに置換して行末に改行タグをつけて、UTF-8エンコーディングをバイト文字列に変換してイテレータで返す。
if __name__ == "__main__":
import unopy
XSCRIPTCONTEXT = unopy.connect()
if not XSCRIPTCONTEXT:
print("Failed to connect.")
import sys
sys.exit(0)
libreoffice55()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment