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 case QAccessible::Switch:
413 if (!m_stateExplicitlySet.focusable)
414 m_state.focusable =
true;
415 if (!m_stateExplicitlySet.checkable)
416 m_state.checkable =
true;
418 case QAccessible::Button:
419 case QAccessible::MenuItem:
420 case QAccessible::PageTab:
421 case QAccessible::SpinBox:
422 case QAccessible::ComboBox:
423 case QAccessible::Terminal:
424 case QAccessible::ScrollBar:
425 if (!m_stateExplicitlySet.focusable)
426 m_state.focusable =
true;
428 case QAccessible::EditableText:
429 if (!m_stateExplicitlySet.editable)
430 m_state.editable =
true;
431 if (!m_stateExplicitlySet.focusable)
432 m_state.focusable =
true;
434 case QAccessible::StaticText:
435 if (!m_stateExplicitlySet.readOnly)
436 m_state.readOnly =
true;
437 if (!m_stateExplicitlySet.focusable)
438 m_state.focusable =
true;
446bool QQuickAccessibleAttached::wasNameExplicitlySet()
const
448 return m_nameExplicitlySet;
453void QQuickAccessibleAttached::setNameImplicitly(
const QString &name)
456 m_nameExplicitlySet =
false;
459void QQuickAccessibleAttached::setDescriptionImplicitly(
const QString &desc)
461 if (m_descriptionExplicitlySet)
463 setDescription(desc);
464 m_descriptionExplicitlySet =
false;
467QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj)
469 return new QQuickAccessibleAttached(obj);
472bool QQuickAccessibleAttached::ignored()
const
474 auto item = qobject_cast<QQuickItem *>(parent());
475 return item ? !item->d_func()->isAccessible :
false;
478void QQuickAccessibleAttached::setIgnored(
bool ignored)
480 auto item = qobject_cast<QQuickItem *>(parent());
481 if (item &&
this->ignored() != ignored) {
482 item->d_func()->isAccessible = !ignored;
483 QAccessibleEvent event(item,
484 ignored ? QAccessible::ObjectDestroyed : QAccessible::ObjectCreated);
485 QAccessible::updateAccessibility(&event);
486 emit ignoredChanged();
490bool QQuickAccessibleAttached::doAction(
const QString &actionName)
492 QMetaMethod *sig =
nullptr;
493 if (actionName == QAccessibleActionInterface::pressAction())
495 else if (actionName == QAccessibleActionInterface::toggleAction())
497 else if (actionName == QAccessibleActionInterface::increaseAction())
499 else if (actionName == QAccessibleActionInterface::decreaseAction())
501 else if (actionName == QAccessibleActionInterface::scrollUpAction())
503 else if (actionName == QAccessibleActionInterface::scrollDownAction())
504 sig = &sigScrollDown;
505 else if (actionName == QAccessibleActionInterface::scrollLeftAction())
506 sig = &sigScrollLeft;
507 else if (actionName == QAccessibleActionInterface::scrollRightAction())
508 sig = &sigScrollRight;
509 else if (actionName == QAccessibleActionInterface::previousPageAction())
510 sig = &sigPreviousPage;
511 else if (actionName == QAccessibleActionInterface::nextPageAction())
513 if (sig && isSignalConnected(*sig)) {
516 ret = sig->invoke(m_proxying);
518 ret = sig->invoke(
this);
524void QQuickAccessibleAttached::availableActions(QStringList *actions)
const
526 if (isSignalConnected(sigPress))
527 actions->append(QAccessibleActionInterface::pressAction());
528 if (isSignalConnected(sigToggle))
529 actions->append(QAccessibleActionInterface::toggleAction());
530 if (isSignalConnected(sigIncrease))
531 actions->append(QAccessibleActionInterface::increaseAction());
532 if (isSignalConnected(sigDecrease))
533 actions->append(QAccessibleActionInterface::decreaseAction());
534 if (isSignalConnected(sigScrollUp))
535 actions->append(QAccessibleActionInterface::scrollUpAction());
536 if (isSignalConnected(sigScrollDown))
537 actions->append(QAccessibleActionInterface::scrollDownAction());
538 if (isSignalConnected(sigScrollLeft))
539 actions->append(QAccessibleActionInterface::scrollLeftAction());
540 if (isSignalConnected(sigScrollRight))
541 actions->append(QAccessibleActionInterface::scrollRightAction());
542 if (isSignalConnected(sigPreviousPage))
543 actions->append(QAccessibleActionInterface::previousPageAction());
544 if (isSignalConnected(sigNextPage))
545 actions->append(QAccessibleActionInterface::nextPageAction());
548QString QQuickAccessibleAttached::stripHtml(
const QString &html)
550#ifndef QT_NO_TEXTHTMLPARSER
553 return doc.toPlainText();
559void QQuickAccessibleAttached::setProxying(QQuickAccessibleAttached *proxying)
561 if (proxying == m_proxying)
564 const QMetaObject &mo = staticMetaObject;
567 auto mo = m_proxying->metaObject();
568 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
569 for (
int signalIndex = propertyCache->signalOffset();
570 signalIndex < propertyCache->signalCount(); ++signalIndex) {
571 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
572 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
573 if (m.methodType() != QMetaMethod::Signal)
576 disconnect(m_proxying, m,
this, m);
580 m_proxying = proxying;
584 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
585 auto mo = m_proxying->metaObject();
586 for (
int signalIndex = propertyCache->signalOffset();
587 signalIndex < propertyCache->signalCount(); ++signalIndex) {
588 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
589 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
590 connect(proxying, m,
this, m);
595 for (
int prop = mo.propertyOffset(); prop < mo.propertyCount(); ++prop) {
596 const QMetaProperty p = mo.property(prop);
597 if (!p.hasNotifySignal()) {
601 const QMetaMethod signal = p.notifySignal();
602 if (signal.parameterCount() == 0)
605 signal.invoke(
this, Q_ARG(
bool, p.read(
this).toBool()));
610
611
612
613
614
615
616
617void QQuickAccessibleAttached::announce(
const QString &message, QAccessible::AnnouncementPoliteness politeness)
619 QAccessibleAnnouncementEvent event(parent(), message);
620 event.setPoliteness(politeness);
621 QAccessible::updateAccessibility(&event);
624QQuickItem *QQuickAccessibleAttached::findRelation(QAccessible::Relation relation)
const
626 const auto it = std::find_if(m_relations.cbegin(), m_relations.cend(),
627 [relation](
const auto &rel) {
628 return rel.second == relation;
631 return it != m_relations.cend() ? it->first :
nullptr;
636#include "moc_qquickaccessibleattached_p.cpp"