7#if QT_CONFIG(accessibility)
9#include <QtQml/qqmlinfo.h>
11#include "private/qquickitem_p.h"
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
62
63
64
65
66
67
68
69
72
73
74
75
76
77
78
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
125
126
127
128
129
130
131
134
135
136
137
138
139
140
142
143
144
145
146
147
149
150
151
152
153
155
156
157
158
159
161
162
163
164
166
167
168
169
170
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
199
200
201
202
204
205
206
207
208
210
211
212
213
214
216
217
218
219
220
222
223
224
225
227
228
229
230
231
233
234
235
236
238
239
240
241
243
244
245
246
248
249
250
251
252
253
254
255
257
258
259
260
261
262
263
264
267
268
269
270
272
273
274
275
277
278
279
280
282
283
284
285
287
288
289
290
292
293
294
295
297
298
299
300
302
303
304
305
307
308
309
310
312
313
314
315
317QMetaMethod QQuickAccessibleAttached::sigPress;
318QMetaMethod QQuickAccessibleAttached::sigToggle;
319QMetaMethod QQuickAccessibleAttached::sigIncrease;
320QMetaMethod QQuickAccessibleAttached::sigDecrease;
321QMetaMethod QQuickAccessibleAttached::sigScrollUp;
322QMetaMethod QQuickAccessibleAttached::sigScrollDown;
323QMetaMethod QQuickAccessibleAttached::sigScrollLeft;
324QMetaMethod QQuickAccessibleAttached::sigScrollRight;
325QMetaMethod QQuickAccessibleAttached::sigPreviousPage;
326QMetaMethod QQuickAccessibleAttached::sigNextPage;
328QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
329 : QObject(parent), m_role(QAccessible::NoRole)
334 auto item = qobject_cast<QQuickItem *>(parent);
336 item->d_func()->setAccessible();
338 const QLatin1StringView className(QQmlData::ensurePropertyCache(parent)->firstCppMetaObject()->className());
339 if (className != QLatin1StringView(
"QQuickAction")) {
340 qmlWarning(parent) <<
"Accessible attached property must be attached to an object deriving from Item or Action";
344 QAccessibleEvent ev(parent, QAccessible::ObjectCreated);
345 QAccessible::updateAccessibility(&ev);
347 if (
const QMetaObject *pmo = parent->metaObject()) {
348 auto connectPropertyChangeSignal = [parent, pmo,
this](
349 const char *propertyName,
const char *signalName,
int slotIndex)
358 int idxProperty = pmo->indexOfProperty(propertyName);
359 if (idxProperty != -1) {
360 const QMetaProperty property = pmo->property(idxProperty);
361 const QMetaMethod signal = property.notifySignal();
362 if (signal.name() == signalName)
363 QMetaObject::connect(parent, signal.methodIndex(),
this, slotIndex);
367 const QMetaObject &smo = staticMetaObject;
369 QAccessibleInterface *iface = ev.accessibleInterface();
370 if (iface && iface->valueInterface()) {
371 static const int valueChangedIndex = smo.indexOfSlot(
"valueChanged()");
372 connectPropertyChangeSignal(
"value",
"valueChanged", valueChangedIndex);
375 if (iface && iface->textInterface()) {
376 static const int cursorPositionChangedIndex =
377 smo.indexOfSlot(
"cursorPositionChanged()");
378 connectPropertyChangeSignal(
"cursorPosition",
"cursorPositionChanged",
379 cursorPositionChangedIndex);
383 if (!sigPress.isValid()) {
384 sigPress = QMetaMethod::fromSignal(&QQuickAccessibleAttached::pressAction);
385 sigToggle = QMetaMethod::fromSignal(&QQuickAccessibleAttached::toggleAction);
386 sigIncrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::increaseAction);
387 sigDecrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::decreaseAction);
388 sigScrollUp = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollUpAction);
389 sigScrollDown = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollDownAction);
390 sigScrollLeft = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollLeftAction);
391 sigScrollRight = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollRightAction);
392 sigPreviousPage = QMetaMethod::fromSignal(&QQuickAccessibleAttached::previousPageAction);
393 sigNextPage= QMetaMethod::fromSignal(&QQuickAccessibleAttached::nextPageAction);
397QQuickAccessibleAttached::~QQuickAccessibleAttached()
401void QQuickAccessibleAttached::setRole(QAccessible::Role role)
403 if (role != m_role) {
405 Q_EMIT roleChanged();
410 case QAccessible::CheckBox:
411 case QAccessible::RadioButton:
412 if (!m_stateExplicitlySet.focusable)
413 m_state.focusable =
true;
414 if (!m_stateExplicitlySet.checkable)
415 m_state.checkable =
true;
417 case QAccessible::Button:
418 case QAccessible::MenuItem:
419 case QAccessible::PageTab:
420 case QAccessible::SpinBox:
421 case QAccessible::ComboBox:
422 case QAccessible::Terminal:
423 case QAccessible::ScrollBar:
424 if (!m_stateExplicitlySet.focusable)
425 m_state.focusable =
true;
427 case QAccessible::EditableText:
428 if (!m_stateExplicitlySet.editable)
429 m_state.editable =
true;
430 if (!m_stateExplicitlySet.focusable)
431 m_state.focusable =
true;
433 case QAccessible::StaticText:
434 if (!m_stateExplicitlySet.readOnly)
435 m_state.readOnly =
true;
436 if (!m_stateExplicitlySet.focusable)
437 m_state.focusable =
true;
445bool QQuickAccessibleAttached::wasNameExplicitlySet()
const
447 return m_nameExplicitlySet;
452void QQuickAccessibleAttached::setNameImplicitly(
const QString &name)
455 m_nameExplicitlySet =
false;
458void QQuickAccessibleAttached::setDescriptionImplicitly(
const QString &desc)
460 if (m_descriptionExplicitlySet)
462 setDescription(desc);
463 m_descriptionExplicitlySet =
false;
466QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj)
468 return new QQuickAccessibleAttached(obj);
471bool QQuickAccessibleAttached::ignored()
const
473 auto item = qobject_cast<QQuickItem *>(parent());
474 return item ? !item->d_func()->isAccessible :
false;
477void QQuickAccessibleAttached::setIgnored(
bool ignored)
479 auto item = qobject_cast<QQuickItem *>(parent());
480 if (item &&
this->ignored() != ignored) {
481 item->d_func()->isAccessible = !ignored;
482 QAccessibleEvent event(item,
483 ignored ? QAccessible::ObjectDestroyed : QAccessible::ObjectCreated);
484 QAccessible::updateAccessibility(&event);
485 emit ignoredChanged();
489bool QQuickAccessibleAttached::doAction(
const QString &actionName)
491 QMetaMethod *sig =
nullptr;
492 if (actionName == QAccessibleActionInterface::pressAction())
494 else if (actionName == QAccessibleActionInterface::toggleAction())
496 else if (actionName == QAccessibleActionInterface::increaseAction())
498 else if (actionName == QAccessibleActionInterface::decreaseAction())
500 else if (actionName == QAccessibleActionInterface::scrollUpAction())
502 else if (actionName == QAccessibleActionInterface::scrollDownAction())
503 sig = &sigScrollDown;
504 else if (actionName == QAccessibleActionInterface::scrollLeftAction())
505 sig = &sigScrollLeft;
506 else if (actionName == QAccessibleActionInterface::scrollRightAction())
507 sig = &sigScrollRight;
508 else if (actionName == QAccessibleActionInterface::previousPageAction())
509 sig = &sigPreviousPage;
510 else if (actionName == QAccessibleActionInterface::nextPageAction())
512 if (sig && isSignalConnected(*sig)) {
515 ret = sig->invoke(m_proxying);
517 ret = sig->invoke(
this);
523void QQuickAccessibleAttached::availableActions(QStringList *actions)
const
525 if (isSignalConnected(sigPress))
526 actions->append(QAccessibleActionInterface::pressAction());
527 if (isSignalConnected(sigToggle))
528 actions->append(QAccessibleActionInterface::toggleAction());
529 if (isSignalConnected(sigIncrease))
530 actions->append(QAccessibleActionInterface::increaseAction());
531 if (isSignalConnected(sigDecrease))
532 actions->append(QAccessibleActionInterface::decreaseAction());
533 if (isSignalConnected(sigScrollUp))
534 actions->append(QAccessibleActionInterface::scrollUpAction());
535 if (isSignalConnected(sigScrollDown))
536 actions->append(QAccessibleActionInterface::scrollDownAction());
537 if (isSignalConnected(sigScrollLeft))
538 actions->append(QAccessibleActionInterface::scrollLeftAction());
539 if (isSignalConnected(sigScrollRight))
540 actions->append(QAccessibleActionInterface::scrollRightAction());
541 if (isSignalConnected(sigPreviousPage))
542 actions->append(QAccessibleActionInterface::previousPageAction());
543 if (isSignalConnected(sigNextPage))
544 actions->append(QAccessibleActionInterface::nextPageAction());
547QString QQuickAccessibleAttached::stripHtml(
const QString &html)
549#ifndef QT_NO_TEXTHTMLPARSER
552 return doc.toPlainText();
558void QQuickAccessibleAttached::setProxying(QQuickAccessibleAttached *proxying)
560 if (proxying == m_proxying)
563 const QMetaObject &mo = staticMetaObject;
566 auto mo = m_proxying->metaObject();
567 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
568 for (
int signalIndex = propertyCache->signalOffset();
569 signalIndex < propertyCache->signalCount(); ++signalIndex) {
570 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
571 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
572 if (m.methodType() != QMetaMethod::Signal)
575 disconnect(m_proxying, m,
this, m);
579 m_proxying = proxying;
583 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
584 auto mo = m_proxying->metaObject();
585 for (
int signalIndex = propertyCache->signalOffset();
586 signalIndex < propertyCache->signalCount(); ++signalIndex) {
587 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
588 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
589 connect(proxying, m,
this, m);
594 for (
int prop = mo.propertyOffset(); prop < mo.propertyCount(); ++prop) {
595 const QMetaProperty p = mo.property(prop);
596 if (!p.hasNotifySignal()) {
600 const QMetaMethod signal = p.notifySignal();
601 if (signal.parameterCount() == 0)
604 signal.invoke(
this, Q_ARG(
bool, p.read(
this).toBool()));
609
610
611
612
613
614
615
616void QQuickAccessibleAttached::announce(
const QString &message, QAccessible::AnnouncementPoliteness politeness)
618 QAccessibleAnnouncementEvent event(parent(), message);
619 event.setPoliteness(politeness);
620 QAccessible::updateAccessibility(&event);
623QQuickItem *QQuickAccessibleAttached::findRelation(QAccessible::Relation relation)
const
625 const auto it = std::find_if(m_relations.cbegin(), m_relations.cend(),
626 [relation](
const auto &rel) {
627 return rel.second == relation;
630 return it != m_relations.cend() ? it->first :
nullptr;
635#include "moc_qquickaccessibleattached_p.cpp"