kdeui Library API Documentation

kshortcutdialog.cpp

00001 /* This file is part of the KDE libraries
00002     Copyright (C) 2002,2003 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 "kshortcutdialog.h"
00021 
00022 #include <qvariant.h>
00023 
00024 #ifdef Q_WS_X11
00025     #define XK_XKB_KEYS
00026     #define XK_MISCELLANY
00027     #include <X11/Xlib.h>   // For x11Event()
00028     #include <X11/keysymdef.h> // For XK_...
00029 
00030     #ifdef KeyPress
00031         const int XKeyPress = KeyPress;
00032         const int XKeyRelease = KeyRelease;
00033         const int XFocusOut = FocusOut;
00034         const int XFocusIn = FocusIn;
00035         #undef KeyRelease
00036         #undef KeyPress
00037         #undef FocusOut
00038         #undef FocusIn
00039     #endif
00040 #endif
00041 
00042 #include <kshortcutdialog_simple.h>
00043 #include <kshortcutdialog_advanced.h>
00044 
00045 #include <qbuttongroup.h>
00046 #include <qcheckbox.h>
00047 #include <qframe.h>
00048 #include <qlayout.h>
00049 #include <qradiobutton.h>
00050 #include <qtimer.h>
00051 #include <qvbox.h>
00052 
00053 #include <kapplication.h>
00054 #include <kconfig.h>
00055 #include <kdebug.h>
00056 #include <kglobal.h>
00057 #include <kiconloader.h>
00058 #include <kkeynative.h>
00059 #include <klocale.h>
00060 #include <kstdguiitem.h>
00061 #include <kpushbutton.h>
00062 
00063 bool KShortcutDialog::s_showMore = false;
00064 
00065 KShortcutDialog::KShortcutDialog( const KShortcut& shortcut, bool bQtShortcut, QWidget* parent, const char* name )
00066 : KDialogBase( parent, name, true, i18n("Configure Shortcut"),
00067                KDialogBase::Details|KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Cancel, true )
00068 {
00069         setButtonText(Details, i18n("Advanced"));
00070         m_stack = new QVBox(this);
00071         m_stack->setMinimumWidth(360);
00072         m_stack->setSpacing(0);
00073         m_stack->setMargin(0);
00074         setMainWidget(m_stack);
00075         
00076         m_simple = new KShortcutDialogSimple(m_stack);
00077 
00078         m_adv = new KShortcutDialogAdvanced(m_stack);
00079         m_adv->hide();
00080         
00081     m_bQtShortcut = bQtShortcut;
00082 
00083     m_bGrab = false;
00084     m_iSeq = 0;
00085     m_iKey = 0;
00086     m_ptxtCurrent = 0;
00087     m_bRecording = false;
00088     m_mod = 0;
00089 
00090     m_simple->m_btnClearShortcut->setPixmap( SmallIcon( "locationbar_erase" ) );
00091     m_adv->m_btnClearPrimary->setPixmap( SmallIcon( "locationbar_erase" ) );
00092     m_adv->m_btnClearAlternate->setPixmap( SmallIcon( "locationbar_erase" ) );
00093     connect(m_simple->m_btnClearShortcut, SIGNAL(clicked()),
00094             this, SLOT(slotClearShortcut()));
00095     connect(m_adv->m_btnClearPrimary, SIGNAL(clicked()),
00096             this, SLOT(slotClearPrimary()));
00097     connect(m_adv->m_btnClearAlternate, SIGNAL(clicked()),
00098             this, SLOT(slotClearAlternate()));
00099 
00100     connect(m_adv->m_txtPrimary, SIGNAL(clicked()),
00101         m_adv->m_btnPrimary, SLOT(animateClick()));
00102     connect(m_adv->m_txtAlternate, SIGNAL(clicked()),
00103         m_adv->m_btnAlternate, SLOT(animateClick()));
00104     connect(m_adv->m_btnPrimary, SIGNAL(clicked()),
00105         this, SLOT(slotSelectPrimary()));
00106     connect(m_adv->m_btnAlternate, SIGNAL(clicked()),
00107         this, SLOT(slotSelectAlternate()));
00108 
00109     KGuiItem ok = KStdGuiItem::ok();
00110     ok.setText( i18n( "OK" ) );
00111     setButtonOK( ok );
00112 
00113     KGuiItem cancel = KStdGuiItem::cancel();
00114     cancel.setText( i18n( "Cancel" ) );
00115     setButtonCancel( cancel );
00116 
00117     setShortcut( shortcut );
00118     resize( 0, 0 );
00119 
00120     s_showMore = KConfigGroup(KGlobal::config(), "General").readBoolEntry("ShowAlternativeShortcutConfig", s_showMore);
00121     updateDetails();
00122 
00123     #ifdef Q_WS_X11
00124     kapp->installX11EventFilter( this );    // Allow button to capture X Key Events.
00125     #endif
00126 }
00127 
00128 KShortcutDialog::~KShortcutDialog()
00129 {
00130     KConfigGroup group(KGlobal::config(), "General");
00131     group.writeEntry("ShowAlternativeShortcutConfig", s_showMore);
00132 }
00133 
00134 void KShortcutDialog::setShortcut( const KShortcut & shortcut )
00135 {
00136     m_shortcut = shortcut;
00137     updateShortcutDisplay();
00138 }
00139 
00140 void KShortcutDialog::updateShortcutDisplay()
00141 {
00142     QString s[2] = { m_shortcut.seq(0).toString(), m_shortcut.seq(1).toString() };
00143 
00144     if( m_bRecording ) {
00145         m_ptxtCurrent->setDefault( true );
00146         m_ptxtCurrent->setFocus();
00147 
00148         // Display modifiers for the first key in the KKeySequence
00149         if( m_iKey == 0 ) {
00150             if( m_mod ) {
00151                 QString keyModStr;
00152                 if( m_mod & KKey::WIN )   keyModStr += KKey::modFlagLabel(KKey::WIN) + "+";
00153                 if( m_mod & KKey::ALT )   keyModStr += KKey::modFlagLabel(KKey::ALT) + "+";
00154                 if( m_mod & KKey::CTRL )  keyModStr += KKey::modFlagLabel(KKey::CTRL) + "+";
00155                 if( m_mod & KKey::SHIFT ) keyModStr += KKey::modFlagLabel(KKey::SHIFT) + "+";
00156                 s[m_iSeq] = keyModStr;
00157     }
00158         }
00159         // When in the middle of entering multi-key shortcuts,
00160         //  add a "," to the end of the displayed shortcut.
00161         else
00162             s[m_iSeq] += ",";
00163     }
00164     else {
00165         m_adv->m_txtPrimary->setDefault( false );
00166         m_adv->m_txtAlternate->setDefault( false );
00167         this->setFocus();
00168     }
00169     
00170     s[0].replace('&',"&&");
00171     s[1].replace('&',"&&");
00172 
00173     m_simple->m_txtShortcut->setText( s[0] );
00174     m_adv->m_txtPrimary->setText( s[0] );
00175     m_adv->m_txtAlternate->setText( s[1] );
00176 
00177     // Determine the enable state of the 'Less' button
00178     bool bLessOk;
00179     // If there is no shortcut defined,
00180     if( m_shortcut.count() == 0 )
00181         bLessOk = true;
00182     // If there is a single shortcut defined, and it is not a multi-key shortcut,
00183     else if( m_shortcut.count() == 1 && m_shortcut.seq(0).count() <= 1 )
00184         bLessOk = true;
00185     // Otherwise, we have an alternate shortcut or multi-key shortcut(s).
00186     else
00187         bLessOk = false;
00188     enableButton(Details, bLessOk);
00189 }
00190 
00191 void KShortcutDialog::slotDetails()
00192 {
00193     s_showMore = (m_adv->isHidden());
00194     updateDetails();
00195 }
00196 
00197 void KShortcutDialog::updateDetails()
00198 {
00199     bool showAdvanced = s_showMore || (m_shortcut.count() > 1);
00200     setDetails(showAdvanced);
00201     m_bRecording = false;
00202     m_iSeq = 0;
00203     m_iKey = 0;
00204 
00205     if (showAdvanced)
00206     {
00207         m_simple->hide();
00208         m_adv->show();
00209         m_adv->m_btnPrimary->setChecked( true );
00210         slotSelectPrimary();
00211     }
00212     else
00213     {
00214         m_ptxtCurrent = m_simple->m_txtShortcut;
00215         m_adv->hide();
00216         m_simple->show();
00217         m_simple->m_txtShortcut->setDefault( true );
00218         m_simple->m_txtShortcut->setFocus();
00219         m_adv->m_btnMultiKey->setChecked( false );
00220     }
00221     kapp->processEvents();
00222     adjustSize();
00223 }
00224 
00225 void KShortcutDialog::slotSelectPrimary()
00226 {
00227     m_bRecording = false;
00228     m_iSeq = 0;
00229     m_iKey = 0;
00230     m_ptxtCurrent = m_adv->m_txtPrimary;
00231     m_ptxtCurrent->setDefault(true);
00232     m_ptxtCurrent->setFocus();
00233     updateShortcutDisplay();
00234 }
00235         
00236 void KShortcutDialog::slotSelectAlternate()
00237 {
00238     m_bRecording = false;
00239     m_iSeq = 1;
00240     m_iKey = 0;
00241     m_ptxtCurrent = m_adv->m_txtAlternate;
00242     m_ptxtCurrent->setDefault(true);
00243     m_ptxtCurrent->setFocus();
00244     updateShortcutDisplay();
00245 }
00246 
00247 void KShortcutDialog::slotClearShortcut()
00248 {
00249     m_shortcut.setSeq( 0, KKeySequence() );
00250     updateShortcutDisplay();
00251 }
00252 
00253 void KShortcutDialog::slotClearPrimary()
00254 {
00255     m_shortcut.setSeq( 0, KKeySequence() );
00256     m_adv->m_btnPrimary->setChecked( true );
00257     slotSelectPrimary();
00258 }
00259 
00260 void KShortcutDialog::slotClearAlternate()
00261 {
00262     if( m_shortcut.count() == 2 )
00263         m_shortcut.init( m_shortcut.seq(0) );
00264     m_adv->m_btnAlternate->setChecked( true );
00265     slotSelectAlternate();
00266 }
00267 
00268 void KShortcutDialog::slotMultiKeyMode( bool bOn )
00269 {
00270     // If turning off multi-key mode during a recording,
00271     if( !bOn && m_bRecording ) {
00272         m_bRecording = false;
00273     m_iKey = 0;
00274         updateShortcutDisplay();
00275     }
00276 }
00277 
00278 #ifdef Q_WS_X11
00279 bool KShortcutDialog::x11Event( XEvent *pEvent )
00280 {
00281     switch( pEvent->type ) {
00282         case XKeyPress:
00283             x11KeyPressEvent( pEvent );
00284             return true;
00285         case XKeyRelease:
00286             x11KeyReleaseEvent( pEvent );
00287                 return true;
00288         case XFocusIn:
00289             if (!m_bGrab) {
00290                 //kdDebug(125) << "FocusIn and Grab!" << endl;
00291                 grabKeyboard();
00292                 m_bGrab = true;
00293             }
00294             //else
00295             //  kdDebug(125) << "FocusIn" << endl;
00296             break;
00297         case XFocusOut:
00298             if (m_bGrab) {
00299                 //kdDebug(125) << "FocusOut and Ungrab!" << endl;
00300                 releaseKeyboard();
00301                 m_bGrab = false;
00302             }
00303             //else
00304             //  kdDebug(125) << "FocusOut" << endl;
00305             break;
00306         default:
00307             //kdDebug(125) << "x11Event->type = " << pEvent->type << endl;
00308             break;
00309     }
00310     return KDialogBase::x11Event( pEvent );
00311 }
00312 
00313 static uint getModsFromModX( uint keyModX )
00314 {
00315     uint mod = 0;
00316     if( keyModX & KKeyNative::modX(KKey::SHIFT) ) mod += KKey::SHIFT;
00317     if( keyModX & KKeyNative::modX(KKey::CTRL) )  mod += KKey::CTRL;
00318     if( keyModX & KKeyNative::modX(KKey::ALT) )   mod += KKey::ALT;
00319     if( keyModX & KKeyNative::modX(KKey::WIN) )   mod += KKey::WIN;
00320     return mod;
00321 }
00322 
00323 static bool convertSymXToMod( uint keySymX, uint* pmod )
00324 {
00325     switch( keySymX ) {
00326         // Don't allow setting a modifier key as an accelerator.
00327         // Also, don't release the focus yet.  We'll wait until
00328         //  we get a 'normal' key.
00329         case XK_Shift_L:   case XK_Shift_R:   *pmod = KKey::SHIFT; break;
00330         case XK_Control_L: case XK_Control_R: *pmod = KKey::CTRL; break;
00331         case XK_Alt_L:     case XK_Alt_R:     *pmod = KKey::ALT; break;
00332         // FIXME: check whether the Meta or Super key are for the Win modifier
00333         case XK_Meta_L:    case XK_Meta_R:
00334         case XK_Super_L:   case XK_Super_R:   *pmod = KKey::WIN; break;
00335         case XK_Hyper_L:   case XK_Hyper_R:
00336         case XK_Mode_switch:
00337         case XK_Num_Lock:
00338         case XK_Caps_Lock:
00339             break;
00340         default:
00341             return false;
00342                 }
00343     return true;
00344 }
00345 
00346 void KShortcutDialog::x11KeyPressEvent( XEvent* pEvent )
00347 {
00348     KKeyNative keyNative( pEvent );
00349     uint keyModX = keyNative.mod();
00350     uint keySymX = keyNative.sym();
00351 
00352     m_mod = getModsFromModX( keyModX );
00353 
00354     if( keySymX ) {
00355         m_bRecording = true;
00356 
00357         uint mod = 0;
00358         if( convertSymXToMod( keySymX, &mod ) ) {
00359             if( mod )
00360                 m_mod |= mod;
00361         }
00362         else
00363             keyPressed( KKey(keyNative) );
00364     }
00365     updateShortcutDisplay();
00366 }
00367 
00368 void KShortcutDialog::x11KeyReleaseEvent( XEvent* pEvent )
00369 {
00370     // We're only interested in the release of modifier keys,
00371     //  and then only when it's for the first key in a sequence.
00372     if( m_bRecording && m_iKey == 0 ) {
00373         KKeyNative keyNative( pEvent );
00374         uint keyModX = keyNative.mod();
00375         uint keySymX = keyNative.sym();
00376 
00377         m_mod = getModsFromModX( keyModX );
00378 
00379         uint mod = 0;
00380         if( convertSymXToMod( keySymX, &mod ) && mod ) {
00381             m_mod &= ~mod;
00382             if( !m_mod )
00383                 m_bRecording = false;
00384         }
00385         updateShortcutDisplay();
00386     }
00387 }
00388 
00389 #endif // QT_WS_X11
00390 
00391 void KShortcutDialog::keyPressed( KKey key )
00392 {
00393     kdDebug(125) << "keyPressed: " << key.toString() << endl;
00394 
00395     key.simplify();
00396     if( m_bQtShortcut ) {
00397         key = key.keyCodeQt();
00398         if( key.isNull() ) {
00399             // TODO: message box about key not able to be used as application shortcut
00400         }
00401     }
00402 
00403     KKeySequence seq;
00404     if( m_iKey == 0 )
00405         seq = key;
00406     else {
00407         // Remove modifiers
00408         key.init( key.sym(), 0 );
00409         seq = m_shortcut.seq( m_iSeq );
00410         seq.setKey( m_iKey, key );
00411     }
00412 
00413     m_shortcut.setSeq( m_iSeq, seq );
00414 
00415     m_mod = 0;
00416     if( m_adv->m_btnMultiKey->isChecked() && m_iKey < KKeySequence::MAX_KEYS - 1 )
00417         m_iKey++;
00418     else {
00419         m_iKey = 0;
00420         m_bRecording = false;
00421     }
00422 
00423     updateShortcutDisplay();
00424 
00425     if( !m_adv->m_btnMultiKey->isChecked() )
00426         QTimer::singleShot(500, this, SLOT(accept()));
00427 }
00428 
00429 #include "kshortcutdialog.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jan 22 16:45:17 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003