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_x11.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
struct KAccelBase::X
00244 {
00245 uint iAction, iSeq, iVari;
00246
KKeyServer::Key key;
00247
00248 X() {}
00249 X( uint _iAction, uint _iSeq, uint _iVari,
const KKeyServer::Key& _key )
00250 { iAction = _iAction; iSeq = _iSeq; iVari = _iVari;
key = _key; }
00251
00252
int compare(
const X& x )
00253 {
00254
int n =
key.compare( x.key );
00255
if( n != 0 )
return n;
00256
if( iVari != x.iVari )
return iVari - x.iVari;
00257
if( iSeq != x.iSeq )
return iSeq - x.iSeq;
00258
return 0;
00259 }
00260
00261
bool operator <(
const X& x ) {
return compare( x ) < 0; }
00262
bool operator >(
const X& x ) {
return compare( x ) > 0; }
00263
bool operator <=(
const X& x ) {
return compare( x ) <= 0; }
00264 };
00265
00266
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
bool KAccelBase::updateConnections()
00309 {
00310 kdDebug(125) <<
"KAccelBase::updateConnections() this = " <<
this <<
endl;
00311
00312
00313
QValueVector<X> rgKeys;
00314 createKeyList( rgKeys );
00315 m_rgActionsNonUnique.clear();
00316
00317 KKeyToActionMap mapKeyToAction;
00318
for( uint i = 0; i < rgKeys.size(); i++ ) {
00319 X& x = rgKeys[i];
00320
KKeyServer::Key&
key = x.key;
00321 ActionInfo info;
00322
bool bNonUnique =
false;
00323
00324 info.pAction = m_rgActions.actionPtr( x.iAction );
00325 info.iSeq = x.iSeq;
00326 info.iVariation = x.iVari;
00327
00328
00329
if( info.pAction->shortcut().seq(info.iSeq).count() > 1 )
00330 bNonUnique =
true;
00331
00332
else if( i < rgKeys.size() - 1 &&
key == rgKeys[i+1].key ) {
00333
00334
00335
if( info.iVariation == rgKeys[i+1].iVari && info.iSeq == rgKeys[i+1].iSeq )
00336 bNonUnique =
true;
00337
00338 kdDebug(125) <<
"key conflict = " <<
key.key().toStringInternal()
00339 <<
" action1 = " << info.pAction->name()
00340 <<
" action2 = " << m_rgActions.actionPtr( rgKeys[i+1].iAction )->name()
00341 <<
" non-unique = " << bNonUnique <<
endl;
00342
00343
00344
while( i < rgKeys.size() - 1 &&
key == rgKeys[i+1].key )
00345 i++;
00346 }
00347
00348
if( bNonUnique ) {
00349
00350
if( m_mapKeyToAction.contains( key ) ) {
00351 KAccelAction* pAction = m_mapKeyToAction[
key].pAction;
00352
if( pAction ) {
00353 m_mapKeyToAction.remove( key );
00354 disconnectKey( *pAction, key );
00355 pAction->decConnections();
00356 m_rgActionsNonUnique.append( pAction );
00357 }
00358 }
00359
00360 m_rgActionsNonUnique.append( info.pAction );
00361 info.pAction = 0;
00362 }
00363
00364
00365 mapKeyToAction[
key] = info;
00366 }
00367
00368
00369
for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
00370
const KKeyServer::Key&
key = it.key();
00371 KAccelAction* pAction = (*it).pAction;
00372
00373
if( !mapKeyToAction.contains( key ) || mapKeyToAction[
key].pAction != pAction ) {
00374
if( pAction ) {
00375 disconnectKey( *pAction, key );
00376 pAction->decConnections();
00377 }
else
00378 disconnectKey( key );
00379 }
00380 }
00381
00382
00383
00384
00385
for( KKeyToActionMap::iterator it = mapKeyToAction.begin(); it != mapKeyToAction.end(); ++it ) {
00386
const KKeyServer::Key&
key = it.key();
00387 KAccelAction* pAction = (*it).pAction;
00388
if( !m_mapKeyToAction.contains( key ) || m_mapKeyToAction[
key].pAction != pAction ) {
00389
00390
00391
if( pAction ) {
00392
if( connectKey( *pAction, key ) )
00393 pAction->incConnections();
00394 }
else
00395 connectKey( key );
00396 }
00397 }
00398
00399
00400 m_mapKeyToAction = mapKeyToAction;
00401
00402
#ifndef NDEBUG
00403
for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
00404 kdDebug(125) <<
"Key: " << it.key().key().toStringInternal() <<
" => '"
00405 << (((*it).pAction) ? (*it).pAction->name() :
QString::null) <<
"'" <<
endl;
00406 }
00407
#endif
00408
return true;
00409 }
00410
00411
00412
void KAccelBase::createKeyList(
QValueVector<struct X>& rgKeys )
00413 {
00414
00415
if( !m_bEnabled )
00416
return;
00417
00418
00419
00420
for( uint iAction = 0; iAction < m_rgActions.count(); iAction++ ) {
00421 KAccelAction* pAction = m_rgActions.actionPtr( iAction );
00422
if( pAction && pAction->m_pObjSlot && pAction->m_psMethodSlot && pAction != mtemp_pActionRemoving ) {
00423
00424
for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00425
const KKeySequence& seq = pAction->shortcut().seq(iSeq);
00426
if( seq.
count() > 0 ) {
00427
KKeyServer::Variations vars;
00428 vars.
init( seq.
key(0), !m_bNativeKeys );
00429
for( uint iVari = 0; iVari < vars.
count(); iVari++ ) {
00430
if( vars.
key(iVari).code() && vars.
key(iVari).sym() )
00431 rgKeys.push_back( X( iAction, iSeq, iVari, vars.
key( iVari ) ) );
00432
00433 }
00434 }
00435
00436
00437 }
00438 }
00439 }
00440
00441
00442 qHeapSort( rgKeys.begin(), rgKeys.
end() );
00443 }
00444
00445
bool KAccelBase::insertConnection( KAccelAction* pAction )
00446 {
00447
if( !pAction->m_pObjSlot || !pAction->m_psMethodSlot )
00448
return true;
00449
00450 kdDebug(125) <<
"KAccelBase::insertConnection( " << pAction <<
"=\"" << pAction->m_sName <<
"\"; shortcut = " << pAction->shortcut().toStringInternal() <<
" ) this = " <<
this <<
endl;
00451
00452
00453
for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00454
00455
KKeyServer::Variations vars;
00456 vars.
init( pAction->shortcut().seq(iSeq).key(0), !m_bNativeKeys );
00457
for( uint iVari = 0; iVari < vars.
count(); iVari++ ) {
00458
const KKeyServer::Key&
key = vars.
key( iVari );
00459
00460
00461
if(
key.sym() ) {
00462
if( !m_mapKeyToAction.contains( key ) ) {
00463
00464
if( pAction->shortcut().seq(iSeq).count() == 1 ) {
00465 m_mapKeyToAction[
key] = ActionInfo( pAction, iSeq, iVari );
00466
if( connectKey( *pAction, key ) )
00467 pAction->incConnections();
00468 }
00469
00470
else {
00471 m_mapKeyToAction[
key] = ActionInfo( 0, 0, 0 );
00472
00473
if( m_rgActionsNonUnique.findIndex( pAction ) == -1 )
00474 m_rgActionsNonUnique.append( pAction );
00475
if( connectKey( key ) )
00476 pAction->incConnections();
00477 }
00478 }
else {
00479
00480
00481
00482
if( m_mapKeyToAction[
key].pAction != pAction
00483 && m_mapKeyToAction[
key].pAction != 0 ) {
00484 kdDebug(125) <<
"Key conflict: call updateConnections():"
00485 <<
" key = " <<
key.key().toStringInternal() <<
endl;
00486
return updateConnections();
00487 }
00488 }
00489 }
00490 }
00491 }
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
return true;
00506 }
00507
00508
bool KAccelBase::removeConnection( KAccelAction* pAction )
00509 {
00510 kdDebug(125) <<
"KAccelBase::removeConnection( " << pAction <<
" = \"" << pAction->m_sName <<
"\"; shortcut = " << pAction->m_cut.toStringInternal() <<
" ): this = " <<
this <<
endl;
00511
00512
00513
00514
00515
if( m_rgActionsNonUnique.findIndex( pAction ) >= 0 ) {
00516 mtemp_pActionRemoving = pAction;
00517
bool b =
updateConnections();
00518 mtemp_pActionRemoving = 0;
00519
return b;
00520 }
00521
00522 KKeyToActionMap::iterator it = m_mapKeyToAction.begin();
00523
while( it != m_mapKeyToAction.end() ) {
00524
KKeyServer::Key key = it.key();
00525 ActionInfo* pInfo = &(*it);
00526
00527
00528
if( pAction == pInfo->pAction ) {
00529 disconnectKey( *pAction, key );
00530 pAction->decConnections();
00531
00532 KKeyToActionMap::iterator itRemove = it++;
00533 m_mapKeyToAction.remove( itRemove );
00534 }
else
00535 ++it;
00536 }
00537
return true;
00538 }
00539
00540
bool KAccelBase::setShortcut(
const QString& sAction,
const KShortcut& cut )
00541 {
00542 KAccelAction* pAction = actionPtr( sAction );
00543
if( pAction ) {
00544
if( m_bAutoUpdate )
00545 removeConnection( pAction );
00546
00547 pAction->setShortcut( cut );
00548
00549
if( m_bAutoUpdate && !pAction->shortcut().isNull() )
00550 insertConnection( pAction );
00551
return true;
00552 }
else
00553
return false;
00554 }
00555
00556
void KAccelBase::readSettings(
KConfigBase* pConfig )
00557 {
00558 m_rgActions.readActions( m_sConfigGroup, pConfig );
00559
if( m_bAutoUpdate )
00560
updateConnections();
00561 }
00562
00563
void KAccelBase::writeSettings(
KConfigBase* pConfig )
const
00564
{
00565 m_rgActions.writeActions( m_sConfigGroup, pConfig, m_bConfigIsGlobal, m_bConfigIsGlobal );
00566 }
00567
00568
QPopupMenu* KAccelBase::createPopupMenu(
QWidget* pParent,
const KKeySequence& seq )
00569 {
00570 KShortcutMenu* pMenu =
new KShortcutMenu( pParent, &actions(), seq );
00571
00572
bool bActionInserted =
false;
00573
bool bInsertSeparator =
false;
00574
for( uint i = 0; i < actionCount(); i++ ) {
00575
const KAccelAction* pAction = actions().actionPtr( i );
00576
00577
if( !pAction->isEnabled() )
00578
continue;
00579
00580
00581
00582
00583
if( bActionInserted && !pAction->isConfigurable() && pAction->name().contains(
':' ) )
00584 bInsertSeparator =
true;
00585
00586
for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00587
const KKeySequence& seqAction = pAction->shortcut().seq(iSeq);
00588
if( seqAction.
startsWith( seq ) ) {
00589
if( bInsertSeparator ) {
00590 pMenu->insertSeparator();
00591 bInsertSeparator =
false;
00592 }
00593
00594 pMenu->insertAction( i, seqAction );
00595
00596
00597
00598 bActionInserted =
true;
00599
break;
00600 }
00601 }
00602 }
00603 pMenu->updateShortcuts();
00604
return pMenu;
00605 }