kdeui Library API Documentation

kshortcutdialog.cpp

00001 #include "kshortcutdialog.h"
00002 
00003 #include <qbuttongroup.h>
00004 #include <qcheckbox.h>
00005 #include <qlayout.h>
00006 #include <qpushbutton.h>
00007 #include <qradiobutton.h>
00008 #include <qsizepolicy.h>
00009 #include <qtooltip.h>
00010 #include <qvbox.h>
00011 
00012 #include <kapplication.h>
00013 #include <kdebug.h>
00014 #include <kglobalaccel.h>
00015 #include <kiconloader.h>
00016 #include <kkeynative.h>
00017 #include <klocale.h>
00018 #include <kpushbutton.h>
00019 #include <kstdguiitem.h>
00020 
00021 #ifdef Q_WS_X11
00022 #define XK_XKB_KEYS
00023 #define XK_MISCELLANY
00024 #include <X11/Xlib.h>   // For x11Event()
00025 #include <X11/keysymdef.h> // For XK_...
00026 
00027 #ifdef KeyPress
00028 const int XFocusOut = FocusOut;
00029 const int XFocusIn = FocusIn;
00030 const int XKeyPress = KeyPress;
00031 const int XKeyRelease = KeyRelease;
00032 #undef KeyRelease
00033 #undef KeyPress
00034 #undef FocusOut
00035 #undef FocusIn
00036 #endif
00037 #endif
00038 
00039 KShortcutBox::KShortcutBox( const KKeySequence& seq, QWidget* parent, const char* name )
00040 :   QLabel( parent, name )
00041 {
00042     setSeq( seq );
00043     setFrameStyle( QFrame::Panel | QFrame::Plain );
00044 }
00045 
00046 void KShortcutBox::setSeq( const KKeySequence& seq )
00047 {
00048     m_seq = seq;
00049     if( !m_seq.isNull() )
00050         setText( seq.toString() );
00051     else
00052         setText( i18n("None") );
00053 }
00054 
00055 KShortcutDialog::KShortcutDialog( const KShortcut& cut, bool bQtShortcut, QWidget* parent, const char* name )
00056 :   KDialog( parent, name ),
00057     m_cut( cut )
00058 {
00059     m_bQtShortcut = bQtShortcut;
00060     m_bGrabKeyboardOnFocusIn = true;
00061     m_bKeyboardGrabbed = false;
00062     m_iSeq = 0;
00063     m_iKey = 0;
00064     initGUI();
00065 
00066 #ifdef Q_WS_X11
00067     kapp->installX11EventFilter( this );    // Allow button to capture X Key Events.
00068 #endif
00069 }
00070 
00071 KShortcutDialog::~KShortcutDialog()
00072 {
00073     if( m_bKeyboardGrabbed ) {
00074         kdDebug(125) << "KShortcutDialog::~KShortcutDialog(): m_bKeyboardGrabbed still true." << endl;
00075         releaseKeyboard();
00076     }
00077 }
00078 
00079 void KShortcutDialog::initGUI()
00080 {
00081     setCaption( i18n("Define Shortcut") );
00082 
00083     QHBoxLayout* pHLayout = new QHBoxLayout( this, KDialog::marginHint() );
00084     QButtonGroup* pGroup = new QButtonGroup( this );
00085     pHLayout->addWidget( pGroup );
00086 
00087     m_prbSeq[0] = new QRadioButton( i18n("Primary"), pGroup );
00088     m_prbSeq[0]->setChecked( true );
00089     connect( m_prbSeq[0], SIGNAL(clicked()), this, SLOT(slotSeq0Selected()) );
00090     QPushButton* pb0 = new QPushButton( pGroup );
00091     pb0->setFlat( true );
00092     pb0->setPixmap( SmallIcon( "locationbar_erase" ) );
00093     QToolTip::add( pb0, i18n("Clear shortcut") );
00094     connect( pb0, SIGNAL(clicked()), this, SLOT(slotClearSeq0()) );
00095     m_peditSeq[0] = new KShortcutBox( m_cut.seq(0), pGroup );
00096     m_pcbMultiKey[0] = new QCheckBox( i18n("Multi-key"), pGroup );
00097     m_pcbMultiKey[0]->setChecked( m_cut.seq(0).count() > 1 );
00098     connect( m_pcbMultiKey[0], SIGNAL(clicked()), this, SLOT(slotSeq0Selected()) );
00099 
00100     m_prbSeq[1] = new QRadioButton( i18n("Alternate"), pGroup );
00101     connect( m_prbSeq[1], SIGNAL(clicked()), this, SLOT(slotSeq1Selected()) );
00102     QPushButton* pb1 = new QPushButton( pGroup );
00103     pb1->setFlat( true );
00104     pb1->setPixmap( SmallIcon( "locationbar_erase" ) );
00105     QToolTip::add( pb1, i18n("Clear shortcut") );
00106     connect( pb1, SIGNAL(clicked()), this, SLOT(slotClearSeq1()) );
00107     m_peditSeq[1] = new KShortcutBox( m_cut.seq(1), pGroup );
00108     m_pcbMultiKey[1] = new QCheckBox( i18n("Multi-key"), pGroup );
00109     m_pcbMultiKey[1]->setChecked( m_cut.seq(1).count() > 1 );
00110     connect( m_pcbMultiKey[1], SIGNAL(clicked()), this, SLOT(slotSeq1Selected()) );
00111 
00112     QGridLayout* pLayout = new QGridLayout( pGroup, 2, 3, KDialog::marginHint(), KDialog::spacingHint() );
00113     pLayout->setColStretch( 2, 1 );
00114     pLayout->addWidget( m_prbSeq[0], 0, 0 );
00115     pLayout->addWidget( pb0, 0, 1 );
00116     pLayout->addWidget( m_peditSeq[0], 0, 2 );
00117     pLayout->addWidget( m_pcbMultiKey[0], 0, 3 );
00118     pLayout->addWidget( m_prbSeq[1], 1, 0 );
00119     pLayout->addWidget( pb1, 1, 1 );
00120     pLayout->addWidget( m_peditSeq[1], 1, 2 );
00121     pLayout->addWidget( m_pcbMultiKey[1], 1, 3 );
00122 
00123     QVBox* pVBox = new QVBox( this );
00124         
00125     // Don't use KStdGuiItem because shown accels would be assigned as shortcut when pressed
00126     KGuiItem ok = KStdGuiItem::ok();
00127     ok.setText( i18n( "OK" ) );
00128     KGuiItem cancel = KStdGuiItem::cancel();
00129     cancel.setText( i18n( "Cancel" ) );
00130     m_pcmdOK = new KPushButton( ok, pVBox );
00131     m_pcmdCancel = new KPushButton( cancel, pVBox );
00132     m_pcbAutoClose = new QCheckBox( i18n("Auto-close"), pVBox );
00133     m_pcbAutoClose->setChecked( true );
00134     // Disable auto-close if the sequence we're editing is a multi-key shortcut.
00135     m_pcbAutoClose->setEnabled( !m_pcbMultiKey[0]->isChecked() );
00136 
00137     connect( m_pcmdOK, SIGNAL(clicked()), this, SLOT(accept()) );
00138     connect( m_pcmdCancel, SIGNAL(clicked()), this, SLOT(reject()) );
00139 
00140     pHLayout->addWidget( pVBox );
00141     m_prbSeq[0]->clearFocus();
00142 }
00143 
00144 void KShortcutDialog::selectSeq( uint i )
00145 {
00146     kdDebug(125) << "KShortcutDialog::selectSeq( " << i << " )" << endl;
00147     m_iSeq = i;
00148     m_prbSeq[m_iSeq]->setChecked( true );
00149     // Start editing at the first key in the sequence.
00150     m_iKey = 0;
00151     // Can't auto-close if editing a multi-key shortcut.
00152     m_pcbAutoClose->setEnabled( !m_pcbMultiKey[m_iSeq]->isChecked() );
00153     m_prbSeq[m_iSeq]->setFocus();
00154 }
00155 
00156 void KShortcutDialog::clearSeq( uint i )
00157 {
00158     kdDebug(125) << "KShortcutDialog::deleteSeq( " << i << " )" << endl;
00159     m_peditSeq[i]->setSeq( KKeySequence::null() );
00160     m_cut.setSeq( i, KKeySequence::null() );
00161     selectSeq( i );
00162 
00163     // If we're clearing the alternate, then we need to set m_cut.count()
00164     //  back to 1 if there is a primary sequence.
00165     if( i == 1 && m_cut.count() > 0 )
00166         m_cut = m_cut.seq(0);
00167 }
00168 
00169 void KShortcutDialog::slotSeq0Selected() { selectSeq( 0 ); }
00170 void KShortcutDialog::slotSeq1Selected() { selectSeq( 1 ); }
00171 void KShortcutDialog::slotClearSeq0()    { clearSeq( 0 ); }
00172 void KShortcutDialog::slotClearSeq1()    { clearSeq( 1 ); }
00173 
00174 void KShortcutDialog::accept()
00175 {
00176     kdDebug(125) << "KShortcutDialog::accept()" << endl;
00177     m_bGrabKeyboardOnFocusIn = false;
00178     m_bKeyboardGrabbed = false;
00179     releaseKeyboard();
00180     KDialog::accept();
00181 }
00182 
00183 #ifdef Q_WS_X11
00184 bool KShortcutDialog::x11Event( XEvent *pEvent )
00185 {
00186     switch( pEvent->type ) {
00187         case XKeyPress:
00188         case XKeyRelease:
00189             if( m_bKeyboardGrabbed ) {
00190                 x11EventKeyPress( pEvent );
00191                 return true;
00192             }
00193             break;
00194         case ButtonPress:
00195             m_iKey = 0;
00196             break;
00197         case XFocusIn:
00198             kdDebug(125) << "FocusIn" << endl;
00199             if( m_bGrabKeyboardOnFocusIn && !m_bKeyboardGrabbed ) {
00200                 kdDebug(125) << "\tkeyboard grabbed." << endl;
00201                 m_bKeyboardGrabbed = true;
00202                 grabKeyboard();
00203             }
00204             break;
00205         case XFocusOut:
00206             kdDebug(125) << "FocusOut" << endl;
00207             if( m_bKeyboardGrabbed ) {
00208                 kdDebug(125) << "\tkeyboard released." << endl;
00209                 m_bKeyboardGrabbed = false;
00210                 releaseKeyboard();
00211             }
00212             break;
00213         default:
00214             //kdDebug(125) << "x11Event->type = " << pEvent->type << endl;
00215             break;
00216     }
00217     return QWidget::x11Event( pEvent );
00218 }
00219 
00220 void KShortcutDialog::x11EventKeyPress( XEvent *pEvent )
00221 {
00222     KKeyNative keyNative( pEvent );
00223     uint keyModX = keyNative.mod(), keySymX = keyNative.sym();
00224 
00225     //kdDebug(125) << QString( "keycode: 0x%1 state: 0x%2\n" )
00226     //          .arg( pEvent->xkey.keycode, 0, 16 ).arg( pEvent->xkey.state, 0, 16 );
00227 
00228     switch( keySymX ) {
00229         // Don't allow setting a modifier key as an accelerator.
00230         // Also, don't release the focus yet.  We'll wait until
00231         //  we get a 'normal' key.
00232         case XK_Shift_L:   case XK_Shift_R:   keyModX = KKeyNative::modX(KKey::SHIFT); break;
00233         case XK_Control_L: case XK_Control_R: keyModX = KKeyNative::modX(KKey::CTRL); break;
00234         case XK_Alt_L:     case XK_Alt_R:     keyModX = KKeyNative::modX(KKey::ALT); break;
00235         // FIXME: check whether the Meta or Super key are for the Win modifier
00236         case XK_Meta_L:    case XK_Meta_R:
00237         case XK_Super_L:   case XK_Super_R:   keyModX = KKeyNative::modX(KKey::WIN); break;
00238         case XK_Hyper_L:   case XK_Hyper_R:
00239         case XK_Mode_switch:
00240         case XK_Num_Lock:
00241         case XK_Caps_Lock:
00242             break;
00243         default:
00244             if( pEvent->type == XKeyPress && keyNative.sym() ) {
00245                 // If RETURN was pressed and we are recording a
00246                 //  multi-key shortcut, then we are done.
00247                 if( keyNative.sym() == XK_Return && m_iKey > 0 ) {
00248                     accept();
00249                     return;
00250                 }
00251 
00252                 KKey key = keyNative;
00253 #ifndef NDEBUG
00254                 //KKey key2 = key;
00255                 //key2.simplify();
00256                 //if( key != key2 )
00257                 //  kdDebug(125) << key.toStringInternal() << " simplified to " << key2.toStringInternal();
00258 #endif
00259                 key.simplify();
00260                 if( m_bQtShortcut )
00261                     key = key.keyCodeQt();
00262                 KKeySequence seq;
00263                 if( m_iKey == 0 )
00264                     seq = key;
00265                 else {
00266                     seq = m_cut.seq( m_iSeq );
00267                     seq.setKey( m_iKey, key );
00268                 }
00269                 m_cut.setSeq( m_iSeq, seq );
00270 
00271                 if( m_pcbMultiKey[m_iSeq]->isChecked() )
00272                     m_iKey++;
00273 
00274                 m_peditSeq[m_iSeq]->setSeq( m_cut.seq(m_iSeq) );
00275                 //captureShortcut( false );
00276                 // The parent must decide whether this is a valid
00277                 //  key, and if so, call setShortcut(uint) with the new value.
00278                 //emit capturedShortcut( KShortcut(KKey(keyNative)) );
00279                 kdDebug(125) << "m_cut = " << m_cut.toString() << " m_bQtShortcut = " << m_bQtShortcut << endl;
00280                 if( m_pcbAutoClose->isEnabled() && m_pcbAutoClose->isChecked() )
00281                     accept();
00282             }
00283             return;
00284     }
00285 
00286     // If we are editing the first key in the sequence,
00287     //  display modifier keys which are held down
00288     if( m_iKey == 0 ) {
00289         if( pEvent->type == XKeyPress )
00290             keyModX |= pEvent->xkey.state;
00291         else
00292             keyModX = pEvent->xkey.state & ~keyModX;
00293 
00294         QString keyModStr;
00295         if( keyModX & KKeyNative::modX(KKey::WIN) ) keyModStr += KKey::modFlagLabel(KKey::WIN) + "+";
00296         if( keyModX & KKeyNative::modX(KKey::ALT) ) keyModStr += KKey::modFlagLabel(KKey::ALT) + "+";
00297         if( keyModX & KKeyNative::modX(KKey::CTRL) )    keyModStr += KKey::modFlagLabel(KKey::CTRL) + "+";
00298         if( keyModX & KKeyNative::modX(KKey::SHIFT) )   keyModStr += KKey::modFlagLabel(KKey::SHIFT) + "+";
00299 
00300         // Display currently selected modifiers, or redisplay old key.
00301         if( !keyModStr.isEmpty() )
00302             m_peditSeq[m_iSeq]->setText( keyModStr );
00303         else
00304             m_peditSeq[m_iSeq]->setSeq( m_cut.seq(m_iSeq) );
00305     }
00306 }
00307 #endif // QT_WS_X11
00308 
00309 void KShortcutDialog::virtual_hook( int id, void* data )
00310 { KDialog::virtual_hook( id, data ); }
00311 
00312 
00313 #include "kshortcutdialog.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:15:05 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001