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