Source cleaning inspired by and included in patch '[ 1215450 ] cleanup: unreachable...
[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) wxWidgets 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.empty() ) {
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 keyCode = WXK_F1 + wxAtoi(current.c_str() + 1) - 1;
164 }
165 else {
166 // several special cases
167 current.MakeUpper();
168 if ( current == wxT("DEL") )
169 keyCode = WXK_DELETE;
170 else if ( current == wxT("DELETE") )
171 keyCode = WXK_DELETE;
172 else if ( current == wxT("BACK") )
173 keyCode = WXK_BACK;
174 else if ( current == wxT("INS") )
175 keyCode = WXK_INSERT;
176 else if ( current == wxT("INSERT") )
177 keyCode = WXK_INSERT;
178 else if ( current == wxT("ENTER") || current == wxT("RETURN") )
179 keyCode = WXK_RETURN;
180 else if ( current == wxT("PGUP") )
181 keyCode = WXK_PRIOR;
182 else if ( current == wxT("PGDN") )
183 keyCode = WXK_NEXT;
184 else if ( current == wxT("LEFT") )
185 keyCode = WXK_LEFT;
186 else if ( current == wxT("RIGHT") )
187 keyCode = WXK_RIGHT;
188 else if ( current == wxT("UP") )
189 keyCode = WXK_UP;
190 else if ( current == wxT("DOWN") )
191 keyCode = WXK_DOWN;
192 else if ( current == wxT("HOME") )
193 keyCode = WXK_HOME;
194 else if ( current == wxT("END") )
195 keyCode = WXK_END;
196 else if ( current == wxT("SPACE") )
197 keyCode = WXK_SPACE;
198 else if ( current == wxT("TAB") )
199 keyCode = WXK_TAB;
200 else if ( current == wxT("ESC") || current == wxT("ESCAPE") )
201 keyCode = WXK_ESCAPE;
202 else if ( current == wxT("CANCEL") )
203 keyCode = WXK_CANCEL;
204 else if ( current == wxT("CLEAR") )
205 keyCode = WXK_CLEAR;
206 else if ( current == wxT("MENU") )
207 keyCode = WXK_MENU;
208 else if ( current == wxT("PAUSE") )
209 keyCode = WXK_PAUSE;
210 else if ( current == wxT("CAPITAL") )
211 keyCode = WXK_CAPITAL;
212 else if ( current == wxT("SELECT") )
213 keyCode = WXK_SELECT;
214 else if ( current == wxT("PRINT") )
215 keyCode = WXK_PRINT;
216 else if ( current == wxT("EXECUTE") )
217 keyCode = WXK_EXECUTE;
218 else if ( current == wxT("SNAPSHOT") )
219 keyCode = WXK_SNAPSHOT;
220 else if ( current == wxT("HELP") )
221 keyCode = WXK_HELP;
222 else if ( current == wxT("HELP") )
223 keyCode = WXK_HELP;
224 else if ( current == wxT("ADD") )
225 keyCode = WXK_ADD;
226 else if ( current == wxT("SEPARATOR") )
227 keyCode = WXK_SEPARATOR;
228 else if ( current == wxT("SUBTRACT") )
229 keyCode = WXK_SUBTRACT;
230 else if ( current == wxT("DECIMAL") )
231 keyCode = WXK_DECIMAL;
232 else if ( current == wxT("DIVIDE") )
233 keyCode = WXK_DIVIDE;
234 else if ( current == wxT("NUM_LOCK") )
235 keyCode = WXK_NUMLOCK;
236 else if ( current == wxT("SCROLL_LOCK") )
237 keyCode = WXK_SCROLL;
238 else if ( current == wxT("PAGEUP") )
239 keyCode = WXK_PAGEUP;
240 else if ( current == wxT("PAGEDOWN") )
241 keyCode = WXK_PAGEDOWN;
242 else if ( current == wxT("KP_SPACE") )
243 keyCode = WXK_NUMPAD_SPACE;
244 else if ( current == wxT("KP_TAB") )
245 keyCode = WXK_NUMPAD_TAB;
246 else if ( current == wxT("KP_ENTER") )
247 keyCode = WXK_NUMPAD_ENTER;
248 else if ( current == wxT("KP_HOME") )
249 keyCode = WXK_NUMPAD_HOME;
250 else if ( current == wxT("KP_LEFT") )
251 keyCode = WXK_NUMPAD_LEFT;
252 else if ( current == wxT("KP_UP") )
253 keyCode = WXK_NUMPAD_UP;
254 else if ( current == wxT("KP_RIGHT") )
255 keyCode = WXK_NUMPAD_RIGHT;
256 else if ( current == wxT("KP_DOWN") )
257 keyCode = WXK_NUMPAD_DOWN;
258 else if ( current == wxT("KP_PRIOR") )
259 keyCode = WXK_NUMPAD_PRIOR;
260 else if ( current == wxT("KP_PAGEUP") )
261 keyCode = WXK_NUMPAD_PAGEUP;
262 else if ( current == wxT("KP_NEXT;") )
263 keyCode = WXK_NUMPAD_NEXT;
264 else if ( current == wxT("KP_PAGEDOWN") )
265 keyCode = WXK_NUMPAD_PAGEDOWN;
266 else if ( current == wxT("KP_END") )
267 keyCode = WXK_NUMPAD_END;
268 else if ( current == wxT("KP_BEGIN") )
269 keyCode = WXK_NUMPAD_BEGIN;
270 else if ( current == wxT("KP_INSERT") )
271 keyCode = WXK_NUMPAD_INSERT;
272 else if ( current == wxT("KP_DELETE") )
273 keyCode = WXK_NUMPAD_DELETE;
274 else if ( current == wxT("KP_EQUAL") )
275 keyCode = WXK_NUMPAD_EQUAL;
276 else if ( current == wxT("KP_MULTIPLY") )
277 keyCode = WXK_NUMPAD_MULTIPLY;
278 else if ( current == wxT("KP_ADD") )
279 keyCode = WXK_NUMPAD_ADD;
280 else if ( current == wxT("KP_SEPARATOR") )
281 keyCode = WXK_NUMPAD_SEPARATOR;
282 else if ( current == wxT("KP_SUBTRACT") )
283 keyCode = WXK_NUMPAD_SUBTRACT;
284 else if ( current == wxT("KP_DECIMAL") )
285 keyCode = WXK_NUMPAD_DECIMAL;
286 else if ( current == wxT("KP_DIVIDE") )
287 keyCode = WXK_NUMPAD_DIVIDE;
288 else if ( current == wxT("WINDOWS_LEFT") )
289 keyCode = WXK_WINDOWS_LEFT;
290 else if ( current == wxT("WINDOWS_RIGHT") )
291 keyCode = WXK_WINDOWS_RIGHT;
292 else if ( current == wxT("WINDOWS_MENU") )
293 keyCode = WXK_WINDOWS_MENU;
294 else if ( current == wxT("COMMAND") )
295 keyCode = WXK_COMMAND;
296 else if ( current.Left(3) == wxT("KP_") && wxIsdigit(current[3U]) ) {
297 keyCode = WXK_NUMPAD0 + wxAtoi(current.c_str() + 3); }
298 else if ( current.Left(7) == wxT("SPECIAL") && wxIsdigit(current[7U]) ) {
299 keyCode = WXK_SPECIAL1 + wxAtoi(current.c_str() + 7) - 1; }
300 else
301 {
302 wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."),
303 current.c_str());
304 return NULL;
305 }
306 }
307 }
308 }
309
310 if ( keyCode ) {
311 // we do have something
312 return new wxAcceleratorEntry(accelFlags, keyCode);
313 }
314 }
315
316 return (wxAcceleratorEntry *)NULL;
317 }
318
319 wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
320 {
321 return wxGetAccelFromString(GetText());
322 }
323
324 void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
325 {
326 wxString text = m_text.BeforeFirst(wxT('\t'));
327 if ( accel )
328 {
329 text += wxT('\t');
330
331 int flags = accel->GetFlags();
332 if ( flags & wxACCEL_ALT )
333 text += wxT("Alt-");
334 if ( flags & wxACCEL_CTRL )
335 text += wxT("Ctrl-");
336 if ( flags & wxACCEL_SHIFT )
337 text += wxT("Shift-");
338
339 int code = accel->GetKeyCode();
340 switch ( code )
341 {
342 case WXK_F1:
343 case WXK_F2:
344 case WXK_F3:
345 case WXK_F4:
346 case WXK_F5:
347 case WXK_F6:
348 case WXK_F7:
349 case WXK_F8:
350 case WXK_F9:
351 case WXK_F10:
352 case WXK_F11:
353 case WXK_F12:
354 text << wxT('F') << code - WXK_F1 + 1;
355 break;
356
357 // if there are any other keys wxGetAccelFromString() may return,
358 // we should process them here
359
360 default:
361 if ( wxIsalnum(code) )
362 {
363 text << (wxChar)code;
364
365 break;
366 }
367
368 wxFAIL_MSG( wxT("unknown keyboard accel") );
369 }
370 }
371
372 SetText(text);
373 }
374
375 #endif // wxUSE_ACCEL
376
377 bool wxMenuBase::ms_locked = true;
378
379 // ----------------------------------------------------------------------------
380 // wxMenu ctor and dtor
381 // ----------------------------------------------------------------------------
382
383 void wxMenuBase::Init(long style)
384 {
385 m_menuBar = (wxMenuBar *)NULL;
386 m_menuParent = (wxMenu *)NULL;
387
388 m_invokingWindow = (wxWindow *)NULL;
389 m_style = style;
390 m_clientData = (void *)NULL;
391 m_eventHandler = this;
392 }
393
394 wxMenuBase::~wxMenuBase()
395 {
396 WX_CLEAR_LIST(wxMenuItemList, m_items);
397
398 // Actually, in GTK, the submenus have to get deleted first.
399 }
400
401 // ----------------------------------------------------------------------------
402 // wxMenu item adding/removing
403 // ----------------------------------------------------------------------------
404
405 void wxMenuBase::AddSubMenu(wxMenu *submenu)
406 {
407 wxCHECK_RET( submenu, _T("can't add a NULL submenu") );
408
409 submenu->SetParent((wxMenu *)this);
410 }
411
412 wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item)
413 {
414 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") );
415
416 m_items.Append(item);
417 item->SetMenu((wxMenu*)this);
418 if ( item->IsSubMenu() )
419 {
420 AddSubMenu(item->GetSubMenu());
421 }
422
423 return item;
424 }
425
426 wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item)
427 {
428 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") );
429
430 if ( pos == GetMenuItemCount() )
431 {
432 return DoAppend(item);
433 }
434 else
435 {
436 wxCHECK_MSG( pos < GetMenuItemCount(), NULL,
437 wxT("invalid index in wxMenu::Insert") );
438
439 return DoInsert(pos, item);
440 }
441 }
442
443 wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
444 {
445 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") );
446
447 wxMenuItemList::compatibility_iterator node = m_items.Item(pos);
448 wxCHECK_MSG( node, NULL, wxT("invalid index in wxMenu::Insert()") );
449
450 m_items.Insert(node, item);
451 item->SetMenu((wxMenu*)this);
452 if ( item->IsSubMenu() )
453 {
454 AddSubMenu(item->GetSubMenu());
455 }
456
457 return item;
458 }
459
460 wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
461 {
462 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
463
464 return DoRemove(item);
465 }
466
467 wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
468 {
469 wxMenuItemList::compatibility_iterator node = m_items.Find(item);
470
471 // if we get here, the item is valid or one of Remove() functions is broken
472 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
473
474 // we detach the item, but we do delete the list node (i.e. don't call
475 // DetachNode() here!)
476 m_items.Erase(node);
477
478 // item isn't attached to anything any more
479 item->SetMenu((wxMenu *)NULL);
480 wxMenu *submenu = item->GetSubMenu();
481 if ( submenu )
482 {
483 submenu->SetParent((wxMenu *)NULL);
484 if ( submenu->IsAttached() )
485 submenu->Detach();
486 }
487
488 return item;
489 }
490
491 bool wxMenuBase::Delete(wxMenuItem *item)
492 {
493 wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Delete") );
494
495 return DoDelete(item);
496 }
497
498 bool wxMenuBase::DoDelete(wxMenuItem *item)
499 {
500 wxMenuItem *item2 = DoRemove(item);
501 wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
502
503 // don't delete the submenu
504 item2->SetSubMenu((wxMenu *)NULL);
505
506 delete item2;
507
508 return true;
509 }
510
511 bool wxMenuBase::Destroy(wxMenuItem *item)
512 {
513 wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Destroy") );
514
515 return DoDestroy(item);
516 }
517
518 bool wxMenuBase::DoDestroy(wxMenuItem *item)
519 {
520 wxMenuItem *item2 = DoRemove(item);
521 wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
522
523 delete item2;
524
525 return true;
526 }
527
528 // ----------------------------------------------------------------------------
529 // wxMenu searching for items
530 // ----------------------------------------------------------------------------
531
532 // Finds the item id matching the given string, wxNOT_FOUND if not found.
533 int wxMenuBase::FindItem(const wxString& text) const
534 {
535 wxString label = wxMenuItem::GetLabelFromText(text);
536 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
537 node;
538 node = node->GetNext() )
539 {
540 wxMenuItem *item = node->GetData();
541 if ( item->IsSubMenu() )
542 {
543 int rc = item->GetSubMenu()->FindItem(label);
544 if ( rc != wxNOT_FOUND )
545 return rc;
546 }
547
548 // we execute this code for submenus as well to alllow finding them by
549 // name just like the ordinary items
550 if ( !item->IsSeparator() )
551 {
552 if ( item->GetLabel() == label )
553 return item->GetId();
554 }
555 }
556
557 return wxNOT_FOUND;
558 }
559
560 // recursive search for item by id
561 wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
562 {
563 if ( itemMenu )
564 *itemMenu = NULL;
565
566 wxMenuItem *item = NULL;
567 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
568 node && !item;
569 node = node->GetNext() )
570 {
571 item = node->GetData();
572
573 if ( item->GetId() == itemId )
574 {
575 if ( itemMenu )
576 *itemMenu = (wxMenu *)this;
577 }
578 else if ( item->IsSubMenu() )
579 {
580 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
581 }
582 else
583 {
584 // don't exit the loop
585 item = NULL;
586 }
587 }
588
589 return item;
590 }
591
592 // non recursive search
593 wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
594 {
595 wxMenuItem *item = (wxMenuItem *)NULL;
596 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
597
598 size_t pos;
599 for ( pos = 0; node; pos++ )
600 {
601 if ( node->GetData()->GetId() == id )
602 {
603 item = node->GetData();
604
605 break;
606 }
607
608 node = node->GetNext();
609 }
610
611 if ( ppos )
612 {
613 *ppos = item ? pos : (size_t)wxNOT_FOUND;
614 }
615
616 return item;
617 }
618
619 // find by position
620 wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const
621 {
622 wxCHECK_MSG( position < m_items.GetCount(), NULL,
623 _T("wxMenu::FindItemByPosition(): invalid menu index") );
624
625 return m_items.Item( position )->GetData();
626 }
627
628 // ----------------------------------------------------------------------------
629 // wxMenu helpers used by derived classes
630 // ----------------------------------------------------------------------------
631
632 // Update a menu and all submenus recursively. source is the object that has
633 // the update event handlers defined for it. If NULL, the menu or associated
634 // window will be used.
635 void wxMenuBase::UpdateUI(wxEvtHandler* source)
636 {
637 if (GetInvokingWindow())
638 {
639 // Don't update menus if the parent
640 // frame is about to get deleted
641 wxWindow *tlw = wxGetTopLevelParent( GetInvokingWindow() );
642 if (tlw && wxPendingDelete.Member(tlw))
643 return;
644 }
645
646 if ( !source && GetInvokingWindow() )
647 source = GetInvokingWindow()->GetEventHandler();
648 if ( !source )
649 source = GetEventHandler();
650 if ( !source )
651 source = this;
652
653 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
654 while ( node )
655 {
656 wxMenuItem* item = node->GetData();
657 if ( !item->IsSeparator() )
658 {
659 wxWindowID id = item->GetId();
660 wxUpdateUIEvent event(id);
661 event.SetEventObject( source );
662
663 if ( source->ProcessEvent(event) )
664 {
665 // if anything changed, update the changed attribute
666 if (event.GetSetText())
667 SetLabel(id, event.GetText());
668 if (event.GetSetChecked())
669 Check(id, event.GetChecked());
670 if (event.GetSetEnabled())
671 Enable(id, event.GetEnabled());
672 }
673
674 // recurse to the submenus
675 if ( item->GetSubMenu() )
676 item->GetSubMenu()->UpdateUI(source);
677 }
678 //else: item is a separator (which doesn't process update UI events)
679
680 node = node->GetNext();
681 }
682 }
683
684 bool wxMenuBase::SendEvent(int id, int checked)
685 {
686 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
687 event.SetEventObject(this);
688 event.SetInt(checked);
689
690 bool processed = false;
691
692 // Try the menu's event handler
693 // if ( !processed )
694 {
695 wxEvtHandler *handler = GetEventHandler();
696 if ( handler )
697 processed = handler->ProcessEvent(event);
698 }
699
700 // Try the window the menu was popped up from (and up through the
701 // hierarchy)
702 if ( !processed )
703 {
704 const wxMenuBase *menu = this;
705 while ( menu )
706 {
707 wxWindow *win = menu->GetInvokingWindow();
708 if ( win )
709 {
710 processed = win->GetEventHandler()->ProcessEvent(event);
711 break;
712 }
713
714 menu = menu->GetParent();
715 }
716 }
717
718 return processed;
719 }
720
721 // ----------------------------------------------------------------------------
722 // wxMenu attaching/detaching to/from menu bar
723 // ----------------------------------------------------------------------------
724
725 wxMenuBar* wxMenuBase::GetMenuBar() const
726 {
727 if(GetParent())
728 return GetParent()->GetMenuBar();
729 return m_menuBar;
730 }
731
732 void wxMenuBase::Attach(wxMenuBarBase *menubar)
733 {
734 // use Detach() instead!
735 wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") );
736
737 // use IsAttached() to prevent this from happening
738 wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") );
739
740 m_menuBar = (wxMenuBar *)menubar;
741 }
742
743 void wxMenuBase::Detach()
744 {
745 // use IsAttached() to prevent this from happening
746 wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") );
747
748 m_menuBar = NULL;
749 }
750
751 // ----------------------------------------------------------------------------
752 // wxMenu functions forwarded to wxMenuItem
753 // ----------------------------------------------------------------------------
754
755 void wxMenuBase::Enable( int id, bool enable )
756 {
757 wxMenuItem *item = FindItem(id);
758
759 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
760
761 item->Enable(enable);
762 }
763
764 bool wxMenuBase::IsEnabled( int id ) const
765 {
766 wxMenuItem *item = FindItem(id);
767
768 wxCHECK_MSG( item, false, wxT("wxMenu::IsEnabled: no such item") );
769
770 return item->IsEnabled();
771 }
772
773 void wxMenuBase::Check( int id, bool enable )
774 {
775 wxMenuItem *item = FindItem(id);
776
777 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
778
779 item->Check(enable);
780 }
781
782 bool wxMenuBase::IsChecked( int id ) const
783 {
784 wxMenuItem *item = FindItem(id);
785
786 wxCHECK_MSG( item, false, wxT("wxMenu::IsChecked: no such item") );
787
788 return item->IsChecked();
789 }
790
791 void wxMenuBase::SetLabel( int id, const wxString &label )
792 {
793 wxMenuItem *item = FindItem(id);
794
795 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
796
797 item->SetText(label);
798 }
799
800 wxString wxMenuBase::GetLabel( int id ) const
801 {
802 wxMenuItem *item = FindItem(id);
803
804 wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetLabel: no such item") );
805
806 return item->GetText();
807 }
808
809 void wxMenuBase::SetHelpString( int id, const wxString& helpString )
810 {
811 wxMenuItem *item = FindItem(id);
812
813 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
814
815 item->SetHelp( helpString );
816 }
817
818 wxString wxMenuBase::GetHelpString( int id ) const
819 {
820 wxMenuItem *item = FindItem(id);
821
822 wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetHelpString: no such item") );
823
824 return item->GetHelp();
825 }
826
827 // ----------------------------------------------------------------------------
828 // wxMenuBarBase ctor and dtor
829 // ----------------------------------------------------------------------------
830
831 wxMenuBarBase::wxMenuBarBase()
832 {
833 // not attached yet
834 m_menuBarFrame = NULL;
835 }
836
837 wxMenuBarBase::~wxMenuBarBase()
838 {
839 WX_CLEAR_LIST(wxMenuList, m_menus);
840 }
841
842 // ----------------------------------------------------------------------------
843 // wxMenuBar item access: the base class versions manage m_menus list, the
844 // derived class should reflect the changes in the real menubar
845 // ----------------------------------------------------------------------------
846
847 wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
848 {
849 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
850 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
851
852 return node->GetData();
853 }
854
855 bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title))
856 {
857 wxCHECK_MSG( menu, false, wxT("can't append NULL menu") );
858
859 m_menus.Append(menu);
860 menu->Attach(this);
861
862 return true;
863 }
864
865 bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
866 const wxString& title)
867 {
868 if ( pos == m_menus.GetCount() )
869 {
870 return wxMenuBarBase::Append(menu, title);
871 }
872 else // not at the end
873 {
874 wxCHECK_MSG( menu, false, wxT("can't insert NULL menu") );
875
876 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
877 wxCHECK_MSG( node, false, wxT("bad index in wxMenuBar::Insert()") );
878
879 m_menus.Insert(node, menu);
880 menu->Attach(this);
881
882 return true;
883 }
884 }
885
886 wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
887 const wxString& WXUNUSED(title))
888 {
889 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
890
891 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
892 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
893
894 wxMenu *menuOld = node->GetData();
895 node->SetData(menu);
896
897 menu->Attach(this);
898 menuOld->Detach();
899
900 return menuOld;
901 }
902
903 wxMenu *wxMenuBarBase::Remove(size_t pos)
904 {
905 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
906 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
907
908 wxMenu *menu = node->GetData();
909 m_menus.Erase(node);
910 menu->Detach();
911
912 return menu;
913 }
914
915 int wxMenuBarBase::FindMenu(const wxString& title) const
916 {
917 wxString label = wxMenuItem::GetLabelFromText(title);
918
919 size_t count = GetMenuCount();
920 for ( size_t i = 0; i < count; i++ )
921 {
922 wxString title2 = GetLabelTop(i);
923 if ( (title2 == title) ||
924 (wxMenuItem::GetLabelFromText(title2) == label) )
925 {
926 // found
927 return (int)i;
928 }
929 }
930
931 return wxNOT_FOUND;
932
933 }
934
935 // ----------------------------------------------------------------------------
936 // wxMenuBar attaching/detaching to/from the frame
937 // ----------------------------------------------------------------------------
938
939 void wxMenuBarBase::Attach(wxFrame *frame)
940 {
941 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
942
943 m_menuBarFrame = frame;
944 }
945
946 void wxMenuBarBase::Detach()
947 {
948 wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
949
950 m_menuBarFrame = NULL;
951 }
952
953 // ----------------------------------------------------------------------------
954 // wxMenuBar searching for items
955 // ----------------------------------------------------------------------------
956
957 wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const
958 {
959 if ( menu )
960 *menu = NULL;
961
962 wxMenuItem *item = NULL;
963 size_t count = GetMenuCount(), i;
964 wxMenuList::const_iterator it;
965 for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ )
966 {
967 item = (*it)->FindItem(id, menu);
968 }
969
970 return item;
971 }
972
973 int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
974 {
975 wxString label = wxMenuItem::GetLabelFromText(menu);
976
977 int i = 0;
978 wxMenuList::compatibility_iterator node;
979 for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
980 {
981 if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) )
982 return node->GetData()->FindItem(item);
983 }
984
985 return wxNOT_FOUND;
986 }
987
988 // ---------------------------------------------------------------------------
989 // wxMenuBar functions forwarded to wxMenuItem
990 // ---------------------------------------------------------------------------
991
992 void wxMenuBarBase::Enable(int id, bool enable)
993 {
994 wxMenuItem *item = FindItem(id);
995
996 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
997
998 item->Enable(enable);
999 }
1000
1001 void wxMenuBarBase::Check(int id, bool check)
1002 {
1003 wxMenuItem *item = FindItem(id);
1004
1005 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
1006 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
1007
1008 item->Check(check);
1009 }
1010
1011 bool wxMenuBarBase::IsChecked(int id) const
1012 {
1013 wxMenuItem *item = FindItem(id);
1014
1015 wxCHECK_MSG( item, false, wxT("wxMenuBar::IsChecked(): no such item") );
1016
1017 return item->IsChecked();
1018 }
1019
1020 bool wxMenuBarBase::IsEnabled(int id) const
1021 {
1022 wxMenuItem *item = FindItem(id);
1023
1024 wxCHECK_MSG( item, false, wxT("wxMenuBar::IsEnabled(): no such item") );
1025
1026 return item->IsEnabled();
1027 }
1028
1029 void wxMenuBarBase::SetLabel(int id, const wxString& label)
1030 {
1031 wxMenuItem *item = FindItem(id);
1032
1033 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
1034
1035 item->SetText(label);
1036 }
1037
1038 wxString wxMenuBarBase::GetLabel(int id) const
1039 {
1040 wxMenuItem *item = FindItem(id);
1041
1042 wxCHECK_MSG( item, wxEmptyString,
1043 wxT("wxMenuBar::GetLabel(): no such item") );
1044
1045 return item->GetText();
1046 }
1047
1048 void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
1049 {
1050 wxMenuItem *item = FindItem(id);
1051
1052 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
1053
1054 item->SetHelp(helpString);
1055 }
1056
1057 wxString wxMenuBarBase::GetHelpString(int id) const
1058 {
1059 wxMenuItem *item = FindItem(id);
1060
1061 wxCHECK_MSG( item, wxEmptyString,
1062 wxT("wxMenuBar::GetHelpString(): no such item") );
1063
1064 return item->GetHelp();
1065 }
1066
1067 #endif // wxUSE_MENUS