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 	{
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 //------------------------------------------------------------------------------
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 //------------------------------------------------------------------
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 //------------------------------------------------------------------
175 Property OPropertyArrayAggregationHelper::getPropertyByName( const ::rtl::OUString& _rPropertyName ) throw( UnknownPropertyException )
176 {
177 	const Property* pProperty = findPropertyByName( _rPropertyName );
178 
179 	if ( !pProperty )
180 		throw  UnknownPropertyException();
181 
182 	return *pProperty;
183 }
184 
185 //------------------------------------------------------------------------------
186 sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const ::rtl::OUString& _rPropertyName)
187 {
188 	return NULL != findPropertyByName( _rPropertyName );
189 }
190 
191 //------------------------------------------------------------------------------
192 const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: rtl::OUString& _rName ) const
193 {
194 	return lcl_findPropertyByName( m_aProperties, _rName );
195 }
196 
197 //------------------------------------------------------------------------------
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 //------------------------------------------------------------------------------
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 //------------------------------------------------------------------------------
222 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 //------------------------------------------------------------------------------
234 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 //------------------------------------------------------------------------------
255  ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties()
256 {
257 	return m_aProperties;
258 }
259 
260 
261 //------------------------------------------------------------------------------
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 ) throw ( Exception );
387 
388         sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
389     };
390 
391     //--------------------------------------------------------------------------
392     PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
393         :m_rAggregationHelper( _rAggregationHelper )
394         ,m_nCurrentlyForwarding( -1 )
395     {
396     }
397 
398     //--------------------------------------------------------------------------
399     PropertyForwarder::~PropertyForwarder()
400     {
401     }
402 
403     //--------------------------------------------------------------------------
404     void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
405     {
406         m_aProperties.insert( _nHandle );
407     }
408 
409     //--------------------------------------------------------------------------
410     bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle )
411     {
412         return m_aProperties.find( _nHandle ) != m_aProperties.end();
413     }
414 
415     //--------------------------------------------------------------------------
416     void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
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 //------------------------------------------------------------------------------
449 OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
450     :OPropertyStateHelper( rBHlp )
451     ,m_bListening( sal_False )
452 {
453     m_pForwarder = new PropertyForwarder( *this );
454 }
455 
456 //------------------------------------------------------------------------------
457 OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
458 {
459     delete m_pForwarder;
460 }
461 
462 //------------------------------------------------------------------------------
463  ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const  ::com::sun::star::uno::Type& _rType) throw( ::com::sun::star::uno::RuntimeException)
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 //------------------------------------------------------------------------------
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 //------------------------------------------------------------------------------
494 void SAL_CALL OPropertySetAggregationHelper::disposing(const  ::com::sun::star::lang::EventObject& _rSource) throw ( ::com::sun::star::uno::RuntimeException)
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 //------------------------------------------------------------------------------
502 void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const  ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& _rEvents) throw( ::com::sun::star::uno::RuntimeException)
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.getLength() > 0, "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 //------------------------------------------------------------------------------
554 void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const  ::com::sun::star::beans::PropertyChangeEvent& _rEvent) throw( ::com::sun::star::beans::PropertyVetoException,  ::com::sun::star::uno::RuntimeException)
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 //------------------------------------------------------------------------------
565 void OPropertySetAggregationHelper::setAggregation(const  ::com::sun::star::uno::Reference<  ::com::sun::star::uno::XInterface >& _rxDelegate)
566 		throw(  ::com::sun::star::lang::IllegalArgumentException )
567 {
568 	osl::MutexGuard aGuard(rBHelper.rMutex);
569 
570 	if (m_bListening && m_xAggregateSet.is())
571 	{
572 		m_xAggregateMultiSet->removePropertiesChangeListener(this);
573 		m_xAggregateSet->removeVetoableChangeListener(::rtl::OUString(), this);
574 		m_bListening = sal_False;
575 	}
576 
577 	m_xAggregateState		=  m_xAggregateState.query( _rxDelegate );
578 	m_xAggregateSet			=  m_xAggregateSet.query( _rxDelegate );
579 	m_xAggregateMultiSet	=  m_xAggregateMultiSet.query( _rxDelegate );
580 	m_xAggregateFastSet		=  m_xAggregateFastSet.query( _rxDelegate );
581 
582 	// must support XPropertySet and XMultiPropertySet
583 	if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
584 		throw  ::com::sun::star::lang::IllegalArgumentException();
585 }
586 
587 //------------------------------------------------------------------------------
588 void OPropertySetAggregationHelper::startListening()
589 {
590 	osl::MutexGuard aGuard(rBHelper.rMutex);
591 
592 	if (!m_bListening && m_xAggregateSet.is())
593 	{
594 		// als einziger Listener anmelden
595 		 ::com::sun::star::uno::Sequence< ::rtl::OUString > aPropertyNames;
596 		m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
597 		m_xAggregateSet->addVetoableChangeListener(::rtl::OUString(), this);
598 
599 		m_bListening = sal_True;
600 	}
601 }
602 
603 //------------------------------------------------------------------------------
604 void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const ::rtl::OUString& _rPropertyName,
605 																	   const  ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener)
606 																	   throw( ::com::sun::star::beans::UnknownPropertyException,  ::com::sun::star::lang::WrappedTargetException,  ::com::sun::star::uno::RuntimeException)
607 {
608 	OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
609 	if (!m_bListening)
610 		startListening();
611 }
612 
613 //------------------------------------------------------------------------------
614 void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const ::rtl::OUString& _rPropertyName,
615 																	   const  ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener)
616 																	   throw( ::com::sun::star::beans::UnknownPropertyException,  ::com::sun::star::lang::WrappedTargetException,  ::com::sun::star::uno::RuntimeException)
617 {
618 	OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
619 	if (!m_bListening)
620 		startListening();
621 }
622 
623 //------------------------------------------------------------------------------
624 void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const  ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropertyNames,
625 																		 const  ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener)
626 																		 throw( ::com::sun::star::uno::RuntimeException)
627 {
628 	OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
629 	if (!m_bListening)
630 		startListening();
631 }
632 
633 //------------------------------------------------------------------------------
634 sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
635 {
636 	OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
637 	sal_Int32 nOriginalHandle = -1;
638 	rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle);
639 	return nOriginalHandle;
640 }
641 
642 //--------------------------------------------------------------------------
643 ::rtl::OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
644 {
645 	OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
646     Property aProperty;
647     OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
648 	return aProperty.Name;
649 }
650 
651 //------------------------------------------------------------------------------
652 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const  ::com::sun::star::uno::Any& _rValue)
653 		throw(	 ::com::sun::star::beans::UnknownPropertyException,  ::com::sun::star::beans::PropertyVetoException,
654 				 ::com::sun::star::lang::IllegalArgumentException,  ::com::sun::star::lang::WrappedTargetException,
655 				 ::com::sun::star::uno::RuntimeException)
656 {
657 	OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
658 	::rtl::OUString aPropName;
659 	sal_Int32	nOriginalHandle = -1;
660 
661 	// does the handle belong to the aggregation ?
662 	if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
663 		if (m_xAggregateFastSet.is())
664 			m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
665 		else
666 			m_xAggregateSet->setPropertyValue(aPropName, _rValue);
667 	else
668 		OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
669 }
670 
671 //------------------------------------------------------------------------------
672 void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const
673 {
674 	OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
675 	::rtl::OUString aPropName;
676 	sal_Int32	nOriginalHandle = -1;
677 
678 	if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
679 	{
680 		if (m_xAggregateFastSet.is())
681 			rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
682 		else
683 			rValue = m_xAggregateSet->getPropertyValue(aPropName);
684 	}
685     else if ( m_pForwarder->isResponsibleFor( nHandle ) )
686     {
687         // this is a property which has been "overwritten" in our instance (thus
688         // fillAggregatePropertyInfoByHandle didn't find it)
689         rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
690     }
691 }
692 
693 //------------------------------------------------------------------------------
694  ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
695 		throw(	 ::com::sun::star::beans::UnknownPropertyException,
696 				 ::com::sun::star::lang::WrappedTargetException,
697 				 ::com::sun::star::uno::RuntimeException)
698 {
699 	OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
700 	::rtl::OUString aPropName;
701 	sal_Int32	nOriginalHandle = -1;
702 	 ::com::sun::star::uno::Any  aValue;
703 
704 	if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
705 	{
706 		if (m_xAggregateFastSet.is())
707 			aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
708 		else
709 			aValue = m_xAggregateSet->getPropertyValue(aPropName);
710 	}
711 	else
712 		aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
713 
714 	return aValue;
715 }
716 
717 //------------------------------------------------------------------------------
718 void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
719 		const Sequence< ::rtl::OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
720 	throw ( PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException )
721 {
722 	OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
723 	OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
724 
725 	// check where the properties come from
726 	if (!m_xAggregateSet.is())
727 		OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
728 	else if (_rPropertyNames.getLength() == 1) // use the more efficient way
729     {
730         try
731         {
732 		    setPropertyValue( _rPropertyNames[0], _rValues[0] );
733         }
734         catch( const UnknownPropertyException& )
735         {
736             // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
737         #if OSL_DEBUG_LEVEL > 0
738             ::rtl::OStringBuffer aMessage;
739             aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" );
740             aMessage.append( ::rtl::OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) );
741             aMessage.append( "'" );
742             aMessage.append( "\n(implementation " );
743             aMessage.append( typeid( *this ).name() );
744             aMessage.append( ")" );
745             OSL_ENSURE( false, aMessage.getStr() );
746         #endif
747         }
748     }
749 	else
750 	{
751 		OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
752 
753 		// determine which properties belong to the aggregate, and which ones to the delegator
754 		const ::rtl::OUString* pNames = _rPropertyNames.getConstArray();
755 		sal_Int32 nAggCount(0);
756 		sal_Int32 nLen(_rPropertyNames.getLength());
757 
758 		for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames )
759 		{
760 			OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames );
761 			if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg )
762 				throw WrappedTargetException( ::rtl::OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( UnknownPropertyException( ) ) );
763 				// due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException
764 				// so we wrap it into a WrappedTargetException
765 				// #107545# - 2002-02-20 - fs@openoffice.org
766 
767 			if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg )
768 				++nAggCount;
769 		}
770 
771 		pNames = _rPropertyNames.getConstArray();	// reset, we'll need it again below ...
772 
773 		// all properties belong to the aggregate
774 		if (nAggCount == nLen)
775 			m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
776 
777 		// all properties belong to the aggregating object
778 		else if (nAggCount == 0)
779 			OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
780 
781 		// mixed
782 		else
783 		{
784 			const  ::com::sun::star::uno::Any* pValues = _rValues.getConstArray();
785 			 ::com::sun::star::uno::Any* pConvertedValues = NULL;
786 			 ::com::sun::star::uno::Any* pOldValues = NULL;
787 			sal_Int32*	pHandles = NULL;
788 
789 			try
790 			{
791 				// dividing the Names and _rValues
792 
793 				// aggregate's names
794 				Sequence< ::rtl::OUString > AggPropertyNames( nAggCount );
795 				::rtl::OUString* pAggNames = AggPropertyNames.getArray();
796 				// aggregate's values
797 				Sequence< Any >  AggValues( nAggCount );
798 				Any* pAggValues = AggValues.getArray();
799 
800 				// delegator names
801 				Sequence< ::rtl::OUString > DelPropertyNames( nLen - nAggCount );
802 				::rtl::OUString* pDelNames = DelPropertyNames.getArray();
803 
804 				// delegator values
805 				Sequence< Any > DelValues( nLen - nAggCount );
806 				Any* pDelValues = DelValues.getArray();
807 
808 				for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues )
809 				{
810 					if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) )
811 					{
812 						*pAggNames++ = *pNames;
813 						*pAggValues++ = *pValues;
814 					}
815 					else
816 					{
817 						*pDelNames++ = *pNames;
818 						*pDelValues++ = *pValues;
819 					}
820 				}
821 
822 				// reset, needed below
823 				pDelValues = DelValues.getArray();
824 
825 				pHandles = new sal_Int32[ nLen - nAggCount ];
826 
827 				// get the map table
828 				cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
829 
830 				// fill the handle array
831 				sal_Int32 nHitCount = rPH2.fillHandles( pHandles, DelPropertyNames );
832 				if (nHitCount != 0)
833 				{
834 
835 					 pConvertedValues = new  ::com::sun::star::uno::Any[ nHitCount ];
836 					 pOldValues = new  ::com::sun::star::uno::Any[ nHitCount ];
837 					nHitCount = 0;
838 					sal_Int32 i;
839 
840 					{
841 					// must lock the mutex outside the loop. So all values are consistent.
842 						osl::MutexGuard aGuard( rBHelper.rMutex );
843 						for( i = 0; i < (nLen - nAggCount); ++i )
844 						{
845 							if( pHandles[i] != -1 )
846 							{
847 								sal_Int16 nAttributes;
848 								rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
849 								if( nAttributes &  ::com::sun::star::beans::PropertyAttribute::READONLY )
850 									throw  ::com::sun::star::beans::PropertyVetoException();
851 								// Will the property change?
852 								if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
853 															pHandles[i], pDelValues[i] ) )
854 								{
855 									// only increment if the property really change
856 									pHandles[nHitCount]			= pHandles[i];
857 									nHitCount++;
858 								}
859 							}
860 						}
861 					// release guard to fire events
862 					}
863 
864 					// fire vetoable events
865 					fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_True );
866 
867 					// setting the agg Properties
868 					m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
869 
870 					{
871 					// must lock the mutex outside the loop.
872 						osl::MutexGuard aGuard( rBHelper.rMutex );
873 						// Loop over all changed properties
874 						for( i = 0; i < nHitCount; i++ )
875 						{
876 							// Will the property change?
877 							setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
878 						}
879 					// release guard to fire events
880 					}
881 
882 					// fire change events
883 					fire( pHandles, pConvertedValues, pOldValues, nHitCount, sal_False );
884 				}
885 				else
886 					m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
887 
888 			}
889 			catch(::com::sun::star::uno::Exception&)
890 			{
891 				delete [] pHandles;
892 				delete [] pOldValues;
893 				delete [] pConvertedValues;
894 				throw;
895 			}
896 
897 			delete [] pHandles;
898 			delete [] pOldValues;
899 			delete [] pConvertedValues;
900 		}
901 	}
902 }
903 
904 // XPropertyState
905 //------------------------------------------------------------------------------
906  ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const ::rtl::OUString& _rPropertyName)
907 			throw( ::com::sun::star::beans::UnknownPropertyException,  ::com::sun::star::uno::RuntimeException)
908 {
909 	OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
910 	sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
911 
912 	if (nHandle == -1)
913 	{
914 		throw  ::com::sun::star::beans::UnknownPropertyException();
915 	}
916 
917 	::rtl::OUString aPropName;
918 	sal_Int32	nOriginalHandle = -1;
919 	if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
920 	{
921 		if (m_xAggregateState.is())
922 			return m_xAggregateState->getPropertyState(_rPropertyName);
923 		else
924 			return  ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
925 	}
926 	else
927 		return getPropertyStateByHandle(nHandle);
928 }
929 
930 //------------------------------------------------------------------------------
931 void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const ::rtl::OUString& _rPropertyName)
932 		throw( ::com::sun::star::beans::UnknownPropertyException,  ::com::sun::star::uno::RuntimeException)
933 {
934 	OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
935 	sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
936 	if (nHandle == -1)
937 	{
938 		throw  ::com::sun::star::beans::UnknownPropertyException();
939 	}
940 
941 	::rtl::OUString aPropName;
942 	sal_Int32	nOriginalHandle = -1;
943 	if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
944 	{
945 		if (m_xAggregateState.is())
946 			m_xAggregateState->setPropertyToDefault(_rPropertyName);
947 	}
948 	else
949     {
950         try
951         {
952 		    setPropertyToDefaultByHandle( nHandle );
953         }
954         catch( const UnknownPropertyException& ) { throw; }
955         catch( const RuntimeException& ) { throw; }
956         catch( const Exception& )
957         {
958         	OSL_ENSURE( sal_False, "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
959         }
960     }
961 }
962 
963 //------------------------------------------------------------------------------
964  ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const ::rtl::OUString& aPropertyName)
965 		throw( ::com::sun::star::beans::UnknownPropertyException,  ::com::sun::star::lang::WrappedTargetException,  ::com::sun::star::uno::RuntimeException)
966 {
967 	OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
968 	sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
969 
970 	if ( nHandle == -1 )
971 		throw  ::com::sun::star::beans::UnknownPropertyException();
972 
973 	::rtl::OUString aPropName;
974 	sal_Int32	nOriginalHandle = -1;
975 	if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
976 	{
977 		if (m_xAggregateState.is())
978 			return m_xAggregateState->getPropertyDefault(aPropertyName);
979 		else
980 			return  ::com::sun::star::uno::Any();
981 	}
982 	else
983 		return getPropertyDefaultByHandle(nHandle);
984 }
985 
986 //------------------------------------------------------------------------------
987 sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
988 {
989     sal_Bool bModified = sal_False;
990 
991     OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
992     if ( m_pForwarder->isResponsibleFor( _nHandle ) )
993     {
994         // need to determine the type of the property for conversion
995 	    OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
996         Property aProperty;
997         OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
998 
999         Any aCurrentValue;
1000 		getFastPropertyValue( aCurrentValue, _nHandle );
1001 		bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
1002     }
1003 
1004     return bModified;
1005 }
1006 
1007 //------------------------------------------------------------------------------
1008 void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
1009 {
1010     OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
1011     if ( m_pForwarder->isResponsibleFor( _nHandle ) )
1012         m_pForwarder->doForward( _nHandle, _rValue );
1013 }
1014 
1015 //------------------------------------------------------------------------------
1016 void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
1017 {
1018     OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
1019     m_pForwarder->takeResponsibilityFor( _nHandle );
1020 }
1021 
1022 //------------------------------------------------------------------------------
1023 void SAL_CALL OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
1024 {
1025     // not interested in
1026 }
1027 
1028 //------------------------------------------------------------------------------
1029 void SAL_CALL OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32, bool )
1030 {
1031     // not interested in
1032 }
1033 
1034 //------------------------------------------------------------------------------
1035 bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
1036 {
1037     return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
1038 }
1039 
1040 //.........................................................................
1041 }	// namespace comphelper
1042 //.........................................................................
1043 
1044