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