6037ce0e6f
This failure seems to only happen on buildbot, at least it couldn't be reproduced after 100 runs of the test locally, so it just doesn't seem possible to debug it. Disable it to allow detecting when other tests fail (which would be unexpected, unlike this one).
673 lines
19 KiB
C++
673 lines
19 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: tests/events/propagation.cpp
|
|
// Purpose: Test events propagation
|
|
// Author: Vadim Zeitlin
|
|
// Created: 2009-01-16
|
|
// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include "testprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/app.h"
|
|
#include "wx/event.h"
|
|
#include "wx/scrolwin.h"
|
|
#include "wx/window.h"
|
|
#endif // WX_PRECOMP
|
|
|
|
#include "wx/docmdi.h"
|
|
#include "wx/frame.h"
|
|
#include "wx/menu.h"
|
|
#include "wx/scopedptr.h"
|
|
#include "wx/scopeguard.h"
|
|
#include "wx/toolbar.h"
|
|
#include "wx/uiaction.h"
|
|
|
|
// FIXME: Currently under OS X testing paint event doesn't work because neither
|
|
// calling Refresh()+Update() nor even sending wxPaintEvent directly to
|
|
// the window doesn't result in calls to its event handlers, so disable
|
|
// some tests there. But this should be fixed and the tests reenabled
|
|
// because wxPaintEvent propagation in wxScrolledWindow is a perfect
|
|
// example of fragile code that could be broken under OS X.
|
|
#ifndef __WXOSX__
|
|
#define CAN_TEST_PAINT_EVENTS
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
|
|
// this string will record the execution of all handlers
|
|
wxString g_str;
|
|
|
|
// a custom event
|
|
wxDEFINE_EVENT(TEST_EVT, wxCommandEvent);
|
|
|
|
// a custom event handler tracing the propagation of the events of the
|
|
// specified types
|
|
template <class Event>
|
|
class TestEvtHandlerBase : public wxEvtHandler
|
|
{
|
|
public:
|
|
TestEvtHandlerBase(wxEventType evtType, char tag)
|
|
: m_evtType(evtType),
|
|
m_tag(tag)
|
|
{
|
|
Connect(evtType,
|
|
static_cast<wxEventFunction>(&TestEvtHandlerBase::OnTest));
|
|
}
|
|
|
|
// override ProcessEvent() to confirm that it is called for all event
|
|
// handlers in the chain
|
|
virtual bool ProcessEvent(wxEvent& event)
|
|
{
|
|
if ( event.GetEventType() == m_evtType )
|
|
g_str += 'o'; // "o" == "overridden"
|
|
|
|
return wxEvtHandler::ProcessEvent(event);
|
|
}
|
|
|
|
private:
|
|
void OnTest(wxEvent& event)
|
|
{
|
|
g_str += m_tag;
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
const wxEventType m_evtType;
|
|
const char m_tag;
|
|
|
|
wxDECLARE_NO_COPY_TEMPLATE_CLASS(TestEvtHandlerBase, Event);
|
|
};
|
|
|
|
struct TestEvtHandler : TestEvtHandlerBase<wxCommandEvent>
|
|
{
|
|
TestEvtHandler(char tag)
|
|
: TestEvtHandlerBase<wxCommandEvent>(TEST_EVT, tag)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct TestMenuEvtHandler : TestEvtHandlerBase<wxCommandEvent>
|
|
{
|
|
TestMenuEvtHandler(char tag)
|
|
: TestEvtHandlerBase<wxCommandEvent>(wxEVT_MENU, tag)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct TestPaintEvtHandler : TestEvtHandlerBase<wxPaintEvent>
|
|
{
|
|
TestPaintEvtHandler(char tag)
|
|
: TestEvtHandlerBase<wxPaintEvent>(wxEVT_PAINT, tag)
|
|
{
|
|
}
|
|
};
|
|
|
|
// Another custom event handler, suitable for use with Connect().
|
|
struct TestEvtSink : wxEvtHandler
|
|
{
|
|
TestEvtSink(char tag)
|
|
: m_tag(tag)
|
|
{
|
|
}
|
|
|
|
void Handle(wxEvent& event)
|
|
{
|
|
g_str += m_tag;
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
const char m_tag;
|
|
|
|
wxDECLARE_NO_COPY_CLASS(TestEvtSink);
|
|
};
|
|
|
|
// a window handling the test event
|
|
class TestWindow : public wxWindow
|
|
{
|
|
public:
|
|
TestWindow(wxWindow *parent, char tag)
|
|
: wxWindow(parent, wxID_ANY),
|
|
m_tag(tag)
|
|
{
|
|
Connect(TEST_EVT, wxCommandEventHandler(TestWindow::OnTest));
|
|
}
|
|
|
|
private:
|
|
void OnTest(wxCommandEvent& event)
|
|
{
|
|
g_str += m_tag;
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
const char m_tag;
|
|
|
|
wxDECLARE_NO_COPY_CLASS(TestWindow);
|
|
};
|
|
|
|
// a scroll window handling paint event: we want to have a special test case
|
|
// for this because the event propagation is complicated even further than
|
|
// usual here by the presence of wxScrollHelperEvtHandler in the event handlers
|
|
// chain and the fact that OnDraw() virtual method must be called if EVT_PAINT
|
|
// is not handled
|
|
class TestScrollWindow : public wxScrolledWindow
|
|
{
|
|
public:
|
|
TestScrollWindow(wxWindow *parent)
|
|
: wxScrolledWindow(parent, wxID_ANY)
|
|
{
|
|
Connect(wxEVT_PAINT, wxPaintEventHandler(TestScrollWindow::OnPaint));
|
|
}
|
|
|
|
void GeneratePaintEvent()
|
|
{
|
|
#ifdef __WXGTK__
|
|
// We need to map the window, otherwise we're not going to get any
|
|
// paint events for it.
|
|
wxYield();
|
|
|
|
// Ignore events generated during the initial mapping.
|
|
g_str.clear();
|
|
#endif // __WXGTK__
|
|
|
|
Refresh();
|
|
Update();
|
|
}
|
|
|
|
virtual void OnDraw(wxDC& WXUNUSED(dc))
|
|
{
|
|
g_str += 'D'; // draw
|
|
}
|
|
|
|
private:
|
|
void OnPaint(wxPaintEvent& event)
|
|
{
|
|
g_str += 'P'; // paint
|
|
event.Skip();
|
|
}
|
|
|
|
wxDECLARE_NO_COPY_CLASS(TestScrollWindow);
|
|
};
|
|
|
|
int DoFilterEvent(wxEvent& event)
|
|
{
|
|
if ( event.GetEventType() == TEST_EVT ||
|
|
event.GetEventType() == wxEVT_MENU )
|
|
g_str += 'a';
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool DoProcessEvent(wxEvent& event)
|
|
{
|
|
if ( event.GetEventType() == TEST_EVT ||
|
|
event.GetEventType() == wxEVT_MENU )
|
|
g_str += 'A';
|
|
|
|
return false;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
// --------------------------------------------------------------------------
|
|
// test class
|
|
// --------------------------------------------------------------------------
|
|
|
|
class EventPropagationTestCase : public CppUnit::TestCase
|
|
{
|
|
public:
|
|
EventPropagationTestCase() {}
|
|
|
|
virtual void setUp();
|
|
virtual void tearDown();
|
|
|
|
private:
|
|
CPPUNIT_TEST_SUITE( EventPropagationTestCase );
|
|
CPPUNIT_TEST( OneHandler );
|
|
CPPUNIT_TEST( TwoHandlers );
|
|
CPPUNIT_TEST( WindowWithoutHandler );
|
|
CPPUNIT_TEST( WindowWithHandler );
|
|
CPPUNIT_TEST( ForwardEvent );
|
|
CPPUNIT_TEST( ScrollWindowWithoutHandler );
|
|
CPPUNIT_TEST( ScrollWindowWithHandler );
|
|
// for unknown reason, this test will cause the tests segmentation failed
|
|
// under x11, disable it for now.
|
|
#if !defined (__WXX11__)
|
|
CPPUNIT_TEST( MenuEvent );
|
|
#endif
|
|
CPPUNIT_TEST( DocView );
|
|
WXUISIM_TEST( ContextMenuEvent );
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
void OneHandler();
|
|
void TwoHandlers();
|
|
void WindowWithoutHandler();
|
|
void WindowWithHandler();
|
|
void ForwardEvent();
|
|
void ScrollWindowWithoutHandler();
|
|
void ScrollWindowWithHandler();
|
|
void MenuEvent();
|
|
void DocView();
|
|
void ContextMenuEvent();
|
|
|
|
wxDECLARE_NO_COPY_CLASS(EventPropagationTestCase);
|
|
};
|
|
|
|
// register in the unnamed registry so that these tests are run by default
|
|
CPPUNIT_TEST_SUITE_REGISTRATION( EventPropagationTestCase );
|
|
|
|
// also include in its own registry so that these tests can be run alone
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EventPropagationTestCase, "EventPropagationTestCase" );
|
|
|
|
void EventPropagationTestCase::setUp()
|
|
{
|
|
SetFilterEventFunc(DoFilterEvent);
|
|
SetProcessEventFunc(DoProcessEvent);
|
|
|
|
g_str.clear();
|
|
}
|
|
|
|
void EventPropagationTestCase::tearDown()
|
|
{
|
|
SetFilterEventFunc(NULL);
|
|
SetProcessEventFunc(NULL);
|
|
}
|
|
|
|
void EventPropagationTestCase::OneHandler()
|
|
{
|
|
wxCommandEvent event(TEST_EVT);
|
|
TestEvtHandler h1('1');
|
|
h1.ProcessEvent(event);
|
|
CPPUNIT_ASSERT_EQUAL( "oa1A", g_str );
|
|
}
|
|
|
|
void EventPropagationTestCase::TwoHandlers()
|
|
{
|
|
wxCommandEvent event(TEST_EVT);
|
|
TestEvtHandler h1('1');
|
|
TestEvtHandler h2('2');
|
|
h1.SetNextHandler(&h2);
|
|
h2.SetPreviousHandler(&h1);
|
|
h1.ProcessEvent(event);
|
|
CPPUNIT_ASSERT_EQUAL( "oa1o2A", g_str );
|
|
}
|
|
|
|
void EventPropagationTestCase::WindowWithoutHandler()
|
|
{
|
|
wxCommandEvent event(TEST_EVT);
|
|
TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
|
|
wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
|
|
|
|
TestWindow * const child = new TestWindow(parent, 'c');
|
|
|
|
child->GetEventHandler()->ProcessEvent(event);
|
|
CPPUNIT_ASSERT_EQUAL( "acpA", g_str );
|
|
}
|
|
|
|
void EventPropagationTestCase::WindowWithHandler()
|
|
{
|
|
wxCommandEvent event(TEST_EVT);
|
|
TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
|
|
wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
|
|
|
|
TestWindow * const child = new TestWindow(parent, 'c');
|
|
|
|
TestEvtHandler h1('1');
|
|
child->PushEventHandler(&h1);
|
|
wxON_BLOCK_EXIT_OBJ1( *child, wxWindow::PopEventHandler, false );
|
|
TestEvtHandler h2('2');
|
|
child->PushEventHandler(&h2);
|
|
wxON_BLOCK_EXIT_OBJ1( *child, wxWindow::PopEventHandler, false );
|
|
|
|
child->HandleWindowEvent(event);
|
|
CPPUNIT_ASSERT_EQUAL( "oa2o1cpA", g_str );
|
|
}
|
|
|
|
void EventPropagationTestCase::ForwardEvent()
|
|
{
|
|
// The idea of this test is to check that the events explicitly forwarded
|
|
// to another event handler still get pre/post-processed as usual as this
|
|
// used to be broken by the fixes trying to avoid duplicate processing.
|
|
TestWindow * const win = new TestWindow(wxTheApp->GetTopWindow(), 'w');
|
|
wxON_BLOCK_EXIT_OBJ0( *win, wxWindow::Destroy );
|
|
|
|
TestEvtHandler h1('1');
|
|
win->PushEventHandler(&h1);
|
|
wxON_BLOCK_EXIT_OBJ1( *win, wxWindow::PopEventHandler, false );
|
|
|
|
class ForwardEvtHandler : public wxEvtHandler
|
|
{
|
|
public:
|
|
ForwardEvtHandler(wxEvtHandler& h) : m_h(&h) { }
|
|
|
|
virtual bool ProcessEvent(wxEvent& event)
|
|
{
|
|
g_str += 'f';
|
|
|
|
return m_h->ProcessEvent(event);
|
|
}
|
|
|
|
private:
|
|
wxEvtHandler *m_h;
|
|
} f(h1);
|
|
|
|
// First send the event directly to f.
|
|
wxCommandEvent event1(TEST_EVT);
|
|
f.ProcessEvent(event1);
|
|
CPPUNIT_ASSERT_EQUAL( "foa1wA", g_str );
|
|
g_str.clear();
|
|
|
|
// And then also test sending it to f indirectly.
|
|
wxCommandEvent event2(TEST_EVT);
|
|
TestEvtHandler h2('2');
|
|
h2.SetNextHandler(&f);
|
|
h2.ProcessEvent(event2);
|
|
CPPUNIT_ASSERT_EQUAL( "oa2fo1wAA", g_str );
|
|
}
|
|
|
|
void EventPropagationTestCase::ScrollWindowWithoutHandler()
|
|
{
|
|
TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
|
|
wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
|
|
|
|
TestScrollWindow * const win = new TestScrollWindow(parent);
|
|
|
|
#ifdef CAN_TEST_PAINT_EVENTS
|
|
win->GeneratePaintEvent();
|
|
CPPUNIT_ASSERT_EQUAL( "PD", g_str );
|
|
#endif
|
|
|
|
g_str.clear();
|
|
wxCommandEvent eventCmd(TEST_EVT);
|
|
win->HandleWindowEvent(eventCmd);
|
|
CPPUNIT_ASSERT_EQUAL( "apA", g_str );
|
|
}
|
|
|
|
void EventPropagationTestCase::ScrollWindowWithHandler()
|
|
{
|
|
TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
|
|
wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
|
|
|
|
TestScrollWindow * const win = new TestScrollWindow(parent);
|
|
|
|
#ifdef CAN_TEST_PAINT_EVENTS
|
|
TestPaintEvtHandler h('h');
|
|
win->PushEventHandler(&h);
|
|
wxON_BLOCK_EXIT_OBJ1( *win, wxWindow::PopEventHandler, false );
|
|
|
|
win->GeneratePaintEvent();
|
|
CPPUNIT_ASSERT_EQUAL( "ohPD", g_str );
|
|
#endif
|
|
|
|
g_str.clear();
|
|
wxCommandEvent eventCmd(TEST_EVT);
|
|
win->HandleWindowEvent(eventCmd);
|
|
CPPUNIT_ASSERT_EQUAL( "apA", g_str );
|
|
}
|
|
|
|
// Create a menu bar with a single menu containing wxID_APPLY menu item and
|
|
// attach it to the specified frame.
|
|
wxMenu* CreateTestMenu(wxFrame* frame)
|
|
{
|
|
wxMenu* const menu = new wxMenu;
|
|
menu->Append(wxID_APPLY);
|
|
wxMenuBar* const mb = new wxMenuBar;
|
|
mb->Append(menu, "&Menu");
|
|
frame->SetMenuBar(mb);
|
|
|
|
return menu;
|
|
}
|
|
|
|
// Helper for checking that the menu event processing resulted in the expected
|
|
// output from the handlers.
|
|
//
|
|
// Notice that this is supposed to be used with ASSERT_MENU_EVENT_RESULT()
|
|
// macro to make the file name and line number of the caller appear in the
|
|
// failure messages.
|
|
void
|
|
CheckMenuEvent(wxMenu* menu, const char* result, CppUnit::SourceLine sourceLine)
|
|
{
|
|
g_str.clear();
|
|
|
|
// Trigger the menu event: this is more reliable than using
|
|
// wxUIActionSimulator and currently works in all ports as they all call
|
|
// wxMenuBase::SendEvent() from their respective menu event handlers.
|
|
menu->SendEvent(wxID_APPLY);
|
|
|
|
CPPUNIT_NS::assertEquals( result, g_str, sourceLine, "" );
|
|
}
|
|
|
|
#define ASSERT_MENU_EVENT_RESULT(menu, result) \
|
|
CheckMenuEvent((menu), (result), CPPUNIT_SOURCELINE())
|
|
|
|
void EventPropagationTestCase::MenuEvent()
|
|
{
|
|
wxFrame* const frame = static_cast<wxFrame*>(wxTheApp->GetTopWindow());
|
|
|
|
// Create a minimal menu bar.
|
|
wxMenu* const menu = CreateTestMenu(frame);
|
|
wxMenuBar* const mb = menu->GetMenuBar();
|
|
wxScopedPtr<wxMenuBar> ensureMenuBarDestruction(mb);
|
|
wxON_BLOCK_EXIT_OBJ1( *frame, wxFrame::SetMenuBar, (wxMenuBar*)NULL );
|
|
|
|
// Check that wxApp gets the event exactly once.
|
|
ASSERT_MENU_EVENT_RESULT( menu, "aA" );
|
|
|
|
|
|
// Check that the menu event handler is called.
|
|
TestMenuEvtHandler hm('m'); // 'm' for "menu"
|
|
menu->SetNextHandler(&hm);
|
|
wxON_BLOCK_EXIT_OBJ1( *menu,
|
|
wxEvtHandler::SetNextHandler, (wxEvtHandler*)NULL );
|
|
ASSERT_MENU_EVENT_RESULT( menu, "aomA" );
|
|
|
|
|
|
// Test that the event handler associated with the menu bar gets the event.
|
|
TestMenuEvtHandler hb('b'); // 'b' for "menu Bar"
|
|
mb->PushEventHandler(&hb);
|
|
wxON_BLOCK_EXIT_OBJ1( *mb, wxWindow::PopEventHandler, false );
|
|
|
|
ASSERT_MENU_EVENT_RESULT( menu, "aomobA" );
|
|
|
|
|
|
// Also test that the window to which the menu belongs gets the event.
|
|
TestMenuEvtHandler hw('w'); // 'w' for "Window"
|
|
frame->PushEventHandler(&hw);
|
|
wxON_BLOCK_EXIT_OBJ1( *frame, wxWindow::PopEventHandler, false );
|
|
|
|
ASSERT_MENU_EVENT_RESULT( menu, "aomobowA" );
|
|
}
|
|
|
|
// Minimal viable implementations of wxDocument and wxView.
|
|
class EventTestDocument : public wxDocument
|
|
{
|
|
public:
|
|
EventTestDocument() { }
|
|
|
|
wxDECLARE_DYNAMIC_CLASS(EventTestDocument);
|
|
};
|
|
|
|
class EventTestView : public wxView
|
|
{
|
|
public:
|
|
EventTestView() { }
|
|
|
|
virtual void OnDraw(wxDC*) { }
|
|
|
|
wxDECLARE_DYNAMIC_CLASS(EventTestView);
|
|
};
|
|
|
|
wxIMPLEMENT_DYNAMIC_CLASS(EventTestDocument, wxDocument);
|
|
wxIMPLEMENT_DYNAMIC_CLASS(EventTestView, wxView);
|
|
|
|
void EventPropagationTestCase::DocView()
|
|
{
|
|
// Set up the parent frame and its menu bar.
|
|
wxDocManager docManager;
|
|
|
|
wxScopedPtr<wxDocMDIParentFrame>
|
|
parent(new wxDocMDIParentFrame(&docManager, NULL, wxID_ANY, "Parent"));
|
|
|
|
wxMenu* const menu = CreateTestMenu(parent.get());
|
|
|
|
|
|
// Set up the event handlers.
|
|
TestEvtSink sinkDM('m');
|
|
docManager.Connect(wxEVT_MENU,
|
|
wxEventHandler(TestEvtSink::Handle), NULL, &sinkDM);
|
|
|
|
TestEvtSink sinkParent('p');
|
|
parent->Connect(wxEVT_MENU,
|
|
wxEventHandler(TestEvtSink::Handle), NULL, &sinkParent);
|
|
|
|
|
|
// Check that wxDocManager and wxFrame get the event in order.
|
|
ASSERT_MENU_EVENT_RESULT( menu, "ampA" );
|
|
|
|
|
|
// Now check what happens if we have an active document.
|
|
wxDocTemplate docTemplate(&docManager, "Test", "", "", "",
|
|
"Test Document", "Test View",
|
|
wxCLASSINFO(EventTestDocument),
|
|
wxCLASSINFO(EventTestView));
|
|
wxDocument* const doc = docTemplate.CreateDocument("");
|
|
wxView* const view = doc->GetFirstView();
|
|
|
|
wxScopedPtr<wxMDIChildFrame>
|
|
child(new wxDocMDIChildFrame(doc, view, parent.get(), wxID_ANY, "Child"));
|
|
|
|
wxMenu* const menuChild = CreateTestMenu(child.get());
|
|
|
|
// Ensure that the child that we've just created is the active one.
|
|
child->Activate();
|
|
|
|
#ifdef __WXGTK__
|
|
// There are a lot of hacks related to child frame menu bar handling in
|
|
// wxGTK and, in particular, the code in src/gtk/mdi.cpp relies on getting
|
|
// idle events to really put everything in place. Moreover, as wxGTK uses
|
|
// GtkNotebook as its MDI pages container, the frame must be shown for all
|
|
// this to work as gtk_notebook_set_current_page() doesn't do anything if
|
|
// called for a hidden window (this incredible fact cost me quite some time
|
|
// to find empirically -- only to notice its confirmation in GTK+
|
|
// documentation immediately afterwards). So just do whatever it takes to
|
|
// make things work "as usual".
|
|
child->Show();
|
|
parent->Show();
|
|
wxYield();
|
|
#endif // __WXGTK__
|
|
|
|
TestEvtSink sinkDoc('d');
|
|
doc->Connect(wxEVT_MENU,
|
|
wxEventHandler(TestEvtSink::Handle), NULL, &sinkDoc);
|
|
|
|
TestEvtSink sinkView('v');
|
|
view->Connect(wxEVT_MENU,
|
|
wxEventHandler(TestEvtSink::Handle), NULL, &sinkView);
|
|
|
|
TestEvtSink sinkChild('c');
|
|
child->Connect(wxEVT_MENU,
|
|
wxEventHandler(TestEvtSink::Handle), NULL, &sinkChild);
|
|
|
|
// Check that wxDocument, wxView, wxDocManager, child frame and the parent
|
|
// get the event in order.
|
|
ASSERT_MENU_EVENT_RESULT( menuChild, "advmcpA" );
|
|
|
|
|
|
#if wxUSE_TOOLBAR
|
|
// Also check that toolbar events get forwarded to the active child.
|
|
wxToolBar* const tb = parent->CreateToolBar(wxTB_NOICONS);
|
|
tb->AddTool(wxID_APPLY, "Apply", wxNullBitmap);
|
|
tb->Realize();
|
|
|
|
// As in CheckMenuEvent(), use toolbar method actually sending the event
|
|
// instead of bothering with wxUIActionSimulator which would have been
|
|
// trickier.
|
|
g_str.clear();
|
|
tb->OnLeftClick(wxID_APPLY, true /* doesn't matter */);
|
|
|
|
CPPUNIT_ASSERT_EQUAL( "advmcpA", g_str );
|
|
#endif // wxUSE_TOOLBAR
|
|
}
|
|
|
|
#if wxUSE_UIACTIONSIMULATOR
|
|
|
|
class ContextMenuTestWindow : public wxWindow
|
|
{
|
|
public:
|
|
ContextMenuTestWindow(wxWindow *parent, char tag)
|
|
: wxWindow(parent, wxID_ANY),
|
|
m_tag(tag)
|
|
{
|
|
Connect(wxEVT_CONTEXT_MENU,
|
|
wxContextMenuEventHandler(ContextMenuTestWindow::OnMenu));
|
|
}
|
|
|
|
private:
|
|
void OnMenu(wxContextMenuEvent& event)
|
|
{
|
|
g_str += m_tag;
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
const char m_tag;
|
|
|
|
wxDECLARE_NO_COPY_CLASS(ContextMenuTestWindow);
|
|
};
|
|
|
|
void EventPropagationTestCase::ContextMenuEvent()
|
|
{
|
|
ContextMenuTestWindow * const
|
|
parent = new ContextMenuTestWindow(wxTheApp->GetTopWindow(), 'p');
|
|
wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
|
|
|
|
ContextMenuTestWindow * const
|
|
child = new ContextMenuTestWindow(parent, 'c');
|
|
parent->SetSize(100, 100);
|
|
child->SetSize(0, 0, 50, 50);
|
|
child->SetFocus();
|
|
|
|
wxUIActionSimulator sim;
|
|
const wxPoint origin = parent->ClientToScreen(wxPoint(0, 0));
|
|
|
|
// Right clicking in the child should generate an event for it and the
|
|
// parent.
|
|
g_str.clear();
|
|
sim.MouseMove(origin + wxPoint(10, 10));
|
|
sim.MouseClick(wxMOUSE_BTN_RIGHT);
|
|
|
|
// At least with MSW, for WM_CONTEXTMENU to be synthesized by the system
|
|
// from the right mouse click event, we must dispatch the mouse messages.
|
|
wxYield();
|
|
|
|
CPPUNIT_ASSERT_EQUAL( "cp", g_str );
|
|
|
|
// For some unfathomable reason the test below sporadically fails in wxGTK
|
|
// buildbot builds, so disable it there to avoid spurious failure reports.
|
|
#ifdef __WXGTK__
|
|
if ( IsAutomaticTest() )
|
|
return;
|
|
#endif // __WXGTK__
|
|
|
|
// Right clicking outside the child should generate the event just in the
|
|
// parent.
|
|
g_str.clear();
|
|
sim.MouseMove(origin + wxPoint(60, 60));
|
|
sim.MouseClick(wxMOUSE_BTN_RIGHT);
|
|
wxYield();
|
|
CPPUNIT_ASSERT_EQUAL( "p", g_str );
|
|
}
|
|
|
|
#endif // wxUSE_UIACTIONSIMULATOR
|