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