merge the formfield patch from ooo-build
[ooovba.git] / javaunohelper / com / sun / star / lib / uno / helper / PropertySet.java
blobbbf144e857ffe314012ff4d1cc57b5e45ecf1782
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: PropertySet.java,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 package com.sun.star.lib.uno.helper;
32 import com.sun.star.uno.Type;
33 import com.sun.star.lang.EventObject;
34 import com.sun.star.lang.WrappedTargetException;
35 import com.sun.star.uno.TypeClass;
36 import com.sun.star.uno.AnyConverter;
37 import com.sun.star.uno.XInterface;
38 import com.sun.star.uno.Any;
39 import com.sun.star.uno.UnoRuntime;
40 import com.sun.star.beans.XPropertyChangeListener;
41 import com.sun.star.beans.XVetoableChangeListener;
42 import com.sun.star.beans.PropertyChangeEvent;
43 import com.sun.star.beans.XPropertySet;
44 import com.sun.star.beans.Property;
45 import com.sun.star.beans.PropertyAttribute;
46 import com.sun.star.beans.UnknownPropertyException;
47 import com.sun.star.beans.XPropertiesChangeListener;
48 import com.sun.star.beans.XPropertySetInfo;
49 import com.sun.star.beans.XFastPropertySet;
50 import com.sun.star.beans.PropertyVetoException;
51 import com.sun.star.beans.XMultiPropertySet;
52 import java.util.Iterator;
53 import java.util.Collection;
54 import java.util.HashMap;
55 import java.lang.reflect.Field;
56 import com.sun.star.lang.DisposedException;
59 /** This class is an implementation of the interfaces com.sun.star.beans.XPropertySet,
60 * com.sun.star.beans.XFastPropertySet and com.sun.star.beans.XMultiPropertySet. This
61 * class has to be inherited to be used. The values of properties are stored in member
62 * variables of the inheriting class. By overriding the methods
63 * {@link #convertPropertyValue convertPropertyValue},
64 * {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} and
65 * {@link #getPropertyValue(Property)} one can determine how
66 * property values are stored.
67 * When using the supplied implementations of this class then the member variables which
68 * hold property values have to be declared in the class which inherits last in the inheriting
69 * chain and they have to be public<p>
70 * Properties have to be registered by one of the registerProperty methods. They take among other
71 * arguments an Object named <em>id</em> which has to be a String that represents the name of
72 * the member variable. The registering has to occur in the constructor of the inheriting class.
73 * It is no allowed to add or change properties later on.<p>
74 * Example:
75 * <pre>
76 * public class Foo extends PropertySet
77 * {
78 * protected int intProp;
80 * public Foo()
81 * {
82 * registerProperty("PropertyA", 0, new Type(int.class), (short)0, "intProp");
83 * }
84 * }
86 * </pre>
88 public class PropertySet extends ComponentBase implements XPropertySet, XFastPropertySet,
89 XMultiPropertySet
91 private HashMap _nameToPropertyMap;
92 private HashMap _handleToPropertyMap;
93 private HashMap _propertyToIdMap;
94 private Property[] arProperties;
96 private int lastHandle= 1;
98 protected XPropertySetInfo propertySetInfo;
99 protected MultiTypeInterfaceContainer aBoundLC= new MultiTypeInterfaceContainer();
100 protected MultiTypeInterfaceContainer aVetoableLC= new MultiTypeInterfaceContainer();
101 public PropertySet()
103 super();
104 initMappings();
107 /** Registers a property with this helper class and associates the argument <em>id</em> with it.
108 * <em>id</em> is used to identify the storage of the property value. How property values are stored
109 * and retrieved is determined by the methods {@link #convertPropertyValue convertPropertyValue},
110 * {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} and {@link #getPropertyValue(Property) getPropertyValue}
111 * These methods expect <em>id</em> to be a java.lang.String which represents the name of a member variable
112 * which holds the property value.
113 * Only properties which are registered can be accessed. Registration has to occur during
114 * initialization of the inheriting class (i.e. within the contructor).
115 * @param prop The property to be registered.
116 * @param id Identifies the properties storage.
117 * @see #getPropertyId
119 protected void registerProperty(Property prop, Object id)
121 putProperty(prop);
122 assignPropertyId(prop, id);
125 /** Registers a property with this helper class and associates the argument id with it.
126 * It does the same as {@link #registerProperty(Property, Object)}. The first four
127 * arguments are used to construct a Property object.
128 * Registration has to occur during
129 * initialization of the inheriting class (i.e. within the contructor)
130 * @param name The property's name (Property.Name).
131 * @param handle The property's handle (Property.Handle).
132 * @param Type The property's type (Property.Type).
133 * @param attributes The property's attributes (Property.Attributes).
134 * @param id Identifies the property's storage.
136 protected void registerProperty(String name, int handle, Type type, short attributes, Object id)
138 Property p= new Property(name, handle, type, attributes);
139 registerProperty(p, id);
142 /** Registers a property with this class and associates the argument id with it.
143 * It does the same as {@link #registerProperty(Property, Object)}. The first three
144 * arguments are used to construct a Property object. The value for the Property.Handle
145 * is generated and does not have to be specified here. Use this method for registering
146 * a property if you do not care about the Property's handles.
147 * Registration has to occur during
148 * initialization of the inheriting class (i.e. within the contructor).
149 * @param name The property's name (Property.Name).
150 * @param handle The property's handle (Property.Handle).
151 * @param Type The property's type (Property.Type).
152 * @param attributes The property's attributes (Property.Attributes).
153 * @param id Identifies the property's storage.
155 protected void registerProperty(String name, Type type, short attributes, Object id)
157 Property p= new Property(name, lastHandle++, type, attributes);
158 registerProperty(p, id);
161 /** Registers a property with this class. This method expects that property values
162 * are stored in member variables as is the case if the methods convertPropertyValue,
163 * setPropertyValueNoBroadcast and getPropertyValue(Property) are not overridden.
164 * It is presumed that the type of the member variable
165 * corresponds Property.Type. For example, if the TypeClass of Property.Type is to be
166 * a TypeClass.SHORT then the member must be a short or java.lang.Short.
167 * The handle for the property is generated.<br>
168 * If there is no member with the specified name or if the member has an incompatible type
169 * then a com.sun.star.uno.RuntimeException is thrown.
170 * @param propertyName The name of the property.
171 * @param memberName The name of the member variable that holds the value of the property.
172 * @param attributes The property attributes.
174 protected void registerProperty(String propertyName, String memberName, short attributes)
176 Field propField= null;
177 try
179 propField= getClass().getDeclaredField(memberName);
181 catch (NoSuchFieldException e)
183 throw new com.sun.star.uno.RuntimeException("there is no member variable: " + memberName);
185 Class cl= propField.getType();
186 Type t= new Type(cl);
187 if (t.getTypeClass() != TypeClass.UNKNOWN)
189 Property p= new Property(propertyName, lastHandle++, t, attributes);
190 registerProperty(p,memberName);
192 else
193 throw new com.sun.star.uno.RuntimeException("the member has an unknown type: " + memberName);
196 /** Registers a property with this class.
197 * It is presumed that the name of property is equal to the name of the member variable
198 * that holds the property value.
199 * @param propertyName The name of the property and the member variable that holds the property's value.
200 * @param attributes The property attributes.
201 * @see #registerProperty(String, String, short)
203 protected void registerProperty(String propertyName, short attributes)
205 registerProperty(propertyName, propertyName, attributes);
210 /** Returns the Property object for a given property name or null if that property does
211 * not exists (i.e. it has not been registered). Override this method
212 * if you want to implement your own mapping from property names to Property objects.
213 * Then you also have to override {@link #initMappings}, {@link #getProperties()} and
214 * {@link #putProperty(Property)}.
215 * @param propertyName The name of the property (Property.Name)
216 * @return The Property object with the name <em>propertyName</em>.
218 protected Property getProperty(String propertyName)
220 return (Property) _nameToPropertyMap.get(propertyName);
223 /** Returns the Property object with a handle (Property.Handle) as specified by the argument
224 * <em>nHandle</em>. The method returns null if there is no such property (i.e. it has not
225 * been registered). Override this method if you want to implement your own mapping from handles
226 * to Property objects. Then you also have to override {@link #initMappings}, {@link #putProperty(Property)}.
227 * @param nHandle The handle of the property (Property.Handle).
228 * @return The Property object with the handle <em>nHandle</em>
230 protected Property getPropertyByHandle(int nHandle)
232 return (Property) _handleToPropertyMap.get(new Integer(nHandle));
235 /** Returns an array of all Property objects or an array of length null if there
236 * are no properties. Override this method if you want to implement your own mapping from names
237 * to Property objects. Then you also have to override {@link #initMappings}, {@link #getProperty(String)} and
238 * {@link #putProperty}.
239 * @return Array of all Property objects.
241 protected Property[] getProperties()
243 if (arProperties == null)
245 Collection values= _nameToPropertyMap.values();
246 arProperties= (Property[]) values.toArray(new Property[_nameToPropertyMap.size()]);
248 return arProperties;
251 /** Stores a Property object so that it can be retrieved subsequently by
252 * {@link #getProperty(String)},{@link #getProperties()},{@link #getPropertyByHandle(int)}.
253 * Override this method if you want to implement your own mapping from handles
254 * to Property objects and names to Property objects. Then you also need to override {@link #initMappings},
255 * {@link #getProperty(String)},{@link #getProperties()},{@link #getPropertyByHandle(int)}.
256 * @param prop The Property object that is to be stored.
258 protected void putProperty(Property prop)
260 _nameToPropertyMap.put(prop.Name, prop);
261 if (prop.Handle != -1)
262 _handleToPropertyMap.put(new Integer(prop.Handle), prop);
265 /** Assigns an identifyer object to a Property object so that the identifyer
266 * can be obtained by {@link #getPropertyId getPropertyId} later on. The identifyer
267 * is used to specify a certain storage for the property's value. If you do not
268 * override {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} or {@link #getPropertyValue(Property)}
269 * then the argument <em>id</em> has to be a java.lang.String that equals the name of
270 * the member variable that holds the Property's value.
271 * Override this method if you want to implement your own mapping from Property objects to ids or
272 * if you need ids of a type other then java.lang.String.
273 * Then you also need to override {@link #initMappings initMappings} and {@link #getPropertyId getPropertyId}.
274 * @param prop The Property object that is being assigned an id.
275 * @param id The object which identifies the storage used for the property's value.
276 * @see #registerProperty(Property, Object)
278 protected void assignPropertyId(Property prop, Object id)
280 if (id instanceof String && ((String) id).equals("") == false)
281 _propertyToIdMap.put(prop, id);
284 /** Returns the identifyer object for a certain Property. The object must have been
285 * previously assigned to the Property object by {@link #assignPropertyId assignPropertyId}.
286 * Override this method if you want to implement your own mapping from Property objects to ids.
287 * Then you also need to override {@link #initMappings initMappings} and {@link #assignPropertyId assignPropertyId}.
288 * @param prop The property for which the id is to be retrieved.
289 * @return The id object that identifies the storage used for the property's value.
290 * @see #registerProperty(Property, Object)
292 protected Object getPropertyId(Property prop)
294 return _propertyToIdMap.get(prop);
297 /** Initializes data structures used for mappings of property names to property object,
298 * property handles to property objects and property objects to id objects.
299 * Override this method if you want to implement your own mappings. Then you also need to
300 * override {@link #putProperty putProperty},{@link #getProperty getProperty}, {@link #getPropertyByHandle},
301 * {@link #assignPropertyId assignPropertyId} and {@link #getPropertyId getPropertyId}.
303 protected void initMappings()
305 _nameToPropertyMap= new HashMap();
306 _handleToPropertyMap= new HashMap();
307 _propertyToIdMap= new HashMap();
310 /** Makes sure that listeners which are kept in aBoundLC (XPropertyChangeListener) and aVetoableLC
311 * (XVetoableChangeListener) receive a disposing call. Also those listeners are relesased.
313 protected void postDisposing()
315 // Create an event with this as sender
316 EventObject aEvt= new EventObject(this);
318 // inform all listeners to reelease this object
319 aBoundLC.disposeAndClear(aEvt);
320 aVetoableLC.disposeAndClear(aEvt);
323 //XPropertySet ----------------------------------------------------
324 synchronized public void addPropertyChangeListener(String str, XPropertyChangeListener xPropertyChangeListener)
325 throws UnknownPropertyException, WrappedTargetException
327 // only add listeners if you are not disposed
328 if (! bInDispose && ! bDisposed)
330 if (str.length() > 0)
332 Property prop= getProperty(str);
333 if (prop == null)
334 throw new UnknownPropertyException("Property " + str + " is unknown");
336 // Add listener for a certain property
337 if ((prop.Attributes & PropertyAttribute.BOUND) > 0)
338 aBoundLC.addInterface(str, xPropertyChangeListener);
339 else
340 //ignore silently
341 return;
343 else
344 // Add listener for all properties
345 listenerContainer.addInterface(XPropertyChangeListener.class, xPropertyChangeListener);
348 //XPropertySet ----------------------------------------------------
349 synchronized public void addVetoableChangeListener(String str, com.sun.star.beans.XVetoableChangeListener xVetoableChangeListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
351 // only add listeners if you are not disposed
352 if (! bInDispose && ! bDisposed)
354 if (str.length() > 0)
356 Property prop= getProperty(str);
357 if (prop == null)
358 throw new UnknownPropertyException("Property " + str + " is unknown");
360 // Add listener for a certain property
361 if ((prop.Attributes & PropertyAttribute.CONSTRAINED) > 0)
362 aVetoableLC.addInterface(str, xVetoableChangeListener);
363 else
364 //ignore silently
365 return;
367 else
368 // Add listener for all properties
369 listenerContainer.addInterface(XVetoableChangeListener.class, xVetoableChangeListener);
372 //XPropertySet ----------------------------------------------------
373 public com.sun.star.beans.XPropertySetInfo getPropertySetInfo()
375 if (propertySetInfo == null)
377 synchronized (this)
379 if (propertySetInfo == null)
380 propertySetInfo= new PropertySetInfo();
383 return propertySetInfo;
385 //XPropertySet ----------------------------------------------------
386 public Object getPropertyValue(String name) throws UnknownPropertyException, WrappedTargetException
388 Object ret= null;
389 if (bInDispose || bDisposed)
390 throw new com.sun.star.lang.DisposedException("The component has been disposed already");
392 Property prop= getProperty(name);
393 if (prop == null)
394 throw new UnknownPropertyException("The property " + name + " is unknown");
396 synchronized (this)
398 ret= getPropertyValue(prop);
400 // null must not be returned. Either a void any is returned or an any containing
401 // an interface type and a null reference.
402 if (ret == null)
404 if (prop.Type.getTypeClass() == TypeClass.INTERFACE)
405 ret= new Any(prop.Type, null);
406 else
407 ret= new Any(new Type(void.class), null);
409 return ret;
412 //XPropertySet ----------------------------------------------------
413 synchronized public void removePropertyChangeListener(String propName, XPropertyChangeListener listener) throws UnknownPropertyException, WrappedTargetException
414 { // all listeners are automaticly released in a dispose call
415 if (!bInDispose && !bDisposed)
417 if (propName.length() > 0)
419 Property prop = getProperty(propName);
420 if (prop == null)
421 throw new UnknownPropertyException("Property " + propName + " is unknown");
422 aBoundLC.removeInterface(propName, listener);
424 else
425 listenerContainer.removeInterface(XPropertyChangeListener.class, listener);
429 //XPropertySet ----------------------------------------------------
430 synchronized public void removeVetoableChangeListener(String propName, XVetoableChangeListener listener) throws UnknownPropertyException, WrappedTargetException
431 {// all listeners are automaticly released in a dispose call
432 if (!bInDispose && !bDisposed)
434 if (propName.length() > 0)
436 Property prop = getProperty(propName);
437 if (prop == null)
438 throw new UnknownPropertyException("Property " + propName + " is unknown");
439 aVetoableLC.removeInterface(propName, listener);
441 else
442 listenerContainer.removeInterface(XVetoableChangeListener.class, listener);
446 //XPropertySet ----------------------------------------------------
447 /** Sets the value of a property.
448 * The idl description for this interfaces, stipulates that the argument value is an Any. Since a java.lang.Object
449 * reference has the same meaning as an Any this function accepts
450 * java anys (com.sun.star.uno.Any) and all other appropriate objects as arguments. The value argument can be one
451 * of these:
452 * <ul>
453 * <li>java.lang.Boolean</li>
454 * <li>java.lang.Character</li>
455 * <li>java.lang.Byte</li>
456 * <li>java.lang.Short</li>
457 * <li>java.lang.Integer</li>
458 * <li>java.lang.Long</li>
459 * <li>java.lang.Float</li>
460 * <li>java.lang.Double</li>
461 * <li>java.lang.String</li>
462 * <li>com.sun.star.uno.Type</li>
463 * <li><em>objects which implement UNO interfaces</em></li>
464 * <li><em>arrays which contain elements of the types above</em></li>
465 * <li>com.sun.star.uno.Any containing an instance of one of the above types</li>
466 * </ul>
468 * Properties can have the attribute com.sun.star.beans.PropertyAttribute.MAYBEVOID, which means that the value
469 * (not the type) can be void. In order to assign a void value to a property one can either pass an Any which
470 * contains a null reference or pass null directly. In bothe cases the null reference is only accepted if
471 * the PropertyAttribute.MAYBEVOID attribute is set for the property.
473 * Properties which have the attribute MAYBEVOID set (Property.Attributes) can have a void value. The following
474 * considerations presume that the Property has that attribute set. Further, when mentioning an Any's value we
475 * actually refer to the object returned by Any.getObject.
476 * If the argument <em>value</em> is null, or it is an Any whose value is null (but with a valid Type)
477 * then the member variable used for storing the property's value is set to null.
478 * Therefore those properties can only be stored in objects
479 * and primitive types are not allowed (one can use the wrapper classes instead,e.g. java.lang.Byte) .
480 * If a property's value is kept in a member variable of type Any and that reference is still null
481 * then when setPropertyValue is called with
482 * <em>value</em> = null then the member variable is assigned an Any with type void and a null value.
483 * Or if the argument is an Any with a null value then it is assigned to the member variable.
484 * Further, if the variable already
485 * references an Any and setPropertyValue is called with <em>value</em> = null, then the variable is assigned
486 * a new Any with the same type as the previously referenced Any and with a null value.
487 * @param name The name of the property.
488 * @param value The new value of the property.
489 * * */
490 public void setPropertyValue(String name, Object value) throws UnknownPropertyException,
491 PropertyVetoException, com.sun.star.lang.IllegalArgumentException, WrappedTargetException
493 Property prop= getProperty(name);
494 if (prop == null)
495 throw new UnknownPropertyException("Property " + name + " is unknown");
496 setPropertyValue(prop, value);
499 /** Sets the value of a property. It checks if the property's attributes (READONLY,MAYBEVOID), allow that the
500 * new value can be set. It also causes the notification of listeners.
501 * @param prop The property whose value is to be set.
502 * @param value The new value for the property.
504 protected void setPropertyValue(Property prop, Object value) throws UnknownPropertyException,
505 PropertyVetoException, com.sun.star.lang.IllegalArgumentException, WrappedTargetException
507 if ((prop.Attributes & PropertyAttribute.READONLY) == PropertyAttribute.READONLY)
508 throw new com.sun.star.beans.PropertyVetoException();
509 // The value may be null only if MAYBEVOID attribute is set
510 boolean bVoidValue= false;
511 if (value instanceof Any)
512 bVoidValue= ((Any) value).getObject() == null;
513 else
514 bVoidValue= value == null;
515 if (bVoidValue && (prop.Attributes & PropertyAttribute.MAYBEVOID) == 0)
516 throw new com.sun.star.lang.IllegalArgumentException("The property must have a value; the MAYBEVOID attribute is not set!");
517 if (bInDispose || bDisposed)
518 throw new DisposedException("Component is already disposed");
520 //Check if the argument is allowed
521 boolean bValueOk= false;
522 if (value instanceof Any)
523 bValueOk= checkType(((Any) value).getObject());
524 else
525 bValueOk= checkType(value);
526 if (! bValueOk)
527 throw new com.sun.star.lang.IllegalArgumentException("No valid UNO type");
530 boolean bConversionOk= false;
531 Object[] outConvertedVal= new Object[1];
532 Object[] outOldValue= new Object[1];
533 synchronized (this)
535 bConversionOk= convertPropertyValue(prop, outConvertedVal, outOldValue, value);
538 //The next step following the conversion is to set the new value of the property. Prior to this
539 // the XVetoableChangeListener s have to be notified.
540 if (bConversionOk)
542 // If the property is CONSTRAINED, then we must notify XVetoableChangeListener. The listener can throw a com.sun.star.lang.beans.PropertyVetoException which
543 // will cause this method to return (the exception is not caught here).
544 fire( new Property[]{prop}, outConvertedVal, outOldValue, true);
546 synchronized (this)
548 setPropertyValueNoBroadcast(prop, outConvertedVal[0]);
550 // fire a change event (XPropertyChangeListener, PropertyAttribute.BOUND
551 fire( new Property[]{prop}, outConvertedVal, outOldValue, false);
555 /** Converts a value in a way so that it is appropriate for storing as a property value, that is
556 * {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} can process the value without any further
557 * conversion. This implementation presumes that
558 * the values are stored in member variables of the furthest inheriting class. For example,
559 * class A inherits this class then members of class A
560 * can hold property values. If there is a class B which inherits A then only members of B can hold
561 * property values. The variables must be public. A property must have been registered (e.g. by
562 * {@link #registerProperty(Property, Object)} in order for this method to work. The identifyer argument (type Object)
563 * used in the registerProperty methods must
564 * be a java.lang.String, which is, the name of the member variable that holds the property value.
565 * If one opts to store values differently then one may override
566 * this method, as well as {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} and
567 * {@link #getPropertyValue(Property) getPropertyValue(Property)}.
568 * This method is always called as a result of a call to one of the setter methods, such as
569 * {@link #setPropertyValue(String,Object) XPropertySet.setPropertyValue},
570 * {@link #setFastPropertyValue XFastPropertySet.setFastPropertyValue}
571 * and {@link #setPropertyValues XMultiPropertySet.setPropertyValues}.
572 * If this method fails, that is, it returns false or throws an exception, then no listeners are notified and the
573 * property value, that was intended to be changed, remains untouched.<br /> This method does not have to deal with property attributes, such as
574 * PropertyAttribute.READONLY or PropertyAttribute.MAYBEVOID. The processing of these attributes occurs
575 * in the calling methods.<br />
576 * Only if this method returns successfully further processing, such
577 * as listener notification and finally the modifiction of the property's value, will occur.<br />
579 * The actual modification of a property's value is done by {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast}
580 * which is called subsequent to convertPropertyValue.
581 *<p>
582 * This method converts values by help of the com.sun.star.uno.AnyConverter which only does a few widening
583 * conversions on integer types and floating point types. For example, there is the property PropA with a Type equivalent
584 * to int.class and the
585 * value of the property is to be stored in a member variable of type int with name intProp. Then setPropertyValue is
586 * called:
587 * <pre>
588 * set.setPropertyValue( "PropA", new Byte( (byte)111));
589 * </pre>
590 * At some point setPropertyValue will call convertPropertyValue and pass in the Byte object. Since we allow
591 * that Byte values can be used with the property and know that the value is to be stored in intProp (type int)
592 * we convert the Byte object into an Integer object which is then returned in the out-parameter <em>newVal</em>. This
593 * conversion is actually performed by the AnyConverter. Later
594 * the setPropertyValueNoBroadcast is called with that Integer object and the int value can be easily extracted
595 * from the object and be assigned to the member intProp.
596 * <p>
597 * The method handles Any arguments the same as Object arguments. That is, the <em>setVal</em> argument can
598 * be a java.lang.Boolean or a com.sun.star.uno.Any containing a java.lang.Boolean. Likewise, a member
599 * containing a property value can be a com.sun.star.uno.Any or an java.lang.Object.
600 * Then, no conversion is necessary, since they can hold all possible values. However, if
601 * the member is an Object and <em>setVal</em> is an Any then the object contained in the any is assigned to
602 * the member. The extra type information which exists as Type object in the Any will get lost. If this is not
603 * intended then use an Any variable rather then an Object.<br />
604 * If a member is an Object or Any and the argument <em>setVal</em> is an Object, other than String or array,
605 * then it is presumed to be an UNO object and queried for XInterface. If successful, the out-param <em>newVal</em>
606 * returns the XInterface.<br />
607 * If a member is an UNO interface, then <em>setVal</em> is queried for this interface and the result is returned.
608 * If <em>setVal</em> is null then <em>newVal</em> will be null too after return.
609 * <p>
610 * If a property value is stored using a primitive type the the out-parameters
611 * <em>curVal</em> and <em>newVal</em> contain the respective wrapper class (e.g.java.lang.Byte, etc.).
612 * curVal is used in calls to the XVetoableChangeListener and XPropertyChangeListener.
614 * @param property - in-param property for which the data is to be converted.
615 * @param newVal - out-param which contains the converted value on return.
616 * @param curVal - out-param the current value of the property. It is used in calls to the
617 * XVetoableChangeListener and XPropertyChangeListener.
618 * @param setVal - in-param. The value that is to be converted so that it matches Property and the internally used
619 * dataformat for that property.
620 * @return true - Conversion was successful. <em>newVal</em> contains a valid value for the property. false -
621 * conversion failed for some reason.
622 * @throws com.sun.star.lang.IllegalArgumentException The value provided is unfit for the property.
623 * @throws com.sun.star.lang.WrappedTargetException - An exception occured during the conversion, that is to be made known
624 * to the caller.
626 protected boolean convertPropertyValue(Property property, Object[] newVal, Object[]curVal, Object setVal)
627 throws com.sun.star.lang.IllegalArgumentException, WrappedTargetException, UnknownPropertyException
629 boolean ret= true;
632 // get the member name
633 String sMember= (String) getPropertyId(property);
634 if (sMember != null)
636 // use reflection to obtain the field that holds the property value
637 // Class.getDeclaredFields does not return inherited fields. One could use Class.getFields to
638 // also get inherited fields, but only those which are public.
639 Field propField= getClass().getDeclaredField(sMember);
640 if (propField != null)
642 curVal[0]= propField.get(this);
643 Class memberClass= propField.getType();
645 // MAYBEVOID: if setVal == null or it is an Any and getObject returns null, then a void value is to be set
646 // This works only if there are no primitive types. For those we use the respective wrapper classes.
647 // In this implementation, a null reference means void value.
648 boolean bVoidValue= false;
649 boolean bAnyVal= setVal instanceof Any;
650 if (bAnyVal)
651 bVoidValue= ((Any) setVal).getObject() == null;
652 else
653 bVoidValue= setVal == null;
654 if (bVoidValue && memberClass.isPrimitive())
655 throw new com.sun.star.lang.IllegalArgumentException("The implementation does not support the MAYBEVOID attribute for this property");
657 Object convObj= null;
658 //The member that keeps the value of the Property is an Any. It can contain all possible
659 //types, therefore a conversion is not necessary.
660 if (memberClass.equals(Any.class))
662 if (bAnyVal)
663 //parameter setVal is also an Any and can be used without further processing
664 convObj= setVal;
665 else
667 // Parameter setVal is not an Any. We need to construct an Any that contains
668 // the argument setVal.
669 // If setVal is an interface implementation then, we cannot constuct the
670 // Any with setVal.getClass(), because the Any.Type._typeClass would be TypeClass.UNKNOWN.
671 // We try to get an XInterface of setVal and set an XInterface type.
672 if (setVal instanceof XInterface)
674 XInterface xint= UnoRuntime.queryInterface(XInterface.class, setVal);
675 if (xint != null)
676 convObj= new Any(new Type(XInterface.class), xint);
678 // The member is an any, and the past in argument was null reference (MAYBEVOID is set)
679 else if (setVal == null)
681 // if the any member is still null we create a void any
682 if (curVal[0] == null)
683 convObj= new Any(new Type(), null);
684 else
686 //otherwise we create an Any with the same type as a value of null;
687 convObj= new Any( ((Any)curVal[0]).getType(), null);
690 else
691 convObj= new Any(new Type(setVal.getClass()), setVal);
694 else
695 convObj= convert(memberClass, setVal);
696 newVal[0]= convObj;
699 else
700 throw new UnknownPropertyException("Property " + property.Name + " is unknown");
702 catch (java.lang.NoSuchFieldException e)
704 throw new WrappedTargetException("Field does not exist", this, e);
706 catch (java.lang.IllegalAccessException e)
708 throw new WrappedTargetException("", this ,e);
710 return ret;
713 private boolean checkType(Object obj)
715 if (obj == null
716 || obj instanceof Boolean
717 || obj instanceof Character
718 || obj instanceof Number
719 || obj instanceof String
720 || obj instanceof XInterface
721 || obj instanceof Type
722 || obj instanceof com.sun.star.uno.Enum
723 || obj.getClass().isArray())
724 return true;
725 return false;
728 // Param object can be an Any or other object. If obj is null then the return value is null
729 private Object convert( Class cl, Object obj) throws com.sun.star.lang.IllegalArgumentException
731 Object retVal= null;
732 //The member that keeps the value of the Property is an Object.Objects are similar to Anys in that they can
733 // hold all types.
734 if (obj == null || (obj instanceof Any && ((Any) obj).getObject() == null))
735 retVal= null;
736 else if(cl.equals(Object.class))
738 if (obj instanceof Any)
739 obj= ((Any) obj).getObject();
740 retVal= obj;
742 else if(cl.equals(boolean.class))
743 retVal= new Boolean(AnyConverter.toBoolean(obj));
744 else if (cl.equals(char.class))
745 retVal= new Character(AnyConverter.toChar(obj));
746 else if (cl.equals(byte.class))
747 retVal= new Byte(AnyConverter.toByte(obj));
748 else if (cl.equals(short.class))
749 retVal= new Short(AnyConverter.toShort(obj));
750 else if (cl.equals(int.class))
751 retVal= new Integer(AnyConverter.toInt(obj));
752 else if (cl.equals(long.class))
753 retVal= new Long(AnyConverter.toLong(obj));
754 else if (cl.equals(float.class))
755 retVal= new Float(AnyConverter.toFloat(obj));
756 else if (cl.equals(double.class))
757 retVal= new Double(AnyConverter.toDouble(obj));
758 else if (cl.equals(String.class))
759 retVal= AnyConverter.toString(obj);
760 else if (cl.isArray())
761 retVal= AnyConverter.toArray(obj);
762 else if (cl.equals(Type.class))
763 retVal= AnyConverter.toType(obj);
764 else if (cl.equals(Boolean.class))
765 retVal= new Boolean(AnyConverter.toBoolean(obj));
766 else if (cl.equals(Character.class))
767 retVal= new Character(AnyConverter.toChar(obj));
768 else if (cl.equals(Byte.class))
769 retVal= new Byte(AnyConverter.toByte(obj));
770 else if (cl.equals(Short.class))
771 retVal= new Short(AnyConverter.toShort(obj));
772 else if (cl.equals(Integer.class))
773 retVal= new Integer(AnyConverter.toInt(obj));
774 else if (cl.equals(Long.class))
775 retVal= new Long(AnyConverter.toLong(obj));
776 else if (cl.equals(Float.class))
777 retVal= new Float(AnyConverter.toFloat(obj));
778 else if (cl.equals(Double.class))
779 retVal= new Double(AnyConverter.toDouble(obj));
780 else if (XInterface.class.isAssignableFrom(cl))
781 retVal= AnyConverter.toObject(new Type(cl), obj);
782 else if (com.sun.star.uno.Enum.class.isAssignableFrom(cl))
783 retVal= AnyConverter.toObject(new Type(cl), obj);
784 else
785 throw new com.sun.star.lang.IllegalArgumentException("Could not convert the argument");
786 return retVal;
789 /** Sets the value of a property. In this implementation property values are stored in member variables
790 * (see {@link #convertPropertyValue convertPropertyValue} Notification of property listeners
791 * does not occur in this method. By overriding this method one can take full control about how property values
792 * are stored. But then, the {@link #convertPropertyValue convertPropertyValue} and
793 * {@link #getPropertyValue(Property)} must be overridden too.
795 * A Property with the MAYBEVOID attribute set, is stored as null value. Therefore the member variable must be
796 * an Object in order to make use of the property attribute. An exception is Any. The Any variable can be initially null, but
797 * once it is set the reference will not become null again. If the value is to be set to
798 * void then a new Any will be stored
799 * with a valid type but without a value (i.e. Any.getObject returns null).
800 * If a property has the READONLY attribute set, and one of the setter methods, such as setPropertyValue, has been
801 * called, then this method is not going to be called.
802 * @param property the property for which the new value is set
803 * @param value the new value for the property.
804 * @throws com.sun.star.lang.WrappedTargetException An exception, which has to be made known to the caller,
805 * occured during the setting of the value.
807 protected void setPropertyValueNoBroadcast(Property property, Object newVal)
808 throws WrappedTargetException
812 // get the member name
813 String sMember= (String) getPropertyId(property);
814 if (sMember != null)
816 // use reflection to obtain the field that holds the property value
817 // Class.getDeclaredFields does not return inherited fields. One could use Class.getFields to
818 // also get inherited fields, but only those which are public.
819 Field propField= getClass().getDeclaredField(sMember);
820 if (propField != null)
821 propField.set(this, newVal);
824 catch(java.lang.Exception e)
826 throw new WrappedTargetException("PropertySet.setPropertyValueNoBroadcast", this, e);
829 /** Retrieves the value of a property. This implementation presumes that the values are stored in member variables
830 * of the furthest inheriting class (see {@link #convertPropertyValue convertPropertyValue}) and that the
831 * variables are public. The property must have
832 * been registered, for example by {@link #registerProperty(Property, Object)}. The identifyer Object argument
833 * must have been a java.lang.String which was the name of the member variable holding the property value.
834 * When properties are to be stored differently one has to override this method as well as
835 * {@link #convertPropertyValue} and {@link #setPropertyValueNoBroadcast}. <br>
836 * If a value is stored in a variable of a primitive type then this method returns an instance of the respective
837 * wrapper class (e.g. java.lang.Boolean).
838 * @param property The property for which the value is to be retrieved.
839 * @return The value of the property.
841 protected Object getPropertyValue(Property property)
842 throws com.sun.star.lang.WrappedTargetException
844 Object ret= null;
847 // get the member name
848 String sMember= (String) getPropertyId(property);
849 if (sMember != null)
851 // use reflection to obtain the field that holds the property value
852 // Class.getDeclaredFields does not return inherited fields. One could use Class.getFields to
853 // also get inherited fields, but only those which are public.
854 Field propField= getClass().getDeclaredField(sMember);
855 if (propField != null)
856 ret= propField.get(this);
859 catch(java.lang.Exception e)
861 throw new WrappedTargetException("PropertySet.setPropertyValue_NoBroadcast", this, e);
863 return ret;
867 * This method fires events to XPropertyChangeListener,XVetoableChangeListener and
868 * XPropertiesChangeListener event sinks.
869 * To distinguish what listeners are to be called the argument <em>bVetoable</em> is to be set to true if
870 * a XVetoableChangeListener is meant. For XPropertyChangeListener and XPropertiesChangeListener
871 * it is to be set to false.
873 * @param properties Properties wich will be or have been affected.
874 * @param newValues the new values of the properties.
875 * @param oldValues the old values of the properties.
876 * @param bVetoable true means fire to VetoableChangeListener, false means fire to
877 * XPropertyChangedListener and XMultiPropertyChangedListener.
879 protected void fire(
880 Property[] properties,
881 Object[] newValues,
882 Object[] oldValues,
883 boolean bVetoable ) throws PropertyVetoException
885 // Only fire, if one or more properties changed
886 int nNumProps= properties.length;
887 if (nNumProps > 0)
889 PropertyChangeEvent[] arEvts= new PropertyChangeEvent[nNumProps];
890 int nAffectedProps= 0;
891 // Loop over all changed properties to fill the event struct
892 for (int i= 0; i < nNumProps; i++)
894 if ((bVetoable && (properties[i].Attributes & PropertyAttribute.CONSTRAINED) > 0)
895 || (!bVetoable && (properties[i].Attributes & PropertyAttribute.BOUND) > 0))
897 arEvts[i]= new PropertyChangeEvent(this, properties[i].Name, false,
898 properties[i].Handle, oldValues[i], newValues[i]);
899 nAffectedProps++;
902 // fire the events for all changed properties
903 for (int i= 0; i < nAffectedProps; i++)
905 // get the listener container for the property name
906 InterfaceContainer lc= null;
907 if (bVetoable)
908 lc= aVetoableLC.getContainer(arEvts[i].PropertyName);
909 else
910 lc= aBoundLC.getContainer(arEvts[i].PropertyName);
911 if (lc != null)
913 Iterator it= lc.iterator();
914 while( it.hasNext())
916 Object listener= it.next();
917 if (bVetoable)
918 ((XVetoableChangeListener) listener).vetoableChange(arEvts[i]);
919 else
920 ((XPropertyChangeListener) listener).propertyChange(arEvts[i]);
923 // broadcast to all listeners with "" property name
924 if(bVetoable)
925 lc= listenerContainer.getContainer(XVetoableChangeListener.class);
926 else
927 lc= listenerContainer.getContainer(XPropertyChangeListener.class);
928 if(lc != null)
930 Iterator it= lc.iterator();
931 while(it.hasNext() )
933 Object listener= it.next();
934 if( bVetoable ) // fire change Events?
935 ((XVetoableChangeListener) listener).vetoableChange(arEvts[i]);
936 else
937 ((XPropertyChangeListener) listener).propertyChange(arEvts[i]);
941 // fire at XPropertiesChangeListeners
942 // if nAffectedProps == 0 then there are no BOUND properties
943 if (!bVetoable && nAffectedProps > 0)
946 PropertyChangeEvent[] arReduced= new PropertyChangeEvent[nAffectedProps];
947 System.arraycopy(arEvts, 0, arReduced, 0, nAffectedProps);
948 InterfaceContainer lc= listenerContainer.getContainer(XPropertiesChangeListener.class);
949 if (lc != null)
951 Iterator it= lc.iterator();
952 while (it.hasNext())
954 XPropertiesChangeListener listener = (XPropertiesChangeListener) it.next();
955 // fire the hole event sequence to the XPropertiesChangeListener's
956 listener.propertiesChange( arEvts );
962 // XFastPropertySet--------------------------------------------------------------------------------
963 public void setFastPropertyValue(int nHandle, Object aValue ) throws UnknownPropertyException,
964 PropertyVetoException, com.sun.star.lang.IllegalArgumentException, WrappedTargetException
966 Property prop= getPropertyByHandle(nHandle);
967 if (prop == null)
968 throw new UnknownPropertyException(" The property with handle : " + nHandle +" is unknown");
969 setPropertyValue(prop, aValue);
972 // XFastPropertySet --------------------------------------------------------------------------------
973 public Object getFastPropertyValue(int nHandle ) throws UnknownPropertyException,
974 WrappedTargetException
976 Property prop= getPropertyByHandle(nHandle);
977 if (prop == null)
978 throw new UnknownPropertyException("The property with handle : " + nHandle + " is unknown");
979 return getPropertyValue(prop);
982 // XMultiPropertySet -----------------------------------------------------------------------------------
983 public void addPropertiesChangeListener(String[] propNames, XPropertiesChangeListener listener)
985 listenerContainer.addInterface(XPropertiesChangeListener.class, listener);
988 // XMultiPropertySet -----------------------------------------------------------------------------------
989 public void firePropertiesChangeEvent(String[] propNames, XPropertiesChangeListener listener)
991 // Build the events.
992 PropertyChangeEvent[] arEvents= new PropertyChangeEvent[propNames.length];
993 int eventCount= 0;
994 // get a snapshot of the current property values
995 synchronized (this)
997 for (int i= 0; i < propNames.length; i++)
999 Property prop= getProperty(propNames[i]);
1000 if (prop != null)
1002 Object value= null;
1003 try
1005 value= getPropertyValue(prop);
1007 catch(WrappedTargetException e)
1009 continue;
1011 arEvents[eventCount]= new PropertyChangeEvent(this, prop.Name,
1012 false, prop.Handle, value, value);
1013 eventCount++;
1018 // fire events from unsynchronized section so as to prevent deadlocks
1019 if (eventCount > 0)
1021 // Reallocate the array of the events if necessary
1022 if (arEvents.length != eventCount)
1024 PropertyChangeEvent[] arPropsTmp= new PropertyChangeEvent[eventCount];
1025 System.arraycopy(arEvents, 0, arPropsTmp, 0, eventCount);
1026 arEvents= arPropsTmp;
1028 listener.propertiesChange(arEvents);
1031 // XMultiPropertySet -----------------------------------------------------------------------------------
1032 /** If a value for a property could not be retrieved then the respective element in the returned
1033 * array has the value null.
1035 public Object[] getPropertyValues(String[] propNames)
1037 Object[] arValues= new Object[propNames.length];
1038 synchronized (this)
1040 for (int i= 0; i < propNames.length; i++)
1042 Object value= null;
1043 try
1045 value= getPropertyValue(propNames[i]);
1047 catch (Exception e)
1050 arValues[i]= value;
1053 return arValues;
1055 // XMultiPropertySet -----------------------------------------------------------------------------------
1056 public void removePropertiesChangeListener(XPropertiesChangeListener xPropertiesChangeListener)
1058 listenerContainer.removeInterface(XPropertiesChangeListener.class, xPropertiesChangeListener);
1060 // XMultiPropertySet -----------------------------------------------------------------------------------
1061 /** If the array of property names containes an unknown property then it will be ignored.
1063 public void setPropertyValues(String[] propNames, Object[] values) throws PropertyVetoException, com.sun.star.lang.IllegalArgumentException, com.sun.star.lang.WrappedTargetException
1065 for (int i= 0; i < propNames.length; i++)
1067 try
1069 setPropertyValue(propNames[i], values[i]);
1071 catch (UnknownPropertyException e)
1073 continue;
1079 private class PropertySetInfo implements XPropertySetInfo
1081 public com.sun.star.beans.Property[] getProperties()
1083 return PropertySet.this.getProperties();
1086 public com.sun.star.beans.Property getPropertyByName(String name) throws UnknownPropertyException
1088 return getProperty(name);
1091 public boolean hasPropertyByName(String name)
1093 return getProperty(name) != null;