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