libyui  3.10.0
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 using std::string;
41 
42 
43 YShortcut::YShortcut( YWidget * shortcutWidget )
44  : _widget( shortcutWidget )
45 {
46  _preferred = -1;
47  _shortcut = -1;
48  _distinctShortcutChars = -1;
49  _conflict = false;
50  _shortcutStringCached = false;
51  _cleanShortcutStringCached = false;
52 
53  YPushButton * button = dynamic_cast<YPushButton *>( shortcutWidget);
54  _isButton = ( button != 0 );
55 
56  if ( _isButton )
57  {
58  _isWizardButton = strstr( shortcutWidget->widgetClass(), "WizardButton" );
59 
60  // yuiDebug() << shortcutWidget << ( _isWizardButton ? " is " : " is not " ) << "a wizard button" << endl;
61  }
62  else
63  {
64  _isWizardButton = 0;
65  }
66 
67  // yuiDebug() << shortcutWidget << ( _isButton ? " is " : " is not " ) << "a button" << endl;
68 }
69 
70 
72 {
73 }
74 
75 
76 string
78 {
79  if ( ! _shortcutStringCached )
80  {
81  _shortcutString = getShortcutString();
82  _shortcutStringCached = true;
83 
84  // Note: We really need a separate variable here - an empty string
85  // might be a valid value!
86  }
87 
88  return _shortcutString;
89 }
90 
91 
92 string
94 {
95  if ( ! _cleanShortcutStringCached )
96  {
97  _cleanShortcutString = cleanShortcutString( shortcutString() );
98  }
99 
100  return _cleanShortcutString;
101 }
102 
103 
104 string
105 YShortcut::cleanShortcutString( string shortcutString )
106 {
107  string::size_type pos = 0;
108 
109  while ( ( pos = findShortcutPos( shortcutString, pos ) ) != string::npos )
110  {
111  shortcutString.erase( pos, ( string::size_type ) 1 );
112  }
113 
114  return shortcutString;
115 }
116 
117 
118 char
120 {
121  if ( _preferred < 0 )
122  {
123  _preferred = normalized( findShortcut( shortcutString() ) );
124  }
125 
126  return (char) _preferred;
127 }
128 
129 
130 char
132 {
133  if ( _shortcut < 0 )
134  {
135  _shortcut = preferred();
136  }
137 
138  return (char) _shortcut;
139 }
140 
141 
142 void
143 YShortcut::setShortcut( char newShortcut )
144 {
145  string str = cleanShortcutString();
146 
147  if ( newShortcut != YShortcut::None )
148  {
149  char findme[] = { (char)tolower( newShortcut ), (char)toupper( newShortcut ), 0 };
150  string::size_type pos = str.find_first_of( findme );
151 
152  if ( pos == string::npos )
153  {
154  yuiError() << "Can't find '<< " << newShortcut
155  << "' in " << widgetClass()
156  << " \"" << cleanShortcutString() << "\""
157  << endl;
158 
159  return;
160  }
161 
162  str.insert( pos,
163  string( 1, shortcutMarker() ) ); // equivalent to 'string( "& " )'
164  }
165 
166  widget()->setShortcutString( str );
167 
168  _shortcutStringCached = false;
169  _cleanShortcutStringCached = false;
170  _shortcut = newShortcut;
171 }
172 
173 
174 void
176 {
177  setShortcut( YShortcut::None );
178 }
179 
180 
181 int
183 {
184  if ( _distinctShortcutChars < 0 ) // cache this value - it's expensive!
185  {
186  // Create and initialize "contained" array - what possible shortcut
187  // characters are contained in that string?
188 
189  bool contained[ sizeof(char) << 8 ];
190 
191  for ( int i=0; i < DIM( contained ); i++ )
192  contained[i] = false;
193 
194 
195  // Mark characters as contained
196 
197  string clean = cleanShortcutString();
198 
199  for ( string::size_type pos=0; pos < clean.length(); pos++ )
200  {
201  if ( YShortcut::isValid( clean[ pos ] ) )
202  contained[ (int) clean[ pos ] ] = true;
203  }
204 
205 
206  // Count number of contained characters
207 
208  _distinctShortcutChars=0;
209 
210  for ( int i=0; i < DIM( contained ); i++ )
211  {
212  if ( contained[i] )
213  {
214  _distinctShortcutChars++;
215  }
216  }
217  }
218 
219  return _distinctShortcutChars;
220 }
221 
222 
223 bool
225 {
226  string clean = cleanShortcutString();
227 
228  for ( string::size_type pos=0; pos < clean.length(); pos++ )
229  {
230  if ( YShortcut::isValid( clean[ pos ] ) )
231  return true;
232  }
233 
234  return false;
235 }
236 
237 
238 string
240 {
241  return getShortcutString( widget() );
242 }
243 
244 
245 string
247 {
248  if ( ! widget )
249  return string( "" );
250 
251  return widget->shortcutString();
252 }
253 
254 
255 string::size_type
256 YShortcut::findShortcutPos( const string & str, string::size_type pos )
257 {
258  while ( ( pos = str.find( shortcutMarker(), pos ) ) != string::npos )
259  {
260  if ( pos+1 < str.length() )
261  {
262  if ( str[ pos+1 ] == shortcutMarker() ) // escaped marker? ( "&&" )
263  {
264  pos += 2; // skip this and search for more
265  }
266  else
267  return pos;
268  }
269  else
270  {
271  // A pathological case: The string ends with '& '.
272  // This is invalid anyway, but prevent endless loop even in this case.
273  return string::npos;
274  }
275  }
276 
277  return string::npos; // not found
278 }
279 
280 
281 char
282 YShortcut::findShortcut( const string & str, string::size_type pos )
283 {
284  pos = findShortcutPos( str, pos );
285 
286  return pos == string::npos ? (char) 0 : str[ pos+1 ];
287 }
288 
289 
290 bool
292 {
293  if ( c >= 'a' && c <= 'z' ) return true;
294  if ( c >= 'A' && c <= 'Z' ) return true;
295  if ( c >= '0' && c <= '9' ) return true;
296  return false;
297 }
298 
299 
300 char
302 {
303  if ( c >= 'a' && c <= 'z' ) return c - 'a' + 'A';
304  if ( c >= 'A' && c <= 'Z' ) return c;
305  if ( c >= '0' && c <= '9' ) return c;
306  return (char) 0;
307 }
308 
309 
310 
311 string
313 {
314  if ( ! _item )
315  return "";
316 
317  return _item->label();
318 }
319 
320 
321 void
322 YItemShortcut::setShortcut( char newShortcut )
323 {
324  string str = cleanShortcutString();
325 
326  if ( newShortcut != YShortcut::None )
327  {
328  char findme[] = { (char)tolower( newShortcut ), (char)toupper( newShortcut ), 0 };
329  string::size_type pos = str.find_first_of( findme );
330 
331  if ( pos == string::npos )
332  {
333  yuiError() << "Can't find '<< " << newShortcut
334  << "' in item "
335  << " \"" << cleanShortcutString() << "\""
336  << endl;
337 
338  return;
339  }
340 
341  str.insert( pos,
342  string( 1, shortcutMarker() ) ); // equivalent to 'string( "& " )'
343  }
344 
345  _item->setLabel( str );
346 
347  // Notify the parent widget
349 
350  _shortcutStringCached = false;
351  _cleanShortcutStringCached = false;
352  _shortcut = newShortcut;
353 
354 }
YItem::label
std::string label() const
Return this item's label.
Definition: YItem.h:82
YWidget
Abstract base class of all UI widgets.
Definition: YWidget.h:54
YShortcut::shortcutMarker
static char shortcutMarker()
Static function: Returns the character used for marking keyboard shortcuts.
Definition: YShortcut.h:154
YWidget::setShortcutString
virtual void setShortcutString(const std::string &str)
Set the string of this widget that holds the keyboard shortcut, if any.
Definition: YWidget.cc:513
YShortcut::YShortcut
YShortcut(YWidget *shortcut_widget)
Constructor.
Definition: YShortcut.cc:43
YShortcut::~YShortcut
virtual ~YShortcut()
Destructor.
Definition: YShortcut.cc:71
YItemShortcut::setShortcut
virtual void setShortcut(char newShortcut)
Set (override) the shortcut character.
Definition: YShortcut.cc:322
YShortcut::widgetClass
const char * widgetClass() const
Returns the textual representation of the widget class of the widget this shortcut data belongs to.
Definition: YShortcut.h:67
YShortcut::findShortcut
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:282
YShortcut::widget
YWidget * widget() const
Returns the YWidget this shortcut data belong to.
Definition: YShortcut.h:61
YShortcut::setShortcut
virtual void setShortcut(char newShortcut)
Set (override) the shortcut character.
Definition: YShortcut.cc:143
YShortcut::normalized
static char normalized(char c)
Return the normalized version of shortcut character 'c', i.e.
Definition: YShortcut.cc:301
YShortcut::shortcut
char shortcut()
The actual shortcut character.
Definition: YShortcut.cc:131
YItem::setLabel
void setLabel(const std::string &newLabel)
Set this item's label.
Definition: YItem.h:87
YWidget::widgetClass
virtual const char * widgetClass() const
Returns a descriptive name of this widget class for logging, debugging etc.
Definition: YWidget.h:72
YShortcut::clearShortcut
void clearShortcut()
Clear the shortcut: Override the shortcut character with nothing.
Definition: YShortcut.cc:175
YShortcut::isValid
static bool isValid(char c)
Returns 'true' if 'c' is a valid shortcut character, i.e.
Definition: YShortcut.cc:291
YWidget::shortcutString
virtual std::string shortcutString() const
Get the string of this widget that holds the keyboard shortcut, if any.
Definition: YWidget.h:560
YShortcut::shortcutString
std::string shortcutString()
Returns the complete shortcut string (which may or may not contain "&"), i.e.
Definition: YShortcut.cc:77
YShortcut::findShortcutPos
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 ('&') in a string,...
Definition: YShortcut.cc:256
YShortcut::getShortcutString
virtual std::string getShortcutString()
Obtain the the shortcut property of this shortcut's widget - the string that contains "&" to designat...
Definition: YShortcut.cc:239
YShortcut::hasValidShortcutChar
bool hasValidShortcutChar()
Return true if this shortcut contains any character that would be valid as a shortcut character.
Definition: YShortcut.cc:224
YItemShortcut::getShortcutString
virtual std::string getShortcutString()
Obtain the the shortcut property of this shortcut's widget - the string that contains "&" to designat...
Definition: YShortcut.cc:312
YShortcut::distinctShortcutChars
int distinctShortcutChars()
Obtain the number of distinct valid shortcut characters in the shortcut string, i....
Definition: YShortcut.cc:182
YShortcut::preferred
char preferred()
The preferred shortcut character, i.e.
Definition: YShortcut.cc:119
YShortcut::cleanShortcutString
std::string cleanShortcutString()
Returns the shortcut string ( from the widget's shortcut property ) without any "&" markers.
Definition: YShortcut.cc:93
YPushButton
A push button; may have an icon, and a F-key shortcut.
Definition: YPushButton.h:37