00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kaccelbase.h"
00024
00025 #include <qkeycode.h>
00026 #include <qlabel.h>
00027 #include <qpopupmenu.h>
00028
00029 #include <kconfig.h>
00030 #include "kckey.h"
00031 #include <kdebug.h>
00032 #include <kglobal.h>
00033 #include <kkeynative.h>
00034 #include "kkeyserver.h"
00035 #include <klocale.h>
00036 #include "kshortcutmenu.h"
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 KAccelBase::KAccelBase( int fInitCode )
00047 : m_rgActions( this )
00048 {
00049 kdDebug(125) << "KAccelBase(): this = " << this << endl;
00050 m_bNativeKeys = fInitCode & NATIVE_KEYS;
00051 m_bEnabled = true;
00052 m_sConfigGroup = "Shortcuts";
00053 m_bConfigIsGlobal = false;
00054 m_bAutoUpdate = false;
00055 mtemp_pActionRemoving = 0;
00056 }
00057
00058 KAccelBase::~KAccelBase()
00059 {
00060 kdDebug(125) << "~KAccelBase(): this = " << this << endl;
00061 }
00062
00063 uint KAccelBase::actionCount() const { return m_rgActions.count(); }
00064 KAccelActions& KAccelBase::actions() { return m_rgActions; }
00065 bool KAccelBase::isEnabled() const { return m_bEnabled; }
00066
00067
00068
00069
00070 bool KAccelBase::isEnabledInternal() const { return isEnabled(); }
00071
00072 KAccelAction* KAccelBase::actionPtr( const QString& sAction )
00073 { return m_rgActions.actionPtr( sAction ); }
00074
00075 const KAccelAction* KAccelBase::actionPtr( const QString& sAction ) const
00076 { return m_rgActions.actionPtr( sAction ); }
00077
00078 KAccelAction* KAccelBase::actionPtr( const KKeyServer::Key& key )
00079 {
00080 if( !m_mapKeyToAction.contains( key ) )
00081 return 0;
00082
00083 return m_mapKeyToAction[key].pAction;
00084 }
00085
00086 KAccelAction* KAccelBase::actionPtr( const KKey& key )
00087 {
00088 KKeyServer::Key k2;
00089 k2.init( key, !m_bNativeKeys );
00090 return actionPtr( k2 );
00091 }
00092
00093 void KAccelBase::setConfigGroup( const QString& sConfigGroup )
00094 { m_sConfigGroup = sConfigGroup; }
00095
00096 void KAccelBase::setConfigGlobal( bool global )
00097 { m_bConfigIsGlobal = global; }
00098
00099 bool KAccelBase::setActionEnabled( const QString& sAction, bool bEnable )
00100 {
00101 KAccelAction* pAction = actionPtr( sAction );
00102 if( pAction ) {
00103 if( pAction->m_bEnabled != bEnable ) {
00104 kdDebug(125) << "KAccelBase::setActionEnabled( " << sAction << ", " << bEnable << " )" << endl;
00105 pAction->m_bEnabled = bEnable;
00106 if( m_bAutoUpdate ) {
00107
00108 if( bEnable )
00109 insertConnection( pAction );
00110 else if( pAction->isConnected() )
00111 removeConnection( pAction );
00112 }
00113 }
00114 return true;
00115 }
00116 return false;
00117 }
00118
00119 bool KAccelBase::setAutoUpdate( bool bAuto )
00120 {
00121 kdDebug(125) << "KAccelBase::setAutoUpdate( " << bAuto << " ): m_bAutoUpdate on entrance = " << m_bAutoUpdate << endl;
00122 bool b = m_bAutoUpdate;
00123 if( !m_bAutoUpdate && bAuto )
00124 updateConnections();
00125 m_bAutoUpdate = bAuto;
00126 return b;
00127 }
00128
00129 KAccelAction* KAccelBase::insert( const QString& sAction, const QString& sDesc, const QString& sHelp,
00130 const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4,
00131 const QObject* pObjSlot, const char* psMethodSlot,
00132 bool bConfigurable, bool bEnabled )
00133 {
00134
00135 KAccelAction* pAction = m_rgActions.insert(
00136 sAction, sDesc, sHelp,
00137 rgCutDefaults3, rgCutDefaults4,
00138 pObjSlot, psMethodSlot,
00139 bConfigurable, bEnabled );
00140
00141 if( pAction && m_bAutoUpdate )
00142 insertConnection( pAction );
00143
00144
00145 return pAction;
00146 }
00147
00148 KAccelAction* KAccelBase::insert( const QString& sName, const QString& sDesc )
00149 { return m_rgActions.insert( sName, sDesc ); }
00150
00151 bool KAccelBase::remove( const QString& sAction )
00152 {
00153 return m_rgActions.remove( sAction );
00154 }
00155
00156 void KAccelBase::slotRemoveAction( KAccelAction* pAction )
00157 {
00158 removeConnection( pAction );
00159 }
00160
00161 bool KAccelBase::setActionSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot )
00162 {
00163 kdDebug(125) << "KAccelBase::setActionSlot( " << sAction << ", " << pObjSlot << ", " << psMethodSlot << " )\n";
00164 KAccelAction* pAction = m_rgActions.actionPtr( sAction );
00165 if( pAction ) {
00166
00167 if( m_bAutoUpdate && pAction->isConnected() ) {
00168 kdDebug(125) << "\tm_pObjSlot = " << pAction->m_pObjSlot << " m_psMethodSlot = " << pAction->m_psMethodSlot << endl;
00169 removeConnection( pAction );
00170 }
00171
00172 pAction->m_pObjSlot = pObjSlot;
00173 pAction->m_psMethodSlot = psMethodSlot;
00174
00175
00176 if( m_bAutoUpdate && pObjSlot && psMethodSlot )
00177 insertConnection( pAction );
00178
00179 return true;
00180 } else
00181 return false;
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 #ifdef Q_WS_X11
00249 struct KAccelBase::X
00250 {
00251 uint iAction, iSeq, iVari;
00252 KKeyServer::Key key;
00253
00254 X() {}
00255 X( uint _iAction, uint _iSeq, uint _iVari, const KKeyServer::Key& _key )
00256 { iAction = _iAction; iSeq = _iSeq; iVari = _iVari; key = _key; }
00257
00258 int compare( const X& x )
00259 {
00260 int n = key.compare( x.key );
00261 if( n != 0 ) return n;
00262 if( iVari != x.iVari ) return iVari - x.iVari;
00263 if( iSeq != x.iSeq ) return iSeq - x.iSeq;
00264 return 0;
00265 }
00266
00267 bool operator <( const X& x ) { return compare( x ) < 0; }
00268 bool operator >( const X& x ) { return compare( x ) > 0; }
00269 bool operator <=( const X& x ) { return compare( x ) <= 0; }
00270 };
00271 #endif //Q_WS_X11
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 bool KAccelBase::updateConnections()
00316 {
00317 #ifdef Q_WS_X11
00318 kdDebug(125) << "KAccelBase::updateConnections() this = " << this << endl;
00319
00320
00321 QValueVector<X> rgKeys;
00322 createKeyList( rgKeys );
00323 m_rgActionsNonUnique.clear();
00324
00325 KKeyToActionMap mapKeyToAction;
00326 for( uint i = 0; i < rgKeys.size(); i++ ) {
00327 X& x = rgKeys[i];
00328 KKeyServer::Key& key = x.key;
00329 ActionInfo info;
00330 bool bNonUnique = false;
00331
00332 info.pAction = m_rgActions.actionPtr( x.iAction );
00333 info.iSeq = x.iSeq;
00334 info.iVariation = x.iVari;
00335
00336
00337 if( info.pAction->shortcut().seq(info.iSeq).count() > 1 )
00338 bNonUnique = true;
00339
00340 else if( i < rgKeys.size() - 1 && key == rgKeys[i+1].key ) {
00341
00342
00343 if( info.iVariation == rgKeys[i+1].iVari && info.iSeq == rgKeys[i+1].iSeq )
00344 bNonUnique = true;
00345
00346 kdDebug(125) << "key conflict = " << key.key().toStringInternal()
00347 << " action1 = " << info.pAction->name()
00348 << " action2 = " << m_rgActions.actionPtr( rgKeys[i+1].iAction )->name()
00349 << " non-unique = " << bNonUnique << endl;
00350
00351
00352 while( i < rgKeys.size() - 1 && key == rgKeys[i+1].key )
00353 i++;
00354 }
00355
00356 if( bNonUnique ) {
00357
00358 if( m_mapKeyToAction.contains( key ) ) {
00359 KAccelAction* pAction = m_mapKeyToAction[key].pAction;
00360 if( pAction ) {
00361 m_mapKeyToAction.remove( key );
00362 disconnectKey( *pAction, key );
00363 pAction->decConnections();
00364 m_rgActionsNonUnique.append( pAction );
00365 }
00366 }
00367
00368 m_rgActionsNonUnique.append( info.pAction );
00369 info.pAction = 0;
00370 }
00371
00372
00373 mapKeyToAction[key] = info;
00374 }
00375
00376
00377 for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
00378 const KKeyServer::Key& key = it.key();
00379 KAccelAction* pAction = (*it).pAction;
00380
00381 if( !mapKeyToAction.contains( key ) || mapKeyToAction[key].pAction != pAction ) {
00382 if( pAction ) {
00383 disconnectKey( *pAction, key );
00384 pAction->decConnections();
00385 } else
00386 disconnectKey( key );
00387 }
00388 }
00389
00390
00391
00392
00393 for( KKeyToActionMap::iterator it = mapKeyToAction.begin(); it != mapKeyToAction.end(); ++it ) {
00394 const KKeyServer::Key& key = it.key();
00395 KAccelAction* pAction = (*it).pAction;
00396 if( !m_mapKeyToAction.contains( key ) || m_mapKeyToAction[key].pAction != pAction ) {
00397
00398
00399 if( pAction ) {
00400 if( connectKey( *pAction, key ) )
00401 pAction->incConnections();
00402 } else
00403 connectKey( key );
00404 }
00405 }
00406
00407
00408 m_mapKeyToAction = mapKeyToAction;
00409
00410 #ifndef NDEBUG
00411 for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
00412 kdDebug(125) << "Key: " << it.key().key().toStringInternal() << " => '"
00413 << (((*it).pAction) ? (*it).pAction->name() : QString::null) << "'" << endl;
00414 }
00415 #endif
00416 #endif //Q_WS_X11
00417 return true;
00418 }
00419
00420 #ifdef Q_WS_X11
00421
00422 void KAccelBase::createKeyList( QValueVector<struct X>& rgKeys )
00423 {
00424
00425 if( !isEnabledInternal())
00426 return;
00427
00428
00429
00430 for( uint iAction = 0; iAction < m_rgActions.count(); iAction++ ) {
00431 KAccelAction* pAction = m_rgActions.actionPtr( iAction );
00432 if( pAction && pAction->m_pObjSlot && pAction->m_psMethodSlot && pAction != mtemp_pActionRemoving ) {
00433
00434 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00435 const KKeySequence& seq = pAction->shortcut().seq(iSeq);
00436 if( seq.count() > 0 ) {
00437 KKeyServer::Variations vars;
00438 vars.init( seq.key(0), !m_bNativeKeys );
00439 for( uint iVari = 0; iVari < vars.count(); iVari++ ) {
00440 if( vars.key(iVari).code() && vars.key(iVari).sym() )
00441 rgKeys.push_back( X( iAction, iSeq, iVari, vars.key( iVari ) ) );
00442
00443 }
00444 }
00445
00446
00447 }
00448 }
00449 }
00450
00451
00452 qHeapSort( rgKeys.begin(), rgKeys.end() );
00453 }
00454 #endif //Q_WS_X11
00455
00456 bool KAccelBase::insertConnection( KAccelAction* pAction )
00457 {
00458 if( !pAction->m_pObjSlot || !pAction->m_psMethodSlot )
00459 return true;
00460
00461 kdDebug(125) << "KAccelBase::insertConnection( " << pAction << "=\"" << pAction->m_sName << "\"; shortcut = " << pAction->shortcut().toStringInternal() << " ) this = " << this << endl;
00462
00463
00464 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00465
00466 KKeyServer::Variations vars;
00467 vars.init( pAction->shortcut().seq(iSeq).key(0), !m_bNativeKeys );
00468 for( uint iVari = 0; iVari < vars.count(); iVari++ ) {
00469 const KKeyServer::Key& key = vars.key( iVari );
00470
00471
00472 if( key.sym() ) {
00473 if( !m_mapKeyToAction.contains( key ) ) {
00474
00475 if( pAction->shortcut().seq(iSeq).count() == 1 ) {
00476 m_mapKeyToAction[key] = ActionInfo( pAction, iSeq, iVari );
00477 if( connectKey( *pAction, key ) )
00478 pAction->incConnections();
00479 }
00480
00481 else {
00482 m_mapKeyToAction[key] = ActionInfo( 0, 0, 0 );
00483
00484 if( m_rgActionsNonUnique.findIndex( pAction ) == -1 )
00485 m_rgActionsNonUnique.append( pAction );
00486 if( connectKey( key ) )
00487 pAction->incConnections();
00488 }
00489 } else {
00490
00491
00492
00493 if( m_mapKeyToAction[key].pAction != pAction
00494 && m_mapKeyToAction[key].pAction != 0 ) {
00495 kdDebug(125) << "Key conflict with action = " << m_mapKeyToAction[key].pAction->name()
00496 << " key = " << key.key().toStringInternal() << " : call updateConnections()" << endl;
00497 return updateConnections();
00498 }
00499 }
00500 }
00501 }
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 return true;
00517 }
00518
00519 bool KAccelBase::removeConnection( KAccelAction* pAction )
00520 {
00521 kdDebug(125) << "KAccelBase::removeConnection( " << pAction << " = \"" << pAction->m_sName << "\"; shortcut = " << pAction->m_cut.toStringInternal() << " ): this = " << this << endl;
00522
00523
00524
00525
00526 if( m_rgActionsNonUnique.findIndex( pAction ) >= 0 ) {
00527 mtemp_pActionRemoving = pAction;
00528 bool b = updateConnections();
00529 mtemp_pActionRemoving = 0;
00530 return b;
00531 }
00532
00533 KKeyToActionMap::iterator it = m_mapKeyToAction.begin();
00534 while( it != m_mapKeyToAction.end() ) {
00535 KKeyServer::Key key = it.key();
00536 ActionInfo* pInfo = &(*it);
00537
00538
00539 if( pAction == pInfo->pAction ) {
00540 disconnectKey( *pAction, key );
00541 pAction->decConnections();
00542
00543 KKeyToActionMap::iterator itRemove = it++;
00544 m_mapKeyToAction.remove( itRemove );
00545 } else
00546 ++it;
00547 }
00548 return true;
00549 }
00550
00551 bool KAccelBase::setShortcut( const QString& sAction, const KShortcut& cut )
00552 {
00553 KAccelAction* pAction = actionPtr( sAction );
00554 if( pAction ) {
00555 if( m_bAutoUpdate )
00556 removeConnection( pAction );
00557
00558 pAction->setShortcut( cut );
00559
00560 if( m_bAutoUpdate && !pAction->shortcut().isNull() )
00561 insertConnection( pAction );
00562 return true;
00563 } else
00564 return false;
00565 }
00566
00567 void KAccelBase::readSettings( KConfigBase* pConfig )
00568 {
00569 m_rgActions.readActions( m_sConfigGroup, pConfig );
00570 if( m_bAutoUpdate )
00571 updateConnections();
00572 }
00573
00574 void KAccelBase::writeSettings( KConfigBase* pConfig ) const
00575 {
00576 m_rgActions.writeActions( m_sConfigGroup, pConfig, m_bConfigIsGlobal, m_bConfigIsGlobal );
00577 }
00578
00579 QPopupMenu* KAccelBase::createPopupMenu( QWidget* pParent, const KKeySequence& seq )
00580 {
00581 KShortcutMenu* pMenu = new KShortcutMenu( pParent, &actions(), seq );
00582
00583 bool bActionInserted = false;
00584 bool bInsertSeparator = false;
00585 for( uint i = 0; i < actionCount(); i++ ) {
00586 const KAccelAction* pAction = actions().actionPtr( i );
00587
00588 if( !pAction->isEnabled() )
00589 continue;
00590
00591
00592
00593
00594 if( bActionInserted && !pAction->isConfigurable() && pAction->name().contains( ':' ) )
00595 bInsertSeparator = true;
00596
00597 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00598 const KKeySequence& seqAction = pAction->shortcut().seq(iSeq);
00599 if( seqAction.startsWith( seq ) ) {
00600 if( bInsertSeparator ) {
00601 pMenu->insertSeparator();
00602 bInsertSeparator = false;
00603 }
00604
00605 pMenu->insertAction( i, seqAction );
00606
00607
00608
00609 bActionInserted = true;
00610 break;
00611 }
00612 }
00613 }
00614 pMenu->updateShortcuts();
00615 return pMenu;
00616 }