kdeui Library API Documentation

kkeydialog.cpp

00001 /* This file is part of the KDE libraries
00002     Copyright (C) 1998 Mark Donohoe <donohoe@kde.org>
00003     Copyright (C) 1997 Nicolas Hadacek <hadacek@kde.org>
00004     Copyright (C) 1998 Matthias Ettrich <ettrich@kde.org>
00005     Copyright (C) 2001 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., 59 Temple Place - Suite 330,
00020     Boston, MA 02111-1307, USA.
00021 */
00022 
00023 #include "kkeydialog.h"
00024 #include "kkeybutton.h"
00025 
00026 #include <string.h>
00027 
00028 #include <qbuttongroup.h>
00029 #include <qlabel.h>
00030 #include <qlayout.h>
00031 #include <qdrawutil.h>
00032 #include <qpainter.h>
00033 #include <qradiobutton.h>
00034 #include <qregexp.h>
00035 #include <qwhatsthis.h>
00036 
00037 #include <kaccel.h>
00038 #include <kaction.h>
00039 #include <kactionshortcutlist.h>
00040 #include <kapplication.h>
00041 #include <kconfig.h>
00042 #include <kdebug.h>
00043 #include <kglobal.h>
00044 #include <kglobalaccel.h>
00045 #include <klocale.h>
00046 #include <kmessagebox.h>
00047 #include <kshortcut.h>
00048 #include <kshortcutlist.h>
00049 #include <kxmlguifactory.h>
00050 #include <kaboutdata.h>
00051 #include <kstaticdeleter.h>
00052 
00053 #ifdef Q_WS_X11
00054 #define XK_XKB_KEYS
00055 #define XK_MISCELLANY
00056 #include <X11/Xlib.h>   // For x11Event()
00057 #include <X11/keysymdef.h> // For XK_...
00058 
00059 #ifdef KeyPress
00060 const int XFocusOut = FocusOut;
00061 const int XFocusIn = FocusIn;
00062 const int XKeyPress = KeyPress;
00063 const int XKeyRelease = KeyRelease;
00064 #undef KeyRelease
00065 #undef KeyPress
00066 #undef FocusOut
00067 #undef FocusIn
00068 #endif
00069 #endif
00070 
00071 //---------------------------------------------------------------------
00072 // KKeyChooserItem
00073 //---------------------------------------------------------------------
00074 
00075 class KKeyChooserItem : public KListViewItem
00076 {
00077  public:
00078     KKeyChooserItem( KListView* parent, QListViewItem* after, KShortcutList* pList, uint iAction );
00079     KKeyChooserItem( QListViewItem* parent, QListViewItem* after, KShortcutList* pList, uint iAction );
00080 
00081     QString actionName() const;
00082     const KShortcut& shortcut() const;
00083     bool isConfigurable() const
00084         { return m_pList->isConfigurable( m_iAction ); }
00085     const KShortcut& shortcutDefault() const
00086         { return m_pList->shortcutDefault( m_iAction ); }
00087 
00088     void setShortcut( const KShortcut& cut );
00089     void commitChanges();
00090 
00091     virtual QString text( int iCol ) const;
00092     virtual int compare( QListViewItem*, int iCol, bool bAscending ) const;
00093 
00094  protected:
00095     KShortcutList* m_pList;
00096     uint m_iAction;
00097     bool m_bModified;
00098     KShortcut m_cut;
00099 };
00100 
00101 //---------------------------------------------------------------------
00102 // KKeyChooserPrivate
00103 //---------------------------------------------------------------------
00104 
00105 class KKeyChooserPrivate
00106 {
00107  public:
00108     QValueList<KShortcutList*> rgpLists;
00109     QValueList<KShortcutList*> rgpListsAllocated;
00110 
00111     KListView *pList;
00112     QLabel *lInfo;
00113     KKeyButton *pbtnShortcut;
00114     QGroupBox *fCArea;
00115     QButtonGroup *kbGroup;
00116 
00117     QMap<QString, KShortcut> mapGlobals;
00118 
00119     bool bAllowWinKey;
00120     // If this is set, then shortcuts require a modifier:
00121     //  so 'A' would not be valid, whereas 'Ctrl+A' would be.
00122     // Note, however, that this only applies to printable characters.
00123     //  'F1', 'Insert', etc., could still be used.
00124     bool bAllowLetterShortcuts;
00125     // When set, pressing the 'Default' button will select the aDefaultKeycode4,
00126     //  otherwise aDefaultKeycode.
00127     bool bPreferFourModifierKeys;
00128 };
00129 
00130 //---------------------------------------------------------------------
00131 // KKeyChooser
00132 //---------------------------------------------------------------------
00133 
00134 KKeyChooser::KKeyChooser( QWidget* parent, ActionType type, bool bAllowLetterShortcuts )
00135 : QWidget( parent )
00136 {
00137     initGUI( type, bAllowLetterShortcuts );
00138 }
00139 
00140 KKeyChooser::KKeyChooser( KActionCollection* coll, QWidget* parent, bool bAllowLetterShortcuts )
00141 : QWidget( parent )
00142 {
00143     initGUI( Application, bAllowLetterShortcuts );
00144     insert( coll );
00145 }
00146 
00147 KKeyChooser::KKeyChooser( KAccel* pAccel, QWidget* parent, bool bAllowLetterShortcuts )
00148 : QWidget( parent )
00149 {
00150     initGUI( Application, bAllowLetterShortcuts );
00151     insert( pAccel );
00152 }
00153 
00154 KKeyChooser::KKeyChooser( KGlobalAccel* pAccel, QWidget* parent )
00155 : QWidget( parent )
00156 {
00157     initGUI( ApplicationGlobal, false );
00158     insert( pAccel );
00159 }
00160 
00161 KKeyChooser::KKeyChooser( KShortcutList* pList, QWidget* parent, ActionType type, bool bAllowLetterShortcuts )
00162 : QWidget( parent )
00163 {
00164     initGUI( type, bAllowLetterShortcuts );
00165     insert( pList );
00166 }
00167 
00168 KKeyChooser::KKeyChooser( KAccel* actions, QWidget* parent,
00169             bool bCheckAgainstStdKeys,
00170             bool bAllowLetterShortcuts,
00171             bool bAllowWinKey )
00172 : QWidget( parent )
00173 {
00174     ActionType type;
00175     if( bAllowWinKey )
00176         type = (bCheckAgainstStdKeys) ? ApplicationGlobal : Global;
00177     else
00178         type = Application;
00179 
00180     initGUI( type, bAllowLetterShortcuts );
00181     insert( actions );
00182 }
00183 
00184 KKeyChooser::KKeyChooser( KGlobalAccel* actions, QWidget* parent,
00185             bool bCheckAgainstStdKeys,
00186             bool bAllowLetterShortcuts,
00187             bool /*bAllowWinKey*/ )
00188 : QWidget( parent )
00189 {
00190     ActionType type = (bCheckAgainstStdKeys) ? ApplicationGlobal : Global;
00191 
00192     initGUI( type, bAllowLetterShortcuts );
00193     insert( actions );
00194 }
00195 
00196 // list of all existing KKeyChooser's of type Global
00197 // used when checking global shortcut for a possible conflict
00198 // (just checking against kdeglobals isn't enough, the shortcuts
00199 // might have changed in KKeyChooser and not being saved yet)
00200 static QValueList< KKeyChooser* >* globalChoosers = NULL;
00201 static KStaticDeleter< QValueList< KKeyChooser* > > globalChoosersDeleter;
00202 
00203 KKeyChooser::~KKeyChooser()
00204 {
00205         if( m_type == Global && globalChoosers != NULL )
00206             globalChoosers->remove( this );
00207     // Delete allocated KShortcutLists
00208     for( uint i = 0; i < d->rgpListsAllocated.count(); i++ )
00209         delete d->rgpListsAllocated[i];
00210     delete d;
00211 }
00212 
00213 bool KKeyChooser::insert( KActionCollection *pColl)
00214 {
00215     return insert(pColl, QString::null);
00216 }
00217 
00218 bool KKeyChooser::insert( KActionCollection* pColl, const QString &title )
00219 {
00220     QString str = title;
00221     if ( title.isEmpty() && pColl->instance()
00222          && pColl->instance()->aboutData() )
00223         str = pColl->instance()->aboutData()->programName();
00224 
00225     KShortcutList* pList = new KActionShortcutList( pColl );
00226     d->rgpListsAllocated.append( pList );
00227     d->rgpLists.append( pList );
00228     buildListView(d->rgpLists.count() - 1, str);
00229     return true;
00230 }
00231 
00232 bool KKeyChooser::insert( KAccel* pAccel )
00233 {
00234     KShortcutList* pList = new KAccelShortcutList( pAccel );
00235     d->rgpListsAllocated.append( pList );
00236     return insert( pList );
00237 }
00238 
00239 bool KKeyChooser::insert( KGlobalAccel* pAccel )
00240 {
00241     KShortcutList* pList = new KAccelShortcutList( pAccel );
00242     d->rgpListsAllocated.append( pList );
00243     return insert( pList );
00244 }
00245 
00246 bool KKeyChooser::insert( KShortcutList* pList )
00247 {
00248     d->rgpLists.append( pList );
00249     buildListView( d->rgpLists.count() - 1, QString::null );
00250     return true;
00251 }
00252 
00253 void KKeyChooser::commitChanges()
00254 {
00255     kdDebug(125) << "KKeyChooser::commitChanges()" << endl;
00256 
00257     QListViewItemIterator it( d->pList );
00258     for( ; it.current(); ++it ) {
00259         KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(it.current());
00260         if( pItem )
00261             pItem->commitChanges();
00262     }
00263 }
00264 
00265 void KKeyChooser::save()
00266 {
00267     commitChanges();
00268     for( uint i = 0; i < d->rgpLists.count(); i++ )
00269         d->rgpLists[i]->save();
00270 }
00271 
00272 void KKeyChooser::initGUI( ActionType type, bool bAllowLetterShortcuts )
00273 {
00274   d = new KKeyChooserPrivate();
00275 
00276   m_type = type;
00277   d->bAllowLetterShortcuts = bAllowLetterShortcuts;
00278 
00279   d->bAllowWinKey = (m_type == Global || m_type == ApplicationGlobal);
00280   d->bPreferFourModifierKeys = KGlobalAccel::useFourModifierKeys();
00281 
00282   //
00283   // TOP LAYOUT MANAGER
00284   //
00285   // The following layout is used for the dialog
00286   //            LIST LABELS LAYOUT
00287   //            SPLIT LIST BOX WIDGET
00288   //            CHOOSE KEY GROUP BOX WIDGET
00289   //            BUTTONS LAYOUT
00290   // Items are added to topLayout as they are created.
00291   //
00292 
00293   QBoxLayout *topLayout = new QVBoxLayout( this, 0, KDialog::spacingHint() );
00294 
00295   QGridLayout *stackLayout = new QGridLayout(2, 2, 2);
00296   topLayout->addLayout( stackLayout, 10 );
00297   stackLayout->setRowStretch( 1, 10 ); // Only list will stretch
00298 
00299   //
00300   // CREATE SPLIT LIST BOX
00301   //
00302   // fill up the split list box with the action/key pairs.
00303   //
00304   d->pList = new KListView( this );
00305   d->pList->setFocus();
00306 
00307   stackLayout->addMultiCellWidget( d->pList, 1, 1, 0, 1 );
00308   QString wtstr = i18n("Here you can see a list of key bindings, "
00309                        "i.e. associations between actions (e.g. 'Copy') "
00310                        "shown in the left column and keys or combination "
00311                        "of keys (e.g. Ctrl+V) shown in the right column.");
00312 
00313   QWhatsThis::add( d->pList, wtstr );
00314 
00315   d->pList->setAllColumnsShowFocus( true );
00316   d->pList->addColumn(i18n("Action"));
00317   d->pList->addColumn(i18n("Shortcut"));
00318   d->pList->addColumn(i18n("Alternate"));
00319 
00320   connect( d->pList, SIGNAL(currentChanged(QListViewItem*)),
00321            SLOT(slotListItemSelected(QListViewItem*)) );
00322 
00323   //
00324   // CREATE CHOOSE KEY GROUP
00325   //
00326   d->fCArea = new QGroupBox( this );
00327   topLayout->addWidget( d->fCArea, 1 );
00328 
00329   d->fCArea->setTitle( i18n("Shortcut for Selected Action") );
00330   d->fCArea->setFrameStyle( QFrame::Box | QFrame::Sunken );
00331 
00332   //
00333   // CHOOSE KEY GROUP LAYOUT MANAGER
00334   //
00335   QGridLayout *grid = new QGridLayout( d->fCArea, 3, 4, KDialog::spacingHint() );
00336   grid->addRowSpacing( 0, fontMetrics().lineSpacing() );
00337 
00338   d->kbGroup = new QButtonGroup( d->fCArea );
00339   d->kbGroup->hide();
00340   d->kbGroup->setExclusive( true );
00341 
00342   m_prbNone = new QRadioButton( i18n("no key", "&None"), d->fCArea );
00343   d->kbGroup->insert( m_prbNone, NoKey );
00344   m_prbNone->setEnabled( false );
00345   //grid->addMultiCellWidget( rb, 1, 1, 1, 2 );
00346   grid->addWidget( m_prbNone, 1, 0 );
00347   QWhatsThis::add( m_prbNone, i18n("The selected action will not be associated with any key.") );
00348   connect( m_prbNone, SIGNAL(clicked()), SLOT(slotNoKey()) );
00349 
00350   m_prbDef = new QRadioButton( i18n("default key", "De&fault"), d->fCArea );
00351   d->kbGroup->insert( m_prbDef, DefaultKey );
00352   m_prbDef->setEnabled( false );
00353   //grid->addMultiCellWidget( rb, 2, 2, 1, 2 );
00354   grid->addWidget( m_prbDef, 1, 1 );
00355   QWhatsThis::add( m_prbDef, i18n("This will bind the default key to the selected action. Usually a reasonable choice.") );
00356   connect( m_prbDef, SIGNAL(clicked()), SLOT(slotDefaultKey()) );
00357 
00358   m_prbCustom = new QRadioButton( i18n("C&ustom"), d->fCArea );
00359   d->kbGroup->insert( m_prbCustom, CustomKey );
00360   m_prbCustom->setEnabled( false );
00361   //grid->addMultiCellWidget( rb, 3, 3, 1, 2 );
00362   grid->addWidget( m_prbCustom, 1, 2 );
00363   QWhatsThis::add( m_prbCustom, i18n("If this option is selected you can create a customized key binding for the"
00364     " selected action using the buttons below.") );
00365   connect( m_prbCustom, SIGNAL(clicked()), SLOT(slotCustomKey()) );
00366 
00367   //connect( d->kbGroup, SIGNAL( clicked( int ) ), SLOT( keyMode( int ) ) );
00368 
00369   QBoxLayout *pushLayout = new QHBoxLayout( KDialog::spacingHint() );
00370   grid->addLayout( pushLayout, 1, 3 );
00371 
00372   d->pbtnShortcut = new KKeyButton(d->fCArea, "key");
00373   d->pbtnShortcut->setEnabled( false );
00374   connect( d->pbtnShortcut, SIGNAL(capturedShortcut(const KShortcut&)), SLOT(capturedShortcut(const KShortcut&)) );
00375   grid->addRowSpacing( 1, d->pbtnShortcut->sizeHint().height() + 5 );
00376 
00377   wtstr = i18n("Use this button to choose a new shortcut key. Once you click it, "
00378         "you can press the key-combination which you would like to be assigned "
00379         "to the currently selected action.");
00380   QWhatsThis::add( d->pbtnShortcut, wtstr );
00381 
00382   //
00383   // Add widgets to the geometry manager
00384   //
00385   pushLayout->addSpacing( KDialog::spacingHint()*2 );
00386   pushLayout->addWidget( d->pbtnShortcut );
00387   pushLayout->addStretch( 10 );
00388 
00389   d->lInfo = new QLabel(d->fCArea);
00390   //resize(0,0);
00391   //d->lInfo->setAlignment( AlignCenter );
00392   //d->lInfo->setEnabled( false );
00393   //d->lInfo->hide();
00394   grid->addMultiCellWidget( d->lInfo, 2, 2, 0, 3 );
00395 
00396   //d->globalDict = new QDict<int> ( 100, false );
00397   //d->globalDict->setAutoDelete( true );
00398   readGlobalKeys();
00399   //d->stdDict = new QDict<int> ( 100, false );
00400   //d->stdDict->setAutoDelete( true );
00401   //if (type == Application || type == ApplicationGlobal)
00402   //  readStdKeys();
00403   connect( kapp, SIGNAL( settingsChanged( int )), SLOT( slotSettingsChanged( int )));
00404   if( m_type == Global ) {
00405       if( globalChoosers == NULL )
00406           globalChoosers = globalChoosersDeleter.setObject( new QValueList< KKeyChooser* > );
00407       globalChoosers->append( this );
00408   }
00409 }
00410 
00411 // Add all shortcuts to the list
00412 void KKeyChooser::buildListView( uint iList, const QString &title )
00413 {
00414     KShortcutList* pList = d->rgpLists[iList];
00415 
00416     //d->pList->setSorting( -1 );
00417     KListViewItem *pProgramItem, *pGroupItem = 0, *pParentItem, *pItem;
00418 
00419     QString str = (title.isEmpty() ? i18n("Shortcuts") : title);
00420     pParentItem = pProgramItem = pItem = new KListViewItem( d->pList, str );
00421     pParentItem->setExpandable( true );
00422     pParentItem->setOpen( true );
00423     pParentItem->setSelectable( false );
00424     uint nSize = pList->count();
00425     for( uint iAction = 0; iAction < nSize; iAction++ ) {
00426         QString sName = pList->name(iAction);
00427         kdDebug(125) << "Key: " << sName << endl;
00428         if( sName.startsWith( "Program:" ) ) {
00429             pItem = new KListViewItem( d->pList, pProgramItem, pList->label(iAction) );
00430             pItem->setSelectable( false );
00431             pItem->setExpandable( true );
00432             pItem->setOpen( true );
00433             if( !pProgramItem->firstChild() )
00434                 delete pProgramItem;
00435             pProgramItem = pParentItem = pItem;
00436         } else if( sName.startsWith( "Group:" ) ) {
00437             pItem = new KListViewItem( pProgramItem, pParentItem, pList->label(iAction) );
00438             pItem->setSelectable( false );
00439             pItem->setExpandable( true );
00440             pItem->setOpen( true );
00441             if( pGroupItem && !pGroupItem->firstChild() )
00442                 delete pGroupItem;
00443             pGroupItem = pParentItem = pItem;
00444         } else if( !sName.isEmpty() && pList->isConfigurable(iAction) )
00445             pItem = new KKeyChooserItem( pParentItem, pItem, pList, iAction );
00446     }
00447     if( !pProgramItem->firstChild() )
00448         delete pProgramItem;
00449     if( pGroupItem && !pGroupItem->firstChild() )
00450         delete pGroupItem;
00451 }
00452 
00453 void KKeyChooser::updateButtons()
00454 {
00455     // Hack: Do this incase we still have changeKey() running.
00456     //  Better would be to capture the mouse pointer so that we can't click
00457     //   around while we're supposed to be entering a key.
00458     //  Better yet would be a modal dialog for changeKey()!
00459     releaseKeyboard();
00460     KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00461 
00462     if ( !pItem ) {
00463         // if nothing is selected -> disable radio boxes
00464         m_prbNone->setEnabled( false );
00465         m_prbDef->setEnabled( false );
00466         m_prbCustom->setEnabled( false );
00467         d->pbtnShortcut->setEnabled( false );
00468         d->pbtnShortcut->setShortcut( KShortcut() );
00469     } else {
00470         bool bConfigurable = pItem->isConfigurable();
00471         bool bQtShortcut = (m_type == Application || m_type == Standard);
00472         const KShortcut& cutDef = pItem->shortcutDefault();
00473 
00474         // Set key strings
00475         QString keyStrCfg = pItem->shortcut().toString();
00476         QString keyStrDef = cutDef.toString();
00477 
00478         d->pbtnShortcut->setShortcut( pItem->shortcut(), bQtShortcut );
00479         //item->setText( 1, keyStrCfg );
00480         pItem->repaint();
00481         d->lInfo->setText( i18n("Default key:") + QString(" %1").arg(keyStrDef.isEmpty() ? i18n("None") : keyStrDef) );
00482 
00483         // Select the appropriate radio button.
00484         int index = (pItem->shortcut().isNull()) ? NoKey
00485                 : (pItem->shortcut() == cutDef) ? DefaultKey
00486                 : CustomKey;
00487         m_prbNone->setChecked( index == NoKey );
00488         m_prbDef->setChecked( index == DefaultKey );
00489         m_prbCustom->setChecked( index == CustomKey );
00490 
00491         // Enable buttons if this key is configurable.
00492         // The 'Default Key' button must also have a default key.
00493         m_prbNone->setEnabled( bConfigurable );
00494         m_prbDef->setEnabled( bConfigurable && cutDef.count() != 0 );
00495         m_prbCustom->setEnabled( bConfigurable );
00496         d->pbtnShortcut->setEnabled( bConfigurable );
00497     }
00498 }
00499 
00500 void KKeyChooser::slotNoKey()
00501 {
00502     // return if no key is selected
00503     KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00504     if( pItem ) {
00505         //kdDebug(125) << "no Key" << d->pList->currentItem()->text(0) << endl;
00506         pItem->setShortcut( KShortcut() );
00507         updateButtons();
00508         emit keyChange();
00509     }
00510 }
00511 
00512 void KKeyChooser::slotDefaultKey()
00513 {
00514     // return if no key is selected
00515     KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00516     if( pItem ) {
00517         pItem->setShortcut( pItem->shortcutDefault() );
00518         updateButtons();
00519         emit keyChange();
00520     }
00521 }
00522 
00523 void KKeyChooser::slotCustomKey()
00524 {
00525     d->pbtnShortcut->captureShortcut();
00526 }
00527 
00528 void KKeyChooser::readGlobalKeys()
00529 {
00530         d->mapGlobals.clear();
00531         if( m_type == Global )
00532             return; // they will be checked normally, because we're configuring them
00533     QMap<QString, QString> mapEntry = KGlobal::config()->entryMap( "Global Shortcuts" );
00534     QMap<QString, QString>::Iterator it( mapEntry.begin() );
00535     for( uint i = 0; it != mapEntry.end(); ++it, i++ )
00536         d->mapGlobals[it.key()] = KShortcut(*it);
00537 }
00538 
00539 void KKeyChooser::slotSettingsChanged( int category )
00540 {
00541     if( category == KApplication::SETTINGS_SHORTCUTS )
00542         readGlobalKeys(); // reread
00543 }
00544 
00545 void KKeyChooser::fontChange( const QFont & )
00546 {
00547         d->fCArea->setMinimumHeight( 4*d->pbtnShortcut->sizeHint().height() );
00548 
00549         int widget_width = 0;
00550 
00551         setMinimumWidth( 20+5*(widget_width+10) );
00552 }
00553 
00554 void KKeyChooser::allDefault()
00555 {
00556     kdDebug(125) << "KKeyChooser::allDefault()" << endl;
00557 
00558     QListViewItemIterator it( d->pList );
00559     for( ; it.current(); ++it ) {
00560         KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(it.current());
00561         if( pItem )
00562             pItem->setShortcut( pItem->shortcutDefault() );
00563     }
00564 
00565     updateButtons();
00566     emit keyChange();
00567 }
00568 
00569 void KKeyChooser::slotListItemSelected( QListViewItem* )
00570 {
00571     updateButtons();
00572 }
00573 
00574 void KKeyChooser::setPreferFourModifierKeys( bool bPreferFourModifierKeys )
00575 {
00576     d->bPreferFourModifierKeys = bPreferFourModifierKeys;
00577 }
00578 
00579 void KKeyChooser::capturedShortcut( const KShortcut& cut )
00580 {
00581     if( cut.isNull() )
00582         slotNoKey();
00583     else
00584         setShortcut( cut );
00585 }
00586 
00587 // FIXME: give this functionality again -- I don't think it's ever used, though. -- ellis
00588 // TODO: Check lxr.kde.org to see if it's used anywhere
00589 void KKeyChooser::listSync()
00590 {
00591 /*  kdDebug(125) << "KKeyChooser::listSync()" << endl;
00592 
00593     if( d->pColl ) {
00594         // TODO: This is very inefficient.  Come up with something better.
00595         KAccelActions aa;
00596         d->pColl->createKeyMap( aa );
00597         d->actionsNew.updateShortcuts( aa );
00598     } else if( d->pActionsOrig ) {
00599         d->actionsNew.updateShortcuts( *d->pActionsOrig );
00600         update();
00601         updateButtons();
00602     }*/
00603 }
00604 
00605 void KKeyChooser::syncToConfig( const QString& sConfigGroup, KConfigBase* pConfig, bool bClearUnset )
00606 {
00607     kdDebug(125) << "KKeyChooser::syncToConfig( \"" << sConfigGroup << "\", " << pConfig << " ) start" << endl;
00608     if( !pConfig )
00609         pConfig = KGlobal::config();
00610     KConfigGroupSaver cgs( pConfig, sConfigGroup );
00611 
00612     QListViewItemIterator it( d->pList );
00613     for( ; it.current(); ++it ) {
00614         KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(it.current());
00615         if( pItem ) {
00616             QString sEntry = pConfig->readEntry( pItem->actionName() );
00617             if( !sEntry.isNull() || bClearUnset ) {
00618                 if( sEntry == "none" )
00619                     sEntry = QString::null;
00620                 pItem->setShortcut( sEntry );
00621             }
00622             kdDebug(125) << pItem->actionName() << " = " << pItem->shortcut().toStringInternal() << endl;
00623         }
00624     }
00625     updateButtons();
00626     kdDebug(125) << "KKeyChooser::syncToConfig() done" << endl;
00627 }
00628 
00629 void KKeyChooser::setShortcut( const KShortcut& cut )
00630 {
00631     kdDebug(125) << "KKeyChooser::setShortcut( " << cut.toString() << " )" << endl;
00632     KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(d->pList->currentItem());
00633     if( !pItem )
00634         return;
00635 
00636     for( uint i = 0; i < cut.count(); i++ ) {
00637         const KKeySequence& seq = cut.seq(i);
00638         const KKey& key = seq.key(0);
00639 
00640         if( !d->bAllowWinKey && (key.modFlags() & KKey::WIN) ) {
00641             QString s = i18n("The Win key is not allowed in this context.");
00642             KMessageBox::sorry( this, s, i18n("Invalid Shortcut Key") );
00643             return;
00644         }
00645         if( !d->bAllowLetterShortcuts && key.modFlags() == 0
00646             && key.sym() < 0x3000 && QChar(key.sym()).isLetterOrNumber() ) {
00647             QString s = i18n(   "In order to use the '%1' key as a shortcut, "
00648                         "it must be combined with the "
00649                         "Win, Alt, Ctrl, and/or Shift keys." ).arg(QChar(key.sym()));
00650             KMessageBox::sorry( this, s, i18n("Invalid Shortcut Key") );
00651             return;
00652         }
00653     }
00654 
00655     // If key isn't already in use,
00656     if( !isKeyPresent( cut ) ) {
00657         // Set new key code
00658         pItem->setShortcut( cut );
00659         // Update display
00660         updateButtons();
00661         emit keyChange();
00662     }
00663 }
00664 
00665 // Returns iSeq index if cut2 has a sequence of equal or higher priority to a sequence in cut.
00666 // else -1
00667 static int keyConflict( const KShortcut& cut, const KShortcut& cut2 )
00668 {
00669     for( uint iSeq = 0; iSeq < cut.count(); iSeq++ ) {
00670         for( uint iSeq2 = 0; iSeq2 <= iSeq && iSeq2 < cut2.count(); iSeq2++ ) {
00671             if( cut.seq(iSeq) == cut2.seq(iSeq2) )
00672                 return iSeq;
00673         }
00674     }
00675     return -1;
00676 }
00677 
00678 bool KKeyChooser::isKeyPresent( const KShortcut& cut, bool bWarnUser )
00679 {
00680     KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(d->pList->currentItem());
00681 
00682     // If editing global shortcuts, check them for conflicts with the stdaccels.
00683     if( m_type == ApplicationGlobal || m_type == Global ) {
00684         // For each key sequence in the shortcut,
00685         for( uint i = 0; i < cut.count(); i++ ) {
00686             const KKeySequence& seq = cut.seq(i);
00687 
00688             KStdAccel::StdAccel id = KStdAccel::findStdAccel( seq );
00689             if( id != KStdAccel::AccelNone
00690                 && keyConflict( cut, KStdAccel::shortcut( id ) ) > -1 ) {
00691                 if( bWarnUser )
00692                     _warning( seq, KStdAccel::label(id), i18n("Conflict with Standard Application Shortcut") );
00693                 return true;
00694             }
00695         }
00696     }
00697 
00698     QMap<QString, KShortcut>::ConstIterator it;
00699     for( it = d->mapGlobals.begin(); it != d->mapGlobals.end(); ++it ) {
00700         int iSeq = keyConflict( cut, (*it) );
00701         if( iSeq > -1 ) {
00702             if( m_type != Global || it.key() != pItem->actionName() ) {
00703                 if( bWarnUser )
00704                     _warning( cut.seq(iSeq), it.key(), i18n("Conflict with Global Shortcuts") );
00705                 return true;
00706             }
00707         }
00708     }
00709         
00710         if( isKeyPresentLocally( cut, pItem, bWarnUser ? i18n("Key Conflict") : QString::null ))
00711             return true;
00712 
00713         // check also other Global KKeyChooser's
00714         if( m_type == Global && globalChoosers != NULL ) {
00715             for( QValueList< KKeyChooser* >::ConstIterator it = globalChoosers->begin();
00716                  it != globalChoosers->end();
00717                  ++it ) {
00718                 if( (*it) != this && (*it)->isKeyPresentLocally( cut, NULL,
00719                     bWarnUser ? i18n("Key Conflict") : QString::null))
00720                     return true;
00721             }
00722         }
00723     return false;
00724 }
00725 
00726 bool KKeyChooser::isKeyPresentLocally( const KShortcut& cut, KKeyChooserItem* ignoreItem, const QString& warnText )
00727 {
00728     // Search for shortcut conflicts with other actions in the
00729     //  lists we're configuring.
00730     for( QListViewItemIterator it( d->pList ); it.current(); ++it ) {
00731         KKeyChooserItem* pItem2 = dynamic_cast<KKeyChooserItem*>(it.current());
00732         if( pItem2 && pItem2 != ignoreItem ) {
00733             int iSeq = keyConflict( cut, pItem2->shortcut() );
00734             if( iSeq > -1 ) {
00735                 if( !warnText.isNull() )
00736                     _warning( cut.seq(iSeq), pItem2->text(0), warnText );
00737                 return true;
00738             }
00739         }
00740     }
00741         return false;            
00742 }
00743 
00744 void KKeyChooser::_warning( const KKeySequence& cut, QString sAction, QString sTitle )
00745 {
00746     sAction = sAction.stripWhiteSpace();
00747 
00748     QString s =
00749         i18n("The '%1' key combination has already been allocated "
00750         "to the \"%2\" action.\n"
00751         "Please choose a unique key combination.").
00752         arg(cut.toString()).arg(sAction);
00753 
00754     KMessageBox::sorry( this, s, sTitle );
00755 }
00756 
00757 //---------------------------------------------------
00758 KKeyChooserItem::KKeyChooserItem( KListView* parent, QListViewItem* after, KShortcutList* pList, uint iAction )
00759 :   KListViewItem( parent, after )
00760 {
00761     m_pList = pList;
00762     m_iAction = iAction;
00763     m_bModified = false;
00764     m_cut = m_pList->shortcut(m_iAction);
00765 }
00766 
00767 KKeyChooserItem::KKeyChooserItem( QListViewItem* parent, QListViewItem* after, KShortcutList* pList, uint iAction )
00768 :   KListViewItem( parent, after )
00769 {
00770     m_pList = pList;
00771     m_iAction = iAction;
00772     m_bModified = false;
00773     m_cut = m_pList->shortcut(m_iAction);
00774 }
00775 
00776 QString KKeyChooserItem::actionName() const
00777 {
00778     return m_pList->name(m_iAction);
00779 }
00780 
00781 const KShortcut& KKeyChooserItem::shortcut() const
00782 {
00783     return m_cut;
00784 }
00785 
00786 void KKeyChooserItem::setShortcut( const KShortcut& cut )
00787 {
00788     m_cut = cut;
00789     m_bModified = (m_cut != m_pList->shortcut(m_iAction));
00790     listView()->repaintItem( this );
00791 }
00792 
00793 void KKeyChooserItem::commitChanges()
00794 {
00795     if( m_bModified )
00796         m_pList->setShortcut( m_iAction, m_cut );
00797 }
00798 
00799 QString KKeyChooserItem::text( int iCol ) const
00800 {
00801     if( iCol == 0 ) {
00802         // Quick HACK to get rid of '&'s.
00803         QString s = m_pList->label(m_iAction);
00804         QString s2;
00805         for( uint i = 0; i < s.length(); i++ )
00806             if( s[i] != '&' || ( i+1<s.length() && s[i+1] == '&' ) )
00807                 s2 += s[i];
00808         return s2;
00809     }
00810     else if( iCol <= (int) m_cut.count() )
00811         return m_cut.seq(iCol-1).toString();
00812     else
00813         return QString::null;
00814 }
00815 
00816 int KKeyChooserItem::compare( QListViewItem* item, int iCol, bool bAscending ) const
00817 {
00818     KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( item );
00819     if( iCol == 0 && pItem ) {
00820         QString psName1 = m_pList->name(m_iAction);
00821         QString psName2 = pItem->m_pList->name(pItem->m_iAction);
00822         QRegExp rxNumber1( " (\\d+)$" );
00823         QRegExp rxNumber2( " (\\d+)$" );
00824         int iNumber1 = rxNumber1.search( psName1 );
00825         int iNumber2 = rxNumber2.search( psName2 );
00826 
00827         // Check if the last word is one or more digits
00828         if( iNumber1 >= 0 && iNumber1 == iNumber2 && psName1.startsWith( psName2.left( iNumber1+1 ) ) ) {
00829             int n1 = rxNumber1.cap(1).toInt();
00830             int n2 = rxNumber2.cap(1).toInt();
00831             return (n1 < n2) ? -1 : (n1 > n2) ? 1 : 0;
00832         }
00833     }
00834 
00835     return QListViewItem::compare( item, iCol, bAscending );
00836 }
00837 
00838 /************************************************************************/
00839 /* KKeyDialog                                                           */
00840 /*                                                                      */
00841 /* Originally by Nicolas Hadacek <hadacek@via.ecp.fr>                   */
00842 /*                                                                      */
00843 /* Substantially revised by Mark Donohoe <donohoe@kde.org>              */
00844 /*                                                                      */
00845 /* And by Espen Sand <espen@kde.org> 1999-10-19                         */
00846 /* (by using KDialogBase there is almost no code left ;)                */
00847 /*                                                                      */
00848 /************************************************************************/
00849 KKeyDialog::KKeyDialog( KKeyChooser::ActionType type, bool bAllowLetterShortcuts, QWidget *parent, const char* name )
00850 : KDialogBase( parent, name, true, i18n("Configure Shortcuts"), Help|Default|Ok|Cancel, Ok )
00851 {
00852     m_pKeyChooser = new KKeyChooser( this, type, bAllowLetterShortcuts );
00853     setMainWidget( m_pKeyChooser );
00854     connect( this, SIGNAL(defaultClicked()), m_pKeyChooser, SLOT(allDefault()) );
00855     enableButton( Help, false );
00856 
00857     KConfigGroup group( KGlobal::config(), "KKeyDialog Settings" );
00858     QSize sz = size();
00859     resize( group.readSizeEntry( "Dialog Size", &sz ) );
00860 }
00861 
00862 KKeyDialog::KKeyDialog( bool bAllowLetterShortcuts, QWidget *parent, const char* name )
00863 : KDialogBase( parent, name, true, i18n("Configure Shortcuts"), Help|Default|Ok|Cancel, Ok )
00864 {
00865     m_pKeyChooser = new KKeyChooser( this, KKeyChooser::Application, bAllowLetterShortcuts );
00866     setMainWidget( m_pKeyChooser );
00867     connect( this, SIGNAL(defaultClicked()), m_pKeyChooser, SLOT(allDefault()) );
00868     enableButton( Help, false );
00869 
00870     KConfigGroup group( KGlobal::config(), "KKeyDialog Settings" );
00871     QSize sz = size();
00872     resize( group.readSizeEntry( "Dialog Size", &sz ) );
00873 }
00874 
00875 KKeyDialog::~KKeyDialog()
00876 {
00877     KConfigGroup group( KGlobal::config(), "KKeyDialog Settings" );
00878     group.writeEntry( "Dialog Size", size(), true, true );
00879 }
00880 
00881 bool KKeyDialog::insert( KActionCollection* pColl )
00882 {
00883     return m_pKeyChooser->insert( pColl );
00884 }
00885 
00886 bool KKeyDialog::insert(KActionCollection *pColl, const QString &title)
00887 {
00888     return m_pKeyChooser->insert(pColl, title);
00889 }
00890 
00891 bool KKeyDialog::configure( bool bSaveSettings )
00892 {
00893     int retcode = exec();
00894     if( retcode == Accepted ) {
00895         if( bSaveSettings )
00896             m_pKeyChooser->save();
00897         else
00898             commitChanges();
00899     }
00900     return retcode;
00901 }
00902 
00903 void KKeyDialog::commitChanges()
00904 {
00905     m_pKeyChooser->commitChanges();
00906 }
00907 
00908 int KKeyDialog::configure( KActionCollection* coll, QWidget* parent, bool bSaveSettings )
00909 {
00910     return configure( coll, true, parent, bSaveSettings);
00911 }
00912 
00913 int KKeyDialog::configure( KAccel* keys, QWidget* parent, bool bSaveSettings )
00914 {
00915     return configure( keys, true, parent, bSaveSettings);
00916 }
00917 
00918 int KKeyDialog::configure( KGlobalAccel* keys, QWidget* parent, bool bSaveSettings )
00919 {
00920     return configure( keys, true, parent, bSaveSettings);
00921 }
00922 
00923 int KKeyDialog::configure( KAccel* keys, bool bAllowLetterShortcuts, QWidget *parent, bool bSaveSettings )
00924 {
00925     KKeyDialog dlg( bAllowLetterShortcuts, parent );
00926     dlg.m_pKeyChooser->insert( keys );
00927     bool b = dlg.configure( bSaveSettings );
00928     if( b && bSaveSettings )
00929         keys->updateConnections();
00930     return b;
00931 }
00932 
00933 int KKeyDialog::configure( KGlobalAccel* keys, bool bAllowLetterShortcuts, QWidget *parent, bool bSaveSettings )
00934 {
00935     KKeyDialog dlg( KKeyChooser::ApplicationGlobal, bAllowLetterShortcuts, parent );
00936     dlg.m_pKeyChooser->insert( keys );
00937     bool b = dlg.configure( bSaveSettings );
00938     if( b && bSaveSettings )
00939         keys->updateConnections();
00940     return b;
00941 }
00942 
00943 int KKeyDialog::configure( KActionCollection* coll, bool bAllowLetterShortcuts, QWidget *parent, bool bSaveSettings )
00944 {
00945     kdDebug(125) << "KKeyDialog::configureKeys( KActionCollection*, " << bSaveSettings << " )" << endl;
00946     KKeyDialog dlg( bAllowLetterShortcuts, parent );
00947     dlg.m_pKeyChooser->insert( coll );
00948     return dlg.configure( bSaveSettings );
00949 }
00950 
00951 /*int KKeyDialog::configure( KActionPtrList* coll, const QString& file, QWidget *parent, bool bSaveSettings )
00952 {
00953     kdDebug(125) << "KKeyDialog::configureKeys( KActionCollection*, " << file << ", " << bSaveSettings << " )" << endl;
00954     KAccelActions actions;
00955     coll->createKeyMap( actions );
00956 
00957     int retcode = configure( actions, file, parent, bSaveSettings );
00958     if( retcode == Accepted )
00959         coll->setKeyMap( actions );
00960 
00961     return retcode;
00962 }*/
00963 
00964 void KKeyChooser::virtual_hook( int, void* )
00965 { /*BASE::virtual_hook( id, data );*/ }
00966 
00967 void KKeyDialog::virtual_hook( int id, void* data )
00968 { KDialogBase::virtual_hook( id, data ); }
00969 
00970 #include "kkeydialog.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:00 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001