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 <qtoolbutton.h>
00036 #include <qwhatsthis.h>
00037
00038 #include <kaccel.h>
00039 #include <kaction.h>
00040 #include <kaccelaction.h>
00041 #include <kactionshortcutlist.h>
00042 #include <kapplication.h>
00043 #include <kconfig.h>
00044 #include <kdebug.h>
00045 #include <kglobal.h>
00046 #include <kglobalaccel.h>
00047 #include <kiconloader.h>
00048 #include <klistviewsearchline.h>
00049 #include <klocale.h>
00050 #include <kmessagebox.h>
00051 #include <kshortcut.h>
00052 #include <kshortcutlist.h>
00053 #include <kxmlguifactory.h>
00054 #include <kaboutdata.h>
00055 #include <kstaticdeleter.h>
00056
00057 #ifdef Q_WS_X11
00058 #define XK_XKB_KEYS
00059 #define XK_MISCELLANY
00060 #include <X11/Xlib.h>
00061 #include <X11/keysymdef.h>
00062 #include <qwhatsthis.h>
00063
00064 #ifdef KeyPress
00065 const int XFocusOut = FocusOut;
00066 const int XFocusIn = FocusIn;
00067 const int XKeyPress = KeyPress;
00068 const int XKeyRelease = KeyRelease;
00069 #undef KeyRelease
00070 #undef KeyPress
00071 #undef FocusOut
00072 #undef FocusIn
00073 #endif // KEYPRESS
00074 #endif // Q_WX_X11
00075
00076
00077
00078
00079
00080 class KKeyChooserItem : public KListViewItem
00081 {
00082 public:
00083 KKeyChooserItem( KListView* parent, QListViewItem* after, KShortcutList* pList, uint iAction );
00084 KKeyChooserItem( QListViewItem* parent, QListViewItem* after, KShortcutList* pList, uint iAction );
00085
00086 QString actionName() const;
00087 const KShortcut& shortcut() const;
00088 bool isConfigurable() const
00089 { return m_pList->isConfigurable( m_iAction ); }
00090 const KShortcut& shortcutDefault() const
00091 { return m_pList->shortcutDefault( m_iAction ); }
00092 QString whatsThis() const
00093 { return m_pList->whatsThis( m_iAction ); }
00094
00095 void setShortcut( const KShortcut& cut );
00096 void commitChanges();
00097
00098 virtual QString text( int iCol ) const;
00099 virtual int compare( QListViewItem*, int iCol, bool bAscending ) const;
00100
00101 protected:
00102 KShortcutList* m_pList;
00103 uint m_iAction;
00104 bool m_bModified;
00105 KShortcut m_cut;
00106 };
00107
00108
00109 class KKeyChooserWhatsThis : public QWhatsThis
00110 {
00111 public:
00112 KKeyChooserWhatsThis( QListView* listview )
00113 : QWhatsThis( listview->viewport() ), m_listView( listview ) {}
00114
00115 protected:
00116 virtual QString text( const QPoint& p );
00117
00118 private:
00119 QListView* m_listView;
00120 };
00121
00122
00123
00124
00125
00126 class KKeyChooserPrivate
00127 {
00128 public:
00129 QValueList<KShortcutList*> rgpLists;
00130 QValueList<KShortcutList*> rgpListsAllocated;
00131
00132 KListView *pList;
00133 QLabel *lInfo;
00134 KKeyButton *pbtnShortcut;
00135 QGroupBox *fCArea;
00136 QButtonGroup *kbGroup;
00137
00138 QMap<QString, KShortcut> mapGlobals;
00139
00140
00141
00142
00143
00144 bool bAllowLetterShortcuts;
00145
00146
00147 bool bPreferFourModifierKeys;
00148 };
00149
00150
00151
00152
00153
00154 KKeyChooser::KKeyChooser( QWidget* parent, ActionType type, bool bAllowLetterShortcuts )
00155 : QWidget( parent )
00156 {
00157 initGUI( type, bAllowLetterShortcuts );
00158 }
00159
00160 KKeyChooser::KKeyChooser( KActionCollection* coll, QWidget* parent, bool bAllowLetterShortcuts )
00161 : QWidget( parent )
00162 {
00163 initGUI( Application, bAllowLetterShortcuts );
00164 insert( coll );
00165 }
00166
00167 KKeyChooser::KKeyChooser( KAccel* pAccel, QWidget* parent, bool bAllowLetterShortcuts )
00168 : QWidget( parent )
00169 {
00170 initGUI( Application, bAllowLetterShortcuts );
00171 insert( pAccel );
00172 }
00173
00174 KKeyChooser::KKeyChooser( KGlobalAccel* pAccel, QWidget* parent )
00175 : QWidget( parent )
00176 {
00177 initGUI( ApplicationGlobal, false );
00178 insert( pAccel );
00179 }
00180
00181 KKeyChooser::KKeyChooser( KShortcutList* pList, QWidget* parent, ActionType type, bool bAllowLetterShortcuts )
00182 : QWidget( parent )
00183 {
00184 initGUI( type, bAllowLetterShortcuts );
00185 insert( pList );
00186 }
00187
00188 KKeyChooser::KKeyChooser( KAccel* actions, QWidget* parent,
00189 bool bCheckAgainstStdKeys,
00190 bool bAllowLetterShortcuts,
00191 bool bAllowWinKey )
00192 : QWidget( parent )
00193 {
00194 ActionType type;
00195 if( bAllowWinKey )
00196 type = (bCheckAgainstStdKeys) ? ApplicationGlobal : Global;
00197 else
00198 type = Application;
00199
00200 initGUI( type, bAllowLetterShortcuts );
00201 insert( actions );
00202 }
00203
00204 KKeyChooser::KKeyChooser( KGlobalAccel* actions, QWidget* parent,
00205 bool bCheckAgainstStdKeys,
00206 bool bAllowLetterShortcuts,
00207 bool )
00208 : QWidget( parent )
00209 {
00210 ActionType type = (bCheckAgainstStdKeys) ? ApplicationGlobal : Global;
00211
00212 initGUI( type, bAllowLetterShortcuts );
00213 insert( actions );
00214 }
00215
00216
00217
00218
00219
00220
00221 static QValueList< KKeyChooser* >* allChoosers = NULL;
00222 static KStaticDeleter< QValueList< KKeyChooser* > > allChoosersDeleter;
00223
00224 KKeyChooser::~KKeyChooser()
00225 {
00226 allChoosers->remove( this );
00227
00228 for( uint i = 0; i < d->rgpListsAllocated.count(); i++ )
00229 delete d->rgpListsAllocated[i];
00230 delete d;
00231 }
00232
00233 bool KKeyChooser::insert( KActionCollection *pColl)
00234 {
00235 return insert(pColl, QString::null);
00236 }
00237
00238 bool KKeyChooser::insert( KActionCollection* pColl, const QString &title )
00239 {
00240 QString str = title;
00241 if ( title.isEmpty() && pColl->instance()
00242 && pColl->instance()->aboutData() )
00243 str = pColl->instance()->aboutData()->programName();
00244
00245 KShortcutList* pList = new KActionShortcutList( pColl );
00246 d->rgpListsAllocated.append( pList );
00247 d->rgpLists.append( pList );
00248 buildListView(d->rgpLists.count() - 1, str);
00249 return true;
00250 }
00251
00252 bool KKeyChooser::insert( KAccel* pAccel )
00253 {
00254 KShortcutList* pList = new KAccelShortcutList( pAccel );
00255 d->rgpListsAllocated.append( pList );
00256 return insert( pList );
00257 }
00258
00259 bool KKeyChooser::insert( KGlobalAccel* pAccel )
00260 {
00261 KShortcutList* pList = new KAccelShortcutList( pAccel );
00262 d->rgpListsAllocated.append( pList );
00263 return insert( pList );
00264 }
00265
00266 bool KKeyChooser::insert( KShortcutList* pList )
00267 {
00268 d->rgpLists.append( pList );
00269 buildListView( d->rgpLists.count() - 1, QString::null );
00270 return true;
00271 }
00272
00273 void KKeyChooser::commitChanges()
00274 {
00275 kdDebug(125) << "KKeyChooser::commitChanges()" << endl;
00276
00277 QListViewItemIterator it( d->pList );
00278 for( ; it.current(); ++it ) {
00279 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(it.current());
00280 if( pItem )
00281 pItem->commitChanges();
00282 }
00283 }
00284
00285 void KKeyChooser::save()
00286 {
00287 commitChanges();
00288 for( uint i = 0; i < d->rgpLists.count(); i++ )
00289 d->rgpLists[i]->save();
00290 }
00291
00292 void KKeyChooser::initGUI( ActionType type, bool bAllowLetterShortcuts )
00293 {
00294 d = new KKeyChooserPrivate();
00295
00296 m_type = type;
00297 d->bAllowLetterShortcuts = bAllowLetterShortcuts;
00298
00299 d->bPreferFourModifierKeys = KGlobalAccel::useFourModifierKeys();
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 QBoxLayout *topLayout = new QVBoxLayout( this, 0, KDialog::spacingHint() );
00313
00314
00315
00316
00317 QHBoxLayout* searchLayout = new QHBoxLayout(0, 0, KDialog::spacingHint());
00318 topLayout->addLayout(searchLayout, 10);
00319
00320 QToolButton *clearSearch = new QToolButton(this);
00321 clearSearch->setTextLabel(i18n("Clear Search"), true);
00322 clearSearch->setIconSet(SmallIconSet(QApplication::reverseLayout() ? "clear_left" : "locationbar_erase"));
00323 searchLayout->addWidget(clearSearch);
00324 QLabel* slbl = new QLabel(i18n("&Search:"), this);
00325 searchLayout->addWidget(slbl);
00326 KListViewSearchLine* listViewSearch = new KListViewSearchLine(this);
00327 searchLayout->addWidget(listViewSearch);
00328 slbl->setBuddy(listViewSearch);
00329 connect(clearSearch, SIGNAL(pressed()), listViewSearch, SLOT(clear()));
00330
00331 QString wtstr = i18n("Search interactively for shortcut names (e.g. Copy) "
00332 "or combination of keys (e.g. Ctrl+C) by typing them here.");
00333
00334 QWhatsThis::add(slbl, wtstr);
00335 QWhatsThis::add(listViewSearch, wtstr);
00336
00337
00338
00339
00340
00341
00342 QGridLayout *stackLayout = new QGridLayout(2, 2, 2);
00343 topLayout->addLayout( stackLayout, 10 );
00344 stackLayout->setRowStretch( 1, 10 );
00345
00346 d->pList = new KListView( this );
00347 listViewSearch->setListView(d->pList);
00348 QValueList<int> columns;
00349 columns.append(0);
00350 listViewSearch->setSearchColumns(columns);
00351
00352 stackLayout->addMultiCellWidget( d->pList, 1, 1, 0, 1 );
00353
00354 wtstr = i18n("Here you can see a list of key bindings, "
00355 "i.e. associations between actions (e.g. 'Copy') "
00356 "shown in the left column and keys or combination "
00357 "of keys (e.g. Ctrl+V) shown in the right column.");
00358
00359 QWhatsThis::add( d->pList, wtstr );
00360 new KKeyChooserWhatsThis( d->pList );
00361
00362 d->pList->setAllColumnsShowFocus( true );
00363 d->pList->addColumn(i18n("Action"));
00364 d->pList->addColumn(i18n("Shortcut"));
00365 d->pList->addColumn(i18n("Alternate"));
00366
00367 connect( d->pList, SIGNAL(currentChanged(QListViewItem*)),
00368 SLOT(slotListItemSelected(QListViewItem*)) );
00369
00370
00371 connect ( d->pList, SIGNAL ( doubleClicked ( QListViewItem *, const QPoint &, int ) ),
00372 SLOT ( captureCurrentItem()) );
00373 connect ( d->pList, SIGNAL ( spacePressed( QListViewItem* )), SLOT( captureCurrentItem()));
00374
00375
00376
00377 d->fCArea = new QGroupBox( this );
00378 topLayout->addWidget( d->fCArea, 1 );
00379
00380 d->fCArea->setTitle( i18n("Shortcut for Selected Action") );
00381 d->fCArea->setFrameStyle( QFrame::GroupBoxPanel | QFrame::Plain );
00382
00383
00384
00385
00386 QGridLayout *grid = new QGridLayout( d->fCArea, 3, 4, KDialog::spacingHint() );
00387 grid->addRowSpacing( 0, fontMetrics().lineSpacing() );
00388
00389 d->kbGroup = new QButtonGroup( d->fCArea );
00390 d->kbGroup->hide();
00391 d->kbGroup->setExclusive( true );
00392
00393 m_prbNone = new QRadioButton( i18n("no key", "&None"), d->fCArea );
00394 d->kbGroup->insert( m_prbNone, NoKey );
00395 m_prbNone->setEnabled( false );
00396
00397 grid->addWidget( m_prbNone, 1, 0 );
00398 QWhatsThis::add( m_prbNone, i18n("The selected action will not be associated with any key.") );
00399 connect( m_prbNone, SIGNAL(clicked()), SLOT(slotNoKey()) );
00400
00401 m_prbDef = new QRadioButton( i18n("default key", "De&fault"), d->fCArea );
00402 d->kbGroup->insert( m_prbDef, DefaultKey );
00403 m_prbDef->setEnabled( false );
00404
00405 grid->addWidget( m_prbDef, 1, 1 );
00406 QWhatsThis::add( m_prbDef, i18n("This will bind the default key to the selected action. Usually a reasonable choice.") );
00407 connect( m_prbDef, SIGNAL(clicked()), SLOT(slotDefaultKey()) );
00408
00409 m_prbCustom = new QRadioButton( i18n("C&ustom"), d->fCArea );
00410 d->kbGroup->insert( m_prbCustom, CustomKey );
00411 m_prbCustom->setEnabled( false );
00412
00413 grid->addWidget( m_prbCustom, 1, 2 );
00414 QWhatsThis::add( m_prbCustom, i18n("If this option is selected you can create a customized key binding for the"
00415 " selected action using the buttons below.") );
00416 connect( m_prbCustom, SIGNAL(clicked()), SLOT(slotCustomKey()) );
00417
00418
00419
00420 QBoxLayout *pushLayout = new QHBoxLayout( KDialog::spacingHint() );
00421 grid->addLayout( pushLayout, 1, 3 );
00422
00423 d->pbtnShortcut = new KKeyButton(d->fCArea, "key");
00424 d->pbtnShortcut->setEnabled( false );
00425 connect( d->pbtnShortcut, SIGNAL(capturedShortcut(const KShortcut&)), SLOT(capturedShortcut(const KShortcut&)) );
00426 grid->addRowSpacing( 1, d->pbtnShortcut->sizeHint().height() + 5 );
00427
00428 wtstr = i18n("Use this button to choose a new shortcut key. Once you click it, "
00429 "you can press the key-combination which you would like to be assigned "
00430 "to the currently selected action.");
00431 QWhatsThis::add( d->pbtnShortcut, wtstr );
00432
00433
00434
00435
00436 pushLayout->addSpacing( KDialog::spacingHint()*2 );
00437 pushLayout->addWidget( d->pbtnShortcut );
00438 pushLayout->addStretch( 10 );
00439
00440 d->lInfo = new QLabel(d->fCArea);
00441
00442
00443
00444
00445 grid->addMultiCellWidget( d->lInfo, 2, 2, 0, 3 );
00446
00447
00448
00449 readGlobalKeys();
00450
00451
00452
00453
00454 connect( kapp, SIGNAL( settingsChanged( int )), SLOT( slotSettingsChanged( int )));
00455 if( allChoosers == NULL )
00456 allChoosers = allChoosersDeleter.setObject( allChoosers, new QValueList< KKeyChooser* > );
00457 allChoosers->append( this );
00458 }
00459
00460
00461 void KKeyChooser::buildListView( uint iList, const QString &title )
00462 {
00463 KShortcutList* pList = d->rgpLists[iList];
00464 KActionShortcutList *pAList = dynamic_cast<KActionShortcutList*>(pList);
00465
00466 if( m_type == Global || m_type == ApplicationGlobal )
00467 d->pList->setSorting( -1 );
00468 KListViewItem *pProgramItem, *pGroupItem = 0, *pParentItem, *pItem;
00469
00470 QString str = (title.isEmpty() ? i18n("Shortcuts") : title);
00471 pParentItem = pProgramItem = pItem = new KListViewItem( d->pList, str );
00472 pParentItem->setExpandable( true );
00473 pParentItem->setOpen( true );
00474 pParentItem->setSelectable( false );
00475 uint nSize = pList->count();
00476 for( uint iAction = 0; iAction < nSize; iAction++ ) {
00477 QString sName = pList->name(iAction);
00478 kdDebug(125) << "Key: " << sName << endl;
00479 if( sName.startsWith( "Program:" ) ) {
00480 pItem = new KListViewItem( d->pList, pProgramItem, pList->label(iAction) );
00481 pItem->setSelectable( false );
00482 pItem->setExpandable( true );
00483 pItem->setOpen( true );
00484 if( !pProgramItem->firstChild() )
00485 delete pProgramItem;
00486 pProgramItem = pParentItem = pItem;
00487 } else if( sName.startsWith( "Group:" ) ) {
00488 pItem = new KListViewItem( pProgramItem, pParentItem, pList->label(iAction) );
00489 pItem->setSelectable( false );
00490 pItem->setExpandable( true );
00491 pItem->setOpen( true );
00492 if( pGroupItem && !pGroupItem->firstChild() )
00493 delete pGroupItem;
00494 pGroupItem = pParentItem = pItem;
00495 } else if( !sName.isEmpty() && sName != "unnamed" && pList->isConfigurable(iAction) ) {
00496 pItem = new KKeyChooserItem( pParentItem, pItem, pList, iAction );
00497 if(pAList)
00498 pItem->setPixmap(0,pAList->action(iAction)->iconSet().pixmap(QIconSet::Small,QIconSet::Normal));
00499 }
00500 }
00501 if( !pProgramItem->firstChild() )
00502 delete pProgramItem;
00503 if( pGroupItem && !pGroupItem->firstChild() )
00504 delete pGroupItem;
00505 }
00506
00507
00508 void KKeyChooser::updateButtons()
00509 {
00510
00511
00512
00513
00514 releaseKeyboard();
00515 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00516
00517 if ( !pItem ) {
00518
00519 m_prbNone->setEnabled( false );
00520 m_prbDef->setEnabled( false );
00521 m_prbCustom->setEnabled( false );
00522 d->pbtnShortcut->setEnabled( false );
00523 d->pbtnShortcut->setShortcut( KShortcut(), false );
00524 } else {
00525 bool bConfigurable = pItem->isConfigurable();
00526 bool bQtShortcut = (m_type == Application || m_type == Standard);
00527 const KShortcut& cutDef = pItem->shortcutDefault();
00528
00529
00530 QString keyStrCfg = pItem->shortcut().toString();
00531 QString keyStrDef = cutDef.toString();
00532
00533 d->pbtnShortcut->setShortcut( pItem->shortcut(), bQtShortcut );
00534
00535 pItem->repaint();
00536 d->lInfo->setText( i18n("Default key:") + QString(" %1").arg(keyStrDef.isEmpty() ? i18n("None") : keyStrDef) );
00537
00538
00539 int index = (pItem->shortcut().isNull()) ? NoKey
00540 : (pItem->shortcut() == cutDef) ? DefaultKey
00541 : CustomKey;
00542 m_prbNone->setChecked( index == NoKey );
00543 m_prbDef->setChecked( index == DefaultKey );
00544 m_prbCustom->setChecked( index == CustomKey );
00545
00546
00547
00548 m_prbNone->setEnabled( bConfigurable );
00549 m_prbDef->setEnabled( bConfigurable && cutDef.count() != 0 );
00550 m_prbCustom->setEnabled( bConfigurable );
00551 d->pbtnShortcut->setEnabled( bConfigurable );
00552 }
00553 }
00554
00555 void KKeyChooser::slotNoKey()
00556 {
00557
00558 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00559 if( pItem ) {
00560
00561 pItem->setShortcut( KShortcut() );
00562 updateButtons();
00563 emit keyChange();
00564 }
00565 }
00566
00567 void KKeyChooser::slotDefaultKey()
00568 {
00569
00570 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00571 if( pItem )
00572 setShortcut( pItem->shortcutDefault() );
00573 }
00574
00575 void KKeyChooser::slotCustomKey()
00576 {
00577 d->pbtnShortcut->captureShortcut();
00578 }
00579
00580 void KKeyChooser::readGlobalKeys()
00581 {
00582 d->mapGlobals.clear();
00583 if( m_type == Global )
00584 return;
00585 readGlobalKeys( d->mapGlobals );
00586 }
00587
00588 void KKeyChooser::readGlobalKeys( QMap< QString, KShortcut >& map )
00589 {
00590 QMap<QString, QString> mapEntry = KGlobal::config()->entryMap( "Global Shortcuts" );
00591 QMap<QString, QString>::Iterator it( mapEntry.begin() );
00592 for( uint i = 0; it != mapEntry.end(); ++it, i++ )
00593 map[it.key()] = KShortcut(*it);
00594 }
00595
00596 void KKeyChooser::slotSettingsChanged( int category )
00597 {
00598 if( category == KApplication::SETTINGS_SHORTCUTS )
00599 readGlobalKeys();
00600 }
00601
00602 void KKeyChooser::fontChange( const QFont & )
00603 {
00604 d->fCArea->setMinimumHeight( 4*d->pbtnShortcut->sizeHint().height() );
00605
00606 int widget_width = 0;
00607
00608 setMinimumWidth( 20+5*(widget_width+10) );
00609 }
00610
00611
00612
00613
00614
00615 void KKeyChooser::allDefault()
00616 {
00617 kdDebug(125) << "KKeyChooser::allDefault()" << endl;
00618
00619 QListViewItemIterator it( d->pList );
00620 for( ; it.current(); ++it ) {
00621 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(it.current());
00622 if( pItem )
00623 pItem->setShortcut( pItem->shortcutDefault() );
00624 }
00625
00626 updateButtons();
00627 emit keyChange();
00628 }
00629
00630 void KKeyChooser::slotListItemSelected( QListViewItem* )
00631 {
00632 updateButtons();
00633 }
00634
00635 void KKeyChooser::slotListItemDoubleClicked ( QListViewItem *, const QPoint & , int )
00636 {
00637 captureCurrentItem();
00638 }
00639
00640 void KKeyChooser::captureCurrentItem()
00641 {
00642 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( d->pList->currentItem() );
00643 if( pItem != NULL && pItem->isConfigurable())
00644 d->pbtnShortcut->captureShortcut ( );
00645 }
00646
00647 void KKeyChooser::setPreferFourModifierKeys( bool bPreferFourModifierKeys )
00648 {
00649 d->bPreferFourModifierKeys = bPreferFourModifierKeys;
00650 }
00651
00652 void KKeyChooser::capturedShortcut( const KShortcut& cut )
00653 {
00654 if( cut.isNull() )
00655 slotNoKey();
00656 else
00657 setShortcut( cut );
00658 }
00659
00660
00661
00662 void KKeyChooser::listSync()
00663 {
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676 }
00677
00678 void KKeyChooser::syncToConfig( const QString& sConfigGroup, KConfigBase* pConfig, bool bClearUnset )
00679 {
00680 kdDebug(125) << "KKeyChooser::syncToConfig( \"" << sConfigGroup << "\", " << pConfig << " ) start" << endl;
00681 if( !pConfig )
00682 pConfig = KGlobal::config();
00683 KConfigGroupSaver cgs( pConfig, sConfigGroup );
00684
00685 QListViewItemIterator it( d->pList );
00686 for( ; it.current(); ++it ) {
00687 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(it.current());
00688 if( pItem ) {
00689 QString sEntry = pConfig->readEntry( pItem->actionName() );
00690 if( !sEntry.isNull() || bClearUnset ) {
00691 if( sEntry == "none" )
00692 sEntry = QString::null;
00693 pItem->setShortcut( sEntry );
00694 }
00695 kdDebug(125) << pItem->actionName() << " = " << pItem->shortcut().toStringInternal() << endl;
00696 }
00697 }
00698 updateButtons();
00699 kdDebug(125) << "KKeyChooser::syncToConfig() done" << endl;
00700 }
00701
00702 void KKeyChooser::setShortcut( const KShortcut& cut )
00703 {
00704 kdDebug(125) << "KKeyChooser::setShortcut( " << cut.toString() << " )" << endl;
00705 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(d->pList->currentItem());
00706 if( !pItem )
00707 return;
00708
00709 for( uint i = 0; i < cut.count(); i++ ) {
00710 const KKeySequence& seq = cut.seq(i);
00711 const KKey& key = seq.key(0);
00712
00713 if( !d->bAllowLetterShortcuts && key.modFlags() == 0
00714 && key.sym() < 0x3000 && QChar(key.sym()).isLetterOrNumber() ) {
00715 QString s = i18n( "In order to use the '%1' key as a shortcut, "
00716 "it must be combined with the "
00717 "Win, Alt, Ctrl, and/or Shift keys." ).arg(QChar(key.sym()));
00718 KMessageBox::sorry( this, s, i18n("Invalid Shortcut Key") );
00719 return;
00720 }
00721 }
00722
00723
00724 if( !isKeyPresent( cut ) ) {
00725
00726 pItem->setShortcut( cut );
00727
00728 updateButtons();
00729 emit keyChange();
00730 }
00731 }
00732
00733
00734
00735 static int keyConflict( const KShortcut& cut, const KShortcut& cut2 )
00736 {
00737 for( uint iSeq = 0; iSeq < cut.count(); iSeq++ ) {
00738 for( uint iSeq2 = 0; iSeq2 < cut2.count(); iSeq2++ ) {
00739 if( cut.seq(iSeq) == cut2.seq(iSeq2) )
00740 return iSeq;
00741 }
00742 }
00743 return -1;
00744 }
00745
00746
00747 static void removeFromShortcut( KShortcut & cut1, const KShortcut &cut2)
00748 {
00749 for( uint iSeq2 = 0; iSeq2 < cut2.count(); iSeq2++ )
00750 cut1.remove(cut2.seq(iSeq2));
00751 }
00752
00753 bool KKeyChooser::isKeyPresent( const KShortcut& cut, bool bWarnUser )
00754 {
00755 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>(d->pList->currentItem());
00756
00757 if (!pItem) {
00758 return false;
00759 }
00760
00761 bool has_global_chooser = false;
00762 bool has_standard_chooser = false;
00763 for( QValueList< KKeyChooser* >::ConstIterator it = allChoosers->begin();
00764 it != allChoosers->end();
00765 ++it ) {
00766 has_global_chooser |= ((*it)->m_type == Global);
00767 has_standard_chooser |= ((*it)->m_type == Standard);
00768 }
00769
00770
00771 if( m_type == ApplicationGlobal || m_type == Global ) {
00772 if( !has_standard_chooser ) {
00773 if( checkStandardShortcutsConflict( cut, bWarnUser, this ))
00774 return true;
00775 }
00776 }
00777
00778
00779 if( !has_global_chooser ) {
00780 if( checkGlobalShortcutsConflict( cut, bWarnUser, this, d->mapGlobals,
00781 m_type == Global ? pItem->actionName() : QString::null ))
00782 return true;
00783 }
00784
00785 if( isKeyPresentLocally( cut, pItem, bWarnUser ))
00786 return true;
00787
00788
00789 for( QValueList< KKeyChooser* >::ConstIterator it = allChoosers->begin();
00790 it != allChoosers->end();
00791 ++it ) {
00792 if( (*it) != this && (*it)->isKeyPresentLocally( cut, NULL, bWarnUser ))
00793 return true;
00794 }
00795 return false;
00796 }
00797
00798
00799 bool KKeyChooser::isKeyPresentLocally( const KShortcut& cut, KKeyChooserItem* ignoreItem, const QString& warnText )
00800 {
00801 return isKeyPresentLocally( cut, ignoreItem, !warnText.isNull());
00802 }
00803
00804 bool KKeyChooser::isKeyPresentLocally( const KShortcut& cut, KKeyChooserItem* ignoreItem, bool bWarnUser )
00805 {
00806 if ( cut.toString().isEmpty())
00807 return false;
00808
00809
00810 for( QListViewItemIterator it( d->pList ); it.current(); ++it ) {
00811 KKeyChooserItem* pItem2 = dynamic_cast<KKeyChooserItem*>(it.current());
00812 if( pItem2 && pItem2 != ignoreItem ) {
00813 int iSeq = keyConflict( cut, pItem2->shortcut() );
00814 if( iSeq > -1 ) {
00815 if( bWarnUser ) {
00816 if( !promptForReassign( cut.seq(iSeq), pItem2->text(0), Application, this ))
00817 return true;
00818
00819 KShortcut cut2 = pItem2->shortcut();
00820 removeFromShortcut(cut2, cut);
00821 pItem2->setShortcut(cut2);
00822 updateButtons();
00823 emit keyChange();
00824 }
00825 }
00826 }
00827 }
00828 return false;
00829 }
00830
00831 bool KKeyChooser::checkStandardShortcutsConflict( const KShortcut& cut, bool bWarnUser, QWidget* parent )
00832 {
00833
00834 for( uint i = 0; i < cut.count(); i++ ) {
00835 const KKeySequence& seq = cut.seq(i);
00836 KStdAccel::StdAccel id = KStdAccel::findStdAccel( seq );
00837 if( id != KStdAccel::AccelNone
00838 && keyConflict( cut, KStdAccel::shortcut( id ) ) > -1 ) {
00839 if( bWarnUser ) {
00840 if( !promptForReassign( seq, KStdAccel::label(id), Standard, parent ))
00841 return true;
00842 removeStandardShortcut( KStdAccel::label(id), dynamic_cast< KKeyChooser* > ( parent ), KStdAccel::shortcut( id ), cut);
00843 }
00844 }
00845 }
00846 return false;
00847 }
00848
00849 bool KKeyChooser::checkGlobalShortcutsConflict( const KShortcut& cut, bool bWarnUser, QWidget* parent )
00850 {
00851 QMap< QString, KShortcut > map;
00852 readGlobalKeys( map );
00853 return checkGlobalShortcutsConflict( cut, bWarnUser, parent, map, QString::null );
00854 }
00855
00856 bool KKeyChooser::checkGlobalShortcutsConflict( const KShortcut& cut, bool bWarnUser, QWidget* parent,
00857 const QMap< QString, KShortcut >& map, const QString& ignoreAction )
00858 {
00859 QMap<QString, KShortcut>::ConstIterator it;
00860 for( it = map.begin(); it != map.end(); ++it ) {
00861 int iSeq = keyConflict( cut, (*it) );
00862 if( iSeq > -1 ) {
00863 if( ignoreAction.isEmpty() || it.key() != ignoreAction ) {
00864 if( bWarnUser ) {
00865 if( !promptForReassign( cut.seq(iSeq), it.key(), Global, parent ))
00866 return true;
00867 removeGlobalShortcut( it.key(), dynamic_cast< KKeyChooser* >( parent ), (*it), cut);
00868 }
00869 }
00870 }
00871 }
00872 return false;
00873 }
00874
00875 void KKeyChooser::removeStandardShortcut( const QString& name, KKeyChooser* chooser, const KShortcut &origCut, const KShortcut &cut )
00876 {
00877 bool was_in_choosers = false;
00878 if( allChoosers != NULL ) {
00879 for( QValueList< KKeyChooser* >::ConstIterator it = allChoosers->begin();
00880 it != allChoosers->end();
00881 ++it ) {
00882 if( (*it) != chooser && (*it)->m_type == Standard ) {
00883 was_in_choosers |= ( (*it)->removeShortcut( name, cut ));
00884 }
00885 }
00886 }
00887 if( !was_in_choosers ) {
00888 KStdAccel::ShortcutList std_list;
00889 KShortcut newCut = origCut;
00890 removeFromShortcut(newCut, cut);
00891 int index = std_list.index( name );
00892 if ( index >= 0 ) {
00893 std_list.setShortcut( index, newCut );
00894 std_list.save();
00895 }
00896 }
00897 }
00898
00899 void KKeyChooser::removeGlobalShortcut( const QString& name, KKeyChooser* chooser, const KShortcut &origCut, const KShortcut &cut )
00900 {
00901 bool was_in_choosers = false;
00902 if( allChoosers != NULL ) {
00903 for( QValueList< KKeyChooser* >::ConstIterator it = allChoosers->begin();
00904 it != allChoosers->end();
00905 ++it ) {
00906 if( (*it) != chooser && (*it)->m_type == Global ) {
00907 was_in_choosers |= ( (*it)->removeShortcut( name, cut ));
00908 }
00909 }
00910 }
00911 if( !was_in_choosers ) {
00912 KAccelActions actions;
00913 KShortcut newCut = origCut;
00914 removeFromShortcut(newCut, cut);
00915 actions.insert( name, "", "", newCut, newCut);
00916 actions.writeActions( "Global Shortcuts", 0, true, true );
00917 }
00918 }
00919
00920 bool KKeyChooser::removeShortcut( const QString& name, const KShortcut &cut )
00921 {
00922 for( QListViewItemIterator it( d->pList ); it.current(); ++it ) {
00923 KKeyChooserItem* pItem2 = dynamic_cast<KKeyChooserItem*>(it.current());
00924 if( pItem2 && pItem2->actionName() == name ) {
00925
00926 KShortcut cut2 = pItem2->shortcut();
00927 removeFromShortcut(cut2, cut);
00928 pItem2->setShortcut(cut2);
00929 updateButtons();
00930 emit keyChange();
00931 return true;
00932 }
00933 }
00934 return false;
00935 }
00936
00937
00938 void KKeyChooser::_warning( const KKeySequence& cut, QString sAction, QString sTitle )
00939 {
00940 sAction = sAction.stripWhiteSpace();
00941
00942 QString s =
00943 i18n("The '%1' key combination has already been allocated "
00944 "to the \"%2\" action.\n"
00945 "Please choose a unique key combination.").
00946 arg(cut.toString()).arg(sAction);
00947
00948 KMessageBox::sorry( this, s, sTitle );
00949 }
00950
00951 bool KKeyChooser::promptForReassign( const KKeySequence& cut, const QString& sAction, ActionType type, QWidget* parent )
00952 {
00953 if(cut.isNull())
00954 return true;
00955 QString sTitle;
00956 QString s;
00957 if( type == Standard ) {
00958 sTitle = i18n("Conflict with Standard Application Shortcut");
00959 s = i18n("The '%1' key combination has already been allocated "
00960 "to the standard action \"%2\".\n"
00961 "Do you want to reassign it from that action to the current one?");
00962 }
00963 else if( type == Global ) {
00964 sTitle = i18n("Conflict with Global Shortcut");
00965 s = i18n("The '%1' key combination has already been allocated "
00966 "to the global action \"%2\".\n"
00967 "Do you want to reassign it from that action to the current one?");
00968 }
00969 else {
00970 sTitle = i18n("Key Conflict");
00971 s = i18n("The '%1' key combination has already been allocated "
00972 "to the \"%2\" action.\n"
00973 "Do you want to reassign it from that action to the current one?");
00974 }
00975 s = s.arg(cut.toString()).arg(sAction.stripWhiteSpace());
00976
00977 return KMessageBox::warningContinueCancel( parent, s, sTitle, i18n("Reassign") ) == KMessageBox::Continue;
00978 }
00979
00980
00981 KKeyChooserItem::KKeyChooserItem( KListView* parent, QListViewItem* after, KShortcutList* pList, uint iAction )
00982 : KListViewItem( parent, after )
00983 {
00984 m_pList = pList;
00985 m_iAction = iAction;
00986 m_bModified = false;
00987 m_cut = m_pList->shortcut(m_iAction);
00988 }
00989
00990 KKeyChooserItem::KKeyChooserItem( QListViewItem* parent, QListViewItem* after, KShortcutList* pList, uint iAction )
00991 : KListViewItem( parent, after )
00992 {
00993 m_pList = pList;
00994 m_iAction = iAction;
00995 m_bModified = false;
00996 m_cut = m_pList->shortcut(m_iAction);
00997 }
00998
00999 QString KKeyChooserItem::actionName() const
01000 {
01001 return m_pList->name(m_iAction);
01002 }
01003
01004 const KShortcut& KKeyChooserItem::shortcut() const
01005 {
01006 return m_cut;
01007 }
01008
01009 void KKeyChooserItem::setShortcut( const KShortcut& cut )
01010 {
01011 m_cut = cut;
01012 m_bModified = (m_cut != m_pList->shortcut(m_iAction));
01013 listView()->repaintItem( this );
01014 }
01015
01016 void KKeyChooserItem::commitChanges()
01017 {
01018 if( m_bModified )
01019 m_pList->setShortcut( m_iAction, m_cut );
01020 }
01021
01022 QString KKeyChooserItem::text( int iCol ) const
01023 {
01024 if( iCol == 0 ) {
01025
01026 QString s = m_pList->label(m_iAction);
01027 QString s2;
01028 for( uint i = 0; i < s.length(); i++ )
01029 if( s[i] != '&' || ( i+1<s.length() && s[i+1] == '&' ) )
01030 s2 += s[i];
01031 return s2;
01032 }
01033 else if( iCol <= (int) m_cut.count() )
01034 return m_cut.seq(iCol-1).toString();
01035 else
01036 return QString::null;
01037 }
01038
01039 int KKeyChooserItem::compare( QListViewItem* item, int iCol, bool bAscending ) const
01040 {
01041 KKeyChooserItem* pItem = dynamic_cast<KKeyChooserItem*>( item );
01042 if( iCol == 0 && pItem ) {
01043 QString psName1 = m_pList->name(m_iAction);
01044 QString psName2 = pItem->m_pList->name(pItem->m_iAction);
01045 QRegExp rxNumber1( " (\\d+)$" );
01046 QRegExp rxNumber2( " (\\d+)$" );
01047 int iNumber1 = rxNumber1.search( psName1 );
01048 int iNumber2 = rxNumber2.search( psName2 );
01049
01050
01051 if( iNumber1 >= 0 && iNumber1 == iNumber2 && psName1.startsWith( psName2.left( iNumber1+1 ) ) ) {
01052 int n1 = rxNumber1.cap(1).toInt();
01053 int n2 = rxNumber2.cap(1).toInt();
01054 return (n1 < n2) ? -1 : (n1 > n2) ? 1 : 0;
01055 }
01056 }
01057
01058 return QListViewItem::compare( item, iCol, bAscending );
01059 }
01060
01062
01063 QString KKeyChooserWhatsThis::text( const QPoint& p ) {
01064 if ( !m_listView )
01065 return QString::null;
01066
01067 const QListViewItem* item = m_listView->itemAt( p );
01068 const KKeyChooserItem* pItem = dynamic_cast<const KKeyChooserItem*>(item);
01069 if ( !pItem )
01070 return QWhatsThis::textFor( m_listView );
01071
01072 const QString itemWhatsThis = pItem->whatsThis();
01073 if ( itemWhatsThis.isEmpty() )
01074 return QWhatsThis::textFor( m_listView );
01075
01076 return itemWhatsThis;
01077 }
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090 KKeyDialog::KKeyDialog( KKeyChooser::ActionType type, bool bAllowLetterShortcuts, QWidget *parent, const char* name )
01091 : KDialogBase( parent, name ? name : "kkeydialog", true, i18n("Configure Shortcuts"), Default|Ok|Cancel, Ok )
01092 {
01093 m_pKeyChooser = new KKeyChooser( this, type, bAllowLetterShortcuts );
01094 setMainWidget( m_pKeyChooser );
01095 connect( this, SIGNAL(defaultClicked()), m_pKeyChooser, SLOT(allDefault()) );
01096
01097 KConfigGroup group( KGlobal::config(), "KKeyDialog Settings" );
01098 QSize sz = size();
01099 resize( group.readSizeEntry( "Dialog Size", &sz ) );
01100 }
01101
01102 KKeyDialog::KKeyDialog( bool bAllowLetterShortcuts, QWidget *parent, const char* name )
01103 : KDialogBase( parent, name ? name : "kkeydialog", true, i18n("Configure Shortcuts"), Default|Ok|Cancel, Ok )
01104 {
01105 m_pKeyChooser = new KKeyChooser( this, KKeyChooser::Application, bAllowLetterShortcuts );
01106 setMainWidget( m_pKeyChooser );
01107 connect( this, SIGNAL(defaultClicked()), m_pKeyChooser, SLOT(allDefault()) );
01108
01109 KConfigGroup group( KGlobal::config(), "KKeyDialog Settings" );
01110 QSize sz = size();
01111 resize( group.readSizeEntry( "Dialog Size", &sz ) );
01112 }
01113
01114 KKeyDialog::~KKeyDialog()
01115 {
01116 KConfigGroup group( KGlobal::config(), "KKeyDialog Settings" );
01117 group.writeEntry( "Dialog Size", size(), true, true );
01118 }
01119
01120 bool KKeyDialog::insert( KActionCollection* pColl )
01121 {
01122 return m_pKeyChooser->insert( pColl );
01123 }
01124
01125 bool KKeyDialog::insert(KActionCollection *pColl, const QString &title)
01126 {
01127 return m_pKeyChooser->insert(pColl, title);
01128 }
01129
01130 bool KKeyDialog::configure( bool bSaveSettings )
01131 {
01132 int retcode = exec();
01133 if( retcode == Accepted ) {
01134 if( bSaveSettings )
01135 m_pKeyChooser->save();
01136 else
01137 commitChanges();
01138 }
01139 return retcode;
01140 }
01141
01142 void KKeyDialog::commitChanges()
01143 {
01144 m_pKeyChooser->commitChanges();
01145 }
01146
01147 int KKeyDialog::configure( KActionCollection* coll, QWidget* parent, bool bSaveSettings )
01148 {
01149 return configure( coll, true, parent, bSaveSettings);
01150 }
01151
01152 int KKeyDialog::configure( KAccel* keys, QWidget* parent, bool bSaveSettings )
01153 {
01154 return configure( keys, true, parent, bSaveSettings);
01155 }
01156
01157 int KKeyDialog::configure( KGlobalAccel* keys, QWidget* parent, bool bSaveSettings )
01158 {
01159 return configure( keys, true, parent, bSaveSettings);
01160 }
01161
01162 int KKeyDialog::configure( KAccel* keys, bool bAllowLetterShortcuts, QWidget *parent, bool bSaveSettings )
01163 {
01164 KKeyDialog dlg( bAllowLetterShortcuts, parent );
01165 dlg.m_pKeyChooser->insert( keys );
01166 bool b = dlg.configure( bSaveSettings );
01167 if( b && bSaveSettings )
01168 keys->updateConnections();
01169 return b;
01170 }
01171
01172 int KKeyDialog::configure( KGlobalAccel* keys, bool bAllowLetterShortcuts, QWidget *parent, bool bSaveSettings )
01173 {
01174 KKeyDialog dlg( KKeyChooser::ApplicationGlobal, bAllowLetterShortcuts, parent );
01175 dlg.m_pKeyChooser->insert( keys );
01176 bool b = dlg.configure( bSaveSettings );
01177 if( b && bSaveSettings )
01178 keys->updateConnections();
01179 return b;
01180 }
01181
01182 int KKeyDialog::configure( KActionCollection* coll, bool bAllowLetterShortcuts, QWidget *parent, bool bSaveSettings )
01183 {
01184 kdDebug(125) << "KKeyDialog::configureKeys( KActionCollection*, " << bSaveSettings << " )" << endl;
01185 KKeyDialog dlg( bAllowLetterShortcuts, parent );
01186 dlg.m_pKeyChooser->insert( coll );
01187 return dlg.configure( bSaveSettings );
01188 }
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203 void KKeyChooser::virtual_hook( int, void* )
01204 { }
01205
01206 void KKeyDialog::virtual_hook( int id, void* data )
01207 { KDialogBase::virtual_hook( id, data ); }
01208
01209 #include "kkeydialog.moc"