1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2006, 2007 Andreas Hartmetz <ahartmetz@gmail.com>
4 SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz>
5 SPDX-FileCopyrightText: 2008 Alexander Dymo <adymo@kdevelop.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#ifndef KSHORTCUTSDIALOG_P_H
11#define KSHORTCUTSDIALOG_P_H
12
13#include "kkeysequencewidget.h"
14#include "kshortcutseditor.h"
15
16#include <KExtendableItemDelegate>
17
18#include <QCollator>
19#include <QGroupBox>
20#include <QKeySequence>
21#include <QList>
22#include <QMetaType>
23#include <QModelIndex>
24#include <QTreeWidget>
25
26class QLabel;
27class QTreeWidgetItem;
28class QRadioButton;
29class QAction;
30class KActionCollection;
31class QPushButton;
32class QComboBox;
33class KShortcutsDialog;
34
35enum ColumnDesignation {
36 Name = 0,
37 LocalPrimary,
38 LocalAlternate,
39 GlobalPrimary,
40 GlobalAlternate,
41 RockerGesture,
42 ShapeGesture,
43 Id,
44};
45
46enum MyRoles {
47 ShortcutRole = Qt::UserRole,
48 DefaultShortcutRole,
49 ObjectRole,
50};
51
52/**
53 * Type used for QTreeWidgetItems
54 *
55 * @internal
56 */
57enum ItemTypes {
58 NonActionItem = 0,
59 ActionItem = 1,
60};
61
62QKeySequence primarySequence(const QList<QKeySequence> &sequences);
63QKeySequence alternateSequence(const QList<QKeySequence> &sequences);
64
65/**
66 * Mixes the KShortcutWidget into the treeview used by KShortcutsEditor. When selecting an shortcut
67 * it changes the display from "CTRL-W" to the Widget.
68 *
69 * @bug That delegate uses KExtendableItemDelegate. That means a cell can be expanded. When selected
70 * a cell is replaced by a KShortcutsEditor. When painting the widget KExtendableItemDelegate
71 * reparents the widget to the viewport of the itemview it belongs to. The widget is destroyed when
72 * the user selects another shortcut or explicitly issues a contractItem event. But when the user
73 * clears the model the delegate misses that event and doesn't delete the KShortcutseditor. And
74 * remains as a visible artefact in your treeview. Additionally when closing your application you get
75 * an assertion failure from KExtendableItemDelegate.
76 *
77 * @internal
78 */
79class KShortcutsEditorDelegate : public KExtendableItemDelegate
80{
81 Q_OBJECT
82public:
83 KShortcutsEditorDelegate(QTreeWidget *parent, bool allowLetterShortcuts);
84 // reimplemented to have some extra height
85 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
86
87 /**
88 * Set a list of action collections to check against for conflicting
89 * shortcuts.
90 *
91 * @see KKeySequenceWidget::setCheckActionCollections
92 */
93 void setCheckActionCollections(const QList<KActionCollection *> &checkActionCollections);
94
95Q_SIGNALS:
96 void shortcutChanged(const QVariant &, const QModelIndex &);
97public Q_SLOTS:
98 void hiddenBySearchLine(QTreeWidgetItem *, bool);
99
100protected:
101 bool eventFilter(QObject *, QEvent *) override;
102
103private:
104 mutable QPersistentModelIndex m_editingIndex;
105 const bool m_allowLetterShortcuts;
106 QWidget *m_editor = nullptr;
107
108 //! List of actionCollections to check for conflicts.
109 QList<KActionCollection *> m_checkActionCollections;
110
111private Q_SLOTS:
112 void itemActivated(const QModelIndex &index);
113
114 /**
115 * When the user collapses a hole subtree of shortcuts then remove eventually
116 * extended items. Else we get that artefact bug. See above.
117 */
118 void itemCollapsed(const QModelIndex &index);
119
120 /**
121 * If the user allowed stealing a shortcut we want to be able to undo
122 * that.
123 */
124 void stealShortcut(const QKeySequence &seq, QAction *action);
125
126 void keySequenceChanged(const QKeySequence &);
127
128#if 0
129 void shapeGestureChanged(const KShapeGesture &);
130 void rockerGestureChanged(const KRockerGesture &);
131#endif
132};
133
134/**
135 * That widget draws the decoration for KShortCutWidget. That widget is currently the only user.
136 *
137 * @internal
138 */
139class TabConnectedWidget : public QWidget
140{
141 Q_OBJECT
142public:
143 explicit TabConnectedWidget(QWidget *parent)
144 : QWidget(parent)
145 {
146 }
147
148protected:
149 void paintEvent(QPaintEvent *pe) override;
150};
151
152/**
153 * Edit a shortcut. Let you select between using the default shortcut and configuring your own.
154 *
155 * @internal
156 */
157class ShortcutEditWidget : public TabConnectedWidget
158{
159 Q_OBJECT
160public:
161 ShortcutEditWidget(QWidget *viewport, const QKeySequence &defaultSeq, const QKeySequence &activeSeq, bool allowLetterShortcuts);
162
163 //! @see KKeySequenceWidget::setCheckActionCollections()
164 void setCheckActionCollections(const QList<KActionCollection *> &checkActionCollections);
165
166 //@{
167 //! @see KKeySequenceWidget::checkAgainstStandardShortcuts()
168 KKeySequenceWidget::ShortcutTypes checkForConflictsAgainst() const;
169 void setCheckForConflictsAgainst(KKeySequenceWidget::ShortcutTypes);
170 //@}
171
172 //@{
173 //! @see KKeySequenceWidget::checkAgainstStandardShortcuts()
174 bool multiKeyShortcutsAllowed() const;
175 void setMultiKeyShortcutsAllowed(bool);
176 //@}
177
178 //! @see KKeySequenceWidget::setComponentName
179 void setComponentName(const QString &componentName);
180
181 void setAction(QObject *action);
182
183public Q_SLOTS:
184
185 //! Set the displayed sequences
186 void setKeySequence(const QKeySequence &activeSeq);
187
188Q_SIGNALS:
189
190 //! Emitted when the key sequence is changed.
191 void keySequenceChanged(const QKeySequence &);
192
193 //! @see KKeySequenceWidget::stealShortcut()
194 void stealShortcut(const QKeySequence &seq, QAction *action);
195
196private Q_SLOTS:
197
198 void defaultToggled(bool);
199 void setCustom(const QKeySequence &);
200
201private:
202 QLabel *m_defaultLabel;
203 QKeySequence m_defaultKeySequence;
204 QRadioButton *m_defaultRadio;
205 QRadioButton *m_customRadio;
206 KKeySequenceWidget *m_customEditor;
207 bool m_isUpdating;
208 QObject *m_action;
209 const QString m_noneText; // Translated "None" text for labels
210};
211
212#if 0
213Q_DECLARE_METATYPE(KShapeGesture)
214Q_DECLARE_METATYPE(KRockerGesture)
215#endif
216
217class KShortcutSchemesEditor : public QGroupBox
218{
219 Q_OBJECT
220public:
221 explicit KShortcutSchemesEditor(KShortcutsDialog *parent);
222
223 /** @return the currently selected scheme in the editor (may differ from current app's scheme.*/
224 QString currentScheme();
225 void refreshSchemes();
226 void addMoreMenuAction(QAction *action);
227
228private Q_SLOTS:
229 void newScheme();
230 void deleteScheme();
231 void exportShortcutsScheme();
232 void importShortcutsScheme();
233 void saveAsDefaultsForScheme();
234
235Q_SIGNALS:
236 void shortcutsSchemeChanged(const QString &);
237
238protected:
239 void updateDeleteButton();
240
241private:
242 QPushButton *m_newScheme;
243 QPushButton *m_deleteScheme;
244 QPushButton *m_exportScheme;
245 QComboBox *m_schemesList;
246 QMenu *m_moreActionsMenu;
247
248 KShortcutsDialog *m_dialog;
249};
250
251class QAction;
252
253/**
254 * A QTreeWidgetItem that can handle QActions.
255 *
256 * It provides undo, commit functionality for changes made. Changes are effective immediately. You
257 * have to commit them or they will be undone when deleting the item.
258 *
259 * @internal
260 */
261class KShortcutsEditorItem : public QTreeWidgetItem
262{
263public:
264 KShortcutsEditorItem(QTreeWidgetItem *parent, QAction *action);
265
266 /**
267 * Destructor
268 *
269 * Will undo pending changes. If you don't want that. Call commitChanges before
270 */
271 ~KShortcutsEditorItem() override;
272
273 //! Undo the changes since the last commit.
274 void undo();
275
276 //! Commit the changes.
277 void commit();
278
279 QVariant data(int column, int role = Qt::DisplayRole) const override;
280 bool operator<(const QTreeWidgetItem &other) const override;
281
282 QKeySequence keySequence(uint column) const;
283 void setKeySequence(uint column, const QKeySequence &seq);
284#if 0
285 void setShapeGesture(const KShapeGesture &gst);
286 void setRockerGesture(const KRockerGesture &gst);
287#endif
288
289 bool isModified(uint column) const;
290 bool isModified() const;
291
292 void setNameBold(bool flag)
293 {
294 m_isNameBold = flag;
295 }
296
297private:
298 friend class KShortcutsEditorPrivate;
299
300 //! Recheck modified status - could have changed back to initial value
301 void updateModified();
302
303 //! The action this item is responsible for
304 QAction *m_action;
305
306 //! Should the Name column be painted in bold?
307 bool m_isNameBold;
308
309 //@{
310 //! The original shortcuts before user changes. 0 means no change.
311 QList<QKeySequence> *m_oldLocalShortcut = nullptr;
312 QList<QKeySequence> *m_oldGlobalShortcut = nullptr;
313#if 0
314 KShapeGesture *m_oldShapeGesture;
315 KRockerGesture *m_oldRockerGesture;
316#endif
317 //@}
318
319 //! The localized action name
320 QString m_actionNameInTable;
321
322 //! The action id. Needed for exporting and importing
323 QString m_id;
324
325 //! The collator, for sorting
326 QCollator m_collator;
327};
328
329// NEEDED FOR KShortcutsEditorPrivate
330#include "ui_kshortcutsdialog.h"
331
332// Hack to make two protected methods public.
333// Used by both KShortcutsEditorPrivate and KShortcutsEditorDelegate
334class QTreeWidgetHack : public QTreeWidget
335{
336public:
337 QTreeWidgetItem *itemFromIndex(const QModelIndex &index) const
338 {
339 return QTreeWidget::itemFromIndex(index);
340 }
341 QModelIndex indexFromItem(QTreeWidgetItem *item, int column) const
342 {
343 return QTreeWidget::indexFromItem(item, column);
344 }
345};
346
347/**
348 * This class should belong into kshortcutseditor.cpp. But kshortcutseditordelegate uses a static
349 * function of this class. So for now it's here. But i will remove it later.
350 *
351 * @internal
352 */
353class KShortcutsEditorPrivate
354{
355public:
356 explicit KShortcutsEditorPrivate(KShortcutsEditor *qq);
357
358 void initGUI(KShortcutsEditor::ActionTypes actionTypes, KShortcutsEditor::LetterShortcuts allowLetterShortcuts);
359 void appendToView(uint nList, const QString &title = QString());
360 // used in appendToView
361 QTreeWidgetItem *findOrMakeItem(QTreeWidgetItem *parent, const QString &name);
362
363 static KShortcutsEditorItem *itemFromIndex(QTreeWidget *const w, const QModelIndex &index);
364
365 // Set all shortcuts to their default values (bindings).
366 void allDefault();
367
368 // Import shortcuts from file
369 void importConfiguration(KConfigBase *config);
370
371#if 0
372 //helper functions for conflict resolution
373 bool stealShapeGesture(KShortcutsEditorItem *item, const KShapeGesture &gest);
374 bool stealRockerGesture(KShortcutsEditorItem *item, const KRockerGesture &gest);
375#endif
376
377 // conflict resolution functions
378 void changeKeyShortcut(KShortcutsEditorItem *item, uint column, const QKeySequence &capture);
379#if 0
380 void changeShapeGesture(KShortcutsEditorItem *item, const KShapeGesture &capture);
381 void changeRockerGesture(KShortcutsEditorItem *item, const KRockerGesture &capture);
382#endif
383
384 // private slots
385 // this invokes the appropriate conflict resolution function
386 void capturedShortcut(const QVariant &, const QModelIndex &);
387
388 //! Represents the three hierarchies the dialog handles.
389 struct HierarchyInfo {
390 QTreeWidgetItem *root = nullptr;
391 QTreeWidgetItem *program = nullptr;
392 QTreeWidgetItem *action = nullptr;
393 };
394
395 /**
396 * Add @p action at @p level. Checks for QActions and unnamed actions
397 * before adding.
398 *
399 * @return @c true if the action was really added, @c false if not
400 */
401 bool addAction(QAction *action, QTreeWidgetItem *parent);
402
403 void printShortcuts() const;
404
405 void setActionTypes(KShortcutsEditor::ActionTypes actionTypes);
406
407 void setGlobalColumnsHidden(bool hide);
408 void setLocalColumnsHidden(bool hide);
409
410 // members
411 QList<KActionCollection *> actionCollections;
412 KShortcutsEditor *q;
413
414 Ui::KShortcutsDialog ui;
415
416 KShortcutsEditor::ActionTypes actionTypes;
417 KShortcutsEditorDelegate *delegate;
418
419 // Tracks if there are any local shortcuts in any of the action collections shown in the dialog
420 bool m_hasAnyLocalShortcuts = false;
421 // Tracks if there are any Global shortcuts in any of the action collections shown in the dialog
422 bool m_hasAnyGlobalShortcuts = false;
423};
424
425Q_DECLARE_METATYPE(KShortcutsEditorItem *)
426
427#endif /* KSHORTCUTSDIALOG_P_H */
428

source code of kxmlgui/src/kshortcutsdialog_p.h