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 .
19 package com
.sun
.star
.lib
.uno
.helper
;
21 import com
.sun
.star
.beans
.Property
;
22 import com
.sun
.star
.beans
.PropertyAttribute
;
23 import com
.sun
.star
.beans
.PropertyChangeEvent
;
24 import com
.sun
.star
.beans
.PropertyState
;
25 import com
.sun
.star
.beans
.PropertyValue
;
26 import com
.sun
.star
.beans
.PropertyVetoException
;
27 import com
.sun
.star
.beans
.UnknownPropertyException
;
28 import com
.sun
.star
.beans
.XPropertyChangeListener
;
29 import com
.sun
.star
.beans
.XPropertySetInfo
;
30 import com
.sun
.star
.beans
.XVetoableChangeListener
;
31 import com
.sun
.star
.container
.NoSuchElementException
;
32 import com
.sun
.star
.container
.XHierarchicalNameAccess
;
33 import com
.sun
.star
.lang
.DisposedException
;
34 import com
.sun
.star
.lang
.EventObject
;
35 import com
.sun
.star
.lang
.WrappedTargetException
;
36 import com
.sun
.star
.lang
.WrappedTargetRuntimeException
;
37 import com
.sun
.star
.reflection
.XCompoundTypeDescription
;
38 import com
.sun
.star
.reflection
.XIdlClass
;
39 import com
.sun
.star
.reflection
.XIdlField2
;
40 import com
.sun
.star
.reflection
.XIndirectTypeDescription
;
41 import com
.sun
.star
.reflection
.XInterfaceAttributeTypeDescription2
;
42 import com
.sun
.star
.reflection
.XInterfaceMemberTypeDescription
;
43 import com
.sun
.star
.reflection
.XInterfaceTypeDescription2
;
44 import com
.sun
.star
.reflection
.XStructTypeDescription
;
45 import com
.sun
.star
.reflection
.XTypeDescription
;
46 import com
.sun
.star
.reflection
.theCoreReflection
;
47 import com
.sun
.star
.uno
.Any
;
48 import com
.sun
.star
.uno
.AnyConverter
;
49 import com
.sun
.star
.uno
.Type
;
50 import com
.sun
.star
.uno
.TypeClass
;
51 import com
.sun
.star
.uno
.UnoRuntime
;
52 import com
.sun
.star
.uno
.XComponentContext
;
53 import com
.sun
.star
.uno
.XInterface
;
54 import java
.util
.ArrayList
;
55 import java
.util
.HashMap
;
56 import java
.util
.HashSet
;
57 import java
.util
.Iterator
;
61 A helper mixin to implement certain UNO interfaces related to property set
62 handling on top of the attributes of a given UNO interface type.
64 <p>A client will mix in this class by keeping a reference to an instance of
65 this class, and forwarding all methods of (a subset of the interfaces)
66 <code>com.sun.star.beans.XPropertySet</code>,
67 <code>com.sun.star.beans.XFastPropertySet</code>, and
68 <code>com.sun.star.beans.XPropertyAccess</code> to it.</p>
70 <p>Client code should not use the monitors associated with instances of this
71 class, as they are used for internal purposes.</p>
75 public final class PropertySetMixin
{
79 @param context the component context used by this instance; must not be
80 null, and must supply the
81 <code>com.sun.star.reflection.theCoreReflection</code> and
82 <code>com.sun.star.reflection.theTypeDescriptionManager</code> singletons
84 @param object the client UNO object into which this instance is mixed in;
85 must not be null, and must support the given <code>type</code>
87 @param type the UNO interface type whose attributes are mapped to
88 properties; must not be null, and must represent a UNO interface type
90 @param absentOptional a list of optional properties that are not present,
91 and should thus not be visible via
92 <code>com.sun.star.beans.XPropertySet.getPropertySetInfo</code>,
93 <code>com.sun.star.beans.XPropertySet.addPropertyChangeListener</code>,
94 <code>com.sun.star.beans.XPropertySet.removePropertyChangeListener<!--
96 <code>com.sun.star.beans.XPropertySet.addVetoableChangeListener</code>,
97 and <code>com.sun.star.beans.XPropertySet.<!--
98 -->removeVetoableChangeListener</code>; null is treated the same as an
99 empty list; if non-null, the given array must not be modified after it is
100 passed to this constructor. For consistency reasons, the given
101 <code>absentOptional</code> should only contain the names of attributes
102 that represent optional properties that are not present (that is, the
103 attribute getters and setters always throw a
104 <code>com.sun.star.beans.UnknownPropertyException</code>), and should
105 contain each such name only once. If an optional property is not present
106 (that is, the corresponding attribute getter and setter always throw a
107 <code>com.sun.star.beans.UnknownPropertyException</code>) but is not
108 contained in the given <code>absentOptional</code>, then it will be
110 <code>com.sun.star.beans.XPropertySet.getPropertySetInfo</code> as a
111 <code>com.sun.star.beans.Property</code> with a set
112 <code>com.sun.star.beans.PropertyAttribute.OPTIONAL</code>. If the given
113 <code>object</code> does not implement
114 <code>com.sun.star.beans.XPropertySet</code>, then the given
115 <code>absentOptional</code> is effectively ignored and can be null or
118 public PropertySetMixin(
119 XComponentContext context
, XInterface object
, Type type
,
120 String
[] absentOptional
)
122 this.context
= context
;
123 this.object
= object
;
125 this.absentOptional
= absentOptional
;
126 idlClass
= getReflection(type
.getTypeName());
127 XTypeDescription ifc
;
129 XHierarchicalNameAccess xhna
= UnoRuntime
.queryInterface(
130 XHierarchicalNameAccess
.class,
131 context
.getValueByName(
132 "/singletons/com.sun.star.reflection."
133 + "theTypeDescriptionManager"));
134 ifc
= UnoRuntime
.queryInterface(
135 XTypeDescription
.class,
136 xhna
.getByHierarchicalName(type
.getTypeName()));
137 } catch (NoSuchElementException e
) {
138 throw new RuntimeException(e
);
140 HashMap
<String
,PropertyData
> map
= new HashMap
<String
,PropertyData
>();
141 ArrayList
<String
> handleNames
= new ArrayList
<String
>();
142 initProperties(ifc
, map
, handleNames
, new HashSet
<String
>());
144 handleMap
= handleNames
.toArray(new String
[handleNames
.size()]);
148 A method used by clients when implementing UNO interface type attribute
151 <p>First, this method checks whether this instance has already been
152 disposed (see {@link #dispose}), and throws a
153 <code>com.sun.star.beans.DisposedException</code> if applicable. For a
154 constrained attribute (whose setter can explicitly raise
155 <code>com.sun.star.beans.PropertyVetoException</code>), this method
156 notifies any <code>com.sun.star.beans.XVetoableChangeListener</code>s.
157 For a bound attribute, this method modifies the passed-in
158 <code>bound</code> so that it can afterwards be used to notify any
159 <code>com.sun.star.beans.XPropertyChangeListener</code>s. This method
160 should be called before storing the new attribute value, and
161 <code>bound.notifyListeners()</code> should be called exactly once after
162 storing the new attribute value (in case the attribute is bound;
163 otherwise, calling <code>bound.notifyListeners()</code> is ignored).
164 Furthermore, <code>bound.notifyListeners()</code> and this method have to
165 be called from the same thread.</p>
167 @param propertyName the name of the property (which is the same as the
168 name of the attribute that is going to be set)
170 @param oldValue the property value corresponding to the old attribute
171 value. This is only used as
172 <code>com.sun.star.beans.PropertyChangeEvent.OldValue</code>, which is
173 rather useless, anyway (see “Using the Observer Pattern” in
174 <a href="http://tools.openoffice.org/CodingGuidelines.sxw">
175 <cite>OpenOffice.org Coding Guidelines</cite></a>). If the attribute
176 that is going to be set is neither bound nor constrained, or if
177 <code>com.sun.star.beans.PropertyChangeEvent.OldValue</code> should not
178 be set, {@link Any#VOID} can be used instead.
180 @param newValue the property value corresponding to the new
181 attribute value. This is only used as
182 <code>com.sun.star.beans.PropertyChangeEvent.NewValue</code>, which is
183 rather useless, anyway (see “Using the Observer Pattern” in
184 <a href="http://tools.openoffice.org/CodingGuidelines.sxw">
185 <cite>OpenOffice.org Coding Guidelines</cite></a>), <em>unless</em> the
186 attribute that is going to be set is constrained. If the attribute
187 that is going to be set is neither bound nor constrained, or if it is
189 <code>com.sun.star.beans.PropertyChangeEvent.NewValue</code> should not
190 be set, {@link Any#VOID} can be used instead.
192 @param bound a reference to a fresh {@link BoundListeners} instance
193 (which has not been passed to this method before, and on which
194 {@link BoundListeners#notifyListeners} has not yet been called); may only
195 be null if the attribute that is going to be set is not bound
197 @throws PropertyVetoException if a vetoable listener throws it.
199 public void prepareSet(
200 String propertyName
, Object oldValue
, Object newValue
,
201 BoundListeners bound
)
202 throws PropertyVetoException
204 // assert properties.get(propertyName) != null;
205 Property p
= properties
.get(propertyName
).property
;
206 ArrayList
<XVetoableChangeListener
> specificVeto
= null;
207 ArrayList
<XVetoableChangeListener
> unspecificVeto
= null;
208 synchronized (this) {
210 throw new DisposedException("disposed", object
);
212 if ((p
.Attributes
& PropertyAttribute
.CONSTRAINED
) != 0) {
213 ArrayList
<XVetoableChangeListener
> o
= vetoListeners
.get(propertyName
);
215 specificVeto
= new ArrayList
<XVetoableChangeListener
>(o
);
217 o
= vetoListeners
.get("");
219 unspecificVeto
= new ArrayList
<XVetoableChangeListener
>(o
);
222 if ((p
.Attributes
& PropertyAttribute
.BOUND
) != 0) {
223 // assert bound != null;
224 ArrayList
<XPropertyChangeListener
> o
= boundListeners
.get(propertyName
);
226 bound
.specificListeners
= new ArrayList
<XPropertyChangeListener
>(o
);
228 o
= boundListeners
.get("");
230 bound
.unspecificListeners
= new ArrayList
<XPropertyChangeListener
>(o
);
234 if ((p
.Attributes
& PropertyAttribute
.CONSTRAINED
) != 0) {
235 PropertyChangeEvent event
= new PropertyChangeEvent(
236 object
, propertyName
, false, p
.Handle
, oldValue
, newValue
);
237 if (specificVeto
!= null) {
238 for (Iterator
<XVetoableChangeListener
> i
= specificVeto
.iterator(); i
.hasNext();) {
240 i
.next().vetoableChange(event
);
241 } catch (DisposedException e
) {}
244 if (unspecificVeto
!= null) {
245 for (Iterator
<XVetoableChangeListener
> i
= unspecificVeto
.iterator(); i
.hasNext();) {
247 i
.next().vetoableChange(event
);
248 } catch (DisposedException e
) {}
252 if ((p
.Attributes
& PropertyAttribute
.BOUND
) != 0) {
253 // assert bound != null;
254 bound
.event
= new PropertyChangeEvent(
255 object
, propertyName
, false, p
.Handle
, oldValue
, newValue
);
260 A simplified version of {@link #prepareSet(String, Object, Object,
261 PropertySetMixin.BoundListeners)}.
263 <p>This method is useful for attributes that are not constrained.</p>
265 @param propertyName the name of the property (which is the same as the
266 name of the attribute that is going to be set)
268 @param bound a reference to a fresh {@link BoundListeners} instance
269 (which has not been passed to this method before, and on which
270 {@link BoundListeners#notifyListeners} has not yet been called); may only
271 be null if the attribute that is going to be set is not bound
273 public void prepareSet(String propertyName
, BoundListeners bound
) {
275 prepareSet(propertyName
, Any
.VOID
, Any
.VOID
, bound
);
276 } catch (PropertyVetoException e
) {
277 throw new RuntimeException("unexpected " + e
);
282 Marks this instance as being disposed.
284 <p>See <code>com.sun.star.lang.XComponent</code> for the general concept
285 of disposing UNO objects. On the first call to this method, all
287 (<code>com.sun.star.beans.XPropertyChangeListener</code>s and
288 <code>com.sun.star.beans.XVetoableChangeListener</code>s) are notified of
289 the disposing source. Any subsequent calls to this method are
292 public void dispose() {
293 HashMap
<String
,ArrayList
<XPropertyChangeListener
>> bound
;
294 HashMap
<String
,ArrayList
<XVetoableChangeListener
>> veto
;
295 synchronized (this) {
296 bound
= boundListeners
;
297 boundListeners
= null;
298 veto
= vetoListeners
;
299 vetoListeners
= null;
302 EventObject event
= new EventObject(object
);
304 for (Iterator
<ArrayList
<XPropertyChangeListener
>> i
= bound
.values().iterator(); i
.hasNext();) {
305 for (Iterator
<XPropertyChangeListener
> j
= i
.next().iterator(); j
.hasNext();)
307 j
.next().disposing(event
);
312 for (Iterator
<ArrayList
<XVetoableChangeListener
>> i
= veto
.values().iterator(); i
.hasNext();) {
313 for (Iterator
<XVetoableChangeListener
> j
= i
.next().iterator(); j
.hasNext();)
315 j
.next().disposing(event
);
323 <code>com.sun.star.beans.XPropertySet.getPropertySetInfo</code>.
324 @return See com.sun.star.beans.XPropertySet
326 public XPropertySetInfo
getPropertySetInfo() {
327 return new Info(properties
);
331 Implements <code>com.sun.star.beans.XPropertySet.setPropertyValue</code>.
333 See com.sun.star.beans.XPropertySet
335 See com.sun.star.beans.XPropertySet
336 @throws UnknownPropertyException
337 See com.sun.star.beans.XPropertySet
338 @throws PropertyVetoException
339 See com.sun.star.beans.XPropertySet
340 @throws WrappedTargetException
341 See com.sun.star.beans.XPropertySet
343 public void setPropertyValue(String propertyName
, Object value
)
344 throws UnknownPropertyException
, PropertyVetoException
,
345 com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
347 setProperty(propertyName
, value
, false, false, (short) 1);
351 Implements <code>com.sun.star.beans.XPropertySet.getPropertyValue</code>.
353 See com.sun.star.beans.XPropertySet
354 @throws UnknownPropertyException
355 See com.sun.star.beans.XPropertySet
356 @throws WrappedTargetException
357 See com.sun.star.beans.XPropertySet
359 See com.sun.star.beans.XPropertySet
361 public Object
getPropertyValue(String propertyName
)
362 throws UnknownPropertyException
, WrappedTargetException
364 return getProperty(propertyName
, null);
369 <code>com.sun.star.beans.XPropertySet.addPropertyChangeListener</code>.
371 <p>If a listener is added more than once, it will receive all relevant
372 notifications multiple times.</p>
375 See com.sun.star.beans.XPropertySet
377 See com.sun.star.beans.XPropertySet
378 @throws UnknownPropertyException
379 See com.sun.star.beans.XPropertySet
380 @throws WrappedTargetException
381 See com.sun.star.beans.XPropertySet
383 public void addPropertyChangeListener(
384 String propertyName
, XPropertyChangeListener listener
)
385 throws UnknownPropertyException
, WrappedTargetException
387 // assert listener != null;
388 checkUnknown(propertyName
);
390 synchronized (this) {
393 ArrayList
<XPropertyChangeListener
> v
= boundListeners
.get(propertyName
);
395 v
= new ArrayList
<XPropertyChangeListener
>();
396 boundListeners
.put(propertyName
, v
);
402 listener
.disposing(new EventObject(object
));
408 com.sun.star.beans.XPropertySet.removePropertyChangeListener</code>.
411 See com.sun.star.beans.XPropertySet
413 See com.sun.star.beans.XPropertySet
414 @throws UnknownPropertyException
415 See com.sun.star.beans.XPropertySet
416 @throws WrappedTargetException
417 See com.sun.star.beans.XPropertySet
419 public void removePropertyChangeListener(
420 String propertyName
, XPropertyChangeListener listener
)
421 throws UnknownPropertyException
, WrappedTargetException
423 // assert listener != null;
424 checkUnknown(propertyName
);
425 synchronized (this) {
426 if (boundListeners
!= null) {
427 ArrayList
<XPropertyChangeListener
> v
= boundListeners
.get(propertyName
);
437 <code>com.sun.star.beans.XPropertySet.addVetoableChangeListener</code>.
439 <p>If a listener is added more than once, it will receive all relevant
440 notifications multiple times.</p>
443 See com.sun.star.beans.XPropertySet
445 See com.sun.star.beans.XPropertySet
446 @throws UnknownPropertyException
447 See com.sun.star.beans.XPropertySet
448 @throws WrappedTargetException
449 See com.sun.star.beans.XPropertySet
451 public void addVetoableChangeListener(
452 String propertyName
, XVetoableChangeListener listener
)
453 throws UnknownPropertyException
, WrappedTargetException
455 // assert listener != null;
456 checkUnknown(propertyName
);
458 synchronized (this) {
461 ArrayList
<XVetoableChangeListener
> v
= vetoListeners
.get(propertyName
);
463 v
= new ArrayList
<XVetoableChangeListener
>();
464 vetoListeners
.put(propertyName
, v
);
470 listener
.disposing(new EventObject(object
));
476 com.sun.star.beans.XPropertySet.removeVetoableChangeListener</code>.
479 See com.sun.star.beans.XPropertySet
481 See com.sun.star.beans.XPropertySet
482 @throws UnknownPropertyException
483 See com.sun.star.beans.XPropertySet
484 @throws WrappedTargetException
485 See com.sun.star.beans.XPropertySet
487 public void removeVetoableChangeListener(
488 String propertyName
, XVetoableChangeListener listener
)
489 throws UnknownPropertyException
, WrappedTargetException
491 // assert listener != null;
492 checkUnknown(propertyName
);
493 synchronized (this) {
494 if (vetoListeners
!= null) {
495 ArrayList
<XVetoableChangeListener
> v
= vetoListeners
.get(propertyName
);
505 <code>com.sun.star.beans.XFastPropertySet.setFastPropertyValue</code>.
508 See com.sun.star.beans.XFastPropertySet
510 See com.sun.star.beans.XFastPropertySet
511 @throws UnknownPropertyException
512 See com.sun.star.beans.XFastPropertySet
513 @throws PropertyVetoException
514 See com.sun.star.beans.XFastPropertySet
515 @throws WrappedTargetException
516 See com.sun.star.beans.XFastPropertySet
518 public void setFastPropertyValue(int handle
, Object value
)
519 throws UnknownPropertyException
, PropertyVetoException
,
520 com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
522 setProperty(translateHandle(handle
), value
, false, false, (short) 1);
527 <code>com.sun.star.beans.XFastPropertySet.getFastPropertyValue</code>.
530 See com.sun.star.beans.XFastPropertySet
531 @throws UnknownPropertyException
532 See com.sun.star.beans.XFastPropertySet
533 @throws WrappedTargetException
534 See com.sun.star.beans.XFastPropertySet
536 See com.sun.star.beans.XFastPropertySet
538 public Object
getFastPropertyValue(int handle
)
539 throws UnknownPropertyException
, WrappedTargetException
541 return getProperty(translateHandle(handle
), null);
546 <code>com.sun.star.beans.XPropertyAccess.getPropertyValues</code>.
549 See com.sun.star.beans.XPropertyAccess
551 public PropertyValue
[] getPropertyValues() {
552 PropertyValue
[] s
= new PropertyValue
[handleMap
.length
];
554 for (int i
= 0; i
< handleMap
.length
; ++i
) {
555 PropertyState
[] state
= new PropertyState
[1];
558 value
= getProperty(handleMap
[i
], state
);
559 } catch (UnknownPropertyException e
) {
561 } catch (WrappedTargetException e
) {
562 throw new WrappedTargetRuntimeException(e
.getCause(),
563 e
.getMessage(), object
, e
.TargetException
);
565 s
[n
++] = new PropertyValue(handleMap
[i
], i
, value
, state
[0]);
567 if (n
< handleMap
.length
) {
568 PropertyValue
[] s2
= new PropertyValue
[n
];
569 System
.arraycopy(s
, 0, s2
, 0, n
);
577 <code>com.sun.star.beans.XPropertyAccess.setPropertyValues</code>.
580 See com.sun.star.beans.XPropertyAccess
581 @throws UnknownPropertyException
582 See com.sun.star.beans.XPropertyAccess
583 @throws PropertyVetoException
584 See com.sun.star.beans.XPropertyAccess
585 @throws WrappedTargetException
586 See com.sun.star.beans.XPropertyAccess
588 public void setPropertyValues(PropertyValue
[] props
)
589 throws UnknownPropertyException
, PropertyVetoException
,
590 com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
592 for (int i
= 0; i
< props
.length
; ++i
) {
593 if (props
[i
].Handle
!= -1
594 && !props
[i
].Name
.equals(translateHandle(props
[i
].Handle
)))
596 throw new UnknownPropertyException(
597 ("name " + props
[i
].Name
+ " does not match handle "
602 props
[i
].Name
, props
[i
].Value
,
603 props
[i
].State
== PropertyState
.AMBIGUOUS_VALUE
,
604 props
[i
].State
== PropertyState
.DEFAULT_VALUE
, (short) 0);
609 A class used by clients of {@link PropertySetMixin} when implementing UNO
610 interface type attribute setter functions.
612 @see #prepareSet(String, Object, Object, PropertySetMixin.BoundListeners)
614 public static final class BoundListeners
{
618 <code>com.sun.star.beans.XPropertyChangeListener</code>s.
620 @see #prepareSet(String, Object, Object,
621 PropertySetMixin.BoundListeners)
623 public void notifyListeners() {
624 if (specificListeners
!= null) {
625 for (Iterator
<XPropertyChangeListener
> i
= specificListeners
.iterator(); i
.hasNext();) {
627 i
.next().propertyChange(event
);
628 } catch (DisposedException e
) {}
631 if (unspecificListeners
!= null) {
632 for (Iterator
<XPropertyChangeListener
> i
= unspecificListeners
.iterator(); i
.hasNext();)
635 i
.next().propertyChange(event
);
636 } catch (DisposedException e
) {}
641 private ArrayList
<XPropertyChangeListener
> specificListeners
= null;
642 private ArrayList
<XPropertyChangeListener
> unspecificListeners
= null;
643 private PropertyChangeEvent event
= null;
646 private XIdlClass
getReflection(String typeName
) {
647 return theCoreReflection
.get(context
).forName(typeName
);
650 private void initProperties(
651 XTypeDescription type
, HashMap
<String
,PropertyData
> map
, ArrayList
<String
> handleNames
, HashSet
<String
> seen
)
653 XInterfaceTypeDescription2 ifc
= UnoRuntime
.queryInterface(
654 XInterfaceTypeDescription2
.class, resolveTypedefs(type
));
655 if (!seen
.add(ifc
.getName())) {
658 XTypeDescription
[] bases
= ifc
.getBaseTypes();
659 for (int i
= 0; i
< bases
.length
; ++i
) {
660 initProperties(bases
[i
], map
, handleNames
, seen
);
662 XInterfaceMemberTypeDescription
[] members
= ifc
.getMembers();
663 for (int i
= 0; i
< members
.length
; ++i
) {
664 if (members
[i
].getTypeClass() == TypeClass
.INTERFACE_ATTRIBUTE
)
666 XInterfaceAttributeTypeDescription2 attr
=
667 UnoRuntime
.queryInterface(
668 XInterfaceAttributeTypeDescription2
.class,
670 short attrAttribs
= 0;
671 if (attr
.isBound()) {
672 attrAttribs
|= PropertyAttribute
.BOUND
;
674 boolean setUnknown
= false;
675 if (attr
.isReadOnly()) {
676 attrAttribs
|= PropertyAttribute
.READONLY
;
679 XCompoundTypeDescription
[] excs
= attr
.getGetExceptions();
680 boolean getUnknown
= false;
681 //XXX Special interpretation of getter/setter exceptions
682 // only works if the specified exceptions are of the exact
683 // type, not of a supertype:
684 for (int j
= 0; j
< excs
.length
; ++j
) {
685 if (excs
[j
].getName().equals(
686 "com.sun.star.beans.UnknownPropertyException"))
692 excs
= attr
.getSetExceptions();
693 for (int j
= 0; j
< excs
.length
; ++j
) {
694 if (excs
[j
].getName().equals(
695 "com.sun.star.beans.UnknownPropertyException"))
698 } else if (excs
[j
].getName().equals(
699 "com.sun.star.beans."
700 + "PropertyVetoException"))
702 attrAttribs
|= PropertyAttribute
.CONSTRAINED
;
705 if (getUnknown
&& setUnknown
) {
706 attrAttribs
|= PropertyAttribute
.OPTIONAL
;
708 XTypeDescription t
= attr
.getType();
710 t
= resolveTypedefs(t
);
712 if (t
.getName().startsWith(
713 "com.sun.star.beans.Ambiguous<"))
715 n
= PropertyAttribute
.MAYBEAMBIGUOUS
;
716 } else if (t
.getName().startsWith(
717 "com.sun.star.beans.Defaulted<"))
719 n
= PropertyAttribute
.MAYBEDEFAULT
;
720 } else if (t
.getName().startsWith(
721 "com.sun.star.beans.Optional<"))
723 n
= PropertyAttribute
.MAYBEVOID
;
728 t
= UnoRuntime
.queryInterface(XStructTypeDescription
.class, t
).getTypeArguments()[0];
730 String name
= members
[i
].getMemberName();
731 boolean present
= true;
732 if (absentOptional
!= null) {
733 for (int j
= 0; j
< absentOptional
.length
; ++j
) {
734 if (name
.equals(absentOptional
[j
])) {
744 name
, handleNames
.size(),
745 new Type(t
.getName(), t
.getTypeClass()),
750 throw new RuntimeException(
751 "inconsistent UNO type registry");
753 handleNames
.add(name
);
758 private String
translateHandle(int handle
) throws UnknownPropertyException
{
759 if (handle
< 0 || handle
>= handleMap
.length
) {
760 throw new UnknownPropertyException("bad handle " + handle
, object
);
762 return handleMap
[handle
];
765 private void setProperty(
766 String name
, Object value
, boolean isAmbiguous
, boolean isDefaulted
,
767 short illegalArgumentPosition
)
768 throws UnknownPropertyException
, PropertyVetoException
,
769 com
.sun
.star
.lang
.IllegalArgumentException
, WrappedTargetException
771 PropertyData p
= properties
.get(name
);
773 throw new UnknownPropertyException(name
, object
);
776 && (p
.property
.Attributes
& PropertyAttribute
.MAYBEAMBIGUOUS
) == 0)
778 && ((p
.property
.Attributes
& PropertyAttribute
.MAYBEDEFAULT
)
781 throw new com
.sun
.star
.lang
.IllegalArgumentException(
782 ("flagging as ambiguous/defaulted non-ambiguous/defaulted"
783 + " property " + name
),
784 object
, illegalArgumentPosition
);
787 XIdlField2 f
= UnoRuntime
.queryInterface(
788 XIdlField2
.class, idlClass
.getField(name
));
789 Object
[] o
= new Object
[] {
790 new Any(type
, UnoRuntime
.queryInterface(type
, object
)) };
791 Object v
= wrapValue(
793 UnoRuntime
.queryInterface(
794 XIdlField2
.class, idlClass
.getField(name
)).getType(),
795 (p
.property
.Attributes
& PropertyAttribute
.MAYBEAMBIGUOUS
) != 0,
797 (p
.property
.Attributes
& PropertyAttribute
.MAYBEDEFAULT
) != 0,
799 (p
.property
.Attributes
& PropertyAttribute
.MAYBEVOID
) != 0);
802 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
803 if (e
.ArgumentPosition
== 1) {
804 throw new com
.sun
.star
.lang
.IllegalArgumentException(e
,
805 e
.getMessage(), object
, illegalArgumentPosition
);
807 throw new RuntimeException(e
);
809 } catch (com
.sun
.star
.lang
.IllegalAccessException e
) {
810 //TODO Clarify whether PropertyVetoException is the correct
811 // exception to throw when trying to set a read-only property:
812 throw new PropertyVetoException(e
,
813 "cannot set read-only property " + name
, object
);
814 } catch (WrappedTargetRuntimeException e
) {
815 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
816 // guaranteed to originate directly within XIdlField2.get (and thus
817 // have the expected semantics); it might also be passed through
818 // from lower layers.
819 if (new Type(UnknownPropertyException
.class).isSupertypeOf(
820 AnyConverter
.getType(e
.TargetException
))
821 && (p
.property
.Attributes
& PropertyAttribute
.OPTIONAL
) != 0)
823 throw new UnknownPropertyException(e
, name
, object
);
824 } else if (new Type(PropertyVetoException
.class).isSupertypeOf(
825 AnyConverter
.getType(e
.TargetException
))
826 && ((p
.property
.Attributes
827 & PropertyAttribute
.CONSTRAINED
)
830 throw new PropertyVetoException(e
, name
, object
);
832 throw new WrappedTargetException(e
.getCause(),
833 e
.getMessage(), object
, e
.TargetException
);
838 Object
getProperty(String name
, PropertyState
[] state
)
839 throws UnknownPropertyException
, WrappedTargetException
841 PropertyData p
= properties
.get(name
);
843 throw new UnknownPropertyException(name
, object
);
845 XIdlField2 field
= UnoRuntime
.queryInterface(
846 XIdlField2
.class, idlClass
.getField(name
));
850 new Any(type
, UnoRuntime
.queryInterface(type
, object
)));
851 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
852 throw new RuntimeException(e
);
853 } catch (WrappedTargetRuntimeException e
) {
854 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
855 // guaranteed to originate directly within XIdlField2.get (and thus
856 // have the expected semantics); it might also be passed through
857 // from lower layers.
858 if (new Type(UnknownPropertyException
.class).isSupertypeOf(
859 AnyConverter
.getType(e
.TargetException
))
860 && (p
.property
.Attributes
& PropertyAttribute
.OPTIONAL
) != 0)
862 throw new UnknownPropertyException(e
, name
, object
);
864 throw new WrappedTargetException(e
.getCause(),
865 e
.getMessage(), object
, e
.TargetException
);
868 boolean undoAmbiguous
869 = (p
.property
.Attributes
& PropertyAttribute
.MAYBEAMBIGUOUS
) != 0;
870 boolean undoDefaulted
871 = (p
.property
.Attributes
& PropertyAttribute
.MAYBEDEFAULT
) != 0;
873 = (p
.property
.Attributes
& PropertyAttribute
.MAYBEVOID
) != 0;
874 boolean isAmbiguous
= false;
875 boolean isDefaulted
= false;
876 while (undoAmbiguous
|| undoDefaulted
|| undoOptional
) {
877 String typeName
= AnyConverter
.getType(value
).getTypeName();
879 && typeName
.startsWith("com.sun.star.beans.Ambiguous<"))
881 XIdlClass ambiguous
= getReflection(typeName
);
883 isAmbiguous
= AnyConverter
.toBoolean(
884 UnoRuntime
.queryInterface(
886 ambiguous
.getField("IsAmbiguous")).get(value
));
887 value
= UnoRuntime
.queryInterface(
889 ambiguous
.getField("Value")).get(value
);
890 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
891 throw new RuntimeException(e
);
893 undoAmbiguous
= false;
894 } else if (undoDefaulted
895 && typeName
.startsWith("com.sun.star.beans.Defaulted<"))
897 XIdlClass defaulted
= getReflection(typeName
);
899 isDefaulted
= AnyConverter
.toBoolean(
900 UnoRuntime
.queryInterface(
902 defaulted
.getField("IsDefaulted")).get(value
));
903 value
= UnoRuntime
.queryInterface(
905 defaulted
.getField("Value")).get(value
);
906 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
907 throw new RuntimeException(e
);
909 undoDefaulted
= false;
910 } else if (undoOptional
911 && typeName
.startsWith("com.sun.star.beans.Optional<"))
913 XIdlClass optional
= getReflection(typeName
);
915 boolean present
= AnyConverter
.toBoolean(
916 UnoRuntime
.queryInterface(
918 optional
.getField("IsPresent")).get(value
));
923 value
= UnoRuntime
.queryInterface(
925 optional
.getField("Value")).get(value
);
926 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
927 throw new RuntimeException(e
);
929 undoOptional
= false;
931 throw new RuntimeException(
932 "unexpected type of attribute " + name
);
936 //XXX If isAmbiguous && isDefaulted, arbitrarily choose
937 // AMBIGUOUS_VALUE over DEFAULT_VALUE:
938 state
[0] = isAmbiguous
939 ? PropertyState
.AMBIGUOUS_VALUE
941 ? PropertyState
.DEFAULT_VALUE
: PropertyState
.DIRECT_VALUE
;
946 private Object
wrapValue(
947 Object value
, XIdlClass type
, boolean wrapAmbiguous
,
948 boolean isAmbiguous
, boolean wrapDefaulted
, boolean isDefaulted
,
949 boolean wrapOptional
)
952 && type
.getName().startsWith("com.sun.star.beans.Ambiguous<"))
954 Object
[] strct
= new Object
[1];
955 type
.createObject(strct
);
957 XIdlField2 field
= UnoRuntime
.queryInterface(
958 XIdlField2
.class, type
.getField("Value"));
962 value
, field
.getType(), false, false, wrapDefaulted
,
963 isDefaulted
, wrapOptional
));
964 UnoRuntime
.queryInterface(
965 XIdlField2
.class, type
.getField("IsAmbiguous")).set(
966 strct
, Boolean
.valueOf(isAmbiguous
));
967 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
968 throw new RuntimeException(e
);
969 } catch (com
.sun
.star
.lang
.IllegalAccessException e
) {
970 throw new RuntimeException(e
);
973 } else if (wrapDefaulted
974 && type
.getName().startsWith(
975 "com.sun.star.beans.Defaulted<"))
977 Object
[] strct
= new Object
[1];
978 type
.createObject(strct
);
980 XIdlField2 field
= UnoRuntime
.queryInterface(
981 XIdlField2
.class, type
.getField("Value"));
985 value
, field
.getType(), wrapAmbiguous
, isAmbiguous
,
986 false, false, wrapOptional
));
987 UnoRuntime
.queryInterface(
988 XIdlField2
.class, type
.getField("IsDefaulted")).set(
989 strct
, Boolean
.valueOf(isDefaulted
));
990 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
991 throw new RuntimeException(e
);
992 } catch (com
.sun
.star
.lang
.IllegalAccessException e
) {
993 throw new RuntimeException(e
);
996 } else if (wrapOptional
997 && type
.getName().startsWith("com.sun.star.beans.Optional<"))
999 Object
[] strct
= new Object
[1];
1000 type
.createObject(strct
);
1001 boolean present
= !AnyConverter
.isVoid(value
);
1003 UnoRuntime
.queryInterface(
1004 XIdlField2
.class, type
.getField("IsPresent")).set(
1005 strct
, Boolean
.valueOf(present
));
1007 XIdlField2 field
= UnoRuntime
.queryInterface(
1008 XIdlField2
.class, type
.getField("Value"));
1012 value
, field
.getType(), wrapAmbiguous
, isAmbiguous
,
1013 wrapDefaulted
, isDefaulted
, false));
1015 } catch (com
.sun
.star
.lang
.IllegalArgumentException e
) {
1016 throw new RuntimeException(e
);
1017 } catch (com
.sun
.star
.lang
.IllegalAccessException e
) {
1018 throw new RuntimeException(e
);
1022 if (wrapAmbiguous
|| wrapDefaulted
|| wrapOptional
) {
1023 throw new RuntimeException("unexpected type of attribute");
1029 private static XTypeDescription
resolveTypedefs(XTypeDescription type
) {
1030 while (type
.getTypeClass() == TypeClass
.TYPEDEF
) {
1031 type
= UnoRuntime
.queryInterface(
1032 XIndirectTypeDescription
.class, type
).getReferencedType();
1037 private PropertyData
get(Object object
, String propertyName
)
1038 throws UnknownPropertyException
1040 PropertyData p
= properties
.get(propertyName
);
1041 if (p
== null || !p
.present
) {
1042 throw new UnknownPropertyException(propertyName
, object
);
1047 private void checkUnknown(String propertyName
)
1048 throws UnknownPropertyException
1050 if (propertyName
.length() != 0) {
1051 get(this, propertyName
);
1055 private static final class PropertyData
{
1056 public PropertyData(Property property
, boolean present
) {
1057 this.property
= property
;
1058 this.present
= present
;
1061 public final Property property
;
1062 public final boolean present
;
1065 private final class Info
extends WeakBase
implements XPropertySetInfo
1067 public Info(Map
<String
,PropertyData
> properties
) {
1068 this.properties
= properties
;
1071 public Property
[] getProperties() {
1072 ArrayList
<Property
> al
= new ArrayList
<Property
>(properties
.size());
1073 for (Iterator
<PropertyData
> i
= properties
.values().iterator(); i
.hasNext();) {
1074 PropertyData p
= i
.next();
1079 return al
.toArray(new Property
[al
.size()]);
1082 public Property
getPropertyByName(String name
)
1083 throws UnknownPropertyException
1085 return get(this, name
).property
;
1088 public boolean hasPropertyByName(String name
) {
1089 PropertyData p
= properties
.get(name
);
1090 return p
!= null && p
.present
;
1093 private final Map
<String
,PropertyData
> properties
;
1096 private final XComponentContext context
;
1097 private final XInterface object
;
1098 private final Type type
;
1099 private final String
[] absentOptional
;
1100 private final XIdlClass idlClass
;
1101 private final Map
<String
,PropertyData
> properties
; // from String to Property
1102 private final String
[] handleMap
;
1104 private HashMap
<String
,ArrayList
<XPropertyChangeListener
>> boundListeners
1105 = new HashMap
<String
,ArrayList
<XPropertyChangeListener
>>();
1106 // from String to Vector of XPropertyChangeListener
1107 private HashMap
<String
,ArrayList
<XVetoableChangeListener
>> vetoListeners
1108 = new HashMap
<String
,ArrayList
<XVetoableChangeListener
>>();
1109 // from String to Vector of XVetoableChangeListener
1110 private boolean disposed
= false;