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