kaccelbase.cpp
00001 /* 00002 Copyright (C) 1997-2000 Nicolas Hadacek <hadacek@kde.org> 00003 Copyright (C) 1998 Mark Donohoe <donohoe@kde.org> 00004 Copyright (C) 1998 Matthias Ettrich <ettrich@kde.org> 00005 Copyright (c) 2001,2002 Ellis Whitehead <ellis@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "kaccelbase.h" 00024 00025 #include <tqkeycode.h> 00026 #include <tqlabel.h> 00027 #include <tqpopupmenu.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 // class KAccelBase::ActionInfo 00040 //--------------------------------------------------------------------- 00041 00042 //--------------------------------------------------------------------- 00043 // class KAccelBase 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 // see KGlobalAccel::blockShortcuts() stuff - it's to temporarily block 00067 // all global shortcuts, so that the key grabs are released, but from the app's 00068 // point of view the KGlobalAccel is still enabled, so KGlobalAccel needs 00069 // to disable key grabbing even if enabled 00070 bool KAccelBase::isEnabledInternal() const { return isEnabled(); } 00071 00072 KAccelAction* KAccelBase::actionPtr( const TQString& sAction ) 00073 { return m_rgActions.actionPtr( sAction ); } 00074 00075 const KAccelAction* KAccelBase::actionPtr( const TQString& 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 // Note: If more than one action is connected to a single key, nil will be returned. 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 TQString& sConfigGroup ) 00094 { m_sConfigGroup = sConfigGroup; } 00095 00096 void KAccelBase::setConfigGlobal( bool global ) 00097 { m_bConfigIsGlobal = global; } 00098 00099 bool KAccelBase::setActionEnabled( const TQString& 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 // FIXME: the action may already have it's connections inserted! 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 TQString& sAction, const TQString& sDesc, const TQString& sHelp, 00130 const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4, 00131 const TQObject* pObjSlot, const char* psMethodSlot, 00132 bool bConfigurable, bool bEnabled ) 00133 { 00134 kdDebug(125) << "KAccelBase::insert() begin" << endl; 00135 kdDebug(125) << "\t" << sAction << ": " << rgCutDefaults3.toString() << ": " << rgCutDefaults4.toString() << endl; 00136 KAccelAction* 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 //kdDebug(125) << "KAccelBase::insert() end" << endl; 00146 return pAction; 00147 } 00148 00149 KAccelAction* KAccelBase::insert( const TQString& sName, const TQString& sDesc ) 00150 { return m_rgActions.insert( sName, sDesc ); } 00151 00152 bool KAccelBase::remove( const TQString& sAction ) 00153 { 00154 return m_rgActions.remove( sAction ); 00155 } 00156 00157 void KAccelBase::slotRemoveAction( KAccelAction* pAction ) 00158 { 00159 removeConnection( pAction ); 00160 } 00161 00162 bool KAccelBase::setActionSlot( const TQString& sAction, const TQObject* pObjSlot, const char* psMethodSlot ) 00163 { 00164 kdDebug(125) << "KAccelBase::setActionSlot( " << sAction << ", " << pObjSlot << ", " << psMethodSlot << " )\n"; 00165 KAccelAction* pAction = m_rgActions.actionPtr( sAction ); 00166 if( pAction ) { 00167 // If there was a previous connection, remove it. 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 // If we're setting a connection, 00177 if( m_bAutoUpdate && pObjSlot && psMethodSlot ) 00178 insertConnection( pAction ); 00179 00180 return true; 00181 } else 00182 return false; 00183 } 00184 00185 /* 00186 KAccelBase 00187 Run Command=Meta+Enter;Alt+F2 00188 KAccelAction = "Run Command" 00189 1) KAccelKeySeries = "Meta+Enter" 00190 1a) Meta+Enter 00191 1b) Meta+Keypad_Enter 00192 2) KAccelKeySeries = "Alt+F2" 00193 1a) Alt+F2 00194 00195 Konqueror=Meta+I,I 00196 KAccelAction = "Konqueror" 00197 1) KAccelKeySeries = "Meta+I,I" 00198 1a) Meta+I 00199 2a) I 00200 00201 Something=Meta+Asterisk,X 00202 KAccelAction = "Something" 00203 1) KAccelKeySeries = "Meta+Asterisk,X" 00204 1a) Meta+Shift+8 00205 1b) Meta+Keypad_8 00206 2a) X 00207 00208 read in a config entry 00209 split by ';' 00210 find key sequences to disconnect 00211 find new key sequences to connect 00212 check for conflicts with implicit keys 00213 disconnect conflicting implicit keys 00214 connect new key sequences 00215 */ 00216 /* 00217 { 00218 For { 00219 for( KAccelAction::iterator itAction = m_rgActions.begin(); itAction != m_rgActions.end(); ++itAction ) { 00220 KAccelAction& action = *itAction; 00221 for( KAccelSeries::iterator itSeries = action.m_rgSeries.begin(); itSeries != action.m_rgSeries.end(); ++itSeries ) { 00222 KAccelSeries& series = *itSeries; 00223 if( 00224 } 00225 } 00226 } 00227 Sort by: iVariation, iSequence, iSeries, iAction 00228 00229 1) KAccelAction = "Run Command" 00230 1) KAccelKeySeries = "Meta+Enter" 00231 1a) Meta+Enter 00232 1b) Meta+Keypad_Enter 00233 2) KAccelKeySeries = "Alt+F2" 00234 1a) Alt+F2 00235 00236 2) KAccelAction = "Enter Calculation" 00237 1) KAccelKeySeries = "Meta+Keypad_Enter" 00238 1a) Meta+Keypad_Enter 00239 00240 List = 00241 Meta+Enter -> 1, 1, 1a 00242 Meta+Keypad_Enter -> 2, 1, 1a 00243 Alt+F2 -> 1, 2, 1a 00244 [Meta+Keypad_Enter] -> [1, 1, 1b] 00245 00246 } 00247 */ 00248 00249 #ifdef Q_WS_X11 00250 struct KAccelBase::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 #1 Ctrl+A 00276 #2 Ctrl+A 00277 #3 Ctrl+B 00278 ------ 00279 Ctrl+A => Null 00280 Ctrl+B => #3 00281 00282 #1 Ctrl+A 00283 #1 Ctrl+B;Ctrl+A 00284 ------ 00285 Ctrl+A => #1 00286 Ctrl+B => #2 00287 00288 #1 Ctrl+A 00289 #1 Ctrl+B,C 00290 #1 Ctrl+B,D 00291 ------ 00292 Ctrl+A => #1 00293 Ctrl+B => Null 00294 00295 #1 Ctrl+A 00296 #2 Ctrl+Plus(Ctrl+KP_Add) 00297 ------ 00298 Ctrl+A => #1 00299 Ctrl+Plus => #2 00300 Ctrl+KP_Add => #2 00301 00302 #1 Ctrl+Plus(Ctrl+KP_Add) 00303 #2 Ctrl+KP_Add 00304 ------ 00305 Ctrl+Plus => #1 00306 Ctrl+KP_Add => #2 00307 00308 #1 Ctrl+Plus(Ctrl+KP_Add) 00309 #2 Ctrl+A;Ctrl+KP_Add 00310 ------ 00311 Ctrl+A => #2 00312 Ctrl+Plus => #1 00313 Ctrl+KP_Add => #2 00314 */ 00315 00316 bool KAccelBase::updateConnections() 00317 { 00318 #ifdef Q_WS_X11 00319 kdDebug(125) << "KAccelBase::updateConnections() this = " << this << endl; 00320 // Retrieve the list of keys to be connected, sorted by priority. 00321 // (key, variation, seq) 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 // If this is a multi-key shortcut, 00338 if( info.pAction->shortcut().seq(info.iSeq).count() > 1 ) 00339 bNonUnique = true; 00340 // If this key is requested by more than one action, 00341 else if( i < rgKeys.size() - 1 && key == rgKeys[i+1].key ) { 00342 // If multiple actions requesting this key 00343 // have the same priority as the first one, 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 // Skip over the other records with this same key. 00353 while( i < rgKeys.size() - 1 && key == rgKeys[i+1].key ) 00354 i++; 00355 } 00356 00357 if( bNonUnique ) { 00358 // Remove connection to single action if there is one 00359 if( m_mapKeyToAction.contains( key ) ) { 00360 KAccelAction* 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 // Indicate that no single action is associated with this key. 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 // Disconnect keys which no longer have bindings: 00378 for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) { 00379 const KKeyServer::Key& key = it.key(); 00380 KAccelAction* pAction = (*it).pAction; 00381 // If this key is longer used or it points to a different action now, 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 // Connect any unconnected keys: 00392 // In other words, connect any keys which are present in the 00393 // new action map, but which are _not_ present in the old one. 00394 for( KKeyToActionMap::iterator it = mapKeyToAction.begin(); it != mapKeyToAction.end(); ++it ) { 00395 const KKeyServer::Key& key = it.key(); 00396 KAccelAction* pAction = (*it).pAction; 00397 if( !m_mapKeyToAction.contains( key ) || m_mapKeyToAction[key].pAction != pAction ) { 00398 // TODO: Decide what to do if connect fails. 00399 // Probably should remove this item from map. 00400 if( pAction ) { 00401 if( connectKey( *pAction, key ) ) 00402 pAction->incConnections(); 00403 } else 00404 connectKey( key ); 00405 } 00406 } 00407 00408 // Store new map. 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 // Construct a list of keys to be connected, sorted highest priority first. 00423 void KAccelBase::createKeyList( TQValueVector<struct X>& rgKeys ) 00424 { 00425 kdDebug(125) << "KAccelBase::createKeyList()" << endl; 00426 if( !isEnabledInternal()) { 00427 return; 00428 } 00429 00430 // create the list 00431 // For each action 00432 for( uint iAction = 0; iAction < m_rgActions.count(); iAction++ ) { 00433 KAccelAction* pAction = m_rgActions.actionPtr( iAction ); 00434 if( pAction && pAction->m_pObjSlot && pAction->m_psMethodSlot && pAction != mtemp_pActionRemoving ) { 00435 // For each key sequence associated with action 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 //else { 00449 // kdDebug(125) << "\t*" << pAction->name() << ":" << endl; 00450 // } 00451 } 00452 } 00453 } 00454 00455 // sort by priority: iVariation[of first key], iSequence, iAction 00456 qHeapSort( rgKeys.begin(), rgKeys.end() ); 00457 } 00458 #endif //Q_WS_X11 00459 00460 bool KAccelBase::insertConnection( KAccelAction* pAction ) 00461 { 00462 if( !pAction->m_pObjSlot || !pAction->m_psMethodSlot ) 00463 return true; 00464 00465 kdDebug(125) << "KAccelBase::insertConnection( " << pAction << "=\"" << pAction->m_sName << "\"; shortcut = " << pAction->shortcut().toStringInternal() << " ) this = " << this << endl; 00466 00467 // For each sequence associated with the given action: 00468 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) { 00469 // Get the first key of the sequence. 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 //if( !key.isNull() ) { 00476 if( key.sym() ) { 00477 if( !m_mapKeyToAction.contains( key ) ) { 00478 // If this is a single-key shortcut, 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 // Else this is a multi-key shortcut, 00485 else { 00486 m_mapKeyToAction[key] = ActionInfo( 0, 0, 0 ); 00487 // Insert into non-unique list if it's not already there. 00488 if( m_rgActionsNonUnique.findIndex( pAction ) == -1 ) 00489 m_rgActionsNonUnique.append( pAction ); 00490 if( connectKey( key ) ) 00491 pAction->incConnections(); 00492 } 00493 } else { 00494 // There is a key conflict. A full update 00495 // check is necessary. 00496 // TODO: make this more efficient where possible. 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 //kdDebug(125) << "\tActions = " << m_rgActions.size() << endl; 00509 //for( KAccelActions::const_iterator it = m_rgActions.begin(); it != m_rgActions.end(); ++it ) { 00510 // kdDebug(125) << "\t" << &(*it) << " '" << (*it).m_sName << "'" << endl; 00511 //} 00512 00513 //kdDebug(125) << "\tKeys = " << m_mapKeyToAction.size() << endl; 00514 //for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) { 00515 // //kdDebug(125) << "\tKey: " << it.key().toString() << " => '" << (*it)->m_sName << "'" << endl; 00516 // kdDebug(125) << "\tKey: " << it.key().toString() << " => '" << *it << "'" << endl; 00517 // kdDebug(125) << "\t\t'" << (*it)->m_sName << "'" << endl; 00518 //} 00519 00520 return true; 00521 } 00522 00523 bool KAccelBase::removeConnection( KAccelAction* pAction ) 00524 { 00525 kdDebug(125) << "KAccelBase::removeConnection( " << pAction << " = \"" << pAction->m_sName << "\"; shortcut = " << pAction->m_cut.toStringInternal() << " ): this = " << this << endl; 00526 00527 //for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) 00528 // kdDebug(125) << "\tKey: " << it.key().toString() << " => '" << (*it)->m_sName << "'" << " " << *it << endl; 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 // If the given action is connected to this key, 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 KAccelBase::setShortcut( const TQString& sAction, const KShortcut& cut ) 00556 { 00557 KAccelAction* 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 KAccelBase::readSettings( KConfigBase* pConfig ) 00572 { 00573 m_rgActions.readActions( m_sConfigGroup, pConfig ); 00574 if( m_bAutoUpdate ) 00575 updateConnections(); 00576 } 00577 00578 void KAccelBase::writeSettings( KConfigBase* pConfig ) const 00579 { 00580 m_rgActions.writeActions( m_sConfigGroup, pConfig, m_bConfigIsGlobal, m_bConfigIsGlobal ); 00581 } 00582 00583 TQPopupMenu* KAccelBase::createPopupMenu( TQWidget* pParent, const KKeySequence& seq ) 00584 { 00585 KShortcutMenu* pMenu = new KShortcutMenu( pParent, &actions(), seq ); 00586 00587 bool bActionInserted = false; 00588 bool bInsertSeparator = false; 00589 for( uint i = 0; i < actionCount(); i++ ) { 00590 const KAccelAction* pAction = actions().actionPtr( i ); 00591 00592 if( !pAction->isEnabled() ) 00593 continue; 00594 00595 // If an action has already been inserted into the menu 00596 // and we have a label instead of an action here, 00597 // then indicate that we should insert a separator before the next menu entry. 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 //kdDebug(125) << "sLabel = " << sLabel << ", seq = " << (TQString)seqMenu.qt() << ", i = " << i << endl; 00612 //kdDebug(125) << "pMenu->accel(" << i << ") = " << (TQString)pMenu->accel(i) << endl; 00613 bActionInserted = true; 00614 break; 00615 } 00616 } 00617 } 00618 pMenu->updateShortcuts(); 00619 return pMenu; 00620 }