1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: listenercontainer.hxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #ifndef CONFIGMGR_API_LISTENERCONTAINER_HXX_
32 #define CONFIGMGR_API_LISTENERCONTAINER_HXX_
34 #include <com/sun/star/lang/XEventListener.hpp>
35 #include <com/sun/star/lang/DisposedException.hpp>
36 #include <cppuhelper/interfacecontainer.hxx>
37 #include "datalock.hxx"
38 #include "utility.hxx"
40 #include <osl/diagnose.h>
46 /////////////////////////////////////////////////////////////////////////////////////////////
48 namespace css
= ::com::sun::star
;
49 namespace uno
= css::uno
;
50 namespace lang
= css::lang
;
51 //-----------------------------------------------------------------------------
52 template <class Listener
>
53 class ListenerContainerIterator
57 * Create an iterator over the elements of the container. The iterator
58 * copies the elements of the conatainer. A change to the container does not
59 * affect the iterator.<BR>
60 * Remark: The copy is on demand. The iterator copy the elements only if the container
61 * change the contens. It is not allowed to destroy the container if a iterator exist.
63 * @param rCont the container of the elements.
65 ListenerContainerIterator( cppu::OInterfaceContainerHelper
& rCont
)
71 * Release the connection to the container.
73 ~ListenerContainerIterator() {}
75 /** Return true, if there are more elements in the iterator. */
76 sal_Bool
hasMoreElements() const { return m_xNext
.is() != 0; }
78 /** Return the next element of the iterator. Call this method if
79 * hasMoreElements return false, is an error.
81 uno::Reference
<Listener
> next();
86 cppu::OInterfaceIteratorHelper m_aIter
;
87 uno::Reference
<Listener
> m_xNext
;
89 //-----------------------------------------------------------------------------
92 lang::EventObject aEvent
;
93 std::vector
< uno::Reference
< lang::XEventListener
> > aListeners
;
96 DisposeNotifier(uno::Reference
<uno::XInterface
> const& aInterface
) : aEvent(aInterface
) {}
98 void appendAndClearContainer(cppu::OInterfaceContainerHelper
* pContainer
);
101 //-----------------------------------------------------------------------------
102 struct BasicContainerInfo
104 uno::XInterface
* pInterface
;
105 cppu::OMultiTypeInterfaceContainerHelper
* pContainer
;
106 BasicContainerInfo() : pInterface(0), pContainer(0) {}
109 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
110 class SpecialListenerContainer
114 * Create a container of interface containers.
116 SpecialListenerContainer(std::vector
<BasicContainerInfo
>::size_type nCount
, KeyToIndex_ aMapper
)
117 : m_aSpecialHelper(UnoApiLock::getLock())
118 , m_aContainers(nCount
)
120 , m_bDisposeLock(false)
123 ~SpecialListenerContainer()
125 OSL_ENSURE(isDisposed(), "ERROR: Object was not disposed properly");
129 * check whether this is disposed or still alive
131 * an interface on the object on which's behalf the operation was started
133 * if the object is being disposed
134 * @throw com::sun::star::lang::DisposedException
135 * if the object was disposed completely
137 bool checkAlive(uno::XInterface
* pObject
= 0) volatile const throw(lang::DisposedException
);
139 /// return whether the object is completely alive
140 bool isAlive() volatile const throw();
141 /// return whether the object is currently being disposed
142 bool isDisposing()volatile const throw();
143 /// return whether the object is completely disposed
144 bool isDisposed()volatile const throw();
146 /// return whether the object is present in this container
147 bool isAvailable(std::vector
<BasicContainerInfo
>::size_type nIndex
) const throw()
149 return nIndex
< m_aContainers
.size() && m_aContainers
[nIndex
].pInterface
;
152 std::vector
<BasicContainerInfo
>::size_type
getSize() const
154 return m_aContainers
.size();
157 /// return the interface associated with an index
158 void setObjectAt(std::vector
<BasicContainerInfo
>::size_type nIndex
, uno::XInterface
* pInterface
)
160 OSL_ENSURE( !isDisposed(), "object is disposed" );
164 OSL_ENSURE( nIndex
< m_aContainers
.size(), " Invalid Index into Notifier");
165 OSL_ENSURE( pInterface
, "Invalid NULL Interface passed into Notifier");
167 if ( nIndex
< m_aContainers
.size() && pInterface
!= NULL
)
169 OSL_ENSURE( m_aContainers
[nIndex
].pInterface
== NULL
, "Interface already set");
170 if (m_aContainers
[nIndex
].pInterface
== NULL
)
171 m_aContainers
[nIndex
].pInterface
= pInterface
;
177 /// return the interface associated with an index
178 uno::Reference
<uno::XInterface
> getObjectAt(std::vector
<BasicContainerInfo
>::size_type nIndex
) const
180 uno::Reference
<uno::XInterface
> xRet( nIndex
< m_aContainers
.size() ? m_aContainers
[nIndex
].pInterface
: 0 );
184 /// return the interface associated with an index
185 uno::Reference
<uno::XInterface
> getObjectForKey(Key_
const& aKey
) const
187 std::vector
<BasicContainerInfo
>::size_type nIndex
= m_aMapper
.findIndexForKey(aKey
);
188 uno::Reference
<uno::XInterface
> xRet( nIndex
< m_aContainers
.size() ? m_aContainers
[nIndex
].pInterface
: 0 );
193 * Call disposing on all object in all the container for anIndex
194 * and in the containers for the associated indices
195 * support XEventListener. Then clear the container.
197 bool disposeOne( std::vector
<BasicContainerInfo
>::size_type anIndex
) throw();
200 * Start disposing this object
202 * if disposing has been started
204 * if disposing had already been started before
206 bool beginDisposing() throw();
208 * Continue disposing this object
209 * <p> Call disposing on all object in all the containers that
210 * support XEventListener. Then clear the container.
213 * if disposing has been started
215 * if disposing had already been started before
217 void notifyDisposing() throw();
219 /// mark the end of the dispose processing
220 void endDisposing() throw();
224 * Return the specuial container created under this key.
225 * @return the container created under this key. If the container
226 * was not created, null was returned.
228 cppu::OInterfaceContainerHelper
* getSpecialContainer( const Key_
& aKey
) const
229 { return m_aSpecialHelper
.aLC
.getContainer(aKey
); }
232 * Return the containerhelper created under this index.
233 * @return the container helper created under this key. If the container helper
234 * was not created, null was returned.
236 cppu::OMultiTypeInterfaceContainerHelper
* getContainerHelper( std::vector
<BasicContainerInfo
>::size_type nIndex
) const
238 return ((nIndex
< m_aContainers
.size()) ? m_aContainers
[nIndex
].pContainer
: 0 );
241 * Return the container for the given type created under this index.
242 * @return the container created under this key. If the container
243 * was not created, null was returned.
245 cppu::OInterfaceContainerHelper
* getContainer( std::vector
<BasicContainerInfo
>::size_type nIndex
, const uno::Type
& aType
) const
247 cppu::OMultiTypeInterfaceContainerHelper
* pContainer
= (nIndex
< m_aContainers
.size()) ? m_aContainers
[nIndex
].pContainer
: 0 ;
249 return pContainer
? pContainer
->getContainer(aType
) : 0;
253 * Insert an element in the container specified with the index and type. The position is not specified.
254 * The interface at the given index must be set already.
255 * @param aKey the id of the container.
256 * @param xListener the added interface. It is allowed to insert null or
257 * the same pointer more than once.
258 * @return the new count of elements in the container (or 0 if the object is ready being disposed).
260 sal_Int32
addListener( std::vector
<BasicContainerInfo
>::size_type nIndex
, const uno::Type
& aType
, uno::Reference
< lang::XEventListener
> const& xListener
) throw();
263 * Remove an element from the container specified with the index and type.
264 * It uses the equal definition of uno objects to remove the interfaces.
265 * @param aKey the id of the container.
266 * @param xListener the removed interface.
267 * @return the new count of elements in the container (or 0 if the object is ready being disposed).
269 sal_Int32
removeListener( std::vector
<BasicContainerInfo
>::size_type nIndex
, const uno::Type
& aType
, uno::Reference
< lang::XEventListener
> const& xListener
) throw();
273 * Insert an element in the special container specified with the key. The position is not specified.
274 * The interface at the given index must be set already.
275 * @param aKey the id of the container.
276 * @param xListener the added interface. It is allowed to insert null or
277 * the same pointer more than once.
278 * @return the new count of elements in the container (or 0 if the object is ready being disposed).
280 sal_Int32
addSpecialListener( const Key_
& aKey
, uno::Reference
< lang::XEventListener
> const& xListener
) throw();
283 * Remove an element from the container specified with the key.
284 * It uses the equal definition of uno objects to remove the interfaces.
285 * @param aKey the id of the container.
286 * @param xListener the removed interface.
287 * @return the new count of elements in the container (or 0 if the object is ready being disposed).
289 sal_Int32
removeSpecialListener( const Key_
& aKey
, uno::Reference
< lang::XEventListener
> const& xListener
) throw();
292 void implFillDisposer(DisposeNotifier
& aNotifier
, std::vector
<BasicContainerInfo
>::size_type nIndex
);
294 cppu::OBroadcastHelperVar
< cppu::OMultiTypeInterfaceContainerHelperVar
< Key_
,KeyHash_
,KeyEq_
>, Key_
> m_aSpecialHelper
;
295 std::vector
<BasicContainerInfo
> m_aContainers
;
296 KeyToIndex_ m_aMapper
;
299 //-----------------------------------------------------------------------------
301 /////////////////////////////////////////////////////////////////////////////////////////////
302 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
303 bool SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::checkAlive(uno::XInterface
* pObject
) volatile const throw(lang::DisposedException
)
305 bool bAlive
= !m_aSpecialHelper
.bInDispose
;
306 if (m_aSpecialHelper
.bDisposed
)
308 throw lang::DisposedException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("The object has already been disposed")),pObject
);
312 //-----------------------------------------------------------------------------
313 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
315 bool SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::isAlive() volatile const throw()
317 return !m_aSpecialHelper
.bInDispose
&& !m_aSpecialHelper
.bDisposed
;
319 //-----------------------------------------------------------------------------
320 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
322 bool SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::isDisposing() volatile const throw()
324 return !!m_aSpecialHelper
.bInDispose
;
326 //-----------------------------------------------------------------------------
327 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
329 bool SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::isDisposed() volatile const throw()
331 return !!m_aSpecialHelper
.bDisposed
;
333 //-----------------------------------------------------------------------------
334 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
335 bool SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::disposeOne(std::vector
<BasicContainerInfo
>::size_type nIndex
) throw()
337 // OSL_ENSURE(!isDisposed(),"Object is already disposed in toto");
340 if (nIndex
< m_aContainers
.size())
342 if (uno::XInterface
* pObject
= m_aContainers
[nIndex
].pInterface
)
344 DisposeNotifier
aNotifier(pObject
);
346 implFillDisposer(aNotifier
, nIndex
);
347 m_aContainers
[nIndex
].pInterface
= 0;
348 delete m_aContainers
[nIndex
].pContainer
;
358 //-----------------------------------------------------------------------------
359 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
360 bool SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::beginDisposing() throw()
364 m_aSpecialHelper
.bInDispose
= sal_True
;
365 m_bDisposeLock
= true;
371 //-----------------------------------------------------------------------------
372 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
373 void SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::notifyDisposing() throw()
375 OSL_ENSURE(isDisposing(),"Disposing isn't in progress on this object");
376 OSL_ENSURE(m_bDisposeLock
,"Duplicate call for dispose notification or disposing is not taking place");
380 OSL_ASSERT(m_aSpecialHelper
.bInDispose
);
382 lang::EventObject aBaseEvt
;
383 std::vector
<DisposeNotifier
> aNotifiers
;
385 if (std::vector
<BasicContainerInfo
>::size_type size
= m_aContainers
.size())
387 aNotifiers
.reserve(m_aContainers
.size());
389 aBaseEvt
.Source
= m_aContainers
[0].pInterface
;
390 for(std::vector
<BasicContainerInfo
>::size_type ix
= 0; ix
< size
; ++ix
)
392 if (m_aContainers
[ix
].pInterface
)
394 aNotifiers
.push_back(DisposeNotifier(m_aContainers
[ix
].pInterface
));
395 implFillDisposer(aNotifiers
.back(), ix
);
396 m_aContainers
[ix
].pInterface
= 0;
397 delete m_aContainers
[ix
].pContainer
;
402 m_bDisposeLock
= false;
404 for(std::vector
<BasicContainerInfo
>::size_type jx
= 0, count
= aNotifiers
.size(); jx
< count
; ++jx
)
406 aNotifiers
[jx
].notify();
408 // in case we missed something
409 m_aSpecialHelper
.aLC
.disposeAndClear( aBaseEvt
);
412 //-----------------------------------------------------------------------------
413 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
414 void SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::endDisposing() throw()
416 OSL_ENSURE(isDisposing(),"Disposing isn't in progress on this object");
420 OSL_ENSURE(!m_bDisposeLock
,"Did you forget to notify ?");
422 m_aSpecialHelper
.bDisposed
= sal_True
;
423 m_aSpecialHelper
.bInDispose
= sal_False
;
427 m_bDisposeLock
= false;
431 //-----------------------------------------------------------------------------
432 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
433 sal_Int32 SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::addListener( std::vector
<BasicContainerInfo
>::size_type nIndex
, const uno::Type
& aType
, const uno::Reference
< lang::XEventListener
> & xListener
) throw()
435 if ( nIndex
< m_aContainers
.size() && m_aContainers
[nIndex
].pInterface
)
439 if (m_aContainers
[nIndex
].pContainer
== 0)
440 m_aContainers
[nIndex
].pContainer
= new cppu::OMultiTypeInterfaceContainerHelper(UnoApiLock::getLock());
442 return m_aContainers
[nIndex
].pContainer
->addInterface(aType
,xListener
);
445 else if (xListener
.is())
447 lang::EventObject
aEvent(m_aContainers
[nIndex
].pInterface
);
448 try { xListener
->disposing(aEvent
); } catch (uno::Exception
& ) {}
453 OSL_ENSURE(false, "Invalid index or interface not set");
457 //-----------------------------------------------------------------------------
458 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
459 sal_Int32 SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::addSpecialListener( const Key_
& aKey
, const uno::Reference
< lang::XEventListener
> & xListener
) throw()
461 std::vector
<BasicContainerInfo
>::size_type nIndex
= m_aMapper
.findIndexForKey(aKey
);
462 if ( nIndex
< m_aContainers
.size() && m_aContainers
[nIndex
].pInterface
)
466 return m_aSpecialHelper
.aLC
.addInterface(aKey
,xListener
);
469 else if (xListener
.is())
471 lang::EventObject
aEvent(m_aContainers
[nIndex
].pInterface
);
472 try { xListener
->disposing(aEvent
); } catch (uno::Exception
& ) {}
476 OSL_ENSURE(false, "Invalid index or interface not set");
480 //-----------------------------------------------------------------------------
482 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
483 sal_Int32 SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::removeListener( std::vector
<BasicContainerInfo
>::size_type nIndex
, const uno::Type
& aType
, const uno::Reference
< lang::XEventListener
> & xListener
) throw()
485 OSL_ENSURE( !isDisposed(), "object is disposed" );
489 if ( nIndex
< m_aContainers
.size() && m_aContainers
[nIndex
].pContainer
)
491 return m_aContainers
[nIndex
].pContainer
->removeInterface(aType
,xListener
);
496 //-----------------------------------------------------------------------------
498 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
499 sal_Int32 SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::removeSpecialListener( const Key_
& aKey
, const uno::Reference
< lang::XEventListener
> & xListener
) throw()
501 OSL_ENSURE( !isDisposed(), "object is disposed" );
504 return m_aSpecialHelper
.aLC
.removeInterface(aKey
, xListener
);
509 //-----------------------------------------------------------------------------
510 // relation function. Uses KeyToIndex
511 /* template <class Key_, class KeyHash_, class KeyEq_, class KeyToIndex_>
512 SpecialListenerContainer<Key_,KeyHash_,KeyEq_, KeyToIndex_>::Index
513 SpecialListenerContainer<Key_,KeyHash_,KeyEq_, KeyToIndex_>::findIndexForKey(Key const& aKey)
515 m_aMapper.findIndexForKey(aKey);
517 //-----------------------------------------------------------------------------
518 // relation function. Uses KeyToIndex
519 template <class Key_, class KeyHash_, class KeyEq_, class KeyToIndex_>
520 bool SpecialListenerContainer<Key_,KeyHash_,KeyEq_, KeyToIndex_>::findKeysForIndex(std::vector<BasicContainerInfo>::size_type nIndex, std::vector<Key_> & aKeys)
523 m_aMapper.findKeysForIndex(nIndex,aKeys);
524 return !aKeys.empty();
526 *///-----------------------------------------------------------------------------
527 // relation function. Uses KeyToIndex
528 template <class Key_
, class KeyHash_
, class KeyEq_
, class KeyToIndex_
>
529 void SpecialListenerContainer
<Key_
,KeyHash_
,KeyEq_
, KeyToIndex_
>::implFillDisposer(DisposeNotifier
& aNotifier
, std::vector
<BasicContainerInfo
>::size_type nIndex
)
531 if (cppu::OMultiTypeInterfaceContainerHelper
* pMultiContainer
= m_aContainers
[nIndex
].pContainer
)
533 uno::Sequence
< uno::Type
> aTypes(pMultiContainer
->getContainedTypes());
534 for (sal_Int32 ix
= 0; ix
< aTypes
.getLength(); ++ix
)
536 cppu::OInterfaceContainerHelper
* pContainer
= pMultiContainer
->getContainer(aTypes
[ix
]);
537 OSL_ENSURE(pContainer
,"No container, but the type ?");
539 aNotifier
.appendAndClearContainer(pContainer
);
542 std::vector
<Key_
> aKeys
;
543 if (m_aMapper
.findKeysForIndex(nIndex
,aKeys
))
545 for(typename
std::vector
<Key_
>::iterator it
= aKeys
.begin(); it
!= aKeys
.end(); ++it
)
547 if (cppu::OInterfaceContainerHelper
* pContainer
= m_aSpecialHelper
.aLC
.getContainer(*it
))
549 aNotifier
.appendAndClearContainer(pContainer
);
554 //-----------------------------------------------------------------------------
556 /////////////////////////////////////////////////////////////////////////////////////////////
558 template <class Listener
>
560 void ListenerContainerIterator
<Listener
>::advance()
562 while (!m_xNext
.is() && m_aIter
.hasMoreElements())
564 m_xNext
= m_xNext
.query( m_aIter
.next() );
567 //-----------------------------------------------------------------------------
569 template <class Listener
>
570 uno::Reference
<Listener
> ListenerContainerIterator
<Listener
>::next()
572 uno::Reference
<Listener
> xRet(m_xNext
);
577 //-----------------------------------------------------------------------------
579 /////////////////////////////////////////////////////////////////////////////////////////////
582 #endif // CONFIGMGR_API_LISTENERCONTAINER_HXX_