void tst_QQuickAccessible::ignoredTest()
{
    QScopedPointer<QQuickView> window(new QQuickView());
    window->setSource(testFileUrl("ignored.qml"));
    window->show();

    QQuickItem *contentItem = window->contentItem();
    QVERIFY(contentItem);
    QQuickItem *rootItem = contentItem->childItems().first();
    QVERIFY(rootItem);

    // the window becomes active
    QAccessible::State activatedChange;
    activatedChange.active = true;

    QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.data());
    QVERIFY(iface);
    QAccessibleInterface *rectangleA = iface->child(0);

    QCOMPARE(rectangleA->role(), QAccessible::StaticText);
    QCOMPARE(rectangleA->text(QAccessible::Name), QLatin1String("A"));
    static const char *expected = "BEFIHD";
    // check if node "C" and "G" is skipped and that the order is as expected.
    for (int i = 0; i < rectangleA->childCount(); ++i) {
        QAccessibleInterface *child = rectangleA->child(i);
        QCOMPARE(child->text(QAccessible::Name), QString(QLatin1Char(expected[i])));
    }
    QTestAccessibility::clearEvents();
}
void tst_QQuickAccessible::hitTest()
{
    QQuickView *window = new QQuickView;
    window->setSource(testFileUrl("hittest.qml"));
    window->show();

    QAccessibleInterface *windowIface = QAccessible::queryAccessibleInterface(window);
    QVERIFY(windowIface);
    QAccessibleInterface *rootItem = windowIface->child(0);
    QRect rootRect = rootItem->rect();

    // check the root item from app
    QAccessibleInterface *appIface = QAccessible::queryAccessibleInterface(qApp);
    QVERIFY(appIface);
    QAccessibleInterface *itemHit = appIface->childAt(rootRect.x() + 200, rootRect.y() + 50);
    QVERIFY(itemHit);
    QCOMPARE(itemHit->rect(), rootRect);

    QAccessibleInterface *rootItemIface;
    for (int c = 0; c < rootItem->childCount(); ++c) {
        QAccessibleInterface *iface = rootItem->child(c);
        QString name = iface->text(QAccessible::Name);
        if (name == QLatin1String("rect1")) {
            // hit rect1
            QAccessibleInterface *rect1 = iface;
            QRect rect1Rect = rect1->rect();
            QAccessibleInterface *rootItemIface = rootItem->childAt(rect1Rect.x() + 10, rect1Rect.y() + 10);
            QVERIFY(rootItemIface);
            QCOMPARE(rect1Rect, rootItemIface->rect());
            QCOMPARE(rootItemIface->text(QAccessible::Name), QLatin1String("rect1"));

            // should also work from top level (app)
            QAccessibleInterface *app(QAccessible::queryAccessibleInterface(qApp));
            QAccessibleInterface *itemHit2(topLevelChildAt(app, rect1Rect.x() + 10, rect1Rect.y() + 10));
            QVERIFY(itemHit2);
            QCOMPARE(itemHit2->rect(), rect1Rect);
            QCOMPARE(itemHit2->text(QAccessible::Name), QLatin1String("rect1"));
        } else if (name == QLatin1String("rect2")) {
            QAccessibleInterface *rect2 = iface;
            // FIXME: This is seems broken on OS X
            // QCOMPARE(rect2->rect().translated(rootItem->rect().x(), rootItem->rect().y()), QRect(0, 50, 100, 100));
            QAccessibleInterface *rect20 = rect2->child(0);
            QVERIFY(rect20);
            QCOMPARE(rect20->text(QAccessible::Name), QLatin1String("rect20"));
            QPoint p = rect20->rect().bottomRight() + QPoint(20, 20);
            QAccessibleInterface *rect201 = rect20->childAt(p.x(), p.y());
            QVERIFY(rect201);
            QCOMPARE(rect201->text(QAccessible::Name), QLatin1String("rect201"));
            rootItemIface = topLevelChildAt(windowIface, p.x(), p.y());
            QVERIFY(rootItemIface);
            QCOMPARE(rootItemIface->text(QAccessible::Name), QLatin1String("rect201"));

        }
    }

    delete window;
    QTestAccessibility::clearEvents();
}
void tst_QQuickAccessible::hitTest()
{
    QQuickView *window = new QQuickView;
    window->setSource(testFileUrl("hittest.qml"));
    window->show();

    QAccessibleInterface *windowIface = QAccessible::queryAccessibleInterface(window);
    QVERIFY(windowIface);
    QAccessibleInterface *rootItem = windowIface->child(0);
    QRect rootRect = rootItem->rect();

    // check the root item from app
    QAccessibleInterface *appIface = QAccessible::queryAccessibleInterface(qApp);
    QVERIFY(appIface);
    QAccessibleInterface *itemHit(appIface->childAt(rootRect.x() + 200, rootRect.y() + 50));
    QVERIFY(itemHit);
    QCOMPARE(rootRect, itemHit->rect());

    // hit rect1
    QAccessibleInterface *rect1(rootItem->child(0));
    QRect rect1Rect = rect1->rect();
    QAccessibleInterface *rootItemIface = rootItem->childAt(rect1Rect.x() + 10, rect1Rect.y() + 10);
    QVERIFY(rootItemIface);
    QCOMPARE(rect1Rect, rootItemIface->rect());
    QCOMPARE(rootItemIface->text(QAccessible::Name), QLatin1String("rect1"));

    // should also work from top level (app)
    QAccessibleInterface *app(QAccessible::queryAccessibleInterface(qApp));
    QAccessibleInterface *itemHit2(topLevelChildAt(app, rect1Rect.x() + 10, rect1Rect.y() + 10));
    QVERIFY(itemHit2);
    QCOMPARE(itemHit2->rect(), rect1Rect);
    QCOMPARE(itemHit2->text(QAccessible::Name), QLatin1String("rect1"));

    // hit rect201
    QAccessibleInterface *rect2(rootItem->child(1));
    QVERIFY(rect2);
    // FIXME: This is seems broken on mac
    // QCOMPARE(rect2->rect().translated(rootItem->rect().x(), rootItem->rect().y()), QRect(0, 50, 100, 100));
    QAccessibleInterface *rect20(rect2->child(0));
    QVERIFY(rect20);
    QAccessibleInterface *rect201(rect20->child(1));
    QVERIFY(rect201);

    QRect rect201Rect = rect201->rect();
    rootItemIface = windowIface->childAt(rect201Rect.x() + 20, rect201Rect.y() + 20);
    QVERIFY(rootItemIface);
    QCOMPARE(rootItemIface->rect(), rect201Rect);
    QCOMPARE(rootItemIface->text(QAccessible::Name), QLatin1String("rect201"));

    delete window;
    QTestAccessibility::clearEvents();
}
void tst_QQuickAccessible::basicPropertiesTest()
{
    QAccessibleInterface *app = QAccessible::queryAccessibleInterface(qApp);
    QCOMPARE(app->childCount(), 0);

    QQuickView *window = new QQuickView();
    window->setSource(testFileUrl("statictext.qml"));
    window->show();
    QCOMPARE(app->childCount(), 1);

    QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window);
    QVERIFY(iface);
    QCOMPARE(iface->childCount(), 1);

    QAccessibleInterface *item = iface->child(0);
    QVERIFY(item);
    QCOMPARE(item->childCount(), 2);
    QCOMPARE(item->rect().size(), QSize(400, 400));
    QCOMPARE(item->role(), QAccessible::Client);
    QCOMPARE(iface->indexOfChild(item), 0);

    QAccessibleInterface *text = item->child(0);
    QVERIFY(text);
    QCOMPARE(text->childCount(), 0);

    QCOMPARE(text->text(QAccessible::Name), QLatin1String("Hello Accessibility"));
    QCOMPARE(text->rect().size(), QSize(200, 50));
    QCOMPARE(text->rect().x(), item->rect().x() + 100);
    QCOMPARE(text->rect().y(), item->rect().y() + 20);
    QCOMPARE(text->role(), QAccessible::StaticText);
    QCOMPARE(item->indexOfChild(text), 0);

    QAccessibleInterface *text2 = item->child(1);
    QVERIFY(text2);
    QCOMPARE(text2->childCount(), 0);

    QCOMPARE(text2->text(QAccessible::Name), QLatin1String("The Hello 2 accessible text"));
    QCOMPARE(text2->rect().size(), QSize(100, 40));
    QCOMPARE(text2->rect().x(), item->rect().x() + 100);
    QCOMPARE(text2->rect().y(), item->rect().y() + 40);
    QCOMPARE(text2->role(), QAccessible::StaticText);
    QCOMPARE(item->indexOfChild(text2), 1);

    QCOMPARE(iface->indexOfChild(text2), -1);
    QCOMPARE(text2->indexOfChild(item), -1);

    delete window;
    QTestAccessibility::clearEvents();
}
Beispiel #5
0
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
{
    showDebug(__FUNCTION__, accessible);
    if (!accessible->isValid())
        return E_FAIL;

    if (varChildID.vt == VT_EMPTY)
        return E_INVALIDARG;


    int childIndex = varChildID.lVal;
    QAccessibleInterface *acc = 0;

    if (childIndex < 0) {
        const int entry = childIndex;
        QPair<QObject*, int> ref = qAccessibleRecentSentEvents()->value(entry);
        if (ref.first) {
            acc = QAccessible::queryAccessibleInterface(ref.first);
            if (acc && ref.second) {
                if (ref.second) {
                    QAccessibleInterface *res = acc->child(ref.second - 1);
                    delete acc;
                    if (!res)
                        return E_INVALIDARG;
                    acc = res;
                }
            }
        }
    } else {
        if (childIndex) {
            acc = accessible->child(childIndex - 1);
        } else {
            // FIXME
            Q_ASSERT(0);
        }
    }

    if (acc) {
        QWindowsAccessible* wacc = new QWindowsAccessible(acc);
        wacc->QueryInterface(IID_IDispatch, (void**)ppdispChild);
        return S_OK;
    }

    *ppdispChild = 0;
    return S_FALSE;
}
Beispiel #6
0
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
{
    accessibleDebugClientCalls(accessible);
    if (!accessible->isValid())
        return E_FAIL;

    if (varChildID.vt != VT_I4)
        return E_INVALIDARG;


    int childIndex = varChildID.lVal;
    QAccessibleInterface *acc = 0;

    if (childIndex < 0) {
        const int entry = childIndex;
        QPair<QObject*, int> ref = QWindowsAccessibility::getCachedObject(entry);
        if (ref.first) {
            acc = QAccessible::queryAccessibleInterface(ref.first);
            if (acc && ref.second >= 0) {
                QAccessibleInterface *res = acc->child(ref.second);
                delete acc;
                if (!res)
                    return E_INVALIDARG;
                acc = res;
            }
        } else {
            qWarning("get_accChild got a negative varChildID, but did not find it in cache");
        }
    } else {
        if (childIndex) {
            acc = accessible->child(childIndex - 1);
        } else {
            // Yes, some AT clients (Active Accessibility Object Inspector)
            // actually ask for the same object. As a consequence, we need to clone ourselves:
            if (QAccessibleInterface *par = accessible->parent()) {
                const int indexOf = par->indexOfChild(accessible);
                QAccessibleInterface *clone = par->child(indexOf);
                delete par;
                acc = clone;
            }
        }
    }

    if (acc) {
        *ppdispChild = QWindowsAccessibility::wrap(acc);
        return S_OK;
    }

    return E_FAIL;
}
    static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId)
    {
        QAccessibleInterface *iface = interfaceFromId(objectId);
        if (iface) {
            jintArray jArray = env->NewIntArray(jsize(iface->childCount()));
            for (int i = 0; i < iface->childCount(); ++i) {
                QAccessibleInterface *child = iface->child(i);
                if (child) {
                    QAccessible::Id ifaceId = QAccessible::uniqueId(child);
                    jint jid = ifaceId;
                    env->SetIntArrayRegion(jArray, i, 1, &jid);
                }
            }
            return jArray;
        }

        return env->NewIntArray(jsize(0));
    }
Beispiel #8
0
/*
    Recursiveley navigates the accessible hiearchy looking for an interface that
    passsed the Test (meaning it returns true).
*/
QAccessibleInterface *WidgetNavigator::recursiveSearch(TestBase *test, QAccessibleInterface *iface)
{
    QStack<QAccessibleInterface *> todoInterfaces;
    todoInterfaces.push(iface);

    while (todoInterfaces.isEmpty() == false) {
        QAccessibleInterface *testInterface = todoInterfaces.pop();

        if ((*test)(testInterface))
            return testInterface;

        const int numChildren = testInterface->childCount();
        for (int i = 0; i < numChildren; ++i) {
            QAccessibleInterface *childInterface = testInterface->child(i);
            if (childInterface) {
                todoInterfaces.push(childInterface);
            }
        }
    }
    return 0;
}
Beispiel #9
0
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
{
    showDebug(__FUNCTION__, accessible);
    if (!accessible->isValid())
        return E_FAIL;

    QRect rect;
    if (varID.lVal) {
        QAIPointer child = QAIPointer(accessible->child(varID.lVal - 1));
        if (child->isValid())
            rect = child->rect();
    } else {
        rect = accessible->rect();
    }

    *pxLeft = rect.x();
    *pyTop = rect.y();
    *pcxWidth = rect.width();
    *pcyHeight = rect.height();

    return S_OK;
}
Beispiel #10
0
HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren)
{
    showDebug(__FUNCTION__, accessible);
    if (!accessible->isValid())
        return E_FAIL;

    int cc = accessible->childCount();
    QVector<int> sel(cc);
    int selIndex = 0;
    for (int i = 0; i < cc; ++i) {
        bool isSelected = false;
        QAccessibleInterface *child = accessible->child(i);
        if (child) {
            isSelected = child->state().selected;
            delete child;
        }
        if (isSelected)
            sel[selIndex++] = i+1;
    }
    sel.resize(selIndex);
    if (sel.isEmpty()) {
        (*pvarChildren).vt = VT_EMPTY;
        return S_FALSE;
    }
    if (sel.size() == 1) {
        (*pvarChildren).vt = VT_I4;
        (*pvarChildren).lVal = sel[0];
        return S_OK;
    }
    IEnumVARIANT *iface = new QWindowsEnumerate(sel);
    IUnknown *uiface;
    iface->QueryInterface(IID_IUnknown, (void**)&uiface);
    (*pvarChildren).vt = VT_UNKNOWN;
    (*pvarChildren).punkVal = uiface;

    return S_OK;
}
void tst_QQuickAccessible::checkableTest()
{
    QScopedPointer<QQuickView> window(new QQuickView());
    window->setSource(testFileUrl("checkbuttons.qml"));
    window->show();

    QQuickItem *contentItem = window->contentItem();
    QVERIFY(contentItem);
    QQuickItem *rootItem = contentItem->childItems().first();
    QVERIFY(rootItem);

    // the window becomes active
    QAccessible::State activatedChange;
    activatedChange.active = true;

    QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.data());
    QVERIFY(iface);
    QAccessibleInterface *root = iface->child(0);

    QAccessibleInterface *button1 = root->child(0);
    QCOMPARE(button1->role(), QAccessible::Button);
    QVERIFY(!(button1->state().checked));
    QVERIFY(!(button1->state().checkable));

    QVERIFY(button1->state().focusable);
    QVERIFY(!button1->state().focused);

    QTestAccessibility::clearEvents();

    // set properties
    QQuickItem *button1item = qobject_cast<QQuickItem*>(rootItem->childItems().at(0));
    QVERIFY(button1item);
    QCOMPARE(button1item->objectName(), QLatin1String("button1"));
    button1item->forceActiveFocus();
    QVERIFY(button1->state().focusable);
    QVERIFY(button1->state().focused);

    QAccessibleEvent focusEvent(button1item, QAccessible::Focus);
    QVERIFY_EVENT(&focusEvent);

    QAccessibleInterface *button2 = root->child(1);
    QVERIFY(!(button2->state().checked));
    QVERIFY(button2->state().checkable);
    QQuickItem *button2item = qobject_cast<QQuickItem*>(rootItem->childItems().at(1));
    QVERIFY(button2item);
    QCOMPARE(button2item->objectName(), QLatin1String("button2"));

    QAccessibleInterface *button3 = root->child(2);
    QVERIFY(button3->state().checked);
    QVERIFY(button3->state().checkable);

    QAccessibleInterface *checkBox1 = root->child(3);
    QCOMPARE(checkBox1->role(), QAccessible::CheckBox);
    QVERIFY(checkBox1->state().checked);
    QVERIFY(checkBox1->state().checkable);
    QQuickItem *checkbox1item = qobject_cast<QQuickItem*>(rootItem->childItems().at(3));
    QVERIFY(checkbox1item);
    QCOMPARE(checkbox1item->objectName(), QLatin1String("checkbox1"));

    checkbox1item->setProperty("checked", false);
    QVERIFY(!checkBox1->state().checked);
    QAccessible::State checkState;
    checkState.checked = true;
    QAccessibleStateChangeEvent checkChanged(checkbox1item, checkState);
    QVERIFY_EVENT(&checkChanged);

    checkbox1item->setProperty("checked", true);
    QVERIFY(checkBox1->state().checked);
    QVERIFY_EVENT(&checkChanged);

    QAccessibleInterface *checkBox2 = root->child(4);
    QVERIFY(!(checkBox2->state().checked));
    QVERIFY(checkBox2->state().checkable);

    QTestAccessibility::clearEvents();
}
Beispiel #12
0
// moz: [important, but no need to implement up/down/left/right]
HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
{
    showDebug(__FUNCTION__, accessible);
    if (!accessible->isValid())
        return E_FAIL;

    QAccessibleInterface *acc = 0;
    switch (navDir) {
    case NAVDIR_FIRSTCHILD:
        acc = accessible->child(0);
        break;
    case NAVDIR_LASTCHILD:
        acc = accessible->child(accessible->childCount() - 1);
        break;
    case NAVDIR_NEXT:
    case NAVDIR_PREVIOUS:
        if (!varStart.lVal){
            QAccessibleInterface *parent = accessible->parent();
            if (parent) {
                int index = parent->indexOfChild(accessible);
                index += (navDir == NAVDIR_NEXT) ? 1 : -1;
                if (index >= 0 && index < parent->childCount())
                    acc = parent->child(index);
                delete parent;
            }
        } else {
            int index = varStart.lVal;
            index += (navDir == NAVDIR_NEXT) ? 1 : -1;
            if (index > 0 && index <= accessible->childCount())
                acc = accessible->child(index - 1);
        }
        break;

    // Geometrical
    case NAVDIR_UP:
    case NAVDIR_DOWN:
    case NAVDIR_LEFT:
    case NAVDIR_RIGHT:
        if (QAccessibleInterface *pIface = accessible->parent()) {

            QRect startg = accessible->rect();
            QPoint startc = startg.center();
            QAccessibleInterface *candidate = 0;
            unsigned mindist = UINT_MAX;    // will work on screen sizes at least up to 46340x46340
            const int sibCount = pIface->childCount();
            for (int i = 0; i < sibCount; ++i) {
                QAccessibleInterface *sibling = 0;
                sibling = pIface->child(i);
                Q_ASSERT(sibling);
                if ((accessible->relationTo(sibling) & QAccessible::Self) || sibling->state().invisible) {
                    //ignore ourself and invisible siblings
                    delete sibling;
                    continue;
                }

                QRect sibg = sibling->rect();
                QPoint sibc = sibg.center();
                QPoint sibp;
                QPoint startp;
                QPoint distp;
                switch (navDir) {
                case NAVDIR_LEFT:
                    startp = QPoint(startg.left(), startg.top() + startg.height() / 2);
                    sibp = QPoint(sibg.right(), sibg.top() + sibg.height() / 2);
                    if (QPoint(sibc - startc).x() >= 0) {
                        delete sibling;
                        continue;
                    }
                    distp = sibp - startp;
                    break;
                case NAVDIR_RIGHT:
                    startp = QPoint(startg.right(), startg.top() + startg.height() / 2);
                    sibp = QPoint(sibg.left(), sibg.top() + sibg.height() / 2);
                    if (QPoint(sibc - startc).x() <= 0) {
                        delete sibling;
                        continue;
                    }
                    distp = sibp - startp;
                    break;
                case NAVDIR_UP:
                    startp = QPoint(startg.left() + startg.width() / 2, startg.top());
                    sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.bottom());
                    if (QPoint(sibc - startc).y() >= 0) {
                        delete sibling;
                        continue;
                    }
                    distp = sibp - startp;
                    break;
                case NAVDIR_DOWN:
                    startp = QPoint(startg.left() + startg.width() / 2, startg.bottom());
                    sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.top());
                    if (QPoint(sibc - startc).y() <= 0) {
                        delete sibling;
                        continue;
                    }
                    distp = sibp - startp;
                    break;
                default:
                    break;
                }

                // Since we're *comparing* (and not measuring) distances, we can compare the
                // squared distance, (thus, no need to take the sqrt()).
                unsigned dist = distp.x() * distp.x() + distp.y() * distp.y();
                if (dist < mindist) {
                    delete candidate;
                    candidate = sibling;
                    mindist = dist;
                } else {
                    delete sibling;
                }
            }
            delete pIface;
            acc = candidate;
        }
        break;
    default:
        break;
    }
    if (!acc) {
        (*pvarEnd).vt = VT_EMPTY;
        return S_FALSE;
    }
    QWindowsAccessible* wacc = new QWindowsAccessible(acc);

    IDispatch *iface = 0;
    wacc->QueryInterface(IID_IDispatch, (void**)&iface);
    if (iface) {
        (*pvarEnd).vt = VT_DISPATCH;
        (*pvarEnd).pdispVal = iface;
        return S_OK;
    } else {
        delete wacc;
    }

    (*pvarEnd).vt = VT_EMPTY;
    return S_FALSE;
}
Beispiel #13
0
 QAIPointer childPointer(VARIANT varID)
 {
     return QAIPointer(accessible->child(varID.lVal - 1));
 }