tdeaccelaction.cpp
00001 /* 00002 Copyright (C) 1998 Mark Donohoe <donohoe@kde.org> 00003 Copyright (C) 1997-2000 Nicolas Hadacek <hadacek@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 "tdeaccelaction.h" 00024 #include "tdeaccelbase.h" // for TDEAccelBase::slotRemoveAction() & emitSignal() 00025 00026 #include <tqkeycode.h> 00027 00028 #include <tdeconfig.h> 00029 #include "kckey.h" 00030 #include <kdebug.h> 00031 #include <tdeglobal.h> 00032 #include <kkeynative.h> 00033 #include <tdelocale.h> 00034 #include <tdeshortcutlist.h> 00035 00036 //--------------------------------------------------------------------- 00037 // TDEAccelAction 00038 //--------------------------------------------------------------------- 00039 00040 class TDEAccelActionPrivate 00041 { 00042 public: 00043 uint m_nConnections; 00044 }; 00045 00046 TDEAccelAction::TDEAccelAction() 00047 { 00048 //kdDebug(125) << "TDEAccelAction(): this = " << this << endl; 00049 d = new TDEAccelActionPrivate; 00050 m_pObjSlot = 0; 00051 m_psMethodSlot = 0; 00052 m_bConfigurable = true; 00053 m_bEnabled = true; 00054 m_nIDAccel = 0; 00055 d->m_nConnections = 0; 00056 } 00057 00058 TDEAccelAction::TDEAccelAction( const TDEAccelAction& action ) 00059 { 00060 //kdDebug(125) << "TDEAccelAction( copy from \"" << action.m_sName << "\" ): this = " << this << endl; 00061 d = new TDEAccelActionPrivate; 00062 *this = action; 00063 } 00064 00065 TDEAccelAction::TDEAccelAction( const TQString& sName, const TQString& sLabel, const TQString& sWhatsThis, 00066 const TDEShortcut& cutDef3, const TDEShortcut& cutDef4, 00067 const TQObject* pObjSlot, const char* psMethodSlot, 00068 bool bConfigurable, bool bEnabled ) 00069 { 00070 //kdDebug(125) << "TDEAccelAction( \"" << sName << "\" ): this = " << this << endl; 00071 d = new TDEAccelActionPrivate; 00072 init( sName, sLabel, sWhatsThis, 00073 cutDef3, cutDef4, 00074 pObjSlot, psMethodSlot, 00075 bConfigurable, bEnabled ); 00076 } 00077 00078 TDEAccelAction::~TDEAccelAction() 00079 { 00080 //kdDebug(125) << "\t\t\tTDEAccelAction::~TDEAccelAction( \"" << m_sName << "\" ): this = " << this << endl; 00081 delete d; 00082 } 00083 00084 void TDEAccelAction::clear() 00085 { 00086 m_cut.clear(); 00087 m_pObjSlot = 0; 00088 m_psMethodSlot = 0; 00089 m_bConfigurable = true; 00090 m_bEnabled = true; 00091 m_nIDAccel = 0; 00092 d->m_nConnections = 0; 00093 } 00094 00095 bool TDEAccelAction::init( const TQString& sName, const TQString& sLabel, const TQString& sWhatsThis, 00096 const TDEShortcut& rgCutDefaults3, const TDEShortcut& rgCutDefaults4, 00097 const TQObject* pObjSlot, const char* psMethodSlot, 00098 bool bConfigurable, bool bEnabled ) 00099 { 00100 m_sName = sName; 00101 m_sLabel = sLabel; 00102 m_sWhatsThis = sWhatsThis; 00103 m_cutDefault3 = rgCutDefaults3; 00104 m_cutDefault4 = rgCutDefaults4; 00105 m_pObjSlot = pObjSlot; 00106 m_psMethodSlot = psMethodSlot; 00107 m_bConfigurable = bConfigurable; 00108 m_bEnabled = bEnabled; 00109 m_nIDAccel = 0; 00110 m_cut = shortcutDefault(); 00111 d->m_nConnections = 0; 00112 if( !m_bEnabled ) 00113 kdDebug(125) << "TDEAccelAction::init( \"" << sName << "\" ): created with enabled = false" << endl; 00114 return true; 00115 } 00116 00117 TDEAccelAction& TDEAccelAction::operator =( const TDEAccelAction& action ) 00118 { 00119 m_sName = action.m_sName; 00120 m_sLabel = action.m_sLabel; 00121 m_sWhatsThis = action.m_sWhatsThis; 00122 m_cutDefault3 = action.m_cutDefault3; 00123 m_cutDefault4 = action.m_cutDefault4; 00124 m_pObjSlot = action.m_pObjSlot; 00125 m_psMethodSlot = action.m_psMethodSlot; 00126 m_bConfigurable = action.m_bConfigurable; 00127 m_bEnabled = action.m_bEnabled; 00128 m_nIDAccel = action.m_nIDAccel; 00129 m_cut = action.m_cut; 00130 d->m_nConnections = action.d->m_nConnections; 00131 00132 return *this; 00133 } 00134 00135 void TDEAccelAction::setName( const TQString& s ) 00136 { m_sName = s; } 00137 void TDEAccelAction::setLabel( const TQString& s ) 00138 { m_sLabel = s; } 00139 void TDEAccelAction::setWhatsThis( const TQString& s ) 00140 { m_sWhatsThis = s; } 00141 00142 bool TDEAccelAction::setShortcut( const TDEShortcut& cut ) 00143 { 00144 m_cut = cut; 00145 return true; 00146 } 00147 00148 void TDEAccelAction::setSlot( const TQObject* pObjSlot, const char* psMethodSlot ) 00149 { 00150 m_pObjSlot = pObjSlot; 00151 m_psMethodSlot = psMethodSlot; 00152 } 00153 00154 void TDEAccelAction::setConfigurable( bool b ) 00155 { m_bConfigurable = b; } 00156 void TDEAccelAction::setEnabled( bool b ) 00157 { m_bEnabled = b; } 00158 00159 TQString TDEAccelAction::toString() const 00160 { return m_cut.toString(); } 00161 00162 TQString TDEAccelAction::toStringInternal() const 00163 { return m_cut.toStringInternal( &shortcutDefault() ); } 00164 00165 bool TDEAccelAction::setKeySequence( uint i, const KKeySequence& seq ) 00166 { 00167 if( i < m_cut.count() ) { 00168 m_cut.setSeq( i, seq ); 00169 return true; 00170 } else if( i == m_cut.count() ) 00171 return m_cut.append( seq ); 00172 return false; 00173 } 00174 00175 void TDEAccelAction::clearShortcut() 00176 { 00177 m_cut.clear(); 00178 } 00179 00180 bool TDEAccelAction::contains( const KKeySequence& seq ) 00181 { 00182 return m_cut.contains( seq ); 00183 for( uint i = 0; i < m_cut.count(); i++ ) { 00184 if( m_cut.seq(i) == seq ) 00185 return true; 00186 } 00187 return false; 00188 } 00189 00190 const TDEShortcut& TDEAccelAction::shortcutDefault() const 00191 { return (useFourModifierKeys()) ? m_cutDefault4 : m_cutDefault3; } 00192 bool TDEAccelAction::isConnected() const 00193 { return d->m_nConnections; } 00194 void TDEAccelAction::incConnections() 00195 { d->m_nConnections++; } 00196 void TDEAccelAction::decConnections() 00197 { if( d->m_nConnections > 0 ) d->m_nConnections--; } 00198 00199 // Indicate whether to default to the 3- or 4- modifier keyboard schemes 00200 int TDEAccelAction::g_bUseFourModifierKeys = -1; 00201 00202 bool TDEAccelAction::useFourModifierKeys() 00203 { 00204 if( TDEAccelAction::g_bUseFourModifierKeys == -1 ) { 00205 // Read in whether to use 4 modifier keys 00206 TDEConfigGroupSaver cgs( TDEGlobal::config(), "Keyboard" ); 00207 bool b = TDEGlobal::config()->readBoolEntry( "Use Four Modifier Keys", false ); 00208 TDEAccelAction::g_bUseFourModifierKeys = b && KKeyNative::keyboardHasWinKey(); 00209 } 00210 return TDEAccelAction::g_bUseFourModifierKeys == 1; 00211 } 00212 00213 void TDEAccelAction::useFourModifierKeys( bool b ) 00214 { 00215 if( TDEAccelAction::g_bUseFourModifierKeys != (int)b ) { 00216 TDEAccelAction::g_bUseFourModifierKeys = b && KKeyNative::keyboardHasWinKey(); 00217 // If we're 'turning off' the meta key or, if we're turning it on, 00218 // the keyboard must actually have a meta key. 00219 if( b && !KKeyNative::keyboardHasWinKey() ) 00220 kdDebug(125) << "Tried to use four modifier keys on a keyboard layout without a Meta key.\n"; 00221 } 00222 TDEConfigGroupSaver cgs( TDEGlobal::config(), "Keyboard" ); 00223 TDEGlobal::config()->writeEntry( "Use Four Modifier Keys", TDEAccelAction::g_bUseFourModifierKeys, true, true); 00224 00225 kdDebug(125) << "bUseFourModifierKeys = " << TDEAccelAction::g_bUseFourModifierKeys << endl; 00226 } 00227 00228 //--------------------------------------------------------------------- 00229 // TDEAccelActions 00230 //--------------------------------------------------------------------- 00231 00232 class TDEAccelActionsPrivate 00233 { 00234 public: 00235 }; 00236 00237 TDEAccelActions::TDEAccelActions() 00238 { 00239 kdDebug(125) << "TDEAccelActions(): this = " << this << endl; 00240 initPrivate( 0 ); 00241 } 00242 00243 TDEAccelActions::TDEAccelActions( const TDEAccelActions& actions ) 00244 { 00245 kdDebug(125) << "TDEAccelActions( actions = " << &actions << " ): this = " << this << endl; 00246 initPrivate( 0 ); 00247 init( actions ); 00248 } 00249 00250 TDEAccelActions::TDEAccelActions( TDEAccelBase* pTDEAccelBase ) 00251 { 00252 kdDebug(125) << "TDEAccelActions( TDEAccelBase = " << pTDEAccelBase << " ): this = " << this << endl; 00253 initPrivate( pTDEAccelBase ); 00254 } 00255 00256 TDEAccelActions::~TDEAccelActions() 00257 { 00258 //kdDebug(125) << "TDEAccelActions::~TDEAccelActions(): this = " << this << endl; 00259 clear(); 00260 //delete d; 00261 } 00262 00263 void TDEAccelActions::initPrivate( TDEAccelBase* pTDEAccelBase ) 00264 { 00265 m_pTDEAccelBase = pTDEAccelBase; 00266 m_nSizeAllocated = m_nSize = 0; 00267 m_prgActions = 0; 00268 //d = new TDEAccelActionsPrivate; 00269 } 00270 00271 void TDEAccelActions::clear() 00272 { 00273 kdDebug(125) << "\tTDEAccelActions::clear()" << endl; 00274 for( uint i = 0; i < m_nSize; i++ ) 00275 delete m_prgActions[i]; 00276 delete[] m_prgActions; 00277 00278 m_nSizeAllocated = m_nSize = 0; 00279 m_prgActions = 0; 00280 } 00281 00282 bool TDEAccelActions::init( const TDEAccelActions& actions ) 00283 { 00284 clear(); 00285 resize( actions.count() ); 00286 for( uint i = 0; i < m_nSize; i++ ) { 00287 TDEAccelAction* pAction = actions.m_prgActions[i]; 00288 if( pAction ) 00289 m_prgActions[i] = new TDEAccelAction( *pAction ); 00290 else 00291 m_prgActions[i] = 0; 00292 } 00293 00294 return true; 00295 } 00296 00297 bool TDEAccelActions::init( TDEConfigBase& config, const TQString& sGroup ) 00298 { 00299 kdDebug(125) << "TDEAccelActions::init( " << sGroup << " )" << endl; 00300 TQMap<TQString, TQString> mapEntry = config.entryMap( sGroup ); 00301 resize( mapEntry.count() ); 00302 00303 TQMap<TQString, TQString>::Iterator it( mapEntry.begin() ); 00304 for( uint i = 0; it != mapEntry.end(); ++it, i++ ) { 00305 TQString sShortcuts = *it; 00306 TDEShortcut cuts; 00307 00308 kdDebug(125) << it.key() << " = " << sShortcuts << endl; 00309 if( !sShortcuts.isEmpty() && sShortcuts != "none" ) 00310 cuts.init( sShortcuts ); 00311 00312 m_prgActions[i] = new TDEAccelAction( it.key(), it.key(), it.key(), 00313 cuts, cuts, 00314 0, 0, // pObjSlot, psMethodSlot, 00315 true, false ); // bConfigurable, bEnabled 00316 } 00317 00318 return true; 00319 } 00320 00321 void TDEAccelActions::resize( uint nSize ) 00322 { 00323 if( nSize > m_nSizeAllocated ) { 00324 uint nSizeAllocated = ((nSize/10) + 1) * 10; 00325 TDEAccelAction** prgActions = new TDEAccelAction* [nSizeAllocated]; 00326 00327 // Copy pointers over to new array 00328 for( uint i = 0; i < m_nSizeAllocated; i++ ) 00329 prgActions[i] = m_prgActions[i]; 00330 00331 // Null out new pointers 00332 for( uint i = m_nSizeAllocated; i < nSizeAllocated; i++ ) 00333 prgActions[i] = 0; 00334 00335 delete[] m_prgActions; 00336 m_prgActions = prgActions; 00337 m_nSizeAllocated = nSizeAllocated; 00338 } 00339 00340 m_nSize = nSize; 00341 } 00342 00343 void TDEAccelActions::insertPtr( TDEAccelAction* pAction ) 00344 { 00345 resize( m_nSize + 1 ); 00346 m_prgActions[m_nSize-1] = pAction; 00347 } 00348 00349 void TDEAccelActions::updateShortcuts( TDEAccelActions& actions2 ) 00350 { 00351 kdDebug(125) << "TDEAccelActions::updateShortcuts()" << endl; 00352 bool bChanged = false; 00353 00354 for( uint i = 0; i < m_nSize; i++ ) { 00355 TDEAccelAction* pAction = m_prgActions[i]; 00356 if( pAction && pAction->m_bConfigurable ) { 00357 TDEAccelAction* pAction2 = actions2.actionPtr( pAction->m_sName ); 00358 if( pAction2 ) { 00359 TQString sOld = pAction->m_cut.toStringInternal(); 00360 pAction->m_cut = pAction2->m_cut; 00361 kdDebug(125) << "\t" << pAction->m_sName 00362 << " found: " << sOld 00363 << " => " << pAction2->m_cut.toStringInternal() 00364 << " = " << pAction->m_cut.toStringInternal() << endl; 00365 bChanged = true; 00366 } 00367 } 00368 } 00369 00370 if( bChanged ) 00371 emitKeycodeChanged(); 00372 } 00373 00374 int TDEAccelActions::actionIndex( const TQString& sAction ) const 00375 { 00376 for( uint i = 0; i < m_nSize; i++ ) { 00377 if( m_prgActions[i] == 0 ) 00378 kdWarning(125) << "TDEAccelActions::actionPtr( " << sAction << " ): encountered null pointer at m_prgActions[" << i << "]" << endl; 00379 else if( m_prgActions[i]->m_sName == sAction ) 00380 return (int) i; 00381 } 00382 return -1; 00383 } 00384 00385 TDEAccelAction* TDEAccelActions::actionPtr( uint i ) 00386 { 00387 return m_prgActions[i]; 00388 } 00389 00390 const TDEAccelAction* TDEAccelActions::actionPtr( uint i ) const 00391 { 00392 return m_prgActions[i]; 00393 } 00394 00395 TDEAccelAction* TDEAccelActions::actionPtr( const TQString& sAction ) 00396 { 00397 int i = actionIndex( sAction ); 00398 return (i >= 0) ? m_prgActions[i] : 0; 00399 } 00400 00401 const TDEAccelAction* TDEAccelActions::actionPtr( const TQString& sAction ) const 00402 { 00403 int i = actionIndex( sAction ); 00404 return (i >= 0) ? m_prgActions[i] : 0; 00405 } 00406 00407 TDEAccelAction* TDEAccelActions::actionPtr( KKeySequence cut ) 00408 { 00409 for( uint i = 0; i < m_nSize; i++ ) { 00410 if( m_prgActions[i] == 0 ) 00411 kdWarning(125) << "TDEAccelActions::actionPtr( " << cut.toStringInternal() << " ): encountered null pointer at m_prgActions[" << i << "]" << endl; 00412 else if( m_prgActions[i]->contains( cut ) ) 00413 return m_prgActions[i]; 00414 } 00415 return 0; 00416 } 00417 00418 TDEAccelAction& TDEAccelActions::operator []( uint i ) 00419 { 00420 return *actionPtr( i ); 00421 } 00422 00423 const TDEAccelAction& TDEAccelActions::operator []( uint i ) const 00424 { 00425 return *actionPtr( i ); 00426 } 00427 00428 TDEAccelAction* TDEAccelActions::insert( const TQString& sName, const TQString& sLabel ) 00429 { 00430 if( actionPtr( sName ) ) { 00431 kdWarning(125) << "TDEAccelActions::insertLabel( " << sName << ", " << sLabel << " ): action with same name already present." << endl; 00432 return 0; 00433 } 00434 00435 TDEAccelAction* pAction = new TDEAccelAction; 00436 pAction->m_sName = sName; 00437 pAction->m_sLabel = sLabel; 00438 pAction->m_bConfigurable = false; 00439 pAction->m_bEnabled = false; 00440 00441 insertPtr( pAction ); 00442 return pAction; 00443 } 00444 00445 TDEAccelAction* TDEAccelActions::insert( const TQString& sAction, const TQString& sLabel, const TQString& sWhatsThis, 00446 const TDEShortcut& rgCutDefaults3, const TDEShortcut& rgCutDefaults4, 00447 const TQObject* pObjSlot, const char* psMethodSlot, 00448 bool bConfigurable, bool bEnabled ) 00449 { 00450 //kdDebug(125) << "TDEAccelActions::insert()2 begin" << endl; 00451 if( actionPtr( sAction ) ) { 00452 kdWarning(125) << "TDEAccelActions::insert( " << sAction << " ): action with same name already present." << endl; 00453 return 0; 00454 } 00455 00456 TDEAccelAction* pAction = new TDEAccelAction( 00457 sAction, sLabel, sWhatsThis, 00458 rgCutDefaults3, rgCutDefaults4, 00459 pObjSlot, psMethodSlot, 00460 bConfigurable, bEnabled ); 00461 insertPtr( pAction ); 00462 00463 //kdDebug(125) << "TDEAccelActions::insert()2 end" << endl; 00464 return pAction; 00465 } 00466 00467 bool TDEAccelActions::remove( const TQString& sAction ) 00468 { 00469 kdDebug(125) << "TDEAccelActions::remove( \"" << sAction << "\" ): this = " << this << " m_pTDEAccelBase = " << m_pTDEAccelBase << endl; 00470 00471 int iAction = actionIndex( sAction ); 00472 if( iAction < 0 ) 00473 return false; 00474 00475 if( m_pTDEAccelBase ) 00476 m_pTDEAccelBase->slotRemoveAction( m_prgActions[iAction] ); 00477 delete m_prgActions[iAction]; 00478 00479 for( uint i = iAction; i < m_nSize - 1; i++ ) 00480 m_prgActions[i] = m_prgActions[i+1]; 00481 m_nSize--; 00482 00483 return true; 00484 } 00485 00486 bool TDEAccelActions::readActions( const TQString& sConfigGroup, TDEConfigBase* pConfig ) 00487 { 00488 TDEAccelShortcutList accelList(*this, false); 00489 return accelList.readSettings( sConfigGroup, pConfig ); 00490 } 00491 00492 /* 00493 1) TDEAccelAction = "Something" 00494 1) KKeySequence = "Meta+X,Asterisk" 00495 1) TDEAccelSequence = "Meta+X" 00496 1) KKeySequence = Meta+X 00497 2) TDEAccelSequence = "Asterisk" 00498 1) KKeySequence = Shift+8 (English layout) 00499 2) KKeySequence = Keypad_Asterisk 00500 2) KKeySequence = "Alt+F2" 00501 1) TDEAccelSequence = "Alt+F2" 00502 1) KKeySequence = Alt+F2 00503 -> "Something=Meta+X,Asterisk;Alt+F2" 00504 */ 00505 bool TDEAccelActions::writeActions( const TQString &sGroup, TDEConfigBase* pConfig, 00506 bool bWriteAll, bool bGlobal ) const 00507 { 00508 kdDebug(125) << "TDEAccelActions::writeActions( " << sGroup << ", " << pConfig << ", " << bWriteAll << ", " << bGlobal << " )" << endl; 00509 if( !pConfig ) 00510 pConfig = TDEGlobal::config(); 00511 TDEConfigGroupSaver cs( pConfig, sGroup ); 00512 00513 for( uint i = 0; i < m_nSize; i++ ) { 00514 if( m_prgActions[i] == 0 ) { 00515 kdWarning(125) << "TDEAccelActions::writeActions(): encountered null pointer at m_prgActions[" << i << "]" << endl; 00516 continue; 00517 } 00518 const TDEAccelAction& action = *m_prgActions[i]; 00519 00520 TQString s; 00521 bool bConfigHasAction = !pConfig->readEntry( action.m_sName ).isEmpty(); 00522 bool bSameAsDefault = true; 00523 bool bWriteAction = false; 00524 00525 if( action.m_bConfigurable ) { 00526 s = action.toStringInternal(); 00527 bSameAsDefault = (action.m_cut == action.shortcutDefault()); 00528 00529 //if( bWriteAll && s.isEmpty() ) 00530 if( s.isEmpty() ) 00531 s = "none"; 00532 00533 // If we're using a global config or this setting 00534 // differs from the default, then we want to write. 00535 if( bWriteAll || !bSameAsDefault ) 00536 bWriteAction = true; 00537 00538 if( bWriteAction ) { 00539 kdDebug(125) << "\twriting " << action.m_sName << " = " << s << endl; 00540 // Is passing bGlobal irrelevant, since if it's true, 00541 // then we're using the global config anyway? --ellis 00542 pConfig->writeEntry( action.m_sName, s, true, bGlobal ); 00543 } 00544 // Otherwise, this key is the same as default 00545 // but exists in config file. Remove it. 00546 else if( bConfigHasAction ) { 00547 kdDebug(125) << "\tremoving " << action.m_sName << " because == default" << endl; 00548 pConfig->deleteEntry( action.m_sName, bGlobal ); 00549 } 00550 00551 } 00552 } 00553 00554 pConfig->sync(); 00555 return true; 00556 } 00557 00558 void TDEAccelActions::emitKeycodeChanged() 00559 { 00560 if( m_pTDEAccelBase ) 00561 m_pTDEAccelBase->emitSignal( TDEAccelBase::KEYCODE_CHANGED ); 00562 } 00563 00564 uint TDEAccelActions::count() const 00565 { return m_nSize; }