• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • sources
  • kde-4.12
  • kdelibs
  • kdeui
  • widgets
kkeysequencewidget.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 1998 Mark Donohoe <donohoe@kde.org>
3  Copyright (C) 2001 Ellis Whitehead <ellis@kde.org>
4  Copyright (C) 2007 Andreas Hartmetz <ahartmetz@gmail.com>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "kkeysequencewidget.h"
23 #include "kkeysequencewidget_p.h"
24 
25 #include "kkeyserver.h"
26 
27 #include <QKeyEvent>
28 #include <QTimer>
29 #include <QtCore/QHash>
30 #include <QHBoxLayout>
31 #include <QToolButton>
32 #include <QApplication>
33 
34 #include <kglobalaccel.h>
35 #include <kicon.h>
36 #include <klocale.h>
37 #include <kmessagebox.h>
38 #include <kshortcut.h>
39 #include <kaction.h>
40 #include <kactioncollection.h>
41 
42 #include "kdebug.h"
43 
44 class KKeySequenceWidgetPrivate
45 {
46 public:
47  KKeySequenceWidgetPrivate(KKeySequenceWidget *q);
48 
49  void init();
50 
51  static QKeySequence appendToSequence(const QKeySequence& seq, int keyQt);
52  static bool isOkWhenModifierless(int keyQt);
53 
54  void updateShortcutDisplay();
55  void startRecording();
56 
61  bool conflictWithStandardShortcuts(const QKeySequence &seq);
62 
67  bool conflictWithLocalShortcuts(const QKeySequence &seq);
68 
73  bool conflictWithGlobalShortcuts(const QKeySequence &seq);
74 
78  bool stealStandardShortcut(KStandardShortcut::StandardShortcut std, const QKeySequence &seq);
79 
80  bool checkAgainstStandardShortcuts() const
81  {
82  return checkAgainstShortcutTypes & KKeySequenceWidget::StandardShortcuts;
83  }
84 
85  bool checkAgainstGlobalShortcuts() const
86  {
87  return checkAgainstShortcutTypes & KKeySequenceWidget::GlobalShortcuts;
88  }
89 
90  bool checkAgainstLocalShortcuts() const
91  {
92  return checkAgainstShortcutTypes & KKeySequenceWidget::LocalShortcuts;
93  }
94 
95  void controlModifierlessTimout()
96  {
97  if (nKey != 0 && !modifierKeys) {
98  // No modifier key pressed currently. Start the timout
99  modifierlessTimeout.start(600);
100  } else {
101  // A modifier is pressed. Stop the timeout
102  modifierlessTimeout.stop();
103  }
104 
105  }
106 
107 
108  void cancelRecording()
109  {
110  keySequence = oldKeySequence;
111  doneRecording();
112  }
113 
114 
115  bool promptStealShortcutSystemwide(
116  QWidget *parent,
117  const QHash<QKeySequence, QList<KGlobalShortcutInfo> > &shortcuts,
118  const QKeySequence &sequence)
119  {
120  if (shortcuts.isEmpty()) {
121  // Usage error. Just say no
122  return false;
123  }
124 
125  QString clashingKeys = "";
126  Q_FOREACH (const QKeySequence &seq, shortcuts.keys()) {
127  Q_FOREACH (const KGlobalShortcutInfo &info, shortcuts[seq]) {
128  clashingKeys += i18n("Shortcut '%1' in Application %2 for action %3\n",
129  seq.toString(),
130  info.componentFriendlyName(),
131  info.friendlyName());
132  }
133  }
134 
135  const int hashSize = shortcuts.size();
136 
137  QString message = i18ncp("%1 is the number of conflicts (hidden), %2 is the key sequence of the shortcut that is problematic",
138  "The shortcut '%2' conflicts with the following key combination:\n",
139  "The shortcut '%2' conflicts with the following key combinations:\n",
140  hashSize, sequence.toString());
141  message+=clashingKeys;
142 
143  QString title = i18ncp("%1 is the number of shortcuts with which there is a conflict",
144  "Conflict with Registered Global Shortcut", "Conflict with Registered Global Shortcuts", hashSize);
145 
146  return KMessageBox::warningContinueCancel(parent, message, title, KGuiItem(i18n("Reassign")))
147  == KMessageBox::Continue;
148  }
149 
150 
151 //private slot
152  void doneRecording(bool validate = true);
153 
154 //members
155  KKeySequenceWidget *const q;
156  QHBoxLayout *layout;
157  KKeySequenceButton *keyButton;
158  QToolButton *clearButton;
159 
160  QKeySequence keySequence;
161  QKeySequence oldKeySequence;
162  QTimer modifierlessTimeout;
163  bool allowModifierless;
164  uint nKey;
165  uint modifierKeys;
166  bool isRecording;
167  bool multiKeyShortcutsAllowed;
168  QString componentName;
169 
171  KKeySequenceWidget::ShortcutTypes checkAgainstShortcutTypes;
172 
176  QList<QAction*> checkList; // deprecated
177 
181  QList<KActionCollection*> checkActionCollections;
182 
186  QList<KAction*> stealActions;
187 
188  bool stealShortcuts(const QList<KAction *> &actions, const QKeySequence &seq);
189  void wontStealShortcut(QAction *item, const QKeySequence &seq);
190 
191 };
192 
193 KKeySequenceWidgetPrivate::KKeySequenceWidgetPrivate(KKeySequenceWidget *q)
194  : q(q)
195  ,layout(NULL)
196  ,keyButton(NULL)
197  ,clearButton(NULL)
198  ,allowModifierless(false)
199  ,nKey(0)
200  ,modifierKeys(0)
201  ,isRecording(false)
202  ,multiKeyShortcutsAllowed(true)
203  ,componentName()
204  ,checkAgainstShortcutTypes(KKeySequenceWidget::LocalShortcuts & KKeySequenceWidget::GlobalShortcuts)
205  ,stealActions()
206 {}
207 
208 
209 bool KKeySequenceWidgetPrivate::stealShortcuts(
210  const QList<KAction *> &actions,
211  const QKeySequence &seq)
212 {
213 
214  const int listSize = actions.size();
215 
216  QString title = i18ncp("%1 is the number of conflicts", "Shortcut Conflict", "Shortcut Conflicts", listSize);
217 
218  QString conflictingShortcuts;
219  Q_FOREACH(const KAction *action, actions) {
220  conflictingShortcuts += i18n("Shortcut '%1' for action '%2'\n",
221  action->shortcut().toString(QKeySequence::NativeText),
222  KGlobal::locale()->removeAcceleratorMarker(action->text()));
223  }
224  QString message = i18ncp("%1 is the number of ambigious shortcut clashes (hidden)",
225  "The \"%2\" shortcut is ambiguous with the following shortcut.\n"
226  "Do you want to assign an empty shortcut to this action?\n"
227  "%3",
228  "The \"%2\" shortcut is ambiguous with the following shortcuts.\n"
229  "Do you want to assign an empty shortcut to these actions?\n"
230  "%3",
231  listSize,
232  seq.toString(QKeySequence::NativeText),
233  conflictingShortcuts);
234 
235  if (KMessageBox::warningContinueCancel(q, message, title, KGuiItem(i18n("Reassign"))) != KMessageBox::Continue)
236  return false;
237 
238  return true;
239 }
240 
241 void KKeySequenceWidgetPrivate::wontStealShortcut(QAction *item, const QKeySequence &seq)
242 {
243  QString title( i18n( "Shortcut conflict" ) );
244  QString msg( i18n( "<qt>The '%1' key combination is already used by the <b>%2</b> action.<br>"
245  "Please select a different one.</qt>", seq.toString(QKeySequence::NativeText) ,
246  KGlobal::locale()->removeAcceleratorMarker(item->text()) ) );
247  KMessageBox::sorry( q, msg );
248 }
249 
250 
251 KKeySequenceWidget::KKeySequenceWidget(QWidget *parent)
252  : QWidget(parent),
253  d(new KKeySequenceWidgetPrivate(this))
254 {
255  d->init();
256  setFocusProxy( d->keyButton );
257  connect(d->keyButton, SIGNAL(clicked()), this, SLOT(captureKeySequence()));
258  connect(d->clearButton, SIGNAL(clicked()), this, SLOT(clearKeySequence()));
259  connect(&d->modifierlessTimeout, SIGNAL(timeout()), this, SLOT(doneRecording()));
260  //TODO: how to adopt style changes at runtime?
261  /*QFont modFont = d->clearButton->font();
262  modFont.setStyleHint(QFont::TypeWriter);
263  d->clearButton->setFont(modFont);*/
264  d->updateShortcutDisplay();
265 }
266 
267 
268 void KKeySequenceWidgetPrivate::init()
269 {
270  layout = new QHBoxLayout(q);
271  layout->setMargin(0);
272 
273  keyButton = new KKeySequenceButton(this, q);
274  keyButton->setFocusPolicy(Qt::StrongFocus);
275  keyButton->setIcon(KIcon("configure"));
276  keyButton->setToolTip(i18n("Click on the button, then enter the shortcut like you would in the program.\nExample for Ctrl+a: hold the Ctrl key and press a."));
277  layout->addWidget(keyButton);
278 
279  clearButton = new QToolButton(q);
280  layout->addWidget(clearButton);
281 
282  if (qApp->isLeftToRight())
283  clearButton->setIcon(KIcon("edit-clear-locationbar-rtl"));
284  else
285  clearButton->setIcon(KIcon("edit-clear-locationbar-ltr"));
286 }
287 
288 
289 KKeySequenceWidget::~KKeySequenceWidget ()
290 {
291  delete d;
292 }
293 
294 
295 KKeySequenceWidget::ShortcutTypes KKeySequenceWidget::checkForConflictsAgainst() const
296 {
297  return d->checkAgainstShortcutTypes;
298 }
299 
300 
301 void KKeySequenceWidget::setComponentName(const QString &componentName)
302 {
303  d->componentName = componentName;
304 }
305 
306 bool KKeySequenceWidget::multiKeyShortcutsAllowed() const
307 {
308  return d->multiKeyShortcutsAllowed;
309 }
310 
311 
312 void KKeySequenceWidget::setMultiKeyShortcutsAllowed(bool allowed)
313 {
314  d->multiKeyShortcutsAllowed = allowed;
315 }
316 
317 
318 void KKeySequenceWidget::setCheckForConflictsAgainst(ShortcutTypes types)
319 {
320  d->checkAgainstShortcutTypes = types;
321 }
322 
323 void KKeySequenceWidget::setModifierlessAllowed(bool allow)
324 {
325  d->allowModifierless = allow;
326 }
327 
328 
329 bool KKeySequenceWidget::isKeySequenceAvailable(const QKeySequence &keySequence) const
330 {
331  if (keySequence.isEmpty())
332  return true;
333  return ! ( d->conflictWithLocalShortcuts(keySequence)
334  || d->conflictWithGlobalShortcuts(keySequence)
335  || d->conflictWithStandardShortcuts(keySequence));
336 }
337 
338 
339 bool KKeySequenceWidget::isModifierlessAllowed()
340 {
341  return d->allowModifierless;
342 }
343 
344 
345 void KKeySequenceWidget::setClearButtonShown(bool show)
346 {
347  d->clearButton->setVisible(show);
348 }
349 
350 #ifndef KDE_NO_DEPRECATED
351 void KKeySequenceWidget::setCheckActionList(const QList<QAction*> &checkList) // deprecated
352 {
353  d->checkList = checkList;
354  Q_ASSERT(d->checkActionCollections.isEmpty()); // don't call this method if you call setCheckActionCollections!
355 }
356 #endif
357 
358 void KKeySequenceWidget::setCheckActionCollections(const QList<KActionCollection *>& actionCollections)
359 {
360  d->checkActionCollections = actionCollections;
361 }
362 
363 //slot
364 void KKeySequenceWidget::captureKeySequence()
365 {
366  d->startRecording();
367 }
368 
369 
370 QKeySequence KKeySequenceWidget::keySequence() const
371 {
372  return d->keySequence;
373 }
374 
375 
376 //slot
377 void KKeySequenceWidget::setKeySequence(const QKeySequence &seq, Validation validate)
378 {
379  // oldKeySequence holds the key sequence before recording started, if setKeySequence()
380  // is called while not recording then set oldKeySequence to the existing sequence so
381  // that the keySequenceChanged() signal is emitted if the new and previous key
382  // sequences are different
383  if (!d->isRecording)
384  d->oldKeySequence = d->keySequence;
385 
386  d->keySequence = seq;
387  d->doneRecording(validate == Validate);
388 }
389 
390 
391 //slot
392 void KKeySequenceWidget::clearKeySequence()
393 {
394  setKeySequence(QKeySequence());
395 }
396 
397 //slot
398 void KKeySequenceWidget::applyStealShortcut()
399 {
400  QSet<KActionCollection *> changedCollections;
401 
402  Q_FOREACH (KAction *stealAction, d->stealActions) {
403 
404  // Stealing a shortcut means setting it to an empty one.
405  stealAction->setShortcut(KShortcut(), KAction::ActiveShortcut);
406 
407  // The following code will find the action we are about to
408  // steal from and save it's actioncollection.
409  KActionCollection* parentCollection = 0;
410  foreach(KActionCollection* collection, d->checkActionCollections) {
411  if (collection->actions().contains(stealAction)) {
412  parentCollection = collection;
413  break;
414  }
415  }
416 
417  // Remember the changed collection
418  if (parentCollection) {
419  changedCollections.insert(parentCollection);
420  }
421  }
422 
423  Q_FOREACH (KActionCollection *col, changedCollections) {
424  col->writeSettings();
425  }
426 
427  d->stealActions.clear();
428 }
429 
430 void KKeySequenceButton::setText(const QString &text)
431 {
432  QPushButton::setText(text);
433  //setFixedSize( sizeHint().width()+12, sizeHint().height()+8 );
434 }
435 
436 
437 void KKeySequenceWidgetPrivate::startRecording()
438 {
439  nKey = 0;
440  modifierKeys = 0;
441  oldKeySequence = keySequence;
442  keySequence = QKeySequence();
443  isRecording = true;
444  keyButton->grabKeyboard();
445 
446  if (!QWidget::keyboardGrabber()) {
447  kWarning() << "Failed to grab the keyboard! Most likely qt's nograb option is active";
448  }
449 
450  keyButton->setDown(true);
451  updateShortcutDisplay();
452 }
453 
454 
455 void KKeySequenceWidgetPrivate::doneRecording(bool validate)
456 {
457  modifierlessTimeout.stop();
458  isRecording = false;
459  keyButton->releaseKeyboard();
460  keyButton->setDown(false);
461  stealActions.clear();
462 
463  if (keySequence==oldKeySequence) {
464  // The sequence hasn't changed
465  updateShortcutDisplay();
466  return;
467  }
468 
469  if (validate && !q->isKeySequenceAvailable(keySequence)) {
470  // The sequence had conflicts and the user said no to stealing it
471  keySequence = oldKeySequence;
472  } else {
473  emit q->keySequenceChanged(keySequence);
474  }
475 
476  updateShortcutDisplay();
477 }
478 
479 
480 bool KKeySequenceWidgetPrivate::conflictWithGlobalShortcuts(const QKeySequence &keySequence)
481 {
482 #ifdef Q_WS_WIN
483  //on windows F12 is reserved by the debugger at all times, so we can't use it for a global shortcut
484  if (KKeySequenceWidget::GlobalShortcuts && keySequence.toString().contains("F12")) {
485  QString title = i18n("Reserved Shortcut");
486  QString message = i18n("The F12 key is reserved on Windows, so cannot be used for a global shortcut.\n"
487  "Please choose another one.");
488 
489  KMessageBox::sorry(q, message, title);
490  return false;
491  }
492 #endif
493 
494  if (!(checkAgainstShortcutTypes & KKeySequenceWidget::GlobalShortcuts)) {
495  return false;
496  }
497 
498  // Global shortcuts are on key+modifier shortcuts. They can clash with
499  // each of the keys of a multi key shortcut.
500  QHash<QKeySequence, QList<KGlobalShortcutInfo> > others;
501  for (uint i=0; i<keySequence.count(); ++i) {
502  QKeySequence tmp(keySequence[i]);
503 
504  if (!KGlobalAccel::isGlobalShortcutAvailable(tmp, componentName)) {
505  others.insert(tmp, KGlobalAccel::getGlobalShortcutsByKey(tmp));
506  }
507  }
508 
509  if (!others.isEmpty()
510  && !promptStealShortcutSystemwide(q, others, keySequence)) {
511  return true;
512  }
513 
514  // The user approved stealing the shortcut. We have to steal
515  // it immediately because KAction::setGlobalShortcut() refuses
516  // to set a global shortcut that is already used. There is no
517  // error it just silently fails. So be nice because this is
518  // most likely the first action that is done in the slot
519  // listening to keySequenceChanged().
520  for (uint i=0; i<keySequence.count(); ++i) {
521  KGlobalAccel::stealShortcutSystemwide(keySequence[i]);
522  }
523  return false;
524 }
525 
526 
527 bool KKeySequenceWidgetPrivate::conflictWithLocalShortcuts(const QKeySequence &keySequence)
528 {
529  if (!(checkAgainstShortcutTypes & KKeySequenceWidget::LocalShortcuts)) {
530  return false;
531  }
532 
533  // We have actions both in the deprecated checkList and the
534  // checkActionCollections list. Add all the actions to a single list to
535  // be able to process them in a single loop below.
536  // Note that this can't be done in setCheckActionCollections(), because we
537  // keep pointers to the action collections, and between the call to
538  // setCheckActionCollections() and this function some actions might already be
539  // removed from the collection again.
540  QList<QAction*> allActions;
541  allActions += checkList;
542  foreach(KActionCollection* collection, checkActionCollections) {
543  allActions += collection->actions();
544  }
545 
546  // Because of multikey shortcuts we can have clashes with many shortcuts.
547  //
548  // Example 1:
549  //
550  // Application currently uses 'CTRL-X,a', 'CTRL-X,f' and 'CTRL-X,CTRL-F'
551  // and the user wants to use 'CTRL-X'. 'CTRL-X' will only trigger as
552  // 'activatedAmbiguously()' for obvious reasons.
553  //
554  // Example 2:
555  //
556  // Application currently uses 'CTRL-X'. User wants to use 'CTRL-X,CTRL-F'.
557  // This will shadow 'CTRL-X' for the same reason as above.
558  //
559  // Example 3:
560  //
561  // Some weird combination of Example 1 and 2 with three shortcuts using
562  // 1/2/3 key shortcuts. I think you can imagine.
563  QList<KAction*> conflictingActions;
564 
565  //find conflicting shortcuts with existing actions
566  foreach(QAction * qaction , allActions ) {
567  KAction *kaction=qobject_cast<KAction*>(qaction);
568  if(kaction) {
569  if(kaction->shortcut().conflictsWith(keySequence)) {
570  // A conflict with a KAction. If that action is configurable
571  // ask the user what to do. If not reject this keySequence.
572  if(kaction->isShortcutConfigurable ()) {
573  conflictingActions.append(kaction);
574  } else {
575  wontStealShortcut(kaction, keySequence);
576  return true;
577  }
578  }
579  } else {
580  if(qaction->shortcut() == keySequence) {
581  // A conflict with a QAction. Don't know why :-( but we won't
582  // steal from that kind of actions.
583  wontStealShortcut(qaction, keySequence);
584  return true;
585  }
586  }
587  }
588 
589  if (conflictingActions.isEmpty()) {
590  // No conflicting shortcuts found.
591  return false;
592  }
593 
594  if(stealShortcuts(conflictingActions, keySequence)) {
595  stealActions = conflictingActions;
596  // Announce that the user
597  // agreed
598  Q_FOREACH (KAction *stealAction, stealActions) {
599  emit q->stealShortcut(
600  keySequence,
601  stealAction);
602  }
603  return false;
604  } else {
605  return true;
606  }
607 }
608 
609 
610 bool KKeySequenceWidgetPrivate::conflictWithStandardShortcuts(const QKeySequence &keySequence)
611 {
612  if (!(checkAgainstShortcutTypes & KKeySequenceWidget::StandardShortcuts)) {
613  return false;
614  }
615 
616  KStandardShortcut::StandardShortcut ssc = KStandardShortcut::find(keySequence);
617  if (ssc != KStandardShortcut::AccelNone && !stealStandardShortcut(ssc, keySequence)) {
618  return true;
619  }
620  return false;
621 }
622 
623 
624 bool KKeySequenceWidgetPrivate::stealStandardShortcut(KStandardShortcut::StandardShortcut std, const QKeySequence &seq)
625 {
626  QString title = i18n("Conflict with Standard Application Shortcut");
627  QString message = i18n("The '%1' key combination is also used for the standard action "
628  "\"%2\" that some applications use.\n"
629  "Do you really want to use it as a global shortcut as well?",
630  seq.toString(QKeySequence::NativeText), KStandardShortcut::label(std));
631 
632  if (KMessageBox::warningContinueCancel(q, message, title, KGuiItem(i18n("Reassign"))) != KMessageBox::Continue) {
633  return false;
634  }
635  return true;
636 }
637 
638 
639 void KKeySequenceWidgetPrivate::updateShortcutDisplay()
640 {
641  //empty string if no non-modifier was pressed
642  QString s = keySequence.toString(QKeySequence::NativeText);
643  s.replace('&', QLatin1String("&&"));
644 
645  if (isRecording) {
646  if (modifierKeys) {
647  if (!s.isEmpty()) s.append(",");
648  if (modifierKeys & Qt::META) s += KKeyServer::modToStringUser(Qt::META) + '+';
649 #if defined(Q_WS_MAC)
650  if (modifierKeys & Qt::ALT) s += KKeyServer::modToStringUser(Qt::ALT) + '+';
651  if (modifierKeys & Qt::CTRL) s += KKeyServer::modToStringUser(Qt::CTRL) + '+';
652 #elif defined(Q_WS_X11)
653  if (modifierKeys & Qt::CTRL) s += KKeyServer::modToStringUser(Qt::CTRL) + '+';
654  if (modifierKeys & Qt::ALT) s += KKeyServer::modToStringUser(Qt::ALT) + '+';
655 #endif
656  if (modifierKeys & Qt::SHIFT) s += KKeyServer::modToStringUser(Qt::SHIFT) + '+';
657 
658  } else if (nKey == 0) {
659  s = i18nc("What the user inputs now will be taken as the new shortcut", "Input");
660  }
661  //make it clear that input is still going on
662  s.append(" ...");
663  }
664 
665  if (s.isEmpty()) {
666  s = i18nc("No shortcut defined", "None");
667  }
668 
669  s.prepend(' ');
670  s.append(' ');
671  keyButton->setText(s);
672 }
673 
674 
675 KKeySequenceButton::~KKeySequenceButton()
676 {
677 }
678 
679 
680 //prevent Qt from special casing Tab and Backtab
681 bool KKeySequenceButton::event (QEvent* e)
682 {
683  if (d->isRecording && e->type() == QEvent::KeyPress) {
684  keyPressEvent(static_cast<QKeyEvent *>(e));
685  return true;
686  }
687 
688  // The shortcut 'alt+c' ( or any other dialog local action shortcut )
689  // ended the recording and triggered the action associated with the
690  // action. In case of 'alt+c' ending the dialog. It seems that those
691  // ShortcutOverride events get sent even if grabKeyboard() is active.
692  if (d->isRecording && e->type() == QEvent::ShortcutOverride) {
693  e->accept();
694  return true;
695  }
696 
697  return QPushButton::event(e);
698 }
699 
700 
701 void KKeySequenceButton::keyPressEvent(QKeyEvent *e)
702 {
703  int keyQt = e->key();
704  if (keyQt == -1) {
705  // Qt sometimes returns garbage keycodes, I observed -1, if it doesn't know a key.
706  // We cannot do anything useful with those (several keys have -1, indistinguishable)
707  // and QKeySequence.toString() will also yield a garbage string.
708  KMessageBox::sorry(this,
709  i18n("The key you just pressed is not supported by Qt."),
710  i18n("Unsupported Key"));
711  return d->cancelRecording();
712  }
713 
714  uint newModifiers = e->modifiers() & (Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META);
715 
716  //don't have the return or space key appear as first key of the sequence when they
717  //were pressed to start editing - catch and them and imitate their effect
718  if (!d->isRecording && ((keyQt == Qt::Key_Return || keyQt == Qt::Key_Space))) {
719  d->startRecording();
720  d->modifierKeys = newModifiers;
721  d->updateShortcutDisplay();
722  return;
723  }
724 
725  // We get events even if recording isn't active.
726  if (!d->isRecording)
727  return QPushButton::keyPressEvent(e);
728 
729  e->accept();
730  d->modifierKeys = newModifiers;
731 
732 
733  switch(keyQt) {
734  case Qt::Key_AltGr: //or else we get unicode salad
735  return;
736  case Qt::Key_Shift:
737  case Qt::Key_Control:
738  case Qt::Key_Alt:
739  case Qt::Key_Meta:
740  case Qt::Key_Menu: //unused (yes, but why?)
741  d->controlModifierlessTimout();
742  d->updateShortcutDisplay();
743  break;
744  default:
745 
746  if (d->nKey == 0 && !(d->modifierKeys & ~Qt::SHIFT)) {
747  // It's the first key and no modifier pressed. Check if this is
748  // allowed
749  if (!(KKeySequenceWidgetPrivate::isOkWhenModifierless(keyQt)
750  || d->allowModifierless)) {
751  // No it's not
752  return;
753  }
754  }
755 
756  // We now have a valid key press.
757  if (keyQt) {
758  if ((keyQt == Qt::Key_Backtab) && (d->modifierKeys & Qt::SHIFT)) {
759  keyQt = Qt::Key_Tab | d->modifierKeys;
760  }
761  else if (KKeyServer::isShiftAsModifierAllowed(keyQt)) {
762  keyQt |= d->modifierKeys;
763  }
764  else
765  keyQt |= (d->modifierKeys & ~Qt::SHIFT);
766 
767  if (d->nKey == 0) {
768  d->keySequence = QKeySequence(keyQt);
769  } else {
770  d->keySequence =
771  KKeySequenceWidgetPrivate::appendToSequence(d->keySequence, keyQt);
772  }
773 
774  d->nKey++;
775  if ((!d->multiKeyShortcutsAllowed) || (d->nKey >= 4)) {
776  d->doneRecording();
777  return;
778  }
779  d->controlModifierlessTimout();
780  d->updateShortcutDisplay();
781  }
782  }
783 }
784 
785 
786 void KKeySequenceButton::keyReleaseEvent(QKeyEvent *e)
787 {
788  if (e->key() == -1) {
789  // ignore garbage, see keyPressEvent()
790  return;
791  }
792 
793  if (!d->isRecording)
794  return QPushButton::keyReleaseEvent(e);
795 
796  e->accept();
797 
798  uint newModifiers = e->modifiers() & (Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META);
799 
800  //if a modifier that belongs to the shortcut was released...
801  if ((newModifiers & d->modifierKeys) < d->modifierKeys) {
802  d->modifierKeys = newModifiers;
803  d->controlModifierlessTimout();
804  d->updateShortcutDisplay();
805  }
806 }
807 
808 
809 //static
810 QKeySequence KKeySequenceWidgetPrivate::appendToSequence(const QKeySequence& seq, int keyQt)
811 {
812  switch (seq.count()) {
813  case 0:
814  return QKeySequence(keyQt);
815  case 1:
816  return QKeySequence(seq[0], keyQt);
817  case 2:
818  return QKeySequence(seq[0], seq[1], keyQt);
819  case 3:
820  return QKeySequence(seq[0], seq[1], seq[2], keyQt);
821  default:
822  return seq;
823  }
824 }
825 
826 
827 //static
828 bool KKeySequenceWidgetPrivate::isOkWhenModifierless(int keyQt)
829 {
830  //this whole function is a hack, but especially the first line of code
831  if (QKeySequence(keyQt).toString().length() == 1)
832  return false;
833 
834  switch (keyQt) {
835  case Qt::Key_Return:
836  case Qt::Key_Space:
837  case Qt::Key_Tab:
838  case Qt::Key_Backtab: //does this ever happen?
839  case Qt::Key_Backspace:
840  case Qt::Key_Delete:
841  return false;
842  default:
843  return true;
844  }
845 }
846 
847 #include "kkeysequencewidget.moc"
848 #include "kkeysequencewidget_p.moc"
message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
KKeyServer::isShiftAsModifierAllowed
bool isShiftAsModifierAllowed(int keyQt)
Test if the shift modifier should be recorded for a given key.
Definition: kkeyserver.cpp:113
i18n
QString i18n(const char *text)
KKeySequenceWidget
A widget to input a QKeySequence.
Definition: kkeysequencewidget.h:51
KActionCollection
A container for a set of QAction objects.
Definition: kactioncollection.h:56
KKeySequenceWidget::setComponentName
void setComponentName(const QString &componentName)
If the component using this widget supports shortcuts contexts, it has to set its component name so w...
Definition: kkeysequencewidget.cpp:301
KMessageBox::Continue
Definition: kmessagebox.h:74
kdebug.h
KKeySequenceWidget::GlobalShortcuts
Check against global shortcuts.
Definition: kkeysequencewidget.h:103
KGlobalShortcutInfo::componentFriendlyName
QString componentFriendlyName
Definition: kglobalshortcutinfo.h:45
KKeySequenceWidget::setModifierlessAllowed
void setModifierlessAllowed(bool allow)
This only applies to user input, not to setShortcut().
Definition: kkeysequencewidget.cpp:323
KStandardShortcut::find
StandardShortcut find(const QKeySequence &seq)
Return the StandardShortcut id of the standard accel action which uses this key sequence, or AccelNone if none of them do.
Definition: kstandardshortcut.cpp:295
timeout
int timeout
kactioncollection.h
KStandardShortcut::label
QString label(StandardShortcut id)
Returns a localized label for user-visible display.
Definition: kstandardshortcut.cpp:267
QWidget
KGlobalShortcutInfo
Definition: kglobalshortcutinfo.h:35
kshortcut.h
Defines platform-independent classes for keyboard shortcut handling.
KActionCollection::writeSettings
void writeSettings(KConfigGroup *config=0, bool writeDefaults=false, QAction *oneAction=0) const
Write the current configurable key associations to config.
Definition: kactioncollection.cpp:563
KAction::shortcut
KShortcut shortcut
Definition: kaction.h:220
KKeySequenceWidget::setMultiKeyShortcutsAllowed
void setMultiKeyShortcutsAllowed(bool)
Allow multikey shortcuts?
Definition: kkeysequencewidget.cpp:312
QString
QHash
klocale.h
KShortcut::conflictsWith
bool conflictsWith(const QKeySequence &needle) const
Returns whether at least one of the key sequences conflicts witho needle.
Definition: kshortcut.cpp:156
i18nc
QString i18nc(const char *ctxt, const char *text)
KShortcut
Represents a keyboard shortcut.
Definition: kshortcut.h:57
KKeySequenceWidget::LocalShortcuts
Check with local shortcuts.
Definition: kkeysequencewidget.h:101
KKeySequenceWidget::checkForConflictsAgainst
ShortcutTypes checkForConflictsAgainst() const
The shortcut types we check for conflicts.
KKeySequenceWidget::setKeySequence
void setKeySequence(const QKeySequence &seq, Validation val=NoValidate)
Set the key sequence.
Definition: kkeysequencewidget.cpp:377
kkeyserver.h
KStandardShortcut::StandardShortcut
StandardShortcut
Defines the identifier of all standard accelerators.
Definition: kstandardshortcut.h:55
i18ncp
QString i18ncp(const char *ctxt, const char *sing, const char *plur, const A1 &a1)
SHIFT
#define SHIFT(x)
Definition: kstandardshortcut.cpp:71
KGuiItem
An abstract class for GUI data such as ToolTip and Icon.
Definition: kguiitem.h:36
CTRL
#define CTRL(x)
Definition: kstandardshortcut.cpp:70
KMessageBox::sorry
static void sorry(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
Display an "Sorry" dialog.
Definition: kmessagebox.cpp:904
KActionCollection::actions
QList< QAction * > actions() const
Returns the list of KActions which belong to this action collection.
Definition: kactioncollection.cpp:186
KKeySequenceWidget::clearKeySequence
void clearKeySequence()
Clear the key sequence.
Definition: kkeysequencewidget.cpp:392
KKeySequenceWidget::~KKeySequenceWidget
virtual ~KKeySequenceWidget()
Destructs the widget.
Definition: kkeysequencewidget.cpp:289
KIcon
A wrapper around QIcon that provides KDE icon features.
Definition: kicon.h:40
KKeySequenceWidget::captureKeySequence
void captureKeySequence()
Capture a shortcut from the keyboard.
Definition: kkeysequencewidget.cpp:364
KKeySequenceWidget::Validation
Validation
An enum about validation when setting a key sequence.
Definition: kkeysequencewidget.h:75
ALT
#define ALT(x)
Definition: kstandardshortcut.cpp:73
KKeySequenceWidget::isModifierlessAllowed
bool isModifierlessAllowed()
Definition: kkeysequencewidget.cpp:339
KKeySequenceWidget::applyStealShortcut
void applyStealShortcut()
Actually remove the shortcut that the user wanted to steal, from the action that was using it...
Definition: kkeysequencewidget.cpp:398
KAction::setShortcut
void setShortcut(const KShortcut &shortcut, ShortcutTypes type=ShortcutTypes(ActiveShortcut|DefaultShortcut))
Set the shortcut for this action.
Definition: kaction.cpp:198
kaction.h
QSet
KKeySequenceWidget::StandardShortcuts
Check against standard shortcuts.
Definition: kkeysequencewidget.h:102
KGlobalShortcutInfo::friendlyName
QString friendlyName
Definition: kglobalshortcutinfo.h:42
KKeySequenceWidget::setCheckActionCollections
void setCheckActionCollections(const QList< KActionCollection * > &actionCollections)
Set a list of action collections to check against for conflictuous shortcut.
Definition: kkeysequencewidget.cpp:358
KKeySequenceWidget::setCheckActionList
void setCheckActionList(const QList< QAction * > &checkList)
Definition: kkeysequencewidget.cpp:351
KGlobal::locale
KLocale * locale()
KLocale::removeAcceleratorMarker
QString removeAcceleratorMarker(const QString &label) const
KGlobalAccel::getGlobalShortcutsByKey
static QList< KGlobalShortcutInfo > getGlobalShortcutsByKey(const QKeySequence &seq)
Returns a list of global shortcuts registered for the shortcut .
Definition: kglobalaccel.cpp:520
KKeySequenceWidget::KKeySequenceWidget
KKeySequenceWidget(QWidget *parent=0)
Constructor.
Definition: kkeysequencewidget.cpp:251
KAction::ActiveShortcut
The shortcut will immediately become active but may be reset to "default".
Definition: kaction.h:235
KKeySequenceWidget::multiKeyShortcutsAllowed
bool multiKeyShortcutsAllowed() const
KAction
Class to encapsulate user-driven action or event.
Definition: kaction.h:216
KKeySequenceWidget::keySequence
QKeySequence keySequence() const
Return the currently selected key sequence.
Definition: kkeysequencewidget.cpp:370
kkeysequencewidget.h
KKeySequenceWidget::setClearButtonShown
void setClearButtonShown(bool show)
Set whether a small button to set an empty key sequence should be displayed next to the main input wi...
Definition: kkeysequencewidget.cpp:345
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KAction::isShortcutConfigurable
bool isShortcutConfigurable() const
Returns true if this action's shortcut is configurable.
Definition: kaction.cpp:173
KKeySequenceWidget::setCheckForConflictsAgainst
void setCheckForConflictsAgainst(ShortcutTypes types)
Configure if the widget should check for conflicts with existing shortcuts.
Definition: kkeysequencewidget.cpp:318
KStandardShortcut::AccelNone
Definition: kstandardshortcut.h:58
kglobalaccel.h
KKeySequenceWidget::isKeySequenceAvailable
bool isKeySequenceAvailable(const QKeySequence &seq) const
Checks whether the key sequence seq is available to grab.
Definition: kkeysequencewidget.cpp:329
QToolButton
kicon.h
kmessagebox.h
KKeySequenceWidget::Validate
Validate key sequence.
Definition: kkeysequencewidget.h:77
KGlobalAccel::stealShortcutSystemwide
static void stealShortcutSystemwide(const QKeySequence &seq)
Take away the given shortcut from the named action it belongs to.
Definition: kglobalaccel.cpp:593
KShortcut::toString
QString toString() const
Returns a description of the shortcut as a semicolon-separated list of key sequences, as returned by QKeySequence::toString().
Definition: kshortcut.cpp:249
KGlobalAccel::isGlobalShortcutAvailable
static bool isGlobalShortcutAvailable(const QKeySequence &seq, const QString &component=QString())
Check if the shortcut is available for the component.
Definition: kglobalaccel.cpp:526
KMessageBox::warningContinueCancel
static int warningContinueCancel(QWidget *parent, const QString &text, const QString &caption=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
Display a "warning" dialog.
Definition: kmessagebox.cpp:644
QAction
QList
KKeyServer::modToStringUser
QString modToStringUser(uint mod)
Converts the mask of ORed KKey::ModFlag modifiers to a user-readable string.
Definition: kkeyserver.cpp:98
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:49:14 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal