// Purpose: Test the new event types and wxEvtHandler-methods
// Author: Peter Most
// Created: 2009-01-24
-// RCS-ID: $Id$
// Copyright: (c) 2009 Peter Most
///////////////////////////////////////////////////////////////////////////////
// test events and their handlers
// ----------------------------------------------------------------------------
-const wxEventType EVT_LEGACY = wxNewEventType();
+const wxEventType LegacyEventType = wxNewEventType();
class MyEvent;
-wxDEFINE_EVENT( EVT_MYEVENT, MyEvent )
+wxDEFINE_EVENT(MyEventType, MyEvent);
class MyEvent : public wxEvent
{
public:
- MyEvent() : wxEvent(0, EVT_MYEVENT) { }
+ MyEvent() : wxEvent(0, MyEventType) { }
virtual wxEvent *Clone() const { return new MyEvent; }
};
+typedef void (wxEvtHandler::*MyEventFunction)(MyEvent&);
+#ifndef wxHAS_EVENT_BIND
+ #define MyEventHandler(func) wxEVENT_HANDLER_CAST(MyEventFunction, func)
+#else
+ #define MyEventHandler(func) &func
+#endif
+#define EVT_MYEVENT(func) \
+ wx__DECLARE_EVT0(MyEventType, MyEventHandler(func))
+
class AnotherEvent : public wxEvent
{
};
g_called.function = true;
}
+void GlobalOnEvent(wxEvent&)
+{
+ g_called.function = true;
+}
+
+#ifdef TEST_INVALID_BIND_GLOBAL
void GlobalOnAnotherEvent(AnotherEvent&);
+#endif
void GlobalOnIdle(wxIdleEvent&)
{
struct MySink
{
void OnMyEvent(MyEvent&) { g_called.method = true; }
+ void OnEvent(wxEvent&) { g_called.method = true; }
void OnIdle(wxIdleEvent&) { g_called.method = true; }
};
BEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler)
EVT_IDLE(MyClassWithEventTable::OnIdle)
+ EVT_MYEVENT(MyClassWithEventTable::OnMyEvent)
+#ifdef wxHAS_EVENT_BIND
+ EVT_MYEVENT(MyClassWithEventTable::OnEvent)
+#endif
+
// this shouldn't compile:
+ //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
//EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
END_EVENT_TABLE()
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( DisconnectWildcard );
+ CPPUNIT_TEST( AutoDisconnect );
+#ifdef wxHAS_EVENT_BIND
+ CPPUNIT_TEST( BindFunction );
+ CPPUNIT_TEST( BindStaticMethod );
+ CPPUNIT_TEST( BindFunctor );
+ CPPUNIT_TEST( BindMethod );
+ CPPUNIT_TEST( BindMethodUsingBaseEvent );
+ CPPUNIT_TEST( BindFunctionUsingBaseEvent );
+ CPPUNIT_TEST( BindNonHandler );
+ CPPUNIT_TEST( InvalidBind );
+#endif // wxHAS_EVENT_BIND
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
+ void DisconnectWildcard();
+ void AutoDisconnect();
+#ifdef wxHAS_EVENT_BIND
+ void BindFunction();
+ void BindStaticMethod();
+ void BindFunctor();
+ void BindMethod();
+ void BindMethodUsingBaseEvent();
+ void BindFunctionUsingBaseEvent();
+ void BindNonHandler();
+ void InvalidBind();
+#endif // wxHAS_EVENT_BIND
// these member variables exceptionally don't use "m_" prefix because
// 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
+// also include in its 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), 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);
+ // using casts like this is even uglier than using wxIdleEventHandler but
+ // it should still continue to work for compatibility
+ handler.Connect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle);
+ handler.Disconnect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle);
+
+#ifdef wxHAS_EVENT_BIND
+ handler.Bind(wxEVT_IDLE, GlobalOnIdle);
+ handler.Unbind(wxEVT_IDLE, GlobalOnIdle);
IdleFunctor f;
- handler.Connect(wxEVT_IDLE, f);
- handler.Disconnect(wxEVT_IDLE, f);
+ handler.Bind(wxEVT_IDLE, f);
+ handler.Unbind(wxEVT_IDLE, f);
- handler.Connect(wxEVT_IDLE, &MyHandler::OnIdle);
- handler.Disconnect(wxEVT_IDLE, &MyHandler::OnIdle);
+ handler.Bind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
+ handler.Unbind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
- handler.Connect(wxEVT_IDLE, &MyHandler::StaticOnIdle);
- handler.Disconnect(wxEVT_IDLE, &MyHandler::StaticOnIdle);
-#endif // !wxEVENTS_COMPATIBILITY_2_8
+ handler.Bind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
+ handler.Unbind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
+#endif // wxHAS_EVENT_BIND
}
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 );
+ handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
+ handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
+ handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
- handler.Disconnect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent );
- handler.Disconnect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent );
- handler.Disconnect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::OnEvent );
+ handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
+ handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
+ handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
- 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.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
+ handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
+ handler.Connect( 0, 0, LegacyEventType, (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 );
+ handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
+ handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
+ handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
}
-#if !wxEVENTS_COMPATIBILITY_2_8
+void EvtHandlerTestCase::DisconnectWildcard()
+{
+ // should be able to disconnect a different handler using "wildcard search"
+ MyHandler sink;
+ wxEvtHandler source;
+ source.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink);
+ CPPUNIT_ASSERT(source.Disconnect(wxID_ANY, wxEVT_IDLE));
+ // destruction of source and sink here should properly clean up the
+ // wxEventConnectionRef without crashing
+}
-void EvtHandlerTestCase::ConnectFunction()
+void EvtHandlerTestCase::AutoDisconnect()
+{
+ wxEvtHandler source;
+ {
+ MyHandler sink;
+ source.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink);
+ // mismatched event type, so nothing should be disconnected
+ CPPUNIT_ASSERT(!source.Disconnect(wxEVT_THREAD, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink));
+ }
+ // destruction of sink should have automatically disconnected it, so
+ // there should be nothing to disconnect anymore
+ CPPUNIT_ASSERT(!source.Disconnect(wxID_ANY, wxEVT_IDLE));
+}
+
+#ifdef wxHAS_EVENT_BIND
+
+void EvtHandlerTestCase::BindFunction()
{
// function tests
- handler.Connect( EVT_MYEVENT, GlobalOnMyEvent );
+ handler.Bind( MyEventType, GlobalOnMyEvent );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.function );
- handler.Disconnect( EVT_MYEVENT, GlobalOnMyEvent );
+ handler.Unbind( MyEventType, 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.Bind( MyEventType, GlobalOnMyEvent, 0 );
+ handler.Unbind( MyEventType, GlobalOnMyEvent, 0 );
- handler.Connect( 0, 0, EVT_MYEVENT, GlobalOnMyEvent );
- handler.Disconnect( 0, 0, EVT_MYEVENT, GlobalOnMyEvent );
+ handler.Bind( MyEventType, GlobalOnMyEvent, 0, 0 );
+ handler.Unbind( MyEventType, GlobalOnMyEvent, 0, 0 );
}
-void EvtHandlerTestCase::ConnectStaticMethod()
+void EvtHandlerTestCase::BindStaticMethod()
{
// 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 );
+ handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.smethod );
- handler.Disconnect( EVT_MYEVENT, &MyHandler::StaticOnMyEvent );
+ handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( !g_called.smethod );
- handler.Connect( 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent );
- handler.Disconnect( 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent );
+ handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
+ handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
- handler.Connect( 0, 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent );
- handler.Disconnect( 0, 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent );
+ handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
+ handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
}
-void EvtHandlerTestCase::ConnectFunctor()
+void EvtHandlerTestCase::BindFunctor()
{
// generalized functor tests
MyFunctor functor;
- handler.Connect( EVT_MYEVENT, functor );
+ handler.Bind( MyEventType, functor );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.functor );
- handler.Disconnect( EVT_MYEVENT, functor );
+ handler.Unbind( MyEventType, functor );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( !g_called.functor );
- handler.Connect( 0, EVT_MYEVENT, functor );
- handler.Disconnect( 0, EVT_MYEVENT, functor );
+ handler.Bind( MyEventType, functor, 0 );
+ handler.Unbind( MyEventType, functor, 0 );
+
+ handler.Bind( MyEventType, functor, 0, 0 );
+ handler.Unbind( MyEventType, functor, 0, 0 );
+
+ // test that a temporary functor is working as well and also test that
+ // unbinding a different (though equal) instance of the same functor does
+ // not work
+ MyFunctor func;
+ handler.Bind( MyEventType, MyFunctor() );
+ CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func ));
+
+ handler.Bind( MyEventType, MyFunctor(), 0 );
+ CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0 ));
- handler.Connect( 0, 0, EVT_MYEVENT, functor );
- handler.Disconnect( 0, 0, EVT_MYEVENT, functor );
+ handler.Bind( MyEventType, MyFunctor(), 0, 0 );
+ CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0, 0 ));
}
-void EvtHandlerTestCase::ConnectMethod()
+void EvtHandlerTestCase::BindMethod()
{
// class method tests
- handler.Connect( EVT_MYEVENT, &MyHandler::OnMyEvent );
+ handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler );
+ g_called.Reset();
+ handler.ProcessEvent(e);
+ CPPUNIT_ASSERT( g_called.method );
+ handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler );
+ g_called.Reset();
+ handler.ProcessEvent(e);
+ CPPUNIT_ASSERT( !g_called.method );
+
+ handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
+ handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
+
+ handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
+ handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
+}
+
+void EvtHandlerTestCase::BindMethodUsingBaseEvent()
+{
+ // test connecting a method taking just wxEvent and not MyEvent: this
+ // should work too if we don't need any MyEvent-specific information in the
+ // handler
+ handler.Bind( MyEventType, &MyHandler::OnEvent, &handler );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.method );
- handler.Disconnect( EVT_MYEVENT, &MyHandler::OnMyEvent );
+ handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler );
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.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
+ handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
- handler.Connect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent );
- handler.Disconnect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent );
+ handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
+ handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
}
-void EvtHandlerTestCase::ConnectMethodWithSink()
+
+void EvtHandlerTestCase::BindFunctionUsingBaseEvent()
{
- 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 );
+ // test connecting a function taking just wxEvent and not MyEvent: this
+ // should work too if we don't need any MyEvent-specific information in the
+ // handler
+ handler.Bind( MyEventType, GlobalOnEvent );
+ g_called.Reset();
+ handler.ProcessEvent(e);
+ CPPUNIT_ASSERT( g_called.function );
+ handler.Unbind( MyEventType, GlobalOnEvent );
+ g_called.Reset();
+ handler.ProcessEvent(e);
+ CPPUNIT_ASSERT( !g_called.function );
- 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 );
+ handler.Bind( MyEventType, GlobalOnEvent, 0 );
+ handler.Unbind( MyEventType, GlobalOnEvent, 0 );
+
+ handler.Bind( MyEventType, GlobalOnEvent, 0, 0 );
+ handler.Unbind( MyEventType, GlobalOnEvent, 0, 0 );
}
-void EvtHandlerTestCase::ConnectNonHandler()
+
+
+void EvtHandlerTestCase::BindNonHandler()
{
// class method tests for class not derived from wxEvtHandler
MySink sink;
- handler.Connect( EVT_MYEVENT, &MySink::OnMyEvent, NULL, &sink );
+ handler.Bind( MyEventType, &MySink::OnMyEvent, &sink );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.method );
- handler.Disconnect( EVT_MYEVENT, &MySink::OnMyEvent, NULL, &sink );
+ handler.Unbind( MyEventType, &MySink::OnMyEvent, &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 );
-
- 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 );
-}
-
-void EvtHandlerTestCase::InvalidConnect()
+void EvtHandlerTestCase::InvalidBind()
{
// 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, GlobalOnAnotherEvent);
- //IdleFunctor f; handler.Connect(EVT_MYEVENT, f);
- //handler.Connect(EVT_MYEVENT, &MyHandler::StaticOnAnotherEvent);
- //handler.Connect(EVT_MYEVENT, &MyHandler::OnAnotherEvent);
+
+ // connecting a handler with incompatible signature shouldn't work
+#ifdef TEST_INVALID_BIND_GLOBAL
+ handler.Bind(MyEventType, GlobalOnAnotherEvent);
+#endif
+#ifdef TEST_INVALID_BIND_STATIC
+ handler.Bind(MyEventType, &MyHandler::StaticOnAnotherEvent);
+#endif
+#ifdef TEST_INVALID_BIND_METHOD
+ handler.Bind(MyEventType, &MyHandler::OnAnotherEvent, &handler);
+#endif
+#ifdef TEST_INVALID_BIND_FUNCTOR
+ IdleFunctor f;
+ handler.Bind(MyEventType, f);
+#endif
+
+ // the handler can't be omitted when calling Bind()
+#ifdef TEST_INVALID_BIND_NO_HANDLER
+ handler.Bind(MyEventType, &MyHandler::OnMyEvent);
+#endif
+
+ // calling a derived class method with a base class pointer must not work
+#ifdef TEST_INVALID_BIND_DERIVED
+ struct C1 : wxEvtHandler { };
+ struct C2 : wxEvtHandler { void OnWhatever(wxEvent&); };
+ C1 c1;
+ c1.Bind(&C2::OnWhatever);
+#endif
+
+ // using object pointer incompatible with the method must not work
+#ifdef TEST_INVALID_BIND_WRONG_CLASS
+ MySink mySink;
+ MyHandler myHandler;
+ myHandler.Bind(MyEventType, &MyHandler::OnMyEvent, &mySink);
+#endif
}
-#endif // !wxEVENTS_COMPATIBILITY_2_8
+#endif // wxHAS_EVENT_BIND