LibreOffice5(48)Javaの例:ConfigExamplesをPythonにする その1

LibreOffice 5.3 SDK - Developer's Guide ExamplesのConfigExamplesをやります。LibreOfficeの設定にアクセスする例です。Configuration Management - Apache OpenOffice Wikiの例になります。
p--q/ConfigExamplesが最終的にPythonに翻訳したものになります。

前の関連記事:LibreOffice5(47)拡張機能のソースをオートメーションでも実行する


Javaの例:ConfigExamplesを実行する


まずlinuxBean14.04(132)LibreOfiice5.2のSDKの例をコンパイルするでコンパイルしたものがCUIで動くか確認します。

setsdkenv_unixのランチャでTerminalを起動します。

cd Config

これでConfigExamplesがあるフォルダに移動します。

make ConfigExamples.run
--- starting example: reset group data -----------------------------
java.lang.NullPointerException
 at ConfigExamples.resetGridConfiguration(ConfigExamples.java:809)
 at ConfigExamples.resetGroupExample(ConfigExamples.java:331)
 at ConfigExamples.runExamples(ConfigExamples.java:156)
 at ConfigExamples.run(ConfigExamples.java:136)
 at ConfigExamples.main(ConfigExamples.java:108)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:606)
 at com.sun.star.lib.loader.Loader.main(Loader.java:132)

--- starting example: update set data ---------------
-  DISABLED: (the existing example does not work with this version) -
たくさんスクロールして最後にこれが出力されて終わります。

あとでわかりましたが、この部分は正常に動いていませんでした。

LibreOffice5(36)UNOコンポーネントのJavaの例:TestJavaComponentと同様にしてNetBeans8.0.2のプロジェクトにして実行できるようにしました。

これでJavaの動きを確認しながらPythonに翻訳しました。

ConfigExamples/configexamples.py at 048395d0b650f6186df561887c207d986f399579 · p--q/ConfigExamples

とりあえずざっくりJavaに沿ってPythonに訳したものです。

ConfigExamplesがやっていること: ConfigurationProviderを使う


ConfigExamplesでは最初にLibreOfficeをbootstrap()で起動してオートメーションで接続しています。

そしてcom.sun.star.configuration.ConfigurationProviderサービスをcreateInstanceWithContext()でインスタンス化しています。
def checkProvider(cp):
    if cp is None:
        print("No provider available. Cannot access configuration data.")
        return False
    try:
        if not cp.supportsService("com.sun.star.configuration.ConfigurationProvider"):      
            print("WARNING: The provider is not a 'com.sun.star.configuration.ConfigurationProvider'") 
        services = cp.getSupportedServiceNames()
        t = ("a ", str(services).strip("(),"), "") if len(services)==1 else ("", str(services).strip("()"), "s")
        print("The provider has {}{} service{}.".format(*t))
        print("Using provider implementation: {}.".format(cp.getImplementationName()))
        return True
    except RuntimeException:
        print("ERROR: Failure while checking the provider services.")
        traceback.print_exc()
        return False
checkProvider()でこのインスタンスについて調べています。

引数のcpはConfigurationProviderサービスのインスタンスです。

com.sun.star.configuration.ConfigurationProviderサービスをインスタンス化しているので当然にこのインスタンスはcom.sun.star.configuration.ConfigurationProviderサービスをサポートしていると考えるのですが、supportsService()メソッドでcom.sun.star.configuration.ConfigurationProviderサービスがサポートされているかを調べるとFalseが返ってきます。

ではどのサービスをサポートしているのかgetSupportedServiceNames()メソッドを実行してみるとcom.sun.star.configuration.DefaultProviderサービスが返ってきます。

getImplementationName()で返ってくる実装サービス名はcom.sun.star.comp.configuration.DefaultProviderです。

これはConfiguration - Apache OpenOffice Wikiに書いてある通りの com.sun.star.configuration.DefaultProviderサービスの実装名の付け方になります。

初めからcom.sun.star.configuration.DefaultProviderサービスでインスタンス化したときはsupportsService()メソッドでもcom.sun.star.configuration.DefaultProviderサービスが返ってきます。

LibreOffice: DefaultProvider Service ReferenceにはDefaultProviderはコンポーネントコンテクストのデフォルトのConfigurationProviderである、と書いてあるのでConfigurationProviderをインスタンス化してDefaultProviderのインスタンスが返ってきてもおかしなことではないわけですが、デフォルト以外の例があるのか調べてみたらLibreOffice: ConfigurationProvider Service Reference
のDetailed DescriptionにcreateInstanceWithContextAndArguments()でデータソースを指定できると書いてありました。(createInstanceWithContextAndArgumentsは誤植で正確にはcreateInstanceWithArgumentsAndContext ですね。)

その具体例は見つけられませんでした。

データソースを指定せずにConfigurationProviderをインスタンス化するとDefaultProviderのインスタンスが返ってくるわけです。

とりあえずDefaultProviderがまずソースにするデータはLibreOffice5(12)PythonでLibreOfficeのバージョン番号を得る方法でみたように/opt/libreoffice5.2/share/registry/main.xcdです。

そしてこのConfigurationProviderのインスタンスを使って5つの例を実行しています。

ConfigurationProviderサービスの利用例: 設定を読み込む


readDataExample() 
--- starting example: read grid option settings --------------------
Read grid options: [ Grid is VISIBLE; resolution = (1000,1000); subdivision = (1,1) ]
/org.openoffice.Office.Calc/Grid以下の設定を読み込んで出力しています。
<oor:component-schema oor:name="Calc" oor:package="org.openoffice.Office" xml:lang="en-US">
    <templates>...</templates>
    <component>
        <set oor:name="UnitConversion" oor:node-type="ConversionRule">
        <group oor:name="Content">...</group>
        <group oor:name="Layout">...</group>
        <group oor:name="Input">...</group>
        <group oor:name="Grid">
            <group oor:name="Option">
                <prop oor:name="SnapToGrid" oor:nillable="false" oor:type="xs:boolean">...</prop>
                <prop oor:name="SizeToGrid" oor:nillable="false" oor:type="xs:boolean">...</prop>
                <prop oor:name="VisibleGrid" oor:nillable="false" oor:type="xs:boolean">
                    <value>false</value>
                </prop>
                <prop oor:name="Synchronize" oor:nillable="false" oor:type="xs:boolean">...</prop>
                <group oor:name="XAxis">...</group>
                <group oor:name="YAxis">...</group>
            </group>
        <group oor:name="Resolution">
            <group oor:name="XAxis">
                <prop oor:name="Metric" oor:nillable="false" oor:type="xs:int">
                    <value>1000</value>
                </prop>
                <prop oor:name="NonMetric" oor:nillable="false" oor:type="xs:int">...</prop>
            </group>
            <group oor:name="YAxis">
                <prop oor:name="Metric" oor:nillable="false" oor:type="xs:int">
                    <value>1000</value>
                </prop>
                <prop oor:name="NonMetric" oor:nillable="false" oor:type="xs:int">...</prop>
            </group>
        </group>
        <group oor:name="Subdivision">
            <prop oor:name="XAxis" oor:nillable="false" oor:type="xs:int">
                <value>1</value>
            </prop>
            <prop oor:name="YAxis" oor:nillable="false" oor:type="xs:int">
                <value>1</value>
            </prop>
        </group>
    </group></set></component></oor:component-schema>
DefaultProviderが読み込んでいるはずのmain.xcdの一部タグを展開して抽出しました。

xcdファイルの見方はLibreOffice5(30)xcsファイルとxcuファイルとxcdファイル:その1でやりました。

パッケージorg.openoffice.OfficeのコンポーネントCalcのコンポーネントスキーマノードにデフォル値が設定されています。

ハイライトしている行がreadDataExample()で読み込んで表示させているデータです。
def readGridConfiguration(cp):
    ca = createConfigurationView("/org.openoffice.Office.Calc/Grid", cp)
    visible = ca.getHierarchicalPropertyValue("Option/VisibleGrid")
    reso = ca.getHierarchicalPropertyValue("Resolution")
    reso_elems = reso.getHierarchicalPropertyValues(("XAxis/Metric", "YAxis/Metric"))
    sub = ca.getHierarchicalPropertyValue("Subdivision")
    sub_elems = sub.getPropertyValues(("XAxis", "YAxis"))
    ca.dispose()
    return GridOptions(visible, reso_elems[0], reso_elems[1], sub_elems[0], sub_elems[1])    
def createConfigurationView(path, cp):
    node = PropertyValue(Name="nodepath", Value=path)
    return cp.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", (node,))
まずConfigurationProviderのインスタンスのからcreateInstanceWithArguments()メソッドでパッケージorg.openoffice.OfficeとコンポーネントCalcをドットでつなげたパスを引数にしてConfigurationAccessサービスをインスタンス化しています。
(9行目のGridOptionsはnamedtupleを使っています。LibreOffice5(49)Javaの例:ConfigExamplesをPythonにする その2参照。)

あとはこのインスタンスのメソッドを使ってコンポーネントのサブノードにアクセスします。

getHierarchicalPropertyValue()   
XHierarchicalPropertySetインターフェイスのメソッド
引数は階層プロパティ名 

getHierarchicalPropertyValues() 
XMultiHierarchicalPropertySetインターフェイスのメソッド
引数は階層プロパティ名のタプル 

getPropertyValue()
XPropertySetインターフェイスのメソッド
引数はプロパティ名

getPropertyValues()
XMultiPropertySetインターフェイスのメソッド
引数はプロパティ名のタプル

階層プロパティ名はプロパティ名で置換できますが、逆はできません。

引数によってメソッドを使い分けないといけないのは面倒ですね。

もっとすっきりした方法を考えます。

まずConfigurationProviderとConfigurationAccessのメソッド一覧をみてみます。

com.sun.star.configuration.ConfigurationProviderのサービスとインターフェイスの一覧

def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 tcu = smgr.createInstanceWithContext("pq.Tcu", ctx)  # サービス名か実装名でインスタンス化。
 configurationprovider = smgr.createInstanceWithContext('com.sun.star.configuration.ConfigurationProvider', ctx)
 tcu.wtree(configurationprovider)
LibreOffice5(147)TCUの改良のTCUでConfigurationProviderのインスタンスのメソッド一覧を取得しました。

└─.configuration.DefaultProvider
  │   boolean  EnableAsync
  ├─.lang.XLocalizable
  │     .lang.Locale  getLocale()
  │             void  setLocale( [in] .lang.Locale eLocale)
  ├─.util.XFlushable
  │     void  addFlushListener( [in] .util.XFlushListener l)
  │     void  flush()
  │     void  removeFlushListener( [in] .util.XFlushListener l)
  ├─.util.XRefreshable
  │     void  addRefreshListener( [in] .util.XRefreshListener l)
  │     void  refresh()
  │     void  removeRefreshListener( [in] .util.XRefreshListener l)
  └─.configuration.ConfigurationProvider
     ├─.lang.XComponent
     │     void  addEventListener( [in] .lang.XEventListener xListener)
     │     void  dispose()
     │     void  removeEventListener( [in] .lang.XEventListener aListener)
     └─.lang.XMultiServiceFactory
           .uno.XInterface  createInstance( [in] string aServiceSpecifier
                                 ) raises ( .uno.Exception)
           .uno.XInterface  createInstanceWithArguments( [in] string ServiceSpecifier,
                                                         [in]  [any] Arguments
                                              ) raises ( .uno.Exception)
                  [string]  getAvailableServiceNames()

com.sun.star.configuration.ConfigurationAccessのサービスとインターフェイスの一覧


同様にしてConfigurationAccessのメソッドの一覧を取得しました。
from com.sun.star.beans import PropertyValue
def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 tcu = smgr.createInstanceWithContext("pq.Tcu", ctx)  # サービス名か実装名でインスタンス化。
 configurationprovider = smgr.createInstanceWithContext('com.sun.star.configuration.ConfigurationProvider', ctx)
 node = PropertyValue(Name = 'nodepath', Value = 'org.openoffice.Setup/Product' )  # share/registry/main.xcd内のノードパス。
 configurationaccess = configurationprovider.createInstanceWithArguments('com.sun.star.configuration.ConfigurationAccess', (node,))
 tcu.wtree(configurationaccess)
share/registry/main.xcd内のノードパスをConfigurationProviderに渡してConfigurationAccessを取得しています。

├─.configuration.ConfigurationAccess
│   ├─.configuration.AccessRootElement
│   │   ├─.lang.XComponent
│   │   │     void  addEventListener( [in] .lang.XEventListener xListener)
│   │   │     void  dispose()
│   │   │     void  removeEventListener( [in] .lang.XEventListener aListener)
│   │   ├─.lang.XLocalizable
│   │   │     .lang.Locale  getLocale()
│   │   │             void  setLocale( [in] .lang.Locale eLocale)
│   │   └─.util.XChangesNotifier
│   │        void  addChangesListener( [in] .util.XChangesListener aListener)
│   │        void  removeChangesListener( [in] .util.XChangesListener aListener)
│   ├─.configuration.GroupAccess
│   │   ├─.beans.XMultiPropertyStates
│   │   │                      [any]  getPropertyDefaults( [in] [string] aPropertyNames
│   │   │                                       ) raises ( .lang.WrappedTargetException,
│   │   │                                                  .beans.UnknownPropertyException)
│   │   │     [.beans.PropertyState]  getPropertyStates( [in] [string] aPropertyName
│   │   │                                     ) raises ( .beans.UnknownPropertyException)
│   │   │                       void  setAllPropertiesToDefault()
│   │   │                       void  setPropertiesToDefault( [in] [string] aPropertyNames
│   │   │                                          ) raises ( .beans.UnknownPropertyException)
│   │   ├─.beans.XPropertyState
│   │   │                        any  getPropertyDefault( [in] string aPropertyName
│   │   │                                      ) raises ( .lang.WrappedTargetException,
│   │   │                                                 .beans.UnknownPropertyException)
│   │   │       .beans.PropertyState  getPropertyState( [in] string PropertyName
│   │   │                                    ) raises ( .beans.UnknownPropertyException)
│   │   │     [.beans.PropertyState]  getPropertyStates( [in] [string] aPropertyName
│   │   │                                     ) raises ( .beans.UnknownPropertyException)
│   │   │                       void  setPropertyToDefault( [in] string PropertyName
│   │   │                                        ) raises ( .beans.UnknownPropertyException)
│   │   └─.configuration.PropertyHierarchy
│   │     ├─.beans.XHierarchicalPropertySet
│   │     │     .beans.XHierarchicalPropertySetInfo  getHierarchicalPropertySetInfo()
│   │     │                                     any  getHierarchicalPropertyValue( [in] string aHierarchicalPropertyName
│   │     │                                                             ) raises ( .lang.WrappedTargetException,
│   │     │                                                                        .lang.IllegalArgumentException,
│   │     │                                                                        .beans.UnknownPropertyException)
│   │     │                                    void  setHierarchicalPropertyValue( [in] string aHierarchicalPropertyName,
│   │     │                                                                        [in]    any aValue
│   │     │                                                             ) raises ( .lang.WrappedTargetException,
│   │     │                                                                        .lang.IllegalArgumentException,
│   │     │                                                                        .beans.PropertyVetoException,
│   │     │                                                                        .beans.UnknownPropertyException)
│   │     ├─.beans.XMultiHierarchicalPropertySet
│   │     │     .beans.XHierarchicalPropertySetInfo  getHierarchicalPropertySetInfo()
│   │     │                                   [any]  getHierarchicalPropertyValues( [in] [string] aPropertyNames
│   │     │                                                              ) raises ( .lang.WrappedTargetException,
│   │     │                                                                         .lang.IllegalArgumentException)
│   │     │                                    void  setHierarchicalPropertyValues( [in] [string] aHierarchicalPropertyNames,
│   │     │                                                                         [in]    [any] Values
│   │     │                                                              ) raises ( .lang.WrappedTargetException,
│   │     │                                                                         .lang.IllegalArgumentException,
│   │     │                                                                         .beans.PropertyVetoException)
│   │     ├─.beans.XMultiPropertySet
│   │     │                        void  addPropertiesChangeListener( [in]                         [string] aPropertyNames,
│   │     │                                                           [in] .beans.XPropertiesChangeListener xListener)
│   │     │                        void  firePropertiesChangeEvent( [in]                         [string] aPropertyNames,
│   │     │                                                         [in] .beans.XPropertiesChangeListener xListener)
│   │     │     .beans.XPropertySetInfo  getPropertySetInfo()
│   │     │                       [any]  getPropertyValues( [in] [string] aPropertyNames)
│   │     │                        void  removePropertiesChangeListener( [in] .beans.XPropertiesChangeListener xListener)
│   │     │                        void  setPropertyValues( [in] [string] aPropertyNames,
│   │     │                                                 [in]    [any] aValues
│   │     │                                      ) raises ( .lang.WrappedTargetException,
│   │     │                                                 .lang.IllegalArgumentException,
│   │     │                                                 .beans.PropertyVetoException)
│   │     └─.beans.XPropertySet
│   │                              void  addPropertyChangeListener( [in]                         string aPropertyName,
│   │                                                               [in] .beans.XPropertyChangeListener xListener
│   │                                                    ) raises ( .lang.WrappedTargetException,
│   │                                                               .beans.UnknownPropertyException)
│   │                              void  addVetoableChangeListener( [in]                         string PropertyName,
│   │                                                               [in] .beans.XVetoableChangeListener aListener
│   │                                                    ) raises ( .lang.WrappedTargetException,
│   │                                                               .beans.UnknownPropertyException)
│   │           .beans.XPropertySetInfo  getPropertySetInfo()
│   │                               any  getPropertyValue( [in] string PropertyName
│   │                                           ) raises ( .lang.WrappedTargetException,
│   │                                                      .beans.UnknownPropertyException)
│   │                              void  removePropertyChangeListener( [in]                         string aPropertyName,
│   │                                                                  [in] .beans.XPropertyChangeListener aListener
│   │                                                       ) raises ( .lang.WrappedTargetException,
│   │                                                                  .beans.UnknownPropertyException)
│   │                              void  removeVetoableChangeListener( [in]                         string PropertyName,
│   │                                                                  [in] .beans.XVetoableChangeListener aListener
│   │                                                       ) raises ( .lang.WrappedTargetException,
│   │                                                                  .beans.UnknownPropertyException)
│   │                              void  setPropertyValue( [in] string aPropertyName,
│   │                                                      [in]    any aValue
│   │                                           ) raises ( .lang.WrappedTargetException,
│   │                                                      .lang.IllegalArgumentException,
│   │                                                      .beans.PropertyVetoException,
│   │                                                      .beans.UnknownPropertyException)
│   ├─.configuration.GroupElement
│   │   └─.container.XChild
│   │        .uno.XInterface  getParent()
│   │                   void  setParent( [in] .uno.XInterface Parent
│   │                         ) raises ( .lang.NoSupportException)
│   ├─.configuration.HierarchyAccess
│   │   ├─.beans.XExactName
│   │   │     string  getExactName( [in] string aApproximateName)
│   │   ├─.beans.XPropertySetInfo
│   │   │     [.beans.Property]  getProperties()
│   │   │       .beans.Property  getPropertyByName( [in] string aName
│   │   │                                ) raises ( .beans.UnknownPropertyException)
│   │   │               boolean  hasPropertyByName( [in] string Name)
│   │   ├─.container.XContainer
│   │   │     void  addContainerListener( [in] .container.XContainerListener xListener)
│   │   │     void  removeContainerListener( [in] .container.XContainerListener xListener)
│   │   ├─.container.XHierarchicalNameAccess
│   │   │         any  getByHierarchicalName( [in] string aName
│   │   │                          ) raises ( .container.NoSuchElementException)
│   │   │     boolean  hasByHierarchicalName( [in] string aName)
│   │   └─.container.XNameAccess
│   │     │        any  getByName( [in] string aName
│   │     │             ) raises ( .lang.WrappedTargetException,
│   │     │                        .container.NoSuchElementException)
│   │     │   [string]  getElementNames()
│   │     │    boolean  hasByName( [in] string aName)
│   │     └─.container.XElementAccess
│   │              type  getElementType()
│   │           boolean  hasElements()
│   ├─.configuration.HierarchyElement
│   │   ├─.beans.XProperty
│   │   │     .beans.Property  getAsProperty()
│   │   ├─.beans.XPropertyWithState
│   │   │          .uno.XInterface  getDefaultAsProperty()
│   │   │     .beans.PropertyState  getStateAsProperty()
│   │   │                     void  setToDefaultAsProperty()
│   │   ├─.container.XHierarchicalName
│   │   │     string  composeHierarchicalName( [in] string aRelativeName
│   │   │                           ) raises ( .lang.NoSupportException,
│   │   │                                      .lang.IllegalArgumentException)
│   │   │     string  getHierarchicalName()
│   │   └─.container.XNamed
│   │        string  getName()
│   │          void  setName( [in] string aName)
│   ├─.configuration.SetAccess
│   │   └─.configuration.SimpleSetAccess
│   │     ├─.configuration.XTemplateContainer
│   │     │     string  getElementTemplateName()
│   │     └─.util.XStringEscape
│   │           string  escapeString( [in] string aString
│   │                      ) raises ( .lang.IllegalArgumentException)
│   │           string  unescapeString( [in] string aEscapedString
│   │                        ) raises ( .lang.IllegalArgumentException)
│   └─.configuration.SetElement
│     └─.configuration.XTemplateInstance
│           string  getTemplateName()
├─.beans.XHierarchicalPropertySetInfo
│     .beans.Property  getPropertyByHierarchicalName( [in] string aHierarchicalName
│                                          ) raises ( .beans.UnknownPropertyException)
│             boolean  hasPropertyByHierarchicalName( [in] string aHierarchicalName)
├─.util.XChangesBatch
│                 void  commitChanges()
│     .util.ChangesSet  getPendingChanges()
│              boolean  hasPendingChanges()
└──(サービスやインターフェイスに属しないプロパティ)
           string  ooName
             long  ooOpenSourceContext
           string  ooSetupExtension
           string  ooSetupVersion
           string  ooSetupVersionAboutBox
           string  ooSetupVersionAboutBoxSuffix
           string  ooVendor
           string  ooXMLFileFormatName
           string  ooXMLFileFormatVersion

「サービスやインターフェイスに属しないプロパティ」にでてくるプロパティはshare/registry/main.xcd内のノードパスにあるプロパティです。

参考にしたサイト


Configuration Management - Apache OpenOffice Wiki
ConfigExamplesに該当するデベロッパーガイドの章。

LibreOffice 5.3 SDK - Developer's Guide Examples
Javaの例のConfigExamplesをPythonに訳しています。

Configuration - Apache OpenOffice Wiki
実装サービス名の名づけ例。

Python の or と and 演算子の罠 - Qiita
PythonのorもJavaScriptの||と同様に使えそうです。

次の関連記事:LibreOffice5(49)Javaの例:ConfigExamplesをPythonにする その2

PR

0 件のコメント:

コメントを投稿