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