blob: 26c902293c42bb8287332f9f0f79d9ae91cfd433 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#ifndef COMPHELPER_INC_COMPHELPER_LISTENERNOTIFICATION_HXX
#define COMPHELPER_INC_COMPHELPER_LISTENERNOTIFICATION_HXX
#include <cppuhelper/interfacecontainer.hxx>
/** === begin UNO includes === **/
#include <com/sun/star/lang/XEventListener.hpp>
/** === end UNO includes === **/
#include "comphelper/comphelperdllapi.h"
#include <memory>
//........................................................................
namespace comphelper
{
//........................................................................
//====================================================================
//= OListenerContainer
//====================================================================
/** abstract base class which manages a listener container, including
THB's listener notification pattern which cares for removing listeners
which throw an DisposedException upon notification
Using this class is pretty easy:
<ul>
<li>Derive from it, and overwrite implNotify.</li>
<li>Use <member>impl_addListener</member> and <member>impl_removeListener</member> in your
XFoo::addFooListener and XFoo::removeFooListener methods.</li>
<li>call <member>impl_notify</member> whenever the event you want to notify happened</li>
<li>call <member>disposing</member> upon the disposal of your broadcaster.</li>
</ul>
See <type>OListenerContainerBase</type> for an implementation which even saves
you some more work, by doing the casts for you.
@see http://www.openoffice.org/servlets/ReadMsg?list=interface-announce&msgId=494345
@see OListenerContainerBase
*/
class COMPHELPER_DLLPUBLIC OListenerContainer
{
private:
::cppu::OInterfaceContainerHelper m_aListeners;
public:
/** sends a XEventObject::disposing notification to all listeners, and clears the
listener container
You'll usually call this from within your own dispose/disposing method
*/
void disposing( const ::com::sun::star::lang::EventObject& _rEventSource );
/** clears the container without calling <member scope="com::sun::star::lang">XEventListener::disposing</member>
at the listeners
*/
void clear();
/** determines whether the listener container is currently empty
*/
inline bool
empty() const SAL_THROW(());
/** determines the number of elements in the container
*/
inline size_t
size() const SAL_THROW(());
/** creates an iterator for looping through all registered listeners
*/
inline ::std::auto_ptr< ::cppu::OInterfaceIteratorHelper >
createIterator();
protected:
OListenerContainer( ::osl::Mutex& _rMutex );
virtual ~OListenerContainer();
void impl_addListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener );
void impl_removeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener );
/** notifies all listeners of the given event, using THB's notification pattern
internally, this method will call <member>implNotify</member> for every listener
@return
<TRUE/> if all listeners have been notified, <FALSE/> else. The latter can happen
if <member>implNotify</member> cancelles the notification loop.
@see implNotify
*/
bool impl_notify( const ::com::sun::star::lang::EventObject& _rEvent ) SAL_THROW(( ::com::sun::star::uno::Exception ));
protected:
/** call a single listener
@pure
@throws ::com::sun::star::uno::Exception
if the listener throws an exception during notification. Please don't catch
any listener exceptions in your implementation of this method, simply let them
pass to the caller.
@param _rxListener
specifies the listener to call. Is guaranteed to not be <NULL/>
@param _rEvent
the event to broadcast. This is the same as passed to <member>notify</member>, so if
your base class knows the type passed into <member>notify</member>, it can safely assume
that <arg>_rEvent</arg> is also of this type.
@return
<TRUE/> if the remaining listeners should be called, <FALSE/> if the notification
loop should be cancelled
@see notify
*/
virtual bool implNotify(
const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener,
const ::com::sun::star::lang::EventObject& _rEvent
) SAL_THROW( ( ::com::sun::star::uno::Exception ) ) = 0;
};
//====================================================================
inline bool OListenerContainer::empty() const SAL_THROW(())
{
return ( m_aListeners.getLength() == 0 );
}
inline size_t OListenerContainer::size() const SAL_THROW(())
{
return m_aListeners.getLength();
}
inline ::std::auto_ptr< ::cppu::OInterfaceIteratorHelper > OListenerContainer::createIterator()
{
::std::auto_ptr< ::cppu::OInterfaceIteratorHelper > pIterator( new ::cppu::OInterfaceIteratorHelper( m_aListeners ) );
return pIterator;
}
//====================================================================
//= OSimpleListenerContainer
//====================================================================
/** helper class for simple notification of the form LISTENER::METHOD( EVENT )
This class is not threadsafe!
@param LISTENER
the listener class to call, e.g. <type scope="com::sun::star::lang">XEventListener</type>
@param EVENT
the event type to notify, e.g. <type scope="com::sun::star::lang">EventObject</type>
*/
template< class LISTENER, class EVENT >
class OSimpleListenerContainer : protected OListenerContainer
{
public:
typedef LISTENER ListenerClass;
typedef EVENT EventClass;
typedef void ( SAL_CALL LISTENER::*NotificationMethod )( const EventClass& );
private:
NotificationMethod m_pNotificationMethod;
public:
OSimpleListenerContainer( ::osl::Mutex& _rMutex )
:OListenerContainer( _rMutex )
,m_pNotificationMethod( NULL )
{
}
inline void addListener( const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener )
{
OListenerContainer::impl_addListener( _rxListener.get() );
}
inline void removeListener( const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener )
{
OListenerContainer::impl_removeListener( _rxListener.get() );
}
// publish some otherwise hidden base functionality
using OListenerContainer::disposing;
using OListenerContainer::clear;
using OListenerContainer::empty;
using OListenerContainer::size;
using OListenerContainer::createIterator;
/// typed notification
inline bool notify( const EventClass& _rEvent, NotificationMethod _pNotify ) SAL_THROW(( ::com::sun::star::uno::Exception ));
protected:
inline virtual bool implNotify(
const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener,
const ::com::sun::star::lang::EventObject& _rEvent
) SAL_THROW( ( ::com::sun::star::uno::Exception ) );
};
//--------------------------------------------------------------------
template< class LISTENER, class EVENT >
inline bool OSimpleListenerContainer< LISTENER, EVENT >::notify( const EventClass& _rEvent, NotificationMethod _pNotify ) SAL_THROW(( ::com::sun::star::uno::Exception ))
{
m_pNotificationMethod = _pNotify;
bool bRet = OListenerContainer::impl_notify( _rEvent );
m_pNotificationMethod = NULL;
return bRet;
}
//--------------------------------------------------------------------
template< class LISTENER, class EVENT >
inline bool OSimpleListenerContainer< LISTENER, EVENT >::implNotify(
const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener,
const ::com::sun::star::lang::EventObject& _rEvent ) SAL_THROW( ( ::com::sun::star::uno::Exception ) )
{
const EventClass& rTypedEvent( static_cast< const EventClass& >( _rEvent ) );
ListenerClass* pTypedListener( static_cast< ListenerClass* >( _rxListener.get() ) );
(pTypedListener->*m_pNotificationMethod)( rTypedEvent );
return true;
}
//====================================================================
//= OListenerContainerBase
//====================================================================
/** is a specialization of OListenerContainer which saves you some additional type casts,
by making the required listener and event types template arguments.
*/
template< class LISTENER, class EVENT >
class OListenerContainerBase : public OListenerContainer
{
public:
typedef LISTENER ListenerClass;
typedef EVENT EventClass;
public:
inline OListenerContainerBase( ::osl::Mutex& _rMutex ) : OListenerContainer( _rMutex )
{
}
inline void addTypedListener( const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener )
{
OListenerContainer::impl_addListener( _rxListener.get() );
}
inline void removeTypedListener( const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener )
{
OListenerContainer::impl_removeListener( _rxListener.get() );
}
inline bool notify( const EventClass& _rEvent )
{
return OListenerContainer::impl_notify( _rEvent );
}
using OListenerContainer::impl_notify;
protected:
inline virtual bool implNotify(
const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener,
const ::com::sun::star::lang::EventObject& _rEvent
) SAL_THROW( ( ::com::sun::star::uno::Exception ) );
virtual bool implTypedNotify(
const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener,
const EventClass& _rEvent
) SAL_THROW( ( ::com::sun::star::uno::Exception ) ) = 0;
};
template< class LISTENER, class EVENT >
inline bool OListenerContainerBase< LISTENER, EVENT >::implNotify(
const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener,
const ::com::sun::star::lang::EventObject& _rEvent ) SAL_THROW( ( ::com::sun::star::uno::Exception ) )
{
return implTypedNotify(
::com::sun::star::uno::Reference< ListenerClass >( static_cast< ListenerClass* >( _rxListener.get() ) ),
static_cast< const EventClass& >( _rEvent )
);
}
//........................................................................
} // namespace comphelper
//........................................................................
#endif // COMPHELPER_INC_COMPHELPER_LISTENERNOTIFICATION_HXX