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 "&", "<", ">", "'", """
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("&");
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