tests/auto/qaccessibility_mac/tst_qaccessibility_mac.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 #include <QtTest/QtTest>
       
    42 
       
    43 #if defined(Q_WS_MAC) && !defined (QT_MAC_USE_COCOA)
       
    44 
       
    45 #include <private/qt_mac_p.h>
       
    46 #undef verify // yes, lets reserve the word "verify"
       
    47 
       
    48 #include <QApplication>
       
    49 #include <QDebug>
       
    50 #include <QTimer>
       
    51 #include <QString>
       
    52 #include <QFile>
       
    53 #include <QVariant>
       
    54 #include <QPushButton>
       
    55 #include <QToolBar>
       
    56 #include <QSlider>
       
    57 #include <QListWidget>
       
    58 #include <QTableWidget>
       
    59 #include <QScrollArea>
       
    60 #include <QLabel>
       
    61 #include <QScrollBar>
       
    62 #include <QTextEdit>
       
    63 #include <QAccessibleInterface>
       
    64 #include <QAccessible>
       
    65 #include <QPluginLoader>
       
    66 #include <private/qaccessible_mac_p.h>
       
    67 #include <quiloader.h>
       
    68 
       
    69 #include <sys/types.h> // for getpid()
       
    70 #include <unistd.h>
       
    71 
       
    72 Q_DECLARE_METATYPE(AXUIElementRef);
       
    73 
       
    74 typedef QCFType<CFArrayRef> QCFArrayRef;
       
    75 
       
    76 class tst_qaccessibility_mac : public QObject
       
    77 {
       
    78 Q_OBJECT
       
    79 public slots:
       
    80     void printInfo();
       
    81     void testForm();
       
    82     void testButtons();
       
    83     void testLineEdit();
       
    84     void testLabel();
       
    85     void testGroups();
       
    86     void testTabWidget();
       
    87     void testTabBar();
       
    88     void testComboBox();
       
    89     void testDeleteWidget();
       
    90     void testDeleteWidgets();
       
    91     void testMultipleWindows();
       
    92     void testHiddenWidgets();
       
    93     void testActions();
       
    94     void testChangeState();
       
    95     void testSlider();
       
    96     void testScrollArea();
       
    97     void testListView();
       
    98     void testTableView();
       
    99     void testScrollBar();
       
   100     void testSplitter();
       
   101     void testTextEdit();
       
   102     void testItemViewsWithoutModel();
       
   103 private slots:
       
   104     void testQAElement();
       
   105     void testQAInterface();
       
   106 
       
   107     // ui tests load an .ui file.
       
   108     void uitests_data();
       
   109     void uitests();
       
   110     
       
   111     void tests_data();
       
   112     void tests();
       
   113 private:
       
   114     void runTest(const QString &testSlot);
       
   115 };
       
   116 
       
   117 /*
       
   118     VERIFYs that there is no error and prints an error message if there is.
       
   119 */
       
   120 void testError(AXError error, const QString &text)
       
   121 {
       
   122     if (error)
       
   123         qDebug() << "Error" << error << text;
       
   124     QVERIFY(error == 0);
       
   125 }
       
   126 
       
   127 /*
       
   128     Prints an CFArray holding CFStrings.
       
   129 */
       
   130 void printCFStringArray(CFArrayRef array, const QString &title)
       
   131 {
       
   132     const int numElements = CFArrayGetCount(array);
       
   133     qDebug() << "num" << title << " " <<  numElements;
       
   134 
       
   135     for (int i = 0; i < numElements; ++i) {
       
   136        CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(array, i);
       
   137        qDebug() << QCFString::toQString(str);
       
   138     }
       
   139 }
       
   140 
       
   141 QStringList toQStringList(const CFArrayRef array)
       
   142 {
       
   143     const int numElements = CFArrayGetCount(array);
       
   144     QStringList qtStrings;
       
   145     
       
   146     for (int i = 0; i < numElements; ++i) {
       
   147         CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(array, i);
       
   148         qtStrings.append(QCFString::toQString(str));
       
   149     }
       
   150     
       
   151     return qtStrings;
       
   152 }
       
   153 
       
   154 QVariant AXValueToQVariant(AXValueRef value)
       
   155 {
       
   156     QVariant var;
       
   157     const AXValueType type = AXValueGetType(value);
       
   158     switch (type) {
       
   159         case kAXValueCGPointType : {
       
   160             CGPoint point;
       
   161             if (AXValueGetValue(value, type, &point))
       
   162                 var = QPointF(point.x, point.y);
       
   163         } break;
       
   164         case kAXValueCGSizeType : {
       
   165             CGSize size;
       
   166             if (AXValueGetValue(value, type, &size))
       
   167                 var = QSizeF(size.width, size.height);
       
   168         } break;
       
   169         case kAXValueCGRectType :  {
       
   170             CGRect rect;
       
   171             if (AXValueGetValue(value, type, &rect))
       
   172                 var = QRectF(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
       
   173         } break;
       
   174         case kAXValueCFRangeType :
       
   175 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
       
   176         case kAXValueAXErrorType :
       
   177 #endif
       
   178         case kAXValueIllegalType :
       
   179         default:
       
   180         qDebug() << "Illegal/Unsuported AXValue:" << type;
       
   181         break;
       
   182     };
       
   183     return var;
       
   184 }
       
   185 
       
   186 /*
       
   187     Converts a CFTypeRef to a QVariant, for certain selected types. Prints
       
   188     an error message and returns QVariant() if the type is not supported.
       
   189 */
       
   190 QVariant CFTypeToQVariant(CFTypeRef value)
       
   191 {
       
   192     QVariant var;
       
   193     if (value == 0)
       
   194         return var;
       
   195     const uint typeID = CFGetTypeID(value);
       
   196     if (typeID == CFStringGetTypeID()) {
       
   197         var.setValue(QCFString::toQString((CFStringRef)value));
       
   198     } else if (typeID == CFBooleanGetTypeID()) {
       
   199         var.setValue((bool)CFBooleanGetValue((CFBooleanRef)value));
       
   200     } else if (typeID == AXUIElementGetTypeID()) {
       
   201         var.setValue((AXUIElementRef)value);
       
   202     } else if (typeID == AXValueGetTypeID()) {
       
   203         var = AXValueToQVariant((AXValueRef)value);
       
   204     } else if (typeID == CFNumberGetTypeID()) {
       
   205         CFNumberRef number = (CFNumberRef)value;
       
   206         if (CFNumberGetType(number) != kCFNumberSInt32Type)
       
   207             qDebug() << "unsupported number type" << CFNumberGetType(number);
       
   208         int theNumber;
       
   209         CFNumberGetValue(number, kCFNumberSInt32Type, &theNumber);
       
   210         var.setValue(theNumber);
       
   211     } else if (typeID == CFArrayGetTypeID()) {
       
   212         CFArrayRef cfarray = static_cast<CFArrayRef>(value);
       
   213         QVariantList list;
       
   214         CFIndex size = CFArrayGetCount(cfarray);
       
   215         for (CFIndex i = 0; i < size; ++i)
       
   216             list << CFTypeToQVariant(CFArrayGetValueAtIndex(cfarray, i));
       
   217         var.setValue(list);
       
   218     } else {
       
   219         QCFString str = CFCopyTypeIDDescription(typeID);
       
   220         qDebug() << "Unknown CFType: " << typeID << (QString)str;
       
   221     }
       
   222     return var;
       
   223 }
       
   224 
       
   225 /*
       
   226     Tests if a given attribute is supported by an element. Expects either
       
   227     no error or error -25205 (Not supported). Causes a test failure
       
   228     on other error values.
       
   229 */
       
   230 bool supportsAttribute(AXUIElementRef element, CFStringRef attribute)
       
   231 {
       
   232     CFArrayRef array;
       
   233     AXError err = AXUIElementCopyAttributeNames(element, &array);
       
   234     if (err) {
       
   235         testError(err, QLatin1String("unexpected error when testing for supported attribute") + QCFString::toQString(attribute));
       
   236         return false;
       
   237     }
       
   238     CFRange range;
       
   239     range.location = 0;
       
   240     range.length = CFArrayGetCount(array);
       
   241     return CFArrayContainsValue(array, range, attribute);
       
   242 }
       
   243 
       
   244 /*
       
   245     Returns the accessibility attribute specified with attribute in a QVariant
       
   246 */
       
   247 QVariant attribute(AXUIElementRef element, CFStringRef attribute)
       
   248 {
       
   249     CFTypeRef value = 0;
       
   250     AXError err = AXUIElementCopyAttributeValue(element, attribute, &value);
       
   251 
       
   252     testError(err, QString("Error getting element attribute ") + QCFString::toQString(attribute));
       
   253 
       
   254     if (err)
       
   255         return QVariant();
       
   256 
       
   257     return CFTypeToQVariant(value);
       
   258 }
       
   259 
       
   260 /*
       
   261     Returns the title for an element.
       
   262 */
       
   263 QString title(AXUIElementRef element)
       
   264 {
       
   265     return attribute(element, kAXTitleAttribute).toString();
       
   266 }
       
   267 
       
   268 /*
       
   269     Returns the role for an element.
       
   270 */
       
   271 QString role(AXUIElementRef element)
       
   272 {
       
   273     return attribute(element, kAXRoleAttribute).toString();
       
   274 }
       
   275 
       
   276 /*
       
   277     Returns the subrole for an element.
       
   278 */
       
   279 QString subrole(AXUIElementRef element)
       
   280 {
       
   281     return attribute(element, kAXSubroleAttribute).toString();
       
   282 }
       
   283 
       
   284 /*
       
   285     Returns the role description for an element.
       
   286 */
       
   287 QString roleDescription(AXUIElementRef element)
       
   288 {
       
   289     return attribute(element, kAXRoleDescriptionAttribute).toString();
       
   290 }
       
   291 
       
   292 /*
       
   293     Returns the enabled attribute for an element.
       
   294 */
       
   295 bool enabled(AXUIElementRef element)
       
   296 {
       
   297     return attribute(element, kAXEnabledAttribute).toBool();
       
   298 }
       
   299 
       
   300 /*
       
   301     Returns the value attribute for an element as an QVariant.
       
   302 */
       
   303 QVariant value(AXUIElementRef element)
       
   304 {
       
   305     return attribute(element, kAXValueAttribute);
       
   306 }
       
   307 
       
   308 QVariant value(QAElement element)
       
   309 {
       
   310     return value(element.element());
       
   311 }
       
   312 
       
   313 /*
       
   314     Returns the description attribute for an element as an QVariant.
       
   315 */
       
   316 QVariant description(AXUIElementRef element)
       
   317 {
       
   318     return attribute(element, kAXDescriptionAttribute);
       
   319 }
       
   320 
       
   321 /*
       
   322     Returns the value attribute for an element as an bool.
       
   323 */
       
   324 bool boolValue(AXUIElementRef element)
       
   325 {
       
   326     return attribute(element, kAXValueAttribute).toBool();
       
   327 }
       
   328 
       
   329 /*
       
   330     Returns the parent for an element
       
   331 */
       
   332 AXUIElementRef parent(AXUIElementRef element)
       
   333 {
       
   334     return attribute(element, kAXParentAttribute).value<AXUIElementRef>();
       
   335 }
       
   336 
       
   337 /*
       
   338     Returns the (top-level) window(not a sheet or a drawer) for an element
       
   339 */
       
   340 AXUIElementRef window(AXUIElementRef element)
       
   341 {
       
   342     return attribute(element, kAXWindowAttribute).value<AXUIElementRef>();
       
   343 }
       
   344 
       
   345 /*
       
   346     Returns the (top-level) UI element(can also be a sheet or drawer) for an element
       
   347 */
       
   348 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
       
   349 AXUIElementRef topLevelUIElement(AXUIElementRef element)
       
   350 {
       
   351     return attribute(element, kAXTopLevelUIElementAttribute).value<AXUIElementRef>();
       
   352 }
       
   353 #endif
       
   354 
       
   355 /*
       
   356     Returns thie size of the element.
       
   357 */
       
   358 QSizeF size(AXUIElementRef element)
       
   359 {
       
   360     return attribute(element, kAXSizeAttribute).value<QSizeF>();
       
   361 }
       
   362 
       
   363 /*
       
   364     Returns the position of the element.
       
   365 */
       
   366 QPointF position(AXUIElementRef element)
       
   367 {
       
   368     return attribute(element, kAXPositionAttribute).value<QPointF>();
       
   369 }
       
   370 
       
   371 /*
       
   372     Returns the rect of the element.
       
   373 */
       
   374 QRectF rect(AXUIElementRef element)
       
   375 {
       
   376     return QRectF(position(element), size(element));
       
   377 }
       
   378 
       
   379 bool above(AXUIElementRef a, AXUIElementRef b)
       
   380 {
       
   381     return (position(a).y() + size(a).height() <= position(b).y());
       
   382 }
       
   383 
       
   384 bool contains(AXUIElementRef a, AXUIElementRef b)
       
   385 {
       
   386     return rect(a).contains(rect(b));
       
   387 }
       
   388 
       
   389 QList<AXUIElementRef> tabs(AXUIElementRef element)
       
   390 {
       
   391     CFTypeRef value;
       
   392     AXError err = AXUIElementCopyAttributeValue(element, kAXTabsAttribute, &value);
       
   393     if (err)
       
   394         return QList<AXUIElementRef>();
       
   395         
       
   396     CFArrayRef array = (CFArrayRef)value;
       
   397     QList<AXUIElementRef> elements;
       
   398     const int count = CFArrayGetCount(array);
       
   399     for (int i = 0; i < count; ++i)
       
   400         elements.append((AXUIElementRef)CFArrayGetValueAtIndex(array, i));
       
   401    
       
   402     return elements;
       
   403 }
       
   404 
       
   405 QList<AXUIElementRef> elementListAttribute(AXUIElementRef element, CFStringRef attributeName)
       
   406 {
       
   407     QList<AXUIElementRef> elementList;
       
   408     QVariantList variants = attribute(element, attributeName).value<QVariantList>();
       
   409     foreach(QVariant variant, variants)
       
   410         elementList.append(variant.value<AXUIElementRef>());
       
   411     return elementList;
       
   412 }
       
   413 
       
   414 AXUIElementRef elementAttribute(AXUIElementRef element, CFStringRef attributeName)
       
   415 {
       
   416     return attribute(element, attributeName).value<AXUIElementRef>();
       
   417 }
       
   418 
       
   419 QString stringAttribute(AXUIElementRef element, CFStringRef attributeName)
       
   420 {
       
   421     return attribute(element, attributeName).value<QString>();
       
   422 }
       
   423 
       
   424 
       
   425 /*
       
   426     Returns the UIElement at the given position.
       
   427 */
       
   428 AXUIElementRef childAtPoint(QPointF position)
       
   429 {
       
   430     AXUIElementRef element = 0;
       
   431     const AXError err = AXUIElementCopyElementAtPosition(AXUIElementCreateApplication(getpid()), position.x(), position.y(), &element);
       
   432     if (err) {
       
   433         qDebug() << "Error getting element at " << position;
       
   434         return 0;
       
   435     }
       
   436 
       
   437     return element;
       
   438 }
       
   439 
       
   440 /*
       
   441     Returns a QStringList containing the names of the actions the ui element supports
       
   442 */
       
   443 QStringList actionNames(AXUIElementRef element)
       
   444 {
       
   445     CFArrayRef cfStrings;
       
   446     const AXError err = AXUIElementCopyActionNames(element, &cfStrings);
       
   447     testError(err, "Unable to get action names");
       
   448     return toQStringList(cfStrings);
       
   449 }
       
   450 
       
   451 bool supportsAction(const AXUIElementRef element, const QString &actionName)
       
   452 {
       
   453     const QStringList actions = actionNames(element);
       
   454     return actions.contains(actionName);
       
   455 }
       
   456 
       
   457 bool performAction(const AXUIElementRef element, const QString &actionName)
       
   458 {
       
   459     const AXError err = AXUIElementPerformAction(element, QCFString(actionName));
       
   460     return (err == 0);
       
   461 }
       
   462 
       
   463 /*
       
   464     Om 10.4 and up, verifyes the AXRoleDescription attribute for an element,
       
   465     on 10.3 and below this test always passes.
       
   466 
       
   467     The reason for this is that the HICopyAccessibilityRoleDescription call
       
   468     used to implement this functionality was introduced in 10.4.
       
   469 */
       
   470 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
       
   471     #define VERIFY_ROLE_DESCRIPTION(ELEMENT,  TEXT) \
       
   472             QCOMPARE(roleDescription(ELEMENT), QString(TEXT))
       
   473 #else
       
   474     #define VERIFY_ROLE_DESCRIPTION(ELEMENT,  TEXT) QVERIFY(true)
       
   475 #endif
       
   476 
       
   477 
       
   478 CFArrayRef childrenArray(AXUIElementRef element)
       
   479 {
       
   480     CFTypeRef value = 0;
       
   481     AXError err = AXUIElementCopyAttributeValue(element, kAXChildrenAttribute, &value);
       
   482     if (!err && CFGetTypeID(value) == CFArrayGetTypeID()) {
       
   483         return (CFArrayRef)value;
       
   484     }
       
   485    
       
   486     return CFArrayCreate(0,0,0,0);
       
   487 }
       
   488 
       
   489 /*
       
   490     Gest the child count from an element.
       
   491 */
       
   492 int numChildren(AXUIElementRef element)
       
   493 {
       
   494     return CFArrayGetCount(childrenArray(element));
       
   495 }
       
   496 
       
   497 /*
       
   498     Gets the child with index childIndex from element. Returns 0 if not found.
       
   499 */
       
   500 AXUIElementRef child(AXUIElementRef element, int childIndex)
       
   501 {
       
   502     CFArrayRef children = childrenArray(element);
       
   503     if (childIndex >= CFArrayGetCount(children))
       
   504         return 0;
       
   505 
       
   506     const void *data  = CFArrayGetValueAtIndex(children, childIndex);
       
   507     return (AXUIElementRef)data;
       
   508 }
       
   509 
       
   510 /*
       
   511     Gets the child titled childTitle from element. Returns 0 if not found.
       
   512 */
       
   513 AXUIElementRef childByTitle(AXUIElementRef element, const QString &childTitle)
       
   514 {
       
   515     CFArrayRef children  = childrenArray(element);
       
   516     const int numChildren = CFArrayGetCount(children);
       
   517     for (int i = 0; i < numChildren; ++i) {
       
   518         const AXUIElementRef childElement = (AXUIElementRef)CFArrayGetValueAtIndex(children, i);
       
   519         // Test for support for title attribute before getting it to avoid test fail.
       
   520         if (supportsAttribute(childElement, kAXTitleAttribute) && title(childElement) == childTitle)
       
   521             return childElement;
       
   522     }
       
   523     return 0;
       
   524 }
       
   525 
       
   526 /*
       
   527     Gets the child with the given value from element. Returns 0 if not found.
       
   528 */
       
   529 AXUIElementRef childByValue(AXUIElementRef element, const QVariant &testValue)
       
   530 {
       
   531     CFArrayRef children  = childrenArray(element);
       
   532     const int numChildren = CFArrayGetCount(children);
       
   533     for (int i = 0; i < numChildren; ++i) {
       
   534         const AXUIElementRef childElement = (AXUIElementRef)CFArrayGetValueAtIndex(children, i);
       
   535         // Test for support for value attribute before getting it to avoid test fail.
       
   536         if (supportsAttribute(childElement, kAXValueAttribute) && value(childElement) == testValue)
       
   537             return childElement;
       
   538     }
       
   539     return 0;
       
   540 }
       
   541 
       
   542 /*
       
   543     Gets the child by role from element. Returns 0 if not found.
       
   544 */
       
   545 AXUIElementRef childByRole(AXUIElementRef element, const QString &macRole)
       
   546 {
       
   547     CFArrayRef children  = childrenArray(element);
       
   548     const int numChildren = CFArrayGetCount(children);
       
   549     for (int i = 0; i < numChildren; ++i) {
       
   550         const AXUIElementRef childElement = (AXUIElementRef)CFArrayGetValueAtIndex(children, i);
       
   551         if (role(childElement) == macRole)
       
   552             return childElement;
       
   553     }
       
   554     return 0;
       
   555 }
       
   556 
       
   557 void printTypeForAttribute(AXUIElementRef element, CFStringRef attribute)
       
   558 {
       
   559     CFTypeRef value = 0;
       
   560     AXError err = AXUIElementCopyAttributeValue(element, attribute, &value);
       
   561     if (!err) {
       
   562         qDebug() << "type id" << CFGetTypeID(value);
       
   563         QCFString str = CFCopyTypeIDDescription(CFGetTypeID(value));
       
   564         qDebug() << (QString)str;
       
   565     } else {
       
   566         qDebug() << "Attribute Get error" << endl;
       
   567     }
       
   568 }
       
   569 
       
   570 int indent = 0;
       
   571 QString space()
       
   572 {
       
   573     QString space;
       
   574     for (int i = 0; i < indent; ++i) {
       
   575         space += " ";
       
   576     }
       
   577     return space;
       
   578 }
       
   579 
       
   580 
       
   581 /*
       
   582     Recursively prints acccesibility info for currentElement and all its children.
       
   583 */
       
   584 void printElementInfo(AXUIElementRef currentElement)
       
   585 {
       
   586     if (HIObjectIsAccessibilityIgnored(AXUIElementGetHIObject(currentElement))) {
       
   587         qDebug() << space() << "Ignoring element with role" << role(currentElement);
       
   588         return;
       
   589     }
       
   590     
       
   591     qDebug() << space() <<"Role" << role(currentElement);
       
   592     if (supportsAttribute(currentElement, kAXTitleAttribute))
       
   593         qDebug() << space() << "Title" << title(currentElement);
       
   594     else
       
   595         qDebug() << space() << "Title not supported";
       
   596     
       
   597     if (supportsAttribute(currentElement, kAXValueAttribute))
       
   598         qDebug() << space() << "Value" << attribute(currentElement, kAXValueAttribute);
       
   599     else
       
   600         qDebug() << space() << "Value not supported";
       
   601     
       
   602     qDebug() << space() << "Number of children" << numChildren(currentElement);
       
   603     for (int i = 0; i < numChildren(currentElement); ++i) {
       
   604         AXUIElementRef childElement = child(currentElement, i);
       
   605         // Skip the menu bar.
       
   606         if (role(childElement) != "AXMenuBar") {
       
   607             indent+= 4;
       
   608             printElementInfo(childElement);
       
   609             indent-= 4;
       
   610         }
       
   611     }
       
   612     qDebug() << " ";
       
   613 }
       
   614 
       
   615 /*
       
   616     Recursively prints the child interfaces belonging to interface.
       
   617 */
       
   618 
       
   619 void printChildren(const QAInterface &interface)
       
   620 {
       
   621     if (interface.isValid() == false)
       
   622         return;
       
   623         
       
   624     QList<QAInterface> children = interface.children();
       
   625     if (children.isEmpty())
       
   626         return;
       
   627 
       
   628     qDebug() << "## Children for" << interface;
       
   629     foreach (const QAInterface &child, children) {
       
   630         qDebug() << child << "index in parent" << interface.indexOfChild(child);
       
   631     }
       
   632     foreach (const QAInterface &child, children) {
       
   633         printChildren(child);
       
   634     }
       
   635 }
       
   636 
       
   637 bool isIgnored(AXUIElementRef currentElement)
       
   638 {
       
   639     return HIObjectIsAccessibilityIgnored(AXUIElementGetHIObject(currentElement));
       
   640 }
       
   641 
       
   642 bool equal(CFTypeRef o1, CFTypeRef o2)
       
   643 {
       
   644     if (o1 == 0 || o2 == 0)
       
   645         return false;
       
   646     return CFEqual(o1, o2);
       
   647 }
       
   648 
       
   649 /*
       
   650     Verifies basic element info.
       
   651 */
       
   652 #define VERIFY_ELEMENT(element, _parent, _role) \
       
   653     QVERIFY(element != 0); \
       
   654     QVERIFY(role(element) == _role); \
       
   655     QVERIFY(equal(::parent(element), _parent));
       
   656 /*
       
   657     Verifies that the application and the main form is there has the right info.
       
   658 */
       
   659 void testAppAndForm(AXUIElementRef application)
       
   660 {
       
   661     QVERIFY(title(application) == "tst_qaccessibility_mac");
       
   662     QVERIFY(role(application) == "AXApplication");
       
   663 
       
   664     AXUIElementRef form = childByTitle(application, "Form");
       
   665     VERIFY_ELEMENT(form, application, "AXWindow");
       
   666 }
       
   667 
       
   668 void tst_qaccessibility_mac::printInfo()
       
   669 {
       
   670     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   671     printElementInfo(currentApplication);
       
   672 }
       
   673 
       
   674 /*
       
   675     Tests for form.ui
       
   676 */
       
   677 void tst_qaccessibility_mac::testForm()
       
   678 {
       
   679     // Get reference to the current application.
       
   680     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   681     testAppAndForm(currentApplication);
       
   682     childByTitle(currentApplication, "Form");
       
   683 }
       
   684 
       
   685 /*
       
   686     Tests for buttons.ui
       
   687 */
       
   688 void tst_qaccessibility_mac::testButtons()
       
   689 {
       
   690     // Get reference to the current application.
       
   691     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   692     testAppAndForm(currentApplication);
       
   693     AXUIElementRef form = childByTitle(currentApplication, "Form");
       
   694 
       
   695     AXUIElementRef ren = childByTitle(form, "Ren");
       
   696     VERIFY_ELEMENT(ren, form, "AXButton");
       
   697     QVERIFY(enabled(ren) == true);
       
   698     VERIFY_ROLE_DESCRIPTION(ren, "button");
       
   699 
       
   700     AXUIElementRef stimpy = childByTitle(form, "Stimpy");
       
   701     VERIFY_ELEMENT(stimpy, form, "AXRadioButton");
       
   702     QVERIFY(enabled(stimpy) == true);
       
   703     QVERIFY(value(stimpy).toInt() == 1); // checked;
       
   704     VERIFY_ROLE_DESCRIPTION(stimpy, "radio button");
       
   705 
       
   706     AXUIElementRef pinky = childByTitle(form, "Pinky");
       
   707     VERIFY_ELEMENT(pinky, form, "AXCheckBox");
       
   708     QVERIFY(enabled(pinky) == false);
       
   709     QVERIFY(value(pinky).toInt() == 0); // unchecked;
       
   710     VERIFY_ROLE_DESCRIPTION(pinky, "check box");
       
   711 
       
   712     AXUIElementRef brain = childByTitle(form, "Brain");
       
   713     VERIFY_ELEMENT(brain, form, "AXButton");
       
   714     VERIFY_ROLE_DESCRIPTION(brain, "button");
       
   715 }
       
   716 
       
   717 void tst_qaccessibility_mac::testLabel()
       
   718 {
       
   719     // Get reference to the current application.
       
   720     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   721 
       
   722     testAppAndForm(currentApplication);
       
   723     AXUIElementRef form = childByTitle(currentApplication, "Form");
       
   724     AXUIElementRef label = childByValue(form, "This is a Text Label");
       
   725     QVERIFY(label);
       
   726     VERIFY_ELEMENT(label, form, "AXStaticText");
       
   727     VERIFY_ROLE_DESCRIPTION(label, "text");
       
   728     QCOMPARE(supportsAttribute(label, kAXDescriptionAttribute), false);
       
   729 }
       
   730 
       
   731 /*
       
   732     Tests for lineedit.ui
       
   733 */
       
   734 void tst_qaccessibility_mac::testLineEdit()
       
   735 {
       
   736     // Get reference to the current application.
       
   737     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   738 
       
   739     testAppAndForm(currentApplication);
       
   740     AXUIElementRef form = childByTitle(currentApplication, "Form");
       
   741     AXUIElementRef lineEdit = childByValue(form, "Line edit");
       
   742     VERIFY_ELEMENT(lineEdit, form, "AXTextField");
       
   743     VERIFY_ROLE_DESCRIPTION(lineEdit, "text field");
       
   744 }
       
   745 
       
   746 /*
       
   747     Tests for groups.ui
       
   748 */
       
   749 void tst_qaccessibility_mac::testGroups()
       
   750 {
       
   751     // Get reference to the current application.
       
   752     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   753 
       
   754     testAppAndForm(currentApplication);
       
   755     AXUIElementRef form = childByTitle(currentApplication, "Form");
       
   756 
       
   757     AXUIElementRef groupA = childByTitle(form, "Group A");
       
   758     VERIFY_ELEMENT(groupA, form, "AXGroup");
       
   759     AXUIElementRef button1 = childByTitle(groupA, "PushButton 1");
       
   760     VERIFY_ELEMENT(button1, groupA, "AXButton");
       
   761     VERIFY_ROLE_DESCRIPTION(groupA, "group");
       
   762 
       
   763     AXUIElementRef groupB = childByTitle(form, "Group B");
       
   764     VERIFY_ELEMENT(groupB, form, "AXGroup");
       
   765     AXUIElementRef button3 = childByTitle(groupB, "PushButton 3");
       
   766     VERIFY_ELEMENT(button3, groupB, "AXButton");
       
   767 }
       
   768 
       
   769 /*
       
   770     Tests for tabs.ui
       
   771 */
       
   772 void tst_qaccessibility_mac::testTabWidget()
       
   773 {
       
   774     {   // Test that the QTabWidget hierarchy is what we expect it to be.
       
   775         QTabWidget tabWidget;
       
   776         tabWidget.show();
       
   777         QAInterface interface = QAccessible::queryAccessibleInterface(&tabWidget);
       
   778         tabWidget.addTab(new QPushButton("Foo"), "FooTab");
       
   779         tabWidget.addTab(new QPushButton("Bar"), "BarTab");
       
   780         QCOMPARE(interface.childCount(), 2);
       
   781         const QList<QAInterface> children = interface.children();
       
   782         QVERIFY(children.at(0).object()->inherits("QStackedWidget"));
       
   783         QVERIFY(children.at(1).object()->inherits("QTabBar"));
       
   784         
       
   785         const QList<QAInterface> tabBarChildren = children.at(1).children();
       
   786         QCOMPARE(tabBarChildren.count(), 4);
       
   787         QCOMPARE(tabBarChildren.at(0).text(QAccessible::Name), QLatin1String("FooTab"));
       
   788         QCOMPARE(tabBarChildren.at(1).text(QAccessible::Name), QLatin1String("BarTab"));
       
   789         QCOMPARE(tabBarChildren.at(0).role(), QAccessible::PageTab);
       
   790         QCOMPARE(tabBarChildren.at(1).role(), QAccessible::PageTab);
       
   791 
       
   792         // Check that the hierarchy manager is able to register the tab bar children.
       
   793         QAccessibleHierarchyManager *manager = QAccessibleHierarchyManager::instance();
       
   794         QAInterface tabBarInterface = children.at(1);
       
   795         QAElement tabBarElement = manager->registerInterface(tabBarInterface);
       
   796         QCOMPARE(manager->lookup(tabBarElement).childCount(), 4);
       
   797         manager->registerChildren(tabBarInterface);
       
   798         QAElement tabButtonElement = manager->lookup(tabBarChildren.at(1));
       
   799         QAInterface tabButtonInterface = manager->lookup(tabButtonElement);
       
   800         QCOMPARE(tabButtonInterface.text(QAccessible::Name), QLatin1String("BarTab"));
       
   801         QVERIFY(isItInteresting(tabButtonInterface) == true);
       
   802     }
       
   803 
       
   804     // Get reference to the current application.
       
   805     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   806 
       
   807     testAppAndForm(currentApplication);
       
   808     const QString formTitle = "Form";
       
   809     AXUIElementRef form = childByTitle(currentApplication, formTitle);
       
   810     QVERIFY(form);
       
   811 
       
   812     const QString tabRole = "AXTabGroup";
       
   813     AXUIElementRef tabGroup = childByRole(form, tabRole);
       
   814     QVERIFY(tabGroup);
       
   815 
       
   816     // Test that we have three child buttons (the tab buttons + plus the contents of the first tab)
       
   817     const int numChildren = ::numChildren(tabGroup);
       
   818     QCOMPARE(numChildren, 3);
       
   819     
       
   820     const QString tab1Title = "Tab 1";
       
   821     AXUIElementRef tabButton1 = childByTitle(tabGroup, tab1Title);
       
   822     QVERIFY (tabButton1);
       
   823     VERIFY_ELEMENT(tabButton1, tabGroup, "AXRadioButton");
       
   824     QCOMPARE(title(tabButton1), tab1Title);
       
   825 
       
   826     const QString tab2Title = "Tab 2";
       
   827     const AXUIElementRef tabButton2 = childByTitle(tabGroup, tab2Title);
       
   828     QVERIFY(tabButton2);
       
   829     VERIFY_ELEMENT(tabButton2, tabGroup, "AXRadioButton");
       
   830     QCOMPARE(title(tabButton2), tab2Title);
       
   831     
       
   832     // Test that the window and top-level-ui-elment is the form.
       
   833     // Window is not reported properly on 10.5
       
   834     if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5) {
       
   835         QVERIFY(equal(window(tabGroup), form));
       
   836 
       
   837     //   ### hangs on 10.4
       
   838 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
       
   839     QVERIFY(equal(window(tabButton1), form));
       
   840 #endif
       
   841     }
       
   842 //   ### hangs on 10.4
       
   843 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
       
   844     QVERIFY(equal(topLevelUIElement(tabGroup), form));
       
   845     QVERIFY(equal(topLevelUIElement(tabButton1), form));    
       
   846 #endif
       
   847     // Test the bounding rectangles for the tab group and buttons.
       
   848     const QRectF groupRect(position(tabGroup), size(tabGroup));
       
   849     const QRectF tabButton1Rect(position(tabButton1), size(tabButton1));
       
   850     const QRectF tabButton2Rect(position(tabButton2), size(tabButton2));
       
   851     
       
   852     QVERIFY(groupRect.isNull() == false);
       
   853     QVERIFY(tabButton1Rect.isNull() == false);
       
   854     QVERIFY(tabButton1Rect.isNull() == false);
       
   855         
       
   856     QVERIFY(groupRect.contains(tabButton1Rect));
       
   857     QVERIFY(groupRect.contains(tabButton2Rect));
       
   858     QVERIFY(tabButton2Rect.contains(tabButton1Rect) == false);
       
   859     
       
   860     // Test the childAtPoint event.
       
   861     const AXUIElementRef childAtTab1Position = childAtPoint(position(tabButton1) + QPointF(5,5));
       
   862     QVERIFY(equal(childAtTab1Position, tabButton1));
       
   863     const AXUIElementRef childAtOtherPosition = childAtPoint(position(tabButton1) - QPointF(5,5));
       
   864     QVERIFY(equal(childAtOtherPosition, tabButton1) == false);
       
   865 
       
   866     // Test AXTabs attribute
       
   867     QVERIFY(supportsAttribute(tabGroup, kAXTabsAttribute));
       
   868     QList<AXUIElementRef> tabElements = tabs(tabGroup);
       
   869     QCOMPARE(tabElements.count(), 2);
       
   870     QVERIFY(equal(tabElements.at(0), tabButton1));
       
   871     QVERIFY(equal(tabElements.at(1), tabButton2));
       
   872     
       
   873     // Perform the press action on each child.
       
   874     for (int i = 0; i < numChildren; ++i) {
       
   875         const AXUIElementRef child = ::child(tabGroup, i);
       
   876         QVERIFY(supportsAction(child, "AXPress"));
       
   877         QVERIFY(performAction(child, "AXPress"));
       
   878     }
       
   879 }
       
   880 
       
   881 void tst_qaccessibility_mac::testTabBar()
       
   882 {
       
   883     QTabBar tabBar;
       
   884     tabBar.addTab("Tab A");
       
   885     tabBar.addTab("Tab B");
       
   886     tabBar.show();
       
   887 
       
   888     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   889     AXUIElementRef window = childByRole(currentApplication, "AXWindow");
       
   890     QVERIFY(window);
       
   891 
       
   892     const QString tabRole = "AXTabGroup";
       
   893     AXUIElementRef tabGroup = childByRole(window, tabRole);
       
   894     QVERIFY(tabGroup);
       
   895 
       
   896     const int numChildren = ::numChildren(tabGroup);
       
   897     QCOMPARE(numChildren, 2);
       
   898     
       
   899     const QString tab1Title = "Tab A";
       
   900     AXUIElementRef tabButton1 = childByTitle(tabGroup, tab1Title);
       
   901     QVERIFY (tabButton1);
       
   902     VERIFY_ELEMENT(tabButton1, tabGroup, "AXRadioButton");
       
   903     QCOMPARE(title(tabButton1), tab1Title);
       
   904 
       
   905     const QString tab2Title = "Tab B";
       
   906     const AXUIElementRef tabButton2 = childByTitle(tabGroup, tab2Title);
       
   907     QVERIFY(tabButton2);
       
   908     VERIFY_ELEMENT(tabButton2, tabGroup, "AXRadioButton");
       
   909     QCOMPARE(title(tabButton2), tab2Title);
       
   910 
       
   911     // Test the childAtPoint event.
       
   912     const AXUIElementRef childAtTab1Position = childAtPoint(position(tabButton1) + QPointF(5,5));
       
   913     QVERIFY(equal(childAtTab1Position, tabButton1));
       
   914     const AXUIElementRef childAtOtherPosition = childAtPoint(position(tabButton1) - QPointF(5,5));
       
   915     QVERIFY(equal(childAtOtherPosition, tabButton1) == false);
       
   916 
       
   917     // Test AXTabs attribute
       
   918     QVERIFY(supportsAttribute(tabGroup, kAXTabsAttribute));
       
   919     QList<AXUIElementRef> tabElements = tabs(tabGroup);
       
   920     QCOMPARE(tabElements.count(), 2);
       
   921     QVERIFY(equal(tabElements.at(0), tabButton1));
       
   922     QVERIFY(equal(tabElements.at(1), tabButton2));
       
   923     
       
   924     // Perform the press action on each child.
       
   925     for (int i = 0; i < numChildren; ++i) {
       
   926         const AXUIElementRef child = ::child(tabGroup, i);
       
   927         QVERIFY(supportsAction(child, "AXPress"));
       
   928         QVERIFY(performAction(child, "AXPress"));
       
   929     }
       
   930 }
       
   931 
       
   932 void tst_qaccessibility_mac::testComboBox()
       
   933 {
       
   934     // Get reference to the current application.
       
   935     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   936 
       
   937     testAppAndForm(currentApplication);
       
   938     const QString formTitle = "Form";
       
   939     AXUIElementRef form = childByTitle(currentApplication, formTitle);
       
   940     
       
   941     const QString comboBoxRole = "AXPopUpButton";
       
   942     AXUIElementRef comboBox = childByRole(form, comboBoxRole);
       
   943     QVERIFY(comboBox != 0);
       
   944     QVERIFY(supportsAction(comboBox, "AXPress"));
       
   945     QVERIFY(performAction(comboBox, "AXPress"));
       
   946 }
       
   947 
       
   948 void tst_qaccessibility_mac::testDeleteWidget()
       
   949 {
       
   950     const QString buttonTitle = "Hi there";
       
   951     QWidget *form = new QWidget(0, Qt::Window);
       
   952     form->setWindowTitle("Form");
       
   953     form->show();
       
   954     QPushButton *button = new QPushButton(buttonTitle, form);
       
   955     button->show();
       
   956 
       
   957     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   958     testAppAndForm(currentApplication);
       
   959     AXUIElementRef formElement = childByTitle(currentApplication, "Form");
       
   960 
       
   961     AXUIElementRef buttonElement = childByTitle(formElement, buttonTitle);
       
   962     QVERIFY(buttonElement);
       
   963 
       
   964     button->hide();
       
   965     delete button;
       
   966 
       
   967     buttonElement = childByTitle(formElement, buttonTitle);
       
   968     QVERIFY(!buttonElement);
       
   969     delete form;
       
   970 }
       
   971 
       
   972 void tst_qaccessibility_mac::testDeleteWidgets()
       
   973 {
       
   974     const QString buttonTitle = "Hi there";
       
   975     const int repeats = 10;
       
   976 
       
   977     for (int i = 0; i < repeats; ++i) {
       
   978 
       
   979         QWidget *form = new QWidget(0, Qt::Window);
       
   980         form->setWindowTitle("Form");
       
   981         form->show();
       
   982     
       
   983         QPushButton *button = new QPushButton(buttonTitle, form);
       
   984         button->show();
       
   985     
       
   986         AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   987         testAppAndForm(currentApplication);
       
   988         AXUIElementRef formElement = childByTitle(currentApplication, "Form");
       
   989         AXUIElementRef buttonElement = childByTitle(formElement, buttonTitle);
       
   990         QVERIFY(buttonElement);
       
   991         delete form;
       
   992 
       
   993         {
       
   994             AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
   995             QVERIFY(currentApplication);
       
   996             AXUIElementRef formElement = childByTitle(currentApplication, "Form");
       
   997             QVERIFY(!formElement);
       
   998         }
       
   999     }
       
  1000 
       
  1001     for (int i = 0; i < repeats; ++i) {
       
  1002         QWidget *form = new QWidget(0, Qt::Window);
       
  1003         form->setWindowTitle("Form");
       
  1004 
       
  1005     
       
  1006         new QScrollBar(form);
       
  1007         form->show();
       
  1008     
       
  1009         AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
  1010         testAppAndForm(currentApplication);
       
  1011         AXUIElementRef formElement = childByTitle(currentApplication, "Form");
       
  1012         
       
  1013         const AXUIElementRef scrollBarElement = childByRole(formElement, "AXScrollBar");
       
  1014         QVERIFY(scrollBarElement);
       
  1015         delete form;
       
  1016 
       
  1017         {
       
  1018             AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
  1019             QVERIFY(currentApplication);
       
  1020             AXUIElementRef formElement = childByTitle(currentApplication, "Form");
       
  1021             QVERIFY(!formElement);
       
  1022         }
       
  1023     }
       
  1024 
       
  1025     for (int i = 0; i < repeats; ++i) {
       
  1026         QWidget *form = new QWidget(0, Qt::Window);
       
  1027         form->setWindowTitle("Form");
       
  1028     
       
  1029         QListWidget *listWidget = new QListWidget(form);
       
  1030         listWidget->addItem("Foo");
       
  1031         listWidget->addItem("Bar");
       
  1032         form->show();
       
  1033     
       
  1034         AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
  1035         testAppAndForm(currentApplication);
       
  1036         AXUIElementRef formElement = childByTitle(currentApplication, "Form");
       
  1037 
       
  1038         const AXUIElementRef scrollAreaElement = childByRole(formElement, "AXScrollArea");
       
  1039         QVERIFY(scrollAreaElement);
       
  1040 
       
  1041         const AXUIElementRef listElement = childByRole(scrollAreaElement, "AXList");
       
  1042         QVERIFY(listElement);
       
  1043         delete form;
       
  1044 
       
  1045         {
       
  1046             AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
  1047             QVERIFY(currentApplication);
       
  1048             AXUIElementRef formElement = childByTitle(currentApplication, "Form");
       
  1049             QVERIFY(!formElement);
       
  1050         }
       
  1051     }
       
  1052 
       
  1053 }
       
  1054 
       
  1055 void tst_qaccessibility_mac::testMultipleWindows()
       
  1056 {
       
  1057     const QString formATitle("FormA");
       
  1058     const QString formBTitle("FormB");
       
  1059 
       
  1060     // Create a window
       
  1061     QWidget *formA = new QWidget(0, Qt::Window);
       
  1062     formA->setWindowTitle(formATitle);
       
  1063     formA->show();
       
  1064 
       
  1065     // Test if we can access the window
       
  1066     AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
  1067     AXUIElementRef formAElement = childByTitle(currentApplication, formATitle);
       
  1068     QVERIFY(formAElement);
       
  1069 
       
  1070     // Create another window
       
  1071     QWidget *formB = new QWidget(0, Qt::Window);
       
  1072     formB->setWindowTitle(formBTitle);
       
  1073     formB->show();
       
  1074 
       
  1075     // Test if we can access both windows
       
  1076     formAElement = childByTitle(currentApplication, formATitle);
       
  1077     QVERIFY(formAElement);
       
  1078 
       
  1079     AXUIElementRef formBElement = childByTitle(currentApplication, formBTitle);
       
  1080     QVERIFY(formBElement);
       
  1081     
       
  1082     delete formA;
       
  1083 }
       
  1084 
       
  1085 void tst_qaccessibility_mac::testHiddenWidgets()
       
  1086 {
       
  1087     const QString windowTitle ="a widget";
       
  1088     QWidget * const window = new QWidget(0);
       
  1089     window->setWindowTitle(windowTitle);
       
  1090     window->show();
       
  1091 
       
  1092     const AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
  1093     const AXUIElementRef windowElement = childByTitle(currentApplication, windowTitle);
       
  1094     QVERIFY(windowElement);
       
  1095     QCOMPARE(isIgnored(windowElement), false);
       
  1096     
       
  1097     const QString buttonTitle = "a button";
       
  1098     QPushButton * const button = new QPushButton(window);    
       
  1099     button->setText(buttonTitle);
       
  1100     button->show();
       
  1101     
       
  1102     const AXUIElementRef buttonElement = childByTitle(windowElement, buttonTitle);
       
  1103     QVERIFY(buttonElement);
       
  1104     QCOMPARE(isIgnored(buttonElement), false);
       
  1105 
       
  1106     const QString toolbarTitle = "a toolbar";
       
  1107     QToolBar * const toolbar = new QToolBar(toolbarTitle, window);
       
  1108     toolbar->show();
       
  1109     
       
  1110     const AXUIElementRef toolBarElement = childByTitle(windowElement, toolbarTitle);
       
  1111     QVERIFY(toolBarElement == 0);
       
  1112 
       
  1113     delete window;
       
  1114 };
       
  1115 
       
  1116 void tst_qaccessibility_mac::testActions()
       
  1117 {
       
  1118     // create a window with a push button
       
  1119     const QString windowTitle ="a widget";
       
  1120     QWidget * const window = new QWidget();
       
  1121     window->setWindowTitle(windowTitle);
       
  1122     window->show();
       
  1123 
       
  1124     const AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
  1125     const AXUIElementRef windowElement = childByTitle(currentApplication, windowTitle);
       
  1126     QVERIFY(windowElement);
       
  1127 
       
  1128     const QString buttonTitle = "a button";
       
  1129     QPushButton * const button = new QPushButton(window);    
       
  1130     button->setText(buttonTitle);
       
  1131     button->show();
       
  1132     
       
  1133     const AXUIElementRef buttonElement = childByTitle(windowElement, buttonTitle);
       
  1134     QVERIFY(buttonElement);
       
  1135 
       
  1136     // Verify that the button has the Press action.
       
  1137     const QStringList actions = actionNames(buttonElement);
       
  1138     const QString pressActionName("AXPress");
       
  1139     QVERIFY(actions.contains(pressActionName));
       
  1140     
       
  1141     // Press button and check the pressed signal
       
  1142     QSignalSpy pressed(button, SIGNAL(pressed()));
       
  1143     QVERIFY(performAction(buttonElement, pressActionName));
       
  1144     QCOMPARE(pressed.count(), 1);
       
  1145     
       
  1146     pressed.clear();
       
  1147     QVERIFY(performAction(buttonElement, QString("does not exist")));
       
  1148     QCOMPARE(pressed.count(), 0);
       
  1149 
       
  1150     delete window;
       
  1151 };
       
  1152 
       
  1153 void tst_qaccessibility_mac::testChangeState()
       
  1154 {
       
  1155     const QString windowTitle ="a widget";
       
  1156     QWidget * const window = new QWidget();
       
  1157     window->setWindowTitle(windowTitle);
       
  1158     window->show();
       
  1159  
       
  1160     const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
       
  1161     const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
       
  1162     QVERIFY(windowElement);
       
  1163     const int otherChildren = numChildren(windowElement);
       
  1164     
       
  1165     const QString buttonTitle = "Button";
       
  1166     QPushButton * const button = new QPushButton(buttonTitle, window);
       
  1167     button->setText(buttonTitle);  
       
  1168 
       
  1169     // Test that show/hide adds/removes the button from the hierachy.
       
  1170     QVERIFY(childByTitle(windowElement, buttonTitle) == 0);
       
  1171     QCOMPARE(numChildren(windowElement), otherChildren);
       
  1172     button->show();
       
  1173     QVERIFY(childByTitle(windowElement, buttonTitle) != 0);
       
  1174     QCOMPARE(numChildren(windowElement), otherChildren + 1);
       
  1175     button->hide();
       
  1176     QVERIFY(childByTitle(windowElement, buttonTitle) == 0);
       
  1177     QCOMPARE(numChildren(windowElement), otherChildren);
       
  1178     button->show();
       
  1179     QVERIFY(childByTitle(windowElement, buttonTitle) != 0);
       
  1180     QCOMPARE(numChildren(windowElement), otherChildren + 1);
       
  1181 
       
  1182     // Test that hiding and showing a widget also removes and adds all its children.
       
  1183     {
       
  1184         QWidget * const parent = new QWidget(window);
       
  1185         const int otherChildren = numChildren(windowElement);
       
  1186         
       
  1187         QPushButton * const child = new QPushButton(parent);
       
  1188         const QString childButtonTitle = "child button";
       
  1189         child->setText(childButtonTitle);
       
  1190         
       
  1191         parent->show();
       
  1192         QVERIFY(childByTitle(windowElement, childButtonTitle) != 0);
       
  1193         QCOMPARE(numChildren(windowElement), otherChildren + 1);
       
  1194 
       
  1195         parent->hide();
       
  1196         QVERIFY(childByTitle(windowElement, childButtonTitle) == 0);
       
  1197         QCOMPARE(numChildren(windowElement), otherChildren );
       
  1198 
       
  1199         parent->show();
       
  1200         QVERIFY(childByTitle(windowElement, childButtonTitle) != 0);
       
  1201         QCOMPARE(numChildren(windowElement), otherChildren + 1);
       
  1202         
       
  1203         delete parent;
       
  1204     }
       
  1205 
       
  1206     // Test that the enabled attribute is updated after a call to setEnabled.
       
  1207     const AXUIElementRef buttonElement = childByTitle(windowElement, buttonTitle);
       
  1208     QVERIFY(enabled(buttonElement));
       
  1209     button->setEnabled(false);
       
  1210     QVERIFY(enabled(buttonElement) == false);
       
  1211     button->setEnabled(true);
       
  1212     QVERIFY(enabled(buttonElement));
       
  1213 
       
  1214     // Test that changing the title updates the accessibility information.
       
  1215     const QString buttonTitle2 = "Button 2";    
       
  1216     button->setText(buttonTitle2);
       
  1217     QVERIFY(childByTitle(windowElement, buttonTitle2) != 0);
       
  1218     QVERIFY(childByTitle(windowElement, buttonTitle) == 0);
       
  1219 
       
  1220     delete window;
       
  1221 }
       
  1222 
       
  1223 void tst_qaccessibility_mac::testSlider()
       
  1224 {
       
  1225     const QString windowTitle = "a widget";
       
  1226     QWidget * const window = new QWidget();
       
  1227     window->setWindowTitle(windowTitle);
       
  1228     window->show();
       
  1229  
       
  1230     const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
       
  1231     QVERIFY(applicationElement);
       
  1232     const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
       
  1233     QVERIFY(windowElement);
       
  1234     const int windowChildren = numChildren(windowElement);
       
  1235     
       
  1236     QSlider * const slider = new QSlider(window);
       
  1237     slider->show();
       
  1238     const AXUIElementRef sliderElement = childByRole(windowElement, "AXSlider");
       
  1239     QVERIFY(sliderElement);
       
  1240 
       
  1241     // Test that the slider and its children are removed from the hierachy when we call hide().
       
  1242     QCOMPARE(numChildren(windowElement), windowChildren + 1);
       
  1243     slider->hide();
       
  1244     QCOMPARE(numChildren(windowElement), windowChildren);
       
  1245     
       
  1246     delete slider;
       
  1247 }
       
  1248 
       
  1249 void tst_qaccessibility_mac::testScrollArea()
       
  1250 {
       
  1251     QWidget window;
       
  1252     const QString windowTitle = "window";
       
  1253     window.setWindowTitle(windowTitle);
       
  1254     window.resize(300, 300);
       
  1255 
       
  1256     QScrollArea scrollArea(&window);
       
  1257     scrollArea.resize(300, 300);
       
  1258     scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
       
  1259     scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
       
  1260 
       
  1261     QLabel label;
       
  1262     label.setText("Foo"); 
       
  1263     scrollArea.setWidget(&label);
       
  1264 
       
  1265     window.show();
       
  1266 
       
  1267     // Verify that the QAinterface returns the correct children
       
  1268     QAInterface interface = QAccessible::queryAccessibleInterface(&scrollArea);
       
  1269     QCOMPARE(interface.childCount(), 3);
       
  1270     
       
  1271     QAInterface viewport = interface.navigate(QAccessible::Child, 1);
       
  1272     QVERIFY(viewport.isValid());
       
  1273 
       
  1274     QAInterface scrollBarContainer1 = interface.navigate(QAccessible::Child, 2);
       
  1275     QVERIFY(scrollBarContainer1.isValid());
       
  1276 
       
  1277     QAInterface scrollBar1 = scrollBarContainer1.navigate(QAccessible::Child, 1);
       
  1278 
       
  1279     QVERIFY(scrollBar1.isValid());
       
  1280     QVERIFY(scrollBar1.role() == QAccessible::ScrollBar);
       
  1281 
       
  1282     QAInterface scrollBarContainer2 = interface.navigate(QAccessible::Child, 3);
       
  1283     QVERIFY(scrollBarContainer1.isValid());
       
  1284 
       
  1285     QAInterface scrollBar2 = scrollBarContainer2.navigate(QAccessible::Child, 1);
       
  1286     QVERIFY(scrollBar2.isValid());
       
  1287     QVERIFY(scrollBar2.role() == QAccessible::ScrollBar);    
       
  1288 
       
  1289     // Navigate to the scroll area from the application
       
  1290     const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
       
  1291     QVERIFY(applicationElement);
       
  1292     const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
       
  1293     QVERIFY(windowElement);
       
  1294     const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
       
  1295     QVERIFY(scrollAreaElement);
       
  1296 
       
  1297     // Get the scroll bars
       
  1298     QVERIFY(supportsAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute));
       
  1299     const AXUIElementRef horizontalScrollBar = elementAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute);
       
  1300     QVERIFY(horizontalScrollBar);
       
  1301     QVERIFY(role(horizontalScrollBar) == "AXScrollBar");
       
  1302     QVERIFY(stringAttribute(horizontalScrollBar, kAXOrientationAttribute) == "AXHorizontalOrientation");
       
  1303 
       
  1304     QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute));
       
  1305     const AXUIElementRef verticalScrollBar = elementAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute);
       
  1306     QVERIFY(verticalScrollBar);
       
  1307     QVERIFY(role(verticalScrollBar) == "AXScrollBar");
       
  1308     QVERIFY(stringAttribute(verticalScrollBar, kAXOrientationAttribute) == "AXVerticalOrientation");
       
  1309 
       
  1310     // Get the contents and verify that we get the label.
       
  1311     QVERIFY(supportsAttribute(scrollAreaElement, kAXContentsAttribute));
       
  1312     const QList<AXUIElementRef> contents = elementListAttribute(scrollAreaElement, kAXContentsAttribute);
       
  1313     QCOMPARE(contents.count(), 1);
       
  1314     AXUIElementRef content = contents.at(0);
       
  1315     QVERIFY(role(content) == "AXStaticText");
       
  1316     QVERIFY(title(content) == "Foo");
       
  1317 
       
  1318     // Turn scroll bars off
       
  1319     {
       
  1320     scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       
  1321     scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       
  1322     QVERIFY(supportsAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute) == false);
       
  1323     QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute) == false);
       
  1324 
       
  1325     QVERIFY(supportsAttribute(scrollAreaElement, kAXContentsAttribute));
       
  1326     const QList<AXUIElementRef> contents = elementListAttribute(scrollAreaElement, kAXContentsAttribute);
       
  1327     QCOMPARE(contents.count(), 1);
       
  1328     AXUIElementRef content = contents.at(0);
       
  1329     
       
  1330     QVERIFY(role(content) == "AXStaticText");
       
  1331     QVERIFY(title(content) == "Foo");
       
  1332     }
       
  1333 
       
  1334     // Turn the horizontal scrollbar on.
       
  1335     {
       
  1336     scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
       
  1337     scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       
  1338     QVERIFY(supportsAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute) == true);
       
  1339     QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute) == false);
       
  1340 
       
  1341     const AXUIElementRef horizontalScrollBar = elementAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute);
       
  1342     QVERIFY(horizontalScrollBar);
       
  1343     QVERIFY(role(horizontalScrollBar) == "AXScrollBar");
       
  1344     QVERIFY(stringAttribute(horizontalScrollBar, kAXOrientationAttribute) == "AXHorizontalOrientation");
       
  1345 
       
  1346     QVERIFY(supportsAttribute(scrollAreaElement, kAXContentsAttribute));
       
  1347     const QList<AXUIElementRef> contents = elementListAttribute(scrollAreaElement, kAXContentsAttribute);
       
  1348     QCOMPARE(contents.count(), 1);
       
  1349     AXUIElementRef content = contents.at(0);
       
  1350     QVERIFY(role(content) == "AXStaticText");
       
  1351     QVERIFY(title(content) == "Foo");
       
  1352     }
       
  1353 
       
  1354     // Turn the vertical scrollbar on.
       
  1355     {
       
  1356     scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       
  1357     scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
       
  1358     QVERIFY(supportsAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute) == false);
       
  1359     QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute) == true);
       
  1360 
       
  1361     QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute));
       
  1362     const AXUIElementRef verticalScrollBar = elementAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute);
       
  1363     QVERIFY(verticalScrollBar);
       
  1364     QVERIFY(role(verticalScrollBar) == "AXScrollBar");
       
  1365     QVERIFY(stringAttribute(verticalScrollBar, kAXOrientationAttribute) == "AXVerticalOrientation");
       
  1366 
       
  1367     QVERIFY(supportsAttribute(scrollAreaElement, kAXContentsAttribute));
       
  1368     const QList<AXUIElementRef> contents = elementListAttribute(scrollAreaElement, kAXContentsAttribute);
       
  1369     QCOMPARE(contents.count(), 1);
       
  1370     AXUIElementRef content = contents.at(0);
       
  1371     QVERIFY(role(content) == "AXStaticText");
       
  1372     QVERIFY(title(content) == "Foo");
       
  1373     }
       
  1374 }
       
  1375 
       
  1376 void tst_qaccessibility_mac::testListView()
       
  1377 {
       
  1378     QWidget window;
       
  1379     const QString windowTitle("window");
       
  1380     window.setWindowTitle(windowTitle);
       
  1381     window.resize(300, 300);
       
  1382 
       
  1383     QListWidget *listWidget = new QListWidget(&window);
       
  1384     listWidget->setObjectName("listwidget");
       
  1385     listWidget->addItem("A");
       
  1386     listWidget->addItem("B");
       
  1387     listWidget->addItem("C");
       
  1388     
       
  1389     window.show();
       
  1390     QTest::qWait(1);
       
  1391         
       
  1392     {
       
  1393         // Verify that QAInterface works as expected for list views
       
  1394         QAInterface listWidgetInterface = QAccessible::queryAccessibleInterface(listWidget);
       
  1395         QCOMPARE(listWidgetInterface.role(), QAccessible::Client);
       
  1396         QCOMPARE(listWidgetInterface.childCount(), 1);
       
  1397         QAInterface viewPort = listWidgetInterface.childAt(1);
       
  1398         QCOMPARE(viewPort.role(), QAccessible::List);
       
  1399         QVERIFY(viewPort.object() != 0);
       
  1400         QCOMPARE(viewPort.childCount(), 3);
       
  1401         const QList<QAInterface> rows = viewPort.children();
       
  1402         QCOMPARE(rows.count(), 3);
       
  1403         QVERIFY(rows.at(0).object() == 0);
       
  1404         QCOMPARE(rows.at(0).parent().indexOfChild(rows.at(0)), 1);
       
  1405         QCOMPARE(rows.at(1).parent().indexOfChild(rows.at(1)), 2);
       
  1406         QCOMPARE(rows.at(2).parent().indexOfChild(rows.at(2)), 3);         
       
  1407         
       
  1408         // test the QAInterface comparison operator
       
  1409         QVERIFY(rows.at(0) == rows.at(0));
       
  1410         QVERIFY(rows.at(0) != rows.at(1));
       
  1411         QVERIFY(rows.at(0) != viewPort);
       
  1412         QVERIFY(viewPort == viewPort);
       
  1413         QVERIFY(listWidgetInterface != viewPort);
       
  1414         QVERIFY(listWidgetInterface == listWidgetInterface);
       
  1415         
       
  1416         // test QAInterface::isHIView()
       
  1417         QVERIFY(viewPort.isHIView());
       
  1418         QVERIFY(listWidgetInterface.isHIView());
       
  1419         QVERIFY(rows.at(0).isHIView() == false);
       
  1420     }
       
  1421 
       
  1422     const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
       
  1423     QVERIFY(applicationElement);
       
  1424     const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
       
  1425     QVERIFY(windowElement);
       
  1426     const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
       
  1427     QVERIFY(scrollAreaElement);
       
  1428     const AXUIElementRef listElement = childByRole(scrollAreaElement, "AXList");
       
  1429     QVERIFY(listElement);
       
  1430     QVERIFY(equal(::parent(listElement), scrollAreaElement));
       
  1431     // Window is not reported properly on 10.5
       
  1432     if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5) 
       
  1433         QVERIFY(equal(::window(listElement), windowElement));
       
  1434     
       
  1435     const AXUIElementRef A = childByTitle(listElement, "A");
       
  1436     QVERIFY(A);
       
  1437     const AXUIElementRef B = childByTitle(listElement, "B");
       
  1438     QVERIFY(B);
       
  1439     const AXUIElementRef C = childByTitle(listElement, "C");
       
  1440     QVERIFY(C);
       
  1441 
       
  1442     QVERIFY(value(A) == "A");
       
  1443     QVERIFY(equal(::parent(A), listElement));
       
  1444     QVERIFY(enabled(A));
       
  1445 
       
  1446     // Window is not reported properly on 10.5, this test
       
  1447     // hangs on 10.4. Disable it for now.
       
  1448     //    if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5) 
       
  1449     //        QVERIFY(equal(::window(A), windowElement));
       
  1450     
       
  1451     QVERIFY(above(A, B));
       
  1452     QVERIFY(!above(B, A));
       
  1453     QVERIFY(above(B, C));
       
  1454     QVERIFY(contains(listElement, A));
       
  1455     QVERIFY(!contains(A, listElement));
       
  1456     QVERIFY(contains(listElement, B));
       
  1457     QVERIFY(contains(listElement, C));
       
  1458 }
       
  1459 
       
  1460 void tst_qaccessibility_mac::testTableView()
       
  1461 {
       
  1462     QWidget window;
       
  1463     const QString windowTitle("window");
       
  1464     window.setWindowTitle(windowTitle);
       
  1465     window.resize(300, 300);
       
  1466 
       
  1467     QTableWidget *tableWidget = new QTableWidget(&window);
       
  1468     tableWidget->setObjectName("tablewidget");
       
  1469     tableWidget->setRowCount(3);
       
  1470     tableWidget->setColumnCount(2);
       
  1471 
       
  1472     tableWidget->setItem(0, 0, new QTableWidgetItem("A1"));
       
  1473     tableWidget->setItem(0, 1, new QTableWidgetItem("A2"));
       
  1474 
       
  1475     tableWidget->setItem(1, 0, new QTableWidgetItem("B1"));
       
  1476     tableWidget->setItem(1, 1, new QTableWidgetItem("B2"));
       
  1477 
       
  1478     tableWidget->setItem(2, 0, new QTableWidgetItem("C1"));
       
  1479     tableWidget->setItem(2, 1, new QTableWidgetItem("C2"));
       
  1480 
       
  1481     window.show();
       
  1482     
       
  1483     {
       
  1484         // Verify that QAInterface works as expected for table view children.
       
  1485         QAInterface tableWidgetInterface = QAccessible::queryAccessibleInterface(tableWidget);
       
  1486         QCOMPARE(tableWidgetInterface.role(), QAccessible::Client);
       
  1487         QCOMPARE(tableWidgetInterface.childCount(), 1);
       
  1488         QAInterface viewPort = tableWidgetInterface.childAt(1);
       
  1489         QCOMPARE(viewPort.childCount(), 4);
       
  1490         QCOMPARE(viewPort.role(), QAccessible::Table);
       
  1491         QVERIFY(viewPort.object() != 0);
       
  1492         const QList<QAInterface> rows = viewPort.children();
       
  1493         QCOMPARE(rows.count(), 4);
       
  1494         QVERIFY(rows.at(0).object() == 0);
       
  1495         QCOMPARE(rows.at(0).parent().indexOfChild(rows.at(0)), 1);
       
  1496         QCOMPARE(rows.at(1).parent().indexOfChild(rows.at(1)), 2);
       
  1497         QCOMPARE(rows.at(2).parent().indexOfChild(rows.at(2)), 3);         
       
  1498 
       
  1499         QAInterface Arow = rows.at(1);
       
  1500         QCOMPARE(Arow.role(), QAccessible::Row);
       
  1501         QAInterface Brow = rows.at(2);
       
  1502 
       
  1503         QVERIFY(Arow.name() == "1");
       
  1504         QVERIFY(Brow.name() == "2");
       
  1505 
       
  1506         QVERIFY(Arow == Arow);
       
  1507         QVERIFY(Brow != Arow);
       
  1508         QVERIFY(Arow.isHIView() == false);
       
  1509         QCOMPARE(Arow.childCount(), 3);
       
  1510         QList<QAInterface> Achildren = Arow.children();
       
  1511         QCOMPARE(Achildren.count(), 3);
       
  1512         QAInterface A1 = Achildren.at(1);
       
  1513         QAInterface A2 = Achildren.at(2);
       
  1514         QCOMPARE(Arow.indexOfChild(A1), 2);
       
  1515         QCOMPARE(Arow.indexOfChild(A2), 3);
       
  1516         QCOMPARE(A1.role(), QAccessible::Cell);
       
  1517 
       
  1518         QList<QAInterface> Bchildren = Brow.children();
       
  1519         QCOMPARE(Bchildren.count(), 3);
       
  1520         QAInterface B1 = Bchildren.at(1);
       
  1521         QAInterface B2 = Bchildren.at(2);
       
  1522         QVERIFY(B1.parent() == Brow);
       
  1523         QVERIFY(B1.parent() != Arow);
       
  1524         QCOMPARE(Arow.indexOfChild(B1), -1);
       
  1525 
       
  1526         QVERIFY(A1 == A1);
       
  1527         QVERIFY(A1 != A2);
       
  1528         QVERIFY(B1 != A1);
       
  1529         QVERIFY(B1 != A2);
       
  1530         QVERIFY(A1 != Arow);
       
  1531         QVERIFY(A1 != Brow);
       
  1532         QVERIFY(A1 != viewPort);
       
  1533         QVERIFY(A1.isHIView() == false);
       
  1534 
       
  1535         QVERIFY(B1.parent() == Brow);
       
  1536         QVERIFY(A1.parent() == Arow);
       
  1537         B1 = A1;
       
  1538         QVERIFY(B1.parent() == Arow);
       
  1539     }
       
  1540     
       
  1541     const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
       
  1542     QVERIFY(applicationElement);
       
  1543     const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
       
  1544     QVERIFY(windowElement);
       
  1545     const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
       
  1546     QVERIFY(scrollAreaElement);
       
  1547     const AXUIElementRef tableElement = childByRole(scrollAreaElement, "AXTable");
       
  1548     QVERIFY(tableElement);
       
  1549    
       
  1550     {
       
  1551         // Verify that QAccessibleHierarchyManager can look up table view children correctly
       
  1552         QAccessibleHierarchyManager *manager = QAccessibleHierarchyManager::instance();
       
  1553         QAInterface tableInterface = manager->lookup(tableElement);
       
  1554         QVERIFY(tableInterface.isValid());
       
  1555         QVERIFY(tableInterface.role() == QAccessible::Table);
       
  1556    
       
  1557         QAInterface ArowInterface = tableInterface.childAt(2);
       
  1558 
       
  1559         QVERIFY(ArowInterface.name() == "1");
       
  1560         QVERIFY(manager->lookup(manager->lookup(ArowInterface)).name() == "1");
       
  1561 
       
  1562         QCOMPARE(ArowInterface.childCount(), 3);
       
  1563         QAInterface A1Interface = ArowInterface.childAt(2);
       
  1564 
       
  1565         QCOMPARE(A1Interface.value(), QString("A1"));
       
  1566         QVERIFY(value(manager->lookup(A1Interface)).toString() == "A1");
       
  1567 
       
  1568         QAInterface A2Interface = ArowInterface.childAt(3);
       
  1569         QAElement A2Element = manager->lookup(A2Interface);
       
  1570         QVERIFY(manager->lookup(A2Element).value() == "A2");
       
  1571         QVERIFY(value(A2Element).toString() == "A2");
       
  1572 
       
  1573         QAInterface BrowInterface = tableInterface.childAt(3);
       
  1574         QVERIFY(BrowInterface.value() == "2");
       
  1575         QVERIFY(manager->lookup(manager->lookup(BrowInterface)).value() == "2");
       
  1576 
       
  1577         QCOMPARE(BrowInterface.childCount(), 3);
       
  1578         QAInterface B1Interface = BrowInterface.childAt(2);
       
  1579         QVERIFY(value(manager->lookup(B1Interface)).toString() == "B1");
       
  1580 
       
  1581         QAInterface B2Interface = BrowInterface.childAt(3);
       
  1582         QAElement B2Element = manager->lookup(B2Interface);
       
  1583         QVERIFY(manager->lookup(B2Element).value() == "B2");
       
  1584         QVERIFY(value(B2Element).toString() == "B2");
       
  1585     }
       
  1586 
       
  1587 
       
  1588 
       
  1589     const AXUIElementRef Arow = childByTitle(tableElement, "1");
       
  1590     QVERIFY(Arow);
       
  1591     const AXUIElementRef Brow = childByTitle(tableElement, "2");
       
  1592     QVERIFY(Brow);
       
  1593     const AXUIElementRef Crow = childByTitle(tableElement, "3");
       
  1594     QVERIFY(Crow);
       
  1595 
       
  1596     QCOMPARE(numChildren(Arow), 3);
       
  1597     const AXUIElementRef A1cell = childByTitle(Arow, "A1");
       
  1598     QVERIFY(A1cell);
       
  1599     QVERIFY(role(A1cell) == "AXTextField");
       
  1600     const AXUIElementRef A2cell = childByTitle(Arow, "A2");
       
  1601     QVERIFY(A2cell);
       
  1602     QVERIFY(equal(::parent(A2cell), Arow));
       
  1603 
       
  1604     const AXUIElementRef B2cell = childByTitle(Brow, "B2");
       
  1605     QVERIFY(B2cell);
       
  1606     QVERIFY(equal(::parent(B2cell), Brow));
       
  1607 
       
  1608     {
       
  1609         QVERIFY(supportsAttribute(tableElement, kAXRowsAttribute));
       
  1610         const QList<AXUIElementRef> rows = elementListAttribute(tableElement, kAXRowsAttribute);
       
  1611         QCOMPARE(rows.count(), 3); // the header is not a row
       
  1612         QVERIFY(value(rows.at(1)) == "2");
       
  1613         QVERIFY(value(rows.at(2)) == "3");
       
  1614     }
       
  1615 
       
  1616     {
       
  1617         QVERIFY(supportsAttribute(tableElement, kAXVisibleRowsAttribute));
       
  1618         const QList<AXUIElementRef> rows = elementListAttribute(tableElement, kAXVisibleRowsAttribute);
       
  1619         QCOMPARE(rows.count(), 3);
       
  1620         QVERIFY(value(rows.at(1)) == "2");
       
  1621     }
       
  1622     {
       
  1623         QVERIFY(supportsAttribute(tableElement, kAXSelectedRowsAttribute));
       
  1624         const QList<AXUIElementRef> rows = elementListAttribute(tableElement, kAXSelectedRowsAttribute);
       
  1625         QCOMPARE(rows.count(), 0);
       
  1626     }
       
  1627 
       
  1628     // test row visibility
       
  1629     {
       
  1630         QTableWidget tableWidget;
       
  1631         tableWidget.setObjectName("tablewidget");
       
  1632         tableWidget.setRowCount(1000);
       
  1633         tableWidget.setColumnCount(1);
       
  1634 
       
  1635         for (int i =0; i < 1000; ++i) {
       
  1636             tableWidget.setItem(i, 0, new QTableWidgetItem("item"));
       
  1637         }
       
  1638         tableWidget.show();
       
  1639         
       
  1640         QAInterface tableWidgetInterface = QAccessible::queryAccessibleInterface(&tableWidget);
       
  1641         QAInterface viewPortInterface = tableWidgetInterface.childAt(1);
       
  1642         QCOMPARE(viewPortInterface.childCount(), 1001);
       
  1643 
       
  1644         QVERIFY((viewPortInterface.childAt(2).state() & QAccessible::Invisible) == false);
       
  1645         QVERIFY((viewPortInterface.childAt(2).state() & QAccessible::Offscreen) == false);
       
  1646         
       
  1647         QVERIFY(viewPortInterface.childAt(500).state() & QAccessible::Invisible);
       
  1648 //        QVERIFY(viewPortInterface.childAt(500).state() & QAccessible::Offscreen);
       
  1649         tableWidget.hide();
       
  1650     }
       
  1651 
       
  1652 //    printElementInfo(tableElement);
       
  1653 //    QTest::qWait(1000000);
       
  1654 }
       
  1655 
       
  1656 void tst_qaccessibility_mac::testScrollBar()
       
  1657 {
       
  1658     {
       
  1659         QScrollBar scrollBar;
       
  1660         scrollBar.show();
       
  1661 
       
  1662         QAInterface scrollBarInterface = QAccessible::queryAccessibleInterface(&scrollBar);
       
  1663         QVERIFY(scrollBarInterface.isValid());
       
  1664         QCOMPARE(scrollBarInterface.childCount(), 5);
       
  1665         QCOMPARE(scrollBarInterface.indexOfChild(scrollBarInterface.childAt(1)), 1);
       
  1666         QCOMPARE(scrollBarInterface.indexOfChild(scrollBarInterface.childAt(2)), 2);
       
  1667         QCOMPARE(scrollBarInterface.indexOfChild(scrollBarInterface.childAt(5)), 5);
       
  1668         QCOMPARE(scrollBarInterface.indexOfChild(scrollBarInterface), -1);
       
  1669     }
       
  1670 
       
  1671     const AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
  1672     testAppAndForm(currentApplication);
       
  1673     const AXUIElementRef form = childByTitle(currentApplication, "Form");
       
  1674     QVERIFY(form);
       
  1675     const AXUIElementRef scrollBarElement = childByRole(form, "AXScrollBar");
       
  1676     QVERIFY(scrollBarElement);
       
  1677     QCOMPARE(attribute(scrollBarElement, kAXOrientationAttribute).toString(), QLatin1String("AXVerticalOrientation"));
       
  1678 
       
  1679     {
       
  1680         const AXUIElementRef lineUpElement = childByTitle(scrollBarElement, "Line up");
       
  1681         QVERIFY(lineUpElement);
       
  1682         QCOMPARE (subrole(lineUpElement), QLatin1String("AXDecrementArrow"));
       
  1683     }{
       
  1684         const AXUIElementRef lineDownElement = childByTitle(scrollBarElement, "Line down");
       
  1685         QVERIFY(lineDownElement);
       
  1686         QCOMPARE (subrole(lineDownElement), QLatin1String("AXIncrementArrow"));
       
  1687     }{
       
  1688         const AXUIElementRef pageUpElement = childByTitle(scrollBarElement, "Page up");
       
  1689         QVERIFY(pageUpElement);
       
  1690         QCOMPARE (subrole(pageUpElement), QLatin1String("AXDecrementPage"));
       
  1691     }{
       
  1692         const AXUIElementRef pageDownElement = childByTitle(scrollBarElement, "Page down");
       
  1693         QVERIFY(pageDownElement);
       
  1694         QCOMPARE (subrole(pageDownElement), QLatin1String("AXIncrementPage"));
       
  1695     }{
       
  1696         const AXUIElementRef valueIndicatorElement = childByTitle(scrollBarElement, "Position");
       
  1697         QVERIFY(valueIndicatorElement);
       
  1698         QCOMPARE(value(valueIndicatorElement).toInt(), 50);
       
  1699     }
       
  1700 }
       
  1701 
       
  1702 void tst_qaccessibility_mac::testSplitter()
       
  1703 {
       
  1704     const AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
       
  1705     testAppAndForm(currentApplication);
       
  1706     const AXUIElementRef form = childByTitle(currentApplication, "Form");
       
  1707     QVERIFY(form);
       
  1708     
       
  1709     const AXUIElementRef splitGroupElement = childByRole(form, "AXSplitGroup");
       
  1710     QVERIFY(splitGroupElement);
       
  1711 
       
  1712     for (int i = 0; i < numChildren(splitGroupElement); ++i)
       
  1713         QVERIFY(child(splitGroupElement, 3));
       
  1714 
       
  1715     // Visual Order: Foo splitter Bar splitter Baz
       
  1716     QList<AXUIElementRef> splitterList = elementListAttribute(splitGroupElement, kAXSplittersAttribute);
       
  1717     QCOMPARE(splitterList.count(), 2); 
       
  1718     foreach (AXUIElementRef splitter, splitterList) {
       
  1719         QCOMPARE(role(splitter), QLatin1String("AXSplitter"));
       
  1720         QVERIFY(supportsAttribute(splitter, kAXPreviousContentsAttribute));
       
  1721         QVERIFY(supportsAttribute(splitter, kAXNextContentsAttribute));
       
  1722         QCOMPARE(attribute(splitter, kAXOrientationAttribute).toString(), QLatin1String("AXVerticalOrientation"));
       
  1723         QList<AXUIElementRef> prevList = elementListAttribute(splitter, kAXPreviousContentsAttribute);  
       
  1724         QCOMPARE(prevList.count(), 1); 
       
  1725         QList<AXUIElementRef> nextList = elementListAttribute(splitter, kAXNextContentsAttribute);  
       
  1726         QCOMPARE(nextList.count(), 1);
       
  1727         
       
  1728         // verify order
       
  1729         if (title(prevList.at(0)) == QLatin1String("Foo"))
       
  1730             QCOMPARE(title(nextList.at(0)), QLatin1String("Bar"));
       
  1731         else if (title(prevList.at(0)) == QLatin1String("Bar"))
       
  1732             QCOMPARE(title(nextList.at(0)), QLatin1String("Baz"));
       
  1733         else {
       
  1734             QFAIL("Splitter contents and handles are out of order"); 
       
  1735         }
       
  1736     }
       
  1737 }
       
  1738 
       
  1739 void tst_qaccessibility_mac::testTextEdit()
       
  1740 {
       
  1741     QWidget window;
       
  1742     const QString windowTitle("window");
       
  1743     window.setWindowTitle(windowTitle);
       
  1744     window.resize(300, 300);
       
  1745 
       
  1746     QTextEdit *textEdit = new QTextEdit(&window);
       
  1747     textEdit->resize(300, 300);
       
  1748     const QString textLine("this is a line");
       
  1749     textEdit->setText(textLine);
       
  1750     
       
  1751     window.show();
       
  1752 
       
  1753     const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
       
  1754     QVERIFY(applicationElement);
       
  1755     const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
       
  1756     QVERIFY(windowElement);
       
  1757     const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
       
  1758     QVERIFY(scrollAreaElement);
       
  1759     const AXUIElementRef textElement = childByRole(scrollAreaElement, "AXTextField");
       
  1760     QVERIFY(textElement);
       
  1761     QVERIFY(value(textElement) == textLine);
       
  1762 }
       
  1763 
       
  1764 void testModelLessItemView(QAbstractItemView *itemView, const QByteArray &role)
       
  1765 {
       
  1766     const QString windowTitle("window");
       
  1767     itemView->setWindowTitle(windowTitle);
       
  1768     itemView->show();
       
  1769 
       
  1770     QTest::qWait(100);
       
  1771 #if defined(Q_WS_X11)
       
  1772     qt_x11_wait_for_window_manager(w);
       
  1773 #endif
       
  1774 
       
  1775     QAccessibleInterface *acc = QAccessible::queryAccessibleInterface(itemView);
       
  1776     QVERIFY(acc->isValid());
       
  1777     QCOMPARE(acc->childCount(), 1);
       
  1778     acc->role(0);
       
  1779     acc->rect(0);
       
  1780 
       
  1781     QAccessibleInterface *accViewport = 0;
       
  1782     int entry = acc->navigate(QAccessible::Child, 1, &accViewport);
       
  1783     QVERIFY(accViewport);
       
  1784     QCOMPARE(entry, 0);
       
  1785     QVERIFY(accViewport->isValid());
       
  1786     QCOMPARE(accViewport->childCount(), 0);
       
  1787     accViewport->role(0);
       
  1788     accViewport->rect(0);
       
  1789 
       
  1790     delete acc;
       
  1791     delete accViewport;
       
  1792         
       
  1793     const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
       
  1794     QVERIFY(applicationElement);
       
  1795     const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
       
  1796     QVERIFY(windowElement);
       
  1797     const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
       
  1798     QVERIFY(scrollAreaElement);
       
  1799     const AXUIElementRef tableElement = childByRole(scrollAreaElement, role);
       
  1800     QVERIFY(tableElement);
       
  1801     
       
  1802     delete itemView;
       
  1803 }
       
  1804 
       
  1805 void tst_qaccessibility_mac::testItemViewsWithoutModel()
       
  1806 {
       
  1807     testModelLessItemView(new QListView(), "AXList");
       
  1808     testModelLessItemView(new QTableView(), "AXTable");
       
  1809 }
       
  1810 
       
  1811 void tst_qaccessibility_mac::testQAElement()
       
  1812 {
       
  1813     {
       
  1814         QAElement element;
       
  1815         QVERIFY(element.isValid() == false);
       
  1816     }
       
  1817     
       
  1818     {
       
  1819         QAElement element(0, 0);
       
  1820         QVERIFY(element.isValid() == false);
       
  1821     }
       
  1822 
       
  1823     {
       
  1824         int argc = 0;
       
  1825         char **argv = 0;
       
  1826         QApplication app(argc, argv);
       
  1827         QWidget w;
       
  1828         QAElement element(reinterpret_cast<HIObjectRef>(w.winId()), 0);
       
  1829         QVERIFY(element.isValid() == true);
       
  1830     }
       
  1831 
       
  1832 }
       
  1833 
       
  1834 void tst_qaccessibility_mac::testQAInterface()
       
  1835 {
       
  1836     {
       
  1837         QAInterface interface;
       
  1838         QVERIFY(interface.isValid() == false);
       
  1839     }
       
  1840     
       
  1841     {
       
  1842         QAInterface interface(0, 0);
       
  1843         QVERIFY(interface.isValid() == false);
       
  1844     }
       
  1845 
       
  1846     {
       
  1847         int argc = 0;
       
  1848         char **argv = 0;
       
  1849         QApplication app(argc, argv);
       
  1850 
       
  1851         {
       
  1852             QWidget w;
       
  1853             QAInterface element(QAccessible::queryAccessibleInterface(&w), 0);
       
  1854             QVERIFY(element.isValid() == true);
       
  1855         }
       
  1856         {
       
  1857             QWidget w;
       
  1858             QAInterface element(QAccessible::queryAccessibleInterface(&w), 100);
       
  1859             QVERIFY(element.isValid() == false);
       
  1860         }
       
  1861     }
       
  1862 }
       
  1863 
       
  1864 void tst_qaccessibility_mac::uitests_data()
       
  1865 {
       
  1866     QTest::addColumn<QString>("uiFilename");
       
  1867     QTest::addColumn<QString>("testSlot");
       
  1868 
       
  1869     QTest::newRow("form") << "form.ui" << SLOT(testForm());
       
  1870     QTest::newRow("buttons") << "buttons.ui" << SLOT(testButtons());
       
  1871     QTest::newRow("label") << "label.ui" << SLOT(testLabel());
       
  1872     QTest::newRow("line edit") << "lineedit.ui" << SLOT(testLineEdit());
       
  1873     QTest::newRow("groups") << "groups.ui" << SLOT(testGroups());
       
  1874     QTest::newRow("tabs") << "tabs.ui" << SLOT(testTabWidget());
       
  1875     QTest::newRow("combobox") << "combobox.ui" << SLOT(testComboBox());
       
  1876     QTest::newRow("scrollbar") << "scrollbar.ui" << SLOT(testScrollBar());
       
  1877     QTest::newRow("splitters") << "splitters.ui" << SLOT(testSplitter());
       
  1878 }
       
  1879 
       
  1880 void tst_qaccessibility_mac::uitests()
       
  1881 {
       
  1882     QFETCH(QString, uiFilename);
       
  1883     QFETCH(QString, testSlot);
       
  1884 
       
  1885     // The Accessibility interface must be enabled to run this test.
       
  1886     if (!AXAPIEnabled())
       
  1887         QSKIP("Accessibility not enabled. Check \"Enable access for assistive devices\" in the system preferences -> universal access to run this test.", SkipAll);
       
  1888 
       
  1889     int argc = 0;
       
  1890     char **argv = 0;
       
  1891     QApplication app(argc, argv);
       
  1892 
       
  1893     // Create and display form.
       
  1894     QUiLoader loader;
       
  1895     QFile file(":" + uiFilename);
       
  1896     QVERIFY(file.exists());
       
  1897     file.open(QFile::ReadOnly);
       
  1898     QWidget *window = loader.load(&file, 0);
       
  1899     QVERIFY(window);
       
  1900     file.close();
       
  1901     window->show();
       
  1902 
       
  1903     QTimer::singleShot(50, this, qPrintable(testSlot));
       
  1904     // Quit when returning to the main event loop after running tests.
       
  1905     QTimer::singleShot(200, &app, SLOT(quit()));
       
  1906     app.exec();
       
  1907     delete window;
       
  1908 }
       
  1909 
       
  1910 void tst_qaccessibility_mac::tests_data()
       
  1911 {
       
  1912     QTest::addColumn<QString>("testSlot");
       
  1913     QTest::newRow("deleteWidget") << SLOT(testDeleteWidget());
       
  1914     QTest::newRow("deleteWidgets") << SLOT(testDeleteWidgets());
       
  1915     QTest::newRow("multipleWindows") << SLOT(testMultipleWindows());
       
  1916     QTest::newRow("hiddenWidgets") << SLOT(testHiddenWidgets());
       
  1917     QTest::newRow("actions") << SLOT(testActions());
       
  1918     QTest::newRow("changeState") << SLOT(testChangeState());
       
  1919     QTest::newRow("slider") << SLOT(testSlider());
       
  1920     QTest::newRow("scrollArea") << SLOT(testScrollArea());
       
  1921     QTest::newRow("listView") << SLOT(testListView());
       
  1922     QTest::newRow("tableView") << SLOT(testTableView());
       
  1923     QTest::newRow("textEdit") << SLOT(testTextEdit());
       
  1924     QTest::newRow("ItemViews without model") << SLOT(testItemViewsWithoutModel());
       
  1925     QTest::newRow("tabbar") << SLOT(testTabBar());
       
  1926 }
       
  1927 
       
  1928 void tst_qaccessibility_mac::tests()
       
  1929 {
       
  1930     QFETCH(QString, testSlot);
       
  1931     runTest(testSlot);
       
  1932 }
       
  1933 
       
  1934 /*
       
  1935     Tests show that querying the accessibility interface directly does not work. (I get a
       
  1936     kAXErrorAPIDisabled error, indicating that the accessible API is disabled, which it isn't.)
       
  1937     To work around this, we run the tests in a callback slot called from the main event loop.
       
  1938 */
       
  1939 void tst_qaccessibility_mac::runTest(const QString &testSlot)
       
  1940 {
       
  1941     // The Accessibility interface must be enabled to run this test.
       
  1942     if (!AXAPIEnabled())
       
  1943         QSKIP("Accessibility not enabled. Check \"Enable access for assistive devices\" in the system preferences -> universal access to run this test.", SkipAll);
       
  1944 
       
  1945     int argc = 0;
       
  1946     char **argv = 0;
       
  1947     QApplication app(argc, argv);
       
  1948 
       
  1949     QTimer::singleShot(50, this, qPrintable(testSlot));
       
  1950     // Quit when returning to the main event loop after running tests.
       
  1951     QTimer::singleShot(200, &app, SLOT(quit()));
       
  1952     app.exec();
       
  1953 
       
  1954 }
       
  1955 
       
  1956 QTEST_APPLESS_MAIN(tst_qaccessibility_mac)
       
  1957 
       
  1958 #else // defined(Q_WS_MAC) && !defined (QT_MAC_USE_COCOA)
       
  1959 
       
  1960 QTEST_NOOP_MAIN
       
  1961 
       
  1962 #endif
       
  1963 
       
  1964 #include "tst_qaccessibility_mac.moc"
       
  1965 
       
  1966