]> git.saurik.com Git - wxWidgets.git/blame - tests/events/propagation.cpp
Consistently set wxMenuBar parent in all ports.
[wxWidgets.git] / tests / events / propagation.cpp
CommitLineData
1649d288
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: tests/events/propagation.cpp
3// Purpose: Test events propagation
4// Author: Vadim Zeitlin
5// Created: 2009-01-16
6// RCS-ID: $Id$
7// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
8///////////////////////////////////////////////////////////////////////////////
9
10// ----------------------------------------------------------------------------
11// headers
12// ----------------------------------------------------------------------------
13
14#include "testprec.h"
15
16#ifdef __BORLANDC__
17 #pragma hdrstop
18#endif
19
20#ifndef WX_PRECOMP
c21dcf80
VZ
21 #include "wx/app.h"
22 #include "wx/event.h"
ce45133e 23 #include "wx/scrolwin.h"
c21dcf80 24 #include "wx/window.h"
1649d288
VZ
25#endif // WX_PRECOMP
26
3bad8c39
VZ
27#include "wx/frame.h"
28#include "wx/menu.h"
29
1649d288
VZ
30#include "wx/scopeguard.h"
31
32namespace
33{
34
35// this string will record the execution of all handlers
36wxString g_str;
37
38// a custom event
39wxDEFINE_EVENT(TEST_EVT, wxCommandEvent);
40
ce45133e
VZ
41// a custom event handler tracing the propagation of the events of the
42// specified types
43template <class Event>
44class TestEvtHandlerBase : public wxEvtHandler
1649d288
VZ
45{
46public:
ce45133e
VZ
47 TestEvtHandlerBase(wxEventType evtType, char tag)
48 : m_evtType(evtType),
49 m_tag(tag)
1649d288 50 {
ce45133e
VZ
51 Connect(evtType,
52 static_cast<wxEventFunction>(&TestEvtHandlerBase::OnTest));
1649d288
VZ
53 }
54
55 // override ProcessEvent() to confirm that it is called for all event
56 // handlers in the chain
57 virtual bool ProcessEvent(wxEvent& event)
58 {
ce45133e 59 if ( event.GetEventType() == m_evtType )
1649d288
VZ
60 g_str += 'o'; // "o" == "overridden"
61
62 return wxEvtHandler::ProcessEvent(event);
63 }
64
65private:
ce45133e 66 void OnTest(wxEvent& event)
1649d288
VZ
67 {
68 g_str += m_tag;
69
70 event.Skip();
71 }
72
ce45133e 73 const wxEventType m_evtType;
1649d288
VZ
74 const char m_tag;
75
ce45133e
VZ
76 wxDECLARE_NO_COPY_TEMPLATE_CLASS(TestEvtHandlerBase, Event);
77};
78
79struct TestEvtHandler : TestEvtHandlerBase<wxCommandEvent>
80{
81 TestEvtHandler(char tag)
82 : TestEvtHandlerBase<wxCommandEvent>(TEST_EVT, tag)
83 {
84 }
85};
86
3bad8c39
VZ
87struct TestMenuEvtHandler : TestEvtHandlerBase<wxCommandEvent>
88{
89 TestMenuEvtHandler(char tag)
90 : TestEvtHandlerBase<wxCommandEvent>(wxEVT_MENU, tag)
91 {
92 }
93};
94
ce45133e
VZ
95struct TestPaintEvtHandler : TestEvtHandlerBase<wxPaintEvent>
96{
97 TestPaintEvtHandler(char tag)
98 : TestEvtHandlerBase<wxPaintEvent>(wxEVT_PAINT, tag)
99 {
100 }
1649d288
VZ
101};
102
103// a window handling the test event
104class TestWindow : public wxWindow
105{
106public:
107 TestWindow(wxWindow *parent, char tag)
108 : wxWindow(parent, wxID_ANY),
109 m_tag(tag)
110 {
111 Connect(TEST_EVT, wxCommandEventHandler(TestWindow::OnTest));
112 }
113
114private:
115 void OnTest(wxCommandEvent& event)
116 {
117 g_str += m_tag;
118
119 event.Skip();
120 }
121
122 const char m_tag;
123
124 DECLARE_NO_COPY_CLASS(TestWindow)
125};
126
ce45133e
VZ
127// a scroll window handling paint event: we want to have a special test case
128// for this because the event propagation is complicated even further than
129// usual here by the presence of wxScrollHelperEvtHandler in the event handlers
130// chain and the fact that OnDraw() virtual method must be called if EVT_PAINT
131// is not handled
132class TestScrollWindow : public wxScrolledWindow
133{
134public:
135 TestScrollWindow(wxWindow *parent)
136 : wxScrolledWindow(parent, wxID_ANY)
137 {
138 Connect(wxEVT_PAINT, wxPaintEventHandler(TestScrollWindow::OnPaint));
139 }
140
141 virtual void OnDraw(wxDC& WXUNUSED(dc))
142 {
143 g_str += 'D'; // draw
144 }
145
146private:
147 void OnPaint(wxPaintEvent& event)
148 {
149 g_str += 'P'; // paint
150 event.Skip();
151 }
152
153 wxDECLARE_NO_COPY_CLASS(TestScrollWindow);
154};
155
1649d288
VZ
156int DoFilterEvent(wxEvent& event)
157{
3bad8c39
VZ
158 if ( event.GetEventType() == TEST_EVT ||
159 event.GetEventType() == wxEVT_MENU )
1649d288
VZ
160 g_str += 'a';
161
162 return -1;
163}
164
165bool DoProcessEvent(wxEvent& event)
166{
3bad8c39
VZ
167 if ( event.GetEventType() == TEST_EVT ||
168 event.GetEventType() == wxEVT_MENU )
1649d288
VZ
169 g_str += 'A';
170
171 return false;
172}
173
174} // anonymous namespace
175
176// --------------------------------------------------------------------------
177// test class
178// --------------------------------------------------------------------------
179
180class EventPropagationTestCase : public CppUnit::TestCase
181{
182public:
183 EventPropagationTestCase() {}
184
185 virtual void setUp();
186 virtual void tearDown();
187
188private:
189 CPPUNIT_TEST_SUITE( EventPropagationTestCase );
190 CPPUNIT_TEST( OneHandler );
191 CPPUNIT_TEST( TwoHandlers );
192 CPPUNIT_TEST( WindowWithoutHandler );
193 CPPUNIT_TEST( WindowWithHandler );
bbdee10d 194 CPPUNIT_TEST( ForwardEvent );
ce45133e
VZ
195 CPPUNIT_TEST( ScrollWindowWithoutHandler );
196 CPPUNIT_TEST( ScrollWindowWithHandler );
3bad8c39 197 CPPUNIT_TEST( MenuEvent );
1649d288
VZ
198 CPPUNIT_TEST_SUITE_END();
199
200 void OneHandler();
201 void TwoHandlers();
202 void WindowWithoutHandler();
203 void WindowWithHandler();
bbdee10d 204 void ForwardEvent();
ce45133e
VZ
205 void ScrollWindowWithoutHandler();
206 void ScrollWindowWithHandler();
3bad8c39 207 void MenuEvent();
1649d288
VZ
208
209 DECLARE_NO_COPY_CLASS(EventPropagationTestCase)
210};
211
212// register in the unnamed registry so that these tests are run by default
213CPPUNIT_TEST_SUITE_REGISTRATION( EventPropagationTestCase );
214
e3778b4d 215// also include in its own registry so that these tests can be run alone
1649d288
VZ
216CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EventPropagationTestCase, "EventPropagationTestCase" );
217
218void EventPropagationTestCase::setUp()
219{
220 SetFilterEventFunc(DoFilterEvent);
221 SetProcessEventFunc(DoProcessEvent);
222
223 g_str.clear();
224}
225
226void EventPropagationTestCase::tearDown()
227{
228 SetFilterEventFunc(NULL);
229 SetProcessEventFunc(NULL);
230}
231
232void EventPropagationTestCase::OneHandler()
233{
234 wxCommandEvent event(TEST_EVT);
235 TestEvtHandler h1('1');
236 h1.ProcessEvent(event);
237 CPPUNIT_ASSERT_EQUAL( "oa1A", g_str );
238}
239
240void EventPropagationTestCase::TwoHandlers()
241{
242 wxCommandEvent event(TEST_EVT);
243 TestEvtHandler h1('1');
244 TestEvtHandler h2('2');
245 h1.SetNextHandler(&h2);
246 h2.SetPreviousHandler(&h1);
247 h1.ProcessEvent(event);
248 CPPUNIT_ASSERT_EQUAL( "oa1o2A", g_str );
249}
250
251void EventPropagationTestCase::WindowWithoutHandler()
252{
253 wxCommandEvent event(TEST_EVT);
254 TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
255 wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
256
257 TestWindow * const child = new TestWindow(parent, 'c');
258
004867db 259 child->GetEventHandler()->ProcessEvent(event);
1649d288
VZ
260 CPPUNIT_ASSERT_EQUAL( "acpA", g_str );
261}
262
263void EventPropagationTestCase::WindowWithHandler()
264{
265 wxCommandEvent event(TEST_EVT);
266 TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
267 wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
268
269 TestWindow * const child = new TestWindow(parent, 'c');
270
271 TestEvtHandler h1('1');
272 child->PushEventHandler(&h1);
9ebfc963 273 wxON_BLOCK_EXIT_OBJ1( *child, wxWindow::PopEventHandler, false );
1649d288
VZ
274 TestEvtHandler h2('2');
275 child->PushEventHandler(&h2);
9ebfc963 276 wxON_BLOCK_EXIT_OBJ1( *child, wxWindow::PopEventHandler, false );
1649d288
VZ
277
278 child->HandleWindowEvent(event);
279 CPPUNIT_ASSERT_EQUAL( "oa2o1cpA", g_str );
280}
281
bbdee10d
VZ
282void EventPropagationTestCase::ForwardEvent()
283{
284 // The idea of this test is to check that the events explicitly forwarded
285 // to another event handler still get pre/post-processed as usual as this
286 // used to be broken by the fixes trying to avoid duplicate processing.
287 TestWindow * const win = new TestWindow(wxTheApp->GetTopWindow(), 'w');
288 wxON_BLOCK_EXIT_OBJ0( *win, wxWindow::Destroy );
289
290 TestEvtHandler h1('1');
291 win->PushEventHandler(&h1);
292 wxON_BLOCK_EXIT_OBJ1( *win, wxWindow::PopEventHandler, false );
293
294 class ForwardEvtHandler : public wxEvtHandler
295 {
296 public:
297 ForwardEvtHandler(wxEvtHandler& h) : m_h(&h) { }
298
299 virtual bool ProcessEvent(wxEvent& event)
300 {
301 g_str += 'f';
302
303 return m_h->ProcessEvent(event);
304 }
305
306 private:
307 wxEvtHandler *m_h;
308 } f(h1);
309
310 // First send the event directly to f.
311 wxCommandEvent event1(TEST_EVT);
312 f.ProcessEvent(event1);
313 CPPUNIT_ASSERT_EQUAL( "foa1wA", g_str );
314 g_str.clear();
315
316 // And then also test sending it to f indirectly.
317 wxCommandEvent event2(TEST_EVT);
318 TestEvtHandler h2('2');
319 h2.SetNextHandler(&f);
320 h2.ProcessEvent(event2);
321 CPPUNIT_ASSERT_EQUAL( "oa2fo1wAA", g_str );
322}
323
ce45133e
VZ
324void EventPropagationTestCase::ScrollWindowWithoutHandler()
325{
52212bcb
VZ
326 TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
327 wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
328
329 TestScrollWindow * const win = new TestScrollWindow(parent);
ce45133e 330
33a190be 331#if !defined(__WXOSX__) && !defined(__WXGTK3__)
ce45133e
VZ
332 wxPaintEvent event(win->GetId());
333 win->ProcessWindowEvent(event);
334 CPPUNIT_ASSERT_EQUAL( "PD", g_str );
f009da6e 335#endif
52212bcb
VZ
336 g_str.clear();
337 wxCommandEvent eventCmd(TEST_EVT);
338 win->HandleWindowEvent(eventCmd);
339 CPPUNIT_ASSERT_EQUAL( "apA", g_str );
ce45133e
VZ
340}
341
342void EventPropagationTestCase::ScrollWindowWithHandler()
343{
52212bcb
VZ
344 TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
345 wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
346
347 TestScrollWindow * const win = new TestScrollWindow(parent);
ce45133e 348
33a190be 349#if !defined(__WXOSX__) && !defined(__WXGTK3__)
ce45133e
VZ
350 TestPaintEvtHandler h('h');
351 win->PushEventHandler(&h);
352 wxON_BLOCK_EXIT_OBJ1( *win, wxWindow::PopEventHandler, false );
353
354 wxPaintEvent event(win->GetId());
355 win->ProcessWindowEvent(event);
356 CPPUNIT_ASSERT_EQUAL( "ohPD", g_str );
15536294 357#endif
52212bcb
VZ
358
359 g_str.clear();
360 wxCommandEvent eventCmd(TEST_EVT);
361 win->HandleWindowEvent(eventCmd);
362 CPPUNIT_ASSERT_EQUAL( "apA", g_str );
ce45133e
VZ
363}
364
3bad8c39
VZ
365// Helper for checking that the menu event processing resulted in the expected
366// output from the handlers.
367void CheckMenuEvent(wxMenu* menu, const char* expected)
368{
369 g_str.clear();
370
371 // Trigger the menu event: this is more reliable than using
372 // wxUIActionSimulator and currently works in all ports as they all call
373 // wxMenuBase::SendEvent() from their respective menu event handlers.
374 menu->SendEvent(wxID_NEW);
375
376 CPPUNIT_ASSERT_EQUAL( expected, g_str );
377}
378
379void EventPropagationTestCase::MenuEvent()
380{
381 // Create a minimal menu bar.
382 wxMenu* const menu = new wxMenu;
383 menu->Append(wxID_NEW);
384 wxMenuBar* const mb = new wxMenuBar;
385 mb->Append(menu, "&Menu");
386
387 wxFrame* const frame = static_cast<wxFrame*>(wxTheApp->GetTopWindow());
388 frame->SetMenuBar(mb);
389 wxON_BLOCK_EXIT_OBJ1( *frame, wxFrame::SetMenuBar, (wxMenuBar*)NULL );
390
391 // Check that wxApp gets the event exactly once.
392 CheckMenuEvent( menu, "aA" );
393
394
395 // Check that the menu event handler is called.
396 TestMenuEvtHandler hm('m'); // 'm' for "menu"
397 menu->SetNextHandler(&hm);
398 wxON_BLOCK_EXIT_OBJ1( *menu,
399 wxEvtHandler::SetNextHandler, (wxEvtHandler*)NULL );
400 CheckMenuEvent( menu, "aomA" );
401
402
4ed3f4ab
VZ
403 // Test that the event handler associated with the menu bar gets the event.
404 TestMenuEvtHandler hb('b'); // 'b' for "menu Bar"
405 mb->PushEventHandler(&hb);
406 wxON_BLOCK_EXIT_OBJ1( *mb, wxWindow::PopEventHandler, false );
407
408 CheckMenuEvent( menu, "aomobA" );
409
410
3bad8c39
VZ
411 // Also test that the window to which the menu belongs gets the event.
412 TestMenuEvtHandler hw('w'); // 'w' for "Window"
413 frame->PushEventHandler(&hw);
414 wxON_BLOCK_EXIT_OBJ1( *frame, wxWindow::PopEventHandler, false );
415
4ed3f4ab 416 CheckMenuEvent( menu, "aomobowA" );
3bad8c39 417}