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