複雑なツールバー 
OOo 2.2 からアドオンでも容易にボタン以外のコントロール (テキストフィールドやドロップダウンボタン、リストボックスなど) をツールバーに組み込めるようになりました。しかし、組み込みは簡単ですが利用が少し面倒です。ここでは Py-UNO を利用して複雑なツールバーを作成していきます。
Generic UNO Interfaces for complex toolbar controls
で SDK 付属の例に関してアドオンでの複雑なツールバーの利用が説明されています。しかし、利用されていないコードが含まれていたりといったことで不必要にごちゃごちゃしています。
準備 
以下を理解するには次のことを知っているといいかもしれません。
作成するのは主に次のファイルです。これらのファイル名は一例で変更できます。
- Addons.xcu - アドオン用のツールバー
- ProtocolHandler.xcu - プロトコルハンドラ定義
- handler.py - プロトコルハンドラ実装
コマンド 
OpenOffice.org のコマンド実行環境に関する説明です。
OpenOffice.org ではメニューなどからコマンドを実行し、そのコマンドをコンポーネントが受け取ることで (ユーザーなどからの) 処理が行われます。このコマンドは URL 形式をしています。そのため、その URL にはプロトコル (http: や .uno: など) とパス (localhost や Copy など) が含まれます。API でこの URL を取り扱うときには com.sun.star.util.URL
構造体を利用します。
OOo に組み込まれているコマンドはどこかのコンポーネントによって処理されます。組み込み型のコマンドはコマンド URL として .uno:Copy といった形で実行されます。.uno: 部分がプロトコル、Copy 部分がパスに相当します。ここではそういったコマンドを受け取り、処理するコンポーネントを新たに作成しなければいけません。
新たに作成するコンポーネントが取り扱うプロトコルは勝手に決めてかまいませんが、簡単なものだと他の人が作成したものと同じになり正しく動作しないかもしれないので、ドメイン名を逆からといったように長めにするほうがいいとされています。
ここではプロトコルを "mytools.handler:" とします。パスの部分はツールバーに配置するコントロールと関連して付けます。
XDispatchProvider 
あるコマンドがメニューの項目やツールバーのボタンなどに割り当てられていたとします。ツールバーマネージャによりその項目もしくはボタンが作成されたときにそれに対応したコンポーネントの com.sun.star.frame.XDispatchProvider インターフェースの queryDispatch メソッドが呼ばれます。このとき、コンポーネントは状況に応じて com.sun.star.frame.XDispatch インターフェースを戻します。大抵は次のようなことを確認します。
- プロトコルやパス名の確認
- その他の状況に依存しているのであれば、その確認
実際にコマンドが実行されるときに XDispatch インターフェースの dispatch メソッドが呼ばれます。そのため、queryDispatch メソッドが XDispatch インターフェースを戻さなければそのコマンドは使用できなくなります。こういった場合にはツールバーボタンが灰色に無効化された状態になります。
XDispatch インターフェースを戻さないのではなくボタンや項目を無効にする処理をするべきです。
XDispatchProvider
XDispatch 
コマンドが実行されるとき、queryDispatch メソッドにより返された XDispatch インターフェースの dispatch メソッドが呼ばれ、コンポーネントが処理を行います。
プロトコルハンドラを実装するだけであれば XDispatch の役目はほとんどこれだけです。しかし、ツールバーのさまざまな種類のコントロールを取り扱うにはこのインターフェースのほかのメソッドを使わなければいけません。
queryDispatch の後、XDispatch インターフェースの addStatusListener メソッドがリスナーを登録するために呼ばれます。このとき、ツールバーのコントロールに変更を加えられるリスナーがメソッドの引数として含まれます。これを利用してリストボックスに項目を追加したりといったことを行います。
XDispatch
XControlNotificationListener 
com.sun.star.frame.XControlNotificationListener
インターフェースはコントロールでイベントが起きた際のリスナーです。このインターフェースを XDispatch を実装するコンポーネントに実装しておくとイベントを受け取ることができます。テキストフィールドの文字列が変更されたときなどに値を受け取るために利用します。
XControlNotificationListener
ツールバーと機能 
さっぱり例が思いつかなかったので次のようなツールバーを作成することにします。
- 次のようにテキストフィールド、ボタン、スピンコントロールを備えたツールバー。
- 各コントロールは Writer ドキュメントでのみ表示される。
ボタンを押すとテキストフィールドに入力された文字がスピンコントロールで指定された回数だけテキストカーソル位置に入力される。
パッケージ

アドオンツールバー 
ツールバーでは次のコントロールを作成、利用できます。
コントロール | オプション | 説明 |
Button | | ボタン |
Combobox | * | コンボボックス |
Dropdownbox | * | リストボックス |
DropdownButton | * | ドロップダウンボタン |
Editfield | * | テキストフィールド |
ImageButton | | 画像ボタン |
Spinfield | * | スピンフィールド |
ToggleButton | | トグルボタン |
ToggleDropdownButton | | 切り替えドロップボタン |
*: Width 指定可
ツールバーの設定時に利用するコントロールのプロパティは次のものです。
プロパティ | 型 | 説明 |
URL | string | コントロールの URL |
Title | string | ラベルまたはツールチップテキスト(ロカライズ可) |
Context | string | コントロールを表示するモジュール名 |
ImageIdentifier | string | 画像指定 |
Target | string | ターゲットフレーム |
ControlType | string | コントロールの種類 |
Width | long | コントロールの幅 (種類に依存) |
アドオンのツールバーを Addons.xcu に記述して作成します。アドオンファイルの OOo レジストリ内での名称は org.openoffice.Office.Addons です。
AddonUI の OfficeToolBar に新しいノードを追加してやると新しいツールバーが作成できます。ノード名は独自のものになるように付けます、ここでは "mytools.test.toolbar2" とします。
Addons.xcu ファイル
0
1
2
3
4
5
| <?xml version='1.0' encoding='UTF-8'?>
<oor:component-data xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema" oor:name="Addons"
oor:package="org.openoffice.Office">
<node oor:name="AddonUI">
<node oor:name="OfficeToolBar">
<node oor:name="mytools.test.toolbar2" oor:op="replace">
|
ツールバーにコントロールを追加していきます。コントロールごとに新しいノードを作成し、プロパティとして URL、Title、Context などを設定します。
テキストフィールド 
一つ目はテキストフィールドです。
- URL: mytools.handler:edit。このコントロールが実行されたときなどにこの、プロトコル+パスが利用されます。
- Title: Text。コントロールのツールチップに表示されます。
- Context: com.sun.star.text.TextDocument。Writer ドキュメントのときのみこのコントロールを表示します。
- ControlType: Editfield。テキストフィールドを作成します。
- Width: 100。テキストフィールドなどは幅の指定が可能です。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <node oor:name="a1_0" oor:op="replace">
<prop oor:name="URL">
<value>mytools.handler:edit</value>
</prop>
<prop oor:name="Title">
<value>Text</value>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<value>com.sun.star.text.TextDocument</value>
</prop>
<prop oor:name="ControlType">
<value>Editfield</value>
</prop>
<prop oor:name="Width">
<value>100</value>
</prop>
</node>
|
ボタン 
二つ目のコントロールはボタンです。
- URL: mytools.handler:button
- ImageIdentifier: %origin%/write。表示画像として、この Addons.xcu ファイルを配置したディレクトリにある writer_16.bmp を指定。
0
1
2
3
4
5
6
7
8
9
10
11
12
| <node oor:name="a1_1" oor:op="replace">
<prop oor:name="URL">
<value>mytools.handler:button</value>
</prop>
<prop oor:name="Title">
<value>Insert</value>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<value>com.sun.star.text.TextDocument</value>
</prop>
<prop oor:name="ImageIdentifier" oor:type="xs:string">
<value>%origin%/write</value>
</prop>
</node>
|
スピンフィールド 
三つ目のコントロールとしてスピンコントロールです。
- URL: mytools.handler:spin
- ControlType: Spinfield
- Width: 50
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| <node oor:name="a1_2" oor:op="replace">
<prop oor:name="URL">
<value>mytools.handler:spin</value>
</prop>
<prop oor:name="Title">
<value>Number of times</value>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<value>com.sun.star.text.TextDocument</value>
</prop>
<prop oor:name="ControlType">
<value>Spinfield</value>
</prop>
<prop oor:name="Width">
<value>50</value>
</prop>
</node>
</node>
</node>
</node>
</oor:component-data>
|
プロトコルハンドラ 
プロトコルハンドラの設定を ProtocolHandler.xcu に記述します。このファイルのスキーマは shared/schema/org/openoffice/Office/ProtocolHandler.xcs にあります。
このファイルでは、どのプロトコルハンドラ (コンポーネント) がどのようなプロトコルをハンドルするかを定義します。プロトコルハンドラはそのコンポーネントを実装するコンポーネントの実装名で指定します。また、プロトコルは文字列で指定しますが、プロトコル以降の部分はワイルドカードとして * が利用できます。
- 実装名 (6 行目): mytools.handler.Test
- プロトコル (8 行目): mytools.handler:*
プロトコルはアドオンツールバーでコントロールの URL プロパティに指定したものと同じにします。
ProtocolHandler.xcu
0
1
2
3
4
5
6
7
8
9
10
| <?xml version='1.0' encoding='UTF-8'?>
<oor:component-data xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema" oor:name="ProtocolHandler"
oor:package="org.openoffice.Office">
<node oor:name="HandlerSet">
<node oor:name="mytools.handler.Test" oor:op="replace">
<prop oor:name="Protocols" oor:type="oor:string-list">
<value>mytools.handler:*</value>
</prop>
</node>
</node>
</oor:component-data>
|
ここで定義したプロトコルハンドラは mytools.handler: につづくすべての URL を受け取ります。プロトコルハンドラの本体のコンポーネントは実装名 mytools.handler.Test のコンポーネントとして以下で作成します。
コンポーネント 
プロトコルハンドラを実際に実装する UNO コンポーネントを作成します。
注意点
- ボタンを押したときにテキストフィールドの値を取得して・・・といったことはできない。が、コントロールの各種イベント時にその値を取得できるので、値をどこかに保存しておいて利用する。
- ツールバーはフレームごとに作成される。そのため、保存する値はフレームごとに管理する。
- フレームが閉じられたとき、保存していた値などを削除する。フレームが閉じられたことを検出するためにフレームの XComponent インターフェースの addEventListener メソッドを利用して com.sun.star.lang.XEventListener
インターフェースをリスナーとして追加する。このリスナーはフレームが閉じられたときに disposing メソッドが呼ばれるため、そのイベントでフレームが閉じられるときを知ります。
UNO を実装する Python のコードは UTF-8 で改行コードを LF にしておくとエラー無く利用できます (改行コードに CR が含まれると不明なエラーの基になります)。
拡張機能に含まれているコードと行番号が違っているかもしれません。
宣言部 
uno.py を createUnoStruct などの利用のために、unohelper.py を登録のためにインポートします。また、UNO コンポーネントなどが継承するインターフェースもインポートしておきます。
handler.py ファイル
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| #!
# -*- coding: utf_8 -*-
import uno
import unohelper
#interfaces
from com.sun.star.frame import XControlNotificationListener
from com.sun.star.frame import XDispatch
from com.sun.star.frame import XDispatchProvider
from com.sun.star.lang import XEventListener
from com.sun.star.lang import XInitialization
from com.sun.star.lang import XServiceInfo
# handled protocol by this component
HANDLED_PROTOCOL = "mytools.handler:"
# implementation name of this component
PROTOCOLHANDLER_IMPLEMENTATIONNAME = "mytools.handler.Test"
|
コード内で利用するプロトコルは一律 (mytools.handler:) なので定義しておきます。実装名も同様です。
ヘルパークラス 
値を保存しておくために利用するクラスです。あとでグローバル変数としてインスタンス化する必要があるので先にクラスを定義しておきます。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # this helper retains something for toolbar control
class Helper(unohelper.Base):
def __init__(self):
# self.listeners store something for each frame
self.listeners = []
return
# set value of the control indicated by Path
def setValue(self,xFrame,Path,Value):
for listener in self.listeners:
if listener["frame"] == xFrame:
listener["values"][Path] = Value
return
# get value of the control of Path
def getValue(self,xFrame,Path):
for listener in self.listeners:
if listener["frame"] == xFrame:
if listener["values"].has_key(Path):
return listener["values"][Path]
return None
|
setValue と getValue でフレームごと、パス指定でコントロールの値 (など) を保存、取得します。
XDispatch インターフェースを持つクラスのインスタンスが作成されたとき addDispatch メソッドでフレームを追加しておきます。さらに、フレームにイベントリスナーを追加します。フレームに追加するリスナーが disposing されるときが、フレームが閉じられるときです。
新しい XDispatch が登録されるとき一つのフレームに対して self.listeners リストに辞書を一つ用意します。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # when new frame is created (new toolbar with it controls is created)
# container: stores key: Path, value: XStatusListener
def addDispatch(self,xDispatch,xFrame,Path):
for listener in self.listeners:
if listener["frame"] == xFrame:
listener["dispatch"][Path] = xDispatch
return
# new item
elements = {"frame": xFrame, "dispatch": {}, "container": {},"values": {} }
elements["dispatch"][Path] = xDispatch
self.listeners.append(elements)
xFrame.addEventListener(ItemEventListener(xFrame))
return
# get its dipatch
def getDispatch(self,xFrame,Path):
for listener in self.listeners:
if listener["frame"] == xFrame:
if listener["dispatch"].has_key(Path):
return listener["dispatch"][Path]
break
return None
|
コントロールに対してコマンドを実行するときに次のメソッドを利用します。これは、イベントが起きたり dispatch が実行されたコントロール以外のコントロールに対して操作するときに利用します。
0
1
2
3
4
5
6
7
8
9
| # change status of the control of Path
def notify(self,xFrame,Path,aEvent):
for listener in self.listeners:
if listener["frame"] == xFrame:
if listener["container"].has_key(Path):
xControl = listener["container"][Path]
xControl.statusChanged(aEvent)
break
return
|
XStatusListener を追加します。このようにコントロールのリスナーを変数に保持しておくことで後から利用できるようにします。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # add control to container
def addListener(self,xFrame,xControl,Path):
for listener in self.listeners:
if listener["frame"] == xFrame:
listener["container"][Path] = xControl
break
return
# remove control from container
def removeListener(self,xFrame,xControl,Path):
for listener in self.listeners:
if listener["frame"] == xFrame:
container = listener["container"][Path]
for i in range(len(container)):
if container[i] is xControl:
try:
del container[i]
except:
pass
break
return
|
フレームに追加してフレームが閉じるときを知るために利用するリスナーです。フレーム (ドキュメント) が閉じるときにこのリスナーの disposing メソッドが呼ばれます。そのとき、所定のフレームの変数を開放、削除します。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # this listener could be dispose listeners when frame is closed
class ItemEventListener(
unohelper.Base,
XEventListener):
def __init__(self,xFrame):
self.frame = xFrame
# when frame closing, registerd listener is removed
def disposing(self,aEvent):
listeners = ListenerHelper.listeners
for i in range(len(listeners)):
if listeners[i]["frame"] == self.frame:
del listeners[i]
return
|
データなどの保存のための変数 
上記 Helper クラスのインスタンスをグローバル変数に入れて利用します。
0
1
| # to keep something
ListenerHelper = Helper()
|
プロトコルハンドラコンポーネント 
プロトコルハンドラを実装するメインのコンポーネントです。メインのはずですが簡単です。
プロトコルハンドラ (サービス com.sun.star.frame.ProtocolHandler
) 実装には次のインターフェースが必要です。
- XDispatchProvider
- XInitialization: 初期化用
また、XServiceInfo インターフェースはサービスを実装するときにコンポーネントに必要です。実際は XTypeProvider も実装するべきです。(Py-UNO でのコンポーネントは unohelper.Base を継承すれば、登録情報から自動的に登録されます。)
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # component implementation class
class TestProtocolHandler(unohelper.Base,
XServiceInfo,
XDispatchProvider,
XInitialization):
def __init__(self,ctx):
self.ctx = ctx
self.smgr = ctx.ServiceManager
self.frame = None
return
# XInitialization
def initialize(self,objects):
if len(objects) > 0:
self.frame = objects[0]
return
|
inilialize メソッドがプロトコルハンドラ初期化時に呼ばれ、フレームオブジェクトへの参照が渡されます。ドキュメントにアクセスするためにこのフレームへの参照を保存しておきます。フレーム - コントローラ - (ドキュメント) モデルと順を経てドキュメントにアクセスできます。
XDispatchProvider インターフェースのメソッド queryDispatch では、正しいプロトコル+パスの URL が渡されたとき XDispatch インターフェースを返します (その他の条件が必要であれば判断する)。ツールバーで作成した三つのコントロールのパスはそれぞれ "edit"、"button"、"spin" です。XDispatch インターフェースを実装するのは別のクラスとしています。
queryDispatch メソッドが呼ばれるのは、ドキュメントのフレームが作成されてツールバーマネージャからツールバーが作成されたときです。この時点でフレームが利用できるので、このフレームへの参照を ListenerHelper 変数に保存しておきます。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # XDispatchProvider
def queryDispatch(self,aURL,name,flag):
dispatch = None
if aURL.Protocol == HANDLED_PROTOCOL:
if aURL.Path in ["button","edit","spin"]:
dispatch = BaseDispatch(self.ctx,self.frame)
ListenerHelper.addDispatch(dispatch,self.frame,aURL.Path)
return dispatch
# XDispatchProvider
def queryDispatches(self,descs):
dispatchers = []
for desc in descs:
dispatchers.append(
self.queryDispatch(desc.FeatureURL,desc.FrameName,desc.SearchFlags))
return tuple(dispatchers)
|
サービスの情報定義部分です。
0
1
2
3
4
5
6
7
8
| # XServiceInfo
def supportsService(self,name):
return (name == "com.sun.star.frame.ProtocolHandler")
# XServiceInfo
def getImplementationName(self):
return PROTOCOLHANDLER_IMPLEMENTATIONNAME
# XServiceInfo
def getSupportedServiceNames(self):
return ("com.sun.star.frame.ProtocolHandler",)
|
XDispatch インターフェースなど 
コントロールが実行されたり、コントロールのイベントの通知を処理するために利用するクラスです。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
| # dispatch base
class BaseDispatch(unohelper.Base,
XDispatch,
XControlNotificationListener):
def __init__(self,ctx,frame):
self.ctx = ctx
self.smgr = ctx.ServiceManager
self.frame = frame
self.doc = None
controller = self.frame.Controller
if controller:
self.doc = controller.Model
|
コントロールが実行されるときに呼ばれる dispatch メソッドです。button はボタンがマウスでクリックされたときに、edit はテキストフィールドでエンターキーが押されたときに実行されます。このときの二番目の引数は com.sun.star.beans.PropertyValue のシークエンスです。実行時の引数関してはコントロール実行時引数を参照してください。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # XDispatch
# do dispatch when control actioned
def dispatch(self,aURL,args):
if aURL.Protocol == HANDLED_PROTOCOL:
if aURL.Path == "button":
self.insertText()
elif aURL.Path == "edit":
self.insertText()
elif aURL.Path == "spin":
for arg in args:
# value changed by the buttons of the spin control
if arg.Name == "Value":
value = int(arg.Value)
ListenerHelper.setValue(
self.frame,aURL.Path,value)
return
|
ボタンが押されたとき、またはテキストフィールドでエンターキーが押されたときに insertText で文字列を Writer ドキュメントに書き込みます。スピンボタンが押されたときスピンコントロールが実行されたことになります。
コントロールの初期化と値の変更 
ここでツールバーコントロールを初期化できます。コントロールにリスナーを追加するために addStatusListener メソッドが呼ばれます。そのとき XStatusListener が引数として渡さされます。コントロールへの変更はステータスの変更とにより行います。
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
| # add status listener
# this is called when the toolbar is instantiated
def addStatusListener(self,xControl,aURL):
if aURL.Protocol == HANDLED_PROTOCOL:
if aURL.Path == "edit":
aNamedValue = self.makeNamedValue("Text","string ")
self.sendCommand(xControl,aURL,"SetText",(aNamedValue,))
elif aURL.Path == "spin":
aNamedValue1 = self.makeNamedValue("Value",1)
aNamedValue2 = self.makeNamedValue("Step",1)
aNamedValue3 = self.makeNamedValue("LowerLimit",1)
aNamedValue4 = self.makeNamedValue("UpperLimit",100)
#aNamedValue5 = self.makeNamedValue("OutputFormat","0.0")
self.sendCommand(xControl,aURL,"SetValues",
(aNamedValue1,aNamedValue2,aNamedValue3,aNamedValue4))
ListenerHelper.addListener(self.frame,xControl,aURL.Path)
return
def removeStatusListener(self,xControl,aURL):
ListenerHelper.removeListener(self.frame.xControl,aURL.Path)
return
|
ステータス変更を com.sun.star.frame.FeatureStateEvent
構造体で知らせることで変更します。それぞれの値は次のようになります。
- FeatureURL: 変更するコントロールの URL
- IsEnabled: コントロールの有効化
- Requery: XDispatch が必要かどうか
- State: 変更後の新しい状態
- Source: XDispatch インターフェース
State にコントロールコマンドを com.sun.star.frame.ControlCommand
で指定します。
- Command: コントロールを操作するコマンド
- Arguments: 操作時の値
コマンドは各コントロールにより異なります。コントロールコマンドの項目を参照してください。
上記ではテキストフィールドに値を設定するために次のようにしています。
if aURL.Path == "edit":
aNamedValue = self.makeNamedValue("Text","string ")
self.sendCommand(xControl,aURL,"SetText",(aNamedValue,))
コマンド "SetText" でテキストの変更を送信、引数は NamedValue で Name: Text、Value: "string " です。これを実行するとテキストフィールドに "string " の文字が設定されます。
コマンドの送信によるステータスの変更は次のメソッドで statusChanged メソッドを呼び出すことで実際に行います。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # send command to control herself
def sendCommand(self,xControl,aURL,aCmd,Args,Enabled=True):
aEvent = uno.createUnoStruct(
"com.sun.star.frame.FeatureStateEvent")
aControlCmd = uno.createUnoStruct(
"com.sun.star.frame.ControlCommand")
aControlCmd.Command = aCmd
aControlCmd.Arguments = Args
aEvent.FeatureURL = aURL
aEvent.IsEnabled = Enabled
aEvent.Requery = False
aEvent.Source = self
aEvent.State = aControlCmd
xControl.statusChanged(aEvent)
return
|
イベントによる操作の時にはコントロールの XStatusListener が直接利用できます。しかし、イベントが発生したコントロール以外の操作では保存しておいたコントロールの XStatusListener を利用します。sendCommandTo では変数に入れておいたものを利用してステータスの変更を指定したコントロールに通知します。
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
| # send command to the control indicated by aURL.Path
def sendCommandTo(self,aURL,aCmd,Args,Enabled=True):
aEvent = uno.createUnoStruct(
"com.sun.star.frame.FeatureStateEvent")
aControlCmd = uno.createUnoStruct(
"com.sun.star.frame.ControlCommand")
if aCmd != "":
aControlCmd.Command = aCmd
aControlCmd.Arguments = Args
aEvent.State = aControlCmd
else:
aEvent.State = None
aEvent.FeatureURL = aURL
aEvent.IsEnabled = Enabled
aEvent.Requery = False
aEvent.Source = self
ListenerHelper.notify(self.frame,aURL.Path,aEvent)
return
# create new com.sun.star.beans.NamedValue
def makeNamedValue(self,name,value):
aNamedValue = uno.createUnoStruct("com.sun.star.beans.NamedValue")
aNamedValue.Name = name
aNamedValue.Value = value
return aNamedValue
|
コントロールのイベント 
コントロールでイベントが発生したときに呼ばれる controlEvent メソッドです。メソッドの引数は com.sun.star.frame.ControlEvent
です。ツールバーのコントロールの値を取得できるのはここでのみです。そのため、ここで値の変更を受け取ったら、値を変数に保存しておきます。
テキストフィールド edit とスピンボタン spin の値の変更を受け取り、ListenerHelper に値を保存しています。このとき、フレーム、コントロールのパスに対して値を保持します。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # XControlNotificationListener
def controlEvent(self,Event):
if Event.aURL.Protocol == HANDLED_PROTOCOL:
if Event.aURL.Path == "edit":
if Event.Event == "TextChanged":
for named in Event.aInformation:
if named.Name == "Text":
ListenerHelper.setValue(
self.frame,Event.aURL.Path,str(named.Value))
elif Event.aURL.Path == "spin":
if Event.Event == "TextChanged":
for named in Event.aInformation:
if named.Name == "Text":
value = int(named.Value)
if 0 < value <= 100:
ListenerHelper.setValue(
self.frame,Event.aURL.Path,value)
return
|
コントロールが実行されたとき dispatch から利用するプライベート関数です。保存してあるコントロールの値を取り出して Writer ドキュメントに書き込みます。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # insert some text
def insertText(self):
txt = ListenerHelper.getValue(self.frame,"edit")
value = int(ListenerHelper.getValue(self.frame,"spin"))
if txt and value:
self.WriteText(txt * value)
return
# insert text at the selected position
def WriteText(self,txt):
controller = self.frame.Controller
if controller:
doc = controller.getModel()
text = doc.getText()
viewCursor = controller.getViewCursor()
viewCursor.setString(txt)
viewCursor.collapseToEnd()
return
|
UNO コンポーネントの登録 
Py-UNO のコンポーネント登録のための情報です。unohelper.py で定義されている ImplementationHelper を利用して容易に登録情報を作成できます。addImplementation メソッドに、コンポーネントを実際に実装するクラス、実装名、サービス名 (タプルで) を与えます。
0
1
2
3
4
| # register information
g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(
TestProtocolHandler,
PROTOCOLHANDLER_IMPLEMENTATIONNAME,
("com.sun.star.frame.ProtocolHandler",),)
|
コントロール操作用コマンド 
操作用コマンドの一覧です。コマンドは OOo のソースコード framework/source/uielement 以下のファイルなどからから抜き出したものです。
コントロール | コマンド | 引数 | 説明 |
Button | | | なし |
Combobox | SetText | Text = string | テキストを設定する |
SetList | List = []string | リストを設定する |
AddEntry | Text = string | 項目を追加する |
InsertEntry | Text = string, Pos = long | 項目を挿入する |
RemoveEntryPos | Pos = long | 項目を削除する |
RemoveEntryText | Text = string | 項目を削除する |
SetDropDownLines | Lines = long | ドロップダウン行数を設定する |
SetBackgroundColor | Color = Long | 背景色を設定する |
SetTextColor | Color = Long | 文字色を設定する |
Dropdownbox | SetList | List = []string | リストを設定する |
AddEntry | Text = string | 項目を追加する |
InsertEntry | Text = string, Pos = long | 項目を挿入する |
RemoveEntryPos | Pos = long | 項目を削除する |
RemoveEntryText | Text = string | 項目を削除する |
SetDropDownLines | Lines = long | ドロップダウン行数を設定する |
DropdownButton | SetList | List = []string | リストを設定する |
CheckItemPos | Pos = long | アイテムにチェックを入れる |
AddEntry | Text = string | 項目を追加する |
InsertEntry | Text = string, Pos = long | 項目を挿入する |
RemoveEntryPos | Pos = long | 項目を削除する |
RemoveEntryText | Text = string | 項目を削除する |
Editfield | SetText | Text = string | 文字列を設定する |
ImageButton | SetImage | URL = string | 画像を変更する |
Spinfield | SetStep | Step = long | ステップ値を変更する |
SetValue | Value = long | 値を設定する |
SetValues | Value = long, Step = long, LowerLimit = long, UpperLimit = long, OutputFormat = string | 設定値を変更する |
SetLowerLimit | LowerLimit = long | 下限値を変更する |
SetUpperLimit | UpperLimit = long | 上限値を変更する |
SetOutputFormat | OutputFormat = string | 表示フォーマットを変更する |
ToggleDropdownButton | SetList | List = []string | リストを設定する |
CheckItemPos | Pos = long | アイテムにチェックを入れる |
AddEntry | Text = string | 項目を追加する |
InsertEntry | Text = string, Pos = long | 項目を挿入する |
RemoveEntryPos | Pos = long | 項目を削除する |
RemoveEntryText | Text = string | 項目を削除する |
コントロールのイベント 
コントロールで発生するイベント名と引数の一覧です。イベント名と引数のセットは com.sun.star.beans.NamedValue
のシークエンスです。
これらは OOo のソースコード framework/source/uielement 以下のファイルなどからから抜き出したものです。
コントロール | イベント | 引数 | 説明 |
Button | | | |
Combobox | ListChanged | List = []string | リストの変更 |
TextChanged | Text = string | テキストの変更 |
FocusSet | | フォーカスイン |
FocusLost | | フォーカスアウト |
DropdownBox | ListChanged | List = []string | リストの変更 |
FocusSet | | フォーカスイン |
FocusLost | | フォーカスアウト |
DropdownButton | ListChanged | List = []string | リストの変更 |
Pos | ItemChecked = long | 選択アイテムの変更 |
Editfield | TextChanged | Text = string | テキストの変更 |
FocusSet | | フォーカスイン |
FocusLost | | フォーカスアウト |
ImageButton | ImageChanged | URL = string | 画像の変更 |
Spinfield | TextChanged | Text = string | テキストの変更 |
FocusSet | | フォーカスイン |
FocusLost | | フォーカスアウト |
ToggleDropdownButton | ListChanged | List = []string | リストの変更 |
Pos | ItemChecked = long | 選択アイテムの変更 |
コントロール実行時引数 
コントロールが実行されたとき dispatch メソッドが呼ばれます。そのときの引数の値の種類一覧です。引数は com.sun.star.beans.PropertyValue のシークエンスです。
これらは OOo のソースコード framework/source/uielement 以下のファイルなどからから抜き出したものです。
コントロール | 引数 | 説明 |
Button | KeyModifire = long | ボタン動作時 |
Combobox | Text = string, KeyModifire = long | コンボボックス動作時 |
DropdownBox | Text = string, KeyModifire = long | ドロップダウンボックス項目選択時 |
Editfield | Text = string, KeyModifire = long | テキストフィールド動作時 |
ImageButton | KeyModifire = long | ボタン動作時 |
Spinfield | Value = long/double, KeyModifire = long | スピン値変更時 |
ToggleDropdownButton | Text = string, KeyModifire = long | ボタン動作時 |
拡張機能パッケージの作成 
UNO コンポーネント、アドオンツールバー、プロトコルハンドラを使えるようにするには拡張機能パッケージを作成して OpenOffice.org にインストールしなければいけません。
上記で作成した各ファイル以外に拡張機能パッケージに使うファイルを用意します。
各ファイルの詳細は拡張機能パッケージ?を参照してください。
description.xml 
拡張機能ファイルの識別子やバージョン、依存性を設定するファイルです。必ずしも必要というわけではありませんが作成するべきです。
- 識別子 identifier: 拡張機能のパッケージに独自の ID を与えて他の拡張機能と区別するためのものです。ここでは mytools.complextoolbar.test としています。
- バージョン version: 拡張機能マネージャが認識するパッケージのバージョンです。0.0.1
- 依存性 dependencies: OOo のバージョンに依存する場合に利用します。複雑なツールバーの Addons.xcu ファイルは OOo 2.2 以降でサポートされてるので 2.2 以降としています。
0
1
2
3
4
5
6
7
8
| <?xml version="1.0" encoding="UTF-8"?>
<description xmlns="http://openoffice.org/extensions/description/2006"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:d="http://openoffice.org/extensions/description/2006">
<identifier value="mytools.complextoolbar.test" />
<version value="0.0.1" />
<dependencies>
<OpenOffice.org-minimal-version value="2.2" d:name="OpenOffice.org 2.2" />
</dependencies>
</description>
|
META-INF/manifest.xml 
拡張機能パッケージに含まれるファイルの種類を拡張機能マネージャに教える必要があるファイルに関して記述します。
設定が必要なのは UNO コンポーネントのファイル、設定ファイル (Addons.xcu および ProtocolHandler.xcu) です。それぞれ次のような種類になります。
- handler.py: application/vnd.sun.star.uno-component;type=Python
- Addons.xcu: application/vnd.sun.star.configuration-data
- ProtocolHandler.xcu: application/vnd.sun.star.configuration-data
0
1
2
3
4
5
6
7
| <?xml version="1.0" encoding="UTF-8"?>
<manifest:manifest>
<manifest:file-entry manifest:full-path="handler.py"
manifest:media-type="application/vnd.sun.star.uno-component;type=Python"/>
<manifest:file-entry manifest:full-path="Addons.xcu"
manifest:media-type="application/vnd.sun.star.configuration-data"/>
<manifest:file-entry manifest:full-path="ProtocolHandler.xcu"
manifest:media-type="application/vnd.sun.star.configuration-data"/>
</manifest:manifest>
|
パッケージ化 
拡張機能パッケージは ZIP アーカイブです。ファイルの構成を次のように配置されるように ZIP ファイルを作成します。manifest.xml で指定した位置にファイルを配置します。
- handler.py
- Addons.xcu
- ProtocolHandler.xcu
- description.xml
- META-INF / - manifest.xml
ZIP アーカイブを作成したらファイル名を mytools_ComplexToolbar-0.0.1oxt などに変更します。
インストール 
作成したパッケージを OOo の拡張機能マネージャからインストールします。
アンインストールも同様に行います。
ツールバーの利用 
Py-UNO で作成したコンポーネントを正しく動作させるためには OOo を再起動させます。クイックスタートを利用している場合は一度停止させます。
作成したツールバーは Writer でのみ表示されるコントロールで構成されているので、Writer を起動します。正しく表示され、すべてのコントロールが有効であればツールバーの作成およびプロトコルハンドラが正しく実装されていることになります。
ツールバーが表示されないときは Addons.xcu ファイルに不備があるかもしれません。
また、ツールバーが表示されるがコントロールが有効になっていないときは (初期化時に無効化していないとき)、プロトコルハンドラに不具合があるかもしれません。
パッケージ 
mytools_ComoplexToolbar-0.0.1.oxt
コメント 
意味分からんといったコメントはここへ。