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>
00025 #include <X11/keysymdef.h>
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 );
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
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
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
00150 m_iKey = 0;
00151
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
00164
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
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
00226
00227
00228 switch( keySymX ) {
00229
00230
00231
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
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
00246
00247 if( keyNative.sym() == XK_Return && m_iKey > 0 ) {
00248 accept();
00249 return;
00250 }
00251
00252 KKey key = keyNative;
00253 #ifndef NDEBUG
00254
00255
00256
00257
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
00276
00277
00278
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
00287
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
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"