1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org>
4 SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#ifndef KKEYSEQUENCEWIDGET_H
10#define KKEYSEQUENCEWIDGET_H
11
12#include <kxmlgui_export.h>
13
14#include <QList>
15#include <QPushButton>
16
17class KKeySequenceWidgetPrivate;
18class QAction;
19class KActionCollection;
20
21/**
22 * @class KKeySequenceWidget kkeysequencewidget.h KKeySequenceWidget
23 *
24 * @short A widget to input a QKeySequence.
25 *
26 * This widget lets the user choose a QKeySequence, which is usually used as a
27 * shortcut key. The recording is initiated by calling captureKeySequence() or
28 * the user clicking into the widget.
29 *
30 * The widgets provides support for conflict handling. See
31 * setCheckForConflictsAgainst() for more information.
32 *
33 * \image html kkeysequencewidget.png "KKeySequenceWidget"
34 *
35 * @author Mark Donohoe <donohoe@kde.org>
36 */
37class KXMLGUI_EXPORT KKeySequenceWidget : public QWidget
38{
39 Q_OBJECT
40
41 /// @since 5.65
42 Q_PROPERTY(QKeySequence keySequence READ keySequence WRITE setKeySequence NOTIFY keySequenceChanged)
43
44 Q_PROPERTY(bool multiKeyShortcutsAllowed READ multiKeyShortcutsAllowed WRITE setMultiKeyShortcutsAllowed)
45
46 Q_PROPERTY(ShortcutTypes checkForConflictsAgainst READ checkForConflictsAgainst WRITE setCheckForConflictsAgainst)
47
48 Q_PROPERTY(bool modifierlessAllowed READ isModifierlessAllowed WRITE setModifierlessAllowed)
49
50 /// @since 6.1
51 Q_PROPERTY(bool modifierOnlyAllowed READ modifierOnlyAllowed WRITE setModifierOnlyAllowed)
52
53public:
54 /// An enum about validation when setting a key sequence.
55 ///@see setKeySequence()
56 enum Validation {
57 /// Validate key sequence
58 Validate = 0,
59 /// Use key sequence without validation
60 NoValidate = 1,
61 };
62
63 /**
64 * Constructor.
65 */
66 explicit KKeySequenceWidget(QWidget *parent = nullptr);
67
68 /**
69 * Destructs the widget.
70 */
71 ~KKeySequenceWidget() override;
72
73 /**
74 * \name Configuration
75 *
76 * Configuration options for the widget.
77 * @see ShortcutTypes
78 */
79 //@{
80
81 enum ShortcutType {
82 None = 0x00, //!< No checking for conflicts
83 LocalShortcuts = 0x01, //!< Check with local shortcuts. @see setCheckActionCollections()
84 StandardShortcuts = 0x02, //!< Check against standard shortcuts. @see KStandardShortcut
85 GlobalShortcuts = 0x04, //!< Check against global shortcuts. @see KGlobalAccel
86 };
87 /**
88 * Stores a combination of #ShortcutType values.
89 */
90 Q_DECLARE_FLAGS(ShortcutTypes, ShortcutType)
91 Q_FLAG(ShortcutTypes)
92
93 /**
94 * Configure if the widget should check for conflicts with existing
95 * shortcuts.
96 *
97 * When capturing a key sequence for local shortcuts you should check
98 * against GlobalShortcuts and your other local shortcuts. This is the
99 * default.
100 *
101 * You have to provide the local actions to check against with
102 * setCheckActionCollections().
103 *
104 * When capturing a key sequence for a global shortcut you should
105 * check against StandardShortcuts, GlobalShortcuts and your local
106 * shortcuts.
107 *
108 * There are two ways to react to a user agreeing to steal a shortcut:
109 *
110 * 1. Listen to the stealShortcut() signal and steal the shortcuts
111 * manually. It's your responsibility to save that change later when
112 * you think it is appropriate.
113 *
114 * 2. Call applyStealShortcut() and KKeySequenceWidget will steal the
115 * shortcut. This will save the actionCollections the shortcut is part
116 * of so make sure it doesn't inadvertly save some unwanted changes
117 * too. Read its documentation for some limitation when handling
118 * global shortcuts.
119 *
120 * If you want to do the conflict checking yourself here are some code
121 * snippets for global ...
122 *
123 * \code
124 * QStringList conflicting = KGlobalAccel::findActionNameSystemwide(keySequence);
125 * if (!conflicting.isEmpty()) {
126 * // Inform and ask the user about the conflict and reassigning
127 * // the keys sequence
128 * if (!KGlobalAccel::promptStealShortcutSystemwide(q, conflicting, keySequence)) {
129 * return true;
130 * }
131 * KGlobalAccel::stealShortcutSystemwide(keySequence);
132 * }
133 * \endcode
134 *
135 * ... and standard shortcuts
136 *
137 * \code
138 * KStandardShortcut::StandardShortcut ssc = KStandardShortcut::find(keySequence);
139 * if (ssc != KStandardShortcut::AccelNone) {
140 * // We have a conflict
141 * }
142 * \endcode
143 *
144 *
145 * @since 4.2
146 */
147 void setCheckForConflictsAgainst(ShortcutTypes types);
148
149 /**
150 * The shortcut types we check for conflicts.
151 *
152 * @see setCheckForConflictsAgainst()
153 * @since 4.2
154 */
155 ShortcutTypes checkForConflictsAgainst() const;
156
157 /**
158 * Allow multikey shortcuts?
159 */
160 void setMultiKeyShortcutsAllowed(bool);
161 bool multiKeyShortcutsAllowed() const;
162
163 /**
164 * This only applies to user input, not to setKeySequence().
165 * Set whether to accept "plain" keys without modifiers (like Ctrl, Alt, Meta).
166 * Plain keys by our definition include letter and symbol keys and
167 * text editing keys (Return, Space, Tab, Backspace, Delete).
168 * "Special" keys like F1, Cursor keys, Insert, PageDown will always work.
169 */
170 void setModifierlessAllowed(bool allow);
171
172 /**
173 * @see setModifierlessAllowed()
174 */
175 bool isModifierlessAllowed();
176
177 /**
178 * Whether to allow modifier-only key sequences.
179 * @since 6.1
180 */
181 void setModifierOnlyAllowed(bool allow);
182 bool modifierOnlyAllowed() const;
183
184 /**
185 * Set whether a small button to set an empty key sequence should be displayed next to the
186 * main input widget. The default is to show the clear button.
187 */
188 void setClearButtonShown(bool show);
189
190 //@}
191
192 /**
193 * Checks whether the key sequence @p seq is available to grab.
194 *
195 * The sequence is checked under the same rules as if it has been typed by
196 * the user. This method is useful if you get key sequences from another
197 * input source and want to check if it is save to set them.
198 *
199 * @since 4.2
200 */
201 bool isKeySequenceAvailable(const QKeySequence &seq) const;
202
203 /**
204 * Return the currently selected key sequence.
205 */
206 QKeySequence keySequence() const;
207
208 /**
209 * Set a list of action collections to check against for conflictuous shortcut.
210 *
211 * @see setCheckForConflictsAgainst()
212 *
213 * If a QAction with a conflicting shortcut is found inside this list and
214 * its shortcut can be configured (KActionCollection::isShortcutConfigurable()
215 * returns true) the user will be prompted whether to steal the shortcut
216 * from this action.
217 *
218 * @since 4.1
219 */
220 void setCheckActionCollections(const QList<KActionCollection *> &actionCollections);
221
222 /**
223 * If the component using this widget supports shortcuts contexts, it has
224 * to set its component name so we can check conflicts correctly.
225 */
226 void setComponentName(const QString &componentName);
227
228Q_SIGNALS:
229
230 /**
231 * This signal is emitted when the current key sequence has changed, be it by user
232 * input or programmatically.
233 */
234 void keySequenceChanged(const QKeySequence &seq);
235
236 /**
237 * This signal is emitted after the user agreed to steal a shortcut from
238 * an action. This is only done for local shortcuts. So you can be sure \a
239 * action is one of the actions you provided with setCheckActionList() or
240 * setCheckActionCollections().
241 *
242 * If you listen to that signal and don't call applyStealShortcut() you
243 * are supposed to steal the shortcut and save this change.
244 */
245 void stealShortcut(const QKeySequence &seq, QAction *action);
246
247public Q_SLOTS:
248
249 /**
250 * Capture a shortcut from the keyboard. This call will only return once a key sequence
251 * has been captured or input was aborted.
252 * If a key sequence was input, keySequenceChanged() will be emitted.
253 *
254 * @see setModifierlessAllowed()
255 */
256 void captureKeySequence();
257
258 /**
259 * Set the key sequence.
260 *
261 * If @p val == Validate, and the call is actually changing the key sequence,
262 * conflictuous shortcut will be checked.
263 */
264 void setKeySequence(const QKeySequence &seq, Validation val = NoValidate);
265
266 /**
267 * Clear the key sequence.
268 */
269 void clearKeySequence();
270
271 /**
272 * Actually remove the shortcut that the user wanted to steal, from the
273 * action that was using it. This only applies to actions provided to us
274 * by setCheckActionCollections() and setCheckActionList().
275 *
276 * Global and Standard Shortcuts have to be stolen immediately when the
277 * user gives his consent (technical reasons). That means those changes
278 * will be active even if you never call applyStealShortcut().
279 *
280 * To be called before you apply your changes. No local shortcuts are
281 * stolen until this function is called.
282 */
283 void applyStealShortcut();
284
285private:
286 friend class KKeySequenceWidgetPrivate;
287 KKeySequenceWidgetPrivate *const d;
288
289 bool event(QEvent *ev) override;
290
291 Q_DISABLE_COPY(KKeySequenceWidget)
292};
293
294Q_DECLARE_OPERATORS_FOR_FLAGS(KKeySequenceWidget::ShortcutTypes)
295
296#endif // KKEYSEQUENCEWIDGET_H
297

source code of kxmlgui/src/kkeysequencewidget.h