1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/mnemonics.cpp
3 // Purpose:     implementation of GTK mnemonics conversion functions
4 // Author:      Vadim Zeitlin
5 // Created:     2007-11-12
6 // Copyright:   (c) 2007 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence:     wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 // ============================================================================
11 // declarations
12 // ============================================================================
13 
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17 
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20 
21 
22 #include "wx/log.h"
23 #include "wx/gtk/private/mnemonics.h"
24 
25 namespace
26 {
27 
28 // ----------------------------------------------------------------------------
29 // constants
30 // ----------------------------------------------------------------------------
31 
32 // Names of the standard XML entities.
33 const char *const entitiesNames[] =
34 {
35     "&amp;", "&lt;", "&gt;", "&apos;", "&quot;"
36 };
37 
38 } // anonymous namespace
39 
40 // ============================================================================
41 // implementation
42 // ============================================================================
43 
44 // ----------------------------------------------------------------------------
45 // internal helper: apply the operation indicated by flag
46 // ----------------------------------------------------------------------------
47 
48 enum MnemonicsFlag
49 {
50     MNEMONICS_REMOVE,
51     MNEMONICS_CONVERT,
52     MNEMONICS_CONVERT_MARKUP
53 };
54 
GTKProcessMnemonics(const wxString & label,MnemonicsFlag flag)55 static wxString GTKProcessMnemonics(const wxString& label, MnemonicsFlag flag)
56 {
57     wxString labelGTK;
58     labelGTK.reserve(label.length());
59     for ( wxString::const_iterator i = label.begin(); i != label.end(); ++i )
60     {
61         wxChar ch = *i;
62 
63         switch ( ch )
64         {
65             case wxT('&'):
66                 if ( i + 1 == label.end() )
67                 {
68                     // "&" at the end of string is an error
69                     wxLogDebug(wxT("Invalid label \"%s\"."), label);
70                     break;
71                 }
72 
73                 if ( flag == MNEMONICS_CONVERT_MARKUP )
74                 {
75                     bool isMnemonic = true;
76                     size_t distanceFromEnd = label.end() - i;
77 
78                     // is this ampersand introducing a mnemonic or rather an entity?
79                     for (size_t j=0; j < WXSIZEOF(entitiesNames); j++)
80                     {
81                         const char *entity = entitiesNames[j];
82                         size_t entityLen = wxStrlen(entity);
83 
84                         if (distanceFromEnd >= entityLen &&
85                             wxString(i, i + entityLen) == entity)
86                         {
87                             labelGTK << entity;
88                             i += entityLen - 1;     // the -1 is because main for()
89                                                     // loop already increments i
90                             isMnemonic = false;
91 
92                             break;
93                         }
94                     }
95 
96                     if (!isMnemonic)
97                         continue;
98                 }
99 
100                 ch = *(++i); // skip '&' itself
101                 switch ( ch )
102                 {
103                     case wxT('&'):
104                         // special case: "&&" is not a mnemonic at all but just
105                         // an escaped "&"
106                         if ( flag == MNEMONICS_CONVERT_MARKUP )
107                             labelGTK += wxT("&amp;");
108                         else
109                             labelGTK += wxT('&');
110                         break;
111 
112                     case wxT('_'):
113                         if ( flag != MNEMONICS_REMOVE )
114                         {
115                             // '_' can't be a GTK mnemonic apparently so
116                             // replace it with something similar
117                             labelGTK += wxT("_-");
118                             break;
119                         }
120                         wxFALLTHROUGH;
121 
122                     default:
123                         if ( flag != MNEMONICS_REMOVE )
124                             labelGTK += wxT('_');
125                         labelGTK += ch;
126                 }
127                 break;
128 
129             case wxT('_'):
130                 if ( flag != MNEMONICS_REMOVE )
131                 {
132                     // escape any existing underlines in the string so that
133                     // they don't become mnemonics accidentally
134                     labelGTK += wxT("__");
135                     break;
136                 }
137                 wxFALLTHROUGH;
138 
139             default:
140                 labelGTK += ch;
141         }
142     }
143 
144     return labelGTK;
145 }
146 
147 // ----------------------------------------------------------------------------
148 // public functions
149 // ----------------------------------------------------------------------------
150 
wxGTKRemoveMnemonics(const wxString & label)151 wxString wxGTKRemoveMnemonics(const wxString& label)
152 {
153     return GTKProcessMnemonics(label, MNEMONICS_REMOVE);
154 }
155 
wxConvertMnemonicsToGTK(const wxString & label)156 wxString wxConvertMnemonicsToGTK(const wxString& label)
157 {
158     return GTKProcessMnemonics(label, MNEMONICS_CONVERT);
159 }
160 
wxConvertMnemonicsToGTKMarkup(const wxString & label)161 wxString wxConvertMnemonicsToGTKMarkup(const wxString& label)
162 {
163     return GTKProcessMnemonics(label, MNEMONICS_CONVERT_MARKUP);
164 }
165 
wxConvertMnemonicsFromGTK(const wxString & gtkLabel)166 wxString wxConvertMnemonicsFromGTK(const wxString& gtkLabel)
167 {
168     wxString label;
169     for ( const wxChar *pc = gtkLabel.c_str(); *pc; pc++ )
170     {
171         // '_' is the escape character for GTK+.
172 
173         if ( *pc == wxT('_') && *(pc+1) == wxT('_'))
174         {
175             // An underscore was escaped.
176             label += wxT('_');
177             pc++;
178         }
179         else if ( *pc == wxT('_') )
180         {
181             // Convert GTK+ hotkey symbol to wxWidgets/Windows standard
182             label += wxT('&');
183         }
184         else if ( *pc == wxT('&') )
185         {
186             // Double the ampersand to escape it as far as wxWidgets is concerned
187             label += wxT("&&");
188         }
189         else
190         {
191             // don't remove ampersands '&' since if we have them in the menu title
192             // it means that they were doubled to indicate "&" instead of accelerator
193             label += *pc;
194         }
195     }
196 
197     return label;
198 }
199 
200