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
) {
139 css::uno::Reference
< css::reflection::XTypeDescription
> > bases(
140 ifc
->getBaseTypes());
141 for (sal_Int32 i
= 0; i
< bases
.getLength(); ++i
) {
142 initProperties(bases
[i
], absentOptional
, handleNames
, seen
);
146 css::reflection::XInterfaceMemberTypeDescription
> > members(
148 OUString
const * absentBegin
= absentOptional
.getConstArray();
149 OUString
const * absentEnd
=
150 absentBegin
+ absentOptional
.getLength();
151 for (sal_Int32 i
= 0; i
< members
.getLength(); ++i
) {
152 if (members
[i
]->getTypeClass()
153 == css::uno::TypeClass_INTERFACE_ATTRIBUTE
)
156 css::reflection::XInterfaceAttributeTypeDescription2
> attr(
157 members
[i
], css::uno::UNO_QUERY_THROW
);
158 sal_Int16 attrAttribs
= 0;
159 if (attr
->isBound()) {
160 attrAttribs
|= css::beans::PropertyAttribute::BOUND
;
162 bool bSetUnknown
= false;
163 if (attr
->isReadOnly()) {
164 attrAttribs
|= css::beans::PropertyAttribute::READONLY
;
169 css::reflection::XCompoundTypeDescription
> > excs(
170 attr
->getGetExceptions());
171 bool bGetUnknown
= false;
172 //XXX Special interpretation of getter/setter exceptions only
173 // works if the specified exceptions are of the exact type, not
175 for (sal_Int32 j
= 0; j
< excs
.getLength(); ++j
) {
176 if ( excs
[j
]->getName() == "com.sun.star.beans.UnknownPropertyException" )
182 excs
= attr
->getSetExceptions();
183 for (sal_Int32 j
= 0; j
< excs
.getLength(); ++j
) {
184 if ( excs
[j
]->getName() == "com.sun.star.beans.UnknownPropertyException" )
187 } else if ( excs
[j
]->getName() == "com.sun.star.beans.PropertyVetoException" )
190 |= css::beans::PropertyAttribute::CONSTRAINED
;
193 if (bGetUnknown
&& bSetUnknown
) {
194 attrAttribs
|= css::beans::PropertyAttribute::OPTIONAL
;
196 css::uno::Reference
< css::reflection::XTypeDescription
> t(
200 t
= resolveTypedefs(t
);
202 if (t
->getName().startsWith(
203 "com.sun.star.beans.Ambiguous<"))
205 n
= css::beans::PropertyAttribute::MAYBEAMBIGUOUS
;
206 } else if (t
->getName().startsWith(
207 "com.sun.star.beans.Defaulted<"))
209 n
= css::beans::PropertyAttribute::MAYBEDEFAULT
;
210 } else if (t
->getName().startsWith(
211 "com.sun.star.beans.Optional<"))
213 n
= css::beans::PropertyAttribute::MAYBEVOID
;
217 if ((attrAttribs
& n
) != 0) {
222 css::uno::Reference
< css::reflection::XTypeDescription
> >
225 css::reflection::XStructTypeDescription
>(
226 t
, css::uno::UNO_QUERY_THROW
)->
228 if (args
.getLength() != 1) {
229 throw css::uno::RuntimeException(
230 "inconsistent UNO type registry");
234 std::vector
< OUString
>::size_type handles
235 = handleNames
->size();
236 if (handles
> SAL_MAX_INT32
) {
237 throw css::uno::RuntimeException(
238 "interface type has too many attributes");
240 OUString
name(members
[i
]->getMemberName());
241 if (!properties
.emplace(
244 css::beans::Property(
245 name
, static_cast< sal_Int32
>(handles
),
247 t
->getTypeClass(), t
->getName()),
249 (std::find(absentBegin
, absentEnd
, name
)
253 throw css::uno::RuntimeException(
254 "inconsistent UNO type registry");
256 handleNames
->push_back(name
);
262 css::uno::Reference
< css::reflection::XTypeDescription
> Data::resolveTypedefs(
263 css::uno::Reference
< css::reflection::XTypeDescription
> const & type
)
265 css::uno::Reference
< css::reflection::XTypeDescription
> t(type
);
266 while (t
->getTypeClass() == css::uno::TypeClass_TYPEDEF
) {
267 t
= css::uno::Reference
< css::reflection::XIndirectTypeDescription
>(
268 t
, css::uno::UNO_QUERY_THROW
)->getReferencedType();
273 class Info
: public cppu::WeakImplHelper
< css::beans::XPropertySetInfo
> {
275 explicit Info(Data
* data
): m_data(data
) {}
277 virtual css::uno::Sequence
< css::beans::Property
> SAL_CALL
getProperties() override
;
279 virtual css::beans::Property SAL_CALL
getPropertyByName(
280 OUString
const & name
) override
;
282 virtual sal_Bool SAL_CALL
hasPropertyByName(OUString
const & name
) override
;
285 rtl::Reference
< Data
> m_data
;
288 css::uno::Sequence
< css::beans::Property
> Info::getProperties()
290 assert(m_data
->properties
.size() <= SAL_MAX_INT32
);
291 css::uno::Sequence
< css::beans::Property
> s(
292 static_cast< sal_Int32
>(m_data
->properties
.size()));
294 for (const auto& rEntry
: m_data
->properties
)
296 if (rEntry
.second
.present
) {
297 s
[n
++] = rEntry
.second
.property
;
304 css::beans::Property
Info::getPropertyByName(OUString
const & name
)
306 return m_data
->get(static_cast< cppu::OWeakObject
* >(this), name
)->
310 sal_Bool
Info::hasPropertyByName(OUString
const & name
)
312 Data::PropertyMap::iterator
i(m_data
->properties
.find(name
));
313 return i
!= m_data
->properties
.end() && i
->second
.present
;
317 std::multiset
< css::uno::Reference
< css::beans::XPropertyChangeListener
> >
322 class PropertySetMixinImpl::BoundListeners::Impl
{
324 BoundListenerBag specificListeners
;
325 BoundListenerBag unspecificListeners
;
326 css::beans::PropertyChangeEvent event
;
329 PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl
) {}
331 PropertySetMixinImpl::BoundListeners::~BoundListeners() {
335 void PropertySetMixinImpl::BoundListeners::notify() const {
336 for (const auto& rxListener
: m_impl
->specificListeners
)
339 rxListener
->propertyChange(m_impl
->event
);
340 } catch (css::lang::DisposedException
&) {}
342 for (const auto& rxListener
: m_impl
->unspecificListeners
)
345 rxListener
->propertyChange(m_impl
->event
);
346 } catch (css::lang::DisposedException
&) {}
350 class PropertySetMixinImpl::Impl
: public Data
{
353 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
354 Implements theImplements
,
355 css::uno::Sequence
< OUString
> const & absentOptional
,
356 css::uno::Type
const & type
);
358 OUString
const & translateHandle(
359 css::uno::Reference
< css::uno::XInterface
> const & object
,
360 sal_Int32 handle
) const;
363 css::uno::Reference
< css::uno::XInterface
> const & object
,
364 OUString
const & name
, css::uno::Any
const & value
,
365 bool isAmbiguous
, bool isDefaulted
, sal_Int16 illegalArgumentPosition
)
368 css::uno::Any
getProperty(
369 css::uno::Reference
< css::uno::XInterface
> const & object
,
370 OUString
const & name
, css::beans::PropertyState
* state
) const;
372 PropertySetMixinImpl::Implements implements
;
373 css::uno::Sequence
< OUString
> handleMap
;
375 typedef std::map
< OUString
, BoundListenerBag
> BoundListenerMap
;
378 std::multiset
< css::uno::Reference
< css::beans::XVetoableChangeListener
> >
381 typedef std::map
< OUString
, VetoListenerBag
> VetoListenerMap
;
383 mutable osl::Mutex mutex
;
384 BoundListenerMap boundListeners
;
385 VetoListenerMap vetoListeners
;
389 css::uno::Reference
< css::reflection::XIdlClass
> getReflection(
390 OUString
const & typeName
) const;
392 static css::uno::Any
wrapValue(
393 css::uno::Reference
< css::uno::XInterface
> const & object
,
394 css::uno::Any
const & value
,
395 css::uno::Reference
< css::reflection::XIdlClass
> const & type
,
396 bool wrapAmbiguous
, bool isAmbiguous
, bool wrapDefaulted
,
397 bool isDefaulted
, bool wrapOptional
);
399 css::uno::Reference
< css::uno::XComponentContext
> const & m_context
;
400 css::uno::Type m_type
;
401 css::uno::Reference
< css::reflection::XIdlClass
> m_idlClass
;
404 PropertySetMixinImpl::Impl::Impl(
405 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
406 Implements theImplements
,
407 css::uno::Sequence
< OUString
> const & absentOptional
,
408 css::uno::Type
const & type
):
409 implements(theImplements
), disposed(false), m_context(context
),
412 assert(context
.is());
415 & ~(IMPLEMENTS_PROPERTY_SET
| IMPLEMENTS_FAST_PROPERTY_SET
416 | IMPLEMENTS_PROPERTY_ACCESS
))
418 m_idlClass
= getReflection(m_type
.getTypeName());
419 css::uno::Reference
< css::reflection::XTypeDescription
> ifc
;
422 css::uno::Reference
< css::container::XHierarchicalNameAccess
>(
423 m_context
->getValueByName(
424 "/singletons/com.sun.star.reflection."
425 "theTypeDescriptionManager"),
426 css::uno::UNO_QUERY_THROW
)->getByHierarchicalName(
427 m_type
.getTypeName()),
428 css::uno::UNO_QUERY_THROW
);
429 } catch (css::container::NoSuchElementException
& e
) {
430 css::uno::Any anyEx
= cppu::getCaughtException();
431 throw css::lang::WrappedTargetRuntimeException(
432 "unexpected com.sun.star.container.NoSuchElementException: "
436 std::vector
< OUString
> handleNames
;
437 initProperties(ifc
, absentOptional
, &handleNames
);
438 std::vector
< OUString
>::size_type size
= handleNames
.size();
439 assert(size
<= SAL_MAX_INT32
);
440 handleMap
.realloc(static_cast< sal_Int32
>(size
));
441 std::copy(handleNames
.begin(), handleNames
.end(), handleMap
.getArray());
444 OUString
const & PropertySetMixinImpl::Impl::translateHandle(
445 css::uno::Reference
< css::uno::XInterface
> const & object
,
446 sal_Int32 handle
) const
448 if (handle
< 0 || handle
>= handleMap
.getLength()) {
449 throw css::beans::UnknownPropertyException(
450 "bad handle " + OUString::number(handle
), object
);
452 return handleMap
[handle
];
455 void PropertySetMixinImpl::Impl::setProperty(
456 css::uno::Reference
< css::uno::XInterface
> const & object
,
457 OUString
const & name
, css::uno::Any
const & value
, bool isAmbiguous
,
458 bool isDefaulted
, sal_Int16 illegalArgumentPosition
) const
460 PropertyMap::const_iterator
i(properties
.find(name
));
461 if (i
== properties
.end()) {
462 throw css::beans::UnknownPropertyException(name
, object
);
465 && ((i
->second
.property
.Attributes
466 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
469 && ((i
->second
.property
.Attributes
470 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
473 throw css::lang::IllegalArgumentException(
474 ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
476 object
, illegalArgumentPosition
);
478 css::uno::Reference
< css::reflection::XIdlField2
> f(
479 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
);
480 css::uno::Any
o(object
->queryInterface(m_type
));
484 (css::uno::Reference
< css::reflection::XIdlField2
>(
485 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
)->
487 ((i
->second
.property
.Attributes
488 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
491 ((i
->second
.property
.Attributes
492 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
495 ((i
->second
.property
.Attributes
496 & css::beans::PropertyAttribute::MAYBEVOID
)
500 } catch (css::lang::IllegalArgumentException
& e
) {
501 if (e
.ArgumentPosition
== 1) {
502 throw css::lang::IllegalArgumentException(
503 e
.Message
, object
, illegalArgumentPosition
);
505 css::uno::Any anyEx
= cppu::getCaughtException();
506 throw css::lang::WrappedTargetRuntimeException(
507 "unexpected com.sun.star.lang.IllegalArgumentException: "
511 } catch (css::lang::IllegalAccessException
&) {
512 //TODO Clarify whether PropertyVetoException is the correct exception
513 // to throw when trying to set a read-only property:
514 throw css::beans::PropertyVetoException(
515 "cannot set read-only property " + name
, object
);
516 } catch (css::lang::WrappedTargetRuntimeException
& e
) {
517 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
518 // guaranteed to originate directly within XIdlField2.get (and thus have
519 // the expected semantics); it might also be passed through from lower
521 if (e
.TargetException
.isExtractableTo(
522 cppu::UnoType
<css::beans::UnknownPropertyException
>::get())
523 && ((i
->second
.property
.Attributes
524 & css::beans::PropertyAttribute::OPTIONAL
)
527 throw css::beans::UnknownPropertyException(name
, object
);
528 } else if (e
.TargetException
.isExtractableTo(
529 cppu::UnoType
<css::beans::PropertyVetoException
>::get())
530 && ((i
->second
.property
.Attributes
531 & css::beans::PropertyAttribute::CONSTRAINED
)
534 css::beans::PropertyVetoException exc
;
535 e
.TargetException
>>= exc
;
536 if (exc
.Message
.isEmpty() )
537 throw css::beans::PropertyVetoException("Invalid " + name
, object
);
541 throw css::lang::WrappedTargetException(
542 e
.Message
, object
, e
.TargetException
);
547 css::uno::Any
PropertySetMixinImpl::Impl::getProperty(
548 css::uno::Reference
< css::uno::XInterface
> const & object
,
549 OUString
const & name
, css::beans::PropertyState
* state
) const
551 PropertyMap::const_iterator
i(properties
.find(name
));
552 if (i
== properties
.end()) {
553 throw css::beans::UnknownPropertyException(name
, object
);
555 css::uno::Reference
< css::reflection::XIdlField2
> field(
556 m_idlClass
->getField(name
), css::uno::UNO_QUERY_THROW
);
559 value
= field
->get(object
->queryInterface(m_type
));
560 } catch (css::lang::IllegalArgumentException
& e
) {
561 css::uno::Any anyEx
= cppu::getCaughtException();
562 throw css::lang::WrappedTargetRuntimeException(
563 "unexpected com.sun.star.lang.IllegalArgumentException: "
566 } catch (css::lang::WrappedTargetRuntimeException
& e
) {
567 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
568 // guaranteed to originate directly within XIdlField2.get (and thus have
569 // the expected semantics); it might also be passed through from lower
571 if (e
.TargetException
.isExtractableTo(
572 cppu::UnoType
<css::beans::UnknownPropertyException
>::get())
573 && ((i
->second
.property
.Attributes
574 & css::beans::PropertyAttribute::OPTIONAL
)
577 throw css::beans::UnknownPropertyException(name
, object
);
579 throw css::lang::WrappedTargetException(
580 e
.Message
, object
, e
.TargetException
);
584 = ((i
->second
.property
.Attributes
585 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS
)
588 = ((i
->second
.property
.Attributes
589 & css::beans::PropertyAttribute::MAYBEDEFAULT
)
592 = ((i
->second
.property
.Attributes
593 & css::beans::PropertyAttribute::MAYBEVOID
)
595 bool isAmbiguous
= false;
596 bool isDefaulted
= false;
597 while (undoAmbiguous
|| undoDefaulted
|| undoOptional
) {
599 && value
.getValueTypeName().startsWith(
600 "com.sun.star.beans.Ambiguous<"))
602 css::uno::Reference
< css::reflection::XIdlClass
> ambiguous(
603 getReflection(value
.getValueTypeName()));
605 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
606 ambiguous
->getField("IsAmbiguous"),
607 css::uno::UNO_QUERY_THROW
)->get(value
)
610 throw css::uno::RuntimeException(
611 ("unexpected type of com.sun.star.beans.Ambiguous"
612 " IsAmbiguous member"),
615 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
616 ambiguous
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
618 } catch (css::lang::IllegalArgumentException
& e
) {
619 css::uno::Any anyEx
= cppu::getCaughtException();
620 throw css::lang::WrappedTargetRuntimeException(
621 "unexpected com.sun.star.lang.IllegalArgumentException: "
625 undoAmbiguous
= false;
626 } else if (undoDefaulted
627 && value
.getValueTypeName().startsWith(
628 "com.sun.star.beans.Defaulted<"))
630 css::uno::Reference
< css::reflection::XIdlClass
> defaulted(
631 getReflection(value
.getValueTypeName()));
634 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
635 defaulted
->getField("IsDefaulted"),
636 css::uno::UNO_QUERY_THROW
)->get(value
)
639 throw css::uno::RuntimeException(
640 ("unexpected type of com.sun.star.beans.Defaulted"
641 " IsDefaulted member"),
644 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
645 defaulted
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
647 } catch (css::lang::IllegalArgumentException
& e
) {
648 css::uno::Any anyEx
= cppu::getCaughtException();
649 throw css::lang::WrappedTargetRuntimeException(
650 "unexpected com.sun.star.lang.IllegalArgumentException: "
654 undoDefaulted
= false;
655 } else if (undoOptional
656 && value
.getValueTypeName().startsWith(
657 "com.sun.star.beans.Optional<"))
659 css::uno::Reference
< css::reflection::XIdlClass
> optional(
660 getReflection(value
.getValueTypeName()));
662 bool present
= false;
663 if (!(css::uno::Reference
< css::reflection::XIdlField2
>(
664 optional
->getField("IsPresent"),
665 css::uno::UNO_QUERY_THROW
)->get(value
)
668 throw css::uno::RuntimeException(
669 ("unexpected type of com.sun.star.beans.Optional"
670 " IsPresent member"),
677 value
= css::uno::Reference
< css::reflection::XIdlField2
>(
678 optional
->getField("Value"), css::uno::UNO_QUERY_THROW
)->
680 } catch (css::lang::IllegalArgumentException
& e
) {
681 css::uno::Any anyEx
= cppu::getCaughtException();
682 throw css::lang::WrappedTargetRuntimeException(
683 "unexpected com.sun.star.lang.IllegalArgumentException: "
687 undoOptional
= false;
689 throw css::uno::RuntimeException(
690 "unexpected type of attribute " + name
, object
);
693 if (state
!= nullptr) {
694 //XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE
695 // over DEFAULT_VALUE:
697 ? css::beans::PropertyState_AMBIGUOUS_VALUE
699 ? css::beans::PropertyState_DEFAULT_VALUE
700 : css::beans::PropertyState_DIRECT_VALUE
;
705 css::uno::Reference
< css::reflection::XIdlClass
>
706 PropertySetMixinImpl::Impl::getReflection(OUString
const & typeName
) const
708 return css::uno::Reference
< css::reflection::XIdlClass
>(
709 css::reflection::theCoreReflection::get(m_context
)->forName(typeName
),
710 css::uno::UNO_SET_THROW
);
713 css::uno::Any
PropertySetMixinImpl::Impl::wrapValue(
714 css::uno::Reference
< css::uno::XInterface
> const & object
,
715 css::uno::Any
const & value
,
716 css::uno::Reference
< css::reflection::XIdlClass
> const & type
,
717 bool wrapAmbiguous
, bool isAmbiguous
, bool wrapDefaulted
, bool isDefaulted
,
720 assert(wrapAmbiguous
|| !isAmbiguous
);
721 assert(wrapDefaulted
|| !isDefaulted
);
723 && type
->getName().startsWith("com.sun.star.beans.Ambiguous<"))
726 type
->createObject(strct
);
728 css::uno::Reference
< css::reflection::XIdlField2
> field(
729 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
733 object
, value
, field
->getType(), false, false,
734 wrapDefaulted
, isDefaulted
, wrapOptional
));
735 css::uno::Reference
< css::reflection::XIdlField2
>(
736 type
->getField("IsAmbiguous"), css::uno::UNO_QUERY_THROW
)->set(
737 strct
, css::uno::Any(isAmbiguous
));
738 } catch (css::lang::IllegalArgumentException
& e
) {
739 css::uno::Any anyEx
= cppu::getCaughtException();
740 throw css::lang::WrappedTargetRuntimeException(
741 "unexpected com.sun.star.lang.IllegalArgumentException: "
744 } catch (css::lang::IllegalAccessException
& e
) {
745 css::uno::Any anyEx
= cppu::getCaughtException();
746 throw css::lang::WrappedTargetRuntimeException(
747 "unexpected com.sun.star.lang.IllegalAccessException: "
754 && type
->getName().startsWith("com.sun.star.beans.Defaulted<"))
757 type
->createObject(strct
);
759 css::uno::Reference
< css::reflection::XIdlField2
> field(
760 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
764 object
, value
, field
->getType(), wrapAmbiguous
, isAmbiguous
,
765 false, false, wrapOptional
));
766 css::uno::Reference
< css::reflection::XIdlField2
>(
767 type
->getField("IsDefaulted"), css::uno::UNO_QUERY_THROW
)->set(
768 strct
, css::uno::Any(isDefaulted
));
769 } catch (css::lang::IllegalArgumentException
& e
) {
770 css::uno::Any anyEx
= cppu::getCaughtException();
771 throw css::lang::WrappedTargetRuntimeException(
772 "unexpected com.sun.star.lang.IllegalArgumentException: "
775 } catch (css::lang::IllegalAccessException
& e
) {
776 css::uno::Any anyEx
= cppu::getCaughtException();
777 throw css::lang::WrappedTargetRuntimeException(
778 "unexpected com.sun.star.lang.IllegalAccessException: "
785 && type
->getName().startsWith("com.sun.star.beans.Optional<"))
788 type
->createObject(strct
);
789 bool present
= value
.hasValue();
791 css::uno::Reference
< css::reflection::XIdlField2
>(
792 type
->getField("IsPresent"), css::uno::UNO_QUERY_THROW
)->set(
793 strct
, css::uno::Any(present
));
795 css::uno::Reference
< css::reflection::XIdlField2
> field(
796 type
->getField("Value"), css::uno::UNO_QUERY_THROW
);
800 object
, value
, field
->getType(), wrapAmbiguous
,
801 isAmbiguous
, wrapDefaulted
, isDefaulted
, false));
803 } catch (css::lang::IllegalArgumentException
& e
) {
804 css::uno::Any anyEx
= cppu::getCaughtException();
805 throw css::lang::WrappedTargetRuntimeException(
806 "unexpected com.sun.star.lang.IllegalArgumentException: "
809 } catch (css::lang::IllegalAccessException
& e
) {
810 css::uno::Any anyEx
= cppu::getCaughtException();
811 throw css::lang::WrappedTargetRuntimeException(
812 "unexpected com.sun.star.lang.IllegalAccessException: "
818 if (wrapAmbiguous
|| wrapDefaulted
|| wrapOptional
) {
819 throw css::uno::RuntimeException(
820 "unexpected type of attribute", object
);
825 PropertySetMixinImpl::PropertySetMixinImpl(
826 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
827 Implements implements
,
828 css::uno::Sequence
< OUString
> const & absentOptional
,
829 css::uno::Type
const & type
)
831 m_impl
= new Impl(context
, implements
, absentOptional
, type
);
835 PropertySetMixinImpl::~PropertySetMixinImpl() {
839 void PropertySetMixinImpl::checkUnknown(OUString
const & propertyName
) {
840 if (!propertyName
.isEmpty()) {
842 static_cast< css::beans::XPropertySet
* >(this), propertyName
);
846 void PropertySetMixinImpl::prepareSet(
847 OUString
const & propertyName
, css::uno::Any
const & oldValue
,
848 css::uno::Any
const & newValue
, BoundListeners
* boundListeners
)
850 Impl::PropertyMap::const_iterator
it(m_impl
->properties
.find(propertyName
));
851 assert(it
!= m_impl
->properties
.end());
852 Impl::VetoListenerBag specificVeto
;
853 Impl::VetoListenerBag unspecificVeto
;
855 osl::MutexGuard
g(m_impl
->mutex
);
856 if (m_impl
->disposed
) {
857 throw css::lang::DisposedException(
858 "disposed", static_cast< css::beans::XPropertySet
* >(this));
860 if ((it
->second
.property
.Attributes
861 & css::beans::PropertyAttribute::CONSTRAINED
)
864 Impl::VetoListenerMap::const_iterator
i(
865 m_impl
->vetoListeners
.find(propertyName
));
866 if (i
!= m_impl
->vetoListeners
.end()) {
867 specificVeto
= i
->second
;
869 i
= m_impl
->vetoListeners
.find("");
870 if (i
!= m_impl
->vetoListeners
.end()) {
871 unspecificVeto
= i
->second
;
874 if ((it
->second
.property
.Attributes
875 & css::beans::PropertyAttribute::BOUND
)
878 assert(boundListeners
!= nullptr);
879 Impl::BoundListenerMap::const_iterator
i(
880 m_impl
->boundListeners
.find(propertyName
));
881 if (i
!= m_impl
->boundListeners
.end()) {
882 boundListeners
->m_impl
->specificListeners
= i
->second
;
884 i
= m_impl
->boundListeners
.find("");
885 if (i
!= m_impl
->boundListeners
.end()) {
886 boundListeners
->m_impl
->unspecificListeners
= i
->second
;
890 if ((it
->second
.property
.Attributes
891 & css::beans::PropertyAttribute::CONSTRAINED
)
894 css::beans::PropertyChangeEvent
event(
895 static_cast< css::beans::XPropertySet
* >(this), propertyName
,
896 false, it
->second
.property
.Handle
, oldValue
, newValue
);
897 for (auto& rxVetoListener
: specificVeto
)
900 rxVetoListener
->vetoableChange(event
);
901 } catch (css::lang::DisposedException
&) {}
903 for (auto& rxVetoListener
: unspecificVeto
)
906 rxVetoListener
->vetoableChange(event
);
907 } catch (css::lang::DisposedException
&) {}
910 if ((it
->second
.property
.Attributes
& css::beans::PropertyAttribute::BOUND
)
913 assert(boundListeners
!= nullptr);
914 boundListeners
->m_impl
->event
= css::beans::PropertyChangeEvent(
915 static_cast< css::beans::XPropertySet
* >(this), propertyName
,
916 false, it
->second
.property
.Handle
, oldValue
, newValue
);
920 void PropertySetMixinImpl::dispose() {
921 Impl::BoundListenerMap boundListeners
;
922 Impl::VetoListenerMap vetoListeners
;
924 osl::MutexGuard
g(m_impl
->mutex
);
925 boundListeners
.swap(m_impl
->boundListeners
);
926 vetoListeners
.swap(m_impl
->vetoListeners
);
927 m_impl
->disposed
= true;
929 css::lang::EventObject
event(
930 static_cast< css::beans::XPropertySet
* >(this));
931 for (const auto& rEntry
: boundListeners
)
933 for (auto& rxBoundListener
: rEntry
.second
)
935 rxBoundListener
->disposing(event
);
938 for (const auto& rEntry
: vetoListeners
)
940 for (auto& rxVetoListener
: rEntry
.second
)
942 rxVetoListener
->disposing(event
);
947 css::uno::Any
PropertySetMixinImpl::queryInterface(css::uno::Type
const & type
)
949 if ((m_impl
->implements
& IMPLEMENTS_PROPERTY_SET
) != 0
950 && type
== css::beans::XPropertySet::static_type())
952 css::uno::Reference
< css::uno::XInterface
> ifc(
953 static_cast< css::beans::XPropertySet
* >(this));
954 return css::uno::Any(&ifc
, type
);
956 if ((m_impl
->implements
& IMPLEMENTS_FAST_PROPERTY_SET
) != 0
957 && type
== css::beans::XFastPropertySet::static_type())
959 css::uno::Reference
< css::uno::XInterface
> ifc(
960 static_cast< css::beans::XFastPropertySet
* >(this));
961 return css::uno::Any(&ifc
, type
);
963 if ((m_impl
->implements
& IMPLEMENTS_PROPERTY_ACCESS
) != 0
964 && type
== css::beans::XPropertyAccess::static_type())
966 css::uno::Reference
< css::uno::XInterface
> ifc(
967 static_cast< css::beans::XPropertyAccess
* >(this));
968 return css::uno::Any(&ifc
, type
);
970 return css::uno::Any();
973 css::uno::Reference
< css::beans::XPropertySetInfo
>
974 PropertySetMixinImpl::getPropertySetInfo()
976 return new Info(m_impl
);
979 void PropertySetMixinImpl::setPropertyValue(
980 OUString
const & propertyName
, css::uno::Any
const & value
)
983 static_cast< css::beans::XPropertySet
* >(this), propertyName
, value
,
987 css::uno::Any
PropertySetMixinImpl::getPropertyValue(
988 OUString
const & propertyName
)
990 return m_impl
->getProperty(
991 static_cast< css::beans::XPropertySet
* >(this), propertyName
, nullptr);
994 void PropertySetMixinImpl::addPropertyChangeListener(
995 OUString
const & propertyName
,
996 css::uno::Reference
< css::beans::XPropertyChangeListener
> const & listener
)
998 css::uno::Reference
< css::beans::XPropertyChangeListener
>(
999 listener
, css::uno::UNO_SET_THROW
); // reject NULL listener
1000 checkUnknown(propertyName
);
1003 osl::MutexGuard
g(m_impl
->mutex
);
1004 disposed
= m_impl
->disposed
;
1006 m_impl
->boundListeners
[propertyName
].insert(listener
);
1010 listener
->disposing(
1011 css::lang::EventObject(
1012 static_cast< css::beans::XPropertySet
* >(this)));
1016 void PropertySetMixinImpl::removePropertyChangeListener(
1017 OUString
const & propertyName
,
1018 css::uno::Reference
< css::beans::XPropertyChangeListener
> const & listener
)
1020 assert(listener
.is());
1021 checkUnknown(propertyName
);
1022 osl::MutexGuard
g(m_impl
->mutex
);
1023 Impl::BoundListenerMap::iterator
i(
1024 m_impl
->boundListeners
.find(propertyName
));
1025 if (i
!= m_impl
->boundListeners
.end()) {
1026 BoundListenerBag::iterator
j(i
->second
.find(listener
));
1027 if (j
!= i
->second
.end()) {
1033 void PropertySetMixinImpl::addVetoableChangeListener(
1034 OUString
const & propertyName
,
1035 css::uno::Reference
< css::beans::XVetoableChangeListener
> const & listener
)
1037 css::uno::Reference
< css::beans::XVetoableChangeListener
>(
1038 listener
, css::uno::UNO_SET_THROW
); // reject NULL listener
1039 checkUnknown(propertyName
);
1042 osl::MutexGuard
g(m_impl
->mutex
);
1043 disposed
= m_impl
->disposed
;
1045 m_impl
->vetoListeners
[propertyName
].insert(listener
);
1049 listener
->disposing(
1050 css::lang::EventObject(
1051 static_cast< css::beans::XPropertySet
* >(this)));
1055 void PropertySetMixinImpl::removeVetoableChangeListener(
1056 OUString
const & propertyName
,
1057 css::uno::Reference
< css::beans::XVetoableChangeListener
> const & listener
)
1059 assert(listener
.is());
1060 checkUnknown(propertyName
);
1061 osl::MutexGuard
g(m_impl
->mutex
);
1062 Impl::VetoListenerMap::iterator
i(m_impl
->vetoListeners
.find(propertyName
));
1063 if (i
!= m_impl
->vetoListeners
.end()) {
1064 Impl::VetoListenerBag::iterator
j(i
->second
.find(listener
));
1065 if (j
!= i
->second
.end()) {
1071 void PropertySetMixinImpl::setFastPropertyValue(
1072 sal_Int32 handle
, css::uno::Any
const & value
)
1074 m_impl
->setProperty(
1075 static_cast< css::beans::XPropertySet
* >(this),
1076 m_impl
->translateHandle(
1077 static_cast< css::beans::XPropertySet
* >(this), handle
),
1078 value
, false, false, 1);
1081 css::uno::Any
PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle
)
1083 return m_impl
->getProperty(
1084 static_cast< css::beans::XPropertySet
* >(this),
1085 m_impl
->translateHandle(
1086 static_cast< css::beans::XPropertySet
* >(this), handle
),
1090 css::uno::Sequence
< css::beans::PropertyValue
>
1091 PropertySetMixinImpl::getPropertyValues()
1093 css::uno::Sequence
< css::beans::PropertyValue
> s(
1094 m_impl
->handleMap
.getLength());
1096 for (sal_Int32 i
= 0; i
< m_impl
->handleMap
.getLength(); ++i
) {
1098 s
[n
].Value
= m_impl
->getProperty(
1099 static_cast< css::beans::XPropertySet
* >(this),
1100 m_impl
->handleMap
[i
], &s
[n
].State
);
1101 } catch (css::beans::UnknownPropertyException
&) {
1103 } catch (css::lang::WrappedTargetException
& e
) {
1104 throw css::lang::WrappedTargetRuntimeException(
1105 e
.Message
, static_cast< css::beans::XPropertySet
* >(this),
1108 s
[n
].Name
= m_impl
->handleMap
[i
];
1116 void PropertySetMixinImpl::setPropertyValues(
1117 css::uno::Sequence
< css::beans::PropertyValue
> const & props
)
1119 for (sal_Int32 i
= 0; i
< props
.getLength(); ++i
) {
1120 if (props
[i
].Handle
!= -1
1122 != m_impl
->translateHandle(
1123 static_cast< css::beans::XPropertySet
* >(this),
1126 throw css::beans::UnknownPropertyException(
1127 ("name " + props
[i
].Name
+ " does not match handle "
1128 + OUString::number(props
[i
].Handle
)),
1129 static_cast< css::beans::XPropertySet
* >(this));
1131 m_impl
->setProperty(
1132 static_cast< css::beans::XPropertySet
* >(this), props
[i
].Name
,
1134 props
[i
].State
== css::beans::PropertyState_AMBIGUOUS_VALUE
,
1135 props
[i
].State
== css::beans::PropertyState_DEFAULT_VALUE
, 0);
1139 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */