1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the plugins of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "itemviews.h"
44
#include <qheaderview.h>
45
#include <qtableview.h>
46
#include <qlistview.h>
47
#include <qtreeview.h>
48
#include <private/qtreewidget_p.h>
49
#include <qaccessible2.h>
52
#ifndef QT_NO_ACCESSIBILITY
56
QString Q_GUI_EXPORT qt_accStripAmp(const QString &text);
58
#ifndef QT_NO_ITEMVIEWS
60
Implementation of the IAccessible2 table2 interface. Much simpler than
61
the other table interfaces since there is only the main table and cells:
71
QAbstractItemView *QAccessibleTable::view() const
73
return qobject_cast<QAbstractItemView*>(object());
76
int QAccessibleTable::logicalIndex(const QModelIndex &index) const
78
if (!view()->model() || !index.isValid())
80
int vHeader = verticalHeader() ? 1 : 0;
81
int hHeader = horizontalHeader() ? 1 : 0;
82
return (index.row() + hHeader)*(index.model()->columnCount() + vHeader) + (index.column() + vHeader);
85
QAccessibleInterface *QAccessibleTable::childFromLogical(int logicalIndex) const
90
int vHeader = verticalHeader() ? 1 : 0;
91
int hHeader = horizontalHeader() ? 1 : 0;
93
int columns = view()->model()->columnCount() + vHeader;
95
int row = logicalIndex / columns;
96
int column = logicalIndex % columns;
101
return new QAccessibleTableCornerButton(view());
103
return new QAccessibleTableHeaderCell(view(), row-1, Qt::Vertical);
109
return new QAccessibleTableHeaderCell(view(), column, Qt::Horizontal);
114
QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
115
if (!index.isValid()) {
116
qWarning() << "QAccessibleTable::childFromLogical: Invalid index at: " << row << column;
119
return new QAccessibleTableCell(view(), index, cellRole());
122
QAccessibleTable::QAccessibleTable(QWidget *w)
123
: QAccessibleObject(w)
127
if (qobject_cast<const QTableView*>(view())) {
128
m_role = QAccessible::Table;
129
} else if (qobject_cast<const QTreeView*>(view())) {
130
m_role = QAccessible::Tree;
131
} else if (qobject_cast<const QListView*>(view())) {
132
m_role = QAccessible::List;
134
// is this our best guess?
135
m_role = QAccessible::Table;
139
QAccessibleTable::~QAccessibleTable()
143
QHeaderView *QAccessibleTable::horizontalHeader() const
145
QHeaderView *header = 0;
147
#ifndef QT_NO_TABLEVIEW
148
} else if (const QTableView *tv = qobject_cast<const QTableView*>(view())) {
149
header = tv->horizontalHeader();
151
#ifndef QT_NO_TREEVIEW
152
} else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view())) {
153
header = tv->header();
159
QHeaderView *QAccessibleTable::verticalHeader() const
161
QHeaderView *header = 0;
163
#ifndef QT_NO_TABLEVIEW
164
} else if (const QTableView *tv = qobject_cast<const QTableView*>(view())) {
165
header = tv->verticalHeader();
171
QAccessibleTableCell *QAccessibleTable::cell(const QModelIndex &index) const
174
return new QAccessibleTableCell(view(), index, cellRole());
178
QAccessibleInterface *QAccessibleTable::cellAt(int row, int column) const
180
if (!view()->model())
182
Q_ASSERT(role() != QAccessible::Tree);
183
QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
184
if (!index.isValid()) {
185
qWarning() << "QAccessibleTable::cellAt: invalid index: " << index << " for " << view();
191
QAccessibleInterface *QAccessibleTable::caption() const
196
QString QAccessibleTable::columnDescription(int column) const
198
if (!view()->model())
200
return view()->model()->headerData(column, Qt::Horizontal).toString();
203
int QAccessibleTable::columnCount() const
205
if (!view()->model())
207
return view()->model()->columnCount();
210
int QAccessibleTable::rowCount() const
212
if (!view()->model())
214
return view()->model()->rowCount();
217
int QAccessibleTable::selectedCellCount() const
219
if (!view()->selectionModel())
221
return view()->selectionModel()->selectedIndexes().count();
224
int QAccessibleTable::selectedColumnCount() const
226
if (!view()->selectionModel())
228
return view()->selectionModel()->selectedColumns().count();
231
int QAccessibleTable::selectedRowCount() const
233
if (!view()->selectionModel())
235
return view()->selectionModel()->selectedRows().count();
238
QString QAccessibleTable::rowDescription(int row) const
240
if (!view()->model())
242
return view()->model()->headerData(row, Qt::Vertical).toString();
245
QList<QAccessibleInterface *> QAccessibleTable::selectedCells() const
247
QList<QAccessibleInterface*> cells;
248
if (!view()->selectionModel())
250
Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedIndexes()) {
251
cells.append(cell(index));
256
QList<int> QAccessibleTable::selectedColumns() const
258
if (!view()->selectionModel())
261
Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedColumns()) {
262
columns.append(index.column());
267
QList<int> QAccessibleTable::selectedRows() const
269
if (!view()->selectionModel())
272
Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedRows()) {
273
rows.append(index.row());
278
QAccessibleInterface *QAccessibleTable::summary() const
283
bool QAccessibleTable::isColumnSelected(int column) const
285
if (!view()->selectionModel())
287
return view()->selectionModel()->isColumnSelected(column, QModelIndex());
290
bool QAccessibleTable::isRowSelected(int row) const
292
if (!view()->selectionModel())
294
return view()->selectionModel()->isRowSelected(row, QModelIndex());
297
bool QAccessibleTable::selectRow(int row)
299
if (!view()->model() || !view()->selectionModel())
301
QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
302
if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
304
view()->selectionModel()->select(index, QItemSelectionModel::Select);
308
bool QAccessibleTable::selectColumn(int column)
310
if (!view()->model() || !view()->selectionModel())
312
QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
313
if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
315
view()->selectionModel()->select(index, QItemSelectionModel::Select);
319
bool QAccessibleTable::unselectRow(int row)
321
if (!view()->model() || !view()->selectionModel())
323
QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
324
if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
326
view()->selectionModel()->select(index, QItemSelectionModel::Deselect);
330
bool QAccessibleTable::unselectColumn(int column)
332
if (!view()->model() || !view()->selectionModel())
334
QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
335
if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
337
view()->selectionModel()->select(index, QItemSelectionModel::Columns & QItemSelectionModel::Deselect);
341
QAccessible::Role QAccessibleTable::role() const
346
QAccessible::State QAccessibleTable::state() const
348
return QAccessible::State();
351
QAccessibleInterface *QAccessibleTable::childAt(int x, int y) const
353
QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0));
354
QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset);
355
// FIXME: if indexPosition < 0 in one coordinate, return header
357
QModelIndex index = view()->indexAt(indexPosition);
358
if (index.isValid()) {
359
return childFromLogical(logicalIndex(index));
364
int QAccessibleTable::childCount() const
366
if (!view()->model())
368
int vHeader = verticalHeader() ? 1 : 0;
369
int hHeader = horizontalHeader() ? 1 : 0;
370
return (view()->model()->rowCount()+hHeader) * (view()->model()->columnCount()+vHeader);
373
int QAccessibleTable::indexOfChild(const QAccessibleInterface *iface) const
375
if (!view()->model())
377
QSharedPointer<QAccessibleInterface> parent(iface->parent());
378
if (parent->object() != view())
381
Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class
382
if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
383
const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface);
384
return logicalIndex(cell->m_index);
385
} else if (iface->role() == QAccessible::ColumnHeader){
386
const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
387
return cell->index + (verticalHeader() ? 1 : 0);
388
} else if (iface->role() == QAccessible::RowHeader){
389
const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
390
return (cell->index + 1) * (view()->model()->rowCount() + 1);
391
} else if (iface->role() == QAccessible::Pane) {
392
return 0; // corner button
394
qWarning() << "WARNING QAccessibleTable::indexOfChild Fix my children..."
395
<< iface->role() << iface->text(QAccessible::Name);
397
// FIXME: we are in denial of our children. this should stop.
401
QString QAccessibleTable::text(QAccessible::Text t) const
403
if (t == QAccessible::Description)
404
return view()->accessibleDescription();
405
return view()->accessibleName();
408
QRect QAccessibleTable::rect() const
410
if (!view()->isVisible())
412
QPoint pos = view()->mapToGlobal(QPoint(0, 0));
413
return QRect(pos.x(), pos.y(), view()->width(), view()->height());
416
QAccessibleInterface *QAccessibleTable::parent() const
418
if (view()->parent()) {
419
if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) {
420
return QAccessible::queryAccessibleInterface(view()->parent()->parent());
422
return QAccessible::queryAccessibleInterface(view()->parent());
427
QAccessibleInterface *QAccessibleTable::child(int index) const
429
return childFromLogical(index);
432
void *QAccessibleTable::interface_cast(QAccessible::InterfaceType t)
434
if (t == QAccessible::TableInterface)
435
return static_cast<QAccessibleTableInterface*>(this);
441
QModelIndex QAccessibleTree::indexFromLogical(int row, int column) const
443
if (!isValid() || !view()->model())
444
return QModelIndex();
446
const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
447
if ((row < 0) || (column < 0) || (treeView->d_func()->viewItems.count() <= row)) {
448
qWarning() << "QAccessibleTree::indexFromLogical: invalid index: " << row << column << " for " << treeView;
449
return QModelIndex();
451
QModelIndex modelIndex = treeView->d_func()->viewItems.at(row).index;
453
if (modelIndex.isValid() && column > 0) {
454
modelIndex = view()->model()->index(modelIndex.row(), column, modelIndex.parent());
459
QAccessibleInterface *QAccessibleTree::childAt(int x, int y) const
461
if (!view()->model())
463
QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0));
464
QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset);
466
QModelIndex index = view()->indexAt(indexPosition);
467
if (!index.isValid())
470
const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
471
int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0);
472
int column = index.column();
474
int i = row * view()->model()->columnCount() + column;
478
int QAccessibleTree::childCount() const
480
const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
482
if (!view()->model())
485
int hHeader = horizontalHeader() ? 1 : 0;
486
return (treeView->d_func()->viewItems.count() + hHeader)* view()->model()->columnCount();
490
QAccessibleInterface *QAccessibleTree::child(int index) const
492
if ((index < 0) || (!view()->model()))
494
int hHeader = horizontalHeader() ? 1 : 0;
497
if (index < view()->model()->columnCount()) {
498
return new QAccessibleTableHeaderCell(view(), index, Qt::Horizontal);
500
index -= view()->model()->columnCount();
504
int row = index / view()->model()->columnCount();
505
int column = index % view()->model()->columnCount();
506
QModelIndex modelIndex = indexFromLogical(row, column);
507
if (modelIndex.isValid()) {
508
return cell(modelIndex);
513
int QAccessibleTree::rowCount() const
515
const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
517
return treeView->d_func()->viewItems.count();
520
int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const
522
if (!view()->model())
524
QSharedPointer<QAccessibleInterface> parent(iface->parent());
525
if (parent->object() != view())
528
if (iface->role() == QAccessible::TreeItem) {
529
const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface);
530
const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
532
int row = treeView->d_func()->viewIndex(cell->m_index) + (horizontalHeader() ? 1 : 0);
533
int column = cell->m_index.column();
535
int index = row * view()->model()->columnCount() + column;
536
//qDebug() << "QAccessibleTree::indexOfChild r " << row << " c " << column << "index " << index;
537
Q_ASSERT(index >= treeView->model()->columnCount());
539
} else if (iface->role() == QAccessible::ColumnHeader){
540
const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
541
//qDebug() << "QAccessibleTree::indexOfChild header " << cell->index;
544
qWarning() << "WARNING QAccessibleTable::indexOfChild invalid child"
545
<< iface->role() << iface->text(QAccessible::Name);
547
// FIXME: add scrollbars and don't just ignore them
551
QAccessibleInterface *QAccessibleTree::cellAt(int row, int column) const
553
QModelIndex index = indexFromLogical(row, column);
554
if (!index.isValid()) {
555
qWarning() << "Requested invalid tree cell: " << row << column;
558
return new QAccessibleTableCell(view(), index, cellRole());
561
QString QAccessibleTree::rowDescription(int) const
563
return QString(); // no headers for rows in trees
566
bool QAccessibleTree::isRowSelected(int row) const
568
if (!view()->selectionModel())
570
QModelIndex index = indexFromLogical(row);
571
return view()->selectionModel()->isRowSelected(index.row(), index.parent());
574
bool QAccessibleTree::selectRow(int row)
576
if (!view()->selectionModel())
578
QModelIndex index = indexFromLogical(row);
579
if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
581
view()->selectionModel()->select(index, QItemSelectionModel::Select);
587
QAccessibleTableCell::QAccessibleTableCell(QAbstractItemView *view_, const QModelIndex &index_, QAccessible::Role role_)
588
: /* QAccessibleSimpleEditableTextInterface(this), */ view(view_), m_index(index_), m_role(role_)
590
if (!index_.isValid())
591
qWarning() << "QAccessibleTableCell::QAccessibleTableCell with invalid index: " << index_;
594
void *QAccessibleTableCell::interface_cast(QAccessible::InterfaceType t)
596
if (t == QAccessible::TableCellInterface)
597
return static_cast<QAccessibleTableCellInterface*>(this);
601
int QAccessibleTableCell::columnExtent() const { return 1; }
602
int QAccessibleTableCell::rowExtent() const { return 1; }
604
QList<QAccessibleInterface*> QAccessibleTableCell::rowHeaderCells() const
606
QList<QAccessibleInterface*> headerCell;
607
if (verticalHeader()) {
608
headerCell.append(new QAccessibleTableHeaderCell(view, m_index.row(), Qt::Vertical));
613
QList<QAccessibleInterface*> QAccessibleTableCell::columnHeaderCells() const
615
QList<QAccessibleInterface*> headerCell;
616
if (horizontalHeader()) {
617
headerCell.append(new QAccessibleTableHeaderCell(view, m_index.column(), Qt::Horizontal));
622
QHeaderView *QAccessibleTableCell::horizontalHeader() const
624
QHeaderView *header = 0;
627
#ifndef QT_NO_TABLEVIEW
628
} else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) {
629
header = tv->horizontalHeader();
631
#ifndef QT_NO_TREEVIEW
632
} else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) {
633
header = tv->header();
640
QHeaderView *QAccessibleTableCell::verticalHeader() const
642
QHeaderView *header = 0;
643
#ifndef QT_NO_TABLEVIEW
644
if (const QTableView *tv = qobject_cast<const QTableView*>(view))
645
header = tv->verticalHeader();
650
int QAccessibleTableCell::columnIndex() const
652
return m_index.column();
655
int QAccessibleTableCell::rowIndex() const
657
if (role() == QAccessible::TreeItem) {
658
const QTreeView *treeView = qobject_cast<const QTreeView*>(view);
660
int row = treeView->d_func()->viewIndex(m_index);
663
return m_index.row();
666
bool QAccessibleTableCell::isSelected() const
668
return view->selectionModel()->isSelected(m_index);
671
void QAccessibleTableCell::rowColumnExtents(int *row, int *column, int *rowExtents, int *columnExtents, bool *selected) const
673
*row = m_index.row();
674
*column = m_index.column();
677
*selected = isSelected();
680
QAccessibleInterface *QAccessibleTableCell::table() const
682
return QAccessible::queryAccessibleInterface(view);
685
QAccessible::Role QAccessibleTableCell::role() const
690
QAccessible::State QAccessibleTableCell::state() const
692
QAccessible::State st;
693
QRect globalRect = view->rect();
694
globalRect.translate(view->mapToGlobal(QPoint(0,0)));
695
if (!globalRect.intersects(rect()))
698
if (view->selectionModel()->isSelected(m_index))
700
if (view->selectionModel()->currentIndex() == m_index)
702
if (m_index.model()->data(m_index, Qt::CheckStateRole).toInt() == Qt::Checked)
705
Qt::ItemFlags flags = m_index.flags();
706
if (flags & Qt::ItemIsSelectable) {
707
st.selectable = true;
709
if (view->selectionMode() == QAbstractItemView::MultiSelection)
710
st.multiSelectable = true;
711
if (view->selectionMode() == QAbstractItemView::ExtendedSelection)
712
st.extSelectable = true;
714
if (m_role == QAccessible::TreeItem) {
715
const QTreeView *treeView = qobject_cast<const QTreeView*>(view);
716
if (treeView->model()->hasChildren(m_index))
717
st.expandable = true;
718
if (treeView->isExpanded(m_index))
725
QRect QAccessibleTableCell::rect() const
728
r = view->visualRect(m_index);
731
r.translate(view->viewport()->mapTo(view, QPoint(0,0)));
732
r.translate(view->mapToGlobal(QPoint(0, 0)));
736
QString QAccessibleTableCell::text(QAccessible::Text t) const
738
QAbstractItemModel *model = view->model();
741
case QAccessible::Value:
742
case QAccessible::Name:
743
value = model->data(m_index, Qt::AccessibleTextRole).toString();
745
value = model->data(m_index, Qt::DisplayRole).toString();
747
case QAccessible::Description:
748
value = model->data(m_index, Qt::AccessibleDescriptionRole).toString();
756
void QAccessibleTableCell::setText(QAccessible::Text /*t*/, const QString &text)
758
if (!(m_index.flags() & Qt::ItemIsEditable))
760
view->model()->setData(m_index, text);
763
bool QAccessibleTableCell::isValid() const
765
return view && view->model() && m_index.isValid();
768
QAccessibleInterface *QAccessibleTableCell::parent() const
770
if (m_role == QAccessible::TreeItem)
771
return new QAccessibleTree(view);
773
return new QAccessibleTable(view);
776
QAccessibleInterface *QAccessibleTableCell::child(int) const
781
QAccessibleTableHeaderCell::QAccessibleTableHeaderCell(QAbstractItemView *view_, int index_, Qt::Orientation orientation_)
782
: view(view_), index(index_), orientation(orientation_)
784
Q_ASSERT(index_ >= 0);
787
QAccessible::Role QAccessibleTableHeaderCell::role() const
789
if (orientation == Qt::Horizontal)
790
return QAccessible::ColumnHeader;
791
return QAccessible::RowHeader;
794
QAccessible::State QAccessibleTableHeaderCell::state() const
796
return QAccessible::State();
799
QRect QAccessibleTableHeaderCell::rect() const
801
QHeaderView *header = 0;
803
#ifndef QT_NO_TABLEVIEW
804
} else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) {
805
if (orientation == Qt::Horizontal) {
806
header = tv->horizontalHeader();
808
header = tv->verticalHeader();
811
#ifndef QT_NO_TREEVIEW
812
} else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) {
813
header = tv->header();
818
QPoint zero = header->mapToGlobal(QPoint(0, 0));
819
int sectionSize = header->sectionSize(index);
820
int sectionPos = header->sectionPosition(index);
821
return orientation == Qt::Horizontal
822
? QRect(zero.x() + sectionPos, zero.y(), sectionSize, header->height())
823
: QRect(zero.x(), zero.y() + sectionPos, header->width(), sectionSize);
826
QString QAccessibleTableHeaderCell::text(QAccessible::Text t) const
828
QAbstractItemModel *model = view->model();
831
case QAccessible::Value:
832
case QAccessible::Name:
833
value = model->headerData(index, orientation, Qt::AccessibleTextRole).toString();
835
value = model->headerData(index, orientation, Qt::DisplayRole).toString();
837
case QAccessible::Description:
838
value = model->headerData(index, orientation, Qt::AccessibleDescriptionRole).toString();
846
void QAccessibleTableHeaderCell::setText(QAccessible::Text, const QString &)
851
bool QAccessibleTableHeaderCell::isValid() const
853
return view && view->model() && (index >= 0)
854
&& ((orientation == Qt::Horizontal) ? (index < view->model()->columnCount()) : (index < view->model()->rowCount()));
857
QAccessibleInterface *QAccessibleTableHeaderCell::parent() const
860
#ifndef QT_NO_TREEVIEW
861
} else if (qobject_cast<const QTreeView*>(view)) {
862
return new QAccessibleTree(view);
865
return new QAccessibleTable(view);
869
QAccessibleInterface *QAccessibleTableHeaderCell::child(int) const
874
#endif // QT_NO_ITEMVIEWS
878
#endif // QT_NO_ACCESSIBILITY