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 | |
17 | class KKeySequenceWidgetPrivate; |
18 | class QAction; |
19 | class 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 | */ |
37 | class 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 | |
53 | public: |
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 | |
228 | Q_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 | |
247 | public 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 | |
285 | private: |
286 | friend class KKeySequenceWidgetPrivate; |
287 | KKeySequenceWidgetPrivate *const d; |
288 | |
289 | bool event(QEvent *ev) override; |
290 | |
291 | Q_DISABLE_COPY(KKeySequenceWidget) |
292 | }; |
293 | |
294 | Q_DECLARE_OPERATORS_FOR_FLAGS(KKeySequenceWidget::ShortcutTypes) |
295 | |
296 | #endif // KKEYSEQUENCEWIDGET_H |
297 | |