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