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;
362static void connectPropertyChangeSignals(QQuickAccessibleAttached *attached,
363 QAccessibleInterface *accessibleInterface)
365 QObject *parent = attached->parent();
366 const QMetaObject *parentMetaObject = parent->metaObject();
367 if (!accessibleInterface || !parentMetaObject)
370 auto connectPropertyChangeSignal = [parent, parentMetaObject, attached](
371 const char *propertyName,
const char *signalName,
int slotIndex)
380 int propertyIndex = parentMetaObject->indexOfProperty(propertyName);
381 if (propertyIndex != -1) {
382 const QMetaProperty property = parentMetaObject->property(propertyIndex);
383 const QMetaMethod signal = property.notifySignal();
384 if (signal.name() == signalName) {
385 QMetaObject::connect(parent, signal.methodIndex(), attached, slotIndex,
386 Qt::UniqueConnection);
390 const QMetaObject &attachedMetaObject = QQuickAccessibleAttached::staticMetaObject;
392 if (accessibleInterface->valueInterface()) {
393 static const int valueChangedIndex = attachedMetaObject.indexOfSlot(
"valueChanged()");
394 connectPropertyChangeSignal(
"value",
"valueChanged", valueChangedIndex);
397 if (accessibleInterface->textInterface()) {
398 static const int cursorPositionChangedIndex =
399 attachedMetaObject.indexOfSlot(
"cursorPositionChanged()");
400 connectPropertyChangeSignal(
"cursorPosition",
"cursorPositionChanged",
401 cursorPositionChangedIndex);
405QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
406 : QObject(parent), m_role(QAccessible::NoRole)
411 auto item = qobject_cast<QQuickItem *>(parent);
413 item->d_func()->setAccessible();
415 const QLatin1StringView className(QQmlData::ensurePropertyCache(parent)->firstCppMetaObject()->className());
416 if (className != QLatin1StringView(
"QQuickAction")) {
417 qmlWarning(parent) <<
"Accessible attached property must be attached to an object deriving from Item or Action";
421 QAccessibleEvent ev(parent, QAccessible::ObjectCreated);
422 QAccessible::updateAccessibility(&ev);
424 connectPropertyChangeSignals(
this, ev.accessibleInterface());
426 if (!sigPress.isValid()) {
427 sigPress = QMetaMethod::fromSignal(&QQuickAccessibleAttached::pressAction);
428 sigToggle = QMetaMethod::fromSignal(&QQuickAccessibleAttached::toggleAction);
429 sigIncrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::increaseAction);
430 sigDecrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::decreaseAction);
431 sigShowOnScreen = QMetaMethod::fromSignal(&QQuickAccessibleAttached::showOnScreenAction);
432 sigScrollUp = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollUpAction);
433 sigScrollDown = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollDownAction);
434 sigScrollLeft = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollLeftAction);
435 sigScrollRight = QMetaMethod::fromSignal(&QQuickAccessibleAttached::scrollRightAction);
436 sigPreviousPage = QMetaMethod::fromSignal(&QQuickAccessibleAttached::previousPageAction);
437 sigNextPage= QMetaMethod::fromSignal(&QQuickAccessibleAttached::nextPageAction);
441QQuickAccessibleAttached::~QQuickAccessibleAttached()
445void QQuickAccessibleAttached::setRole(QAccessible::Role role)
447 if (role != m_role) {
449 Q_EMIT roleChanged();
454 case QAccessible::CheckBox:
455 case QAccessible::RadioButton:
456 case QAccessible::Switch:
457 if (!m_stateExplicitlySet.focusable)
458 m_state.focusable =
true;
459 if (!m_stateExplicitlySet.checkable)
460 m_state.checkable =
true;
462 case QAccessible::Button:
463 case QAccessible::MenuItem:
464 case QAccessible::PageTab:
465 case QAccessible::SpinBox:
466 case QAccessible::ComboBox:
467 case QAccessible::Terminal:
468 case QAccessible::ScrollBar:
469 if (!m_stateExplicitlySet.focusable)
470 m_state.focusable =
true;
472 case QAccessible::EditableText:
473 if (!m_stateExplicitlySet.editable)
474 m_state.editable =
true;
475 if (!m_stateExplicitlySet.focusable)
476 m_state.focusable =
true;
478 case QAccessible::StaticText:
479 if (!m_stateExplicitlySet.readOnly)
480 m_state.readOnly =
true;
481 if (!m_stateExplicitlySet.focusable)
482 m_state.focusable =
true;
488 connectPropertyChangeSignals(
this, QAccessible::queryAccessibleInterface(parent()));
492bool QQuickAccessibleAttached::wasNameExplicitlySet()
const
494 return m_nameExplicitlySet;
499void QQuickAccessibleAttached::setNameImplicitly(
const QString &name)
502 m_nameExplicitlySet =
false;
505void QQuickAccessibleAttached::setDescriptionImplicitly(
const QString &desc)
507 if (m_descriptionExplicitlySet)
509 setDescription(desc);
510 m_descriptionExplicitlySet =
false;
513QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj)
515 return new QQuickAccessibleAttached(obj);
518bool QQuickAccessibleAttached::ignored()
const
520 auto item = qobject_cast<QQuickItem *>(parent());
521 return item ? !item->d_func()->isAccessible :
false;
524void QQuickAccessibleAttached::setIgnored(
bool ignored)
526 auto item = qobject_cast<QQuickItem *>(parent());
527 if (item &&
this->ignored() != ignored) {
528 item->d_func()->isAccessible = !ignored;
529 QAccessibleEvent event(item,
530 ignored ? QAccessible::ObjectDestroyed : QAccessible::ObjectCreated);
531 QAccessible::updateAccessibility(&event);
532 emit ignoredChanged();
536bool QQuickAccessibleAttached::doAction(
const QString &actionName)
538 QMetaMethod *sig =
nullptr;
539 if (actionName == QAccessibleActionInterface::pressAction())
541 else if (actionName == QAccessibleActionInterface::toggleAction())
543 else if (actionName == QAccessibleActionInterface::increaseAction())
545 else if (actionName == QAccessibleActionInterface::decreaseAction())
547 else if (actionName == QAccessibleActionInterface::showOnScreenAction())
548 sig = &sigShowOnScreen;
549 else if (actionName == QAccessibleActionInterface::scrollUpAction())
551 else if (actionName == QAccessibleActionInterface::scrollDownAction())
552 sig = &sigScrollDown;
553 else if (actionName == QAccessibleActionInterface::scrollLeftAction())
554 sig = &sigScrollLeft;
555 else if (actionName == QAccessibleActionInterface::scrollRightAction())
556 sig = &sigScrollRight;
557 else if (actionName == QAccessibleActionInterface::previousPageAction())
558 sig = &sigPreviousPage;
559 else if (actionName == QAccessibleActionInterface::nextPageAction())
561 if (sig && isSignalConnected(*sig)) {
564 ret = sig->invoke(m_proxying);
566 ret = sig->invoke(
this);
572void QQuickAccessibleAttached::availableActions(QStringList *actions)
const
574 if (isSignalConnected(sigPress))
575 actions->append(QAccessibleActionInterface::pressAction());
576 if (isSignalConnected(sigToggle))
577 actions->append(QAccessibleActionInterface::toggleAction());
578 if (isSignalConnected(sigIncrease))
579 actions->append(QAccessibleActionInterface::increaseAction());
580 if (isSignalConnected(sigDecrease))
581 actions->append(QAccessibleActionInterface::decreaseAction());
582 if (isSignalConnected(sigShowOnScreen))
583 actions->append(QAccessibleActionInterface::showOnScreenAction());
584 if (isSignalConnected(sigScrollUp))
585 actions->append(QAccessibleActionInterface::scrollUpAction());
586 if (isSignalConnected(sigScrollDown))
587 actions->append(QAccessibleActionInterface::scrollDownAction());
588 if (isSignalConnected(sigScrollLeft))
589 actions->append(QAccessibleActionInterface::scrollLeftAction());
590 if (isSignalConnected(sigScrollRight))
591 actions->append(QAccessibleActionInterface::scrollRightAction());
592 if (isSignalConnected(sigPreviousPage))
593 actions->append(QAccessibleActionInterface::previousPageAction());
594 if (isSignalConnected(sigNextPage))
595 actions->append(QAccessibleActionInterface::nextPageAction());
598QString QQuickAccessibleAttached::stripHtml(
const QString &html)
600#ifndef QT_NO_TEXTHTMLPARSER
603 return doc.toPlainText();
609void QQuickAccessibleAttached::setProxying(QQuickAccessibleAttached *proxying)
611 if (proxying == m_proxying)
614 const QMetaObject &mo = staticMetaObject;
617 auto mo = m_proxying->metaObject();
618 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
619 for (
int signalIndex = propertyCache->signalOffset();
620 signalIndex < propertyCache->signalCount(); ++signalIndex) {
621 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
622 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
623 if (m.methodType() != QMetaMethod::Signal)
626 disconnect(m_proxying, m,
this, m);
630 m_proxying = proxying;
634 auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
635 auto mo = m_proxying->metaObject();
636 for (
int signalIndex = propertyCache->signalOffset();
637 signalIndex < propertyCache->signalCount(); ++signalIndex) {
638 const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
639 Q_ASSERT(m.methodType() == QMetaMethod::Signal);
640 connect(proxying, m,
this, m);
645 for (
int prop = mo.propertyOffset(); prop < mo.propertyCount(); ++prop) {
646 const QMetaProperty p = mo.property(prop);
647 if (!p.hasNotifySignal()) {
651 const QMetaMethod signal = p.notifySignal();
652 if (signal.parameterCount() == 0)
655 signal.invoke(
this, Q_ARG(
bool, p.read(
this).toBool()));
660
661
662
663
664
665
666
667void QQuickAccessibleAttached::announce(
const QString &message, QAccessible::AnnouncementPoliteness politeness)
669 QAccessibleAnnouncementEvent event(parent(), message);
670 event.setPoliteness(politeness);
671 QAccessible::updateAccessibility(&event);
674QQuickItem *QQuickAccessibleAttached::findRelation(QAccessible::Relation relation)
const
676 const auto it = std::find_if(m_relations.cbegin(), m_relations.cend(),
677 [relation](
const auto &rel) {
678 return rel.second == relation;
681 return it != m_relations.cend() ? it->first :
nullptr;
686#include "moc_qquickaccessibleattached_p.cpp"