Top > OOoPython > UNOComponent

UNO コンポーネント Edit

Python-UNO では UNO コンポーネントの作成もできます。UNO コンポーネントでは次のようなものがよく知られています。

  • Calc アドイン関数
  • チャートアドイン
  • スマートタグ

これらは既存のサービスを利用、拡張して作成されるコンポーネントです。こういったもの以外にも Py-UNO では新たなサービス、インターフェースを実装できます。新規なサービスやインターフェースを実装するにはやはり IDL を定義しなければいけません (Calc アドイン関数では インターフェースの IDL を書かなければいけません)。

簡単なコンポーネントの作成 Edit

ここでは簡単な UNO コンポーネントを作成します。IDL を定義しないで済むように既存のインターフェースを利用します。

サービスとして実装される UNO コンポーネントに com.sun.star.task.XJobExecutor インターフェースを実装しておくと、メニューの項目などから簡単にマクロなどのように利用できます。

UNO コンポーネントは次のようなインターフェースを実装しているべきです。

XTypeProvider は unohelper.Base クラスを継承してやると自分で実装しなくても済みます。

XJobExecutor インターフェース Edit

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 コンポーネント作成 Edit

実際に UNO コンポーネントを実装します。

まずは宣言部分です。日本語を含むときにはエンコードを指定しておきます。

インポートするモジュールは次のものです。

  • uno: createUnoStruct を利用。
  • unohelper: unohelper.Base クラスの継承およびサービスの登録に利用。
  • time: python の標準ライブラリです。
  • 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 メソッドに次の三つの引数を与えます。

  1. コンポーネントを実際に実装するクラス
  2. 実装名を string で
  3. コンポーネントが提供するサービス名を string のタプルで
  0
  1
  2
  3
  4
  5
# uno implementation
g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(
    TestComponent,
    IMPLEMENTATION_NAME,
    ("com.sun.star.task.JobExecutor",),)

コンポーネントの配置 Edit

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 などに変更します。

インストール Edit

作成した拡張機能パッケージはツール - 拡張機能マネージャからインストールします。 インストール後、OOo を一度再起動します。クイックスタートを利用しているのであれば一度終了させてください。

実行 Edit

作成したコンポーネントを実行してみます。

とりあえず、コンポーネントを 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 拡張機能で容易にできます。

パッケージ Edit

fileTestComponent.oxt


Attach file: fileTestComponent.oxt 1034 download [Information]

Reload   New Lower page making Edit Freeze Diff Upload Copy Rename   Front page List of pages Search Recent changes Backup   Help   RSS of recent changes