Bump version to 4.3-4
[LibreOffice.git] / cppuhelper / source / propertysetmixin.cxx
blob51984dbe0244946c8eab18c500022e0863756291
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 setUnknown = false;
167 if (attr->isReadOnly()) {
168 attrAttribs |= css::beans::PropertyAttribute::READONLY;
169 setUnknown = true;
171 css::uno::Sequence<
172 css::uno::Reference<
173 css::reflection::XCompoundTypeDescription > > excs(
174 attr->getGetExceptions());
175 bool getUnknown = 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 getUnknown = 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 setUnknown = true;
191 } else if ( excs[j]->getName() == "com.sun.star.beans.PropertyVetoException" )
193 attrAttribs
194 |= css::beans::PropertyAttribute::CONSTRAINED;
197 if (getUnknown && setUnknown) {
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",
235 css::uno::Reference< css::uno::XInterface >());
237 t = args[0];
239 std::vector< rtl::OUString >::size_type handles
240 = handleNames->size();
241 if (handles > SAL_MAX_INT32) {
242 throw css::uno::RuntimeException(
243 "interface type has too many attributes",
244 css::uno::Reference< css::uno::XInterface >());
246 rtl::OUString name(members[i]->getMemberName());
247 if (!properties.insert(
248 PropertyMap::value_type(
249 name,
250 PropertyData(
251 css::beans::Property(
252 name, static_cast< sal_Int32 >(handles),
253 css::uno::Type(
254 t->getTypeClass(), t->getName()),
255 attrAttribs),
256 (std::find(absentBegin, absentEnd, name)
257 == absentEnd)))).
258 second)
260 throw css::uno::RuntimeException(
261 "inconsistent UNO type registry",
262 css::uno::Reference< css::uno::XInterface >());
264 handleNames->push_back(name);
270 css::uno::Reference< css::reflection::XTypeDescription > Data::resolveTypedefs(
271 css::uno::Reference< css::reflection::XTypeDescription > const & type)
273 css::uno::Reference< css::reflection::XTypeDescription > t(type);
274 while (t->getTypeClass() == css::uno::TypeClass_TYPEDEF) {
275 t = css::uno::Reference< css::reflection::XIndirectTypeDescription >(
276 t, css::uno::UNO_QUERY_THROW)->getReferencedType();
278 return t;
281 class Info: public cppu::WeakImplHelper1< css::beans::XPropertySetInfo > {
282 public:
283 explicit Info(Data * data): m_data(data) {}
285 virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties()
286 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
288 virtual css::beans::Property SAL_CALL getPropertyByName(
289 rtl::OUString const & name)
290 throw (
291 css::beans::UnknownPropertyException, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
293 virtual sal_Bool SAL_CALL hasPropertyByName(rtl::OUString const & name)
294 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
296 private:
297 rtl::Reference< Data > m_data;
300 css::uno::Sequence< css::beans::Property > Info::getProperties()
301 throw (css::uno::RuntimeException, std::exception)
303 assert(m_data->properties.size() <= SAL_MAX_INT32);
304 css::uno::Sequence< css::beans::Property > s(
305 static_cast< sal_Int32 >(m_data->properties.size()));
306 sal_Int32 n = 0;
307 for (Data::PropertyMap::iterator i(m_data->properties.begin());
308 i != m_data->properties.end(); ++i)
310 if (i->second.present) {
311 s[n++] = i->second.property;
314 s.realloc(n);
315 return s;
318 css::beans::Property Info::getPropertyByName(rtl::OUString const & name)
319 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException, std::exception)
321 return m_data->get(static_cast< cppu::OWeakObject * >(this), name)->
322 second.property;
325 sal_Bool Info::hasPropertyByName(rtl::OUString const & name)
326 throw (css::uno::RuntimeException, std::exception)
328 Data::PropertyMap::iterator i(m_data->properties.find(name));
329 return i != m_data->properties.end() && i->second.present;
332 typedef
333 std::multiset< css::uno::Reference< css::beans::XPropertyChangeListener > >
334 BoundListenerBag;
338 class PropertySetMixinImpl::BoundListeners::Impl {
339 public:
340 BoundListenerBag specificListeners;
341 BoundListenerBag unspecificListeners;
342 css::beans::PropertyChangeEvent event;
345 PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl) {}
347 PropertySetMixinImpl::BoundListeners::~BoundListeners() {
348 delete m_impl;
351 void PropertySetMixinImpl::BoundListeners::notify() const {
352 for (BoundListenerBag::const_iterator i(m_impl->specificListeners.begin());
353 i != m_impl->specificListeners.end(); ++i)
355 try {
356 (*i)->propertyChange(m_impl->event);
357 } catch (css::lang::DisposedException &) {}
359 for (BoundListenerBag::const_iterator i(
360 m_impl->unspecificListeners.begin());
361 i != m_impl->unspecificListeners.end(); ++i)
363 try {
364 (*i)->propertyChange(m_impl->event);
365 } catch (css::lang::DisposedException &) {}
369 class PropertySetMixinImpl::Impl: public Data {
370 public:
371 Impl(
372 css::uno::Reference< css::uno::XComponentContext > const & context,
373 Implements theImplements,
374 css::uno::Sequence< rtl::OUString > const & absentOptional,
375 css::uno::Type const & type);
377 rtl::OUString translateHandle(
378 css::uno::Reference< css::uno::XInterface > const & object,
379 sal_Int32 handle) const;
381 void setProperty(
382 css::uno::Reference< css::uno::XInterface > const & object,
383 rtl::OUString const & name, css::uno::Any const & value,
384 bool isAmbiguous, bool isDefaulted, sal_Int16 illegalArgumentPosition)
385 const;
387 css::uno::Any getProperty(
388 css::uno::Reference< css::uno::XInterface > const & object,
389 rtl::OUString const & name, css::beans::PropertyState * state) const;
391 PropertySetMixinImpl::Implements implements;
392 css::uno::Sequence< rtl::OUString > handleMap;
394 typedef std::map< rtl::OUString, BoundListenerBag > BoundListenerMap;
396 typedef
397 std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > >
398 VetoListenerBag;
400 typedef std::map< rtl::OUString, VetoListenerBag > VetoListenerMap;
402 mutable osl::Mutex mutex;
403 BoundListenerMap boundListeners;
404 VetoListenerMap vetoListeners;
405 bool disposed;
407 private:
408 css::uno::Reference< css::reflection::XIdlClass > getReflection(
409 rtl::OUString const & typeName) const;
411 static css::uno::Any wrapValue(
412 css::uno::Reference< css::uno::XInterface > const & object,
413 css::uno::Any const & value,
414 css::uno::Reference< css::reflection::XIdlClass > const & type,
415 bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted,
416 bool isDefaulted, bool wrapOptional);
418 css::uno::Reference< css::uno::XComponentContext > const & m_context;
419 css::uno::Sequence< rtl::OUString > m_absentOptional;
420 css::uno::Type m_type;
421 css::uno::Reference< css::reflection::XIdlClass > m_idlClass;
424 PropertySetMixinImpl::Impl::Impl(
425 css::uno::Reference< css::uno::XComponentContext > const & context,
426 Implements theImplements,
427 css::uno::Sequence< rtl::OUString > const & absentOptional,
428 css::uno::Type const & type):
429 implements(theImplements), disposed(false), m_context(context),
430 m_absentOptional(absentOptional), m_type(type)
432 assert(context.is());
433 assert(
434 (implements
435 & ~(IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET
436 | IMPLEMENTS_PROPERTY_ACCESS))
437 == 0);
438 m_idlClass = getReflection(m_type.getTypeName());
439 css::uno::Reference< css::reflection::XTypeDescription > ifc;
440 try {
441 ifc = css::uno::Reference< css::reflection::XTypeDescription >(
442 css::uno::Reference< css::container::XHierarchicalNameAccess >(
443 m_context->getValueByName(
444 "/singletons/com.sun.star.reflection."
445 "theTypeDescriptionManager"),
446 css::uno::UNO_QUERY_THROW)->getByHierarchicalName(
447 m_type.getTypeName()),
448 css::uno::UNO_QUERY_THROW);
449 } catch (css::container::NoSuchElementException & e) {
450 throw css::uno::RuntimeException(
451 ("unexpected com.sun.star.container.NoSuchElementException: "
452 + e.Message),
453 css::uno::Reference< css::uno::XInterface >());
455 std::vector< rtl::OUString > handleNames;
456 initProperties(ifc, m_absentOptional, &handleNames);
457 std::vector< rtl::OUString >::size_type size = handleNames.size();
458 assert(size <= SAL_MAX_INT32);
459 handleMap.realloc(static_cast< sal_Int32 >(size));
460 std::copy(handleNames.begin(), handleNames.end(), handleMap.getArray());
463 rtl::OUString PropertySetMixinImpl::Impl::translateHandle(
464 css::uno::Reference< css::uno::XInterface > const & object,
465 sal_Int32 handle) const
467 if (handle < 0 || handle >= handleMap.getLength()) {
468 throw css::beans::UnknownPropertyException(
469 "bad handle " + rtl::OUString::number(handle), object);
471 return handleMap[handle];
474 void PropertySetMixinImpl::Impl::setProperty(
475 css::uno::Reference< css::uno::XInterface > const & object,
476 rtl::OUString const & name, css::uno::Any const & value, bool isAmbiguous,
477 bool isDefaulted, sal_Int16 illegalArgumentPosition) const
479 PropertyMap::const_iterator i(properties.find(name));
480 if (i == properties.end()) {
481 throw css::beans::UnknownPropertyException(name, object);
483 if ((isAmbiguous
484 && ((i->second.property.Attributes
485 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
486 == 0))
487 || (isDefaulted
488 && ((i->second.property.Attributes
489 & css::beans::PropertyAttribute::MAYBEDEFAULT)
490 == 0)))
492 throw css::lang::IllegalArgumentException(
493 ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
494 + name),
495 object, illegalArgumentPosition);
497 css::uno::Reference< css::reflection::XIdlField2 > f(
498 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
499 css::uno::Any o(object->queryInterface(m_type));
500 css::uno::Any v(
501 wrapValue(
502 object, value,
503 (css::uno::Reference< css::reflection::XIdlField2 >(
504 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW)->
505 getType()),
506 ((i->second.property.Attributes
507 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
508 != 0),
509 isAmbiguous,
510 ((i->second.property.Attributes
511 & css::beans::PropertyAttribute::MAYBEDEFAULT)
512 != 0),
513 isDefaulted,
514 ((i->second.property.Attributes
515 & css::beans::PropertyAttribute::MAYBEVOID)
516 != 0)));
517 try {
518 f->set(o, v);
519 } catch (css::lang::IllegalArgumentException & e) {
520 if (e.ArgumentPosition == 1) {
521 throw css::lang::IllegalArgumentException(
522 e.Message, object, illegalArgumentPosition);
523 } else {
524 throw css::uno::RuntimeException(
525 ("unexpected com.sun.star.lang.IllegalArgumentException: "
526 + e.Message),
527 object);
529 } catch (css::lang::IllegalAccessException &) {
530 //TODO Clarify whether PropertyVetoException is the correct exception
531 // to throw when trying to set a read-only property:
532 throw css::beans::PropertyVetoException(
533 "cannot set read-only property " + name, object);
534 } catch (css::lang::WrappedTargetRuntimeException & e) {
535 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
536 // guaranteed to originate directly within XIdlField2.get (and thus have
537 // the expected semantics); it might also be passed through from lower
538 // layers.
539 if (e.TargetException.isExtractableTo(
540 cppu::UnoType<css::beans::UnknownPropertyException>::get())
541 && ((i->second.property.Attributes
542 & css::beans::PropertyAttribute::OPTIONAL)
543 != 0))
545 throw css::beans::UnknownPropertyException(name, object);
546 } else if (e.TargetException.isExtractableTo(
547 cppu::UnoType<css::beans::PropertyVetoException>::get())
548 && ((i->second.property.Attributes
549 & css::beans::PropertyAttribute::CONSTRAINED)
550 != 0))
552 css::beans::PropertyVetoException exc;
553 e.TargetException >>= exc;
554 if (exc.Message.isEmpty() )
555 throw css::beans::PropertyVetoException("Invalid " + name, object);
556 else
557 throw exc;
558 } else {
559 throw css::lang::WrappedTargetException(
560 e.Message, object, e.TargetException);
565 css::uno::Any PropertySetMixinImpl::Impl::getProperty(
566 css::uno::Reference< css::uno::XInterface > const & object,
567 rtl::OUString const & name, css::beans::PropertyState * state) const
569 PropertyMap::const_iterator i(properties.find(name));
570 if (i == properties.end()) {
571 throw css::beans::UnknownPropertyException(name, object);
573 css::uno::Reference< css::reflection::XIdlField2 > field(
574 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
575 css::uno::Any value;
576 try {
577 value = field->get(object->queryInterface(m_type));
578 } catch (css::lang::IllegalArgumentException & e) {
579 throw css::uno::RuntimeException(
580 ("unexpected com.sun.star.lang.IllegalArgumentException: "
581 + e.Message),
582 object);
583 } catch (css::lang::WrappedTargetRuntimeException & e) {
584 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
585 // guaranteed to originate directly within XIdlField2.get (and thus have
586 // the expected semantics); it might also be passed through from lower
587 // layers.
588 if (e.TargetException.isExtractableTo(
589 cppu::UnoType<css::beans::UnknownPropertyException>::get())
590 && ((i->second.property.Attributes
591 & css::beans::PropertyAttribute::OPTIONAL)
592 != 0))
594 throw css::beans::UnknownPropertyException(name, object);
595 } else {
596 throw css::lang::WrappedTargetException(
597 e.Message, object, e.TargetException);
600 bool undoAmbiguous
601 = ((i->second.property.Attributes
602 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
603 != 0);
604 bool undoDefaulted
605 = ((i->second.property.Attributes
606 & css::beans::PropertyAttribute::MAYBEDEFAULT)
607 != 0);
608 bool undoOptional
609 = ((i->second.property.Attributes
610 & css::beans::PropertyAttribute::MAYBEVOID)
611 != 0);
612 bool isAmbiguous = false;
613 bool isDefaulted = false;
614 while (undoAmbiguous || undoDefaulted || undoOptional) {
615 if (undoAmbiguous
616 && value.getValueTypeName().startsWith(
617 "com.sun.star.beans.Ambiguous<"))
619 css::uno::Reference< css::reflection::XIdlClass > ambiguous(
620 getReflection(value.getValueTypeName()));
621 try {
622 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
623 ambiguous->getField("IsAmbiguous"),
624 css::uno::UNO_QUERY_THROW)->get(value)
625 >>= isAmbiguous))
627 throw css::uno::RuntimeException(
628 ("unexpected type of com.sun.star.beans.Ambiguous"
629 " IsAmbiguous member"),
630 object);
632 value = css::uno::Reference< css::reflection::XIdlField2 >(
633 ambiguous->getField("Value"), css::uno::UNO_QUERY_THROW)->
634 get(value);
635 } catch (css::lang::IllegalArgumentException & e) {
636 throw css::uno::RuntimeException(
637 ("unexpected com.sun.star.lang.IllegalArgumentException: "
638 + e.Message),
639 object);
641 undoAmbiguous = false;
642 } else if (undoDefaulted
643 && value.getValueTypeName().startsWith(
644 "com.sun.star.beans.Defaulted<"))
646 css::uno::Reference< css::reflection::XIdlClass > defaulted(
647 getReflection(value.getValueTypeName()));
648 try {
650 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
651 defaulted->getField("IsDefaulted"),
652 css::uno::UNO_QUERY_THROW)->get(value)
653 >>= isDefaulted))
655 throw css::uno::RuntimeException(
656 ("unexpected type of com.sun.star.beans.Defaulted"
657 " IsDefaulted member"),
658 object);
660 value = css::uno::Reference< css::reflection::XIdlField2 >(
661 defaulted->getField("Value"), css::uno::UNO_QUERY_THROW)->
662 get(value);
663 } catch (css::lang::IllegalArgumentException & e) {
664 throw css::uno::RuntimeException(
665 ("unexpected com.sun.star.lang.IllegalArgumentException: "
666 + e.Message),
667 object);
669 undoDefaulted = false;
670 } else if (undoOptional
671 && value.getValueTypeName().startsWith(
672 "com.sun.star.beans.Optional<"))
674 css::uno::Reference< css::reflection::XIdlClass > optional(
675 getReflection(value.getValueTypeName()));
676 try {
677 bool present = false;
678 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
679 optional->getField("IsPresent"),
680 css::uno::UNO_QUERY_THROW)->get(value)
681 >>= present))
683 throw css::uno::RuntimeException(
684 ("unexpected type of com.sun.star.beans.Optional"
685 " IsPresent member"),
686 object);
688 if (!present) {
689 value.clear();
690 break;
692 value = css::uno::Reference< css::reflection::XIdlField2 >(
693 optional->getField("Value"), css::uno::UNO_QUERY_THROW)->
694 get(value);
695 } catch (css::lang::IllegalArgumentException & e) {
696 throw css::uno::RuntimeException(
697 ("unexpected com.sun.star.lang.IllegalArgumentException: "
698 + e.Message),
699 object);
701 undoOptional = false;
702 } else {
703 throw css::uno::RuntimeException(
704 "unexpected type of attribute " + name, object);
707 if (state != 0) {
708 //XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE
709 // over DEFAULT_VALUE:
710 *state = isAmbiguous
711 ? css::beans::PropertyState_AMBIGUOUS_VALUE
712 : isDefaulted
713 ? css::beans::PropertyState_DEFAULT_VALUE
714 : css::beans::PropertyState_DIRECT_VALUE;
716 return value;
719 css::uno::Reference< css::reflection::XIdlClass >
720 PropertySetMixinImpl::Impl::getReflection(rtl::OUString const & typeName) const
722 return css::uno::Reference< css::reflection::XIdlClass >(
723 css::reflection::theCoreReflection::get(m_context)->forName(typeName),
724 css::uno::UNO_SET_THROW);
727 css::uno::Any PropertySetMixinImpl::Impl::wrapValue(
728 css::uno::Reference< css::uno::XInterface > const & object,
729 css::uno::Any const & value,
730 css::uno::Reference< css::reflection::XIdlClass > const & type,
731 bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted, bool isDefaulted,
732 bool wrapOptional)
734 assert(wrapAmbiguous || !isAmbiguous);
735 assert(wrapDefaulted || !isDefaulted);
736 if (wrapAmbiguous
737 && type->getName().startsWith("com.sun.star.beans.Ambiguous<"))
739 css::uno::Any strct;
740 type->createObject(strct);
741 try {
742 css::uno::Reference< css::reflection::XIdlField2 > field(
743 type->getField("Value"), css::uno::UNO_QUERY_THROW);
744 field->set(
745 strct,
746 wrapValue(
747 object, value, field->getType(), false, false,
748 wrapDefaulted, isDefaulted, wrapOptional));
749 css::uno::Reference< css::reflection::XIdlField2 >(
750 type->getField("IsAmbiguous"), css::uno::UNO_QUERY_THROW)->set(
751 strct, css::uno::makeAny(isAmbiguous));
752 } catch (css::lang::IllegalArgumentException & e) {
753 throw css::uno::RuntimeException(
754 ("unexpected com.sun.star.lang.IllegalArgumentException: "
755 + e.Message),
756 object);
757 } catch (css::lang::IllegalAccessException & e) {
758 throw css::uno::RuntimeException(
759 ("unexpected com.sun.star.lang.IllegalAccessException: "
760 + e.Message),
761 object);
763 return strct;
764 } else if (wrapDefaulted
765 && type->getName().startsWith("com.sun.star.beans.Defaulted<"))
767 css::uno::Any strct;
768 type->createObject(strct);
769 try {
770 css::uno::Reference< css::reflection::XIdlField2 > field(
771 type->getField("Value"), css::uno::UNO_QUERY_THROW);
772 field->set(
773 strct,
774 wrapValue(
775 object, value, field->getType(), wrapAmbiguous, isAmbiguous,
776 false, false, wrapOptional));
777 css::uno::Reference< css::reflection::XIdlField2 >(
778 type->getField("IsDefaulted"), css::uno::UNO_QUERY_THROW)->set(
779 strct, css::uno::makeAny(isDefaulted));
780 } catch (css::lang::IllegalArgumentException & e) {
781 throw css::uno::RuntimeException(
782 ("unexpected com.sun.star.lang.IllegalArgumentException: "
783 + e.Message),
784 object);
785 } catch (css::lang::IllegalAccessException & e) {
786 throw css::uno::RuntimeException(
787 ("unexpected com.sun.star.lang.IllegalAccessException: "
788 + e.Message),
789 object);
791 return strct;
792 } else if (wrapOptional
793 && type->getName().startsWith("com.sun.star.beans.Optional<"))
795 css::uno::Any strct;
796 type->createObject(strct);
797 bool present = value.hasValue();
798 try {
799 css::uno::Reference< css::reflection::XIdlField2 >(
800 type->getField("IsPresent"), css::uno::UNO_QUERY_THROW)->set(
801 strct, css::uno::makeAny(present));
802 if (present) {
803 css::uno::Reference< css::reflection::XIdlField2 > field(
804 type->getField("Value"), css::uno::UNO_QUERY_THROW);
805 field->set(
806 strct,
807 wrapValue(
808 object, value, field->getType(), wrapAmbiguous,
809 isAmbiguous, wrapDefaulted, isDefaulted, false));
811 } catch (css::lang::IllegalArgumentException & e) {
812 throw css::uno::RuntimeException(
813 ("unexpected com.sun.star.lang.IllegalArgumentException: "
814 + e.Message),
815 object);
816 } catch (css::lang::IllegalAccessException & e) {
817 throw css::uno::RuntimeException(
818 ("unexpected com.sun.star.lang.IllegalAccessException: "
819 + e.Message),
820 object);
822 return strct;
823 } else {
824 if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
825 throw css::uno::RuntimeException(
826 "unexpected type of attribute", object);
828 return value;
832 PropertySetMixinImpl::PropertySetMixinImpl(
833 css::uno::Reference< css::uno::XComponentContext > const & context,
834 Implements implements,
835 css::uno::Sequence< rtl::OUString > const & absentOptional,
836 css::uno::Type const & type)
838 m_impl = new Impl(context, implements, absentOptional, type);
839 m_impl->acquire();
842 PropertySetMixinImpl::~PropertySetMixinImpl() {
843 m_impl->release();
846 void PropertySetMixinImpl::checkUnknown(rtl::OUString const & propertyName) {
847 if (!propertyName.isEmpty()) {
848 m_impl->get(
849 static_cast< css::beans::XPropertySet * >(this), propertyName);
853 void PropertySetMixinImpl::prepareSet(
854 rtl::OUString const & propertyName, css::uno::Any const & oldValue,
855 css::uno::Any const & newValue, BoundListeners * boundListeners)
857 Impl::PropertyMap::const_iterator it(m_impl->properties.find(propertyName));
858 assert(it != m_impl->properties.end());
859 Impl::VetoListenerBag specificVeto;
860 Impl::VetoListenerBag unspecificVeto;
862 osl::MutexGuard g(m_impl->mutex);
863 if (m_impl->disposed) {
864 throw css::lang::DisposedException(
865 "disposed", static_cast< css::beans::XPropertySet * >(this));
867 if ((it->second.property.Attributes
868 & css::beans::PropertyAttribute::CONSTRAINED)
869 != 0)
871 Impl::VetoListenerMap::const_iterator i(
872 m_impl->vetoListeners.find(propertyName));
873 if (i != m_impl->vetoListeners.end()) {
874 specificVeto = i->second;
876 i = m_impl->vetoListeners.find("");
877 if (i != m_impl->vetoListeners.end()) {
878 unspecificVeto = i->second;
881 if ((it->second.property.Attributes
882 & css::beans::PropertyAttribute::BOUND)
883 != 0)
885 assert(boundListeners != 0);
886 Impl::BoundListenerMap::const_iterator i(
887 m_impl->boundListeners.find(propertyName));
888 if (i != m_impl->boundListeners.end()) {
889 boundListeners->m_impl->specificListeners = i->second;
891 i = m_impl->boundListeners.find("");
892 if (i != m_impl->boundListeners.end()) {
893 boundListeners->m_impl->unspecificListeners = i->second;
897 if ((it->second.property.Attributes
898 & css::beans::PropertyAttribute::CONSTRAINED)
899 != 0)
901 css::beans::PropertyChangeEvent event(
902 static_cast< css::beans::XPropertySet * >(this), propertyName,
903 false, it->second.property.Handle, oldValue, newValue);
904 for (Impl::VetoListenerBag::iterator i(specificVeto.begin());
905 i != specificVeto.end(); ++i)
907 try {
908 (*i)->vetoableChange(event);
909 } catch (css::lang::DisposedException &) {}
911 for (Impl::VetoListenerBag::iterator i(unspecificVeto.begin());
912 i != unspecificVeto.end(); ++i)
914 try {
915 (*i)->vetoableChange(event);
916 } catch (css::lang::DisposedException &) {}
919 if ((it->second.property.Attributes & css::beans::PropertyAttribute::BOUND)
920 != 0)
922 assert(boundListeners != 0);
923 boundListeners->m_impl->event = css::beans::PropertyChangeEvent(
924 static_cast< css::beans::XPropertySet * >(this), propertyName,
925 false, it->second.property.Handle, oldValue, newValue);
929 void PropertySetMixinImpl::dispose() {
930 Impl::BoundListenerMap boundListeners;
931 Impl::VetoListenerMap vetoListeners;
933 osl::MutexGuard g(m_impl->mutex);
934 boundListeners.swap(m_impl->boundListeners);
935 vetoListeners.swap(m_impl->vetoListeners);
936 m_impl->disposed = true;
938 css::lang::EventObject event(
939 static_cast< css::beans::XPropertySet * >(this));
940 for (Impl::BoundListenerMap::iterator i(boundListeners.begin());
941 i != boundListeners.end(); ++i)
943 for (BoundListenerBag::iterator j(i->second.begin());
944 j != i->second.end(); ++j)
946 (*j)->disposing(event);
949 for (Impl::VetoListenerMap::iterator i(vetoListeners.begin());
950 i != vetoListeners.end(); ++i)
952 for (Impl::VetoListenerBag::iterator j(i->second.begin());
953 j != i->second.end(); ++j)
955 (*j)->disposing(event);
960 css::uno::Any PropertySetMixinImpl::queryInterface(css::uno::Type const & type)
961 throw (css::uno::RuntimeException, std::exception)
963 if (((m_impl->implements & IMPLEMENTS_PROPERTY_SET) != 0
964 && type == css::beans::XPropertySet::static_type()))
966 css::uno::Reference< css::uno::XInterface > ifc(
967 static_cast< css::beans::XPropertySet * >(this));
968 return css::uno::Any(&ifc, type);
969 } else if ((m_impl->implements & IMPLEMENTS_FAST_PROPERTY_SET) != 0
970 && type == css::beans::XFastPropertySet::static_type())
972 css::uno::Reference< css::uno::XInterface > ifc(
973 static_cast< css::beans::XFastPropertySet * >(this));
974 return css::uno::Any(&ifc, type);
975 } else if ((m_impl->implements & IMPLEMENTS_PROPERTY_ACCESS) != 0
976 && type == css::beans::XPropertyAccess::static_type())
978 css::uno::Reference< css::uno::XInterface > ifc(
979 static_cast< css::beans::XPropertyAccess * >(this));
980 return css::uno::Any(&ifc, type);
981 } else {
982 return css::uno::Any();
986 css::uno::Reference< css::beans::XPropertySetInfo >
987 PropertySetMixinImpl::getPropertySetInfo()
988 throw (css::uno::RuntimeException, std::exception)
990 return new Info(m_impl);
993 void PropertySetMixinImpl::setPropertyValue(
994 rtl::OUString const & propertyName, css::uno::Any const & value)
995 throw (
996 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
997 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
998 css::uno::RuntimeException, std::exception)
1000 m_impl->setProperty(
1001 static_cast< css::beans::XPropertySet * >(this), propertyName, value,
1002 false, false, 1);
1005 css::uno::Any PropertySetMixinImpl::getPropertyValue(
1006 rtl::OUString const & propertyName)
1007 throw (
1008 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1009 css::uno::RuntimeException, std::exception)
1011 return m_impl->getProperty(
1012 static_cast< css::beans::XPropertySet * >(this), propertyName, 0);
1015 void PropertySetMixinImpl::addPropertyChangeListener(
1016 rtl::OUString const & propertyName,
1017 css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
1018 throw (
1019 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1020 css::uno::RuntimeException, std::exception)
1022 css::uno::Reference< css::beans::XPropertyChangeListener >(
1023 listener, css::uno::UNO_SET_THROW); // reject NULL listener
1024 checkUnknown(propertyName);
1025 bool disposed;
1027 osl::MutexGuard g(m_impl->mutex);
1028 disposed = m_impl->disposed;
1029 if (!disposed) {
1030 m_impl->boundListeners[propertyName].insert(listener);
1033 if (disposed) {
1034 listener->disposing(
1035 css::lang::EventObject(
1036 static_cast< css::beans::XPropertySet * >(this)));
1040 void PropertySetMixinImpl::removePropertyChangeListener(
1041 rtl::OUString const & propertyName,
1042 css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
1043 throw (
1044 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1045 css::uno::RuntimeException, std::exception)
1047 assert(listener.is());
1048 checkUnknown(propertyName);
1049 osl::MutexGuard g(m_impl->mutex);
1050 Impl::BoundListenerMap::iterator i(
1051 m_impl->boundListeners.find(propertyName));
1052 if (i != m_impl->boundListeners.end()) {
1053 BoundListenerBag::iterator j(i->second.find(listener));
1054 if (j != i->second.end()) {
1055 i->second.erase(j);
1060 void PropertySetMixinImpl::addVetoableChangeListener(
1061 rtl::OUString const & propertyName,
1062 css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
1063 throw (
1064 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1065 css::uno::RuntimeException, std::exception)
1067 css::uno::Reference< css::beans::XVetoableChangeListener >(
1068 listener, css::uno::UNO_SET_THROW); // reject NULL listener
1069 checkUnknown(propertyName);
1070 bool disposed;
1072 osl::MutexGuard g(m_impl->mutex);
1073 disposed = m_impl->disposed;
1074 if (!disposed) {
1075 m_impl->vetoListeners[propertyName].insert(listener);
1078 if (disposed) {
1079 listener->disposing(
1080 css::lang::EventObject(
1081 static_cast< css::beans::XPropertySet * >(this)));
1085 void PropertySetMixinImpl::removeVetoableChangeListener(
1086 rtl::OUString const & propertyName,
1087 css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
1088 throw (
1089 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1090 css::uno::RuntimeException, std::exception)
1092 assert(listener.is());
1093 checkUnknown(propertyName);
1094 osl::MutexGuard g(m_impl->mutex);
1095 Impl::VetoListenerMap::iterator i(m_impl->vetoListeners.find(propertyName));
1096 if (i != m_impl->vetoListeners.end()) {
1097 Impl::VetoListenerBag::iterator j(i->second.find(listener));
1098 if (j != i->second.end()) {
1099 i->second.erase(j);
1104 void PropertySetMixinImpl::setFastPropertyValue(
1105 sal_Int32 handle, css::uno::Any const & value)
1106 throw (
1107 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1108 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1109 css::uno::RuntimeException, std::exception)
1111 m_impl->setProperty(
1112 static_cast< css::beans::XPropertySet * >(this),
1113 m_impl->translateHandle(
1114 static_cast< css::beans::XPropertySet * >(this), handle),
1115 value, false, false, 1);
1118 css::uno::Any PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle)
1119 throw (
1120 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1121 css::uno::RuntimeException, std::exception)
1123 return m_impl->getProperty(
1124 static_cast< css::beans::XPropertySet * >(this),
1125 m_impl->translateHandle(
1126 static_cast< css::beans::XPropertySet * >(this), handle),
1130 css::uno::Sequence< css::beans::PropertyValue >
1131 PropertySetMixinImpl::getPropertyValues()
1132 throw (css::uno::RuntimeException, std::exception)
1134 css::uno::Sequence< css::beans::PropertyValue > s(
1135 m_impl->handleMap.getLength());
1136 sal_Int32 n = 0;
1137 for (sal_Int32 i = 0; i < m_impl->handleMap.getLength(); ++i) {
1138 try {
1139 s[n].Value = m_impl->getProperty(
1140 static_cast< css::beans::XPropertySet * >(this),
1141 m_impl->handleMap[i], &s[n].State);
1142 } catch (css::beans::UnknownPropertyException &) {
1143 continue;
1144 } catch (css::lang::WrappedTargetException & e) {
1145 throw css::lang::WrappedTargetRuntimeException(
1146 e.Message, static_cast< css::beans::XPropertySet * >(this),
1147 e.TargetException);
1149 s[n].Name = m_impl->handleMap[i];
1150 s[n].Handle = i;
1151 ++n;
1153 s.realloc(n);
1154 return s;
1157 void PropertySetMixinImpl::setPropertyValues(
1158 css::uno::Sequence< css::beans::PropertyValue > const & props)
1159 throw (
1160 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1161 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1162 css::uno::RuntimeException, std::exception)
1164 for (sal_Int32 i = 0; i < props.getLength(); ++i) {
1165 if (props[i].Handle != -1
1166 && (props[i].Name
1167 != m_impl->translateHandle(
1168 static_cast< css::beans::XPropertySet * >(this),
1169 props[i].Handle)))
1171 throw css::beans::UnknownPropertyException(
1172 ("name " + props[i].Name + " does not match handle "
1173 + rtl::OUString::number(props[i].Handle)),
1174 static_cast< css::beans::XPropertySet * >(this));
1176 m_impl->setProperty(
1177 static_cast< css::beans::XPropertySet * >(this), props[i].Name,
1178 props[i].Value,
1179 props[i].State == css::beans::PropertyState_AMBIGUOUS_VALUE,
1180 props[i].State == css::beans::PropertyState_DEFAULT_VALUE, 0);
1184 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */