1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 #ifndef _CPPUHELPER_INTERFACECONTAINER_H_ 28 #define _CPPUHELPER_INTERFACECONTAINER_H_ 29 30 #include <vector> 31 #include <osl/mutex.hxx> 32 #include <rtl/alloc.h> 33 #include <com/sun/star/uno/Sequence.hxx> 34 #include <com/sun/star/uno/XInterface.hpp> 35 #ifndef _COM_SUN_STAR_LANG_EVENTOBJECT_HXX_ 36 #include <com/sun/star/lang/EventObject.hpp> 37 #endif 38 39 #ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HXX_ 40 #include "com/sun/star/lang/DisposedException.hpp" 41 #endif 42 43 /** */ //for docpp 44 namespace cppu 45 { 46 47 namespace detail { 48 49 union element_alias 50 { 51 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > *pAsSequence; 52 ::com::sun::star::uno::XInterface * pAsInterface; 53 element_alias() : pAsInterface(0) {} 54 }; 55 56 } 57 58 //=================================================================== 59 class OInterfaceContainerHelper; 60 /** 61 This is the iterator of a InterfaceContainerHelper. Typically 62 one constructs an instance on the stack for one firing session. 63 It is not allowed to assign or copy an instance of this class. 64 65 @see OInterfaceContainerHelper 66 */ 67 class OInterfaceIteratorHelper 68 { 69 public: 70 /** 71 Create an iterator over the elements of the container. The iterator 72 copies the elements of the conatainer. A change to the container 73 during the lifetime of an iterator is allowed and does not 74 affect the iterator-instance. The iterator and the container take cares 75 themself for concurrent access, no additional guarding is necessary. 76 77 Remark: The copy is on demand. The iterator copy the elements only if the container 78 change the contents. It is not allowed to destroy the container as long 79 as an iterator exist. 80 81 @param rCont the container of the elements. 82 */ 83 OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont ) SAL_THROW( () ); 84 85 /** 86 Releases the connection to the container. 87 */ 88 ~OInterfaceIteratorHelper() SAL_THROW( () ); 89 90 /** Return sal_True, if there are more elements in the iterator. */ 91 sal_Bool SAL_CALL hasMoreElements() const SAL_THROW( () ) 92 { return nRemain != 0; } 93 /** Return the next element of the iterator. Calling this method if 94 hasMoreElements() has returned sal_False, is an error. Cast the 95 returned pointer to the 96 */ 97 ::com::sun::star::uno::XInterface * SAL_CALL next() SAL_THROW( () ); 98 99 /** Removes the current element (the last one returned by next()) 100 from the underlying container. Calling this method before 101 next() has been called or calling it twice with no next() 102 inbetween is an error. 103 */ 104 void SAL_CALL remove() SAL_THROW( () ); 105 106 private: 107 OInterfaceContainerHelper & rCont; 108 sal_Bool bIsList; 109 110 detail::element_alias aData; 111 112 sal_Int32 nRemain; 113 114 OInterfaceIteratorHelper( const OInterfaceIteratorHelper & ) SAL_THROW( () ); 115 OInterfaceIteratorHelper & operator = ( const OInterfaceIteratorHelper & ) SAL_THROW( () ); 116 }; 117 118 //=================================================================== 119 /** 120 A container of interfaces. To access the elements use an iterator. 121 This implementation is thread save. 122 123 @see OInterfaceIteratorHelper 124 */ 125 class OInterfaceContainerHelper 126 { 127 public: 128 // these are here to force memory de/allocation to sal lib. 129 inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () ) 130 { return ::rtl_allocateMemory( nSize ); } 131 inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () ) 132 { ::rtl_freeMemory( pMem ); } 133 inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () ) 134 { return pMem; } 135 inline static void SAL_CALL operator delete( void *, void * ) SAL_THROW( () ) 136 {} 137 138 /** 139 Create an interface container. 140 141 @param rMutex the mutex to protect multi thread access. 142 The lifetime must be longer than the lifetime 143 of this object. 144 */ 145 OInterfaceContainerHelper( ::osl::Mutex & rMutex ) SAL_THROW( () ); 146 /** 147 Release all interfaces. All iterators must be destroyed before 148 the container is destructed. 149 */ 150 ~OInterfaceContainerHelper() SAL_THROW( () ); 151 /** 152 Return the number of Elements in the container. Only useful if you have acquired 153 the mutex. 154 */ 155 sal_Int32 SAL_CALL getLength() const SAL_THROW( () ); 156 157 /** 158 Return all interfaces added to this container. 159 **/ 160 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > SAL_CALL getElements() const SAL_THROW( () ); 161 162 /** Inserts an element into the container. The position is not specified, thus it is not 163 specified in which order events are fired. 164 165 @attention 166 If you add the same interface more than once, then it will be added to the elements list 167 more than once and thus if you want to remove that interface from the list, you have to call 168 removeInterface() the same number of times. 169 In the latter case, you will also get events fired more than once (if the interface is a 170 listener interface). 171 172 @param rxIFace 173 interface to be added; it is allowed to insert null or 174 the same interface more than once 175 @return 176 the new count of elements in the container 177 */ 178 sal_Int32 SAL_CALL addInterface( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & rxIFace ) SAL_THROW( () ); 179 /** Removes an element from the container. It uses interface equality to remove the interface. 180 181 @param rxIFace 182 interface to be removed 183 @return 184 the new count of elements in the container 185 */ 186 sal_Int32 SAL_CALL removeInterface( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & rxIFace ) SAL_THROW( () ); 187 /** 188 Call disposing on all object in the container that 189 support XEventListener. Than clear the container. 190 */ 191 void SAL_CALL disposeAndClear( const ::com::sun::star::lang::EventObject & rEvt ) SAL_THROW( () ); 192 /** 193 Clears the container without calling disposing(). 194 */ 195 void SAL_CALL clear() SAL_THROW( () ); 196 197 /** Executes a functor for each contained listener of specified type, e.g. 198 <code>forEach<awt::XPaintListener>(...</code>. 199 200 If a com::sun::star::lang::DisposedException occurs which relates to 201 the called listener, then that listener is removed from the container. 202 203 @tpl ListenerT listener type 204 @tpl FuncT unary functor type, let your compiler deduce this for you 205 @param func unary functor object expecting an argument of type 206 ::com::sun::star::uno::Reference<ListenerT> 207 */ 208 template <typename ListenerT, typename FuncT> 209 inline void forEach( FuncT const& func ); 210 211 /** Calls a UNO listener method for each contained listener. 212 213 The listener method must take a single argument of type EventT, 214 and return <code>void</code>. 215 216 If a com::sun::star::lang::DisposedException occurs which relates to 217 the called listener, then that listener is removed from the container. 218 219 @tpl ListenerT UNO event listener type, let your compiler deduce this for you 220 @tpl EventT event type, let your compiler deduce this for you 221 @param NotificationMethod 222 Pointer to a method of a ListenerT interface. 223 @param Event 224 Event to notify to all contained listeners 225 226 @example 227 <pre> 228 awt::PaintEvent aEvent( static_cast< ::cppu::OWeakObject* >( this ), ... ); 229 listeners.notifyEach( &XPaintListener::windowPaint, aEvent ); 230 </pre> 231 */ 232 template< typename ListenerT, typename EventT > 233 inline void notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event ); 234 235 private: 236 friend class OInterfaceIteratorHelper; 237 /** 238 bIsList == TRUE -> aData.pAsSequence of type Sequence< XInterfaceSequence >, 239 otherwise aData.pAsInterface == of type (XEventListener *) 240 */ 241 detail::element_alias aData; 242 ::osl::Mutex & rMutex; 243 /** TRUE -> used by an iterator. */ 244 sal_Bool bInUse; 245 /** TRUE -> aData.pAsSequence is of type Sequence< XInterfaceSequence >. */ 246 sal_Bool bIsList; 247 248 OInterfaceContainerHelper( const OInterfaceContainerHelper & ) SAL_THROW( () ); 249 OInterfaceContainerHelper & operator = ( const OInterfaceContainerHelper & ) SAL_THROW( () ); 250 251 /* 252 Dulicate content of the conaitner and release the old one without destroying. 253 The mutex must be locked and the memberbInUse must be true. 254 */ 255 void copyAndResetInUse() SAL_THROW( () ); 256 257 private: 258 template< typename ListenerT, typename EventT > 259 class NotifySingleListener 260 { 261 private: 262 typedef void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ); 263 NotificationMethod m_pMethod; 264 const EventT& m_rEvent; 265 public: 266 NotifySingleListener( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { } 267 268 void operator()( const ::com::sun::star::uno::Reference<ListenerT>& listener ) const 269 { 270 (listener.get()->*m_pMethod)( m_rEvent ); 271 } 272 }; 273 }; 274 275 template <typename ListenerT, typename FuncT> 276 inline void OInterfaceContainerHelper::forEach( FuncT const& func ) 277 { 278 OInterfaceIteratorHelper iter( *this ); 279 while (iter.hasMoreElements()) { 280 ::com::sun::star::uno::Reference<ListenerT> const xListener( 281 iter.next(), ::com::sun::star::uno::UNO_QUERY ); 282 if (xListener.is()) { 283 #if defined(EXCEPTIONS_OFF) 284 func( xListener ); 285 #else 286 try { 287 func( xListener ); 288 } 289 catch (::com::sun::star::lang::DisposedException const& exc) { 290 if (exc.Context == xListener) 291 iter.remove(); 292 } 293 #endif 294 } 295 } 296 } 297 298 template< typename ListenerT, typename EventT > 299 inline void OInterfaceContainerHelper::notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event ) 300 { 301 forEach< ListenerT, NotifySingleListener< ListenerT, EventT > >( NotifySingleListener< ListenerT, EventT >( NotificationMethod, Event ) ); 302 } 303 304 //=================================================================== 305 /** 306 A helper class to store interface references of different types. 307 308 @see OInterfaceIteratorHelper 309 @see OInterfaceContainerHelper 310 */ 311 template< class key , class hashImpl , class equalImpl > 312 class OMultiTypeInterfaceContainerHelperVar 313 { 314 public: 315 // these are here to force memory de/allocation to sal lib. 316 inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () ) 317 { return ::rtl_allocateMemory( nSize ); } 318 inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () ) 319 { ::rtl_freeMemory( pMem ); } 320 inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () ) 321 { return pMem; } 322 inline static void SAL_CALL operator delete( void *, void * ) SAL_THROW( () ) 323 {} 324 325 /** 326 Create a container of interface containers. 327 328 @param rMutex the mutex to protect multi thread access. 329 The lifetime must be longer than the lifetime 330 of this object. 331 */ 332 inline OMultiTypeInterfaceContainerHelperVar( ::osl::Mutex & ) SAL_THROW( () ); 333 /** 334 Deletes all containers. 335 */ 336 inline ~OMultiTypeInterfaceContainerHelperVar() SAL_THROW( () ); 337 338 /** 339 Return all id's under which at least one interface is added. 340 */ 341 inline ::com::sun::star::uno::Sequence< key > SAL_CALL getContainedTypes() const SAL_THROW( () ); 342 343 /** 344 Return the container created under this key. 345 The InterfaceContainerHelper exists until the whole MultiTypeContainer is destroyed. 346 @return the container created under this key. If the container 347 was not created, null was returned. 348 */ 349 inline OInterfaceContainerHelper * SAL_CALL getContainer( const key & ) const SAL_THROW( () ); 350 351 /** Inserts an element into the container with the specified key. 352 The position is not specified, thus it is not specified in which order events are fired. 353 354 @attention 355 If you add the same interface more than once, then it will be added to the elements list 356 more than once and thus if you want to remove that interface from the list, you have to call 357 removeInterface() the same number of times. 358 In the latter case, you will also get events fired more than once (if the interface is a 359 listener interface). 360 361 @param rKey 362 the id of the container 363 @param r 364 interface to be added; it is allowed, to insert null or 365 the same interface more than once 366 @return 367 the new count of elements in the container 368 */ 369 inline sal_Int32 SAL_CALL addInterface( 370 const key & rKey, 371 const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & r ) 372 SAL_THROW( () ); 373 374 /** Removes an element from the container with the specified key. 375 It uses interface equality to remove the interface. 376 377 @param rKey 378 the id of the container 379 @param rxIFace 380 interface to be removed 381 @return 382 the new count of elements in the container 383 */ 384 inline sal_Int32 SAL_CALL removeInterface( 385 const key & rKey, 386 const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & rxIFace ) 387 SAL_THROW( () ); 388 389 /** 390 Call disposing on all references in the container, that 391 support XEventListener. Then clears the container. 392 @param rEvt the event object which is passed during disposing() call 393 */ 394 inline void SAL_CALL disposeAndClear( const ::com::sun::star::lang::EventObject & rEvt ) SAL_THROW( () ); 395 /** 396 Remove all elements of all containers. Does not delete the container. 397 */ 398 inline void SAL_CALL clear() SAL_THROW( () ); 399 400 typedef key keyType; 401 private: 402 typedef ::std::vector< std::pair < key , void* > > InterfaceMap; 403 InterfaceMap *m_pMap; 404 ::osl::Mutex & rMutex; 405 406 inline typename InterfaceMap::iterator find(const key &rKey) const 407 { 408 typename InterfaceMap::iterator iter = m_pMap->begin(); 409 typename InterfaceMap::iterator end = m_pMap->end(); 410 411 while( iter != end ) 412 { 413 equalImpl equal; 414 if( equal( iter->first, rKey ) ) 415 break; 416 iter++; 417 } 418 return iter; 419 } 420 421 inline OMultiTypeInterfaceContainerHelperVar( const OMultiTypeInterfaceContainerHelperVar & ) SAL_THROW( () ); 422 inline OMultiTypeInterfaceContainerHelperVar & operator = ( const OMultiTypeInterfaceContainerHelperVar & ) SAL_THROW( () ); 423 }; 424 425 426 427 428 /** 429 This struct contains the standard variables of a broadcaster. Helper 430 classes only know a reference to this struct instead of references 431 to the four members. The access to the members must be guarded with 432 rMutex. 433 434 The additional template parameter keyType has been added, because gcc 435 can't compile addListener( const container::keyType &key ). 436 */ 437 template < class container , class keyType > 438 struct OBroadcastHelperVar 439 { 440 /** The shared mutex. */ 441 ::osl::Mutex & rMutex; 442 /** ListenerContainer class is thread save. */ 443 container aLC; 444 /** Dispose call ready. */ 445 sal_Bool bDisposed; 446 /** In dispose call. */ 447 sal_Bool bInDispose; 448 449 /** 450 Initialize the structur. bDispose and bInDispose are set to false. 451 @param rMutex the mutex reference. 452 */ 453 OBroadcastHelperVar( ::osl::Mutex & rMutex_ ) SAL_THROW( () ) 454 : rMutex( rMutex_ ) 455 , aLC( rMutex_ ) 456 , bDisposed( sal_False ) 457 , bInDispose( sal_False ) 458 {} 459 460 /** 461 adds a listener threadsafe. 462 **/ 463 inline void addListener( 464 const keyType &key, 465 const ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface > &r ) 466 SAL_THROW( () ) 467 { 468 ::osl::MutexGuard guard( rMutex ); 469 OSL_ENSURE( !bInDispose, "do not add listeners in the dispose call" ); 470 OSL_ENSURE( !bDisposed, "object is disposed" ); 471 if( ! bInDispose && ! bDisposed ) 472 aLC.addInterface( key , r ); 473 } 474 475 /** 476 removes a listener threadsafe 477 **/ 478 inline void removeListener( 479 const keyType &key, 480 const ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface > & r ) 481 SAL_THROW( () ) 482 { 483 ::osl::MutexGuard guard( rMutex ); 484 OSL_ENSURE( !bDisposed, "object is disposed" ); 485 if( ! bInDispose && ! bDisposed ) 486 aLC.removeInterface( key , r ); 487 } 488 489 /** 490 Return the container created under this key. 491 @return the container created under this key. If the container 492 was not created, null was returned. This can be used to optimize 493 performance ( construction of an event object can be avoided ). 494 ***/ 495 inline OInterfaceContainerHelper * SAL_CALL getContainer( const keyType &key ) const SAL_THROW( () ) 496 { return aLC.getContainer( key ); } 497 }; 498 499 /*------------------------------------------ 500 * 501 * In general, the above templates are used with a Type as key. 502 * Therefore a default declaration is given ( OMultiTypeInterfaceContainerHelper and OBroadcastHelper ) 503 * 504 *------------------------------------------*/ 505 506 // helper function call class 507 struct hashType_Impl 508 { 509 size_t operator()(const ::com::sun::star::uno::Type & s) const SAL_THROW( () ) 510 { return s.getTypeName().hashCode(); } 511 }; 512 513 514 /** Specialized class for key type com::sun::star::uno::Type, 515 without explicit usage of STL symbols. 516 */ 517 class OMultiTypeInterfaceContainerHelper 518 { 519 public: 520 // these are here to force memory de/allocation to sal lib. 521 inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () ) 522 { return ::rtl_allocateMemory( nSize ); } 523 inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () ) 524 { ::rtl_freeMemory( pMem ); } 525 inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () ) 526 { return pMem; } 527 inline static void SAL_CALL operator delete( void *, void * ) SAL_THROW( () ) 528 {} 529 530 /** 531 Create a container of interface containers. 532 533 @param rMutex the mutex to protect multi thread access. 534 The lifetime must be longer than the lifetime 535 of this object. 536 */ 537 OMultiTypeInterfaceContainerHelper( ::osl::Mutex & ) SAL_THROW( () ); 538 /** 539 Delete all containers. 540 */ 541 ~OMultiTypeInterfaceContainerHelper() SAL_THROW( () ); 542 543 /** 544 Return all id's under which at least one interface is added. 545 */ 546 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getContainedTypes() const SAL_THROW( () ); 547 548 /** 549 Return the container created under this key. 550 @return the container created under this key. If the container 551 was not created, null was returned. 552 */ 553 OInterfaceContainerHelper * SAL_CALL getContainer( const ::com::sun::star::uno::Type & rKey ) const SAL_THROW( () ); 554 555 /** Inserts an element into the container with the specified key. 556 The position is not specified, thus it is not specified in which order events are fired. 557 558 @attention 559 If you add the same interface more than once, then it will be added to the elements list 560 more than once and thus if you want to remove that interface from the list, you have to call 561 removeInterface() the same number of times. 562 In the latter case, you will also get events fired more than once (if the interface is a 563 listener interface). 564 565 @param rKey 566 the id of the container 567 @param r 568 interface to be added; it is allowed, to insert null or 569 the same interface more than once 570 @return 571 the new count of elements in the container 572 */ 573 sal_Int32 SAL_CALL addInterface( 574 const ::com::sun::star::uno::Type & rKey, 575 const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & r ) 576 SAL_THROW( () ); 577 578 /** Removes an element from the container with the specified key. 579 It uses interface equality to remove the interface. 580 581 @param rKey 582 the id of the container 583 @param rxIFace 584 interface to be removed 585 @return 586 the new count of elements in the container 587 */ 588 sal_Int32 SAL_CALL removeInterface( 589 const ::com::sun::star::uno::Type & rKey, 590 const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & rxIFace ) 591 SAL_THROW( () ); 592 593 /** 594 Call disposing on all object in the container that 595 support XEventListener. Than clear the container. 596 */ 597 void SAL_CALL disposeAndClear( const ::com::sun::star::lang::EventObject & rEvt ) SAL_THROW( () ); 598 /** 599 Remove all elements of all containers. Does not delete the container. 600 */ 601 void SAL_CALL clear() SAL_THROW( () ); 602 603 typedef ::com::sun::star::uno::Type keyType; 604 private: 605 void *m_pMap; 606 ::osl::Mutex & rMutex; 607 608 inline OMultiTypeInterfaceContainerHelper( const OMultiTypeInterfaceContainerHelper & ) SAL_THROW( () ); 609 inline OMultiTypeInterfaceContainerHelper & operator = ( const OMultiTypeInterfaceContainerHelper & ) SAL_THROW( () ); 610 }; 611 612 typedef OBroadcastHelperVar< OMultiTypeInterfaceContainerHelper , OMultiTypeInterfaceContainerHelper::keyType > OBroadcastHelper; 613 614 } 615 616 #endif 617 618