]> git.saurik.com Git - wxWidgets.git/blame - tests/events/evthandler.cpp
wiring OnInit on osx to a later point in event processing
[wxWidgets.git] / tests / events / evthandler.cpp
CommitLineData
b2238cc3
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: tests/events/evthandler.cpp
3// Purpose: Test the new event types and wxEvtHandler-methods
4// Author: Peter Most
5// Created: 2009-01-24
6// RCS-ID: $Id$
7// Copyright: (c) 2009 Peter Most
8///////////////////////////////////////////////////////////////////////////////
9
10// ----------------------------------------------------------------------------
11// headers
12// ----------------------------------------------------------------------------
13
14#include "testprec.h"
15
16#ifdef __BORLANDC__
17 #pragma hdrstop
18#endif
19
b2238cc3
VZ
20#include "wx/event.h"
21
f3ff831f
VZ
22// ----------------------------------------------------------------------------
23// test events and their handlers
24// ----------------------------------------------------------------------------
b2238cc3 25
a01ada05 26const wxEventType LegacyEventType = wxNewEventType();
b2238cc3 27
9b3ff3c0 28class MyEvent;
16be58c1 29wxDEFINE_EVENT(MyEventType, MyEvent);
9b3ff3c0 30
b2238cc3
VZ
31class MyEvent : public wxEvent
32{
9b3ff3c0 33public:
a01ada05 34 MyEvent() : wxEvent(0, MyEventType) { }
9b3ff3c0
VZ
35
36 virtual wxEvent *Clone() const { return new MyEvent; }
b2238cc3
VZ
37};
38
bb87b19b 39typedef void (wxEvtHandler::*MyEventFunction)(MyEvent&);
890d70eb 40#ifndef wxHAS_EVENT_BIND
5293e4b7
VZ
41 #define MyEventHandler(func) wxEVENT_HANDLER_CAST(MyEventFunction, func)
42#else
43 #define MyEventHandler(func) &func
44#endif
bb87b19b
VZ
45#define EVT_MYEVENT(func) \
46 wx__DECLARE_EVT0(MyEventType, MyEventHandler(func))
a01ada05 47
9b3ff3c0
VZ
48class AnotherEvent : public wxEvent
49{
50};
b2238cc3 51
9b3ff3c0
VZ
52namespace
53{
54
55struct Called
56{
57 Called() { Reset(); }
58
59 void Reset()
60 {
61 function =
62 functor =
63 method =
64 smethod = false;
65 }
66
67 bool function,
68 functor,
69 method,
70 smethod;
71} g_called;
72
73void GlobalOnMyEvent(MyEvent&)
74{
75 g_called.function = true;
76}
b2238cc3 77
890d70eb
VZ
78void GlobalOnEvent(wxEvent&)
79{
80 g_called.function = true;
81}
82
1ed753dc 83#ifdef TEST_INVALID_BIND_GLOBAL
f3ff831f 84void GlobalOnAnotherEvent(AnotherEvent&);
1ed753dc 85#endif
f3ff831f
VZ
86
87void GlobalOnIdle(wxIdleEvent&)
88{
89 g_called.function = true;
90}
91
92struct MyFunctor
b2238cc3 93{
9b3ff3c0 94 void operator()(MyEvent &) { g_called.functor = true; }
f3ff831f 95};
b2238cc3 96
f3ff831f
VZ
97struct IdleFunctor
98{
99 void operator()(wxIdleEvent &) { g_called.functor = true; }
b2238cc3
VZ
100};
101
b2238cc3
VZ
102class MyHandler : public wxEvtHandler
103{
9b3ff3c0 104public:
f3ff831f
VZ
105 static void StaticOnMyEvent(MyEvent &) { g_called.smethod = true; }
106 static void StaticOnAnotherEvent(AnotherEvent &);
107 static void StaticOnIdle(wxIdleEvent&) { g_called.smethod = true; }
108
9b3ff3c0 109 void OnMyEvent(MyEvent&) { g_called.method = true; }
f3ff831f
VZ
110 void OnEvent(wxEvent&) { g_called.method = true; }
111 void OnAnotherEvent(AnotherEvent&);
112 void OnIdle(wxIdleEvent&) { g_called.method = true; }
113};
b2238cc3 114
f3ff831f
VZ
115// we can also handle events in classes not deriving from wxEvtHandler
116struct MySink
117{
118 void OnMyEvent(MyEvent&) { g_called.method = true; }
a01ada05 119 void OnEvent(wxEvent&) { g_called.method = true; }
f3ff831f
VZ
120 void OnIdle(wxIdleEvent&) { g_called.method = true; }
121};
b2238cc3 122
f3ff831f
VZ
123// also test event table compilation
124class MyClassWithEventTable : public wxEvtHandler
125{
126public:
127 void OnMyEvent(MyEvent&) { g_called.method = true; }
128 void OnEvent(wxEvent&) { g_called.method = true; }
129 void OnAnotherEvent(AnotherEvent&);
130 void OnIdle(wxIdleEvent&) { g_called.method = true; }
131
132private:
133 DECLARE_EVENT_TABLE()
b2238cc3
VZ
134};
135
f3ff831f
VZ
136BEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler)
137 EVT_IDLE(MyClassWithEventTable::OnIdle)
138
a01ada05 139 EVT_MYEVENT(MyClassWithEventTable::OnMyEvent)
890d70eb 140#ifdef wxHAS_EVENT_BIND
a01ada05 141 EVT_MYEVENT(MyClassWithEventTable::OnEvent)
bb87b19b 142#endif
a01ada05 143
f3ff831f 144 // this shouldn't compile:
a01ada05 145 //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
f3ff831f
VZ
146 //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
147END_EVENT_TABLE()
148
9b3ff3c0
VZ
149} // anonymous namespace
150
f3ff831f
VZ
151
152// --------------------------------------------------------------------------
153// test class
154// --------------------------------------------------------------------------
155
156class EvtHandlerTestCase : public CppUnit::TestCase
b2238cc3 157{
f3ff831f
VZ
158public:
159 EvtHandlerTestCase() {}
160
161private:
162 CPPUNIT_TEST_SUITE( EvtHandlerTestCase );
163 CPPUNIT_TEST( BuiltinConnect );
164 CPPUNIT_TEST( LegacyConnect );
75b2220e
VZ
165 CPPUNIT_TEST( DisconnectWildcard );
166 CPPUNIT_TEST( AutoDisconnect );
890d70eb 167#ifdef wxHAS_EVENT_BIND
5293e4b7
VZ
168 CPPUNIT_TEST( BindFunction );
169 CPPUNIT_TEST( BindStaticMethod );
170 CPPUNIT_TEST( BindFunctor );
171 CPPUNIT_TEST( BindMethod );
172 CPPUNIT_TEST( BindMethodUsingBaseEvent );
890d70eb 173 CPPUNIT_TEST( BindFunctionUsingBaseEvent );
5293e4b7
VZ
174 CPPUNIT_TEST( BindNonHandler );
175 CPPUNIT_TEST( InvalidBind );
890d70eb 176#endif // wxHAS_EVENT_BIND
f3ff831f
VZ
177 CPPUNIT_TEST_SUITE_END();
178
179 void BuiltinConnect();
180 void LegacyConnect();
75b2220e
VZ
181 void DisconnectWildcard();
182 void AutoDisconnect();
890d70eb 183#ifdef wxHAS_EVENT_BIND
5293e4b7
VZ
184 void BindFunction();
185 void BindStaticMethod();
186 void BindFunctor();
187 void BindMethod();
188 void BindMethodUsingBaseEvent();
890d70eb 189 void BindFunctionUsingBaseEvent();
5293e4b7
VZ
190 void BindNonHandler();
191 void InvalidBind();
890d70eb 192#endif // wxHAS_EVENT_BIND
f3ff831f 193
b2238cc3 194
f3ff831f
VZ
195 // these member variables exceptionally don't use "m_" prefix because
196 // they're used so many times
b2238cc3 197 MyHandler handler;
9b3ff3c0 198 MyEvent e;
b2238cc3 199
f3ff831f
VZ
200 DECLARE_NO_COPY_CLASS(EvtHandlerTestCase)
201};
b2238cc3 202
f3ff831f
VZ
203// register in the unnamed registry so that these tests are run by default
204CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase );
205
e3778b4d 206// also include in its own registry so that these tests can be run alone
f3ff831f
VZ
207CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase, "EvtHandlerTestCase" );
208
209void EvtHandlerTestCase::BuiltinConnect()
210{
211 handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle));
212 handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle));
213
214 handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
215 handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
b2238cc3 216
a01ada05
VZ
217 // using casts like this is even uglier than using wxIdleEventHandler but
218 // it should still continue to work for compatibility
219 handler.Connect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle);
220 handler.Disconnect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle);
221
890d70eb 222#ifdef wxHAS_EVENT_BIND
5293e4b7
VZ
223 handler.Bind(wxEVT_IDLE, GlobalOnIdle);
224 handler.Unbind(wxEVT_IDLE, GlobalOnIdle);
b2238cc3 225
f3ff831f 226 IdleFunctor f;
5293e4b7
VZ
227 handler.Bind(wxEVT_IDLE, f);
228 handler.Unbind(wxEVT_IDLE, f);
b2238cc3 229
5293e4b7
VZ
230 handler.Bind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
231 handler.Unbind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
f3ff831f 232
5293e4b7
VZ
233 handler.Bind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
234 handler.Unbind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
890d70eb 235#endif // wxHAS_EVENT_BIND
f3ff831f
VZ
236}
237
238void EvtHandlerTestCase::LegacyConnect()
239{
a01ada05
VZ
240 handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
241 handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
242 handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
b2238cc3 243
a01ada05
VZ
244 handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
245 handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
246 handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
b2238cc3 247
f3ff831f 248
a01ada05
VZ
249 handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
250 handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
251 handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
f3ff831f 252
a01ada05
VZ
253 handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
254 handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
255 handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
f3ff831f 256}
b2238cc3 257
75b2220e
VZ
258void EvtHandlerTestCase::DisconnectWildcard()
259{
260 // should be able to disconnect a different handler using "wildcard search"
261 MyHandler sink;
262 wxEvtHandler source;
263 source.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink);
264 CPPUNIT_ASSERT(source.Disconnect(wxID_ANY, wxEVT_IDLE));
265 // destruction of source and sink here should properly clean up the
266 // wxEventConnectionRef without crashing
267}
268
269void EvtHandlerTestCase::AutoDisconnect()
270{
271 wxEvtHandler source;
272 {
273 MyHandler sink;
274 source.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink);
275 // mismatched event type, so nothing should be disconnected
276 CPPUNIT_ASSERT(!source.Disconnect(wxEVT_THREAD, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink));
277 }
278 // destruction of sink should have automatically disconnected it, so
279 // there should be nothing to disconnect anymore
280 CPPUNIT_ASSERT(!source.Disconnect(wxID_ANY, wxEVT_IDLE));
281}
282
890d70eb 283#ifdef wxHAS_EVENT_BIND
f3ff831f 284
5293e4b7 285void EvtHandlerTestCase::BindFunction()
f3ff831f
VZ
286{
287 // function tests
5293e4b7 288 handler.Bind( MyEventType, GlobalOnMyEvent );
f3ff831f
VZ
289 g_called.Reset();
290 handler.ProcessEvent(e);
291 CPPUNIT_ASSERT( g_called.function );
5293e4b7 292 handler.Unbind( MyEventType, GlobalOnMyEvent );
f3ff831f
VZ
293 g_called.Reset();
294 handler.ProcessEvent(e);
295 CPPUNIT_ASSERT( !g_called.function ); // check that it was disconnected
296
5293e4b7
VZ
297 handler.Bind( MyEventType, GlobalOnMyEvent, 0 );
298 handler.Unbind( MyEventType, GlobalOnMyEvent, 0 );
f3ff831f 299
5293e4b7
VZ
300 handler.Bind( MyEventType, GlobalOnMyEvent, 0, 0 );
301 handler.Unbind( MyEventType, GlobalOnMyEvent, 0, 0 );
f3ff831f
VZ
302}
303
5293e4b7 304void EvtHandlerTestCase::BindStaticMethod()
f3ff831f
VZ
305{
306 // static method tests (this is same as functions but still test it just in
307 // case we hit some strange compiler bugs)
5293e4b7 308 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent );
9b3ff3c0
VZ
309 g_called.Reset();
310 handler.ProcessEvent(e);
311 CPPUNIT_ASSERT( g_called.smethod );
5293e4b7 312 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent );
9b3ff3c0
VZ
313 g_called.Reset();
314 handler.ProcessEvent(e);
f3ff831f 315 CPPUNIT_ASSERT( !g_called.smethod );
b2238cc3 316
5293e4b7
VZ
317 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
318 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
b2238cc3 319
5293e4b7
VZ
320 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
321 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
f3ff831f 322}
b2238cc3 323
5293e4b7 324void EvtHandlerTestCase::BindFunctor()
f3ff831f
VZ
325{
326 // generalized functor tests
327 MyFunctor functor;
b2238cc3 328
5293e4b7 329 handler.Bind( MyEventType, functor );
f3ff831f
VZ
330 g_called.Reset();
331 handler.ProcessEvent(e);
332 CPPUNIT_ASSERT( g_called.functor );
5293e4b7 333 handler.Unbind( MyEventType, functor );
f3ff831f
VZ
334 g_called.Reset();
335 handler.ProcessEvent(e);
336 CPPUNIT_ASSERT( !g_called.functor );
b2238cc3 337
5293e4b7
VZ
338 handler.Bind( MyEventType, functor, 0 );
339 handler.Unbind( MyEventType, functor, 0 );
f3ff831f 340
5293e4b7
VZ
341 handler.Bind( MyEventType, functor, 0, 0 );
342 handler.Unbind( MyEventType, functor, 0, 0 );
ca6911c3 343
09be3364
VZ
344 // test that a temporary functor is working as well and also test that
345 // unbinding a different (though equal) instance of the same functor does
346 // not work
347 MyFunctor func;
ca6911c3 348 handler.Bind( MyEventType, MyFunctor() );
09be3364 349 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func ));
ca6911c3
VZ
350
351 handler.Bind( MyEventType, MyFunctor(), 0 );
09be3364 352 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0 ));
ca6911c3
VZ
353
354 handler.Bind( MyEventType, MyFunctor(), 0, 0 );
09be3364 355 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0, 0 ));
f3ff831f 356}
b2238cc3 357
5293e4b7 358void EvtHandlerTestCase::BindMethod()
f3ff831f
VZ
359{
360 // class method tests
5293e4b7 361 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler );
a01ada05
VZ
362 g_called.Reset();
363 handler.ProcessEvent(e);
364 CPPUNIT_ASSERT( g_called.method );
5293e4b7 365 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler );
a01ada05
VZ
366 g_called.Reset();
367 handler.ProcessEvent(e);
368 CPPUNIT_ASSERT( !g_called.method );
369
5293e4b7
VZ
370 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
371 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
a01ada05 372
5293e4b7
VZ
373 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
374 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
a01ada05
VZ
375}
376
5293e4b7 377void EvtHandlerTestCase::BindMethodUsingBaseEvent()
a01ada05
VZ
378{
379 // test connecting a method taking just wxEvent and not MyEvent: this
380 // should work too if we don't need any MyEvent-specific information in the
381 // handler
5293e4b7 382 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler );
f3ff831f
VZ
383 g_called.Reset();
384 handler.ProcessEvent(e);
385 CPPUNIT_ASSERT( g_called.method );
5293e4b7 386 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler );
f3ff831f
VZ
387 g_called.Reset();
388 handler.ProcessEvent(e);
389 CPPUNIT_ASSERT( !g_called.method );
b2238cc3 390
5293e4b7
VZ
391 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
392 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
b2238cc3 393
5293e4b7
VZ
394 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
395 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
f3ff831f 396}
b2238cc3 397
f3ff831f 398
890d70eb
VZ
399void EvtHandlerTestCase::BindFunctionUsingBaseEvent()
400{
401 // test connecting a function taking just wxEvent and not MyEvent: this
402 // should work too if we don't need any MyEvent-specific information in the
403 // handler
404 handler.Bind( MyEventType, GlobalOnEvent );
405 g_called.Reset();
406 handler.ProcessEvent(e);
407 CPPUNIT_ASSERT( g_called.function );
408 handler.Unbind( MyEventType, GlobalOnEvent );
409 g_called.Reset();
410 handler.ProcessEvent(e);
411 CPPUNIT_ASSERT( !g_called.function );
412
413 handler.Bind( MyEventType, GlobalOnEvent, 0 );
414 handler.Unbind( MyEventType, GlobalOnEvent, 0 );
415
416 handler.Bind( MyEventType, GlobalOnEvent, 0, 0 );
417 handler.Unbind( MyEventType, GlobalOnEvent, 0, 0 );
418}
419
420
421
5293e4b7 422void EvtHandlerTestCase::BindNonHandler()
f3ff831f
VZ
423{
424 // class method tests for class not derived from wxEvtHandler
425 MySink sink;
b2238cc3 426
5293e4b7 427 handler.Bind( MyEventType, &MySink::OnMyEvent, &sink );
f3ff831f
VZ
428 g_called.Reset();
429 handler.ProcessEvent(e);
430 CPPUNIT_ASSERT( g_called.method );
5293e4b7 431 handler.Unbind( MyEventType, &MySink::OnMyEvent, &sink );
f3ff831f
VZ
432 g_called.Reset();
433 handler.ProcessEvent(e);
434 CPPUNIT_ASSERT( !g_called.method );
435}
b2238cc3 436
5293e4b7 437void EvtHandlerTestCase::InvalidBind()
f3ff831f 438{
9b3ff3c0
VZ
439 // these calls shouldn't compile but we unfortunately can't check this
440 // automatically, you need to uncomment them manually and test that
441 // compilation does indeed fail
5293e4b7 442
449cb073
VZ
443 // connecting a handler with incompatible signature shouldn't work
444#ifdef TEST_INVALID_BIND_GLOBAL
445 handler.Bind(MyEventType, GlobalOnAnotherEvent);
446#endif
447#ifdef TEST_INVALID_BIND_STATIC
448 handler.Bind(MyEventType, &MyHandler::StaticOnAnotherEvent);
449#endif
450#ifdef TEST_INVALID_BIND_METHOD
451 handler.Bind(MyEventType, &MyHandler::OnAnotherEvent, &handler);
452#endif
453#ifdef TEST_INVALID_BIND_FUNCTOR
454 IdleFunctor f;
455 handler.Bind(MyEventType, f);
456#endif
457
48c56e04
VZ
458 // the handler can't be omitted when calling Bind()
459#ifdef TEST_INVALID_BIND_NO_HANDLER
460 handler.Bind(MyEventType, &MyHandler::OnMyEvent);
461#endif
462
449cb073
VZ
463 // calling a derived class method with a base class pointer must not work
464#ifdef TEST_INVALID_BIND_DERIVED
465 struct C1 : wxEvtHandler { };
466 struct C2 : wxEvtHandler { void OnWhatever(wxEvent&); };
467 C1 c1;
468 c1.Bind(&C2::OnWhatever);
469#endif
470
471 // using object pointer incompatible with the method must not work
472#ifdef TEST_INVALID_BIND_WRONG_CLASS
473 MySink mySink;
474 MyHandler myHandler;
475 myHandler.Bind(MyEventType, &MyHandler::OnMyEvent, &mySink);
476#endif
b2238cc3
VZ
477}
478
890d70eb 479#endif // wxHAS_EVENT_BIND