1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QIdentityProxyModel>
30#include <QLabel>
31#include <QLineEdit>
32#include <QScrollBar>
33#include <QSignalSpy>
34#include <QSortFilterProxyModel>
35#include <QStandardItemModel>
36#include <QStringListModel>
37#include <QStyledItemDelegate>
38#include <QTableView>
39#include <QTest>
40#include <private/qapplication_p.h>
41#include <private/qtablewidget_p.h>
42#include <private/qtesthelpers_p.h>
43#if QT_CONFIG(textmarkdownwriter)
44#include <private/qtextmarkdownwriter_p.h>
45#endif
46
47
48using namespace QTestPrivate;
49
50#ifdef QT_BUILD_INTERNAL
51#define VERIFY_SPANS_CONSISTENCY(TEST_VIEW_) \
52 QVERIFY(static_cast<QTableViewPrivate*>(QObjectPrivate::get(TEST_VIEW_))->spans.checkConsistency())
53#else
54#define VERIFY_SPANS_CONSISTENCY(TEST_VIEW_) (void)false
55#endif
56
57Q_DECLARE_METATYPE(Qt::Key);
58Q_DECLARE_METATYPE(Qt::KeyboardModifier);
59Q_DECLARE_METATYPE(QItemSelectionModel::SelectionFlag);
60using BoolList = QVector<bool>;
61using IntList = QVector<int>;
62using KeyList = QVector<Qt::Key>;
63using SpanList = QVector<QRect>;
64
65class QtTestTableModel: public QAbstractTableModel
66{
67 Q_OBJECT
68
69signals:
70 void invalidIndexEncountered() const;
71
72public slots:
73 bool submit() override { ++submit_count; return QAbstractTableModel::submit(); }
74
75public:
76 QtTestTableModel(int rows = 0, int columns = 0, QObject *parent = nullptr)
77 : QAbstractTableModel(parent), row_count(rows), column_count(columns)
78 {}
79
80 int rowCount(const QModelIndex& = QModelIndex()) const override
81 {
82 return row_count;
83 }
84
85 int columnCount(const QModelIndex& = QModelIndex()) const override
86 {
87 return column_count;
88 }
89
90 bool isEditable(const QModelIndex &) const { return true; }
91
92 Qt::ItemFlags flags(const QModelIndex &index) const override
93 {
94 Qt::ItemFlags index_flags = QAbstractTableModel::flags(index);
95 if (disabled_rows.contains(value: index.row())
96 || disabled_columns.contains(value: index.column()))
97 index_flags &= ~Qt::ItemIsEnabled;
98 return index_flags;
99 }
100
101 void disableRow(int row)
102 {
103 disabled_rows.insert(value: row);
104 }
105
106 void enableRow(int row)
107 {
108 disabled_rows.remove(value: row);
109 }
110
111 void disableColumn(int column)
112 {
113 disabled_columns.insert(value: column);
114 }
115
116 void enableColumn(int column)
117 {
118 disabled_columns.remove(value: column);
119 }
120
121 QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override
122 {
123 if (!idx.isValid() || idx.row() >= row_count || idx.column() >= column_count) {
124 qWarning() << "Invalid modelIndex [%d,%d,%p]" << idx;
125 emit invalidIndexEncountered();
126 return QVariant();
127 }
128
129 if (role == Qt::DisplayRole || role == Qt::EditRole) {
130 return QLatin1Char('[') + QString::number(idx.row()) + QLatin1Char(',')
131 + QString::number(idx.column()) + QLatin1String(",0]");
132 }
133
134 return QVariant();
135 }
136
137 bool insertRows(int start, int count, const QModelIndex &parent = QModelIndex()) override
138 {
139 if (start < 0 || start > row_count)
140 return false;
141
142 beginInsertRows(parent, first: start, last: start + count - 1);
143 row_count += count;
144 endInsertRows();
145 return true;
146 }
147
148 bool removeRows(int start, int count, const QModelIndex &parent = QModelIndex()) override
149 {
150 if (start < 0 || start >= row_count || row_count < count)
151 return false;
152
153 beginRemoveRows(parent, first: start, last: start + count - 1);
154 row_count -= count;
155 endRemoveRows();
156 return true;
157 }
158
159 void removeLastRow()
160 {
161 beginRemoveRows(parent: QModelIndex(), first: row_count - 1, last: row_count - 1);
162 --row_count;
163 endRemoveRows();
164 }
165
166 void removeAllRows()
167 {
168 beginRemoveRows(parent: QModelIndex(), first: 0, last: row_count - 1);
169 row_count = 0;
170 endRemoveRows();
171 }
172
173 bool insertColumns(int start, int count, const QModelIndex &parent = QModelIndex()) override
174 {
175 if (start < 0 || start > column_count)
176 return false;
177
178 beginInsertColumns(parent, first: start, last: start + count - 1);
179 column_count += count;
180 endInsertColumns();
181 return true;
182 }
183
184 bool removeColumns(int start, int count, const QModelIndex &parent = QModelIndex()) override
185 {
186 if (start < 0 || start >= column_count || column_count < count)
187 return false;
188
189 beginRemoveColumns(parent, first: start, last: start + count - 1);
190 column_count -= count;
191 endRemoveColumns();
192 return true;
193 }
194
195 void removeLastColumn()
196 {
197 beginRemoveColumns(parent: QModelIndex(), first: column_count - 1, last: column_count - 1);
198 --column_count;
199 endRemoveColumns();
200 }
201
202 void removeAllColumns()
203 {
204 beginRemoveColumns(parent: QModelIndex(), first: 0, last: column_count - 1);
205 column_count = 0;
206 endRemoveColumns();
207 }
208
209 bool canFetchMore(const QModelIndex &) const override
210 {
211 return can_fetch_more;
212 }
213
214 void fetchMore(const QModelIndex &) override
215 {
216 ++fetch_more_count;
217 }
218
219 QSet<int> disabled_rows;
220 QSet<int> disabled_columns;
221 int row_count;
222 int column_count;
223 int submit_count = 0;
224 int fetch_more_count = 0;
225 bool can_fetch_more = false;
226};
227
228class QtTestTableView : public QTableView
229{
230 Q_OBJECT
231public:
232 using QTableView::QTableView;
233
234 void setModel(QAbstractItemModel *model) override
235 {
236 QTableView::setModel(model);
237 connect(sender: selectionModel(), signal: &QItemSelectionModel::currentChanged,
238 receiver: this, slot: &QtTestTableView::slotCurrentChanged);
239 connect(sender: selectionModel(), signal: &QItemSelectionModel::selectionChanged,
240 receiver: this, slot: &QtTestTableView::itemSelectionChanged);
241 // Allow small sections in this test, since this test was made before we correctly enforced minimum sizes.
242 horizontalHeader()->setMinimumSectionSize(0);
243 verticalHeader()->setMinimumSectionSize(0);
244 }
245
246 using QTableView::moveCursor;
247 using QTableView::isIndexHidden;
248 using QTableView::setSelection;
249 using QTableView::selectedIndexes;
250 using QTableView::sizeHintForRow;
251 using QTableView::viewOptions;
252
253 bool checkSignalOrder = false;
254public slots:
255 void slotCurrentChanged(QModelIndex, QModelIndex) {
256 hasCurrentChanged++;
257 if (checkSignalOrder)
258 QVERIFY(hasCurrentChanged > hasSelectionChanged);
259 }
260
261 void itemSelectionChanged(QItemSelection , QItemSelection ) {
262 hasSelectionChanged++;
263 if (checkSignalOrder)
264 QVERIFY(hasCurrentChanged >= hasSelectionChanged);
265 }
266private:
267 int hasCurrentChanged = 0;
268 int hasSelectionChanged = 0;
269
270 friend class tst_QTableView;
271 friend struct QMetaTypeId<QtTestTableView::CursorAction>;
272};
273Q_DECLARE_METATYPE(QtTestTableView::CursorAction);
274
275class QtTestItemDelegate : public QStyledItemDelegate
276{
277public:
278 QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override
279 {
280 return hint;
281 }
282
283 QSize hint;
284};
285
286class tst_QTableView : public QObject
287{
288 Q_OBJECT
289
290private:
291 using CursorActionList = QVector<QtTestTableView::CursorAction>;
292private slots:
293 void getSetCheck();
294
295 void noDelegate();
296 void noModel();
297 void emptyModel();
298
299 void removeRows_data();
300 void removeRows();
301
302 void removeColumns_data();
303 void removeColumns();
304
305 void keyboardNavigation_data();
306 void keyboardNavigation();
307
308 void headerSections_data();
309 void headerSections();
310
311 void moveCursor_data();
312 void moveCursor();
313
314 void moveCursorStrikesBack_data();
315 void moveCursorStrikesBack();
316
317 void moveCursorBiggerJump();
318
319 void hideRows_data();
320 void hideRows();
321
322 void hideColumns_data();
323 void hideColumns();
324
325 void selection_data();
326 void selection();
327
328 void selectRow_data();
329 void selectRow();
330
331 void selectColumn_data();
332 void selectColumn();
333
334 void selectall_data();
335 void selectall();
336
337 void visualRect_data();
338 void visualRect();
339
340 void fetchMore();
341 void setHeaders();
342
343 void resizeRowsToContents_data();
344 void resizeRowsToContents();
345
346 void resizeColumnsToContents_data();
347 void resizeColumnsToContents();
348
349 void rowViewportPosition_data();
350 void rowViewportPosition();
351
352 void rowAt_data();
353 void rowAt();
354
355 void rowHeight_data();
356 void rowHeight();
357
358 void columnViewportPosition_data();
359 void columnViewportPosition();
360
361 void columnAt_data();
362 void columnAt();
363
364 void columnWidth_data();
365 void columnWidth();
366
367 void hiddenRow_data();
368 void hiddenRow();
369
370 void hiddenColumn_data();
371 void hiddenColumn();
372
373 void sortingEnabled_data();
374 void sortingEnabled();
375
376 void sortByColumn_data();
377 void sortByColumn();
378
379 void scrollTo_data();
380 void scrollTo();
381
382 void indexAt_data();
383 void indexAt();
384
385 void span_data();
386 void span();
387 void spans();
388 void spans_data();
389 void spansAfterRowInsertion();
390 void spansAfterColumnInsertion();
391 void spansAfterRowRemoval();
392 void spansAfterColumnRemoval();
393 void editSpanFromDirections_data();
394 void editSpanFromDirections();
395
396 void checkHeaderReset();
397 void checkHeaderMinSize();
398
399 void resizeToContents();
400
401 void tabFocus();
402 void bigModel();
403 void selectionSignal();
404 void setCurrentIndex();
405
406 // task-specific tests:
407 void task173773_updateVerticalHeader();
408 void task227953_setRootIndex();
409 void task240266_veryBigColumn();
410 void task248688_autoScrollNavigation();
411 void task259308_scrollVerticalHeaderSwappedSections();
412 void task191545_dragSelectRows();
413 void taskQTBUG_5062_spansInconsistency();
414 void taskQTBUG_4516_clickOnRichTextLabel();
415#if QT_CONFIG(wheelevent)
416 void taskQTBUG_5237_wheelEventOnHeader();
417#endif
418 void taskQTBUG_8585_crashForNoGoodReason();
419 void taskQTBUG_7774_RtoLVisualRegionForSelection();
420 void taskQTBUG_8777_scrollToSpans();
421 void taskQTBUG_10169_sizeHintForRow();
422 void taskQTBUG_30653_doItemsLayout();
423 void taskQTBUG_50171_selectRowAfterSwapColumns();
424 void deselectRow();
425
426#if QT_CONFIG(wheelevent)
427 void mouseWheel_data();
428 void mouseWheel();
429#endif
430
431 void addColumnWhileEditing();
432 void task234926_setHeaderSorting();
433
434 void changeHeaderData();
435 void viewOptions();
436
437 void taskQTBUG_7232_AllowUserToControlSingleStep();
438
439#if QT_CONFIG(textmarkdownwriter)
440 void markdownWriter();
441#endif
442};
443
444// Testing get/set functions
445void tst_QTableView::getSetCheck()
446{
447 QTableView obj1;
448
449 obj1.setSortingEnabled(false);
450 QCOMPARE(false, obj1.isSortingEnabled());
451 obj1.setSortingEnabled(true);
452 QCOMPARE(true, obj1.isSortingEnabled());
453
454 obj1.setShowGrid(false);
455 QCOMPARE(false, obj1.showGrid());
456 obj1.setShowGrid(true);
457 QCOMPARE(true, obj1.showGrid());
458
459 obj1.setGridStyle(Qt::NoPen);
460 QCOMPARE(Qt::NoPen, obj1.gridStyle());
461 obj1.setGridStyle(Qt::SolidLine);
462 QCOMPARE(Qt::SolidLine, obj1.gridStyle());
463
464 obj1.setRootIndex(QModelIndex());
465 QCOMPARE(QModelIndex(), obj1.rootIndex());
466 QStandardItemModel model(10, 10);
467 obj1.setModel(&model);
468 QModelIndex index = model.index(row: 0, column: 0);
469 obj1.setRootIndex(index);
470 QCOMPARE(index, obj1.rootIndex());
471
472 QHeaderView *var1 = new QHeaderView(Qt::Horizontal);
473 obj1.setHorizontalHeader(var1);
474 QCOMPARE(var1, obj1.horizontalHeader());
475 obj1.setHorizontalHeader(nullptr);
476 QCOMPARE(var1, obj1.horizontalHeader());
477 delete var1;
478
479 QHeaderView *var2 = new QHeaderView(Qt::Vertical);
480 obj1.setVerticalHeader(var2);
481 QCOMPARE(var2, obj1.verticalHeader());
482 obj1.setVerticalHeader(nullptr);
483 QCOMPARE(var2, obj1.verticalHeader());
484 delete var2;
485
486 QCOMPARE(obj1.isCornerButtonEnabled(), true);
487 obj1.setCornerButtonEnabled(false);
488 QCOMPARE(obj1.isCornerButtonEnabled(), false);
489}
490void tst_QTableView::noDelegate()
491{
492 QtTestTableModel model(3, 3);
493 QTableView view;
494 view.setModel(&model);
495 view.setItemDelegate(nullptr);
496 view.show();
497}
498
499void tst_QTableView::noModel()
500{
501 QTableView view;
502 view.show();
503}
504
505void tst_QTableView::emptyModel()
506{
507 QtTestTableModel model;
508 QTableView view;
509 QSignalSpy spy(&model, &QtTestTableModel::invalidIndexEncountered);
510 view.setModel(&model);
511 view.show();
512 QCOMPARE(spy.count(), 0);
513}
514
515void tst_QTableView::removeRows_data()
516{
517 QTest::addColumn<int>(name: "rowCount");
518 QTest::addColumn<int>(name: "columnCount");
519
520 QTest::newRow(dataTag: "2x2") << 2 << 2;
521 QTest::newRow(dataTag: "10x10") << 10 << 10;
522}
523
524void tst_QTableView::removeRows()
525{
526 QFETCH(int, rowCount);
527 QFETCH(int, columnCount);
528
529 QtTestTableModel model(rowCount, columnCount);
530 QSignalSpy spy(&model, &QtTestTableModel::invalidIndexEncountered);
531
532 QTableView view;
533 view.setModel(&model);
534 view.show();
535
536 model.removeLastRow();
537 QCOMPARE(spy.count(), 0);
538
539 model.removeAllRows();
540 QCOMPARE(spy.count(), 0);
541}
542
543void tst_QTableView::removeColumns_data()
544{
545 QTest::addColumn<int>(name: "rowCount");
546 QTest::addColumn<int>(name: "columnCount");
547
548 QTest::newRow(dataTag: "2x2") << 2 << 2;
549 QTest::newRow(dataTag: "10x10") << 10 << 10;
550}
551
552void tst_QTableView::removeColumns()
553{
554 QFETCH(int, rowCount);
555 QFETCH(int, columnCount);
556
557 QtTestTableModel model(rowCount, columnCount);
558 QSignalSpy spy(&model, &QtTestTableModel::invalidIndexEncountered);
559
560 QTableView view;
561 view.setModel(&model);
562 view.show();
563
564 model.removeLastColumn();
565 QCOMPARE(spy.count(), 0);
566
567 model.removeAllColumns();
568 QCOMPARE(spy.count(), 0);
569}
570
571void tst_QTableView::keyboardNavigation_data()
572{
573 QTest::addColumn<int>(name: "rowCount");
574 QTest::addColumn<int>(name: "columnCount");
575 QTest::addColumn<bool>(name: "tabKeyNavigation");
576 QTest::addColumn<KeyList>(name: "keyPresses");
577
578 const KeyList keyList {
579 Qt::Key_Up, Qt::Key_Up, Qt::Key_Right, Qt::Key_Right,
580 Qt::Key_Up, Qt::Key_Left, Qt::Key_Left, Qt::Key_Up,
581 Qt::Key_Down, Qt::Key_Up, Qt::Key_Up, Qt::Key_Up,
582 Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, Qt::Key_Left,
583 Qt::Key_Left, Qt::Key_Up, Qt::Key_Down, Qt::Key_Down,
584 Qt::Key_Tab, Qt::Key_Backtab};
585
586 QTest::newRow(dataTag: "16x16 model") << 16 << 16 << true << keyList;
587 QTest::newRow(dataTag: "no tab") << 8 << 8 << false << keyList;
588}
589
590void tst_QTableView::keyboardNavigation()
591{
592 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
593 QSKIP("Wayland: This fails. Figure out why.");
594
595 QFETCH(int, rowCount);
596 QFETCH(int, columnCount);
597 QFETCH(bool, tabKeyNavigation);
598 QFETCH(const KeyList, keyPresses);
599
600 QtTestTableModel model(rowCount, columnCount);
601 QTableView view;
602 view.setModel(&model);
603
604 view.setTabKeyNavigation(tabKeyNavigation);
605 QModelIndex index = model.index(row: rowCount - 1, column: columnCount - 1);
606 view.setCurrentIndex(index);
607
608 view.show();
609 QApplication::setActiveWindow(&view);
610 QVERIFY(QTest::qWaitForWindowActive(&view));
611
612 int row = rowCount - 1;
613 int column = columnCount - 1;
614 for (Qt::Key key : keyPresses) {
615
616 switch (key) {
617 case Qt::Key_Up:
618 row = qMax(a: 0, b: row - 1);
619 break;
620 case Qt::Key_Down:
621 row = qMin(a: rowCount - 1, b: row + 1);
622 break;
623 case Qt::Key_Backtab:
624 if (!tabKeyNavigation)
625 break;
626 Q_FALLTHROUGH();
627 case Qt::Key_Left:
628 column = qMax(a: 0, b: column - 1);
629 break;
630 case Qt::Key_Tab:
631 if (!tabKeyNavigation)
632 break;
633 Q_FALLTHROUGH();
634 case Qt::Key_Right:
635 column = qMin(a: columnCount - 1, b: column + 1);
636 break;
637 default:
638 break;
639 }
640
641 QTest::keyClick(widget: &view, key);
642 QApplication::processEvents();
643
644 QModelIndex index = model.index(row, column);
645 QCOMPARE(view.currentIndex(), index);
646 }
647}
648
649void tst_QTableView::headerSections_data()
650{
651 QTest::addColumn<int>(name: "rowCount");
652 QTest::addColumn<int>(name: "columnCount");
653 QTest::addColumn<int>(name: "row");
654 QTest::addColumn<int>(name: "column");
655 QTest::addColumn<int>(name: "rowHeight");
656 QTest::addColumn<int>(name: "columnWidth");
657
658 QTest::newRow(dataTag: "") << 10 << 10 << 5 << 5 << 30 << 30;
659}
660
661void tst_QTableView::headerSections()
662{
663 QFETCH(int, rowCount);
664 QFETCH(int, columnCount);
665 QFETCH(int, row);
666 QFETCH(int, column);
667 QFETCH(int, rowHeight);
668 QFETCH(int, columnWidth);
669
670 QtTestTableModel model(rowCount, columnCount);
671
672 QTableView view;
673 QHeaderView *hheader = view.horizontalHeader();
674 QHeaderView *vheader = view.verticalHeader();
675
676 view.setModel(&model);
677 hheader->setMinimumSectionSize(columnWidth);
678 vheader->setMinimumSectionSize(rowHeight);
679 view.show();
680
681 hheader->doItemsLayout();
682 vheader->doItemsLayout();
683
684 QCOMPARE(hheader->count(), model.columnCount());
685 QCOMPARE(vheader->count(), model.rowCount());
686
687 view.setRowHeight(row, height: rowHeight);
688 QCOMPARE(view.rowHeight(row), rowHeight);
689 view.hideRow(row);
690 QCOMPARE(view.rowHeight(row), 0);
691 view.showRow(row);
692 QCOMPARE(view.rowHeight(row), rowHeight);
693
694 view.setColumnWidth(column, width: columnWidth);
695 QCOMPARE(view.columnWidth(column), columnWidth);
696 view.hideColumn(column);
697 QCOMPARE(view.columnWidth(column), 0);
698 view.showColumn(column);
699 QCOMPARE(view.columnWidth(column), columnWidth);
700}
701
702typedef QPair<int,int> IntPair;
703
704void tst_QTableView::moveCursor_data()
705{
706 QTest::addColumn<int>(name: "rowCount");
707 QTest::addColumn<int>(name: "columnCount");
708 QTest::addColumn<int>(name: "hideRow");
709 QTest::addColumn<int>(name: "hideColumn");
710
711 QTest::addColumn<int>(name: "startRow");
712 QTest::addColumn<int>(name: "startColumn");
713
714 QTest::addColumn<QtTestTableView::CursorAction>(name: "cursorMoveAction");
715 QTest::addColumn<Qt::KeyboardModifier>(name: "modifier");
716
717 QTest::addColumn<int>(name: "expectedRow");
718 QTest::addColumn<int>(name: "expectedColumn");
719 QTest::addColumn<IntPair>(name: "moveRow");
720 QTest::addColumn<IntPair>(name: "moveColumn");
721
722 // MoveRight
723 QTest::newRow(dataTag: "MoveRight (0,0)")
724 << 4 << 4 << -1 << -1
725 << 0 << 0
726 << QtTestTableView::MoveRight << Qt::NoModifier
727 << 0 << 1 << IntPair(0,0) << IntPair(0,0);
728
729 QTest::newRow(dataTag: "MoveRight (3,0)")
730 << 4 << 4 << -1 << -1
731 << 3 << 0
732 << QtTestTableView::MoveRight << Qt::NoModifier
733 << 3 << 1 << IntPair(0,0) << IntPair(0,0);
734
735 QTest::newRow(dataTag: "MoveRight (3,3)")
736 << 4 << 4 << -1 << -1
737 << 3 << 3
738 << QtTestTableView::MoveRight << Qt::NoModifier
739 << 3 << 3 << IntPair(0,0) << IntPair(0,0); // ###
740
741 QTest::newRow(dataTag: "MoveRight, hidden column 1 (0,0)")
742 << 4 << 4 << -1 << 1
743 << 0 << 0
744 << QtTestTableView::MoveRight << Qt::NoModifier
745 << 0 << 2 << IntPair(0,0) << IntPair(0,0);
746
747 QTest::newRow(dataTag: "MoveRight, hidden column 3 (0,2)")
748 << 4 << 4 << -1 << 3
749 << 0 << 2
750 << QtTestTableView::MoveRight << Qt::NoModifier
751 << 0 << 2 << IntPair(0,0) << IntPair(0,0); // ###
752
753 // MoveNext should in addition wrap
754 QTest::newRow(dataTag: "MoveNext (0,0)")
755 << 4 << 4 << -1 << -1
756 << 0 << 0
757 << QtTestTableView::MoveNext << Qt::NoModifier
758 << 0 << 1 << IntPair(0,0) << IntPair(0,0);
759
760 QTest::newRow(dataTag: "MoveNext (0,2)")
761 << 4 << 4 << -1 << -1
762 << 0 << 2
763 << QtTestTableView::MoveNext << Qt::NoModifier
764 << 0 << 3 << IntPair(0,0) << IntPair(0,0);
765
766 QTest::newRow(dataTag: "MoveNext, wrap (0,3)")
767 << 4 << 4 << -1 << -1
768 << 0 << 3
769 << QtTestTableView::MoveNext << Qt::NoModifier
770 << 1 << 0 << IntPair(0,0) << IntPair(0,0);
771
772 QTest::newRow(dataTag: "MoveNext, wrap (3,3)")
773 << 4 << 4 << -1 << -1
774 << 3 << 3
775 << QtTestTableView::MoveNext << Qt::NoModifier
776 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
777
778 QTest::newRow(dataTag: "MoveNext, hidden column 1 (0,0)")
779 << 4 << 4 << -1 << 1
780 << 0 << 0
781 << QtTestTableView::MoveNext << Qt::NoModifier
782 << 0 << 2 << IntPair(0,0) << IntPair(0,0);
783
784 QTest::newRow(dataTag: "MoveNext, wrap, hidden column 3 (0,2)")
785 << 4 << 4 << -1 << 3
786 << 0 << 2
787 << QtTestTableView::MoveNext << Qt::NoModifier
788 << 1 << 0 << IntPair(0,0) << IntPair(0,0);
789
790 QTest::newRow(dataTag: "MoveNext, wrap, hidden column 3 (3,2)")
791 << 4 << 4 << -1 << 3
792 << 3 << 2
793 << QtTestTableView::MoveNext << Qt::NoModifier
794 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
795
796 QTest::newRow(dataTag: "MoveNext, wrapy, wrapx, hidden column 3, hidden row 3 (2,2)")
797 << 4 << 4 << 3 << 3
798 << 2 << 2
799 << QtTestTableView::MoveNext << Qt::NoModifier
800 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
801
802 QTest::newRow(dataTag: "MoveNext, wrap, hidden column 2, moved column from 3 to 0. (0,2)")
803 << 4 << 4 << -1 << 2
804 << 0 << 2
805 << QtTestTableView::MoveNext << Qt::NoModifier
806 << 1 << 3 << IntPair(0,0) << IntPair(3,0);
807
808 // MoveLeft
809 QTest::newRow(dataTag: "MoveLeft (0,0)")
810 << 4 << 4 << -1 << -1
811 << 0 << 0
812 << QtTestTableView::MoveLeft << Qt::NoModifier
813 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
814
815 QTest::newRow(dataTag: "MoveLeft (0,3)")
816 << 4 << 4 << -1 << -1
817 << 0 << 3
818 << QtTestTableView::MoveLeft << Qt::NoModifier
819 << 0 << 2 << IntPair(0,0) << IntPair(0,0);
820
821 QTest::newRow(dataTag: "MoveLeft (1,0)")
822 << 4 << 4 << -1 << -1
823 << 1 << 0
824 << QtTestTableView::MoveLeft << Qt::NoModifier
825 << 1 << 0 << IntPair(0,0) << IntPair(0,0);
826
827 QTest::newRow(dataTag: "MoveLeft, hidden column 0 (0,2)")
828 << 4 << 4 << -1 << 1
829 << 0 << 2
830 << QtTestTableView::MoveLeft << Qt::NoModifier
831 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
832
833 QTest::newRow(dataTag: "MoveLeft, hidden column 0 (0,1)")
834 << 4 << 4 << -1 << 0
835 << 0 << 1
836 << QtTestTableView::MoveLeft << Qt::NoModifier
837 << 0 << 1 << IntPair(0,0) << IntPair(0,0);
838
839 // MovePrevious should in addition wrap
840 QTest::newRow(dataTag: "MovePrevious (0,3)")
841 << 4 << 4 << -1 << -1
842 << 0 << 3
843 << QtTestTableView::MovePrevious << Qt::NoModifier
844 << 0 << 2 << IntPair(0,0) << IntPair(0,0);
845
846 QTest::newRow(dataTag: "MovePrevious (0,1)")
847 << 4 << 4 << -1 << -1
848 << 0 << 1
849 << QtTestTableView::MovePrevious << Qt::NoModifier
850 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
851
852 QTest::newRow(dataTag: "MovePrevious, wrap (1,0)")
853 << 4 << 4 << -1 << -1
854 << 1 << 0
855 << QtTestTableView::MovePrevious << Qt::NoModifier
856 << 0 << 3 << IntPair(0,0) << IntPair(0,0);
857
858 QTest::newRow(dataTag: "MovePrevious, wrap, (0,0)")
859 << 4 << 4 << -1 << -1
860 << 0 << 0
861 << QtTestTableView::MovePrevious << Qt::NoModifier
862 << 3 << 3 << IntPair(0,0) << IntPair(0,0);
863
864 QTest::newRow(dataTag: "MovePrevious, hidden column 1 (0,2)")
865 << 4 << 4 << -1 << 1
866 << 0 << 2
867 << QtTestTableView::MovePrevious << Qt::NoModifier
868 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
869
870 QTest::newRow(dataTag: "MovePrevious, wrap, hidden column 3 (0,2)")
871 << 4 << 4 << -1 << 3
872 << 0 << 2
873 << QtTestTableView::MovePrevious << Qt::NoModifier
874 << 0 << 1 << IntPair(0,0) << IntPair(0,0);
875
876 QTest::newRow(dataTag: "MovePrevious, wrapy, hidden column 0 (0,1)")
877 << 4 << 4 << -1 << 0
878 << 0 << 1
879 << QtTestTableView::MovePrevious << Qt::NoModifier
880 << 3 << 3 << IntPair(0,0) << IntPair(0,0);
881
882 QTest::newRow(dataTag: "MovePrevious, wrap, hidden column 0, hidden row 0 (1,1)")
883 << 4 << 4 << 0 << 0
884 << 1 << 1
885 << QtTestTableView::MovePrevious << Qt::NoModifier
886 << 3 << 3 << IntPair(0,0) << IntPair(0,0);
887
888 QTest::newRow(dataTag: "MovePrevious, wrap, hidden column 1, moved column from 0 to 3. (1,2)")
889 << 4 << 4 << -1 << 1
890 << 1 << 2
891 << QtTestTableView::MovePrevious << Qt::NoModifier
892 << 0 << 0 << IntPair(0,0) << IntPair(0,3);
893
894 // MoveDown
895 QTest::newRow(dataTag: "MoveDown (0,0)")
896 << 4 << 4 << -1 << -1
897 << 0 << 0
898 << QtTestTableView::MoveDown << Qt::NoModifier
899 << 1 << 0 << IntPair(0,0) << IntPair(0,0);
900
901 QTest::newRow(dataTag: "MoveDown (3,0)")
902 << 4 << 4 << -1 << -1
903 << 3 << 0
904 << QtTestTableView::MoveDown << Qt::NoModifier
905 << 3 << 0 << IntPair(0,0) << IntPair(0,0);
906
907 QTest::newRow(dataTag: "MoveDown (3,3)")
908 << 4 << 4 << -1 << -1
909 << 3 << 3
910 << QtTestTableView::MoveDown << Qt::NoModifier
911 << 3 << 3 << IntPair(0,0) << IntPair(0,0);
912
913 QTest::newRow(dataTag: "MoveDown, hidden row 1 (0,0)")
914 << 4 << 4 << 1 << -1
915 << 0 << 0
916 << QtTestTableView::MoveDown << Qt::NoModifier
917 << 2 << 0 << IntPair(0,0) << IntPair(0,0);
918
919 QTest::newRow(dataTag: "MoveDown, hidden row 3 (2,0)")
920 << 4 << 4 << 3 << -1
921 << 2 << 0
922 << QtTestTableView::MoveDown << Qt::NoModifier
923 << 2 << 0 << IntPair(0,0) << IntPair(0,0);
924
925 QTest::newRow(dataTag: "MoveDown, hidden row 0 hidden column 0 (0,0)")
926 << 4 << 4 << 0 << 0
927 << 0 << 0
928 << QtTestTableView::MoveDown << Qt::NoModifier
929 << 1 << 1 << IntPair(0,0) << IntPair(0,0);
930
931 // MoveUp
932 QTest::newRow(dataTag: "MoveUp (0,0)")
933 << 4 << 4 << -1 << -1
934 << 0 << 0
935 << QtTestTableView::MoveUp << Qt::NoModifier
936 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
937
938 QTest::newRow(dataTag: "MoveUp (3, 0)")
939 << 4 << 4 << -1 << -1
940 << 3 << 0
941 << QtTestTableView::MoveUp << Qt::NoModifier
942 << 2 << 0 << IntPair(0,0) << IntPair(0,0);
943
944 QTest::newRow(dataTag: "MoveUp (0,1)")
945 << 4 << 4 << -1 << -1
946 << 0 << 1
947 << QtTestTableView::MoveUp << Qt::NoModifier
948 << 0 << 1 << IntPair(0,0) << IntPair(0,0);
949
950 QTest::newRow(dataTag: "MoveUp, hidden row 1 (2,0)")
951 << 4 << 4 << 1 << -1
952 << 2 << 0
953 << QtTestTableView::MoveUp << Qt::NoModifier
954 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
955
956 QTest::newRow(dataTag: "MoveUp, hidden row (1,0)")
957 << 4 << 4 << 0 << -1
958 << 1 << 0
959 << QtTestTableView::MoveUp << Qt::NoModifier
960 << 1 << 0 << IntPair(0,0) << IntPair(0,0);
961
962 // MoveHome
963 QTest::newRow(dataTag: "MoveHome (0,0)")
964 << 4 << 4 << -1 << -1
965 << 0 << 0
966 << QtTestTableView::MoveHome << Qt::NoModifier
967 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
968
969 QTest::newRow(dataTag: "MoveHome (3,3)")
970 << 4 << 4 << -1 << -1
971 << 3 << 3
972 << QtTestTableView::MoveHome << Qt::NoModifier
973 << 3 << 0 << IntPair(0,0) << IntPair(0,0);
974
975 QTest::newRow(dataTag: "MoveHome, hidden column 0 (3,3)")
976 << 4 << 4 << -1 << 0
977 << 3 << 3
978 << QtTestTableView::MoveHome << Qt::NoModifier
979 << 3 << 1 << IntPair(0,0) << IntPair(0,0);
980
981 // Use Ctrl modifier
982 QTest::newRow(dataTag: "MoveHome + Ctrl (0,0)")
983 << 4 << 4 << -1 << -1
984 << 0 << 0
985 << QtTestTableView::MoveHome << Qt::ControlModifier
986 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
987
988 QTest::newRow(dataTag: "MoveHome + Ctrl (3,3)")
989 << 4 << 4 << -1 << -1
990 << 3 << 3
991 << QtTestTableView::MoveHome << Qt::ControlModifier
992 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
993
994 QTest::newRow(dataTag: "MoveHome + Ctrl, hidden column 0, hidden row 0 (3,3)")
995 << 4 << 4 << 0 << 0
996 << 3 << 3
997 << QtTestTableView::MoveHome << Qt::ControlModifier
998 << 1 << 1 << IntPair(0,0) << IntPair(0,0);
999
1000 // MoveEnd
1001 QTest::newRow(dataTag: "MoveEnd (0,0)")
1002 << 4 << 4 << -1 << -1
1003 << 0 << 0
1004 << QtTestTableView::MoveEnd << Qt::NoModifier
1005 << 0 << 3 << IntPair(0,0) << IntPair(0,0);
1006
1007 QTest::newRow(dataTag: "MoveEnd (3,3)")
1008 << 4 << 4 << -1 << -1
1009 << 3 << 3
1010 << QtTestTableView::MoveEnd << Qt::NoModifier
1011 << 3 << 3 << IntPair(0,0) << IntPair(0,0);
1012
1013 QTest::newRow(dataTag: "MoveEnd, hidden column (0,0)")
1014 << 4 << 4 << -1 << 3
1015 << 0 << 0
1016 << QtTestTableView::MoveEnd << Qt::NoModifier
1017 << 0<< 2 << IntPair(0,0) << IntPair(0,0);
1018
1019 // Use Ctrl modifier
1020 QTest::newRow(dataTag: "MoveEnd + Ctrl (0,0)")
1021 << 4 << 4 << -1 << -1
1022 << 0 << 0
1023 << QtTestTableView::MoveEnd << Qt::ControlModifier
1024 << 3 << 3 << IntPair(0,0) << IntPair(0,0);
1025
1026 QTest::newRow(dataTag: "MoveEnd + Ctrl (3,3)")
1027 << 4 << 4 << -1 << -1
1028 << 3 << 3
1029 << QtTestTableView::MoveEnd << Qt::ControlModifier
1030 << 3 << 3 << IntPair(0,0) << IntPair(0,0);
1031
1032 QTest::newRow(dataTag: "MoveEnd + Ctrl, hidden column 3 (0,0)")
1033 << 4 << 4 << -1 << 3
1034 << 0 << 0
1035 << QtTestTableView::MoveEnd << Qt::ControlModifier
1036 << 3 << 2 << IntPair(0,0) << IntPair(0,0);
1037
1038 QTest::newRow(dataTag: "MoveEnd + Ctrl, hidden column 3, hidden row 3 (0,0)")
1039 << 4 << 4 << 3 << 3
1040 << 0 << 0
1041 << QtTestTableView::MoveEnd << Qt::ControlModifier
1042 << 2 << 2 << IntPair(0,0) << IntPair(0,0);
1043
1044 QTest::newRow(dataTag: "MovePageUp (0,0)")
1045 << 4 << 4 << -1 << -1
1046 << 0 << 0
1047 << QtTestTableView::MovePageUp << Qt::NoModifier
1048 << 0 << 0 << IntPair(0,0) << IntPair(0,0);
1049
1050 QTest::newRow(dataTag: "MovePageUp (3,3)")
1051 << 4 << 4 << -1 << -1
1052 << 3 << 3
1053 << QtTestTableView::MovePageUp << Qt::NoModifier
1054 << 0 << 3 << IntPair(0,0) << IntPair(0,0);
1055
1056 QTest::newRow(dataTag: "MovePageDown (3, 3)")
1057 << 4 << 4 << -1 << -1
1058 << 3 << 3
1059 << QtTestTableView::MovePageDown << Qt::NoModifier
1060 << 3 << 3 << IntPair(0,0) << IntPair(0,0);
1061
1062 QTest::newRow(dataTag: "MovePageDown (0, 3)")
1063 << 4 << 4 << -1 << -1
1064 << 0 << 3
1065 << QtTestTableView::MovePageDown << Qt::NoModifier
1066 << 3 << 3 << IntPair(0,0) << IntPair(0,0);
1067}
1068
1069void tst_QTableView::moveCursor()
1070{
1071 QFETCH(int, rowCount);
1072 QFETCH(int, columnCount);
1073 QFETCH(int, hideRow);
1074 QFETCH(int, hideColumn);
1075 QFETCH(int, startRow);
1076 QFETCH(int, startColumn);
1077 QFETCH(QtTestTableView::CursorAction, cursorMoveAction);
1078 QFETCH(Qt::KeyboardModifier, modifier);
1079 QFETCH(int, expectedRow);
1080 QFETCH(int, expectedColumn);
1081 QFETCH(IntPair, moveRow);
1082 QFETCH(IntPair, moveColumn);
1083
1084 QtTestTableModel model(rowCount, columnCount);
1085 QtTestTableView view;
1086
1087 view.setModel(&model);
1088 // we have to make sure that PgUp/PgDown can scroll to the bottom/top
1089 view.resize(w: view.horizontalHeader()->length() + 50,
1090 h: view.verticalHeader()->length() + 50);
1091 view.hideRow(row: hideRow);
1092 view.hideColumn(column: hideColumn);
1093 if (moveColumn.first != moveColumn.second)
1094 view.horizontalHeader()->moveSection(from: moveColumn.first, to: moveColumn.second);
1095 if (moveRow.first != moveRow.second)
1096 view.verticalHeader()->moveSection(from: moveRow.first, to: moveRow.second);
1097
1098 view.show();
1099
1100 QModelIndex index = model.index(row: startRow, column: startColumn);
1101 view.setCurrentIndex(index);
1102
1103 QModelIndex newIndex = view.moveCursor(cursorAction: cursorMoveAction, modifiers: modifier);
1104 // expected fails, task 119433
1105 if(newIndex.row() == -1)
1106 return;
1107 QCOMPARE(newIndex.row(), expectedRow);
1108 QCOMPARE(newIndex.column(), expectedColumn);
1109}
1110
1111void tst_QTableView::moveCursorStrikesBack_data()
1112{
1113 QTest::addColumn<int>(name: "hideRow");
1114 QTest::addColumn<int>(name: "hideColumn");
1115 QTest::addColumn<IntList>(name: "disableRows");
1116 QTest::addColumn<IntList>(name: "disableColumns");
1117 QTest::addColumn<QRect>(name: "span");
1118
1119 QTest::addColumn<int>(name: "startRow");
1120 QTest::addColumn<int>(name: "startColumn");
1121 QTest::addColumn<CursorActionList>(name: "cursorMoveActions");
1122 QTest::addColumn<int>(name: "expectedRow");
1123 QTest::addColumn<int>(name: "expectedColumn");
1124
1125 QTest::newRow(dataTag: "Last column disabled. Task QTBUG-3878") << -1 << -1
1126 << IntList()
1127 << (IntList() << 6)
1128 << QRect()
1129 << 0 << 5
1130 << CursorActionList{QtTestTableView::MoveNext}
1131 << 1 << 0;
1132
1133 QTest::newRow(dataTag: "Last column disabled 2. Task QTBUG-3878") << -1 << -1
1134 << IntList()
1135 << (IntList() << 6)
1136 << QRect()
1137 << 1 << 0
1138 << CursorActionList{QtTestTableView::MovePrevious}
1139 << 0 << 5;
1140
1141 QTest::newRow(dataTag: "Span, anchor column hidden") << -1 << 1
1142 << IntList()
1143 << IntList()
1144 << QRect(1, 2, 2, 3)
1145 << 2 << 0
1146 << CursorActionList{QtTestTableView::MoveNext}
1147 << 2 << 1;
1148
1149 QTest::newRow(dataTag: "Span, anchor column disabled") << -1 << -1
1150 << IntList()
1151 << (IntList() << 1)
1152 << QRect(1, 2, 2, 3)
1153 << 2 << 0
1154 << CursorActionList{QtTestTableView::MoveNext}
1155 << 2 << 1;
1156
1157 QTest::newRow(dataTag: "Span, anchor row hidden") << 2 << -1
1158 << IntList()
1159 << IntList()
1160 << QRect(1, 2, 2, 3)
1161 << 1 << 2
1162 << CursorActionList{QtTestTableView::MoveDown}
1163 << 2 << 1;
1164
1165 QTest::newRow(dataTag: "Span, anchor row disabled") << -1 << -1
1166 << (IntList() << 2)
1167 << IntList()
1168 << QRect(1, 2, 2, 3)
1169 << 1 << 2
1170 << CursorActionList{QtTestTableView::MoveDown}
1171 << 2 << 1;
1172
1173 QTest::newRow(dataTag: "Move through span right") << -1 << -1
1174 << IntList()
1175 << IntList()
1176 << QRect(1, 2, 2, 3)
1177 << 3 << 0
1178 << CursorActionList{QtTestTableView::MoveRight,
1179 QtTestTableView::MoveRight}
1180 << 3 << 3;
1181
1182 QTest::newRow(dataTag: "Move through span left") << -1 << -1
1183 << IntList()
1184 << IntList()
1185 << QRect(1, 2, 2, 3)
1186 << 3 << 3
1187 << CursorActionList{QtTestTableView::MoveLeft,
1188 QtTestTableView::MoveLeft}
1189 << 3 << 0;
1190
1191 QTest::newRow(dataTag: "Move through span down") << -1 << -1
1192 << IntList()
1193 << IntList()
1194 << QRect(1, 2, 2, 3)
1195 << 1 << 2
1196 << CursorActionList{QtTestTableView::MoveDown,
1197 QtTestTableView::MoveDown}
1198 << 5 << 2;
1199
1200 QTest::newRow(dataTag: "Move through span up") << -1 << -1
1201 << IntList()
1202 << IntList()
1203 << QRect(1, 2, 2, 3)
1204 << 5 << 2
1205 << CursorActionList{QtTestTableView::MoveUp,
1206 QtTestTableView::MoveUp}
1207 << 1 << 2;
1208
1209 IntList fullList;
1210 for (int i = 0; i < 7; ++i)
1211 fullList << i;
1212
1213 QTest::newRow(dataTag: "All disabled, wrap forward. => invalid index") << -1 << -1
1214 << fullList
1215 << fullList
1216 << QRect()
1217 << 1 << 0
1218 << CursorActionList{QtTestTableView::MoveNext}
1219 << -1 << -1;
1220
1221 QTest::newRow(dataTag: "All disabled, wrap backwards. => invalid index") << -1 << -1
1222 << fullList
1223 << fullList
1224 << QRect()
1225 << 1 << 0
1226 << CursorActionList{QtTestTableView::MovePrevious}
1227 << -1 << -1;
1228
1229 QTest::newRow(dataTag: "Last column disabled, MoveEnd. QTBUG-72400") << -1 << -1
1230 << IntList()
1231 << (IntList() << 6)
1232 << QRect()
1233 << 0 << 0
1234 << CursorActionList{QtTestTableView::MoveEnd}
1235 << 0 << 5;
1236
1237 QTest::newRow(dataTag: "First column disabled, MoveHome. QTBUG-72400") << -1 << -1
1238 << IntList()
1239 << (IntList() << 0)
1240 << QRect()
1241 << 0 << 6
1242 << CursorActionList{QtTestTableView::MoveHome}
1243 << 0 << 1;
1244
1245 QTest::newRow(dataTag: "First row disabled, MovePageUp. QTBUG-72400") << -1 << -1
1246 << (IntList() << 0)
1247 << IntList()
1248 << QRect()
1249 << 2 << 0
1250 << CursorActionList{QtTestTableView::MovePageUp}
1251 << 1 << 0;
1252
1253 QTest::newRow(dataTag: "Last row disabled, MovePageDown. QTBUG-72400") << -1 << -1
1254 << (IntList() << 6)
1255 << IntList()
1256 << QRect()
1257 << 4 << 0
1258 << CursorActionList{QtTestTableView::MovePageDown}
1259 << 5 << 0;
1260}
1261
1262void tst_QTableView::moveCursorStrikesBack()
1263{
1264 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
1265 QSKIP("Wayland: This fails. Figure out why.");
1266
1267 QFETCH(int, hideRow);
1268 QFETCH(int, hideColumn);
1269 QFETCH(const IntList, disableRows);
1270 QFETCH(const IntList, disableColumns);
1271 QFETCH(QRect, span);
1272
1273 QFETCH(int, startRow);
1274 QFETCH(int, startColumn);
1275 QFETCH(const CursorActionList, cursorMoveActions);
1276 QFETCH(int, expectedRow);
1277 QFETCH(int, expectedColumn);
1278
1279 QtTestTableModel model(7, 7);
1280 QtTestTableView view;
1281 view.setModel(&model);
1282 view.hideRow(row: hideRow);
1283 view.hideColumn(column: hideColumn);
1284
1285 if (span.height() && span.width())
1286 view.setSpan(row: span.top(), column: span.left(), rowSpan: span.height(), columnSpan: span.width());
1287 view.show();
1288 QVERIFY(QTest::qWaitForWindowActive(&view));
1289 // resize to make sure there are scrollbars
1290 view.resize(w: view.columnWidth(column: 0) * 7, h: view.rowHeight(row: 0) * 7);
1291
1292 QModelIndex index = model.index(row: startRow, column: startColumn);
1293 view.setCurrentIndex(index);
1294
1295 for (int row : disableRows)
1296 model.disableRow(row);
1297 for (int column : disableColumns)
1298 model.disableColumn(column);
1299
1300 int newRow = -1;
1301 int newColumn = -1;
1302 for (auto cursorMoveAction : cursorMoveActions) {
1303 QModelIndex newIndex = view.moveCursor(cursorAction: cursorMoveAction, modifiers: {});
1304 view.setCurrentIndex(newIndex);
1305 newRow = newIndex.row();
1306 newColumn = newIndex.column();
1307 }
1308
1309 QCOMPARE(newRow, expectedRow);
1310 QCOMPARE(newColumn, expectedColumn);
1311}
1312
1313void tst_QTableView::moveCursorBiggerJump()
1314{
1315 QtTestTableModel model(50, 7);
1316 QTableView view;
1317 view.setModel(&model);
1318 view.show();
1319 QVERIFY(QTest::qWaitForWindowExposed(&view));
1320
1321 int height = view.horizontalHeader()->height();
1322 for (int i=0;i<8;i++)
1323 height += view.verticalHeader()->sectionSize(logicalIndex: i);
1324 view.resize(w: view.width(), h: height);
1325 view.setCurrentIndex(model.index(row: 0,column: 0));
1326
1327 QTest::keyClick(widget: &view, key: Qt::Key_PageDown);
1328 QCOMPARE(view.indexAt(QPoint(0,0)), model.index(1,0));
1329 QTest::keyClick(widget: &view, key: Qt::Key_PageDown);
1330 QCOMPARE(view.indexAt(QPoint(0,0)), model.index(8,0));
1331 QTest::keyClick(widget: &view, key: Qt::Key_PageDown);
1332 QCOMPARE(view.indexAt(QPoint(0,0)), model.index(15,0));
1333 QTest::keyClick(widget: &view, key: Qt::Key_PageUp);
1334 QCOMPARE(view.indexAt(QPoint(0,0)), model.index(14,0));
1335 QTest::keyClick(widget: &view, key: Qt::Key_PageUp);
1336 QCOMPARE(view.indexAt(QPoint(0,0)), model.index(7,0));
1337 QTest::keyClick(widget: &view, key: Qt::Key_PageUp);
1338 QCOMPARE(view.indexAt(QPoint(0,0)), model.index(0,0));
1339
1340 QTest::keyClick(widget: &view, key: Qt::Key_PageDown);
1341 view.verticalHeader()->hideSection(alogicalIndex: 0);
1342 QTest::keyClick(widget: &view, key: Qt::Key_PageUp);
1343 QTRY_COMPARE(view.currentIndex().row(), view.rowAt(0));
1344}
1345
1346void tst_QTableView::hideRows_data()
1347{
1348 QTest::addColumn<int>(name: "rowCount");
1349 QTest::addColumn<int>(name: "columnCount");
1350 QTest::addColumn<int>(name: "showRow"); // hide, then show
1351 QTest::addColumn<int>(name: "hideRow"); // hide only
1352 QTest::addColumn<int>(name: "row");
1353 QTest::addColumn<int>(name: "column");
1354 QTest::addColumn<int>(name: "rowSpan");
1355 QTest::addColumn<int>(name: "columnSpan");
1356
1357 QTest::newRow(dataTag: "show row 0, hide row 3, no span")
1358 << 10 << 10
1359 << 0
1360 << 3
1361 << -1 << -1
1362 << 1 << 1;
1363
1364 QTest::newRow(dataTag: "show row 0, hide row 3, span")
1365 << 10 << 10
1366 << 0
1367 << 3
1368 << 0 << 0
1369 << 3 << 2;
1370}
1371
1372void tst_QTableView::hideRows()
1373{
1374 QFETCH(int, rowCount);
1375 QFETCH(int, columnCount);
1376 QFETCH(int, showRow);
1377 QFETCH(int, hideRow);
1378 QFETCH(int, row);
1379 QFETCH(int, column);
1380 QFETCH(int, rowSpan);
1381 QFETCH(int, columnSpan);
1382
1383 QtTestTableModel model(rowCount, columnCount);
1384 QTableView view;
1385
1386 view.setModel(&model);
1387 view.setSpan(row, column, rowSpan, columnSpan);
1388
1389 view.hideRow(row: showRow);
1390 QVERIFY(view.isRowHidden(showRow));
1391
1392 view.hideRow(row: hideRow);
1393 QVERIFY(view.isRowHidden(hideRow));
1394
1395 view.showRow(row: showRow);
1396 QVERIFY(!view.isRowHidden(showRow));
1397 QVERIFY(view.isRowHidden(hideRow));
1398}
1399
1400void tst_QTableView::hideColumns_data()
1401{
1402 QTest::addColumn<int>(name: "rowCount");
1403 QTest::addColumn<int>(name: "columnCount");
1404 QTest::addColumn<int>(name: "showColumn"); // hide, then show
1405 QTest::addColumn<int>(name: "hideColumn"); // hide only
1406 QTest::addColumn<int>(name: "row");
1407 QTest::addColumn<int>(name: "column");
1408 QTest::addColumn<int>(name: "rowSpan");
1409 QTest::addColumn<int>(name: "columnSpan");
1410
1411 QTest::newRow(dataTag: "show col 0, hide col 3, no span")
1412 << 10 << 10
1413 << 0
1414 << 3
1415 << -1 << -1
1416 << 1 << 1;
1417
1418 QTest::newRow(dataTag: "show col 0, hide col 3, span")
1419 << 10 << 10
1420 << 0
1421 << 3
1422 << 0 << 0
1423 << 3 << 2;
1424}
1425
1426void tst_QTableView::hideColumns()
1427{
1428 QFETCH(int, rowCount);
1429 QFETCH(int, columnCount);
1430 QFETCH(int, showColumn);
1431 QFETCH(int, hideColumn);
1432 QFETCH(int, row);
1433 QFETCH(int, column);
1434 QFETCH(int, rowSpan);
1435 QFETCH(int, columnSpan);
1436
1437 QtTestTableModel model(rowCount, columnCount);
1438
1439 QTableView view;
1440 view.setModel(&model);
1441 view.setSpan(row, column, rowSpan, columnSpan);
1442
1443 view.hideColumn(column: showColumn);
1444 QVERIFY(view.isColumnHidden(showColumn));
1445
1446 view.hideColumn(column: hideColumn);
1447 QVERIFY(view.isColumnHidden(hideColumn));
1448
1449 view.showColumn(column: showColumn);
1450 QVERIFY(!view.isColumnHidden(showColumn));
1451 QVERIFY(view.isColumnHidden(hideColumn));
1452}
1453
1454void tst_QTableView::selection_data()
1455{
1456 QTest::addColumn<int>(name: "rowCount");
1457 QTest::addColumn<int>(name: "columnCount");
1458 QTest::addColumn<int>(name: "row");
1459 QTest::addColumn<int>(name: "column");
1460 QTest::addColumn<int>(name: "rowSpan");
1461 QTest::addColumn<int>(name: "columnSpan");
1462 QTest::addColumn<int>(name: "hideRow");
1463 QTest::addColumn<int>(name: "hideColumn");
1464 QTest::addColumn<int>(name: "moveRowFrom");
1465 QTest::addColumn<int>(name: "moveRowTo");
1466 QTest::addColumn<int>(name: "moveColumnFrom");
1467 QTest::addColumn<int>(name: "moveColumnTo");
1468 QTest::addColumn<int>(name: "rowHeight");
1469 QTest::addColumn<int>(name: "columnWidth");
1470 QTest::addColumn<int>(name: "x");
1471 QTest::addColumn<int>(name: "y");
1472 QTest::addColumn<int>(name: "width");
1473 QTest::addColumn<int>(name: "height");
1474 QTest::addColumn<QItemSelectionModel::SelectionFlag>(name: "command");
1475 QTest::addColumn<int>(name: "selectedCount"); // ### make this more detailed
1476
1477 QTest::newRow(dataTag: "no span, no hidden, no moved, 3x3 select")
1478 << 10 << 10 // dim
1479 << -1 << -1 // pos
1480 << 1 << 1 // span
1481 << -1 << -1 // hide
1482 << -1 << -1 // move row
1483 << -1 << -1 // move col
1484 << 40 << 40 // cell size
1485 << 20 << 20 << 80 << 80 // rect
1486 << QItemSelectionModel::Select // command
1487 << 9; // selected count
1488
1489 QTest::newRow(dataTag: "row span, no hidden, no moved, 3x3 select")
1490 << 10 << 10 // dim
1491 << 1 << 1 // pos
1492 << 2 << 1 // span
1493 << -1 << -1 // hide
1494 << -1 << -1 // move row
1495 << -1 << -1 // move col
1496 << 40 << 40 // cell size
1497 << 20 << 20 << 80 << 80 // rect
1498 << QItemSelectionModel::Select // command
1499 << 8; // selected count
1500
1501 QTest::newRow(dataTag: "col span, no hidden, no moved, 3x3 select")
1502 << 10 << 10 // dim
1503 << 1 << 1 // pos
1504 << 1 << 2 // span
1505 << -1 << -1 // hide
1506 << -1 << -1 // move row
1507 << -1 << -1 // move col
1508 << 40 << 40 // cell size
1509 << 20 << 20 << 80 << 80 // rect
1510 << QItemSelectionModel::Select // command
1511 << 8; // selected count
1512
1513 QTest::newRow(dataTag: "no span, row hidden, no moved, 3x3 select")
1514 << 10 << 10 // dim
1515 << -1 << -1 // pos
1516 << 1 << 1 // span
1517 << 1 << -1 // hide
1518 << -1 << -1 // move row
1519 << -1 << -1 // move col
1520 << 40 << 40 // cell size
1521 << 20 << 20 << 80 << 80 // rect
1522 << QItemSelectionModel::Select // command
1523 << 9; // selected count
1524
1525 QTest::newRow(dataTag: "no span, col hidden, no moved, 3x3 select")
1526 << 10 << 10 // dim
1527 << -1 << -1 // pos
1528 << 1 << 1 // span
1529 << -1 << 1 // hide
1530 << -1 << -1 // move row
1531 << -1 << -1 // move col
1532 << 40 << 40 // cell size
1533 << 20 << 20 << 80 << 80 // rect
1534 << QItemSelectionModel::Select // command
1535 << 9; // selected count
1536
1537 QTest::newRow(dataTag: "no span, no hidden, row moved, 3x3 select")
1538 << 10 << 10 // dim
1539 << -1 << -1 // pos
1540 << 1 << 1 // span
1541 << -1 << -1 // hide
1542 << 1 << 3 // move row
1543 << -1 << -1 // move col
1544 << 40 << 40 // cell size
1545 << 20 << 20 << 80 << 80 // rect
1546 << QItemSelectionModel::Select // command
1547 << 9; // selected count
1548
1549 QTest::newRow(dataTag: "no span, no hidden, col moved, 3x3 select")
1550 << 10 << 10 // dim
1551 << -1 << -1 // pos
1552 << 1 << 1 // span
1553 << -1 << -1 // hide
1554 << -1 << -1 // move row
1555 << 1 << 3 // move col
1556 << 40 << 40 // cell size
1557 << 20 << 20 << 80 << 80 // rect
1558 << QItemSelectionModel::Select // command
1559 << 9; // selected count
1560}
1561
1562void tst_QTableView::selection()
1563{
1564 QFETCH(int, rowCount);
1565 QFETCH(int, columnCount);
1566 QFETCH(int, row);
1567 QFETCH(int, column);
1568 QFETCH(int, rowSpan);
1569 QFETCH(int, columnSpan);
1570 QFETCH(int, hideRow);
1571 QFETCH(int, hideColumn);
1572 QFETCH(int, moveRowFrom);
1573 QFETCH(int, moveRowTo);
1574 QFETCH(int, moveColumnFrom);
1575 QFETCH(int, moveColumnTo);
1576 QFETCH(int, rowHeight);
1577 QFETCH(int, columnWidth);
1578 QFETCH(int, x);
1579 QFETCH(int, y);
1580 QFETCH(int, width);
1581 QFETCH(int, height);
1582 QFETCH(QItemSelectionModel::SelectionFlag, command);
1583 QFETCH(int, selectedCount);
1584
1585 QtTestTableModel model(rowCount, columnCount);
1586
1587 QtTestTableView view;
1588 view.show();
1589 view.setModel(&model);
1590
1591 view.setSpan(row, column, rowSpan, columnSpan);
1592
1593 view.hideRow(row: hideRow);
1594 view.hideColumn(column: hideColumn);
1595
1596 view.verticalHeader()->moveSection(from: moveRowFrom, to: moveRowTo);
1597 view.horizontalHeader()->moveSection(from: moveColumnFrom, to: moveColumnTo);
1598
1599 for (int r = 0; r < rowCount; ++r)
1600 view.setRowHeight(row: r, height: rowHeight);
1601 for (int c = 0; c < columnCount; ++c)
1602 view.setColumnWidth(column: c, width: columnWidth);
1603
1604 view.setSelection(rect: QRect(x, y, width, height), command);
1605
1606 QCOMPARE(view.selectedIndexes().count(), selectedCount);
1607}
1608
1609void tst_QTableView::selectRow_data()
1610{
1611 QTest::addColumn<int>(name: "rowCount");
1612 QTest::addColumn<int>(name: "columnCount");
1613 QTest::addColumn<int>(name: "row");
1614 QTest::addColumn<QAbstractItemView::SelectionMode>(name: "mode");
1615 QTest::addColumn<QAbstractItemView::SelectionBehavior>(name: "behavior");
1616 QTest::addColumn<int>(name: "selectedItems");
1617
1618 QTest::newRow(dataTag: "SingleSelection and SelectItems")
1619 << 10 << 10
1620 << 0
1621 << QAbstractItemView::SingleSelection
1622 << QAbstractItemView::SelectItems
1623 << 0;
1624
1625 QTest::newRow(dataTag: "SingleSelection and SelectRows")
1626 << 10 << 10
1627 << 0
1628 << QAbstractItemView::SingleSelection
1629 << QAbstractItemView::SelectRows
1630 << 10;
1631
1632 QTest::newRow(dataTag: "SingleSelection and SelectColumns")
1633 << 10 << 10
1634 << 0
1635 << QAbstractItemView::SingleSelection
1636 << QAbstractItemView::SelectColumns
1637 << 0;
1638
1639 QTest::newRow(dataTag: "MultiSelection and SelectItems")
1640 << 10 << 10
1641 << 0
1642 << QAbstractItemView::MultiSelection
1643 << QAbstractItemView::SelectItems
1644 << 10;
1645
1646 QTest::newRow(dataTag: "MultiSelection and SelectRows")
1647 << 10 << 10
1648 << 0
1649 << QAbstractItemView::MultiSelection
1650 << QAbstractItemView::SelectRows
1651 << 10;
1652
1653 QTest::newRow(dataTag: "MultiSelection and SelectColumns")
1654 << 10 << 10
1655 << 0
1656 << QAbstractItemView::MultiSelection
1657 << QAbstractItemView::SelectColumns
1658 << 0;
1659
1660 QTest::newRow(dataTag: "ExtendedSelection and SelectItems")
1661 << 10 << 10
1662 << 0
1663 << QAbstractItemView::ExtendedSelection
1664 << QAbstractItemView::SelectItems
1665 << 10;
1666
1667 QTest::newRow(dataTag: "ExtendedSelection and SelectRows")
1668 << 10 << 10
1669 << 0
1670 << QAbstractItemView::ExtendedSelection
1671 << QAbstractItemView::SelectRows
1672 << 10;
1673
1674 QTest::newRow(dataTag: "ExtendedSelection and SelectColumns")
1675 << 10 << 10
1676 << 0
1677 << QAbstractItemView::ExtendedSelection
1678 << QAbstractItemView::SelectColumns
1679 << 0;
1680
1681 QTest::newRow(dataTag: "ContiguousSelection and SelectItems")
1682 << 10 << 10
1683 << 0
1684 << QAbstractItemView::ContiguousSelection
1685 << QAbstractItemView::SelectItems
1686 << 10;
1687
1688 QTest::newRow(dataTag: "ContiguousSelection and SelectRows")
1689 << 10 << 10
1690 << 0
1691 << QAbstractItemView::ContiguousSelection
1692 << QAbstractItemView::SelectRows
1693 << 10;
1694
1695 QTest::newRow(dataTag: "ContiguousSelection and SelectColumns")
1696 << 10 << 10
1697 << 0
1698 << QAbstractItemView::ContiguousSelection
1699 << QAbstractItemView::SelectColumns
1700 << 0;
1701}
1702
1703void tst_QTableView::selectRow()
1704{
1705 QFETCH(int, rowCount);
1706 QFETCH(int, columnCount);
1707 QFETCH(int, row);
1708 QFETCH(QAbstractItemView::SelectionMode, mode);
1709 QFETCH(QAbstractItemView::SelectionBehavior, behavior);
1710 QFETCH(int, selectedItems);
1711
1712 QtTestTableModel model(rowCount, columnCount);
1713 QTableView view;
1714
1715 view.setModel(&model);
1716 view.setSelectionMode(mode);
1717 view.setSelectionBehavior(behavior);
1718
1719 QCOMPARE(view.selectionModel()->selectedIndexes().count(), 0);
1720
1721 view.selectRow(row);
1722
1723 //test we have 10 items selected
1724 QCOMPARE(view.selectionModel()->selectedIndexes().count(), selectedItems);
1725 //test that all 10 items are in the same row
1726 for (int i = 0; selectedItems > 0 && i < rowCount; ++i)
1727 QCOMPARE(view.selectionModel()->selectedIndexes().at(i).row(), row);
1728}
1729
1730void tst_QTableView::selectColumn_data()
1731{
1732 QTest::addColumn<int>(name: "rowCount");
1733 QTest::addColumn<int>(name: "columnCount");
1734 QTest::addColumn<int>(name: "column");
1735 QTest::addColumn<QAbstractItemView::SelectionMode>(name: "mode");
1736 QTest::addColumn<QAbstractItemView::SelectionBehavior>(name: "behavior");
1737 QTest::addColumn<int>(name: "selectedItems");
1738
1739 QTest::newRow(dataTag: "SingleSelection and SelectItems")
1740 << 10 << 10
1741 << 0
1742 << QAbstractItemView::SingleSelection
1743 << QAbstractItemView::SelectItems
1744 << 0;
1745
1746 QTest::newRow(dataTag: "SingleSelection and SelectRows")
1747 << 10 << 10
1748 << 0
1749 << QAbstractItemView::SingleSelection
1750 << QAbstractItemView::SelectRows
1751 << 0;
1752
1753 QTest::newRow(dataTag: "SingleSelection and SelectColumns")
1754 << 10 << 10
1755 << 0
1756 << QAbstractItemView::SingleSelection
1757 << QAbstractItemView::SelectColumns
1758 << 10;
1759
1760 QTest::newRow(dataTag: "MultiSelection and SelectItems")
1761 << 10 << 10
1762 << 0
1763 << QAbstractItemView::MultiSelection
1764 << QAbstractItemView::SelectItems
1765 << 10;
1766
1767 QTest::newRow(dataTag: "MultiSelection and SelectRows")
1768 << 10 << 10
1769 << 0
1770 << QAbstractItemView::MultiSelection
1771 << QAbstractItemView::SelectRows
1772 << 0;
1773
1774 QTest::newRow(dataTag: "MultiSelection and SelectColumns")
1775 << 10 << 10
1776 << 0
1777 << QAbstractItemView::MultiSelection
1778 << QAbstractItemView::SelectColumns
1779 << 10;
1780
1781 QTest::newRow(dataTag: "ExtendedSelection and SelectItems")
1782 << 10 << 10
1783 << 0
1784 << QAbstractItemView::ExtendedSelection
1785 << QAbstractItemView::SelectItems
1786 << 10;
1787
1788 QTest::newRow(dataTag: "ExtendedSelection and SelectRows")
1789 << 10 << 10
1790 << 0
1791 << QAbstractItemView::ExtendedSelection
1792 << QAbstractItemView::SelectRows
1793 << 0;
1794
1795 QTest::newRow(dataTag: "ExtendedSelection and SelectColumns")
1796 << 10 << 10
1797 << 0
1798 << QAbstractItemView::ExtendedSelection
1799 << QAbstractItemView::SelectColumns
1800 << 10;
1801
1802 QTest::newRow(dataTag: "ContiguousSelection and SelectItems")
1803 << 10 << 10
1804 << 0
1805 << QAbstractItemView::ContiguousSelection
1806 << QAbstractItemView::SelectItems
1807 << 10;
1808
1809 QTest::newRow(dataTag: "ContiguousSelection and SelectRows")
1810 << 10 << 10
1811 << 0
1812 << QAbstractItemView::ContiguousSelection
1813 << QAbstractItemView::SelectRows
1814 << 0;
1815
1816 QTest::newRow(dataTag: "ContiguousSelection and SelectColumns")
1817 << 10 << 10
1818 << 0
1819 << QAbstractItemView::ContiguousSelection
1820 << QAbstractItemView::SelectColumns
1821 << 10;
1822}
1823
1824void tst_QTableView::selectColumn()
1825{
1826 QFETCH(int, rowCount);
1827 QFETCH(int, columnCount);
1828 QFETCH(int, column);
1829 QFETCH(QAbstractItemView::SelectionMode, mode);
1830 QFETCH(QAbstractItemView::SelectionBehavior, behavior);
1831 QFETCH(int, selectedItems);
1832
1833 QtTestTableModel model(rowCount, columnCount);
1834
1835 QTableView view;
1836 view.setModel(&model);
1837 view.setSelectionMode(mode);
1838 view.setSelectionBehavior(behavior);
1839
1840 QCOMPARE(view.selectionModel()->selectedIndexes().count(), 0);
1841
1842 view.selectColumn(column);
1843
1844 QCOMPARE(view.selectionModel()->selectedIndexes().count(), selectedItems);
1845 for (int i = 0; selectedItems > 0 && i < columnCount; ++i)
1846 QCOMPARE(view.selectionModel()->selectedIndexes().at(i).column(), column);
1847}
1848
1849void tst_QTableView::selectall_data()
1850{
1851 QTest::addColumn<int>(name: "rowCount");
1852 QTest::addColumn<int>(name: "columnCount");
1853 QTest::addColumn<int>(name: "row");
1854 QTest::addColumn<int>(name: "column");
1855 QTest::addColumn<int>(name: "rowSpan");
1856 QTest::addColumn<int>(name: "columnSpan");
1857 QTest::addColumn<int>(name: "hideRow");
1858 QTest::addColumn<int>(name: "hideColumn");
1859 QTest::addColumn<int>(name: "moveRowFrom");
1860 QTest::addColumn<int>(name: "moveRowTo");
1861 QTest::addColumn<int>(name: "moveColumnFrom");
1862 QTest::addColumn<int>(name: "moveColumnTo");
1863 QTest::addColumn<int>(name: "rowHeight");
1864 QTest::addColumn<int>(name: "columnWidth");
1865 QTest::addColumn<int>(name: "selectedCount"); // ### make this more detailed
1866
1867 QTest::newRow(dataTag: "no span, no hidden, no moved")
1868 << 10 << 10 // dim
1869 << -1 << -1 // pos
1870 << 1 << 1 // span
1871 << -1 << -1 // hide
1872 << -1 << -1 // move row
1873 << -1 << -1 // move col
1874 << 40 << 40 // cell size
1875 << 100; // selected count
1876
1877 QTest::newRow(dataTag: "row span, no hidden, no moved")
1878 << 10 << 10 // dim
1879 << 1 << 1 // pos
1880 << 2 << 1 // span
1881 << -1 << -1 // hide
1882 << -1 << -1 // move row
1883 << -1 << -1 // move col
1884 << 40 << 40 // cell size
1885 << 99; // selected count
1886
1887 QTest::newRow(dataTag: "col span, no hidden, no moved")
1888 << 10 << 10 // dim
1889 << 1 << 1 // pos
1890 << 1 << 2 // span
1891 << -1 << -1 // hide
1892 << -1 << -1 // move row
1893 << -1 << -1 // move col
1894 << 40 << 40 // cell size
1895 << 99; // selected count
1896
1897 QTest::newRow(dataTag: "no span, row hidden, no moved")
1898 << 10 << 10 // dim
1899 << -1 << -1 // pos
1900 << 1 << 1 // span
1901 << 1 << -1 // hide
1902 << -1 << -1 // move row
1903 << -1 << -1 // move col
1904 << 40 << 40 // cell size
1905 << 90; // selected count
1906
1907 QTest::newRow(dataTag: "no span, col hidden, no moved")
1908 << 10 << 10 // dim
1909 << -1 << -1 // pos
1910 << 1 << 1 // span
1911 << -1 << 1 // hide
1912 << -1 << -1 // move row
1913 << -1 << -1 // move col
1914 << 40 << 40 // cell size
1915 << 90; // selected count
1916
1917 QTest::newRow(dataTag: "no span, no hidden, row moved")
1918 << 10 << 10 // dim
1919 << -1 << -1 // pos
1920 << 1 << 1 // span
1921 << -1 << -1 // hide
1922 << 1 << 3 // move row
1923 << -1 << -1 // move col
1924 << 40 << 40 // cell size
1925 << 100; // selected count
1926
1927 QTest::newRow(dataTag: "no span, no hidden, col moved")
1928 << 10 << 10 // dim
1929 << -1 << -1 // pos
1930 << 1 << 1 // span
1931 << -1 << -1 // hide
1932 << -1 << -1 // move row
1933 << 1 << 3 // move col
1934 << 40 << 40 // cell size
1935 << 100; // selected count
1936}
1937
1938void QTest__keySequence(QWidget* widget, const QKeySequence &ks)
1939{
1940 for (int i = 0; i < ks.count(); ++i)
1941 {
1942 Qt::Key key = Qt::Key(ks[i] & ~Qt::KeyboardModifierMask);
1943 Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(ks[i] & Qt::KeyboardModifierMask);
1944 QTest::keyClick(widget, key, modifier: modifiers);
1945 }
1946}
1947
1948void tst_QTableView::selectall()
1949{
1950 QFETCH(int, rowCount);
1951 QFETCH(int, columnCount);
1952 QFETCH(int, row);
1953 QFETCH(int, column);
1954 QFETCH(int, rowSpan);
1955 QFETCH(int, columnSpan);
1956 QFETCH(int, hideRow);
1957 QFETCH(int, hideColumn);
1958 QFETCH(int, moveRowFrom);
1959 QFETCH(int, moveRowTo);
1960 QFETCH(int, moveColumnFrom);
1961 QFETCH(int, moveColumnTo);
1962 QFETCH(int, rowHeight);
1963 QFETCH(int, columnWidth);
1964 QFETCH(int, selectedCount);
1965
1966 QtTestTableModel model(rowCount, columnCount);
1967
1968 QtTestTableView view;
1969 view.show();
1970 view.setModel(&model);
1971
1972 view.setSpan(row, column, rowSpan, columnSpan);
1973
1974 view.hideRow(row: hideRow);
1975 view.hideColumn(column: hideColumn);
1976
1977 view.verticalHeader()->moveSection(from: moveRowFrom, to: moveRowTo);
1978 view.horizontalHeader()->moveSection(from: moveColumnFrom, to: moveColumnTo);
1979
1980 for (int r = 0; r < rowCount; ++r)
1981 view.setRowHeight(row: r, height: rowHeight);
1982 for (int c = 0; c < columnCount; ++c)
1983 view.setColumnWidth(column: c, width: columnWidth);
1984
1985 // try slot first
1986 view.clearSelection();
1987 QCOMPARE(view.selectedIndexes().count(), 0);
1988 view.selectAll();
1989 QCOMPARE(view.selectedIndexes().count(), selectedCount);
1990
1991 // try by key sequence
1992 view.clearSelection();
1993 QCOMPARE(view.selectedIndexes().count(), 0);
1994 QTest__keySequence(widget: &view, ks: QKeySequence(QKeySequence::SelectAll));
1995 QCOMPARE(view.selectedIndexes().count(), selectedCount);
1996
1997 // check again with no selection mode
1998 view.clearSelection();
1999 view.setSelectionMode(QAbstractItemView::NoSelection);
2000 QCOMPARE(view.selectedIndexes().count(), 0);
2001 QTest__keySequence(widget: &view, ks: QKeySequence(QKeySequence::SelectAll));
2002 QCOMPARE(view.selectedIndexes().count(), 0);
2003}
2004
2005void tst_QTableView::visualRect_data()
2006{
2007 QTest::addColumn<int>(name: "rowCount");
2008 QTest::addColumn<int>(name: "columnCount");
2009 QTest::addColumn<int>(name: "hideRow");
2010 QTest::addColumn<int>(name: "hideColumn");
2011 QTest::addColumn<int>(name: "row");
2012 QTest::addColumn<int>(name: "column");
2013 QTest::addColumn<int>(name: "rowHeight");
2014 QTest::addColumn<int>(name: "columnWidth");
2015 QTest::addColumn<QRect>(name: "expectedRect");
2016
2017 QTest::newRow(dataTag: "(0,0)")
2018 << 10 << 10
2019 << -1 << -1
2020 << 0 << 0
2021 << 20 << 30
2022 << QRect(0, 0, 29, 19);
2023
2024 QTest::newRow(dataTag: "(0,0) hidden row")
2025 << 10 << 10
2026 << 0 << -1
2027 << 0 << 0
2028 << 20 << 30
2029 << QRect();
2030
2031 QTest::newRow(dataTag: "(0,0) hidden column")
2032 << 10 << 10
2033 << -1 << 0
2034 << 0 << 0
2035 << 20 << 30
2036 << QRect();
2037
2038 QTest::newRow(dataTag: "(0,0) hidden row and column")
2039 << 10 << 10
2040 << 0 << 0
2041 << 0 << 0
2042 << 20 << 30
2043 << QRect();
2044
2045 QTest::newRow(dataTag: "(0,0) out of bounds")
2046 << 10 << 10
2047 << -1 << -1
2048 << 20 << 20
2049 << 20 << 30
2050 << QRect();
2051
2052 QTest::newRow(dataTag: "(5,5), hidden row")
2053 << 10 << 10
2054 << 5 << -1
2055 << 5 << 5
2056 << 20 << 30
2057 << QRect();
2058
2059 QTest::newRow(dataTag: "(9,9)")
2060 << 10 << 10
2061 << -1 << -1
2062 << 9 << 9
2063 << 20 << 30
2064 << QRect(30*9, 20*9, 29, 19);
2065}
2066
2067void tst_QTableView::visualRect()
2068{
2069 QFETCH(int, rowCount);
2070 QFETCH(int, columnCount);
2071 QFETCH(int, hideRow);
2072 QFETCH(int, hideColumn);
2073 QFETCH(int, row);
2074 QFETCH(int, column);
2075 QFETCH(int, rowHeight);
2076 QFETCH(int, columnWidth);
2077 QFETCH(QRect, expectedRect);
2078
2079 QtTestTableModel model(rowCount, columnCount);
2080
2081 QTableView view;
2082 view.setModel(&model);
2083 view.horizontalHeader()->setMinimumSectionSize(0);
2084 view.verticalHeader()->setMinimumSectionSize(0);
2085 // Make sure that it has 1 pixel between each cell.
2086 view.setGridStyle(Qt::SolidLine);
2087 for (int i = 0; i < view.verticalHeader()->count(); ++i)
2088 view.verticalHeader()->resizeSection(logicalIndex: i, size: rowHeight);
2089 for (int i = 0; i < view.horizontalHeader()->count(); ++i)
2090 view.horizontalHeader()->resizeSection(logicalIndex: i, size: columnWidth);
2091
2092 view.hideRow(row: hideRow);
2093 view.hideColumn(column: hideColumn);
2094
2095 QRect rect = view.visualRect(index: model.index(row, column));
2096 QCOMPARE(rect, expectedRect);
2097}
2098
2099void tst_QTableView::fetchMore()
2100{
2101 QtTestTableModel model(64, 64);
2102
2103 model.can_fetch_more = true;
2104
2105 QTableView view;
2106 view.setModel(&model);
2107 view.show();
2108
2109 QCOMPARE(model.fetch_more_count, 0);
2110 view.verticalScrollBar()->setValue(view.verticalScrollBar()->maximum());
2111 QVERIFY(model.fetch_more_count > 0);
2112
2113 model.fetch_more_count = 0; //reset
2114 view.scrollToTop();
2115 QCOMPARE(model.fetch_more_count, 0);
2116
2117 view.scrollToBottom();
2118 QVERIFY(model.fetch_more_count > 0);
2119
2120 model.fetch_more_count = 0; //reset
2121 view.scrollToTop();
2122 view.setCurrentIndex(model.index(row: 0, column: 0));
2123 QCOMPARE(model.fetch_more_count, 0);
2124
2125 for (int i = 0; i < 64; ++i)
2126 QTest::keyClick(widget: &view, key: Qt::Key_Down);
2127 QCOMPARE(view.currentIndex(), model.index(63, 0));
2128 QVERIFY(model.fetch_more_count > 0);
2129}
2130
2131void tst_QTableView::setHeaders()
2132{
2133 QTableView view;
2134
2135 // Make sure we don't delete ourselves
2136 view.setVerticalHeader(view.verticalHeader());
2137 view.verticalHeader()->count();
2138 view.setHorizontalHeader(view.horizontalHeader());
2139 view.horizontalHeader()->count();
2140
2141 // Try passing around a header without it being deleted
2142 QTableView view2;
2143 view2.setVerticalHeader(view.verticalHeader());
2144 view2.setHorizontalHeader(view.horizontalHeader());
2145 view.setHorizontalHeader(new QHeaderView(Qt::Horizontal));
2146 view.setVerticalHeader(new QHeaderView(Qt::Vertical));
2147 view2.verticalHeader()->count();
2148 view2.horizontalHeader()->count();
2149
2150}
2151
2152void tst_QTableView::resizeRowsToContents_data()
2153{
2154 QTest::addColumn<int>(name: "rowCount");
2155 QTest::addColumn<int>(name: "columnCount");
2156 QTest::addColumn<bool>(name: "showGrid");
2157 QTest::addColumn<int>(name: "cellWidth");
2158 QTest::addColumn<int>(name: "cellHeight");
2159 QTest::addColumn<int>(name: "rowHeight");
2160 QTest::addColumn<int>(name: "columnWidth");
2161
2162 QTest::newRow(dataTag: "10x10 grid shown 40x40")
2163 << 10 << 10 << false << 40 << 40 << 40 << 40;
2164
2165 QTest::newRow(dataTag: "10x10 grid not shown 40x40")
2166 << 10 << 10 << true << 40 << 40 << 41 << 41;
2167}
2168
2169void tst_QTableView::resizeRowsToContents()
2170{
2171 QFETCH(int, rowCount);
2172 QFETCH(int, columnCount);
2173 QFETCH(bool, showGrid);
2174 QFETCH(int, cellWidth);
2175 QFETCH(int, cellHeight);
2176 QFETCH(int, rowHeight);
2177 QFETCH(int, columnWidth);
2178 Q_UNUSED(columnWidth)
2179
2180 QtTestTableModel model(rowCount, columnCount);
2181 QtTestTableView view;
2182 QtTestItemDelegate delegate;
2183
2184 view.setModel(&model);
2185 view.setItemDelegate(&delegate);
2186 view.setShowGrid(showGrid); // the grid will add to the row height
2187
2188 delegate.hint = QSize(cellWidth, cellHeight);
2189
2190 QSignalSpy resizedSpy(view.verticalHeader(), &QHeaderView::sectionResized);
2191 view.resizeRowsToContents();
2192
2193 QCOMPARE(resizedSpy.count(), model.rowCount());
2194 for (int r = 0; r < model.rowCount(); ++r)
2195 QCOMPARE(view.rowHeight(r), rowHeight);
2196}
2197
2198void tst_QTableView::resizeColumnsToContents_data()
2199{
2200 QTest::addColumn<int>(name: "rowCount");
2201 QTest::addColumn<int>(name: "columnCount");
2202 QTest::addColumn<bool>(name: "showGrid");
2203 QTest::addColumn<int>(name: "cellWidth");
2204 QTest::addColumn<int>(name: "cellHeight");
2205 QTest::addColumn<int>(name: "rowHeight");
2206 QTest::addColumn<int>(name: "columnWidth");
2207
2208 QTest::newRow(dataTag: "10x10 grid not shown 60x60")
2209 << 10 << 10 << false << 60 << 60 << 60 << 60;
2210
2211 QTest::newRow(dataTag: "10x10 grid shown 60x60")
2212 << 10 << 10 << true << 60 << 60 << 61 << 61;
2213}
2214
2215void tst_QTableView::resizeColumnsToContents()
2216{
2217 QFETCH(int, rowCount);
2218 QFETCH(int, columnCount);
2219 QFETCH(bool, showGrid);
2220 QFETCH(int, cellWidth);
2221 QFETCH(int, cellHeight);
2222 QFETCH(int, rowHeight);
2223 QFETCH(int, columnWidth);
2224 Q_UNUSED(rowHeight)
2225
2226 QtTestTableModel model(rowCount, columnCount);
2227 QtTestTableView view;
2228 QtTestItemDelegate delegate;
2229
2230 view.setModel(&model);
2231 view.setItemDelegate(&delegate);
2232 view.setShowGrid(showGrid); // the grid will add to the row height
2233
2234 delegate.hint = QSize(cellWidth, cellHeight);
2235
2236 QSignalSpy resizedSpy(view.horizontalHeader(), &QHeaderView::sectionResized);
2237 view.resizeColumnsToContents();
2238
2239 QCOMPARE(resizedSpy.count(), model.columnCount());
2240 for (int c = 0; c < model.columnCount(); ++c)
2241 QCOMPARE(view.columnWidth(c), columnWidth);
2242}
2243
2244void tst_QTableView::rowViewportPosition_data()
2245{
2246 QTest::addColumn<int>(name: "rowCount");
2247 QTest::addColumn<int>(name: "rowHeight");
2248 QTest::addColumn<int>(name: "row");
2249 QTest::addColumn<QAbstractItemView::ScrollMode>(name: "verticalScrollMode");
2250 QTest::addColumn<int>(name: "verticalScrollValue");
2251 QTest::addColumn<int>(name: "rowViewportPosition");
2252
2253 QTest::newRow(dataTag: "row 0, scroll per item 0")
2254 << 10 << 40 << 0 << QAbstractItemView::ScrollPerItem << 0 << 0;
2255
2256 QTest::newRow(dataTag: "row 1, scroll per item, 0")
2257 << 10 << 40 << 1 << QAbstractItemView::ScrollPerItem << 0 << 1 * 40;
2258
2259 QTest::newRow(dataTag: "row 1, scroll per item, 1")
2260 << 10 << 40 << 1 << QAbstractItemView::ScrollPerItem << 1 << 0;
2261
2262 QTest::newRow(dataTag: "row 5, scroll per item, 0")
2263 << 10 << 40 << 5 << QAbstractItemView::ScrollPerItem << 0 << 5 * 40;
2264
2265 QTest::newRow(dataTag: "row 5, scroll per item, 5")
2266 << 10 << 40 << 5 << QAbstractItemView::ScrollPerItem << 5 << 0;
2267
2268 QTest::newRow(dataTag: "row 9, scroll per item, 0")
2269 << 10 << 40 << 9 << QAbstractItemView::ScrollPerItem << 0 << 9 * 40;
2270
2271 QTest::newRow(dataTag: "row 9, scroll per item, 5")
2272 << 10 << 40 << 9 << QAbstractItemView::ScrollPerItem << 5 << 4 * 40;
2273
2274 QTest::newRow(dataTag: "row 0, scroll per pixel 0")
2275 << 10 << 40 << 0 << QAbstractItemView::ScrollPerPixel << 0 << 0;
2276
2277 QTest::newRow(dataTag: "row 1, scroll per pixel, 0")
2278 << 10 << 40 << 1 << QAbstractItemView::ScrollPerPixel << 0 << 1 * 40;
2279
2280 QTest::newRow(dataTag: "row 1, scroll per pixel, 1")
2281 << 10 << 40 << 1 << QAbstractItemView::ScrollPerPixel << 1 * 40 << 0;
2282
2283 QTest::newRow(dataTag: "row 5, scroll per pixel, 0")
2284 << 10 << 40 << 5 << QAbstractItemView::ScrollPerPixel << 0 << 5 * 40;
2285
2286 QTest::newRow(dataTag: "row 5, scroll per pixel, 5")
2287 << 10 << 40 << 5 << QAbstractItemView::ScrollPerPixel << 5 * 40 << 0;
2288
2289 QTest::newRow(dataTag: "row 9, scroll per pixel, 0")
2290 << 10 << 40 << 9 << QAbstractItemView::ScrollPerPixel << 0 << 9 * 40;
2291
2292 QTest::newRow(dataTag: "row 9, scroll per pixel, 5")
2293 << 10 << 40 << 9 << QAbstractItemView::ScrollPerPixel << 5 * 40 << 4 * 40;
2294}
2295
2296void tst_QTableView::rowViewportPosition()
2297{
2298 QFETCH(int, rowCount);
2299 QFETCH(int, rowHeight);
2300 QFETCH(int, row);
2301 QFETCH(QAbstractItemView::ScrollMode, verticalScrollMode);
2302 QFETCH(int, verticalScrollValue);
2303 QFETCH(int, rowViewportPosition);
2304
2305 QtTestTableModel model(rowCount, 1);
2306 QtTestTableView view;
2307 setFrameless(&view);
2308 view.resize(w: 100, h: 2 * rowHeight);
2309 view.show();
2310
2311 view.setModel(&model);
2312 for (int r = 0; r < rowCount; ++r)
2313 view.setRowHeight(row: r, height: rowHeight);
2314
2315 view.setVerticalScrollMode(verticalScrollMode);
2316 view.verticalScrollBar()->setValue(verticalScrollValue);
2317
2318#ifdef Q_OS_WINRT
2319 QEXPECT_FAIL("row 1, scroll per item, 1", "Fails on WinRT - QTBUG-68297", Abort);
2320 QEXPECT_FAIL("row 5, scroll per item, 5", "Fails on WinRT - QTBUG-68297", Abort);
2321 QEXPECT_FAIL("row 9, scroll per item, 5", "Fails on WinRT - QTBUG-68297", Abort);
2322 QEXPECT_FAIL("row 1, scroll per pixel, 1", "Fails on WinRT - QTBUG-68297", Abort);
2323 QEXPECT_FAIL("row 5, scroll per pixel, 5", "Fails on WinRT - QTBUG-68297", Abort);
2324 QEXPECT_FAIL("row 9, scroll per pixel, 5", "Fails on WinRT - QTBUG-68297", Abort);
2325#endif
2326 QCOMPARE(view.rowViewportPosition(row), rowViewportPosition);
2327}
2328
2329void tst_QTableView::rowAt_data()
2330{
2331 QTest::addColumn<int>(name: "rowCount");
2332 QTest::addColumn<int>(name: "rowHeight");
2333 QTest::addColumn<IntList>(name: "hiddenRows");
2334 QTest::addColumn<int>(name: "coordinate");
2335 QTest::addColumn<int>(name: "row");
2336
2337 QTest::newRow(dataTag: "row at 100") << 5 << 40 << IntList() << 100 << 2;
2338 QTest::newRow(dataTag: "row at 180") << 5 << 40 << IntList() << 180 << 4;
2339 QTest::newRow(dataTag: "row at 20") << 5 << 40 << IntList() << 20 << 0;
2340
2341 // ### expand the dataset to include hidden rows
2342}
2343
2344void tst_QTableView::rowAt()
2345{
2346 QFETCH(int, rowCount);
2347 QFETCH(int, rowHeight);
2348 QFETCH(IntList, hiddenRows);
2349 QFETCH(int, coordinate);
2350 QFETCH(int, row);
2351
2352 QtTestTableModel model(rowCount, 1);
2353 QtTestTableView view;
2354 view.resize(w: 100, h: 2 * rowHeight);
2355
2356 view.setModel(&model);
2357
2358 for (int r = 0; r < rowCount; ++r)
2359 view.setRowHeight(row: r, height: rowHeight);
2360
2361 for (int i = 0; i < hiddenRows.count(); ++i)
2362 view.hideRow(row: hiddenRows.at(i));
2363
2364 QCOMPARE(view.rowAt(coordinate), row);
2365}
2366
2367void tst_QTableView::rowHeight_data()
2368{
2369 QTest::addColumn<int>(name: "rowCount");
2370 QTest::addColumn<IntList>(name: "rowHeights");
2371 QTest::addColumn<BoolList>(name: "hiddenRows");
2372
2373 QTest::newRow(dataTag: "increasing")
2374 << 5
2375 << (IntList() << 20 << 30 << 40 << 50 << 60)
2376 << (BoolList() << false << false << false << false << false);
2377
2378 QTest::newRow(dataTag: "decreasing")
2379 << 5
2380 << (IntList() << 60 << 50 << 40 << 30 << 20)
2381 << (BoolList() << false << false << false << false << false);
2382
2383 QTest::newRow(dataTag: "random")
2384 << 5
2385 << (IntList() << 87 << 34 << 68 << 91 << 27)
2386 << (BoolList() << false << false << false << false << false);
2387
2388 // ### expand the dataset to include hidden rows
2389}
2390
2391void tst_QTableView::rowHeight()
2392{
2393 QFETCH(int, rowCount);
2394 QFETCH(IntList, rowHeights);
2395 QFETCH(BoolList, hiddenRows);
2396
2397 QtTestTableModel model(rowCount, 1);
2398 QtTestTableView view;
2399
2400 view.setModel(&model);
2401
2402 for (int r = 0; r < rowCount; ++r) {
2403 view.setRowHeight(row: r, height: rowHeights.at(i: r));
2404 view.setRowHidden(row: r, hide: hiddenRows.at(i: r));
2405 }
2406
2407 for (int r = 0; r < rowCount; ++r) {
2408 if (hiddenRows.at(i: r))
2409 QCOMPARE(view.rowHeight(r), 0);
2410 else
2411 QCOMPARE(view.rowHeight(r), rowHeights.at(r));
2412 }
2413}
2414
2415void tst_QTableView::columnViewportPosition_data()
2416{
2417 QTest::addColumn<int>(name: "columnCount");
2418 QTest::addColumn<int>(name: "columnWidth");
2419 QTest::addColumn<int>(name: "column");
2420 QTest::addColumn<QAbstractItemView::ScrollMode>(name: "horizontalScrollMode");
2421 QTest::addColumn<int>(name: "horizontalScrollValue");
2422 QTest::addColumn<int>(name: "columnViewportPosition");
2423
2424 QTest::newRow(dataTag: "column 0, scroll per item 0")
2425 << 10 << 40 << 0 << QAbstractItemView::ScrollPerItem << 0 << 0;
2426
2427 QTest::newRow(dataTag: "column 1, scroll per item, 0")
2428 << 10 << 40 << 1 << QAbstractItemView::ScrollPerItem << 0 << 1 * 40;
2429
2430 QTest::newRow(dataTag: "column 1, scroll per item, 1")
2431 << 10 << 40 << 1 << QAbstractItemView::ScrollPerItem << 1 << 0;
2432
2433 QTest::newRow(dataTag: "column 5, scroll per item, 0")
2434 << 10 << 40 << 5 << QAbstractItemView::ScrollPerItem << 0 << 5 * 40;
2435
2436 QTest::newRow(dataTag: "column 5, scroll per item, 5")
2437 << 10 << 40 << 5 << QAbstractItemView::ScrollPerItem << 5 << 0;
2438
2439 QTest::newRow(dataTag: "column 9, scroll per item, 0")
2440 << 10 << 40 << 9 << QAbstractItemView::ScrollPerItem << 0 << 9 * 40;
2441
2442 QTest::newRow(dataTag: "column 9, scroll per item, 5")
2443 << 10 << 40 << 9 << QAbstractItemView::ScrollPerItem << 5 << 4 * 40;
2444
2445 QTest::newRow(dataTag: "column 0, scroll per pixel 0")
2446 << 10 << 40 << 0 << QAbstractItemView::ScrollPerPixel << 0 << 0;
2447
2448 QTest::newRow(dataTag: "column 1, scroll per pixel 0")
2449 << 10 << 40 << 1 << QAbstractItemView::ScrollPerPixel << 0 << 1 * 40;
2450
2451 QTest::newRow(dataTag: "column 1, scroll per pixel 1")
2452 << 10 << 40 << 1 << QAbstractItemView::ScrollPerPixel << 1 * 40 << 0;
2453
2454 QTest::newRow(dataTag: "column 5, scroll per pixel 0")
2455 << 10 << 40 << 5 << QAbstractItemView::ScrollPerPixel << 0 << 5 * 40;
2456
2457 QTest::newRow(dataTag: "column 5, scroll per pixel 5")
2458 << 10 << 40 << 5 << QAbstractItemView::ScrollPerPixel << 5 * 40 << 0;
2459
2460 QTest::newRow(dataTag: "column 9, scroll per pixel 0")
2461 << 10 << 40 << 9 << QAbstractItemView::ScrollPerPixel << 0 << 9 * 40;
2462
2463 QTest::newRow(dataTag: "column 9, scroll per pixel 5")
2464 << 10 << 40 << 9 << QAbstractItemView::ScrollPerPixel << 5 * 40 << 4 * 40;
2465}
2466
2467void tst_QTableView::columnViewportPosition()
2468{
2469 QFETCH(int, columnCount);
2470 QFETCH(int, columnWidth);
2471 QFETCH(int, column);
2472 QFETCH(QAbstractItemView::ScrollMode, horizontalScrollMode);
2473 QFETCH(int, horizontalScrollValue);
2474 QFETCH(int, columnViewportPosition);
2475
2476 QtTestTableModel model(1, columnCount);
2477 QtTestTableView view;
2478 setFrameless(&view);
2479 view.resize(w: 2 * columnWidth, h: 100);
2480 view.show();
2481
2482 view.setModel(&model);
2483 for (int c = 0; c < columnCount; ++c)
2484 view.setColumnWidth(column: c, width: columnWidth);
2485
2486 view.setHorizontalScrollMode(horizontalScrollMode);
2487 view.horizontalScrollBar()->setValue(horizontalScrollValue);
2488
2489#ifdef Q_OS_WINRT
2490 QEXPECT_FAIL("column 5, scroll per item, 5", "Fails on WinRT - QTBUG-68297", Abort);
2491 QEXPECT_FAIL("column 9, scroll per item, 5", "Fails on WinRT - QTBUG-68297", Abort);
2492 QEXPECT_FAIL("column 1, scroll per pixel 1", "Fails on WinRT - QTBUG-68297", Abort);
2493 QEXPECT_FAIL("column 5, scroll per pixel 5", "Fails on WinRT - QTBUG-68297", Abort);
2494 QEXPECT_FAIL("column 9, scroll per pixel 5", "Fails on WinRT - QTBUG-68297", Abort);
2495#endif
2496 QCOMPARE(view.columnViewportPosition(column), columnViewportPosition);
2497}
2498
2499void tst_QTableView::columnAt_data()
2500{
2501 QTest::addColumn<int>(name: "columnCount");
2502 QTest::addColumn<int>(name: "columnWidth");
2503 QTest::addColumn<IntList>(name: "hiddenColumns");
2504 QTest::addColumn<int>(name: "coordinate");
2505 QTest::addColumn<int>(name: "column");
2506
2507 QTest::newRow(dataTag: "column at 100") << 5 << 40 << IntList() << 100 << 2;
2508 QTest::newRow(dataTag: "column at 180") << 5 << 40 << IntList() << 180 << 4;
2509 QTest::newRow(dataTag: "column at 20") << 5 << 40 << IntList() << 20 << 0;
2510
2511 // ### expand the dataset to include hidden coumns
2512}
2513
2514void tst_QTableView::columnAt()
2515{
2516 QFETCH(int, columnCount);
2517 QFETCH(int, columnWidth);
2518 QFETCH(IntList, hiddenColumns);
2519 QFETCH(int, coordinate);
2520 QFETCH(int, column);
2521
2522 QtTestTableModel model(1, columnCount);
2523 QtTestTableView view;
2524 view.resize(w: 2 * columnWidth, h: 100);
2525
2526 view.setModel(&model);
2527
2528 for (int c = 0; c < columnCount; ++c)
2529 view.setColumnWidth(column: c, width: columnWidth);
2530
2531 for (int i = 0; i < hiddenColumns.count(); ++i)
2532 view.hideColumn(column: hiddenColumns.at(i));
2533
2534 QCOMPARE(view.columnAt(coordinate), column);
2535}
2536
2537void tst_QTableView::columnWidth_data()
2538{
2539 QTest::addColumn<int>(name: "columnCount");
2540 QTest::addColumn<IntList>(name: "columnWidths");
2541 QTest::addColumn<BoolList>(name: "hiddenColumns");
2542
2543 QTest::newRow(dataTag: "increasing")
2544 << 5
2545 << (IntList() << 20 << 30 << 40 << 50 << 60)
2546 << (BoolList() << false << false << false << false << false);
2547
2548 QTest::newRow(dataTag: "decreasing")
2549 << 5
2550 << (IntList() << 60 << 50 << 40 << 30 << 20)
2551 << (BoolList() << false << false << false << false << false);
2552
2553 QTest::newRow(dataTag: "random")
2554 << 5
2555 << (IntList() << 87 << 34 << 68 << 91 << 27)
2556 << (BoolList() << false << false << false << false << false);
2557
2558 // ### expand the dataset to include hidden columns
2559}
2560
2561void tst_QTableView::columnWidth()
2562{
2563 QFETCH(int, columnCount);
2564 QFETCH(IntList, columnWidths);
2565 QFETCH(BoolList, hiddenColumns);
2566
2567 QtTestTableModel model(1, columnCount);
2568 QtTestTableView view;
2569
2570 view.setModel(&model);
2571
2572 for (int c = 0; c < columnCount; ++c) {
2573 view.setColumnWidth(column: c, width: columnWidths.at(i: c));
2574 view.setColumnHidden(column: c, hide: hiddenColumns.at(i: c));
2575 }
2576
2577 for (int c = 0; c < columnCount; ++c) {
2578 if (hiddenColumns.at(i: c))
2579 QCOMPARE(view.columnWidth(c), 0);
2580 else
2581 QCOMPARE(view.columnWidth(c), columnWidths.at(c));
2582 }
2583}
2584
2585void tst_QTableView::hiddenRow_data()
2586{
2587 QTest::addColumn<int>(name: "rowCount");
2588 QTest::addColumn<BoolList>(name: "hiddenRows");
2589
2590 QTest::newRow(dataTag: "first hidden")
2591 << 5 << (BoolList() << true << false << false << false << false);
2592
2593 QTest::newRow(dataTag: "last hidden")
2594 << 5 << (BoolList() << false << false << false << false << true);
2595
2596 QTest::newRow(dataTag: "none hidden")
2597 << 5 << (BoolList() << false << false << false << false << false);
2598
2599 QTest::newRow(dataTag: "all hidden")
2600 << 5 << (BoolList() << true << true << true << true << true);
2601 }
2602
2603void tst_QTableView::hiddenRow()
2604{
2605 QFETCH(int, rowCount);
2606 QFETCH(BoolList, hiddenRows);
2607
2608
2609 QtTestTableModel model(rowCount, 1);
2610 QtTestTableView view;
2611
2612 view.setModel(&model);
2613
2614 for (int r = 0; r < rowCount; ++r)
2615 QVERIFY(!view.isRowHidden(r));
2616
2617 for (int r = 0; r < rowCount; ++r)
2618 view.setRowHidden(row: r, hide: hiddenRows.at(i: r));
2619
2620 for (int r = 0; r < rowCount; ++r)
2621 QCOMPARE(view.isRowHidden(r), hiddenRows.at(r));
2622
2623 for (int r = 0; r < rowCount; ++r)
2624 view.setRowHidden(row: r, hide: false);
2625
2626 for (int r = 0; r < rowCount; ++r)
2627 QVERIFY(!view.isRowHidden(r));
2628}
2629
2630void tst_QTableView::hiddenColumn_data()
2631{
2632 QTest::addColumn<int>(name: "columnCount");
2633 QTest::addColumn<BoolList>(name: "hiddenColumns");
2634
2635 QTest::newRow(dataTag: "first hidden")
2636 << 5 << (BoolList() << true << false << false << false << false);
2637
2638 QTest::newRow(dataTag: "last hidden")
2639 << 5 << (BoolList() << false << false << false << false << true);
2640
2641 QTest::newRow(dataTag: "none hidden")
2642 << 5 << (BoolList() << false << false << false << false << false);
2643
2644 QTest::newRow(dataTag: "all hidden")
2645 << 5 << (BoolList() << true << true << true << true << true);
2646}
2647
2648void tst_QTableView::hiddenColumn()
2649{
2650 QFETCH(int, columnCount);
2651 QFETCH(BoolList, hiddenColumns);
2652
2653 QtTestTableModel model(1, columnCount);
2654 QtTestTableView view;
2655
2656 view.setModel(&model);
2657
2658 for (int c = 0; c < columnCount; ++c)
2659 QVERIFY(!view.isColumnHidden(c));
2660
2661 for (int c = 0; c < columnCount; ++c)
2662 view.setColumnHidden(column: c, hide: hiddenColumns.at(i: c));
2663
2664 for (int c = 0; c < columnCount; ++c)
2665 QCOMPARE(view.isColumnHidden(c), hiddenColumns.at(c));
2666
2667 for (int c = 0; c < columnCount; ++c)
2668 view.setColumnHidden(column: c, hide: false);
2669
2670 for (int c = 0; c < columnCount; ++c)
2671 QVERIFY(!view.isColumnHidden(c));
2672}
2673
2674void tst_QTableView::sortingEnabled_data()
2675{
2676// QTest::addColumn<int>("columnCount");
2677}
2678
2679void tst_QTableView::sortingEnabled()
2680{
2681// QFETCH(int, columnCount);
2682}
2683
2684void tst_QTableView::sortByColumn_data()
2685{
2686 QTest::addColumn<bool>(name: "sortingEnabled");
2687 QTest::newRow(dataTag: "sorting enabled") << true;
2688 QTest::newRow(dataTag: "sorting disabled") << false;
2689}
2690
2691// Checks sorting and that sortByColumn also sets the sortIndicator
2692void tst_QTableView::sortByColumn()
2693{
2694 QFETCH(bool, sortingEnabled);
2695 QTableView view;
2696 QStandardItemModel model(4, 2);
2697 QSortFilterProxyModel sfpm; // default QStandardItemModel does not support 'unsorted' state
2698 sfpm.setSourceModel(&model);
2699 model.setItem(row: 0, column: 0, item: new QStandardItem("b"));
2700 model.setItem(row: 1, column: 0, item: new QStandardItem("d"));
2701 model.setItem(row: 2, column: 0, item: new QStandardItem("c"));
2702 model.setItem(row: 3, column: 0, item: new QStandardItem("a"));
2703 model.setItem(row: 0, column: 1, item: new QStandardItem("e"));
2704 model.setItem(row: 1, column: 1, item: new QStandardItem("g"));
2705 model.setItem(row: 2, column: 1, item: new QStandardItem("h"));
2706 model.setItem(row: 3, column: 1, item: new QStandardItem("f"));
2707
2708 view.setSortingEnabled(sortingEnabled);
2709 view.setModel(&sfpm);
2710 view.show();
2711
2712 view.sortByColumn(column: 1, order: Qt::DescendingOrder);
2713 QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 1);
2714 QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("c"));
2715 QCOMPARE(view.model()->data(view.model()->index(1, 0)).toString(), QString::fromLatin1("d"));
2716 QCOMPARE(view.model()->data(view.model()->index(0, 1)).toString(), QString::fromLatin1("h"));
2717 QCOMPARE(view.model()->data(view.model()->index(1, 1)).toString(), QString::fromLatin1("g"));
2718
2719 view.sortByColumn(column: 0, order: Qt::AscendingOrder);
2720 QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 0);
2721 QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("a"));
2722 QCOMPARE(view.model()->data(view.model()->index(1, 0)).toString(), QString::fromLatin1("b"));
2723 QCOMPARE(view.model()->data(view.model()->index(0, 1)).toString(), QString::fromLatin1("f"));
2724 QCOMPARE(view.model()->data(view.model()->index(1, 1)).toString(), QString::fromLatin1("e"));
2725
2726 view.sortByColumn(column: -1, order: Qt::AscendingOrder);
2727 QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), -1);
2728 QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("b"));
2729 QCOMPARE(view.model()->data(view.model()->index(1, 0)).toString(), QString::fromLatin1("d"));
2730 QCOMPARE(view.model()->data(view.model()->index(0, 1)).toString(), QString::fromLatin1("e"));
2731 QCOMPARE(view.model()->data(view.model()->index(1, 1)).toString(), QString::fromLatin1("g"));
2732
2733 // a new 'sortByColumn()' should do a re-sort (e.g. due to the data changed), QTBUG-86268
2734 view.setModel(&model);
2735 view.sortByColumn(column: 0, order: Qt::AscendingOrder);
2736 QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("a"));
2737 model.setItem(row: 0, column: 0, item: new QStandardItem("x"));
2738 view.sortByColumn(column: 0, order: Qt::AscendingOrder);
2739 QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("b"));
2740}
2741
2742void tst_QTableView::scrollTo_data()
2743{
2744 QTest::addColumn<QAbstractItemView::ScrollMode>(name: "verticalScrollMode");
2745 QTest::addColumn<QAbstractItemView::ScrollMode>(name: "horizontalScrollMode");
2746 QTest::addColumn<int>(name: "rowCount");
2747 QTest::addColumn<int>(name: "columnCount");
2748 QTest::addColumn<int>(name: "rowHeight");
2749 QTest::addColumn<int>(name: "columnWidth");
2750 QTest::addColumn<int>(name: "hiddenRow");
2751 QTest::addColumn<int>(name: "hiddenColumn");
2752 QTest::addColumn<int>(name: "row");
2753 QTest::addColumn<int>(name: "column");
2754 QTest::addColumn<int>(name: "rowSpan");
2755 QTest::addColumn<int>(name: "columnSpan");
2756 QTest::addColumn<int>(name: "horizontalScroll");
2757 QTest::addColumn<int>(name: "verticalScroll");
2758 QTest::addColumn<QAbstractItemView::ScrollHint>(name: "scrollHint");
2759 QTest::addColumn<int>(name: "expectedHorizontalScroll");
2760 QTest::addColumn<int>(name: "expectedVerticalScroll");
2761
2762 QTest::newRow(dataTag: "no hidden, no span, no scroll, per item")
2763 << QAbstractItemView::ScrollPerItem
2764 << QAbstractItemView::ScrollPerItem
2765 << 10 << 10 // table
2766 << 80 << 80 // size
2767 << -1 << -1 // hide
2768 << 0 << 0 // cell
2769 << 1 << 1 // span
2770 << 0 << 0 // scroll
2771 << QAbstractItemView::PositionAtTop
2772 << 0 << 0; // expected
2773
2774 QTest::newRow(dataTag: "no hidden, no span, no scroll, per pixel")
2775 << QAbstractItemView::ScrollPerPixel
2776 << QAbstractItemView::ScrollPerPixel
2777 << 10 << 10 // table
2778 << 80 << 80 // size
2779 << -1 << -1 // hide
2780 << 0 << 0 // cell
2781 << 1 << 1 // span
2782 << 0 << 0 // scroll
2783 << QAbstractItemView::PositionAtTop
2784 << 0 << 0; // expected
2785
2786 QTest::newRow(dataTag: "hidden, no span, no scroll, per item")
2787 << QAbstractItemView::ScrollPerItem
2788 << QAbstractItemView::ScrollPerItem
2789 << 10 << 10 // table
2790 << 80 << 80 // size
2791 << 3 << 3 // hide
2792 << 5 << 5 // cell
2793 << 1 << 1 // span
2794 << 0 << 0 // scroll
2795 << QAbstractItemView::PositionAtTop
2796 << 4 << 4; // expected
2797}
2798
2799void tst_QTableView::scrollTo()
2800{
2801 QFETCH(QAbstractItemView::ScrollMode, horizontalScrollMode);
2802 QFETCH(QAbstractItemView::ScrollMode, verticalScrollMode);
2803 QFETCH(int, rowCount);
2804 QFETCH(int, columnCount);
2805 QFETCH(int, rowHeight);
2806 QFETCH(int, columnWidth);
2807 QFETCH(int, hiddenRow);
2808 QFETCH(int, hiddenColumn);
2809 QFETCH(int, row);
2810 QFETCH(int, column);
2811 QFETCH(int, rowSpan);
2812 QFETCH(int, columnSpan);
2813 QFETCH(int, horizontalScroll);
2814 QFETCH(int, verticalScroll);
2815 QFETCH(QAbstractItemView::ScrollHint, scrollHint);
2816 QFETCH(int, expectedHorizontalScroll);
2817 QFETCH(int, expectedVerticalScroll);
2818
2819 QtTestTableModel model(rowCount, columnCount);
2820 QWidget toplevel;
2821 setFrameless(&toplevel);
2822 QtTestTableView view(&toplevel);
2823
2824 toplevel.show();
2825 // resizing to this size will ensure that there can ONLY_BE_ONE_CELL inside the view.
2826 QSize forcedSize(columnWidth * 2, rowHeight * 2);
2827 view.resize(forcedSize);
2828 QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
2829 QTRY_COMPARE(view.size(), forcedSize);
2830
2831 view.setModel(&model);
2832 view.setSpan(row, column, rowSpan, columnSpan);
2833 view.hideRow(row: hiddenRow);
2834 view.hideColumn(column: hiddenColumn);
2835 view.setHorizontalScrollMode(horizontalScrollMode);
2836 view.setVerticalScrollMode(verticalScrollMode);
2837
2838 for (int r = 0; r < rowCount; ++r)
2839 view.setRowHeight(row: r, height: rowHeight);
2840 for (int c = 0; c < columnCount; ++c)
2841 view.setColumnWidth(column: c, width: columnWidth);
2842
2843 view.horizontalScrollBar()->setValue(horizontalScroll);
2844 view.verticalScrollBar()->setValue(verticalScroll);
2845
2846 QModelIndex index = model.index(row, column);
2847 QVERIFY(index.isValid());
2848 view.scrollTo(index, hint: scrollHint);
2849 QTRY_COMPARE(view.verticalScrollBar()->value(), expectedVerticalScroll);
2850 QTRY_COMPARE(view.horizontalScrollBar()->value(), expectedHorizontalScroll);
2851}
2852
2853void tst_QTableView::indexAt_data()
2854{
2855 QTest::addColumn<int>(name: "rowCount");
2856 QTest::addColumn<int>(name: "columnCount");
2857
2858 QTest::addColumn<int>(name: "rowHeight");
2859 QTest::addColumn<int>(name: "columnWidth");
2860
2861 QTest::addColumn<int>(name: "hiddenRow");
2862 QTest::addColumn<int>(name: "hiddenColumn");
2863
2864 QTest::addColumn<int>(name: "row");
2865 QTest::addColumn<int>(name: "column");
2866 QTest::addColumn<int>(name: "rowSpan");
2867 QTest::addColumn<int>(name: "columnSpan");
2868 QTest::addColumn<int>(name: "horizontalScroll");
2869 QTest::addColumn<int>(name: "verticalScroll");
2870 QTest::addColumn<int>(name: "x");
2871 QTest::addColumn<int>(name: "y");
2872 QTest::addColumn<int>(name: "expectedRow");
2873 QTest::addColumn<int>(name: "expectedColumn");
2874
2875 QTest::newRow(dataTag: "no hidden, no span, no scroll, (20,20)")
2876 << 10 << 10 // dim
2877 << 40 << 40 // size
2878 << -1 << -1 // hide
2879 << -1 << -1 // pos
2880 << 1 << 1 // span
2881 << 0 << 0 // scroll
2882 << 20 << 20 // point
2883 << 0 << 0; // expected
2884
2885 QTest::newRow(dataTag: "row hidden, no span, no scroll, at (20,20)")
2886 << 10 << 10 // dim
2887 << 40 << 40 // size
2888 << 0 << -1 // hide
2889 << -1 << -1 // pos
2890 << 1 << 1 // span
2891 << 0 << 0 // scroll
2892 << 20 << 20 // point
2893 << 1 << 0; // expected
2894
2895 QTest::newRow(dataTag: "col hidden, no span, no scroll, at (20,20)")
2896 << 10 << 10 // dim
2897 << 40 << 40 // size
2898 << -1 << 0 // hide
2899 << -1 << -1 // pos
2900 << 1 << 1 // span
2901 << 0 << 0 // scroll
2902 << 20 << 20 // point
2903 << 0 << 1; // expected
2904
2905 QTest::newRow(dataTag: "no hidden, row span, no scroll, at (60,20)")
2906 << 10 << 10 // dim
2907 << 40 << 40 // size
2908 << -1 << -1 // hide
2909 << 0 << 0 // pos
2910 << 2 << 1 // span
2911 << 0 << 0 // scroll
2912 << 20 << 60 // point
2913 << 0 << 0; // expected
2914
2915
2916 QTest::newRow(dataTag: "no hidden, col span, no scroll, at (60,20)")
2917 << 10 << 10 // dim
2918 << 40 << 40 // size
2919 << -1 << -1 // hide
2920 << 0 << 0 // pos
2921 << 1 << 2 // span
2922 << 0 << 0 // scroll
2923 << 60 << 20 // point
2924 << 0 << 0; // expected
2925
2926 QTest::newRow(dataTag: "no hidden, no span, scroll (5,0), at (20,20)")
2927 << 20 << 20 // dim
2928 << 40 << 40 // size
2929 << -1 << -1 // hide
2930 << -1 << -1 // pos
2931 << 1 << 1 // span
2932 << 5 << 0 // scroll
2933 << 20 << 20 // point
2934 << 0 << 5; // expected
2935
2936 QTest::newRow(dataTag: "no hidden, no span, scroll (0,5), at (20,20)")
2937 << 20 << 20 // dim
2938 << 40 << 40 // size
2939 << -1 << -1 // hide
2940 << -1 << -1 // pos
2941 << 1 << 1 // span
2942 << 0 << 5 // scroll
2943 << 20 << 20 // point
2944 << 5 << 0; // expected
2945
2946 QTest::newRow(dataTag: "no hidden, no span, scroll (5,5), at (20,20)")
2947 << 20 << 20 // dim
2948 << 40 << 40 // size
2949 << -1 << -1 // hide
2950 << -1 << -1 // pos
2951 << 1 << 1 // span
2952 << 5 << 5 // scroll
2953 << 20 << 20 // point
2954 << 5 << 5; // expected
2955}
2956
2957void tst_QTableView::indexAt()
2958{
2959 QFETCH(int, rowCount);
2960 QFETCH(int, columnCount);
2961 QFETCH(int, rowHeight);
2962 QFETCH(int, columnWidth);
2963 QFETCH(int, hiddenRow);
2964 QFETCH(int, hiddenColumn);
2965 QFETCH(int, row);
2966 QFETCH(int, column);
2967 QFETCH(int, rowSpan);
2968 QFETCH(int, columnSpan);
2969 QFETCH(int, horizontalScroll);
2970 QFETCH(int, verticalScroll);
2971 QFETCH(int, x);
2972 QFETCH(int, y);
2973 QFETCH(int, expectedRow);
2974 QFETCH(int, expectedColumn);
2975
2976 QtTestTableModel model(rowCount, columnCount);
2977 QWidget toplevel;
2978 QtTestTableView view(&toplevel);
2979
2980 toplevel.show();
2981 QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
2982
2983 //some styles change the scroll mode in their polish
2984 view.setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
2985 view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
2986
2987 view.setModel(&model);
2988 view.setSpan(row, column, rowSpan, columnSpan);
2989 view.hideRow(row: hiddenRow);
2990 view.hideColumn(column: hiddenColumn);
2991
2992 for (int r = 0; r < rowCount; ++r)
2993 view.setRowHeight(row: r, height: rowHeight);
2994 for (int c = 0; c < columnCount; ++c)
2995 view.setColumnWidth(column: c, width: columnWidth);
2996
2997 view.horizontalScrollBar()->setValue(horizontalScroll);
2998 view.verticalScrollBar()->setValue(verticalScroll);
2999
3000 QModelIndex index = view.indexAt(p: QPoint(x, y));
3001 QTRY_COMPARE(index.row(), expectedRow);
3002 QTRY_COMPARE(index.column(), expectedColumn);
3003}
3004
3005void tst_QTableView::span_data()
3006{
3007 QTest::addColumn<int>(name: "rowCount");
3008 QTest::addColumn<int>(name: "columnCount");
3009 QTest::addColumn<int>(name: "hiddenRow");
3010 QTest::addColumn<int>(name: "hiddenColumn");
3011 QTest::addColumn<int>(name: "row");
3012 QTest::addColumn<int>(name: "column");
3013 QTest::addColumn<int>(name: "rowSpan");
3014 QTest::addColumn<int>(name: "columnSpan");
3015 QTest::addColumn<int>(name: "expectedRowSpan");
3016 QTest::addColumn<int>(name: "expectedColumnSpan");
3017 QTest::addColumn<bool>(name: "clear");
3018
3019 QTest::newRow(dataTag: "top left 2x2")
3020 << 10 << 10
3021 << -1 << -1
3022 << 0 << 0
3023 << 2 << 2
3024 << 2 << 2
3025 << false;
3026
3027 QTest::newRow(dataTag: "top left 1x2")
3028 << 10 << 10
3029 << 3 << 3
3030 << 0 << 0
3031 << 1 << 2
3032 << 1 << 2
3033 << false;
3034
3035 QTest::newRow(dataTag: "top left 2x1")
3036 << 10 << 10
3037 << -1 << -1
3038 << 0 << 0
3039 << 2 << 1
3040 << 2 << 1
3041 << false;
3042
3043 /* This makes no sens.
3044 QTest::newRow("top left 2x0")
3045 << 10 << 10
3046 << -1 << -1
3047 << 0 << 0
3048 << 2 << 0
3049 << 2 << 0
3050 << false;
3051
3052 QTest::newRow("top left 0x2")
3053 << 10 << 10
3054 << -1 << -1
3055 << 0 << 0
3056 << 0 << 2
3057 << 0 << 2
3058 << false;*/
3059
3060 QTest::newRow(dataTag: "invalid 2x2")
3061 << 10 << 10
3062 << -1 << -1
3063 << -1 << -1
3064 << 2 << 2
3065 << 1 << 1
3066 << false;
3067
3068 QTest::newRow(dataTag: "top left 2x2")
3069 << 10 << 10
3070 << -1 << -1
3071 << 0 << 0
3072 << 2 << 2
3073 << 2 << 2
3074 << false;
3075
3076 QTest::newRow(dataTag: "bottom right 2x2")
3077 << 10 << 10
3078 << -1 << -1
3079 << 8 << 8
3080 << 2 << 2
3081 << 2 << 2
3082 << false;
3083
3084 QTest::newRow(dataTag: "invalid span 2x2")
3085 << 10 << 10
3086 << -1 << -1
3087 << 8 << 8
3088 << 2 << 2
3089 << 2 << 2
3090 << false;
3091
3092 QTest::newRow(dataTag: "invalid span 3x3")
3093 << 10 << 10
3094 << -1 << -1
3095 << 6 << 6
3096 << 3 << 3
3097 << 2 << 3
3098 << true;
3099
3100}
3101
3102void tst_QTableView::span()
3103{
3104 QFETCH(int, rowCount);
3105 QFETCH(int, columnCount);
3106 QFETCH(int, hiddenRow);
3107 QFETCH(int, hiddenColumn);
3108 QFETCH(int, row);
3109 QFETCH(int, column);
3110 QFETCH(int, rowSpan);
3111 QFETCH(int, columnSpan);
3112 QFETCH(int, expectedRowSpan);
3113 QFETCH(int, expectedColumnSpan);
3114 QFETCH(bool, clear);
3115
3116 QtTestTableModel model(rowCount, columnCount);
3117 QtTestTableView view;
3118
3119 view.setModel(&model);
3120 view.show();
3121
3122 view.setSpan(row, column, rowSpan, columnSpan);
3123 if (clear) {
3124 model.removeLastRow();
3125 model.removeLastRow();
3126 view.update();
3127 }
3128
3129 view.hideRow(row: hiddenRow);
3130 view.hideColumn(column: hiddenColumn);
3131 view.show();
3132
3133 QCOMPARE(view.rowSpan(row, column), expectedRowSpan);
3134 QCOMPARE(view.columnSpan(row, column), expectedColumnSpan);
3135
3136 if (hiddenRow > -1) {
3137 QModelIndex hidden = model.index(row: hiddenRow, column: columnCount - 1);
3138 QVERIFY(view.isIndexHidden(hidden));
3139 }
3140
3141 if (hiddenColumn > -1) {
3142 QModelIndex hidden = model.index(row: rowCount - 1, column: hiddenColumn);
3143 QVERIFY(view.isIndexHidden(hidden));
3144 }
3145
3146 view.clearSpans();
3147 QCOMPARE(view.rowSpan(row, column), 1);
3148 QCOMPARE(view.columnSpan(row, column), 1);
3149
3150 VERIFY_SPANS_CONSISTENCY(&view);
3151}
3152
3153void tst_QTableView::spans_data()
3154{
3155 QTest::addColumn<int>(name: "rows");
3156 QTest::addColumn<int>(name: "columns");
3157 QTest::addColumn<SpanList>(name: "spans");
3158 QTest::addColumn<bool>(name: "hideRowLastRowOfFirstSpan");
3159 QTest::addColumn<QPoint>(name: "pos");
3160 QTest::addColumn<int>(name: "expectedRowSpan");
3161 QTest::addColumn<int>(name: "expectedColumnSpan");
3162
3163 QTest::newRow(dataTag: "1x3 span, query 3,0")
3164 << 5 << 5
3165 << (SpanList() << QRect(3, 0, 1, 3))
3166 << false //no hidden row
3167 << QPoint(3, 0)
3168 << 1
3169 << 3;
3170
3171 QTest::newRow(dataTag: "1x3 span, query 3,1")
3172 << 5 << 5
3173 << (SpanList() << QRect(3, 0, 1, 3))
3174 << false //no hidden row
3175 << QPoint(3, 1)
3176 << 1
3177 << 3;
3178
3179 QTest::newRow(dataTag: "1x3 span, query 3,2")
3180 << 5 << 5
3181 << (SpanList() << QRect(3, 0, 1, 3))
3182 << false //no hidden row
3183 << QPoint(3, 2)
3184 << 1
3185 << 3;
3186
3187 QTest::newRow(dataTag: "two 1x2 spans at the same column, query at 3,0")
3188 << 5 << 5
3189 << (SpanList() << QRect(3, 0, 1, 2) << QRect(4, 0, 1, 2))
3190 << false //no hidden row
3191 << QPoint(3, 0)
3192 << 1
3193 << 2;
3194
3195 QTest::newRow(dataTag: "two 1x2 spans at the same column, query at 4,0")
3196 << 5 << 5
3197 << (SpanList() << QRect(3, 0, 1, 2) << QRect(4, 0, 1, 2))
3198 << false //no hidden row
3199 << QPoint(4, 0)
3200 << 1
3201 << 2;
3202
3203 QTest::newRow(dataTag: "how to order spans (1,1)")
3204 << 5 << 5
3205 << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
3206 << false //no hidden row
3207 << QPoint(1, 1)
3208 << 3
3209 << 1;
3210
3211 QTest::newRow(dataTag: "how to order spans (2,1)")
3212 << 5 << 5
3213 << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
3214 << false //no hidden row
3215 << QPoint(2, 1)
3216 << 3
3217 << 1;
3218
3219 QTest::newRow(dataTag: "how to order spans (3,1)")
3220 << 5 << 5
3221 << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
3222 << false //no hidden row
3223 << QPoint(3, 1)
3224 << 3
3225 << 1;
3226
3227 QTest::newRow(dataTag: "how to order spans (1,2)")
3228 << 5 << 5
3229 << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
3230 << false //no hidden row
3231 << QPoint(1, 2)
3232 << 2
3233 << 1;
3234
3235 QTest::newRow(dataTag: "how to order spans (2,2)")
3236 << 5 << 5
3237 << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
3238 << false //no hidden row
3239 << QPoint(2, 2)
3240 << 2
3241 << 1;
3242
3243 QTest::newRow(dataTag: "spans with hidden rows")
3244 << 3 << 2
3245 << (SpanList() << QRect(0, 0, 2, 2) << QRect(2, 0, 1, 2))
3246 << true //we hide the last row of the first span
3247 << QPoint(2, 0)
3248 << 1
3249 << 2;
3250
3251 QTest::newRow(dataTag: "QTBUG-6004: No failing assertion, then it passes.")
3252 << 5 << 5
3253 << (SpanList() << QRect(0, 0, 2, 2) << QRect(0, 0, 1, 1))
3254 << false
3255 << QPoint(0, 0)
3256 << 1
3257 << 1;
3258
3259 QTest::newRow(dataTag: "QTBUG-6004 (follow-up): No failing assertion, then it passes.")
3260 << 10 << 10
3261 << (SpanList() << QRect(2, 2, 1, 3) << QRect(2, 2, 1, 1))
3262 << false
3263 << QPoint(0, 0)
3264 << 1
3265 << 1;
3266
3267 QTest::newRow(dataTag: "QTBUG-9631: remove one span")
3268 << 10 << 10
3269 << (SpanList() << QRect(1, 1, 2, 1) << QRect(2, 2, 2, 2) << QRect(1, 1, 1, 1))
3270 << false
3271 << QPoint(1, 1)
3272 << 1
3273 << 1;
3274}
3275
3276void tst_QTableView::spans()
3277{
3278 QFETCH(int, rows);
3279 QFETCH(int, columns);
3280 QFETCH(const SpanList, spans);
3281 QFETCH(bool, hideRowLastRowOfFirstSpan);
3282 QFETCH(QPoint, pos);
3283 QFETCH(int, expectedRowSpan);
3284 QFETCH(int, expectedColumnSpan);
3285
3286 QtTestTableModel model(rows, columns);
3287 QtTestTableView view;
3288
3289 view.setModel(&model);
3290 view.show();
3291
3292 for (const auto &sp : spans)
3293 view.setSpan(row: sp.x(), column: sp.y(), rowSpan: sp.width(), columnSpan: sp.height());
3294
3295 if (hideRowLastRowOfFirstSpan) {
3296 view.setRowHidden(row: spans.at(i: 0).bottom(), hide: true);
3297 //we check that the span didn't break the visual rects of the model indexes
3298 QRect first = view.visualRect( index: model.index(row: spans.at(i: 0).top(), column: 0));
3299 QRect next = view.visualRect( index: model.index(row: spans.at(i: 0).bottom() + 1, column: 0));
3300 QVERIFY(first.intersected(next).isEmpty());
3301 }
3302
3303 QCOMPARE(view.columnSpan(pos.x(), pos.y()), expectedColumnSpan);
3304 QCOMPARE(view.rowSpan(pos.x(), pos.y()), expectedRowSpan);
3305
3306 VERIFY_SPANS_CONSISTENCY(&view);
3307}
3308
3309void tst_QTableView::spansAfterRowInsertion()
3310{
3311 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
3312 QSKIP("Wayland: This fails. Figure out why.");
3313
3314 QtTestTableModel model(10, 10);
3315 QtTestTableView view;
3316 view.setModel(&model);
3317 view.setSpan(row: 3, column: 3, rowSpan: 3, columnSpan: 3);
3318 view.show();
3319 QVERIFY(QTest::qWaitForWindowActive(&view));
3320
3321 // Insertion before the span only shifts the span.
3322 view.model()->insertRows(row: 0, count: 2);
3323 QCOMPARE(view.rowSpan(3, 3), 1);
3324 QCOMPARE(view.columnSpan(3, 3), 1);
3325 QCOMPARE(view.rowSpan(5, 3), 3);
3326 QCOMPARE(view.columnSpan(5, 3), 3);
3327
3328 // Insertion happens before the given row, so it only shifts the span also.
3329 view.model()->insertRows(row: 5, count: 2);
3330 QCOMPARE(view.rowSpan(5, 3), 1);
3331 QCOMPARE(view.columnSpan(5, 3), 1);
3332 QCOMPARE(view.rowSpan(7, 3), 3);
3333 QCOMPARE(view.columnSpan(7, 3), 3);
3334
3335 // Insertion inside the span expands it.
3336 view.model()->insertRows(row: 8, count: 2);
3337 QCOMPARE(view.rowSpan(7, 3), 5);
3338 QCOMPARE(view.columnSpan(7, 3), 3);
3339
3340 // Insertion after the span does nothing to it.
3341 view.model()->insertRows(row: 12, count: 2);
3342 QCOMPARE(view.rowSpan(7, 3), 5);
3343 QCOMPARE(view.columnSpan(7, 3), 3);
3344
3345 VERIFY_SPANS_CONSISTENCY(&view);
3346}
3347
3348void tst_QTableView::spansAfterColumnInsertion()
3349{
3350 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
3351 QSKIP("Wayland: This fails. Figure out why.");
3352
3353 QtTestTableModel model(10, 10);
3354 QtTestTableView view;
3355 view.setModel(&model);
3356 view.setSpan(row: 3, column: 3, rowSpan: 3, columnSpan: 3);
3357 view.show();
3358 QVERIFY(QTest::qWaitForWindowActive(&view));
3359
3360 // Insertion before the span only shifts the span.
3361 view.model()->insertColumns(column: 0, count: 2);
3362 QCOMPARE(view.rowSpan(3, 3), 1);
3363 QCOMPARE(view.columnSpan(3, 3), 1);
3364 QCOMPARE(view.rowSpan(3, 5), 3);
3365 QCOMPARE(view.columnSpan(3, 5), 3);
3366
3367 // Insertion happens before the given column, so it only shifts the span also.
3368 view.model()->insertColumns(column: 5, count: 2);
3369 QCOMPARE(view.rowSpan(3, 5), 1);
3370 QCOMPARE(view.columnSpan(3, 5), 1);
3371 QCOMPARE(view.rowSpan(3, 7), 3);
3372 QCOMPARE(view.columnSpan(3, 7), 3);
3373
3374 // Insertion inside the span expands it.
3375 view.model()->insertColumns(column: 8, count: 2);
3376 QCOMPARE(view.rowSpan(3, 7), 3);
3377 QCOMPARE(view.columnSpan(3, 7), 5);
3378
3379 // Insertion after the span does nothing to it.
3380 view.model()->insertColumns(column: 12, count: 2);
3381 QCOMPARE(view.rowSpan(3, 7), 3);
3382 QCOMPARE(view.columnSpan(3, 7), 5);
3383
3384 VERIFY_SPANS_CONSISTENCY(&view);
3385}
3386
3387void tst_QTableView::spansAfterRowRemoval()
3388{
3389 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
3390 QSKIP("Wayland: This fails. Figure out why.");
3391
3392 QtTestTableModel model(10, 10);
3393 QtTestTableView view;
3394 view.setModel(&model);
3395
3396 static const QRect spans[] = {
3397 {0, 1, 1, 2},
3398 {1, 2, 1, 2},
3399 {2, 2, 1, 5},
3400 {2, 8, 1, 2},
3401 {3, 4, 1, 2},
3402 {4, 4, 1, 4},
3403 {5, 6, 1, 3},
3404 {6, 7, 1, 3}
3405 };
3406 for (const QRect &span : spans)
3407 view.setSpan(row: span.top(), column: span.left(), rowSpan: span.height(), columnSpan: span.width());
3408
3409 view.show();
3410 QVERIFY(QTest::qWaitForWindowActive(&view));
3411 view.model()->removeRows(row: 3, count: 3);
3412
3413 static const QRect expectedSpans[] = {
3414 {0, 1, 1, 2},
3415 {1, 2, 1, 1},
3416 {2, 2, 1, 2},
3417 {2, 5, 1, 2},
3418 {3, 4, 1, 1},
3419 {4, 3, 1, 2},
3420 {5, 3, 1, 3},
3421 {6, 4, 1, 3}
3422 };
3423 for (const QRect &span : expectedSpans) {
3424 QCOMPARE(view.columnSpan(span.top(), span.left()), span.width());
3425 QCOMPARE(view.rowSpan(span.top(), span.left()), span.height());
3426 }
3427
3428 VERIFY_SPANS_CONSISTENCY(&view);
3429}
3430
3431void tst_QTableView::spansAfterColumnRemoval()
3432{
3433 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
3434 QSKIP("Wayland: This fails. Figure out why.");
3435
3436 QtTestTableModel model(10, 10);
3437 QtTestTableView view;
3438 view.setModel(&model);
3439
3440 // Same set as above just swapping columns and rows.
3441 static const QRect spans[] = {
3442 {0, 1, 1, 2},
3443 {1, 2, 1, 2},
3444 {2, 2, 1, 5},
3445 {2, 8, 1, 2},
3446 {3, 4, 1, 2},
3447 {4, 4, 1, 4},
3448 {5, 6, 1, 3},
3449 {6, 7, 1, 3}
3450 };
3451 for (const QRect &span : spans)
3452 view.setSpan(row: span.left(), column: span.top(), rowSpan: span.width(), columnSpan: span.height());
3453
3454 view.show();
3455 QVERIFY(QTest::qWaitForWindowActive(&view));
3456 view.model()->removeColumns(column: 3, count: 3);
3457
3458 static const QRect expectedSpans[] = {
3459 {0, 1, 1, 2},
3460 {1, 2, 1, 1},
3461 {2, 2, 1, 2},
3462 {2, 5, 1, 2},
3463 {3, 4, 1, 1},
3464 {4, 3, 1, 2},
3465 {5, 3, 1, 3},
3466 {6, 4, 1, 3}
3467 };
3468 for (const QRect &span : expectedSpans) {
3469 QCOMPARE(view.columnSpan(span.left(), span.top()), span.height());
3470 QCOMPARE(view.rowSpan(span.left(), span.top()), span.width());
3471 }
3472
3473 VERIFY_SPANS_CONSISTENCY(&view);
3474}
3475
3476void tst_QTableView::editSpanFromDirections_data()
3477{
3478 QTest::addColumn<KeyList>(name: "keyPresses");
3479 QTest::addColumn<QSharedPointer<QStandardItemModel>>(name: "model");
3480 QTest::addColumn<int>(name: "row");
3481 QTest::addColumn<int>(name: "column");
3482 QTest::addColumn<int>(name: "rowSpan");
3483 QTest::addColumn<int>(name: "columnSpan");
3484 QTest::addColumn<QModelIndex>(name: "expectedVisualCursorIndex");
3485 QTest::addColumn<QModelIndex>(name: "expectedEditedIndex");
3486
3487 /* x = the cell that should be edited
3488 c = the cell that should actually be the current index
3489 +---+---+
3490 | | |
3491 +---+---+
3492 | | x |
3493 +---+ +
3494 | | c |
3495 +---+---+
3496 | | ^ |
3497 +---+---+ */
3498 KeyList keyPresses {Qt::Key_Right, Qt::Key_PageDown, Qt::Key_Up};
3499 QSharedPointer<QStandardItemModel> model(new QStandardItemModel(4, 2));
3500 QTest::newRow(dataTag: "row span, bottom up")
3501 << keyPresses << model << 1 << 1 << 2 << 1 << model->index(row: 2, column: 1) << model->index(row: 1, column: 1);
3502
3503 /* +---+---+
3504 | | v |
3505 +---+---+
3506 | |x,c|
3507 +---+ +
3508 | | |
3509 +---+---+
3510 | | |
3511 +---+---+ */
3512 keyPresses = {Qt::Key_Right, Qt::Key_Down};
3513 model = QSharedPointer<QStandardItemModel>::create(arguments: 4, arguments: 2);
3514 QTest::newRow(dataTag: "row span, top down")
3515 << keyPresses << model << 1 << 1 << 2 << 1 << model->index(row: 1, column: 1) << model->index(row: 1, column: 1);
3516
3517 /* +---+---+---+
3518 | | | |
3519 +---+---+---+
3520 | |x,c| < |
3521 +---+ +---+
3522 | | | |
3523 +---+---+---+ */
3524 keyPresses = {Qt::Key_End, Qt::Key_Down, Qt::Key_Left};
3525 model = QSharedPointer<QStandardItemModel>::create(arguments: 3, arguments: 3);
3526 QTest::newRow(dataTag: "row span, right to left")
3527 << keyPresses << model << 1 << 1 << 2 << 1 << model->index(row: 1, column: 1) << model->index(row: 1, column: 1);
3528
3529 /* +---+---+---+
3530 | | | |
3531 +---+---+---+
3532 | | x | |
3533 +---+ +---+
3534 | > | c | |
3535 +---+---+---+ */
3536 keyPresses = {Qt::Key_PageDown, Qt::Key_Right};
3537 model = QSharedPointer<QStandardItemModel>::create(arguments: 3, arguments: 3);
3538 QTest::newRow(dataTag: "row span, left to right")
3539 << keyPresses << model << 1 << 1 << 2 << 1 << model->index(row: 2, column: 1) << model->index(row: 1, column: 1);
3540
3541 /* +---+---+---+
3542 | | | |
3543 +---+---+---+
3544 |x,c |
3545 +---+---+---+
3546 | ^ | | |
3547 +---+---+---+ */
3548 keyPresses = {Qt::Key_PageDown, Qt::Key_Up};
3549 model = QSharedPointer<QStandardItemModel>::create(arguments: 3, arguments: 3);
3550 QTest::newRow(dataTag: "col span, bottom up")
3551 << keyPresses << model << 1 << 0 << 1 << 3 << model->index(row: 1, column: 0) << model->index(row: 1, column: 0);
3552
3553 /* +---+---+---+
3554 | | | |
3555 +---+---+---+
3556 | x c |
3557 +---+---+---+
3558 | | ^ | |
3559 +---+---+---+ */
3560 keyPresses = {Qt::Key_PageDown, Qt::Key_Right, Qt::Key_Up};
3561 model = QSharedPointer<QStandardItemModel>::create(arguments: 3, arguments: 3);
3562 QTest::newRow(dataTag: "col span, bottom up #2")
3563 << keyPresses << model << 1 << 0 << 1 << 3 << model->index(row: 1, column: 1) << model->index(row: 1, column: 0);
3564
3565 /* +---+---+---+
3566 | | | v |
3567 +---+---+---+
3568 | x c |
3569 +---+---+---+
3570 | | | |
3571 +---+---+---+ */
3572 keyPresses = {Qt::Key_End, Qt::Key_Down};
3573 model = QSharedPointer<QStandardItemModel>::create(arguments: 3, arguments: 3);
3574 QTest::newRow(dataTag: "col span, top down")
3575 << keyPresses << model << 1 << 0 << 1 << 3 << model->index(row: 1, column: 2) << model->index(row: 1, column: 0);
3576}
3577
3578class TableViewWithCursorExposed : public QTableView
3579{
3580public:
3581 using QTableView::QTableView;
3582
3583 QModelIndex visualCursorIndex()
3584 {
3585 QTableViewPrivate *d = static_cast<QTableViewPrivate*>(qt_widget_private(widget: this));
3586 return d->model->index(row: d->visualCursor.y(), column: d->visualCursor.x());
3587 }
3588};
3589
3590void tst_QTableView::editSpanFromDirections()
3591{
3592 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
3593 QSKIP("Wayland: This fails. Figure out why.");
3594
3595 QFETCH(const KeyList, keyPresses);
3596 QFETCH(QSharedPointer<QStandardItemModel>, model);
3597 QFETCH(int, row);
3598 QFETCH(int, column);
3599 QFETCH(int, rowSpan);
3600 QFETCH(int, columnSpan);
3601 QFETCH(QModelIndex, expectedVisualCursorIndex);
3602 QFETCH(QModelIndex, expectedEditedIndex);
3603
3604 TableViewWithCursorExposed view;
3605 view.setModel(model.data());
3606 // we have to make sure that PgUp/PgDown can scroll to the bottom/top
3607 view.resize(w: view.horizontalHeader()->length() + 50,
3608 h: view.verticalHeader()->length() + 50);
3609 view.setSpan(row, column, rowSpan, columnSpan);
3610 view.show();
3611 QVERIFY(QTest::qWaitForWindowActive(&view));
3612
3613 for (Qt::Key key : keyPresses)
3614 QTest::keyClick(widget: &view, key);
3615 QCOMPARE(view.visualCursorIndex(), expectedVisualCursorIndex);
3616 QCOMPARE(view.selectionModel()->currentIndex(), expectedEditedIndex);
3617
3618 QTest::keyClick(widget: &view, key: Qt::Key_X);
3619 QTest::keyClick(widget: QApplication::focusWidget(), key: Qt::Key_Enter);
3620 QTRY_COMPARE(view.model()->data(expectedEditedIndex).toString(), QLatin1String("x"));
3621}
3622
3623class Model : public QAbstractTableModel
3624{
3625 Q_OBJECT
3626public:
3627 using QAbstractTableModel::QAbstractTableModel;
3628
3629 int rowCount(const QModelIndex &) const override
3630 {
3631 return rows;
3632 }
3633 int columnCount(const QModelIndex &) const override
3634 {
3635 return columns;
3636 }
3637 QVariant data(const QModelIndex &, int) const override
3638 {
3639 return QVariant();
3640 }
3641 void res()
3642 {
3643 beginResetModel();
3644 endResetModel();
3645 }
3646
3647 int rows = 0;
3648 int columns = 0;
3649};
3650
3651void tst_QTableView::checkHeaderReset()
3652{
3653 QTableView view;
3654 Model m;
3655 m.rows = 3;
3656 m.columns = 3;
3657 view.setModel(&m);
3658
3659 m.rows = 4;
3660 m.columns = 4;
3661 m.res();
3662 QCOMPARE(view.horizontalHeader()->count(), 4);
3663}
3664
3665void tst_QTableView::checkHeaderMinSize()
3666{
3667 //tests if the minimumsize is of a header is taken into account
3668 //while computing QTableView geometry. For that we test the position of the
3669 //viewport.
3670 QTableView view;
3671 QStringListModel m;
3672 m.setStringList({QLatin1String("one cell is enough")});
3673 view.setModel(&m);
3674
3675 //setting the minimum height on the horizontal header
3676 //and the minimum width on the vertical header
3677 view.horizontalHeader()->setMinimumHeight(50);
3678 view.verticalHeader()->setMinimumWidth(100);
3679
3680 view.show();
3681
3682 QVERIFY( view.verticalHeader()->y() >= view.horizontalHeader()->minimumHeight());
3683 QVERIFY( view.horizontalHeader()->x() >= view.verticalHeader()->minimumWidth());
3684}
3685
3686void tst_QTableView::resizeToContents()
3687{
3688 //checks that the resize to contents is consistent
3689 QTableWidget table(2,3);
3690 QTableWidget table2(2,3);
3691 QTableWidget table3(2,3);
3692
3693
3694 table.setHorizontalHeaderItem(column: 0, item: new QTableWidgetItem("A Lot of text here: BLA BLA BLA"));
3695 table2.setHorizontalHeaderItem(column: 0, item: new QTableWidgetItem("A Lot of text here: BLA BLA BLA"));
3696 table3.setHorizontalHeaderItem(column: 0, item: new QTableWidgetItem("A Lot of text here: BLA BLA BLA"));
3697 table.horizontalHeader()->setVisible(false);
3698 table2.horizontalHeader()->setVisible(false);
3699 table.verticalHeader()->setVisible(false);
3700 table2.verticalHeader()->setVisible(false);
3701
3702
3703 for (int i = 0; i < table.columnCount(); i++)
3704 table.resizeColumnToContents(column: i);
3705 for (int i = 0; i < table.rowCount(); i++)
3706 table.resizeRowToContents(row: i);
3707 table2.resizeColumnsToContents();
3708 table2.resizeRowsToContents();
3709 table3.resizeColumnsToContents();
3710 table3.resizeRowsToContents();
3711
3712 //now let's check the row/col sizes
3713 for (int i = 0; i < table.columnCount(); i++) {
3714 QCOMPARE(table.columnWidth(i), table2.columnWidth(i));
3715 QCOMPARE(table2.columnWidth(i), table3.columnWidth(i));
3716 }
3717 for (int i = 0; i < table.rowCount(); i++) {
3718 QCOMPARE(table.rowHeight(i), table2.rowHeight(i));
3719 QCOMPARE(table2.rowHeight(i), table3.rowHeight(i));
3720 }
3721
3722}
3723
3724QT_BEGIN_NAMESPACE
3725extern bool Q_WIDGETS_EXPORT qt_tab_all_widgets(); // qapplication.cpp
3726QT_END_NAMESPACE
3727
3728void tst_QTableView::tabFocus()
3729{
3730 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
3731 QSKIP("Wayland: This fails. Figure out why.");
3732
3733 if (!qt_tab_all_widgets())
3734 QSKIP("This test requires full keyboard control to be enabled.");
3735
3736 // QTableView enables tabKeyNavigation by default, but you should be able
3737 // to change focus on an empty table view, or on a table view that doesn't
3738 // have this property set.
3739 QWidget window;
3740 window.resize(w: 200, h: 200);
3741
3742 QTableView *view = new QTableView(&window);
3743 QLineEdit *edit = new QLineEdit(&window);
3744
3745 window.show();
3746 QApplication::setActiveWindow(&window);
3747 window.setFocus();
3748 window.activateWindow();
3749 QVERIFY(QTest::qWaitForWindowActive(&window));
3750
3751 // window
3752 QVERIFY(window.hasFocus());
3753 QVERIFY(!view->hasFocus());
3754 QVERIFY(!edit->hasFocus());
3755
3756 for (int i = 0; i < 2; ++i) {
3757 // tab to view
3758 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Tab);
3759 QTRY_VERIFY(!window.hasFocus());
3760 QVERIFY(view->hasFocus());
3761 QVERIFY(!edit->hasFocus());
3762
3763 // tab to edit
3764 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Tab);
3765 QTRY_VERIFY(edit->hasFocus());
3766 QVERIFY(!window.hasFocus());
3767 QVERIFY(!view->hasFocus());
3768 }
3769
3770 // backtab to view
3771 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Backtab);
3772 QTRY_VERIFY(view->hasFocus());
3773 QVERIFY(!window.hasFocus());
3774 QVERIFY(!edit->hasFocus());
3775
3776 // backtab to edit
3777 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Backtab);
3778 QTRY_VERIFY(edit->hasFocus());
3779 QVERIFY(!window.hasFocus());
3780 QVERIFY(!view->hasFocus());
3781
3782 QStandardItemModel model;
3783 view->setModel(&model);
3784
3785 // backtab to view
3786 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Backtab);
3787 QTRY_VERIFY(view->hasFocus());
3788 QVERIFY(!window.hasFocus());
3789 QVERIFY(!edit->hasFocus());
3790
3791 // backtab to edit
3792 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Backtab);
3793 QTRY_VERIFY(edit->hasFocus());
3794 QVERIFY(!window.hasFocus());
3795 QVERIFY(!view->hasFocus());
3796
3797 model.insertRow(arow: 0, aitem: new QStandardItem("Hei"));
3798 model.insertRow(arow: 0, aitem: new QStandardItem("Hei"));
3799 model.insertRow(arow: 0, aitem: new QStandardItem("Hei"));
3800
3801 // backtab to view
3802 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Backtab);
3803 QTRY_VERIFY(view->hasFocus());
3804 QVERIFY(!window.hasFocus());
3805 QVERIFY(!edit->hasFocus());
3806
3807 // backtab to edit doesn't work
3808 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Backtab);
3809 QVERIFY(!window.hasFocus());
3810 QVERIFY(view->hasFocus());
3811 QVERIFY(!edit->hasFocus());
3812
3813 view->setTabKeyNavigation(false);
3814
3815 // backtab to edit
3816 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Backtab);
3817 QTRY_VERIFY(edit->hasFocus());
3818 QVERIFY(!window.hasFocus());
3819 QVERIFY(!view->hasFocus());
3820
3821 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Tab);
3822 QTRY_VERIFY(view->hasFocus());
3823 QTest::keyPress(widget: QApplication::focusWidget(), key: Qt::Key_Tab);
3824 QTRY_VERIFY(edit->hasFocus());
3825}
3826
3827class BigModel : public QAbstractTableModel
3828{
3829 Q_OBJECT
3830public:
3831 QVariant data(const QModelIndex &index,
3832 int role = Qt::DisplayRole) const override
3833 {
3834 if (role == Qt::DisplayRole)
3835 return QString::number(index.column()) + QLatin1String(" - ") + QString::number(index.row());
3836 return QVariant();
3837 }
3838
3839 int rowCount(const QModelIndex &parent = QModelIndex()) const override
3840 {
3841 Q_UNUSED(parent)
3842 return 10000000;
3843 }
3844
3845 int columnCount(const QModelIndex &parent = QModelIndex()) const override
3846 {
3847 Q_UNUSED(parent)
3848 return 20000000;
3849 }
3850};
3851
3852void tst_QTableView::bigModel()
3853{
3854 //should not crash
3855 QTableView view;
3856 BigModel model;
3857 view.setModel(&model);
3858 view.show();
3859 view.setSpan(row: 10002,column: 10002,rowSpan: 6,columnSpan: 6);
3860 QTest::qWait(ms: 100);
3861 view.resize(w: 1000,h: 1000);
3862 QTest::qWait(ms: 100);
3863 view.scrollTo(index: model.index(row: 10010,column: 10010));
3864 QTest::qWait(ms: 100);
3865}
3866
3867void tst_QTableView::selectionSignal()
3868{
3869 QtTestTableModel model(10, 10);
3870 QtTestTableView view;
3871 view.checkSignalOrder = true;
3872 view.setModel(&model);
3873 view.resize(w: 200, h: 200);
3874 view.show();
3875 QVERIFY(QTest::qWaitForWindowExposed(&view));
3876 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: view.visualRect(index: model.index(row: 2, column: 0)).center());
3877}
3878
3879void tst_QTableView::setCurrentIndex()
3880{
3881 QtTestTableModel model(4, 4);
3882 QtTestTableView view;
3883 view.setModel(&model);
3884
3885 // submit() slot should be called in model when current row changes
3886 view.setCurrentIndex(model.index(row: 0,column: 0));
3887 QCOMPARE(model.submit_count, 1);
3888 view.setCurrentIndex(model.index(row: 0,column: 2));
3889 QCOMPARE(model.submit_count, 1);
3890 view.setCurrentIndex(model.index(row: 1,column: 0));
3891 QCOMPARE(model.submit_count, 2);
3892 view.setCurrentIndex(model.index(row: 3,column: 3));
3893 QCOMPARE(model.submit_count, 3);
3894 view.setCurrentIndex(model.index(row: 0,column: 1));
3895 QCOMPARE(model.submit_count, 4);
3896 view.setCurrentIndex(model.index(row: 0,column: 0));
3897 QCOMPARE(model.submit_count, 4);
3898}
3899
3900class task173773_EventFilter : public QObject
3901{
3902 int paintEventCount_ = 0;
3903public:
3904 using QObject::QObject;
3905 int paintEventCount() const { return paintEventCount_; }
3906private:
3907 bool eventFilter(QObject *obj, QEvent *e) override
3908 {
3909 Q_UNUSED(obj)
3910 if (e->type() == QEvent::Paint)
3911 ++paintEventCount_;
3912 return false;
3913 }
3914};
3915
3916void tst_QTableView::task173773_updateVerticalHeader()
3917{
3918 QStandardItemModel model(2, 1);
3919 model.setData(index: model.index(row: 0, column: 0), value: 0);
3920 model.setData(index: model.index(row: 1, column: 0), value: 1);
3921
3922 QSortFilterProxyModel proxyModel;
3923 proxyModel.setSourceModel(&model);
3924
3925 QTableView view;
3926 view.setModel(&proxyModel);
3927 view.setSortingEnabled(true);
3928 view.show();
3929 QVERIFY(QTest::qWaitForWindowExposed(&view));
3930
3931 view.sortByColumn(column: 0, order: Qt::AscendingOrder);
3932 QTest::qWait(ms: 100);
3933
3934 task173773_EventFilter eventFilter;
3935 view.verticalHeader()->viewport()->installEventFilter(filterObj: &eventFilter);
3936
3937 view.sortByColumn(column: 0, order: Qt::DescendingOrder);
3938 QTest::qWait(ms: 100);
3939
3940 // ### note: this test may occasionally pass even if the bug is present!
3941 QVERIFY(eventFilter.paintEventCount() > 0);
3942}
3943
3944void tst_QTableView::task227953_setRootIndex()
3945{
3946 QTableView tableView;
3947
3948 //model = tree with two items with tables as children
3949 QStandardItemModel model;
3950 QStandardItem item1, item2;
3951 model.appendColumn(items: QList<QStandardItem*>() << &item1 << &item2);
3952
3953
3954 //setup the first table as a child of the first item
3955 for ( int row = 0; row < 40; ++row ) {
3956 item1.appendRow(aitems: QList<QStandardItem*>() << new QStandardItem(QLatin1String("row ") + QString::number(row)));
3957 }
3958
3959 //setup the second table as a child of the second item
3960 for ( int row = 0; row < 10; ++row ) {
3961 item2.appendRow(aitems: QList<QStandardItem*>() << new QStandardItem(QLatin1String("row ") + QString::number(row)));
3962 }
3963
3964 tableView.setModel(&model);
3965
3966 //show the first 10 rows of the first table
3967 QModelIndex root = model.indexFromItem(item: &item1);
3968 tableView.setRootIndex(root);
3969 for (int i = 10; i != 40; ++i) {
3970 tableView.setRowHidden(row: i, hide: true);
3971 }
3972
3973 QCOMPARE(tableView.verticalHeader()->count(), 40);
3974 QCOMPARE(tableView.verticalHeader()->hiddenSectionCount(), 30);
3975
3976 //show the first 10 rows of the second table
3977 tableView.setRootIndex(model.indexFromItem(item: &item2));
3978
3979 QCOMPARE(tableView.verticalHeader()->count(), 10);
3980 QCOMPARE(tableView.verticalHeader()->hiddenSectionCount(), 0);
3981 QVERIFY(!tableView.verticalHeader()->isHidden());
3982}
3983
3984void tst_QTableView::task240266_veryBigColumn()
3985{
3986 QTableView table;
3987 table.setFixedSize(w: 500, h: 300); //just to make sure we have the 2 first columns visible
3988 QStandardItemModel model(1, 3);
3989 table.setModel(&model);
3990 table.setColumnWidth(column: 0, width: 100); //normal column
3991 table.setColumnWidth(column: 1, width: 100); //normal column
3992 table.setColumnWidth(column: 2, width: 9000); //very big column
3993 table.show();
3994 QVERIFY(QTest::qWaitForWindowExposed(&table));
3995
3996 //some styles change the scroll mode in their polish
3997 table.setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
3998 table.setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
3999
4000 QScrollBar *scroll = table.horizontalScrollBar();
4001 QCOMPARE(scroll->minimum(), 0);
4002 QCOMPARE(scroll->maximum(), model.columnCount() - 1);
4003 QCOMPARE(scroll->singleStep(), 1);
4004
4005 //1 is not always a very correct value for pageStep. Ideally this should be dynamic.
4006 //Maybe something for Qt 5 ;-)
4007 QCOMPARE(scroll->pageStep(), 1);
4008
4009}
4010
4011void tst_QTableView::task248688_autoScrollNavigation()
4012{
4013 //we make sure that when navigating with the keyboard the view is correctly scrolled
4014 //to the current item
4015 QStandardItemModel model(16, 16);
4016 QTableView view;
4017 view.setModel(&model);
4018
4019 view.hideColumn(column: 8);
4020 view.hideRow(row: 8);
4021 view.show();
4022 for (int r = 0; r < model.rowCount(); ++r) {
4023 if (view.isRowHidden(row: r))
4024 continue;
4025 for (int c = 0; c < model.columnCount(); ++c) {
4026 if (view.isColumnHidden(column: c))
4027 continue;
4028 QModelIndex index = model.index(row: r, column: c);
4029 view.setCurrentIndex(index);
4030 QVERIFY(view.viewport()->rect().contains(view.visualRect(index)));
4031 }
4032 }
4033}
4034
4035#if QT_CONFIG(wheelevent)
4036void tst_QTableView::mouseWheel_data()
4037{
4038 QTest::addColumn<QAbstractItemView::ScrollMode>(name: "scrollMode");
4039 QTest::addColumn<int>(name: "delta");
4040 QTest::addColumn<int>(name: "horizontalPositon");
4041 QTest::addColumn<int>(name: "verticalPosition");
4042
4043 QTest::newRow(dataTag: "scroll up per item")
4044 << QAbstractItemView::ScrollPerItem << 120
4045 << 10 - QApplication::wheelScrollLines() << 10 - QApplication::wheelScrollLines();
4046 QTest::newRow(dataTag: "scroll down per item")
4047 << QAbstractItemView::ScrollPerItem << -120
4048 << 10 + QApplication::wheelScrollLines() << 10 + QApplication::wheelScrollLines();
4049 QTest::newRow(dataTag: "scroll down per pixel")
4050 << QAbstractItemView::ScrollPerPixel << -120
4051 << 10 + QApplication::wheelScrollLines() * 91 << 10 + QApplication::wheelScrollLines() * 46;
4052}
4053
4054void tst_QTableView::mouseWheel()
4055{
4056 QFETCH(QAbstractItemView::ScrollMode, scrollMode);
4057 QFETCH(int, delta);
4058 QFETCH(int, horizontalPositon);
4059 QFETCH(int, verticalPosition);
4060
4061 QtTestTableModel model(100, 100);
4062 QWidget topLevel;
4063 QtTestTableView view(&topLevel);
4064 view.resize(w: 500, h: 500);
4065 topLevel.show();
4066
4067 QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
4068
4069 view.setModel(&model);
4070
4071 for (int r = 0; r < 100; ++r)
4072 view.setRowHeight(row: r, height: 50);
4073 for (int c = 0; c < 100; ++c)
4074 view.setColumnWidth(column: c, width: 100);
4075
4076 view.setHorizontalScrollMode(scrollMode);
4077 view.setVerticalScrollMode(scrollMode);
4078 view.horizontalScrollBar()->setValue(10);
4079 view.verticalScrollBar()->setValue(10);
4080
4081 QPoint pos = view.viewport()->geometry().center();
4082 QWheelEvent verticalEvent(pos, view.mapToGlobal(pos), QPoint(), QPoint(0, delta),
4083 Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
4084 QWheelEvent horizontalEvent(pos, view.mapToGlobal(pos), QPoint(), QPoint(delta, 0),
4085 Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
4086 QApplication::sendEvent(receiver: view.viewport(), event: &horizontalEvent);
4087 QVERIFY(qAbs(view.horizontalScrollBar()->value() - horizontalPositon) < 15);
4088 QApplication::sendEvent(receiver: view.viewport(), event: &verticalEvent);
4089 QVERIFY(qAbs(view.verticalScrollBar()->value() - verticalPosition) < 15);
4090}
4091#endif // QT_CONFIG(wheelevent)
4092
4093void tst_QTableView::addColumnWhileEditing()
4094{
4095 QTableView view;
4096 QStandardItemModel model(1, 10);
4097 view.setModel(&model);
4098 QModelIndex last = model.index(row: 0,column: 9);
4099 view.show();
4100
4101 view.openPersistentEditor(index: last);
4102 view.scrollTo(index: last);
4103
4104 //let's see if the editor is moved to the right location
4105 //after adding a column
4106 model.setColumnCount(model.columnCount() + 1);
4107 QPointer<QLineEdit> editor = view.findChild<QLineEdit*>();
4108 QVERIFY(editor);
4109 QCOMPARE(editor->geometry(), view.visualRect(last));
4110
4111 //let's see if the editor is moved to the right location
4112 //after removing a column
4113 view.scrollTo(index: model.index(row: 0, column: model.columnCount()-1));
4114 model.setColumnCount(model.columnCount() - 1);
4115 QVERIFY(editor);
4116 QCOMPARE(editor->geometry(), view.visualRect(last));
4117}
4118
4119void tst_QTableView::task259308_scrollVerticalHeaderSwappedSections()
4120{
4121 QStandardItemModel model;
4122 model.setRowCount(50);
4123 model.setColumnCount(2);
4124 for (int row = 0; row < model.rowCount(); ++row)
4125 for (int col = 0; col < model.columnCount(); ++col) {
4126 const QModelIndex &idx = model.index(row, column: col);
4127 model.setData(index: idx, value: QVariant(row), role: Qt::EditRole);
4128 }
4129
4130 QTableView tv;
4131 tv.setModel(&model);
4132 tv.show();
4133 tv.verticalHeader()->swapSections(first: 0, second: model.rowCount() - 1);
4134 tv.setCurrentIndex(model.index(row: model.rowCount() - 1, column: 0));
4135
4136 QVERIFY(QTest::qWaitForWindowExposed(&tv));
4137 QTest::keyClick(widget: &tv, key: Qt::Key_PageUp); // PageUp won't scroll when at top
4138 QTRY_COMPARE(tv.rowAt(0), tv.verticalHeader()->logicalIndex(0));
4139
4140 int newRow = tv.rowAt(y: tv.viewport()->height());
4141 QTest::keyClick(widget: &tv, key: Qt::Key_PageDown); // Scroll down and check current
4142 QTRY_COMPARE(tv.currentIndex().row(), newRow);
4143
4144 tv.setCurrentIndex(model.index(row: 0, column: 0));
4145 QTest::keyClick(widget: &tv, key: Qt::Key_PageDown); // PageDown won't scroll when at the bottom
4146 QTRY_COMPARE(tv.rowAt(tv.viewport()->height() - 1), tv.verticalHeader()->logicalIndex(model.rowCount() - 1));
4147}
4148
4149template <typename T>
4150struct ValueSaver {
4151 T &var, value;
4152 ValueSaver(T &v) : var(v), value(v) { }
4153 ~ValueSaver() { var = value; }
4154};
4155
4156void tst_QTableView::task191545_dragSelectRows()
4157{
4158 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
4159 QSKIP("Wayland: This fails. Figure out why.");
4160
4161 QStandardItemModel model(10, 10);
4162 QTableView table;
4163 table.setModel(&model);
4164 table.setSelectionBehavior(QAbstractItemView::SelectItems);
4165 table.setSelectionMode(QAbstractItemView::ExtendedSelection);
4166 table.setMinimumSize(minw: 1000, minh: 400);
4167 table.show();
4168 QVERIFY(QTest::qWaitForWindowActive(&table));
4169
4170 ValueSaver<Qt::KeyboardModifiers> saver(QApplicationPrivate::modifier_buttons);
4171 QApplicationPrivate::modifier_buttons = Qt::ControlModifier;
4172
4173 {
4174 QRect cellRect = table.visualRect(index: model.index(row: 3, column: 0));
4175 QHeaderView *vHeader = table.verticalHeader();
4176 QWidget *vHeaderVp = vHeader->viewport();
4177 QPoint rowPos(cellRect.center());
4178 QMouseEvent rowPressEvent(QEvent::MouseButtonPress, rowPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
4179 QCoreApplication::sendEvent(receiver: vHeaderVp, event: &rowPressEvent);
4180
4181 for (int i = 0; i < 4; ++i) {
4182 rowPos.setY(rowPos.y() + cellRect.height());
4183 QMouseEvent moveEvent(QEvent::MouseMove, rowPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
4184 QCoreApplication::sendEvent(receiver: vHeaderVp, event: &moveEvent);
4185 }
4186 QMouseEvent rowReleaseEvent(QEvent::MouseButtonRelease, rowPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
4187 QCoreApplication::sendEvent(receiver: vHeaderVp, event: &rowReleaseEvent);
4188
4189 for (int i = 0; i < 4; ++i) {
4190 QModelIndex index = model.index(row: 3 + i, column: 0, parent: table.rootIndex());
4191 QVERIFY(vHeader->selectionModel()->selectedRows().contains(index));
4192 }
4193 }
4194
4195 {
4196 QRect cellRect = table.visualRect(index: model.index(row: 0, column: 3));
4197 QHeaderView *hHeader = table.horizontalHeader();
4198 QWidget *hHeaderVp = hHeader->viewport();
4199 QPoint colPos((cellRect.left() + cellRect.right()) / 2, 5);
4200 QMouseEvent colPressEvent(QEvent::MouseButtonPress, colPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
4201 QCoreApplication::sendEvent(receiver: hHeaderVp, event: &colPressEvent);
4202
4203 for (int i = 0; i < 4; ++i) {
4204 colPos.setX(colPos.x() + cellRect.width());
4205 QMouseEvent moveEvent(QEvent::MouseMove, colPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
4206 QCoreApplication::sendEvent(receiver: hHeaderVp, event: &moveEvent);
4207 }
4208 QMouseEvent colReleaseEvent(QEvent::MouseButtonRelease, colPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
4209 QCoreApplication::sendEvent(receiver: hHeaderVp, event: &colReleaseEvent);
4210
4211 for (int i = 0; i < 4; ++i) {
4212 QModelIndex index = model.index(row: 0, column: 3 + i, parent: table.rootIndex());
4213 QVERIFY(hHeader->selectionModel()->selectedColumns().contains(index));
4214 }
4215 }
4216
4217 {
4218 QRect cellRect = table.visualRect(index: model.index(row: 2, column: 2));
4219 QWidget *tableVp = table.viewport();
4220 QPoint cellPos = cellRect.center();
4221 QMouseEvent cellPressEvent(QEvent::MouseButtonPress, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
4222 QCoreApplication::sendEvent(receiver: tableVp, event: &cellPressEvent);
4223
4224 for (int i = 0; i < 6; ++i) {
4225 cellPos.setX(cellPos.x() + cellRect.width());
4226 cellPos.setY(cellPos.y() + cellRect.height());
4227 QMouseEvent moveEvent(QEvent::MouseMove, cellPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
4228 QCoreApplication::sendEvent(receiver: tableVp, event: &moveEvent);
4229 }
4230 QMouseEvent cellReleaseEvent(QEvent::MouseButtonRelease, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
4231 QCoreApplication::sendEvent(receiver: tableVp, event: &cellReleaseEvent);
4232
4233 for (int i = 0; i < 6; ++i) {
4234 for (int j = 0; j < 6; ++j) {
4235 QModelIndex index = model.index(row: 2 + i, column: 2 + j, parent: table.rootIndex());
4236 QVERIFY(table.selectionModel()->isSelected(index));
4237 }
4238 }
4239 }
4240
4241 {
4242 QRect cellRect = table.visualRect(index: model.index(row: 3, column: 3));
4243 QWidget *tableVp = table.viewport();
4244 QPoint cellPos = cellRect.center();
4245 QMouseEvent cellPressEvent(QEvent::MouseButtonPress, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
4246 QCoreApplication::sendEvent(receiver: tableVp, event: &cellPressEvent);
4247
4248 for (int i = 0; i < 6; ++i) {
4249 cellPos.setX(cellPos.x() + cellRect.width());
4250 cellPos.setY(cellPos.y() + cellRect.height());
4251 QMouseEvent moveEvent(QEvent::MouseMove, cellPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
4252 QCoreApplication::sendEvent(receiver: tableVp, event: &moveEvent);
4253 }
4254 QMouseEvent cellReleaseEvent(QEvent::MouseButtonRelease, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
4255 QCoreApplication::sendEvent(receiver: tableVp, event: &cellReleaseEvent);
4256
4257 QTest::qWait(ms: 200);
4258 for (int i = 0; i < 6; ++i) {
4259 for (int j = 0; j < 6; ++j) {
4260 QModelIndex index = model.index(row: 3 + i, column: 3 + j, parent: table.rootIndex());
4261 QVERIFY(!table.selectionModel()->isSelected(index));
4262 }
4263 }
4264 }
4265}
4266
4267void tst_QTableView::task234926_setHeaderSorting()
4268{
4269 QStringListModel model;
4270 QSortFilterProxyModel sfpm; // default QStandardItemModel does not support 'unsorted' state
4271 sfpm.setSourceModel(&model);
4272 const QStringList data({"orange", "apple", "banana", "lemon", "pumpkin"});
4273 QStringList sortedDataA = data;
4274 QStringList sortedDataD = data;
4275 std::sort(first: sortedDataA.begin(), last: sortedDataA.end());
4276 std::sort(first: sortedDataD.begin(), last: sortedDataD.end(), comp: std::greater<QString>());
4277 model.setStringList(data);
4278 QTableView view;
4279 view.setModel(&sfpm);
4280
4281 QTRY_COMPARE(model.stringList(), data);
4282 view.setSortingEnabled(true);
4283 view.sortByColumn(column: 0, order: Qt::AscendingOrder);
4284 for (int i = 0; i < sortedDataA.size(); ++i)
4285 QCOMPARE(view.model()->data(view.model()->index(i, 0)).toString(), sortedDataA.at(i));
4286
4287 view.horizontalHeader()->setSortIndicator(logicalIndex: 0, order: Qt::DescendingOrder);
4288 for (int i = 0; i < sortedDataD.size(); ++i)
4289 QCOMPARE(view.model()->data(view.model()->index(i, 0)).toString(), sortedDataD.at(i));
4290
4291 QHeaderView *h = new QHeaderView(Qt::Horizontal);
4292 h->setModel(&model);
4293 view.setHorizontalHeader(h);
4294 h->setSortIndicator(logicalIndex: 0, order: Qt::AscendingOrder);
4295 for (int i = 0; i < sortedDataA.size(); ++i)
4296 QCOMPARE(view.model()->data(view.model()->index(i, 0)).toString(), sortedDataA.at(i));
4297
4298 h->setSortIndicator(logicalIndex: 0, order: Qt::DescendingOrder);
4299 for (int i = 0; i < sortedDataD.size(); ++i)
4300 QCOMPARE(view.model()->data(view.model()->index(i, 0)).toString(), sortedDataD.at(i));
4301
4302 view.sortByColumn(column: -1, order: Qt::AscendingOrder);
4303 QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), -1);
4304 for (int i = 0; i < data.size(); ++i)
4305 QCOMPARE(view.model()->data(view.model()->index(i, 0)).toString(), data.at(i));
4306}
4307
4308void tst_QTableView::taskQTBUG_5062_spansInconsistency()
4309{
4310 const int nRows = 5;
4311 const int nColumns = 5;
4312
4313 QtTestTableModel model(nRows, nColumns);
4314 QtTestTableView view;
4315 view.setModel(&model);
4316
4317 for (int i = 0; i < nRows; ++i)
4318 view.setSpan(row: i, column: 0, rowSpan: 1, columnSpan: nColumns);
4319 view.setSpan(row: 2, column: 0, rowSpan: 1, columnSpan: 1);
4320 view.setSpan(row: 3, column: 0, rowSpan: 1, columnSpan: 1);
4321
4322 VERIFY_SPANS_CONSISTENCY(&view);
4323}
4324
4325void tst_QTableView::taskQTBUG_4516_clickOnRichTextLabel()
4326{
4327 QTableView view;
4328 QStandardItemModel model(5,5);
4329 view.setModel(&model);
4330 QLabel label("rich text");
4331 label.setTextFormat(Qt::RichText);
4332 view.setIndexWidget(index: model.index(row: 1,column: 1), widget: &label);
4333 view.show();
4334 QVERIFY(QTest::qWaitForWindowExposed(&view));
4335
4336 view.setCurrentIndex(model.index(row: 0,column: 0));
4337 QCOMPARE(view.currentIndex(), model.index(0,0));
4338
4339 QTest::mouseClick(widget: &label, button: Qt::LeftButton);
4340 QCOMPARE(view.currentIndex(), model.index(1,1));
4341}
4342
4343
4344void tst_QTableView::changeHeaderData()
4345{
4346 QTableView view;
4347 QStandardItemModel model(5,5);
4348 view.setModel(&model);
4349 view.show();
4350 QVERIFY(QTest::qWaitForWindowExposed(&view));
4351
4352 QString text = "long long long text";
4353 const int textWidth = view.verticalHeader()->fontMetrics().horizontalAdvance(text);
4354 QVERIFY(view.verticalHeader()->width() < textWidth);
4355
4356 model.setHeaderData(section: 2, orientation: Qt::Vertical, value: text);
4357
4358 QTRY_VERIFY(view.verticalHeader()->width() > textWidth);
4359}
4360
4361#if QT_CONFIG(wheelevent)
4362void tst_QTableView::taskQTBUG_5237_wheelEventOnHeader()
4363{
4364 QTableView view;
4365 QStandardItemModel model(500,5);
4366 view.setModel(&model);
4367 view.show();
4368 QVERIFY(QTest::qWaitForWindowExposed(&view));
4369
4370 int sbValueBefore = view.verticalScrollBar()->value();
4371 QHeaderView *header = view.verticalHeader();
4372 QTest::mouseMove(widget: header);
4373 QPoint pos = header->geometry().center();
4374 QWheelEvent wheelEvent(pos, header->viewport()->mapToGlobal(pos), QPoint(), QPoint(0, -720),
4375 Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
4376 QApplication::sendEvent(receiver: header->viewport(), event: &wheelEvent);
4377 int sbValueAfter = view.verticalScrollBar()->value();
4378 QVERIFY(sbValueBefore != sbValueAfter);
4379}
4380#endif
4381
4382class TestTableView : public QTableView
4383{
4384 Q_OBJECT
4385public:
4386 TestTableView(QWidget *parent = nullptr) : QTableView(parent)
4387 {
4388 connect(sender: this, signal: &QTableView::entered, receiver: this, slot: &TestTableView::openPersistentEditor);
4389 }
4390public slots:
4391 void onDataChanged()
4392 {
4393 for (int i = 0; i < model()->rowCount(); i++) {
4394 setRowHidden(row: i, hide: model()->data(index: model()->index(row: i, column: 0)).toBool());
4395 }
4396 }
4397};
4398
4399
4400void tst_QTableView::taskQTBUG_8585_crashForNoGoodReason()
4401{
4402 QStandardItemModel model;
4403 model.insertColumn(acolumn: 0, aparent: QModelIndex());
4404 for (int i = 0; i < 20; i++)
4405 model.insertRow(arow: i);
4406
4407 TestTableView w;
4408 w.setMouseTracking(true);
4409 w.setModel(&model);
4410 connect(sender: &model, signal: &QStandardItemModel::dataChanged, receiver: &w, slot: &TestTableView::onDataChanged);
4411 w.show();
4412 QVERIFY(QTest::qWaitForWindowExposed(&w));
4413 for (int i = 0; i < 10; i++)
4414 {
4415 QTest::mouseMove(widget: w.viewport(), pos: QPoint(50, 20));
4416 w.model()->setData(index: w.indexAt(p: QPoint(50, 20)), value: true);
4417 QTest::mouseMove(widget: w.viewport(), pos: QPoint(50, 25));
4418 }
4419}
4420
4421class TableView7774 : public QTableView
4422{
4423public:
4424 using QTableView::visualRegionForSelection;
4425};
4426
4427void tst_QTableView::taskQTBUG_7774_RtoLVisualRegionForSelection()
4428{
4429 TableView7774 view;
4430 QStandardItemModel model(5,5);
4431 view.setModel(&model);
4432 view.setLayoutDirection(Qt::RightToLeft);
4433 view.show();
4434 QVERIFY(QTest::qWaitForWindowExposed(&view));
4435
4436 QItemSelectionRange range(model.index(row: 2, column: 0), model.index(row: 2, column: model.columnCount() - 1));
4437 QItemSelection selection;
4438 selection << range;
4439 QRegion region = view.visualRegionForSelection(selection);
4440 QVERIFY(!region.isEmpty());
4441 QCOMPARE(region.begin()[0], view.visualRect(range.topLeft()) | view.visualRect(range.bottomRight()));
4442}
4443
4444void tst_QTableView::taskQTBUG_8777_scrollToSpans()
4445{
4446 QTableWidget table(75,5);
4447 for (int i=0; i<50; i++)
4448 table.setSpan(row: 2+i, column: 0, rowSpan: 1, columnSpan: 5);
4449 table.setCurrentCell(row: 0,column: 2);
4450 table.show();
4451
4452 for (int i = 0; i < 45; ++i)
4453 QTest::keyClick(widget: &table, key: Qt::Key_Down);
4454
4455 QVERIFY(table.verticalScrollBar()->value() > 10);
4456}
4457
4458void tst_QTableView::taskQTBUG_10169_sizeHintForRow()
4459{
4460 QtTestTableView tableView;
4461 QStandardItemModel model(1, 3);
4462 model.setData(index: model.index(row: 0, column: 0), value: "Word wrapping text goes here.");
4463 tableView.setModel(&model);
4464 tableView.verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
4465 const int orderedHeight = tableView.sizeHintForRow(row: 0);
4466 tableView.horizontalHeader()->moveSection(from: 2, to: 0);
4467 const int reorderedHeight = tableView.sizeHintForRow(row: 0);
4468
4469 //the order of the columns shouldn't matter.
4470 QCOMPARE(orderedHeight, reorderedHeight);
4471}
4472
4473void tst_QTableView::viewOptions()
4474{
4475 QtTestTableView view;
4476 QStyleOptionViewItem options = view.viewOptions();
4477 QVERIFY(options.showDecorationSelected);
4478}
4479
4480void tst_QTableView::taskQTBUG_30653_doItemsLayout()
4481{
4482 QWidget topLevel;
4483 QtTestTableView view(&topLevel);
4484
4485 QtTestTableModel model(5, 5);
4486 view.setModel(&model);
4487
4488 QtTestItemDelegate delegate;
4489 delegate.hint = QSize(50, 50);
4490 view.setItemDelegate(&delegate);
4491
4492 view.resizeRowsToContents();
4493 view.resizeColumnsToContents();
4494
4495 // show two and half rows/cols
4496 int extraWidth = view.verticalHeader()->sizeHint().width() + view.verticalScrollBar()->sizeHint().width();
4497 int extraHeight = view.horizontalHeader()->sizeHint().height() + view.horizontalScrollBar()->sizeHint().height();
4498 view.resize(w: 125 + extraWidth, h: 125 + extraHeight);
4499
4500 topLevel.show();
4501 QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
4502
4503 // the offset after scrollToBottom() and doItemsLayout() should not differ
4504 // as the view content should stay aligned to the last section
4505 view.scrollToBottom();
4506 int scrollToBottomOffset = view.verticalHeader()->offset();
4507 view.doItemsLayout();
4508 int doItemsLayoutOffset = view.verticalHeader()->offset();
4509
4510 QCOMPARE(scrollToBottomOffset, doItemsLayoutOffset);
4511}
4512
4513void tst_QTableView::taskQTBUG_7232_AllowUserToControlSingleStep()
4514{
4515 // When we set the scrollMode to ScrollPerPixel it will adjust the scrollbars singleStep automatically
4516 // Setting a singlestep on a scrollbar should however imply that the user takes control (and it is not changed by geometry updates).
4517 // Setting a singlestep to -1 return to an automatic control of the singleStep.
4518 QTableView t;
4519 t.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
4520 t.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
4521 QStandardItemModel model(200, 200);
4522 t.setModel(&model);
4523 t.show();
4524 QVERIFY(QTest::qWaitForWindowExposed(&t));
4525 t.setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
4526 t.setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
4527
4528 t.setGeometry(ax: 200, ay: 200, aw: 200, ah: 200);
4529 int vStep1 = t.verticalScrollBar()->singleStep();
4530 int hStep1 = t.horizontalScrollBar()->singleStep();
4531 QVERIFY(vStep1 > 1);
4532 QVERIFY(hStep1 > 1);
4533
4534 t.verticalScrollBar()->setSingleStep(1);
4535 t.setGeometry(ax: 300, ay: 300, aw: 300, ah: 300);
4536 QCOMPARE(t.verticalScrollBar()->singleStep(), 1);
4537
4538 t.horizontalScrollBar()->setSingleStep(1);
4539 t.setGeometry(ax: 400, ay: 400, aw: 400, ah: 400);
4540 QCOMPARE(t.horizontalScrollBar()->singleStep(), 1);
4541
4542 t.setGeometry(ax: 200, ay: 200, aw: 200, ah: 200);
4543 t.verticalScrollBar()->setSingleStep(-1);
4544 t.horizontalScrollBar()->setSingleStep(-1);
4545 QCOMPARE(vStep1, t.verticalScrollBar()->singleStep());
4546 QCOMPARE(hStep1, t.horizontalScrollBar()->singleStep());
4547}
4548
4549void tst_QTableView::taskQTBUG_50171_selectRowAfterSwapColumns()
4550{
4551 {
4552 QtTestTableView tableView;
4553 QtTestTableModel model(2, 3);
4554 tableView.setModel(&model);
4555
4556 tableView.horizontalHeader()->swapSections(first: 1, second: 2);
4557 tableView.horizontalHeader()->hideSection(alogicalIndex: 0);
4558 tableView.selectRow(row: 1);
4559
4560 QItemSelectionModel* tableSelectionModel = tableView.selectionModel();
4561 QCOMPARE(tableSelectionModel->isRowSelected(1, QModelIndex()), true);
4562 QCOMPARE(tableSelectionModel->isSelected(tableView.model()->index(0, 0)), false);
4563 QCOMPARE(tableSelectionModel->isSelected(tableView.model()->index(0, 1)), false);
4564 QCOMPARE(tableSelectionModel->isSelected(tableView.model()->index(0, 2)), false);
4565 }
4566
4567 {
4568 QtTestTableView tableView;
4569 QtTestTableModel model(3, 2);
4570 tableView.setModel(&model);
4571
4572 tableView.verticalHeader()->swapSections(first: 1, second: 2);
4573 tableView.verticalHeader()->hideSection(alogicalIndex: 0);
4574 tableView.selectColumn(column: 1);
4575
4576 QItemSelectionModel* sModel = tableView.selectionModel();
4577 QCOMPARE(sModel->isColumnSelected(1, QModelIndex()), true);
4578 QCOMPARE(sModel->isSelected(tableView.model()->index(0, 0)), false);
4579 QCOMPARE(sModel->isSelected(tableView.model()->index(1, 0)), false);
4580 QCOMPARE(sModel->isSelected(tableView.model()->index(2, 0)), false);
4581 }
4582}
4583
4584class DeselectTableWidget : public QTableWidget
4585{
4586public:
4587 using QTableWidget::QTableWidget;
4588 QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &,
4589 const QEvent * = nullptr) const override
4590 {
4591 return QItemSelectionModel::Toggle;
4592 }
4593};
4594
4595void tst_QTableView::deselectRow()
4596{
4597 DeselectTableWidget tw(20, 20);
4598 tw.show();
4599 QVERIFY(QTest::qWaitForWindowExposed(&tw));
4600 tw.hideColumn(column: 0);
4601 QVERIFY(tw.isColumnHidden(0));
4602 tw.selectRow(row: 1);
4603 QVERIFY(tw.selectionModel()->isRowSelected(1, QModelIndex()));
4604 tw.selectRow(row: 1);
4605 // QTBUG-79092 - deselection was not possible when column 0 was hidden
4606 QVERIFY(!tw.selectionModel()->isRowSelected(1, QModelIndex()));
4607}
4608
4609// This has nothing to do with QTableView, but it's convenient to reuse the QtTestTableModel
4610#if QT_CONFIG(textmarkdownwriter)
4611
4612// #define DEBUG_WRITE_OUTPUT
4613
4614void tst_QTableView::markdownWriter()
4615{
4616 QtTestTableModel model(2, 3);
4617 QString md;
4618 {
4619 QTextStream stream(&md);
4620 QTextMarkdownWriter writer(stream, QTextDocument::MarkdownDialectGitHub);
4621 writer.writeTable(table: &model);
4622 }
4623
4624#ifdef DEBUG_WRITE_OUTPUT
4625 {
4626 QFile out("/tmp/table.md");
4627 out.open(QFile::WriteOnly);
4628 out.write(md.toUtf8());
4629 out.close();
4630 }
4631#endif
4632
4633 QCOMPARE(md, QString::fromLatin1("|1 |2 |3 |\n|-------|-------|-------|\n|[0,0,0]|[0,1,0]|[0,2,0]|\n|[1,0,0]|[1,1,0]|[1,2,0]|\n"));
4634}
4635#endif
4636
4637QTEST_MAIN(tst_QTableView)
4638#include "tst_qtableview.moc"
4639

source code of qtbase/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp