/*
  IAccessible
*/
HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
{
    showDebug(__FUNCTION__, accessible);
    if (!accessible->isValid())
        return E_FAIL;

    int control = accessible->childAt(xLeft, yTop);
    if (control == -1) {
        (*pvarID).vt = VT_EMPTY;
        return S_FALSE;
    }
    QAccessibleInterface *acc = 0;
    if (control)
        accessible->navigate(Child, control, &acc);
    if (!acc) {
        (*pvarID).vt = VT_I4;
        (*pvarID).lVal = control;
        return S_OK;
    }

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

    (*pvarID).vt = VT_EMPTY;
    return S_FALSE;
}
Exemple #2
0
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID)
{
    showDebug(__FUNCTION__, accessible);
    if (!accessible->isValid())
        return E_FAIL;

    QAccessibleInterface *acc = 0;
    int control = accessible->navigate(QAccessible::FocusChild, 1, &acc);
    if (control == -1) {
        (*pvarID).vt = VT_EMPTY;
        return S_FALSE;
    }
    if (!acc || control == 0) {
        (*pvarID).vt = VT_I4;
        (*pvarID).lVal = control ? control : CHILDID_SELF;
        return S_OK;
    }

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

    (*pvarID).vt = VT_EMPTY;
    return S_FALSE;
}
Exemple #3
0
int QAccessibleTable2Cell::navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const
{
    if (relation == Ancestor && index == 1) {
        if (m_role == QAccessible::TreeItem) {
            *iface = new QAccessibleTree(view);
        } else {
            *iface = new QAccessibleTable2(view);
        }
        return 0;
    }

    *iface = 0;
    if (!view)
        return -1;

    switch (relation) {

    case Child: {
        return -1;
    }
    case Sibling:
        if (index > 0) {
            QAccessibleInterface *parent = queryAccessibleInterface(view);
            int ret = parent->navigate(QAccessible::Child, index, iface);
            delete parent;
            if (*iface)
                return ret;
        }
        return -1;

// From table1 implementation:
//    case Up:
//    case Down:
//    case Left:
//    case Right: {
//        // This is in the "not so nice" category. In order to find out which item
//        // is geometrically around, we have to set the current index, navigate
//        // and restore the index as well as the old selection
//        view->setUpdatesEnabled(false);
//        const QModelIndex oldIdx = view->currentIndex();
//        QList<QModelIndex> kids = children();
//        const QModelIndex currentIndex = index ? kids.at(index - 1) : QModelIndex(row);
//        const QItemSelection oldSelection = view->selectionModel()->selection();
//        view->setCurrentIndex(currentIndex);
//        const QModelIndex idx = view->moveCursor(toCursorAction(relation), Qt::NoModifier);
//        view->setCurrentIndex(oldIdx);
//        view->selectionModel()->select(oldSelection, QItemSelectionModel::ClearAndSelect);
//        view->setUpdatesEnabled(true);
//        if (!idx.isValid())
//            return -1;

//        if (idx.parent() != row.parent() || idx.row() != row.row())
//            *iface = cell(idx);
//        return index ? kids.indexOf(idx) + 1 : 0; }
    default:
        break;
    }

    return -1;
}
HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren)
{
#ifdef DEBUG_SHOW_ATCLIENT_COMMANDS
    showDebug(__FUNCTION__, accessible);
#endif //DEBUG_SHOW_ATCLIENT_COMMANDS
    if (!accessible->isValid())
        return E_FAIL;

    int cc = accessible->childCount();
    QVector<int> sel(cc);
    int selIndex = 0;
    for (int i = 1; i <= cc; ++i) {
        QAccessibleInterface *child = 0;
        int i2 = accessible->navigate(Child, i, &child);
        bool isSelected = false;
        if (child) {
            isSelected = child->state(0) & Selected;
            delete child;
            child = 0;
        } else {
            isSelected = accessible->state(i2) & Selected;
        }
        if (isSelected)
            sel[selIndex++] = i;
    }
    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;
}
HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispParent)
{
    showDebug(__FUNCTION__, accessible);
    if (!accessible->isValid())
        return E_FAIL;

    QAccessibleInterface *acc = 0;
    accessible->navigate(Ancestor, 1, &acc);
    if (acc) {
        QWindowsAccessible* wacc = new QWindowsAccessible(acc);
        wacc->QueryInterface(IID_IDispatch, (void**)ppdispParent);

        if (*ppdispParent)
            return S_OK;
    }

    *ppdispParent = 0;
    return S_FALSE;
}
HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
{
#ifdef DEBUG_SHOW_ATCLIENT_COMMANDS
    showDebug(__FUNCTION__, accessible);
#endif //DEBUG_SHOW_ATCLIENT_COMMANDS
    if (!accessible->isValid())
        return E_FAIL;

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

    QAccessibleInterface *acc = 0;
    RelationFlag rel = varChildID.lVal ? Child : Self;
    accessible->navigate(rel, varChildID.lVal, &acc);

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

    *ppdispChild = 0;
    return S_FALSE;
}
HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
{
#ifdef DEBUG_SHOW_ATCLIENT_COMMANDS
    showDebug(__FUNCTION__, accessible);
#endif //DEBUG_SHOW_ATCLIENT_COMMANDS
    if (!accessible->isValid())
        return E_FAIL;

    QAccessibleInterface *acc = 0;
    int control = -1;
    switch(navDir) {
    case NAVDIR_FIRSTCHILD:
        control = accessible->navigate(Child, 1, &acc);
        break;
    case NAVDIR_LASTCHILD:
        control = accessible->navigate(Child, accessible->childCount(), &acc);
        break;
    case NAVDIR_NEXT:
    case NAVDIR_PREVIOUS:
        if (!varStart.lVal){
            QAccessibleInterface *parent = 0;
            accessible->navigate(Ancestor, 1, &parent);
            if (parent) {
                int index = parent->indexOfChild(accessible);
                index += (navDir == NAVDIR_NEXT) ? 1 : -1;
                if (index > 0 && index <= parent->childCount())
                    control = parent->navigate(Child, index, &acc);
                delete parent;
            }
        } else {
            int index = varStart.lVal;
            index += (navDir == NAVDIR_NEXT) ? 1 : -1;
            if (index > 0 && index <= accessible->childCount())
                control = accessible->navigate(Child, index, &acc);
        }
        break;
    case NAVDIR_UP:
        control = accessible->navigate(Up, varStart.lVal, &acc);
        break;
    case NAVDIR_DOWN:
        control = accessible->navigate(Down, varStart.lVal, &acc);
        break;
    case NAVDIR_LEFT:
        control = accessible->navigate(Left, varStart.lVal, &acc);
        break;
    case NAVDIR_RIGHT:
        control = accessible->navigate(Right, varStart.lVal, &acc);
        break;
    default:
        break;
    }
    if (control == -1) {
        (*pvarEnd).vt = VT_EMPTY;
        return S_FALSE;
    }
    if (!acc) {
        (*pvarEnd).vt = VT_I4;
        (*pvarEnd).lVal = control;
        return S_OK;
    }

    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;
}
/*! \reimp */
int QAccessibleWidget::navigate(RelationFlag relation, int entry,
                                QAccessibleInterface **target) const
{
    if (!target)
        return -1;

    *target = 0;
    QObject *targetObject = 0;

    QWidgetList childList = childWidgets(widget());
    bool complexWidget = childList.size() < childCount();

    switch (relation) {
    // Hierarchical
    case Self:
        targetObject = object();
        break;
    case Child:
        if (complexWidget) {
            if (entry > 0 && entry <= childCount())
                return entry;
            return -1;
        }else {
            if (entry > 0 && childList.size() >= entry)
                targetObject = childList.at(entry - 1);
        }
        break;
    case Ancestor:
        {
            if (entry <= 0)
                return -1;
            targetObject = widget()->parentWidget();
            int i;
            for (i = entry; i > 1 && targetObject; --i)
                targetObject = targetObject->parent();
            if (!targetObject && i == 1)
                targetObject = qApp;
        }
        break;
    case Sibling:
        {
            QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(parentObject());
            if (!iface)
                return -1;

            iface->navigate(Child, entry, target);
            delete iface;
            if (*target)
                return 0;
        }
        break;

    // Geometrical
    case QAccessible::Left:
        if (complexWidget && entry) {
            if (entry < 2 || widget()->height() > widget()->width() + 20) // looks vertical
                return -1;
            return entry - 1;
        }
        // fall through
    case QAccessible::Right:
        if (complexWidget && entry) {
            if (entry >= childCount() || widget()->height() > widget()->width() + 20) // looks vertical
                return -1;
            return entry + 1;
        }
        // fall through
    case QAccessible::Up:
        if (complexWidget && entry) {
            if (entry < 2 || widget()->width() > widget()->height() + 20) // looks horizontal
                return - 1;
            return entry - 1;
        }
        // fall through
    case QAccessible::Down:
        if (complexWidget && entry) {
            if (entry >= childCount() || widget()->width() > widget()->height()  + 20) // looks horizontal
                return - 1;
            return entry + 1;
        } else {
            QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
            if (!pIface)
                return -1;

            QRect startg = rect(0);
            QPoint startc = startg.center();
            QAccessibleInterface *candidate = 0;
            int mindist = 100000;
            int sibCount = pIface->childCount();
            for (int i = 0; i < sibCount; ++i) {
                QAccessibleInterface *sibling = 0;
                pIface->navigate(Child, i+1, &sibling);
                Q_ASSERT(sibling);
                if ((relationTo(0, sibling, 0) & Self) || (sibling->state(0) & QAccessible::Invisible)) {
                    //ignore ourself and invisible siblings
                    delete sibling;
                    continue;
                }

                QRect sibg = sibling->rect(0);
                QPoint sibc = sibg.center();
                QPoint sibp;
                QPoint startp;
                QPoint distp;
                switch (relation) {
                case QAccessible::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 QAccessible::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 QAccessible::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 QAccessible::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;
                }

                int dist = (int)qSqrt((qreal)distp.x() * distp.x() + distp.y() * distp.y());
                if (dist < mindist) {
                    delete candidate;
                    candidate = sibling;
                    mindist = dist;
                } else {
                    delete sibling;
                }
            }
            delete pIface;
            *target = candidate;
            if (*target)
                return 0;
        }
        break;
    case Covers:
        if (entry > 0) {
            QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
            if (!pIface)
                return -1;

            QRect r = rect(0);
            int sibCount = pIface->childCount();
            QAccessibleInterface *sibling = 0;
            for (int i = pIface->indexOfChild(this) + 1; i <= sibCount && entry; ++i) {
                pIface->navigate(Child, i, &sibling);
                if (!sibling || (sibling->state(0) & Invisible)) {
                    delete sibling;
                    sibling = 0;
                    continue;
                }
                if (sibling->rect(0).intersects(r))
                    --entry;
                if (!entry)
                    break;
                delete sibling;
                sibling = 0;
            }
            delete pIface;
            *target = sibling;
            if (*target)
                return 0;
        }
        break;
    case Covered:
        if (entry > 0) {
            QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
            if (!pIface)
                return -1;

            QRect r = rect(0);
            int index = pIface->indexOfChild(this);
            QAccessibleInterface *sibling = 0;
            for (int i = 1; i < index && entry; ++i) {
                pIface->navigate(Child, i, &sibling);
                Q_ASSERT(sibling);
                if (!sibling || (sibling->state(0) & Invisible)) {
                    delete sibling;
                    sibling = 0;
                    continue;
                }
                if (sibling->rect(0).intersects(r))
                    --entry;
                if (!entry)
                    break;
                delete sibling;
                sibling = 0;
            }
            delete pIface;
            *target = sibling;
            if (*target)
                return 0;
        }
        break;

    // Logical
    case FocusChild:
        {
            if (widget()->hasFocus()) {
                targetObject = object();
                break;
            }

            QWidget *fw = widget()->focusWidget();
            if (!fw)
                return -1;

            if (isAncestor(widget(), fw) || fw == widget())
                targetObject = fw;
            /* ###
            QWidget *parent = fw;
            while (parent && !targetObject) {
                parent = parent->parentWidget();
                if (parent == widget())
                    targetObject = fw;
            }
            */
        }
        break;
    case Label:
        if (entry > 0) {
            QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
            if (!pIface)
                return -1;

            // first check for all siblings that are labels to us
            // ideally we would go through all objects and check, but that
            // will be too expensive
            int sibCount = pIface->childCount();
            QAccessibleInterface *candidate = 0;
            for (int i = 0; i < sibCount && entry; ++i) {
                const int childId = pIface->navigate(Child, i+1, &candidate);
                Q_ASSERT(childId >= 0);
                if (childId > 0)
                    candidate = pIface;
                if (candidate->relationTo(childId, this, 0) & Label)
                    --entry;
                if (!entry)
                    break;
                if (candidate != pIface)
                    delete candidate;
                candidate = 0;
            }
            if (!candidate) {
                if (pIface->relationTo(0, this, 0) & Label)
                    --entry;
                if (!entry)
                    candidate = pIface;
            }
            if (pIface != candidate)
                delete pIface;

            *target = candidate;
            if (*target)
                return 0;
        }
        break;
    case Labelled: // only implemented in subclasses
        break;
    case Controller:
        if (entry > 0) {
            // check all senders we are connected to,
            // and figure out which one are controllers to us
            QACConnectionObject *connectionObject = (QACConnectionObject*)object();
            QObjectList allSenders = connectionObject->senderList();
            QObjectList senders;
            for (int s = 0; s < allSenders.size(); ++s) {
                QObject *sender = allSenders.at(s);
                QAccessibleInterface *candidate = QAccessible::queryAccessibleInterface(sender);
                if (!candidate)
                    continue;
                if (candidate->relationTo(0, this, 0)&Controller)
                    senders << sender;
                delete candidate;
            }
            if (entry <= senders.size())
                targetObject = senders.at(entry-1);
        }
        break;
    case Controlled:
        if (entry > 0) {
            QObjectList allReceivers;
            QACConnectionObject *connectionObject = (QACConnectionObject*)object();
            for (int sig = 0; sig < d->primarySignals.count(); ++sig) {
                QObjectList receivers = connectionObject->receiverList(d->primarySignals.at(sig).toAscii());
                allReceivers += receivers;
            }
            if (entry <= allReceivers.size())
                targetObject = allReceivers.at(entry-1);
        }
        break;
    default:
        break;
    }

    *target = QAccessible::queryAccessibleInterface(targetObject);
    return *target ? 0 : -1;
}
/*! \reimp */
QAccessible::Relation QAccessibleWidget::relationTo(int child,
            const QAccessibleInterface *other, int otherChild) const
{
    Relation relation = Unrelated;
    if (d->asking == this) // recursive call
        return relation;

    QObject *o = other ? other->object() : 0;
    if (!o)
        return relation;

    QWidget *focus = widget()->focusWidget();
    if (object() == focus && isAncestor(o, focus))
        relation |= FocusChild;

    QACConnectionObject *connectionObject = (QACConnectionObject*)object();
    for (int sig = 0; sig < d->primarySignals.count(); ++sig) {
        if (connectionObject->isSender(o, d->primarySignals.at(sig).toAscii())) {
            relation |= Controller;
            break;
        }
    }
    // test for passive relationships.
    // d->asking protects from endless recursion.
    d->asking = this;
    int inverse = other->relationTo(otherChild, this, child);
    d->asking = 0;

    if (inverse & Controller)
        relation |= Controlled;
    if (inverse & Label)
        relation |= Labelled;

    if(o == object()) {
        if (child && !otherChild)
            return relation | Child;
        if (!child && otherChild)
            return relation | Ancestor;
        if (!child && !otherChild)
            return relation | Self;
    }

    QObject *parent = object()->parent();
    if (o == parent)
        return relation | Child;

    if (o->parent() == parent) {
        relation |= Sibling;
        QAccessibleInterface *sibIface = QAccessible::queryAccessibleInterface(o);
        Q_ASSERT(sibIface);
        QRect wg = rect(0);
        QRect sg = sibIface->rect(0);
        if (wg.intersects(sg)) {
            QAccessibleInterface *pIface = 0;
            sibIface->navigate(Ancestor, 1, &pIface);
            if (pIface && !((sibIface->state(0) | state(0)) & Invisible)) {
                int wi = pIface->indexOfChild(this);
                int si = pIface->indexOfChild(sibIface);

                if (wi > si)
                    relation |= QAccessible::Covers;
                else
                    relation |= QAccessible::Covered;
            }
            delete pIface;
        } else {
            QPoint wc = wg.center();
            QPoint sc = sg.center();
            if (wc.x() < sc.x())
                relation |= QAccessible::Left;
            else if(wc.x() > sc.x())
                relation |= QAccessible::Right;
            if (wc.y() < sc.y())
                relation |= QAccessible::Up;
            else if (wc.y() > sc.y())
                relation |= QAccessible::Down;
        }
        delete sibIface;

        return relation;
    }

    if (isAncestor(o, object()))
        return relation | Descendent;
    if (isAncestor(object(), o))
        return relation | Ancestor;

    return relation;
}