UNO コンポーネント 
Python-UNO では UNO コンポーネントの作成もできます。UNO コンポーネントでは次のようなものがよく知られています。
- Calc アドイン関数
- チャートアドイン
- スマートタグ
これらは既存のサービスを利用、拡張して作成されるコンポーネントです。こういったもの以外にも Py-UNO では新たなサービス、インターフェースを実装できます。新規なサービスやインターフェースを実装するにはやはり IDL を定義しなければいけません (Calc アドイン関数では インターフェースの IDL を書かなければいけません)。
簡単なコンポーネントの作成 
ここでは簡単な UNO コンポーネントを作成します。IDL を定義しないで済むように既存のインターフェースを利用します。
サービスとして実装される UNO コンポーネントに com.sun.star.task.XJobExecutor インターフェースを実装しておくと、メニューの項目などから簡単にマクロなどのように利用できます。
UNO コンポーネントは次のようなインターフェースを実装しているべきです。
XTypeProvider は unohelper.Base クラスを継承してやると自分で実装しなくても済みます。
XJobExecutor インターフェース 
XJobExecutor インターフェースには trigger メソッドがあります。
- void trigger( [in] string Event )
このメソッドを介してサービスを実行できます。また引数は任意の文字列です。
このインターフェースを実装したコンポーネントは service:SERVICE_NAME?ARGUMENT 形式の URL で trigger メソッドを呼び出せます。ARGUMENT は trigger メソッドの引数として渡されます。
(これは service: プロトコルのプロトコルハンドラが、指定のサービスをインスタンス化して trigger してくれるためです。shared/registry/data/org/openoffice/Office/ProtocolHandler.xcu にリストがあります。)
UNO コンポーネント作成 
実際に UNO コンポーネントを実装します。
まずは宣言部分です。日本語を含むときにはエンコードを指定しておきます。
インポートするモジュールは次のものです。
- uno: createUnoStruct を利用。
- unohelper: unohelper.Base クラスの継承およびサービスの登録に利用。
- XJobExecutor: trigger メソッドを利用します。
- com.sun.star.awt.WindowClass: この enum 値はメッセージボックス作成に利用します。
- com.sun.star.awt.WindowAttribute: 同様にメッセージボックス作成に利用します。
component.py
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| | #!
# -*- coding: utf_8 -*-
import uno
import unohelper
import time
# interfaces
from com.sun.star.task import XJobExecutor
# enums
from com.sun.star.awt.WindowClass import MODALTOP
from com.sun.star.awt.WindowAttribute import \
MOVEABLE as WA_MOVEABLE, CLOSEABLE as WA_CLOSEABLE, BORDER as WA_BORDER
IMPLEMENTATION_NAME = "mytools.example.TestComponent"
|
コンポーネントのメインクラスです。このクラスは unohelper.Base および XJobExecutor インターフェースを継承しています。
クラスがインスタンス化されるときにコンポーネントコンテキストが渡されます。ドキュメントにアクセスのに com.sun.star.frame.Desktop を利用するのでここでインスタンス化しておきます。
0
1
2
3
4
5
6
7
| | class TestComponent(unohelper.Base,XJobExecutor):
def __init__(self,ctx):
self.ctx = ctx
self.smgr = self.ctx.ServiceManager
self.desktop = self.smgr.createInstanceWithContext(
"com.sun.star.frame.Desktop",self.ctx)
return
|
XJobExecutor インターフェースの trigger メソッドを実装します。Event が空文字列の時には何も行いません。引数をチェックして指定の動作を行います。エラーメッセージをメッセージボックスで表示するために下記でダイアログを作成しています。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| | # XJobExecutor
def trigger(self,Event):
if Event == "":
return
doc = self.desktop.getCurrentComponent()
if doc:
if doc.isReadonly():
self.showMessage("Document is readonly.")
return
if Event == "date":
now = time.strftime(u'%Y%%s%m%%s%d%%s') % (u'年',u'月',u'日')
elif Event == "time":
now = time.strftime("%H%%s%M%%s%S%%s") % (u'時',u'分',u'秒')
else:
now = time.strftime("%Y%%s%m%%s%d%%s%H%%s%M%%s%S%%s") % (
u'年',u'月',u'日',u'時',u'分',u'秒')
if doc.supportsService("com.sun.star.text.TextDocument"):
if not doc.getCurrentSelection().supportsService(
"com.sun.star.text.TextRanges"):
self.showMessage("Wrong object is selected.")
return
controller = doc.getCurrentController()
if controller:
cursor = controller.getViewCursor()
cursor.setString(now)
cursor.collapseToEnd()
elif doc.supportsService("com.sun.star.sheet.SpreadsheetDocument"):
selection = doc.getCurrentSelection()
if selection:
if selection.supportsService("com.sun.star.sheet.SheetCell"):
selection.setString(now)
else:
self.showMessage("Wrong object is selected.")
else:
self.showMessage("This kind of document is not supported.")
return
|
メッセージを表示するダイアログを作成します。Py-UNO には OOo Basic のようなメッセージボックスはありません。自分で作成しなければいけません。このダイアログは OOo 2.0.3 以降で動作します。OOo 2.2 以降であれば com.sun.star.awt.Toolkit サービスの com.sun.star.awt.XMessageBoxFactory インターフェースを使用して簡単にダイアログを作成できます。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| | def showMessage(self,message,title=""):
frame = self.desktop.getActiveFrame()
if frame:
window = frame.getContainerWindow()
toolkit = window.getToolkit()
aWindowDesc = uno.createUnoStruct("com.sun.star.awt.WindowDescriptor")
aWindowDesc.Type = MODALTOP
aWindowDesc.WindowServiceName = "infobox"
#aWindowDesc.ParentIndex = -1
aWindowDesc.Bounds = self.createRect(0,0,0,0)
aWindowDesc.Parent = window
aWindowDesc.WindowAttributes = WA_MOVEABLE + WA_CLOSEABLE + WA_BORDER
msgwin = toolkit.createWindow(aWindowDesc)
msgwin.setCaptionText(title)
msgwin.setMessageText(message)
msgwin.execute()
msgwin.dispose()
def createRect(self,x,y,width,height):
aRect = uno.createUnoStruct("com.sun.star.awt.Rectangle")
aRect.X = x
aRect.Y = y
aRect.Width = width
aRect.Height = height
return aRect
|
コンポーネントを登録する部分です。unohelper がコンポーネントを簡単に登録するクラスを提供してくれています。このとき、g_ImplementationHelper 変数名を変えてはいけません。
addImplementation メソッドに次の三つの引数を与えます。
- コンポーネントを実際に実装するクラス
- 実装名を string で
- コンポーネントが提供するサービス名を string のタプルで
0
1
2
3
4
5
| | # uno implementation
g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(
TestComponent,
IMPLEMENTATION_NAME,
("com.sun.star.task.JobExecutor",),)
|
コンポーネントの配置 
UNO コンポーネントを作成したら OOo の拡張機能マネージャを使ってコンポーネントを配備します。
コンポーネントを入れた拡張機能パッケージを作成しなければいけません。
ZIP アーカイブに次のようなファイル構成になるようにファイルを入れます。
- component.py
- META-INF/manifest.xml
manifest.xml
0
1
2
3
| <?xml version="1.0" encoding="UTF-8"?>
<manifest:manifest>
<manifest:file-entry manifest:full-path="component.py"
manifest:media-type="application/vnd.sun.star.uno-component;type=Python"/>
</manifest:manifest>
|
作成した ZIP アーカイブファイルの名前を TestComponent.oxt などに変更します。
インストール 
作成した拡張機能パッケージはツール - 拡張機能マネージャからインストールします。
インストール後、OOo を一度再起動します。クイックスタートを利用しているのであれば一度終了させてください。
実行 
作成したコンポーネントを実行してみます。
とりあえず、コンポーネントを OOo Basic から作成して実行してみます。
0
1
2
3
| | Sub MyComponentTest
oMyComponent = CreateUnoService("mytools.example.TestComponent")
oMyComponent.trigger("date")
End Sub
|
unohelper.ImplementationHelper クラスを利用して登録したコンポーネントは実装名と同じ名前でインスタンス化できます。
trigger をメニューなど Dispatch から行うには次のような URL を利用します。
service:mytools.example.TestComponent?date
形式は次のようになっています。
"service:" + SERVICE_NAME + "?" + ARGUMENT
引数は一つしか与えられませんが、内部で解析するのであれば複数与えられます。
メニューに上記のような URL を入れるにはアドオン用メニューやツールバーを利用します。
試すだけであれば BookmarksMenu 拡張機能で容易にできます。
パッケージ 
TestComponent.oxt