/* Copyright (C) 1998 Mark Donohoe Copyright (C) 1997-2000 Nicolas Hadacek Copyright (C) 1998 Matthias Ettrich Copyright (c) 2001,2002 Ellis Whitehead This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tdeaccelaction.h" #include "tdeaccelbase.h" // for TDEAccelBase::slotRemoveAction() & emitSignal() #include #include #include "kckey.h" #include #include #include #include #include //--------------------------------------------------------------------- // TDEAccelAction //--------------------------------------------------------------------- class TDEAccelActionPrivate { public: uint m_nConnections; }; TDEAccelAction::TDEAccelAction() { //kdDebug(125) << "TDEAccelAction(): this = " << this << endl; d = new TDEAccelActionPrivate; m_pObjSlot = 0; m_psMethodSlot = 0; m_bConfigurable = true; m_bEnabled = true; m_nIDAccel = 0; d->m_nConnections = 0; } TDEAccelAction::TDEAccelAction( const TDEAccelAction& action ) { //kdDebug(125) << "TDEAccelAction( copy from \"" << action.m_sName << "\" ): this = " << this << endl; d = new TDEAccelActionPrivate; *this = action; } TDEAccelAction::TDEAccelAction( const TQString& sName, const TQString& sLabel, const TQString& sWhatsThis, const TDEShortcut& cutDef3, const TDEShortcut& cutDef4, const TQObject* pObjSlot, const char* psMethodSlot, bool bConfigurable, bool bEnabled ) { //kdDebug(125) << "TDEAccelAction( \"" << sName << "\" ): this = " << this << endl; d = new TDEAccelActionPrivate; init( sName, sLabel, sWhatsThis, cutDef3, cutDef4, pObjSlot, psMethodSlot, bConfigurable, bEnabled ); } TDEAccelAction::~TDEAccelAction() { //kdDebug(125) << "\t\t\tTDEAccelAction::~TDEAccelAction( \"" << m_sName << "\" ): this = " << this << endl; delete d; } void TDEAccelAction::clear() { m_cut.clear(); m_pObjSlot = 0; m_psMethodSlot = 0; m_bConfigurable = true; m_bEnabled = true; m_nIDAccel = 0; d->m_nConnections = 0; } bool TDEAccelAction::init( const TQString& sName, const TQString& sLabel, const TQString& sWhatsThis, const TDEShortcut& rgCutDefaults3, const TDEShortcut& rgCutDefaults4, const TQObject* pObjSlot, const char* psMethodSlot, bool bConfigurable, bool bEnabled ) { m_sName = sName; m_sLabel = sLabel; m_sWhatsThis = sWhatsThis; m_cutDefault3 = rgCutDefaults3; m_cutDefault4 = rgCutDefaults4; m_pObjSlot = pObjSlot; m_psMethodSlot = psMethodSlot; m_bConfigurable = bConfigurable; m_bEnabled = bEnabled; m_nIDAccel = 0; m_cut = shortcutDefault(); d->m_nConnections = 0; if( !m_bEnabled ) kdDebug(125) << "TDEAccelAction::init( \"" << sName << "\" ): created with enabled = false" << endl; return true; } TDEAccelAction& TDEAccelAction::operator =( const TDEAccelAction& action ) { m_sName = action.m_sName; m_sLabel = action.m_sLabel; m_sWhatsThis = action.m_sWhatsThis; m_cutDefault3 = action.m_cutDefault3; m_cutDefault4 = action.m_cutDefault4; m_pObjSlot = action.m_pObjSlot; m_psMethodSlot = action.m_psMethodSlot; m_bConfigurable = action.m_bConfigurable; m_bEnabled = action.m_bEnabled; m_nIDAccel = action.m_nIDAccel; m_cut = action.m_cut; d->m_nConnections = action.d->m_nConnections; return *this; } void TDEAccelAction::setName( const TQString& s ) { m_sName = s; } void TDEAccelAction::setLabel( const TQString& s ) { m_sLabel = s; } void TDEAccelAction::setWhatsThis( const TQString& s ) { m_sWhatsThis = s; } bool TDEAccelAction::setShortcut( const TDEShortcut& cut ) { m_cut = cut; return true; } void TDEAccelAction::setSlot( const TQObject* pObjSlot, const char* psMethodSlot ) { m_pObjSlot = pObjSlot; m_psMethodSlot = psMethodSlot; } void TDEAccelAction::setConfigurable( bool b ) { m_bConfigurable = b; } void TDEAccelAction::setEnabled( bool b ) { m_bEnabled = b; } TQString TDEAccelAction::toString() const { return m_cut.toString(); } TQString TDEAccelAction::toStringInternal() const { return m_cut.toStringInternal( &shortcutDefault() ); } bool TDEAccelAction::setKeySequence( uint i, const KKeySequence& seq ) { if( i < m_cut.count() ) { m_cut.setSeq( i, seq ); return true; } else if( i == m_cut.count() ) return m_cut.append( seq ); return false; } void TDEAccelAction::clearShortcut() { m_cut.clear(); } bool TDEAccelAction::contains( const KKeySequence& seq ) { return m_cut.contains( seq ); for( uint i = 0; i < m_cut.count(); i++ ) { if( m_cut.seq(i) == seq ) return true; } return false; } const TDEShortcut& TDEAccelAction::shortcutDefault() const { return (useFourModifierKeys()) ? m_cutDefault4 : m_cutDefault3; } bool TDEAccelAction::isConnected() const { return d->m_nConnections; } void TDEAccelAction::incConnections() { d->m_nConnections++; } void TDEAccelAction::decConnections() { if( d->m_nConnections > 0 ) d->m_nConnections--; } // Indicate whether to default to the 3- or 4- modifier keyboard schemes int TDEAccelAction::g_bUseFourModifierKeys = -1; bool TDEAccelAction::useFourModifierKeys() { if( TDEAccelAction::g_bUseFourModifierKeys == -1 ) { // Read in whether to use 4 modifier keys TDEConfigGroupSaver cgs( TDEGlobal::config(), "Keyboard" ); bool b = TDEGlobal::config()->readBoolEntry( "Use Four Modifier Keys", false ); TDEAccelAction::g_bUseFourModifierKeys = b && KKeyNative::keyboardHasWinKey(); } return TDEAccelAction::g_bUseFourModifierKeys == 1; } void TDEAccelAction::useFourModifierKeys( bool b ) { if( TDEAccelAction::g_bUseFourModifierKeys != (int)b ) { TDEAccelAction::g_bUseFourModifierKeys = b && KKeyNative::keyboardHasWinKey(); // If we're 'turning off' the meta key or, if we're turning it on, // the keyboard must actually have a meta key. if( b && !KKeyNative::keyboardHasWinKey() ) kdDebug(125) << "Tried to use four modifier keys on a keyboard layout without a Meta key.\n"; } TDEConfigGroupSaver cgs( TDEGlobal::config(), "Keyboard" ); TDEGlobal::config()->writeEntry( "Use Four Modifier Keys", TDEAccelAction::g_bUseFourModifierKeys, true, true); kdDebug(125) << "bUseFourModifierKeys = " << TDEAccelAction::g_bUseFourModifierKeys << endl; } //--------------------------------------------------------------------- // TDEAccelActions //--------------------------------------------------------------------- class TDEAccelActionsPrivate { public: }; TDEAccelActions::TDEAccelActions() { kdDebug(125) << "TDEAccelActions(): this = " << this << endl; initPrivate( 0 ); } TDEAccelActions::TDEAccelActions( const TDEAccelActions& actions ) { kdDebug(125) << "TDEAccelActions( actions = " << &actions << " ): this = " << this << endl; initPrivate( 0 ); init( actions ); } TDEAccelActions::TDEAccelActions( TDEAccelBase* pTDEAccelBase ) { kdDebug(125) << "TDEAccelActions( TDEAccelBase = " << pTDEAccelBase << " ): this = " << this << endl; initPrivate( pTDEAccelBase ); } TDEAccelActions::~TDEAccelActions() { //kdDebug(125) << "TDEAccelActions::~TDEAccelActions(): this = " << this << endl; clear(); //delete d; } void TDEAccelActions::initPrivate( TDEAccelBase* pTDEAccelBase ) { m_pTDEAccelBase = pTDEAccelBase; m_nSizeAllocated = m_nSize = 0; m_prgActions = 0; //d = new TDEAccelActionsPrivate; } void TDEAccelActions::clear() { kdDebug(125) << "\tTDEAccelActions::clear()" << endl; for( uint i = 0; i < m_nSize; i++ ) delete m_prgActions[i]; delete[] m_prgActions; m_nSizeAllocated = m_nSize = 0; m_prgActions = 0; } bool TDEAccelActions::init( const TDEAccelActions& actions ) { clear(); resize( actions.count() ); for( uint i = 0; i < m_nSize; i++ ) { TDEAccelAction* pAction = actions.m_prgActions[i]; if( pAction ) m_prgActions[i] = new TDEAccelAction( *pAction ); else m_prgActions[i] = 0; } return true; } bool TDEAccelActions::init( TDEConfigBase& config, const TQString& sGroup ) { kdDebug(125) << "TDEAccelActions::init( " << sGroup << " )" << endl; TQMap mapEntry = config.entryMap( sGroup ); resize( mapEntry.count() ); TQMap::Iterator it( mapEntry.begin() ); for( uint i = 0; it != mapEntry.end(); ++it, i++ ) { TQString sShortcuts = *it; TDEShortcut cuts; kdDebug(125) << it.key() << " = " << sShortcuts << endl; if( !sShortcuts.isEmpty() && sShortcuts != "none" ) cuts.init( sShortcuts ); m_prgActions[i] = new TDEAccelAction( it.key(), it.key(), it.key(), cuts, cuts, 0, 0, // pObjSlot, psMethodSlot, true, false ); // bConfigurable, bEnabled } return true; } void TDEAccelActions::resize( uint nSize ) { if( nSize > m_nSizeAllocated ) { uint nSizeAllocated = ((nSize/10) + 1) * 10; TDEAccelAction** prgActions = new TDEAccelAction* [nSizeAllocated]; // Copy pointers over to new array for( uint i = 0; i < m_nSizeAllocated; i++ ) prgActions[i] = m_prgActions[i]; // Null out new pointers for( uint i = m_nSizeAllocated; i < nSizeAllocated; i++ ) prgActions[i] = 0; delete[] m_prgActions; m_prgActions = prgActions; m_nSizeAllocated = nSizeAllocated; } m_nSize = nSize; } void TDEAccelActions::insertPtr( TDEAccelAction* pAction ) { resize( m_nSize + 1 ); m_prgActions[m_nSize-1] = pAction; } void TDEAccelActions::updateShortcuts( TDEAccelActions& actions2 ) { kdDebug(125) << "TDEAccelActions::updateShortcuts()" << endl; bool bChanged = false; for( uint i = 0; i < m_nSize; i++ ) { TDEAccelAction* pAction = m_prgActions[i]; if( pAction && pAction->m_bConfigurable ) { TDEAccelAction* pAction2 = actions2.actionPtr( pAction->m_sName ); if( pAction2 ) { TQString sOld = pAction->m_cut.toStringInternal(); pAction->m_cut = pAction2->m_cut; kdDebug(125) << "\t" << pAction->m_sName << " found: " << sOld << " => " << pAction2->m_cut.toStringInternal() << " = " << pAction->m_cut.toStringInternal() << endl; bChanged = true; } } } if( bChanged ) emitKeycodeChanged(); } int TDEAccelActions::actionIndex( const TQString& sAction ) const { for( uint i = 0; i < m_nSize; i++ ) { if( m_prgActions[i] == 0 ) kdWarning(125) << "TDEAccelActions::actionPtr( " << sAction << " ): encountered null pointer at m_prgActions[" << i << "]" << endl; else if( m_prgActions[i]->m_sName == sAction ) return (int) i; } return -1; } TDEAccelAction* TDEAccelActions::actionPtr( uint i ) { return m_prgActions[i]; } const TDEAccelAction* TDEAccelActions::actionPtr( uint i ) const { return m_prgActions[i]; } TDEAccelAction* TDEAccelActions::actionPtr( const TQString& sAction ) { int i = actionIndex( sAction ); return (i >= 0) ? m_prgActions[i] : 0; } const TDEAccelAction* TDEAccelActions::actionPtr( const TQString& sAction ) const { int i = actionIndex( sAction ); return (i >= 0) ? m_prgActions[i] : 0; } TDEAccelAction* TDEAccelActions::actionPtr( KKeySequence cut ) { for( uint i = 0; i < m_nSize; i++ ) { if( m_prgActions[i] == 0 ) kdWarning(125) << "TDEAccelActions::actionPtr( " << cut.toStringInternal() << " ): encountered null pointer at m_prgActions[" << i << "]" << endl; else if( m_prgActions[i]->contains( cut ) ) return m_prgActions[i]; } return 0; } TDEAccelAction& TDEAccelActions::operator []( uint i ) { return *actionPtr( i ); } const TDEAccelAction& TDEAccelActions::operator []( uint i ) const { return *actionPtr( i ); } TDEAccelAction* TDEAccelActions::insert( const TQString& sName, const TQString& sLabel ) { if( actionPtr( sName ) ) { kdWarning(125) << "TDEAccelActions::insertLabel( " << sName << ", " << sLabel << " ): action with same name already present." << endl; return 0; } TDEAccelAction* pAction = new TDEAccelAction; pAction->m_sName = sName; pAction->m_sLabel = sLabel; pAction->m_bConfigurable = false; pAction->m_bEnabled = false; insertPtr( pAction ); return pAction; } TDEAccelAction* TDEAccelActions::insert( const TQString& sAction, const TQString& sLabel, const TQString& sWhatsThis, const TDEShortcut& rgCutDefaults3, const TDEShortcut& rgCutDefaults4, const TQObject* pObjSlot, const char* psMethodSlot, bool bConfigurable, bool bEnabled ) { //kdDebug(125) << "TDEAccelActions::insert()2 begin" << endl; if( actionPtr( sAction ) ) { kdWarning(125) << "TDEAccelActions::insert( " << sAction << " ): action with same name already present." << endl; return 0; } TDEAccelAction* pAction = new TDEAccelAction( sAction, sLabel, sWhatsThis, rgCutDefaults3, rgCutDefaults4, pObjSlot, psMethodSlot, bConfigurable, bEnabled ); insertPtr( pAction ); //kdDebug(125) << "TDEAccelActions::insert()2 end" << endl; return pAction; } bool TDEAccelActions::remove( const TQString& sAction ) { kdDebug(125) << "TDEAccelActions::remove( \"" << sAction << "\" ): this = " << this << " m_pTDEAccelBase = " << m_pTDEAccelBase << endl; int iAction = actionIndex( sAction ); if( iAction < 0 ) return false; if( m_pTDEAccelBase ) m_pTDEAccelBase->slotRemoveAction( m_prgActions[iAction] ); delete m_prgActions[iAction]; for( uint i = iAction; i < m_nSize - 1; i++ ) m_prgActions[i] = m_prgActions[i+1]; m_nSize--; return true; } bool TDEAccelActions::readActions( const TQString& sConfigGroup, TDEConfigBase* pConfig ) { TDEAccelShortcutList accelList(*this, false); return accelList.readSettings( sConfigGroup, pConfig ); } /* 1) TDEAccelAction = "Something" 1) KKeySequence = "Meta+X,Asterisk" 1) TDEAccelSequence = "Meta+X" 1) KKeySequence = Meta+X 2) TDEAccelSequence = "Asterisk" 1) KKeySequence = Shift+8 (English layout) 2) KKeySequence = Keypad_Asterisk 2) KKeySequence = "Alt+F2" 1) TDEAccelSequence = "Alt+F2" 1) KKeySequence = Alt+F2 -> "Something=Meta+X,Asterisk;Alt+F2" */ bool TDEAccelActions::writeActions( const TQString &sGroup, TDEConfigBase* pConfig, bool bWriteAll, bool bGlobal ) const { kdDebug(125) << "TDEAccelActions::writeActions( " << sGroup << ", " << pConfig << ", " << bWriteAll << ", " << bGlobal << " )" << endl; if( !pConfig ) pConfig = TDEGlobal::config(); TDEConfigGroupSaver cs( pConfig, sGroup ); for( uint i = 0; i < m_nSize; i++ ) { if( m_prgActions[i] == 0 ) { kdWarning(125) << "TDEAccelActions::writeActions(): encountered null pointer at m_prgActions[" << i << "]" << endl; continue; } const TDEAccelAction& action = *m_prgActions[i]; TQString s; bool bConfigHasAction = !pConfig->readEntry( action.m_sName ).isEmpty(); bool bSameAsDefault = true; bool bWriteAction = false; if( action.m_bConfigurable ) { s = action.toStringInternal(); bSameAsDefault = (action.m_cut == action.shortcutDefault()); //if( bWriteAll && s.isEmpty() ) if( s.isEmpty() ) s = "none"; // If we're using a global config or this setting // differs from the default, then we want to write. if( bWriteAll || !bSameAsDefault ) bWriteAction = true; if( bWriteAction ) { kdDebug(125) << "\twriting " << action.m_sName << " = " << s << endl; // Is passing bGlobal irrelevant, since if it's true, // then we're using the global config anyway? --ellis pConfig->writeEntry( action.m_sName, s, true, bGlobal ); } // Otherwise, this key is the same as default // but exists in config file. Remove it. else if( bConfigHasAction ) { kdDebug(125) << "\tremoving " << action.m_sName << " because == default" << endl; pConfig->deleteEntry( action.m_sName, bGlobal ); } } } pConfig->sync(); return true; } void TDEAccelActions::emitKeycodeChanged() { if( m_pTDEAccelBase ) m_pTDEAccelBase->emitSignal( TDEAccelBase::KEYCODE_CHANGED ); } uint TDEAccelActions::count() const { return m_nSize; }