]> git.saurik.com Git - wxWidgets.git/blame - src/common/menucmn.cpp
set eol-style and keywords properties on new files
[wxWidgets.git] / src / common / menucmn.cpp
CommitLineData
3dfac970 1///////////////////////////////////////////////////////////////////////////////
0ad966ee 2// Name: src/common/menucmn.cpp
3dfac970
VZ
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
3dfac970
VZ
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
1e6feb95
VZ
27#if wxUSE_MENUS
28
3dfac970 29#ifndef WX_PRECOMP
1e6feb95
VZ
30 #include "wx/intl.h"
31 #include "wx/log.h"
3dfac970 32 #include "wx/menu.h"
1aecefa5 33 #include "wx/frame.h"
3dfac970
VZ
34#endif
35
345319d6
VZ
36#include "wx/stockitem.h"
37
3dfac970
VZ
38// ----------------------------------------------------------------------------
39// template lists
40// ----------------------------------------------------------------------------
41
42#include "wx/listimpl.cpp"
717a57c2 43
259c43f6
VZ
44WX_DEFINE_LIST(wxMenuList)
45WX_DEFINE_LIST(wxMenuItemList)
3dfac970
VZ
46
47// ============================================================================
48// implementation
49// ============================================================================
50
28953245
SC
51// ----------------------------------------------------------------------------
52// XTI for wxMenu(Bar)
53// ----------------------------------------------------------------------------
54
55#if wxUSE_EXTENDED_RTTI
56
57WX_DEFINE_LIST( wxMenuInfoList )
58
59wxDEFINE_FLAGS( wxMenuStyle )
60wxBEGIN_FLAGS( wxMenuStyle )
61wxFLAGS_MEMBER(wxMENU_TEAROFF)
62wxEND_FLAGS( wxMenuStyle )
63
64wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu, wxEvtHandler, "wx/menu.h")
65wxCOLLECTION_TYPE_INFO( wxMenuItem *, wxMenuItemList ) ;
66
67template<> void wxCollectionToVariantArray( wxMenuItemList const &theList,
68 wxVariantBaseArray &value)
69{
70 wxListCollectionToVariantArray<wxMenuItemList::compatibility_iterator>( theList, value ) ;
71}
72
73wxBEGIN_PROPERTIES_TABLE(wxMenu)
74wxEVENT_PROPERTY( Select, wxEVT_COMMAND_MENU_SELECTED, wxCommandEvent)
75
76wxPROPERTY( Title, wxString, SetTitle, GetTitle, wxString(), \
77 0 /*flags*/, wxT("Helpstring"), wxT("group") )
78
79wxREADONLY_PROPERTY_FLAGS( MenuStyle, wxMenuStyle, long, GetStyle, \
80 wxEMPTY_PARAMETER_VALUE, 0 /*flags*/, wxT("Helpstring"), \
81 wxT("group")) // style
82
83wxPROPERTY_COLLECTION( MenuItems, wxMenuItemList, wxMenuItem*, Append, \
84 GetMenuItems, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
85wxEND_PROPERTIES_TABLE()
86
87wxEMPTY_HANDLERS_TABLE(wxMenu)
88
89wxDIRECT_CONSTRUCTOR_2( wxMenu, wxString, Title, long, MenuStyle )
90
91wxDEFINE_FLAGS( wxMenuBarStyle )
92
93wxBEGIN_FLAGS( wxMenuBarStyle )
94wxFLAGS_MEMBER(wxMB_DOCKABLE)
95wxEND_FLAGS( wxMenuBarStyle )
96
97// the negative id would lead the window (its superclass !) to
98// vetoe streaming out otherwise
99bool wxMenuBarStreamingCallback( const wxObject *WXUNUSED(object), wxObjectWriter *,
100 wxObjectReaderCallback *, wxVariantBaseArray & )
101{
102 return true;
103}
104
105wxIMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar, wxWindow, "wx/menu.h", \
106 wxMenuBarStreamingCallback)
107
108wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo, wxObject, "wx/menu.h")
109
110wxBEGIN_PROPERTIES_TABLE(wxMenuInfo)
111wxREADONLY_PROPERTY( Menu, wxMenu*, GetMenu, wxEMPTY_PARAMETER_VALUE, \
112 0 /*flags*/, wxT("Helpstring"), wxT("group"))
113
114wxREADONLY_PROPERTY( Title, wxString, GetTitle, wxString(), \
115 0 /*flags*/, wxT("Helpstring"), wxT("group"))
116wxEND_PROPERTIES_TABLE()
117
118wxEMPTY_HANDLERS_TABLE(wxMenuInfo)
119
120wxCONSTRUCTOR_2( wxMenuInfo, wxMenu*, Menu, wxString, Title )
121
122wxCOLLECTION_TYPE_INFO( wxMenuInfo *, wxMenuInfoList ) ;
123
124template<> void wxCollectionToVariantArray( wxMenuInfoList const &theList,
125 wxVariantBaseArray &value)
126{
127 wxListCollectionToVariantArray<wxMenuInfoList::compatibility_iterator>( theList, value ) ;
128}
129
130wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
131wxPROPERTY_COLLECTION( MenuInfos, wxMenuInfoList, wxMenuInfo*, AppendMenuInfo, \
132 GetMenuInfos, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
133wxEND_PROPERTIES_TABLE()
134
135wxEMPTY_HANDLERS_TABLE(wxMenuBar)
136
137wxCONSTRUCTOR_DUMMY( wxMenuBar )
138
139#else
140// IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
141// IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
142// IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo, wxObject)
143#endif
144
145
146// ----------------------------------------------------------------------------
147// XTI for wxMenuItem
148// ----------------------------------------------------------------------------
149
150#if wxUSE_EXTENDED_RTTI
151
152bool wxMenuItemStreamingCallback( const wxObject *object, wxObjectWriter *,
153 wxObjectReaderCallback *, wxVariantBaseArray & )
154{
155 const wxMenuItem * mitem = wx_dynamic_cast(const wxMenuItem*, object);
156 if ( mitem->GetMenu() && !mitem->GetMenu()->GetTitle().empty() )
157 {
158 // we don't stream out the first two items for menus with a title,
159 // they will be reconstructed
160 if ( mitem->GetMenu()->FindItemByPosition(0) == mitem ||
161 mitem->GetMenu()->FindItemByPosition(1) == mitem )
162 return false;
163 }
164 return true;
165}
166
167wxBEGIN_ENUM( wxItemKind )
168wxENUM_MEMBER( wxITEM_SEPARATOR )
169wxENUM_MEMBER( wxITEM_NORMAL )
170wxENUM_MEMBER( wxITEM_CHECK )
171wxENUM_MEMBER( wxITEM_RADIO )
172wxEND_ENUM( wxItemKind )
173
174wxIMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuItem, wxObject, "wx/menuitem.h", \
175 wxMenuItemStreamingCallback)
176
177wxBEGIN_PROPERTIES_TABLE(wxMenuItem)
178wxPROPERTY( Parent, wxMenu*, SetMenu, GetMenu, wxEMPTY_PARAMETER_VALUE, \
179 0 /*flags*/, wxT("Helpstring"), wxT("group") )
180wxPROPERTY( Id, int, SetId, GetId, wxEMPTY_PARAMETER_VALUE, \
181 0 /*flags*/, wxT("Helpstring"), wxT("group") )
182wxPROPERTY( Text, wxString, SetText, GetText, wxString(), \
183 0 /*flags*/, wxT("Helpstring"), wxT("group") )
184wxPROPERTY( Help, wxString, SetHelp, GetHelp, wxString(), \
185 0 /*flags*/, wxT("Helpstring"), wxT("group") )
186wxREADONLY_PROPERTY( Kind, wxItemKind, GetKind, wxEMPTY_PARAMETER_VALUE, \
187 0 /*flags*/, wxT("Helpstring"), wxT("group") )
188wxPROPERTY( SubMenu, wxMenu*, SetSubMenu, GetSubMenu, wxEMPTY_PARAMETER_VALUE, \
189 0 /*flags*/, wxT("Helpstring"), wxT("group") )
190wxPROPERTY( Enabled, bool, Enable, IsEnabled, wxVariantBase((bool)true), \
191 0 /*flags*/, wxT("Helpstring"), wxT("group") )
192wxPROPERTY( Checked, bool, Check, IsChecked, wxVariantBase((bool)false), \
193 0 /*flags*/, wxT("Helpstring"), wxT("group") )
194wxPROPERTY( Checkable, bool, SetCheckable, IsCheckable, wxVariantBase((bool)false), \
195 0 /*flags*/, wxT("Helpstring"), wxT("group") )
196wxEND_PROPERTIES_TABLE()
197
198wxEMPTY_HANDLERS_TABLE(wxMenuItem)
199
200wxDIRECT_CONSTRUCTOR_6( wxMenuItem, wxMenu*, Parent, int, Id, wxString, \
201 Text, wxString, Help, wxItemKind, Kind, wxMenu*, SubMenu )
202#else
203//IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
204#endif
205
3dfac970 206// ----------------------------------------------------------------------------
c36d4774 207// wxMenuItemBase
ee0a94cf
RR
208// ----------------------------------------------------------------------------
209
210wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu,
211 int id,
212 const wxString& text,
213 const wxString& help,
214 wxItemKind kind,
215 wxMenu *subMenu)
ee0a94cf 216{
d93b9874
VZ
217 switch ( id )
218 {
219 case wxID_ANY:
220 m_id = wxWindow::NewControlId();
221 break;
222
223 case wxID_SEPARATOR:
224 m_id = wxID_SEPARATOR;
a1040229
VZ
225
226 // there is a lot of existing code just doing Append(wxID_SEPARATOR)
227 // and it makes sense to omit the following optional parameters,
228 // including the kind one which doesn't default to wxITEM_SEPARATOR,
229 // of course, so override it here
230 kind = wxITEM_SEPARATOR;
d93b9874
VZ
231 break;
232
0c51948f
VS
233 case wxID_NONE:
234 // (popup) menu titles in wxMSW use this ID to indicate that
235 // it's not a real menu item, so we don't want the check below to
236 // apply to it
237 m_id = id;
238 break;
239
d93b9874
VZ
240 default:
241 // ids are limited to 16 bits under MSW so portable code shouldn't
242 // use ids outside of this range (negative ids generated by wx are
243 // fine though)
244 wxASSERT_MSG( (id >= 0 && id < SHRT_MAX) ||
245 (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST),
246 wxS("invalid id value") );
247 m_id = id;
248 }
249
9cd28f48
VZ
250 // notice that parentMenu can be NULL: the item can be attached to the menu
251 // later with SetMenu()
ee0a94cf
RR
252
253 m_parentMenu = parentMenu;
254 m_subMenu = subMenu;
255 m_isEnabled = true;
256 m_isChecked = false;
ee0a94cf 257 m_kind = kind;
345319d6 258
52af3158 259 SetItemLabel(text);
345319d6 260 SetHelp(help);
ee0a94cf
RR
261}
262
263wxMenuItemBase::~wxMenuItemBase()
264{
265 delete m_subMenu;
266}
267
268#if wxUSE_ACCEL
269
1e6feb95
VZ
270wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
271{
65776a15 272 return wxAcceleratorEntry::Create(GetItemLabel());
1e6feb95
VZ
273}
274
717a57c2
VZ
275void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
276{
277 wxString text = m_text.BeforeFirst(wxT('\t'));
278 if ( accel )
279 {
280 text += wxT('\t');
ee0a94cf 281 text += accel->ToString();
717a57c2
VZ
282 }
283
52af3158 284 SetItemLabel(text);
717a57c2
VZ
285}
286
287#endif // wxUSE_ACCEL
288
52af3158 289void wxMenuItemBase::SetItemLabel(const wxString& str)
345319d6
VZ
290{
291 m_text = str;
292
293 if ( m_text.empty() && !IsSeparator() )
294 {
295 wxASSERT_MSG( wxIsStockID(GetId()),
296 wxT("A non-stock menu item with an empty label?") );
297 m_text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR |
298 wxSTOCK_WITH_MNEMONIC);
299 }
300}
301
302void wxMenuItemBase::SetHelp(const wxString& str)
303{
304 m_help = str;
305
306 if ( m_help.empty() && !IsSeparator() && wxIsStockID(GetId()) )
307 {
308 // get a stock help string
309 m_help = wxGetStockHelpString(GetId());
310 }
311}
312
cabb286d
PC
313#ifndef __WXPM__
314wxString wxMenuItemBase::GetLabelText(const wxString& text)
315{
316 return wxStripMenuCodes(text);
317}
318#endif
319
52af3158
JS
320#if WXWIN_COMPATIBILITY_2_8
321wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
322{
323 return GetLabelText(text);
324}
325#endif
326
6d971354
RR
327bool wxMenuBase::ms_locked = true;
328
717a57c2
VZ
329// ----------------------------------------------------------------------------
330// wxMenu ctor and dtor
331// ----------------------------------------------------------------------------
332
333void wxMenuBase::Init(long style)
334{
d3b9f782
VZ
335 m_menuBar = NULL;
336 m_menuParent = NULL;
717a57c2 337
d3b9f782 338 m_invokingWindow = NULL;
717a57c2 339 m_style = style;
d3b9f782 340 m_clientData = NULL;
717a57c2
VZ
341 m_eventHandler = this;
342}
343
344wxMenuBase::~wxMenuBase()
345{
222ed1d6 346 WX_CLEAR_LIST(wxMenuItemList, m_items);
717a57c2
VZ
347}
348
349// ----------------------------------------------------------------------------
350// wxMenu item adding/removing
351// ----------------------------------------------------------------------------
352
1e6feb95
VZ
353void wxMenuBase::AddSubMenu(wxMenu *submenu)
354{
9a83f860 355 wxCHECK_RET( submenu, wxT("can't add a NULL submenu") );
1e6feb95 356
1e6feb95
VZ
357 submenu->SetParent((wxMenu *)this);
358}
359
9add9367 360wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item)
717a57c2 361{
9add9367 362 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") );
717a57c2
VZ
363
364 m_items.Append(item);
1e93ca17 365 item->SetMenu((wxMenu*)this);
1e6feb95
VZ
366 if ( item->IsSubMenu() )
367 {
368 AddSubMenu(item->GetSubMenu());
369 }
717a57c2 370
9add9367 371 return item;
717a57c2
VZ
372}
373
9add9367 374wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item)
717a57c2 375{
9add9367 376 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") );
717a57c2 377
32db328c
VZ
378 if ( pos == GetMenuItemCount() )
379 {
380 return DoAppend(item);
381 }
382 else
383 {
4e32eea1 384 wxCHECK_MSG( pos < GetMenuItemCount(), NULL,
32db328c
VZ
385 wxT("invalid index in wxMenu::Insert") );
386
387 return DoInsert(pos, item);
388 }
717a57c2
VZ
389}
390
9add9367 391wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
717a57c2 392{
9add9367 393 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") );
717a57c2 394
222ed1d6 395 wxMenuItemList::compatibility_iterator node = m_items.Item(pos);
4e32eea1 396 wxCHECK_MSG( node, NULL, wxT("invalid index in wxMenu::Insert()") );
717a57c2
VZ
397
398 m_items.Insert(node, item);
1e93ca17 399 item->SetMenu((wxMenu*)this);
1e6feb95
VZ
400 if ( item->IsSubMenu() )
401 {
402 AddSubMenu(item->GetSubMenu());
403 }
717a57c2 404
9add9367 405 return item;
717a57c2
VZ
406}
407
408wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
409{
410 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
411
412 return DoRemove(item);
413}
414
415wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
416{
222ed1d6 417 wxMenuItemList::compatibility_iterator node = m_items.Find(item);
717a57c2
VZ
418
419 // if we get here, the item is valid or one of Remove() functions is broken
420 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
421
422 // we detach the item, but we do delete the list node (i.e. don't call
423 // DetachNode() here!)
222ed1d6 424 m_items.Erase(node);
717a57c2
VZ
425
426 // item isn't attached to anything any more
d3b9f782 427 item->SetMenu(NULL);
717a57c2
VZ
428 wxMenu *submenu = item->GetSubMenu();
429 if ( submenu )
430 {
d3b9f782 431 submenu->SetParent(NULL);
082006f3
VZ
432 if ( submenu->IsAttached() )
433 submenu->Detach();
717a57c2
VZ
434 }
435
436 return item;
437}
438
439bool wxMenuBase::Delete(wxMenuItem *item)
440{
4e32eea1 441 wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Delete") );
717a57c2
VZ
442
443 return DoDelete(item);
444}
445
446bool wxMenuBase::DoDelete(wxMenuItem *item)
447{
448 wxMenuItem *item2 = DoRemove(item);
4e32eea1 449 wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
717a57c2
VZ
450
451 // don't delete the submenu
d3b9f782 452 item2->SetSubMenu(NULL);
717a57c2
VZ
453
454 delete item2;
455
4e32eea1 456 return true;
717a57c2
VZ
457}
458
459bool wxMenuBase::Destroy(wxMenuItem *item)
460{
4e32eea1 461 wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Destroy") );
717a57c2
VZ
462
463 return DoDestroy(item);
464}
465
466bool wxMenuBase::DoDestroy(wxMenuItem *item)
467{
468 wxMenuItem *item2 = DoRemove(item);
4e32eea1 469 wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
717a57c2
VZ
470
471 delete item2;
472
4e32eea1 473 return true;
717a57c2
VZ
474}
475
476// ----------------------------------------------------------------------------
477// wxMenu searching for items
478// ----------------------------------------------------------------------------
479
4e32eea1 480// Finds the item id matching the given string, wxNOT_FOUND if not found.
717a57c2
VZ
481int wxMenuBase::FindItem(const wxString& text) const
482{
52af3158 483 wxString label = wxMenuItem::GetLabelText(text);
222ed1d6 484 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
717a57c2
VZ
485 node;
486 node = node->GetNext() )
487 {
488 wxMenuItem *item = node->GetData();
489 if ( item->IsSubMenu() )
490 {
491 int rc = item->GetSubMenu()->FindItem(label);
492 if ( rc != wxNOT_FOUND )
493 return rc;
494 }
adb21613
VZ
495
496 // we execute this code for submenus as well to alllow finding them by
497 // name just like the ordinary items
498 if ( !item->IsSeparator() )
717a57c2 499 {
68bc148c 500 if ( item->GetItemLabelText() == label )
717a57c2
VZ
501 return item->GetId();
502 }
503 }
504
505 return wxNOT_FOUND;
506}
507
508// recursive search for item by id
509wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
510{
511 if ( itemMenu )
512 *itemMenu = NULL;
513
514 wxMenuItem *item = NULL;
222ed1d6 515 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
717a57c2
VZ
516 node && !item;
517 node = node->GetNext() )
518 {
519 item = node->GetData();
520
521 if ( item->GetId() == itemId )
522 {
523 if ( itemMenu )
524 *itemMenu = (wxMenu *)this;
525 }
526 else if ( item->IsSubMenu() )
527 {
528 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
529 }
530 else
531 {
532 // don't exit the loop
533 item = NULL;
534 }
535 }
536
537 return item;
538}
539
540// non recursive search
541wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
542{
d3b9f782 543 wxMenuItem *item = NULL;
222ed1d6 544 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
717a57c2
VZ
545
546 size_t pos;
547 for ( pos = 0; node; pos++ )
548 {
1dddf838
VZ
549 if ( node->GetData()->GetId() == id )
550 {
551 item = node->GetData();
552
717a57c2 553 break;
1dddf838 554 }
717a57c2
VZ
555
556 node = node->GetNext();
557 }
558
559 if ( ppos )
560 {
1987af7e 561 *ppos = item ? pos : (size_t)wxNOT_FOUND;
717a57c2
VZ
562 }
563
564 return item;
565}
566
01ebf752
JS
567// find by position
568wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const
569{
20aed026 570 wxCHECK_MSG( position < m_items.GetCount(), NULL,
9a83f860 571 wxT("wxMenu::FindItemByPosition(): invalid menu index") );
20aed026
VZ
572
573 return m_items.Item( position )->GetData();
01ebf752
JS
574}
575
717a57c2 576// ----------------------------------------------------------------------------
1e6feb95 577// wxMenu helpers used by derived classes
717a57c2
VZ
578// ----------------------------------------------------------------------------
579
580// Update a menu and all submenus recursively. source is the object that has
581// the update event handlers defined for it. If NULL, the menu or associated
582// window will be used.
583void wxMenuBase::UpdateUI(wxEvtHandler* source)
584{
5ce61d9f
RR
585 if (GetInvokingWindow())
586 {
587 // Don't update menus if the parent
588 // frame is about to get deleted
589 wxWindow *tlw = wxGetTopLevelParent( GetInvokingWindow() );
590 if (tlw && wxPendingDelete.Member(tlw))
591 return;
592 }
593
717a57c2
VZ
594 if ( !source && GetInvokingWindow() )
595 source = GetInvokingWindow()->GetEventHandler();
596 if ( !source )
597 source = GetEventHandler();
598 if ( !source )
599 source = this;
600
222ed1d6 601 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
717a57c2
VZ
602 while ( node )
603 {
604 wxMenuItem* item = node->GetData();
605 if ( !item->IsSeparator() )
606 {
607 wxWindowID id = item->GetId();
608 wxUpdateUIEvent event(id);
609 event.SetEventObject( source );
610
611 if ( source->ProcessEvent(event) )
612 {
18afa2ac 613 // if anything changed, update the changed attribute
717a57c2
VZ
614 if (event.GetSetText())
615 SetLabel(id, event.GetText());
616 if (event.GetSetChecked())
617 Check(id, event.GetChecked());
618 if (event.GetSetEnabled())
619 Enable(id, event.GetEnabled());
620 }
621
622 // recurse to the submenus
623 if ( item->GetSubMenu() )
624 item->GetSubMenu()->UpdateUI(source);
625 }
18afa2ac 626 //else: item is a separator (which doesn't process update UI events)
717a57c2
VZ
627
628 node = node->GetNext();
629 }
630}
631
1e6feb95
VZ
632bool wxMenuBase::SendEvent(int id, int checked)
633{
634 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
635 event.SetEventObject(this);
636 event.SetInt(checked);
637
4e32eea1 638 bool processed = false;
1e6feb95 639
7739f9c9
VZ
640 // Try the menu's event handler first
641 wxEvtHandler *handler = GetEventHandler();
642 if ( handler )
643 processed = handler->SafelyProcessEvent(event);
1e6feb95 644
7739f9c9 645 // Try the window the menu was popped up from or its menu bar belongs to
1e6feb95
VZ
646 if ( !processed )
647 {
7739f9c9
VZ
648 wxWindow * const win = GetWindow();
649 if ( win )
650 processed = win->HandleWindowEvent(event);
1e6feb95
VZ
651 }
652
653 return processed;
654}
655
656// ----------------------------------------------------------------------------
657// wxMenu attaching/detaching to/from menu bar
658// ----------------------------------------------------------------------------
659
dbdf9a17
DE
660wxMenuBar* wxMenuBase::GetMenuBar() const
661{
662 if(GetParent())
663 return GetParent()->GetMenuBar();
664 return m_menuBar;
665}
666
1e6feb95
VZ
667void wxMenuBase::Attach(wxMenuBarBase *menubar)
668{
669 // use Detach() instead!
9a83f860 670 wxASSERT_MSG( menubar, wxT("menu can't be attached to NULL menubar") );
1e6feb95
VZ
671
672 // use IsAttached() to prevent this from happening
9a83f860 673 wxASSERT_MSG( !m_menuBar, wxT("attaching menu twice?") );
1e6feb95
VZ
674
675 m_menuBar = (wxMenuBar *)menubar;
676}
677
678void wxMenuBase::Detach()
679{
680 // use IsAttached() to prevent this from happening
9a83f860 681 wxASSERT_MSG( m_menuBar, wxT("detaching unattached menu?") );
1e6feb95
VZ
682
683 m_menuBar = NULL;
684}
685
e3f5caa2
VZ
686// ----------------------------------------------------------------------------
687// wxMenu invoking window handling
688// ----------------------------------------------------------------------------
689
690void wxMenuBase::SetInvokingWindow(wxWindow *win)
691{
692 wxASSERT_MSG( !GetParent(),
693 "should only be called for top level popup menus" );
694 wxASSERT_MSG( !IsAttached(),
695 "menus attached to menu bar can't have invoking window" );
696
697 m_invokingWindow = win;
698}
699
394cfde3 700wxWindow *wxMenuBase::GetWindow() const
e3f5caa2 701{
394cfde3
VZ
702 // only the top level menus have non-NULL invoking window or a pointer to
703 // the menu bar so recurse upwards until we find it
e3f5caa2
VZ
704 const wxMenuBase *menu = this;
705 while ( menu->GetParent() )
706 {
707 menu = menu->GetParent();
708 }
709
394cfde3
VZ
710 return menu->GetMenuBar() ? menu->GetMenuBar()->GetFrame()
711 : menu->GetInvokingWindow();
7118e711
VZ
712}
713
717a57c2
VZ
714// ----------------------------------------------------------------------------
715// wxMenu functions forwarded to wxMenuItem
716// ----------------------------------------------------------------------------
717
718void wxMenuBase::Enable( int id, bool enable )
719{
720 wxMenuItem *item = FindItem(id);
721
722 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
723
724 item->Enable(enable);
725}
726
727bool wxMenuBase::IsEnabled( int id ) const
728{
729 wxMenuItem *item = FindItem(id);
730
4e32eea1 731 wxCHECK_MSG( item, false, wxT("wxMenu::IsEnabled: no such item") );
717a57c2
VZ
732
733 return item->IsEnabled();
734}
735
736void wxMenuBase::Check( int id, bool enable )
737{
738 wxMenuItem *item = FindItem(id);
739
740 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
741
742 item->Check(enable);
743}
744
745bool wxMenuBase::IsChecked( int id ) const
746{
747 wxMenuItem *item = FindItem(id);
748
4e32eea1 749 wxCHECK_MSG( item, false, wxT("wxMenu::IsChecked: no such item") );
717a57c2
VZ
750
751 return item->IsChecked();
752}
753
754void wxMenuBase::SetLabel( int id, const wxString &label )
755{
756 wxMenuItem *item = FindItem(id);
757
758 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
759
52af3158 760 item->SetItemLabel(label);
717a57c2
VZ
761}
762
763wxString wxMenuBase::GetLabel( int id ) const
764{
765 wxMenuItem *item = FindItem(id);
766
525d8583 767 wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetLabel: no such item") );
717a57c2 768
52af3158 769 return item->GetItemLabel();
717a57c2
VZ
770}
771
772void wxMenuBase::SetHelpString( int id, const wxString& helpString )
773{
774 wxMenuItem *item = FindItem(id);
775
776 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
777
778 item->SetHelp( helpString );
779}
780
781wxString wxMenuBase::GetHelpString( int id ) const
782{
783 wxMenuItem *item = FindItem(id);
784
525d8583 785 wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetHelpString: no such item") );
717a57c2
VZ
786
787 return item->GetHelp();
788}
789
790// ----------------------------------------------------------------------------
791// wxMenuBarBase ctor and dtor
3dfac970
VZ
792// ----------------------------------------------------------------------------
793
794wxMenuBarBase::wxMenuBarBase()
795{
1e6feb95
VZ
796 // not attached yet
797 m_menuBarFrame = NULL;
3dfac970
VZ
798}
799
800wxMenuBarBase::~wxMenuBarBase()
801{
222ed1d6 802 WX_CLEAR_LIST(wxMenuList, m_menus);
3dfac970
VZ
803}
804
805// ----------------------------------------------------------------------------
806// wxMenuBar item access: the base class versions manage m_menus list, the
807// derived class should reflect the changes in the real menubar
808// ----------------------------------------------------------------------------
809
810wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
811{
222ed1d6 812 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
3dfac970
VZ
813 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
814
815 return node->GetData();
816}
817
b871bb95 818bool wxMenuBarBase::Append(wxMenu *menu, const wxString& title)
3dfac970 819{
4e32eea1 820 wxCHECK_MSG( menu, false, wxT("can't append NULL menu") );
b871bb95 821 wxCHECK_MSG( !title.empty(), false, wxT("can't append menu with empty title") );
3dfac970
VZ
822
823 m_menus.Append(menu);
1e6feb95 824 menu->Attach(this);
3dfac970 825
4e32eea1 826 return true;
3dfac970
VZ
827}
828
829bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
32db328c 830 const wxString& title)
3dfac970 831{
32db328c
VZ
832 if ( pos == m_menus.GetCount() )
833 {
186baeb2 834 return wxMenuBarBase::Append(menu, title);
32db328c 835 }
1e6feb95 836 else // not at the end
32db328c 837 {
4e32eea1 838 wxCHECK_MSG( menu, false, wxT("can't insert NULL menu") );
3dfac970 839
222ed1d6 840 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
4e32eea1 841 wxCHECK_MSG( node, false, wxT("bad index in wxMenuBar::Insert()") );
3dfac970 842
32db328c 843 m_menus.Insert(node, menu);
1e6feb95 844 menu->Attach(this);
3dfac970 845
4e32eea1 846 return true;
32db328c 847 }
3dfac970
VZ
848}
849
850wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
851 const wxString& WXUNUSED(title))
852{
853 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
854
222ed1d6 855 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
3dfac970
VZ
856 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
857
858 wxMenu *menuOld = node->GetData();
859 node->SetData(menu);
860
1e6feb95
VZ
861 menu->Attach(this);
862 menuOld->Detach();
863
3dfac970
VZ
864 return menuOld;
865}
866
867wxMenu *wxMenuBarBase::Remove(size_t pos)
868{
222ed1d6 869 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
3dfac970
VZ
870 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
871
3dfac970 872 wxMenu *menu = node->GetData();
222ed1d6 873 m_menus.Erase(node);
1e6feb95 874 menu->Detach();
3dfac970 875
3dfac970
VZ
876 return menu;
877}
878
270e8b6a 879int wxMenuBarBase::FindMenu(const wxString& title) const
52130557 880{
52af3158 881 wxString label = wxMenuItem::GetLabelText(title);
52130557
VZ
882
883 size_t count = GetMenuCount();
884 for ( size_t i = 0; i < count; i++ )
885 {
52af3158 886 wxString title2 = GetMenuLabel(i);
52130557 887 if ( (title2 == title) ||
52af3158 888 (wxMenuItem::GetLabelText(title2) == label) )
52130557
VZ
889 {
890 // found
2b5f62a0 891 return (int)i;
52130557
VZ
892 }
893 }
894
895 return wxNOT_FOUND;
896
897}
898
1e6feb95
VZ
899// ----------------------------------------------------------------------------
900// wxMenuBar attaching/detaching to/from the frame
901// ----------------------------------------------------------------------------
902
903void wxMenuBarBase::Attach(wxFrame *frame)
904{
905 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
906
907 m_menuBarFrame = frame;
908}
909
910void wxMenuBarBase::Detach()
911{
912 wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
913
914 m_menuBarFrame = NULL;
915}
916
917// ----------------------------------------------------------------------------
918// wxMenuBar searching for items
919// ----------------------------------------------------------------------------
920
921wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const
922{
923 if ( menu )
924 *menu = NULL;
925
926 wxMenuItem *item = NULL;
222ed1d6
MB
927 size_t count = GetMenuCount(), i;
928 wxMenuList::const_iterator it;
929 for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ )
1e6feb95 930 {
222ed1d6 931 item = (*it)->FindItem(id, menu);
1e6feb95
VZ
932 }
933
934 return item;
935}
936
937int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
938{
52af3158 939 wxString label = wxMenuItem::GetLabelText(menu);
1e6feb95
VZ
940
941 int i = 0;
222ed1d6 942 wxMenuList::compatibility_iterator node;
1e6feb95
VZ
943 for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
944 {
52af3158 945 if ( label == wxMenuItem::GetLabelText(GetMenuLabel(i)) )
1e6feb95
VZ
946 return node->GetData()->FindItem(item);
947 }
948
949 return wxNOT_FOUND;
950}
951
3dfac970
VZ
952// ---------------------------------------------------------------------------
953// wxMenuBar functions forwarded to wxMenuItem
954// ---------------------------------------------------------------------------
955
956void wxMenuBarBase::Enable(int id, bool enable)
957{
958 wxMenuItem *item = FindItem(id);
959
960 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
961
962 item->Enable(enable);
963}
964
965void wxMenuBarBase::Check(int id, bool check)
966{
967 wxMenuItem *item = FindItem(id);
968
969 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
970 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
971
972 item->Check(check);
973}
974
975bool wxMenuBarBase::IsChecked(int id) const
976{
977 wxMenuItem *item = FindItem(id);
978
4e32eea1 979 wxCHECK_MSG( item, false, wxT("wxMenuBar::IsChecked(): no such item") );
3dfac970
VZ
980
981 return item->IsChecked();
982}
983
984bool wxMenuBarBase::IsEnabled(int id) const
985{
986 wxMenuItem *item = FindItem(id);
987
4e32eea1 988 wxCHECK_MSG( item, false, wxT("wxMenuBar::IsEnabled(): no such item") );
3dfac970
VZ
989
990 return item->IsEnabled();
991}
992
993void wxMenuBarBase::SetLabel(int id, const wxString& label)
994{
995 wxMenuItem *item = FindItem(id);
996
997 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
998
52af3158 999 item->SetItemLabel(label);
3dfac970
VZ
1000}
1001
1002wxString wxMenuBarBase::GetLabel(int id) const
1003{
1004 wxMenuItem *item = FindItem(id);
1005
1006 wxCHECK_MSG( item, wxEmptyString,
1007 wxT("wxMenuBar::GetLabel(): no such item") );
1008
52af3158 1009 return item->GetItemLabel();
3dfac970
VZ
1010}
1011
1012void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
1013{
1014 wxMenuItem *item = FindItem(id);
1015
1016 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
1017
1018 item->SetHelp(helpString);
1019}
1020
1021wxString wxMenuBarBase::GetHelpString(int id) const
1022{
1023 wxMenuItem *item = FindItem(id);
1024
1025 wxCHECK_MSG( item, wxEmptyString,
1026 wxT("wxMenuBar::GetHelpString(): no such item") );
1027
1028 return item->GetHelp();
1029}
1030
9cd28f48 1031void wxMenuBarBase::UpdateMenus()
4d538595
DS
1032{
1033 wxEvtHandler* source;
1034 wxMenu* menu;
1035 int nCount = GetMenuCount();
1036 for (int n = 0; n < nCount; n++)
1037 {
1038 menu = GetMenu( n );
1039 if (menu != NULL)
1040 {
1041 source = menu->GetEventHandler();
1042 if (source != NULL)
1043 menu->UpdateUI( source );
1044 }
1045 }
1046}
1047
68bc148c
JS
1048#if WXWIN_COMPATIBILITY_2_8
1049// get or change the label of the menu at given position
1050void wxMenuBarBase::SetLabelTop(size_t pos, const wxString& label)
1051{
1052 SetMenuLabel(pos, label);
1053}
1054
1055wxString wxMenuBarBase::GetLabelTop(size_t pos) const
1056{
c4e43bea 1057 return GetMenuLabelText(pos);
68bc148c
JS
1058}
1059#endif
1060
1e6feb95 1061#endif // wxUSE_MENUS