1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 package com.sun.star.comp.extensionoptions;
23 
24 import com.sun.star.lib.uno.helper.Factory;
25 import com.sun.star.lib.uno.helper.WeakBase;
26 import com.sun.star.lang.XMultiComponentFactory;
27 import com.sun.star.lang.XSingleComponentFactory;
28 import com.sun.star.lang.XMultiServiceFactory;
29 import com.sun.star.lang.WrappedTargetException;
30 import com.sun.star.lang.IllegalArgumentException;
31 import com.sun.star.lang.XInitialization;
32 import com.sun.star.lang.XTypeProvider;
33 import com.sun.star.lang.XServiceInfo;
34 import com.sun.star.lang.WrappedTargetException;
35 import com.sun.star.uno.UnoRuntime;
36 import com.sun.star.uno.Any;
37 import com.sun.star.uno.AnyConverter;
38 import com.sun.star.uno.XComponentContext;
39 import com.sun.star.uno.Exception;
40 import com.sun.star.registry.XRegistryKey;
41 import com.sun.star.awt.XContainerWindowEventHandler;
42 import com.sun.star.awt.XControl;
43 import com.sun.star.awt.XControlModel;
44 import com.sun.star.awt.XControlContainer;
45 import com.sun.star.container.XNameAccess;
46 import com.sun.star.container.NoSuchElementException;
47 import com.sun.star.beans.PropertyValue;
48 import com.sun.star.beans.PropertyState;
49 import com.sun.star.beans.XPropertySet;
50 import com.sun.star.beans.UnknownPropertyException;
51 import com.sun.star.beans.PropertyVetoException;
52 import com.sun.star.util.XChangesBatch;
53 
54 /** A handler which supports multiple options pages which all
55  *  have the same controls.
56  */
57 public class OptionsEventHandler {
58 
59     public static class _OptionsEventHandler extends WeakBase
60         implements XServiceInfo, XContainerWindowEventHandler {
61 
62         static private final String __serviceName =
63         "com.sun.star.comp.extensionoptions.OptionsEventHandler";
64 
65         private XComponentContext m_cmpCtx;
66 
67         private XMultiComponentFactory m_xMCF;
68 
69         private XNameAccess m_xAccessLeaves;
70 
71         /**Names of supported options pages.
72          */
73         private String[] m_arWindowNames = {
74             "Writer1", "Writer2", "Writer3", "Calc1", "Calc2", "Calc3",
75             "Draw1", "Draw2", "Draw3", "Node1_1", "Node1_2", "Node1_3",
76             "Node2_1", "Node2_2", "Node2_3", "Node3_1", "Node3_2", "Node3_3"};
77 
78         /**Names of the controls which are supported by this handler. All these
79          *controls must have a "Text" property.
80          */
81         private String[] m_arStringControls = {
82             "String0", "String1", "String2", "String3", "String4"};
83 
_OptionsEventHandler(XComponentContext xCompContext)84         public _OptionsEventHandler(XComponentContext xCompContext) {
85                 m_cmpCtx = xCompContext;
86                 m_xMCF = m_cmpCtx.getServiceManager();
87 
88             //Create the com.sun.star.configuration.ConfigurationUpdateAccess
89             //for the registry node which contains the data for our option
90             //pages.
91             XMultiServiceFactory xConfig;
92             try {
93                 xConfig = (XMultiServiceFactory) UnoRuntime.queryInterface(
94                     XMultiServiceFactory.class,
95                     m_cmpCtx.getServiceManager().createInstanceWithContext(
96                         "com.sun.star.configuration.ConfigurationProvider", m_cmpCtx));
97             } catch (com.sun.star.uno.Exception e) {
98                 e.printStackTrace();
99                 return;
100             }
101 
102             //One argument for creating the ConfigurationUpdateAccess is the "nodepath".
103             //Our nodepath point to the node of which the direct subnodes represent the
104             //different options pages.
105             Object[] args = new Object[1];
106             args[0] = new PropertyValue(
107                 "nodepath", 0, "/org.openoffice.desktop.deployment.options.ExtensionData/Leaves",
108                 PropertyState.DIRECT_VALUE);
109 
110             //We get the com.sun.star.container.XNameAccess from the instance of
111             //ConfigurationUpdateAccess and save it for later use.
112             try {
113                 m_xAccessLeaves = (XNameAccess) UnoRuntime.queryInterface(
114                     XNameAccess.class, xConfig.createInstanceWithArguments(
115                         "com.sun.star.configuration.ConfigurationUpdateAccess", args));
116 
117             } catch (com.sun.star.uno.Exception e) {
118                 e.printStackTrace();
119                 return;
120             }
121         }
122 
123         /** This method returns an array of all supported service names.
124          * @return Array of supported service names.
125          */
getSupportedServiceNames()126         public String[] getSupportedServiceNames() {
127             return getServiceNames();
128         }
129 
130         /** This method is a simple helper function to used in the
131          * static component initialisation functions as well as in
132          * getSupportedServiceNames.
133          */
getServiceNames()134         public static String[] getServiceNames() {
135             String[] sSupportedServiceNames = { __serviceName };
136             return sSupportedServiceNames;
137         }
138 
139         /** This method returns true, if the given service will be
140          * supported by the component.
141          * @param sServiceName Service name.
142          * @return True, if the given service name will be supported.
143          */
supportsService( String sServiceName )144         public boolean supportsService( String sServiceName ) {
145             return sServiceName.equals( __serviceName );
146         }
147 
148         /** Return the class name of the component.
149          * @return Class name of the component.
150          */
getImplementationName()151         public String getImplementationName() {
152             return  _OptionsEventHandler.class.getName();
153         }
154 
155         //XContainerWindowEventHandler
callHandlerMethod(com.sun.star.awt.XWindow aWindow, Object aEventObject, String sMethod)156         public boolean callHandlerMethod(com.sun.star.awt.XWindow aWindow,
157                                         Object aEventObject, String sMethod)
158             throws WrappedTargetException {
159             if (sMethod.equals("external_event") ){
160                 try {
161                     return handleExternalEvent(aWindow, aEventObject);
162                 } catch (com.sun.star.uno.RuntimeException re) {
163                     throw re;
164                 } catch (com.sun.star.uno.Exception e) {
165                     throw new WrappedTargetException(sMethod, this, e);
166                 }
167             }
168 
169             return true;
170         }
171 
172         //XContainerWindowEventHandler
getSupportedMethodNames()173         public String[] getSupportedMethodNames() {
174             return new String[] {"external_event"};
175         }
176 
handleExternalEvent(com.sun.star.awt.XWindow aWindow, Object aEventObject)177         private boolean handleExternalEvent(com.sun.star.awt.XWindow aWindow, Object aEventObject)
178             throws com.sun.star.uno.Exception {
179             try {
180                 String sMethod = AnyConverter.toString(aEventObject);
181                 if (sMethod.equals("ok")) {
182                     saveData(aWindow);
183                 } else if (sMethod.equals("back") || sMethod.equals("initialize")) {
184                     loadData(aWindow);
185                 }
186             } catch (com.sun.star.lang.IllegalArgumentException e) {
187                 throw new com.sun.star.lang.IllegalArgumentException(
188                     "Method external_event requires a string in the event object argument.",
189                     this, (short) -1);
190             }
191 
192             return true;
193         }
194 
saveData(com.sun.star.awt.XWindow aWindow)195         private void saveData(com.sun.star.awt.XWindow aWindow)
196             throws com.sun.star.lang.IllegalArgumentException,
197             com.sun.star.uno.Exception {
198 
199             //Determine the name of the options page. This serves two purposes. First, if this
200             //options page is supported by this handler and second we use the name two locate
201             //the corresponding data in the registry.
202             String sWindowName = getWindowName(aWindow);
203             if (sWindowName == null)
204                 throw new com.sun.star.lang.IllegalArgumentException(
205                     "This window is not supported by this handler", this, (short) -1);
206 
207             //To access the separate controls of the window we need to obtain the
208             //XControlContainer from the window implementation
209             XControlContainer xContainer = (XControlContainer) UnoRuntime.queryInterface(
210                 XControlContainer.class, aWindow);
211             if (xContainer == null)
212                 throw new com.sun.star.uno.Exception(
213                     "Could not get XControlContainer from window.", this);
214 
215             //This is an implementation which will be used for several options pages
216             //which all have the same controls. m_arStringControls is an array which
217             //contains the names.
218             for (int i = 0; i < m_arStringControls.length; i++) {
219 
220                 //To obtain the data from the controls we need to get their model.
221                 //First get the respective control from the XControlContainer.
222                 XControl xControl = xContainer.getControl(m_arStringControls[i]);
223 
224                 //This generic handler and the corresponding registry schema support
225                 //up to five text controls. However, if a options page does not use all
226                 //five controls then we will not complain here.
227                 if (xControl == null)
228                     continue;
229 
230                 //From the control we get the model, which in turn supports the
231                 //XPropertySet interface, which we finally use to get the data from
232                 //the control.
233                 XPropertySet xProp = (XPropertySet) UnoRuntime.queryInterface(
234                     XPropertySet.class, xControl.getModel());
235 
236                 if (xProp == null)
237                     throw new com.sun.star.uno.Exception(
238                         "Could not get XPropertySet from control.", this);
239                 //Get the "Text" property.
240                 Object aText = xProp.getPropertyValue("Text");
241                 String sValue = null;
242 
243                 //The value is still contained in a com.sun.star.uno.Any - so convert it.
244                 try {
245                     sValue = AnyConverter.toString(aText);
246                 } catch (com.sun.star.lang.IllegalArgumentException e) {
247                     throw new com.sun.star.lang.IllegalArgumentException(
248                         "Wrong property type.", this, (short) -1);
249                 }
250 
251                 //Now we have the actual string value of the control. What we need now is
252                 //the XPropertySet of the respective property in the registry, so that we
253                 //can store the value.
254                 //To access the registry we have previously created a service instance
255                 //of com.sun.star.configuration.ConfigurationUpdateAccess which supports
256                 //com.sun.star.container.XNameAccess. The XNameAccess is used to get the
257                 //particular registry node which represents this options page.
258                 //Fortunately the name of the window is the same as the registry node.
259                 XPropertySet xLeaf = (XPropertySet) UnoRuntime.queryInterface(
260                     XPropertySet.class, m_xAccessLeaves.getByName(sWindowName));
261                 if (xLeaf == null)
262                     throw new  com.sun.star.uno.Exception(
263                         "XPropertySet not supported.", this);
264 
265                 //Finally we can set the value
266                 xLeaf.setPropertyValue(m_arStringControls[i], sValue);
267             }
268 
269             //Committing the changes will cause or changes to be written to the registry.
270             XChangesBatch xUpdateCommit =
271                 (XChangesBatch) UnoRuntime.queryInterface(XChangesBatch.class, m_xAccessLeaves);
272             xUpdateCommit.commitChanges();
273         }
274 
loadData(com.sun.star.awt.XWindow aWindow)275         private void loadData(com.sun.star.awt.XWindow aWindow)
276             throws com.sun.star.uno.Exception {
277 
278             //Determine the name of the window. This serves two purposes. First, if this
279             //window is supported by this handler and second we use the name two locate
280             //the corresponding data in the registry.
281             String sWindowName = getWindowName(aWindow);
282             if (sWindowName == null)
283                 throw new com.sun.star.lang.IllegalArgumentException(
284                     "The window is not supported by this handler", this, (short) -1);
285 
286             //To acces the separate controls of the window we need to obtain the
287             //XControlContainer from window implementation
288             XControlContainer xContainer = (XControlContainer) UnoRuntime.queryInterface(
289                 XControlContainer.class, aWindow);
290             if (xContainer == null)
291                 throw new com.sun.star.uno.Exception(
292                     "Could not get XControlContainer from window.", this);
293 
294             //This is an implementation which will be used for several options pages
295             //which all have the same controls. m_arStringControls is an array which
296             //contains the names.
297             for (int i = 0; i < m_arStringControls.length; i++) {
298 
299                 //load the values from the registry
300                 //To access the registry we have previously created a service instance
301                 //of com.sun.star.configuration.ConfigurationUpdateAccess which supports
302                 //com.sun.star.container.XNameAccess. We obtain now the section
303                 //of the registry which is assigned to this options page.
304                 XPropertySet xLeaf = (XPropertySet) UnoRuntime.queryInterface(
305                     XPropertySet.class, m_xAccessLeaves.getByName(sWindowName));
306                 if (xLeaf == null)
307                     throw new  com.sun.star.uno.Exception(
308                         "XPropertySet not supported.", this);
309 
310                 //The properties in the registry have the same name as the respective
311                 //controls. We use the names now to obtain the property values.
312                 Object aValue = xLeaf.getPropertyValue(m_arStringControls[i]);
313 
314                 //Now that we have the value we need to set it at the corresponding
315                 //control in the window. The XControlContainer, which we obtained earlier
316                 //is the means to get hold of all the controls.
317                 XControl xControl = xContainer.getControl(m_arStringControls[i]);
318 
319                 //This generic handler and the corresponding registry schema support
320                 //up to five text controls. However, if a options page does not use all
321                 //five controls then we will not complain here.
322                 if (xControl == null)
323                     continue;
324 
325                 //From the control we get the model, which in turn supports the
326                 //XPropertySet interface, which we finally use to set the data at the
327                 //control
328                 XPropertySet xProp = (XPropertySet) UnoRuntime.queryInterface(
329                     XPropertySet.class, xControl.getModel());
330 
331                 if (xProp == null)
332                     throw new com.sun.star.uno.Exception(
333                         "Could not get XPropertySet from control.", this);
334 
335                 //This handler supports only text controls, which are named "Pattern Field"
336                 //in the dialog editor. We set the "Text" property.
337                 xProp.setPropertyValue("Text", aValue);
338             }
339         }
340 
341         //Checks if the name property of the window is one of the supported names and returns
342         //always a valid string or null
getWindowName(com.sun.star.awt.XWindow aWindow)343         private String getWindowName(com.sun.star.awt.XWindow aWindow)
344             throws com.sun.star.uno.Exception {
345 
346             if (aWindow == null)
347                 new com.sun.star.lang.IllegalArgumentException(
348                     "Method external_event requires that a window is passed as argument",
349                     this, (short) -1);
350 
351             //We need to get the control model of the window. Therefore the first step is
352             //to query for it.
353             XControl xControlDlg = (XControl) UnoRuntime.queryInterface(
354                 XControl.class, aWindow);
355 
356             if (xControlDlg == null)
357                 throw new com.sun.star.uno.Exception(
358                     "Cannot obtain XControl from XWindow in method external_event.");
359             //Now get model
360             XControlModel xModelDlg = xControlDlg.getModel();
361 
362             if (xModelDlg == null)
363                 throw new com.sun.star.uno.Exception(
364                     "Cannot obtain XControlModel from XWindow in method external_event.", this);
365             //The model itself does not provide any information except that its
366             //implementation supports XPropertySet which is used to access the data.
367             XPropertySet xPropDlg = (XPropertySet) UnoRuntime.queryInterface(
368                 XPropertySet.class, xModelDlg);
369             if (xPropDlg == null)
370                 throw new com.sun.star.uno.Exception(
371                     "Cannot obtain XPropertySet from window in method external_event.", this);
372 
373             //Get the "Name" property of the window
374             Object aWindowName = xPropDlg.getPropertyValue("Name");
375 
376             //Get the string from the returned com.sun.star.uno.Any
377             String sName = null;
378             try {
379                 sName = AnyConverter.toString(aWindowName);
380             } catch (com.sun.star.lang.IllegalArgumentException e) {
381                 throw new com.sun.star.uno.Exception(
382                     "Name - property of window is not a string.", this);
383             }
384 
385             //Eventually we can check if we this handler can "handle" this options page.
386             //The class has a member m_arWindowNames which contains all names of windows
387             //for which it is intended
388             for (int i = 0; i < m_arWindowNames.length; i++) {
389                 if (m_arWindowNames[i].equals(sName)) {
390                     return sName;
391                 }
392             }
393             return null;
394         }
395     }
396 
397 
398     /**
399      * Gives a factory for creating the service.
400      * This method is called by the <code>JavaLoader</code>
401      * <p>
402      * @return  returns a <code>XSingleComponentFactory</code> for creating
403      *          the component
404      * @param   sImplName the name of the implementation for which a
405      *          service is desired
406      * @see     com.sun.star.comp.loader.JavaLoader
407      */
__getComponentFactory(String sImplName)408     public static XSingleComponentFactory __getComponentFactory(String sImplName)
409     {
410         XSingleComponentFactory xFactory = null;
411 
412         if ( sImplName.equals( _OptionsEventHandler.class.getName() ) )
413             xFactory = Factory.createComponentFactory(_OptionsEventHandler.class,
414                                              _OptionsEventHandler.getServiceNames());
415 
416         return xFactory;
417     }
418 
419     /**
420      * Writes the service information into the given registry key.
421      * This method is called by the <code>JavaLoader</code>
422      * <p>
423      * @return  returns true if the operation succeeded
424      * @param   regKey the registryKey
425      * @see     com.sun.star.comp.loader.JavaLoader
426      */
__writeRegistryServiceInfo(XRegistryKey regKey)427     public static boolean __writeRegistryServiceInfo(XRegistryKey regKey) {
428         return Factory.writeRegistryServiceInfo(_OptionsEventHandler.class.getName(),
429                                                 _OptionsEventHandler.getServiceNames(),
430                                                 regKey);
431     }
432 
433     /** This method is a member of the interface for initializing an object
434      * directly after its creation.
435      * @param object This array of arbitrary objects will be passed to the
436      * component after its creation.
437      * @throws Exception Every exception will not be handled, but will be
438      * passed to the caller.
439      */
initialize( Object[] object )440     public void initialize( Object[] object )
441         throws com.sun.star.uno.Exception {
442     }
443 
444 }
445