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