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