1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        tests/menu/menu.cpp
3 // Purpose:     wxMenu unit test
4 // Author:      wxWidgets team
5 // Created:     2010-11-10
6 // Copyright:   (c) 2010 wxWidgets team
7 ///////////////////////////////////////////////////////////////////////////////
8 
9 // ----------------------------------------------------------------------------
10 // headers
11 // ----------------------------------------------------------------------------
12 
13 #include "testprec.h"
14 
15 #if wxUSE_MENUBAR
16 
17 
18 #ifndef WX_PRECOMP
19     #include "wx/wx.h"
20 #endif // WX_PRECOMP
21 
22 #include "wx/menu.h"
23 #include "wx/scopedptr.h"
24 #include "wx/translation.h"
25 #include "wx/uiaction.h"
26 
27 #include <stdarg.h>
28 
29 // ----------------------------------------------------------------------------
30 // helper
31 // ----------------------------------------------------------------------------
32 
33 namespace
34 {
35 
36 enum
37 {
38     MenuTestCase_Foo = 10000,
39     MenuTestCase_SelectAll,
40     MenuTestCase_Bar,
41     MenuTestCase_First
42 };
43 
PopulateMenu(wxMenu * menu,const wxString & name,size_t & itemcount)44 void PopulateMenu(wxMenu* menu, const wxString& name,  size_t& itemcount)
45 {
46     // Start at item 1 to make it human-readable ;)
47     for (int n=1; n<6; ++n, ++itemcount)
48     {
49         wxString label = name; label << n;
50         menu->Append(MenuTestCase_First + itemcount, label, label + " help string");
51     }
52 }
53 
RecursivelyCountMenuItems(const wxMenu * menu,size_t & count)54 void RecursivelyCountMenuItems(const wxMenu* menu, size_t& count)
55 {
56     CPPUNIT_ASSERT( menu );
57 
58     count += menu->GetMenuItemCount();
59     for (size_t n=0; n < menu->GetMenuItemCount(); ++n)
60     {
61         wxMenuItem* item = menu->FindItemByPosition(n);
62         if (item->IsSubMenu())
63         {
64             RecursivelyCountMenuItems(item->GetSubMenu(), count);
65         }
66     }
67 }
68 
69 } // anon namespace
70 
71 
72 // ----------------------------------------------------------------------------
73 // test class
74 // ----------------------------------------------------------------------------
75 
76 class MenuTestCase : public CppUnit::TestCase
77 {
78 public:
MenuTestCase()79     MenuTestCase() {}
80 
setUp()81     virtual void setUp() wxOVERRIDE { CreateFrame(); }
tearDown()82     virtual void tearDown() wxOVERRIDE { m_frame->Destroy(); }
83 
84 private:
85     CPPUNIT_TEST_SUITE( MenuTestCase );
86         CPPUNIT_TEST( FindInMenubar );
87         CPPUNIT_TEST( FindInMenu );
88         CPPUNIT_TEST( EnableTop );
89         CPPUNIT_TEST( Count );
90         CPPUNIT_TEST( Labels );
91 #if wxUSE_INTL
92         CPPUNIT_TEST( TranslatedMnemonics );
93 #endif // wxUSE_INTL
94         CPPUNIT_TEST( RadioItems );
95         CPPUNIT_TEST( RemoveAdd );
96         CPPUNIT_TEST( ChangeBitmap );
97         WXUISIM_TEST( Events );
98     CPPUNIT_TEST_SUITE_END();
99 
100     void CreateFrame();
101 
102     void FindInMenubar();
103     void FindInMenu();
104     void EnableTop();
105     void Count();
106     void Labels();
107 #if wxUSE_INTL
108     void TranslatedMnemonics();
109 #endif // wxUSE_INTL
110     void RadioItems();
111     void RemoveAdd();
112     void ChangeBitmap();
113     void Events();
114 
115     wxFrame* m_frame;
116 
117     // Holds the number of menuitems contained in all the menus
118     size_t m_itemCount;
119 
120     // Store here the id of a known submenu item, to be searched for later
121     int m_submenuItemId;
122 
123     // and a sub-submenu item
124     int m_subsubmenuItemId;
125 
126     wxArrayString m_menuLabels;
127 
128     // The menu containing the item with MenuTestCase_Bar id.
129     wxMenu* m_menuWithBar;
130 
131     wxDECLARE_NO_COPY_CLASS(MenuTestCase);
132 };
133 
134 // register in the unnamed registry so that these tests are run by default
135 CPPUNIT_TEST_SUITE_REGISTRATION( MenuTestCase );
136 
137 // also include in its own registry so that these tests can be run alone
138 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MenuTestCase, "MenuTestCase" );
139 
CreateFrame()140 void MenuTestCase::CreateFrame()
141 {
142     m_frame = new wxFrame(wxTheApp->GetTopWindow(), wxID_ANY, "test frame");
143 
144     wxMenu *fileMenu = new wxMenu;
145     wxMenu *helpMenu = new wxMenu;
146     wxMenu *subMenu = new wxMenu;
147     wxMenu *subsubMenu = new wxMenu;
148 
149     m_itemCount = 0;
150 
151     PopulateMenu(subsubMenu, "Subsubmenu item ", m_itemCount);
152 
153     // Store one of its IDs for later
154     m_subsubmenuItemId = MenuTestCase_First + m_itemCount - 2;
155 
156     PopulateMenu(subMenu, "Submenu item ", m_itemCount);
157 
158     // Store one of its IDs for later
159     m_submenuItemId = MenuTestCase_First + m_itemCount - 2;
160 
161     subMenu->AppendSubMenu(subsubMenu, "Subsubmen&u", "Test a subsubmenu");
162     m_itemCount++;
163 
164     // Check GetTitle() returns the correct string _before_ appending to the bar
165     fileMenu->SetTitle("&Foo\tCtrl-F");
166     CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", fileMenu->GetTitle() );
167 
168     PopulateMenu(fileMenu, "Filemenu item ", m_itemCount);
169 
170     fileMenu->Append(MenuTestCase_Foo, "&Foo\tCtrl-F", "Test item to be found");
171     m_itemCount++;
172     fileMenu->Append(MenuTestCase_SelectAll, "Select &all\tCtrl-A",
173                      "Accelerator conflicting with wxTextCtrl");
174     m_itemCount++;
175 
176 
177     PopulateMenu(helpMenu, "Helpmenu item ", m_itemCount);
178     helpMenu->Append(MenuTestCase_Bar, "Bar\tF1");
179     m_itemCount++;
180     m_menuWithBar = helpMenu;
181     helpMenu->AppendSubMenu(subMenu, "Sub&menu", "Test a submenu");
182     m_itemCount++;
183 
184     // Use an arraystring here, to help with future tests
185     m_menuLabels.Add("&File");
186     m_menuLabels.Add("&Help");
187 
188     wxMenuBar *menuBar = new wxMenuBar();
189     menuBar->Append(fileMenu, m_menuLabels[0]);
190     menuBar->Append(helpMenu, m_menuLabels[1]);
191     m_frame->SetMenuBar(menuBar);
192 }
193 
FindInMenubar()194 void MenuTestCase::FindInMenubar()
195 {
196     wxMenuBar* bar = m_frame->GetMenuBar();
197 
198     // Find by name:
199     CPPUNIT_ASSERT( bar->FindMenu("File") != wxNOT_FOUND );
200     CPPUNIT_ASSERT( bar->FindMenu("&File") != wxNOT_FOUND );
201     CPPUNIT_ASSERT( bar->FindMenu("&Fail") == wxNOT_FOUND );
202 
203     // Find by menu name plus item name:
204     CPPUNIT_ASSERT( bar->FindMenuItem("File", "Foo") != wxNOT_FOUND );
205     CPPUNIT_ASSERT( bar->FindMenuItem("&File", "&Foo") != wxNOT_FOUND );
206     // and using the menu label
207     int index = bar->FindMenu("&File");
208     CPPUNIT_ASSERT( index != wxNOT_FOUND );
209     wxString menulabel = bar->GetMenuLabel(index);
210     CPPUNIT_ASSERT( bar->FindMenuItem(menulabel, "&Foo") != wxNOT_FOUND );
211     // and title
212     wxString menutitle = bar->GetMenu(index)->GetTitle();
213     CPPUNIT_ASSERT( bar->FindMenuItem(menutitle, "&Foo") != wxNOT_FOUND );
214 
215     // Find by position:
216     for (size_t n=0; n < bar->GetMenuCount(); ++n)
217     {
218         CPPUNIT_ASSERT( bar->GetMenu(n) );
219     }
220 
221     // Find by id:
222     wxMenu* menu = NULL;
223     wxMenuItem* item = NULL;
224     item = bar->FindItem(MenuTestCase_Foo, &menu);
225     CPPUNIT_ASSERT( item );
226     CPPUNIT_ASSERT( menu );
227     // Check that the correct menu was found
228     CPPUNIT_ASSERT( menu->FindChildItem(MenuTestCase_Foo) );
229 
230     // Find submenu item:
231     item = bar->FindItem(m_submenuItemId, &menu);
232     CPPUNIT_ASSERT( item );
233     CPPUNIT_ASSERT( menu );
234     // and, for completeness, a subsubmenu one:
235     item = bar->FindItem(m_subsubmenuItemId, &menu);
236     CPPUNIT_ASSERT( item );
237     CPPUNIT_ASSERT( menu );
238 }
239 
FindInMenu()240 void MenuTestCase::FindInMenu()
241 {
242     wxMenuBar* bar = m_frame->GetMenuBar();
243 
244     // Find by name:
245     wxMenu* menuFind = bar->GetMenu(0);
246     CPPUNIT_ASSERT( menuFind->FindItem("Foo") != wxNOT_FOUND );
247     CPPUNIT_ASSERT( menuFind->FindItem("&Foo") != wxNOT_FOUND );
248     // and for submenus
249     wxMenu* menuHelp = bar->GetMenu(1);
250     CPPUNIT_ASSERT( menuHelp->FindItem("Submenu") != wxNOT_FOUND );
251     CPPUNIT_ASSERT( menuHelp->FindItem("Sub&menu") != wxNOT_FOUND );
252 
253     // Find by position:
254     size_t n;
255     for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
256     {
257         CPPUNIT_ASSERT( menuHelp->FindItemByPosition(n) );
258     }
259 
260     // Find by id:
261     CPPUNIT_ASSERT( menuHelp->FindItem(MenuTestCase_Bar) );
262     CPPUNIT_ASSERT( !menuHelp->FindItem(MenuTestCase_Foo) );
263 
264     for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
265     {
266         size_t locatedAt;
267         wxMenuItem* itemByPos = menuHelp->FindItemByPosition(n);
268         CPPUNIT_ASSERT( itemByPos );
269         wxMenuItem* itemById = menuHelp->FindChildItem(itemByPos->GetId(), &locatedAt);
270         CPPUNIT_ASSERT_EQUAL( itemByPos, itemById );
271         CPPUNIT_ASSERT_EQUAL( locatedAt, n );
272     }
273 
274     // Find submenu item:
275     for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
276     {
277         wxMenuItem* item = menuHelp->FindItemByPosition(n);
278         if (item->IsSubMenu())
279         {
280             wxMenu* submenu;
281             wxMenuItem* submenuItem = menuHelp->FindItem(m_submenuItemId, &submenu);
282             CPPUNIT_ASSERT( submenuItem );
283             CPPUNIT_ASSERT( item->GetSubMenu() == submenu );
284         }
285     }
286 }
287 
EnableTop()288 void MenuTestCase::EnableTop()
289 {
290     wxMenuBar* const bar = m_frame->GetMenuBar();
291     CPPUNIT_ASSERT( bar->IsEnabledTop(0) );
292     bar->EnableTop( 0, false );
293     CPPUNIT_ASSERT( !bar->IsEnabledTop(0) );
294     bar->EnableTop( 0, true );
295     CPPUNIT_ASSERT( bar->IsEnabledTop(0) );
296 }
297 
Count()298 void MenuTestCase::Count()
299 {
300     wxMenuBar* bar = m_frame->GetMenuBar();
301     // I suppose you could call this "counting menubars" :)
302     CPPUNIT_ASSERT( bar );
303 
304     CPPUNIT_ASSERT_EQUAL( bar->GetMenuCount(), 2 );
305 
306     size_t count = 0;
307     for (size_t n=0; n < bar->GetMenuCount(); ++n)
308     {
309         RecursivelyCountMenuItems(bar->GetMenu(n), count);
310     }
311     CPPUNIT_ASSERT_EQUAL( count, m_itemCount );
312 }
313 
Labels()314 void MenuTestCase::Labels()
315 {
316     wxMenuBar* bar = m_frame->GetMenuBar();
317     CPPUNIT_ASSERT( bar );
318     wxMenu* filemenu;
319     wxMenuItem* itemFoo = bar->FindItem(MenuTestCase_Foo, &filemenu);
320     CPPUNIT_ASSERT( itemFoo );
321     CPPUNIT_ASSERT( filemenu );
322 
323     // These return labels including mnemonics/accelerators:
324 
325     // wxMenuBar
326     CPPUNIT_ASSERT_EQUAL( "&File", bar->GetMenuLabel(0) );
327     CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", bar->GetLabel(MenuTestCase_Foo) );
328 
329     // wxMenu
330     CPPUNIT_ASSERT_EQUAL( "&File", filemenu->GetTitle() );
331     CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", filemenu->GetLabel(MenuTestCase_Foo) );
332 
333     // wxMenuItem
334     CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", itemFoo->GetItemLabel() );
335 
336     // These return labels stripped of mnemonics/accelerators:
337 
338     // wxMenuBar
339     CPPUNIT_ASSERT_EQUAL( "File", bar->GetMenuLabelText(0) );
340 
341     // wxMenu
342     CPPUNIT_ASSERT_EQUAL( "Foo", filemenu->GetLabelText(MenuTestCase_Foo) );
343 
344     // wxMenuItem
345     CPPUNIT_ASSERT_EQUAL( "Foo", itemFoo->GetItemLabelText() );
346     CPPUNIT_ASSERT_EQUAL( "Foo", wxMenuItem::GetLabelText("&Foo\tCtrl-F") );
347 }
348 
349 #if wxUSE_INTL
350 
351 static wxString
GetTranslatedString(const wxTranslations & trans,const wxString & s)352 GetTranslatedString(const wxTranslations& trans, const wxString& s)
353 {
354     const wxString* t = trans.GetTranslatedString(s);
355     return t ? *t : s;
356 }
357 
TranslatedMnemonics()358 void MenuTestCase::TranslatedMnemonics()
359 {
360     // Check that appended mnemonics are correctly stripped;
361     // see https://trac.wxwidgets.org/ticket/16736
362     wxTranslations trans;
363     trans.SetLanguage(wxLANGUAGE_JAPANESE);
364     wxFileTranslationsLoader::AddCatalogLookupPathPrefix("./intl");
365     CPPUNIT_ASSERT( trans.AddCatalog("internat") );
366 
367     // Check the translation is being used:
368     CPPUNIT_ASSERT( wxString("&File") != GetTranslatedString(trans, "&File") );
369 
370     wxString filemenu = m_frame->GetMenuBar()->GetMenuLabel(0);
371     CPPUNIT_ASSERT_EQUAL
372     (
373          wxStripMenuCodes(GetTranslatedString(trans, "&File"), wxStrip_Menu),
374          wxStripMenuCodes(GetTranslatedString(trans, filemenu), wxStrip_Menu)
375     );
376 
377     // Test strings that have shortcuts. Duplicate non-mnemonic translations
378     // exist for both "Edit" and "View", for ease of comparison
379     CPPUNIT_ASSERT_EQUAL
380     (
381          GetTranslatedString(trans, "Edit"),
382          wxStripMenuCodes(GetTranslatedString(trans, "E&dit\tCtrl+E"), wxStrip_Menu)
383     );
384 
385     // "Vie&w" also has a space before the (&W)
386     CPPUNIT_ASSERT_EQUAL
387     (
388          GetTranslatedString(trans, "View"),
389          wxStripMenuCodes(GetTranslatedString(trans, "Vie&w\tCtrl+V"), wxStrip_Menu)
390     );
391 
392     // Test a 'normal' mnemonic too: the translation is "Preten&d"
393     CPPUNIT_ASSERT_EQUAL
394     (
395          "Pretend",
396          wxStripMenuCodes(GetTranslatedString(trans, "B&ogus"), wxStrip_Menu)
397     );
398 }
399 #endif // wxUSE_INTL
400 
RadioItems()401 void MenuTestCase::RadioItems()
402 {
403     wxMenuBar * const bar = m_frame->GetMenuBar();
404     wxMenu * const menu = new wxMenu;
405     bar->Append(menu, "&Radio");
406 
407     // Adding consecutive radio items creates a radio group.
408     menu->AppendRadioItem(MenuTestCase_First, "Radio 0");
409     menu->AppendRadioItem(MenuTestCase_First + 1, "Radio 1");
410 
411     // First item of a radio group is checked by default.
412     CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
413 
414     // Subsequent items in a group are not checked.
415     CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 1) );
416 
417 #ifdef __WXQT__
418     WARN("Radio check test does not work under Qt");
419 #else
420     // Checking the second one make the first one unchecked however.
421     menu->Check(MenuTestCase_First + 1, true);
422     CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First) );
423     CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 1) );
424     menu->Check(MenuTestCase_First, true);
425 #endif
426 
427     // Adding more radio items after a separator creates another radio group...
428     menu->AppendSeparator();
429     menu->AppendRadioItem(MenuTestCase_First + 2, "Radio 2");
430     menu->AppendRadioItem(MenuTestCase_First + 3, "Radio 3");
431     menu->AppendRadioItem(MenuTestCase_First + 4, "Radio 4");
432 
433     // ... which is independent from the first one.
434     CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
435     CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 2) );
436 
437 #ifdef __WXQT__
438     WARN("Radio check test does not work under Qt");
439 #else
440     menu->Check(MenuTestCase_First + 3, true);
441     CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 3) );
442     CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 2) );
443 
444     CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
445     menu->Check(MenuTestCase_First + 2, true);
446 #endif
447 
448     // Insert an item in the middle of an existing radio group.
449     menu->InsertRadioItem(4, MenuTestCase_First + 5, "Radio 5");
450     CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 2) );
451     CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 5) );
452 
453 #ifdef __WXQT__
454     WARN("Radio check test does not work under Qt");
455 #else
456     menu->Check( MenuTestCase_First + 5, true );
457     CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 3) );
458 
459     menu->Check( MenuTestCase_First + 3, true );
460 #endif
461 
462     // Prepend a couple of items before the first group.
463     menu->PrependRadioItem(MenuTestCase_First + 6, "Radio 6");
464     menu->PrependRadioItem(MenuTestCase_First + 7, "Radio 7");
465     CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 6) );
466     CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 7) );
467 
468 #ifdef __WXQT__
469     WARN("Radio check test does not work under Qt");
470 #else
471     menu->Check(MenuTestCase_First + 7, true);
472     CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 1) );
473 
474 
475     // Check that the last radio group still works as expected.
476     menu->Check(MenuTestCase_First + 4, true);
477     CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 5) );
478 #endif
479 }
480 
RemoveAdd()481 void MenuTestCase::RemoveAdd()
482 {
483     wxMenuBar* bar = m_frame->GetMenuBar();
484 
485     wxMenu* menu0 = bar->GetMenu(0);
486     wxMenu* menu1 = bar->GetMenu(1);
487     wxMenuItem* item = new wxMenuItem(menu0, MenuTestCase_Foo + 100, "t&ext\tCtrl-E");
488     menu0->Insert(0, item);
489     CPPUNIT_ASSERT( menu0->FindItemByPosition(0) == item );
490     menu0->Remove(item);
491     CPPUNIT_ASSERT( menu0->FindItemByPosition(0) != item );
492     menu1->Insert(0, item);
493     CPPUNIT_ASSERT( menu1->FindItemByPosition(0) == item );
494     menu1->Remove(item);
495     CPPUNIT_ASSERT( menu1->FindItemByPosition(0) != item );
496     menu0->Insert(0, item);
497     CPPUNIT_ASSERT( menu0->FindItemByPosition(0) == item );
498     menu0->Delete(item);
499 }
500 
ChangeBitmap()501 void MenuTestCase::ChangeBitmap()
502 {
503     wxMenu *menu = new wxMenu;
504 
505     wxMenuItem *item = new wxMenuItem(menu, wxID_ANY, "Item");
506     menu->Append(item);
507 
508     // On Windows Vista (and later) calling SetBitmap, *after* the menu
509     // item has already been added, used to result in a stack overflow:
510     // [Do]SetBitmap can call GetHBitmapForMenu which will call SetBitmap
511     // again etc...
512     item->SetBitmap( wxBitmap(1, 1) );
513 
514 
515     // Force owner drawn usage by having a bitmap that's wider than the
516     // standard size. This results in rearranging the parent menu which
517     // hasn't always worked properly and lead to a null pointer exception.
518     item->SetBitmap( wxBitmap(512, 1) );
519 
520     wxDELETE(menu);
521 }
522 
523 #if wxUSE_UIACTIONSIMULATOR
524 
525 // In C++98 this class can't be defined inside Events() method, unfortunately,
526 // as its OnMenu() method wouldn't be usable with template Bind() then.
527 class MenuEventHandler : public wxEvtHandler
528 {
529 public:
MenuEventHandler(wxWindow * win)530     MenuEventHandler(wxWindow* win)
531         : m_win(win)
532     {
533         m_win->Bind(wxEVT_MENU, &MenuEventHandler::OnMenu, this);
534 
535         m_gotEvent = false;
536         m_event = NULL;
537     }
538 
~MenuEventHandler()539     virtual ~MenuEventHandler()
540     {
541         m_win->Unbind(wxEVT_MENU, &MenuEventHandler::OnMenu, this);
542 
543         delete m_event;
544     }
545 
GetEvent()546     const wxCommandEvent& GetEvent()
547     {
548         CPPUNIT_ASSERT( m_gotEvent );
549 
550         m_gotEvent = false;
551 
552         return *m_event;
553     }
554 
GotEvent() const555     bool GotEvent() const
556     {
557         return m_gotEvent;
558     }
559 
560 private:
OnMenu(wxCommandEvent & event)561     void OnMenu(wxCommandEvent& event)
562     {
563         CPPUNIT_ASSERT( !m_gotEvent );
564 
565         delete m_event;
566         m_event = static_cast<wxCommandEvent*>(event.Clone());
567         m_gotEvent = true;
568     }
569 
570     wxWindow* const m_win;
571     wxCommandEvent* m_event;
572     bool m_gotEvent;
573 };
574 
575 #endif // wxUSE_UIACTIONSIMULATOR
576 
Events()577 void MenuTestCase::Events()
578 {
579 #if wxUSE_UIACTIONSIMULATOR
580     MenuEventHandler handler(m_frame);
581 
582     // Invoke the accelerator.
583     m_frame->Show();
584     m_frame->SetFocus();
585     wxYield();
586 
587     wxUIActionSimulator sim;
588     sim.KeyDown(WXK_F1);
589     sim.KeyUp(WXK_F1);
590     wxYield();
591 
592     const wxCommandEvent& ev = handler.GetEvent();
593     CPPUNIT_ASSERT_EQUAL( static_cast<int>(MenuTestCase_Bar), ev.GetId() );
594 
595     wxObject* const src = ev.GetEventObject();
596     CPPUNIT_ASSERT( src );
597 
598     CPPUNIT_ASSERT_EQUAL( "wxMenu",
599                           wxString(src->GetClassInfo()->GetClassName()) );
600     CPPUNIT_ASSERT_EQUAL( static_cast<wxObject*>(m_menuWithBar),
601                           src );
602 
603     // Invoke another accelerator, it should also work.
604     sim.Char('A', wxMOD_CONTROL);
605     wxYield();
606 
607     const wxCommandEvent& ev2 = handler.GetEvent();
608     CHECK( ev2.GetId() == static_cast<int>(MenuTestCase_SelectAll) );
609 
610     // Now create a text control which uses the same accelerator for itself and
611     // check that when the text control has focus, the accelerator does _not_
612     // work.
613     wxTextCtrl* const text = new wxTextCtrl(m_frame, wxID_ANY, "Testing");
614     text->SetFocus();
615 
616     sim.Char('A', wxMOD_CONTROL);
617     wxYield();
618 
619     CHECK( !handler.GotEvent() );
620 #endif // wxUSE_UIACTIONSIMULATOR
621 }
622 
623 namespace
624 {
625 
VerifyAccelAssigned(wxString labelText,int keycode)626 void VerifyAccelAssigned( wxString labelText, int keycode )
627 {
628     const wxScopedPtr<wxAcceleratorEntry> entry(
629         wxAcceleratorEntry::Create( labelText )
630     );
631 
632     CHECK( entry );
633     CHECK( entry->GetKeyCode() == keycode );
634 }
635 
636 struct key
637 {
638     int      keycode;
639     wxString name;
640     bool     skip;
641 };
642 key modKeys[] =
643 {
644     { wxACCEL_NORMAL, "Normal", false },
645     { wxACCEL_CTRL,   "Ctrl",   false },
646     { wxACCEL_SHIFT,  "Shift",  false },
647     { wxACCEL_ALT,    "Alt",    false }
648 };
649 /*
650  The keys marked as skip below are not supported as accelerator
651  keys on GTK.
652  */
653 key specialKeys[] =
654 {
655     { WXK_F1,               "WXK_F1",               false },
656     { WXK_F2,               "WXK_F2",               false },
657     { WXK_F3,               "WXK_F3",               false },
658     { WXK_F4,               "WXK_F4",               false },
659     { WXK_F5,               "WXK_F5",               false },
660     { WXK_F6,               "WXK_F6",               false },
661     { WXK_F7,               "WXK_F7",               false },
662     { WXK_F8,               "WXK_F8",               false },
663     { WXK_F9,               "WXK_F9",               false },
664     { WXK_F10,              "WXK_F10",              false },
665     { WXK_F11,              "WXK_F11",              false },
666     { WXK_F12,              "WXK_F12",              false },
667     { WXK_F13,              "WXK_F13",              false },
668     { WXK_F14,              "WXK_F14",              false },
669     { WXK_F15,              "WXK_F15",              false },
670     { WXK_F16,              "WXK_F16",              false },
671     { WXK_F17,              "WXK_F17",              false },
672     { WXK_F18,              "WXK_F18",              false },
673     { WXK_F19,              "WXK_F19",              false },
674     { WXK_F20,              "WXK_F20",              false },
675     { WXK_F21,              "WXK_F21",              false },
676     { WXK_F22,              "WXK_F22",              false },
677     { WXK_F23,              "WXK_F23",              false },
678     { WXK_F24,              "WXK_F24",              false },
679     { WXK_INSERT,           "WXK_INSERT",           false },
680     { WXK_DELETE,           "WXK_DELETE",           false },
681     { WXK_UP,               "WXK_UP",               false },
682     { WXK_DOWN,             "WXK_DOWN",             false },
683     { WXK_PAGEUP,           "WXK_PAGEUP",           false },
684     { WXK_PAGEDOWN,         "WXK_PAGEDOWN",         false },
685     { WXK_LEFT,             "WXK_LEFT",             false },
686     { WXK_RIGHT,            "WXK_RIGHT",            false },
687     { WXK_HOME,             "WXK_HOME",             false },
688     { WXK_END,              "WXK_END",              false },
689     { WXK_RETURN,           "WXK_RETURN",           false },
690     { WXK_BACK,             "WXK_BACK",             false },
691     { WXK_TAB,              "WXK_TAB",              true },
692     { WXK_ESCAPE,           "WXK_ESCAPE",           false },
693     { WXK_SPACE,            "WXK_SPACE",            false },
694     { WXK_MULTIPLY,         "WXK_MULTIPLY",         false },
695     { WXK_ADD,              "WXK_ADD",              true },
696     { WXK_SEPARATOR,        "WXK_SEPARATOR",        true },
697     { WXK_SUBTRACT,         "WXK_SUBTRACT",         true },
698     { WXK_DECIMAL,          "WXK_DECIMAL",          true },
699     { WXK_DIVIDE,           "WXK_DIVIDE",           true },
700     { WXK_CANCEL,           "WXK_CANCEL",           false },
701     { WXK_CLEAR,            "WXK_CLEAR",            false },
702     { WXK_MENU,             "WXK_MENU",             false },
703     { WXK_PAUSE,            "WXK_PAUSE",            false },
704     { WXK_CAPITAL,          "WXK_CAPITAL",          true },
705     { WXK_SELECT,           "WXK_SELECT",           false },
706     { WXK_PRINT,            "WXK_PRINT",            false },
707     { WXK_EXECUTE,          "WXK_EXECUTE",          false },
708     { WXK_SNAPSHOT,         "WXK_SNAPSHOT",         true },
709     { WXK_HELP,             "WXK_HELP",             false },
710     { WXK_NUMLOCK,          "WXK_NUMLOCK",          true },
711     { WXK_SCROLL,           "WXK_SCROLL",           true },
712     { WXK_NUMPAD_INSERT,    "WXK_NUMPAD_INSERT",    false },
713     { WXK_NUMPAD_DELETE,    "WXK_NUMPAD_DELETE",    false },
714     { WXK_NUMPAD_SPACE,     "WXK_NUMPAD_SPACE",     false },
715     { WXK_NUMPAD_TAB,       "WXK_NUMPAD_TAB",       true },
716     { WXK_NUMPAD_ENTER,     "WXK_NUMPAD_ENTER",     false },
717     { WXK_NUMPAD_F1,        "WXK_NUMPAD_F1",        false },
718     { WXK_NUMPAD_F2,        "WXK_NUMPAD_F2",        false },
719     { WXK_NUMPAD_F3,        "WXK_NUMPAD_F3",        false },
720     { WXK_NUMPAD_F4,        "WXK_NUMPAD_F4",        false },
721     { WXK_NUMPAD_HOME,      "WXK_NUMPAD_HOME",      false },
722     { WXK_NUMPAD_LEFT,      "WXK_NUMPAD_LEFT",      false },
723     { WXK_NUMPAD_UP,        "WXK_NUMPAD_UP",        false },
724     { WXK_NUMPAD_RIGHT,     "WXK_NUMPAD_RIGHT",     false },
725     { WXK_NUMPAD_DOWN,      "WXK_NUMPAD_DOWN",      false },
726     { WXK_NUMPAD_PAGEUP,    "WXK_NUMPAD_PAGEUP",    false },
727     { WXK_NUMPAD_PAGEDOWN,  "WXK_NUMPAD_PAGEDOWN",  false },
728     { WXK_NUMPAD_END,       "WXK_NUMPAD_END",       false },
729     { WXK_NUMPAD_BEGIN,     "WXK_NUMPAD_BEGIN",     false },
730     { WXK_NUMPAD_EQUAL,     "WXK_NUMPAD_EQUAL",     false },
731     { WXK_NUMPAD_MULTIPLY,  "WXK_NUMPAD_MULTIPLY",  false },
732     { WXK_NUMPAD_ADD,       "WXK_NUMPAD_ADD",       false },
733     { WXK_NUMPAD_SEPARATOR, "WXK_NUMPAD_SEPARATOR", false },
734     { WXK_NUMPAD_SUBTRACT,  "WXK_NUMPAD_SUBTRACT",  false },
735     { WXK_NUMPAD_DECIMAL,   "WXK_NUMPAD_DECIMAL",   false },
736     { WXK_NUMPAD_DIVIDE,    "WXK_NUMPAD_DIVIDE",    false },
737     { WXK_NUMPAD0,          "WXK_NUMPAD0",          false },
738     { WXK_NUMPAD1,          "WXK_NUMPAD1",          false },
739     { WXK_NUMPAD2,          "WXK_NUMPAD2",          false },
740     { WXK_NUMPAD3,          "WXK_NUMPAD3",          false },
741     { WXK_NUMPAD4,          "WXK_NUMPAD4",          false },
742     { WXK_NUMPAD5,          "WXK_NUMPAD5",          false },
743     { WXK_NUMPAD6,          "WXK_NUMPAD6",          false },
744     { WXK_NUMPAD7,          "WXK_NUMPAD7",          false },
745     { WXK_NUMPAD8,          "WXK_NUMPAD8",          false },
746     { WXK_NUMPAD9,          "WXK_NUMPAD9",          false },
747     { WXK_WINDOWS_LEFT,     "WXK_WINDOWS_LEFT",     true },
748     { WXK_WINDOWS_RIGHT,    "WXK_WINDOWS_RIGHT",    true },
749     { WXK_WINDOWS_MENU,     "WXK_WINDOWS_MENU",     false },
750     { WXK_COMMAND,          "WXK_COMMAND",          true }
751 };
752 
753 }
754 
755 TEST_CASE( "wxMenuItemAccelEntry", "[menu][accelentry]" )
756 {
757     wxMenu* menu = new wxMenu;
758 
759     menu->Append( wxID_ANY, "Test" );
760     wxMenuItem* item = menu->FindItemByPosition( 0 );
761 
762     SECTION( "Modifier keys" )
763     {
764         for ( unsigned i = 0; i < WXSIZEOF(modKeys); i++ )
765         {
766             const key& k = modKeys[i];
767 
768             INFO( wxString::Format( "Modifier: %s",  k.name ) );
769             wxAcceleratorEntry accelEntry( k.keycode, 'A' , wxID_ANY, item );
770             item->SetAccel( &accelEntry );
771 
772             wxString labelText = item->GetItemLabel();
773             INFO( wxString::Format( "Label text: %s", labelText ) );
774 
775             VerifyAccelAssigned( labelText, 'A' );
776         }
777     }
778 
779     SECTION( "Special keys" )
780     {
781         for ( unsigned i = 0; i < WXSIZEOF(specialKeys); i++ )
782         {
783             const key& k = specialKeys[i];
784 
785             if( k.skip )
786                 continue;
787 
788             INFO( wxString::Format( "Keycode: %s",  k.name ) );
789             wxAcceleratorEntry accelEntry( wxACCEL_CTRL, k.keycode, wxID_ANY, item );
790             item->SetAccel( &accelEntry );
791 
792             wxString labelText = item->GetItemLabel();
793             INFO( wxString::Format( "Label text: %s", labelText ) );
794 
795             VerifyAccelAssigned( labelText, k.keycode );
796         }
797     }
798 }
799 
800 #endif
801