]> git.saurik.com Git - wxWidgets.git/blame - src/common/menucmn.cpp
Fix crash when using a proxy (m_protocol already gets cleaned up via CleanData())
[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$
77ffb593 8// Copyright: (c) wxWidgets team
65571936 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;
4e32eea1
WS
71 m_isEnabled = true;
72 m_isChecked = false;
d65c269b
VZ
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
525d8583 144 if ( current.empty() ) {
1e6feb95
VZ
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());
7d098cfd 209 return NULL;
1e6feb95
VZ
210 }
211 }
212 }
213 }
214
215 if ( keyCode ) {
216 // we do have something
217 return new wxAcceleratorEntry(accelFlags, keyCode);
218 }
219 }
220
221 return (wxAcceleratorEntry *)NULL;
222}
223
224wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
225{
226 return wxGetAccelFromString(GetText());
227}
228
717a57c2
VZ
229void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
230{
231 wxString text = m_text.BeforeFirst(wxT('\t'));
232 if ( accel )
233 {
234 text += wxT('\t');
235
236 int flags = accel->GetFlags();
237 if ( flags & wxACCEL_ALT )
238 text += wxT("Alt-");
239 if ( flags & wxACCEL_CTRL )
240 text += wxT("Ctrl-");
241 if ( flags & wxACCEL_SHIFT )
242 text += wxT("Shift-");
243
244 int code = accel->GetKeyCode();
245 switch ( code )
246 {
247 case WXK_F1:
248 case WXK_F2:
249 case WXK_F3:
250 case WXK_F4:
251 case WXK_F5:
252 case WXK_F6:
253 case WXK_F7:
254 case WXK_F8:
255 case WXK_F9:
256 case WXK_F10:
257 case WXK_F11:
258 case WXK_F12:
259 text << wxT('F') << code - WXK_F1 + 1;
260 break;
261
262 // if there are any other keys wxGetAccelFromString() may return,
263 // we should process them here
264
265 default:
0c6099b7 266 if ( wxIsalnum(code) )
717a57c2
VZ
267 {
268 text << (wxChar)code;
269
270 break;
271 }
272
273 wxFAIL_MSG( wxT("unknown keyboard accel") );
274 }
275 }
276
277 SetText(text);
278}
279
280#endif // wxUSE_ACCEL
281
6d971354
RR
282bool wxMenuBase::ms_locked = true;
283
717a57c2
VZ
284// ----------------------------------------------------------------------------
285// wxMenu ctor and dtor
286// ----------------------------------------------------------------------------
287
288void wxMenuBase::Init(long style)
289{
717a57c2
VZ
290 m_menuBar = (wxMenuBar *)NULL;
291 m_menuParent = (wxMenu *)NULL;
292
293 m_invokingWindow = (wxWindow *)NULL;
294 m_style = style;
295 m_clientData = (void *)NULL;
296 m_eventHandler = this;
297}
298
299wxMenuBase::~wxMenuBase()
300{
222ed1d6 301 WX_CLEAR_LIST(wxMenuItemList, m_items);
41efa9a7 302
1e6feb95 303 // Actually, in GTK, the submenus have to get deleted first.
717a57c2
VZ
304}
305
306// ----------------------------------------------------------------------------
307// wxMenu item adding/removing
308// ----------------------------------------------------------------------------
309
1e6feb95
VZ
310void wxMenuBase::AddSubMenu(wxMenu *submenu)
311{
312 wxCHECK_RET( submenu, _T("can't add a NULL submenu") );
313
1e6feb95
VZ
314 submenu->SetParent((wxMenu *)this);
315}
316
9add9367 317wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item)
717a57c2 318{
9add9367 319 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") );
717a57c2
VZ
320
321 m_items.Append(item);
1e93ca17 322 item->SetMenu((wxMenu*)this);
1e6feb95
VZ
323 if ( item->IsSubMenu() )
324 {
325 AddSubMenu(item->GetSubMenu());
326 }
717a57c2 327
9add9367 328 return item;
717a57c2
VZ
329}
330
9add9367 331wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item)
717a57c2 332{
9add9367 333 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") );
717a57c2 334
32db328c
VZ
335 if ( pos == GetMenuItemCount() )
336 {
337 return DoAppend(item);
338 }
339 else
340 {
4e32eea1 341 wxCHECK_MSG( pos < GetMenuItemCount(), NULL,
32db328c
VZ
342 wxT("invalid index in wxMenu::Insert") );
343
344 return DoInsert(pos, item);
345 }
717a57c2
VZ
346}
347
9add9367 348wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
717a57c2 349{
9add9367 350 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") );
717a57c2 351
222ed1d6 352 wxMenuItemList::compatibility_iterator node = m_items.Item(pos);
4e32eea1 353 wxCHECK_MSG( node, NULL, wxT("invalid index in wxMenu::Insert()") );
717a57c2
VZ
354
355 m_items.Insert(node, item);
1e93ca17 356 item->SetMenu((wxMenu*)this);
1e6feb95
VZ
357 if ( item->IsSubMenu() )
358 {
359 AddSubMenu(item->GetSubMenu());
360 }
717a57c2 361
9add9367 362 return item;
717a57c2
VZ
363}
364
365wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
366{
367 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
368
369 return DoRemove(item);
370}
371
372wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
373{
222ed1d6 374 wxMenuItemList::compatibility_iterator node = m_items.Find(item);
717a57c2
VZ
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!)
222ed1d6 381 m_items.Erase(node);
717a57c2
VZ
382
383 // item isn't attached to anything any more
1e93ca17 384 item->SetMenu((wxMenu *)NULL);
717a57c2
VZ
385 wxMenu *submenu = item->GetSubMenu();
386 if ( submenu )
387 {
388 submenu->SetParent((wxMenu *)NULL);
082006f3
VZ
389 if ( submenu->IsAttached() )
390 submenu->Detach();
717a57c2
VZ
391 }
392
393 return item;
394}
395
396bool wxMenuBase::Delete(wxMenuItem *item)
397{
4e32eea1 398 wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Delete") );
717a57c2
VZ
399
400 return DoDelete(item);
401}
402
403bool wxMenuBase::DoDelete(wxMenuItem *item)
404{
405 wxMenuItem *item2 = DoRemove(item);
4e32eea1 406 wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
717a57c2
VZ
407
408 // don't delete the submenu
409 item2->SetSubMenu((wxMenu *)NULL);
410
411 delete item2;
412
4e32eea1 413 return true;
717a57c2
VZ
414}
415
416bool wxMenuBase::Destroy(wxMenuItem *item)
417{
4e32eea1 418 wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Destroy") );
717a57c2
VZ
419
420 return DoDestroy(item);
421}
422
423bool wxMenuBase::DoDestroy(wxMenuItem *item)
424{
425 wxMenuItem *item2 = DoRemove(item);
4e32eea1 426 wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
717a57c2
VZ
427
428 delete item2;
429
4e32eea1 430 return true;
717a57c2
VZ
431}
432
433// ----------------------------------------------------------------------------
434// wxMenu searching for items
435// ----------------------------------------------------------------------------
436
4e32eea1 437// Finds the item id matching the given string, wxNOT_FOUND if not found.
717a57c2
VZ
438int wxMenuBase::FindItem(const wxString& text) const
439{
3b59cdbf 440 wxString label = wxMenuItem::GetLabelFromText(text);
222ed1d6 441 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
717a57c2
VZ
442 node;
443 node = node->GetNext() )
444 {
445 wxMenuItem *item = node->GetData();
446 if ( item->IsSubMenu() )
447 {
448 int rc = item->GetSubMenu()->FindItem(label);
449 if ( rc != wxNOT_FOUND )
450 return rc;
451 }
adb21613
VZ
452
453 // we execute this code for submenus as well to alllow finding them by
454 // name just like the ordinary items
455 if ( !item->IsSeparator() )
717a57c2
VZ
456 {
457 if ( item->GetLabel() == label )
458 return item->GetId();
459 }
460 }
461
462 return wxNOT_FOUND;
463}
464
465// recursive search for item by id
466wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
467{
468 if ( itemMenu )
469 *itemMenu = NULL;
470
471 wxMenuItem *item = NULL;
222ed1d6 472 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
717a57c2
VZ
473 node && !item;
474 node = node->GetNext() )
475 {
476 item = node->GetData();
477
478 if ( item->GetId() == itemId )
479 {
480 if ( itemMenu )
481 *itemMenu = (wxMenu *)this;
482 }
483 else if ( item->IsSubMenu() )
484 {
485 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
486 }
487 else
488 {
489 // don't exit the loop
490 item = NULL;
491 }
492 }
493
494 return item;
495}
496
497// non recursive search
498wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
499{
500 wxMenuItem *item = (wxMenuItem *)NULL;
222ed1d6 501 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
717a57c2
VZ
502
503 size_t pos;
504 for ( pos = 0; node; pos++ )
505 {
1dddf838
VZ
506 if ( node->GetData()->GetId() == id )
507 {
508 item = node->GetData();
509
717a57c2 510 break;
1dddf838 511 }
717a57c2
VZ
512
513 node = node->GetNext();
514 }
515
516 if ( ppos )
517 {
1987af7e 518 *ppos = item ? pos : (size_t)wxNOT_FOUND;
717a57c2
VZ
519 }
520
521 return item;
522}
523
01ebf752
JS
524// find by position
525wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const
526{
20aed026
VZ
527 wxCHECK_MSG( position < m_items.GetCount(), NULL,
528 _T("wxMenu::FindItemByPosition(): invalid menu index") );
529
530 return m_items.Item( position )->GetData();
01ebf752
JS
531}
532
717a57c2 533// ----------------------------------------------------------------------------
1e6feb95 534// wxMenu helpers used by derived classes
717a57c2
VZ
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.
540void wxMenuBase::UpdateUI(wxEvtHandler* source)
541{
5ce61d9f
RR
542 if (GetInvokingWindow())
543 {
544 // Don't update menus if the parent
545 // frame is about to get deleted
546 wxWindow *tlw = wxGetTopLevelParent( GetInvokingWindow() );
547 if (tlw && wxPendingDelete.Member(tlw))
548 return;
549 }
550
717a57c2
VZ
551 if ( !source && GetInvokingWindow() )
552 source = GetInvokingWindow()->GetEventHandler();
553 if ( !source )
554 source = GetEventHandler();
555 if ( !source )
556 source = this;
557
222ed1d6 558 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
717a57c2
VZ
559 while ( node )
560 {
561 wxMenuItem* item = node->GetData();
562 if ( !item->IsSeparator() )
563 {
564 wxWindowID id = item->GetId();
565 wxUpdateUIEvent event(id);
566 event.SetEventObject( source );
567
568 if ( source->ProcessEvent(event) )
569 {
18afa2ac 570 // if anything changed, update the changed attribute
717a57c2
VZ
571 if (event.GetSetText())
572 SetLabel(id, event.GetText());
573 if (event.GetSetChecked())
574 Check(id, event.GetChecked());
575 if (event.GetSetEnabled())
576 Enable(id, event.GetEnabled());
577 }
578
579 // recurse to the submenus
580 if ( item->GetSubMenu() )
581 item->GetSubMenu()->UpdateUI(source);
582 }
18afa2ac 583 //else: item is a separator (which doesn't process update UI events)
717a57c2
VZ
584
585 node = node->GetNext();
586 }
587}
588
1e6feb95
VZ
589bool wxMenuBase::SendEvent(int id, int checked)
590{
591 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
592 event.SetEventObject(this);
593 event.SetInt(checked);
594
4e32eea1 595 bool processed = false;
1e6feb95 596
1e6feb95
VZ
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
dbdf9a17
DE
630wxMenuBar* wxMenuBase::GetMenuBar() const
631{
632 if(GetParent())
633 return GetParent()->GetMenuBar();
634 return m_menuBar;
635}
636
1e6feb95
VZ
637void wxMenuBase::Attach(wxMenuBarBase *menubar)
638{
639 // use Detach() instead!
640 wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") );
641
642 // use IsAttached() to prevent this from happening
643 wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") );
644
645 m_menuBar = (wxMenuBar *)menubar;
646}
647
648void wxMenuBase::Detach()
649{
650 // use IsAttached() to prevent this from happening
651 wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") );
652
653 m_menuBar = NULL;
654}
655
717a57c2
VZ
656// ----------------------------------------------------------------------------
657// wxMenu functions forwarded to wxMenuItem
658// ----------------------------------------------------------------------------
659
660void wxMenuBase::Enable( int id, bool enable )
661{
662 wxMenuItem *item = FindItem(id);
663
664 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
665
666 item->Enable(enable);
667}
668
669bool wxMenuBase::IsEnabled( int id ) const
670{
671 wxMenuItem *item = FindItem(id);
672
4e32eea1 673 wxCHECK_MSG( item, false, wxT("wxMenu::IsEnabled: no such item") );
717a57c2
VZ
674
675 return item->IsEnabled();
676}
677
678void wxMenuBase::Check( int id, bool enable )
679{
680 wxMenuItem *item = FindItem(id);
681
682 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
683
684 item->Check(enable);
685}
686
687bool wxMenuBase::IsChecked( int id ) const
688{
689 wxMenuItem *item = FindItem(id);
690
4e32eea1 691 wxCHECK_MSG( item, false, wxT("wxMenu::IsChecked: no such item") );
717a57c2
VZ
692
693 return item->IsChecked();
694}
695
696void wxMenuBase::SetLabel( int id, const wxString &label )
697{
698 wxMenuItem *item = FindItem(id);
699
700 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
701
702 item->SetText(label);
703}
704
705wxString wxMenuBase::GetLabel( int id ) const
706{
707 wxMenuItem *item = FindItem(id);
708
525d8583 709 wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetLabel: no such item") );
717a57c2
VZ
710
711 return item->GetText();
712}
713
714void wxMenuBase::SetHelpString( int id, const wxString& helpString )
715{
716 wxMenuItem *item = FindItem(id);
717
718 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
719
720 item->SetHelp( helpString );
721}
722
723wxString wxMenuBase::GetHelpString( int id ) const
724{
725 wxMenuItem *item = FindItem(id);
726
525d8583 727 wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetHelpString: no such item") );
717a57c2
VZ
728
729 return item->GetHelp();
730}
731
732// ----------------------------------------------------------------------------
733// wxMenuBarBase ctor and dtor
3dfac970
VZ
734// ----------------------------------------------------------------------------
735
736wxMenuBarBase::wxMenuBarBase()
737{
1e6feb95
VZ
738 // not attached yet
739 m_menuBarFrame = NULL;
3dfac970
VZ
740}
741
742wxMenuBarBase::~wxMenuBarBase()
743{
222ed1d6 744 WX_CLEAR_LIST(wxMenuList, m_menus);
3dfac970
VZ
745}
746
747// ----------------------------------------------------------------------------
748// wxMenuBar item access: the base class versions manage m_menus list, the
749// derived class should reflect the changes in the real menubar
750// ----------------------------------------------------------------------------
751
752wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
753{
222ed1d6 754 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
3dfac970
VZ
755 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
756
757 return node->GetData();
758}
759
760bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title))
761{
4e32eea1 762 wxCHECK_MSG( menu, false, wxT("can't append NULL menu") );
3dfac970
VZ
763
764 m_menus.Append(menu);
1e6feb95 765 menu->Attach(this);
3dfac970 766
4e32eea1 767 return true;
3dfac970
VZ
768}
769
770bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
32db328c 771 const wxString& title)
3dfac970 772{
32db328c
VZ
773 if ( pos == m_menus.GetCount() )
774 {
186baeb2 775 return wxMenuBarBase::Append(menu, title);
32db328c 776 }
1e6feb95 777 else // not at the end
32db328c 778 {
4e32eea1 779 wxCHECK_MSG( menu, false, wxT("can't insert NULL menu") );
3dfac970 780
222ed1d6 781 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
4e32eea1 782 wxCHECK_MSG( node, false, wxT("bad index in wxMenuBar::Insert()") );
3dfac970 783
32db328c 784 m_menus.Insert(node, menu);
1e6feb95 785 menu->Attach(this);
3dfac970 786
4e32eea1 787 return true;
32db328c 788 }
3dfac970
VZ
789}
790
791wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
792 const wxString& WXUNUSED(title))
793{
794 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
795
222ed1d6 796 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
3dfac970
VZ
797 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
798
799 wxMenu *menuOld = node->GetData();
800 node->SetData(menu);
801
1e6feb95
VZ
802 menu->Attach(this);
803 menuOld->Detach();
804
3dfac970
VZ
805 return menuOld;
806}
807
808wxMenu *wxMenuBarBase::Remove(size_t pos)
809{
222ed1d6 810 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
3dfac970
VZ
811 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
812
3dfac970 813 wxMenu *menu = node->GetData();
222ed1d6 814 m_menus.Erase(node);
1e6feb95 815 menu->Detach();
3dfac970 816
3dfac970
VZ
817 return menu;
818}
819
270e8b6a 820int wxMenuBarBase::FindMenu(const wxString& title) const
52130557
VZ
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
2b5f62a0 832 return (int)i;
52130557
VZ
833 }
834 }
835
836 return wxNOT_FOUND;
837
838}
839
1e6feb95
VZ
840// ----------------------------------------------------------------------------
841// wxMenuBar attaching/detaching to/from the frame
842// ----------------------------------------------------------------------------
843
844void wxMenuBarBase::Attach(wxFrame *frame)
845{
846 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
847
848 m_menuBarFrame = frame;
849}
850
851void 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
862wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const
863{
864 if ( menu )
865 *menu = NULL;
866
867 wxMenuItem *item = NULL;
222ed1d6
MB
868 size_t count = GetMenuCount(), i;
869 wxMenuList::const_iterator it;
870 for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ )
1e6feb95 871 {
222ed1d6 872 item = (*it)->FindItem(id, menu);
1e6feb95
VZ
873 }
874
875 return item;
876}
877
878int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
879{
880 wxString label = wxMenuItem::GetLabelFromText(menu);
881
882 int i = 0;
222ed1d6 883 wxMenuList::compatibility_iterator node;
1e6feb95
VZ
884 for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
885 {
886 if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) )
887 return node->GetData()->FindItem(item);
888 }
889
890 return wxNOT_FOUND;
891}
892
3dfac970
VZ
893// ---------------------------------------------------------------------------
894// wxMenuBar functions forwarded to wxMenuItem
895// ---------------------------------------------------------------------------
896
897void wxMenuBarBase::Enable(int id, bool enable)
898{
899 wxMenuItem *item = FindItem(id);
900
901 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
902
903 item->Enable(enable);
904}
905
906void wxMenuBarBase::Check(int id, bool check)
907{
908 wxMenuItem *item = FindItem(id);
909
910 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
911 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
912
913 item->Check(check);
914}
915
916bool wxMenuBarBase::IsChecked(int id) const
917{
918 wxMenuItem *item = FindItem(id);
919
4e32eea1 920 wxCHECK_MSG( item, false, wxT("wxMenuBar::IsChecked(): no such item") );
3dfac970
VZ
921
922 return item->IsChecked();
923}
924
925bool wxMenuBarBase::IsEnabled(int id) const
926{
927 wxMenuItem *item = FindItem(id);
928
4e32eea1 929 wxCHECK_MSG( item, false, wxT("wxMenuBar::IsEnabled(): no such item") );
3dfac970
VZ
930
931 return item->IsEnabled();
932}
933
934void wxMenuBarBase::SetLabel(int id, const wxString& label)
935{
936 wxMenuItem *item = FindItem(id);
937
938 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
939
940 item->SetText(label);
941}
942
943wxString wxMenuBarBase::GetLabel(int id) const
944{
945 wxMenuItem *item = FindItem(id);
946
947 wxCHECK_MSG( item, wxEmptyString,
948 wxT("wxMenuBar::GetLabel(): no such item") );
949
950 return item->GetText();
951}
952
953void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
954{
955 wxMenuItem *item = FindItem(id);
956
957 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
958
959 item->SetHelp(helpString);
960}
961
962wxString wxMenuBarBase::GetHelpString(int id) const
963{
964 wxMenuItem *item = FindItem(id);
965
966 wxCHECK_MSG( item, wxEmptyString,
967 wxT("wxMenuBar::GetHelpString(): no such item") );
968
969 return item->GetHelp();
970}
971
1e6feb95 972#endif // wxUSE_MENUS