cURL: follow redirects
[LibreOffice.git] / cppuhelper / source / propertysetmixin.cxx
blobbe101b6167a23628b8852a03b7f44c3a988c3de0
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 <exception>
25 #include <map>
26 #include <set>
27 #include <vector>
29 #include <com/sun/star/beans/Property.hpp>
30 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/beans/PropertyVetoException.hpp>
34 #include <com/sun/star/beans/UnknownPropertyException.hpp>
35 #include <com/sun/star/beans/XFastPropertySet.hpp>
36 #include <com/sun/star/beans/XPropertyAccess.hpp>
37 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/beans/XPropertySetInfo.hpp>
40 #include <com/sun/star/beans/XVetoableChangeListener.hpp>
41 #include <com/sun/star/container/NoSuchElementException.hpp>
42 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
43 #include <com/sun/star/lang/DisposedException.hpp>
44 #include <com/sun/star/lang/EventObject.hpp>
45 #include <com/sun/star/lang/IllegalAccessException.hpp>
46 #include <com/sun/star/lang/IllegalArgumentException.hpp>
47 #include <com/sun/star/lang/WrappedTargetException.hpp>
48 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
49 #include <com/sun/star/reflection/XCompoundTypeDescription.hpp>
50 #include <com/sun/star/reflection/XIdlClass.hpp>
51 #include <com/sun/star/reflection/XIdlField2.hpp>
52 #include <com/sun/star/reflection/XIndirectTypeDescription.hpp>
53 #include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp>
54 #include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
55 #include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp>
56 #include <com/sun/star/reflection/XStructTypeDescription.hpp>
57 #include <com/sun/star/reflection/XTypeDescription.hpp>
58 #include <com/sun/star/reflection/theCoreReflection.hpp>
59 #include <com/sun/star/uno/Any.hxx>
60 #include <com/sun/star/uno/DeploymentException.hpp>
61 #include <com/sun/star/uno/Exception.hpp>
62 #include <com/sun/star/uno/Reference.hxx>
63 #include <com/sun/star/uno/RuntimeException.hpp>
64 #include <com/sun/star/uno/Sequence.hxx>
65 #include <com/sun/star/uno/Type.hxx>
66 #include <com/sun/star/uno/TypeClass.hpp>
67 #include <com/sun/star/uno/XComponentContext.hpp>
68 #include <com/sun/star/uno/XInterface.hpp>
69 #include <cppuhelper/implbase1.hxx>
70 #include <cppuhelper/propertysetmixin.hxx>
71 #include <cppuhelper/weak.hxx>
72 #include <osl/mutex.hxx>
73 #include <rtl/ref.hxx>
74 #include <rtl/ustring.hxx>
75 #include <sal/types.h>
76 #include <salhelper/simplereferenceobject.hxx>
78 using cppu::PropertySetMixinImpl;
80 namespace {
82 struct PropertyData {
83 explicit PropertyData(
84 css::beans::Property const & theProperty, bool thePresent):
85 property(theProperty), present(thePresent) {}
87 css::beans::Property property;
88 bool present;
91 struct Data: public salhelper::SimpleReferenceObject {
92 typedef std::map< rtl::OUString, PropertyData > PropertyMap;
94 PropertyMap properties;
96 PropertyMap::const_iterator get(
97 css::uno::Reference< css::uno::XInterface > const & object,
98 rtl::OUString const & name) const;
100 protected:
101 void initProperties(
102 css::uno::Reference< css::reflection::XTypeDescription > const & type,
103 css::uno::Sequence< rtl::OUString > const & absentOptional,
104 std::vector< rtl::OUString > * handleNames)
106 TypeSet seen;
107 initProperties(type, absentOptional, handleNames, &seen);
110 private:
111 typedef std::set< rtl::OUString > TypeSet;
113 void initProperties(
114 css::uno::Reference< css::reflection::XTypeDescription > const & type,
115 css::uno::Sequence< rtl::OUString > const & absentOptional,
116 std::vector< rtl::OUString > * handleNames, TypeSet * seen);
118 static css::uno::Reference< css::reflection::XTypeDescription >
119 resolveTypedefs(
120 css::uno::Reference< css::reflection::XTypeDescription > const & type);
123 Data::PropertyMap::const_iterator Data::get(
124 css::uno::Reference< css::uno::XInterface > const & object,
125 rtl::OUString const & name) const
127 PropertyMap::const_iterator i(properties.find(name));
128 if (i == properties.end() || !i->second.present) {
129 throw css::beans::UnknownPropertyException(name, object);
131 return i;
134 void Data::initProperties(
135 css::uno::Reference< css::reflection::XTypeDescription > const & type,
136 css::uno::Sequence< rtl::OUString > const & absentOptional,
137 std::vector< rtl::OUString > * handleNames, TypeSet * seen)
139 css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > ifc(
140 resolveTypedefs(type), css::uno::UNO_QUERY_THROW);
141 if (seen->insert(ifc->getName()).second) {
142 css::uno::Sequence<
143 css::uno::Reference< css::reflection::XTypeDescription > > bases(
144 ifc->getBaseTypes());
145 for (sal_Int32 i = 0; i < bases.getLength(); ++i) {
146 initProperties(bases[i], absentOptional, handleNames, seen);
148 css::uno::Sequence<
149 css::uno::Reference<
150 css::reflection::XInterfaceMemberTypeDescription > > members(
151 ifc->getMembers());
152 rtl::OUString const * absentBegin = absentOptional.getConstArray();
153 rtl::OUString const * absentEnd =
154 absentBegin + absentOptional.getLength();
155 for (sal_Int32 i = 0; i < members.getLength(); ++i) {
156 if (members[i]->getTypeClass()
157 == css::uno::TypeClass_INTERFACE_ATTRIBUTE)
159 css::uno::Reference<
160 css::reflection::XInterfaceAttributeTypeDescription2 > attr(
161 members[i], css::uno::UNO_QUERY_THROW);
162 sal_Int16 attrAttribs = 0;
163 if (attr->isBound()) {
164 attrAttribs |= css::beans::PropertyAttribute::BOUND;
166 bool bSetUnknown = false;
167 if (attr->isReadOnly()) {
168 attrAttribs |= css::beans::PropertyAttribute::READONLY;
169 bSetUnknown = true;
171 css::uno::Sequence<
172 css::uno::Reference<
173 css::reflection::XCompoundTypeDescription > > excs(
174 attr->getGetExceptions());
175 bool bGetUnknown = false;
176 //XXX Special interpretation of getter/setter exceptions only
177 // works if the specified exceptions are of the exact type, not
178 // of a supertype:
179 for (sal_Int32 j = 0; j < excs.getLength(); ++j) {
180 if ( excs[j]->getName() == "com.sun.star.beans.UnknownPropertyException" )
182 bGetUnknown = true;
183 break;
186 excs = attr->getSetExceptions();
187 for (sal_Int32 j = 0; j < excs.getLength(); ++j) {
188 if ( excs[j]->getName() == "com.sun.star.beans.UnknownPropertyException" )
190 bSetUnknown = true;
191 } else if ( excs[j]->getName() == "com.sun.star.beans.PropertyVetoException" )
193 attrAttribs
194 |= css::beans::PropertyAttribute::CONSTRAINED;
197 if (bGetUnknown && bSetUnknown) {
198 attrAttribs |= css::beans::PropertyAttribute::OPTIONAL;
200 css::uno::Reference< css::reflection::XTypeDescription > t(
201 attr->getType());
202 for (;;)
204 t = resolveTypedefs(t);
205 sal_Int16 n;
206 if (t->getName().startsWith(
207 "com.sun.star.beans.Ambiguous<"))
209 n = css::beans::PropertyAttribute::MAYBEAMBIGUOUS;
210 } else if (t->getName().startsWith(
211 "com.sun.star.beans.Defaulted<"))
213 n = css::beans::PropertyAttribute::MAYBEDEFAULT;
214 } else if (t->getName().startsWith(
215 "com.sun.star.beans.Optional<"))
217 n = css::beans::PropertyAttribute::MAYBEVOID;
218 } else {
219 break;
221 if ((attrAttribs & n) != 0) {
222 break;
224 attrAttribs |= n;
225 css::uno::Sequence<
226 css::uno::Reference< css::reflection::XTypeDescription > >
227 args(
228 css::uno::Reference<
229 css::reflection::XStructTypeDescription >(
230 t, css::uno::UNO_QUERY_THROW)->
231 getTypeArguments());
232 if (args.getLength() != 1) {
233 throw css::uno::RuntimeException(
234 "inconsistent UNO type registry");
236 t = args[0];
238 std::vector< rtl::OUString >::size_type handles
239 = handleNames->size();
240 if (handles > SAL_MAX_INT32) {
241 throw css::uno::RuntimeException(
242 "interface type has too many attributes");
244 rtl::OUString name(members[i]->getMemberName());
245 if (!properties.insert(
246 PropertyMap::value_type(
247 name,
248 PropertyData(
249 css::beans::Property(
250 name, static_cast< sal_Int32 >(handles),
251 css::uno::Type(
252 t->getTypeClass(), t->getName()),
253 attrAttribs),
254 (std::find(absentBegin, absentEnd, name)
255 == absentEnd)))).
256 second)
258 throw css::uno::RuntimeException(
259 "inconsistent UNO type registry");
261 handleNames->push_back(name);
267 css::uno::Reference< css::reflection::XTypeDescription > Data::resolveTypedefs(
268 css::uno::Reference< css::reflection::XTypeDescription > const & type)
270 css::uno::Reference< css::reflection::XTypeDescription > t(type);
271 while (t->getTypeClass() == css::uno::TypeClass_TYPEDEF) {
272 t = css::uno::Reference< css::reflection::XIndirectTypeDescription >(
273 t, css::uno::UNO_QUERY_THROW)->getReferencedType();
275 return t;
278 class Info: public cppu::WeakImplHelper1< css::beans::XPropertySetInfo > {
279 public:
280 explicit Info(Data * data): m_data(data) {}
282 virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties()
283 throw (css::uno::RuntimeException, std::exception) override;
285 virtual css::beans::Property SAL_CALL getPropertyByName(
286 rtl::OUString const & name)
287 throw (
288 css::beans::UnknownPropertyException, css::uno::RuntimeException, std::exception) override;
290 virtual sal_Bool SAL_CALL hasPropertyByName(rtl::OUString const & name)
291 throw (css::uno::RuntimeException, std::exception) override;
293 private:
294 rtl::Reference< Data > m_data;
297 css::uno::Sequence< css::beans::Property > Info::getProperties()
298 throw (css::uno::RuntimeException, std::exception)
300 assert(m_data->properties.size() <= SAL_MAX_INT32);
301 css::uno::Sequence< css::beans::Property > s(
302 static_cast< sal_Int32 >(m_data->properties.size()));
303 sal_Int32 n = 0;
304 for (Data::PropertyMap::iterator i(m_data->properties.begin());
305 i != m_data->properties.end(); ++i)
307 if (i->second.present) {
308 s[n++] = i->second.property;
311 s.realloc(n);
312 return s;
315 css::beans::Property Info::getPropertyByName(rtl::OUString const & name)
316 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException, std::exception)
318 return m_data->get(static_cast< cppu::OWeakObject * >(this), name)->
319 second.property;
322 sal_Bool Info::hasPropertyByName(rtl::OUString const & name)
323 throw (css::uno::RuntimeException, std::exception)
325 Data::PropertyMap::iterator i(m_data->properties.find(name));
326 return i != m_data->properties.end() && i->second.present;
329 typedef
330 std::multiset< css::uno::Reference< css::beans::XPropertyChangeListener > >
331 BoundListenerBag;
335 class PropertySetMixinImpl::BoundListeners::Impl {
336 public:
337 BoundListenerBag specificListeners;
338 BoundListenerBag unspecificListeners;
339 css::beans::PropertyChangeEvent event;
342 PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl) {}
344 PropertySetMixinImpl::BoundListeners::~BoundListeners() {
345 delete m_impl;
348 void PropertySetMixinImpl::BoundListeners::notify() const {
349 for (BoundListenerBag::const_iterator i(m_impl->specificListeners.begin());
350 i != m_impl->specificListeners.end(); ++i)
352 try {
353 (*i)->propertyChange(m_impl->event);
354 } catch (css::lang::DisposedException &) {}
356 for (BoundListenerBag::const_iterator i(
357 m_impl->unspecificListeners.begin());
358 i != m_impl->unspecificListeners.end(); ++i)
360 try {
361 (*i)->propertyChange(m_impl->event);
362 } catch (css::lang::DisposedException &) {}
366 class PropertySetMixinImpl::Impl: public Data {
367 public:
368 Impl(
369 css::uno::Reference< css::uno::XComponentContext > const & context,
370 Implements theImplements,
371 css::uno::Sequence< rtl::OUString > const & absentOptional,
372 css::uno::Type const & type);
374 rtl::OUString translateHandle(
375 css::uno::Reference< css::uno::XInterface > const & object,
376 sal_Int32 handle) const;
378 void setProperty(
379 css::uno::Reference< css::uno::XInterface > const & object,
380 rtl::OUString const & name, css::uno::Any const & value,
381 bool isAmbiguous, bool isDefaulted, sal_Int16 illegalArgumentPosition)
382 const;
384 css::uno::Any getProperty(
385 css::uno::Reference< css::uno::XInterface > const & object,
386 rtl::OUString const & name, css::beans::PropertyState * state) const;
388 PropertySetMixinImpl::Implements implements;
389 css::uno::Sequence< rtl::OUString > handleMap;
391 typedef std::map< rtl::OUString, BoundListenerBag > BoundListenerMap;
393 typedef
394 std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > >
395 VetoListenerBag;
397 typedef std::map< rtl::OUString, VetoListenerBag > VetoListenerMap;
399 mutable osl::Mutex mutex;
400 BoundListenerMap boundListeners;
401 VetoListenerMap vetoListeners;
402 bool disposed;
404 private:
405 css::uno::Reference< css::reflection::XIdlClass > getReflection(
406 rtl::OUString const & typeName) const;
408 static css::uno::Any wrapValue(
409 css::uno::Reference< css::uno::XInterface > const & object,
410 css::uno::Any const & value,
411 css::uno::Reference< css::reflection::XIdlClass > const & type,
412 bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted,
413 bool isDefaulted, bool wrapOptional);
415 css::uno::Reference< css::uno::XComponentContext > const & m_context;
416 css::uno::Sequence< rtl::OUString > m_absentOptional;
417 css::uno::Type m_type;
418 css::uno::Reference< css::reflection::XIdlClass > m_idlClass;
421 PropertySetMixinImpl::Impl::Impl(
422 css::uno::Reference< css::uno::XComponentContext > const & context,
423 Implements theImplements,
424 css::uno::Sequence< rtl::OUString > const & absentOptional,
425 css::uno::Type const & type):
426 implements(theImplements), disposed(false), m_context(context),
427 m_absentOptional(absentOptional), m_type(type)
429 assert(context.is());
430 assert(
431 (implements
432 & ~(IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET
433 | IMPLEMENTS_PROPERTY_ACCESS))
434 == 0);
435 m_idlClass = getReflection(m_type.getTypeName());
436 css::uno::Reference< css::reflection::XTypeDescription > ifc;
437 try {
438 ifc.set(
439 css::uno::Reference< css::container::XHierarchicalNameAccess >(
440 m_context->getValueByName(
441 "/singletons/com.sun.star.reflection."
442 "theTypeDescriptionManager"),
443 css::uno::UNO_QUERY_THROW)->getByHierarchicalName(
444 m_type.getTypeName()),
445 css::uno::UNO_QUERY_THROW);
446 } catch (css::container::NoSuchElementException & e) {
447 throw css::uno::RuntimeException(
448 "unexpected com.sun.star.container.NoSuchElementException: "
449 + e.Message);
451 std::vector< rtl::OUString > handleNames;
452 initProperties(ifc, m_absentOptional, &handleNames);
453 std::vector< rtl::OUString >::size_type size = handleNames.size();
454 assert(size <= SAL_MAX_INT32);
455 handleMap.realloc(static_cast< sal_Int32 >(size));
456 std::copy(handleNames.begin(), handleNames.end(), handleMap.getArray());
459 rtl::OUString PropertySetMixinImpl::Impl::translateHandle(
460 css::uno::Reference< css::uno::XInterface > const & object,
461 sal_Int32 handle) const
463 if (handle < 0 || handle >= handleMap.getLength()) {
464 throw css::beans::UnknownPropertyException(
465 "bad handle " + rtl::OUString::number(handle), object);
467 return handleMap[handle];
470 void PropertySetMixinImpl::Impl::setProperty(
471 css::uno::Reference< css::uno::XInterface > const & object,
472 rtl::OUString const & name, css::uno::Any const & value, bool isAmbiguous,
473 bool isDefaulted, sal_Int16 illegalArgumentPosition) const
475 PropertyMap::const_iterator i(properties.find(name));
476 if (i == properties.end()) {
477 throw css::beans::UnknownPropertyException(name, object);
479 if ((isAmbiguous
480 && ((i->second.property.Attributes
481 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
482 == 0))
483 || (isDefaulted
484 && ((i->second.property.Attributes
485 & css::beans::PropertyAttribute::MAYBEDEFAULT)
486 == 0)))
488 throw css::lang::IllegalArgumentException(
489 ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
490 + name),
491 object, illegalArgumentPosition);
493 css::uno::Reference< css::reflection::XIdlField2 > f(
494 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
495 css::uno::Any o(object->queryInterface(m_type));
496 css::uno::Any v(
497 wrapValue(
498 object, value,
499 (css::uno::Reference< css::reflection::XIdlField2 >(
500 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW)->
501 getType()),
502 ((i->second.property.Attributes
503 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
504 != 0),
505 isAmbiguous,
506 ((i->second.property.Attributes
507 & css::beans::PropertyAttribute::MAYBEDEFAULT)
508 != 0),
509 isDefaulted,
510 ((i->second.property.Attributes
511 & css::beans::PropertyAttribute::MAYBEVOID)
512 != 0)));
513 try {
514 f->set(o, v);
515 } catch (css::lang::IllegalArgumentException & e) {
516 if (e.ArgumentPosition == 1) {
517 throw css::lang::IllegalArgumentException(
518 e.Message, object, illegalArgumentPosition);
519 } else {
520 throw css::uno::RuntimeException(
521 ("unexpected com.sun.star.lang.IllegalArgumentException: "
522 + e.Message),
523 object);
525 } catch (css::lang::IllegalAccessException &) {
526 //TODO Clarify whether PropertyVetoException is the correct exception
527 // to throw when trying to set a read-only property:
528 throw css::beans::PropertyVetoException(
529 "cannot set read-only property " + name, object);
530 } catch (css::lang::WrappedTargetRuntimeException & e) {
531 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
532 // guaranteed to originate directly within XIdlField2.get (and thus have
533 // the expected semantics); it might also be passed through from lower
534 // layers.
535 if (e.TargetException.isExtractableTo(
536 cppu::UnoType<css::beans::UnknownPropertyException>::get())
537 && ((i->second.property.Attributes
538 & css::beans::PropertyAttribute::OPTIONAL)
539 != 0))
541 throw css::beans::UnknownPropertyException(name, object);
542 } else if (e.TargetException.isExtractableTo(
543 cppu::UnoType<css::beans::PropertyVetoException>::get())
544 && ((i->second.property.Attributes
545 & css::beans::PropertyAttribute::CONSTRAINED)
546 != 0))
548 css::beans::PropertyVetoException exc;
549 e.TargetException >>= exc;
550 if (exc.Message.isEmpty() )
551 throw css::beans::PropertyVetoException("Invalid " + name, object);
552 else
553 throw exc;
554 } else {
555 throw css::lang::WrappedTargetException(
556 e.Message, object, e.TargetException);
561 css::uno::Any PropertySetMixinImpl::Impl::getProperty(
562 css::uno::Reference< css::uno::XInterface > const & object,
563 rtl::OUString const & name, css::beans::PropertyState * state) const
565 PropertyMap::const_iterator i(properties.find(name));
566 if (i == properties.end()) {
567 throw css::beans::UnknownPropertyException(name, object);
569 css::uno::Reference< css::reflection::XIdlField2 > field(
570 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
571 css::uno::Any value;
572 try {
573 value = field->get(object->queryInterface(m_type));
574 } catch (css::lang::IllegalArgumentException & e) {
575 throw css::uno::RuntimeException(
576 ("unexpected com.sun.star.lang.IllegalArgumentException: "
577 + e.Message),
578 object);
579 } catch (css::lang::WrappedTargetRuntimeException & e) {
580 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
581 // guaranteed to originate directly within XIdlField2.get (and thus have
582 // the expected semantics); it might also be passed through from lower
583 // layers.
584 if (e.TargetException.isExtractableTo(
585 cppu::UnoType<css::beans::UnknownPropertyException>::get())
586 && ((i->second.property.Attributes
587 & css::beans::PropertyAttribute::OPTIONAL)
588 != 0))
590 throw css::beans::UnknownPropertyException(name, object);
591 } else {
592 throw css::lang::WrappedTargetException(
593 e.Message, object, e.TargetException);
596 bool undoAmbiguous
597 = ((i->second.property.Attributes
598 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
599 != 0);
600 bool undoDefaulted
601 = ((i->second.property.Attributes
602 & css::beans::PropertyAttribute::MAYBEDEFAULT)
603 != 0);
604 bool undoOptional
605 = ((i->second.property.Attributes
606 & css::beans::PropertyAttribute::MAYBEVOID)
607 != 0);
608 bool isAmbiguous = false;
609 bool isDefaulted = false;
610 while (undoAmbiguous || undoDefaulted || undoOptional) {
611 if (undoAmbiguous
612 && value.getValueTypeName().startsWith(
613 "com.sun.star.beans.Ambiguous<"))
615 css::uno::Reference< css::reflection::XIdlClass > ambiguous(
616 getReflection(value.getValueTypeName()));
617 try {
618 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
619 ambiguous->getField("IsAmbiguous"),
620 css::uno::UNO_QUERY_THROW)->get(value)
621 >>= isAmbiguous))
623 throw css::uno::RuntimeException(
624 ("unexpected type of com.sun.star.beans.Ambiguous"
625 " IsAmbiguous member"),
626 object);
628 value = css::uno::Reference< css::reflection::XIdlField2 >(
629 ambiguous->getField("Value"), css::uno::UNO_QUERY_THROW)->
630 get(value);
631 } catch (css::lang::IllegalArgumentException & e) {
632 throw css::uno::RuntimeException(
633 ("unexpected com.sun.star.lang.IllegalArgumentException: "
634 + e.Message),
635 object);
637 undoAmbiguous = false;
638 } else if (undoDefaulted
639 && value.getValueTypeName().startsWith(
640 "com.sun.star.beans.Defaulted<"))
642 css::uno::Reference< css::reflection::XIdlClass > defaulted(
643 getReflection(value.getValueTypeName()));
644 try {
646 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
647 defaulted->getField("IsDefaulted"),
648 css::uno::UNO_QUERY_THROW)->get(value)
649 >>= isDefaulted))
651 throw css::uno::RuntimeException(
652 ("unexpected type of com.sun.star.beans.Defaulted"
653 " IsDefaulted member"),
654 object);
656 value = css::uno::Reference< css::reflection::XIdlField2 >(
657 defaulted->getField("Value"), css::uno::UNO_QUERY_THROW)->
658 get(value);
659 } catch (css::lang::IllegalArgumentException & e) {
660 throw css::uno::RuntimeException(
661 ("unexpected com.sun.star.lang.IllegalArgumentException: "
662 + e.Message),
663 object);
665 undoDefaulted = false;
666 } else if (undoOptional
667 && value.getValueTypeName().startsWith(
668 "com.sun.star.beans.Optional<"))
670 css::uno::Reference< css::reflection::XIdlClass > optional(
671 getReflection(value.getValueTypeName()));
672 try {
673 bool present = false;
674 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
675 optional->getField("IsPresent"),
676 css::uno::UNO_QUERY_THROW)->get(value)
677 >>= present))
679 throw css::uno::RuntimeException(
680 ("unexpected type of com.sun.star.beans.Optional"
681 " IsPresent member"),
682 object);
684 if (!present) {
685 value.clear();
686 break;
688 value = css::uno::Reference< css::reflection::XIdlField2 >(
689 optional->getField("Value"), css::uno::UNO_QUERY_THROW)->
690 get(value);
691 } catch (css::lang::IllegalArgumentException & e) {
692 throw css::uno::RuntimeException(
693 ("unexpected com.sun.star.lang.IllegalArgumentException: "
694 + e.Message),
695 object);
697 undoOptional = false;
698 } else {
699 throw css::uno::RuntimeException(
700 "unexpected type of attribute " + name, object);
703 if (state != nullptr) {
704 //XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE
705 // over DEFAULT_VALUE:
706 *state = isAmbiguous
707 ? css::beans::PropertyState_AMBIGUOUS_VALUE
708 : isDefaulted
709 ? css::beans::PropertyState_DEFAULT_VALUE
710 : css::beans::PropertyState_DIRECT_VALUE;
712 return value;
715 css::uno::Reference< css::reflection::XIdlClass >
716 PropertySetMixinImpl::Impl::getReflection(rtl::OUString const & typeName) const
718 return css::uno::Reference< css::reflection::XIdlClass >(
719 css::reflection::theCoreReflection::get(m_context)->forName(typeName),
720 css::uno::UNO_SET_THROW);
723 css::uno::Any PropertySetMixinImpl::Impl::wrapValue(
724 css::uno::Reference< css::uno::XInterface > const & object,
725 css::uno::Any const & value,
726 css::uno::Reference< css::reflection::XIdlClass > const & type,
727 bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted, bool isDefaulted,
728 bool wrapOptional)
730 assert(wrapAmbiguous || !isAmbiguous);
731 assert(wrapDefaulted || !isDefaulted);
732 if (wrapAmbiguous
733 && type->getName().startsWith("com.sun.star.beans.Ambiguous<"))
735 css::uno::Any strct;
736 type->createObject(strct);
737 try {
738 css::uno::Reference< css::reflection::XIdlField2 > field(
739 type->getField("Value"), css::uno::UNO_QUERY_THROW);
740 field->set(
741 strct,
742 wrapValue(
743 object, value, field->getType(), false, false,
744 wrapDefaulted, isDefaulted, wrapOptional));
745 css::uno::Reference< css::reflection::XIdlField2 >(
746 type->getField("IsAmbiguous"), css::uno::UNO_QUERY_THROW)->set(
747 strct, css::uno::makeAny(isAmbiguous));
748 } catch (css::lang::IllegalArgumentException & e) {
749 throw css::uno::RuntimeException(
750 ("unexpected com.sun.star.lang.IllegalArgumentException: "
751 + e.Message),
752 object);
753 } catch (css::lang::IllegalAccessException & e) {
754 throw css::uno::RuntimeException(
755 ("unexpected com.sun.star.lang.IllegalAccessException: "
756 + e.Message),
757 object);
759 return strct;
760 } else if (wrapDefaulted
761 && type->getName().startsWith("com.sun.star.beans.Defaulted<"))
763 css::uno::Any strct;
764 type->createObject(strct);
765 try {
766 css::uno::Reference< css::reflection::XIdlField2 > field(
767 type->getField("Value"), css::uno::UNO_QUERY_THROW);
768 field->set(
769 strct,
770 wrapValue(
771 object, value, field->getType(), wrapAmbiguous, isAmbiguous,
772 false, false, wrapOptional));
773 css::uno::Reference< css::reflection::XIdlField2 >(
774 type->getField("IsDefaulted"), css::uno::UNO_QUERY_THROW)->set(
775 strct, css::uno::makeAny(isDefaulted));
776 } catch (css::lang::IllegalArgumentException & e) {
777 throw css::uno::RuntimeException(
778 ("unexpected com.sun.star.lang.IllegalArgumentException: "
779 + e.Message),
780 object);
781 } catch (css::lang::IllegalAccessException & e) {
782 throw css::uno::RuntimeException(
783 ("unexpected com.sun.star.lang.IllegalAccessException: "
784 + e.Message),
785 object);
787 return strct;
788 } else if (wrapOptional
789 && type->getName().startsWith("com.sun.star.beans.Optional<"))
791 css::uno::Any strct;
792 type->createObject(strct);
793 bool present = value.hasValue();
794 try {
795 css::uno::Reference< css::reflection::XIdlField2 >(
796 type->getField("IsPresent"), css::uno::UNO_QUERY_THROW)->set(
797 strct, css::uno::makeAny(present));
798 if (present) {
799 css::uno::Reference< css::reflection::XIdlField2 > field(
800 type->getField("Value"), css::uno::UNO_QUERY_THROW);
801 field->set(
802 strct,
803 wrapValue(
804 object, value, field->getType(), wrapAmbiguous,
805 isAmbiguous, wrapDefaulted, isDefaulted, false));
807 } catch (css::lang::IllegalArgumentException & e) {
808 throw css::uno::RuntimeException(
809 ("unexpected com.sun.star.lang.IllegalArgumentException: "
810 + e.Message),
811 object);
812 } catch (css::lang::IllegalAccessException & e) {
813 throw css::uno::RuntimeException(
814 ("unexpected com.sun.star.lang.IllegalAccessException: "
815 + e.Message),
816 object);
818 return strct;
819 } else {
820 if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
821 throw css::uno::RuntimeException(
822 "unexpected type of attribute", object);
824 return value;
828 PropertySetMixinImpl::PropertySetMixinImpl(
829 css::uno::Reference< css::uno::XComponentContext > const & context,
830 Implements implements,
831 css::uno::Sequence< rtl::OUString > const & absentOptional,
832 css::uno::Type const & type)
834 m_impl = new Impl(context, implements, absentOptional, type);
835 m_impl->acquire();
838 PropertySetMixinImpl::~PropertySetMixinImpl() {
839 m_impl->release();
842 void PropertySetMixinImpl::checkUnknown(rtl::OUString const & propertyName) {
843 if (!propertyName.isEmpty()) {
844 m_impl->get(
845 static_cast< css::beans::XPropertySet * >(this), propertyName);
849 void PropertySetMixinImpl::prepareSet(
850 rtl::OUString const & propertyName, css::uno::Any const & oldValue,
851 css::uno::Any const & newValue, BoundListeners * boundListeners)
853 Impl::PropertyMap::const_iterator it(m_impl->properties.find(propertyName));
854 assert(it != m_impl->properties.end());
855 Impl::VetoListenerBag specificVeto;
856 Impl::VetoListenerBag unspecificVeto;
858 osl::MutexGuard g(m_impl->mutex);
859 if (m_impl->disposed) {
860 throw css::lang::DisposedException(
861 "disposed", static_cast< css::beans::XPropertySet * >(this));
863 if ((it->second.property.Attributes
864 & css::beans::PropertyAttribute::CONSTRAINED)
865 != 0)
867 Impl::VetoListenerMap::const_iterator i(
868 m_impl->vetoListeners.find(propertyName));
869 if (i != m_impl->vetoListeners.end()) {
870 specificVeto = i->second;
872 i = m_impl->vetoListeners.find("");
873 if (i != m_impl->vetoListeners.end()) {
874 unspecificVeto = i->second;
877 if ((it->second.property.Attributes
878 & css::beans::PropertyAttribute::BOUND)
879 != 0)
881 assert(boundListeners != nullptr);
882 Impl::BoundListenerMap::const_iterator i(
883 m_impl->boundListeners.find(propertyName));
884 if (i != m_impl->boundListeners.end()) {
885 boundListeners->m_impl->specificListeners = i->second;
887 i = m_impl->boundListeners.find("");
888 if (i != m_impl->boundListeners.end()) {
889 boundListeners->m_impl->unspecificListeners = i->second;
893 if ((it->second.property.Attributes
894 & css::beans::PropertyAttribute::CONSTRAINED)
895 != 0)
897 css::beans::PropertyChangeEvent event(
898 static_cast< css::beans::XPropertySet * >(this), propertyName,
899 false, it->second.property.Handle, oldValue, newValue);
900 for (Impl::VetoListenerBag::iterator i(specificVeto.begin());
901 i != specificVeto.end(); ++i)
903 try {
904 (*i)->vetoableChange(event);
905 } catch (css::lang::DisposedException &) {}
907 for (Impl::VetoListenerBag::iterator i(unspecificVeto.begin());
908 i != unspecificVeto.end(); ++i)
910 try {
911 (*i)->vetoableChange(event);
912 } catch (css::lang::DisposedException &) {}
915 if ((it->second.property.Attributes & css::beans::PropertyAttribute::BOUND)
916 != 0)
918 assert(boundListeners != nullptr);
919 boundListeners->m_impl->event = css::beans::PropertyChangeEvent(
920 static_cast< css::beans::XPropertySet * >(this), propertyName,
921 false, it->second.property.Handle, oldValue, newValue);
925 void PropertySetMixinImpl::dispose() {
926 Impl::BoundListenerMap boundListeners;
927 Impl::VetoListenerMap vetoListeners;
929 osl::MutexGuard g(m_impl->mutex);
930 boundListeners.swap(m_impl->boundListeners);
931 vetoListeners.swap(m_impl->vetoListeners);
932 m_impl->disposed = true;
934 css::lang::EventObject event(
935 static_cast< css::beans::XPropertySet * >(this));
936 for (Impl::BoundListenerMap::iterator i(boundListeners.begin());
937 i != boundListeners.end(); ++i)
939 for (BoundListenerBag::iterator j(i->second.begin());
940 j != i->second.end(); ++j)
942 (*j)->disposing(event);
945 for (Impl::VetoListenerMap::iterator i(vetoListeners.begin());
946 i != vetoListeners.end(); ++i)
948 for (Impl::VetoListenerBag::iterator j(i->second.begin());
949 j != i->second.end(); ++j)
951 (*j)->disposing(event);
956 css::uno::Any PropertySetMixinImpl::queryInterface(css::uno::Type const & type)
957 throw (css::uno::RuntimeException, std::exception)
959 if (((m_impl->implements & IMPLEMENTS_PROPERTY_SET) != 0
960 && type == css::beans::XPropertySet::static_type()))
962 css::uno::Reference< css::uno::XInterface > ifc(
963 static_cast< css::beans::XPropertySet * >(this));
964 return css::uno::Any(&ifc, type);
965 } else if ((m_impl->implements & IMPLEMENTS_FAST_PROPERTY_SET) != 0
966 && type == css::beans::XFastPropertySet::static_type())
968 css::uno::Reference< css::uno::XInterface > ifc(
969 static_cast< css::beans::XFastPropertySet * >(this));
970 return css::uno::Any(&ifc, type);
971 } else if ((m_impl->implements & IMPLEMENTS_PROPERTY_ACCESS) != 0
972 && type == css::beans::XPropertyAccess::static_type())
974 css::uno::Reference< css::uno::XInterface > ifc(
975 static_cast< css::beans::XPropertyAccess * >(this));
976 return css::uno::Any(&ifc, type);
977 } else {
978 return css::uno::Any();
982 css::uno::Reference< css::beans::XPropertySetInfo >
983 PropertySetMixinImpl::getPropertySetInfo()
984 throw (css::uno::RuntimeException, std::exception)
986 return new Info(m_impl);
989 void PropertySetMixinImpl::setPropertyValue(
990 rtl::OUString const & propertyName, css::uno::Any const & value)
991 throw (
992 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
993 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
994 css::uno::RuntimeException, std::exception)
996 m_impl->setProperty(
997 static_cast< css::beans::XPropertySet * >(this), propertyName, value,
998 false, false, 1);
1001 css::uno::Any PropertySetMixinImpl::getPropertyValue(
1002 rtl::OUString const & propertyName)
1003 throw (
1004 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1005 css::uno::RuntimeException, std::exception)
1007 return m_impl->getProperty(
1008 static_cast< css::beans::XPropertySet * >(this), propertyName, nullptr);
1011 void PropertySetMixinImpl::addPropertyChangeListener(
1012 rtl::OUString const & propertyName,
1013 css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
1014 throw (
1015 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1016 css::uno::RuntimeException, std::exception)
1018 css::uno::Reference< css::beans::XPropertyChangeListener >(
1019 listener, css::uno::UNO_SET_THROW); // reject NULL listener
1020 checkUnknown(propertyName);
1021 bool disposed;
1023 osl::MutexGuard g(m_impl->mutex);
1024 disposed = m_impl->disposed;
1025 if (!disposed) {
1026 m_impl->boundListeners[propertyName].insert(listener);
1029 if (disposed) {
1030 listener->disposing(
1031 css::lang::EventObject(
1032 static_cast< css::beans::XPropertySet * >(this)));
1036 void PropertySetMixinImpl::removePropertyChangeListener(
1037 rtl::OUString const & propertyName,
1038 css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
1039 throw (
1040 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1041 css::uno::RuntimeException, std::exception)
1043 assert(listener.is());
1044 checkUnknown(propertyName);
1045 osl::MutexGuard g(m_impl->mutex);
1046 Impl::BoundListenerMap::iterator i(
1047 m_impl->boundListeners.find(propertyName));
1048 if (i != m_impl->boundListeners.end()) {
1049 BoundListenerBag::iterator j(i->second.find(listener));
1050 if (j != i->second.end()) {
1051 i->second.erase(j);
1056 void PropertySetMixinImpl::addVetoableChangeListener(
1057 rtl::OUString const & propertyName,
1058 css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
1059 throw (
1060 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1061 css::uno::RuntimeException, std::exception)
1063 css::uno::Reference< css::beans::XVetoableChangeListener >(
1064 listener, css::uno::UNO_SET_THROW); // reject NULL listener
1065 checkUnknown(propertyName);
1066 bool disposed;
1068 osl::MutexGuard g(m_impl->mutex);
1069 disposed = m_impl->disposed;
1070 if (!disposed) {
1071 m_impl->vetoListeners[propertyName].insert(listener);
1074 if (disposed) {
1075 listener->disposing(
1076 css::lang::EventObject(
1077 static_cast< css::beans::XPropertySet * >(this)));
1081 void PropertySetMixinImpl::removeVetoableChangeListener(
1082 rtl::OUString const & propertyName,
1083 css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
1084 throw (
1085 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1086 css::uno::RuntimeException, std::exception)
1088 assert(listener.is());
1089 checkUnknown(propertyName);
1090 osl::MutexGuard g(m_impl->mutex);
1091 Impl::VetoListenerMap::iterator i(m_impl->vetoListeners.find(propertyName));
1092 if (i != m_impl->vetoListeners.end()) {
1093 Impl::VetoListenerBag::iterator j(i->second.find(listener));
1094 if (j != i->second.end()) {
1095 i->second.erase(j);
1100 void PropertySetMixinImpl::setFastPropertyValue(
1101 sal_Int32 handle, css::uno::Any const & value)
1102 throw (
1103 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1104 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1105 css::uno::RuntimeException, std::exception)
1107 m_impl->setProperty(
1108 static_cast< css::beans::XPropertySet * >(this),
1109 m_impl->translateHandle(
1110 static_cast< css::beans::XPropertySet * >(this), handle),
1111 value, false, false, 1);
1114 css::uno::Any PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle)
1115 throw (
1116 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1117 css::uno::RuntimeException, std::exception)
1119 return m_impl->getProperty(
1120 static_cast< css::beans::XPropertySet * >(this),
1121 m_impl->translateHandle(
1122 static_cast< css::beans::XPropertySet * >(this), handle),
1123 nullptr);
1126 css::uno::Sequence< css::beans::PropertyValue >
1127 PropertySetMixinImpl::getPropertyValues()
1128 throw (css::uno::RuntimeException, std::exception)
1130 css::uno::Sequence< css::beans::PropertyValue > s(
1131 m_impl->handleMap.getLength());
1132 sal_Int32 n = 0;
1133 for (sal_Int32 i = 0; i < m_impl->handleMap.getLength(); ++i) {
1134 try {
1135 s[n].Value = m_impl->getProperty(
1136 static_cast< css::beans::XPropertySet * >(this),
1137 m_impl->handleMap[i], &s[n].State);
1138 } catch (css::beans::UnknownPropertyException &) {
1139 continue;
1140 } catch (css::lang::WrappedTargetException & e) {
1141 throw css::lang::WrappedTargetRuntimeException(
1142 e.Message, static_cast< css::beans::XPropertySet * >(this),
1143 e.TargetException);
1145 s[n].Name = m_impl->handleMap[i];
1146 s[n].Handle = i;
1147 ++n;
1149 s.realloc(n);
1150 return s;
1153 void PropertySetMixinImpl::setPropertyValues(
1154 css::uno::Sequence< css::beans::PropertyValue > const & props)
1155 throw (
1156 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1157 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1158 css::uno::RuntimeException, std::exception)
1160 for (sal_Int32 i = 0; i < props.getLength(); ++i) {
1161 if (props[i].Handle != -1
1162 && (props[i].Name
1163 != m_impl->translateHandle(
1164 static_cast< css::beans::XPropertySet * >(this),
1165 props[i].Handle)))
1167 throw css::beans::UnknownPropertyException(
1168 ("name " + props[i].Name + " does not match handle "
1169 + rtl::OUString::number(props[i].Handle)),
1170 static_cast< css::beans::XPropertySet * >(this));
1172 m_impl->setProperty(
1173 static_cast< css::beans::XPropertySet * >(this), props[i].Name,
1174 props[i].Value,
1175 props[i].State == css::beans::PropertyState_AMBIGUOUS_VALUE,
1176 props[i].State == css::beans::PropertyState_DEFAULT_VALUE, 0);
1180 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */