Add a comment to clarify what kind of inputs the class handles
[LibreOffice.git] / comphelper / source / property / propshlp.cxx
blobffefa93e65c07c7c12ff31ab5ba6e865f3e677ed
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/diagnose.h>
21 #include <cppuhelper/implbase.hxx>
22 #include <cppuhelper/queryinterface.hxx>
23 #include <comphelper/propshlp.hxx>
24 #include <cppuhelper/exc_hlp.hxx>
25 #include <com/sun/star/beans/PropertyAttribute.hpp>
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <com/sun/star/lang/IllegalArgumentException.hpp>
28 #include <memory>
29 #include <sal/log.hxx>
31 using namespace com::sun::star::uno;
32 using namespace com::sun::star::beans;
33 using namespace com::sun::star::lang;
34 using namespace cppu;
36 namespace comphelper
38 extern "C" {
40 static int compare_OUString_Property_Impl(const void* arg1, const void* arg2) noexcept
42 return static_cast<OUString const*>(arg1)->compareTo(static_cast<Property const*>(arg2)->Name);
46 /**
47 * The class which implements the PropertySetInfo interface.
50 namespace
52 class OPropertySetHelperInfo_Impl : public WeakImplHelper<css::beans::XPropertySetInfo>
54 Sequence<Property> aInfos;
56 public:
57 explicit OPropertySetHelperInfo_Impl(IPropertyArrayHelper& rHelper_);
59 // XPropertySetInfo-methods
60 virtual Sequence<Property> SAL_CALL getProperties() override;
61 virtual Property SAL_CALL getPropertyByName(const OUString& PropertyName) override;
62 virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& PropertyName) override;
66 /**
67 * Create an object that implements XPropertySetInfo IPropertyArrayHelper.
69 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(IPropertyArrayHelper& rHelper_)
70 : aInfos(rHelper_.getProperties())
74 /**
75 * Return the sequence of properties, which are provided through the constructor.
77 Sequence<Property> OPropertySetHelperInfo_Impl::getProperties() { return aInfos; }
79 /**
80 * Return the sequence of properties, which are provided through the constructor.
82 Property OPropertySetHelperInfo_Impl::getPropertyByName(const OUString& PropertyName)
84 Property* pR
85 = static_cast<Property*>(bsearch(&PropertyName, aInfos.getConstArray(), aInfos.getLength(),
86 sizeof(Property), compare_OUString_Property_Impl));
87 if (!pR)
88 throw UnknownPropertyException(PropertyName);
90 return *pR;
93 /**
94 * Return the sequence of properties, which are provided through the constructor.
96 sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName(const OUString& PropertyName)
98 Property* pR
99 = static_cast<Property*>(bsearch(&PropertyName, aInfos.getConstArray(), aInfos.getLength(),
100 sizeof(Property), compare_OUString_Property_Impl));
101 return pR != nullptr;
104 OPropertySetHelper::OPropertySetHelper() {}
106 OPropertySetHelper::OPropertySetHelper(bool bIgnoreRuntimeExceptionsWhileFiring)
107 : m_bIgnoreRuntimeExceptionsWhileFiring(bIgnoreRuntimeExceptionsWhileFiring)
112 * You must call disposing before.
114 OPropertySetHelper::~OPropertySetHelper() {}
116 // XInterface
117 Any OPropertySetHelper::queryInterface(const css::uno::Type& rType)
119 return ::cppu::queryInterface(rType, static_cast<XPropertySet*>(this),
120 static_cast<XMultiPropertySet*>(this),
121 static_cast<XFastPropertySet*>(this));
125 * called from the derivee's XTypeProvider::getTypes implementation
127 css::uno::Sequence<css::uno::Type> OPropertySetHelper::getTypes()
129 return { UnoType<css::beans::XPropertySet>::get(),
130 UnoType<css::beans::XMultiPropertySet>::get(),
131 UnoType<css::beans::XFastPropertySet>::get() };
134 // ComponentHelper
135 void OPropertySetHelper::disposing(std::unique_lock<std::mutex>& rGuard)
137 // Create an event with this as sender
138 Reference<XPropertySet> rSource = this;
139 EventObject aEvt;
140 aEvt.Source = rSource;
142 // inform all listeners to release this object
143 // The listener containers are automatically cleared
144 aBoundLC.disposeAndClear(rGuard, aEvt);
145 aVetoableLC.disposeAndClear(rGuard, aEvt);
148 Reference<XPropertySetInfo>
149 OPropertySetHelper::createPropertySetInfo(IPropertyArrayHelper& rProperties)
151 return new OPropertySetHelperInfo_Impl(rProperties);
154 // XPropertySet
155 void OPropertySetHelper::setPropertyValue(const OUString& rPropertyName, const Any& rValue)
157 // get the map table
158 IPropertyArrayHelper& rPH = getInfoHelper();
159 // map the name to the handle
160 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
161 std::unique_lock aGuard(m_aMutex);
162 setFastPropertyValueImpl(aGuard, nHandle, rValue);
165 // XPropertySet
166 Any OPropertySetHelper::getPropertyValue(const OUString& rPropertyName)
168 std::unique_lock aGuard(m_aMutex);
169 return getPropertyValueImpl(aGuard, rPropertyName);
172 Any OPropertySetHelper::getPropertyValueImpl(std::unique_lock<std::mutex>& rGuard,
173 const OUString& rPropertyName)
175 // get the map table
176 IPropertyArrayHelper& rPH = getInfoHelper();
177 // map the name to the handle
178 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
179 if (nHandle == -1)
180 throw UnknownPropertyException(rPropertyName);
181 // call the method of the XFastPropertySet interface
182 Any aAny;
183 getFastPropertyValue(rGuard, aAny, nHandle);
184 return aAny;
187 // XPropertySet
188 void OPropertySetHelper::addPropertyChangeListener(
189 const OUString& rPropertyName, const Reference<XPropertyChangeListener>& rxListener)
191 std::unique_lock aGuard(m_aMutex);
192 OSL_ENSURE(!m_bDisposed, "object is disposed");
193 if (m_bDisposed)
194 return;
196 // only add listeners if you are not disposed
197 // a listener with no name means all properties
198 if (!rPropertyName.isEmpty())
200 // get the map table
201 IPropertyArrayHelper& rPH = getInfoHelper();
202 // map the name to the handle
203 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
204 if (nHandle == -1)
206 // property not known throw exception
207 throw UnknownPropertyException(rPropertyName);
210 sal_Int16 nAttributes;
211 rPH.fillPropertyMembersByHandle(nullptr, &nAttributes, nHandle);
212 if (!(nAttributes & css::beans::PropertyAttribute::BOUND))
214 OSL_FAIL("add listener to an unbound property");
215 // silent ignore this
216 return;
218 // add the change listener to the helper container
219 aBoundLC.addInterface(aGuard, nHandle, rxListener);
221 else
222 // add the change listener to the helper container
223 maPropertyChangeListeners.addInterface(aGuard, rxListener);
226 // XPropertySet
227 void OPropertySetHelper::removePropertyChangeListener(
228 const OUString& rPropertyName, const Reference<XPropertyChangeListener>& rxListener)
230 std::unique_lock aGuard(m_aMutex);
231 OSL_ENSURE(!m_bDisposed, "object is disposed");
232 // all listeners are automatically released in a dispose call
233 if (m_bDisposed)
234 return;
236 if (!rPropertyName.isEmpty())
238 // get the map table
239 IPropertyArrayHelper& rPH = getInfoHelper();
240 // map the name to the handle
241 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
242 if (nHandle == -1)
243 // property not known throw exception
244 throw UnknownPropertyException(rPropertyName);
245 aBoundLC.removeInterface(aGuard, nHandle, rxListener);
247 else
249 // remove the change listener to the helper container
250 maPropertyChangeListeners.removeInterface(aGuard, rxListener);
254 // XPropertySet
255 void OPropertySetHelper::addVetoableChangeListener(
256 const OUString& rPropertyName, const Reference<XVetoableChangeListener>& rxListener)
258 std::unique_lock aGuard(m_aMutex);
259 OSL_ENSURE(!m_bDisposed, "object is disposed");
260 if (m_bDisposed)
261 return;
263 // only add listeners if you are not disposed
264 // a listener with no name means all properties
265 if (!rPropertyName.isEmpty())
267 // get the map table
268 IPropertyArrayHelper& rPH = getInfoHelper();
269 // map the name to the handle
270 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
271 if (nHandle == -1)
273 // property not known throw exception
274 throw UnknownPropertyException(rPropertyName);
277 sal_Int16 nAttributes;
278 rPH.fillPropertyMembersByHandle(nullptr, &nAttributes, nHandle);
279 if (!(nAttributes & PropertyAttribute::CONSTRAINED))
281 OSL_FAIL("addVetoableChangeListener, and property is not constrained");
282 // silent ignore this
283 return;
285 // add the vetoable listener to the helper container
286 aVetoableLC.addInterface(aGuard, nHandle, rxListener);
288 else
289 // add the vetoable listener to the helper container
290 maVetoableChangeListeners.addInterface(aGuard, rxListener);
293 // XPropertySet
294 void OPropertySetHelper::removeVetoableChangeListener(
295 const OUString& rPropertyName, const Reference<XVetoableChangeListener>& rxListener)
297 std::unique_lock aGuard(m_aMutex);
298 OSL_ENSURE(!m_bDisposed, "object is disposed");
299 // all listeners are automatically released in a dispose call
300 if (m_bDisposed)
301 return;
303 if (!rPropertyName.isEmpty())
305 // get the map table
306 IPropertyArrayHelper& rPH = getInfoHelper();
307 // map the name to the handle
308 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
309 if (nHandle == -1)
311 // property not known throw exception
312 throw UnknownPropertyException(rPropertyName);
314 // remove the vetoable listener to the helper container
315 aVetoableLC.removeInterface(aGuard, nHandle, rxListener);
317 else
318 // add the vetoable listener to the helper container
319 maVetoableChangeListeners.removeInterface(aGuard, rxListener);
322 void OPropertySetHelper::setDependentFastPropertyValue(std::unique_lock<std::mutex>& rGuard,
323 sal_Int32 i_handle,
324 const css::uno::Any& i_value)
326 sal_Int16 nAttributes(0);
327 IPropertyArrayHelper& rInfo = getInfoHelper();
328 if (!rInfo.fillPropertyMembersByHandle(nullptr, &nAttributes, i_handle))
329 // unknown property
330 throw UnknownPropertyException(OUString::number(i_handle));
332 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which
333 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
334 // to change their value.
336 Any aConverted, aOld;
337 bool bChanged = convertFastPropertyValue(rGuard, aConverted, aOld, i_handle, i_value);
338 if (!bChanged)
339 return;
341 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
342 // a good idea. The caller is responsible for not invoking this for constrained properties.
343 OSL_ENSURE((nAttributes & PropertyAttribute::CONSTRAINED) == 0,
344 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained "
345 "properties!");
347 // actually set the new value
350 setFastPropertyValue_NoBroadcast(rGuard, i_handle, aConverted);
352 catch (const UnknownPropertyException&)
354 throw; /* allowed to leave */
356 catch (const PropertyVetoException&)
358 throw; /* allowed to leave */
360 catch (const IllegalArgumentException&)
362 throw; /* allowed to leave */
364 catch (const WrappedTargetException&)
366 throw; /* allowed to leave */
368 catch (const RuntimeException&)
370 throw; /* allowed to leave */
372 catch (const Exception&)
374 // not allowed to leave this method
375 WrappedTargetException aWrapped;
376 aWrapped.TargetException = ::cppu::getCaughtException();
377 aWrapped.Context = static_cast<XPropertySet*>(this);
378 throw aWrapped;
381 // remember the handle/values, for the events to be fired later
382 m_handles.push_back(i_handle);
383 m_newValues.push_back(
384 aConverted); // TODO: setFastPropertyValue notifies the unconverted value here ...?
385 m_oldValues.push_back(aOld);
388 // XFastPropertySet
389 void OPropertySetHelper::setFastPropertyValue(sal_Int32 nHandle, const Any& rValue)
391 std::unique_lock aGuard(m_aMutex);
392 setFastPropertyValueImpl(aGuard, nHandle, rValue);
395 void OPropertySetHelper::setFastPropertyValueImpl(std::unique_lock<std::mutex>& rGuard,
396 sal_Int32 nHandle, const Any& rValue)
398 OSL_ENSURE(!m_bDisposed, "object is disposed");
400 IPropertyArrayHelper& rInfo = getInfoHelper();
401 sal_Int16 nAttributes;
402 if (!rInfo.fillPropertyMembersByHandle(nullptr, &nAttributes, nHandle))
404 // unknown property
405 throw UnknownPropertyException(OUString::number(nHandle));
407 if (nAttributes & PropertyAttribute::READONLY)
408 throw PropertyVetoException();
410 Any aConvertedVal;
411 Any aOldVal;
413 // Will the property change?
414 bool bChanged = convertFastPropertyValue(rGuard, aConvertedVal, aOldVal, nHandle, rValue);
415 if (!bChanged)
416 return;
418 // Is it a constrained property?
419 if (nAttributes & PropertyAttribute::CONSTRAINED)
421 // In aValue is the converted rValue
422 // fire a constrained event
423 // second parameter NULL means constrained
424 fire(rGuard, &nHandle, &rValue, &aOldVal, 1, true);
429 // set the property to the new value
430 setFastPropertyValue_NoBroadcast(rGuard, nHandle, aConvertedVal);
432 catch (const css::beans::UnknownPropertyException&)
434 throw; /* allowed to leave */
436 catch (const css::beans::PropertyVetoException&)
438 throw; /* allowed to leave */
440 catch (const css::lang::IllegalArgumentException&)
442 throw; /* allowed to leave */
444 catch (const css::lang::WrappedTargetException&)
446 throw; /* allowed to leave */
448 catch (const css::uno::RuntimeException&)
450 throw; /* allowed to leave */
452 catch (const css::uno::Exception& e)
454 // not allowed to leave this method
455 css::lang::WrappedTargetException aWrap;
456 aWrap.Context = static_cast<css::beans::XPropertySet*>(this);
457 aWrap.TargetException <<= e;
459 throw aWrap;
462 // file a change event, if the value changed
463 impl_fireAll(rGuard, &nHandle, &rValue, &aOldVal, 1);
466 // XFastPropertySet
467 Any OPropertySetHelper::getFastPropertyValue(sal_Int32 nHandle)
469 IPropertyArrayHelper& rInfo = getInfoHelper();
470 if (!rInfo.fillPropertyMembersByHandle(nullptr, nullptr, nHandle))
471 // unknown property
472 throw UnknownPropertyException(OUString::number(nHandle));
474 Any aRet;
475 std::unique_lock aGuard(m_aMutex);
476 getFastPropertyValue(aGuard, aRet, nHandle);
477 return aRet;
480 void OPropertySetHelper::impl_fireAll(std::unique_lock<std::mutex>& rGuard, sal_Int32* i_handles,
481 const Any* i_newValues, const Any* i_oldValues,
482 sal_Int32 i_count)
484 if (m_handles.empty())
486 fire(rGuard, i_handles, i_newValues, i_oldValues, i_count, false);
487 return;
490 const size_t additionalEvents = m_handles.size();
491 OSL_ENSURE(additionalEvents == m_newValues.size() && additionalEvents == m_oldValues.size(),
492 "OPropertySetHelper::impl_fireAll: inconsistency!");
494 std::vector<sal_Int32> allHandles(additionalEvents + i_count);
495 std::copy(m_handles.begin(), m_handles.end(), allHandles.begin());
496 std::copy(i_handles, i_handles + i_count, allHandles.begin() + additionalEvents);
498 std::vector<Any> allNewValues(additionalEvents + i_count);
499 std::copy(m_newValues.begin(), m_newValues.end(), allNewValues.begin());
500 std::copy(i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents);
502 std::vector<Any> allOldValues(additionalEvents + i_count);
503 std::copy(m_oldValues.begin(), m_oldValues.end(), allOldValues.begin());
504 std::copy(i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents);
506 m_handles.clear();
507 m_newValues.clear();
508 m_oldValues.clear();
510 fire(rGuard, allHandles.data(), allNewValues.data(), allOldValues.data(),
511 additionalEvents + i_count, false);
514 void OPropertySetHelper::fire(std::unique_lock<std::mutex>& rGuard, sal_Int32* pnHandles,
515 const Any* pNewValues, const Any* pOldValues,
516 sal_Int32 nHandles, // This is the Count of the array
517 bool bVetoable)
519 // Only fire, if one or more properties changed
520 if (!nHandles)
521 return;
523 // create the event sequence of all changed properties
524 Sequence<PropertyChangeEvent> aEvts(nHandles);
525 PropertyChangeEvent* pEvts = aEvts.getArray();
526 Reference<XInterface> xSource(static_cast<XPropertySet*>(this), UNO_QUERY);
527 sal_Int32 i;
528 sal_Int32 nChangesLen = 0;
529 // Loop over all changed properties to fill the event struct
530 for (i = 0; i < nHandles; i++)
532 // Vetoable fire and constrained attribute set or
533 // Change fire and Changed and bound attribute set
534 IPropertyArrayHelper& rInfo = getInfoHelper();
535 sal_Int16 nAttributes;
536 OUString aPropName;
537 rInfo.fillPropertyMembersByHandle(&aPropName, &nAttributes, pnHandles[i]);
539 if ((bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED))
540 || (!bVetoable && (nAttributes & PropertyAttribute::BOUND)))
542 pEvts[nChangesLen].Source = xSource;
543 pEvts[nChangesLen].PropertyName = aPropName;
544 pEvts[nChangesLen].PropertyHandle = pnHandles[i];
545 pEvts[nChangesLen].OldValue = pOldValues[i];
546 pEvts[nChangesLen].NewValue = pNewValues[i];
547 nChangesLen++;
551 bool bIgnoreRuntimeExceptionsWhileFiring = m_bIgnoreRuntimeExceptionsWhileFiring;
553 // fire the events for all changed properties
554 for (i = 0; i < nChangesLen; i++)
556 if (bVetoable) // fire change Events?
557 fireVetoableChangeListeners(
558 rGuard, aVetoableLC.getContainer(rGuard, pEvts[i].PropertyHandle), pEvts[i]);
559 else
560 // get the listener container for the property name
561 firePropertyChangeListeners(
562 rGuard, aBoundLC.getContainer(rGuard, pEvts[i].PropertyHandle), pEvts[i]);
564 // broadcast to all listeners with "" property name
565 if (bVetoable)
566 // fire change Events?
567 fireVetoableChangeListeners(rGuard, &maVetoableChangeListeners, pEvts[i]);
568 else
569 firePropertyChangeListeners(rGuard, &maPropertyChangeListeners, pEvts[i]);
572 // reduce array to changed properties
573 aEvts.realloc(nChangesLen);
575 if (bVetoable)
576 return;
578 if (!maPropertiesChangeListeners.getLength(rGuard))
579 return;
581 // Here is a Bug, unbound properties are also fired
582 OInterfaceIteratorHelper4 aIt(rGuard, maPropertiesChangeListeners);
583 rGuard.unlock();
584 while (aIt.hasMoreElements())
586 XPropertiesChangeListener* pL = aIt.next().get();
591 // fire the whole event sequence to the
592 // XPropertiesChangeListener's
593 pL->propertiesChange(aEvts);
595 catch (DisposedException& exc)
597 OSL_ENSURE(exc.Context.is(), "DisposedException without Context!");
598 if (exc.Context == pL)
600 rGuard.lock();
601 aIt.remove(rGuard);
602 rGuard.unlock();
604 else
605 throw;
608 catch (RuntimeException& exc)
610 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
611 if (!bIgnoreRuntimeExceptionsWhileFiring)
612 throw;
615 rGuard.lock();
618 void OPropertySetHelper::fireVetoableChangeListeners(
619 std::unique_lock<std::mutex>& rGuard,
620 comphelper::OInterfaceContainerHelper4<css::beans::XVetoableChangeListener>* pListeners,
621 const css::beans::PropertyChangeEvent& rChangeEvent)
623 if (!pListeners || !pListeners->getLength(rGuard))
624 return;
625 // Iterate over all listeners and send events
626 OInterfaceIteratorHelper4 aIt(rGuard, *pListeners);
627 rGuard.unlock();
628 while (aIt.hasMoreElements())
630 XVetoableChangeListener* pL = aIt.next().get();
635 pL->vetoableChange(rChangeEvent);
637 catch (DisposedException& exc)
639 OSL_ENSURE(exc.Context.is(), "DisposedException without Context!");
640 if (exc.Context == pL)
642 rGuard.lock();
643 aIt.remove(rGuard);
644 rGuard.unlock();
646 else
647 throw;
650 catch (RuntimeException& exc)
652 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
653 if (!m_bIgnoreRuntimeExceptionsWhileFiring)
654 throw;
657 rGuard.lock();
660 void OPropertySetHelper::firePropertyChangeListeners(
661 std::unique_lock<std::mutex>& rGuard,
662 comphelper::OInterfaceContainerHelper4<css::beans::XPropertyChangeListener>* pListeners,
663 const css::beans::PropertyChangeEvent& rChangeEvent)
665 if (!pListeners || !pListeners->getLength(rGuard))
666 return;
667 // Iterate over all listeners and send events
668 OInterfaceIteratorHelper4 aIt(rGuard, *pListeners);
669 rGuard.unlock();
670 while (aIt.hasMoreElements())
672 XPropertyChangeListener* pL = aIt.next().get();
677 pL->propertyChange(rChangeEvent);
679 catch (DisposedException& exc)
681 OSL_ENSURE(exc.Context.is(), "DisposedException without Context!");
682 if (exc.Context == pL)
684 rGuard.lock();
685 aIt.remove(rGuard);
686 rGuard.unlock();
688 else
689 throw;
692 catch (RuntimeException& exc)
694 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
695 if (!m_bIgnoreRuntimeExceptionsWhileFiring)
696 throw;
699 rGuard.lock();
702 // OPropertySetHelper
703 void OPropertySetHelper::setFastPropertyValues(std::unique_lock<std::mutex>& rGuard,
704 sal_Int32 nSeqLen, sal_Int32* pHandles,
705 const Any* pValues, sal_Int32 nHitCount)
707 OSL_ENSURE(!m_bDisposed, "object is disposed");
709 // get the map table
710 IPropertyArrayHelper& rPH = getInfoHelper();
712 std::unique_ptr<Any[]> pConvertedValues(new Any[nHitCount]);
713 std::unique_ptr<Any[]> pOldValues(new Any[nHitCount]);
714 sal_Int32 n = 0;
715 sal_Int32 i;
717 for (i = 0; i < nSeqLen; i++)
719 if (pHandles[i] != -1)
721 sal_Int16 nAttributes;
722 rPH.fillPropertyMembersByHandle(nullptr, &nAttributes, pHandles[i]);
723 if (nAttributes & PropertyAttribute::READONLY)
724 throw PropertyVetoException();
725 // Will the property change?
726 if (convertFastPropertyValue(rGuard, pConvertedValues[n], pOldValues[n], pHandles[i],
727 pValues[i]))
729 // only increment if the property really change
730 pHandles[n] = pHandles[i];
731 n++;
736 // fire vetoable events
737 fire(rGuard, pHandles, pConvertedValues.get(), pOldValues.get(), n, true);
739 // Loop over all changed properties
740 for (i = 0; i < n; i++)
742 // Will the property change?
743 setFastPropertyValue_NoBroadcast(rGuard, pHandles[i], pConvertedValues[i]);
746 // fire change events
747 impl_fireAll(rGuard, pHandles, pConvertedValues.get(), pOldValues.get(), n);
750 // XMultiPropertySet
752 * The sequence may be contain not known properties. The implementation
753 * must ignore these properties.
755 void OPropertySetHelper::setPropertyValues(const Sequence<OUString>& rPropertyNames,
756 const Sequence<Any>& rValues)
758 sal_Int32 nSeqLen = rPropertyNames.getLength();
759 if (nSeqLen != rValues.getLength())
760 throw IllegalArgumentException(u"lengths do not match"_ustr,
761 static_cast<XPropertySet*>(this), -1);
762 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nSeqLen]);
763 // get the map table
764 IPropertyArrayHelper& rPH = getInfoHelper();
765 // fill the handle array
766 sal_Int32 nHitCount = rPH.fillHandles(pHandles.get(), rPropertyNames);
767 if (nHitCount == 0)
768 return;
769 std::unique_lock aGuard(m_aMutex);
770 setFastPropertyValues(aGuard, nSeqLen, pHandles.get(), rValues.getConstArray(), nHitCount);
773 // XMultiPropertySet
774 Sequence<Any> OPropertySetHelper::getPropertyValues(const Sequence<OUString>& rPropertyNames)
776 sal_Int32 nSeqLen = rPropertyNames.getLength();
777 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nSeqLen]);
778 Sequence<Any> aValues(nSeqLen);
780 // get the map table
781 IPropertyArrayHelper& rPH = getInfoHelper();
782 // fill the handle array
783 rPH.fillHandles(pHandles.get(), rPropertyNames);
785 Any* pValues = aValues.getArray();
787 std::unique_lock aGuard(m_aMutex);
788 // fill the sequence with the values
789 for (sal_Int32 i = 0; i < nSeqLen; i++)
790 getFastPropertyValue(aGuard, pValues[i], pHandles[i]);
792 return aValues;
795 // XMultiPropertySet
796 void OPropertySetHelper::addPropertiesChangeListener(
797 const Sequence<OUString>&, const Reference<XPropertiesChangeListener>& rListener)
799 std::unique_lock g(m_aMutex);
800 maPropertiesChangeListeners.addInterface(g, rListener);
803 // XMultiPropertySet
804 void OPropertySetHelper::removePropertiesChangeListener(
805 const Reference<XPropertiesChangeListener>& rListener)
807 std::unique_lock g(m_aMutex);
808 maPropertiesChangeListeners.removeInterface(g, rListener);
811 // XMultiPropertySet
812 void OPropertySetHelper::firePropertiesChangeEvent(
813 const Sequence<OUString>& rPropertyNames, const Reference<XPropertiesChangeListener>& rListener)
815 sal_Int32 nLen = rPropertyNames.getLength();
816 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nLen]);
817 IPropertyArrayHelper& rPH = getInfoHelper();
818 rPH.fillHandles(pHandles.get(), rPropertyNames);
820 // get the count of matching properties
821 sal_Int32 nFireLen = 0;
822 sal_Int32 i;
823 for (i = 0; i < nLen; i++)
824 if (pHandles[i] != -1)
825 nFireLen++;
827 Sequence<PropertyChangeEvent> aChanges(nFireLen);
828 PropertyChangeEvent* pChanges = aChanges.getArray();
831 // must lock the mutex outside the loop. So all values are consistent.
832 std::unique_lock aGuard(m_aMutex);
833 Reference<XInterface> xSource(static_cast<XPropertySet*>(this), UNO_QUERY);
834 sal_Int32 nFirePos = 0;
835 for (i = 0; i < nLen; i++)
837 if (pHandles[i] != -1)
839 pChanges[nFirePos].Source = xSource;
840 pChanges[nFirePos].PropertyName = rPropertyNames[i];
841 pChanges[nFirePos].PropertyHandle = pHandles[i];
842 getFastPropertyValue(aGuard, pChanges[nFirePos].OldValue, pHandles[i]);
843 pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue;
844 nFirePos++;
847 // release guard to fire events
849 if (nFireLen)
850 rListener->propertiesChange(aChanges);
853 UnoImplBase::~UnoImplBase() {}
855 } // end namespace comphelper
857 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */