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
RevLine 
[2]1/****************************************************************************
2**
[846]3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
[561]4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
[2]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**
[561]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.
[2]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**
[561]36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
[2]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()) {
[769]727 m_current = view->rootIndex().isValid() ?
728 view->rootIndex().child(0,0) : view->model()->index(0, 0);
[2]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;
895 // ### This will fail if a row is hidden.
896 const QAccessibleItemRow *ifRow = static_cast<const QAccessibleItemRow *>(iface);
897 if (ifRow->horizontalHeader())
898 return 1;
899
900 QModelIndex idx = ifRow->row;
901 if (!idx.isValid())
902 return -1;
903
904 entry = entryFromIndex(idx);
905 if (horizontalHeader())
906 ++entry;
907
908 return entry;
909
910 } else {
911 return QAccessibleAbstractScrollArea::indexOfChild(iface);
912 }
913}
914
915QModelIndex QAccessibleItemView::childIndex(int child) const
916{
917 if (!atViewport())
918 return QModelIndex();
919 ModelIndexIterator it(itemView());
920 it.next(child - 1);
921 return it.current();
922}
923
924int QAccessibleItemView::entryFromIndex(const QModelIndex &index) const
925{
926 int entry = -1;
927 if (false) {
928#ifndef QT_NO_TREEVIEW
929 } else if (QTreeView *tree = qobject_cast<QTreeView*>(itemView())) {
930 entry = tree->visualIndex(index) + 1;
931#endif
932#ifndef QT_NO_LISTVIEW
933 } else if (QListView *list = qobject_cast<QListView*>(itemView())) {
934 entry = list->visualIndex(index) + 1;
935#endif
936#ifndef QT_NO_TABLEVIEW
937 } else if (QTableView *table = qobject_cast<QTableView*>(itemView())) {
938 entry = table->visualIndex(index) + 1;
939#endif
940 }
941 return entry;
942}
943
944int QAccessibleItemView::childCount() const
945{
946 if (atViewport()) {
947 if (itemView()->model() == 0)
948 return 0;
949 QAbstractItemModel *m = itemView()->model();
950 QModelIndex idx = m->index(0,0);
951 if (!idx.isValid())
952 return 0;
953 ModelIndexIterator it(itemView());
954 int count = 1;
955 while (it.next()) {
956 ++count;
957 }
958 if (horizontalHeader())
959 ++count;
960
961 return count;
962 } else {
963 return QAccessibleAbstractScrollArea::childCount();
964 }
965}
966
967QString QAccessibleItemView::text(Text t, int child) const
968{
969 if (atViewport()) {
970 if (!child)
971 return QAccessibleAbstractScrollArea::text(t, child);
972
973 QAccessibleItemRow item(itemView(), childIndex(child));
974 return item.text(t, 1);
975 } else {
976 return QAccessibleAbstractScrollArea::text(t, child);
977 }
978}
979
980void QAccessibleItemView::setText(Text t, int child, const QString &text)
981{
982 if (atViewport()) {
983 if (!child) {
984 QAccessibleAbstractScrollArea::setText(t, child, text);
985 return;
986 }
987
988 QAccessibleItemRow item(itemView(), childIndex(child));
989 item.setText(t, 1, text);
990 } else {
991 QAccessibleAbstractScrollArea::setText(t, child, text);
992 }
993}
994
995QRect QAccessibleItemView::rect(int child) const
996{
997 if (atViewport()) {
998 QRect r;
999 if (!child) {
1000 // Make sure that the rect *include* the vertical and horizontal headers, while
1001 // not including the potential vertical and horizontal scrollbars.
1002 QAbstractItemView *w = itemView();
1003
1004 int vscrollWidth = 0;
1005 const QScrollBar *sb = w->verticalScrollBar();
1006 if (sb && sb->isVisible())
1007 vscrollWidth = sb->width();
1008
1009 int hscrollHeight = 0;
1010 sb = w->horizontalScrollBar();
1011 if (sb && sb->isVisible())
1012 hscrollHeight = sb->height();
1013
1014 QPoint globalPos = w->mapToGlobal(QPoint(0,0));
1015 r = w->rect().translated(globalPos);
1016 if (w->isRightToLeft()) {
1017 r.adjust(vscrollWidth, 0, 0, -hscrollHeight);
1018 } else {
1019 r.adjust(0, 0, -vscrollWidth, -hscrollHeight);
1020 }
1021 } else {
1022 QAccessibleInterface *iface = 0;
1023 if (navigate(Child, child, &iface) == 0) {
1024 r = iface->rect(0);
1025 delete iface;
1026 }
1027 }
1028 return r;
1029 } else {
1030 QRect r = QAccessibleAbstractScrollArea::rect(child);
1031 if (child == 1) {
1032 // include the potential vertical and horizontal headers
1033
1034 const QHeaderView *header = verticalHeader();
1035 int headerWidth = (header && header->isVisible()) ? header->width() : 0;
1036 header = horizontalHeader();
1037 int headerHeight= (header && header->isVisible()) ? header->height() : 0;
1038 if (itemView()->isRightToLeft()) {
1039 r.adjust(0, -headerHeight, headerWidth, 0);
1040 } else {
1041 r.adjust(-headerWidth, -headerHeight, 0, 0);
1042 }
1043 }
1044 return r;
1045 }
1046}
1047
1048int QAccessibleItemView::childAt(int x, int y) const
1049{
1050 if (atViewport()) {
1051 QPoint p(x, y);
1052 for (int i = childCount(); i >= 0; --i) {
1053 if (rect(i).contains(p))
1054 return i;
1055 }
1056 return -1;
1057 } else {
1058 return QAccessibleAbstractScrollArea::childAt(x, y);
1059 }
1060}
1061
1062QAccessible::Role QAccessibleItemView::role(int child) const
1063{
1064 if ((!atViewport() && child) || (atViewport() && child == 0)) {
1065 QAbstractItemView *view = itemView();
1066#ifndef QT_NO_TABLEVIEW
1067 if (qobject_cast<QTableView *>(view))
1068 return Table;
1069#endif
1070#ifndef QT_NO_LISTVIEW
1071 if (qobject_cast<QListView *>(view))
1072 return List;
1073#endif
1074 return Tree;
1075 }
1076 if (atViewport()) {
1077 if (child)
1078 return Row;
1079 }
1080
1081 return QAccessibleAbstractScrollArea::role(child);
1082}
1083
1084QAccessible::State QAccessibleItemView::state(int child) const
1085{
1086 State st = Normal;
1087
1088 if (itemView() == 0)
1089 return State(Unavailable);
1090
1091 bool queryViewPort = (atViewport() && child == 0) || (!atViewport() && child == 1);
1092 if (queryViewPort) {
1093 if (itemView()->selectionMode() != QAbstractItemView::NoSelection) {
1094 st |= Selectable;
1095 st |= Focusable;
1096 }
1097 } else if (atViewport()) { // children of viewport
1098 if (horizontalHeader())
1099 --child;
1100 if (child) {
1101 QAccessibleItemRow item(itemView(), childIndex(child));
1102 st |= item.state(0);
1103 }
1104 } else if (!atViewport() && child != 1) {
1105 st = QAccessibleAbstractScrollArea::state(child);
1106 }
1107 return st;
1108}
1109
1110bool QAccessibleItemView::isValid() const
1111{
1112 if (atViewport())
1113 return QAccessibleWidgetEx::isValid();
1114 else
1115 return QAccessibleAbstractScrollArea::isValid();
1116}
1117
1118int QAccessibleItemView::navigate(RelationFlag relation, int index,
1119 QAccessibleInterface **iface) const
1120{
1121 if (atViewport()) {
1122 if (relation == Ancestor && index == 1) {
1123 *iface = new QAccessibleItemView(itemView());
1124 return 0;
1125 } else if (relation == Child && index >= 1) {
1126 if (horizontalHeader()) {
1127 if (index == 1) {
1128 *iface = new QAccessibleItemRow(itemView(), QModelIndex(), true);
1129 return 0;
1130 }
1131 --index;
1132 }
1133
1134 //###JAS hidden rows..
1135 QModelIndex idx = childIndex(index);
1136 if (idx.isValid()) {
1137 *iface = new QAccessibleItemRow(itemView(), idx);
1138 return 0;
1139 }
1140 } else if (relation == Sibling && index >= 1) {
1141 QAccessibleInterface *parent = new QAccessibleItemView(itemView());
1142 return parent->navigate(Child, index, iface);
1143 }
1144 *iface = 0;
1145 return -1;
1146 } else {
1147 return QAccessibleAbstractScrollArea::navigate(relation, index, iface);
1148 }
1149}
1150
1151/* returns the model index for a given row and column */
1152QModelIndex QAccessibleItemView::index(int row, int column) const
1153{
1154 return itemView()->model()->index(row, column);
1155}
1156
1157QAccessibleInterface *QAccessibleItemView::accessibleAt(int row, int column)
1158{
1159 QWidget *indexWidget = itemView()->indexWidget(index(row, column));
1160 return QAccessible::queryAccessibleInterface(indexWidget);
1161}
1162
1163/* We don't have a concept of a "caption" in Qt's standard widgets */
1164QAccessibleInterface *QAccessibleItemView::caption()
1165{
1166 return 0;
1167}
1168
1169/* childIndex is row * columnCount + columnIndex */
1170int QAccessibleItemView::childIndex(int rowIndex, int columnIndex)
1171{
1172 return rowIndex * itemView()->model()->columnCount() + columnIndex;
1173}
1174
1175/* Return the header data as column description */
1176QString QAccessibleItemView::columnDescription(int column)
1177{
1178 return itemView()->model()->headerData(column, Qt::Horizontal).toString();
1179}
1180
1181/* We don't support column spanning atm */
1182int QAccessibleItemView::columnSpan(int /* row */, int /* column */)
1183{
1184 return 1;
1185}
1186
1187/* Return the horizontal header view */
1188QAccessibleInterface *QAccessibleItemView::columnHeader()
1189{
1190#ifndef QT_NO_TREEVIEW
1191 if (QTreeView *tree = qobject_cast<QTreeView *>(itemView()))
1192 return QAccessible::queryAccessibleInterface(tree->header());
1193#endif
1194#ifndef QT_NO_TABLEVIEW
1195 if (QTableView *table = qobject_cast<QTableView *>(itemView()))
1196 return QAccessible::queryAccessibleInterface(table->horizontalHeader());
1197#endif
1198 return 0;
1199}
1200
1201int QAccessibleItemView::columnIndex(int childIndex)
1202{
1203 int columnCount = itemView()->model()->columnCount();
1204 if (!columnCount)
1205 return 0;
1206
1207 return childIndex % columnCount;
1208}
1209
1210int QAccessibleItemView::columnCount()
1211{
1212 return itemView()->model()->columnCount();
1213}
1214
1215int QAccessibleItemView::rowCount()
1216{
1217 return itemView()->model()->rowCount();
1218}
1219
1220int QAccessibleItemView::selectedColumnCount()
1221{
1222 return itemView()->selectionModel()->selectedColumns().count();
1223}
1224
1225int QAccessibleItemView::selectedRowCount()
1226{
1227 return itemView()->selectionModel()->selectedRows().count();
1228}
1229
1230QString QAccessibleItemView::rowDescription(int row)
1231{
1232 return itemView()->model()->headerData(row, Qt::Vertical).toString();
1233}
1234
1235/* We don't support row spanning */
1236int QAccessibleItemView::rowSpan(int /*row*/, int /*column*/)
1237{
1238 return 1;
1239}
1240
1241QAccessibleInterface *QAccessibleItemView::rowHeader()
1242{
1243#ifndef QT_NO_TABLEVIEW
1244 if (QTableView *table = qobject_cast<QTableView *>(itemView()))
1245 return QAccessible::queryAccessibleInterface(table->verticalHeader());
1246#endif
1247 return 0;
1248}
1249
1250int QAccessibleItemView::rowIndex(int childIndex)
1251{
1252 int columnCount = itemView()->model()->columnCount();
1253 if (!columnCount)
1254 return 0;
1255
1256 return int(childIndex / columnCount);
1257}
1258
1259int QAccessibleItemView::selectedRows(int maxRows, QList<int> *rows)
1260{
1261 Q_ASSERT(rows);
1262
1263 const QModelIndexList selRows = itemView()->selectionModel()->selectedRows();
1264 int maxCount = qMin(selRows.count(), maxRows);
1265
1266 for (int i = 0; i < maxCount; ++i)
1267 rows->append(selRows.at(i).row());
1268
1269 return maxCount;
1270}
1271
1272int QAccessibleItemView::selectedColumns(int maxColumns, QList<int> *columns)
1273{
1274 Q_ASSERT(columns);
1275
1276 const QModelIndexList selColumns = itemView()->selectionModel()->selectedColumns();
1277 int maxCount = qMin(selColumns.count(), maxColumns);
1278
1279 for (int i = 0; i < maxCount; ++i)
1280 columns->append(selColumns.at(i).row());
1281
1282 return maxCount;
1283}
1284
1285/* Qt widgets don't have a concept of a summary */
1286QAccessibleInterface *QAccessibleItemView::summary()
1287{
1288 return 0;
1289}
1290
1291bool QAccessibleItemView::isColumnSelected(int column)
1292{
1293 return itemView()->selectionModel()->isColumnSelected(column, QModelIndex());
1294}
1295
1296bool QAccessibleItemView::isRowSelected(int row)
1297{
1298 return itemView()->selectionModel()->isRowSelected(row, QModelIndex());
1299}
1300
1301bool QAccessibleItemView::isSelected(int row, int column)
1302{
1303 return itemView()->selectionModel()->isSelected(index(row, column));
1304}
1305
1306void QAccessibleItemView::selectRow(int row)
1307{
1308 QItemSelectionModel *s = itemView()->selectionModel();
1309 s->select(index(row, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
1310}
1311
1312void QAccessibleItemView::selectColumn(int column)
1313{
1314 QItemSelectionModel *s = itemView()->selectionModel();
1315 s->select(index(0, column), QItemSelectionModel::Select | QItemSelectionModel::Columns);
1316}
1317
1318void QAccessibleItemView::unselectRow(int row)
1319{
1320 QItemSelectionModel *s = itemView()->selectionModel();
1321 s->select(index(row, 0), QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
1322}
1323
1324void QAccessibleItemView::unselectColumn(int column)
1325{
1326 QItemSelectionModel *s = itemView()->selectionModel();
1327 s->select(index(0, column), QItemSelectionModel::Deselect | QItemSelectionModel::Columns);
1328}
1329
1330void QAccessibleItemView::cellAtIndex(int index, int *row, int *column, int *rSpan,
1331 int *cSpan, bool *isSelect)
1332{
1333 *row = rowIndex(index);
1334 *column = columnIndex(index);
1335 *rSpan = rowSpan(*row, *column);
1336 *cSpan = columnSpan(*row, *column);
1337 *isSelect = isSelected(*row, *column);
1338}
1339
1340/*!
1341 \class QAccessibleHeader
1342 \brief The QAccessibleHeader class implements the QAccessibleInterface for header widgets.
1343 \internal
1344
1345 \ingroup accessibility
1346*/
1347
1348/*!
1349 Constructs a QAccessibleHeader object for \a w.
1350*/
1351QAccessibleHeader::QAccessibleHeader(QWidget *w)
1352: QAccessibleWidgetEx(w)
1353{
1354 Q_ASSERT(header());
1355 addControllingSignal(QLatin1String("sectionClicked(int)"));
1356}
1357
1358/*! Returns the QHeaderView. */
1359QHeaderView *QAccessibleHeader::header() const
1360{
1361 return qobject_cast<QHeaderView*>(object());
1362}
1363
1364/*! \reimp */
1365QRect QAccessibleHeader::rect(int child) const
1366{
1367 if (!child)
1368 return QAccessibleWidgetEx::rect(0);
1369
1370 QHeaderView *h = header();
1371 QPoint zero = h->mapToGlobal(QPoint(0, 0));
1372 int sectionSize = h->sectionSize(child - 1);
1373 int sectionPos = h->sectionPosition(child - 1);
1374 return h->orientation() == Qt::Horizontal
1375 ? QRect(zero.x() + sectionPos, zero.y(), sectionSize, h->height())
1376 : QRect(zero.x(), zero.y() + sectionPos, h->width(), sectionSize);
1377}
1378
1379/*! \reimp */
1380int QAccessibleHeader::childCount() const
1381{
1382 return header()->count();
1383}
1384
1385/*! \reimp */
1386QString QAccessibleHeader::text(Text t, int child) const
1387{
1388 QString str;
1389
1390 if (child > 0 && child <= childCount()) {
1391 switch (t) {
1392 case Name:
1393 str = header()->model()->headerData(child - 1, header()->orientation()).toString();
1394 break;
1395 case Description: {
1396 QAccessibleEvent event(QEvent::AccessibilityDescription, child);
1397 if (QApplication::sendEvent(widget(), &event))
1398 str = event.value();
1399 break; }
1400 case Help: {
1401 QAccessibleEvent event(QEvent::AccessibilityHelp, child);
1402 if (QApplication::sendEvent(widget(), &event))
1403 str = event.value();
1404 break; }
1405 default:
1406 break;
1407 }
1408 }
1409 if (str.isEmpty())
1410 str = QAccessibleWidgetEx::text(t, child);
1411 return str;
1412}
1413
1414/*! \reimp */
1415QAccessible::Role QAccessibleHeader::role(int) const
1416{
1417 return (header()->orientation() == Qt::Horizontal) ? ColumnHeader : RowHeader;
1418}
1419
1420/*! \reimp */
1421QAccessible::State QAccessibleHeader::state(int child) const
1422{
1423 State state = QAccessibleWidgetEx::state(child);
1424
1425 if (child) {
1426 int section = child - 1;
1427 if (header()->isSectionHidden(section))
1428 state |= Invisible;
1429 if (header()->resizeMode(section) != QHeaderView::Custom)
1430 state |= Sizeable;
1431 } else {
1432 if (header()->isMovable())
1433 state |= Movable;
1434 }
1435 if (!header()->isClickable())
1436 state |= Unavailable;
1437 return state;
1438}
1439#endif // QT_NO_ITEMVIEWS
1440
1441#ifndef QT_NO_TABBAR
1442/*!
1443 \class QAccessibleTabBar
1444 \brief The QAccessibleTabBar class implements the QAccessibleInterface for tab bars.
1445 \internal
1446
1447 \ingroup accessibility
1448*/
1449
1450/*!
1451 Constructs a QAccessibleTabBar object for \a w.
1452*/
1453QAccessibleTabBar::QAccessibleTabBar(QWidget *w)
1454: QAccessibleWidgetEx(w)
1455{
1456 Q_ASSERT(tabBar());
1457}
1458
1459/*! Returns the QTabBar. */
1460QTabBar *QAccessibleTabBar::tabBar() const
1461{
1462 return qobject_cast<QTabBar*>(object());
1463}
1464
1465QAbstractButton *QAccessibleTabBar::button(int child) const
1466{
1467 if (child <= tabBar()->count())
1468 return 0;
1469 QTabBarPrivate * const tabBarPrivate = tabBar()->d_func();
1470 if (child - tabBar()->count() == 1)
1471 return tabBarPrivate->leftB;
1472 if (child - tabBar()->count() == 2)
1473 return tabBarPrivate->rightB;
1474 Q_ASSERT(false);
1475 return 0;
1476}
1477
1478/*! \reimp */
1479QRect QAccessibleTabBar::rect(int child) const
1480{
1481 if (!child || !tabBar()->isVisible())
1482 return QAccessibleWidgetEx::rect(0);
1483
1484 QPoint tp = tabBar()->mapToGlobal(QPoint(0,0));
1485 QRect rec;
1486 if (child <= tabBar()->count()) {
1487 rec = tabBar()->tabRect(child - 1);
1488 } else {
1489 QWidget *widget = button(child);
1490 rec = widget ? widget->geometry() : QRect();
1491 }
1492 return QRect(tp.x() + rec.x(), tp.y() + rec.y(), rec.width(), rec.height());
1493}
1494
1495/*! \reimp */
1496int QAccessibleTabBar::childCount() const
1497{
1498 // tabs + scroll buttons
1499 return tabBar()->count() + 2;
1500}
1501
1502/*! \reimp */
1503QString QAccessibleTabBar::text(Text t, int child) const
1504{
1505 QString str;
1506
1507 if (child > tabBar()->count()) {
1508 bool left = child - tabBar()->count() == 1;
1509 switch (t) {
1510 case Name:
1511 return left ? QTabBar::tr("Scroll Left") : QTabBar::tr("Scroll Right");
1512 default:
1513 break;
1514 }
[846]1515 } else {
[2]1516 switch (t) {
1517 case Name:
[846]1518 if (child > 0)
1519 return qt_accStripAmp(tabBar()->tabText(child - 1));
1520 else if (tabBar()->currentIndex() != -1)
1521 return qt_accStripAmp(tabBar()->tabText(tabBar()->currentIndex()));
1522 break;
[2]1523 default:
1524 break;
1525 }
1526 }
1527
1528 if (str.isEmpty())
1529 str = QAccessibleWidgetEx::text(t, child);;
1530 return str;
1531}
1532
1533/*! \reimp */
1534QAccessible::Role QAccessibleTabBar::role(int child) const
1535{
1536 if (!child)
1537 return PageTabList;
1538 if (child > tabBar()->count())
1539 return PushButton;
1540 return PageTab;
1541}
1542
1543/*! \reimp */
1544QAccessible::State QAccessibleTabBar::state(int child) const
1545{
1546 State st = QAccessibleWidgetEx::state(0);
1547
1548 if (!child)
1549 return st;
1550
1551 QTabBar *tb = tabBar();
1552
1553 if (child > tb->count()) {
1554 QWidget *bt = button(child);
1555 if (!bt)
1556 return st;
1557 if (bt->isEnabled() == false)
1558 st |= Unavailable;
1559 if (bt->isVisible() == false)
1560 st |= Invisible;
1561 if (bt->focusPolicy() != Qt::NoFocus && bt->isActiveWindow())
1562 st |= Focusable;
1563 if (bt->hasFocus())
1564 st |= Focused;
1565 return st;
1566 }
1567
1568 if (!tb->isTabEnabled(child - 1))
1569 st |= Unavailable;
1570 else
1571 st |= Selectable;
1572
1573 if (!tb->currentIndex() == child - 1)
1574 st |= Selected;
1575
1576 return st;
1577}
1578
1579/*! \reimp */
1580bool QAccessibleTabBar::doAction(int action, int child, const QVariantList &)
1581{
1582 if (!child)
1583 return false;
1584
1585 if (action != QAccessible::DefaultAction && action != QAccessible::Press)
1586 return false;
1587
1588 if (child > tabBar()->count()) {
1589 QAbstractButton *bt = button(child);
1590 if (!bt->isEnabled())
1591 return false;
1592 bt->animateClick();
1593 return true;
1594 }
1595 if (!tabBar()->isTabEnabled(child - 1))
1596 return false;
1597 tabBar()->setCurrentIndex(child - 1);
1598 return true;
1599}
1600
1601/*!
1602 Selects the item with index \a child if \a on is true; otherwise
1603 unselects it. If \a extend is true and the selection mode is not
1604 \c Single and there is an existing selection, the selection is
1605 extended to include all the items from the existing selection up
1606 to and including the item with index \a child. Returns true if a
1607 selection was made or extended; otherwise returns false.
1608
1609 \sa selection() clearSelection()
1610*/
1611bool QAccessibleTabBar::setSelected(int child, bool on, bool extend)
1612{
1613 if (!child || !on || extend || child > tabBar()->count())
1614 return false;
1615
1616 if (!tabBar()->isTabEnabled(child - 1))
1617 return false;
1618 tabBar()->setCurrentIndex(child - 1);
1619 return true;
1620}
1621
1622/*!
1623 Returns a (possibly empty) list of indexes of the items selected
1624 in the list box.
1625
1626 \sa setSelected() clearSelection()
1627*/
1628QVector<int> QAccessibleTabBar::selection() const
1629{
1630 QVector<int> array;
1631 if (tabBar()->currentIndex() != -1)
1632 array +=tabBar()->currentIndex() + 1;
1633 return array;
1634}
1635
1636#endif // QT_NO_TABBAR
1637
1638#ifndef QT_NO_COMBOBOX
1639/*!
1640 \class QAccessibleComboBox
1641 \brief The QAccessibleComboBox class implements the QAccessibleInterface for editable and read-only combo boxes.
1642 \internal
1643
1644 \ingroup accessibility
1645*/
1646
1647/*!
1648 \enum QAccessibleComboBox::ComboBoxElements
1649
1650 \internal
1651
1652 \value ComboBoxSelf
1653 \value CurrentText
1654 \value OpenList
1655 \value PopupList
1656*/
1657
1658/*!
1659 Constructs a QAccessibleComboBox object for \a w.
1660*/
1661QAccessibleComboBox::QAccessibleComboBox(QWidget *w)
1662: QAccessibleWidgetEx(w, ComboBox)
1663{
1664 Q_ASSERT(comboBox());
1665}
1666
1667/*!
1668 Returns the combobox.
1669*/
1670QComboBox *QAccessibleComboBox::comboBox() const
1671{
1672 return qobject_cast<QComboBox*>(object());
1673}
1674
1675/*! \reimp */
1676QRect QAccessibleComboBox::rect(int child) const
1677{
1678 QPoint tp;
1679 QStyle::SubControl sc;
1680 QRect r;
1681 switch (child) {
1682 case CurrentText:
1683 if (comboBox()->isEditable()) {
1684 tp = comboBox()->lineEdit()->mapToGlobal(QPoint(0,0));
1685 r = comboBox()->lineEdit()->rect();
1686 sc = QStyle::SC_None;
1687 } else {
1688 tp = comboBox()->mapToGlobal(QPoint(0,0));
1689 sc = QStyle::SC_ComboBoxEditField;
1690 }
1691 break;
1692 case OpenList:
1693 tp = comboBox()->mapToGlobal(QPoint(0,0));
1694 sc = QStyle::SC_ComboBoxArrow;
1695 break;
1696 default:
1697 return QAccessibleWidgetEx::rect(child);
1698 }
1699
1700 if (sc != QStyle::SC_None) {
1701 QStyleOptionComboBox option;
1702 option.initFrom(comboBox());
1703 r = comboBox()->style()->subControlRect(QStyle::CC_ComboBox, &option, sc, comboBox());
1704 }
1705 return QRect(tp.x() + r.x(), tp.y() + r.y(), r.width(), r.height());
1706}
1707
1708/*! \reimp */
1709int QAccessibleComboBox::navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const
1710{
1711 *target = 0;
1712 if (entry > ComboBoxSelf) switch (rel) {
1713 case Child:
1714 if (entry < PopupList)
1715 return entry;
1716 if (entry == PopupList) {
1717 QAbstractItemView *view = comboBox()->view();
1718 QWidget *parent = view ? view->parentWidget() : 0;
1719 *target = QAccessible::queryAccessibleInterface(parent);
1720 return *target ? 0 : -1;
1721 }
1722 case QAccessible::Left:
1723 return entry == OpenList ? CurrentText : -1;
1724 case QAccessible::Right:
1725 return entry == CurrentText ? OpenList : -1;
1726 case QAccessible::Up:
1727 return -1;
1728 case QAccessible::Down:
1729 return -1;
1730 default:
1731 break;
1732 }
1733 return QAccessibleWidgetEx::navigate(rel, entry, target);
1734}
1735
1736/*! \reimp */
1737int QAccessibleComboBox::childCount() const
1738{
1739 return comboBox()->view() ? PopupList : OpenList;
1740}
1741
1742/*! \reimp */
1743int QAccessibleComboBox::childAt(int x, int y) const
1744{
1745 if (!comboBox()->isVisible())
1746 return -1;
1747 QPoint gp = widget()->mapToGlobal(QPoint(0, 0));
1748 if (!QRect(gp.x(), gp.y(), widget()->width(), widget()->height()).contains(x, y))
1749 return -1;
1750
1751 // a complex control
1752 for (int i = 1; i < PopupList; ++i) {
1753 if (rect(i).contains(x, y))
1754 return i;
1755 }
1756 return 0;
1757}
1758
1759/*! \reimp */
1760int QAccessibleComboBox::indexOfChild(const QAccessibleInterface *child) const
1761{
1762 QObject *viewParent = comboBox()->view() ? comboBox()->view()->parentWidget() : 0;
1763 if (child->object() == viewParent)
1764 return PopupList;
1765 return -1;
1766}
1767
1768/*! \reimp */
1769QString QAccessibleComboBox::text(Text t, int child) const
1770{
1771 QString str;
1772
1773 switch (t) {
1774 case Name:
1775 if (child == OpenList)
1776 str = QComboBox::tr("Open");
1777 else
1778 str = QAccessibleWidgetEx::text(t, 0);
1779 break;
1780#ifndef QT_NO_SHORTCUT
1781 case Accelerator:
1782 if (child == OpenList)
1783 str = (QString)QKeySequence(Qt::Key_Down);
1784 // missing break?
1785#endif
1786 case Value:
1787 if (comboBox()->isEditable())
1788 str = comboBox()->lineEdit()->text();
1789 else
1790 str = comboBox()->currentText();
1791 break;
1792 default:
1793 break;
1794 }
1795 if (str.isEmpty())
1796 str = QAccessibleWidgetEx::text(t, 0);
1797 return str;
1798}
1799
1800/*! \reimp */
1801QAccessible::Role QAccessibleComboBox::role(int child) const
1802{
1803 switch (child) {
1804 case CurrentText:
1805 if (comboBox()->isEditable())
1806 return EditableText;
1807 return StaticText;
1808 case OpenList:
1809 return PushButton;
1810 case PopupList:
1811 return List;
1812 default:
1813 return ComboBox;
1814 }
1815}
1816
1817/*! \reimp */
1818QAccessible::State QAccessibleComboBox::state(int /*child*/) const
1819{
1820 return QAccessibleWidgetEx::state(0);
1821}
1822
1823/*! \reimp */
1824bool QAccessibleComboBox::doAction(int action, int child, const QVariantList &)
1825{
1826 if (child == 2 && (action == DefaultAction || action == Press)) {
1827 if (comboBox()->view()->isVisible()) {
1828 comboBox()->hidePopup();
1829 } else {
1830 comboBox()->showPopup();
1831 }
1832 return true;
1833 }
1834 return false;
1835}
1836
1837QString QAccessibleComboBox::actionText(int action, Text t, int child) const
1838{
1839 QString text;
1840 if (child == 2 && t == Name && (action == DefaultAction || action == Press))
1841 text = comboBox()->view()->isVisible() ? QComboBox::tr("Close") : QComboBox::tr("Open");
1842 return text;
1843}
1844#endif // QT_NO_COMBOBOX
1845
1846static inline void removeInvisibleWidgetsFromList(QWidgetList *list)
1847{
1848 if (!list || list->isEmpty())
1849 return;
1850
1851 for (int i = 0; i < list->count(); ++i) {
1852 QWidget *widget = list->at(i);
1853 if (!widget->isVisible())
1854 list->removeAt(i);
1855 }
1856}
1857
1858#ifndef QT_NO_SCROLLAREA
1859// ======================= QAccessibleAbstractScrollArea =======================
1860QAccessibleAbstractScrollArea::QAccessibleAbstractScrollArea(QWidget *widget)
1861 : QAccessibleWidgetEx(widget, Client)
1862{
1863 Q_ASSERT(qobject_cast<QAbstractScrollArea *>(widget));
1864}
1865
1866QString QAccessibleAbstractScrollArea::text(Text textType, int child) const
1867{
1868 if (child == Self)
1869 return QAccessibleWidgetEx::text(textType, 0);
1870 QWidgetList children = accessibleChildren();
1871 if (child < 1 || child > children.count())
1872 return QString();
1873 QAccessibleInterface *childInterface = queryAccessibleInterface(children.at(child - 1));
1874 if (!childInterface)
1875 return QString();
1876 QString string = childInterface->text(textType, 0);
1877 delete childInterface;
1878 return string;
1879}
1880
1881void QAccessibleAbstractScrollArea::setText(Text textType, int child, const QString &text)
1882{
1883 if (text.isEmpty())
1884 return;
1885 if (child == 0) {
1886 QAccessibleWidgetEx::setText(textType, 0, text);
1887 return;
1888 }
1889 QWidgetList children = accessibleChildren();
1890 if (child < 1 || child > children.count())
1891 return;
1892 QAccessibleInterface *childInterface = queryAccessibleInterface(children.at(child - 1));
1893 if (!childInterface)
1894 return;
1895 childInterface->setText(textType, 0, text);
1896 delete childInterface;
1897}
1898
1899QAccessible::State QAccessibleAbstractScrollArea::state(int child) const
1900{
1901 if (child == Self)
1902 return QAccessibleWidgetEx::state(child);
1903 QWidgetList children = accessibleChildren();
1904 if (child < 1 || child > children.count())
1905 return QAccessibleWidgetEx::state(Self);
1906 QAccessibleInterface *childInterface = queryAccessibleInterface(children.at(child - 1));
1907 if (!childInterface)
1908 return QAccessibleWidgetEx::state(Self);
1909 QAccessible::State returnState = childInterface->state(0);
1910 delete childInterface;
1911 return returnState;
1912}
1913
1914QVariant QAccessibleAbstractScrollArea::invokeMethodEx(QAccessible::Method, int, const QVariantList &)
1915{
1916 return QVariant();
1917}
1918
1919int QAccessibleAbstractScrollArea::childCount() const
1920{
1921 return accessibleChildren().count();
1922}
1923
1924int QAccessibleAbstractScrollArea::indexOfChild(const QAccessibleInterface *child) const
1925{
1926 if (!child || !child->object())
1927 return -1;
1928 int index = accessibleChildren().indexOf(qobject_cast<QWidget *>(child->object()));
1929 if (index >= 0)
1930 return ++index;
1931 return -1;
1932}
1933
1934bool QAccessibleAbstractScrollArea::isValid() const
1935{
1936 return (QAccessibleWidgetEx::isValid() && abstractScrollArea() && abstractScrollArea()->viewport());
1937}
1938
1939int QAccessibleAbstractScrollArea::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const
1940{
1941 if (!target)
1942 return -1;
1943
1944 *target = 0;
1945
1946 QWidget *targetWidget = 0;
1947 QWidget *entryWidget = 0;
1948
1949 if (relation == Child ||
1950 relation == Left || relation == Up || relation == Right || relation == Down) {
1951 QWidgetList children = accessibleChildren();
1952 if (entry < 0 || entry > children.count())
1953 return -1;
1954
1955 if (entry == Self)
1956 entryWidget = abstractScrollArea();
1957 else
1958 entryWidget = children.at(entry - 1);
1959 AbstractScrollAreaElement entryElement = elementType(entryWidget);
1960
1961 // Not one of the most beautiful switches I've ever seen, but I believe it has
1962 // to be like this since each case need special handling.
1963 // It might be possible to make it more general, but I'll leave that as an exercise
1964 // to the reader. :-)
1965 switch (relation) {
1966 case Child:
1967 if (entry > 0)
1968 targetWidget = children.at(entry - 1);
1969 break;
1970 case Left:
1971 if (entry < 1)
1972 break;
1973 switch (entryElement) {
1974 case Viewport:
1975 if (!isLeftToRight())
1976 targetWidget = abstractScrollArea()->verticalScrollBar();
1977 break;
1978 case HorizontalContainer:
1979 if (!isLeftToRight())
1980 targetWidget = abstractScrollArea()->cornerWidget();
1981 break;
1982 case VerticalContainer:
1983 if (isLeftToRight())
1984 targetWidget = abstractScrollArea()->viewport();
1985 break;
1986 case CornerWidget:
1987 if (isLeftToRight())
1988 targetWidget = abstractScrollArea()->horizontalScrollBar();
1989 break;
1990 default:
1991 break;
1992 }
1993 break;
1994 case Right:
1995 if (entry < 1)
1996 break;
1997 switch (entryElement) {
1998 case Viewport:
1999 if (isLeftToRight())
2000 targetWidget = abstractScrollArea()->verticalScrollBar();
2001 break;
2002 case HorizontalContainer:
2003 targetWidget = abstractScrollArea()->cornerWidget();
2004 break;
2005 case VerticalContainer:
2006 if (!isLeftToRight())
2007 targetWidget = abstractScrollArea()->viewport();
2008 break;
2009 case CornerWidget:
2010 if (!isLeftToRight())
2011 targetWidget = abstractScrollArea()->horizontalScrollBar();
2012 break;
2013 default:
2014 break;
2015 }
2016 break;
2017 case Up:
2018 if (entry < 1)
2019 break;
2020 switch (entryElement) {
2021 case HorizontalContainer:
2022 targetWidget = abstractScrollArea()->viewport();
2023 break;
2024 case CornerWidget:
2025 targetWidget = abstractScrollArea()->verticalScrollBar();
2026 break;
2027 default:
2028 break;
2029 }
2030 break;
2031 case Down:
2032 if (entry < 1)
2033 break;
2034 switch (entryElement) {
2035 case Viewport:
2036 targetWidget = abstractScrollArea()->horizontalScrollBar();
2037 break;
2038 case VerticalContainer:
2039 targetWidget = abstractScrollArea()->cornerWidget();
2040 break;
2041 default:
2042 break;
2043 }
2044 break;
2045 default:
2046 break;
2047 }
2048 } else {
2049 return QAccessibleWidgetEx::navigate(relation, entry, target);
2050 }
2051
2052 if (qobject_cast<const QScrollBar *>(targetWidget))
2053 targetWidget = targetWidget->parentWidget();
2054 *target = QAccessible::queryAccessibleInterface(targetWidget);
2055 return *target ? 0: -1;
2056}
2057
2058QRect QAccessibleAbstractScrollArea::rect(int child) const
2059{
2060 if (!abstractScrollArea()->isVisible())
2061 return QRect();
2062 if (child == Self)
2063 return QAccessibleWidgetEx::rect(child);
2064 QWidgetList children = accessibleChildren();
2065 if (child < 1 || child > children.count())
2066 return QRect();
2067 const QWidget *childWidget = children.at(child - 1);
2068 if (!childWidget->isVisible())
2069 return QRect();
2070 return QRect(childWidget->mapToGlobal(QPoint(0, 0)), childWidget->size());
2071}
2072
2073int QAccessibleAbstractScrollArea::childAt(int x, int y) const
2074{
2075 if (!abstractScrollArea()->isVisible())
2076 return -1;
2077#if 0
2078 const QRect globalSelfGeometry = rect(Self);
2079 if (!globalSelfGeometry.isValid() || !globalSelfGeometry.contains(QPoint(x, y)))
2080 return -1;
2081 const QWidgetList children = accessibleChildren();
2082 for (int i = 0; i < children.count(); ++i) {
2083 const QWidget *child = children.at(i);
2084 const QRect globalChildGeometry = QRect(child->mapToGlobal(QPoint(0, 0)), child->size());
2085 if (globalChildGeometry.contains(QPoint(x, y))) {
2086 return ++i;
2087 }
2088 }
2089 return 0;
2090#else
2091 for (int i = childCount(); i >= 0; --i) {
2092 if (rect(i).contains(x, y))
2093 return i;
2094 }
2095 return -1;
2096#endif
2097}
2098
2099QAbstractScrollArea *QAccessibleAbstractScrollArea::abstractScrollArea() const
2100{
2101 return static_cast<QAbstractScrollArea *>(object());
2102}
2103
2104QWidgetList QAccessibleAbstractScrollArea::accessibleChildren() const
2105{
2106 QWidgetList children;
2107
2108 // Viewport.
2109 QWidget * viewport = abstractScrollArea()->viewport();
2110 if (viewport)
2111 children.append(viewport);
2112
2113 // Horizontal scrollBar container.
2114 QScrollBar *horizontalScrollBar = abstractScrollArea()->horizontalScrollBar();
2115 if (horizontalScrollBar && horizontalScrollBar->isVisible()) {
2116 children.append(horizontalScrollBar->parentWidget());
2117 }
2118
2119 // Vertical scrollBar container.
2120 QScrollBar *verticalScrollBar = abstractScrollArea()->verticalScrollBar();
2121 if (verticalScrollBar && verticalScrollBar->isVisible()) {
2122 children.append(verticalScrollBar->parentWidget());
2123 }
2124
2125 // CornerWidget.
2126 QWidget *cornerWidget = abstractScrollArea()->cornerWidget();
2127 if (cornerWidget && cornerWidget->isVisible())
2128 children.append(cornerWidget);
2129
2130 return children;
2131}
2132
2133QAccessibleAbstractScrollArea::AbstractScrollAreaElement
2134QAccessibleAbstractScrollArea::elementType(QWidget *widget) const
2135{
2136 if (!widget)
2137 return Undefined;
2138
2139 if (widget == abstractScrollArea())
2140 return Self;
2141 if (widget == abstractScrollArea()->viewport())
2142 return Viewport;
2143 if (widget->objectName() == QLatin1String("qt_scrollarea_hcontainer"))
2144 return HorizontalContainer;
2145 if (widget->objectName() == QLatin1String("qt_scrollarea_vcontainer"))
2146 return VerticalContainer;
2147 if (widget == abstractScrollArea()->cornerWidget())
2148 return CornerWidget;
2149
2150 return Undefined;
2151}
2152
2153bool QAccessibleAbstractScrollArea::isLeftToRight() const
2154{
2155 return abstractScrollArea()->isLeftToRight();
2156}
2157
2158// ======================= QAccessibleScrollArea ===========================
2159QAccessibleScrollArea::QAccessibleScrollArea(QWidget *widget)
2160 : QAccessibleAbstractScrollArea(widget)
2161{
2162 Q_ASSERT(qobject_cast<QScrollArea *>(widget));
2163}
2164#endif // QT_NO_SCROLLAREA
2165
2166QT_END_NAMESPACE
2167
2168#endif // QT_NO_ACCESSIBILITY
Note: See TracBrowser for help on using the repository browser.