KDeclarative

keysequencevalidator.cpp
1/*
2 SPDX-FileCopyrightText: 2024 Arjen Hiemstra <ahiemstra@heimr.nl>
3 SPDX-FileCopyrightText: 2020 David Redondo <davidedmundson@kde.org>
4 SPDX-FileCopyrightText: 2014 David Edmundson <davidedmundson@kde.org>
5 SPDX-FileCopyrightText: 1998 Mark Donohoe <donohoe@kde.org>
6 SPDX-FileCopyrightText: 2001 Ellis Whitehead <ellis@kde.org>
7 SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
8
9 SPDX-License-Identifier: LGPL-2.1-or-later
10*/
11
12#include "keysequencevalidator.h"
13
14#include <KLocalizedString>
15#include <KStandardShortcut>
16
17#include <config-kdeclarative.h>
18#if HAVE_KGLOBALACCEL
19#include <KGlobalAccel>
20#include <KGlobalShortcutInfo>
21#endif
22
23KeySequenceValidator::KeySequenceValidator(QObject *parent)
24 : QObject(parent)
25{
26}
27
28QKeySequence KeySequenceValidator::currentKeySequence() const
29{
30 return m_currentKeySequence;
31}
32
33void KeySequenceValidator::setCurrentKeySequence(const QKeySequence &sequence)
34{
35 if (m_currentKeySequence == sequence) {
36 return;
37 }
38
39 m_currentKeySequence = sequence;
40 Q_EMIT currentKeySequenceChanged();
41}
42
43KeySequenceHelper::ShortcutTypes KeySequenceValidator::validateTypes() const
44{
45 return m_validateTypes;
46}
47
48void KeySequenceValidator::setValidateTypes(KeySequenceHelper::ShortcutTypes types)
49{
50 if (m_validateTypes == types) {
51 return;
52 }
53
54 m_validateTypes = types;
55 Q_EMIT validateTypesChanged();
56}
57
58void KeySequenceValidator::validateSequence(const QKeySequence &keySequence)
59{
60 ValidationResult result = ValidationResult::Accept;
61 if (m_validateTypes & KeySequenceHelper::GlobalShortcuts) {
62 result = validateGlobalShortcut(keySequence);
63 }
64
65 if (result == ValidationResult::Reject) {
66 Q_EMIT finished(m_currentKeySequence);
67 return;
68 }
69
70 if (result == ValidationResult::QuestionPending) {
71 return;
72 }
73
74 if (m_validateTypes & KeySequenceHelper::StandardShortcuts) {
75 result = validateStandardShortcut(keySequence);
76 }
77
78 if (result == ValidationResult::Reject) {
79 Q_EMIT finished(m_currentKeySequence);
80 } else if (result == ValidationResult::Accept) {
81 Q_EMIT finished(keySequence);
82 }
83}
84
85void KeySequenceValidator::accept()
86{
87 QKeySequence keySequence = m_pendingKeySequence;
88 m_pendingKeySequence = QKeySequence{};
89
90 ValidationResult result = ValidationResult::Accept;
91 if (m_validateGlobalPending) {
92 m_validateGlobalPending = false;
93 if (m_validateTypes & KeySequenceHelper::StandardShortcuts) {
94 result = validateStandardShortcut(keySequence);
95 }
96 }
97
98 if (result == ValidationResult::Reject) {
99 Q_EMIT finished(m_currentKeySequence);
100 } else if (result == ValidationResult::Accept) {
101 Q_EMIT finished(keySequence);
102 }
103}
104
105void KeySequenceValidator::reject()
106{
107 m_pendingKeySequence = QKeySequence{};
108 Q_EMIT finished(m_currentKeySequence);
109}
110
111KeySequenceValidator::ValidationResult KeySequenceValidator::validateGlobalShortcut(const QKeySequence &keySequence)
112{
113#ifdef Q_OS_WIN
114 // on windows F12 is reserved by the debugger at all times, so we can't use it for a global shortcut
115 if (keySequence.toString().contains(QLatin1String("F12"))) {
116 QString title = i18n("Reserved Shortcut");
117 QString message = i18n(
118 "The F12 key is reserved on Windows, so cannot be used for a global shortcut.\n"
119 "Please choose another one.");
120
121 Q_EMIT error(title, message);
122 return ValidationResult::Reject;
123 } else {
124 return ValidationResult::Accept;
125 }
126#elif HAVE_KGLOBALACCEL
127 // Global shortcuts are on key+modifier shortcuts. They can clash with a multi key shortcut.
132 others << KGlobalAccel::globalShortcutsByKey(keySequence);
133
134 // look for shortcuts shadowing
135 shadow << KGlobalAccel::globalShortcutsByKey(keySequence, KGlobalAccel::MatchType::Shadows);
136 shadowed << KGlobalAccel::globalShortcutsByKey(keySequence, KGlobalAccel::MatchType::Shadowed);
137 }
138
139 if (!shadow.isEmpty() || !shadowed.isEmpty()) {
140 QString title = i18n("Global Shortcut Shadowing");
141 QString message;
142 if (!shadowed.isEmpty()) {
143 message += i18n("The '%1' key combination is shadowed by following global actions:\n").arg(keySequence.toString());
144 for (const KGlobalShortcutInfo &info : std::as_const(shadowed)) {
145 message += i18n("Action '%1' in context '%2'\n").arg(info.friendlyName(), info.contextFriendlyName());
146 }
147 }
148 if (!shadow.isEmpty()) {
149 message += i18n("The '%1' key combination shadows following global actions:\n").arg(keySequence.toString());
150 for (const KGlobalShortcutInfo &info : std::as_const(shadow)) {
151 message += i18n("Action '%1' in context '%2'\n").arg(info.friendlyName(), info.contextFriendlyName());
152 }
153 }
154
155 Q_EMIT error(title, message);
156 return ValidationResult::Reject;
157 }
158
159 if (!others.isEmpty()) {
160 QString title = i18nc("@dialog:title", "Found Conflict");
161 QString message;
162
163 if (others.size() == 1) {
164 auto info = others.at(0);
165 message = i18n("Shortcut '%1' is already assigned to action '%2' of %3.\nDo you want to reassign it?",
166 keySequence.toString(),
167 info.friendlyName(),
168 info.componentFriendlyName());
169 } else {
170 message = i18n("Shortcut '%1' is already assigned to the following actions:\n");
171 for (const auto &info : std::as_const(others)) {
172 message += i18n("Action '%1' of %2\n", info.friendlyName(), info.componentFriendlyName());
173 }
174 message += i18n("Do you want to reassign it?");
175 }
176
177 m_pendingKeySequence = keySequence;
178 m_validateGlobalPending = true;
179 Q_EMIT question(title, message);
180 return ValidationResult::QuestionPending;
181 }
182#endif
183 return ValidationResult::Accept;
184}
185
186KeySequenceValidator::ValidationResult KeySequenceValidator::validateStandardShortcut(const QKeySequence &keySequence)
187{
189 if (ssc != KStandardShortcut::AccelNone) {
190 QString title = i18n("Conflict with Standard Application Shortcut");
191 QString message = i18n(
192 "The '%1' key combination is also used for the standard action "
193 "\"%2\" that some applications use.\n"
194 "Do you really want to use it as a global shortcut as well?",
197
198 m_pendingKeySequence = keySequence;
199 Q_EMIT question(title, message);
200 return ValidationResult::QuestionPending;
201 } else {
202 return ValidationResult::Accept;
203 }
204}
205
206#include "moc_keysequencevalidator.cpp"
static QList< KGlobalShortcutInfo > globalShortcutsByKey(const QKeySequence &seq, MatchType type=Equal)
static bool isGlobalShortcutAvailable(const QKeySequence &seq, const QString &component=QString())
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
const QList< QKeySequence > & find()
QString label(StandardShortcut id)
const_reference at(qsizetype i) const const
bool isEmpty() const const
qsizetype size() const const
Q_EMITQ_EMIT
QString arg(Args &&... args) const const
void keySequence(QWidget *widget, const QKeySequence &keySequence)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:56:17 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.