Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
itemviews.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "itemviews_p.h"
6
7#include <qheaderview.h>
8#if QT_CONFIG(tableview)
9#include <qtableview.h>
10#endif
11#if QT_CONFIG(listview)
12#include <qlistview.h>
13#endif
14#if QT_CONFIG(treeview)
15#include <qtreeview.h>
16#include <private/qtreeview_p.h>
17#endif
18#include <private/qwidget_p.h>
19
20#if QT_CONFIG(accessibility)
21
22QT_BEGIN_NAMESPACE
23
24/*
25Implementation of the IAccessible2 table2 interface. Much simpler than
26the other table interfaces since there is only the main table and cells:
27
28TABLE/LIST/TREE
29 |- HEADER CELL
30 |- CELL
31 |- CELL
32 ...
33*/
34
35
36QAbstractItemView *QAccessibleTable::view() const
37{
38 return qobject_cast<QAbstractItemView*>(object());
39}
40
41int QAccessibleTable::logicalIndex(const QModelIndex &index) const
42{
43 const QAbstractItemModel *theModel = index.model();
44 if (!theModel || !index.isValid())
45 return -1;
46
47#if QT_CONFIG(listview)
48 if (role() == QAccessible::List) {
49 if (index.column() != qobject_cast<const QListView*>(view())->modelColumn())
50 return -1;
51 else
52 return index.row();
53 } else
54#endif
55 {
56 const int vHeader = verticalHeader() ? 1 : 0;
57 const int hHeader = horizontalHeader() ? 1 : 0;
58 return (index.row() + hHeader) * (columnCount() + vHeader)
59 + (index.column() + vHeader);
60 }
61}
62
63QAccessibleTable::QAccessibleTable(QWidget *w, QAccessible::Role role)
64 : QAccessibleWidgetV2(w, role)
65{
66 Q_ASSERT(view());
67}
68
69QAccessibleTable::~QAccessibleTable()
70{
71 for (QAccessible::Id id : std::as_const(childToId))
72 QAccessible::deleteAccessibleInterface(id);
73}
74
75QHeaderView *QAccessibleTable::horizontalHeader() const
76{
77 QHeaderView *header = nullptr;
78 if (false) {
79#if QT_CONFIG(tableview)
80 } else if (const QTableView *tv = qobject_cast<const QTableView*>(view())) {
81 header = tv->horizontalHeader();
82#endif
83#if QT_CONFIG(treeview)
84 } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view())) {
85 header = tv->header();
86#endif
87 }
88 return header;
89}
90
91QHeaderView *QAccessibleTable::verticalHeader() const
92{
93 QHeaderView *header = nullptr;
94 if (false) {
95#if QT_CONFIG(tableview)
96 } else if (const QTableView *tv = qobject_cast<const QTableView*>(view())) {
97 header = tv->verticalHeader();
98#endif
99 }
100 return header;
101}
102
103// Normally cellAt takes row/column in the range
104// [0 .. rowCount())
105// [0 .. columnCount())
106//
107// As an extension we allow clients to ask for headers
108//
109// * Has both vertical and horizontal headers:
110// (-1,-1) -> corner button
111// * Has column headers:
112// (-1, column) -> column header for column \a column
113// * has row headers
114// (row, -1) -> row header for row \a row
115//
116// If asking for a header that does not exist, The invalid
117// index warning is logged, and nullptr is returned.
118QAccessibleInterface *QAccessibleTable::cellAt(int row, int column) const
119{
120 const QAbstractItemView *theView = view();
121 const QAbstractItemModel *theModel = theView->model();
122 if (!theModel)
123 return nullptr;
124 Q_ASSERT(role() != QAccessible::List);
125 Q_ASSERT(role() != QAccessible::Tree);
126
127 const int vHeader = verticalHeader() ? 1 : 0;
128 const int hHeader = horizontalHeader() ? 1 : 0;
129
130 const int doHHeader = ((row == -1) && hHeader);
131 const int doVHeader = ((column == -1) && vHeader);
132
133 if (doVHeader && doHHeader)
134 return child(0);
135
136 if (doVHeader)
137 return child((row + hHeader) * (columnCount() + vHeader) + (column + vHeader));
138
139 if (doHHeader)
140 return child((row + hHeader) * (columnCount() + vHeader) + (column + vHeader));
141
142 QModelIndex index = theModel->index(row, column, theView->rootIndex());
143 if (Q_UNLIKELY(!index.isValid())) {
144 qWarning() << "QAccessibleTable::cellAt: invalid index: " << index << " for " << theView;
145 return nullptr;
146 }
147 return child(logicalIndex(index));
148}
149
150QAccessibleInterface *QAccessibleTable::caption() const
151{
152 return nullptr;
153}
154
155QString QAccessibleTable::columnDescription(int column) const
156{
157 const QAbstractItemView *theView = view();
158 const QAbstractItemModel *theModel = theView->model();
159 if (!theModel)
160 return QString();
161 return theModel->headerData(column, Qt::Horizontal).toString();
162}
163
164int QAccessibleTable::columnCount() const
165{
166 const QAbstractItemView *theView = view();
167 const QAbstractItemModel *theModel = theView->model();
168 if (!theModel)
169 return 0;
170 const int modelColumnCount = theModel->columnCount(theView->rootIndex());
171 return role() == QAccessible::List ? qMin(1, modelColumnCount) : modelColumnCount;
172}
173
174int QAccessibleTable::rowCount() const
175{
176 const QAbstractItemView *theView = view();
177 const QAbstractItemModel *theModel = theView->model();
178 if (!theModel)
179 return 0;
180 return theModel->rowCount(theView->rootIndex());
181}
182
183int QAccessibleTable::selectedCellCount() const
184{
185 if (!view()->selectionModel())
186 return 0;
187 return view()->selectionModel()->selectedIndexes().size();
188}
189
190int QAccessibleTable::selectedColumnCount() const
191{
192 if (!view()->selectionModel())
193 return 0;
194 return view()->selectionModel()->selectedColumns().size();
195}
196
197int QAccessibleTable::selectedRowCount() const
198{
199 if (!view()->selectionModel())
200 return 0;
201 return view()->selectionModel()->selectedRows().size();
202}
203
204QString QAccessibleTable::rowDescription(int row) const
205{
206 const QAbstractItemView *theView = view();
207 const QAbstractItemModel *theModel = theView->model();
208 if (!theModel)
209 return QString();
210 return theModel->headerData(row, Qt::Vertical).toString();
211}
212
213QList<QAccessibleInterface *> QAccessibleTable::selectedCells() const
214{
215 QList<QAccessibleInterface*> cells;
216 if (!view()->selectionModel())
217 return cells;
218 const QModelIndexList selectedIndexes = view()->selectionModel()->selectedIndexes();
219 cells.reserve(selectedIndexes.size());
220 for (const QModelIndex &index : selectedIndexes)
221 cells.append(child(logicalIndex(index)));
222 return cells;
223}
224
225QList<int> QAccessibleTable::selectedColumns() const
226{
227 if (!view()->selectionModel())
228 return QList<int>();
229 QList<int> columns;
230 const QModelIndexList selectedColumns = view()->selectionModel()->selectedColumns();
231 columns.reserve(selectedColumns.size());
232 for (const QModelIndex &index : selectedColumns)
233 columns.append(index.column());
234
235 return columns;
236}
237
238QList<int> QAccessibleTable::selectedRows() const
239{
240 if (!view()->selectionModel())
241 return QList<int>();
242 QList<int> rows;
243 const QModelIndexList selectedRows = view()->selectionModel()->selectedRows();
244 rows.reserve(selectedRows.size());
245 for (const QModelIndex &index : selectedRows)
246 rows.append(index.row());
247
248 return rows;
249}
250
251QAccessibleInterface *QAccessibleTable::summary() const
252{
253 return nullptr;
254}
255
256bool QAccessibleTable::isColumnSelected(int column) const
257{
258 if (!view()->selectionModel())
259 return false;
260 return view()->selectionModel()->isColumnSelected(column, QModelIndex());
261}
262
263bool QAccessibleTable::isRowSelected(int row) const
264{
265 if (!view()->selectionModel())
266 return false;
267 return view()->selectionModel()->isRowSelected(row, QModelIndex());
268}
269
270bool QAccessibleTable::selectRow(int row)
271{
272 QAbstractItemView *theView = view();
273 const QAbstractItemModel *theModel = theView->model();
274 if (!theModel || !view()->selectionModel())
275 return false;
276
277 const QModelIndex rootIndex = theView->rootIndex();
278 const QModelIndex index = theModel->index(row, 0, rootIndex);
279
280 if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns)
281 return false;
282
283 switch (view()->selectionMode()) {
284 case QAbstractItemView::NoSelection:
285 return false;
286 case QAbstractItemView::SingleSelection:
287 if (view()->selectionBehavior() != QAbstractItemView::SelectRows && columnCount() > 1 )
288 return false;
289 view()->clearSelection();
290 break;
291 case QAbstractItemView::ContiguousSelection:
292 if ((!row || !theView->selectionModel()->isRowSelected(row - 1, rootIndex))
293 && !theView->selectionModel()->isRowSelected(row + 1, rootIndex)) {
294 theView->clearSelection();
295 }
296 break;
297 default:
298 break;
299 }
300
301 view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
302 return true;
303}
304
305bool QAccessibleTable::selectColumn(int column)
306{
307 QAbstractItemView *theView = view();
308 const QAbstractItemModel *theModel = theView->model();
309 auto *selectionModel = theView->selectionModel();
310 if (!theModel || !selectionModel)
311 return false;
312
313 const QModelIndex rootIndex = theView->rootIndex();
314 const QModelIndex index = theModel->index(0, column, rootIndex);
315
316 if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectRows)
317 return false;
318
319 switch (theView->selectionMode()) {
320 case QAbstractItemView::NoSelection:
321 return false;
322 case QAbstractItemView::SingleSelection:
323 if (theView->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1)
324 return false;
325 Q_FALLTHROUGH();
326 case QAbstractItemView::ContiguousSelection:
327 if ((!column || !selectionModel->isColumnSelected(column - 1, rootIndex))
328 && !selectionModel->isColumnSelected(column + 1, rootIndex)) {
329 theView->clearSelection();
330 }
331 break;
332 default:
333 break;
334 }
335
336 selectionModel->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns);
337 return true;
338}
339
340bool QAccessibleTable::unselectRow(int row)
341{
342 const QAbstractItemView *theView = view();
343 const QAbstractItemModel *theModel = theView->model();
344 auto *selectionModel = theView->selectionModel();
345 if (!theModel || !selectionModel)
346 return false;
347
348 const QModelIndex rootIndex = theView->rootIndex();
349 const QModelIndex index = view()->model()->index(row, 0, rootIndex);
350 if (!index.isValid())
351 return false;
352
353 QItemSelection selection(index, index);
354
355 switch (theView->selectionMode()) {
356 case QAbstractItemView::SingleSelection:
357 //In SingleSelection and ContiguousSelection once an item
358 //is selected, there's no way for the user to unselect all items
359 if (selectedRowCount() == 1)
360 return false;
361 break;
362 case QAbstractItemView::ContiguousSelection:
363 if (selectedRowCount() == 1)
364 return false;
365
366 if ((!row || selectionModel->isRowSelected(row - 1, rootIndex))
367 && selectionModel->isRowSelected(row + 1, rootIndex)) {
368 //If there are rows selected both up the current row and down the current rown,
369 //the ones which are down the current row will be deselected
370 selection = QItemSelection(index, theModel->index(rowCount() - 1, 0, rootIndex));
371 }
372 break;
373 default:
374 break;
375 }
376
377 selectionModel->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
378 return true;
379}
380
381bool QAccessibleTable::unselectColumn(int column)
382{
383 const QAbstractItemView *theView = view();
384 const QAbstractItemModel *theModel = theView->model();
385 auto *selectionModel = theView->selectionModel();
386 if (!theModel || !selectionModel)
387 return false;
388
389 const QModelIndex rootIndex = theView->rootIndex();
390 const QModelIndex index = view()->model()->index(0, column, rootIndex);
391 if (!index.isValid())
392 return false;
393
394 QItemSelection selection(index, index);
395
396 switch (view()->selectionMode()) {
397 case QAbstractItemView::SingleSelection:
398 //In SingleSelection and ContiguousSelection once an item
399 //is selected, there's no way for the user to unselect all items
400 if (selectedColumnCount() == 1)
401 return false;
402 break;
403 case QAbstractItemView::ContiguousSelection:
404 if (selectedColumnCount() == 1)
405 return false;
406
407 if ((!column || selectionModel->isColumnSelected(column - 1, rootIndex))
408 && selectionModel->isColumnSelected(column + 1, rootIndex)) {
409 //If there are columns selected both at the left of the current row and at the right
410 //of the current rown, the ones which are at the right will be deselected
411 selection = QItemSelection(index, theModel->index(0, columnCount() - 1, rootIndex));
412 }
413 break;
414 default:
415 break;
416 }
417
418 selectionModel->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns);
419 return true;
420}
421
422int QAccessibleTable::selectedItemCount() const
423{
424 return selectedCellCount();
425}
426
427QList<QAccessibleInterface*> QAccessibleTable::selectedItems() const
428{
429 return selectedCells();
430}
431
432bool QAccessibleTable::isSelected(QAccessibleInterface *childCell) const
433{
434 if (!childCell || childCell->parent() != this) {
435 qWarning() << "QAccessibleTable::isSelected: Accessible interface must be a direct child of the table interface.";
436 return false;
437 }
438
439 const QAccessibleTableCellInterface *cell = childCell->tableCellInterface();
440 if (cell)
441 return cell->isSelected();
442
443 return false;
444}
445
446bool QAccessibleTable::select(QAccessibleInterface *childCell)
447{
448 if (!childCell || childCell->parent() != this) {
449 qWarning() << "QAccessibleTable::select: Accessible interface must be a direct child of the table interface.";
450 return false;
451 }
452
453 if (!childCell->tableCellInterface()) {
454 qWarning() << "QAccessibleTable::select: Accessible interface doesn't implement table cell interface.";
455 return false;
456 }
457
458 if (childCell->role() == QAccessible::Cell || childCell->role() == QAccessible::ListItem || childCell->role() == QAccessible::TreeItem) {
459 QAccessibleTableCell* cell = static_cast<QAccessibleTableCell*>(childCell);
460 cell->selectCell();
461 return true;
462 }
463
464 return false;
465}
466
467bool QAccessibleTable::unselect(QAccessibleInterface *childCell)
468{
469 if (!childCell || childCell->parent() != this) {
470 qWarning() << "QAccessibleTable::select: Accessible interface must be a direct child of the table interface.";
471 return false;
472 }
473
474 if (!childCell->tableCellInterface()) {
475 qWarning() << "QAccessibleTable::unselect: Accessible interface doesn't implement table cell interface.";
476 return false;
477 }
478
479 if (childCell->role() == QAccessible::Cell || childCell->role() == QAccessible::ListItem || childCell->role() == QAccessible::TreeItem) {
480 QAccessibleTableCell* cell = static_cast<QAccessibleTableCell*>(childCell);
481 cell->unselectCell();
482 return true;
483 }
484
485 return false;
486}
487
488bool QAccessibleTable::selectAll()
489{
490 view()->selectAll();
491 return true;
492}
493
494bool QAccessibleTable::clear()
495{
496 view()->selectionModel()->clearSelection();
497 return true;
498}
499
500
501QAccessibleInterface *QAccessibleTable::childAt(int x, int y) const
502{
503 QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0));
504 QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset);
505 // FIXME: if indexPosition < 0 in one coordinate, return header
506
507 const QModelIndex index = view()->indexAt(indexPosition);
508 if (index.isValid())
509 return child(logicalIndex(index));
510 return nullptr;
511}
512
513QAccessibleInterface *QAccessibleTable::focusChild() const
514{
515 QModelIndex index = view()->currentIndex();
516 if (!index.isValid())
517 return nullptr;
518
519 return child(logicalIndex(index));
520}
521
522int QAccessibleTable::childCount() const
523{
524 const QAbstractItemView *theView = view();
525 if (!theView)
526 return 0;
527 const QAbstractItemModel *theModel = theView->model();
528 if (!theModel)
529 return 0;
530 const QModelIndex rootIndex = theView->rootIndex();
531 int vHeader = verticalHeader() ? 1 : 0;
532 int hHeader = horizontalHeader() ? 1 : 0;
533 return (theModel->rowCount(rootIndex) + hHeader) * (columnCount() + vHeader);
534}
535
536int QAccessibleTable::indexOfChild(const QAccessibleInterface *iface) const
537{
538 const QAbstractItemView *theView = view();
539 if (!theView)
540 return -1;
541 const QAbstractItemModel *theModel = theView->model();
542 if (!theModel)
543 return -1;
544 QAccessibleInterface *parent = iface->parent();
545 if (parent->object() != theView)
546 return -1;
547
548 const QModelIndex rootIndex = theView->rootIndex();
549 Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class
550 if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
551 const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface);
552 return logicalIndex(cell->m_index);
553 } else if (iface->role() == QAccessible::ColumnHeader){
554 const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
555 return cell->index + (verticalHeader() ? 1 : 0);
556 } else if (iface->role() == QAccessible::RowHeader){
557 const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
558 return (cell->index + 1) * (theModel->columnCount(rootIndex) + 1);
559 } else if (iface->role() == QAccessible::Pane) {
560 return 0; // corner button
561 } else {
562 qWarning() << "WARNING QAccessibleTable::indexOfChild Fix my children..."
563 << iface->role() << iface->text(QAccessible::Name);
564 }
565 // FIXME: we are in denial of our children. this should stop.
566 return -1;
567}
568
569QAccessibleInterface *QAccessibleTable::parent() const
570{
571 if (view() && view()->parent()) {
572 if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) {
573 return QAccessible::queryAccessibleInterface(view()->parent()->parent());
574 }
575 return QAccessible::queryAccessibleInterface(view()->parent());
576 }
577 return QAccessible::queryAccessibleInterface(qApp);
578}
579
580QAccessibleInterface *QAccessibleTable::child(int logicalIndex) const
581{
582 QAbstractItemView *theView = view();
583 if (!theView)
584 return nullptr;
585
586 const QAbstractItemModel *theModel = theView->model();
587 if (!theModel)
588 return nullptr;
589
590 const QModelIndex rootIndex = theView->rootIndex();
591 auto id = childToId.constFind(logicalIndex);
592 if (id != childToId.constEnd())
593 return QAccessible::accessibleInterface(id.value());
594
595 int vHeader = verticalHeader() ? 1 : 0;
596 int hHeader = horizontalHeader() ? 1 : 0;
597
598 int columns = theModel->columnCount(rootIndex) + vHeader;
599
600 int row = logicalIndex / columns;
601 int column = logicalIndex % columns;
602
603 QAccessibleInterface *iface = nullptr;
604
605 if (vHeader) {
606 if (column == 0) {
607 if (hHeader && row == 0) {
608 iface = new QAccessibleTableCornerButton(theView);
609 } else {
610 iface = new QAccessibleTableHeaderCell(theView, row - hHeader, Qt::Vertical);
611 }
612 }
613 --column;
614 }
615 if (!iface && hHeader) {
616 if (row == 0) {
617 iface = new QAccessibleTableHeaderCell(theView, column, Qt::Horizontal);
618 }
619 --row;
620 }
621
622 if (!iface) {
623 QModelIndex index = theModel->index(row, column, rootIndex);
624 if (Q_UNLIKELY(!index.isValid())) {
625 qWarning("QAccessibleTable::child: Invalid index at: %d %d", row, column);
626 return nullptr;
627 }
628 iface = new QAccessibleTableCell(theView, index, cellRole());
629 }
630
631 QAccessible::registerAccessibleInterface(iface);
632 childToId.insert(logicalIndex, QAccessible::uniqueId(iface));
633 return iface;
634}
635
636void *QAccessibleTable::interface_cast(QAccessible::InterfaceType t)
637{
638 if (t == QAccessible::SelectionInterface)
639 return static_cast<QAccessibleSelectionInterface*>(this);
640 if (t == QAccessible::TableInterface)
641 return static_cast<QAccessibleTableInterface*>(this);
642 return QAccessibleWidgetV2::interface_cast(t);
643}
644
645void QAccessibleTable::modelChange(QAccessibleTableModelChangeEvent *event)
646{
647 // if there is no cache yet, we don't update anything
648 if (childToId.isEmpty())
649 return;
650
651 switch (event->modelChangeType()) {
652 case QAccessibleTableModelChangeEvent::ModelReset:
653 for (QAccessible::Id id : std::as_const(childToId))
654 QAccessible::deleteAccessibleInterface(id);
655 childToId.clear();
656 break;
657
658 // rows are inserted: move every row after that
659 case QAccessibleTableModelChangeEvent::RowsInserted:
660 case QAccessibleTableModelChangeEvent::ColumnsInserted: {
661 int newRows = event->lastRow() - event->firstRow() + 1;
662 int newColumns = event->lastColumn() - event->firstColumn() + 1;
663
664 ChildCache newCache;
665 ChildCache::ConstIterator iter = childToId.constBegin();
666
667 while (iter != childToId.constEnd()) {
668 QAccessible::Id id = iter.value();
669 QAccessibleInterface *iface = QAccessible::accessibleInterface(id);
670 Q_ASSERT(iface);
671 if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsInserted
672 && iface->role() == QAccessible::RowHeader) {
673 QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface);
674 if (cell->index >= event->firstRow()) {
675 cell->index += newRows;
676 }
677 } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsInserted
678 && iface->role() == QAccessible::ColumnHeader) {
679 QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface);
680 if (cell->index >= event->firstColumn()) {
681 cell->index += newColumns;
682 }
683 }
684 if (indexOfChild(iface) >= 0) {
685 newCache.insert(indexOfChild(iface), id);
686 } else {
687 // ### This should really not happen,
688 // but it might if the view has a root index set.
689 // This needs to be fixed.
690 QAccessible::deleteAccessibleInterface(id);
691 }
692 ++iter;
693 }
694 childToId = newCache;
695 break;
696 }
697
698 case QAccessibleTableModelChangeEvent::ColumnsRemoved:
699 case QAccessibleTableModelChangeEvent::RowsRemoved: {
700 int deletedColumns = event->lastColumn() - event->firstColumn() + 1;
701 int deletedRows = event->lastRow() - event->firstRow() + 1;
702 ChildCache newCache;
703 ChildCache::ConstIterator iter = childToId.constBegin();
704 while (iter != childToId.constEnd()) {
705 QAccessible::Id id = iter.value();
706 QAccessibleInterface *iface = QAccessible::accessibleInterface(id);
707 Q_ASSERT(iface);
708 if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
709 Q_ASSERT(iface->tableCellInterface());
710 QAccessibleTableCell *cell = static_cast<QAccessibleTableCell*>(iface->tableCellInterface());
711 // Since it is a QPersistentModelIndex, we only need to check if it is valid
712 if (cell->m_index.isValid())
713 newCache.insert(indexOfChild(cell), id);
714 else
715 QAccessible::deleteAccessibleInterface(id);
716 } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsRemoved
717 && iface->role() == QAccessible::RowHeader) {
718 QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface);
719 if (cell->index < event->firstRow()) {
720 newCache.insert(indexOfChild(cell), id);
721 } else if (cell->index > event->lastRow()) {
722 cell->index -= deletedRows;
723 newCache.insert(indexOfChild(cell), id);
724 } else {
725 QAccessible::deleteAccessibleInterface(id);
726 }
727 } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsRemoved
728 && iface->role() == QAccessible::ColumnHeader) {
729 QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface);
730 if (cell->index < event->firstColumn()) {
731 newCache.insert(indexOfChild(cell), id);
732 } else if (cell->index > event->lastColumn()) {
733 cell->index -= deletedColumns;
734 newCache.insert(indexOfChild(cell), id);
735 } else {
736 QAccessible::deleteAccessibleInterface(id);
737 }
738 }
739 ++iter;
740 }
741 childToId = newCache;
742 break;
743 }
744
745 case QAccessibleTableModelChangeEvent::DataChanged:
746 // nothing to do in this case
747 break;
748 }
749}
750
751#if QT_CONFIG(treeview)
752
753// TREE VIEW
754
755QModelIndex QAccessibleTree::indexFromLogical(int row, int column) const
756{
757 if (!isValid() || !view()->model())
758 return QModelIndex();
759
760 const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
761 if (Q_UNLIKELY(row < 0 || column < 0 || treeView->d_func()->viewItems.size() <= row)) {
762 qWarning() << "QAccessibleTree::indexFromLogical: invalid index: " << row << column << " for " << treeView;
763 return QModelIndex();
764 }
765 QModelIndex modelIndex = treeView->d_func()->viewItems.at(row).index;
766
767 if (modelIndex.isValid() && column > 0) {
768 modelIndex = view()->model()->index(modelIndex.row(), column, modelIndex.parent());
769 }
770 return modelIndex;
771}
772
773QAccessibleInterface *QAccessibleTree::childAt(int x, int y) const
774{
775 const QAbstractItemView *theView = view();
776 if (!theView)
777 return nullptr;
778 const QAbstractItemModel *theModel = theView->model();
779 if (!theModel)
780 return nullptr;
781
782 const QPoint viewportOffset = theView->viewport()->mapTo(theView, QPoint(0, 0));
783 const QPoint indexPosition = theView->mapFromGlobal(QPoint(x, y) - viewportOffset);
784
785 const QModelIndex index = theView->indexAt(indexPosition);
786 if (!index.isValid())
787 return nullptr;
788
789 const QTreeView *treeView = qobject_cast<const QTreeView *>(theView);
790 int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0);
791 int column = index.column();
792
793 int i = row * theModel->columnCount(theView->rootIndex()) + column;
794 return child(i);
795}
796
797QAccessibleInterface *QAccessibleTree::focusChild() const
798{
799 const QAbstractItemView *theView = view();
800 if (!theView)
801 return nullptr;
802 const QAbstractItemModel *theModel = theView->model();
803 const QModelIndex index = theView->currentIndex();
804 if (!index.isValid())
805 return nullptr;
806
807 const QTreeView *treeView = qobject_cast<const QTreeView *>(theView);
808 const int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0);
809 const int column = index.column();
810
811 int i = row * theModel->columnCount(theView->rootIndex()) + column;
812 return child(i);
813}
814
815int QAccessibleTree::childCount() const
816{
817 const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
818 if (!treeView)
819 return 0;
820 const QAbstractItemModel *theModel = treeView->model();
821 if (!theModel)
822 return 0;
823
824 int hHeader = horizontalHeader() ? 1 : 0;
825 return (treeView->d_func()->viewItems.size() + hHeader)
826 * theModel->columnCount(treeView->rootIndex());
827}
828
829QAccessibleInterface *QAccessibleTree::child(int logicalIndex) const
830{
831 QAbstractItemView *theView = view();
832 if (!theView)
833 return nullptr;
834 const QAbstractItemModel *theModel = theView->model();
835 const QModelIndex rootIndex = theView->rootIndex();
836 if (logicalIndex < 0 || !theModel || !theModel->columnCount(rootIndex))
837 return nullptr;
838
839 auto id = childToId.constFind(logicalIndex);
840 if (id != childToId.constEnd())
841 return QAccessible::accessibleInterface(id.value());
842
843 QAccessibleInterface *iface = nullptr;
844 int index = logicalIndex;
845
846 if (horizontalHeader()) {
847 if (index < theModel->columnCount(rootIndex))
848 iface = new QAccessibleTableHeaderCell(theView, index, Qt::Horizontal);
849 else
850 index -= theModel->columnCount(rootIndex);
851 }
852
853 if (!iface) {
854 const int row = index / theModel->columnCount(rootIndex);
855 const int column = index % theModel->columnCount(rootIndex);
856 const QModelIndex modelIndex = indexFromLogical(row, column);
857 if (!modelIndex.isValid())
858 return nullptr;
859 iface = new QAccessibleTableCell(theView, modelIndex, cellRole());
860 }
861 QAccessible::registerAccessibleInterface(iface);
862 childToId.insert(logicalIndex, QAccessible::uniqueId(iface));
863 return iface;
864}
865
866int QAccessibleTree::rowCount() const
867{
868 const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
869 if (!treeView)
870 return 0;
871 return treeView->d_func()->viewItems.size();
872}
873
874int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const
875{
876 const QAbstractItemView *theView = view();
877 if (!theView)
878 return -1;
879 const QAbstractItemModel *theModel = theView->model();
880 if (!theModel)
881 return -1;
882 QAccessibleInterface *parent = iface->parent();
883 if (parent->object() != theView)
884 return -1;
885
886 if (iface->role() == QAccessible::TreeItem) {
887 const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface);
888 const QTreeView *treeView = qobject_cast<const QTreeView *>(theView);
889 Q_ASSERT(treeView);
890 int row = treeView->d_func()->viewIndex(cell->m_index) + (horizontalHeader() ? 1 : 0);
891 int column = cell->m_index.column();
892
893 int index = row * theModel->columnCount(theView->rootIndex()) + column;
894 return index;
895 } else if (iface->role() == QAccessible::ColumnHeader){
896 const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
897 return cell->index;
898 } else {
899 qWarning() << "WARNING QAccessibleTable::indexOfChild invalid child"
900 << iface->role() << iface->text(QAccessible::Name);
901 }
902 // FIXME: add scrollbars and don't just ignore them
903 return -1;
904}
905
906QAccessibleInterface *QAccessibleTree::cellAt(int row, int column) const
907{
908 QModelIndex index = indexFromLogical(row, column);
909 if (Q_UNLIKELY(!index.isValid())) {
910 qWarning("Requested invalid tree cell: %d %d", row, column);
911 return nullptr;
912 }
913 const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
914 Q_ASSERT(treeView);
915 int logicalIndex = treeView->d_func()->accessibleTable2Index(index);
916
917 return child(logicalIndex);
918}
919
920QString QAccessibleTree::rowDescription(int) const
921{
922 return QString(); // no headers for rows in trees
923}
924
925bool QAccessibleTree::isRowSelected(int row) const
926{
927 if (!view()->selectionModel())
928 return false;
929 QModelIndex index = indexFromLogical(row);
930 return view()->selectionModel()->isRowSelected(index.row(), index.parent());
931}
932
933bool QAccessibleTree::selectRow(int row)
934{
935 if (!view()->selectionModel())
936 return false;
937 QModelIndex index = indexFromLogical(row);
938
939 if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns)
940 return false;
941
942 switch (view()->selectionMode()) {
943 case QAbstractItemView::NoSelection:
944 return false;
945 case QAbstractItemView::SingleSelection:
946 if ((view()->selectionBehavior() != QAbstractItemView::SelectRows) && (columnCount() > 1))
947 return false;
948 view()->clearSelection();
949 break;
950 case QAbstractItemView::ContiguousSelection:
951 if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex()))
952 && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex()))
953 view()->clearSelection();
954 break;
955 default:
956 break;
957 }
958
959 view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
960 return true;
961}
962
963#endif // QT_CONFIG(treeview)
964
965#if QT_CONFIG(listview)
966
967// LIST VIEW
968
969QAccessibleInterface *QAccessibleList::child(int logicalIndex) const
970{
971 QAbstractItemView *theView = view();
972 if (!theView)
973 return nullptr;
974 const QAbstractItemModel *theModel = theView->model();
975 if (!theModel)
976 return nullptr;
977
978 if (columnCount() == 0) {
979 return nullptr;
980 }
981
982 const auto id = childToId.constFind(logicalIndex);
983 if (id != childToId.constEnd())
984 return QAccessible::accessibleInterface(id.value());
985
986 const QListView *listView = qobject_cast<const QListView*>(theView);
987 Q_ASSERT(listView);
988 int row = logicalIndex;
989 int column = listView->modelColumn();
990
991 const QModelIndex rootIndex = theView->rootIndex();
992 const QModelIndex index = theModel->index(row, column, rootIndex);
993 if (Q_UNLIKELY(!index.isValid())) {
994 qWarning("QAccessibleList::child: Invalid index at: %d %d", row, column);
995 return nullptr;
996 }
997 const auto iface = new QAccessibleTableCell(theView, index, cellRole());
998
999 QAccessible::registerAccessibleInterface(iface);
1000 childToId.insert(logicalIndex, QAccessible::uniqueId(iface));
1001 return iface;
1002}
1003
1004QAccessibleInterface *QAccessibleList::cellAt(int row, int column) const
1005{
1006 if (column != 0)
1007 return nullptr;
1008
1009 return child(row);
1010}
1011
1012int QAccessibleList::selectedCellCount() const
1013{
1014 QAbstractItemView *theView = view();
1015 if (!theView->selectionModel())
1016 return 0;
1017 const QListView *listView = qobject_cast<const QListView*>(theView);
1018 const int modelColumn = listView->modelColumn();
1019 const QModelIndexList selectedIndexes = theView->selectionModel()->selectedIndexes();
1020 return std::count_if(selectedIndexes.cbegin(), selectedIndexes.cend(),
1021 [modelColumn](const auto &index) {
1022 return index.column() == modelColumn;
1023 });
1024}
1025
1026QList<QAccessibleInterface *> QAccessibleList::selectedCells() const
1027{
1028 QAbstractItemView *theView = view();
1029 QList<QAccessibleInterface*> cells;
1030 if (!view()->selectionModel() || columnCount() == 0)
1031 return cells;
1032 const QListView *listView = qobject_cast<const QListView*>(theView);
1033 const int modelColumn = listView->modelColumn();
1034 const QModelIndexList selectedIndexes = theView->selectionModel()->selectedIndexes();
1035 cells.reserve(qMin(selectedIndexes.size(), rowCount()));
1036 for (const QModelIndex &index : selectedIndexes)
1037 if (index.column() == modelColumn) {
1038 cells.append(child(index.row()));
1039 }
1040 return cells;
1041}
1042
1043#endif // QT_CONFIG(listview)
1044
1045// TABLE CELL
1046
1047QAccessibleTableCell::QAccessibleTableCell(QAbstractItemView *view_, const QModelIndex &index_, QAccessible::Role role_)
1048 : /* QAccessibleSimpleEditableTextInterface(this), */ view(view_), m_index(index_), m_role(role_)
1049{
1050 if (Q_UNLIKELY(!index_.isValid()))
1051 qWarning() << "QAccessibleTableCell::QAccessibleTableCell with invalid index: " << index_;
1052}
1053
1054void *QAccessibleTableCell::interface_cast(QAccessible::InterfaceType t)
1055{
1056 if (t == QAccessible::TableCellInterface)
1057 return static_cast<QAccessibleTableCellInterface*>(this);
1058 if (t == QAccessible::ActionInterface)
1059 return static_cast<QAccessibleActionInterface*>(this);
1060 return nullptr;
1061}
1062
1063int QAccessibleTableCell::columnExtent() const { return 1; }
1064int QAccessibleTableCell::rowExtent() const { return 1; }
1065
1066QList<QAccessibleInterface*> QAccessibleTableCell::rowHeaderCells() const
1067{
1068 QList<QAccessibleInterface*> headerCell;
1069 if (verticalHeader()) {
1070 // FIXME
1071 headerCell.append(new QAccessibleTableHeaderCell(view, m_index.row(), Qt::Vertical));
1072 }
1073 return headerCell;
1074}
1075
1076QList<QAccessibleInterface*> QAccessibleTableCell::columnHeaderCells() const
1077{
1078 QList<QAccessibleInterface*> headerCell;
1079 if (horizontalHeader()) {
1080 // FIXME
1081 headerCell.append(new QAccessibleTableHeaderCell(view, m_index.column(), Qt::Horizontal));
1082 }
1083 return headerCell;
1084}
1085
1086QHeaderView *QAccessibleTableCell::horizontalHeader() const
1087{
1088 QHeaderView *header = nullptr;
1089
1090 if (false) {
1091#if QT_CONFIG(tableview)
1092 } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) {
1093 header = tv->horizontalHeader();
1094#endif
1095#if QT_CONFIG(treeview)
1096 } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) {
1097 header = tv->header();
1098#endif
1099 }
1100
1101 return header;
1102}
1103
1104QHeaderView *QAccessibleTableCell::verticalHeader() const
1105{
1106 QHeaderView *header = nullptr;
1107#if QT_CONFIG(tableview)
1108 if (const QTableView *tv = qobject_cast<const QTableView*>(view))
1109 header = tv->verticalHeader();
1110#endif
1111 return header;
1112}
1113
1114int QAccessibleTableCell::columnIndex() const
1115{
1116 if (!isValid())
1117 return -1;
1118#if QT_CONFIG(listview)
1119 if (role() == QAccessible::ListItem) {
1120 return 0;
1121 }
1122#endif
1123 return m_index.column();
1124}
1125
1126int QAccessibleTableCell::rowIndex() const
1127{
1128 if (!isValid())
1129 return -1;
1130#if QT_CONFIG(treeview)
1131 if (role() == QAccessible::TreeItem) {
1132 const QTreeView *treeView = qobject_cast<const QTreeView*>(view);
1133 Q_ASSERT(treeView);
1134 int row = treeView->d_func()->viewIndex(m_index);
1135 return row;
1136 }
1137#endif
1138 return m_index.row();
1139}
1140
1141bool QAccessibleTableCell::isSelected() const
1142{
1143 if (!isValid())
1144 return false;
1145 return view->selectionModel()->isSelected(m_index);
1146}
1147
1148QStringList QAccessibleTableCell::actionNames() const
1149{
1150 QStringList names;
1151 names << toggleAction();
1152 return names;
1153}
1154
1155void QAccessibleTableCell::doAction(const QString& actionName)
1156{
1157 if (actionName == toggleAction()) {
1158#if defined(Q_OS_ANDROID)
1159 QAccessibleInterface *parentInterface = parent();
1160 while (parentInterface){
1161 if (parentInterface->role() == QAccessible::ComboBox) {
1162 selectCell();
1163 parentInterface->actionInterface()->doAction(pressAction());
1164 return;
1165 } else {
1166 parentInterface = parentInterface->parent();
1167 }
1168 }
1169#endif
1170 if (isSelected()) {
1171 unselectCell();
1172 } else {
1173 selectCell();
1174 }
1175 }
1176}
1177
1178QStringList QAccessibleTableCell::keyBindingsForAction(const QString &) const
1179{
1180 return QStringList();
1181}
1182
1183
1184void QAccessibleTableCell::selectCell()
1185{
1186 if (!isValid())
1187 return;
1188 QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
1189 if (selectionMode == QAbstractItemView::NoSelection)
1190 return;
1191 Q_ASSERT(table());
1192 QAccessibleTableInterface *cellTable = table()->tableInterface();
1193
1194 switch (view->selectionBehavior()) {
1195 case QAbstractItemView::SelectItems:
1196 break;
1197 case QAbstractItemView::SelectColumns:
1198 if (cellTable)
1199 cellTable->selectColumn(m_index.column());
1200 return;
1201 case QAbstractItemView::SelectRows:
1202 if (cellTable)
1203 cellTable->selectRow(m_index.row());
1204 return;
1205 }
1206
1207 if (selectionMode == QAbstractItemView::SingleSelection) {
1208 view->clearSelection();
1209 }
1210
1211 view->selectionModel()->select(m_index, QItemSelectionModel::Select);
1212}
1213
1214void QAccessibleTableCell::unselectCell()
1215{
1216 if (!isValid())
1217 return;
1218 QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
1219 if (selectionMode == QAbstractItemView::NoSelection)
1220 return;
1221
1222 QAccessibleTableInterface *cellTable = table()->tableInterface();
1223
1224 switch (view->selectionBehavior()) {
1225 case QAbstractItemView::SelectItems:
1226 break;
1227 case QAbstractItemView::SelectColumns:
1228 if (cellTable)
1229 cellTable->unselectColumn(m_index.column());
1230 return;
1231 case QAbstractItemView::SelectRows:
1232 if (cellTable)
1233 cellTable->unselectRow(m_index.row());
1234 return;
1235 }
1236
1237 //If the mode is not MultiSelection or ExtendedSelection and only
1238 //one cell is selected it cannot be unselected by the user
1239 if ((selectionMode != QAbstractItemView::MultiSelection)
1240 && (selectionMode != QAbstractItemView::ExtendedSelection)
1241 && (view->selectionModel()->selectedIndexes().size() <= 1))
1242 return;
1243
1244 view->selectionModel()->select(m_index, QItemSelectionModel::Deselect);
1245}
1246
1247QAccessibleInterface *QAccessibleTableCell::table() const
1248{
1249 return QAccessible::queryAccessibleInterface(view);
1250}
1251
1252QAccessible::Role QAccessibleTableCell::role() const
1253{
1254 return m_role;
1255}
1256
1257QAccessible::State QAccessibleTableCell::state() const
1258{
1259 QAccessible::State st;
1260 if (!isValid())
1261 return st;
1262
1263 QRect globalRect = view->rect();
1264 globalRect.translate(view->mapToGlobal(QPoint(0,0)));
1265 if (!globalRect.intersects(rect()))
1266 st.invisible = true;
1267
1268 if (view->selectionModel()->isSelected(m_index))
1269 st.selected = true;
1270 if (view->selectionModel()->currentIndex() == m_index)
1271 st.focused = true;
1272
1273 const QVariant checkState = m_index.data(Qt::CheckStateRole);
1274 if (checkState.toInt() == Qt::Checked)
1275 st.checked = true;
1276
1277 Qt::ItemFlags flags = m_index.flags();
1278 if ((flags & Qt::ItemIsUserCheckable) && checkState.isValid())
1279 st.checkable = true;
1280 if (flags & Qt::ItemIsSelectable) {
1281 st.selectable = true;
1282 st.focusable = true;
1283 if (view->selectionMode() == QAbstractItemView::MultiSelection)
1284 st.multiSelectable = true;
1285 if (view->selectionMode() == QAbstractItemView::ExtendedSelection)
1286 st.extSelectable = true;
1287 }
1288#if QT_CONFIG(treeview)
1289 if (m_role == QAccessible::TreeItem) {
1290 const QTreeView *treeView = qobject_cast<const QTreeView*>(view);
1291 if (treeView->model()->hasChildren(m_index))
1292 st.expandable = true;
1293 if (treeView->isExpanded(m_index))
1294 st.expanded = true;
1295 }
1296#endif
1297 return st;
1298}
1299
1300
1301QRect QAccessibleTableCell::rect() const
1302{
1303 QRect r;
1304 if (!isValid())
1305 return r;
1306 r = view->visualRect(m_index);
1307
1308 if (!r.isNull()) {
1309 r.translate(view->viewport()->mapTo(view, QPoint(0,0)));
1310 r.translate(view->mapToGlobal(QPoint(0, 0)));
1311 }
1312 return r;
1313}
1314
1315QString QAccessibleTableCell::text(QAccessible::Text t) const
1316{
1317 QString value;
1318 if (!isValid())
1319 return value;
1320 QAbstractItemModel *model = view->model();
1321 switch (t) {
1322 case QAccessible::Name:
1323 value = model->data(m_index, Qt::AccessibleTextRole).toString();
1324 if (value.isEmpty())
1325 value = model->data(m_index, Qt::DisplayRole).toString();
1326 break;
1327 case QAccessible::Description:
1328 value = model->data(m_index, Qt::AccessibleDescriptionRole).toString();
1329 break;
1330 default:
1331 break;
1332 }
1333 return value;
1334}
1335
1336void QAccessibleTableCell::setText(QAccessible::Text /*t*/, const QString &text)
1337{
1338 if (!isValid() || !(m_index.flags() & Qt::ItemIsEditable))
1339 return;
1340 view->model()->setData(m_index, text);
1341}
1342
1343bool QAccessibleTableCell::isValid() const
1344{
1345 return view && !qt_widget_private(view)->data.in_destructor
1346 && view->model() && m_index.isValid();
1347}
1348
1349QAccessibleInterface *QAccessibleTableCell::parent() const
1350{
1351 return QAccessible::queryAccessibleInterface(view);
1352}
1353
1354QAccessibleInterface *QAccessibleTableCell::child(int) const
1355{
1356 return nullptr;
1357}
1358
1359QAccessibleTableHeaderCell::QAccessibleTableHeaderCell(QAbstractItemView *view_, int index_, Qt::Orientation orientation_)
1360 : view(view_), index(index_), orientation(orientation_)
1361{
1362 Q_ASSERT(index_ >= 0);
1363}
1364
1365QAccessible::Role QAccessibleTableHeaderCell::role() const
1366{
1367 if (orientation == Qt::Horizontal)
1368 return QAccessible::ColumnHeader;
1369 return QAccessible::RowHeader;
1370}
1371
1372QAccessible::State QAccessibleTableHeaderCell::state() const
1373{
1374 QAccessible::State s;
1375 if (QHeaderView *h = headerView()) {
1376 s.invisible = !h->testAttribute(Qt::WA_WState_Visible);
1377 s.disabled = !h->isEnabled();
1378 }
1379 return s;
1380}
1381
1382QRect QAccessibleTableHeaderCell::rect() const
1383{
1384 QHeaderView *header = nullptr;
1385 if (false) {
1386#if QT_CONFIG(tableview)
1387 } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) {
1388 if (orientation == Qt::Horizontal) {
1389 header = tv->horizontalHeader();
1390 } else {
1391 header = tv->verticalHeader();
1392 }
1393#endif
1394#if QT_CONFIG(treeview)
1395 } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) {
1396 header = tv->header();
1397#endif
1398 }
1399 if (!header)
1400 return QRect();
1401 QPoint zero = header->mapToGlobal(QPoint(0, 0));
1402 int sectionSize = header->sectionSize(index);
1403 int sectionPos = header->sectionPosition(index);
1404 return orientation == Qt::Horizontal
1405 ? QRect(zero.x() + sectionPos, zero.y(), sectionSize, header->height())
1406 : QRect(zero.x(), zero.y() + sectionPos, header->width(), sectionSize);
1407}
1408
1409QString QAccessibleTableHeaderCell::text(QAccessible::Text t) const
1410{
1411 QAbstractItemModel *model = view->model();
1412 QString value;
1413 switch (t) {
1414 case QAccessible::Name:
1415 value = model->headerData(index, orientation, Qt::AccessibleTextRole).toString();
1416 if (value.isEmpty())
1417 value = model->headerData(index, orientation, Qt::DisplayRole).toString();
1418 break;
1419 case QAccessible::Description:
1420 value = model->headerData(index, orientation, Qt::AccessibleDescriptionRole).toString();
1421 break;
1422 default:
1423 break;
1424 }
1425 return value;
1426}
1427
1428void QAccessibleTableHeaderCell::setText(QAccessible::Text, const QString &)
1429{
1430 return;
1431}
1432
1433bool QAccessibleTableHeaderCell::isValid() const
1434{
1435 const QAbstractItemModel *theModel = view && !qt_widget_private(view)->data.in_destructor
1436 ? view->model() : nullptr;
1437 if (!theModel)
1438 return false;
1439 const QModelIndex rootIndex = view->rootIndex();
1440 return (index >= 0) && ((orientation == Qt::Horizontal)
1441 ? (index < theModel->columnCount(rootIndex))
1442 : (index < theModel->rowCount(rootIndex)));
1443}
1444
1445QAccessibleInterface *QAccessibleTableHeaderCell::parent() const
1446{
1447 return QAccessible::queryAccessibleInterface(view);
1448}
1449
1450QAccessibleInterface *QAccessibleTableHeaderCell::child(int) const
1451{
1452 return nullptr;
1453}
1454
1455QHeaderView *QAccessibleTableHeaderCell::headerView() const
1456{
1457 QHeaderView *header = nullptr;
1458 if (false) {
1459#if QT_CONFIG(tableview)
1460 } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) {
1461 if (orientation == Qt::Horizontal) {
1462 header = tv->horizontalHeader();
1463 } else {
1464 header = tv->verticalHeader();
1465 }
1466#endif
1467#if QT_CONFIG(treeview)
1468 } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) {
1469 header = tv->header();
1470#endif
1471 }
1472 return header;
1473}
1474
1475QT_END_NAMESPACE
1476
1477#endif // QT_CONFIG(accessibility)