1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qquickaccessibleattached_p.h" |
5 | |
6 | #if QT_CONFIG(accessibility) |
7 | |
8 | #include <QtQml/qqmlinfo.h> |
9 | |
10 | #include "private/qquickitem_p.h" |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | /*! |
15 | \qmltype Accessible |
16 | \nativetype QQuickAccessibleAttached |
17 | \brief Enables accessibility of QML items. |
18 | |
19 | \inqmlmodule QtQuick |
20 | \ingroup qtquick-visual-utility |
21 | \ingroup accessibility |
22 | |
23 | This class is part of the \l {Accessibility for Qt Quick Applications}. |
24 | |
25 | Items the user interacts with or that give information to the user |
26 | need to expose their information to the accessibility framework. |
27 | Then assistive tools can make use of that information to enable |
28 | users to interact with the application in various ways. |
29 | This enables Qt Quick applications to be used with screen-readers for example. |
30 | |
31 | The most important properties are \l name, \l description and \l role. |
32 | |
33 | Example implementation of a simple button: |
34 | \qml |
35 | Rectangle { |
36 | id: myButton |
37 | Text { |
38 | id: label |
39 | text: "next" |
40 | } |
41 | Accessible.role: Accessible.Button |
42 | Accessible.name: label.text |
43 | Accessible.description: "shows the next page" |
44 | Accessible.onPressAction: { |
45 | // do a button click |
46 | } |
47 | } |
48 | \endqml |
49 | The \l role is set to \c Button to indicate the type of control. |
50 | \l {Accessible::}{name} is the most important information and bound to the text on the button. |
51 | The name is a short and consise description of the control and should reflect the visual label. |
52 | In this case it is not clear what the button does with the name only, so \l description contains |
53 | an explanation. |
54 | There is also a signal handler \l {Accessible::pressAction}{Accessible.pressAction} which can be invoked by assistive tools to trigger |
55 | the button. This signal handler needs to have the same effect as tapping or clicking the button would have. |
56 | |
57 | \sa Accessibility |
58 | */ |
59 | |
60 | /*! |
61 | \qmlproperty string QtQuick::Accessible::name |
62 | |
63 | This property sets an accessible name. |
64 | For a button for example, this should have a binding to its text. |
65 | In general this property should be set to a simple and concise |
66 | but human readable name. Do not include the type of control |
67 | you want to represent but just the name. |
68 | */ |
69 | |
70 | /*! |
71 | \qmlproperty string QtQuick::Accessible::description |
72 | |
73 | This property sets an accessible description. |
74 | Similar to the name it describes the item. The description |
75 | can be a little more verbose and tell what the item does, |
76 | for example the functionality of the button it describes. |
77 | */ |
78 | |
79 | /*! |
80 | \qmlproperty enumeration QtQuick::Accessible::role |
81 | |
82 | This flags sets the semantic type of the widget. |
83 | A button for example would have "Button" as type. |
84 | The value must be one of \l QAccessible::Role. |
85 | |
86 | Some roles have special semantics. |
87 | In order to implement check boxes for example a "checked" property is expected. |
88 | |
89 | \table |
90 | \header |
91 | \li \b {Role} |
92 | \li \b {Properties and signals} |
93 | \li \b {Explanation} |
94 | \row |
95 | \li All interactive elements |
96 | \li \l focusable and \l focused |
97 | \li All elements that the user can interact with should have focusable set to \c true and |
98 | set \c focus to \c true when they have the focus. This is important even for applications |
99 | that run on touch-only devices since screen readers often implement a virtual focus that |
100 | can be moved from item to item. |
101 | \row |
102 | \li Button, CheckBox, RadioButton |
103 | \li \l {Accessible::pressAction}{Accessible.pressAction} |
104 | \li A button should have a signal handler with the name \c onPressAction. |
105 | This signal may be emitted by an assistive tool such as a screen-reader. |
106 | The implementation needs to behave the same as a mouse click or tap on the button. |
107 | \row |
108 | \li CheckBox, RadioButton |
109 | \li \l checkable, \l checked, \l {Accessible::toggleAction}{Accessible.toggleAction} |
110 | |
111 | \li The check state of the check box. Updated on Press, Check and Uncheck actions. |
112 | \row |
113 | \li Slider, SpinBox, Dial, ScrollBar |
114 | \li \c value, \c minimumValue, \c maximumValue, \c stepSize |
115 | \li These properties reflect the state and possible values for the elements. |
116 | \row |
117 | \li Slider, SpinBox, Dial, ScrollBar |
118 | \li \l {Accessible::increaseAction}{Accessible.increaseAction}, \l {Accessible::decreaseAction}{Accessible.decreaseAction} |
119 | \li Actions to increase and decrease the value of the element. |
120 | \endtable |
121 | */ |
122 | |
123 | /*! |
124 | \qmlproperty string QtQuick::Accessible::id |
125 | |
126 | This property sets an identifier for the object. |
127 | It can be used to provide stable identifiers to UI tests. |
128 | By default, the identifier is set to the ID of the QML object. |
129 | If the ID is not set the default of \l QAccessible::Identifier is used. |
130 | */ |
131 | |
132 | /*! \qmlproperty bool QtQuick::Accessible::focusable |
133 | \brief This property holds whether this item is focusable. |
134 | |
135 | By default, this property is \c false except for items where the role is one of |
136 | \c CheckBox, \c RadioButton, \c Button, \c MenuItem, \c PageTab, \c EditableText, \c SpinBox, \c ComboBox, |
137 | \c Terminal or \c ScrollBar. |
138 | \sa focused |
139 | */ |
140 | /*! \qmlproperty bool QtQuick::Accessible::focused |
141 | \brief This property holds whether this item currently has the active focus. |
142 | |
143 | By default, this property is \c false, but it will return \c true for items that |
144 | have \l QQuickItem::hasActiveFocus() returning \c true. |
145 | \sa focusable |
146 | */ |
147 | /*! \qmlproperty bool QtQuick::Accessible::checkable |
148 | \brief This property holds whether this item is checkable (like a check box or some buttons). |
149 | |
150 | By default this property is \c false. |
151 | \sa checked |
152 | */ |
153 | /*! \qmlproperty bool QtQuick::Accessible::checked |
154 | \brief This property holds whether this item is currently checked. |
155 | |
156 | By default this property is \c false. |
157 | \sa checkable |
158 | */ |
159 | /*! \qmlproperty bool QtQuick::Accessible::editable |
160 | \brief This property holds whether this item has editable text. |
161 | |
162 | By default this property is \c false. |
163 | */ |
164 | /*! \qmlproperty bool QtQuick::Accessible::searchEdit |
165 | \brief This property holds whether this item is input for a search query. |
166 | This property will only affect editable text. |
167 | |
168 | By default this property is \c false. |
169 | */ |
170 | /*! \qmlproperty bool QtQuick::Accessible::ignored |
171 | \brief This property holds whether this item should be ignored by the accessibility framework. |
172 | |
173 | Sometimes an item is part of a group of items that should be treated as one. For example two labels might be |
174 | visually placed next to each other, but separate items. For accessibility purposes they should be treated as one |
175 | and thus they are represented by a third invisible item with the right geometry. |
176 | |
177 | For example a speed display adds "m/s" as a smaller label: |
178 | \qml |
179 | Row { |
180 | Label { |
181 | id: speedLabel |
182 | text: "Speed: 5" |
183 | Accessible.ignored: true |
184 | } |
185 | Label { |
186 | text: qsTr("m/s") |
187 | Accessible.ignored: true |
188 | } |
189 | Accessible.role: Accessible.StaticText |
190 | Accessible.name: speedLabel.text + " meters per second" |
191 | } |
192 | \endqml |
193 | |
194 | \since 5.4 |
195 | By default this property is \c false. |
196 | */ |
197 | /*! \qmlproperty bool QtQuick::Accessible::multiLine |
198 | \brief This property holds whether this item has multiple text lines. |
199 | |
200 | By default this property is \c false. |
201 | */ |
202 | /*! \qmlproperty bool QtQuick::Accessible::readOnly |
203 | \brief This property indicates that a text field is read only. |
204 | |
205 | It is relevant when the role is \l QAccessible::EditableText and set to be read-only. |
206 | By default this property is \c false. |
207 | */ |
208 | /*! \qmlproperty bool QtQuick::Accessible::selected |
209 | \brief This property holds whether this item is selected. |
210 | |
211 | By default this property is \c false. |
212 | \sa selectable |
213 | */ |
214 | /*! \qmlproperty bool QtQuick::Accessible::selectable |
215 | \brief This property holds whether this item can be selected. |
216 | |
217 | By default this property is \c false. |
218 | \sa selected |
219 | */ |
220 | /*! \qmlproperty bool QtQuick::Accessible::pressed |
221 | \brief This property holds whether this item is pressed (for example a button during a mouse click). |
222 | |
223 | By default this property is \c false. |
224 | */ |
225 | /*! \qmlproperty bool QtQuick::Accessible::checkStateMixed |
226 | \brief This property holds whether this item is in the partially checked state. |
227 | |
228 | By default this property is \c false. |
229 | \sa checked, checkable |
230 | */ |
231 | /*! \qmlproperty bool QtQuick::Accessible::defaultButton |
232 | \brief This property holds whether this item is the default button of a dialog. |
233 | |
234 | By default this property is \c false. |
235 | */ |
236 | /*! \qmlproperty bool QtQuick::Accessible::passwordEdit |
237 | \brief This property holds whether this item is a password text edit. |
238 | |
239 | By default this property is \c false. |
240 | */ |
241 | /*! \qmlproperty bool QtQuick::Accessible::selectableText |
242 | \brief This property holds whether this item contains selectable text. |
243 | |
244 | By default this property is \c false. |
245 | */ |
246 | |
247 | /*! |
248 | \qmlsignal QtQuick::Accessible::pressAction() |
249 | |
250 | This signal is emitted when a press action is received from an assistive tool such as a screen-reader. |
251 | */ |
252 | /*! |
253 | \qmlsignal QtQuick::Accessible::toggleAction() |
254 | |
255 | This signal is emitted when a toggle action is received from an assistive tool such as a screen-reader. |
256 | */ |
257 | /*! |
258 | \qmlsignal QtQuick::Accessible::increaseAction() |
259 | |
260 | This signal is emitted when a increase action is received from an assistive tool such as a screen-reader. |
261 | */ |
262 | /*! |
263 | \qmlsignal QtQuick::Accessible::decreaseAction() |
264 | |
265 | This signal is emitted when a decrease action is received from an assistive tool such as a screen-reader. |
266 | */ |
267 | /*! |
268 | \qmlsignal QtQuick::Accessible::scrollUpAction() |
269 | |
270 | This signal is emitted when a scroll up action is received from an assistive tool such as a screen-reader. |
271 | */ |
272 | /*! |
273 | \qmlsignal QtQuick::Accessible::scrollDownAction() |
274 | |
275 | This signal is emitted when a scroll down action is received from an assistive tool such as a screen-reader. |
276 | */ |
277 | /*! |
278 | \qmlsignal QtQuick::Accessible::scrollLeftAction() |
279 | |
280 | This signal is emitted when a scroll left action is received from an assistive tool such as a screen-reader. |
281 | */ |
282 | /*! |
283 | \qmlsignal QtQuick::Accessible::scrollRightAction() |
284 | |
285 | This signal is emitted when a scroll right action is received from an assistive tool such as a screen-reader. |
286 | */ |
287 | /*! |
288 | \qmlsignal QtQuick::Accessible::previousPageAction() |
289 | |
290 | This signal is emitted when a previous page action is received from an assistive tool such as a screen-reader. |
291 | */ |
292 | /*! |
293 | \qmlsignal QtQuick::Accessible::nextPageAction() |
294 | |
295 | This signal is emitted when a next page action is received from an assistive tool such as a screen-reader. |
296 | */ |
297 | |
298 | QMetaMethod QQuickAccessibleAttached::sigPress; |
299 | QMetaMethod QQuickAccessibleAttached::sigToggle; |
300 | QMetaMethod QQuickAccessibleAttached::sigIncrease; |
301 | QMetaMethod QQuickAccessibleAttached::sigDecrease; |
302 | QMetaMethod QQuickAccessibleAttached::sigScrollUp; |
303 | QMetaMethod QQuickAccessibleAttached::sigScrollDown; |
304 | QMetaMethod QQuickAccessibleAttached::sigScrollLeft; |
305 | QMetaMethod QQuickAccessibleAttached::sigScrollRight; |
306 | QMetaMethod QQuickAccessibleAttached::sigPreviousPage; |
307 | QMetaMethod QQuickAccessibleAttached::sigNextPage; |
308 | |
309 | QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent) |
310 | : QObject(parent), m_role(QAccessible::NoRole) |
311 | { |
312 | Q_ASSERT(parent); |
313 | // Enable accessibility for items with accessible content. This also |
314 | // enables accessibility for the ancestors of such items. |
315 | auto item = qobject_cast<QQuickItem *>(o: parent); |
316 | if (item) { |
317 | item->d_func()->setAccessible(); |
318 | } else { |
319 | const QLatin1StringView className(QQmlData::ensurePropertyCache(object: parent)->firstCppMetaObject()->className()); |
320 | if (className != QLatin1StringView("QQuickAction" )) { |
321 | qmlWarning(me: parent) << "Accessible must be attached to an Item or an Action" ; |
322 | return; |
323 | } |
324 | } |
325 | QAccessibleEvent ev(parent, QAccessible::ObjectCreated); |
326 | QAccessible::updateAccessibility(event: &ev); |
327 | |
328 | if (const QMetaObject *pmo = parent->metaObject()) { |
329 | auto connectPropertyChangeSignal = [parent, pmo, this]( |
330 | const char *propertyName, const char *signalName, int slotIndex) |
331 | { |
332 | // basically does this: |
333 | // if the parent has the property \a propertyName with the associated \a signalName: |
334 | // connect(parent, signalName, this, slotIndex) |
335 | |
336 | // Note that we explicitly want to only connect to standard property/signal naming |
337 | // convention: "value" & "valueChanged" |
338 | // (e.g. avoid a compound property with e.g. a signal notifier named "updated()") |
339 | int idxProperty = pmo->indexOfProperty(name: propertyName); |
340 | if (idxProperty != -1) { |
341 | const QMetaProperty property = pmo->property(index: idxProperty); |
342 | const QMetaMethod signal = property.notifySignal(); |
343 | if (signal.name() == signalName) |
344 | QMetaObject::connect(sender: parent, signal_index: signal.methodIndex(), receiver: this, method_index: slotIndex); |
345 | } |
346 | return; |
347 | }; |
348 | const QMetaObject &smo = staticMetaObject; |
349 | static const int valueChangedIndex = smo.indexOfSlot(slot: "valueChanged()" ); |
350 | connectPropertyChangeSignal("value" , "valueChanged" , valueChangedIndex); |
351 | |
352 | static const int cursorPositionChangedIndex = smo.indexOfSlot(slot: "cursorPositionChanged()" ); |
353 | connectPropertyChangeSignal("cursorPosition" , "cursorPositionChanged" , |
354 | cursorPositionChangedIndex); |
355 | } |
356 | |
357 | if (!sigPress.isValid()) { |
358 | sigPress = QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::pressAction); |
359 | sigToggle = QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::toggleAction); |
360 | sigIncrease = QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::increaseAction); |
361 | sigDecrease = QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::decreaseAction); |
362 | sigScrollUp = QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::scrollUpAction); |
363 | sigScrollDown = QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::scrollDownAction); |
364 | sigScrollLeft = QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::scrollLeftAction); |
365 | sigScrollRight = QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::scrollRightAction); |
366 | sigPreviousPage = QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::previousPageAction); |
367 | sigNextPage= QMetaMethod::fromSignal(signal: &QQuickAccessibleAttached::nextPageAction); |
368 | } |
369 | } |
370 | |
371 | QQuickAccessibleAttached::~QQuickAccessibleAttached() |
372 | { |
373 | } |
374 | |
375 | void QQuickAccessibleAttached::setRole(QAccessible::Role role) |
376 | { |
377 | if (role != m_role) { |
378 | m_role = role; |
379 | Q_EMIT roleChanged(); |
380 | // There is no way to signify role changes at the moment. |
381 | // QAccessible::updateAccessibility(parent(), 0, QAccessible::); |
382 | |
383 | switch (role) { |
384 | case QAccessible::CheckBox: |
385 | case QAccessible::RadioButton: |
386 | if (!m_stateExplicitlySet.focusable) |
387 | m_state.focusable = true; |
388 | if (!m_stateExplicitlySet.checkable) |
389 | m_state.checkable = true; |
390 | break; |
391 | case QAccessible::Button: |
392 | case QAccessible::MenuItem: |
393 | case QAccessible::PageTab: |
394 | case QAccessible::SpinBox: |
395 | case QAccessible::ComboBox: |
396 | case QAccessible::Terminal: |
397 | case QAccessible::ScrollBar: |
398 | if (!m_stateExplicitlySet.focusable) |
399 | m_state.focusable = true; |
400 | break; |
401 | case QAccessible::EditableText: |
402 | if (!m_stateExplicitlySet.editable) |
403 | m_state.editable = true; |
404 | if (!m_stateExplicitlySet.focusable) |
405 | m_state.focusable = true; |
406 | break; |
407 | case QAccessible::StaticText: |
408 | if (!m_stateExplicitlySet.readOnly) |
409 | m_state.readOnly = true; |
410 | if (!m_stateExplicitlySet.focusable) |
411 | m_state.focusable = true; |
412 | break; |
413 | default: |
414 | break; |
415 | } |
416 | } |
417 | } |
418 | |
419 | bool QQuickAccessibleAttached::wasNameExplicitlySet() const |
420 | { |
421 | return m_nameExplicitlySet; |
422 | } |
423 | |
424 | // Allows types to attach an accessible name to an item as a convenience, |
425 | // so long as the user hasn't done so themselves. |
426 | void QQuickAccessibleAttached::setNameImplicitly(const QString &name) |
427 | { |
428 | setName(name); |
429 | m_nameExplicitlySet = false; |
430 | } |
431 | |
432 | QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj) |
433 | { |
434 | return new QQuickAccessibleAttached(obj); |
435 | } |
436 | |
437 | bool QQuickAccessibleAttached::ignored() const |
438 | { |
439 | auto item = qobject_cast<QQuickItem *>(o: parent()); |
440 | return item ? !item->d_func()->isAccessible : false; |
441 | } |
442 | |
443 | void QQuickAccessibleAttached::setIgnored(bool ignored) |
444 | { |
445 | auto item = qobject_cast<QQuickItem *>(o: parent()); |
446 | if (item && this->ignored() != ignored) { |
447 | item->d_func()->isAccessible = !ignored; |
448 | emit ignoredChanged(); |
449 | } |
450 | } |
451 | |
452 | bool QQuickAccessibleAttached::doAction(const QString &actionName) |
453 | { |
454 | QMetaMethod *sig = nullptr; |
455 | if (actionName == QAccessibleActionInterface::pressAction()) |
456 | sig = &sigPress; |
457 | else if (actionName == QAccessibleActionInterface::toggleAction()) |
458 | sig = &sigToggle; |
459 | else if (actionName == QAccessibleActionInterface::increaseAction()) |
460 | sig = &sigIncrease; |
461 | else if (actionName == QAccessibleActionInterface::decreaseAction()) |
462 | sig = &sigDecrease; |
463 | else if (actionName == QAccessibleActionInterface::scrollUpAction()) |
464 | sig = &sigScrollUp; |
465 | else if (actionName == QAccessibleActionInterface::scrollDownAction()) |
466 | sig = &sigScrollDown; |
467 | else if (actionName == QAccessibleActionInterface::scrollLeftAction()) |
468 | sig = &sigScrollLeft; |
469 | else if (actionName == QAccessibleActionInterface::scrollRightAction()) |
470 | sig = &sigScrollRight; |
471 | else if (actionName == QAccessibleActionInterface::previousPageAction()) |
472 | sig = &sigPreviousPage; |
473 | else if (actionName == QAccessibleActionInterface::nextPageAction()) |
474 | sig = &sigNextPage; |
475 | if (sig && isSignalConnected(signal: *sig)) { |
476 | bool ret = false; |
477 | if (m_proxying) |
478 | ret = sig->invoke(obj: m_proxying); |
479 | if (!ret) |
480 | ret = sig->invoke(obj: this); |
481 | return ret; |
482 | } |
483 | return false; |
484 | } |
485 | |
486 | void QQuickAccessibleAttached::availableActions(QStringList *actions) const |
487 | { |
488 | if (isSignalConnected(signal: sigPress)) |
489 | actions->append(t: QAccessibleActionInterface::pressAction()); |
490 | if (isSignalConnected(signal: sigToggle)) |
491 | actions->append(t: QAccessibleActionInterface::toggleAction()); |
492 | if (isSignalConnected(signal: sigIncrease)) |
493 | actions->append(t: QAccessibleActionInterface::increaseAction()); |
494 | if (isSignalConnected(signal: sigDecrease)) |
495 | actions->append(t: QAccessibleActionInterface::decreaseAction()); |
496 | if (isSignalConnected(signal: sigScrollUp)) |
497 | actions->append(t: QAccessibleActionInterface::scrollUpAction()); |
498 | if (isSignalConnected(signal: sigScrollDown)) |
499 | actions->append(t: QAccessibleActionInterface::scrollDownAction()); |
500 | if (isSignalConnected(signal: sigScrollLeft)) |
501 | actions->append(t: QAccessibleActionInterface::scrollLeftAction()); |
502 | if (isSignalConnected(signal: sigScrollRight)) |
503 | actions->append(t: QAccessibleActionInterface::scrollRightAction()); |
504 | if (isSignalConnected(signal: sigPreviousPage)) |
505 | actions->append(t: QAccessibleActionInterface::previousPageAction()); |
506 | if (isSignalConnected(signal: sigNextPage)) |
507 | actions->append(t: QAccessibleActionInterface::nextPageAction()); |
508 | } |
509 | |
510 | QString QQuickAccessibleAttached::stripHtml(const QString &html) |
511 | { |
512 | #ifndef QT_NO_TEXTHTMLPARSER |
513 | QTextDocument doc; |
514 | doc.setHtml(html); |
515 | return doc.toPlainText(); |
516 | #else |
517 | return html; |
518 | #endif |
519 | } |
520 | |
521 | void QQuickAccessibleAttached::setProxying(QQuickAccessibleAttached *proxying) |
522 | { |
523 | if (proxying == m_proxying) |
524 | return; |
525 | |
526 | const QMetaObject &mo = staticMetaObject; |
527 | if (m_proxying) { |
528 | // We disconnect all signals from the proxy into this object |
529 | auto mo = m_proxying->metaObject(); |
530 | auto propertyCache = QQmlData::ensurePropertyCache(object: m_proxying); |
531 | for (int signalIndex = propertyCache->signalOffset(); |
532 | signalIndex < propertyCache->signalCount(); ++signalIndex) { |
533 | const QMetaMethod m = mo->method(index: propertyCache->signal(index: signalIndex)->coreIndex()); |
534 | Q_ASSERT(m.methodType() == QMetaMethod::Signal); |
535 | if (m.methodType() != QMetaMethod::Signal) |
536 | continue; |
537 | |
538 | disconnect(sender: m_proxying, signal: m, receiver: this, member: m); |
539 | } |
540 | } |
541 | |
542 | m_proxying = proxying; |
543 | |
544 | if (m_proxying) { |
545 | // We connect all signals from the proxy into this object |
546 | auto propertyCache = QQmlData::ensurePropertyCache(object: m_proxying); |
547 | auto mo = m_proxying->metaObject(); |
548 | for (int signalIndex = propertyCache->signalOffset(); |
549 | signalIndex < propertyCache->signalCount(); ++signalIndex) { |
550 | const QMetaMethod m = mo->method(index: propertyCache->signal(index: signalIndex)->coreIndex()); |
551 | Q_ASSERT(m.methodType() == QMetaMethod::Signal); |
552 | connect(sender: proxying, signal: m, receiver: this, method: m); |
553 | } |
554 | } |
555 | |
556 | // We check all properties |
557 | for (int prop = mo.propertyOffset(); prop < mo.propertyCount(); ++prop) { |
558 | const QMetaProperty p = mo.property(index: prop); |
559 | if (!p.hasNotifySignal()) { |
560 | continue; |
561 | } |
562 | |
563 | const QMetaMethod signal = p.notifySignal(); |
564 | if (signal.parameterCount() == 0) |
565 | signal.invoke(obj: this); |
566 | else |
567 | signal.invoke(obj: this, Q_ARG(bool, p.read(this).toBool())); |
568 | } |
569 | } |
570 | |
571 | /*! |
572 | * \since 6.8 |
573 | * Issues an announcement event with a \a message with politeness \a politeness. |
574 | * |
575 | * \sa QAccessibleAnnouncementEvent |
576 | */ |
577 | void QQuickAccessibleAttached::announce(const QString &message, QAccessible::AnnouncementPoliteness politeness) |
578 | { |
579 | QAccessibleAnnouncementEvent event(parent(), message); |
580 | event.setPoliteness(politeness); |
581 | QAccessible::updateAccessibility(event: &event); |
582 | } |
583 | |
584 | QT_END_NAMESPACE |
585 | |
586 | #include "moc_qquickaccessibleattached_p.cpp" |
587 | |
588 | #endif |
589 | |