From: Vadim Zeitlin Date: Mon, 2 Feb 2009 20:38:56 +0000 (+0000) Subject: Changes to template Connect() to make it compile with MSVC7 and possible other X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/f3ff831f3be88834579fc9a0ce17f24745650faf?ds=sidebyside Changes to template Connect() to make it compile with MSVC7 and possible other not quite up-to-date compilers, to reduce repetitions and to allow using methods of non-wxEvtHandler-derived classes as event callbacks: 1. Don't rely on compiler ability to deduce template parameter from the type of a parameter of a function used as another template parameter, at least MSVC7 can't do this and it's probably not the only one. 2. Do rely on compiler support for partial specialization to make wxEventFunctorMethod compile for non-wxEvtHandler-derived handlers while still keeping the old functionality for the wxEvtHandler-derived ones. 3. Don't make any difference between functions and functors, both are callable objects so use them as such, this allows to fold code for both cases. 4. Avoid the use of dynamic_cast<>. 5. Several naming changes: a) wxTypedEventType -> wxEventTypeTag (because this is what it is) b) Subscribe/Unsubscribe -> DoConnect/Disconnect (to follow the usual convention of public Foo calling private DoFoo and to avoid using up another name) c) Derived -> ObjClass (because it's not clear what does Derived mean) 6. Extend the unit test to cover more cases. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58625 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/event.h b/include/wx/event.h index 8bea624513..ed6a8017f2 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -27,6 +27,10 @@ #include "wx/thread.h" #include "wx/tracker.h" +#if !wxEVENTS_COMPATIBILITY_2_8 + #include "wx/meta/convertible.h" +#endif + // ---------------------------------------------------------------------------- // forward declarations // ---------------------------------------------------------------------------- @@ -131,20 +135,20 @@ extern WXDLLIMPEXP_BASE wxEventType wxNewEventType(); // a nested typedef: #define wxDEFINE_EVENT( name, type ) \ - const wxTypedEventType< type > name( wxNewEventType() ); + const wxEventTypeTag< type > name( wxNewEventType() ); #define wxDECLARE_EXPORTED_EVENT( expdecl, name, type ) \ - extern const expdecl wxTypedEventType< type > name; + extern const expdecl wxEventTypeTag< type > name; // Define/Declare a templatized event type and initialize it with a // predefined event type. (Only used for wxEVT_SPIN_XXX for backward // compatibility) #define wxDEFINE_EVENT_ALIAS( name, type, value ) \ - const wxTypedEventType< type > name( value ); + const wxEventTypeTag< type > name( value ); #define wxDECLARE_EXPORTED_EVENT_ALIAS( expdecl, name, type ) \ - extern const expdecl wxTypedEventType< type > name; + extern const expdecl wxEventTypeTag< type > name; // Declare a local (not exported) templatized event type: @@ -162,13 +166,18 @@ extern WXDLLIMPEXP_BASE wxEventType wxNewEventType(); #if !wxEVENTS_COMPATIBILITY_2_8 -template -class wxTypedEventType +// 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 +// parameter and provide a mapping between the event type values and their +// corresponding wxEvent-derived classes. +template +class wxEventTypeTag { public: - typedef Event CorrespondingEvent; + // The class of wxEvent-derived class carried by the events of this type. + typedef T EventClass; - wxTypedEventType(wxEventType type) { m_type = type; } + wxEventTypeTag(wxEventType type) { m_type = type; } // Return a wxEventType reference for the initialization of the static // event tables. See wxEventTableEntry::m_eventType for a more thorough @@ -201,18 +210,24 @@ public: virtual ~wxEventFunctor(); // Invoke the actual event handler: - virtual void operator()(wxEvtHandler *, wxEvent &) = 0; + 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; - virtual wxEvtHandler *GetHandler() const { return NULL; } + // these functions are used for functors comparison in Matches() + virtual void *GetHandler() const { return GetEvtHandler(); } + virtual wxEventFunction GetMethod() const { return NULL; } - virtual wxObjectEventFunction GetMethod() const { return NULL; } + // 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; } }; -// A plain method functor +// 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 class WXDLLIMPEXP_BASE wxObjectEventFunctor : public wxEventFunctor { public: @@ -229,22 +244,26 @@ public: (realHandler->*m_method)(event); } - virtual bool Matches(const wxEventFunctor& other) const + virtual bool Matches(const wxEventFunctor& func) const { - wxEvtHandler * const handler = other.GetHandler(); + void * const handler = func.GetHandler(); + if ( handler && GetHandler() != handler ) + return false; - return (m_handler == handler || !handler) && - (m_method == other.GetMethod()); + const wxEventFunction method = GetMethod(); + return !method || GetMethod() == method; } - virtual wxEvtHandler *GetHandler() const { return m_handler; } - virtual wxObjectEventFunction GetMethod() const { return m_method; } + virtual wxEvtHandler *GetEvtHandler() const { return m_handler; } + virtual wxEventFunction GetMethod() const { return m_method; } private: wxEvtHandler *m_handler; wxObjectEventFunction m_method; }; +#if wxEVENTS_COMPATIBILITY_2_8 + // Create a functor for the legacy events: handler can be NULL and its default // value is used by the event table macros @@ -257,224 +276,234 @@ wxNewEventFunctor(const wxEventType& WXUNUSED(evtType), } inline wxObjectEventFunctor -wxConstructEventFunctor(const wxEventType& WXUNUSED(evtType), +wxMakeEventFunctor(const wxEventType& WXUNUSED(evtType), wxObjectEventFunction method, wxEvtHandler *handler) { return wxObjectEventFunctor(method, handler); } -#if !wxEVENTS_COMPATIBILITY_2_8 +#else // !wxEVENTS_COMPATIBILITY_2_8 -template +// functor forwarding the event to anything callable (function, static method, +// generalized functor...) +template class wxEventFunctorFunction : public wxEventFunctor { public: - wxEventFunctorFunction(void (*handler)(typename EventType::CorrespondingEvent &)) + typedef typename EventTag::EventClass EventArg; + + wxEventFunctorFunction(Functor handler) { m_handler = handler; } virtual void operator()(wxEvtHandler *WXUNUSED(handler), wxEvent& event) { - // Protect against wrong event i.e. wxMouseEvent evt(wxEVT_PAINT): - wxASSERT( dynamic_cast< typename EventType::CorrespondingEvent * >( &event ) != NULL ); - - // Will throw a std::bad_cast exception in release build: - ( *m_handler )( dynamic_cast< typename EventType::CorrespondingEvent & >( event )); + m_handler(static_cast(event)); } - virtual bool Matches( const wxEventFunctor &right ) const + virtual bool Matches(const wxEventFunctor& WXUNUSED(func)) const { - wxEventFunctorFunction const &other = dynamic_cast< wxEventFunctorFunction const & >( right ); - - return m_handler == other.m_handler || other.m_handler == NULL; + // 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: - void ( *m_handler )( typename EventType::CorrespondingEvent & ); + Functor m_handler; +}; + +// helper class defining operations different for method functors using an +// object of wxEvtHandler-derived class as handler and the others +namespace wxPrivate +{ + +template struct HandlerImpl; + +// specialization for handlers deriving from wxEvtHandler +template +struct HandlerImpl +{ + static bool IsEvtHandler() + { return true; } + static T *ConvertFromEvtHandler(wxEvtHandler *p) + { return static_cast(p); } + static wxEvtHandler *ConvertToEvtHandler(T *p) + { return p; } + static wxEventFunction ConvertToEvtFunction(void (T::*f)(A&)) + { return reinterpret_cast(f); } }; +// specialization for handlers not deriving from wxEvtHandler +template +struct HandlerImpl +{ + static bool IsEvtHandler() + { return false; } + static T *ConvertFromEvtHandler(wxEvtHandler *) + { return NULL; } + static wxEvtHandler *ConvertToEvtHandler(T *) + { return NULL; } + static wxEventFunction ConvertToEvtFunction(void (T::*)(A&)) + { return NULL; } +}; + +} // namespace wxPrivate -template -class wxEventFunctorMethod : public wxEventFunctor +// functor forwarding the event to a method of the given object +// +// notice that the object class may be different from the class in which the +// method is defined but it must be convertible to this class +template +class wxEventFunctorMethod + : public wxEventFunctor, + private wxPrivate::HandlerImpl + < + Class, + typename EventTag::EventClass, + wxConvertibleTo::value + > { public: - wxEventFunctorMethod( void ( Class::*method )( typename EventType::CorrespondingEvent & ), - Derived *handler ) + typedef typename EventTag::EventClass EventArg; + + wxEventFunctorMethod(void (Class::*method)(EventArg&), ObjClass *handler) { + wxASSERT_MSG( handler || IsEvtHandler(), + "handlers defined in non-wxEvtHandler-derived classes " + "must be connected with a valid sink object" ); + m_handler = handler; m_method = method; } - virtual void operator () ( wxEvtHandler *handler, wxEvent &event ) + virtual void operator()(wxEvtHandler *handler, wxEvent& event) { - // Compile-time type check 1: This requires Derived to derive from or - // be of the same type as Class - Class *realHandler = m_handler; - - if( m_handler == NULL ) + Class * realHandler = m_handler; + if ( !realHandler ) { - // Verify that the handler does indeed derive from the class - // containing the handler method - wxASSERT( dynamic_cast< Class * >( handler) != NULL ); + realHandler = ConvertFromEvtHandler(handler); - realHandler = dynamic_cast< Class * >( handler ); + // this is not supposed to happen but check for it nevertheless + wxCHECK_RET( realHandler, "invalid event handler" ); } - // Protect against wrong event i.e. wxMouseEvent evt(wxEVT_PAINT): - wxASSERT( dynamic_cast< typename EventType::CorrespondingEvent * >( &event ) != NULL ); - - // Will throw a std::bad_cast exception in release build: - ( realHandler->*m_method )( dynamic_cast< typename EventType::CorrespondingEvent & >( event )); + (realHandler->*m_method)(static_cast(event)); } - virtual bool Matches( const wxEventFunctor &right ) const + virtual bool Matches(const wxEventFunctor& func) const { - wxEventFunctorMethod const &other = dynamic_cast< wxEventFunctorMethod const & >( right ); + void * const handler = func.GetHandler(); + if ( handler && GetHandler() != handler ) + return false; - return (( m_handler == other.m_handler || other.m_handler == NULL ) && - ( m_method == other.m_method || other.m_method == NULL )); + const wxEventFunction method = GetMethod(); + return !method || GetMethod() == method; } - virtual wxEvtHandler *GetHandler() const + virtual void *GetHandler() const { - // This makes sure Derived derives from wxEvtHandler (it is still - // possible and even ok if Class does not derive from wxEvtHandler. In - // this case Derived would end up using multiple inheritance: class - // Derived : public wxEvtHandler, public Class { } where Class contains - // the method to call, but wxEvtHandler contains the wxTrackable and - // code for weak ref support return m_handler; } - virtual wxObjectEventFunction GetMethod() const + virtual wxEventFunction GetMethod() const { - return reinterpret_cast(m_method); + return ConvertToEvtFunction(m_method); + } + + virtual wxEvtHandler *GetEvtHandler() const + { + return ConvertToEvtHandler(m_handler); } private: - Derived *m_handler; - void (Class::*m_method)(typename EventType::CorrespondingEvent&); + ObjClass *m_handler; + void (Class::*m_method)(EventArg&); }; - -template -class wxEventFunctorAdapter : public wxEventFunctor +// partial specialization for legacy event types +template +class wxEventFunctorMethod + : public wxObjectEventFunctor { public: - wxEventFunctorAdapter( Functor &functor ) + wxEventFunctorMethod(wxObjectEventFunction method, ObjClass *handler) + : wxObjectEventFunctor(method, handler) { - m_functor = functor; } - - virtual void operator () ( wxEvtHandler *WXUNUSED( handler ), wxEvent &event ) - { - // Protect against wrong event i.e. wxMouseEvent evt(wxEVT_PAINT): - wxASSERT( dynamic_cast< typename EventType::CorrespondingEvent * >( &event ) != NULL ); - - // Will throw a std::bad_cast exception in release build: - m_functor( dynamic_cast< typename EventType::CorrespondingEvent & >( event )); - } - - virtual bool Matches( const wxEventFunctor &right ) const - { - wxEventFunctorAdapter const &other = dynamic_cast< wxEventFunctorAdapter const & >( right ); - - return m_functor == other.m_functor; - } - -private: - Functor m_functor; }; + // -// Create functors for the templatized events (needed in wxEvtHandler::Connect): -// +// Create functors for the templatized events, either allocated on the heap for +// wxNewXXX() variants (this is needed in wxEvtHandler::Connect() to store them +// in dynamic event table) or just by returning them as temporary objects (this +// is enough for Disconnect() and we allocate unnecessary heap allocation like +// this) -// Create a functor for functions: -template -inline wxEventFunctorFunction * -wxNewEventFunctor(const EventType &, - void (*function)(typename EventType::CorrespondingEvent&)) +// Create functors wrapping other functors (including functions): +template +inline wxEventFunctorFunction * +wxNewEventFunctor(const EventTag&, Functor func) { - return new wxEventFunctorFunction(function); + return new wxEventFunctorFunction(func); } -// Create a functor for methods: - -template -inline wxEventFunctorMethod * -wxNewEventFunctor(const EventType &, - void (Class::*method)(typename EventType::CorrespondingEvent&)) +template +inline wxEventFunctorFunction +wxMakeEventFunctor(const EventTag&, Functor func) { - return new wxEventFunctorMethod(method, NULL); + return wxEventFunctorFunction(func); } -template -inline wxEventFunctorMethod * -wxNewEventFunctor(const EventType &, - void (Class::*method)(typename EventType::CorrespondingEvent &), - Derived *handler ) -{ - return new wxEventFunctorMethod(method, handler); -} -// Create a functor for arbitrary functors (like boost::function): -template -inline wxEventFunctorAdapter * -wxNewEventFunctor(const EventType &, - Functor& functor ) +// Create functors for methods: +template + +inline wxEventFunctorMethod * +wxNewEventFunctor(const EventTag&, + void (Class::*method)(EventArg&), + ObjClass *handler) { - return new wxEventFunctorAdapter(functor); + return new wxEventFunctorMethod(method, handler); } -// -// Construct functors for the templatized events (needed in wxEvtHandler::Disconnect): -// - -// Construct a functor for functions: - -template -inline wxEventFunctorFunction -wxConstructEventFunctor(const EventType &, - void (*function)(typename EventType::CorrespondingEvent&)) +template + +inline wxEventFunctorMethod +wxMakeEventFunctor(const EventTag&, + void (Class::*method)(EventArg&), + ObjClass *handler) { - return wxEventFunctorFunction(function); + return wxEventFunctorMethod(method, handler); } -// Construct a functor for methods: - -template -inline wxEventFunctorMethod -wxConstructEventFunctor(const EventType &, - void (Class::*method)(typename EventType::CorrespondingEvent&)) +// Special case for the wxNewEventFunctor() calls used inside the event table +// macros: they don't specify the handler so ObjClass can't be deduced +template +inline wxEventFunctorMethod * +wxNewEventFunctor(const EventTag&, void (Class::*method)(EventArg&)) { - return wxEventFunctorMethod(method, NULL); + return new wxEventFunctorMethod(method, NULL); } -template -inline wxEventFunctorMethod -wxConstructEventFunctor(const EventType &, - void (Class::*method)(typename EventType::CorrespondingEvent&), - Derived *handler) +template + +inline wxEventFunctorMethod +wxMakeEventFunctor(const EventTag&, void (Class::*method)(EventArg&)) { - return wxEventFunctorMethod(method, handler); -} - -// Construct a functor for arbitrary functors (like boost:function): - -template -inline wxEventFunctorAdapter -wxConstructEventFunctor(const EventType &, - Functor& functor) -{ - return wxEventFunctorAdapter(functor); + return wxEventFunctorMethod(method, NULL); } #endif // !wxEVENTS_COMPATIBILITY_2_8 + // many, but not all, standard event types // some generic events @@ -1016,7 +1045,7 @@ class WXDLLIMPEXP_CORE wxScrollWinEvent : public wxEvent public: wxScrollWinEvent(wxEventType commandType = wxEVT_NULL, int pos = 0, int orient = 0); - wxScrollWinEvent(const wxScrollWinEvent & event) : wxEvent(event) + wxScrollWinEvent(const wxScrollWinEvent& event) : wxEvent(event) { m_commandInt = event.m_commandInt; m_extraLong = event.m_extraLong; } @@ -1260,7 +1289,7 @@ public: m_x(x), m_y(y), m_cursor() { } - wxSetCursorEvent(const wxSetCursorEvent & event) + wxSetCursorEvent(const wxSetCursorEvent& event) : wxEvent(event), m_x(event.m_x), m_y(event.m_y), @@ -1403,7 +1432,7 @@ public: : wxEvent(winid, wxEVT_SIZE), m_size(sz) { } - wxSizeEvent(const wxSizeEvent & event) + wxSizeEvent(const wxSizeEvent& event) : wxEvent(event), m_size(event.m_size), m_rect(event.m_rect) { } @@ -1658,7 +1687,7 @@ public: wxMenuEvent(wxEventType type = wxEVT_NULL, int winid = 0, wxMenu* menu = NULL) : wxEvent(winid, type) { m_menuId = winid; m_menu = menu; } - wxMenuEvent(const wxMenuEvent & event) + wxMenuEvent(const wxMenuEvent& event) : wxEvent(event) { m_menuId = event.m_menuId; m_menu = event.m_menu; } @@ -1696,7 +1725,7 @@ public: m_veto(false), // should be false by default m_canVeto(true) {} - wxCloseEvent(const wxCloseEvent & event) + wxCloseEvent(const wxCloseEvent& event) : wxEvent(event), m_loggingOff(event.m_loggingOff), m_veto(event.m_veto), @@ -1746,7 +1775,7 @@ public: wxShowEvent(int winid = 0, bool show = false) : wxEvent(winid, wxEVT_SHOW) { m_show = show; } - wxShowEvent(const wxShowEvent & event) + wxShowEvent(const wxShowEvent& event) : wxEvent(event) { m_show = event.m_show; } @@ -1778,7 +1807,7 @@ public: wxIconizeEvent(int winid = 0, bool iconized = true) : wxEvent(winid, wxEVT_ICONIZE) { m_iconized = iconized; } - wxIconizeEvent(const wxIconizeEvent & event) + wxIconizeEvent(const wxIconizeEvent& event) : wxEvent(event) { m_iconized = event.m_iconized; } @@ -1860,7 +1889,7 @@ public: m_joyStick(joystick) { } - wxJoystickEvent(const wxJoystickEvent & event) + wxJoystickEvent(const wxJoystickEvent& event) : wxEvent(event), m_pos(event.m_pos), m_zPosition(event.m_zPosition), @@ -1995,7 +2024,7 @@ public: m_setText = m_setChecked = false; } - wxUpdateUIEvent(const wxUpdateUIEvent & event) + wxUpdateUIEvent(const wxUpdateUIEvent& event) : wxCommandEvent(event), m_checked(event.m_checked), m_enabled(event.m_enabled), @@ -2191,7 +2220,7 @@ public: : wxEvent(winid, wxEVT_QUERY_NEW_PALETTE), m_paletteRealized(false) { } - wxQueryNewPaletteEvent(const wxQueryNewPaletteEvent & event) + wxQueryNewPaletteEvent(const wxQueryNewPaletteEvent& event) : wxEvent(event), m_paletteRealized(event.m_paletteRealized) { } @@ -2337,7 +2366,7 @@ public: m_pos(pt), m_origin(GuessOrigin(origin)) { } - wxHelpEvent(const wxHelpEvent & event) + wxHelpEvent(const wxHelpEvent& event) : wxCommandEvent(event), m_pos(event.m_pos), m_target(event.m_target), @@ -2395,7 +2424,7 @@ public: wxWindowID winid = 0) : wxCommandEvent(type, winid) { } - wxClipboardTextEvent(const wxClipboardTextEvent & event) + wxClipboardTextEvent(const wxClipboardTextEvent& event) : wxCommandEvent(event) { } @@ -2422,7 +2451,7 @@ public: : wxCommandEvent(type, winid), m_pos(pt) { } - wxContextMenuEvent(const wxContextMenuEvent & event) + wxContextMenuEvent(const wxContextMenuEvent& event) : wxCommandEvent(event), m_pos(event.m_pos) { } @@ -2468,7 +2497,7 @@ public: : wxEvent(0, wxEVT_IDLE), m_requestMore(false) { } - wxIdleEvent(const wxIdleEvent & event) + wxIdleEvent(const wxIdleEvent& event) : wxEvent(event), m_requestMore(event.m_requestMore) { } @@ -2534,7 +2563,7 @@ struct WXDLLIMPEXP_BASE wxEventTableEntryBase // being initialized (a temporary instance is created and then this // constructor is called). - const_cast< wxEventTableEntryBase & >( entry ).m_fn = NULL; + const_cast( entry ).m_fn = NULL; } ~wxEventTableEntryBase() @@ -2554,7 +2583,7 @@ struct WXDLLIMPEXP_BASE wxEventTableEntryBase wxObject* m_callbackUserData; private: - wxEventTableEntryBase &operator = ( const wxEventTableEntryBase & ); + DECLARE_NO_ASSIGN_CLASS(wxEventTableEntryBase) }; // an entry from a static event table @@ -2575,7 +2604,7 @@ struct WXDLLIMPEXP_BASE wxEventTableEntry : public wxEventTableEntryBase const int& m_eventType; private: - wxEventTableEntry &operator = ( const wxEventTableEntry & ); + DECLARE_NO_ASSIGN_CLASS(wxEventTableEntry) }; // an entry used in dynamic event table managed by wxEvtHandler::Connect() @@ -2593,7 +2622,7 @@ struct WXDLLIMPEXP_BASE wxDynamicEventTableEntry : public wxEventTableEntryBase int m_eventType; private: - wxDynamicEventTableEntry &operator = ( const wxDynamicEventTableEntry & ); + DECLARE_NO_ASSIGN_CLASS(wxDynamicEventTableEntry) }; // ---------------------------------------------------------------------------- @@ -2634,7 +2663,7 @@ public: // Handle the given event, in other words search the event table hash // and call self->ProcessEvent() if a match was found. - bool HandleEvent(wxEvent &event, wxEvtHandler *self); + bool HandleEvent(wxEvent& event, wxEvtHandler *self); // Clear table void Clear(); @@ -2745,6 +2774,15 @@ public: // Connecting and disconnecting // ---------------------------- + // These functions are used for old, untyped, event handlers and don't + // check that the type of the function passed to them actually matches the + // type of the event. They also only allow connecting events to methods of + // wxEvtHandler-derived classes. + // + // The template Connect() methods below are safer and allow connecting + // events to arbitrary functions or functors -- but require compiler + // support for templates. + // Dynamic association of a member function handler with the event handler, // winid and event type void Connect(int winid, @@ -2754,9 +2792,9 @@ public: wxObject *userData = NULL, wxEvtHandler *eventSink = NULL) { - wxObjectEventFunctor *functor = wxNewEventFunctor( eventType, func, eventSink ); - - Subscribe( winid, lastId, eventType, functor, userData ); + DoConnect(winid, lastId, eventType, + wxNewEventFunctor(eventType, func, eventSink), + userData); } // Convenience function: take just one id @@ -2781,9 +2819,9 @@ public: wxObject *userData = NULL, wxEvtHandler *eventSink = NULL) { - wxObjectEventFunctor functor = wxConstructEventFunctor( eventType, func, eventSink ); - - return Unsubscribe( winid, lastId, eventType, functor, userData ); + return DoDisconnect(winid, lastId, eventType, + wxMakeEventFunctor(eventType, func, eventSink), + userData ); } bool Disconnect(int winid = wxID_ANY, @@ -2798,305 +2836,258 @@ public: wxObject *userData = NULL, wxEvtHandler *eventSink = NULL) { return Disconnect(wxID_ANY, eventType, func, userData, eventSink); } + #if !wxEVENTS_COMPATIBILITY_2_8 - // - // Connect a method to an event: - // + // Event handling in functions (including generalized functors): - template - void Connect( int winid, - int lastId, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL ) - { - wxEventFunctorMethod< EventType, Class, Class > *functor = - wxNewEventFunctor( eventType, func, static_cast< Class * const >( this )); + template + void Connect(int winid, + int lastId, + const EventTag& eventType, + Functor func) + { + DoConnect(winid, lastId, eventType, + wxNewEventFunctor(eventType, func)); + } - Subscribe( winid, lastId, eventType, functor, userData ); - } + template + void Connect(int winid, const EventTag& eventType, Functor func) + { Connect(winid, wxID_ANY, eventType, func); } - template - void Connect( int winid, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL ) - { Connect( winid, wxID_ANY, eventType, func, userData ); } - - template - void Connect( const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL ) - { Connect( wxID_ANY, wxID_ANY, eventType, func, userData ); } - - template - void Connect( int winid, - int lastId, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { - wxEventFunctorMethod< EventType, Class, Derived > *functor = - wxNewEventFunctor( eventType, func, eventSink ); + template + void Connect(const EventTag& eventType, Functor func) + { Connect(wxID_ANY, eventType, func); } - Subscribe( winid, lastId, eventType, functor, userData ); - } - template - void Connect( int winid, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { Connect( winid, wxID_ANY, eventType, func, userData, eventSink ); } - - template - void Connect( const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { Connect( wxID_ANY, wxID_ANY, eventType, func, userData, eventSink ); } - - template - static void Connect( Sender *sender, - int winid, - int lastId, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) + template + bool Disconnect(int winid, + int lastId, + const EventTag& eventType, + Functor func) { - wxEventFunctorMethod< EventType, Class, Derived > *functor = - wxNewEventFunctor( eventType, func, eventSink ); - - sender->Subscribe( winid, lastId, eventType, functor, userData ); + return DoDisconnect(winid, lastId, eventType, + wxMakeEventFunctor(eventType, func)); } - template - static void Connect( Sender *sender, - int winid, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { Connect( sender, winid, wxID_ANY, eventType, func, userData, eventSink ); } - - template - static void Connect( Sender *sender, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { Connect( sender, wxID_ANY, wxID_ANY, eventType, func, userData, eventSink ); } + template + bool Disconnect(int winid, const EventTag& eventType, Functor func) + { return Disconnect(winid, wxID_ANY, eventType, func); } + template + bool Disconnect(const EventTag& eventType, Functor func) + { return Disconnect(wxID_ANY, eventType, func); } + + + + // Event handling in class methods: the object handling the event (i.e. + // this object itself by default or eventSink if specified) must be + // convertible to this class. // - // Connect a function to an event: - // - template + // Notice that we need to have separate overloads for the versions with and + // without eventSink because in the latter case we must check that this + // object itself derives from Class while in the former this is not + // necessarily true + + // Methods connecting/disconnecting event to this object itself + + template void Connect(int winid, int lastId, - const EventType &eventType, - void (*func)(typename EventType::CorrespondingEvent&), - wxObject* userData = NULL) + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL) { - wxEventFunctorFunction< EventType > *functor = wxNewEventFunctor( eventType, func ); - - Subscribe( winid, lastId, eventType, functor, userData ); + DoConnect(winid, lastId, eventType, + wxNewEventFunctor(eventType, func, static_cast(this)), + userData); } - template - void Connect( int winid, - const EventType &eventType, - void ( *func )( typename EventType::CorrespondingEvent & ), - wxObject* userData = NULL ) - { Connect( winid, wxID_ANY, eventType, func, userData ); } + template + void Connect(int winid, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL) + { Connect(winid, wxID_ANY, eventType, func, userData); } - template - void Connect( const EventType &eventType, - void ( *func )( typename EventType::CorrespondingEvent & ), - wxObject* userData = NULL ) - { Connect( wxID_ANY, wxID_ANY, eventType, func, userData ); } + template + void Connect(const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL) + { Connect(wxID_ANY, eventType, func, userData); } - // - // Connect an arbitrary functor to an event: - // - template - void Connect( int winid, - int lastId, - const EventType &eventType, - Functor &functor, - wxObject* userData = NULL) + template + bool Disconnect(int winid, + int lastId, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL) { - wxEventFunctorAdapter< EventType, Functor > *adapter = - wxNewEventFunctor( eventType, functor ); - - Subscribe( winid, lastId, eventType, adapter, userData ); + return DoDisconnect(winid, lastId, eventType, + wxMakeEventFunctor(eventType, func, + static_cast(this)), + userData); } - template - void Connect( int winid, - const EventType &eventType, - Functor &functor, - wxObject* userData = NULL) - { Connect( winid, wxID_ANY, eventType, functor, userData ); } - - template - void Connect( const EventType &eventType, - Functor &functor, - wxObject* userData = NULL) - { Connect( wxID_ANY, wxID_ANY, eventType, functor, userData ); } - // - // Disconnect a function from an event: - // + template + bool Disconnect(int winid, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL) + { return Disconnect(winid, wxID_ANY, eventType, func, userData); } - template - bool Disconnect( int winid, - int lastId, - const EventType &eventType, - void ( *func )( typename EventType::CorrespondingEvent & ), - wxObject* userData = NULL ) - { - wxEventFunctorFunction< EventType > functor = wxConstructEventFunctor( eventType, func ); + template + bool Disconnect(const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL) + { return Disconnect(wxID_ANY, eventType, func, userData); } + + + // Methods connecting/disconnecting event to another object - return Unsubscribe( winid, lastId, eventType, functor, userData ); + template + + void Connect(int winid, + int lastId, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData, + ObjClass *eventSink) + { + DoConnect(winid, lastId, eventType, + wxNewEventFunctor(eventType, func, eventSink), + userData); } - template - bool Disconnect( int winid, - const EventType &eventType, - void ( *func )( typename EventType::CorrespondingEvent & ), - wxObject* userData = NULL ) - { return Disconnect( winid, wxID_ANY, eventType, func, userData ); } + template + + void Connect(int winid, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData, + ObjClass *eventSink) + { Connect(winid, wxID_ANY, eventType, func, userData, eventSink); } - template - bool Disconnect( const EventType &eventType, - void ( *func )( typename EventType::CorrespondingEvent & ), - wxObject* userData = NULL ) - { return Disconnect( wxID_ANY, wxID_ANY, eventType, func, userData ); } + template + + void Connect(const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData, + ObjClass *eventSink) + { Connect(wxID_ANY, eventType, func, userData, eventSink); } - // - // Disconnect a method from an event: - // - template - bool Disconnect( int winid, - int lastId, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL ) - { - wxEventFunctorMethod< EventType, Class, Class > functor = - wxConstructEventFunctor( eventType, func, static_cast< Class * const >( this )); + template + + bool Disconnect(int winid, + int lastId, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData, + ObjClass *eventSink) + { + return DoDisconnect(winid, lastId, eventType, + wxMakeEventFunctor(eventType, func, eventSink), + userData); + } - return Unsubscribe( winid, lastId, eventType, functor, userData ); - } + template + + bool Disconnect(int winid, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData, + ObjClass *eventSink) + { return Disconnect(winid, wxID_ANY, eventType, func, + userData, eventSink); } + + template + + bool Disconnect(const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData, + ObjClass *eventSink) + { return Disconnect(wxID_ANY, eventType, func, userData, eventSink); } - template - bool Disconnect( int winid, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL ) - { return Disconnect( winid, wxID_ANY, eventType, func, userData ); } - - template - bool Disconnect( const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL ) - { return Disconnect( wxID_ANY, wxID_ANY, eventType, func, userData ); } - - template - bool Disconnect( int winid, - int lastId, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { - wxEventFunctorMethod< EventType, Class, Derived > functor = - wxConstructEventFunctor( eventType, func, eventSink ); - return Unsubscribe( winid, lastId, eventType, functor, userData ); - } - template - bool Disconnect( int winid, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { return Disconnect( winid, wxID_ANY, eventType, func, userData, eventSink ); } - - template - bool Disconnect( const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { return Disconnect( wxID_ANY, wxID_ANY, eventType, func, userData, eventSink ); } - - template - static bool Disconnect( Sender *sender, - int winid, - int lastId, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) + // Static version of Connect() which allows to specify the event source and + // event handler in a more symmetric way + template + static void Connect(ObjSource *eventSrc, + int winid, + int lastId, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL, + ObjClass *eventSink = NULL) { - wxEventFunctorMethod< EventType, Class, Derived > functor = - wxConstructEventFunctor( eventType, func, eventSink ); + eventSrc->Connect(winid, lastId, eventType, func, userData, eventSink); + } - return sender->Unsubscribe( winid, lastId, eventType, functor, userData ); + template + static void Connect(ObjSource *eventSrc, + int winid, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL, + ObjClass *eventSink = NULL) + { + Connect(eventSrc, winid, wxID_ANY, eventType, func, userData, eventSink); } - template - static bool Disconnect( Sender *sender, - int winid, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { return Disconnect( sender, winid, wxID_ANY, eventType, func, userData, eventSink ); } - - template - static bool Disconnect( Sender *sender, - const EventType &eventType, - void ( Class::*func )( typename EventType::CorrespondingEvent & ), - wxObject *userData = NULL, - Derived *eventSink = NULL ) - { return Disconnect( sender, wxID_ANY, wxID_ANY, eventType, func, userData, eventSink ); } + template + static void Connect(ObjSource *eventSrc, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL, + ObjClass *eventSink = NULL) + { + Connect(eventSrc, wxID_ANY, eventType, func, userData, eventSink); + } - // - // Disconnect an arbitrary functor from an event: - // - template - bool Disconnect( int winid, - int lastId, - const EventType &eventType, - Functor &functor, - wxObject* userData = NULL) + template + static bool Disconnect(ObjSource *eventSrc, + int winid, + int lastId, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL, + ObjClass *eventSink = NULL) { - wxEventFunctorAdapter< EventType, Functor > adapter = - wxConstructEventFunctor( eventType, functor ); - - return Unsubscribe( winid, lastId, eventType, adapter, userData ); + return eventSrc->Disconnect(winid, lastId, eventType, func, + userData, eventSink); } - template - bool Disconnect( int winid, - const EventType &eventType, - Functor &functor, - wxObject* userData = NULL) - { return Disconnect( winid, wxID_ANY, eventType, functor, userData ); } - - template - bool Disconnect( const EventType &eventType, - Functor &functor, - wxObject* userData = NULL) - { return Disconnect( wxID_ANY, wxID_ANY, eventType, functor, userData ); } + template + static bool Disconnect(ObjSource *eventSrc, + int winid, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL, + ObjClass *eventSink = NULL) + { + return Disconnect(eventSrc, winid, wxID_ANY, eventType, func, + userData, eventSink); + } + template + static bool Disconnect(ObjSource *eventSrc, + const EventTag& eventType, + void (Class::*func)(EventArg&), + wxObject *userData = NULL, + ObjClass *eventSink = NULL) + { + return Disconnect(eventSrc, wxID_ANY, eventType, func, + userData, eventSink); + } #endif // !wxEVENTS_COMPATIBILITY_2_8 @@ -3140,17 +3131,17 @@ public: private: - void Subscribe(int winid, + void DoConnect(int winid, int lastId, wxEventType eventType, wxEventFunctor *func, - wxObject* userData); + wxObject* userData = NULL); - bool Unsubscribe(int winid, - int lastId, - wxEventType eventType, - const wxEventFunctor &func, - wxObject *userData); + bool DoDisconnect(int winid, + int lastId, + wxEventType eventType, + const wxEventFunctor& func, + wxObject *userData = NULL); static const wxEventTableEntry sm_eventTableEntries[]; diff --git a/include/wx/msw/chkconf.h b/include/wx/msw/chkconf.h index 356cb0160b..d1d30c7c24 100644 --- a/include/wx/msw/chkconf.h +++ b/include/wx/msw/chkconf.h @@ -406,7 +406,7 @@ Windows. */ #if !wxEVENTS_COMPATIBILITY_2_8 -# if !wxCHECK_VISUALC_VERSION(8) +# if !wxCHECK_VISUALC_VERSION(7) # undef wxEVENTS_COMPATIBILITY_2_8 # define wxEVENTS_COMPATIBILITY_2_8 1 # endif diff --git a/src/common/event.cpp b/src/common/event.cpp index 85951a1b3e..6a878fd460 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -1065,7 +1065,7 @@ wxEvtHandler::~wxEvtHandler() // Remove ourselves from sink destructor notifications // (this has usually been done, in wxTrackable destructor) - wxEvtHandler *eventSink = entry->m_fn->GetHandler(); + wxEvtHandler *eventSink = entry->m_fn->GetEvtHandler(); if ( eventSink ) { wxEventConnectionRef * const @@ -1408,10 +1408,11 @@ bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event) return false; } -void wxEvtHandler::Subscribe( int id, int lastId, - wxEventType eventType, - wxEventFunctor *func, - wxObject *userData ) +void wxEvtHandler::DoConnect(int id, + int lastId, + wxEventType eventType, + wxEventFunctor *func, + wxObject *userData) { wxDynamicEventTableEntry *entry = new wxDynamicEventTableEntry(eventType, id, lastId, func, userData); @@ -1423,7 +1424,7 @@ void wxEvtHandler::Subscribe( int id, int lastId, m_dynamicEvents->Insert( (wxObject*) entry ); // Make sure we get to know when a sink is destroyed - wxEvtHandler *eventSink = func->GetHandler(); + wxEvtHandler *eventSink = func->GetEvtHandler(); if ( eventSink && eventSink != this ) { wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink); @@ -1435,17 +1436,17 @@ void wxEvtHandler::Subscribe( int id, int lastId, } bool -wxEvtHandler::Unsubscribe(int id, - int lastId, - wxEventType eventType, - const wxEventFunctor& func, - wxObject *userData) +wxEvtHandler::DoDisconnect(int id, + int lastId, + wxEventType eventType, + const wxEventFunctor& func, + wxObject *userData) { if (!m_dynamicEvents) return false; // Remove connection from tracker node (wxEventConnectionRef) - wxEvtHandler *eventSink = func.GetHandler(); + wxEvtHandler *eventSink = func.GetEvtHandler(); if ( eventSink && eventSink != this ) { wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink); @@ -1490,7 +1491,7 @@ bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event ) if ( event.GetEventType() == entry->m_eventType ) { - wxEvtHandler *handler = entry->m_fn->GetHandler(); + wxEvtHandler *handler = entry->m_fn->GetEvtHandler(); if ( !handler ) handler = this; if ( ProcessEventIfMatchesId(*entry, handler, event) ) @@ -1571,7 +1572,7 @@ void wxEvtHandler::OnSinkDestroyed( wxEvtHandler *sink ) wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); node_nxt = node->GetNext(); - if ( entry->m_fn->GetHandler() == sink ) + if ( entry->m_fn->GetEvtHandler() == sink ) { delete entry->m_callbackUserData; m_dynamicEvents->Erase( node ); diff --git a/tests/events/evthandler.cpp b/tests/events/evthandler.cpp index d19a1fde30..137fe3e6e2 100644 --- a/tests/events/evthandler.cpp +++ b/tests/events/evthandler.cpp @@ -17,38 +17,11 @@ #pragma hdrstop #endif -#ifndef WX_PRECOMP -#endif // WX_PRECOMP - #include "wx/event.h" - -// -------------------------------------------------------------------------- -// test class -// -------------------------------------------------------------------------- - -class EvtHandlerTestCase : public CppUnit::TestCase -{ -public: - EvtHandlerTestCase() {} - -private: - CPPUNIT_TEST_SUITE( EvtHandlerTestCase ); - CPPUNIT_TEST( TestConnectCompilation ); - CPPUNIT_TEST( TestEventFunctorCompare ); - CPPUNIT_TEST_SUITE_END(); - - void TestConnectCompilation(); - void TestEventFunctorCompare(); - - DECLARE_NO_COPY_CLASS(EvtHandlerTestCase) -}; - -// register in the unnamed registry so that these tests are run by default -CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase ); - -// also include in it's own registry so that these tests can be run alone -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase, "EvtHandlerTestCase" ); +// ---------------------------------------------------------------------------- +// test events and their handlers +// ---------------------------------------------------------------------------- const wxEventType EVT_LEGACY = wxNewEventType(); @@ -93,44 +66,145 @@ void GlobalOnMyEvent(MyEvent&) g_called.function = true; } -class MyFunctor +void GlobalOnAnotherEvent(AnotherEvent&); + +void GlobalOnIdle(wxIdleEvent&) +{ + g_called.function = true; +} + +struct MyFunctor { -public: void operator()(MyEvent &) { g_called.functor = true; } +}; - bool operator==(const MyFunctor &) const { return true; } +struct IdleFunctor +{ + void operator()(wxIdleEvent &) { g_called.functor = true; } }; class MyHandler : public wxEvtHandler { public: + static void StaticOnMyEvent(MyEvent &) { g_called.smethod = true; } + static void StaticOnAnotherEvent(AnotherEvent &); + static void StaticOnIdle(wxIdleEvent&) { g_called.smethod = true; } + void OnMyEvent(MyEvent&) { g_called.method = true; } + void OnEvent(wxEvent&) { g_called.method = true; } + void OnAnotherEvent(AnotherEvent&); + void OnIdle(wxIdleEvent&) { g_called.method = true; } +}; - static void StaticOnMyEvent(MyEvent &) { g_called.smethod = true; } +// we can also handle events in classes not deriving from wxEvtHandler +struct MySink +{ + void OnMyEvent(MyEvent&) { g_called.method = true; } + void OnIdle(wxIdleEvent&) { g_called.method = true; } +}; - void OnEvent(wxEvent &) { } - void OnAnotherEvent(AnotherEvent&) { } +// also test event table compilation +class MyClassWithEventTable : public wxEvtHandler +{ +public: + void OnMyEvent(MyEvent&) { g_called.method = true; } + void OnEvent(wxEvent&) { g_called.method = true; } + void OnAnotherEvent(AnotherEvent&); + void OnIdle(wxIdleEvent&) { g_called.method = true; } + +private: + DECLARE_EVENT_TABLE() }; +BEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler) + EVT_IDLE(MyClassWithEventTable::OnIdle) + + // this shouldn't compile: + //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent) +END_EVENT_TABLE() + } // anonymous namespace -void EvtHandlerTestCase::TestConnectCompilation() + +// -------------------------------------------------------------------------- +// test class +// -------------------------------------------------------------------------- + +class EvtHandlerTestCase : public CppUnit::TestCase { - // Test that connecting the 'legacy' events still compiles: +public: + EvtHandlerTestCase() {} + +private: + CPPUNIT_TEST_SUITE( EvtHandlerTestCase ); + CPPUNIT_TEST( BuiltinConnect ); + CPPUNIT_TEST( LegacyConnect ); +#if !wxEVENTS_COMPATIBILITY_2_8 + CPPUNIT_TEST( ConnectFunction ); + CPPUNIT_TEST( ConnectStaticMethod ); + CPPUNIT_TEST( ConnectFunctor ); + CPPUNIT_TEST( ConnectMethod ); + CPPUNIT_TEST( ConnectMethodWithSink ); + CPPUNIT_TEST( ConnectNonHandler ); + CPPUNIT_TEST( StaticConnect ); + CPPUNIT_TEST( InvalidConnect ); +#endif // !wxEVENTS_COMPATIBILITY_2_8 + CPPUNIT_TEST_SUITE_END(); + + void BuiltinConnect(); + void LegacyConnect(); +#if !wxEVENTS_COMPATIBILITY_2_8 + void ConnectFunction(); + void ConnectStaticMethod(); + void ConnectFunctor(); + void ConnectMethod(); + void ConnectMethodWithSink(); + void ConnectNonHandler(); + void StaticConnect(); + void InvalidConnect(); +#endif // !wxEVENTS_COMPATIBILITY_2_8 + + // these member variables exceptionally don't use "m_" prefix because + // they're used so many times MyHandler handler; MyEvent e; - handler.Connect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); - handler.Connect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); - handler.Connect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + DECLARE_NO_COPY_CLASS(EvtHandlerTestCase) +}; - handler.Disconnect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); - handler.Disconnect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); - handler.Disconnect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); +// register in the unnamed registry so that these tests are run by default +CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase ); + +// also include in it's own registry so that these tests can be run alone +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase, "EvtHandlerTestCase" ); + +void EvtHandlerTestCase::BuiltinConnect() +{ + handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle)); + handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle)); + + handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler); + handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler); +#if !wxEVENTS_COMPATIBILITY_2_8 + handler.Connect(wxEVT_IDLE, GlobalOnIdle); + handler.Disconnect(wxEVT_IDLE, GlobalOnIdle); + IdleFunctor f; + handler.Connect(wxEVT_IDLE, f); + handler.Disconnect(wxEVT_IDLE, f); + handler.Connect(wxEVT_IDLE, &MyHandler::OnIdle); + handler.Disconnect(wxEVT_IDLE, &MyHandler::OnIdle); + + handler.Connect(wxEVT_IDLE, &MyHandler::StaticOnIdle); + handler.Disconnect(wxEVT_IDLE, &MyHandler::StaticOnIdle); +#endif // !wxEVENTS_COMPATIBILITY_2_8 +} + +void EvtHandlerTestCase::LegacyConnect() +{ handler.Connect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent ); handler.Connect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent ); handler.Connect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent ); @@ -139,38 +213,99 @@ void EvtHandlerTestCase::TestConnectCompilation() handler.Disconnect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent ); handler.Disconnect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent ); - // Call (and therefore instantiate) all Connect() variants to detect template - // errors: + + handler.Connect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + handler.Connect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + handler.Connect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + + handler.Disconnect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + handler.Disconnect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + handler.Disconnect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); +} #if !wxEVENTS_COMPATIBILITY_2_8 + +void EvtHandlerTestCase::ConnectFunction() +{ + // function tests + handler.Connect( EVT_MYEVENT, GlobalOnMyEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.function ); + handler.Disconnect( EVT_MYEVENT, GlobalOnMyEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.function ); // check that it was disconnected + + handler.Connect( 0, EVT_MYEVENT, GlobalOnMyEvent ); + handler.Disconnect( 0, EVT_MYEVENT, GlobalOnMyEvent ); + + handler.Connect( 0, 0, EVT_MYEVENT, GlobalOnMyEvent ); + handler.Disconnect( 0, 0, EVT_MYEVENT, GlobalOnMyEvent ); +} + +void EvtHandlerTestCase::ConnectStaticMethod() +{ + // static method tests (this is same as functions but still test it just in + // case we hit some strange compiler bugs) handler.Connect( EVT_MYEVENT, &MyHandler::StaticOnMyEvent ); g_called.Reset(); handler.ProcessEvent(e); CPPUNIT_ASSERT( g_called.smethod ); handler.Disconnect( EVT_MYEVENT, &MyHandler::StaticOnMyEvent ); - g_called.Reset(); handler.ProcessEvent(e); - CPPUNIT_ASSERT( !g_called.smethod ); // check that it was disconnected + CPPUNIT_ASSERT( !g_called.smethod ); handler.Connect( 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent ); handler.Disconnect( 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent ); handler.Connect( 0, 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent ); handler.Disconnect( 0, 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent ); +} +void EvtHandlerTestCase::ConnectFunctor() +{ + // generalized functor tests + MyFunctor functor; + handler.Connect( EVT_MYEVENT, functor ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.functor ); + handler.Disconnect( EVT_MYEVENT, functor ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.functor ); - handler.Connect( EVT_MYEVENT, &MyHandler::OnMyEvent ); - handler.Connect( 0, EVT_MYEVENT, &MyHandler::OnMyEvent ); - handler.Connect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent ); + handler.Connect( 0, EVT_MYEVENT, functor ); + handler.Disconnect( 0, EVT_MYEVENT, functor ); + + handler.Connect( 0, 0, EVT_MYEVENT, functor ); + handler.Disconnect( 0, 0, EVT_MYEVENT, functor ); +} +void EvtHandlerTestCase::ConnectMethod() +{ + // class method tests + handler.Connect( EVT_MYEVENT, &MyHandler::OnMyEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.method ); handler.Disconnect( EVT_MYEVENT, &MyHandler::OnMyEvent ); - handler.Disconnect( 0, EVT_MYEVENT, &MyHandler::OnMyEvent ); - handler.Disconnect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.method ); + handler.Connect( 0, EVT_MYEVENT, &MyHandler::OnMyEvent ); + handler.Disconnect( 0, EVT_MYEVENT, &MyHandler::OnMyEvent ); + handler.Connect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent ); + handler.Disconnect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent ); +} +void EvtHandlerTestCase::ConnectMethodWithSink() +{ handler.Connect( EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); handler.Connect( 0, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); handler.Connect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); @@ -178,8 +313,25 @@ void EvtHandlerTestCase::TestConnectCompilation() handler.Disconnect( EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); handler.Disconnect( 0, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); handler.Disconnect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); +} + +void EvtHandlerTestCase::ConnectNonHandler() +{ + // class method tests for class not derived from wxEvtHandler + MySink sink; + handler.Connect( EVT_MYEVENT, &MySink::OnMyEvent, NULL, &sink ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.method ); + handler.Disconnect( EVT_MYEVENT, &MySink::OnMyEvent, NULL, &sink ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.method ); +} +void EvtHandlerTestCase::StaticConnect() +{ wxEvtHandler::Connect( &handler, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); wxEvtHandler::Connect( &handler, 0, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); wxEvtHandler::Connect( &handler, 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); @@ -187,43 +339,17 @@ void EvtHandlerTestCase::TestConnectCompilation() wxEvtHandler::Disconnect( &handler, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); wxEvtHandler::Disconnect( &handler, 0, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); wxEvtHandler::Disconnect( &handler, 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent, NULL, &handler ); +} - - - MyFunctor functor; - - handler.Connect( EVT_MYEVENT, functor ); - handler.Connect( 0, EVT_MYEVENT, functor ); - handler.Connect( 0, 0, EVT_MYEVENT, functor ); - - handler.Disconnect( EVT_MYEVENT, functor ); - handler.Disconnect( 0, EVT_MYEVENT, functor ); - handler.Disconnect( 0, 0, EVT_MYEVENT, functor ); - +void EvtHandlerTestCase::InvalidConnect() +{ // these calls shouldn't compile but we unfortunately can't check this // automatically, you need to uncomment them manually and test that // compilation does indeed fail - //handler.Connect(EVT_MYEVENT, &MyHandler::OnAnotherEvent, NULL, &handler); -#endif // !wxEVENTS_COMPATIBILITY_2_8 -} - -void EvtHandlerTestCase::TestEventFunctorCompare() -{ -//#if !wxEVENTS_COMPATIBILITY_2_8 -// MyHandler handler1; -// wxEventFunctor *connectFunctor = wxNewEventFunctor( EVT_MYEVENT, &MyHandler::OnMyEvent, &handler1 ); -// wxEventFunctor *disconnectFunctor = wxNewEventFunctor( EVT_MYEVENT, &MyHandler::OnMyEvent, &handler1 ); -// wxEventFunctor *nullFunctor = wxNewEventFunctor( EVT_MYEVENT, &MyHandler::OnMyEvent ); -// -// CPPUNIT_ASSERT( connectFunctor->Matches( *disconnectFunctor )); -// CPPUNIT_ASSERT( disconnectFunctor->Matches( *connectFunctor )); -// -// CPPUNIT_ASSERT( connectFunctor->Matches( *nullFunctor )); -// CPPUNIT_ASSERT( nullFunctor->Matches( *connectFunctor )); -// -// CPPUNIT_ASSERT( disconnectFunctor->Matches( *nullFunctor )); -// CPPUNIT_ASSERT( nullFunctor->Matches( *disconnectFunctor )); -//#endif + //handler.Connect(EVT_MYEVENT, GlobalOnAnotherEvent); + //IdleFunctor f; handler.Connect(EVT_MYEVENT, f); + //handler.Connect(EVT_MYEVENT, &MyHandler::StaticOnAnotherEvent); + //handler.Connect(EVT_MYEVENT, &MyHandler::OnAnotherEvent); } - +#endif // !wxEVENTS_COMPATIBILITY_2_8