home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / menucmn.cpp < prev    next >
C/C++ Source or Header  |  2002-11-22  |  27KB  |  957 lines

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