LibreOffice5(38)Java Component ExampleをPythonに翻訳する

LibreOffice 5.3 SDK - Developer's Guide ExamplesのWriting UNO componentsのJavaの例Java Component ExampleをPythonに書き換えたPythonComponent.oxtを作成します。IDEとしてlinuxBean14.04(149)LibreOfficeマクロ開発環境の構築:その1のEclipse Neon.2(4.6.2)を使いました。

前の関連記事:LibreOffice5(37)bootstrap()で起動したLibreOfficeをエラーなく終了させる


Java Component Example: UNOIDLを定義して拡張機能を作成する例


TestPythonComponentという名前でPyDevプロジェクトを作成しました(p--q/TestPythonComponent。Java Component Exampleという名前にするべきでしたが時すでに遅し、、、)

srcフォルダに/opt/libreoffice5.2/sdk/examples/DevelopersGuide/Components/JavaComponentフォルダの内容をコピーしました。

さらにMETA-INFフォルダ、pythonpathフォルダ、idlフォルダを作成しidlフォルダにidlファイルをそこに移動させました。


Eclipseでidlファイルを開こうとするとエディタの選択を迫られます。

とりあえずCancelをクリックします。


PyDev Package Explorerでidlファイルを右クリック→Open With→Text Editor、を選択するとEclipseでidlファイルが開けます。

今回はidlファイルはそのまま使います。

createRDB.pyでidlファイルからrdbファイルを作成する


何回もコマンドを打つのは面倒なのでidlファイルをコンパイルしてrdbファイルにするPythonスクリプトcreateRDB.pyを作成しました。

srcフォルダと同じ階層にcreateRDB.pyファイルを配置します。

createRDB.pyを実行するとsrc/idlにあるidlファイルをidlcでコンパイルしてurdファイルにしたあとregmergeでrdbファイルにしてsrcフォルダに出力します。

rdbファイル名はcreateRDB.pyの定数BASE_NAMEに設定しておきます(TestPythonComponent/createRDB.py at master · p--q/TestPythonComponent)。

この定数は次の.comonentsファイル名やoxtファイル名にも使います。

 javaファイルををpyファイルに翻訳する


これは自動ではできないので自分で翻訳しないといけません。

sdk/examples/DevelopersGuide/Components/JavaComponentにあるTestComponentA.javaとTestComponentB.javaをPythonに翻訳します。

TestJavaComponent.javaとTestServiceProvider.javaはデプロイしたoxtファイルの動作確認のためのものなので拡張機能ファイルの作成には不要です。

TestComponentB.javaはimplementation helper WeakBaseを使わずに実装したものですが、これに相当するPythonのunohelper.pyを使わずに実装する方法はよくわからなかったので、TestComponentB.pyTestComponentA.pyの名前を変えただけのものにしています。

Java Component Exampleは一つのUNO Componentに2つの実装サービスをもたせた例です。

解説はMultiple Implementations per Component Fileになります。

この「1つのコンポーネントに複数の実装例」の「コンポーネント」とはLibreOffice(67)Writing UNO componentsのThumbs Exampleその3 でいうJavaコンポーネントファイルと思っていたので、Pythonではjarファイルにまとめないのでどうするのか考えました。

結論としては単純にoxtファイルの最上層にg_ImplementationHelper.addImplementation()を書いたpyファイルを複数置くだけのことでした。

なのでPython UNO Componentの場合のper Component FileのComponent Fileとはoxtファイルのことを指すことになります。

per Moduleでもいけるかどうかは確認していません。

JavaからPythonへの翻訳自体はOOoPython - ...?などを参考にしました。

Javaのコードよりもだいぶ簡素に書けます。

次のcreateManifest.pyを実行する前にPython UNO ComponentのインスタンスにするPythonクラスをコーディングしたpyファイルをsrcフォルダに作成しておきます。

createManifest.py.componentsファイルとTMETA-INF/manifest.xmlファイルを作成する


.componentsファイルはLibreOffice(67)Writing UNO componentsのThumbs Exampleその3で学習したようにOpenOffice 3.4のPassive Component Registrationに伴って登場したもので、これがなくてもmanifest.xmlファイルにすべて登録してしまうこともできます。

MRILibreOffice5(36)UNOコンポーネントのJavaの例:TestJavaComponentで見つけた、 easydevCalendar for CalcといったPythonで実装された拡張機能を見ても.componentsファイルは使われていません。

でもTestJavaComponentでは.componentsファイルを使っているのでPythonでも.componentsファイルを使うことにします。

Pythonでの.componentsファイルの書き方の解説はPython Loader - Apache OpenOffice Wikiにあります。

複数のPython UNO Componentを登録するにはcomponentノードを対応させればうまくいきました。

今回は.componentsファイルにTestComponentA.pyとTestComponentB.pyを登録しました。

各Python UNO Componentについてpyファイル名、実装サービス名、サービス名の3つが必要です。

createManifest.pyではこれらについて各Python UNO Componentごとにタプルにして、そのタプルのリストを定数LSTとしてモジュールの最初に定義しました。

Pythonではxmlのノードを扱うxml.etree.ElementTreeが用意されていますが、解説を読んでもとくに名前空間のところなどが理解が難しくXML - Dive Into Python 3 日本語版を読んでよく理解できました。

createManifest.pyはlxmlを使わずxml.etree.ElementTreeだけで書くことができました。

ただ、manifext.xmlにあるDOCTYPEの出力方法がわからずこれは省略しました。

DOCTYPEは他の拡張機能の例では書いてないのでなくてもよいようです。

出力ファイルを上書きする前に拡張子bkをつけてバックアップしていますが、bkファイル自体は上書きしています。

createOXT.pyでoxtファイルを作成する


oxtファイルの作成にzipコマンドを使用するのでインストールしていなければインストールしてzipコマンドへのパスの設定が必要です。

今回作成したPythonComonent.oxtファイルにはpythonpathフォルダはありませんが、pythonpathフォルダがsrcフォルダにあればpythonpathフォルダ内のpyファイルとmoファイルをoxtファイルに取り込むようにしています。

oxtファイルはsrcフォルダと同じ階層に出力されます。

depoyOXT.pyでLibreOfficeの拡張機能マネージャーに登録する


oxtファイル作成中は動作確認のため何回もデプロイするのが面倒なので、デプロイするスクリプトも作成しました。

LibreOfficeを起動した状態でこのスクリプトを実行したときはLibreOfficeの再起動が必要です。

TestJavaComponent.javaをPythonに翻訳する


TestJavaComponent.javaはデプロイしたJavaComponent.oxt動作確認をするものです。

ということで今回作成したPythonComponent.oxtをLibreOfficeの拡張機能マネージャーに登録して再起動した状態で動作確認するTestPythonComponent.pyを作成しました。

これを実行すると以下の出力があるはずです。
Connected to a running office ...
Using remote servicemanager
Hello World! by Python UNO Component
The Office has been terminated.
最後の出力行はLibreOffice5(37)bootstrap()で起動したLibreOfficeをエラーなく終了させるの結果を反映させたものです。

オリジナルのJavaComponent.oxtではLibreOfficeのプロセスがバックグラウンドで起動したままなので、タスクマネージャでそのプロセスを終了させないとLibreOfficeのウィンドウを表示させることができなくなってしまいます。

PythonComonent.oxtではそうならないようになっています。

参考にしたサイト


LibreOffice 5.3 SDK - Developer's Guide Examples
今回このJava Component ExampleをPythonに翻訳しました。

Multiple Implementations per Component File
Java Component Exampleの解説。

OOoPython - ...?
Python UNO Component作成のためのとても役立つ資料集。

hanya/MRI: An object introspection tool for OpenOffice API
Pythonで書かれた拡張機能の例。

UniversoLibreMexicoAC/easydev: Tool for easy develop macros in LibreOffice... with Python
Pythonで書かれた拡張機能の例。serviceは複数のインターフェイスを継承しておりold-styleになっています。

Calendar for Calc — LibreOffice Extensions and Templates Website
Pythonで書かれた拡張機能の例。

Python Loader - Apache OpenOffice Wiki
Pythonの.componentファイルの例があります。

20.5. xml.etree.ElementTree — ElementTree XML API — Python 3.5.3 ドキュメント
Pythonでxmlを扱うモジュール。

XML - Dive Into Python 3 日本語版
この解説がxmlファイルの理解にとても役立ちました。

python - Create a temporary compressed file - Stack Overflow
shutilでzipファイルを操作する例があります。

Creating a simple XML file using python - Stack Overflow
Pythonでゼロからxmlファイルを作成する例。SubElement()でノードを追加します。

python - Saving XML files using ElementTree - Stack Overflow
xml.etree.ElementTreeで名前空間のns0を消す方法。ElementTree.register_namespace()で解決しました。

xml - How to create <!DOCTYPE> with Python's cElementTree - Stack Overflow
結局Python3.5でDOCTYPEを出力する方法はわからずDOCTYPEの出力は諦めました。

path - Use a Glob() to find files recursively in Python? - Stack Overflow
globで特定のフォルダ内で特定の拡張子のファイルを抽出する方法。**を挟めば解決しました。

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

PR

0 件のコメント:

コメントを投稿