LibreOffice Module cppuhelper (master) 1
propertysetmixin.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <algorithm>
23#include <cassert>
24#include <map>
25#include <mutex>
26#include <set>
27#include <utility>
28#include <vector>
29
30#include <com/sun/star/beans/Property.hpp>
31#include <com/sun/star/beans/PropertyChangeEvent.hpp>
32#include <com/sun/star/beans/PropertyAttribute.hpp>
33#include <com/sun/star/beans/PropertyValue.hpp>
34#include <com/sun/star/beans/PropertyVetoException.hpp>
35#include <com/sun/star/beans/UnknownPropertyException.hpp>
36#include <com/sun/star/beans/XFastPropertySet.hpp>
37#include <com/sun/star/beans/XPropertyAccess.hpp>
38#include <com/sun/star/beans/XPropertyChangeListener.hpp>
39#include <com/sun/star/beans/XPropertySet.hpp>
40#include <com/sun/star/beans/XPropertySetInfo.hpp>
41#include <com/sun/star/beans/XVetoableChangeListener.hpp>
42#include <com/sun/star/container/NoSuchElementException.hpp>
43#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
44#include <com/sun/star/lang/DisposedException.hpp>
45#include <com/sun/star/lang/EventObject.hpp>
46#include <com/sun/star/lang/IllegalAccessException.hpp>
47#include <com/sun/star/lang/IllegalArgumentException.hpp>
48#include <com/sun/star/lang/WrappedTargetException.hpp>
49#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
50#include <com/sun/star/reflection/XCompoundTypeDescription.hpp>
51#include <com/sun/star/reflection/XIdlClass.hpp>
52#include <com/sun/star/reflection/XIdlField2.hpp>
53#include <com/sun/star/reflection/XIndirectTypeDescription.hpp>
54#include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp>
55#include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
56#include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp>
57#include <com/sun/star/reflection/XStructTypeDescription.hpp>
58#include <com/sun/star/reflection/XTypeDescription.hpp>
59#include <com/sun/star/reflection/theCoreReflection.hpp>
60#include <com/sun/star/uno/Any.hxx>
61#include <com/sun/star/uno/Reference.hxx>
62#include <com/sun/star/uno/RuntimeException.hpp>
63#include <com/sun/star/uno/Sequence.hxx>
64#include <com/sun/star/uno/Type.hxx>
65#include <com/sun/star/uno/TypeClass.hpp>
66#include <com/sun/star/uno/XComponentContext.hpp>
67#include <com/sun/star/uno/XInterface.hpp>
71#include <cppuhelper/weak.hxx>
72#include <rtl/ref.hxx>
73#include <rtl/ustring.hxx>
74#include <sal/types.h>
76
78
79namespace {
80
81struct PropertyData {
82 explicit PropertyData(
83 css::beans::Property theProperty, bool thePresent):
84 property(std::move(theProperty)), present(thePresent) {}
85
86 css::beans::Property property;
87 bool present;
88};
89
91 typedef std::map< OUString, PropertyData > PropertyMap;
92
94
95 PropertyMap::const_iterator get(
96 css::uno::Reference< css::uno::XInterface > const & object,
97 OUString const & name) const;
98
99protected:
100 void initProperties(
101 css::uno::Reference< css::reflection::XTypeDescription > const & type,
102 css::uno::Sequence< OUString > const & absentOptional,
103 std::vector< OUString > * handleNames)
104 {
105 std::set<OUString> seen;
106 initProperties(type, absentOptional, handleNames, &seen);
107 }
108
109private:
110 void initProperties(
111 css::uno::Reference< css::reflection::XTypeDescription > const & type,
112 css::uno::Sequence< OUString > const & absentOptional,
113 std::vector< OUString > * handleNames, std::set<OUString> * seen);
114
115 static css::uno::Reference< css::reflection::XTypeDescription >
116 resolveTypedefs(
117 css::uno::Reference< css::reflection::XTypeDescription > const & type);
118};
119
120Data::PropertyMap::const_iterator Data::get(
121 css::uno::Reference< css::uno::XInterface > const & object,
122 OUString const & name) const
123{
124 PropertyMap::const_iterator i(properties.find(name));
125 if (i == properties.end() || !i->second.present) {
126 throw css::beans::UnknownPropertyException(name, object);
127 }
128 return i;
129}
130
131void Data::initProperties(
132 css::uno::Reference< css::reflection::XTypeDescription > const & type,
133 css::uno::Sequence< OUString > const & absentOptional,
134 std::vector< OUString > * handleNames, std::set<OUString> * seen)
135{
136 css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > ifc(
137 resolveTypedefs(type), css::uno::UNO_QUERY_THROW);
138 if (!seen->insert(ifc->getName()).second)
139 return;
140
141 const css::uno::Sequence<
142 css::uno::Reference< css::reflection::XTypeDescription > > bases(
143 ifc->getBaseTypes());
144 for (const auto & i : bases) {
145 initProperties(i, absentOptional, handleNames, seen);
146 }
147 const css::uno::Sequence<
148 css::uno::Reference<
149 css::reflection::XInterfaceMemberTypeDescription > > members(
150 ifc->getMembers());
151 OUString const * absentBegin = absentOptional.getConstArray();
152 OUString const * absentEnd =
153 absentBegin + absentOptional.getLength();
154 for (const auto & m : members) {
155 if (m->getTypeClass()
156 == css::uno::TypeClass_INTERFACE_ATTRIBUTE)
157 {
158 css::uno::Reference<
159 css::reflection::XInterfaceAttributeTypeDescription2 > attr(
160 m, css::uno::UNO_QUERY_THROW);
161 sal_Int16 attrAttribs = 0;
162 if (attr->isBound()) {
163 attrAttribs |= css::beans::PropertyAttribute::BOUND;
164 }
165 bool bSetUnknown = false;
166 if (attr->isReadOnly()) {
167 attrAttribs |= css::beans::PropertyAttribute::READONLY;
168 bSetUnknown = true;
169 }
170 css::uno::Sequence<
171 css::uno::Reference<
172 css::reflection::XCompoundTypeDescription > > excs(
173 attr->getGetExceptions());
174 bool bGetUnknown = false;
175 //XXX Special interpretation of getter/setter exceptions only
176 // works if the specified exceptions are of the exact type, not
177 // of a supertype:
178 for (const auto & ex : std::as_const(excs)) {
179 if ( ex->getName() == "com.sun.star.beans.UnknownPropertyException" )
180 {
181 bGetUnknown = true;
182 break;
183 }
184 }
185 excs = attr->getSetExceptions();
186 for (const auto & ex : std::as_const(excs)) {
187 if ( ex->getName() == "com.sun.star.beans.UnknownPropertyException" )
188 {
189 bSetUnknown = true;
190 } else if ( ex->getName() == "com.sun.star.beans.PropertyVetoException" )
191 {
192 attrAttribs
193 |= css::beans::PropertyAttribute::CONSTRAINED;
194 }
195 }
196 if (bGetUnknown && bSetUnknown) {
197 attrAttribs |= css::beans::PropertyAttribute::OPTIONAL;
198 }
199 css::uno::Reference< css::reflection::XTypeDescription > t(
200 attr->getType());
201 for (;;)
202 {
203 t = resolveTypedefs(t);
204 sal_Int16 n;
205 if (t->getName().startsWith(
206 "com.sun.star.beans.Ambiguous<"))
207 {
208 n = css::beans::PropertyAttribute::MAYBEAMBIGUOUS;
209 } else if (t->getName().startsWith(
210 "com.sun.star.beans.Defaulted<"))
211 {
212 n = css::beans::PropertyAttribute::MAYBEDEFAULT;
213 } else if (t->getName().startsWith(
214 "com.sun.star.beans.Optional<"))
215 {
216 n = css::beans::PropertyAttribute::MAYBEVOID;
217 } else {
218 break;
219 }
220 if ((attrAttribs & n) != 0) {
221 break;
222 }
223 attrAttribs |= n;
224 const css::uno::Sequence<
225 css::uno::Reference< css::reflection::XTypeDescription > >
226 args(
227 css::uno::Reference<
228 css::reflection::XStructTypeDescription >(
229 t, css::uno::UNO_QUERY_THROW)->
230 getTypeArguments());
231 if (args.getLength() != 1) {
232 throw css::uno::RuntimeException(
233 "inconsistent UNO type registry");
234 }
235 t = args[0];
236 }
237 std::vector< OUString >::size_type handles
238 = handleNames->size();
239 if (handles > SAL_MAX_INT32) {
240 throw css::uno::RuntimeException(
241 "interface type has too many attributes");
242 }
243 OUString name(m->getMemberName());
244 if (!properties.emplace(
245 name,
246 PropertyData(
247 css::beans::Property(
248 name, static_cast< sal_Int32 >(handles),
249 css::uno::Type(
250 t->getTypeClass(), t->getName()),
251 attrAttribs),
252 (std::find(absentBegin, absentEnd, name)
253 == absentEnd))).
254 second)
255 {
256 throw css::uno::RuntimeException(
257 "inconsistent UNO type registry");
258 }
259 handleNames->push_back(name);
260 }
261 }
262}
263
264css::uno::Reference< css::reflection::XTypeDescription > Data::resolveTypedefs(
265 css::uno::Reference< css::reflection::XTypeDescription > const & type)
266{
267 css::uno::Reference< css::reflection::XTypeDescription > t(type);
268 while (t->getTypeClass() == css::uno::TypeClass_TYPEDEF) {
269 t = css::uno::Reference< css::reflection::XIndirectTypeDescription >(
270 t, css::uno::UNO_QUERY_THROW)->getReferencedType();
271 }
272 return t;
273}
274
275class Info: public cppu::WeakImplHelper< css::beans::XPropertySetInfo > {
276public:
277 explicit Info(Data * data): m_data(data) {}
278
279 virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties() override;
280
281 virtual css::beans::Property SAL_CALL getPropertyByName(
282 OUString const & name) override;
283
284 virtual sal_Bool SAL_CALL hasPropertyByName(OUString const & name) override;
285
286private:
288};
289
290css::uno::Sequence< css::beans::Property > Info::getProperties()
291{
292 assert(m_data->properties.size() <= SAL_MAX_INT32);
293 css::uno::Sequence< css::beans::Property > s(
294 static_cast< sal_Int32 >(m_data->properties.size()));
295 auto r = asNonConstRange(s);
296 sal_Int32 n = 0;
297 for (const auto& rEntry : m_data->properties)
298 {
299 if (rEntry.second.present) {
300 r[n++] = rEntry.second.property;
301 }
302 }
303 s.realloc(n);
304 return s;
305}
306
307css::beans::Property Info::getPropertyByName(OUString const & name)
308{
309 return m_data->get(static_cast< cppu::OWeakObject * >(this), name)->
310 second.property;
311}
312
313sal_Bool Info::hasPropertyByName(OUString const & name)
314{
315 Data::PropertyMap::iterator i(m_data->properties.find(name));
316 return i != m_data->properties.end() && i->second.present;
317}
318
319typedef
320std::multiset< css::uno::Reference< css::beans::XPropertyChangeListener > >
321BoundListenerBag;
322
323}
324
326public:
327 BoundListenerBag specificListeners;
328 BoundListenerBag unspecificListeners;
329 css::beans::PropertyChangeEvent event;
330};
331
332PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl) {}
333
335 delete m_impl;
336}
337
339 for (const auto& rxListener : m_impl->specificListeners)
340 {
341 try {
342 rxListener->propertyChange(m_impl->event);
343 } catch (css::lang::DisposedException &) {}
344 }
345 for (const auto& rxListener : m_impl->unspecificListeners)
346 {
347 try {
348 rxListener->propertyChange(m_impl->event);
349 } catch (css::lang::DisposedException &) {}
350 }
351}
352
354public:
355 Impl(
356 css::uno::Reference< css::uno::XComponentContext > const & context,
357 Implements theImplements,
358 css::uno::Sequence< OUString > const & absentOptional,
359 css::uno::Type const & type);
360
361 OUString const & translateHandle(
362 css::uno::Reference< css::uno::XInterface > const & object,
363 sal_Int32 handle) const;
364
365 void setProperty(
366 css::uno::Reference< css::uno::XInterface > const & object,
367 OUString const & name, css::uno::Any const & value,
368 bool isAmbiguous, bool isDefaulted, sal_Int16 illegalArgumentPosition)
369 const;
370
371 css::uno::Any getProperty(
372 css::uno::Reference< css::uno::XInterface > const & object,
373 OUString const & name, css::beans::PropertyState * state) const;
374
376 css::uno::Sequence< OUString > handleMap;
377
378 typedef std::map< OUString, BoundListenerBag > BoundListenerMap;
379
380 typedef
381 std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > >
383
384 typedef std::map< OUString, VetoListenerBag > VetoListenerMap;
385
386 mutable std::mutex mutex;
390
391private:
392 css::uno::Reference< css::reflection::XIdlClass > getReflection(
393 OUString const & typeName) const;
394
395 static css::uno::Any wrapValue(
396 css::uno::Reference< css::uno::XInterface > const & object,
397 css::uno::Any const & value,
398 css::uno::Reference< css::reflection::XIdlClass > const & type,
399 bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted,
400 bool isDefaulted, bool wrapOptional);
401
402 css::uno::Reference< css::uno::XComponentContext > const & m_context;
403 css::uno::Type m_type;
404 css::uno::Reference< css::reflection::XIdlClass > m_idlClass;
405};
406
408 css::uno::Reference< css::uno::XComponentContext > const & context,
409 Implements theImplements,
410 css::uno::Sequence< OUString > const & absentOptional,
411 css::uno::Type const & type):
412 implements(theImplements), disposed(false), m_context(context),
413 m_type(type)
414{
415 assert(context.is());
416 assert(
418 & ~(IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET
419 | IMPLEMENTS_PROPERTY_ACCESS))
420 == 0);
421 m_idlClass = getReflection(m_type.getTypeName());
422 css::uno::Reference< css::reflection::XTypeDescription > ifc;
423 try {
424 ifc.set(
425 css::uno::Reference< css::container::XHierarchicalNameAccess >(
426 m_context->getValueByName(
427 "/singletons/com.sun.star.reflection."
428 "theTypeDescriptionManager"),
429 css::uno::UNO_QUERY_THROW)->getByHierarchicalName(
430 m_type.getTypeName()),
431 css::uno::UNO_QUERY_THROW);
432 } catch (css::container::NoSuchElementException & e) {
433 css::uno::Any anyEx = cppu::getCaughtException();
434 throw css::lang::WrappedTargetRuntimeException(
435 "unexpected com.sun.star.container.NoSuchElementException: "
436 + e.Message,
437 nullptr, anyEx );
438 }
439 std::vector< OUString > handleNames;
440 initProperties(ifc, absentOptional, &handleNames);
441 std::vector< OUString >::size_type size = handleNames.size();
442 assert(size <= SAL_MAX_INT32);
443 handleMap.realloc(static_cast< sal_Int32 >(size));
444 std::copy(handleNames.begin(), handleNames.end(), handleMap.getArray());
445}
446
448 css::uno::Reference< css::uno::XInterface > const & object,
449 sal_Int32 handle) const
450{
451 if (handle < 0 || handle >= handleMap.getLength()) {
452 throw css::beans::UnknownPropertyException(
453 "bad handle " + OUString::number(handle), object);
454 }
455 return handleMap[handle];
456}
457
459 css::uno::Reference< css::uno::XInterface > const & object,
460 OUString const & name, css::uno::Any const & value, bool isAmbiguous,
461 bool isDefaulted, sal_Int16 illegalArgumentPosition) const
462{
463 PropertyMap::const_iterator i(properties.find(name));
464 if (i == properties.end()) {
465 throw css::beans::UnknownPropertyException(name, object);
466 }
467 if ((isAmbiguous
468 && ((i->second.property.Attributes
469 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
470 == 0))
471 || (isDefaulted
472 && ((i->second.property.Attributes
473 & css::beans::PropertyAttribute::MAYBEDEFAULT)
474 == 0)))
475 {
476 throw css::lang::IllegalArgumentException(
477 ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
478 + name),
479 object, illegalArgumentPosition);
480 }
481 css::uno::Reference< css::reflection::XIdlField2 > f(
482 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
483 css::uno::Any o(object->queryInterface(m_type));
484 css::uno::Any v(
485 wrapValue(
486 object, value,
487 (css::uno::Reference< css::reflection::XIdlField2 >(
488 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW)->
489 getType()),
490 ((i->second.property.Attributes
491 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
492 != 0),
493 isAmbiguous,
494 ((i->second.property.Attributes
495 & css::beans::PropertyAttribute::MAYBEDEFAULT)
496 != 0),
497 isDefaulted,
498 ((i->second.property.Attributes
499 & css::beans::PropertyAttribute::MAYBEVOID)
500 != 0)));
501 try {
502 f->set(o, v);
503 } catch (css::lang::IllegalArgumentException & e) {
504 if (e.ArgumentPosition == 1) {
505 throw css::lang::IllegalArgumentException(
506 e.Message, object, illegalArgumentPosition);
507 } else {
508 css::uno::Any anyEx = cppu::getCaughtException();
509 throw css::lang::WrappedTargetRuntimeException(
510 "unexpected com.sun.star.lang.IllegalArgumentException: "
511 + e.Message,
512 object, anyEx );
513 }
514 } catch (css::lang::IllegalAccessException &) {
515 //TODO Clarify whether PropertyVetoException is the correct exception
516 // to throw when trying to set a read-only property:
517 throw css::beans::PropertyVetoException(
518 "cannot set read-only property " + name, object);
519 } catch (css::lang::WrappedTargetRuntimeException & e) {
520 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
521 // guaranteed to originate directly within XIdlField2.get (and thus have
522 // the expected semantics); it might also be passed through from lower
523 // layers.
524 if (e.TargetException.isExtractableTo(
526 && ((i->second.property.Attributes
527 & css::beans::PropertyAttribute::OPTIONAL)
528 != 0))
529 {
530 throw css::beans::UnknownPropertyException(name, object);
531 } else if (e.TargetException.isExtractableTo(
533 && ((i->second.property.Attributes
534 & css::beans::PropertyAttribute::CONSTRAINED)
535 != 0))
536 {
537 css::beans::PropertyVetoException exc;
538 e.TargetException >>= exc;
539 if (exc.Message.isEmpty() )
540 throw css::beans::PropertyVetoException("Invalid " + name, object);
541 else
542 throw exc;
543 } else {
544 throw css::lang::WrappedTargetException(
545 e.Message, object, e.TargetException);
546 }
547 }
548}
549
551 css::uno::Reference< css::uno::XInterface > const & object,
552 OUString const & name, css::beans::PropertyState * state) const
553{
554 PropertyMap::const_iterator i(properties.find(name));
555 if (i == properties.end()) {
556 throw css::beans::UnknownPropertyException(name, object);
557 }
558 css::uno::Reference< css::reflection::XIdlField2 > field(
559 m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
560 css::uno::Any value;
561 try {
562 value = field->get(object->queryInterface(m_type));
563 } catch (css::lang::IllegalArgumentException & e) {
564 css::uno::Any anyEx = cppu::getCaughtException();
565 throw css::lang::WrappedTargetRuntimeException(
566 "unexpected com.sun.star.lang.IllegalArgumentException: "
567 + e.Message,
568 object, anyEx );
569 } catch (css::lang::WrappedTargetRuntimeException & e) {
570 //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
571 // guaranteed to originate directly within XIdlField2.get (and thus have
572 // the expected semantics); it might also be passed through from lower
573 // layers.
574 if (e.TargetException.isExtractableTo(
576 && ((i->second.property.Attributes
577 & css::beans::PropertyAttribute::OPTIONAL)
578 != 0))
579 {
580 throw css::beans::UnknownPropertyException(name, object);
581 } else {
582 throw css::lang::WrappedTargetException(
583 e.Message, object, e.TargetException);
584 }
585 }
586 bool undoAmbiguous
587 = ((i->second.property.Attributes
588 & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
589 != 0);
590 bool undoDefaulted
591 = ((i->second.property.Attributes
592 & css::beans::PropertyAttribute::MAYBEDEFAULT)
593 != 0);
594 bool undoOptional
595 = ((i->second.property.Attributes
596 & css::beans::PropertyAttribute::MAYBEVOID)
597 != 0);
598 bool isAmbiguous = false;
599 bool isDefaulted = false;
600 while (undoAmbiguous || undoDefaulted || undoOptional) {
601 if (undoAmbiguous
602 && value.getValueTypeName().startsWith(
603 "com.sun.star.beans.Ambiguous<"))
604 {
605 css::uno::Reference< css::reflection::XIdlClass > ambiguous(
606 getReflection(value.getValueTypeName()));
607 try {
608 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
609 ambiguous->getField("IsAmbiguous"),
610 css::uno::UNO_QUERY_THROW)->get(value)
611 >>= isAmbiguous))
612 {
613 throw css::uno::RuntimeException(
614 ("unexpected type of com.sun.star.beans.Ambiguous"
615 " IsAmbiguous member"),
616 object);
617 }
618 value = css::uno::Reference< css::reflection::XIdlField2 >(
619 ambiguous->getField("Value"), css::uno::UNO_QUERY_THROW)->
620 get(value);
621 } catch (css::lang::IllegalArgumentException & e) {
622 css::uno::Any anyEx = cppu::getCaughtException();
623 throw css::lang::WrappedTargetRuntimeException(
624 "unexpected com.sun.star.lang.IllegalArgumentException: "
625 + e.Message,
626 object, anyEx );
627 }
628 undoAmbiguous = false;
629 } else if (undoDefaulted
630 && value.getValueTypeName().startsWith(
631 "com.sun.star.beans.Defaulted<"))
632 {
633 css::uno::Reference< css::reflection::XIdlClass > defaulted(
634 getReflection(value.getValueTypeName()));
635 try {
636
637 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
638 defaulted->getField("IsDefaulted"),
639 css::uno::UNO_QUERY_THROW)->get(value)
640 >>= isDefaulted))
641 {
642 throw css::uno::RuntimeException(
643 ("unexpected type of com.sun.star.beans.Defaulted"
644 " IsDefaulted member"),
645 object);
646 }
647 value = css::uno::Reference< css::reflection::XIdlField2 >(
648 defaulted->getField("Value"), css::uno::UNO_QUERY_THROW)->
649 get(value);
650 } catch (css::lang::IllegalArgumentException & e) {
651 css::uno::Any anyEx = cppu::getCaughtException();
652 throw css::lang::WrappedTargetRuntimeException(
653 "unexpected com.sun.star.lang.IllegalArgumentException: "
654 + e.Message,
655 object, anyEx );
656 }
657 undoDefaulted = false;
658 } else if (undoOptional
659 && value.getValueTypeName().startsWith(
660 "com.sun.star.beans.Optional<"))
661 {
662 css::uno::Reference< css::reflection::XIdlClass > optional(
663 getReflection(value.getValueTypeName()));
664 try {
665 bool present = false;
666 if (!(css::uno::Reference< css::reflection::XIdlField2 >(
667 optional->getField("IsPresent"),
668 css::uno::UNO_QUERY_THROW)->get(value)
669 >>= present))
670 {
671 throw css::uno::RuntimeException(
672 ("unexpected type of com.sun.star.beans.Optional"
673 " IsPresent member"),
674 object);
675 }
676 if (!present) {
677 value.clear();
678 break;
679 }
680 value = css::uno::Reference< css::reflection::XIdlField2 >(
681 optional->getField("Value"), css::uno::UNO_QUERY_THROW)->
682 get(value);
683 } catch (css::lang::IllegalArgumentException & e) {
684 css::uno::Any anyEx = cppu::getCaughtException();
685 throw css::lang::WrappedTargetRuntimeException(
686 "unexpected com.sun.star.lang.IllegalArgumentException: "
687 + e.Message,
688 object, anyEx );
689 }
690 undoOptional = false;
691 } else {
692 throw css::uno::RuntimeException(
693 "unexpected type of attribute " + name, object);
694 }
695 }
696 if (state != nullptr) {
697 //XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE
698 // over DEFAULT_VALUE:
699 *state = isAmbiguous
700 ? css::beans::PropertyState_AMBIGUOUS_VALUE
701 : isDefaulted
702 ? css::beans::PropertyState_DEFAULT_VALUE
703 : css::beans::PropertyState_DIRECT_VALUE;
704 }
705 return value;
706}
707
708css::uno::Reference< css::reflection::XIdlClass >
709PropertySetMixinImpl::Impl::getReflection(OUString const & typeName) const
710{
711 return css::uno::Reference< css::reflection::XIdlClass >(
712 css::reflection::theCoreReflection::get(m_context)->forName(typeName),
713 css::uno::UNO_SET_THROW);
714}
715
717 css::uno::Reference< css::uno::XInterface > const & object,
718 css::uno::Any const & value,
719 css::uno::Reference< css::reflection::XIdlClass > const & type,
720 bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted, bool isDefaulted,
721 bool wrapOptional)
722{
723 assert(wrapAmbiguous || !isAmbiguous);
724 assert(wrapDefaulted || !isDefaulted);
725 if (wrapAmbiguous
726 && type->getName().startsWith("com.sun.star.beans.Ambiguous<"))
727 {
728 css::uno::Any strct;
729 type->createObject(strct);
730 try {
731 css::uno::Reference< css::reflection::XIdlField2 > field(
732 type->getField("Value"), css::uno::UNO_QUERY_THROW);
733 field->set(
734 strct,
735 wrapValue(
736 object, value, field->getType(), false, false,
737 wrapDefaulted, isDefaulted, wrapOptional));
738 css::uno::Reference< css::reflection::XIdlField2 >(
739 type->getField("IsAmbiguous"), css::uno::UNO_QUERY_THROW)->set(
740 strct, css::uno::Any(isAmbiguous));
741 } catch (css::lang::IllegalArgumentException & e) {
742 css::uno::Any anyEx = cppu::getCaughtException();
743 throw css::lang::WrappedTargetRuntimeException(
744 "unexpected com.sun.star.lang.IllegalArgumentException: "
745 + e.Message,
746 object, anyEx );
747 } catch (css::lang::IllegalAccessException & e) {
748 css::uno::Any anyEx = cppu::getCaughtException();
749 throw css::lang::WrappedTargetRuntimeException(
750 "unexpected com.sun.star.lang.IllegalAccessException: "
751 + e.Message,
752 object, anyEx );
753 }
754 return strct;
755 }
756 if (wrapDefaulted
757 && type->getName().startsWith("com.sun.star.beans.Defaulted<"))
758 {
759 css::uno::Any strct;
760 type->createObject(strct);
761 try {
762 css::uno::Reference< css::reflection::XIdlField2 > field(
763 type->getField("Value"), css::uno::UNO_QUERY_THROW);
764 field->set(
765 strct,
766 wrapValue(
767 object, value, field->getType(), wrapAmbiguous, isAmbiguous,
768 false, false, wrapOptional));
769 css::uno::Reference< css::reflection::XIdlField2 >(
770 type->getField("IsDefaulted"), css::uno::UNO_QUERY_THROW)->set(
771 strct, css::uno::Any(isDefaulted));
772 } catch (css::lang::IllegalArgumentException & e) {
773 css::uno::Any anyEx = cppu::getCaughtException();
774 throw css::lang::WrappedTargetRuntimeException(
775 "unexpected com.sun.star.lang.IllegalArgumentException: "
776 + e.Message,
777 object, anyEx );
778 } catch (css::lang::IllegalAccessException & e) {
779 css::uno::Any anyEx = cppu::getCaughtException();
780 throw css::lang::WrappedTargetRuntimeException(
781 "unexpected com.sun.star.lang.IllegalAccessException: "
782 + e.Message,
783 object, anyEx );
784 }
785 return strct;
786 }
787 if (wrapOptional
788 && type->getName().startsWith("com.sun.star.beans.Optional<"))
789 {
790 css::uno::Any strct;
791 type->createObject(strct);
792 bool present = value.hasValue();
793 try {
794 css::uno::Reference< css::reflection::XIdlField2 >(
795 type->getField("IsPresent"), css::uno::UNO_QUERY_THROW)->set(
796 strct, css::uno::Any(present));
797 if (present) {
798 css::uno::Reference< css::reflection::XIdlField2 > field(
799 type->getField("Value"), css::uno::UNO_QUERY_THROW);
800 field->set(
801 strct,
802 wrapValue(
803 object, value, field->getType(), wrapAmbiguous,
804 isAmbiguous, wrapDefaulted, isDefaulted, false));
805 }
806 } catch (css::lang::IllegalArgumentException & e) {
807 css::uno::Any anyEx = cppu::getCaughtException();
808 throw css::lang::WrappedTargetRuntimeException(
809 "unexpected com.sun.star.lang.IllegalArgumentException: "
810 + e.Message,
811 object, anyEx );
812 } catch (css::lang::IllegalAccessException & e) {
813 css::uno::Any anyEx = cppu::getCaughtException();
814 throw css::lang::WrappedTargetRuntimeException(
815 "unexpected com.sun.star.lang.IllegalAccessException: "
816 + e.Message,
817 object, anyEx );
818 }
819 return strct;
820 }
821 if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
822 throw css::uno::RuntimeException(
823 "unexpected type of attribute", object);
824 }
825 return value;
826}
827
828PropertySetMixinImpl::PropertySetMixinImpl(
829 css::uno::Reference< css::uno::XComponentContext > const & context,
830 Implements implements,
831 css::uno::Sequence< OUString > const & absentOptional,
832 css::uno::Type const & type)
833{
834 m_impl = new Impl(context, implements, absentOptional, type);
835 m_impl->acquire();
836}
837
838PropertySetMixinImpl::~PropertySetMixinImpl() {
839 m_impl->release();
840}
841
842void PropertySetMixinImpl::checkUnknown(OUString const & propertyName) {
843 if (!propertyName.isEmpty()) {
844 m_impl->get(
845 static_cast< css::beans::XPropertySet * >(this), propertyName);
846 }
847}
848
849void PropertySetMixinImpl::prepareSet(
850 OUString const & propertyName, css::uno::Any const & oldValue,
851 css::uno::Any const & newValue, BoundListeners * boundListeners)
852{
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;
857 {
858 std::scoped_lock g(m_impl->mutex);
859 if (m_impl->disposed) {
860 throw css::lang::DisposedException(
861 "disposed", static_cast< css::beans::XPropertySet * >(this));
862 }
863 if ((it->second.property.Attributes
864 & css::beans::PropertyAttribute::CONSTRAINED)
865 != 0)
866 {
867 Impl::VetoListenerMap::const_iterator i(
868 m_impl->vetoListeners.find(propertyName));
869 if (i != m_impl->vetoListeners.end()) {
870 specificVeto = i->second;
871 }
872 i = m_impl->vetoListeners.find("");
873 if (i != m_impl->vetoListeners.end()) {
874 unspecificVeto = i->second;
875 }
876 }
877 if ((it->second.property.Attributes
878 & css::beans::PropertyAttribute::BOUND)
879 != 0)
880 {
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;
886 }
887 i = m_impl->boundListeners.find("");
888 if (i != m_impl->boundListeners.end()) {
889 boundListeners->m_impl->unspecificListeners = i->second;
890 }
891 }
892 }
893 if ((it->second.property.Attributes
894 & css::beans::PropertyAttribute::CONSTRAINED)
895 != 0)
896 {
897 css::beans::PropertyChangeEvent event(
898 static_cast< css::beans::XPropertySet * >(this), propertyName,
899 false, it->second.property.Handle, oldValue, newValue);
900 for (auto& rxVetoListener : specificVeto)
901 {
902 try {
903 rxVetoListener->vetoableChange(event);
904 } catch (css::lang::DisposedException &) {}
905 }
906 for (auto& rxVetoListener : unspecificVeto)
907 {
908 try {
909 rxVetoListener->vetoableChange(event);
910 } catch (css::lang::DisposedException &) {}
911 }
912 }
913 if ((it->second.property.Attributes & css::beans::PropertyAttribute::BOUND)
914 != 0)
915 {
916 assert(boundListeners != nullptr);
917 boundListeners->m_impl->event = css::beans::PropertyChangeEvent(
918 static_cast< css::beans::XPropertySet * >(this), propertyName,
919 false, it->second.property.Handle, oldValue, newValue);
920 }
921}
922
923void PropertySetMixinImpl::dispose() {
924 Impl::BoundListenerMap boundListeners;
925 Impl::VetoListenerMap vetoListeners;
926 {
927 std::scoped_lock g(m_impl->mutex);
928 boundListeners.swap(m_impl->boundListeners);
929 vetoListeners.swap(m_impl->vetoListeners);
930 m_impl->disposed = true;
931 }
932 css::lang::EventObject event(
933 static_cast< css::beans::XPropertySet * >(this));
934 for (const auto& rEntry : boundListeners)
935 {
936 for (auto& rxBoundListener : rEntry.second)
937 {
938 rxBoundListener->disposing(event);
939 }
940 }
941 for (const auto& rEntry : vetoListeners)
942 {
943 for (auto& rxVetoListener : rEntry.second)
944 {
945 rxVetoListener->disposing(event);
946 }
947 }
948}
949
950css::uno::Any PropertySetMixinImpl::queryInterface(css::uno::Type const & type)
951{
952 if ((m_impl->implements & IMPLEMENTS_PROPERTY_SET) != 0
953 && type == css::beans::XPropertySet::static_type())
954 {
955 css::uno::Reference< css::uno::XInterface > ifc(
956 static_cast< css::beans::XPropertySet * >(this));
957 return css::uno::Any(&ifc, type);
958 }
959 if ((m_impl->implements & IMPLEMENTS_FAST_PROPERTY_SET) != 0
960 && type == css::beans::XFastPropertySet::static_type())
961 {
962 css::uno::Reference< css::uno::XInterface > ifc(
963 static_cast< css::beans::XFastPropertySet * >(this));
964 return css::uno::Any(&ifc, type);
965 }
966 if ((m_impl->implements & IMPLEMENTS_PROPERTY_ACCESS) != 0
967 && type == css::beans::XPropertyAccess::static_type())
968 {
969 css::uno::Reference< css::uno::XInterface > ifc(
970 static_cast< css::beans::XPropertyAccess * >(this));
971 return css::uno::Any(&ifc, type);
972 }
973 return css::uno::Any();
974}
975
976css::uno::Reference< css::beans::XPropertySetInfo >
977PropertySetMixinImpl::getPropertySetInfo()
978{
979 return new Info(m_impl);
980}
981
982void PropertySetMixinImpl::setPropertyValue(
983 OUString const & propertyName, css::uno::Any const & value)
984{
985 m_impl->setProperty(
986 static_cast< css::beans::XPropertySet * >(this), propertyName, value,
987 false, false, 1);
988}
989
990css::uno::Any PropertySetMixinImpl::getPropertyValue(
991 OUString const & propertyName)
992{
993 return m_impl->getProperty(
994 static_cast< css::beans::XPropertySet * >(this), propertyName, nullptr);
995}
996
997void PropertySetMixinImpl::addPropertyChangeListener(
998 OUString const & propertyName,
999 css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
1000{
1001 css::uno::Reference< css::beans::XPropertyChangeListener >(
1002 listener, css::uno::UNO_SET_THROW); // reject NULL listener
1003 checkUnknown(propertyName);
1004 bool disposed;
1005 {
1006 std::scoped_lock g(m_impl->mutex);
1007 disposed = m_impl->disposed;
1008 if (!disposed) {
1009 m_impl->boundListeners[propertyName].insert(listener);
1010 }
1011 }
1012 if (disposed) {
1013 listener->disposing(
1014 css::lang::EventObject(
1015 static_cast< css::beans::XPropertySet * >(this)));
1016 }
1017}
1018
1019void PropertySetMixinImpl::removePropertyChangeListener(
1020 OUString const & propertyName,
1021 css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
1022{
1023 assert(listener.is());
1024 checkUnknown(propertyName);
1025 std::scoped_lock g(m_impl->mutex);
1026 Impl::BoundListenerMap::iterator i(
1027 m_impl->boundListeners.find(propertyName));
1028 if (i != m_impl->boundListeners.end()) {
1029 BoundListenerBag::iterator j(i->second.find(listener));
1030 if (j != i->second.end()) {
1031 i->second.erase(j);
1032 }
1033 }
1034}
1035
1036void PropertySetMixinImpl::addVetoableChangeListener(
1037 OUString const & propertyName,
1038 css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
1039{
1040 css::uno::Reference< css::beans::XVetoableChangeListener >(
1041 listener, css::uno::UNO_SET_THROW); // reject NULL listener
1042 checkUnknown(propertyName);
1043 bool disposed;
1044 {
1045 std::scoped_lock g(m_impl->mutex);
1046 disposed = m_impl->disposed;
1047 if (!disposed) {
1048 m_impl->vetoListeners[propertyName].insert(listener);
1049 }
1050 }
1051 if (disposed) {
1052 listener->disposing(
1053 css::lang::EventObject(
1054 static_cast< css::beans::XPropertySet * >(this)));
1055 }
1056}
1057
1058void PropertySetMixinImpl::removeVetoableChangeListener(
1059 OUString const & propertyName,
1060 css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
1061{
1062 assert(listener.is());
1063 checkUnknown(propertyName);
1064 std::scoped_lock g(m_impl->mutex);
1065 Impl::VetoListenerMap::iterator i(m_impl->vetoListeners.find(propertyName));
1066 if (i != m_impl->vetoListeners.end()) {
1067 Impl::VetoListenerBag::iterator j(i->second.find(listener));
1068 if (j != i->second.end()) {
1069 i->second.erase(j);
1070 }
1071 }
1072}
1073
1074void PropertySetMixinImpl::setFastPropertyValue(
1075 sal_Int32 handle, css::uno::Any const & value)
1076{
1077 m_impl->setProperty(
1078 static_cast< css::beans::XPropertySet * >(this),
1079 m_impl->translateHandle(
1080 static_cast< css::beans::XPropertySet * >(this), handle),
1081 value, false, false, 1);
1082}
1083
1084css::uno::Any PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle)
1085{
1086 return m_impl->getProperty(
1087 static_cast< css::beans::XPropertySet * >(this),
1088 m_impl->translateHandle(
1089 static_cast< css::beans::XPropertySet * >(this), handle),
1090 nullptr);
1091}
1092
1093css::uno::Sequence< css::beans::PropertyValue >
1094PropertySetMixinImpl::getPropertyValues()
1095{
1096 css::uno::Sequence< css::beans::PropertyValue > s(
1097 m_impl->handleMap.getLength());
1098 auto r = asNonConstRange(s);
1099 sal_Int32 n = 0;
1100 for (sal_Int32 i = 0; i < m_impl->handleMap.getLength(); ++i) {
1101 try {
1102 r[n].Value = m_impl->getProperty(
1103 static_cast< css::beans::XPropertySet * >(this),
1104 m_impl->handleMap[i], &r[n].State);
1105 } catch (css::beans::UnknownPropertyException &) {
1106 continue;
1107 } catch (css::lang::WrappedTargetException & e) {
1108 throw css::lang::WrappedTargetRuntimeException(
1109 e.Message, static_cast< css::beans::XPropertySet * >(this),
1110 e.TargetException);
1111 }
1112 r[n].Name = m_impl->handleMap[i];
1113 r[n].Handle = i;
1114 ++n;
1115 }
1116 s.realloc(n);
1117 return s;
1118}
1119
1120void PropertySetMixinImpl::setPropertyValues(
1121 css::uno::Sequence< css::beans::PropertyValue > const & props)
1122{
1123 for (const auto & p : props) {
1124 if (p.Handle != -1
1125 && (p.Name
1126 != m_impl->translateHandle(
1127 static_cast< css::beans::XPropertySet * >(this),
1128 p.Handle)))
1129 {
1130 throw css::beans::UnknownPropertyException(
1131 ("name " + p.Name + " does not match handle "
1132 + OUString::number(p.Handle)),
1133 static_cast< css::beans::XPropertySet * >(this));
1134 }
1135 m_impl->setProperty(
1136 static_cast< css::beans::XPropertySet * >(this), p.Name,
1137 p.Value,
1138 p.State == css::beans::PropertyState_AMBIGUOUS_VALUE,
1139 p.State == css::beans::PropertyState_DEFAULT_VALUE, 0);
1140 }
1141}
1142
1143/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
std::map< OUString, BoundListenerBag > BoundListenerMap
OUString const & translateHandle(css::uno::Reference< css::uno::XInterface > const &object, sal_Int32 handle) const
css::uno::Reference< css::reflection::XIdlClass > m_idlClass
static css::uno::Any wrapValue(css::uno::Reference< css::uno::XInterface > const &object, css::uno::Any const &value, css::uno::Reference< css::reflection::XIdlClass > const &type, bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted, bool isDefaulted, bool wrapOptional)
css::uno::Reference< css::reflection::XIdlClass > getReflection(OUString const &typeName) const
std::map< OUString, VetoListenerBag > VetoListenerMap
std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > > VetoListenerBag
Impl(css::uno::Reference< css::uno::XComponentContext > const &context, Implements theImplements, css::uno::Sequence< OUString > const &absentOptional, css::uno::Type const &type)
css::uno::Sequence< OUString > handleMap
void setProperty(css::uno::Reference< css::uno::XInterface > const &object, OUString const &name, css::uno::Any const &value, bool isAmbiguous, bool isDefaulted, sal_Int16 illegalArgumentPosition) const
PropertySetMixinImpl::Implements implements
css::uno::Reference< css::uno::XComponentContext > const & m_context
css::uno::Any getProperty(css::uno::Reference< css::uno::XInterface > const &object, OUString const &name, css::beans::PropertyState *state) const
Base class to implement a UNO object supporting weak references, i.e.
Definition: weak.hxx:48
A class used by subclasses of cppu::PropertySetMixin when implementing UNO interface type attribute s...
void notify() const
Notifies any css::beans::XPropertyChangeListeners.
A helper base class for cppu::PropertySetMixin.
Implements
Flags used by subclasses of cppu::PropertySetMixin to specify what UNO interface types shall be suppo...
const Type m_type
float v
const char * name
void * p
sal_Int64 n
size
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
Compares demanded type to given template argument types.
Any SAL_CALL getCaughtException()
Use this function to get the dynamic type of a caught C++-UNO exception; completes the above function...
Info
int i
m
args
dictionary props
std::map< sal_Int32, STLPropertyMapEntry > PropertyMap
SVX_DLLPUBLIC OUString getProperty(css::uno::Reference< css::beans::XPropertyContainer > const &rxPropertyContainer, OUString const &rName)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
sal_Int16 value
bool getType(BSTR name, Type &type)
OUString typeName
PyObject_HEAD PyUNO_callable_Internals * members
#define SAL_MAX_INT32
unsigned char sal_Bool
ResultType type