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