From 345319d60c69cac3f5e9e74ee570d20370fc532f Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Tue, 5 Sep 2006 21:00:55 +0000
Subject: [PATCH] fixes to menu stock items support (patch 1547639)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41021 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/menuitem.tex   | 35 +++++++++++++++++++++++++++-----
 docs/latex/wx/stockitems.tex | 12 ++++++++---
 include/wx/menuitem.h        |  4 ++--
 include/wx/stockitem.h       | 12 +++++++++++
 src/common/menucmn.cpp       | 39 ++++++++++++++++++++++++++++++++----
 src/common/stockitem.cpp     | 36 +++++++++++++++++++++++++++++++++
 src/gtk1/menu.cpp            |  5 +++--
 src/msw/menuitem.cpp         | 25 +++++++++--------------
 src/os2/menuitem.cpp         | 17 ++++++++--------
 src/univ/menu.cpp            | 12 +++--------
 10 files changed, 147 insertions(+), 50 deletions(-)

diff --git a/docs/latex/wx/menuitem.tex b/docs/latex/wx/menuitem.tex
index c80fea13a9..d5cc838779 100644
--- a/docs/latex/wx/menuitem.tex
+++ b/docs/latex/wx/menuitem.tex
@@ -42,11 +42,36 @@ only implemented for Windows and GTK+.
 
 Constructs a wxMenuItem object.
 
-The preferred way to create standard menu items is to use default value of
-\arg{text}. If no text is supplied and \arg{id} is one of standard IDs from
-\helpref{this list}{stockitems}, a standard label and a standard accelerator
-will be used. In addition to that, the button will be decorated with stock
-icons under GTK+ 2.
+Menu items can be standard, or ``stock menu items'', or custom. For the
+standard menu items (such as commands to open a file, exit the program and so
+on, see \helpref{stock items}{stockitems} for the full list) it is enough to
+specify just the stock ID and leave \arg{text} and \arg{helpString} empty. In
+fact, leaving at least \arg{text} empty for the stock menu items is strongly
+recommended as they will have appearance and keyboard interface (including
+standard accelerators) familiar to the user.
+
+For the custom (non-stock) menu items, \arg{text} must be specified and while 
+\arg{helpString} may be left empty, it's recommended to pass the item
+description (which is automatically shown by the library in the status bar when
+the menu item is selected) in this parameter.
+
+Finally note that you can e.g. use a stock menu label without using its stock
+help string:
+
+\begin{verbatim}
+// use all stock properties:
+helpMenu->Append(wxID_ABOUT);
+
+// use the stock label and the stock accelerator but not the stock help string:
+helpMenu->Append(wxID_ABOUT, wxEmptyString, wxT("My custom help string"));
+
+// use all stock properties except for the bitmap:
+wxMenuItem *mymenu = new wxMenuItem(helpMenu, wxID_ABOUT);
+mymenu->SetBitmap(wxArtProvider::GetBitmap(wxART_WARNING));
+helpMenu->Append(mymenu);
+\end{verbatim}
+
+that is, stock properties are set independently one from the other.
 
 \wxheading{Parameters}
 
diff --git a/docs/latex/wx/stockitems.tex b/docs/latex/wx/stockitems.tex
index 9c335b8099..6257e7df34 100644
--- a/docs/latex/wx/stockitems.tex
+++ b/docs/latex/wx/stockitems.tex
@@ -1,9 +1,11 @@
 \section{Stock items}\label{stockitems}
 
-Window IDs for which stock buttons are created
-(see \helpref{wxButton constructor}{wxbuttonctor}):
+Window IDs for which stock buttons and menu items are created
+(see \helpref{wxButton constructor}{wxbuttonctor} and 
+\helpref{wxMenuItem constructor}{wxmenuitemctor}):
 
 \begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf Stock ID}}{{\bf Stock label}}
 \twocolitem{wxID\_ABOUT}{"\&About"}
 \twocolitem{wxID\_ADD}{"Add"}
 \twocolitem{wxID\_APPLY}{"\&Apply"}
@@ -58,4 +60,8 @@ Window IDs for which stock buttons are created
 \twocolitem{wxID\_ZOOM\_FIT}{"Zoom to \&Fit"}
 \twocolitem{wxID\_ZOOM\_IN}{"Zoom \&In"}
 \twocolitem{wxID\_ZOOM\_OUT}{"Zoom \&Out"}
-\end{twocollist}\itemsep=0pt
+\end{twocollist}
+
+
+Note that some of the IDs listed above have also a stock accelerator
+and an help string associated.
diff --git a/include/wx/menuitem.h b/include/wx/menuitem.h
index fa7b1e4f17..2a619da623 100644
--- a/include/wx/menuitem.h
+++ b/include/wx/menuitem.h
@@ -64,7 +64,7 @@ public:
     //     any), i.e. it may contain '&' or '_' or "\t..." and thus is
     //     different from the item's label which only contains the text shown
     //     in the menu
-    virtual void SetText(const wxString& str) { m_text = str; }
+    virtual void SetText(const wxString& str);
     wxString GetLabel() const { return GetLabelFromText(m_text); }
     const wxString& GetText() const { return m_text; }
 
@@ -92,7 +92,7 @@ public:
     void Toggle() { Check(!m_isChecked); }
 
     // help string (displayed in the status bar by default)
-    void SetHelp(const wxString& str) { m_help = str; }
+    void SetHelp(const wxString& str);
     const wxString& GetHelp() const { return m_help; }
 
 #if wxUSE_ACCEL
diff --git a/include/wx/stockitem.h b/include/wx/stockitem.h
index 65e01d9f72..126489afa4 100644
--- a/include/wx/stockitem.h
+++ b/include/wx/stockitem.h
@@ -51,6 +51,18 @@ WXDLLEXPORT wxString wxGetStockLabel(wxWindowID id,
 
 #endif
 
+// wxStockHelpStringClient conceptually works like wxArtClient: it gives a hint to
+// wxGetStockHelpString() about the context where the help string is to be used
+enum wxStockHelpStringClient
+{
+    wxSTOCK_MENU        // help string to use for menu items
+};
+
+// Returns an help string for the given stock UI element and for the given "context".
+WXDLLEXPORT wxString wxGetStockHelpString(wxWindowID id,
+                                          wxStockHelpStringClient client = wxSTOCK_MENU);
+
+
 #ifdef __WXGTK20__
 
 #include <gdk/gdktypes.h>
diff --git a/src/common/menucmn.cpp b/src/common/menucmn.cpp
index 896c9e1e03..a5843bc275 100644
--- a/src/common/menucmn.cpp
+++ b/src/common/menucmn.cpp
@@ -34,6 +34,8 @@
     #include "wx/menu.h"
 #endif
 
+#include "wx/stockitem.h"
+
 // ----------------------------------------------------------------------------
 // template lists
 // ----------------------------------------------------------------------------
@@ -174,13 +176,17 @@ static int
 bool
 wxAcceleratorEntry::ParseAccel(const wxString& text, int *flagsOut, int *keyOut)
 {
-    // the parser won't like leading/trailing spaces
-    wxString label = text.Strip(wxString::both);
+    // the parser won't like trailing spaces
+    wxString label = text;
+    label.Trim(true);  // the initial \t must be preserved so don't strip leading whitespaces
 
     // check for accelerators: they are given after '\t'
     int posTab = label.Find(wxT('\t'));
     if ( posTab == wxNOT_FOUND )
+    {
+        wxLogDebug(wxT("Invalid menu label: no accelerators"));
         return false;
+    }
 
     // parse the accelerator string
     int accelFlags = wxACCEL_NORMAL;
@@ -360,8 +366,6 @@ wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu,
                                const wxString& help,
                                wxItemKind kind,
                                wxMenu *subMenu)
-              : m_text(text),
-                m_help(help)
 {
     wxASSERT_MSG( parentMenu != NULL, wxT("menuitem should have a menu") );
 
@@ -375,6 +379,9 @@ wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu,
         m_id = wxNewId();
     if (m_id == wxID_SEPARATOR)
         m_kind = wxITEM_SEPARATOR;
+
+    SetText(text);
+    SetHelp(help);
 }
 
 wxMenuItemBase::~wxMenuItemBase()
@@ -403,6 +410,30 @@ void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
 
 #endif // wxUSE_ACCEL
 
+void wxMenuItemBase::SetText(const wxString& str)
+{
+    m_text = str;
+
+    if ( m_text.empty() && !IsSeparator() )
+    {
+        wxASSERT_MSG( wxIsStockID(GetId()),
+                      wxT("A non-stock menu item with an empty label?") );
+        m_text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR |
+                                          wxSTOCK_WITH_MNEMONIC);
+    }
+}
+
+void wxMenuItemBase::SetHelp(const wxString& str)
+{
+    m_help = str;
+
+    if ( m_help.empty() && !IsSeparator() && wxIsStockID(GetId()) )
+    {
+        // get a stock help string
+        m_help = wxGetStockHelpString(GetId());
+    }
+}
+
 bool wxMenuBase::ms_locked = true;
 
 // ----------------------------------------------------------------------------
diff --git a/src/common/stockitem.cpp b/src/common/stockitem.cpp
index bda58fced8..6bf9ac60e3 100644
--- a/src/common/stockitem.cpp
+++ b/src/common/stockitem.cpp
@@ -190,6 +190,42 @@ wxString wxGetStockLabel(wxWindowID id, long flags)
     return stockLabel;
 }
 
+wxString wxGetStockHelpString(wxWindowID id, wxStockHelpStringClient client)
+{
+    wxString stockHelp;
+
+    #define STOCKITEM(stockid, ctx, helpstr)             \
+        case stockid:                                    \
+            if (client==ctx) stockHelp = helpstr;        \
+            break;
+
+    switch (id)
+    {
+        // NB: these help string should be not too specific as they could be used
+        //     in completely different programs!
+        STOCKITEM(wxID_ABOUT,    wxSTOCK_MENU, _("Show about dialog"))
+        STOCKITEM(wxID_COPY,     wxSTOCK_MENU, _("Copy selection"))
+        STOCKITEM(wxID_CUT,      wxSTOCK_MENU, _("Cut selection"))
+        STOCKITEM(wxID_DELETE,   wxSTOCK_MENU, _("Delete selection"))
+        STOCKITEM(wxID_REPLACE,  wxSTOCK_MENU, _("Replace selection"))
+        STOCKITEM(wxID_PASTE,    wxSTOCK_MENU, _("Paste selection"))
+        STOCKITEM(wxID_EXIT,     wxSTOCK_MENU, _("Quit this program"))
+        STOCKITEM(wxID_REDO,     wxSTOCK_MENU, _("Redo last action"))
+        STOCKITEM(wxID_UNDO,     wxSTOCK_MENU, _("Undo last action"))
+        STOCKITEM(wxID_CLOSE,    wxSTOCK_MENU, _("Close current document"))
+        STOCKITEM(wxID_SAVE,     wxSTOCK_MENU, _("Save current document"))
+        STOCKITEM(wxID_SAVEAS,   wxSTOCK_MENU, _("Save current document with a different filename"))
+
+        default:
+            // there's no stock help string for this ID / client
+            return wxEmptyString;
+    }
+
+    #undef STOCKITEM
+
+    return stockHelp;
+}
+
 #if wxUSE_ACCEL
 
 wxAcceleratorEntry wxGetStockAccelerator(wxWindowID id)
diff --git a/src/gtk1/menu.cpp b/src/gtk1/menu.cpp
index 10fee257c6..fa3f149dd0 100644
--- a/src/gtk1/menu.cpp
+++ b/src/gtk1/menu.cpp
@@ -769,10 +769,11 @@ wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
 void wxMenuItem::SetText( const wxString& string )
 {
     wxString str = string;
-    if (str.IsEmpty())
+    if ( str.empty() && !IsSeparator() )
     {
         wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
-        str = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
+        str = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR |
+                                       wxSTOCK_WITH_MNEMONIC);
     }
 
     // Some optimization to avoid flicker
diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp
index d2d737ae34..79c03953b8 100644
--- a/src/msw/menuitem.cpp
+++ b/src/msw/menuitem.cpp
@@ -154,12 +154,6 @@ wxMenuItem::wxMenuItem(wxMenu *parentMenu,
 
 void wxMenuItem::Init()
 {
-    if (m_text.IsEmpty())
-    {
-        wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
-        m_text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
-    }
-
     m_radioGroup.start = -1;
     m_isRadioGroupStart = false;
 
@@ -351,17 +345,16 @@ void wxMenuItem::SetText(const wxString& txt)
     if ( m_text == txt )
         return;
 
-    if (text.IsEmpty())
-    {
-        wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
-        text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
-    }
-
+    // wxMenuItemBase will do stock ID checks
     wxMenuItemBase::SetText(text);
-    OWNER_DRAWN_ONLY( wxOwnerDrawn::SetName(text) );
+
+    // m_text could now be different from 'text' if we are a stock menu item,
+    // so use only m_text below
+
+    OWNER_DRAWN_ONLY( wxOwnerDrawn::SetName(m_text) );
 #if wxUSE_OWNER_DRAWN
     // tell the owner drawing code to to show the accel string as well
-    SetAccelString(text.AfterFirst(_T('\t')));
+    SetAccelString(m_text.AfterFirst(_T('\t')));
 #endif
 
     HMENU hMenu = GetHMenuOf(m_parentMenu);
@@ -399,7 +392,7 @@ void wxMenuItem::SetText(const wxString& txt)
 #endif  //owner drawn
         {
             flagsOld |= MF_STRING;
-            data = (wxChar*) text.c_str();
+            data = (wxChar*) m_text.c_str();
         }
 
 #ifdef __WXWINCE__
@@ -413,7 +406,7 @@ void wxMenuItem::SetText(const wxString& txt)
         info.cbSize = sizeof(info);
         info.fMask = MIIM_TYPE;
         info.fType = MFT_STRING;
-        info.cch = text.length();
+        info.cch = m_text.length();
         info.dwTypeData = (LPTSTR) data ;
         if ( !::SetMenuItemInfo(hMenu, id, FALSE, & info) )
         {
diff --git a/src/os2/menuitem.cpp b/src/os2/menuitem.cpp
index 2a5f378584..9a0ed81340 100644
--- a/src/os2/menuitem.cpp
+++ b/src/os2/menuitem.cpp
@@ -373,17 +373,16 @@ void wxMenuItem::SetText( const wxString& rText )
     if (m_text == sText)
         return;
 
-    if (sText.IsEmpty())
-    {
-        wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
-        sText = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
-    }
-
+    // wxMenuItemBase will do stock ID checks
     wxMenuItemBase::SetText(sText);
-    OWNER_DRAWN_ONLY(wxOwnerDrawn::SetName(sText));
+
+    // m_text could now be different from 'text' if we are a stock menu item,
+    // so use only m_text below
+
+    OWNER_DRAWN_ONLY(wxOwnerDrawn::SetName(m_text));
 #if  wxUSE_OWNER_DRAWN
     if (rText.IsEmpty())
-        SetAccelString(sText.AfterFirst(_T('\t')));
+        SetAccelString(m_text.AfterFirst(_T('\t')));
     else
         SetAccelString(rText.AfterFirst(_T('\t')));
 #endif // wxUSE_OWNER_DRAWN
@@ -428,7 +427,7 @@ void wxMenuItem::SetText( const wxString& rText )
 #endif  //owner drawn
         {
             uFlagsOld |= MIS_TEXT;
-            pData = (BYTE*)sText.c_str();
+            pData = (BYTE*)m_text.c_str();
         }
 
         //
diff --git a/src/univ/menu.cpp b/src/univ/menu.cpp
index e2e7f7ab8f..0a29b8ada5 100644
--- a/src/univ/menu.cpp
+++ b/src/univ/menu.cpp
@@ -1538,18 +1538,12 @@ void wxMenuItem::UpdateAccelInfo()
     m_strAccel = m_text.AfterFirst(_T('\t'));
 }
 
-void wxMenuItem::SetText(const wxString& txt)
+void wxMenuItem::SetText(const wxString& text)
 {
-    if ( txt != m_text )
+    if ( text != m_text )
     {
-        wxString text = txt;
-        if (text.IsEmpty())
-        {
-            wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
-            text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
-        }
-
         // first call the base class version to change m_text
+        // (and also check if we don't have a stock menu item)
         wxMenuItemBase::SetText(text);
 
         UpdateAccelInfo();
-- 
2.50.0

