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