00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "tdeaccelbase.h"
00024
00025 #include <tqkeycode.h>
00026 #include <tqlabel.h>
00027 #include <tqpopupmenu.h>
00028
00029 #include <tdeconfig.h>
00030 #include "kckey.h"
00031 #include <kdebug.h>
00032 #include <tdeglobal.h>
00033 #include <kkeynative.h>
00034 #include "kkeyserver.h"
00035 #include <tdelocale.h>
00036 #include "tdeshortcutmenu.h"
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 TDEAccelBase::TDEAccelBase( int fInitCode )
00047 : m_rgActions( this )
00048 {
00049 kdDebug(125) << "TDEAccelBase(): 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 TDEAccelBase::~TDEAccelBase()
00059 {
00060 kdDebug(125) << "~TDEAccelBase(): this = " << this << endl;
00061 }
00062
00063 uint TDEAccelBase::actionCount() const { return m_rgActions.count(); }
00064 TDEAccelActions& TDEAccelBase::actions() { return m_rgActions; }
00065 bool TDEAccelBase::isEnabled() const { return m_bEnabled; }
00066
00067
00068
00069
00070 bool TDEAccelBase::isEnabledInternal() const { return isEnabled(); }
00071
00072 TDEAccelAction* TDEAccelBase::actionPtr( const TQString& sAction )
00073 { return m_rgActions.actionPtr( sAction ); }
00074
00075 const TDEAccelAction* TDEAccelBase::actionPtr( const TQString& sAction ) const
00076 { return m_rgActions.actionPtr( sAction ); }
00077
00078 TDEAccelAction* TDEAccelBase::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 TDEAccelAction* TDEAccelBase::actionPtr( const KKey& key )
00087 {
00088 KKeyServer::Key k2;
00089 k2.init( key, !m_bNativeKeys );
00090 return actionPtr( k2 );
00091 }
00092
00093 void TDEAccelBase::setConfigGroup( const TQString& sConfigGroup )
00094 { m_sConfigGroup = sConfigGroup; }
00095
00096 void TDEAccelBase::setConfigGlobal( bool global )
00097 { m_bConfigIsGlobal = global; }
00098
00099 bool TDEAccelBase::setActionEnabled( const TQString& sAction, bool bEnable )
00100 {
00101 TDEAccelAction* pAction = actionPtr( sAction );
00102 if( pAction ) {
00103 if( pAction->m_bEnabled != bEnable ) {
00104 kdDebug(125) << "TDEAccelBase::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 TDEAccelBase::setAutoUpdate( bool bAuto )
00120 {
00121 kdDebug(125) << "TDEAccelBase::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 TDEAccelAction* TDEAccelBase::insert( const TQString& sAction, const TQString& sDesc, const TQString& sHelp,
00130 const TDEShortcut& rgCutDefaults3, const TDEShortcut& rgCutDefaults4,
00131 const TQObject* pObjSlot, const char* psMethodSlot,
00132 bool bConfigurable, bool bEnabled )
00133 {
00134 kdDebug(125) << "TDEAccelBase::insert() begin" << endl;
00135 kdDebug(125) << "\t" << sAction << ": " << rgCutDefaults3.toString() << ": " << rgCutDefaults4.toString() << endl;
00136 TDEAccelAction* pAction = m_rgActions.insert(
00137 sAction, sDesc, sHelp,
00138 rgCutDefaults3, rgCutDefaults4,
00139 pObjSlot, psMethodSlot,
00140 bConfigurable, bEnabled );
00141
00142 if( pAction && m_bAutoUpdate )
00143 insertConnection( pAction );
00144
00145
00146 return pAction;
00147 }
00148
00149 TDEAccelAction* TDEAccelBase::insert( const TQString& sName, const TQString& sDesc )
00150 { return m_rgActions.insert( sName, sDesc ); }
00151
00152 bool TDEAccelBase::remove( const TQString& sAction )
00153 {
00154 return m_rgActions.remove( sAction );
00155 }
00156
00157 void TDEAccelBase::slotRemoveAction( TDEAccelAction* pAction )
00158 {
00159 removeConnection( pAction );
00160 }
00161
00162 bool TDEAccelBase::setActionSlot( const TQString& sAction, const TQObject* pObjSlot, const char* psMethodSlot )
00163 {
00164 kdDebug(125) << "TDEAccelBase::setActionSlot( " << sAction << ", " << pObjSlot << ", " << psMethodSlot << " )\n";
00165 TDEAccelAction* pAction = m_rgActions.actionPtr( sAction );
00166 if( pAction ) {
00167
00168 if( m_bAutoUpdate && pAction->isConnected() ) {
00169 kdDebug(125) << "\tm_pObjSlot = " << pAction->m_pObjSlot << " m_psMethodSlot = " << pAction->m_psMethodSlot << endl;
00170 removeConnection( pAction );
00171 }
00172
00173 pAction->m_pObjSlot = pObjSlot;
00174 pAction->m_psMethodSlot = psMethodSlot;
00175
00176
00177 if( m_bAutoUpdate && pObjSlot && psMethodSlot )
00178 insertConnection( pAction );
00179
00180 return true;
00181 } else
00182 return false;
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
00249 #ifdef Q_WS_X11
00250 struct TDEAccelBase::X
00251 {
00252 uint iAction, iSeq, iVari;
00253 KKeyServer::Key key;
00254
00255 X() {}
00256 X( uint _iAction, uint _iSeq, uint _iVari, const KKeyServer::Key& _key )
00257 { iAction = _iAction; iSeq = _iSeq; iVari = _iVari; key = _key; }
00258
00259 int compare( const X& x )
00260 {
00261 int n = key.compare( x.key );
00262 if( n != 0 ) return n;
00263 if( iVari != x.iVari ) return iVari - x.iVari;
00264 if( iSeq != x.iSeq ) return iSeq - x.iSeq;
00265 return 0;
00266 }
00267
00268 bool operator <( const X& x ) { return compare( x ) < 0; }
00269 bool operator >( const X& x ) { return compare( x ) > 0; }
00270 bool operator <=( const X& x ) { return compare( x ) <= 0; }
00271 };
00272 #endif //Q_WS_X11
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
00316 bool TDEAccelBase::updateConnections()
00317 {
00318 #ifdef Q_WS_X11
00319 kdDebug(125) << "TDEAccelBase::updateConnections() this = " << this << endl;
00320
00321
00322 TQValueVector<X> rgKeys;
00323 createKeyList( rgKeys );
00324 m_rgActionsNonUnique.clear();
00325
00326 KKeyToActionMap mapKeyToAction;
00327 for( uint i = 0; i < rgKeys.size(); i++ ) {
00328 X& x = rgKeys[i];
00329 KKeyServer::Key& key = x.key;
00330 ActionInfo info;
00331 bool bNonUnique = false;
00332
00333 info.pAction = m_rgActions.actionPtr( x.iAction );
00334 info.iSeq = x.iSeq;
00335 info.iVariation = x.iVari;
00336
00337
00338 if( info.pAction->shortcut().seq(info.iSeq).count() > 1 )
00339 bNonUnique = true;
00340
00341 else if( i < rgKeys.size() - 1 && key == rgKeys[i+1].key ) {
00342
00343
00344 if( info.iVariation == rgKeys[i+1].iVari && info.iSeq == rgKeys[i+1].iSeq )
00345 bNonUnique = true;
00346
00347 kdDebug(125) << "key conflict = " << key.key().toStringInternal()
00348 << " action1 = " << info.pAction->name()
00349 << " action2 = " << m_rgActions.actionPtr( rgKeys[i+1].iAction )->name()
00350 << " non-unique = " << bNonUnique << endl;
00351
00352
00353 while( i < rgKeys.size() - 1 && key == rgKeys[i+1].key )
00354 i++;
00355 }
00356
00357 if( bNonUnique ) {
00358
00359 if( m_mapKeyToAction.contains( key ) ) {
00360 TDEAccelAction* pAction = m_mapKeyToAction[key].pAction;
00361 if( pAction ) {
00362 m_mapKeyToAction.remove( key );
00363 disconnectKey( *pAction, key );
00364 pAction->decConnections();
00365 m_rgActionsNonUnique.append( pAction );
00366 }
00367 }
00368
00369 m_rgActionsNonUnique.append( info.pAction );
00370 info.pAction = 0;
00371 }
00372
00373 kdDebug(125) << "mapKeyToAction[" << key.key().toStringInternal() << "] = " << info.pAction << endl;
00374 mapKeyToAction[key] = info;
00375 }
00376
00377
00378 for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
00379 const KKeyServer::Key& key = it.key();
00380 TDEAccelAction* pAction = (*it).pAction;
00381
00382 if( !mapKeyToAction.contains( key ) || mapKeyToAction[key].pAction != pAction ) {
00383 if( pAction ) {
00384 disconnectKey( *pAction, key );
00385 pAction->decConnections();
00386 } else
00387 disconnectKey( key );
00388 }
00389 }
00390
00391
00392
00393
00394 for( KKeyToActionMap::iterator it = mapKeyToAction.begin(); it != mapKeyToAction.end(); ++it ) {
00395 const KKeyServer::Key& key = it.key();
00396 TDEAccelAction* pAction = (*it).pAction;
00397 if( !m_mapKeyToAction.contains( key ) || m_mapKeyToAction[key].pAction != pAction ) {
00398
00399
00400 if( pAction ) {
00401 if( connectKey( *pAction, key ) )
00402 pAction->incConnections();
00403 } else
00404 connectKey( key );
00405 }
00406 }
00407
00408
00409 m_mapKeyToAction = mapKeyToAction;
00410
00411 #ifndef NDEBUG
00412 for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
00413 kdDebug(125) << "Key: " << it.key().key().toStringInternal() << " => '"
00414 << (((*it).pAction) ? (*it).pAction->name() : TQString::null) << "'" << endl;
00415 }
00416 #endif
00417 #endif //Q_WS_X11
00418 return true;
00419 }
00420
00421 #ifdef Q_WS_X11
00422
00423 void TDEAccelBase::createKeyList( TQValueVector<struct X>& rgKeys )
00424 {
00425 kdDebug(125) << "TDEAccelBase::createKeyList()" << endl;
00426 if( !isEnabledInternal()) {
00427 return;
00428 }
00429
00430
00431
00432 for( uint iAction = 0; iAction < m_rgActions.count(); iAction++ ) {
00433 TDEAccelAction* pAction = m_rgActions.actionPtr( iAction );
00434 if( pAction && pAction->m_pObjSlot && pAction->m_psMethodSlot && pAction != mtemp_pActionRemoving ) {
00435
00436 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00437 const KKeySequence& seq = pAction->shortcut().seq(iSeq);
00438 if( seq.count() > 0 ) {
00439 KKeyServer::Variations vars;
00440 vars.init( seq.key(0), !m_bNativeKeys );
00441 for( uint iVari = 0; iVari < vars.count(); iVari++ ) {
00442 if( vars.key(iVari).code() && vars.key(iVari).sym() ) {
00443 rgKeys.push_back( X( iAction, iSeq, iVari, vars.key( iVari ) ) );
00444 }
00445 kdDebug(125) << "\t" << pAction->name() << ": " << vars.key(iVari).key().toStringInternal() << " [action specified: " << pAction->toStringInternal() << "]" << endl;
00446 }
00447 }
00448
00449
00450
00451 }
00452 }
00453 }
00454
00455
00456 qHeapSort( rgKeys.begin(), rgKeys.end() );
00457 }
00458 #endif //Q_WS_X11
00459
00460 bool TDEAccelBase::insertConnection( TDEAccelAction* pAction )
00461 {
00462 if( !pAction->m_pObjSlot || !pAction->m_psMethodSlot )
00463 return true;
00464
00465 kdDebug(125) << "TDEAccelBase::insertConnection( " << pAction << "=\"" << pAction->m_sName << "\"; shortcut = " << pAction->shortcut().toStringInternal() << " ) this = " << this << endl;
00466
00467
00468 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00469
00470 KKeyServer::Variations vars;
00471 vars.init( pAction->shortcut().seq(iSeq).key(0), !m_bNativeKeys );
00472 for( uint iVari = 0; iVari < vars.count(); iVari++ ) {
00473 const KKeyServer::Key& key = vars.key( iVari );
00474
00475
00476 if( key.sym() ) {
00477 if( !m_mapKeyToAction.contains( key ) ) {
00478
00479 if( pAction->shortcut().seq(iSeq).count() == 1 ) {
00480 m_mapKeyToAction[key] = ActionInfo( pAction, iSeq, iVari );
00481 if( connectKey( *pAction, key ) )
00482 pAction->incConnections();
00483 }
00484
00485 else {
00486 m_mapKeyToAction[key] = ActionInfo( 0, 0, 0 );
00487
00488 if( m_rgActionsNonUnique.findIndex( pAction ) == -1 )
00489 m_rgActionsNonUnique.append( pAction );
00490 if( connectKey( key ) )
00491 pAction->incConnections();
00492 }
00493 } else {
00494
00495
00496
00497 if( m_mapKeyToAction[key].pAction != pAction
00498 && m_mapKeyToAction[key].pAction != 0 ) {
00499 kdDebug(125) << "Key conflict with action = " << m_mapKeyToAction[key].pAction->name()
00500 << " key = " << key.key().toStringInternal() << " : call updateConnections()" << endl;
00501 return updateConnections();
00502 }
00503 }
00504 }
00505 }
00506 }
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520 return true;
00521 }
00522
00523 bool TDEAccelBase::removeConnection( TDEAccelAction* pAction )
00524 {
00525 kdDebug(125) << "TDEAccelBase::removeConnection( " << pAction << " = \"" << pAction->m_sName << "\"; shortcut = " << pAction->m_cut.toStringInternal() << " ): this = " << this << endl;
00526
00527
00528
00529
00530 if( m_rgActionsNonUnique.findIndex( pAction ) >= 0 ) {
00531 mtemp_pActionRemoving = pAction;
00532 bool b = updateConnections();
00533 mtemp_pActionRemoving = 0;
00534 return b;
00535 }
00536
00537 KKeyToActionMap::iterator it = m_mapKeyToAction.begin();
00538 while( it != m_mapKeyToAction.end() ) {
00539 KKeyServer::Key key = it.key();
00540 ActionInfo* pInfo = &(*it);
00541
00542
00543 if( pAction == pInfo->pAction ) {
00544 disconnectKey( *pAction, key );
00545 pAction->decConnections();
00546
00547 KKeyToActionMap::iterator itRemove = it++;
00548 m_mapKeyToAction.remove( itRemove );
00549 } else
00550 ++it;
00551 }
00552 return true;
00553 }
00554
00555 bool TDEAccelBase::setShortcut( const TQString& sAction, const TDEShortcut& cut )
00556 {
00557 TDEAccelAction* pAction = actionPtr( sAction );
00558 if( pAction ) {
00559 if( m_bAutoUpdate )
00560 removeConnection( pAction );
00561
00562 pAction->setShortcut( cut );
00563
00564 if( m_bAutoUpdate && !pAction->shortcut().isNull() )
00565 insertConnection( pAction );
00566 return true;
00567 } else
00568 return false;
00569 }
00570
00571 void TDEAccelBase::readSettings( TDEConfigBase* pConfig )
00572 {
00573 m_rgActions.readActions( m_sConfigGroup, pConfig );
00574 if( m_bAutoUpdate )
00575 updateConnections();
00576 }
00577
00578 void TDEAccelBase::writeSettings( TDEConfigBase* pConfig ) const
00579 {
00580 m_rgActions.writeActions( m_sConfigGroup, pConfig, m_bConfigIsGlobal, m_bConfigIsGlobal );
00581 }
00582
00583 TQPopupMenu* TDEAccelBase::createPopupMenu( TQWidget* pParent, const KKeySequence& seq )
00584 {
00585 TDEShortcutMenu* pMenu = new TDEShortcutMenu( pParent, &actions(), seq );
00586
00587 bool bActionInserted = false;
00588 bool bInsertSeparator = false;
00589 for( uint i = 0; i < actionCount(); i++ ) {
00590 const TDEAccelAction* pAction = actions().actionPtr( i );
00591
00592 if( !pAction->isEnabled() )
00593 continue;
00594
00595
00596
00597
00598 if( bActionInserted && !pAction->isConfigurable() && pAction->name().contains( ':' ) )
00599 bInsertSeparator = true;
00600
00601 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
00602 const KKeySequence& seqAction = pAction->shortcut().seq(iSeq);
00603 if( seqAction.startsWith( seq ) ) {
00604 if( bInsertSeparator ) {
00605 pMenu->insertSeparator();
00606 bInsertSeparator = false;
00607 }
00608
00609 pMenu->insertAction( i, seqAction );
00610
00611
00612
00613 bActionInserted = true;
00614 break;
00615 }
00616 }
00617 }
00618 pMenu->updateShortcuts();
00619 return pMenu;
00620 }