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 <set>
26 #include <vector>
27 
28 #include <com/sun/star/beans/Property.hpp>
29 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
30 #include <com/sun/star/beans/PropertyAttribute.hpp>
31 #include <com/sun/star/beans/PropertyValue.hpp>
32 #include <com/sun/star/beans/PropertyVetoException.hpp>
33 #include <com/sun/star/beans/UnknownPropertyException.hpp>
34 #include <com/sun/star/beans/XFastPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertyAccess.hpp>
36 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/beans/XPropertySetInfo.hpp>
39 #include <com/sun/star/beans/XVetoableChangeListener.hpp>
40 #include <com/sun/star/container/NoSuchElementException.hpp>
41 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
42 #include <com/sun/star/lang/DisposedException.hpp>
43 #include <com/sun/star/lang/EventObject.hpp>
44 #include <com/sun/star/lang/IllegalAccessException.hpp>
45 #include <com/sun/star/lang/IllegalArgumentException.hpp>
46 #include <com/sun/star/lang/WrappedTargetException.hpp>
47 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
48 #include <com/sun/star/reflection/XCompoundTypeDescription.hpp>
49 #include <com/sun/star/reflection/XIdlClass.hpp>
50 #include <com/sun/star/reflection/XIdlField2.hpp>
51 #include <com/sun/star/reflection/XIndirectTypeDescription.hpp>
52 #include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp>
53 #include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
54 #include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp>
55 #include <com/sun/star/reflection/XStructTypeDescription.hpp>
56 #include <com/sun/star/reflection/XTypeDescription.hpp>
57 #include <com/sun/star/reflection/theCoreReflection.hpp>
58 #include <com/sun/star/uno/Any.hxx>
59 #include <com/sun/star/uno/Reference.hxx>
60 #include <com/sun/star/uno/RuntimeException.hpp>
61 #include <com/sun/star/uno/Sequence.hxx>
62 #include <com/sun/star/uno/Type.hxx>
63 #include <com/sun/star/uno/TypeClass.hpp>
64 #include <com/sun/star/uno/XComponentContext.hpp>
65 #include <com/sun/star/uno/XInterface.hpp>
66 #include <cppuhelper/exc_hlp.hxx>
67 #include <cppuhelper/implbase.hxx>
69 #include <cppuhelper/weak.hxx>
70 #include <osl/mutex.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  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  sal_Int32 n = 0;
295  for (const auto& rEntry : m_data->properties)
296  {
297  if (rEntry.second.present) {
298  s[n++] = rEntry.second.property;
299  }
300  }
301  s.realloc(n);
302  return s;
303 }
304 
305 css::beans::Property Info::getPropertyByName(OUString const & name)
306 {
307  return m_data->get(static_cast< cppu::OWeakObject * >(this), name)->
308  second.property;
309 }
310 
311 sal_Bool Info::hasPropertyByName(OUString const & name)
312 {
313  Data::PropertyMap::iterator i(m_data->properties.find(name));
314  return i != m_data->properties.end() && i->second.present;
315 }
316 
317 typedef
318 std::multiset< css::uno::Reference< css::beans::XPropertyChangeListener > >
319 BoundListenerBag;
320 
321 }
322 
324 public:
325  BoundListenerBag specificListeners;
326  BoundListenerBag unspecificListeners;
327  css::beans::PropertyChangeEvent event;
328 };
329 
330 PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl) {}
331 
333  delete m_impl;
334 }
335 
337  for (const auto& rxListener : m_impl->specificListeners)
338  {
339  try {
340  rxListener->propertyChange(m_impl->event);
341  } catch (css::lang::DisposedException &) {}
342  }
343  for (const auto& rxListener : m_impl->unspecificListeners)
344  {
345  try {
346  rxListener->propertyChange(m_impl->event);
347  } catch (css::lang::DisposedException &) {}
348  }
349 }
350 
352 public:
353  Impl(
354  css::uno::Reference< css::uno::XComponentContext > const & context,
355  Implements theImplements,
356  css::uno::Sequence< OUString > const & absentOptional,
357  css::uno::Type const & type);
358 
359  OUString const & translateHandle(
360  css::uno::Reference< css::uno::XInterface > const & object,
361  sal_Int32 handle) const;
362 
363  void setProperty(
364  css::uno::Reference< css::uno::XInterface > const & object,
365  OUString const & name, css::uno::Any const & value,
366  bool isAmbiguous, bool isDefaulted, sal_Int16 illegalArgumentPosition)
367  const;
368 
369  css::uno::Any getProperty(
370  css::uno::Reference< css::uno::XInterface > const & object,
371  OUString const & name, css::beans::PropertyState * state) const;
372 
374  css::uno::Sequence< OUString > handleMap;
375 
376  typedef std::map< OUString, BoundListenerBag > BoundListenerMap;
377 
378  typedef
379  std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > >
381 
382  typedef std::map< OUString, VetoListenerBag > VetoListenerMap;
383 
384  mutable osl::Mutex mutex;
385  BoundListenerMap boundListeners;
386  VetoListenerMap vetoListeners;
387  bool disposed;
388 
389 private:
390  css::uno::Reference< css::reflection::XIdlClass > getReflection(
391  OUString const & typeName) const;
392 
393  static css::uno::Any wrapValue(
394  css::uno::Reference< css::uno::XInterface > const & object,
395  css::uno::Any const & value,
396  css::uno::Reference< css::reflection::XIdlClass > const & type,
397  bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted,
398  bool isDefaulted, bool wrapOptional);
399 
400  css::uno::Reference< css::uno::XComponentContext > const & m_context;
401  css::uno::Type m_type;
402  css::uno::Reference< css::reflection::XIdlClass > m_idlClass;
403 };
404 
406  css::uno::Reference< css::uno::XComponentContext > const & context,
407  Implements theImplements,
408  css::uno::Sequence< OUString > const & absentOptional,
409  css::uno::Type const & type):
410  implements(theImplements), disposed(false), m_context(context),
411  m_type(type)
412 {
413  assert(context.is());
414  assert(
415  (implements
416  & ~(IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET
417  | IMPLEMENTS_PROPERTY_ACCESS))
418  == 0);
419  m_idlClass = getReflection(m_type.getTypeName());
420  css::uno::Reference< css::reflection::XTypeDescription > ifc;
421  try {
422  ifc.set(
423  css::uno::Reference< css::container::XHierarchicalNameAccess >(
424  m_context->getValueByName(
425  "/singletons/com.sun.star.reflection."
426  "theTypeDescriptionManager"),
427  css::uno::UNO_QUERY_THROW)->getByHierarchicalName(
428  m_type.getTypeName()),
429  css::uno::UNO_QUERY_THROW);
430  } catch (css::container::NoSuchElementException & e) {
431  css::uno::Any anyEx = cppu::getCaughtException();
432  throw css::lang::WrappedTargetRuntimeException(
433  "unexpected com.sun.star.container.NoSuchElementException: "
434  + e.Message,
435  nullptr, anyEx );
436  }
437  std::vector< OUString > handleNames;
438  initProperties(ifc, absentOptional, &handleNames);
439  std::vector< OUString >::size_type size = handleNames.size();
440  assert(size <= SAL_MAX_INT32);
441  handleMap.realloc(static_cast< sal_Int32 >(size));
442  std::copy(handleNames.begin(), handleNames.end(), handleMap.getArray());
443 }
444 
446  css::uno::Reference< css::uno::XInterface > const & object,
447  sal_Int32 handle) const
448 {
449  if (handle < 0 || handle >= handleMap.getLength()) {
450  throw css::beans::UnknownPropertyException(
451  "bad handle " + OUString::number(handle), object);
452  }
453  return handleMap[handle];
454 }
455 
457  css::uno::Reference< css::uno::XInterface > const & object,
458  OUString const & name, css::uno::Any const & value, bool isAmbiguous,
459  bool isDefaulted, sal_Int16 illegalArgumentPosition) const
460 {
461  PropertyMap::const_iterator i(properties.find(name));
462  if (i == properties.end()) {
463  throw css::beans::UnknownPropertyException(name, object);
464  }
465  if ((isAmbiguous
466  && ((i->second.property.Attributes
467  & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
468  == 0))
469  || (isDefaulted
470  && ((i->second.property.Attributes
471  & css::beans::PropertyAttribute::MAYBEDEFAULT)
472  == 0)))
473  {
474  throw css::lang::IllegalArgumentException(
475  ("flagging as ambiguous/defaulted non-ambiguous/defaulted property "
476  + name),
477  object, illegalArgumentPosition);
478  }
479  css::uno::Reference< css::reflection::XIdlField2 > f(
480  m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
481  css::uno::Any o(object->queryInterface(m_type));
482  css::uno::Any v(
483  wrapValue(
484  object, value,
485  (css::uno::Reference< css::reflection::XIdlField2 >(
486  m_idlClass->getField(name), css::uno::UNO_QUERY_THROW)->
487  getType()),
488  ((i->second.property.Attributes
489  & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
490  != 0),
491  isAmbiguous,
492  ((i->second.property.Attributes
493  & css::beans::PropertyAttribute::MAYBEDEFAULT)
494  != 0),
495  isDefaulted,
496  ((i->second.property.Attributes
497  & css::beans::PropertyAttribute::MAYBEVOID)
498  != 0)));
499  try {
500  f->set(o, v);
501  } catch (css::lang::IllegalArgumentException & e) {
502  if (e.ArgumentPosition == 1) {
503  throw css::lang::IllegalArgumentException(
504  e.Message, object, illegalArgumentPosition);
505  } else {
506  css::uno::Any anyEx = cppu::getCaughtException();
507  throw css::lang::WrappedTargetRuntimeException(
508  "unexpected com.sun.star.lang.IllegalArgumentException: "
509  + e.Message,
510  object, anyEx );
511  }
512  } catch (css::lang::IllegalAccessException &) {
513  //TODO Clarify whether PropertyVetoException is the correct exception
514  // to throw when trying to set a read-only property:
515  throw css::beans::PropertyVetoException(
516  "cannot set read-only property " + name, object);
517  } catch (css::lang::WrappedTargetRuntimeException & e) {
518  //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
519  // guaranteed to originate directly within XIdlField2.get (and thus have
520  // the expected semantics); it might also be passed through from lower
521  // layers.
522  if (e.TargetException.isExtractableTo(
524  && ((i->second.property.Attributes
525  & css::beans::PropertyAttribute::OPTIONAL)
526  != 0))
527  {
528  throw css::beans::UnknownPropertyException(name, object);
529  } else if (e.TargetException.isExtractableTo(
531  && ((i->second.property.Attributes
532  & css::beans::PropertyAttribute::CONSTRAINED)
533  != 0))
534  {
535  css::beans::PropertyVetoException exc;
536  e.TargetException >>= exc;
537  if (exc.Message.isEmpty() )
538  throw css::beans::PropertyVetoException("Invalid " + name, object);
539  else
540  throw exc;
541  } else {
542  throw css::lang::WrappedTargetException(
543  e.Message, object, e.TargetException);
544  }
545  }
546 }
547 
549  css::uno::Reference< css::uno::XInterface > const & object,
550  OUString const & name, css::beans::PropertyState * state) const
551 {
552  PropertyMap::const_iterator i(properties.find(name));
553  if (i == properties.end()) {
554  throw css::beans::UnknownPropertyException(name, object);
555  }
556  css::uno::Reference< css::reflection::XIdlField2 > field(
557  m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
558  css::uno::Any value;
559  try {
560  value = field->get(object->queryInterface(m_type));
561  } catch (css::lang::IllegalArgumentException & e) {
562  css::uno::Any anyEx = cppu::getCaughtException();
563  throw css::lang::WrappedTargetRuntimeException(
564  "unexpected com.sun.star.lang.IllegalArgumentException: "
565  + e.Message,
566  object, anyEx );
567  } catch (css::lang::WrappedTargetRuntimeException & e) {
568  //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
569  // guaranteed to originate directly within XIdlField2.get (and thus have
570  // the expected semantics); it might also be passed through from lower
571  // layers.
572  if (e.TargetException.isExtractableTo(
574  && ((i->second.property.Attributes
575  & css::beans::PropertyAttribute::OPTIONAL)
576  != 0))
577  {
578  throw css::beans::UnknownPropertyException(name, object);
579  } else {
580  throw css::lang::WrappedTargetException(
581  e.Message, object, e.TargetException);
582  }
583  }
584  bool undoAmbiguous
585  = ((i->second.property.Attributes
586  & css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
587  != 0);
588  bool undoDefaulted
589  = ((i->second.property.Attributes
590  & css::beans::PropertyAttribute::MAYBEDEFAULT)
591  != 0);
592  bool undoOptional
593  = ((i->second.property.Attributes
594  & css::beans::PropertyAttribute::MAYBEVOID)
595  != 0);
596  bool isAmbiguous = false;
597  bool isDefaulted = false;
598  while (undoAmbiguous || undoDefaulted || undoOptional) {
599  if (undoAmbiguous
600  && value.getValueTypeName().startsWith(
601  "com.sun.star.beans.Ambiguous<"))
602  {
603  css::uno::Reference< css::reflection::XIdlClass > ambiguous(
604  getReflection(value.getValueTypeName()));
605  try {
606  if (!(css::uno::Reference< css::reflection::XIdlField2 >(
607  ambiguous->getField("IsAmbiguous"),
608  css::uno::UNO_QUERY_THROW)->get(value)
609  >>= isAmbiguous))
610  {
611  throw css::uno::RuntimeException(
612  ("unexpected type of com.sun.star.beans.Ambiguous"
613  " IsAmbiguous member"),
614  object);
615  }
616  value = css::uno::Reference< css::reflection::XIdlField2 >(
617  ambiguous->getField("Value"), css::uno::UNO_QUERY_THROW)->
618  get(value);
619  } catch (css::lang::IllegalArgumentException & e) {
620  css::uno::Any anyEx = cppu::getCaughtException();
621  throw css::lang::WrappedTargetRuntimeException(
622  "unexpected com.sun.star.lang.IllegalArgumentException: "
623  + e.Message,
624  object, anyEx );
625  }
626  undoAmbiguous = false;
627  } else if (undoDefaulted
628  && value.getValueTypeName().startsWith(
629  "com.sun.star.beans.Defaulted<"))
630  {
631  css::uno::Reference< css::reflection::XIdlClass > defaulted(
632  getReflection(value.getValueTypeName()));
633  try {
634 
635  if (!(css::uno::Reference< css::reflection::XIdlField2 >(
636  defaulted->getField("IsDefaulted"),
637  css::uno::UNO_QUERY_THROW)->get(value)
638  >>= isDefaulted))
639  {
640  throw css::uno::RuntimeException(
641  ("unexpected type of com.sun.star.beans.Defaulted"
642  " IsDefaulted member"),
643  object);
644  }
645  value = css::uno::Reference< css::reflection::XIdlField2 >(
646  defaulted->getField("Value"), css::uno::UNO_QUERY_THROW)->
647  get(value);
648  } catch (css::lang::IllegalArgumentException & e) {
649  css::uno::Any anyEx = cppu::getCaughtException();
650  throw css::lang::WrappedTargetRuntimeException(
651  "unexpected com.sun.star.lang.IllegalArgumentException: "
652  + e.Message,
653  object, anyEx );
654  }
655  undoDefaulted = false;
656  } else if (undoOptional
657  && value.getValueTypeName().startsWith(
658  "com.sun.star.beans.Optional<"))
659  {
660  css::uno::Reference< css::reflection::XIdlClass > optional(
661  getReflection(value.getValueTypeName()));
662  try {
663  bool present = false;
664  if (!(css::uno::Reference< css::reflection::XIdlField2 >(
665  optional->getField("IsPresent"),
666  css::uno::UNO_QUERY_THROW)->get(value)
667  >>= present))
668  {
669  throw css::uno::RuntimeException(
670  ("unexpected type of com.sun.star.beans.Optional"
671  " IsPresent member"),
672  object);
673  }
674  if (!present) {
675  value.clear();
676  break;
677  }
678  value = css::uno::Reference< css::reflection::XIdlField2 >(
679  optional->getField("Value"), css::uno::UNO_QUERY_THROW)->
680  get(value);
681  } catch (css::lang::IllegalArgumentException & e) {
682  css::uno::Any anyEx = cppu::getCaughtException();
683  throw css::lang::WrappedTargetRuntimeException(
684  "unexpected com.sun.star.lang.IllegalArgumentException: "
685  + e.Message,
686  object, anyEx );
687  }
688  undoOptional = false;
689  } else {
690  throw css::uno::RuntimeException(
691  "unexpected type of attribute " + name, object);
692  }
693  }
694  if (state != nullptr) {
695  //XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE
696  // over DEFAULT_VALUE:
697  *state = isAmbiguous
698  ? css::beans::PropertyState_AMBIGUOUS_VALUE
699  : isDefaulted
700  ? css::beans::PropertyState_DEFAULT_VALUE
701  : css::beans::PropertyState_DIRECT_VALUE;
702  }
703  return value;
704 }
705 
706 css::uno::Reference< css::reflection::XIdlClass >
707 PropertySetMixinImpl::Impl::getReflection(OUString const & typeName) const
708 {
709  return css::uno::Reference< css::reflection::XIdlClass >(
710  css::reflection::theCoreReflection::get(m_context)->forName(typeName),
711  css::uno::UNO_SET_THROW);
712 }
713 
715  css::uno::Reference< css::uno::XInterface > const & object,
716  css::uno::Any const & value,
717  css::uno::Reference< css::reflection::XIdlClass > const & type,
718  bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted, bool isDefaulted,
719  bool wrapOptional)
720 {
721  assert(wrapAmbiguous || !isAmbiguous);
722  assert(wrapDefaulted || !isDefaulted);
723  if (wrapAmbiguous
724  && type->getName().startsWith("com.sun.star.beans.Ambiguous<"))
725  {
726  css::uno::Any strct;
727  type->createObject(strct);
728  try {
729  css::uno::Reference< css::reflection::XIdlField2 > field(
730  type->getField("Value"), css::uno::UNO_QUERY_THROW);
731  field->set(
732  strct,
733  wrapValue(
734  object, value, field->getType(), false, false,
735  wrapDefaulted, isDefaulted, wrapOptional));
736  css::uno::Reference< css::reflection::XIdlField2 >(
737  type->getField("IsAmbiguous"), css::uno::UNO_QUERY_THROW)->set(
738  strct, css::uno::Any(isAmbiguous));
739  } catch (css::lang::IllegalArgumentException & e) {
740  css::uno::Any anyEx = cppu::getCaughtException();
741  throw css::lang::WrappedTargetRuntimeException(
742  "unexpected com.sun.star.lang.IllegalArgumentException: "
743  + e.Message,
744  object, anyEx );
745  } catch (css::lang::IllegalAccessException & e) {
746  css::uno::Any anyEx = cppu::getCaughtException();
747  throw css::lang::WrappedTargetRuntimeException(
748  "unexpected com.sun.star.lang.IllegalAccessException: "
749  + e.Message,
750  object, anyEx );
751  }
752  return strct;
753  }
754  if (wrapDefaulted
755  && type->getName().startsWith("com.sun.star.beans.Defaulted<"))
756  {
757  css::uno::Any strct;
758  type->createObject(strct);
759  try {
760  css::uno::Reference< css::reflection::XIdlField2 > field(
761  type->getField("Value"), css::uno::UNO_QUERY_THROW);
762  field->set(
763  strct,
764  wrapValue(
765  object, value, field->getType(), wrapAmbiguous, isAmbiguous,
766  false, false, wrapOptional));
767  css::uno::Reference< css::reflection::XIdlField2 >(
768  type->getField("IsDefaulted"), css::uno::UNO_QUERY_THROW)->set(
769  strct, css::uno::Any(isDefaulted));
770  } catch (css::lang::IllegalArgumentException & e) {
771  css::uno::Any anyEx = cppu::getCaughtException();
772  throw css::lang::WrappedTargetRuntimeException(
773  "unexpected com.sun.star.lang.IllegalArgumentException: "
774  + e.Message,
775  object, anyEx );
776  } catch (css::lang::IllegalAccessException & e) {
777  css::uno::Any anyEx = cppu::getCaughtException();
778  throw css::lang::WrappedTargetRuntimeException(
779  "unexpected com.sun.star.lang.IllegalAccessException: "
780  + e.Message,
781  object, anyEx );
782  }
783  return strct;
784  }
785  if (wrapOptional
786  && type->getName().startsWith("com.sun.star.beans.Optional<"))
787  {
788  css::uno::Any strct;
789  type->createObject(strct);
790  bool present = value.hasValue();
791  try {
792  css::uno::Reference< css::reflection::XIdlField2 >(
793  type->getField("IsPresent"), css::uno::UNO_QUERY_THROW)->set(
794  strct, css::uno::Any(present));
795  if (present) {
796  css::uno::Reference< css::reflection::XIdlField2 > field(
797  type->getField("Value"), css::uno::UNO_QUERY_THROW);
798  field->set(
799  strct,
800  wrapValue(
801  object, value, field->getType(), wrapAmbiguous,
802  isAmbiguous, wrapDefaulted, isDefaulted, false));
803  }
804  } catch (css::lang::IllegalArgumentException & e) {
805  css::uno::Any anyEx = cppu::getCaughtException();
806  throw css::lang::WrappedTargetRuntimeException(
807  "unexpected com.sun.star.lang.IllegalArgumentException: "
808  + e.Message,
809  object, anyEx );
810  } catch (css::lang::IllegalAccessException & e) {
811  css::uno::Any anyEx = cppu::getCaughtException();
812  throw css::lang::WrappedTargetRuntimeException(
813  "unexpected com.sun.star.lang.IllegalAccessException: "
814  + e.Message,
815  object, anyEx );
816  }
817  return strct;
818  }
819  if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
820  throw css::uno::RuntimeException(
821  "unexpected type of attribute", object);
822  }
823  return value;
824 }
825 
826 PropertySetMixinImpl::PropertySetMixinImpl(
827  css::uno::Reference< css::uno::XComponentContext > const & context,
828  Implements implements,
829  css::uno::Sequence< OUString > const & absentOptional,
830  css::uno::Type const & type)
831 {
832  m_impl = new Impl(context, implements, absentOptional, type);
833  m_impl->acquire();
834 }
835 
836 PropertySetMixinImpl::~PropertySetMixinImpl() {
837  m_impl->release();
838 }
839 
840 void PropertySetMixinImpl::checkUnknown(OUString const & propertyName) {
841  if (!propertyName.isEmpty()) {
842  m_impl->get(
843  static_cast< css::beans::XPropertySet * >(this), propertyName);
844  }
845 }
846 
847 void PropertySetMixinImpl::prepareSet(
848  OUString const & propertyName, css::uno::Any const & oldValue,
849  css::uno::Any const & newValue, BoundListeners * boundListeners)
850 {
851  Impl::PropertyMap::const_iterator it(m_impl->properties.find(propertyName));
852  assert(it != m_impl->properties.end());
853  Impl::VetoListenerBag specificVeto;
854  Impl::VetoListenerBag unspecificVeto;
855  {
856  osl::MutexGuard g(m_impl->mutex);
857  if (m_impl->disposed) {
858  throw css::lang::DisposedException(
859  "disposed", static_cast< css::beans::XPropertySet * >(this));
860  }
861  if ((it->second.property.Attributes
862  & css::beans::PropertyAttribute::CONSTRAINED)
863  != 0)
864  {
865  Impl::VetoListenerMap::const_iterator i(
866  m_impl->vetoListeners.find(propertyName));
867  if (i != m_impl->vetoListeners.end()) {
868  specificVeto = i->second;
869  }
870  i = m_impl->vetoListeners.find("");
871  if (i != m_impl->vetoListeners.end()) {
872  unspecificVeto = i->second;
873  }
874  }
875  if ((it->second.property.Attributes
876  & css::beans::PropertyAttribute::BOUND)
877  != 0)
878  {
879  assert(boundListeners != nullptr);
880  Impl::BoundListenerMap::const_iterator i(
881  m_impl->boundListeners.find(propertyName));
882  if (i != m_impl->boundListeners.end()) {
883  boundListeners->m_impl->specificListeners = i->second;
884  }
885  i = m_impl->boundListeners.find("");
886  if (i != m_impl->boundListeners.end()) {
887  boundListeners->m_impl->unspecificListeners = i->second;
888  }
889  }
890  }
891  if ((it->second.property.Attributes
892  & css::beans::PropertyAttribute::CONSTRAINED)
893  != 0)
894  {
895  css::beans::PropertyChangeEvent event(
896  static_cast< css::beans::XPropertySet * >(this), propertyName,
897  false, it->second.property.Handle, oldValue, newValue);
898  for (auto& rxVetoListener : specificVeto)
899  {
900  try {
901  rxVetoListener->vetoableChange(event);
902  } catch (css::lang::DisposedException &) {}
903  }
904  for (auto& rxVetoListener : unspecificVeto)
905  {
906  try {
907  rxVetoListener->vetoableChange(event);
908  } catch (css::lang::DisposedException &) {}
909  }
910  }
911  if ((it->second.property.Attributes & css::beans::PropertyAttribute::BOUND)
912  != 0)
913  {
914  assert(boundListeners != nullptr);
915  boundListeners->m_impl->event = css::beans::PropertyChangeEvent(
916  static_cast< css::beans::XPropertySet * >(this), propertyName,
917  false, it->second.property.Handle, oldValue, newValue);
918  }
919 }
920 
921 void PropertySetMixinImpl::dispose() {
922  Impl::BoundListenerMap boundListeners;
923  Impl::VetoListenerMap vetoListeners;
924  {
925  osl::MutexGuard g(m_impl->mutex);
926  boundListeners.swap(m_impl->boundListeners);
927  vetoListeners.swap(m_impl->vetoListeners);
928  m_impl->disposed = true;
929  }
930  css::lang::EventObject event(
931  static_cast< css::beans::XPropertySet * >(this));
932  for (const auto& rEntry : boundListeners)
933  {
934  for (auto& rxBoundListener : rEntry.second)
935  {
936  rxBoundListener->disposing(event);
937  }
938  }
939  for (const auto& rEntry : vetoListeners)
940  {
941  for (auto& rxVetoListener : rEntry.second)
942  {
943  rxVetoListener->disposing(event);
944  }
945  }
946 }
947 
948 css::uno::Any PropertySetMixinImpl::queryInterface(css::uno::Type const & type)
949 {
950  if ((m_impl->implements & IMPLEMENTS_PROPERTY_SET) != 0
951  && type == css::beans::XPropertySet::static_type())
952  {
953  css::uno::Reference< css::uno::XInterface > ifc(
954  static_cast< css::beans::XPropertySet * >(this));
955  return css::uno::Any(&ifc, type);
956  }
957  if ((m_impl->implements & IMPLEMENTS_FAST_PROPERTY_SET) != 0
958  && type == css::beans::XFastPropertySet::static_type())
959  {
960  css::uno::Reference< css::uno::XInterface > ifc(
961  static_cast< css::beans::XFastPropertySet * >(this));
962  return css::uno::Any(&ifc, type);
963  }
964  if ((m_impl->implements & IMPLEMENTS_PROPERTY_ACCESS) != 0
965  && type == css::beans::XPropertyAccess::static_type())
966  {
967  css::uno::Reference< css::uno::XInterface > ifc(
968  static_cast< css::beans::XPropertyAccess * >(this));
969  return css::uno::Any(&ifc, type);
970  }
971  return css::uno::Any();
972 }
973 
974 css::uno::Reference< css::beans::XPropertySetInfo >
975 PropertySetMixinImpl::getPropertySetInfo()
976 {
977  return new Info(m_impl);
978 }
979 
980 void PropertySetMixinImpl::setPropertyValue(
981  OUString const & propertyName, css::uno::Any const & value)
982 {
983  m_impl->setProperty(
984  static_cast< css::beans::XPropertySet * >(this), propertyName, value,
985  false, false, 1);
986 }
987 
988 css::uno::Any PropertySetMixinImpl::getPropertyValue(
989  OUString const & propertyName)
990 {
991  return m_impl->getProperty(
992  static_cast< css::beans::XPropertySet * >(this), propertyName, nullptr);
993 }
994 
995 void PropertySetMixinImpl::addPropertyChangeListener(
996  OUString const & propertyName,
997  css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
998 {
999  css::uno::Reference< css::beans::XPropertyChangeListener >(
1000  listener, css::uno::UNO_SET_THROW); // reject NULL listener
1001  checkUnknown(propertyName);
1002  bool disposed;
1003  {
1004  osl::MutexGuard g(m_impl->mutex);
1005  disposed = m_impl->disposed;
1006  if (!disposed) {
1007  m_impl->boundListeners[propertyName].insert(listener);
1008  }
1009  }
1010  if (disposed) {
1011  listener->disposing(
1012  css::lang::EventObject(
1013  static_cast< css::beans::XPropertySet * >(this)));
1014  }
1015 }
1016 
1017 void PropertySetMixinImpl::removePropertyChangeListener(
1018  OUString const & propertyName,
1019  css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
1020 {
1021  assert(listener.is());
1022  checkUnknown(propertyName);
1023  osl::MutexGuard g(m_impl->mutex);
1024  Impl::BoundListenerMap::iterator i(
1025  m_impl->boundListeners.find(propertyName));
1026  if (i != m_impl->boundListeners.end()) {
1027  BoundListenerBag::iterator j(i->second.find(listener));
1028  if (j != i->second.end()) {
1029  i->second.erase(j);
1030  }
1031  }
1032 }
1033 
1034 void PropertySetMixinImpl::addVetoableChangeListener(
1035  OUString const & propertyName,
1036  css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
1037 {
1038  css::uno::Reference< css::beans::XVetoableChangeListener >(
1039  listener, css::uno::UNO_SET_THROW); // reject NULL listener
1040  checkUnknown(propertyName);
1041  bool disposed;
1042  {
1043  osl::MutexGuard g(m_impl->mutex);
1044  disposed = m_impl->disposed;
1045  if (!disposed) {
1046  m_impl->vetoListeners[propertyName].insert(listener);
1047  }
1048  }
1049  if (disposed) {
1050  listener->disposing(
1051  css::lang::EventObject(
1052  static_cast< css::beans::XPropertySet * >(this)));
1053  }
1054 }
1055 
1056 void PropertySetMixinImpl::removeVetoableChangeListener(
1057  OUString const & propertyName,
1058  css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
1059 {
1060  assert(listener.is());
1061  checkUnknown(propertyName);
1062  osl::MutexGuard g(m_impl->mutex);
1063  Impl::VetoListenerMap::iterator i(m_impl->vetoListeners.find(propertyName));
1064  if (i != m_impl->vetoListeners.end()) {
1065  Impl::VetoListenerBag::iterator j(i->second.find(listener));
1066  if (j != i->second.end()) {
1067  i->second.erase(j);
1068  }
1069  }
1070 }
1071 
1072 void PropertySetMixinImpl::setFastPropertyValue(
1073  sal_Int32 handle, css::uno::Any const & value)
1074 {
1075  m_impl->setProperty(
1076  static_cast< css::beans::XPropertySet * >(this),
1077  m_impl->translateHandle(
1078  static_cast< css::beans::XPropertySet * >(this), handle),
1079  value, false, false, 1);
1080 }
1081 
1082 css::uno::Any PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle)
1083 {
1084  return m_impl->getProperty(
1085  static_cast< css::beans::XPropertySet * >(this),
1086  m_impl->translateHandle(
1087  static_cast< css::beans::XPropertySet * >(this), handle),
1088  nullptr);
1089 }
1090 
1091 css::uno::Sequence< css::beans::PropertyValue >
1092 PropertySetMixinImpl::getPropertyValues()
1093 {
1094  css::uno::Sequence< css::beans::PropertyValue > s(
1095  m_impl->handleMap.getLength());
1096  sal_Int32 n = 0;
1097  for (sal_Int32 i = 0; i < m_impl->handleMap.getLength(); ++i) {
1098  try {
1099  s[n].Value = m_impl->getProperty(
1100  static_cast< css::beans::XPropertySet * >(this),
1101  m_impl->handleMap[i], &s[n].State);
1102  } catch (css::beans::UnknownPropertyException &) {
1103  continue;
1104  } catch (css::lang::WrappedTargetException & e) {
1105  throw css::lang::WrappedTargetRuntimeException(
1106  e.Message, static_cast< css::beans::XPropertySet * >(this),
1107  e.TargetException);
1108  }
1109  s[n].Name = m_impl->handleMap[i];
1110  s[n].Handle = i;
1111  ++n;
1112  }
1113  s.realloc(n);
1114  return s;
1115 }
1116 
1117 void PropertySetMixinImpl::setPropertyValues(
1118  css::uno::Sequence< css::beans::PropertyValue > const & props)
1119 {
1120  for (const auto & p : props) {
1121  if (p.Handle != -1
1122  && (p.Name
1123  != m_impl->translateHandle(
1124  static_cast< css::beans::XPropertySet * >(this),
1125  p.Handle)))
1126  {
1127  throw css::beans::UnknownPropertyException(
1128  ("name " + p.Name + " does not match handle "
1129  + OUString::number(p.Handle)),
1130  static_cast< css::beans::XPropertySet * >(this));
1131  }
1132  m_impl->setProperty(
1133  static_cast< css::beans::XPropertySet * >(this), p.Name,
1134  p.Value,
1135  p.State == css::beans::PropertyState_AMBIGUOUS_VALUE,
1136  p.State == css::beans::PropertyState_DEFAULT_VALUE, 0);
1137  }
1138 }
1139 
1140 /* 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...
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
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
static void copy(Sequence< Type > &rDest, const Sequence< Type > &rSource, sal_Int32 nOffset)
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)