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>
30 #include <com/sun/star/beans/Property.hpp>
31 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
32 #include <com/sun/star/beans/PropertyAttribute.hpp>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <com/sun/star/beans/PropertyVetoException.hpp>
35 #include <com/sun/star/beans/UnknownPropertyException.hpp>
36 #include <com/sun/star/beans/XFastPropertySet.hpp>
37 #include <com/sun/star/beans/XPropertyAccess.hpp>
38 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/beans/XPropertySetInfo.hpp>
41 #include <com/sun/star/beans/XVetoableChangeListener.hpp>
42 #include <com/sun/star/container/NoSuchElementException.hpp>
43 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
44 #include <com/sun/star/lang/DisposedException.hpp>
45 #include <com/sun/star/lang/EventObject.hpp>
46 #include <com/sun/star/lang/IllegalAccessException.hpp>
47 #include <com/sun/star/lang/IllegalArgumentException.hpp>
48 #include <com/sun/star/lang/WrappedTargetException.hpp>
49 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
50 #include <com/sun/star/reflection/XCompoundTypeDescription.hpp>
51 #include <com/sun/star/reflection/XIdlClass.hpp>
52 #include <com/sun/star/reflection/XIdlField2.hpp>
53 #include <com/sun/star/reflection/XIndirectTypeDescription.hpp>
54 #include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp>
55 #include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
56 #include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp>
57 #include <com/sun/star/reflection/XStructTypeDescription.hpp>
58 #include <com/sun/star/reflection/XTypeDescription.hpp>
59 #include <com/sun/star/reflection/theCoreReflection.hpp>
60 #include <com/sun/star/uno/Any.hxx>
61 #include <com/sun/star/uno/Reference.hxx>
62 #include <com/sun/star/uno/RuntimeException.hpp>
63 #include <com/sun/star/uno/Sequence.hxx>
64 #include <com/sun/star/uno/Type.hxx>
65 #include <com/sun/star/uno/TypeClass.hpp>
66 #include <com/sun/star/uno/XComponentContext.hpp>
67 #include <com/sun/star/uno/XInterface.hpp>
68 #include <cppu/unotype.hxx>
69 #include <cppuhelper/exc_hlp.hxx>
70 #include <cppuhelper/implbase.hxx>
71 #include <cppuhelper/propertysetmixin.hxx>
72 #include <cppuhelper/weak.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 theProperty
, bool thePresent
):
85 property(std::move(theProperty
)), present(thePresent
) {}
87 css::beans::Property property
;
91 struct Data
: public salhelper::SimpleReferenceObject
{
92 typedef std::map
< OUString
, PropertyData
> PropertyMap
;
94 PropertyMap properties
;
96 PropertyMap::const_iterator
get(
97 css::uno::Reference
< css::uno::XInterface
> const & object
,
98 OUString
const & name
) const;
102 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
,
103 css::uno::Sequence
< OUString
> const & absentOptional
,
104 std::vector
< OUString
> * handleNames
)
106 std::set
<OUString
> seen
;
107 initProperties(type
, absentOptional
, handleNames
, &seen
);
112 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
,
113 css::uno::Sequence
< OUString
> const & absentOptional
,
114 std::vector
< OUString
> * handleNames
, std::set
<OUString
> * seen
);
116 static css::uno::Reference
< css::reflection::XTypeDescription
>
118 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
);
121 Data::PropertyMap::const_iterator
Data::get(
122 css::uno::Reference
< css::uno::XInterface
> const & object
,
123 OUString
const & name
) const
125 PropertyMap::const_iterator
i(properties
.find(name
));
126 if (i
== properties
.end() || !i
->second
.present
) {
127 throw css::beans::UnknownPropertyException(name
, object
);
132 void Data::initProperties(
133 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
,
134 css::uno::Sequence
< OUString
> const & absentOptional
,
135 std::vector
< OUString
> * handleNames
, std::set
<OUString
> * seen
)
137 css::uno::Reference
< css::reflection::XInterfaceTypeDescription2
> ifc(
138 resolveTypedefs(type
), css::uno::UNO_QUERY_THROW
);
139 if (!seen
->insert(ifc
->getName()).second
)
142 const css::uno::Sequence
<
143 css::uno::Reference
< css::reflection::XTypeDescription
> > bases(
144 ifc
->getBaseTypes());
145 for (const auto & i
: bases
) {
146 initProperties(i
, absentOptional
, handleNames
, seen
);
148 const css::uno::Sequence
<
150 css::reflection::XInterfaceMemberTypeDescription
> > members(
152 OUString
const * absentBegin
= absentOptional
.getConstArray();
153 OUString
const * absentEnd
=
154 absentBegin
+ absentOptional
.getLength();
155 for (const auto & m
: members
) {
156 if (m
->getTypeClass()
157 == css::uno::TypeClass_INTERFACE_ATTRIBUTE
)
160 css::reflection::XInterfaceAttributeTypeDescription2
> attr(
161 m
, 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 (const auto & ex
: std::as_const(excs
)) {
180 if ( ex
->getName() == "com.sun.star.beans.UnknownPropertyException" )
186 excs
= attr
->getSetExceptions();
187 for (const auto & ex
: std::as_const(excs
)) {
188 if ( ex
->getName() == "com.sun.star.beans.UnknownPropertyException" )
191 } else if ( ex
->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) {
225 const css::uno::Sequence
<
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
< 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 OUString
name(m
->getMemberName());
245 if (!properties
.emplace(
248 css::beans::Property(
249 name
, static_cast< sal_Int32
>(handles
),
251 t
->getTypeClass(), t
->getName()),
253 (std::find(absentBegin
, absentEnd
, name
)
257 throw css::uno::RuntimeException(
258 "inconsistent UNO type registry");
260 handleNames
->push_back(name
);
265 css::uno::Reference
< css::reflection::XTypeDescription
> Data::resolveTypedefs(
266 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
)
268 css::uno::Reference
< css::reflection::XTypeDescription
> t(type
);
269 while (t
->getTypeClass() == css::uno::TypeClass_TYPEDEF
) {
270 t
= css::uno::Reference
< css::reflection::XIndirectTypeDescription
>(
271 t
, css::uno::UNO_QUERY_THROW
)->getReferencedType();
276 class Info
: public cppu::WeakImplHelper
< css::beans::XPropertySetInfo
> {
278 explicit Info(Data
* data
): m_data(data
) {}
280 virtual css::uno::Sequence
< css::beans::Property
> SAL_CALL
getProperties() override
;
282 virtual css::beans::Property SAL_CALL
getPropertyByName(
283 OUString
const & name
) override
;
285 virtual sal_Bool SAL_CALL
hasPropertyByName(OUString
const & name
) override
;
288 rtl::Reference
< Data
> m_data
;
291 css::uno::Sequence
< css::beans::Property
> Info::getProperties()
293 assert(m_data
->properties
.size() <= SAL_MAX_INT32
);
294 css::uno::Sequence
< css::beans::Property
> s(
295 static_cast< sal_Int32
>(m_data
->properties
.size()));
296 auto r
= asNonConstRange(s
);
298 for (const auto& rEntry
: m_data
->properties
)
300 if (rEntry
.second
.present
) {
301 r
[n
++] = rEntry
.second
.property
;
308 css::beans::Property
Info::getPropertyByName(OUString
const & name
)
310 return m_data
->get(static_cast< cppu::OWeakObject
* >(this), name
)->
314 sal_Bool
Info::hasPropertyByName(OUString
const & name
)
316 Data::PropertyMap::iterator
i(m_data
->properties
.find(name
));
317 return i
!= m_data
->properties
.end() && i
->second
.present
;
321 std::multiset
< css::uno::Reference
< css::beans::XPropertyChangeListener
> >
326 class PropertySetMixinImpl::BoundListeners::Impl
{
328 BoundListenerBag specificListeners
;
329 BoundListenerBag unspecificListeners
;
330 css::beans::PropertyChangeEvent event
;
333 PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl
) {}
335 PropertySetMixinImpl::BoundListeners::~BoundListeners() {
339 void PropertySetMixinImpl::BoundListeners::notify() const {
340 for (const auto& rxListener
: m_impl
->specificListeners
)
343 rxListener
->propertyChange(m_impl
->event
);
344 } catch (css::lang::DisposedException
&) {}
346 for (const auto& rxListener
: m_impl
->unspecificListeners
)
349 rxListener
->propertyChange(m_impl
->event
);
350 } catch (css::lang::DisposedException
&) {}
354 class PropertySetMixinImpl::Impl
: public Data
{
357 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
358 Implements theImplements
,
359 css::uno::Sequence
< OUString
> const & absentOptional
,
360 css::uno::Type
const & type
);
362 OUString
const & translateHandle(
363 css::uno::Reference
< css::uno::XInterface
> const & object
,
364 sal_Int32 handle
) const;
367 css::uno::Reference
< css::uno::XInterface
> const & object
,
368 OUString
const & name
, css::uno::Any
const & value
,
369 bool isAmbiguous
, bool isDefaulted
, sal_Int16 illegalArgumentPosition
)
372 css::uno::Any
getProperty(
373 css::uno::Reference
< css::uno::XInterface
> const & object
,
374 OUString
const & name
, css::beans::PropertyState
* state
) const;
376 PropertySetMixinImpl::Implements implements
;
377 css::uno::Sequence
< OUString
> handleMap
;
379 typedef std::map
< OUString
, BoundListenerBag
> BoundListenerMap
;
382 std::multiset
< css::uno::Reference
< css::beans::XVetoableChangeListener
> >
385 typedef std::map
< OUString
, VetoListenerBag
> VetoListenerMap
;
387 mutable std::mutex mutex
;
388 BoundListenerMap boundListeners
;
389 VetoListenerMap vetoListeners
;
393 css::uno::Reference
< css::reflection::XIdlClass
> getReflection(
394 OUString
const & typeName
) const;
396 static css::uno::Any
wrapValue(
397 css::uno::Reference
< css::uno::XInterface
> const & object
,
398 css::uno::Any
const & value
,
399 css::uno::Reference
< css::reflection::XIdlClass
> const & type
,
400 bool wrapAmbiguous
, bool isAmbiguous
, bool wrapDefaulted
,
401 bool isDefaulted
, bool wrapOptional
);
403 css::uno::Reference
< css::uno::XComponentContext
> const & m_context
;
404 css::uno::Type m_type
;
405 css::uno::Reference
< css::reflection::XIdlClass
> m_idlClass
;
408 PropertySetMixinImpl::Impl::Impl(
409 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
410 Implements theImplements
,
411 css::uno::Sequence
< OUString
> const & absentOptional
,
412 css::uno::Type
const & type
):
413 implements(theImplements
), disposed(false), m_context(context
),
416 assert(context
.is());
419 & ~(IMPLEMENTS_PROPERTY_SET
| IMPLEMENTS_FAST_PROPERTY_SET
420 | IMPLEMENTS_PROPERTY_ACCESS
))
422 m_idlClass
= getReflection(m_type
.getTypeName());
423 css::uno::Reference
< css::reflection::XTypeDescription
> ifc
;
426 css::uno::Reference
< css::container::XHierarchicalNameAccess
>(
427 m_context
->getValueByName(
428 "/singletons/com.sun.star.reflection."
429 "theTypeDescriptionManager"),
430 css::uno::UNO_QUERY_THROW
)->getByHierarchicalName(
431 m_type
.getTypeName()),
432 css::uno::UNO_QUERY_THROW
);
433 } catch (css::container::NoSuchElementException
& e
) {
434 css::uno::Any anyEx
= cppu::getCaughtException();
435 throw css::lang::WrappedTargetRuntimeException(
436 "unexpected com.sun.star.container.NoSuchElementException: "
440 std::vector
< OUString
> handleNames
;
441 initProperties(ifc
, absentOptional
, &handleNames
);
442 std::vector
< OUString
>::size_type size
= handleNames
.size();
443 assert(size
<= SAL_MAX_INT32
);
444 handleMap
.realloc(static_cast< sal_Int32
>(size
));
445 std::copy(handleNames
.begin(), handleNames
.end(), handleMap
.getArray());
448 OUString
const & PropertySetMixinImpl::Impl::translateHandle(
449 css::uno::Reference
< css::uno::XInterface
> const & object
,
450 sal_Int32 handle
) const
452 if (handle
< 0 || handle
>= handleMap
.getLength()) {
453 throw css::beans::UnknownPropertyException(
454 "bad handle " + OUString::number(handle
), object
);
456 return handleMap
[handle
];
459 void PropertySetMixinImpl::Impl::setProperty(
460 css::uno::Reference
< css::uno::XInterface
> const & object
,
461 OUString
const & name
, css::uno::Any
const & value
, bool isAmbiguous
,
462 bool isDefaulted
, sal_Int16 illegalArgumentPosition
) const
464 PropertyMap::const_iterator
i(properties
.find(name
));
465 if (i
== properties
.end()) {
466 throw css::beans::UnknownPropertyException(name
, object
);
469 && ((i
->second
.property
.Attributes
470 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
473 && ((i
->second
.property
.Attributes
474 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
477 throw css::lang::IllegalArgumentException(
478 ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
480 object
, illegalArgumentPosition
);
482 css::uno::Reference
< css::reflection::XIdlField2
> f(
483 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
);
484 css::uno::Any
o(object
->queryInterface(m_type
));
488 (css::uno::Reference
< css::reflection::XIdlField2
>(
489 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
)->
491 ((i
->second
.property
.Attributes
492 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
495 ((i
->second
.property
.Attributes
496 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
499 ((i
->second
.property
.Attributes
500 & css::beans::PropertyAttribute::MAYBEVOID
)
504 } catch (css::lang::IllegalArgumentException
& e
) {
505 if (e
.ArgumentPosition
== 1) {
506 throw css::lang::IllegalArgumentException(
507 e
.Message
, object
, illegalArgumentPosition
);
509 css::uno::Any anyEx
= cppu::getCaughtException();
510 throw css::lang::WrappedTargetRuntimeException(
511 "unexpected com.sun.star.lang.IllegalArgumentException: "
515 } catch (css::lang::IllegalAccessException
&) {
516 //TODO Clarify whether PropertyVetoException is the correct exception
517 // to throw when trying to set a read-only property:
518 throw css::beans::PropertyVetoException(
519 "cannot set read-only property " + name
, object
);
520 } catch (css::lang::WrappedTargetRuntimeException
& e
) {
521 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
522 // guaranteed to originate directly within XIdlField2.get (and thus have
523 // the expected semantics); it might also be passed through from lower
525 if (e
.TargetException
.isExtractableTo(
526 cppu::UnoType
<css::beans::UnknownPropertyException
>::get())
527 && ((i
->second
.property
.Attributes
528 & css::beans::PropertyAttribute::OPTIONAL
)
531 throw css::beans::UnknownPropertyException(name
, object
);
532 } else if (e
.TargetException
.isExtractableTo(
533 cppu::UnoType
<css::beans::PropertyVetoException
>::get())
534 && ((i
->second
.property
.Attributes
535 & css::beans::PropertyAttribute::CONSTRAINED
)
538 css::beans::PropertyVetoException exc
;
539 e
.TargetException
>>= exc
;
540 if (exc
.Message
.isEmpty() )
541 throw css::beans::PropertyVetoException("Invalid " + name
, object
);
545 throw css::lang::WrappedTargetException(
546 e
.Message
, object
, e
.TargetException
);
551 css::uno::Any
PropertySetMixinImpl::Impl::getProperty(
552 css::uno::Reference
< css::uno::XInterface
> const & object
,
553 OUString
const & name
, css::beans::PropertyState
* state
) const
555 PropertyMap::const_iterator
i(properties
.find(name
));
556 if (i
== properties
.end()) {
557 throw css::beans::UnknownPropertyException(name
, object
);
559 css::uno::Reference
< css::reflection::XIdlField2
> field(
560 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
);
563 value
= field
->get(object
->queryInterface(m_type
));
564 } catch (css::lang::IllegalArgumentException
& e
) {
565 css::uno::Any anyEx
= cppu::getCaughtException();
566 throw css::lang::WrappedTargetRuntimeException(
567 "unexpected com.sun.star.lang.IllegalArgumentException: "
570 } catch (css::lang::WrappedTargetRuntimeException
& e
) {
571 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
572 // guaranteed to originate directly within XIdlField2.get (and thus have
573 // the expected semantics); it might also be passed through from lower
575 if (e
.TargetException
.isExtractableTo(
576 cppu::UnoType
<css::beans::UnknownPropertyException
>::get())
577 && ((i
->second
.property
.Attributes
578 & css::beans::PropertyAttribute::OPTIONAL
)
581 throw css::beans::UnknownPropertyException(name
, object
);
583 throw css::lang::WrappedTargetException(
584 e
.Message
, object
, e
.TargetException
);
588 = ((i
->second
.property
.Attributes
589 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
592 = ((i
->second
.property
.Attributes
593 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
596 = ((i
->second
.property
.Attributes
597 & css::beans::PropertyAttribute::MAYBEVOID
)
599 bool isAmbiguous
= false;
600 bool isDefaulted
= false;
601 while (undoAmbiguous
|| undoDefaulted
|| undoOptional
) {
603 && value
.getValueTypeName().startsWith(
604 "com.sun.star.beans.Ambiguous<"))
606 css::uno::Reference
< css::reflection::XIdlClass
> ambiguous(
607 getReflection(value
.getValueTypeName()));
609 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
610 ambiguous
->getField("IsAmbiguous"),
611 css::uno::UNO_QUERY_THROW
)->get(value
)
614 throw css::uno::RuntimeException(
615 ("unexpected type of com.sun.star.beans.Ambiguous"
616 " IsAmbiguous member"),
619 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
620 ambiguous
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
622 } catch (css::lang::IllegalArgumentException
& e
) {
623 css::uno::Any anyEx
= cppu::getCaughtException();
624 throw css::lang::WrappedTargetRuntimeException(
625 "unexpected com.sun.star.lang.IllegalArgumentException: "
629 undoAmbiguous
= false;
630 } else if (undoDefaulted
631 && value
.getValueTypeName().startsWith(
632 "com.sun.star.beans.Defaulted<"))
634 css::uno::Reference
< css::reflection::XIdlClass
> defaulted(
635 getReflection(value
.getValueTypeName()));
638 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
639 defaulted
->getField("IsDefaulted"),
640 css::uno::UNO_QUERY_THROW
)->get(value
)
643 throw css::uno::RuntimeException(
644 ("unexpected type of com.sun.star.beans.Defaulted"
645 " IsDefaulted member"),
648 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
649 defaulted
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
651 } catch (css::lang::IllegalArgumentException
& e
) {
652 css::uno::Any anyEx
= cppu::getCaughtException();
653 throw css::lang::WrappedTargetRuntimeException(
654 "unexpected com.sun.star.lang.IllegalArgumentException: "
658 undoDefaulted
= false;
659 } else if (undoOptional
660 && value
.getValueTypeName().startsWith(
661 "com.sun.star.beans.Optional<"))
663 css::uno::Reference
< css::reflection::XIdlClass
> optional(
664 getReflection(value
.getValueTypeName()));
666 bool present
= false;
667 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
668 optional
->getField("IsPresent"),
669 css::uno::UNO_QUERY_THROW
)->get(value
)
672 throw css::uno::RuntimeException(
673 ("unexpected type of com.sun.star.beans.Optional"
674 " IsPresent member"),
681 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
682 optional
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
684 } catch (css::lang::IllegalArgumentException
& e
) {
685 css::uno::Any anyEx
= cppu::getCaughtException();
686 throw css::lang::WrappedTargetRuntimeException(
687 "unexpected com.sun.star.lang.IllegalArgumentException: "
691 undoOptional
= false;
693 throw css::uno::RuntimeException(
694 "unexpected type of attribute " + name
, object
);
697 if (state
!= nullptr) {
698 //XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE
699 // over DEFAULT_VALUE:
701 ? css::beans::PropertyState_AMBIGUOUS_VALUE
703 ? css::beans::PropertyState_DEFAULT_VALUE
704 : css::beans::PropertyState_DIRECT_VALUE
;
709 css::uno::Reference
< css::reflection::XIdlClass
>
710 PropertySetMixinImpl::Impl::getReflection(OUString
const & typeName
) const
712 return css::uno::Reference
< css::reflection::XIdlClass
>(
713 css::reflection::theCoreReflection::get(m_context
)->forName(typeName
),
714 css::uno::UNO_SET_THROW
);
717 css::uno::Any
PropertySetMixinImpl::Impl::wrapValue(
718 css::uno::Reference
< css::uno::XInterface
> const & object
,
719 css::uno::Any
const & value
,
720 css::uno::Reference
< css::reflection::XIdlClass
> const & type
,
721 bool wrapAmbiguous
, bool isAmbiguous
, bool wrapDefaulted
, bool isDefaulted
,
724 assert(wrapAmbiguous
|| !isAmbiguous
);
725 assert(wrapDefaulted
|| !isDefaulted
);
727 && type
->getName().startsWith("com.sun.star.beans.Ambiguous<"))
730 type
->createObject(strct
);
732 css::uno::Reference
< css::reflection::XIdlField2
> field(
733 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
737 object
, value
, field
->getType(), false, false,
738 wrapDefaulted
, isDefaulted
, wrapOptional
));
739 css::uno::Reference
< css::reflection::XIdlField2
>(
740 type
->getField("IsAmbiguous"), css::uno::UNO_QUERY_THROW
)->set(
741 strct
, css::uno::Any(isAmbiguous
));
742 } catch (css::lang::IllegalArgumentException
& e
) {
743 css::uno::Any anyEx
= cppu::getCaughtException();
744 throw css::lang::WrappedTargetRuntimeException(
745 "unexpected com.sun.star.lang.IllegalArgumentException: "
748 } catch (css::lang::IllegalAccessException
& e
) {
749 css::uno::Any anyEx
= cppu::getCaughtException();
750 throw css::lang::WrappedTargetRuntimeException(
751 "unexpected com.sun.star.lang.IllegalAccessException: "
758 && type
->getName().startsWith("com.sun.star.beans.Defaulted<"))
761 type
->createObject(strct
);
763 css::uno::Reference
< css::reflection::XIdlField2
> field(
764 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
768 object
, value
, field
->getType(), wrapAmbiguous
, isAmbiguous
,
769 false, false, wrapOptional
));
770 css::uno::Reference
< css::reflection::XIdlField2
>(
771 type
->getField("IsDefaulted"), css::uno::UNO_QUERY_THROW
)->set(
772 strct
, css::uno::Any(isDefaulted
));
773 } catch (css::lang::IllegalArgumentException
& e
) {
774 css::uno::Any anyEx
= cppu::getCaughtException();
775 throw css::lang::WrappedTargetRuntimeException(
776 "unexpected com.sun.star.lang.IllegalArgumentException: "
779 } catch (css::lang::IllegalAccessException
& e
) {
780 css::uno::Any anyEx
= cppu::getCaughtException();
781 throw css::lang::WrappedTargetRuntimeException(
782 "unexpected com.sun.star.lang.IllegalAccessException: "
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::Any(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 css::uno::Any anyEx
= cppu::getCaughtException();
809 throw css::lang::WrappedTargetRuntimeException(
810 "unexpected com.sun.star.lang.IllegalArgumentException: "
813 } catch (css::lang::IllegalAccessException
& e
) {
814 css::uno::Any anyEx
= cppu::getCaughtException();
815 throw css::lang::WrappedTargetRuntimeException(
816 "unexpected com.sun.star.lang.IllegalAccessException: "
822 if (wrapAmbiguous
|| wrapDefaulted
|| wrapOptional
) {
823 throw css::uno::RuntimeException(
824 "unexpected type of attribute", object
);
829 PropertySetMixinImpl::PropertySetMixinImpl(
830 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
831 Implements implements
,
832 css::uno::Sequence
< OUString
> const & absentOptional
,
833 css::uno::Type
const & type
)
835 m_impl
= new Impl(context
, implements
, absentOptional
, type
);
839 PropertySetMixinImpl::~PropertySetMixinImpl() {
843 void PropertySetMixinImpl::checkUnknown(OUString
const & propertyName
) {
844 if (!propertyName
.isEmpty()) {
846 static_cast< css::beans::XPropertySet
* >(this), propertyName
);
850 void PropertySetMixinImpl::prepareSet(
851 OUString
const & propertyName
, css::uno::Any
const & oldValue
,
852 css::uno::Any
const & newValue
, BoundListeners
* boundListeners
)
854 Impl::PropertyMap::const_iterator
it(m_impl
->properties
.find(propertyName
));
855 assert(it
!= m_impl
->properties
.end());
856 Impl::VetoListenerBag specificVeto
;
857 Impl::VetoListenerBag unspecificVeto
;
859 std::scoped_lock
g(m_impl
->mutex
);
860 if (m_impl
->disposed
) {
861 throw css::lang::DisposedException(
862 "disposed", static_cast< css::beans::XPropertySet
* >(this));
864 if ((it
->second
.property
.Attributes
865 & css::beans::PropertyAttribute::CONSTRAINED
)
868 Impl::VetoListenerMap::const_iterator
i(
869 m_impl
->vetoListeners
.find(propertyName
));
870 if (i
!= m_impl
->vetoListeners
.end()) {
871 specificVeto
= i
->second
;
873 i
= m_impl
->vetoListeners
.find("");
874 if (i
!= m_impl
->vetoListeners
.end()) {
875 unspecificVeto
= i
->second
;
878 if ((it
->second
.property
.Attributes
879 & css::beans::PropertyAttribute::BOUND
)
882 assert(boundListeners
!= nullptr);
883 Impl::BoundListenerMap::const_iterator
i(
884 m_impl
->boundListeners
.find(propertyName
));
885 if (i
!= m_impl
->boundListeners
.end()) {
886 boundListeners
->m_impl
->specificListeners
= i
->second
;
888 i
= m_impl
->boundListeners
.find("");
889 if (i
!= m_impl
->boundListeners
.end()) {
890 boundListeners
->m_impl
->unspecificListeners
= i
->second
;
894 if ((it
->second
.property
.Attributes
895 & css::beans::PropertyAttribute::CONSTRAINED
)
898 css::beans::PropertyChangeEvent
event(
899 static_cast< css::beans::XPropertySet
* >(this), propertyName
,
900 false, it
->second
.property
.Handle
, oldValue
, newValue
);
901 for (auto& rxVetoListener
: specificVeto
)
904 rxVetoListener
->vetoableChange(event
);
905 } catch (css::lang::DisposedException
&) {}
907 for (auto& rxVetoListener
: unspecificVeto
)
910 rxVetoListener
->vetoableChange(event
);
911 } catch (css::lang::DisposedException
&) {}
914 if ((it
->second
.property
.Attributes
& css::beans::PropertyAttribute::BOUND
)
917 assert(boundListeners
!= nullptr);
918 boundListeners
->m_impl
->event
= css::beans::PropertyChangeEvent(
919 static_cast< css::beans::XPropertySet
* >(this), propertyName
,
920 false, it
->second
.property
.Handle
, oldValue
, newValue
);
924 void PropertySetMixinImpl::dispose() {
925 Impl::BoundListenerMap boundListeners
;
926 Impl::VetoListenerMap vetoListeners
;
928 std::scoped_lock
g(m_impl
->mutex
);
929 boundListeners
.swap(m_impl
->boundListeners
);
930 vetoListeners
.swap(m_impl
->vetoListeners
);
931 m_impl
->disposed
= true;
933 css::lang::EventObject
event(
934 static_cast< css::beans::XPropertySet
* >(this));
935 for (const auto& rEntry
: boundListeners
)
937 for (auto& rxBoundListener
: rEntry
.second
)
939 rxBoundListener
->disposing(event
);
942 for (const auto& rEntry
: vetoListeners
)
944 for (auto& rxVetoListener
: rEntry
.second
)
946 rxVetoListener
->disposing(event
);
951 css::uno::Any
PropertySetMixinImpl::queryInterface(css::uno::Type
const & type
)
953 if ((m_impl
->implements
& IMPLEMENTS_PROPERTY_SET
) != 0
954 && type
== cppu::UnoType
<css::beans::XPropertySet
>::get())
956 css::uno::Reference
< css::uno::XInterface
> ifc(
957 static_cast< css::beans::XPropertySet
* >(this));
958 return css::uno::Any(&ifc
, type
);
960 if ((m_impl
->implements
& IMPLEMENTS_FAST_PROPERTY_SET
) != 0
961 && type
== cppu::UnoType
<css::beans::XFastPropertySet
>::get())
963 css::uno::Reference
< css::uno::XInterface
> ifc(
964 static_cast< css::beans::XFastPropertySet
* >(this));
965 return css::uno::Any(&ifc
, type
);
967 if ((m_impl
->implements
& IMPLEMENTS_PROPERTY_ACCESS
) != 0
968 && type
== cppu::UnoType
<css::beans::XPropertyAccess
>::get())
970 css::uno::Reference
< css::uno::XInterface
> ifc(
971 static_cast< css::beans::XPropertyAccess
* >(this));
972 return css::uno::Any(&ifc
, type
);
974 return css::uno::Any();
977 css::uno::Reference
< css::beans::XPropertySetInfo
>
978 PropertySetMixinImpl::getPropertySetInfo()
980 return new Info(m_impl
);
983 void PropertySetMixinImpl::setPropertyValue(
984 OUString
const & propertyName
, css::uno::Any
const & value
)
987 static_cast< css::beans::XPropertySet
* >(this), propertyName
, value
,
991 css::uno::Any
PropertySetMixinImpl::getPropertyValue(
992 OUString
const & propertyName
)
994 return m_impl
->getProperty(
995 static_cast< css::beans::XPropertySet
* >(this), propertyName
, nullptr);
998 void PropertySetMixinImpl::addPropertyChangeListener(
999 OUString
const & propertyName
,
1000 css::uno::Reference
< css::beans::XPropertyChangeListener
> const & listener
)
1002 css::uno::Reference
< css::beans::XPropertyChangeListener
>(
1003 listener
, css::uno::UNO_SET_THROW
); // reject NULL listener
1004 checkUnknown(propertyName
);
1007 std::scoped_lock
g(m_impl
->mutex
);
1008 disposed
= m_impl
->disposed
;
1010 m_impl
->boundListeners
[propertyName
].insert(listener
);
1014 listener
->disposing(
1015 css::lang::EventObject(
1016 static_cast< css::beans::XPropertySet
* >(this)));
1020 void PropertySetMixinImpl::removePropertyChangeListener(
1021 OUString
const & propertyName
,
1022 css::uno::Reference
< css::beans::XPropertyChangeListener
> const & listener
)
1024 assert(listener
.is());
1025 checkUnknown(propertyName
);
1026 std::scoped_lock
g(m_impl
->mutex
);
1027 Impl::BoundListenerMap::iterator
i(
1028 m_impl
->boundListeners
.find(propertyName
));
1029 if (i
!= m_impl
->boundListeners
.end()) {
1030 BoundListenerBag::iterator
j(i
->second
.find(listener
));
1031 if (j
!= i
->second
.end()) {
1037 void PropertySetMixinImpl::addVetoableChangeListener(
1038 OUString
const & propertyName
,
1039 css::uno::Reference
< css::beans::XVetoableChangeListener
> const & listener
)
1041 css::uno::Reference
< css::beans::XVetoableChangeListener
>(
1042 listener
, css::uno::UNO_SET_THROW
); // reject NULL listener
1043 checkUnknown(propertyName
);
1046 std::scoped_lock
g(m_impl
->mutex
);
1047 disposed
= m_impl
->disposed
;
1049 m_impl
->vetoListeners
[propertyName
].insert(listener
);
1053 listener
->disposing(
1054 css::lang::EventObject(
1055 static_cast< css::beans::XPropertySet
* >(this)));
1059 void PropertySetMixinImpl::removeVetoableChangeListener(
1060 OUString
const & propertyName
,
1061 css::uno::Reference
< css::beans::XVetoableChangeListener
> const & listener
)
1063 assert(listener
.is());
1064 checkUnknown(propertyName
);
1065 std::scoped_lock
g(m_impl
->mutex
);
1066 Impl::VetoListenerMap::iterator
i(m_impl
->vetoListeners
.find(propertyName
));
1067 if (i
!= m_impl
->vetoListeners
.end()) {
1068 Impl::VetoListenerBag::iterator
j(i
->second
.find(listener
));
1069 if (j
!= i
->second
.end()) {
1075 void PropertySetMixinImpl::setFastPropertyValue(
1076 sal_Int32 handle
, css::uno::Any
const & value
)
1078 m_impl
->setProperty(
1079 static_cast< css::beans::XPropertySet
* >(this),
1080 m_impl
->translateHandle(
1081 static_cast< css::beans::XPropertySet
* >(this), handle
),
1082 value
, false, false, 1);
1085 css::uno::Any
PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle
)
1087 return m_impl
->getProperty(
1088 static_cast< css::beans::XPropertySet
* >(this),
1089 m_impl
->translateHandle(
1090 static_cast< css::beans::XPropertySet
* >(this), handle
),
1094 css::uno::Sequence
< css::beans::PropertyValue
>
1095 PropertySetMixinImpl::getPropertyValues()
1097 css::uno::Sequence
< css::beans::PropertyValue
> s(
1098 m_impl
->handleMap
.getLength());
1099 auto r
= asNonConstRange(s
);
1101 for (sal_Int32 i
= 0; i
< m_impl
->handleMap
.getLength(); ++i
) {
1103 r
[n
].Value
= m_impl
->getProperty(
1104 static_cast< css::beans::XPropertySet
* >(this),
1105 m_impl
->handleMap
[i
], &r
[n
].State
);
1106 } catch (css::beans::UnknownPropertyException
&) {
1108 } catch (css::lang::WrappedTargetException
& e
) {
1109 throw css::lang::WrappedTargetRuntimeException(
1110 e
.Message
, static_cast< css::beans::XPropertySet
* >(this),
1113 r
[n
].Name
= m_impl
->handleMap
[i
];
1121 void PropertySetMixinImpl::setPropertyValues(
1122 css::uno::Sequence
< css::beans::PropertyValue
> const & props
)
1124 for (const auto & p
: props
) {
1127 != m_impl
->translateHandle(
1128 static_cast< css::beans::XPropertySet
* >(this),
1131 throw css::beans::UnknownPropertyException(
1132 ("name " + p
.Name
+ " does not match handle "
1133 + OUString::number(p
.Handle
)),
1134 static_cast< css::beans::XPropertySet
* >(this));
1136 m_impl
->setProperty(
1137 static_cast< css::beans::XPropertySet
* >(this), p
.Name
,
1139 p
.State
== css::beans::PropertyState_AMBIGUOUS_VALUE
,
1140 p
.State
== css::beans::PropertyState_DEFAULT_VALUE
, 0);
1144 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */