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_toolkit.hxx"
30 #include "toolkit/controls/geometrycontrolmodel.hxx"
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/beans/PropertyAttribute.hpp>
33 #include <osl/diagnose.h>
34 #include <rtl/instance.hxx>
35 #include <comphelper/property.hxx>
36 #include <comphelper/sequence.hxx>
37 #ifndef _COM_SUN_STAR_XNAMECONTAINER_HPP_
38 #include <toolkit/controls/eventcontainer.hxx>
39 #endif
40 #include <toolkit/helper/property.hxx>
41 #include <tools/debug.hxx>
42 #include <algorithm>
43 #include <functional>
44 #include <comphelper/sequence.hxx>
45 
46 
47 #define GCM_PROPERTY_ID_POS_X		        1
48 #define GCM_PROPERTY_ID_POS_Y		        2
49 #define GCM_PROPERTY_ID_WIDTH		        3
50 #define GCM_PROPERTY_ID_HEIGHT		        4
51 #define GCM_PROPERTY_ID_NAME		        5
52 #define GCM_PROPERTY_ID_TABINDEX	        6
53 #define GCM_PROPERTY_ID_STEP		        7
54 #define GCM_PROPERTY_ID_TAG			        8
55 #define GCM_PROPERTY_ID_RESOURCERESOLVER    9
56 
57 #define GCM_PROPERTY_POS_X		        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("PositionX"))
58 #define GCM_PROPERTY_POS_Y		        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("PositionY"))
59 #define GCM_PROPERTY_WIDTH		        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Width"))
60 #define GCM_PROPERTY_HEIGHT		        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Height"))
61 #define GCM_PROPERTY_NAME		        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Name"))
62 #define GCM_PROPERTY_TABINDEX	        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TabIndex"))
63 #define GCM_PROPERTY_STEP		        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Step"))
64 #define GCM_PROPERTY_TAG		        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Tag"))
65 #define GCM_PROPERTY_RESOURCERESOLVER	::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ResourceResolver"))
66 
67 #define DEFAULT_ATTRIBS()		PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT
68 
69 //........................................................................
70 // namespace toolkit
71 // {
72 //........................................................................
73 
74 	using namespace ::com::sun::star;
75 	using namespace ::com::sun::star::uno;
76 	using namespace ::com::sun::star::lang;
77 	using namespace ::com::sun::star::beans;
78 	using namespace ::com::sun::star::util;
79 	using namespace ::com::sun::star::container;
80 	using namespace ::comphelper;
81 
82 	//====================================================================
83 	//= OGeometryControlModel_Base
84 	//====================================================================
85 	//--------------------------------------------------------------------
86 	OGeometryControlModel_Base::OGeometryControlModel_Base(::com::sun::star::uno::XAggregation* _pAggregateInstance)
87 		:OPropertySetAggregationHelper( m_aBHelper )
88 		,OPropertyContainer( m_aBHelper )
89 		,OGCM_Base( m_aMutex )
90 		,m_nPosX(0)
91 		,m_nPosY(0)
92 		,m_nWidth(0)
93 		,m_nHeight(0)
94 		,m_nTabIndex(-1)
95 		,m_nStep(0)
96 		,m_bCloneable(sal_False)
97 	{
98 		OSL_ENSURE(NULL != _pAggregateInstance, "OGeometryControlModel_Base::OGeometryControlModel_Base: invalid aggregate!");
99 
100 		increment(m_refCount);
101 		{
102 			m_xAggregate = _pAggregateInstance;
103 
104 			{	// check if the aggregat is cloneable
105 				Reference< XCloneable > xCloneAccess(m_xAggregate, UNO_QUERY);
106 				m_bCloneable = xCloneAccess.is();
107 			}
108 
109 			setAggregation(m_xAggregate);
110 			m_xAggregate->setDelegator(static_cast< XWeak* >(this));
111 		}
112 		decrement(m_refCount);
113 
114 		registerProperties();
115 	}
116 
117 	//--------------------------------------------------------------------
118 	OGeometryControlModel_Base::OGeometryControlModel_Base(Reference< XCloneable >& _rxAggregateInstance)
119 		:OPropertySetAggregationHelper( m_aBHelper )
120 		,OPropertyContainer( m_aBHelper )
121 		,OGCM_Base( m_aMutex )
122 		,m_nPosX(0)
123 		,m_nPosY(0)
124 		,m_nWidth(0)
125 		,m_nHeight(0)
126 		,m_nTabIndex(-1)
127 		,m_nStep(0)
128 		,m_bCloneable(_rxAggregateInstance.is())
129 	{
130 		increment(m_refCount);
131 		{
132             {
133                 // ensure that the temporary gets destructed NOW
134                 m_xAggregate = Reference< XAggregation >(_rxAggregateInstance, UNO_QUERY);
135             }
136 			OSL_ENSURE(m_xAggregate.is(), "OGeometryControlModel_Base::OGeometryControlModel_Base: invalid object given!");
137 
138 			// now the aggregate has a ref count of 2, but before setting the delegator it must be 1
139 			_rxAggregateInstance.clear();
140 			// now it should be the 1 we need here ...
141 
142 			setAggregation(m_xAggregate);
143 			m_xAggregate->setDelegator(static_cast< XWeak* >(this));
144 		}
145 		decrement(m_refCount);
146 
147 		registerProperties();
148 	}
149 
150 	//--------------------------------------------------------------------
151 	Sequence< Type > SAL_CALL OGeometryControlModel_Base::getTypes(  ) throw (RuntimeException)
152 	{
153 		// our own types
154 		Sequence< Type > aTypes = ::comphelper::concatSequences(
155 			OPropertySetAggregationHelper::getTypes(),
156 			OPropertyContainer::getTypes(),
157 			OGCM_Base::getTypes()
158 		);
159 
160 		if ( m_xAggregate.is() )
161 		{
162 			// retrieve the types of the aggregate
163 			Reference< XTypeProvider > xAggregateTypeProv;
164 			m_xAggregate->queryAggregation( ::getCppuType( &xAggregateTypeProv ) ) >>= xAggregateTypeProv;
165 			OSL_ENSURE( xAggregateTypeProv.is(), "OGeometryControlModel_Base::getTypes: aggregate should be a type provider!" );
166 			Sequence< Type > aAggTypes;
167 			if ( xAggregateTypeProv.is() )
168 				aAggTypes = xAggregateTypeProv->getTypes();
169 
170 			// concat the sequences
171 			sal_Int32 nOldSize = aTypes.getLength();
172 			aTypes.realloc( nOldSize + aAggTypes.getLength() );
173 			::std::copy(
174 				aAggTypes.getConstArray(),
175 				aAggTypes.getConstArray() + aAggTypes.getLength(),
176 				aTypes.getArray() + nOldSize
177 			);
178 		}
179 
180 		return aTypes;
181 	}
182 
183 	//--------------------------------------------------------------------
184 	void OGeometryControlModel_Base::registerProperties()
185 	{
186 		// register our members for the property handling of the OPropertyContainer
187 		registerProperty(GCM_PROPERTY_POS_X,	GCM_PROPERTY_ID_POS_X,		DEFAULT_ATTRIBS(), &m_nPosX, ::getCppuType(&m_nPosX));
188 		registerProperty(GCM_PROPERTY_POS_Y,	GCM_PROPERTY_ID_POS_Y,		DEFAULT_ATTRIBS(), &m_nPosY, ::getCppuType(&m_nPosY));
189 		registerProperty(GCM_PROPERTY_WIDTH,	GCM_PROPERTY_ID_WIDTH,		DEFAULT_ATTRIBS(), &m_nWidth, ::getCppuType(&m_nWidth));
190 		registerProperty(GCM_PROPERTY_HEIGHT,	GCM_PROPERTY_ID_HEIGHT,		DEFAULT_ATTRIBS(), &m_nHeight, ::getCppuType(&m_nHeight));
191 		registerProperty(GCM_PROPERTY_NAME,		GCM_PROPERTY_ID_NAME,		DEFAULT_ATTRIBS(), &m_aName, ::getCppuType(&m_aName));
192 		registerProperty(GCM_PROPERTY_TABINDEX,	GCM_PROPERTY_ID_TABINDEX,	DEFAULT_ATTRIBS(), &m_nTabIndex, ::getCppuType(&m_nTabIndex));
193 		registerProperty(GCM_PROPERTY_STEP,		GCM_PROPERTY_ID_STEP,		DEFAULT_ATTRIBS(), &m_nStep, ::getCppuType(&m_nStep));
194 		registerProperty(GCM_PROPERTY_TAG,		GCM_PROPERTY_ID_TAG,		DEFAULT_ATTRIBS(), &m_aTag, ::getCppuType(&m_aTag));
195         registerProperty(GCM_PROPERTY_RESOURCERESOLVER, GCM_PROPERTY_ID_RESOURCERESOLVER, DEFAULT_ATTRIBS(), &m_xStrResolver, ::getCppuType(&m_xStrResolver));
196 	}
197 
198 	//--------------------------------------------------------------------
199 	::com::sun::star::uno::Any OGeometryControlModel_Base::ImplGetDefaultValueByHandle(sal_Int32 nHandle) const
200 	{
201 		::com::sun::star::uno::Any aDefault;
202 
203         switch ( nHandle )
204         {
205             case GCM_PROPERTY_ID_POS_X:			    aDefault <<= (sal_Int32) 0; break;
206             case GCM_PROPERTY_ID_POS_Y:			    aDefault <<= (sal_Int32) 0; break;
207             case GCM_PROPERTY_ID_WIDTH:			    aDefault <<= (sal_Int32) 0; break;
208             case GCM_PROPERTY_ID_HEIGHT:		    aDefault <<= (sal_Int32) 0; break;
209             case GCM_PROPERTY_ID_NAME:			    aDefault <<= ::rtl::OUString(); break;
210             case GCM_PROPERTY_ID_TABINDEX:		    aDefault <<= (sal_Int16) -1; break;
211             case GCM_PROPERTY_ID_STEP:			    aDefault <<= (sal_Int32) 0; break;
212             case GCM_PROPERTY_ID_TAG:			    aDefault <<= ::rtl::OUString(); break;
213             case GCM_PROPERTY_ID_RESOURCERESOLVER:  aDefault <<= Reference< resource::XStringResourceResolver >(); break;
214             default:							DBG_ERROR( "ImplGetDefaultValueByHandle - unknown Property" );
215         }
216 
217 		return aDefault;
218 	}
219 
220 	//--------------------------------------------------------------------
221 	::com::sun::star::uno::Any OGeometryControlModel_Base::ImplGetPropertyValueByHandle(sal_Int32 nHandle) const
222 	{
223 		::com::sun::star::uno::Any aValue;
224 
225         switch ( nHandle )
226         {
227             case GCM_PROPERTY_ID_POS_X:			aValue <<= m_nPosX; break;
228             case GCM_PROPERTY_ID_POS_Y:			aValue <<= m_nPosY; break;
229             case GCM_PROPERTY_ID_WIDTH:			aValue <<= m_nWidth; break;
230             case GCM_PROPERTY_ID_HEIGHT:		aValue <<= m_nHeight; break;
231             case GCM_PROPERTY_ID_NAME:			aValue <<= m_aName; break;
232             case GCM_PROPERTY_ID_TABINDEX:		aValue <<= m_nTabIndex; break;
233             case GCM_PROPERTY_ID_STEP:			aValue <<= m_nStep; break;
234             case GCM_PROPERTY_ID_TAG:			aValue <<= m_aTag; break;
235             case GCM_PROPERTY_ID_RESOURCERESOLVER: aValue <<= m_xStrResolver; break;
236             default:							DBG_ERROR( "ImplGetPropertyValueByHandle - unknown Property" );
237         }
238 
239 		return aValue;
240 	}
241 
242 	//--------------------------------------------------------------------
243 	void OGeometryControlModel_Base::ImplSetPropertyValueByHandle(sal_Int32 nHandle, const :: com::sun::star::uno::Any& aValue)
244 	{
245         switch ( nHandle )
246         {
247             case GCM_PROPERTY_ID_POS_X:			aValue >>= m_nPosX; break;
248             case GCM_PROPERTY_ID_POS_Y:			aValue >>= m_nPosY; break;
249             case GCM_PROPERTY_ID_WIDTH:			aValue >>= m_nWidth; break;
250             case GCM_PROPERTY_ID_HEIGHT:		aValue >>= m_nHeight; break;
251             case GCM_PROPERTY_ID_NAME:			aValue >>= m_aName; break;
252             case GCM_PROPERTY_ID_TABINDEX:		aValue >>= m_nTabIndex; break;
253             case GCM_PROPERTY_ID_STEP:			aValue >>= m_nStep; break;
254             case GCM_PROPERTY_ID_TAG:			aValue >>= m_aTag; break;
255             case GCM_PROPERTY_ID_RESOURCERESOLVER: aValue >>= m_xStrResolver; break;
256             default:							DBG_ERROR( "ImplSetPropertyValueByHandle - unknown Property" );
257         }
258 	}
259 
260 	//--------------------------------------------------------------------
261 	Any SAL_CALL OGeometryControlModel_Base::queryAggregation( const Type& _rType ) throw(RuntimeException)
262 	{
263 		Any aReturn;
264 		if (_rType.equals(::getCppuType(static_cast< Reference< XCloneable>* >(NULL))) && !m_bCloneable)
265 			// somebody is asking for the XCloneable interface, but our aggregate does not support it
266 			// -> outta here
267 			// (need this extra check, cause OGCM_Base::queryAggregation would return this interface
268 			// in every case)
269 			return aReturn;
270 
271 		aReturn = OGCM_Base::queryAggregation(_rType);
272 			// the basic interfaces (XInterface, XAggregation etc)
273 
274 		if (!aReturn.hasValue())
275 			aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
276 			// the property set related interfaces
277 
278 		if (!aReturn.hasValue() && m_xAggregate.is())
279 			aReturn = m_xAggregate->queryAggregation(_rType);
280 			// the interfaces our aggregate can provide
281 
282 		return aReturn;
283 	}
284 
285 	//--------------------------------------------------------------------
286 	Any SAL_CALL OGeometryControlModel_Base::queryInterface( const Type& _rType ) throw(RuntimeException)
287 	{
288 		return OGCM_Base::queryInterface(_rType);
289 	}
290 
291 	//--------------------------------------------------------------------
292 	void SAL_CALL OGeometryControlModel_Base::acquire(  ) throw()
293 	{
294 		OGCM_Base::acquire();
295 	}
296 
297 	//--------------------------------------------------------------------
298 	void SAL_CALL OGeometryControlModel_Base::release(  ) throw()
299 	{
300 		OGCM_Base::release();
301 	}
302 
303 	//--------------------------------------------------------------------
304 	void OGeometryControlModel_Base::releaseAggregation()
305 	{
306 		// release the aggregate (_before_ clearing m_xAggregate)
307 		if (m_xAggregate.is())
308 			m_xAggregate->setDelegator(NULL);
309 		setAggregation(NULL);
310 	}
311 
312 	//--------------------------------------------------------------------
313 	OGeometryControlModel_Base::~OGeometryControlModel_Base()
314 	{
315 		releaseAggregation();
316 	}
317 
318 	//--------------------------------------------------------------------
319 	sal_Bool SAL_CALL OGeometryControlModel_Base::convertFastPropertyValue(Any& _rConvertedValue, Any& _rOldValue,
320 			sal_Int32 _nHandle, const Any& _rValue) throw (IllegalArgumentException)
321 	{
322 		return OPropertyContainer::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
323 	}
324 
325 	//--------------------------------------------------------------------
326 	void SAL_CALL OGeometryControlModel_Base::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) throw (Exception)
327 	{
328 		OPropertyContainer::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
329 	}
330 
331 	//--------------------------------------------------------------------
332 	void SAL_CALL OGeometryControlModel_Base::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
333 	{
334 		OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>(const_cast<OGeometryControlModel_Base*>(this)->getInfoHelper());
335 		::rtl::OUString sPropName;
336 		sal_Int32	nOriginalHandle = -1;
337 
338 		if (rPH.fillAggregatePropertyInfoByHandle(&sPropName, &nOriginalHandle, _nHandle))
339 			OPropertySetAggregationHelper::getFastPropertyValue(_rValue, _nHandle);
340 		else
341 			OPropertyContainer::getFastPropertyValue(_rValue, _nHandle);
342 	}
343 
344 	//--------------------------------------------------------------------
345 	::com::sun::star::beans::PropertyState OGeometryControlModel_Base::getPropertyStateByHandle(sal_Int32 nHandle)
346 	{
347 		::com::sun::star::uno::Any aValue = ImplGetPropertyValueByHandle( nHandle );
348 		::com::sun::star::uno::Any aDefault = ImplGetDefaultValueByHandle( nHandle );
349 
350 		return CompareProperties( aValue, aDefault ) ? ::com::sun::star::beans::PropertyState_DEFAULT_VALUE : ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
351 	}
352 
353 	//--------------------------------------------------------------------
354 	void OGeometryControlModel_Base::setPropertyToDefaultByHandle(sal_Int32 nHandle)
355 	{
356 		ImplSetPropertyValueByHandle( nHandle , ImplGetDefaultValueByHandle( nHandle ) );
357 	}
358 
359 	//--------------------------------------------------------------------
360 	::com::sun::star::uno::Any OGeometryControlModel_Base::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
361 	{
362 		return ImplGetDefaultValueByHandle( nHandle );
363 	}
364 
365 	//--------------------------------------------------------------------
366 	Reference< XPropertySetInfo> SAL_CALL OGeometryControlModel_Base::getPropertySetInfo() throw(RuntimeException)
367 	{
368 		return OPropertySetAggregationHelper::createPropertySetInfo(getInfoHelper());
369 	}
370 
371 	//--------------------------------------------------------------------
372 	Reference< XCloneable > SAL_CALL OGeometryControlModel_Base::createClone(  ) throw(RuntimeException)
373 	{
374 		OSL_ENSURE(m_bCloneable, "OGeometryControlModel_Base::createClone: invalid call!");
375 		if (!m_bCloneable)
376 			return Reference< XCloneable >();
377 
378 		// let the aggregate create it's own clone
379 		// the interface
380 		Reference< XCloneable > xCloneAccess;
381 		m_xAggregate->queryAggregation(::getCppuType(&xCloneAccess)) >>= xCloneAccess;
382 		OSL_ENSURE(xCloneAccess.is(), "OGeometryControlModel_Base::createClone: suspicious aggregate!");
383 		if (!xCloneAccess.is())
384 			return Reference< XCloneable >();
385 		// the aggregate's clone
386 		Reference< XCloneable > xAggregateClone = xCloneAccess->createClone();
387 		OSL_ENSURE(xAggregateClone.is(), "OGeometryControlModel_Base::createClone: suspicious return of the aggregate!");
388 
389 		// create a new wrapper aggregating this return value
390 		OGeometryControlModel_Base* pOwnClone = createClone_Impl(xAggregateClone);
391 		OSL_ENSURE(pOwnClone, "OGeometryControlModel_Base::createClone: invalid derivee behaviour!");
392 		OSL_ENSURE(!xAggregateClone.is(), "OGeometryControlModel_Base::createClone: invalid ctor behaviour!");
393 			// should have been reset
394 
395 		// set properties
396 		pOwnClone->m_nPosX		= m_nPosX;
397 		pOwnClone->m_nPosY		= m_nPosY;
398 		pOwnClone->m_nWidth		= m_nWidth;
399 		pOwnClone->m_nHeight	= m_nHeight;
400 		pOwnClone->m_aName		= m_aName;
401 		pOwnClone->m_nTabIndex	= m_nTabIndex;
402 		pOwnClone->m_nStep		= m_nStep;
403 		pOwnClone->m_aTag		= m_aTag;
404 
405 
406         // Clone event container
407 		Reference< ::com::sun::star::script::XScriptEventsSupplier > xEventsSupplier =
408             static_cast< ::com::sun::star::script::XScriptEventsSupplier* >( this );
409 		Reference< ::com::sun::star::script::XScriptEventsSupplier > xCloneEventsSupplier =
410             static_cast< ::com::sun::star::script::XScriptEventsSupplier* >( pOwnClone );
411 
412 		if( xEventsSupplier.is() && xCloneEventsSupplier.is() )
413 		{
414 			Reference< XNameContainer > xEventCont = xEventsSupplier->getEvents();
415 			Reference< XNameContainer > xCloneEventCont = xCloneEventsSupplier->getEvents();
416 
417 			::com::sun::star::uno::Sequence< ::rtl::OUString > aNames =
418                 xEventCont->getElementNames();
419 			const ::rtl::OUString* pNames = aNames.getConstArray();
420 			sal_Int32 i, nNameCount = aNames.getLength();
421 
422 			for( i = 0 ; i < nNameCount ; i++ )
423 			{
424                 ::rtl::OUString aName = pNames[ i ];
425 				::com::sun::star::uno::Any aElement = xEventCont->getByName( aName );
426                 xCloneEventCont->insertByName( aName, aElement );
427 			}
428 		}
429 
430 		return pOwnClone;
431 	}
432 
433 	//--------------------------------------------------------------------
434 	Reference< XNameContainer > SAL_CALL OGeometryControlModel_Base::getEvents() throw(RuntimeException)
435 	{
436 		if( !mxEventContainer.is() )
437 			mxEventContainer = (XNameContainer*)new toolkit::ScriptEventContainer();
438 		return mxEventContainer;
439 	}
440 
441 	//--------------------------------------------------------------------
442     void SAL_CALL OGeometryControlModel_Base::disposing()
443 	{
444 		OGCM_Base::disposing();
445 		OPropertySetAggregationHelper::disposing();
446 
447 		Reference<XComponent>  xComp;
448 		if ( query_aggregation( m_xAggregate, xComp ) )
449 			xComp->dispose();
450 	}
451 
452 	//====================================================================
453 	//= OCommonGeometryControlModel
454 	//====================================================================
455 	//--------------------------------------------------------------------
456 
457 	typedef	::std::hash_map< ::rtl::OUString, sal_Int32, ::comphelper::UStringHash > HashMapString2Int;
458 	typedef ::std::vector< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property > >	PropSeqArray;
459 	typedef ::std::vector< ::std::vector< sal_Int32 > > IntArrayArray;
460 
461 	// for creating class-unique PropertySetInfo's, we need some info:
462 	namespace { struct ServiceSpecifierMap : public rtl::Static< HashMapString2Int, ServiceSpecifierMap > {}; }
463 	// this one maps from a String, which is the service specifier for our
464 	// aggregate, to a unique id
465 
466 	namespace { struct AggregateProperties : public rtl::Static< PropSeqArray, AggregateProperties > {}; }
467 	// this one contains the properties which belong to all the unique ids
468 	// in ServiceSpecifierMap
469 
470 	namespace { struct AmbiguousPropertyIds : public rtl::Static< IntArrayArray, AmbiguousPropertyIds > {}; }
471 	// the ids of the properties which we as well as our aggregate supply
472 	// For such props, we let our base class handle them, and whenever such
473 	// a prop is set, we forward this to our aggregate.
474 
475 	// With this, we can ensure that two instances of this class share the
476 	// same PropertySetInfo if and only if both aggregates have the same
477 	// service specifier.
478 
479 
480 	//--------------------------------------------------------------------
481 	OCommonGeometryControlModel::OCommonGeometryControlModel( Reference< XCloneable >& _rxAgg, const ::rtl::OUString& _rServiceSpecifier )
482 		:OGeometryControlModel_Base( _rxAgg )
483 		,m_sServiceSpecifier( _rServiceSpecifier )
484 		,m_nPropertyMapId( 0 )
485 	{
486 		Reference< XPropertySetInfo > xPI;
487 		if ( m_xAggregateSet.is() )
488 			xPI = m_xAggregateSet->getPropertySetInfo();
489 		if ( !xPI.is() )
490 		{
491 			releaseAggregation();
492 			throw IllegalArgumentException();
493 		}
494 
495 	        HashMapString2Int &rMap = ServiceSpecifierMap::get();
496 		HashMapString2Int::iterator aPropMapIdPos = rMap.find( m_sServiceSpecifier );
497 		if ( rMap.end() == aPropMapIdPos )
498 		{
499 			PropSeqArray &rAggProperties = AggregateProperties::get();
500 			m_nPropertyMapId = rAggProperties.size();
501 			rAggProperties.push_back( xPI->getProperties() );
502 			AmbiguousPropertyIds::get().push_back( IntArrayArray::value_type() );
503 
504 			rMap[ m_sServiceSpecifier ] = m_nPropertyMapId;
505 		}
506 		else
507 			m_nPropertyMapId = aPropMapIdPos->second;
508 	}
509 
510 	//--------------------------------------------------------------------
511 	struct PropertyNameLess : public ::std::binary_function< Property, Property, bool >
512 	{
513 		bool operator()( const Property& _rLHS, const Property& _rRHS )
514 		{
515 			return _rLHS.Name < _rRHS.Name ? true : false;
516 		}
517 	};
518 
519 	//--------------------------------------------------------------------
520 	struct PropertyNameEqual : public ::std::unary_function< Property, bool >
521 	{
522 		const ::rtl::OUString&	m_rCompare;
523 		PropertyNameEqual( const ::rtl::OUString& _rCompare ) : m_rCompare( _rCompare ) { }
524 
525 		bool operator()( const Property& _rLHS )
526 		{
527 			return _rLHS.Name == m_rCompare ? true : false;
528 		}
529 	};
530 
531 	//--------------------------------------------------------------------
532 	::cppu::IPropertyArrayHelper* OCommonGeometryControlModel::createArrayHelper( sal_Int32 _nId ) const
533 	{
534 		OSL_ENSURE( _nId == m_nPropertyMapId, "OCommonGeometryControlModel::createArrayHelper: invalid argument!" );
535 		OSL_ENSURE( _nId < (sal_Int32)AggregateProperties::get().size(), "OCommonGeometryControlModel::createArrayHelper: invalid status info (1)!" );
536 		OSL_ENSURE( _nId < (sal_Int32)AmbiguousPropertyIds::get().size(), "OCommonGeometryControlModel::createArrayHelper: invalid status info (2)!" );
537 
538 		// our own properties
539 		Sequence< Property > aProps;
540 		OPropertyContainer::describeProperties( aProps );
541 
542 		// the aggregate properties
543 		Sequence< Property > aAggregateProps;
544 		aAggregateProps = AggregateProperties::get()[ _nId ];
545 
546 		// look for duplicates, and remember them
547 		IntArrayArray::value_type& rDuplicateIds = AmbiguousPropertyIds::get()[ _nId ];
548 		// for this, sort the aggregate properties
549 		::std::sort(
550 			aAggregateProps.getArray(),
551 			aAggregateProps.getArray() + aAggregateProps.getLength(),
552 			PropertyNameLess()
553 		);
554 		const Property* pAggProps = aAggregateProps.getConstArray();
555 		const Property* pAggPropsEnd = aAggregateProps.getConstArray() + aAggregateProps.getLength();
556 
557 		// now loop through our own props
558 		const Property* pProp = aProps.getConstArray();
559 		const Property* pPropEnd = aProps.getConstArray() + aProps.getLength();
560 		while ( pProp < pPropEnd )
561 		{
562 			// look for the current property in the properties of our aggregate
563 			const Property* pAggPropPos = ::std::find_if( pAggProps, pAggPropsEnd, PropertyNameEqual( pProp->Name ) );
564 			if ( pAggPropPos != pAggPropsEnd )
565 			{	// found a duplicate
566 				// -> remove from the aggregate property sequence
567 				::comphelper::removeElementAt( aAggregateProps, pAggPropPos - pAggProps );
568 				// which means we have to adjust the pointers
569 				pAggProps = aAggregateProps.getConstArray(),
570 				pAggPropsEnd = aAggregateProps.getConstArray() + aAggregateProps.getLength(),
571 
572 				// and additionally, remember the id of this property
573 				rDuplicateIds.push_back( pProp->Handle );
574 			}
575 
576 			++pProp;
577 		}
578 
579 		// now, finally, sort the duplicates
580 		::std::sort( rDuplicateIds.begin(), rDuplicateIds.end(), ::std::less< sal_Int32 >() );
581 
582 		return new OPropertyArrayAggregationHelper(aProps, aAggregateProps);
583 	}
584 
585 	//--------------------------------------------------------------------
586 	::cppu::IPropertyArrayHelper& SAL_CALL OCommonGeometryControlModel::getInfoHelper()
587 	{
588 		return *getArrayHelper( m_nPropertyMapId );
589 	}
590 
591 	//--------------------------------------------------------------------
592 	OGeometryControlModel_Base* OCommonGeometryControlModel::createClone_Impl( Reference< XCloneable >& _rxAggregateInstance )
593 	{
594 		return new OCommonGeometryControlModel( _rxAggregateInstance, m_sServiceSpecifier );
595 	}
596 
597 	//--------------------------------------------------------------------
598 	Sequence< sal_Int8 > SAL_CALL OCommonGeometryControlModel::getImplementationId(  ) throw (RuntimeException)
599 	{
600 		static ::cppu::OImplementationId * pId = NULL;
601 		if ( !pId )
602 		{
603 			::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
604 			if ( !pId )
605 			{
606 				static ::cppu::OImplementationId s_aId;
607 				pId = &s_aId;
608 			}
609 		}
610 		return pId->getImplementationId();
611 	}
612 
613 	//--------------------------------------------------------------------
614 	struct Int32Equal : public ::std::unary_function< sal_Int32, bool >
615 	{
616 		sal_Int32	m_nCompare;
617 		Int32Equal( sal_Int32 _nCompare ) : m_nCompare( _nCompare ) { }
618 
619 		bool operator()( sal_Int32 _nLHS )
620 		{
621 			return _nLHS == m_nCompare ? true  : false;
622 		}
623 	};
624 
625 	//--------------------------------------------------------------------
626 	void SAL_CALL OCommonGeometryControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
627 	{
628 		OGeometryControlModel_Base::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
629 
630 		// look if this id is one we recognized as duplicate
631 		IntArrayArray::value_type& rDuplicateIds = AmbiguousPropertyIds::get()[ m_nPropertyMapId ];
632 
633 		IntArrayArray::value_type::const_iterator aPos = ::std::find_if(
634 			rDuplicateIds.begin(),
635 			rDuplicateIds.end(),
636 			Int32Equal( _nHandle )
637 		);
638 
639 		if ( rDuplicateIds.end() != aPos )
640 		{
641 			// yes, it is such a property
642 			::rtl::OUString sPropName;
643 			sal_Int16 nAttributes(0);
644 			static_cast< OPropertyArrayAggregationHelper* >( getArrayHelper( m_nPropertyMapId ) )->fillPropertyMembersByHandle( &sPropName, &nAttributes, _nHandle );
645 
646 			if ( m_xAggregateSet.is() && sPropName.getLength() )
647 				m_xAggregateSet->setPropertyValue( sPropName, _rValue );
648 		}
649 	}
650 
651 //........................................................................
652 // }	// namespace toolkit
653 //........................................................................
654