1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/events/propagation.cpp
3 // Purpose: Test events propagation
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
8 ///////////////////////////////////////////////////////////////////////////////
10 // ----------------------------------------------------------------------------
12 // ----------------------------------------------------------------------------
23 #include "wx/scrolwin.h"
24 #include "wx/window.h"
27 #include "wx/scopeguard.h"
32 // this string will record the execution of all handlers
36 wxDEFINE_EVENT(TEST_EVT
, wxCommandEvent
);
38 // a custom event handler tracing the propagation of the events of the
40 template <class Event
>
41 class TestEvtHandlerBase
: public wxEvtHandler
44 TestEvtHandlerBase(wxEventType evtType
, char tag
)
49 static_cast<wxEventFunction
>(&TestEvtHandlerBase::OnTest
));
52 // override ProcessEvent() to confirm that it is called for all event
53 // handlers in the chain
54 virtual bool ProcessEvent(wxEvent
& event
)
56 if ( event
.GetEventType() == m_evtType
)
57 g_str
+= 'o'; // "o" == "overridden"
59 return wxEvtHandler::ProcessEvent(event
);
63 void OnTest(wxEvent
& event
)
70 const wxEventType m_evtType
;
73 wxDECLARE_NO_COPY_TEMPLATE_CLASS(TestEvtHandlerBase
, Event
);
76 struct TestEvtHandler
: TestEvtHandlerBase
<wxCommandEvent
>
78 TestEvtHandler(char tag
)
79 : TestEvtHandlerBase
<wxCommandEvent
>(TEST_EVT
, tag
)
84 struct TestPaintEvtHandler
: TestEvtHandlerBase
<wxPaintEvent
>
86 TestPaintEvtHandler(char tag
)
87 : TestEvtHandlerBase
<wxPaintEvent
>(wxEVT_PAINT
, tag
)
92 // a window handling the test event
93 class TestWindow
: public wxWindow
96 TestWindow(wxWindow
*parent
, char tag
)
97 : wxWindow(parent
, wxID_ANY
),
100 Connect(TEST_EVT
, wxCommandEventHandler(TestWindow::OnTest
));
104 void OnTest(wxCommandEvent
& event
)
113 DECLARE_NO_COPY_CLASS(TestWindow
)
116 // a scroll window handling paint event: we want to have a special test case
117 // for this because the event propagation is complicated even further than
118 // usual here by the presence of wxScrollHelperEvtHandler in the event handlers
119 // chain and the fact that OnDraw() virtual method must be called if EVT_PAINT
121 class TestScrollWindow
: public wxScrolledWindow
124 TestScrollWindow(wxWindow
*parent
)
125 : wxScrolledWindow(parent
, wxID_ANY
)
127 Connect(wxEVT_PAINT
, wxPaintEventHandler(TestScrollWindow::OnPaint
));
130 virtual void OnDraw(wxDC
& WXUNUSED(dc
))
132 g_str
+= 'D'; // draw
136 void OnPaint(wxPaintEvent
& event
)
138 g_str
+= 'P'; // paint
142 wxDECLARE_NO_COPY_CLASS(TestScrollWindow
);
145 int DoFilterEvent(wxEvent
& event
)
147 if ( event
.GetEventType() == TEST_EVT
)
153 bool DoProcessEvent(wxEvent
& event
)
155 if ( event
.GetEventType() == TEST_EVT
)
161 } // anonymous namespace
163 // --------------------------------------------------------------------------
165 // --------------------------------------------------------------------------
167 class EventPropagationTestCase
: public CppUnit::TestCase
170 EventPropagationTestCase() {}
172 virtual void setUp();
173 virtual void tearDown();
176 CPPUNIT_TEST_SUITE( EventPropagationTestCase
);
177 CPPUNIT_TEST( OneHandler
);
178 CPPUNIT_TEST( TwoHandlers
);
179 CPPUNIT_TEST( WindowWithoutHandler
);
180 CPPUNIT_TEST( WindowWithHandler
);
181 CPPUNIT_TEST( ForwardEvent
);
182 CPPUNIT_TEST( ScrollWindowWithoutHandler
);
183 CPPUNIT_TEST( ScrollWindowWithHandler
);
184 CPPUNIT_TEST_SUITE_END();
188 void WindowWithoutHandler();
189 void WindowWithHandler();
191 void ScrollWindowWithoutHandler();
192 void ScrollWindowWithHandler();
194 DECLARE_NO_COPY_CLASS(EventPropagationTestCase
)
197 // register in the unnamed registry so that these tests are run by default
198 CPPUNIT_TEST_SUITE_REGISTRATION( EventPropagationTestCase
);
200 // also include in its own registry so that these tests can be run alone
201 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EventPropagationTestCase
, "EventPropagationTestCase" );
203 void EventPropagationTestCase::setUp()
205 SetFilterEventFunc(DoFilterEvent
);
206 SetProcessEventFunc(DoProcessEvent
);
211 void EventPropagationTestCase::tearDown()
213 SetFilterEventFunc(NULL
);
214 SetProcessEventFunc(NULL
);
217 void EventPropagationTestCase::OneHandler()
219 wxCommandEvent
event(TEST_EVT
);
220 TestEvtHandler
h1('1');
221 h1
.ProcessEvent(event
);
222 CPPUNIT_ASSERT_EQUAL( "oa1A", g_str
);
225 void EventPropagationTestCase::TwoHandlers()
227 wxCommandEvent
event(TEST_EVT
);
228 TestEvtHandler
h1('1');
229 TestEvtHandler
h2('2');
230 h1
.SetNextHandler(&h2
);
231 h2
.SetPreviousHandler(&h1
);
232 h1
.ProcessEvent(event
);
233 CPPUNIT_ASSERT_EQUAL( "oa1o2A", g_str
);
236 void EventPropagationTestCase::WindowWithoutHandler()
238 wxCommandEvent
event(TEST_EVT
);
239 TestWindow
* const parent
= new TestWindow(wxTheApp
->GetTopWindow(), 'p');
240 wxON_BLOCK_EXIT_OBJ0( *parent
, wxWindow::Destroy
);
242 TestWindow
* const child
= new TestWindow(parent
, 'c');
244 child
->GetEventHandler()->ProcessEvent(event
);
245 CPPUNIT_ASSERT_EQUAL( "acpA", g_str
);
248 void EventPropagationTestCase::WindowWithHandler()
250 wxCommandEvent
event(TEST_EVT
);
251 TestWindow
* const parent
= new TestWindow(wxTheApp
->GetTopWindow(), 'p');
252 wxON_BLOCK_EXIT_OBJ0( *parent
, wxWindow::Destroy
);
254 TestWindow
* const child
= new TestWindow(parent
, 'c');
256 TestEvtHandler
h1('1');
257 child
->PushEventHandler(&h1
);
258 wxON_BLOCK_EXIT_OBJ1( *child
, wxWindow::PopEventHandler
, false );
259 TestEvtHandler
h2('2');
260 child
->PushEventHandler(&h2
);
261 wxON_BLOCK_EXIT_OBJ1( *child
, wxWindow::PopEventHandler
, false );
263 child
->HandleWindowEvent(event
);
264 CPPUNIT_ASSERT_EQUAL( "oa2o1cpA", g_str
);
267 void EventPropagationTestCase::ForwardEvent()
269 // The idea of this test is to check that the events explicitly forwarded
270 // to another event handler still get pre/post-processed as usual as this
271 // used to be broken by the fixes trying to avoid duplicate processing.
272 TestWindow
* const win
= new TestWindow(wxTheApp
->GetTopWindow(), 'w');
273 wxON_BLOCK_EXIT_OBJ0( *win
, wxWindow::Destroy
);
275 TestEvtHandler
h1('1');
276 win
->PushEventHandler(&h1
);
277 wxON_BLOCK_EXIT_OBJ1( *win
, wxWindow::PopEventHandler
, false );
279 class ForwardEvtHandler
: public wxEvtHandler
282 ForwardEvtHandler(wxEvtHandler
& h
) : m_h(&h
) { }
284 virtual bool ProcessEvent(wxEvent
& event
)
288 return m_h
->ProcessEvent(event
);
295 // First send the event directly to f.
296 wxCommandEvent
event1(TEST_EVT
);
297 f
.ProcessEvent(event1
);
298 CPPUNIT_ASSERT_EQUAL( "foa1wA", g_str
);
301 // And then also test sending it to f indirectly.
302 wxCommandEvent
event2(TEST_EVT
);
303 TestEvtHandler
h2('2');
304 h2
.SetNextHandler(&f
);
305 h2
.ProcessEvent(event2
);
306 CPPUNIT_ASSERT_EQUAL( "oa2fo1wAA", g_str
);
309 void EventPropagationTestCase::ScrollWindowWithoutHandler()
311 TestWindow
* const parent
= new TestWindow(wxTheApp
->GetTopWindow(), 'p');
312 wxON_BLOCK_EXIT_OBJ0( *parent
, wxWindow::Destroy
);
314 TestScrollWindow
* const win
= new TestScrollWindow(parent
);
316 #if !defined(__WXOSX__) && !defined(__WXGTK3__)
317 wxPaintEvent
event(win
->GetId());
318 win
->ProcessWindowEvent(event
);
319 CPPUNIT_ASSERT_EQUAL( "PD", g_str
);
322 wxCommandEvent
eventCmd(TEST_EVT
);
323 win
->HandleWindowEvent(eventCmd
);
324 CPPUNIT_ASSERT_EQUAL( "apA", g_str
);
327 void EventPropagationTestCase::ScrollWindowWithHandler()
329 TestWindow
* const parent
= new TestWindow(wxTheApp
->GetTopWindow(), 'p');
330 wxON_BLOCK_EXIT_OBJ0( *parent
, wxWindow::Destroy
);
332 TestScrollWindow
* const win
= new TestScrollWindow(parent
);
334 #if !defined(__WXOSX__) && !defined(__WXGTK3__)
335 TestPaintEvtHandler
h('h');
336 win
->PushEventHandler(&h
);
337 wxON_BLOCK_EXIT_OBJ1( *win
, wxWindow::PopEventHandler
, false );
339 wxPaintEvent
event(win
->GetId());
340 win
->ProcessWindowEvent(event
);
341 CPPUNIT_ASSERT_EQUAL( "ohPD", g_str
);
345 wxCommandEvent
eventCmd(TEST_EVT
);
346 win
->HandleWindowEvent(eventCmd
);
347 CPPUNIT_ASSERT_EQUAL( "apA", g_str
);