]>
Commit | Line | Data |
---|---|---|
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 | ||
a7c0de8a | 27 | #include "wx/docmdi.h" |
3bad8c39 VZ |
28 | #include "wx/frame.h" |
29 | #include "wx/menu.h" | |
bbde2164 | 30 | #include "wx/scopedptr.h" |
1649d288 VZ |
31 | #include "wx/scopeguard.h" |
32 | ||
23366691 VZ |
33 | // FIXME: Currently under OS X testing paint event doesn't work because neither |
34 | // calling Refresh()+Update() nor even sending wxPaintEvent directly to | |
35 | // the window doesn't result in calls to its event handlers, so disable | |
36 | // some tests there. But this should be fixed and the tests reenabled | |
37 | // because wxPaintEvent propagation in wxScrolledWindow is a perfect | |
38 | // example of fragile code that could be broken under OS X. | |
39 | #ifndef __WXOSX__ | |
40 | #define CAN_TEST_PAINT_EVENTS | |
41 | #endif | |
42 | ||
1649d288 VZ |
43 | namespace |
44 | { | |
45 | ||
46 | // this string will record the execution of all handlers | |
47 | wxString g_str; | |
48 | ||
49 | // a custom event | |
50 | wxDEFINE_EVENT(TEST_EVT, wxCommandEvent); | |
51 | ||
ce45133e VZ |
52 | // a custom event handler tracing the propagation of the events of the |
53 | // specified types | |
54 | template <class Event> | |
55 | class TestEvtHandlerBase : public wxEvtHandler | |
1649d288 VZ |
56 | { |
57 | public: | |
ce45133e VZ |
58 | TestEvtHandlerBase(wxEventType evtType, char tag) |
59 | : m_evtType(evtType), | |
60 | m_tag(tag) | |
1649d288 | 61 | { |
ce45133e VZ |
62 | Connect(evtType, |
63 | static_cast<wxEventFunction>(&TestEvtHandlerBase::OnTest)); | |
1649d288 VZ |
64 | } |
65 | ||
66 | // override ProcessEvent() to confirm that it is called for all event | |
67 | // handlers in the chain | |
68 | virtual bool ProcessEvent(wxEvent& event) | |
69 | { | |
ce45133e | 70 | if ( event.GetEventType() == m_evtType ) |
1649d288 VZ |
71 | g_str += 'o'; // "o" == "overridden" |
72 | ||
73 | return wxEvtHandler::ProcessEvent(event); | |
74 | } | |
75 | ||
76 | private: | |
ce45133e | 77 | void OnTest(wxEvent& event) |
1649d288 VZ |
78 | { |
79 | g_str += m_tag; | |
80 | ||
81 | event.Skip(); | |
82 | } | |
83 | ||
ce45133e | 84 | const wxEventType m_evtType; |
1649d288 VZ |
85 | const char m_tag; |
86 | ||
ce45133e VZ |
87 | wxDECLARE_NO_COPY_TEMPLATE_CLASS(TestEvtHandlerBase, Event); |
88 | }; | |
89 | ||
90 | struct TestEvtHandler : TestEvtHandlerBase<wxCommandEvent> | |
91 | { | |
92 | TestEvtHandler(char tag) | |
93 | : TestEvtHandlerBase<wxCommandEvent>(TEST_EVT, tag) | |
94 | { | |
95 | } | |
96 | }; | |
97 | ||
3bad8c39 VZ |
98 | struct TestMenuEvtHandler : TestEvtHandlerBase<wxCommandEvent> |
99 | { | |
100 | TestMenuEvtHandler(char tag) | |
101 | : TestEvtHandlerBase<wxCommandEvent>(wxEVT_MENU, tag) | |
102 | { | |
103 | } | |
104 | }; | |
105 | ||
ce45133e VZ |
106 | struct TestPaintEvtHandler : TestEvtHandlerBase<wxPaintEvent> |
107 | { | |
108 | TestPaintEvtHandler(char tag) | |
109 | : TestEvtHandlerBase<wxPaintEvent>(wxEVT_PAINT, tag) | |
110 | { | |
111 | } | |
1649d288 VZ |
112 | }; |
113 | ||
a7c0de8a VZ |
114 | // Another custom event handler, suitable for use with Connect(). |
115 | struct TestEvtSink : wxEvtHandler | |
116 | { | |
117 | TestEvtSink(char tag) | |
118 | : m_tag(tag) | |
119 | { | |
120 | } | |
121 | ||
122 | void Handle(wxEvent& event) | |
123 | { | |
124 | g_str += m_tag; | |
125 | ||
126 | event.Skip(); | |
127 | } | |
128 | ||
129 | const char m_tag; | |
130 | ||
131 | wxDECLARE_NO_COPY_CLASS(TestEvtSink); | |
132 | }; | |
133 | ||
1649d288 VZ |
134 | // a window handling the test event |
135 | class TestWindow : public wxWindow | |
136 | { | |
137 | public: | |
138 | TestWindow(wxWindow *parent, char tag) | |
139 | : wxWindow(parent, wxID_ANY), | |
140 | m_tag(tag) | |
141 | { | |
142 | Connect(TEST_EVT, wxCommandEventHandler(TestWindow::OnTest)); | |
143 | } | |
144 | ||
145 | private: | |
146 | void OnTest(wxCommandEvent& event) | |
147 | { | |
148 | g_str += m_tag; | |
149 | ||
150 | event.Skip(); | |
151 | } | |
152 | ||
153 | const char m_tag; | |
154 | ||
155 | DECLARE_NO_COPY_CLASS(TestWindow) | |
156 | }; | |
157 | ||
ce45133e VZ |
158 | // a scroll window handling paint event: we want to have a special test case |
159 | // for this because the event propagation is complicated even further than | |
160 | // usual here by the presence of wxScrollHelperEvtHandler in the event handlers | |
161 | // chain and the fact that OnDraw() virtual method must be called if EVT_PAINT | |
162 | // is not handled | |
163 | class TestScrollWindow : public wxScrolledWindow | |
164 | { | |
165 | public: | |
166 | TestScrollWindow(wxWindow *parent) | |
167 | : wxScrolledWindow(parent, wxID_ANY) | |
168 | { | |
169 | Connect(wxEVT_PAINT, wxPaintEventHandler(TestScrollWindow::OnPaint)); | |
170 | } | |
171 | ||
23366691 VZ |
172 | void GeneratePaintEvent() |
173 | { | |
174 | #ifdef __WXGTK__ | |
175 | // We need to map the window, otherwise we're not going to get any | |
176 | // paint events for it. | |
177 | wxYield(); | |
178 | ||
179 | // Ignore events generated during the initial mapping. | |
180 | g_str.clear(); | |
181 | #endif // __WXGTK__ | |
182 | ||
183 | Refresh(); | |
184 | Update(); | |
185 | } | |
186 | ||
ce45133e VZ |
187 | virtual void OnDraw(wxDC& WXUNUSED(dc)) |
188 | { | |
189 | g_str += 'D'; // draw | |
190 | } | |
191 | ||
192 | private: | |
193 | void OnPaint(wxPaintEvent& event) | |
194 | { | |
195 | g_str += 'P'; // paint | |
196 | event.Skip(); | |
197 | } | |
198 | ||
199 | wxDECLARE_NO_COPY_CLASS(TestScrollWindow); | |
200 | }; | |
201 | ||
1649d288 VZ |
202 | int DoFilterEvent(wxEvent& event) |
203 | { | |
3bad8c39 VZ |
204 | if ( event.GetEventType() == TEST_EVT || |
205 | event.GetEventType() == wxEVT_MENU ) | |
1649d288 VZ |
206 | g_str += 'a'; |
207 | ||
208 | return -1; | |
209 | } | |
210 | ||
211 | bool DoProcessEvent(wxEvent& event) | |
212 | { | |
3bad8c39 VZ |
213 | if ( event.GetEventType() == TEST_EVT || |
214 | event.GetEventType() == wxEVT_MENU ) | |
1649d288 VZ |
215 | g_str += 'A'; |
216 | ||
217 | return false; | |
218 | } | |
219 | ||
220 | } // anonymous namespace | |
221 | ||
222 | // -------------------------------------------------------------------------- | |
223 | // test class | |
224 | // -------------------------------------------------------------------------- | |
225 | ||
226 | class EventPropagationTestCase : public CppUnit::TestCase | |
227 | { | |
228 | public: | |
229 | EventPropagationTestCase() {} | |
230 | ||
231 | virtual void setUp(); | |
232 | virtual void tearDown(); | |
233 | ||
234 | private: | |
235 | CPPUNIT_TEST_SUITE( EventPropagationTestCase ); | |
236 | CPPUNIT_TEST( OneHandler ); | |
237 | CPPUNIT_TEST( TwoHandlers ); | |
238 | CPPUNIT_TEST( WindowWithoutHandler ); | |
239 | CPPUNIT_TEST( WindowWithHandler ); | |
bbdee10d | 240 | CPPUNIT_TEST( ForwardEvent ); |
ce45133e VZ |
241 | CPPUNIT_TEST( ScrollWindowWithoutHandler ); |
242 | CPPUNIT_TEST( ScrollWindowWithHandler ); | |
3bad8c39 | 243 | CPPUNIT_TEST( MenuEvent ); |
a7c0de8a | 244 | CPPUNIT_TEST( DocView ); |
1649d288 VZ |
245 | CPPUNIT_TEST_SUITE_END(); |
246 | ||
247 | void OneHandler(); | |
248 | void TwoHandlers(); | |
249 | void WindowWithoutHandler(); | |
250 | void WindowWithHandler(); | |
bbdee10d | 251 | void ForwardEvent(); |
ce45133e VZ |
252 | void ScrollWindowWithoutHandler(); |
253 | void ScrollWindowWithHandler(); | |
3bad8c39 | 254 | void MenuEvent(); |
a7c0de8a | 255 | void DocView(); |
1649d288 VZ |
256 | |
257 | DECLARE_NO_COPY_CLASS(EventPropagationTestCase) | |
258 | }; | |
259 | ||
260 | // register in the unnamed registry so that these tests are run by default | |
261 | CPPUNIT_TEST_SUITE_REGISTRATION( EventPropagationTestCase ); | |
262 | ||
e3778b4d | 263 | // also include in its own registry so that these tests can be run alone |
1649d288 VZ |
264 | CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EventPropagationTestCase, "EventPropagationTestCase" ); |
265 | ||
266 | void EventPropagationTestCase::setUp() | |
267 | { | |
268 | SetFilterEventFunc(DoFilterEvent); | |
269 | SetProcessEventFunc(DoProcessEvent); | |
270 | ||
271 | g_str.clear(); | |
272 | } | |
273 | ||
274 | void EventPropagationTestCase::tearDown() | |
275 | { | |
276 | SetFilterEventFunc(NULL); | |
277 | SetProcessEventFunc(NULL); | |
278 | } | |
279 | ||
280 | void EventPropagationTestCase::OneHandler() | |
281 | { | |
282 | wxCommandEvent event(TEST_EVT); | |
283 | TestEvtHandler h1('1'); | |
284 | h1.ProcessEvent(event); | |
285 | CPPUNIT_ASSERT_EQUAL( "oa1A", g_str ); | |
286 | } | |
287 | ||
288 | void EventPropagationTestCase::TwoHandlers() | |
289 | { | |
290 | wxCommandEvent event(TEST_EVT); | |
291 | TestEvtHandler h1('1'); | |
292 | TestEvtHandler h2('2'); | |
293 | h1.SetNextHandler(&h2); | |
294 | h2.SetPreviousHandler(&h1); | |
295 | h1.ProcessEvent(event); | |
296 | CPPUNIT_ASSERT_EQUAL( "oa1o2A", g_str ); | |
297 | } | |
298 | ||
299 | void EventPropagationTestCase::WindowWithoutHandler() | |
300 | { | |
301 | wxCommandEvent event(TEST_EVT); | |
302 | TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p'); | |
303 | wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy ); | |
304 | ||
305 | TestWindow * const child = new TestWindow(parent, 'c'); | |
306 | ||
004867db | 307 | child->GetEventHandler()->ProcessEvent(event); |
1649d288 VZ |
308 | CPPUNIT_ASSERT_EQUAL( "acpA", g_str ); |
309 | } | |
310 | ||
311 | void EventPropagationTestCase::WindowWithHandler() | |
312 | { | |
313 | wxCommandEvent event(TEST_EVT); | |
314 | TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p'); | |
315 | wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy ); | |
316 | ||
317 | TestWindow * const child = new TestWindow(parent, 'c'); | |
318 | ||
319 | TestEvtHandler h1('1'); | |
320 | child->PushEventHandler(&h1); | |
9ebfc963 | 321 | wxON_BLOCK_EXIT_OBJ1( *child, wxWindow::PopEventHandler, false ); |
1649d288 VZ |
322 | TestEvtHandler h2('2'); |
323 | child->PushEventHandler(&h2); | |
9ebfc963 | 324 | wxON_BLOCK_EXIT_OBJ1( *child, wxWindow::PopEventHandler, false ); |
1649d288 VZ |
325 | |
326 | child->HandleWindowEvent(event); | |
327 | CPPUNIT_ASSERT_EQUAL( "oa2o1cpA", g_str ); | |
328 | } | |
329 | ||
bbdee10d VZ |
330 | void EventPropagationTestCase::ForwardEvent() |
331 | { | |
332 | // The idea of this test is to check that the events explicitly forwarded | |
333 | // to another event handler still get pre/post-processed as usual as this | |
334 | // used to be broken by the fixes trying to avoid duplicate processing. | |
335 | TestWindow * const win = new TestWindow(wxTheApp->GetTopWindow(), 'w'); | |
336 | wxON_BLOCK_EXIT_OBJ0( *win, wxWindow::Destroy ); | |
337 | ||
338 | TestEvtHandler h1('1'); | |
339 | win->PushEventHandler(&h1); | |
340 | wxON_BLOCK_EXIT_OBJ1( *win, wxWindow::PopEventHandler, false ); | |
341 | ||
342 | class ForwardEvtHandler : public wxEvtHandler | |
343 | { | |
344 | public: | |
345 | ForwardEvtHandler(wxEvtHandler& h) : m_h(&h) { } | |
346 | ||
347 | virtual bool ProcessEvent(wxEvent& event) | |
348 | { | |
349 | g_str += 'f'; | |
350 | ||
351 | return m_h->ProcessEvent(event); | |
352 | } | |
353 | ||
354 | private: | |
355 | wxEvtHandler *m_h; | |
356 | } f(h1); | |
357 | ||
358 | // First send the event directly to f. | |
359 | wxCommandEvent event1(TEST_EVT); | |
360 | f.ProcessEvent(event1); | |
361 | CPPUNIT_ASSERT_EQUAL( "foa1wA", g_str ); | |
362 | g_str.clear(); | |
363 | ||
364 | // And then also test sending it to f indirectly. | |
365 | wxCommandEvent event2(TEST_EVT); | |
366 | TestEvtHandler h2('2'); | |
367 | h2.SetNextHandler(&f); | |
368 | h2.ProcessEvent(event2); | |
369 | CPPUNIT_ASSERT_EQUAL( "oa2fo1wAA", g_str ); | |
370 | } | |
371 | ||
ce45133e VZ |
372 | void EventPropagationTestCase::ScrollWindowWithoutHandler() |
373 | { | |
52212bcb VZ |
374 | TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p'); |
375 | wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy ); | |
376 | ||
377 | TestScrollWindow * const win = new TestScrollWindow(parent); | |
ce45133e | 378 | |
23366691 VZ |
379 | #ifdef CAN_TEST_PAINT_EVENTS |
380 | win->GeneratePaintEvent(); | |
ce45133e | 381 | CPPUNIT_ASSERT_EQUAL( "PD", g_str ); |
f009da6e | 382 | #endif |
23366691 | 383 | |
52212bcb VZ |
384 | g_str.clear(); |
385 | wxCommandEvent eventCmd(TEST_EVT); | |
386 | win->HandleWindowEvent(eventCmd); | |
387 | CPPUNIT_ASSERT_EQUAL( "apA", g_str ); | |
ce45133e VZ |
388 | } |
389 | ||
390 | void EventPropagationTestCase::ScrollWindowWithHandler() | |
391 | { | |
52212bcb VZ |
392 | TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p'); |
393 | wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy ); | |
394 | ||
395 | TestScrollWindow * const win = new TestScrollWindow(parent); | |
ce45133e | 396 | |
23366691 | 397 | #ifdef CAN_TEST_PAINT_EVENTS |
ce45133e VZ |
398 | TestPaintEvtHandler h('h'); |
399 | win->PushEventHandler(&h); | |
400 | wxON_BLOCK_EXIT_OBJ1( *win, wxWindow::PopEventHandler, false ); | |
401 | ||
23366691 | 402 | win->GeneratePaintEvent(); |
ce45133e | 403 | CPPUNIT_ASSERT_EQUAL( "ohPD", g_str ); |
15536294 | 404 | #endif |
52212bcb VZ |
405 | |
406 | g_str.clear(); | |
407 | wxCommandEvent eventCmd(TEST_EVT); | |
408 | win->HandleWindowEvent(eventCmd); | |
409 | CPPUNIT_ASSERT_EQUAL( "apA", g_str ); | |
ce45133e VZ |
410 | } |
411 | ||
bbde2164 VZ |
412 | // Create a menu bar with a single menu containing wxID_APPLY menu item and |
413 | // attach it to the specified frame. | |
414 | wxMenu* CreateTestMenu(wxFrame* frame) | |
415 | { | |
416 | wxMenu* const menu = new wxMenu; | |
417 | menu->Append(wxID_APPLY); | |
418 | wxMenuBar* const mb = new wxMenuBar; | |
419 | mb->Append(menu, "&Menu"); | |
420 | frame->SetMenuBar(mb); | |
421 | ||
422 | return menu; | |
423 | } | |
424 | ||
3bad8c39 VZ |
425 | // Helper for checking that the menu event processing resulted in the expected |
426 | // output from the handlers. | |
9fe94219 VZ |
427 | // |
428 | // Notice that this is supposed to be used with ASSERT_MENU_EVENT_RESULT() | |
429 | // macro to make the file name and line number of the caller appear in the | |
430 | // failure messages. | |
431 | void | |
432 | CheckMenuEvent(wxMenu* menu, const char* result, CppUnit::SourceLine sourceLine) | |
3bad8c39 VZ |
433 | { |
434 | g_str.clear(); | |
435 | ||
436 | // Trigger the menu event: this is more reliable than using | |
437 | // wxUIActionSimulator and currently works in all ports as they all call | |
438 | // wxMenuBase::SendEvent() from their respective menu event handlers. | |
bbde2164 | 439 | menu->SendEvent(wxID_APPLY); |
3bad8c39 | 440 | |
9fe94219 | 441 | CPPUNIT_NS::assertEquals( result, g_str, sourceLine, "" ); |
3bad8c39 VZ |
442 | } |
443 | ||
9fe94219 VZ |
444 | #define ASSERT_MENU_EVENT_RESULT(menu, result) \ |
445 | CheckMenuEvent((menu), (result), CPPUNIT_SOURCELINE()) | |
446 | ||
3bad8c39 VZ |
447 | void EventPropagationTestCase::MenuEvent() |
448 | { | |
3bad8c39 | 449 | wxFrame* const frame = static_cast<wxFrame*>(wxTheApp->GetTopWindow()); |
bbde2164 VZ |
450 | |
451 | // Create a minimal menu bar. | |
452 | wxMenu* const menu = CreateTestMenu(frame); | |
453 | wxMenuBar* const mb = menu->GetMenuBar(); | |
454 | wxScopedPtr<wxMenuBar> ensureMenuBarDestruction(mb); | |
3bad8c39 VZ |
455 | wxON_BLOCK_EXIT_OBJ1( *frame, wxFrame::SetMenuBar, (wxMenuBar*)NULL ); |
456 | ||
457 | // Check that wxApp gets the event exactly once. | |
9fe94219 | 458 | ASSERT_MENU_EVENT_RESULT( menu, "aA" ); |
3bad8c39 VZ |
459 | |
460 | ||
461 | // Check that the menu event handler is called. | |
462 | TestMenuEvtHandler hm('m'); // 'm' for "menu" | |
463 | menu->SetNextHandler(&hm); | |
464 | wxON_BLOCK_EXIT_OBJ1( *menu, | |
465 | wxEvtHandler::SetNextHandler, (wxEvtHandler*)NULL ); | |
9fe94219 | 466 | ASSERT_MENU_EVENT_RESULT( menu, "aomA" ); |
3bad8c39 VZ |
467 | |
468 | ||
4ed3f4ab VZ |
469 | // Test that the event handler associated with the menu bar gets the event. |
470 | TestMenuEvtHandler hb('b'); // 'b' for "menu Bar" | |
471 | mb->PushEventHandler(&hb); | |
472 | wxON_BLOCK_EXIT_OBJ1( *mb, wxWindow::PopEventHandler, false ); | |
473 | ||
9fe94219 | 474 | ASSERT_MENU_EVENT_RESULT( menu, "aomobA" ); |
4ed3f4ab VZ |
475 | |
476 | ||
3bad8c39 VZ |
477 | // Also test that the window to which the menu belongs gets the event. |
478 | TestMenuEvtHandler hw('w'); // 'w' for "Window" | |
479 | frame->PushEventHandler(&hw); | |
480 | wxON_BLOCK_EXIT_OBJ1( *frame, wxWindow::PopEventHandler, false ); | |
481 | ||
9fe94219 | 482 | ASSERT_MENU_EVENT_RESULT( menu, "aomobowA" ); |
3bad8c39 | 483 | } |
a7c0de8a VZ |
484 | |
485 | // Minimal viable implementations of wxDocument and wxView. | |
486 | class EventTestDocument : public wxDocument | |
487 | { | |
488 | public: | |
489 | EventTestDocument() { } | |
490 | ||
491 | wxDECLARE_DYNAMIC_CLASS(EventTestDocument); | |
492 | }; | |
493 | ||
494 | class EventTestView : public wxView | |
495 | { | |
496 | public: | |
497 | EventTestView() { } | |
498 | ||
499 | virtual void OnDraw(wxDC*) { } | |
500 | ||
501 | wxDECLARE_DYNAMIC_CLASS(EventTestView); | |
502 | }; | |
503 | ||
504 | wxIMPLEMENT_DYNAMIC_CLASS(EventTestDocument, wxDocument); | |
505 | wxIMPLEMENT_DYNAMIC_CLASS(EventTestView, wxView); | |
506 | ||
507 | void EventPropagationTestCase::DocView() | |
508 | { | |
509 | // Set up the parent frame and its menu bar. | |
510 | wxDocManager docManager; | |
511 | ||
512 | wxScopedPtr<wxDocMDIParentFrame> | |
513 | parent(new wxDocMDIParentFrame(&docManager, NULL, wxID_ANY, "Parent")); | |
514 | ||
515 | wxMenu* const menu = CreateTestMenu(parent.get()); | |
516 | ||
517 | ||
518 | // Set up the event handlers. | |
519 | TestEvtSink sinkDM('m'); | |
520 | docManager.Connect(wxEVT_MENU, | |
521 | wxEventHandler(TestEvtSink::Handle), NULL, &sinkDM); | |
522 | ||
523 | TestEvtSink sinkParent('p'); | |
524 | parent->Connect(wxEVT_MENU, | |
525 | wxEventHandler(TestEvtSink::Handle), NULL, &sinkParent); | |
526 | ||
527 | ||
528 | // Check that wxDocManager and wxFrame get the event in order. | |
529 | ASSERT_MENU_EVENT_RESULT( menu, "ampA" ); | |
530 | ||
531 | ||
532 | // Now check what happens if we have an active document. | |
533 | wxDocTemplate docTemplate(&docManager, "Test", "", "", "", | |
534 | "Test Document", "Test View", | |
535 | wxCLASSINFO(EventTestDocument), | |
536 | wxCLASSINFO(EventTestView)); | |
537 | wxDocument* const doc = docTemplate.CreateDocument(""); | |
538 | wxView* const view = doc->GetFirstView(); | |
539 | ||
540 | wxScopedPtr<wxFrame> | |
541 | child(new wxDocMDIChildFrame(doc, view, parent.get(), wxID_ANY, "Child")); | |
542 | ||
543 | wxMenu* const menuChild = CreateTestMenu(child.get()); | |
544 | ||
545 | #ifdef __WXGTK__ | |
546 | // There are a lot of hacks related to child frame menu bar handling in | |
547 | // wxGTK and, in particular, the code in src/gtk/mdi.cpp relies on getting | |
548 | // idle events to really put everything in place. Moreover, as wxGTK uses | |
549 | // GtkNotebook as its MDI pages container, the frame must be shown for all | |
550 | // this to work as gtk_notebook_set_current_page() doesn't do anything if | |
551 | // called for a hidden window (this incredible fact cost me quite some time | |
552 | // to find empirically -- only to notice its confirmation in GTK+ | |
553 | // documentation immediately afterwards). So just do whatever it takes to | |
554 | // make things work "as usual". | |
555 | child->Show(); | |
556 | parent->Show(); | |
557 | wxYield(); | |
558 | #endif // __WXGTK__ | |
559 | ||
560 | TestEvtSink sinkDoc('d'); | |
561 | doc->Connect(wxEVT_MENU, | |
562 | wxEventHandler(TestEvtSink::Handle), NULL, &sinkDoc); | |
563 | ||
564 | TestEvtSink sinkView('v'); | |
565 | view->Connect(wxEVT_MENU, | |
566 | wxEventHandler(TestEvtSink::Handle), NULL, &sinkView); | |
567 | ||
568 | TestEvtSink sinkChild('c'); | |
569 | child->Connect(wxEVT_MENU, | |
570 | wxEventHandler(TestEvtSink::Handle), NULL, &sinkChild); | |
571 | ||
572 | // Check that wxDocument, wxView, wxDocManager, child frame and the parent | |
573 | // get the event in order. | |
574 | ASSERT_MENU_EVENT_RESULT( menuChild, "advmcpA" ); | |
575 | } |