Skip to content
hanya edited this page Jun 9, 2014 · 5 revisions

Table of Contents

マクロ

MRI には MRI 自身をコントロールするマクロ機能があります。このマクロは Python で書くことができます。

マクロではすべての MRI の機能にアクセスできますが、オフィースがクラッシュするかもしれません。しかし、MRI は一般的なユーザーのためのものではないので、深刻な問題ではありません。

MRI のマクロは MRI の実装に深く関係しています。そのため、MRI の内部構造を知らなければマクロを書くことは難しいでしょう。このドキュメントでは、重要な部分のみ説明しています。詳細については MRI のコードを参照してください。

マクロメニュー

MRI ウィンドウを開いてください。ウィドウのメインメニューに Macros メニュー項目があります。このメニューの項目は動的に作成されます。

マクロは以下のディレクトリに保存されている必要があります。

  • 拡張機能のレポジトリ、これは MRI に付属するものです。
  • ユーザーのレポジトリ、これはメインメニューの Tools - Configuration... から設定できます。
ユーザーのレポジトリでは、アクセス権限を持っているどんなディレクトリでも選択できます。推奨する場所は $(user)/Scripts/python/mri_macros やその他の場所です。

マクロのインポート

MRI マクロが含まれているファイルを持っているなら、それをマクロディレクトリに配置する簡単な方法が用意されています。Macros - bundle.py - Import Macros を選択してください。選択したファイルがユーザーのマクロ用ディレクトリへコピーされます。

マクロファイルが ZIP、tar.gz, tar.bz2 アーカイブに圧縮されている場合、解凍されて内容がインポートされます。また、README ファイルがアーカイブに含まれている場合、インポートされる前にその内容がライセンスダイアログに表示されます。

マクロのリロード

マクロメニューは動的に作成されますが、一旦読み込まれると静的なものになります。マクロレポジトリに変更があった場合、再度読み込んでください。Macros - bundle.py - Reload Macros を選択してください。この項目は既に読み込まれた項目を削除して再度読み込みます。

マクロのファイル形式

マクロは Python で書き、ファイルの拡張子として ".py" をつけ、ユーザーのレポジトリに保存してください。レポジトリについては前出の項目を参照してください。

マクロの種類

MRI で実行できるマクロには二種類あります。一つは、MRI 自身を拡張する簡単なコードです。もうひとつは、記録可能なマクロで、項目に対して行われた操作がコードとして生成されます。このドキュメントでは、前者を「普通のマクロ」と呼び、後者を「アクションマクロ」と呼ぶことにします。

普通のマクロ

普通のマクロの例を示します。

# # hello.py example
# __all__ の項目がマクロメニューに表示されます。
# リスト中の順番は保持され、
# 空の項目は区切り線になります。
__all__ = ["hello_world", "", "another_function"]

def hello_world(mri):
    """ Greeting
        Description of this method """
    # The document string of the function is used to specify 
    # its title and description. First line is used for title of it 
    # and second line is used for description of the function.
    mri.message("Hello World!")

def another_function(mri):
    pass

def private_function(mri):
   """ This function is not shown in the list of function. """
マクロのファイルは imp.load_source 関数でモジュールとして読み込まれます。関数はひとつの引数を取り、それは MRI オブジェクトです。すべての MRI の機能にここからアクセスできます。機能については以下の項目を参照してください。

関数のドキュメント文字列は、メニュー項目または他の場所でタイトルおよびツールチップテキストとして使用されます。

変数はファイルからエクスポートされている関数のリストを取得するために使用されます。前出の例では、hello_world と another_function のみが hello.py 項目のサブ項目として表示され、空の文字列によって指定された区切り線で区切られます。

現在のターゲットを使用する例を示します。ここで呼び出したメソッドはコードジェネレータが記録しません。

def another_example(mri):
   target = mri.current.target # 現在のターゲットの実際の値
   sheets = target.getSheets()
   sheet = sheets.getSheets()
   # To do something

アクションマクロ

アクションマクロは API 呼び出しをコードとして記録できます。Entry のインスタンスを利用して作業する点が普通のマクロとは異なります。履歴に項目がないエントリーを利用する場合、ジェネレータステートメントで履歴に登録してください。

簡単な例を示します。

def action_macro(mri):
    current = mri.current # current is a Writer document object
    text = current.getText()
    cursor = text.createTextCursor()
getText と createTextCursor メソッドの呼び出しと、それらのメソッドの返り値が履歴に自動的に登録されます。

サービスのインスタンスなど、新しいインスタンスで作業する場合、履歴に登録してください。

def macro_test(mri):
    current = mri.current
    transformer = mri.create_service(
        "com.sun.star.util.URLTransformer")
    yield current, transformer
ジェネレータは親エントリーと履歴に登録したいエントリーのタプルを返さなければいけません。最初の要素は履歴に登録されている親エントリーでなければいけません。

アクションマクロとそれを利用するコードジェネレータには様々な制限があります。例えば、リスナーのような独自の UNO コンポーネントはアクションマクロで利用できません。

MRI オブジェクト

すべてのマクロは現在の MRI インスタンスを最初の引数として受け取ります。その値は、MRI のコアプログラムです。MRI インスタンスはユーザーインターフェースをサポートしていません。MRI のウィンドウは ui インスタンス変数を通じてアクセスできます。

インスタンス変数

MRI インスタンスはインスタンス変数に様々な値を保持しています。

変数 説明
ctx pyuno コンポーネントコンテキスト。
config mytools_Mri.config.Config 設定
web mytools_Mri.web.IDL ウェブページを開くウェブブラウザクラス。
engine mytools_Mri.engine.Engine イントロスペクションとリフレクション。
history mytools_Mri.node.Root 履歴階層。
current mytools_Mri.engine.Entry 現在のエントリー。
cg mytools_Mri.cg.CodeGenerator コードジェネレータの管理。
mode bool ノーマルモードで True、False でマクロモード。
open_new bool True の場合、次のターゲットは新しい MRI で開きます。
macros mytools_Mri.macros.Macros マクロの管理。
ui mytools_Mri.ui.MRIUi UI インスタンス。

メソッド

以下のメソッドは Entry のインスタンスを返し、メソッドの呼び出しに応じてコードのエントリーを生成します。

 get_component_context() -> Entry

コンポーネントコンテキストを返します。

 assign_element(k, value, append=False) -> None

現在のシークエンスに要素を設定します。この関数は Entry のインスタンスの [] メソッドによって呼び出されます。

 create_service(name, *args, **kwds) -> Enry | pyuno

名前で指定されたサービスのインスタンスを返します。nocode=True が指定された場合、サービスのインスタンスの pyuno オブジェクトが返されます。

 create_struct(name, *args, **kwds) -> Entry | pyuno

名前で指定された構造体の新しいインスタンスを返します。nocode=True が指定された場合、構造体のオブジェクトが返されます。

 create_sequence(type_name, length, var=None) -> Entry

型名と長さを指定して作成された新しいシークエンスを返します。

 declare_variable(type_name, value) -> Entry

指定した名前で変数を生成してコードにエントリーを追加します。

ComponentContext

MRI は ctx インスタンス変数に css.uno.XComponentContext インターフェースを保持しています。新しい UNO サービスのインスタンスを作成するために使用できます。

現在のエントリー

MRI keeps current target in current instance variable, which is instance of mytools_Mri.engine.Entry class.

Engine オブジェクト

エンジンは UNO オブジェクトの情報を取得するためのコアオブジェクトです。css.beans.Introspection, css.reflection.CoreReflection および css.reflection.TypeDescription サービスを使用しており、mytools_Mri.engine.Engine クラスで実装されています。エンジンのインスタンスは MRI のエンジンインスタンス変数からアクセスできます。

def use_engine(mri):
    """ Shows type name of the current target. """
    engine = mri.engine
    current = mri.current
    mri.ui.message(engine.get_type_name(current))

Web オブジェクト

ウェブオブジェクトは設定でユーザーの指定したウェブブラウザで上生ページを開く手助けをしてくれます。mytools_Mri.web.IDL クラスで実装されています。

def open_url(mri):
    """ Allows to open any URL in your web browser. """
    url = "http://example.com/"
    mri.web.open_url(url)

def open_ref(mri):
    """ Open IDL reference with its name, 
        second argument is optional. """
    idl = "com.sun.star.awt.Rectangle"
    name = "X"
    mri.web.open_idl_reference(idl, name)

MRI UI オブジェクト

mytools_Mri.ui.MRIUi クラスは MRI のウィンドウを管理しています。

変数 説明
ctx pyuno コンポーネントコンテキスト。
main mytools_Mri.MRI MRI インスタンス。
desktop pyuno デスクトップインスタンス。
listeners dict リスナーインスタンス。
property_mode bool True の場合プロパティ値を設定、それ以外で取得。
tree mytools_Mri.ui.pages.HistoryTreeUi ツリー状に履歴を表示するサブウィンドウ。
dlgs mytools_Mri.ui.dialogs.Dialogs ダイアログを提供します。
status_eraser threading.Timer ステータス表示を消去するタイマー。
frame pyuno MRI ウィンドウのフレーム。
cont pyuno MRI ウィンドウのコンテナウィンドウ。
pages mytools_Mri.ui.pages.InfoUi/GridUi コントロールの内容へのアクセスを提供。

ダイアログ

mytools_Mri.ui.dialogs.Dialogs クラスにいくつかダイアログが定義されています。それらのダイアログは MRIUi クラスのインスタンスの dlgs インスタンス変数から利用できます。

def dialog_select(mri):
    items = ("Item 1", "Item 2", "Item 3", "Item 1")
    item = mri.ui.dlgs.dialog_select(items, "Title")
    mri.ui.dlgs.dialog_info("%s is selected. " % item)

dialog_select メソッドの二番目の引数はダイアログのタイトルを指定します。上記の場合、二つの Item 1 項目があり、そのどちらが選択されたかどうかを知るには、三番目の引数に True を指定してください。その場合、返り値が選択された値のインデックスになります。キャンセルされた場合、None が返ります。

ユーザーによるテキストの入力を取得したい場合、入力ダイアログを表示する dialog_input メソッドを使用してください。

def dialog_input(mri):
    text = mri.ui.dlgs.dialog_input(
          "Service Name", "Input a service name.", 
          "com.sun.star.awt.")
    mri.ui.message(text)
すべての引数は省略可能です。

履歴からエントリーを選択させるダイアログもあります。

def history_selector(mri):
    entry = mri.ui.dlgs.history_selector("Select Entry")
    if entry:
        mri.ui.message(entry.name)
メソッドの返り値は mytools_Mri.engine.Entry クラスのインスタンスです。

ダイアログになにかを表示したい場合や、ユーザーに選択を求める場合、message メソッドが用意されています。このメソッドは css.awt.XMessageBoxFactory へのショートカットを提供します。詳細はリファレンスを参照してください。このメソッドの定義は次のようになっています。

 def message(self, message, title="", type="messbox", buttons=1):

エントリー

Entry クラスは MRI がインスペクトする現在または他のターゲットを保持するためのクラスです。例えば、現在のターゲットは MRI インスタンスの current インスタンス変数からアクセスできます。Entry クラスは mytools_Mri.engine モジュールで定義されており、継承構造は以下のようになっています。

mytools_Mri.engine.Entry < 
  (mytools_Mri.engine.EntryBase, mytools_Mri.node.Node)
Entry クラスは二つの親クラスを継承していますが、自身では新しいメソッドを定義していません。Node クラスは履歴構造を構築する機能を提供します。EntryBase クラスはそのインスタンスを利用したマクロを書くために重要なメソッドを提供します。

次の表に Entry クラスのインスタンス変数についてまとめます。

変数 説明
target object このインスタンスでラップされている実際の値。
inspected pyuno css.beans.XIntrospectionAccess インターフェース。
type pyuno css.reflection.CoreReflection による IDL 型。
mri mytools_Mri.MRI 生きている MRI インスタンスへの参照。
code_entry mytools_Mri.cg.CodeEntry コード生成のための情報を保持。

次の表にある機能をもつ関数を提供しています。

メソッド 説明
get_target() 実際の値を取得するためにターゲットのインスタンス変数を使用してください。
has_interface(name) 指定したインターフェースをエクスポートしているかどうかを確認します。
supports_service(name) ターゲットが指定したサービスをサポートしているかどうかを確認します。
append(obj) obj をリストに追加します。エントリーが MRI インスタンスの create_sequence メソッドで作成されたリストの場合のみ動作します。

ページ

MRIUi の pages インスタンス変数は mytools_Mri.pages.InfoUi または GridUi インスタンスを保持しています。どちらを保持しているかどうかは、MRI ウィンドウが表示しているコントロールに依存します。これらのクラスの継承構造は少し複雑です。それらの継承構造を以下に示します。すべてのクラスは mytools_Mri.ui.pages モジュールで定義されています。

InfoUi < (Ui, PageStatus, 
   Pages < PagesBase)
GridUi < (Ui, PageStatus, 
   GridPages < GridPagesBase < PagesBase)
Ui クラスは型、実装名、検索フィールド、履歴リストコントロールへのアクセスを提供します。次の表で Ui クラスで定義されている重要なメソッドについて説明します。
メソッド 説明
get_type_name() 型名を返します。
set_type_name(name) 型名を設定します。
get_imple_name() 実装名を返します。
set_imple_name(name) 実装名を設定します。
get_code() 現在のコードテキストを取得します。
set_code(txt) 現在のコードテキストを設定します。

PageStatus クラスは情報ページの更新状態を管理しています。

PagesBase クラスは子クラスによって提供されるべき複数のメソッドを提供しています。それらのメソッドは情報コントロールへのアクセスを提供しています。Properties: 0, Methods: 1, Interfaces: 2, Services 3 となっています。

メソッド 説明
get_selected(index=None) 選択されているテキストを返します。
get_current_line(index=None) 現在の行を返します。
get_first_word(index=None) 現在の行の最初の単語を返します。
activate(index) アクティブページのインデックスを指定します。
get_active() アクティブページのインデックスを取得します。
search(search_text, index=None) 検索します。
各ページの内容はそのページが最初にアクティブになった時に更新されることに注意してください。

MRI ウィンドウのコントローラ

MRI は独自のコントローラを使用しており、ウィンドウのフレームに結び付けられています。そのコントローラは Python で書かれており、他の MRI のインスタンスへのアクセスを提供しています。すべての MRI ウィンドウはデスクトップに登録されており、それらは css.frame.XFrame インターフェースからアクセスできます。

def do_something_with(mri):
    # find MRI window from the desktop
    found = None
    frames = mri.ui.desktop.getFrames()
    for i in range(frames.getCount()):
        frame = frames.getByIndex(i)
        if frame.getTitle() == "MRI":
            found = frame
            break
    if found:
        controller = found.getController()
        # MRIUi instance of another MRI
        ui = controller.ui
        mri2 = ui.main # instance of mytools_Mri.MRI
この方法はオフィースの同じ Python インスタンス上で動作するどんな Python コードでも動作します。bundle.py - Diff マクロはこの方法を他の MRI からエントリーを取得するために使用しています。

MRI ウィンドウの構造

MRI ウィンドウの階層構造を示します。

frame: css.frame.Frame
  - Controller: mytools_Mri.ui.controller.Controller
    - Model: いつも None
  - Container Window: 普通のウィンドウ
  - Component Window: css.awt.UnoControlContainer
    - splitter: コントロールのコンテナに追加されていません。
    - label_status: ステータスを表示する FixedText。
    - edit_type: 型情報を表示するフィールド。
    - edit_in: 実装名を表示するフィールド。
    - list_hist: 履歴リスト。
    - btn_back: 戻るボタン。
    - btn_forward: 進むボタン。
    - edit_search: 検索フィールド。
    - btn_search: 検索ボタン。
    - btn_tree: ツリーを開くボタン。
    - btn_index_acc: Index ボタン。
    - btn_name_acc: Name ボタン。
    - subcont: css.awt.UnoControlContainer (タブなしモード)
      - info_0: 
      - info_1: 
      - info_2: 
      - info_3: 
   - subcont: css.awt.UnoControlContainer (タブモード)
      - page_0
        - info_0
      - page_1
        - info_1
      - page_2
        - info_2
      - page_3
        - info_3
subcont の構造はウィンドウがタブコントロールを使用しているかどうかで変わります。MRIUi インスタンスの pages インスタンス変数から簡単にアクセスできます。

拡張機能パッケージの Macros ディレクトリに配置されている bundle.py ファイルに多くの例があります。

例 1

現在のシェープコレクションにあるすべての子シェープをインスペクトするコードを示します。

def inspect_shapes(mri):
    """ Inspect Shapes
        Inspect all shapes in this container. """
    shape = mri.current # current target
    # check current shape is correct type
    if shape.supports_service("com.sun.star.drawing.ShapeCollection"):
        # getCount call is not collected to code
        for i in range(shape.target.getCount()):
             child = shape.getByIndex(i)
Entry クラスの supports_service メソッドを使用して現在のターゲットが正しい型かどうかを確認します。ターゲットが css.lang.XServiceInfo インターフェースをサポートしていない場合、False が返ります。ユーザーに警告したければ、例外を送出するか、mri.message メソッドでメッセージを表示してください。

例 2

Entry インスタンスは target インスタンス変数に実際の値を保持しています。ターゲットの実際の値が必要なら、その値を参照してください。

def show_property_value(mri):
    current = mri.current
    ui = mri.ui
    ui.message(current.target)