Fix truncating CJK mnemonics in control labels

13068d3603 introduced code for stripping
CJK mnemonics (i.e. trailing " (&X)") from the menu items, but due to
the use of wxStripMenuCodes() in wxControl::GetLabelText(), it also
applied to the control labels, resulting in wrongly measuring their size
(because the text used for measurement didn't include the "(&X)" part)
and truncating them in display.

Fix this by adding an explicit wxStrip_CJKMnemonics and using it only in
the code dealing with the menu item labels. This requires more changes
than just modifying GetLabelText() to use some wxStrip_NoCJKMnemonics
flag, but is more compatible as it's not impossible that some existing
code using wxStripMenuCodes() could be broken by this change too, while
now the existing behaviour is preserved.

Also improve wxStrip_XXX documentation.

Closes https://github.com/wxWidgets/wxWidgets/pull/1439

See #16736.

Closes #18452.
This commit is contained in:
Vadim Zeitlin
2019-07-24 11:19:29 +02:00
parent 8ea46e70c5
commit 9d92ba185c
12 changed files with 80 additions and 30 deletions

View File

@@ -652,8 +652,18 @@ enum
// strip everything after '\t' // strip everything after '\t'
wxStrip_Accel = 2, wxStrip_Accel = 2,
// strip everything (this is the default) // strip mnemonics of the form "(&X)" appended to the string (used in CJK
wxStrip_All = wxStrip_Mnemonics | wxStrip_Accel // translations)
wxStrip_CJKMnemonics = 4,
// strip everything (this doesn't include wxStrip_CJKMnemonics for
// compatibility)
wxStrip_All = wxStrip_Mnemonics | wxStrip_Accel,
// strip everything including CJK mnemonics, suitable for menu items labels
// only (despite its name, wxStripMenuCodes() is currently used for control
// labels too)
wxStrip_Menu = wxStrip_All | wxStrip_CJKMnemonics
}; };
// strip mnemonics and/or accelerators from the label // strip mnemonics and/or accelerators from the label

View File

@@ -682,14 +682,54 @@ void wxSetDisplayName(const wxString& displayName);
*/ */
enum enum
{ {
// strip '&' characters /**
Strip '&' characters.
This flag removes all the ampersands before another character and
replaces double ampersands with a single one.
*/
wxStrip_Mnemonics = 1, wxStrip_Mnemonics = 1,
// strip everything after '\t' /**
Strip everything after '\t'.
This flags removes everything following the last TAB character in the
string, if any.
*/
wxStrip_Accel = 2, wxStrip_Accel = 2,
// strip everything (this is the default) /**
wxStrip_All = wxStrip_Mnemonics | wxStrip_Accel Strip everything looking like CJK mnemonic.
CJK (Chinese, Japanese, Korean) translations sometimes preserve the
original English accelerator or mnemonic in the translated string by
putting it after the translated string in parentheses, e.g. the string
"&File" could be translated as "<translation-of-word-file> (&F)".
This flag strips trailing "(&X)" from the string.
@since 3.1.3
*/
wxStrip_CJKMnemonics = 4,
/**
Strip both mnemonics and accelerators.
This is the value used by wxStripMenuCodes() by default.
Note that, despite the name, this flag does @e not strip all, as it
doesn't include wxStrip_CJKMnemonics for compatibility.
*/
wxStrip_All = wxStrip_Mnemonics | wxStrip_Accel,
/**
Strip everything from menu item labels.
This flag is used by wxWidgets internally and removes CJK mnemonics
from the labels too, in addition to the usual mnemonics and
accelerators. It is only suitable for use with the menu items.
*/
wxStrip_Menu = wxStrip_All | wxStrip_CJKMnemonics
}; };
/** /**

View File

@@ -326,7 +326,7 @@ void wxMenuItemBase::SetHelp(const wxString& str)
wxString wxMenuItemBase::GetLabelText(const wxString& text) wxString wxMenuItemBase::GetLabelText(const wxString& text)
{ {
return wxStripMenuCodes(text); return wxStripMenuCodes(text, wxStrip_Menu);
} }
#if WXWIN_COMPATIBILITY_2_8 #if WXWIN_COMPATIBILITY_2_8

View File

@@ -1177,7 +1177,7 @@ wxString wxStripMenuCodes(const wxString& in, int flags)
// In some East Asian languages _("&File") translates as "<translation>(&F)" // In some East Asian languages _("&File") translates as "<translation>(&F)"
// Check for this first, otherwise fall through to the standard situation // Check for this first, otherwise fall through to the standard situation
if (flags & wxStrip_Mnemonics) if ( flags & wxStrip_CJKMnemonics )
{ {
wxString label(in), accel; wxString label(in), accel;
int pos = in.Find('\t'); int pos = in.Find('\t');

View File

@@ -756,9 +756,9 @@ void wxMenuItem::SetItemLabel( const wxString& string )
// Some optimization to avoid flicker // Some optimization to avoid flicker
wxString oldLabel = m_text; wxString oldLabel = m_text;
oldLabel = wxStripMenuCodes(oldLabel); oldLabel = wxStripMenuCodes(oldLabel, wxStrip_Menu);
oldLabel.Replace(wxT("_"), wxEmptyString); oldLabel.Replace(wxT("_"), wxEmptyString);
wxString label1 = wxStripMenuCodes(str); wxString label1 = wxStripMenuCodes(str, wxStrip_Menu);
wxString oldhotkey = GetHotKey(); // Store the old hotkey in Ctrl-foo format wxString oldhotkey = GetHotKey(); // Store the old hotkey in Ctrl-foo format
wxCharBuffer oldbuf = wxGTK_CONV( GetGtkHotKey(*this) ); // and as <control>foo wxCharBuffer oldbuf = wxGTK_CONV( GetGtkHotKey(*this) ); // and as <control>foo

View File

@@ -292,12 +292,12 @@ wxMenu *wxMenuBar::Remove(size_t pos)
// Returns -1 if none found. // Returns -1 if none found.
int wxMenuBar::FindMenuItem(const wxString& menuString, const wxString& itemString) const int wxMenuBar::FindMenuItem(const wxString& menuString, const wxString& itemString) const
{ {
const wxString stripped = wxStripMenuCodes(menuString); const wxString stripped = wxStripMenuCodes(menuString, wxStrip_Menu);
size_t menuCount = GetMenuCount(); size_t menuCount = GetMenuCount();
for (size_t i = 0; i < menuCount; i++) for (size_t i = 0; i < menuCount; i++)
{ {
if ( wxStripMenuCodes(m_titles[i]) == stripped ) if ( wxStripMenuCodes(m_titles[i], wxStrip_Menu) == stripped )
return m_menus.Item(i)->GetData()->FindItem (itemString); return m_menus.Item(i)->GetData()->FindItem (itemString);
} }
return wxNOT_FOUND; return wxNOT_FOUND;
@@ -347,7 +347,7 @@ bool wxMenuBar::CreateMenuBar(wxFrame* parent)
wxString title(m_titles[i]); wxString title(m_titles[i]);
menu->SetButtonWidget(menu->CreateMenu (this, menuBarW, menu, i, title, true)); menu->SetButtonWidget(menu->CreateMenu (this, menuBarW, menu, i, title, true));
if (strcmp (wxStripMenuCodes(title), "Help") == 0) if (strcmp (wxStripMenuCodes(title, wxStrip_Menu), "Help") == 0)
XtVaSetValues ((Widget) menuBarW, XmNmenuHelpWidget, (Widget) menu->GetButtonWidget(), NULL); XtVaSetValues ((Widget) menuBarW, XmNmenuHelpWidget, (Widget) menu->GetButtonWidget(), NULL);
// tear off menu support // tear off menu support
@@ -478,7 +478,7 @@ WXWidget wxMenu::CreateMenu (wxMenuBar * menuBar,
char mnem = wxFindMnemonic (title); char mnem = wxFindMnemonic (title);
menu = XmCreatePulldownMenu ((Widget) parent, wxMOTIF_STR("pulldown"), args, 3); menu = XmCreatePulldownMenu ((Widget) parent, wxMOTIF_STR("pulldown"), args, 3);
wxString title2(wxStripMenuCodes(title)); wxString title2(wxStripMenuCodes(title, wxStrip_Menu));
wxXmString label_str(title2); wxXmString label_str(title2);
buttonWidget = XtVaCreateManagedWidget(title2, buttonWidget = XtVaCreateManagedWidget(title2,
#if wxUSE_GADGETS #if wxUSE_GADGETS

View File

@@ -161,7 +161,7 @@ void wxMenuItem::CreateItem (WXWidget menu, wxMenuBar * menuBar,
{ {
// Id=-3 identifies a Title item. // Id=-3 identifies a Title item.
m_buttonWidget = (WXWidget) XtVaCreateManagedWidget m_buttonWidget = (WXWidget) XtVaCreateManagedWidget
(wxStripMenuCodes(m_text), (wxStripMenuCodes(m_text, wxStrip_Menu),
xmLabelGadgetClass, (Widget) menu, NULL); xmLabelGadgetClass, (Widget) menu, NULL);
} }
else if (!IsSeparator() && !m_subMenu) else if (!IsSeparator() && !m_subMenu)
@@ -174,7 +174,7 @@ void wxMenuItem::CreateItem (WXWidget menu, wxMenuBar * menuBar,
txt = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC); txt = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR|wxSTOCK_WITH_MNEMONIC);
} }
wxString strName = wxStripMenuCodes(txt); wxString strName = wxStripMenuCodes(txt, wxStrip_Menu);
if (IsCheckable()) if (IsCheckable())
{ {
m_buttonWidget = (WXWidget) XtVaCreateManagedWidget (strName, m_buttonWidget = (WXWidget) XtVaCreateManagedWidget (strName,
@@ -302,7 +302,7 @@ void wxMenuItem::DestroyItem(bool full)
void wxMenuItem::SetItemLabel(const wxString& label) void wxMenuItem::SetItemLabel(const wxString& label)
{ {
char mnem = wxFindMnemonic (label); char mnem = wxFindMnemonic (label);
wxString label2 = wxStripMenuCodes(label); wxString label2 = wxStripMenuCodes(label, wxStrip_Menu);
m_text = label; m_text = label;

View File

@@ -1570,7 +1570,7 @@ void MDIInsertWindowMenu(wxWindow *win, WXHMENU hMenu, HMENU menuWin, const wxSt
MenuIterator it(hmenu); MenuIterator it(hmenu);
while ( it.GetNext(buf) ) while ( it.GetNext(buf) )
{ {
const wxString label = wxStripMenuCodes(buf); const wxString label = wxStripMenuCodes(buf, wxStrip_Menu);
if ( label == wxGetStockLabel(wxID_HELP, wxSTOCK_NOFLAGS) ) if ( label == wxGetStockLabel(wxID_HELP, wxSTOCK_NOFLAGS) )
{ {
inserted = true; inserted = true;

View File

@@ -232,8 +232,8 @@ public :
virtual NSMenu* MacCreateOrFindWindowMenu() virtual NSMenu* MacCreateOrFindWindowMenu()
{ {
NSString* nsWindowMenuTitle = wxNSStringWithWxString(wxStripMenuCodes(wxApp::s_macWindowMenuTitleName)); NSString* nsWindowMenuTitle = wxNSStringWithWxString(wxStripMenuCodes(wxApp::s_macWindowMenuTitleName, wxStrip_Menu));
NSString* nsAlternateWindowMenuTitle = wxNSStringWithWxString(wxStripMenuCodes(_("&Window"))); NSString* nsAlternateWindowMenuTitle = wxNSStringWithWxString(wxStripMenuCodes(_("&Window"), wxStrip_Menu));
NSMenu* windowMenu = nil; NSMenu* windowMenu = nil;

View File

@@ -64,7 +64,7 @@ void wxMenu::Init()
m_noEventsMode = false; m_noEventsMode = false;
m_radioData = NULL; m_radioData = NULL;
m_peer = wxMenuImpl::Create( this, wxStripMenuCodes(m_title) ); m_peer = wxMenuImpl::Create( this, wxStripMenuCodes(m_title, wxStrip_Menu) );
// if we have a title, insert it in the beginning of the menu // if we have a title, insert it in the beginning of the menu
@@ -221,7 +221,7 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
void wxMenu::SetTitle(const wxString& label) void wxMenu::SetTitle(const wxString& label)
{ {
m_title = label ; m_title = label ;
GetPeer()->SetTitle( wxStripMenuCodes( label ) ); GetPeer()->SetTitle( wxStripMenuCodes( label, wxStrip_Menu ) );
} }
bool wxMenu::ProcessCommand(wxCommandEvent & event) bool wxMenu::ProcessCommand(wxCommandEvent & event)

View File

@@ -41,10 +41,10 @@ wxMenuItem::wxMenuItem(wxMenu *pParentMenu,
// In other languages there is no difference in naming the Exit/Quit menu item between MacOS and Windows guidelines // In other languages there is no difference in naming the Exit/Quit menu item between MacOS and Windows guidelines
// therefore these item must not be translated // therefore these item must not be translated
if (pParentMenu != NULL && !pParentMenu->GetNoEventsMode()) if (pParentMenu != NULL && !pParentMenu->GetNoEventsMode())
if ( wxStripMenuCodes(m_text).Upper() == wxT("EXIT") ) if ( wxStripMenuCodes(m_text, wxStrip_Menu).Upper() == wxT("EXIT") )
m_text = wxT("Quit\tCtrl+Q") ; m_text = wxT("Quit\tCtrl+Q") ;
wxString text = wxStripMenuCodes(m_text, (pParentMenu != NULL && pParentMenu->GetNoEventsMode()) ? wxStrip_Accel : wxStrip_All); wxString text = wxStripMenuCodes(m_text, (pParentMenu != NULL && pParentMenu->GetNoEventsMode()) ? wxStrip_Accel : wxStrip_Menu);
if (text.IsEmpty() && !IsSeparator()) if (text.IsEmpty() && !IsSeparator())
{ {
wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?")); wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));
@@ -191,7 +191,7 @@ void wxMenuItem::UpdateItemText()
if ( !m_parentMenu ) if ( !m_parentMenu )
return ; return ;
wxString text = wxStripMenuCodes(m_text, m_parentMenu != NULL && m_parentMenu->GetNoEventsMode() ? wxStrip_Accel : wxStrip_All); wxString text = wxStripMenuCodes(m_text, m_parentMenu != NULL && m_parentMenu->GetNoEventsMode() ? wxStrip_Accel : wxStrip_Menu);
if (text.IsEmpty() && !IsSeparator()) if (text.IsEmpty() && !IsSeparator())
{ {
wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?")); wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?"));

View File

@@ -365,8 +365,8 @@ void MenuTestCase::TranslatedMnemonics()
wxString filemenu = m_frame->GetMenuBar()->GetMenuLabel(0); wxString filemenu = m_frame->GetMenuBar()->GetMenuLabel(0);
CPPUNIT_ASSERT_EQUAL CPPUNIT_ASSERT_EQUAL
( (
wxStripMenuCodes(GetTranslatedString(trans, "&File")), wxStripMenuCodes(GetTranslatedString(trans, "&File"), wxStrip_Menu),
wxStripMenuCodes(GetTranslatedString(trans, filemenu)) wxStripMenuCodes(GetTranslatedString(trans, filemenu), wxStrip_Menu)
); );
// Test strings that have shortcuts. Duplicate non-mnemonic translations // Test strings that have shortcuts. Duplicate non-mnemonic translations
@@ -374,21 +374,21 @@ void MenuTestCase::TranslatedMnemonics()
CPPUNIT_ASSERT_EQUAL CPPUNIT_ASSERT_EQUAL
( (
GetTranslatedString(trans, "Edit"), GetTranslatedString(trans, "Edit"),
wxStripMenuCodes(GetTranslatedString(trans, "E&dit\tCtrl+E")) wxStripMenuCodes(GetTranslatedString(trans, "E&dit\tCtrl+E"), wxStrip_Menu)
); );
// "Vie&w" also has a space before the (&W) // "Vie&w" also has a space before the (&W)
CPPUNIT_ASSERT_EQUAL CPPUNIT_ASSERT_EQUAL
( (
GetTranslatedString(trans, "View"), GetTranslatedString(trans, "View"),
wxStripMenuCodes(GetTranslatedString(trans, "Vie&w\tCtrl+V")) wxStripMenuCodes(GetTranslatedString(trans, "Vie&w\tCtrl+V"), wxStrip_Menu)
); );
// Test a 'normal' mnemonic too: the translation is "Preten&d" // Test a 'normal' mnemonic too: the translation is "Preten&d"
CPPUNIT_ASSERT_EQUAL CPPUNIT_ASSERT_EQUAL
( (
"Pretend", "Pretend",
wxStripMenuCodes(GetTranslatedString(trans, "B&ogus")) wxStripMenuCodes(GetTranslatedString(trans, "B&ogus"), wxStrip_Menu)
); );
} }
#endif // wxUSE_INTL #endif // wxUSE_INTL