libyui  3.0.10
/usr/src/RPM/BUILD/libyui-3.0.10/src/YShortcut.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or 
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019   File:         YShortcut.cc
00020 
00021   Author:       Stefan Hundhammer <sh@suse.de>
00022 
00023 /-*/
00024 
00025 
00026 #include <ctype.h>      // toupper(), tolower()
00027 #include <string.h>     // strstr()
00028 
00029 #define YUILogComponent "ui-shortcuts"
00030 #include "YUILog.h"
00031 
00032 #include "YShortcut.h"
00033 #include "YPushButton.h"
00034 #include "YDumbTab.h"
00035 
00036 
00037 // Return the number of elements of an array of any type
00038 #define DIM( ARRAY )    ( (int) ( sizeof( ARRAY)/( sizeof( ARRAY[0] ) ) ) )
00039 
00040 
00041 YShortcut::YShortcut( YWidget * shortcutWidget )
00042     : _widget( shortcutWidget )
00043 {
00044     _preferred                  = -1;
00045     _shortcut                   = -1;
00046     _distinctShortcutChars      = -1;
00047     _conflict                   = false;
00048     _shortcutStringCached       = false;
00049     _cleanShortcutStringCached  = false;
00050 
00051     YPushButton * button = dynamic_cast<YPushButton *>( shortcutWidget);
00052     _isButton = ( button != 0 );
00053 
00054     if ( _isButton )
00055     {
00056         _isWizardButton = strstr( shortcutWidget->widgetClass(), "WizardButton" );
00057 
00058         // yuiDebug() << shortcutWidget <<  ( _isWizardButton ? " is " : " is not " ) << "a wizard button" << endl;
00059     }
00060     else
00061     {
00062         _isWizardButton = 0;
00063     }
00064 
00065     // yuiDebug() << shortcutWidget <<  ( _isButton ? " is " : " is not " ) << "a button" << endl;
00066 }
00067 
00068 
00069 YShortcut::~YShortcut()
00070 {
00071 }
00072 
00073 
00074 std::string
00075 YShortcut::shortcutString()
00076 {
00077     if ( ! _shortcutStringCached )
00078     {
00079         _shortcutString         = getShortcutString();
00080         _shortcutStringCached   = true;
00081 
00082         // Note: We really need a separate variable here - an empty string
00083         // might be a valid value!
00084     }
00085 
00086     return _shortcutString;
00087 }
00088 
00089 
00090 std::string
00091 YShortcut::cleanShortcutString()
00092 {
00093     if ( ! _cleanShortcutStringCached )
00094     {
00095         _cleanShortcutString = cleanShortcutString( shortcutString() );
00096     }
00097 
00098     return _cleanShortcutString;
00099 }
00100 
00101 
00102 std::string
00103 YShortcut::cleanShortcutString( std::string shortcutString )
00104 {
00105     std::string::size_type pos = 0;
00106 
00107     while ( ( pos = findShortcutPos( shortcutString, pos ) ) != std::string::npos )
00108     {
00109         shortcutString.erase( pos, ( std::string::size_type ) 1 );
00110     }
00111 
00112     return shortcutString;
00113 }
00114 
00115 
00116 char
00117 YShortcut::preferred()
00118 {
00119     if ( _preferred < 0 )
00120     {
00121         _preferred = normalized( findShortcut( shortcutString() ) );
00122     }
00123 
00124     return (char) _preferred;
00125 }
00126 
00127 
00128 char
00129 YShortcut::shortcut()
00130 {
00131     if ( _shortcut < 0 )
00132     {
00133         _shortcut = preferred();
00134     }
00135 
00136     return (char) _shortcut;
00137 }
00138 
00139 
00140 void
00141 YShortcut::setShortcut( char newShortcut )
00142 {
00143     std::string str = cleanShortcutString();
00144 
00145     if ( newShortcut != YShortcut::None )
00146     {
00147         char findme[] = { (char)tolower( newShortcut ), (char)toupper( newShortcut ), 0 };
00148         std::string::size_type pos = str.find_first_of( findme );
00149 
00150         if ( pos == std::string::npos )
00151         {
00152             yuiError() << "Can't find '<< " << newShortcut
00153                        << "' in " << widgetClass()
00154                        << " \"" << cleanShortcutString() << "\""
00155                        << std::endl;
00156 
00157             return;
00158         }
00159 
00160         str.insert( pos,
00161                     std::string( 1, shortcutMarker() ) );       // equivalent to 'std::string( "& " )'
00162     }
00163 
00164     widget()->setShortcutString( str );
00165 
00166     _shortcutStringCached       = false;
00167     _cleanShortcutStringCached  = false;
00168     _shortcut = newShortcut;
00169 }
00170 
00171 
00172 void
00173 YShortcut::clearShortcut()
00174 {
00175     setShortcut( YShortcut::None );
00176 }
00177 
00178 
00179 int
00180 YShortcut::distinctShortcutChars()
00181 {
00182     if ( _distinctShortcutChars < 0 )   // cache this value - it's expensive!
00183     {
00184         // Create and initialize "contained" array - what possible shortcut
00185         // characters are contained in that string?
00186 
00187         bool contained[ sizeof(char) << 8 ];
00188 
00189         for ( int i=0; i < DIM( contained ); i++ )
00190             contained[i] = false;
00191 
00192 
00193         // Mark characters as contained
00194 
00195         std::string clean = cleanShortcutString();
00196 
00197         for ( std::string::size_type pos=0; pos < clean.length(); pos++ )
00198         {
00199             if ( YShortcut::isValid( clean[ pos ] ) )
00200                 contained[ (int) clean[ pos ] ] = true;
00201         }
00202 
00203 
00204         // Count number of contained characters
00205 
00206         _distinctShortcutChars=0;
00207 
00208         for ( int i=0; i < DIM( contained ); i++ )
00209         {
00210             if ( contained[i] )
00211             {
00212                 _distinctShortcutChars++;
00213             }
00214         }
00215     }
00216 
00217     return _distinctShortcutChars;
00218 }
00219 
00220 
00221 bool
00222 YShortcut::hasValidShortcutChar()
00223 {
00224     std::string clean = cleanShortcutString();
00225 
00226     for ( std::string::size_type pos=0; pos < clean.length(); pos++ )
00227     {
00228         if ( YShortcut::isValid( clean[ pos ] ) )
00229             return true;
00230     }
00231 
00232     return false;
00233 }
00234 
00235 
00236 std::string
00237 YShortcut::getShortcutString()
00238 {
00239     return getShortcutString( widget() );
00240 }
00241 
00242 
00243 std::string
00244 YShortcut::getShortcutString( const YWidget * widget )
00245 {
00246     if ( ! widget )
00247         return std::string( "" );
00248 
00249     return widget->shortcutString();
00250 }
00251 
00252 
00253 std::string::size_type
00254 YShortcut::findShortcutPos( const std::string & str, std::string::size_type pos )
00255 {
00256     while ( ( pos = str.find( shortcutMarker(), pos ) ) != std::string::npos )
00257     {
00258         if ( pos+1 < str.length() )
00259         {
00260             if ( str[ pos+1 ] == shortcutMarker() )     // escaped marker? ( "&&" )
00261             {
00262                 pos += 2;                               // skip this and search for more
00263             }
00264             else
00265                 return pos;
00266         }
00267         else
00268         {
00269             // A pathological case: The string ends with '& '.
00270             // This is invalid anyway, but prevent endless loop even in this case.
00271             return std::string::npos;
00272         }
00273     }
00274 
00275     return std::string::npos;   // not found
00276 }
00277 
00278 
00279 char
00280 YShortcut::findShortcut( const std::string & str, std::string::size_type pos )
00281 {
00282     pos = findShortcutPos( str, pos );
00283 
00284     return pos == std::string::npos ? (char) 0 : str[ pos+1 ];
00285 }
00286 
00287 
00288 bool
00289 YShortcut::isValid( char c )
00290 {
00291     if ( c >= 'a' && c <= 'z' ) return true;
00292     if ( c >= 'A' && c <= 'Z' ) return true;
00293     if ( c >= '0' && c <= '9' ) return true;
00294     return false;
00295 }
00296 
00297 
00298 char
00299 YShortcut::normalized( char c )
00300 {
00301     if ( c >= 'a' && c <= 'z' ) return c - 'a' + 'A';
00302     if ( c >= 'A' && c <= 'Z' ) return c;
00303     if ( c >= '0' && c <= '9' ) return c;
00304     return (char) 0;
00305 }
00306 
00307 
00308 
00309 std::string
00310 YItemShortcut::getShortcutString()
00311 {
00312     if ( ! _item )
00313         return "";
00314 
00315     return _item->label();
00316 }
00317 
00318 
00319 void
00320 YItemShortcut::setShortcut( char newShortcut )
00321 {
00322     std::string str = cleanShortcutString();
00323 
00324     if ( newShortcut != YShortcut::None )
00325     {
00326         char findme[] = { (char)tolower( newShortcut ), (char)toupper( newShortcut ), 0 };
00327         std::string::size_type pos = str.find_first_of( findme );
00328 
00329         if ( pos == std::string::npos )
00330         {
00331             yuiError() << "Can't find '<< " << newShortcut
00332                        << "' in item "
00333                        << " \"" << cleanShortcutString() << "\""
00334                        << std::endl;
00335 
00336             return;
00337         }
00338 
00339         str.insert( pos,
00340                     std::string( 1, shortcutMarker() ) );       // equivalent to 'std::string( "& " )'
00341     }
00342 
00343     _item->setLabel( str );
00344 
00345     // Notify the parent widget
00346     widget()->setShortcutString( widget()->shortcutString() );
00347 
00348     _shortcutStringCached       = false;
00349     _cleanShortcutStringCached  = false;
00350     _shortcut = newShortcut;
00351 
00352 }
 All Classes Functions Variables Enumerations Friends