improvements to wxEventFunctor classes; use wxHAS_EVENT_BIND instead of wxEVENTS_COMPATIBILITY_2_8 (see #10653)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@60470 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2009-05-02 12:52:54 +00:00
parent 1ba0367603
commit 890d70ebea
17 changed files with 329 additions and 273 deletions

View File

@@ -27,7 +27,7 @@
#include "wx/thread.h"
#include "wx/tracker.h"
#if !wxEVENTS_COMPATIBILITY_2_8
#ifdef wxHAS_EVENT_BIND
#include "wx/meta/convertible.h"
#endif
@@ -101,7 +101,7 @@ extern WXDLLIMPEXP_BASE wxEventType wxNewEventType();
// New macros to create templatized event types:
#if wxEVENTS_COMPATIBILITY_2_8
#ifndef wxHAS_EVENT_BIND
// Define/Declare a wxEventType-based event type:
@@ -126,7 +126,8 @@ extern WXDLLIMPEXP_BASE wxEventType wxNewEventType();
#define wxDECLARE_EVENT( name, type ) \
wxDECLARE_EXPORTED_EVENT( wxEMPTY_PARAMETER_VALUE, name, type )
#else
#else // wxHAS_EVENT_BIND
// Define/Declare a templatized event type with the corresponding event as
// a nested typedef:
@@ -151,16 +152,15 @@ extern WXDLLIMPEXP_BASE wxEventType wxNewEventType();
#define wxDECLARE_EVENT( name, type ) \
wxDECLARE_EXPORTED_EVENT( wxEMPTY_PARAMETER_VALUE, name, type )
#endif
#endif // wxHAS_EVENT_BIND
// Try to cast the given event handler to the correct handler type:
#define wxEVENT_HANDLER_CAST( functype, func ) \
( wxObjectEventFunction )( wxEventFunction )wxStaticCastEvent( functype, &func )
// Template which associates the correct event object with the event type
#if !wxEVENTS_COMPATIBILITY_2_8
#ifdef wxHAS_EVENT_BIND
// The tag is a type associated to the event type (which is an integer itself,
// in spite of its name) value. It exists in order to be used as a template
@@ -184,7 +184,7 @@ private:
wxEventType m_type;
};
#endif // !wxEVENTS_COMPATIBILITY_2_8
#endif // wxHAS_EVENT_BIND
// These are needed for the functor definitions
typedef void (wxEvtHandler::*wxEventFunction)(wxEvent&);
@@ -199,6 +199,15 @@ typedef void (wxEvtHandler::*wxEventFunction)(wxEvent&);
typedef wxEventFunction wxObjectEventFunction;
// wxEventFunctorClassInfo is used as a unique identifier for wxEventFunctor-
// derived classes; it is more light weight than wxClassInfo and can be used in
// template classes
typedef void (*wxEventFunctorClassInfo)();
// this macro must be used in wxEventFunctor-derived classes
#define wxDEFINE_EVENT_FUNCTOR_CLASS_INFO( classInfoName ) \
static void classInfoName() {}
// The event functor which is stored in the static and dynamic event tables:
class WXDLLIMPEXP_BASE wxEventFunctor
{
@@ -209,54 +218,74 @@ public:
virtual void operator()(wxEvtHandler *, wxEvent&) = 0;
// this function tests whether this functor is matched, for the purpose of
// finding it in an event table in Disconnect(), by the given func
virtual bool Matches(const wxEventFunctor& func) const = 0;
// finding it in an event table in Unbind(), by the given functor:
virtual bool IsMatching(const wxEventFunctor& functor) const = 0;
// these functions are used for functors comparison in Matches()
virtual void *GetHandler() const { return GetEvtHandler(); }
virtual wxEventFunction GetMethod() const { return NULL; }
// Test whether the given class info is the same as from this functor. This
// allows us in IsMatching to safely downcast the given wxEventFunctor without
// the usage of dynamic_cast<>().
virtual bool IsSameClass(wxEventFunctorClassInfo classInfo) const = 0;
// this one is also used elsewhere in the code and should be overridden to
// return non-NULL if we are indeed associated with an wxEvtHandler
virtual wxEvtHandler *GetEvtHandler() const { return NULL; }
// If the functor holds an wxEvtHandler, then get access to it and track
// its lifetime with wxEventConnectionRef:
virtual wxEvtHandler *GetEvtHandler() const
{ return NULL; }
// This is only used to maintain backward compatibility in
// wxAppConsoleBase::CallEventHandler and ensures that an overwritten
// wxAppConsoleBase::HandleEvent is still called for functors which hold an
// wxEventFunction:
virtual wxEventFunction GetEvtMethod() const
{ return NULL; }
};
// A plain method functor: notice that it is used even with the new events as
// it is reused as a specialization of wxEventFunctorMethod for legacy untyped
// event types
// A plain method functor for the untyped legacy event types:
class WXDLLIMPEXP_BASE wxObjectEventFunctor : public wxEventFunctor
{
public:
wxObjectEventFunctor(wxObjectEventFunction method, wxEvtHandler *handler)
: m_handler( handler ), m_method( method )
{ }
virtual void operator()(wxEvtHandler *handler, wxEvent& event)
{
m_handler = handler;
m_method = method;
wxEvtHandler * const realHandler = m_handler ? m_handler : handler;
(realHandler->*m_method)(event);
}
virtual void operator()(wxEvtHandler *handler, wxEvent& event);
virtual bool Matches(const wxEventFunctor& func) const
virtual bool IsMatching(const wxEventFunctor& functor) const
{
void * const handler = func.GetHandler();
if ( handler && GetHandler() != handler )
if ( functor.IsSameClass( sm_classInfo ))
{
const wxObjectEventFunctor &other =
static_cast< const wxObjectEventFunctor & >( functor );
// FIXME-VC6: amazing but true: replacing "method == NULL" here
// with "!method" makes VC6 crash with an ICE in DLL build (only!)
return ( m_method == other.m_method || other.m_method == NULL ) &&
( m_handler == other.m_handler || other.m_handler == NULL );
}
else
return false;
const wxEventFunction method = GetMethod();
// FIXME-VC6: amazing but true: replacing "method == NULL" here with
// "!method" makes VC6 crash with an ICE in DLL build (only!)
return method == NULL || GetMethod() == method;
}
virtual wxEvtHandler *GetEvtHandler() const { return m_handler; }
virtual wxEventFunction GetMethod() const { return m_method; }
virtual bool IsSameClass( wxEventFunctorClassInfo otherClassInfo ) const
{ return sm_classInfo == otherClassInfo; }
virtual wxEvtHandler *GetEvtHandler() const
{ return m_handler; }
virtual wxEventFunction GetEvtMethod() const
{ return m_method; }
private:
wxEvtHandler *m_handler;
wxEventFunction m_method;
};
#if wxEVENTS_COMPATIBILITY_2_8
wxDEFINE_EVENT_FUNCTOR_CLASS_INFO( sm_classInfo );
};
// Create a functor for the legacy events: used by Connect()
inline wxObjectEventFunctor *
@@ -283,40 +312,7 @@ wxMakeEventFunctor(const wxEventType& WXUNUSED(evtType),
return wxObjectEventFunctor(method, handler);
}
#else // !wxEVENTS_COMPATIBILITY_2_8
// functor forwarding the event to anything callable (function, static method,
// generalized functor...)
template <typename EventTag, typename Functor>
class wxEventFunctorFunction : public wxEventFunctor
{
public:
typedef typename EventTag::EventClass EventArg;
wxEventFunctorFunction(Functor handler)
{
m_handler = handler;
}
virtual void operator()(wxEvtHandler *WXUNUSED(handler), wxEvent& event)
{
m_handler(static_cast<EventArg&>(event));
}
virtual bool Matches(const wxEventFunctor& WXUNUSED(func)) const
{
// we have no way to compare arbitrary functors so just consider them
// to be equal: this means that disconnecting a functor will always
// find the last functor connected which in turn implies that it's
// probably a bad idea to connect more than one functor if you plan to
// disconnect them but this limitation doesn't seem very important in
// practice
return true;
}
private:
Functor m_handler;
};
#ifdef wxHAS_EVENT_BIND
namespace wxPrivate
{
@@ -356,7 +352,7 @@ struct HandlerImpl<T, A, true>
{ return static_cast<T *>(p); }
static wxEvtHandler *ConvertToEvtHandler(T *p)
{ return p; }
static wxEventFunction ConvertToEvtFunction(void (T::*f)(A&))
static wxEventFunction ConvertToEvtMethod(void (T::*f)(A&))
{ return static_cast<wxEventFunction>(
reinterpret_cast<void (T::*)(wxEvent&)>(f)); }
};
@@ -371,7 +367,7 @@ struct HandlerImpl<T, A, false>
{ return NULL; }
static wxEvtHandler *ConvertToEvtHandler(T *)
{ return NULL; }
static wxEventFunction ConvertToEvtFunction(void (T::*)(A&))
static wxEventFunction ConvertToEvtMethod(void (T::*)(A&))
{ return NULL; }
};
@@ -406,6 +402,7 @@ public:
wxEventFunctorMethod(void (Class::*method)(EventArg&), EventHandler *handler)
: m_handler( handler ), m_method( method )
{
wxASSERT_MSG( handler || this->IsEvtHandler(),
"handlers defined in non-wxEvtHandler-derived classes "
@@ -415,9 +412,6 @@ public:
// you're trying to use is not compatible with (i.e. is not the same as
// or a base class of) the real event class used for this event type
CheckHandlerArgument(static_cast<EventClass *>(NULL));
m_handler = handler;
m_method = method;
}
virtual void operator()(wxEvtHandler *handler, wxEvent& event)
@@ -437,60 +431,179 @@ public:
(realHandler->*m_method)(static_cast<EventArg&>(event));
}
virtual bool Matches(const wxEventFunctor& func) const
virtual bool IsMatching(const wxEventFunctor& functor) const
{
void * const handler = func.GetHandler();
if ( handler && GetHandler() != handler )
if ( !functor.IsSameClass(sm_classInfo) )
return false;
const wxEventFunction method = GetMethod();
return !method || GetMethod() == method;
typedef wxEventFunctorMethod<EventTag, Class, EventArg, EventHandler>
ThisFunctor;
// the cast is valid because IsSameClass() returned true above
const ThisFunctor& other = static_cast<const ThisFunctor &>(functor);
return (m_method == other.m_method || other.m_method == NULL) &&
(m_handler == other.m_handler || other.m_handler == NULL);
}
virtual void *GetHandler() const
{
return m_handler;
}
virtual wxEventFunction GetMethod() const
{
return this->ConvertToEvtFunction(m_method);
}
virtual bool IsSameClass( wxEventFunctorClassInfo otherClassInfo ) const
{ return sm_classInfo == otherClassInfo; }
virtual wxEvtHandler *GetEvtHandler() const
{
return this->ConvertToEvtHandler(m_handler);
}
{ return this->ConvertToEvtHandler(m_handler); }
virtual wxEventFunction GetEvtMethod() const
{ return this->ConvertToEvtMethod(m_method); }
private:
EventHandler *m_handler;
void (Class::*m_method)(EventArg&);
wxDEFINE_EVENT_FUNCTOR_CLASS_INFO( sm_classInfo );
};
// functor forwarding the event to function (function, static method)
template <typename EventTag, typename EventArg>
class wxEventFunctorFunction : public wxEventFunctor
{
private:
static void CheckHandlerArgument(EventArg *) { }
public:
// the event class associated with the given event tag
typedef typename wxPrivate::EventClassOf<EventTag>::type EventClass;
wxEventFunctorFunction( void ( *handler )( EventArg & ))
: m_handler( handler )
{
// if you get an error here it means that the signature of the handler
// you're trying to use is not compatible with (i.e. is not the same as
// or a base class of) the real event class used for this event type
CheckHandlerArgument(static_cast<EventClass *>(NULL));
}
virtual void operator()(wxEvtHandler *WXUNUSED(handler), wxEvent& event)
{
// If you get an error here like "must use .* or ->* to call
// pointer-to-member function" then you probably tried to call
// Bind/Unbind with a method pointer but without a handler pointer or
// NULL as a handler e.g.:
// Unbind( wxEVT_XXX, &EventHandler::method );
// or
// Unbind( wxEVT_XXX, &EventHandler::method, NULL )
m_handler(static_cast<EventArg&>(event));
}
virtual bool IsMatching(const wxEventFunctor &functor) const
{
if ( !functor.IsSameClass(sm_classInfo) )
return false;
typedef wxEventFunctorFunction<EventTag, EventArg> ThisFunctor;
const ThisFunctor& other = static_cast<const ThisFunctor&>( functor );
return m_handler == other.m_handler;
}
virtual bool IsSameClass( wxEventFunctorClassInfo otherClassInfo ) const
{ return sm_classInfo == otherClassInfo; }
private:
void (*m_handler)(EventArg&);
wxDEFINE_EVENT_FUNCTOR_CLASS_INFO( sm_classInfo );
};
template <typename EventTag, typename Functor>
class wxEventFunctorFunctor : public wxEventFunctor
{
public:
typedef typename EventTag::EventClass EventArg;
wxEventFunctorFunctor(Functor& handler)
: m_handler(handler), m_handlerAddr(&handler)
{ }
virtual void operator()(wxEvtHandler *WXUNUSED(handler), wxEvent& event)
{
// If you get an error here like "must use '.*' or '->*' to call
// pointer-to-member function" then you probably tried to call
// Bind/Unbind with a method pointer but without a handler pointer or
// NULL as a handler e.g.:
// Unbind( wxEVT_XXX, &EventHandler::method );
// or
// Unbind( wxEVT_XXX, &EventHandler::method, NULL )
m_handler(static_cast<EventArg&>(event));
}
virtual bool IsMatching(const wxEventFunctor &functor) const
{
if ( !functor.IsSameClass(sm_classInfo) )
return false;
typedef wxEventFunctorFunctor<EventTag, Functor> FunctorThis;
const FunctorThis& other = static_cast<const FunctorThis&>(functor);
// The only reliable/portable way to compare two functors is by
// identity:
return m_handlerAddr == other.m_handlerAddr;
}
virtual bool IsSameClass( wxEventFunctorClassInfo otherClassInfo ) const
{ return sm_classInfo == otherClassInfo; }
private:
// Store a copy of the functor to prevent using/calling an already
// destroyed instance:
Functor m_handler;
// Use the address of the original functor for comparison in IsMatching:
const void *m_handlerAddr;
wxDEFINE_EVENT_FUNCTOR_CLASS_INFO( sm_classInfo );
};
// Create functors for the templatized events, either allocated on the heap for
// wxNewXXX() variants (this is needed in wxEvtHandler::Bind<>() to store them
// in dynamic event table) or just by returning them as temporary objects (this
// in dynamic event table) or just by returning them as a temporary objects (this
// is enough for Unbind<>() and we avoid unnecessary heap allocation like this).
// Create functors wrapping other functors (including functions):
template <typename EventTag, typename Functor>
inline wxEventFunctorFunction<EventTag, Functor> *
wxNewEventFunctor(const EventTag&, Functor func)
// Create functors wrapping functions:
template <typename EventTag, typename EventArg>
inline wxEventFunctorFunction<EventTag, EventArg> *
wxNewEventFunctor(const EventTag&, void (*func)(EventArg &))
{
return new wxEventFunctorFunction<EventTag, Functor>(func);
return new wxEventFunctorFunction<EventTag, EventArg>(func);
}
template <typename EventTag, typename EventArg>
inline wxEventFunctorFunction<EventTag, EventArg>
wxMakeEventFunctor(const EventTag&, void (*func)(EventArg &))
{
return wxEventFunctorFunction<EventTag, EventArg>(func);
}
// Create functors wrapping other functors:
template <typename EventTag, typename Functor>
inline wxEventFunctorFunctor<EventTag, Functor> *
wxNewEventFunctor(const EventTag&, Functor &func)
{
return new wxEventFunctorFunctor<EventTag, Functor>(func);
}
template <typename EventTag, typename Functor>
inline wxEventFunctorFunction<EventTag, Functor>
wxMakeEventFunctor(const EventTag&, Functor func)
inline wxEventFunctorFunctor<EventTag, Functor>
wxMakeEventFunctor(const EventTag&, Functor &func)
{
return wxEventFunctorFunction<EventTag, Functor>(func);
return wxEventFunctorFunctor<EventTag, Functor>(func);
}
// Create functors for methods:
// Create functors wrapping methods:
template
<typename EventTag, typename Class, typename EventArg, typename EventHandler>
inline wxEventFunctorMethod<EventTag, Class, EventArg, EventHandler> *
@@ -524,7 +637,7 @@ wxNewEventTableFunctor(const EventTag&, void (Class::*method)(EventArg&))
method, NULL);
}
#endif // !wxEVENTS_COMPATIBILITY_2_8
#endif // wxHAS_EVENT_BIND
// many, but not all, standard event types
@@ -2871,7 +2984,7 @@ public:
wxObject *userData = NULL,
wxEvtHandler *eventSink = NULL)
{
DoConnect(winid, lastId, eventType,
DoBind(winid, lastId, eventType,
wxNewEventFunctor(eventType, func, eventSink),
userData);
}
@@ -2898,7 +3011,7 @@ public:
wxObject *userData = NULL,
wxEvtHandler *eventSink = NULL)
{
return DoDisconnect(winid, lastId, eventType,
return DoUnbind(winid, lastId, eventType,
wxMakeEventFunctor(eventType, func, eventSink),
userData );
}
@@ -2916,16 +3029,42 @@ public:
wxEvtHandler *eventSink = NULL)
{ return Disconnect(wxID_ANY, eventType, func, userData, eventSink); }
#if !wxEVENTS_COMPATIBILITY_2_8
// Bind arbitrary functor (including just a function) to an event:
template <typename EventTag, typename Functor>
#ifdef wxHAS_EVENT_BIND
// Bind functions to an event:
template <typename EventTag, typename EventArg>
void Bind(const EventTag& eventType,
Functor functor,
void (*function)(EventArg &),
int winid = wxID_ANY,
int lastId = wxID_ANY,
wxObject *userData = NULL)
{
DoConnect(winid, lastId, eventType,
DoBind(winid, lastId, eventType,
wxNewEventFunctor(eventType, function),
userData);
}
template <typename EventTag, typename EventArg>
bool Unbind(const EventTag& eventType,
void (*function)(EventArg &),
int winid = wxID_ANY,
int lastId = wxID_ANY,
wxObject *userData = NULL)
{
return DoUnbind(winid, lastId, eventType,
wxMakeEventFunctor(eventType, function),
userData);
}
// Bind functors to an event:
template <typename EventTag, typename Functor>
void Bind(const EventTag& eventType,
Functor &functor,
int winid = wxID_ANY,
int lastId = wxID_ANY,
wxObject *userData = NULL)
{
DoBind(winid, lastId, eventType,
wxNewEventFunctor(eventType, functor),
userData);
}
@@ -2933,12 +3072,12 @@ public:
template <typename EventTag, typename Functor>
bool Unbind(const EventTag& eventType,
Functor functor,
Functor &functor,
int winid = wxID_ANY,
int lastId = wxID_ANY,
wxObject *userData = NULL)
{
return DoDisconnect(winid, lastId, eventType,
return DoUnbind(winid, lastId, eventType,
wxMakeEventFunctor(eventType, functor),
userData);
}
@@ -2955,7 +3094,7 @@ public:
int lastId = wxID_ANY,
wxObject *userData = NULL)
{
DoConnect(winid, lastId, eventType,
DoBind(winid, lastId, eventType,
wxNewEventFunctor(eventType, method, handler),
userData);
}
@@ -2968,11 +3107,11 @@ public:
int lastId = wxID_ANY,
wxObject *userData = NULL )
{
return DoDisconnect(winid, lastId, eventType,
return DoUnbind(winid, lastId, eventType,
wxMakeEventFunctor(eventType, method, handler),
userData);
}
#endif // !wxEVENTS_COMPATIBILITY_2_8
#endif // wxHAS_EVENT_BIND
wxList* GetDynamicEventTable() const { return m_dynamicEvents ; }
@@ -3014,13 +3153,13 @@ public:
private:
void DoConnect(int winid,
void DoBind(int winid,
int lastId,
wxEventType eventType,
wxEventFunctor *func,
wxObject* userData = NULL);
bool DoDisconnect(int winid,
bool DoUnbind(int winid,
int lastId,
wxEventType eventType,
const wxEventFunctor& func,
@@ -3155,13 +3294,6 @@ private:
wxDECLARE_NO_ASSIGN_CLASS(wxEventConnectionRef);
};
inline void wxObjectEventFunctor::operator()(wxEvtHandler *handler, wxEvent& event)
{
wxEvtHandler * const realHandler = m_handler ? m_handler : handler;
(realHandler->*m_method)(event);
}
// Post a message to the given event handler which will be processed during the
// next event loop iteration.
//
@@ -3771,17 +3903,17 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
// (and not in a private header) because the base class must be visible from
// other public headers, please do NOT use this in your code, it will be
// removed from future wx versions without warning.
#if wxEVENTS_COMPATIBILITY_2_8
#ifndef wxHAS_EVENT_BIND
#define wxBIND_OR_CONNECT_HACK_BASE_CLASS public wxEvtHandler,
#define wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLASS : public wxEvtHandler
#define wxBIND_OR_CONNECT_HACK(w, evt, handler, func, obj) \
win->Connect(evt, handler(func), NULL, obj)
#else // wxEVENTS_COMPATIBILITY_2_8
#else // wxHAS_EVENT_BIND
#define wxBIND_OR_CONNECT_HACK_BASE_CLASS
#define wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLASS
#define wxBIND_OR_CONNECT_HACK(w, evt, handler, func, obj) \
win->Bind(evt, &func, obj)
#endif // wxEVENTS_COMPATIBILITY_2_8/!wxEVENTS_COMPATIBILITY_2_8
#endif // wxHAS_EVENT_BIND
#if wxUSE_GUI