1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: PropertySetMixin.java,v $
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 ************************************************************************/
31 package com
.sun
.star
.lib
.uno
.helper
;
33 import com
.sun
.star
.beans
.Property
;
34 import com
.sun
.star
.beans
.PropertyAttribute
;
35 import com
.sun
.star
.beans
.PropertyChangeEvent
;
36 import com
.sun
.star
.beans
.PropertyState
;
37 import com
.sun
.star
.beans
.PropertyValue
;
38 import com
.sun
.star
.beans
.PropertyVetoException
;
39 import com
.sun
.star
.beans
.UnknownPropertyException
;
40 import com
.sun
.star
.beans
.XPropertyChangeListener
;
41 import com
.sun
.star
.beans
.XPropertySetInfo
;
42 import com
.sun
.star
.beans
.XVetoableChangeListener
;
43 import com
.sun
.star
.container
.NoSuchElementException
;
44 import com
.sun
.star
.container
.XHierarchicalNameAccess
;
45 import com
.sun
.star
.lang
.DisposedException
;
46 import com
.sun
.star
.lang
.EventObject
;
47 import com
.sun
.star
.lang
.WrappedTargetException
;
48 import com
.sun
.star
.lang
.WrappedTargetRuntimeException
;
49 import com
.sun
.star
.lang
.XComponent
;
50 import com
.sun
.star
.reflection
.XCompoundTypeDescription
;
51 import com
.sun
.star
.reflection
.XIdlClass
;
52 import com
.sun
.star
.reflection
.XIdlField2
;
53 import com
.sun
.star
.reflection
.XIdlReflection
;
54 import com
.sun
.star
.reflection
.XIndirectTypeDescription
;
55 import com
.sun
.star
.reflection
.XInterfaceAttributeTypeDescription2
;
56 import com
.sun
.star
.reflection
.XInterfaceMemberTypeDescription
;
57 import com
.sun
.star
.reflection
.XInterfaceTypeDescription2
;
58 import com
.sun
.star
.reflection
.XStructTypeDescription
;
59 import com
.sun
.star
.reflection
.XTypeDescription
;
60 import com
.sun
.star
.uno
.Any
;
61 import com
.sun
.star
.uno
.AnyConverter
;
62 import com
.sun
.star
.uno
.DeploymentException
;
63 import com
.sun
.star
.uno
.Type
;
64 import com
.sun
.star
.uno
.TypeClass
;
65 import com
.sun
.star
.uno
.UnoRuntime
;
66 import com
.sun
.star
.uno
.XComponentContext
;
67 import com
.sun
.star
.uno
.XInterface
;
68 import java
.util
.ArrayList
;
69 import java
.util
.HashMap
;
70 import java
.util
.HashSet
;
71 import java
.util
.Iterator
;
73 import java
.util
.Vector
;
76 A helper mixin to implement certain UNO interfaces related to property set
77 handling on top of the attributes of a given UNO interface type.
79 <p>A client will mix in this class by keeping a reference to an instance of
80 this class, and forwarding all methods of (a subset of the interfaces)
81 <code>com.sun.star.beans.XPropertySet</code>,
82 <code>com.sun.star.beans.XFastPropertySet</code>, and
83 <code>com.sun.star.beans.XPropertyAccess</code> to it.</p>
85 <p>Client code should not use the monitors associated with instances of this
86 class, as they are used for internal purposes.</p>
90 public final class PropertySetMixin
{
94 @param context the component context used by this instance; must not be
95 null, and must supply the service
96 <code>com.sun.star.reflection.CoreReflection</code> and the singleton
97 <code>com.sun.star.reflection.theTypeDescriptionManager</code>
99 @param object the client UNO object into which this instance is mixed in;
100 must not be null, and must support the given <code>type</code>
102 @param type the UNO interface type whose attributes are mapped to
103 properties; must not be null, and must represent a UNO interface type
105 @param absentOptional a list of optional properties that are not present,
106 and should thus not be visible via
107 <code>com.sun.star.beans.XPropertySet.getPropertySetInfo</code>,
108 <code>com.sun.star.beans.XPropertySet.addPropertyChangeListener</code>,
109 <code>com.sun.star.beans.XPropertySet.removePropertyChangeListener<!--
111 <code>com.sun.star.beans.XPropertySet.addVetoableChangeListener</code>,
112 and <code>com.sun.star.beans.XPropertySet.<!--
113 -->removeVetoableChangeListener</code>; null is treated the same as an
114 empty list; if non-null, the given array must not be modified after it is
115 passed to this constructor. For consistency reasons, the given
116 <code>absentOptional</code> should only contain the names of attributes
117 that represent optional properties that are not present (that is, the
118 attribute getters and setters always throw a
119 <code>com.sun.star.beans.UnknownPropertyException</code>), and should
120 contain each such name only once. If an optional property is not present
121 (that is, the corresponding attribute getter and setter always throw a
122 <code>com.sun.star.beans.UnknownPropertyException</code>) but is not
123 contained in the given <code>absentOptional</code>, then it will be
125 <code>com.sun.star.beans.XPropertySet.getPropertySetInfo</code> as a
126 <code>com.sun.star.beans.Property</code> with a set
127 <code>com.sun.star.beans.PropertyAttribute.OPTIONAL</code>. If the given
128 <code>object</code> does not implement
129 <code>com.sun.star.beans.XPropertySet</code>, then the given
130 <code>absentOptional</code> is effectively ignored and can be null or
133 public PropertySetMixin(
134 XComponentContext context
, XInterface object
, Type type
,
135 String
[] absentOptional
)
137 // assert context != null && object != null && type != null
138 // && type.getTypeClass() == TypeClass.INTERFACE;
139 this.context
= context
;
140 this.object
= object
;
142 this.absentOptional
= absentOptional
;
143 idlClass
= getReflection(type
.getTypeName());
144 XTypeDescription ifc
;
146 ifc
= UnoRuntime
.queryInterface(
147 XTypeDescription
.class,
148 (UnoRuntime
.queryInterface(
149 XHierarchicalNameAccess
.class,
150 context
.getValueByName(
151 "/singletons/com.sun.star.reflection."
152 + "theTypeDescriptionManager")).
153 getByHierarchicalName(type
.getTypeName())));
154 } catch (NoSuchElementException e
) {
155 throw new RuntimeException(
156 "unexpected com.sun.star.container.NoSuchElementException: "
159 HashMap map
= new HashMap();
160 ArrayList handleNames
= new ArrayList();
161 initProperties(ifc
, map
, handleNames
, new HashSet());
163 handleMap
= (String
[]) handleNames
.toArray(
164 new String
[handleNames
.size()]);
168 A method used by clients when implementing UNO interface type attribute
171 <p>First, this method checks whether this instance has already been
172 disposed (see {@link #dispose}), and throws a
173 <code>com.sun.star.beans.DisposedException</code> if applicable. For a
174 constrained attribute (whose setter can explicitly raise
175 <code>com.sun.star.beans.PropertyVetoException</code>), this method
176 notifies any <code>com.sun.star.beans.XVetoableChangeListener</code>s.
177 For a bound attribute, this method modifies the passed-in
178 <code>bound</code> so that it can afterwards be used to notify any
179 <code>com.sun.star.beans.XPropertyChangeListener</code>s. This method
180 should be called before storing the new attribute value, and
181 <code>bound.notifyListeners()</code> should be called exactly once after
182 storing the new attribute value (in case the attribute is bound;
183 otherwise, calling <code>bound.notifyListeners()</code> is ignored).
184 Furthermore, <code>bound.notifyListeners()</code> and this method have to
185 be called from the same thread.</p>
187 @param propertyName the name of the property (which is the same as the
188 name of the attribute that is going to be set)
190 @param oldValue the property value corresponding to the old attribute
191 value. This is only used as
192 <code>com.sun.star.beans.PropertyChangeEvent.OldValue</code>, which is
193 rather useless, anyway (see “Using the Observer Pattern” in
194 <a href="http://tools.openoffice.org/CodingGuidelines.sxw">
195 <cite>OpenOffice.org Coding Guidelines</cite></a>). If the attribute
196 that is going to be set is neither bound nor constrained, or if
197 <code>com.sun.star.beans.PropertyChangeEvent.OldValue</code> should not
198 be set, {@link Any#VOID} can be used instead.
200 @param newValue the property value corresponding to the new
201 attribute value. This is only used as
202 <code>com.sun.star.beans.PropertyChangeEvent.NewValue</code>, which is
203 rather useless, anyway (see “Using the Observer Pattern&rdquo: in
204 <a href="http://tools.openoffice.org/CodingGuidelines.sxw">
205 <cite>OpenOffice.org Coding Guidelines</cite></a>), <em>unless</em> the
206 attribute that is going to be set is constrained. If the attribute
207 that is going to be set is neither bound nor constrained, or if it is
209 <code>com.sun.star.beans.PropertyChangeEvent.NewValue</code> should not
210 be set, {@link Any#VOID} can be used instead.
212 @param bound a reference to a fresh {@link BoundListeners} instance
213 (which has not been passed to this method before, and on which
214 {@link BoundListeners#notifyListeners} has not yet been called); may only
215 be null if the attribute that is going to be set is not bound
217 public void prepareSet(
218 String propertyName
, Object oldValue
, Object newValue
,
219 BoundListeners bound
)
220 throws PropertyVetoException
222 // assert properties.get(propertyName) != null;
223 Property p
= ((PropertyData
) properties
.get(propertyName
)).property
;
224 Vector specificVeto
= null;
225 Vector unspecificVeto
= null;
226 synchronized (this) {
228 throw new DisposedException("disposed", object
);
230 if ((p
.Attributes
& PropertyAttribute
.CONSTRAINED
) != 0) {
231 Object o
= vetoListeners
.get(propertyName
);
233 specificVeto
= (Vector
) ((Vector
) o
).clone();
235 o
= vetoListeners
.get("");
237 unspecificVeto
= (Vector
) ((Vector
) o
).clone();
240 if ((p
.Attributes
& PropertyAttribute
.BOUND
) != 0) {
241 // assert bound != null;
242 Object o
= boundListeners
.get(propertyName
);
244 bound
.specificListeners
= (Vector
) ((Vector
) o
).clone();
246 o
= boundListeners
.get("");
248 bound
.unspecificListeners
= (Vector
) ((Vector
) o
).clone();
252 if ((p
.Attributes
& PropertyAttribute
.CONSTRAINED
) != 0) {
253 PropertyChangeEvent event
= new PropertyChangeEvent(
254 object
, propertyName
, false, p
.Handle
, oldValue
, newValue
);
255 if (specificVeto
!= null) {
256 for (Iterator i
= specificVeto
.iterator(); i
.hasNext();) {
258 ((XVetoableChangeListener
) i
.next()).vetoableChange(
260 } catch (DisposedException e
) {}
263 if (unspecificVeto
!= null) {
264 for (Iterator i
= unspecificVeto
.iterator(); i
.hasNext();) {
266 ((XVetoableChangeListener
) i
.next()).vetoableChange(
268 } catch (DisposedException e
) {}
272 if ((p
.Attributes
& PropertyAttribute
.BOUND
) != 0) {
273 // assert bound != null;
274 bound
.event
= new PropertyChangeEvent(
275 object
, propertyName
, false, p
.Handle
, oldValue
, newValue
);
280 A simplified version of {@link #prepareSet(String, Object, Object,
281 PropertySetMixin.BoundListeners)}.
283 <p>This method is useful for attributes that are not constrained.</p>
285 @param propertyName the name of the property (which is the same as the
286 name of the attribute that is going to be set)
288 @param bound a reference to a fresh {@link BoundListeners} instance
289 (which has not been passed to this method before, and on which
290 {@link BoundListeners#notifyListeners} has not yet been called); may only
291 be null if the attribute that is going to be set is not bound
293 public void prepareSet(String propertyName
, BoundListeners bound
) {
295 prepareSet(propertyName
, Any
.VOID
, Any
.VOID
, bound
);
296 } catch (PropertyVetoException e
) {
297 throw new RuntimeException("unexpected " + e
);
302 Marks this instance as being disposed.
304 <p>See <code>com.sun.star.lang.XComponent</code> for the general concept
305 of disposing UNO objects. On the first call to this method, all
307 (<code>com.sun.star.beans.XPropertyChangeListener</code>s and
308 <code>com.sun.star.beans.XVetoableChangeListener</code>s) are notified of
309 the disposing source. Any subsequent calls to this method are
312 public void dispose() {
315 synchronized (this) {
316 bound
= boundListeners
;
317 boundListeners
= null;
318 veto
= vetoListeners
;
319 vetoListeners
= null;
322 EventObject event
= new EventObject(object
);
324 for (Iterator i
= bound
.values().iterator(); i
.hasNext();) {
325 for (Iterator j
= ((Vector
) i
.next()).iterator(); j
.hasNext();)
327 ((XPropertyChangeListener
) j
.next()).disposing(event
);
332 for (Iterator i
= veto
.values().iterator(); i
.hasNext();) {
333 for (Iterator j
= ((Vector
) i
.next()).iterator(); j
.hasNext();)
335 ((XVetoableChangeListener
) j
.next()).disposing(event
);
343 <code>com.sun.star.beans.XPropertySet.getPropertySetInfo</code>.
345 public XPropertySetInfo
getPropertySetInfo() {
346 return new Info(properties
);
350 Implements <code>com.sun.star.beans.XPropertySet.setPropertyValue</code>.
352 public void setPropertyValue(String propertyName
, Object value
)
353 throws UnknownPropertyException
, PropertyVetoException
,
354 com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
356 setProperty(propertyName
, value
, false, false, (short) 1);
360 Implements <code>com.sun.star.beans.XPropertySet.getPropertyValue</code>.
362 public Object
getPropertyValue(String propertyName
)
363 throws UnknownPropertyException
, WrappedTargetException
365 return getProperty(propertyName
, null);
370 <code>com.sun.star.beans.XPropertySet.addPropertyChangeListener</code>.
372 <p>If a listener is added more than once, it will receive all relevant
373 notifications multiple times.</p>
375 public void addPropertyChangeListener(
376 String propertyName
, XPropertyChangeListener listener
)
377 throws UnknownPropertyException
, WrappedTargetException
379 // assert listener != null;
380 checkUnknown(propertyName
);
382 synchronized (this) {
385 Vector v
= (Vector
) boundListeners
.get(propertyName
);
388 boundListeners
.put(propertyName
, v
);
394 listener
.disposing(new EventObject(object
));
400 com.sun.star.beans.XPropertySet.removePropertyChangeListener</code>.
402 public void removePropertyChangeListener(
403 String propertyName
, XPropertyChangeListener listener
)
404 throws UnknownPropertyException
, WrappedTargetException
406 // assert listener != null;
407 checkUnknown(propertyName
);
408 synchronized (this) {
409 if (boundListeners
!= null) {
410 Vector v
= (Vector
) boundListeners
.get(propertyName
);
420 <code>com.sun.star.beans.XPropertySet.addVetoableChangeListener</code>.
422 <p>If a listener is added more than once, it will receive all relevant
423 notifications multiple times.</p>
425 public void addVetoableChangeListener(
426 String propertyName
, XVetoableChangeListener listener
)
427 throws UnknownPropertyException
, WrappedTargetException
429 // assert listener != null;
430 checkUnknown(propertyName
);
432 synchronized (this) {
435 Vector v
= (Vector
) vetoListeners
.get(propertyName
);
438 vetoListeners
.put(propertyName
, v
);
444 listener
.disposing(new EventObject(object
));
450 com.sun.star.beans.XPropertySet.removeVetoableChangeListener</code>.
452 public void removeVetoableChangeListener(
453 String propertyName
, XVetoableChangeListener listener
)
454 throws UnknownPropertyException
, WrappedTargetException
456 // assert listener != null;
457 checkUnknown(propertyName
);
458 synchronized (this) {
459 if (vetoListeners
!= null) {
460 Vector v
= (Vector
) vetoListeners
.get(propertyName
);
470 <code>com.sun.star.beans.XFastPropertySet.setFastPropertyValue</code>.
472 public void setFastPropertyValue(int handle
, Object value
)
473 throws UnknownPropertyException
, PropertyVetoException
,
474 com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
476 setProperty(translateHandle(handle
), value
, false, false, (short) 1);
481 <code>com.sun.star.beans.XFastPropertySet.getFastPropertyValue</code>.
483 public Object
getFastPropertyValue(int handle
)
484 throws UnknownPropertyException
, WrappedTargetException
486 return getProperty(translateHandle(handle
), null);
491 <code>com.sun.star.beans.XPropertyAccess.getPropertyValues</code>.
493 public PropertyValue
[] getPropertyValues() {
494 PropertyValue
[] s
= new PropertyValue
[handleMap
.length
];
496 for (int i
= 0; i
< handleMap
.length
; ++i
) {
497 PropertyState
[] state
= new PropertyState
[1];
500 value
= getProperty(handleMap
[i
], state
);
501 } catch (UnknownPropertyException e
) {
503 } catch (WrappedTargetException e
) {
504 throw new WrappedTargetRuntimeException(
505 e
.getMessage(), object
, e
.TargetException
);
507 s
[n
++] = new PropertyValue(handleMap
[i
], i
, value
, state
[0]);
509 if (n
< handleMap
.length
) {
510 PropertyValue
[] s2
= new PropertyValue
[n
];
511 System
.arraycopy(s
, 0, s2
, 0, n
);
519 <code>com.sun.star.beans.XPropertyAccess.setPropertyValues</code>.
521 public void setPropertyValues(PropertyValue
[] props
)
522 throws UnknownPropertyException
, PropertyVetoException
,
523 com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
525 for (int i
= 0; i
< props
.length
; ++i
) {
526 if (props
[i
].Handle
!= -1
527 && !props
[i
].Name
.equals(translateHandle(props
[i
].Handle
)))
529 throw new UnknownPropertyException(
530 ("name " + props
[i
].Name
+ " does not match handle "
535 props
[i
].Name
, props
[i
].Value
,
536 props
[i
].State
== PropertyState
.AMBIGUOUS_VALUE
,
537 props
[i
].State
== PropertyState
.DEFAULT_VALUE
, (short) 0);
542 A class used by clients of {@link PropertySetMixin} when implementing UNO
543 interface type attribute setter functions.
545 @see #prepareSet(String, Object, Object, PropertySetMixin.BoundListeners)
547 public static final class BoundListeners
{
551 public BoundListeners() {}
555 <code>com.sun.star.beans.XPropertyChangeListener</code>s.
557 @see #prepareSet(String, Object, Object,
558 PropertySetMixin.BoundListeners)
560 public void notifyListeners() {
561 if (specificListeners
!= null) {
562 for (Iterator i
= specificListeners
.iterator(); i
.hasNext();) {
564 ((XPropertyChangeListener
) i
.next()).propertyChange(
566 } catch (DisposedException e
) {}
569 if (unspecificListeners
!= null) {
570 for (Iterator i
= unspecificListeners
.iterator(); i
.hasNext();)
573 ((XPropertyChangeListener
) i
.next()).propertyChange(
575 } catch (DisposedException e
) {}
580 private Vector specificListeners
= null;
581 private Vector unspecificListeners
= null;
582 private PropertyChangeEvent event
= null;
585 private XIdlClass
getReflection(String typeName
) {
588 refl
= UnoRuntime
.queryInterface(
589 XIdlReflection
.class,
590 context
.getServiceManager().createInstanceWithContext(
591 "com.sun.star.reflection.CoreReflection", context
));
592 } catch (com
.sun
.star
.uno
.Exception e
) {
593 throw new DeploymentException(
594 ("component context fails to supply service"
595 + " com.sun.star.reflection.CoreReflection: "
600 return refl
.forName(typeName
);
602 XComponent comp
= UnoRuntime
.queryInterface(XComponent
.class, refl
);
609 private void initProperties(
610 XTypeDescription type
, HashMap map
, ArrayList handleNames
, HashSet seen
)
612 XInterfaceTypeDescription2 ifc
= UnoRuntime
.queryInterface(
613 XInterfaceTypeDescription2
.class, resolveTypedefs(type
));
614 if (seen
.add(ifc
.getName())) {
615 XTypeDescription
[] bases
= ifc
.getBaseTypes();
616 for (int i
= 0; i
< bases
.length
; ++i
) {
617 initProperties(bases
[i
], map
, handleNames
, seen
);
619 XInterfaceMemberTypeDescription
[] members
= ifc
.getMembers();
620 for (int i
= 0; i
< members
.length
; ++i
) {
621 if (members
[i
].getTypeClass() == TypeClass
.INTERFACE_ATTRIBUTE
)
623 XInterfaceAttributeTypeDescription2 attr
=
624 UnoRuntime
.queryInterface(
625 XInterfaceAttributeTypeDescription2
.class,
627 short attrAttribs
= 0;
628 if (attr
.isBound()) {
629 attrAttribs
|= PropertyAttribute
.BOUND
;
631 boolean setUnknown
= false;
632 if (attr
.isReadOnly()) {
633 attrAttribs
|= PropertyAttribute
.READONLY
;
636 XCompoundTypeDescription
[] excs
= attr
.getGetExceptions();
637 boolean getUnknown
= false;
638 //XXX Special interpretation of getter/setter exceptions
639 // only works if the specified exceptions are of the exact
640 // type, not of a supertype:
641 for (int j
= 0; j
< excs
.length
; ++j
) {
642 if (excs
[j
].getName().equals(
643 "com.sun.star.beans.UnknownPropertyException"))
649 excs
= attr
.getSetExceptions();
650 for (int j
= 0; j
< excs
.length
; ++j
) {
651 if (excs
[j
].getName().equals(
652 "com.sun.star.beans.UnknownPropertyException"))
655 } else if (excs
[j
].getName().equals(
656 "com.sun.star.beans."
657 + "PropertyVetoException"))
659 attrAttribs
|= PropertyAttribute
.CONSTRAINED
;
662 if (getUnknown
&& setUnknown
) {
663 attrAttribs
|= PropertyAttribute
.OPTIONAL
;
665 XTypeDescription t
= attr
.getType();
667 t
= resolveTypedefs(t
);
669 if (t
.getName().startsWith(
670 "com.sun.star.beans.Ambiguous<"))
672 n
= PropertyAttribute
.MAYBEAMBIGUOUS
;
673 } else if (t
.getName().startsWith(
674 "com.sun.star.beans.Defaulted<"))
676 n
= PropertyAttribute
.MAYBEDEFAULT
;
677 } else if (t
.getName().startsWith(
678 "com.sun.star.beans.Optional<"))
680 n
= PropertyAttribute
.MAYBEVOID
;
685 t
= (UnoRuntime
.queryInterface(
686 XStructTypeDescription
.class, t
)).
687 getTypeArguments()[0];
689 String name
= members
[i
].getMemberName();
690 boolean present
= true;
691 if (absentOptional
!= null) {
692 for (int j
= 0; j
< absentOptional
.length
; ++j
) {
693 if (name
.equals(absentOptional
[j
])) {
703 name
, handleNames
.size(),
704 new Type(t
.getName(), t
.getTypeClass()),
709 throw new RuntimeException(
710 "inconsistent UNO type registry");
712 handleNames
.add(name
);
718 private String
translateHandle(int handle
) throws UnknownPropertyException
{
719 if (handle
< 0 || handle
>= handleMap
.length
) {
720 throw new UnknownPropertyException("bad handle " + handle
, object
);
722 return handleMap
[handle
];
725 private void setProperty(
726 String name
, Object value
, boolean isAmbiguous
, boolean isDefaulted
,
727 short illegalArgumentPosition
)
728 throws UnknownPropertyException
, PropertyVetoException
,
729 com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
731 PropertyData p
= (PropertyData
) properties
.get(name
);
733 throw new UnknownPropertyException(name
, object
);
736 && (p
.property
.Attributes
& PropertyAttribute
.MAYBEAMBIGUOUS
) == 0)
738 && ((p
.property
.Attributes
& PropertyAttribute
.MAYBEDEFAULT
)
741 throw new com
.sun
.star
.lang
.IllegalArgumentException(
742 ("flagging as ambiguous/defaulted non-ambiguous/defaulted"
743 + " property " + name
),
744 object
, illegalArgumentPosition
);
747 XIdlField2 f
= UnoRuntime
.queryInterface(
748 XIdlField2
.class, idlClass
.getField(name
));
749 Object
[] o
= new Object
[] {
750 new Any(type
, UnoRuntime
.queryInterface(type
, object
)) };
751 Object v
= wrapValue(
753 UnoRuntime
.queryInterface(
754 XIdlField2
.class, idlClass
.getField(name
)).getType(),
755 (p
.property
.Attributes
& PropertyAttribute
.MAYBEAMBIGUOUS
) != 0,
757 (p
.property
.Attributes
& PropertyAttribute
.MAYBEDEFAULT
) != 0,
759 (p
.property
.Attributes
& PropertyAttribute
.MAYBEVOID
) != 0);
762 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
763 if (e
.ArgumentPosition
== 1) {
764 throw new com
.sun
.star
.lang
.IllegalArgumentException(
765 e
.getMessage(), object
, illegalArgumentPosition
);
767 throw new RuntimeException(
768 "unexpected com.sun.star.lang.IllegalArgumentException: "
771 } catch (com
.sun
.star
.lang
.IllegalAccessException e
) {
772 //TODO Clarify whether PropertyVetoException is the correct
773 // exception to throw when trying to set a read-only property:
774 throw new PropertyVetoException(
775 "cannot set read-only property " + name
, object
);
776 } catch (WrappedTargetRuntimeException e
) {
777 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
778 // guaranteed to originate directly within XIdlField2.get (and thus
779 // have the expected semantics); it might also be passed through
780 // from lower layers.
781 if (new Type(UnknownPropertyException
.class).isSupertypeOf(
782 AnyConverter
.getType(e
.TargetException
))
783 && (p
.property
.Attributes
& PropertyAttribute
.OPTIONAL
) != 0)
785 throw new UnknownPropertyException(name
, object
);
786 } else if (new Type(PropertyVetoException
.class).isSupertypeOf(
787 AnyConverter
.getType(e
.TargetException
))
788 && ((p
.property
.Attributes
789 & PropertyAttribute
.CONSTRAINED
)
792 throw new PropertyVetoException(name
, object
);
794 throw new WrappedTargetException(
795 e
.getMessage(), object
, e
.TargetException
);
800 Object
getProperty(String name
, PropertyState
[] state
)
801 throws UnknownPropertyException
, WrappedTargetException
803 PropertyData p
= (PropertyData
) properties
.get(name
);
805 throw new UnknownPropertyException(name
, object
);
807 XIdlField2 field
= UnoRuntime
.queryInterface(
808 XIdlField2
.class, idlClass
.getField(name
));
812 new Any(type
, UnoRuntime
.queryInterface(type
, object
)));
813 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
814 throw new RuntimeException(
815 "unexpected com.sun.star.lang.IllegalArgumentException: "
817 } catch (WrappedTargetRuntimeException e
) {
818 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
819 // guaranteed to originate directly within XIdlField2.get (and thus
820 // have the expected semantics); it might also be passed through
821 // from lower layers.
822 if (new Type(UnknownPropertyException
.class).isSupertypeOf(
823 AnyConverter
.getType(e
.TargetException
))
824 && (p
.property
.Attributes
& PropertyAttribute
.OPTIONAL
) != 0)
826 throw new UnknownPropertyException(name
, object
);
828 throw new WrappedTargetException(
829 e
.getMessage(), object
, e
.TargetException
);
832 boolean undoAmbiguous
833 = (p
.property
.Attributes
& PropertyAttribute
.MAYBEAMBIGUOUS
) != 0;
834 boolean undoDefaulted
835 = (p
.property
.Attributes
& PropertyAttribute
.MAYBEDEFAULT
) != 0;
837 = (p
.property
.Attributes
& PropertyAttribute
.MAYBEVOID
) != 0;
838 boolean isAmbiguous
= false;
839 boolean isDefaulted
= false;
840 while (undoAmbiguous
|| undoDefaulted
|| undoOptional
) {
841 String typeName
= AnyConverter
.getType(value
).getTypeName();
843 && typeName
.startsWith("com.sun.star.beans.Ambiguous<"))
845 XIdlClass ambiguous
= getReflection(typeName
);
847 isAmbiguous
= AnyConverter
.toBoolean(
848 UnoRuntime
.queryInterface(
850 ambiguous
.getField("IsAmbiguous")).get(value
));
851 value
= UnoRuntime
.queryInterface(
853 ambiguous
.getField("Value")).get(value
);
854 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
855 throw new RuntimeException(
857 + " com.sun.star.lang.IllegalArgumentException: "
860 undoAmbiguous
= false;
861 } else if (undoDefaulted
862 && typeName
.startsWith("com.sun.star.beans.Defaulted<"))
864 XIdlClass defaulted
= getReflection(typeName
);
866 isDefaulted
= AnyConverter
.toBoolean(
867 UnoRuntime
.queryInterface(
869 defaulted
.getField("IsDefaulted")).get(value
));
870 value
= UnoRuntime
.queryInterface(
872 defaulted
.getField("Value")).get(value
);
873 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
874 throw new RuntimeException(
876 + " com.sun.star.lang.IllegalArgumentException: "
879 undoDefaulted
= false;
880 } else if (undoOptional
881 && typeName
.startsWith("com.sun.star.beans.Optional<"))
883 XIdlClass optional
= getReflection(typeName
);
885 boolean present
= AnyConverter
.toBoolean(
886 UnoRuntime
.queryInterface(
888 optional
.getField("IsPresent")).get(value
));
893 value
= UnoRuntime
.queryInterface(
895 optional
.getField("Value")).get(value
);
896 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
897 throw new RuntimeException(
899 + " com.sun.star.lang.IllegalArgumentException: "
902 undoOptional
= false;
904 throw new RuntimeException(
905 "unexpected type of attribute " + name
);
909 //XXX If isAmbiguous && isDefaulted, arbitrarily choose
910 // AMBIGUOUS_VALUE over DEFAULT_VALUE:
911 state
[0] = isAmbiguous
912 ? PropertyState
.AMBIGUOUS_VALUE
914 ? PropertyState
.DEFAULT_VALUE
: PropertyState
.DIRECT_VALUE
;
919 private Object
wrapValue(
920 Object value
, XIdlClass type
, boolean wrapAmbiguous
,
921 boolean isAmbiguous
, boolean wrapDefaulted
, boolean isDefaulted
,
922 boolean wrapOptional
)
924 // assert (wrapAmbiguous || !isAmbiguous)
925 // && (wrapDefaulted || !isDefaulted);
927 && type
.getName().startsWith("com.sun.star.beans.Ambiguous<"))
929 Object
[] strct
= new Object
[1];
930 type
.createObject(strct
);
932 XIdlField2 field
= UnoRuntime
.queryInterface(
933 XIdlField2
.class, type
.getField("Value"));
937 value
, field
.getType(), false, false, wrapDefaulted
,
938 isDefaulted
, wrapOptional
));
939 UnoRuntime
.queryInterface(
940 XIdlField2
.class, type
.getField("IsAmbiguous")).set(
941 strct
, new Boolean(isAmbiguous
));
942 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
943 throw new RuntimeException(
944 "unexpected com.sun.star.lang.IllegalArgumentException: "
946 } catch (com
.sun
.star
.lang
.IllegalAccessException e
) {
947 throw new RuntimeException(
948 "unexpected com.sun.star.lang.IllegalAccessException: "
952 } else if (wrapDefaulted
953 && type
.getName().startsWith(
954 "com.sun.star.beans.Defaulted<"))
956 Object
[] strct
= new Object
[1];
957 type
.createObject(strct
);
959 XIdlField2 field
= UnoRuntime
.queryInterface(
960 XIdlField2
.class, type
.getField("Value"));
964 value
, field
.getType(), wrapAmbiguous
, isAmbiguous
,
965 false, false, wrapOptional
));
966 UnoRuntime
.queryInterface(
967 XIdlField2
.class, type
.getField("IsDefaulted")).set(
968 strct
, new Boolean(isDefaulted
));
969 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
970 throw new RuntimeException(
971 "unexpected com.sun.star.lang.IllegalArgumentException: "
973 } catch (com
.sun
.star
.lang
.IllegalAccessException e
) {
974 throw new RuntimeException(
975 "unexpected com.sun.star.lang.IllegalAccessException: "
979 } else if (wrapOptional
980 && type
.getName().startsWith("com.sun.star.beans.Optional<"))
982 Object
[] strct
= new Object
[1];
983 type
.createObject(strct
);
984 boolean present
= !AnyConverter
.isVoid(value
);
986 UnoRuntime
.queryInterface(
987 XIdlField2
.class, type
.getField("IsPresent")).set(
988 strct
, new Boolean(present
));
990 XIdlField2 field
= UnoRuntime
.queryInterface(
991 XIdlField2
.class, type
.getField("Value"));
995 value
, field
.getType(), wrapAmbiguous
, isAmbiguous
,
996 wrapDefaulted
, isDefaulted
, false));
998 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
999 throw new RuntimeException(
1000 "unexpected com.sun.star.lang.IllegalArgumentException: "
1002 } catch (com
.sun
.star
.lang
.IllegalAccessException e
) {
1003 throw new RuntimeException(
1004 "unexpected com.sun.star.lang.IllegalAccessException: "
1009 if (wrapAmbiguous
|| wrapDefaulted
|| wrapOptional
) {
1010 throw new RuntimeException("unexpected type of attribute");
1016 private static XTypeDescription
resolveTypedefs(XTypeDescription type
) {
1017 while (type
.getTypeClass() == TypeClass
.TYPEDEF
) {
1018 type
= UnoRuntime
.queryInterface(
1019 XIndirectTypeDescription
.class, type
).getReferencedType();
1024 private PropertyData
get(Object object
, String propertyName
)
1025 throws UnknownPropertyException
1027 PropertyData p
= (PropertyData
) properties
.get(propertyName
);
1028 if (p
== null || !p
.present
) {
1029 throw new UnknownPropertyException(propertyName
, object
);
1034 private void checkUnknown(String propertyName
)
1035 throws UnknownPropertyException
1037 if (!propertyName
.equals("")) {
1038 get(this, propertyName
);
1042 private static final class PropertyData
{
1043 public PropertyData(Property property
, boolean present
) {
1044 this.property
= property
;
1045 this.present
= present
;
1048 public final Property property
;
1049 public final boolean present
;
1052 private final class Info
extends WeakBase
implements XPropertySetInfo
1054 public Info(Map properties
) {
1055 this.properties
= properties
;
1058 public Property
[] getProperties() {
1059 ArrayList al
= new ArrayList(properties
.size());
1060 for (Iterator i
= properties
.values().iterator(); i
.hasNext();) {
1061 PropertyData p
= (PropertyData
) i
.next();
1066 return (Property
[]) al
.toArray(new Property
[al
.size()]);
1069 public Property
getPropertyByName(String name
)
1070 throws UnknownPropertyException
1072 return get(this, name
).property
;
1075 public boolean hasPropertyByName(String name
) {
1076 PropertyData p
= (PropertyData
) properties
.get(name
);
1077 return p
!= null && p
.present
;
1080 private final Map properties
; // from String to Property
1083 private final XComponentContext context
;
1084 private final XInterface object
;
1085 private final Type type
;
1086 private final String
[] absentOptional
;
1087 private final XIdlClass idlClass
;
1088 private final Map properties
; // from String to Property
1089 private final String
[] handleMap
;
1091 private HashMap boundListeners
= new HashMap();
1092 // from String to Vector of XPropertyChangeListener
1093 private HashMap vetoListeners
= new HashMap();
1094 // from String to Vector of XVetoableChangeListener
1095 private boolean disposed
= false;