File indexing completed on 2024-09-08 06:45:01
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 0253 /** 0254 * A QTreeWidgetItem that can handle QActions. 0255 * 0256 * It provides undo, commit functionality for changes made. Changes are effective immediately. You 0257 * have to commit them or they will be undone when deleting the item. 0258 * 0259 * @internal 0260 */ 0261 class KShortcutsEditorItem : public QTreeWidgetItem 0262 { 0263 public: 0264 KShortcutsEditorItem(QTreeWidgetItem *parent, QAction *action); 0265 0266 /** 0267 * Destructor 0268 * 0269 * Will undo pending changes. If you don't want that. Call commitChanges before 0270 */ 0271 ~KShortcutsEditorItem() override; 0272 0273 //! Undo the changes since the last commit. 0274 void undo(); 0275 0276 //! Commit the changes. 0277 void commit(); 0278 0279 QVariant data(int column, int role = Qt::DisplayRole) const override; 0280 bool operator<(const QTreeWidgetItem &other) const override; 0281 0282 QKeySequence keySequence(uint column) const; 0283 void setKeySequence(uint column, const QKeySequence &seq); 0284 #if 0 0285 void setShapeGesture(const KShapeGesture &gst); 0286 void setRockerGesture(const KRockerGesture &gst); 0287 #endif 0288 0289 bool isModified(uint column) const; 0290 bool isModified() const; 0291 0292 void setNameBold(bool flag) 0293 { 0294 m_isNameBold = flag; 0295 } 0296 0297 private: 0298 friend class KShortcutsEditorPrivate; 0299 0300 //! Recheck modified status - could have changed back to initial value 0301 void updateModified(); 0302 0303 //! The action this item is responsible for 0304 QAction *m_action; 0305 0306 //! Should the Name column be painted in bold? 0307 bool m_isNameBold; 0308 0309 //@{ 0310 //! The original shortcuts before user changes. 0 means no change. 0311 QList<QKeySequence> *m_oldLocalShortcut = nullptr; 0312 QList<QKeySequence> *m_oldGlobalShortcut = nullptr; 0313 #if 0 0314 KShapeGesture *m_oldShapeGesture; 0315 KRockerGesture *m_oldRockerGesture; 0316 #endif 0317 //@} 0318 0319 //! The localized action name 0320 QString m_actionNameInTable; 0321 0322 //! The action id. Needed for exporting and importing 0323 QString m_id; 0324 0325 //! The collator, for sorting 0326 QCollator m_collator; 0327 }; 0328 0329 // NEEDED FOR KShortcutsEditorPrivate 0330 #include "ui_kshortcutsdialog.h" 0331 0332 // Hack to make two protected methods public. 0333 // Used by both KShortcutsEditorPrivate and KShortcutsEditorDelegate 0334 class QTreeWidgetHack : public QTreeWidget 0335 { 0336 public: 0337 QTreeWidgetItem *itemFromIndex(const QModelIndex &index) const 0338 { 0339 return QTreeWidget::itemFromIndex(index); 0340 } 0341 QModelIndex indexFromItem(QTreeWidgetItem *item, int column) const 0342 { 0343 return QTreeWidget::indexFromItem(item, column); 0344 } 0345 }; 0346 0347 /** 0348 * This class should belong into kshortcutseditor.cpp. But kshortcutseditordelegate uses a static 0349 * function of this class. So for now it's here. But i will remove it later. 0350 * 0351 * @internal 0352 */ 0353 class KShortcutsEditorPrivate 0354 { 0355 public: 0356 explicit KShortcutsEditorPrivate(KShortcutsEditor *qq); 0357 0358 void initGUI(KShortcutsEditor::ActionTypes actionTypes, KShortcutsEditor::LetterShortcuts allowLetterShortcuts); 0359 void appendToView(uint nList, const QString &title = QString()); 0360 // used in appendToView 0361 QTreeWidgetItem *findOrMakeItem(QTreeWidgetItem *parent, const QString &name); 0362 0363 static KShortcutsEditorItem *itemFromIndex(QTreeWidget *const w, const QModelIndex &index); 0364 0365 // Set all shortcuts to their default values (bindings). 0366 void allDefault(); 0367 0368 // Import shortcuts from file 0369 void importConfiguration(KConfigBase *config); 0370 0371 #if 0 0372 //helper functions for conflict resolution 0373 bool stealShapeGesture(KShortcutsEditorItem *item, const KShapeGesture &gest); 0374 bool stealRockerGesture(KShortcutsEditorItem *item, const KRockerGesture &gest); 0375 #endif 0376 0377 // conflict resolution functions 0378 void changeKeyShortcut(KShortcutsEditorItem *item, uint column, const QKeySequence &capture); 0379 #if 0 0380 void changeShapeGesture(KShortcutsEditorItem *item, const KShapeGesture &capture); 0381 void changeRockerGesture(KShortcutsEditorItem *item, const KRockerGesture &capture); 0382 #endif 0383 0384 // private slots 0385 // this invokes the appropriate conflict resolution function 0386 void capturedShortcut(const QVariant &, const QModelIndex &); 0387 0388 //! Represents the three hierarchies the dialog handles. 0389 struct HierarchyInfo { 0390 QTreeWidgetItem *root = nullptr; 0391 QTreeWidgetItem *program = nullptr; 0392 QTreeWidgetItem *action = nullptr; 0393 }; 0394 0395 /** 0396 * Add @p action at @p level. Checks for QActions and unnamed actions 0397 * before adding. 0398 * 0399 * @return @c true if the action was really added, @c false if not 0400 */ 0401 bool addAction(QAction *action, QTreeWidgetItem *parent); 0402 0403 void printShortcuts() const; 0404 0405 void setActionTypes(KShortcutsEditor::ActionTypes actionTypes); 0406 0407 void setGlobalColumnsHidden(bool hide); 0408 void setLocalColumnsHidden(bool hide); 0409 0410 // members 0411 QList<KActionCollection *> actionCollections; 0412 KShortcutsEditor *q; 0413 0414 Ui::KShortcutsDialog ui; 0415 0416 KShortcutsEditor::ActionTypes actionTypes; 0417 KShortcutsEditorDelegate *delegate; 0418 0419 // Tracks if there are any local shortcuts in any of the action collections shown in the dialog 0420 bool m_hasAnyLocalShortcuts = false; 0421 // Tracks if there are any Global shortcuts in any of the action collections shown in the dialog 0422 bool m_hasAnyGlobalShortcuts = false; 0423 }; 0424 0425 Q_DECLARE_METATYPE(KShortcutsEditorItem *) 0426 0427 #endif /* KSHORTCUTSDIALOG_P_H */