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