-
-
Save p--q/be1849ca738ad4ae0c42 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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を設定。 | |
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番の要素に取得。 | |
yield "".join(branch).encode() # 枝をつけてメソッドを出力。 | |
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番の要素に「,」を取得。 | |
yield "".join(branch).encode() # 枝をつけてメソッド名とその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番の要素に「,」を取得。 | |
yield "".join(branch).encode() # 枝をつけて引数を出力。 | |
del branch[2:] # branchの2番以上の要素は破棄する。 | |
t_ex = j.Exceptions # 例外を取得。 | |
if t_ex: # 例外があるとき。 | |
yield "".join(branch).encode() # 最後の引数を出力。 | |
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: # まだ次の例外があるとき。 | |
yield ("".join(branch) + ",").encode() # 「,」をつけて出力。 | |
else: # 最後の要素のとき。 | |
yield ("".join(branch) + ")").encode() # 閉じ括弧をつけて出力。 | |
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: # 例外がないとき。 | |
yield ("".join(branch) + ")").encode() # 閉じ括弧をつけて最後の引数を出力。 | |
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インターフェイスをもつオブジェクトのタプルを取得。 | |
yield "".join(branch).encode() # 枝をつけて出力。 | |
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]) # サービス属性の型のうち最大文字数を取得。 | |
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