mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-08-18 01:19:45 +08:00
This is a combination of running clang-tidy with modernize-use-nullptr check for some ports (GTK, X11, OSX) and manual changes to the ports for which it couldn't be used easily (MSW, DFB) and also manually updating the docs. Also replace NULL with null or nullptr in the comments as this is more consistent with the use of nullptr in the code and makes it simpler to grep for the remaining occurrences of NULL itself. And also use null in the assert messages. Only a few occurrences of "NULL" are still left in non-C files, mostly corresponding to unclear comments or string output which it might not be safe to change.
860 lines
28 KiB
C++
860 lines
28 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
|
|
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif // WX_PRECOMP
|
|
|
|
#include "wx/menu.h"
|
|
#include "wx/scopedptr.h"
|
|
#include "wx/translation.h"
|
|
#include "wx/uiaction.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// helper
|
|
// ----------------------------------------------------------------------------
|
|
|
|
namespace
|
|
{
|
|
|
|
enum
|
|
{
|
|
MenuTestCase_Foo = 10000,
|
|
MenuTestCase_SelectAll,
|
|
MenuTestCase_Bar,
|
|
MenuTestCase_ExtraAccel,
|
|
MenuTestCase_ExtraAccels,
|
|
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() override { CreateFrame(); }
|
|
virtual void tearDown() override { 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++;
|
|
|
|
// Test adding an extra accelerator to the item before adding it to the menu.
|
|
wxAcceleratorEntry entry;
|
|
|
|
wxMenuItem* const
|
|
extraAccel = new wxMenuItem(fileMenu, MenuTestCase_ExtraAccel, "Extra accels");
|
|
|
|
CHECK( entry.FromString("Ctrl-U") );
|
|
extraAccel->SetAccel(&entry);
|
|
|
|
CHECK( entry.FromString("Ctrl-V") );
|
|
extraAccel->AddExtraAccel(entry);
|
|
|
|
fileMenu->Append(extraAccel);
|
|
m_itemCount++;
|
|
|
|
// And now also test adding 2 of them after creating the initial menu item.
|
|
wxMenuItem* const
|
|
extraAccels = fileMenu->Append(MenuTestCase_ExtraAccels, "Extra accels 2");
|
|
m_itemCount++;
|
|
|
|
CHECK( entry.FromString("Ctrl-T") );
|
|
extraAccels->AddExtraAccel(entry);
|
|
|
|
CHECK(entry.FromString("Shift-Ctrl-W"));
|
|
extraAccels->AddExtraAccel(entry);
|
|
|
|
CHECK(entry.FromString("Ctrl-W"));
|
|
extraAccels->SetAccel(&entry);
|
|
|
|
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 = nullptr;
|
|
wxMenuItem* item = nullptr;
|
|
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://github.com/wxWidgets/wxWidgets/issues/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_event = nullptr;
|
|
}
|
|
|
|
virtual ~MenuEventHandler()
|
|
{
|
|
m_win->Unbind(wxEVT_MENU, &MenuEventHandler::OnMenu, this);
|
|
|
|
delete m_event;
|
|
}
|
|
|
|
// Check that we received an event with the given ID and return the event
|
|
// object if we did (otherwise fail the test and return nullptr).
|
|
const wxObject* CheckGot(int expectedId)
|
|
{
|
|
if ( !m_event )
|
|
{
|
|
FAIL("Event not generated");
|
|
return nullptr;
|
|
}
|
|
|
|
CHECK( m_event->GetId() == expectedId );
|
|
|
|
const wxObject* const src = m_event->GetEventObject();
|
|
|
|
delete m_event;
|
|
m_event = nullptr;
|
|
|
|
return src;
|
|
}
|
|
|
|
bool GotEvent() const
|
|
{
|
|
return m_event != nullptr;
|
|
}
|
|
|
|
private:
|
|
void OnMenu(wxCommandEvent& event)
|
|
{
|
|
CHECK( !m_event );
|
|
|
|
m_event = static_cast<wxCommandEvent*>(event.Clone());
|
|
}
|
|
|
|
wxWindow* const m_win;
|
|
wxCommandEvent* m_event;
|
|
};
|
|
|
|
#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();
|
|
|
|
INFO("Expecting event for F1");
|
|
if ( const wxObject* const src = handler.CheckGot(MenuTestCase_Bar) )
|
|
{
|
|
CHECK( wxString(src->GetClassInfo()->GetClassName()) == "wxMenu" );
|
|
CHECK( src == m_menuWithBar );
|
|
}
|
|
|
|
// Invoke another accelerator, it should also work.
|
|
sim.Char('A', wxMOD_CONTROL);
|
|
wxYield();
|
|
|
|
INFO("Expecting event for Ctrl-A");
|
|
handler.CheckGot(MenuTestCase_SelectAll);
|
|
|
|
// Invoke accelerator and extra accelerators, all of them should work.
|
|
sim.Char('U', wxMOD_CONTROL);
|
|
wxYield();
|
|
INFO("Expecting event for Ctrl-U");
|
|
handler.CheckGot(MenuTestCase_ExtraAccel);
|
|
|
|
sim.Char('V', wxMOD_CONTROL);
|
|
wxYield();
|
|
INFO("Expecting event for Ctrl-V");
|
|
handler.CheckGot(MenuTestCase_ExtraAccel);
|
|
|
|
sim.Char('W', wxMOD_CONTROL);
|
|
wxYield();
|
|
INFO("Expecting event for Ctrl-W");
|
|
handler.CheckGot(MenuTestCase_ExtraAccels);
|
|
|
|
sim.Char('T', wxMOD_CONTROL);
|
|
wxYield();
|
|
INFO("Expecting event for Ctrl-T");
|
|
handler.CheckGot(MenuTestCase_ExtraAccels);
|
|
|
|
sim.Char('W', wxMOD_CONTROL | wxMOD_SHIFT);
|
|
wxYield();
|
|
INFO("Expecting event for Ctrl-Shift-W");
|
|
handler.CheckGot(MenuTestCase_ExtraAccels);
|
|
|
|
// 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 )
|
|
{
|
|
const wxScopedPtr<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
|