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