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
{
+// helper template defining nested "type" typedef as the event class
+// corresponding to the given event type
+template <typename T> struct EventClassOf;
+
+// the typed events provide the information about the class of the events they
+// carry themselves:
+template <typename T>
+struct EventClassOf< wxEventTypeTag<T> >
+{
+ typedef typename wxEventTypeTag<T>::EventClass type;
+};
+
+// for the old untyped events we don't have information about the exact event
+// class carried by them
+template <>
+struct EventClassOf<wxEventType>
+{
+ typedef wxEvent type;
+};
+
+
+// helper class defining operations different for method functors using an
+// object of wxEvtHandler-derived class as handler and the others
template <typename T, typename A, bool> struct HandlerImpl;
// specialization for handlers deriving from wxEvtHandler
static wxEvtHandler *ConvertToEvtHandler(T *p)
{ return p; }
static wxEventFunction ConvertToEvtFunction(void (T::*f)(A&))
- { return reinterpret_cast<wxEventFunction>(f); }
+ { return static_cast<wxEventFunction>(
+ reinterpret_cast<void (T::*)(wxEvent&)>(f)); }
};
// specialization for handlers not deriving from wxEvtHandler
//
// 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 <typename EventTag, typename Class, typename ObjClass>
+//
+// also, the type of the handler parameter doesn't need to be exactly the same
+// as EventTag::EventClass but it must be its base class -- this is explicitly
+// allowed to handle different events in the same handler taking wxEvent&, for
+// example
+template
+ <typename EventTag, typename Class, typename EventArg, typename ObjClass>
class wxEventFunctorMethod
: public wxEventFunctor,
private wxPrivate::HandlerImpl
<
Class,
- typename EventTag::EventClass,
+ EventArg,
wxConvertibleTo<Class, wxEvtHandler>::value
>
{
+private:
+ static void CheckHandlerArgument(EventArg *) { }
+
public:
- typedef typename EventTag::EventClass EventArg;
+ // the event class associated with the given event tag
+ typedef typename wxPrivate::EventClassOf<EventTag>::type EventClass;
+
wxEventFunctorMethod(void (Class::*method)(EventArg&), ObjClass *handler)
{
"handlers defined in non-wxEvtHandler-derived classes "
"must be connected with a valid sink object" );
+ // 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));
+
m_handler = handler;
m_method = method;
}
wxCHECK_RET( realHandler, "invalid event handler" );
}
+ // the real (run-time) type of event is EventClass and we checked in
+ // the ctor that EventClass can be converted to EventArg, so this cast
+ // is always valid
(realHandler->*m_method)(static_cast<EventArg&>(event));
}
void (Class::*m_method)(EventArg&);
};
-// partial specialization for legacy event types
-template <typename ObjClass>
-class wxEventFunctorMethod<wxEventType, wxEvtHandler, ObjClass>
- : public wxObjectEventFunctor
-{
-public:
- wxEventFunctorMethod(wxObjectEventFunction method, ObjClass *handler)
- : wxObjectEventFunctor(method, handler)
- {
- }
-};
-
//
// Create functors for the templatized events, either allocated on the heap for
// Create functors for methods:
template
<typename EventTag, typename Class, typename EventArg, typename ObjClass>
-inline wxEventFunctorMethod<EventTag, Class, ObjClass> *
+inline wxEventFunctorMethod<EventTag, Class, EventArg, ObjClass> *
wxNewEventFunctor(const EventTag&,
void (Class::*method)(EventArg&),
ObjClass *handler)
{
- return new wxEventFunctorMethod<EventTag, Class, ObjClass>(method, handler);
+ return new wxEventFunctorMethod<EventTag, Class, EventArg, ObjClass>(
+ method, handler);
}
template
<typename EventTag, typename Class, typename EventArg, typename ObjClass>
-inline wxEventFunctorMethod<EventTag, Class, ObjClass>
+inline wxEventFunctorMethod<EventTag, Class, EventArg, ObjClass>
wxMakeEventFunctor(const EventTag&,
void (Class::*method)(EventArg&),
ObjClass *handler)
{
- return wxEventFunctorMethod<EventTag, Class, ObjClass>(method, handler);
+ return wxEventFunctorMethod<EventTag, Class, EventArg, ObjClass>(
+ method, handler);
}
// 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 <typename EventTag, typename Class, typename EventArg>
-inline wxEventFunctorMethod<EventTag, Class, Class> *
+inline wxEventFunctorMethod<EventTag, Class, EventArg, Class> *
wxNewEventFunctor(const EventTag&, void (Class::*method)(EventArg&))
{
- return new wxEventFunctorMethod<EventTag, Class, Class>(method, NULL);
+ return new wxEventFunctorMethod<EventTag, Class, EventArg, Class>(
+ method, NULL);
}
template
<typename EventTag, typename Class, typename EventArg, typename ObjClass>
-inline wxEventFunctorMethod<EventTag, Class, Class>
+inline wxEventFunctorMethod<EventTag, Class, EventArg, Class>
wxMakeEventFunctor(const EventTag&, void (Class::*method)(EventArg&))
{
- return wxEventFunctorMethod<EventTag, Class, Class>(method, NULL);
+ return wxEventFunctorMethod<EventTag, Class, EventArg, Class>(
+ method, NULL);
}
#endif // !wxEVENTS_COMPATIBILITY_2_8
// 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; }
};
+#define EVT_MYEVENT(func) wx__DECLARE_EVT0(MyEventType, &func)
+
class AnotherEvent : public wxEvent
{
};
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)
+ EVT_MYEVENT(MyClassWithEventTable::OnEvent)
+
// this shouldn't compile:
+ //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
//EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
END_EVENT_TABLE()
CPPUNIT_TEST( ConnectStaticMethod );
CPPUNIT_TEST( ConnectFunctor );
CPPUNIT_TEST( ConnectMethod );
+ CPPUNIT_TEST( ConnectMethodUsingBaseEvent );
CPPUNIT_TEST( ConnectMethodWithSink );
CPPUNIT_TEST( ConnectNonHandler );
CPPUNIT_TEST( StaticConnect );
void ConnectStaticMethod();
void ConnectFunctor();
void ConnectMethod();
+ void ConnectMethodUsingBaseEvent();
void ConnectMethodWithSink();
void ConnectNonHandler();
void StaticConnect();
handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
+ // 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);
+
#if !wxEVENTS_COMPATIBILITY_2_8
handler.Connect(wxEVT_IDLE, GlobalOnIdle);
handler.Disconnect(wxEVT_IDLE, GlobalOnIdle);
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::ConnectFunction()
{
// function tests
- handler.Connect( EVT_MYEVENT, GlobalOnMyEvent );
+ handler.Connect( MyEventType, GlobalOnMyEvent );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.function );
- handler.Disconnect( EVT_MYEVENT, GlobalOnMyEvent );
+ handler.Disconnect( 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.Connect( 0, MyEventType, GlobalOnMyEvent );
+ handler.Disconnect( 0, MyEventType, GlobalOnMyEvent );
- handler.Connect( 0, 0, EVT_MYEVENT, GlobalOnMyEvent );
- handler.Disconnect( 0, 0, EVT_MYEVENT, GlobalOnMyEvent );
+ handler.Connect( 0, 0, MyEventType, GlobalOnMyEvent );
+ handler.Disconnect( 0, 0, MyEventType, 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 );
+ handler.Connect( MyEventType, &MyHandler::StaticOnMyEvent );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.smethod );
- handler.Disconnect( EVT_MYEVENT, &MyHandler::StaticOnMyEvent );
+ handler.Disconnect( 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.Connect( 0, MyEventType, &MyHandler::StaticOnMyEvent );
+ handler.Disconnect( 0, MyEventType, &MyHandler::StaticOnMyEvent );
- handler.Connect( 0, 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent );
- handler.Disconnect( 0, 0, EVT_MYEVENT, &MyHandler::StaticOnMyEvent );
+ handler.Connect( 0, 0, MyEventType, &MyHandler::StaticOnMyEvent );
+ handler.Disconnect( 0, 0, MyEventType, &MyHandler::StaticOnMyEvent );
}
void EvtHandlerTestCase::ConnectFunctor()
// generalized functor tests
MyFunctor functor;
- handler.Connect( EVT_MYEVENT, functor );
+ handler.Connect( MyEventType, functor );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.functor );
- handler.Disconnect( EVT_MYEVENT, functor );
+ handler.Disconnect( 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.Connect( 0, MyEventType, functor );
+ handler.Disconnect( 0, MyEventType, functor );
- handler.Connect( 0, 0, EVT_MYEVENT, functor );
- handler.Disconnect( 0, 0, EVT_MYEVENT, functor );
+ handler.Connect( 0, 0, MyEventType, functor );
+ handler.Disconnect( 0, 0, MyEventType, functor );
}
void EvtHandlerTestCase::ConnectMethod()
{
// class method tests
- handler.Connect( EVT_MYEVENT, &MyHandler::OnMyEvent );
+ handler.Connect( MyEventType, &MyHandler::OnMyEvent );
+ g_called.Reset();
+ handler.ProcessEvent(e);
+ CPPUNIT_ASSERT( g_called.method );
+ handler.Disconnect( MyEventType, &MyHandler::OnMyEvent );
+ g_called.Reset();
+ handler.ProcessEvent(e);
+ CPPUNIT_ASSERT( !g_called.method );
+
+ handler.Connect( 0, MyEventType, &MyHandler::OnMyEvent );
+ handler.Disconnect( 0, MyEventType, &MyHandler::OnMyEvent );
+
+ handler.Connect( 0, 0, MyEventType, &MyHandler::OnMyEvent );
+ handler.Disconnect( 0, 0, MyEventType, &MyHandler::OnMyEvent );
+}
+
+void EvtHandlerTestCase::ConnectMethodUsingBaseEvent()
+{
+ // 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.Connect( MyEventType, &MyHandler::OnEvent );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.method );
- handler.Disconnect( EVT_MYEVENT, &MyHandler::OnMyEvent );
+ handler.Disconnect( MyEventType, &MyHandler::OnEvent );
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, MyEventType, &MyHandler::OnEvent );
+ handler.Disconnect( 0, MyEventType, &MyHandler::OnEvent );
- handler.Connect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent );
- handler.Disconnect( 0, 0, EVT_MYEVENT, &MyHandler::OnMyEvent );
+ handler.Connect( 0, 0, MyEventType, &MyHandler::OnEvent );
+ handler.Disconnect( 0, 0, MyEventType, &MyHandler::OnEvent );
}
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 );
+ handler.Connect( MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
+ handler.Connect( 0, MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
+ handler.Connect( 0, 0, MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
- 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.Disconnect( MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
+ handler.Disconnect( 0, MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
+ handler.Disconnect( 0, 0, MyEventType, &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 );
+ handler.Connect( MyEventType, &MySink::OnMyEvent, NULL, &sink );
g_called.Reset();
handler.ProcessEvent(e);
CPPUNIT_ASSERT( g_called.method );
- handler.Disconnect( EVT_MYEVENT, &MySink::OnMyEvent, NULL, &sink );
+ handler.Disconnect( MyEventType, &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 );
+ wxEvtHandler::Connect( &handler, MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
+ wxEvtHandler::Connect( &handler, 0, MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
+ wxEvtHandler::Connect( &handler, 0, 0, MyEventType, &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 );
+ wxEvtHandler::Disconnect( &handler, MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
+ wxEvtHandler::Disconnect( &handler, 0, MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
+ wxEvtHandler::Disconnect( &handler, 0, 0, MyEventType, &MyHandler::OnMyEvent, NULL, &handler );
}
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, GlobalOnAnotherEvent);
- //IdleFunctor f; handler.Connect(EVT_MYEVENT, f);
- //handler.Connect(EVT_MYEVENT, &MyHandler::StaticOnAnotherEvent);
- //handler.Connect(EVT_MYEVENT, &MyHandler::OnAnotherEvent);
+ //handler.Connect(MyEventType, GlobalOnAnotherEvent);
+ //IdleFunctor f; handler.Connect(MyEventType, f);
+ //handler.Connect(MyEventType, &MyHandler::StaticOnAnotherEvent);
+ //handler.Connect(MyEventType, &MyHandler::OnAnotherEvent);
}
#endif // !wxEVENTS_COMPATIBILITY_2_8