LibreOffice5(28)MRI - UNO Object Inspection Tool:その4

前の関連記事:LibreOffice5(27)MRI - UNO Object Inspection Tool:その3


前回やったオートメーションで逐次実行する方法は最初のウィンドウを表示するところまでしか見れませんでした。結局あれこれした結果LibreOfficeに取り込まれた拡張機能のキャッシュをPyDevのプロジェクトに取り込むことでリモートデバッグできました。

LibreOfficeの拡張機能のキャッシュをソースにしてPyDevプロジェクトを作成する


LibreOffice5(18)拡張機能python-tokencounter-calc-addin.oxtをリモートデバッグするでは拡張機能のコードのコピーが単にPyDevのプロジェクトにあるだけでリモートデバッグできたので、「リモートデバッグ」の「リモート」とは逐次実行しているコードが同一のものではなくコピーであればデバッグできると解釈していました。

でもMRIでは同じようにはできず、Pythonのリモートデバッグの原理資料も探せず解決法がわからなかったので結局LibreOffice5(9)oxtファイルによる拡張機能の更新の反映はLibreOfficeの再起動が必要でみつけた拡張機能のキャッシュのコードをPyDevプロジェクトに取り込んで同一のコードでデバッガをつなぐと逐次実行できました。
(2017.7.17追記LibreOffice5(61)オプションダイアログの作成例: MaximumPageSize.oxtの拡張機能の例ではキャッシュでPyDevプロジェクトを作成しなくても、import pydevd; pydevd.settrace()を挿入するだけでブレークできましたので、わざわざキャッシュでPyDevプロジェクトを作成する必要はないのかもしれません。)

これが「リモート」なのかどうか、、、

まずLibreOfficeの拡張機能マネージャーにMRIを登録してLibreOfficeを再起動しておく必要があります。

linuxBean14.04(93)Eclipse4.5にPyDevをインストールでPyDevをインストールした状態でPyDevパースペクティブにします。

linuxBean14.04(86)AnacondaのパッケージをLibreOfficeマクロで使うで作成した~/.local/lib/python3.3/site-packages/sites.pthの最後に/opt/eclipse/plugins/org.python.pydev_4.4.0.201510052309/pysrcを追記しておくなどしてpydevへPYTHONPATHを通しておく必要があります。

File→New→PyDev Project(またはFile→New→Other→PyDev→PyDev Project)。


Project nameをMRI_cache、Grammar Versionを3.0、InterpreterをLibreOfficeのバンドルPythonにしました。

Create links to existing sources (select them on the next page)を選択してNext。


~/.config/libreoffice/4/user/uno_packages/cache/uno_packages/lu3282wehczb.tmp_/MRI-1.3.1.oxt

今回はこのパスに拡張機能のキャッシュがありましたが、インストールごとに赤字の部分のフォルダ名が変わるのでそれはフォルダ作成日時など参考に探すしかありません。

Finish。

これでPyDev Package ExplorerにMRI_cacheプロジェクトができましたのであとは逐次実行を開始したい場所にimport pydevd; pydevd.settrace()を仕掛ければよいわけです。


拡張機能マネージャーで登録し直すとキャッシュフォルダ名が変更になるのでリンクが途切れてしまいます。

そのときはプロジェクトのプロパティからLinked Resourcesを新しいキャッシュフォルダに変更します。

MRIのソースを読む


引数のpyunoオブジェクトはまずMRI-1.3.1.oxt/pythonpath/mytools_Mri/component.pyで処理されています。

inspectメソッドの場合はMriクラスのinspect()メソッドからそのままMri._run_mri()メソッドにオブジェクトが渡され、メニューから実行したときはMri.trigger()メソッドでインスペクトされるオブジェクトを作られてMri._run_mri()メソッドが呼ばれています。

なのでとりあえずMri._run_mri()メソッドにimport pydevd; pydevd.settrace()を仕掛けました。
    def _run_mri(self, target, name=''):
        import pydevd; pydevd.settrace()
        if name == "":
            name = self.VAR_NAME
面倒なのでキャッシュファイルを直接書き換えて保存しました。

このデバッグコードはデバッグしない時はコメントアウトしておかないとMRIが動かなくなります。

デバッグサーバを起動していなくてもそこで止まったままになってしまうようです。

キャッシュファイルは拡張機能を削除すると消えてしまうので必要ならば削除前にキャッシュファイルをコピーしておく必要があります。

キャシュを変更して保存したらLibreOfficeを再起動します。

Debugパースペクティブに切り替えてPyDev→Start Debug Server。

次にLibreOfficeからツール→アドオン→MRI。



あとはStep OverボタンやStep Intoボタンで逐次実行できます。


            mri = mytools_Mri.MRI(self.ctx, mytools_Mri.ui.MRIUi)
ここからStep IntoするとGUIの設定に入っていきます。

どこでStep Intoするのか判断するのは結構面倒です。

一旦import pydevd; pydevd.settrace()を挿入したところでブレークしたあとはPyDevでブレークポイントを設定してみたいところまで飛ぶと楽できます。

(MRI-1.3.1.oxt/pythonpath/mytools_Mri/ui/frame.py)

PyDevパースペクティブで行番号の左をダブルクリックするとブレークポイントを設定できます。


Resumeボタンをクリックすると設定したブレークポイントまで実行されます。

MRIのメインウィンドウははノンモダルダイアログではなくてフレームを作ってメニューなども全部設定作っていますね。

OOoBasic/Dialog - ...?の例にあるメニューバー付きウィンドウに作成例がありました。

グリッドコントロール (3.3)にグリッドの例もありますね。


History treeボタンをクリックした時に表示されるウィンドウもフレームから作っているようです。

各ボタンから起動されるメソッドはMRI-1.3.1.oxt/pythonpath/mytools_Mri/ui/listeners.pyのButtonListenerクラスに一覧がありました。
class ButtonListener(unohelper.Base, XActionListener):
    def __init__(self, cast):
        self.cast = cast
    def disposing(self, ev): pass
    def actionPerformed(self, ev):
        cmd = str(ev.ActionCommand)
        if cmd == 'ref':
            self.cast.open_idl_reference()
        elif cmd == 'back':
            self.cast.history_back()
        elif cmd == 'forward':
            self.cast.history_forward()
        elif cmd == 'search':
            self.cast.search_word()
        elif cmd == 'index':
            self.cast.try_index_access()
        elif cmd == 'name':
            self.cast.try_name_access()
        elif cmd == 'history':
            self.cast.show_history_tree(ev)
ここをブレイクしても引っかからなかったのでshow_history_treeでpythonpathフォルダ内を検索するとMRI-1.3.1.oxt/pythonpath/mytools_Mri/ui/__init__.pyにshow_history_tree()メソッドがありました。
    def show_history_tree(self, ev=None):
        """ Show the window of history tree. """
        import pydevd; pydevd.settrace()
        if self.tree:
            self.tree._tree_frame.close(True)
            self.tree = None
ここにimport pydevd; pydevd.settrace()を挿入してファイルを保存後LibreOfficeを再起動してMRIを起動してHistory treeボタンをクリックするとここでブレイクされました。

うーん、簡単には理解できなさそうです、、、

フレームとコントローラーは見つけましたがモデルはどこで処理しているのでしょう?

grid.pyの33行目でpage.getModel()でモデルを得ています。

、、、うーん、難しい、、、

参考にしたサイト


OOoBasic/Dialog - ...?
LibreOfficeのダイアログとウィンドウの作成例が多数あります。

次の関連記事:LibreOffice5(29)ダイアログエディタの言語ツールバーを利用する方法

PR

0 件のコメント:

コメントを投稿