office-gobmx/cppuhelper/source/propertysetmixin.cxx
Luboš Luňák 64b993e046 finish deprecation of O(U)String::valueOf()
Compiler plugin to replace with matching number(), boolean() or OUString ctor,
ran it, few manual tweaks, mark as really deprecated.

Change-Id: I4a79bdbcf4c460d21e73b635d2bd3725c22876b2
2013-08-21 15:10:35 +02:00

1381 lines
53 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "sal/config.h"
#include "cppuhelper/propertysetmixin.hxx"
#include "com/sun/star/beans/Property.hpp"
#include "com/sun/star/beans/PropertyChangeEvent.hpp"
#include "com/sun/star/beans/PropertyAttribute.hpp"
#include "com/sun/star/beans/PropertyValue.hpp"
#include "com/sun/star/beans/PropertyVetoException.hpp"
#include "com/sun/star/beans/UnknownPropertyException.hpp"
#include "com/sun/star/beans/XFastPropertySet.hpp"
#include "com/sun/star/beans/XPropertyAccess.hpp"
#include "com/sun/star/beans/XPropertyChangeListener.hpp"
#include "com/sun/star/beans/XPropertySet.hpp"
#include "com/sun/star/beans/XPropertySetInfo.hpp"
#include "com/sun/star/beans/XVetoableChangeListener.hpp"
#include "com/sun/star/container/NoSuchElementException.hpp"
#include "com/sun/star/container/XHierarchicalNameAccess.hpp"
#include "com/sun/star/lang/DisposedException.hpp"
#include "com/sun/star/lang/EventObject.hpp"
#include "com/sun/star/lang/IllegalAccessException.hpp"
#include "com/sun/star/lang/IllegalArgumentException.hpp"
#include "com/sun/star/lang/WrappedTargetException.hpp"
#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
#include "com/sun/star/lang/XComponent.hpp"
#include "com/sun/star/lang/XMultiComponentFactory.hpp"
#include "com/sun/star/reflection/XCompoundTypeDescription.hpp"
#include "com/sun/star/reflection/XIdlClass.hpp"
#include "com/sun/star/reflection/XIdlField2.hpp"
#include "com/sun/star/reflection/XIdlReflection.hpp"
#include "com/sun/star/reflection/XIndirectTypeDescription.hpp"
#include "com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp"
#include "com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp"
#include "com/sun/star/reflection/XInterfaceTypeDescription2.hpp"
#include "com/sun/star/reflection/XStructTypeDescription.hpp"
#include "com/sun/star/reflection/XTypeDescription.hpp"
#include "com/sun/star/uno/Any.hxx"
#include "com/sun/star/uno/DeploymentException.hpp"
#include "com/sun/star/uno/Exception.hpp"
#include "com/sun/star/uno/Reference.hxx"
#include "com/sun/star/uno/RuntimeException.hpp"
#include "com/sun/star/uno/Sequence.hxx"
#include "com/sun/star/uno/Type.hxx"
#include "com/sun/star/uno/TypeClass.hpp"
#include "com/sun/star/uno/XComponentContext.hpp"
#include "com/sun/star/uno/XInterface.hpp"
#include "cppuhelper/implbase1.hxx"
#include "cppuhelper/weak.hxx"
#include "osl/diagnose.h"
#include "osl/mutex.hxx"
#include "rtl/ref.hxx"
#include "rtl/string.h"
#include "rtl/ustring.h"
#include "rtl/ustring.hxx"
#include "sal/types.h"
#include "salhelper/simplereferenceobject.hxx"
#include <algorithm>
#include <map>
#include <new>
#include <set>
#include <vector>
using cppu::PropertySetMixinImpl;
namespace {
template< typename T > struct AutoDispose {
AutoDispose() {}
~AutoDispose() {
try {
dispose();
} catch (...) {}
}
void dispose() {
css::uno::Reference< css::lang::XComponent > comp(
ifc, css::uno::UNO_QUERY);
if (comp.is()) {
comp->dispose();
}
ifc.clear();
}
css::uno::Reference< T > ifc;
private:
AutoDispose(AutoDispose &); // not defined
void operator =(AutoDispose); // not defined
};
struct PropertyData {
explicit PropertyData(
css::beans::Property const & theProperty, bool thePresent):
property(theProperty), present(thePresent) {}
css::beans::Property property;
bool present;
};
struct Data: public salhelper::SimpleReferenceObject {
typedef std::map< rtl::OUString, PropertyData > PropertyMap;
PropertyMap properties;
PropertyMap::const_iterator get(
css::uno::Reference< css::uno::XInterface > const & object,
rtl::OUString const & name) const;
protected:
void initProperties(
css::uno::Reference< css::reflection::XTypeDescription > const & type,
css::uno::Sequence< rtl::OUString > const & absentOptional,
std::vector< rtl::OUString > * handleNames)
{
TypeSet seen;
initProperties(type, absentOptional, handleNames, &seen);
}
private:
typedef std::set< rtl::OUString > TypeSet;
void initProperties(
css::uno::Reference< css::reflection::XTypeDescription > const & type,
css::uno::Sequence< rtl::OUString > const & absentOptional,
std::vector< rtl::OUString > * handleNames, TypeSet * seen);
static css::uno::Reference< css::reflection::XTypeDescription >
resolveTypedefs(
css::uno::Reference< css::reflection::XTypeDescription > const & type);
};
Data::PropertyMap::const_iterator Data::get(
css::uno::Reference< css::uno::XInterface > const & object,
rtl::OUString const & name) const
{
PropertyMap::const_iterator i(properties.find(name));
if (i == properties.end() || !i->second.present) {
throw css::beans::UnknownPropertyException(name, object);
}
return i;
}
void Data::initProperties(
css::uno::Reference< css::reflection::XTypeDescription > const & type,
css::uno::Sequence< rtl::OUString > const & absentOptional,
std::vector< rtl::OUString > * handleNames, TypeSet * seen)
{
css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > ifc(
resolveTypedefs(type), css::uno::UNO_QUERY_THROW);
if (seen->insert(ifc->getName()).second) {
css::uno::Sequence<
css::uno::Reference< css::reflection::XTypeDescription > > bases(
ifc->getBaseTypes());
for (sal_Int32 i = 0; i < bases.getLength(); ++i) {
initProperties(bases[i], absentOptional, handleNames, seen);
}
css::uno::Sequence<
css::uno::Reference<
css::reflection::XInterfaceMemberTypeDescription > > members(
ifc->getMembers());
rtl::OUString const * absentBegin = absentOptional.getConstArray();
rtl::OUString const * absentEnd =
absentBegin + absentOptional.getLength();
for (sal_Int32 i = 0; i < members.getLength(); ++i) {
if (members[i]->getTypeClass()
== css::uno::TypeClass_INTERFACE_ATTRIBUTE)
{
css::uno::Reference<
css::reflection::XInterfaceAttributeTypeDescription2 > attr(
members[i], css::uno::UNO_QUERY_THROW);
sal_Int16 attrAttribs = 0;
if (attr->isBound()) {
attrAttribs |= css::beans::PropertyAttribute::BOUND;
}
bool setUnknown = false;
if (attr->isReadOnly()) {
attrAttribs |= css::beans::PropertyAttribute::READONLY;
setUnknown = true;
}
css::uno::Sequence<
css::uno::Reference<
css::reflection::XCompoundTypeDescription > > excs(
attr->getGetExceptions());
bool getUnknown = false;
//XXX Special interpretation of getter/setter exceptions only
// works if the specified exceptions are of the exact type, not
// of a supertype:
for (sal_Int32 j = 0; j < excs.getLength(); ++j) {
if ( excs[j]->getName() == "com.sun.star.beans.UnknownPropertyException" )
{
getUnknown = true;
break;
}
}
excs = attr->getSetExceptions();
for (sal_Int32 j = 0; j < excs.getLength(); ++j) {
if ( excs[j]->getName() == "com.sun.star.beans.UnknownPropertyException" )
{
setUnknown = true;
} else if ( excs[j]->getName() == "com.sun.star.beans.PropertyVetoException" )
{
attrAttribs
|= css::beans::PropertyAttribute::CONSTRAINED;
}
}
if (getUnknown && setUnknown) {
attrAttribs |= css::beans::PropertyAttribute::OPTIONAL;
}
css::uno::Reference< css::reflection::XTypeDescription > t(
attr->getType());
for (;;)
{
t = resolveTypedefs(t);
sal_Int16 n;
if (t->getName().matchAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.beans.Ambiguous<")))
{
n = css::beans::PropertyAttribute::MAYBEAMBIGUOUS;
} else if (t->getName().matchAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.beans.Defaulted<")))
{
n = css::beans::PropertyAttribute::MAYBEDEFAULT;
} else if (t->getName().matchAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.beans.Optional<")))
{
n = css::beans::PropertyAttribute::MAYBEVOID;
} else {
break;
}
if ((attrAttribs & n) != 0) {
break;
}
attrAttribs |= n;
css::uno::Sequence<
css::uno::Reference< css::reflection::XTypeDescription > >
args(
css::uno::Reference<
css::reflection::XStructTypeDescription >(
t,
css::uno::UNO_QUERY_THROW)->getTypeArguments());
if (args.getLength() != 1) {
throw css::uno::RuntimeException(
rtl::OUString(
"inconsistent UNO type registry"),
css::uno::Reference< css::uno::XInterface >());
}
t = args[0];
}
std::vector< rtl::OUString >::size_type handles
= handleNames->size();
if (handles > SAL_MAX_INT32) {
throw css::uno::RuntimeException(
rtl::OUString(
"interface type has too many attributes"),
css::uno::Reference< css::uno::XInterface >());
}
rtl::OUString name(members[i]->getMemberName());
if (!properties.insert(
PropertyMap::value_type(
name,
PropertyData(
css::beans::Property(
name, static_cast< sal_Int32 >(handles),
css::uno::Type(
t->getTypeClass(), t->getName()),
attrAttribs),
(std::find(absentBegin, absentEnd, name)
== absentEnd)))).
second)
{
throw css::uno::RuntimeException(
rtl::OUString(
"inconsistent UNO type registry"),
css::uno::Reference< css::uno::XInterface >());
}
handleNames->push_back(name);
}
}
}
}
css::uno::Reference< css::reflection::XTypeDescription > Data::resolveTypedefs(
css::uno::Reference< css::reflection::XTypeDescription > const & type)
{
css::uno::Reference< css::reflection::XTypeDescription > t(type);
while (t->getTypeClass() == css::uno::TypeClass_TYPEDEF) {
t = css::uno::Reference< css::reflection::XIndirectTypeDescription >(
t, css::uno::UNO_QUERY_THROW)->getReferencedType();
}
return t;
}
class Info: public cppu::WeakImplHelper1< css::beans::XPropertySetInfo > {
public:
explicit Info(Data * data): m_data(data) {}
virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties()
throw (css::uno::RuntimeException);
virtual css::beans::Property SAL_CALL getPropertyByName(
rtl::OUString const & name)
throw (
css::beans::UnknownPropertyException, css::uno::RuntimeException);
virtual sal_Bool SAL_CALL hasPropertyByName(rtl::OUString const & name)
throw (css::uno::RuntimeException);
private:
rtl::Reference< Data > m_data;
};
css::uno::Sequence< css::beans::Property > Info::getProperties()
throw (css::uno::RuntimeException)
{
try {
OSL_ASSERT(m_data->properties.size() <= SAL_MAX_INT32);
css::uno::Sequence< css::beans::Property > s(
static_cast< sal_Int32 >(m_data->properties.size()));
sal_Int32 n = 0;
for (Data::PropertyMap::iterator i(m_data->properties.begin());
i != m_data->properties.end(); ++i)
{
if (i->second.present) {
s[n++] = i->second.property;
}
}
s.realloc(n);
return s;
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< cppu::OWeakObject * >(this));
}
}
css::beans::Property Info::getPropertyByName(rtl::OUString const & name)
throw (css::beans::UnknownPropertyException, css::uno::RuntimeException)
{
return m_data->get(static_cast< cppu::OWeakObject * >(this), name)->
second.property;
}
sal_Bool Info::hasPropertyByName(rtl::OUString const & name)
throw (css::uno::RuntimeException)
{
Data::PropertyMap::iterator i(m_data->properties.find(name));
return i != m_data->properties.end() && i->second.present;
}
typedef
std::multiset< css::uno::Reference< css::beans::XPropertyChangeListener > >
BoundListenerBag;
}
class PropertySetMixinImpl::BoundListeners::Impl {
public:
BoundListenerBag specificListeners;
BoundListenerBag unspecificListeners;
css::beans::PropertyChangeEvent event;
};
PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl) {}
PropertySetMixinImpl::BoundListeners::~BoundListeners() {
delete m_impl;
}
void PropertySetMixinImpl::BoundListeners::notify() const {
for (BoundListenerBag::const_iterator i(m_impl->specificListeners.begin());
i != m_impl->specificListeners.end(); ++i)
{
try {
(*i)->propertyChange(m_impl->event);
} catch (css::lang::DisposedException &) {}
}
for (BoundListenerBag::const_iterator i(
m_impl->unspecificListeners.begin());
i != m_impl->unspecificListeners.end(); ++i)
{
try {
(*i)->propertyChange(m_impl->event);
} catch (css::lang::DisposedException &) {}
}
}
class PropertySetMixinImpl::Impl: public Data {
public:
Impl(
css::uno::Reference< css::uno::XComponentContext > const & context,
Implements theImplements,
css::uno::Sequence< rtl::OUString > const & absentOptional,
css::uno::Type const & type);
rtl::OUString translateHandle(
css::uno::Reference< css::uno::XInterface > const & object,
sal_Int32 handle) const;
void setProperty(
css::uno::Reference< css::uno::XInterface > const & object,
rtl::OUString const & name, css::uno::Any const & value,
bool isAmbiguous, bool isDefaulted, sal_Int16 illegalArgumentPosition)
const;
css::uno::Any getProperty(
css::uno::Reference< css::uno::XInterface > const & object,
rtl::OUString const & name, css::beans::PropertyState * state) const;
PropertySetMixinImpl::Implements implements;
css::uno::Sequence< rtl::OUString > handleMap;
typedef std::map< rtl::OUString, BoundListenerBag > BoundListenerMap;
typedef
std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > >
VetoListenerBag;
typedef std::map< rtl::OUString, VetoListenerBag > VetoListenerMap;
mutable osl::Mutex mutex;
BoundListenerMap boundListeners;
VetoListenerMap vetoListeners;
bool disposed;
private:
css::uno::Reference< css::reflection::XIdlClass > getReflection(
rtl::OUString const & typeName) const;
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::uno::XComponentContext > const & m_context;
css::uno::Sequence< rtl::OUString > m_absentOptional;
css::uno::Type m_type;
css::uno::Reference< css::reflection::XIdlClass > m_idlClass;
};
PropertySetMixinImpl::Impl::Impl(
css::uno::Reference< css::uno::XComponentContext > const & context,
Implements theImplements,
css::uno::Sequence< rtl::OUString > const & absentOptional,
css::uno::Type const & type):
implements(theImplements), disposed(false), m_context(context),
m_absentOptional(absentOptional), m_type(type)
{
OSL_ASSERT(
context.is()
&& ((implements
& ~(IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET
| IMPLEMENTS_PROPERTY_ACCESS))
== 0));
m_idlClass = getReflection(m_type.getTypeName());
css::uno::Reference< css::reflection::XTypeDescription > ifc;
try {
ifc = css::uno::Reference< css::reflection::XTypeDescription >(
css::uno::Reference< css::container::XHierarchicalNameAccess >(
m_context->getValueByName(
rtl::OUString(
"/singletons/com.sun.star.reflection."
"theTypeDescriptionManager")),
css::uno::UNO_QUERY_THROW)->getByHierarchicalName(
m_type.getTypeName()),
css::uno::UNO_QUERY_THROW);
} catch (css::container::NoSuchElementException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected"
" com.sun.star.container.NoSuchElementException: ")
+ e.Message),
css::uno::Reference< css::uno::XInterface >());
}
std::vector< rtl::OUString > handleNames;
initProperties(ifc, m_absentOptional, &handleNames);
std::vector< rtl::OUString >::size_type size = handleNames.size();
OSL_ASSERT(size <= SAL_MAX_INT32);
handleMap.realloc(static_cast< sal_Int32 >(size));
std::copy(handleNames.begin(), handleNames.end(), handleMap.getArray());
}
rtl::OUString PropertySetMixinImpl::Impl::translateHandle(
css::uno::Reference< css::uno::XInterface > const & object,
sal_Int32 handle) const
{
if (handle < 0 || handle >= handleMap.getLength()) {
throw css::beans::UnknownPropertyException(
(rtl::OUString("bad handle ")
+ rtl::OUString::number(handle)),
object);
}
return handleMap[handle];
}
void PropertySetMixinImpl::Impl::setProperty(
css::uno::Reference< css::uno::XInterface > const & object,
rtl::OUString const & name, css::uno::Any const & value, bool isAmbiguous,
bool isDefaulted, sal_Int16 illegalArgumentPosition) const
{
PropertyMap::const_iterator i(properties.find(name));
if (i == properties.end()) {
throw css::beans::UnknownPropertyException(name, object);
}
if ((isAmbiguous
&& ((i->second.property.Attributes
& css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
== 0))
|| (isDefaulted
&& ((i->second.property.Attributes
& css::beans::PropertyAttribute::MAYBEDEFAULT)
== 0)))
{
throw css::lang::IllegalArgumentException(
(rtl::OUString(
"flagging as ambiguous/defaulted non-ambiguous/defaulted"
" property ")
+ name),
object, illegalArgumentPosition);
}
css::uno::Reference< css::reflection::XIdlField2 > f(
m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
css::uno::Any o(object->queryInterface(m_type));
css::uno::Any v(
wrapValue(
object, value,
(css::uno::Reference< css::reflection::XIdlField2 >(
m_idlClass->getField(name), css::uno::UNO_QUERY_THROW)->
getType()),
((i->second.property.Attributes
& css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
!= 0),
isAmbiguous,
((i->second.property.Attributes
& css::beans::PropertyAttribute::MAYBEDEFAULT)
!= 0),
isDefaulted,
((i->second.property.Attributes
& css::beans::PropertyAttribute::MAYBEVOID)
!= 0)));
try {
f->set(o, v);
} catch (css::lang::IllegalArgumentException & e) {
if (e.ArgumentPosition == 1) {
throw css::lang::IllegalArgumentException(
e.Message, object, illegalArgumentPosition);
} else {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected"
" com.sun.star.lang.IllegalArgumentException: ")
+ e.Message),
object);
}
} catch (css::lang::IllegalAccessException &) {
//TODO Clarify whether PropertyVetoException is the correct exception
// to throw when trying to set a read-only property:
throw css::beans::PropertyVetoException(
(rtl::OUString("cannot set read-only property ")
+ name),
object);
} catch (css::lang::WrappedTargetRuntimeException & e) {
//FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
// guaranteed to originate directly within XIdlField2.get (and thus have
// the expected semantics); it might also be passed through from lower
// layers.
if (e.TargetException.isExtractableTo(
getCppuType(
static_cast< css::beans::UnknownPropertyException * >(0)))
&& ((i->second.property.Attributes
& css::beans::PropertyAttribute::OPTIONAL)
!= 0))
{
throw css::beans::UnknownPropertyException(name, object);
} else if (e.TargetException.isExtractableTo(
getCppuType(
static_cast< css::beans::PropertyVetoException * >(
0)))
&& ((i->second.property.Attributes
& css::beans::PropertyAttribute::CONSTRAINED)
!= 0))
{
css::beans::PropertyVetoException exc;
e.TargetException >>= exc;
if (exc.Message.isEmpty() )
throw css::beans::PropertyVetoException("Invalid " + name, object);
else
throw exc;
} else {
throw css::lang::WrappedTargetException(
e.Message, object, e.TargetException);
}
}
}
css::uno::Any PropertySetMixinImpl::Impl::getProperty(
css::uno::Reference< css::uno::XInterface > const & object,
rtl::OUString const & name, css::beans::PropertyState * state) const
{
PropertyMap::const_iterator i(properties.find(name));
if (i == properties.end()) {
throw css::beans::UnknownPropertyException(name, object);
}
css::uno::Reference< css::reflection::XIdlField2 > field(
m_idlClass->getField(name), css::uno::UNO_QUERY_THROW);
css::uno::Any value;
try {
value = field->get(object->queryInterface(m_type));
} catch (css::lang::IllegalArgumentException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected com.sun.star.lang.IllegalArgumentException: ")
+ e.Message),
object);
} catch (css::lang::WrappedTargetRuntimeException & e) {
//FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
// guaranteed to originate directly within XIdlField2.get (and thus have
// the expected semantics); it might also be passed through from lower
// layers.
if (e.TargetException.isExtractableTo(
getCppuType(
static_cast< css::beans::UnknownPropertyException * >(0)))
&& ((i->second.property.Attributes
& css::beans::PropertyAttribute::OPTIONAL)
!= 0))
{
throw css::beans::UnknownPropertyException(name, object);
} else {
throw css::lang::WrappedTargetException(
e.Message, object, e.TargetException);
}
}
bool undoAmbiguous
= ((i->second.property.Attributes
& css::beans::PropertyAttribute::MAYBEAMBIGUOUS)
!= 0);
bool undoDefaulted
= ((i->second.property.Attributes
& css::beans::PropertyAttribute::MAYBEDEFAULT)
!= 0);
bool undoOptional
= ((i->second.property.Attributes
& css::beans::PropertyAttribute::MAYBEVOID)
!= 0);
bool isAmbiguous = false;
bool isDefaulted = false;
while (undoAmbiguous || undoDefaulted || undoOptional) {
if (undoAmbiguous
&& value.getValueTypeName().matchAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.beans.Ambiguous<")))
{
css::uno::Reference< css::reflection::XIdlClass > ambiguous(
getReflection(value.getValueTypeName()));
try {
if (!(css::uno::Reference< css::reflection::XIdlField2 >(
ambiguous->getField(
rtl::OUString("IsAmbiguous")),
css::uno::UNO_QUERY_THROW)->get(value)
>>= isAmbiguous))
{
throw css::uno::RuntimeException(
rtl::OUString(
"unexpected type of"
" com.sun.star.beans.Ambiguous IsAmbiguous"
" member"),
object);
}
value = css::uno::Reference< css::reflection::XIdlField2 >(
ambiguous->getField(
rtl::OUString("Value")),
css::uno::UNO_QUERY_THROW)->get(value);
} catch (css::lang::IllegalArgumentException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected com.sun.star.lang."
"IllegalArgumentException: ")
+ e.Message),
object);
}
undoAmbiguous = false;
} else if (undoDefaulted
&& value.getValueTypeName().matchAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.beans.Defaulted<")))
{
css::uno::Reference< css::reflection::XIdlClass > defaulted(
getReflection(value.getValueTypeName()));
try {
if (!(css::uno::Reference< css::reflection::XIdlField2 >(
defaulted->getField(
rtl::OUString("IsDefaulted")),
css::uno::UNO_QUERY_THROW)->get(value)
>>= isDefaulted))
{
throw css::uno::RuntimeException(
rtl::OUString(
"unexpected type of"
" com.sun.star.beans.Defaulted IsDefaulted"
" member"),
object);
}
value = css::uno::Reference< css::reflection::XIdlField2 >(
defaulted->getField(
rtl::OUString("Value")),
css::uno::UNO_QUERY_THROW)->get(value);
} catch (css::lang::IllegalArgumentException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected com.sun.star.lang."
"IllegalArgumentException: ")
+ e.Message),
object);
}
undoDefaulted = false;
} else if (undoOptional
&& value.getValueTypeName().matchAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.beans.Optional<")))
{
css::uno::Reference< css::reflection::XIdlClass > optional(
getReflection(value.getValueTypeName()));
try {
bool present = false;
if (!(css::uno::Reference< css::reflection::XIdlField2 >(
optional->getField(
rtl::OUString("IsPresent")),
css::uno::UNO_QUERY_THROW)->get(value)
>>= present))
{
throw css::uno::RuntimeException(
rtl::OUString(
"unexpected type of com.sun.star.beans.Optional"
" IsPresent member"),
object);
}
if (!present) {
value.clear();
break;
}
value = css::uno::Reference< css::reflection::XIdlField2 >(
optional->getField(
rtl::OUString("Value")),
css::uno::UNO_QUERY_THROW)->get(value);
} catch (css::lang::IllegalArgumentException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected com.sun.star.lang."
"IllegalArgumentException: ")
+ e.Message),
object);
}
undoOptional = false;
} else {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected type of attribute ")
+ name),
object);
}
}
if (state != 0) {
//XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE
// over DEFAULT_VALUE:
*state = isAmbiguous
? css::beans::PropertyState_AMBIGUOUS_VALUE
: isDefaulted
? css::beans::PropertyState_DEFAULT_VALUE
: css::beans::PropertyState_DIRECT_VALUE;
}
return value;
}
css::uno::Reference< css::reflection::XIdlClass >
PropertySetMixinImpl::Impl::getReflection(rtl::OUString const & typeName) const
{
css::uno::Reference< css::lang::XMultiComponentFactory > factory(
m_context->getServiceManager(), css::uno::UNO_QUERY_THROW);
AutoDispose< css::reflection::XIdlReflection > refl;
try {
refl.ifc = css::uno::Reference< css::reflection::XIdlReflection >(
factory->createInstanceWithContext(
rtl::OUString(
"com.sun.star.reflection.CoreReflection"),
m_context),
css::uno::UNO_QUERY_THROW);
} catch (css::uno::RuntimeException &) {
throw;
} catch (css::uno::Exception & e) {
throw css::uno::DeploymentException(
(rtl::OUString(
"component context fails to supply service"
" com.sun.star.reflection.CoreReflection: ")
+ e.Message),
m_context);
}
css::uno::Reference< css::reflection::XIdlClass > idlClass(
refl.ifc->forName(typeName), css::uno::UNO_QUERY_THROW);
refl.dispose();
return idlClass;
}
css::uno::Any PropertySetMixinImpl::Impl::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)
{
OSL_ASSERT(
(wrapAmbiguous || !isAmbiguous) && (wrapDefaulted || !isDefaulted));
if (wrapAmbiguous
&& type->getName().matchAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.beans.Ambiguous<")))
{
css::uno::Any strct;
type->createObject(strct);
try {
css::uno::Reference< css::reflection::XIdlField2 > field(
type->getField(
rtl::OUString("Value")),
css::uno::UNO_QUERY_THROW);
field->set(
strct,
wrapValue(
object, value, field->getType(), false, false,
wrapDefaulted, isDefaulted, wrapOptional));
css::uno::Reference< css::reflection::XIdlField2 >(
type->getField(
rtl::OUString("IsAmbiguous")),
css::uno::UNO_QUERY_THROW)->set(
strct, css::uno::makeAny(isAmbiguous));
} catch (css::lang::IllegalArgumentException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected"
" com.sun.star.lang.IllegalArgumentException: ")
+ e.Message),
object);
} catch (css::lang::IllegalAccessException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected"
" com.sun.star.lang.IllegalAccessException: ")
+ e.Message),
object);
}
return strct;
} else if (wrapDefaulted
&& type->getName().matchAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.beans.Defaulted<")))
{
css::uno::Any strct;
type->createObject(strct);
try {
css::uno::Reference< css::reflection::XIdlField2 > field(
type->getField(
rtl::OUString("Value")),
css::uno::UNO_QUERY_THROW);
field->set(
strct,
wrapValue(
object, value, field->getType(), wrapAmbiguous, isAmbiguous,
false, false, wrapOptional));
css::uno::Reference< css::reflection::XIdlField2 >(
type->getField(
rtl::OUString("IsDefaulted")),
css::uno::UNO_QUERY_THROW)->set(
strct, css::uno::makeAny(isDefaulted));
} catch (css::lang::IllegalArgumentException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected"
" com.sun.star.lang.IllegalArgumentException: ")
+ e.Message),
object);
} catch (css::lang::IllegalAccessException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected"
" com.sun.star.lang.IllegalAccessException: ")
+ e.Message),
object);
}
return strct;
} else if (wrapOptional
&& type->getName().matchAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.beans.Optional<")))
{
css::uno::Any strct;
type->createObject(strct);
bool present = value.hasValue();
try {
css::uno::Reference< css::reflection::XIdlField2 >(
type->getField(
rtl::OUString("IsPresent")),
css::uno::UNO_QUERY_THROW)->set(
strct, css::uno::makeAny(present));
if (present) {
css::uno::Reference< css::reflection::XIdlField2 > field(
type->getField(
rtl::OUString("Value")),
css::uno::UNO_QUERY_THROW);
field->set(
strct,
wrapValue(
object, value, field->getType(), wrapAmbiguous,
isAmbiguous, wrapDefaulted, isDefaulted, false));
}
} catch (css::lang::IllegalArgumentException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected"
" com.sun.star.lang.IllegalArgumentException: ")
+ e.Message),
object);
} catch (css::lang::IllegalAccessException & e) {
throw css::uno::RuntimeException(
(rtl::OUString(
"unexpected"
" com.sun.star.lang.IllegalAccessException: ")
+ e.Message),
object);
}
return strct;
} else {
if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
throw css::uno::RuntimeException(
rtl::OUString(
"unexpected type of attribute"),
object);
}
return value;
}
}
PropertySetMixinImpl::PropertySetMixinImpl(
css::uno::Reference< css::uno::XComponentContext > const & context,
Implements implements,
css::uno::Sequence< rtl::OUString > const & absentOptional,
css::uno::Type const & type)
{
m_impl = new Impl(context, implements, absentOptional, type);
m_impl->acquire();
}
PropertySetMixinImpl::~PropertySetMixinImpl() {
m_impl->release();
}
void PropertySetMixinImpl::checkUnknown(rtl::OUString const & propertyName) {
if (!propertyName.isEmpty()) {
m_impl->get(
static_cast< css::beans::XPropertySet * >(this), propertyName);
}
}
void PropertySetMixinImpl::prepareSet(
rtl::OUString const & propertyName, css::uno::Any const & oldValue,
css::uno::Any const & newValue, BoundListeners * boundListeners)
{
Impl::PropertyMap::const_iterator it(m_impl->properties.find(propertyName));
OSL_ASSERT(it != m_impl->properties.end());
Impl::VetoListenerBag specificVeto;
Impl::VetoListenerBag unspecificVeto;
{
osl::MutexGuard g(m_impl->mutex);
if (m_impl->disposed) {
throw css::lang::DisposedException(
rtl::OUString("disposed"),
static_cast< css::beans::XPropertySet * >(this));
}
if ((it->second.property.Attributes
& css::beans::PropertyAttribute::CONSTRAINED)
!= 0)
{
Impl::VetoListenerMap::const_iterator i(
m_impl->vetoListeners.find(propertyName));
if (i != m_impl->vetoListeners.end()) {
specificVeto = i->second;
}
i = m_impl->vetoListeners.find(rtl::OUString());
if (i != m_impl->vetoListeners.end()) {
unspecificVeto = i->second;
}
}
if ((it->second.property.Attributes
& css::beans::PropertyAttribute::BOUND)
!= 0)
{
OSL_ASSERT(boundListeners != 0);
Impl::BoundListenerMap::const_iterator i(
m_impl->boundListeners.find(propertyName));
if (i != m_impl->boundListeners.end()) {
boundListeners->m_impl->specificListeners = i->second;
}
i = m_impl->boundListeners.find(rtl::OUString());
if (i != m_impl->boundListeners.end()) {
boundListeners->m_impl->unspecificListeners = i->second;
}
}
}
if ((it->second.property.Attributes
& css::beans::PropertyAttribute::CONSTRAINED)
!= 0)
{
css::beans::PropertyChangeEvent event(
static_cast< css::beans::XPropertySet * >(this), propertyName,
false, it->second.property.Handle, oldValue, newValue);
for (Impl::VetoListenerBag::iterator i(specificVeto.begin());
i != specificVeto.end(); ++i)
{
try {
(*i)->vetoableChange(event);
} catch (css::lang::DisposedException &) {}
}
for (Impl::VetoListenerBag::iterator i(unspecificVeto.begin());
i != unspecificVeto.end(); ++i)
{
try {
(*i)->vetoableChange(event);
} catch (css::lang::DisposedException &) {}
}
}
if ((it->second.property.Attributes & css::beans::PropertyAttribute::BOUND)
!= 0)
{
OSL_ASSERT(boundListeners != 0);
boundListeners->m_impl->event = css::beans::PropertyChangeEvent(
static_cast< css::beans::XPropertySet * >(this), propertyName,
false, it->second.property.Handle, oldValue, newValue);
}
}
void PropertySetMixinImpl::dispose() {
Impl::BoundListenerMap boundListeners;
Impl::VetoListenerMap vetoListeners;
{
osl::MutexGuard g(m_impl->mutex);
boundListeners.swap(m_impl->boundListeners);
vetoListeners.swap(m_impl->vetoListeners);
m_impl->disposed = true;
}
css::lang::EventObject event(
static_cast< css::beans::XPropertySet * >(this));
for (Impl::BoundListenerMap::iterator i(boundListeners.begin());
i != boundListeners.end(); ++i)
{
for (BoundListenerBag::iterator j(i->second.begin());
j != i->second.end(); ++j)
{
(*j)->disposing(event);
}
}
for (Impl::VetoListenerMap::iterator i(vetoListeners.begin());
i != vetoListeners.end(); ++i)
{
for (Impl::VetoListenerBag::iterator j(i->second.begin());
j != i->second.end(); ++j)
{
(*j)->disposing(event);
}
}
}
css::uno::Any PropertySetMixinImpl::queryInterface(css::uno::Type const & type)
throw (css::uno::RuntimeException)
{
if (((m_impl->implements & IMPLEMENTS_PROPERTY_SET) != 0
&& type == css::beans::XPropertySet::static_type()))
{
css::uno::Reference< css::uno::XInterface > ifc(
static_cast< css::beans::XPropertySet * >(this));
return css::uno::Any(&ifc, type);
} else if ((m_impl->implements & IMPLEMENTS_FAST_PROPERTY_SET) != 0
&& type == css::beans::XFastPropertySet::static_type())
{
css::uno::Reference< css::uno::XInterface > ifc(
static_cast< css::beans::XFastPropertySet * >(this));
return css::uno::Any(&ifc, type);
} else if ((m_impl->implements & IMPLEMENTS_PROPERTY_ACCESS) != 0
&& type == css::beans::XPropertyAccess::static_type())
{
css::uno::Reference< css::uno::XInterface > ifc(
static_cast< css::beans::XPropertyAccess * >(this));
return css::uno::Any(&ifc, type);
} else {
return css::uno::Any();
}
}
css::uno::Reference< css::beans::XPropertySetInfo >
PropertySetMixinImpl::getPropertySetInfo() throw (css::uno::RuntimeException) {
try {
return new Info(m_impl);
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
void PropertySetMixinImpl::setPropertyValue(
rtl::OUString const & propertyName, css::uno::Any const & value)
throw (
css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
css::uno::RuntimeException)
{
try {
m_impl->setProperty(
static_cast< css::beans::XPropertySet * >(this), propertyName,
value, false, false, 1);
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
css::uno::Any PropertySetMixinImpl::getPropertyValue(
rtl::OUString const & propertyName)
throw (
css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
css::uno::RuntimeException)
{
try {
return m_impl->getProperty(
static_cast< css::beans::XPropertySet * >(this), propertyName, 0);
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
void PropertySetMixinImpl::addPropertyChangeListener(
rtl::OUString const & propertyName,
css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
throw (
css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
css::uno::RuntimeException)
{
css::uno::Reference< css::beans::XPropertyChangeListener >(
listener, css::uno::UNO_QUERY_THROW); // reject NULL listener
checkUnknown(propertyName);
try {
bool disposed;
{
osl::MutexGuard g(m_impl->mutex);
disposed = m_impl->disposed;
if (!disposed) {
m_impl->boundListeners[propertyName].insert(listener);
}
}
if (disposed) {
listener->disposing(
css::lang::EventObject(
static_cast< css::beans::XPropertySet * >(this)));
}
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
void PropertySetMixinImpl::removePropertyChangeListener(
rtl::OUString const & propertyName,
css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
throw (
css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
css::uno::RuntimeException)
{
OSL_ASSERT(listener.is());
checkUnknown(propertyName);
try {
osl::MutexGuard g(m_impl->mutex);
Impl::BoundListenerMap::iterator i(
m_impl->boundListeners.find(propertyName));
if (i != m_impl->boundListeners.end()) {
BoundListenerBag::iterator j(i->second.find(listener));
if (j != i->second.end()) {
i->second.erase(j);
}
}
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
void PropertySetMixinImpl::addVetoableChangeListener(
rtl::OUString const & propertyName,
css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
throw (
css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
css::uno::RuntimeException)
{
css::uno::Reference< css::beans::XVetoableChangeListener >(
listener, css::uno::UNO_QUERY_THROW); // reject NULL listener
checkUnknown(propertyName);
try {
bool disposed;
{
osl::MutexGuard g(m_impl->mutex);
disposed = m_impl->disposed;
if (!disposed) {
m_impl->vetoListeners[propertyName].insert(listener);
}
}
if (disposed) {
listener->disposing(
css::lang::EventObject(
static_cast< css::beans::XPropertySet * >(this)));
}
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
void PropertySetMixinImpl::removeVetoableChangeListener(
rtl::OUString const & propertyName,
css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
throw (
css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
css::uno::RuntimeException)
{
OSL_ASSERT(listener.is());
checkUnknown(propertyName);
try {
osl::MutexGuard g(m_impl->mutex);
Impl::VetoListenerMap::iterator i(
m_impl->vetoListeners.find(propertyName));
if (i != m_impl->vetoListeners.end()) {
Impl::VetoListenerBag::iterator j(i->second.find(listener));
if (j != i->second.end()) {
i->second.erase(j);
}
}
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
void PropertySetMixinImpl::setFastPropertyValue(
sal_Int32 handle, css::uno::Any const & value)
throw (
css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
css::uno::RuntimeException)
{
try {
m_impl->setProperty(
static_cast< css::beans::XPropertySet * >(this),
m_impl->translateHandle(
static_cast< css::beans::XPropertySet * >(this), handle),
value, false, false, 1);
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
css::uno::Any PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle)
throw (
css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
css::uno::RuntimeException)
{
try {
return m_impl->getProperty(
static_cast< css::beans::XPropertySet * >(this),
m_impl->translateHandle(
static_cast< css::beans::XPropertySet * >(this), handle),
0);
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
css::uno::Sequence< css::beans::PropertyValue >
PropertySetMixinImpl::getPropertyValues() throw (css::uno::RuntimeException) {
try {
css::uno::Sequence< css::beans::PropertyValue > s(
m_impl->handleMap.getLength());
sal_Int32 n = 0;
for (sal_Int32 i = 0; i < m_impl->handleMap.getLength(); ++i) {
try {
s[n].Value = m_impl->getProperty(
static_cast< css::beans::XPropertySet * >(this),
m_impl->handleMap[i], &s[n].State);
} catch (css::beans::UnknownPropertyException &) {
continue;
} catch (css::lang::WrappedTargetException & e) {
throw css::lang::WrappedTargetRuntimeException(
e.Message, static_cast< css::beans::XPropertySet * >(this),
e.TargetException);
}
s[n].Name = m_impl->handleMap[i];
s[n].Handle = i;
++n;
}
s.realloc(n);
return s;
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
void PropertySetMixinImpl::setPropertyValues(
css::uno::Sequence< css::beans::PropertyValue > const & props)
throw (
css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
css::uno::RuntimeException)
{
try {
for (sal_Int32 i = 0; i < props.getLength(); ++i) {
if (props[i].Handle != -1
&& (props[i].Name
!= m_impl->translateHandle(
static_cast< css::beans::XPropertySet * >(this),
props[i].Handle)))
{
throw css::beans::UnknownPropertyException(
(rtl::OUString("name ")
+ props[i].Name
+ rtl::OUString(" does not match handle ")
+ rtl::OUString::number(props[i].Handle)),
static_cast< css::beans::XPropertySet * >(this));
}
m_impl->setProperty(
static_cast< css::beans::XPropertySet * >(this), props[i].Name,
props[i].Value,
props[i].State == css::beans::PropertyState_AMBIGUOUS_VALUE,
props[i].State == css::beans::PropertyState_DEFAULT_VALUE, 0);
}
} catch (std::bad_alloc &) {
//TODO OutOfMemoryException:
throw css::uno::RuntimeException(
rtl::OUString(), static_cast< css::beans::XPropertySet * >(this));
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */