1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <QtGui/qtguiglobal.h>
41 #if QT_CONFIG(accessibility)
42 
43 #include "qwindowsuiatextrangeprovider.h"
44 #include "qwindowsuiamainprovider.h"
45 #include "qwindowsuiautils.h"
46 #include "qwindowscontext.h"
47 
48 #include <QtGui/qaccessible.h>
49 #include <QtCore/qloggingcategory.h>
50 #include <QtCore/qstring.h>
51 #include <QtCore/qvarlengtharray.h>
52 
53 QT_BEGIN_NAMESPACE
54 
55 using namespace QWindowsUiAutomation;
56 
57 
QWindowsUiaTextRangeProvider(QAccessible::Id id,int startOffset,int endOffset)58 QWindowsUiaTextRangeProvider::QWindowsUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset) :
59     QWindowsUiaBaseProvider(id),
60     m_startOffset(startOffset),
61     m_endOffset(endOffset)
62 {
63     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this << startOffset << endOffset;
64 }
65 
~QWindowsUiaTextRangeProvider()66 QWindowsUiaTextRangeProvider::~QWindowsUiaTextRangeProvider()
67 {
68     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
69 }
70 
AddToSelection()71 HRESULT QWindowsUiaTextRangeProvider::AddToSelection()
72 {
73     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
74     return Select();
75 }
76 
Clone(ITextRangeProvider ** pRetVal)77 HRESULT QWindowsUiaTextRangeProvider::Clone(ITextRangeProvider **pRetVal)
78 {
79     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
80 
81     if (!pRetVal)
82         return E_INVALIDARG;
83 
84     *pRetVal = new QWindowsUiaTextRangeProvider(id(), m_startOffset, m_endOffset);
85     return S_OK;
86 }
87 
88 // Two ranges are considered equal if their start/end points are the same.
Compare(ITextRangeProvider * range,BOOL * pRetVal)89 HRESULT QWindowsUiaTextRangeProvider::Compare(ITextRangeProvider *range, BOOL *pRetVal)
90 {
91     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
92 
93     if (!range || !pRetVal)
94         return E_INVALIDARG;
95 
96     auto *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(range);
97     *pRetVal = ((targetProvider->m_startOffset == m_startOffset) && (targetProvider->m_endOffset == m_endOffset));
98     return S_OK;
99 }
100 
101 // Compare different endpoinds between two providers.
CompareEndpoints(TextPatternRangeEndpoint endpoint,ITextRangeProvider * targetRange,TextPatternRangeEndpoint targetEndpoint,int * pRetVal)102 HRESULT QWindowsUiaTextRangeProvider::CompareEndpoints(TextPatternRangeEndpoint endpoint,
103                                                        ITextRangeProvider *targetRange,
104                                                        TextPatternRangeEndpoint targetEndpoint,
105                                                        int *pRetVal)
106 {
107     qCDebug(lcQpaUiAutomation) << __FUNCTION__
108         << "endpoint=" << endpoint << "targetRange=" << targetRange
109         << "targetEndpoint=" << targetEndpoint << "this: " << this;
110 
111     if (!targetRange || !pRetVal)
112         return E_INVALIDARG;
113 
114     auto *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange);
115 
116     int point = (endpoint == TextPatternRangeEndpoint_Start) ? m_startOffset : m_endOffset;
117     int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ?
118                 targetProvider->m_startOffset : targetProvider->m_endOffset;
119     *pRetVal = point - targetPoint;
120     return S_OK;
121 }
122 
123 // Expands/normalizes the range for a given text unit.
ExpandToEnclosingUnit(TextUnit unit)124 HRESULT QWindowsUiaTextRangeProvider::ExpandToEnclosingUnit(TextUnit unit)
125 {
126     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "unit=" << unit << "this: " << this;
127 
128     QAccessibleInterface *accessible = accessibleInterface();
129     if (!accessible)
130         return UIA_E_ELEMENTNOTAVAILABLE;
131 
132     QAccessibleTextInterface *textInterface = accessible->textInterface();
133     if (!textInterface)
134         return UIA_E_ELEMENTNOTAVAILABLE;
135 
136     int len = textInterface->characterCount();
137     if (len < 1) {
138         m_startOffset = 0;
139         m_endOffset = 0;
140     } else {
141         if (unit == TextUnit_Character) {
142             m_startOffset = qBound(0, m_startOffset, len - 1);
143             m_endOffset = m_startOffset + 1;
144         } else {
145             QString text = textInterface->text(0, len);
146             for (int t = m_startOffset; t >= 0; --t) {
147                 if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) {
148                     m_startOffset = t;
149                     break;
150                 }
151             }
152             for (int t = m_startOffset; t < len; ++t) {
153                 if ((t == len - 1) || (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1])))) {
154                     m_endOffset = t + 1;
155                     break;
156                 }
157             }
158         }
159     }
160     return S_OK;
161 }
162 
163 // Not supported.
FindAttribute(TEXTATTRIBUTEID,VARIANT,BOOL,ITextRangeProvider ** pRetVal)164 HRESULT QWindowsUiaTextRangeProvider::FindAttribute(TEXTATTRIBUTEID /* attributeId */,
165                                                     VARIANT /* val */, BOOL /* backward */,
166                                                     ITextRangeProvider **pRetVal)
167 {
168     if (!pRetVal)
169         return E_INVALIDARG;
170     *pRetVal = nullptr;
171     return S_OK;
172 }
173 
174 // Returns the value of a given attribute.
GetAttributeValue(TEXTATTRIBUTEID attributeId,VARIANT * pRetVal)175 HRESULT STDMETHODCALLTYPE QWindowsUiaTextRangeProvider::GetAttributeValue(TEXTATTRIBUTEID attributeId,
176                                                                           VARIANT *pRetVal)
177 {
178     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "attributeId=" << attributeId << "this: " << this;
179 
180     if (!pRetVal)
181         return E_INVALIDARG;
182     clearVariant(pRetVal);
183 
184     QAccessibleInterface *accessible = accessibleInterface();
185     if (!accessible)
186         return UIA_E_ELEMENTNOTAVAILABLE;
187 
188     QAccessibleTextInterface *textInterface = accessible->textInterface();
189     if (!textInterface)
190         return UIA_E_ELEMENTNOTAVAILABLE;
191 
192     switch (attributeId) {
193     case UIA_IsReadOnlyAttributeId:
194         setVariantBool(accessible->state().readOnly, pRetVal);
195         break;
196     case UIA_CaretPositionAttributeId:
197         if (textInterface->cursorPosition() == 0)
198             setVariantI4(CaretPosition_BeginningOfLine, pRetVal);
199         else if (textInterface->cursorPosition() == textInterface->characterCount())
200             setVariantI4(CaretPosition_EndOfLine, pRetVal);
201         else
202             setVariantI4(CaretPosition_Unknown, pRetVal);
203         break;
204     default:
205         break;
206     }
207     return S_OK;
208 }
209 
210 // Returns an array of bounding rectangles for text lines within the range.
GetBoundingRectangles(SAFEARRAY ** pRetVal)211 HRESULT QWindowsUiaTextRangeProvider::GetBoundingRectangles(SAFEARRAY **pRetVal)
212 {
213     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
214 
215     if (!pRetVal)
216         return E_INVALIDARG;
217 
218     QAccessibleInterface *accessible = accessibleInterface();
219     if (!accessible)
220         return UIA_E_ELEMENTNOTAVAILABLE;
221 
222     QAccessibleTextInterface *textInterface = accessible->textInterface();
223     if (!textInterface)
224         return UIA_E_ELEMENTNOTAVAILABLE;
225 
226     QWindow *window = windowForAccessible(accessible);
227     if (!window)
228         return UIA_E_ELEMENTNOTAVAILABLE;
229 
230     int len = textInterface->characterCount();
231     QVarLengthArray<QRect> rectList;
232 
233     if ((m_startOffset >= 0) && (m_endOffset <= len) && (m_startOffset < m_endOffset)) {
234         int start, end;
235         textInterface->textAtOffset(m_startOffset, QAccessible::LineBoundary, &start, &end);
236         while ((start >= 0) && (end >= 0)) {
237             int startRange = qMax(start, m_startOffset);
238             int endRange = qMin(end, m_endOffset);
239             if (startRange < endRange) {
240                 // Calculates a bounding rectangle for the line and adds it to the list.
241                 const QRect startRect = textInterface->characterRect(startRange);
242                 const QRect endRect = textInterface->characterRect(endRange - 1);
243                 const QRect lineRect(qMin(startRect.x(), endRect.x()),
244                                      qMin(startRect.y(), endRect.y()),
245                                      qMax(startRect.x() + startRect.width(), endRect.x() + endRect.width()) - qMin(startRect.x(), endRect.x()),
246                                      qMax(startRect.y() + startRect.height(), endRect.y() + endRect.height()) - qMin(startRect.y(), endRect.y()));
247                 rectList.append(lineRect);
248             }
249             if (end >= len) break;
250             textInterface->textAfterOffset(end + 1, QAccessible::LineBoundary, &start, &end);
251         }
252     }
253 
254     if ((*pRetVal = SafeArrayCreateVector(VT_R8, 0, 4 * rectList.size()))) {
255         for (int i = 0; i < rectList.size(); ++i) {
256             // Scale rect for high DPI screens.
257             UiaRect uiaRect;
258             rectToNativeUiaRect(rectList[i], window, &uiaRect);
259             double coords[4] = { uiaRect.left, uiaRect.top, uiaRect.width, uiaRect.height };
260             for (int j = 0; j < 4; ++j) {
261                 LONG idx = 4 * i + j;
262                 SafeArrayPutElement(*pRetVal, &idx, &coords[j]);
263             }
264         }
265     }
266     return S_OK;
267 }
268 
269 // Returns an array of children elements embedded within the range.
GetChildren(SAFEARRAY ** pRetVal)270 HRESULT QWindowsUiaTextRangeProvider::GetChildren(SAFEARRAY **pRetVal)
271 {
272     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
273 
274     if (!pRetVal)
275         return E_INVALIDARG;
276     // Not supporting any children.
277     *pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, 0);
278     return S_OK;
279 }
280 
281 // Returns a provider for the enclosing element (text to which the range belongs).
GetEnclosingElement(IRawElementProviderSimple ** pRetVal)282 HRESULT QWindowsUiaTextRangeProvider::GetEnclosingElement(IRawElementProviderSimple **pRetVal)
283 {
284     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
285 
286     if (!pRetVal)
287         return E_INVALIDARG;
288 
289     QAccessibleInterface *accessible = accessibleInterface();
290     if (!accessible)
291         return UIA_E_ELEMENTNOTAVAILABLE;
292 
293     *pRetVal = QWindowsUiaMainProvider::providerForAccessible(accessible);
294     return S_OK;
295 }
296 
297 // Gets the text within the range.
GetText(int maxLength,BSTR * pRetVal)298 HRESULT QWindowsUiaTextRangeProvider::GetText(int maxLength, BSTR *pRetVal)
299 {
300     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << maxLength << "this: " << this;
301 
302     if (!pRetVal)
303         return E_INVALIDARG;
304     *pRetVal = nullptr;
305 
306     QAccessibleInterface *accessible = accessibleInterface();
307     if (!accessible)
308         return UIA_E_ELEMENTNOTAVAILABLE;
309 
310     QAccessibleTextInterface *textInterface = accessible->textInterface();
311     if (!textInterface)
312         return UIA_E_ELEMENTNOTAVAILABLE;
313 
314     int len = textInterface->characterCount();
315     QString rangeText;
316     if ((m_startOffset >= 0) && (m_endOffset <= len) && (m_startOffset < m_endOffset))
317         rangeText = textInterface->text(m_startOffset, m_endOffset);
318 
319     if ((maxLength > -1) && (rangeText.size() > maxLength))
320         rangeText.truncate(maxLength);
321     *pRetVal = bStrFromQString(rangeText);
322     return S_OK;
323 }
324 
325 // Moves the range a specified number of units (and normalizes it).
Move(TextUnit unit,int count,int * pRetVal)326 HRESULT QWindowsUiaTextRangeProvider::Move(TextUnit unit, int count, int *pRetVal)
327 {
328     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "unit=" << unit << "count=" << count << "this: " << this;
329 
330     if (!pRetVal)
331         return E_INVALIDARG;
332     *pRetVal = 0;
333 
334     QAccessibleInterface *accessible = accessibleInterface();
335     if (!accessible)
336         return UIA_E_ELEMENTNOTAVAILABLE;
337 
338     QAccessibleTextInterface *textInterface = accessible->textInterface();
339     if (!textInterface)
340         return UIA_E_ELEMENTNOTAVAILABLE;
341 
342     int len = textInterface->characterCount();
343 
344     if (len < 1)
345         return S_OK;
346 
347     if (unit == TextUnit_Character) {
348         // Moves the start point, ensuring it lies within the bounds.
349         int start = qBound(0, m_startOffset + count, len - 1);
350         // If range was initially empty, leaves it as is; otherwise, normalizes it to one char.
351         m_endOffset = (m_endOffset > m_startOffset) ? start + 1 : start;
352         *pRetVal = start - m_startOffset; // Returns the actually moved distance.
353         m_startOffset = start;
354     } else {
355         if (count > 0) {
356             MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, pRetVal);
357             MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, pRetVal);
358         } else {
359             MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, pRetVal);
360             MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, pRetVal);
361         }
362     }
363     return S_OK;
364 }
365 
366 // Copies the value of an end point from one range to another.
MoveEndpointByRange(TextPatternRangeEndpoint endpoint,ITextRangeProvider * targetRange,TextPatternRangeEndpoint targetEndpoint)367 HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByRange(TextPatternRangeEndpoint endpoint,
368                                                           ITextRangeProvider *targetRange,
369                                                           TextPatternRangeEndpoint targetEndpoint)
370 {
371     if (!targetRange)
372         return E_INVALIDARG;
373 
374     qCDebug(lcQpaUiAutomation) << __FUNCTION__
375         << "endpoint=" << endpoint << "targetRange=" << targetRange << "targetEndpoint=" << targetEndpoint << "this: " << this;
376 
377     auto *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange);
378 
379     int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ?
380                 targetProvider->m_startOffset : targetProvider->m_endOffset;
381 
382     // If the moved endpoint crosses the other endpoint, that one is moved too.
383     if (endpoint == TextPatternRangeEndpoint_Start) {
384         m_startOffset = targetPoint;
385         if (m_endOffset < m_startOffset)
386             m_endOffset = m_startOffset;
387     } else {
388         m_endOffset = targetPoint;
389         if (m_endOffset < m_startOffset)
390             m_startOffset = m_endOffset;
391     }
392     return S_OK;
393 }
394 
395 // Moves an endpoint an specific number of units.
MoveEndpointByUnit(TextPatternRangeEndpoint endpoint,TextUnit unit,int count,int * pRetVal)396 HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByUnit(TextPatternRangeEndpoint endpoint,
397                                                          TextUnit unit, int count,
398                                                          int *pRetVal)
399 {
400     qCDebug(lcQpaUiAutomation) << __FUNCTION__
401         << "endpoint=" << endpoint << "unit=" << unit << "count=" << count << "this: " << this;
402 
403     if (!pRetVal)
404         return E_INVALIDARG;
405     *pRetVal = 0;
406 
407     QAccessibleInterface *accessible = accessibleInterface();
408     if (!accessible)
409         return UIA_E_ELEMENTNOTAVAILABLE;
410 
411     QAccessibleTextInterface *textInterface = accessible->textInterface();
412     if (!textInterface)
413         return UIA_E_ELEMENTNOTAVAILABLE;
414 
415     int len = textInterface->characterCount();
416 
417     if (len < 1)
418         return S_OK;
419 
420     if (unit == TextUnit_Character) {
421         if (endpoint == TextPatternRangeEndpoint_Start) {
422             int boundedValue = qBound(0, m_startOffset + count, len - 1);
423             *pRetVal = boundedValue - m_startOffset;
424             m_startOffset = boundedValue;
425             m_endOffset = qBound(m_startOffset, m_endOffset, len);
426         } else {
427             int boundedValue = qBound(0, m_endOffset + count, len);
428             *pRetVal = boundedValue - m_endOffset;
429             m_endOffset = boundedValue;
430             m_startOffset = qBound(0, m_startOffset, m_endOffset);
431         }
432     } else {
433         QString text = textInterface->text(0, len);
434         int moved = 0;
435 
436         if (endpoint == TextPatternRangeEndpoint_Start) {
437             if (count > 0) {
438                 for (int t = m_startOffset; (t < len - 1) && (moved < count); ++t) {
439                     if (isTextUnitSeparator(unit, text[t]) && !isTextUnitSeparator(unit, text[t + 1])) {
440                         m_startOffset = t + 1;
441                         ++moved;
442                     }
443                 }
444                 m_endOffset = qBound(m_startOffset, m_endOffset, len);
445             } else {
446                 for (int t = m_startOffset - 1; (t >= 0) && (moved > count); --t) {
447                     if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) {
448                         m_startOffset = t;
449                         --moved;
450                     }
451                 }
452             }
453         } else {
454             if (count > 0) {
455                 for (int t = m_endOffset; (t < len) && (moved < count); ++t) {
456                     if ((t == len - 1) || (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1])))) {
457                         m_endOffset = t + 1;
458                         ++moved;
459                     }
460                 }
461             } else {
462                 int end = 0;
463                 for (int t = m_endOffset - 2; (t > 0) && (moved > count); --t) {
464                     if (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1]))) {
465                         end = t + 1;
466                         --moved;
467                     }
468                 }
469                 m_endOffset = end;
470                 m_startOffset = qBound(0, m_startOffset, m_endOffset);
471             }
472         }
473         *pRetVal = moved;
474     }
475     return S_OK;
476 }
477 
RemoveFromSelection()478 HRESULT QWindowsUiaTextRangeProvider::RemoveFromSelection()
479 {
480     qCDebug(lcQpaUiAutomation) << __FUNCTION__;
481     // unselects all
482     return unselect();
483 }
484 
485 // Scrolls the range into view.
ScrollIntoView(BOOL alignToTop)486 HRESULT QWindowsUiaTextRangeProvider::ScrollIntoView(BOOL alignToTop)
487 {
488     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "alignToTop=" << alignToTop << "this: " << this;
489 
490     QAccessibleInterface *accessible = accessibleInterface();
491     if (!accessible)
492         return UIA_E_ELEMENTNOTAVAILABLE;
493 
494     QAccessibleTextInterface *textInterface = accessible->textInterface();
495     if (!textInterface)
496         return UIA_E_ELEMENTNOTAVAILABLE;
497 
498     textInterface->scrollToSubstring(m_startOffset, m_endOffset);
499     return S_OK;
500 }
501 
502 // Selects the range.
Select()503 HRESULT QWindowsUiaTextRangeProvider::Select()
504 {
505     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
506 
507     QAccessibleInterface *accessible = accessibleInterface();
508     if (!accessible)
509         return UIA_E_ELEMENTNOTAVAILABLE;
510 
511     QAccessibleTextInterface *textInterface = accessible->textInterface();
512     if (!textInterface)
513         return UIA_E_ELEMENTNOTAVAILABLE;
514 
515     // unselects all and adds a new selection
516     unselect();
517     textInterface->addSelection(m_startOffset, m_endOffset);
518     return S_OK;
519 }
520 
521 // Not supported.
FindText(BSTR,BOOL,BOOL,ITextRangeProvider ** pRetVal)522 HRESULT QWindowsUiaTextRangeProvider::FindText(BSTR /* text */, BOOL /* backward */,
523                                                BOOL /* ignoreCase */,
524                                                ITextRangeProvider **pRetVal)
525 {
526     if (!pRetVal)
527         return E_INVALIDARG;
528     *pRetVal = nullptr;
529     return S_OK;
530 }
531 
532 // Removes all selected ranges from the text element.
unselect()533 HRESULT QWindowsUiaTextRangeProvider::unselect()
534 {
535     qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
536 
537     QAccessibleInterface *accessible = accessibleInterface();
538     if (!accessible)
539         return UIA_E_ELEMENTNOTAVAILABLE;
540 
541     QAccessibleTextInterface *textInterface = accessible->textInterface();
542     if (!textInterface)
543         return UIA_E_ELEMENTNOTAVAILABLE;
544 
545     int selCount = textInterface->selectionCount();
546 
547     for (int i = selCount - 1; i >= 0; --i)
548         textInterface->removeSelection(i);
549     return S_OK;
550 }
551 
552 QT_END_NAMESPACE
553 
554 #endif // QT_CONFIG(accessibility)
555