kdecore Library API Documentation

kshortcut.cpp

00001 /*  This file is part of the KDE libraries
00002     Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Library General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to
00016     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017     Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #include "kshortcut.h"
00021 #include "kkeynative.h"
00022 #ifdef Q_WS_X11
00023 #include "kkeyserver_x11.h"
00024 #endif
00025 
00026 #include <qevent.h>
00027 #include <qstringlist.h>
00028 
00029 #include <kdebug.h>
00030 #include <kglobal.h>
00031 #include <klocale.h>
00032 #include <ksimpleconfig.h>
00033 
00034 //----------------------------------------------------
00035 
00036 static KKey* g_pspec = 0;
00037 static KKeySequence* g_pseq = 0;
00038 static KShortcut* g_pcut = 0;
00039 
00040 //----------------------------------------------------
00041 // KKey
00042 //----------------------------------------------------
00043 
00044 KKey::KKey()                          { clear(); }
00045 KKey::KKey( uint key, uint modFlags ) { init( key, modFlags ); }
00046 KKey::KKey( int keyQt )               { init( keyQt ); }
00047 KKey::KKey( const QKeySequence& seq ) { init( seq ); }
00048 KKey::KKey( const QKeyEvent* pEvent ) { init( pEvent ); }
00049 KKey::KKey( const KKey& key )         { init( key ); }
00050 KKey::KKey( const QString& sKey )     { init( sKey ); }
00051 
00052 KKey::~KKey()
00053 {
00054 }
00055 
00056 void KKey::clear()
00057 {
00058     m_sym = 0;
00059     m_mod = 0;
00060 }
00061 
00062 bool KKey::init( uint key, uint modFlags )
00063 {
00064     m_sym = key;
00065     m_mod = modFlags;
00066     return true;
00067 }
00068 
00069 bool KKey::init( int keyQt )
00070 {
00071     //KKeyServer::Sym sym;
00072 
00073     //if( sym.initQt( keyQt )
00074     if( KKeyServer::keyQtToSym( keyQt, m_sym )
00075         && KKeyServer::keyQtToMod( keyQt, m_mod ) )
00076         return true;
00077     else {
00078         m_sym = 0;
00079         m_mod = 0;
00080         return false;
00081     }
00082 }
00083 
00084 bool KKey::init( const QKeySequence& key )
00085 {
00086     // TODO: if key.count() > 1, should we return failure?
00087     return init( (int) key );
00088 }
00089 
00090 bool KKey::init( const QKeyEvent* pEvent )
00091 {
00092     int keyQt = pEvent->key();
00093     if( pEvent->state() & Qt::ShiftButton )   keyQt |= Qt::SHIFT;
00094     if( pEvent->state() & Qt::ControlButton ) keyQt |= Qt::CTRL;
00095     if( pEvent->state() & Qt::AltButton )     keyQt |= Qt::ALT;
00096     if( pEvent->state() & Qt::MetaButton )     keyQt |= Qt::META;
00097     return init( keyQt );
00098 }
00099 
00100 bool KKey::init( const KKey& key )
00101 {
00102     m_sym = key.m_sym;
00103     m_mod = key.m_mod;
00104     return true;
00105 }
00106 
00107 bool KKey::init( const QString& sSpec )
00108 {
00109     clear();
00110 
00111     QString sKey = sSpec.stripWhiteSpace();
00112     if( sKey.startsWith( "default(" ) && sKey.endsWith( ")" ) )
00113         sKey = sKey.mid( 8, sKey.length() - 9 );
00114     // i.e., "Ctrl++" = "Ctrl+Plus"
00115     if( sKey.endsWith( "++" ) )
00116         sKey = sKey.left( sKey.length() - 1 ) + "plus";
00117     QStringList rgs = QStringList::split( '+', sKey, true );
00118 
00119     uint i;
00120     // Check for modifier keys first.
00121     for( i = 0; i < rgs.size(); i++ ) {
00122         QString s = rgs[i].lower();
00123         if( s == "shift" )     m_mod |= KKey::SHIFT;
00124         else if( s == "ctrl" ) m_mod |= KKey::CTRL;
00125         else if( s == "alt" )  m_mod |= KKey::ALT;
00126         else if( s == "win" )  m_mod |= KKey::WIN;
00127         else if( s == "meta" ) m_mod |= KKey::WIN;
00128         else break;
00129     }
00130     // If there is one non-blank key left:
00131     if( (i == rgs.size() - 1 && !rgs[i].isEmpty()) ) {
00132         KKeyServer::Sym sym( rgs[i] );
00133         m_sym = sym.m_sym;
00134     }
00135 
00136     if( m_sym == 0 )
00137         m_mod = 0;
00138 
00139     kdDebug(125) << "KKey::init( \"" << sSpec << "\" ):"
00140         << " m_sym = " << QString::number(m_sym, 16)
00141         << ", m_mod = " << QString::number(m_mod, 16) << endl;
00142 
00143     return m_sym != 0;
00144 }
00145 
00146 bool KKey::isNull() const          { return m_sym == 0; }
00147 uint KKey::sym() const             { return m_sym; }
00148 uint KKey::modFlags() const        { return m_mod; }
00149 
00150 int KKey::compare( const KKey& spec ) const
00151 {
00152     if( m_sym != spec.m_sym )
00153         return m_sym - spec.m_sym;
00154     if( m_mod != spec.m_mod )
00155         return m_mod - spec.m_mod;
00156     return 0;
00157 }
00158 
00159 int KKey::keyCodeQt() const
00160 {
00161     return KKeyNative( *this ).keyCodeQt();
00162 }
00163 
00164 QString KKey::toString() const
00165 {
00166     QString s;
00167 
00168     s = KKeyServer::modToStringUser( m_mod );
00169     if( !s.isEmpty() )
00170         s += '+';
00171     s += KKeyServer::Sym(m_sym).toString();
00172 
00173     return s;
00174 }
00175 
00176 QString KKey::toStringInternal() const
00177 {
00178     //kdDebug(125) << "KKey::toStringInternal(): this = " << this
00179     //  << " mod = " << QString::number(m_mod, 16)
00180     //  << " key = " << QString::number(m_sym, 16) << endl;
00181     QString s;
00182 
00183     s = KKeyServer::modToStringInternal( m_mod );
00184     if( !s.isEmpty() )
00185         s += '+';
00186     s += KKeyServer::Sym(m_sym).toStringInternal();
00187     return s;
00188 }
00189 
00190 KKey& KKey::null()
00191 {
00192     if( !g_pspec )
00193         g_pspec = new KKey;
00194     if( !g_pspec->isNull() )
00195         g_pspec->clear();
00196     return *g_pspec;
00197 }
00198 
00199 QString KKey::modFlagLabel( ModFlag modFlag )
00200 {
00201     return KKeyServer::modToStringUser( modFlag );
00202 }
00203 
00204 //---------------------------------------------------------------------
00205 // KKeySequence
00206 //---------------------------------------------------------------------
00207 
00208 KKeySequence::KKeySequence()                          { clear(); }
00209 KKeySequence::KKeySequence( const QKeySequence& seq ) { init( seq ); }
00210 KKeySequence::KKeySequence( const KKey& key )         { init( key ); }
00211 KKeySequence::KKeySequence( const KKeySequence& seq ) { init( seq ); }
00212 KKeySequence::KKeySequence( const QString& s )        { init( s ); }
00213 
00214 KKeySequence::~KKeySequence()
00215 {
00216 }
00217 
00218 void KKeySequence::clear()
00219 {
00220     m_nKeys = 0;
00221     m_bTriggerOnRelease = false;
00222 }
00223 
00224 bool KKeySequence::init( const QKeySequence& seq )
00225 {
00226     clear();
00227 #if QT_VERSION >= 0x030100
00228     if( !seq.isEmpty() ) {
00229         for( uint i = 0; i < seq.count(); i++ ) {
00230             m_rgvar[i].init( seq[i] );
00231             if( m_rgvar[i].isNull() )
00232                 return false;
00233         }
00234         m_nKeys = seq.count();
00235         m_bTriggerOnRelease = false;
00236     }
00237 #else // Qt 3.0.x
00238     if( seq ) {
00239         m_rgvar[ 0 ].init(  seq );
00240         if( !m_rgvar[ 0 ].isNull() ) {
00241             m_nKeys = 1;
00242             m_bTriggerOnRelease = false;
00243         }
00244     }
00245 #endif
00246     return true;
00247 }
00248 
00249 bool KKeySequence::init( const KKey& key )
00250 {
00251     if( !key.isNull() ) {
00252         m_nKeys = 1;
00253         m_rgvar[0].init( key );
00254         m_bTriggerOnRelease = false;
00255     } else
00256         clear();
00257     return true;
00258 }
00259 
00260 bool KKeySequence::init( const KKeySequence& seq )
00261 {
00262     m_bTriggerOnRelease = false;
00263     m_nKeys = seq.m_nKeys;
00264     for( uint i = 0; i < m_nKeys; i++ ) {
00265         if( seq.m_rgvar[i].isNull() ) {
00266             kdDebug(125) << "KKeySequence::init( seq ): key[" << i << "] is null." << endl;
00267             m_nKeys = 0;
00268             return false;
00269         }
00270         m_rgvar[i] = seq.m_rgvar[i];
00271     }
00272     return true;
00273 }
00274 
00275 bool KKeySequence::init( const QString& s )
00276 {
00277     m_bTriggerOnRelease = false;
00278     //kdDebug(125) << "KKeySequence::init( " << s << " )" << endl;
00279     QStringList rgs = QStringList::split( ',', s );
00280     if( s == "none" || rgs.size() == 0 ) {
00281         clear();
00282         return true;
00283     } else if( rgs.size() <= MAX_KEYS ) {
00284         m_nKeys = rgs.size();
00285         for( uint i = 0; i < m_nKeys; i++ ) {
00286             m_rgvar[i].init( KKey(rgs[i]) );
00287             //kdDebug(125) << "\t'" << rgs[i] << "' => " << m_rgvar[i].toStringInternal() << endl;
00288         }
00289         return true;
00290     } else {
00291         clear();
00292         return false;
00293     }
00294 }
00295 
00296 uint KKeySequence::count() const
00297 {
00298     return m_nKeys;
00299 }
00300 
00301 const KKey& KKeySequence::key( uint i ) const
00302 {
00303     if( i < m_nKeys )
00304         return m_rgvar[i];
00305     else
00306         return KKey::null();
00307 }
00308 
00309 bool KKeySequence::isTriggerOnRelease() const
00310     { return m_bTriggerOnRelease; }
00311 
00312 bool KKeySequence::setKey( uint iKey, const KKey& key )
00313 {
00314     if( iKey <= m_nKeys && iKey < MAX_KEYS ) {
00315         m_rgvar[iKey].init( key );
00316         if( iKey == m_nKeys )
00317             m_nKeys++;
00318         return true;
00319     } else
00320         return false;
00321 }
00322 
00323 bool KKeySequence::isNull() const
00324 {
00325     return m_nKeys == 0;
00326 }
00327 
00328 bool KKeySequence::startsWith( const KKeySequence& seq ) const
00329 {
00330     if( m_nKeys < seq.m_nKeys )
00331         return false;
00332 
00333     for( uint i = 0; i < seq.m_nKeys; i++ ) {
00334         if( m_rgvar[i] != seq.m_rgvar[i] )
00335             return false;
00336     }
00337 
00338     return true;
00339 }
00340 
00341 int KKeySequence::compare( const KKeySequence& seq ) const
00342 {
00343     for( uint i = 0; i < m_nKeys && i < seq.m_nKeys; i++ ) {
00344         int ret = m_rgvar[i].compare( seq.m_rgvar[i] );
00345         if( ret != 0 )
00346             return ret;
00347     }
00348     if( m_nKeys != seq.m_nKeys )
00349         return m_nKeys - seq.m_nKeys;
00350     else
00351         return 0;
00352 }
00353 
00354 QKeySequence KKeySequence::qt() const
00355 {
00356     int k[4] = { 0, 0, 0, 0 };
00357     
00358     for( uint i = 0; i < count(); i++ )
00359         k[i] = KKeyNative(key(i)).keyCodeQt();
00360 #if QT_VERSION >= 0x030100
00361     QKeySequence seq( k[0], k[1], k[2], k[3] );
00362 #else // Qt-3.0.x
00363     QKeySequence seq;
00364     if(  count() == 1 )
00365         seq = KKeyNative( key( 0 ) ).keyCodeQt();
00366 #endif
00367     return seq;
00368 }
00369 
00370 int KKeySequence::keyCodeQt() const
00371 {
00372     return (count() == 1) ? KKeyNative(key(0)).keyCodeQt() : 0;
00373 }
00374 
00375 QString KKeySequence::toString() const
00376 {
00377     if( m_nKeys < 1 ) return QString::null;
00378 
00379     QString s;
00380     s = m_rgvar[0].toString();
00381     for( uint i = 1; i < m_nKeys; i++ ) {
00382         s += ",";
00383         s += m_rgvar[i].toString();
00384     }
00385 
00386     return s;
00387 }
00388 
00389 QString KKeySequence::toStringInternal() const
00390 {
00391     if( m_nKeys < 1 ) return QString::null;
00392 
00393     QString s;
00394     s = m_rgvar[0].toStringInternal();
00395     for( uint i = 1; i < m_nKeys; i++ ) {
00396         s += ",";
00397         s += m_rgvar[i].toStringInternal();
00398     }
00399 
00400     return s;
00401 }
00402 
00403 KKeySequence& KKeySequence::null()
00404 {
00405     if( !g_pseq )
00406         g_pseq = new KKeySequence;
00407     if( !g_pseq->isNull() )
00408         g_pseq->clear();
00409     return *g_pseq;
00410 }
00411 
00412 //---------------------------------------------------------------------
00413 // KShortcut
00414 //---------------------------------------------------------------------
00415 
00416 KShortcut::KShortcut()                            { clear(); }
00417 KShortcut::KShortcut( int keyQt )                 { init( keyQt ); }
00418 KShortcut::KShortcut( const QKeySequence& key )   { init( key ); }
00419 KShortcut::KShortcut( const KKey& key )           { init( key ); }
00420 KShortcut::KShortcut( const KKeySequence& seq )   { init( seq ); }
00421 KShortcut::KShortcut( const KShortcut& cut )      { init( cut ); }
00422 KShortcut::KShortcut( const char* ps )            { init( QString(ps) ); }
00423 KShortcut::KShortcut( const QString& s )          { init( s ); }
00424 
00425 KShortcut::~KShortcut()
00426 {
00427 }
00428 
00429 void KShortcut::clear()
00430 {
00431     m_nSeqs = 0;
00432 }
00433 
00434 bool KShortcut::init( int keyQt )
00435 {
00436     if( keyQt ) {
00437         m_nSeqs = 1;
00438         m_rgseq[0].init( QKeySequence(keyQt) );
00439     } else
00440         clear();
00441     return true;
00442 }
00443 
00444 bool KShortcut::init( const QKeySequence& key )
00445 {
00446     m_nSeqs = 1;
00447     m_rgseq[0].init( key );
00448     return true;
00449 }
00450 
00451 bool KShortcut::init( const KKey& spec )
00452 {
00453     m_nSeqs = 1;
00454     m_rgseq[0].init( spec );
00455     return true;
00456 }
00457 
00458 bool KShortcut::init( const KKeySequence& seq )
00459 {
00460     m_nSeqs = 1;
00461     m_rgseq[0] = seq;
00462     return true;
00463 }
00464 
00465 bool KShortcut::init( const KShortcut& cut )
00466 {
00467     m_nSeqs = cut.m_nSeqs;
00468     for( uint i = 0; i < m_nSeqs; i++ )
00469         m_rgseq[i] = cut.m_rgseq[i];
00470     return true;
00471 }
00472 
00473 bool KShortcut::init( const QString& s )
00474 {
00475     bool bRet = true;
00476     QStringList rgs = QStringList::split( ';', s );
00477 
00478     if( s == "none" || rgs.size() == 0 )
00479         clear();
00480     else if( rgs.size() <= MAX_SEQUENCES ) {
00481         m_nSeqs = rgs.size();
00482         for( uint i = 0; i < m_nSeqs; i++ ) {
00483             QString& sSeq = rgs[i];
00484             if( sSeq.startsWith( "default(" ) )
00485                 sSeq = sSeq.mid( 8, sSeq.length() - 9 );
00486             m_rgseq[i].init( sSeq );
00487             //kdDebug(125) << "*\t'" << sSeq << "' => " << m_rgseq[i].toStringInternal() << endl;
00488         }
00489     } else {
00490         clear();
00491         bRet = false;
00492     }
00493 
00494     if( !s.isEmpty() ) {
00495         QString sDebug;
00496         QTextStream os( &sDebug, IO_WriteOnly );
00497         os << "KShortcut::init( \"" << s << "\" ): ";
00498         for( uint i = 0; i < m_nSeqs; i++ ) {
00499             os << " m_rgseq[" << i << "]: ";
00500             KKeyServer::Variations vars;
00501             vars.init( m_rgseq[i].key(0), true );
00502             for( uint j = 0; j < vars.count(); j++ )
00503                 os << QString::number(vars.m_rgkey[j].keyCodeQt(),16) << ',';
00504         }
00505         kdDebug(125) << sDebug << endl;
00506     }
00507 
00508     return bRet;
00509 }
00510 
00511 uint KShortcut::count() const
00512 {
00513     return m_nSeqs;
00514 }
00515 
00516 const KKeySequence& KShortcut::seq( uint i ) const
00517 {
00518     return (i < m_nSeqs) ? m_rgseq[i] : KKeySequence::null();
00519 }
00520 
00521 int KShortcut::keyCodeQt() const
00522 {
00523     if( m_nSeqs >= 1 )
00524         return m_rgseq[0].keyCodeQt();
00525     return QKeySequence();
00526 }
00527 
00528 bool KShortcut::isNull() const
00529 {
00530     return m_nSeqs == 0;
00531 }
00532 
00533 int KShortcut::compare( const KShortcut& cut ) const
00534 {
00535     for( uint i = 0; i < m_nSeqs && i < cut.m_nSeqs; i++ ) {
00536         int ret = m_rgseq[i].compare( cut.m_rgseq[i] );
00537         if( ret != 0 )
00538             return ret;
00539     }
00540     return m_nSeqs - cut.m_nSeqs;
00541 }
00542 
00543 bool KShortcut::contains( const KKey& key ) const
00544 {
00545     return contains( KKeySequence(key) );
00546 }
00547 
00548 bool KShortcut::contains( const KKeyNative& keyNative ) const
00549 {
00550     KKey key = keyNative.key();
00551     key.simplify();
00552 
00553     for( uint i = 0; i < count(); i++ ) {
00554         if( !m_rgseq[i].isNull()
00555             && m_rgseq[i].count() == 1
00556             && m_rgseq[i].key(0) == key )
00557             return true;
00558     }
00559     return false;
00560 }
00561 
00562 bool KShortcut::contains( const KKeySequence& seq ) const
00563 {
00564     for( uint i = 0; i < count(); i++ ) {
00565         if( !m_rgseq[i].isNull() && m_rgseq[i] == seq )
00566             return true;
00567     }
00568     return false;
00569 }
00570 
00571 bool KShortcut::setSeq( uint iSeq, const KKeySequence& seq )
00572 {
00573     // TODO: check if seq is null, and act accordingly.
00574     if( iSeq <= m_nSeqs && iSeq < MAX_SEQUENCES ) {
00575         m_rgseq[iSeq] = seq;
00576         if( iSeq == m_nSeqs )
00577             m_nSeqs++;
00578         return true;
00579     } else
00580         return false;
00581 }
00582 
00583 void KShortcut::remove( const KKeySequence& seq )
00584 {
00585     if (seq.isNull()) return;
00586     
00587     for( uint iSeq = 0; iSeq < m_nSeqs; iSeq++ )
00588     {
00589         if (m_rgseq[iSeq] == seq)
00590         {
00591             for( uint jSeq = iSeq + 1; jSeq < m_nSeqs; jSeq++)
00592                 m_rgseq[jSeq-1] = m_rgseq[jSeq];
00593             m_nSeqs--;
00594         }
00595     }
00596 }
00597 
00598 bool KShortcut::append( const KKeySequence& seq )
00599 {
00600     if( m_nSeqs < MAX_SEQUENCES ) {
00601         if( !seq.isNull() ) {
00602             m_rgseq[m_nSeqs] = seq;
00603             m_nSeqs++;
00604         }
00605         return true;
00606     } else
00607         return false;
00608 }
00609 
00610 bool KShortcut::append( const KKey& spec )
00611 {
00612     if( m_nSeqs < MAX_SEQUENCES ) {
00613         m_rgseq[m_nSeqs].init( spec );
00614         m_nSeqs++;
00615         return true;
00616     } else
00617         return false;
00618 }
00619 
00620 bool KShortcut::append( const KShortcut& cut )
00621 {
00622     uint seqs = m_nSeqs, co = cut.count();
00623     for( uint i=0; i<co; i++ ) {
00624         if (!contains(cut.seq(i))) seqs++;
00625     }
00626     if( seqs > MAX_SEQUENCES ) return false;
00627 
00628     for( uint i=0; i<co; i++ ) {
00629         const KKeySequence& seq = cut.seq(i);
00630         if(!contains(seq)) {
00631             m_rgseq[m_nSeqs] = seq;
00632             m_nSeqs++;
00633         }
00634     }
00635     return true;
00636 }
00637 
00638 KShortcut::operator QKeySequence () const
00639 {
00640     if( count() >= 1 )
00641         return m_rgseq[0].qt();
00642     else
00643         return QKeySequence();
00644 }
00645 
00646 QString KShortcut::toString() const
00647 {
00648     QString s;
00649 
00650     for( uint i = 0; i < count(); i++ ) {
00651         s += m_rgseq[i].toString();
00652         if( i < count() - 1 )
00653             s += ';';
00654     }
00655 
00656     return s;
00657 }
00658 
00659 QString KShortcut::toStringInternal( const KShortcut* pcutDefault ) const
00660 {
00661     QString s;
00662 
00663     for( uint i = 0; i < count(); i++ ) {
00664         const KKeySequence& seq = m_rgseq[i];
00665         if( pcutDefault && i < pcutDefault->count() && seq == (*pcutDefault).seq(i) ) {
00666             s += "default(";
00667             s += seq.toStringInternal();
00668             s += ")";
00669         } else
00670             s += seq.toStringInternal();
00671         if( i < count() - 1 )
00672             s += ';';
00673     }
00674 
00675     return s;
00676 }
00677 
00678 KShortcut& KShortcut::null()
00679 {
00680     if( !g_pcut )
00681         g_pcut = new KShortcut;
00682     if( !g_pcut->isNull() )
00683         g_pcut->clear();
00684     return *g_pcut;
00685 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 23 17:11:37 2004 by doxygen 1.3.8-20040913 written by Dimitri van Heesch, © 1997-2003