Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / comphelper / source / property / propshlp.cxx
blobdd227cc15e2525c48443425f7932af3d3bf94dc5
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 osl;
32 using namespace com::sun::star::uno;
33 using namespace com::sun::star::beans;
34 using namespace com::sun::star::lang;
35 using namespace cppu;
37 namespace comphelper
39 extern "C" {
41 static int compare_OUString_Property_Impl(const void* arg1, const void* arg2) SAL_THROW_EXTERN_C()
43 return static_cast<OUString const*>(arg1)->compareTo(static_cast<Property const*>(arg2)->Name);
47 /**
48 * The class which implements the PropertySetInfo interface.
51 namespace
53 class OPropertySetHelperInfo_Impl : public WeakImplHelper<css::beans::XPropertySetInfo>
55 Sequence<Property> aInfos;
57 public:
58 explicit OPropertySetHelperInfo_Impl(IPropertyArrayHelper& rHelper_);
60 // XPropertySetInfo-methods
61 virtual Sequence<Property> SAL_CALL getProperties() override;
62 virtual Property SAL_CALL getPropertyByName(const OUString& PropertyName) override;
63 virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& PropertyName) override;
67 /**
68 * Create an object that implements XPropertySetInfo IPropertyArrayHelper.
70 OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl(IPropertyArrayHelper& rHelper_)
71 : aInfos(rHelper_.getProperties())
75 /**
76 * Return the sequence of properties, which are provided through the constructor.
78 Sequence<Property> OPropertySetHelperInfo_Impl::getProperties() { return aInfos; }
80 /**
81 * Return the sequence of properties, which are provided through the constructor.
83 Property OPropertySetHelperInfo_Impl::getPropertyByName(const OUString& PropertyName)
85 Property* pR
86 = static_cast<Property*>(bsearch(&PropertyName, aInfos.getConstArray(), aInfos.getLength(),
87 sizeof(Property), compare_OUString_Property_Impl));
88 if (!pR)
89 throw UnknownPropertyException(PropertyName);
91 return *pR;
94 /**
95 * Return the sequence of properties, which are provided through the constructor.
97 sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName(const OUString& PropertyName)
99 Property* pR
100 = static_cast<Property*>(bsearch(&PropertyName, aInfos.getConstArray(), aInfos.getLength(),
101 sizeof(Property), compare_OUString_Property_Impl));
102 return pR != nullptr;
105 OPropertySetHelper::OPropertySetHelper() {}
107 OPropertySetHelper::OPropertySetHelper(bool bIgnoreRuntimeExceptionsWhileFiring)
108 : m_bIgnoreRuntimeExceptionsWhileFiring(bIgnoreRuntimeExceptionsWhileFiring)
113 * You must call disposing before.
115 OPropertySetHelper::~OPropertySetHelper() {}
117 // XInterface
118 Any OPropertySetHelper::queryInterface(const css::uno::Type& rType)
120 return ::cppu::queryInterface(rType, static_cast<XPropertySet*>(this),
121 static_cast<XMultiPropertySet*>(this),
122 static_cast<XFastPropertySet*>(this));
126 * called from the derivee's XTypeProvider::getTypes implementation
128 css::uno::Sequence<css::uno::Type> OPropertySetHelper::getTypes()
130 return { UnoType<css::beans::XPropertySet>::get(),
131 UnoType<css::beans::XMultiPropertySet>::get(),
132 UnoType<css::beans::XFastPropertySet>::get() };
135 // ComponentHelper
136 void OPropertySetHelper::disposing(std::unique_lock<std::mutex>& rGuard)
138 // Create an event with this as sender
139 Reference<XPropertySet> rSource = this;
140 EventObject aEvt;
141 aEvt.Source = rSource;
143 // inform all listeners to release this object
144 // The listener containers are automatically cleared
145 aBoundLC.disposeAndClear(rGuard, aEvt);
146 aVetoableLC.disposeAndClear(rGuard, aEvt);
149 Reference<XPropertySetInfo>
150 OPropertySetHelper::createPropertySetInfo(IPropertyArrayHelper& rProperties)
152 return new OPropertySetHelperInfo_Impl(rProperties);
155 // XPropertySet
156 void OPropertySetHelper::setPropertyValue(const OUString& rPropertyName, const Any& rValue)
158 // get the map table
159 IPropertyArrayHelper& rPH = getInfoHelper();
160 // map the name to the handle
161 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
162 std::unique_lock aGuard(m_aMutex);
163 setFastPropertyValueImpl(aGuard, nHandle, rValue);
166 // XPropertySet
167 Any OPropertySetHelper::getPropertyValue(const OUString& rPropertyName)
169 std::unique_lock aGuard(m_aMutex);
170 return getPropertyValueImpl(aGuard, rPropertyName);
173 Any OPropertySetHelper::getPropertyValueImpl(std::unique_lock<std::mutex>& rGuard,
174 const OUString& rPropertyName)
176 // get the map table
177 IPropertyArrayHelper& rPH = getInfoHelper();
178 // map the name to the handle
179 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
180 // call the method of the XFastPropertySet interface
181 Any aAny;
182 getFastPropertyValue(rGuard, aAny, nHandle);
183 return aAny;
186 // XPropertySet
187 void OPropertySetHelper::addPropertyChangeListener(
188 const OUString& rPropertyName, const Reference<XPropertyChangeListener>& rxListener)
190 std::unique_lock aGuard(m_aMutex);
191 OSL_ENSURE(!m_bDisposed, "object is disposed");
192 if (m_bDisposed)
193 return;
195 // only add listeners if you are not disposed
196 // a listener with no name means all properties
197 if (!rPropertyName.isEmpty())
199 // get the map table
200 IPropertyArrayHelper& rPH = getInfoHelper();
201 // map the name to the handle
202 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
203 if (nHandle == -1)
205 // property not known throw exception
206 throw UnknownPropertyException(rPropertyName);
209 sal_Int16 nAttributes;
210 rPH.fillPropertyMembersByHandle(nullptr, &nAttributes, nHandle);
211 if (!(nAttributes & css::beans::PropertyAttribute::BOUND))
213 OSL_FAIL("add listener to an unbound property");
214 // silent ignore this
215 return;
217 // add the change listener to the helper container
218 aBoundLC.addInterface(aGuard, nHandle, rxListener);
220 else
221 // add the change listener to the helper container
222 maPropertyChangeListeners.addInterface(aGuard, rxListener);
225 // XPropertySet
226 void OPropertySetHelper::removePropertyChangeListener(
227 const OUString& rPropertyName, const Reference<XPropertyChangeListener>& rxListener)
229 std::unique_lock aGuard(m_aMutex);
230 OSL_ENSURE(!m_bDisposed, "object is disposed");
231 // all listeners are automatically released in a dispose call
232 if (m_bDisposed)
233 return;
235 if (!rPropertyName.isEmpty())
237 // get the map table
238 IPropertyArrayHelper& rPH = getInfoHelper();
239 // map the name to the handle
240 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
241 if (nHandle == -1)
242 // property not known throw exception
243 throw UnknownPropertyException(rPropertyName);
244 aBoundLC.removeInterface(aGuard, nHandle, rxListener);
246 else
248 // remove the change listener to the helper container
249 maPropertyChangeListeners.removeInterface(aGuard, rxListener);
253 // XPropertySet
254 void OPropertySetHelper::addVetoableChangeListener(
255 const OUString& rPropertyName, const Reference<XVetoableChangeListener>& rxListener)
257 std::unique_lock aGuard(m_aMutex);
258 OSL_ENSURE(!m_bDisposed, "object is disposed");
259 if (m_bDisposed)
260 return;
262 // only add listeners if you are not disposed
263 // a listener with no name means all properties
264 if (!rPropertyName.isEmpty())
266 // get the map table
267 IPropertyArrayHelper& rPH = getInfoHelper();
268 // map the name to the handle
269 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
270 if (nHandle == -1)
272 // property not known throw exception
273 throw UnknownPropertyException(rPropertyName);
276 sal_Int16 nAttributes;
277 rPH.fillPropertyMembersByHandle(nullptr, &nAttributes, nHandle);
278 if (!(nAttributes & PropertyAttribute::CONSTRAINED))
280 OSL_FAIL("addVetoableChangeListener, and property is not constrained");
281 // silent ignore this
282 return;
284 // add the vetoable listener to the helper container
285 aVetoableLC.addInterface(aGuard, nHandle, rxListener);
287 else
288 // add the vetoable listener to the helper container
289 maVetoableChangeListeners.addInterface(aGuard, rxListener);
292 // XPropertySet
293 void OPropertySetHelper::removeVetoableChangeListener(
294 const OUString& rPropertyName, const Reference<XVetoableChangeListener>& rxListener)
296 std::unique_lock aGuard(m_aMutex);
297 OSL_ENSURE(!m_bDisposed, "object is disposed");
298 // all listeners are automatically released in a dispose call
299 if (m_bDisposed)
300 return;
302 if (!rPropertyName.isEmpty())
304 // get the map table
305 IPropertyArrayHelper& rPH = getInfoHelper();
306 // map the name to the handle
307 sal_Int32 nHandle = rPH.getHandleByName(rPropertyName);
308 if (nHandle == -1)
310 // property not known throw exception
311 throw UnknownPropertyException(rPropertyName);
313 // remove the vetoable listener to the helper container
314 aVetoableLC.removeInterface(aGuard, nHandle, rxListener);
316 else
317 // add the vetoable listener to the helper container
318 maVetoableChangeListeners.removeInterface(aGuard, rxListener);
321 void OPropertySetHelper::setDependentFastPropertyValue(std::unique_lock<std::mutex>& rGuard,
322 sal_Int32 i_handle,
323 const css::uno::Any& i_value)
325 sal_Int16 nAttributes(0);
326 IPropertyArrayHelper& rInfo = getInfoHelper();
327 if (!rInfo.fillPropertyMembersByHandle(nullptr, &nAttributes, i_handle))
328 // unknown property
329 throw UnknownPropertyException(OUString::number(i_handle));
331 // no need to check for READONLY-ness of the property. The method is intended to be called internally, which
332 // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed
333 // to change their value.
335 Any aConverted, aOld;
336 bool bChanged = convertFastPropertyValue(rGuard, aConverted, aOld, i_handle, i_value);
337 if (!bChanged)
338 return;
340 // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be
341 // a good idea. The caller is responsible for not invoking this for constrained properties.
342 OSL_ENSURE((nAttributes & PropertyAttribute::CONSTRAINED) == 0,
343 "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained "
344 "properties!");
346 // actually set the new value
349 setFastPropertyValue_NoBroadcast(rGuard, i_handle, aConverted);
351 catch (const UnknownPropertyException&)
353 throw; /* allowed to leave */
355 catch (const PropertyVetoException&)
357 throw; /* allowed to leave */
359 catch (const IllegalArgumentException&)
361 throw; /* allowed to leave */
363 catch (const WrappedTargetException&)
365 throw; /* allowed to leave */
367 catch (const RuntimeException&)
369 throw; /* allowed to leave */
371 catch (const Exception&)
373 // not allowed to leave this method
374 WrappedTargetException aWrapped;
375 aWrapped.TargetException = ::cppu::getCaughtException();
376 aWrapped.Context = static_cast<XPropertySet*>(this);
377 throw aWrapped;
380 // remember the handle/values, for the events to be fired later
381 m_handles.push_back(i_handle);
382 m_newValues.push_back(
383 aConverted); // TODO: setFastPropertyValue notifies the unconverted value here ...?
384 m_oldValues.push_back(aOld);
387 // XFastPropertySet
388 void OPropertySetHelper::setFastPropertyValue(sal_Int32 nHandle, const Any& rValue)
390 std::unique_lock aGuard(m_aMutex);
391 setFastPropertyValueImpl(aGuard, nHandle, rValue);
394 void OPropertySetHelper::setFastPropertyValueImpl(std::unique_lock<std::mutex>& rGuard,
395 sal_Int32 nHandle, const Any& rValue)
397 OSL_ENSURE(!m_bDisposed, "object is disposed");
399 IPropertyArrayHelper& rInfo = getInfoHelper();
400 sal_Int16 nAttributes;
401 if (!rInfo.fillPropertyMembersByHandle(nullptr, &nAttributes, nHandle))
403 // unknown property
404 throw UnknownPropertyException(OUString::number(nHandle));
406 if (nAttributes & PropertyAttribute::READONLY)
407 throw PropertyVetoException();
409 Any aConvertedVal;
410 Any aOldVal;
412 // Will the property change?
413 bool bChanged = convertFastPropertyValue(rGuard, aConvertedVal, aOldVal, nHandle, rValue);
414 if (!bChanged)
415 return;
417 // Is it a constrained property?
418 if (nAttributes & PropertyAttribute::CONSTRAINED)
420 // In aValue is the converted rValue
421 // fire a constrained event
422 // second parameter NULL means constrained
423 fire(rGuard, &nHandle, &rValue, &aOldVal, 1, true);
428 // set the property to the new value
429 setFastPropertyValue_NoBroadcast(rGuard, nHandle, aConvertedVal);
431 catch (const css::beans::UnknownPropertyException&)
433 throw; /* allowed to leave */
435 catch (const css::beans::PropertyVetoException&)
437 throw; /* allowed to leave */
439 catch (const css::lang::IllegalArgumentException&)
441 throw; /* allowed to leave */
443 catch (const css::lang::WrappedTargetException&)
445 throw; /* allowed to leave */
447 catch (const css::uno::RuntimeException&)
449 throw; /* allowed to leave */
451 catch (const css::uno::Exception& e)
453 // not allowed to leave this method
454 css::lang::WrappedTargetException aWrap;
455 aWrap.Context = static_cast<css::beans::XPropertySet*>(this);
456 aWrap.TargetException <<= e;
458 throw aWrap;
461 // file a change event, if the value changed
462 impl_fireAll(rGuard, &nHandle, &rValue, &aOldVal, 1);
465 // XFastPropertySet
466 Any OPropertySetHelper::getFastPropertyValue(sal_Int32 nHandle)
468 IPropertyArrayHelper& rInfo = getInfoHelper();
469 if (!rInfo.fillPropertyMembersByHandle(nullptr, nullptr, nHandle))
470 // unknown property
471 throw UnknownPropertyException(OUString::number(nHandle));
473 Any aRet;
474 std::unique_lock aGuard(m_aMutex);
475 getFastPropertyValue(aGuard, aRet, nHandle);
476 return aRet;
479 void OPropertySetHelper::impl_fireAll(std::unique_lock<std::mutex>& rGuard, sal_Int32* i_handles,
480 const Any* i_newValues, const Any* i_oldValues,
481 sal_Int32 i_count)
483 if (m_handles.empty())
485 fire(rGuard, i_handles, i_newValues, i_oldValues, i_count, false);
486 return;
489 const size_t additionalEvents = m_handles.size();
490 OSL_ENSURE(additionalEvents == m_newValues.size() && additionalEvents == m_oldValues.size(),
491 "OPropertySetHelper::impl_fireAll: inconsistency!");
493 std::vector<sal_Int32> allHandles(additionalEvents + i_count);
494 std::copy(m_handles.begin(), m_handles.end(), allHandles.begin());
495 std::copy(i_handles, i_handles + i_count, allHandles.begin() + additionalEvents);
497 std::vector<Any> allNewValues(additionalEvents + i_count);
498 std::copy(m_newValues.begin(), m_newValues.end(), allNewValues.begin());
499 std::copy(i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents);
501 std::vector<Any> allOldValues(additionalEvents + i_count);
502 std::copy(m_oldValues.begin(), m_oldValues.end(), allOldValues.begin());
503 std::copy(i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents);
505 m_handles.clear();
506 m_newValues.clear();
507 m_oldValues.clear();
509 fire(rGuard, allHandles.data(), allNewValues.data(), allOldValues.data(),
510 additionalEvents + i_count, false);
513 void OPropertySetHelper::fire(std::unique_lock<std::mutex>& rGuard, sal_Int32* pnHandles,
514 const Any* pNewValues, const Any* pOldValues,
515 sal_Int32 nHandles, // This is the Count of the array
516 bool bVetoable)
518 if (!m_bFireEvents)
519 return;
521 // Only fire, if one or more properties changed
522 if (!nHandles)
523 return;
525 // create the event sequence of all changed properties
526 Sequence<PropertyChangeEvent> aEvts(nHandles);
527 PropertyChangeEvent* pEvts = aEvts.getArray();
528 Reference<XInterface> xSource(static_cast<XPropertySet*>(this), UNO_QUERY);
529 sal_Int32 i;
530 sal_Int32 nChangesLen = 0;
531 // Loop over all changed properties to fill the event struct
532 for (i = 0; i < nHandles; i++)
534 // Vetoable fire and constrained attribute set or
535 // Change fire and Changed and bound attribute set
536 IPropertyArrayHelper& rInfo = getInfoHelper();
537 sal_Int16 nAttributes;
538 OUString aPropName;
539 rInfo.fillPropertyMembersByHandle(&aPropName, &nAttributes, pnHandles[i]);
541 if ((bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED))
542 || (!bVetoable && (nAttributes & PropertyAttribute::BOUND)))
544 pEvts[nChangesLen].Source = xSource;
545 pEvts[nChangesLen].PropertyName = aPropName;
546 pEvts[nChangesLen].PropertyHandle = pnHandles[i];
547 pEvts[nChangesLen].OldValue = pOldValues[i];
548 pEvts[nChangesLen].NewValue = pNewValues[i];
549 nChangesLen++;
553 bool bIgnoreRuntimeExceptionsWhileFiring = m_bIgnoreRuntimeExceptionsWhileFiring;
555 // fire the events for all changed properties
556 for (i = 0; i < nChangesLen; i++)
558 if (bVetoable) // fire change Events?
559 fireVetoableChangeListeners(
560 rGuard, aVetoableLC.getContainer(rGuard, pEvts[i].PropertyHandle), pEvts[i]);
561 else
562 // get the listener container for the property name
563 firePropertyChangeListeners(
564 rGuard, aBoundLC.getContainer(rGuard, pEvts[i].PropertyHandle), pEvts[i]);
566 // broadcast to all listeners with "" property name
567 if (bVetoable)
568 // fire change Events?
569 fireVetoableChangeListeners(rGuard, &maVetoableChangeListeners, pEvts[i]);
570 else
571 firePropertyChangeListeners(rGuard, &maPropertyChangeListeners, pEvts[i]);
574 // reduce array to changed properties
575 aEvts.realloc(nChangesLen);
577 if (bVetoable)
578 return;
580 if (!maPropertiesChangeListeners.getLength(rGuard))
581 return;
583 // Here is a Bug, unbound properties are also fired
584 OInterfaceIteratorHelper4 aIt(rGuard, maPropertiesChangeListeners);
585 rGuard.unlock();
586 while (aIt.hasMoreElements())
588 XPropertiesChangeListener* pL = aIt.next().get();
593 // fire the whole event sequence to the
594 // XPropertiesChangeListener's
595 pL->propertiesChange(aEvts);
597 catch (DisposedException& exc)
599 OSL_ENSURE(exc.Context.is(), "DisposedException without Context!");
600 if (exc.Context == pL)
602 rGuard.lock();
603 aIt.remove(rGuard);
604 rGuard.unlock();
606 else
607 throw;
610 catch (RuntimeException& exc)
612 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
613 if (!bIgnoreRuntimeExceptionsWhileFiring)
614 throw;
617 rGuard.lock();
620 void OPropertySetHelper::fireVetoableChangeListeners(
621 std::unique_lock<std::mutex>& rGuard,
622 comphelper::OInterfaceContainerHelper4<css::beans::XVetoableChangeListener>* pListeners,
623 const css::beans::PropertyChangeEvent& rChangeEvent)
625 if (!pListeners || !pListeners->getLength(rGuard))
626 return;
627 // Iterate over all listeners and send events
628 OInterfaceIteratorHelper4 aIt(rGuard, *pListeners);
629 rGuard.unlock();
630 while (aIt.hasMoreElements())
632 XVetoableChangeListener* pL = aIt.next().get();
637 pL->vetoableChange(rChangeEvent);
639 catch (DisposedException& exc)
641 OSL_ENSURE(exc.Context.is(), "DisposedException without Context!");
642 if (exc.Context == pL)
644 rGuard.lock();
645 aIt.remove(rGuard);
646 rGuard.unlock();
648 else
649 throw;
652 catch (RuntimeException& exc)
654 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
655 if (!m_bIgnoreRuntimeExceptionsWhileFiring)
656 throw;
659 rGuard.lock();
662 void OPropertySetHelper::firePropertyChangeListeners(
663 std::unique_lock<std::mutex>& rGuard,
664 comphelper::OInterfaceContainerHelper4<css::beans::XPropertyChangeListener>* pListeners,
665 const css::beans::PropertyChangeEvent& rChangeEvent)
667 if (!pListeners || !pListeners->getLength(rGuard))
668 return;
669 // Iterate over all listeners and send events
670 OInterfaceIteratorHelper4 aIt(rGuard, *pListeners);
671 rGuard.unlock();
672 while (aIt.hasMoreElements())
674 XPropertyChangeListener* pL = aIt.next().get();
679 pL->propertyChange(rChangeEvent);
681 catch (DisposedException& exc)
683 OSL_ENSURE(exc.Context.is(), "DisposedException without Context!");
684 if (exc.Context == pL)
686 rGuard.lock();
687 aIt.remove(rGuard);
688 rGuard.unlock();
690 else
691 throw;
694 catch (RuntimeException& exc)
696 SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc);
697 if (!m_bIgnoreRuntimeExceptionsWhileFiring)
698 throw;
701 rGuard.lock();
704 // OPropertySetHelper
705 void OPropertySetHelper::setFastPropertyValues(std::unique_lock<std::mutex>& rGuard,
706 sal_Int32 nSeqLen, sal_Int32* pHandles,
707 const Any* pValues, sal_Int32 nHitCount)
709 OSL_ENSURE(!m_bDisposed, "object is disposed");
711 // get the map table
712 IPropertyArrayHelper& rPH = getInfoHelper();
714 std::unique_ptr<Any[]> pConvertedValues(new Any[nHitCount]);
715 std::unique_ptr<Any[]> pOldValues(new Any[nHitCount]);
716 sal_Int32 n = 0;
717 sal_Int32 i;
719 for (i = 0; i < nSeqLen; i++)
721 if (pHandles[i] != -1)
723 sal_Int16 nAttributes;
724 rPH.fillPropertyMembersByHandle(nullptr, &nAttributes, pHandles[i]);
725 if (nAttributes & PropertyAttribute::READONLY)
726 throw PropertyVetoException();
727 // Will the property change?
728 if (convertFastPropertyValue(rGuard, pConvertedValues[n], pOldValues[n], pHandles[i],
729 pValues[i]))
731 // only increment if the property really change
732 pHandles[n] = pHandles[i];
733 n++;
738 // fire vetoable events
739 fire(rGuard, pHandles, pConvertedValues.get(), pOldValues.get(), n, true);
741 // Loop over all changed properties
742 for (i = 0; i < n; i++)
744 // Will the property change?
745 setFastPropertyValue_NoBroadcast(rGuard, pHandles[i], pConvertedValues[i]);
748 // fire change events
749 impl_fireAll(rGuard, pHandles, pConvertedValues.get(), pOldValues.get(), n);
752 // XMultiPropertySet
754 * The sequence may be contain not known properties. The implementation
755 * must ignore these properties.
757 void OPropertySetHelper::setPropertyValues(const Sequence<OUString>& rPropertyNames,
758 const Sequence<Any>& rValues)
760 sal_Int32 nSeqLen = rPropertyNames.getLength();
761 if (nSeqLen != rValues.getLength())
762 throw IllegalArgumentException("lengths do not match", static_cast<XPropertySet*>(this),
763 -1);
764 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nSeqLen]);
765 // get the map table
766 IPropertyArrayHelper& rPH = getInfoHelper();
767 // fill the handle array
768 sal_Int32 nHitCount = rPH.fillHandles(pHandles.get(), rPropertyNames);
769 if (nHitCount == 0)
770 return;
771 std::unique_lock aGuard(m_aMutex);
772 setFastPropertyValues(aGuard, nSeqLen, pHandles.get(), rValues.getConstArray(), nHitCount);
775 // XMultiPropertySet
776 Sequence<Any> OPropertySetHelper::getPropertyValues(const Sequence<OUString>& rPropertyNames)
778 sal_Int32 nSeqLen = rPropertyNames.getLength();
779 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nSeqLen]);
780 Sequence<Any> aValues(nSeqLen);
782 // get the map table
783 IPropertyArrayHelper& rPH = getInfoHelper();
784 // fill the handle array
785 rPH.fillHandles(pHandles.get(), rPropertyNames);
787 Any* pValues = aValues.getArray();
789 std::unique_lock aGuard(m_aMutex);
790 // fill the sequence with the values
791 for (sal_Int32 i = 0; i < nSeqLen; i++)
792 getFastPropertyValue(aGuard, pValues[i], pHandles[i]);
794 return aValues;
797 // XMultiPropertySet
798 void OPropertySetHelper::addPropertiesChangeListener(
799 const Sequence<OUString>&, const Reference<XPropertiesChangeListener>& rListener)
801 std::unique_lock g(m_aMutex);
802 maPropertiesChangeListeners.addInterface(g, rListener);
805 // XMultiPropertySet
806 void OPropertySetHelper::removePropertiesChangeListener(
807 const Reference<XPropertiesChangeListener>& rListener)
809 std::unique_lock g(m_aMutex);
810 maPropertiesChangeListeners.removeInterface(g, rListener);
813 // XMultiPropertySet
814 void OPropertySetHelper::firePropertiesChangeEvent(
815 const Sequence<OUString>& rPropertyNames, const Reference<XPropertiesChangeListener>& rListener)
817 sal_Int32 nLen = rPropertyNames.getLength();
818 std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nLen]);
819 IPropertyArrayHelper& rPH = getInfoHelper();
820 rPH.fillHandles(pHandles.get(), rPropertyNames);
821 const OUString* pNames = rPropertyNames.getConstArray();
823 // get the count of matching properties
824 sal_Int32 nFireLen = 0;
825 sal_Int32 i;
826 for (i = 0; i < nLen; i++)
827 if (pHandles[i] != -1)
828 nFireLen++;
830 Sequence<PropertyChangeEvent> aChanges(nFireLen);
831 PropertyChangeEvent* pChanges = aChanges.getArray();
834 // must lock the mutex outside the loop. So all values are consistent.
835 std::unique_lock aGuard(m_aMutex);
836 Reference<XInterface> xSource(static_cast<XPropertySet*>(this), UNO_QUERY);
837 sal_Int32 nFirePos = 0;
838 for (i = 0; i < nLen; i++)
840 if (pHandles[i] != -1)
842 pChanges[nFirePos].Source = xSource;
843 pChanges[nFirePos].PropertyName = pNames[i];
844 pChanges[nFirePos].PropertyHandle = pHandles[i];
845 getFastPropertyValue(aGuard, pChanges[nFirePos].OldValue, pHandles[i]);
846 pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue;
847 nFirePos++;
850 // release guard to fire events
852 if (nFireLen)
853 rListener->propertiesChange(aChanges);
856 UnoImplBase::~UnoImplBase() {}
858 } // end namespace comphelper
860 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */