diff options
author | Frederik Gladhorn <frederik.gladhorn@nokia.com> | 2011-06-27 14:28:50 (GMT) |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@nokia.com> | 2011-07-13 14:51:28 (GMT) |
commit | e797ba558dddd45522b5a317316e497e9efc44a8 (patch) | |
tree | 31f218a3d5a609036331edd16110a4634d297eec /src/plugins | |
parent | 95952a0a1d66fba31b44a723497ec89e8d97604c (diff) | |
download | Qt-e797ba558dddd45522b5a317316e497e9efc44a8.zip Qt-e797ba558dddd45522b5a317316e497e9efc44a8.tar.gz Qt-e797ba558dddd45522b5a317316e497e9efc44a8.tar.bz2 |
Add IAccessible2 table2 implementation.
Implement the IAccessible table2 interface for itemviews.
This is simpler than what we have in complexwidgets.
For now it is only used on Linux.
Reviewed-by: Gabi
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/accessible/widgets/itemviews.cpp | 1029 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/itemviews.h | 319 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/main.cpp | 22 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/widgets.pro | 22 |
4 files changed, 1382 insertions, 10 deletions
diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp new file mode 100644 index 0000000..d7432e9 --- /dev/null +++ b/src/plugins/accessible/widgets/itemviews.cpp @@ -0,0 +1,1029 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "itemviews.h" + +#include <qheaderview.h> +#include <qtableview.h> +#include <qlistview.h> +#include <qtreeview.h> +#include <private/qtreewidget_p.h> +#include <qaccessible2.h> +#include <QDebug> + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); + +#ifndef QT_NO_ITEMVIEWS +/* +Implementation of the IAccessible2 table2 interface. Much simpler than +the other table interfaces since there is only the main table and cells: + +TABLE/LIST/TREE + |- HEADER CELL + |- CELL + |- CELL + ... +*/ + +int QAccessibleTable2::logicalIndex(const QModelIndex &index) const +{ + if (!index.isValid()) + return -1; + int vHeader = verticalHeader() ? 1 : 0; + int hHeader = horizontalHeader() ? 1 : 0; + // row * number columns + column + 1 for one based counting + return (index.row() + hHeader)*(index.model()->columnCount() + vHeader) + (index.column() + vHeader) + 1; +} + +QAccessibleInterface *QAccessibleTable2::childFromLogical(int logicalIndex) const +{ + logicalIndex--; // one based counting ftw + int vHeader = verticalHeader() ? 1 : 0; + int hHeader = horizontalHeader() ? 1 : 0; + + int columns = view->model()->columnCount() + vHeader; + + int row = logicalIndex / columns; + int column = logicalIndex % columns; + + if (vHeader) { + if (column == 0) { + if (row == 0) { + return new QAccessibleTable2CornerButton(view); + } + return new QAccessibleTable2HeaderCell(view, row-1, Qt::Vertical); + } + --column; + } + if (hHeader) { + if (row == 0) { + return new QAccessibleTable2HeaderCell(view, column, Qt::Horizontal); + } + --row; + } + return new QAccessibleTable2Cell(view, view->model()->index(row, column), cellRole()); +} + +QAccessibleTable2::QAccessibleTable2(QWidget *w) + : QAccessibleObjectEx(w) +{ + view = qobject_cast<QAbstractItemView *>(w); + Q_ASSERT(view); + + if (qobject_cast<const QTableView*>(view)) { + m_role = QAccessible::Table; + } else if (qobject_cast<const QTreeView*>(view)) { + m_role = QAccessible::Tree; + } else if (qobject_cast<const QListView*>(view)) { + m_role = QAccessible::List; + } else { + // is this our best guess? + m_role = QAccessible::Table; + } +} + +QAccessibleTable2::~QAccessibleTable2() +{ +} + +QHeaderView *QAccessibleTable2::horizontalHeader() const +{ + QHeaderView *header = 0; + 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 *QAccessibleTable2::verticalHeader() const +{ + QHeaderView *header = 0; + if (false) { +#ifndef QT_NO_TABLEVIEW + } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) { + header = tv->verticalHeader(); +#endif + } + return header; +} + +void QAccessibleTable2::modelReset() +{} + +void QAccessibleTable2::rowsInserted(const QModelIndex &, int first, int last) +{ + lastChange.firstRow = first; + lastChange.lastRow = last; + lastChange.firstColumn = 0; + lastChange.lastColumn = 0; + lastChange.type = QAccessible2::TableModelChangeInsert; +} + +void QAccessibleTable2::rowsRemoved(const QModelIndex &, int first, int last) +{ + lastChange.firstRow = first; + lastChange.lastRow = last; + lastChange.firstColumn = 0; + lastChange.lastColumn = 0; + lastChange.type = QAccessible2::TableModelChangeDelete; +} + +void QAccessibleTable2::columnsInserted(const QModelIndex &, int first, int last) +{ + lastChange.firstRow = 0; + lastChange.lastRow = 0; + lastChange.firstColumn = first; + lastChange.lastColumn = last; + lastChange.type = QAccessible2::TableModelChangeInsert; +} + +void QAccessibleTable2::columnsRemoved(const QModelIndex &, int first, int last) +{ + lastChange.firstRow = 0; + lastChange.lastRow = 0; + lastChange.firstColumn = first; + lastChange.lastColumn = last; + lastChange.type = QAccessible2::TableModelChangeDelete; +} + +void QAccessibleTable2::rowsMoved( const QModelIndex &, int, int, const QModelIndex &, int) +{ + lastChange.firstRow = 0; + lastChange.lastRow = 0; + lastChange.firstColumn = 0; + lastChange.lastColumn = 0; + lastChange.type = QAccessible2::TableModelChangeUpdate; +} + +void QAccessibleTable2::columnsMoved( const QModelIndex &, int, int, const QModelIndex &, int) +{ + lastChange.firstRow = 0; + lastChange.lastRow = 0; + lastChange.firstColumn = 0; + lastChange.lastColumn = 0; + lastChange.type = QAccessible2::TableModelChangeUpdate; +} + +QAccessibleTable2Cell *QAccessibleTable2::cell(const QModelIndex &index) const +{ + if (index.isValid()) + return new QAccessibleTable2Cell(view, index, cellRole()); + return 0; +} + +QAccessibleTable2CellInterface *QAccessibleTable2::cellAt(int row, int column) const +{ + Q_ASSERT(role(0) != QAccessible::Tree); + QModelIndex index = view->model()->index(row, column); + //Q_ASSERT(index.isValid()); + if (!index.isValid()) { + qWarning() << "QAccessibleTable2::cellAt: invalid index: " << index << " for " << view; + return 0; + } + return cell(index); +} + +QAccessibleInterface *QAccessibleTable2::caption() const +{ + return 0; +} + +QString QAccessibleTable2::columnDescription(int column) const +{ + return view->model()->headerData(column, Qt::Horizontal).toString(); +} + +int QAccessibleTable2::columnCount() const +{ + return view->model()->columnCount(); +} + +int QAccessibleTable2::rowCount() const +{ + return view->model()->rowCount(); +} + +int QAccessibleTable2::selectedCellCount() const +{ + return view->selectionModel()->selectedIndexes().count(); +} + +int QAccessibleTable2::selectedColumnCount() const +{ + return view->selectionModel()->selectedColumns().count(); +} + +int QAccessibleTable2::selectedRowCount() const +{ + return view->selectionModel()->selectedRows().count(); +} + +QString QAccessibleTable2::rowDescription(int row) const +{ + return view->model()->headerData(row, Qt::Vertical).toString(); +} + +QList<QAccessibleTable2CellInterface*> QAccessibleTable2::selectedCells() const +{ + QList<QAccessibleTable2CellInterface*> cells; + Q_FOREACH (const QModelIndex &index, view->selectionModel()->selectedIndexes()) { + cells.append(cell(index)); + } + return cells; +} + +QList<int> QAccessibleTable2::selectedColumns() const +{ + QList<int> columns; + Q_FOREACH(const QModelIndex &index, view->selectionModel()->selectedColumns()) { + columns.append(index.column()); + } + return columns; +} + +QList<int> QAccessibleTable2::selectedRows() const +{ + QList<int> rows; + Q_FOREACH(const QModelIndex &index, view->selectionModel()->selectedRows()) { + rows.append(index.row()); + } + return rows; +} + +QAccessibleInterface *QAccessibleTable2::summary() const +{ + return 0; +} + +bool QAccessibleTable2::isColumnSelected(int column) const +{ + return view->selectionModel()->isColumnSelected(column, QModelIndex()); +} + +bool QAccessibleTable2::isRowSelected(int row) const +{ + return view->selectionModel()->isRowSelected(row, QModelIndex()); +} + +bool QAccessibleTable2::selectRow(int row) +{ + QModelIndex index = view->model()->index(row, 0); + if (!index.isValid() || view->selectionMode() & QAbstractItemView::NoSelection) + return false; + view->selectionModel()->select(index, QItemSelectionModel::Select); + return true; +} + +bool QAccessibleTable2::selectColumn(int column) +{ + QModelIndex index = view->model()->index(0, column); + if (!index.isValid() || view->selectionMode() & QAbstractItemView::NoSelection) + return false; + view->selectionModel()->select(index, QItemSelectionModel::Select); + return true; +} + +bool QAccessibleTable2::unselectRow(int row) +{ + QModelIndex index = view->model()->index(row, 0); + if (!index.isValid() || view->selectionMode() & QAbstractItemView::NoSelection) + return false; + view->selectionModel()->select(index, QItemSelectionModel::Deselect); + return true; +} + +bool QAccessibleTable2::unselectColumn(int column) +{ + QModelIndex index = view->model()->index(0, column); + if (!index.isValid() || view->selectionMode() & QAbstractItemView::NoSelection) + return false; + view->selectionModel()->select(index, QItemSelectionModel::Columns & QItemSelectionModel::Deselect); + return true; +} + +QAccessible2::TableModelChange QAccessibleTable2::modelChange() const +{ + QAccessible2::TableModelChange change; + // FIXME + return change; +} + +QAccessible::Role QAccessibleTable2::role(int child) const +{ + Q_ASSERT(child >= 0); + if (child > 0) + return QAccessible::Cell; + return m_role; +} + +QAccessible::State QAccessibleTable2::state(int child) const +{ + Q_ASSERT(child == 0); + return QAccessible::Normal | HasInvokeExtension; +} + +int QAccessibleTable2::childAt(int x, int y) const +{ + QPoint viewportOffset = view->viewport()->mapTo(view, QPoint(0,0)); + QPoint indexPosition = view->mapFromGlobal(QPoint(x, y) - viewportOffset); + // FIXME: if indexPosition < 0 in one coordinate, return header + + QModelIndex index = view->indexAt(indexPosition); + if (index.isValid()) { + return logicalIndex(index); + } + return -1; +} + +int QAccessibleTable2::childCount() const +{ + int vHeader = verticalHeader() ? 1 : 0; + int hHeader = horizontalHeader() ? 1 : 0; + return (view->model()->rowCount()+hHeader) * (view->model()->columnCount()+vHeader); +} + +int QAccessibleTable2::indexOfChild(const QAccessibleInterface *iface) const +{ + Q_ASSERT(iface->role(0) != QAccessible::TreeItem); // should be handled by tree class + if (iface->role(0) == QAccessible::Cell || iface->role(0) == QAccessible::ListItem) { + const QAccessibleTable2Cell* cell = static_cast<const QAccessibleTable2Cell*>(iface); + return logicalIndex(cell->m_index); + } else if (iface->role(0) == QAccessible::ColumnHeader){ + const QAccessibleTable2HeaderCell* cell = static_cast<const QAccessibleTable2HeaderCell*>(iface); + return cell->index + (verticalHeader() ? 1 : 0) + 1; + } else if (iface->role(0) == QAccessible::RowHeader){ + const QAccessibleTable2HeaderCell* cell = static_cast<const QAccessibleTable2HeaderCell*>(iface); + return (cell->index+1) * (view->model()->rowCount()+1) + 1; + } else if (iface->role(0) == QAccessible::Pane) { + return 1; // corner button + } else { + qWarning() << "WARNING QAccessibleTable2::indexOfChild Fix my children..." + << iface->role(0) << iface->text(QAccessible::Name, 0); + } + // FIXME: we are in denial of our children. this should stop. + return -1; +} + +QString QAccessibleTable2::text(Text t, int child) const +{ + Q_ASSERT(child == 0); + if (t == QAccessible::Description) + return view->accessibleDescription(); + return view->accessibleName(); +} + +QRect QAccessibleTable2::rect(int child) const +{ + Q_ASSERT(!child); + if (!view->isVisible()) + return QRect(); + QPoint pos = view->mapToGlobal(QPoint(0, 0)); + return QRect(pos.x(), pos.y(), view->width(), view->height()); +} + +int QAccessibleTable2::navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const +{ + *iface = 0; + switch (relation) { + case Ancestor: { + if (index == 1 && view->parent()) { + *iface = QAccessible::queryAccessibleInterface(view->parent()); + if (*iface) + return 0; + } + break; + } + case QAccessible::Child: { + Q_ASSERT(index > 0); + *iface = childFromLogical(index); + if (*iface) { + return 0; + } + break; + } + default: + break; + } + return -1; +} + +QAccessible::Relation QAccessibleTable2::relationTo(int, const QAccessibleInterface *, int) const +{ + return QAccessible::Unrelated; +} + +#ifndef QT_NO_ACTION +int QAccessibleTable2::userActionCount(int) const +{ + return 0; +} +QString QAccessibleTable2::actionText(int, Text, int) const +{ + return QString(); +} +bool QAccessibleTable2::doAction(int, int, const QVariantList &) +{ + return false; +} +#endif + + +// TREE VIEW + +QModelIndex QAccessibleTree::indexFromLogical(int row, int column) const +{ + const QTreeView *treeView = qobject_cast<const QTreeView*>(view); + QModelIndex modelIndex = treeView->d_func()->viewItems.at(row).index; + + if (modelIndex.isValid() && column > 0) { + modelIndex = view->model()->index(modelIndex.row(), column, modelIndex.parent()); + } + return modelIndex; +} + +int QAccessibleTree::childAt(int x, int y) const +{ + QPoint viewportOffset = view->viewport()->mapTo(view, QPoint(0,0)); + QPoint indexPosition = view->mapFromGlobal(QPoint(x, y) - viewportOffset); + + QModelIndex index = view->indexAt(indexPosition); + if (!index.isValid()) + return -1; + + const QTreeView *treeView = qobject_cast<const QTreeView*>(view); + int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0); + int column = index.column(); + + int i = row * view->model()->columnCount() + column + 1; + Q_ASSERT(i > view->model()->columnCount()); + return i; +} + +int QAccessibleTree::childCount() const +{ + const QTreeView *treeView = qobject_cast<const QTreeView*>(view); + Q_ASSERT(treeView); + if (!view->model()) + return 0; + + int hHeader = horizontalHeader() ? 1 : 0; + return (treeView->d_func()->viewItems.count() + hHeader)* view->model()->columnCount(); +} + +int QAccessibleTree::rowCount() const +{ + const QTreeView *treeView = qobject_cast<const QTreeView*>(view); + Q_ASSERT(treeView); + return treeView->d_func()->viewItems.count(); +} + +int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const +{ + if (iface->role(0) == QAccessible::TreeItem) { + const QAccessibleTable2Cell* cell = static_cast<const QAccessibleTable2Cell*>(iface); + const QTreeView *treeView = qobject_cast<const QTreeView*>(view); + Q_ASSERT(treeView); + int row = treeView->d_func()->viewIndex(cell->m_index) + (horizontalHeader() ? 1 : 0); + int column = cell->m_index.column(); + + int index = row * view->model()->columnCount() + column + 1; + //qDebug() << "QAccessibleTree::indexOfChild r " << row << " c " << column << "index " << index; + Q_ASSERT(index > treeView->model()->columnCount()); + return index; + } else if (iface->role(0) == QAccessible::ColumnHeader){ + const QAccessibleTable2HeaderCell* cell = static_cast<const QAccessibleTable2HeaderCell*>(iface); + //qDebug() << "QAccessibleTree::indexOfChild header " << cell->index << "is: " << cell->index + 1; + return cell->index + 1; + } else { + qWarning() << "WARNING QAccessibleTable2::indexOfChild invalid child" + << iface->role(0) << iface->text(QAccessible::Name, 0); + } + // FIXME: add scrollbars and don't just ignore them + return -1; +} + +int QAccessibleTree::navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const +{ + switch (relation) { + case QAccessible::Child: { + Q_ASSERT(index > 0); + --index; + int hHeader = horizontalHeader() ? 1 : 0; + + if (hHeader) { + if (index < view->model()->columnCount()) { + *iface = new QAccessibleTable2HeaderCell(view, index, Qt::Horizontal); + return 0; + } else { + index -= view->model()->columnCount(); + } + } + + int row = index / view->model()->columnCount(); + int column = index % view->model()->columnCount(); + QModelIndex modelIndex = indexFromLogical(row, column); + if (modelIndex.isValid()) { + *iface = cell(modelIndex); + return 0; + } + return -1; + } + default: + break; + } + return QAccessibleTable2::navigate(relation, index, iface); +} + +QAccessible::Relation QAccessibleTree::relationTo(int, const QAccessibleInterface *, int) const +{ + return QAccessible::Unrelated; +} + +QAccessibleTable2CellInterface *QAccessibleTree::cellAt(int row, int column) const +{ + QModelIndex index = indexFromLogical(row, column); + if (!index.isValid()) { + qWarning() << "Requested invalid tree cell: " << row << column; + return 0; + } + return new QAccessibleTable2Cell(view, index, cellRole()); +} + +QString QAccessibleTree::rowDescription(int) const +{ + return QString(); // no headers for rows in trees +} + +bool QAccessibleTree::isRowSelected(int row) const +{ + QModelIndex index = indexFromLogical(row); + return view->selectionModel()->isRowSelected(index.row(), index.parent()); +} + +bool QAccessibleTree::selectRow(int row) +{ + QModelIndex index = indexFromLogical(row); + if (!index.isValid() || view->selectionMode() & QAbstractItemView::NoSelection) + return false; + view->selectionModel()->select(index, QItemSelectionModel::Select); + return true; +} + +// TABLE CELL + +QAccessibleTable2Cell::QAccessibleTable2Cell(QAbstractItemView *view_, const QModelIndex &index_, QAccessible::Role role_) + : /* QAccessibleSimpleEditableTextInterface(this), */ view(view_), m_index(index_), m_role(role_) +{ + Q_ASSERT(index_.isValid()); +} + +int QAccessibleTable2Cell::columnExtent() const { return 1; } +int QAccessibleTable2Cell::rowExtent() const { return 1; } + +QList<QAccessibleInterface*> QAccessibleTable2Cell::rowHeaderCells() const +{ + QList<QAccessibleInterface*> headerCell; + if (verticalHeader()) { + headerCell.append(new QAccessibleTable2HeaderCell(view, m_index.row(), Qt::Vertical)); + } + return headerCell; +} + +QList<QAccessibleInterface*> QAccessibleTable2Cell::columnHeaderCells() const +{ + QList<QAccessibleInterface*> headerCell; + if (horizontalHeader()) { + headerCell.append(new QAccessibleTable2HeaderCell(view, m_index.column(), Qt::Horizontal)); + } + return headerCell; +} + +QHeaderView *QAccessibleTable2Cell::horizontalHeader() const +{ + QHeaderView *header = 0; + + 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 *QAccessibleTable2Cell::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 QAccessibleTable2Cell::columnIndex() const +{ + return m_index.column(); +} + +int QAccessibleTable2Cell::rowIndex() const +{ + if (role(0) == QAccessible::TreeItem) { + const QTreeView *treeView = qobject_cast<const QTreeView*>(view); + Q_ASSERT(treeView); + int row = treeView->d_func()->viewIndex(m_index); + return row; + } + return m_index.row(); +} + +bool QAccessibleTable2Cell::isSelected() const +{ + return view->selectionModel()->isSelected(m_index); +} + +void QAccessibleTable2Cell::rowColumnExtents(int *row, int *column, int *rowExtents, int *columnExtents, bool *selected) const +{ + *row = m_index.row(); + *column = m_index.column(); + *rowExtents = 1; + *columnExtents = 1; + *selected = isSelected(); +} + +QAccessibleTable2Interface* QAccessibleTable2Cell::table() const +{ + return QAccessible::queryAccessibleInterface(view)->table2Interface(); +} + +QAccessible::Role QAccessibleTable2Cell::role(int child) const +{ + Q_ASSERT(child == 0); + return m_role; +} + +QAccessible::State QAccessibleTable2Cell::state(int child) const +{ + Q_ASSERT(child == 0); + State st = Normal; + + QRect globalRect = view->rect(); + globalRect.translate(view->mapToGlobal(QPoint(0,0))); + if (!globalRect.intersects(rect(0))) + st |= Invisible; + + if (view->selectionModel()->isSelected(m_index)) + st |= Selected; + if (view->selectionModel()->currentIndex() == m_index) + st |= Focused; + if (m_index.model()->data(m_index, Qt::CheckStateRole).toInt() == Qt::Checked) + st |= Checked; + + Qt::ItemFlags flags = m_index.flags(); + if (flags & Qt::ItemIsSelectable) { + st |= Selectable; + st |= Focusable; + if (view->selectionMode() == QAbstractItemView::MultiSelection) + st |= MultiSelectable; + if (view->selectionMode() == QAbstractItemView::ExtendedSelection) + st |= ExtSelectable; + } + if (m_role == QAccessible::TreeItem) { + const QTreeView *treeView = qobject_cast<const QTreeView*>(view); + if (treeView->isExpanded(m_index)) + st |= Expanded; + } + return st; +} + +bool QAccessibleTable2Cell::isExpandable() const +{ + return view->model()->hasChildren(m_index); +} + +QRect QAccessibleTable2Cell::rect(int child) const +{ + Q_ASSERT(child == 0); + + QRect r; + r = view->visualRect(m_index); + + if (!r.isNull()) + r.translate(view->viewport()->mapTo(view, QPoint(0,0))); + r.translate(view->mapToGlobal(QPoint(0, 0))); + return r; +} + +QString QAccessibleTable2Cell::text(Text t, int child) const +{ + Q_ASSERT(child == 0); + QAbstractItemModel *model = view->model(); + QString value; + switch(t) { + case QAccessible::Value: + case QAccessible::Name: + value = model->data(m_index, Qt::AccessibleTextRole).toString(); + if (value.isEmpty()) + value = model->data(m_index, Qt::DisplayRole).toString(); + break; + case QAccessible::Description: + value = model->data(m_index, Qt::AccessibleDescriptionRole).toString(); + break; + default: + break; + } + return value; +} + +void QAccessibleTable2Cell::setText(Text /*t*/, int child, const QString &text) +{ + Q_ASSERT(child == 0); + if (!m_index.flags() & Qt::ItemIsEditable) + return; + view->model()->setData(m_index, text); +} + +bool QAccessibleTable2Cell::isValid() const +{ + if (!m_index.isValid()) { + qDebug() << "Interface is not valid"; + } + + return m_index.isValid(); +} + +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; +} + +QAccessible::Relation QAccessibleTable2Cell::relationTo(int child, const QAccessibleInterface *other, int otherChild) const +{ + Q_ASSERT(child == 0); + Q_ASSERT(otherChild == 0); + // we only check for parent-child relationships in trees + if (m_role == QAccessible::TreeItem && other->role(0) == QAccessible::TreeItem) { + QModelIndex otherIndex = static_cast<const QAccessibleTable2Cell*>(other)->m_index; + // is the other our parent? + if (otherIndex.parent() == m_index) + return QAccessible::Ancestor; + // are we the other's child? + if (m_index.parent() == otherIndex) + return QAccessible::Child; + } + return QAccessible::Unrelated; +} + +#ifndef QT_NO_ACTION +int QAccessibleTable2Cell::userActionCount(int) const +{ + return 0; +} + +QString QAccessibleTable2Cell::actionText(int, Text, int) const +{ + return QString(); +} + +bool QAccessibleTable2Cell::doAction(int, int, const QVariantList &) +{ + return false; +} + +QAccessibleTable2HeaderCell::QAccessibleTable2HeaderCell(QAbstractItemView *view_, int index_, Qt::Orientation orientation_) + : view(view_), index(index_), orientation(orientation_) +{ + Q_ASSERT(index_ >= 0); +} + +QAccessible::Role QAccessibleTable2HeaderCell::role(int child) const +{ + Q_ASSERT(child == 0); + if (orientation == Qt::Horizontal) + return QAccessible::ColumnHeader; + return QAccessible::RowHeader; +} + +QAccessible::State QAccessibleTable2HeaderCell::state(int child) const +{ + Q_ASSERT(child == 0); + return QAccessible::Normal; +} + +QRect QAccessibleTable2HeaderCell::rect(int child) const +{ + Q_ASSERT(child == 0); + + QHeaderView *header = 0; + if (false) { +#ifndef QT_NO_TABLEVIEW + } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) { + if (orientation == Qt::Horizontal) { + header = tv->horizontalHeader(); + } else { + header = tv->verticalHeader(); + } +#endif +#ifndef QT_NO_TREEVIEW + } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) { + header = tv->header(); +#endif + } + QPoint zero = header->mapToGlobal(QPoint(0, 0)); + int sectionSize = header->sectionSize(index); + int sectionPos = header->sectionPosition(index); + return orientation == Qt::Horizontal + ? QRect(zero.x() + sectionPos, zero.y(), sectionSize, header->height()) + : QRect(zero.x(), zero.y() + sectionPos, header->width(), sectionSize); +} + +QString QAccessibleTable2HeaderCell::text(Text t, int child) const +{ + Q_ASSERT(child == 0); + QAbstractItemModel *model = view->model(); + QString value; + switch (t) { + case QAccessible::Value: + case QAccessible::Name: + value = model->headerData(index, orientation, Qt::AccessibleTextRole).toString(); + if (value.isEmpty()) + value = model->headerData(index, orientation, Qt::DisplayRole).toString(); + break; + case QAccessible::Description: + value = model->headerData(index, orientation, Qt::AccessibleDescriptionRole).toString(); + break; + default: + break; + } + return value; +} + +void QAccessibleTable2HeaderCell::setText(Text, int, const QString &) +{ + return; +} + +bool QAccessibleTable2HeaderCell::isValid() const +{ + return true; +} + +int QAccessibleTable2HeaderCell::navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const +{ + if (relation == QAccessible::Ancestor && index == 1) { + if (false) { +#ifndef QT_NO_TREEVIEW + } else if (qobject_cast<const QTreeView*>(view)) { + *iface = new QAccessibleTree(view); + return 0; +#endif + } else { + *iface = new QAccessibleTable2(view); + return 0; + } + } + *iface = 0; + return -1; +} + +QAccessible::Relation QAccessibleTable2HeaderCell::relationTo(int, const QAccessibleInterface *, int) const +{ + return QAccessible::Unrelated; +} + +#ifndef QT_NO_ACTION +int QAccessibleTable2HeaderCell::userActionCount(int) const +{ + return 0; +} + +QString QAccessibleTable2HeaderCell::actionText(int, Text, int) const +{ + return QString(); +} + +bool QAccessibleTable2HeaderCell::doAction(int, int, const QVariantList &) +{ + return false; +} +#endif + + + +#endif + +#endif // QT_NO_ITEMVIEWS + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/itemviews.h b/src/plugins/accessible/widgets/itemviews.h new file mode 100644 index 0000000..c8492e3 --- /dev/null +++ b/src/plugins/accessible/widgets/itemviews.h @@ -0,0 +1,319 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ACCESSIBLE_ITEMVIEWS_H +#define ACCESSIBLE_ITEMVIEWS_H + +#include <QtGui/qabstractitemview.h> +#include <QtGui/qheaderview.h> +#include <QtGui/qaccessible.h> +#include <QtGui/qaccessible2.h> +#include <QtGui/qaccessiblewidget.h> + + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +#ifndef QT_NO_ITEMVIEWS + +class QAccessibleTable2Cell; +class QAccessibleTable2HeaderCell; + +class QAccessibleTable2: public QAccessibleTable2Interface, public QAccessibleObjectEx +{ + Q_ACCESSIBLE_OBJECT +public: + explicit QAccessibleTable2(QWidget *w); + + virtual ~QAccessibleTable2(); + + QObject *object() const { return view; } + Role role(int child) const; + State state(int child) const; + QString text(Text t, int child) const; + QRect rect(int child) const; + + int childAt(int x, int y) const; + int childCount() const; + int indexOfChild(const QAccessibleInterface *) const; + + int navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const; + Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const; + +#ifndef QT_NO_ACTION + int userActionCount(int child) const; + QString actionText(int action, Text t, int child) const; + bool doAction(int action, int child, const QVariantList ¶ms); +#endif + QVariant invokeMethodEx(Method, int, const QVariantList &) { return QVariant(); } + + // table2 interface + virtual QAccessibleTable2CellInterface *cellAt(int row, int column) const; + virtual QAccessibleInterface *caption() const; + virtual QAccessibleInterface *summary() const; + virtual QString columnDescription(int column) const; + virtual QString rowDescription(int row) const; + virtual int columnCount() const; + virtual int rowCount() const; + virtual QAccessible2::TableModelChange modelChange() const; + + // selection + virtual int selectedCellCount() const; + virtual int selectedColumnCount() const; + virtual int selectedRowCount() const; + virtual QList<QAccessibleTable2CellInterface*> selectedCells() const; + virtual QList<int> selectedColumns() const; + virtual QList<int> selectedRows() const; + virtual bool isColumnSelected(int column) const; + virtual bool isRowSelected(int row) const; + virtual bool selectRow(int row); + virtual bool selectColumn(int column); + virtual bool unselectRow(int row); + virtual bool unselectColumn(int column); + +protected: + virtual void modelReset(); + virtual void rowsInserted(const QModelIndex &parent, int first, int last); + virtual void rowsRemoved(const QModelIndex &parent, int first, int last); + virtual void columnsInserted(const QModelIndex &parent, int first, int last); + virtual void columnsRemoved(const QModelIndex &parent, int first, int last); + virtual void rowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row); + virtual void columnsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column); + +protected: + QAbstractItemView* view; + QAccessible2::TableModelChange lastChange; + inline QAccessibleTable2Cell *cell(const QModelIndex &index) const; + inline QAccessible::Role cellRole() const { + switch (m_role) { + case QAccessible::List: + return QAccessible::ListItem; + case QAccessible::Table: + return QAccessible::Cell; + case QAccessible::Tree: + return QAccessible::TreeItem; + default: + Q_ASSERT(0); + } + return QAccessible::NoRole; + } + + QHeaderView *horizontalHeader() const; + QHeaderView *verticalHeader() const; +private: + // the child index for a model index + inline int logicalIndex(const QModelIndex &index) const; + // the model index from the child index + QAccessibleInterface *childFromLogical(int logicalIndex) const; + QAccessible::Role m_role; +}; + +class QAccessibleTree :public QAccessibleTable2 +{ +public: + explicit QAccessibleTree(QWidget *w) + : QAccessibleTable2(w) + {} + + virtual ~QAccessibleTree() {} + + int childAt(int x, int y) const; + int childCount() const; + int indexOfChild(const QAccessibleInterface *) const; + + int rowCount() const; + + int navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const; + Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const; + + // table2 interface + QAccessibleTable2CellInterface *cellAt(int row, int column) const; + QString rowDescription(int row) const; + bool isRowSelected(int row) const; + bool selectRow(int row); + +private: + QModelIndex indexFromLogical(int row, int column = 0) const; +}; + +class QAccessibleTable2Cell: public QAccessibleTable2CellInterface /*), public QAccessibleTextInterface, public QAccessibleSimpleEditableTextInterface*/ +{ +public: + QAccessibleTable2Cell(QAbstractItemView *view, const QModelIndex &m_index, QAccessible::Role role); + + QObject *object() const { return 0; } + Role role(int child) const; + State state(int child) const; + QRect rect(int child) const; + bool isValid() const; + + int childAt(int, int) const { return 0; } + int childCount() const { return 0; } + int indexOfChild(const QAccessibleInterface *) const { return -1; } + + QString text(Text t, int child) const; + void setText(Text t, int child, const QString &text); + + int navigate(RelationFlag relation, int m_index, QAccessibleInterface **iface) const; + Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const; + + bool isExpandable() const; + +#ifndef QT_NO_ACTION + int userActionCount(int child) const; + QString actionText(int action, Text t, int child) const; + bool doAction(int action, int child, const QVariantList ¶ms); +#endif + + // cell interface + virtual int columnExtent() const; + virtual QList<QAccessibleInterface*> columnHeaderCells() const; + virtual int columnIndex() const; + virtual int rowExtent() const; + virtual QList<QAccessibleInterface*> rowHeaderCells() const; + virtual int rowIndex() const; + virtual bool isSelected() const; + virtual void rowColumnExtents(int *row, int *column, int *rowExtents, int *columnExtents, bool *selected) const; + virtual QAccessibleTable2Interface* table() const; + +private: + QHeaderView *verticalHeader() const; + QHeaderView *horizontalHeader() const; + QAbstractItemView *view; + QModelIndex m_index; + QAccessible::Role m_role; + +friend class QAccessibleTable2; +friend class QAccessibleTree; +}; + + +class QAccessibleTable2HeaderCell: public QAccessibleInterface /*), public QAccessibleTextInterface, public QAccessibleSimpleEditableTextInterface*/ +{ +public: + // For header cells, pass the header view in addition + QAccessibleTable2HeaderCell(QAbstractItemView *view, int index, Qt::Orientation orientation); + + QObject *object() const { return 0; } + Role role(int child) const; + State state(int child) const; + QRect rect(int child) const; + bool isValid() const; + + int childAt(int, int) const { return 0; } + int childCount() const { return 0; } + int indexOfChild(const QAccessibleInterface *) const { return -1; } + + QString text(Text t, int child) const; + void setText(Text t, int child, const QString &text); + + int navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const; + Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const; + +#ifndef QT_NO_ACTION + int userActionCount(int child) const; + QString actionText(int action, Text t, int child) const; + bool doAction(int action, int child, const QVariantList ¶ms); +#endif + +private: + QAbstractItemView *view; + int index; + Qt::Orientation orientation; + +friend class QAccessibleTable2; +friend class QAccessibleTree; +}; + +// This is the corner button on the top left of a table. +// It can be used to select all cells or it is not active at all. +// For now it is ignored. +class QAccessibleTable2CornerButton: public QAccessibleInterface +{ +public: + QAccessibleTable2CornerButton(QAbstractItemView *view_) + :view(view_) + {} + + QObject *object() const { return 0; } + Role role(int child) const { Q_ASSERT(child == 0); return QAccessible::Pane; } + State state(int child) const { Q_ASSERT(child == 0); return QAccessible::Normal; } + QRect rect(int child) const { Q_ASSERT(child == 0); return QRect(); } + bool isValid() const { return true; } + + int childAt(int, int) const { return 0; } + int childCount() const { return 0; } + int indexOfChild(const QAccessibleInterface *) const { return -1; } + + QString text(Text, int) const { return QString(); } + void setText(Text, int, const QString &) {} + + int navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const + { + if (relation == QAccessible::Ancestor && index == 1) { + *iface = QAccessible::queryAccessibleInterface(view); + return 0; + } + return -1; + } + Relation relationTo(int, const QAccessibleInterface *, int) const + { + return QAccessible::Unrelated; + } + +#ifndef QT_NO_ACTION + int userActionCount(int) const { return 0; } + QString actionText(int, Text, int) const { return QString(); } + bool doAction(int, int, const QVariantList &) { return false; } +#endif +private: + QAbstractItemView *view; +}; + + +#endif + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#endif // ACCESSIBLE_ITEMVIEWS_H diff --git a/src/plugins/accessible/widgets/main.cpp b/src/plugins/accessible/widgets/main.cpp index aa5459c..cd17a6e 100644 --- a/src/plugins/accessible/widgets/main.cpp +++ b/src/plugins/accessible/widgets/main.cpp @@ -44,11 +44,13 @@ #include "simplewidgets.h" #include "rangecontrols.h" #include "complexwidgets.h" +#include "itemviews.h" #include <qaccessibleplugin.h> #include <qplugin.h> #include <qpushbutton.h> #include <qtoolbutton.h> +#include <qtreeview.h> #include <qvariant.h> #include <qaccessible.h> @@ -56,6 +58,7 @@ QT_BEGIN_NAMESPACE + class AccessibleFactory : public QAccessiblePlugin { public: @@ -251,6 +254,22 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec iface = new QAccessibleMenu(widget); #endif #ifndef QT_NO_ITEMVIEWS +#ifdef Q_WS_X11 + } else if (classname == QLatin1String("QAbstractItemView")) { + if (qobject_cast<const QTreeView*>(widget)) { + iface = new QAccessibleTree(widget); + } else { + iface = new QAccessibleTable2(widget); + } + } else if (classname == QLatin1String("QWidget") + && widget->objectName() == QLatin1String("qt_scrollarea_viewport") + && qobject_cast<QAbstractItemView*>(widget->parentWidget())) { + if (qobject_cast<const QTreeView*>(widget->parentWidget())) { + iface = new QAccessibleTree(widget->parentWidget()); + } else { + iface = new QAccessibleTable2(widget->parentWidget()); + } +#else } else if (classname == QLatin1String("QHeaderView")) { iface = new QAccessibleHeader(widget); } else if (classname == QLatin1String("QAbstractItemView")) { @@ -259,7 +278,8 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec && widget->objectName() == QLatin1String("qt_scrollarea_viewport") && qobject_cast<QAbstractItemView*>(widget->parentWidget())) { iface = new QAccessibleItemView(widget); -#endif +#endif // Q_WS_X11 +#endif // QT_NO_ITEMVIEWS #ifndef QT_NO_TABBAR } else if (classname == QLatin1String("QTabBar")) { iface = new QAccessibleTabBar(widget); diff --git a/src/plugins/accessible/widgets/widgets.pro b/src/plugins/accessible/widgets/widgets.pro index 79110cb..9632f41 100644 --- a/src/plugins/accessible/widgets/widgets.pro +++ b/src/plugins/accessible/widgets/widgets.pro @@ -7,14 +7,18 @@ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/accessible QTDIR_build:REQUIRES += "contains(QT_CONFIG, accessibility)" SOURCES += main.cpp \ - simplewidgets.cpp \ - rangecontrols.cpp \ - complexwidgets.cpp \ - qaccessiblewidgets.cpp \ - qaccessiblemenu.cpp + simplewidgets.cpp \ + rangecontrols.cpp \ + complexwidgets.cpp \ + qaccessiblewidgets.cpp \ + qaccessiblemenu.cpp \ + itemviews.cpp HEADERS += qaccessiblewidgets.h \ - simplewidgets.h \ - rangecontrols.h \ - complexwidgets.h \ - qaccessiblemenu.h + simplewidgets.h \ + rangecontrols.h \ + complexwidgets.h \ + qaccessiblemenu.h \ + itemviews.h + + |