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 
31 #ifndef _COMPHELPER_MASTERPROPERTYSET_HXX_
32 #include <comphelper/MasterPropertySet.hxx>
33 #endif
34 #include <comphelper/MasterPropertySetInfo.hxx>
35 #include <comphelper/ChainablePropertySet.hxx>
36 #include <comphelper/ChainablePropertySetInfo.hxx>
37 #include <vos/mutex.hxx>
38 
39 #include <memory>       // STL auto_ptr
40 
41 //////////////////////////////////////////////////////////////////////
42 
43 class AutoOGuardArray
44 {
45     sal_Int32                       nSize;
46     std::auto_ptr< vos::OGuard > *  pGuardArray;
47 
48 public:
49     AutoOGuardArray( sal_Int32 nNumElements );
50     ~AutoOGuardArray();
51 
52     std::auto_ptr< vos::OGuard > &  operator[] ( sal_Int32 i ) { return pGuardArray[i]; }
53 };
54 
55 AutoOGuardArray::AutoOGuardArray( sal_Int32 nNumElements )
56 {
57     nSize       = nNumElements;
58     pGuardArray = new std::auto_ptr< vos::OGuard >[ nSize ];
59 }
60 
61 AutoOGuardArray::~AutoOGuardArray()
62 {
63     //!! release auto_ptr's and thus the mutexes locks
64     delete [] pGuardArray;
65 
66 }
67 
68 //////////////////////////////////////////////////////////////////////
69 
70 using namespace ::rtl;
71 using namespace ::comphelper;
72 using namespace ::com::sun::star;
73 using namespace ::com::sun::star::uno;
74 using namespace ::com::sun::star::lang;
75 using namespace ::com::sun::star::beans;
76 using vos::IMutex;
77 
78 SlaveData::SlaveData ( ChainablePropertySet *pSlave)
79 : mpSlave ( pSlave )
80 , mxSlave ( pSlave )
81 , mbInit ( sal_False )
82 {
83 }
84 
85 MasterPropertySet::MasterPropertySet( comphelper::MasterPropertySetInfo* pInfo, IMutex *pMutex )
86 	throw()
87 : mpInfo ( pInfo )
88 , mpMutex ( pMutex )
89 , mnLastId ( 0 )
90 , mxInfo ( pInfo )
91 {
92 }
93 
94 void MasterPropertySet::lockMutex()
95 {
96 	if (mpMutex)
97 		mpMutex->acquire();
98 }
99 void MasterPropertySet::unlockMutex()
100 {
101 	if (mpMutex)
102 		mpMutex->release();
103 }
104 
105 MasterPropertySet::~MasterPropertySet()
106 	throw()
107 {
108 	SlaveMap::iterator aEnd = maSlaveMap.end(), aIter = maSlaveMap.begin();
109 	while (aIter != aEnd )
110 	{
111 		delete (*aIter).second;
112 		aIter++;
113 	}
114 }
115 
116 // XPropertySet
117 Reference< XPropertySetInfo > SAL_CALL MasterPropertySet::getPropertySetInfo(  )
118 	throw(RuntimeException)
119 {
120 	return mxInfo;
121 }
122 
123 void MasterPropertySet::registerSlave ( ChainablePropertySet *pNewSet )
124 	throw()
125 {
126 	maSlaveMap [ ++mnLastId ] = new SlaveData ( pNewSet );
127 	mpInfo->add ( pNewSet->mpInfo->maMap, mnLastId );
128 }
129 
130 void SAL_CALL MasterPropertySet::setPropertyValue( const ::rtl::OUString& rPropertyName, const Any& rValue )
131 	throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
132 {
133     // acquire mutex in c-tor and releases it in the d-tor (exception safe!).
134     std::auto_ptr< vos::OGuard > pMutexGuard;
135     if (mpMutex)
136         pMutexGuard.reset( new vos::OGuard(mpMutex) );
137 
138     PropertyDataHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName );
139 
140 	if( aIter == mpInfo->maMap.end())
141 		throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) );
142 
143 	if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours !
144 	{
145 		_preSetValues();
146 		_setSingleValue( *((*aIter).second->mpInfo), rValue );
147 		_postSetValues();
148 	}
149 	else
150 	{
151         ChainablePropertySet * pSlave = maSlaveMap [ (*aIter).second->mnMapId ]->mpSlave;
152 
153         // acquire mutex in c-tor and releases it in the d-tor (exception safe!).
154         std::auto_ptr< vos::OGuard > pMutexGuard2;
155         if (pSlave->mpMutex)
156             pMutexGuard2.reset( new vos::OGuard(pSlave->mpMutex) );
157 
158 		pSlave->_preSetValues();
159 		pSlave->_setSingleValue( *((*aIter).second->mpInfo), rValue );
160 		pSlave->_postSetValues();
161 	}
162 }
163 
164 Any SAL_CALL MasterPropertySet::getPropertyValue( const ::rtl::OUString& rPropertyName )
165 	throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
166 {
167     // acquire mutex in c-tor and releases it in the d-tor (exception safe!).
168     std::auto_ptr< vos::OGuard > pMutexGuard;
169     if (mpMutex)
170         pMutexGuard.reset( new vos::OGuard(mpMutex) );
171 
172     PropertyDataHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName );
173 
174 	if( aIter == mpInfo->maMap.end())
175 		throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) );
176 
177 	Any aAny;
178 	if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours !
179 	{
180 		_preGetValues();
181 		_getSingleValue( *((*aIter).second->mpInfo), aAny );
182 		_postGetValues();
183 	}
184 	else
185 	{
186 		ChainablePropertySet * pSlave = maSlaveMap [ (*aIter).second->mnMapId ]->mpSlave;
187 
188         // acquire mutex in c-tor and releases it in the d-tor (exception safe!).
189         std::auto_ptr< vos::OGuard > pMutexGuard2;
190         if (pSlave->mpMutex)
191             pMutexGuard2.reset( new vos::OGuard(pSlave->mpMutex) );
192 
193 		pSlave->_preGetValues();
194 		pSlave->_getSingleValue( *((*aIter).second->mpInfo), aAny );
195 		pSlave->_postGetValues();
196 	}
197 	return aAny;
198 }
199 
200 void SAL_CALL MasterPropertySet::addPropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& )
201 	throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
202 {
203 	// todo
204 }
205 
206 void SAL_CALL MasterPropertySet::removePropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& )
207 	throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
208 {
209 	// todo
210 }
211 
212 void SAL_CALL MasterPropertySet::addVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& )
213 	throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
214 {
215 	// todo
216 }
217 
218 void SAL_CALL MasterPropertySet::removeVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& )
219 	throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
220 {
221 	// todo
222 }
223 
224 // XMultiPropertySet
225 void SAL_CALL MasterPropertySet::setPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames, const Sequence< Any >& aValues )
226 	throw(PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
227 {
228     // acquire mutex in c-tor and releases it in the d-tor (exception safe!).
229     std::auto_ptr< vos::OGuard > pMutexGuard;
230     if (mpMutex)
231         pMutexGuard.reset( new vos::OGuard(mpMutex) );
232 
233     const sal_Int32 nCount = aPropertyNames.getLength();
234 
235 	if( nCount != aValues.getLength() )
236 		throw IllegalArgumentException();
237 
238 	if( nCount )
239 	{
240 		_preSetValues();
241 
242 		const Any * pAny = aValues.getConstArray();
243 		const OUString * pString = aPropertyNames.getConstArray();
244 		PropertyDataHash::const_iterator aEnd = mpInfo->maMap.end(), aIter;
245 
246         //!! have an auto_ptr to an array of OGuards in order to have the
247         //!! allocated memory properly freed (exception safe!).
248         //!! Since the array itself has auto_ptrs as members we have to use a
249         //!! helper class 'AutoOGuardArray' in order to have
250         //!! the acquired locks properly released.
251         AutoOGuardArray aOGuardArray( nCount );
252 
253 		for ( sal_Int32 i = 0; i < nCount; ++i, ++pString, ++pAny )
254 		{
255 			aIter = mpInfo->maMap.find ( *pString );
256 			if ( aIter == aEnd )
257 				throw UnknownPropertyException( *pString, static_cast< XPropertySet* >( this ) );
258 
259 			if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours !
260 				_setSingleValue( *((*aIter).second->mpInfo), *pAny );
261 			else
262 			{
263 				SlaveData * pSlave = maSlaveMap [ (*aIter).second->mnMapId ];
264 				if (!pSlave->IsInit())
265 				{
266                     // acquire mutex in c-tor and releases it in the d-tor (exception safe!).
267                     if (pSlave->mpSlave->mpMutex)
268                         aOGuardArray[i].reset( new vos::OGuard(pSlave->mpSlave->mpMutex) );
269 
270 					pSlave->mpSlave->_preSetValues();
271 					pSlave->SetInit ( sal_True );
272 				}
273 				pSlave->mpSlave->_setSingleValue( *((*aIter).second->mpInfo), *pAny );
274 			}
275 		}
276 
277 		_postSetValues();
278 		SlaveMap::const_iterator aSlaveIter = maSlaveMap.begin(), aSlaveEnd = maSlaveMap.end();
279 		while (aSlaveIter != aSlaveEnd)
280 		{
281 			if ( (*aSlaveIter).second->IsInit())
282 			{
283 				(*aSlaveIter).second->mpSlave->_postSetValues();
284 				(*aSlaveIter).second->SetInit ( sal_False );
285 			}
286 			++aSlaveIter;
287 		}
288 	}
289 }
290 
291 Sequence< Any > SAL_CALL MasterPropertySet::getPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames )
292 	throw(RuntimeException)
293 {
294     // acquire mutex in c-tor and releases it in the d-tor (exception safe!).
295     std::auto_ptr< vos::OGuard > pMutexGuard;
296     if (mpMutex)
297         pMutexGuard.reset( new vos::OGuard(mpMutex) );
298 
299     const sal_Int32 nCount = aPropertyNames.getLength();
300 
301 	Sequence < Any > aValues ( nCount );
302 
303 	if( nCount )
304 	{
305 		_preGetValues();
306 
307 		Any * pAny = aValues.getArray();
308 		const OUString * pString = aPropertyNames.getConstArray();
309 		PropertyDataHash::const_iterator aEnd = mpInfo->maMap.end(), aIter;
310 
311         //!! have an auto_ptr to an array of OGuards in order to have the
312         //!! allocated memory properly freed (exception safe!).
313         //!! Since the array itself has auto_ptrs as members we have to use a
314         //!! helper class 'AutoOGuardArray' in order to have
315         //!! the acquired locks properly released.
316         AutoOGuardArray aOGuardArray( nCount );
317 
318 		for ( sal_Int32 i = 0; i < nCount; ++i, ++pString, ++pAny )
319 		{
320 			aIter = mpInfo->maMap.find ( *pString );
321 			if ( aIter == aEnd )
322 				throw UnknownPropertyException( *pString, static_cast< XPropertySet* >( this ) );
323 
324 			if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours !
325 				_getSingleValue( *((*aIter).second->mpInfo), *pAny );
326 			else
327 			{
328 				SlaveData * pSlave = maSlaveMap [ (*aIter).second->mnMapId ];
329 				if (!pSlave->IsInit())
330 				{
331                     // acquire mutex in c-tor and releases it in the d-tor (exception safe!).
332                     if (pSlave->mpSlave->mpMutex)
333                         aOGuardArray[i].reset( new vos::OGuard(pSlave->mpSlave->mpMutex) );
334 
335 					pSlave->mpSlave->_preGetValues();
336 					pSlave->SetInit ( sal_True );
337 				}
338 				pSlave->mpSlave->_getSingleValue( *((*aIter).second->mpInfo), *pAny );
339 			}
340 		}
341 
342 		_postSetValues();
343 		SlaveMap::const_iterator aSlaveIter = maSlaveMap.begin(), aSlaveEnd = maSlaveMap.end();
344 		while (aSlaveIter != aSlaveEnd)
345 		{
346 			if ( (*aSlaveIter).second->IsInit())
347 			{
348 				(*aSlaveIter).second->mpSlave->_postSetValues();
349 				(*aSlaveIter).second->SetInit ( sal_False );
350 			}
351 			++aSlaveIter;
352 		}
353 	}
354 	return aValues;
355 }
356 
357 void SAL_CALL MasterPropertySet::addPropertiesChangeListener( const Sequence< ::rtl::OUString >&, const Reference< XPropertiesChangeListener >& )
358 	throw(RuntimeException)
359 {
360 	// todo
361 }
362 
363 void SAL_CALL MasterPropertySet::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& )
364 	throw(RuntimeException)
365 {
366 	// todo
367 }
368 
369 void SAL_CALL MasterPropertySet::firePropertiesChangeEvent( const Sequence< ::rtl::OUString >&, const Reference< XPropertiesChangeListener >& )
370 	throw(RuntimeException)
371 {
372 	// todo
373 }
374 
375 // XPropertyState
376 PropertyState SAL_CALL MasterPropertySet::getPropertyState( const ::rtl::OUString& PropertyName )
377 	throw(UnknownPropertyException, RuntimeException)
378 {
379 	PropertyDataHash::const_iterator aIter =  mpInfo->maMap.find( PropertyName );
380 	if( aIter == mpInfo->maMap.end())
381 		throw UnknownPropertyException( PropertyName, static_cast< XPropertySet* >( this ) );
382 
383 	PropertyState aState;
384 
385 	if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours !
386 	{
387 		_preGetPropertyState();
388 		_getPropertyState( *((*aIter).second->mpInfo), aState );
389 		_postGetPropertyState();
390 	}
391 	else
392 	{
393 		ChainablePropertySet * pSlave = maSlaveMap [ (*aIter).second->mnMapId ]->mpSlave;
394 
395         // acquire mutex in c-tor and releases it in the d-tor (exception safe!).
396         std::auto_ptr< vos::OGuard > pMutexGuard;
397         if (pSlave->mpMutex)
398             pMutexGuard.reset( new vos::OGuard(pSlave->mpMutex) );
399 
400 		pSlave->_preGetPropertyState();
401 		pSlave->_getPropertyState( *((*aIter).second->mpInfo), aState );
402 		pSlave->_postGetPropertyState();
403 	}
404 
405 	return aState;
406 }
407 
408 Sequence< PropertyState > SAL_CALL MasterPropertySet::getPropertyStates( const Sequence< ::rtl::OUString >& rPropertyNames )
409 	throw(UnknownPropertyException, RuntimeException)
410 {
411 	const sal_Int32 nCount = rPropertyNames.getLength();
412 
413 	Sequence< PropertyState > aStates( nCount );
414 	if( nCount )
415 	{
416 		PropertyState * pState = aStates.getArray();
417 		const OUString * pString = rPropertyNames.getConstArray();
418 		PropertyDataHash::const_iterator aEnd = mpInfo->maMap.end(), aIter;
419 		_preGetPropertyState();
420 
421 		for ( sal_Int32 i = 0; i < nCount; ++i, ++pString, ++pState )
422 		{
423 			aIter = mpInfo->maMap.find ( *pString );
424 			if ( aIter == aEnd )
425 				throw UnknownPropertyException( *pString, static_cast< XPropertySet* >( this ) );
426 
427 			if ( (*aIter).second->mnMapId == 0 ) // 0 means it's one of ours !
428 				_getPropertyState( *((*aIter).second->mpInfo), *pState );
429 			else
430 			{
431 				SlaveData * pSlave = maSlaveMap [ (*aIter).second->mnMapId ];
432 				if (!pSlave->IsInit())
433 				{
434 					pSlave->mpSlave->_preGetPropertyState();
435 					pSlave->SetInit ( sal_True );
436 				}
437 				pSlave->mpSlave->_getPropertyState( *((*aIter).second->mpInfo), *pState );
438 			}
439 		}
440 		_postGetPropertyState();
441 		SlaveMap::const_iterator aSlaveIter = maSlaveMap.begin(), aSlaveEnd = maSlaveMap.end();
442 		while (aSlaveIter != aSlaveEnd)
443 		{
444 			if ( (*aSlaveIter).second->IsInit())
445 			{
446 				(*aSlaveIter).second->mpSlave->_postGetPropertyState();
447 				(*aSlaveIter).second->SetInit ( sal_False );
448 			}
449 			++aSlaveIter;
450 		}
451 	}
452 	return aStates;
453 }
454 
455 void SAL_CALL MasterPropertySet::setPropertyToDefault( const ::rtl::OUString& rPropertyName )
456 	throw(UnknownPropertyException, RuntimeException)
457 {
458 	PropertyDataHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName );
459 
460 	if( aIter == mpInfo->maMap.end())
461 		throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) );
462 	_setPropertyToDefault( *((*aIter).second->mpInfo) );
463 }
464 
465 Any SAL_CALL MasterPropertySet::getPropertyDefault( const ::rtl::OUString& rPropertyName )
466 	throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
467 {
468 	PropertyDataHash::const_iterator aIter = mpInfo->maMap.find ( rPropertyName );
469 
470 	if( aIter == mpInfo->maMap.end())
471 		throw UnknownPropertyException( rPropertyName, static_cast< XPropertySet* >( this ) );
472 	return _getPropertyDefault( *((*aIter).second->mpInfo) );
473 }
474 
475 void MasterPropertySet::_preGetPropertyState ()
476 	throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException )
477 {
478 	OSL_ENSURE( sal_False, "you have to implement this yourself!");
479 }
480 
481 void MasterPropertySet::_getPropertyState( const comphelper::PropertyInfo&, PropertyState& )
482 	throw(UnknownPropertyException )
483 {
484 	OSL_ENSURE( sal_False, "you have to implement this yourself!");
485 }
486 
487 void MasterPropertySet::_postGetPropertyState ()
488 	throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException )
489 {
490 	OSL_ENSURE( sal_False, "you have to implement this yourself!");
491 }
492 
493 void MasterPropertySet::_setPropertyToDefault( const comphelper::PropertyInfo& )
494 	throw(UnknownPropertyException )
495 {
496 	OSL_ENSURE( sal_False, "you have to implement this yourself!");
497 }
498 
499 Any MasterPropertySet::_getPropertyDefault( const comphelper::PropertyInfo& )
500 	throw(UnknownPropertyException, WrappedTargetException )
501 {
502 	OSL_ENSURE( sal_False, "you have to implement this yourself!");
503 	Any aAny;
504 	return aAny;
505 }
506