Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  propertysetmixin.cxx   Sprache: 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 <algorithm>
#include <cassert>
#include <map>
#include <mutex>
#include <set>
#include <utility>
#include <vector>

#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/reflection/XCompoundTypeDescription.hpp>
#include <com/sun/star/reflection/XIdlClass.hpp>
#include <com/sun/star/reflection/XIdlField2.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/reflection/theCoreReflection.hpp>
#include <com/sun/star/uno/Any.hxx>
#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 <cppu/unotype.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/propertysetmixin.hxx>
#include <cppuhelper/weak.hxx>
#include <rtl/ref.hxx>
#include <rtl/ustring.hxx>
#include <sal/types.h>
#include <salhelper/simplereferenceobject.hxx>

using cppu::PropertySetMixinImpl;

namespace {

struct PropertyData {
    explicit PropertyData(
        css::beans::Property theProperty, bool thePresent):
        property(std::move(theProperty)), present(thePresent) {}

    css::beans::Property property;
    bool present;
};

struct Data: public salhelper::SimpleReferenceObject {
    typedef std::map< OUString, PropertyData > PropertyMap;

    PropertyMap properties;

    PropertyMap::const_iterator get(
        css::uno::Reference< css::uno::XInterface > const & object,
        OUString const & name) const;

protected:
    void initProperties(
        css::uno::Reference< css::reflection::XTypeDescription > const & type,
        css::uno::Sequence< OUString > const & absentOptional,
        std::vector< OUString > * handleNames)
    {
        std::set<OUString> seen;
        initProperties(type, absentOptional, handleNames, &seen);
    }

private:
    void initProperties(
        css::uno::Reference< css::reflection::XTypeDescription > const & type,
        css::uno::Sequence< OUString > const & absentOptional,
        std::vector< OUString > * handleNames, std::set<OUString> * 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,
    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< OUString > const & absentOptional,
    std::vector< OUString > * handleNames, std::set<OUString> * seen)
{
    css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > ifc(
        resolveTypedefs(type), css::uno::UNO_QUERY_THROW);
    if (!seen->insert(ifc->getName()).second)
        return;

    const css::uno::Sequence<
        css::uno::Reference< css::reflection::XTypeDescription > > bases(
        ifc->getBaseTypes());
    for (const auto & i : bases) {
        initProperties(i, absentOptional, handleNames, seen);
    }
    const css::uno::Sequence<
        css::uno::Reference<
            css::reflection::XInterfaceMemberTypeDescription > > members(
        ifc->getMembers());
    for (const auto & m : members) {
        if (m->getTypeClass()
            == css::uno::TypeClass_INTERFACE_ATTRIBUTE)
        {
            css::uno::Reference<
            css::reflection::XInterfaceAttributeTypeDescription2 > attr(
                m, css::uno::UNO_QUERY_THROW);
            sal_Int16 attrAttribs = 0;
            if (attr->isBound()) {
                attrAttribs |= css::beans::PropertyAttribute::BOUND;
            }
            bool bSetUnknown = false;
            if (attr->isReadOnly()) {
                attrAttribs |= css::beans::PropertyAttribute::READONLY;
                bSetUnknown = true;
            }
            css::uno::Sequence<
            css::uno::Reference<
            css::reflection::XCompoundTypeDescription > > excs(
                attr->getGetExceptions());
            bool bGetUnknown = false;
            //XXX  Special interpretation of getter/setter exceptions only
            // works if the specified exceptions are of the exact type, not
            // of a supertype:
            for (const auto & ex : excs) {
                if ( ex->getName() == "com.sun.star.beans.UnknownPropertyException" )
                {
                    bGetUnknown = true;
                    break;
                }
            }
            excs = attr->getSetExceptions();
            for (const auto & ex : excs) {
                if ( ex->getName() == "com.sun.star.beans.UnknownPropertyException" )
                {
                    bSetUnknown = true;
                } else if ( ex->getName() == "com.sun.star.beans.PropertyVetoException" )
                {
                    attrAttribs
                        |= css::beans::PropertyAttribute::CONSTRAINED;
                }
            }
            if (bGetUnknown && bSetUnknown) {
                attrAttribs |= css::beans::PropertyAttribute::OPTIONAL;
            }
            css::uno::Reference< css::reflection::XTypeDescription > t(
                attr->getType());
            for (;;)
            {
                t = resolveTypedefs(t);
                sal_Int16 n;
                if (t->getName().startsWith(
                        "com.sun.star.beans.Ambiguous<"))
                {
                    n = css::beans::PropertyAttribute::MAYBEAMBIGUOUS;
                } else if (t->getName().startsWith(
                               "com.sun.star.beans.Defaulted<"))
                {
                    n = css::beans::PropertyAttribute::MAYBEDEFAULT;
                } else if (t->getName().startsWith(
                               "com.sun.star.beans.Optional<"))
                {
                    n = css::beans::PropertyAttribute::MAYBEVOID;
                } else {
                    break;
                }
                if ((attrAttribs & n) != 0) {
                    break;
                }
                attrAttribs |= n;
                const 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(
                        u"inconsistent UNO type registry"_ustr);
                }
                t = args[0];
            }
            std::vector< OUString >::size_type handles
                = handleNames->size();
            if (handles > SAL_MAX_INT32) {
                throw css::uno::RuntimeException(
                    u"interface type has too many attributes"_ustr);
            }
            OUString name(m->getMemberName());
            if (!properties.emplace(
                        name,
                        PropertyData(
                            css::beans::Property(
                                name, static_cast< sal_Int32 >(handles),
                                css::uno::Type(
                                    t->getTypeClass(), t->getName()),
                                attrAttribs),
                            (std::find(absentOptional.begin(), absentOptional.end(), name)
                             == absentOptional.end()))).
                second)
            {
                throw css::uno::RuntimeException(
                    u"inconsistent UNO type registry"_ustr);
            }
            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::WeakImplHelper< css::beans::XPropertySetInfo > {
public:
    explicit Info(Data * data): m_data(data) {}

    virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties() override;

    virtual css::beans::Property SAL_CALL getPropertyByName(
        OUString const & name) override;

    virtual sal_Bool SAL_CALL hasPropertyByName(OUString const & name) override;

private:
    rtl::Reference< Data > m_data;
};

css::uno::Sequence< css::beans::Property > Info::getProperties()
{
    assert(m_data->properties.size() <= SAL_MAX_INT32);
    css::uno::Sequence< css::beans::Property > s(
        static_cast< sal_Int32 >(m_data->properties.size()));
    auto r = asNonConstRange(s);
    sal_Int32 n = 0;
    for (const auto& rEntry : m_data->properties)
    {
        if (rEntry.second.present) {
            r[n++] = rEntry.second.property;
        }
    }
    s.realloc(n);
    return s;
}

css::beans::Property Info::getPropertyByName(OUString const & name)
{
    return m_data->get(static_cast< cppu::OWeakObject * >(this), name)->
        second.property;
}

sal_Bool Info::hasPropertyByName(OUString const & name)
{
    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 (const auto& rxListener : m_impl->specificListeners)
    {
        try {
            rxListener->propertyChange(m_impl->event);
        } catch (css::lang::DisposedException &) {}
    }
    for (const auto& rxListener : m_impl->unspecificListeners)
    {
        try {
            rxListener->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< OUString > const & absentOptional,
        css::uno::Type const & type);

    OUString const & translateHandle(
        css::uno::Reference< css::uno::XInterface > const & object,
        sal_Int32 handle) const;

    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::Any getProperty(
        css::uno::Reference< css::uno::XInterface > const & object,
        OUString const & name, css::beans::PropertyState * state) const;

    PropertySetMixinImpl::Implements implements;
    css::uno::Sequence< OUString > handleMap;

    typedef std::map< OUString, BoundListenerBag > BoundListenerMap;

    typedef
    std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > >
    VetoListenerBag;

    typedef std::map< OUString, VetoListenerBag > VetoListenerMap;

    mutable std::mutex mutex;
    BoundListenerMap boundListeners;
    VetoListenerMap vetoListeners;
    bool disposed;

private:
    css::uno::Reference< css::reflection::XIdlClass > getReflection(
        OUString const & typeNameconst;

    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::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< OUString > const & absentOptional,
    css::uno::Type const & type):
    implements(theImplements), disposed(false), m_context(context),
    m_type(type)
{
    assert(context.is());
    assert(
        (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.set(
            css::uno::Reference< css::container::XHierarchicalNameAccess >(
                m_context->getValueByName(
                    u"/singletons/com.sun.star.reflection."
                    "theTypeDescriptionManager"_ustr),
                css::uno::UNO_QUERY_THROW)->getByHierarchicalName(
                    m_type.getTypeName()),
            css::uno::UNO_QUERY_THROW);
    } catch (css::container::NoSuchElementException & e) {
        css::uno::Any anyEx = cppu::getCaughtException();
        throw css::lang::WrappedTargetRuntimeException(
            "unexpected com.sun.star.container.NoSuchElementException: "
             + e.Message,
             nullptr, anyEx );
    }
    std::vector< OUString > handleNames;
    initProperties(ifc, absentOptional, &handleNames);
    std::vector< OUString >::size_type size = handleNames.size();
    assert(size <= SAL_MAX_INT32);
    handleMap.realloc(static_cast< sal_Int32 >(size));
    std::copy(handleNames.begin(), handleNames.end(), handleMap.getArray());
}

OUString const & 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(
            "bad handle " + OUString::number(handle), object);
    }
    return handleMap[handle];
}

void PropertySetMixinImpl::Impl::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
{
    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(
            ("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 {
            css::uno::Any anyEx = cppu::getCaughtException();
            throw css::lang::WrappedTargetRuntimeException(
                "unexpected com.sun.star.lang.IllegalArgumentException: "
                 + e.Message,
                object, anyEx );
        }
    } 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(
            "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(
                cppu::UnoType<css::beans::UnknownPropertyException>::get())
            && ((i->second.property.Attributes
                 & css::beans::PropertyAttribute::OPTIONAL)
                != 0))
        {
            throw css::beans::UnknownPropertyException(name, object);
        } else if (e.TargetException.isExtractableTo(
                       cppu::UnoType<css::beans::PropertyVetoException>::get())
                   && ((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,
    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) {
        css::uno::Any anyEx = cppu::getCaughtException();
        throw css::lang::WrappedTargetRuntimeException(
            "unexpected com.sun.star.lang.IllegalArgumentException: "
             + e.Message,
             object, anyEx );
    } 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(
                cppu::UnoType<css::beans::UnknownPropertyException>::get())
            && ((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().startsWith(
                "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(u"IsAmbiguous"_ustr),
                          css::uno::UNO_QUERY_THROW)->get(value)
                      >>= isAmbiguous))
                {
                    throw css::uno::RuntimeException(
                        (u"unexpected type of com.sun.star.beans.Ambiguous"
                         " IsAmbiguous member"_ustr),
                        object);
                }
                value = css::uno::Reference< css::reflection::XIdlField2 >(
                    ambiguous->getField(u"Value"_ustr), css::uno::UNO_QUERY_THROW)->
                    get(value);
            } catch (css::lang::IllegalArgumentException & e) {
                css::uno::Any anyEx = cppu::getCaughtException();
                throw css::lang::WrappedTargetRuntimeException(
                    "unexpected com.sun.star.lang.IllegalArgumentException: "
                     + e.Message,
                     object, anyEx );
            }
            undoAmbiguous = false;
        } else if (undoDefaulted
                   && value.getValueTypeName().startsWith(
                       "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(u"IsDefaulted"_ustr),
                          css::uno::UNO_QUERY_THROW)->get(value)
                      >>= isDefaulted))
                {
                    throw css::uno::RuntimeException(
                        (u"unexpected type of com.sun.star.beans.Defaulted"
                         " IsDefaulted member"_ustr),
                        object);
                }
                value = css::uno::Reference< css::reflection::XIdlField2 >(
                    defaulted->getField(u"Value"_ustr), css::uno::UNO_QUERY_THROW)->
                    get(value);
            } catch (css::lang::IllegalArgumentException & e) {
                css::uno::Any anyEx = cppu::getCaughtException();
                throw css::lang::WrappedTargetRuntimeException(
                    "unexpected com.sun.star.lang.IllegalArgumentException: "
                     + e.Message,
                    object, anyEx );
            }
            undoDefaulted = false;
        } else if (undoOptional
                   && value.getValueTypeName().startsWith(
                       "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(u"IsPresent"_ustr),
                          css::uno::UNO_QUERY_THROW)->get(value)
                      >>= present))
                {
                    throw css::uno::RuntimeException(
                        (u"unexpected type of com.sun.star.beans.Optional"
                         " IsPresent member"_ustr),
                        object);
                }
                if (!present) {
                    value.clear();
                    break;
                }
                value = css::uno::Reference< css::reflection::XIdlField2 >(
                    optional->getField(u"Value"_ustr), css::uno::UNO_QUERY_THROW)->
                    get(value);
            } catch (css::lang::IllegalArgumentException & e) {
                css::uno::Any anyEx = cppu::getCaughtException();
                throw css::lang::WrappedTargetRuntimeException(
                    "unexpected com.sun.star.lang.IllegalArgumentException: "
                     + e.Message,
                     object, anyEx );
            }
            undoOptional = false;
        } else {
            throw css::uno::RuntimeException(
                "unexpected type of attribute " + name, object);
        }
    }
    if (state != nullptr) {
        //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(OUString const & typeNameconst
{
    return css::uno::Reference< css::reflection::XIdlClass >(
        css::reflection::theCoreReflection::get(m_context)->forName(typeName),
        css::uno::UNO_SET_THROW);
}

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)
{
    assert(wrapAmbiguous || !isAmbiguous);
    assert(wrapDefaulted || !isDefaulted);
    if (wrapAmbiguous
        && type->getName().startsWith("com.sun.star.beans.Ambiguous<"))
    {
        css::uno::Any strct;
        type->createObject(strct);
        try {
            css::uno::Reference< css::reflection::XIdlField2 > field(
                type->getField(u"Value"_ustr), css::uno::UNO_QUERY_THROW);
            field->set(
                strct,
                wrapValue(
                    object, value, field->getType(), falsefalse,
                    wrapDefaulted, isDefaulted, wrapOptional));
            css::uno::Reference< css::reflection::XIdlField2 >(
                type->getField(u"IsAmbiguous"_ustr), css::uno::UNO_QUERY_THROW)->set(
                    strct, css::uno::Any(isAmbiguous));
        } catch (css::lang::IllegalArgumentException & e) {
            css::uno::Any anyEx = cppu::getCaughtException();
            throw css::lang::WrappedTargetRuntimeException(
                "unexpected com.sun.star.lang.IllegalArgumentException: "
                 + e.Message,
                 object, anyEx );
        } catch (css::lang::IllegalAccessException & e) {
            css::uno::Any anyEx = cppu::getCaughtException();
            throw css::lang::WrappedTargetRuntimeException(
                "unexpected com.sun.star.lang.IllegalAccessException: "
                 + e.Message,
                 object, anyEx );
        }
        return strct;
    }
    if (wrapDefaulted
               && type->getName().startsWith("com.sun.star.beans.Defaulted<"))
    {
        css::uno::Any strct;
        type->createObject(strct);
        try {
            css::uno::Reference< css::reflection::XIdlField2 > field(
                type->getField(u"Value"_ustr), css::uno::UNO_QUERY_THROW);
            field->set(
                strct,
                wrapValue(
                    object, value, field->getType(), wrapAmbiguous, isAmbiguous,
                    falsefalse, wrapOptional));
            css::uno::Reference< css::reflection::XIdlField2 >(
                type->getField(u"IsDefaulted"_ustr), css::uno::UNO_QUERY_THROW)->set(
                    strct, css::uno::Any(isDefaulted));
        } catch (css::lang::IllegalArgumentException & e) {
            css::uno::Any anyEx = cppu::getCaughtException();
            throw css::lang::WrappedTargetRuntimeException(
                "unexpected com.sun.star.lang.IllegalArgumentException: "
                 + e.Message,
                 object, anyEx );
        } catch (css::lang::IllegalAccessException & e) {
            css::uno::Any anyEx = cppu::getCaughtException();
            throw css::lang::WrappedTargetRuntimeException(
                "unexpected com.sun.star.lang.IllegalAccessException: "
                 + e.Message,
                 object, anyEx );
        }
        return strct;
    }
    if (wrapOptional
               && type->getName().startsWith("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(u"IsPresent"_ustr), css::uno::UNO_QUERY_THROW)->set(
                    strct, css::uno::Any(present));
            if (present) {
                css::uno::Reference< css::reflection::XIdlField2 > field(
                    type->getField(u"Value"_ustr), css::uno::UNO_QUERY_THROW);
                field->set(
                    strct,
                    wrapValue(
                        object, value, field->getType(), wrapAmbiguous,
                        isAmbiguous, wrapDefaulted, isDefaulted, false));
            }
        } catch (css::lang::IllegalArgumentException & e) {
            css::uno::Any anyEx = cppu::getCaughtException();
            throw css::lang::WrappedTargetRuntimeException(
                "unexpected com.sun.star.lang.IllegalArgumentException: "
                 + e.Message,
                 object, anyEx );
        } catch (css::lang::IllegalAccessException & e) {
            css::uno::Any anyEx = cppu::getCaughtException();
            throw css::lang::WrappedTargetRuntimeException(
                "unexpected com.sun.star.lang.IllegalAccessException: "
                 + e.Message,
                object, anyEx );
        }
        return strct;
    }
    if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
        throw css::uno::RuntimeException(
            u"unexpected type of attribute"_ustr, object);
    }
    return value;
}

PropertySetMixinImpl::PropertySetMixinImpl(
    css::uno::Reference< css::uno::XComponentContext > const & context,
    Implements implements,
    css::uno::Sequence< 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(OUString const & propertyName) {
    if (!propertyName.isEmpty()) {
        m_impl->get(
            static_cast< css::beans::XPropertySet * >(this), propertyName);
    }
}

void PropertySetMixinImpl::prepareSet(
    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));
    assert(it != m_impl->properties.end());
    Impl::VetoListenerBag specificVeto;
    Impl::VetoListenerBag unspecificVeto;
    {
        std::scoped_lock g(m_impl->mutex);
        if (m_impl->disposed) {
            throw css::lang::DisposedException(
                u"disposed"_ustr, 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(u""_ustr);
            if (i != m_impl->vetoListeners.end()) {
                unspecificVeto = i->second;
            }
        }
        if ((it->second.property.Attributes
             & css::beans::PropertyAttribute::BOUND)
            != 0)
        {
            assert(boundListeners != nullptr);
            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(u""_ustr);
            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 (auto& rxVetoListener : specificVeto)
        {
            try {
                rxVetoListener->vetoableChange(event);
            } catch (css::lang::DisposedException &) {}
        }
        for (auto& rxVetoListener : unspecificVeto)
        {
            try {
                rxVetoListener->vetoableChange(event);
            } catch (css::lang::DisposedException &) {}
        }
    }
    if ((it->second.property.Attributes & css::beans::PropertyAttribute::BOUND)
        != 0)
    {
        assert(boundListeners != nullptr);
        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;
    {
        std::scoped_lock 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 (const auto& rEntry : boundListeners)
    {
        for (auto& rxBoundListener : rEntry.second)
        {
            rxBoundListener->disposing(event);
        }
    }
    for (const auto& rEntry : vetoListeners)
    {
        for (auto& rxVetoListener : rEntry.second)
        {
            rxVetoListener->disposing(event);
        }
    }
}

css::uno::Any PropertySetMixinImpl::queryInterface(css::uno::Type const & type)
{
    if ((m_impl->implements & IMPLEMENTS_PROPERTY_SET) != 0
         && type == cppu::UnoType<css::beans::XPropertySet>::get())
    {
        css::uno::Reference< css::uno::XInterface > ifc(
            static_cast< css::beans::XPropertySet * >(this));
        return css::uno::Any(&ifc, type);
    }
    if ((m_impl->implements & IMPLEMENTS_FAST_PROPERTY_SET) != 0
               && type == cppu::UnoType<css::beans::XFastPropertySet>::get())
    {
        css::uno::Reference< css::uno::XInterface > ifc(
            static_cast< css::beans::XFastPropertySet * >(this));
        return css::uno::Any(&ifc, type);
    }
    if ((m_impl->implements & IMPLEMENTS_PROPERTY_ACCESS) != 0
               && type == cppu::UnoType<css::beans::XPropertyAccess>::get())
    {
        css::uno::Reference< css::uno::XInterface > ifc(
            static_cast< css::beans::XPropertyAccess * >(this));
        return css::uno::Any(&ifc, type);
    }
    return css::uno::Any();
}

css::uno::Reference< css::beans::XPropertySetInfo >
PropertySetMixinImpl::getPropertySetInfo()
{
    return new Info(m_impl);
}

void PropertySetMixinImpl::setPropertyValue(
    OUString const & propertyName, css::uno::Any const & value)
{
    m_impl->setProperty(
        static_cast< css::beans::XPropertySet * >(this), propertyName, value,
        falsefalse, 1);
}

css::uno::Any PropertySetMixinImpl::getPropertyValue(
    OUString const & propertyName)
{
    return m_impl->getProperty(
        static_cast< css::beans::XPropertySet * >(this), propertyName, nullptr);
}

void PropertySetMixinImpl::addPropertyChangeListener(
    OUString const & propertyName,
    css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
{
    css::uno::Reference< css::beans::XPropertyChangeListener >(
        listener, css::uno::UNO_SET_THROW); // reject NULL listener
    checkUnknown(propertyName);
    bool disposed;
    {
        std::scoped_lock 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)));
    }
}

void PropertySetMixinImpl::removePropertyChangeListener(
    OUString const & propertyName,
    css::uno::Reference< css::beans::XPropertyChangeListener > const & listener)
{
    assert(listener.is());
    checkUnknown(propertyName);
    std::scoped_lock 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);
        }
    }
}

void PropertySetMixinImpl::addVetoableChangeListener(
    OUString const & propertyName,
    css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
{
    css::uno::Reference< css::beans::XVetoableChangeListener >(
        listener, css::uno::UNO_SET_THROW); // reject NULL listener
    checkUnknown(propertyName);
    bool disposed;
    {
        std::scoped_lock 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)));
    }
}

void PropertySetMixinImpl::removeVetoableChangeListener(
    OUString const & propertyName,
    css::uno::Reference< css::beans::XVetoableChangeListener > const & listener)
{
    assert(listener.is());
    checkUnknown(propertyName);
    std::scoped_lock 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);
        }
    }
}

void PropertySetMixinImpl::setFastPropertyValue(
    sal_Int32 handle, css::uno::Any const & value)
{
    m_impl->setProperty(
        static_cast< css::beans::XPropertySet * >(this),
        m_impl->translateHandle(
            static_cast< css::beans::XPropertySet * >(this), handle),
        value, falsefalse, 1);
}

css::uno::Any PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle)
{
    return m_impl->getProperty(
        static_cast< css::beans::XPropertySet * >(this),
        m_impl->translateHandle(
            static_cast< css::beans::XPropertySet * >(this), handle),
        nullptr);
}

css::uno::Sequence< css::beans::PropertyValue >
PropertySetMixinImpl::getPropertyValues()
{
    css::uno::Sequence< css::beans::PropertyValue > s(
        m_impl->handleMap.getLength());
    auto r = asNonConstRange(s);
    sal_Int32 n = 0;
    for (sal_Int32 i = 0; i < m_impl->handleMap.getLength(); ++i) {
        try {
            r[n].Value = m_impl->getProperty(
                static_cast< css::beans::XPropertySet * >(this),
                m_impl->handleMap[i], &r[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);
        }
        r[n].Name = m_impl->handleMap[i];
        r[n].Handle = i;
        ++n;
    }
    s.realloc(n);
    return s;
}

void PropertySetMixinImpl::setPropertyValues(
    css::uno::Sequence< css::beans::PropertyValue > const & props)
{
    for (const auto & p : props) {
        if (p.Handle != -1
            && (p.Name
                != m_impl->translateHandle(
                    static_cast< css::beans::XPropertySet * >(this),
                    p.Handle)))
        {
            throw css::beans::UnknownPropertyException(
                ("name " + p.Name + " does not match handle "
                 + OUString::number(p.Handle)),
                static_cast< css::beans::XPropertySet * >(this));
        }
        m_impl->setProperty(
            static_cast< css::beans::XPropertySet * >(this), p.Name,
            p.Value,
            p.State == css::beans::PropertyState_AMBIGUOUS_VALUE,
            p.State == css::beans::PropertyState_DEFAULT_VALUE, 0);
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=94 H=94 G=93

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge