libyui  3.3.1
YShortcut.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: YShortcut.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 
26 #include <ctype.h> // toupper(), tolower()
27 #include <string.h> // strstr()
28 
29 #define YUILogComponent "ui-shortcuts"
30 #include "YUILog.h"
31 
32 #include "YShortcut.h"
33 #include "YPushButton.h"
34 #include "YDumbTab.h"
35 
36 
37 // Return the number of elements of an array of any type
38 #define DIM( ARRAY ) ( (int) ( sizeof( ARRAY)/( sizeof( ARRAY[0] ) ) ) )
39 
40 
41 YShortcut::YShortcut( YWidget * shortcutWidget )
42  : _widget( shortcutWidget )
43 {
44  _preferred = -1;
45  _shortcut = -1;
46  _distinctShortcutChars = -1;
47  _conflict = false;
48  _shortcutStringCached = false;
49  _cleanShortcutStringCached = false;
50 
51  YPushButton * button = dynamic_cast<YPushButton *>( shortcutWidget);
52  _isButton = ( button != 0 );
53 
54  if ( _isButton )
55  {
56  _isWizardButton = strstr( shortcutWidget->widgetClass(), "WizardButton" );
57 
58  // yuiDebug() << shortcutWidget << ( _isWizardButton ? " is " : " is not " ) << "a wizard button" << endl;
59  }
60  else
61  {
62  _isWizardButton = 0;
63  }
64 
65  // yuiDebug() << shortcutWidget << ( _isButton ? " is " : " is not " ) << "a button" << endl;
66 }
67 
68 
70 {
71 }
72 
73 
74 std::string
76 {
77  if ( ! _shortcutStringCached )
78  {
79  _shortcutString = getShortcutString();
80  _shortcutStringCached = true;
81 
82  // Note: We really need a separate variable here - an empty string
83  // might be a valid value!
84  }
85 
86  return _shortcutString;
87 }
88 
89 
90 std::string
92 {
93  if ( ! _cleanShortcutStringCached )
94  {
95  _cleanShortcutString = cleanShortcutString( shortcutString() );
96  }
97 
98  return _cleanShortcutString;
99 }
100 
101 
102 std::string
104 {
105  std::string::size_type pos = 0;
106 
107  while ( ( pos = findShortcutPos( shortcutString, pos ) ) != std::string::npos )
108  {
109  shortcutString.erase( pos, ( std::string::size_type ) 1 );
110  }
111 
112  return shortcutString;
113 }
114 
115 
116 char
118 {
119  if ( _preferred < 0 )
120  {
121  _preferred = normalized( findShortcut( shortcutString() ) );
122  }
123 
124  return (char) _preferred;
125 }
126 
127 
128 char
130 {
131  if ( _shortcut < 0 )
132  {
133  _shortcut = preferred();
134  }
135 
136  return (char) _shortcut;
137 }
138 
139 
140 void
141 YShortcut::setShortcut( char newShortcut )
142 {
143  std::string str = cleanShortcutString();
144 
145  if ( newShortcut != YShortcut::None )
146  {
147  char findme[] = { (char)tolower( newShortcut ), (char)toupper( newShortcut ), 0 };
148  std::string::size_type pos = str.find_first_of( findme );
149 
150  if ( pos == std::string::npos )
151  {
152  yuiError() << "Can't find '<< " << newShortcut
153  << "' in " << widgetClass()
154  << " \"" << cleanShortcutString() << "\""
155  << std::endl;
156 
157  return;
158  }
159 
160  str.insert( pos,
161  std::string( 1, shortcutMarker() ) ); // equivalent to 'std::string( "& " )'
162  }
163 
164  widget()->setShortcutString( str );
165 
166  _shortcutStringCached = false;
167  _cleanShortcutStringCached = false;
168  _shortcut = newShortcut;
169 }
170 
171 
172 void
174 {
175  setShortcut( YShortcut::None );
176 }
177 
178 
179 int
181 {
182  if ( _distinctShortcutChars < 0 ) // cache this value - it's expensive!
183  {
184  // Create and initialize "contained" array - what possible shortcut
185  // characters are contained in that string?
186 
187  bool contained[ sizeof(char) << 8 ];
188 
189  for ( int i=0; i < DIM( contained ); i++ )
190  contained[i] = false;
191 
192 
193  // Mark characters as contained
194 
195  std::string clean = cleanShortcutString();
196 
197  for ( std::string::size_type pos=0; pos < clean.length(); pos++ )
198  {
199  if ( YShortcut::isValid( clean[ pos ] ) )
200  contained[ (int) clean[ pos ] ] = true;
201  }
202 
203 
204  // Count number of contained characters
205 
206  _distinctShortcutChars=0;
207 
208  for ( int i=0; i < DIM( contained ); i++ )
209  {
210  if ( contained[i] )
211  {
212  _distinctShortcutChars++;
213  }
214  }
215  }
216 
217  return _distinctShortcutChars;
218 }
219 
220 
221 bool
223 {
224  std::string clean = cleanShortcutString();
225 
226  for ( std::string::size_type pos=0; pos < clean.length(); pos++ )
227  {
228  if ( YShortcut::isValid( clean[ pos ] ) )
229  return true;
230  }
231 
232  return false;
233 }
234 
235 
236 std::string
238 {
239  return getShortcutString( widget() );
240 }
241 
242 
243 std::string
245 {
246  if ( ! widget )
247  return std::string( "" );
248 
249  return widget->shortcutString();
250 }
251 
252 
253 std::string::size_type
254 YShortcut::findShortcutPos( const std::string & str, std::string::size_type pos )
255 {
256  while ( ( pos = str.find( shortcutMarker(), pos ) ) != std::string::npos )
257  {
258  if ( pos+1 < str.length() )
259  {
260  if ( str[ pos+1 ] == shortcutMarker() ) // escaped marker? ( "&&" )
261  {
262  pos += 2; // skip this and search for more
263  }
264  else
265  return pos;
266  }
267  else
268  {
269  // A pathological case: The string ends with '& '.
270  // This is invalid anyway, but prevent endless loop even in this case.
271  return std::string::npos;
272  }
273  }
274 
275  return std::string::npos; // not found
276 }
277 
278 
279 char
280 YShortcut::findShortcut( const std::string & str, std::string::size_type pos )
281 {
282  pos = findShortcutPos( str, pos );
283 
284  return pos == std::string::npos ? (char) 0 : str[ pos+1 ];
285 }
286 
287 
288 bool
290 {
291  if ( c >= 'a' && c <= 'z' ) return true;
292  if ( c >= 'A' && c <= 'Z' ) return true;
293  if ( c >= '0' && c <= '9' ) return true;
294  return false;
295 }
296 
297 
298 char
300 {
301  if ( c >= 'a' && c <= 'z' ) return c - 'a' + 'A';
302  if ( c >= 'A' && c <= 'Z' ) return c;
303  if ( c >= '0' && c <= '9' ) return c;
304  return (char) 0;
305 }
306 
307 
308 
309 std::string
311 {
312  if ( ! _item )
313  return "";
314 
315  return _item->label();
316 }
317 
318 
319 void
320 YItemShortcut::setShortcut( char newShortcut )
321 {
322  std::string str = cleanShortcutString();
323 
324  if ( newShortcut != YShortcut::None )
325  {
326  char findme[] = { (char)tolower( newShortcut ), (char)toupper( newShortcut ), 0 };
327  std::string::size_type pos = str.find_first_of( findme );
328 
329  if ( pos == std::string::npos )
330  {
331  yuiError() << "Can't find '<< " << newShortcut
332  << "' in item "
333  << " \"" << cleanShortcutString() << "\""
334  << std::endl;
335 
336  return;
337  }
338 
339  str.insert( pos,
340  std::string( 1, shortcutMarker() ) ); // equivalent to 'std::string( "& " )'
341  }
342 
343  _item->setLabel( str );
344 
345  // Notify the parent widget
347 
348  _shortcutStringCached = false;
349  _cleanShortcutStringCached = false;
350  _shortcut = newShortcut;
351 
352 }
virtual std::string shortcutString() const
Get the string of this widget that holds the keyboard shortcut, if any.
Definition: YWidget.h:560
virtual ~YShortcut()
Destructor.
Definition: YShortcut.cc:69
virtual const char * widgetClass() const
Returns a descriptive name of this widget class for logging, debugging etc.
Definition: YWidget.h:72
char preferred()
The preferred shortcut character, i.e.
Definition: YShortcut.cc:117
virtual void setShortcut(char newShortcut)
Set (override) the shortcut character.
Definition: YShortcut.cc:320
static std::string::size_type findShortcutPos(const std::string &str, std::string::size_type start_pos=0)
Static function: Find the next occurrence of the shortcut marker (&#39;&&#39;) in a string, beginning at starting position start_pos.
Definition: YShortcut.cc:254
virtual std::string getShortcutString()
Obtain the the shortcut property of this shortcut&#39;s widget - the string that contains "&" to designat...
Definition: YShortcut.cc:237
const char * widgetClass() const
Returns the textual representation of the widget class of the widget this shortcut data belongs to...
Definition: YShortcut.h:67
virtual void setShortcut(char newShortcut)
Set (override) the shortcut character.
Definition: YShortcut.cc:141
static char normalized(char c)
Return the normalized version of shortcut character &#39;c&#39;, i.e.
Definition: YShortcut.cc:299
virtual std::string getShortcutString()
Obtain the the shortcut property of this shortcut&#39;s widget - the string that contains "&" to designat...
Definition: YShortcut.cc:310
A push button; may have an icon, and a F-key shortcut.
Definition: YPushButton.h:37
std::string cleanShortcutString()
Returns the shortcut string ( from the widget&#39;s shortcut property ) without any "&" markers...
Definition: YShortcut.cc:91
static char shortcutMarker()
Static function: Returns the character used for marking keyboard shortcuts.
Definition: YShortcut.h:154
static char findShortcut(const std::string &str, std::string::size_type start_pos=0)
Static function: Find the next shortcut marker in a string, beginning at starting position start_pos...
Definition: YShortcut.cc:280
std::string shortcutString()
Returns the complete shortcut string (which may or may not contain "&"), i.e.
Definition: YShortcut.cc:75
virtual void setShortcutString(const std::string &str)
Set the string of this widget that holds the keyboard shortcut, if any.
Definition: YWidget.cc:508
void clearShortcut()
Clear the shortcut: Override the shortcut character with nothing.
Definition: YShortcut.cc:173
int distinctShortcutChars()
Obtain the number of distinct valid shortcut characters in the shortcut string, i.e.
Definition: YShortcut.cc:180
bool hasValidShortcutChar()
Return true if this shortcut contains any character that would be valid as a shortcut character...
Definition: YShortcut.cc:222
YWidget * widget() const
Returns the YWidget this shortcut data belong to.
Definition: YShortcut.h:61
Abstract base class of all UI widgets.
Definition: YWidget.h:54
char shortcut()
The actual shortcut character.
Definition: YShortcut.cc:129
YShortcut(YWidget *shortcut_widget)
Constructor.
Definition: YShortcut.cc:41
static bool isValid(char c)
Returns &#39;true&#39; if &#39;c&#39; is a valid shortcut character, i.e.
Definition: YShortcut.cc:289