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