1/*
2 * SPDX-FileCopyrightText: 2017 Marco Martin <mart@kde.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#ifndef MNEMONICATTACHED_H
8#define MNEMONICATTACHED_H
9
10#include <QObject>
11#include <QQuickWindow>
12
13#include <QQmlEngine>
14
15/**
16 * This Attached property is used to calculate automated keyboard sequences
17 * to trigger actions based upon their text: if an "&" mnemonic is
18 * used (ie "&Ok"), the system will attempt to assign the desired letter giving
19 * it priority, otherwise a letter among the ones in the label will be used if
20 * possible and not conflicting.
21 * Different kinds of controls will have different priorities in assigning the
22 * shortcut: for instance the "Ok/Cancel" buttons in a dialog will have priority
23 * over fields of a FormLayout.
24 * @see ControlType
25 *
26 * Usually the developer shouldn't use this directly as base components
27 * already use this, but only when implementing a custom graphical Control.
28 * @since 2.3
29 */
30class MnemonicAttached : public QObject
31{
32 Q_OBJECT
33 QML_NAMED_ELEMENT(MnemonicData)
34 QML_ATTACHED(MnemonicAttached)
35 QML_UNCREATABLE("Cannot create objects of type MnemonicData, use it as an attached property")
36 /**
37 * The label of the control we want to compute a mnemonic for, instance
38 * "Label:" or "&Ok"
39 */
40 Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged FINAL)
41
42 /**
43 * The user-visible final label, which will have the shortcut letter underlined,
44 * such as "&lt;u&gt;O&lt;/u&gt;k"
45 */
46 Q_PROPERTY(QString richTextLabel READ richTextLabel NOTIFY richTextLabelChanged FINAL)
47
48 /**
49 * The label with an "&" mnemonic in the place which will have the shortcut
50 * assigned, regardless of whether the & was assigned by the user or automatically generated.
51 */
52 Q_PROPERTY(QString mnemonicLabel READ mnemonicLabel NOTIFY mnemonicLabelChanged FINAL)
53
54 /**
55 * Only if true this mnemonic will be considered for the global assignment
56 * default: true
57 */
58 Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged FINAL)
59
60 /**
61 * The type of control this mnemonic is attached: different types of controls have different importance and priority for shortcut assignment.
62 * @see ControlType
63 */
64 Q_PROPERTY(MnemonicAttached::ControlType controlType READ controlType WRITE setControlType NOTIFY controlTypeChanged FINAL)
65
66 /**
67 * The final key sequence assigned, if any: it will be Alt+alphanumeric char
68 */
69 Q_PROPERTY(QKeySequence sequence READ sequence NOTIFY sequenceChanged FINAL)
70
71 /**
72 * True when the user is pressing alt and the accelerators should be shown
73 *
74 * @since 5.72
75 * @since 2.15
76 */
77 Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged FINAL)
78
79public:
80 enum ControlType {
81 ActionElement, /**< pushbuttons, checkboxes etc */
82 DialogButton, /**< buttons for dialogs */
83 MenuItem, /**< Menu items */
84 FormLabel, /**< Buddy label in a FormLayout*/
85 SecondaryControl, /**< Other controls that are considered not much important and low priority for shortcuts */
86 };
87 Q_ENUM(ControlType)
88
89 explicit MnemonicAttached(QObject *parent = nullptr);
90 ~MnemonicAttached() override;
91
92 void setLabel(const QString &text);
93 QString label() const;
94
95 QString richTextLabel() const;
96 QString mnemonicLabel() const;
97
98 void setEnabled(bool enabled);
99 bool enabled() const;
100
101 void setControlType(MnemonicAttached::ControlType controlType);
102 ControlType controlType() const;
103
104 QKeySequence sequence();
105
106 void setActive(bool active);
107 bool active() const;
108
109 // QML attached property
110 static MnemonicAttached *qmlAttachedProperties(QObject *object);
111
112protected:
113 void updateSequence();
114
115Q_SIGNALS:
116 void labelChanged();
117 void enabledChanged();
118 void sequenceChanged();
119 void richTextLabelChanged();
120 void mnemonicLabelChanged();
121 void controlTypeChanged();
122 void activeChanged();
123
124private:
125 QWindow *window() const;
126
127 void onAltPressed();
128 void onAltReleased();
129
130 void calculateWeights();
131
132 // TODO: to have support for DIALOG_BUTTON_EXTRA_WEIGHT etc, a type enum should be exported
133 enum {
134 // Additional weight for first character in string
135 FIRST_CHARACTER_EXTRA_WEIGHT = 50,
136 // Additional weight for the beginning of a word
137 WORD_BEGINNING_EXTRA_WEIGHT = 50,
138 // Additional weight for a 'wanted' accelerator ie string with '&'
139 WANTED_ACCEL_EXTRA_WEIGHT = 150,
140 // Default weight for an 'action' widget (ie, pushbuttons)
141 ACTION_ELEMENT_WEIGHT = 50,
142 // Additional weight for the dialog buttons (large, we basically never want these reassigned)
143 DIALOG_BUTTON_EXTRA_WEIGHT = 300,
144 // Weight for FormLayout labels (low)
145 FORM_LABEL_WEIGHT = 20,
146 // Weight for Secondary controls which are considered less important (low)
147 SECONDARY_CONTROL_WEIGHT = 10,
148 // Default weight for menu items
149 MENU_ITEM_WEIGHT = 250,
150 };
151
152 // order word letters by weight
153 int m_weight = 0;
154 int m_baseWeight = 0;
155 ControlType m_controlType = SecondaryControl;
156 QMap<int, QChar> m_weights;
157
158 QString m_label;
159 QString m_actualRichTextLabel;
160 QString m_richTextLabel;
161 QString m_mnemonicLabel;
162 QKeySequence m_sequence;
163 bool m_enabled = true;
164 bool m_active = false;
165
166 QPointer<QQuickWindow> m_window;
167
168 // global mapping of mnemonics
169 // TODO: map by QWindow
170 static QHash<QKeySequence, MnemonicAttached *> s_sequenceToObject;
171};
172
173QML_DECLARE_TYPEINFO(MnemonicAttached, QML_HAS_ATTACHED_PROPERTIES)
174
175#endif // MnemonicATTACHED_H
176

source code of kirigami/src/mnemonicattached.h