68ee7ffa2a
Allow building without wxMenuBar (but with wxMenu), as this class doesn't exist and can't be reasonably implemented under iOS (but wxMenu can and should be, as it's widely used in iOS 14 UI).
801 lines
26 KiB
C++
801 lines
26 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: tests/menu/menu.cpp
|
|
// Purpose: wxMenu unit test
|
|
// Author: wxWidgets team
|
|
// Created: 2010-11-10
|
|
// Copyright: (c) 2010 wxWidgets team
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include "testprec.h"
|
|
|
|
#if wxUSE_MENUBAR
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif // WX_PRECOMP
|
|
|
|
#include "wx/menu.h"
|
|
#include "wx/translation.h"
|
|
#include "wx/uiaction.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// helper
|
|
// ----------------------------------------------------------------------------
|
|
|
|
namespace
|
|
{
|
|
|
|
enum
|
|
{
|
|
MenuTestCase_Foo = 10000,
|
|
MenuTestCase_SelectAll,
|
|
MenuTestCase_Bar,
|
|
MenuTestCase_First
|
|
};
|
|
|
|
void PopulateMenu(wxMenu* menu, const wxString& name, size_t& itemcount)
|
|
{
|
|
// Start at item 1 to make it human-readable ;)
|
|
for (int n=1; n<6; ++n, ++itemcount)
|
|
{
|
|
wxString label = name; label << n;
|
|
menu->Append(MenuTestCase_First + itemcount, label, label + " help string");
|
|
}
|
|
}
|
|
|
|
void RecursivelyCountMenuItems(const wxMenu* menu, size_t& count)
|
|
{
|
|
CPPUNIT_ASSERT( menu );
|
|
|
|
count += menu->GetMenuItemCount();
|
|
for (size_t n=0; n < menu->GetMenuItemCount(); ++n)
|
|
{
|
|
wxMenuItem* item = menu->FindItemByPosition(n);
|
|
if (item->IsSubMenu())
|
|
{
|
|
RecursivelyCountMenuItems(item->GetSubMenu(), count);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // anon namespace
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// test class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class MenuTestCase : public CppUnit::TestCase
|
|
{
|
|
public:
|
|
MenuTestCase() {}
|
|
|
|
virtual void setUp() wxOVERRIDE { CreateFrame(); }
|
|
virtual void tearDown() wxOVERRIDE { m_frame->Destroy(); }
|
|
|
|
private:
|
|
CPPUNIT_TEST_SUITE( MenuTestCase );
|
|
CPPUNIT_TEST( FindInMenubar );
|
|
CPPUNIT_TEST( FindInMenu );
|
|
CPPUNIT_TEST( EnableTop );
|
|
CPPUNIT_TEST( Count );
|
|
CPPUNIT_TEST( Labels );
|
|
#if wxUSE_INTL
|
|
CPPUNIT_TEST( TranslatedMnemonics );
|
|
#endif // wxUSE_INTL
|
|
CPPUNIT_TEST( RadioItems );
|
|
CPPUNIT_TEST( RemoveAdd );
|
|
CPPUNIT_TEST( ChangeBitmap );
|
|
WXUISIM_TEST( Events );
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
void CreateFrame();
|
|
|
|
void FindInMenubar();
|
|
void FindInMenu();
|
|
void EnableTop();
|
|
void Count();
|
|
void Labels();
|
|
#if wxUSE_INTL
|
|
void TranslatedMnemonics();
|
|
#endif // wxUSE_INTL
|
|
void RadioItems();
|
|
void RemoveAdd();
|
|
void ChangeBitmap();
|
|
void Events();
|
|
|
|
wxFrame* m_frame;
|
|
|
|
// Holds the number of menuitems contained in all the menus
|
|
size_t m_itemCount;
|
|
|
|
// Store here the id of a known submenu item, to be searched for later
|
|
int m_submenuItemId;
|
|
|
|
// and a sub-submenu item
|
|
int m_subsubmenuItemId;
|
|
|
|
wxArrayString m_menuLabels;
|
|
|
|
// The menu containing the item with MenuTestCase_Bar id.
|
|
wxMenu* m_menuWithBar;
|
|
|
|
wxDECLARE_NO_COPY_CLASS(MenuTestCase);
|
|
};
|
|
|
|
// register in the unnamed registry so that these tests are run by default
|
|
CPPUNIT_TEST_SUITE_REGISTRATION( MenuTestCase );
|
|
|
|
// also include in its own registry so that these tests can be run alone
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MenuTestCase, "MenuTestCase" );
|
|
|
|
void MenuTestCase::CreateFrame()
|
|
{
|
|
m_frame = new wxFrame(wxTheApp->GetTopWindow(), wxID_ANY, "test frame");
|
|
|
|
wxMenu *fileMenu = new wxMenu;
|
|
wxMenu *helpMenu = new wxMenu;
|
|
wxMenu *subMenu = new wxMenu;
|
|
wxMenu *subsubMenu = new wxMenu;
|
|
|
|
m_itemCount = 0;
|
|
|
|
PopulateMenu(subsubMenu, "Subsubmenu item ", m_itemCount);
|
|
|
|
// Store one of its IDs for later
|
|
m_subsubmenuItemId = MenuTestCase_First + m_itemCount - 2;
|
|
|
|
PopulateMenu(subMenu, "Submenu item ", m_itemCount);
|
|
|
|
// Store one of its IDs for later
|
|
m_submenuItemId = MenuTestCase_First + m_itemCount - 2;
|
|
|
|
subMenu->AppendSubMenu(subsubMenu, "Subsubmen&u", "Test a subsubmenu");
|
|
m_itemCount++;
|
|
|
|
// Check GetTitle() returns the correct string _before_ appending to the bar
|
|
fileMenu->SetTitle("&Foo\tCtrl-F");
|
|
CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", fileMenu->GetTitle() );
|
|
|
|
PopulateMenu(fileMenu, "Filemenu item ", m_itemCount);
|
|
|
|
fileMenu->Append(MenuTestCase_Foo, "&Foo\tCtrl-F", "Test item to be found");
|
|
m_itemCount++;
|
|
fileMenu->Append(MenuTestCase_SelectAll, "Select &all\tCtrl-A",
|
|
"Accelerator conflicting with wxTextCtrl");
|
|
m_itemCount++;
|
|
|
|
|
|
PopulateMenu(helpMenu, "Helpmenu item ", m_itemCount);
|
|
helpMenu->Append(MenuTestCase_Bar, "Bar\tF1");
|
|
m_itemCount++;
|
|
m_menuWithBar = helpMenu;
|
|
helpMenu->AppendSubMenu(subMenu, "Sub&menu", "Test a submenu");
|
|
m_itemCount++;
|
|
|
|
// Use an arraystring here, to help with future tests
|
|
m_menuLabels.Add("&File");
|
|
m_menuLabels.Add("&Help");
|
|
|
|
wxMenuBar *menuBar = new wxMenuBar();
|
|
menuBar->Append(fileMenu, m_menuLabels[0]);
|
|
menuBar->Append(helpMenu, m_menuLabels[1]);
|
|
m_frame->SetMenuBar(menuBar);
|
|
}
|
|
|
|
void MenuTestCase::FindInMenubar()
|
|
{
|
|
wxMenuBar* bar = m_frame->GetMenuBar();
|
|
|
|
// Find by name:
|
|
CPPUNIT_ASSERT( bar->FindMenu("File") != wxNOT_FOUND );
|
|
CPPUNIT_ASSERT( bar->FindMenu("&File") != wxNOT_FOUND );
|
|
CPPUNIT_ASSERT( bar->FindMenu("&Fail") == wxNOT_FOUND );
|
|
|
|
// Find by menu name plus item name:
|
|
CPPUNIT_ASSERT( bar->FindMenuItem("File", "Foo") != wxNOT_FOUND );
|
|
CPPUNIT_ASSERT( bar->FindMenuItem("&File", "&Foo") != wxNOT_FOUND );
|
|
// and using the menu label
|
|
int index = bar->FindMenu("&File");
|
|
CPPUNIT_ASSERT( index != wxNOT_FOUND );
|
|
wxString menulabel = bar->GetMenuLabel(index);
|
|
CPPUNIT_ASSERT( bar->FindMenuItem(menulabel, "&Foo") != wxNOT_FOUND );
|
|
// and title
|
|
wxString menutitle = bar->GetMenu(index)->GetTitle();
|
|
CPPUNIT_ASSERT( bar->FindMenuItem(menutitle, "&Foo") != wxNOT_FOUND );
|
|
|
|
// Find by position:
|
|
for (size_t n=0; n < bar->GetMenuCount(); ++n)
|
|
{
|
|
CPPUNIT_ASSERT( bar->GetMenu(n) );
|
|
}
|
|
|
|
// Find by id:
|
|
wxMenu* menu = NULL;
|
|
wxMenuItem* item = NULL;
|
|
item = bar->FindItem(MenuTestCase_Foo, &menu);
|
|
CPPUNIT_ASSERT( item );
|
|
CPPUNIT_ASSERT( menu );
|
|
// Check that the correct menu was found
|
|
CPPUNIT_ASSERT( menu->FindChildItem(MenuTestCase_Foo) );
|
|
|
|
// Find submenu item:
|
|
item = bar->FindItem(m_submenuItemId, &menu);
|
|
CPPUNIT_ASSERT( item );
|
|
CPPUNIT_ASSERT( menu );
|
|
// and, for completeness, a subsubmenu one:
|
|
item = bar->FindItem(m_subsubmenuItemId, &menu);
|
|
CPPUNIT_ASSERT( item );
|
|
CPPUNIT_ASSERT( menu );
|
|
}
|
|
|
|
void MenuTestCase::FindInMenu()
|
|
{
|
|
wxMenuBar* bar = m_frame->GetMenuBar();
|
|
|
|
// Find by name:
|
|
wxMenu* menuFind = bar->GetMenu(0);
|
|
CPPUNIT_ASSERT( menuFind->FindItem("Foo") != wxNOT_FOUND );
|
|
CPPUNIT_ASSERT( menuFind->FindItem("&Foo") != wxNOT_FOUND );
|
|
// and for submenus
|
|
wxMenu* menuHelp = bar->GetMenu(1);
|
|
CPPUNIT_ASSERT( menuHelp->FindItem("Submenu") != wxNOT_FOUND );
|
|
CPPUNIT_ASSERT( menuHelp->FindItem("Sub&menu") != wxNOT_FOUND );
|
|
|
|
// Find by position:
|
|
size_t n;
|
|
for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
|
|
{
|
|
CPPUNIT_ASSERT( menuHelp->FindItemByPosition(n) );
|
|
}
|
|
|
|
// Find by id:
|
|
CPPUNIT_ASSERT( menuHelp->FindItem(MenuTestCase_Bar) );
|
|
CPPUNIT_ASSERT( !menuHelp->FindItem(MenuTestCase_Foo) );
|
|
|
|
for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
|
|
{
|
|
size_t locatedAt;
|
|
wxMenuItem* itemByPos = menuHelp->FindItemByPosition(n);
|
|
CPPUNIT_ASSERT( itemByPos );
|
|
wxMenuItem* itemById = menuHelp->FindChildItem(itemByPos->GetId(), &locatedAt);
|
|
CPPUNIT_ASSERT_EQUAL( itemByPos, itemById );
|
|
CPPUNIT_ASSERT_EQUAL( locatedAt, n );
|
|
}
|
|
|
|
// Find submenu item:
|
|
for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
|
|
{
|
|
wxMenuItem* item = menuHelp->FindItemByPosition(n);
|
|
if (item->IsSubMenu())
|
|
{
|
|
wxMenu* submenu;
|
|
wxMenuItem* submenuItem = menuHelp->FindItem(m_submenuItemId, &submenu);
|
|
CPPUNIT_ASSERT( submenuItem );
|
|
CPPUNIT_ASSERT( item->GetSubMenu() == submenu );
|
|
}
|
|
}
|
|
}
|
|
|
|
void MenuTestCase::EnableTop()
|
|
{
|
|
wxMenuBar* const bar = m_frame->GetMenuBar();
|
|
CPPUNIT_ASSERT( bar->IsEnabledTop(0) );
|
|
bar->EnableTop( 0, false );
|
|
CPPUNIT_ASSERT( !bar->IsEnabledTop(0) );
|
|
bar->EnableTop( 0, true );
|
|
CPPUNIT_ASSERT( bar->IsEnabledTop(0) );
|
|
}
|
|
|
|
void MenuTestCase::Count()
|
|
{
|
|
wxMenuBar* bar = m_frame->GetMenuBar();
|
|
// I suppose you could call this "counting menubars" :)
|
|
CPPUNIT_ASSERT( bar );
|
|
|
|
CPPUNIT_ASSERT_EQUAL( bar->GetMenuCount(), 2 );
|
|
|
|
size_t count = 0;
|
|
for (size_t n=0; n < bar->GetMenuCount(); ++n)
|
|
{
|
|
RecursivelyCountMenuItems(bar->GetMenu(n), count);
|
|
}
|
|
CPPUNIT_ASSERT_EQUAL( count, m_itemCount );
|
|
}
|
|
|
|
void MenuTestCase::Labels()
|
|
{
|
|
wxMenuBar* bar = m_frame->GetMenuBar();
|
|
CPPUNIT_ASSERT( bar );
|
|
wxMenu* filemenu;
|
|
wxMenuItem* itemFoo = bar->FindItem(MenuTestCase_Foo, &filemenu);
|
|
CPPUNIT_ASSERT( itemFoo );
|
|
CPPUNIT_ASSERT( filemenu );
|
|
|
|
// These return labels including mnemonics/accelerators:
|
|
|
|
// wxMenuBar
|
|
CPPUNIT_ASSERT_EQUAL( "&File", bar->GetMenuLabel(0) );
|
|
CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", bar->GetLabel(MenuTestCase_Foo) );
|
|
|
|
// wxMenu
|
|
CPPUNIT_ASSERT_EQUAL( "&File", filemenu->GetTitle() );
|
|
CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", filemenu->GetLabel(MenuTestCase_Foo) );
|
|
|
|
// wxMenuItem
|
|
CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", itemFoo->GetItemLabel() );
|
|
|
|
// These return labels stripped of mnemonics/accelerators:
|
|
|
|
// wxMenuBar
|
|
CPPUNIT_ASSERT_EQUAL( "File", bar->GetMenuLabelText(0) );
|
|
|
|
// wxMenu
|
|
CPPUNIT_ASSERT_EQUAL( "Foo", filemenu->GetLabelText(MenuTestCase_Foo) );
|
|
|
|
// wxMenuItem
|
|
CPPUNIT_ASSERT_EQUAL( "Foo", itemFoo->GetItemLabelText() );
|
|
CPPUNIT_ASSERT_EQUAL( "Foo", wxMenuItem::GetLabelText("&Foo\tCtrl-F") );
|
|
}
|
|
|
|
#if wxUSE_INTL
|
|
|
|
static wxString
|
|
GetTranslatedString(const wxTranslations& trans, const wxString& s)
|
|
{
|
|
const wxString* t = trans.GetTranslatedString(s);
|
|
return t ? *t : s;
|
|
}
|
|
|
|
void MenuTestCase::TranslatedMnemonics()
|
|
{
|
|
// Check that appended mnemonics are correctly stripped;
|
|
// see https://trac.wxwidgets.org/ticket/16736
|
|
wxTranslations trans;
|
|
trans.SetLanguage(wxLANGUAGE_JAPANESE);
|
|
wxFileTranslationsLoader::AddCatalogLookupPathPrefix("./intl");
|
|
CPPUNIT_ASSERT( trans.AddCatalog("internat") );
|
|
|
|
// Check the translation is being used:
|
|
CPPUNIT_ASSERT( wxString("&File") != GetTranslatedString(trans, "&File") );
|
|
|
|
wxString filemenu = m_frame->GetMenuBar()->GetMenuLabel(0);
|
|
CPPUNIT_ASSERT_EQUAL
|
|
(
|
|
wxStripMenuCodes(GetTranslatedString(trans, "&File"), wxStrip_Menu),
|
|
wxStripMenuCodes(GetTranslatedString(trans, filemenu), wxStrip_Menu)
|
|
);
|
|
|
|
// Test strings that have shortcuts. Duplicate non-mnemonic translations
|
|
// exist for both "Edit" and "View", for ease of comparison
|
|
CPPUNIT_ASSERT_EQUAL
|
|
(
|
|
GetTranslatedString(trans, "Edit"),
|
|
wxStripMenuCodes(GetTranslatedString(trans, "E&dit\tCtrl+E"), wxStrip_Menu)
|
|
);
|
|
|
|
// "Vie&w" also has a space before the (&W)
|
|
CPPUNIT_ASSERT_EQUAL
|
|
(
|
|
GetTranslatedString(trans, "View"),
|
|
wxStripMenuCodes(GetTranslatedString(trans, "Vie&w\tCtrl+V"), wxStrip_Menu)
|
|
);
|
|
|
|
// Test a 'normal' mnemonic too: the translation is "Preten&d"
|
|
CPPUNIT_ASSERT_EQUAL
|
|
(
|
|
"Pretend",
|
|
wxStripMenuCodes(GetTranslatedString(trans, "B&ogus"), wxStrip_Menu)
|
|
);
|
|
}
|
|
#endif // wxUSE_INTL
|
|
|
|
void MenuTestCase::RadioItems()
|
|
{
|
|
wxMenuBar * const bar = m_frame->GetMenuBar();
|
|
wxMenu * const menu = new wxMenu;
|
|
bar->Append(menu, "&Radio");
|
|
|
|
// Adding consecutive radio items creates a radio group.
|
|
menu->AppendRadioItem(MenuTestCase_First, "Radio 0");
|
|
menu->AppendRadioItem(MenuTestCase_First + 1, "Radio 1");
|
|
|
|
// First item of a radio group is checked by default.
|
|
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
|
|
|
|
// Subsequent items in a group are not checked.
|
|
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 1) );
|
|
|
|
#ifdef __WXQT__
|
|
WARN("Radio check test does not work under Qt");
|
|
#else
|
|
// Checking the second one make the first one unchecked however.
|
|
menu->Check(MenuTestCase_First + 1, true);
|
|
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First) );
|
|
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 1) );
|
|
menu->Check(MenuTestCase_First, true);
|
|
#endif
|
|
|
|
// Adding more radio items after a separator creates another radio group...
|
|
menu->AppendSeparator();
|
|
menu->AppendRadioItem(MenuTestCase_First + 2, "Radio 2");
|
|
menu->AppendRadioItem(MenuTestCase_First + 3, "Radio 3");
|
|
menu->AppendRadioItem(MenuTestCase_First + 4, "Radio 4");
|
|
|
|
// ... which is independent from the first one.
|
|
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
|
|
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 2) );
|
|
|
|
#ifdef __WXQT__
|
|
WARN("Radio check test does not work under Qt");
|
|
#else
|
|
menu->Check(MenuTestCase_First + 3, true);
|
|
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 3) );
|
|
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 2) );
|
|
|
|
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
|
|
menu->Check(MenuTestCase_First + 2, true);
|
|
#endif
|
|
|
|
// Insert an item in the middle of an existing radio group.
|
|
menu->InsertRadioItem(4, MenuTestCase_First + 5, "Radio 5");
|
|
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 2) );
|
|
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 5) );
|
|
|
|
#ifdef __WXQT__
|
|
WARN("Radio check test does not work under Qt");
|
|
#else
|
|
menu->Check( MenuTestCase_First + 5, true );
|
|
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 3) );
|
|
|
|
menu->Check( MenuTestCase_First + 3, true );
|
|
#endif
|
|
|
|
// Prepend a couple of items before the first group.
|
|
menu->PrependRadioItem(MenuTestCase_First + 6, "Radio 6");
|
|
menu->PrependRadioItem(MenuTestCase_First + 7, "Radio 7");
|
|
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 6) );
|
|
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 7) );
|
|
|
|
#ifdef __WXQT__
|
|
WARN("Radio check test does not work under Qt");
|
|
#else
|
|
menu->Check(MenuTestCase_First + 7, true);
|
|
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 1) );
|
|
|
|
|
|
// Check that the last radio group still works as expected.
|
|
menu->Check(MenuTestCase_First + 4, true);
|
|
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 5) );
|
|
#endif
|
|
}
|
|
|
|
void MenuTestCase::RemoveAdd()
|
|
{
|
|
wxMenuBar* bar = m_frame->GetMenuBar();
|
|
|
|
wxMenu* menu0 = bar->GetMenu(0);
|
|
wxMenu* menu1 = bar->GetMenu(1);
|
|
wxMenuItem* item = new wxMenuItem(menu0, MenuTestCase_Foo + 100, "t&ext\tCtrl-E");
|
|
menu0->Insert(0, item);
|
|
CPPUNIT_ASSERT( menu0->FindItemByPosition(0) == item );
|
|
menu0->Remove(item);
|
|
CPPUNIT_ASSERT( menu0->FindItemByPosition(0) != item );
|
|
menu1->Insert(0, item);
|
|
CPPUNIT_ASSERT( menu1->FindItemByPosition(0) == item );
|
|
menu1->Remove(item);
|
|
CPPUNIT_ASSERT( menu1->FindItemByPosition(0) != item );
|
|
menu0->Insert(0, item);
|
|
CPPUNIT_ASSERT( menu0->FindItemByPosition(0) == item );
|
|
menu0->Delete(item);
|
|
}
|
|
|
|
void MenuTestCase::ChangeBitmap()
|
|
{
|
|
wxMenu *menu = new wxMenu;
|
|
|
|
wxMenuItem *item = new wxMenuItem(menu, wxID_ANY, "Item");
|
|
menu->Append(item);
|
|
|
|
// On Windows Vista (and later) calling SetBitmap, *after* the menu
|
|
// item has already been added, used to result in a stack overflow:
|
|
// [Do]SetBitmap can call GetHBitmapForMenu which will call SetBitmap
|
|
// again etc...
|
|
item->SetBitmap( wxBitmap(1, 1) );
|
|
|
|
|
|
// Force owner drawn usage by having a bitmap that's wider than the
|
|
// standard size. This results in rearranging the parent menu which
|
|
// hasn't always worked properly and lead to a null pointer exception.
|
|
item->SetBitmap( wxBitmap(512, 1) );
|
|
|
|
wxDELETE(menu);
|
|
}
|
|
|
|
#if wxUSE_UIACTIONSIMULATOR
|
|
|
|
// In C++98 this class can't be defined inside Events() method, unfortunately,
|
|
// as its OnMenu() method wouldn't be usable with template Bind() then.
|
|
class MenuEventHandler : public wxEvtHandler
|
|
{
|
|
public:
|
|
MenuEventHandler(wxWindow* win)
|
|
: m_win(win)
|
|
{
|
|
m_win->Bind(wxEVT_MENU, &MenuEventHandler::OnMenu, this);
|
|
|
|
m_gotEvent = false;
|
|
m_event = NULL;
|
|
}
|
|
|
|
virtual ~MenuEventHandler()
|
|
{
|
|
m_win->Unbind(wxEVT_MENU, &MenuEventHandler::OnMenu, this);
|
|
|
|
delete m_event;
|
|
}
|
|
|
|
const wxCommandEvent& GetEvent()
|
|
{
|
|
CPPUNIT_ASSERT( m_gotEvent );
|
|
|
|
m_gotEvent = false;
|
|
|
|
return *m_event;
|
|
}
|
|
|
|
bool GotEvent() const
|
|
{
|
|
return m_gotEvent;
|
|
}
|
|
|
|
private:
|
|
void OnMenu(wxCommandEvent& event)
|
|
{
|
|
CPPUNIT_ASSERT( !m_gotEvent );
|
|
|
|
delete m_event;
|
|
m_event = static_cast<wxCommandEvent*>(event.Clone());
|
|
m_gotEvent = true;
|
|
}
|
|
|
|
wxWindow* const m_win;
|
|
wxCommandEvent* m_event;
|
|
bool m_gotEvent;
|
|
};
|
|
|
|
#endif // wxUSE_UIACTIONSIMULATOR
|
|
|
|
void MenuTestCase::Events()
|
|
{
|
|
#if wxUSE_UIACTIONSIMULATOR
|
|
MenuEventHandler handler(m_frame);
|
|
|
|
// Invoke the accelerator.
|
|
m_frame->Show();
|
|
m_frame->SetFocus();
|
|
wxYield();
|
|
|
|
wxUIActionSimulator sim;
|
|
sim.KeyDown(WXK_F1);
|
|
sim.KeyUp(WXK_F1);
|
|
wxYield();
|
|
|
|
const wxCommandEvent& ev = handler.GetEvent();
|
|
CPPUNIT_ASSERT_EQUAL( static_cast<int>(MenuTestCase_Bar), ev.GetId() );
|
|
|
|
wxObject* const src = ev.GetEventObject();
|
|
CPPUNIT_ASSERT( src );
|
|
|
|
CPPUNIT_ASSERT_EQUAL( "wxMenu",
|
|
wxString(src->GetClassInfo()->GetClassName()) );
|
|
CPPUNIT_ASSERT_EQUAL( static_cast<wxObject*>(m_menuWithBar),
|
|
src );
|
|
|
|
// Invoke another accelerator, it should also work.
|
|
sim.Char('A', wxMOD_CONTROL);
|
|
wxYield();
|
|
|
|
const wxCommandEvent& ev2 = handler.GetEvent();
|
|
CHECK( ev2.GetId() == static_cast<int>(MenuTestCase_SelectAll) );
|
|
|
|
// Now create a text control which uses the same accelerator for itself and
|
|
// check that when the text control has focus, the accelerator does _not_
|
|
// work.
|
|
wxTextCtrl* const text = new wxTextCtrl(m_frame, wxID_ANY, "Testing");
|
|
text->SetFocus();
|
|
|
|
sim.Char('A', wxMOD_CONTROL);
|
|
wxYield();
|
|
|
|
CHECK( !handler.GotEvent() );
|
|
#endif // wxUSE_UIACTIONSIMULATOR
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
void VerifyAccelAssigned( wxString labelText, int keycode )
|
|
{
|
|
wxAcceleratorEntry* entry = wxAcceleratorEntry::Create( labelText );
|
|
|
|
CHECK( entry );
|
|
CHECK( entry->GetKeyCode() == keycode );
|
|
}
|
|
|
|
struct key
|
|
{
|
|
int keycode;
|
|
wxString name;
|
|
bool skip;
|
|
};
|
|
key modKeys[] =
|
|
{
|
|
{ wxACCEL_NORMAL, "Normal", false },
|
|
{ wxACCEL_CTRL, "Ctrl", false },
|
|
{ wxACCEL_SHIFT, "Shift", false },
|
|
{ wxACCEL_ALT, "Alt", false }
|
|
};
|
|
/*
|
|
The keys marked as skip below are not supported as accelerator
|
|
keys on GTK.
|
|
*/
|
|
key specialKeys[] =
|
|
{
|
|
{ WXK_F1, "WXK_F1", false },
|
|
{ WXK_F2, "WXK_F2", false },
|
|
{ WXK_F3, "WXK_F3", false },
|
|
{ WXK_F4, "WXK_F4", false },
|
|
{ WXK_F5, "WXK_F5", false },
|
|
{ WXK_F6, "WXK_F6", false },
|
|
{ WXK_F7, "WXK_F7", false },
|
|
{ WXK_F8, "WXK_F8", false },
|
|
{ WXK_F9, "WXK_F9", false },
|
|
{ WXK_F10, "WXK_F10", false },
|
|
{ WXK_F11, "WXK_F11", false },
|
|
{ WXK_F12, "WXK_F12", false },
|
|
{ WXK_F13, "WXK_F13", false },
|
|
{ WXK_F14, "WXK_F14", false },
|
|
{ WXK_F15, "WXK_F15", false },
|
|
{ WXK_F16, "WXK_F16", false },
|
|
{ WXK_F17, "WXK_F17", false },
|
|
{ WXK_F18, "WXK_F18", false },
|
|
{ WXK_F19, "WXK_F19", false },
|
|
{ WXK_F20, "WXK_F20", false },
|
|
{ WXK_F21, "WXK_F21", false },
|
|
{ WXK_F22, "WXK_F22", false },
|
|
{ WXK_F23, "WXK_F23", false },
|
|
{ WXK_F24, "WXK_F24", false },
|
|
{ WXK_INSERT, "WXK_INSERT", false },
|
|
{ WXK_DELETE, "WXK_DELETE", false },
|
|
{ WXK_UP, "WXK_UP", false },
|
|
{ WXK_DOWN, "WXK_DOWN", false },
|
|
{ WXK_PAGEUP, "WXK_PAGEUP", false },
|
|
{ WXK_PAGEDOWN, "WXK_PAGEDOWN", false },
|
|
{ WXK_LEFT, "WXK_LEFT", false },
|
|
{ WXK_RIGHT, "WXK_RIGHT", false },
|
|
{ WXK_HOME, "WXK_HOME", false },
|
|
{ WXK_END, "WXK_END", false },
|
|
{ WXK_RETURN, "WXK_RETURN", false },
|
|
{ WXK_BACK, "WXK_BACK", false },
|
|
{ WXK_TAB, "WXK_TAB", true },
|
|
{ WXK_ESCAPE, "WXK_ESCAPE", false },
|
|
{ WXK_SPACE, "WXK_SPACE", false },
|
|
{ WXK_MULTIPLY, "WXK_MULTIPLY", false },
|
|
{ WXK_ADD, "WXK_ADD", true },
|
|
{ WXK_SEPARATOR, "WXK_SEPARATOR", true },
|
|
{ WXK_SUBTRACT, "WXK_SUBTRACT", true },
|
|
{ WXK_DECIMAL, "WXK_DECIMAL", true },
|
|
{ WXK_DIVIDE, "WXK_DIVIDE", true },
|
|
{ WXK_CANCEL, "WXK_CANCEL", false },
|
|
{ WXK_CLEAR, "WXK_CLEAR", false },
|
|
{ WXK_MENU, "WXK_MENU", false },
|
|
{ WXK_PAUSE, "WXK_PAUSE", false },
|
|
{ WXK_CAPITAL, "WXK_CAPITAL", true },
|
|
{ WXK_SELECT, "WXK_SELECT", false },
|
|
{ WXK_PRINT, "WXK_PRINT", false },
|
|
{ WXK_EXECUTE, "WXK_EXECUTE", false },
|
|
{ WXK_SNAPSHOT, "WXK_SNAPSHOT", true },
|
|
{ WXK_HELP, "WXK_HELP", false },
|
|
{ WXK_NUMLOCK, "WXK_NUMLOCK", true },
|
|
{ WXK_SCROLL, "WXK_SCROLL", true },
|
|
{ WXK_NUMPAD_INSERT, "WXK_NUMPAD_INSERT", false },
|
|
{ WXK_NUMPAD_DELETE, "WXK_NUMPAD_DELETE", false },
|
|
{ WXK_NUMPAD_SPACE, "WXK_NUMPAD_SPACE", false },
|
|
{ WXK_NUMPAD_TAB, "WXK_NUMPAD_TAB", true },
|
|
{ WXK_NUMPAD_ENTER, "WXK_NUMPAD_ENTER", false },
|
|
{ WXK_NUMPAD_F1, "WXK_NUMPAD_F1", false },
|
|
{ WXK_NUMPAD_F2, "WXK_NUMPAD_F2", false },
|
|
{ WXK_NUMPAD_F3, "WXK_NUMPAD_F3", false },
|
|
{ WXK_NUMPAD_F4, "WXK_NUMPAD_F4", false },
|
|
{ WXK_NUMPAD_HOME, "WXK_NUMPAD_HOME", false },
|
|
{ WXK_NUMPAD_LEFT, "WXK_NUMPAD_LEFT", false },
|
|
{ WXK_NUMPAD_UP, "WXK_NUMPAD_UP", false },
|
|
{ WXK_NUMPAD_RIGHT, "WXK_NUMPAD_RIGHT", false },
|
|
{ WXK_NUMPAD_DOWN, "WXK_NUMPAD_DOWN", false },
|
|
{ WXK_NUMPAD_PAGEUP, "WXK_NUMPAD_PAGEUP", false },
|
|
{ WXK_NUMPAD_PAGEDOWN, "WXK_NUMPAD_PAGEDOWN", false },
|
|
{ WXK_NUMPAD_END, "WXK_NUMPAD_END", false },
|
|
{ WXK_NUMPAD_BEGIN, "WXK_NUMPAD_BEGIN", false },
|
|
{ WXK_NUMPAD_EQUAL, "WXK_NUMPAD_EQUAL", false },
|
|
{ WXK_NUMPAD_MULTIPLY, "WXK_NUMPAD_MULTIPLY", false },
|
|
{ WXK_NUMPAD_ADD, "WXK_NUMPAD_ADD", false },
|
|
{ WXK_NUMPAD_SEPARATOR, "WXK_NUMPAD_SEPARATOR", false },
|
|
{ WXK_NUMPAD_SUBTRACT, "WXK_NUMPAD_SUBTRACT", false },
|
|
{ WXK_NUMPAD_DECIMAL, "WXK_NUMPAD_DECIMAL", false },
|
|
{ WXK_NUMPAD_DIVIDE, "WXK_NUMPAD_DIVIDE", false },
|
|
{ WXK_NUMPAD0, "WXK_NUMPAD0", false },
|
|
{ WXK_NUMPAD1, "WXK_NUMPAD1", false },
|
|
{ WXK_NUMPAD2, "WXK_NUMPAD2", false },
|
|
{ WXK_NUMPAD3, "WXK_NUMPAD3", false },
|
|
{ WXK_NUMPAD4, "WXK_NUMPAD4", false },
|
|
{ WXK_NUMPAD5, "WXK_NUMPAD5", false },
|
|
{ WXK_NUMPAD6, "WXK_NUMPAD6", false },
|
|
{ WXK_NUMPAD7, "WXK_NUMPAD7", false },
|
|
{ WXK_NUMPAD8, "WXK_NUMPAD8", false },
|
|
{ WXK_NUMPAD9, "WXK_NUMPAD9", false },
|
|
{ WXK_WINDOWS_LEFT, "WXK_WINDOWS_LEFT", true },
|
|
{ WXK_WINDOWS_RIGHT, "WXK_WINDOWS_RIGHT", true },
|
|
{ WXK_WINDOWS_MENU, "WXK_WINDOWS_MENU", false },
|
|
{ WXK_COMMAND, "WXK_COMMAND", true }
|
|
};
|
|
|
|
}
|
|
|
|
TEST_CASE( "wxMenuItemAccelEntry", "[menu][accelentry]" )
|
|
{
|
|
wxMenu* menu = new wxMenu;
|
|
|
|
menu->Append( wxID_ANY, "Test" );
|
|
wxMenuItem* item = menu->FindItemByPosition( 0 );
|
|
|
|
SECTION( "Modifier keys" )
|
|
{
|
|
for ( unsigned i = 0; i < WXSIZEOF(modKeys); i++ )
|
|
{
|
|
const key& k = modKeys[i];
|
|
|
|
INFO( wxString::Format( "Modifier: %s", k.name ) );
|
|
wxAcceleratorEntry accelEntry( k.keycode, 'A' , wxID_ANY, item );
|
|
item->SetAccel( &accelEntry );
|
|
|
|
wxString labelText = item->GetItemLabel();
|
|
INFO( wxString::Format( "Label text: %s", labelText ) );
|
|
|
|
VerifyAccelAssigned( labelText, 'A' );
|
|
}
|
|
}
|
|
|
|
SECTION( "Special keys" )
|
|
{
|
|
for ( unsigned i = 0; i < WXSIZEOF(specialKeys); i++ )
|
|
{
|
|
const key& k = specialKeys[i];
|
|
|
|
if( k.skip )
|
|
continue;
|
|
|
|
INFO( wxString::Format( "Keycode: %s", k.name ) );
|
|
wxAcceleratorEntry accelEntry( wxACCEL_CTRL, k.keycode, wxID_ANY, item );
|
|
item->SetAccel( &accelEntry );
|
|
|
|
wxString labelText = item->GetItemLabel();
|
|
INFO( wxString::Format( "Label text: %s", labelText ) );
|
|
|
|
VerifyAccelAssigned( labelText, k.keycode );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|