<commit_before>/*
 * D-Bus AT-SPI, Qt Adaptor
 *
 * Copyright 2009-2011 Nokia Corporation and/or its subsidiary(-ies).
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */


#include <QtCore/QMetaObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>

#include <QAccessibleTextInterface>
#include <QAccessibleEditableTextInterface>
#include <QAccessibleTableInterface>
#include <QAccessibleActionInterface>
#include <QAccessibleValueInterface>

#include <QtCore/QtDebug>
#include <QtGui/QApplication>
#include <QtGui/QWidget>

#include "accessible.h"
#include "adaptor.h"
#include "bridge.h"
#include "constant_mappings.h"


QSpiAdaptor::QSpiAdaptor(QAccessibleInterface *interface_, int child)
    : interface(interface_), child(child)
{
}

QObject* QSpiAdaptor::getObject() const
{
    return interface->object();
}

QSpiObjectReference QSpiAdaptor::getReference() const
{
    return reference;
}

QStringList QSpiAdaptor::getSupportedInterfaces() const
{
    return supportedInterfaces;
}

bool QSpiAdaptor::checkInterface() const
{
    // The interface can be deleted behind our back with no notification.
    if (!interface->isValid()) {
        spiBridge->removeAdaptor(const_cast<QSpiAdaptor*>(this));
        return false;
    }
    return true;
}

QSpiAccessibleCacheItem QSpiAdaptor::getCacheItem() const
{
    Q_ASSERT(interface);
    if (!interface->isValid()) {
        qWarning() << "QSpiObject::getCacheItem: invalid interface" << reference.path.path();
        return QSpiAccessibleCacheItem();
    }

    QSpiAccessibleCacheItem item;
    item.path = getReference();
    item.parent = getParentReference();
    item.application = spiBridge->getRootReference();
    item.children = GetChildren();
    item.supportedInterfaces = getSupportedInterfaces();
    item.name = interface->text(QAccessible::Name, child);
    item.role = qSpiRoleMapping.value(interface->role(child)).spiRole();
    item.description = interface->text(QAccessible::Description, child);
    item.state = GetState();
    return item;
}

void QSpiAdaptor::signalChildrenChanged(const QString &type, int detail1, int detail2, const QDBusVariant &data)
{
    emit ChildrenChanged(type, detail1, detail2, data, spiBridge->getRootReference());
}

int QSpiAdaptor::childCount() const
{
    if (!checkInterface()) return 0;

    if (child)
        return 0;
    return interface->childCount();
}

QString QSpiAdaptor::description() const
{
    if (!checkInterface()) return QString();
    return interface->text(QAccessible::Description, child);
}

QString QSpiAdaptor::name() const
{
    if (!checkInterface()) return QString();
    QString name = interface->text(QAccessible::Name, child);
    if (!name.isEmpty()) {
        return name;
    }
    return interface->text(QAccessible::Value, child);
}

QSpiObjectReference QSpiAdaptor::parent() const
{
    if (!checkInterface()) return QSpiObjectReference();
    return getParentReference();
}

QSpiObjectReference QSpiAdaptor::GetApplication() const
{
    if (!checkInterface()) return QSpiObjectReference();
    return spiBridge->getRootReference();
}

QSpiAttributeSet QSpiAdaptor::GetAttributes() const
{
    if (!checkInterface()) return QSpiAttributeSet();
    // No attributes interface in QAccessible so a blank list seems the sensible option.
    QSpiAttributeSet out0;
    return out0;
}

QSpiObjectReference QSpiAdaptor::GetChildAtIndex(int index) const
{
    if (!checkInterface()) return QSpiObjectReference();
    // if we are the child of a complex widget, we cannot have any children
    Q_ASSERT(child == 0);
    Q_ASSERT(index < interface->childCount());
    QSpiAdaptor* child = getChild(index+1);
    if (!child) {
        qWarning() << "WARNING:QSpiAdaptor::GetChildAtIndex no child: " << index << getReference().path.path() << interface->object();
        return QSpiObjectReference();
    }
    return child->getReference();
}

QSpiObjectReferenceArray QSpiAdaptor::GetChildren() const
{
    QList<QSpiObjectReference> children;
    if (!checkInterface()) return children;

    // TODO: become independent of caching the interfaces...
    //    QPair<QAccessibleInterface*, int> pair = QSpiAccessible::interfaceFromPath(getReference().path.path());
//    qDebug() << "CHILDREN: " << getReference().path.path();

    // when we are a child that means that we cannot have children of our own
    if (child) {
        QAccessibleInterface *iface;
        interface->navigate(QAccessible::Ancestor, 1, &iface);
        qWarning() << "WARNING:QSpiAdaptor::GetChildren Request child of virtual child: "
                   << getReference().path.path() << interface->object() << "child: " << childIndex() << " parent: " << iface->object();
        delete iface;
        return children;
    }

    for (int i = 1; i <= interface->childCount(); ++i) {
        QSpiAdaptor* child = getChild(i);
        if (child)
            children << child->getReference();

//        // use navigate and return refernces
//        QAccessibleInterface* childInterface;
//        int childIndex = interface->navigate(QAccessible::Child, i, &childInterface);
//        QString path;
//        if (childIndex) {
//            path = QSpiAccessible::pathForInterface(interface, childIndex);
//        } else {
//            Q_ASSERT(childInterface);
//            path = QSpiAccessible::pathForInterface(childInterface, childIndex);
//        }
//        qDebug() << "   CHILD: " << path;
//        children.append(QSpiObjectReference(spiBridge->dBusConnection(), QDBusObjectPath(path)));
    }

    Q_ASSERT(interface->childCount() == children.count());

    return children;
}

QSpiAdaptor* QSpiAdaptor::getChild(int index) const
{
    Q_ASSERT(index > 0 && index <= interface->childCount());
    QAccessibleInterface *child = 0;
    int ret = interface->navigate(QAccessible::Child, index, &child);
    if (ret == 0) {
        return spiBridge->interfaceToAccessible(child, 0, true);
    } else if (ret > 0){
        Q_ASSERT(ret <= interface->childCount());<commit_msg>Do not crash when interface->childCount() != children.count().<commit_after>/*
 * D-Bus AT-SPI, Qt Adaptor
 *
 * Copyright 2009-2011 Nokia Corporation and/or its subsidiary(-ies).
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */


#include <QtCore/QMetaObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>

#include <QAccessibleTextInterface>
#include <QAccessibleEditableTextInterface>
#include <QAccessibleTableInterface>
#include <QAccessibleActionInterface>
#include <QAccessibleValueInterface>

#include <QtCore/QtDebug>
#include <QtGui/QApplication>
#include <QtGui/QWidget>

#include "accessible.h"
#include "adaptor.h"
#include "bridge.h"
#include "constant_mappings.h"


QSpiAdaptor::QSpiAdaptor(QAccessibleInterface *interface_, int child)
    : interface(interface_), child(child)
{
}

QObject* QSpiAdaptor::getObject() const
{
    return interface->object();
}

QSpiObjectReference QSpiAdaptor::getReference() const
{
    return reference;
}

QStringList QSpiAdaptor::getSupportedInterfaces() const
{
    return supportedInterfaces;
}

bool QSpiAdaptor::checkInterface() const
{
    // The interface can be deleted behind our back with no notification.
    if (!interface->isValid()) {
        spiBridge->removeAdaptor(const_cast<QSpiAdaptor*>(this));
        return false;
    }
    return true;
}

QSpiAccessibleCacheItem QSpiAdaptor::getCacheItem() const
{
    Q_ASSERT(interface);
    if (!interface->isValid()) {
        qWarning() << "QSpiObject::getCacheItem: invalid interface" << reference.path.path();
        return QSpiAccessibleCacheItem();
    }

    QSpiAccessibleCacheItem item;
    item.path = getReference();
    item.parent = getParentReference();
    item.application = spiBridge->getRootReference();
    item.children = GetChildren();
    item.supportedInterfaces = getSupportedInterfaces();
    item.name = interface->text(QAccessible::Name, child);
    item.role = qSpiRoleMapping.value(interface->role(child)).spiRole();
    item.description = interface->text(QAccessible::Description, child);
    item.state = GetState();
    return item;
}

void QSpiAdaptor::signalChildrenChanged(const QString &type, int detail1, int detail2, const QDBusVariant &data)
{
    emit ChildrenChanged(type, detail1, detail2, data, spiBridge->getRootReference());
}

int QSpiAdaptor::childCount() const
{
    if (!checkInterface()) return 0;

    if (child)
        return 0;
    return interface->childCount();
}

QString QSpiAdaptor::description() const
{
    if (!checkInterface()) return QString();
    return interface->text(QAccessible::Description, child);
}

QString QSpiAdaptor::name() const
{
    if (!checkInterface()) return QString();
    QString name = interface->text(QAccessible::Name, child);
    if (!name.isEmpty()) {
        return name;
    }
    return interface->text(QAccessible::Value, child);
}

QSpiObjectReference QSpiAdaptor::parent() const
{
    if (!checkInterface()) return QSpiObjectReference();
    return getParentReference();
}

QSpiObjectReference QSpiAdaptor::GetApplication() const
{
    if (!checkInterface()) return QSpiObjectReference();
    return spiBridge->getRootReference();
}

QSpiAttributeSet QSpiAdaptor::GetAttributes() const
{
    if (!checkInterface()) return QSpiAttributeSet();
    // No attributes interface in QAccessible so a blank list seems the sensible option.
    QSpiAttributeSet out0;
    return out0;
}

QSpiObjectReference QSpiAdaptor::GetChildAtIndex(int index) const
{
    if (!checkInterface()) return QSpiObjectReference();
    // if we are the child of a complex widget, we cannot have any children
    Q_ASSERT(child == 0);
    Q_ASSERT(index < interface->childCount());
    QSpiAdaptor* child = getChild(index+1);
    if (!child) {
        qWarning() << "WARNING:QSpiAdaptor::GetChildAtIndex no child: " << index << getReference().path.path() << interface->object();
        return QSpiObjectReference();
    }
    return child->getReference();
}

QSpiObjectReferenceArray QSpiAdaptor::GetChildren() const
{
    QList<QSpiObjectReference> children;
    if (!checkInterface()) return children;

    // TODO: become independent of caching the interfaces...
    //    QPair<QAccessibleInterface*, int> pair = QSpiAccessible::interfaceFromPath(getReference().path.path());
//    qDebug() << "CHILDREN: " << getReference().path.path();

    // when we are a child that means that we cannot have children of our own
    if (child) {
        QAccessibleInterface *iface;
        interface->navigate(QAccessible::Ancestor, 1, &iface);
        qWarning() << "WARNING:QSpiAdaptor::GetChildren Request child of virtual child: "
                   << getReference().path.path() << interface->object() << "child: " << childIndex() << " parent: " << iface->object();
        delete iface;
        return children;
    }

    for (int i = 1; i <= interface->childCount(); ++i) {
        QSpiAdaptor* child = getChild(i);
        if (child)
            children << child->getReference();

//        // use navigate and return refernces
//        QAccessibleInterface* childInterface;
//        int childIndex = interface->navigate(QAccessible::Child, i, &childInterface);
//        QString path;
//        if (childIndex) {
//            path = QSpiAccessible::pathForInterface(interface, childIndex);
//        } else {
//            Q_ASSERT(childInterface);
//            path = QSpiAccessible::pathForInterface(childInterface, childIndex);
//        }
//        qDebug() << "   CHILD: " << path;
//        children.append(QSpiObjectReference(spiBridge->dBusConnection(), QDBusObjectPath(path)));
    }

//    Q_ASSERT(interface->childCount() == children.count());
    if (interface->childCount() != children.count()) {
        qWarning() << "WARNING: Widget reports more children than it has. This will lead to inconsistent behavior."
                   << interface->object() << qSpiRoleMapping[interface->role(child)].name() << getReference().path.path();
    }


    return children;
}

QSpiAdaptor* QSpiAdaptor::getChild(int index) const
{
    Q_ASSERT(index > 0 && index <= interface->childCount());
    QAccessibleInterface *child = 0;
    int ret = interface->navigate(QAccessible::Child, index, &child);
    if (ret == 0) {
        return spiBridge->interfaceToAccessible(child, 0, true);
    } else if (ret > 0){
        Q_ASSERT(ret <= interface->childCount());
{'fraction_non_alphanumeric': 0.1264101822389355, 'fraction_numerical': 0.0039051200462829044, 'mean_word_length': 3.9126110124333926, 'pattern_counts': {'":': 0, '<': 129, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '457021', 'n_tokens_mistral': 4141, 'n_tokens_neox': 4016, 'n_words': 1051}