Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / cppuhelper / source / propertysetmixin.cxx
bloba37185e766869985d698b8123c082efe60f8dcdd
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 css::uno::Sequence<
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);
144 css::uno::Sequence<
145 css::uno::Reference<
146 css::reflection::XInterfaceMemberTypeDescription > > members(
147 ifc->getMembers());
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)
155 css::uno::Reference<
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;
165 bSetUnknown = true;
167 css::uno::Sequence<
168 css::uno::Reference<
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
174 // of a supertype:
175 for (sal_Int32 j = 0; j < excs.getLength(); ++j) {
176 if ( excs[j]->getName() == "com.sun.star.beans.UnknownPropertyException" )
178 bGetUnknown = true;
179 break;
182 excs = attr->getSetExceptions();
183 for (sal_Int32 j = 0; j < excs.getLength(); ++j) {
184 if ( excs[j]->getName() == "com.sun.star.beans.UnknownPropertyException" )
186 bSetUnknown = true;
187 } else if ( excs[j]->getName() == "com.sun.star.beans.PropertyVetoException" )
189 attrAttribs
190 |= css::beans::PropertyAttribute::CONSTRAINED;
193 if (bGetUnknown && bSetUnknown) {
194 attrAttribs |= css::beans::PropertyAttribute::OPTIONAL;
196 css::uno::Reference< css::reflection::XTypeDescription > t(
197 attr->getType());
198 for (;;)
200 t = resolveTypedefs(t);
201 sal_Int16 n;
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;
214 } else {
215 break;
217 if ((attrAttribs & n) != 0) {
218 break;
220 attrAttribs |= n;
221 css::uno::Sequence<
222 css::uno::Reference< css::reflection::XTypeDescription > >
223 args(
224 css::uno::Reference<
225 css::reflection::XStructTypeDescription >(
226 t, css::uno::UNO_QUERY_THROW)->
227 getTypeArguments());
228 if (args.getLength() != 1) {
229 throw css::uno::RuntimeException(
230 "inconsistent UNO type registry");
232 t = args[0];
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(
242 name,
243 PropertyData(
244 css::beans::Property(
245 name, static_cast< sal_Int32 >(handles),
246 css::uno::Type(
247 t->getTypeClass(), t->getName()),
248 attrAttribs),
249 (std::find(absentBegin, absentEnd, name)
250 == absentEnd))).
251 second)
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();
270 return t;
273 class Info: public cppu::WeakImplHelper< css::beans::XPropertySetInfo > {
274 public:
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;
284 private:
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()));
293 sal_Int32 n = 0;
294 for (const auto& rEntry : m_data->properties)
296 if (rEntry.second.present) {
297 s[n++] = rEntry.second.property;
300 s.realloc(n);
301 return s;
304 css::beans::Property Info::getPropertyByName(OUString const & name)
306 return m_data->get(static_cast< cppu::OWeakObject * >(this), name)->
307 second.property;
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;
316 typedef
317 std::multiset< css::uno::Reference< css::beans::XPropertyChangeListener > >
318 BoundListenerBag;
322 class PropertySetMixinImpl::BoundListeners::Impl {
323 public:
324 BoundListenerBag specificListeners;
325 BoundListenerBag unspecificListeners;
326 css::beans::PropertyChangeEvent event;
329 PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl) {}
331 PropertySetMixinImpl::BoundListeners::~BoundListeners() {
332 delete m_impl;
335 void PropertySetMixinImpl::BoundListeners::notify() const {
336 for (const auto& rxListener : m_impl->specificListeners)
338 try {
339 rxListener->propertyChange(m_impl->event);
340 } catch (css::lang::DisposedException &) {}
342 for (const auto& rxListener : m_impl->unspecificListeners)
344 try {
345 rxListener->propertyChange(m_impl->event);
346 } catch (css::lang::DisposedException &) {}
350 class PropertySetMixinImpl::Impl: public Data {
351 public:
352 Impl(
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;
362 void setProperty(
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)
366 const;
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;
377 typedef
378 std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > >
379 VetoListenerBag;
381 typedef std::map< OUString, VetoListenerBag > VetoListenerMap;
383 mutable osl::Mutex mutex;
384 BoundListenerMap boundListeners;
385 VetoListenerMap vetoListeners;
386 bool disposed;
388 private:
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),
410 m_type(type)
412 assert(context.is());
413 assert(
414 (implements
415 & ~(IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET
416 | IMPLEMENTS_PROPERTY_ACCESS))
417 == 0);
418 m_idlClass = getReflection(m_type.getTypeName());
419 css::uno::Reference< css::reflection::XTypeDescription > ifc;
420 try {
421 ifc.set(
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: "
433 + e.Message,
434 nullptr, anyEx );
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);
464 if ((isAmbiguous
465 && ((i->second.property.Attributes
466 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
467 == 0))
468 || (isDefaulted
469 && ((i->second.property.Attributes
470 & css::beans::PropertyAttribute::MAYBEDEFAULT)
471 == 0)))
473 throw css::lang::IllegalArgumentException(
474 ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
475 + name),
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));
481 css::uno::Any v(
482 wrapValue(
483 object, value,
484 (css::uno::Reference< css::reflection::XIdlField2 >(
485 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW)->
486 getType()),
487 ((i->second.property.Attributes
488 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
489 != 0),
490 isAmbiguous,
491 ((i->second.property.Attributes
492 & css::beans::PropertyAttribute::MAYBEDEFAULT)
493 != 0),
494 isDefaulted,
495 ((i->second.property.Attributes
496 & css::beans::PropertyAttribute::MAYBEVOID)
497 != 0)));
498 try {
499 f->set(o, v);
500 } catch (css::lang::IllegalArgumentException & e) {
501 if (e.ArgumentPosition == 1) {
502 throw css::lang::IllegalArgumentException(
503 e.Message, object, illegalArgumentPosition);
504 } else {
505 css::uno::Any anyEx = cppu::getCaughtException();
506 throw css::lang::WrappedTargetRuntimeException(
507 "unexpected com.sun.star.lang.IllegalArgumentException: "
508 + e.Message,
509 object, anyEx );
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
520 // layers.
521 if (e.TargetException.isExtractableTo(
522 cppu::UnoType<css::beans::UnknownPropertyException>::get())
523 && ((i->second.property.Attributes
524 & css::beans::PropertyAttribute::OPTIONAL)
525 != 0))
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)
532 != 0))
534 css::beans::PropertyVetoException exc;
535 e.TargetException >>= exc;
536 if (exc.Message.isEmpty() )
537 throw css::beans::PropertyVetoException("Invalid " + name, object);
538 else
539 throw exc;
540 } else {
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);
557 css::uno::Any value;
558 try {
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: "
564 + e.Message,
565 object, anyEx );
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
570 // layers.
571 if (e.TargetException.isExtractableTo(
572 cppu::UnoType<css::beans::UnknownPropertyException>::get())
573 && ((i->second.property.Attributes
574 & css::beans::PropertyAttribute::OPTIONAL)
575 != 0))
577 throw css::beans::UnknownPropertyException(name, object);
578 } else {
579 throw css::lang::WrappedTargetException(
580 e.Message, object, e.TargetException);
583 bool undoAmbiguous
584 = ((i->second.property.Attributes
585 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
586 != 0);
587 bool undoDefaulted
588 = ((i->second.property.Attributes
589 & css::beans::PropertyAttribute::MAYBEDEFAULT)
590 != 0);
591 bool undoOptional
592 = ((i->second.property.Attributes
593 & css::beans::PropertyAttribute::MAYBEVOID)
594 != 0);
595 bool isAmbiguous = false;
596 bool isDefaulted = false;
597 while (undoAmbiguous || undoDefaulted || undoOptional) {
598 if (undoAmbiguous
599 && value.getValueTypeName().startsWith(
600 "com.sun.star.beans.Ambiguous<"))
602 css::uno::Reference< css::reflection::XIdlClass > ambiguous(
603 getReflection(value.getValueTypeName()));
604 try {
605 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
606 ambiguous->getField("IsAmbiguous"),
607 css::uno::UNO_QUERY_THROW)->get(value)
608 >>= isAmbiguous))
610 throw css::uno::RuntimeException(
611 ("unexpected type of com.sun.star.beans.Ambiguous"
612 " IsAmbiguous member"),
613 object);
615 value = css::uno::Reference< css::reflection::XIdlField2 >(
616 ambiguous->getField("Value"), css::uno::UNO_QUERY_THROW)->
617 get(value);
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: "
622 + e.Message,
623 object, anyEx );
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()));
632 try {
634 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
635 defaulted->getField("IsDefaulted"),
636 css::uno::UNO_QUERY_THROW)->get(value)
637 >>= isDefaulted))
639 throw css::uno::RuntimeException(
640 ("unexpected type of com.sun.star.beans.Defaulted"
641 " IsDefaulted member"),
642 object);
644 value = css::uno::Reference< css::reflection::XIdlField2 >(
645 defaulted->getField("Value"), css::uno::UNO_QUERY_THROW)->
646 get(value);
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: "
651 + e.Message,
652 object, anyEx );
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()));
661 try {
662 bool present = false;
663 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
664 optional->getField("IsPresent"),
665 css::uno::UNO_QUERY_THROW)->get(value)
666 >>= present))
668 throw css::uno::RuntimeException(
669 ("unexpected type of com.sun.star.beans.Optional"
670 " IsPresent member"),
671 object);
673 if (!present) {
674 value.clear();
675 break;
677 value = css::uno::Reference< css::reflection::XIdlField2 >(
678 optional->getField("Value"), css::uno::UNO_QUERY_THROW)->
679 get(value);
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: "
684 + e.Message,
685 object, anyEx );
687 undoOptional = false;
688 } else {
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:
696 *state = isAmbiguous
697 ? css::beans::PropertyState_AMBIGUOUS_VALUE
698 : isDefaulted
699 ? css::beans::PropertyState_DEFAULT_VALUE
700 : css::beans::PropertyState_DIRECT_VALUE;
702 return 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,
718 bool wrapOptional)
720 assert(wrapAmbiguous || !isAmbiguous);
721 assert(wrapDefaulted || !isDefaulted);
722 if (wrapAmbiguous
723 && type->getName().startsWith("com.sun.star.beans.Ambiguous<"))
725 css::uno::Any strct;
726 type->createObject(strct);
727 try {
728 css::uno::Reference< css::reflection::XIdlField2 > field(
729 type->getField("Value"), css::uno::UNO_QUERY_THROW);
730 field->set(
731 strct,
732 wrapValue(
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: "
742 + e.Message,
743 object, anyEx );
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: "
748 + e.Message,
749 object, anyEx );
751 return strct;
753 if (wrapDefaulted
754 && type->getName().startsWith("com.sun.star.beans.Defaulted<"))
756 css::uno::Any strct;
757 type->createObject(strct);
758 try {
759 css::uno::Reference< css::reflection::XIdlField2 > field(
760 type->getField("Value"), css::uno::UNO_QUERY_THROW);
761 field->set(
762 strct,
763 wrapValue(
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: "
773 + e.Message,
774 object, anyEx );
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: "
779 + e.Message,
780 object, anyEx );
782 return strct;
784 if (wrapOptional
785 && type->getName().startsWith("com.sun.star.beans.Optional<"))
787 css::uno::Any strct;
788 type->createObject(strct);
789 bool present = value.hasValue();
790 try {
791 css::uno::Reference< css::reflection::XIdlField2 >(
792 type->getField("IsPresent"), css::uno::UNO_QUERY_THROW)->set(
793 strct, css::uno::Any(present));
794 if (present) {
795 css::uno::Reference< css::reflection::XIdlField2 > field(
796 type->getField("Value"), css::uno::UNO_QUERY_THROW);
797 field->set(
798 strct,
799 wrapValue(
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: "
807 + e.Message,
808 object, anyEx );
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: "
813 + e.Message,
814 object, anyEx );
816 return strct;
818 if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
819 throw css::uno::RuntimeException(
820 "unexpected type of attribute", object);
822 return value;
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);
832 m_impl->acquire();
835 PropertySetMixinImpl::~PropertySetMixinImpl() {
836 m_impl->release();
839 void PropertySetMixinImpl::checkUnknown(OUString const & propertyName) {
840 if (!propertyName.isEmpty()) {
841 m_impl->get(
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)
862 != 0)
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)
876 != 0)
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)
892 != 0)
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)
899 try {
900 rxVetoListener->vetoableChange(event);
901 } catch (css::lang::DisposedException &) {}
903 for (auto& rxVetoListener : unspecificVeto)
905 try {
906 rxVetoListener->vetoableChange(event);
907 } catch (css::lang::DisposedException &) {}
910 if ((it->second.property.Attributes & css::beans::PropertyAttribute::BOUND)
911 != 0)
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)
982 m_impl->setProperty(
983 static_cast< css::beans::XPropertySet * >(this), propertyName, value,
984 false, false, 1);
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);
1001 bool disposed;
1003 osl::MutexGuard g(m_impl->mutex);
1004 disposed = m_impl->disposed;
1005 if (!disposed) {
1006 m_impl->boundListeners[propertyName].insert(listener);
1009 if (disposed) {
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()) {
1028 i->second.erase(j);
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);
1040 bool disposed;
1042 osl::MutexGuard g(m_impl->mutex);
1043 disposed = m_impl->disposed;
1044 if (!disposed) {
1045 m_impl->vetoListeners[propertyName].insert(listener);
1048 if (disposed) {
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()) {
1066 i->second.erase(j);
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),
1087 nullptr);
1090 css::uno::Sequence< css::beans::PropertyValue >
1091 PropertySetMixinImpl::getPropertyValues()
1093 css::uno::Sequence< css::beans::PropertyValue > s(
1094 m_impl->handleMap.getLength());
1095 sal_Int32 n = 0;
1096 for (sal_Int32 i = 0; i < m_impl->handleMap.getLength(); ++i) {
1097 try {
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 &) {
1102 continue;
1103 } catch (css::lang::WrappedTargetException & e) {
1104 throw css::lang::WrappedTargetRuntimeException(
1105 e.Message, static_cast< css::beans::XPropertySet * >(this),
1106 e.TargetException);
1108 s[n].Name = m_impl->handleMap[i];
1109 s[n].Handle = i;
1110 ++n;
1112 s.realloc(n);
1113 return s;
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
1121 && (props[i].Name
1122 != m_impl->translateHandle(
1123 static_cast< css::beans::XPropertySet * >(this),
1124 props[i].Handle)))
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,
1133 props[i].Value,
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: */