1
0
Fork 0
libreoffice/comphelper/source/property/propshlp.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

857 lines
29 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 <osl/diagnose.h>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/queryinterface.hxx>
#include <comphelper/propshlp.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <memory>
#include <sal/log.hxx>
using namespace com::sun::star::uno;
using namespace com::sun::star::beans;
using namespace com::sun::star::lang;
using namespace cppu;
namespace comphelper
{
extern "C" {
static int compare_OUString_Property_Impl(const void* arg1, const void* arg2) noexcept
{
return static_cast<OUString const*>(arg1)->compareTo(static_cast<Property const*>(arg2)->Name);
}
}
/**
* The class which implements the PropertySetInfo interface.
*/
namespace
{
class OPropertySetHelperInfo_Impl : public WeakImplHelper<css::beans::XPropertySetInfo>
{
Sequence<Property> aInfos;
public:
explicit OPropertySetHelperInfo_Impl(IPropertyArrayHelper& rHelper_);
// XPropertySetInfo-methods
virtual Sequence<Property> SAL_CALL getProperties() override;
virtual Property SAL_CALL getPropertyByName(const OUString& PropertyName) override;
virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& PropertyName) override;
};
}
/**
* Create an object that implements XPropertySetInfo IPropertyArrayHelper.
*/
OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(IPropertyArrayHelper& rHelper_)
: aInfos(rHelper_.getProperties())
{
}
/**
* Return the sequence of properties, which are provided through the constructor.
*/
Sequence<Property> OPropertySetHelperInfo_Impl::getProperties() { return aInfos; }
/**
* Return the sequence of properties, which are provided through the constructor.
*/
Property OPropertySetHelperInfo_Impl::getPropertyByName(const OUString& PropertyName)
{
Property* pR
= static_cast<Property*>(bsearch(&PropertyName, aInfos.getConstArray(), aInfos.getLength(),
sizeof(Property), compare_OUString_Property_Impl));
if (!pR)
throw UnknownPropertyException(PropertyName);
return *pR;
}
/**
* Return the sequence of properties, which are provided through the constructor.
*/
sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName(const OUString& PropertyName)
{
Property* pR
= static_cast<Property*>(bsearch(&PropertyName, aInfos.getConstArray(), aInfos.getLength(),
sizeof(Property), compare_OUString_Property_Impl));
return pR != nullptr;
}
OPropertySetHelper::OPropertySetHelper() {}
OPropertySetHelper::OPropertySetHelper(bool bIgnoreRuntimeExceptionsWhileFiring)
: m_bIgnoreRuntimeExceptionsWhileFiring(bIgnoreRuntimeExceptionsWhileFiring)
{
}
/**
* You must call disposing before.
*/
OPropertySetHelper::~OPropertySetHelper() {}
// XInterface
Any OPropertySetHelper::queryInterface(const css::uno::Type& rType)
{
return ::cppu::queryInterface(rType, static_cast<XPropertySet*>(this),
static_cast<XMultiPropertySet*>(this),
static_cast<XFastPropertySet*>(this));
}
/**
* called from the derivee's XTypeProvider::getTypes implementation
*/
css::uno::Sequence<css::uno::Type> OPropertySetHelper::getTypes()
{
return { UnoType<css::beans::XPropertySet>::get(),
UnoType<css::beans::XMultiPropertySet>::get(),
UnoType<css::beans::XFastPropertySet>::get() };
}
// ComponentHelper
void OPropertySetHelper::disposing(std::unique_lock<std::mutex>& rGuard)
{
// Create an event with this as sender
Reference<XPropertySet> rSource = this;
EventObject aEvt;
aEvt.Source = rSource;
// inform all listeners to release this object
// The listener containers are automatically cleared
aBoundLC.disposeAndClear(rGuard, aEvt);
aVetoableLC.disposeAndClear(rGuard, aEvt);
}
Reference<XPropertySetInfo>
OPropertySetHelper::createPropertySetInfo(IPropertyArrayHelper& rProperties)
{
return new OPropertySetHelperInfo_Impl(rProperties);
}
// XPropertySet
void OPropertySetHelper::setPropertyValue(const OUString& rPropertyName, const Any& rValue)
{
// get the map table
IPropertyArrayHelper& rPH = getInfoHelper();
// map the name to the handle
sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
std::unique_lock aGuard(m_aMutex);
setFastPropertyValueImpl(aGuard, nHandle, rValue);
}
// XPropertySet
Any OPropertySetHelper::getPropertyValue(const OUString& rPropertyName)
{
std::unique_lock aGuard(m_aMutex);
return getPropertyValueImpl(aGuard, rPropertyName);
}
Any OPropertySetHelper::getPropertyValueImpl(std::unique_lock<std::mutex>& rGuard,
const OUString& rPropertyName)
{
// get the map table
IPropertyArrayHelper& rPH = getInfoHelper();
// map the name to the handle
sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
if (nHandle == -1)
throw UnknownPropertyException(rPropertyName);
// call the method of the XFastPropertySet interface
Any aAny;
getFastPropertyValue(rGuard, aAny, nHandle);
return aAny;
}
// XPropertySet
void OPropertySetHelper::addPropertyChangeListener(
const OUString& rPropertyName, const Reference<XPropertyChangeListener>& rxListener)
{
std::unique_lock aGuard(m_aMutex);
OSL_ENSURE(!m_bDisposed, "object is disposed");
if (m_bDisposed)
return;
// only add listeners if you are not disposed
// a listener with no name means all properties
if (!rPropertyName.isEmpty())
{
// get the map table
IPropertyArrayHelper& rPH = getInfoHelper();
// map the name to the handle
sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
if (nHandle == -1)
{
// property not known throw exception
throw UnknownPropertyException(rPropertyName);
}
sal_Int16 nAttributes;
rPH.fillPropertyMembersByHandle(nullptr, &nAttributes, nHandle);
if (!(nAttributes & css::beans::PropertyAttribute::BOUND))
{
OSL_FAIL("add listener to an unbound property");
// silent ignore this
return;
}
// add the change listener to the helper container
aBoundLC.addInterface(aGuard, nHandle, rxListener);
}
else
// add the change listener to the helper container
maPropertyChangeListeners.addInterface(aGuard, rxListener);
}
// XPropertySet
void OPropertySetHelper::removePropertyChangeListener(
const OUString& rPropertyName, const Reference<XPropertyChangeListener>& rxListener)
{
std::unique_lock aGuard(m_aMutex);
OSL_ENSURE(!m_bDisposed, "object is disposed");
// all listeners are automatically released in a dispose call
if (m_bDisposed)
return;
if (!rPropertyName.isEmpty())
{
// get the map table
IPropertyArrayHelper& rPH = getInfoHelper();
// map the name to the handle
sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
if (nHandle == -1)
// property not known throw exception
throw UnknownPropertyException(rPropertyName);
aBoundLC.removeInterface(aGuard, nHandle, rxListener);
}
else
{
// remove the change listener to the helper container
maPropertyChangeListeners.removeInterface(aGuard, rxListener);
}
}
// XPropertySet
void OPropertySetHelper::addVetoableChangeListener(
const OUString& rPropertyName, const Reference<XVetoableChangeListener>& rxListener)
{
std::unique_lock aGuard(m_aMutex);
OSL_ENSURE(!m_bDisposed, "object is disposed");
if (m_bDisposed)
return;
// only add listeners if you are not disposed
// a listener with no name means all properties
if (!rPropertyName.isEmpty())
{
// get the map table
IPropertyArrayHelper& rPH = getInfoHelper();
// map the name to the handle
sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
if (nHandle == -1)
{
// property not known throw exception
throw UnknownPropertyException(rPropertyName);
}
sal_Int16 nAttributes;
rPH.fillPropertyMembersByHandle(nullptr, &nAttributes, nHandle);
if (!(nAttributes & PropertyAttribute::CONSTRAINED))
{
OSL_FAIL("addVetoableChangeListener, and property is not constrained");
// silent ignore this
return;
}
// add the vetoable listener to the helper container
aVetoableLC.addInterface(aGuard, nHandle, rxListener);
}
else
// add the vetoable listener to the helper container
maVetoableChangeListeners.addInterface(aGuard, rxListener);
}
// XPropertySet
void OPropertySetHelper::removeVetoableChangeListener(
const OUString& rPropertyName, const Reference<XVetoableChangeListener>& rxListener)
{
std::unique_lock aGuard(m_aMutex);
OSL_ENSURE(!m_bDisposed, "object is disposed");
// all listeners are automatically released in a dispose call
if (m_bDisposed)
return;
if (!rPropertyName.isEmpty())
{
// get the map table
IPropertyArrayHelper& rPH = getInfoHelper();
// map the name to the handle
sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
if (nHandle == -1)
{
// property not known throw exception
throw UnknownPropertyException(rPropertyName);
}
// remove the vetoable listener to the helper container
aVetoableLC.removeInterface(aGuard, nHandle, rxListener);
}
else
// add the vetoable listener to the helper container
maVetoableChangeListeners.removeInterface(aGuard, rxListener);
}
void OPropertySetHelper::setDependentFastPropertyValue(std::unique_lock<std::mutex>& rGuard,
sal_Int32 i_handle,
const css::uno::Any& i_value)
{
sal_Int16 nAttributes(0);
IPropertyArrayHelper& rInfo = getInfoHelper();
if (!rInfo.fillPropertyMembersByHandle(nullptr, &nAttributes, i_handle))
// unknown property
throw UnknownPropertyException(OUString::number(i_handle));
// no need to check for READONLY-ness of the property. The method is intended to be called internally, which
// implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
// to change their value.
Any aConverted, aOld;
bool bChanged = convertFastPropertyValue(rGuard, aConverted, aOld, i_handle, i_value);
if (!bChanged)
return;
// don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
// a good idea. The caller is responsible for not invoking this for constrained properties.
OSL_ENSURE((nAttributes & PropertyAttribute::CONSTRAINED) == 0,
"OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained "
"properties!");
// actually set the new value
try
{
setFastPropertyValue_NoBroadcast(rGuard, i_handle, aConverted);
}
catch (const UnknownPropertyException&)
{
throw; /* allowed to leave */
}
catch (const PropertyVetoException&)
{
throw; /* allowed to leave */
}
catch (const IllegalArgumentException&)
{
throw; /* allowed to leave */
}
catch (const WrappedTargetException&)
{
throw; /* allowed to leave */
}
catch (const RuntimeException&)
{
throw; /* allowed to leave */
}
catch (const Exception&)
{
// not allowed to leave this method
WrappedTargetException aWrapped;
aWrapped.TargetException = ::cppu::getCaughtException();
aWrapped.Context = static_cast<XPropertySet*>(this);
throw aWrapped;
}
// remember the handle/values, for the events to be fired later
m_handles.push_back(i_handle);
m_newValues.push_back(
aConverted); // TODO: setFastPropertyValue notifies the unconverted value here ...?
m_oldValues.push_back(aOld);
}
// XFastPropertySet
void OPropertySetHelper::setFastPropertyValue(sal_Int32 nHandle, const Any& rValue)
{
std::unique_lock aGuard(m_aMutex);
setFastPropertyValueImpl(aGuard, nHandle, rValue);
}
void OPropertySetHelper::setFastPropertyValueImpl(std::unique_lock<std::mutex>& rGuard,
sal_Int32 nHandle, const Any& rValue)
{
OSL_ENSURE(!m_bDisposed, "object is disposed");
IPropertyArrayHelper& rInfo = getInfoHelper();
sal_Int16 nAttributes;
if (!rInfo.fillPropertyMembersByHandle(nullptr, &nAttributes, nHandle))
{
// unknown property
throw UnknownPropertyException(OUString::number(nHandle));
}
if (nAttributes & PropertyAttribute::READONLY)
throw PropertyVetoException();
Any aConvertedVal;
Any aOldVal;
// Will the property change?
bool bChanged = convertFastPropertyValue(rGuard, aConvertedVal, aOldVal, nHandle, rValue);
if (!bChanged)
return;
// Is it a constrained property?
if (nAttributes & PropertyAttribute::CONSTRAINED)
{
// In aValue is the converted rValue
// fire a constrained event
// second parameter NULL means constrained
fire(rGuard, &nHandle, &rValue, &aOldVal, 1, true);
}
try
{
// set the property to the new value
setFastPropertyValue_NoBroadcast(rGuard, nHandle, aConvertedVal);
}
catch (const css::beans::UnknownPropertyException&)
{
throw; /* allowed to leave */
}
catch (const css::beans::PropertyVetoException&)
{
throw; /* allowed to leave */
}
catch (const css::lang::IllegalArgumentException&)
{
throw; /* allowed to leave */
}
catch (const css::lang::WrappedTargetException&)
{
throw; /* allowed to leave */
}
catch (const css::uno::RuntimeException&)
{
throw; /* allowed to leave */
}
catch (const css::uno::Exception& e)
{
// not allowed to leave this method
css::lang::WrappedTargetException aWrap;
aWrap.Context = static_cast<css::beans::XPropertySet*>(this);
aWrap.TargetException <<= e;
throw aWrap;
}
// file a change event, if the value changed
impl_fireAll(rGuard, &nHandle, &rValue, &aOldVal, 1);
}
// XFastPropertySet
Any OPropertySetHelper::getFastPropertyValue(sal_Int32 nHandle)
{
IPropertyArrayHelper& rInfo = getInfoHelper();
if (!rInfo.fillPropertyMembersByHandle(nullptr, nullptr, nHandle))
// unknown property
throw UnknownPropertyException(OUString::number(nHandle));
Any aRet;
std::unique_lock aGuard(m_aMutex);
getFastPropertyValue(aGuard, aRet, nHandle);
return aRet;
}
void OPropertySetHelper::impl_fireAll(std::unique_lock<std::mutex>& rGuard, sal_Int32* i_handles,
const Any* i_newValues, const Any* i_oldValues,
sal_Int32 i_count)
{
if (m_handles.empty())
{
fire(rGuard, i_handles, i_newValues, i_oldValues, i_count, false);
return;
}
const size_t additionalEvents = m_handles.size();
OSL_ENSURE(additionalEvents == m_newValues.size() && additionalEvents == m_oldValues.size(),
"OPropertySetHelper::impl_fireAll: inconsistency!");
std::vector<sal_Int32> allHandles(additionalEvents + i_count);
std::copy(m_handles.begin(), m_handles.end(), allHandles.begin());
std::copy(i_handles, i_handles + i_count, allHandles.begin() + additionalEvents);
std::vector<Any> allNewValues(additionalEvents + i_count);
std::copy(m_newValues.begin(), m_newValues.end(), allNewValues.begin());
std::copy(i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents);
std::vector<Any> allOldValues(additionalEvents + i_count);
std::copy(m_oldValues.begin(), m_oldValues.end(), allOldValues.begin());
std::copy(i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents);
m_handles.clear();
m_newValues.clear();
m_oldValues.clear();
fire(rGuard, allHandles.data(), allNewValues.data(), allOldValues.data(),
additionalEvents + i_count, false);
}
void OPropertySetHelper::fire(std::unique_lock<std::mutex>& rGuard, sal_Int32* pnHandles,
const Any* pNewValues, const Any* pOldValues,
sal_Int32 nHandles, // This is the Count of the array
bool bVetoable)
{
// Only fire, if one or more properties changed
if (!nHandles)
return;
// create the event sequence of all changed properties
Sequence<PropertyChangeEvent> aEvts(nHandles);
PropertyChangeEvent* pEvts = aEvts.getArray();
Reference<XInterface> xSource(static_cast<XPropertySet*>(this), UNO_QUERY);
sal_Int32 i;
sal_Int32 nChangesLen = 0;
// Loop over all changed properties to fill the event struct
for (i = 0; i < nHandles; i++)
{
// Vetoable fire and constrained attribute set or
// Change fire and Changed and bound attribute set
IPropertyArrayHelper& rInfo = getInfoHelper();
sal_Int16 nAttributes;
OUString aPropName;
rInfo.fillPropertyMembersByHandle(&aPropName, &nAttributes, pnHandles[i]);
if ((bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED))
|| (!bVetoable && (nAttributes & PropertyAttribute::BOUND)))
{
pEvts[nChangesLen].Source = xSource;
pEvts[nChangesLen].PropertyName = aPropName;
pEvts[nChangesLen].PropertyHandle = pnHandles[i];
pEvts[nChangesLen].OldValue = pOldValues[i];
pEvts[nChangesLen].NewValue = pNewValues[i];
nChangesLen++;
}
}
bool bIgnoreRuntimeExceptionsWhileFiring = m_bIgnoreRuntimeExceptionsWhileFiring;
// fire the events for all changed properties
for (i = 0; i < nChangesLen; i++)
{
if (bVetoable) // fire change Events?
fireVetoableChangeListeners(
rGuard, aVetoableLC.getContainer(rGuard, pEvts[i].PropertyHandle), pEvts[i]);
else
// get the listener container for the property name
firePropertyChangeListeners(
rGuard, aBoundLC.getContainer(rGuard, pEvts[i].PropertyHandle), pEvts[i]);
// broadcast to all listeners with "" property name
if (bVetoable)
// fire change Events?
fireVetoableChangeListeners(rGuard, &maVetoableChangeListeners, pEvts[i]);
else
firePropertyChangeListeners(rGuard, &maPropertyChangeListeners, pEvts[i]);
}
// reduce array to changed properties
aEvts.realloc(nChangesLen);
if (bVetoable)
return;
if (!maPropertiesChangeListeners.getLength(rGuard))
return;
// Here is a Bug, unbound properties are also fired
OInterfaceIteratorHelper4 aIt(rGuard, maPropertiesChangeListeners);
rGuard.unlock();
while (aIt.hasMoreElements())
{
XPropertiesChangeListener* pL = aIt.next().get();
try
{
try
{
// fire the whole event sequence to the
// XPropertiesChangeListener's
pL->propertiesChange(aEvts);
}
catch (DisposedException& exc)
{
OSL_ENSURE(exc.Context.is(), "DisposedException without Context!");
if (exc.Context == pL)
{
rGuard.lock();
aIt.remove(rGuard);
rGuard.unlock();
}
else
throw;
}
}
catch (RuntimeException& exc)
{
SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
if (!bIgnoreRuntimeExceptionsWhileFiring)
throw;
}
}
rGuard.lock();
}
void OPropertySetHelper::fireVetoableChangeListeners(
std::unique_lock<std::mutex>& rGuard,
comphelper::OInterfaceContainerHelper4<css::beans::XVetoableChangeListener>* pListeners,
const css::beans::PropertyChangeEvent& rChangeEvent)
{
if (!pListeners || !pListeners->getLength(rGuard))
return;
// Iterate over all listeners and send events
OInterfaceIteratorHelper4 aIt(rGuard, *pListeners);
rGuard.unlock();
while (aIt.hasMoreElements())
{
XVetoableChangeListener* pL = aIt.next().get();
try
{
try
{
pL->vetoableChange(rChangeEvent);
}
catch (DisposedException& exc)
{
OSL_ENSURE(exc.Context.is(), "DisposedException without Context!");
if (exc.Context == pL)
{
rGuard.lock();
aIt.remove(rGuard);
rGuard.unlock();
}
else
throw;
}
}
catch (RuntimeException& exc)
{
SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
if (!m_bIgnoreRuntimeExceptionsWhileFiring)
throw;
}
}
rGuard.lock();
}
void OPropertySetHelper::firePropertyChangeListeners(
std::unique_lock<std::mutex>& rGuard,
comphelper::OInterfaceContainerHelper4<css::beans::XPropertyChangeListener>* pListeners,
const css::beans::PropertyChangeEvent& rChangeEvent)
{
if (!pListeners || !pListeners->getLength(rGuard))
return;
// Iterate over all listeners and send events
OInterfaceIteratorHelper4 aIt(rGuard, *pListeners);
rGuard.unlock();
while (aIt.hasMoreElements())
{
XPropertyChangeListener* pL = aIt.next().get();
try
{
try
{
pL->propertyChange(rChangeEvent);
}
catch (DisposedException& exc)
{
OSL_ENSURE(exc.Context.is(), "DisposedException without Context!");
if (exc.Context == pL)
{
rGuard.lock();
aIt.remove(rGuard);
rGuard.unlock();
}
else
throw;
}
}
catch (RuntimeException& exc)
{
SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
if (!m_bIgnoreRuntimeExceptionsWhileFiring)
throw;
}
}
rGuard.lock();
}
// OPropertySetHelper
void OPropertySetHelper::setFastPropertyValues(std::unique_lock<std::mutex>& rGuard,
sal_Int32 nSeqLen, sal_Int32* pHandles,
const Any* pValues, sal_Int32 nHitCount)
{
OSL_ENSURE(!m_bDisposed, "object is disposed");
// get the map table
IPropertyArrayHelper& rPH = getInfoHelper();
std::unique_ptr<Any[]> pConvertedValues(new Any[nHitCount]);
std::unique_ptr<Any[]> pOldValues(new Any[nHitCount]);
sal_Int32 n = 0;
sal_Int32 i;
for (i = 0; i < nSeqLen; i++)
{
if (pHandles[i] != -1)
{
sal_Int16 nAttributes;
rPH.fillPropertyMembersByHandle(nullptr, &nAttributes, pHandles[i]);
if (nAttributes & PropertyAttribute::READONLY)
throw PropertyVetoException();
// Will the property change?
if (convertFastPropertyValue(rGuard, pConvertedValues[n], pOldValues[n], pHandles[i],
pValues[i]))
{
// only increment if the property really change
pHandles[n] = pHandles[i];
n++;
}
}
}
// fire vetoable events
fire(rGuard, pHandles, pConvertedValues.get(), pOldValues.get(), n, true);
// Loop over all changed properties
for (i = 0; i < n; i++)
{
// Will the property change?
setFastPropertyValue_NoBroadcast(rGuard, pHandles[i], pConvertedValues[i]);
}
// fire change events
impl_fireAll(rGuard, pHandles, pConvertedValues.get(), pOldValues.get(), n);
}
// XMultiPropertySet
/**
* The sequence may be contain not known properties. The implementation
* must ignore these properties.
*/
void OPropertySetHelper::setPropertyValues(const Sequence<OUString>& rPropertyNames,
const Sequence<Any>& rValues)
{
sal_Int32 nSeqLen = rPropertyNames.getLength();
if (nSeqLen != rValues.getLength())
throw IllegalArgumentException(u"lengths do not match"_ustr,
static_cast<XPropertySet*>(this), -1);
std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nSeqLen]);
// get the map table
IPropertyArrayHelper& rPH = getInfoHelper();
// fill the handle array
sal_Int32 nHitCount = rPH.fillHandles(pHandles.get(), rPropertyNames);
if (nHitCount == 0)
return;
std::unique_lock aGuard(m_aMutex);
setFastPropertyValues(aGuard, nSeqLen, pHandles.get(), rValues.getConstArray(), nHitCount);
}
// XMultiPropertySet
Sequence<Any> OPropertySetHelper::getPropertyValues(const Sequence<OUString>& rPropertyNames)
{
sal_Int32 nSeqLen = rPropertyNames.getLength();
std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nSeqLen]);
Sequence<Any> aValues(nSeqLen);
// get the map table
IPropertyArrayHelper& rPH = getInfoHelper();
// fill the handle array
rPH.fillHandles(pHandles.get(), rPropertyNames);
Any* pValues = aValues.getArray();
std::unique_lock aGuard(m_aMutex);
// fill the sequence with the values
for (sal_Int32 i = 0; i < nSeqLen; i++)
getFastPropertyValue(aGuard, pValues[i], pHandles[i]);
return aValues;
}
// XMultiPropertySet
void OPropertySetHelper::addPropertiesChangeListener(
const Sequence<OUString>&, const Reference<XPropertiesChangeListener>& rListener)
{
std::unique_lock g(m_aMutex);
maPropertiesChangeListeners.addInterface(g, rListener);
}
// XMultiPropertySet
void OPropertySetHelper::removePropertiesChangeListener(
const Reference<XPropertiesChangeListener>& rListener)
{
std::unique_lock g(m_aMutex);
maPropertiesChangeListeners.removeInterface(g, rListener);
}
// XMultiPropertySet
void OPropertySetHelper::firePropertiesChangeEvent(
const Sequence<OUString>& rPropertyNames, const Reference<XPropertiesChangeListener>& rListener)
{
sal_Int32 nLen = rPropertyNames.getLength();
std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nLen]);
IPropertyArrayHelper& rPH = getInfoHelper();
rPH.fillHandles(pHandles.get(), rPropertyNames);
// get the count of matching properties
sal_Int32 nFireLen = 0;
sal_Int32 i;
for (i = 0; i < nLen; i++)
if (pHandles[i] != -1)
nFireLen++;
Sequence<PropertyChangeEvent> aChanges(nFireLen);
PropertyChangeEvent* pChanges = aChanges.getArray();
{
// must lock the mutex outside the loop. So all values are consistent.
std::unique_lock aGuard(m_aMutex);
Reference<XInterface> xSource(static_cast<XPropertySet*>(this), UNO_QUERY);
sal_Int32 nFirePos = 0;
for (i = 0; i < nLen; i++)
{
if (pHandles[i] != -1)
{
pChanges[nFirePos].Source = xSource;
pChanges[nFirePos].PropertyName = rPropertyNames[i];
pChanges[nFirePos].PropertyHandle = pHandles[i];
getFastPropertyValue(aGuard, pChanges[nFirePos].OldValue, pHandles[i]);
pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue;
nFirePos++;
}
}
// release guard to fire events
}
if (nFireLen)
rListener->propertiesChange(aChanges);
}
UnoImplBase::~UnoImplBase() {}
} // end namespace comphelper
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */