Merge "persistent color scheme selection"
[trojita.git] / src / Gui / ShortcutHandler / ShortcutHandler.h
blob5bf3ab97374708c767f17fe4a58ea6bb8ebc8561
1 /*
2 Copyright (C) 2012, 2013 by Glad Deschrijver <glad.deschrijver@gmail.com>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of
7 the License or (at your option) version 3 or any later version
8 accepted by the membership of KDE e.V. (or its successor approved
9 by the membership of KDE e.V.), which shall act as a proxy
10 defined in Section 14 of version 3 of the license.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #ifndef SHORTCUTHANDLER_H
22 #define SHORTCUTHANDLER_H
24 #ifndef QT_NO_SHORTCUT
26 #include <QHash>
27 #include <QKeySequence>
28 #include <QObject>
29 #include <QPointer>
30 #include <QStringList>
32 class QAction;
33 class QSettings;
34 class QWidget;
36 namespace Gui
39 class ShortcutConfigDialog;
40 class ShortcutConfigWidget;
42 class ActionDescription
44 public:
45 explicit ActionDescription(const QString &iconName = QString(), const QString &text = QString(), const QString &defaultShortcut = QString(), const QString &parentId = QObject::tr("Main Window")) : iconName(iconName), text(text), defaultShortcut(defaultShortcut), shortcut(defaultShortcut), parentId(parentId) {}
46 QString iconName;
47 QString text;
48 QString defaultShortcut;
49 QString shortcut;
50 QString parentId;
51 QPointer<QAction> action;
54 /**
55 * @short Class for handling the configuration of keyboard shortcuts.
57 * This class is used for handling the configuration of keyboard shortcuts
58 * for actions defined with QAction.
60 * \b Initialization \n
62 * Only one ShortcutHandler instance can be created during the lifetime of
63 * your application. Typically this is done in the constructor of your main
64 * window as follows:
66 * \code
67 * ShortcutHandler *shortcutHandler = new ShortcutHandler(parentWidget);
68 * QSettings *settingsObject = new QSettings(parentWidget);
69 * shortcutHandler->setSettingsObject(settingsObject);
70 * \endcode
72 * where parentWidget is the widget which will serve as the parent widget
73 * for the shortcut configuration dialog (typically this is the main window
74 * of your application). The shortcut configuration dialog will be modal
75 * w.r.t. parentWidget. Specifying the parent in this way also ensures that
76 * the ShortcutHandler object itself will be deleted when parentWidget is
77 * deleted.
79 * In the example above, a QSettings object is defined and passed to the
80 * ShortcutHandler instance using setSettingsObject(QSettings*). This is
81 * required. This allows you to save the shortcut configuration in the
82 * same place as the other configuration settings of your program. Note that
83 * ShortcutHandler doesn't take over responsibility of the QSettings object,
84 * which should therefore be deleted by the caller. The QSettings object
85 * passed to ShortcutHandler should exist during the entire lifetime of the
86 * ShortcutHandler object, and should therefore not be deleted before the
87 * ShortcutHandler object is deleted.
89 * \b Making the shortcuts of your actions configurable \n
91 * In order to make a shortcut configurable, the QAction which has this
92 * shortcut must be added to the ShortcutHandler instance using
93 * addAction(QAction*) or addAction(QAction*, const QString&). For example:
95 * \code
96 * QAction *quitAction = new QAction(tr("&Quit"), this);
97 * quitAction->setShortcut(tr("Ctrl+Q"));
98 * quitAction->setObjectName("action_application_exit");
99 * ShortcutHandler::instance()->addAction(quitAction);
100 * \endcode
102 * This code can be used in any class in which you have included the
103 * shortcuthandler.h header file. It doesn't matter in which way the
104 * shortcut of the action is defined (e.g. the initial shortcut could
105 * also have been set to QKeySequence::Open) and the shortcut handling
106 * even works if there is no initial shortcut set. Note that if there
107 * is a shortcut set before the action is added to the ShortcutHandler
108 * object, then it will serve as the default shortcut in the configuration
109 * dialog. Note that it is compulsary to set the object name of the action
110 * with setObjectName(const QString&) before the action is added to the
111 * ShortcutHandler object, because the object name of the action (which
112 * should be unique throughout the whole application) is used to store the
113 * shortcut in the settings on disk. The action can be safely removed
114 * during the lifetime of the ShortcutHandler instance. Actions can be
115 * added to the ShortcutHandler instance at any moment during its lifetime,
116 * even after the configuration widget has already been shown (the new
117 * actions will be visible in the configuration widget when it is shown
118 * again).
120 * The second argument to addAction(QAction*, const QString&) sets the
121 * label under which the action is classified in the shortcut configuration
122 * dialog. If this label is not set, then it defaults to
123 * QObject::tr("Main Window").
125 * After all QActions are initialized and the appropriate ones are added
126 * to ShortcutHandler, the following code must be run in order to read
127 * previous modifications to the shortcuts from disk:
129 * \code
130 * ShortcutHandler::instance()->readSettings();
131 * \endcode
133 * \b Making use of predefined shortcuts \n
135 * Instead of first creating actions and then adding them to ShortcutHandler,
136 * you can predefine shortcuts using
137 * defineAction(const QString&, const QString&, const QString&, const QString&, const QString&) or
138 * defineAction(const QString&, const QString&, const QString&, const QKeySequence::StandardKey&, const QString&),
139 * after which you create the actions for the predefined shortcuts with
140 * createAction(const QString&, QWidget*) or
141 * createAction(const QString&, QObject*, const char*, QWidget*).
142 * The first argument of both createAction() functions is the name of an action as known
143 * by ShortcutHandler. The last argument of both functions is the widget
144 * that will be the parent of the action. The second function has two
145 * additional arguments which define the receiver of the actions's
146 * triggered() signal and the slot which is executed when this signal is
147 * triggered. For example, in the constructor of the main window you can use:
149 * \code
150 * ShortcutHandler::instance()->defineAction("action_application_exit", "application-exit", tr("E&xit"), QKeySequence::Quit, tr("Main Window"));
151 * ShortcutHandler::instance()->defineAction("action_toggle_document_editable", "document-edit", tr("&Set/Unset Document Editable"), tr("Ctrl+E"), tr("Main Window"));
152 * \endcode
154 * and anywhere in the program you can define:
156 * \code
157 * QAction *quitAction = ShortcutHandler::instance()->createAction("action_application_exit", this, SLOT(slotQuitApplication()), this);
158 * \endcode
160 * This code creates an action with the shortcut, text and icon defined for
161 * "action_application_exit" in ShortcutHandler. If no text or icon is defined
162 * for "action_application_exit", quitAction will be equal to 0. This action
163 * will call the slotQuitApplication() slot defined in "this" (the second
164 * argument) and has "this" (the last argument) as parent. If the action
165 * should be checkable, then the following code can be used:
167 * \code
168 * QAction *toggleEditableAction = ShortcutHandler::instance()->createAction("action_toggle_document_editable", this);
169 * toggleEditableAction->setCheckable();
170 * connect(toggleEditableAction, SIGNAL(triggered(bool)), this, SLOT(slotToggleEditable(bool)));
171 * \endcode
173 * In both cases, if an action is created with createAction(), it can be
174 * accessed later with action(const QString&). For example:
176 * \code
177 * toolBar->addAction(ShortcutHandler::instance()->action("action_toggle_document_editable"));
178 * \endcode
180 * After all actions are defined using defineAction(), the following code
181 * must be run in order to read previous modifications to the shortcuts
182 * from disk:
184 * \code
185 * ShortcutHandler::instance()->readSettings();
186 * \endcode
188 * \b Accessing the shortcut configuration dialog \n
190 * In order to make the shortcut configuration dialog accessible to the
191 * users of your program, an action can be added to a menu or toolbar.
192 * This action can be obtained with
193 * ShortcutHandler::instance()->shortcutConfigAction()
194 * anywhere in your program. For example:
196 * \code
197 * QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
198 * settingsMenu->addAction(ShortcutHandler::instance()->shortcutConfigAction());
199 * \endcode
201 * This code adds an item labeled "Configure Shortcuts" (or a localized
202 * version of this) to settingsMenu, which when triggered shows the shortcut
203 * configuration dialog. The shortcut configuration dialog is deleted when
204 * the parent widget of the ShortcutHandler instance is deleted.
206 * Warning: this approach cannot be combined with the following approach.
208 * \b Adding the shortcut configuration widget to an existing dialog \n
210 * Alternatively to adding an action which opens a shortcut configuration
211 * dialog as described above, it is possible to add a shortcut configuration
212 * widget to an existing configuration dialog. For example, in the constructor
213 * of a configuration dialog one can have:
215 * \code
216 * QVBoxLayout *mainLayout = new QVBoxLayout;
217 * mainLayout->addWidget(ShortcutHandler::instance()->configWidget());
218 * setLayout(mainLayout);
219 * \endcode
221 * You can use ShortcutHandler::instance()->configWidget() multiple times,
222 * but this will always refer to the same widget. The shortcut configuration
223 * widget is deleted when the parent widget of the ShortcutHandler is deleted
224 * (or when its new parent is deleted if the widget is reparented).
226 * In order to save the modified shortcuts to disk, it is necessary to call
227 * ShortcutHandler::instance()->accept() each time the configuration dialog
228 * to which this widget is added is accepted. This can happen for example
229 * in the configuration dialog's own accept() function.
231 * Warning: this approach cannot be combined with the previous approach:
232 * either you add an action with shortcutConfigAction() (which shows a
233 * standalone shortcut configuration dialog) or you add a widget with
234 * configWidget(). Using both is not possible.
236 * \b Exclusivity groups \n
238 * By default all shortcuts managed by ShortcutHandler should be different.
239 * ShortcutHandler does however not test initially if this condition is
240 * satisfied. When the user attempts to set a shortcut which is already in
241 * use, a warning is displayed and the possibility is given to unset the
242 * shortcut for the action that had the shortcut previously. Sometimes it
243 * is however useful to be able to use the same shortcut in different
244 * situations, for example when the application has two dialogs which can
245 * never be shown together, or when the application has a full screen mode
246 * effectively hiding the default window of the application. In order to
247 * be able to use the same shortcuts in such situations, exclusivity groups
248 * can be defined. For example, the code
250 * \code
251 * ShortcutHandler::instance()->addExclusivityGroup(QStringList() << tr("Presentation"));
252 * ShortcutHandler::instance()->addExclusivityGroup(QStringList() << tr("LaTeX commands") << tr("Math commands"));
253 * \endcode
255 * defines two exclusivity groups. The first one contains one element
256 * ("Presentation"), the second one contains two elements ("LaTeX commands"
257 * and "Math commands"). The elements must be labels which are passed
258 * previously to addAction(QAction*, const QString&) as the second argument.
259 * Actions having the label "Presentation" will then be required to
260 * have unique shortcuts, no two actions which have either one of the
261 * labels "LaTeX commands" and "Math commands" can have the same shortcuts.
262 * On the other hand, actions with label "Presentation" can have the
263 * same shortcuts as actions with label "LaTeX commands" or "Math commands".
265 * By default, there exists a label "Main Window" which belongs to its own
266 * exclusivity group. This label only exists when actions are added with
267 * addAction(QAction*, const QString&) without the second argument being
268 * specified (the corresponding exclusivity group always exists, but is
269 * ignored in this case). It is possible to add other labels to this
270 * exclusivity group by specifying for example:
272 * \code
273 * ShortcutHandler::instance()->addExclusivityGroup(QStringList() << tr("Main Window") << tr("Presentation"));
274 * \endcode
276 * This code adds "Presentation" to the exclusivity group containing
277 * "Main Window".
279 * If no exclusivity groups are defined, all labels are added to the same
280 * exclusivity group (which is the group containing "Main Window").
282 * Note that adding an exclusivity group can only be done \b after \n all
283 * necessary labels are added to the shortcut handler using
284 * addAction(QAction*, const QString&) where the second argument is the
285 * label which is added to the exclusivity group. If a label is added to
286 * two or more exclusivity groups in subsequent calls of
287 * addExclusivityGroup(), then the label will only belong to the last
288 * defined exclusivity group.
290 class ShortcutHandler : public QObject
292 Q_OBJECT
294 public:
295 explicit ShortcutHandler(QWidget *parent);
296 ~ShortcutHandler();
297 static ShortcutHandler *instance() { return self; }
299 void setSettingsObject(QSettings *settings);
301 * Defines an action with a shortcut. All actions defined using this
302 * function will be visible in the shortcut configuration widget.
303 * \param actionName the name under which the action is known to the shortcut configuration system
304 * \param iconName the name of the icon displayed when the action is added to a menu or toolbar. If iconName is an empty string, then no icon is shown.
305 * \param text the text visible on the item in the menu or toolbar corresponding to this action
306 * \param defaultShortcut the (localized) string describing the default shortcut which triggers this action, e.g. tr("Ctrl+E")
307 * \param parentId the title under which this action is shown in the shortcut configuration widget. In the shortcut configuration widget, the actions are grouped according to parentId.
309 void defineAction(const QString &actionName, const QString &iconName, const QString &text, const QString &defaultShortcut = QString(), const QString &parentId = QObject::tr("Main Window"));
311 * Defines an action with a shortcut. All actions defined using this
312 * function will be visible in the shortcut configuration widget.
313 * \param actionName the name under which the action is known to the shortcut configuration system
314 * \param iconName the name of the icon displayed when the action is added to a menu or toolbar. If iconName is an empty string, then no icon is shown.
315 * \param text the text visible on the item in the menu or toolbar corresponding to this action
316 * \param key the QKeySequence::StandardKey value describing the default shortcut which triggers this action, e.g. QKeySequence::Quit
317 * \param parentId the title under which this action is shown in the shortcut configuration widget. In the shortcut configuration widget, the actions are grouped according to parentId.
319 void defineAction(const QString &actionName, const QString &iconName, const QString &text, const QKeySequence::StandardKey &key, const QString &parentId = QObject::tr("Main Window"));
320 QAction *createAction(const QString &actionName, QWidget *parent = 0);
321 QAction *createAction(const QString &actionName, QObject *receiver, const char *member, QWidget *parent = 0);
322 void addExclusivityGroup(const QStringList &group);
323 QSettings *settingsObject();
324 QAction *action(const QString &actionName);
325 QAction *shortcutConfigAction();
326 ShortcutConfigWidget *configWidget();
327 void accept();
328 void reject();
329 void readSettings();
331 private Q_SLOTS:
332 void changeShortcuts(const QHash<QString, ActionDescription> &actionDescriptions);
333 void openShortcutConfigDialog();
335 private:
336 static ShortcutHandler *self;
338 QSettings *m_settings;
339 QPointer<QAction> m_shortcutConfigAction;
340 QPointer<ShortcutConfigDialog> m_shortcutConfigDialog;
341 QPointer<ShortcutConfigWidget> m_shortcutConfigWidget;
343 QHash<QString, ActionDescription> m_actionDescriptions;
344 QList<QStringList> m_exclusivityGroups;
347 } // namespace Gui
349 #endif // QT_NO_SHORTCUT
351 #endif // SHORTCUTHANDLER_H