/* 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 "kaccelaction.h" #include "kaccelbase.h" // for KAccelBase::slotRemoveAction() & emitSignal() #include #include #include "kckey.h" #include #include #include #include #include //--------------------------------------------------------------------- // KAccelAction //--------------------------------------------------------------------- class KAccelActionPrivate { public: uint m_nConnections; }; KAccelAction::KAccelAction() { //kdDebug(125) << "KAccelAction(): this = " << this << endl; d = new KAccelActionPrivate; m_pObjSlot = 0; m_psMethodSlot = 0; m_bConfigurable = true; m_bEnabled = true; m_nIDAccel = 0; d->m_nConnections = 0; } KAccelAction::KAccelAction( const KAccelAction& action ) { //kdDebug(125) << "KAccelAction( copy from \"" << action.m_sName << "\" ): this = " << this << endl; d = new KAccelActionPrivate; *this = action; } KAccelAction::KAccelAction( const TQString& sName, const TQString& sLabel, const TQString& sWhatsThis, const KShortcut& cutDef3, const KShortcut& cutDef4, const TQObject* pObjSlot, const char* psMethodSlot, bool bConfigurable, bool bEnabled ) { //kdDebug(125) << "KAccelAction( \"" << sName << "\" ): this = " << this << endl; d = new KAccelActionPrivate; init( sName, sLabel, sWhatsThis, cutDef3, cutDef4, pObjSlot, psMethodSlot, bConfigurable, bEnabled ); } KAccelAction::~KAccelAction() { //kdDebug(125) << "\t\t\tKAccelAction::~KAccelAction( \"" << m_sName << "\" ): this = " << this << endl; delete d; } void KAccelAction::clear() { m_cut.clear(); m_pObjSlot = 0; m_psMethodSlot = 0; m_bConfigurable = true; m_bEnabled = true; m_nIDAccel = 0; d->m_nConnections = 0; } bool KAccelAction::init( const TQString& sName, const TQString& sLabel, const TQString& sWhatsThis, const KShortcut& rgCutDefaults3, const KShortcut& 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) << "KAccelAction::init( \"" << sName << "\" ): created with enabled = false" << endl; return true; } KAccelAction& KAccelAction::operator =( const KAccelAction& 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 KAccelAction::setName( const TQString& s ) { m_sName = s; } void KAccelAction::setLabel( const TQString& s ) { m_sLabel = s; } void KAccelAction::setWhatsThis( const TQString& s ) { m_sWhatsThis = s; } bool KAccelAction::setShortcut( const KShortcut& cut ) { m_cut = cut; return true; } void KAccelAction::setSlot( const TQObject* pObjSlot, const char* psMethodSlot ) { m_pObjSlot = pObjSlot; m_psMethodSlot = psMethodSlot; } void KAccelAction::setConfigurable( bool b ) { m_bConfigurable = b; } void KAccelAction::setEnabled( bool b ) { m_bEnabled = b; } TQString KAccelAction::toString() const { return m_cut.toString(); } TQString KAccelAction::toStringInternal() const { return m_cut.toStringInternal( &shortcutDefault() ); } bool KAccelAction::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 KAccelAction::clearShortcut() { m_cut.clear(); } bool KAccelAction::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 KShortcut& KAccelAction::shortcutDefault() const { return (useFourModifierKeys()) ? m_cutDefault4 : m_cutDefault3; } bool KAccelAction::isConnected() const { return d->m_nConnections; } void KAccelAction::incConnections() { d->m_nConnections++; } void KAccelAction::decConnections() { if( d->m_nConnections > 0 ) d->m_nConnections--; } // Indicate whether to default to the 3- or 4- modifier keyboard schemes int KAccelAction::g_bUseFourModifierKeys = -1; bool KAccelAction::useFourModifierKeys() { if( KAccelAction::g_bUseFourModifierKeys == -1 ) { // Read in whether to use 4 modifier keys KConfigGroupSaver cgs( KGlobal::config(), "Keyboard" ); bool b = KGlobal::config()->readBoolEntry( "Use Four Modifier Keys", false ); KAccelAction::g_bUseFourModifierKeys = b && KKeyNative::keyboardHasWinKey(); } return KAccelAction::g_bUseFourModifierKeys == 1; } void KAccelAction::useFourModifierKeys( bool b ) { if( KAccelAction::g_bUseFourModifierKeys != (int)b ) { KAccelAction::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"; } KConfigGroupSaver cgs( KGlobal::config(), "Keyboard" ); KGlobal::config()->writeEntry( "Use Four Modifier Keys", KAccelAction::g_bUseFourModifierKeys, true, true); kdDebug(125) << "bUseFourModifierKeys = " << KAccelAction::g_bUseFourModifierKeys << endl; } //--------------------------------------------------------------------- // KAccelActions //--------------------------------------------------------------------- class KAccelActionsPrivate { public: }; KAccelActions::KAccelActions() { kdDebug(125) << "KAccelActions(): this = " << this << endl; initPrivate( 0 ); } KAccelActions::KAccelActions( const KAccelActions& actions ) { kdDebug(125) << "KAccelActions( actions = " << &actions << " ): this = " << this << endl; initPrivate( 0 ); init( actions ); } KAccelActions::KAccelActions( KAccelBase* pKAccelBase ) { kdDebug(125) << "KAccelActions( KAccelBase = " << pKAccelBase << " ): this = " << this << endl; initPrivate( pKAccelBase ); } KAccelActions::~KAccelActions() { //kdDebug(125) << "KAccelActions::~KAccelActions(): this = " << this << endl; clear(); //delete d; } void KAccelActions::initPrivate( KAccelBase* pKAccelBase ) { m_pKAccelBase = pKAccelBase; m_nSizeAllocated = m_nSize = 0; m_prgActions = 0; //d = new KAccelActionsPrivate; } void KAccelActions::clear() { kdDebug(125) << "\tKAccelActions::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 KAccelActions::init( const KAccelActions& actions ) { clear(); resize( actions.count() ); for( uint i = 0; i < m_nSize; i++ ) { KAccelAction* pAction = actions.m_prgActions[i]; if( pAction ) m_prgActions[i] = new KAccelAction( *pAction ); else m_prgActions[i] = 0; } return true; } bool KAccelActions::init( KConfigBase& config, const TQString& sGroup ) { kdDebug(125) << "KAccelActions::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; KShortcut cuts; kdDebug(125) << it.key() << " = " << sShortcuts << endl; if( !sShortcuts.isEmpty() && sShortcuts != "none" ) cuts.init( sShortcuts ); m_prgActions[i] = new KAccelAction( it.key(), it.key(), it.key(), cuts, cuts, 0, 0, // pObjSlot, psMethodSlot, true, false ); // bConfigurable, bEnabled } return true; } void KAccelActions::resize( uint nSize ) { if( nSize > m_nSizeAllocated ) { uint nSizeAllocated = ((nSize/10) + 1) * 10; KAccelAction** prgActions = new KAccelAction* [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 KAccelActions::insertPtr( KAccelAction* pAction ) { resize( m_nSize + 1 ); m_prgActions[m_nSize-1] = pAction; } void KAccelActions::updateShortcuts( KAccelActions& actions2 ) { kdDebug(125) << "KAccelActions::updateShortcuts()" << endl; bool bChanged = false; for( uint i = 0; i < m_nSize; i++ ) { KAccelAction* pAction = m_prgActions[i]; if( pAction && pAction->m_bConfigurable ) { KAccelAction* 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 KAccelActions::actionIndex( const TQString& sAction ) const { for( uint i = 0; i < m_nSize; i++ ) { if( m_prgActions[i] == 0 ) kdWarning(125) << "KAccelActions::actionPtr( " << sAction << " ): encountered null pointer at m_prgActions[" << i << "]" << endl; else if( m_prgActions[i]->m_sName == sAction ) return (int) i; } return -1; } KAccelAction* KAccelActions::actionPtr( uint i ) { return m_prgActions[i]; } const KAccelAction* KAccelActions::actionPtr( uint i ) const { return m_prgActions[i]; } KAccelAction* KAccelActions::actionPtr( const TQString& sAction ) { int i = actionIndex( sAction ); return (i >= 0) ? m_prgActions[i] : 0; } const KAccelAction* KAccelActions::actionPtr( const TQString& sAction ) const { int i = actionIndex( sAction ); return (i >= 0) ? m_prgActions[i] : 0; } KAccelAction* KAccelActions::actionPtr( KKeySequence cut ) { for( uint i = 0; i < m_nSize; i++ ) { if( m_prgActions[i] == 0 ) kdWarning(125) << "KAccelActions::actionPtr( " << cut.toStringInternal() << " ): encountered null pointer at m_prgActions[" << i << "]" << endl; else if( m_prgActions[i]->contains( cut ) ) return m_prgActions[i]; } return 0; } KAccelAction& KAccelActions::operator []( uint i ) { return *actionPtr( i ); } const KAccelAction& KAccelActions::operator []( uint i ) const { return *actionPtr( i ); } KAccelAction* KAccelActions::insert( const TQString& sName, const TQString& sLabel ) { if( actionPtr( sName ) ) { kdWarning(125) << "KAccelActions::insertLabel( " << sName << ", " << sLabel << " ): action with same name already present." << endl; return 0; } KAccelAction* pAction = new KAccelAction; pAction->m_sName = sName; pAction->m_sLabel = sLabel; pAction->m_bConfigurable = false; pAction->m_bEnabled = false; insertPtr( pAction ); return pAction; } KAccelAction* KAccelActions::insert( const TQString& sAction, const TQString& sLabel, const TQString& sWhatsThis, const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4, const TQObject* pObjSlot, const char* psMethodSlot, bool bConfigurable, bool bEnabled ) { //kdDebug(125) << "KAccelActions::insert()2 begin" << endl; if( actionPtr( sAction ) ) { kdWarning(125) << "KAccelActions::insert( " << sAction << " ): action with same name already present." << endl; return 0; } KAccelAction* pAction = new KAccelAction( sAction, sLabel, sWhatsThis, rgCutDefaults3, rgCutDefaults4, pObjSlot, psMethodSlot, bConfigurable, bEnabled ); insertPtr( pAction ); //kdDebug(125) << "KAccelActions::insert()2 end" << endl; return pAction; } bool KAccelActions::remove( const TQString& sAction ) { kdDebug(125) << "KAccelActions::remove( \"" << sAction << "\" ): this = " << this << " m_pKAccelBase = " << m_pKAccelBase << endl; int iAction = actionIndex( sAction ); if( iAction < 0 ) return false; if( m_pKAccelBase ) m_pKAccelBase->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 KAccelActions::readActions( const TQString& sConfigGroup, KConfigBase* pConfig ) { KAccelShortcutList accelList(*this, false); return accelList.readSettings( sConfigGroup, pConfig ); } /* 1) KAccelAction = "Something" 1) KKeySequence = "Meta+X,Asterisk" 1) KAccelSequence = "Meta+X" 1) KKeySequence = Meta+X 2) KAccelSequence = "Asterisk" 1) KKeySequence = Shift+8 (English layout) 2) KKeySequence = Keypad_Asterisk 2) KKeySequence = "Alt+F2" 1) KAccelSequence = "Alt+F2" 1) KKeySequence = Alt+F2 -> "Something=Meta+X,Asterisk;Alt+F2" */ bool KAccelActions::writeActions( const TQString &sGroup, KConfigBase* pConfig, bool bWriteAll, bool bGlobal ) const { kdDebug(125) << "KAccelActions::writeActions( " << sGroup << ", " << pConfig << ", " << bWriteAll << ", " << bGlobal << " )" << endl; if( !pConfig ) pConfig = KGlobal::config(); KConfigGroupSaver cs( pConfig, sGroup ); for( uint i = 0; i < m_nSize; i++ ) { if( m_prgActions[i] == 0 ) { kdWarning(125) << "KAccelActions::writeActions(): encountered null pointer at m_prgActions[" << i << "]" << endl; continue; } const KAccelAction& 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 KAccelActions::emitKeycodeChanged() { if( m_pKAccelBase ) m_pKAccelBase->emitSignal( KAccelBase::KEYCODE_CHANGED ); } uint KAccelActions::count() const { return m_nSize; }