]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/menucmn.cpp
fixed 3 infinite loops -- the person who tested this code must have had a lot of...
[wxWidgets.git] / src / common / menucmn.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: common/menucmn.cpp
3// Purpose: wxMenu and wxMenuBar methods common to all ports
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 26.10.99
7// RCS-ID: $Id$
8// Copyright: (c) wxWindows team
9// Licence: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "menubase.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#if wxUSE_MENUS
32
33#include <ctype.h>
34
35#ifndef WX_PRECOMP
36 #include "wx/intl.h"
37 #include "wx/log.h"
38 #include "wx/menu.h"
39#endif
40
41// ----------------------------------------------------------------------------
42// template lists
43// ----------------------------------------------------------------------------
44
45#include "wx/listimpl.cpp"
46
47WX_DEFINE_LIST(wxMenuList);
48WX_DEFINE_LIST(wxMenuItemList);
49
50// ============================================================================
51// implementation
52// ============================================================================
53
54// ----------------------------------------------------------------------------
55// wxMenuItem
56// ----------------------------------------------------------------------------
57
58wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu,
59 int id,
60 const wxString& text,
61 const wxString& help,
62 wxItemKind kind,
63 wxMenu *subMenu)
64 : m_text(text),
65 m_help(help)
66{
67 wxASSERT_MSG( parentMenu != NULL, wxT("menuitem should have a menu") );
68
69 m_parentMenu = parentMenu;
70 m_subMenu = subMenu;
71 m_isEnabled = TRUE;
72 m_isChecked = FALSE;
73 m_id = id;
74 m_kind = kind;
75}
76
77wxMenuItemBase::~wxMenuItemBase()
78{
79 delete m_subMenu;
80}
81
82#if wxUSE_ACCEL
83
84// return wxAcceleratorEntry for the given menu string or NULL if none
85// specified
86wxAcceleratorEntry *wxGetAccelFromString(const wxString& label)
87{
88 // check for accelerators: they are given after '\t'
89 int posTab = label.Find(wxT('\t'));
90 if ( posTab != wxNOT_FOUND ) {
91 // parse the accelerator string
92 int keyCode = 0;
93 int accelFlags = wxACCEL_NORMAL;
94 wxString current;
95 for ( size_t n = (size_t)posTab + 1; n < label.Len(); n++ ) {
96 if ( (label[n] == '+') || (label[n] == '-') ) {
97 if ( current == _("ctrl") )
98 accelFlags |= wxACCEL_CTRL;
99 else if ( current == _("alt") )
100 accelFlags |= wxACCEL_ALT;
101 else if ( current == _("shift") )
102 accelFlags |= wxACCEL_SHIFT;
103 else {
104 // we may have "Ctrl-+", for example, but we still want to
105 // catch typos like "Crtl-A" so only give the warning if we
106 // have something before the current '+' or '-', else take
107 // it as a literal symbol
108 if ( current.empty() )
109 {
110 current += label[n];
111
112 // skip clearing it below
113 continue;
114 }
115 else
116 {
117 wxLogDebug(wxT("Unknown accel modifier: '%s'"),
118 current.c_str());
119 }
120 }
121
122 current.clear();
123 }
124 else {
125 current += wxTolower(label[n]);
126 }
127 }
128
129 if ( current.IsEmpty() ) {
130 wxLogDebug(wxT("No accel key found, accel string ignored."));
131 }
132 else {
133 if ( current.Len() == 1 ) {
134 // it's a letter
135 keyCode = wxToupper(current[0U]);
136 }
137 else {
138 // is it a function key?
139 if ( current[0U] == 'f' && isdigit(current[1U]) &&
140 (current.Len() == 2 ||
141 (current.Len() == 3 && isdigit(current[2U]))) ) {
142 int n;
143 wxSscanf(current.c_str() + 1, wxT("%d"), &n);
144
145 keyCode = WXK_F1 + n - 1;
146 }
147 else {
148 // several special cases
149 current.MakeUpper();
150 if ( current == wxT("DEL") ) {
151 keyCode = WXK_DELETE;
152 }
153 else if ( current == wxT("DELETE") ) {
154 keyCode = WXK_DELETE;
155 }
156 else if ( current == wxT("INS") ) {
157 keyCode = WXK_INSERT;
158 }
159 else if ( current == wxT("INSERT") ) {
160 keyCode = WXK_INSERT;
161 }
162 else if ( current == wxT("ENTER") || current == wxT("RETURN") ) {
163 keyCode = WXK_RETURN;
164 }
165 else if ( current == wxT("PGUP") ) {
166 keyCode = WXK_PRIOR;
167 }
168 else if ( current == wxT("PGDN") ) {
169 keyCode = WXK_NEXT;
170 }
171 else if ( current == wxT("LEFT") ) {
172 keyCode = WXK_LEFT;
173 }
174 else if ( current == wxT("RIGHT") ) {
175 keyCode = WXK_RIGHT;
176 }
177 else if ( current == wxT("UP") ) {
178 keyCode = WXK_UP;
179 }
180 else if ( current == wxT("DOWN") ) {
181 keyCode = WXK_DOWN;
182 }
183 else if ( current == wxT("HOME") ) {
184 keyCode = WXK_HOME;
185 }
186 else if ( current == wxT("END") ) {
187 keyCode = WXK_END;
188 }
189 else if ( current == wxT("SPACE") ) {
190 keyCode = WXK_SPACE;
191 }
192 else if ( current == wxT("TAB") ) {
193 keyCode = WXK_TAB;
194 }
195 else
196 {
197 wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."),
198 current.c_str());
199 }
200 }
201 }
202 }
203
204 if ( keyCode ) {
205 // we do have something
206 return new wxAcceleratorEntry(accelFlags, keyCode);
207 }
208 }
209
210 return (wxAcceleratorEntry *)NULL;
211}
212
213wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
214{
215 return wxGetAccelFromString(GetText());
216}
217
218void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
219{
220 wxString text = m_text.BeforeFirst(wxT('\t'));
221 if ( accel )
222 {
223 text += wxT('\t');
224
225 int flags = accel->GetFlags();
226 if ( flags & wxACCEL_ALT )
227 text += wxT("Alt-");
228 if ( flags & wxACCEL_CTRL )
229 text += wxT("Ctrl-");
230 if ( flags & wxACCEL_SHIFT )
231 text += wxT("Shift-");
232
233 int code = accel->GetKeyCode();
234 switch ( code )
235 {
236 case WXK_F1:
237 case WXK_F2:
238 case WXK_F3:
239 case WXK_F4:
240 case WXK_F5:
241 case WXK_F6:
242 case WXK_F7:
243 case WXK_F8:
244 case WXK_F9:
245 case WXK_F10:
246 case WXK_F11:
247 case WXK_F12:
248 text << wxT('F') << code - WXK_F1 + 1;
249 break;
250
251 // if there are any other keys wxGetAccelFromString() may return,
252 // we should process them here
253
254 default:
255 if ( wxIsalnum(code) )
256 {
257 text << (wxChar)code;
258
259 break;
260 }
261
262 wxFAIL_MSG( wxT("unknown keyboard accel") );
263 }
264 }
265
266 SetText(text);
267}
268
269#endif // wxUSE_ACCEL
270
271// ----------------------------------------------------------------------------
272// wxMenu ctor and dtor
273// ----------------------------------------------------------------------------
274
275void wxMenuBase::Init(long style)
276{
277 m_items.DeleteContents(TRUE);
278
279 m_menuBar = (wxMenuBar *)NULL;
280 m_menuParent = (wxMenu *)NULL;
281
282 m_invokingWindow = (wxWindow *)NULL;
283 m_style = style;
284 m_clientData = (void *)NULL;
285 m_eventHandler = this;
286
287#if wxUSE_MENU_CALLBACK
288 m_callback = (wxFunction) NULL;
289#endif // wxUSE_MENU_CALLBACK
290}
291
292wxMenuBase::~wxMenuBase()
293{
294 // nothing to do, wxMenuItemList dtor will delete the menu items.
295
296 // Actually, in GTK, the submenus have to get deleted first.
297}
298
299// ----------------------------------------------------------------------------
300// wxMenu item adding/removing
301// ----------------------------------------------------------------------------
302
303void wxMenuBase::AddSubMenu(wxMenu *submenu)
304{
305 wxCHECK_RET( submenu, _T("can't add a NULL submenu") );
306
307 if ( m_menuBar )
308 {
309 submenu->Attach(m_menuBar);
310 }
311
312 submenu->SetParent((wxMenu *)this);
313}
314
315bool wxMenuBase::DoAppend(wxMenuItem *item)
316{
317 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Append()") );
318
319 m_items.Append(item);
320 if ( item->IsSubMenu() )
321 {
322 AddSubMenu(item->GetSubMenu());
323 }
324
325 return TRUE;
326}
327
328bool wxMenuBase::Insert(size_t pos, wxMenuItem *item)
329{
330 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert") );
331
332 if ( pos == GetMenuItemCount() )
333 {
334 return DoAppend(item);
335 }
336 else
337 {
338 wxCHECK_MSG( pos < GetMenuItemCount(), FALSE,
339 wxT("invalid index in wxMenu::Insert") );
340
341 return DoInsert(pos, item);
342 }
343}
344
345bool wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
346{
347 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert()") );
348
349 wxMenuItemList::Node *node = m_items.Item(pos);
350 wxCHECK_MSG( node, FALSE, wxT("invalid index in wxMenu::Insert()") );
351
352 m_items.Insert(node, item);
353 if ( item->IsSubMenu() )
354 {
355 AddSubMenu(item->GetSubMenu());
356 }
357
358 return TRUE;
359}
360
361wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
362{
363 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
364
365 return DoRemove(item);
366}
367
368wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
369{
370 wxMenuItemList::Node *node = m_items.Find(item);
371
372 // if we get here, the item is valid or one of Remove() functions is broken
373 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
374
375 // we detach the item, but we do delete the list node (i.e. don't call
376 // DetachNode() here!)
377 node->SetData((wxMenuItem *)NULL); // to prevent it from deleting the item
378 m_items.DeleteNode(node);
379
380 // item isn't attached to anything any more
381 wxMenu *submenu = item->GetSubMenu();
382 if ( submenu )
383 {
384 submenu->SetParent((wxMenu *)NULL);
385 }
386
387 return item;
388}
389
390bool wxMenuBase::Delete(wxMenuItem *item)
391{
392 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Delete") );
393
394 return DoDelete(item);
395}
396
397bool wxMenuBase::DoDelete(wxMenuItem *item)
398{
399 wxMenuItem *item2 = DoRemove(item);
400 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
401
402 // don't delete the submenu
403 item2->SetSubMenu((wxMenu *)NULL);
404
405 delete item2;
406
407 return TRUE;
408}
409
410bool wxMenuBase::Destroy(wxMenuItem *item)
411{
412 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Destroy") );
413
414 return DoDestroy(item);
415}
416
417bool wxMenuBase::DoDestroy(wxMenuItem *item)
418{
419 wxMenuItem *item2 = DoRemove(item);
420 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
421
422 delete item2;
423
424 return TRUE;
425}
426
427// ----------------------------------------------------------------------------
428// wxMenu searching for items
429// ----------------------------------------------------------------------------
430
431// Finds the item id matching the given string, -1 if not found.
432int wxMenuBase::FindItem(const wxString& text) const
433{
434 wxString label = wxMenuItem::GetLabelFromText(text);
435 for ( wxMenuItemList::Node *node = m_items.GetFirst();
436 node;
437 node = node->GetNext() )
438 {
439 wxMenuItem *item = node->GetData();
440 if ( item->IsSubMenu() )
441 {
442 int rc = item->GetSubMenu()->FindItem(label);
443 if ( rc != wxNOT_FOUND )
444 return rc;
445 }
446
447 // we execute this code for submenus as well to alllow finding them by
448 // name just like the ordinary items
449 if ( !item->IsSeparator() )
450 {
451 if ( item->GetLabel() == label )
452 return item->GetId();
453 }
454 }
455
456 return wxNOT_FOUND;
457}
458
459// recursive search for item by id
460wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
461{
462 if ( itemMenu )
463 *itemMenu = NULL;
464
465 wxMenuItem *item = NULL;
466 for ( wxMenuItemList::Node *node = m_items.GetFirst();
467 node && !item;
468 node = node->GetNext() )
469 {
470 item = node->GetData();
471
472 if ( item->GetId() == itemId )
473 {
474 if ( itemMenu )
475 *itemMenu = (wxMenu *)this;
476 }
477 else if ( item->IsSubMenu() )
478 {
479 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
480 }
481 else
482 {
483 // don't exit the loop
484 item = NULL;
485 }
486 }
487
488 return item;
489}
490
491// non recursive search
492wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
493{
494 wxMenuItem *item = (wxMenuItem *)NULL;
495 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
496
497 size_t pos;
498 for ( pos = 0; node; pos++ )
499 {
500 if ( node->GetData()->GetId() == id )
501 {
502 item = node->GetData();
503
504 break;
505 }
506
507 node = node->GetNext();
508 }
509
510 if ( ppos )
511 {
512 *ppos = item ? pos : (size_t)wxNOT_FOUND;
513 }
514
515 return item;
516}
517
518// ----------------------------------------------------------------------------
519// wxMenu helpers used by derived classes
520// ----------------------------------------------------------------------------
521
522// Update a menu and all submenus recursively. source is the object that has
523// the update event handlers defined for it. If NULL, the menu or associated
524// window will be used.
525void wxMenuBase::UpdateUI(wxEvtHandler* source)
526{
527 if ( !source && GetInvokingWindow() )
528 source = GetInvokingWindow()->GetEventHandler();
529 if ( !source )
530 source = GetEventHandler();
531 if ( !source )
532 source = this;
533
534 wxMenuItemList::Node* node = GetMenuItems().GetFirst();
535 while ( node )
536 {
537 wxMenuItem* item = node->GetData();
538 if ( !item->IsSeparator() )
539 {
540 wxWindowID id = item->GetId();
541 wxUpdateUIEvent event(id);
542 event.SetEventObject( source );
543
544 if ( source->ProcessEvent(event) )
545 {
546 // if anything changed, update the chanegd attribute
547 if (event.GetSetText())
548 SetLabel(id, event.GetText());
549 if (event.GetSetChecked())
550 Check(id, event.GetChecked());
551 if (event.GetSetEnabled())
552 Enable(id, event.GetEnabled());
553 }
554
555 // recurse to the submenus
556 if ( item->GetSubMenu() )
557 item->GetSubMenu()->UpdateUI(source);
558 }
559 //else: item is a separator (which don't process update UI events)
560
561 node = node->GetNext();
562 }
563}
564
565bool wxMenuBase::SendEvent(int id, int checked)
566{
567 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
568 event.SetEventObject(this);
569 event.SetInt(checked);
570
571 bool processed = FALSE;
572
573#if wxUSE_MENU_CALLBACK
574 // Try a callback
575 if (m_callback)
576 {
577 (void)(*(m_callback))(*this, event);
578 processed = TRUE;
579 }
580#endif // wxUSE_MENU_CALLBACK
581
582 // Try the menu's event handler
583 if ( !processed )
584 {
585 wxEvtHandler *handler = GetEventHandler();
586 if ( handler )
587 processed = handler->ProcessEvent(event);
588 }
589
590 // Try the window the menu was popped up from (and up through the
591 // hierarchy)
592 if ( !processed )
593 {
594 const wxMenuBase *menu = this;
595 while ( menu )
596 {
597 wxWindow *win = menu->GetInvokingWindow();
598 if ( win )
599 {
600 processed = win->GetEventHandler()->ProcessEvent(event);
601 break;
602 }
603
604 menu = menu->GetParent();
605 }
606 }
607
608 return processed;
609}
610
611// ----------------------------------------------------------------------------
612// wxMenu attaching/detaching to/from menu bar
613// ----------------------------------------------------------------------------
614
615void wxMenuBase::Attach(wxMenuBarBase *menubar)
616{
617 // use Detach() instead!
618 wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") );
619
620 // use IsAttached() to prevent this from happening
621 wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") );
622
623 m_menuBar = (wxMenuBar *)menubar;
624}
625
626void wxMenuBase::Detach()
627{
628 // use IsAttached() to prevent this from happening
629 wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") );
630
631 m_menuBar = NULL;
632}
633
634// ----------------------------------------------------------------------------
635// wxMenu functions forwarded to wxMenuItem
636// ----------------------------------------------------------------------------
637
638void wxMenuBase::Enable( int id, bool enable )
639{
640 wxMenuItem *item = FindItem(id);
641
642 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
643
644 item->Enable(enable);
645}
646
647bool wxMenuBase::IsEnabled( int id ) const
648{
649 wxMenuItem *item = FindItem(id);
650
651 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") );
652
653 return item->IsEnabled();
654}
655
656void wxMenuBase::Check( int id, bool enable )
657{
658 wxMenuItem *item = FindItem(id);
659
660 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
661
662 item->Check(enable);
663}
664
665bool wxMenuBase::IsChecked( int id ) const
666{
667 wxMenuItem *item = FindItem(id);
668
669 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") );
670
671 return item->IsChecked();
672}
673
674void wxMenuBase::SetLabel( int id, const wxString &label )
675{
676 wxMenuItem *item = FindItem(id);
677
678 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
679
680 item->SetText(label);
681}
682
683wxString wxMenuBase::GetLabel( int id ) const
684{
685 wxMenuItem *item = FindItem(id);
686
687 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") );
688
689 return item->GetText();
690}
691
692void wxMenuBase::SetHelpString( int id, const wxString& helpString )
693{
694 wxMenuItem *item = FindItem(id);
695
696 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
697
698 item->SetHelp( helpString );
699}
700
701wxString wxMenuBase::GetHelpString( int id ) const
702{
703 wxMenuItem *item = FindItem(id);
704
705 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
706
707 return item->GetHelp();
708}
709
710// ----------------------------------------------------------------------------
711// wxMenuBarBase ctor and dtor
712// ----------------------------------------------------------------------------
713
714wxMenuBarBase::wxMenuBarBase()
715{
716 // we own the menus when we get them
717 m_menus.DeleteContents(TRUE);
718
719 // not attached yet
720 m_menuBarFrame = NULL;
721}
722
723wxMenuBarBase::~wxMenuBarBase()
724{
725 // nothing to do, the list will delete the menus because of the call to
726 // DeleteContents() above
727}
728
729// ----------------------------------------------------------------------------
730// wxMenuBar item access: the base class versions manage m_menus list, the
731// derived class should reflect the changes in the real menubar
732// ----------------------------------------------------------------------------
733
734wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
735{
736 wxMenuList::Node *node = m_menus.Item(pos);
737 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
738
739 return node->GetData();
740}
741
742bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title))
743{
744 wxCHECK_MSG( menu, FALSE, wxT("can't append NULL menu") );
745
746 m_menus.Append(menu);
747 menu->Attach(this);
748
749 return TRUE;
750}
751
752bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
753 const wxString& title)
754{
755 if ( pos == m_menus.GetCount() )
756 {
757 return wxMenuBarBase::Append(menu, title);
758 }
759 else // not at the end
760 {
761 wxCHECK_MSG( menu, FALSE, wxT("can't insert NULL menu") );
762
763 wxMenuList::Node *node = m_menus.Item(pos);
764 wxCHECK_MSG( node, FALSE, wxT("bad index in wxMenuBar::Insert()") );
765
766 m_menus.Insert(node, menu);
767 menu->Attach(this);
768
769 return TRUE;
770 }
771}
772
773wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
774 const wxString& WXUNUSED(title))
775{
776 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
777
778 wxMenuList::Node *node = m_menus.Item(pos);
779 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
780
781 wxMenu *menuOld = node->GetData();
782 node->SetData(menu);
783
784 menu->Attach(this);
785 menuOld->Detach();
786
787 return menuOld;
788}
789
790wxMenu *wxMenuBarBase::Remove(size_t pos)
791{
792 wxMenuList::Node *node = m_menus.Item(pos);
793 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
794
795 node = m_menus.DetachNode(node);
796 wxCHECK( node, NULL ); // unexpected
797 wxMenu *menu = node->GetData();
798 menu->Detach();
799
800 delete node;
801
802 return menu;
803}
804
805int wxMenuBarBase::FindMenu(const wxString& title) const
806{
807 wxString label = wxMenuItem::GetLabelFromText(title);
808
809 size_t count = GetMenuCount();
810 for ( size_t i = 0; i < count; i++ )
811 {
812 wxString title2 = GetLabelTop(i);
813 if ( (title2 == title) ||
814 (wxMenuItem::GetLabelFromText(title2) == label) )
815 {
816 // found
817 return (int)i;
818 }
819 }
820
821 return wxNOT_FOUND;
822
823}
824
825// ----------------------------------------------------------------------------
826// wxMenuBar attaching/detaching to/from the frame
827// ----------------------------------------------------------------------------
828
829void wxMenuBarBase::Attach(wxFrame *frame)
830{
831 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
832
833 m_menuBarFrame = frame;
834}
835
836void wxMenuBarBase::Detach()
837{
838 wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
839
840 m_menuBarFrame = NULL;
841}
842
843// ----------------------------------------------------------------------------
844// wxMenuBar searching for items
845// ----------------------------------------------------------------------------
846
847wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const
848{
849 if ( menu )
850 *menu = NULL;
851
852 wxMenuItem *item = NULL;
853 size_t count = GetMenuCount();
854 for ( size_t i = 0; !item && (i < count); i++ )
855 {
856 item = m_menus[i]->FindItem(id, menu);
857 }
858
859 return item;
860}
861
862int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
863{
864 wxString label = wxMenuItem::GetLabelFromText(menu);
865
866 int i = 0;
867 wxMenuList::Node *node;
868 for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
869 {
870 if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) )
871 return node->GetData()->FindItem(item);
872 }
873
874 return wxNOT_FOUND;
875}
876
877// ---------------------------------------------------------------------------
878// wxMenuBar functions forwarded to wxMenuItem
879// ---------------------------------------------------------------------------
880
881void wxMenuBarBase::Enable(int id, bool enable)
882{
883 wxMenuItem *item = FindItem(id);
884
885 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
886
887 item->Enable(enable);
888}
889
890void wxMenuBarBase::Check(int id, bool check)
891{
892 wxMenuItem *item = FindItem(id);
893
894 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
895 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
896
897 item->Check(check);
898}
899
900bool wxMenuBarBase::IsChecked(int id) const
901{
902 wxMenuItem *item = FindItem(id);
903
904 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") );
905
906 return item->IsChecked();
907}
908
909bool wxMenuBarBase::IsEnabled(int id) const
910{
911 wxMenuItem *item = FindItem(id);
912
913 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") );
914
915 return item->IsEnabled();
916}
917
918void wxMenuBarBase::SetLabel(int id, const wxString& label)
919{
920 wxMenuItem *item = FindItem(id);
921
922 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
923
924 item->SetText(label);
925}
926
927wxString wxMenuBarBase::GetLabel(int id) const
928{
929 wxMenuItem *item = FindItem(id);
930
931 wxCHECK_MSG( item, wxEmptyString,
932 wxT("wxMenuBar::GetLabel(): no such item") );
933
934 return item->GetText();
935}
936
937void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
938{
939 wxMenuItem *item = FindItem(id);
940
941 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
942
943 item->SetHelp(helpString);
944}
945
946wxString wxMenuBarBase::GetHelpString(int id) const
947{
948 wxMenuItem *item = FindItem(id);
949
950 wxCHECK_MSG( item, wxEmptyString,
951 wxT("wxMenuBar::GetHelpString(): no such item") );
952
953 return item->GetHelp();
954}
955
956#endif // wxUSE_MENUS