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 <kaccelaction.h> 00040 #include <kactionshortcutlist.h> 00041 #include <kapplication.h> 00042 #include <kconfig.h> 00043 #include <kdebug.h> 00044 #include <kglobal.h> 00045 #include <kglobalaccel.h> 00046 #include <klocale.h> 00047 #include <kmessagebox.h> 00048 #include <kshortcut.h> 00049 #include <kshortcutlist.h> 00050 #include <kxmlguifactory.h> 00051 #include <kaboutdata.h> 00052 #include <kstaticdeleter.h> 00053 00054 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00055 #define XK_XKB_KEYS 00056 #define XK_MISCELLANY 00057 #include <X11/Xlib.h> // For x11Event() // schroder 00058 #include <X11/keysymdef.h> // For XK_... // schroder 00059 00060 #ifdef KeyPress 00061 const int XFocusOut = FocusOut; 00062 const int XFocusIn = FocusIn; 00063 const int XKeyPress = KeyPress; 00064 const int XKeyRelease = KeyRelease; 00065 #undef KeyRelease 00066 #undef KeyPress 00067 #undef FocusOut 00068 #undef FocusIn 00069 #endif // KEYPRESS 00070 #endif // Q_WX_X11 && ! K_WS_QTONLY 00071 00072 //--------------------------------------------------------------------- 00073 // KKeyChooserItem 00074 //--------------------------------------------------------------------- 00075 00076 class KKeyChooserItem : public KListViewItem 00077 { 00078 public: 00079 KKeyChooserItem( KListView* parent, QListViewItem* after, KShortcutList* pList, uint iAction ); 00080 KKeyChooserItem( QListViewItem* parent, QListViewItem* after, KShortcutList* pList, uint iAction ); 00081 00082 QString actionName() const; 00083 const KShortcut& shortcut() const; 00084 bool isConfigurable() const 00085 { return m_pList->isConfigurable( m_iAction ); } 00086 const KShortcut& shortcutDefault() const 00087 { return m_pList->shortcutDefault( m_iAction ); } 00088 00089 void setShortcut( const KShortcut& cut ); 00090 void commitChanges(); 00091 00092 virtual QString text( int iCol ) const; 00093 virtual int compare( QListViewItem*, int iCol, bool bAscending ) const; 00094 00095 protected: 00096 KShortcutList* m_pList; 00097 uint m_iAction; 00098 bool m_bModified; 00099 KShortcut m_cut; 00100 }; 00101 00102 //--------------------------------------------------------------------- 00103 // KKeyChooserPrivate 00104 //--------------------------------------------------------------------- 00105 00106 class KKeyChooserPrivate 00107 { 00108 public: 00109 QValueList<KShortcutList*> rgpLists; 00110 QValueList<KShortcutList*> rgpListsAllocated; 00111 00112 KListView *pList; 00113 QLabel *lInfo; 00114 KKeyButton *pbtnShortcut; 00115 QGroupBox *fCArea; 00116 QButtonGroup *kbGroup; 00117 00118 QMap<QString, KShortcut> mapGlobals; 00119 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 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 // Also used when reassigning a shortcut from one chooser to another. 00201 static QValueList< KKeyChooser* >* allChoosers = NULL; 00202 static KStaticDeleter< QValueList< KKeyChooser* > > allChoosersDeleter; 00203 00204 KKeyChooser::~KKeyChooser() 00205 { 00206 allChoosers->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->bPreferFourModifierKeys = KGlobalAccel::useFourModifierKeys(); 00280 00281 // 00282 // TOP LAYOUT MANAGER 00283 // 00284 // The following layout is used for the dialog 00285 // LIST LABELS LAYOUT 00286 // SPLIT LIST BOX WIDGET 00287 // CHOOSE KEY GROUP BOX WIDGET 00288 // BUTTONS LAYOUT 00289 // Items are added to topLayout as they are created. 00290 // 00291 00292 QBoxLayout *topLayout = new QVBoxLayout( this, 0, KDialog::spacingHint() ); 00293 00294 QGridLayout *stackLayout = new QGridLayout(2, 2, 2); 00295 topLayout->addLayout( stackLayout, 10 ); 00296 stackLayout->setRowStretch( 1, 10 ); // Only list will stretch 00297 00298 // 00299 // CREATE SPLIT LIST BOX 00300 // 00301 // fill up the split list box with the action/key pairs. 00302 // 00303 d->pList = new KListView( this ); 00304 d->pList->setFocus(); 00305 00306 stackLayout->addMultiCellWidget( d->pList, 1, 1, 0, 1 ); 00307 QString wtstr = i18n("Here you can see a list of key bindings, " 00308 "i.e. associations between actions (e.g. 'Copy') " 00309 "shown in the left column and keys or combination " 00310 "of keys (e.g. Ctrl+V) shown in the right column."); 00311 00312 QWhatsThis::add( d->pList, wtstr ); 00313 00314 d->pList->setAllColumnsShowFocus( true ); 00315 d->pList->addColumn(i18n("Action")); 00316 d->pList->addColumn(i18n("Shortcut")); 00317 d->pList->addColumn(i18n("Alternate")); 00318 00319 connect( d->pList, SIGNAL(currentChanged(QListViewItem*)), 00320 SLOT(slotListItemSelected(QListViewItem*)) ); 00321 00322 // handle double clicking an item 00323 connect ( d->pList, SIGNAL ( doubleClicked ( QListViewItem *, const QPoint &, int ) ), 00324 SLOT ( captureCurrentItem()) ); 00325 connect ( d->pList, SIGNAL ( spacePressed( QListViewItem* )), SLOT( captureCurrentItem())); 00326 // 00327 // CREATE CHOOSE KEY GROUP 00328 // 00329 d->fCArea = new QGroupBox( this ); 00330 topLayout->addWidget( d->fCArea, 1 ); 00331 00332 d->fCArea->setTitle( i18n("Shortcut for Selected Action") ); 00333 d->fCArea->setFrameStyle( QFrame::Box | QFrame::Sunken ); 00334 00335 // 00336 // CHOOSE KEY GROUP LAYOUT MANAGER 00337 // 00338 QGridLayout *grid = new QGridLayout( d->fCArea, 3, 4, KDialog::spacingHint() ); 00339 grid->addRowSpacing( 0, fontMetrics().lineSpacing() ); 00340 00341 d->kbGroup = new QButtonGroup( d->fCArea ); 00342 d->kbGroup->hide(); 00343 d->kbGroup->setExclusive( true ); 00344 00345 m_prbNone = new QRadioButton( i18n("no key", "&None"), d->fCArea ); 00346 d->kbGroup->insert( m_prbNone, NoKey ); 00347 m_prbNone->setEnabled( false ); 00348 //grid->addMultiCellWidget( rb, 1, 1, 1, 2 ); 00349 grid->addWidget( m_prbNone, 1, 0 ); 00350 QWhatsThis::add( m_prbNone, i18n("The selected action will not be associated with any key.") ); 00351 connect( m_prbNone, SIGNAL(clicked()), SLOT(slotNoKey()) ); 00352 00353 m_prbDef = new QRadioButton( i18n("default key", "De&fault"), d->fCArea ); 00354 d->kbGroup->insert( m_prbDef, DefaultKey ); 00355 m_prbDef->setEnabled( false ); 00356 //grid->addMultiCellWidget( rb, 2, 2, 1, 2 ); 00357 grid->addWidget( m_prbDef, 1, 1 ); 00358 QWhatsThis::add( m_prbDef, i18n("This will bind the default key to the selected action. Usually a reasonable choice.") ); 00359 connect( m_prbDef, SIGNAL(clicked()), SLOT(slotDefaultKey()) ); 00360 00361 m_prbCustom = new QRadioButton( i18n("C&ustom"), d->fCArea ); 00362 d->kbGroup->insert( m_prbCustom, CustomKey ); 00363 m_prbCustom->setEnabled( false ); 00364 //grid->addMultiCellWidget( rb, 3, 3, 1, 2 ); 00365 grid->addWidget( m_prbCustom, 1, 2 ); 00366 QWhatsThis::add( m_prbCustom, i18n("If this option is selected you can create a customized key binding for the" 00367 " selected action using the buttons below.") ); 00368 connect( m_prbCustom, SIGNAL(clicked()), SLOT(slotCustomKey()) ); 00369 00370 //connect( d->kbGroup, SIGNAL( clicked( int ) ), SLOT( keyMode( int ) ) ); 00371 00372 QBoxLayout *pushLayout = new QHBoxLayout( KDialog::spacingHint() ); 00373 grid->addLayout( pushLayout, 1, 3 ); 00374 00375 d->pbtnShortcut = new KKeyButton(d->fCArea, "key"); 00376 d->pbtnShortcut->setEnabled( false ); 00377 connect( d->pbtnShortcut, SIGNAL(capturedShortcut(const KShortcut&)), SLOT(capturedShortcut(const KShortcut&)) ); 00378 grid->addRowSpacing( 1, d->pbtnShortcut->sizeHint().height() + 5 ); 00379 00380 wtstr = i18n("Use this button to choose a new shortcut key. Once you click it, " 00381 "you can press the key-combination which you would like to be assigned " 00382 "to the currently selected action."); 00383 QWhatsThis::add( d->pbtnShortcut, wtstr ); 00384 00385 // 00386 // Add widgets to the geometry manager 00387 // 00388 pushLayout->addSpacing( KDialog::spacingHint()*2 ); 00389 pushLayout->addWidget( d->pbtnShortcut ); 00390 pushLayout->addStretch( 10 ); 00391 00392 d->lInfo = new QLabel(d->fCArea); 00393 //resize(0,0); 00394 //d->lInfo->setAlignment( AlignCenter ); 00395 //d->lInfo->setEnabled( false ); 00396 //d->lInfo->hide(); 00397 grid->addMultiCellWidget( d->lInfo, 2, 2, 0, 3 ); 00398 00399 //d->globalDict = new QDict<int> ( 100, false ); 00400 //d->globalDict->setAutoDelete( true ); 00401 readGlobalKeys(); 00402 //d->stdDict = new QDict<int> ( 100, false ); 00403 //d->stdDict->setAutoDelete( true ); 00404 //if (type == Application || type == ApplicationGlobal) 00405 // readStdKeys(); 00406 connect( kapp, SIGNAL( settingsChanged( int )), SLOT( slotSettingsChanged( int ))); 00407 if( allChoosers == NULL ) 00408 allChoosers = allChoosersDeleter.setObject( allChoosers, new QValueList< KKeyChooser* > ); 00409 allChoosers->append( this ); 00410 } 00411 00412 // Add all shortcuts to the list 00413 void KKeyChooser::buildListView( uint iList, const QString &title ) 00414 { 00415 KShortcutList* pList = d->rgpLists[iList]; 00416 00417 if( m_type == Global || m_type == ApplicationGlobal ) 00418 d->pList->setSorting( -1 ); 00419 KListViewItem *pProgramItem, *pGroupItem = 0, *pParentItem, *pItem; 00420 00421 QString str = (title.isEmpty() ? i18n("Shortcuts") : title); 00422 pParentItem = pProgramItem = pItem = new KListViewItem( d->pList, str ); 00423 pParentItem->setExpandable( true ); 00424 pParentItem->setOpen( true ); 00425 pParentItem->setSelectable( false ); 00426 uint nSize = pList->count(); 00427 for( uint iAction = 0; iAction < nSize; iAction++ ) { 00428 QString sName = pList->name(iAction); 00429 kdDebug(125) << "Key: " << sName << endl; 00430 if( sName.startsWith( "Program:" ) ) { 00431 pItem = new KListViewItem( d->pList, pProgramItem, pList->label(iAction) ); 00432 pItem->setSelectable( false ); 00433 pItem->setExpandable( true ); 00434 pItem->setOpen( true ); 00435 if( !pProgramItem->firstChild() ) 00436 delete pProgramItem; 00437 pProgramItem = pParentItem = pItem; 00438 } else if( sName.startsWith( "Group:" ) ) { 00439 pItem = new KListViewItem( pProgramItem, pParentItem, pList->label(iAction) ); 00440 pItem->setSelectable( false ); 00441 pItem->setExpandable( true ); 00442 pItem->setOpen( true ); 00443 if( pGroupItem && !pGroupItem->firstChild() ) 00444 delete pGroupItem; 00445 pGroupItem = pParentItem = pItem; 00446 } else if( !sName.isEmpty() && pList->isConfigurable(iAction) ) 00447 pItem = new KKeyChooserItem( pParentItem, pItem, pList, iAction ); 00448 } 00449 if( !pProgramItem->firstChild() ) 00450 delete pProgramItem; 00451 if( pGroupItem && !pGroupItem->firstChild() ) 00452 delete pGroupItem; 00453 } 00454 00455 void KKeyChooser::updateButtons() 00456 { 00457 // Hack: Do this incase we still have changeKey() running. 00458 // Better would be to capture the mouse pointer so that we can't click 00459 // around while we're supposed to be entering a key. 00460 // Better yet would be a modal dialog for changeKey()! 00461 releaseKeyboard(); 00462 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() ); 00463 00464 if ( !pItem ) { 00465 // if nothing is selected -> disable radio boxes 00466 m_prbNone->setEnabled( false ); 00467 m_prbDef->setEnabled( false ); 00468 m_prbCustom->setEnabled( false ); 00469 d->pbtnShortcut->setEnabled( false ); 00470 d->pbtnShortcut->setShortcut( KShortcut(), false ); 00471 } else { 00472 bool bConfigurable = pItem->isConfigurable(); 00473 bool bQtShortcut = (m_type == Application || m_type == Standard); 00474 const KShortcut& cutDef = pItem->shortcutDefault(); 00475 00476 // Set key strings 00477 QString keyStrCfg = pItem->shortcut().toString(); 00478 QString keyStrDef = cutDef.toString(); 00479 00480 d->pbtnShortcut->setShortcut( pItem->shortcut(), bQtShortcut ); 00481 //item->setText( 1, keyStrCfg ); 00482 pItem->repaint(); 00483 d->lInfo->setText( i18n("Default key:") + QString(" %1").arg(keyStrDef.isEmpty() ? i18n("None") : keyStrDef) ); 00484 00485 // Select the appropriate radio button. 00486 int index = (pItem->shortcut().isNull()) ? NoKey 00487 : (pItem->shortcut() == cutDef) ? DefaultKey 00488 : CustomKey; 00489 m_prbNone->setChecked( index == NoKey ); 00490 m_prbDef->setChecked( index == DefaultKey ); 00491 m_prbCustom->setChecked( index == CustomKey ); 00492 00493 // Enable buttons if this key is configurable. 00494 // The 'Default Key' button must also have a default key. 00495 m_prbNone->setEnabled( bConfigurable ); 00496 m_prbDef->setEnabled( bConfigurable && cutDef.count() != 0 ); 00497 m_prbCustom->setEnabled( bConfigurable ); 00498 d->pbtnShortcut->setEnabled( bConfigurable ); 00499 } 00500 } 00501 00502 void KKeyChooser::slotNoKey() 00503 { 00504 // return if no key is selected 00505 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() ); 00506 if( pItem ) { 00507 //kdDebug(125) << "no Key" << d->pList->currentItem()->text(0) << endl; 00508 pItem->setShortcut( KShortcut() ); 00509 updateButtons(); 00510 emit keyChange(); 00511 } 00512 } 00513 00514 void KKeyChooser::slotDefaultKey() 00515 { 00516 // return if no key is selected 00517 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() ); 00518 if( pItem ) // don't set it directly, check for conflicts 00519 setShortcut( pItem->shortcutDefault() ); 00520 } 00521 00522 void KKeyChooser::slotCustomKey() 00523 { 00524 d->pbtnShortcut->captureShortcut(); 00525 } 00526 00527 void KKeyChooser::readGlobalKeys() 00528 { 00529 d->mapGlobals.clear(); 00530 if( m_type == Global ) 00531 return; // they will be checked normally, because we're configuring them 00532 readGlobalKeys( d->mapGlobals ); 00533 } 00534 00535 void KKeyChooser::readGlobalKeys( QMap< QString, KShortcut >& map ) 00536 { 00537 QMap<QString, QString> mapEntry = KGlobal::config()->entryMap( "Global Shortcuts" ); 00538 QMap<QString, QString>::Iterator it( mapEntry.begin() ); 00539 for( uint i = 0; it != mapEntry.end(); ++it, i++ ) 00540 map[it.key()] = KShortcut(*it); 00541 } 00542 00543 void KKeyChooser::slotSettingsChanged( int category ) 00544 { 00545 if( category == KApplication::SETTINGS_SHORTCUTS ) 00546 readGlobalKeys(); // reread 00547 } 00548 00549 void KKeyChooser::fontChange( const QFont & ) 00550 { 00551 d->fCArea->setMinimumHeight( 4*d->pbtnShortcut->sizeHint().height() ); 00552 00553 int widget_width = 0; 00554 00555 setMinimumWidth( 20+5*(widget_width+10) ); 00556 } 00557 00558 // KDE4 IMHO this shouldn't be here at all - it cannot check whether the default 00559 // shortcut don't conflict with some already changed ones (e.g. global shortcuts). 00560 // Also, I personally find reseting all shortcuts to default (i.e. hardcoded in the app) 00561 // ones after pressing the 'Default' button rather a misfeature. 00562 void KKeyChooser::allDefault() 00563 { 00564 kdDebug(125) << "KKeyChooser::allDefault()" << endl; 00565 00566 QListViewItemIterator it( d->pList ); 00567 for( ; it.current(); ++it ) { 00568 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(it.current()); 00569 if( pItem ) 00570 pItem->setShortcut( pItem->shortcutDefault() ); 00571 } 00572 00573 updateButtons(); 00574 emit keyChange(); 00575 } 00576 00577 void KKeyChooser::slotListItemSelected( QListViewItem* ) 00578 { 00579 updateButtons(); 00580 } 00581 00582 void KKeyChooser::slotListItemDoubleClicked ( QListViewItem *, const QPoint & , int ) 00583 { // KDE4 dump this 00584 captureCurrentItem(); 00585 } 00586 00587 void KKeyChooser::captureCurrentItem() 00588 { 00589 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() ); 00590 if( pItem != NULL && pItem->isConfigurable()) 00591 d->pbtnShortcut->captureShortcut ( ); 00592 } 00593 00594 void KKeyChooser::setPreferFourModifierKeys( bool bPreferFourModifierKeys ) 00595 { 00596 d->bPreferFourModifierKeys = bPreferFourModifierKeys; 00597 } 00598 00599 void KKeyChooser::capturedShortcut( const KShortcut& cut ) 00600 { 00601 if( cut.isNull() ) 00602 slotNoKey(); 00603 else 00604 setShortcut( cut ); 00605 } 00606 00607 // FIXME: give this functionality again -- I don't think it's ever used, though. -- ellis 00608 // TODO: Check lxr.kde.org to see if it's used anywhere 00609 void KKeyChooser::listSync() 00610 { 00611 /* kdDebug(125) << "KKeyChooser::listSync()" << endl; 00612 00613 if( d->pColl ) { 00614 // TODO: This is very inefficient. Come up with something better. 00615 KAccelActions aa; 00616 d->pColl->createKeyMap( aa ); 00617 d->actionsNew.updateShortcuts( aa ); 00618 } else if( d->pActionsOrig ) { 00619 d->actionsNew.updateShortcuts( *d->pActionsOrig ); 00620 update(); 00621 updateButtons(); 00622 }*/ 00623 } 00624 00625 void KKeyChooser::syncToConfig( const QString& sConfigGroup, KConfigBase* pConfig, bool bClearUnset ) 00626 { 00627 kdDebug(125) << "KKeyChooser::syncToConfig( \"" << sConfigGroup << "\", " << pConfig << " ) start" << endl; 00628 if( !pConfig ) 00629 pConfig = KGlobal::config(); 00630 KConfigGroupSaver cgs( pConfig, sConfigGroup ); 00631 00632 QListViewItemIterator it( d->pList ); 00633 for( ; it.current(); ++it ) { 00634 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(it.current()); 00635 if( pItem ) { 00636 QString sEntry = pConfig->readEntry( pItem->actionName() ); 00637 if( !sEntry.isNull() || bClearUnset ) { 00638 if( sEntry == "none" ) 00639 sEntry = QString::null; 00640 pItem->setShortcut( sEntry ); 00641 } 00642 kdDebug(125) << pItem->actionName() << " = " << pItem->shortcut().toStringInternal() << endl; 00643 } 00644 } 00645 updateButtons(); 00646 kdDebug(125) << "KKeyChooser::syncToConfig() done" << endl; 00647 } 00648 00649 void KKeyChooser::setShortcut( const KShortcut& cut ) 00650 { 00651 kdDebug(125) << "KKeyChooser::setShortcut( " << cut.toString() << " )" << endl; 00652 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(d->pList->currentItem()); 00653 if( !pItem ) 00654 return; 00655 00656 for( uint i = 0; i < cut.count(); i++ ) { 00657 const KKeySequence& seq = cut.seq(i); 00658 const KKey& key = seq.key(0); 00659 00660 if( !d->bAllowLetterShortcuts && key.modFlags() == 0 00661 && key.sym() < 0x3000 && QChar(key.sym()).isLetterOrNumber() ) { 00662 QString s = i18n( "In order to use the '%1' key as a shortcut, " 00663 "it must be combined with the " 00664 "Win, Alt, Ctrl, and/or Shift keys." ).arg(QChar(key.sym())); 00665 KMessageBox::sorry( this, s, i18n("Invalid Shortcut Key") ); 00666 return; 00667 } 00668 } 00669 00670 // If key isn't already in use, 00671 if( !isKeyPresent( cut ) ) { 00672 // Set new key code 00673 pItem->setShortcut( cut ); 00674 // Update display 00675 updateButtons(); 00676 emit keyChange(); 00677 } 00678 } 00679 00680 // Returns iSeq index if cut2 has a sequence of equal or higher priority to a sequence in cut. 00681 // else -1 00682 static int keyConflict( const KShortcut& cut, const KShortcut& cut2 ) 00683 { 00684 for( uint iSeq = 0; iSeq < cut.count(); iSeq++ ) { 00685 for( uint iSeq2 = 0; iSeq2 <= iSeq && iSeq2 < cut2.count(); iSeq2++ ) { 00686 if( cut.seq(iSeq) == cut2.seq(iSeq2) ) 00687 return iSeq; 00688 } 00689 } 00690 return -1; 00691 } 00692 00693 bool KKeyChooser::isKeyPresent( const KShortcut& cut, bool bWarnUser ) 00694 { 00695 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(d->pList->currentItem()); 00696 00697 if (!pItem) { 00698 return false; 00699 } 00700 00701 bool has_global_chooser = false; 00702 bool has_standard_chooser = false; 00703 for( QValueList< KKeyChooser* >::ConstIterator it = allChoosers->begin(); 00704 it != allChoosers->end(); 00705 ++it ) { 00706 has_global_chooser |= ((*it)->m_type == Global); 00707 has_standard_chooser |= ((*it)->m_type == Standard); 00708 } 00709 00710 // If editing global shortcuts, check them for conflicts with the stdaccels. 00711 if( m_type == ApplicationGlobal || m_type == Global ) { 00712 if( !has_standard_chooser ) { 00713 if( checkStandardShortcutsConflict( cut, bWarnUser, this )) 00714 return true; 00715 } 00716 } 00717 00718 // only check the global keys if one of the keychoosers isn't global 00719 if( !has_global_chooser ) { 00720 if( checkGlobalShortcutsConflict( cut, bWarnUser, this, d->mapGlobals, 00721 m_type == Global ? pItem->actionName() : QString::null )) 00722 return true; 00723 } 00724 00725 if( isKeyPresentLocally( cut, pItem, bWarnUser )) 00726 return true; 00727 00728 // check also other KKeyChooser's 00729 for( QValueList< KKeyChooser* >::ConstIterator it = allChoosers->begin(); 00730 it != allChoosers->end(); 00731 ++it ) { 00732 if( (*it) != this && (*it)->isKeyPresentLocally( cut, NULL, bWarnUser )) 00733 return true; 00734 } 00735 return false; 00736 } 00737 00738 // KDE4 remove 00739 bool KKeyChooser::isKeyPresentLocally( const KShortcut& cut, KKeyChooserItem* ignoreItem, const QString& warnText ) 00740 { 00741 return isKeyPresentLocally( cut, ignoreItem, !warnText.isNull()); 00742 } 00743 00744 bool KKeyChooser::isKeyPresentLocally( const KShortcut& cut, KKeyChooserItem* ignoreItem, bool bWarnUser ) 00745 { 00746 if ( cut.toString().isEmpty()) 00747 return false; 00748 // Search for shortcut conflicts with other actions in the 00749 // lists we're configuring. 00750 for( QListViewItemIterator it( d->pList ); it.current(); ++it ) { 00751 KKeyChooserItem* pItem2 = dynamic_cast<KKeyChooserItem*>(it.current()); 00752 if( pItem2 && pItem2 != ignoreItem ) { 00753 int iSeq = keyConflict( cut, pItem2->shortcut() ); 00754 if( iSeq > -1 ) { 00755 if( bWarnUser ) { 00756 if( !promptForReassign( cut.seq(iSeq), pItem2->text(0), Application, this )) 00757 return true; 00758 // else remove the shortcut from it 00759 pItem2->setShortcut( KShortcut()); 00760 updateButtons(); 00761 emit keyChange(); 00762 } 00763 } 00764 } 00765 } 00766 return false; 00767 } 00768 00769 bool KKeyChooser::checkStandardShortcutsConflict( const KShortcut& cut, bool bWarnUser, QWidget* parent ) 00770 { 00771 // For each key sequence in the shortcut, 00772 for( uint i = 0; i < cut.count(); i++ ) { 00773 const KKeySequence& seq = cut.seq(i); 00774 KStdAccel::StdAccel id = KStdAccel::findStdAccel( seq ); 00775 if( id != KStdAccel::AccelNone 00776 && keyConflict( cut, KStdAccel::shortcut( id ) ) > -1 ) { 00777 if( bWarnUser ) { 00778 if( !promptForReassign( seq, KStdAccel::label(id), Standard, parent )) 00779 return true; 00780 removeStandardShortcut( KStdAccel::label(id), dynamic_cast< KKeyChooser* > ( parent )); 00781 } 00782 } 00783 } 00784 return false; 00785 } 00786 00787 bool KKeyChooser::checkGlobalShortcutsConflict( const KShortcut& cut, bool bWarnUser, QWidget* parent ) 00788 { 00789 QMap< QString, KShortcut > map; 00790 readGlobalKeys( map ); 00791 return checkGlobalShortcutsConflict( cut, bWarnUser, parent, map, QString::null ); 00792 } 00793 00794 bool KKeyChooser::checkGlobalShortcutsConflict( const KShortcut& cut, bool bWarnUser, QWidget* parent, 00795 const QMap< QString, KShortcut >& map, const QString& ignoreAction ) 00796 { 00797 QMap<QString, KShortcut>::ConstIterator it; 00798 for( it = map.begin(); it != map.end(); ++it ) { 00799 int iSeq = keyConflict( cut, (*it) ); 00800 if( iSeq > -1 ) { 00801 if( ignoreAction.isEmpty() || it.key() != ignoreAction ) { 00802 if( bWarnUser ) { 00803 if( !promptForReassign( cut.seq(iSeq), it.key(), Global, parent )) 00804 return true; 00805 removeGlobalShortcut( it.key(), dynamic_cast< KKeyChooser* >( parent )); 00806 } 00807 } 00808 } 00809 } 00810 return false; 00811 } 00812 00813 void KKeyChooser::removeStandardShortcut( const QString& name, KKeyChooser* chooser ) 00814 { 00815 bool was_in_choosers = false; 00816 if( allChoosers != NULL ) { 00817 for( QValueList< KKeyChooser* >::ConstIterator it = allChoosers->begin(); 00818 it != allChoosers->end(); 00819 ++it ) { 00820 if( (*it) != chooser && (*it)->m_type == Standard ) { 00821 was_in_choosers |= ( (*it)->resetShortcut( name )); 00822 } 00823 } 00824 } 00825 if( !was_in_choosers ) { // not edited, needs to be changed in config file 00826 KStdAccel::ShortcutList std_list; 00827 std_list.setShortcut( std_list.index( name ), KShortcut()); 00828 std_list.save(); 00829 } 00830 } 00831 00832 void KKeyChooser::removeGlobalShortcut( const QString& name, KKeyChooser* chooser ) 00833 { 00834 bool was_in_choosers = false; 00835 if( allChoosers != NULL ) { 00836 for( QValueList< KKeyChooser* >::ConstIterator it = allChoosers->begin(); 00837 it != allChoosers->end(); 00838 ++it ) { 00839 if( (*it) != chooser && (*it)->m_type == Global ) { 00840 was_in_choosers |= ( (*it)->resetShortcut( name )); 00841 } 00842 } 00843 } 00844 if( !was_in_choosers ) { // not edited, needs to be changed in config file 00845 KAccelActions actions; 00846 actions.insert( name, "", "", KShortcut(), KShortcut()); 00847 actions.writeActions( "Global Shortcuts", 0, true, true ); 00848 } 00849 } 00850 00851 bool KKeyChooser::resetShortcut( const QString& name ) 00852 { 00853 for( QListViewItemIterator it( d->pList ); it.current(); ++it ) { 00854 KKeyChooserItem* pItem2 = dynamic_cast<KKeyChooserItem*>(it.current()); 00855 if( pItem2 && pItem2->actionName() == name ) { 00856 pItem2->setShortcut( KShortcut()); 00857 updateButtons(); 00858 emit keyChange(); 00859 return true; 00860 } 00861 } 00862 return false; 00863 } 00864 00865 // KDE4 remove this 00866 void KKeyChooser::_warning( const KKeySequence& cut, QString sAction, QString sTitle ) 00867 { 00868 sAction = sAction.stripWhiteSpace(); 00869 00870 QString s = 00871 i18n("The '%1' key combination has already been allocated " 00872 "to the \"%2\" action.\n" 00873 "Please choose a unique key combination."). 00874 arg(cut.toString()).arg(sAction); 00875 00876 KMessageBox::sorry( this, s, sTitle ); 00877 } 00878 00879 bool KKeyChooser::promptForReassign( const KKeySequence& cut, const QString& sAction, ActionType type, QWidget* parent ) 00880 { 00881 QString sTitle; 00882 QString s; 00883 if( type == Standard ) { 00884 sTitle = i18n("Conflict with Standard Application Shortcut"); 00885 s = i18n("The '%1' key combination has already been allocated " 00886 "to the standard action \"%2\".\n" 00887 "Do you want to reassign it from that action to the current one?"); 00888 } 00889 else if( type == Global ) { 00890 sTitle = i18n("Conflict with Global Shortcut"); 00891 s = i18n("The '%1' key combination has already been allocated " 00892 "to the global action \"%2\".\n" 00893 "Do you want to reassign it from that action to the current one?"); 00894 } 00895 else { 00896 sTitle = i18n("Key Conflict"); 00897 s = i18n("The '%1' key combination has already been allocated " 00898 "to the \"%2\" action.\n" 00899 "Do you want to reassign it from that action to the current one?"); 00900 } 00901 s = s.arg(cut.toString()).arg(sAction.stripWhiteSpace()); 00902 00903 return KMessageBox::warningYesNo( parent, s, sTitle ) == KMessageBox::Yes; 00904 } 00905 00906 //--------------------------------------------------- 00907 KKeyChooserItem::KKeyChooserItem( KListView* parent, QListViewItem* after, KShortcutList* pList, uint iAction ) 00908 : KListViewItem( parent, after ) 00909 { 00910 m_pList = pList; 00911 m_iAction = iAction; 00912 m_bModified = false; 00913 m_cut = m_pList->shortcut(m_iAction); 00914 } 00915 00916 KKeyChooserItem::KKeyChooserItem( QListViewItem* parent, QListViewItem* after, KShortcutList* pList, uint iAction ) 00917 : KListViewItem( parent, after ) 00918 { 00919 m_pList = pList; 00920 m_iAction = iAction; 00921 m_bModified = false; 00922 m_cut = m_pList->shortcut(m_iAction); 00923 } 00924 00925 QString KKeyChooserItem::actionName() const 00926 { 00927 return m_pList->name(m_iAction); 00928 } 00929 00930 const KShortcut& KKeyChooserItem::shortcut() const 00931 { 00932 return m_cut; 00933 } 00934 00935 void KKeyChooserItem::setShortcut( const KShortcut& cut ) 00936 { 00937 m_cut = cut; 00938 m_bModified = (m_cut != m_pList->shortcut(m_iAction)); 00939 listView()->repaintItem( this ); 00940 } 00941 00942 void KKeyChooserItem::commitChanges() 00943 { 00944 if( m_bModified ) 00945 m_pList->setShortcut( m_iAction, m_cut ); 00946 } 00947 00948 QString KKeyChooserItem::text( int iCol ) const 00949 { 00950 if( iCol == 0 ) { 00951 // Quick HACK to get rid of '&'s. 00952 QString s = m_pList->label(m_iAction); 00953 QString s2; 00954 for( uint i = 0; i < s.length(); i++ ) 00955 if( s[i] != '&' || ( i+1<s.length() && s[i+1] == '&' ) ) 00956 s2 += s[i]; 00957 return s2; 00958 } 00959 else if( iCol <= (int) m_cut.count() ) 00960 return m_cut.seq(iCol-1).toString(); 00961 else 00962 return QString::null; 00963 } 00964 00965 int KKeyChooserItem::compare( QListViewItem* item, int iCol, bool bAscending ) const 00966 { 00967 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( item ); 00968 if( iCol == 0 && pItem ) { 00969 QString psName1 = m_pList->name(m_iAction); 00970 QString psName2 = pItem->m_pList->name(pItem->m_iAction); 00971 QRegExp rxNumber1( " (\\d+)$" ); 00972 QRegExp rxNumber2( " (\\d+)$" ); 00973 int iNumber1 = rxNumber1.search( psName1 ); 00974 int iNumber2 = rxNumber2.search( psName2 ); 00975 00976 // Check if the last word is one or more digits 00977 if( iNumber1 >= 0 && iNumber1 == iNumber2 && psName1.startsWith( psName2.left( iNumber1+1 ) ) ) { 00978 int n1 = rxNumber1.cap(1).toInt(); 00979 int n2 = rxNumber2.cap(1).toInt(); 00980 return (n1 < n2) ? -1 : (n1 > n2) ? 1 : 0; 00981 } 00982 } 00983 00984 return QListViewItem::compare( item, iCol, bAscending ); 00985 } 00986 00987 /************************************************************************/ 00988 /* KKeyDialog */ 00989 /* */ 00990 /* Originally by Nicolas Hadacek <hadacek@via.ecp.fr> */ 00991 /* */ 00992 /* Substantially revised by Mark Donohoe <donohoe@kde.org> */ 00993 /* */ 00994 /* And by Espen Sand <espen@kde.org> 1999-10-19 */ 00995 /* (by using KDialogBase there is almost no code left ;) */ 00996 /* */ 00997 /************************************************************************/ 00998 KKeyDialog::KKeyDialog( KKeyChooser::ActionType type, bool bAllowLetterShortcuts, QWidget *parent, const char* name ) 00999 : KDialogBase( parent, name, true, i18n("Configure Shortcuts"), Help|Default|Ok|Cancel, Ok ) 01000 { 01001 m_pKeyChooser = new KKeyChooser( this, type, bAllowLetterShortcuts ); 01002 setMainWidget( m_pKeyChooser ); 01003 connect( this, SIGNAL(defaultClicked()), m_pKeyChooser, SLOT(allDefault()) ); 01004 enableButton( Help, false ); 01005 01006 KConfigGroup group( KGlobal::config(), "KKeyDialog Settings" ); 01007 QSize sz = size(); 01008 resize( group.readSizeEntry( "Dialog Size", &sz ) ); 01009 } 01010 01011 KKeyDialog::KKeyDialog( bool bAllowLetterShortcuts, QWidget *parent, const char* name ) 01012 : KDialogBase( parent, name, true, i18n("Configure Shortcuts"), Help|Default|Ok|Cancel, Ok ) 01013 { 01014 m_pKeyChooser = new KKeyChooser( this, KKeyChooser::Application, bAllowLetterShortcuts ); 01015 setMainWidget( m_pKeyChooser ); 01016 connect( this, SIGNAL(defaultClicked()), m_pKeyChooser, SLOT(allDefault()) ); 01017 enableButton( Help, false ); 01018 01019 KConfigGroup group( KGlobal::config(), "KKeyDialog Settings" ); 01020 QSize sz = size(); 01021 resize( group.readSizeEntry( "Dialog Size", &sz ) ); 01022 } 01023 01024 KKeyDialog::~KKeyDialog() 01025 { 01026 KConfigGroup group( KGlobal::config(), "KKeyDialog Settings" ); 01027 group.writeEntry( "Dialog Size", size(), true, true ); 01028 } 01029 01030 bool KKeyDialog::insert( KActionCollection* pColl ) 01031 { 01032 return m_pKeyChooser->insert( pColl ); 01033 } 01034 01035 bool KKeyDialog::insert(KActionCollection *pColl, const QString &title) 01036 { 01037 return m_pKeyChooser->insert(pColl, title); 01038 } 01039 01040 bool KKeyDialog::configure( bool bSaveSettings ) 01041 { 01042 int retcode = exec(); 01043 if( retcode == Accepted ) { 01044 if( bSaveSettings ) 01045 m_pKeyChooser->save(); 01046 else 01047 commitChanges(); 01048 } 01049 return retcode; 01050 } 01051 01052 void KKeyDialog::commitChanges() 01053 { 01054 m_pKeyChooser->commitChanges(); 01055 } 01056 01057 int KKeyDialog::configure( KActionCollection* coll, QWidget* parent, bool bSaveSettings ) 01058 { 01059 return configure( coll, true, parent, bSaveSettings); 01060 } 01061 01062 int KKeyDialog::configure( KAccel* keys, QWidget* parent, bool bSaveSettings ) 01063 { 01064 return configure( keys, true, parent, bSaveSettings); 01065 } 01066 01067 int KKeyDialog::configure( KGlobalAccel* keys, QWidget* parent, bool bSaveSettings ) 01068 { 01069 return configure( keys, true, parent, bSaveSettings); 01070 } 01071 01072 int KKeyDialog::configure( KAccel* keys, bool bAllowLetterShortcuts, QWidget *parent, bool bSaveSettings ) 01073 { 01074 KKeyDialog dlg( bAllowLetterShortcuts, parent ); 01075 dlg.m_pKeyChooser->insert( keys ); 01076 bool b = dlg.configure( bSaveSettings ); 01077 if( b && bSaveSettings ) 01078 keys->updateConnections(); 01079 return b; 01080 } 01081 01082 int KKeyDialog::configure( KGlobalAccel* keys, bool bAllowLetterShortcuts, QWidget *parent, bool bSaveSettings ) 01083 { 01084 KKeyDialog dlg( KKeyChooser::ApplicationGlobal, bAllowLetterShortcuts, parent ); 01085 dlg.m_pKeyChooser->insert( keys ); 01086 bool b = dlg.configure( bSaveSettings ); 01087 if( b && bSaveSettings ) 01088 keys->updateConnections(); 01089 return b; 01090 } 01091 01092 int KKeyDialog::configure( KActionCollection* coll, bool bAllowLetterShortcuts, QWidget *parent, bool bSaveSettings ) 01093 { 01094 kdDebug(125) << "KKeyDialog::configureKeys( KActionCollection*, " << bSaveSettings << " )" << endl; 01095 KKeyDialog dlg( bAllowLetterShortcuts, parent ); 01096 dlg.m_pKeyChooser->insert( coll ); 01097 return dlg.configure( bSaveSettings ); 01098 } 01099 01100 /*int KKeyDialog::configure( KActionPtrList* coll, const QString& file, QWidget *parent, bool bSaveSettings ) 01101 { 01102 kdDebug(125) << "KKeyDialog::configureKeys( KActionCollection*, " << file << ", " << bSaveSettings << " )" << endl; 01103 KAccelActions actions; 01104 coll->createKeyMap( actions ); 01105 01106 int retcode = configure( actions, file, parent, bSaveSettings ); 01107 if( retcode == Accepted ) 01108 coll->setKeyMap( actions ); 01109 01110 return retcode; 01111 }*/ 01112 01113 void KKeyChooser::virtual_hook( int, void* ) 01114 { /*BASE::virtual_hook( id, data );*/ } 01115 01116 void KKeyDialog::virtual_hook( int id, void* data ) 01117 { KDialogBase::virtual_hook( id, data ); } 01118 01119 #include "kkeydialog.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 12 15:08:16 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003