2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 package com
.sun
.star
.lib
.uno
.helper
;
20 import com
.sun
.star
.uno
.Type
;
21 import com
.sun
.star
.lang
.EventObject
;
22 import com
.sun
.star
.lang
.WrappedTargetException
;
23 import com
.sun
.star
.uno
.TypeClass
;
24 import com
.sun
.star
.uno
.AnyConverter
;
25 import com
.sun
.star
.uno
.XInterface
;
26 import com
.sun
.star
.uno
.Any
;
27 import com
.sun
.star
.uno
.UnoRuntime
;
28 import com
.sun
.star
.beans
.XPropertyChangeListener
;
29 import com
.sun
.star
.beans
.XVetoableChangeListener
;
30 import com
.sun
.star
.beans
.PropertyChangeEvent
;
31 import com
.sun
.star
.beans
.XPropertySet
;
32 import com
.sun
.star
.beans
.Property
;
33 import com
.sun
.star
.beans
.PropertyAttribute
;
34 import com
.sun
.star
.beans
.UnknownPropertyException
;
35 import com
.sun
.star
.beans
.XPropertiesChangeListener
;
36 import com
.sun
.star
.beans
.XPropertySetInfo
;
37 import com
.sun
.star
.beans
.XFastPropertySet
;
38 import com
.sun
.star
.beans
.PropertyVetoException
;
39 import com
.sun
.star
.beans
.XMultiPropertySet
;
40 import java
.util
.Iterator
;
41 import java
.util
.Collection
;
42 import java
.util
.HashMap
;
43 import java
.lang
.reflect
.Field
;
44 import com
.sun
.star
.lang
.DisposedException
;
47 /** This class is an implementation of the interfaces com.sun.star.beans.XPropertySet,
48 * com.sun.star.beans.XFastPropertySet and com.sun.star.beans.XMultiPropertySet. This
49 * class has to be inherited to be used. The values of properties are stored in member
50 * variables of the inheriting class. By overriding the methods
51 * {@link #convertPropertyValue convertPropertyValue},
52 * {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} and
53 * {@link #getPropertyValue(Property)} one can determine how
54 * property values are stored.
55 * When using the supplied implementations of this class then the member variables which
56 * hold property values have to be declared in the class which inherits last in the inheriting
57 * chain and they have to be public<p>
58 * Properties have to be registered by one of the registerProperty methods. They take among other
59 * arguments an Object named <em>id</em> which has to be a String that represents the name of
60 * the member variable. The registering has to occur in the constructor of the inheriting class.
61 * It is no allowed to add or change properties later on.<p>
64 * public class Foo extends PropertySet
66 * protected int intProp;
70 * registerProperty("PropertyA", 0, new Type(int.class), (short)0, "intProp");
76 public class PropertySet
extends ComponentBase
implements XPropertySet
, XFastPropertySet
,
79 private HashMap
<String
,Property
> _nameToPropertyMap
;
80 private HashMap
<Integer
,Property
> _handleToPropertyMap
;
81 private HashMap
<Property
,Object
> _propertyToIdMap
;
82 private Property
[] arProperties
;
84 private int lastHandle
= 1;
86 protected XPropertySetInfo propertySetInfo
;
87 protected MultiTypeInterfaceContainer aBoundLC
= new MultiTypeInterfaceContainer();
88 protected MultiTypeInterfaceContainer aVetoableLC
= new MultiTypeInterfaceContainer();
95 /** Registers a property with this helper class and associates the argument <em>id</em> with it.
96 * <em>id</em> is used to identify the storage of the property value. How property values are stored
97 * and retrieved is determined by the methods {@link #convertPropertyValue convertPropertyValue},
98 * {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} and {@link #getPropertyValue(Property) getPropertyValue}
99 * These methods expect <em>id</em> to be a String which represents the name of a member variable
100 * which holds the property value.
101 * Only properties which are registered can be accessed. Registration has to occur during
102 * initialization of the inheriting class (i.e. within the constructor).
103 * @param prop The property to be registered.
104 * @param id Identifies the properties storage.
105 * @see #getPropertyId
107 protected void registerProperty(Property prop
, Object id
)
110 assignPropertyId(prop
, id
);
113 /** Registers a property with this helper class and associates the argument id with it.
114 * It does the same as {@link #registerProperty(Property, Object)}. The first four
115 * arguments are used to construct a Property object.
116 * Registration has to occur during
117 * initialization of the inheriting class (i.e. within the constructor)
118 * @param name The property's name (Property.Name).
119 * @param handle The property's handle (Property.Handle).
120 * @param type The property's type (Property.Type).
121 * @param attributes The property's attributes (Property.Attributes).
122 * @param id Identifies the property's storage.
124 protected void registerProperty(String name
, int handle
, Type type
, short attributes
, Object id
)
126 Property p
= new Property(name
, handle
, type
, attributes
);
127 registerProperty(p
, id
);
130 /** Registers a property with this class and associates the argument id with it.
131 * It does the same as {@link #registerProperty(Property, Object)}. The first three
132 * arguments are used to construct a Property object. The value for the Property.Handle
133 * is generated and does not have to be specified here. Use this method for registering
134 * a property if you do not care about the Property's handles.
135 * Registration has to occur during
136 * initialization of the inheriting class (i.e. within the constructor).
137 * @param name The property's name (Property.Name).
138 * @param type The property's type (Property.Type).
139 * @param attributes The property's attributes (Property.Attributes).
140 * @param id Identifies the property's storage.
142 protected void registerProperty(String name
, Type type
, short attributes
, Object id
)
144 Property p
= new Property(name
, lastHandle
++, type
, attributes
);
145 registerProperty(p
, id
);
148 /** Registers a property with this class. This method expects that property values
149 * are stored in member variables as is the case if the methods convertPropertyValue,
150 * setPropertyValueNoBroadcast and getPropertyValue(Property) are not overridden.
151 * It is presumed that the type of the member variable
152 * corresponds Property.Type. For example, if the TypeClass of Property.Type is to be
153 * a TypeClass.SHORT then the member must be a short or java.lang.Short.
154 * The handle for the property is generated.<br>
155 * If there is no member with the specified name or if the member has an incompatible type
156 * then a com.sun.star.uno.RuntimeException is thrown.
157 * @param propertyName The name of the property.
158 * @param memberName The name of the member variable that holds the value of the property.
159 * @param attributes The property attributes.
161 protected void registerProperty(String propertyName
, String memberName
, short attributes
)
163 Field propField
= null;
166 propField
= getClass().getDeclaredField(memberName
);
168 catch (NoSuchFieldException e
)
170 throw new com
.sun
.star
.uno
.RuntimeException(e
, "there is no member variable: " + memberName
);
172 Class cl
= propField
.getType();
173 Type t
= new Type(cl
);
174 if (t
.getTypeClass() != TypeClass
.UNKNOWN
)
176 Property p
= new Property(propertyName
, lastHandle
++, t
, attributes
);
177 registerProperty(p
,memberName
);
180 throw new com
.sun
.star
.uno
.RuntimeException("the member has an unknown type: " + memberName
);
183 /** Registers a property with this class.
184 * It is presumed that the name of property is equal to the name of the member variable
185 * that holds the property value.
186 * @param propertyName The name of the property and the member variable that holds the property's value.
187 * @param attributes The property attributes.
188 * @see #registerProperty(String, String, short)
190 protected void registerProperty(String propertyName
, short attributes
)
192 registerProperty(propertyName
, propertyName
, attributes
);
197 /** Returns the Property object for a given property name or null if that property does
198 * not exists (i.e. it has not been registered). Override this method
199 * if you want to implement your own mapping from property names to Property objects.
200 * Then you also have to override {@link #initMappings}, {@link #getProperties()} and
201 * {@link #putProperty(Property)}.
202 * @param propertyName The name of the property (Property.Name)
203 * @return The Property object with the name <em>propertyName</em>.
205 protected Property
getProperty(String propertyName
)
207 return _nameToPropertyMap
.get(propertyName
);
210 /** Returns the Property object with a handle (Property.Handle) as specified by the argument
211 * <em>nHandle</em>. The method returns null if there is no such property (i.e. it has not
212 * been registered). Override this method if you want to implement your own mapping from handles
213 * to Property objects. Then you also have to override {@link #initMappings}, {@link #putProperty(Property)}.
214 * @param nHandle The handle of the property (Property.Handle).
215 * @return The Property object with the handle <em>nHandle</em>
217 protected Property
getPropertyByHandle(int nHandle
)
219 return _handleToPropertyMap
.get(Integer
.valueOf(nHandle
));
222 /** Returns an array of all Property objects or an array of length null if there
223 * are no properties. Override this method if you want to implement your own mapping from names
224 * to Property objects. Then you also have to override {@link #initMappings}, {@link #getProperty(String)} and
225 * {@link #putProperty}.
226 * @return Array of all Property objects.
228 protected Property
[] getProperties()
230 if (arProperties
== null)
232 Collection
<Property
> values
= _nameToPropertyMap
.values();
233 arProperties
= values
.toArray(new Property
[_nameToPropertyMap
.size()]);
238 /** Stores a Property object so that it can be retrieved subsequently by
239 * {@link #getProperty(String)},{@link #getProperties()},{@link #getPropertyByHandle(int)}.
240 * Override this method if you want to implement your own mapping from handles
241 * to Property objects and names to Property objects. Then you also need to override {@link #initMappings},
242 * {@link #getProperty(String)},{@link #getProperties()},{@link #getPropertyByHandle(int)}.
243 * @param prop The Property object that is to be stored.
245 protected void putProperty(Property prop
)
247 _nameToPropertyMap
.put(prop
.Name
, prop
);
248 if (prop
.Handle
!= -1)
249 _handleToPropertyMap
.put(Integer
.valueOf(prop
.Handle
), prop
);
252 /** Assigns an identifier object to a Property object so that the identifier
253 * can be obtained by {@link #getPropertyId getPropertyId} later on. The identifier
254 * is used to specify a certain storage for the property's value. If you do not
255 * override {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} or {@link #getPropertyValue(Property)}
256 * then the argument <em>id</em> has to be a String that equals the name of
257 * the member variable that holds the Property's value.
258 * Override this method if you want to implement your own mapping from Property objects to ids or
259 * if you need ids of a type other than String.
260 * Then you also need to override {@link #initMappings initMappings} and {@link #getPropertyId getPropertyId}.
261 * @param prop The Property object that is being assigned an id.
262 * @param id The object which identifies the storage used for the property's value.
263 * @see #registerProperty(Property, Object)
265 protected void assignPropertyId(Property prop
, Object id
)
267 if (id
instanceof String
&& ((String
) id
).length() != 0)
268 _propertyToIdMap
.put(prop
, id
);
271 /** Returns the identifier object for a certain Property. The object must have been
272 * previously assigned to the Property object by {@link #assignPropertyId assignPropertyId}.
273 * Override this method if you want to implement your own mapping from Property objects to ids.
274 * Then you also need to override {@link #initMappings initMappings} and {@link #assignPropertyId assignPropertyId}.
275 * @param prop The property for which the id is to be retrieved.
276 * @return The id object that identifies the storage used for the property's value.
277 * @see #registerProperty(Property, Object)
279 protected Object
getPropertyId(Property prop
)
281 return _propertyToIdMap
.get(prop
);
284 /** Initializes data structures used for mappings of property names to property object,
285 * property handles to property objects and property objects to id objects.
286 * Override this method if you want to implement your own mappings. Then you also need to
287 * override {@link #putProperty putProperty},{@link #getProperty getProperty}, {@link #getPropertyByHandle},
288 * {@link #assignPropertyId assignPropertyId} and {@link #getPropertyId getPropertyId}.
290 protected void initMappings()
292 _nameToPropertyMap
= new HashMap
<String
,Property
>();
293 _handleToPropertyMap
= new HashMap
<Integer
,Property
>();
294 _propertyToIdMap
= new HashMap
<Property
,Object
>();
297 /** Makes sure that listeners which are kept in aBoundLC (XPropertyChangeListener) and aVetoableLC
298 * (XVetoableChangeListener) receive a disposing call. Also those listeners are released.
301 protected void postDisposing()
303 // Create an event with this as sender
304 EventObject aEvt
= new EventObject(this);
306 // inform all listeners to release this object
307 aBoundLC
.disposeAndClear(aEvt
);
308 aVetoableLC
.disposeAndClear(aEvt
);
311 //XPropertySet ----------------------------------------------------
312 synchronized public void addPropertyChangeListener(String str
, XPropertyChangeListener xPropertyChangeListener
)
313 throws UnknownPropertyException
, WrappedTargetException
315 // only add listeners if you are not disposed
316 if (! bInDispose
&& ! bDisposed
)
318 if (str
.length() > 0)
320 Property prop
= getProperty(str
);
322 throw new UnknownPropertyException("Property " + str
+ " is unknown");
324 // Add listener for a certain property
325 if ((prop
.Attributes
& PropertyAttribute
.BOUND
) > 0)
326 aBoundLC
.addInterface(str
, xPropertyChangeListener
);
332 // Add listener for all properties
333 listenerContainer
.addInterface(XPropertyChangeListener
.class, xPropertyChangeListener
);
336 //XPropertySet ----------------------------------------------------
337 synchronized public void addVetoableChangeListener(String str
, com
.sun
.star
.beans
.XVetoableChangeListener xVetoableChangeListener
) throws com
.sun
.star
.beans
.UnknownPropertyException
, com
.sun
.star
.lang
.WrappedTargetException
339 // only add listeners if you are not disposed
340 if (! bInDispose
&& ! bDisposed
)
342 if (str
.length() > 0)
344 Property prop
= getProperty(str
);
346 throw new UnknownPropertyException("Property " + str
+ " is unknown");
348 // Add listener for a certain property
349 if ((prop
.Attributes
& PropertyAttribute
.CONSTRAINED
) > 0)
350 aVetoableLC
.addInterface(str
, xVetoableChangeListener
);
356 // Add listener for all properties
357 listenerContainer
.addInterface(XVetoableChangeListener
.class, xVetoableChangeListener
);
360 //XPropertySet ----------------------------------------------------
361 public synchronized com
.sun
.star
.beans
.XPropertySetInfo
getPropertySetInfo()
363 if (propertySetInfo
== null)
364 propertySetInfo
= new PropertySetInfo();
365 return propertySetInfo
;
367 //XPropertySet ----------------------------------------------------
368 public Object
getPropertyValue(String name
) throws UnknownPropertyException
, WrappedTargetException
371 if (bInDispose
|| bDisposed
)
372 throw new com
.sun
.star
.lang
.DisposedException("The component has been disposed already");
374 Property prop
= getProperty(name
);
376 throw new UnknownPropertyException("The property " + name
+ " is unknown");
380 ret
= getPropertyValue(prop
);
382 // null must not be returned. Either a void any is returned or an any containing
383 // an interface type and a null reference.
386 if (prop
.Type
.getTypeClass() == TypeClass
.INTERFACE
)
387 ret
= new Any(prop
.Type
, null);
389 ret
= new Any(new Type(void.class), null);
394 //XPropertySet ----------------------------------------------------
395 synchronized public void removePropertyChangeListener(String propName
, XPropertyChangeListener listener
) throws UnknownPropertyException
, WrappedTargetException
396 { // all listeners are automatically released in a dispose call
397 if (!bInDispose
&& !bDisposed
)
399 if (propName
.length() > 0)
401 Property prop
= getProperty(propName
);
403 throw new UnknownPropertyException("Property " + propName
+ " is unknown");
404 aBoundLC
.removeInterface(propName
, listener
);
407 listenerContainer
.removeInterface(XPropertyChangeListener
.class, listener
);
411 //XPropertySet ----------------------------------------------------
412 synchronized public void removeVetoableChangeListener(String propName
, XVetoableChangeListener listener
) throws UnknownPropertyException
, WrappedTargetException
413 {// all listeners are automatically released in a dispose call
414 if (!bInDispose
&& !bDisposed
)
416 if (propName
.length() > 0)
418 Property prop
= getProperty(propName
);
420 throw new UnknownPropertyException("Property " + propName
+ " is unknown");
421 aVetoableLC
.removeInterface(propName
, listener
);
424 listenerContainer
.removeInterface(XVetoableChangeListener
.class, listener
);
428 //XPropertySet ----------------------------------------------------
429 /** Sets the value of a property.
430 * The idl description for this interfaces, stipulates that the argument value is an Any. Since a java.lang.Object
431 * reference has the same meaning as an Any this function accepts
432 * java anys (com.sun.star.uno.Any) and all other appropriate objects as arguments. The value argument can be one
435 * <li>java.lang.Boolean</li>
436 * <li>java.lang.Character</li>
437 * <li>java.lang.Byte</li>
438 * <li>java.lang.Short</li>
439 * <li>java.lang.Integer</li>
440 * <li>java.lang.Long</li>
441 * <li>java.lang.Float</li>
442 * <li>java.lang.Double</li>
444 * <li>com.sun.star.uno.Type</li>
445 * <li><em>objects which implement UNO interfaces</em></li>
446 * <li><em>arrays which contain elements of the types above</em></li>
447 * <li>com.sun.star.uno.Any containing an instance of one of the above types</li>
450 * Properties can have the attribute com.sun.star.beans.PropertyAttribute.MAYBEVOID, which means that the value
451 * (not the type) can be void. In order to assign a void value to a property one can either pass an Any which
452 * contains a null reference or pass null directly. In both cases the null reference is only accepted if
453 * the PropertyAttribute.MAYBEVOID attribute is set for the property.
455 * Properties which have the attribute MAYBEVOID set (Property.Attributes) can have a void value. The following
456 * considerations presume that the Property has that attribute set. Further, when mentioning an Any's value we
457 * actually refer to the object returned by Any.getObject.
458 * If the argument <em>value</em> is null, or it is an Any whose value is null (but with a valid Type)
459 * then the member variable used for storing the property's value is set to null.
460 * Therefore those properties can only be stored in objects
461 * and primitive types are not allowed (one can use the wrapper classes instead,e.g. java.lang.Byte) .
462 * If a property's value is kept in a member variable of type Any and that reference is still null
463 * then when setPropertyValue is called with
464 * <em>value</em> = null then the member variable is assigned an Any with type void and a null value.
465 * Or if the argument is an Any with a null value then it is assigned to the member variable.
466 * Further, if the variable already
467 * references an Any and setPropertyValue is called with <em>value</em> = null, then the variable is assigned
468 * a new Any with the same type as the previously referenced Any and with a null value.
469 * @param name The name of the property.
470 * @param value The new value of the property.
472 public void setPropertyValue(String name
, Object value
) throws UnknownPropertyException
,
473 PropertyVetoException
, com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
475 Property prop
= getProperty(name
);
477 throw new UnknownPropertyException("Property " + name
+ " is unknown");
478 setPropertyValue(prop
, value
);
481 /** Sets the value of a property. It checks if the property's attributes (READONLY,MAYBEVOID), allow that the
482 * new value can be set. It also causes the notification of listeners.
483 * @param prop The property whose value is to be set.
484 * @param value The new value for the property.
486 * @throws UnknownPropertyException
487 * See com.sun.star.beans.XPropertySet
488 * @throws PropertyVetoException
489 * See com.sun.star.beans.XPropertySet
490 * @throws WrappedTargetException
491 * See com.sun.star.beans.XPropertySet
493 protected void setPropertyValue(Property prop
, Object value
) throws UnknownPropertyException
,
494 PropertyVetoException
, com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
496 if ((prop
.Attributes
& PropertyAttribute
.READONLY
) == PropertyAttribute
.READONLY
)
497 throw new com
.sun
.star
.beans
.PropertyVetoException();
498 // The value may be null only if MAYBEVOID attribute is set
500 if (value
instanceof Any
)
501 bVoidValue
= ((Any
) value
).getObject() == null;
503 bVoidValue
= value
== null;
504 if (bVoidValue
&& (prop
.Attributes
& PropertyAttribute
.MAYBEVOID
) == 0)
505 throw new com
.sun
.star
.lang
.IllegalArgumentException("The property must have a value; the MAYBEVOID attribute is not set!");
506 if (bInDispose
|| bDisposed
)
507 throw new DisposedException("Component is already disposed");
509 //Check if the argument is allowed
511 if (value
instanceof Any
)
512 bValueOk
= checkType(((Any
) value
).getObject());
514 bValueOk
= checkType(value
);
516 throw new com
.sun
.star
.lang
.IllegalArgumentException("No valid UNO type");
519 boolean bConversionOk
= false;
520 Object
[] outConvertedVal
= new Object
[1];
521 Object
[] outOldValue
= new Object
[1];
524 bConversionOk
= convertPropertyValue(prop
, outConvertedVal
, outOldValue
, value
);
527 //The next step following the conversion is to set the new value of the property. Prior to this
528 // the XVetoableChangeListener s have to be notified.
531 // If the property is CONSTRAINED, then we must notify XVetoableChangeListener. The listener can throw a com.sun.star.lang.beans.PropertyVetoException which
532 // will cause this method to return (the exception is not caught here).
533 fire( new Property
[]{prop
}, outConvertedVal
, outOldValue
, true);
537 setPropertyValueNoBroadcast(prop
, outConvertedVal
[0]);
539 // fire a change event (XPropertyChangeListener, PropertyAttribute.BOUND
540 fire( new Property
[]{prop
}, outConvertedVal
, outOldValue
, false);
544 /** Converts a value in a way so that it is appropriate for storing as a property value, that is
545 * {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} can process the value without any further
546 * conversion. This implementation presumes that
547 * the values are stored in member variables of the furthest inheriting class. For example,
548 * class A inherits this class then members of class A
549 * can hold property values. If there is a class B which inherits A then only members of B can hold
550 * property values. The variables must be public. A property must have been registered (e.g. by
551 * {@link #registerProperty(Property, Object)} in order for this method to work. The identifier argument (type Object)
552 * used in the registerProperty methods must
553 * be a String, which is, the name of the member variable that holds the property value.
554 * If one opts to store values differently then one may override
555 * this method, as well as {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} and
556 * {@link #getPropertyValue(Property) getPropertyValue(Property)}.
557 * This method is always called as a result of a call to one of the setter methods, such as
558 * {@link #setPropertyValue(String,Object) XPropertySet.setPropertyValue},
559 * {@link #setFastPropertyValue XFastPropertySet.setFastPropertyValue}
560 * and {@link #setPropertyValues XMultiPropertySet.setPropertyValues}.
561 * If this method fails, that is, it returns false or throws an exception, then no listeners are notified and the
562 * property value, that was intended to be changed, remains untouched.
564 * This method does not have to deal with property attributes, such as
565 * PropertyAttribute.READONLY or PropertyAttribute.MAYBEVOID. The processing of these attributes occurs
566 * in the calling methods.
568 * Only if this method returns successfully further processing, such
569 * as listener notification and finally the modification of the property's value, will occur.
571 * The actual modification of a property's value is done by {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast}
572 * which is called subsequent to convertPropertyValue.
574 * This method converts values by help of the com.sun.star.uno.AnyConverter which only does a few widening
575 * conversions on integer types and floating point types. For example, there is the property PropA with a Type equivalent
576 * to int.class and the
577 * value of the property is to be stored in a member variable of type int with name intProp. Then setPropertyValue is
580 * set.setPropertyValue( "PropA", Byte.valueOf( (byte)111));
582 * At some point setPropertyValue will call convertPropertyValue and pass in the Byte object. Since we allow
583 * that Byte values can be used with the property and know that the value is to be stored in intProp (type int)
584 * we convert the Byte object into an Integer object which is then returned in the out-parameter <em>newVal</em>. This
585 * conversion is actually performed by the AnyConverter. Later
586 * the setPropertyValueNoBroadcast is called with that Integer object and the int value can be easily extracted
587 * from the object and be assigned to the member intProp.
589 * The method handles Any arguments the same as Object arguments. That is, the <em>setVal</em> argument can
590 * be a java.lang.Boolean or a com.sun.star.uno.Any containing a java.lang.Boolean. Likewise, a member
591 * containing a property value can be a com.sun.star.uno.Any or a java.lang.Object.
592 * Then, no conversion is necessary, since they can hold all possible values. However, if
593 * the member is an Object and <em>setVal</em> is an Any then the object contained in the any is assigned to
594 * the member. The extra type information which exists as Type object in the Any will get lost. If this is not
595 * intended then use an Any variable rather than an Object.
597 * If a member is an Object or Any and the argument <em>setVal</em> is an Object, other than String or array,
598 * then it is presumed to be a UNO object and queried for XInterface. If successful, the out-param <em>newVal</em>
599 * returns the XInterface.
601 * If a member is a UNO interface, then <em>setVal</em> is queried for this interface and the result is returned.
602 * If <em>setVal</em> is null then <em>newVal</em> will be null too after return.
604 * If a property value is stored using a primitive type the out-parameters
605 * <em>curVal</em> and <em>newVal</em> contain the respective wrapper class (e.g.java.lang.Byte, etc.).
606 * curVal is used in calls to the XVetoableChangeListener and XPropertyChangeListener.
608 * @param property - in-param property for which the data is to be converted.
609 * @param newVal - out-param which contains the converted value on return.
610 * @param curVal - out-param the current value of the property. It is used in calls to the
611 * XVetoableChangeListener and XPropertyChangeListener.
612 * @param setVal - in-param. The value that is to be converted so that it matches Property and the internally used
613 * dataformat for that property.
614 * @return true - Conversion was successful. <em>newVal</em> contains a valid value for the property. false -
615 * conversion failed for some reason.
617 * @throws UnknownPropertyException
618 * See com.sun.star.beans.XPropertySet
619 * @throws com.sun.star.lang.IllegalArgumentException The value provided is unfit for the property.
620 * @throws com.sun.star.lang.WrappedTargetException - An exception occurred during the conversion, that is to be made known
623 protected boolean convertPropertyValue(Property property
, Object
[] newVal
, Object
[]curVal
, Object setVal
)
624 throws com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
, UnknownPropertyException
629 // get the member name
630 String sMember
= (String
) getPropertyId(property
);
633 // use reflection to obtain the field that holds the property value
634 // Class.getDeclaredFields does not return inherited fields. One could use Class.getFields to
635 // also get inherited fields, but only those which are public.
636 Field propField
= getClass().getDeclaredField(sMember
);
637 if (propField
!= null)
639 curVal
[0]= propField
.get(this);
640 Class memberClass
= propField
.getType();
642 // MAYBEVOID: if setVal == null or it is an Any and getObject returns null, then a void value is to be set
643 // This works only if there are no primitive types. For those we use the respective wrapper classes.
644 // In this implementation, a null reference means void value.
645 boolean bVoidValue
= false;
646 boolean bAnyVal
= setVal
instanceof Any
;
648 bVoidValue
= ((Any
) setVal
).getObject() == null;
650 bVoidValue
= setVal
== null;
651 if (bVoidValue
&& memberClass
.isPrimitive())
652 throw new com
.sun
.star
.lang
.IllegalArgumentException("The implementation does not support the MAYBEVOID attribute for this property");
654 Object convObj
= null;
655 //The member that keeps the value of the Property is an Any. It can contain all possible
656 //types, therefore a conversion is not necessary.
657 if (memberClass
.equals(Any
.class))
660 //parameter setVal is also an Any and can be used without further processing
664 // Parameter setVal is not an Any. We need to construct an Any that contains
665 // the argument setVal.
666 // If setVal is an interface implementation then, we cannot construct the
667 // Any with setVal.getClass(), because the Any.Type._typeClass would be TypeClass.UNKNOWN.
668 // We try to get an XInterface of setVal and set an XInterface type.
669 if (setVal
instanceof XInterface
)
671 XInterface xint
= UnoRuntime
.queryInterface(XInterface
.class, setVal
);
673 convObj
= new Any(new Type(XInterface
.class), xint
);
675 // The member is an any, and the past in argument was null reference (MAYBEVOID is set)
676 else if (setVal
== null)
678 // if the any member is still null we create a void any
679 if (curVal
[0] == null)
680 convObj
= new Any(new Type(), null);
683 //otherwise we create an Any with the same type as a value of null;
684 convObj
= new Any( ((Any
)curVal
[0]).getType(), null);
688 convObj
= new Any(new Type(setVal
.getClass()), setVal
);
692 convObj
= convert(memberClass
, setVal
);
697 throw new UnknownPropertyException("Property " + property
.Name
+ " is unknown");
699 catch (java
.lang
.NoSuchFieldException e
)
701 throw new WrappedTargetException(e
, "Field does not exist", this, e
);
703 catch (java
.lang
.IllegalAccessException e
)
705 throw new WrappedTargetException(e
, "", this ,e
);
710 private boolean checkType(Object obj
)
713 || obj
instanceof Boolean
714 || obj
instanceof Character
715 || obj
instanceof Number
716 || obj
instanceof String
717 || obj
instanceof XInterface
718 || obj
instanceof Type
719 || obj
instanceof com
.sun
.star
.uno
.Enum
720 || obj
.getClass().isArray();
723 // Param object can be an Any or other object. If obj is null then the return value is null
724 private Object
convert( Class cl
, Object obj
) throws com
.sun
.star
.lang
.IllegalArgumentException
727 //The member that keeps the value of the Property is an Object.Objects are similar to Anys in that they can
729 if (obj
== null || (obj
instanceof Any
&& ((Any
) obj
).getObject() == null))
731 else if(cl
.equals(Object
.class))
733 if (obj
instanceof Any
)
734 obj
= ((Any
) obj
).getObject();
737 else if(cl
.equals(boolean.class))
738 retVal
= Boolean
.valueOf(AnyConverter
.toBoolean(obj
));
739 else if (cl
.equals(char.class))
740 retVal
= Character
.valueOf(AnyConverter
.toChar(obj
));
741 else if (cl
.equals(byte.class))
742 retVal
= Byte
.valueOf(AnyConverter
.toByte(obj
));
743 else if (cl
.equals(short.class))
744 retVal
= Short
.valueOf(AnyConverter
.toShort(obj
));
745 else if (cl
.equals(int.class))
746 retVal
= Integer
.valueOf(AnyConverter
.toInt(obj
));
747 else if (cl
.equals(long.class))
748 retVal
= Long
.valueOf(AnyConverter
.toLong(obj
));
749 else if (cl
.equals(float.class))
750 retVal
= Float
.valueOf(AnyConverter
.toFloat(obj
));
751 else if (cl
.equals(double.class))
752 retVal
= Double
.valueOf(AnyConverter
.toDouble(obj
));
753 else if (cl
.equals(String
.class))
754 retVal
= AnyConverter
.toString(obj
);
755 else if (cl
.isArray())
756 retVal
= AnyConverter
.toArray(obj
);
757 else if (cl
.equals(Type
.class))
758 retVal
= AnyConverter
.toType(obj
);
759 else if (cl
.equals(Boolean
.class))
760 retVal
= Boolean
.valueOf(AnyConverter
.toBoolean(obj
));
761 else if (cl
.equals(Character
.class))
762 retVal
= Character
.valueOf(AnyConverter
.toChar(obj
));
763 else if (cl
.equals(Byte
.class))
764 retVal
= Byte
.valueOf(AnyConverter
.toByte(obj
));
765 else if (cl
.equals(Short
.class))
766 retVal
= Short
.valueOf(AnyConverter
.toShort(obj
));
767 else if (cl
.equals(Integer
.class))
768 retVal
= Integer
.valueOf(AnyConverter
.toInt(obj
));
769 else if (cl
.equals(Long
.class))
770 retVal
= Long
.valueOf(AnyConverter
.toLong(obj
));
771 else if (cl
.equals(Float
.class))
772 retVal
= Float
.valueOf(AnyConverter
.toFloat(obj
));
773 else if (cl
.equals(Double
.class))
774 retVal
= Double
.valueOf(AnyConverter
.toDouble(obj
));
775 else if (XInterface
.class.isAssignableFrom(cl
))
776 retVal
= AnyConverter
.toObject(new Type(cl
), obj
);
777 else if (com
.sun
.star
.uno
.Enum
.class.isAssignableFrom(cl
))
778 retVal
= AnyConverter
.toObject(new Type(cl
), obj
);
780 throw new com
.sun
.star
.lang
.IllegalArgumentException("Could not convert the argument");
784 /** Sets the value of a property. In this implementation property values are stored in member variables
785 * (see {@link #convertPropertyValue convertPropertyValue} Notification of property listeners
786 * does not occur in this method. By overriding this method one can take full control about how property values
787 * are stored. But then, the {@link #convertPropertyValue convertPropertyValue} and
788 * {@link #getPropertyValue(Property)} must be overridden too.
790 * A Property with the MAYBEVOID attribute set, is stored as null value. Therefore the member variable must be
791 * an Object in order to make use of the property attribute. An exception is Any. The Any variable can be initially null, but
792 * once it is set the reference will not become null again. If the value is to be set to
793 * void then a new Any will be stored
794 * with a valid type but without a value (i.e. Any.getObject returns null).
795 * If a property has the READONLY attribute set, and one of the setter methods, such as setPropertyValue, has been
796 * called, then this method is not going to be called.
797 * @param property the property for which the new value is set
798 * @param newVal the new value for the property.
799 * @throws com.sun.star.lang.WrappedTargetException An exception, which has to be made known to the caller,
800 * occurred during the setting of the value.
802 protected void setPropertyValueNoBroadcast(Property property
, Object newVal
)
803 throws WrappedTargetException
807 // get the member name
808 String sMember
= (String
) getPropertyId(property
);
811 // use reflection to obtain the field that holds the property value
812 // Class.getDeclaredFields does not return inherited fields. One could use Class.getFields to
813 // also get inherited fields, but only those which are public.
814 Field propField
= getClass().getDeclaredField(sMember
);
815 if (propField
!= null)
816 propField
.set(this, newVal
);
819 catch(java
.lang
.Exception e
)
821 throw new WrappedTargetException(e
, "PropertySet.setPropertyValueNoBroadcast", this, e
);
824 /** Retrieves the value of a property. This implementation presumes that the values are stored in member variables
825 * of the furthest inheriting class (see {@link #convertPropertyValue convertPropertyValue}) and that the
826 * variables are public. The property must have
827 * been registered, for example by {@link #registerProperty(Property, Object)}. The identifier Object argument
828 * must have been a String which was the name of the member variable holding the property value.
829 * When properties are to be stored differently one has to override this method as well as
830 * {@link #convertPropertyValue} and {@link #setPropertyValueNoBroadcast}. <br>
831 * If a value is stored in a variable of a primitive type then this method returns an instance of the respective
832 * wrapper class (e.g. java.lang.Boolean).
833 * @param property The property for which the value is to be retrieved.
834 * @return The value of the property.
836 protected Object
getPropertyValue(Property property
)
841 // get the member name
842 String sMember
= (String
) getPropertyId(property
);
845 // use reflection to obtain the field that holds the property value
846 // Class.getDeclaredFields does not return inherited fields. One could use Class.getFields to
847 // also get inherited fields, but only those which are public.
848 Field propField
= getClass().getDeclaredField(sMember
);
849 if (propField
!= null)
850 ret
= propField
.get(this);
853 catch(java
.lang
.NoSuchFieldException e
)
855 throw new java
.lang
.RuntimeException(e
);
857 catch(java
.lang
.IllegalAccessException e
)
859 throw new java
.lang
.RuntimeException(e
);
865 * This method fires events to XPropertyChangeListener,XVetoableChangeListener and
866 * XPropertiesChangeListener event sinks.
867 * To distinguish what listeners are to be called the argument <em>bVetoable</em> is to be set to true if
868 * a XVetoableChangeListener is meant. For XPropertyChangeListener and XPropertiesChangeListener
869 * it is to be set to false.
871 * @param properties Properties which will be or have been affected.
872 * @param newValues the new values of the properties.
873 * @param oldValues the old values of the properties.
874 * @param bVetoable true means fire to VetoableChangeListener, false means fire to
875 * XPropertyChangedListener and XMultiPropertyChangedListener.
877 * @throws PropertyVetoException
878 * if a vetoable listener throws it.
881 Property
[] properties
,
884 boolean bVetoable
) throws PropertyVetoException
886 // Only fire, if one or more properties changed
887 int nNumProps
= properties
.length
;
890 PropertyChangeEvent
[] arEvts
= new PropertyChangeEvent
[nNumProps
];
891 int nAffectedProps
= 0;
892 // Loop over all changed properties to fill the event struct
893 for (int i
= 0; i
< nNumProps
; i
++)
895 if ((bVetoable
&& (properties
[i
].Attributes
& PropertyAttribute
.CONSTRAINED
) > 0)
896 || (!bVetoable
&& (properties
[i
].Attributes
& PropertyAttribute
.BOUND
) > 0))
898 arEvts
[i
]= new PropertyChangeEvent(this, properties
[i
].Name
, false,
899 properties
[i
].Handle
, oldValues
[i
], newValues
[i
]);
903 // fire the events for all changed properties
904 for (int i
= 0; i
< nAffectedProps
; i
++)
906 // get the listener container for the property name
907 InterfaceContainer lc
;
909 lc
= aVetoableLC
.getContainer(arEvts
[i
].PropertyName
);
911 lc
= aBoundLC
.getContainer(arEvts
[i
].PropertyName
);
912 Iterator it
= lc
!= null ? lc
.iterator() : null;
917 Object listener
= it
.next();
919 ((XVetoableChangeListener
) listener
).vetoableChange(arEvts
[i
]);
921 ((XPropertyChangeListener
) listener
).propertyChange(arEvts
[i
]);
924 // broadcast to all listeners with "" property name
926 lc
= listenerContainer
.getContainer(XVetoableChangeListener
.class);
928 lc
= listenerContainer
.getContainer(XPropertyChangeListener
.class);
929 it
= lc
!= null ? lc
.iterator() : null;
934 Object listener
= it
.next();
935 if( bVetoable
) // fire change Events?
936 ((XVetoableChangeListener
) listener
).vetoableChange(arEvts
[i
]);
938 ((XPropertyChangeListener
) listener
).propertyChange(arEvts
[i
]);
942 // fire at XPropertiesChangeListeners
943 // if nAffectedProps == 0 then there are no BOUND properties
944 if (!bVetoable
&& nAffectedProps
> 0)
947 PropertyChangeEvent
[] arReduced
= new PropertyChangeEvent
[nAffectedProps
];
948 System
.arraycopy(arEvts
, 0, arReduced
, 0, nAffectedProps
);
949 InterfaceContainer lc
= listenerContainer
.getContainer(XPropertiesChangeListener
.class);
950 Iterator it
= lc
!= null ? lc
.iterator() : null;
955 XPropertiesChangeListener listener
= (XPropertiesChangeListener
) it
.next();
956 // fire the whole event sequence to the XPropertiesChangeListener's
957 listener
.propertiesChange( arEvts
);
963 // XFastPropertySet--------------------------------------------------------------------------------
964 public void setFastPropertyValue(int nHandle
, Object aValue
) throws UnknownPropertyException
,
965 PropertyVetoException
, com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
967 Property prop
= getPropertyByHandle(nHandle
);
969 throw new UnknownPropertyException(" The property with handle : " + nHandle
+" is unknown");
970 setPropertyValue(prop
, aValue
);
973 // XFastPropertySet --------------------------------------------------------------------------------
974 public Object
getFastPropertyValue(int nHandle
) throws UnknownPropertyException
,
975 WrappedTargetException
977 Property prop
= getPropertyByHandle(nHandle
);
979 throw new UnknownPropertyException("The property with handle : " + nHandle
+ " is unknown");
980 return getPropertyValue(prop
);
983 // XMultiPropertySet -----------------------------------------------------------------------------------
984 public void addPropertiesChangeListener(String
[] propNames
, XPropertiesChangeListener listener
)
986 listenerContainer
.addInterface(XPropertiesChangeListener
.class, listener
);
989 // XMultiPropertySet -----------------------------------------------------------------------------------
990 public void firePropertiesChangeEvent(String
[] propNames
, XPropertiesChangeListener listener
)
993 PropertyChangeEvent
[] arEvents
= new PropertyChangeEvent
[propNames
.length
];
995 // get a snapshot of the current property values
998 for (int i
= 0; i
< propNames
.length
; i
++)
1000 Property prop
= getProperty(propNames
[i
]);
1006 value
= getPropertyValue(prop
);
1012 arEvents
[eventCount
]= new PropertyChangeEvent(this, prop
.Name
,
1013 false, prop
.Handle
, value
, value
);
1019 // fire events from unsynchronized section so as to prevent deadlocks
1022 // Reallocate the array of the events if necessary
1023 if (arEvents
.length
!= eventCount
)
1025 PropertyChangeEvent
[] arPropsTmp
= new PropertyChangeEvent
[eventCount
];
1026 System
.arraycopy(arEvents
, 0, arPropsTmp
, 0, eventCount
);
1027 arEvents
= arPropsTmp
;
1029 listener
.propertiesChange(arEvents
);
1032 // XMultiPropertySet -----------------------------------------------------------------------------------
1033 /** If a value for a property could not be retrieved then the respective element in the returned
1034 * array has the value null.
1036 public Object
[] getPropertyValues(String
[] propNames
)
1038 Object
[] arValues
= new Object
[propNames
.length
];
1041 for (int i
= 0; i
< propNames
.length
; i
++)
1046 value
= getPropertyValue(propNames
[i
]);
1056 // XMultiPropertySet -----------------------------------------------------------------------------------
1057 public void removePropertiesChangeListener(XPropertiesChangeListener xPropertiesChangeListener
)
1059 listenerContainer
.removeInterface(XPropertiesChangeListener
.class, xPropertiesChangeListener
);
1061 // XMultiPropertySet -----------------------------------------------------------------------------------
1062 /** If the array of property names contains an unknown property then it will be ignored.
1064 public void setPropertyValues(String
[] propNames
, Object
[] values
) throws PropertyVetoException
, com
.sun
.star
.lang
.IllegalArgumentException
, com
.sun
.star
.lang
.WrappedTargetException
1066 for (int i
= 0; i
< propNames
.length
; i
++)
1070 setPropertyValue(propNames
[i
], values
[i
]);
1072 catch (UnknownPropertyException e
)
1080 private class PropertySetInfo
implements XPropertySetInfo
1082 public com
.sun
.star
.beans
.Property
[] getProperties()
1084 return PropertySet
.this.getProperties();
1087 public com
.sun
.star
.beans
.Property
getPropertyByName(String name
) throws UnknownPropertyException
1089 return getProperty(name
);
1092 public boolean hasPropertyByName(String name
)
1094 return getProperty(name
) != null;