File indexing completed on 2024-04-28 15:27:43
0001 /* 0002 * SPDX-FileCopyrightText: 2017 Marco Martin <mart@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef MNEMONICATTACHED_H 0008 #define MNEMONICATTACHED_H 0009 0010 #include <QObject> 0011 #include <QQuickWindow> 0012 0013 /** 0014 * @brief This attached property allows to define keyboard sequences to trigger 0015 * actions based upon their text. 0016 * 0017 * A mnemonic, otherwise known as an accelerator, is an accessibility feature to 0018 * signal to the user that a certain action (typically in a menu) can be 0019 * triggered by pressing Alt + a certain key that is indicated by an ampersand 0020 * sign (&). For instance, a File menu could be marked in code as &File and 0021 * would be displayed to the user with an underscore under the letter F. This 0022 * allows to invoke actions without having to navigate the UI with a mouse. 0023 * 0024 * This class automates the management of mnemonics, so if a key is already 0025 * taken, the next available key is used. Likewise, certain components get 0026 * increased priority: an "OK/Cancel" buttons in a Dialog will have priority 0027 * over fields of a org::kde::kirigami::FormLayout. 0028 * 0029 * Mnemonics are already managed by visual QtQuick and Kirigami controls, so 0030 * only use this class to implement your own visual QML controls. 0031 * 0032 * @see ::ControlType 0033 * 0034 * @since org.kde.kirigami 2.3 0035 */ 0036 class MnemonicAttached : public QObject 0037 { 0038 Q_OBJECT 0039 /** 0040 * @brief This property holds the label of the control that we want to 0041 * compute a mnemonic for. 0042 * 0043 * For example: ``"Label:"`` or ``"&Ok"`` 0044 */ 0045 Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) 0046 0047 /** 0048 * @brief This property holds the user-visible final label. 0049 * 0050 * The user-visible final label, which will have the shortcut letter 0051 * underlined, such as "<u>O</u>k". 0052 */ 0053 Q_PROPERTY(QString richTextLabel READ richTextLabel NOTIFY richTextLabelChanged) 0054 0055 /** 0056 * @brief This property holds the label with an "&" mnemonic in the place 0057 * which defines the shortcut key. 0058 * 0059 * @note The "&" will be automatically added if it is not set by the 0060 * user. 0061 */ 0062 Q_PROPERTY(QString mnemonicLabel READ mnemonicLabel NOTIFY mnemonicLabelChanged) 0063 0064 /** 0065 * @brief This property sets whether this mnemonic is enabled. 0066 * 0067 * Set this to @c false to disable the accelerator marker (&) and its 0068 * respective shortcut. 0069 * 0070 * default: ``true`` 0071 */ 0072 Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) 0073 0074 /** 0075 * @brief This property holds the control type that this mnemonic is 0076 * attached to. 0077 * 0078 * @note Different types of controls have different importance and priority 0079 * for shortcut assignment. 0080 * 0081 * @see ::ControlType 0082 */ 0083 Q_PROPERTY(MnemonicAttached::ControlType controlType READ controlType WRITE setControlType NOTIFY controlTypeChanged) 0084 0085 /** 0086 * @brief This property holds the final key sequence. 0087 * 0088 * @note The final key sequence will be Alt+alphanumeric char. 0089 */ 0090 Q_PROPERTY(QKeySequence sequence READ sequence NOTIFY sequenceChanged) 0091 0092 /** 0093 * @brief This property holds whether the user is pressing alt and 0094 * accelerators should be shown. 0095 * 0096 * @since KDE Frameworks 5.72 0097 * @since org.kde.kirigami 2.15 0098 */ 0099 Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) 0100 0101 public: 0102 enum ControlType { 0103 ActionElement, /**< pushbuttons, checkboxes etc */ 0104 DialogButton, /**< buttons for dialogs */ 0105 MenuItem, /**< Menu items */ 0106 FormLabel, /**< Buddy label in a FormLayout*/ 0107 SecondaryControl, /**< Other controls that are considered not much important and low priority for shortcuts */ 0108 }; 0109 Q_ENUM(ControlType) 0110 0111 explicit MnemonicAttached(QObject *parent = nullptr); 0112 ~MnemonicAttached() override; 0113 0114 void setLabel(const QString &text); 0115 QString label() const; 0116 0117 QString richTextLabel() const; 0118 QString mnemonicLabel() const; 0119 0120 void setEnabled(bool enabled); 0121 bool enabled() const; 0122 0123 void setControlType(MnemonicAttached::ControlType controlType); 0124 ControlType controlType() const; 0125 0126 QKeySequence sequence(); 0127 0128 void setActive(bool active); 0129 bool active() const; 0130 0131 // QML attached property 0132 static MnemonicAttached *qmlAttachedProperties(QObject *object); 0133 0134 protected: 0135 bool eventFilter(QObject *watched, QEvent *e) override; 0136 void updateSequence(); 0137 0138 Q_SIGNALS: 0139 void labelChanged(); 0140 void enabledChanged(); 0141 void sequenceChanged(); 0142 void richTextLabelChanged(); 0143 void mnemonicLabelChanged(); 0144 void controlTypeChanged(); 0145 void activeChanged(); 0146 0147 private: 0148 void calculateWeights(); 0149 bool installEventFilterForWindow(QQuickWindow *wnd); 0150 bool removeEventFilterForWindow(QQuickWindow *wnd); 0151 0152 // TODO: to have support for DIALOG_BUTTON_EXTRA_WEIGHT etc, a type enum should be exported 0153 enum { 0154 // Additional weight for first character in string 0155 FIRST_CHARACTER_EXTRA_WEIGHT = 50, 0156 // Additional weight for the beginning of a word 0157 WORD_BEGINNING_EXTRA_WEIGHT = 50, 0158 // Additional weight for a 'wanted' accelerator ie string with '&' 0159 WANTED_ACCEL_EXTRA_WEIGHT = 150, 0160 // Default weight for an 'action' widget (ie, pushbuttons) 0161 ACTION_ELEMENT_WEIGHT = 50, 0162 // Additional weight for the dialog buttons (large, we basically never want these reassigned) 0163 DIALOG_BUTTON_EXTRA_WEIGHT = 300, 0164 // Weight for FormLayout labels (low) 0165 FORM_LABEL_WEIGHT = 20, 0166 // Weight for Secondary controls which are considered less important (low) 0167 SECONDARY_CONTROL_WEIGHT = 10, 0168 // Default weight for menu items 0169 MENU_ITEM_WEIGHT = 250, 0170 }; 0171 0172 // order word letters by weight 0173 int m_weight = 0; 0174 int m_baseWeight = 0; 0175 ControlType m_controlType = SecondaryControl; 0176 QMap<int, QChar> m_weights; 0177 0178 QString m_label; 0179 QString m_actualRichTextLabel; 0180 QString m_richTextLabel; 0181 QString m_mnemonicLabel; 0182 QKeySequence m_sequence; 0183 bool m_enabled = true; 0184 bool m_active = false; 0185 0186 QPointer<QQuickWindow> m_window; 0187 0188 // global mapping of mnemonics 0189 // TODO: map by QWindow 0190 static QHash<QKeySequence, MnemonicAttached *> s_sequenceToObject; 0191 }; 0192 0193 QML_DECLARE_TYPEINFO(MnemonicAttached, QML_HAS_ATTACHED_PROPERTIES) 0194 0195 #endif // MnemonicATTACHED_H