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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
213
214
215
216
218
219
220
221
222
224
225
226
227
228
230
231
232
233
234
236
237
238
239
241
242
243
244
245
247
248
249
250
252
253
254
255
257
258
259
260
262
263
264
265
266
267
268
269
271
272
273
274
275
276
277
278
281
282
283
284
286
287
288
289
291
292
293
294
296
297
298
299
301
302
303
304
305
307
308
309
310
312
313
314
315
317
318
319
320
322
323
324
325
327
328
329
330
332
333
334
335
337QMetaMethod QQuickAccessibleAttached::sigPress;
338QMetaMethod QQuickAccessibleAttached::sigToggle;
339QMetaMethod QQuickAccessibleAttached::sigIncrease;
340QMetaMethod QQuickAccessibleAttached::sigDecrease;
341QMetaMethod QQuickAccessibleAttached::sigShowOnScreen;
342QMetaMethod QQuickAccessibleAttached::sigScrollUp;
343QMetaMethod QQuickAccessibleAttached::sigScrollDown;
344QMetaMethod QQuickAccessibleAttached::sigScrollLeft;
345QMetaMethod QQuickAccessibleAttached::sigScrollRight;
346QMetaMethod QQuickAccessibleAttached::sigPreviousPage;
347QMetaMethod QQuickAccessibleAttached::sigNextPage;
349QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
350 : QObject(parent), m_role(QAccessible::NoRole)
355 auto item = qobject_cast<QQuickItem *>(parent);
357 item->d_func()->setAccessible();
359 const QLatin1StringView className(QQmlData::ensurePropertyCache(parent)->firstCppMetaObject()->className());
360 if (className != QLatin1StringView(
"QQuickAction")) {
361 qmlWarning(parent) <<
"Accessible attached property must be attached to an object deriving from Item or Action";
365 QAccessibleEvent ev(parent, QAccessible::ObjectCreated);
366 QAccessible::updateAccessibility(&ev);
368 if (
const QMetaObject *pmo = parent->metaObject()) {
369 auto connectPropertyChangeSignal = [parent, pmo,
this](
370 const char *propertyName,
const char *signalName,
int slotIndex)
379 int idxProperty = pmo->indexOfProperty(propertyName);
380 if (idxProperty != -1) {
381 const QMetaProperty property = pmo->property(idxProperty);
382 const QMetaMethod signal = property.notifySignal();
383 if (signal.name() == signalName)
384 QMetaObject::connect(parent, signal.methodIndex(),
this, slotIndex);
388 const QMetaObject &smo = staticMetaObject;
390 QAccessibleInterface *iface = ev.accessibleInterface();
391 if (iface && iface->valueInterface()) {
392 static const int valueChangedIndex = smo.indexOfSlot(
"valueChanged()");
393 connectPropertyChangeSignal(
"value",
"valueChanged", valueChangedIndex);
396 if (iface && iface->textInterface()) {
397 static const int cursorPositionChangedIndex =
398 smo.indexOfSlot(
"cursorPositionChanged()");
399 connectPropertyChangeSignal(
"cursorPosition",
"cursorPositionChanged",
400 cursorPositionChangedIndex);
404 if (!sigPress.isValid()) {
405 sigPress = QMetaMethod::fromSignal(&QQuickAccessibleAttached::pressAction);
406 sigToggle = QMetaMethod::fromSignal(&QQuickAccessibleAttached::toggleAction);
407 sigIncrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::increaseAction);
408 sigDecrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::decreaseAction);
409 sigShowOnScreen = QMetaMethod::fromSignal(&QQuickAccessibleAttached::showOnScreenAction);
410 sigScrollUp = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollUpAction);
411 sigScrollDown = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollDownAction);
412 sigScrollLeft = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollLeftAction);
413 sigScrollRight = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollRightAction);
414 sigPreviousPage = QMetaMethod::fromSignal(&QQuickAccessibleAttached::previousPageAction);
415 sigNextPage= QMetaMethod::fromSignal(&QQuickAccessibleAttached::nextPageAction);
419QQuickAccessibleAttached::~QQuickAccessibleAttached()
423void QQuickAccessibleAttached::setRole(QAccessible::Role role)
425 if (role != m_role) {
427 Q_EMIT roleChanged();
432 case QAccessible::CheckBox:
433 case QAccessible::RadioButton:
434 case QAccessible::Switch:
435 if (!m_stateExplicitlySet.focusable)
436 m_state.focusable =
true;
437 if (!m_stateExplicitlySet.checkable)
438 m_state.checkable =
true;
440 case QAccessible::Button:
441 case QAccessible::MenuItem:
442 case QAccessible::PageTab:
443 case QAccessible::SpinBox:
444 case QAccessible::ComboBox:
445 case QAccessible::Terminal:
446 case QAccessible::ScrollBar:
447 if (!m_stateExplicitlySet.focusable)
448 m_state.focusable =
true;
450 case QAccessible::EditableText:
451 if (!m_stateExplicitlySet.editable)
452 m_state.editable =
true;
453 if (!m_stateExplicitlySet.focusable)
454 m_state.focusable =
true;
456 case QAccessible::StaticText:
457 if (!m_stateExplicitlySet.readOnly)
458 m_state.readOnly =
true;
459 if (!m_stateExplicitlySet.focusable)
460 m_state.focusable =
true;
468bool QQuickAccessibleAttached::wasNameExplicitlySet()
const
470 return m_nameExplicitlySet;
475void QQuickAccessibleAttached::setNameImplicitly(
const QString &name)
478 m_nameExplicitlySet =
false;
481void QQuickAccessibleAttached::setDescriptionImplicitly(
const QString &desc)
483 if (m_descriptionExplicitlySet)
485 setDescription(desc);
486 m_descriptionExplicitlySet =
false;
489QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj)
491 return new QQuickAccessibleAttached(obj);
494bool QQuickAccessibleAttached::ignored()
const
496 auto item = qobject_cast<QQuickItem *>(parent());
497 return item ? !item->d_func()->isAccessible :
false;
500void QQuickAccessibleAttached::setIgnored(
bool ignored)
502 auto item = qobject_cast<QQuickItem *>(parent());
503 if (item &&
this->ignored() != ignored) {
504 item->d_func()->isAccessible = !ignored;
505 QAccessibleEvent event(item,
506 ignored ? QAccessible::ObjectDestroyed : QAccessible::ObjectCreated);
507 QAccessible::updateAccessibility(&event);
508 emit ignoredChanged();
512bool QQuickAccessibleAttached::doAction(
const QString &actionName)
514 QMetaMethod *sig =
nullptr;
515 if (actionName == QAccessibleActionInterface::pressAction())
517 else if (actionName == QAccessibleActionInterface::toggleAction())
519 else if (actionName == QAccessibleActionInterface::increaseAction())
521 else if (actionName == QAccessibleActionInterface::decreaseAction())
523 else if (actionName == QAccessibleActionInterface::showOnScreenAction())
524 sig = &sigShowOnScreen;
525 else if (actionName == QAccessibleActionInterface::scrollUpAction())
527 else if (actionName == QAccessibleActionInterface::scrollDownAction())
528 sig = &sigScrollDown;
529 else if (actionName == QAccessibleActionInterface::scrollLeftAction())
530 sig = &sigScrollLeft;
531 else if (actionName == QAccessibleActionInterface::scrollRightAction())
532 sig = &sigScrollRight;
533 else if (actionName == QAccessibleActionInterface::previousPageAction())
534 sig = &sigPreviousPage;
535 else if (actionName == QAccessibleActionInterface::nextPageAction())
537 if (sig && isSignalConnected(*sig)) {
540 ret = sig->invoke(m_proxying);
542 ret = sig->invoke(
this);
548void QQuickAccessibleAttached::availableActions(QStringList *actions)
const
550 if (isSignalConnected(sigPress))
551 actions->append(QAccessibleActionInterface::pressAction());
552 if (isSignalConnected(sigToggle))
553 actions->append(QAccessibleActionInterface::toggleAction());
554 if (isSignalConnected(sigIncrease))
555 actions->append(QAccessibleActionInterface::increaseAction());
556 if (isSignalConnected(sigDecrease))
557 actions->append(QAccessibleActionInterface::decreaseAction());
558 if (isSignalConnected(sigShowOnScreen))
559 actions->append(QAccessibleActionInterface::showOnScreenAction());
560 if (isSignalConnected(sigScrollUp))
561 actions->append(QAccessibleActionInterface::scrollUpAction());
562 if (isSignalConnected(sigScrollDown))
563 actions->append(QAccessibleActionInterface::scrollDownAction());
564 if (isSignalConnected(sigScrollLeft))
565 actions->append(QAccessibleActionInterface::scrollLeftAction());
566 if (isSignalConnected(sigScrollRight))
567 actions->append(QAccessibleActionInterface::scrollRightAction());
568 if (isSignalConnected(sigPreviousPage))
569 actions->append(QAccessibleActionInterface::previousPageAction());
570 if (isSignalConnected(sigNextPage))
571 actions->append(QAccessibleActionInterface::nextPageAction());
574QString QQuickAccessibleAttached::stripHtml(
const QString &html)
576#ifndef QT_NO_TEXTHTMLPARSER
579 return doc.toPlainText();
585void QQuickAccessibleAttached::setProxying(QQuickAccessibleAttached *proxying)
587 if (proxying == m_proxying)
590 const QMetaObject &mo = staticMetaObject;
593 auto mo = m_proxying->metaObject();
594 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
595 for (
int signalIndex = propertyCache->signalOffset();
596 signalIndex < propertyCache->signalCount(); ++signalIndex) {
597 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
598 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
599 if (m.methodType() != QMetaMethod::Signal)
602 disconnect(m_proxying, m,
this, m);
606 m_proxying = proxying;
610 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
611 auto mo = m_proxying->metaObject();
612 for (
int signalIndex = propertyCache->signalOffset();
613 signalIndex < propertyCache->signalCount(); ++signalIndex) {
614 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
615 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
616 connect(proxying, m,
this, m);
621 for (
int prop = mo.propertyOffset(); prop < mo.propertyCount(); ++prop) {
622 const QMetaProperty p = mo.property(prop);
623 if (!p.hasNotifySignal()) {
627 const QMetaMethod signal = p.notifySignal();
628 if (signal.parameterCount() == 0)
631 signal.invoke(
this, Q_ARG(
bool, p.read(
this).toBool()));
636
637
638
639
640
641
642
643void QQuickAccessibleAttached::announce(
const QString &message, QAccessible::AnnouncementPoliteness politeness)
645 QAccessibleAnnouncementEvent event(parent(), message);
646 event.setPoliteness(politeness);
647 QAccessible::updateAccessibility(&event);
650QQuickItem *QQuickAccessibleAttached::findRelation(QAccessible::Relation relation)
const
652 const auto it = std::find_if(m_relations.cbegin(), m_relations.cend(),
653 [relation](
const auto &rel) {
654 return rel.second == relation;
657 return it != m_relations.cend() ? it->first :
nullptr;
662#include "moc_qquickaccessibleattached_p.cpp"