merge the formfield patch from ooo-build
[ooovba.git] / comphelper / source / container / enumerablemap.cxx
blob0b26f3cd1c6f50e7c0d8fdb53248abedcb3cb77e
1 /*************************************************************************
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * Copyright 2009 by Sun Microsystems, Inc.
6 * OpenOffice.org - a multi-platform office productivity suite
8 * This file is part of OpenOffice.org.
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.
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).
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 ************************************************************************/
26 // MARKER(update_precomp.py): autogen include statement, do not remove
27 #include "precompiled_comphelper.hxx"
29 #include "comphelper_module.hxx"
30 #include "comphelper/anytostring.hxx"
31 #include "comphelper/componentbase.hxx"
32 #include "comphelper/componentcontext.hxx"
33 #include "comphelper/extract.hxx"
35 /** === begin UNO includes === **/
36 #include <com/sun/star/container/XEnumerableMap.hpp>
37 #include <com/sun/star/lang/XInitialization.hpp>
38 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
39 #include <com/sun/star/beans/Pair.hpp>
40 #include <com/sun/star/lang/XServiceInfo.hpp>
41 /** === end UNO includes === **/
43 #include <cppuhelper/compbase3.hxx>
44 #include <cppuhelper/implbase1.hxx>
45 #include <rtl/math.hxx>
46 #include <rtl/ustrbuf.hxx>
47 #include <typelib/typedescription.hxx>
49 #include <functional>
50 #include <map>
51 #include <memory>
52 #include <boost/shared_ptr.hpp>
54 //........................................................................
55 namespace comphelper
57 //........................................................................
59 /** === begin UNO using === **/
60 using ::com::sun::star::uno::Reference;
61 using ::com::sun::star::uno::XInterface;
62 using ::com::sun::star::uno::UNO_QUERY;
63 using ::com::sun::star::uno::UNO_QUERY_THROW;
64 using ::com::sun::star::uno::UNO_SET_THROW;
65 using ::com::sun::star::uno::Exception;
66 using ::com::sun::star::uno::RuntimeException;
67 using ::com::sun::star::uno::Any;
68 using ::com::sun::star::uno::makeAny;
69 using ::com::sun::star::uno::Sequence;
70 using ::com::sun::star::uno::Type;
71 using ::com::sun::star::container::XEnumerableMap;
72 using ::com::sun::star::lang::NoSupportException;
73 using ::com::sun::star::beans::IllegalTypeException;
74 using ::com::sun::star::container::NoSuchElementException;
75 using ::com::sun::star::lang::IllegalArgumentException;
76 using ::com::sun::star::lang::XInitialization;
77 using ::com::sun::star::ucb::AlreadyInitializedException;
78 using ::com::sun::star::beans::Pair;
79 using ::com::sun::star::uno::TypeClass;
80 using ::com::sun::star::uno::TypeClass_VOID;
81 using ::com::sun::star::uno::TypeClass_CHAR;
82 using ::com::sun::star::uno::TypeClass_BOOLEAN;
83 using ::com::sun::star::uno::TypeClass_BYTE;
84 using ::com::sun::star::uno::TypeClass_SHORT;
85 using ::com::sun::star::uno::TypeClass_UNSIGNED_SHORT;
86 using ::com::sun::star::uno::TypeClass_LONG;
87 using ::com::sun::star::uno::TypeClass_UNSIGNED_LONG;
88 using ::com::sun::star::uno::TypeClass_HYPER;
89 using ::com::sun::star::uno::TypeClass_UNSIGNED_HYPER;
90 using ::com::sun::star::uno::TypeClass_FLOAT;
91 using ::com::sun::star::uno::TypeClass_DOUBLE;
92 using ::com::sun::star::uno::TypeClass_STRING;
93 using ::com::sun::star::uno::TypeClass_TYPE;
94 using ::com::sun::star::uno::TypeClass_ENUM;
95 using ::com::sun::star::uno::TypeClass_INTERFACE;
96 using ::com::sun::star::uno::TypeClass_UNKNOWN;
97 using ::com::sun::star::uno::TypeClass_ANY;
98 using ::com::sun::star::uno::TypeClass_EXCEPTION;
99 using ::com::sun::star::uno::TypeClass_STRUCT;
100 using ::com::sun::star::uno::TypeClass_UNION;
101 using ::com::sun::star::lang::XServiceInfo;
102 using ::com::sun::star::uno::XComponentContext;
103 using ::com::sun::star::container::XEnumeration;
104 using ::com::sun::star::uno::TypeDescription;
105 using ::com::sun::star::lang::WrappedTargetException;
106 using ::com::sun::star::lang::DisposedException;
107 /** === end UNO using === **/
109 //====================================================================
110 //= IKeyPredicateLess
111 //====================================================================
112 class SAL_NO_VTABLE IKeyPredicateLess
114 public:
115 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const = 0;
116 virtual ~IKeyPredicateLess() {}
119 //====================================================================
120 //= LessPredicateAdapter
121 //====================================================================
122 struct LessPredicateAdapter : public ::std::binary_function< Any, Any, bool >
124 LessPredicateAdapter( const IKeyPredicateLess& _predicate )
125 :m_predicate( _predicate )
129 bool operator()( const Any& _lhs, const Any& _rhs ) const
131 return m_predicate.isLess( _lhs, _rhs );
134 private:
135 const IKeyPredicateLess& m_predicate;
137 private:
138 LessPredicateAdapter(); // never implemented
141 //====================================================================
142 //= ScalarPredicateLess
143 //====================================================================
144 template< typename SCALAR >
145 class ScalarPredicateLess : public IKeyPredicateLess
147 public:
148 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
150 SCALAR lhs(0), rhs(0);
151 if ( !( _lhs >>= lhs )
152 || !( _rhs >>= rhs )
154 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
155 return lhs < rhs;
159 //====================================================================
160 //= StringPredicateLess
161 //====================================================================
162 class StringPredicateLess : public IKeyPredicateLess
164 public:
165 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
167 ::rtl::OUString lhs, rhs;
168 if ( !( _lhs >>= lhs )
169 || !( _rhs >>= rhs )
171 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
172 return lhs < rhs;
176 //====================================================================
177 //= TypePredicateLess
178 //====================================================================
179 class TypePredicateLess : public IKeyPredicateLess
181 public:
182 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
184 Type lhs, rhs;
185 if ( !( _lhs >>= lhs )
186 || !( _rhs >>= rhs )
188 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
189 return lhs.getTypeName() < rhs.getTypeName();
193 //====================================================================
194 //= EnumPredicateLess
195 //====================================================================
196 class EnumPredicateLess : public IKeyPredicateLess
198 public:
199 EnumPredicateLess( const Type& _enumType )
200 :m_enumType( _enumType )
204 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
206 sal_Int32 lhs(0), rhs(0);
207 if ( !::cppu::enum2int( lhs, _lhs )
208 || !::cppu::enum2int( rhs, _rhs )
209 || !_lhs.getValueType().equals( m_enumType )
210 || !_rhs.getValueType().equals( m_enumType )
212 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
213 return lhs < rhs;
216 private:
217 const Type m_enumType;
220 //====================================================================
221 //= InterfacePredicateLess
222 //====================================================================
223 class InterfacePredicateLess : public IKeyPredicateLess
225 public:
226 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
228 if ( ( _lhs.getValueTypeClass() != TypeClass_INTERFACE )
229 || ( _rhs.getValueTypeClass() != TypeClass_INTERFACE )
231 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
233 Reference< XInterface > lhs( _lhs, UNO_QUERY );
234 Reference< XInterface > rhs( _rhs, UNO_QUERY );
235 return lhs.get() < rhs.get();
239 //====================================================================
240 //= MapData
241 //====================================================================
242 class IMapModificationListener;
243 typedef ::std::vector< IMapModificationListener* > MapListeners;
245 typedef ::std::map< Any, Any, LessPredicateAdapter > KeyedValues;
246 struct MapData
248 Type m_aKeyType;
249 Type m_aValueType;
250 ::std::auto_ptr< KeyedValues > m_pValues;
251 ::boost::shared_ptr< IKeyPredicateLess > m_pKeyCompare;
252 bool m_bMutable;
253 MapListeners m_aModListeners;
255 MapData()
256 :m_bMutable( true )
260 MapData( const MapData& _source )
261 :m_aKeyType( _source.m_aKeyType )
262 ,m_aValueType( _source.m_aValueType )
263 ,m_pValues( new KeyedValues( *_source.m_pValues ) )
264 ,m_pKeyCompare( _source.m_pKeyCompare )
265 ,m_bMutable( false )
266 ,m_aModListeners()
269 private:
270 MapData& operator=( const MapData& _source ); // not implemented
273 //====================================================================
274 //= IMapModificationListener
275 //====================================================================
276 /** implemented by components who want to be notified of modifications in the MapData they work with
278 class SAL_NO_VTABLE IMapModificationListener
280 public:
281 /// called when the map was modified
282 virtual void mapModified() = 0;
283 virtual ~IMapModificationListener()
288 //====================================================================
289 //= MapData helpers
290 //====================================================================
291 //--------------------------------------------------------------------
292 static void lcl_registerMapModificationListener( MapData& _mapData, IMapModificationListener& _listener )
294 #if OSL_DEBUG_LEVEL > 0
295 for ( MapListeners::const_iterator lookup = _mapData.m_aModListeners.begin();
296 lookup != _mapData.m_aModListeners.end();
297 ++lookup
300 OSL_ENSURE( *lookup != &_listener, "lcl_registerMapModificationListener: this listener is already registered!" );
302 #endif
303 _mapData.m_aModListeners.push_back( &_listener );
306 //--------------------------------------------------------------------
307 static void lcl_revokeMapModificationListener( MapData& _mapData, IMapModificationListener& _listener )
309 for ( MapListeners::iterator lookup = _mapData.m_aModListeners.begin();
310 lookup != _mapData.m_aModListeners.end();
311 ++lookup
314 if ( *lookup == &_listener )
316 _mapData.m_aModListeners.erase( lookup );
317 return;
320 OSL_ENSURE( false, "lcl_revokeMapModificationListener: the listener is not registered!" );
323 //--------------------------------------------------------------------
324 static void lcl_notifyMapDataListeners_nothrow( const MapData& _mapData )
326 for ( MapListeners::const_iterator loop = _mapData.m_aModListeners.begin();
327 loop != _mapData.m_aModListeners.end();
328 ++loop
331 (*loop)->mapModified();
335 //====================================================================
336 //= EnumerableMap
337 //====================================================================
338 typedef ::cppu::WeakAggComponentImplHelper3 < XInitialization
339 , XEnumerableMap
340 , XServiceInfo
341 > Map_IFace;
343 class COMPHELPER_DLLPRIVATE EnumerableMap :public Map_IFace
344 ,public ComponentBase
346 protected:
347 EnumerableMap( const ComponentContext& _rContext );
348 virtual ~EnumerableMap();
350 // XInitialization
351 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException);
353 // XEnumerableMap
354 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);
355 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);
356 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);
358 // XMap
359 virtual Type SAL_CALL getKeyType() throw (RuntimeException);
360 virtual Type SAL_CALL getValueType() throw (RuntimeException);
361 virtual void SAL_CALL clear( ) throw (NoSupportException, RuntimeException);
362 virtual ::sal_Bool SAL_CALL containsKey( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException);
363 virtual ::sal_Bool SAL_CALL containsValue( const Any& _value ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException);
364 virtual Any SAL_CALL get( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException);
365 virtual Any SAL_CALL put( const Any& _key, const Any& _value ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, RuntimeException);
366 virtual Any SAL_CALL remove( const Any& _key ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException);
368 // XElementAccess (base of XMap)
369 virtual Type SAL_CALL getElementType() throw (RuntimeException);
370 virtual ::sal_Bool SAL_CALL hasElements() throw (RuntimeException);
372 // XServiceInfo
373 virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (RuntimeException);
374 virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException);
375 virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (RuntimeException);
377 public:
378 // XServiceInfo, static version (used for component registration)
379 static ::rtl::OUString SAL_CALL getImplementationName_static( );
380 static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static( );
381 static Reference< XInterface > SAL_CALL Create( const Reference< XComponentContext >& );
383 private:
384 void impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues );
386 /// throws a IllegalTypeException if the given value is not compatible with our ValueType
387 void impl_checkValue_throw( const Any& _value ) const;
388 void impl_checkKey_throw( const Any& _key ) const;
389 void impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const;
390 void impl_checkMutable_throw() const;
392 private:
393 ::osl::Mutex m_aMutex;
394 ComponentContext m_aContext;
395 MapData m_aData;
397 ::std::vector< ::com::sun::star::uno::WeakReference< XInterface > >
398 m_aDependentComponents;
401 //====================================================================
402 //= EnumerationType
403 //====================================================================
404 enum EnumerationType
406 eKeys, eValues, eBoth
409 //====================================================================
410 //= MapEnumerator
411 //====================================================================
412 class MapEnumerator : public IMapModificationListener
414 public:
415 MapEnumerator( ::cppu::OWeakObject& _rParent, MapData& _mapData, const EnumerationType _type )
416 :m_rParent( _rParent )
417 ,m_rMapData( _mapData )
418 ,m_eType( _type )
419 ,m_mapPos( _mapData.m_pValues->begin() )
420 ,m_disposed( false )
422 lcl_registerMapModificationListener( m_rMapData, *this );
425 virtual ~MapEnumerator()
427 dispose();
430 void dispose()
432 if ( !m_disposed )
434 lcl_revokeMapModificationListener( m_rMapData, *this );
435 m_disposed = true;
439 // XEnumeration equivalents
440 ::sal_Bool hasMoreElements();
441 Any nextElement();
443 // IMapModificationListener
444 virtual void mapModified();
446 private:
447 ::cppu::OWeakObject& m_rParent;
448 MapData& m_rMapData;
449 const EnumerationType m_eType;
450 KeyedValues::const_iterator m_mapPos;
451 bool m_disposed;
453 private:
454 MapEnumerator(); // not implemented
455 MapEnumerator( const MapEnumerator& ); // not implemented
456 MapEnumerator& operator=( const MapEnumerator& ); // not implemented
459 //====================================================================
460 //= MapEnumeration
461 //====================================================================
462 typedef ::cppu::WeakImplHelper1 < XEnumeration
463 > MapEnumeration_Base;
464 class MapEnumeration :public ComponentBase
465 ,public MapEnumeration_Base
467 public:
468 MapEnumeration( ::cppu::OWeakObject& _parentMap, MapData& _mapData, ::cppu::OBroadcastHelper& _rBHelper,
469 const EnumerationType _type, const bool _isolated )
470 :ComponentBase( _rBHelper, ComponentBase::NoInitializationNeeded() )
471 ,m_xKeepMapAlive( _parentMap )
472 ,m_pMapDataCopy( _isolated ? new MapData( _mapData ) : NULL )
473 ,m_aEnumerator( *this, _isolated ? *m_pMapDataCopy : _mapData, _type )
477 // XEnumeration
478 virtual ::sal_Bool SAL_CALL hasMoreElements( ) throw (RuntimeException);
479 virtual Any SAL_CALL nextElement( ) throw (NoSuchElementException, WrappedTargetException, RuntimeException);
481 protected:
482 virtual ~MapEnumeration()
484 acquire();
486 ::osl::MutexGuard aGuard( getMutex() );
487 m_aEnumerator.dispose();
488 m_pMapDataCopy.reset();
492 private:
493 // sicne we share our mutex with the main map, we need to keep it alive as long as we live
494 Reference< XInterface > m_xKeepMapAlive;
495 ::std::auto_ptr< MapData > m_pMapDataCopy;
496 MapEnumerator m_aEnumerator;
499 //====================================================================
500 //= EnumerableMap
501 //====================================================================
502 //--------------------------------------------------------------------
503 EnumerableMap::EnumerableMap( const ComponentContext& _rContext )
504 :Map_IFace( m_aMutex )
505 ,ComponentBase( Map_IFace::rBHelper )
506 ,m_aContext( _rContext )
510 //--------------------------------------------------------------------
511 EnumerableMap::~EnumerableMap()
513 if ( !impl_isDisposed() )
515 acquire();
516 dispose();
520 //--------------------------------------------------------------------
521 void SAL_CALL EnumerableMap::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException)
523 ComponentMethodGuard aGuard( *this, ComponentMethodGuard::WithoutInit );
524 if ( impl_isInitialized_nothrow() )
525 throw AlreadyInitializedException();
527 sal_Int32 nArgumentCount = _arguments.getLength();
528 if ( ( nArgumentCount != 2 ) && ( nArgumentCount != 3 ) )
529 throw IllegalArgumentException();
531 Type aKeyType, aValueType;
532 if ( !( _arguments[0] >>= aKeyType ) )
533 throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "com.sun.star.uno.Type expected." ), *this, 1 );
534 if ( !( _arguments[1] >>= aValueType ) )
535 throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "com.sun.star.uno.Type expected." ), *this, 2 );
537 Sequence< Pair< Any, Any > > aInitialValues;
538 bool bMutable = true;
539 if ( nArgumentCount == 3 )
541 if ( !( _arguments[2] >>= aInitialValues ) )
542 throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "[]com.sun.star.beans.Pair<any,any> expected." ), *this, 2 );
543 bMutable = false;
546 // for the value, anything is allowed, except VOID
547 if ( ( aValueType.getTypeClass() == TypeClass_VOID ) || ( aValueType.getTypeClass() == TypeClass_UNKNOWN ) )
548 throw IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported value type." ) ), *this );
550 // create the comparator for the KeyType, and throw if the type is not supported
551 TypeClass eKeyTypeClass = aKeyType.getTypeClass();
552 ::std::auto_ptr< IKeyPredicateLess > pComparator;
553 switch ( eKeyTypeClass )
555 case TypeClass_CHAR:
556 pComparator.reset( new ScalarPredicateLess< sal_Unicode >() );
557 break;
558 case TypeClass_BOOLEAN:
559 pComparator.reset( new ScalarPredicateLess< sal_Bool >() );
560 break;
561 case TypeClass_BYTE:
562 pComparator.reset( new ScalarPredicateLess< sal_Int8 >() );
563 break;
564 case TypeClass_SHORT:
565 pComparator.reset( new ScalarPredicateLess< sal_Int16 >() );
566 break;
567 case TypeClass_UNSIGNED_SHORT:
568 pComparator.reset( new ScalarPredicateLess< sal_uInt16 >() );
569 break;
570 case TypeClass_LONG:
571 pComparator.reset( new ScalarPredicateLess< sal_Int32 >() );
572 break;
573 case TypeClass_UNSIGNED_LONG:
574 pComparator.reset( new ScalarPredicateLess< sal_uInt32 >() );
575 break;
576 case TypeClass_HYPER:
577 pComparator.reset( new ScalarPredicateLess< sal_Int64 >() );
578 break;
579 case TypeClass_UNSIGNED_HYPER:
580 pComparator.reset( new ScalarPredicateLess< sal_uInt64 >() );
581 break;
582 case TypeClass_FLOAT:
583 pComparator.reset( new ScalarPredicateLess< float >() );
584 break;
585 case TypeClass_DOUBLE:
586 pComparator.reset( new ScalarPredicateLess< double >() );
587 break;
588 case TypeClass_STRING:
589 pComparator.reset( new StringPredicateLess() );
590 break;
591 case TypeClass_TYPE:
592 pComparator.reset( new TypePredicateLess() );
593 break;
594 case TypeClass_ENUM:
595 pComparator.reset( new EnumPredicateLess( aKeyType ) );
596 break;
597 case TypeClass_INTERFACE:
598 pComparator.reset( new InterfacePredicateLess() );
599 break;
600 default:
601 throw IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), *this );
604 // init members
605 m_aData.m_aKeyType = aKeyType;
606 m_aData.m_aValueType = aValueType;
607 m_aData.m_pKeyCompare = pComparator;
608 m_aData.m_pValues.reset( new KeyedValues( *m_aData.m_pKeyCompare ) );
609 m_aData.m_bMutable = bMutable;
611 if ( aInitialValues.getLength() )
612 impl_initValues_throw( aInitialValues );
614 setInitialized();
617 //--------------------------------------------------------------------
618 void EnumerableMap::impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues )
620 OSL_PRECOND( m_aData.m_pValues.get() && m_aData.m_pValues->empty(), "EnumerableMap::impl_initValues_throw: illegal call!" );
621 if ( !m_aData.m_pValues.get() || !m_aData.m_pValues->empty() )
622 throw RuntimeException();
624 const Pair< Any, Any >* mapping = _initialValues.getConstArray();
625 const Pair< Any, Any >* mappingEnd = mapping + _initialValues.getLength();
626 Any normalizedValue;
627 for ( ; mapping != mappingEnd; ++mapping )
629 impl_checkValue_throw( mapping->Second );
630 (*m_aData.m_pValues)[ mapping->First ] = mapping->Second;
634 //--------------------------------------------------------------------
635 void EnumerableMap::impl_checkValue_throw( const Any& _value ) const
637 if ( !_value.hasValue() )
638 // nothing to do, NULL values are always allowed, regardless of the ValueType
639 return;
641 TypeClass eAllowedTypeClass = m_aData.m_aValueType.getTypeClass();
642 bool bValid = false;
644 switch ( eAllowedTypeClass )
646 default:
647 bValid = ( _value.getValueTypeClass() == eAllowedTypeClass );
648 break;
649 case TypeClass_ANY:
650 bValid = true;
651 break;
652 case TypeClass_INTERFACE:
654 // special treatment: _value might contain the proper type, but the interface
655 // might actually be NULL. Which is still valid ...
656 if ( m_aData.m_aValueType.isAssignableFrom( _value.getValueType() ) )
657 // this also catches the special case where XFoo is our value type,
658 // and _value contains a NULL-reference to XFoo, or a derived type
659 bValid = true;
660 else
662 Reference< XInterface > xValue( _value, UNO_QUERY );
663 Any aTypedValue;
664 if ( xValue.is() )
665 // XInterface is not-NULL, but is X(ValueType) not-NULL, too?
666 xValue.set( xValue->queryInterface( m_aData.m_aValueType ), UNO_QUERY );
667 bValid = xValue.is();
670 break;
671 case TypeClass_EXCEPTION:
672 case TypeClass_STRUCT:
673 case TypeClass_UNION:
675 // values are accepted if and only if their type equals, or is derived from, our value type
677 if ( _value.getValueTypeClass() != eAllowedTypeClass )
678 bValid = false;
679 else
681 const TypeDescription aValueTypeDesc( _value.getValueType() );
682 const TypeDescription aRequiredTypeDesc( m_aData.m_aValueType );
684 const _typelib_CompoundTypeDescription* pValueCompoundTypeDesc =
685 reinterpret_cast< const _typelib_CompoundTypeDescription* >( aValueTypeDesc.get() );
687 while ( pValueCompoundTypeDesc )
689 if ( typelib_typedescription_equals( &pValueCompoundTypeDesc->aBase, aRequiredTypeDesc.get() ) )
690 break;
691 pValueCompoundTypeDesc = pValueCompoundTypeDesc->pBaseTypeDescription;
693 bValid = ( pValueCompoundTypeDesc != NULL );
696 break;
699 if ( !bValid )
701 ::rtl::OUStringBuffer aMessage;
702 aMessage.appendAscii( "Incompatible value type. Found '" );
703 aMessage.append( _value.getValueTypeName() );
704 aMessage.appendAscii( "', where '" );
705 aMessage.append( m_aData.m_aValueType.getTypeName() );
706 aMessage.appendAscii( "' (or compatible type) is expected." );
707 throw IllegalTypeException( aMessage.makeStringAndClear(), *const_cast< EnumerableMap* >( this ) );
710 impl_checkNaN_throw( _value, m_aData.m_aValueType );
713 //--------------------------------------------------------------------
714 void EnumerableMap::impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const
716 if ( ( _keyOrValueType.getTypeClass() == TypeClass_DOUBLE )
717 || ( _keyOrValueType.getTypeClass() == TypeClass_FLOAT )
720 double nValue(0);
721 if ( _keyOrValue >>= nValue )
722 if ( ::rtl::math::isNan( nValue ) )
723 throw IllegalArgumentException(
724 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NaN (not-a-number) not supported by this implementation." ) ),
725 *const_cast< EnumerableMap* >( this ), 0 );
726 // (note that the case of _key not containing a float/double value is handled in the
727 // respective IKeyPredicateLess implementation, so there's no need to handle this here.)
731 //--------------------------------------------------------------------
732 void EnumerableMap::impl_checkKey_throw( const Any& _key ) const
734 if ( !_key.hasValue() )
735 throw IllegalArgumentException(
736 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NULL keys not supported by this implementation." ) ),
737 *const_cast< EnumerableMap* >( this ), 0 );
739 impl_checkNaN_throw( _key, m_aData.m_aKeyType );
742 //--------------------------------------------------------------------
743 void EnumerableMap::impl_checkMutable_throw() const
745 if ( !m_aData.m_bMutable )
746 throw NoSupportException(
747 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "The map is immutable." ) ),
748 *const_cast< EnumerableMap* >( this ) );
751 //--------------------------------------------------------------------
752 Reference< XEnumeration > SAL_CALL EnumerableMap::createKeyEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException)
754 ComponentMethodGuard aGuard( *this );
755 return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eKeys, _Isolated );
758 //--------------------------------------------------------------------
759 Reference< XEnumeration > SAL_CALL EnumerableMap::createValueEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException)
761 ComponentMethodGuard aGuard( *this );
762 return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eValues, _Isolated );
765 //--------------------------------------------------------------------
766 Reference< XEnumeration > SAL_CALL EnumerableMap::createElementEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException)
768 ComponentMethodGuard aGuard( *this );
769 return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eBoth, _Isolated );
772 //--------------------------------------------------------------------
773 Type SAL_CALL EnumerableMap::getKeyType() throw (RuntimeException)
775 ComponentMethodGuard aGuard( *this );
776 return m_aData.m_aKeyType;
779 //--------------------------------------------------------------------
780 Type SAL_CALL EnumerableMap::getValueType() throw (RuntimeException)
782 ComponentMethodGuard aGuard( *this );
783 return m_aData.m_aValueType;
786 //--------------------------------------------------------------------
787 void SAL_CALL EnumerableMap::clear( ) throw (NoSupportException, RuntimeException)
789 ComponentMethodGuard aGuard( *this );
790 impl_checkMutable_throw();
792 m_aData.m_pValues->clear();
794 lcl_notifyMapDataListeners_nothrow( m_aData );
797 //--------------------------------------------------------------------
798 ::sal_Bool SAL_CALL EnumerableMap::containsKey( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException)
800 ComponentMethodGuard aGuard( *this );
801 impl_checkKey_throw( _key );
803 KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
804 return ( pos != m_aData.m_pValues->end() );
807 //--------------------------------------------------------------------
808 ::sal_Bool SAL_CALL EnumerableMap::containsValue( const Any& _value ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException)
810 ComponentMethodGuard aGuard( *this );
811 impl_checkValue_throw( _value );
813 for ( KeyedValues::const_iterator mapping = m_aData.m_pValues->begin();
814 mapping != m_aData.m_pValues->end();
815 ++mapping
818 if ( mapping->second == _value )
819 return sal_True;
821 return sal_False;
824 //--------------------------------------------------------------------
825 Any SAL_CALL EnumerableMap::get( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException)
827 ComponentMethodGuard aGuard( *this );
828 impl_checkKey_throw( _key );
830 KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
831 if ( pos == m_aData.m_pValues->end() )
832 throw NoSuchElementException( anyToString( _key ), *this );
834 return pos->second;
837 //--------------------------------------------------------------------
838 Any SAL_CALL EnumerableMap::put( const Any& _key, const Any& _value ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, RuntimeException)
840 ComponentMethodGuard aGuard( *this );
841 impl_checkMutable_throw();
842 impl_checkKey_throw( _key );
843 impl_checkValue_throw( _value );
845 Any previousValue;
847 KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
848 if ( pos != m_aData.m_pValues->end() )
850 previousValue = pos->second;
851 pos->second = _value;
853 else
855 (*m_aData.m_pValues)[ _key ] = _value;
858 lcl_notifyMapDataListeners_nothrow( m_aData );
860 return previousValue;
863 //--------------------------------------------------------------------
864 Any SAL_CALL EnumerableMap::remove( const Any& _key ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException)
866 ComponentMethodGuard aGuard( *this );
867 impl_checkMutable_throw();
868 impl_checkKey_throw( _key );
870 Any previousValue;
872 KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
873 if ( pos != m_aData.m_pValues->end() )
875 previousValue = pos->second;
876 m_aData.m_pValues->erase( pos );
879 lcl_notifyMapDataListeners_nothrow( m_aData );
881 return previousValue;
884 //--------------------------------------------------------------------
885 Type SAL_CALL EnumerableMap::getElementType() throw (RuntimeException)
887 return ::cppu::UnoType< Pair< Any, Any > >::get();
890 //--------------------------------------------------------------------
891 ::sal_Bool SAL_CALL EnumerableMap::hasElements() throw (RuntimeException)
893 ComponentMethodGuard aGuard( *this );
894 return m_aData.m_pValues->empty();
897 //--------------------------------------------------------------------
898 ::rtl::OUString SAL_CALL EnumerableMap::getImplementationName( ) throw (RuntimeException)
900 return getImplementationName_static();
903 //--------------------------------------------------------------------
904 ::sal_Bool SAL_CALL EnumerableMap::supportsService( const ::rtl::OUString& _serviceName ) throw (RuntimeException)
906 Sequence< ::rtl::OUString > aServices( getSupportedServiceNames() );
907 for ( sal_Int32 i=0; i<aServices.getLength(); ++i )
908 if ( _serviceName == aServices[i] )
909 return sal_True;
910 return sal_False;
913 //--------------------------------------------------------------------
914 Sequence< ::rtl::OUString > SAL_CALL EnumerableMap::getSupportedServiceNames( ) throw (RuntimeException)
916 return getSupportedServiceNames_static();
919 //--------------------------------------------------------------------
920 ::rtl::OUString SAL_CALL EnumerableMap::getImplementationName_static( )
922 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.comphelper.EnumerableMap" ) );
925 //--------------------------------------------------------------------
926 Sequence< ::rtl::OUString > SAL_CALL EnumerableMap::getSupportedServiceNames_static( )
928 Sequence< ::rtl::OUString > aServiceNames(1);
929 aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.container.EnumerableMap" ) );
930 return aServiceNames;
933 //--------------------------------------------------------------------
934 Reference< XInterface > SAL_CALL EnumerableMap::Create( const Reference< XComponentContext >& _context )
936 return *new EnumerableMap( ComponentContext( _context ) );
939 //====================================================================
940 //= MapEnumerator
941 //====================================================================
942 //--------------------------------------------------------------------
943 ::sal_Bool MapEnumerator::hasMoreElements()
945 if ( m_disposed )
946 throw DisposedException( ::rtl::OUString(), m_rParent );
947 return m_mapPos != m_rMapData.m_pValues->end();
950 //--------------------------------------------------------------------
951 Any MapEnumerator::nextElement()
953 if ( m_disposed )
954 throw DisposedException( ::rtl::OUString(), m_rParent );
955 if ( m_mapPos == m_rMapData.m_pValues->end() )
956 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No more elements." ) ), m_rParent );
958 Any aNextElement;
959 switch ( m_eType )
961 case eKeys: aNextElement = m_mapPos->first; break;
962 case eValues: aNextElement = m_mapPos->second; break;
963 case eBoth: aNextElement <<= Pair< Any, Any >( m_mapPos->first, m_mapPos->second ); break;
965 ++m_mapPos;
966 return aNextElement;
969 //--------------------------------------------------------------------
970 void MapEnumerator::mapModified()
972 m_disposed = true;
975 //====================================================================
976 //= MapEnumeration - implementation
977 //====================================================================
978 //--------------------------------------------------------------------
979 ::sal_Bool SAL_CALL MapEnumeration::hasMoreElements( ) throw (RuntimeException)
981 ComponentMethodGuard aGuard( *this );
982 return m_aEnumerator.hasMoreElements();
985 //--------------------------------------------------------------------
986 Any SAL_CALL MapEnumeration::nextElement( ) throw (NoSuchElementException, WrappedTargetException, RuntimeException)
988 ComponentMethodGuard aGuard( *this );
989 return m_aEnumerator.nextElement();
992 //........................................................................
993 } // namespace comphelper
994 //........................................................................
996 void createRegistryInfo_Map()
998 ::comphelper::module::OAutoRegistration< ::comphelper::EnumerableMap > aAutoRegistration;