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

source code of qtbase/src/widgets/accessible/itemviews.cpp