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