LibreOffice5(39)ProtocolHandler Addon Javaのxcuファイルを出力するPythonスクリプト

Writing UNO components examplesのJavaの例のLibreOffice(65)Writing UNO componentsのThumbs Exampleその1で調べた5個のうち、3個目のProtocolHandler Addon JavaをPythonでやります。p--q/ProtocolHandlerAddonPythonにGitリポジトリがあります。

前の関連記事:LibreOffice5(38)Java Component ExampleをPythonに翻訳する


PyDevプロジェクトProtocolHandlerAddonPythonの作成


PyDevプロジェクト作成手順はlinuxBean14.04(149)LibreOfficeマクロ開発環境の構築:その1の通りです。

LibreOffice5(38)Java Component ExampleをPythonに翻訳するで作成したtoolsフォルダをPyDevプロジェクト下のフォルダにコピーしてこれらのスクリプトを修正して使います。

、、、結局これらのスクリプトはかなり書き換えました。

 今回の例ではidlファイルのコンパイルは不要ですが、Addons.xcuファイルとProtocolHandler.xcuファイルを作成しないといけません。

これらもxml形式で書いてありノードのoor:nameプロパティで名付けられています。

xcuファイルの書き方についてはLibreOffice5(30)xcsファイルとxcuファイルとxcdファイル:その1で学習しましたが、キーボードから入力して作成するのは大変です。

しかも適当なデバッガを見つけられなかったので動作しないときの原因特定は大変です。

ということでこれらxmlファイルもPythonスクリプトで書き出すことにしました。

EclipseでxcuファイルをXMLエディタでみる設定



Eclipse Java EE IDE for Web Developers. Neon.2 Release (4.6.2)のPyDev Package Explorerでxcuをダブルクリックするとエディタの選択を求められます。

しかしこのEclipseにはもともとXMLエディタがインストールされているはずです。

なのでPreferences for File Assocationsをクリックします。

PreferencesのGeneral→Editors→File Associationsが開きます。


File typesのAddボタンをクリックして*.xcuを入力してOKボタンをクリックします。

次にAssociated editorsのAddボタンをクリックしてXML Editorを選択します。

Preferencesを閉じると元の関連付けのダイアログに戻ってしまうのでCancelでダイアログを閉じます。

もう一度xcuファイルをダブルクリックすると今度はXMLエディタでxcuファイルが開きました。

私の環境ではEclipseを再起動しないと関連付けが有効にならないことがありました。

.componentsファイルもxmlなので同様にXMLエディタと関連付けました。

XMLエディタタブでは下にDesignタブとSourceタブがあります。


Designタブではノードと属性が整理されて表示され右クリックで編集もできます。

Sourceタブではシンタックスハイライトされたソースが表示されています。

右クリック→Source→Format、で見やすく整理できます。


こちらの方が私には読みやすいのですが、毎回Formatコマンドをしないといけないのが難点です。

自動的にFormatしてくれる設定を探してみましたが、Format XML code in Eclipse - Stack OverflowのQ&Aにあるようにそういう設定はないようです。

xmlファイルをPythonスクリプトで書き出す


xmlファイルはすべてPythonスクリプトで書き出すことにしました。

ProtocolHandlerAddonPython/step2createXCU.py at 416033d915b901c0d4b9bfd2c655189f108d83e1 · p--q/ProtocolHandlerAddonPython

これは単純にタグをそのまま書き出しています。

Calendar5_BloggerのJavaScriptでやったようにタグの要素をインデックスで指定しています(20.5. xml.etree.ElementTree — ElementTree XML API — Python 3.5.3 ドキュメント)。

だけどこの方法はほとんど汎用性がありません。

ProtocolHandlerAddonPython/step3createXCUs.py at e6dcb149c236c8618108ba7dad327a47bc4206d2 · p--q/ProtocolHandlerAddonPython

クラスを使った方法に書き換えてだいぶ使いまわししやすくなりました。

/opt/libreoffice5.2/share/registry/main.xcdをChromiumで開いて整形されるのを待った後Addonsで検索してcomponent-schemaノードをみてクラスを分類しました。

JavaScriptのときも同じようにしようと思ったのですが、HTMLノードはObject.create()するとHTMLノードでなくなってしまったのでJavaScriptでは諦めていました。

PythonではElement オブジェクトを継承したクラスを作成してXMLノードにすることができました。

だけどこのクラスでself.foo = fooといったように値をもたせようとしてもできませんでした。

Can't set attributes on ElementTree.Element instance in Python 3 - Stack Overflowこれを読んでElement オブジェクトは特殊なインスタンスなのでそういうものととりあえず納得しました。

JavaScriptでもインスタンスであるHTMLノードをObject.create()するのではなく、それを返すオブジェクトをObject.create()すればうまくいけそうに思えてきました。

つまりファクトリーを継承していくということです。

Pythonのクラスもselfを返しているのでJavaScriptも同じようにできるはずです。

このスクリプトを書くうえで頭を悩ましたのは親クラスのメソッドの中から子クラスのメソッドをどうやって呼び出すかです。

子クラスから親クラスのメソッドはsuper().親クラスのメソッド()、で呼び出すことができます。

A←B←Cと継承しているときはsuper()はCからB,Aという順にメソッドを探しにいき、最初に出会ったメソッドを実行していました。

なのでxml.etree.ElementTree←Elem←MenuItem←AddonMenu、と継承してMenuItemクラスに__init__()メソッドがないときAddonMenuクラスで呼び出したsuper().__init__()はElemクラスにある__init__()メソッドを実行しています。

複数のクラスを継承しているときは継承するときに左に書いたクラスのメソッドから順に探しにいきます。

で、逆に親クラスで子クラスのメソッドを使いたい場合はどうするか、ということですが調べてもわからなかったので、メソッドそのものを渡すことにしました(step3createXCUs.pyではsubMenuメソッド)。

関数が第一級オブジェクトではないJavaではどうするのかと考えてみましたが、親クラスで抽象メソッドを定義すればよいようです。

だけどそうすると子クラスで抽象メソッドを実装しないといけなくなります。

実装されていることをコンパイルのときに確認して強制するという点ではそれが利点になることもあるわけですが、Pythonはコンパイルしないので関係なさそうです。

PyDevのテンプレート機能でdocstringを書く


Classを導入するとコードを読むだけではその機能がわかりずらいのでこの機会にdocstringをなるべく書くようにします。

PyDevではクラスやメソッド、関数のある行でCtrl+1→Make docstringでdocstringのテンプレートが挿入できます。

docstringのテンプレートの設定はWindow→Preferences→PyDev→Editor→Code Style→Docstringsで変更できます。


Type doctag generationをAlwaysにしました。

メソッドの行では引数の一覧を表示してくれます。

戻り値は探知してくれませんでした。
    def methodOne(self,val):
        '''
        
        :param val:
        :type val:
        :returns:
        :rtype:
        '''
        return val + " by Python UNO Component"
戻り値については自分でreturnsとrtypeの行を追加しないといけません。

参考にしたサイト


LibreOffice 5.3 SDK - Developer's Guide Examples
このProtocolHandler Addon Javaのxcuファイルを書き出すPythonスクリプトを作成しました。

Format XML code in Eclipse - Stack Overflow
EclipseのXMLエディタのソースの整形は毎回手動でやるしかないようです。

20.5. xml.etree.ElementTree — ElementTree XML API — Python 3.5.3 ドキュメント
xmlの子ノードにはインデックスでアクセスできます。

Object.create() - JavaScript | MDN
JavaScriptでもこのObject.create()を使って継承ができるはずですがまだ習得できていません。

20.5.3.2. Element オブジェクト
このxml.etree.ElementTree.Elementクラスの派生させてxmlノードを返すクラスを作成しました。

Can't set attributes on ElementTree.Element instance in Python 3 - Stack Overflow
xml.etree.ElementTree.Elementのインスタンスにはプロパティが追加できませんでした。

OOoPython/ComplexToolbar - ...?
ProtocolHandler AddonのPython実装例。Python3に変換しないとLibreOffice5.2では動きませんでした。

OOoPython/Memo - ...?
UNO コンポーネントの initialize()メソッドの解説。ProtocolHandlerAddonのクラスではフレームが渡されます。

[翻訳] PEP 0484 -- 型ヒント (Type Hints) - Qiita
docstringの作成の参考にしましたがなかなか消化が難しいです。

2. Example on how to document your Python docstrings — Sphinx and RST syntax guide (0.9.3)
docstringの書き方例。

次の関連記事:LibreOffice5(40)ツールバーやメニューに表示させるアイコン画像

PR

0 件のコメント:

コメントを投稿