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 KAccelAction* KAccelBase::actionPtr( const QString& sAction )
00068 { return m_rgActions.actionPtr( sAction ); }
00069
00070 const KAccelAction* KAccelBase::actionPtr( const QString& sAction ) const
00071 { return m_rgActions.actionPtr( sAction ); }
00072
00073 KAccelAction* KAccelBase::actionPtr( const KKeyServer::Key& key )
00074 {
00075 if( !m_mapKeyToAction.contains( key ) )
00076 return 0;
00077
00078 return m_mapKeyToAction[key].pAction;
00079 }
00080
00081 KAccelAction* KAccelBase::actionPtr( const KKey& key )
00082 {
00083 KKeyServer::Key k2;
00084 k2.init( key, !m_bNativeKeys );
00085 return actionPtr( k2 );
00086 }
00087
00088 void KAccelBase::setConfigGroup( const QString& sConfigGroup )
00089 { m_sConfigGroup = sConfigGroup; }
00090
00091 void KAccelBase::setConfigGlobal( bool global )
00092 { m_bConfigIsGlobal = global; }
00093
00094 bool KAccelBase::setActionEnabled( const QString& sAction, bool bEnable )
00095 {
00096 KAccelAction* pAction = actionPtr( sAction );
00097 if( pAction ) {
00098 if( pAction->m_bEnabled != bEnable ) {
00099 kdDebug(125) << "KAccelBase::setActionEnabled( " << sAction << ", " << bEnable << " )" << endl;
00100 pAction->m_bEnabled = bEnable;
00101 if( m_bAutoUpdate ) {
00102
00103 if( bEnable )
00104 insertConnection( pAction );
00105 else if( pAction->isConnected() )
00106 removeConnection( pAction );
00107 }
00108 }
00109 return true;
00110 }
00111 return false;
00112 }
00113
00114 bool KAccelBase::setAutoUpdate( bool bAuto )
00115 {
00116 kdDebug(125) << "KAccelBase::setAutoUpdate( " << bAuto << " ): m_bAutoUpdate on entrance = " << m_bAutoUpdate << endl;
00117 bool b = m_bAutoUpdate;
00118 if( !m_bAutoUpdate && bAuto )
00119 updateConnections();
00120 m_bAutoUpdate = bAuto;
00121 return b;
00122 }
00123
00124 KAccelAction* KAccelBase::insert( const QString& sAction, const QString& sDesc, const QString& sHelp,
00125 const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4,
00126 const QObject* pObjSlot, const char* psMethodSlot,
00127 bool bConfigurable, bool bEnabled )
00128 {
00129
00130 KAccelAction* pAction = m_rgActions.insert(
00131 sAction, sDesc, sHelp,
00132 rgCutDefaults3, rgCutDefaults4,
00133 pObjSlot, psMethodSlot,
00134 bConfigurable, bEnabled );
00135
00136 if( pAction && m_bAutoUpdate )
00137 insertConnection( pAction );
00138
00139
00140 return pAction;
00141 }
00142
00143 KAccelAction* KAccelBase::insert( const QString& sName, const QString& sDesc )
00144 { return m_rgActions.insert( sName, sDesc ); }
00145
00146 bool KAccelBase::remove( const QString& sAction )
00147 {
00148 return m_rgActions.remove( sAction );
00149 }
00150
00151 void KAccelBase::slotRemoveAction( KAccelAction* pAction )
00152 {
00153 removeConnection( pAction );
00154 }
00155
00156 bool KAccelBase::setActionSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot )
00157 {
00158 kdDebug(125) << "KAccelBase::setActionSlot( " << sAction << ", " << pObjSlot << ", " << psMethodSlot << " )\n";
00159 KAccelAction* pAction = m_rgActions.actionPtr( sAction );
00160 if( pAction ) {
00161
00162 if( m_bAutoUpdate && pAction->isConnected() ) {
00163 kdDebug(125) << "\tm_pObjSlot = " << pAction->m_pObjSlot << " m_psMethodSlot = " << pAction->m_psMethodSlot << endl;
00164 removeConnection( pAction );
00165 }
00166
00167 pAction->m_pObjSlot = pObjSlot;
00168 pAction->m_psMethodSlot = psMethodSlot;
00169
00170
00171 if( m_bAutoUpdate && pObjSlot && psMethodSlot )
00172 insertConnection( pAction );
00173
00174 return true;
00175 } else
00176 return false;
00177 }
00178
00179
00180
00181
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 #ifdef Q_WS_X11
00244 struct KAccelBase::X
00245 {
00246 uint iAction, iSeq, iVari;
00247 KKeyServer::Key key;
00248
00249 X() {}
00250 X( uint _iAction, uint _iSeq, uint _iVari, const KKeyServer::Key& _key )
00251 { iAction = _iAction; iSeq = _iSeq; iVari = _iVari; key = _key; }
00252
00253 int compare( const X& x )
00254 {
00255 int n = key.compare( x.key );
00256 if( n != 0 ) return n;
00257 if( iVari != x.iVari ) return iVari - x.iVari;
00258 if( iSeq != x.iSeq ) return iSeq - x.iSeq;
00259 return 0;
00260 }
00261
00262 bool operator <( const X& x ) { return compare( x ) < 0; }
00263 bool operator >( const X& x ) { return compare( x ) > 0; }
00264 bool operator <=( const X& x ) { return compare( x ) <= 0; }
00265 };
00266 #endif //Q_WS_X11
00267
00268
00269
00270
00271
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 bool KAccelBase::updateConnections()
00311 {
00312 #ifdef Q_WS_X11
00313 kdDebug(125) << "KAccelBase::updateConnections() this = " << this << endl;
00314
00315
00316 QValueVector<X> rgKeys;
00317 createKeyList( rgKeys );
00318 m_rgActionsNonUnique.clear();
00319
00320 KKeyToActionMap mapKeyToAction;
00321 for( uint i = 0; i < rgKeys.size(); i++ ) {
00322 X& x = rgKeys[i];
00323 KKeyServer::Key& key = x.key;
00324 ActionInfo info;
00325 bool bNonUnique = false;
00326
00327 info.pAction = m_rgActions.actionPtr( x.iAction );
00328 info.iSeq = x.iSeq;
00329 info.iVariation = x.iVari;
00330
00331
00332 if( info.pAction->shortcut().seq(info.iSeq).count() > 1 )
00333 bNonUnique = true;
00334
00335 else if( i < rgKeys.size() - 1 && key == rgKeys[i+1].key ) {
00336
00337
00338 if( info.iVariation == rgKeys[i+1].iVari && info.iSeq == rgKeys[i+1].iSeq )
00339 bNonUnique = true;
00340
00341 kdDebug(125) << "key conflict = " << key.key().toStringInternal()
00342 << " action1 = " << info.pAction->name()
00343 << " action2 = " << m_rgActions.actionPtr( rgKeys[i+1].iAction )->name()
00344 << " non-unique = " << bNonUnique << endl;
00345
00346
00347 while( i < rgKeys.size() - 1 && key == rgKeys[i+1].key )
00348 i++;
00349 }
00350
00351 if( bNonUnique ) {
00352
00353 if( m_mapKeyToAction.contains( key ) ) {
00354 KAccelAction* pAction = m_mapKeyToAction[key].pAction;
00355 if( pAction ) {
00356 m_mapKeyToAction.remove( key );
00357 disconnectKey( *pAction, key );
00358 pAction->decConnections();
00359 m_rgActionsNonUnique.append( pAction );
00360 }
00361 }
00362
00363 m_rgActionsNonUnique.append( info.pAction );
00364 info.pAction = 0;
00365 }
00366
00367
00368 mapKeyToAction[key] = info;
00369 }
00370
00371
00372 for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
00373 const KKeyServer::Key& key = it.key();
00374 KAccelAction* pAction = (*it).pAction;
00375
00376 if( !mapKeyToAction.contains( key ) || mapKeyToAction[key].pAction != pAction ) {
00377 if( pAction ) {
00378 disconnectKey( *pAction, key );
00379 pAction->decConnections();
00380 } else
00381 disconnectKey( key );
00382 }
00383 }
00384
00385
00386
00387
00388 for( KKeyToActionMap::iterator it = mapKeyToAction.begin(); it != mapKeyToAction.end(); ++it ) {
00389 const KKeyServer::Key& key = it.key();
00390 KAccelAction* pAction = (*it).pAction;
00391 if( !m_mapKeyToAction.contains( key ) || m_mapKeyToAction[key].pAction != pAction ) {
00392
00393
00394 if( pAction ) {
00395 if( connectKey( *pAction, key ) )
00396 pAction->incConnections();
00397 } else
00398 connectKey( key );
00399 }
00400 }
00401
00402
00403 m_mapKeyToAction = mapKeyToAction;
00404
00405 #ifndef NDEBUG
00406 for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
00407 kdDebug(125) << "Key: " << it.key().key().toStringInternal() << " => '"
00408 << (((*it).pAction) ? (*it).pAction->name() : QString::null) << "'" << endl;
00409 }
00410 #endif
00411 #endif //Q_WS_X11
00412 return true;
00413 }
00414
00415 #ifdef Q_WS_X11
00416
00417 void KAccelBase::createKeyList( QValueVector<struct X>& rgKeys )
00418 {
00419
00420 if( !m_bEnabled )
00421 return;
00422
00423
00424
00425 for( uint iAction = 0; iAction < m_rgActions.count(); iAction++ ) {
00426 KAccelAction* pAction = m_rgActions.actionPtr( iAction );
00427 if( pAction && pAction->m_pObjSlot && pAction->m_psMethodSlot && pAction != mtemp_pActionRemoving ) {
00428
00429 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00430 const KKeySequence& seq = pAction->shortcut().seq(iSeq);
00431 if( seq.count() > 0 ) {
00432 KKeyServer::Variations vars;
00433 vars.init( seq.key(0), !m_bNativeKeys );
00434 for( uint iVari = 0; iVari < vars.count(); iVari++ ) {
00435 if( vars.key(iVari).code() && vars.key(iVari).sym() )
00436 rgKeys.push_back( X( iAction, iSeq, iVari, vars.key( iVari ) ) );
00437
00438 }
00439 }
00440
00441
00442 }
00443 }
00444 }
00445
00446
00447 qHeapSort( rgKeys.begin(), rgKeys.end() );
00448 }
00449 #endif //Q_WS_X11
00450
00451 bool KAccelBase::insertConnection( KAccelAction* pAction )
00452 {
00453 if( !pAction->m_pObjSlot || !pAction->m_psMethodSlot )
00454 return true;
00455
00456 kdDebug(125) << "KAccelBase::insertConnection( " << pAction << "=\"" << pAction->m_sName << "\"; shortcut = " << pAction->shortcut().toStringInternal() << " ) this = " << this << endl;
00457
00458
00459 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00460
00461 KKeyServer::Variations vars;
00462 vars.init( pAction->shortcut().seq(iSeq).key(0), !m_bNativeKeys );
00463 for( uint iVari = 0; iVari < vars.count(); iVari++ ) {
00464 const KKeyServer::Key& key = vars.key( iVari );
00465
00466
00467 if( key.sym() ) {
00468 if( !m_mapKeyToAction.contains( key ) ) {
00469
00470 if( pAction->shortcut().seq(iSeq).count() == 1 ) {
00471 m_mapKeyToAction[key] = ActionInfo( pAction, iSeq, iVari );
00472 if( connectKey( *pAction, key ) )
00473 pAction->incConnections();
00474 }
00475
00476 else {
00477 m_mapKeyToAction[key] = ActionInfo( 0, 0, 0 );
00478
00479 if( m_rgActionsNonUnique.findIndex( pAction ) == -1 )
00480 m_rgActionsNonUnique.append( pAction );
00481 if( connectKey( key ) )
00482 pAction->incConnections();
00483 }
00484 } else {
00485
00486
00487
00488 if( m_mapKeyToAction[key].pAction != pAction
00489 && m_mapKeyToAction[key].pAction != 0 ) {
00490 kdDebug(125) << "Key conflict with action = " << m_mapKeyToAction[key].pAction->name()
00491 << " key = " << key.key().toStringInternal() << " : call updateConnections()" << endl;
00492 return updateConnections();
00493 }
00494 }
00495 }
00496 }
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511 return true;
00512 }
00513
00514 bool KAccelBase::removeConnection( KAccelAction* pAction )
00515 {
00516 kdDebug(125) << "KAccelBase::removeConnection( " << pAction << " = \"" << pAction->m_sName << "\"; shortcut = " << pAction->m_cut.toStringInternal() << " ): this = " << this << endl;
00517
00518
00519
00520
00521 if( m_rgActionsNonUnique.findIndex( pAction ) >= 0 ) {
00522 mtemp_pActionRemoving = pAction;
00523 bool b = updateConnections();
00524 mtemp_pActionRemoving = 0;
00525 return b;
00526 }
00527
00528 KKeyToActionMap::iterator it = m_mapKeyToAction.begin();
00529 while( it != m_mapKeyToAction.end() ) {
00530 KKeyServer::Key key = it.key();
00531 ActionInfo* pInfo = &(*it);
00532
00533
00534 if( pAction == pInfo->pAction ) {
00535 disconnectKey( *pAction, key );
00536 pAction->decConnections();
00537
00538 KKeyToActionMap::iterator itRemove = it++;
00539 m_mapKeyToAction.remove( itRemove );
00540 } else
00541 ++it;
00542 }
00543 return true;
00544 }
00545
00546 bool KAccelBase::setShortcut( const QString& sAction, const KShortcut& cut )
00547 {
00548 KAccelAction* pAction = actionPtr( sAction );
00549 if( pAction ) {
00550 if( m_bAutoUpdate )
00551 removeConnection( pAction );
00552
00553 pAction->setShortcut( cut );
00554
00555 if( m_bAutoUpdate && !pAction->shortcut().isNull() )
00556 insertConnection( pAction );
00557 return true;
00558 } else
00559 return false;
00560 }
00561
00562 void KAccelBase::readSettings( KConfigBase* pConfig )
00563 {
00564 m_rgActions.readActions( m_sConfigGroup, pConfig );
00565 if( m_bAutoUpdate )
00566 updateConnections();
00567 }
00568
00569 void KAccelBase::writeSettings( KConfigBase* pConfig ) const
00570 {
00571 m_rgActions.writeActions( m_sConfigGroup, pConfig, m_bConfigIsGlobal, m_bConfigIsGlobal );
00572 }
00573
00574 QPopupMenu* KAccelBase::createPopupMenu( QWidget* pParent, const KKeySequence& seq )
00575 {
00576 KShortcutMenu* pMenu = new KShortcutMenu( pParent, &actions(), seq );
00577
00578 bool bActionInserted = false;
00579 bool bInsertSeparator = false;
00580 for( uint i = 0; i < actionCount(); i++ ) {
00581 const KAccelAction* pAction = actions().actionPtr( i );
00582
00583 if( !pAction->isEnabled() )
00584 continue;
00585
00586
00587
00588
00589 if( bActionInserted && !pAction->isConfigurable() && pAction->name().contains( ':' ) )
00590 bInsertSeparator = true;
00591
00592 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00593 const KKeySequence& seqAction = pAction->shortcut().seq(iSeq);
00594 if( seqAction.startsWith( seq ) ) {
00595 if( bInsertSeparator ) {
00596 pMenu->insertSeparator();
00597 bInsertSeparator = false;
00598 }
00599
00600 pMenu->insertAction( i, seqAction );
00601
00602
00603
00604 bActionInserted = true;
00605 break;
00606 }
00607 }
00608 }
00609 pMenu->updateShortcuts();
00610 return pMenu;
00611 }