summaryrefslogtreecommitdiffstats
path: root/kdecore/kshortcut.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdecore/kshortcut.cpp')
-rw-r--r--kdecore/kshortcut.cpp671
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;
+}