File indexing completed on 2024-03-03 04:08:05

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org>
0004     SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #ifndef KKEYSEQUENCEWIDGET_H
0010 #define KKEYSEQUENCEWIDGET_H
0011 
0012 #include <kxmlgui_export.h>
0013 
0014 #include <QList>
0015 #include <QPushButton>
0016 
0017 class KKeySequenceWidgetPrivate;
0018 class QAction;
0019 class KActionCollection;
0020 
0021 /**
0022  * @class KKeySequenceWidget kkeysequencewidget.h KKeySequenceWidget
0023  *
0024  * @short A widget to input a QKeySequence.
0025  *
0026  * This widget lets the user choose a QKeySequence, which is usually used as a
0027  * shortcut key. The recording is initiated by calling captureKeySequence() or
0028  * the user clicking into the widget.
0029  *
0030  * The widgets provides support for conflict handling. See
0031  * setCheckForConflictsAgainst() for more information.
0032  *
0033  * \image html kkeysequencewidget.png "KKeySequenceWidget"
0034  *
0035  * @author Mark Donohoe <donohoe@kde.org>
0036  */
0037 class KXMLGUI_EXPORT KKeySequenceWidget : public QWidget
0038 {
0039     Q_OBJECT
0040 
0041     /// @since 5.65
0042     Q_PROPERTY(QKeySequence keySequence READ keySequence WRITE setKeySequence NOTIFY keySequenceChanged)
0043 
0044     Q_PROPERTY(bool multiKeyShortcutsAllowed READ multiKeyShortcutsAllowed WRITE setMultiKeyShortcutsAllowed)
0045 
0046     Q_PROPERTY(ShortcutTypes checkForConflictsAgainst READ checkForConflictsAgainst WRITE setCheckForConflictsAgainst)
0047 
0048     Q_PROPERTY(bool modifierlessAllowed READ isModifierlessAllowed WRITE setModifierlessAllowed)
0049 
0050 public:
0051     /// An enum about validation when setting a key sequence.
0052     ///@see setKeySequence()
0053     enum Validation {
0054         /// Validate key sequence
0055         Validate = 0,
0056         /// Use key sequence without validation
0057         NoValidate = 1,
0058     };
0059 
0060     /**
0061      * Constructor.
0062      */
0063     explicit KKeySequenceWidget(QWidget *parent = nullptr);
0064 
0065     /**
0066      * Destructs the widget.
0067      */
0068     ~KKeySequenceWidget() override;
0069 
0070     /**
0071      * \name Configuration
0072      *
0073      * Configuration options for the widget.
0074      * @see ShortcutTypes
0075      */
0076     //@{
0077 
0078     enum ShortcutType {
0079         None = 0x00, //!< No checking for conflicts
0080         LocalShortcuts = 0x01, //!< Check with local shortcuts. @see setCheckActionCollections()
0081         StandardShortcuts = 0x02, //!< Check against standard shortcuts. @see KStandardShortcut
0082         GlobalShortcuts = 0x04, //!< Check against global shortcuts. @see KGlobalAccel
0083     };
0084     /**
0085      * Stores a combination of #ShortcutType values.
0086      */
0087     Q_DECLARE_FLAGS(ShortcutTypes, ShortcutType)
0088     Q_FLAG(ShortcutTypes)
0089 
0090     /**
0091      * Configure if the widget should check for conflicts with existing
0092      * shortcuts.
0093      *
0094      * When capturing a key sequence for local shortcuts you should check
0095      * against GlobalShortcuts and your other local shortcuts. This is the
0096      * default.
0097      *
0098      * You have to provide the local actions to check against with
0099      * setCheckActionCollections().
0100      *
0101      * When capturing a key sequence for a global shortcut you should
0102      * check against StandardShortcuts, GlobalShortcuts and your local
0103      * shortcuts.
0104      *
0105      * There are two ways to react to a user agreeing to steal a shortcut:
0106      *
0107      * 1. Listen to the stealShortcut() signal and steal the shortcuts
0108      * manually. It's your responsibility to save that change later when
0109      * you think it is appropriate.
0110      *
0111      * 2. Call applyStealShortcut() and KKeySequenceWidget will steal the
0112      * shortcut. This will save the actionCollections the shortcut is part
0113      * of so make sure it doesn't inadvertly save some unwanted changes
0114      * too. Read its documentation for some limitation when handling
0115      * global shortcuts.
0116      *
0117      * If you want to do the conflict checking yourself here are some code
0118      * snippets for global ...
0119      *
0120      * \code
0121      * QStringList conflicting = KGlobalAccel::findActionNameSystemwide(keySequence);
0122      * if (!conflicting.isEmpty()) {
0123      *     // Inform and ask the user about the conflict and reassigning
0124      *     // the keys sequence
0125      *     if (!KGlobalAccel::promptStealShortcutSystemwide(q, conflicting, keySequence)) {
0126      *         return true;
0127      *     }
0128      *     KGlobalAccel::stealShortcutSystemwide(keySequence);
0129      * }
0130      * \endcode
0131      *
0132      * ...  and standard shortcuts
0133      *
0134      * \code
0135      * KStandardShortcut::StandardShortcut ssc = KStandardShortcut::find(keySequence);
0136      * if (ssc != KStandardShortcut::AccelNone) {
0137      *     // We have a conflict
0138      * }
0139      * \endcode
0140      *
0141      *
0142      * @since 4.2
0143      */
0144     void setCheckForConflictsAgainst(ShortcutTypes types);
0145 
0146     /**
0147      * The shortcut types we check for conflicts.
0148      *
0149      * @see setCheckForConflictsAgainst()
0150      * @since 4.2
0151      */
0152     ShortcutTypes checkForConflictsAgainst() const;
0153 
0154     /**
0155      * Allow multikey shortcuts?
0156      */
0157     void setMultiKeyShortcutsAllowed(bool);
0158     bool multiKeyShortcutsAllowed() const;
0159 
0160     /**
0161      * This only applies to user input, not to setKeySequence().
0162      * Set whether to accept "plain" keys without modifiers (like Ctrl, Alt, Meta).
0163      * Plain keys by our definition include letter and symbol keys and
0164      * text editing keys (Return, Space, Tab, Backspace, Delete).
0165      * "Special" keys like F1, Cursor keys, Insert, PageDown will always work.
0166      */
0167     void setModifierlessAllowed(bool allow);
0168 
0169     /**
0170      * @see setModifierlessAllowed()
0171      */
0172     bool isModifierlessAllowed();
0173 
0174     /**
0175      * Set whether a small button to set an empty key sequence should be displayed next to the
0176      * main input widget. The default is to show the clear button.
0177      */
0178     void setClearButtonShown(bool show);
0179 
0180     //@}
0181 
0182     /**
0183      * Checks whether the key sequence @p seq is available to grab.
0184      *
0185      * The sequence is checked under the same rules as if it has been typed by
0186      * the user. This method is useful if you get key sequences from another
0187      * input source and want to check if it is save to set them.
0188      *
0189      * @since 4.2
0190      */
0191     bool isKeySequenceAvailable(const QKeySequence &seq) const;
0192 
0193     /**
0194      * Return the currently selected key sequence.
0195      */
0196     QKeySequence keySequence() const;
0197 
0198     /**
0199      * Set a list of action collections to check against for conflictuous shortcut.
0200      *
0201      * @see setCheckForConflictsAgainst()
0202      *
0203      * If a QAction with a conflicting shortcut is found inside this list and
0204      * its shortcut can be configured (KActionCollection::isShortcutConfigurable()
0205      * returns true) the user will be prompted whether to steal the shortcut
0206      * from this action.
0207      *
0208      * @since 4.1
0209      */
0210     void setCheckActionCollections(const QList<KActionCollection *> &actionCollections);
0211 
0212     /**
0213      * If the component using this widget supports shortcuts contexts, it has
0214      * to set its component name so we can check conflicts correctly.
0215      */
0216     void setComponentName(const QString &componentName);
0217 
0218 Q_SIGNALS:
0219 
0220     /**
0221      * This signal is emitted when the current key sequence has changed, be it by user
0222      * input or programmatically.
0223      */
0224     void keySequenceChanged(const QKeySequence &seq);
0225 
0226     /**
0227      * This signal is emitted after the user agreed to steal a shortcut from
0228      * an action. This is only done for local shortcuts. So you can be sure \a
0229      * action is one of the actions you provided with setCheckActionList() or
0230      * setCheckActionCollections().
0231      *
0232      * If you listen to that signal and don't call applyStealShortcut() you
0233      * are supposed to steal the shortcut and save this change.
0234      */
0235     void stealShortcut(const QKeySequence &seq, QAction *action);
0236 
0237 public Q_SLOTS:
0238 
0239     /**
0240      * Capture a shortcut from the keyboard. This call will only return once a key sequence
0241      * has been captured or input was aborted.
0242      * If a key sequence was input, keySequenceChanged() will be emitted.
0243      *
0244      * @see setModifierlessAllowed()
0245      */
0246     void captureKeySequence();
0247 
0248     /**
0249      * Set the key sequence.
0250      *
0251      * If @p val == Validate, and the call is actually changing the key sequence,
0252      * conflictuous shortcut will be checked.
0253      */
0254     void setKeySequence(const QKeySequence &seq, Validation val = NoValidate);
0255 
0256     /**
0257      * Clear the key sequence.
0258      */
0259     void clearKeySequence();
0260 
0261     /**
0262      * Actually remove the shortcut that the user wanted to steal, from the
0263      * action that was using it. This only applies to actions provided to us
0264      * by setCheckActionCollections() and setCheckActionList().
0265      *
0266      * Global and Standard Shortcuts have to be stolen immediately when the
0267      * user gives his consent (technical reasons). That means those changes
0268      * will be active even if you never call applyStealShortcut().
0269      *
0270      * To be called before you apply your changes. No local shortcuts are
0271      * stolen until this function is called.
0272      */
0273     void applyStealShortcut();
0274 
0275 private:
0276     friend class KKeySequenceWidgetPrivate;
0277     KKeySequenceWidgetPrivate *const d;
0278 
0279     bool event(QEvent *ev) override;
0280 
0281     Q_DISABLE_COPY(KKeySequenceWidget)
0282 };
0283 
0284 Q_DECLARE_OPERATORS_FOR_FLAGS(KKeySequenceWidget::ShortcutTypes)
0285 
0286 #endif // KKEYSEQUENCEWIDGET_H