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 <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 // 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 QString& sAction ) 00073 { return m_rgActions.actionPtr( sAction ); } 00074 00075 const KAccelAction* KAccelBase::actionPtr( const QString& 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 QString& sConfigGroup ) 00094 { m_sConfigGroup = sConfigGroup; } 00095 00096 void KAccelBase::setConfigGlobal( bool global ) 00097 { m_bConfigIsGlobal = global; } 00098 00099 bool KAccelBase::setActionEnabled( const QString& 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 QString& sAction, const QString& sDesc, const QString& sHelp, 00130 const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4, 00131 const QObject* pObjSlot, const char* psMethodSlot, 00132 bool bConfigurable, bool bEnabled ) 00133 { 00134 //kdDebug(125) << "KAccelBase::insert() begin" << endl; 00135 KAccelAction* pAction = m_rgActions.insert( 00136 sAction, sDesc, sHelp, 00137 rgCutDefaults3, rgCutDefaults4, 00138 pObjSlot, psMethodSlot, 00139 bConfigurable, bEnabled ); 00140 00141 if( pAction && m_bAutoUpdate ) 00142 insertConnection( pAction ); 00143 00144 //kdDebug(125) << "KAccelBase::insert() end" << endl; 00145 return pAction; 00146 } 00147 00148 KAccelAction* KAccelBase::insert( const QString& sName, const QString& sDesc ) 00149 { return m_rgActions.insert( sName, sDesc ); } 00150 00151 bool KAccelBase::remove( const QString& sAction ) 00152 { 00153 return m_rgActions.remove( sAction ); 00154 } 00155 00156 void KAccelBase::slotRemoveAction( KAccelAction* pAction ) 00157 { 00158 removeConnection( pAction ); 00159 } 00160 00161 bool KAccelBase::setActionSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot ) 00162 { 00163 kdDebug(125) << "KAccelBase::setActionSlot( " << sAction << ", " << pObjSlot << ", " << psMethodSlot << " )\n"; 00164 KAccelAction* pAction = m_rgActions.actionPtr( sAction ); 00165 if( pAction ) { 00166 // If there was a previous connection, remove it. 00167 if( m_bAutoUpdate && pAction->isConnected() ) { 00168 kdDebug(125) << "\tm_pObjSlot = " << pAction->m_pObjSlot << " m_psMethodSlot = " << pAction->m_psMethodSlot << endl; 00169 removeConnection( pAction ); 00170 } 00171 00172 pAction->m_pObjSlot = pObjSlot; 00173 pAction->m_psMethodSlot = psMethodSlot; 00174 00175 // If we're setting a connection, 00176 if( m_bAutoUpdate && pObjSlot && psMethodSlot ) 00177 insertConnection( pAction ); 00178 00179 return true; 00180 } else 00181 return false; 00182 } 00183 00184 /* 00185 KAccelBase 00186 Run Command=Meta+Enter;Alt+F2 00187 KAccelAction = "Run Command" 00188 1) KAccelKeySeries = "Meta+Enter" 00189 1a) Meta+Enter 00190 1b) Meta+Keypad_Enter 00191 2) KAccelKeySeries = "Alt+F2" 00192 1a) Alt+F2 00193 00194 Konqueror=Meta+I,I 00195 KAccelAction = "Konqueror" 00196 1) KAccelKeySeries = "Meta+I,I" 00197 1a) Meta+I 00198 2a) I 00199 00200 Something=Meta+Asterisk,X 00201 KAccelAction = "Something" 00202 1) KAccelKeySeries = "Meta+Asterisk,X" 00203 1a) Meta+Shift+8 00204 1b) Meta+Keypad_8 00205 2a) X 00206 00207 read in a config entry 00208 split by ';' 00209 find key sequences to disconnect 00210 find new key sequences to connect 00211 check for conflicts with implicit keys 00212 disconnect conflicting implicit keys 00213 connect new key sequences 00214 */ 00215 /* 00216 { 00217 For { 00218 for( KAccelAction::iterator itAction = m_rgActions.begin(); itAction != m_rgActions.end(); ++itAction ) { 00219 KAccelAction& action = *itAction; 00220 for( KAccelSeries::iterator itSeries = action.m_rgSeries.begin(); itSeries != action.m_rgSeries.end(); ++itSeries ) { 00221 KAccelSeries& series = *itSeries; 00222 if( 00223 } 00224 } 00225 } 00226 Sort by: iVariation, iSequence, iSeries, iAction 00227 00228 1) KAccelAction = "Run Command" 00229 1) KAccelKeySeries = "Meta+Enter" 00230 1a) Meta+Enter 00231 1b) Meta+Keypad_Enter 00232 2) KAccelKeySeries = "Alt+F2" 00233 1a) Alt+F2 00234 00235 2) KAccelAction = "Enter Calculation" 00236 1) KAccelKeySeries = "Meta+Keypad_Enter" 00237 1a) Meta+Keypad_Enter 00238 00239 List = 00240 Meta+Enter -> 1, 1, 1a 00241 Meta+Keypad_Enter -> 2, 1, 1a 00242 Alt+F2 -> 1, 2, 1a 00243 [Meta+Keypad_Enter] -> [1, 1, 1b] 00244 00245 } 00246 */ 00247 00248 #ifdef Q_WS_X11 00249 struct KAccelBase::X 00250 { 00251 uint iAction, iSeq, iVari; 00252 KKeyServer::Key key; 00253 00254 X() {} 00255 X( uint _iAction, uint _iSeq, uint _iVari, const KKeyServer::Key& _key ) 00256 { iAction = _iAction; iSeq = _iSeq; iVari = _iVari; key = _key; } 00257 00258 int compare( const X& x ) 00259 { 00260 int n = key.compare( x.key ); 00261 if( n != 0 ) return n; 00262 if( iVari != x.iVari ) return iVari - x.iVari; 00263 if( iSeq != x.iSeq ) return iSeq - x.iSeq; 00264 return 0; 00265 } 00266 00267 bool operator <( const X& x ) { return compare( x ) < 0; } 00268 bool operator >( const X& x ) { return compare( x ) > 0; } 00269 bool operator <=( const X& x ) { return compare( x ) <= 0; } 00270 }; 00271 #endif //Q_WS_X11 00272 00273 /* 00274 #1 Ctrl+A 00275 #2 Ctrl+A 00276 #3 Ctrl+B 00277 ------ 00278 Ctrl+A => Null 00279 Ctrl+B => #3 00280 00281 #1 Ctrl+A 00282 #1 Ctrl+B;Ctrl+A 00283 ------ 00284 Ctrl+A => #1 00285 Ctrl+B => #2 00286 00287 #1 Ctrl+A 00288 #1 Ctrl+B,C 00289 #1 Ctrl+B,D 00290 ------ 00291 Ctrl+A => #1 00292 Ctrl+B => Null 00293 00294 #1 Ctrl+A 00295 #2 Ctrl+Plus(Ctrl+KP_Add) 00296 ------ 00297 Ctrl+A => #1 00298 Ctrl+Plus => #2 00299 Ctrl+KP_Add => #2 00300 00301 #1 Ctrl+Plus(Ctrl+KP_Add) 00302 #2 Ctrl+KP_Add 00303 ------ 00304 Ctrl+Plus => #1 00305 Ctrl+KP_Add => #2 00306 00307 #1 Ctrl+Plus(Ctrl+KP_Add) 00308 #2 Ctrl+A;Ctrl+KP_Add 00309 ------ 00310 Ctrl+A => #2 00311 Ctrl+Plus => #1 00312 Ctrl+KP_Add => #2 00313 */ 00314 00315 bool KAccelBase::updateConnections() 00316 { 00317 #ifdef Q_WS_X11 00318 kdDebug(125) << "KAccelBase::updateConnections() this = " << this << endl; 00319 // Retrieve the list of keys to be connected, sorted by priority. 00320 // (key, variation, seq) 00321 QValueVector<X> rgKeys; 00322 createKeyList( rgKeys ); 00323 m_rgActionsNonUnique.clear(); 00324 00325 KKeyToActionMap mapKeyToAction; 00326 for( uint i = 0; i < rgKeys.size(); i++ ) { 00327 X& x = rgKeys[i]; 00328 KKeyServer::Key& key = x.key; 00329 ActionInfo info; 00330 bool bNonUnique = false; 00331 00332 info.pAction = m_rgActions.actionPtr( x.iAction ); 00333 info.iSeq = x.iSeq; 00334 info.iVariation = x.iVari; 00335 00336 // If this is a multi-key shortcut, 00337 if( info.pAction->shortcut().seq(info.iSeq).count() > 1 ) 00338 bNonUnique = true; 00339 // If this key is requested by more than one action, 00340 else if( i < rgKeys.size() - 1 && key == rgKeys[i+1].key ) { 00341 // If multiple actions requesting this key 00342 // have the same priority as the first one, 00343 if( info.iVariation == rgKeys[i+1].iVari && info.iSeq == rgKeys[i+1].iSeq ) 00344 bNonUnique = true; 00345 00346 kdDebug(125) << "key conflict = " << key.key().toStringInternal() 00347 << " action1 = " << info.pAction->name() 00348 << " action2 = " << m_rgActions.actionPtr( rgKeys[i+1].iAction )->name() 00349 << " non-unique = " << bNonUnique << endl; 00350 00351 // Skip over the other records with this same key. 00352 while( i < rgKeys.size() - 1 && key == rgKeys[i+1].key ) 00353 i++; 00354 } 00355 00356 if( bNonUnique ) { 00357 // Remove connection to single action if there is one 00358 if( m_mapKeyToAction.contains( key ) ) { 00359 KAccelAction* pAction = m_mapKeyToAction[key].pAction; 00360 if( pAction ) { 00361 m_mapKeyToAction.remove( key ); 00362 disconnectKey( *pAction, key ); 00363 pAction->decConnections(); 00364 m_rgActionsNonUnique.append( pAction ); 00365 } 00366 } 00367 // Indicate that no single action is associated with this key. 00368 m_rgActionsNonUnique.append( info.pAction ); 00369 info.pAction = 0; 00370 } 00371 00372 //kdDebug(125) << "mapKeyToAction[" << key.toStringInternal() << "] = " << info.pAction << endl; 00373 mapKeyToAction[key] = info; 00374 } 00375 00376 // Disconnect keys which no longer have bindings: 00377 for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) { 00378 const KKeyServer::Key& key = it.key(); 00379 KAccelAction* pAction = (*it).pAction; 00380 // If this key is longer used or it points to a different action now, 00381 if( !mapKeyToAction.contains( key ) || mapKeyToAction[key].pAction != pAction ) { 00382 if( pAction ) { 00383 disconnectKey( *pAction, key ); 00384 pAction->decConnections(); 00385 } else 00386 disconnectKey( key ); 00387 } 00388 } 00389 00390 // Connect any unconnected keys: 00391 // In other words, connect any keys which are present in the 00392 // new action map, but which are _not_ present in the old one. 00393 for( KKeyToActionMap::iterator it = mapKeyToAction.begin(); it != mapKeyToAction.end(); ++it ) { 00394 const KKeyServer::Key& key = it.key(); 00395 KAccelAction* pAction = (*it).pAction; 00396 if( !m_mapKeyToAction.contains( key ) || m_mapKeyToAction[key].pAction != pAction ) { 00397 // TODO: Decide what to do if connect fails. 00398 // Probably should remove this item from map. 00399 if( pAction ) { 00400 if( connectKey( *pAction, key ) ) 00401 pAction->incConnections(); 00402 } else 00403 connectKey( key ); 00404 } 00405 } 00406 00407 // Store new map. 00408 m_mapKeyToAction = mapKeyToAction; 00409 00410 #ifndef NDEBUG 00411 for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) { 00412 kdDebug(125) << "Key: " << it.key().key().toStringInternal() << " => '" 00413 << (((*it).pAction) ? (*it).pAction->name() : QString::null) << "'" << endl; 00414 } 00415 #endif 00416 #endif //Q_WS_X11 00417 return true; 00418 } 00419 00420 #ifdef Q_WS_X11 00421 // Construct a list of keys to be connected, sorted highest priority first. 00422 void KAccelBase::createKeyList( QValueVector<struct X>& rgKeys ) 00423 { 00424 //kdDebug(125) << "KAccelBase::createKeyList()" << endl; 00425 if( !isEnabledInternal()) 00426 return; 00427 00428 // create the list 00429 // For each action 00430 for( uint iAction = 0; iAction < m_rgActions.count(); iAction++ ) { 00431 KAccelAction* pAction = m_rgActions.actionPtr( iAction ); 00432 if( pAction && pAction->m_pObjSlot && pAction->m_psMethodSlot && pAction != mtemp_pActionRemoving ) { 00433 // For each key sequence associated with action 00434 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) { 00435 const KKeySequence& seq = pAction->shortcut().seq(iSeq); 00436 if( seq.count() > 0 ) { 00437 KKeyServer::Variations vars; 00438 vars.init( seq.key(0), !m_bNativeKeys ); 00439 for( uint iVari = 0; iVari < vars.count(); iVari++ ) { 00440 if( vars.key(iVari).code() && vars.key(iVari).sym() ) 00441 rgKeys.push_back( X( iAction, iSeq, iVari, vars.key( iVari ) ) ); 00442 //kdDebug(125) << "\t" << pAction->name() << ": " << vars.key(iVari).toStringInternal() << endl; 00443 } 00444 } 00445 //else 00446 // kdDebug(125) << "\t*" << pAction->name() << ":" << endl; 00447 } 00448 } 00449 } 00450 00451 // sort by priority: iVariation[of first key], iSequence, iAction 00452 qHeapSort( rgKeys.begin(), rgKeys.end() ); 00453 } 00454 #endif //Q_WS_X11 00455 00456 bool KAccelBase::insertConnection( KAccelAction* pAction ) 00457 { 00458 if( !pAction->m_pObjSlot || !pAction->m_psMethodSlot ) 00459 return true; 00460 00461 kdDebug(125) << "KAccelBase::insertConnection( " << pAction << "=\"" << pAction->m_sName << "\"; shortcut = " << pAction->shortcut().toStringInternal() << " ) this = " << this << endl; 00462 00463 // For each sequence associated with the given action: 00464 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) { 00465 // Get the first key of the sequence. 00466 KKeyServer::Variations vars; 00467 vars.init( pAction->shortcut().seq(iSeq).key(0), !m_bNativeKeys ); 00468 for( uint iVari = 0; iVari < vars.count(); iVari++ ) { 00469 const KKeyServer::Key& key = vars.key( iVari ); 00470 00471 //if( !key.isNull() ) { 00472 if( key.sym() ) { 00473 if( !m_mapKeyToAction.contains( key ) ) { 00474 // If this is a single-key shortcut, 00475 if( pAction->shortcut().seq(iSeq).count() == 1 ) { 00476 m_mapKeyToAction[key] = ActionInfo( pAction, iSeq, iVari ); 00477 if( connectKey( *pAction, key ) ) 00478 pAction->incConnections(); 00479 } 00480 // Else this is a multi-key shortcut, 00481 else { 00482 m_mapKeyToAction[key] = ActionInfo( 0, 0, 0 ); 00483 // Insert into non-unique list if it's not already there. 00484 if( m_rgActionsNonUnique.findIndex( pAction ) == -1 ) 00485 m_rgActionsNonUnique.append( pAction ); 00486 if( connectKey( key ) ) 00487 pAction->incConnections(); 00488 } 00489 } else { 00490 // There is a key conflict. A full update 00491 // check is necessary. 00492 // TODO: make this more efficient where possible. 00493 if( m_mapKeyToAction[key].pAction != pAction 00494 && m_mapKeyToAction[key].pAction != 0 ) { 00495 kdDebug(125) << "Key conflict with action = " << m_mapKeyToAction[key].pAction->name() 00496 << " key = " << key.key().toStringInternal() << " : call updateConnections()" << endl; 00497 return updateConnections(); 00498 } 00499 } 00500 } 00501 } 00502 } 00503 00504 //kdDebug(125) << "\tActions = " << m_rgActions.size() << endl; 00505 //for( KAccelActions::const_iterator it = m_rgActions.begin(); it != m_rgActions.end(); ++it ) { 00506 // kdDebug(125) << "\t" << &(*it) << " '" << (*it).m_sName << "'" << endl; 00507 //} 00508 00509 //kdDebug(125) << "\tKeys = " << m_mapKeyToAction.size() << endl; 00510 //for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) { 00511 // //kdDebug(125) << "\tKey: " << it.key().toString() << " => '" << (*it)->m_sName << "'" << endl; 00512 // kdDebug(125) << "\tKey: " << it.key().toString() << " => '" << *it << "'" << endl; 00513 // kdDebug(125) << "\t\t'" << (*it)->m_sName << "'" << endl; 00514 //} 00515 00516 return true; 00517 } 00518 00519 bool KAccelBase::removeConnection( KAccelAction* pAction ) 00520 { 00521 kdDebug(125) << "KAccelBase::removeConnection( " << pAction << " = \"" << pAction->m_sName << "\"; shortcut = " << pAction->m_cut.toStringInternal() << " ): this = " << this << endl; 00522 00523 //for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) 00524 // kdDebug(125) << "\tKey: " << it.key().toString() << " => '" << (*it)->m_sName << "'" << " " << *it << endl; 00525 00526 if( m_rgActionsNonUnique.findIndex( pAction ) >= 0 ) { 00527 mtemp_pActionRemoving = pAction; 00528 bool b = updateConnections(); 00529 mtemp_pActionRemoving = 0; 00530 return b; 00531 } 00532 00533 KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); 00534 while( it != m_mapKeyToAction.end() ) { 00535 KKeyServer::Key key = it.key(); 00536 ActionInfo* pInfo = &(*it); 00537 00538 // If the given action is connected to this key, 00539 if( pAction == pInfo->pAction ) { 00540 disconnectKey( *pAction, key ); 00541 pAction->decConnections(); 00542 00543 KKeyToActionMap::iterator itRemove = it++; 00544 m_mapKeyToAction.remove( itRemove ); 00545 } else 00546 ++it; 00547 } 00548 return true; 00549 } 00550 00551 bool KAccelBase::setShortcut( const QString& sAction, const KShortcut& cut ) 00552 { 00553 KAccelAction* pAction = actionPtr( sAction ); 00554 if( pAction ) { 00555 if( m_bAutoUpdate ) 00556 removeConnection( pAction ); 00557 00558 pAction->setShortcut( cut ); 00559 00560 if( m_bAutoUpdate && !pAction->shortcut().isNull() ) 00561 insertConnection( pAction ); 00562 return true; 00563 } else 00564 return false; 00565 } 00566 00567 void KAccelBase::readSettings( KConfigBase* pConfig ) 00568 { 00569 m_rgActions.readActions( m_sConfigGroup, pConfig ); 00570 if( m_bAutoUpdate ) 00571 updateConnections(); 00572 } 00573 00574 void KAccelBase::writeSettings( KConfigBase* pConfig ) const 00575 { 00576 m_rgActions.writeActions( m_sConfigGroup, pConfig, m_bConfigIsGlobal, m_bConfigIsGlobal ); 00577 } 00578 00579 QPopupMenu* KAccelBase::createPopupMenu( QWidget* pParent, const KKeySequence& seq ) 00580 { 00581 KShortcutMenu* pMenu = new KShortcutMenu( pParent, &actions(), seq ); 00582 00583 bool bActionInserted = false; 00584 bool bInsertSeparator = false; 00585 for( uint i = 0; i < actionCount(); i++ ) { 00586 const KAccelAction* pAction = actions().actionPtr( i ); 00587 00588 if( !pAction->isEnabled() ) 00589 continue; 00590 00591 // If an action has already been inserted into the menu 00592 // and we have a label instead of an action here, 00593 // then indicate that we should insert a separator before the next menu entry. 00594 if( bActionInserted && !pAction->isConfigurable() && pAction->name().contains( ':' ) ) 00595 bInsertSeparator = true; 00596 00597 for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) { 00598 const KKeySequence& seqAction = pAction->shortcut().seq(iSeq); 00599 if( seqAction.startsWith( seq ) ) { 00600 if( bInsertSeparator ) { 00601 pMenu->insertSeparator(); 00602 bInsertSeparator = false; 00603 } 00604 00605 pMenu->insertAction( i, seqAction ); 00606 00607 //kdDebug(125) << "sLabel = " << sLabel << ", seq = " << (QString)seqMenu.qt() << ", i = " << i << endl; 00608 //kdDebug(125) << "pMenu->accel(" << i << ") = " << (QString)pMenu->accel(i) << endl; 00609 bActionInserted = true; 00610 break; 00611 } 00612 } 00613 } 00614 pMenu->updateShortcuts(); 00615 return pMenu; 00616 }