1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "precompiled_comphelper.hxx"
25 
26 #include "comphelper_module.hxx"
27 #include "comphelper/anytostring.hxx"
28 #include "comphelper/anycompare.hxx"
29 #include "comphelper/componentbase.hxx"
30 #include "comphelper/componentcontext.hxx"
31 #include "comphelper/extract.hxx"
32 
33 /** === begin UNO includes === **/
34 #include <com/sun/star/container/XEnumerableMap.hpp>
35 #include <com/sun/star/lang/XInitialization.hpp>
36 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
37 #include <com/sun/star/beans/Pair.hpp>
38 #include <com/sun/star/lang/XServiceInfo.hpp>
39 /** === end UNO includes === **/
40 
41 #include <cppuhelper/compbase3.hxx>
42 #include <cppuhelper/implbase1.hxx>
43 #include <rtl/math.hxx>
44 #include <rtl/ustrbuf.hxx>
45 #include <typelib/typedescription.hxx>
46 
47 #include <map>
48 #include <boost/shared_ptr.hpp>
49 
50 //........................................................................
51 namespace comphelper
52 {
53 //........................................................................
54 
55 	/** === begin UNO using === **/
56 	using ::com::sun::star::uno::Reference;
57 	using ::com::sun::star::uno::XInterface;
58 	using ::com::sun::star::uno::UNO_QUERY;
59 	using ::com::sun::star::uno::UNO_QUERY_THROW;
60 	using ::com::sun::star::uno::UNO_SET_THROW;
61 	using ::com::sun::star::uno::Exception;
62 	using ::com::sun::star::uno::RuntimeException;
63 	using ::com::sun::star::uno::Any;
64 	using ::com::sun::star::uno::makeAny;
65 	using ::com::sun::star::uno::Sequence;
66 	using ::com::sun::star::uno::Type;
67 	using ::com::sun::star::container::XEnumerableMap;
68 	using ::com::sun::star::lang::NoSupportException;
69 	using ::com::sun::star::beans::IllegalTypeException;
70 	using ::com::sun::star::container::NoSuchElementException;
71 	using ::com::sun::star::lang::IllegalArgumentException;
72 	using ::com::sun::star::lang::XInitialization;
73 	using ::com::sun::star::ucb::AlreadyInitializedException;
74 	using ::com::sun::star::beans::Pair;
75 	using ::com::sun::star::uno::TypeClass;
76 	using ::com::sun::star::uno::TypeClass_VOID;
77 	using ::com::sun::star::uno::TypeClass_UNKNOWN;
78 	using ::com::sun::star::uno::TypeClass_ANY;
79 	using ::com::sun::star::uno::TypeClass_EXCEPTION;
80 	using ::com::sun::star::uno::TypeClass_STRUCT;
81 	using ::com::sun::star::uno::TypeClass_UNION;
82 	using ::com::sun::star::uno::TypeClass_FLOAT;
83 	using ::com::sun::star::uno::TypeClass_DOUBLE;
84 	using ::com::sun::star::uno::TypeClass_INTERFACE;
85 	using ::com::sun::star::lang::XServiceInfo;
86 	using ::com::sun::star::uno::XComponentContext;
87 	using ::com::sun::star::container::XEnumeration;
88 	using ::com::sun::star::uno::TypeDescription;
89 	using ::com::sun::star::lang::WrappedTargetException;
90 	using ::com::sun::star::lang::DisposedException;
91 	/** === end UNO using === **/
92 
93 	//====================================================================
94 	//= MapData
95 	//====================================================================
96 	class IMapModificationListener;
97 	typedef ::std::vector< IMapModificationListener* > MapListeners;
98 
99 	typedef ::std::map< Any, Any, LessPredicateAdapter > KeyedValues;
100 	struct MapData
101 	{
102 		Type										m_aKeyType;
103 		Type										m_aValueType;
104 		::std::auto_ptr< KeyedValues >				m_pValues;
105 		::boost::shared_ptr< IKeyPredicateLess >	m_pKeyCompare;
106 		bool										m_bMutable;
107 		MapListeners								m_aModListeners;
108 
MapDatacomphelper::MapData109 		MapData()
110 			:m_bMutable( true )
111 		{
112 		}
113 
MapDatacomphelper::MapData114 		MapData( const MapData& _source )
115 			:m_aKeyType( _source.m_aKeyType )
116 			,m_aValueType( _source.m_aValueType )
117 			,m_pValues( new KeyedValues( *_source.m_pValues ) )
118 			,m_pKeyCompare( _source.m_pKeyCompare )
119 			,m_bMutable( false )
120 			,m_aModListeners()
121 		{
122 		}
123 	private:
124 		MapData& operator=( const MapData& _source ); // not implemented
125 	};
126 
127 	//====================================================================
128 	//= IMapModificationListener
129 	//====================================================================
130 	/** implemented by components who want to be notified of modifications in the MapData they work with
131 	*/
132 	class SAL_NO_VTABLE IMapModificationListener
133 	{
134 	public:
135 		/// called when the map was modified
136 		virtual void mapModified() = 0;
~IMapModificationListener()137 		virtual ~IMapModificationListener()
138 		{
139 		}
140 	};
141 
142 	//====================================================================
143 	//= MapData helpers
144 	//====================================================================
145 	//--------------------------------------------------------------------
lcl_registerMapModificationListener(MapData & _mapData,IMapModificationListener & _listener)146 	static void lcl_registerMapModificationListener( MapData& _mapData, IMapModificationListener& _listener )
147 	{
148 	#if OSL_DEBUG_LEVEL > 0
149 		for (   MapListeners::const_iterator lookup = _mapData.m_aModListeners.begin();
150 				lookup != _mapData.m_aModListeners.end();
151 				++lookup
152 			)
153 		{
154 			OSL_ENSURE( *lookup != &_listener, "lcl_registerMapModificationListener: this listener is already registered!" );
155 		}
156 	#endif
157 		_mapData.m_aModListeners.push_back( &_listener );
158 	}
159 
160 	//--------------------------------------------------------------------
lcl_revokeMapModificationListener(MapData & _mapData,IMapModificationListener & _listener)161 	static void lcl_revokeMapModificationListener( MapData& _mapData, IMapModificationListener& _listener )
162 	{
163 		for (   MapListeners::iterator lookup = _mapData.m_aModListeners.begin();
164 				lookup != _mapData.m_aModListeners.end();
165 				++lookup
166 			)
167 		{
168 			if ( *lookup == &_listener )
169 			{
170 				_mapData.m_aModListeners.erase( lookup );
171 				return;
172 			}
173 		}
174 		OSL_ENSURE( false, "lcl_revokeMapModificationListener: the listener is not registered!" );
175 	}
176 
177 	//--------------------------------------------------------------------
lcl_notifyMapDataListeners_nothrow(const MapData & _mapData)178 	static void lcl_notifyMapDataListeners_nothrow( const MapData& _mapData )
179 	{
180 		for (   MapListeners::const_iterator loop = _mapData.m_aModListeners.begin();
181 				loop != _mapData.m_aModListeners.end();
182 				++loop
183 			)
184 		{
185 			(*loop)->mapModified();
186 		}
187 	}
188 
189 	//====================================================================
190 	//= EnumerableMap
191 	//====================================================================
192 	typedef ::cppu::WeakAggComponentImplHelper3 <   XInitialization
193 												,   XEnumerableMap
194 												,   XServiceInfo
195 												> Map_IFace;
196 
197 	class COMPHELPER_DLLPRIVATE EnumerableMap :public Map_IFace
198 									,public ComponentBase
199 	{
200 	protected:
201 		EnumerableMap( const ComponentContext& _rContext );
202 		virtual ~EnumerableMap();
203 
204 		// XInitialization
205 		virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException);
206 
207 		// XEnumerableMap
208 		virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createKeyEnumeration( ::sal_Bool _Isolated ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException);
209 		virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createValueEnumeration( ::sal_Bool _Isolated ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException);
210 		virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createElementEnumeration( ::sal_Bool _Isolated ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException);
211 
212 		// XMap
213 		virtual Type SAL_CALL getKeyType() throw (RuntimeException);
214 		virtual Type SAL_CALL getValueType() throw (RuntimeException);
215 		virtual void SAL_CALL clear(  ) throw (NoSupportException, RuntimeException);
216 		virtual ::sal_Bool SAL_CALL containsKey( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException);
217 		virtual ::sal_Bool SAL_CALL containsValue( const Any& _value ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException);
218 		virtual Any SAL_CALL get( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException);
219 		virtual Any SAL_CALL put( const Any& _key, const Any& _value ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, RuntimeException);
220 		virtual Any SAL_CALL remove( const Any& _key ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException);
221 
222 		// XElementAccess (base of XMap)
223 		virtual Type SAL_CALL getElementType() throw (RuntimeException);
224 		virtual ::sal_Bool SAL_CALL hasElements() throw (RuntimeException);
225 
226 		// XServiceInfo
227 		virtual ::rtl::OUString SAL_CALL getImplementationName(  ) throw (RuntimeException);
228 		virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException);
229 		virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames(  ) throw (RuntimeException);
230 
231 	public:
232 		// XServiceInfo, static version (used for component registration)
233 		static ::rtl::OUString SAL_CALL getImplementationName_static(  );
234 		static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(  );
235 		static Reference< XInterface > SAL_CALL Create( const Reference< XComponentContext >& );
236 
237 	private:
238 		void impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues );
239 
240 		/// throws a IllegalTypeException if the given value is not compatible with our ValueType
241 		void impl_checkValue_throw( const Any& _value ) const;
242 		void impl_checkKey_throw( const Any& _key ) const;
243 		void impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const;
244 		void impl_checkMutable_throw() const;
245 
246 	private:
247 		::osl::Mutex		m_aMutex;
248 		ComponentContext	m_aContext;
249 		MapData				m_aData;
250 
251 		::std::vector< ::com::sun::star::uno::WeakReference< XInterface > >
252 							m_aDependentComponents;
253 	};
254 
255 	//====================================================================
256 	//= EnumerationType
257 	//====================================================================
258 	enum EnumerationType
259 	{
260 		eKeys, eValues, eBoth
261 	};
262 
263 	//====================================================================
264 	//= MapEnumerator
265 	//====================================================================
266 	class MapEnumerator : public IMapModificationListener
267 	{
268 	public:
MapEnumerator(::cppu::OWeakObject & _rParent,MapData & _mapData,const EnumerationType _type)269 		MapEnumerator( ::cppu::OWeakObject& _rParent, MapData& _mapData, const EnumerationType _type )
270 			:m_rParent( _rParent )
271 			,m_rMapData( _mapData )
272 			,m_eType( _type )
273 			,m_mapPos( _mapData.m_pValues->begin() )
274 			,m_disposed( false )
275 		{
276 			lcl_registerMapModificationListener( m_rMapData, *this );
277 		}
278 
~MapEnumerator()279 		virtual ~MapEnumerator()
280 		{
281 			dispose();
282 		}
283 
dispose()284 		void dispose()
285 		{
286 			if ( !m_disposed )
287 			{
288 				lcl_revokeMapModificationListener( m_rMapData, *this );
289 				m_disposed = true;
290 			}
291 		}
292 
293 		// XEnumeration equivalents
294 		::sal_Bool hasMoreElements();
295 		Any nextElement();
296 
297 		// IMapModificationListener
298 		virtual void mapModified();
299 
300 	private:
301 		::cppu::OWeakObject&		m_rParent;
302 		MapData&					m_rMapData;
303 		const EnumerationType		m_eType;
304 		KeyedValues::const_iterator	m_mapPos;
305 		bool						m_disposed;
306 
307 	private:
308 		MapEnumerator(); // not implemented
309 		MapEnumerator( const MapEnumerator& ); // not implemented
310 		MapEnumerator& operator=( const MapEnumerator& ); // not implemented
311 	};
312 
313 	//====================================================================
314 	//= MapEnumeration
315 	//====================================================================
316 	typedef ::cppu::WeakImplHelper1 <   XEnumeration
317 									>   MapEnumeration_Base;
318 	class MapEnumeration :public ComponentBase
319 						 ,public MapEnumeration_Base
320 	{
321 	public:
MapEnumeration(::cppu::OWeakObject & _parentMap,MapData & _mapData,::cppu::OBroadcastHelper & _rBHelper,const EnumerationType _type,const bool _isolated)322 		MapEnumeration( ::cppu::OWeakObject& _parentMap, MapData& _mapData, ::cppu::OBroadcastHelper& _rBHelper,
323 						const EnumerationType _type, const bool _isolated )
324 			:ComponentBase( _rBHelper, ComponentBase::NoInitializationNeeded() )
325 			,m_xKeepMapAlive( _parentMap )
326 			,m_pMapDataCopy( _isolated ? new MapData( _mapData ) : NULL )
327 			,m_aEnumerator( *this, _isolated ? *m_pMapDataCopy : _mapData, _type )
328 		{
329 		}
330 
331 		// XEnumeration
332 		virtual ::sal_Bool SAL_CALL hasMoreElements(  ) throw (RuntimeException);
333 		virtual Any SAL_CALL nextElement(  ) throw (NoSuchElementException, WrappedTargetException, RuntimeException);
334 
335 	protected:
~MapEnumeration()336 		virtual ~MapEnumeration()
337 		{
338 			acquire();
339 			{
340 				::osl::MutexGuard aGuard( getMutex() );
341 				m_aEnumerator.dispose();
342 				m_pMapDataCopy.reset();
343 			}
344 		}
345 
346 	private:
347 		// since we share our mutex with the main map, we need to keep it alive as long as we live
348 		Reference< XInterface >		m_xKeepMapAlive;
349 		::std::auto_ptr< MapData >	m_pMapDataCopy;
350 		MapEnumerator				m_aEnumerator;
351 	};
352 
353 	//====================================================================
354 	//= EnumerableMap
355 	//====================================================================
356 	//--------------------------------------------------------------------
EnumerableMap(const ComponentContext & _rContext)357 	EnumerableMap::EnumerableMap( const ComponentContext& _rContext )
358 		:Map_IFace( m_aMutex )
359 		,ComponentBase( Map_IFace::rBHelper )
360 		,m_aContext( _rContext )
361 	{
362 	}
363 
364 	//--------------------------------------------------------------------
~EnumerableMap()365 	EnumerableMap::~EnumerableMap()
366 	{
367 		if ( !impl_isDisposed() )
368 		{
369 			acquire();
370 			dispose();
371 		}
372 	}
373 
374 	//--------------------------------------------------------------------
initialize(const Sequence<Any> & _arguments)375 	void SAL_CALL EnumerableMap::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException)
376 	{
377 		ComponentMethodGuard aGuard( *this, ComponentMethodGuard::WithoutInit );
378 		if ( impl_isInitialized_nothrow() )
379 			throw AlreadyInitializedException();
380 
381 		sal_Int32 nArgumentCount = _arguments.getLength();
382 		if ( ( nArgumentCount != 2 ) && ( nArgumentCount != 3 ) )
383 			throw IllegalArgumentException();
384 
385 		Type aKeyType, aValueType;
386 		if ( !( _arguments[0] >>= aKeyType ) )
387 			throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "com.sun.star.uno.Type expected." ), *this, 1 );
388 		if ( !( _arguments[1] >>= aValueType ) )
389 			throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "com.sun.star.uno.Type expected." ), *this, 2 );
390 
391 		Sequence< Pair< Any, Any > > aInitialValues;
392 		bool bMutable = true;
393 		if ( nArgumentCount == 3 )
394 		{
395 			if ( !( _arguments[2] >>= aInitialValues ) )
396 				throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "[]com.sun.star.beans.Pair<any,any> expected." ), *this, 2 );
397 			bMutable = false;
398 		}
399 
400 		// for the value, anything is allowed, except VOID
401 		if ( ( aValueType.getTypeClass() == TypeClass_VOID ) || ( aValueType.getTypeClass() == TypeClass_UNKNOWN ) )
402 			throw IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported value type." ) ), *this );
403 
404 		// create the comparator for the KeyType, and throw if the type is not supported
405 		::std::auto_ptr< IKeyPredicateLess > pComparator( getStandardLessPredicate( aKeyType, NULL ) );
406 		if ( !pComparator.get() )
407 			throw IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), *this );
408 
409 		// init members
410 		m_aData.m_aKeyType = aKeyType;
411 		m_aData.m_aValueType = aValueType;
412 		m_aData.m_pKeyCompare = pComparator;
413 		m_aData.m_pValues.reset( new KeyedValues( *m_aData.m_pKeyCompare ) );
414 		m_aData.m_bMutable = bMutable;
415 
416 		if ( aInitialValues.getLength() )
417 			impl_initValues_throw( aInitialValues );
418 
419 		setInitialized();
420 	}
421 
422 	//--------------------------------------------------------------------
impl_initValues_throw(const Sequence<Pair<Any,Any>> & _initialValues)423 	void EnumerableMap::impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues )
424 	{
425 		OSL_PRECOND( m_aData.m_pValues.get() && m_aData.m_pValues->empty(), "EnumerableMap::impl_initValues_throw: illegal call!" );
426 		if ( !m_aData.m_pValues.get() || !m_aData.m_pValues->empty() )
427 			throw RuntimeException();
428 
429 		const Pair< Any, Any >* mapping = _initialValues.getConstArray();
430 		const Pair< Any, Any >* mappingEnd = mapping + _initialValues.getLength();
431 		Any normalizedValue;
432 		for ( ; mapping != mappingEnd; ++mapping )
433 		{
434 			impl_checkValue_throw( mapping->Second );
435 			(*m_aData.m_pValues)[ mapping->First ] = mapping->Second;
436 		}
437 	}
438 
439 	//--------------------------------------------------------------------
impl_checkValue_throw(const Any & _value) const440 	void EnumerableMap::impl_checkValue_throw( const Any& _value ) const
441 	{
442 		if ( !_value.hasValue() )
443 			// nothing to do, NULL values are always allowed, regardless of the ValueType
444 			return;
445 
446 		TypeClass eAllowedTypeClass = m_aData.m_aValueType.getTypeClass();
447 		bool bValid = false;
448 
449 		switch ( eAllowedTypeClass )
450 		{
451 		default:
452 			bValid = ( _value.getValueTypeClass() == eAllowedTypeClass );
453 			break;
454 		case TypeClass_ANY:
455 			bValid = true;
456 			break;
457 		case TypeClass_INTERFACE:
458 		{
459 			// special treatment: _value might contain the proper type, but the interface
460 			// might actually be NULL. Which is still valid...
461 			if ( m_aData.m_aValueType.isAssignableFrom( _value.getValueType() ) )
462 				// this also catches the special case where XFoo is our value type,
463 				// and _value contains a NULL-reference to XFoo, or a derived type
464 				bValid = true;
465 			else
466 			{
467 				Reference< XInterface > xValue( _value, UNO_QUERY );
468 				Any aTypedValue;
469 				if ( xValue.is() )
470 					// XInterface is not-NULL, but is X(ValueType) not-NULL, too?
471 					xValue.set( xValue->queryInterface( m_aData.m_aValueType ), UNO_QUERY );
472 				bValid = xValue.is();
473 			}
474 		}
475 		break;
476 		case TypeClass_EXCEPTION:
477 		case TypeClass_STRUCT:
478 		case TypeClass_UNION:
479 		{
480 			// values are accepted if and only if their type equals, or is derived from, our value type
481 
482 			if ( _value.getValueTypeClass() != eAllowedTypeClass )
483 				bValid = false;
484 			else
485 			{
486 				const TypeDescription aValueTypeDesc( _value.getValueType() );
487 				const TypeDescription aRequiredTypeDesc( m_aData.m_aValueType );
488 
489 				const _typelib_CompoundTypeDescription* pValueCompoundTypeDesc =
490 					reinterpret_cast< const _typelib_CompoundTypeDescription* >( aValueTypeDesc.get() );
491 
492 				while ( pValueCompoundTypeDesc )
493 				{
494 					if ( typelib_typedescription_equals( &pValueCompoundTypeDesc->aBase, aRequiredTypeDesc.get() ) )
495 						break;
496 					pValueCompoundTypeDesc = pValueCompoundTypeDesc->pBaseTypeDescription;
497 				}
498 				bValid = ( pValueCompoundTypeDesc != NULL );
499 			}
500 		}
501 		break;
502 		}
503 
504 		if ( !bValid )
505 		{
506 			::rtl::OUStringBuffer aMessage;
507 			aMessage.appendAscii( "Incompatible value type. Found '" );
508 			aMessage.append( _value.getValueTypeName() );
509 			aMessage.appendAscii( "', where '" );
510 			aMessage.append( m_aData.m_aValueType.getTypeName() );
511 			aMessage.appendAscii( "' (or compatible type) is expected." );
512 			throw IllegalTypeException( aMessage.makeStringAndClear(), *const_cast< EnumerableMap* >( this ) );
513 		}
514 
515 		impl_checkNaN_throw( _value, m_aData.m_aValueType );
516 	}
517 
518 	//--------------------------------------------------------------------
impl_checkNaN_throw(const Any & _keyOrValue,const Type & _keyOrValueType) const519 	void EnumerableMap::impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const
520 	{
521 		if  (   ( _keyOrValueType.getTypeClass() == TypeClass_DOUBLE )
522 			||  ( _keyOrValueType.getTypeClass() == TypeClass_FLOAT )
523 			)
524 		{
525 			double nValue(0);
526 			if ( _keyOrValue >>= nValue )
527 				if ( ::rtl::math::isNan( nValue ) )
528 					throw IllegalArgumentException(
529 						::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NaN (not-a-number) not supported by this implementation." ) ),
530 						*const_cast< EnumerableMap* >( this ), 0 );
531 			// (note that the case of _key not containing a float/double value is handled in the
532 			// respective IKeyPredicateLess implementation, so there's no need to handle this here.)
533 		}
534 	}
535 
536 	//--------------------------------------------------------------------
impl_checkKey_throw(const Any & _key) const537 	void EnumerableMap::impl_checkKey_throw( const Any& _key ) const
538 	{
539 		if ( !_key.hasValue() )
540 			throw IllegalArgumentException(
541 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NULL keys not supported by this implementation." ) ),
542 				*const_cast< EnumerableMap* >( this ), 0 );
543 
544 		impl_checkNaN_throw( _key, m_aData.m_aKeyType );
545 	}
546 
547 	//--------------------------------------------------------------------
impl_checkMutable_throw() const548 	void EnumerableMap::impl_checkMutable_throw() const
549 	{
550 		if ( !m_aData.m_bMutable )
551 			throw NoSupportException(
552 					::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "The map is immutable." ) ),
553 					*const_cast< EnumerableMap* >( this ) );
554 	}
555 
556 	//--------------------------------------------------------------------
createKeyEnumeration(::sal_Bool _Isolated)557 	Reference< XEnumeration > SAL_CALL EnumerableMap::createKeyEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException)
558 	{
559 		ComponentMethodGuard aGuard( *this );
560 		return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eKeys, _Isolated );
561 	}
562 
563 	//--------------------------------------------------------------------
createValueEnumeration(::sal_Bool _Isolated)564 	Reference< XEnumeration > SAL_CALL EnumerableMap::createValueEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException)
565 	{
566 		ComponentMethodGuard aGuard( *this );
567 		return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eValues, _Isolated );
568 	}
569 
570 	//--------------------------------------------------------------------
createElementEnumeration(::sal_Bool _Isolated)571 	Reference< XEnumeration > SAL_CALL EnumerableMap::createElementEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException)
572 	{
573 		ComponentMethodGuard aGuard( *this );
574 		return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eBoth, _Isolated );
575 	}
576 
577 	//--------------------------------------------------------------------
getKeyType()578 	Type SAL_CALL EnumerableMap::getKeyType() throw (RuntimeException)
579 	{
580 		ComponentMethodGuard aGuard( *this );
581 		return m_aData.m_aKeyType;
582 	}
583 
584 	//--------------------------------------------------------------------
getValueType()585 	Type SAL_CALL EnumerableMap::getValueType() throw (RuntimeException)
586 	{
587 		ComponentMethodGuard aGuard( *this );
588 		return m_aData.m_aValueType;
589 	}
590 
591 	//--------------------------------------------------------------------
clear()592 	void SAL_CALL EnumerableMap::clear(  ) throw (NoSupportException, RuntimeException)
593 	{
594 		ComponentMethodGuard aGuard( *this );
595 		impl_checkMutable_throw();
596 
597 		m_aData.m_pValues->clear();
598 
599 		lcl_notifyMapDataListeners_nothrow( m_aData );
600 	}
601 
602 	//--------------------------------------------------------------------
containsKey(const Any & _key)603 	::sal_Bool SAL_CALL EnumerableMap::containsKey( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException)
604 	{
605 		ComponentMethodGuard aGuard( *this );
606 		impl_checkKey_throw( _key );
607 
608 		KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
609 		return ( pos != m_aData.m_pValues->end() );
610 	}
611 
612 	//--------------------------------------------------------------------
containsValue(const Any & _value)613 	::sal_Bool SAL_CALL EnumerableMap::containsValue( const Any& _value ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException)
614 	{
615 		ComponentMethodGuard aGuard( *this );
616 		impl_checkValue_throw( _value );
617 
618 		for (   KeyedValues::const_iterator mapping = m_aData.m_pValues->begin();
619 				mapping != m_aData.m_pValues->end();
620 				++mapping
621 			)
622 		{
623 			if ( mapping->second == _value )
624 				return sal_True;
625 		}
626 		return sal_False;
627 	}
628 
629 	//--------------------------------------------------------------------
get(const Any & _key)630 	Any SAL_CALL EnumerableMap::get( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException)
631 	{
632 		ComponentMethodGuard aGuard( *this );
633 		impl_checkKey_throw( _key );
634 
635 		KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
636 		if ( pos == m_aData.m_pValues->end() )
637 			throw NoSuchElementException( anyToString( _key ), *this );
638 
639 		return pos->second;
640 	}
641 
642 	//--------------------------------------------------------------------
put(const Any & _key,const Any & _value)643 	Any SAL_CALL EnumerableMap::put( const Any& _key, const Any& _value ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, RuntimeException)
644 	{
645 		ComponentMethodGuard aGuard( *this );
646 		impl_checkMutable_throw();
647 		impl_checkKey_throw( _key );
648 		impl_checkValue_throw( _value );
649 
650 		Any previousValue;
651 
652 		KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
653 		if ( pos != m_aData.m_pValues->end() )
654 		{
655 			previousValue = pos->second;
656 			pos->second = _value;
657 		}
658 		else
659 		{
660 			(*m_aData.m_pValues)[ _key ] = _value;
661 		}
662 
663 		lcl_notifyMapDataListeners_nothrow( m_aData );
664 
665 		return previousValue;
666 	}
667 
668 	//--------------------------------------------------------------------
remove(const Any & _key)669 	Any SAL_CALL EnumerableMap::remove( const Any& _key ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException)
670 	{
671 		ComponentMethodGuard aGuard( *this );
672 		impl_checkMutable_throw();
673 		impl_checkKey_throw( _key );
674 
675 		Any previousValue;
676 
677 		KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
678 		if ( pos != m_aData.m_pValues->end() )
679 		{
680 			previousValue = pos->second;
681 			m_aData.m_pValues->erase( pos );
682 		}
683 
684 		lcl_notifyMapDataListeners_nothrow( m_aData );
685 
686 		return previousValue;
687 	}
688 
689 	//--------------------------------------------------------------------
getElementType()690 	Type SAL_CALL EnumerableMap::getElementType() throw (RuntimeException)
691 	{
692 		return ::cppu::UnoType< Pair< Any, Any > >::get();
693 	}
694 
695 	//--------------------------------------------------------------------
hasElements()696 	::sal_Bool SAL_CALL EnumerableMap::hasElements() throw (RuntimeException)
697 	{
698 		ComponentMethodGuard aGuard( *this );
699 		return m_aData.m_pValues->empty();
700 	}
701 
702 	//--------------------------------------------------------------------
getImplementationName()703 	::rtl::OUString SAL_CALL EnumerableMap::getImplementationName(  ) throw (RuntimeException)
704 	{
705 		return getImplementationName_static();
706 	}
707 
708 	//--------------------------------------------------------------------
supportsService(const::rtl::OUString & _serviceName)709 	::sal_Bool SAL_CALL EnumerableMap::supportsService( const ::rtl::OUString& _serviceName ) throw (RuntimeException)
710 	{
711 		Sequence< ::rtl::OUString > aServices( getSupportedServiceNames() );
712 		for ( sal_Int32 i=0; i<aServices.getLength(); ++i )
713 			if ( _serviceName == aServices[i] )
714 				return sal_True;
715 		return sal_False;
716 	}
717 
718 	//--------------------------------------------------------------------
getSupportedServiceNames()719 	Sequence< ::rtl::OUString > SAL_CALL EnumerableMap::getSupportedServiceNames(  ) throw (RuntimeException)
720 	{
721 		return getSupportedServiceNames_static();
722 	}
723 
724 	//--------------------------------------------------------------------
getImplementationName_static()725 	::rtl::OUString SAL_CALL EnumerableMap::getImplementationName_static(  )
726 	{
727 		return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.comphelper.EnumerableMap" ) );
728 	}
729 
730 	//--------------------------------------------------------------------
getSupportedServiceNames_static()731 	Sequence< ::rtl::OUString > SAL_CALL EnumerableMap::getSupportedServiceNames_static(  )
732 	{
733 		Sequence< ::rtl::OUString > aServiceNames(1);
734 		aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.container.EnumerableMap" ) );
735 		return aServiceNames;
736 	}
737 
738 	//--------------------------------------------------------------------
Create(const Reference<XComponentContext> & _context)739 	Reference< XInterface > SAL_CALL EnumerableMap::Create( const Reference< XComponentContext >& _context )
740 	{
741 		return *new EnumerableMap( ComponentContext( _context ) );
742 	}
743 
744 	//====================================================================
745 	//= MapEnumerator
746 	//====================================================================
747 	//--------------------------------------------------------------------
hasMoreElements()748 	::sal_Bool MapEnumerator::hasMoreElements()
749 	{
750 		if ( m_disposed )
751 			throw DisposedException( ::rtl::OUString(), m_rParent );
752 		return m_mapPos != m_rMapData.m_pValues->end();
753 	}
754 
755 	//--------------------------------------------------------------------
nextElement()756 	Any MapEnumerator::nextElement()
757 	{
758 		if ( m_disposed )
759 			throw DisposedException( ::rtl::OUString(), m_rParent );
760 		if ( m_mapPos == m_rMapData.m_pValues->end() )
761 			throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No more elements." ) ), m_rParent );
762 
763 		Any aNextElement;
764 		switch ( m_eType )
765 		{
766 		case eKeys:		aNextElement = m_mapPos->first; break;
767 		case eValues:	aNextElement = m_mapPos->second; break;
768 		case eBoth:		aNextElement <<= Pair< Any, Any >( m_mapPos->first, m_mapPos->second ); break;
769 		}
770 		++m_mapPos;
771 		return aNextElement;
772 	}
773 
774 	//--------------------------------------------------------------------
mapModified()775 	void MapEnumerator::mapModified()
776 	{
777 		m_disposed = true;
778 	}
779 
780 	//====================================================================
781 	//= MapEnumeration - implementation
782 	//====================================================================
783 	//--------------------------------------------------------------------
hasMoreElements()784 	::sal_Bool SAL_CALL MapEnumeration::hasMoreElements(  ) throw (RuntimeException)
785 	{
786 		ComponentMethodGuard aGuard( *this );
787 		return m_aEnumerator.hasMoreElements();
788 	}
789 
790 	//--------------------------------------------------------------------
nextElement()791 	Any SAL_CALL MapEnumeration::nextElement(  ) throw (NoSuchElementException, WrappedTargetException, RuntimeException)
792 	{
793 		ComponentMethodGuard aGuard( *this );
794 		return m_aEnumerator.nextElement();
795 	}
796 
797 //........................................................................
798 }	// namespace comphelper
799 //........................................................................
800 
createRegistryInfo_Map()801 void createRegistryInfo_Map()
802 {
803 	::comphelper::module::OAutoRegistration< ::comphelper::EnumerableMap > aAutoRegistration;
804 }
805