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>
28 #include <com/sun/star/beans/Property.hpp>
29 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
30 #include <com/sun/star/beans/PropertyAttribute.hpp>
31 #include <com/sun/star/beans/PropertyValue.hpp>
32 #include <com/sun/star/beans/PropertyVetoException.hpp>
33 #include <com/sun/star/beans/UnknownPropertyException.hpp>
34 #include <com/sun/star/beans/XFastPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertyAccess.hpp>
36 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/beans/XPropertySetInfo.hpp>
39 #include <com/sun/star/beans/XVetoableChangeListener.hpp>
40 #include <com/sun/star/container/NoSuchElementException.hpp>
41 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
42 #include <com/sun/star/lang/DisposedException.hpp>
43 #include <com/sun/star/lang/EventObject.hpp>
44 #include <com/sun/star/lang/IllegalAccessException.hpp>
45 #include <com/sun/star/lang/IllegalArgumentException.hpp>
46 #include <com/sun/star/lang/WrappedTargetException.hpp>
47 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
48 #include <com/sun/star/reflection/XCompoundTypeDescription.hpp>
49 #include <com/sun/star/reflection/XIdlClass.hpp>
50 #include <com/sun/star/reflection/XIdlField2.hpp>
51 #include <com/sun/star/reflection/XIndirectTypeDescription.hpp>
52 #include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp>
53 #include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
54 #include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp>
55 #include <com/sun/star/reflection/XStructTypeDescription.hpp>
56 #include <com/sun/star/reflection/XTypeDescription.hpp>
57 #include <com/sun/star/reflection/theCoreReflection.hpp>
58 #include <com/sun/star/uno/Any.hxx>
59 #include <com/sun/star/uno/Reference.hxx>
60 #include <com/sun/star/uno/RuntimeException.hpp>
61 #include <com/sun/star/uno/Sequence.hxx>
62 #include <com/sun/star/uno/Type.hxx>
63 #include <com/sun/star/uno/TypeClass.hpp>
64 #include <com/sun/star/uno/XComponentContext.hpp>
65 #include <com/sun/star/uno/XInterface.hpp>
66 #include <cppuhelper/exc_hlp.hxx>
67 #include <cppuhelper/implbase.hxx>
68 #include <cppuhelper/propertysetmixin.hxx>
69 #include <cppuhelper/weak.hxx>
70 #include <osl/mutex.hxx>
71 #include <rtl/ref.hxx>
72 #include <rtl/ustring.hxx>
73 #include <sal/types.h>
74 #include <salhelper/simplereferenceobject.hxx>
76 using cppu::PropertySetMixinImpl
;
81 explicit PropertyData(
82 css::beans::Property
const & theProperty
, bool thePresent
):
83 property(theProperty
), present(thePresent
) {}
85 css::beans::Property property
;
89 struct Data
: public salhelper::SimpleReferenceObject
{
90 typedef std::map
< OUString
, PropertyData
> PropertyMap
;
92 PropertyMap properties
;
94 PropertyMap::const_iterator
get(
95 css::uno::Reference
< css::uno::XInterface
> const & object
,
96 OUString
const & name
) const;
100 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
,
101 css::uno::Sequence
< OUString
> const & absentOptional
,
102 std::vector
< OUString
> * handleNames
)
104 std::set
<OUString
> seen
;
105 initProperties(type
, absentOptional
, handleNames
, &seen
);
110 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
,
111 css::uno::Sequence
< OUString
> const & absentOptional
,
112 std::vector
< OUString
> * handleNames
, std::set
<OUString
> * seen
);
114 static css::uno::Reference
< css::reflection::XTypeDescription
>
116 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
);
119 Data::PropertyMap::const_iterator
Data::get(
120 css::uno::Reference
< css::uno::XInterface
> const & object
,
121 OUString
const & name
) const
123 PropertyMap::const_iterator
i(properties
.find(name
));
124 if (i
== properties
.end() || !i
->second
.present
) {
125 throw css::beans::UnknownPropertyException(name
, object
);
130 void Data::initProperties(
131 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
,
132 css::uno::Sequence
< OUString
> const & absentOptional
,
133 std::vector
< OUString
> * handleNames
, std::set
<OUString
> * seen
)
135 css::uno::Reference
< css::reflection::XInterfaceTypeDescription2
> ifc(
136 resolveTypedefs(type
), css::uno::UNO_QUERY_THROW
);
137 if (!seen
->insert(ifc
->getName()).second
)
140 const css::uno::Sequence
<
141 css::uno::Reference
< css::reflection::XTypeDescription
> > bases(
142 ifc
->getBaseTypes());
143 for (const auto & i
: bases
) {
144 initProperties(i
, absentOptional
, handleNames
, seen
);
146 const css::uno::Sequence
<
148 css::reflection::XInterfaceMemberTypeDescription
> > members(
150 OUString
const * absentBegin
= absentOptional
.getConstArray();
151 OUString
const * absentEnd
=
152 absentBegin
+ absentOptional
.getLength();
153 for (const auto & m
: members
) {
154 if (m
->getTypeClass()
155 == css::uno::TypeClass_INTERFACE_ATTRIBUTE
)
158 css::reflection::XInterfaceAttributeTypeDescription2
> attr(
159 m
, css::uno::UNO_QUERY_THROW
);
160 sal_Int16 attrAttribs
= 0;
161 if (attr
->isBound()) {
162 attrAttribs
|= css::beans::PropertyAttribute::BOUND
;
164 bool bSetUnknown
= false;
165 if (attr
->isReadOnly()) {
166 attrAttribs
|= css::beans::PropertyAttribute::READONLY
;
171 css::reflection::XCompoundTypeDescription
> > excs(
172 attr
->getGetExceptions());
173 bool bGetUnknown
= false;
174 //XXX Special interpretation of getter/setter exceptions only
175 // works if the specified exceptions are of the exact type, not
177 for (const auto & ex
: std::as_const(excs
)) {
178 if ( ex
->getName() == "com.sun.star.beans.UnknownPropertyException" )
184 excs
= attr
->getSetExceptions();
185 for (const auto & ex
: std::as_const(excs
)) {
186 if ( ex
->getName() == "com.sun.star.beans.UnknownPropertyException" )
189 } else if ( ex
->getName() == "com.sun.star.beans.PropertyVetoException" )
192 |= css::beans::PropertyAttribute::CONSTRAINED
;
195 if (bGetUnknown
&& bSetUnknown
) {
196 attrAttribs
|= css::beans::PropertyAttribute::OPTIONAL
;
198 css::uno::Reference
< css::reflection::XTypeDescription
> t(
202 t
= resolveTypedefs(t
);
204 if (t
->getName().startsWith(
205 "com.sun.star.beans.Ambiguous<"))
207 n
= css::beans::PropertyAttribute::MAYBEAMBIGUOUS
;
208 } else if (t
->getName().startsWith(
209 "com.sun.star.beans.Defaulted<"))
211 n
= css::beans::PropertyAttribute::MAYBEDEFAULT
;
212 } else if (t
->getName().startsWith(
213 "com.sun.star.beans.Optional<"))
215 n
= css::beans::PropertyAttribute::MAYBEVOID
;
219 if ((attrAttribs
& n
) != 0) {
224 css::uno::Reference
< css::reflection::XTypeDescription
> >
227 css::reflection::XStructTypeDescription
>(
228 t
, css::uno::UNO_QUERY_THROW
)->
230 if (args
.getLength() != 1) {
231 throw css::uno::RuntimeException(
232 "inconsistent UNO type registry");
236 std::vector
< OUString
>::size_type handles
237 = handleNames
->size();
238 if (handles
> SAL_MAX_INT32
) {
239 throw css::uno::RuntimeException(
240 "interface type has too many attributes");
242 OUString
name(m
->getMemberName());
243 if (!properties
.emplace(
246 css::beans::Property(
247 name
, static_cast< sal_Int32
>(handles
),
249 t
->getTypeClass(), t
->getName()),
251 (std::find(absentBegin
, absentEnd
, name
)
255 throw css::uno::RuntimeException(
256 "inconsistent UNO type registry");
258 handleNames
->push_back(name
);
263 css::uno::Reference
< css::reflection::XTypeDescription
> Data::resolveTypedefs(
264 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
)
266 css::uno::Reference
< css::reflection::XTypeDescription
> t(type
);
267 while (t
->getTypeClass() == css::uno::TypeClass_TYPEDEF
) {
268 t
= css::uno::Reference
< css::reflection::XIndirectTypeDescription
>(
269 t
, css::uno::UNO_QUERY_THROW
)->getReferencedType();
274 class Info
: public cppu::WeakImplHelper
< css::beans::XPropertySetInfo
> {
276 explicit Info(Data
* data
): m_data(data
) {}
278 virtual css::uno::Sequence
< css::beans::Property
> SAL_CALL
getProperties() override
;
280 virtual css::beans::Property SAL_CALL
getPropertyByName(
281 OUString
const & name
) override
;
283 virtual sal_Bool SAL_CALL
hasPropertyByName(OUString
const & name
) override
;
286 rtl::Reference
< Data
> m_data
;
289 css::uno::Sequence
< css::beans::Property
> Info::getProperties()
291 assert(m_data
->properties
.size() <= SAL_MAX_INT32
);
292 css::uno::Sequence
< css::beans::Property
> s(
293 static_cast< sal_Int32
>(m_data
->properties
.size()));
295 for (const auto& rEntry
: m_data
->properties
)
297 if (rEntry
.second
.present
) {
298 s
[n
++] = rEntry
.second
.property
;
305 css::beans::Property
Info::getPropertyByName(OUString
const & name
)
307 return m_data
->get(static_cast< cppu::OWeakObject
* >(this), name
)->
311 sal_Bool
Info::hasPropertyByName(OUString
const & name
)
313 Data::PropertyMap::iterator
i(m_data
->properties
.find(name
));
314 return i
!= m_data
->properties
.end() && i
->second
.present
;
318 std::multiset
< css::uno::Reference
< css::beans::XPropertyChangeListener
> >
323 class PropertySetMixinImpl::BoundListeners::Impl
{
325 BoundListenerBag specificListeners
;
326 BoundListenerBag unspecificListeners
;
327 css::beans::PropertyChangeEvent event
;
330 PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl
) {}
332 PropertySetMixinImpl::BoundListeners::~BoundListeners() {
336 void PropertySetMixinImpl::BoundListeners::notify() const {
337 for (const auto& rxListener
: m_impl
->specificListeners
)
340 rxListener
->propertyChange(m_impl
->event
);
341 } catch (css::lang::DisposedException
&) {}
343 for (const auto& rxListener
: m_impl
->unspecificListeners
)
346 rxListener
->propertyChange(m_impl
->event
);
347 } catch (css::lang::DisposedException
&) {}
351 class PropertySetMixinImpl::Impl
: public Data
{
354 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
355 Implements theImplements
,
356 css::uno::Sequence
< OUString
> const & absentOptional
,
357 css::uno::Type
const & type
);
359 OUString
const & translateHandle(
360 css::uno::Reference
< css::uno::XInterface
> const & object
,
361 sal_Int32 handle
) const;
364 css::uno::Reference
< css::uno::XInterface
> const & object
,
365 OUString
const & name
, css::uno::Any
const & value
,
366 bool isAmbiguous
, bool isDefaulted
, sal_Int16 illegalArgumentPosition
)
369 css::uno::Any
getProperty(
370 css::uno::Reference
< css::uno::XInterface
> const & object
,
371 OUString
const & name
, css::beans::PropertyState
* state
) const;
373 PropertySetMixinImpl::Implements implements
;
374 css::uno::Sequence
< OUString
> handleMap
;
376 typedef std::map
< OUString
, BoundListenerBag
> BoundListenerMap
;
379 std::multiset
< css::uno::Reference
< css::beans::XVetoableChangeListener
> >
382 typedef std::map
< OUString
, VetoListenerBag
> VetoListenerMap
;
384 mutable osl::Mutex mutex
;
385 BoundListenerMap boundListeners
;
386 VetoListenerMap vetoListeners
;
390 css::uno::Reference
< css::reflection::XIdlClass
> getReflection(
391 OUString
const & typeName
) const;
393 static css::uno::Any
wrapValue(
394 css::uno::Reference
< css::uno::XInterface
> const & object
,
395 css::uno::Any
const & value
,
396 css::uno::Reference
< css::reflection::XIdlClass
> const & type
,
397 bool wrapAmbiguous
, bool isAmbiguous
, bool wrapDefaulted
,
398 bool isDefaulted
, bool wrapOptional
);
400 css::uno::Reference
< css::uno::XComponentContext
> const & m_context
;
401 css::uno::Type m_type
;
402 css::uno::Reference
< css::reflection::XIdlClass
> m_idlClass
;
405 PropertySetMixinImpl::Impl::Impl(
406 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
407 Implements theImplements
,
408 css::uno::Sequence
< OUString
> const & absentOptional
,
409 css::uno::Type
const & type
):
410 implements(theImplements
), disposed(false), m_context(context
),
413 assert(context
.is());
416 & ~(IMPLEMENTS_PROPERTY_SET
| IMPLEMENTS_FAST_PROPERTY_SET
417 | IMPLEMENTS_PROPERTY_ACCESS
))
419 m_idlClass
= getReflection(m_type
.getTypeName());
420 css::uno::Reference
< css::reflection::XTypeDescription
> ifc
;
423 css::uno::Reference
< css::container::XHierarchicalNameAccess
>(
424 m_context
->getValueByName(
425 "/singletons/com.sun.star.reflection."
426 "theTypeDescriptionManager"),
427 css::uno::UNO_QUERY_THROW
)->getByHierarchicalName(
428 m_type
.getTypeName()),
429 css::uno::UNO_QUERY_THROW
);
430 } catch (css::container::NoSuchElementException
& e
) {
431 css::uno::Any anyEx
= cppu::getCaughtException();
432 throw css::lang::WrappedTargetRuntimeException(
433 "unexpected com.sun.star.container.NoSuchElementException: "
437 std::vector
< OUString
> handleNames
;
438 initProperties(ifc
, absentOptional
, &handleNames
);
439 std::vector
< OUString
>::size_type size
= handleNames
.size();
440 assert(size
<= SAL_MAX_INT32
);
441 handleMap
.realloc(static_cast< sal_Int32
>(size
));
442 std::copy(handleNames
.begin(), handleNames
.end(), handleMap
.getArray());
445 OUString
const & PropertySetMixinImpl::Impl::translateHandle(
446 css::uno::Reference
< css::uno::XInterface
> const & object
,
447 sal_Int32 handle
) const
449 if (handle
< 0 || handle
>= handleMap
.getLength()) {
450 throw css::beans::UnknownPropertyException(
451 "bad handle " + OUString::number(handle
), object
);
453 return handleMap
[handle
];
456 void PropertySetMixinImpl::Impl::setProperty(
457 css::uno::Reference
< css::uno::XInterface
> const & object
,
458 OUString
const & name
, css::uno::Any
const & value
, bool isAmbiguous
,
459 bool isDefaulted
, sal_Int16 illegalArgumentPosition
) const
461 PropertyMap::const_iterator
i(properties
.find(name
));
462 if (i
== properties
.end()) {
463 throw css::beans::UnknownPropertyException(name
, object
);
466 && ((i
->second
.property
.Attributes
467 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
470 && ((i
->second
.property
.Attributes
471 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
474 throw css::lang::IllegalArgumentException(
475 ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
477 object
, illegalArgumentPosition
);
479 css::uno::Reference
< css::reflection::XIdlField2
> f(
480 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
);
481 css::uno::Any
o(object
->queryInterface(m_type
));
485 (css::uno::Reference
< css::reflection::XIdlField2
>(
486 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
)->
488 ((i
->second
.property
.Attributes
489 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
492 ((i
->second
.property
.Attributes
493 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
496 ((i
->second
.property
.Attributes
497 & css::beans::PropertyAttribute::MAYBEVOID
)
501 } catch (css::lang::IllegalArgumentException
& e
) {
502 if (e
.ArgumentPosition
== 1) {
503 throw css::lang::IllegalArgumentException(
504 e
.Message
, object
, illegalArgumentPosition
);
506 css::uno::Any anyEx
= cppu::getCaughtException();
507 throw css::lang::WrappedTargetRuntimeException(
508 "unexpected com.sun.star.lang.IllegalArgumentException: "
512 } catch (css::lang::IllegalAccessException
&) {
513 //TODO Clarify whether PropertyVetoException is the correct exception
514 // to throw when trying to set a read-only property:
515 throw css::beans::PropertyVetoException(
516 "cannot set read-only property " + name
, object
);
517 } catch (css::lang::WrappedTargetRuntimeException
& e
) {
518 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
519 // guaranteed to originate directly within XIdlField2.get (and thus have
520 // the expected semantics); it might also be passed through from lower
522 if (e
.TargetException
.isExtractableTo(
523 cppu::UnoType
<css::beans::UnknownPropertyException
>::get())
524 && ((i
->second
.property
.Attributes
525 & css::beans::PropertyAttribute::OPTIONAL
)
528 throw css::beans::UnknownPropertyException(name
, object
);
529 } else if (e
.TargetException
.isExtractableTo(
530 cppu::UnoType
<css::beans::PropertyVetoException
>::get())
531 && ((i
->second
.property
.Attributes
532 & css::beans::PropertyAttribute::CONSTRAINED
)
535 css::beans::PropertyVetoException exc
;
536 e
.TargetException
>>= exc
;
537 if (exc
.Message
.isEmpty() )
538 throw css::beans::PropertyVetoException("Invalid " + name
, object
);
542 throw css::lang::WrappedTargetException(
543 e
.Message
, object
, e
.TargetException
);
548 css::uno::Any
PropertySetMixinImpl::Impl::getProperty(
549 css::uno::Reference
< css::uno::XInterface
> const & object
,
550 OUString
const & name
, css::beans::PropertyState
* state
) const
552 PropertyMap::const_iterator
i(properties
.find(name
));
553 if (i
== properties
.end()) {
554 throw css::beans::UnknownPropertyException(name
, object
);
556 css::uno::Reference
< css::reflection::XIdlField2
> field(
557 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
);
560 value
= field
->get(object
->queryInterface(m_type
));
561 } catch (css::lang::IllegalArgumentException
& e
) {
562 css::uno::Any anyEx
= cppu::getCaughtException();
563 throw css::lang::WrappedTargetRuntimeException(
564 "unexpected com.sun.star.lang.IllegalArgumentException: "
567 } catch (css::lang::WrappedTargetRuntimeException
& e
) {
568 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
569 // guaranteed to originate directly within XIdlField2.get (and thus have
570 // the expected semantics); it might also be passed through from lower
572 if (e
.TargetException
.isExtractableTo(
573 cppu::UnoType
<css::beans::UnknownPropertyException
>::get())
574 && ((i
->second
.property
.Attributes
575 & css::beans::PropertyAttribute::OPTIONAL
)
578 throw css::beans::UnknownPropertyException(name
, object
);
580 throw css::lang::WrappedTargetException(
581 e
.Message
, object
, e
.TargetException
);
585 = ((i
->second
.property
.Attributes
586 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
589 = ((i
->second
.property
.Attributes
590 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
593 = ((i
->second
.property
.Attributes
594 & css::beans::PropertyAttribute::MAYBEVOID
)
596 bool isAmbiguous
= false;
597 bool isDefaulted
= false;
598 while (undoAmbiguous
|| undoDefaulted
|| undoOptional
) {
600 && value
.getValueTypeName().startsWith(
601 "com.sun.star.beans.Ambiguous<"))
603 css::uno::Reference
< css::reflection::XIdlClass
> ambiguous(
604 getReflection(value
.getValueTypeName()));
606 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
607 ambiguous
->getField("IsAmbiguous"),
608 css::uno::UNO_QUERY_THROW
)->get(value
)
611 throw css::uno::RuntimeException(
612 ("unexpected type of com.sun.star.beans.Ambiguous"
613 " IsAmbiguous member"),
616 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
617 ambiguous
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
619 } catch (css::lang::IllegalArgumentException
& e
) {
620 css::uno::Any anyEx
= cppu::getCaughtException();
621 throw css::lang::WrappedTargetRuntimeException(
622 "unexpected com.sun.star.lang.IllegalArgumentException: "
626 undoAmbiguous
= false;
627 } else if (undoDefaulted
628 && value
.getValueTypeName().startsWith(
629 "com.sun.star.beans.Defaulted<"))
631 css::uno::Reference
< css::reflection::XIdlClass
> defaulted(
632 getReflection(value
.getValueTypeName()));
635 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
636 defaulted
->getField("IsDefaulted"),
637 css::uno::UNO_QUERY_THROW
)->get(value
)
640 throw css::uno::RuntimeException(
641 ("unexpected type of com.sun.star.beans.Defaulted"
642 " IsDefaulted member"),
645 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
646 defaulted
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
648 } catch (css::lang::IllegalArgumentException
& e
) {
649 css::uno::Any anyEx
= cppu::getCaughtException();
650 throw css::lang::WrappedTargetRuntimeException(
651 "unexpected com.sun.star.lang.IllegalArgumentException: "
655 undoDefaulted
= false;
656 } else if (undoOptional
657 && value
.getValueTypeName().startsWith(
658 "com.sun.star.beans.Optional<"))
660 css::uno::Reference
< css::reflection::XIdlClass
> optional(
661 getReflection(value
.getValueTypeName()));
663 bool present
= false;
664 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
665 optional
->getField("IsPresent"),
666 css::uno::UNO_QUERY_THROW
)->get(value
)
669 throw css::uno::RuntimeException(
670 ("unexpected type of com.sun.star.beans.Optional"
671 " IsPresent member"),
678 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
679 optional
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
681 } catch (css::lang::IllegalArgumentException
& e
) {
682 css::uno::Any anyEx
= cppu::getCaughtException();
683 throw css::lang::WrappedTargetRuntimeException(
684 "unexpected com.sun.star.lang.IllegalArgumentException: "
688 undoOptional
= false;
690 throw css::uno::RuntimeException(
691 "unexpected type of attribute " + name
, object
);
694 if (state
!= nullptr) {
695 //XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE
696 // over DEFAULT_VALUE:
698 ? css::beans::PropertyState_AMBIGUOUS_VALUE
700 ? css::beans::PropertyState_DEFAULT_VALUE
701 : css::beans::PropertyState_DIRECT_VALUE
;
706 css::uno::Reference
< css::reflection::XIdlClass
>
707 PropertySetMixinImpl::Impl::getReflection(OUString
const & typeName
) const
709 return css::uno::Reference
< css::reflection::XIdlClass
>(
710 css::reflection::theCoreReflection::get(m_context
)->forName(typeName
),
711 css::uno::UNO_SET_THROW
);
714 css::uno::Any
PropertySetMixinImpl::Impl::wrapValue(
715 css::uno::Reference
< css::uno::XInterface
> const & object
,
716 css::uno::Any
const & value
,
717 css::uno::Reference
< css::reflection::XIdlClass
> const & type
,
718 bool wrapAmbiguous
, bool isAmbiguous
, bool wrapDefaulted
, bool isDefaulted
,
721 assert(wrapAmbiguous
|| !isAmbiguous
);
722 assert(wrapDefaulted
|| !isDefaulted
);
724 && type
->getName().startsWith("com.sun.star.beans.Ambiguous<"))
727 type
->createObject(strct
);
729 css::uno::Reference
< css::reflection::XIdlField2
> field(
730 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
734 object
, value
, field
->getType(), false, false,
735 wrapDefaulted
, isDefaulted
, wrapOptional
));
736 css::uno::Reference
< css::reflection::XIdlField2
>(
737 type
->getField("IsAmbiguous"), css::uno::UNO_QUERY_THROW
)->set(
738 strct
, css::uno::Any(isAmbiguous
));
739 } catch (css::lang::IllegalArgumentException
& e
) {
740 css::uno::Any anyEx
= cppu::getCaughtException();
741 throw css::lang::WrappedTargetRuntimeException(
742 "unexpected com.sun.star.lang.IllegalArgumentException: "
745 } catch (css::lang::IllegalAccessException
& e
) {
746 css::uno::Any anyEx
= cppu::getCaughtException();
747 throw css::lang::WrappedTargetRuntimeException(
748 "unexpected com.sun.star.lang.IllegalAccessException: "
755 && type
->getName().startsWith("com.sun.star.beans.Defaulted<"))
758 type
->createObject(strct
);
760 css::uno::Reference
< css::reflection::XIdlField2
> field(
761 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
765 object
, value
, field
->getType(), wrapAmbiguous
, isAmbiguous
,
766 false, false, wrapOptional
));
767 css::uno::Reference
< css::reflection::XIdlField2
>(
768 type
->getField("IsDefaulted"), css::uno::UNO_QUERY_THROW
)->set(
769 strct
, css::uno::Any(isDefaulted
));
770 } catch (css::lang::IllegalArgumentException
& e
) {
771 css::uno::Any anyEx
= cppu::getCaughtException();
772 throw css::lang::WrappedTargetRuntimeException(
773 "unexpected com.sun.star.lang.IllegalArgumentException: "
776 } catch (css::lang::IllegalAccessException
& e
) {
777 css::uno::Any anyEx
= cppu::getCaughtException();
778 throw css::lang::WrappedTargetRuntimeException(
779 "unexpected com.sun.star.lang.IllegalAccessException: "
786 && type
->getName().startsWith("com.sun.star.beans.Optional<"))
789 type
->createObject(strct
);
790 bool present
= value
.hasValue();
792 css::uno::Reference
< css::reflection::XIdlField2
>(
793 type
->getField("IsPresent"), css::uno::UNO_QUERY_THROW
)->set(
794 strct
, css::uno::Any(present
));
796 css::uno::Reference
< css::reflection::XIdlField2
> field(
797 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
801 object
, value
, field
->getType(), wrapAmbiguous
,
802 isAmbiguous
, wrapDefaulted
, isDefaulted
, false));
804 } catch (css::lang::IllegalArgumentException
& e
) {
805 css::uno::Any anyEx
= cppu::getCaughtException();
806 throw css::lang::WrappedTargetRuntimeException(
807 "unexpected com.sun.star.lang.IllegalArgumentException: "
810 } catch (css::lang::IllegalAccessException
& e
) {
811 css::uno::Any anyEx
= cppu::getCaughtException();
812 throw css::lang::WrappedTargetRuntimeException(
813 "unexpected com.sun.star.lang.IllegalAccessException: "
819 if (wrapAmbiguous
|| wrapDefaulted
|| wrapOptional
) {
820 throw css::uno::RuntimeException(
821 "unexpected type of attribute", object
);
826 PropertySetMixinImpl::PropertySetMixinImpl(
827 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
828 Implements implements
,
829 css::uno::Sequence
< OUString
> const & absentOptional
,
830 css::uno::Type
const & type
)
832 m_impl
= new Impl(context
, implements
, absentOptional
, type
);
836 PropertySetMixinImpl::~PropertySetMixinImpl() {
840 void PropertySetMixinImpl::checkUnknown(OUString
const & propertyName
) {
841 if (!propertyName
.isEmpty()) {
843 static_cast< css::beans::XPropertySet
* >(this), propertyName
);
847 void PropertySetMixinImpl::prepareSet(
848 OUString
const & propertyName
, css::uno::Any
const & oldValue
,
849 css::uno::Any
const & newValue
, BoundListeners
* boundListeners
)
851 Impl::PropertyMap::const_iterator
it(m_impl
->properties
.find(propertyName
));
852 assert(it
!= m_impl
->properties
.end());
853 Impl::VetoListenerBag specificVeto
;
854 Impl::VetoListenerBag unspecificVeto
;
856 osl::MutexGuard
g(m_impl
->mutex
);
857 if (m_impl
->disposed
) {
858 throw css::lang::DisposedException(
859 "disposed", static_cast< css::beans::XPropertySet
* >(this));
861 if ((it
->second
.property
.Attributes
862 & css::beans::PropertyAttribute::CONSTRAINED
)
865 Impl::VetoListenerMap::const_iterator
i(
866 m_impl
->vetoListeners
.find(propertyName
));
867 if (i
!= m_impl
->vetoListeners
.end()) {
868 specificVeto
= i
->second
;
870 i
= m_impl
->vetoListeners
.find("");
871 if (i
!= m_impl
->vetoListeners
.end()) {
872 unspecificVeto
= i
->second
;
875 if ((it
->second
.property
.Attributes
876 & css::beans::PropertyAttribute::BOUND
)
879 assert(boundListeners
!= nullptr);
880 Impl::BoundListenerMap::const_iterator
i(
881 m_impl
->boundListeners
.find(propertyName
));
882 if (i
!= m_impl
->boundListeners
.end()) {
883 boundListeners
->m_impl
->specificListeners
= i
->second
;
885 i
= m_impl
->boundListeners
.find("");
886 if (i
!= m_impl
->boundListeners
.end()) {
887 boundListeners
->m_impl
->unspecificListeners
= i
->second
;
891 if ((it
->second
.property
.Attributes
892 & css::beans::PropertyAttribute::CONSTRAINED
)
895 css::beans::PropertyChangeEvent
event(
896 static_cast< css::beans::XPropertySet
* >(this), propertyName
,
897 false, it
->second
.property
.Handle
, oldValue
, newValue
);
898 for (auto& rxVetoListener
: specificVeto
)
901 rxVetoListener
->vetoableChange(event
);
902 } catch (css::lang::DisposedException
&) {}
904 for (auto& rxVetoListener
: unspecificVeto
)
907 rxVetoListener
->vetoableChange(event
);
908 } catch (css::lang::DisposedException
&) {}
911 if ((it
->second
.property
.Attributes
& css::beans::PropertyAttribute::BOUND
)
914 assert(boundListeners
!= nullptr);
915 boundListeners
->m_impl
->event
= css::beans::PropertyChangeEvent(
916 static_cast< css::beans::XPropertySet
* >(this), propertyName
,
917 false, it
->second
.property
.Handle
, oldValue
, newValue
);
921 void PropertySetMixinImpl::dispose() {
922 Impl::BoundListenerMap boundListeners
;
923 Impl::VetoListenerMap vetoListeners
;
925 osl::MutexGuard
g(m_impl
->mutex
);
926 boundListeners
.swap(m_impl
->boundListeners
);
927 vetoListeners
.swap(m_impl
->vetoListeners
);
928 m_impl
->disposed
= true;
930 css::lang::EventObject
event(
931 static_cast< css::beans::XPropertySet
* >(this));
932 for (const auto& rEntry
: boundListeners
)
934 for (auto& rxBoundListener
: rEntry
.second
)
936 rxBoundListener
->disposing(event
);
939 for (const auto& rEntry
: vetoListeners
)
941 for (auto& rxVetoListener
: rEntry
.second
)
943 rxVetoListener
->disposing(event
);
948 css::uno::Any
PropertySetMixinImpl::queryInterface(css::uno::Type
const & type
)
950 if ((m_impl
->implements
& IMPLEMENTS_PROPERTY_SET
) != 0
951 && type
== css::beans::XPropertySet::static_type())
953 css::uno::Reference
< css::uno::XInterface
> ifc(
954 static_cast< css::beans::XPropertySet
* >(this));
955 return css::uno::Any(&ifc
, type
);
957 if ((m_impl
->implements
& IMPLEMENTS_FAST_PROPERTY_SET
) != 0
958 && type
== css::beans::XFastPropertySet::static_type())
960 css::uno::Reference
< css::uno::XInterface
> ifc(
961 static_cast< css::beans::XFastPropertySet
* >(this));
962 return css::uno::Any(&ifc
, type
);
964 if ((m_impl
->implements
& IMPLEMENTS_PROPERTY_ACCESS
) != 0
965 && type
== css::beans::XPropertyAccess::static_type())
967 css::uno::Reference
< css::uno::XInterface
> ifc(
968 static_cast< css::beans::XPropertyAccess
* >(this));
969 return css::uno::Any(&ifc
, type
);
971 return css::uno::Any();
974 css::uno::Reference
< css::beans::XPropertySetInfo
>
975 PropertySetMixinImpl::getPropertySetInfo()
977 return new Info(m_impl
);
980 void PropertySetMixinImpl::setPropertyValue(
981 OUString
const & propertyName
, css::uno::Any
const & value
)
984 static_cast< css::beans::XPropertySet
* >(this), propertyName
, value
,
988 css::uno::Any
PropertySetMixinImpl::getPropertyValue(
989 OUString
const & propertyName
)
991 return m_impl
->getProperty(
992 static_cast< css::beans::XPropertySet
* >(this), propertyName
, nullptr);
995 void PropertySetMixinImpl::addPropertyChangeListener(
996 OUString
const & propertyName
,
997 css::uno::Reference
< css::beans::XPropertyChangeListener
> const & listener
)
999 css::uno::Reference
< css::beans::XPropertyChangeListener
>(
1000 listener
, css::uno::UNO_SET_THROW
); // reject NULL listener
1001 checkUnknown(propertyName
);
1004 osl::MutexGuard
g(m_impl
->mutex
);
1005 disposed
= m_impl
->disposed
;
1007 m_impl
->boundListeners
[propertyName
].insert(listener
);
1011 listener
->disposing(
1012 css::lang::EventObject(
1013 static_cast< css::beans::XPropertySet
* >(this)));
1017 void PropertySetMixinImpl::removePropertyChangeListener(
1018 OUString
const & propertyName
,
1019 css::uno::Reference
< css::beans::XPropertyChangeListener
> const & listener
)
1021 assert(listener
.is());
1022 checkUnknown(propertyName
);
1023 osl::MutexGuard
g(m_impl
->mutex
);
1024 Impl::BoundListenerMap::iterator
i(
1025 m_impl
->boundListeners
.find(propertyName
));
1026 if (i
!= m_impl
->boundListeners
.end()) {
1027 BoundListenerBag::iterator
j(i
->second
.find(listener
));
1028 if (j
!= i
->second
.end()) {
1034 void PropertySetMixinImpl::addVetoableChangeListener(
1035 OUString
const & propertyName
,
1036 css::uno::Reference
< css::beans::XVetoableChangeListener
> const & listener
)
1038 css::uno::Reference
< css::beans::XVetoableChangeListener
>(
1039 listener
, css::uno::UNO_SET_THROW
); // reject NULL listener
1040 checkUnknown(propertyName
);
1043 osl::MutexGuard
g(m_impl
->mutex
);
1044 disposed
= m_impl
->disposed
;
1046 m_impl
->vetoListeners
[propertyName
].insert(listener
);
1050 listener
->disposing(
1051 css::lang::EventObject(
1052 static_cast< css::beans::XPropertySet
* >(this)));
1056 void PropertySetMixinImpl::removeVetoableChangeListener(
1057 OUString
const & propertyName
,
1058 css::uno::Reference
< css::beans::XVetoableChangeListener
> const & listener
)
1060 assert(listener
.is());
1061 checkUnknown(propertyName
);
1062 osl::MutexGuard
g(m_impl
->mutex
);
1063 Impl::VetoListenerMap::iterator
i(m_impl
->vetoListeners
.find(propertyName
));
1064 if (i
!= m_impl
->vetoListeners
.end()) {
1065 Impl::VetoListenerBag::iterator
j(i
->second
.find(listener
));
1066 if (j
!= i
->second
.end()) {
1072 void PropertySetMixinImpl::setFastPropertyValue(
1073 sal_Int32 handle
, css::uno::Any
const & value
)
1075 m_impl
->setProperty(
1076 static_cast< css::beans::XPropertySet
* >(this),
1077 m_impl
->translateHandle(
1078 static_cast< css::beans::XPropertySet
* >(this), handle
),
1079 value
, false, false, 1);
1082 css::uno::Any
PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle
)
1084 return m_impl
->getProperty(
1085 static_cast< css::beans::XPropertySet
* >(this),
1086 m_impl
->translateHandle(
1087 static_cast< css::beans::XPropertySet
* >(this), handle
),
1091 css::uno::Sequence
< css::beans::PropertyValue
>
1092 PropertySetMixinImpl::getPropertyValues()
1094 css::uno::Sequence
< css::beans::PropertyValue
> s(
1095 m_impl
->handleMap
.getLength());
1097 for (sal_Int32 i
= 0; i
< m_impl
->handleMap
.getLength(); ++i
) {
1099 s
[n
].Value
= m_impl
->getProperty(
1100 static_cast< css::beans::XPropertySet
* >(this),
1101 m_impl
->handleMap
[i
], &s
[n
].State
);
1102 } catch (css::beans::UnknownPropertyException
&) {
1104 } catch (css::lang::WrappedTargetException
& e
) {
1105 throw css::lang::WrappedTargetRuntimeException(
1106 e
.Message
, static_cast< css::beans::XPropertySet
* >(this),
1109 s
[n
].Name
= m_impl
->handleMap
[i
];
1117 void PropertySetMixinImpl::setPropertyValues(
1118 css::uno::Sequence
< css::beans::PropertyValue
> const & props
)
1120 for (const auto & p
: props
) {
1123 != m_impl
->translateHandle(
1124 static_cast< css::beans::XPropertySet
* >(this),
1127 throw css::beans::UnknownPropertyException(
1128 ("name " + p
.Name
+ " does not match handle "
1129 + OUString::number(p
.Handle
)),
1130 static_cast< css::beans::XPropertySet
* >(this));
1132 m_impl
->setProperty(
1133 static_cast< css::beans::XPropertySet
* >(this), p
.Name
,
1135 p
.State
== css::beans::PropertyState_AMBIGUOUS_VALUE
,
1136 p
.State
== css::beans::PropertyState_DEFAULT_VALUE
, 0);
1140 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */