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         // sicne 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