]> git.saurik.com Git - wxWidgets.git/blame - src/common/menucmn.cpp
Expand the range of WXK_ values that are excluded from OnChar.
[wxWidgets.git] / src / common / menucmn.cpp
CommitLineData
3dfac970
VZ
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
55d99c7a 9// Licence: wxWindows licence
3dfac970
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
3dfac970
VZ
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
1e6feb95
VZ
31#if wxUSE_MENUS
32
33#include <ctype.h>
34
3dfac970 35#ifndef WX_PRECOMP
1e6feb95
VZ
36 #include "wx/intl.h"
37 #include "wx/log.h"
3dfac970
VZ
38 #include "wx/menu.h"
39#endif
40
41// ----------------------------------------------------------------------------
42// template lists
43// ----------------------------------------------------------------------------
44
45#include "wx/listimpl.cpp"
717a57c2 46
3dfac970 47WX_DEFINE_LIST(wxMenuList);
717a57c2 48WX_DEFINE_LIST(wxMenuItemList);
3dfac970
VZ
49
50// ============================================================================
51// implementation
52// ============================================================================
53
54// ----------------------------------------------------------------------------
717a57c2
VZ
55// wxMenuItem
56// ----------------------------------------------------------------------------
57
d65c269b
VZ
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;
e0dd12db
RD
75 if (m_id == wxID_ANY)
76 m_id = wxNewId();
77 if (m_id == wxID_SEPARATOR)
78 m_kind = wxITEM_SEPARATOR;
d65c269b
VZ
79}
80
717a57c2
VZ
81wxMenuItemBase::~wxMenuItemBase()
82{
1e6feb95 83 delete m_subMenu;
717a57c2
VZ
84}
85
86#if wxUSE_ACCEL
87
c53207a5
VS
88static 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
1e6feb95
VZ
97// return wxAcceleratorEntry for the given menu string or NULL if none
98// specified
99wxAcceleratorEntry *wxGetAccelFromString(const wxString& label)
100{
6d971354
RR
101 // wxPrintf( wxT("label %s\n"), label.c_str() );
102
1e6feb95
VZ
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] == '-') ) {
c53207a5 112 if ( CompareAccelString(current, wxTRANSLATE("ctrl")) )
1e6feb95 113 accelFlags |= wxACCEL_CTRL;
c53207a5 114 else if ( CompareAccelString(current, wxTRANSLATE("alt")) )
1e6feb95 115 accelFlags |= wxACCEL_ALT;
c53207a5 116 else if ( CompareAccelString(current, wxTRANSLATE("shift")) )
1e6feb95
VZ
117 accelFlags |= wxACCEL_SHIFT;
118 else {
a070d8ce
VZ
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 }
1e6feb95
VZ
135 }
136
a070d8ce 137 current.clear();
1e6feb95
VZ
138 }
139 else {
a380af4d 140 current += (wxChar) wxTolower(label[n]);
1e6feb95
VZ
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
c921fd59
GD
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 }
1e6feb95
VZ
157 }
158 else {
159 // is it a function key?
1c193821 160 if ( current[0U] == 'f' && wxIsdigit(current[1U]) &&
1e6feb95 161 (current.Len() == 2 ||
1c193821 162 (current.Len() == 3 && wxIsdigit(current[2U]))) ) {
1e6feb95
VZ
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();
41b78190 171 if ( current == wxT("DEL") )
1e6feb95 172 keyCode = WXK_DELETE;
41b78190 173 else if ( current == wxT("DELETE") )
1e6feb95 174 keyCode = WXK_DELETE;
41efa9a7
JS
175 else if ( current == wxT("BACK") )
176 keyCode = WXK_BACK;
41b78190 177 else if ( current == wxT("INS") )
1e6feb95 178 keyCode = WXK_INSERT;
41b78190 179 else if ( current == wxT("INSERT") )
1e6feb95 180 keyCode = WXK_INSERT;
41b78190 181 else if ( current == wxT("ENTER") || current == wxT("RETURN") )
2b5f62a0 182 keyCode = WXK_RETURN;
41b78190 183 else if ( current == wxT("PGUP") )
2b5f62a0 184 keyCode = WXK_PRIOR;
41b78190 185 else if ( current == wxT("PGDN") )
2b5f62a0 186 keyCode = WXK_NEXT;
41b78190 187 else if ( current == wxT("LEFT") )
2b5f62a0 188 keyCode = WXK_LEFT;
41b78190 189 else if ( current == wxT("RIGHT") )
2b5f62a0 190 keyCode = WXK_RIGHT;
41b78190 191 else if ( current == wxT("UP") )
2b5f62a0 192 keyCode = WXK_UP;
41b78190 193 else if ( current == wxT("DOWN") )
2b5f62a0 194 keyCode = WXK_DOWN;
41b78190 195 else if ( current == wxT("HOME") )
2b5f62a0 196 keyCode = WXK_HOME;
41b78190 197 else if ( current == wxT("END") )
2b5f62a0 198 keyCode = WXK_END;
41b78190 199 else if ( current == wxT("SPACE") )
2b5f62a0 200 keyCode = WXK_SPACE;
41b78190 201 else if ( current == wxT("TAB") )
2b5f62a0 202 keyCode = WXK_TAB;
73baf01a 203 else if ( current == wxT("ESC") || current == wxT("ESCAPE") )
41b78190 204 keyCode = WXK_ESCAPE;
1e6feb95
VZ
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
223wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
224{
225 return wxGetAccelFromString(GetText());
226}
227
717a57c2
VZ
228void 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
6d971354
RR
281bool wxMenuBase::ms_locked = true;
282
717a57c2
VZ
283// ----------------------------------------------------------------------------
284// wxMenu ctor and dtor
285// ----------------------------------------------------------------------------
286
287void wxMenuBase::Init(long style)
288{
717a57c2
VZ
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
298wxMenuBase::~wxMenuBase()
299{
222ed1d6 300 WX_CLEAR_LIST(wxMenuItemList, m_items);
41efa9a7 301
1e6feb95 302 // Actually, in GTK, the submenus have to get deleted first.
717a57c2
VZ
303}
304
305// ----------------------------------------------------------------------------
306// wxMenu item adding/removing
307// ----------------------------------------------------------------------------
308
1e6feb95
VZ
309void wxMenuBase::AddSubMenu(wxMenu *submenu)
310{
311 wxCHECK_RET( submenu, _T("can't add a NULL submenu") );
312
313 if ( m_menuBar )
314 {
315 submenu->Attach(m_menuBar);
316 }
317
318 submenu->SetParent((wxMenu *)this);
319}
320
9add9367 321wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item)
717a57c2 322{
9add9367 323 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") );
717a57c2
VZ
324
325 m_items.Append(item);
1e93ca17 326 item->SetMenu((wxMenu*)this);
1e6feb95
VZ
327 if ( item->IsSubMenu() )
328 {
329 AddSubMenu(item->GetSubMenu());
330 }
717a57c2 331
9add9367 332 return item;
717a57c2
VZ
333}
334
9add9367 335wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item)
717a57c2 336{
9add9367 337 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") );
717a57c2 338
32db328c
VZ
339 if ( pos == GetMenuItemCount() )
340 {
341 return DoAppend(item);
342 }
343 else
344 {
345 wxCHECK_MSG( pos < GetMenuItemCount(), FALSE,
346 wxT("invalid index in wxMenu::Insert") );
347
348 return DoInsert(pos, item);
349 }
717a57c2
VZ
350}
351
9add9367 352wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
717a57c2 353{
9add9367 354 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") );
717a57c2 355
222ed1d6 356 wxMenuItemList::compatibility_iterator node = m_items.Item(pos);
717a57c2
VZ
357 wxCHECK_MSG( node, FALSE, wxT("invalid index in wxMenu::Insert()") );
358
359 m_items.Insert(node, item);
1e93ca17 360 item->SetMenu((wxMenu*)this);
1e6feb95
VZ
361 if ( item->IsSubMenu() )
362 {
363 AddSubMenu(item->GetSubMenu());
364 }
717a57c2 365
9add9367 366 return item;
717a57c2
VZ
367}
368
369wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
370{
371 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
372
373 return DoRemove(item);
374}
375
376wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
377{
222ed1d6 378 wxMenuItemList::compatibility_iterator node = m_items.Find(item);
717a57c2
VZ
379
380 // if we get here, the item is valid or one of Remove() functions is broken
381 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
382
383 // we detach the item, but we do delete the list node (i.e. don't call
384 // DetachNode() here!)
222ed1d6 385 m_items.Erase(node);
717a57c2
VZ
386
387 // item isn't attached to anything any more
1e93ca17 388 item->SetMenu((wxMenu *)NULL);
717a57c2
VZ
389 wxMenu *submenu = item->GetSubMenu();
390 if ( submenu )
391 {
392 submenu->SetParent((wxMenu *)NULL);
393 }
394
395 return item;
396}
397
398bool wxMenuBase::Delete(wxMenuItem *item)
399{
39d03faf 400 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Delete") );
717a57c2
VZ
401
402 return DoDelete(item);
403}
404
405bool wxMenuBase::DoDelete(wxMenuItem *item)
406{
407 wxMenuItem *item2 = DoRemove(item);
408 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
409
410 // don't delete the submenu
411 item2->SetSubMenu((wxMenu *)NULL);
412
413 delete item2;
414
415 return TRUE;
416}
417
418bool wxMenuBase::Destroy(wxMenuItem *item)
419{
39d03faf 420 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Destroy") );
717a57c2
VZ
421
422 return DoDestroy(item);
423}
424
425bool wxMenuBase::DoDestroy(wxMenuItem *item)
426{
427 wxMenuItem *item2 = DoRemove(item);
428 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
429
430 delete item2;
431
432 return TRUE;
433}
434
435// ----------------------------------------------------------------------------
436// wxMenu searching for items
437// ----------------------------------------------------------------------------
438
439// Finds the item id matching the given string, -1 if not found.
440int wxMenuBase::FindItem(const wxString& text) const
441{
3b59cdbf 442 wxString label = wxMenuItem::GetLabelFromText(text);
222ed1d6 443 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
717a57c2
VZ
444 node;
445 node = node->GetNext() )
446 {
447 wxMenuItem *item = node->GetData();
448 if ( item->IsSubMenu() )
449 {
450 int rc = item->GetSubMenu()->FindItem(label);
451 if ( rc != wxNOT_FOUND )
452 return rc;
453 }
adb21613
VZ
454
455 // we execute this code for submenus as well to alllow finding them by
456 // name just like the ordinary items
457 if ( !item->IsSeparator() )
717a57c2
VZ
458 {
459 if ( item->GetLabel() == label )
460 return item->GetId();
461 }
462 }
463
464 return wxNOT_FOUND;
465}
466
467// recursive search for item by id
468wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
469{
470 if ( itemMenu )
471 *itemMenu = NULL;
472
473 wxMenuItem *item = NULL;
222ed1d6 474 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
717a57c2
VZ
475 node && !item;
476 node = node->GetNext() )
477 {
478 item = node->GetData();
479
480 if ( item->GetId() == itemId )
481 {
482 if ( itemMenu )
483 *itemMenu = (wxMenu *)this;
484 }
485 else if ( item->IsSubMenu() )
486 {
487 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
488 }
489 else
490 {
491 // don't exit the loop
492 item = NULL;
493 }
494 }
495
496 return item;
497}
498
499// non recursive search
500wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
501{
502 wxMenuItem *item = (wxMenuItem *)NULL;
222ed1d6 503 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
717a57c2
VZ
504
505 size_t pos;
506 for ( pos = 0; node; pos++ )
507 {
1dddf838
VZ
508 if ( node->GetData()->GetId() == id )
509 {
510 item = node->GetData();
511
717a57c2 512 break;
1dddf838 513 }
717a57c2
VZ
514
515 node = node->GetNext();
516 }
517
518 if ( ppos )
519 {
1987af7e 520 *ppos = item ? pos : (size_t)wxNOT_FOUND;
717a57c2
VZ
521 }
522
523 return item;
524}
525
01ebf752
JS
526// find by position
527wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const
528{
20aed026
VZ
529 wxCHECK_MSG( position < m_items.GetCount(), NULL,
530 _T("wxMenu::FindItemByPosition(): invalid menu index") );
531
532 return m_items.Item( position )->GetData();
01ebf752
JS
533}
534
717a57c2 535// ----------------------------------------------------------------------------
1e6feb95 536// wxMenu helpers used by derived classes
717a57c2
VZ
537// ----------------------------------------------------------------------------
538
539// Update a menu and all submenus recursively. source is the object that has
540// the update event handlers defined for it. If NULL, the menu or associated
541// window will be used.
542void wxMenuBase::UpdateUI(wxEvtHandler* source)
543{
5ce61d9f
RR
544 if (GetInvokingWindow())
545 {
546 // Don't update menus if the parent
547 // frame is about to get deleted
548 wxWindow *tlw = wxGetTopLevelParent( GetInvokingWindow() );
549 if (tlw && wxPendingDelete.Member(tlw))
550 return;
551 }
552
717a57c2
VZ
553 if ( !source && GetInvokingWindow() )
554 source = GetInvokingWindow()->GetEventHandler();
555 if ( !source )
556 source = GetEventHandler();
557 if ( !source )
558 source = this;
559
222ed1d6 560 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
717a57c2
VZ
561 while ( node )
562 {
563 wxMenuItem* item = node->GetData();
564 if ( !item->IsSeparator() )
565 {
566 wxWindowID id = item->GetId();
567 wxUpdateUIEvent event(id);
568 event.SetEventObject( source );
569
570 if ( source->ProcessEvent(event) )
571 {
18afa2ac 572 // if anything changed, update the changed attribute
717a57c2
VZ
573 if (event.GetSetText())
574 SetLabel(id, event.GetText());
575 if (event.GetSetChecked())
576 Check(id, event.GetChecked());
577 if (event.GetSetEnabled())
578 Enable(id, event.GetEnabled());
579 }
580
581 // recurse to the submenus
582 if ( item->GetSubMenu() )
583 item->GetSubMenu()->UpdateUI(source);
584 }
18afa2ac 585 //else: item is a separator (which doesn't process update UI events)
717a57c2
VZ
586
587 node = node->GetNext();
588 }
589}
590
1e6feb95
VZ
591bool wxMenuBase::SendEvent(int id, int checked)
592{
593 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
594 event.SetEventObject(this);
595 event.SetInt(checked);
596
597 bool processed = FALSE;
598
1e6feb95
VZ
599 // Try the menu's event handler
600 if ( !processed )
601 {
602 wxEvtHandler *handler = GetEventHandler();
603 if ( handler )
604 processed = handler->ProcessEvent(event);
605 }
606
607 // Try the window the menu was popped up from (and up through the
608 // hierarchy)
609 if ( !processed )
610 {
611 const wxMenuBase *menu = this;
612 while ( menu )
613 {
614 wxWindow *win = menu->GetInvokingWindow();
615 if ( win )
616 {
617 processed = win->GetEventHandler()->ProcessEvent(event);
618 break;
619 }
620
621 menu = menu->GetParent();
622 }
623 }
624
625 return processed;
626}
627
628// ----------------------------------------------------------------------------
629// wxMenu attaching/detaching to/from menu bar
630// ----------------------------------------------------------------------------
631
632void wxMenuBase::Attach(wxMenuBarBase *menubar)
633{
634 // use Detach() instead!
635 wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") );
636
637 // use IsAttached() to prevent this from happening
638 wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") );
639
640 m_menuBar = (wxMenuBar *)menubar;
641}
642
643void wxMenuBase::Detach()
644{
645 // use IsAttached() to prevent this from happening
646 wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") );
647
648 m_menuBar = NULL;
649}
650
717a57c2
VZ
651// ----------------------------------------------------------------------------
652// wxMenu functions forwarded to wxMenuItem
653// ----------------------------------------------------------------------------
654
655void wxMenuBase::Enable( int id, bool enable )
656{
657 wxMenuItem *item = FindItem(id);
658
659 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
660
661 item->Enable(enable);
662}
663
664bool wxMenuBase::IsEnabled( int id ) const
665{
666 wxMenuItem *item = FindItem(id);
667
668 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") );
669
670 return item->IsEnabled();
671}
672
673void wxMenuBase::Check( int id, bool enable )
674{
675 wxMenuItem *item = FindItem(id);
676
677 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
678
679 item->Check(enable);
680}
681
682bool wxMenuBase::IsChecked( int id ) const
683{
684 wxMenuItem *item = FindItem(id);
685
686 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") );
687
688 return item->IsChecked();
689}
690
691void wxMenuBase::SetLabel( int id, const wxString &label )
692{
693 wxMenuItem *item = FindItem(id);
694
695 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
696
697 item->SetText(label);
698}
699
700wxString wxMenuBase::GetLabel( int id ) const
701{
702 wxMenuItem *item = FindItem(id);
703
704 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") );
705
706 return item->GetText();
707}
708
709void wxMenuBase::SetHelpString( int id, const wxString& helpString )
710{
711 wxMenuItem *item = FindItem(id);
712
713 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
714
715 item->SetHelp( helpString );
716}
717
718wxString wxMenuBase::GetHelpString( int id ) const
719{
720 wxMenuItem *item = FindItem(id);
721
722 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
723
724 return item->GetHelp();
725}
726
727// ----------------------------------------------------------------------------
728// wxMenuBarBase ctor and dtor
3dfac970
VZ
729// ----------------------------------------------------------------------------
730
731wxMenuBarBase::wxMenuBarBase()
732{
1e6feb95
VZ
733 // not attached yet
734 m_menuBarFrame = NULL;
3dfac970
VZ
735}
736
737wxMenuBarBase::~wxMenuBarBase()
738{
222ed1d6 739 WX_CLEAR_LIST(wxMenuList, m_menus);
3dfac970
VZ
740}
741
742// ----------------------------------------------------------------------------
743// wxMenuBar item access: the base class versions manage m_menus list, the
744// derived class should reflect the changes in the real menubar
745// ----------------------------------------------------------------------------
746
747wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
748{
222ed1d6 749 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
3dfac970
VZ
750 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
751
752 return node->GetData();
753}
754
755bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title))
756{
757 wxCHECK_MSG( menu, FALSE, wxT("can't append NULL menu") );
758
759 m_menus.Append(menu);
1e6feb95 760 menu->Attach(this);
3dfac970
VZ
761
762 return TRUE;
763}
764
765bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
32db328c 766 const wxString& title)
3dfac970 767{
32db328c
VZ
768 if ( pos == m_menus.GetCount() )
769 {
186baeb2 770 return wxMenuBarBase::Append(menu, title);
32db328c 771 }
1e6feb95 772 else // not at the end
32db328c
VZ
773 {
774 wxCHECK_MSG( menu, FALSE, wxT("can't insert NULL menu") );
3dfac970 775
222ed1d6 776 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
32db328c 777 wxCHECK_MSG( node, FALSE, wxT("bad index in wxMenuBar::Insert()") );
3dfac970 778
32db328c 779 m_menus.Insert(node, menu);
1e6feb95 780 menu->Attach(this);
3dfac970 781
32db328c
VZ
782 return TRUE;
783 }
3dfac970
VZ
784}
785
786wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
787 const wxString& WXUNUSED(title))
788{
789 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
790
222ed1d6 791 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
3dfac970
VZ
792 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
793
794 wxMenu *menuOld = node->GetData();
795 node->SetData(menu);
796
1e6feb95
VZ
797 menu->Attach(this);
798 menuOld->Detach();
799
3dfac970
VZ
800 return menuOld;
801}
802
803wxMenu *wxMenuBarBase::Remove(size_t pos)
804{
222ed1d6 805 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
3dfac970
VZ
806 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
807
3dfac970 808 wxMenu *menu = node->GetData();
222ed1d6 809 m_menus.Erase(node);
1e6feb95 810 menu->Detach();
3dfac970 811
3dfac970
VZ
812 return menu;
813}
814
270e8b6a 815int wxMenuBarBase::FindMenu(const wxString& title) const
52130557
VZ
816{
817 wxString label = wxMenuItem::GetLabelFromText(title);
818
819 size_t count = GetMenuCount();
820 for ( size_t i = 0; i < count; i++ )
821 {
822 wxString title2 = GetLabelTop(i);
823 if ( (title2 == title) ||
824 (wxMenuItem::GetLabelFromText(title2) == label) )
825 {
826 // found
2b5f62a0 827 return (int)i;
52130557
VZ
828 }
829 }
830
831 return wxNOT_FOUND;
832
833}
834
1e6feb95
VZ
835// ----------------------------------------------------------------------------
836// wxMenuBar attaching/detaching to/from the frame
837// ----------------------------------------------------------------------------
838
839void wxMenuBarBase::Attach(wxFrame *frame)
840{
841 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
842
843 m_menuBarFrame = frame;
844}
845
846void wxMenuBarBase::Detach()
847{
848 wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
849
850 m_menuBarFrame = NULL;
851}
852
853// ----------------------------------------------------------------------------
854// wxMenuBar searching for items
855// ----------------------------------------------------------------------------
856
857wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const
858{
859 if ( menu )
860 *menu = NULL;
861
862 wxMenuItem *item = NULL;
222ed1d6
MB
863 size_t count = GetMenuCount(), i;
864 wxMenuList::const_iterator it;
865 for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ )
1e6feb95 866 {
222ed1d6 867 item = (*it)->FindItem(id, menu);
1e6feb95
VZ
868 }
869
870 return item;
871}
872
873int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
874{
875 wxString label = wxMenuItem::GetLabelFromText(menu);
876
877 int i = 0;
222ed1d6 878 wxMenuList::compatibility_iterator node;
1e6feb95
VZ
879 for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
880 {
881 if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) )
882 return node->GetData()->FindItem(item);
883 }
884
885 return wxNOT_FOUND;
886}
887
3dfac970
VZ
888// ---------------------------------------------------------------------------
889// wxMenuBar functions forwarded to wxMenuItem
890// ---------------------------------------------------------------------------
891
892void wxMenuBarBase::Enable(int id, bool enable)
893{
894 wxMenuItem *item = FindItem(id);
895
896 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
897
898 item->Enable(enable);
899}
900
901void wxMenuBarBase::Check(int id, bool check)
902{
903 wxMenuItem *item = FindItem(id);
904
905 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
906 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
907
908 item->Check(check);
909}
910
911bool wxMenuBarBase::IsChecked(int id) const
912{
913 wxMenuItem *item = FindItem(id);
914
915 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") );
916
917 return item->IsChecked();
918}
919
920bool wxMenuBarBase::IsEnabled(int id) const
921{
922 wxMenuItem *item = FindItem(id);
923
924 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") );
925
926 return item->IsEnabled();
927}
928
929void wxMenuBarBase::SetLabel(int id, const wxString& label)
930{
931 wxMenuItem *item = FindItem(id);
932
933 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
934
935 item->SetText(label);
936}
937
938wxString wxMenuBarBase::GetLabel(int id) const
939{
940 wxMenuItem *item = FindItem(id);
941
942 wxCHECK_MSG( item, wxEmptyString,
943 wxT("wxMenuBar::GetLabel(): no such item") );
944
945 return item->GetText();
946}
947
948void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
949{
950 wxMenuItem *item = FindItem(id);
951
952 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
953
954 item->SetHelp(helpString);
955}
956
957wxString wxMenuBarBase::GetHelpString(int id) const
958{
959 wxMenuItem *item = FindItem(id);
960
961 wxCHECK_MSG( item, wxEmptyString,
962 wxT("wxMenuBar::GetHelpString(): no such item") );
963
964 return item->GetHelp();
965}
966
1e6feb95 967#endif // wxUSE_MENUS