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のメソッド一覧


LibreOffice5(35)unoinsp.py:PyDevパッケージで管理するのunoinspでConfigurationProviderのインスタンスのメソッド一覧を取得しました。
pyuno object
├─.configuration.DefaultProvider
│   │   boolean  EnableAsync
│   ├─.lang.XLocalizable
│   │   │   .lang.Locale  getLocale()
│   │   │           void  setLocale( [in] .lang.Locale eLocale)
│   │   └─.uno.XInterface
│   │               void  acquire()
│   │                any  queryInterface( [in] type aType)
│   │               void  release()
│   ├─.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()
├─.lang.XServiceInfo
│           string  getImplementationName()
│         [string]  getSupportedServiceNames()
│          boolean  supportsService( [in] string ServiceName)
├─.lang.XTypeProvider
│         [byte]  getImplementationId()
│         [type]  getTypes()
└─.uno.XWeak
            .uno.XAdapter  queryAdapter()

com.sun.star.configuration.ConfigurationAccessのメソッド一覧


同様にしてConfigurationAccessのメソッドの一覧を取得しました。

とてもたくさんメソッドがあります。

メソッドがないように見えるサービスはすでに出力済のメソッドしかないもののはずです。
pyuno object
├─.configuration.ConfigurationAccess
│   ├─.configuration.AccessRootElement
│   │   ├─.lang.XComponent
│   │   │   │   void  addEventListener( [in] .lang.XEventListener xListener)
│   │   │   │   void  dispose()
│   │   │   │   void  removeEventListener( [in] .lang.XEventListener aListener)
│   │   │   └─.uno.XInterface
│   │   │               void  acquire()
│   │   │                any  queryInterface( [in] type aType)
│   │   │               void  release()
│   │   ├─.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.HierarchyElement
│   │         ├─.beans.XProperty
│   │         │         .beans.Property  getAsProperty()
│   │         ├─.beans.XPropertyWithState
│   │         │              .uno.XInterface  getDefaultAsProperty()
│   │         │         .beans.PropertyState  getStateAsProperty()
│   │         │                         void  setToDefaultAsProperty()
│   │         ├─.container.XChild
│   │         │         .uno.XInterface  getParent()
│   │         │                    void  setParent( [in] .uno.XInterface Parent
│   │         │                          ) raises ( .lang.NoSupportException)
│   │         ├─.container.XHierarchicalName
│   │         │         string  composeHierarchicalName( [in] string aRelativeName
│   │         │                               ) raises ( .lang.NoSupportException,
│   │         │                                          .lang.IllegalArgumentException)
│   │         │         string  getHierarchicalName()
│   │         └─.container.XNamed
│   │                     string  getName()
│   │                       void  setName( [in] string aName)
│   ├─.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.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.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
│   │   └─.configuration.HierarchyElement
│   ├─.configuration.HierarchyAccess
│   ├─.configuration.HierarchyElement
│   ├─.configuration.SetAccess
│   │   ├─.configuration.HierarchyAccess
│   │   └─.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()
│         └─.configuration.HierarchyElement
├─.beans.XHierarchicalPropertySetInfo
│         .beans.Property  getPropertyByHierarchicalName( [in] string aHierarchicalName
│                                              ) raises ( .beans.UnknownPropertyException)
│                 boolean  hasPropertyByHierarchicalName( [in] string aHierarchicalName)
├─.lang.XServiceInfo
│           string  getImplementationName()
│         [string]  getSupportedServiceNames()
│          boolean  supportsService( [in] string ServiceName)
├─.lang.XTypeProvider
│         [byte]  getImplementationId()
│         [type]  getTypes()
├─.uno.XWeak
│         .uno.XAdapter  queryAdapter()
└─.util.XChangesBatch
                        void  commitChanges()
            .util.ChangesSet  getPendingChanges()
                     boolean  hasPendingChanges()

参考にしたサイト


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 件のコメント:

コメントを投稿