]> git.saurik.com Git - wxWidgets.git/blame - tests/events/evthandler.cpp
Implemented non-selection of content when setting focus via the keyboard.
[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
f3ff831f
VZ
83void GlobalOnAnotherEvent(AnotherEvent&);
84
85void GlobalOnIdle(wxIdleEvent&)
86{
87 g_called.function = true;
88}
89
90struct MyFunctor
b2238cc3 91{
9b3ff3c0 92 void operator()(MyEvent &) { g_called.functor = true; }
f3ff831f 93};
b2238cc3 94
f3ff831f
VZ
95struct IdleFunctor
96{
97 void operator()(wxIdleEvent &) { g_called.functor = true; }
b2238cc3
VZ
98};
99
b2238cc3
VZ
100class MyHandler : public wxEvtHandler
101{
9b3ff3c0 102public:
f3ff831f
VZ
103 static void StaticOnMyEvent(MyEvent &) { g_called.smethod = true; }
104 static void StaticOnAnotherEvent(AnotherEvent &);
105 static void StaticOnIdle(wxIdleEvent&) { g_called.smethod = true; }
106
9b3ff3c0 107 void OnMyEvent(MyEvent&) { g_called.method = true; }
f3ff831f
VZ
108 void OnEvent(wxEvent&) { g_called.method = true; }
109 void OnAnotherEvent(AnotherEvent&);
110 void OnIdle(wxIdleEvent&) { g_called.method = true; }
111};
b2238cc3 112
f3ff831f
VZ
113// we can also handle events in classes not deriving from wxEvtHandler
114struct MySink
115{
116 void OnMyEvent(MyEvent&) { g_called.method = true; }
a01ada05 117 void OnEvent(wxEvent&) { g_called.method = true; }
f3ff831f
VZ
118 void OnIdle(wxIdleEvent&) { g_called.method = true; }
119};
b2238cc3 120
f3ff831f
VZ
121// also test event table compilation
122class MyClassWithEventTable : public wxEvtHandler
123{
124public:
125 void OnMyEvent(MyEvent&) { g_called.method = true; }
126 void OnEvent(wxEvent&) { g_called.method = true; }
127 void OnAnotherEvent(AnotherEvent&);
128 void OnIdle(wxIdleEvent&) { g_called.method = true; }
129
130private:
131 DECLARE_EVENT_TABLE()
b2238cc3
VZ
132};
133
f3ff831f
VZ
134BEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler)
135 EVT_IDLE(MyClassWithEventTable::OnIdle)
136
a01ada05 137 EVT_MYEVENT(MyClassWithEventTable::OnMyEvent)
890d70eb 138#ifdef wxHAS_EVENT_BIND
a01ada05 139 EVT_MYEVENT(MyClassWithEventTable::OnEvent)
bb87b19b 140#endif
a01ada05 141
f3ff831f 142 // this shouldn't compile:
a01ada05 143 //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
f3ff831f
VZ
144 //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
145END_EVENT_TABLE()
146
9b3ff3c0
VZ
147} // anonymous namespace
148
f3ff831f
VZ
149
150// --------------------------------------------------------------------------
151// test class
152// --------------------------------------------------------------------------
153
154class EvtHandlerTestCase : public CppUnit::TestCase
b2238cc3 155{
f3ff831f
VZ
156public:
157 EvtHandlerTestCase() {}
158
159private:
160 CPPUNIT_TEST_SUITE( EvtHandlerTestCase );
161 CPPUNIT_TEST( BuiltinConnect );
162 CPPUNIT_TEST( LegacyConnect );
890d70eb 163#ifdef wxHAS_EVENT_BIND
5293e4b7
VZ
164 CPPUNIT_TEST( BindFunction );
165 CPPUNIT_TEST( BindStaticMethod );
166 CPPUNIT_TEST( BindFunctor );
167 CPPUNIT_TEST( BindMethod );
168 CPPUNIT_TEST( BindMethodUsingBaseEvent );
890d70eb 169 CPPUNIT_TEST( BindFunctionUsingBaseEvent );
5293e4b7
VZ
170 CPPUNIT_TEST( BindNonHandler );
171 CPPUNIT_TEST( InvalidBind );
890d70eb 172#endif // wxHAS_EVENT_BIND
f3ff831f
VZ
173 CPPUNIT_TEST_SUITE_END();
174
175 void BuiltinConnect();
176 void LegacyConnect();
890d70eb 177#ifdef wxHAS_EVENT_BIND
5293e4b7
VZ
178 void BindFunction();
179 void BindStaticMethod();
180 void BindFunctor();
181 void BindMethod();
182 void BindMethodUsingBaseEvent();
890d70eb 183 void BindFunctionUsingBaseEvent();
5293e4b7
VZ
184 void BindNonHandler();
185 void InvalidBind();
890d70eb 186#endif // wxHAS_EVENT_BIND
f3ff831f 187
b2238cc3 188
f3ff831f
VZ
189 // these member variables exceptionally don't use "m_" prefix because
190 // they're used so many times
b2238cc3 191 MyHandler handler;
9b3ff3c0 192 MyEvent e;
b2238cc3 193
f3ff831f
VZ
194 DECLARE_NO_COPY_CLASS(EvtHandlerTestCase)
195};
b2238cc3 196
f3ff831f
VZ
197// register in the unnamed registry so that these tests are run by default
198CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase );
199
e3778b4d 200// also include in its own registry so that these tests can be run alone
f3ff831f
VZ
201CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase, "EvtHandlerTestCase" );
202
203void EvtHandlerTestCase::BuiltinConnect()
204{
205 handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle));
206 handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle));
207
208 handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
209 handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
b2238cc3 210
a01ada05
VZ
211 // using casts like this is even uglier than using wxIdleEventHandler but
212 // it should still continue to work for compatibility
213 handler.Connect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle);
214 handler.Disconnect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle);
215
890d70eb 216#ifdef wxHAS_EVENT_BIND
5293e4b7
VZ
217 handler.Bind(wxEVT_IDLE, GlobalOnIdle);
218 handler.Unbind(wxEVT_IDLE, GlobalOnIdle);
b2238cc3 219
f3ff831f 220 IdleFunctor f;
5293e4b7
VZ
221 handler.Bind(wxEVT_IDLE, f);
222 handler.Unbind(wxEVT_IDLE, f);
b2238cc3 223
5293e4b7
VZ
224 handler.Bind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
225 handler.Unbind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
f3ff831f 226
5293e4b7
VZ
227 handler.Bind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
228 handler.Unbind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
890d70eb 229#endif // wxHAS_EVENT_BIND
f3ff831f
VZ
230}
231
232void EvtHandlerTestCase::LegacyConnect()
233{
a01ada05
VZ
234 handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
235 handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
236 handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
b2238cc3 237
a01ada05
VZ
238 handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
239 handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
240 handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
b2238cc3 241
f3ff831f 242
a01ada05
VZ
243 handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
244 handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
245 handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
f3ff831f 246
a01ada05
VZ
247 handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
248 handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
249 handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
f3ff831f 250}
b2238cc3 251
890d70eb 252#ifdef wxHAS_EVENT_BIND
f3ff831f 253
5293e4b7 254void EvtHandlerTestCase::BindFunction()
f3ff831f
VZ
255{
256 // function tests
5293e4b7 257 handler.Bind( MyEventType, GlobalOnMyEvent );
f3ff831f
VZ
258 g_called.Reset();
259 handler.ProcessEvent(e);
260 CPPUNIT_ASSERT( g_called.function );
5293e4b7 261 handler.Unbind( MyEventType, GlobalOnMyEvent );
f3ff831f
VZ
262 g_called.Reset();
263 handler.ProcessEvent(e);
264 CPPUNIT_ASSERT( !g_called.function ); // check that it was disconnected
265
5293e4b7
VZ
266 handler.Bind( MyEventType, GlobalOnMyEvent, 0 );
267 handler.Unbind( MyEventType, GlobalOnMyEvent, 0 );
f3ff831f 268
5293e4b7
VZ
269 handler.Bind( MyEventType, GlobalOnMyEvent, 0, 0 );
270 handler.Unbind( MyEventType, GlobalOnMyEvent, 0, 0 );
f3ff831f
VZ
271}
272
5293e4b7 273void EvtHandlerTestCase::BindStaticMethod()
f3ff831f
VZ
274{
275 // static method tests (this is same as functions but still test it just in
276 // case we hit some strange compiler bugs)
5293e4b7 277 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent );
9b3ff3c0
VZ
278 g_called.Reset();
279 handler.ProcessEvent(e);
280 CPPUNIT_ASSERT( g_called.smethod );
5293e4b7 281 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent );
9b3ff3c0
VZ
282 g_called.Reset();
283 handler.ProcessEvent(e);
f3ff831f 284 CPPUNIT_ASSERT( !g_called.smethod );
b2238cc3 285
5293e4b7
VZ
286 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
287 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
b2238cc3 288
5293e4b7
VZ
289 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
290 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
f3ff831f 291}
b2238cc3 292
5293e4b7 293void EvtHandlerTestCase::BindFunctor()
f3ff831f
VZ
294{
295 // generalized functor tests
296 MyFunctor functor;
b2238cc3 297
5293e4b7 298 handler.Bind( MyEventType, functor );
f3ff831f
VZ
299 g_called.Reset();
300 handler.ProcessEvent(e);
301 CPPUNIT_ASSERT( g_called.functor );
5293e4b7 302 handler.Unbind( MyEventType, functor );
f3ff831f
VZ
303 g_called.Reset();
304 handler.ProcessEvent(e);
305 CPPUNIT_ASSERT( !g_called.functor );
b2238cc3 306
5293e4b7
VZ
307 handler.Bind( MyEventType, functor, 0 );
308 handler.Unbind( MyEventType, functor, 0 );
f3ff831f 309
5293e4b7
VZ
310 handler.Bind( MyEventType, functor, 0, 0 );
311 handler.Unbind( MyEventType, functor, 0, 0 );
ca6911c3 312
09be3364
VZ
313 // test that a temporary functor is working as well and also test that
314 // unbinding a different (though equal) instance of the same functor does
315 // not work
316 MyFunctor func;
ca6911c3 317 handler.Bind( MyEventType, MyFunctor() );
09be3364 318 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func ));
ca6911c3
VZ
319
320 handler.Bind( MyEventType, MyFunctor(), 0 );
09be3364 321 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0 ));
ca6911c3
VZ
322
323 handler.Bind( MyEventType, MyFunctor(), 0, 0 );
09be3364 324 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0, 0 ));
f3ff831f 325}
b2238cc3 326
5293e4b7 327void EvtHandlerTestCase::BindMethod()
f3ff831f
VZ
328{
329 // class method tests
5293e4b7 330 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler );
a01ada05
VZ
331 g_called.Reset();
332 handler.ProcessEvent(e);
333 CPPUNIT_ASSERT( g_called.method );
5293e4b7 334 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler );
a01ada05
VZ
335 g_called.Reset();
336 handler.ProcessEvent(e);
337 CPPUNIT_ASSERT( !g_called.method );
338
5293e4b7
VZ
339 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
340 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
a01ada05 341
5293e4b7
VZ
342 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
343 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
a01ada05
VZ
344}
345
5293e4b7 346void EvtHandlerTestCase::BindMethodUsingBaseEvent()
a01ada05
VZ
347{
348 // test connecting a method taking just wxEvent and not MyEvent: this
349 // should work too if we don't need any MyEvent-specific information in the
350 // handler
5293e4b7 351 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler );
f3ff831f
VZ
352 g_called.Reset();
353 handler.ProcessEvent(e);
354 CPPUNIT_ASSERT( g_called.method );
5293e4b7 355 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler );
f3ff831f
VZ
356 g_called.Reset();
357 handler.ProcessEvent(e);
358 CPPUNIT_ASSERT( !g_called.method );
b2238cc3 359
5293e4b7
VZ
360 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
361 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
b2238cc3 362
5293e4b7
VZ
363 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
364 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
f3ff831f 365}
b2238cc3 366
f3ff831f 367
890d70eb
VZ
368void EvtHandlerTestCase::BindFunctionUsingBaseEvent()
369{
370 // test connecting a function taking just wxEvent and not MyEvent: this
371 // should work too if we don't need any MyEvent-specific information in the
372 // handler
373 handler.Bind( MyEventType, GlobalOnEvent );
374 g_called.Reset();
375 handler.ProcessEvent(e);
376 CPPUNIT_ASSERT( g_called.function );
377 handler.Unbind( MyEventType, GlobalOnEvent );
378 g_called.Reset();
379 handler.ProcessEvent(e);
380 CPPUNIT_ASSERT( !g_called.function );
381
382 handler.Bind( MyEventType, GlobalOnEvent, 0 );
383 handler.Unbind( MyEventType, GlobalOnEvent, 0 );
384
385 handler.Bind( MyEventType, GlobalOnEvent, 0, 0 );
386 handler.Unbind( MyEventType, GlobalOnEvent, 0, 0 );
387}
388
389
390
5293e4b7 391void EvtHandlerTestCase::BindNonHandler()
f3ff831f
VZ
392{
393 // class method tests for class not derived from wxEvtHandler
394 MySink sink;
b2238cc3 395
5293e4b7 396 handler.Bind( MyEventType, &MySink::OnMyEvent, &sink );
f3ff831f
VZ
397 g_called.Reset();
398 handler.ProcessEvent(e);
399 CPPUNIT_ASSERT( g_called.method );
5293e4b7 400 handler.Unbind( MyEventType, &MySink::OnMyEvent, &sink );
f3ff831f
VZ
401 g_called.Reset();
402 handler.ProcessEvent(e);
403 CPPUNIT_ASSERT( !g_called.method );
404}
b2238cc3 405
5293e4b7 406void EvtHandlerTestCase::InvalidBind()
f3ff831f 407{
9b3ff3c0
VZ
408 // these calls shouldn't compile but we unfortunately can't check this
409 // automatically, you need to uncomment them manually and test that
410 // compilation does indeed fail
5293e4b7 411
449cb073
VZ
412 // connecting a handler with incompatible signature shouldn't work
413#ifdef TEST_INVALID_BIND_GLOBAL
414 handler.Bind(MyEventType, GlobalOnAnotherEvent);
415#endif
416#ifdef TEST_INVALID_BIND_STATIC
417 handler.Bind(MyEventType, &MyHandler::StaticOnAnotherEvent);
418#endif
419#ifdef TEST_INVALID_BIND_METHOD
420 handler.Bind(MyEventType, &MyHandler::OnAnotherEvent, &handler);
421#endif
422#ifdef TEST_INVALID_BIND_FUNCTOR
423 IdleFunctor f;
424 handler.Bind(MyEventType, f);
425#endif
426
48c56e04
VZ
427 // the handler can't be omitted when calling Bind()
428#ifdef TEST_INVALID_BIND_NO_HANDLER
429 handler.Bind(MyEventType, &MyHandler::OnMyEvent);
430#endif
431
449cb073
VZ
432 // calling a derived class method with a base class pointer must not work
433#ifdef TEST_INVALID_BIND_DERIVED
434 struct C1 : wxEvtHandler { };
435 struct C2 : wxEvtHandler { void OnWhatever(wxEvent&); };
436 C1 c1;
437 c1.Bind(&C2::OnWhatever);
438#endif
439
440 // using object pointer incompatible with the method must not work
441#ifdef TEST_INVALID_BIND_WRONG_CLASS
442 MySink mySink;
443 MyHandler myHandler;
444 myHandler.Bind(MyEventType, &MyHandler::OnMyEvent, &mySink);
445#endif
b2238cc3
VZ
446}
447
890d70eb 448#endif // wxHAS_EVENT_BIND