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