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

KDEUI

  • 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
44class KKeySequenceWidgetPrivate
45{
46public:
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
193KKeySequenceWidgetPrivate::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
209bool 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
241void 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
251KKeySequenceWidget::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
268void 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
289KKeySequenceWidget::~KKeySequenceWidget ()
290{
291 delete d;
292}
293
294
295KKeySequenceWidget::ShortcutTypes KKeySequenceWidget::checkForConflictsAgainst() const
296{
297 return d->checkAgainstShortcutTypes;
298}
299
300
301void KKeySequenceWidget::setComponentName(const QString &componentName)
302{
303 d->componentName = componentName;
304}
305
306bool KKeySequenceWidget::multiKeyShortcutsAllowed() const
307{
308 return d->multiKeyShortcutsAllowed;
309}
310
311
312void KKeySequenceWidget::setMultiKeyShortcutsAllowed(bool allowed)
313{
314 d->multiKeyShortcutsAllowed = allowed;
315}
316
317
318void KKeySequenceWidget::setCheckForConflictsAgainst(ShortcutTypes types)
319{
320 d->checkAgainstShortcutTypes = types;
321}
322
323void KKeySequenceWidget::setModifierlessAllowed(bool allow)
324{
325 d->allowModifierless = allow;
326}
327
328
329bool 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
339bool KKeySequenceWidget::isModifierlessAllowed()
340{
341 return d->allowModifierless;
342}
343
344
345void KKeySequenceWidget::setClearButtonShown(bool show)
346{
347 d->clearButton->setVisible(show);
348}
349
350#ifndef KDE_NO_DEPRECATED
351void 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
358void KKeySequenceWidget::setCheckActionCollections(const QList<KActionCollection *>& actionCollections)
359{
360 d->checkActionCollections = actionCollections;
361}
362
363//slot
364void KKeySequenceWidget::captureKeySequence()
365{
366 d->startRecording();
367}
368
369
370QKeySequence KKeySequenceWidget::keySequence() const
371{
372 return d->keySequence;
373}
374
375
376//slot
377void 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
392void KKeySequenceWidget::clearKeySequence()
393{
394 setKeySequence(QKeySequence());
395}
396
397//slot
398void 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
430void KKeySequenceButton::setText(const QString &text)
431{
432 QPushButton::setText(text);
433 //setFixedSize( sizeHint().width()+12, sizeHint().height()+8 );
434}
435
436
437void 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
455void 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
480bool 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
527bool 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
610bool 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
624bool 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
639void 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
675KKeySequenceButton::~KKeySequenceButton()
676{
677}
678
679
680//prevent Qt from special casing Tab and Backtab
681bool 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
701void 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
786void 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
810QKeySequence 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
828bool 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"
KActionCollection
A container for a set of QAction objects.
Definition: kactioncollection.h:57
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
KActionCollection::actions
QList< QAction * > actions() const
Returns the list of KActions which belong to this action collection.
Definition: kactioncollection.cpp:186
KAction
Class to encapsulate user-driven action or event.
Definition: kaction.h:217
KAction::shortcut
KShortcut shortcut
Definition: kaction.h:220
KAction::isShortcutConfigurable
bool isShortcutConfigurable() const
Returns true if this action's shortcut is configurable.
Definition: kaction.cpp:173
KAction::ActiveShortcut
@ ActiveShortcut
The shortcut will immediately become active but may be reset to "default".
Definition: kaction.h:235
KAction::setShortcut
void setShortcut(const KShortcut &shortcut, ShortcutTypes type=ShortcutTypes(ActiveShortcut|DefaultShortcut))
Set the shortcut for this action.
Definition: kaction.cpp:198
KGlobalAccel::getGlobalShortcutsByKey
static QList< KGlobalShortcutInfo > getGlobalShortcutsByKey(const QKeySequence &seq)
Returns a list of global shortcuts registered for the shortcut @seq.
Definition: kglobalaccel.cpp:520
KGlobalAccel::stealShortcutSystemwide
static void stealShortcutSystemwide(const QKeySequence &seq)
Take away the given shortcut from the named action it belongs to.
Definition: kglobalaccel.cpp:593
KGlobalAccel::isGlobalShortcutAvailable
static bool isGlobalShortcutAvailable(const QKeySequence &seq, const QString &component=QString())
Check if the shortcut @seq is available for the component.
Definition: kglobalaccel.cpp:526
KGlobalShortcutInfo
Definition: kglobalshortcutinfo.h:36
KGlobalShortcutInfo::friendlyName
Q_SCRIPTABLEQString friendlyName
Definition: kglobalshortcutinfo.h:42
KGlobalShortcutInfo::componentFriendlyName
Q_SCRIPTABLEQString componentFriendlyName
Definition: kglobalshortcutinfo.h:45
KGuiItem
An abstract class for GUI data such as ToolTip and Icon.
Definition: kguiitem.h:37
KIcon
A wrapper around QIcon that provides KDE icon features.
Definition: kicon.h:41
KKeySequenceWidget
A widget to input a QKeySequence.
Definition: kkeysequencewidget.h:52
KKeySequenceWidget::setModifierlessAllowed
void setModifierlessAllowed(bool allow)
This only applies to user input, not to setShortcut().
Definition: kkeysequencewidget.cpp:323
KKeySequenceWidget::GlobalShortcuts
@ GlobalShortcuts
Check against global shortcuts.
Definition: kkeysequencewidget.h:103
KKeySequenceWidget::StandardShortcuts
@ StandardShortcuts
Check against standard shortcuts.
Definition: kkeysequencewidget.h:102
KKeySequenceWidget::LocalShortcuts
@ LocalShortcuts
Check with local shortcuts.
Definition: kkeysequencewidget.h:101
KKeySequenceWidget::clearKeySequence
void clearKeySequence()
Clear the key sequence.
Definition: kkeysequencewidget.cpp:392
KKeySequenceWidget::isKeySequenceAvailable
bool isKeySequenceAvailable(const QKeySequence &seq) const
Checks whether the key sequence seq is available to grab.
Definition: kkeysequencewidget.cpp:329
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
KKeySequenceWidget::~KKeySequenceWidget
virtual ~KKeySequenceWidget()
Destructs the widget.
Definition: kkeysequencewidget.cpp:289
KKeySequenceWidget::setMultiKeyShortcutsAllowed
void setMultiKeyShortcutsAllowed(bool)
Allow multikey shortcuts?
Definition: kkeysequencewidget.cpp:312
KKeySequenceWidget::setCheckActionList
void setCheckActionList(const QList< QAction * > &checkList)
Definition: kkeysequencewidget.cpp:351
KKeySequenceWidget::isModifierlessAllowed
bool isModifierlessAllowed()
Definition: kkeysequencewidget.cpp:339
KKeySequenceWidget::multiKeyShortcutsAllowed
bool multiKeyShortcutsAllowed
Definition: kkeysequencewidget.h:60
KKeySequenceWidget::checkForConflictsAgainst
ShortcutTypes checkForConflictsAgainst
Definition: kkeysequencewidget.h:65
KKeySequenceWidget::keySequence
QKeySequence keySequence() const
Return the currently selected key sequence.
Definition: kkeysequencewidget.cpp:370
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
KKeySequenceWidget::captureKeySequence
void captureKeySequence()
Capture a shortcut from the keyboard.
Definition: kkeysequencewidget.cpp:364
KKeySequenceWidget::KKeySequenceWidget
KKeySequenceWidget(QWidget *parent=0)
Constructor.
Definition: kkeysequencewidget.cpp:251
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
KKeySequenceWidget::setKeySequence
void setKeySequence(const QKeySequence &seq, Validation val=NoValidate)
Set the key sequence.
Definition: kkeysequencewidget.cpp:377
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::Validation
Validation
An enum about validation when setting a key sequence.
Definition: kkeysequencewidget.h:75
KKeySequenceWidget::Validate
@ Validate
Validate key sequence.
Definition: kkeysequencewidget.h:77
KKeySequenceWidget::setCheckForConflictsAgainst
void setCheckForConflictsAgainst(ShortcutTypes types)
Configure if the widget should check for conflicts with existing shortcuts.
Definition: kkeysequencewidget.cpp:318
KLocale::removeAcceleratorMarker
QString removeAcceleratorMarker(const QString &label) const
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
KMessageBox::Continue
@ Continue
Definition: kmessagebox.h:74
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
KShortcut
Represents a keyboard shortcut.
Definition: kshortcut.h:58
KShortcut::toString
QString toString() const
Returns a description of the shortcut as a semicolon-separated list of key sequences,...
Definition: kshortcut.cpp:249
KShortcut::conflictsWith
bool conflictsWith(const QKeySequence &needle) const
Returns whether at least one of the key sequences conflicts witho needle.
Definition: kshortcut.cpp:156
QAction
QHash
QList
QSet
QToolButton
QWidget
kWarning
#define kWarning
kaction.h
kactioncollection.h
kdebug.h
kglobalaccel.h
kicon.h
timeout
int timeout
kkeysequencewidget.h
kkeyserver.h
klocale.h
i18n
QString i18n(const char *text)
i18nc
QString i18nc(const char *ctxt, const char *text)
i18ncp
QString i18ncp(const char *ctxt, const char *sing, const char *plur, const A1 &a1)
kmessagebox.h
kshortcut.h
Defines platform-independent classes for keyboard shortcut handling.
SHIFT
#define SHIFT(x)
Definition: kstandardshortcut.cpp:71
KGlobal::locale
KLocale * locale()
KKeyServer::modToStringUser
QString modToStringUser(uint mod)
Converts the mask of ORed KKey::ModFlag modifiers to a user-readable string.
Definition: kkeyserver.cpp:98
KKeyServer::isShiftAsModifierAllowed
bool isShiftAsModifierAllowed(int keyQt)
Test if the shift modifier should be recorded for a given key.
Definition: kkeyserver.cpp:113
message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
KStandardShortcut::label
QString label(StandardShortcut id)
Returns a localized label for user-visible display.
Definition: kstandardshortcut.cpp:267
KStandardShortcut::find
const KShortcut & find()
Find, search.
Definition: kstandardshortcut.cpp:342
KStandardShortcut::StandardShortcut
StandardShortcut
Defines the identifier of all standard accelerators.
Definition: kstandardshortcut.h:55
KStandardShortcut::AccelNone
@ AccelNone
Definition: kstandardshortcut.h:58
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 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
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
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