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