diff options
Diffstat (limited to 'kdecore/kshortcut.cpp')
-rw-r--r-- | kdecore/kshortcut.cpp | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/kdecore/kshortcut.cpp b/kdecore/kshortcut.cpp new file mode 100644 index 000000000..4e03b1a2a --- /dev/null +++ b/kdecore/kshortcut.cpp @@ -0,0 +1,671 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kshortcut.h" +#include "kkeynative.h" +#include "kkeyserver.h" + +#include <qevent.h> +#include <qstringlist.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <ksimpleconfig.h> + +//---------------------------------------------------- + +static KKey* g_pspec = 0; +static KKeySequence* g_pseq = 0; +static KShortcut* g_pcut = 0; + +//---------------------------------------------------- +// KKey +//---------------------------------------------------- + +KKey::KKey() { clear(); } +KKey::KKey( uint key, uint modFlags ) { init( key, modFlags ); } +KKey::KKey( int keyQt ) { init( keyQt ); } +KKey::KKey( const QKeySequence& seq ) { init( seq ); } +KKey::KKey( const QKeyEvent* pEvent ) { init( pEvent ); } +KKey::KKey( const KKey& key ) { init( key ); } +KKey::KKey( const QString& sKey ) { init( sKey ); } + +KKey::~KKey() +{ +} + +void KKey::clear() +{ + m_sym = 0; + m_mod = 0; +} + +bool KKey::init( uint key, uint modFlags ) +{ + m_sym = key; + m_mod = modFlags; + return true; +} + +bool KKey::init( int keyQt ) +{ + //KKeyServer::Sym sym; + + //if( sym.initQt( keyQt ) + if( KKeyServer::keyQtToSym( keyQt, m_sym ) + && KKeyServer::keyQtToMod( keyQt, m_mod ) ) + return true; + else { + m_sym = 0; + m_mod = 0; + return false; + } +} + +bool KKey::init( const QKeySequence& key ) +{ + // TODO: if key.count() > 1, should we return failure? + return init( (int) key ); +} + +bool KKey::init( const QKeyEvent* pEvent ) +{ + int keyQt = pEvent->key(); + if( pEvent->state() & Qt::ShiftButton ) keyQt |= Qt::SHIFT; + if( pEvent->state() & Qt::ControlButton ) keyQt |= Qt::CTRL; + if( pEvent->state() & Qt::AltButton ) keyQt |= Qt::ALT; + if( pEvent->state() & Qt::MetaButton ) keyQt |= Qt::META; + return init( keyQt ); +} + +bool KKey::init( const KKey& key ) +{ + m_sym = key.m_sym; + m_mod = key.m_mod; + return true; +} + +bool KKey::init( const QString& sSpec ) +{ + clear(); + + QString sKey = sSpec.stripWhiteSpace(); + if( sKey.startsWith( "default(" ) && sKey.endsWith( ")" ) ) + sKey = sKey.mid( 8, sKey.length() - 9 ); + // i.e., "Ctrl++" = "Ctrl+Plus" + if( sKey.endsWith( "++" ) ) + sKey = sKey.left( sKey.length() - 1 ) + "plus"; + QStringList rgs = QStringList::split( '+', sKey, true ); + + uint i; + // Check for modifier keys first. + for( i = 0; i < rgs.size(); i++ ) { + QString s = rgs[i].lower(); + if( s == "shift" ) m_mod |= KKey::SHIFT; + else if( s == "ctrl" ) m_mod |= KKey::CTRL; + else if( s == "alt" ) m_mod |= KKey::ALT; + else if( s == "win" ) m_mod |= KKey::WIN; + else if( s == "meta" ) m_mod |= KKey::WIN; + else { + uint m = KKeyServer::stringUserToMod( s ); + if( m != 0 ) m_mod |= m; + else break; + } + } + // If there is one non-blank key left: + if( (i == rgs.size() - 1 && !rgs[i].isEmpty()) ) { + KKeyServer::Sym sym( rgs[i] ); + m_sym = sym.m_sym; + } + + if( m_sym == 0 ) + m_mod = 0; + + kdDebug(125) << "KKey::init( \"" << sSpec << "\" ):" + << " m_sym = " << QString::number(m_sym, 16) + << ", m_mod = " << QString::number(m_mod, 16) << endl; + + return m_sym != 0; +} + +bool KKey::isNull() const { return m_sym == 0; } +uint KKey::sym() const { return m_sym; } +uint KKey::modFlags() const { return m_mod; } + +int KKey::compare( const KKey& spec ) const +{ + if( m_sym != spec.m_sym ) + return m_sym - spec.m_sym; + if( m_mod != spec.m_mod ) + return m_mod - spec.m_mod; + return 0; +} + +int KKey::keyCodeQt() const +{ + return KKeyNative( *this ).keyCodeQt(); +} + +QString KKey::toString() const +{ + QString s; + + s = KKeyServer::modToStringUser( m_mod ); + if( !s.isEmpty() ) + s += '+'; + s += KKeyServer::Sym(m_sym).toString(); + + return s; +} + +QString KKey::toStringInternal() const +{ + //kdDebug(125) << "KKey::toStringInternal(): this = " << this + // << " mod = " << QString::number(m_mod, 16) + // << " key = " << QString::number(m_sym, 16) << endl; + QString s; + + s = KKeyServer::modToStringInternal( m_mod ); + if( !s.isEmpty() ) + s += '+'; + s += KKeyServer::Sym(m_sym).toStringInternal(); + return s; +} + +KKey& KKey::null() +{ + if( !g_pspec ) + g_pspec = new KKey; + if( !g_pspec->isNull() ) + g_pspec->clear(); + return *g_pspec; +} + +QString KKey::modFlagLabel( ModFlag modFlag ) +{ + return KKeyServer::modToStringUser( modFlag ); +} + +//--------------------------------------------------------------------- +// KKeySequence +//--------------------------------------------------------------------- + +KKeySequence::KKeySequence() { clear(); } +KKeySequence::KKeySequence( const QKeySequence& seq ) { init( seq ); } +KKeySequence::KKeySequence( const KKey& key ) { init( key ); } +KKeySequence::KKeySequence( const KKeySequence& seq ) { init( seq ); } +KKeySequence::KKeySequence( const QString& s ) { init( s ); } + +KKeySequence::~KKeySequence() +{ +} + +void KKeySequence::clear() +{ + m_nKeys = 0; + m_bTriggerOnRelease = false; +} + +bool KKeySequence::init( const QKeySequence& seq ) +{ + clear(); + if( !seq.isEmpty() ) { + for( uint i = 0; i < seq.count(); i++ ) { + m_rgvar[i].init( seq[i] ); + if( m_rgvar[i].isNull() ) + return false; + } + m_nKeys = seq.count(); + m_bTriggerOnRelease = false; + } + return true; +} + +bool KKeySequence::init( const KKey& key ) +{ + if( !key.isNull() ) { + m_nKeys = 1; + m_rgvar[0].init( key ); + m_bTriggerOnRelease = false; + } else + clear(); + return true; +} + +bool KKeySequence::init( const KKeySequence& seq ) +{ + m_bTriggerOnRelease = false; + m_nKeys = seq.m_nKeys; + for( uint i = 0; i < m_nKeys; i++ ) { + if( seq.m_rgvar[i].isNull() ) { + kdDebug(125) << "KKeySequence::init( seq ): key[" << i << "] is null." << endl; + m_nKeys = 0; + return false; + } + m_rgvar[i] = seq.m_rgvar[i]; + } + return true; +} + +bool KKeySequence::init( const QString& s ) +{ + m_bTriggerOnRelease = false; + //kdDebug(125) << "KKeySequence::init( " << s << " )" << endl; + QStringList rgs = QStringList::split( ',', s ); + if( s == "none" || rgs.size() == 0 ) { + clear(); + return true; + } else if( rgs.size() <= MAX_KEYS ) { + m_nKeys = rgs.size(); + for( uint i = 0; i < m_nKeys; i++ ) { + m_rgvar[i].init( KKey(rgs[i]) ); + //kdDebug(125) << "\t'" << rgs[i] << "' => " << m_rgvar[i].toStringInternal() << endl; + } + return true; + } else { + clear(); + return false; + } +} + +uint KKeySequence::count() const +{ + return m_nKeys; +} + +const KKey& KKeySequence::key( uint i ) const +{ + if( i < m_nKeys ) + return m_rgvar[i]; + else + return KKey::null(); +} + +bool KKeySequence::isTriggerOnRelease() const + { return m_bTriggerOnRelease; } + +bool KKeySequence::setKey( uint iKey, const KKey& key ) +{ + if( iKey <= m_nKeys && iKey < MAX_KEYS ) { + m_rgvar[iKey].init( key ); + if( iKey == m_nKeys ) + m_nKeys++; + return true; + } else + return false; +} + +bool KKeySequence::isNull() const +{ + return m_nKeys == 0; +} + +bool KKeySequence::startsWith( const KKeySequence& seq ) const +{ + if( m_nKeys < seq.m_nKeys ) + return false; + + for( uint i = 0; i < seq.m_nKeys; i++ ) { + if( m_rgvar[i] != seq.m_rgvar[i] ) + return false; + } + + return true; +} + +int KKeySequence::compare( const KKeySequence& seq ) const +{ + for( uint i = 0; i < m_nKeys && i < seq.m_nKeys; i++ ) { + int ret = m_rgvar[i].compare( seq.m_rgvar[i] ); + if( ret != 0 ) + return ret; + } + if( m_nKeys != seq.m_nKeys ) + return m_nKeys - seq.m_nKeys; + else + return 0; +} + +QKeySequence KKeySequence::qt() const +{ + int k[4] = { 0, 0, 0, 0 }; + + for( uint i = 0; i < count(); i++ ) + k[i] = KKeyNative(key(i)).keyCodeQt(); + QKeySequence seq( k[0], k[1], k[2], k[3] ); + return seq; +} + +int KKeySequence::keyCodeQt() const +{ + return (count() == 1) ? KKeyNative(key(0)).keyCodeQt() : 0; +} + +QString KKeySequence::toString() const +{ + if( m_nKeys < 1 ) return QString::null; + + QString s; + s = m_rgvar[0].toString(); + for( uint i = 1; i < m_nKeys; i++ ) { + s += ","; + s += m_rgvar[i].toString(); + } + + return s; +} + +QString KKeySequence::toStringInternal() const +{ + if( m_nKeys < 1 ) return QString::null; + + QString s; + s = m_rgvar[0].toStringInternal(); + for( uint i = 1; i < m_nKeys; i++ ) { + s += ","; + s += m_rgvar[i].toStringInternal(); + } + + return s; +} + +KKeySequence& KKeySequence::null() +{ + if( !g_pseq ) + g_pseq = new KKeySequence; + if( !g_pseq->isNull() ) + g_pseq->clear(); + return *g_pseq; +} + +//--------------------------------------------------------------------- +// KShortcut +//--------------------------------------------------------------------- + +KShortcut::KShortcut() { clear(); } +KShortcut::KShortcut( int keyQt ) { init( keyQt ); } +KShortcut::KShortcut( const QKeySequence& key ) { init( key ); } +KShortcut::KShortcut( const KKey& key ) { init( key ); } +KShortcut::KShortcut( const KKeySequence& seq ) { init( seq ); } +KShortcut::KShortcut( const KShortcut& cut ) { init( cut ); } +KShortcut::KShortcut( const char* ps ) { init( QString(ps) ); } +KShortcut::KShortcut( const QString& s ) { init( s ); } + +KShortcut::~KShortcut() +{ +} + +void KShortcut::clear() +{ + m_nSeqs = 0; +} + +bool KShortcut::init( int keyQt ) +{ + if( keyQt ) { + m_nSeqs = 1; + m_rgseq[0].init( QKeySequence(keyQt) ); + } else + clear(); + return true; +} + +bool KShortcut::init( const QKeySequence& key ) +{ + m_nSeqs = 1; + m_rgseq[0].init( key ); + return true; +} + +bool KShortcut::init( const KKey& spec ) +{ + m_nSeqs = 1; + m_rgseq[0].init( spec ); + return true; +} + +bool KShortcut::init( const KKeySequence& seq ) +{ + m_nSeqs = 1; + m_rgseq[0] = seq; + return true; +} + +bool KShortcut::init( const KShortcut& cut ) +{ + m_nSeqs = cut.m_nSeqs; + for( uint i = 0; i < m_nSeqs; i++ ) + m_rgseq[i] = cut.m_rgseq[i]; + return true; +} + +bool KShortcut::init( const QString& s ) +{ + bool bRet = true; + QStringList rgs = QStringList::split( ';', s ); + + if( s == "none" || rgs.size() == 0 ) + clear(); + else if( rgs.size() <= MAX_SEQUENCES ) { + m_nSeqs = rgs.size(); + for( uint i = 0; i < m_nSeqs; i++ ) { + QString& sSeq = rgs[i]; + if( sSeq.startsWith( "default(" ) ) + sSeq = sSeq.mid( 8, sSeq.length() - 9 ); + m_rgseq[i].init( sSeq ); + //kdDebug(125) << "*\t'" << sSeq << "' => " << m_rgseq[i].toStringInternal() << endl; + } + } else { + clear(); + bRet = false; + } + + if( !s.isEmpty() ) { + QString sDebug; + QTextStream os( &sDebug, IO_WriteOnly ); + os << "KShortcut::init( \"" << s << "\" ): "; + for( uint i = 0; i < m_nSeqs; i++ ) { + os << " m_rgseq[" << i << "]: "; + KKeyServer::Variations vars; + vars.init( m_rgseq[i].key(0), true ); + for( uint j = 0; j < vars.count(); j++ ) + os << QString::number(vars.m_rgkey[j].keyCodeQt(),16) << ','; + } + kdDebug(125) << sDebug << endl; + } + + return bRet; +} + +uint KShortcut::count() const +{ + return m_nSeqs; +} + +const KKeySequence& KShortcut::seq( uint i ) const +{ + return (i < m_nSeqs) ? m_rgseq[i] : KKeySequence::null(); +} + +int KShortcut::keyCodeQt() const +{ + if( m_nSeqs >= 1 ) + return m_rgseq[0].keyCodeQt(); + return QKeySequence(); +} + +bool KShortcut::isNull() const +{ + return m_nSeqs == 0; +} + +int KShortcut::compare( const KShortcut& cut ) const +{ + for( uint i = 0; i < m_nSeqs && i < cut.m_nSeqs; i++ ) { + int ret = m_rgseq[i].compare( cut.m_rgseq[i] ); + if( ret != 0 ) + return ret; + } + return m_nSeqs - cut.m_nSeqs; +} + +bool KShortcut::contains( const KKey& key ) const +{ + return contains( KKeySequence(key) ); +} + +bool KShortcut::contains( const KKeyNative& keyNative ) const +{ + KKey key = keyNative.key(); + key.simplify(); + + for( uint i = 0; i < count(); i++ ) { + if( !m_rgseq[i].isNull() + && m_rgseq[i].count() == 1 + && m_rgseq[i].key(0) == key ) + return true; + } + return false; +} + +bool KShortcut::contains( const KKeySequence& seq ) const +{ + for( uint i = 0; i < count(); i++ ) { + if( !m_rgseq[i].isNull() && m_rgseq[i] == seq ) + return true; + } + return false; +} + +bool KShortcut::setSeq( uint iSeq, const KKeySequence& seq ) +{ + // TODO: check if seq is null, and act accordingly. + if( iSeq <= m_nSeqs && iSeq < MAX_SEQUENCES ) { + m_rgseq[iSeq] = seq; + if( iSeq == m_nSeqs ) + m_nSeqs++; + return true; + } else + return false; +} + +void KShortcut::remove( const KKeySequence& seq ) +{ + if (seq.isNull()) return; + + for( uint iSeq = 0; iSeq < m_nSeqs; iSeq++ ) + { + if (m_rgseq[iSeq] == seq) + { + for( uint jSeq = iSeq + 1; jSeq < m_nSeqs; jSeq++) + m_rgseq[jSeq-1] = m_rgseq[jSeq]; + m_nSeqs--; + } + } +} + +bool KShortcut::append( const KKeySequence& seq ) +{ + if( m_nSeqs < MAX_SEQUENCES ) { + if( !seq.isNull() ) { + m_rgseq[m_nSeqs] = seq; + m_nSeqs++; + } + return true; + } else + return false; +} + +bool KShortcut::append( const KKey& spec ) +{ + if( m_nSeqs < MAX_SEQUENCES ) { + m_rgseq[m_nSeqs].init( spec ); + m_nSeqs++; + return true; + } else + return false; +} + +bool KShortcut::append( const KShortcut& cut ) +{ + uint seqs = m_nSeqs, co = cut.count(); + for( uint i=0; i<co; i++ ) { + if (!contains(cut.seq(i))) seqs++; + } + if( seqs > MAX_SEQUENCES ) return false; + + for( uint i=0; i<co; i++ ) { + const KKeySequence& seq = cut.seq(i); + if(!contains(seq)) { + m_rgseq[m_nSeqs] = seq; + m_nSeqs++; + } + } + return true; +} + +KShortcut::operator QKeySequence () const +{ + if( count() >= 1 ) + return m_rgseq[0].qt(); + else + return QKeySequence(); +} + +QString KShortcut::toString() const +{ + QString s; + + for( uint i = 0; i < count(); i++ ) { + s += m_rgseq[i].toString(); + if( i < count() - 1 ) + s += ';'; + } + + return s; +} + +QString KShortcut::toStringInternal( const KShortcut* pcutDefault ) const +{ + QString s; + + for( uint i = 0; i < count(); i++ ) { + const KKeySequence& seq = m_rgseq[i]; + if( pcutDefault && i < pcutDefault->count() && seq == (*pcutDefault).seq(i) ) { + s += "default("; + s += seq.toStringInternal(); + s += ")"; + } else + s += seq.toStringInternal(); + if( i < count() - 1 ) + s += ';'; + } + + return s; +} + +KShortcut& KShortcut::null() +{ + if( !g_pcut ) + g_pcut = new KShortcut; + if( !g_pcut->isNull() ) + g_pcut->clear(); + return *g_pcut; +} |