diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/plugins/accessible/widgets/complexwidgets.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/plugins/accessible/widgets/complexwidgets.cpp')
-rw-r--r-- | src/plugins/accessible/widgets/complexwidgets.cpp | 2163 |
1 files changed, 2163 insertions, 0 deletions
diff --git a/src/plugins/accessible/widgets/complexwidgets.cpp b/src/plugins/accessible/widgets/complexwidgets.cpp new file mode 100644 index 0000000..68ca02b --- /dev/null +++ b/src/plugins/accessible/widgets/complexwidgets.cpp @@ -0,0 +1,2163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "complexwidgets.h" + +#include <qapplication.h> +#include <qabstractbutton.h> +#include <qevent.h> +#include <qheaderview.h> +#include <qtabbar.h> +#include <qcombobox.h> +#include <qlistview.h> +#include <qtableview.h> +#include <qlineedit.h> +#include <qstyle.h> +#include <qstyleoption.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qtreeview.h> +#include <private/qtabbar_p.h> +#include <QAbstractScrollArea> +#include <QScrollArea> +#include <QScrollBar> +#include <QDebug> + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); + +#ifndef QT_NO_ITEMVIEWS +/* +The MSDN article "Exposing Data Tables through Microsoft Active Accessibility" explains +how data tables should be exposed. Url: http://msdn2.microsoft.com/en-us/library/ms971325.aspx +Basically, the model is like this: + +ROLE_SYSTEM_TABLE + |- ROLE_SYSTEM_ROW + | |- ROLE_SYSTEM_ROWHEADER + | |- ROLE_SYSTEM_COLUMNHEADER + | |- ROLE_SYSTEM_COLUMNHEADER + | |- ROLE_SYSTEM_COLUMNHEADER + | '- .. + |- ROLE_SYSTEM_ROW + | |- ROLE_SYSTEM_ROWHEADER + | |- ROLE_SYSTEM_CELL + | |- ROLE_SYSTEM_CELL + | |- ROLE_SYSTEM_CELL + | '- .. + |- ROLE_SYSTEM_ROW + | |- ROLE_SYSTEM_ROWHEADER + | |- ROLE_SYSTEM_CELL + | |- ROLE_SYSTEM_CELL + | |- ROLE_SYSTEM_CELL + | '- .. + '- .. + +The headers of QTreeView is also represented like this. +*/ +QAccessibleItemRow::QAccessibleItemRow(QAbstractItemView *aView, const QModelIndex &index, bool isHeader) + : row(index), view(aView), m_header(isHeader) +{ +} + +QHeaderView *QAccessibleItemRow::horizontalHeader() const +{ + QHeaderView *header = 0; + if (m_header) { + if (false) { +#ifndef QT_NO_TABLEVIEW + } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) { + header = tv->horizontalHeader(); +#endif +#ifndef QT_NO_TREEVIEW + } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) { + header = tv->header(); +#endif + } + } + return header; +} + +QHeaderView *QAccessibleItemRow::verticalHeader() const +{ + QHeaderView *header = 0; +#ifndef QT_NO_TABLEVIEW + if (const QTableView *tv = qobject_cast<const QTableView*>(view)) + header = tv->verticalHeader(); +#endif + return header; +} + +int QAccessibleItemRow::logicalFromChild(QHeaderView *header, int child) const +{ + int logical = -1; + if (header->sectionsHidden()) { + int kid = 0; + for (int i = 0; i < header->count(); ++i) { + if (!header->isSectionHidden(i)) + ++kid; + if (kid == child) { + logical = i; + break; + } + } + } else { + logical = child - 1; + } + return logical; +} + +QRect QAccessibleItemRow::rect(int child) const +{ + QRect r; + if (view && view->isVisible()) { + if (QHeaderView *header = horizontalHeader()) { + if (!child) { + r = header->rect(); + } else { + if (QHeaderView *vheader = verticalHeader()) { + if (child == 1) { + int w = vheader->width(); + int h = header->height(); + r.setRect(0, 0, w, h); + } + --child; + } + if (child) { + int logical = logicalFromChild(header, child); + int w = header->sectionSize(logical); + r.setRect(header->sectionViewportPosition(logical), 0, w, header->height()); + r.translate(header->mapTo(view, QPoint(0, 0))); + } + } + } else if (row.isValid()) { + if (!child) { + QModelIndex parent = row.parent(); + const int colCount = row.model()->columnCount(parent); + for (int i = 0; i < colCount; ++i) + r |= view->visualRect(row.model()->index(row.row(), i, parent)); + r.translate(view->viewport()->mapTo(view, QPoint(0,0))); + + if (const QHeaderView *vheader = verticalHeader()) { // include the section of the vertical header + QRect re; + int logicalRow = row.row(); + int h = vheader->sectionSize(logicalRow); + re.setRect(0, vheader->sectionViewportPosition(logicalRow), vheader->width(), h); + re.translate(vheader->mapTo(view, QPoint(0, 0))); + r |= re; + } + } else { + if (QHeaderView *vheader = verticalHeader()) { + if (child == 1) { + int logicalRow = row.row(); + int h = vheader->sectionSize(logicalRow); + r.setRect(0, vheader->sectionViewportPosition(logicalRow), vheader->width(), h); + r.translate(vheader->mapTo(view, QPoint(0, 0))); + } + --child; + } + if (child) { + r = view->visualRect(childIndex(child)); + r.translate(view->viewport()->mapTo(view, QPoint(0,0))); + } + } + } + } + if (!r.isNull()) + r.translate(view->mapToGlobal(QPoint(0, 0))); + + return r; +} + +int QAccessibleItemRow::treeLevel() const +{ + int level = 0; + QModelIndex idx = row; + while (idx.isValid()) { + idx = idx.parent(); + ++level; + } + return level; +} + +QString QAccessibleItemRow::text_helper(int child) const +{ + QString value; + if (m_header) { + if (!child) + return QString(); + if (verticalHeader()) { + if (child == 1) + return QString(); + --child; + } + QHeaderView *header = horizontalHeader(); + int logical = logicalFromChild(header, child); + value = view->model()->headerData(logical, Qt::Horizontal, Qt::AccessibleTextRole).toString(); + if (value.isEmpty()) + value = view->model()->headerData(logical, Qt::Horizontal).toString(); + return value; + } else { + if (!child) { // for one-column views (i.e. QListView) + if (children().count() >= 1) + child = 1; + else + return QString(); + } + if (verticalHeader()) { + if (child == 1) { + int logical = row.row(); + value = view->model()->headerData(logical, Qt::Vertical, Qt::AccessibleTextRole).toString(); + if (value.isEmpty()) + value = view->model()->headerData(logical, Qt::Vertical).toString(); + return value; + } else { + --child; + } + } + } + if (value.isEmpty()) { + QModelIndex idx = childIndex(child); + if (idx.isValid()) { + value = idx.model()->data(idx, Qt::AccessibleTextRole).toString(); + if (value.isEmpty()) + value = idx.model()->data(idx, Qt::DisplayRole).toString(); + } + } + return value; +} + +QString QAccessibleItemRow::text(Text t, int child) const +{ + QString value; + if (t == Name) { + value = text_helper(child); + } else if (t == Value) { +#ifndef QT_NO_TREEVIEW + if (qobject_cast<const QTreeView*>(view)) { + if (child == 0) + value = QString::number(treeLevel()); + } else +#endif + { + value = text_helper(child); + } + } else if (t == Description) { +#ifndef QT_NO_TREEVIEW + if (child == 0 && qobject_cast<const QTreeView*>(view)) { + // We store the tree coordinates of the current item in the description. + // This enables some screen readers to report where the focus is + // in a tree view. (works in JAWS). Also, Firefox does the same thing. + // For instance the description "L2, 4 of 25 with 24" means + // "L2": Tree Level 2 + // "4 of 25": We are item 4 out of in total 25 other siblings + // "with 24": We have 24 children. (JAWS does not read this number) + + // level + int level = treeLevel(); + + QAbstractItemModel *m = view->model(); + // totalSiblings and itemIndex + QModelIndex parent = row.parent(); + int rowCount = m->rowCount(parent); + int itemIndex = -1; + int totalSiblings = 0; + for (int i = 0 ; i < rowCount; ++i) { + QModelIndex sibling = row.sibling(i, 0); + if (!view->isIndexHidden(sibling)) + ++totalSiblings; + if (row == sibling) + itemIndex = totalSiblings; + } + int totalChildren = m->rowCount(row); // JAWS does not report child count, so we do + // this simple and efficient. + // (don't check if they are all visible). + value = QString::fromAscii("L%1, %2 of %3 with %4").arg(level).arg(itemIndex).arg(totalSiblings).arg(totalChildren); + } else +#endif // QT_NO_TREEVIEW + { + if (!m_header) { + if (child == 0 && children().count() >= 1) + child = 1; + if (verticalHeader()) { + if (child == 1) { + value = view->model()->headerData(row.row(), Qt::Vertical).toString(); + } + --child; + } + if (child) { + QModelIndex idx = childIndex(child); + value = idx.model()->data(idx, Qt::AccessibleDescriptionRole).toString(); + } + + } + } + } + return value; +} + +void QAccessibleItemRow::setText(Text t, int child, const QString &text) +{ + if (m_header) { + if (child) + view->model()->setHeaderData(child - 1, Qt::Horizontal, text); + // child == 0 means the cell to the left of the horizontal header, which is empty!? + } else { + if (!child) { + if (children().count() == 1) + child = 1; + else + return; + } + + if (verticalHeader()) { + if (child == 1) { + view->model()->setHeaderData(row.row(), Qt::Vertical, text); + return; + } + --child; + } + QModelIndex idx = childIndex(child); + if (!idx.isValid()) + return; + + switch (t) { + case Description: + const_cast<QAbstractItemModel *>(idx.model())->setData(idx, text, + Qt::AccessibleDescriptionRole); + break; + case Value: + const_cast<QAbstractItemModel *>(idx.model())->setData(idx, text, Qt::EditRole); + break; + default: + break; + } + } +} + +QModelIndex QAccessibleItemRow::childIndex(int child) const +{ + QList<QModelIndex> kids = children(); + Q_ASSERT(child >= 1 && child <= kids.count()); + return kids.at(child - 1); +} + +QList<QModelIndex> QAccessibleItemRow::children() const +{ + QList<QModelIndex> kids; + for (int i = 0; i < row.model()->columnCount(row.parent()); ++i) { + QModelIndex idx = row.model()->index(row.row(), i, row.parent()); + if (!view->isIndexHidden(idx)) { + kids << idx; + } + } + return kids; +} + +bool QAccessibleItemRow::isValid() const +{ + return m_header ? true : row.isValid(); +} + +QObject *QAccessibleItemRow::object() const +{ + return 0; +} + +int QAccessibleItemRow::childCount() const +{ + int count = 0; + if (QHeaderView *header = horizontalHeader()) { + count = header->count() - header->hiddenSectionCount(); + } else { + count = children().count(); + } +#ifndef QT_NO_TABLEVIEW + if (qobject_cast<const QTableView*>(view)) { + if (verticalHeader()) + ++count; + } +#endif + return count; +} + +int QAccessibleItemRow::indexOfChild(const QAccessibleInterface *iface) const +{ + if (!iface || iface->role(0) != Row) + return -1; + + //### meaningless code? + QList<QModelIndex> kids = children(); + QModelIndex idx = static_cast<const QAccessibleItemRow *>(iface)->row; + if (!idx.isValid()) + return -1; + return kids.indexOf(idx) + 1; +} + +QAccessible::Relation QAccessibleItemRow::relationTo(int child, const QAccessibleInterface *other, + int otherChild) const +{ + if (!child && !otherChild && other->object() == view) + return Child; + if (!child && !otherChild && other == this) + return Self; + if (!child && otherChild && other == this) + return Ancestor; + if (child && otherChild && other == this) + return Sibling; + return Unrelated; +} + +int QAccessibleItemRow::childAt(int x, int y) const +{ + if (!view || !view->isVisible()) + return -1; + + for (int i = childCount(); i >= 0; --i) { + if (rect(i).contains(x, y)) + return i; + } + return -1; +} + +QAbstractItemView::CursorAction QAccessibleItemRow::toCursorAction( + QAccessible::Relation rel) +{ + switch (rel) { + case QAccessible::Up: + return QAbstractItemView::MoveUp; + case QAccessible::Down: + return QAbstractItemView::MoveDown; + case QAccessible::Left: + return QAbstractItemView::MoveLeft; + case QAccessible::Right: + return QAbstractItemView::MoveRight; + default: + Q_ASSERT(false); + } + // should never be reached. + return QAbstractItemView::MoveRight; +} + +int QAccessibleItemRow::navigate(RelationFlag relation, int index, + QAccessibleInterface **iface) const +{ + *iface = 0; + if (!view) + return -1; + + switch (relation) { + case Ancestor: { + if (!index) + return -1; + QAccessibleItemView *ancestor = new QAccessibleItemView(view->viewport()); + if (index == 1) { + *iface = ancestor; + return 0; + } else if (index > 1) { + int ret = ancestor->navigate(Ancestor, index - 1, iface); + delete ancestor; + return ret; + } + } + case Child: { + if (!index) + return -1; + if (index < 1 && index > childCount()) + return -1; + + return index;} + case Sibling: + if (index) { + QAccessibleInterface *ifaceParent = 0; + navigate(Ancestor, 1, &ifaceParent); + if (ifaceParent) { + int entry = ifaceParent->navigate(Child, index, iface); + delete ifaceParent; + return entry; + } + } + return -1; + 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 = new QAccessibleItemRow(view, idx); + return index ? kids.indexOf(idx) + 1 : 0; } + default: + break; + } + + return -1; +} + +QAccessible::Role QAccessibleItemRow::role(int child) const +{ + if (false) { +#ifndef QT_NO_TREEVIEW + } else if (qobject_cast<const QTreeView*>(view)) { + if (horizontalHeader()) { + if (!child) + return Row; + return ColumnHeader; + } + return TreeItem; +#endif +#ifndef QT_NO_LISTVIEW + } else if (qobject_cast<const QListView*>(view)) { + return ListItem; +#endif +#ifndef QT_NO_TABLEVIEW + } else if (qobject_cast<const QTableView *>(view)) { + if (!child) + return Row; + if (child == 1) { + if (verticalHeader()) + return RowHeader; + } + if (m_header) + return ColumnHeader; +#endif + } + return Cell; +} + +QAccessible::State QAccessibleItemRow::state(int child) const +{ + State st = Normal; + + if (!view) + return st; + + QAccessibleInterface *parent = 0; + QRect globalRect; + if (navigate(Ancestor, 1, &parent) == 0) { + globalRect = parent->rect(0); + delete parent; + } + if (!globalRect.intersects(rect(child))) + st |= Invisible; + + if (!horizontalHeader()) { + if (!(st & Invisible)) { + if (child) { + if (QHeaderView *vheader = verticalHeader() ) { + if (child == 1) { + if (!vheader->isVisible()) + st |= Invisible; + } + --child; + } + if (child) { + QModelIndex idx = childIndex(child); + if (!idx.isValid()) + return st; + + if (view->selectionModel()->isSelected(idx)) + st |= Selected; + if (view->selectionModel()->currentIndex() == idx) + st |= Focused; + if (idx.model()->data(idx, Qt::CheckStateRole).toInt() == Qt::Checked) + st |= Checked; + + Qt::ItemFlags flags = idx.flags(); + if (flags & Qt::ItemIsSelectable) { + st |= Selectable; + if (view->selectionMode() == QAbstractItemView::MultiSelection) + st |= MultiSelectable; + if (view->selectionMode() == QAbstractItemView::ExtendedSelection) + st |= ExtSelectable; + } + } + } else { + Qt::ItemFlags flags = row.flags(); + if (flags & Qt::ItemIsSelectable) { + st |= Selectable; + st |= Focusable; + } + if (view->selectionModel()->isRowSelected(row.row(), row.parent())) + st |= Selected; + if (view->selectionModel()->currentIndex().row() == row.row()) + st |= Focused; + } + } + } + + return st; +} + +int QAccessibleItemRow::userActionCount(int) const +{ + return 0; +} + +QString QAccessibleItemRow::actionText(int, Text, int) const +{ + return QString(); +} + +static QItemSelection rowAt(const QModelIndex &idx) +{ + return QItemSelection(idx.sibling(idx.row(), 0), + idx.sibling(idx.row(), idx.model()->columnCount(idx.parent()))); +} + +bool QAccessibleItemRow::doAction(int action, int child, const QVariantList & /*params*/) +{ + if (!view) + return false; + + if (verticalHeader()) + --child; + + QModelIndex idx = child ? childIndex(child) : QModelIndex(row); + if (!idx.isValid()) + return false; + + QItemSelectionModel::SelectionFlags command = QItemSelectionModel::NoUpdate; + + switch (action) { + case SetFocus: + view->setCurrentIndex(idx); + return true; + case ExtendSelection: + if (!child) + return false; + view->selectionModel()->select(QItemSelection(view->currentIndex(), idx), + QItemSelectionModel::SelectCurrent); + return true; + case Select: + command = QItemSelectionModel::ClearAndSelect; + break; + case ClearSelection: + command = QItemSelectionModel::Clear; + break; + case RemoveSelection: + command = QItemSelectionModel::Deselect; + break; + case AddToSelection: + command = QItemSelectionModel::SelectCurrent; + break; + } + if (command == QItemSelectionModel::NoUpdate) + return false; + + if (child) + view->selectionModel()->select(idx, command); + else + view->selectionModel()->select(rowAt(row), command); + return true; +} + +class ModelIndexIterator +{ +public: + ModelIndexIterator(QAbstractItemView *view, const QModelIndex &start = QModelIndex()) : m_view(view) + { +#ifndef QT_NO_LISTVIEW + list = qobject_cast<QListView*>(m_view); +#endif +#ifndef QT_NO_TREEVIEW + tree = qobject_cast<QTreeView*>(m_view); +#endif +#ifndef QT_NO_TABLEVIEW + table = qobject_cast<QTableView*>(m_view); +#endif + if (start.isValid()) { + m_current = start; + } else if (m_view && m_view->model()) { + m_current = view->model()->index(0, 0); + } + } + + bool next(int count = 1) { + for (int i = 0; i < count; ++i) { + do { + if (m_current.isValid()) { + const QAbstractItemModel *m = m_current.model(); +#ifndef QT_NO_TREEVIEW + if (tree && m_current.model()->hasChildren(m_current) && tree->isExpanded(m_current)) { + m_current = m_current.child(0, 0); + } else +#endif + { + int row = m_current.row(); + QModelIndex par = m_current.parent(); + + // Go up to the parent if we reach the end of the rows + // If m_curent becomses invalid, stop going up. + while (row + 1 >= m->rowCount(par)) { + m_current = par; + if (m_current.isValid()) { + row = m_current.row(); + par = m_current.parent(); + } else { + row = 0; + par = QModelIndex(); + break; + } + } + + if (m_current.isValid()) + m_current = m_current.sibling(row + 1, 0); + } + } + } while (isHidden()); + } + return m_current.isValid(); + } + + bool isHidden() const { + if (false) { +#ifndef QT_NO_LISTVIEW + } else if (list) { + return list->isRowHidden(m_current.row()); +#endif +#ifndef QT_NO_TREEVIEW + } else if (tree) { + return tree->isRowHidden(m_current.row(), m_current.parent()); +#endif +#ifndef QT_NO_TABLEVIEW + } else if (table) { + return table->isRowHidden(m_current.row()); +#endif + } + return false; + } + + QModelIndex current() const { + return m_current; + } + +private: + QModelIndex m_current; + QAbstractItemView *m_view; + +#ifndef QT_NO_TREEVIEW + QTreeView *tree; +#endif +#ifndef QT_NO_LISTVIEW + QListView *list; +#endif +#ifndef QT_NO_TABLEVIEW + QTableView *table; +#endif +}; + +QAccessibleItemView::QAccessibleItemView(QWidget *w) + : QAccessibleAbstractScrollArea(w->objectName() == QLatin1String("qt_scrollarea_viewport") ? w->parentWidget() : w) +{ + atVP = w->objectName() == QLatin1String("qt_scrollarea_viewport"); + +} + + +QHeaderView *QAccessibleItemView::horizontalHeader() const +{ + QHeaderView *header = 0; + if (false) { +#ifndef QT_NO_TABLEVIEW + } else if (const QTableView *tv = qobject_cast<const QTableView*>(itemView())) { + header = tv->horizontalHeader(); +#endif +#ifndef QT_NO_TREEVIEW + } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(itemView())) { + header = tv->header(); +#endif + } + return header; +} + +QHeaderView *QAccessibleItemView::verticalHeader() const +{ + QHeaderView *header = 0; + if (false) { +#ifndef QT_NO_TABLEVIEW + } else if (const QTableView *tv = qobject_cast<const QTableView*>(itemView())) { + header = tv->verticalHeader(); +#endif + } + return header; +} + + +bool QAccessibleItemView::isValidChildRole(QAccessible::Role role) const +{ + if (atViewport()) { + if (false) { +#ifndef QT_NO_TREEVIEW + } else if (qobject_cast<const QTreeView*>(itemView())) { + return (role == TreeItem || role == Row); +#endif +#ifndef QT_NO_LISTVIEW + } else if (qobject_cast<const QListView*>(itemView())) { + return (role == ListItem); +#endif + } + // TableView + return role == Row; + } else { + if (false) { +#ifndef QT_NO_TREEVIEW + } else if (qobject_cast<const QTreeView*>(itemView())) { + return (role == Tree); +#endif +#ifndef QT_NO_LISTVIEW + } else if (qobject_cast<const QListView*>(itemView())) { + return (role == List); +#endif + } + // TableView + return (role == Table); + } +} + +QObject *QAccessibleItemView::object() const +{ + QObject *view = QAccessibleAbstractScrollArea::object(); + Q_ASSERT(qobject_cast<const QAbstractItemView *>(view)); + if (atViewport()) + view = qobject_cast<const QAbstractItemView *>(view)->viewport(); + return view; +} + +QAbstractItemView *QAccessibleItemView::itemView() const +{ + return qobject_cast<QAbstractItemView *>(QAccessibleAbstractScrollArea::object()); +} + +int QAccessibleItemView::indexOfChild(const QAccessibleInterface *iface) const +{ + if (atViewport()) { + if (!iface || !isValidChildRole(iface->role(0))) + return -1; + + int entry = -1; + // ### This will fail if a row is hidden. + const QAccessibleItemRow *ifRow = static_cast<const QAccessibleItemRow *>(iface); + if (ifRow->horizontalHeader()) + return 1; + + QModelIndex idx = ifRow->row; + if (!idx.isValid()) + return -1; + + entry = entryFromIndex(idx); + if (horizontalHeader()) + ++entry; + + return entry; + + } else { + return QAccessibleAbstractScrollArea::indexOfChild(iface); + } +} + +QModelIndex QAccessibleItemView::childIndex(int child) const +{ + if (!atViewport()) + return QModelIndex(); + ModelIndexIterator it(itemView()); + it.next(child - 1); + return it.current(); +} + +int QAccessibleItemView::entryFromIndex(const QModelIndex &index) const +{ + int entry = -1; + if (false) { +#ifndef QT_NO_TREEVIEW + } else if (QTreeView *tree = qobject_cast<QTreeView*>(itemView())) { + entry = tree->visualIndex(index) + 1; +#endif +#ifndef QT_NO_LISTVIEW + } else if (QListView *list = qobject_cast<QListView*>(itemView())) { + entry = list->visualIndex(index) + 1; +#endif +#ifndef QT_NO_TABLEVIEW + } else if (QTableView *table = qobject_cast<QTableView*>(itemView())) { + entry = table->visualIndex(index) + 1; +#endif + } + return entry; +} + +int QAccessibleItemView::childCount() const +{ + if (atViewport()) { + if (itemView()->model() == 0) + return 0; + QAbstractItemModel *m = itemView()->model(); + QModelIndex idx = m->index(0,0); + if (!idx.isValid()) + return 0; + ModelIndexIterator it(itemView()); + int count = 1; + while (it.next()) { + ++count; + } + if (horizontalHeader()) + ++count; + + return count; + } else { + return QAccessibleAbstractScrollArea::childCount(); + } +} + +QString QAccessibleItemView::text(Text t, int child) const +{ + if (atViewport()) { + if (!child) + return QAccessibleAbstractScrollArea::text(t, child); + + QAccessibleItemRow item(itemView(), childIndex(child)); + return item.text(t, 1); + } else { + return QAccessibleAbstractScrollArea::text(t, child); + } +} + +void QAccessibleItemView::setText(Text t, int child, const QString &text) +{ + if (atViewport()) { + if (!child) { + QAccessibleAbstractScrollArea::setText(t, child, text); + return; + } + + QAccessibleItemRow item(itemView(), childIndex(child)); + item.setText(t, 1, text); + } else { + QAccessibleAbstractScrollArea::setText(t, child, text); + } +} + +QRect QAccessibleItemView::rect(int child) const +{ + if (atViewport()) { + QRect r; + if (!child) { + // Make sure that the rect *include* the vertical and horizontal headers, while + // not including the potential vertical and horizontal scrollbars. + QAbstractItemView *w = itemView(); + + int vscrollWidth = 0; + const QScrollBar *sb = w->verticalScrollBar(); + if (sb && sb->isVisible()) + vscrollWidth = sb->width(); + + int hscrollHeight = 0; + sb = w->horizontalScrollBar(); + if (sb && sb->isVisible()) + hscrollHeight = sb->height(); + + QPoint globalPos = w->mapToGlobal(QPoint(0,0)); + r = w->rect().translated(globalPos); + if (w->isRightToLeft()) { + r.adjust(vscrollWidth, 0, 0, -hscrollHeight); + } else { + r.adjust(0, 0, -vscrollWidth, -hscrollHeight); + } + } else { + QAccessibleInterface *iface = 0; + if (navigate(Child, child, &iface) == 0) { + r = iface->rect(0); + delete iface; + } + } + return r; + } else { + QRect r = QAccessibleAbstractScrollArea::rect(child); + if (child == 1) { + // include the potential vertical and horizontal headers + + const QHeaderView *header = verticalHeader(); + int headerWidth = (header && header->isVisible()) ? header->width() : 0; + header = horizontalHeader(); + int headerHeight= (header && header->isVisible()) ? header->height() : 0; + if (itemView()->isRightToLeft()) { + r.adjust(0, -headerHeight, headerWidth, 0); + } else { + r.adjust(-headerWidth, -headerHeight, 0, 0); + } + } + return r; + } +} + +int QAccessibleItemView::childAt(int x, int y) const +{ + if (atViewport()) { + QPoint p(x, y); + for (int i = childCount(); i >= 0; --i) { + if (rect(i).contains(p)) + return i; + } + return -1; + } else { + return QAccessibleAbstractScrollArea::childAt(x, y); + } +} + +QAccessible::Role QAccessibleItemView::role(int child) const +{ + if ((!atViewport() && child) || (atViewport() && child == 0)) { + QAbstractItemView *view = itemView(); +#ifndef QT_NO_TABLEVIEW + if (qobject_cast<QTableView *>(view)) + return Table; +#endif +#ifndef QT_NO_LISTVIEW + if (qobject_cast<QListView *>(view)) + return List; +#endif + return Tree; + } + if (atViewport()) { + if (child) + return Row; + } + + return QAccessibleAbstractScrollArea::role(child); +} + +QAccessible::State QAccessibleItemView::state(int child) const +{ + State st = Normal; + + if (itemView() == 0) + return State(Unavailable); + + bool queryViewPort = (atViewport() && child == 0) || (!atViewport() && child == 1); + if (queryViewPort) { + if (itemView()->selectionMode() != QAbstractItemView::NoSelection) { + st |= Selectable; + st |= Focusable; + } + } else if (atViewport()) { // children of viewport + if (horizontalHeader()) + --child; + if (child) { + QAccessibleItemRow item(itemView(), childIndex(child)); + st |= item.state(0); + } + } else if (!atViewport() && child != 1) { + st = QAccessibleAbstractScrollArea::state(child); + } + return st; +} + +bool QAccessibleItemView::isValid() const +{ + if (atViewport()) + return QAccessibleWidgetEx::isValid(); + else + return QAccessibleAbstractScrollArea::isValid(); +} + +int QAccessibleItemView::navigate(RelationFlag relation, int index, + QAccessibleInterface **iface) const +{ + if (atViewport()) { + if (relation == Ancestor && index == 1) { + *iface = new QAccessibleItemView(itemView()); + return 0; + } else if (relation == Child && index >= 1) { + if (horizontalHeader()) { + if (index == 1) { + *iface = new QAccessibleItemRow(itemView(), QModelIndex(), true); + return 0; + } + --index; + } + + //###JAS hidden rows.. + QModelIndex idx = childIndex(index); + if (idx.isValid()) { + *iface = new QAccessibleItemRow(itemView(), idx); + return 0; + } + } else if (relation == Sibling && index >= 1) { + QAccessibleInterface *parent = new QAccessibleItemView(itemView()); + return parent->navigate(Child, index, iface); + } + *iface = 0; + return -1; + } else { + return QAccessibleAbstractScrollArea::navigate(relation, index, iface); + } +} + +/* returns the model index for a given row and column */ +QModelIndex QAccessibleItemView::index(int row, int column) const +{ + return itemView()->model()->index(row, column); +} + +QAccessibleInterface *QAccessibleItemView::accessibleAt(int row, int column) +{ + QWidget *indexWidget = itemView()->indexWidget(index(row, column)); + return QAccessible::queryAccessibleInterface(indexWidget); +} + +/* We don't have a concept of a "caption" in Qt's standard widgets */ +QAccessibleInterface *QAccessibleItemView::caption() +{ + return 0; +} + +/* childIndex is row * columnCount + columnIndex */ +int QAccessibleItemView::childIndex(int rowIndex, int columnIndex) +{ + return rowIndex * itemView()->model()->columnCount() + columnIndex; +} + +/* Return the header data as column description */ +QString QAccessibleItemView::columnDescription(int column) +{ + return itemView()->model()->headerData(column, Qt::Horizontal).toString(); +} + +/* We don't support column spanning atm */ +int QAccessibleItemView::columnSpan(int /* row */, int /* column */) +{ + return 1; +} + +/* Return the horizontal header view */ +QAccessibleInterface *QAccessibleItemView::columnHeader() +{ +#ifndef QT_NO_TREEVIEW + if (QTreeView *tree = qobject_cast<QTreeView *>(itemView())) + return QAccessible::queryAccessibleInterface(tree->header()); +#endif +#ifndef QT_NO_TABLEVIEW + if (QTableView *table = qobject_cast<QTableView *>(itemView())) + return QAccessible::queryAccessibleInterface(table->horizontalHeader()); +#endif + return 0; +} + +int QAccessibleItemView::columnIndex(int childIndex) +{ + int columnCount = itemView()->model()->columnCount(); + if (!columnCount) + return 0; + + return childIndex % columnCount; +} + +int QAccessibleItemView::columnCount() +{ + return itemView()->model()->columnCount(); +} + +int QAccessibleItemView::rowCount() +{ + return itemView()->model()->rowCount(); +} + +int QAccessibleItemView::selectedColumnCount() +{ + return itemView()->selectionModel()->selectedColumns().count(); +} + +int QAccessibleItemView::selectedRowCount() +{ + return itemView()->selectionModel()->selectedRows().count(); +} + +QString QAccessibleItemView::rowDescription(int row) +{ + return itemView()->model()->headerData(row, Qt::Vertical).toString(); +} + +/* We don't support row spanning */ +int QAccessibleItemView::rowSpan(int /*row*/, int /*column*/) +{ + return 1; +} + +QAccessibleInterface *QAccessibleItemView::rowHeader() +{ +#ifndef QT_NO_TABLEVIEW + if (QTableView *table = qobject_cast<QTableView *>(itemView())) + return QAccessible::queryAccessibleInterface(table->verticalHeader()); +#endif + return 0; +} + +int QAccessibleItemView::rowIndex(int childIndex) +{ + int columnCount = itemView()->model()->columnCount(); + if (!columnCount) + return 0; + + return int(childIndex / columnCount); +} + +int QAccessibleItemView::selectedRows(int maxRows, QList<int> *rows) +{ + Q_ASSERT(rows); + + const QModelIndexList selRows = itemView()->selectionModel()->selectedRows(); + int maxCount = qMin(selRows.count(), maxRows); + + for (int i = 0; i < maxCount; ++i) + rows->append(selRows.at(i).row()); + + return maxCount; +} + +int QAccessibleItemView::selectedColumns(int maxColumns, QList<int> *columns) +{ + Q_ASSERT(columns); + + const QModelIndexList selColumns = itemView()->selectionModel()->selectedColumns(); + int maxCount = qMin(selColumns.count(), maxColumns); + + for (int i = 0; i < maxCount; ++i) + columns->append(selColumns.at(i).row()); + + return maxCount; +} + +/* Qt widgets don't have a concept of a summary */ +QAccessibleInterface *QAccessibleItemView::summary() +{ + return 0; +} + +bool QAccessibleItemView::isColumnSelected(int column) +{ + return itemView()->selectionModel()->isColumnSelected(column, QModelIndex()); +} + +bool QAccessibleItemView::isRowSelected(int row) +{ + return itemView()->selectionModel()->isRowSelected(row, QModelIndex()); +} + +bool QAccessibleItemView::isSelected(int row, int column) +{ + return itemView()->selectionModel()->isSelected(index(row, column)); +} + +void QAccessibleItemView::selectRow(int row) +{ + QItemSelectionModel *s = itemView()->selectionModel(); + s->select(index(row, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows); +} + +void QAccessibleItemView::selectColumn(int column) +{ + QItemSelectionModel *s = itemView()->selectionModel(); + s->select(index(0, column), QItemSelectionModel::Select | QItemSelectionModel::Columns); +} + +void QAccessibleItemView::unselectRow(int row) +{ + QItemSelectionModel *s = itemView()->selectionModel(); + s->select(index(row, 0), QItemSelectionModel::Deselect | QItemSelectionModel::Rows); +} + +void QAccessibleItemView::unselectColumn(int column) +{ + QItemSelectionModel *s = itemView()->selectionModel(); + s->select(index(0, column), QItemSelectionModel::Deselect | QItemSelectionModel::Columns); +} + +void QAccessibleItemView::cellAtIndex(int index, int *row, int *column, int *rSpan, + int *cSpan, bool *isSelect) +{ + *row = rowIndex(index); + *column = columnIndex(index); + *rSpan = rowSpan(*row, *column); + *cSpan = columnSpan(*row, *column); + *isSelect = isSelected(*row, *column); +} + +/*! + \class QAccessibleHeader + \brief The QAccessibleHeader class implements the QAccessibleInterface for header widgets. + \internal + + \ingroup accessibility +*/ + +/*! + Constructs a QAccessibleHeader object for \a w. +*/ +QAccessibleHeader::QAccessibleHeader(QWidget *w) +: QAccessibleWidgetEx(w) +{ + Q_ASSERT(header()); + addControllingSignal(QLatin1String("sectionClicked(int)")); +} + +/*! Returns the QHeaderView. */ +QHeaderView *QAccessibleHeader::header() const +{ + return qobject_cast<QHeaderView*>(object()); +} + +/*! \reimp */ +QRect QAccessibleHeader::rect(int child) const +{ + if (!child) + return QAccessibleWidgetEx::rect(0); + + QHeaderView *h = header(); + QPoint zero = h->mapToGlobal(QPoint(0, 0)); + int sectionSize = h->sectionSize(child - 1); + int sectionPos = h->sectionPosition(child - 1); + return h->orientation() == Qt::Horizontal + ? QRect(zero.x() + sectionPos, zero.y(), sectionSize, h->height()) + : QRect(zero.x(), zero.y() + sectionPos, h->width(), sectionSize); +} + +/*! \reimp */ +int QAccessibleHeader::childCount() const +{ + return header()->count(); +} + +/*! \reimp */ +QString QAccessibleHeader::text(Text t, int child) const +{ + QString str; + + if (child > 0 && child <= childCount()) { + switch (t) { + case Name: + str = header()->model()->headerData(child - 1, header()->orientation()).toString(); + break; + case Description: { + QAccessibleEvent event(QEvent::AccessibilityDescription, child); + if (QApplication::sendEvent(widget(), &event)) + str = event.value(); + break; } + case Help: { + QAccessibleEvent event(QEvent::AccessibilityHelp, child); + if (QApplication::sendEvent(widget(), &event)) + str = event.value(); + break; } + default: + break; + } + } + if (str.isEmpty()) + str = QAccessibleWidgetEx::text(t, child); + return str; +} + +/*! \reimp */ +QAccessible::Role QAccessibleHeader::role(int) const +{ + return (header()->orientation() == Qt::Horizontal) ? ColumnHeader : RowHeader; +} + +/*! \reimp */ +QAccessible::State QAccessibleHeader::state(int child) const +{ + State state = QAccessibleWidgetEx::state(child); + + if (child) { + int section = child - 1; + if (header()->isSectionHidden(section)) + state |= Invisible; + if (header()->resizeMode(section) != QHeaderView::Custom) + state |= Sizeable; + } else { + if (header()->isMovable()) + state |= Movable; + } + if (!header()->isClickable()) + state |= Unavailable; + return state; +} +#endif // QT_NO_ITEMVIEWS + +#ifndef QT_NO_TABBAR +/*! + \class QAccessibleTabBar + \brief The QAccessibleTabBar class implements the QAccessibleInterface for tab bars. + \internal + + \ingroup accessibility +*/ + +/*! + Constructs a QAccessibleTabBar object for \a w. +*/ +QAccessibleTabBar::QAccessibleTabBar(QWidget *w) +: QAccessibleWidgetEx(w) +{ + Q_ASSERT(tabBar()); +} + +/*! Returns the QTabBar. */ +QTabBar *QAccessibleTabBar::tabBar() const +{ + return qobject_cast<QTabBar*>(object()); +} + +QAbstractButton *QAccessibleTabBar::button(int child) const +{ + if (child <= tabBar()->count()) + return 0; + QTabBarPrivate * const tabBarPrivate = tabBar()->d_func(); + if (child - tabBar()->count() == 1) + return tabBarPrivate->leftB; + if (child - tabBar()->count() == 2) + return tabBarPrivate->rightB; + Q_ASSERT(false); + return 0; +} + +/*! \reimp */ +QRect QAccessibleTabBar::rect(int child) const +{ + if (!child || !tabBar()->isVisible()) + return QAccessibleWidgetEx::rect(0); + + QPoint tp = tabBar()->mapToGlobal(QPoint(0,0)); + QRect rec; + if (child <= tabBar()->count()) { + rec = tabBar()->tabRect(child - 1); + } else { + QWidget *widget = button(child); + rec = widget ? widget->geometry() : QRect(); + } + return QRect(tp.x() + rec.x(), tp.y() + rec.y(), rec.width(), rec.height()); +} + +/*! \reimp */ +int QAccessibleTabBar::childCount() const +{ + // tabs + scroll buttons + return tabBar()->count() + 2; +} + +/*! \reimp */ +QString QAccessibleTabBar::text(Text t, int child) const +{ + QString str; + + if (child > tabBar()->count()) { + bool left = child - tabBar()->count() == 1; + switch (t) { + case Name: + return left ? QTabBar::tr("Scroll Left") : QTabBar::tr("Scroll Right"); + default: + break; + } + } else if (child > 0) { + switch (t) { + case Name: + return qt_accStripAmp(tabBar()->tabText(child - 1)); + default: + break; + } + } + + if (str.isEmpty()) + str = QAccessibleWidgetEx::text(t, child);; + return str; +} + +/*! \reimp */ +QAccessible::Role QAccessibleTabBar::role(int child) const +{ + if (!child) + return PageTabList; + if (child > tabBar()->count()) + return PushButton; + return PageTab; +} + +/*! \reimp */ +QAccessible::State QAccessibleTabBar::state(int child) const +{ + State st = QAccessibleWidgetEx::state(0); + + if (!child) + return st; + + QTabBar *tb = tabBar(); + + if (child > tb->count()) { + QWidget *bt = button(child); + if (!bt) + return st; + if (bt->isEnabled() == false) + st |= Unavailable; + if (bt->isVisible() == false) + st |= Invisible; + if (bt->focusPolicy() != Qt::NoFocus && bt->isActiveWindow()) + st |= Focusable; + if (bt->hasFocus()) + st |= Focused; + return st; + } + + if (!tb->isTabEnabled(child - 1)) + st |= Unavailable; + else + st |= Selectable; + + if (!tb->currentIndex() == child - 1) + st |= Selected; + + return st; +} + +/*! \reimp */ +bool QAccessibleTabBar::doAction(int action, int child, const QVariantList &) +{ + if (!child) + return false; + + if (action != QAccessible::DefaultAction && action != QAccessible::Press) + return false; + + if (child > tabBar()->count()) { + QAbstractButton *bt = button(child); + if (!bt->isEnabled()) + return false; + bt->animateClick(); + return true; + } + if (!tabBar()->isTabEnabled(child - 1)) + return false; + tabBar()->setCurrentIndex(child - 1); + return true; +} + +/*! + Selects the item with index \a child if \a on is true; otherwise + unselects it. If \a extend is true and the selection mode is not + \c Single and there is an existing selection, the selection is + extended to include all the items from the existing selection up + to and including the item with index \a child. Returns true if a + selection was made or extended; otherwise returns false. + + \sa selection() clearSelection() +*/ +bool QAccessibleTabBar::setSelected(int child, bool on, bool extend) +{ + if (!child || !on || extend || child > tabBar()->count()) + return false; + + if (!tabBar()->isTabEnabled(child - 1)) + return false; + tabBar()->setCurrentIndex(child - 1); + return true; +} + +/*! + Returns a (possibly empty) list of indexes of the items selected + in the list box. + + \sa setSelected() clearSelection() +*/ +QVector<int> QAccessibleTabBar::selection() const +{ + QVector<int> array; + if (tabBar()->currentIndex() != -1) + array +=tabBar()->currentIndex() + 1; + return array; +} + +#endif // QT_NO_TABBAR + +#ifndef QT_NO_COMBOBOX +/*! + \class QAccessibleComboBox + \brief The QAccessibleComboBox class implements the QAccessibleInterface for editable and read-only combo boxes. + \internal + + \ingroup accessibility +*/ + +/*! + \enum QAccessibleComboBox::ComboBoxElements + + \internal + + \value ComboBoxSelf + \value CurrentText + \value OpenList + \value PopupList +*/ + +/*! + Constructs a QAccessibleComboBox object for \a w. +*/ +QAccessibleComboBox::QAccessibleComboBox(QWidget *w) +: QAccessibleWidgetEx(w, ComboBox) +{ + Q_ASSERT(comboBox()); +} + +/*! + Returns the combobox. +*/ +QComboBox *QAccessibleComboBox::comboBox() const +{ + return qobject_cast<QComboBox*>(object()); +} + +/*! \reimp */ +QRect QAccessibleComboBox::rect(int child) const +{ + QPoint tp; + QStyle::SubControl sc; + QRect r; + switch (child) { + case CurrentText: + if (comboBox()->isEditable()) { + tp = comboBox()->lineEdit()->mapToGlobal(QPoint(0,0)); + r = comboBox()->lineEdit()->rect(); + sc = QStyle::SC_None; + } else { + tp = comboBox()->mapToGlobal(QPoint(0,0)); + sc = QStyle::SC_ComboBoxEditField; + } + break; + case OpenList: + tp = comboBox()->mapToGlobal(QPoint(0,0)); + sc = QStyle::SC_ComboBoxArrow; + break; + default: + return QAccessibleWidgetEx::rect(child); + } + + if (sc != QStyle::SC_None) { + QStyleOptionComboBox option; + option.initFrom(comboBox()); + r = comboBox()->style()->subControlRect(QStyle::CC_ComboBox, &option, sc, comboBox()); + } + return QRect(tp.x() + r.x(), tp.y() + r.y(), r.width(), r.height()); +} + +/*! \reimp */ +int QAccessibleComboBox::navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const +{ + *target = 0; + if (entry > ComboBoxSelf) switch (rel) { + case Child: + if (entry < PopupList) + return entry; + if (entry == PopupList) { + QAbstractItemView *view = comboBox()->view(); + QWidget *parent = view ? view->parentWidget() : 0; + *target = QAccessible::queryAccessibleInterface(parent); + return *target ? 0 : -1; + } + case QAccessible::Left: + return entry == OpenList ? CurrentText : -1; + case QAccessible::Right: + return entry == CurrentText ? OpenList : -1; + case QAccessible::Up: + return -1; + case QAccessible::Down: + return -1; + default: + break; + } + return QAccessibleWidgetEx::navigate(rel, entry, target); +} + +/*! \reimp */ +int QAccessibleComboBox::childCount() const +{ + return comboBox()->view() ? PopupList : OpenList; +} + +/*! \reimp */ +int QAccessibleComboBox::childAt(int x, int y) const +{ + if (!comboBox()->isVisible()) + return -1; + QPoint gp = widget()->mapToGlobal(QPoint(0, 0)); + if (!QRect(gp.x(), gp.y(), widget()->width(), widget()->height()).contains(x, y)) + return -1; + + // a complex control + for (int i = 1; i < PopupList; ++i) { + if (rect(i).contains(x, y)) + return i; + } + return 0; +} + +/*! \reimp */ +int QAccessibleComboBox::indexOfChild(const QAccessibleInterface *child) const +{ + QObject *viewParent = comboBox()->view() ? comboBox()->view()->parentWidget() : 0; + if (child->object() == viewParent) + return PopupList; + return -1; +} + +/*! \reimp */ +QString QAccessibleComboBox::text(Text t, int child) const +{ + QString str; + + switch (t) { + case Name: + if (child == OpenList) + str = QComboBox::tr("Open"); + else + str = QAccessibleWidgetEx::text(t, 0); + break; +#ifndef QT_NO_SHORTCUT + case Accelerator: + if (child == OpenList) + str = (QString)QKeySequence(Qt::Key_Down); + // missing break? +#endif + case Value: + if (comboBox()->isEditable()) + str = comboBox()->lineEdit()->text(); + else + str = comboBox()->currentText(); + break; + default: + break; + } + if (str.isEmpty()) + str = QAccessibleWidgetEx::text(t, 0); + return str; +} + +/*! \reimp */ +QAccessible::Role QAccessibleComboBox::role(int child) const +{ + switch (child) { + case CurrentText: + if (comboBox()->isEditable()) + return EditableText; + return StaticText; + case OpenList: + return PushButton; + case PopupList: + return List; + default: + return ComboBox; + } +} + +/*! \reimp */ +QAccessible::State QAccessibleComboBox::state(int /*child*/) const +{ + return QAccessibleWidgetEx::state(0); +} + +/*! \reimp */ +bool QAccessibleComboBox::doAction(int action, int child, const QVariantList &) +{ + if (child == 2 && (action == DefaultAction || action == Press)) { + if (comboBox()->view()->isVisible()) { + comboBox()->hidePopup(); + } else { + comboBox()->showPopup(); + } + return true; + } + return false; +} + +QString QAccessibleComboBox::actionText(int action, Text t, int child) const +{ + QString text; + if (child == 2 && t == Name && (action == DefaultAction || action == Press)) + text = comboBox()->view()->isVisible() ? QComboBox::tr("Close") : QComboBox::tr("Open"); + return text; +} +#endif // QT_NO_COMBOBOX + +static inline void removeInvisibleWidgetsFromList(QWidgetList *list) +{ + if (!list || list->isEmpty()) + return; + + for (int i = 0; i < list->count(); ++i) { + QWidget *widget = list->at(i); + if (!widget->isVisible()) + list->removeAt(i); + } +} + +#ifndef QT_NO_SCROLLAREA +// ======================= QAccessibleAbstractScrollArea ======================= +QAccessibleAbstractScrollArea::QAccessibleAbstractScrollArea(QWidget *widget) + : QAccessibleWidgetEx(widget, Client) +{ + Q_ASSERT(qobject_cast<QAbstractScrollArea *>(widget)); +} + +QString QAccessibleAbstractScrollArea::text(Text textType, int child) const +{ + if (child == Self) + return QAccessibleWidgetEx::text(textType, 0); + QWidgetList children = accessibleChildren(); + if (child < 1 || child > children.count()) + return QString(); + QAccessibleInterface *childInterface = queryAccessibleInterface(children.at(child - 1)); + if (!childInterface) + return QString(); + QString string = childInterface->text(textType, 0); + delete childInterface; + return string; +} + +void QAccessibleAbstractScrollArea::setText(Text textType, int child, const QString &text) +{ + if (text.isEmpty()) + return; + if (child == 0) { + QAccessibleWidgetEx::setText(textType, 0, text); + return; + } + QWidgetList children = accessibleChildren(); + if (child < 1 || child > children.count()) + return; + QAccessibleInterface *childInterface = queryAccessibleInterface(children.at(child - 1)); + if (!childInterface) + return; + childInterface->setText(textType, 0, text); + delete childInterface; +} + +QAccessible::State QAccessibleAbstractScrollArea::state(int child) const +{ + if (child == Self) + return QAccessibleWidgetEx::state(child); + QWidgetList children = accessibleChildren(); + if (child < 1 || child > children.count()) + return QAccessibleWidgetEx::state(Self); + QAccessibleInterface *childInterface = queryAccessibleInterface(children.at(child - 1)); + if (!childInterface) + return QAccessibleWidgetEx::state(Self); + QAccessible::State returnState = childInterface->state(0); + delete childInterface; + return returnState; +} + +QVariant QAccessibleAbstractScrollArea::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + +int QAccessibleAbstractScrollArea::childCount() const +{ + return accessibleChildren().count(); +} + +int QAccessibleAbstractScrollArea::indexOfChild(const QAccessibleInterface *child) const +{ + if (!child || !child->object()) + return -1; + int index = accessibleChildren().indexOf(qobject_cast<QWidget *>(child->object())); + if (index >= 0) + return ++index; + return -1; +} + +bool QAccessibleAbstractScrollArea::isValid() const +{ + return (QAccessibleWidgetEx::isValid() && abstractScrollArea() && abstractScrollArea()->viewport()); +} + +int QAccessibleAbstractScrollArea::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const +{ + if (!target) + return -1; + + *target = 0; + + QWidget *targetWidget = 0; + QWidget *entryWidget = 0; + + if (relation == Child || + relation == Left || relation == Up || relation == Right || relation == Down) { + QWidgetList children = accessibleChildren(); + if (entry < 0 || entry > children.count()) + return -1; + + if (entry == Self) + entryWidget = abstractScrollArea(); + else + entryWidget = children.at(entry - 1); + AbstractScrollAreaElement entryElement = elementType(entryWidget); + + // Not one of the most beautiful switches I've ever seen, but I believe it has + // to be like this since each case need special handling. + // It might be possible to make it more general, but I'll leave that as an exercise + // to the reader. :-) + switch (relation) { + case Child: + if (entry > 0) + targetWidget = children.at(entry - 1); + break; + case Left: + if (entry < 1) + break; + switch (entryElement) { + case Viewport: + if (!isLeftToRight()) + targetWidget = abstractScrollArea()->verticalScrollBar(); + break; + case HorizontalContainer: + if (!isLeftToRight()) + targetWidget = abstractScrollArea()->cornerWidget(); + break; + case VerticalContainer: + if (isLeftToRight()) + targetWidget = abstractScrollArea()->viewport(); + break; + case CornerWidget: + if (isLeftToRight()) + targetWidget = abstractScrollArea()->horizontalScrollBar(); + break; + default: + break; + } + break; + case Right: + if (entry < 1) + break; + switch (entryElement) { + case Viewport: + if (isLeftToRight()) + targetWidget = abstractScrollArea()->verticalScrollBar(); + break; + case HorizontalContainer: + targetWidget = abstractScrollArea()->cornerWidget(); + break; + case VerticalContainer: + if (!isLeftToRight()) + targetWidget = abstractScrollArea()->viewport(); + break; + case CornerWidget: + if (!isLeftToRight()) + targetWidget = abstractScrollArea()->horizontalScrollBar(); + break; + default: + break; + } + break; + case Up: + if (entry < 1) + break; + switch (entryElement) { + case HorizontalContainer: + targetWidget = abstractScrollArea()->viewport(); + break; + case CornerWidget: + targetWidget = abstractScrollArea()->verticalScrollBar(); + break; + default: + break; + } + break; + case Down: + if (entry < 1) + break; + switch (entryElement) { + case Viewport: + targetWidget = abstractScrollArea()->horizontalScrollBar(); + break; + case VerticalContainer: + targetWidget = abstractScrollArea()->cornerWidget(); + break; + default: + break; + } + break; + default: + break; + } + } else { + return QAccessibleWidgetEx::navigate(relation, entry, target); + } + + if (qobject_cast<const QScrollBar *>(targetWidget)) + targetWidget = targetWidget->parentWidget(); + *target = QAccessible::queryAccessibleInterface(targetWidget); + return *target ? 0: -1; +} + +QRect QAccessibleAbstractScrollArea::rect(int child) const +{ + if (!abstractScrollArea()->isVisible()) + return QRect(); + if (child == Self) + return QAccessibleWidgetEx::rect(child); + QWidgetList children = accessibleChildren(); + if (child < 1 || child > children.count()) + return QRect(); + const QWidget *childWidget = children.at(child - 1); + if (!childWidget->isVisible()) + return QRect(); + return QRect(childWidget->mapToGlobal(QPoint(0, 0)), childWidget->size()); +} + +int QAccessibleAbstractScrollArea::childAt(int x, int y) const +{ + if (!abstractScrollArea()->isVisible()) + return -1; +#if 0 + const QRect globalSelfGeometry = rect(Self); + if (!globalSelfGeometry.isValid() || !globalSelfGeometry.contains(QPoint(x, y))) + return -1; + const QWidgetList children = accessibleChildren(); + for (int i = 0; i < children.count(); ++i) { + const QWidget *child = children.at(i); + const QRect globalChildGeometry = QRect(child->mapToGlobal(QPoint(0, 0)), child->size()); + if (globalChildGeometry.contains(QPoint(x, y))) { + return ++i; + } + } + return 0; +#else + for (int i = childCount(); i >= 0; --i) { + if (rect(i).contains(x, y)) + return i; + } + return -1; +#endif +} + +QAbstractScrollArea *QAccessibleAbstractScrollArea::abstractScrollArea() const +{ + return static_cast<QAbstractScrollArea *>(object()); +} + +QWidgetList QAccessibleAbstractScrollArea::accessibleChildren() const +{ + QWidgetList children; + + // Viewport. + QWidget * viewport = abstractScrollArea()->viewport(); + if (viewport) + children.append(viewport); + + // Horizontal scrollBar container. + QScrollBar *horizontalScrollBar = abstractScrollArea()->horizontalScrollBar(); + if (horizontalScrollBar && horizontalScrollBar->isVisible()) { + children.append(horizontalScrollBar->parentWidget()); + } + + // Vertical scrollBar container. + QScrollBar *verticalScrollBar = abstractScrollArea()->verticalScrollBar(); + if (verticalScrollBar && verticalScrollBar->isVisible()) { + children.append(verticalScrollBar->parentWidget()); + } + + // CornerWidget. + QWidget *cornerWidget = abstractScrollArea()->cornerWidget(); + if (cornerWidget && cornerWidget->isVisible()) + children.append(cornerWidget); + + return children; +} + +QAccessibleAbstractScrollArea::AbstractScrollAreaElement +QAccessibleAbstractScrollArea::elementType(QWidget *widget) const +{ + if (!widget) + return Undefined; + + if (widget == abstractScrollArea()) + return Self; + if (widget == abstractScrollArea()->viewport()) + return Viewport; + if (widget->objectName() == QLatin1String("qt_scrollarea_hcontainer")) + return HorizontalContainer; + if (widget->objectName() == QLatin1String("qt_scrollarea_vcontainer")) + return VerticalContainer; + if (widget == abstractScrollArea()->cornerWidget()) + return CornerWidget; + + return Undefined; +} + +bool QAccessibleAbstractScrollArea::isLeftToRight() const +{ + return abstractScrollArea()->isLeftToRight(); +} + +// ======================= QAccessibleScrollArea =========================== +QAccessibleScrollArea::QAccessibleScrollArea(QWidget *widget) + : QAccessibleAbstractScrollArea(widget) +{ + Q_ASSERT(qobject_cast<QScrollArea *>(widget)); +} +#endif // QT_NO_SCROLLAREA + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY |