source: trunk/src/plugins/accessible/widgets/complexwidgets.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 62.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the plugins of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "complexwidgets.h"
43
44#include <qapplication.h>
45#include <qabstractbutton.h>
46#include <qevent.h>
47#include <qheaderview.h>
48#include <qtabbar.h>
49#include <qcombobox.h>
50#include <qlistview.h>
51#include <qtableview.h>
52#include <qlineedit.h>
53#include <qstyle.h>
54#include <qstyleoption.h>
55#include <qtooltip.h>
56#include <qwhatsthis.h>
57#include <qtreeview.h>
58#include <private/qtabbar_p.h>
59#include <QAbstractScrollArea>
60#include <QScrollArea>
61#include <QScrollBar>
62#include <QDebug>
63
64#ifndef QT_NO_ACCESSIBILITY
65
66QT_BEGIN_NAMESPACE
67
68QString Q_GUI_EXPORT qt_accStripAmp(const QString &text);
69
70#ifndef QT_NO_ITEMVIEWS
71/*
72The MSDN article "Exposing Data Tables through Microsoft Active Accessibility" explains
73how data tables should be exposed. Url: http://msdn2.microsoft.com/en-us/library/ms971325.aspx
74Basically, the model is like this:
75
76ROLE_SYSTEM_TABLE
77 |- ROLE_SYSTEM_ROW
78 | |- ROLE_SYSTEM_ROWHEADER
79 | |- ROLE_SYSTEM_COLUMNHEADER
80 | |- ROLE_SYSTEM_COLUMNHEADER
81 | |- ROLE_SYSTEM_COLUMNHEADER
82 | '- ..
83 |- ROLE_SYSTEM_ROW
84 | |- ROLE_SYSTEM_ROWHEADER
85 | |- ROLE_SYSTEM_CELL
86 | |- ROLE_SYSTEM_CELL
87 | |- ROLE_SYSTEM_CELL
88 | '- ..
89 |- ROLE_SYSTEM_ROW
90 | |- ROLE_SYSTEM_ROWHEADER
91 | |- ROLE_SYSTEM_CELL
92 | |- ROLE_SYSTEM_CELL
93 | |- ROLE_SYSTEM_CELL
94 | '- ..
95 '- ..
96
97The headers of QTreeView is also represented like this.
98*/
99QAccessibleItemRow::QAccessibleItemRow(QAbstractItemView *aView, const QModelIndex &index, bool isHeader)
100 : row(index), view(aView), m_header(isHeader)
101{
102}
103
104QHeaderView *QAccessibleItemRow::horizontalHeader() const
105{
106 QHeaderView *header = 0;
107 if (m_header) {
108 if (false) {
109#ifndef QT_NO_TABLEVIEW
110 } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) {
111 header = tv->horizontalHeader();
112#endif
113#ifndef QT_NO_TREEVIEW
114 } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) {
115 header = tv->header();
116#endif
117 }
118 }
119 return header;
120}
121
122QHeaderView *QAccessibleItemRow::verticalHeader() const
123{
124 QHeaderView *header = 0;
125#ifndef QT_NO_TABLEVIEW
126 if (const QTableView *tv = qobject_cast<const QTableView*>(view))
127 header = tv->verticalHeader();
128#endif
129 return header;
130}
131
132int QAccessibleItemRow::logicalFromChild(QHeaderView *header, int child) const
133{
134 int logical = -1;
135 if (header->sectionsHidden()) {
136 int kid = 0;
137 for (int i = 0; i < header->count(); ++i) {
138 if (!header->isSectionHidden(i))
139 ++kid;
140 if (kid == child) {
141 logical = i;
142 break;
143 }
144 }
145 } else {
146 logical = child - 1;
147 }
148 return logical;
149}
150
151QRect QAccessibleItemRow::rect(int child) const
152{
153 QRect r;
154 if (view && view->isVisible()) {
155 if (QHeaderView *header = horizontalHeader()) {
156 if (!child) {
157 r = header->rect();
158 } else {
159 if (QHeaderView *vheader = verticalHeader()) {
160 if (child == 1) {
161 int w = vheader->width();
162 int h = header->height();
163 r.setRect(0, 0, w, h);
164 }
165 --child;
166 }
167 if (child) {
168 int logical = logicalFromChild(header, child);
169 int w = header->sectionSize(logical);
170 r.setRect(header->sectionViewportPosition(logical), 0, w, header->height());
171 r.translate(header->mapTo(view, QPoint(0, 0)));
172 }
173 }
174 } else if (row.isValid()) {
175 if (!child) {
176 QModelIndex parent = row.parent();
177 const int colCount = row.model()->columnCount(parent);
178 for (int i = 0; i < colCount; ++i)
179 r |= view->visualRect(row.model()->index(row.row(), i, parent));
180 r.translate(view->viewport()->mapTo(view, QPoint(0,0)));
181
182 if (const QHeaderView *vheader = verticalHeader()) { // include the section of the vertical header
183 QRect re;
184 int logicalRow = row.row();
185 int h = vheader->sectionSize(logicalRow);
186 re.setRect(0, vheader->sectionViewportPosition(logicalRow), vheader->width(), h);
187 re.translate(vheader->mapTo(view, QPoint(0, 0)));
188 r |= re;
189 }
190 } else {
191 if (QHeaderView *vheader = verticalHeader()) {
192 if (child == 1) {
193 int logicalRow = row.row();
194 int h = vheader->sectionSize(logicalRow);
195 r.setRect(0, vheader->sectionViewportPosition(logicalRow), vheader->width(), h);
196 r.translate(vheader->mapTo(view, QPoint(0, 0)));
197 }
198 --child;
199 }
200 if (child) {
201 r = view->visualRect(childIndex(child));
202 r.translate(view->viewport()->mapTo(view, QPoint(0,0)));
203 }
204 }
205 }
206 }
207 if (!r.isNull())
208 r.translate(view->mapToGlobal(QPoint(0, 0)));
209
210 return r;
211}
212
213int QAccessibleItemRow::treeLevel() const
214{
215 int level = 0;
216 QModelIndex idx = row;
217 while (idx.isValid()) {
218 idx = idx.parent();
219 ++level;
220 }
221 return level;
222}
223
224QString QAccessibleItemRow::text_helper(int child) const
225{
226 QString value;
227 if (m_header) {
228 if (!child)
229 return QString();
230 if (verticalHeader()) {
231 if (child == 1)
232 return QString();
233 --child;
234 }
235 QHeaderView *header = horizontalHeader();
236 int logical = logicalFromChild(header, child);
237 value = view->model()->headerData(logical, Qt::Horizontal, Qt::AccessibleTextRole).toString();
238 if (value.isEmpty())
239 value = view->model()->headerData(logical, Qt::Horizontal).toString();
240 return value;
241 } else {
242 if (!child) { // for one-column views (i.e. QListView)
243 if (children().count() >= 1)
244 child = 1;
245 else
246 return QString();
247 }
248 if (verticalHeader()) {
249 if (child == 1) {
250 int logical = row.row();
251 value = view->model()->headerData(logical, Qt::Vertical, Qt::AccessibleTextRole).toString();
252 if (value.isEmpty())
253 value = view->model()->headerData(logical, Qt::Vertical).toString();
254 return value;
255 } else {
256 --child;
257 }
258 }
259 }
260 if (value.isEmpty()) {
261 QModelIndex idx = childIndex(child);
262 if (idx.isValid()) {
263 value = idx.model()->data(idx, Qt::AccessibleTextRole).toString();
264 if (value.isEmpty())
265 value = idx.model()->data(idx, Qt::DisplayRole).toString();
266 }
267 }
268 return value;
269}
270
271QString QAccessibleItemRow::text(Text t, int child) const
272{
273 QString value;
274 if (t == Name) {
275 value = text_helper(child);
276 } else if (t == Value) {
277#ifndef QT_NO_TREEVIEW
278 if (qobject_cast<const QTreeView*>(view)) {
279 if (child == 0)
280 value = QString::number(treeLevel());
281 } else
282#endif
283 {
284 value = text_helper(child);
285 }
286 } else if (t == Description) {
287#ifndef QT_NO_TREEVIEW
288 if (child == 0 && qobject_cast<const QTreeView*>(view)) {
289 // We store the tree coordinates of the current item in the description.
290 // This enables some screen readers to report where the focus is
291 // in a tree view. (works in JAWS). Also, Firefox does the same thing.
292 // For instance the description "L2, 4 of 25 with 24" means
293 // "L2": Tree Level 2
294 // "4 of 25": We are item 4 out of in total 25 other siblings
295 // "with 24": We have 24 children. (JAWS does not read this number)
296
297 // level
298 int level = treeLevel();
299
300 QAbstractItemModel *m = view->model();
301 // totalSiblings and itemIndex
302 QModelIndex parent = row.parent();
303 int rowCount = m->rowCount(parent);
304 int itemIndex = -1;
305 int totalSiblings = 0;
306 for (int i = 0 ; i < rowCount; ++i) {
307 QModelIndex sibling = row.sibling(i, 0);
308 if (!view->isIndexHidden(sibling))
309 ++totalSiblings;
310 if (row == sibling)
311 itemIndex = totalSiblings;
312 }
313 int totalChildren = m->rowCount(row); // JAWS does not report child count, so we do
314 // this simple and efficient.
315 // (don't check if they are all visible).
316 value = QString::fromAscii("L%1, %2 of %3 with %4").arg(level).arg(itemIndex).arg(totalSiblings).arg(totalChildren);
317 } else
318#endif // QT_NO_TREEVIEW
319 {
320 if (!m_header) {
321 if (child == 0 && children().count() >= 1)
322 child = 1;
323 if (verticalHeader()) {
324 if (child == 1) {
325 value = view->model()->headerData(row.row(), Qt::Vertical).toString();
326 }
327 --child;
328 }
329 if (child) {
330 QModelIndex idx = childIndex(child);
331 value = idx.model()->data(idx, Qt::AccessibleDescriptionRole).toString();
332 }
333
334 }
335 }
336 }
337 return value;
338}
339
340void QAccessibleItemRow::setText(Text t, int child, const QString &text)
341{
342 if (m_header) {
343 if (child)
344 view->model()->setHeaderData(child - 1, Qt::Horizontal, text);
345 // child == 0 means the cell to the left of the horizontal header, which is empty!?
346 } else {
347 if (!child) {
348 if (children().count() == 1)
349 child = 1;
350 else
351 return;
352 }
353
354 if (verticalHeader()) {
355 if (child == 1) {
356 view->model()->setHeaderData(row.row(), Qt::Vertical, text);
357 return;
358 }
359 --child;
360 }
361 QModelIndex idx = childIndex(child);
362 if (!idx.isValid())
363 return;
364
365 switch (t) {
366 case Description:
367 const_cast<QAbstractItemModel *>(idx.model())->setData(idx, text,
368 Qt::AccessibleDescriptionRole);
369 break;
370 case Value:
371 const_cast<QAbstractItemModel *>(idx.model())->setData(idx, text, Qt::EditRole);
372 break;
373 default:
374 break;
375 }
376 }
377}
378
379QModelIndex QAccessibleItemRow::childIndex(int child) const
380{
381 QList<QModelIndex> kids = children();
382 Q_ASSERT(child >= 1 && child <= kids.count());
383 return kids.at(child - 1);
384}
385
386QList<QModelIndex> QAccessibleItemRow::children() const
387{
388 QList<QModelIndex> kids;
389 for (int i = 0; i < row.model()->columnCount(row.parent()); ++i) {
390 QModelIndex idx = row.model()->index(row.row(), i, row.parent());
391 if (!view->isIndexHidden(idx)) {
392 kids << idx;
393 }
394 }
395 return kids;
396}
397
398bool QAccessibleItemRow::isValid() const
399{
400 return m_header ? true : row.isValid();
401}
402
403QObject *QAccessibleItemRow::object() const
404{
405 return 0;
406}
407
408int QAccessibleItemRow::childCount() const
409{
410 int count = 0;
411 if (QHeaderView *header = horizontalHeader()) {
412 count = header->count() - header->hiddenSectionCount();
413 } else {
414 count = children().count();
415 }
416#ifndef QT_NO_TABLEVIEW
417 if (qobject_cast<const QTableView*>(view)) {
418 if (verticalHeader())
419 ++count;
420 }
421#endif
422 return count;
423}
424
425int QAccessibleItemRow::indexOfChild(const QAccessibleInterface *iface) const
426{
427 if (!iface || iface->role(0) != Row)
428 return -1;
429
430 //### meaningless code?
431 QList<QModelIndex> kids = children();
432 QModelIndex idx = static_cast<const QAccessibleItemRow *>(iface)->row;
433 if (!idx.isValid())
434 return -1;
435 return kids.indexOf(idx) + 1;
436}
437
438QAccessible::Relation QAccessibleItemRow::relationTo(int child, const QAccessibleInterface *other,
439 int otherChild) const
440{
441 if (!child && !otherChild && other->object() == view)
442 return Child;
443 if (!child && !otherChild && other == this)
444 return Self;
445 if (!child && otherChild && other == this)
446 return Ancestor;
447 if (child && otherChild && other == this)
448 return Sibling;
449 return Unrelated;
450}
451
452int QAccessibleItemRow::childAt(int x, int y) const
453{
454 if (!view || !view->isVisible())
455 return -1;
456
457 for (int i = childCount(); i >= 0; --i) {
458 if (rect(i).contains(x, y))
459 return i;
460 }
461 return -1;
462}
463
464QAbstractItemView::CursorAction QAccessibleItemRow::toCursorAction(
465 QAccessible::Relation rel)
466{
467 switch (rel) {
468 case QAccessible::Up:
469 return QAbstractItemView::MoveUp;
470 case QAccessible::Down:
471 return QAbstractItemView::MoveDown;
472 case QAccessible::Left:
473 return QAbstractItemView::MoveLeft;
474 case QAccessible::Right:
475 return QAbstractItemView::MoveRight;
476 default:
477 Q_ASSERT(false);
478 }
479 // should never be reached.
480 return QAbstractItemView::MoveRight;
481}
482
483int QAccessibleItemRow::navigate(RelationFlag relation, int index,
484 QAccessibleInterface **iface) const
485{
486 *iface = 0;
487 if (!view)
488 return -1;
489
490 switch (relation) {
491 case Ancestor: {
492 if (!index)
493 return -1;
494 QAccessibleItemView *ancestor = new QAccessibleItemView(view->viewport());
495 if (index == 1) {
496 *iface = ancestor;
497 return 0;
498 } else if (index > 1) {
499 int ret = ancestor->navigate(Ancestor, index - 1, iface);
500 delete ancestor;
501 return ret;
502 }
503 }
504 case Child: {
505 if (!index)
506 return -1;
507 if (index < 1 && index > childCount())
508 return -1;
509
510 return index;}
511 case Sibling:
512 if (index) {
513 QAccessibleInterface *ifaceParent = 0;
514 navigate(Ancestor, 1, &ifaceParent);
515 if (ifaceParent) {
516 int entry = ifaceParent->navigate(Child, index, iface);
517 delete ifaceParent;
518 return entry;
519 }
520 }
521 return -1;
522 case Up:
523 case Down:
524 case Left:
525 case Right: {
526 // This is in the "not so nice" category. In order to find out which item
527 // is geometrically around, we have to set the current index, navigate
528 // and restore the index as well as the old selection
529 view->setUpdatesEnabled(false);
530 const QModelIndex oldIdx = view->currentIndex();
531 QList<QModelIndex> kids = children();
532 const QModelIndex currentIndex = index ? kids.at(index - 1) : QModelIndex(row);
533 const QItemSelection oldSelection = view->selectionModel()->selection();
534 view->setCurrentIndex(currentIndex);
535 const QModelIndex idx = view->moveCursor(toCursorAction(relation), Qt::NoModifier);
536 view->setCurrentIndex(oldIdx);
537 view->selectionModel()->select(oldSelection, QItemSelectionModel::ClearAndSelect);
538 view->setUpdatesEnabled(true);
539 if (!idx.isValid())
540 return -1;
541
542 if (idx.parent() != row.parent() || idx.row() != row.row())
543 *iface = new QAccessibleItemRow(view, idx);
544 return index ? kids.indexOf(idx) + 1 : 0; }
545 default:
546 break;
547 }
548
549 return -1;
550}
551
552QAccessible::Role QAccessibleItemRow::role(int child) const
553{
554 if (false) {
555#ifndef QT_NO_TREEVIEW
556 } else if (qobject_cast<const QTreeView*>(view)) {
557 if (horizontalHeader()) {
558 if (!child)
559 return Row;
560 return ColumnHeader;
561 }
562 return TreeItem;
563#endif
564#ifndef QT_NO_LISTVIEW
565 } else if (qobject_cast<const QListView*>(view)) {
566 return ListItem;
567#endif
568#ifndef QT_NO_TABLEVIEW
569 } else if (qobject_cast<const QTableView *>(view)) {
570 if (!child)
571 return Row;
572 if (child == 1) {
573 if (verticalHeader())
574 return RowHeader;
575 }
576 if (m_header)
577 return ColumnHeader;
578#endif
579 }
580 return Cell;
581}
582
583QAccessible::State QAccessibleItemRow::state(int child) const
584{
585 State st = Normal;
586
587 if (!view)
588 return st;
589
590 QAccessibleInterface *parent = 0;
591 QRect globalRect;
592 if (navigate(Ancestor, 1, &parent) == 0) {
593 globalRect = parent->rect(0);
594 delete parent;
595 }
596 if (!globalRect.intersects(rect(child)))
597 st |= Invisible;
598
599 if (!horizontalHeader()) {
600 if (!(st & Invisible)) {
601 if (child) {
602 if (QHeaderView *vheader = verticalHeader() ) {
603 if (child == 1) {
604 if (!vheader->isVisible())
605 st |= Invisible;
606 }
607 --child;
608 }
609 if (child) {
610 QModelIndex idx = childIndex(child);
611 if (!idx.isValid())
612 return st;
613
614 if (view->selectionModel()->isSelected(idx))
615 st |= Selected;
616 if (view->selectionModel()->currentIndex() == idx)
617 st |= Focused;
618 if (idx.model()->data(idx, Qt::CheckStateRole).toInt() == Qt::Checked)
619 st |= Checked;
620
621 Qt::ItemFlags flags = idx.flags();
622 if (flags & Qt::ItemIsSelectable) {
623 st |= Selectable;
624 if (view->selectionMode() == QAbstractItemView::MultiSelection)
625 st |= MultiSelectable;
626 if (view->selectionMode() == QAbstractItemView::ExtendedSelection)
627 st |= ExtSelectable;
628 }
629 }
630 } else {
631 Qt::ItemFlags flags = row.flags();
632 if (flags & Qt::ItemIsSelectable) {
633 st |= Selectable;
634 st |= Focusable;
635 }
636 if (view->selectionModel()->isRowSelected(row.row(), row.parent()))
637 st |= Selected;
638 if (view->selectionModel()->currentIndex().row() == row.row())
639 st |= Focused;
640 }
641 }
642 }
643
644 return st;
645}
646
647int QAccessibleItemRow::userActionCount(int) const
648{
649 return 0;
650}
651
652QString QAccessibleItemRow::actionText(int, Text, int) const
653{
654 return QString();
655}
656
657static QItemSelection rowAt(const QModelIndex &idx)
658{
659 return QItemSelection(idx.sibling(idx.row(), 0),
660 idx.sibling(idx.row(), idx.model()->columnCount(idx.parent())));
661}
662
663bool QAccessibleItemRow::doAction(int action, int child, const QVariantList & /*params*/)
664{
665 if (!view)
666 return false;
667
668 if (verticalHeader())
669 --child;
670
671 QModelIndex idx = child ? childIndex(child) : QModelIndex(row);
672 if (!idx.isValid())
673 return false;
674
675 QItemSelectionModel::SelectionFlags command = QItemSelectionModel::NoUpdate;
676
677 switch (action) {
678 case SetFocus:
679 view->setCurrentIndex(idx);
680 return true;
681 case ExtendSelection:
682 if (!child)
683 return false;
684 view->selectionModel()->select(QItemSelection(view->currentIndex(), idx),
685 QItemSelectionModel::SelectCurrent);
686 return true;
687 case Select:
688 command = QItemSelectionModel::ClearAndSelect;
689 break;
690 case ClearSelection:
691 command = QItemSelectionModel::Clear;
692 break;
693 case RemoveSelection:
694 command = QItemSelectionModel::Deselect;
695 break;
696 case AddToSelection:
697 command = QItemSelectionModel::SelectCurrent;
698 break;
699 }
700 if (command == QItemSelectionModel::NoUpdate)
701 return false;
702
703 if (child)
704 view->selectionModel()->select(idx, command);
705 else
706 view->selectionModel()->select(rowAt(row), command);
707 return true;
708}
709
710class ModelIndexIterator
711{
712public:
713 ModelIndexIterator(QAbstractItemView *view, const QModelIndex &start = QModelIndex()) : m_view(view)
714 {
715#ifndef QT_NO_LISTVIEW
716 list = qobject_cast<QListView*>(m_view);
717#endif
718#ifndef QT_NO_TREEVIEW
719 tree = qobject_cast<QTreeView*>(m_view);
720#endif
721#ifndef QT_NO_TABLEVIEW
722 table = qobject_cast<QTableView*>(m_view);
723#endif
724 if (start.isValid()) {
725 m_current = start;
726 } else if (m_view && m_view->model()) {
727 m_current = view->rootIndex().isValid() ?
728 view->rootIndex().child(0,0) : view->model()->index(0, 0);
729 }
730 }
731
732 bool next(int count = 1) {
733 for (int i = 0; i < count; ++i) {
734 do {
735 if (m_current.isValid()) {
736 const QAbstractItemModel *m = m_current.model();
737#ifndef QT_NO_TREEVIEW
738 if (tree && m_current.model()->hasChildren(m_current) && tree->isExpanded(m_current)) {
739 m_current = m_current.child(0, 0);
740 } else
741#endif
742 {
743 int row = m_current.row();
744 QModelIndex par = m_current.parent();
745
746 // Go up to the parent if we reach the end of the rows
747 // If m_curent becomses invalid, stop going up.
748 while (row + 1 >= m->rowCount(par)) {
749 m_current = par;
750 if (m_current.isValid()) {
751 row = m_current.row();
752 par = m_current.parent();
753 } else {
754 row = 0;
755 par = QModelIndex();
756 break;
757 }
758 }
759
760 if (m_current.isValid())
761 m_current = m_current.sibling(row + 1, 0);
762 }
763 }
764 } while (isHidden());
765 }
766 return m_current.isValid();
767 }
768
769 bool isHidden() const {
770 if (false) {
771#ifndef QT_NO_LISTVIEW
772 } else if (list) {
773 return list->isRowHidden(m_current.row());
774#endif
775#ifndef QT_NO_TREEVIEW
776 } else if (tree) {
777 return tree->isRowHidden(m_current.row(), m_current.parent());
778#endif
779#ifndef QT_NO_TABLEVIEW
780 } else if (table) {
781 return table->isRowHidden(m_current.row());
782#endif
783 }
784 return false;
785 }
786
787 QModelIndex current() const {
788 return m_current;
789 }
790
791private:
792 QModelIndex m_current;
793 QAbstractItemView *m_view;
794
795#ifndef QT_NO_TREEVIEW
796 QTreeView *tree;
797#endif
798#ifndef QT_NO_LISTVIEW
799 QListView *list;
800#endif
801#ifndef QT_NO_TABLEVIEW
802 QTableView *table;
803#endif
804};
805
806QAccessibleItemView::QAccessibleItemView(QWidget *w)
807 : QAccessibleAbstractScrollArea(w->objectName() == QLatin1String("qt_scrollarea_viewport") ? w->parentWidget() : w)
808{
809 atVP = w->objectName() == QLatin1String("qt_scrollarea_viewport");
810
811}
812
813
814QHeaderView *QAccessibleItemView::horizontalHeader() const
815{
816 QHeaderView *header = 0;
817 if (false) {
818#ifndef QT_NO_TABLEVIEW
819 } else if (const QTableView *tv = qobject_cast<const QTableView*>(itemView())) {
820 header = tv->horizontalHeader();
821#endif
822#ifndef QT_NO_TREEVIEW
823 } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(itemView())) {
824 header = tv->header();
825#endif
826 }
827 return header;
828}
829
830QHeaderView *QAccessibleItemView::verticalHeader() const
831{
832 QHeaderView *header = 0;
833 if (false) {
834#ifndef QT_NO_TABLEVIEW
835 } else if (const QTableView *tv = qobject_cast<const QTableView*>(itemView())) {
836 header = tv->verticalHeader();
837#endif
838 }
839 return header;
840}
841
842
843bool QAccessibleItemView::isValidChildRole(QAccessible::Role role) const
844{
845 if (atViewport()) {
846 if (false) {
847#ifndef QT_NO_TREEVIEW
848 } else if (qobject_cast<const QTreeView*>(itemView())) {
849 return (role == TreeItem || role == Row);
850#endif
851#ifndef QT_NO_LISTVIEW
852 } else if (qobject_cast<const QListView*>(itemView())) {
853 return (role == ListItem);
854#endif
855 }
856 // TableView
857 return role == Row;
858 } else {
859 if (false) {
860#ifndef QT_NO_TREEVIEW
861 } else if (qobject_cast<const QTreeView*>(itemView())) {
862 return (role == Tree);
863#endif
864#ifndef QT_NO_LISTVIEW
865 } else if (qobject_cast<const QListView*>(itemView())) {
866 return (role == List);
867#endif
868 }
869 // TableView
870 return (role == Table);
871 }
872}
873
874QObject *QAccessibleItemView::object() const
875{
876 QObject *view = QAccessibleAbstractScrollArea::object();
877 Q_ASSERT(qobject_cast<const QAbstractItemView *>(view));
878 if (atViewport())
879 view = qobject_cast<const QAbstractItemView *>(view)->viewport();
880 return view;
881}
882
883QAbstractItemView *QAccessibleItemView::itemView() const
884{
885 return qobject_cast<QAbstractItemView *>(QAccessibleAbstractScrollArea::object());
886}
887
888int QAccessibleItemView::indexOfChild(const QAccessibleInterface *iface) const
889{
890 if (atViewport()) {
891 if (!iface || !isValidChildRole(iface->role(0)))
892 return -1;
893
894 int entry = -1;