nss: makefile bitrot: no need for android spcial case anymore
[LibreOffice.git] / cppuhelper / source / propertysetmixin.cxx
blobc7c8154896a48f9156ee77a8da02573f0bc4edae
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <algorithm>
23 #include <cassert>
24 #include <map>
25 #include <set>
26 #include <vector>
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;
78 namespace {
80 struct PropertyData {
81 explicit PropertyData(
82 css::beans::Property const & theProperty, bool thePresent):
83 property(theProperty), present(thePresent) {}
85 css::beans::Property property;
86 bool present;
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;
98 protected:
99 void initProperties(
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);
108 private:
109 void initProperties(
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 >
115 resolveTypedefs(
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);
127 return i;
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)
138 return;
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<
147 css::uno::Reference<
148 css::reflection::XInterfaceMemberTypeDescription > > members(
149 ifc->getMembers());
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)
157 css::uno::Reference<
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;
167 bSetUnknown = true;
169 css::uno::Sequence<
170 css::uno::Reference<
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
176 // of a supertype:
177 for (const auto & ex : std::as_const(excs)) {
178 if ( ex->getName() == "com.sun.star.beans.UnknownPropertyException" )
180 bGetUnknown = true;
181 break;
184 excs = attr->getSetExceptions();
185 for (const auto & ex : std::as_const(excs)) {
186 if ( ex->getName() == "com.sun.star.beans.UnknownPropertyException" )
188 bSetUnknown = true;
189 } else if ( ex->getName() == "com.sun.star.beans.PropertyVetoException" )
191 attrAttribs
192 |= css::beans::PropertyAttribute::CONSTRAINED;
195 if (bGetUnknown && bSetUnknown) {
196 attrAttribs |= css::beans::PropertyAttribute::OPTIONAL;
198 css::uno::Reference< css::reflection::XTypeDescription > t(
199 attr->getType());
200 for (;;)
202 t = resolveTypedefs(t);
203 sal_Int16 n;
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;
216 } else {
217 break;
219 if ((attrAttribs & n) != 0) {
220 break;
222 attrAttribs |= n;
223 css::uno::Sequence<
224 css::uno::Reference< css::reflection::XTypeDescription > >
225 args(
226 css::uno::Reference<
227 css::reflection::XStructTypeDescription >(
228 t, css::uno::UNO_QUERY_THROW)->
229 getTypeArguments());
230 if (args.getLength() != 1) {
231 throw css::uno::RuntimeException(
232 "inconsistent UNO type registry");
234 t = args[0];
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(
244 name,
245 PropertyData(
246 css::beans::Property(
247 name, static_cast< sal_Int32 >(handles),
248 css::uno::Type(
249 t->getTypeClass(), t->getName()),
250 attrAttribs),
251 (std::find(absentBegin, absentEnd, name)
252 == absentEnd))).
253 second)
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();
271 return t;
274 class Info: public cppu::WeakImplHelper< css::beans::XPropertySetInfo > {
275 public:
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;
285 private:
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()));
294 sal_Int32 n = 0;
295 for (const auto& rEntry : m_data->properties)
297 if (rEntry.second.present) {
298 s[n++] = rEntry.second.property;
301 s.realloc(n);
302 return s;
305 css::beans::Property Info::getPropertyByName(OUString const & name)
307 return m_data->get(static_cast< cppu::OWeakObject * >(this), name)->
308 second.property;
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;
317 typedef
318 std::multiset< css::uno::Reference< css::beans::XPropertyChangeListener > >
319 BoundListenerBag;
323 class PropertySetMixinImpl::BoundListeners::Impl {
324 public:
325 BoundListenerBag specificListeners;
326 BoundListenerBag unspecificListeners;
327 css::beans::PropertyChangeEvent event;
330 PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl) {}
332 PropertySetMixinImpl::BoundListeners::~BoundListeners() {
333 delete m_impl;
336 void PropertySetMixinImpl::BoundListeners::notify() const {
337 for (const auto& rxListener : m_impl->specificListeners)
339 try {
340 rxListener->propertyChange(m_impl->event);
341 } catch (css::lang::DisposedException &) {}
343 for (const auto& rxListener : m_impl->unspecificListeners)
345 try {
346 rxListener->propertyChange(m_impl->event);
347 } catch (css::lang::DisposedException &) {}
351 class PropertySetMixinImpl::Impl: public Data {
352 public:
353 Impl(
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;
363 void setProperty(
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)
367 const;
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;
378 typedef
379 std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > >
380 VetoListenerBag;
382 typedef std::map< OUString, VetoListenerBag > VetoListenerMap;
384 mutable osl::Mutex mutex;
385 BoundListenerMap boundListeners;
386 VetoListenerMap vetoListeners;
387 bool disposed;
389 private:
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),
411 m_type(type)
413 assert(context.is());
414 assert(
415 (implements
416 & ~(IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET
417 | IMPLEMENTS_PROPERTY_ACCESS))
418 == 0);
419 m_idlClass = getReflection(m_type.getTypeName());
420 css::uno::Reference< css::reflection::XTypeDescription > ifc;
421 try {
422 ifc.set(
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: "
434 + e.Message,
435 nullptr, anyEx );
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);
465 if ((isAmbiguous
466 && ((i->second.property.Attributes
467 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
468 == 0))
469 || (isDefaulted
470 && ((i->second.property.Attributes
471 & css::beans::PropertyAttribute::MAYBEDEFAULT)
472 == 0)))
474 throw css::lang::IllegalArgumentException(
475 ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
476 + name),
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));
482 css::uno::Any v(
483 wrapValue(
484 object, value,
485 (css::uno::Reference< css::reflection::XIdlField2 >(
486 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW)->
487 getType()),
488 ((i->second.property.Attributes
489 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
490 != 0),
491 isAmbiguous,
492 ((i->second.property.Attributes
493 & css::beans::PropertyAttribute::MAYBEDEFAULT)
494 != 0),
495 isDefaulted,
496 ((i->second.property.Attributes
497 & css::beans::PropertyAttribute::MAYBEVOID)
498 != 0)));
499 try {
500 f->set(o, v);
501 } catch (css::lang::IllegalArgumentException & e) {
502 if (e.ArgumentPosition == 1) {
503 throw css::lang::IllegalArgumentException(
504 e.Message, object, illegalArgumentPosition);
505 } else {
506 css::uno::Any anyEx = cppu::getCaughtException();
507 throw css::lang::WrappedTargetRuntimeException(
508 "unexpected com.sun.star.lang.IllegalArgumentException: "
509 + e.Message,
510 object, anyEx );
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
521 // layers.
522 if (e.TargetException.isExtractableTo(
523 cppu::UnoType<css::beans::UnknownPropertyException>::get())
524 && ((i->second.property.Attributes
525 & css::beans::PropertyAttribute::OPTIONAL)
526 != 0))
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)
533 != 0))
535 css::beans::PropertyVetoException exc;
536 e.TargetException >>= exc;
537 if (exc.Message.isEmpty() )
538 throw css::beans::PropertyVetoException("Invalid " + name, object);
539 else
540 throw exc;
541 } else {
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);
558 css::uno::Any value;
559 try {
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: "
565 + e.Message,
566 object, anyEx );
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
571 // layers.
572 if (e.TargetException.isExtractableTo(
573 cppu::UnoType<css::beans::UnknownPropertyException>::get())
574 && ((i->second.property.Attributes
575 & css::beans::PropertyAttribute::OPTIONAL)
576 != 0))
578 throw css::beans::UnknownPropertyException(name, object);
579 } else {
580 throw css::lang::WrappedTargetException(
581 e.Message, object, e.TargetException);
584 bool undoAmbiguous
585 = ((i->second.property.Attributes
586 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
587 != 0);
588 bool undoDefaulted
589 = ((i->second.property.Attributes
590 & css::beans::PropertyAttribute::MAYBEDEFAULT)
591 != 0);
592 bool undoOptional
593 = ((i->second.property.Attributes
594 & css::beans::PropertyAttribute::MAYBEVOID)
595 != 0);
596 bool isAmbiguous = false;
597 bool isDefaulted = false;
598 while (undoAmbiguous || undoDefaulted || undoOptional) {
599 if (undoAmbiguous
600 && value.getValueTypeName().startsWith(
601 "com.sun.star.beans.Ambiguous<"))
603 css::uno::Reference< css::reflection::XIdlClass > ambiguous(
604 getReflection(value.getValueTypeName()));
605 try {
606 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
607 ambiguous->getField("IsAmbiguous"),
608 css::uno::UNO_QUERY_THROW)->get(value)
609 >>= isAmbiguous))
611 throw css::uno::RuntimeException(
612 ("unexpected type of com.sun.star.beans.Ambiguous"
613 " IsAmbiguous member"),
614 object);
616 value = css::uno::Reference< css::reflection::XIdlField2 >(
617 ambiguous->getField("Value"), css::uno::UNO_QUERY_THROW)->
618 get(value);
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: "
623 + e.Message,
624 object, anyEx );
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()));
633 try {
635 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
636 defaulted->getField("IsDefaulted"),
637 css::uno::UNO_QUERY_THROW)->get(value)
638 >>= isDefaulted))
640 throw css::uno::RuntimeException(
641 ("unexpected type of com.sun.star.beans.Defaulted"
642 " IsDefaulted member"),
643 object);
645 value = css::uno::Reference< css::reflection::XIdlField2 >(
646 defaulted->getField("Value"), css::uno::UNO_QUERY_THROW)->
647 get(value);
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: "
652 + e.Message,
653 object, anyEx );
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()));
662 try {
663 bool present = false;
664 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
665 optional->getField("IsPresent"),
666 css::uno::UNO_QUERY_THROW)->get(value)
667 >>= present))
669 throw css::uno::RuntimeException(
670 ("unexpected type of com.sun.star.beans.Optional"
671 " IsPresent member"),
672 object);
674 if (!present) {
675 value.clear();
676 break;
678 value = css::uno::Reference< css::reflection::XIdlField2 >(
679 optional->getField("Value"), css::uno::UNO_QUERY_THROW)->
680 get(value);
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: "
685 + e.Message,
686 object, anyEx );
688 undoOptional = false;
689 } else {
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:
697 *state = isAmbiguous
698 ? css::beans::PropertyState_AMBIGUOUS_VALUE
699 : isDefaulted
700 ? css::beans::PropertyState_DEFAULT_VALUE
701 : css::beans::PropertyState_DIRECT_VALUE;
703 return 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,
719 bool wrapOptional)
721 assert(wrapAmbiguous || !isAmbiguous);
722 assert(wrapDefaulted || !isDefaulted);
723 if (wrapAmbiguous
724 && type->getName().startsWith("com.sun.star.beans.Ambiguous<"))
726 css::uno::Any strct;
727 type->createObject(strct);
728 try {
729 css::uno::Reference< css::reflection::XIdlField2 > field(
730 type->getField("Value"), css::uno::UNO_QUERY_THROW);
731 field->set(
732 strct,
733 wrapValue(
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: "
743 + e.Message,
744 object, anyEx );
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: "
749 + e.Message,
750 object, anyEx );
752 return strct;
754 if (wrapDefaulted
755 && type->getName().startsWith("com.sun.star.beans.Defaulted<"))
757 css::uno::Any strct;
758 type->createObject(strct);
759 try {
760 css::uno::Reference< css::reflection::XIdlField2 > field(
761 type->getField("Value"), css::uno::UNO_QUERY_THROW);
762 field->set(
763 strct,
764 wrapValue(
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: "
774 + e.Message,
775 object, anyEx );
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: "
780 + e.Message,
781 object, anyEx );
783 return strct;
785 if (wrapOptional
786 && type->getName().startsWith("com.sun.star.beans.Optional<"))
788 css::uno::Any strct;
789 type->createObject(strct);
790 bool present = value.hasValue();
791 try {
792 css::uno::Reference< css::reflection::XIdlField2 >(
793 type->getField("IsPresent"), css::uno::UNO_QUERY_THROW)->set(
794 strct, css::uno::Any(present));
795 if (present) {
796 css::uno::Reference< css::reflection::XIdlField2 > field(
797 type->getField("Value"), css::uno::UNO_QUERY_THROW);
798 field->set(
799 strct,
800 wrapValue(
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: "
808 + e.Message,
809 object, anyEx );
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: "
814 + e.Message,
815 object, anyEx );
817 return strct;
819 if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
820 throw css::uno::RuntimeException(
821 "unexpected type of attribute", object);
823 return value;
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);
833 m_impl->acquire();
836 PropertySetMixinImpl::~PropertySetMixinImpl() {
837 m_impl->release();
840 void PropertySetMixinImpl::checkUnknown(OUString const & propertyName) {
841 if (!propertyName.isEmpty()) {
842 m_impl->get(
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)
863 != 0)
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)
877 != 0)
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)
893 != 0)
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)
900 try {
901 rxVetoListener->vetoableChange(event);
902 } catch (css::lang::DisposedException &) {}
904 for (auto& rxVetoListener : unspecificVeto)
906 try {
907 rxVetoListener->vetoableChange(event);
908 } catch (css::lang::DisposedException &) {}
911 if ((it->second.property.Attributes & css::beans::PropertyAttribute::BOUND)
912 != 0)
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)
983 m_impl->setProperty(
984 static_cast< css::beans::XPropertySet * >(this), propertyName, value,
985 false, false, 1);
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);
1002 bool disposed;
1004 osl::MutexGuard g(m_impl->mutex);
1005 disposed = m_impl->disposed;
1006 if (!disposed) {
1007 m_impl->boundListeners[propertyName].insert(listener);
1010 if (disposed) {
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()) {
1029 i->second.erase(j);
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);
1041 bool disposed;
1043 osl::MutexGuard g(m_impl->mutex);
1044 disposed = m_impl->disposed;
1045 if (!disposed) {
1046 m_impl->vetoListeners[propertyName].insert(listener);
1049 if (disposed) {
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()) {
1067 i->second.erase(j);
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),
1088 nullptr);
1091 css::uno::Sequence< css::beans::PropertyValue >
1092 PropertySetMixinImpl::getPropertyValues()
1094 css::uno::Sequence< css::beans::PropertyValue > s(
1095 m_impl->handleMap.getLength());
1096 sal_Int32 n = 0;
1097 for (sal_Int32 i = 0; i < m_impl->handleMap.getLength(); ++i) {
1098 try {
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 &) {
1103 continue;
1104 } catch (css::lang::WrappedTargetException & e) {
1105 throw css::lang::WrappedTargetRuntimeException(
1106 e.Message, static_cast< css::beans::XPropertySet * >(this),
1107 e.TargetException);
1109 s[n].Name = m_impl->handleMap[i];
1110 s[n].Handle = i;
1111 ++n;
1113 s.realloc(n);
1114 return s;
1117 void PropertySetMixinImpl::setPropertyValues(
1118 css::uno::Sequence< css::beans::PropertyValue > const & props)
1120 for (const auto & p : props) {
1121 if (p.Handle != -1
1122 && (p.Name
1123 != m_impl->translateHandle(
1124 static_cast< css::beans::XPropertySet * >(this),
1125 p.Handle)))
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,
1134 p.Value,
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: */