1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
29 #include <com/sun/star/beans/Property.hpp>
30 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/beans/PropertyVetoException.hpp>
34 #include <com/sun/star/beans/UnknownPropertyException.hpp>
35 #include <com/sun/star/beans/XFastPropertySet.hpp>
36 #include <com/sun/star/beans/XPropertyAccess.hpp>
37 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/beans/XPropertySetInfo.hpp>
40 #include <com/sun/star/beans/XVetoableChangeListener.hpp>
41 #include <com/sun/star/container/NoSuchElementException.hpp>
42 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
43 #include <com/sun/star/lang/DisposedException.hpp>
44 #include <com/sun/star/lang/EventObject.hpp>
45 #include <com/sun/star/lang/IllegalAccessException.hpp>
46 #include <com/sun/star/lang/IllegalArgumentException.hpp>
47 #include <com/sun/star/lang/WrappedTargetException.hpp>
48 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
49 #include <com/sun/star/reflection/XCompoundTypeDescription.hpp>
50 #include <com/sun/star/reflection/XIdlClass.hpp>
51 #include <com/sun/star/reflection/XIdlField2.hpp>
52 #include <com/sun/star/reflection/XIndirectTypeDescription.hpp>
53 #include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp>
54 #include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
55 #include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp>
56 #include <com/sun/star/reflection/XStructTypeDescription.hpp>
57 #include <com/sun/star/reflection/XTypeDescription.hpp>
58 #include <com/sun/star/reflection/theCoreReflection.hpp>
59 #include <com/sun/star/uno/Any.hxx>
60 #include <com/sun/star/uno/DeploymentException.hpp>
61 #include <com/sun/star/uno/Exception.hpp>
62 #include <com/sun/star/uno/Reference.hxx>
63 #include <com/sun/star/uno/RuntimeException.hpp>
64 #include <com/sun/star/uno/Sequence.hxx>
65 #include <com/sun/star/uno/Type.hxx>
66 #include <com/sun/star/uno/TypeClass.hpp>
67 #include <com/sun/star/uno/XComponentContext.hpp>
68 #include <com/sun/star/uno/XInterface.hpp>
69 #include <cppuhelper/implbase1.hxx>
70 #include <cppuhelper/propertysetmixin.hxx>
71 #include <cppuhelper/weak.hxx>
72 #include <osl/mutex.hxx>
73 #include <rtl/ref.hxx>
74 #include <rtl/ustring.hxx>
75 #include <sal/types.h>
76 #include <salhelper/simplereferenceobject.hxx>
78 using cppu::PropertySetMixinImpl
;
83 explicit PropertyData(
84 css::beans::Property
const & theProperty
, bool thePresent
):
85 property(theProperty
), present(thePresent
) {}
87 css::beans::Property property
;
91 struct Data
: public salhelper::SimpleReferenceObject
{
92 typedef std::map
< rtl::OUString
, PropertyData
> PropertyMap
;
94 PropertyMap properties
;
96 PropertyMap::const_iterator
get(
97 css::uno::Reference
< css::uno::XInterface
> const & object
,
98 rtl::OUString
const & name
) const;
102 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
,
103 css::uno::Sequence
< rtl::OUString
> const & absentOptional
,
104 std::vector
< rtl::OUString
> * handleNames
)
107 initProperties(type
, absentOptional
, handleNames
, &seen
);
111 typedef std::set
< rtl::OUString
> TypeSet
;
114 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
,
115 css::uno::Sequence
< rtl::OUString
> const & absentOptional
,
116 std::vector
< rtl::OUString
> * handleNames
, TypeSet
* seen
);
118 static css::uno::Reference
< css::reflection::XTypeDescription
>
120 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
);
123 Data::PropertyMap::const_iterator
Data::get(
124 css::uno::Reference
< css::uno::XInterface
> const & object
,
125 rtl::OUString
const & name
) const
127 PropertyMap::const_iterator
i(properties
.find(name
));
128 if (i
== properties
.end() || !i
->second
.present
) {
129 throw css::beans::UnknownPropertyException(name
, object
);
134 void Data::initProperties(
135 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
,
136 css::uno::Sequence
< rtl::OUString
> const & absentOptional
,
137 std::vector
< rtl::OUString
> * handleNames
, TypeSet
* seen
)
139 css::uno::Reference
< css::reflection::XInterfaceTypeDescription2
> ifc(
140 resolveTypedefs(type
), css::uno::UNO_QUERY_THROW
);
141 if (seen
->insert(ifc
->getName()).second
) {
143 css::uno::Reference
< css::reflection::XTypeDescription
> > bases(
144 ifc
->getBaseTypes());
145 for (sal_Int32 i
= 0; i
< bases
.getLength(); ++i
) {
146 initProperties(bases
[i
], absentOptional
, handleNames
, seen
);
150 css::reflection::XInterfaceMemberTypeDescription
> > members(
152 rtl::OUString
const * absentBegin
= absentOptional
.getConstArray();
153 rtl::OUString
const * absentEnd
=
154 absentBegin
+ absentOptional
.getLength();
155 for (sal_Int32 i
= 0; i
< members
.getLength(); ++i
) {
156 if (members
[i
]->getTypeClass()
157 == css::uno::TypeClass_INTERFACE_ATTRIBUTE
)
160 css::reflection::XInterfaceAttributeTypeDescription2
> attr(
161 members
[i
], css::uno::UNO_QUERY_THROW
);
162 sal_Int16 attrAttribs
= 0;
163 if (attr
->isBound()) {
164 attrAttribs
|= css::beans::PropertyAttribute::BOUND
;
166 bool bSetUnknown
= false;
167 if (attr
->isReadOnly()) {
168 attrAttribs
|= css::beans::PropertyAttribute::READONLY
;
173 css::reflection::XCompoundTypeDescription
> > excs(
174 attr
->getGetExceptions());
175 bool bGetUnknown
= false;
176 //XXX Special interpretation of getter/setter exceptions only
177 // works if the specified exceptions are of the exact type, not
179 for (sal_Int32 j
= 0; j
< excs
.getLength(); ++j
) {
180 if ( excs
[j
]->getName() == "com.sun.star.beans.UnknownPropertyException" )
186 excs
= attr
->getSetExceptions();
187 for (sal_Int32 j
= 0; j
< excs
.getLength(); ++j
) {
188 if ( excs
[j
]->getName() == "com.sun.star.beans.UnknownPropertyException" )
191 } else if ( excs
[j
]->getName() == "com.sun.star.beans.PropertyVetoException" )
194 |= css::beans::PropertyAttribute::CONSTRAINED
;
197 if (bGetUnknown
&& bSetUnknown
) {
198 attrAttribs
|= css::beans::PropertyAttribute::OPTIONAL
;
200 css::uno::Reference
< css::reflection::XTypeDescription
> t(
204 t
= resolveTypedefs(t
);
206 if (t
->getName().startsWith(
207 "com.sun.star.beans.Ambiguous<"))
209 n
= css::beans::PropertyAttribute::MAYBEAMBIGUOUS
;
210 } else if (t
->getName().startsWith(
211 "com.sun.star.beans.Defaulted<"))
213 n
= css::beans::PropertyAttribute::MAYBEDEFAULT
;
214 } else if (t
->getName().startsWith(
215 "com.sun.star.beans.Optional<"))
217 n
= css::beans::PropertyAttribute::MAYBEVOID
;
221 if ((attrAttribs
& n
) != 0) {
226 css::uno::Reference
< css::reflection::XTypeDescription
> >
229 css::reflection::XStructTypeDescription
>(
230 t
, css::uno::UNO_QUERY_THROW
)->
232 if (args
.getLength() != 1) {
233 throw css::uno::RuntimeException(
234 "inconsistent UNO type registry");
238 std::vector
< rtl::OUString
>::size_type handles
239 = handleNames
->size();
240 if (handles
> SAL_MAX_INT32
) {
241 throw css::uno::RuntimeException(
242 "interface type has too many attributes");
244 rtl::OUString
name(members
[i
]->getMemberName());
245 if (!properties
.insert(
246 PropertyMap::value_type(
249 css::beans::Property(
250 name
, static_cast< sal_Int32
>(handles
),
252 t
->getTypeClass(), t
->getName()),
254 (std::find(absentBegin
, absentEnd
, name
)
258 throw css::uno::RuntimeException(
259 "inconsistent UNO type registry");
261 handleNames
->push_back(name
);
267 css::uno::Reference
< css::reflection::XTypeDescription
> Data::resolveTypedefs(
268 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
)
270 css::uno::Reference
< css::reflection::XTypeDescription
> t(type
);
271 while (t
->getTypeClass() == css::uno::TypeClass_TYPEDEF
) {
272 t
= css::uno::Reference
< css::reflection::XIndirectTypeDescription
>(
273 t
, css::uno::UNO_QUERY_THROW
)->getReferencedType();
278 class Info
: public cppu::WeakImplHelper1
< css::beans::XPropertySetInfo
> {
280 explicit Info(Data
* data
): m_data(data
) {}
282 virtual css::uno::Sequence
< css::beans::Property
> SAL_CALL
getProperties()
283 throw (css::uno::RuntimeException
, std::exception
) override
;
285 virtual css::beans::Property SAL_CALL
getPropertyByName(
286 rtl::OUString
const & name
)
288 css::beans::UnknownPropertyException
, css::uno::RuntimeException
, std::exception
) override
;
290 virtual sal_Bool SAL_CALL
hasPropertyByName(rtl::OUString
const & name
)
291 throw (css::uno::RuntimeException
, std::exception
) override
;
294 rtl::Reference
< Data
> m_data
;
297 css::uno::Sequence
< css::beans::Property
> Info::getProperties()
298 throw (css::uno::RuntimeException
, std::exception
)
300 assert(m_data
->properties
.size() <= SAL_MAX_INT32
);
301 css::uno::Sequence
< css::beans::Property
> s(
302 static_cast< sal_Int32
>(m_data
->properties
.size()));
304 for (Data::PropertyMap::iterator
i(m_data
->properties
.begin());
305 i
!= m_data
->properties
.end(); ++i
)
307 if (i
->second
.present
) {
308 s
[n
++] = i
->second
.property
;
315 css::beans::Property
Info::getPropertyByName(rtl::OUString
const & name
)
316 throw (css::beans::UnknownPropertyException
, css::uno::RuntimeException
, std::exception
)
318 return m_data
->get(static_cast< cppu::OWeakObject
* >(this), name
)->
322 sal_Bool
Info::hasPropertyByName(rtl::OUString
const & name
)
323 throw (css::uno::RuntimeException
, std::exception
)
325 Data::PropertyMap::iterator
i(m_data
->properties
.find(name
));
326 return i
!= m_data
->properties
.end() && i
->second
.present
;
330 std::multiset
< css::uno::Reference
< css::beans::XPropertyChangeListener
> >
335 class PropertySetMixinImpl::BoundListeners::Impl
{
337 BoundListenerBag specificListeners
;
338 BoundListenerBag unspecificListeners
;
339 css::beans::PropertyChangeEvent event
;
342 PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl
) {}
344 PropertySetMixinImpl::BoundListeners::~BoundListeners() {
348 void PropertySetMixinImpl::BoundListeners::notify() const {
349 for (BoundListenerBag::const_iterator
i(m_impl
->specificListeners
.begin());
350 i
!= m_impl
->specificListeners
.end(); ++i
)
353 (*i
)->propertyChange(m_impl
->event
);
354 } catch (css::lang::DisposedException
&) {}
356 for (BoundListenerBag::const_iterator
i(
357 m_impl
->unspecificListeners
.begin());
358 i
!= m_impl
->unspecificListeners
.end(); ++i
)
361 (*i
)->propertyChange(m_impl
->event
);
362 } catch (css::lang::DisposedException
&) {}
366 class PropertySetMixinImpl::Impl
: public Data
{
369 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
370 Implements theImplements
,
371 css::uno::Sequence
< rtl::OUString
> const & absentOptional
,
372 css::uno::Type
const & type
);
374 rtl::OUString
translateHandle(
375 css::uno::Reference
< css::uno::XInterface
> const & object
,
376 sal_Int32 handle
) const;
379 css::uno::Reference
< css::uno::XInterface
> const & object
,
380 rtl::OUString
const & name
, css::uno::Any
const & value
,
381 bool isAmbiguous
, bool isDefaulted
, sal_Int16 illegalArgumentPosition
)
384 css::uno::Any
getProperty(
385 css::uno::Reference
< css::uno::XInterface
> const & object
,
386 rtl::OUString
const & name
, css::beans::PropertyState
* state
) const;
388 PropertySetMixinImpl::Implements implements
;
389 css::uno::Sequence
< rtl::OUString
> handleMap
;
391 typedef std::map
< rtl::OUString
, BoundListenerBag
> BoundListenerMap
;
394 std::multiset
< css::uno::Reference
< css::beans::XVetoableChangeListener
> >
397 typedef std::map
< rtl::OUString
, VetoListenerBag
> VetoListenerMap
;
399 mutable osl::Mutex mutex
;
400 BoundListenerMap boundListeners
;
401 VetoListenerMap vetoListeners
;
405 css::uno::Reference
< css::reflection::XIdlClass
> getReflection(
406 rtl::OUString
const & typeName
) const;
408 static css::uno::Any
wrapValue(
409 css::uno::Reference
< css::uno::XInterface
> const & object
,
410 css::uno::Any
const & value
,
411 css::uno::Reference
< css::reflection::XIdlClass
> const & type
,
412 bool wrapAmbiguous
, bool isAmbiguous
, bool wrapDefaulted
,
413 bool isDefaulted
, bool wrapOptional
);
415 css::uno::Reference
< css::uno::XComponentContext
> const & m_context
;
416 css::uno::Sequence
< rtl::OUString
> m_absentOptional
;
417 css::uno::Type m_type
;
418 css::uno::Reference
< css::reflection::XIdlClass
> m_idlClass
;
421 PropertySetMixinImpl::Impl::Impl(
422 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
423 Implements theImplements
,
424 css::uno::Sequence
< rtl::OUString
> const & absentOptional
,
425 css::uno::Type
const & type
):
426 implements(theImplements
), disposed(false), m_context(context
),
427 m_absentOptional(absentOptional
), m_type(type
)
429 assert(context
.is());
432 & ~(IMPLEMENTS_PROPERTY_SET
| IMPLEMENTS_FAST_PROPERTY_SET
433 | IMPLEMENTS_PROPERTY_ACCESS
))
435 m_idlClass
= getReflection(m_type
.getTypeName());
436 css::uno::Reference
< css::reflection::XTypeDescription
> ifc
;
439 css::uno::Reference
< css::container::XHierarchicalNameAccess
>(
440 m_context
->getValueByName(
441 "/singletons/com.sun.star.reflection."
442 "theTypeDescriptionManager"),
443 css::uno::UNO_QUERY_THROW
)->getByHierarchicalName(
444 m_type
.getTypeName()),
445 css::uno::UNO_QUERY_THROW
);
446 } catch (css::container::NoSuchElementException
& e
) {
447 throw css::uno::RuntimeException(
448 "unexpected com.sun.star.container.NoSuchElementException: "
451 std::vector
< rtl::OUString
> handleNames
;
452 initProperties(ifc
, m_absentOptional
, &handleNames
);
453 std::vector
< rtl::OUString
>::size_type size
= handleNames
.size();
454 assert(size
<= SAL_MAX_INT32
);
455 handleMap
.realloc(static_cast< sal_Int32
>(size
));
456 std::copy(handleNames
.begin(), handleNames
.end(), handleMap
.getArray());
459 rtl::OUString
PropertySetMixinImpl::Impl::translateHandle(
460 css::uno::Reference
< css::uno::XInterface
> const & object
,
461 sal_Int32 handle
) const
463 if (handle
< 0 || handle
>= handleMap
.getLength()) {
464 throw css::beans::UnknownPropertyException(
465 "bad handle " + rtl::OUString::number(handle
), object
);
467 return handleMap
[handle
];
470 void PropertySetMixinImpl::Impl::setProperty(
471 css::uno::Reference
< css::uno::XInterface
> const & object
,
472 rtl::OUString
const & name
, css::uno::Any
const & value
, bool isAmbiguous
,
473 bool isDefaulted
, sal_Int16 illegalArgumentPosition
) const
475 PropertyMap::const_iterator
i(properties
.find(name
));
476 if (i
== properties
.end()) {
477 throw css::beans::UnknownPropertyException(name
, object
);
480 && ((i
->second
.property
.Attributes
481 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
484 && ((i
->second
.property
.Attributes
485 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
488 throw css::lang::IllegalArgumentException(
489 ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
491 object
, illegalArgumentPosition
);
493 css::uno::Reference
< css::reflection::XIdlField2
> f(
494 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
);
495 css::uno::Any
o(object
->queryInterface(m_type
));
499 (css::uno::Reference
< css::reflection::XIdlField2
>(
500 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
)->
502 ((i
->second
.property
.Attributes
503 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
506 ((i
->second
.property
.Attributes
507 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
510 ((i
->second
.property
.Attributes
511 & css::beans::PropertyAttribute::MAYBEVOID
)
515 } catch (css::lang::IllegalArgumentException
& e
) {
516 if (e
.ArgumentPosition
== 1) {
517 throw css::lang::IllegalArgumentException(
518 e
.Message
, object
, illegalArgumentPosition
);
520 throw css::uno::RuntimeException(
521 ("unexpected com.sun.star.lang.IllegalArgumentException: "
525 } catch (css::lang::IllegalAccessException
&) {
526 //TODO Clarify whether PropertyVetoException is the correct exception
527 // to throw when trying to set a read-only property:
528 throw css::beans::PropertyVetoException(
529 "cannot set read-only property " + name
, object
);
530 } catch (css::lang::WrappedTargetRuntimeException
& e
) {
531 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
532 // guaranteed to originate directly within XIdlField2.get (and thus have
533 // the expected semantics); it might also be passed through from lower
535 if (e
.TargetException
.isExtractableTo(
536 cppu::UnoType
<css::beans::UnknownPropertyException
>::get())
537 && ((i
->second
.property
.Attributes
538 & css::beans::PropertyAttribute::OPTIONAL
)
541 throw css::beans::UnknownPropertyException(name
, object
);
542 } else if (e
.TargetException
.isExtractableTo(
543 cppu::UnoType
<css::beans::PropertyVetoException
>::get())
544 && ((i
->second
.property
.Attributes
545 & css::beans::PropertyAttribute::CONSTRAINED
)
548 css::beans::PropertyVetoException exc
;
549 e
.TargetException
>>= exc
;
550 if (exc
.Message
.isEmpty() )
551 throw css::beans::PropertyVetoException("Invalid " + name
, object
);
555 throw css::lang::WrappedTargetException(
556 e
.Message
, object
, e
.TargetException
);
561 css::uno::Any
PropertySetMixinImpl::Impl::getProperty(
562 css::uno::Reference
< css::uno::XInterface
> const & object
,
563 rtl::OUString
const & name
, css::beans::PropertyState
* state
) const
565 PropertyMap::const_iterator
i(properties
.find(name
));
566 if (i
== properties
.end()) {
567 throw css::beans::UnknownPropertyException(name
, object
);
569 css::uno::Reference
< css::reflection::XIdlField2
> field(
570 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
);
573 value
= field
->get(object
->queryInterface(m_type
));
574 } catch (css::lang::IllegalArgumentException
& e
) {
575 throw css::uno::RuntimeException(
576 ("unexpected com.sun.star.lang.IllegalArgumentException: "
579 } catch (css::lang::WrappedTargetRuntimeException
& e
) {
580 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
581 // guaranteed to originate directly within XIdlField2.get (and thus have
582 // the expected semantics); it might also be passed through from lower
584 if (e
.TargetException
.isExtractableTo(
585 cppu::UnoType
<css::beans::UnknownPropertyException
>::get())
586 && ((i
->second
.property
.Attributes
587 & css::beans::PropertyAttribute::OPTIONAL
)
590 throw css::beans::UnknownPropertyException(name
, object
);
592 throw css::lang::WrappedTargetException(
593 e
.Message
, object
, e
.TargetException
);
597 = ((i
->second
.property
.Attributes
598 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
601 = ((i
->second
.property
.Attributes
602 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
605 = ((i
->second
.property
.Attributes
606 & css::beans::PropertyAttribute::MAYBEVOID
)
608 bool isAmbiguous
= false;
609 bool isDefaulted
= false;
610 while (undoAmbiguous
|| undoDefaulted
|| undoOptional
) {
612 && value
.getValueTypeName().startsWith(
613 "com.sun.star.beans.Ambiguous<"))
615 css::uno::Reference
< css::reflection::XIdlClass
> ambiguous(
616 getReflection(value
.getValueTypeName()));
618 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
619 ambiguous
->getField("IsAmbiguous"),
620 css::uno::UNO_QUERY_THROW
)->get(value
)
623 throw css::uno::RuntimeException(
624 ("unexpected type of com.sun.star.beans.Ambiguous"
625 " IsAmbiguous member"),
628 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
629 ambiguous
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
631 } catch (css::lang::IllegalArgumentException
& e
) {
632 throw css::uno::RuntimeException(
633 ("unexpected com.sun.star.lang.IllegalArgumentException: "
637 undoAmbiguous
= false;
638 } else if (undoDefaulted
639 && value
.getValueTypeName().startsWith(
640 "com.sun.star.beans.Defaulted<"))
642 css::uno::Reference
< css::reflection::XIdlClass
> defaulted(
643 getReflection(value
.getValueTypeName()));
646 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
647 defaulted
->getField("IsDefaulted"),
648 css::uno::UNO_QUERY_THROW
)->get(value
)
651 throw css::uno::RuntimeException(
652 ("unexpected type of com.sun.star.beans.Defaulted"
653 " IsDefaulted member"),
656 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
657 defaulted
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
659 } catch (css::lang::IllegalArgumentException
& e
) {
660 throw css::uno::RuntimeException(
661 ("unexpected com.sun.star.lang.IllegalArgumentException: "
665 undoDefaulted
= false;
666 } else if (undoOptional
667 && value
.getValueTypeName().startsWith(
668 "com.sun.star.beans.Optional<"))
670 css::uno::Reference
< css::reflection::XIdlClass
> optional(
671 getReflection(value
.getValueTypeName()));
673 bool present
= false;
674 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
675 optional
->getField("IsPresent"),
676 css::uno::UNO_QUERY_THROW
)->get(value
)
679 throw css::uno::RuntimeException(
680 ("unexpected type of com.sun.star.beans.Optional"
681 " IsPresent member"),
688 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
689 optional
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
691 } catch (css::lang::IllegalArgumentException
& e
) {
692 throw css::uno::RuntimeException(
693 ("unexpected com.sun.star.lang.IllegalArgumentException: "
697 undoOptional
= false;
699 throw css::uno::RuntimeException(
700 "unexpected type of attribute " + name
, object
);
703 if (state
!= nullptr) {
704 //XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE
705 // over DEFAULT_VALUE:
707 ? css::beans::PropertyState_AMBIGUOUS_VALUE
709 ? css::beans::PropertyState_DEFAULT_VALUE
710 : css::beans::PropertyState_DIRECT_VALUE
;
715 css::uno::Reference
< css::reflection::XIdlClass
>
716 PropertySetMixinImpl::Impl::getReflection(rtl::OUString
const & typeName
) const
718 return css::uno::Reference
< css::reflection::XIdlClass
>(
719 css::reflection::theCoreReflection::get(m_context
)->forName(typeName
),
720 css::uno::UNO_SET_THROW
);
723 css::uno::Any
PropertySetMixinImpl::Impl::wrapValue(
724 css::uno::Reference
< css::uno::XInterface
> const & object
,
725 css::uno::Any
const & value
,
726 css::uno::Reference
< css::reflection::XIdlClass
> const & type
,
727 bool wrapAmbiguous
, bool isAmbiguous
, bool wrapDefaulted
, bool isDefaulted
,
730 assert(wrapAmbiguous
|| !isAmbiguous
);
731 assert(wrapDefaulted
|| !isDefaulted
);
733 && type
->getName().startsWith("com.sun.star.beans.Ambiguous<"))
736 type
->createObject(strct
);
738 css::uno::Reference
< css::reflection::XIdlField2
> field(
739 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
743 object
, value
, field
->getType(), false, false,
744 wrapDefaulted
, isDefaulted
, wrapOptional
));
745 css::uno::Reference
< css::reflection::XIdlField2
>(
746 type
->getField("IsAmbiguous"), css::uno::UNO_QUERY_THROW
)->set(
747 strct
, css::uno::makeAny(isAmbiguous
));
748 } catch (css::lang::IllegalArgumentException
& e
) {
749 throw css::uno::RuntimeException(
750 ("unexpected com.sun.star.lang.IllegalArgumentException: "
753 } catch (css::lang::IllegalAccessException
& e
) {
754 throw css::uno::RuntimeException(
755 ("unexpected com.sun.star.lang.IllegalAccessException: "
760 } else if (wrapDefaulted
761 && type
->getName().startsWith("com.sun.star.beans.Defaulted<"))
764 type
->createObject(strct
);
766 css::uno::Reference
< css::reflection::XIdlField2
> field(
767 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
771 object
, value
, field
->getType(), wrapAmbiguous
, isAmbiguous
,
772 false, false, wrapOptional
));
773 css::uno::Reference
< css::reflection::XIdlField2
>(
774 type
->getField("IsDefaulted"), css::uno::UNO_QUERY_THROW
)->set(
775 strct
, css::uno::makeAny(isDefaulted
));
776 } catch (css::lang::IllegalArgumentException
& e
) {
777 throw css::uno::RuntimeException(
778 ("unexpected com.sun.star.lang.IllegalArgumentException: "
781 } catch (css::lang::IllegalAccessException
& e
) {
782 throw css::uno::RuntimeException(
783 ("unexpected com.sun.star.lang.IllegalAccessException: "
788 } else if (wrapOptional
789 && type
->getName().startsWith("com.sun.star.beans.Optional<"))
792 type
->createObject(strct
);
793 bool present
= value
.hasValue();
795 css::uno::Reference
< css::reflection::XIdlField2
>(
796 type
->getField("IsPresent"), css::uno::UNO_QUERY_THROW
)->set(
797 strct
, css::uno::makeAny(present
));
799 css::uno::Reference
< css::reflection::XIdlField2
> field(
800 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
804 object
, value
, field
->getType(), wrapAmbiguous
,
805 isAmbiguous
, wrapDefaulted
, isDefaulted
, false));
807 } catch (css::lang::IllegalArgumentException
& e
) {
808 throw css::uno::RuntimeException(
809 ("unexpected com.sun.star.lang.IllegalArgumentException: "
812 } catch (css::lang::IllegalAccessException
& e
) {
813 throw css::uno::RuntimeException(
814 ("unexpected com.sun.star.lang.IllegalAccessException: "
820 if (wrapAmbiguous
|| wrapDefaulted
|| wrapOptional
) {
821 throw css::uno::RuntimeException(
822 "unexpected type of attribute", object
);
828 PropertySetMixinImpl::PropertySetMixinImpl(
829 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
830 Implements implements
,
831 css::uno::Sequence
< rtl::OUString
> const & absentOptional
,
832 css::uno::Type
const & type
)
834 m_impl
= new Impl(context
, implements
, absentOptional
, type
);
838 PropertySetMixinImpl::~PropertySetMixinImpl() {
842 void PropertySetMixinImpl::checkUnknown(rtl::OUString
const & propertyName
) {
843 if (!propertyName
.isEmpty()) {
845 static_cast< css::beans::XPropertySet
* >(this), propertyName
);
849 void PropertySetMixinImpl::prepareSet(
850 rtl::OUString
const & propertyName
, css::uno::Any
const & oldValue
,
851 css::uno::Any
const & newValue
, BoundListeners
* boundListeners
)
853 Impl::PropertyMap::const_iterator
it(m_impl
->properties
.find(propertyName
));
854 assert(it
!= m_impl
->properties
.end());
855 Impl::VetoListenerBag specificVeto
;
856 Impl::VetoListenerBag unspecificVeto
;
858 osl::MutexGuard
g(m_impl
->mutex
);
859 if (m_impl
->disposed
) {
860 throw css::lang::DisposedException(
861 "disposed", static_cast< css::beans::XPropertySet
* >(this));
863 if ((it
->second
.property
.Attributes
864 & css::beans::PropertyAttribute::CONSTRAINED
)
867 Impl::VetoListenerMap::const_iterator
i(
868 m_impl
->vetoListeners
.find(propertyName
));
869 if (i
!= m_impl
->vetoListeners
.end()) {
870 specificVeto
= i
->second
;
872 i
= m_impl
->vetoListeners
.find("");
873 if (i
!= m_impl
->vetoListeners
.end()) {
874 unspecificVeto
= i
->second
;
877 if ((it
->second
.property
.Attributes
878 & css::beans::PropertyAttribute::BOUND
)
881 assert(boundListeners
!= nullptr);
882 Impl::BoundListenerMap::const_iterator
i(
883 m_impl
->boundListeners
.find(propertyName
));
884 if (i
!= m_impl
->boundListeners
.end()) {
885 boundListeners
->m_impl
->specificListeners
= i
->second
;
887 i
= m_impl
->boundListeners
.find("");
888 if (i
!= m_impl
->boundListeners
.end()) {
889 boundListeners
->m_impl
->unspecificListeners
= i
->second
;
893 if ((it
->second
.property
.Attributes
894 & css::beans::PropertyAttribute::CONSTRAINED
)
897 css::beans::PropertyChangeEvent
event(
898 static_cast< css::beans::XPropertySet
* >(this), propertyName
,
899 false, it
->second
.property
.Handle
, oldValue
, newValue
);
900 for (Impl::VetoListenerBag::iterator
i(specificVeto
.begin());
901 i
!= specificVeto
.end(); ++i
)
904 (*i
)->vetoableChange(event
);
905 } catch (css::lang::DisposedException
&) {}
907 for (Impl::VetoListenerBag::iterator
i(unspecificVeto
.begin());
908 i
!= unspecificVeto
.end(); ++i
)
911 (*i
)->vetoableChange(event
);
912 } catch (css::lang::DisposedException
&) {}
915 if ((it
->second
.property
.Attributes
& css::beans::PropertyAttribute::BOUND
)
918 assert(boundListeners
!= nullptr);
919 boundListeners
->m_impl
->event
= css::beans::PropertyChangeEvent(
920 static_cast< css::beans::XPropertySet
* >(this), propertyName
,
921 false, it
->second
.property
.Handle
, oldValue
, newValue
);
925 void PropertySetMixinImpl::dispose() {
926 Impl::BoundListenerMap boundListeners
;
927 Impl::VetoListenerMap vetoListeners
;
929 osl::MutexGuard
g(m_impl
->mutex
);
930 boundListeners
.swap(m_impl
->boundListeners
);
931 vetoListeners
.swap(m_impl
->vetoListeners
);
932 m_impl
->disposed
= true;
934 css::lang::EventObject
event(
935 static_cast< css::beans::XPropertySet
* >(this));
936 for (Impl::BoundListenerMap::iterator
i(boundListeners
.begin());
937 i
!= boundListeners
.end(); ++i
)
939 for (BoundListenerBag::iterator
j(i
->second
.begin());
940 j
!= i
->second
.end(); ++j
)
942 (*j
)->disposing(event
);
945 for (Impl::VetoListenerMap::iterator
i(vetoListeners
.begin());
946 i
!= vetoListeners
.end(); ++i
)
948 for (Impl::VetoListenerBag::iterator
j(i
->second
.begin());
949 j
!= i
->second
.end(); ++j
)
951 (*j
)->disposing(event
);
956 css::uno::Any
PropertySetMixinImpl::queryInterface(css::uno::Type
const & type
)
957 throw (css::uno::RuntimeException
, std::exception
)
959 if (((m_impl
->implements
& IMPLEMENTS_PROPERTY_SET
) != 0
960 && type
== css::beans::XPropertySet::static_type()))
962 css::uno::Reference
< css::uno::XInterface
> ifc(
963 static_cast< css::beans::XPropertySet
* >(this));
964 return css::uno::Any(&ifc
, type
);
965 } else if ((m_impl
->implements
& IMPLEMENTS_FAST_PROPERTY_SET
) != 0
966 && type
== css::beans::XFastPropertySet::static_type())
968 css::uno::Reference
< css::uno::XInterface
> ifc(
969 static_cast< css::beans::XFastPropertySet
* >(this));
970 return css::uno::Any(&ifc
, type
);
971 } else if ((m_impl
->implements
& IMPLEMENTS_PROPERTY_ACCESS
) != 0
972 && type
== css::beans::XPropertyAccess::static_type())
974 css::uno::Reference
< css::uno::XInterface
> ifc(
975 static_cast< css::beans::XPropertyAccess
* >(this));
976 return css::uno::Any(&ifc
, type
);
978 return css::uno::Any();
982 css::uno::Reference
< css::beans::XPropertySetInfo
>
983 PropertySetMixinImpl::getPropertySetInfo()
984 throw (css::uno::RuntimeException
, std::exception
)
986 return new Info(m_impl
);
989 void PropertySetMixinImpl::setPropertyValue(
990 rtl::OUString
const & propertyName
, css::uno::Any
const & value
)
992 css::beans::UnknownPropertyException
, css::beans::PropertyVetoException
,
993 css::lang::IllegalArgumentException
, css::lang::WrappedTargetException
,
994 css::uno::RuntimeException
, std::exception
)
997 static_cast< css::beans::XPropertySet
* >(this), propertyName
, value
,
1001 css::uno::Any
PropertySetMixinImpl::getPropertyValue(
1002 rtl::OUString
const & propertyName
)
1004 css::beans::UnknownPropertyException
, css::lang::WrappedTargetException
,
1005 css::uno::RuntimeException
, std::exception
)
1007 return m_impl
->getProperty(
1008 static_cast< css::beans::XPropertySet
* >(this), propertyName
, nullptr);
1011 void PropertySetMixinImpl::addPropertyChangeListener(
1012 rtl::OUString
const & propertyName
,
1013 css::uno::Reference
< css::beans::XPropertyChangeListener
> const & listener
)
1015 css::beans::UnknownPropertyException
, css::lang::WrappedTargetException
,
1016 css::uno::RuntimeException
, std::exception
)
1018 css::uno::Reference
< css::beans::XPropertyChangeListener
>(
1019 listener
, css::uno::UNO_SET_THROW
); // reject NULL listener
1020 checkUnknown(propertyName
);
1023 osl::MutexGuard
g(m_impl
->mutex
);
1024 disposed
= m_impl
->disposed
;
1026 m_impl
->boundListeners
[propertyName
].insert(listener
);
1030 listener
->disposing(
1031 css::lang::EventObject(
1032 static_cast< css::beans::XPropertySet
* >(this)));
1036 void PropertySetMixinImpl::removePropertyChangeListener(
1037 rtl::OUString
const & propertyName
,
1038 css::uno::Reference
< css::beans::XPropertyChangeListener
> const & listener
)
1040 css::beans::UnknownPropertyException
, css::lang::WrappedTargetException
,
1041 css::uno::RuntimeException
, std::exception
)
1043 assert(listener
.is());
1044 checkUnknown(propertyName
);
1045 osl::MutexGuard
g(m_impl
->mutex
);
1046 Impl::BoundListenerMap::iterator
i(
1047 m_impl
->boundListeners
.find(propertyName
));
1048 if (i
!= m_impl
->boundListeners
.end()) {
1049 BoundListenerBag::iterator
j(i
->second
.find(listener
));
1050 if (j
!= i
->second
.end()) {
1056 void PropertySetMixinImpl::addVetoableChangeListener(
1057 rtl::OUString
const & propertyName
,
1058 css::uno::Reference
< css::beans::XVetoableChangeListener
> const & listener
)
1060 css::beans::UnknownPropertyException
, css::lang::WrappedTargetException
,
1061 css::uno::RuntimeException
, std::exception
)
1063 css::uno::Reference
< css::beans::XVetoableChangeListener
>(
1064 listener
, css::uno::UNO_SET_THROW
); // reject NULL listener
1065 checkUnknown(propertyName
);
1068 osl::MutexGuard
g(m_impl
->mutex
);
1069 disposed
= m_impl
->disposed
;
1071 m_impl
->vetoListeners
[propertyName
].insert(listener
);
1075 listener
->disposing(
1076 css::lang::EventObject(
1077 static_cast< css::beans::XPropertySet
* >(this)));
1081 void PropertySetMixinImpl::removeVetoableChangeListener(
1082 rtl::OUString
const & propertyName
,
1083 css::uno::Reference
< css::beans::XVetoableChangeListener
> const & listener
)
1085 css::beans::UnknownPropertyException
, css::lang::WrappedTargetException
,
1086 css::uno::RuntimeException
, std::exception
)
1088 assert(listener
.is());
1089 checkUnknown(propertyName
);
1090 osl::MutexGuard
g(m_impl
->mutex
);
1091 Impl::VetoListenerMap::iterator
i(m_impl
->vetoListeners
.find(propertyName
));
1092 if (i
!= m_impl
->vetoListeners
.end()) {
1093 Impl::VetoListenerBag::iterator
j(i
->second
.find(listener
));
1094 if (j
!= i
->second
.end()) {
1100 void PropertySetMixinImpl::setFastPropertyValue(
1101 sal_Int32 handle
, css::uno::Any
const & value
)
1103 css::beans::UnknownPropertyException
, css::beans::PropertyVetoException
,
1104 css::lang::IllegalArgumentException
, css::lang::WrappedTargetException
,
1105 css::uno::RuntimeException
, std::exception
)
1107 m_impl
->setProperty(
1108 static_cast< css::beans::XPropertySet
* >(this),
1109 m_impl
->translateHandle(
1110 static_cast< css::beans::XPropertySet
* >(this), handle
),
1111 value
, false, false, 1);
1114 css::uno::Any
PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle
)
1116 css::beans::UnknownPropertyException
, css::lang::WrappedTargetException
,
1117 css::uno::RuntimeException
, std::exception
)
1119 return m_impl
->getProperty(
1120 static_cast< css::beans::XPropertySet
* >(this),
1121 m_impl
->translateHandle(
1122 static_cast< css::beans::XPropertySet
* >(this), handle
),
1126 css::uno::Sequence
< css::beans::PropertyValue
>
1127 PropertySetMixinImpl::getPropertyValues()
1128 throw (css::uno::RuntimeException
, std::exception
)
1130 css::uno::Sequence
< css::beans::PropertyValue
> s(
1131 m_impl
->handleMap
.getLength());
1133 for (sal_Int32 i
= 0; i
< m_impl
->handleMap
.getLength(); ++i
) {
1135 s
[n
].Value
= m_impl
->getProperty(
1136 static_cast< css::beans::XPropertySet
* >(this),
1137 m_impl
->handleMap
[i
], &s
[n
].State
);
1138 } catch (css::beans::UnknownPropertyException
&) {
1140 } catch (css::lang::WrappedTargetException
& e
) {
1141 throw css::lang::WrappedTargetRuntimeException(
1142 e
.Message
, static_cast< css::beans::XPropertySet
* >(this),
1145 s
[n
].Name
= m_impl
->handleMap
[i
];
1153 void PropertySetMixinImpl::setPropertyValues(
1154 css::uno::Sequence
< css::beans::PropertyValue
> const & props
)
1156 css::beans::UnknownPropertyException
, css::beans::PropertyVetoException
,
1157 css::lang::IllegalArgumentException
, css::lang::WrappedTargetException
,
1158 css::uno::RuntimeException
, std::exception
)
1160 for (sal_Int32 i
= 0; i
< props
.getLength(); ++i
) {
1161 if (props
[i
].Handle
!= -1
1163 != m_impl
->translateHandle(
1164 static_cast< css::beans::XPropertySet
* >(this),
1167 throw css::beans::UnknownPropertyException(
1168 ("name " + props
[i
].Name
+ " does not match handle "
1169 + rtl::OUString::number(props
[i
].Handle
)),
1170 static_cast< css::beans::XPropertySet
* >(this));
1172 m_impl
->setProperty(
1173 static_cast< css::beans::XPropertySet
* >(this), props
[i
].Name
,
1175 props
[i
].State
== css::beans::PropertyState_AMBIGUOUS_VALUE
,
1176 props
[i
].State
== css::beans::PropertyState_DEFAULT_VALUE
, 0);
1180 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */