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
291
293
294
295
296
298
299
300
301
303
304
305
306
308
309
310
311
313
314
315
316
318
319
320
321
323QMetaMethod QQuickAccessibleAttached::sigPress;
324QMetaMethod QQuickAccessibleAttached::sigToggle;
325QMetaMethod QQuickAccessibleAttached::sigIncrease;
326QMetaMethod QQuickAccessibleAttached::sigDecrease;
327QMetaMethod QQuickAccessibleAttached::sigShowOnScreen;
328QMetaMethod QQuickAccessibleAttached::sigScrollUp;
329QMetaMethod QQuickAccessibleAttached::sigScrollDown;
330QMetaMethod QQuickAccessibleAttached::sigScrollLeft;
331QMetaMethod QQuickAccessibleAttached::sigScrollRight;
332QMetaMethod QQuickAccessibleAttached::sigPreviousPage;
333QMetaMethod QQuickAccessibleAttached::sigNextPage;
335QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
336 : QObject(parent), m_role(QAccessible::NoRole)
341 auto item = qobject_cast<QQuickItem *>(parent);
343 item->d_func()->setAccessible();
345 const QLatin1StringView className(QQmlData::ensurePropertyCache(parent)->firstCppMetaObject()->className());
346 if (className != QLatin1StringView(
"QQuickAction")) {
347 qmlWarning(parent) <<
"Accessible attached property must be attached to an object deriving from Item or Action";
351 QAccessibleEvent ev(parent, QAccessible::ObjectCreated);
352 QAccessible::updateAccessibility(&ev);
354 if (
const QMetaObject *pmo = parent->metaObject()) {
355 auto connectPropertyChangeSignal = [parent, pmo,
this](
356 const char *propertyName,
const char *signalName,
int slotIndex)
365 int idxProperty = pmo->indexOfProperty(propertyName);
366 if (idxProperty != -1) {
367 const QMetaProperty property = pmo->property(idxProperty);
368 const QMetaMethod signal = property.notifySignal();
369 if (signal.name() == signalName)
370 QMetaObject::connect(parent, signal.methodIndex(),
this, slotIndex);
374 const QMetaObject &smo = staticMetaObject;
376 QAccessibleInterface *iface = ev.accessibleInterface();
377 if (iface && iface->valueInterface()) {
378 static const int valueChangedIndex = smo.indexOfSlot(
"valueChanged()");
379 connectPropertyChangeSignal(
"value",
"valueChanged", valueChangedIndex);
382 if (iface && iface->textInterface()) {
383 static const int cursorPositionChangedIndex =
384 smo.indexOfSlot(
"cursorPositionChanged()");
385 connectPropertyChangeSignal(
"cursorPosition",
"cursorPositionChanged",
386 cursorPositionChangedIndex);
390 if (!sigPress.isValid()) {
391 sigPress = QMetaMethod::fromSignal(&QQuickAccessibleAttached::pressAction);
392 sigToggle = QMetaMethod::fromSignal(&QQuickAccessibleAttached::toggleAction);
393 sigIncrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::increaseAction);
394 sigDecrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::decreaseAction);
395 sigShowOnScreen = QMetaMethod::fromSignal(&QQuickAccessibleAttached::showOnScreenAction);
396 sigScrollUp = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollUpAction);
397 sigScrollDown = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollDownAction);
398 sigScrollLeft = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollLeftAction);
399 sigScrollRight = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollRightAction);
400 sigPreviousPage = QMetaMethod::fromSignal(&QQuickAccessibleAttached::previousPageAction);
401 sigNextPage= QMetaMethod::fromSignal(&QQuickAccessibleAttached::nextPageAction);
405QQuickAccessibleAttached::~QQuickAccessibleAttached()
409void QQuickAccessibleAttached::setRole(QAccessible::Role role)
411 if (role != m_role) {
413 Q_EMIT roleChanged();
418 case QAccessible::CheckBox:
419 case QAccessible::RadioButton:
420 case QAccessible::Switch:
421 if (!m_stateExplicitlySet.focusable)
422 m_state.focusable =
true;
423 if (!m_stateExplicitlySet.checkable)
424 m_state.checkable =
true;
426 case QAccessible::Button:
427 case QAccessible::MenuItem:
428 case QAccessible::PageTab:
429 case QAccessible::SpinBox:
430 case QAccessible::ComboBox:
431 case QAccessible::Terminal:
432 case QAccessible::ScrollBar:
433 if (!m_stateExplicitlySet.focusable)
434 m_state.focusable =
true;
436 case QAccessible::EditableText:
437 if (!m_stateExplicitlySet.editable)
438 m_state.editable =
true;
439 if (!m_stateExplicitlySet.focusable)
440 m_state.focusable =
true;
442 case QAccessible::StaticText:
443 if (!m_stateExplicitlySet.readOnly)
444 m_state.readOnly =
true;
445 if (!m_stateExplicitlySet.focusable)
446 m_state.focusable =
true;
454bool QQuickAccessibleAttached::wasNameExplicitlySet()
const
456 return m_nameExplicitlySet;
461void QQuickAccessibleAttached::setNameImplicitly(
const QString &name)
464 m_nameExplicitlySet =
false;
467void QQuickAccessibleAttached::setDescriptionImplicitly(
const QString &desc)
469 if (m_descriptionExplicitlySet)
471 setDescription(desc);
472 m_descriptionExplicitlySet =
false;
475QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj)
477 return new QQuickAccessibleAttached(obj);
480bool QQuickAccessibleAttached::ignored()
const
482 auto item = qobject_cast<QQuickItem *>(parent());
483 return item ? !item->d_func()->isAccessible :
false;
486void QQuickAccessibleAttached::setIgnored(
bool ignored)
488 auto item = qobject_cast<QQuickItem *>(parent());
489 if (item &&
this->ignored() != ignored) {
490 item->d_func()->isAccessible = !ignored;
491 QAccessibleEvent event(item,
492 ignored ? QAccessible::ObjectDestroyed : QAccessible::ObjectCreated);
493 QAccessible::updateAccessibility(&event);
494 emit ignoredChanged();
498bool QQuickAccessibleAttached::doAction(
const QString &actionName)
500 QMetaMethod *sig =
nullptr;
501 if (actionName == QAccessibleActionInterface::pressAction())
503 else if (actionName == QAccessibleActionInterface::toggleAction())
505 else if (actionName == QAccessibleActionInterface::increaseAction())
507 else if (actionName == QAccessibleActionInterface::decreaseAction())
509 else if (actionName == QAccessibleActionInterface::showOnScreenAction())
510 sig = &sigShowOnScreen;
511 else if (actionName == QAccessibleActionInterface::scrollUpAction())
513 else if (actionName == QAccessibleActionInterface::scrollDownAction())
514 sig = &sigScrollDown;
515 else if (actionName == QAccessibleActionInterface::scrollLeftAction())
516 sig = &sigScrollLeft;
517 else if (actionName == QAccessibleActionInterface::scrollRightAction())
518 sig = &sigScrollRight;
519 else if (actionName == QAccessibleActionInterface::previousPageAction())
520 sig = &sigPreviousPage;
521 else if (actionName == QAccessibleActionInterface::nextPageAction())
523 if (sig && isSignalConnected(*sig)) {
526 ret = sig->invoke(m_proxying);
528 ret = sig->invoke(
this);
534void QQuickAccessibleAttached::availableActions(QStringList *actions)
const
536 if (isSignalConnected(sigPress))
537 actions->append(QAccessibleActionInterface::pressAction());
538 if (isSignalConnected(sigToggle))
539 actions->append(QAccessibleActionInterface::toggleAction());
540 if (isSignalConnected(sigIncrease))
541 actions->append(QAccessibleActionInterface::increaseAction());
542 if (isSignalConnected(sigDecrease))
543 actions->append(QAccessibleActionInterface::decreaseAction());
544 if (isSignalConnected(sigShowOnScreen))
545 actions->append(QAccessibleActionInterface::showOnScreenAction());
546 if (isSignalConnected(sigScrollUp))
547 actions->append(QAccessibleActionInterface::scrollUpAction());
548 if (isSignalConnected(sigScrollDown))
549 actions->append(QAccessibleActionInterface::scrollDownAction());
550 if (isSignalConnected(sigScrollLeft))
551 actions->append(QAccessibleActionInterface::scrollLeftAction());
552 if (isSignalConnected(sigScrollRight))
553 actions->append(QAccessibleActionInterface::scrollRightAction());
554 if (isSignalConnected(sigPreviousPage))
555 actions->append(QAccessibleActionInterface::previousPageAction());
556 if (isSignalConnected(sigNextPage))
557 actions->append(QAccessibleActionInterface::nextPageAction());
560QString QQuickAccessibleAttached::stripHtml(
const QString &html)
562#ifndef QT_NO_TEXTHTMLPARSER
565 return doc.toPlainText();
571void QQuickAccessibleAttached::setProxying(QQuickAccessibleAttached *proxying)
573 if (proxying == m_proxying)
576 const QMetaObject &mo = staticMetaObject;
579 auto mo = m_proxying->metaObject();
580 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
581 for (
int signalIndex = propertyCache->signalOffset();
582 signalIndex < propertyCache->signalCount(); ++signalIndex) {
583 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
584 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
585 if (m.methodType() != QMetaMethod::Signal)
588 disconnect(m_proxying, m,
this, m);
592 m_proxying = proxying;
596 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
597 auto mo = m_proxying->metaObject();
598 for (
int signalIndex = propertyCache->signalOffset();
599 signalIndex < propertyCache->signalCount(); ++signalIndex) {
600 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
601 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
602 connect(proxying, m,
this, m);
607 for (
int prop = mo.propertyOffset(); prop < mo.propertyCount(); ++prop) {
608 const QMetaProperty p = mo.property(prop);
609 if (!p.hasNotifySignal()) {
613 const QMetaMethod signal = p.notifySignal();
614 if (signal.parameterCount() == 0)
617 signal.invoke(
this, Q_ARG(
bool, p.read(
this).toBool()));
622
623
624
625
626
627
628
629void QQuickAccessibleAttached::announce(
const QString &message, QAccessible::AnnouncementPoliteness politeness)
631 QAccessibleAnnouncementEvent event(parent(), message);
632 event.setPoliteness(politeness);
633 QAccessible::updateAccessibility(&event);
636QQuickItem *QQuickAccessibleAttached::findRelation(QAccessible::Relation relation)
const
638 const auto it = std::find_if(m_relations.cbegin(), m_relations.cend(),
639 [relation](
const auto &rel) {
640 return rel.second == relation;
643 return it != m_relations.cend() ? it->first :
nullptr;
648#include "moc_qquickaccessibleattached_p.cpp"