xref: /trunk/main/comphelper/source/property/propagg.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_comphelper.hxx"
26 #include "comphelper/propagg.hxx"
27 #include "comphelper/property.hxx"
28 #include <cppuhelper/queryinterface.hxx>
29 #include <osl/diagnose.h>
30 #include <com/sun/star/beans/PropertyAttribute.hpp>
31 
32 #if OSL_DEBUG_LEVEL > 0
33 #include <typeinfo>
34 #include <rtl/strbuf.hxx>
35 #endif
36 
37 #include <algorithm>
38 #include <set>
39 
40 //.........................................................................
41 namespace comphelper
42 {
43 //.........................................................................
44 
45     using namespace ::com::sun::star::uno;
46     using namespace ::com::sun::star::lang;
47     using namespace ::com::sun::star::beans;
48 
49     using namespace internal;
50 
51     //------------------------------------------------------------------------------
52     namespace
53     {
lcl_findPropertyByName(const Sequence<Property> & _rProps,const::rtl::OUString & _rName)54         const Property* lcl_findPropertyByName( const Sequence< Property >& _rProps, const ::rtl::OUString& _rName )
55         {
56             sal_Int32 nLen = _rProps.getLength();
57             const Property* pProperties = _rProps.getConstArray();
58             const Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen,_rName, ::comphelper::PropertyStringLessFunctor());
59             if ( pResult && ( pResult == pProperties + nLen || pResult->Name != _rName) )
60                 pResult = NULL;
61 
62             return pResult;
63         }
64     }
65 //==================================================================
66 //= OPropertyArrayAggregationHelper
67 //==================================================================
68 
69 //------------------------------------------------------------------------------
OPropertyArrayAggregationHelper(const Sequence<Property> & _rProperties,const Sequence<Property> & _rAggProperties,IPropertyInfoService * _pInfoService,sal_Int32 _nFirstAggregateId)70 OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper(
71         const  Sequence< Property >& _rProperties, const  Sequence< Property >& _rAggProperties,
72         IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
73     :m_aProperties( _rProperties )
74 {
75     sal_Int32 nDelegatorProps = _rProperties.getLength();
76     sal_Int32 nAggregateProps = _rAggProperties.getLength();
77 
78     // make room for all properties
79     sal_Int32 nMergedProps = nDelegatorProps + nAggregateProps;
80     m_aProperties.realloc( nMergedProps );
81 
82     const   Property* pAggregateProps   = _rAggProperties.getConstArray();
83     const   Property* pDelegateProps    = _rProperties.getConstArray();
84             Property* pMergedProps = m_aProperties.getArray();
85 
86     // if properties are present both at the delegatee and the aggregate, then the former are supposed to win.
87     // So, we'll need an existence check.
88     ::std::set< ::rtl::OUString > aDelegatorProps;
89 
90     // create the map for the delegator properties
91     sal_Int32 nMPLoop = 0;
92     for ( ; nMPLoop < nDelegatorProps; ++nMPLoop, ++pDelegateProps )
93     {
94         m_aPropertyAccessors[ pDelegateProps->Handle ] = OPropertyAccessor( -1, nMPLoop, sal_False );
95         OSL_ENSURE( aDelegatorProps.find( pDelegateProps->Name ) == aDelegatorProps.end(),
96             "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
97         aDelegatorProps.insert( pDelegateProps->Name );
98     }
99 
100     // create the map for the aggregate properties
101     sal_Int32 nAggregateHandle = _nFirstAggregateId;
102     pMergedProps += nDelegatorProps;
103     for ( ; nMPLoop < nMergedProps; ++pAggregateProps )
104     {
105         // if the aggregate property is present at the delegatee already, ignore it
106         if ( aDelegatorProps.find( pAggregateProps->Name ) != aDelegatorProps.end() )
107         {
108             --nMergedProps;
109             continue;
110         }
111 
112         // next aggregate property - remember it
113         *pMergedProps = *pAggregateProps;
114 
115         // determine the handle for the property which we will expose to the outside world
116         sal_Int32 nHandle = -1;
117         // ask the infor service first
118         if ( _pInfoService )
119             nHandle = _pInfoService->getPreferedPropertyId( pMergedProps->Name );
120 
121         if ( -1 == nHandle )
122             // no handle from the info service -> default
123             nHandle = nAggregateHandle++;
124         else
125         {   // check if we alread have a property with the given handle
126             const  Property* pPropsTilNow = m_aProperties.getConstArray();
127             for ( sal_Int32 nCheck = 0; nCheck < nMPLoop; ++nCheck, ++pPropsTilNow )
128                 if ( pPropsTilNow->Handle == nHandle )
129                 {   // conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough)
130                     nHandle = nAggregateHandle++;
131                     break;
132                 }
133         }
134 
135         // remember the accessor for this property
136         m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( pMergedProps->Handle, nMPLoop, sal_True );
137         pMergedProps->Handle = nHandle;
138 
139         ++nMPLoop;
140         ++pMergedProps;
141     }
142     m_aProperties.realloc( nMergedProps );
143     pMergedProps = m_aProperties.getArray();    // reset, needed again below
144 
145     // sortieren der Properties nach Namen
146     ::std::sort( pMergedProps, pMergedProps+nMergedProps, PropertyCompareByName());
147 
148     pMergedProps = m_aProperties.getArray();
149 
150     // Positionen in der Map abgleichen
151     for ( nMPLoop = 0; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps )
152         m_aPropertyAccessors[ pMergedProps->Handle ].nPos = nMPLoop;
153 }
154 
155 //------------------------------------------------------------------
classifyProperty(const::rtl::OUString & _rName)156 OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const ::rtl::OUString& _rName )
157 {
158     PropertyOrigin eOrigin = UNKNOWN_PROPERTY;
159     // look up the name
160     const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
161     if ( pPropertyDescriptor )
162     {
163         // look up the handle for this name
164         ConstPropertyAccessorMapIterator aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
165         OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
166         if ( m_aPropertyAccessors.end() != aPos )
167         {
168             eOrigin = aPos->second.bAggregate ? AGGREGATE_PROPERTY : DELEGATOR_PROPERTY;
169         }
170     }
171     return eOrigin;
172 }
173 
174 //------------------------------------------------------------------
getPropertyByName(const::rtl::OUString & _rPropertyName)175 Property OPropertyArrayAggregationHelper::getPropertyByName( const ::rtl::OUString& _rPropertyName )
176 {
177     const Property* pProperty = findPropertyByName( _rPropertyName );
178 
179     if ( !pProperty )
180         throw  UnknownPropertyException();
181 
182     return *pProperty;
183 }
184 
185 //------------------------------------------------------------------------------
hasPropertyByName(const::rtl::OUString & _rPropertyName)186 sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const ::rtl::OUString& _rPropertyName)
187 {
188     return NULL != findPropertyByName( _rPropertyName );
189 }
190 
191 //------------------------------------------------------------------------------
findPropertyByName(const::rtl::OUString & _rName) const192 const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: rtl::OUString& _rName ) const
193 {
194     return lcl_findPropertyByName( m_aProperties, _rName );
195 }
196 
197 //------------------------------------------------------------------------------
getHandleByName(const::rtl::OUString & _rPropertyName)198 sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const ::rtl::OUString& _rPropertyName)
199 {
200     const Property* pProperty = findPropertyByName( _rPropertyName );
201     return pProperty ? pProperty->Handle : -1;
202 }
203 
204 //------------------------------------------------------------------------------
fillPropertyMembersByHandle(::rtl::OUString * _pPropName,sal_Int16 * _pAttributes,sal_Int32 _nHandle)205 sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle(
206             ::rtl::OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
207 {
208     ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
209     sal_Bool bRet = i != m_aPropertyAccessors.end();
210     if (bRet)
211     {
212         const  ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
213         if (_pPropName)
214             *_pPropName = rProperty.Name;
215         if (_pAttributes)
216             *_pAttributes = rProperty.Attributes;
217     }
218     return bRet;
219 }
220 
221 //------------------------------------------------------------------------------
getPropertyByHandle(sal_Int32 _nHandle,Property & _rProperty) const222 sal_Bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
223 {
224     ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle);
225     if ( pos != m_aPropertyAccessors.end() )
226     {
227         _rProperty = m_aProperties[ pos->second.nPos ];
228         return sal_True;
229     }
230     return sal_False;
231 }
232 
233 //------------------------------------------------------------------------------
fillAggregatePropertyInfoByHandle(::rtl::OUString * _pPropName,sal_Int32 * _pOriginalHandle,sal_Int32 _nHandle) const234 sal_Bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle(
235             ::rtl::OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
236 {
237     ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
238     sal_Bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
239     if (bRet)
240     {
241         if (_pOriginalHandle)
242             *_pOriginalHandle = (*i).second.nOriginalHandle;
243         if (_pPropName)
244         {
245             OSL_ENSURE((*i).second.nPos < m_aProperties.getLength(),"Invalid index for sequence!");
246             const  ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
247             *_pPropName = rProperty.Name;
248         }
249     }
250     return bRet;
251 }
252 
253 
254 //------------------------------------------------------------------------------
getProperties()255  ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties()
256 {
257     return m_aProperties;
258 }
259 
260 
261 //------------------------------------------------------------------------------
fillHandles(sal_Int32 * _pHandles,const::com::sun::star::uno::Sequence<::rtl::OUString> & _rPropNames)262 sal_Int32 OPropertyArrayAggregationHelper::fillHandles(
263         sal_Int32* _pHandles, const  ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropNames )
264 {
265     sal_Int32 nHitCount = 0;
266     const ::rtl::OUString* pReqProps = _rPropNames.getConstArray();
267     sal_Int32 nReqLen = _rPropNames.getLength();
268 
269 #if OSL_DEBUG_LEVEL > 0
270     // assure that the sequence is sorted
271     {
272         const ::rtl::OUString* pLookup = _rPropNames.getConstArray();
273         const ::rtl::OUString* pEnd = _rPropNames.getConstArray() + _rPropNames.getLength() - 1;
274         for (; pLookup < pEnd; ++pLookup)
275         {
276             const ::rtl::OUString* pCompare = pLookup + 1;
277             const ::rtl::OUString* pCompareEnd = pEnd + 1;
278             for (; pCompare < pCompareEnd; ++pCompare)
279             {
280                 OSL_ENSURE(pLookup->compareTo(*pCompare) < 0, "OPropertyArrayAggregationHelper::fillHandles : property names are not sorted!");
281             }
282         }
283     }
284 #endif
285 
286     const  ::com::sun::star::beans::Property* pCur = m_aProperties.getConstArray();
287     const  ::com::sun::star::beans::Property* pEnd = m_aProperties.getConstArray() + m_aProperties.getLength();
288 
289     for( sal_Int32 i = 0; i < nReqLen; ++i )
290     {
291         // Logarithmus ermitteln
292         sal_uInt32 n = (sal_uInt32)(pEnd - pCur);
293         sal_Int32 nLog = 0;
294         while( n )
295         {
296             nLog += 1;
297             n = n >> 1;
298         }
299 
300         // Anzahl der noch zu suchenden Properties * dem Log2 der verbleibenden
301         // zu dursuchenden Properties.
302         if( (nReqLen - i) * nLog >= pEnd - pCur )
303         {
304             // linear search is better
305             while( pCur < pEnd && pReqProps[i] > pCur->Name )
306             {
307                 pCur++;
308             }
309             if( pCur < pEnd && pReqProps[i] == pCur->Name )
310             {
311                 _pHandles[i] = pCur->Handle;
312                 nHitCount++;
313             }
314             else
315                 _pHandles[i] = -1;
316         }
317         else
318         {
319             // binary search is better
320             sal_Int32   nCompVal = 1;
321             const  ::com::sun::star::beans::Property*  pOldEnd = pEnd--;
322             const  ::com::sun::star::beans::Property*  pMid = pCur;
323 
324             while( nCompVal != 0 && pCur <= pEnd )
325             {
326                 pMid = (pEnd - pCur) / 2 + pCur;
327 
328                 nCompVal = pReqProps[i].compareTo( pMid->Name );
329 
330                 if( nCompVal > 0 )
331                     pCur = pMid + 1;
332                 else
333                     pEnd = pMid - 1;
334             }
335 
336             if( nCompVal == 0 )
337             {
338                 _pHandles[i] = pMid->Handle;
339                 nHitCount++;
340                 pCur = pMid +1;
341             }
342             else if( nCompVal > 0 )
343             {
344                 _pHandles[i] = -1;
345                 pCur = pMid + 1;
346             }
347             else
348             {
349                 _pHandles[i] = -1;
350                 pCur = pMid;
351             }
352             pEnd = pOldEnd;
353         }
354     }
355     return nHitCount;
356 }
357 
358 //==================================================================
359 //= PropertyForwarder
360 //==================================================================
361 namespace internal
362 {
363     class PropertyForwarder
364     {
365     private:
366         OPropertySetAggregationHelper&  m_rAggregationHelper;
367         ::std::set< sal_Int32 >         m_aProperties;
368         sal_Int32                       m_nCurrentlyForwarding;
369 
370     public:
371         PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper );
372         ~PropertyForwarder();
373 
374         /** declares that the forwarder should be responsible for the given property
375 
376         @param _nHandle
377             the public handle (<em>not</em> the original handle!) of the property
378         */
379         void    takeResponsibilityFor( sal_Int32 _nHandle );
380 
381         /** checks whether the forwarder is responsible for the given property
382         */
383         bool    isResponsibleFor( sal_Int32 _nHandle );
384 
385         /// actually forwards a property value to the aggregate
386         void    doForward( sal_Int32 _nHandle, const Any& _rValue );
387 
getCurrentlyForwardedProperty() const388         sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
389     };
390 
391     //--------------------------------------------------------------------------
PropertyForwarder(OPropertySetAggregationHelper & _rAggregationHelper)392     PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
393         :m_rAggregationHelper( _rAggregationHelper )
394         ,m_nCurrentlyForwarding( -1 )
395     {
396     }
397 
398     //--------------------------------------------------------------------------
~PropertyForwarder()399     PropertyForwarder::~PropertyForwarder()
400     {
401     }
402 
403     //--------------------------------------------------------------------------
takeResponsibilityFor(sal_Int32 _nHandle)404     void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
405     {
406         m_aProperties.insert( _nHandle );
407     }
408 
409     //--------------------------------------------------------------------------
isResponsibleFor(sal_Int32 _nHandle)410     bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle )
411     {
412         return m_aProperties.find( _nHandle ) != m_aProperties.end();
413     }
414 
415     //--------------------------------------------------------------------------
doForward(sal_Int32 _nHandle,const Any & _rValue)416     void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue )
417     {
418         OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" );
419         if ( m_rAggregationHelper.m_xAggregateSet.is() )
420         {
421             m_rAggregationHelper.forwardingPropertyValue( _nHandle );
422 
423             OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
424             m_nCurrentlyForwarding = _nHandle;
425 
426             try
427             {
428                 m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue );
429                     // TODO: cache the property name? (it's a O(log n) search)
430             }
431             catch( const Exception& )
432             {
433                 m_rAggregationHelper.forwardedPropertyValue( _nHandle, false );
434                 throw;
435             }
436 
437             m_nCurrentlyForwarding = -1;
438 
439             m_rAggregationHelper.forwardedPropertyValue( _nHandle, true );
440         }
441     }
442 }
443 
444 //==================================================================
445 //= OPropertySetAggregationHelper
446 //==================================================================
447 
448 //------------------------------------------------------------------------------
OPropertySetAggregationHelper(::cppu::OBroadcastHelper & rBHlp)449 OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
450     :OPropertyStateHelper( rBHlp )
451     ,m_bListening( sal_False )
452 {
453     m_pForwarder = new PropertyForwarder( *this );
454 }
455 
456 //------------------------------------------------------------------------------
~OPropertySetAggregationHelper()457 OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
458 {
459     delete m_pForwarder;
460 }
461 
462 //------------------------------------------------------------------------------
queryInterface(const::com::sun::star::uno::Type & _rType)463  ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const  ::com::sun::star::uno::Type& _rType)
464 {
465      ::com::sun::star::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
466 
467     if ( !aReturn.hasValue() )
468         aReturn = cppu::queryInterface(_rType
469         ,static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this)
470         ,static_cast< ::com::sun::star::beans::XVetoableChangeListener*>(this)
471         ,static_cast< ::com::sun::star::lang::XEventListener*>(static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this))
472         );
473 
474     return aReturn;
475 }
476 
477 //------------------------------------------------------------------------------
disposing()478 void OPropertySetAggregationHelper::disposing()
479 {
480     osl::MutexGuard aGuard(rBHelper.rMutex);
481 
482     if ( m_xAggregateSet.is() && m_bListening )
483     {
484         // als einziger Listener anmelden
485         m_xAggregateMultiSet->removePropertiesChangeListener(this);
486         m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this);
487         m_bListening = sal_False;
488     }
489 
490     OPropertyStateHelper::disposing();
491 }
492 
493 //------------------------------------------------------------------------------
disposing(const::com::sun::star::lang::EventObject & _rSource)494 void SAL_CALL OPropertySetAggregationHelper::disposing(const  ::com::sun::star::lang::EventObject& _rSource)
495 {
496     OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !");
497     if (_rSource.Source == m_xAggregateSet)
498         m_bListening = sal_False;
499 }
500 
501 //------------------------------------------------------------------------------
propertiesChange(const::com::sun::star::uno::Sequence<::com::sun::star::beans::PropertyChangeEvent> & _rEvents)502 void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const  ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& _rEvents)
503 {
504     OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
505 
506     sal_Int32 nLen = _rEvents.getLength();
507     cppu::IPropertyArrayHelper& rPH = getInfoHelper();
508 
509     if (1 == nLen)
510     {
511         const  ::com::sun::star::beans::PropertyChangeEvent& evt = _rEvents.getConstArray()[0];
512         OSL_ENSURE( !evt.PropertyName.isEmpty(), "OPropertySetAggregationHelper::propertiesChange : invalid event !");
513             // we had a bug where this assertion would have us saved a whole day :) (72514)
514         sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
515 
516         // If nHandle is -1 the event marks a (aggregate) property which we hide to callers
517         // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered
518         // setting this property. In this case, it will be notified later (by the OPropertySetHelper
519         // implementation)
520 
521         if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
522             fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, sal_False);
523     }
524     else
525     {
526         sal_Int32* pHandles = new sal_Int32[nLen];
527          ::com::sun::star::uno::Any* pNewValues = new  ::com::sun::star::uno::Any[nLen];
528          ::com::sun::star::uno::Any* pOldValues = new  ::com::sun::star::uno::Any[nLen];
529 
530         const  ::com::sun::star::beans::PropertyChangeEvent* pEvents = _rEvents.getConstArray();
531         sal_Int32 nDest = 0;
532         for (sal_Int32 nSource=0; nSource<nLen; ++nSource, ++pEvents)
533         {
534             sal_Int32 nHandle = rPH.getHandleByName(pEvents->PropertyName);
535             if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
536             {   // same as above : -1 is valid (73247) ...
537                 pHandles[nDest] = nHandle;
538                 pNewValues[nDest] = pEvents->NewValue;
539                 pOldValues[nDest] = pEvents->OldValue;
540                 ++nDest;
541             }
542         }
543 
544         if (nDest)
545             fire(pHandles, pNewValues, pOldValues, nDest, sal_False);
546 
547         delete[] pHandles;
548         delete[] pNewValues;
549         delete[] pOldValues;
550     }
551 }
552 
553 //------------------------------------------------------------------------------
vetoableChange(const::com::sun::star::beans::PropertyChangeEvent & _rEvent)554 void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const  ::com::sun::star::beans::PropertyChangeEvent& _rEvent)
555 {
556     OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !");
557 
558     cppu::IPropertyArrayHelper& rPH = getInfoHelper();
559 
560     sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName);
561     fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, sal_True);
562 }
563 
564 //------------------------------------------------------------------------------
setAggregation(const::com::sun::star::uno::Reference<::com::sun::star::uno::XInterface> & _rxDelegate)565 void OPropertySetAggregationHelper::setAggregation(const  ::com::sun::star::uno::Reference<  ::com::sun::star::uno::XInterface >& _rxDelegate)
566 {
567     osl::MutexGuard aGuard(rBHelper.rMutex);
568 
569     if (m_bListening && m_xAggregateSet.is())
570     {
571         m_xAggregateMultiSet->removePropertiesChangeListener(this);
572         m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this);
573         m_bListening = sal_False;
574     }
575 
576     m_xAggregateState       =  m_xAggregateState.query( _rxDelegate );
577     m_xAggregateSet         =  m_xAggregateSet.query( _rxDelegate );
578     m_xAggregateMultiSet    =  m_xAggregateMultiSet.query( _rxDelegate );
579     m_xAggregateFastSet     =  m_xAggregateFastSet.query( _rxDelegate );
580 
581     // must support XPropertySet and XMultiPropertySet
582     if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
583         throw  ::com::sun::star::lang::IllegalArgumentException();
584 }
585 
586 //------------------------------------------------------------------------------
startListening()587 void OPropertySetAggregationHelper::startListening()
588 {
589     osl::MutexGuard aGuard(rBHelper.rMutex);
590 
591     if (!m_bListening && m_xAggregateSet.is())
592     {
593         // als einziger Listener anmelden
594          ::com::sun::star::uno::Sequence< ::rtl::OUString > aPropertyNames;
595         m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
596         m_xAggregateSet->addVetoableChangeListener(::rtl::OUString(), this);
597 
598         m_bListening = sal_True;
599     }
600 }
601 
602 //------------------------------------------------------------------------------
addVetoableChangeListener(const::rtl::OUString & _rPropertyName,const::com::sun::star::uno::Reference<::com::sun::star::beans::XVetoableChangeListener> & _rxListener)603 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const ::rtl::OUString& _rPropertyName,
604                                                                        const  ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener)
605 {
606     OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
607     if (!m_bListening)
608         startListening();
609 }
610 
611 //------------------------------------------------------------------------------
addPropertyChangeListener(const::rtl::OUString & _rPropertyName,const::com::sun::star::uno::Reference<::com::sun::star::beans::XPropertyChangeListener> & _rxListener)612 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const ::rtl::OUString& _rPropertyName,
613                                                                        const  ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener)
614 {
615     OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
616     if (!m_bListening)
617         startListening();
618 }
619 
620 //------------------------------------------------------------------------------
addPropertiesChangeListener(const::com::sun::star::uno::Sequence<::rtl::OUString> & _rPropertyNames,const::com::sun::star::uno::Reference<::com::sun::star::beans::XPropertiesChangeListener> & _rxListener)621 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const  ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropertyNames,
622                                                                          const  ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener)
623 {
624     OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
625     if (!m_bListening)
626         startListening();
627 }
628 
629 //------------------------------------------------------------------------------
getOriginalHandle(sal_Int32 nHandle) const630 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
631 {
632     OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
633     sal_Int32 nOriginalHandle = -1;
634     rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle);
635     return nOriginalHandle;
636 }
637 
638 //--------------------------------------------------------------------------
getPropertyName(sal_Int32 _nHandle) const639 ::rtl::OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
640 {
641     OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
642     Property aProperty;
643     OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
644     return aProperty.Name;
645 }
646 
647 //------------------------------------------------------------------------------
setFastPropertyValue(sal_Int32 _nHandle,const::com::sun::star::uno::Any & _rValue)648 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const  ::com::sun::star::uno::Any& _rValue)
649 {
650     OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
651     ::rtl::OUString aPropName;
652     sal_Int32   nOriginalHandle = -1;
653 
654     // does the handle belong to the aggregation ?
655     if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
656         if (m_xAggregateFastSet.is())
657             m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
658         else
659             m_xAggregateSet->setPropertyValue(aPropName, _rValue);
660     else
661         OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
662 }
663 
664 //------------------------------------------------------------------------------
getFastPropertyValue(::com::sun::star::uno::Any & rValue,sal_Int32 nHandle) const665 void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const
666 {
667     OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
668     ::rtl::OUString aPropName;
669     sal_Int32   nOriginalHandle = -1;
670 
671     if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
672     {
673         if (m_xAggregateFastSet.is())
674             rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
675         else
676             rValue = m_xAggregateSet->getPropertyValue(aPropName);
677     }
678     else if ( m_pForwarder->isResponsibleFor( nHandle ) )
679     {
680         // this is a property which has been "overwritten" in our instance (thus
681         // fillAggregatePropertyInfoByHandle didn't find it)
682         rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
683     }
684 }
685 
686 //------------------------------------------------------------------------------
getFastPropertyValue(sal_Int32 nHandle)687  ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
688 {
689     OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
690     ::rtl::OUString aPropName;
691     sal_Int32   nOriginalHandle = -1;
692      ::com::sun::star::uno::Any  aValue;
693 
694     if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
695     {
696         if (m_xAggregateFastSet.is())
697             aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
698         else
699             aValue = m_xAggregateSet->getPropertyValue(aPropName);
700     }
701     else
702         aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
703 
704     return aValue;
705 }
706 
707 //------------------------------------------------------------------------------
setPropertyValues(const Sequence<::rtl::OUString> & _rPropertyNames,const Sequence<Any> & _rValues)708 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
709         const Sequence< ::rtl::OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
710 {
711     OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
712     OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
713 
714     // check where the properties come from
715     if (!m_xAggregateSet.is())
716         OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
717     else if (_rPropertyNames.getLength() == 1) // use the more efficient way
718     {
719         try
720         {
721             setPropertyValue( _rPropertyNames[0], _rValues[0] );
722         }
723         catch( const UnknownPropertyException& )
724         {
725             // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
726         #if OSL_DEBUG_LEVEL > 0
727             ::rtl::OStringBuffer aMessage;
728             aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" );
729             aMessage.append( ::rtl::OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) );
730             aMessage.append( "'" );
731             aMessage.append( "\n(implementation " );
732             aMessage.append( typeid( *this ).name() );
733             aMessage.append( ")" );
734             OSL_ENSURE( false, aMessage.getStr() );
735         #endif
736         }
737     }
738     else
739     {
740         OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
741 
742         // determine which properties belong to the aggregate, and which ones to the delegator
743         const ::rtl::OUString* pNames = _rPropertyNames.getConstArray();
744         sal_Int32 nAggCount(0);
745         sal_Int32 nLen(_rPropertyNames.getLength());
746 
747         for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames )
748         {
749             OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames );
750             if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg )
751                 throw WrappedTargetException( ::rtl::OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( UnknownPropertyException( ) ) );
752                 // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException
753                 // so we wrap it into a WrappedTargetException
754                 // #107545# - 2002-02-20 - fs@openoffice.org
755 
756             if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg )
757                 ++nAggCount;
758         }
759 
760         pNames = _rPropertyNames.getConstArray();   // reset, we'll need it again below ...
761 
762         // all properties belong to the aggregate
763         if (nAggCount == nLen)
764             m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
765 
766         // all properties belong to the aggregating object
767         else if (nAggCount == 0)
768             OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
769 
770         // mixed
771         else
772         {
773             const  ::com::sun::star::uno::Any* pValues = _rValues.getConstArray();
774              ::com::sun::star::uno::Any* pConvertedValues = NULL;
775              ::com::sun::star::uno::Any* pOldValues = NULL;
776             sal_Int32*  pHandles = NULL;
777 
778             try
779             {
780                 // dividing the Names and _rValues
781 
782                 // aggregate's names
783                 Sequence< ::rtl::OUString > AggPropertyNames( nAggCount );
784                 ::rtl::OUString* pAggNames = AggPropertyNames.getArray();
785                 // aggregate's values
786                 Sequence< Any >  AggValues( nAggCount );
787                 Any* pAggValues = AggValues.getArray();
788 
789                 // delegator names
790                 Sequence< ::rtl::OUString > DelPropertyNames( nLen - nAggCount );
791                 ::rtl::OUString* pDelNames = DelPropertyNames.getArray();
792 
793                 // delegator values
794                 Sequence< Any > DelValues( nLen - nAggCount );
795                 Any* pDelValues = DelValues.getArray();
796 
797                 for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues )
798                 {
799                     if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) )
800                     {
801                         *pAggNames++ = *pNames;
802                         *pAggValues++ = *pValues;
803                     }
804                     else
805                     {
806                         *pDelNames++ = *pNames;
807                         *pDelValues++ = *pValues;
808                     }
809                 }
810 
811                 // reset, needed below
812                 pDelValues = DelValues.getArray();
813 
814                 pHandles = new sal_Int32[ nLen - nAggCount ];
815 
816                 // get the map table
817                 cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
818 
819                 // fill the handle array
820                 sal_Int32 nHitCount = rPH2.fillHandles( pHandles, DelPropertyNames );
821                 if (nHitCount != 0)
822                 {
823 
824                      pConvertedValues = new  ::com::sun::star::uno::Any[ nHitCount ];
825                      pOldValues = new  ::com::sun::star::uno::Any[ nHitCount ];
826                     nHitCount = 0;
827                     sal_Int32 i;
828 
829                     {
830                     // must lock the mutex outside the loop. So all values are consistent.
831                         osl::MutexGuard aGuard( rBHelper.rMutex );
832                         for( i = 0; i < (nLen - nAggCount); ++i )
833                         {
834                             if( pHandles[i] != -1 )
835                             {
836                                 sal_Int16 nAttributes;
837                                 rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
838                                 if( nAttributes &  ::com::sun::star::beans::PropertyAttribute::READONLY )
839                                     throw  ::com::sun::star::beans::PropertyVetoException();
840                                 // Will the property change?
841                                 if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
842                                                             pHandles[i], pDelValues[i] ) )
843                                 {
844                                     // only increment if the property really change
845                                     pHandles[nHitCount]         = pHandles[i];
846                                     nHitCount++;
847                                 }
848                             }
849                         }
850                     // release guard to fire events
851                     }
852 
853                     // fire vetoable events
854                     fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_True );
855 
856                     // setting the agg Properties
857                     m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
858 
859                     {
860                     // must lock the mutex outside the loop.
861                         osl::MutexGuard aGuard( rBHelper.rMutex );
862                         // Loop over all changed properties
863                         for( i = 0; i < nHitCount; i++ )
864                         {
865                             // Will the property change?
866                             setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
867                         }
868                     // release guard to fire events
869                     }
870 
871                     // fire change events
872                     fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_False );
873                 }
874                 else
875                     m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
876 
877             }
878             catch(::com::sun::star::uno::Exception&)
879             {
880                 delete [] pHandles;
881                 delete [] pOldValues;
882                 delete [] pConvertedValues;
883                 throw;
884             }
885 
886             delete [] pHandles;
887             delete [] pOldValues;
888             delete [] pConvertedValues;
889         }
890     }
891 }
892 
893 // XPropertyState
894 //------------------------------------------------------------------------------
getPropertyState(const::rtl::OUString & _rPropertyName)895  ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const ::rtl::OUString& _rPropertyName)
896 {
897     OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
898     sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
899 
900     if (nHandle == -1)
901     {
902         throw  ::com::sun::star::beans::UnknownPropertyException();
903     }
904 
905     ::rtl::OUString aPropName;
906     sal_Int32   nOriginalHandle = -1;
907     if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
908     {
909         if (m_xAggregateState.is())
910             return m_xAggregateState->getPropertyState(_rPropertyName);
911         else
912             return  ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
913     }
914     else
915         return getPropertyStateByHandle(nHandle);
916 }
917 
918 //------------------------------------------------------------------------------
setPropertyToDefault(const::rtl::OUString & _rPropertyName)919 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const ::rtl::OUString& _rPropertyName)
920 {
921     OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
922     sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
923     if (nHandle == -1)
924     {
925         throw  ::com::sun::star::beans::UnknownPropertyException();
926     }
927 
928     ::rtl::OUString aPropName;
929     sal_Int32   nOriginalHandle = -1;
930     if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
931     {
932         if (m_xAggregateState.is())
933             m_xAggregateState->setPropertyToDefault(_rPropertyName);
934     }
935     else
936     {
937         try
938         {
939             setPropertyToDefaultByHandle( nHandle );
940         }
941         catch( const UnknownPropertyException& ) { throw; }
942         catch( const RuntimeException& ) { throw; }
943         catch( const Exception& )
944         {
945             OSL_ENSURE( sal_False, "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
946         }
947     }
948 }
949 
950 //------------------------------------------------------------------------------
getPropertyDefault(const::rtl::OUString & aPropertyName)951  ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const ::rtl::OUString& aPropertyName)
952 {
953     OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
954     sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
955 
956     if ( nHandle == -1 )
957         throw  ::com::sun::star::beans::UnknownPropertyException();
958 
959     ::rtl::OUString aPropName;
960     sal_Int32   nOriginalHandle = -1;
961     if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
962     {
963         if (m_xAggregateState.is())
964             return m_xAggregateState->getPropertyDefault(aPropertyName);
965         else
966             return  ::com::sun::star::uno::Any();
967     }
968     else
969         return getPropertyDefaultByHandle(nHandle);
970 }
971 
972 //------------------------------------------------------------------------------
convertFastPropertyValue(Any & _rConvertedValue,Any & _rOldValue,sal_Int32 _nHandle,const Any & _rValue)973 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue )
974 {
975     sal_Bool bModified = sal_False;
976 
977     OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
978     if ( m_pForwarder->isResponsibleFor( _nHandle ) )
979     {
980         // need to determine the type of the property for conversion
981         OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
982         Property aProperty;
983         OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
984 
985         Any aCurrentValue;
986         getFastPropertyValue( aCurrentValue, _nHandle );
987         bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
988     }
989 
990     return bModified;
991 }
992 
993 //------------------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle,const Any & _rValue)994 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
995 {
996     OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
997     if ( m_pForwarder->isResponsibleFor( _nHandle ) )
998         m_pForwarder->doForward( _nHandle, _rValue );
999 }
1000 
1001 //------------------------------------------------------------------------------
declareForwardedProperty(sal_Int32 _nHandle)1002 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
1003 {
1004     OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
1005     m_pForwarder->takeResponsibilityFor( _nHandle );
1006 }
1007 
1008 //------------------------------------------------------------------------------
forwardingPropertyValue(sal_Int32)1009 void SAL_CALL OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
1010 {
1011     // not interested in
1012 }
1013 
1014 //------------------------------------------------------------------------------
forwardedPropertyValue(sal_Int32,bool)1015 void SAL_CALL OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32, bool )
1016 {
1017     // not interested in
1018 }
1019 
1020 //------------------------------------------------------------------------------
isCurrentlyForwardingProperty(sal_Int32 _nHandle) const1021 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
1022 {
1023     return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
1024 }
1025 
1026 //.........................................................................
1027 }   // namespace comphelper
1028 //.........................................................................
1029