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 }