1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: Mark Donohoe <donohoe@kde.org>
4 SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org>
5 SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#ifndef KKEYSEQUENCEWIDGET_H
11#define KKEYSEQUENCEWIDGET_H
12
13#include <kxmlgui_export.h>
14
15#include <KKeySequenceRecorder>
16
17#include <QList>
18#include <QPushButton>
19
20class KKeySequenceWidgetPrivate;
21class QAction;
22class KActionCollection;
23
24/*!
25 * \class KKeySequenceWidget
26 * \inmodule KXmlGui
27 *
28 * \brief A widget to input a QKeySequence.
29 *
30 * This widget lets the user choose a QKeySequence, which is usually used as a
31 * shortcut key. The recording is initiated by calling captureKeySequence() or
32 * by the user clicking on the widget.
33 *
34 * The widgets provides support for conflict handling.
35 *
36 * \image kkeysequencewidget.png "KKeySequenceWidget"
37 *
38 * \sa setCheckForConflictsAgainst()
39 */
40class KXMLGUI_EXPORT KKeySequenceWidget : public QWidget
41{
42 Q_OBJECT
43
44 /*!
45 * \property KKeySequenceWidget::keySequence
46 */
47 Q_PROPERTY(QKeySequence keySequence READ keySequence WRITE setKeySequence NOTIFY keySequenceChanged)
48
49 /*!
50 * \property KKeySequenceWidget::multiKeyShortcutsAllowed
51 */
52 Q_PROPERTY(bool multiKeyShortcutsAllowed READ multiKeyShortcutsAllowed WRITE setMultiKeyShortcutsAllowed)
53
54 /*!
55 * \property KKeySequenceWidget::checkForConflictsAgainst
56 */
57 Q_PROPERTY(ShortcutTypes checkForConflictsAgainst READ checkForConflictsAgainst WRITE setCheckForConflictsAgainst)
58
59 /*!
60 * \property KKeySequenceWidget::modifierlessAllowed
61 * \deprecated[6.12]
62 * Use the patterns property
63 */
64 Q_PROPERTY(bool modifierlessAllowed READ isModifierlessAllowed WRITE setModifierlessAllowed)
65
66 /*!
67 * \property KKeySequenceWidget::modifierOnlyAllowed
68 */
69 Q_PROPERTY(bool modifierOnlyAllowed READ modifierOnlyAllowed WRITE setModifierOnlyAllowed)
70
71 /*!
72 * \property KKeySequenceWidget::recording
73 * Indicates whether a key sequence is currently being recorded.
74 *
75 * \since 6.12
76 */
77 Q_PROPERTY(bool recording READ isRecording NOTIFY recordingChanged)
78
79 /*!
80 * \property KKeySequenceWidget::patterns
81 * Specifies the accepted shortcut formats.
82 *
83 * Default is KKeySequenceRecorder::ModifierAndKey.
84 *
85 * \since 6.12
86 */
87 Q_PROPERTY(KKeySequenceRecorder::Patterns patterns READ patterns WRITE setPatterns)
88
89public:
90 /*!
91 * \enum KKeySequenceWidget::Validation
92 *
93 * An enum about validation when setting a key sequence.
94 *
95 * \sa setKeySequence()
96 *
97 * \value Validate
98 * Validate key sequence.
99 * \value NoValidate
100 * Use key sequence without validation.
101 */
102 enum Validation {
103 Validate = 0,
104 NoValidate = 1,
105 };
106
107 /*!
108 * \brief Constructs a widget used to input a QKeySequence.
109 */
110 explicit KKeySequenceWidget(QWidget *parent = nullptr);
111
112 ~KKeySequenceWidget() override;
113
114 /*!
115 * \enum KKeySequenceWidget::ShortcutType
116 *
117 * \value None
118 * No checking for conflicts.
119 * \value LocalShortcuts
120 * Check with local shortcuts.
121 * \sa setCheckActionCollections()
122 * \value StandardShortcuts
123 * Check against standard shortcuts.
124 * \sa KStandardShortcut
125 * \value GlobalShortcuts
126 * Check against global shortcuts.
127 * \sa KGlobalAccel
128 */
129 enum ShortcutType {
130 None = 0x00,
131 LocalShortcuts = 0x01,
132 StandardShortcuts = 0x02,
133 GlobalShortcuts = 0x04,
134 };
135 Q_DECLARE_FLAGS(ShortcutTypes, ShortcutType)
136 Q_FLAG(ShortcutTypes)
137
138 /*!
139 * \brief Configure if the widget should check for conflicts with existing
140 * shortcut \a types.
141 *
142 * When capturing a key sequence for local shortcuts you should check
143 * against GlobalShortcuts and your other local shortcuts. This is the
144 * default.
145 *
146 * You have to provide the local actions to check against with
147 * setCheckActionCollections().
148 *
149 * When capturing a key sequence for a global shortcut you should
150 * check against StandardShortcuts, GlobalShortcuts and your local
151 * shortcuts.
152 *
153 * There are two ways to react to a user agreeing to steal a shortcut:
154 *
155 * 1. Listen to the stealShortcut() signal and steal the shortcuts
156 * manually. It's your responsibility to save that change later when
157 * you think it is appropriate.
158 *
159 * 2. Call applyStealShortcut() and KKeySequenceWidget will steal the
160 * shortcut. This will save the actionCollections the shortcut is part
161 * of so make sure it doesn't inadvertly save some unwanted changes
162 * too. Read its documentation for some limitation when handling
163 * global shortcuts.
164 *
165 * If you want to do the conflict checking yourself here are some code
166 * snippets for global ...
167 *
168 * \code
169 * QStringList conflicting = KGlobalAccel::findActionNameSystemwide(keySequence);
170 * if (!conflicting.isEmpty()) {
171 * // Inform and ask the user about the conflict and reassigning
172 * // the keys sequence
173 * if (!KGlobalAccel::promptStealShortcutSystemwide(q, conflicting, keySequence)) {
174 * return true;
175 * }
176 * KGlobalAccel::stealShortcutSystemwide(keySequence);
177 * }
178 * \endcode
179 *
180 * ... and standard shortcuts
181 *
182 * \code
183 * KStandardShortcut::StandardShortcut ssc = KStandardShortcut::find(keySequence);
184 * if (ssc != KStandardShortcut::AccelNone) {
185 * // We have a conflict
186 * }
187 * \endcode
188 *
189 * \since 4.2
190 */
191 void setCheckForConflictsAgainst(ShortcutTypes types);
192
193 /*!
194 * \brief The shortcut types we check for conflicts.
195 *
196 * \sa setCheckForConflictsAgainst()
197 * \since 4.2
198 */
199 ShortcutTypes checkForConflictsAgainst() const;
200
201 /*!
202 * \brief Sets whether to allow for multikey shortcuts.
203 */
204 void setMultiKeyShortcutsAllowed(bool);
205
206 /*!
207 * \brief Returns whether multikey shortcuts are allowed.
208 */
209 bool multiKeyShortcutsAllowed() const;
210
211#if KXMLGUI_ENABLE_DEPRECATED_SINCE(6, 12)
212 /*!
213 * \brief Sets whether to \a allow "plain" keys without modifiers
214 * (like Ctrl, Alt, Meta).
215 *
216 * This only applies to user input, not to setKeySequence().
217 *
218 * Plain keys by our definition include letter and symbol keys and
219 * text editing keys (Return, Space, Tab, Backspace, Delete).
220 *
221 * "Special" keys like F1, Cursor keys, Insert, PageDown will always work.
222 *
223 * \deprecated[6.12]
224 * Use setPatterns() instead
225 */
226 KXMLGUI_DEPRECATED_VERSION(6, 12, "Use setPatterns()") void setModifierlessAllowed(bool allow);
227
228 /*!
229 * \sa setModifierlessAllowed()
230 *
231 * \deprecated[6.12]
232 * Use patterns() instead
233 * \brief Returns whether "plain" keys without modifiers
234 * (like Ctrl, Alt, Meta) are allowed.
235 * \sa setModifierlessAllowed()
236 */
237 KXMLGUI_DEPRECATED_VERSION(6, 12, "Use patterns()") bool isModifierlessAllowed();
238
239 /*!
240 * Whether to allow modifier-only key sequences.
241 * \since 6.1
242 * \deprecated[6.12]
243 * Use setPatterns() instead
244 */
245 KXMLGUI_DEPRECATED_VERSION(6, 12, "Use setPatterns()") void setModifierOnlyAllowed(bool allow);
246
247 /*!
248 * \deprecated[6.12] Use patterns() instead
249 */
250 KXMLGUI_DEPRECATED_VERSION(6, 12, "Use patterns()") bool modifierOnlyAllowed() const;
251#endif
252
253 /*!
254 * \brief Sets whether to \a show a small button to set an empty key sequence
255 * next to the main input widget.
256 *
257 * The default is to show the clear button.
258 */
259 void setClearButtonShown(bool show);
260
261 /*!
262 * \brief Returns whether the key sequence \a seq is available to grab.
263 *
264 * The sequence is checked under the same rules as if it has been typed by
265 * the user. This method is useful if you get key sequences from another
266 * input source and want to check if it is save to set them.
267 *
268 * \since 4.2
269 */
270 bool isKeySequenceAvailable(const QKeySequence &seq) const;
271
272 /*!
273 * \brief Returns the currently selected key sequence.
274 * \since 5.65
275 */
276 QKeySequence keySequence() const;
277
278 /*!
279 * \brief Sets a list of \a actionCollections to check against for conflictuous shortcut.
280 *
281 *
282 * If a QAction with a conflicting shortcut is found inside this list and
283 * its shortcut can be configured (KActionCollection::isShortcutConfigurable()
284 * returns true) the user will be prompted whether to steal the shortcut
285 * from this action.
286 *
287 * \sa setCheckForConflictsAgainst()
288 * \since 4.1
289 */
290 void setCheckActionCollections(const QList<KActionCollection *> &actionCollections);
291
292 /*!
293 * \brief Sets the \a componentName for the component using this widget.
294 *
295 * If the component using this widget supports shortcuts contexts,
296 * it must set its component name so we can check conflicts correctly.
297 */
298 void setComponentName(const QString &componentName);
299
300 /*!
301 * Returns \c true if a key sequence is currently being recorded; otherwise returns \c false.
302 *
303 * \since 6.12
304 */
305 bool isRecording() const;
306
307 /*!
308 * Sets the accepted shortcut patterns to \a patterns. A shortcut pattern specifies what
309 * components the recoreded shortcut must have, e.g. whether it should include modifier keys, etc.
310 *
311 * \since 6.12
312 */
313 void setPatterns(KKeySequenceRecorder::Patterns patterns);
314
315 /*!
316 * Returns the accepted shortcut patterns.
317 *
318 * Default is Modifier | Key
319 *
320 * \since 6.12
321 */
322 KKeySequenceRecorder::Patterns patterns() const;
323
324Q_SIGNALS:
325
326 /*!
327 * \brief This signal is emitted when the current key sequence \a seq has changed,
328 * be it by user input or programmatically.
329 * \since 5.65
330 */
331 void keySequenceChanged(const QKeySequence &seq);
332
333 /*!
334 * \brief This signal is emitted after the user agreed to steal a shortcut
335 * sequence \a seq from an \a action.
336 *
337 * This is only done for local shortcuts. So you can be sure
338 * \a action is one of the actions you provided with setCheckActionList() or
339 * setCheckActionCollections().
340 *
341 * If you listen to that signal and don't call applyStealShortcut() you
342 * are supposed to steal the shortcut and save this change.
343 */
344 void stealShortcut(const QKeySequence &seq, QAction *action);
345
346 /*!
347 * This signal is emitted when the user begins or finishes recording a key sequence. It
348 * is not emitted when the current key sequence is changed using setKeySequence().
349 *
350 * \since 6.12
351 */
352 void recordingChanged();
353
354public Q_SLOTS:
355
356 /*!
357 * \brief Capture a shortcut from the keyboard.
358 *
359 * This call will only return once a key sequence has been captured
360 * or input was aborted.
361 *
362 * If a key sequence was input, keySequenceChanged() will be emitted.
363 *
364 * \sa setModifierlessAllowed()
365 */
366 void captureKeySequence();
367
368 /*!
369 * \brief Sets the key sequence \a seq.
370 *
371 * If \a val == Validate, and the call is actually changing the key sequence,
372 * conflictuous shortcut will be checked.
373 *
374 * \since 5.65
375 */
376 void setKeySequence(const QKeySequence &seq, Validation val = NoValidate);
377
378 /*!
379 * \brief Clears the key sequence.
380 */
381 void clearKeySequence();
382
383 /*!
384 * \brief Actually remove the shortcut that the user wanted to steal, from the
385 * action that was using it.
386 *
387 * This only applies to actions provided to us
388 * by setCheckActionCollections() and setCheckActionList().
389 *
390 * Global and Standard Shortcuts have to be stolen immediately when the
391 * user gives their consent (technical reasons). That means those changes
392 * will be active even if you never call applyStealShortcut().
393 *
394 * To be called before you apply your changes. No local shortcuts are
395 * stolen until this function is called.
396 */
397 void applyStealShortcut();
398
399private:
400 friend class KKeySequenceWidgetPrivate;
401 KKeySequenceWidgetPrivate *const d;
402
403 bool event(QEvent *ev) override;
404
405 Q_DISABLE_COPY(KKeySequenceWidget)
406};
407
408Q_DECLARE_OPERATORS_FOR_FLAGS(KKeySequenceWidget::ShortcutTypes)
409
410#endif // KKEYSEQUENCEWIDGET_H
411

source code of kxmlgui/src/kkeysequencewidget.h