1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQUICKACCESSIBLEATTACHED_H
5#define QQUICKACCESSIBLEATTACHED_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtQuick/qquickitem.h>
19
20#include <QtCore/qobject.h>
21#include <QtCore/qstring.h>
22
23#if QT_CONFIG(accessibility)
24
25#include <QtGui/qaccessible.h>
26#include <private/qtquickglobal_p.h>
27#include <QtQml/qqml.h>
28
29QT_BEGIN_NAMESPACE
30
31
32#define STATE_PROPERTY(P) \
33 Q_PROPERTY(bool P READ P WRITE set_ ## P NOTIFY P ## Changed FINAL) \
34 bool P() const { return m_proxying && !m_stateExplicitlySet.P ? m_proxying->P() : m_state.P ; } \
35 void set_ ## P(bool arg) \
36 { \
37 if (m_proxying) \
38 m_proxying->set_##P(arg);\
39 m_stateExplicitlySet.P = true; \
40 if (m_state.P == arg) \
41 return; \
42 m_state.P = arg; \
43 Q_EMIT P ## Changed(arg); \
44 QAccessible::State changedState; \
45 changedState.P = true; \
46 QAccessibleStateChangeEvent ev(parent(), changedState); \
47 QAccessible::updateAccessibility(&ev); \
48 } \
49 Q_SIGNAL void P ## Changed(bool arg);
50
51class Q_QUICK_EXPORT QQuickAccessibleAttached : public QObject
52{
53 Q_OBJECT
54 Q_PROPERTY(QAccessible::Role role READ role WRITE setRole NOTIFY roleChanged FINAL)
55 Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
56 Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged FINAL)
57 Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged FINAL)
58 Q_PROPERTY(bool ignored READ ignored WRITE setIgnored NOTIFY ignoredChanged FINAL)
59 Q_PROPERTY(QQuickItem *labelledBy READ labelledBy WRITE setLabelledBy NOTIFY labelledByChanged FINAL)
60 Q_PROPERTY(QQuickItem *labelFor READ labelFor WRITE setLabelFor NOTIFY labelForChanged FINAL)
61
62 QML_NAMED_ELEMENT(Accessible)
63 QML_ADDED_IN_VERSION(2, 0)
64 QML_UNCREATABLE("Accessible is only available via attached properties.")
65 QML_ATTACHED(QQuickAccessibleAttached)
66 QML_EXTENDED_NAMESPACE(QAccessible)
67
68public:
69 STATE_PROPERTY(checkable)
70 STATE_PROPERTY(checked)
71 STATE_PROPERTY(editable)
72 STATE_PROPERTY(focusable)
73 STATE_PROPERTY(focused)
74 STATE_PROPERTY(multiLine)
75 STATE_PROPERTY(readOnly)
76 STATE_PROPERTY(selected)
77 STATE_PROPERTY(selectable)
78 STATE_PROPERTY(pressed)
79 STATE_PROPERTY(checkStateMixed)
80 STATE_PROPERTY(defaultButton)
81 STATE_PROPERTY(passwordEdit)
82 STATE_PROPERTY(selectableText)
83 STATE_PROPERTY(searchEdit)
84
85 QQuickAccessibleAttached(QObject *parent);
86 ~QQuickAccessibleAttached();
87
88 QAccessible::Role role() const { return m_role; }
89 void setRole(QAccessible::Role role);
90 QString name() const {
91 if (m_state.passwordEdit)
92 return QString();
93 if (!m_nameExplicitlySet && m_proxying && m_proxying->wasNameExplicitlySet())
94 return m_proxying->name();
95 return m_name;
96 }
97
98 bool wasNameExplicitlySet() const;
99 void setName(const QString &name) {
100 m_nameExplicitlySet = true;
101 if (name != m_name) {
102 m_name = name;
103 Q_EMIT nameChanged();
104 QAccessibleEvent ev(parent(), QAccessible::NameChanged);
105 QAccessible::updateAccessibility(event: &ev);
106 }
107 }
108 void setNameImplicitly(const QString &name);
109
110 QString description() const {
111 return !m_descriptionExplicitlySet && m_proxying ? m_proxying->description() : m_description;
112 }
113 void setDescription(const QString &description)
114 {
115 if (!m_descriptionExplicitlySet && m_proxying) {
116 disconnect(sender: m_proxying, signal: &QQuickAccessibleAttached::descriptionChanged, receiver: this, slot: &QQuickAccessibleAttached::descriptionChanged);
117 }
118 m_descriptionExplicitlySet = true;
119 if (m_description != description) {
120 m_description = description;
121 Q_EMIT descriptionChanged();
122 QAccessibleEvent ev(parent(), QAccessible::DescriptionChanged);
123 QAccessible::updateAccessibility(event: &ev);
124 }
125 }
126 void setDescriptionImplicitly(const QString &desc);
127
128 QString id() const { return m_id; }
129 void setId(const QString &id)
130 {
131 if (m_id != id) {
132 m_id = id;
133 Q_EMIT idChanged();
134 QAccessibleEvent ev(parent(), QAccessible::IdentifierChanged);
135 QAccessible::updateAccessibility(event: &ev);
136 }
137 }
138
139 QQuickItem *labelledBy() const
140 {
141 return findRelation(relation: QAccessible::Labelled);
142 }
143
144 void setLabelledBy(QQuickItem *labelledBy)
145 {
146 setLabelledByInternal(labelledBy);
147
148 QQuickAccessibleAttached *label = qobject_cast<QQuickAccessibleAttached *>(
149 object: qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: labelledBy));
150
151 label->setLabelForInternal(qobject_cast<QQuickItem *>(o: parent()));
152 }
153 void setLabelledByInternal(QQuickItem *labelledBy)
154 {
155 m_relations.append(t: { labelledBy, QAccessible::Labelled });
156 Q_EMIT labelledByChanged();
157 }
158
159 QQuickItem *labelFor() const
160 {
161 return findRelation(relation: QAccessible::Label);
162 }
163
164 void setLabelFor(QQuickItem *labelFor)
165 {
166 setLabelForInternal(labelFor);
167
168 QQuickAccessibleAttached *labelled = qobject_cast<QQuickAccessibleAttached *>(
169 object: qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: labelFor));
170 labelled->setLabelledBy(qobject_cast<QQuickItem *>(o: parent()));
171 }
172
173 void setLabelForInternal(QQuickItem *labelFor)
174 {
175 m_relations.append(t: { labelFor, QAccessible::Label });
176 Q_EMIT labelForChanged();
177 }
178
179 // Factory function
180 static QQuickAccessibleAttached *qmlAttachedProperties(QObject *obj);
181
182 static QQuickAccessibleAttached *attachedProperties(const QObject *obj)
183 {
184 return qobject_cast<QQuickAccessibleAttached*>(object: qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj, create: false));
185 }
186
187 // Property getter
188 static QVariant property(const QObject *object, const char *propertyName)
189 {
190 if (QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(obj: object))
191 return attachedObject->property(name: propertyName);
192 return QVariant();
193 }
194
195 static bool setProperty(QObject *object, const char *propertyName, const QVariant &value)
196 {
197 QObject *obj = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: object, create: true);
198 if (!obj) {
199 qWarning(msg: "cannot set property Accessible.%s of QObject %s", propertyName, object->metaObject()->className());
200 return false;
201 }
202 return obj->setProperty(name: propertyName, value);
203 }
204
205 static QObject *findAccessible(QObject *object, QAccessible::Role role = QAccessible::NoRole)
206 {
207 while (object) {
208 QQuickAccessibleAttached *att = QQuickAccessibleAttached::attachedProperties(obj: object);
209 if (att && (role == QAccessible::NoRole || att->role() == role)) {
210 break;
211 }
212 if (auto action = object->property(name: "action").value<QObject *>(); action) {
213 QQuickAccessibleAttached *att = QQuickAccessibleAttached::attachedProperties(obj: action);
214 if (att && (role == QAccessible::NoRole || att->role() == role)) {
215 object = action;
216 break;
217 }
218 }
219 object = object->parent();
220 }
221 return object;
222 }
223
224 QAccessible::State state() const { return m_state; }
225 bool ignored() const;
226 bool doAction(const QString &actionName);
227 void availableActions(QStringList *actions) const;
228
229 Q_REVISION(6, 2) Q_INVOKABLE static QString stripHtml(const QString &html);
230 void setProxying(QQuickAccessibleAttached *proxying);
231
232 Q_REVISION(6, 8) Q_INVOKABLE void announce(const QString &message, QAccessible::AnnouncementPoliteness politeness = QAccessible::AnnouncementPoliteness::Polite);
233
234public Q_SLOTS:
235 void valueChanged() {
236 QAccessibleValueChangeEvent ev(parent(), parent()->property(name: "value"));
237 QAccessible::updateAccessibility(event: &ev);
238 }
239 void cursorPositionChanged() {
240 QAccessibleTextCursorEvent ev(parent(), parent()->property(name: "cursorPosition").toInt());
241 QAccessible::updateAccessibility(event: &ev);
242 }
243
244 void setIgnored(bool ignored);
245
246Q_SIGNALS:
247 void roleChanged();
248 void nameChanged();
249 void descriptionChanged();
250 void idChanged();
251 void ignoredChanged();
252 void labelledByChanged();
253 void labelForChanged();
254 void pressAction();
255 void toggleAction();
256 void increaseAction();
257 void decreaseAction();
258 void scrollUpAction();
259 void scrollDownAction();
260 void scrollLeftAction();
261 void scrollRightAction();
262 void previousPageAction();
263 void nextPageAction();
264
265private:
266 QQuickItem *findRelation(QAccessible::Relation relation) const;
267
268 QAccessible::Role m_role;
269 QAccessible::State m_state;
270 QAccessible::State m_stateExplicitlySet;
271 QString m_name;
272 bool m_nameExplicitlySet = false;
273 QString m_description;
274 bool m_descriptionExplicitlySet = false;
275 QQuickAccessibleAttached* m_proxying = nullptr;
276 QString m_id;
277 QList<std::pair<QQuickItem *, QAccessible::Relation>> m_relations;
278
279 static QMetaMethod sigPress;
280 static QMetaMethod sigToggle;
281 static QMetaMethod sigIncrease;
282 static QMetaMethod sigDecrease;
283 static QMetaMethod sigScrollUp;
284 static QMetaMethod sigScrollDown;
285 static QMetaMethod sigScrollLeft;
286 static QMetaMethod sigScrollRight;
287 static QMetaMethod sigPreviousPage;
288 static QMetaMethod sigNextPage;
289
290public:
291 using QObject::property;
292};
293
294
295QT_END_NAMESPACE
296
297#endif // accessibility
298
299#endif
300

source code of qtdeclarative/src/quick/items/qquickaccessibleattached_p.h