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.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:57:40 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001