1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Copyright (C) 2012 Thorbjørn Lund Martsum - tmartsum[at]gmail.com
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
41 ****************************************************************************/
44 #include <QtTest/QtTest>
45 #include <QStandardItemModel>
46 #include <QStringListModel>
47 #include <QSortFilterProxyModel>
50 #include <qabstractitemmodel.h>
51 #include <qapplication.h>
52 #include <qheaderview.h>
53 #include <private/qheaderview_p.h>
54 #include <qitemdelegate.h>
55 #include <qtreewidget.h>
58 typedef QList<int> IntList;
59 Q_DECLARE_METATYPE(IntList)
61 typedef QList<bool> BoolList;
62 Q_DECLARE_METATYPE(BoolList)
64 class protected_QHeaderView : public QHeaderView
68 protected_QHeaderView(Qt::Orientation orientation) : QHeaderView(orientation) {
73 void testhorizontalOffset();
74 void testverticalOffset();
75 friend class tst_QHeaderView;
78 class XResetModel : public QStandardItemModel
80 virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
83 bool r = QStandardItemModel::removeRows(row, count, parent);
88 virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
91 bool r = QStandardItemModel::insertRows(row, count, parent);
98 class tst_QHeaderView : public QObject
104 virtual ~tst_QHeaderView();
108 void cleanupTestCase();
116 void visualIndexAt_data();
117 void visualIndexAt();
129 void sectionSize_data();
134 void sectionSizeHint();
136 void logicalIndexAt();
139 void moveSection_data();
144 void resizeSection_data();
145 void resizeSection();
147 void resizeAndMoveSection_data();
148 void resizeAndMoveSection();
149 void resizeHiddenSection_data();
150 void resizeHiddenSection();
151 void resizeAndInsertSection_data();
152 void resizeAndInsertSection();
153 void resizeWithResizeModes_data();
154 void resizeWithResizeModes();
155 void moveAndInsertSection_data();
156 void moveAndInsertSection();
157 void highlightSections();
158 void showSortIndicator();
159 void sortIndicatorTracking();
160 void removeAndInsertRow();
161 void unhideSection();
163 void headerDataChanged();
164 void currentChanged();
165 void horizontalOffset();
166 void verticalOffset();
167 void stretchSectionCount();
168 void hiddenSectionCount();
170 void moveSectionAndReset();
171 void moveSectionAndRemove();
173 void defaultSectionSizeTest();
175 void defaultAlignment_data();
176 void defaultAlignment();
178 void globalResizeMode_data();
179 void globalResizeMode();
181 void sectionPressedSignal_data();
182 void sectionPressedSignal();
183 void sectionClickedSignal_data() { sectionPressedSignal_data(); }
184 void sectionClickedSignal();
186 void defaultSectionSize_data();
187 void defaultSectionSize();
189 void oneSectionSize();
191 void hideAndInsert_data();
192 void hideAndInsert();
194 void removeSection();
195 void preserveHiddenSectionWidth();
196 void invisibleStretchLastSection();
197 void noSectionsWithNegativeSize();
199 void emptySectionSpan();
200 void task236450_hidden_data();
201 void task236450_hidden();
202 void task248050_hideRow();
203 void QTBUG6058_reset();
204 void QTBUG7833_sectionClicked();
205 void QTBUG8650_crashOnInsertSections();
206 void QTBUG12268_hiddenMovedSectionSorting();
207 void QTBUG14242_hideSectionAutoSize();
208 void ensureNoIndexAtLength();
209 void offsetConsistent();
211 void initialSortOrderRole();
213 void logicalIndexAtTest_data() { setupTestData(); }
214 void visualIndexAtTest_data() { setupTestData(); }
215 void hideShowTest_data() { setupTestData(); }
216 void swapSectionsTest_data() { setupTestData(); }
217 void moveSectionTest_data() { setupTestData(); }
218 void defaultSizeTest_data() { setupTestData(); }
219 void removeTest_data() { setupTestData(true); }
220 void insertTest_data() { setupTestData(true); }
221 void mixedTests_data() { setupTestData(true); }
222 void resizeToContentTest_data() { setupTestData(); }
223 void logicalIndexAtTest();
224 void visualIndexAtTest();
226 void swapSectionsTest();
227 void moveSectionTest();
228 void defaultSizeTest();
232 void resizeToContentTest();
233 void testStreamWithHide();
236 void setupTestData(bool use_reset_model = false);
237 void additionalInit();
238 void calculateAndCheck(int cppline, const int precalced_comparedata[]);
242 QStandardItemModel *model;
243 QTableView *m_tableview;
244 bool m_using_reset_model;
248 class QtTestModel: public QAbstractTableModel
254 QtTestModel(QObject *parent = 0): QAbstractTableModel(parent),
255 cols(0), rows(0), wrongIndex(false) {}
256 int rowCount(const QModelIndex&) const { return rows; }
257 int columnCount(const QModelIndex&) const { return cols; }
258 bool isEditable(const QModelIndex &) const { return true; }
260 QVariant data(const QModelIndex &idx, int) const
262 if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) {
264 qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(), idx.internalPointer());
266 return QString("[%1,%2,%3]").arg(idx.row()).arg(idx.column()).arg(0);//idx.data());
269 void insertOneColumn(int col)
271 beginInsertColumns(QModelIndex(), col, col);
278 beginRemoveRows(QModelIndex(), rows - 1, rows - 1);
285 beginRemoveRows(QModelIndex(), 0, rows - 1);
290 void removeOneColumn(int col)
292 beginRemoveColumns(QModelIndex(), col, col);
297 void removeLastColumn()
299 beginRemoveColumns(QModelIndex(), cols - 1, cols - 1);
304 void removeAllColumns()
306 beginRemoveColumns(QModelIndex(), 0, cols - 1);
315 emit layoutChanged();
319 mutable bool wrongIndex;
322 // Testing get/set functions
323 void tst_QHeaderView::getSetCheck()
325 protected_QHeaderView obj1(Qt::Horizontal);
326 // bool QHeaderView::highlightSections()
327 // void QHeaderView::setHighlightSections(bool)
328 obj1.setHighlightSections(false);
329 QCOMPARE(false, obj1.highlightSections());
330 obj1.setHighlightSections(true);
331 QCOMPARE(true, obj1.highlightSections());
333 // bool QHeaderView::stretchLastSection()
334 // void QHeaderView::setStretchLastSection(bool)
335 obj1.setStretchLastSection(false);
336 QCOMPARE(false, obj1.stretchLastSection());
337 obj1.setStretchLastSection(true);
338 QCOMPARE(true, obj1.stretchLastSection());
340 // int QHeaderView::defaultSectionSize()
341 // void QHeaderView::setDefaultSectionSize(int)
342 obj1.setDefaultSectionSize(-1);
343 QVERIFY(obj1.defaultSectionSize() >= 0);
344 obj1.setDefaultSectionSize(0);
345 QCOMPARE(0, obj1.defaultSectionSize());
346 obj1.setDefaultSectionSize(INT_MAX);
347 QCOMPARE(INT_MAX, obj1.defaultSectionSize());
349 // int QHeaderView::minimumSectionSize()
350 // void QHeaderView::setMinimumSectionSize(int)
351 obj1.setMinimumSectionSize(-1);
352 QVERIFY(obj1.minimumSectionSize() >= 0);
353 obj1.setMinimumSectionSize(0);
354 QCOMPARE(0, obj1.minimumSectionSize());
355 obj1.setMinimumSectionSize(INT_MAX);
356 QCOMPARE(INT_MAX, obj1.minimumSectionSize());
358 // int QHeaderView::offset()
359 // void QHeaderView::setOffset(int)
361 QCOMPARE(0, obj1.offset());
362 obj1.setOffset(INT_MIN);
363 QCOMPARE(INT_MIN, obj1.offset());
364 obj1.setOffset(INT_MAX);
365 QCOMPARE(INT_MAX, obj1.offset());
369 tst_QHeaderView::tst_QHeaderView()
371 qRegisterMetaType<int>("Qt::SortOrder");
374 tst_QHeaderView::~tst_QHeaderView()
378 void tst_QHeaderView::initTestCase()
380 #ifdef Q_OS_WINCE //disable magic for WindowsCE
381 qApp->setAutoMaximizeThreshold(-1);
383 m_tableview = new QTableView();
386 void tst_QHeaderView::cleanupTestCase()
391 void tst_QHeaderView::init()
393 topLevel = new QWidget();
394 view = new QHeaderView(Qt::Vertical,topLevel);
395 // Some initial value tests before a model is added
396 QCOMPARE(view->length(), 0);
397 QVERIFY(view->sizeHint() == QSize(0,0));
398 QCOMPARE(view->sectionSizeHint(0), -1);
401 model = new QStandardItemModel(1, 1);
402 view->setModel(model);
403 //qDebug() << view->count();
409 model = new QStandardItemModel(rows, columns);
411 for (int row = 0; row < rows; ++row) {
412 for (int column = 0; column < columns; ++column) {
413 QModelIndex index = model->index(row, column, QModelIndex());
414 model->setData(index, QVariant((row+1) * (column+1)));
419 QSignalSpy spy(view, SIGNAL(sectionCountChanged(int, int)));
420 view->setModel(model);
421 QCOMPARE(spy.count(), 1);
422 view->resize(200,200);
426 void tst_QHeaderView::cleanup()
428 m_tableview->setUpdatesEnabled(true);
429 if (view && view->parent() != m_tableview)
436 void tst_QHeaderView::noModel()
438 QHeaderView emptyView(Qt::Vertical);
439 QCOMPARE(emptyView.count(), 0);
442 void tst_QHeaderView::emptyModel()
444 QtTestModel testmodel;
445 view->setModel(&testmodel);
446 QVERIFY(!testmodel.wrongIndex);
447 QCOMPARE(view->count(), testmodel.rows);
448 view->setModel(model);
451 void tst_QHeaderView::removeRows()
454 model.rows = model.cols = 10;
456 QHeaderView vertical(Qt::Vertical);
457 QHeaderView horizontal(Qt::Horizontal);
459 vertical.setModel(&model);
460 horizontal.setModel(&model);
463 QCOMPARE(vertical.count(), model.rows);
464 QCOMPARE(horizontal.count(), model.cols);
466 model.removeLastRow();
467 QVERIFY(!model.wrongIndex);
468 QCOMPARE(vertical.count(), model.rows);
469 QCOMPARE(horizontal.count(), model.cols);
471 model.removeAllRows();
472 QVERIFY(!model.wrongIndex);
473 QCOMPARE(vertical.count(), model.rows);
474 QCOMPARE(horizontal.count(), model.cols);
478 void tst_QHeaderView::removeCols()
481 model.rows = model.cols = 10;
483 QHeaderView vertical(Qt::Vertical);
484 QHeaderView horizontal(Qt::Horizontal);
485 vertical.setModel(&model);
486 horizontal.setModel(&model);
489 QCOMPARE(vertical.count(), model.rows);
490 QCOMPARE(horizontal.count(), model.cols);
492 model.removeLastColumn();
493 QVERIFY(!model.wrongIndex);
494 QCOMPARE(vertical.count(), model.rows);
495 QCOMPARE(horizontal.count(), model.cols);
497 model.removeAllColumns();
498 QVERIFY(!model.wrongIndex);
499 QCOMPARE(vertical.count(), model.rows);
500 QCOMPARE(horizontal.count(), model.cols);
503 void tst_QHeaderView::movable()
505 QCOMPARE(view->sectionsMovable(), false);
506 view->setSectionsMovable(false);
507 QCOMPARE(view->sectionsMovable(), false);
508 view->setSectionsMovable(true);
509 QCOMPARE(view->sectionsMovable(), true);
512 void tst_QHeaderView::clickable()
514 QCOMPARE(view->sectionsClickable(), false);
515 view->setSectionsClickable(false);
516 QCOMPARE(view->sectionsClickable(), false);
517 view->setSectionsClickable(true);
518 QCOMPARE(view->sectionsClickable(), true);
521 void tst_QHeaderView::hidden()
523 //hideSection() & showSection call setSectionHidden
524 // Test bad arguments
525 QCOMPARE(view->isSectionHidden(-1), false);
526 QCOMPARE(view->isSectionHidden(view->count()), false);
527 QCOMPARE(view->isSectionHidden(999999), false);
529 view->setSectionHidden(-1, true);
530 view->setSectionHidden(view->count(), true);
531 view->setSectionHidden(999999, true);
532 view->setSectionHidden(-1, false);
533 view->setSectionHidden(view->count(), false);
534 view->setSectionHidden(999999, false);
536 // Hidden sections shouldn't have visual properties (except position)
537 int pos = view->defaultSectionSize();
538 view->setSectionHidden(1, true);
539 QCOMPARE(view->sectionSize(1), 0);
540 QCOMPARE(view->sectionPosition(1), pos);
541 view->resizeSection(1, 100);
542 QCOMPARE(view->sectionViewportPosition(1), pos);
543 QCOMPARE(view->sectionSize(1), 0);
544 view->setSectionHidden(1, false);
545 QCOMPARE(view->isSectionHidden(0), false);
546 QCOMPARE(view->sectionSize(0), view->defaultSectionSize());
549 void tst_QHeaderView::stretch()
551 // Show before resize and setStrechLastSection
552 #if defined(Q_OS_WINCE)
553 QSize viewSize(200,300);
555 QSize viewSize(500, 500);
557 view->resize(viewSize);
558 view->setStretchLastSection(true);
559 QCOMPARE(view->stretchLastSection(), true);
561 QCOMPARE(view->width(), viewSize.width());
562 QCOMPARE(view->visualIndexAt(view->viewport()->height() - 5), 3);
564 view->setSectionHidden(3, true);
565 QCOMPARE(view->visualIndexAt(view->viewport()->height() - 5), 2);
567 view->setStretchLastSection(false);
568 QCOMPARE(view->stretchLastSection(), false);
571 void tst_QHeaderView::oneSectionSize()
573 //this ensures that if there is only one section, it gets a correct width (more than 0)
574 QHeaderView view (Qt::Vertical);
579 view.setSectionResizeMode(QHeaderView::Interactive);
580 view.setModel(&model);
584 QVERIFY(view.sectionSize(0) > 0);
588 void tst_QHeaderView::sectionSize_data()
590 QTest::addColumn<QList<int> >("boundsCheck");
591 QTest::addColumn<QList<int> >("defaultSizes");
592 QTest::addColumn<int>("initialDefaultSize");
593 QTest::addColumn<int>("lastVisibleSectionSize");
594 QTest::addColumn<int>("persistentSectionSize");
596 QTest::newRow("data set one")
597 << (QList<int>() << -1 << 0 << 4 << 9999)
598 << (QList<int>() << 10 << 30 << 30)
604 void tst_QHeaderView::sectionSize()
606 QFETCH(QList<int>, boundsCheck);
607 QFETCH(QList<int>, defaultSizes);
608 QFETCH(int, initialDefaultSize);
609 QFETCH(int, lastVisibleSectionSize);
610 QFETCH(int, persistentSectionSize);
613 // We test on a device with doubled pixels. Therefore we need to specify
614 // different boundaries.
615 initialDefaultSize = qMax(view->minimumSectionSize(), 30);
619 foreach (int val, boundsCheck)
620 view->sectionSize(val);
623 QCOMPARE(view->defaultSectionSize(), initialDefaultSize);
624 foreach (int def, defaultSizes) {
625 view->setDefaultSectionSize(def);
626 QCOMPARE(view->defaultSectionSize(), def);
629 view->setDefaultSectionSize(initialDefaultSize);
630 for (int s = 0; s < view->count(); ++s)
631 QCOMPARE(view->sectionSize(s), initialDefaultSize);
632 view->doItemsLayout();
634 // stretch last section
635 view->setStretchLastSection(true);
636 int lastSection = view->count() - 1;
638 //test that when hiding the last column,
639 //resizing the new last visible columns still works
640 view->hideSection(lastSection);
641 view->resizeSection(lastSection - 1, lastVisibleSectionSize);
642 QCOMPARE(view->sectionSize(lastSection - 1), lastVisibleSectionSize);
643 view->showSection(lastSection);
645 // turn off stretching
646 view->setStretchLastSection(false);
647 QCOMPARE(view->sectionSize(lastSection), initialDefaultSize);
650 int sectionCount = view->count();
651 for (int i = 0; i < sectionCount; ++i)
652 view->resizeSection(i, persistentSectionSize);
654 model.cols = sectionCount * 2;
655 model.rows = sectionCount * 2;
656 view->setModel(&model);
657 for (int j = 0; j < sectionCount; ++j)
658 QCOMPARE(view->sectionSize(j), persistentSectionSize);
659 for (int k = sectionCount; k < view->count(); ++k)
660 QCOMPARE(view->sectionSize(k), initialDefaultSize);
663 void tst_QHeaderView::visualIndex()
665 // Test bad arguments
666 QCOMPARE(view->visualIndex(999999), -1);
667 QCOMPARE(view->visualIndex(-1), -1);
668 QCOMPARE(view->visualIndex(1), 1);
669 view->setSectionHidden(1, true);
670 QCOMPARE(view->visualIndex(1), 1);
671 QCOMPARE(view->visualIndex(2), 2);
673 view->setSectionHidden(1, false);
674 QCOMPARE(view->visualIndex(1), 1);
675 QCOMPARE(view->visualIndex(2), 2);
678 void tst_QHeaderView::visualIndexAt_data()
680 QTest::addColumn<QList<int> >("hidden");
681 QTest::addColumn<QList<int> >("from");
682 QTest::addColumn<QList<int> >("to");
683 QTest::addColumn<QList<int> >("coordinate");
684 QTest::addColumn<QList<int> >("visual");
686 QList<int> coordinateList;
688 coordinateList << -1 << 0 << 31 << 91 << 99999;
690 // We test on a device with doubled pixels. Therefore we need to specify
691 // different boundaries.
692 coordinateList << -1 << 0 << 33 << 97 << 99999;
695 QTest::newRow("no hidden, no moved sections")
700 << (QList<int>() << -1 << 0 << 1 << 3 << -1);
702 QTest::newRow("no hidden, moved sections")
704 << (QList<int>() << 0)
705 << (QList<int>() << 1)
707 << (QList<int>() << -1 << 0 << 1 << 3 << -1);
709 QTest::newRow("hidden, no moved sections")
710 << (QList<int>() << 0)
714 << (QList<int>() << -1 << 1 << 2 << 3 << -1);
717 void tst_QHeaderView::visualIndexAt()
719 QFETCH(QList<int>, hidden);
720 QFETCH(QList<int>, from);
721 QFETCH(QList<int>, to);
722 QFETCH(QList<int>, coordinate);
723 QFETCH(QList<int>, visual);
725 view->setStretchLastSection(true);
728 for (int i = 0; i < hidden.count(); ++i)
729 view->setSectionHidden(hidden.at(i), true);
731 for (int j = 0; j < from.count(); ++j)
732 view->moveSection(from.at(j), to.at(j));
736 for (int k = 0; k < coordinate.count(); ++k)
737 QCOMPARE(view->visualIndexAt(coordinate.at(k)), visual.at(k));
740 void tst_QHeaderView::length()
742 #if defined(Q_OS_WINCE)
743 QFont font(QLatin1String("Tahoma"), 7);
746 view->setStretchLastSection(true);
749 //minimumSectionSize should be the size of the last section of the widget is not tall enough
750 int length = view->minimumSectionSize();
751 for (int i=0; i < view->count()-1; i++) {
752 length += view->sectionSize(i);
755 length = qMax(length, view->viewport()->height());
756 QCOMPARE(length, view->length());
758 view->setStretchLastSection(false);
761 QVERIFY(length != view->length());
763 // layoutChanged might mean rows have been removed
767 view->setModel(&model);
768 int oldLength = view->length();
770 QCOMPARE(model.rows, view->count());
771 QVERIFY(oldLength != view->length());
774 void tst_QHeaderView::offset()
776 QCOMPARE(view->offset(), 0);
778 QCOMPARE(view->offset(), 10);
780 QCOMPARE(view->offset(), 0);
782 // Test odd arguments
786 void tst_QHeaderView::sectionSizeHint()
788 // Test bad arguments
789 view->sectionSizeHint(-1);
790 view->sectionSizeHint(99999);
792 // TODO how to test the return value?
795 void tst_QHeaderView::logicalIndex()
797 // Test bad arguments
798 QCOMPARE(view->logicalIndex(-1), -1);
799 QCOMPARE(view->logicalIndex(99999), -1);
802 void tst_QHeaderView::logicalIndexAt()
804 // Test bad arguments
805 view->logicalIndexAt(-1);
806 view->logicalIndexAt(99999);
807 QCOMPARE(view->logicalIndexAt(0), 0);
808 QCOMPARE(view->logicalIndexAt(1), 0);
811 view->setStretchLastSection(true);
813 QCOMPARE(view->logicalIndexAt(0), 0);
814 QCOMPARE(view->logicalIndexAt(view->sectionSize(0)-1), 0);
815 QCOMPARE(view->logicalIndexAt(view->sectionSize(0)+1), 1);
817 int last = view->length() - 1;//view->viewport()->height() - 10;
818 QCOMPARE(view->logicalIndexAt(last), 3);
820 int outofbounds = view->length() + 1;//view->viewport()->height() + 1;
821 QCOMPARE(view->logicalIndexAt(outofbounds), -1);
823 view->moveSection(0,1);
825 QCOMPARE(view->logicalIndexAt(0), 1);
826 QCOMPARE(view->logicalIndexAt(view->sectionSize(0)-1), 1);
827 QCOMPARE(view->logicalIndexAt(view->sectionSize(0)+1), 0);
829 QCOMPARE(view->logicalIndexAt(last), 3);
830 view->moveSection(1,0);
834 void tst_QHeaderView::swapSections()
836 view->swapSections(-1, 1);
837 view->swapSections(99999, 1);
838 view->swapSections(1, -1);
839 view->swapSections(1, 99999);
841 QVector<int> logical = (QVector<int>() << 0 << 1 << 2 << 3);
843 QSignalSpy spy1(view, SIGNAL(sectionMoved(int, int, int)));
845 QCOMPARE(view->sectionsMoved(), false);
846 view->swapSections(1, 1);
847 QCOMPARE(view->sectionsMoved(), false);
848 view->swapSections(1, 2);
849 QCOMPARE(view->sectionsMoved(), true);
850 view->swapSections(2, 1);
851 QCOMPARE(view->sectionsMoved(), true);
852 for (int i = 0; i < view->count(); ++i)
853 QCOMPARE(view->logicalIndex(i), logical.at(i));
854 QCOMPARE(spy1.count(), 4);
856 logical = (QVector<int>() << 3 << 1 << 2 << 0);
857 view->swapSections(3, 0);
858 QCOMPARE(view->sectionsMoved(), true);
859 for (int j = 0; j < view->count(); ++j)
860 QCOMPARE(view->logicalIndex(j), logical.at(j));
861 QCOMPARE(spy1.count(), 6);
864 void tst_QHeaderView::moveSection_data()
866 QTest::addColumn<QList<int> >("hidden");
867 QTest::addColumn<QList<int> >("from");
868 QTest::addColumn<QList<int> >("to");
869 QTest::addColumn<QList<bool> >("moved");
870 QTest::addColumn<QList<int> >("logical");
871 QTest::addColumn<int>("count");
873 QTest::newRow("bad args, no hidden")
875 << (QList<int>() << -1 << 1 << 99999 << 1)
876 << (QList<int>() << 1 << -1 << 1 << 99999)
877 << (QList<bool>() << false << false << false << false)
878 << (QList<int>() << 0 << 1 << 2 << 3)
881 QTest::newRow("good args, no hidden")
883 << (QList<int>() << 1 << 1 << 2 << 1)
884 << (QList<int>() << 1 << 2 << 1 << 2)
885 << (QList<bool>() << false << true << true << true)
886 << (QList<int>() << 0 << 2 << 1 << 3)
889 QTest::newRow("hidden sections")
890 << (QList<int>() << 0 << 3)
891 << (QList<int>() << 1 << 1 << 2 << 1)
892 << (QList<int>() << 1 << 2 << 1 << 2)
893 << (QList<bool>() << false << true << true << true)
894 << (QList<int>() << 0 << 2 << 1 << 3)
898 void tst_QHeaderView::moveSection()
900 QFETCH(QList<int>, hidden);
901 QFETCH(QList<int>, from);
902 QFETCH(QList<int>, to);
903 QFETCH(QList<bool>, moved);
904 QFETCH(QList<int>, logical);
907 QVERIFY(from.count() == to.count());
908 QVERIFY(from.count() == moved.count());
909 QVERIFY(view->count() == logical.count());
911 QSignalSpy spy1(view, SIGNAL(sectionMoved(int, int, int)));
912 QCOMPARE(view->sectionsMoved(), false);
914 for (int h = 0; h < hidden.count(); ++h)
915 view->setSectionHidden(hidden.at(h), true);
917 for (int i = 0; i < from.count(); ++i) {
918 view->moveSection(from.at(i), to.at(i));
919 QCOMPARE(view->sectionsMoved(), moved.at(i));
922 for (int j = 0; j < view->count(); ++j)
923 QCOMPARE(view->logicalIndex(j), logical.at(j));
925 QCOMPARE(spy1.count(), count);
928 void tst_QHeaderView::resizeAndMoveSection_data()
930 QTest::addColumn<IntList>("logicalIndexes");
931 QTest::addColumn<IntList>("sizes");
932 QTest::addColumn<int>("logicalFrom");
933 QTest::addColumn<int>("logicalTo");
935 QTest::newRow("resizeAndMove-1")
936 << (IntList() << 0 << 1)
937 << (IntList() << 20 << 40)
940 QTest::newRow("resizeAndMove-2")
941 << (IntList() << 0 << 1 << 2 << 3)
942 << (IntList() << 20 << 60 << 10 << 80)
945 QTest::newRow("resizeAndMove-3")
946 << (IntList() << 0 << 1 << 2 << 3)
947 << (IntList() << 100 << 60 << 40 << 10)
950 QTest::newRow("resizeAndMove-4")
951 << (IntList() << 0 << 1 << 2 << 3)
952 << (IntList() << 10 << 40 << 80 << 30)
955 QTest::newRow("resizeAndMove-5")
956 << (IntList() << 2 << 3)
957 << (IntList() << 100 << 200)
961 void tst_QHeaderView::resizeAndMoveSection()
963 QFETCH(IntList, logicalIndexes);
964 QFETCH(IntList, sizes);
965 QFETCH(int, logicalFrom);
966 QFETCH(int, logicalTo);
968 // Save old visual indexes and sizes
969 IntList oldVisualIndexes;
971 foreach (int logical, logicalIndexes) {
972 oldVisualIndexes.append(view->visualIndex(logical));
973 oldSizes.append(view->sectionSize(logical));
977 for (int i = 0; i < logicalIndexes.size(); ++i) {
978 int logical = logicalIndexes.at(i);
979 view->resizeSection(logical, sizes.at(i));
983 int visualFrom = view->visualIndex(logicalFrom);
984 int visualTo = view->visualIndex(logicalTo);
985 view->moveSection(visualFrom, visualTo);
986 QCOMPARE(view->visualIndex(logicalFrom), visualTo);
988 // Check that sizes are still correct
989 for (int i = 0; i < logicalIndexes.size(); ++i) {
990 int logical = logicalIndexes.at(i);
991 QCOMPARE(view->sectionSize(logical), sizes.at(i));
994 // Move sections back
995 view->moveSection(visualTo, visualFrom);
997 // Check that sizes are still correct
998 for (int i = 0; i < logicalIndexes.size(); ++i) {
999 int logical = logicalIndexes.at(i);
1000 QCOMPARE(view->sectionSize(logical), sizes.at(i));
1003 // Put everything back as it was
1004 for (int i = 0; i < logicalIndexes.size(); ++i) {
1005 int logical = logicalIndexes.at(i);
1006 view->resizeSection(logical, oldSizes.at(i));
1007 QCOMPARE(view->visualIndex(logical), oldVisualIndexes.at(i));
1011 void tst_QHeaderView::resizeHiddenSection_data()
1013 QTest::addColumn<int>("section");
1014 QTest::addColumn<int>("initialSize");
1015 QTest::addColumn<int>("finalSize");
1017 QTest::newRow("section 0 resize 50 to 20")
1020 QTest::newRow("section 1 resize 50 to 20")
1023 QTest::newRow("section 2 resize 50 to 20")
1026 QTest::newRow("section 3 resize 50 to 20")
1030 void tst_QHeaderView::resizeHiddenSection()
1032 QFETCH(int, section);
1033 QFETCH(int, initialSize);
1034 QFETCH(int, finalSize);
1036 view->resizeSection(section, initialSize);
1037 view->setSectionHidden(section, true);
1038 QCOMPARE(view->sectionSize(section), 0);
1040 view->resizeSection(section, finalSize);
1041 QCOMPARE(view->sectionSize(section), 0);
1043 view->setSectionHidden(section, false);
1044 QCOMPARE(view->sectionSize(section), finalSize);
1047 void tst_QHeaderView::resizeAndInsertSection_data()
1049 QTest::addColumn<int>("section");
1050 QTest::addColumn<int>("size");
1051 QTest::addColumn<int>("insert");
1052 QTest::addColumn<int>("compare");
1053 QTest::addColumn<int>("expected");
1055 QTest::newRow("section 0 size 50 insert 0")
1056 << 0 << 50 << 0 << 1 << 50;
1058 QTest::newRow("section 1 size 50 insert 1")
1059 << 0 << 50 << 1 << 0 << 50;
1061 QTest::newRow("section 1 size 50 insert 0")
1062 << 1 << 50 << 0 << 2 << 50;
1066 void tst_QHeaderView::resizeAndInsertSection()
1068 QFETCH(int, section);
1070 QFETCH(int, insert);
1071 QFETCH(int, compare);
1072 QFETCH(int, expected);
1074 view->setStretchLastSection(false);
1076 view->resizeSection(section, size);
1077 QCOMPARE(view->sectionSize(section), size);
1079 model->insertRow(insert);
1081 QCOMPARE(view->sectionSize(compare), expected);
1084 void tst_QHeaderView::resizeWithResizeModes_data()
1086 QTest::addColumn<int>("size");
1087 QTest::addColumn<QList<int> >("sections");
1088 QTest::addColumn<QList<int> >("modes");
1089 QTest::addColumn<QList<int> >("expected");
1091 QTest::newRow("stretch first section")
1093 << (QList<int>() << 100 << 100 << 100 << 100)
1094 << (QList<int>() << ((int)QHeaderView::Stretch)
1095 << ((int)QHeaderView::Interactive)
1096 << ((int)QHeaderView::Interactive)
1097 << ((int)QHeaderView::Interactive))
1098 << (QList<int>() << 300 << 100 << 100 << 100);
1101 void tst_QHeaderView::resizeWithResizeModes()
1104 QFETCH(QList<int>, sections);
1105 QFETCH(QList<int>, modes);
1106 QFETCH(QList<int>, expected);
1108 view->setStretchLastSection(false);
1109 for (int i = 0; i < sections.count(); ++i) {
1110 view->resizeSection(i, sections.at(i));
1111 view->setSectionResizeMode(i, (QHeaderView::ResizeMode)modes.at(i));
1114 view->resize(size, size);
1115 for (int j = 0; j < expected.count(); ++j)
1116 QCOMPARE(view->sectionSize(j), expected.at(j));
1119 void tst_QHeaderView::moveAndInsertSection_data()
1121 QTest::addColumn<int>("from");
1122 QTest::addColumn<int>("to");
1123 QTest::addColumn<int>("insert");
1124 QTest::addColumn<QList<int> >("mapping");
1126 QTest::newRow("move from 1 to 3, insert 0")
1127 << 1 << 3 << 0 <<(QList<int>() << 0 << 1 << 3 << 4 << 2);
1131 void tst_QHeaderView::moveAndInsertSection()
1135 QFETCH(int, insert);
1136 QFETCH(QList<int>, mapping);
1138 view->setStretchLastSection(false);
1140 view->moveSection(from, to);
1142 model->insertRow(insert);
1144 for (int i = 0; i < mapping.count(); ++i)
1145 QCOMPARE(view->logicalIndex(i), mapping.at(i));
1148 void tst_QHeaderView::resizeMode()
1150 // resizeMode must not be called with an invalid index
1151 int last = view->count() - 1;
1152 view->setSectionResizeMode(QHeaderView::Interactive);
1153 QCOMPARE(view->sectionResizeMode(last), QHeaderView::Interactive);
1154 QCOMPARE(view->sectionResizeMode(1), QHeaderView::Interactive);
1155 view->setSectionResizeMode(QHeaderView::Stretch);
1156 QCOMPARE(view->sectionResizeMode(last), QHeaderView::Stretch);
1157 QCOMPARE(view->sectionResizeMode(1), QHeaderView::Stretch);
1158 view->setSectionResizeMode(QHeaderView::Custom);
1159 QCOMPARE(view->sectionResizeMode(last), QHeaderView::Custom);
1160 QCOMPARE(view->sectionResizeMode(1), QHeaderView::Custom);
1162 // test when sections have been moved
1163 view->setStretchLastSection(false);
1164 for (int i=0; i < (view->count() - 1); ++i)
1165 view->setSectionResizeMode(i, QHeaderView::Interactive);
1166 int logicalIndex = view->count() / 2;
1167 view->setSectionResizeMode(logicalIndex, QHeaderView::Stretch);
1168 view->moveSection(view->visualIndex(logicalIndex), 0);
1169 for (int i=0; i < (view->count() - 1); ++i) {
1170 if (i == logicalIndex)
1171 QCOMPARE(view->sectionResizeMode(i), QHeaderView::Stretch);
1173 QCOMPARE(view->sectionResizeMode(i), QHeaderView::Interactive);
1177 void tst_QHeaderView::resizeSection_data()
1179 QTest::addColumn<int>("initial");
1180 QTest::addColumn<QList<int> >("logical");
1181 QTest::addColumn<QList<int> >("size");
1182 QTest::addColumn<QList<int> >("mode");
1183 QTest::addColumn<int>("resized");
1184 QTest::addColumn<QList<int> >("expected");
1186 QTest::newRow("bad args")
1188 << (QList<int>() << -1 << -1 << 99999 << 99999 << 4)
1189 << (QList<int>() << -1 << 0 << 99999 << -1 << -1)
1191 << int(QHeaderView::Interactive)
1192 << int(QHeaderView::Interactive)
1193 << int(QHeaderView::Interactive)
1194 << int(QHeaderView::Interactive))
1196 << (QList<int>() << 0 << 0 << 0 << 0 << 0);
1199 void tst_QHeaderView::resizeSection()
1202 QFETCH(int, initial);
1203 QFETCH(QList<int>, logical);
1204 QFETCH(QList<int>, size);
1205 QFETCH(QList<int>, mode);
1206 QFETCH(int, resized);
1207 QFETCH(QList<int>, expected);
1209 view->resize(400, 400);
1212 view->setSectionsMovable(true);
1213 view->setStretchLastSection(false);
1215 for (int i = 0; i < logical.count(); ++i)
1216 if (logical.at(i) > -1 && logical.at(i) < view->count()) // for now
1217 view->setSectionResizeMode(logical.at(i), (QHeaderView::ResizeMode)mode.at(i));
1219 for (int j = 0; j < logical.count(); ++j)
1220 view->resizeSection(logical.at(j), initial);
1222 QSignalSpy spy(view, SIGNAL(sectionResized(int, int, int)));
1224 for (int k = 0; k < logical.count(); ++k)
1225 view->resizeSection(logical.at(k), size.at(k));
1227 QCOMPARE(spy.count(), resized);
1229 for (int l = 0; l < logical.count(); ++l)
1230 QCOMPARE(view->sectionSize(logical.at(l)), expected.at(l));
1233 void tst_QHeaderView::highlightSections()
1235 view->setHighlightSections(true);
1236 QCOMPARE(view->highlightSections(), true);
1237 view->setHighlightSections(false);
1238 QCOMPARE(view->highlightSections(), false);
1241 void tst_QHeaderView::showSortIndicator()
1243 view->setSortIndicatorShown(true);
1244 QCOMPARE(view->isSortIndicatorShown(), true);
1245 QCOMPARE(view->sortIndicatorOrder(), Qt::DescendingOrder);
1246 view->setSortIndicator(1, Qt::AscendingOrder);
1247 QCOMPARE(view->sortIndicatorOrder(), Qt::AscendingOrder);
1248 view->setSortIndicator(1, Qt::DescendingOrder);
1249 QCOMPARE(view->sortIndicatorOrder(), Qt::DescendingOrder);
1250 view->setSortIndicatorShown(false);
1251 QCOMPARE(view->isSortIndicatorShown(), false);
1253 view->setSortIndicator(999999, Qt::DescendingOrder);
1254 // Don't segfault baby :)
1255 view->setSortIndicatorShown(true);
1257 view->setSortIndicator(0, Qt::DescendingOrder);
1258 // Don't assert baby :)
1261 void tst_QHeaderView::sortIndicatorTracking()
1264 model.rows = model.cols = 10;
1266 QHeaderView hv(Qt::Horizontal);
1268 hv.setModel(&model);
1270 hv.setSortIndicatorShown(true);
1271 hv.setSortIndicator(1, Qt::DescendingOrder);
1273 model.removeOneColumn(8);
1274 QCOMPARE(hv.sortIndicatorSection(), 1);
1276 model.removeOneColumn(2);
1277 QCOMPARE(hv.sortIndicatorSection(), 1);
1279 model.insertOneColumn(2);
1280 QCOMPARE(hv.sortIndicatorSection(), 1);
1282 model.insertOneColumn(1);
1283 QCOMPARE(hv.sortIndicatorSection(), 2);
1285 model.removeOneColumn(0);
1286 QCOMPARE(hv.sortIndicatorSection(), 1);
1288 model.removeOneColumn(1);
1289 QCOMPARE(hv.sortIndicatorSection(), -1);
1292 void tst_QHeaderView::removeAndInsertRow()
1294 // Check if logicalIndex returns the correct value after we have removed a row
1295 // we might as well te
1296 for (int i = 0; i < model->rowCount(); ++i) {
1297 QCOMPARE(i, view->logicalIndex(i));
1300 while (model->removeRow(0)) {
1301 for (int i = 0; i < model->rowCount(); ++i) {
1302 QCOMPARE(i, view->logicalIndex(i));
1307 for (pass = 0; pass < 5; pass++) {
1308 for (int i = 0; i < model->rowCount(); ++i) {
1309 QCOMPARE(i, view->logicalIndex(i));
1311 model->insertRow(0);
1314 while (model->removeRows(0, 2)) {
1315 for (int i = 0; i < model->rowCount(); ++i) {
1316 QCOMPARE(i, view->logicalIndex(i));
1320 for (pass = 0; pass < 3; pass++) {
1321 model->insertRows(0, 2);
1322 for (int i = 0; i < model->rowCount(); ++i) {
1323 QCOMPARE(i, view->logicalIndex(i));
1327 for (pass = 0; pass < 3; pass++) {
1328 model->insertRows(3, 2);
1329 for (int i = 0; i < model->rowCount(); ++i) {
1330 QCOMPARE(i, view->logicalIndex(i));
1335 for (pass = 0; pass < 3; pass++) {
1336 int rowCount = model->rowCount();
1337 model->insertRows(rowCount, 1);
1338 for (int i = 0; i < rowCount; ++i) {
1339 QCOMPARE(i, view->logicalIndex(i));
1344 void tst_QHeaderView::unhideSection()
1346 // You should not necessarily expect the same size back again, so the best test we can do is to test if it is larger than 0 after a unhide.
1347 QCOMPARE(view->sectionsHidden(), false);
1348 view->setSectionHidden(0, true);
1349 QCOMPARE(view->sectionsHidden(), true);
1350 QVERIFY(view->sectionSize(0) == 0);
1351 view->setSectionResizeMode(QHeaderView::Interactive);
1352 view->setSectionHidden(0, false);
1353 QVERIFY(view->sectionSize(0) > 0);
1355 view->setSectionHidden(0, true);
1356 QVERIFY(view->sectionSize(0) == 0);
1357 view->setSectionHidden(0, true);
1358 QVERIFY(view->sectionSize(0) == 0);
1359 view->setSectionResizeMode(QHeaderView::Stretch);
1360 view->setSectionHidden(0, false);
1361 QVERIFY(view->sectionSize(0) > 0);
1365 void tst_QHeaderView::event()
1367 protected_QHeaderView x(Qt::Vertical);
1369 protected_QHeaderView y(Qt::Horizontal);
1374 void protected_QHeaderView::testEvent()
1377 QHoverEvent enterEvent(QEvent::HoverEnter, QPoint(), QPoint());
1379 QHoverEvent eventLeave(QEvent::HoverLeave, QPoint(), QPoint());
1381 QHoverEvent eventMove(QEvent::HoverMove, QPoint(), QPoint());
1385 void tst_QHeaderView::headerDataChanged()
1387 // This shouldn't asserver because view is Vertical
1388 view->headerDataChanged(Qt::Horizontal, -1, -1);
1391 view->headerDataChanged(Qt::Vertical, -1, -1);
1394 // No crashing please
1395 view->headerDataChanged(Qt::Horizontal, 0, 1);
1396 view->headerDataChanged(Qt::Vertical, 0, 1);
1399 void tst_QHeaderView::currentChanged()
1401 view->setCurrentIndex(QModelIndex());
1404 void tst_QHeaderView::horizontalOffset()
1406 protected_QHeaderView x(Qt::Vertical);
1407 x.testhorizontalOffset();
1408 protected_QHeaderView y(Qt::Horizontal);
1409 y.testhorizontalOffset();
1412 void tst_QHeaderView::verticalOffset()
1414 protected_QHeaderView x(Qt::Vertical);
1415 x.testverticalOffset();
1416 protected_QHeaderView y(Qt::Horizontal);
1417 y.testverticalOffset();
1420 void protected_QHeaderView::testhorizontalOffset()
1422 if(orientation() == Qt::Horizontal){
1423 QCOMPARE(horizontalOffset(), 0);
1425 QCOMPARE(horizontalOffset(), 10);
1428 QCOMPARE(horizontalOffset(), 0);
1432 void protected_QHeaderView::testverticalOffset()
1434 if(orientation() == Qt::Vertical){
1435 QCOMPARE(verticalOffset(), 0);
1437 QCOMPARE(verticalOffset(), 10);
1440 QCOMPARE(verticalOffset(), 0);
1443 void tst_QHeaderView::stretchSectionCount()
1445 view->setStretchLastSection(false);
1446 QCOMPARE(view->stretchSectionCount(), 0);
1447 view->setStretchLastSection(true);
1448 QCOMPARE(view->stretchSectionCount(), 0);
1450 view->setSectionResizeMode(0, QHeaderView::Stretch);
1451 QCOMPARE(view->stretchSectionCount(), 1);
1454 void tst_QHeaderView::hiddenSectionCount()
1457 model->insertRows(0, 10);
1458 // Hide every other one
1459 for (int i=0; i<10; i++)
1460 view->setSectionHidden(i, (i & 1) == 0);
1462 QCOMPARE(view->hiddenSectionCount(), 5);
1464 view->setSectionResizeMode(QHeaderView::Stretch);
1465 QCOMPARE(view->hiddenSectionCount(), 5);
1467 // Remove some rows and make sure they are now still counted
1468 model->removeRow(9);
1469 model->removeRow(8);
1470 model->removeRow(7);
1471 model->removeRow(6);
1472 QCOMPARE(view->count(), 6);
1473 QCOMPARE(view->hiddenSectionCount(), 3);
1474 model->removeRows(0,5);
1475 QCOMPARE(view->count(), 1);
1476 QCOMPARE(view->hiddenSectionCount(), 0);
1477 QVERIFY(view->count() >= view->hiddenSectionCount());
1480 void tst_QHeaderView::focusPolicy()
1482 QHeaderView view(Qt::Horizontal);
1483 QCOMPARE(view.focusPolicy(), Qt::NoFocus);
1486 QCOMPARE(widget.header()->focusPolicy(), Qt::NoFocus);
1487 QVERIFY(!widget.focusProxy());
1488 QVERIFY(!widget.hasFocus());
1489 QVERIFY(!widget.header()->focusProxy());
1490 QVERIFY(!widget.header()->hasFocus());
1493 widget.setFocus(Qt::OtherFocusReason);
1494 QApplication::setActiveWindow(&widget);
1495 widget.activateWindow();
1496 QVERIFY(QTest::qWaitForWindowActive(&widget));
1497 QVERIFY(widget.hasFocus());
1498 QVERIFY(!widget.header()->hasFocus());
1500 widget.setFocusPolicy(Qt::NoFocus);
1501 widget.clearFocus();
1502 QTRY_VERIFY(!widget.hasFocus());
1503 QVERIFY(!widget.header()->hasFocus());
1505 QTest::keyPress(&widget, Qt::Key_Tab);
1507 qApp->processEvents();
1508 qApp->processEvents();
1510 QVERIFY(!widget.hasFocus());
1511 QVERIFY(!widget.header()->hasFocus());
1514 class SimpleModel : public QAbstractItemModel
1519 SimpleModel( QObject* parent=0)
1520 : QAbstractItemModel(parent),
1523 QModelIndex parent(const QModelIndex &/*child*/) const
1525 return QModelIndex();
1527 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
1529 return hasIndex(row, column, parent) ? createIndex(row, column, 0) : QModelIndex();
1531 int rowCount(const QModelIndex & /* parent */) const
1535 int columnCount(const QModelIndex &/*parent= QModelIndex()*/) const
1540 QVariant data(const QModelIndex &index, int role) const
1542 if (!index.isValid())
1546 if (role == Qt::DisplayRole) {
1547 return QString::fromLatin1("%1,%2").arg(index.row()).arg(index.column());
1552 void setColumnCount( int c )
1561 void tst_QHeaderView::moveSectionAndReset()
1564 QHeaderView v(Qt::Horizontal);
1567 for (cc = 2; cc < 4; ++cc) {
1568 m.setColumnCount(cc);
1571 for (moveto = 1; moveto < cc; ++moveto) {
1572 v.moveSection(movefrom, moveto);
1573 m.setColumnCount(cc - 1);
1575 for (int i = 0; i < cc - 1; ++i) {
1576 QCOMPARE(v.logicalIndex(v.visualIndex(i)), i);
1582 void tst_QHeaderView::moveSectionAndRemove()
1584 QStandardItemModel m;
1585 QHeaderView v(Qt::Horizontal);
1588 v.model()->insertColumns(0, 3);
1589 v.moveSection(0, 1);
1591 QCOMPARE(v.count(), 3);
1592 v.model()->removeColumns(0, v.model()->columnCount());
1593 QCOMPARE(v.count(), 0);
1596 void tst_QHeaderView::saveRestore()
1599 QHeaderView h1(Qt::Horizontal);
1601 h1.swapSections(0, 2);
1602 h1.resizeSection(1, 10);
1603 h1.setSortIndicatorShown(true);
1604 h1.setSortIndicator(1,Qt::DescendingOrder);
1605 QByteArray s1 = h1.saveState();
1607 QHeaderView h2(Qt::Vertical);
1608 QSignalSpy spy(&h2, SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)));
1611 h2.restoreState(s1);
1613 QCOMPARE(spy.count(), 1);
1614 QCOMPARE(spy.at(0).at(0).toInt(), 1);
1616 QCOMPARE(h2.logicalIndex(0), 2);
1617 QCOMPARE(h2.logicalIndex(2), 0);
1618 QCOMPARE(h2.sectionSize(1), 10);
1619 QCOMPARE(h2.sortIndicatorSection(), 1);
1620 QCOMPARE(h2.sortIndicatorOrder(), Qt::DescendingOrder);
1621 QCOMPARE(h2.isSortIndicatorShown(), true);
1623 QByteArray s2 = h2.saveState();
1628 void tst_QHeaderView::defaultSectionSizeTest()
1632 QStandardItemModel amodel(4, 4);
1633 qtv.setModel(&amodel);
1634 QHeaderView *hv = qtv.verticalHeader();
1635 const int defaultSize = 26;
1636 hv->setDefaultSectionSize(defaultSize + 1); // Set it to a value different from defaultSize.
1638 // no hidden Sections
1639 hv->resizeSection(1, 0);
1640 hv->setDefaultSectionSize(defaultSize);
1641 QVERIFY(hv->sectionSize(1) == defaultSize);
1643 // with hidden sections
1644 hv->resizeSection(1, 0);
1646 hv->setDefaultSectionSize(defaultSize);
1648 QVERIFY(hv->sectionSize(0) == defaultSize); // trivial case.
1649 QVERIFY(hv->sectionSize(1) == defaultSize); // just sized 0. Now it should be 10
1650 QVERIFY(hv->sectionSize(2) == 0); // section is hidden. It should not be resized.
1654 void tst_QHeaderView::defaultAlignment_data()
1656 QTest::addColumn<int>("direction");
1657 QTest::addColumn<int>("initial");
1658 QTest::addColumn<int>("alignment");
1660 QTest::newRow("horizontal right aligned")
1661 << int(Qt::Horizontal)
1662 << int(Qt::AlignCenter)
1663 << int(Qt::AlignRight);
1665 QTest::newRow("horizontal left aligned")
1666 << int(Qt::Horizontal)
1667 << int(Qt::AlignCenter)
1668 << int(Qt::AlignLeft);
1670 QTest::newRow("vertical right aligned")
1671 << int(Qt::Vertical)
1672 << int(Qt::AlignLeft|Qt::AlignVCenter)
1673 << int(Qt::AlignRight);
1675 QTest::newRow("vertical left aligned")
1676 << int(Qt::Vertical)
1677 << int(Qt::AlignLeft|Qt::AlignVCenter)
1678 << int(Qt::AlignLeft);
1681 void tst_QHeaderView::defaultAlignment()
1683 QFETCH(int, direction);
1684 QFETCH(int, initial);
1685 QFETCH(int, alignment);
1689 QHeaderView header((Qt::Orientation)direction);
1690 header.setModel(&m);
1692 QCOMPARE(header.defaultAlignment(), (Qt::Alignment)initial);
1693 header.setDefaultAlignment((Qt::Alignment)alignment);
1694 QCOMPARE(header.defaultAlignment(), (Qt::Alignment)alignment);
1697 void tst_QHeaderView::globalResizeMode_data()
1699 QTest::addColumn<int>("direction");
1700 QTest::addColumn<int>("mode");
1701 QTest::addColumn<int>("insert");
1703 QTest::newRow("horizontal ResizeToContents 0")
1704 << int(Qt::Horizontal)
1705 << int(QHeaderView::ResizeToContents)
1709 void tst_QHeaderView::globalResizeMode()
1711 QFETCH(int, direction);
1713 QFETCH(int, insert);
1715 QStandardItemModel m(4, 4);
1716 QHeaderView h((Qt::Orientation)direction);
1719 h.setSectionResizeMode((QHeaderView::ResizeMode)mode);
1720 m.insertRow(insert);
1721 for (int i = 0; i < h.count(); ++i)
1722 QCOMPARE(h.sectionResizeMode(i), (QHeaderView::ResizeMode)mode);
1726 void tst_QHeaderView::sectionPressedSignal_data()
1728 QTest::addColumn<int>("direction");
1729 QTest::addColumn<bool>("clickable");
1730 QTest::addColumn<int>("count");
1732 QTest::newRow("horizontal unclickable 0")
1733 << int(Qt::Horizontal)
1737 QTest::newRow("horizontal clickable 1")
1738 << int(Qt::Horizontal)
1743 void tst_QHeaderView::sectionPressedSignal()
1745 QFETCH(int, direction);
1746 QFETCH(bool, clickable);
1749 QStandardItemModel m(4, 4);
1750 QHeaderView h((Qt::Orientation)direction);
1754 h.setSectionsClickable(clickable);
1756 QSignalSpy spy(&h, SIGNAL(sectionPressed(int)));
1758 QCOMPARE(spy.count(), 0);
1759 QTest::mousePress(h.viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(5, 5));
1760 QCOMPARE(spy.count(), count);
1763 void tst_QHeaderView::sectionClickedSignal()
1765 QFETCH(int, direction);
1766 QFETCH(bool, clickable);
1769 QStandardItemModel m(4, 4);
1770 QHeaderView h((Qt::Orientation)direction);
1774 h.setSectionsClickable(clickable);
1775 h.setSortIndicatorShown(true);
1777 QSignalSpy spy(&h, SIGNAL(sectionClicked(int)));
1778 QSignalSpy spy2(&h, SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)));
1780 QCOMPARE(spy.count(), 0);
1781 QCOMPARE(spy2.count(), 0);
1782 QTest::mouseClick(h.viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(5, 5));
1783 QCOMPARE(spy.count(), count);
1784 QCOMPARE(spy2.count(), count);
1786 //now let's try with the sort indicator hidden (the result should be the same
1789 h.setSortIndicatorShown(false);
1790 QTest::mouseClick(h.viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(5, 5));
1791 QCOMPARE(spy.count(), count);
1792 QCOMPARE(spy2.count(), count);
1795 void tst_QHeaderView::defaultSectionSize_data()
1797 QTest::addColumn<int>("direction");
1798 QTest::addColumn<int>("oldDefaultSize");
1799 QTest::addColumn<int>("newDefaultSize");
1801 //QTest::newRow("horizontal,-5") << int(Qt::Horizontal) << 100 << -5;
1802 QTest::newRow("horizontal, 0") << int(Qt::Horizontal) << 100 << 0;
1803 QTest::newRow("horizontal, 5") << int(Qt::Horizontal) << 100 << 5;
1804 QTest::newRow("horizontal,25") << int(Qt::Horizontal) << 100 << 5;
1807 void tst_QHeaderView::defaultSectionSize()
1809 QFETCH(int, direction);
1810 QFETCH(int, oldDefaultSize);
1811 QFETCH(int, newDefaultSize);
1813 QStandardItemModel m(4, 4);
1814 QHeaderView h((Qt::Orientation)direction);
1818 QCOMPARE(h.defaultSectionSize(), oldDefaultSize);
1819 h.setDefaultSectionSize(newDefaultSize);
1820 QCOMPARE(h.defaultSectionSize(), newDefaultSize);
1822 for (int i = 0; i < h.count(); ++i)
1823 QCOMPARE(h.sectionSize(i), newDefaultSize);
1826 void tst_QHeaderView::hideAndInsert_data()
1828 QTest::addColumn<int>("direction");
1829 QTest::addColumn<int>("hide");
1830 QTest::addColumn<int>("insert");
1831 QTest::addColumn<int>("hidden");
1833 QTest::newRow("horizontal, 0, 0") << int(Qt::Horizontal) << 0 << 0 << 1;
1836 void tst_QHeaderView::hideAndInsert()
1838 QFETCH(int, direction);
1840 QFETCH(int, insert);
1841 QFETCH(int, hidden);
1843 QStandardItemModel m(4, 4);
1844 QHeaderView h((Qt::Orientation)direction);
1848 h.setSectionHidden(hide, true);
1850 if (direction == Qt::Vertical)
1851 m.insertRow(insert);
1853 m.insertColumn(insert);
1855 for (int i = 0; i < h.count(); ++i)
1857 QCOMPARE(h.isSectionHidden(i), false);
1859 QCOMPARE(h.isSectionHidden(i), true);
1862 void tst_QHeaderView::removeSection()
1864 //test that removing a hidden section gives the expected result: the next row should be hidden
1866 const int hidden = 3; //section that will be hidden
1867 const QStringList list = QStringList() << "0" << "1" << "2" << "3" << "4" << "5" << "6";
1869 QStringListModel model( list );
1870 QHeaderView view(Qt::Vertical);
1871 view.setModel(&model);
1872 view.hideSection(hidden);
1873 view.hideSection(1);
1877 for(int i = 0; i < view.count(); i++) {
1878 if (i == (hidden-1)) { //-1 because we removed a row in the meantime
1879 QCOMPARE(view.sectionSize(i), 0);
1880 QVERIFY(view.isSectionHidden(i));
1882 QCOMPARE(view.sectionSize(i), view.defaultSectionSize() );
1883 QVERIFY(!view.isSectionHidden(i));
1888 void tst_QHeaderView::preserveHiddenSectionWidth()
1890 const QStringList list = QStringList() << "0" << "1" << "2" << "3";
1892 QStringListModel model( list );
1893 QHeaderView view(Qt::Vertical);
1894 view.setModel(&model);
1895 view.resizeSection(0, 100);
1896 view.resizeSection(1, 10);
1897 view.resizeSection(2, 50);
1898 view.setSectionResizeMode(3, QHeaderView::Stretch);
1901 view.hideSection(2);
1903 view.showSection(1);
1904 QCOMPARE(view.sectionSize(0), 100);
1905 QCOMPARE(view.sectionSize(1), 50);
1907 view.hideSection(1);
1909 view.showSection(2);
1910 QCOMPARE(view.sectionSize(0), 100);
1911 QCOMPARE(view.sectionSize(1), view.defaultSectionSize());
1912 QCOMPARE(view.sectionSize(2), 50);
1915 void tst_QHeaderView::invisibleStretchLastSection()
1918 QStandardItemModel model(1, count);
1919 QHeaderView view(Qt::Horizontal);
1920 view.setModel(&model);
1921 int height = view.height();
1923 view.resize(view.defaultSectionSize() * (count / 2), height); // don't show all sections
1925 view.setStretchLastSection(true);
1926 // stretch section is not visible; it should not be stretched
1927 for (int i = 0; i < count; ++i)
1928 QCOMPARE(view.sectionSize(i), view.defaultSectionSize());
1930 view.resize(view.defaultSectionSize() * (count + 1), height); // give room to stretch
1932 // stretch section is visible; it should be stretched
1933 for (int i = 0; i < count - 1; ++i)
1934 QCOMPARE(view.sectionSize(i), view.defaultSectionSize());
1935 QCOMPARE(view.sectionSize(count - 1), view.defaultSectionSize() * 2);
1938 void tst_QHeaderView::noSectionsWithNegativeSize()
1940 QStandardItemModel m(4, 4);
1941 QHeaderView h(Qt::Horizontal);
1943 h.resizeSection(1, -5);
1944 QVERIFY(h.sectionSize(1) >= 0); // Sections with negative sizes not well defined.
1947 void tst_QHeaderView::emptySectionSpan()
1949 QHeaderViewPrivate::SectionItem section;
1950 QCOMPARE(section.sectionSize(), 0);
1953 void tst_QHeaderView::task236450_hidden_data()
1955 QTest::addColumn<QList<int> >("hide1");
1956 QTest::addColumn<QList<int> >("hide2");
1958 QTest::newRow("set 1") << (QList<int>() << 1 << 3)
1959 << (QList<int>() << 1 << 5);
1961 QTest::newRow("set 2") << (QList<int>() << 2 << 3)
1962 << (QList<int>() << 1 << 5);
1964 QTest::newRow("set 3") << (QList<int>() << 0 << 2 << 4)
1965 << (QList<int>() << 2 << 3 << 5);
1969 void tst_QHeaderView::task236450_hidden()
1971 QFETCH(QList<int>, hide1);
1972 QFETCH(QList<int>, hide2);
1973 const QStringList list = QStringList() << "0" << "1" << "2" << "3" << "4" << "5";
1975 QStringListModel model( list );
1976 protected_QHeaderView view(Qt::Vertical);
1977 view.setModel(&model);
1980 foreach (int i, hide1)
1981 view.hideSection(i);
1983 QCOMPARE(view.hiddenSectionCount(), hide1.count());
1984 for (int i = 0; i < 6; i++) {
1985 QCOMPARE(!view.isSectionHidden(i), !hide1.contains(i));
1988 view.setDefaultSectionSize(2);
1989 view.scheduleDelayedItemsLayout();
1990 view.executeDelayedItemsLayout(); //force to do a relayout
1992 QCOMPARE(view.hiddenSectionCount(), hide1.count());
1993 for (int i = 0; i < 6; i++) {
1994 QCOMPARE(!view.isSectionHidden(i), !hide1.contains(i));
1995 view.setSectionHidden(i, hide2.contains(i));
1998 QCOMPARE(view.hiddenSectionCount(), hide2.count());
1999 for (int i = 0; i < 6; i++) {
2000 QCOMPARE(!view.isSectionHidden(i), !hide2.contains(i));
2005 void tst_QHeaderView::task248050_hideRow()
2007 //this is the sequence of events that make the task fail
2008 protected_QHeaderView header(Qt::Vertical);
2009 QStandardItemModel model(0, 1);
2010 header.setStretchLastSection(false);
2011 header.setDefaultSectionSize(17);
2012 header.setModel(&model);
2013 header.doItemsLayout();
2015 model.setRowCount(3);
2017 QCOMPARE(header.sectionPosition(2), 17*2);
2019 header.hideSection(1);
2020 QCOMPARE(header.sectionPosition(2), 17);
2023 //the size of the section shouldn't have changed
2024 QCOMPARE(header.sectionPosition(2), 17);
2028 //returns 0 if everything is fine.
2029 static int checkHeaderViewOrder(QHeaderView *view, const QVector<int> &expected)
2031 if (view->count() != expected.count())
2034 for (int i = 0; i < expected.count(); i++) {
2035 if (view->logicalIndex(i) != expected.at(i))
2037 if (view->visualIndex(expected.at(i)) != i)
2044 void tst_QHeaderView::QTBUG6058_reset()
2046 QStringListModel model1( QStringList() << "0" << "1" << "2" << "3" << "4" << "5" );
2047 QStringListModel model2( QStringList() << "a" << "b" << "c" );
2048 QSortFilterProxyModel proxy;
2050 QHeaderView view(Qt::Vertical);
2051 view.setModel(&proxy);
2055 proxy.setSourceModel(&model1);
2056 QApplication::processEvents();
2057 view.swapSections(0,2);
2058 view.swapSections(1,4);
2059 QApplication::processEvents();
2060 QCOMPARE(checkHeaderViewOrder(&view, QVector<int>() << 2 << 4 << 0 << 3 << 1 << 5) , 0);
2062 proxy.setSourceModel(&model2);
2063 QApplication::processEvents();
2064 QCOMPARE(checkHeaderViewOrder(&view, QVector<int>() << 2 << 0 << 1 ) , 0);
2066 proxy.setSourceModel(&model1);
2067 QApplication::processEvents();
2068 QCOMPARE(checkHeaderViewOrder(&view, QVector<int>() << 2 << 0 << 1 << 3 << 4 << 5 ) , 0);
2071 void tst_QHeaderView::QTBUG7833_sectionClicked()
2078 QStandardItemModel *sim = new QStandardItemModel(&tv);
2079 QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(&tv);
2080 proxyModel->setSourceModel(sim);
2081 proxyModel->setDynamicSortFilter(true);
2082 proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
2084 QList<QStandardItem *> row;
2085 for (int i = 0; i < 12; i++)
2086 row.append(new QStandardItem(QString(QLatin1Char('A' + i))));
2087 sim->appendRow(row);
2089 for (int i = 12; i > 0; i--)
2090 row.append(new QStandardItem(QString(QLatin1Char('A' + i))));
2091 sim->appendRow(row);
2093 tv.setSortingEnabled(true);
2094 tv.horizontalHeader()->setSortIndicatorShown(true);
2095 tv.horizontalHeader()->setSectionsClickable(true);
2096 tv.horizontalHeader()->setStretchLastSection(true);
2097 tv.horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
2099 tv.setModel(proxyModel);
2100 tv.setColumnHidden(5, true);
2101 tv.setColumnHidden(6, true);
2102 tv.horizontalHeader()->swapSections(8, 10);
2103 tv.sortByColumn(1, Qt::AscendingOrder);
2105 QSignalSpy clickedSpy(tv.horizontalHeader(), SIGNAL(sectionClicked(int)));
2106 QSignalSpy pressedSpy(tv.horizontalHeader(), SIGNAL(sectionPressed(int)));
2109 QTest::mouseClick(tv.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier,
2110 QPoint(tv.horizontalHeader()->sectionViewportPosition(11) + tv.horizontalHeader()->sectionSize(11)/2, 5));
2111 QCOMPARE(clickedSpy.count(), 1);
2112 QCOMPARE(pressedSpy.count(), 1);
2113 QCOMPARE(clickedSpy.at(0).at(0).toInt(), 11);
2114 QCOMPARE(pressedSpy.at(0).at(0).toInt(), 11);
2116 QTest::mouseClick(tv.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier,
2117 QPoint(tv.horizontalHeader()->sectionViewportPosition(8) + tv.horizontalHeader()->sectionSize(0)/2, 5));
2119 QCOMPARE(clickedSpy.count(), 2);
2120 QCOMPARE(pressedSpy.count(), 2);
2121 QCOMPARE(clickedSpy.at(1).at(0).toInt(), 8);
2122 QCOMPARE(pressedSpy.at(1).at(0).toInt(), 8);
2124 QTest::mouseClick(tv.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier,
2125 QPoint(tv.horizontalHeader()->sectionViewportPosition(0) + tv.horizontalHeader()->sectionSize(0)/2, 5));
2127 QCOMPARE(clickedSpy.count(), 3);
2128 QCOMPARE(pressedSpy.count(), 3);
2129 QCOMPARE(clickedSpy.at(2).at(0).toInt(), 0);
2130 QCOMPARE(pressedSpy.at(2).at(0).toInt(), 0);
2133 void tst_QHeaderView::QTBUG8650_crashOnInsertSections()
2135 QStringList headerLabels;
2136 QHeaderView view(Qt::Horizontal);
2137 QStandardItemModel model(2,2);
2138 view.setModel(&model);
2139 view.moveSection(1, 0);
2140 view.hideSection(0);
2142 QList<QStandardItem *> items;
2143 items << new QStandardItem("c");
2144 model.insertColumn(0, items);
2147 void tst_QHeaderView::QTBUG12268_hiddenMovedSectionSorting()
2149 QTableView view; // ### this test fails on QTableView &view = *m_tableview; !? + shadowing view member
2150 QStandardItemModel *model = new QStandardItemModel(4,3, &view);
2151 for (int i = 0; i< model->rowCount(); ++i)
2152 for (int j = 0; j< model->columnCount(); ++j)
2153 model->setData(model->index(i,j), QString("item [%1,%2]").arg(i).arg(j));
2154 view.setModel(model);
2155 view.horizontalHeader()->setSectionsMovable(true);
2156 view.setSortingEnabled(true);
2157 view.sortByColumn(1, Qt::AscendingOrder);
2158 view.horizontalHeader()->moveSection(0,2);
2159 view.setColumnHidden(1, true);
2161 QVERIFY(QTest::qWaitForWindowExposed(&view));
2162 QCOMPARE(view.horizontalHeader()->hiddenSectionCount(), 1);
2163 QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton);
2164 QCOMPARE(view.horizontalHeader()->hiddenSectionCount(), 1);
2167 void tst_QHeaderView::QTBUG14242_hideSectionAutoSize()
2170 QStandardItemModel amodel(4, 4);
2171 qtv.setModel(&amodel);
2172 QHeaderView *hv = qtv.verticalHeader();
2173 hv->setDefaultSectionSize(25);
2174 hv->setSectionResizeMode(QHeaderView::ResizeToContents);
2178 int afterlength = hv->length();
2180 int calced_length = 0;
2181 for (int u = 0; u < hv->count(); ++u)
2182 calced_length += hv->sectionSize(u);
2184 QVERIFY(calced_length == afterlength);
2187 void tst_QHeaderView::ensureNoIndexAtLength()
2190 QStandardItemModel amodel(4, 4);
2191 qtv.setModel(&amodel);
2192 QHeaderView *hv = qtv.verticalHeader();
2193 QVERIFY(hv->visualIndexAt(hv->length()) == -1);
2194 hv->resizeSection(hv->count() - 1, 0);
2195 QVERIFY(hv->visualIndexAt(hv->length()) == -1);
2198 void tst_QHeaderView::offsetConsistent()
2200 // Ensure that a hidden section 'far away'
2201 // does not affect setOffsetToSectionPosition ..
2202 const int sectionToHide = 513;
2204 QStandardItemModel amodel(1000, 4);
2205 qtv.setModel(&amodel);
2206 QHeaderView *hv = qtv.verticalHeader();
2207 for (int u = 0; u < 100; u += 2)
2208 hv->resizeSection(u, 0);
2209 hv->setOffsetToSectionPosition(150);
2210 int offset1 = hv->offset();
2211 hv->hideSection(sectionToHide);
2212 hv->setOffsetToSectionPosition(150);
2213 int offset2 = hv->offset();
2214 QVERIFY(offset1 == offset2);
2215 // Ensure that hidden indexes (still) is considered.
2216 hv->resizeSection(sectionToHide, hv->sectionSize(200) * 2);
2217 hv->setOffsetToSectionPosition(800);
2218 offset1 = hv->offset();
2219 hv->showSection(sectionToHide);
2220 hv->setOffsetToSectionPosition(800);
2221 offset2 = hv->offset();
2222 QVERIFY(offset2 > offset1);
2225 void tst_QHeaderView::initialSortOrderRole()
2227 QTableView view; // ### Shadowing member view (of type QHeaderView)
2228 QStandardItemModel *model = new QStandardItemModel(4, 3, &view);
2229 for (int i = 0; i< model->rowCount(); ++i)
2230 for (int j = 0; j< model->columnCount(); ++j)
2231 model->setData(model->index(i,j), QString("item [%1,%2]").arg(i).arg(j));
2232 QStandardItem *ascendingItem = new QStandardItem();
2233 QStandardItem *descendingItem = new QStandardItem();
2234 ascendingItem->setData(Qt::AscendingOrder, Qt::InitialSortOrderRole);
2235 descendingItem->setData(Qt::DescendingOrder, Qt::InitialSortOrderRole);
2236 model->setHorizontalHeaderItem(1, ascendingItem);
2237 model->setHorizontalHeaderItem(2, descendingItem);
2238 view.setModel(model);
2239 view.setSortingEnabled(true);
2240 view.sortByColumn(0, Qt::AscendingOrder);
2242 QVERIFY(QTest::qWaitForWindowExposed(&view));
2244 const int column1Pos = view.horizontalHeader()->sectionViewportPosition(1) + 5; // +5 not to be on the handle
2245 QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(column1Pos, 0));
2246 QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 1);
2247 QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::AscendingOrder);
2249 const int column2Pos = view.horizontalHeader()->sectionViewportPosition(2) + 5; // +5 not to be on the handle
2250 QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(column2Pos, 0));
2251 QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 2);
2252 QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::DescendingOrder);
2254 const int column0Pos = view.horizontalHeader()->sectionViewportPosition(0) + 5; // +5 not to be on the handle
2255 QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(column0Pos, 0));
2256 QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 0);
2257 QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::AscendingOrder);
2260 const bool block_some_signals = true; // The test should also work with this set to false
2261 const int rowcount = 500;
2262 const int colcount = 10;
2264 QString istr(int n, bool comma = true)
2273 void tst_QHeaderView::calculateAndCheck(int cppline, const int precalced_comparedata[])
2275 qint64 endtimer = timer.elapsed();
2276 const bool silentmode = true;
2278 qDebug().nospace() << "(Time:" << endtimer << ")";
2281 sline.setNum(cppline - 1);
2283 const int p1 = 3133777; // just a prime (maybe not that random ;) )
2284 const int p2 = 135928393; // just a random large prime - a bit less than signed 32-bit
2287 int sum_logical = 0;
2289 int sum_hidden_size = 0;
2290 int sum_lookup_visual = 0;
2291 int sum_lookup_logical = 0;
2294 int chk_logical = 1;
2296 int chk_hidden_size = 1;
2297 int chk_lookup_visual = 1;
2298 int chk_lookup_logical = 1;
2300 int header_lenght = 0;
2301 int lastindex = view->count() - 1;
2303 // calculate information based on index
2304 for (int i = 0; i <= lastindex; ++i) {
2305 int visual = view->visualIndex(i);
2306 int logical = view->logicalIndex(i);
2307 int ssize = view->sectionSize(i);
2309 sum_visual += visual;
2310 sum_logical += logical;
2315 chk_visual *= (visual + 1) * (i + 1) * p1;
2320 chk_logical *= (logical + 1) * (i + 1 + (logical != i) ) * p1;
2325 chk_sizes *= ( (ssize + 2) * (i + 1) * p1);
2328 if (view->isSectionHidden(i)) {
2329 view->showSection(i);
2330 int hiddensize = view->sectionSize(i);
2331 sum_hidden_size += hiddensize;
2332 chk_hidden_size %= p2;
2333 chk_hidden_size += ( (hiddensize + 1) * (i + 1) * p1);
2334 // (hiddensize + 1) in the above to differ between hidden and size 0
2335 // Though it can be changed (why isn't sections with size 0 hidden?)
2337 view->hideSection(i);
2341 // lookup indexes by pixel position
2342 const int max_lookup_count = 500;
2343 int lookup_to = view->height() + 1;
2344 if (lookup_to > max_lookup_count)
2345 lookup_to = max_lookup_count; // We limit this lookup - not to spend years when testing.
2346 // Notice that lookupTest also has its own extra test
2347 for (int u = 0; u < max_lookup_count; ++u) {
2348 int visu = view->visualIndexAt(u);
2349 int logi = view->logicalIndexAt(u);
2350 sum_lookup_visual += logi;
2351 sum_lookup_logical += visu;
2352 chk_lookup_visual %= p2;
2353 chk_lookup_visual *= ( (u + 1) * p1 * (visu + 2));
2354 chk_lookup_logical %= p2;
2355 chk_lookup_logical *= ( (u + 1) * p1 * (logi + 2));
2357 header_lenght = view->length();
2359 // visual and logical indexes.
2360 int sum_to_last_index = (lastindex * (lastindex + 1)) / 2; // == 0 + 1 + 2 + 3 + ... + lastindex
2362 const bool write_calced_data = false; // Do not write calculated output (unless the test fails)
2363 if (write_calced_data) {
2364 qDebug().nospace() << "(" << cppline - 1 << ")" // << " const int precalced[] = "
2365 << " {" << chk_visual << ", " << chk_logical << ", " << chk_sizes << ", " << chk_hidden_size
2366 << ", " << chk_lookup_visual << ", " << chk_lookup_logical << ", " << header_lenght << "};";
2369 const bool sanity_checks = true;
2370 if (sanity_checks) {
2371 QString msg = QString("sanity problem at ") + sline;
2372 char *verifytext = QTest::toString(msg);
2374 QVERIFY2(m_tableview->model()->rowCount() == view->count() , verifytext);
2375 QVERIFY2(view->visualIndex(lastindex + 1) <= 0, verifytext); // there is no such index in model
2376 QVERIFY2(view->logicalIndex(lastindex + 1) <= 0, verifytext); // there is no such index in model.
2377 QVERIFY2(view->logicalIndex(lastindex + 1) <= 0, verifytext); // there is no such index in model.
2378 QVERIFY2(lastindex < 0 || view->visualIndex(0) >= 0, verifytext); // no rows or legal index
2379 QVERIFY2(lastindex < 0 || view->logicalIndex(0) >= 0, verifytext); // no rows or legal index
2380 QVERIFY2(lastindex < 0 || view->visualIndex(lastindex) >= 0, verifytext); // no rows or legal index
2381 QVERIFY2(lastindex < 0 || view->logicalIndex(lastindex) >= 0, verifytext); // no rows or legal index
2382 QVERIFY2(view->visualIndexAt(-1) == -1, verifytext);
2383 QVERIFY2(view->logicalIndexAt(-1) == -1, verifytext);
2384 QVERIFY2(view->visualIndexAt(view->length()) == -1, verifytext);
2385 QVERIFY2(view->logicalIndexAt(view->length()) == -1, verifytext);
2386 QVERIFY2(sum_visual == sum_logical, verifytext);
2387 QVERIFY2(sum_to_last_index == sum_logical, verifytext);
2391 const bool check_semantics = true; // Otherwise there is no 'real' test
2392 if (!check_semantics)
2395 const int *x = precalced_comparedata;
2397 QString msg = "semantic problem at " + QString(__FILE__) + " (" + sline + ")";
2398 msg += "\nThe *expected* result was : {" + istr(x[0]) + istr(x[1]) + istr(x[2]) + istr(x[3])
2399 + istr(x[4]) + istr(x[5]) + istr(x[6], false) + "}";
2400 msg += "\nThe calculated result was : {";
2401 msg += istr(chk_visual) + istr(chk_logical) + istr(chk_sizes) + istr(chk_hidden_size)
2402 + istr(chk_lookup_visual) + istr(chk_lookup_logical) + istr(header_lenght, false) + "};";
2404 char *verifytext = QTest::toString(msg);
2406 QVERIFY2(chk_visual == x[0], verifytext);
2407 QVERIFY2(chk_logical == x[1], verifytext);
2408 QVERIFY2(chk_sizes == x[2], verifytext);
2409 QVERIFY2(chk_hidden_size == x[3], verifytext);
2410 QVERIFY2(chk_lookup_visual == x[4], verifytext);
2411 QVERIFY2(chk_lookup_logical == x[5], verifytext);
2412 QVERIFY2(header_lenght == x[6], verifytext);
2415 void tst_QHeaderView::setupTestData(bool also_use_reset_model)
2417 QTest::addColumn<bool>("updates_enabled");
2418 QTest::addColumn<bool>("special_prepare");
2419 QTest::addColumn<bool>("reset_model");
2421 if (also_use_reset_model) {
2422 QTest::newRow("no_updates+normal+reset") << false << false << true;
2423 QTest::newRow("hasupdates+normal+reset") << true << false << true;
2424 QTest::newRow("no_updates+special+reset") << false << true << true;
2425 QTest::newRow("hasupdates+special+reset") << true << true << true;
2428 QTest::newRow("no_updates+normal") << false << false << false;
2429 QTest::newRow("hasupdates+normal") << true << false << false;
2430 QTest::newRow("no_updates+special") << false << true << false;
2431 QTest::newRow("hasupdates+special") << true << true << false;
2434 void tst_QHeaderView::additionalInit()
2436 m_tableview->setVerticalHeader(view);
2438 QFETCH(bool, updates_enabled);
2439 QFETCH(bool, special_prepare);
2440 QFETCH(bool, reset_model);
2442 m_using_reset_model = reset_model;
2444 if (m_using_reset_model) {
2445 XResetModel *m = new XResetModel();
2446 m_tableview->setModel(m);
2450 m_tableview->setModel(model);
2453 const int default_section_size = 25;
2454 view->setDefaultSectionSize(default_section_size); // Important - otherwise there will be semantic changes
2458 if (special_prepare) {
2460 for (int u = 0; u <= rowcount; ++u) // ensures fragmented spans in e.g Qt 4.7
2461 model->setRowCount(u);
2463 model->setColumnCount(colcount);
2464 view->swapSections(0, rowcount - 1);
2465 view->swapSections(0, rowcount - 1); // No real change - setup visual and log-indexes
2466 view->hideSection(rowcount - 1);
2467 view->showSection(rowcount - 1); // No real change - (maybe init hidden vector)
2469 model->setColumnCount(colcount);
2470 model->setRowCount(rowcount);
2474 for (int i = 0; i < model->rowCount(); ++i) {
2475 model->setData(model->index(i, 0), QVariant(i));
2478 s += 'a' + (i % 25);
2479 model->setData(model->index(i, 1), QVariant(s));
2481 m_tableview->setUpdatesEnabled(updates_enabled);
2482 view->blockSignals(block_some_signals);
2486 void tst_QHeaderView::logicalIndexAtTest()
2490 view->swapSections(4, 9); // Make sure that visual and logical Indexes are not just the same.
2494 for (int u = 0; u < model->rowCount(); ++u) {
2495 view->resizeSection(u, 10 + u % 30);
2496 int v = view->visualIndexAt(u * 29);
2497 view->visualIndexAt(u * 29);
2501 view->resizeSection(0, 0); // Make sure that we have a 0 size section - before the result set
2502 view->setSectionHidden(6, true); // Make sure we have a real hidden section before result set
2504 //qDebug() << "logicalIndexAtTest" << check1 << check2;
2505 const int precalced_check1 = 106327;
2506 const int precalced_check2 = 29856418;
2507 QVERIFY(precalced_check1 == check1);
2508 QVERIFY(precalced_check2 == check2);
2510 const int precalced_results[] = { 1145298384, -1710423344, -650981936, 372919464, -1544372176, -426463328, 12124 };
2511 calculateAndCheck(__LINE__, precalced_results);
2514 void tst_QHeaderView::visualIndexAtTest()
2518 view->swapSections(4, 9); // Make sure that visual and logical Indexes are not just the same.
2522 for (int u = 0; u < model->rowCount(); ++u) {
2523 view->resizeSection(u, 3 + u % 17);
2524 int v = view->visualIndexAt(u * 29);
2529 view->resizeSection(1, 0); // Make sure that we have a 0 size section - before the result set
2530 view->setSectionHidden(5, true); // Make sure we have a real hidden section before result set
2532 //qDebug() << "visualIndexAtTest" << check1 << check2;
2533 const int precalced_check1 = 72665;
2534 const int precalced_check2 = 14015890;
2535 QVERIFY(precalced_check1 == check1);
2536 QVERIFY(precalced_check2 == check2);
2538 const int precalced_results[] = { 1145298384, -1710423344, -1457520212, 169223959, 557466160, -324939600, 5453 };
2539 calculateAndCheck(__LINE__, precalced_results);
2542 void tst_QHeaderView::hideShowTest()
2546 for (int u = model->rowCount(); u >= 0; --u)
2548 view->hideSection(u);
2550 for (int u = model->rowCount(); u >= 0; --u)
2552 view->showSection(u);
2554 view->setSectionHidden(model->rowCount(), true); // invalid hide (should be ignored)
2555 view->setSectionHidden(-1, true); // invalid hide (should be ignored)
2557 const int precalced_results[] = { -1523279360, -1523279360, -1321506816, 2105322423, 1879611280, 1879611280, 5225 };
2558 calculateAndCheck(__LINE__, precalced_results);
2561 void tst_QHeaderView::swapSectionsTest()
2565 for (int u = 0; u < rowcount / 2; ++u)
2566 view->swapSections(u, rowcount - u - 1);
2568 for (int u = 0; u < rowcount; u += 2)
2569 view->swapSections(u, u + 1);
2571 view->swapSections(0, model->rowCount()); // invalid swapsection (should be ignored)
2573 const int precalced_results[] = { -1536450048, -1774641430, -1347156568, 1, 1719705216, -240077576, 12500 };
2574 calculateAndCheck(__LINE__, precalced_results);
2577 void tst_QHeaderView::moveSectionTest()
2581 for (int u = 1; u < 5; ++u)
2582 view->moveSection(u, model->rowCount() - u);
2584 view->moveSection(2, model->rowCount() / 2);
2585 view->moveSection(0, 10);
2586 view->moveSection(0, model->rowCount() - 10);
2588 view->moveSection(0, model->rowCount()); // invalid move (should be ignored)
2590 const int precalced_results[] = { 645125952, 577086896, -1347156568, 1, 1719705216, 709383416, 12500 };
2591 calculateAndCheck(__LINE__, precalced_results);
2594 void tst_QHeaderView::defaultSizeTest()
2598 view->hideSection(rowcount / 2);
2599 int restore_to = view->defaultSectionSize();
2600 view->setDefaultSectionSize(restore_to + 5);
2602 const int precalced_results[] = { -1523279360, -1523279360, -1739688320, -1023807777, 997629696, 997629696, 14970 };
2603 calculateAndCheck(__LINE__, precalced_results);
2605 view->setDefaultSectionSize(restore_to);
2608 void tst_QHeaderView::removeTest()
2612 view->swapSections(0, 5);
2613 model->removeRows(0, 1); // remove one row
2614 model->removeRows(4, 10);
2615 model->setRowCount(model->rowCount() / 2 - 1);
2617 if (m_using_reset_model) {
2618 const int precalced_results[] = { 1741224292, -135269187, -569519837, 1, 1719705216, -1184395000, 6075 };
2619 calculateAndCheck(__LINE__, precalced_results);
2621 const int precalced_results[] = { 289162397, 289162397, -569519837, 1, 1719705216, 1719705216, 6075 };
2622 calculateAndCheck(__LINE__, precalced_results);
2626 void tst_QHeaderView::insertTest()
2630 view->swapSections(0, model->rowCount() - 1);
2631 model->insertRows(0, 1); // insert one row
2632 model->insertRows(4, 10);
2633 model->setRowCount(model->rowCount() * 2 - 1);
2635 if (m_using_reset_model) {
2636 const int precalced_results[] = { 2040508069, -1280266538, -150350734, 1, 1719705216, 1331312784, 25525 };
2637 calculateAndCheck(__LINE__, precalced_results);
2639 const int precalced_results[] = { -1909447021, 339092083, -150350734, 1, 1719705216, -969712728, 25525 };
2640 calculateAndCheck(__LINE__, precalced_results);
2644 void tst_QHeaderView::mixedTests()
2648 model->setRowCount(model->rowCount() + 10);
2650 for (int u = 0; u < model->rowCount(); u += 2)
2651 view->swapSections(u, u + 1);
2653 view->moveSection(0, 5);
2655 for (int u = model->rowCount(); u >= 0; --u) {
2657 view->hideSection(u);
2659 view->showSection(u);
2662 model->insertRows(3, 7);
2663 model->removeRows(8, 3);
2664 model->setRowCount(model->rowCount() - 10);
2666 if (m_using_reset_model) {
2667 const int precalced_results[] = { 898296472, 337096378, -543340640, 1, -1251526424, -568618976, 9250 };
2668 calculateAndCheck(__LINE__, precalced_results);
2670 const int precalced_results[] = { 1911338224, 1693514365, -613398968, -1912534953, 1582159424, -1851079000, 9300 };
2671 calculateAndCheck(__LINE__, precalced_results);
2675 void tst_QHeaderView::resizeToContentTest()
2679 QModelIndex idx = model->index(2, 2);
2680 model->setData(idx, QVariant("A normal string"));
2682 idx = model->index(1, 3);
2683 model->setData(idx, QVariant("A normal longer string to test resize"));
2685 QHeaderView *hh = m_tableview->horizontalHeader();
2686 hh->resizeSections(QHeaderView::ResizeToContents);
2687 QVERIFY(hh->sectionSize(3) > hh->sectionSize(2));
2689 for (int u = 0; u < 10; ++u)
2690 view->resizeSection(u, 1);
2692 view->resizeSections(QHeaderView::ResizeToContents);
2693 QVERIFY(view->sectionSize(1) > 1);
2694 QVERIFY(view->sectionSize(2) > 1);
2696 view->setDefaultSectionSize(25); // To make sure our precalced data are correct. We do not know font height etc.
2698 const int precalced_results[] = { -1523279360, -1523279360, -1347156568, 1, 1719705216, 1719705216, 12500 };
2699 calculateAndCheck(__LINE__, precalced_results);
2702 void tst_QHeaderView::testStreamWithHide()
2704 #ifndef QT_NO_DATASTREAM
2705 m_tableview->setVerticalHeader(view);
2706 m_tableview->setModel(model);
2707 view->setDefaultSectionSize(25);
2708 view->hideSection(2);
2709 view->swapSections(1, 2);
2711 QByteArray s = view->saveState();
2712 view->swapSections(1, 2);
2713 view->setDefaultSectionSize(30); // To make sure our precalced data are correct.
2714 view->restoreState(s);
2716 const int precalced_results[] = { -1116614432, -1528653200, -1914165644, 244434607, -1111214068, 750357900, 75};
2717 calculateAndCheck(__LINE__, precalced_results);
2719 QSKIP("Datastream required for testStreamWithHide. Skipping this test.");
2723 QTEST_MAIN(tst_QHeaderView)
2724 #include "tst_qheaderview.moc"