File indexing completed on 2024-10-06 09:43:55
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2006, 2007 Andreas Hartmetz <ahartmetz@gmail.com> 0004 SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz> 0005 SPDX-FileCopyrightText: 2008 Alexander Dymo <adymo@kdevelop.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #ifndef KSHORTCUTSDIALOG_P_H 0011 #define KSHORTCUTSDIALOG_P_H 0012 0013 #include "kkeysequencewidget.h" 0014 #include "kshortcutseditor.h" 0015 0016 #include <KExtendableItemDelegate> 0017 0018 #include <QCollator> 0019 #include <QGroupBox> 0020 #include <QKeySequence> 0021 #include <QList> 0022 #include <QMetaType> 0023 #include <QModelIndex> 0024 #include <QTreeWidget> 0025 0026 class QLabel; 0027 class QTreeWidgetItem; 0028 class QRadioButton; 0029 class QAction; 0030 class KActionCollection; 0031 class QPushButton; 0032 class QComboBox; 0033 class KShortcutsDialog; 0034 0035 enum ColumnDesignation { 0036 Name = 0, 0037 LocalPrimary, 0038 LocalAlternate, 0039 GlobalPrimary, 0040 GlobalAlternate, 0041 RockerGesture, 0042 ShapeGesture, 0043 Id, 0044 }; 0045 0046 enum MyRoles { 0047 ShortcutRole = Qt::UserRole, 0048 DefaultShortcutRole, 0049 ObjectRole, 0050 }; 0051 0052 /** 0053 * Type used for QTreeWidgetItems 0054 * 0055 * @internal 0056 */ 0057 enum ItemTypes { 0058 NonActionItem = 0, 0059 ActionItem = 1, 0060 }; 0061 0062 QKeySequence primarySequence(const QList<QKeySequence> &sequences); 0063 QKeySequence alternateSequence(const QList<QKeySequence> &sequences); 0064 0065 /** 0066 * Mixes the KShortcutWidget into the treeview used by KShortcutsEditor. When selecting an shortcut 0067 * it changes the display from "CTRL-W" to the Widget. 0068 * 0069 * @bug That delegate uses KExtendableItemDelegate. That means a cell can be expanded. When selected 0070 * a cell is replaced by a KShortcutsEditor. When painting the widget KExtendableItemDelegate 0071 * reparents the widget to the viewport of the itemview it belongs to. The widget is destroyed when 0072 * the user selects another shortcut or explicitly issues a contractItem event. But when the user 0073 * clears the model the delegate misses that event and doesn't delete the KShortcutseditor. And 0074 * remains as a visible artefact in your treeview. Additionally when closing your application you get 0075 * an assertion failure from KExtendableItemDelegate. 0076 * 0077 * @internal 0078 */ 0079 class KShortcutsEditorDelegate : public KExtendableItemDelegate 0080 { 0081 Q_OBJECT 0082 public: 0083 KShortcutsEditorDelegate(QTreeWidget *parent, bool allowLetterShortcuts); 0084 // reimplemented to have some extra height 0085 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; 0086 0087 /** 0088 * Set a list of action collections to check against for conflicting 0089 * shortcuts. 0090 * 0091 * @see KKeySequenceWidget::setCheckActionCollections 0092 */ 0093 void setCheckActionCollections(const QList<KActionCollection *> &checkActionCollections); 0094 0095 Q_SIGNALS: 0096 void shortcutChanged(const QVariant &, const QModelIndex &); 0097 public Q_SLOTS: 0098 void hiddenBySearchLine(QTreeWidgetItem *, bool); 0099 0100 protected: 0101 bool eventFilter(QObject *, QEvent *) override; 0102 0103 private: 0104 mutable QPersistentModelIndex m_editingIndex; 0105 const bool m_allowLetterShortcuts; 0106 QWidget *m_editor = nullptr; 0107 0108 //! List of actionCollections to check for conflicts. 0109 QList<KActionCollection *> m_checkActionCollections; 0110 0111 private Q_SLOTS: 0112 void itemActivated(const QModelIndex &index); 0113 0114 /** 0115 * When the user collapses a hole subtree of shortcuts then remove eventually 0116 * extended items. Else we get that artefact bug. See above. 0117 */ 0118 void itemCollapsed(const QModelIndex &index); 0119 0120 /** 0121 * If the user allowed stealing a shortcut we want to be able to undo 0122 * that. 0123 */ 0124 void stealShortcut(const QKeySequence &seq, QAction *action); 0125 0126 void keySequenceChanged(const QKeySequence &); 0127 0128 #if 0 0129 void shapeGestureChanged(const KShapeGesture &); 0130 void rockerGestureChanged(const KRockerGesture &); 0131 #endif 0132 }; 0133 0134 /** 0135 * That widget draws the decoration for KShortCutWidget. That widget is currently the only user. 0136 * 0137 * @internal 0138 */ 0139 class TabConnectedWidget : public QWidget 0140 { 0141 Q_OBJECT 0142 public: 0143 explicit TabConnectedWidget(QWidget *parent) 0144 : QWidget(parent) 0145 { 0146 } 0147 0148 protected: 0149 void paintEvent(QPaintEvent *pe) override; 0150 }; 0151 0152 /** 0153 * Edit a shortcut. Let you select between using the default shortcut and configuring your own. 0154 * 0155 * @internal 0156 */ 0157 class ShortcutEditWidget : public TabConnectedWidget 0158 { 0159 Q_OBJECT 0160 public: 0161 ShortcutEditWidget(QWidget *viewport, const QKeySequence &defaultSeq, const QKeySequence &activeSeq, bool allowLetterShortcuts); 0162 0163 //! @see KKeySequenceWidget::setCheckActionCollections() 0164 void setCheckActionCollections(const QList<KActionCollection *> &checkActionCollections); 0165 0166 //@{ 0167 //! @see KKeySequenceWidget::checkAgainstStandardShortcuts() 0168 KKeySequenceWidget::ShortcutTypes checkForConflictsAgainst() const; 0169 void setCheckForConflictsAgainst(KKeySequenceWidget::ShortcutTypes); 0170 //@} 0171 0172 //@{ 0173 //! @see KKeySequenceWidget::checkAgainstStandardShortcuts() 0174 bool multiKeyShortcutsAllowed() const; 0175 void setMultiKeyShortcutsAllowed(bool); 0176 //@} 0177 0178 //! @see KKeySequenceWidget::setComponentName 0179 void setComponentName(const QString &componentName); 0180 0181 void setAction(QObject *action); 0182 0183 public Q_SLOTS: 0184 0185 //! Set the displayed sequences 0186 void setKeySequence(const QKeySequence &activeSeq); 0187 0188 Q_SIGNALS: 0189 0190 //! Emitted when the key sequence is changed. 0191 void keySequenceChanged(const QKeySequence &); 0192 0193 //! @see KKeySequenceWidget::stealShortcut() 0194 void stealShortcut(const QKeySequence &seq, QAction *action); 0195 0196 private Q_SLOTS: 0197 0198 void defaultToggled(bool); 0199 void setCustom(const QKeySequence &); 0200 0201 private: 0202 QLabel *m_defaultLabel; 0203 QKeySequence m_defaultKeySequence; 0204 QRadioButton *m_defaultRadio; 0205 QRadioButton *m_customRadio; 0206 KKeySequenceWidget *m_customEditor; 0207 bool m_isUpdating; 0208 QObject *m_action; 0209 const QString m_noneText; // Translated "None" text for labels 0210 }; 0211 0212 #if 0 0213 Q_DECLARE_METATYPE(KShapeGesture) 0214 Q_DECLARE_METATYPE(KRockerGesture) 0215 #endif 0216 0217 class KShortcutSchemesEditor : public QGroupBox 0218 { 0219 Q_OBJECT 0220 public: 0221 explicit KShortcutSchemesEditor(KShortcutsDialog *parent); 0222 0223 /** @return the currently selected scheme in the editor (may differ from current app's scheme.*/ 0224 QString currentScheme(); 0225 void refreshSchemes(); 0226 void addMoreMenuAction(QAction *action); 0227 0228 private Q_SLOTS: 0229 void newScheme(); 0230 void deleteScheme(); 0231 void exportShortcutsScheme(); 0232 void importShortcutsScheme(); 0233 void saveAsDefaultsForScheme(); 0234 0235 Q_SIGNALS: 0236 void shortcutsSchemeChanged(const QString &); 0237 0238 protected: 0239 void updateDeleteButton(); 0240 0241 private: 0242 QPushButton *m_newScheme; 0243 QPushButton *m_deleteScheme; 0244 QPushButton *m_exportScheme; 0245 QComboBox *m_schemesList; 0246 QMenu *m_moreActionsMenu; 0247 0248 KShortcutsDialog *m_dialog; 0249 }; 0250 0251 class QAction; 0252 #if 0 0253 class KShapeGesture; 0254 class KRockerGesture; 0255 #endif 0256 0257 /** 0258 * A QTreeWidgetItem that can handle QActions. 0259 * 0260 * It provides undo, commit functionality for changes made. Changes are effective immediately. You 0261 * have to commit them or they will be undone when deleting the item. 0262 * 0263 * @internal 0264 */ 0265 class KShortcutsEditorItem : public QTreeWidgetItem 0266 { 0267 public: 0268 KShortcutsEditorItem(QTreeWidgetItem *parent, QAction *action); 0269 0270 /** 0271 * Destructor 0272 * 0273 * Will undo pending changes. If you don't want that. Call commitChanges before 0274 */ 0275 ~KShortcutsEditorItem() override; 0276 0277 //! Undo the changes since the last commit. 0278 void undo(); 0279 0280 //! Commit the changes. 0281 void commit(); 0282 0283 QVariant data(int column, int role = Qt::DisplayRole) const override; 0284 bool operator<(const QTreeWidgetItem &other) const override; 0285 0286 QKeySequence keySequence(uint column) const; 0287 void setKeySequence(uint column, const QKeySequence &seq); 0288 #if 0 0289 void setShapeGesture(const KShapeGesture &gst); 0290 void setRockerGesture(const KRockerGesture &gst); 0291 #endif 0292 0293 bool isModified(uint column) const; 0294 bool isModified() const; 0295 0296 void setNameBold(bool flag) 0297 { 0298 m_isNameBold = flag; 0299 } 0300 0301 private: 0302 friend class KShortcutsEditorPrivate; 0303 0304 //! Recheck modified status - could have changed back to initial value 0305 void updateModified(); 0306 0307 //! The action this item is responsible for 0308 QAction *m_action; 0309 0310 //! Should the Name column be painted in bold? 0311 bool m_isNameBold; 0312 0313 //@{ 0314 //! The original shortcuts before user changes. 0 means no change. 0315 QList<QKeySequence> *m_oldLocalShortcut = nullptr; 0316 QList<QKeySequence> *m_oldGlobalShortcut = nullptr; 0317 #if 0 0318 KShapeGesture *m_oldShapeGesture; 0319 KRockerGesture *m_oldRockerGesture; 0320 #endif 0321 //@} 0322 0323 //! The localized action name 0324 QString m_actionNameInTable; 0325 0326 //! The action id. Needed for exporting and importing 0327 QString m_id; 0328 0329 //! The collator, for sorting 0330 QCollator m_collator; 0331 }; 0332 0333 // NEEDED FOR KShortcutsEditorPrivate 0334 #include "ui_kshortcutsdialog.h" 0335 0336 // Hack to make two protected methods public. 0337 // Used by both KShortcutsEditorPrivate and KShortcutsEditorDelegate 0338 class QTreeWidgetHack : public QTreeWidget 0339 { 0340 public: 0341 QTreeWidgetItem *itemFromIndex(const QModelIndex &index) const 0342 { 0343 return QTreeWidget::itemFromIndex(index); 0344 } 0345 QModelIndex indexFromItem(QTreeWidgetItem *item, int column) const 0346 { 0347 return QTreeWidget::indexFromItem(item, column); 0348 } 0349 }; 0350 0351 /** 0352 * This class should belong into kshortcutseditor.cpp. But kshortcutseditordelegate uses a static 0353 * function of this class. So for now it's here. But i will remove it later. 0354 * 0355 * @internal 0356 */ 0357 class KShortcutsEditorPrivate 0358 { 0359 public: 0360 explicit KShortcutsEditorPrivate(KShortcutsEditor *qq); 0361 0362 void initGUI(KShortcutsEditor::ActionTypes actionTypes, KShortcutsEditor::LetterShortcuts allowLetterShortcuts); 0363 void appendToView(uint nList, const QString &title = QString()); 0364 // used in appendToView 0365 QTreeWidgetItem *findOrMakeItem(QTreeWidgetItem *parent, const QString &name); 0366 0367 static KShortcutsEditorItem *itemFromIndex(QTreeWidget *const w, const QModelIndex &index); 0368 0369 // Set all shortcuts to their default values (bindings). 0370 void allDefault(); 0371 0372 // clear all shortcuts 0373 void clearConfiguration(); 0374 0375 // Import shortcuts from file 0376 void importConfiguration(KConfigBase *config); 0377 0378 #if 0 0379 //helper functions for conflict resolution 0380 bool stealShapeGesture(KShortcutsEditorItem *item, const KShapeGesture &gest); 0381 bool stealRockerGesture(KShortcutsEditorItem *item, const KRockerGesture &gest); 0382 #endif 0383 0384 // conflict resolution functions 0385 void changeKeyShortcut(KShortcutsEditorItem *item, uint column, const QKeySequence &capture); 0386 #if 0 0387 void changeShapeGesture(KShortcutsEditorItem *item, const KShapeGesture &capture); 0388 void changeRockerGesture(KShortcutsEditorItem *item, const KRockerGesture &capture); 0389 #endif 0390 0391 // private slots 0392 // this invokes the appropriate conflict resolution function 0393 void capturedShortcut(const QVariant &, const QModelIndex &); 0394 0395 //! Represents the three hierarchies the dialog handles. 0396 struct HierarchyInfo { 0397 QTreeWidgetItem *root = nullptr; 0398 QTreeWidgetItem *program = nullptr; 0399 QTreeWidgetItem *action = nullptr; 0400 }; 0401 0402 /** 0403 * Add @p action at @p level. Checks for QActions and unnamed actions 0404 * before adding. 0405 * 0406 * @return @c true if the action was really added, @c false if not 0407 */ 0408 bool addAction(QAction *action, QTreeWidgetItem *parent); 0409 0410 void printShortcuts() const; 0411 0412 void setActionTypes(KShortcutsEditor::ActionTypes actionTypes); 0413 0414 void setGlobalColumnsHidden(bool hide); 0415 void setLocalColumnsHidden(bool hide); 0416 0417 // members 0418 QList<KActionCollection *> actionCollections; 0419 KShortcutsEditor *q; 0420 0421 Ui::KShortcutsDialog ui; 0422 0423 KShortcutsEditor::ActionTypes actionTypes; 0424 KShortcutsEditorDelegate *delegate; 0425 0426 // Tracks if there are any Global shortcuts in any of the action collections shown in the dialog 0427 bool m_hasAnyGlobalShortcuts = false; 0428 }; 0429 0430 Q_DECLARE_METATYPE(KShortcutsEditorItem *) 0431 0432 #endif /* KSHORTCUTSDIALOG_P_H */