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