summaryrefslogtreecommitdiffstats
path: root/src/widgets/accessible/itemviews.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/accessible/itemviews.cpp')
-rw-r--r--src/widgets/accessible/itemviews.cpp1220
1 files changed, 1220 insertions, 0 deletions
diff --git a/src/widgets/accessible/itemviews.cpp b/src/widgets/accessible/itemviews.cpp
new file mode 100644
index 0000000000..36b48cfd05
--- /dev/null
+++ b/src/widgets/accessible/itemviews.cpp
@@ -0,0 +1,1220 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "itemviews.h"
+
+#include <qheaderview.h>
+#include <qtableview.h>
+#include <qlistview.h>
+#include <qtreeview.h>
+#include <private/qtreewidget_p.h>
+
+#ifndef QT_NO_ACCESSIBILITY
+
+QT_BEGIN_NAMESPACE
+
+#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
+ ...
+*/
+
+
+QAbstractItemView *QAccessibleTable::view() const
+{
+ return qobject_cast<QAbstractItemView*>(object());
+}
+
+int QAccessibleTable::logicalIndex(const QModelIndex &index) const
+{
+ if (!view()->model() || !index.isValid())
+ return -1;
+ int vHeader = verticalHeader() ? 1 : 0;
+ int hHeader = horizontalHeader() ? 1 : 0;
+ return (index.row() + hHeader)*(index.model()->columnCount() + vHeader) + (index.column() + vHeader);
+}
+
+QAccessibleTable::QAccessibleTable(QWidget *w)
+ : QAccessibleObject(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;
+ }
+}
+
+bool QAccessibleTable::isValid() const
+{
+ return (view() && !qobject_cast<QWidget*>(view())->d_func()->data.in_destructor);
+}
+
+QAccessibleTable::~QAccessibleTable()
+{
+ Q_FOREACH (QAccessible::Id id, childToId.values())
+ QAccessible::deleteAccessibleInterface(id);
+}
+
+QHeaderView *QAccessibleTable::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 *QAccessibleTable::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;
+}
+
+QAccessibleInterface *QAccessibleTable::cellAt(int row, int column) const
+{
+ if (!view()->model())
+ return 0;
+ Q_ASSERT(role() != QAccessible::Tree);
+ QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
+ if (!index.isValid()) {
+ qWarning() << "QAccessibleTable::cellAt: invalid index: " << index << " for " << view();
+ return 0;
+ }
+ return child(logicalIndex(index));
+}
+
+QAccessibleInterface *QAccessibleTable::caption() const
+{
+ return 0;
+}
+
+QString QAccessibleTable::columnDescription(int column) const
+{
+ if (!view()->model())
+ return QString();
+ return view()->model()->headerData(column, Qt::Horizontal).toString();
+}
+
+int QAccessibleTable::columnCount() const
+{
+ if (!view()->model())
+ return 0;
+ return view()->model()->columnCount();
+}
+
+int QAccessibleTable::rowCount() const
+{
+ if (!view()->model())
+ return 0;
+ return view()->model()->rowCount();
+}
+
+int QAccessibleTable::selectedCellCount() const
+{
+ if (!view()->selectionModel())
+ return 0;
+ return view()->selectionModel()->selectedIndexes().count();
+}
+
+int QAccessibleTable::selectedColumnCount() const
+{
+ if (!view()->selectionModel())
+ return 0;
+ return view()->selectionModel()->selectedColumns().count();
+}
+
+int QAccessibleTable::selectedRowCount() const
+{
+ if (!view()->selectionModel())
+ return 0;
+ return view()->selectionModel()->selectedRows().count();
+}
+
+QString QAccessibleTable::rowDescription(int row) const
+{
+ if (!view()->model())
+ return QString();
+ return view()->model()->headerData(row, Qt::Vertical).toString();
+}
+
+QList<QAccessibleInterface *> QAccessibleTable::selectedCells() const
+{
+ QList<QAccessibleInterface*> cells;
+ if (!view()->selectionModel())
+ return cells;
+ Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedIndexes())
+ cells.append(child(logicalIndex(index)));
+ return cells;
+}
+
+QList<int> QAccessibleTable::selectedColumns() const
+{
+ if (!view()->selectionModel())
+ return QList<int>();
+ QList<int> columns;
+ Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedColumns()) {
+ columns.append(index.column());
+ }
+ return columns;
+}
+
+QList<int> QAccessibleTable::selectedRows() const
+{
+ if (!view()->selectionModel())
+ return QList<int>();
+ QList<int> rows;
+ Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedRows()) {
+ rows.append(index.row());
+ }
+ return rows;
+}
+
+QAccessibleInterface *QAccessibleTable::summary() const
+{
+ return 0;
+}
+
+bool QAccessibleTable::isColumnSelected(int column) const
+{
+ if (!view()->selectionModel())
+ return false;
+ return view()->selectionModel()->isColumnSelected(column, QModelIndex());
+}
+
+bool QAccessibleTable::isRowSelected(int row) const
+{
+ if (!view()->selectionModel())
+ return false;
+ return view()->selectionModel()->isRowSelected(row, QModelIndex());
+}
+
+bool QAccessibleTable::selectRow(int row)
+{
+ if (!view()->model() || !view()->selectionModel())
+ return false;
+ QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
+
+ if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns)
+ return false;
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::NoSelection:
+ return false;
+ case QAbstractItemView::SingleSelection:
+ if (view()->selectionBehavior() != QAbstractItemView::SelectRows && columnCount() > 1 )
+ return false;
+ view()->clearSelection();
+ break;
+ case QAbstractItemView::ContiguousSelection:
+ if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex()))
+ && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex()))
+ view()->clearSelection();
+ break;
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ return true;
+}
+
+bool QAccessibleTable::selectColumn(int column)
+{
+ if (!view()->model() || !view()->selectionModel())
+ return false;
+ QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
+
+ if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectRows)
+ return false;
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::NoSelection:
+ return false;
+ case QAbstractItemView::SingleSelection:
+ if (view()->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1)
+ return false;
+ case QAbstractItemView::ContiguousSelection:
+ if ((!column || !view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex()))
+ && !view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex()))
+ view()->clearSelection();
+ break;
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ return true;
+}
+
+bool QAccessibleTable::unselectRow(int row)
+{
+ if (!view()->model() || !view()->selectionModel())
+ return false;
+
+ QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
+ if (!index.isValid())
+ return false;
+
+ QItemSelection selection(index, index);
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::SingleSelection:
+ //In SingleSelection and ContiguousSelection once an item
+ //is selected, there's no way for the user to unselect all items
+ if (selectedRowCount() == 1)
+ return false;
+ break;
+ case QAbstractItemView::ContiguousSelection:
+ if (selectedRowCount() == 1)
+ return false;
+
+ if ((!row || view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex()))
+ && view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) {
+ //If there are rows selected both up the current row and down the current rown,
+ //the ones which are down the current row will be deselected
+ selection = QItemSelection(index, view()->model()->index(rowCount() - 1, 0, view()->rootIndex()));
+ }
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
+ return true;
+}
+
+bool QAccessibleTable::unselectColumn(int column)
+{
+ if (!view()->model() || !view()->selectionModel())
+ return false;
+
+ QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
+ if (!index.isValid())
+ return false;
+
+ QItemSelection selection(index, index);
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::SingleSelection:
+ //In SingleSelection and ContiguousSelection once an item
+ //is selected, there's no way for the user to unselect all items
+ if (selectedColumnCount() == 1)
+ return false;
+ break;
+ case QAbstractItemView::ContiguousSelection:
+ if (selectedColumnCount() == 1)
+ return false;
+
+ if ((!column || view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex()))
+ && view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) {
+ //If there are columns selected both at the left of the current row and at the right
+ //of the current rown, the ones which are at the right will be deselected
+ selection = QItemSelection(index, view()->model()->index(0, columnCount() - 1, view()->rootIndex()));
+ }
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns);
+ return true;
+}
+
+QAccessible::Role QAccessibleTable::role() const
+{
+ return m_role;
+}
+
+QAccessible::State QAccessibleTable::state() const
+{
+ return QAccessible::State();
+}
+
+QAccessibleInterface *QAccessibleTable::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 child(logicalIndex(index));
+ }
+ return 0;
+}
+
+int QAccessibleTable::childCount() const
+{
+ if (!view()->model())
+ return 0;
+ int vHeader = verticalHeader() ? 1 : 0;
+ int hHeader = horizontalHeader() ? 1 : 0;
+ return (view()->model()->rowCount()+hHeader) * (view()->model()->columnCount()+vHeader);
+}
+
+int QAccessibleTable::indexOfChild(const QAccessibleInterface *iface) const
+{
+ if (!view()->model())
+ return -1;
+ QAccessibleInterface *parent = iface->parent();
+ if (parent->object() != view())
+ return -1;
+
+ Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class
+ if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
+ const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface);
+ return logicalIndex(cell->m_index);
+ } else if (iface->role() == QAccessible::ColumnHeader){
+ const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
+ return cell->index + (verticalHeader() ? 1 : 0);
+ } else if (iface->role() == QAccessible::RowHeader){
+ const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
+ return (cell->index + 1) * (view()->model()->columnCount() + 1);
+ } else if (iface->role() == QAccessible::Pane) {
+ return 0; // corner button
+ } else {
+ qWarning() << "WARNING QAccessibleTable::indexOfChild Fix my children..."
+ << iface->role() << iface->text(QAccessible::Name);
+ }
+ // FIXME: we are in denial of our children. this should stop.
+ return -1;
+}
+
+QString QAccessibleTable::text(QAccessible::Text t) const
+{
+ if (t == QAccessible::Description)
+ return view()->accessibleDescription();
+ return view()->accessibleName();
+}
+
+QRect QAccessibleTable::rect() const
+{
+ if (!view()->isVisible())
+ return QRect();
+ QPoint pos = view()->mapToGlobal(QPoint(0, 0));
+ return QRect(pos.x(), pos.y(), view()->width(), view()->height());
+}
+
+QAccessibleInterface *QAccessibleTable::parent() const
+{
+ if (view() && view()->parent()) {
+ if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) {
+ return QAccessible::queryAccessibleInterface(view()->parent()->parent());
+ }
+ return QAccessible::queryAccessibleInterface(view()->parent());
+ }
+ return 0;
+}
+
+QAccessibleInterface *QAccessibleTable::child(int logicalIndex) const
+{
+ if (!view()->model())
+ return 0;
+
+ if (childToId.contains(logicalIndex)) {
+ QAccessible::Id id = childToId.value(logicalIndex);
+ return QAccessible::accessibleInterface(id);
+ }
+
+ int vHeader = verticalHeader() ? 1 : 0;
+ int hHeader = horizontalHeader() ? 1 : 0;
+
+ int columns = view()->model()->columnCount() + vHeader;
+
+ int row = logicalIndex / columns;
+ int column = logicalIndex % columns;
+
+ QAccessibleInterface *iface = 0;
+
+ if (vHeader) {
+ if (column == 0) {
+ if (hHeader && row == 0) {
+ iface = new QAccessibleTableCornerButton(view());
+ } else {
+ iface = new QAccessibleTableHeaderCell(view(), row - hHeader, Qt::Vertical);
+ }
+ }
+ --column;
+ }
+ if (!iface && hHeader) {
+ if (row == 0) {
+ iface = new QAccessibleTableHeaderCell(view(), column, Qt::Horizontal);
+ }
+ --row;
+ }
+
+ if (!iface) {
+ QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
+ if (!index.isValid()) {
+ qWarning() << "QAccessibleTable::child: Invalid index at: " << row << column;
+ return 0;
+ }
+ iface = new QAccessibleTableCell(view(), index, cellRole());
+ }
+
+ QAccessible::registerAccessibleInterface(iface);
+ childToId.insert(logicalIndex, QAccessible::uniqueId(iface));
+ return iface;
+}
+
+void *QAccessibleTable::interface_cast(QAccessible::InterfaceType t)
+{
+ if (t == QAccessible::TableInterface)
+ return static_cast<QAccessibleTableInterface*>(this);
+ return 0;
+}
+
+void QAccessibleTable::modelChange(QAccessibleTableModelChangeEvent *event)
+{
+ // if there is no cache yet, we don't update anything
+ if (childToId.isEmpty())
+ return;
+
+ switch (event->modelChangeType()) {
+ case QAccessibleTableModelChangeEvent::ModelReset:
+ Q_FOREACH (QAccessible::Id id, childToId.values())
+ QAccessible::deleteAccessibleInterface(id);
+ childToId.clear();
+ break;
+
+ // rows are inserted: move every row after that
+ case QAccessibleTableModelChangeEvent::RowsInserted:
+ case QAccessibleTableModelChangeEvent::ColumnsInserted: {
+ int newRows = event->lastRow() - event->firstRow() + 1;
+ int newColumns = event->lastColumn() - event->firstColumn() + 1;
+
+ ChildCache newCache;
+ ChildCache::ConstIterator iter = childToId.constBegin();
+
+ while (iter != childToId.constEnd()) {
+ QAccessible::Id id = iter.value();
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(id);
+ Q_ASSERT(iface);
+ if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
+ Q_ASSERT(iface->tableCellInterface());
+ QAccessibleTableCell *cell = static_cast<QAccessibleTableCell*>(iface->tableCellInterface());
+ if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsInserted
+ && cell->m_index.row() >= event->firstRow()) {
+ int newRow = cell->m_index.row() + newRows;
+ cell->m_index = cell->m_index.sibling(newRow, cell->m_index.column());
+ } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsInserted
+ && cell->m_index.column() >= event->firstColumn()) {
+ int newColumn = cell->m_index.column() + newColumns;
+ cell->m_index = cell->m_index.sibling(cell->m_index.row(), newColumn);
+ }
+ } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsInserted
+ && iface->role() == QAccessible::RowHeader) {
+ QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface);
+ if (cell->index >= event->firstRow()) {
+ cell->index += newRows;
+ }
+ } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsInserted
+ && iface->role() == QAccessible::ColumnHeader) {
+ QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface);
+ if (cell->index >= event->firstColumn()) {
+ cell->index += newColumns;
+ }
+ }
+ if (indexOfChild(iface) >= 0) {
+ newCache.insert(indexOfChild(iface), id);
+ } else {
+ // ### This should really not happen,
+ // but it might if the view has a root index set.
+ // This needs to be fixed.
+ QAccessible::deleteAccessibleInterface(id);
+ }
+ ++iter;
+ }
+ childToId = newCache;
+ break;
+ }
+
+ case QAccessibleTableModelChangeEvent::ColumnsRemoved:
+ case QAccessibleTableModelChangeEvent::RowsRemoved: {
+ int deletedColumns = event->lastColumn() - event->firstColumn() + 1;
+ int deletedRows = event->lastRow() - event->firstRow() + 1;
+ ChildCache newCache;
+ ChildCache::ConstIterator iter = childToId.constBegin();
+ while (iter != childToId.constEnd()) {
+ QAccessible::Id id = iter.value();
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(id);
+ Q_ASSERT(iface);
+ if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
+ Q_ASSERT(iface->tableCellInterface());
+ QAccessibleTableCell *cell = static_cast<QAccessibleTableCell*>(iface->tableCellInterface());
+ if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsRemoved) {
+ if (cell->m_index.row() < event->firstRow()) {
+ newCache.insert(indexOfChild(cell), id);
+ } else if (cell->m_index.row() > event->lastRow()) {
+ int newRow = cell->m_index.row() - deletedRows;
+ cell->m_index = cell->m_index.sibling(newRow, cell->m_index.column());
+ newCache.insert(indexOfChild(cell), id);
+ } else {
+ QAccessible::deleteAccessibleInterface(id);
+ }
+ } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsRemoved) {
+ if (cell->m_index.column() < event->firstColumn()) {
+ newCache.insert(indexOfChild(cell), id);
+ } else if (cell->m_index.column() > event->lastColumn()) {
+ int newColumn = cell->m_index.column() - deletedColumns;
+ cell->m_index = cell->m_index.sibling(cell->m_index.row(), newColumn);
+ newCache.insert(indexOfChild(cell), id);
+ } else {
+ QAccessible::deleteAccessibleInterface(id);
+ }
+ }
+ } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsRemoved
+ && iface->role() == QAccessible::RowHeader) {
+ QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface);
+ if (cell->index < event->firstRow()) {
+ newCache.insert(indexOfChild(cell), id);
+ } else if (cell->index > event->lastRow()) {
+ cell->index -= deletedRows;
+ newCache.insert(indexOfChild(cell), id);
+ } else {
+ QAccessible::deleteAccessibleInterface(id);
+ }
+ } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsRemoved
+ && iface->role() == QAccessible::ColumnHeader) {
+ QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface);
+ if (cell->index < event->firstColumn()) {
+ newCache.insert(indexOfChild(cell), id);
+ } else if (cell->index > event->lastColumn()) {
+ cell->index -= deletedColumns;
+ newCache.insert(indexOfChild(cell), id);
+ } else {
+ QAccessible::deleteAccessibleInterface(id);
+ }
+ }
+ ++iter;
+ }
+ childToId = newCache;
+ break;
+ }
+
+ case QAccessibleTableModelChangeEvent::DataChanged:
+ // nothing to do in this case
+ break;
+ }
+}
+
+// TREE VIEW
+
+QModelIndex QAccessibleTree::indexFromLogical(int row, int column) const
+{
+ if (!isValid() || !view()->model())
+ return QModelIndex();
+
+ const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
+ if ((row < 0) || (column < 0) || (treeView->d_func()->viewItems.count() <= row)) {
+ qWarning() << "QAccessibleTree::indexFromLogical: invalid index: " << row << column << " for " << treeView;
+ return QModelIndex();
+ }
+ 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;
+}
+
+QAccessibleInterface *QAccessibleTree::childAt(int x, int y) const
+{
+ if (!view()->model())
+ return 0;
+ 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 0;
+
+ 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;
+ return child(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();
+}
+
+
+QAccessibleInterface *QAccessibleTree::child(int logicalIndex) const
+{
+ if (logicalIndex < 0 || !view()->model() || !view()->model()->columnCount())
+ return 0;
+
+ QAccessibleInterface *iface = 0;
+ int index = logicalIndex;
+
+ if (horizontalHeader()) {
+ if (index < view()->model()->columnCount()) {
+ iface = new QAccessibleTableHeaderCell(view(), index, Qt::Horizontal);
+ } else {
+ index -= view()->model()->columnCount();
+ }
+ }
+
+ if (!iface) {
+ int row = index / view()->model()->columnCount();
+ int column = index % view()->model()->columnCount();
+ QModelIndex modelIndex = indexFromLogical(row, column);
+ if (!modelIndex.isValid())
+ return 0;
+ iface = new QAccessibleTableCell(view(), modelIndex, cellRole());
+ }
+ QAccessible::registerAccessibleInterface(iface);
+ // ### FIXME: get interfaces from the cache instead of re-creating them
+ return iface;
+}
+
+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 (!view()->model())
+ return -1;
+ QAccessibleInterface *parent = iface->parent();
+ if (parent->object() != view())
+ return -1;
+
+ if (iface->role() == QAccessible::TreeItem) {
+ const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(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;
+ return index;
+ } else if (iface->role() == QAccessible::ColumnHeader){
+ const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
+ return cell->index;
+ } else {
+ qWarning() << "WARNING QAccessibleTable::indexOfChild invalid child"
+ << iface->role() << iface->text(QAccessible::Name);
+ }
+ // FIXME: add scrollbars and don't just ignore them
+ return -1;
+}
+
+QAccessibleInterface *QAccessibleTree::cellAt(int row, int column) const
+{
+ QModelIndex index = indexFromLogical(row, column);
+ if (!index.isValid()) {
+ qWarning() << "Requested invalid tree cell: " << row << column;
+ return 0;
+ }
+ const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
+ Q_ASSERT(treeView);
+ int logicalIndex = treeView->d_func()->accessibleTable2Index(index);
+
+ return child(logicalIndex); // FIXME ### new QAccessibleTableCell(view(), index, cellRole());
+}
+
+QString QAccessibleTree::rowDescription(int) const
+{
+ return QString(); // no headers for rows in trees
+}
+
+bool QAccessibleTree::isRowSelected(int row) const
+{
+ if (!view()->selectionModel())
+ return false;
+ QModelIndex index = indexFromLogical(row);
+ return view()->selectionModel()->isRowSelected(index.row(), index.parent());
+}
+
+bool QAccessibleTree::selectRow(int row)
+{
+ if (!view()->selectionModel())
+ return false;
+ QModelIndex index = indexFromLogical(row);
+
+ if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns)
+ return false;
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::NoSelection:
+ return false;
+ case QAbstractItemView::SingleSelection:
+ if ((view()->selectionBehavior() != QAbstractItemView::SelectRows) && (columnCount() > 1))
+ return false;
+ view()->clearSelection();
+ break;
+ case QAbstractItemView::ContiguousSelection:
+ if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex()))
+ && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex()))
+ view()->clearSelection();
+ break;
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ return true;
+}
+
+// TABLE CELL
+
+QAccessibleTableCell::QAccessibleTableCell(QAbstractItemView *view_, const QModelIndex &index_, QAccessible::Role role_)
+ : /* QAccessibleSimpleEditableTextInterface(this), */ view(view_), m_index(index_), m_role(role_)
+{
+ if (!index_.isValid())
+ qWarning() << "QAccessibleTableCell::QAccessibleTableCell with invalid index: " << index_;
+}
+
+void *QAccessibleTableCell::interface_cast(QAccessible::InterfaceType t)
+{
+ if (t == QAccessible::TableCellInterface)
+ return static_cast<QAccessibleTableCellInterface*>(this);
+ if (t == QAccessible::ActionInterface)
+ return static_cast<QAccessibleActionInterface*>(this);
+ return 0;
+}
+
+int QAccessibleTableCell::columnExtent() const { return 1; }
+int QAccessibleTableCell::rowExtent() const { return 1; }
+
+QList<QAccessibleInterface*> QAccessibleTableCell::rowHeaderCells() const
+{
+ QList<QAccessibleInterface*> headerCell;
+ if (verticalHeader()) {
+ // FIXME
+ headerCell.append(new QAccessibleTableHeaderCell(view, m_index.row(), Qt::Vertical));
+ }
+ return headerCell;
+}
+
+QList<QAccessibleInterface*> QAccessibleTableCell::columnHeaderCells() const
+{
+ QList<QAccessibleInterface*> headerCell;
+ if (horizontalHeader()) {
+ // FIXME
+ headerCell.append(new QAccessibleTableHeaderCell(view, m_index.column(), Qt::Horizontal));
+ }
+ return headerCell;
+}
+
+QHeaderView *QAccessibleTableCell::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 *QAccessibleTableCell::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 QAccessibleTableCell::columnIndex() const
+{
+ return m_index.column();
+}
+
+int QAccessibleTableCell::rowIndex() const
+{
+ if (role() == 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 QAccessibleTableCell::isSelected() const
+{
+ return view->selectionModel()->isSelected(m_index);
+}
+
+QStringList QAccessibleTableCell::actionNames() const
+{
+ QStringList names;
+ names << toggleAction();
+ return names;
+}
+
+void QAccessibleTableCell::doAction(const QString& actionName)
+{
+ if (actionName == toggleAction()) {
+ if (isSelected())
+ unselectCell();
+ else
+ selectCell();
+ }
+}
+
+QStringList QAccessibleTableCell::keyBindingsForAction(const QString &) const
+{
+ return QStringList();
+}
+
+
+void QAccessibleTableCell::selectCell()
+{
+ QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
+ if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection))
+ return;
+ Q_ASSERT(table());
+ QAccessibleTableInterface *cellTable = table()->tableInterface();
+
+ switch (view->selectionBehavior()) {
+ case QAbstractItemView::SelectItems:
+ break;
+ case QAbstractItemView::SelectColumns:
+ if (cellTable)
+ cellTable->selectColumn(m_index.column());
+ return;
+ case QAbstractItemView::SelectRows:
+ if (cellTable)
+ cellTable->selectRow(m_index.row());
+ return;
+ }
+
+ if (selectionMode == QAbstractItemView::SingleSelection) {
+ view->clearSelection();
+ }
+
+ view->selectionModel()->select(m_index, QItemSelectionModel::Select);
+}
+
+void QAccessibleTableCell::unselectCell()
+{
+
+ QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
+ if (!m_index.isValid() || (selectionMode & QAbstractItemView::NoSelection))
+ return;
+
+ QAccessibleTableInterface *cellTable = table()->tableInterface();
+
+ switch (view->selectionBehavior()) {
+ case QAbstractItemView::SelectItems:
+ break;
+ case QAbstractItemView::SelectColumns:
+ if (cellTable)
+ cellTable->unselectColumn(m_index.column());
+ return;
+ case QAbstractItemView::SelectRows:
+ if (cellTable)
+ cellTable->unselectRow(m_index.row());
+ return;
+ }
+
+ //If the mode is not MultiSelection or ExtendedSelection and only
+ //one cell is selected it cannot be unselected by the user
+ if ((selectionMode != QAbstractItemView::MultiSelection)
+ && (selectionMode != QAbstractItemView::ExtendedSelection)
+ && (view->selectionModel()->selectedIndexes().count() <= 1))
+ return;
+
+ view->selectionModel()->select(m_index, QItemSelectionModel::Deselect);
+}
+
+QAccessibleInterface *QAccessibleTableCell::table() const
+{
+ return QAccessible::queryAccessibleInterface(view);
+}
+
+QAccessible::Role QAccessibleTableCell::role() const
+{
+ return m_role;
+}
+
+QAccessible::State QAccessibleTableCell::state() const
+{
+ QAccessible::State st;
+ QRect globalRect = view->rect();
+ globalRect.translate(view->mapToGlobal(QPoint(0,0)));
+ if (!globalRect.intersects(rect()))
+ st.invisible = true;
+
+ if (view->selectionModel()->isSelected(m_index))
+ st.selected = true;
+ if (view->selectionModel()->currentIndex() == m_index)
+ st.focused = true;
+ if (m_index.model()->data(m_index, Qt::CheckStateRole).toInt() == Qt::Checked)
+ st.checked = true;
+
+ Qt::ItemFlags flags = m_index.flags();
+ if (flags & Qt::ItemIsSelectable) {
+ st.selectable = true;
+ st.focusable = true;
+ if (view->selectionMode() == QAbstractItemView::MultiSelection)
+ st.multiSelectable = true;
+ if (view->selectionMode() == QAbstractItemView::ExtendedSelection)
+ st.extSelectable = true;
+ }
+ if (m_role == QAccessible::TreeItem) {
+ const QTreeView *treeView = qobject_cast<const QTreeView*>(view);
+ if (treeView->model()->hasChildren(m_index))
+ st.expandable = true;
+ if (treeView->isExpanded(m_index))
+ st.expanded = true;
+ }
+ return st;
+}
+
+
+QRect QAccessibleTableCell::rect() const
+{
+ 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 QAccessibleTableCell::text(QAccessible::Text t) const
+{
+ QAbstractItemModel *model = view->model();
+ QString value;
+ switch (t) {
+ 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 QAccessibleTableCell::setText(QAccessible::Text /*t*/, const QString &text)
+{
+ if (!(m_index.flags() & Qt::ItemIsEditable))
+ return;
+ view->model()->setData(m_index, text);
+}
+
+bool QAccessibleTableCell::isValid() const
+{
+ return view && view->model() && m_index.isValid();
+}
+
+QAccessibleInterface *QAccessibleTableCell::parent() const
+{
+ return QAccessible::queryAccessibleInterface(view);
+}
+
+QAccessibleInterface *QAccessibleTableCell::child(int) const
+{
+ return 0;
+}
+
+QAccessibleTableHeaderCell::QAccessibleTableHeaderCell(QAbstractItemView *view_, int index_, Qt::Orientation orientation_)
+ : view(view_), index(index_), orientation(orientation_)
+{
+ Q_ASSERT(index_ >= 0);
+}
+
+QAccessible::Role QAccessibleTableHeaderCell::role() const
+{
+ if (orientation == Qt::Horizontal)
+ return QAccessible::ColumnHeader;
+ return QAccessible::RowHeader;
+}
+
+QAccessible::State QAccessibleTableHeaderCell::state() const
+{
+ QAccessible::State s;
+ if (QHeaderView *h = headerView()) {
+ s.invisible = !h->testAttribute(Qt::WA_WState_Visible);
+ s.disabled = !h->isEnabled();
+ }
+ return s;
+}
+
+QRect QAccessibleTableHeaderCell::rect() const
+{
+ 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
+ }
+ if (!header)
+ return QRect();
+ 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 QAccessibleTableHeaderCell::text(QAccessible::Text t) const
+{
+ QAbstractItemModel *model = view->model();
+ QString value;
+ switch (t) {
+ 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 QAccessibleTableHeaderCell::setText(QAccessible::Text, const QString &)
+{
+ return;
+}
+
+bool QAccessibleTableHeaderCell::isValid() const
+{
+ return view && view->model() && (index >= 0)
+ && ((orientation == Qt::Horizontal) ? (index < view->model()->columnCount()) : (index < view->model()->rowCount()));
+}
+
+QAccessibleInterface *QAccessibleTableHeaderCell::parent() const
+{
+ return QAccessible::queryAccessibleInterface(view);
+}
+
+QAccessibleInterface *QAccessibleTableHeaderCell::child(int) const
+{
+ return 0;
+}
+
+QHeaderView *QAccessibleTableHeaderCell::headerView() const
+{
+ 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
+ }
+ return header;
+}
+
+#endif // QT_NO_ITEMVIEWS
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ACCESSIBILITY