Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qtableview.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtableview.h"
5
6#include <qheaderview.h>
7#include <qitemdelegate.h>
8#include <qapplication.h>
9#include <qpainter.h>
10#include <qstyle.h>
11#include <qsize.h>
12#include <qevent.h>
13#include <qbitarray.h>
14#include <qscrollbar.h>
15#if QT_CONFIG(abstractbutton)
16#include <qabstractbutton.h>
17#endif
18#include <private/qapplication_p.h>
19#include <private/qtableview_p.h>
20#include <private/qheaderview_p.h>
21#include <private/qscrollbar_p.h>
22#if QT_CONFIG(accessibility)
23#include <qaccessible.h>
24#endif
25
26#include <algorithm>
27
29
34{
35 spans.push_back(span);
36 Index::iterator it_y = index.lowerBound(-span->top());
37 if (it_y == index.end() || it_y.key() != -span->top()) {
38 //there is no spans that starts with the row in the index, so create a sublist for it.
39 SubIndex sub_index;
40 if (it_y != index.end()) {
41 //the previouslist is the list of spans that sarts _before_ the row of the span.
42 // and which may intersect this row.
43 const SubIndex previousList = it_y.value();
44 for (Span *s : previousList) {
45 //If a subspans intersect the row, we need to split it into subspans
46 if (s->bottom() >= span->top())
47 sub_index.insert(-s->left(), s);
48 }
49 }
50 it_y = index.insert(-span->top(), sub_index);
51 //we will insert span to *it_y in the later loop
52 }
53
54 //insert the span as supspan in all the lists that intesects the span
55 while(-it_y.key() <= span->bottom()) {
56 (*it_y).insert(-span->left(), span);
57 if (it_y == index.begin())
58 break;
59 --it_y;
60 }
61}
62
63
72{
73 if (old_height < span->height()) {
74 //add the span as subspan in all the lists that intersect the new covered columns
75 Index::iterator it_y = index.lowerBound(-(span->top() + old_height - 1));
76 Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list
77 while (-it_y.key() <= span->bottom()) {
78 (*it_y).insert(-span->left(), span);
79 if (it_y == index.begin())
80 break;
81 --it_y;
82 }
83 } else if (old_height > span->height()) {
84 //remove the span from all the subspans lists that intersect the columns not covered anymore
85 Index::iterator it_y = index.lowerBound(-qMax(span->bottom(), span->top())); //qMax useful if height is 0
86 Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list
87 while (-it_y.key() <= span->top() + old_height -1) {
88 if (-it_y.key() > span->bottom()) {
89 int removed = (*it_y).remove(-span->left());
90 Q_ASSERT(removed == 1);
91 Q_UNUSED(removed);
92 if (it_y->isEmpty()) {
93 it_y = index.erase(it_y);
94 }
95 }
96 if (it_y == index.begin())
97 break;
98 --it_y;
99 }
100 }
101
102 if (span->width() == 0 && span->height() == 0) {
103 spans.remove(span);
104 delete span;
105 }
106}
107
113{
114 Index::const_iterator it_y = index.lowerBound(-y);
115 if (it_y == index.end())
116 return nullptr;
117 SubIndex::const_iterator it_x = (*it_y).lowerBound(-x);
118 if (it_x == (*it_y).end())
119 return nullptr;
120 Span *span = *it_x;
121 if (span->right() >= x && span->bottom() >= y)
122 return span;
123 return nullptr;
124}
125
126
131{
133 index.clear();
134 spans.clear();
135}
136
141{
143 Index::const_iterator it_y = index.lowerBound(-y);
144 if (it_y == index.end())
145 --it_y;
146 while(-it_y.key() <= y + h) {
147 SubIndex::const_iterator it_x = (*it_y).lowerBound(-x);
148 if (it_x == (*it_y).end())
149 --it_x;
150 while(-it_x.key() <= x + w) {
151 Span *s = *it_x;
152 if (s->bottom() >= y && s->right() >= x)
153 list << s;
154 if (it_x == (*it_y).begin())
155 break;
156 --it_x;
157 }
158 if (it_y == index.begin())
159 break;
160 --it_y;
161 }
162 return list;
163}
164
165#undef DEBUG_SPAN_UPDATE
166
167#ifdef DEBUG_SPAN_UPDATE
169{
170 str << '(' << span.top() << ',' << span.left() << ',' << span.bottom() << ',' << span.right() << ')';
171 return str;
172}
173#endif
174
179{
180#ifdef DEBUG_SPAN_UPDATE
181 qDebug() << start << end << Qt::endl << index;
182#endif
183 if (spans.empty())
184 return;
185
186 int delta = end - start + 1;
187#ifdef DEBUG_SPAN_UPDATE
188 qDebug("Before");
189#endif
190 for (Span *span : spans) {
191#ifdef DEBUG_SPAN_UPDATE
192 qDebug() << span << *span;
193#endif
194 if (span->m_bottom < start)
195 continue;
196 if (span->m_top >= start)
197 span->m_top += delta;
198 span->m_bottom += delta;
199 }
200
201#ifdef DEBUG_SPAN_UPDATE
202 qDebug("After");
204 qDebug() << span << *span;
205#endif
206
207 for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
208 int y = -it_y.key();
209 if (y < start) {
210 ++it_y;
211 continue;
212 }
213
214 index.insert(-y - delta, it_y.value());
215 it_y = index.erase(it_y);
216 }
217#ifdef DEBUG_SPAN_UPDATE
218 qDebug() << index;
219#endif
220}
221
226{
227#ifdef DEBUG_SPAN_UPDATE
228 qDebug() << start << end << Qt::endl << index;
229#endif
230 if (spans.empty())
231 return;
232
233 int delta = end - start + 1;
234#ifdef DEBUG_SPAN_UPDATE
235 qDebug("Before");
236#endif
237 for (Span *span : spans) {
238#ifdef DEBUG_SPAN_UPDATE
239 qDebug() << span << *span;
240#endif
241 if (span->m_right < start)
242 continue;
243 if (span->m_left >= start)
244 span->m_left += delta;
245 span->m_right += delta;
246 }
247
248#ifdef DEBUG_SPAN_UPDATE
249 qDebug("After");
251 qDebug() << span << *span;
252#endif
253
254 for (Index::iterator it_y = index.begin(); it_y != index.end(); ++it_y) {
255 SubIndex &subindex = it_y.value();
256 for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ) {
257 int x = -it.key();
258 if (x < start) {
259 ++it;
260 continue;
261 }
262 subindex.insert(-x - delta, it.value());
263 it = subindex.erase(it);
264 }
265 }
266#ifdef DEBUG_SPAN_UPDATE
267 qDebug() << index;
268#endif
269}
270
276bool QSpanCollection::cleanSpanSubIndex(QSpanCollection::SubIndex &subindex, int y, bool update)
277{
278 if (subindex.isEmpty())
279 return true;
280
281 bool should_be_deleted = true;
282 SubIndex::iterator it = subindex.end();
283 do {
284 --it;
285 int x = -it.key();
286 Span *span = it.value();
287 if (span->will_be_deleted) {
288 it = subindex.erase(it);
289 continue;
290 }
291 if (update && span->m_left != x) {
292 subindex.insert(-span->m_left, span);
293 it = subindex.erase(it);
294 }
295 if (should_be_deleted && span->m_top == y)
296 should_be_deleted = false;
297 } while (it != subindex.begin());
298
299 return should_be_deleted;
300}
301
306{
307#ifdef DEBUG_SPAN_UPDATE
308 qDebug() << start << end << Qt::endl << index;
309#endif
310 if (spans.empty())
311 return;
312
313 SpanList spansToBeDeleted;
314 int delta = end - start + 1;
315#ifdef DEBUG_SPAN_UPDATE
316 qDebug("Before");
317#endif
318 for (SpanList::iterator it = spans.begin(); it != spans.end(); ) {
319 Span *span = *it;
320#ifdef DEBUG_SPAN_UPDATE
321 qDebug() << span << *span;
322#endif
323 if (span->m_bottom < start) {
324 ++it;
325 continue;
326 }
327 if (span->m_top < start) {
328 if (span->m_bottom <= end)
329 span->m_bottom = start - 1;
330 else
331 span->m_bottom -= delta;
332 } else {
333 if (span->m_bottom > end) {
334 if (span->m_top <= end)
335 span->m_top = start;
336 else
337 span->m_top -= delta;
338 span->m_bottom -= delta;
339 } else {
340 span->will_be_deleted = true;
341 }
342 }
343 if (span->m_top == span->m_bottom && span->m_left == span->m_right)
344 span->will_be_deleted = true;
345 if (span->will_be_deleted) {
346 spansToBeDeleted.push_back(span);
347 it = spans.erase(it);
348 } else {
349 ++it;
350 }
351 }
352
353#ifdef DEBUG_SPAN_UPDATE
354 qDebug("After");
356 qDebug() << span << *span;
357#endif
358 if (spans.empty()) {
359 qDeleteAll(spansToBeDeleted);
360 index.clear();
361 return;
362 }
363
364 Index::iterator it_y = index.end();
365 do {
366 --it_y;
367 int y = -it_y.key();
368 SubIndex &subindex = it_y.value();
369 if (y < start) {
370 if (cleanSpanSubIndex(subindex, y))
371 it_y = index.erase(it_y);
372 } else if (y >= start && y <= end) {
373 bool span_at_start = false;
374 SubIndex spansToBeMoved;
375 for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ++it) {
376 Span *span = it.value();
377 if (span->will_be_deleted)
378 continue;
379 if (!span_at_start && span->m_top == start)
380 span_at_start = true;
381 spansToBeMoved.insert(it.key(), span);
382 }
383
384 if (y == start && span_at_start)
385 subindex.clear();
386 else
387 it_y = index.erase(it_y);
388
389 if (span_at_start) {
390 Index::iterator it_start;
391 if (y == start)
392 it_start = it_y;
393 else {
394 it_start = index.find(-start);
395 if (it_start == index.end())
396 it_start = index.insert(-start, SubIndex());
397 }
398 SubIndex &start_subindex = it_start.value();
399 for (SubIndex::iterator it = spansToBeMoved.begin(); it != spansToBeMoved.end(); ++it)
400 start_subindex.insert(it.key(), it.value());
401 }
402 } else {
403 if (y == end + 1) {
404 Index::iterator it_top = index.find(-y + delta);
405 if (it_top == index.end())
406 it_top = index.insert(-y + delta, SubIndex());
407 for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ) {
408 Span *span = it.value();
409 if (!span->will_be_deleted)
410 it_top.value().insert(it.key(), span);
411 ++it;
412 }
413 } else {
414 index.insert(-y + delta, subindex);
415 }
416 it_y = index.erase(it_y);
417 }
418 } while (it_y != index.begin());
419
420#ifdef DEBUG_SPAN_UPDATE
421 qDebug() << index;
422 qDebug("Deleted");
423 foreach (QSpanCollection::Span *span, spansToBeDeleted)
424 qDebug() << span << *span;
425#endif
426 qDeleteAll(spansToBeDeleted);
427}
428
433{
434#ifdef DEBUG_SPAN_UPDATE
435 qDebug() << start << end << Qt::endl << index;
436#endif
437 if (spans.empty())
438 return;
439
440 SpanList toBeDeleted;
441 int delta = end - start + 1;
442#ifdef DEBUG_SPAN_UPDATE
443 qDebug("Before");
444#endif
445 for (SpanList::iterator it = spans.begin(); it != spans.end(); ) {
446 Span *span = *it;
447#ifdef DEBUG_SPAN_UPDATE
448 qDebug() << span << *span;
449#endif
450 if (span->m_right < start) {
451 ++it;
452 continue;
453 }
454 if (span->m_left < start) {
455 if (span->m_right <= end)
456 span->m_right = start - 1;
457 else
458 span->m_right -= delta;
459 } else {
460 if (span->m_right > end) {
461 if (span->m_left <= end)
462 span->m_left = start;
463 else
464 span->m_left -= delta;
465 span->m_right -= delta;
466 } else {
467 span->will_be_deleted = true;
468 }
469 }
470 if (span->m_top == span->m_bottom && span->m_left == span->m_right)
471 span->will_be_deleted = true;
472 if (span->will_be_deleted) {
473 toBeDeleted.push_back(span);
474 it = spans.erase(it);
475 } else {
476 ++it;
477 }
478 }
479
480#ifdef DEBUG_SPAN_UPDATE
481 qDebug("After");
483 qDebug() << span << *span;
484#endif
485 if (spans.empty()) {
486 qDeleteAll(toBeDeleted);
487 index.clear();
488 return;
489 }
490
491 for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
492 int y = -it_y.key();
493 if (cleanSpanSubIndex(it_y.value(), y, true))
494 it_y = index.erase(it_y);
495 else
496 ++it_y;
497 }
498
499#ifdef DEBUG_SPAN_UPDATE
500 qDebug() << index;
501 qDebug("Deleted");
502 foreach (QSpanCollection::Span *span, toBeDeleted)
503 qDebug() << span << *span;
504#endif
505 qDeleteAll(toBeDeleted);
506}
507
508#ifdef QT_BUILD_INTERNAL
513bool QSpanCollection::checkConsistency() const
514{
515 for (Index::const_iterator it_y = index.begin(); it_y != index.end(); ++it_y) {
516 int y = -it_y.key();
517 const SubIndex &subIndex = it_y.value();
518 for (SubIndex::const_iterator it = subIndex.begin(); it != subIndex.end(); ++it) {
519 int x = -it.key();
520 Span *span = it.value();
521 const bool contains = std::find(spans.begin(), spans.end(), span) != spans.end();
522 if (!contains || span->left() != x || y < span->top() || y > span->bottom())
523 return false;
524 }
525 }
526
527 for (const Span *span : spans) {
528 if (span->width() < 1 || span->height() < 1
529 || (span->width() == 1 && span->height() == 1))
530 return false;
531 for (int y = span->top(); y <= span->bottom(); ++y) {
532 Index::const_iterator it_y = index.find(-y);
533 if (it_y == index.end()) {
534 if (y == span->top())
535 return false;
536 else
537 continue;
538 }
539 const SubIndex &subIndex = it_y.value();
540 SubIndex::const_iterator it = subIndex.find(-span->left());
541 if (it == subIndex.end() || it.value() != span)
542 return false;
543 }
544 }
545 return true;
546}
547#endif
548
549#if QT_CONFIG(abstractbutton)
550class QTableCornerButton : public QAbstractButton
551{
553public:
554 QTableCornerButton(QWidget *parent) : QAbstractButton(parent) {}
555 void paintEvent(QPaintEvent*) override {
557 opt.initFrom(this);
558 QStyle::State state = QStyle::State_None;
559 if (isEnabled())
561 if (isActiveWindow())
563 if (isDown())
565 opt.state = state;
566 opt.rect = rect();
568 QPainter painter(this);
570 }
571};
572#endif
573
575{
576 Q_Q(QTableView);
577
579
580 QHeaderView *vertical = new QHeaderView(Qt::Vertical, q);
581 vertical->setSectionsClickable(true);
582 vertical->setHighlightSections(true);
583 q->setVerticalHeader(vertical);
584
585 QHeaderView *horizontal = new QHeaderView(Qt::Horizontal, q);
586 horizontal->setSectionsClickable(true);
587 horizontal->setHighlightSections(true);
588 q->setHorizontalHeader(horizontal);
589
590 tabKeyNavigation = true;
591
592#if QT_CONFIG(abstractbutton)
593 cornerWidget = new QTableCornerButton(q);
594 cornerWidget->setFocusPolicy(Qt::NoFocus);
595 QObject::connect(cornerWidget, SIGNAL(clicked()), q, SLOT(selectAll()));
596#endif
597}
598
604{
605 Q_ASSERT(range && range->isValid());
606
607 int top = range->top();
608 int left = range->left();
609 int bottom = range->bottom();
610 int right = range->right();
611
613 --bottom;
615 --right;
616
617 if (top > bottom || left > right) { // everything is hidden
619 return;
620 }
621
623 ++top;
625 ++left;
626
627 if (top > bottom || left > right) { // everything is hidden
629 return;
630 }
631
632 QModelIndex bottomRight = model->index(bottom, right, range->parent());
633 QModelIndex topLeft = model->index(top, left, range->parent());
634 *range = QItemSelectionRange(topLeft, bottomRight);
635}
636
637QRect QTableViewPrivate::intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const
638{
639 Q_Q(const QTableView);
640
641 using minMaxPair = std::pair<int, int>;
642 const auto calcMinMax = [q](QHeaderView *hdr, int startIdx, int endIdx, minMaxPair bounds) -> minMaxPair
643 {
644 minMaxPair ret(std::numeric_limits<int>::max(), std::numeric_limits<int>::min());
645 if (hdr->sectionsMoved()) {
646 for (int i = startIdx; i <= endIdx; ++i) {
647 const int start = hdr->sectionViewportPosition(i);
648 const int end = start + hdr->sectionSize(i);
649 ret.first = std::min(start, ret.first);
650 ret.second = std::max(end, ret.second);
651 if (ret.first <= bounds.first && ret.second >= bounds.second)
652 break;
653 }
654 } else {
655 if (q->isRightToLeft() && q->horizontalHeader() == hdr)
656 std::swap(startIdx, endIdx);
657 ret.first = hdr->sectionViewportPosition(startIdx);
658 ret.second = hdr->sectionViewportPosition(endIdx) +
659 hdr->sectionSize(endIdx);
660 }
661 return ret;
662 };
663
664 const auto yVals = calcMinMax(verticalHeader, topLeft.row(), bottomRight.row(),
665 minMaxPair(rect.top(), rect.bottom()));
666 if (yVals.first == yVals.second) // all affected rows are hidden
667 return QRect();
668
669 // short circuit: check if no row is inside rect
670 const QRect colRect(QPoint(rect.left(), yVals.first),
671 QPoint(rect.right(), yVals.second));
672 const QRect intersected = rect.intersected(colRect);
673 if (intersected.isNull())
674 return QRect();
675
676 const auto xVals = calcMinMax(horizontalHeader, topLeft.column(), bottomRight.column(),
677 minMaxPair(rect.left(), rect.right()));
678 const QRect updateRect(QPoint(xVals.first, yVals.first),
679 QPoint(xVals.second, yVals.second));
680 return rect.intersected(updateRect);
681}
682
687void QTableViewPrivate::setSpan(int row, int column, int rowSpan, int columnSpan)
688{
689 if (Q_UNLIKELY(row < 0 || column < 0 || rowSpan <= 0 || columnSpan <= 0)) {
690 qWarning("QTableView::setSpan: invalid span given: (%d, %d, %d, %d)",
692 return;
693 }
695 if (sp) {
696 if (sp->top() != row || sp->left() != column) {
697 qWarning("QTableView::setSpan: span cannot overlap");
698 return;
699 }
700 if (rowSpan == 1 && columnSpan == 1) {
701 rowSpan = columnSpan = 0;
702 }
703 const int old_height = sp->height();
704 sp->m_bottom = row + rowSpan - 1;
705 sp->m_right = column + columnSpan - 1;
706 spans.updateSpan(sp, old_height);
707 return;
708 } else if (Q_UNLIKELY(rowSpan == 1 && columnSpan == 1)) {
709 qWarning("QTableView::setSpan: single cell span won't be added");
710 return;
711 }
714}
715
721{
723 if (sp)
724 return *sp;
725
726 return QSpanCollection::Span(row, column, 1, 1);
727}
728
734{
735 int visual = header->visualIndex(logical);
736 for (int i = 1; i < span; ) {
737 if (++visual >= header->count())
738 break;
739 logical = header->logicalIndex(visual);
740 ++i;
741 }
742 return logical;
743}
744
751{
752 int endLogical = sectionSpanEndLogical(header, logical, span);
753 return header->sectionPosition(endLogical)
754 - header->sectionPosition(logical)
755 + header->sectionSize(endLogical);
756}
757
764bool QTableViewPrivate::spanContainsSection(const QHeaderView *header, int logical, int spanLogical, int span) const
765{
766 if (logical == spanLogical)
767 return true; // it's the start of the span
768 int visual = header->visualIndex(spanLogical);
769 for (int i = 1; i < span; ) {
770 if (++visual >= header->count())
771 break;
772 spanLogical = header->logicalIndex(visual);
773 if (logical == spanLogical)
774 return true;
775 ++i;
776 }
777 return false;
778}
779
786 SearchDirection searchDirection) const
787{
788 const int lc = logicalColumn(column);
789 int visualRow = rowToStart;
790 const auto isCellActive = [this](int vr, int lc)
791 {
792 const int lr = logicalRow(vr);
793 return !isRowHidden(lr) && isCellEnabled(lr, lc);
794 };
795 switch (searchDirection) {
797 if (visualRow < limit) {
798 while (!isCellActive(visualRow, lc)) {
799 if (++visualRow == limit)
800 return rowToStart;
801 }
802 }
803 break;
805 while (visualRow > limit && !isCellActive(visualRow, lc))
806 --visualRow;
807 break;
808 }
809 return visualRow;
810}
811
818 SearchDirection searchDirection) const
819{
820 const int lr = logicalRow(row);
821 int visualColumn = columnToStart;
822 const auto isCellActive = [this](int lr, int vc)
823 {
824 const int lc = logicalColumn(vc);
825 return !isColumnHidden(lc) && isCellEnabled(lr, lc);
826 };
827 switch (searchDirection) {
829 while (visualColumn < limit && !isCellActive(lr, visualColumn))
830 ++visualColumn;
831 break;
833 while (visualColumn > limit && !isCellActive(lr, visualColumn))
834 --visualColumn;
835 break;
836 }
837 return visualColumn;
838}
839
845{
846 Q_Q(const QTableView);
847 // vertical
848 int row = span.top();
850 int rowh = rowSpanHeight(row, span.height());
851 // horizontal
852 int column = span.left();
853 int colw = columnSpanWidth(column, span.width());
854 if (q->isRightToLeft())
855 column = span.right();
857
858 const int i = showGrid ? 1 : 0;
859 if (q->isRightToLeft())
860 return QRect(colp + i, rowp, colw - i, rowh - i);
861 return QRect(colp, rowp, colw - i, rowh - i);
862}
863
871 const QStyleOptionViewItem &option, QBitArray *drawn,
872 int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn)
873{
874 Q_Q(const QTableView);
875 bool alternateBase = false;
876 QRegion region = viewport->rect();
877
879 bool sectionMoved = verticalHeader->sectionsMoved() || horizontalHeader->sectionsMoved();
880
881 if (!sectionMoved) {
882 visibleSpans = spans.spansInRect(logicalColumn(firstVisualColumn), logicalRow(firstVisualRow),
883 lastVisualColumn - firstVisualColumn + 1, lastVisualRow - firstVisualRow + 1);
884 } else {
885 // Any cell outside the viewport, on the top or left, can still end up visible inside the
886 // viewport if is has a span. Calculating if a spanned cell overlaps with the viewport is
887 // "easy" enough when the columns (or rows) in the view are aligned with the columns
888 // in the model; In that case you know that if a column is outside the viewport on the
889 // right, it cannot affect the drawing of the cells inside the viewport, even with a span.
890 // And under that assumption, the spansInRect() function can be used (which is optimized
891 // to only iterate the spans that are close to the viewport).
892 // But when the view has rearranged the columns (or rows), this is no longer true. In that
893 // case, even if a column, according to the model, is outside the viewport on the right, it
894 // can still overlap with the viewport. This can happen if it was moved to the left of the
895 // viewport and one of its cells has a span. In that case we need to take the theoretically
896 // slower route and iterate through all the spans, and check if any of them overlaps with
897 // the viewport.
898 const auto spanList = spans.spans;
899 for (QSpanCollection::Span *span : spanList) {
900 const int spanVisualLeft = visualColumn(span->left());
901 const int spanVisualTop = visualRow(span->top());
902 const int spanVisualRight = spanVisualLeft + span->width() - 1;
903 const int spanVisualBottom = spanVisualTop + span->height() - 1;
904 if ((spanVisualLeft <= lastVisualColumn && spanVisualRight >= firstVisualColumn)
905 && (spanVisualTop <= lastVisualRow && spanVisualBottom >= firstVisualRow))
906 visibleSpans.insert(span);
907 }
908 }
909
910 for (QSpanCollection::Span *span : std::as_const(visibleSpans)) {
911 int row = span->top();
912 int col = span->left();
914 if (!index.isValid())
915 continue;
917 rect.translate(scrollDelayOffset);
918 if (!area.intersects(rect))
919 continue;
920 QStyleOptionViewItem opt = option;
921 opt.rect = rect;
922 alternateBase = alternatingColors && (span->top() & 1);
923 opt.features.setFlag(QStyleOptionViewItem::Alternate, alternateBase);
925 if (showGrid) {
926 // adjust the clip rect to be able to paint the top & left grid lines
927 // if the headers are not visible, see paintEvent()
929 rect.setTop(rect.top() + 1);
930 if (verticalHeader->visualIndex(row) == 0) {
931 if (q->isLeftToRight())
932 rect.setLeft(rect.left() + 1);
933 else
934 rect.setRight(rect.right() - 1);
935 }
936 }
937 region -= rect;
938 for (int r = span->top(); r <= span->bottom(); ++r) {
939 const int vr = visualRow(r);
940 if (vr < firstVisualRow || vr > lastVisualRow)
941 continue;
942 for (int c = span->left(); c <= span->right(); ++c) {
943 const int vc = visualColumn(c);
944 if (vc < firstVisualColumn || vc > lastVisualColumn)
945 continue;
946 drawn->setBit((vr - firstVisualRow) * (lastVisualColumn - firstVisualColumn + 1)
947 + vc - firstVisualColumn);
948 }
949 }
950
951 }
952 painter->setClipRegion(region);
953}
954
960{
963}
964
970{
973}
974
980{
983}
984
990{
993}
994
1000{
1001 model->sort(column, order);
1002}
1003
1008void QTableViewPrivate::drawCell(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index)
1009{
1010 Q_Q(QTableView);
1011 QStyleOptionViewItem opt = option;
1012
1015 if (index == hover)
1017 if (option.state & QStyle::State_Enabled) {
1019 if ((model->flags(index) & Qt::ItemIsEnabled) == 0) {
1020 opt.state &= ~QStyle::State_Enabled;
1021 cg = QPalette::Disabled;
1022 } else {
1023 cg = QPalette::Normal;
1024 }
1026 }
1027
1028 if (index == q->currentIndex()) {
1029 const bool focus = (q->hasFocus() || viewport->hasFocus()) && q->currentIndex().isValid();
1030 if (focus)
1032 }
1033
1034 q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, q);
1035
1036 q->itemDelegateForIndex(index)->paint(painter, opt, index);
1037}
1038
1043int QTableViewPrivate::widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option) const
1044{
1045 Q_Q(const QTableView);
1046 const int oldHint = hint;
1048 if (editor && persistent.contains(editor)) {
1049 hint = qMax(hint, editor->sizeHint().width());
1050 int min = editor->minimumSize().width();
1051 int max = editor->maximumSize().width();
1052 hint = qBound(min, hint, max);
1053 }
1054 hint = qMax(hint, q->itemDelegateForIndex(index)->sizeHint(option, index).width());
1055
1056 if (hasSpans()) {
1057 auto span = spans.spanAt(index.column(), index.row());
1058 if (span && span->m_left == index.column() && span->m_top == index.row()) {
1059 // spans are screwed up when sections are moved
1060 const auto left = logicalColumn(span->m_left);
1061 for (int i = 1; i <= span->width(); ++i)
1062 hint -= q->columnWidth(visualColumn(left + i));
1063 }
1064 hint = std::max(hint, oldHint);
1065 }
1066 return hint;
1067}
1068
1073int QTableViewPrivate::heightHintForIndex(const QModelIndex &index, int hint, QStyleOptionViewItem &option) const
1074{
1075 Q_Q(const QTableView);
1077 if (editor && persistent.contains(editor)) {
1079 int min = editor->minimumSize().height();
1080 int max = editor->maximumSize().height();
1081 hint = qBound(min, hint, max);
1082 }
1083
1084 if (wrapItemText) {// for wrapping boundaries
1085 option.rect.setY(q->rowViewportPosition(index.row()));
1086 int height = q->rowHeight(index.row());
1087 // if the option.height == 0 then q->itemDelegateForIndex(index)->sizeHint(option, index) will be wrong.
1088 // The option.height == 0 is used to conclude that the text is not wrapped, and hence it will
1089 // (exactly like widthHintForIndex) return a QSize with a long width (that we don't use) -
1090 // and the height of the text if it was/is on one line.
1091 // What we want is a height hint for the current width (and we know that this section is not hidden)
1092 // Therefore we catch this special situation with:
1093 if (height == 0)
1094 height = 1;
1095 option.rect.setHeight(height);
1096 option.rect.setX(q->columnViewportPosition(index.column()));
1097 option.rect.setWidth(q->columnWidth(index.column()));
1098 if (hasSpans()) {
1099 auto span = spans.spanAt(index.column(), index.row());
1100 if (span && span->m_left == index.column() && span->m_top == index.row())
1101 option.rect.setWidth(std::max(option.rect.width(), visualSpanRect(*span).width()));
1102 }
1103 // 1px less space when grid is shown (see drawCell)
1104 if (showGrid)
1105 option.rect.setWidth(option.rect.width() - 1);
1106 }
1107 hint = qMax(hint, q->itemDelegateForIndex(index)->sizeHint(option, index).height());
1108 return hint;
1109}
1110
1111
1202{
1203 Q_D(QTableView);
1204 d->init();
1205}
1206
1212{
1213 Q_D(QTableView);
1214 d->init();
1215}
1216
1221{
1222}
1223
1228{
1229 Q_D(const QTableView);
1230 QSize result( (d->verticalHeader->isHidden() ? 0 : d->verticalHeader->width()) + d->horizontalHeader->length(),
1231 (d->horizontalHeader->isHidden() ? 0 : d->horizontalHeader->height()) + d->verticalHeader->length());
1232 return result;
1233}
1234
1239{
1240 Q_D(QTableView);
1241 if (model == d->model)
1242 return;
1243 //let's disconnect from the old model
1244 if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
1245 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1246 this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
1247 disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1248 this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
1249 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1250 this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
1251 disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1252 this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
1253 }
1254 if (d->selectionModel) { // support row editing
1255 disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
1256 d->model, SLOT(submit()));
1257 }
1258 if (model) { //and connect to the new one
1260 this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
1261 connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1262 this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
1263 connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1264 this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
1265 connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1266 this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
1267 }
1268 d->verticalHeader->setModel(model);
1269 d->horizontalHeader->setModel(model);
1271}
1272
1277{
1278 Q_D(QTableView);
1279 if (index == d->root) {
1280 viewport()->update();
1281 return;
1282 }
1283 d->verticalHeader->setRootIndex(index);
1284 d->horizontalHeader->setRootIndex(index);
1286}
1287
1292{
1293 Q_D(QTableView);
1295 if (!d->verticalHeader->updatesEnabled())
1296 d->verticalHeader->setUpdatesEnabled(true);
1297}
1298
1303{
1304 Q_D(QTableView);
1306 if (d->selectionModel) {
1307 // support row editing
1308 disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
1309 d->model, SLOT(submit()));
1310 }
1311
1312 d->verticalHeader->setSelectionModel(selectionModel);
1313 d->horizontalHeader->setSelectionModel(selectionModel);
1315
1316 if (d->selectionModel) {
1317 // support row editing
1318 connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
1319 d->model, SLOT(submit()));
1320 }
1321}
1322
1329{
1330 Q_D(const QTableView);
1331 return d->horizontalHeader;
1332}
1333
1340{
1341 Q_D(const QTableView);
1342 return d->verticalHeader;
1343}
1344
1351{
1352 Q_D(QTableView);
1353
1354 if (!header || header == d->horizontalHeader)
1355 return;
1356 if (d->horizontalHeader && d->horizontalHeader->parent() == this)
1357 delete d->horizontalHeader;
1358 d->horizontalHeader = header;
1359 d->horizontalHeader->setParent(this);
1360 d->horizontalHeader->setFirstSectionMovable(true);
1361 if (!d->horizontalHeader->model()) {
1362 d->horizontalHeader->setModel(d->model);
1363 if (d->selectionModel)
1364 d->horizontalHeader->setSelectionModel(d->selectionModel);
1365 }
1366
1367 connect(d->horizontalHeader,SIGNAL(sectionResized(int,int,int)),
1368 this, SLOT(columnResized(int,int,int)));
1369 connect(d->horizontalHeader, SIGNAL(sectionMoved(int,int,int)),
1370 this, SLOT(columnMoved(int,int,int)));
1371 connect(d->horizontalHeader, SIGNAL(sectionCountChanged(int,int)),
1372 this, SLOT(columnCountChanged(int,int)));
1373 connect(d->horizontalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectColumn(int)));
1374 connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectColumn(int)));
1375 connect(d->horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
1376 this, SLOT(resizeColumnToContents(int)));
1377 connect(d->horizontalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
1378
1379 //update the sorting enabled states on the new header
1380 setSortingEnabled(d->sortingEnabled);
1381}
1382
1389{
1390 Q_D(QTableView);
1391
1392 if (!header || header == d->verticalHeader)
1393 return;
1394 if (d->verticalHeader && d->verticalHeader->parent() == this)
1395 delete d->verticalHeader;
1396 d->verticalHeader = header;
1397 d->verticalHeader->setParent(this);
1398 d->verticalHeader->setFirstSectionMovable(true);
1399 if (!d->verticalHeader->model()) {
1400 d->verticalHeader->setModel(d->model);
1401 if (d->selectionModel)
1402 d->verticalHeader->setSelectionModel(d->selectionModel);
1403 }
1404
1405 connect(d->verticalHeader, SIGNAL(sectionResized(int,int,int)),
1406 this, SLOT(rowResized(int,int,int)));
1407 connect(d->verticalHeader, SIGNAL(sectionMoved(int,int,int)),
1408 this, SLOT(rowMoved(int,int,int)));
1409 connect(d->verticalHeader, SIGNAL(sectionCountChanged(int,int)),
1410 this, SLOT(rowCountChanged(int,int)));
1411 connect(d->verticalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectRow(int)));
1412 connect(d->verticalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectRow(int)));
1413 connect(d->verticalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
1414 this, SLOT(resizeRowToContents(int)));
1415 connect(d->verticalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
1416}
1417
1424{
1425 Q_D(QTableView);
1426
1427 d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
1428
1429 dx = isRightToLeft() ? -dx : dx;
1430 if (dx) {
1431 int oldOffset = d->horizontalHeader->offset();
1432 d->horizontalHeader->d_func()->setScrollOffset(horizontalScrollBar(), horizontalScrollMode());
1434 int newOffset = d->horizontalHeader->offset();
1435 dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset;
1436 }
1437 }
1438 if (dy) {
1439 int oldOffset = d->verticalHeader->offset();
1440 d->verticalHeader->d_func()->setScrollOffset(verticalScrollBar(), verticalScrollMode());
1442 int newOffset = d->verticalHeader->offset();
1443 dy = oldOffset - newOffset;
1444 }
1445 }
1446 d->scrollContentsBy(dx, dy);
1447
1448 if (d->showGrid) {
1449 //we need to update the first line of the previous top item in the view
1450 //because it has the grid drawn if the header is invisible.
1451 //It is strictly related to what's done at then end of the paintEvent
1452 if (dy > 0 && d->horizontalHeader->isHidden()) {
1453 d->viewport->update(0, dy, d->viewport->width(), dy);
1454 }
1455 if (dx > 0 && d->verticalHeader->isHidden()) {
1456 d->viewport->update(dx, 0, dx, d->viewport->height());
1457 }
1458 }
1459}
1460
1464void QTableView::initViewItemOption(QStyleOptionViewItem *option) const
1465{
1467 option->showDecorationSelected = true;
1468}
1469
1474{
1475 Q_D(QTableView);
1476 // setup temp variables for the painting
1477 QStyleOptionViewItem option;
1479 const QPoint offset = d->scrollDelayOffset;
1480 const bool showGrid = d->showGrid;
1481 const int gridSize = showGrid ? 1 : 0;
1482 const int gridHint = style()->styleHint(QStyle::SH_Table_GridLineColor, &option, this);
1483 const QColor gridColor = QColor::fromRgba(static_cast<QRgb>(gridHint));
1484 const QPen gridPen = QPen(gridColor, 1, d->gridStyle);
1485 const QHeaderView *verticalHeader = d->verticalHeader;
1486 const QHeaderView *horizontalHeader = d->horizontalHeader;
1487 const bool alternate = d->alternatingColors;
1488 const bool rightToLeft = isRightToLeft();
1489
1490 QPainter painter(d->viewport);
1491
1492 // if there's nothing to do, clear the area and return
1493 if (horizontalHeader->count() == 0 || verticalHeader->count() == 0 || !d->itemDelegate)
1494 return;
1495
1496 const int x = horizontalHeader->length() - horizontalHeader->offset() - (rightToLeft ? 0 : 1);
1497 const int y = verticalHeader->length() - verticalHeader->offset() - 1;
1498
1499 //firstVisualRow is the visual index of the first visible row. lastVisualRow is the visual index of the last visible Row.
1500 //same goes for ...VisualColumn
1501 int firstVisualRow = qMax(verticalHeader->visualIndexAt(0),0);
1502 int lastVisualRow = verticalHeader->visualIndexAt(verticalHeader->height());
1503 if (lastVisualRow == -1)
1504 lastVisualRow = d->model->rowCount(d->root) - 1;
1505
1506 int firstVisualColumn = horizontalHeader->visualIndexAt(0);
1507 int lastVisualColumn = horizontalHeader->visualIndexAt(horizontalHeader->width());
1508 if (rightToLeft)
1509 qSwap(firstVisualColumn, lastVisualColumn);
1510 if (firstVisualColumn == -1)
1511 firstVisualColumn = 0;
1512 if (lastVisualColumn == -1)
1513 lastVisualColumn = horizontalHeader->count() - 1;
1514
1515 QBitArray drawn((lastVisualRow - firstVisualRow + 1) * (lastVisualColumn - firstVisualColumn + 1));
1516
1517 const QRegion region = event->region().translated(offset);
1518
1519 if (d->hasSpans()) {
1520 d->drawAndClipSpans(region, &painter, option, &drawn,
1521 firstVisualRow, lastVisualRow, firstVisualColumn, lastVisualColumn);
1522 }
1523
1524 for (QRect dirtyArea : region) {
1525 dirtyArea.setBottom(qMin(dirtyArea.bottom(), int(y)));
1526 if (rightToLeft) {
1527 dirtyArea.setLeft(qMax(dirtyArea.left(), d->viewport->width() - int(x)));
1528 } else {
1529 dirtyArea.setRight(qMin(dirtyArea.right(), int(x)));
1530 }
1531 // dirtyArea may be invalid when the horizontal header is not stretched
1532 if (!dirtyArea.isValid())
1533 continue;
1534
1535 // get the horizontal start and end visual sections
1536 int left = horizontalHeader->visualIndexAt(dirtyArea.left());
1537 int right = horizontalHeader->visualIndexAt(dirtyArea.right());
1538 if (rightToLeft)
1539 qSwap(left, right);
1540 if (left == -1) left = 0;
1541 if (right == -1) right = horizontalHeader->count() - 1;
1542
1543 // get the vertical start and end visual sections and if alternate color
1544 int bottom = verticalHeader->visualIndexAt(dirtyArea.bottom());
1545 if (bottom == -1) bottom = verticalHeader->count() - 1;
1546 int top = 0;
1547 bool alternateBase = false;
1548 if (alternate && verticalHeader->sectionsHidden()) {
1549 const int verticalOffset = verticalHeader->offset();
1551 for (int y = 0;
1553 ++top) {
1555 if (alternate && !verticalHeader->isSectionHidden(row))
1556 alternateBase = !alternateBase;
1557 }
1558 } else {
1559 top = verticalHeader->visualIndexAt(dirtyArea.top());
1560 alternateBase = (top & 1) && alternate;
1561 }
1562 if (top == -1 || top > bottom)
1563 continue;
1564
1565 // Paint each row item
1566 for (int visualRowIndex = top; visualRowIndex <= bottom; ++visualRowIndex) {
1567 int row = verticalHeader->logicalIndex(visualRowIndex);
1569 continue;
1570 int rowY = rowViewportPosition(row);
1571 rowY += offset.y();
1572 int rowh = rowHeight(row) - gridSize;
1573
1574 // Paint each column item
1575 for (int visualColumnIndex = left; visualColumnIndex <= right; ++visualColumnIndex) {
1576 int currentBit = (visualRowIndex - firstVisualRow) * (lastVisualColumn - firstVisualColumn + 1)
1577 + visualColumnIndex - firstVisualColumn;
1578
1579 if (currentBit < 0 || currentBit >= drawn.size() || drawn.testBit(currentBit))
1580 continue;
1581 drawn.setBit(currentBit);
1582
1583 int col = horizontalHeader->logicalIndex(visualColumnIndex);
1585 continue;
1586 int colp = columnViewportPosition(col);
1587 colp += offset.x();
1588 int colw = columnWidth(col) - gridSize;
1589
1590 const QModelIndex index = d->model->index(row, col, d->root);
1591 if (index.isValid()) {
1592 option.rect = QRect(colp + (showGrid && rightToLeft ? 1 : 0), rowY, colw, rowh);
1593 if (alternate) {
1594 if (alternateBase)
1595 option.features |= QStyleOptionViewItem::Alternate;
1596 else
1597 option.features &= ~QStyleOptionViewItem::Alternate;
1598 }
1599 d->drawCell(&painter, option, index);
1600 }
1601 }
1602 alternateBase = !alternateBase && alternate;
1603 }
1604
1605 if (showGrid) {
1606 // Find the bottom right (the last rows/columns might be hidden)
1608 QPen old = painter.pen();
1609 painter.setPen(gridPen);
1610 // Paint each row
1611 for (int visualIndex = top; visualIndex <= bottom; ++visualIndex) {
1612 int row = verticalHeader->logicalIndex(visualIndex);
1614 continue;
1615 int rowY = rowViewportPosition(row);
1616 rowY += offset.y();
1617 int rowh = rowHeight(row) - gridSize;
1618 QLineF line(dirtyArea.left(), rowY + rowh, dirtyArea.right(), rowY + rowh);
1619 painter.drawLine(line.translated(0.5, 0.5));
1620 }
1621
1622 // Paint each column
1623 for (int h = left; h <= right; ++h) {
1624 int col = horizontalHeader->logicalIndex(h);
1626 continue;
1627 int colp = columnViewportPosition(col);
1628 colp += offset.x();
1629 if (!rightToLeft)
1630 colp += columnWidth(col) - gridSize;
1631 QLineF line(colp, dirtyArea.top(), colp, dirtyArea.bottom());
1632 painter.drawLine(line.translated(0.5, 0.5));
1633 }
1634 const bool drawWhenHidden = style()->styleHint(QStyle::SH_Table_AlwaysDrawLeftTopGridLines,
1635 &option, this);
1636 if (drawWhenHidden && horizontalHeader->isHidden()) {
1637 const int row = verticalHeader->logicalIndex(top);
1639 const int rowY = rowViewportPosition(row) + offset.y();
1640 if (rowY == dirtyArea.top())
1641 painter.drawLine(dirtyArea.left(), rowY, dirtyArea.right(), rowY);
1642 }
1643 }
1644 if (drawWhenHidden && verticalHeader->isHidden()) {
1645 const int col = horizontalHeader->logicalIndex(left);
1646 if (!horizontalHeader->isSectionHidden(col)) {
1647 int colX = columnViewportPosition(col) + offset.x();
1648 if (!isLeftToRight())
1649 colX += columnWidth(left) - 1;
1650 if (isLeftToRight() && colX == dirtyArea.left())
1651 painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom());
1652 if (!isLeftToRight() && colX == dirtyArea.right())
1653 painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom());
1654 }
1655 }
1656 painter.setPen(old);
1657 }
1658 }
1659
1660#if QT_CONFIG(draganddrop)
1661 // Paint the dropIndicator
1662 d->paintDropIndicator(&painter);
1663#endif
1664}
1665
1671{
1672 Q_D(const QTableView);
1673 d->executePostedLayout();
1674 int r = rowAt(pos.y());
1675 int c = columnAt(pos.x());
1676 if (r >= 0 && c >= 0) {
1677 if (d->hasSpans()) {
1678 QSpanCollection::Span span = d->span(r, c);
1679 r = span.top();
1680 c = span.left();
1681 }
1682 return d->model->index(r, c, d->root);
1683 }
1684 return QModelIndex();
1685}
1686
1696{
1697 Q_D(const QTableView);
1698 return d->horizontalHeader->offset();
1699}
1700
1710{
1711 Q_D(const QTableView);
1712 return d->verticalHeader->offset();
1713}
1714
1723QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1724{
1725 Q_D(QTableView);
1727
1728 int bottom = d->model->rowCount(d->root) - 1;
1729 // make sure that bottom is the bottommost *visible* row
1730 while (bottom >= 0 && isRowHidden(d->logicalRow(bottom)))
1731 --bottom;
1732
1733 int right = d->model->columnCount(d->root) - 1;
1734
1735 while (right >= 0 && isColumnHidden(d->logicalColumn(right)))
1736 --right;
1737
1738 if (bottom == -1 || right == -1)
1739 return QModelIndex(); // model is empty
1740
1741 QModelIndex current = currentIndex();
1742
1743 if (!current.isValid()) {
1744 int row = 0;
1745 int column = 0;
1746 while (column < right && isColumnHidden(d->logicalColumn(column)))
1747 ++column;
1748 while (isRowHidden(d->logicalRow(row)) && row < bottom)
1749 ++row;
1750 d->visualCursor = QPoint(column, row);
1751 return d->model->index(d->logicalRow(row), d->logicalColumn(column), d->root);
1752 }
1753
1754 // Update visual cursor if current index has changed.
1755 QPoint visualCurrent(d->visualColumn(current.column()), d->visualRow(current.row()));
1756 if (visualCurrent != d->visualCursor) {
1757 if (d->hasSpans()) {
1758 QSpanCollection::Span span = d->span(current.row(), current.column());
1759 if (span.top() > d->visualCursor.y() || d->visualCursor.y() > span.bottom()
1760 || span.left() > d->visualCursor.x() || d->visualCursor.x() > span.right())
1761 d->visualCursor = visualCurrent;
1762 } else {
1763 d->visualCursor = visualCurrent;
1764 }
1765 }
1766
1767 int visualRow = d->visualCursor.y();
1768 if (visualRow > bottom)
1769 visualRow = bottom;
1770 Q_ASSERT(visualRow != -1);
1771 int visualColumn = d->visualCursor.x();
1772 if (visualColumn > right)
1773 visualColumn = right;
1774 Q_ASSERT(visualColumn != -1);
1775
1776 if (isRightToLeft()) {
1777 if (cursorAction == MoveLeft)
1778 cursorAction = MoveRight;
1779 else if (cursorAction == MoveRight)
1780 cursorAction = MoveLeft;
1781 }
1782
1783 switch (cursorAction) {
1784 case MoveUp: {
1785 int originalRow = visualRow;
1786#ifdef QT_KEYPAD_NAVIGATION
1787 if (QApplicationPrivate::keypadNavigationEnabled() && visualRow == 0)
1788 visualRow = d->visualRow(model()->rowCount() - 1) + 1;
1789 // FIXME? visualRow = bottom + 1;
1790#endif
1791 int r = d->logicalRow(visualRow);
1792 int c = d->logicalColumn(visualColumn);
1793 if (r != -1 && d->hasSpans()) {
1794 QSpanCollection::Span span = d->span(r, c);
1795 if (span.width() > 1 || span.height() > 1)
1796 visualRow = d->visualRow(span.top());
1797 }
1798 while (visualRow >= 0) {
1799 --visualRow;
1800 r = d->logicalRow(visualRow);
1801 c = d->logicalColumn(visualColumn);
1802 if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c)))
1803 break;
1804 }
1805 if (visualRow < 0)
1806 visualRow = originalRow;
1807 break;
1808 }
1809 case MoveDown: {
1810 int originalRow = visualRow;
1811 if (d->hasSpans()) {
1812 QSpanCollection::Span span = d->span(current.row(), current.column());
1813 visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
1814 }
1815#ifdef QT_KEYPAD_NAVIGATION
1816 if (QApplicationPrivate::keypadNavigationEnabled() && visualRow >= bottom)
1817 visualRow = -1;
1818#endif
1819 int r = d->logicalRow(visualRow);
1820 int c = d->logicalColumn(visualColumn);
1821 if (r != -1 && d->hasSpans()) {
1822 QSpanCollection::Span span = d->span(r, c);
1823 if (span.width() > 1 || span.height() > 1)
1824 visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
1825 }
1826 while (visualRow <= bottom) {
1827 ++visualRow;
1828 r = d->logicalRow(visualRow);
1829 c = d->logicalColumn(visualColumn);
1830 if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c)))
1831 break;
1832 }
1833 if (visualRow > bottom)
1834 visualRow = originalRow;
1835 break;
1836 }
1837 case MovePrevious:
1838 case MoveLeft: {
1839 int originalRow = visualRow;
1840 int originalColumn = visualColumn;
1841 bool firstTime = true;
1842 bool looped = false;
1843 bool wrapped = false;
1844 do {
1845 int r = d->logicalRow(visualRow);
1846 int c = d->logicalColumn(visualColumn);
1847 if (firstTime && c != -1 && d->hasSpans()) {
1848 firstTime = false;
1849 QSpanCollection::Span span = d->span(r, c);
1850 if (span.width() > 1 || span.height() > 1)
1851 visualColumn = d->visualColumn(span.left());
1852 }
1853 while (visualColumn >= 0) {
1854 --visualColumn;
1855 r = d->logicalRow(visualRow);
1856 c = d->logicalColumn(visualColumn);
1857 if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c)))
1858 break;
1859 if (wrapped && (originalRow < visualRow || (originalRow == visualRow && originalColumn <= visualColumn))) {
1860 looped = true;
1861 break;
1862 }
1863 }
1864 if (cursorAction == MoveLeft || visualColumn >= 0)
1865 break;
1866 visualColumn = right + 1;
1867 if (visualRow == 0) {
1868 wrapped = true;
1869 visualRow = bottom;
1870 } else {
1871 --visualRow;
1872 }
1873 } while (!looped);
1874 if (visualColumn < 0)
1875 visualColumn = originalColumn;
1876 break;
1877 }
1878 case MoveNext:
1879 case MoveRight: {
1880 int originalRow = visualRow;
1881 int originalColumn = visualColumn;
1882 bool firstTime = true;
1883 bool looped = false;
1884 bool wrapped = false;
1885 do {
1886 int r = d->logicalRow(visualRow);
1887 int c = d->logicalColumn(visualColumn);
1888 if (firstTime && c != -1 && d->hasSpans()) {
1889 firstTime = false;
1890 QSpanCollection::Span span = d->span(r, c);
1891 if (span.width() > 1 || span.height() > 1)
1892 visualColumn = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
1893 }
1894 while (visualColumn <= right) {
1895 ++visualColumn;
1896 r = d->logicalRow(visualRow);
1897 c = d->logicalColumn(visualColumn);
1898 if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c)))
1899 break;
1900 if (wrapped && (originalRow > visualRow || (originalRow == visualRow && originalColumn >= visualColumn))) {
1901 looped = true;
1902 break;
1903 }
1904 }
1905 if (cursorAction == MoveRight || visualColumn <= right)
1906 break;
1907 visualColumn = -1;
1908 if (visualRow == bottom) {
1909 wrapped = true;
1910 visualRow = 0;
1911 } else {
1912 ++visualRow;
1913 }
1914 } while (!looped);
1915 if (visualColumn > right)
1916 visualColumn = originalColumn;
1917 break;
1918 }
1919 case MoveHome:
1920 visualColumn = d->nextActiveVisualColumn(visualRow, 0, right,
1923 visualRow = d->nextActiveVisualRow(0, visualColumn, bottom,
1925 break;
1926 case MoveEnd:
1927 visualColumn = d->nextActiveVisualColumn(visualRow, right, -1,
1930 visualRow = d->nextActiveVisualRow(bottom, visualColumn, -1,
1932 break;
1933 case MovePageUp: {
1934 int newLogicalRow = rowAt(visualRect(current).bottom() - d->viewport->height());
1935 int visualRow = (newLogicalRow == -1 ? 0 : d->visualRow(newLogicalRow));
1936 visualRow = d->nextActiveVisualRow(visualRow, current.column(), bottom,
1938 newLogicalRow = d->logicalRow(visualRow);
1939 return d->model->index(newLogicalRow, current.column(), d->root);
1940 }
1941 case MovePageDown: {
1942 int newLogicalRow = rowAt(visualRect(current).top() + d->viewport->height());
1943 int visualRow = (newLogicalRow == -1 ? bottom : d->visualRow(newLogicalRow));
1944 visualRow = d->nextActiveVisualRow(visualRow, current.column(), -1,
1946 newLogicalRow = d->logicalRow(visualRow);
1947 return d->model->index(newLogicalRow, current.column(), d->root);
1948 }}
1949
1950 d->visualCursor = QPoint(visualColumn, visualRow);
1951 int logicalRow = d->logicalRow(visualRow);
1952 int logicalColumn = d->logicalColumn(visualColumn);
1953 if (!d->model->hasIndex(logicalRow, logicalColumn, d->root))
1954 return QModelIndex();
1955
1956 QModelIndex result = d->model->index(logicalRow, logicalColumn, d->root);
1957 if (!d->isRowHidden(logicalRow) && !d->isColumnHidden(logicalColumn) && d->isIndexEnabled(result)) {
1958 if (d->hasSpans()) {
1959 QSpanCollection::Span span = d->span(result.row(), result.column());
1960 if (span.width() > 1 || span.height() > 1) {
1961 result = d->model->sibling(span.top(), span.left(), result);
1962 }
1963 }
1964 return result;
1965 }
1966
1967 return QModelIndex();
1968}
1969
1977void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
1978{
1979 Q_D(QTableView);
1980 QModelIndex tl = indexAt(QPoint(isRightToLeft() ? qMax(rect.left(), rect.right())
1981 : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom())));
1982 QModelIndex br = indexAt(QPoint(isRightToLeft() ? qMin(rect.left(), rect.right()) :
1983 qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom())));
1984 if (!d->selectionModel || !tl.isValid() || !br.isValid() || !d->isIndexEnabled(tl) || !d->isIndexEnabled(br))
1985 return;
1986
1987 bool verticalMoved = verticalHeader()->sectionsMoved();
1988 bool horizontalMoved = horizontalHeader()->sectionsMoved();
1989
1991
1992 if (d->hasSpans()) {
1993 bool expanded;
1994 // when the current selection does not intersect with any spans of merged cells,
1995 // the range of selected cells must be the same as if there were no merged cells
1996 bool intersectsSpan = false;
1997 int top = qMin(d->visualRow(tl.row()), d->visualRow(br.row()));
1998 int left = qMin(d->visualColumn(tl.column()), d->visualColumn(br.column()));
1999 int bottom = qMax(d->visualRow(tl.row()), d->visualRow(br.row()));
2000 int right = qMax(d->visualColumn(tl.column()), d->visualColumn(br.column()));
2001 do {
2002 expanded = false;
2003 for (QSpanCollection::Span *it : d->spans.spans) {
2004 const QSpanCollection::Span &span = *it;
2005 int t = d->visualRow(span.top());
2006 int l = d->visualColumn(span.left());
2007 int b = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
2008 int r = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
2009 if ((t > bottom) || (l > right) || (top > b) || (left > r))
2010 continue; // no intersect
2011 intersectsSpan = true;
2012 if (t < top) {
2013 top = t;
2014 expanded = true;
2015 }
2016 if (l < left) {
2017 left = l;
2018 expanded = true;
2019 }
2020 if (b > bottom) {
2021 bottom = b;
2022 expanded = true;
2023 }
2024 if (r > right) {
2025 right = r;
2026 expanded = true;
2027 }
2028 if (expanded)
2029 break;
2030 }
2031 } while (expanded);
2032 if (intersectsSpan) {
2033 selection.reserve((right - left + 1) * (bottom - top + 1));
2034 for (int horizontal = left; horizontal <= right; ++horizontal) {
2035 int column = d->logicalColumn(horizontal);
2036 for (int vertical = top; vertical <= bottom; ++vertical) {
2037 int row = d->logicalRow(vertical);
2038 QModelIndex index = d->model->index(row, column, d->root);
2040 }
2041 }
2042 } else {
2043 QItemSelectionRange range(tl, br);
2044 if (!range.isEmpty())
2046 }
2047 } else if (verticalMoved && horizontalMoved) {
2048 int top = d->visualRow(tl.row());
2049 int left = d->visualColumn(tl.column());
2050 int bottom = d->visualRow(br.row());
2051 int right = d->visualColumn(br.column());
2052 selection.reserve((right - left + 1) * (bottom - top + 1));
2053 for (int horizontal = left; horizontal <= right; ++horizontal) {
2054 int column = d->logicalColumn(horizontal);
2055 for (int vertical = top; vertical <= bottom; ++vertical) {
2056 int row = d->logicalRow(vertical);
2057 QModelIndex index = d->model->index(row, column, d->root);
2059 }
2060 }
2061 } else if (horizontalMoved) {
2062 int left = d->visualColumn(tl.column());
2063 int right = d->visualColumn(br.column());
2064 selection.reserve(right - left + 1);
2065 for (int visual = left; visual <= right; ++visual) {
2066 int column = d->logicalColumn(visual);
2067 QModelIndex topLeft = d->model->index(tl.row(), column, d->root);
2068 QModelIndex bottomRight = d->model->index(br.row(), column, d->root);
2069 selection.append(QItemSelectionRange(topLeft, bottomRight));
2070 }
2071 } else if (verticalMoved) {
2072 int top = d->visualRow(tl.row());
2073 int bottom = d->visualRow(br.row());
2074 selection.reserve(bottom - top + 1);
2075 for (int visual = top; visual <= bottom; ++visual) {
2076 int row = d->logicalRow(visual);
2077 QModelIndex topLeft = d->model->index(row, tl.column(), d->root);
2078 QModelIndex bottomRight = d->model->index(row, br.column(), d->root);
2079 selection.append(QItemSelectionRange(topLeft, bottomRight));
2080 }
2081 } else { // nothing moved
2082 QItemSelectionRange range(tl, br);
2083 if (!range.isEmpty())
2085 }
2086
2087 d->selectionModel->select(selection, command);
2088}
2089
2100{
2101 Q_D(const QTableView);
2102
2103 if (selection.isEmpty())
2104 return QRegion();
2105
2106 QRegion selectionRegion;
2107 const QRect &viewportRect = d->viewport->rect();
2108 bool verticalMoved = verticalHeader()->sectionsMoved();
2109 bool horizontalMoved = horizontalHeader()->sectionsMoved();
2110
2111 if ((verticalMoved && horizontalMoved) || (d->hasSpans() && (verticalMoved || horizontalMoved))) {
2112 for (const auto &range : selection) {
2113 if (range.parent() != d->root || !range.isValid())
2114 continue;
2115 for (int r = range.top(); r <= range.bottom(); ++r)
2116 for (int c = range.left(); c <= range.right(); ++c) {
2117 const QRect &rangeRect = visualRect(d->model->index(r, c, d->root));
2118 if (viewportRect.intersects(rangeRect))
2119 selectionRegion += rangeRect;
2120 }
2121 }
2122 } else if (horizontalMoved) {
2123 for (const auto &range : selection) {
2124 if (range.parent() != d->root || !range.isValid())
2125 continue;
2126 int top = rowViewportPosition(range.top());
2127 int bottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom());
2128 if (top > bottom)
2129 qSwap<int>(top, bottom);
2130 int height = bottom - top;
2131 for (int c = range.left(); c <= range.right(); ++c) {
2132 const QRect rangeRect(columnViewportPosition(c), top, columnWidth(c), height);
2133 if (viewportRect.intersects(rangeRect))
2134 selectionRegion += rangeRect;
2135 }
2136 }
2137 } else if (verticalMoved) {
2138 for (const auto &range : selection) {
2139 if (range.parent() != d->root || !range.isValid())
2140 continue;
2141 int left = columnViewportPosition(range.left());
2142 int right = columnViewportPosition(range.right()) + columnWidth(range.right());
2143 if (left > right)
2144 qSwap<int>(left, right);
2145 int width = right - left;
2146 for (int r = range.top(); r <= range.bottom(); ++r) {
2147 const QRect rangeRect(left, rowViewportPosition(r), width, rowHeight(r));
2148 if (viewportRect.intersects(rangeRect))
2149 selectionRegion += rangeRect;
2150 }
2151 }
2152 } else { // nothing moved
2153 const int gridAdjust = showGrid() ? 1 : 0;
2154 for (auto range : selection) {
2155 if (range.parent() != d->root || !range.isValid())
2156 continue;
2157 d->trimHiddenSelections(&range);
2158
2159 const int rtop = rowViewportPosition(range.top());
2160 const int rbottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom());
2161 int rleft;
2162 int rright;
2163 if (isLeftToRight()) {
2164 rleft = columnViewportPosition(range.left());
2165 rright = columnViewportPosition(range.right()) + columnWidth(range.right());
2166 } else {
2167 rleft = columnViewportPosition(range.right());
2168 rright = columnViewportPosition(range.left()) + columnWidth(range.left());
2169 }
2170 const QRect rangeRect(QPoint(rleft, rtop), QPoint(rright - 1 - gridAdjust, rbottom - 1 - gridAdjust));
2171 if (viewportRect.intersects(rangeRect))
2172 selectionRegion += rangeRect;
2173 if (d->hasSpans()) {
2174 const auto spansInRect = d->spans.spansInRect(range.left(), range.top(), range.width(), range.height());
2175 for (QSpanCollection::Span *s : spansInRect) {
2176 if (range.contains(s->top(), s->left(), range.parent())) {
2177 const QRect &visualSpanRect = d->visualSpanRect(*s);
2178 if (viewportRect.intersects(visualSpanRect))
2179 selectionRegion += visualSpanRect;
2180 }
2181 }
2182 }
2183 }
2184 }
2185
2186 return selectionRegion;
2187}
2188
2189
2194{
2195 Q_D(const QTableView);
2196 QModelIndexList viewSelected;
2197 QModelIndexList modelSelected;
2198 if (d->selectionModel)
2199 modelSelected = d->selectionModel->selectedIndexes();
2200 for (int i = 0; i < modelSelected.size(); ++i) {
2201 QModelIndex index = modelSelected.at(i);
2202 if (!isIndexHidden(index) && index.parent() == d->root)
2203 viewSelected.append(index);
2204 }
2205 return viewSelected;
2206}
2207
2208
2214void QTableView::rowCountChanged(int oldCount, int newCount )
2215{
2216 Q_D(QTableView);
2217 //when removing rows, we need to disable updates for the header until the geometries have been
2218 //updated and the offset has been adjusted, or we risk calling paintSection for all the sections
2219 if (newCount < oldCount)
2220 d->verticalHeader->setUpdatesEnabled(false);
2221 d->doDelayedItemsLayout();
2222}
2223
2230{
2231 Q_D(QTableView);
2234 d->horizontalHeader->setOffsetToSectionPosition(horizontalScrollBar()->value());
2235 else
2236 d->horizontalHeader->setOffset(horizontalScrollBar()->value());
2237 d->viewport->update();
2238}
2239
2244{
2245 Q_D(QTableView);
2246 if (d->geometryRecursionBlock)
2247 return;
2248 d->geometryRecursionBlock = true;
2249
2250 int width = 0;
2251 if (!d->verticalHeader->isHidden()) {
2252 width = qMax(d->verticalHeader->minimumWidth(), d->verticalHeader->sizeHint().width());
2253 width = qMin(width, d->verticalHeader->maximumWidth());
2254 }
2255 int height = 0;
2256 if (!d->horizontalHeader->isHidden()) {
2257 height = qMax(d->horizontalHeader->minimumHeight(), d->horizontalHeader->sizeHint().height());
2258 height = qMin(height, d->horizontalHeader->maximumHeight());
2259 }
2260 bool reverse = isRightToLeft();
2261 if (reverse)
2262 setViewportMargins(0, height, width, 0);
2263 else
2264 setViewportMargins(width, height, 0, 0);
2265
2266 // update headers
2267
2268 QRect vg = d->viewport->geometry();
2269
2270 int verticalLeft = reverse ? vg.right() + 1 : (vg.left() - width);
2271 d->verticalHeader->setGeometry(verticalLeft, vg.top(), width, vg.height());
2272 if (d->verticalHeader->isHidden())
2273 QMetaObject::invokeMethod(d->verticalHeader, "updateGeometries");
2274
2275 int horizontalTop = vg.top() - height;
2276 d->horizontalHeader->setGeometry(vg.left(), horizontalTop, vg.width(), height);
2277 if (d->horizontalHeader->isHidden())
2278 QMetaObject::invokeMethod(d->horizontalHeader, "updateGeometries");
2279
2280#if QT_CONFIG(abstractbutton)
2281 // update cornerWidget
2282 if (d->horizontalHeader->isHidden() || d->verticalHeader->isHidden()) {
2283 d->cornerWidget->setHidden(true);
2284 } else {
2285 d->cornerWidget->setHidden(false);
2286 d->cornerWidget->setGeometry(verticalLeft, horizontalTop, width, height);
2287 }
2288#endif
2289
2290 // update scroll bars
2291
2292 // ### move this block into the if
2293 QSize vsize = d->viewport->size();
2294 QSize max = maximumViewportSize();
2295 const int horizontalLength = d->horizontalHeader->length();
2296 const int verticalLength = d->verticalHeader->length();
2297 if (max.width() >= horizontalLength && max.height() >= verticalLength)
2298 vsize = max;
2299
2300 // horizontal scroll bar
2301 const int columnCount = d->horizontalHeader->count();
2302 const int viewportWidth = vsize.width();
2303 int columnsInViewport = 0;
2304 for (int width = 0, column = columnCount - 1; column >= 0; --column) {
2305 int logical = d->horizontalHeader->logicalIndex(column);
2306 if (!d->horizontalHeader->isSectionHidden(logical)) {
2307 width += d->horizontalHeader->sectionSize(logical);
2308 if (width > viewportWidth)
2309 break;
2310 ++columnsInViewport;
2311 }
2312 }
2313 columnsInViewport = qMax(columnsInViewport, 1); //there must be always at least 1 column
2314
2316 const int visibleColumns = columnCount - d->horizontalHeader->hiddenSectionCount();
2317 horizontalScrollBar()->setRange(0, visibleColumns - columnsInViewport);
2318 horizontalScrollBar()->setPageStep(columnsInViewport);
2319 if (columnsInViewport >= visibleColumns)
2320 d->horizontalHeader->setOffset(0);
2321 horizontalScrollBar()->setSingleStep(1);
2322 } else { // ScrollPerPixel
2323 horizontalScrollBar()->setPageStep(vsize.width());
2324 horizontalScrollBar()->setRange(0, horizontalLength - vsize.width());
2325 horizontalScrollBar()->d_func()->itemviewChangeSingleStep(qMax(vsize.width() / (columnsInViewport + 1), 2));
2326 }
2327
2328 // vertical scroll bar
2329 const int rowCount = d->verticalHeader->count();
2330 const int viewportHeight = vsize.height();
2331 int rowsInViewport = 0;
2332 for (int height = 0, row = rowCount - 1; row >= 0; --row) {
2333 int logical = d->verticalHeader->logicalIndex(row);
2334 if (!d->verticalHeader->isSectionHidden(logical)) {
2335 height += d->verticalHeader->sectionSize(logical);
2336 if (height > viewportHeight)
2337 break;
2338 ++rowsInViewport;
2339 }
2340 }
2341 rowsInViewport = qMax(rowsInViewport, 1); //there must be always at least 1 row
2342
2344 const int visibleRows = rowCount - d->verticalHeader->hiddenSectionCount();
2345 verticalScrollBar()->setRange(0, visibleRows - rowsInViewport);
2346 verticalScrollBar()->setPageStep(rowsInViewport);
2347 if (rowsInViewport >= visibleRows)
2348 d->verticalHeader->setOffset(0);
2349 verticalScrollBar()->setSingleStep(1);
2350 } else { // ScrollPerPixel
2351 verticalScrollBar()->setPageStep(vsize.height());
2352 verticalScrollBar()->setRange(0, verticalLength - vsize.height());
2353 verticalScrollBar()->d_func()->itemviewChangeSingleStep(qMax(vsize.height() / (rowsInViewport + 1), 2));
2354 }
2355 d->verticalHeader->d_func()->setScrollOffset(verticalScrollBar(), verticalScrollMode());
2356
2357 d->geometryRecursionBlock = false;
2359}
2360
2376{
2377 Q_D(const QTableView);
2378
2379 if (!model())
2380 return -1;
2381
2382 ensurePolished();
2383 const int maximumProcessCols = d->verticalHeader->resizeContentsPrecision();
2384
2385
2386 int left = qMax(0, d->horizontalHeader->visualIndexAt(0));
2387 int right = d->horizontalHeader->visualIndexAt(d->viewport->width());
2388 if (right == -1) // the table don't have enough columns to fill the viewport
2389 right = d->model->columnCount(d->root) - 1;
2390
2391 QStyleOptionViewItem option;
2393
2394 int hint = 0;
2396 int columnsProcessed = 0;
2397 int column = left;
2398 for (; column <= right; ++column) {
2399 int logicalColumn = d->horizontalHeader->logicalIndex(column);
2400 if (d->horizontalHeader->isSectionHidden(logicalColumn))
2401 continue;
2402 index = d->model->index(row, logicalColumn, d->root);
2403 hint = d->heightHintForIndex(index, hint, option);
2404
2405 ++columnsProcessed;
2406 if (columnsProcessed == maximumProcessCols)
2407 break;
2408 }
2409
2410 int actualRight = d->model->columnCount(d->root) - 1;
2411 int idxLeft = left;
2412 int idxRight = column - 1;
2413
2414 if (maximumProcessCols == 0)
2415 columnsProcessed = 0; // skip the while loop
2416
2417 while (columnsProcessed != maximumProcessCols && (idxLeft > 0 || idxRight < actualRight)) {
2418 int logicalIdx = -1;
2419
2420 if ((columnsProcessed % 2 && idxLeft > 0) || idxRight == actualRight) {
2421 while (idxLeft > 0) {
2422 --idxLeft;
2423 int logcol = d->horizontalHeader->logicalIndex(idxLeft);
2424 if (d->horizontalHeader->isSectionHidden(logcol))
2425 continue;
2426 logicalIdx = logcol;
2427 break;
2428 }
2429 } else {
2430 while (idxRight < actualRight) {
2431 ++idxRight;
2432 int logcol = d->horizontalHeader->logicalIndex(idxRight);
2433 if (d->horizontalHeader->isSectionHidden(logcol))
2434 continue;
2435 logicalIdx = logcol;
2436 break;
2437 }
2438 }
2439 if (logicalIdx < 0)
2440 continue;
2441
2442 index = d->model->index(row, logicalIdx, d->root);
2443 hint = d->heightHintForIndex(index, hint, option);
2444 ++columnsProcessed;
2445 }
2446
2447 return d->showGrid ? hint + 1 : hint;
2448}
2449
2466{
2467 Q_D(const QTableView);
2468
2469 if (!model())
2470 return -1;
2471
2472 ensurePolished();
2473 const int maximumProcessRows = d->horizontalHeader->resizeContentsPrecision();
2474
2475 int top = qMax(0, d->verticalHeader->visualIndexAt(0));
2476 int bottom = d->verticalHeader->visualIndexAt(d->viewport->height());
2477 if (!isVisible() || bottom == -1) // the table don't have enough rows to fill the viewport
2478 bottom = d->model->rowCount(d->root) - 1;
2479
2480 QStyleOptionViewItem option;
2482
2483 int hint = 0;
2484 int rowsProcessed = 0;
2486 int row = top;
2487 for (; row <= bottom; ++row) {
2488 int logicalRow = d->verticalHeader->logicalIndex(row);
2489 if (d->verticalHeader->isSectionHidden(logicalRow))
2490 continue;
2491 index = d->model->index(logicalRow, column, d->root);
2492
2493 hint = d->widthHintForIndex(index, hint, option);
2494 ++rowsProcessed;
2495 if (rowsProcessed == maximumProcessRows)
2496 break;
2497 }
2498
2499 int actualBottom = d->model->rowCount(d->root) - 1;
2500 int idxTop = top;
2501 int idxBottom = row - 1;
2502
2503 if (maximumProcessRows == 0)
2504 rowsProcessed = 0; // skip the while loop
2505
2506 while (rowsProcessed != maximumProcessRows && (idxTop > 0 || idxBottom < actualBottom)) {
2507 int logicalIdx = -1;
2508
2509 if ((rowsProcessed % 2 && idxTop > 0) || idxBottom == actualBottom) {
2510 while (idxTop > 0) {
2511 --idxTop;
2512 int logrow = d->verticalHeader->logicalIndex(idxTop);
2513 if (d->verticalHeader->isSectionHidden(logrow))
2514 continue;
2515 logicalIdx = logrow;
2516 break;
2517 }
2518 } else {
2519 while (idxBottom < actualBottom) {
2520 ++idxBottom;
2521 int logrow = d->verticalHeader->logicalIndex(idxBottom);
2522 if (d->verticalHeader->isSectionHidden(logrow))
2523 continue;
2524 logicalIdx = logrow;
2525 break;
2526 }
2527 }
2528 if (logicalIdx < 0)
2529 continue;
2530
2531 index = d->model->index(logicalIdx, column, d->root);
2532 hint = d->widthHintForIndex(index, hint, option);
2533 ++rowsProcessed;
2534 }
2535
2536 return d->showGrid ? hint + 1 : hint;
2537}
2538
2544{
2545 Q_D(const QTableView);
2546 return d->verticalHeader->sectionViewportPosition(row);
2547}
2548
2558int QTableView::rowAt(int y) const
2559{
2560 Q_D(const QTableView);
2561 return d->verticalHeader->logicalIndexAt(y);
2562}
2563
2570{
2571 Q_D(const QTableView);
2572 d->verticalHeader->resizeSection(row, height);
2573}
2574
2581{
2582 Q_D(const QTableView);
2583 return d->verticalHeader->sectionSize(row);
2584}
2585
2591{
2592 Q_D(const QTableView);
2593 return d->horizontalHeader->sectionViewportPosition(column);
2594}
2595
2606{
2607 Q_D(const QTableView);
2608 return d->horizontalHeader->logicalIndexAt(x);
2609}
2610
2617{
2618 Q_D(const QTableView);
2619 d->horizontalHeader->resizeSection(column, width);
2620}
2621
2628{
2629 Q_D(const QTableView);
2630 return d->horizontalHeader->sectionSize(column);
2631}
2632
2639{
2640 Q_D(const QTableView);
2641 return d->verticalHeader->isSectionHidden(row);
2642}
2643
2650{
2651 Q_D(QTableView);
2652 if (row < 0 || row >= d->verticalHeader->count())
2653 return;
2654 d->verticalHeader->setSectionHidden(row, hide);
2655}
2656
2663{
2664 Q_D(const QTableView);
2665 return d->horizontalHeader->isSectionHidden(column);
2666}
2667
2675{
2676 Q_D(QTableView);
2677 if (column < 0 || column >= d->horizontalHeader->count())
2678 return;
2679 d->horizontalHeader->setSectionHidden(column, hide);
2680}
2681
2704{
2705 Q_D(QTableView);
2707 if (enable) {
2708 disconnect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
2709 this, SLOT(_q_selectColumn(int)));
2710 disconnect(horizontalHeader(), SIGNAL(sectionPressed(int)),
2711 this, SLOT(selectColumn(int)));
2712 //sortByColumn has to be called before we connect or set the sortingEnabled flag
2713 // because otherwise it will not call sort on the model.
2714 sortByColumn(horizontalHeader()->sortIndicatorSection(),
2715 horizontalHeader()->sortIndicatorOrder());
2716 connect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
2717 this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)), Qt::UniqueConnection);
2718 } else {
2719 connect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
2720 this, SLOT(_q_selectColumn(int)), Qt::UniqueConnection);
2721 connect(horizontalHeader(), SIGNAL(sectionPressed(int)),
2723 disconnect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
2724 this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)));
2725 }
2726 d->sortingEnabled = enable;
2727}
2728
2730{
2731 Q_D(const QTableView);
2732 return d->sortingEnabled;
2733}
2734
2743{
2744 Q_D(const QTableView);
2745 return d->showGrid;
2746}
2747
2749{
2750 Q_D(QTableView);
2751 if (d->showGrid != show) {
2752 d->showGrid = show;
2753 d->viewport->update();
2754 }
2755}
2756
2764{
2765 Q_D(const QTableView);
2766 return d->gridStyle;
2767}
2768
2770{
2771 Q_D(QTableView);
2772 if (d->gridStyle != style) {
2773 d->gridStyle = style;
2774 d->viewport->update();
2775 }
2776}
2777
2793{
2794 Q_D(QTableView);
2795 if (d->wrapItemText == on)
2796 return;
2797 d->wrapItemText = on;
2798 QMetaObject::invokeMethod(d->verticalHeader, "resizeSections");
2799 QMetaObject::invokeMethod(d->horizontalHeader, "resizeSections");
2800}
2801
2803{
2804 Q_D(const QTableView);
2805 return d->wrapItemText;
2806}
2807
2808#if QT_CONFIG(abstractbutton)
2820void QTableView::setCornerButtonEnabled(bool enable)
2821{
2822 Q_D(QTableView);
2823 d->cornerWidget->setEnabled(enable);
2824}
2825
2826bool QTableView::isCornerButtonEnabled() const
2827{
2828 Q_D(const QTableView);
2829 return d->cornerWidget->isEnabled();
2830}
2831#endif
2832
2841{
2842 Q_D(const QTableView);
2843 if (!d->isIndexValid(index) || index.parent() != d->root
2844 || (!d->hasSpans() && isIndexHidden(index)))
2845 return QRect();
2846
2847 d->executePostedLayout();
2848
2849 if (d->hasSpans()) {
2850 QSpanCollection::Span span = d->span(index.row(), index.column());
2851 return d->visualSpanRect(span);
2852 }
2853
2854 int rowp = rowViewportPosition(index.row());
2855 int rowh = rowHeight(index.row());
2856 int colp = columnViewportPosition(index.column());
2857 int colw = columnWidth(index.column());
2858
2859 const int i = showGrid() ? 1 : 0;
2860 return QRect(colp, rowp, colw - i, rowh - i);
2861}
2862
2870{
2871 Q_D(QTableView);
2872
2873 // check if we really need to do anything
2874 if (!d->isIndexValid(index)
2875 || (d->model->parent(index) != d->root)
2876 || isRowHidden(index.row()) || isColumnHidden(index.column()))
2877 return;
2878
2880 if (d->hasSpans())
2881 span = d->span(index.row(), index.column());
2882
2883 // Adjust horizontal position
2884
2885 int viewportWidth = d->viewport->width();
2886 int horizontalOffset = d->horizontalHeader->offset();
2887 int horizontalPosition = d->horizontalHeader->sectionPosition(index.column());
2888 int horizontalIndex = d->horizontalHeader->visualIndex(index.column());
2889 int cellWidth = d->hasSpans()
2890 ? d->columnSpanWidth(index.column(), span.width())
2891 : d->horizontalHeader->sectionSize(index.column());
2892
2894
2895 bool positionAtLeft = (horizontalPosition - horizontalOffset < 0);
2896 bool positionAtRight = (horizontalPosition - horizontalOffset + cellWidth > viewportWidth);
2897
2898 if (hint == PositionAtCenter || positionAtRight) {
2899 int w = (hint == PositionAtCenter ? viewportWidth / 2 : viewportWidth);
2900 int x = cellWidth;
2901 while (horizontalIndex > 0) {
2902 x += columnWidth(d->horizontalHeader->logicalIndex(horizontalIndex-1));
2903 if (x > w)
2904 break;
2905 --horizontalIndex;
2906 }
2907 }
2908
2909 if (positionAtRight || hint == PositionAtCenter || positionAtLeft) {
2910 int hiddenSections = 0;
2911 if (d->horizontalHeader->sectionsHidden()) {
2912 for (int s = horizontalIndex - 1; s >= 0; --s) {
2913 int column = d->horizontalHeader->logicalIndex(s);
2914 if (d->horizontalHeader->isSectionHidden(column))
2915 ++hiddenSections;
2916 }
2917 }
2918 horizontalScrollBar()->setValue(horizontalIndex - hiddenSections);
2919 }
2920
2921 } else { // ScrollPerPixel
2922 if (hint == PositionAtCenter) {
2923 horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
2924 } else {
2925 if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
2926 horizontalScrollBar()->setValue(horizontalPosition);
2927 else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
2928 horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
2929 }
2930 }
2931
2932 // Adjust vertical position
2933
2934 int viewportHeight = d->viewport->height();
2935 int verticalOffset = d->verticalHeader->offset();
2936 int verticalPosition = d->verticalHeader->sectionPosition(index.row());
2937 int verticalIndex = d->verticalHeader->visualIndex(index.row());
2938 int cellHeight = d->hasSpans()
2939 ? d->rowSpanHeight(index.row(), span.height())
2940 : d->verticalHeader->sectionSize(index.row());
2941
2942 if (verticalPosition - verticalOffset < 0 || cellHeight > viewportHeight) {
2943 if (hint == EnsureVisible)
2945 } else if (verticalPosition - verticalOffset + cellHeight > viewportHeight) {
2946 if (hint == EnsureVisible)
2948 }
2949
2951
2953 int h = (hint == PositionAtCenter ? viewportHeight / 2 : viewportHeight);
2954 int y = cellHeight;
2955 while (verticalIndex > 0) {
2956 int row = d->verticalHeader->logicalIndex(verticalIndex - 1);
2957 y += d->verticalHeader->sectionSize(row);
2958 if (y > h)
2959 break;
2960 --verticalIndex;
2961 }
2962 }
2963
2965 int hiddenSections = 0;
2966 if (d->verticalHeader->sectionsHidden()) {
2967 for (int s = verticalIndex - 1; s >= 0; --s) {
2968 int row = d->verticalHeader->logicalIndex(s);
2969 if (d->verticalHeader->isSectionHidden(row))
2970 ++hiddenSections;
2971 }
2972 }
2973 verticalScrollBar()->setValue(verticalIndex - hiddenSections);
2974 }
2975
2976 } else { // ScrollPerPixel
2977 if (hint == PositionAtTop) {
2978 verticalScrollBar()->setValue(verticalPosition);
2979 } else if (hint == PositionAtBottom) {
2980 verticalScrollBar()->setValue(verticalPosition - viewportHeight + cellHeight);
2981 } else if (hint == PositionAtCenter) {
2982 verticalScrollBar()->setValue(verticalPosition - ((viewportHeight - cellHeight) / 2));
2983 }
2984 }
2985
2986 update(index);
2987}
2988
2996void QTableView::rowResized(int row, int, int)
2997{
2998 Q_D(QTableView);
2999 d->rowsToUpdate.append(row);
3000 if (d->rowResizeTimerID == 0)
3001 d->rowResizeTimerID = startTimer(0);
3002}
3003
3012{
3013 Q_D(QTableView);
3014 d->columnsToUpdate.append(column);
3015 if (d->columnResizeTimerID == 0)
3016 d->columnResizeTimerID = startTimer(0);
3017}
3018
3023{
3024 Q_D(QTableView);
3025
3026 if (event->timerId() == d->columnResizeTimerID) {
3027 const int oldScrollMax = horizontalScrollBar()->maximum();
3030 killTimer(d->columnResizeTimerID);
3031 d->columnResizeTimerID = 0;
3032 } else {
3034 }
3035
3036 QRect rect;
3037 int viewportHeight = d->viewport->height();
3038 int viewportWidth = d->viewport->width();
3039 if (d->hasSpans() || horizontalScrollBar()->value() == oldScrollMax) {
3040 rect = QRect(0, 0, viewportWidth, viewportHeight);
3041 } else {
3042 for (int i = d->columnsToUpdate.size()-1; i >= 0; --i) {
3043 int column = d->columnsToUpdate.at(i);
3045 if (isRightToLeft())
3046 rect |= QRect(0, 0, x + columnWidth(column), viewportHeight);
3047 else
3048 rect |= QRect(x, 0, viewportWidth - x, viewportHeight);
3049 }
3050 }
3051
3052 d->viewport->update(rect.normalized());
3053 d->columnsToUpdate.clear();
3054 }
3055
3056 if (event->timerId() == d->rowResizeTimerID) {
3057 const int oldScrollMax = verticalScrollBar()->maximum();
3060 killTimer(d->rowResizeTimerID);
3061 d->rowResizeTimerID = 0;
3062 } else {
3064 }
3065
3066 int viewportHeight = d->viewport->height();
3067 int viewportWidth = d->viewport->width();
3068 int top;
3069 if (d->hasSpans() || verticalScrollBar()->value() == oldScrollMax) {
3070 top = 0;
3071 } else {
3072 top = viewportHeight;
3073 for (int i = d->rowsToUpdate.size()-1; i >= 0; --i) {
3074 int y = rowViewportPosition(d->rowsToUpdate.at(i));
3075 top = qMin(top, y);
3076 }
3077 }
3078
3079 d->viewport->update(QRect(0, top, viewportWidth, viewportHeight - top));
3080 d->rowsToUpdate.clear();
3081 }
3082
3084}
3085
3093void QTableView::rowMoved(int row, int oldIndex, int newIndex)
3094{
3095 Q_UNUSED(row);
3096 Q_D(QTableView);
3097
3099 int logicalOldIndex = d->verticalHeader->logicalIndex(oldIndex);
3100 int logicalNewIndex = d->verticalHeader->logicalIndex(newIndex);
3101 if (d->hasSpans()) {
3102 d->viewport->update();
3103 } else {
3104 int oldTop = rowViewportPosition(logicalOldIndex);
3105 int newTop = rowViewportPosition(logicalNewIndex);
3106 int oldBottom = oldTop + rowHeight(logicalOldIndex);
3107 int newBottom = newTop + rowHeight(logicalNewIndex);
3108 int top = qMin(oldTop, newTop);
3109 int bottom = qMax(oldBottom, newBottom);
3110 int height = bottom - top;
3111 d->viewport->update(0, top, d->viewport->width(), height);
3112 }
3113}
3114
3122void QTableView::columnMoved(int column, int oldIndex, int newIndex)
3123{
3125 Q_D(QTableView);
3126
3128 int logicalOldIndex = d->horizontalHeader->logicalIndex(oldIndex);
3129 int logicalNewIndex = d->horizontalHeader->logicalIndex(newIndex);
3130 if (d->hasSpans()) {
3131 d->viewport->update();
3132 } else {
3133 int oldLeft = columnViewportPosition(logicalOldIndex);
3134 int newLeft = columnViewportPosition(logicalNewIndex);
3135 int oldRight = oldLeft + columnWidth(logicalOldIndex);
3136 int newRight = newLeft + columnWidth(logicalNewIndex);
3137 int left = qMin(oldLeft, newLeft);
3138 int right = qMax(oldRight, newRight);
3139 int width = right - left;
3140 d->viewport->update(left, 0, width, d->viewport->height());
3141 }
3142}
3143
3151{
3152 Q_D(QTableView);
3153 d->selectRow(row, true);
3154}
3155
3163{
3164 Q_D(QTableView);
3165 d->selectColumn(column, true);
3166}
3167
3174{
3175 Q_D(QTableView);
3176 d->verticalHeader->hideSection(row);
3177}
3178
3185{
3186 Q_D(QTableView);
3187 d->horizontalHeader->hideSection(column);
3188}
3189
3196{
3197 Q_D(QTableView);
3198 d->verticalHeader->showSection(row);
3199}
3200
3207{
3208 Q_D(QTableView);
3209 d->horizontalHeader->showSection(column);
3210}
3211
3219{
3220 Q_D(QTableView);
3221 int content = sizeHintForRow(row);
3222 int header = d->verticalHeader->sectionSizeHint(row);
3223 d->verticalHeader->resizeSection(row, qMax(content, header));
3224}
3225
3233{
3234 Q_D(QTableView);
3235 d->verticalHeader->resizeSections(QHeaderView::ResizeToContents);
3236}
3237
3248{
3249 Q_D(QTableView);
3250 int content = sizeHintForColumn(column);
3251 int header = d->horizontalHeader->sectionSizeHint(column);
3252 d->horizontalHeader->resizeSection(column, qMax(content, header));
3253}
3254
3262{
3263 Q_D(QTableView);
3264 d->horizontalHeader->resizeSections(QHeaderView::ResizeToContents);
3265}
3266
3279{
3280 Q_D(QTableView);
3281 if (column < -1)
3282 return;
3283 d->horizontalHeader->setSortIndicator(column, order);
3284 // If sorting is not enabled or has the same order as before, force to sort now
3285 // else sorting will be trigger through sortIndicatorChanged()
3286 if (!d->sortingEnabled ||
3287 (d->horizontalHeader->sortIndicatorSection() == column && d->horizontalHeader->sortIndicatorOrder() == order))
3288 d->model->sort(column, order);
3289}
3290
3295{
3297}
3298
3303{
3305}
3306
3311{
3312 Q_D(const QTableView);
3313 Q_ASSERT(d->isIndexValid(index));
3314 if (isRowHidden(index.row()) || isColumnHidden(index.column()))
3315 return true;
3316 if (d->hasSpans()) {
3317 QSpanCollection::Span span = d->span(index.row(), index.column());
3318 return !((span.top() == index.row()) && (span.left() == index.column()));
3319 }
3320 return false;
3321}
3322
3332void QTableView::setSpan(int row, int column, int rowSpan, int columnSpan)
3333{
3334 Q_D(QTableView);
3335 if (row < 0 || column < 0 || rowSpan < 0 || columnSpan < 0)
3336 return;
3337 d->setSpan(row, column, rowSpan, columnSpan);
3338 d->viewport->update();
3339}
3340
3349int QTableView::rowSpan(int row, int column) const
3350{
3351 Q_D(const QTableView);
3352 return d->rowSpan(row, column);
3353}
3354
3364{
3365 Q_D(const QTableView);
3366 return d->columnSpan(row, column);
3367}
3368
3378{
3379 Q_D(QTableView);
3380 d->spans.clear();
3381 d->viewport->update();
3382}
3383
3385{
3386 selectRow(row, false);
3387}
3388
3390{
3391 selectColumn(column, false);
3392}
3393
3394void QTableViewPrivate::selectRow(int row, bool anchor)
3395{
3396 Q_Q(QTableView);
3397
3398 if (q->selectionBehavior() == QTableView::SelectColumns
3399 || (q->selectionMode() == QTableView::SingleSelection
3400 && q->selectionBehavior() == QTableView::SelectItems))
3401 return;
3402
3403 if (row >= 0 && row < model->rowCount(root)) {
3404 int column = horizontalHeader->logicalIndexAt(q->isRightToLeft() ? viewport->width() : 0);
3406 QItemSelectionModel::SelectionFlags command = q->selectionCommand(index);
3408 if ((anchor && !(command & QItemSelectionModel::Current))
3409 || (q->selectionMode() == QTableView::SingleSelection))
3411
3412 if (q->selectionMode() != QTableView::SingleSelection
3413 && command.testFlag(QItemSelectionModel::Toggle)) {
3414 if (anchor)
3417 command &= ~QItemSelectionModel::Toggle;
3418 command |= ctrlDragSelectionFlag;
3419 if (!anchor)
3421 }
3422
3423 const auto rowSectionAnchor = currentSelectionStartIndex.row();
3424 QModelIndex upper = model->index(qMin(rowSectionAnchor, row), column, root);
3425 QModelIndex lower = model->index(qMax(rowSectionAnchor, row), column, root);
3426 if ((verticalHeader->sectionsMoved() && upper.row() != lower.row())) {
3427 q->setSelection(q->visualRect(upper) | q->visualRect(lower), command | QItemSelectionModel::Rows);
3428 } else {
3430 }
3431 }
3432}
3433
3435{
3436 Q_Q(QTableView);
3437
3438 if (q->selectionBehavior() == QTableView::SelectRows
3439 || (q->selectionMode() == QTableView::SingleSelection
3440 && q->selectionBehavior() == QTableView::SelectItems))
3441 return;
3442
3443 if (column >= 0 && column < model->columnCount(root)) {
3446 QItemSelectionModel::SelectionFlags command = q->selectionCommand(index);
3448 if ((anchor && !(command & QItemSelectionModel::Current))
3449 || (q->selectionMode() == QTableView::SingleSelection))
3451
3452 if (q->selectionMode() != QTableView::SingleSelection
3453 && command.testFlag(QItemSelectionModel::Toggle)) {
3454 if (anchor)
3457 command &= ~QItemSelectionModel::Toggle;
3458 command |= ctrlDragSelectionFlag;
3459 if (!anchor)
3461 }
3462
3463 const auto columnSectionAnchor = currentSelectionStartIndex.column();
3464 QModelIndex left = model->index(row, qMin(columnSectionAnchor, column), root);
3465 QModelIndex right = model->index(row, qMax(columnSectionAnchor, column), root);
3466 if ((horizontalHeader->sectionsMoved() && left.column() != right.column())) {
3467 q->setSelection(q->visualRect(left) | q->visualRect(right), command | QItemSelectionModel::Columns);
3468 } else {
3470 }
3471 }
3472}
3473
3477void QTableView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
3478{
3479#if QT_CONFIG(accessibility)
3480 if (QAccessible::isActive()) {
3481 if (current.isValid()) {
3482 Q_D(QTableView);
3483 int entry = d->accessibleTable2Index(current);
3484 QAccessibleEvent event(this, QAccessible::Focus);
3485 event.setChild(entry);
3486 QAccessible::updateAccessibility(&event);
3487 }
3488 }
3489#endif
3490 QAbstractItemView::currentChanged(current, previous);
3491}
3492
3497 const QItemSelection &deselected)
3498{
3499 Q_D(QTableView);
3500 Q_UNUSED(d);
3501#if QT_CONFIG(accessibility)
3502 if (QAccessible::isActive()) {
3503 // ### does not work properly for selection ranges.
3504 QModelIndex sel = selected.indexes().value(0);
3505 if (sel.isValid()) {
3506 int entry = d->accessibleTable2Index(sel);
3507 QAccessibleEvent event(this, QAccessible::SelectionAdd);
3508 event.setChild(entry);
3509 QAccessible::updateAccessibility(&event);
3510 }
3511 QModelIndex desel = deselected.indexes().value(0);
3512 if (desel.isValid()) {
3513 int entry = d->accessibleTable2Index(desel);
3514 QAccessibleEvent event(this, QAccessible::SelectionRemove);
3515 event.setChild(entry);
3516 QAccessible::updateAccessibility(&event);
3517 }
3518 }
3519#endif
3520 QAbstractItemView::selectionChanged(selected, deselected);
3521}
3522
3523int QTableView::visualIndex(const QModelIndex &index) const
3524{
3525 return index.row();
3526}
3527
3529
3530#include "qtableview.moc"
3531
3532#include "moc_qtableview.cpp"
The QAbstractButton class is the abstract base class of button widgets, providing functionality commo...
void paintEvent(QPaintEvent *e) override=0
\reimp
static QAbstractItemModel * staticEmptyModel()
virtual Q_INVOKABLE Qt::ItemFlags flags(const QModelIndex &index) const
Returns the item flags for the given index.
virtual Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const =0
Returns the index of the item in the model specified by the given row, column and parent index.
const QEditorInfo & editorForIndex(const QModelIndex &index) const
QAbstractItemView::EditTriggers editTriggers
QPersistentModelIndex currentSelectionStartIndex
QPointer< QItemSelectionModel > selectionModel
QItemSelectionModel::SelectionFlag ctrlDragSelectionFlag
QPersistentModelIndex root
QWidget * editor(const QModelIndex &index, const QStyleOptionViewItem &options)
virtual void selectAll(QItemSelectionModel::SelectionFlags command)
QPersistentModelIndex hover
The QAbstractItemView class provides the basic functionality for item view classes.
QAbstractItemModel * model() const
Returns the model that this view is presenting.
virtual void setSelectionModel(QItemSelectionModel *selectionModel)
Sets the current selection model to the given selectionModel.
void timerEvent(QTimerEvent *event) override
This function is called with the given event when a timer event is sent to the widget.
ScrollMode verticalScrollMode
how the view scrolls its contents in the vertical direction
virtual void verticalScrollbarAction(int action)
virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
This slot is called when the selection is changed.
State state() const
Returns the item view's state.
QModelIndex currentIndex() const
Returns the model index of the current item.
virtual void setModel(QAbstractItemModel *model)
Sets the model for the view to present.
ScrollMode horizontalScrollMode
how the view scrolls its contents in the horizontal direction
virtual void setRootIndex(const QModelIndex &index)
Sets the root item to the item at the given index.
virtual void initViewItemOption(QStyleOptionViewItem *option) const
virtual void doItemsLayout()
void update(const QModelIndex &index)
CursorAction
This enum describes the different ways to navigate between items,.
virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous)
This slot is called when a new item becomes the current item.
ScrollHint
\value EnsureVisible Scroll to ensure that the item is visible.
virtual void rowsInserted(const QModelIndex &parent, int start, int end)
This slot is called when rows are inserted.
virtual void updateEditorGeometries()
QItemSelectionModel * selectionModel() const
Returns the current selection model.
virtual void updateGeometries()
virtual void horizontalScrollbarAction(int action)
\inmodule QtCore
Definition qbitarray.h:13
bool testBit(qsizetype i) const
Returns true if the bit at index position i is 1; otherwise returns false.
Definition qbitarray.h:84
void setBit(qsizetype i)
Sets the bit at index position i to 1.
Definition qbitarray.h:88
qsizetype size() const
Returns the number of bits stored in the bit array.
Definition qbitarray.h:31
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
static QColor fromRgba(QRgb rgba) noexcept
Static convenience function that returns a QColor constructed from the given QRgb value rgba.
Definition qcolor.cpp:2385
\inmodule QtCore
The QHeaderView class provides a header row or header column for item views.
Definition qheaderview.h:18
void setSortIndicatorShown(bool show)
void setHighlightSections(bool highlight)
bool sectionsHidden() const
void setSectionsClickable(bool clickable)
int sectionViewportPosition(int logicalIndex) const
Returns the section viewport position of the given logicalIndex.
bool isSectionHidden(int logicalIndex) const
Returns true if the section specified by logicalIndex is explicitly hidden from the user; otherwise r...
int sectionSize(int logicalIndex) const
Returns the width (or height for vertical headers) of the given logicalIndex.
bool sectionsMoved() const
Returns true if sections in the header has been moved; otherwise returns false;.
int logicalIndexAt(int position) const
Returns the section that covers the given position in the viewport.
int logicalIndex(int visualIndex) const
Returns the logicalIndex for the section at the given visualIndex position, or -1 if visualIndex < 0 ...
int length() const
Returns the length along the orientation of the header.
int visualIndexAt(int position) const
Returns the visual index of the section that covers the given position in the viewport.
int visualIndex(int logicalIndex) const
Returns the visual index position of the section specified by the given logicalIndex,...
int offset() const
Returns the offset of the header: this is the header's left-most (or top-most for vertical headers) v...
int count() const
Returns the number of sections in the header.
Q_INVOKABLE QModelIndexList selectedRows(int column=0) const
Q_INVOKABLE bool isSelected(const QModelIndex &index) const
Returns true if the given model item index is selected.
virtual void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
Sets the model item index to be the current item, and emits currentChanged().
virtual void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
Selects the model item index using the specified command, and emits selectionChanged().
Q_INVOKABLE QModelIndexList selectedColumns(int row=0) const
\inmodule QtCore
Q_CORE_EXPORT QModelIndexList indexes() const
Returns a list of model indexes that correspond to the selected items.
\inmodule QtCore
Definition qline.h:182
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
T value(qsizetype i) const
Definition qlist.h:661
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
const Key & key() const
Definition qmap.h:512
Definition qmap.h:186
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:356
iterator erase(const_iterator it)
Definition qmap.h:618
void clear()
Definition qmap.h:288
bool isEmpty() const
Definition qmap.h:268
iterator begin()
Definition qmap.h:597
iterator end()
Definition qmap.h:601
\inmodule QtCore
constexpr int row() const noexcept
Returns the row this model index refers to.
constexpr int column() const noexcept
Returns the column this model index refers to.
constexpr bool isValid() const noexcept
Returns {true} if this model index is valid; otherwise returns {false}.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
The QPaintEvent class contains event parameters for paint events.
Definition qevent.h:485
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
const QPen & pen() const
Returns the painter's current pen.
void setPen(const QColor &color)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void drawLine(const QLineF &line)
Draws a line defined by line.
Definition qpainter.h:442
void setClipRegion(const QRegion &, Qt::ClipOperation op=Qt::ReplaceClip)
Sets the clip region to the given region using the specified clip operation.
void setCurrentColorGroup(ColorGroup cg)
Set the palette's current color group to cg.
Definition qpalette.h:64
ColorGroup
\value Disabled \value Active \value Inactive \value Normal synonym for Active
Definition qpalette.h:48
@ Disabled
Definition qpalette.h:48
\inmodule QtGui
Definition qpen.h:25
int column() const
Returns the column this persistent model index refers to.
int row() const
Returns the row this persistent model index refers to.
\inmodule QtCore\reentrant
Definition qpoint.h:23
T * data() const
Definition qpointer.h:56
\inmodule QtCore\reentrant
Definition qrect.h:30
bool intersects(const QRect &r) const noexcept
Returns true if this rectangle intersects with the given rectangle (i.e., there is at least one pixel...
Definition qrect.cpp:1065
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition qrect.h:163
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:175
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:172
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:178
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRegion translated(int dx, int dy) const
Definition qregion.cpp:593
Definition qset.h:18
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
iterator find(const T &value)
Definition qset.h:159
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
void addSpan(Span *span)
std::list< Span * > SpanList
QSet< Span * > spansInRect(int x, int y, int w, int h) const
void updateRemovedColumns(int start, int end)
void updateInsertedColumns(int start, int end)
void updateSpan(Span *span, int old_height)
Span * spanAt(int x, int y) const
void updateRemovedRows(int start, int end)
void updateInsertedRows(int start, int end)
QString right(qsizetype n) const
Returns a substring that contains the n rightmost characters of the string.
Definition qstring.cpp:5180
qsizetype count(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4732
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
ButtonFeatures features
The QStyleOptionHeader class is used to describe the parameters for drawing a header.
QStyle::State state
QPalette palette
void initFrom(const QWidget *w)
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
@ State_MouseOver
Definition qstyle.h:80
@ State_Sunken
Definition qstyle.h:69
@ State_HasFocus
Definition qstyle.h:75
@ State_Active
Definition qstyle.h:83
@ State_Enabled
Definition qstyle.h:67
@ State_Selected
Definition qstyle.h:82
@ State_None
Definition qstyle.h:66
@ SH_Table_GridLineColor
Definition qstyle.h:617
@ SH_Table_AlwaysDrawLeftTopGridLines
Definition qstyle.h:703
@ CE_Header
Definition qstyle.h:202
@ PE_PanelItemViewRow
Definition qstyle.h:154
virtual void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const =0
Draws the given element with the provided painter with the style options specified by option.
QRect visualSpanRect(const QSpanCollection::Span &span) const
QSpanCollection spans
int logicalColumn(int visualCol) const
bool hasSpans() const
void drawAndClipSpans(const QRegion &area, QPainter *painter, const QStyleOptionViewItem &option, QBitArray *drawn, int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn)
QHeaderView * horizontalHeader
bool isRowHidden(int row) const
bool isCellEnabled(int row, int column) const
void _q_selectColumn(int column)
bool isColumnHidden(int column) const
int sectionSpanSize(const QHeaderView *header, int logical, int span) const
int nextActiveVisualColumn(int row, int columnToStart, int limit, SearchDirection searchDirection) const
int columnSpan(int row, int column) const
void _q_updateSpanInsertedRows(const QModelIndex &parent, int start, int end)
void selectColumn(int column, bool anchor)
void trimHiddenSelections(QItemSelectionRange *range) const
void _q_updateSpanInsertedColumns(const QModelIndex &parent, int start, int end)
int logicalRow(int visualRow) const
QSpanCollection::Span span(int row, int column) const
void drawCell(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index)
int visualRow(int logicalRow) const
int widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option) const
QHeaderView * verticalHeader
bool spanContainsSection(const QHeaderView *header, int logical, int spanLogical, int span) const
int heightHintForIndex(const QModelIndex &index, int hint, QStyleOptionViewItem &option) const
int rowSpanHeight(int row, int span) const
int nextActiveVisualRow(int rowToStart, int column, int limit, SearchDirection searchDirection) const
void setSpan(int row, int column, int rowSpan, int columnSpan)
int columnSpanWidth(int column, int span) const
void _q_updateSpanRemovedRows(const QModelIndex &parent, int start, int end)
int sectionSpanEndLogical(const QHeaderView *header, int logical, int span) const
void _q_updateSpanRemovedColumns(const QModelIndex &parent, int start, int end)
void selectRow(int row, bool anchor)
int rowSpan(int row, int column) const
QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const override
int visualColumn(int logicalCol) const
void _q_sortIndicatorChanged(int column, Qt::SortOrder order)
void _q_selectRow(int row)
The QTableView class provides a default model/view implementation of a table view.
Definition qtableview.h:18
void setModel(QAbstractItemModel *model) override
\reimp
int rowAt(int y) const
Returns the row in which the given y-coordinate, y, in contents coordinates is located.
bool isColumnHidden(int column) const
Returns true if the given column is hidden; otherwise returns false.
void setHorizontalHeader(QHeaderView *header)
Sets the widget to use for the horizontal header to header.
QTableView(QWidget *parent=nullptr)
Constructs a table view with a parent to represent the data.
int rowSpan(int row, int column) const
void scrollTo(const QModelIndex &index, ScrollHint hint=EnsureVisible) override
\reimp
void columnCountChanged(int oldCount, int newCount)
This slot is called whenever columns are added or deleted.
void setSortingEnabled(bool enable)
If enable is true, enables sorting for the table and immediately trigger a call to sortByColumn() wit...
bool showGrid
whether the grid is shown
Definition qtableview.h:20
void columnResized(int column, int oldWidth, int newWidth)
This slot is called to change the width of the given column.
void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) override
Selects the items within the given rect and in accordance with the specified selection flags.
int columnViewportPosition(int column) const
Returns the x-coordinate in contents coordinates of the given column.
void setVerticalHeader(QHeaderView *header)
Sets the widget to use for the vertical header to header.
QRect visualRect(const QModelIndex &index) const override
\reimp
void sortByColumn(int column, Qt::SortOrder order)
QModelIndex indexAt(const QPoint &p) const override
Returns the index position of the model item corresponding to the table item at position pos in conte...
void resizeColumnsToContents()
Resizes all columns based on the size hints of the delegate used to render each item in the columns.
void initViewItemOption(QStyleOptionViewItem *option) const override
\reimp
int columnWidth(int column) const
Returns the width of the given column.
void setColumnHidden(int column, bool hide)
If hide is true the given column will be hidden; otherwise it will be shown.
int rowHeight(int row) const
Returns the height of the given row.
void setRowHidden(int row, bool hide)
If hide is true row will be hidden, otherwise it will be shown.
void columnMoved(int column, int oldIndex, int newIndex)
This slot is called to change the index of the given column in the table view.
int sizeHintForColumn(int column) const override
Returns the size hint for the given column's width or -1 if there is no model.
bool isRowHidden(int row) const
Returns true if the given row is hidden; otherwise returns false.
void showRow(int row)
Show the given row.
void rowMoved(int row, int oldIndex, int newIndex)
This slot is called to change the index of the given row in the table view.
void scrollContentsBy(int dx, int dy) override
\reimp
void setWordWrap(bool on)
void paintEvent(QPaintEvent *e) override
Paints the table on receipt of the given paint event event.
bool isSortingEnabled() const
Qt::PenStyle gridStyle
the pen style used to draw the grid.
Definition qtableview.h:21
QSize viewportSizeHint() const override
\reimp
void setColumnWidth(int column, int width)
void setShowGrid(bool show)
void selectColumn(int column)
Selects the given column in the table view if the current SelectionMode and SelectionBehavior allows ...
int sizeHintForRow(int row) const override
Returns the size hint for the given row's height or -1 if there is no model.
void selectRow(int row)
Selects the given row in the table view if the current SelectionMode and SelectionBehavior allows row...
void clearSpans()
void hideRow(int row)
Hide the given row.
QRegion visualRegionForSelection(const QItemSelection &selection) const override
\reimp
void updateGeometries() override
\reimp
QHeaderView * horizontalHeader() const
Returns the table view's horizontal header.
int verticalOffset() const override
Returns the vertical offset of the items in the table view.
void showColumn(int column)
Show the given column.
QModelIndexList selectedIndexes() const override
\reimp
bool wordWrap
the item text word-wrapping policy
Definition qtableview.h:23
void rowResized(int row, int oldHeight, int newHeight)
This slot is called to change the height of the given row.
void setSelectionModel(QItemSelectionModel *selectionModel) override
\reimp
int columnSpan(int row, int column) const
void resizeColumnToContents(int column)
Resizes the given column based on the size hints of the delegate used to render each item in the colu...
QHeaderView * verticalHeader() const
Returns the table view's vertical header.
void doItemsLayout() override
void timerEvent(QTimerEvent *event) override
\reimp
~QTableView()
Destroys the table view.
int columnAt(int x) const
Returns the column in which the given x-coordinate, x, in contents coordinates is located.
int rowViewportPosition(int row) const
Returns the y-coordinate in contents coordinates of the given row.
void setSpan(int row, int column, int rowSpan, int columnSpan)
bool isIndexHidden(const QModelIndex &index) const override
\reimp
void hideColumn(int column)
Hide the given column.
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override
Moves the cursor in accordance with the given cursorAction, using the information provided by the mod...
void rowCountChanged(int oldCount, int newCount)
This slot is called whenever rows are added or deleted.
void resizeRowToContents(int row)
Resizes the given row based on the size hints of the delegate used to render each item in the row.
void setGridStyle(Qt::PenStyle style)
void setRowHeight(int row, int height)
void resizeRowsToContents()
Resizes all rows based on the size hints of the delegate used to render each item in the rows.
int horizontalOffset() const override
Returns the horizontal offset of the items in the table view.
\inmodule QtCore
Definition qcoreevent.h:359
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QSize minimumSize
the widget's minimum size
Definition qwidget.h:120
QSize maximumSize
the widget's maximum size in pixels
Definition qwidget.h:121
QRect rect
the internal geometry of the widget excluding any window frame
Definition qwidget.h:116
bool isEnabled() const
Definition qwidget.h:814
QSize sizeHint
the recommended size for the widget
Definition qwidget.h:148
QStyle * style() const
Definition qwidget.cpp:2607
bool isActiveWindow
whether this widget's window is the active window
Definition qwidget.h:139
EGLImageKHR int int EGLuint64KHR * modifiers
QString str
[2]
bool focus
[0]
qSwap(pi, e)
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
rect
[4]
QStyleOptionButton opt
else opt state
[0]
Combined button and popup list for selecting options.
@ NoFocus
Definition qnamespace.h:106
@ Horizontal
Definition qnamespace.h:98
@ Vertical
Definition qnamespace.h:99
SortOrder
Definition qnamespace.h:120
@ ControlModifier
@ UniqueConnection
@ ItemIsEnabled
QTextStream & endl(QTextStream &stream)
Writes '\n' to the stream and flushes the stream.
#define Q_UNLIKELY(x)
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static int area(const QSize &s)
Definition qicon.cpp:152
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble right
GLsizei range
GLint GLsizei width
GLint left
GLint GLint bottom
GLboolean enable
GLuint start
GLenum GLuint GLintptr offset
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLenum GLenum GLsizei void GLsizei void * column
struct _cl_event * event
const GLubyte * c
GLuint entry
GLint limit
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLenum GLenum GLsizei void GLsizei void void * span
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLuint GLenum option
GLfixed GLfixed GLint GLint order
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:13
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
#define sp
#define Q_OBJECT
#define Q_UNUSED(x)
QSqlQueryModel * model
[16]
view show()
[18] //! [19]
QList< int > list
[14]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QDataStream & operator<<(QDataStream &out, const MyClass &myObj)
[4]
myObject disconnect()
[26]
view viewport() -> scroll(dx, dy, deviceRect)
edit hide()
edit isVisible()
QItemSelection * selection
[0]
QPainter painter(this)
[7]
QPointer< QWidget > widget
bool contains(const AT &t) const noexcept
Definition qlist.h:44
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent