00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kaccel.h"
00021
00022 #include <qaccel.h>
00023 #include <qguardedptr.h>
00024 #include <qpopupmenu.h>
00025 #include <qstring.h>
00026 #include <qtimer.h>
00027
00028 #include "kaccelbase.h"
00029 #include <kapplication.h>
00030 #include <kdebug.h>
00031 #include <klocale.h>
00032 #include <kshortcut.h>
00033
00034 #include "kaccelprivate.h"
00035
00036 #ifdef Q_WS_X11
00037 # include <X11/Xlib.h>
00038 # ifdef KeyPress // needed for --enable-final
00039
00040 const int XKeyPress = KeyPress;
00041 # undef KeyPress
00042 # endif
00043 #endif
00044
00045
00046
00047
00048
00049
00050 bool kde_g_bKillAccelOverride = false;
00051
00052 class KAccelEventHandler : public QWidget
00053 {
00054 public:
00055 static KAccelEventHandler* self()
00056 {
00057 if( !g_pSelf )
00058 g_pSelf = new KAccelEventHandler;
00059 return g_pSelf;
00060 }
00061
00062 static void accelActivated( bool b ) { g_bAccelActivated = b; }
00063
00064 private:
00065 KAccelEventHandler();
00066
00067 # ifdef Q_WS_X11
00068 bool x11Event( XEvent* pEvent );
00069 # endif
00070
00071 static KAccelEventHandler* g_pSelf;
00072 static bool g_bAccelActivated;
00073 };
00074
00075 KAccelEventHandler* KAccelEventHandler::g_pSelf = 0;
00076 bool KAccelEventHandler::g_bAccelActivated = false;
00077
00078 KAccelEventHandler::KAccelEventHandler()
00079 {
00080 # ifdef Q_WS_X11
00081 if ( kapp )
00082 kapp->installX11EventFilter( this );
00083 # endif
00084 }
00085
00086 #ifdef Q_WS_X11
00087 bool qt_try_modal( QWidget *, XEvent * );
00088
00089 bool KAccelEventHandler::x11Event( XEvent* pEvent )
00090 {
00091 if( QWidget::keyboardGrabber() || !kapp->focusWidget() )
00092 return false;
00093
00094 if ( !qt_try_modal(kapp->focusWidget(), pEvent) )
00095 return false;
00096
00097 if( pEvent->type == XKeyPress ) {
00098 unsigned int tmp = pEvent->xkey.state;
00099 pEvent->xkey.state &= ~0x2000;
00100 KKeyNative keyNative( pEvent );
00101 pEvent->xkey.state = tmp;
00102 KKey key( keyNative );
00103 key.simplify();
00104 int keyCodeQt = key.keyCodeQt();
00105 int state = 0;
00106 if( key.modFlags() & KKey::SHIFT ) state |= Qt::ShiftButton;
00107 if( key.modFlags() & KKey::CTRL ) state |= Qt::ControlButton;
00108 if( key.modFlags() & KKey::ALT ) state |= Qt::AltButton;
00109 if( key.modFlags() & KKey::WIN ) state |= Qt::MetaButton;
00110
00111 QKeyEvent ke( QEvent::AccelOverride, keyCodeQt, 0, state );
00112 ke.ignore();
00113
00114 g_bAccelActivated = false;
00115 kapp->sendEvent( kapp->focusWidget(), &ke );
00116
00117
00118
00119 if( ke.isAccepted() && !g_bAccelActivated )
00120 kde_g_bKillAccelOverride = true;
00121
00122
00123 return g_bAccelActivated;
00124 }
00125
00126 return false;
00127 }
00128 #endif // Q_WS_X11
00129
00130
00131
00132
00133
00134 KAccelPrivate::KAccelPrivate( KAccel* pParent, QWidget* pWatch )
00135 : KAccelBase( KAccelBase::QT_KEYS )
00136 {
00137
00138 m_pAccel = pParent;
00139 m_pWatch = pWatch;
00140 m_bAutoUpdate = true;
00141 connect( (QAccel*)m_pAccel, SIGNAL(activated(int)), this, SLOT(slotKeyPressed(int)) );
00142
00143 if( m_pWatch )
00144 m_pWatch->installEventFilter( this );
00145 KAccelEventHandler::self();
00146 }
00147
00148 void KAccelPrivate::setEnabled( bool bEnabled )
00149 {
00150 m_bEnabled = bEnabled;
00151 ((QAccel*)m_pAccel)->setEnabled( bEnabled );
00152 }
00153
00154 bool KAccelPrivate::setEnabled( const QString& sAction, bool bEnable )
00155 {
00156 kdDebug(125) << "KAccelPrivate::setEnabled( \"" << sAction << "\", " << bEnable << " ): this = " << this << endl;
00157 KAccelAction* pAction = actionPtr( sAction );
00158 if( !pAction )
00159 return false;
00160 if( pAction->isEnabled() == bEnable )
00161 return true;
00162
00163 pAction->setEnabled( bEnable );
00164
00165 QMap<int, KAccelAction*>::iterator it = m_mapIDToAction.begin();
00166 for( ; it != m_mapIDToAction.end(); ++it ) {
00167 if( *it == pAction )
00168 ((QAccel*)m_pAccel)->setItemEnabled( it.key(), bEnable );
00169 }
00170 return true;
00171 }
00172
00173 bool KAccelPrivate::removeAction( const QString& sAction )
00174 {
00175
00176
00177
00178 KAccelAction* pAction = actions().actionPtr( sAction );
00179 if( pAction ) {
00180 int nID = pAction->getID();
00181
00182 bool b = KAccelBase::remove( sAction );
00183 ((QAccel*)m_pAccel)->removeItem( nID );
00184 return b;
00185 } else
00186 return false;
00187 }
00188
00189 bool KAccelPrivate::emitSignal( KAccelBase::Signal signal )
00190 {
00191 if( signal == KAccelBase::KEYCODE_CHANGED ) {
00192 m_pAccel->emitKeycodeChanged();
00193 return true;
00194 }
00195 return false;
00196 }
00197
00198 bool KAccelPrivate::connectKey( KAccelAction& action, const KKeyServer::Key& key )
00199 {
00200 uint keyQt = key.keyCodeQt();
00201 int nID = ((QAccel*)m_pAccel)->insertItem( keyQt );
00202 m_mapIDToAction[nID] = &action;
00203 m_mapIDToKey[nID] = keyQt;
00204
00205 if( action.objSlotPtr() && action.methodSlotPtr() ) {
00206 ((QAccel*)m_pAccel)->connectItem( nID, action.objSlotPtr(), action.methodSlotPtr() );
00207 if( !action.isEnabled() )
00208 ((QAccel*)m_pAccel)->setItemEnabled( nID, false );
00209 }
00210
00211 kdDebug(125) << "KAccelPrivate::connectKey( \"" << action.name() << "\", " << key.key().toStringInternal() << " = 0x" << QString::number(keyQt,16) << " ): id = " << nID << " m_pObjSlot = " << action.objSlotPtr() << endl;
00212
00213 return nID != 0;
00214 }
00215
00216 bool KAccelPrivate::connectKey( const KKeyServer::Key& key )
00217 {
00218 uint keyQt = key.keyCodeQt();
00219 int nID = ((QAccel*)m_pAccel)->insertItem( keyQt );
00220
00221 m_mapIDToKey[nID] = keyQt;
00222
00223 kdDebug(125) << "KAccelPrivate::connectKey( " << key.key().toStringInternal() << " = 0x" << QString::number(keyQt,16) << " ): id = " << nID << endl;
00224 return nID != 0;
00225 }
00226
00227 bool KAccelPrivate::disconnectKey( KAccelAction& action, const KKeyServer::Key& key )
00228 {
00229 int keyQt = key.keyCodeQt();
00230 QMap<int, int>::iterator it = m_mapIDToKey.begin();
00231 for( ; it != m_mapIDToKey.end(); ++it ) {
00232
00233 if( *it == keyQt ) {
00234 int nID = it.key();
00235 kdDebug(125) << "KAccelPrivate::disconnectKey( \"" << action.name() << "\", 0x" << QString::number(keyQt,16) << " ) : id = " << nID << " m_pObjSlot = " << action.objSlotPtr() << endl;
00236 ((QAccel*)m_pAccel)->removeItem( nID );
00237 m_mapIDToAction.remove( nID );
00238 m_mapIDToKey.remove( it );
00239 return true;
00240 }
00241 }
00242
00243 kdWarning(125) << "Didn't find key in m_mapIDToKey." << endl;
00244 return false;
00245 }
00246
00247 bool KAccelPrivate::disconnectKey( const KKeyServer::Key& key )
00248 {
00249 int keyQt = key.keyCodeQt();
00250 kdDebug(125) << "KAccelPrivate::disconnectKey( 0x" << QString::number(keyQt,16) << " )" << endl;
00251 QMap<int, int>::iterator it = m_mapIDToKey.begin();
00252 for( ; it != m_mapIDToKey.end(); ++it ) {
00253 if( *it == keyQt ) {
00254 ((QAccel*)m_pAccel)->removeItem( it.key() );
00255 m_mapIDToKey.remove( it );
00256 return true;
00257 }
00258 }
00259
00260 kdWarning(125) << "Didn't find key in m_mapIDTokey." << endl;
00261 return false;
00262 }
00263
00264 void KAccelPrivate::slotKeyPressed( int id )
00265 {
00266 kdDebug(125) << "KAccelPrivate::slotKeyPressed( " << id << " )" << endl;
00267
00268 if( m_mapIDToKey.contains( id ) ) {
00269 KKey key = m_mapIDToKey[id];
00270 KKeySequence seq( key );
00271 QPopupMenu* pMenu = createPopupMenu( m_pWatch, seq );
00272
00273
00274
00275
00276
00277
00278
00279 if( pMenu->count() == 2 && static_cast<int>( pMenu->accel(1) ) == 0 ) {
00280 int iAction = pMenu->idAt(1);
00281 slotMenuActivated( iAction );
00282 } else {
00283 connect( pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuActivated(int)) );
00284 pMenu->exec( m_pWatch->mapToGlobal( QPoint( 0, 0 ) ) );
00285 disconnect( pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuActivated(int)) );
00286 }
00287 delete pMenu;
00288 }
00289 }
00290
00291 void KAccelPrivate::slotShowMenu()
00292 {
00293 }
00294
00295 void KAccelPrivate::slotMenuActivated( int iAction )
00296 {
00297 kdDebug(125) << "KAccelPrivate::slotMenuActivated( " << iAction << " )" << endl;
00298 KAccelAction* pAction = actions().actionPtr( iAction );
00299 if( pAction ) {
00300 connect( this, SIGNAL(menuItemActivated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00301 emit menuItemActivated();
00302 disconnect( this, SIGNAL(menuItemActivated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00303 }
00304 }
00305
00306 bool KAccelPrivate::eventFilter( QObject* , QEvent* pEvent )
00307 {
00308 if( pEvent->type() == QEvent::AccelOverride && m_bEnabled ) {
00309 QKeyEvent* pKeyEvent = (QKeyEvent*) pEvent;
00310 KKey key( pKeyEvent );
00311 kdDebug(125) << "KAccelPrivate::eventFilter( AccelOverride ): this = " << this << ", key = " << key.toStringInternal() << endl;
00312 int keyCodeQt = key.keyCodeQt();
00313 QMap<int, int>::iterator it = m_mapIDToKey.begin();
00314 for( ; it != m_mapIDToKey.end(); ++it ) {
00315 if( (*it) == keyCodeQt ) {
00316 int nID = it.key();
00317 kdDebug(125) << "shortcut found!" << endl;
00318 if( m_mapIDToAction.contains( nID ) ) {
00319
00320 KAccelAction* pAction = m_mapIDToAction[nID];
00321 if( !pAction->isEnabled() )
00322 continue;
00323 QGuardedPtr<KAccelPrivate> me = this;
00324 connect( this, SIGNAL(menuItemActivated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00325 emit menuItemActivated();
00326 if (me) {
00327 disconnect( me, SIGNAL(menuItemActivated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00328 }
00329 } else
00330 slotKeyPressed( nID );
00331
00332 pKeyEvent->accept();
00333 KAccelEventHandler::accelActivated( true );
00334 return true;
00335 }
00336 }
00337 }
00338 return false;
00339 }
00340
00341
00342
00343
00344
00345 KAccel::KAccel( QWidget* pParent, const char* psName )
00346 : QAccel( pParent, (psName) ? psName : "KAccel-QAccel" )
00347 {
00348 kdDebug(125) << "KAccel( pParent = " << pParent << ", psName = " << psName << " ): this = " << this << endl;
00349 d = new KAccelPrivate( this, pParent );
00350 }
00351
00352 KAccel::KAccel( QWidget* watch, QObject* pParent, const char* psName )
00353 : QAccel( watch, pParent, (psName) ? psName : "KAccel-QAccel" )
00354 {
00355 kdDebug(125) << "KAccel( watch = " << watch << ", pParent = " << pParent << ", psName = " << psName << " ): this = " << this << endl;
00356 if( !watch )
00357 kdDebug(125) << kdBacktrace() << endl;
00358 d = new KAccelPrivate( this, watch );
00359 }
00360
00361 KAccel::~KAccel()
00362 {
00363 kdDebug(125) << "~KAccel(): this = " << this << endl;
00364 delete d;
00365 }
00366
00367 KAccelActions& KAccel::actions() { return d->actions(); }
00368 const KAccelActions& KAccel::actions() const { return d->actions(); }
00369 bool KAccel::isEnabled() { return d->isEnabled(); }
00370 void KAccel::setEnabled( bool bEnabled ) { d->setEnabled( bEnabled ); }
00371 bool KAccel::setAutoUpdate( bool bAuto ) { return d->setAutoUpdate( bAuto ); }
00372
00373 KAccelAction* KAccel::insert( const QString& sAction, const QString& sLabel, const QString& sWhatsThis,
00374 const KShortcut& cutDef,
00375 const QObject* pObjSlot, const char* psMethodSlot,
00376 bool bConfigurable, bool bEnabled )
00377 {
00378 return d->insert( sAction, sLabel, sWhatsThis,
00379 cutDef, cutDef,
00380 pObjSlot, psMethodSlot,
00381 bConfigurable, bEnabled );
00382 }
00383
00384 KAccelAction* KAccel::insert( const QString& sAction, const QString& sLabel, const QString& sWhatsThis,
00385 const KShortcut& cutDef3, const KShortcut& cutDef4,
00386 const QObject* pObjSlot, const char* psMethodSlot,
00387 bool bConfigurable, bool bEnabled )
00388 {
00389 return d->insert( sAction, sLabel, sWhatsThis,
00390 cutDef3, cutDef4,
00391 pObjSlot, psMethodSlot,
00392 bConfigurable, bEnabled );
00393 }
00394
00395 KAccelAction* KAccel::insert( const char* psAction, const KShortcut& cutDef,
00396 const QObject* pObjSlot, const char* psMethodSlot,
00397 bool bConfigurable, bool bEnabled )
00398 {
00399 return d->insert( psAction, i18n(psAction), QString::null,
00400 cutDef, cutDef,
00401 pObjSlot, psMethodSlot,
00402 bConfigurable, bEnabled );
00403 }
00404
00405 KAccelAction* KAccel::insert( KStdAccel::StdAccel id,
00406 const QObject* pObjSlot, const char* psMethodSlot,
00407 bool bConfigurable, bool bEnabled )
00408 {
00409 QString sAction = KStdAccel::name( id );
00410 if( sAction.isEmpty() )
00411 return 0;
00412
00413 KAccelAction* pAction = d->insert( sAction, KStdAccel::label( id ), KStdAccel::whatsThis( id ),
00414 KStdAccel::shortcutDefault3( id ), KStdAccel::shortcutDefault4( id ),
00415 pObjSlot, psMethodSlot,
00416 bConfigurable, bEnabled );
00417 if( pAction )
00418 pAction->setShortcut( KStdAccel::shortcut( id ) );
00419
00420 return pAction;
00421 }
00422
00423 bool KAccel::remove( const QString& sAction )
00424 { return d->removeAction( sAction ); }
00425 bool KAccel::updateConnections()
00426 { return d->updateConnections(); }
00427
00428 const KShortcut& KAccel::shortcut( const QString& sAction ) const
00429 {
00430 const KAccelAction* pAction = actions().actionPtr( sAction );
00431 return (pAction) ? pAction->shortcut() : KShortcut::null();
00432 }
00433
00434 bool KAccel::setSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot )
00435 { return d->setActionSlot( sAction, pObjSlot, psMethodSlot ); }
00436
00437 bool KAccel::setEnabled( const QString& sAction, bool bEnable )
00438 { return d->setEnabled( sAction, bEnable ); }
00439
00440 bool KAccel::setShortcut( const QString& sAction, const KShortcut& cut )
00441 {
00442 kdDebug(125) << "KAccel::setShortcut( \"" << sAction << "\", " << cut.toStringInternal() << " )" << endl;
00443 KAccelAction* pAction = actions().actionPtr( sAction );
00444 if( pAction ) {
00445 if( pAction->shortcut() != cut )
00446 return d->setShortcut( sAction, cut );
00447 return true;
00448 }
00449 return false;
00450 }
00451
00452 const QString& KAccel::configGroup() const
00453 { return d->configGroup(); }
00454
00455 void KAccel::setConfigGroup( const QString& s )
00456 { d->setConfigGroup( s ); }
00457
00458 bool KAccel::readSettings( KConfigBase* pConfig )
00459 {
00460 d->readSettings( pConfig );
00461 return true;
00462 }
00463
00464 bool KAccel::writeSettings( KConfigBase* pConfig ) const
00465 { d->writeSettings( pConfig ); return true; }
00466
00467 void KAccel::emitKeycodeChanged()
00468 {
00469 kdDebug(125) << "KAccel::emitKeycodeChanged()" << endl;
00470 emit keycodeChanged();
00471 }
00472
00473 #ifndef KDE_NO_COMPAT
00474
00475
00476
00477
00478 bool KAccel::insertItem( const QString& sLabel, const QString& sAction,
00479 const char* cutsDef,
00480 int , QPopupMenu *, bool bConfigurable )
00481 {
00482 KShortcut cut( cutsDef );
00483 bool b = d->insert( sAction, sLabel, QString::null,
00484 cut, cut,
00485 0, 0,
00486 bConfigurable ) != 0;
00487 return b;
00488 }
00489
00490 bool KAccel::insertItem( const QString& sLabel, const QString& sAction,
00491 int key,
00492 int , QPopupMenu*, bool bConfigurable )
00493 {
00494 KShortcut cut;
00495 cut.init( QKeySequence(key) );
00496 KAccelAction* pAction = d->insert( sAction, sLabel, QString::null,
00497 cut, cut,
00498 0, 0,
00499 bConfigurable );
00500 return pAction != 0;
00501 }
00502
00503
00504 bool KAccel::insertStdItem( KStdAccel::StdAccel id, const QString& sLabel )
00505 {
00506 KAccelAction* pAction = d->insert( KStdAccel::name( id ), sLabel, QString::null,
00507 KStdAccel::shortcutDefault3( id ), KStdAccel::shortcutDefault4( id ),
00508 0, 0 );
00509 if( pAction )
00510 pAction->setShortcut( KStdAccel::shortcut( id ) );
00511
00512 return true;
00513 }
00514
00515 bool KAccel::connectItem( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot, bool bActivate )
00516 {
00517 kdDebug(125) << "KAccel::connectItem( " << sAction << ", " << pObjSlot << ", " << psMethodSlot << " )" << endl;
00518 if( bActivate == false )
00519 d->setActionEnabled( sAction, false );
00520 bool b = setSlot( sAction, pObjSlot, psMethodSlot );
00521 if( bActivate == true )
00522 d->setActionEnabled( sAction, true );
00523 return b;
00524 }
00525
00526 bool KAccel::removeItem( const QString& sAction )
00527 { return d->removeAction( sAction ); }
00528
00529 bool KAccel::setItemEnabled( const QString& sAction, bool bEnable )
00530 { return setEnabled( sAction, bEnable ); }
00531
00532 void KAccel::changeMenuAccel( QPopupMenu *menu, int id, const QString& action )
00533 {
00534 KAccelAction* pAction = actions().actionPtr( action );
00535 QString s = menu->text( id );
00536 if( !pAction || s.isEmpty() )
00537 return;
00538
00539 int i = s.find( '\t' );
00540
00541 QString k = pAction->shortcut().seq(0).toString();
00542 if( k.isEmpty() )
00543 return;
00544
00545 if ( i >= 0 )
00546 s.replace( i+1, s.length()-i, k );
00547 else {
00548 s += '\t';
00549 s += k;
00550 }
00551
00552 QPixmap *pp = menu->pixmap(id);
00553 if( pp && !pp->isNull() )
00554 menu->changeItem( *pp, s, id );
00555 else
00556 menu->changeItem( s, id );
00557 }
00558
00559 void KAccel::changeMenuAccel( QPopupMenu *menu, int id, KStdAccel::StdAccel accel )
00560 {
00561 changeMenuAccel( menu, id, KStdAccel::name( accel ) );
00562 }
00563
00564 int KAccel::stringToKey( const QString& sKey )
00565 {
00566 return KKey( sKey ).keyCodeQt();
00567 }
00568
00569 int KAccel::currentKey( const QString& sAction ) const
00570 {
00571 KAccelAction* pAction = d->actionPtr( sAction );
00572 if( pAction )
00573 return pAction->shortcut().keyCodeQt();
00574 return 0;
00575 }
00576
00577 QString KAccel::findKey( int key ) const
00578 {
00579 KAccelAction* pAction = d->actionPtr( KKey(key) );
00580 if( pAction )
00581 return pAction->name();
00582 else
00583 return QString::null;
00584 }
00585 #endif // !KDE_NO_COMPAT
00586
00587 void KAccel::virtual_hook( int, void* )
00588 { }
00589
00590 #include "kaccel.moc"
00591 #include "kaccelprivate.moc"