00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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>
00058 #include <X11/keysymdef.h>
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
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
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
00121
00122
00123
00124 bool bAllowLetterShortcuts;
00125
00126
00127 bool bPreferFourModifierKeys;
00128 };
00129
00130
00131
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 )
00188 : QWidget( parent )
00189 {
00190 ActionType type = (bCheckAgainstStdKeys) ? ApplicationGlobal : Global;
00191
00192 initGUI( type, bAllowLetterShortcuts );
00193 insert( actions );
00194 }
00195
00196
00197
00198
00199
00200
00201 static QValueList< KKeyChooser* >* allChoosers = NULL;
00202 static KStaticDeleter< QValueList< KKeyChooser* > > allChoosersDeleter;
00203
00204 KKeyChooser::~KKeyChooser()
00205 {
00206 allChoosers->remove( this );
00207
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
00283
00284
00285
00286
00287
00288
00289
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 );
00297
00298
00299
00300
00301
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
00323 connect ( d->pList, SIGNAL ( doubleClicked ( QListViewItem *, const QPoint &, int ) ),
00324 SLOT ( captureCurrentItem()) );
00325 connect ( d->pList, SIGNAL ( spacePressed( QListViewItem* )), SLOT( captureCurrentItem()));
00326
00327
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
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
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
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
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
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
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
00394
00395
00396
00397 grid->addMultiCellWidget( d->lInfo, 2, 2, 0, 3 );
00398
00399
00400
00401 readGlobalKeys();
00402
00403
00404
00405
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
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
00458
00459
00460
00461 releaseKeyboard();
00462 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00463
00464 if ( !pItem ) {
00465
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
00477 QString keyStrCfg = pItem->shortcut().toString();
00478 QString keyStrDef = cutDef.toString();
00479
00480 d->pbtnShortcut->setShortcut( pItem->shortcut(), bQtShortcut );
00481
00482 pItem->repaint();
00483 d->lInfo->setText( i18n("Default key:") + QString(" %1").arg(keyStrDef.isEmpty() ? i18n("None") : keyStrDef) );
00484
00485
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
00494
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
00505 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00506 if( pItem ) {
00507
00508 pItem->setShortcut( KShortcut() );
00509 updateButtons();
00510 emit keyChange();
00511 }
00512 }
00513
00514 void KKeyChooser::slotDefaultKey()
00515 {
00516
00517 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00518 if( pItem )
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;
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();
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
00559
00560
00561
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 {
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
00608
00609 void KKeyChooser::listSync()
00610 {
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
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
00671 if( !isKeyPresent( cut ) ) {
00672
00673 pItem->setShortcut( cut );
00674
00675 updateButtons();
00676 emit keyChange();
00677 }
00678 }
00679
00680
00681
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
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
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
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
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
00749
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
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
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 ) {
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 ) {
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
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
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
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
00989
00990
00991
00992
00993
00994
00995
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
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113 void KKeyChooser::virtual_hook( int, void* )
01114 { }
01115
01116 void KKeyDialog::virtual_hook( int id, void* data )
01117 { KDialogBase::virtual_hook( id, data ); }
01118
01119 #include "kkeydialog.moc"