From e6bdd0326fe2e8bbb08c9054bdd5d3bfae0ed9d9 Mon Sep 17 00:00:00 2001 From: Jens-Heiner Rechtien
A client will mix in this class by keeping a reference to an instance of
+ this class, and forwarding all methods of (a subset of the interfaces)
+ com.sun.star.beans.XPropertySet
,
+ com.sun.star.beans.XFastPropertySet
, and
+ com.sun.star.beans.XPropertyAccess
to it.
Client code should not use the monitors associated with instances of this + class, as they are used for internal purposes.
+ + @since UDK 3.2 +*/ +public final class PropertySetMixin { + /** + The constructor. + + @param context the component context used by this instance; must not be + null, and must supply the service +com.sun.star.reflection.CoreReflection
and the singleton
+ com.sun.star.reflection.theTypeDescriptionManager
+
+ @param object the client UNO object into which this instance is mixed in;
+ must not be null, and must support the given type
+
+ @param type the UNO interface type whose attributes are mapped to
+ properties; must not be null, and must represent a UNO interface type
+
+ @param absentOptional a list of optional properties that are not present,
+ and should thus not be visible via
+ com.sun.star.beans.XPropertySet.getPropertySetInfo
; null is
+ treated the same as an empty list; if non-null, the given array must not
+ be modified after it is passed to this constructor. For consistency
+ reasons, the given absentOptional
should only contain the
+ names of attributes that represent optional properties that are not
+ present (that is, the attribute getters and setters always throw a
+ com.sun.star.beans.UnknownPropertyException
), and should
+ contain each such name only once. If an optional property is not present
+ (that is, the corresponding attribute getter and setter always throw a
+ com.sun.star.beans.UnknownPropertyException
) but is not
+ contained in the given absentOptional
, then it will be
+ visible via
+ com.sun.star.beans.XPropertySet.getPropertySetInfo
as a
+ com.sun.star.beans.Property
with a set
+ com.sun.star.beans.PropertyAttribute.OPTIONAL
. If the given
+ object
does not implement
+ com.sun.star.beans.XPropertySet
, then the given
+ absentOptional
is effectively ignored and can be null or
+ empty.
+ */
+ public PropertySetMixin(
+ XComponentContext context, XInterface object, Type type,
+ String[] absentOptional)
+ {
+ // assert context != null && object != null && type != null
+ // && type.getTypeClass() == TypeClass.INTERFACE;
+ this.context = context;
+ this.object = object;
+ this.type = type;
+ this.absentOptional = absentOptional;
+ idlClass = getReflection(type.getTypeName());
+ XTypeDescription ifc;
+ try {
+ ifc = (XTypeDescription) UnoRuntime.queryInterface(
+ XTypeDescription.class,
+ (((XHierarchicalNameAccess) UnoRuntime.queryInterface(
+ XHierarchicalNameAccess.class,
+ context.getValueByName(
+ "/singletons/com.sun.star.reflection."
+ + "theTypeDescriptionManager"))).
+ getByHierarchicalName(type.getTypeName())));
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException(
+ "unexpected com.sun.star.container.NoSuchElementException: "
+ + e.getMessage());
+ }
+ HashMap map = new HashMap();
+ ArrayList handleNames = new ArrayList();
+ initProperties(ifc, map, handleNames, new HashSet());
+ properties = map;
+ handleMap = (String[]) handleNames.toArray(
+ new String[handleNames.size()]);
+ }
+
+ /**
+ A method used by clients when implementing UNO interface type attribute
+ setter functions.
+
+ First, this method checks whether this instance has already been
+ disposed (see {@link #dispose}), and throws a
+ com.sun.star.beans.DisposedException
if applicable. For a
+ constrained attribute (whose setter can explicitly raise
+ com.sun.star.beans.PropertyVetoException
), this method
+ notifies any com.sun.star.beans.XVetoableChangeListener
s.
+ For a bound attribute, this method modifies the passed-in
+ bound
so that it can afterwards be used to notify any
+ com.sun.star.beans.XPropertyChangeListener
s. This method
+ should be called before storing the new attribute value, and
+ bound.notifyListeners()
should be called exactly once after
+ storing the new attribute value (in case the attribute is bound;
+ otherwise, calling bound.notifyListeners()
is ignored).
+ Furthermore, bound.notifyListeners()
and this method have to
+ be called from the same thread.
com.sun.star.beans.PropertyChangeEvent.OldValue
, which is
+ rather useless, anyway (see “Using the Observer Pattern” in
+
+ OpenOffice.org Coding Guidelines). If the attribute
+ that is going to be set is neither bound nor constrained, or if
+ com.sun.star.beans.PropertyChangeEvent.OldValue
should not
+ be set, {@link Any#VOID} can be used instead.
+
+ @param newValue the property value corresponding to the new
+ attribute value. This is only used as
+ com.sun.star.beans.PropertyChangeEvent.NewValue
, which is
+ rather useless, anyway (see “Using the Observer Pattern&rdquo: in
+
+ OpenOffice.org Coding Guidelines), unless the
+ attribute that is going to be set is constrained. If the attribute
+ that is going to be set is neither bound nor constrained, or if it is
+ only bound but
+ com.sun.star.beans.PropertyChangeEvent.NewValue
should not
+ be set, {@link Any#VOID} can be used instead.
+
+ @param bound a reference to a fresh {@link BoundListeners} instance
+ (which has not been passed to this method before, and on which
+ {@link BoundListeners#notifyListeners} has not yet been called); may only
+ be null if the attribute that is going to be set is not bound
+ */
+ public void prepareSet(
+ String propertyName, Object oldValue, Object newValue,
+ BoundListeners bound)
+ throws PropertyVetoException
+ {
+ // assert properties.get(propertyName) != null;
+ Property p = ((PropertyData) properties.get(propertyName)).property;
+ Vector specificVeto = null;
+ Vector unspecificVeto = null;
+ synchronized (this) {
+ if (disposed) {
+ throw new DisposedException("disposed", object);
+ }
+ if ((p.Attributes & PropertyAttribute.CONSTRAINED) != 0) {
+ Object o = vetoListeners.get(propertyName);
+ if (o != null) {
+ specificVeto = (Vector) ((Vector) o).clone();
+ }
+ o = vetoListeners.get("");
+ if (o != null) {
+ unspecificVeto = (Vector) ((Vector) o).clone();
+ }
+ }
+ if ((p.Attributes & PropertyAttribute.BOUND) != 0) {
+ // assert bound != null;
+ Object o = boundListeners.get(propertyName);
+ if (o != null) {
+ bound.specificListeners = (Vector) ((Vector) o).clone();
+ }
+ o = boundListeners.get("");
+ if (o != null) {
+ bound.unspecificListeners = (Vector) ((Vector) o).clone();
+ }
+ }
+ }
+ if ((p.Attributes & PropertyAttribute.CONSTRAINED) != 0) {
+ PropertyChangeEvent event = new PropertyChangeEvent(
+ object, propertyName, false, p.Handle, oldValue, newValue);
+ if (specificVeto != null) {
+ for (Iterator i = specificVeto.iterator(); i.hasNext();) {
+ try {
+ ((XVetoableChangeListener) i.next()).vetoableChange(
+ event);
+ } catch (DisposedException e) {}
+ }
+ }
+ if (unspecificVeto != null) {
+ for (Iterator i = unspecificVeto.iterator(); i.hasNext();) {
+ try {
+ ((XVetoableChangeListener) i.next()).vetoableChange(
+ event);
+ } catch (DisposedException e) {}
+ }
+ }
+ }
+ if ((p.Attributes & PropertyAttribute.BOUND) != 0) {
+ // assert bound != null;
+ bound.event = new PropertyChangeEvent(
+ object, propertyName, false, p.Handle, oldValue, newValue);
+ }
+ }
+
+ /**
+ A simplified version of {@link #prepareSet(String, Object, Object,
+ PropertySetMixin.BoundListeners)}.
+
+ This method is useful for attributes that are not constrained.
+ + @param propertyName the name of the property (which is the same as the + name of the attribute that is going to be set) + + @param bound a reference to a fresh {@link BoundListeners} instance + (which has not been passed to this method before, and on which + {@link BoundListeners#notifyListeners} has not yet been called); may only + be null if the attribute that is going to be set is not bound + */ + public void prepareSet(String propertyName, BoundListeners bound) { + try { + prepareSet(propertyName, Any.VOID, Any.VOID, bound); + } catch (PropertyVetoException e) { + throw new RuntimeException("unexpected " + e); + } + } + + /** + Marks this instance as being disposed. + +See com.sun.star.lang.XComponent
for the general concept
+ of disposing UNO objects. On the first call to this method, all
+ registered listeners
+ (com.sun.star.beans.XPropertyChangeListener
s and
+ com.sun.star.beans.XVetoableChangeListener
s) are notified of
+ the disposing source. Any subsequent calls to this method are
+ ignored.
com.sun.star.beans.XPropertySet.getPropertySetInfo
.
+ */
+ public XPropertySetInfo getPropertySetInfo() {
+ return new Info(properties);
+ }
+
+ /**
+ Implements com.sun.star.beans.XPropertySet.setPropertyValue
.
+ */
+ public void setPropertyValue(String propertyName, Object value)
+ throws UnknownPropertyException, PropertyVetoException,
+ com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ setProperty(propertyName, value, false, false, (short) 1);
+ }
+
+ /**
+ Implements com.sun.star.beans.XPropertySet.getPropertyValue
.
+ */
+ public Object getPropertyValue(String propertyName)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ return getProperty(propertyName, null);
+ }
+
+ /**
+ Implements
+ com.sun.star.beans.XPropertySet.addPropertyChangeListener
.
+
+ If the given property name is neither empty nor the name of a bound
+ property, the listener is registered nonetheless: it can be removed again
+ with a call to {@link #removePropertyChangeListener}, and it is notified
+ when this object is disposed, but it will never be notified about a
+ property change event. Since this method does not check whether the
+ given property name is valid, it never throws
+ com.sun.star.beans.UnknownPropertyException
.
If a listener is added more than once, it will receive all relevant + notifications multiple times.
+ */ + public void addPropertyChangeListener( + String propertyName, XPropertyChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + // assert listener != null; + boolean disp; + synchronized (this) { + disp = disposed; + if (!disp) { + Vector v = (Vector) boundListeners.get(propertyName); + if (v == null) { + v = new Vector(); + boundListeners.put(propertyName, v); + } + v.add(listener); + } + } + if (disp) { + listener.disposing(new EventObject(object)); + } + } + + /** + Implements
+ com.sun.star.beans.XPropertySet.removePropertyChangeListener
.
+ */
+ public void removePropertyChangeListener(
+ String propertyName, XPropertyChangeListener listener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ // assert listener != null;
+ synchronized (this) {
+ if (boundListeners != null) {
+ Vector v = (Vector) boundListeners.get(propertyName);
+ if (v != null) {
+ v.remove(listener);
+ }
+ }
+ }
+ }
+
+ /**
+ Implements
+ com.sun.star.beans.XPropertySet.addVetoableChangeListener
.
+
+ If the given property name is neither empty nor the name of a
+ constrained property, the listener is registered nonetheless: it can be
+ removed again with a call to {@link #removeVetoableChangeListener}, and
+ it is notified when this object is disposed, but it will never be
+ notified about a property change event. Since this method does not check
+ whether the given property name is valid, it never throws
+ com.sun.star.beans.UnknownPropertyException
.
If a listener is added more than once, it will receive all relevant + notifications multiple times.
+ */ + public void addVetoableChangeListener( + String propertyName, XVetoableChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + // assert listener != null; + boolean disp; + synchronized (this) { + disp = disposed; + if (!disp) { + Vector v = (Vector) vetoListeners.get(propertyName); + if (v == null) { + v = new Vector(); + vetoListeners.put(propertyName, v); + } + v.add(listener); + } + } + if (disp) { + listener.disposing(new EventObject(object)); + } + } + + /** + Implements
+ com.sun.star.beans.XPropertySet.removeVetoableChangeListener
.
+ */
+ public void removeVetoableChangeListener(
+ String propertyName, XVetoableChangeListener listener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ // assert listener != null;
+ synchronized (this) {
+ if (vetoListeners != null) {
+ Vector v = (Vector) vetoListeners.get(propertyName);
+ if (v != null) {
+ v.remove(listener);
+ }
+ }
+ }
+ }
+
+ /**
+ Implements
+ com.sun.star.beans.XFastPropertySet.setFastPropertyValue
.
+ */
+ public void setFastPropertyValue(int handle, Object value)
+ throws UnknownPropertyException, PropertyVetoException,
+ com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ setProperty(translateHandle(handle), value, false, false, (short) 1);
+ }
+
+ /**
+ Implements
+ com.sun.star.beans.XFastPropertySet.getFastPropertyValue
.
+ */
+ public Object getFastPropertyValue(int handle)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ return getProperty(translateHandle(handle), null);
+ }
+
+ /**
+ Implements
+ com.sun.star.beans.XPropertyAccess.getPropertyValues
.
+ */
+ public PropertyValue[] getPropertyValues() {
+ PropertyValue[] s = new PropertyValue[handleMap.length];
+ int n = 0;
+ for (int i = 0; i < handleMap.length; ++i) {
+ PropertyState[] state = new PropertyState[1];
+ Object value;
+ try {
+ value = getProperty(handleMap[i], state);
+ } catch (UnknownPropertyException e) {
+ continue;
+ } catch (WrappedTargetException e) {
+ throw new WrappedTargetRuntimeException(
+ e.getMessage(), object, e.TargetException);
+ }
+ s[n++] = new PropertyValue(handleMap[i], i, value, state[0]);
+ }
+ if (n < handleMap.length) {
+ PropertyValue[] s2 = new PropertyValue[n];
+ System.arraycopy(s, 0, s2, 0, n);
+ s = s2;
+ }
+ return s;
+ }
+
+ /**
+ Implements
+ com.sun.star.beans.XPropertyAccess.setPropertyValues
.
+ */
+ public void setPropertyValues(PropertyValue[] props)
+ throws UnknownPropertyException, PropertyVetoException,
+ com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ for (int i = 0; i < props.length; ++i) {
+ if (props[i].Handle != -1
+ && !props[i].Name.equals(translateHandle(props[i].Handle)))
+ {
+ throw new UnknownPropertyException(
+ ("name " + props[i].Name + " does not match handle "
+ + props[i].Handle),
+ object);
+ }
+ setProperty(
+ props[i].Name, props[i].Value,
+ props[i].State == PropertyState.AMBIGUOUS_VALUE,
+ props[i].State == PropertyState.DEFAULT_VALUE, (short) 0);
+ }
+ }
+
+ /**
+ A class used by clients of {@link PropertySetMixin} when implementing UNO
+ interface type attribute setter functions.
+
+ @see #prepareSet(String, Object, Object, PropertySetMixin.BoundListeners)
+ */
+ public static final class BoundListeners {
+ /**
+ The constructor.
+ */
+ public BoundListeners() {}
+
+ /**
+ Notifies any
+ com.sun.star.beans.XPropertyChangeListener
s.
+
+ @see #prepareSet(String, Object, Object,
+ PropertySetMixin.BoundListeners)
+ */
+ public void notifyListeners() {
+ if (specificListeners != null) {
+ for (Iterator i = specificListeners.iterator(); i.hasNext();) {
+ try {
+ ((XPropertyChangeListener) i.next()).propertyChange(
+ event);
+ } catch (DisposedException e) {}
+ }
+ }
+ if (unspecificListeners != null) {
+ for (Iterator i = unspecificListeners.iterator(); i.hasNext();)
+ {
+ try {
+ ((XPropertyChangeListener) i.next()).propertyChange(
+ event);
+ } catch (DisposedException e) {}
+ }
+ }
+ }
+
+ private Vector specificListeners = null;
+ private Vector unspecificListeners = null;
+ private PropertyChangeEvent event = null;
+ }
+
+ private XIdlClass getReflection(String typeName) {
+ XIdlReflection refl;
+ try {
+ refl = (XIdlReflection) UnoRuntime.queryInterface(
+ XIdlReflection.class,
+ context.getServiceManager().createInstanceWithContext(
+ "com.sun.star.reflection.CoreReflection", context));
+ } catch (com.sun.star.uno.Exception e) {
+ throw new DeploymentException(
+ ("component context fails to supply service"
+ + " com.sun.star.reflection.CoreReflection: "
+ + e.getMessage()),
+ context);
+ }
+ try {
+ return refl.forName(typeName);
+ } finally {
+ XComponent comp = (XComponent) UnoRuntime.queryInterface(
+ XComponent.class, refl);
+ if (comp != null) {
+ comp.dispose();
+ }
+ }
+ }
+
+ private void initProperties(
+ XTypeDescription type, HashMap map, ArrayList handleNames, HashSet seen)
+ {
+ XInterfaceTypeDescription2 ifc = (XInterfaceTypeDescription2)
+ UnoRuntime.queryInterface(
+ XInterfaceTypeDescription2.class, resolveTypedefs(type));
+ if (seen.add(ifc.getName())) {
+ XTypeDescription[] bases = ifc.getBaseTypes();
+ for (int i = 0; i < bases.length; ++i) {
+ initProperties(bases[i], map, handleNames, seen);
+ }
+ XInterfaceMemberTypeDescription[] members = ifc.getMembers();
+ for (int i = 0; i < members.length; ++i) {
+ if (members[i].getTypeClass() == TypeClass.INTERFACE_ATTRIBUTE)
+ {
+ XInterfaceAttributeTypeDescription2 attr
+ = ((XInterfaceAttributeTypeDescription2)
+ UnoRuntime.queryInterface(
+ XInterfaceAttributeTypeDescription2.class,
+ members[i]));
+ short attrAttribs = 0;
+ if (attr.isBound()) {
+ attrAttribs |= PropertyAttribute.BOUND;
+ }
+ boolean setUnknown = false;
+ if (attr.isReadOnly()) {
+ attrAttribs |= PropertyAttribute.READONLY;
+ setUnknown = true;
+ }
+ XCompoundTypeDescription[] excs = attr.getGetExceptions();
+ boolean getUnknown = false;
+ //XXX Special interpretation of getter/setter exceptions
+ // only works if the specified exceptions are of the exact
+ // type, not of a supertype:
+ for (int j = 0; j < excs.length; ++j) {
+ if (excs[j].getName().equals(
+ "com.sun.star.beans.UnknownPropertyException"))
+ {
+ getUnknown = true;
+ break;
+ }
+ }
+ excs = attr.getSetExceptions();
+ for (int j = 0; j < excs.length; ++j) {
+ if (excs[j].getName().equals(
+ "com.sun.star.beans.UnknownPropertyException"))
+ {
+ setUnknown = true;
+ } else if (excs[j].getName().equals(
+ "com.sun.star.beans."
+ + "PropertyVetoException"))
+ {
+ attrAttribs |= PropertyAttribute.CONSTRAINED;
+ }
+ }
+ if (getUnknown && setUnknown) {
+ attrAttribs |= PropertyAttribute.OPTIONAL;
+ }
+ XTypeDescription t = attr.getType();
+ for (;;) {
+ t = resolveTypedefs(t);
+ short n;
+ if (t.getName().startsWith(
+ "com.sun.star.beans.Ambiguous<"))
+ {
+ n = PropertyAttribute.MAYBEAMBIGUOUS;
+ } else if (t.getName().startsWith(
+ "com.sun.star.beans.Defaulted<"))
+ {
+ n = PropertyAttribute.MAYBEDEFAULT;
+ } else if (t.getName().startsWith(
+ "com.sun.star.beans.Optional<"))
+ {
+ n = PropertyAttribute.MAYBEVOID;
+ } else {
+ break;
+ }
+ attrAttribs |= n;
+ t = ((XStructTypeDescription) UnoRuntime.queryInterface(
+ XStructTypeDescription.class, t)).
+ getTypeArguments()[0];
+ }
+ String name = members[i].getMemberName();
+ boolean present = true;
+ if (absentOptional != null) {
+ for (int j = 0; j < absentOptional.length; ++j) {
+ if (name.equals(absentOptional[j])) {
+ present = false;
+ break;
+ }
+ }
+ }
+ if (map.put(
+ name,
+ new PropertyData(
+ new Property(
+ name, handleNames.size(),
+ new Type(t.getName(), t.getTypeClass()),
+ attrAttribs),
+ present))
+ != null)
+ {
+ throw new RuntimeException(
+ "inconsistent UNO type registry");
+ }
+ handleNames.add(name);
+ }
+ }
+ }
+ }
+
+ private String translateHandle(int handle) throws UnknownPropertyException {
+ if (handle < 0 || handle >= handleMap.length) {
+ throw new UnknownPropertyException("bad handle " + handle, object);
+ }
+ return handleMap[handle];
+ }
+
+ private void setProperty(
+ String name, Object value, boolean isAmbiguous, boolean isDefaulted,
+ short illegalArgumentPosition)
+ throws UnknownPropertyException, PropertyVetoException,
+ com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ PropertyData p = (PropertyData) properties.get(name);
+ if (p == null) {
+ throw new UnknownPropertyException(name, object);
+ }
+ if ((isAmbiguous
+ && (p.property.Attributes & PropertyAttribute.MAYBEAMBIGUOUS) == 0)
+ || (isDefaulted
+ && ((p.property.Attributes & PropertyAttribute.MAYBEDEFAULT)
+ == 0)))
+ {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ ("flagging as ambiguous/defaulted non-ambiguous/defaulted"
+ + " property " + name),
+ object, illegalArgumentPosition);
+
+ }
+ XIdlField2 f = (XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class, idlClass.getField(name));
+ Object[] o = new Object[] {
+ new Any(type, UnoRuntime.queryInterface(type, object)) };
+ Object v = wrapValue(
+ value,
+ ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class, idlClass.getField(name))).getType(),
+ (p.property.Attributes & PropertyAttribute.MAYBEAMBIGUOUS) != 0,
+ isAmbiguous,
+ (p.property.Attributes & PropertyAttribute.MAYBEDEFAULT) != 0,
+ isDefaulted,
+ (p.property.Attributes & PropertyAttribute.MAYBEVOID) != 0);
+ try {
+ f.set(o, v);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ if (e.ArgumentPosition == 1) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ e.getMessage(), object, illegalArgumentPosition);
+ } else {
+ throw new RuntimeException(
+ "unexpected com.sun.star.lang.IllegalArgumentException: "
+ + e.getMessage());
+ }
+ } catch (com.sun.star.lang.IllegalAccessException e) {
+ //TODO Clarify whether PropertyVetoException is the correct
+ // exception to throw when trying to set a read-only property:
+ throw new PropertyVetoException(
+ "cannot set read-only property " + name, object);
+ } catch (WrappedTargetRuntimeException e) {
+ //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
+ // guaranteed to originate directly within XIdlField2.get (and thus
+ // have the expected semantics); it might also be passed through
+ // from lower layers.
+ if (new Type(UnknownPropertyException.class).isSupertypeOf(
+ AnyConverter.getType(e.TargetException))
+ && (p.property.Attributes & PropertyAttribute.OPTIONAL) != 0)
+ {
+ throw new UnknownPropertyException(name, object);
+ } else if (new Type(PropertyVetoException.class).isSupertypeOf(
+ AnyConverter.getType(e.TargetException))
+ && ((p.property.Attributes
+ & PropertyAttribute.CONSTRAINED)
+ != 0))
+ {
+ throw new PropertyVetoException(name, object);
+ } else {
+ throw new WrappedTargetException(
+ e.getMessage(), object, e.TargetException);
+ }
+ }
+ }
+
+ Object getProperty(String name, PropertyState[] state)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ PropertyData p = (PropertyData) properties.get(name);
+ if (p == null) {
+ throw new UnknownPropertyException(name, object);
+ }
+ XIdlField2 field = (XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class, idlClass.getField(name));
+ Object value;
+ try {
+ value = field.get(
+ new Any(type, UnoRuntime.queryInterface(type, object)));
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(
+ "unexpected com.sun.star.lang.IllegalArgumentException: "
+ + e.getMessage());
+ } catch (WrappedTargetRuntimeException e) {
+ //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
+ // guaranteed to originate directly within XIdlField2.get (and thus
+ // have the expected semantics); it might also be passed through
+ // from lower layers.
+ if (new Type(UnknownPropertyException.class).isSupertypeOf(
+ AnyConverter.getType(e.TargetException))
+ && (p.property.Attributes & PropertyAttribute.OPTIONAL) != 0)
+ {
+ throw new UnknownPropertyException(name, object);
+ } else {
+ throw new WrappedTargetException(
+ e.getMessage(), object, e.TargetException);
+ }
+ }
+ boolean undoAmbiguous
+ = (p.property.Attributes & PropertyAttribute.MAYBEAMBIGUOUS) != 0;
+ boolean undoDefaulted
+ = (p.property.Attributes & PropertyAttribute.MAYBEDEFAULT) != 0;
+ boolean undoOptional
+ = (p.property.Attributes & PropertyAttribute.MAYBEVOID) != 0;
+ boolean isAmbiguous = false;
+ boolean isDefaulted = false;
+ while (undoAmbiguous || undoDefaulted || undoOptional) {
+ String typeName = AnyConverter.getType(value).getTypeName();
+ if (undoAmbiguous
+ && typeName.startsWith("com.sun.star.beans.Ambiguous<"))
+ {
+ XIdlClass ambiguous = getReflection(typeName);
+ try {
+ isAmbiguous = AnyConverter.toBoolean(
+ ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class,
+ ambiguous.getField("IsAmbiguous"))).get(value));
+ value = ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class,
+ ambiguous.getField("Value"))).get(value);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(
+ "unexpected"
+ + " com.sun.star.lang.IllegalArgumentException: "
+ + e.getMessage());
+ }
+ undoAmbiguous = false;
+ } else if (undoDefaulted
+ && typeName.startsWith("com.sun.star.beans.Defaulted<"))
+ {
+ XIdlClass defaulted = getReflection(typeName);
+ try {
+ isDefaulted = AnyConverter.toBoolean(
+ ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class,
+ defaulted.getField("IsDefaulted"))).get(value));
+ value = ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class,
+ defaulted.getField("Value"))).get(value);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(
+ "unexpected"
+ + " com.sun.star.lang.IllegalArgumentException: "
+ + e.getMessage());
+ }
+ undoDefaulted = false;
+ } else if (undoOptional
+ && typeName.startsWith("com.sun.star.beans.Optional<"))
+ {
+ XIdlClass optional = getReflection(typeName);
+ try {
+ boolean present = AnyConverter.toBoolean(
+ ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class,
+ optional.getField("IsPresent"))).get(value));
+ if (!present) {
+ value = Any.VOID;
+ break;
+ }
+ value = ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class,
+ optional.getField("Value"))).get(value);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(
+ "unexpected"
+ + " com.sun.star.lang.IllegalArgumentException: "
+ + e.getMessage());
+ }
+ undoOptional = false;
+ } else {
+ throw new RuntimeException(
+ "unexpected type of attribute " + name);
+ }
+ }
+ if (state != null) {
+ //XXX If isAmbiguous && isDefaulted, arbitrarily choose
+ // AMBIGUOUS_VALUE over DEFAULT_VALUE:
+ state[0] = isAmbiguous
+ ? PropertyState.AMBIGUOUS_VALUE
+ : isDefaulted
+ ? PropertyState.DEFAULT_VALUE : PropertyState.DIRECT_VALUE;
+ }
+ return value;
+ }
+
+ private Object wrapValue(
+ Object value, XIdlClass type, boolean wrapAmbiguous,
+ boolean isAmbiguous, boolean wrapDefaulted, boolean isDefaulted,
+ boolean wrapOptional)
+ {
+ // assert (wrapAmbiguous || !isAmbiguous)
+ // && (wrapDefaulted || !isDefaulted);
+ if (wrapAmbiguous
+ && type.getName().startsWith("com.sun.star.beans.Ambiguous<"))
+ {
+ Object[] strct = new Object[1];
+ type.createObject(strct);
+ try {
+ XIdlField2 field = (XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("Value"));
+ field.set(
+ strct,
+ wrapValue(
+ value, field.getType(), false, false, wrapDefaulted,
+ isDefaulted, wrapOptional));
+ ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("IsAmbiguous"))).set(
+ strct, new Boolean(isAmbiguous));
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(
+ "unexpected com.sun.star.lang.IllegalArgumentException: "
+ + e.getMessage());
+ } catch (com.sun.star.lang.IllegalAccessException e) {
+ throw new RuntimeException(
+ "unexpected com.sun.star.lang.IllegalAccessException: "
+ + e.getMessage());
+ }
+ return strct[0];
+ } else if (wrapDefaulted
+ && type.getName().startsWith(
+ "com.sun.star.beans.Defaulted<"))
+ {
+ Object[] strct = new Object[1];
+ type.createObject(strct);
+ try {
+ XIdlField2 field = (XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("Value"));
+ field.set(
+ strct,
+ wrapValue(
+ value, field.getType(), wrapAmbiguous, isAmbiguous,
+ false, false, wrapOptional));
+ ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("IsDefaulted"))).set(
+ strct, new Boolean(isDefaulted));
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(
+ "unexpected com.sun.star.lang.IllegalArgumentException: "
+ + e.getMessage());
+ } catch (com.sun.star.lang.IllegalAccessException e) {
+ throw new RuntimeException(
+ "unexpected com.sun.star.lang.IllegalAccessException: "
+ + e.getMessage());
+ }
+ return strct[0];
+ } else if (wrapOptional
+ && type.getName().startsWith("com.sun.star.beans.Optional<"))
+ {
+ Object[] strct = new Object[1];
+ type.createObject(strct);
+ boolean present = !AnyConverter.isVoid(value);
+ try {
+ ((XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("IsPresent"))).set(
+ strct, new Boolean(present));
+ if (present) {
+ XIdlField2 field = (XIdlField2) UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("Value"));
+ field.set(
+ strct,
+ wrapValue(
+ value, field.getType(), wrapAmbiguous, isAmbiguous,
+ wrapDefaulted, isDefaulted, false));
+ }
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(
+ "unexpected com.sun.star.lang.IllegalArgumentException: "
+ + e.getMessage());
+ } catch (com.sun.star.lang.IllegalAccessException e) {
+ throw new RuntimeException(
+ "unexpected com.sun.star.lang.IllegalAccessException: "
+ + e.getMessage());
+ }
+ return strct[0];
+ } else {
+ if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
+ throw new RuntimeException("unexpected type of attribute");
+ }
+ return value;
+ }
+ }
+
+ private static XTypeDescription resolveTypedefs(XTypeDescription type) {
+ while (type.getTypeClass() == TypeClass.TYPEDEF) {
+ type = ((XIndirectTypeDescription) UnoRuntime.queryInterface(
+ XIndirectTypeDescription.class, type)).
+ getReferencedType();
+ }
+ return type;
+ }
+
+ private static final class PropertyData {
+ public PropertyData(Property property, boolean present) {
+ this.property = property;
+ this.present = present;
+ }
+
+ public final Property property;
+ public final boolean present;
+ }
+
+ private static final class Info extends WeakBase implements XPropertySetInfo
+ {
+ public Info(Map properties) {
+ this.properties = properties;
+ }
+
+ public Property[] getProperties() {
+ ArrayList al = new ArrayList(properties.size());
+ for (Iterator i = properties.values().iterator(); i.hasNext();) {
+ PropertyData p = (PropertyData) i.next();
+ if (p.present) {
+ al.add(p.property);
+ }
+ }
+ return (Property[]) al.toArray(new Property[al.size()]);
+ }
+
+ public Property getPropertyByName(String name)
+ throws UnknownPropertyException
+ {
+ PropertyData p = (PropertyData) properties.get(name);
+ if (p == null || !p.present) {
+ throw new UnknownPropertyException(name, this);
+ }
+ return p.property;
+ }
+
+ public boolean hasPropertyByName(String name) {
+ PropertyData p = (PropertyData) properties.get(name);
+ return p != null && p.present;
+ }
+
+ private final Map properties; // from String to Property
+ }
+
+ private final XComponentContext context;
+ private final XInterface object;
+ private final Type type;
+ private final String[] absentOptional;
+ private final XIdlClass idlClass;
+ private final Map properties; // from String to Property
+ private final String[] handleMap;
+
+ private HashMap boundListeners = new HashMap();
+ // from String to Vector of XPropertyChangeListener
+ private HashMap vetoListeners = new HashMap();
+ // from String to Vector of XVetoableChangeListener
+ private boolean disposed = false;
+}
--
cgit