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
165
166
168
169
170
171
172
173
175
176
177
178
180
181
182
183
184
186
187
188
189
190
191
192
193
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
222
223
224
225
227
228
229
230
231
233
234
235
236
237
239
240
241
242
243
245
246
247
248
250
251
252
253
254
256
257
258
259
261
262
263
264
266
267
268
269
271
272
273
274
275
276
277
278
280
281
282
283
284
285
286
287
290
291
292
293
295
296
297
298
300
301
302
303
305
306
307
308
310
311
312
313
314
316
317
318
319
321
322
323
324
326
327
328
329
331
332
333
334
336
337
338
339
341
342
343
344
346QMetaMethod QQuickAccessibleAttached::sigPress;
347QMetaMethod QQuickAccessibleAttached::sigToggle;
348QMetaMethod QQuickAccessibleAttached::sigIncrease;
349QMetaMethod QQuickAccessibleAttached::sigDecrease;
350QMetaMethod QQuickAccessibleAttached::sigShowOnScreen;
351QMetaMethod QQuickAccessibleAttached::sigScrollUp;
352QMetaMethod QQuickAccessibleAttached::sigScrollDown;
353QMetaMethod QQuickAccessibleAttached::sigScrollLeft;
354QMetaMethod QQuickAccessibleAttached::sigScrollRight;
355QMetaMethod QQuickAccessibleAttached::sigPreviousPage;
356QMetaMethod QQuickAccessibleAttached::sigNextPage;
358QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
359 : QObject(parent), m_role(QAccessible::NoRole)
364 auto item = qobject_cast<QQuickItem *>(parent);
366 item->d_func()->setAccessible();
368 const QLatin1StringView className(QQmlData::ensurePropertyCache(parent)->firstCppMetaObject()->className());
369 if (className != QLatin1StringView(
"QQuickAction")) {
370 qmlWarning(parent) <<
"Accessible attached property must be attached to an object deriving from Item or Action";
374 QAccessibleEvent ev(parent, QAccessible::ObjectCreated);
375 QAccessible::updateAccessibility(&ev);
377 if (
const QMetaObject *pmo = parent->metaObject()) {
378 auto connectPropertyChangeSignal = [parent, pmo,
this](
379 const char *propertyName,
const char *signalName,
int slotIndex)
388 int idxProperty = pmo->indexOfProperty(propertyName);
389 if (idxProperty != -1) {
390 const QMetaProperty property = pmo->property(idxProperty);
391 const QMetaMethod signal = property.notifySignal();
392 if (signal.name() == signalName)
393 QMetaObject::connect(parent, signal.methodIndex(),
this, slotIndex);
397 const QMetaObject &smo = staticMetaObject;
399 QAccessibleInterface *iface = ev.accessibleInterface();
400 if (iface && iface->valueInterface()) {
401 static const int valueChangedIndex = smo.indexOfSlot(
"valueChanged()");
402 connectPropertyChangeSignal(
"value",
"valueChanged", valueChangedIndex);
405 if (iface && iface->textInterface()) {
406 static const int cursorPositionChangedIndex =
407 smo.indexOfSlot(
"cursorPositionChanged()");
408 connectPropertyChangeSignal(
"cursorPosition",
"cursorPositionChanged",
409 cursorPositionChangedIndex);
413 if (!sigPress.isValid()) {
414 sigPress = QMetaMethod::fromSignal(&QQuickAccessibleAttached::pressAction);
415 sigToggle = QMetaMethod::fromSignal(&QQuickAccessibleAttached::toggleAction);
416 sigIncrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::increaseAction);
417 sigDecrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::decreaseAction);
418 sigShowOnScreen = QMetaMethod::fromSignal(&QQuickAccessibleAttached::showOnScreenAction);
419 sigScrollUp = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollUpAction);
420 sigScrollDown = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollDownAction);
421 sigScrollLeft = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollLeftAction);
422 sigScrollRight = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollRightAction);
423 sigPreviousPage = QMetaMethod::fromSignal(&QQuickAccessibleAttached::previousPageAction);
424 sigNextPage= QMetaMethod::fromSignal(&QQuickAccessibleAttached::nextPageAction);
428QQuickAccessibleAttached::~QQuickAccessibleAttached()
432void QQuickAccessibleAttached::setRole(QAccessible::Role role)
434 if (role != m_role) {
436 Q_EMIT roleChanged();
441 case QAccessible::CheckBox:
442 case QAccessible::RadioButton:
443 case QAccessible::Switch:
444 if (!m_stateExplicitlySet.focusable)
445 m_state.focusable =
true;
446 if (!m_stateExplicitlySet.checkable)
447 m_state.checkable =
true;
449 case QAccessible::Button:
450 case QAccessible::MenuItem:
451 case QAccessible::PageTab:
452 case QAccessible::SpinBox:
453 case QAccessible::ComboBox:
454 case QAccessible::Terminal:
455 case QAccessible::ScrollBar:
456 if (!m_stateExplicitlySet.focusable)
457 m_state.focusable =
true;
459 case QAccessible::EditableText:
460 if (!m_stateExplicitlySet.editable)
461 m_state.editable =
true;
462 if (!m_stateExplicitlySet.focusable)
463 m_state.focusable =
true;
465 case QAccessible::StaticText:
466 if (!m_stateExplicitlySet.readOnly)
467 m_state.readOnly =
true;
468 if (!m_stateExplicitlySet.focusable)
469 m_state.focusable =
true;
477bool QQuickAccessibleAttached::wasNameExplicitlySet()
const
479 return m_nameExplicitlySet;
484void QQuickAccessibleAttached::setNameImplicitly(
const QString &name)
487 m_nameExplicitlySet =
false;
490void QQuickAccessibleAttached::setDescriptionImplicitly(
const QString &desc)
492 if (m_descriptionExplicitlySet)
494 setDescription(desc);
495 m_descriptionExplicitlySet =
false;
498QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj)
500 return new QQuickAccessibleAttached(obj);
503bool QQuickAccessibleAttached::ignored()
const
505 auto item = qobject_cast<QQuickItem *>(parent());
506 return item ? !item->d_func()->isAccessible :
false;
509void QQuickAccessibleAttached::setIgnored(
bool ignored)
511 auto item = qobject_cast<QQuickItem *>(parent());
512 if (item &&
this->ignored() != ignored) {
513 item->d_func()->isAccessible = !ignored;
514 QAccessibleEvent event(item,
515 ignored ? QAccessible::ObjectDestroyed : QAccessible::ObjectCreated);
516 QAccessible::updateAccessibility(&event);
517 emit ignoredChanged();
521bool QQuickAccessibleAttached::doAction(
const QString &actionName)
523 QMetaMethod *sig =
nullptr;
524 if (actionName == QAccessibleActionInterface::pressAction())
526 else if (actionName == QAccessibleActionInterface::toggleAction())
528 else if (actionName == QAccessibleActionInterface::increaseAction())
530 else if (actionName == QAccessibleActionInterface::decreaseAction())
532 else if (actionName == QAccessibleActionInterface::showOnScreenAction())
533 sig = &sigShowOnScreen;
534 else if (actionName == QAccessibleActionInterface::scrollUpAction())
536 else if (actionName == QAccessibleActionInterface::scrollDownAction())
537 sig = &sigScrollDown;
538 else if (actionName == QAccessibleActionInterface::scrollLeftAction())
539 sig = &sigScrollLeft;
540 else if (actionName == QAccessibleActionInterface::scrollRightAction())
541 sig = &sigScrollRight;
542 else if (actionName == QAccessibleActionInterface::previousPageAction())
543 sig = &sigPreviousPage;
544 else if (actionName == QAccessibleActionInterface::nextPageAction())
546 if (sig && isSignalConnected(*sig)) {
549 ret = sig->invoke(m_proxying);
551 ret = sig->invoke(
this);
557void QQuickAccessibleAttached::availableActions(QStringList *actions)
const
559 if (isSignalConnected(sigPress))
560 actions->append(QAccessibleActionInterface::pressAction());
561 if (isSignalConnected(sigToggle))
562 actions->append(QAccessibleActionInterface::toggleAction());
563 if (isSignalConnected(sigIncrease))
564 actions->append(QAccessibleActionInterface::increaseAction());
565 if (isSignalConnected(sigDecrease))
566 actions->append(QAccessibleActionInterface::decreaseAction());
567 if (isSignalConnected(sigShowOnScreen))
568 actions->append(QAccessibleActionInterface::showOnScreenAction());
569 if (isSignalConnected(sigScrollUp))
570 actions->append(QAccessibleActionInterface::scrollUpAction());
571 if (isSignalConnected(sigScrollDown))
572 actions->append(QAccessibleActionInterface::scrollDownAction());
573 if (isSignalConnected(sigScrollLeft))
574 actions->append(QAccessibleActionInterface::scrollLeftAction());
575 if (isSignalConnected(sigScrollRight))
576 actions->append(QAccessibleActionInterface::scrollRightAction());
577 if (isSignalConnected(sigPreviousPage))
578 actions->append(QAccessibleActionInterface::previousPageAction());
579 if (isSignalConnected(sigNextPage))
580 actions->append(QAccessibleActionInterface::nextPageAction());
583QString QQuickAccessibleAttached::stripHtml(
const QString &html)
585#ifndef QT_NO_TEXTHTMLPARSER
588 return doc.toPlainText();
594void QQuickAccessibleAttached::setProxying(QQuickAccessibleAttached *proxying)
596 if (proxying == m_proxying)
599 const QMetaObject &mo = staticMetaObject;
602 auto mo = m_proxying->metaObject();
603 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
604 for (
int signalIndex = propertyCache->signalOffset();
605 signalIndex < propertyCache->signalCount(); ++signalIndex) {
606 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
607 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
608 if (m.methodType() != QMetaMethod::Signal)
611 disconnect(m_proxying, m,
this, m);
615 m_proxying = proxying;
619 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
620 auto mo = m_proxying->metaObject();
621 for (
int signalIndex = propertyCache->signalOffset();
622 signalIndex < propertyCache->signalCount(); ++signalIndex) {
623 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
624 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
625 connect(proxying, m,
this, m);
630 for (
int prop = mo.propertyOffset(); prop < mo.propertyCount(); ++prop) {
631 const QMetaProperty p = mo.property(prop);
632 if (!p.hasNotifySignal()) {
636 const QMetaMethod signal = p.notifySignal();
637 if (signal.parameterCount() == 0)
640 signal.invoke(
this, Q_ARG(
bool, p.read(
this).toBool()));
645
646
647
648
649
650
651
652void QQuickAccessibleAttached::announce(
const QString &message, QAccessible::AnnouncementPoliteness politeness)
654 QAccessibleAnnouncementEvent event(parent(), message);
655 event.setPoliteness(politeness);
656 QAccessible::updateAccessibility(&event);
659QQuickItem *QQuickAccessibleAttached::findRelation(QAccessible::Relation relation)
const
661 const auto it = std::find_if(m_relations.cbegin(), m_relations.cend(),
662 [relation](
const auto &rel) {
663 return rel.second == relation;
666 return it != m_relations.cend() ? it->first :
nullptr;
671#include "moc_qquickaccessibleattached_p.cpp"