| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Copyright (C) 2012 Thorbjørn Lund Martsum - tmartsum[at]gmail.com |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the test suite of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| |
| #include <QtTest/QtTest> |
| #include <QStandardItemModel> |
| #include <QStringListModel> |
| #include <QSortFilterProxyModel> |
| #include <QTableView> |
| #include <QProxyStyle> |
| |
| #include <qabstractitemmodel.h> |
| #include <qapplication.h> |
| #include <qheaderview.h> |
| #include <private/qheaderview_p.h> |
| #include <qitemdelegate.h> |
| #include <qtreewidget.h> |
| #include <qdebug.h> |
| #include <qscreen.h> |
| #include <qdesktopwidget.h> |
| |
| typedef QList<int> IntList; |
| |
| typedef QList<bool> BoolList; |
| |
| class TestStyle : public QProxyStyle |
| { |
| public: |
| void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const |
| { |
| if (element == CE_HeaderSection) { |
| if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) |
| lastPosition = header->position; |
| } |
| QProxyStyle::drawControl(element, option, painter, widget); |
| } |
| mutable QStyleOptionHeader::SectionPosition lastPosition; |
| }; |
| |
| class protected_QHeaderView : public QHeaderView |
| { |
| Q_OBJECT |
| public: |
| protected_QHeaderView(Qt::Orientation orientation) : QHeaderView(orientation) { |
| resizeSections(); |
| }; |
| |
| void testEvent(); |
| void testhorizontalOffset(); |
| void testverticalOffset(); |
| void testVisualRegionForSelection(); |
| friend class tst_QHeaderView; |
| }; |
| |
| class XResetModel : public QStandardItemModel |
| { |
| virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) |
| { |
| blockSignals(true); |
| bool r = QStandardItemModel::removeRows(row, count, parent); |
| blockSignals(false); |
| beginResetModel(); |
| endResetModel(); |
| return r; |
| } |
| virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) |
| { |
| blockSignals(true); |
| bool r = QStandardItemModel::insertRows(row, count, parent); |
| blockSignals(false); |
| beginResetModel(); |
| endResetModel(); |
| return r; |
| } |
| }; |
| |
| class tst_QHeaderView : public QObject |
| { |
| Q_OBJECT |
| |
| public: |
| tst_QHeaderView(); |
| static void initMain(); |
| |
| private slots: |
| void initTestCase(); |
| void cleanupTestCase(); |
| void init(); |
| void cleanup(); |
| void getSetCheck(); |
| void visualIndex(); |
| |
| void visualIndexAt_data(); |
| void visualIndexAt(); |
| |
| void noModel(); |
| void emptyModel(); |
| void removeRows(); |
| void removeCols(); |
| |
| void clickable(); |
| void movable(); |
| void hidden(); |
| void stretch(); |
| |
| void sectionSize_data(); |
| void sectionSize(); |
| |
| void length(); |
| void offset(); |
| void sectionSizeHint(); |
| void logicalIndex(); |
| void logicalIndexAt(); |
| void swapSections(); |
| |
| void moveSection_data(); |
| void moveSection(); |
| |
| void resizeMode(); |
| |
| void resizeSection_data(); |
| void resizeSection(); |
| |
| void resizeAndMoveSection_data(); |
| void resizeAndMoveSection(); |
| void resizeHiddenSection_data(); |
| void resizeHiddenSection(); |
| void resizeAndInsertSection_data(); |
| void resizeAndInsertSection(); |
| void resizeWithResizeModes_data(); |
| void resizeWithResizeModes(); |
| void moveAndInsertSection_data(); |
| void moveAndInsertSection(); |
| void highlightSections(); |
| void showSortIndicator(); |
| void sortIndicatorTracking(); |
| void removeAndInsertRow(); |
| void unhideSection(); |
| void testEvent(); |
| void headerDataChanged(); |
| void currentChanged(); |
| void horizontalOffset(); |
| void verticalOffset(); |
| void stretchSectionCount(); |
| void hiddenSectionCount(); |
| void focusPolicy(); |
| void moveSectionAndReset(); |
| void moveSectionAndRemove(); |
| void saveRestore(); |
| void restoreQt4State(); |
| void restoreToMoreColumns(); |
| void restoreToMoreColumnsNoMovedColumns(); |
| void restoreBeforeSetModel(); |
| void defaultSectionSizeTest(); |
| void defaultSectionSizeTestStyles(); |
| |
| void defaultAlignment_data(); |
| void defaultAlignment(); |
| |
| void globalResizeMode_data(); |
| void globalResizeMode(); |
| |
| void sectionPressedSignal_data(); |
| void sectionPressedSignal(); |
| void sectionClickedSignal_data() { sectionPressedSignal_data(); } |
| void sectionClickedSignal(); |
| |
| void defaultSectionSize_data(); |
| void defaultSectionSize(); |
| |
| void oneSectionSize(); |
| |
| void hideAndInsert_data(); |
| void hideAndInsert(); |
| |
| void removeSection(); |
| void preserveHiddenSectionWidth(); |
| void invisibleStretchLastSection(); |
| void noSectionsWithNegativeSize(); |
| |
| void emptySectionSpan(); |
| void task236450_hidden_data(); |
| void task236450_hidden(); |
| void task248050_hideRow(); |
| void QTBUG6058_reset(); |
| void QTBUG7833_sectionClicked(); |
| void checkLayoutChangeEmptyModel(); |
| void QTBUG8650_crashOnInsertSections(); |
| void QTBUG12268_hiddenMovedSectionSorting(); |
| void QTBUG14242_hideSectionAutoSize(); |
| void QTBUG50171_visualRegionForSwappedItems(); |
| void QTBUG53221_assertShiftHiddenRow(); |
| void QTBUG75615_sizeHintWithStylesheet(); |
| void ensureNoIndexAtLength(); |
| void offsetConsistent(); |
| |
| void initialSortOrderRole(); |
| |
| void logicalIndexAtTest_data() { setupTestData(); } |
| void visualIndexAtTest_data() { setupTestData(); } |
| void hideShowTest_data() { setupTestData(); } |
| void swapSectionsTest_data() { setupTestData(); } |
| void moveSectionTest_data() { setupTestData(); } |
| void defaultSizeTest_data() { setupTestData(); } |
| void removeTest_data() { setupTestData(true); } |
| void insertTest_data() { setupTestData(true); } |
| void mixedTests_data() { setupTestData(true); } |
| void resizeToContentTest_data() { setupTestData(); } |
| void logicalIndexAtTest(); |
| void visualIndexAtTest(); |
| void hideShowTest(); |
| void swapSectionsTest(); |
| void moveSectionTest(); |
| void defaultSizeTest(); |
| void removeTest(); |
| void insertTest(); |
| void mixedTests(); |
| void resizeToContentTest(); |
| void testStreamWithHide(); |
| void testStylePosition(); |
| void stretchAndRestoreLastSection(); |
| void testMinMaxSectionSize_data(); |
| void testMinMaxSectionSize(); |
| void sizeHintCrash(); |
| void testResetCachedSizeHint(); |
| void statusTips(); |
| void testRemovingColumnsViaLayoutChanged(); |
| |
| protected: |
| void setupTestData(bool use_reset_model = false); |
| void additionalInit(); |
| void calculateAndCheck(int cppline, const int precalced_comparedata[]); |
| void testMinMaxSectionSize(bool stretchLastSection); |
| |
| QWidget *topLevel = nullptr; |
| QHeaderView *view = nullptr; |
| QStandardItemModel *model = nullptr; |
| QTableView *m_tableview = nullptr; |
| bool m_using_reset_model = false; |
| bool m_special_prepare = false; |
| QElapsedTimer timer; |
| }; |
| |
| void tst_QHeaderView::initMain() |
| { |
| #ifdef Q_OS_WIN |
| // Ensure minimum size constraints of framed windows on High DPI screens |
| QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); |
| #endif |
| } |
| |
| class QtTestModel: public QAbstractTableModel |
| { |
| |
| Q_OBJECT |
| |
| public: |
| QtTestModel(QObject *parent = 0): QAbstractTableModel(parent), |
| cols(0), rows(0), wrongIndex(false), m_bMultiLine(false) {} |
| int rowCount(const QModelIndex&) const override { return rows; } |
| int columnCount(const QModelIndex&) const override { return cols; } |
| bool isEditable(const QModelIndex &) const { return true; } |
| QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const |
| { |
| if (section < 0 || (role != Qt::DisplayRole && role != Qt::StatusTipRole)) |
| return QVariant(); |
| const int row = (orientation == Qt::Vertical ? section : 0); |
| const int col = (orientation == Qt::Horizontal ? section : 0); |
| if (orientation == Qt::Vertical && row >= rows) |
| return QVariant(); |
| if (orientation == Qt::Horizontal && col >= cols) |
| return QVariant(); |
| if (m_bMultiLine) |
| return QString("%1\n%1").arg(section); |
| return QLatin1Char('[') + QString::number(row) + QLatin1Char(',') |
| + QString::number(col) + QLatin1String(",0] -- Header"); |
| } |
| QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override |
| { |
| if (role != Qt::DisplayRole) |
| return QVariant(); |
| if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) { |
| wrongIndex = true; |
| qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(), idx.internalPointer()); |
| } |
| return QLatin1Char('[') + QString::number(idx.row()) + QLatin1Char(',') |
| + QString::number(idx.column()) + QLatin1String(",0]"); |
| } |
| |
| void insertOneColumn(int col) |
| { |
| beginInsertColumns(QModelIndex(), col, col); |
| --cols; |
| endInsertColumns(); |
| } |
| |
| void removeFirstRow() |
| { |
| beginRemoveRows(QModelIndex(), 0, 0); |
| --rows; |
| endRemoveRows(); |
| } |
| |
| void removeLastRow() |
| { |
| beginRemoveRows(QModelIndex(), rows - 1, rows - 1); |
| --rows; |
| endRemoveRows(); |
| } |
| |
| void removeAllRows() |
| { |
| beginRemoveRows(QModelIndex(), 0, rows - 1); |
| rows = 0; |
| endRemoveRows(); |
| } |
| |
| void removeOneColumn(int col) |
| { |
| beginRemoveColumns(QModelIndex(), col, col); |
| --cols; |
| endRemoveColumns(); |
| } |
| |
| void removeLastColumn() |
| { |
| beginRemoveColumns(QModelIndex(), cols - 1, cols - 1); |
| --cols; |
| endRemoveColumns(); |
| } |
| |
| void removeAllColumns() |
| { |
| beginRemoveColumns(QModelIndex(), 0, cols - 1); |
| cols = 0; |
| endRemoveColumns(); |
| } |
| |
| void cleanup() |
| { |
| emit layoutAboutToBeChanged(); |
| cols = 3; |
| rows = 3; |
| emit layoutChanged(); |
| } |
| |
| void emitLayoutChanged() |
| { |
| emit layoutAboutToBeChanged(); |
| emit layoutChanged(); |
| } |
| |
| void emitLayoutChangedWithRemoveFirstRow() |
| { |
| emit layoutAboutToBeChanged(); |
| QModelIndexList milNew; |
| const auto milOld = persistentIndexList(); |
| milNew.reserve(milOld.size()); |
| for (int i = 0; i < milOld.size(); ++i) |
| milNew += QModelIndex(); |
| changePersistentIndexList(milOld, milNew); |
| emit layoutChanged(); |
| } |
| |
| void setMultiLineHeader(bool bEnable) |
| { |
| beginResetModel(); |
| m_bMultiLine = bEnable; |
| endResetModel(); |
| } |
| |
| int cols, rows; |
| mutable bool wrongIndex; |
| bool m_bMultiLine; |
| }; |
| |
| // Testing get/set functions |
| void tst_QHeaderView::getSetCheck() |
| { |
| protected_QHeaderView obj1(Qt::Horizontal); |
| // bool QHeaderView::highlightSections() |
| // void QHeaderView::setHighlightSections(bool) |
| obj1.setHighlightSections(false); |
| QCOMPARE(false, obj1.highlightSections()); |
| obj1.setHighlightSections(true); |
| QCOMPARE(true, obj1.highlightSections()); |
| |
| // bool QHeaderView::stretchLastSection() |
| // void QHeaderView::setStretchLastSection(bool) |
| obj1.setStretchLastSection(false); |
| QCOMPARE(false, obj1.stretchLastSection()); |
| obj1.setStretchLastSection(true); |
| QCOMPARE(true, obj1.stretchLastSection()); |
| |
| // int QHeaderView::defaultSectionSize() |
| // void QHeaderView::setDefaultSectionSize(int) |
| obj1.setMinimumSectionSize(0); |
| obj1.setDefaultSectionSize(-1); |
| QVERIFY(obj1.defaultSectionSize() >= 0); |
| obj1.setDefaultSectionSize(0); |
| QCOMPARE(0, obj1.defaultSectionSize()); |
| obj1.setDefaultSectionSize(99999); |
| QCOMPARE(99999, obj1.defaultSectionSize()); |
| |
| // int QHeaderView::minimumSectionSize() |
| // void QHeaderView::setMinimumSectionSize(int) |
| obj1.setMinimumSectionSize(-1); |
| QVERIFY(obj1.minimumSectionSize() >= 0); |
| obj1.setMinimumSectionSize(0); |
| QCOMPARE(0, obj1.minimumSectionSize()); |
| obj1.setMinimumSectionSize(99999); |
| QCOMPARE(99999, obj1.minimumSectionSize()); |
| obj1.setMinimumSectionSize(-1); |
| QVERIFY(obj1.minimumSectionSize() < 100); |
| |
| // int QHeaderView::offset() |
| // void QHeaderView::setOffset(int) |
| obj1.setOffset(0); |
| QCOMPARE(0, obj1.offset()); |
| obj1.setOffset(INT_MIN); |
| QCOMPARE(INT_MIN, obj1.offset()); |
| obj1.setOffset(INT_MAX); |
| QCOMPARE(INT_MAX, obj1.offset()); |
| |
| } |
| |
| tst_QHeaderView::tst_QHeaderView() |
| { |
| qRegisterMetaType<int>("Qt::SortOrder"); |
| } |
| |
| void tst_QHeaderView::initTestCase() |
| { |
| m_tableview = new QTableView; |
| qDebug().noquote().nospace() |
| << "default min section size is " |
| << QString::number(m_tableview->verticalHeader()->minimumSectionSize()) |
| << QLatin1Char('/') |
| << m_tableview->horizontalHeader()->minimumSectionSize() |
| << " (v/h)"; |
| } |
| |
| void tst_QHeaderView::cleanupTestCase() |
| { |
| delete m_tableview; |
| } |
| |
| void tst_QHeaderView::init() |
| { |
| topLevel = new QWidget(); |
| view = new QHeaderView(Qt::Vertical,topLevel); |
| // Some initial value tests before a model is added |
| QCOMPARE(view->length(), 0); |
| QCOMPARE(view->sizeHint(), QSize(0,0)); |
| QCOMPARE(view->sectionSizeHint(0), -1); |
| view->setMinimumSectionSize(0); // system default min size can be to large |
| |
| /* |
| model = new QStandardItemModel(1, 1); |
| view->setModel(model); |
| //qDebug() << view->count(); |
| view->sizeHint(); |
| */ |
| |
| int rows = 4; |
| int columns = 4; |
| model = new QStandardItemModel(rows, columns); |
| /* |
| for (int row = 0; row < rows; ++row) { |
| for (int column = 0; column < columns; ++column) { |
| QModelIndex index = model->index(row, column, QModelIndex()); |
| model->setData(index, QVariant((row+1) * (column+1))); |
| } |
| } |
| */ |
| |
| QSignalSpy spy(view, SIGNAL(sectionCountChanged(int,int))); |
| view->setModel(model); |
| QCOMPARE(spy.count(), 1); |
| view->resize(200,200); |
| } |
| |
| void tst_QHeaderView::cleanup() |
| { |
| m_tableview->setUpdatesEnabled(true); |
| if (view && view->parent() != m_tableview) |
| delete view; |
| view = 0; |
| delete model; |
| model = 0; |
| delete topLevel; |
| topLevel = 0; |
| } |
| |
| void tst_QHeaderView::noModel() |
| { |
| QHeaderView emptyView(Qt::Vertical); |
| QCOMPARE(emptyView.count(), 0); |
| } |
| |
| void tst_QHeaderView::emptyModel() |
| { |
| QtTestModel testmodel; |
| view->setModel(&testmodel); |
| QVERIFY(!testmodel.wrongIndex); |
| QCOMPARE(view->count(), testmodel.rows); |
| view->setModel(model); |
| } |
| |
| void tst_QHeaderView::removeRows() |
| { |
| QtTestModel model; |
| model.rows = model.cols = 10; |
| |
| QHeaderView vertical(Qt::Vertical); |
| QHeaderView horizontal(Qt::Horizontal); |
| |
| vertical.setModel(&model); |
| horizontal.setModel(&model); |
| vertical.show(); |
| horizontal.show(); |
| QCOMPARE(vertical.count(), model.rows); |
| QCOMPARE(horizontal.count(), model.cols); |
| |
| model.removeLastRow(); |
| QVERIFY(!model.wrongIndex); |
| QCOMPARE(vertical.count(), model.rows); |
| QCOMPARE(horizontal.count(), model.cols); |
| |
| model.removeAllRows(); |
| QVERIFY(!model.wrongIndex); |
| QCOMPARE(vertical.count(), model.rows); |
| QCOMPARE(horizontal.count(), model.cols); |
| } |
| |
| |
| void tst_QHeaderView::removeCols() |
| { |
| QtTestModel model; |
| model.rows = model.cols = 10; |
| |
| QHeaderView vertical(Qt::Vertical); |
| QHeaderView horizontal(Qt::Horizontal); |
| vertical.setModel(&model); |
| horizontal.setModel(&model); |
| vertical.show(); |
| horizontal.show(); |
| QCOMPARE(vertical.count(), model.rows); |
| QCOMPARE(horizontal.count(), model.cols); |
| |
| model.removeLastColumn(); |
| QVERIFY(!model.wrongIndex); |
| QCOMPARE(vertical.count(), model.rows); |
| QCOMPARE(horizontal.count(), model.cols); |
| |
| model.removeAllColumns(); |
| QVERIFY(!model.wrongIndex); |
| QCOMPARE(vertical.count(), model.rows); |
| QCOMPARE(horizontal.count(), model.cols); |
| } |
| |
| void tst_QHeaderView::movable() |
| { |
| QCOMPARE(view->sectionsMovable(), false); |
| view->setSectionsMovable(false); |
| QCOMPARE(view->sectionsMovable(), false); |
| view->setSectionsMovable(true); |
| QCOMPARE(view->sectionsMovable(), true); |
| |
| QCOMPARE(view->isFirstSectionMovable(), true); |
| view->setFirstSectionMovable(false); |
| QCOMPARE(view->isFirstSectionMovable(), false); |
| view->setFirstSectionMovable(true); |
| QCOMPARE(view->isFirstSectionMovable(), true); |
| } |
| |
| void tst_QHeaderView::clickable() |
| { |
| QCOMPARE(view->sectionsClickable(), false); |
| view->setSectionsClickable(false); |
| QCOMPARE(view->sectionsClickable(), false); |
| view->setSectionsClickable(true); |
| QCOMPARE(view->sectionsClickable(), true); |
| } |
| |
| void tst_QHeaderView::hidden() |
| { |
| //hideSection() & showSection call setSectionHidden |
| // Test bad arguments |
| QCOMPARE(view->isSectionHidden(-1), false); |
| QCOMPARE(view->isSectionHidden(view->count()), false); |
| QCOMPARE(view->isSectionHidden(999999), false); |
| |
| view->setSectionHidden(-1, true); |
| view->setSectionHidden(view->count(), true); |
| view->setSectionHidden(999999, true); |
| view->setSectionHidden(-1, false); |
| view->setSectionHidden(view->count(), false); |
| view->setSectionHidden(999999, false); |
| |
| // Hidden sections shouldn't have visual properties (except position) |
| int pos = view->defaultSectionSize(); |
| view->setSectionHidden(1, true); |
| QCOMPARE(view->sectionSize(1), 0); |
| QCOMPARE(view->sectionPosition(1), pos); |
| view->resizeSection(1, 100); |
| QCOMPARE(view->sectionViewportPosition(1), pos); |
| QCOMPARE(view->sectionSize(1), 0); |
| view->setSectionHidden(1, false); |
| QCOMPARE(view->isSectionHidden(0), false); |
| QCOMPARE(view->sectionSize(0), view->defaultSectionSize()); |
| |
| // d->hiddenSectionSize could go out of sync when a new model |
| // was set which has fewer sections than before and some of them |
| // were hidden |
| QStandardItemModel model2(model->rowCount() - 1, model->columnCount()); |
| |
| for (int i = 0; i < model->rowCount(); ++i) |
| view->setSectionHidden(i, true); |
| view->setModel(&model2); |
| QVERIFY(view->sectionsHidden()); |
| for (int i = 0; i < model2.rowCount(); ++i) { |
| QVERIFY(view->isSectionHidden(i)); |
| } |
| |
| view->setModel(model); |
| for (int i = 0; i < model2.rowCount(); ++i) { |
| QVERIFY(view->isSectionHidden(i)); |
| } |
| QCOMPARE(view->isSectionHidden(model->rowCount() - 1), false); |
| for (int i = 0; i < model->rowCount(); ++i) |
| view->setSectionHidden(i, false); |
| } |
| |
| void tst_QHeaderView::stretch() |
| { |
| // Show before resize and setStretchLastSection |
| QSize viewSize(500, 500); |
| view->resize(viewSize); |
| view->setStretchLastSection(true); |
| QCOMPARE(view->stretchLastSection(), true); |
| topLevel->show(); |
| QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| QCOMPARE(view->width(), viewSize.width()); |
| QCOMPARE(view->visualIndexAt(view->viewport()->height() - 5), 3); |
| |
| view->setSectionHidden(3, true); |
| QCOMPARE(view->visualIndexAt(view->viewport()->height() - 5), 2); |
| |
| view->setStretchLastSection(false); |
| QCOMPARE(view->stretchLastSection(), false); |
| } |
| |
| void tst_QHeaderView::oneSectionSize() |
| { |
| //this ensures that if there is only one section, it gets a correct width (more than 0) |
| QHeaderView view (Qt::Vertical); |
| QtTestModel model; |
| model.cols = 1; |
| model.rows = 1; |
| |
| view.setSectionResizeMode(QHeaderView::Interactive); |
| view.setModel(&model); |
| |
| view.show(); |
| |
| QVERIFY(view.sectionSize(0) > 0); |
| } |
| |
| |
| void tst_QHeaderView::sectionSize_data() |
| { |
| QTest::addColumn<QList<int> >("boundsCheck"); |
| QTest::addColumn<QList<int> >("defaultSizes"); |
| QTest::addColumn<int>("initialDefaultSize"); |
| QTest::addColumn<int>("lastVisibleSectionSize"); |
| QTest::addColumn<int>("persistentSectionSize"); |
| |
| QTest::newRow("data set one") |
| << (QList<int>() << -1 << 0 << 4 << 9999) |
| << (QList<int>() << 10 << 30 << 30) |
| << 30 |
| << 300 |
| << 20; |
| } |
| |
| void tst_QHeaderView::sectionSize() |
| { |
| #if defined Q_OS_QNX |
| QSKIP("The section size is dpi dependent on QNX"); |
| #elif defined Q_OS_WINRT |
| QSKIP("Fails on WinRT - QTBUG-68297"); |
| #endif |
| QFETCH(QList<int>, boundsCheck); |
| QFETCH(QList<int>, defaultSizes); |
| QFETCH(int, initialDefaultSize); |
| QFETCH(int, lastVisibleSectionSize); |
| QFETCH(int, persistentSectionSize); |
| |
| // bounds check |
| foreach (int val, boundsCheck) |
| view->sectionSize(val); |
| |
| // default size |
| QCOMPARE(view->defaultSectionSize(), initialDefaultSize); |
| foreach (int def, defaultSizes) { |
| view->setDefaultSectionSize(def); |
| QCOMPARE(view->defaultSectionSize(), def); |
| } |
| |
| view->setDefaultSectionSize(initialDefaultSize); |
| for (int s = 0; s < view->count(); ++s) |
| QCOMPARE(view->sectionSize(s), initialDefaultSize); |
| view->doItemsLayout(); |
| |
| // stretch last section |
| view->setStretchLastSection(true); |
| int lastSection = view->count() - 1; |
| |
| //test that when hiding the last column, |
| //resizing the new last visible columns still works |
| view->hideSection(lastSection); |
| view->resizeSection(lastSection - 1, lastVisibleSectionSize); |
| QCOMPARE(view->sectionSize(lastSection - 1), lastVisibleSectionSize); |
| view->showSection(lastSection); |
| |
| // turn off stretching |
| view->setStretchLastSection(false); |
| QCOMPARE(view->sectionSize(lastSection), initialDefaultSize); |
| |
| // test persistence |
| int sectionCount = view->count(); |
| for (int i = 0; i < sectionCount; ++i) |
| view->resizeSection(i, persistentSectionSize); |
| QtTestModel model; |
| model.cols = sectionCount * 2; |
| model.rows = sectionCount * 2; |
| view->setModel(&model); |
| for (int j = 0; j < sectionCount; ++j) |
| QCOMPARE(view->sectionSize(j), persistentSectionSize); |
| for (int k = sectionCount; k < view->count(); ++k) |
| QCOMPARE(view->sectionSize(k), initialDefaultSize); |
| } |
| |
| void tst_QHeaderView::visualIndex() |
| { |
| // Test bad arguments |
| QCOMPARE(view->visualIndex(999999), -1); |
| QCOMPARE(view->visualIndex(-1), -1); |
| QCOMPARE(view->visualIndex(1), 1); |
| view->setSectionHidden(1, true); |
| QCOMPARE(view->visualIndex(1), 1); |
| QCOMPARE(view->visualIndex(2), 2); |
| |
| view->setSectionHidden(1, false); |
| QCOMPARE(view->visualIndex(1), 1); |
| QCOMPARE(view->visualIndex(2), 2); |
| } |
| |
| void tst_QHeaderView::visualIndexAt_data() |
| { |
| QTest::addColumn<QList<int> >("hidden"); |
| QTest::addColumn<QList<int> >("from"); |
| QTest::addColumn<QList<int> >("to"); |
| QTest::addColumn<QList<int> >("coordinate"); |
| QTest::addColumn<QList<int> >("visual"); |
| |
| QList<int> coordinateList; |
| coordinateList << -1 << 0 << 31 << 91 << 99999; |
| |
| QTest::newRow("no hidden, no moved sections") |
| << QList<int>() |
| << QList<int>() |
| << QList<int>() |
| << coordinateList |
| << (QList<int>() << -1 << 0 << 1 << 3 << -1); |
| |
| QTest::newRow("no hidden, moved sections") |
| << QList<int>() |
| << (QList<int>() << 0) |
| << (QList<int>() << 1) |
| << coordinateList |
| << (QList<int>() << -1 << 0 << 1 << 3 << -1); |
| |
| QTest::newRow("hidden, no moved sections") |
| << (QList<int>() << 0) |
| << QList<int>() |
| << QList<int>() |
| << coordinateList |
| << (QList<int>() << -1 << 1 << 2 << 3 << -1); |
| } |
| |
| void tst_QHeaderView::visualIndexAt() |
| { |
| #if defined Q_OS_QNX |
| QSKIP("The section size is dpi dependent on QNX"); |
| #elif defined Q_OS_WINRT |
| QSKIP("Fails on WinRT - QTBUG-68297"); |
| #endif |
| QFETCH(QList<int>, hidden); |
| QFETCH(QList<int>, from); |
| QFETCH(QList<int>, to); |
| QFETCH(QList<int>, coordinate); |
| QFETCH(QList<int>, visual); |
| |
| view->setStretchLastSection(true); |
| topLevel->show(); |
| QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| |
| for (int i = 0; i < hidden.count(); ++i) |
| view->setSectionHidden(hidden.at(i), true); |
| |
| for (int j = 0; j < from.count(); ++j) |
| view->moveSection(from.at(j), to.at(j)); |
| |
| QTest::qWait(100); |
| |
| for (int k = 0; k < coordinate.count(); ++k) |
| QCOMPARE(view->visualIndexAt(coordinate.at(k)), visual.at(k)); |
| } |
| |
| void tst_QHeaderView::length() |
| { |
| view->setStretchLastSection(true); |
| topLevel->show(); |
| QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| |
| //minimumSectionSize should be the size of the last section of the widget is not tall enough |
| int length = view->minimumSectionSize(); |
| for (int i=0; i < view->count()-1; i++) { |
| length += view->sectionSize(i); |
| } |
| |
| length = qMax(length, view->viewport()->height()); |
| QCOMPARE(length, view->length()); |
| |
| view->setStretchLastSection(false); |
| topLevel->show(); |
| QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| |
| QVERIFY(length != view->length()); |
| |
| // layoutChanged might mean rows have been removed |
| QtTestModel model; |
| model.cols = 10; |
| model.rows = 10; |
| view->setModel(&model); |
| int oldLength = view->length(); |
| model.cleanup(); |
| QCOMPARE(model.rows, view->count()); |
| QVERIFY(oldLength != view->length()); |
| } |
| |
| void tst_QHeaderView::offset() |
| { |
| QCOMPARE(view->offset(), 0); |
| view->setOffset(10); |
| QCOMPARE(view->offset(), 10); |
| view->setOffset(0); |
| QCOMPARE(view->offset(), 0); |
| |
| // Test odd arguments |
| view->setOffset(-1); |
| } |
| |
| void tst_QHeaderView::sectionSizeHint() |
| { |
| QCOMPARE(view->sectionSizeHint(-1), -1); |
| QCOMPARE(view->sectionSizeHint(99999), -1); |
| QVERIFY(view->sectionSizeHint(0) >= 0); |
| } |
| |
| void tst_QHeaderView::logicalIndex() |
| { |
| // Test bad arguments |
| QCOMPARE(view->logicalIndex(-1), -1); |
| QCOMPARE(view->logicalIndex(99999), -1); |
| } |
| |
| void tst_QHeaderView::logicalIndexAt() |
| { |
| // Test bad arguments |
| view->logicalIndexAt(-1); |
| view->logicalIndexAt(99999); |
| QCOMPARE(view->logicalIndexAt(0), 0); |
| QCOMPARE(view->logicalIndexAt(1), 0); |
| |
| topLevel->show(); |
| QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| view->setStretchLastSection(true); |
| // First item |
| QCOMPARE(view->logicalIndexAt(0), 0); |
| QCOMPARE(view->logicalIndexAt(view->sectionSize(0)-1), 0); |
| QCOMPARE(view->logicalIndexAt(view->sectionSize(0)+1), 1); |
| // Last item |
| int last = view->length() - 1;//view->viewport()->height() - 10; |
| QCOMPARE(view->logicalIndexAt(last), 3); |
| // Not in widget |
| int outofbounds = view->length() + 1;//view->viewport()->height() + 1; |
| QCOMPARE(view->logicalIndexAt(outofbounds), -1); |
| |
| view->moveSection(0,1); |
| // First item |
| QCOMPARE(view->logicalIndexAt(0), 1); |
| QCOMPARE(view->logicalIndexAt(view->sectionSize(0)-1), 1); |
| QCOMPARE(view->logicalIndexAt(view->sectionSize(0)+1), 0); |
| // Last item |
| QCOMPARE(view->logicalIndexAt(last), 3); |
| view->moveSection(1,0); |
| |
| } |
| |
| void tst_QHeaderView::swapSections() |
| { |
| view->swapSections(-1, 1); |
| view->swapSections(99999, 1); |
| view->swapSections(1, -1); |
| view->swapSections(1, 99999); |
| |
| QVector<int> logical = (QVector<int>() << 0 << 1 << 2 << 3); |
| |
| QSignalSpy spy1(view, SIGNAL(sectionMoved(int,int,int))); |
| |
| QCOMPARE(view->sectionsMoved(), false); |
| view->swapSections(1, 1); |
| QCOMPARE(view->sectionsMoved(), false); |
| view->swapSections(1, 2); |
| QCOMPARE(view->sectionsMoved(), true); |
| view->swapSections(2, 1); |
| QCOMPARE(view->sectionsMoved(), true); |
| for (int i = 0; i < view->count(); ++i) |
| QCOMPARE(view->logicalIndex(i), logical.at(i)); |
| QCOMPARE(spy1.count(), 4); |
| |
| logical = (QVector<int>() << 3 << 1 << 2 << 0); |
| view->swapSections(3, 0); |
| QCOMPARE(view->sectionsMoved(), true); |
| for (int j = 0; j < view->count(); ++j) |
| QCOMPARE(view->logicalIndex(j), logical.at(j)); |
| QCOMPARE(spy1.count(), 6); |
| } |
| |
| void tst_QHeaderView::moveSection_data() |
| { |
| QTest::addColumn<QList<int> >("hidden"); |
| QTest::addColumn<QList<int> >("from"); |
| QTest::addColumn<QList<int> >("to"); |
| QTest::addColumn<QList<bool> >("moved"); |
| QTest::addColumn<QList<int> >("logical"); |
| QTest::addColumn<int>("count"); |
| |
| QTest::newRow("bad args, no hidden") |
| << QList<int>() |
| << (QList<int>() << -1 << 1 << 99999 << 1) |
| << (QList<int>() << 1 << -1 << 1 << 99999) |
| << (QList<bool>() << false << false << false << false) |
| << (QList<int>() << 0 << 1 << 2 << 3) |
| << 0; |
| |
| QTest::newRow("good args, no hidden") |
| << QList<int>() |
| << (QList<int>() << 1 << 1 << 2 << 1) |
| << (QList<int>() << 1 << 2 << 1 << 2) |
| << (QList<bool>() << false << true << true << true) |
| << (QList<int>() << 0 << 2 << 1 << 3) |
| << 3; |
| |
| QTest::newRow("hidden sections") |
| << (QList<int>() << 0 << 3) |
| << (QList<int>() << 1 << 1 << 2 << 1) |
| << (QList<int>() << 1 << 2 << 1 << 2) |
| << (QList<bool>() << false << true << true << true) |
| << (QList<int>() << 0 << 2 << 1 << 3) |
| << 3; |
| } |
| |
| void tst_QHeaderView::moveSection() |
| { |
| QFETCH(QList<int>, hidden); |
| QFETCH(QList<int>, from); |
| QFETCH(QList<int>, to); |
| QFETCH(QList<bool>, moved); |
| QFETCH(QList<int>, logical); |
| QFETCH(int, count); |
| |
| QCOMPARE(from.count(), to.count()); |
| QCOMPARE(from.count(), moved.count()); |
| QCOMPARE(view->count(), logical.count()); |
| |
| QSignalSpy spy1(view, SIGNAL(sectionMoved(int,int,int))); |
| QCOMPARE(view->sectionsMoved(), false); |
| |
| for (int h = 0; h < hidden.count(); ++h) |
| view->setSectionHidden(hidden.at(h), true); |
| |
| for (int i = 0; i < from.count(); ++i) { |
| view->moveSection(from.at(i), to.at(i)); |
| QCOMPARE(view->sectionsMoved(), moved.at(i)); |
| } |
| |
| for (int j = 0; j < view->count(); ++j) |
| QCOMPARE(view->logicalIndex(j), logical.at(j)); |
| |
| QCOMPARE(spy1.count(), count); |
| } |
| |
| void tst_QHeaderView::resizeAndMoveSection_data() |
| { |
| QTest::addColumn<IntList>("logicalIndexes"); |
| QTest::addColumn<IntList>("sizes"); |
| QTest::addColumn<int>("logicalFrom"); |
| QTest::addColumn<int>("logicalTo"); |
| |
| QTest::newRow("resizeAndMove-1") |
| << (IntList() << 0 << 1) |
| << (IntList() << 20 << 40) |
| << 0 << 1; |
| |
| QTest::newRow("resizeAndMove-2") |
| << (IntList() << 0 << 1 << 2 << 3) |
| << (IntList() << 20 << 60 << 10 << 80) |
| << 0 << 2; |
| |
| QTest::newRow("resizeAndMove-3") |
| << (IntList() << 0 << 1 << 2 << 3) |
| << (IntList() << 100 << 60 << 40 << 10) |
| << 0 << 3; |
| |
| QTest::newRow("resizeAndMove-4") |
| << (IntList() << 0 << 1 << 2 << 3) |
| << (IntList() << 10 << 40 << 80 << 30) |
| << 1 << 2; |
| |
| QTest::newRow("resizeAndMove-5") |
| << (IntList() << 2 << 3) |
| << (IntList() << 100 << 200) |
| << 3 << 2; |
| } |
| |
| void tst_QHeaderView::resizeAndMoveSection() |
| { |
| QFETCH(IntList, logicalIndexes); |
| QFETCH(IntList, sizes); |
| QFETCH(int, logicalFrom); |
| QFETCH(int, logicalTo); |
| |
| // Save old visual indexes and sizes |
| IntList oldVisualIndexes; |
| IntList oldSizes; |
| foreach (int logical, logicalIndexes) { |
| oldVisualIndexes.append(view->visualIndex(logical)); |
| oldSizes.append(view->sectionSize(logical)); |
| } |
| |
| // Resize sections |
| for (int i = 0; i < logicalIndexes.size(); ++i) { |
| int logical = logicalIndexes.at(i); |
| view->resizeSection(logical, sizes.at(i)); |
| } |
| |
| // Move sections |
| int visualFrom = view->visualIndex(logicalFrom); |
| int visualTo = view->visualIndex(logicalTo); |
| view->moveSection(visualFrom, visualTo); |
| QCOMPARE(view->visualIndex(logicalFrom), visualTo); |
| |
| // Check that sizes are still correct |
| for (int i = 0; i < logicalIndexes.size(); ++i) { |
| int logical = logicalIndexes.at(i); |
| QCOMPARE(view->sectionSize(logical), sizes.at(i)); |
| } |
| |
| // Move sections back |
| view->moveSection(visualTo, visualFrom); |
| |
| // Check that sizes are still correct |
| for (int i = 0; i < logicalIndexes.size(); ++i) { |
| int logical = logicalIndexes.at(i); |
| QCOMPARE(view->sectionSize(logical), sizes.at(i)); |
| } |
| |
| // Put everything back as it was |
| for (int i = 0; i < logicalIndexes.size(); ++i) { |
| int logical = logicalIndexes.at(i); |
| view->resizeSection(logical, oldSizes.at(i)); |
| QCOMPARE(view->visualIndex(logical), oldVisualIndexes.at(i)); |
| } |
| } |
| |
| void tst_QHeaderView::resizeHiddenSection_data() |
| { |
| QTest::addColumn<int>("section"); |
| QTest::addColumn<int>("initialSize"); |
| QTest::addColumn<int>("finalSize"); |
| |
| QTest::newRow("section 0 resize 50 to 20") |
| << 0 << 50 << 20; |
| |
| QTest::newRow("section 1 resize 50 to 20") |
| << 1 << 50 << 20; |
| |
| QTest::newRow("section 2 resize 50 to 20") |
| << 2 << 50 << 20; |
| |
| QTest::newRow("section 3 resize 50 to 20") |
| << 3 << 50 << 20; |
| } |
| |
| void tst_QHeaderView::resizeHiddenSection() |
| { |
| QFETCH(int, section); |
| QFETCH(int, initialSize); |
| QFETCH(int, finalSize); |
| |
| view->resizeSection(section, initialSize); |
| view->setSectionHidden(section, true); |
| QCOMPARE(view->sectionSize(section), 0); |
| |
| view->resizeSection(section, finalSize); |
| QCOMPARE(view->sectionSize(section), 0); |
| |
| view->setSectionHidden(section, false); |
| QCOMPARE(view->sectionSize(section), finalSize); |
| } |
| |
| void tst_QHeaderView::resizeAndInsertSection_data() |
| { |
| QTest::addColumn<int>("section"); |
| QTest::addColumn<int>("size"); |
| QTest::addColumn<int>("insert"); |
| QTest::addColumn<int>("compare"); |
| QTest::addColumn<int>("expected"); |
| |
| QTest::newRow("section 0 size 50 insert 0") |
| << 0 << 50 << 0 << 1 << 50; |
| |
| QTest::newRow("section 1 size 50 insert 1") |
| << 0 << 50 << 1 << 0 << 50; |
| |
| QTest::newRow("section 1 size 50 insert 0") |
| << 1 << 50 << 0 << 2 << 50; |
| |
| } |
| |
| void tst_QHeaderView::resizeAndInsertSection() |
| { |
| QFETCH(int, section); |
| QFETCH(int, size); |
| QFETCH(int, insert); |
| QFETCH(int, compare); |
| QFETCH(int, expected); |
| |
| view->setStretchLastSection(false); |
| |
| view->resizeSection(section, size); |
| QCOMPARE(view->sectionSize(section), size); |
| |
| model->insertRow(insert); |
| |
| QCOMPARE(view->sectionSize(compare), expected); |
| } |
| |
| void tst_QHeaderView::resizeWithResizeModes_data() |
| { |
| QTest::addColumn<int>("size"); |
| QTest::addColumn<QList<int> >("sections"); |
| QTest::addColumn<QList<int> >("modes"); |
| QTest::addColumn<QList<int> >("expected"); |
| |
| QTest::newRow("stretch first section") |
| << 600 |
| << (QList<int>() << 100 << 100 << 100 << 100) |
| << (QList<int>() << ((int)QHeaderView::Stretch) |
| << ((int)QHeaderView::Interactive) |
| << ((int)QHeaderView::Interactive) |
| << ((int)QHeaderView::Interactive)) |
| << (QList<int>() << 300 << 100 << 100 << 100); |
| } |
| |
| void tst_QHeaderView::resizeWithResizeModes() |
| { |
| QFETCH(int, size); |
| QFETCH(QList<int>, sections); |
| QFETCH(QList<int>, modes); |
| QFETCH(QList<int>, expected); |
| |
| view->setStretchLastSection(false); |
| for (int i = 0; i < sections.count(); ++i) { |
| view->resizeSection(i, sections.at(i)); |
| view->setSectionResizeMode(i, (QHeaderView::ResizeMode)modes.at(i)); |
| } |
| topLevel->show(); |
| QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| view->resize(size, size); |
| for (int j = 0; j < expected.count(); ++j) |
| QCOMPARE(view->sectionSize(j), expected.at(j)); |
| } |
| |
| void tst_QHeaderView::moveAndInsertSection_data() |
| { |
| QTest::addColumn<int>("from"); |
| QTest::addColumn<int>("to"); |
| QTest::addColumn<int>("insert"); |
| QTest::addColumn<QList<int> >("mapping"); |
| |
| QTest::newRow("move from 1 to 3, insert 0") |
| << 1 << 3 << 0 <<(QList<int>() << 0 << 1 << 3 << 4 << 2); |
| |
| } |
| |
| void tst_QHeaderView::moveAndInsertSection() |
| { |
| QFETCH(int, from); |
| QFETCH(int, to); |
| QFETCH(int, insert); |
| QFETCH(QList<int>, mapping); |
| |
| view->setStretchLastSection(false); |
| |
| view->moveSection(from, to); |
| |
| model->insertRow(insert); |
| |
| for (int i = 0; i < mapping.count(); ++i) |
| QCOMPARE(view->logicalIndex(i), mapping.at(i)); |
| } |
| |
| void tst_QHeaderView::resizeMode() |
| { |
| // resizeMode must not be called with an invalid index |
| int last = view->count() - 1; |
| view->setSectionResizeMode(QHeaderView::Interactive); |
| QCOMPARE(view->sectionResizeMode(last), QHeaderView::Interactive); |
| QCOMPARE(view->sectionResizeMode(1), QHeaderView::Interactive); |
| view->setSectionResizeMode(QHeaderView::Stretch); |
| QCOMPARE(view->sectionResizeMode(last), QHeaderView::Stretch); |
| QCOMPARE(view->sectionResizeMode(1), QHeaderView::Stretch); |
| view->setSectionResizeMode(QHeaderView::Custom); |
| QCOMPARE(view->sectionResizeMode(last), QHeaderView::Custom); |
| QCOMPARE(view->sectionResizeMode(1), QHeaderView::Custom); |
| |
| // test when sections have been moved |
| view->setStretchLastSection(false); |
| for (int i=0; i < (view->count() - 1); ++i) |
| view->setSectionResizeMode(i, QHeaderView::Interactive); |
| int logicalIndex = view->count() / 2; |
| view->setSectionResizeMode(logicalIndex, QHeaderView::Stretch); |
| view->moveSection(view->visualIndex(logicalIndex), 0); |
| for (int i=0; i < (view->count() - 1); ++i) { |
| if (i == logicalIndex) |
| QCOMPARE(view->sectionResizeMode(i), QHeaderView::Stretch); |
| else |
| QCOMPARE(view->sectionResizeMode(i), QHeaderView::Interactive); |
| } |
| } |
| |
| void tst_QHeaderView::resizeSection_data() |
| { |
| QTest::addColumn<int>("initial"); |
| QTest::addColumn<QList<int> >("logical"); |
| QTest::addColumn<QList<int> >("size"); |
| QTest::addColumn<QList<int> >("mode"); |
| QTest::addColumn<int>("resized"); |
| QTest::addColumn<QList<int> >("expected"); |
| |
| QTest::newRow("bad args") |
| << 100 |
| << (QList<int>() << -1 << -1 << 99999 << 99999 << 4) |
| << (QList<int>() << -1 << 0 << 99999 << -1 << -1) |
| << (QList<int>() |
| << int(QHeaderView::Interactive) |
| << int(QHeaderView::Interactive) |
| << int(QHeaderView::Interactive) |
| << int(QHeaderView::Interactive)) |
| << 0 |
| << (QList<int>() << 0 << 0 << 0 << 0 << 0); |
| } |
| |
| void tst_QHeaderView::resizeSection() |
| { |
| |
| QFETCH(int, initial); |
| QFETCH(QList<int>, logical); |
| QFETCH(QList<int>, size); |
| QFETCH(QList<int>, mode); |
| QFETCH(int, resized); |
| QFETCH(QList<int>, expected); |
| |
| view->resize(400, 400); |
| |
| topLevel->show(); |
| QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| view->setSectionsMovable(true); |
| view->setStretchLastSection(false); |
| |
| for (int i = 0; i < logical.count(); ++i) |
| if (logical.at(i) > -1 && logical.at(i) < view->count()) // for now |
| view->setSectionResizeMode(logical.at(i), (QHeaderView::ResizeMode)mode.at(i)); |
| |
| for (int j = 0; j < logical.count(); ++j) |
| view->resizeSection(logical.at(j), initial); |
| |
| QSignalSpy spy(view, SIGNAL(sectionResized(int,int,int))); |
| |
| for (int k = 0; k < logical.count(); ++k) |
| view->resizeSection(logical.at(k), size.at(k)); |
| |
| QCOMPARE(spy.count(), resized); |
| |
| for (int l = 0; l < logical.count(); ++l) |
| QCOMPARE(view->sectionSize(logical.at(l)), expected.at(l)); |
| } |
| |
| void tst_QHeaderView::highlightSections() |
| { |
| view->setHighlightSections(true); |
| QCOMPARE(view->highlightSections(), true); |
| view->setHighlightSections(false); |
| QCOMPARE(view->highlightSections(), false); |
| } |
| |
| void tst_QHeaderView::showSortIndicator() |
| { |
| view->setSortIndicatorShown(true); |
| QCOMPARE(view->isSortIndicatorShown(), true); |
| QCOMPARE(view->sortIndicatorOrder(), Qt::DescendingOrder); |
| view->setSortIndicator(1, Qt::AscendingOrder); |
| QCOMPARE(view->sortIndicatorOrder(), Qt::AscendingOrder); |
| view->setSortIndicator(1, Qt::DescendingOrder); |
| QCOMPARE(view->sortIndicatorOrder(), Qt::DescendingOrder); |
| view->setSortIndicatorShown(false); |
| QCOMPARE(view->isSortIndicatorShown(), false); |
| |
| view->setSortIndicator(999999, Qt::DescendingOrder); |
| // Don't segfault baby :) |
| view->setSortIndicatorShown(true); |
| |
| view->setSortIndicator(0, Qt::DescendingOrder); |
| // Don't assert baby :) |
| } |
| |
| void tst_QHeaderView::sortIndicatorTracking() |
| { |
| QtTestModel model; |
| model.rows = model.cols = 10; |
| |
| QHeaderView hv(Qt::Horizontal); |
| |
| hv.setModel(&model); |
| hv.show(); |
| hv.setSortIndicatorShown(true); |
| hv.setSortIndicator(1, Qt::DescendingOrder); |
| |
| model.removeOneColumn(8); |
| QCOMPARE(hv.sortIndicatorSection(), 1); |
| |
| model.removeOneColumn(2); |
| QCOMPARE(hv.sortIndicatorSection(), 1); |
| |
| model.insertOneColumn(2); |
| QCOMPARE(hv.sortIndicatorSection(), 1); |
| |
| model.insertOneColumn(1); |
| QCOMPARE(hv.sortIndicatorSection(), 2); |
| |
| model.removeOneColumn(0); |
| QCOMPARE(hv.sortIndicatorSection(), 1); |
| |
| model.removeOneColumn(1); |
| QCOMPARE(hv.sortIndicatorSection(), -1); |
| } |
| |
| void tst_QHeaderView::removeAndInsertRow() |
| { |
| // Check if logicalIndex returns the correct value after we have removed a row |
| // we might as well te |
| for (int i = 0; i < model->rowCount(); ++i) { |
| QCOMPARE(i, view->logicalIndex(i)); |
| } |
| |
| while (model->removeRow(0)) { |
| for (int i = 0; i < model->rowCount(); ++i) { |
| QCOMPARE(i, view->logicalIndex(i)); |
| } |
| } |
| |
| int pass = 0; |
| for (pass = 0; pass < 5; pass++) { |
| for (int i = 0; i < model->rowCount(); ++i) { |
| QCOMPARE(i, view->logicalIndex(i)); |
| } |
| model->insertRow(0); |
| } |
| |
| while (model->removeRows(0, 2)) { |
| for (int i = 0; i < model->rowCount(); ++i) { |
| QCOMPARE(i, view->logicalIndex(i)); |
| } |
| } |
| |
| for (pass = 0; pass < 3; pass++) { |
| model->insertRows(0, 2); |
| for (int i = 0; i < model->rowCount(); ++i) { |
| QCOMPARE(i, view->logicalIndex(i)); |
| } |
| } |
| |
| for (pass = 0; pass < 3; pass++) { |
| model->insertRows(3, 2); |
| for (int i = 0; i < model->rowCount(); ++i) { |
| QCOMPARE(i, view->logicalIndex(i)); |
| } |
| } |
| |
| // Insert at end |
| for (pass = 0; pass < 3; pass++) { |
| int rowCount = model->rowCount(); |
| model->insertRows(rowCount, 1); |
| for (int i = 0; i < rowCount; ++i) { |
| QCOMPARE(i, view->logicalIndex(i)); |
| } |
| } |
| |
| } |
| void tst_QHeaderView::unhideSection() |
| { |
| // 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. |
| QCOMPARE(view->sectionsHidden(), false); |
| view->setSectionHidden(0, true); |
| QCOMPARE(view->sectionsHidden(), true); |
| QCOMPARE(view->sectionSize(0), 0); |
| view->setSectionResizeMode(QHeaderView::Interactive); |
| view->setSectionHidden(0, false); |
| QVERIFY(view->sectionSize(0) > 0); |
| |
| view->setSectionHidden(0, true); |
| QCOMPARE(view->sectionSize(0), 0); |
| view->setSectionHidden(0, true); |
| QCOMPARE(view->sectionSize(0), 0); |
| view->setSectionResizeMode(QHeaderView::Stretch); |
| view->setSectionHidden(0, false); |
| QVERIFY(view->sectionSize(0) > 0); |
| |
| } |
| |
| void tst_QHeaderView::testEvent() |
| { |
| protected_QHeaderView x(Qt::Vertical); |
| x.testEvent(); |
| protected_QHeaderView y(Qt::Horizontal); |
| y.testEvent(); |
| } |
| |
| |
| void protected_QHeaderView::testEvent() |
| { |
| // No crashy please |
| QHoverEvent enterEvent(QEvent::HoverEnter, QPoint(), QPoint()); |
| event(&enterEvent); |
| QHoverEvent eventLeave(QEvent::HoverLeave, QPoint(), QPoint()); |
| event(&eventLeave); |
| QHoverEvent eventMove(QEvent::HoverMove, QPoint(), QPoint()); |
| event(&eventMove); |
| } |
| |
| void tst_QHeaderView::headerDataChanged() |
| { |
| // This shouldn't asserver because view is Vertical |
| view->headerDataChanged(Qt::Horizontal, -1, -1); |
| #if 0 |
| // This will assert |
| view->headerDataChanged(Qt::Vertical, -1, -1); |
| #endif |
| |
| // No crashing please |
| view->headerDataChanged(Qt::Horizontal, 0, 1); |
| view->headerDataChanged(Qt::Vertical, 0, 1); |
| } |
| |
| void tst_QHeaderView::currentChanged() |
| { |
| view->setCurrentIndex(QModelIndex()); |
| } |
| |
| void tst_QHeaderView::horizontalOffset() |
| { |
| protected_QHeaderView x(Qt::Vertical); |
| x.testhorizontalOffset(); |
| protected_QHeaderView y(Qt::Horizontal); |
| y.testhorizontalOffset(); |
| } |
| |
| void tst_QHeaderView::verticalOffset() |
| { |
| protected_QHeaderView x(Qt::Vertical); |
| x.testverticalOffset(); |
| protected_QHeaderView y(Qt::Horizontal); |
| y.testverticalOffset(); |
| } |
| |
| void protected_QHeaderView::testhorizontalOffset() |
| { |
| if(orientation() == Qt::Horizontal){ |
| QCOMPARE(horizontalOffset(), 0); |
| setOffset(10); |
| QCOMPARE(horizontalOffset(), 10); |
| } |
| else |
| QCOMPARE(horizontalOffset(), 0); |
| |
| } |
| |
| void protected_QHeaderView::testverticalOffset() |
| { |
| if(orientation() == Qt::Vertical){ |
| QCOMPARE(verticalOffset(), 0); |
| setOffset(10); |
| QCOMPARE(verticalOffset(), 10); |
| } |
| else |
| QCOMPARE(verticalOffset(), 0); |
| } |
| |
| void tst_QHeaderView::stretchSectionCount() |
| { |
| view->setStretchLastSection(false); |
| QCOMPARE(view->stretchSectionCount(), 0); |
| view->setStretchLastSection(true); |
| QCOMPARE(view->stretchSectionCount(), 0); |
| |
| view->setSectionResizeMode(0, QHeaderView::Stretch); |
| QCOMPARE(view->stretchSectionCount(), 1); |
| } |
| |
| void tst_QHeaderView::hiddenSectionCount() |
| { |
| model->clear(); |
| model->insertRows(0, 10); |
| // Hide every other one |
| for (int i=0; i<10; i++) |
| view->setSectionHidden(i, (i & 1) == 0); |
| |
| QCOMPARE(view->hiddenSectionCount(), 5); |
| |
| view->setSectionResizeMode(QHeaderView::Stretch); |
| QCOMPARE(view->hiddenSectionCount(), 5); |
| |
| // Remove some rows and make sure they are now still counted |
| model->removeRow(9); |
| model->removeRow(8); |
| model->removeRow(7); |
| model->removeRow(6); |
| QCOMPARE(view->count(), 6); |
| QCOMPARE(view->hiddenSectionCount(), 3); |
| model->removeRows(0,5); |
| QCOMPARE(view->count(), 1); |
| QCOMPARE(view->hiddenSectionCount(), 0); |
| QVERIFY(view->count() >= view->hiddenSectionCount()); |
| } |
| |
| void tst_QHeaderView::focusPolicy() |
| { |
| QHeaderView view(Qt::Horizontal); |
| QCOMPARE(view.focusPolicy(), Qt::NoFocus); |
| |
| QTreeWidget widget; |
| QCOMPARE(widget.header()->focusPolicy(), Qt::NoFocus); |
| QVERIFY(!widget.focusProxy()); |
| QVERIFY(!widget.hasFocus()); |
| QVERIFY(!widget.header()->focusProxy()); |
| QVERIFY(!widget.header()->hasFocus()); |
| |
| widget.show(); |
| widget.setFocus(Qt::OtherFocusReason); |
| QApplication::setActiveWindow(&widget); |
| widget.activateWindow(); |
| QVERIFY(QTest::qWaitForWindowActive(&widget)); |
| QVERIFY(widget.hasFocus()); |
| QVERIFY(!widget.header()->hasFocus()); |
| |
| widget.setFocusPolicy(Qt::NoFocus); |
| widget.clearFocus(); |
| QTRY_VERIFY(!widget.hasFocus()); |
| QVERIFY(!widget.header()->hasFocus()); |
| |
| QTest::keyPress(&widget, Qt::Key_Tab); |
| |
| qApp->processEvents(); |
| qApp->processEvents(); |
| |
| QVERIFY(!widget.hasFocus()); |
| QVERIFY(!widget.header()->hasFocus()); |
| } |
| |
| class SimpleModel : public QAbstractItemModel |
| { |
| Q_OBJECT |
| public: |
| |
| SimpleModel( QObject* parent=0) |
| : QAbstractItemModel(parent), |
| m_col_count(3) {} |
| |
| QModelIndex parent(const QModelIndex &/*child*/) const |
| { |
| return QModelIndex(); |
| } |
| QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const |
| { |
| return hasIndex(row, column, parent) ? createIndex(row, column) : QModelIndex(); |
| } |
| int rowCount(const QModelIndex & /*parent*/ = QModelIndex()) const |
| { |
| return 8; |
| } |
| int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const |
| { |
| return m_col_count; |
| } |
| |
| QVariant data(const QModelIndex &index, int role) const |
| { |
| if (!index.isValid()) |
| { |
| return QVariant(); |
| } |
| if (role == Qt::DisplayRole) { |
| return QString::number(index.row()) + QLatin1Char(',') + QString::number(index.column()); |
| } |
| return QVariant(); |
| } |
| |
| void setColumnCount( int c ) |
| { |
| m_col_count = c; |
| } |
| |
| private: |
| int m_col_count; |
| }; |
| |
| void tst_QHeaderView::moveSectionAndReset() |
| { |
| SimpleModel m; |
| QHeaderView v(Qt::Horizontal); |
| v.setModel(&m); |
| int cc = 2; |
| for (cc = 2; cc < 4; ++cc) { |
| m.setColumnCount(cc); |
| int movefrom = 0; |
| int moveto; |
| for (moveto = 1; moveto < cc; ++moveto) { |
| v.moveSection(movefrom, moveto); |
| m.setColumnCount(cc - 1); |
| v.reset(); |
| for (int i = 0; i < cc - 1; ++i) { |
| QCOMPARE(v.logicalIndex(v.visualIndex(i)), i); |
| } |
| } |
| } |
| } |
| |
| void tst_QHeaderView::moveSectionAndRemove() |
| { |
| QStandardItemModel m; |
| QHeaderView v(Qt::Horizontal); |
| |
| v.setModel(&m); |
| v.model()->insertColumns(0, 3); |
| v.moveSection(0, 1); |
| |
| QCOMPARE(v.count(), 3); |
| v.model()->removeColumns(0, v.model()->columnCount()); |
| QCOMPARE(v.count(), 0); |
| } |
| |
| static QByteArray savedState() |
| { |
| QStandardItemModel m(4, 4); |
| QHeaderView h1(Qt::Horizontal); |
| h1.setModel(&m); |
| h1.setMinimumSectionSize(0); // system default min size can be to large |
| h1.swapSections(0, 2); |
| h1.resizeSection(1, 10); |
| h1.setSortIndicatorShown(true); |
| h1.setSortIndicator(2, Qt::DescendingOrder); |
| h1.setSectionHidden(3, true); |
| return h1.saveState(); |
| } |
| |
| void tst_QHeaderView::saveRestore() |
| { |
| QStandardItemModel m(4, 4); |
| const QByteArray s1 = savedState(); |
| |
| QHeaderView h2(Qt::Vertical); |
| QSignalSpy spy(&h2, SIGNAL(sortIndicatorChanged(int,Qt::SortOrder))); |
| |
| h2.setModel(&m); |
| QVERIFY(h2.restoreState(s1)); |
| |
| QCOMPARE(spy.count(), 1); |
| QCOMPARE(spy.at(0).at(0).toInt(), 2); |
| |
| QCOMPARE(h2.logicalIndex(0), 2); |
| QCOMPARE(h2.logicalIndex(2), 0); |
| QCOMPARE(h2.sectionSize(1), 10); |
| QCOMPARE(h2.sortIndicatorSection(), 2); |
| QCOMPARE(h2.sortIndicatorOrder(), Qt::DescendingOrder); |
| QCOMPARE(h2.isSortIndicatorShown(), true); |
| QVERIFY(!h2.isSectionHidden(2)); |
| QVERIFY(h2.isSectionHidden(3)); |
| QCOMPARE(h2.hiddenSectionCount(), 1); |
| |
| QByteArray s2 = h2.saveState(); |
| QCOMPARE(s1, s2); |
| |
| QVERIFY(!h2.restoreState(QByteArrayLiteral("Garbage"))); |
| } |
| |
| void tst_QHeaderView::restoreQt4State() |
| { |
| // QTBUG-40462 |
| // Setting from Qt4, where information about multiple sections were grouped together in one |
| // sectionItem object |
| QStandardItemModel m(4, 10); |
| QHeaderView h2(Qt::Vertical); |
| QByteArray settings_qt4 = |
| QByteArray::fromHex("000000ff00000000000000010000000100000000010000000000000000000000000000" |
| "0000000003e80000000a0101000100000000000000000000000064ffffffff00000081" |
| "0000000000000001000003e80000000a00000000"); |
| QVERIFY(h2.restoreState(settings_qt4)); |
| int sectionItemsLengthTotal = 0; |
| for (int i = 0; i < h2.count(); ++i) |
| sectionItemsLengthTotal += h2.sectionSize(i); |
| QCOMPARE(sectionItemsLengthTotal, h2.length()); |
| |
| // Buggy setting where sum(sectionItems) != length. Check false is returned and this corrupted |
| // state isn't restored |
| QByteArray settings_buggy_length = |
| QByteArray::fromHex("000000ff000000000000000100000000000000050100000000000000000000000a4000" |
| "000000010000000600000258000000fb0000000a010100010000000000000000000000" |
| "0064ffffffff00000081000000000000000a000000d30000000100000000000000c800" |
| "000001000000000000008000000001000000000000005c00000001000000000000003c" |
| "0000000100000000000002580000000100000000000000000000000100000000000002" |
| "580000000100000000000002580000000100000000000003c000000001000000000000" |
| "03e8"); |
| int old_length = h2.length(); |
| QByteArray old_state = h2.saveState(); |
| // Check setting is correctly recognized as corrupted |
| QVERIFY(!h2.restoreState(settings_buggy_length)); |
| // Check nothing has been actually restored |
| QCOMPARE(h2.length(), old_length); |
| QCOMPARE(h2.saveState(), old_state); |
| } |
| |
| void tst_QHeaderView::restoreToMoreColumns() |
| { |
| // Restore state onto a model with more columns |
| const QByteArray s1 = savedState(); |
| QHeaderView h4(Qt::Horizontal); |
| QStandardItemModel fiveColumnsModel(1, 5); |
| h4.setModel(&fiveColumnsModel); |
| QCOMPARE(fiveColumnsModel.columnCount(), 5); |
| QCOMPARE(h4.count(), 5); |
| QVERIFY(h4.restoreState(s1)); |
| QCOMPARE(fiveColumnsModel.columnCount(), 5); |
| QCOMPARE(h4.count(), 5); |
| QCOMPARE(h4.sectionSize(1), 10); |
| for (int i = 0; i < h4.count(); ++i) |
| QVERIFY(h4.sectionSize(i) > 0 || h4.isSectionHidden(i)); |
| QVERIFY(!h4.isSectionHidden(2)); |
| QVERIFY(h4.isSectionHidden(3)); |
| QCOMPARE(h4.hiddenSectionCount(), 1); |
| QCOMPARE(h4.sortIndicatorSection(), 2); |
| QCOMPARE(h4.sortIndicatorOrder(), Qt::DescendingOrder); |
| QCOMPARE(h4.logicalIndex(0), 2); |
| QCOMPARE(h4.logicalIndex(1), 1); |
| QCOMPARE(h4.logicalIndex(2), 0); |
| QCOMPARE(h4.visualIndex(0), 2); |
| QCOMPARE(h4.visualIndex(1), 1); |
| QCOMPARE(h4.visualIndex(2), 0); |
| |
| // Repainting shouldn't crash |
| h4.show(); |
| QVERIFY(QTest::qWaitForWindowExposed(&h4)); |
| } |
| |
| void tst_QHeaderView::restoreToMoreColumnsNoMovedColumns() |
| { |
| // Given a model with 2 columns, for saving state |
| QHeaderView h1(Qt::Horizontal); |
| QStandardItemModel model1(1, 2); |
| h1.setModel(&model1); |
| QCOMPARE(h1.visualIndex(0), 0); |
| QCOMPARE(h1.visualIndex(1), 1); |
| QCOMPARE(h1.logicalIndex(0), 0); |
| QCOMPARE(h1.logicalIndex(1), 1); |
| const QByteArray savedState = h1.saveState(); |
| |
| // And a model with 3 columns, to apply that state upon |
| QHeaderView h2(Qt::Horizontal); |
| QStandardItemModel model2(1, 3); |
| h2.setModel(&model2); |
| QCOMPARE(h2.visualIndex(0), 0); |
| QCOMPARE(h2.visualIndex(1), 1); |
| QCOMPARE(h2.visualIndex(2), 2); |
| QCOMPARE(h2.logicalIndex(0), 0); |
| QCOMPARE(h2.logicalIndex(1), 1); |
| QCOMPARE(h2.logicalIndex(2), 2); |
| |
| // When calling restoreState() |
| QVERIFY(h2.restoreState(savedState)); |
| |
| // Then the index mapping should still be as default |
| QCOMPARE(h2.visualIndex(0), 0); |
| QCOMPARE(h2.visualIndex(1), 1); |
| QCOMPARE(h2.visualIndex(2), 2); |
| QCOMPARE(h2.logicalIndex(0), 0); |
| QCOMPARE(h2.logicalIndex(1), 1); |
| QCOMPARE(h2.logicalIndex(2), 2); |
| |
| // And repainting shouldn't crash |
| h2.show(); |
| QVERIFY(QTest::qWaitForWindowExposed(&h2)); |
| } |
| |
| void tst_QHeaderView::restoreBeforeSetModel() |
| { |
| QHeaderView h2(Qt::Horizontal); |
| const QByteArray s1 = savedState(); |
| // First restore |
| QVERIFY(h2.restoreState(s1)); |
| // Then setModel |
| QStandardItemModel model(4, 4); |
| h2.setModel(&model); |
| |
| // Check the result |
| QCOMPARE(h2.logicalIndex(0), 2); |
| QCOMPARE(h2.logicalIndex(2), 0); |
| QCOMPARE(h2.sectionSize(1), 10); |
| QCOMPARE(h2.sortIndicatorSection(), 2); |
| QCOMPARE(h2.sortIndicatorOrder(), Qt::DescendingOrder); |
| QCOMPARE(h2.isSortIndicatorShown(), true); |
| QVERIFY(!h2.isSectionHidden(2)); |
| QVERIFY(h2.isSectionHidden(3)); |
| QCOMPARE(h2.hiddenSectionCount(), 1); |
| } |
| |
| void tst_QHeaderView::defaultSectionSizeTest() |
| { |
| #if defined Q_OS_WINRT |
| QSKIP("Fails on WinRT - QTBUG-73309"); |
| #endif |
| |
| // Setup |
| QTableView qtv; |
| QHeaderView *hv = qtv.verticalHeader(); |
| hv->setMinimumSectionSize(10); |
| hv->setDefaultSectionSize(99); // Set it to a value different from defaultSize. |
| QStandardItemModel amodel(4, 4); |
| qtv.setModel(&amodel); |
| QCOMPARE(hv->sectionSize(0), 99); |
| QCOMPARE(hv->visualIndexAt(50), 0); // <= also make sure that indexes are calculated |
| hv->setDefaultSectionSize(40); // Set it to a value different from defaultSize. |
| QCOMPARE(hv->visualIndexAt(50), 1); |
| |
| const int defaultSize = 26; |
| hv->setDefaultSectionSize(defaultSize + 1); // Set it to a value different from defaultSize. |
| |
| // no hidden Sections |
| hv->resizeSection(1, 0); |
| hv->setDefaultSectionSize(defaultSize); |
| QCOMPARE(hv->sectionSize(1), defaultSize); |
| |
| // with hidden sections |
| hv->resizeSection(1, 0); |
| hv->hideSection(2); |
| hv->setDefaultSectionSize(defaultSize); |
| |
| QVERIFY(hv->sectionSize(0) == defaultSize); // trivial case. |
| QVERIFY(hv->sectionSize(1) == defaultSize); // just sized 0. Now it should be 10 |
| QVERIFY(hv->sectionSize(2) == 0); // section is hidden. It should not be resized. |
| } |
| |
| class TestHeaderViewStyle : public QProxyStyle |
| { |
| public: |
| TestHeaderViewStyle() : horizontalSectionSize(100) {} |
| int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const override |
| { |
| if (metric == QStyle::PM_HeaderDefaultSectionSizeHorizontal) |
| return horizontalSectionSize; |
| else |
| return QProxyStyle::pixelMetric(metric, option, widget); |
| } |
| int horizontalSectionSize; |
| }; |
| |
| void tst_QHeaderView::defaultSectionSizeTestStyles() |
| { |
| TestHeaderViewStyle style1; |
| TestHeaderViewStyle style2; |
| style1.horizontalSectionSize = 100; |
| style2.horizontalSectionSize = 200; |
| |
| QHeaderView hv(Qt::Horizontal); |
| hv.setStyle(&style1); |
| QCOMPARE(hv.defaultSectionSize(), style1.horizontalSectionSize); |
| hv.setStyle(&style2); |
| QCOMPARE(hv.defaultSectionSize(), style2.horizontalSectionSize); |
| hv.setDefaultSectionSize(70); |
| QCOMPARE(hv.defaultSectionSize(), 70); |
| hv.setStyle(&style1); |
| QCOMPARE(hv.defaultSectionSize(), 70); |
| hv.resetDefaultSectionSize(); |
| QCOMPARE(hv.defaultSectionSize(), style1.horizontalSectionSize); |
| hv.setStyle(&style2); |
| QCOMPARE(hv.defaultSectionSize(), style2.horizontalSectionSize); |
| } |
| |
| void tst_QHeaderView::defaultAlignment_data() |
| { |
| QTest::addColumn<int>("direction"); |
| QTest::addColumn<int>("initial"); |
| QTest::addColumn<int>("alignment"); |
| |
| QTest::newRow("horizontal right aligned") |
| << int(Qt::Horizontal) |
| << int(Qt::AlignCenter) |
| << int(Qt::AlignRight); |
| |
| QTest::newRow("horizontal left aligned") |
| << int(Qt::Horizontal) |
| << int(Qt::AlignCenter) |
| << int(Qt::AlignLeft); |
| |
| QTest::newRow("vertical right aligned") |
| << int(Qt::Vertical) |
| << int(Qt::AlignLeft|Qt::AlignVCenter) |
| << int(Qt::AlignRight); |
| |
| QTest::newRow("vertical left aligned") |
| << int(Qt::Vertical) |
| << int(Qt::AlignLeft|Qt::AlignVCenter) |
| << int(Qt::AlignLeft); |
| } |
| |
| void tst_QHeaderView::defaultAlignment() |
| { |
| QFETCH(int, direction); |
| QFETCH(int, initial); |
| QFETCH(int, alignment); |
| |
| SimpleModel m; |
| |
| QHeaderView header((Qt::Orientation)direction); |
| header.setModel(&m); |
| |
| QCOMPARE(header.defaultAlignment(), (Qt::Alignment)initial); |
| header.setDefaultAlignment((Qt::Alignment)alignment); |
| QCOMPARE(header.defaultAlignment(), (Qt::Alignment)alignment); |
| } |
| |
| void tst_QHeaderView::globalResizeMode_data() |
| { |
| QTest::addColumn<int>("direction"); |
| QTest::addColumn<int>("mode"); |
| QTest::addColumn<int>("insert"); |
| |
| QTest::newRow("horizontal ResizeToContents 0") |
| << int(Qt::Horizontal) |
| << int(QHeaderView::ResizeToContents) |
| << 0; |
| } |
| |
| void tst_QHeaderView::globalResizeMode() |
| { |
| QFETCH(int, direction); |
| QFETCH(int, mode); |
| QFETCH(int, insert); |
| |
| QStandardItemModel m(4, 4); |
| QHeaderView h((Qt::Orientation)direction); |
| h.setModel(&m); |
| |
| h.setSectionResizeMode((QHeaderView::ResizeMode)mode); |
| m.insertRow(insert); |
| for (int i = 0; i < h.count(); ++i) |
| QCOMPARE(h.sectionResizeMode(i), (QHeaderView::ResizeMode)mode); |
| } |
| |
| |
| void tst_QHeaderView::sectionPressedSignal_data() |
| { |
| QTest::addColumn<int>("direction"); |
| QTest::addColumn<bool>("clickable"); |
| QTest::addColumn<int>("count"); |
| |
| QTest::newRow("horizontal unclickable 0") |
| << int(Qt::Horizontal) |
| << false |
| << 0; |
| |
| QTest::newRow("horizontal clickable 1") |
| << int(Qt::Horizontal) |
| << true |
| << 1; |
| } |
| |
| void tst_QHeaderView::sectionPressedSignal() |
| { |
| QFETCH(int, direction); |
| QFETCH(bool, clickable); |
| QFETCH(int, count); |
| |
| QStandardItemModel m(4, 4); |
| QHeaderView h((Qt::Orientation)direction); |
| |
| h.setModel(&m); |
| h.show(); |
| h.setSectionsClickable(clickable); |
| |
| QSignalSpy spy(&h, SIGNAL(sectionPressed(int))); |
| |
| QCOMPARE(spy.count(), 0); |
| QTest::mousePress(h.viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(5, 5)); |
| QCOMPARE(spy.count(), count); |
| } |
| |
| void tst_QHeaderView::sectionClickedSignal() |
| { |
| QFETCH(int, direction); |
| QFETCH(bool, clickable); |
| QFETCH(int, count); |
| |
| QStandardItemModel m(4, 4); |
| QHeaderView h((Qt::Orientation)direction); |
| |
| h.setModel(&m); |
| h.show(); |
| h.setSectionsClickable(clickable); |
| h.setSortIndicatorShown(true); |
| |
| QSignalSpy spy(&h, SIGNAL(sectionClicked(int))); |
| QSignalSpy spy2(&h, SIGNAL(sortIndicatorChanged(int,Qt::SortOrder))); |
| |
| QCOMPARE(spy.count(), 0); |
| QCOMPARE(spy2.count(), 0); |
| QTest::mouseClick(h.viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(5, 5)); |
| QCOMPARE(spy.count(), count); |
| QCOMPARE(spy2.count(), count); |
| |
| //now let's try with the sort indicator hidden (the result should be the same |
| spy.clear(); |
| spy2.clear(); |
| h.setSortIndicatorShown(false); |
| QTest::mouseClick(h.viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(5, 5)); |
| QCOMPARE(spy.count(), count); |
| QCOMPARE(spy2.count(), count); |
| } |
| |
| void tst_QHeaderView::defaultSectionSize_data() |
| { |
| QTest::addColumn<int>("direction"); |
| QTest::addColumn<int>("oldDefaultSize"); |
| QTest::addColumn<int>("newDefaultSize"); |
| |
| //QTest::newRow("horizontal,-5") << int(Qt::Horizontal) << 100 << -5; |
| QTest::newRow("horizontal, 0") << int(Qt::Horizontal) << 100 << 0; |
| QTest::newRow("horizontal, 5") << int(Qt::Horizontal) << 100 << 5; |
| QTest::newRow("horizontal,25") << int(Qt::Horizontal) << 100 << 5; |
| } |
| |
| void tst_QHeaderView::defaultSectionSize() |
| { |
| QFETCH(int, direction); |
| QFETCH(int, oldDefaultSize); |
| QFETCH(int, newDefaultSize); |
| |
| QStandardItemModel m(4, 4); |
| QHeaderView h((Qt::Orientation)direction); |
| |
| h.setModel(&m); |
| h.setMinimumSectionSize(0); |
| |
| QCOMPARE(h.defaultSectionSize(), oldDefaultSize); |
| h.setDefaultSectionSize(newDefaultSize); |
| QCOMPARE(h.defaultSectionSize(), newDefaultSize); |
| h.reset(); |
| for (int i = 0; i < h.count(); ++i) |
| QCOMPARE(h.sectionSize(i), newDefaultSize); |
| } |
| |
| void tst_QHeaderView::hideAndInsert_data() |
| { |
| QTest::addColumn<int>("direction"); |
| QTest::addColumn<int>("hide"); |
| QTest::addColumn<int>("insert"); |
| QTest::addColumn<int>("hidden"); |
| |
| QTest::newRow("horizontal, 0, 0") << int(Qt::Horizontal) << 0 << 0 << 1; |
| } |
| |
| void tst_QHeaderView::hideAndInsert() |
| { |
| QFETCH(int, direction); |
| QFETCH(int, hide); |
| QFETCH(int, insert); |
| QFETCH(int, hidden); |
| |
| QStandardItemModel m(4, 4); |
| QHeaderView h((Qt::Orientation)direction); |
| |
| h.setModel(&m); |
| |
| h.setSectionHidden(hide, true); |
| |
| if (direction == Qt::Vertical) |
| m.insertRow(insert); |
| else |
| m.insertColumn(insert); |
| |
| for (int i = 0; i < h.count(); ++i) |
| if (i != hidden) |
| QCOMPARE(h.isSectionHidden(i), false); |
| else |
| QCOMPARE(h.isSectionHidden(i), true); |
| } |
| |
| void tst_QHeaderView::removeSection() |
| { |
| //test that removing a hidden section gives the expected result: the next row should be hidden |
| //(see task |
| const int hidden = 3; //section that will be hidden |
| const QStringList list = QStringList() << "0" << "1" << "2" << "3" << "4" << "5" << "6"; |
| |
| QStringListModel model( list ); |
| QHeaderView view(Qt::Vertical); |
| view.setModel(&model); |
| view.hideSection(hidden); |
| view.hideSection(1); |
| model.removeRow(1); |
| view.show(); |
| |
| for(int i = 0; i < view.count(); i++) { |
| if (i == (hidden-1)) { //-1 because we removed a row in the meantime |
| QCOMPARE(view.sectionSize(i), 0); |
| QVERIFY(view.isSectionHidden(i)); |
| } else { |
| QCOMPARE(view.sectionSize(i), view.defaultSectionSize() ); |
| QVERIFY(!view.isSectionHidden(i)); |
| } |
| } |
| } |
| |
| void tst_QHeaderView::preserveHiddenSectionWidth() |
| { |
| const QStringList list = QStringList() << "0" << "1" << "2" << "3"; |
| |
| QStringListModel model( list ); |
| QHeaderView view(Qt::Vertical); |
| view.setModel(&model); |
| view.resizeSection(0, 100); |
| view.resizeSection(1, 10); |
| view.resizeSection(2, 50); |
| view.setSectionResizeMode(3, QHeaderView::Stretch); |
| view.show(); |
| |
| view.hideSection(2); |
| model.removeRow(1); |
| view.showSection(1); |
| QCOMPARE(view.sectionSize(0), 100); |
| QCOMPARE(view.sectionSize(1), 50); |
| |
| view.hideSection(1); |
| model.insertRow(1); |
| view.showSection(2); |
| QCOMPARE(view.sectionSize(0), 100); |
| QCOMPARE(view.sectionSize(1), view.defaultSectionSize()); |
| QCOMPARE(view.sectionSize(2), 50); |
| } |
| |
| void tst_QHeaderView::invisibleStretchLastSection() |
| { |
| #ifdef Q_OS_WINRT |
| QSKIP("Fails on WinRT - QTBUG-68297"); |
| #endif |
| int count = 6; |
| QStandardItemModel model(1, count); |
| QHeaderView view(Qt::Horizontal); |
| view.setModel(&model); |
| int height = view.height(); |
| |
| view.resize(view.defaultSectionSize() * (count / 2), height); // don't show all sections |
| view.show(); |
| view.setStretchLastSection(true); |
| // stretch section is not visible; it should not be stretched |
| for (int i = 0; i < count; ++i) |
| QCOMPARE(view.sectionSize(i), view.defaultSectionSize()); |
| |
| view.resize(view.defaultSectionSize() * (count + 1), height); // give room to stretch |
| |
| // stretch section is visible; it should be stretched |
| for (int i = 0; i < count - 1; ++i) |
| QCOMPARE(view.sectionSize(i), view.defaultSectionSize()); |
| QCOMPARE(view.sectionSize(count - 1), view.defaultSectionSize() * 2); |
| } |
| |
| void tst_QHeaderView::noSectionsWithNegativeSize() |
| { |
| QStandardItemModel m(4, 4); |
| QHeaderView h(Qt::Horizontal); |
| h.setModel(&m); |
| h.resizeSection(1, -5); |
| QVERIFY(h.sectionSize(1) >= 0); // Sections with negative sizes not well defined. |
| } |
| |
| void tst_QHeaderView::emptySectionSpan() |
| { |
| QHeaderViewPrivate::SectionItem section; |
| QCOMPARE(section.sectionSize(), 0); |
| } |
| |
| void tst_QHeaderView::task236450_hidden_data() |
| { |
| QTest::addColumn<QList<int> >("hide1"); |
| QTest::addColumn<QList<int> >("hide2"); |
| |
| QTest::newRow("set 1") << (QList<int>() << 1 << 3) |
| << (QList<int>() << 1 << 5); |
| |
| QTest::newRow("set 2") << (QList<int>() << 2 << 3) |
| << (QList<int>() << 1 << 5); |
| |
| QTest::newRow("set 3") << (QList<int>() << 0 << 2 << 4) |
| << (QList<int>() << 2 << 3 << 5); |
| |
| } |
| |
| void tst_QHeaderView::task236450_hidden() |
| { |
| QFETCH(QList<int>, hide1); |
| QFETCH(QList<int>, hide2); |
| const QStringList list = QStringList() << "0" << "1" << "2" << "3" << "4" << "5"; |
| |
| QStringListModel model( list ); |
| protected_QHeaderView view(Qt::Vertical); |
| view.setModel(&model); |
| view.show(); |
| |
| foreach (int i, hide1) |
| view.hideSection(i); |
| |
| QCOMPARE(view.hiddenSectionCount(), hide1.count()); |
| for (int i = 0; i < 6; i++) { |
| QCOMPARE(!view.isSectionHidden(i), !hide1.contains(i)); |
| } |
| |
| view.setDefaultSectionSize(2); |
| view.scheduleDelayedItemsLayout(); |
| view.executeDelayedItemsLayout(); //force to do a relayout |
| |
| QCOMPARE(view.hiddenSectionCount(), hide1.count()); |
| for (int i = 0; i < 6; i++) { |
| QCOMPARE(!view.isSectionHidden(i), !hide1.contains(i)); |
| view.setSectionHidden(i, hide2.contains(i)); |
| } |
| |
| QCOMPARE(view.hiddenSectionCount(), hide2.count()); |
| for (int i = 0; i < 6; i++) { |
| QCOMPARE(!view.isSectionHidden(i), !hide2.contains(i)); |
| } |
| |
| } |
| |
| void tst_QHeaderView::task248050_hideRow() |
| { |
| //this is the sequence of events that make the task fail |
| protected_QHeaderView header(Qt::Vertical); |
| QStandardItemModel model(0, 1); |
| header.setMinimumSectionSize(0); // system default min size can be to large |
| header.setStretchLastSection(false); |
| header.setDefaultSectionSize(17); |
| header.setModel(&model); |
| header.doItemsLayout(); |
| |
| model.setRowCount(3); |
| |
| QCOMPARE(header.sectionPosition(2), 17*2); |
| |
| header.hideSection(1); |
| QCOMPARE(header.sectionPosition(2), 17); |
| |
| QTest::qWait(100); |
| //the size of the section shouldn't have changed |
| QCOMPARE(header.sectionPosition(2), 17); |
| } |
| |
| |
| //returns 0 if everything is fine. |
| static int checkHeaderViewOrder(QHeaderView *view, const QVector<int> &expected) |
| { |
| if (view->count() != expected.count()) |
| return 1; |
| |
| for (int i = 0; i < expected.count(); i++) { |
| if (view->logicalIndex(i) != expected.at(i)) |
| return i + 10; |
| if (view->visualIndex(expected.at(i)) != i) |
| return i + 100; |
| } |
| return 0; |
| } |
| |
| |
| void tst_QHeaderView::QTBUG6058_reset() |
| { |
| QStringListModel model1( QStringList() << "0" << "1" << "2" << "3" << "4" << "5" ); |
| QStringListModel model2( QStringList() << "a" << "b" << "c" ); |
| QSortFilterProxyModel proxy; |
| |
| QHeaderView view(Qt::Vertical); |
| view.setModel(&proxy); |
| view.show(); |
| QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| QVERIFY(QTest::qWaitForWindowActive(&view)); |
| |
| proxy.setSourceModel(&model1); |
| view.swapSections(0,2); |
| view.swapSections(1,4); |
| QVector<int> expectedOrder{2, 4, 0, 3, 1, 5}; |
| QTRY_COMPARE(checkHeaderViewOrder(&view, expectedOrder) , 0); |
| |
| proxy.setSourceModel(&model2); |
| expectedOrder = {2, 0, 1}; |
| QTRY_COMPARE(checkHeaderViewOrder(&view, expectedOrder) , 0); |
| |
| proxy.setSourceModel(&model1); |
| expectedOrder = {2, 0, 1, 3, 4, 5}; |
| QTRY_COMPARE(checkHeaderViewOrder(&view, expectedOrder) , 0); |
| } |
| |
| void tst_QHeaderView::QTBUG7833_sectionClicked() |
| { |
| QTableView tv; |
| QStandardItemModel *sim = new QStandardItemModel(&tv); |
| QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(&tv); |
| proxyModel->setSourceModel(sim); |
| proxyModel->setDynamicSortFilter(true); |
| proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); |
| |
| QList<QStandardItem *> row; |
| for (int i = 0; i < 12; i++) |
| row.append(new QStandardItem(QString(QLatin1Char('A' + i)))); |
| sim->appendRow(row); |
| row.clear(); |
| for (int i = 12; i > 0; i--) |
| row.append(new QStandardItem(QString(QLatin1Char('A' + i)))); |
| sim->appendRow(row); |
| |
| tv.setSortingEnabled(true); |
| tv.horizontalHeader()->setSortIndicatorShown(true); |
| tv.horizontalHeader()->setSectionsClickable(true); |
| tv.horizontalHeader()->setStretchLastSection(true); |
| tv.horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); |
| |
| tv.setModel(proxyModel); |
| const int section4Size = tv.horizontalHeader()->sectionSize(4) + 1; |
| const int section5Size = section4Size + 1; |
| tv.horizontalHeader()->resizeSection(4, section4Size); |
| tv.horizontalHeader()->resizeSection(5, section5Size); |
| tv.setColumnHidden(5, true); |
| tv.setColumnHidden(6, true); |
| tv.horizontalHeader()->swapSections(8, 10); |
| tv.sortByColumn(1, Qt::AscendingOrder); |
| |
| QCOMPARE(tv.isColumnHidden(5), true); |
| QCOMPARE(tv.isColumnHidden(6), true); |
| QCOMPARE(tv.horizontalHeader()->sectionsMoved(), true); |
| QCOMPARE(tv.horizontalHeader()->logicalIndex(8), 10); |
| QCOMPARE(tv.horizontalHeader()->logicalIndex(10), 8); |
| QCOMPARE(tv.horizontalHeader()->sectionSize(4), section4Size); |
| tv.setColumnHidden(5, false); // unhide, section size must be properly restored |
| QCOMPARE(tv.horizontalHeader()->sectionSize(5), section5Size); |
| tv.setColumnHidden(5, true); |
| |
| QSignalSpy clickedSpy(tv.horizontalHeader(), SIGNAL(sectionClicked(int))); |
| QSignalSpy pressedSpy(tv.horizontalHeader(), SIGNAL(sectionPressed(int))); |
| |
| |
| QTest::mouseClick(tv.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, |
| QPoint(tv.horizontalHeader()->sectionViewportPosition(11) + tv.horizontalHeader()->sectionSize(11)/2, 5)); |
| QCOMPARE(clickedSpy.count(), 1); |
| QCOMPARE(pressedSpy.count(), 1); |
| QCOMPARE(clickedSpy.at(0).at(0).toInt(), 11); |
| QCOMPARE(pressedSpy.at(0).at(0).toInt(), 11); |
| |
| QTest::mouseClick(tv.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, |
| QPoint(tv.horizontalHeader()->sectionViewportPosition(8) + tv.horizontalHeader()->sectionSize(0)/2, 5)); |
| |
| QCOMPARE(clickedSpy.count(), 2); |
| QCOMPARE(pressedSpy.count(), 2); |
| QCOMPARE(clickedSpy.at(1).at(0).toInt(), 8); |
| QCOMPARE(pressedSpy.at(1).at(0).toInt(), 8); |
| |
| QTest::mouseClick(tv.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, |
| QPoint(tv.horizontalHeader()->sectionViewportPosition(0) + tv.horizontalHeader()->sectionSize(0)/2, 5)); |
| |
| QCOMPARE(clickedSpy.count(), 3); |
| QCOMPARE(pressedSpy.count(), 3); |
| QCOMPARE(clickedSpy.at(2).at(0).toInt(), 0); |
| QCOMPARE(pressedSpy.at(2).at(0).toInt(), 0); |
| } |
| |
| void tst_QHeaderView::checkLayoutChangeEmptyModel() |
| { |
| QtTestModel tm; |
| tm.cols = 11; |
| QTableView tv; |
| tv.verticalHeader()->setStretchLastSection(true); |
| tv.setModel(&tm); |
| |
| const int section4Size = tv.horizontalHeader()->sectionSize(4) + 1; |
| const int section5Size = section4Size + 1; |
| tv.horizontalHeader()->resizeSection(4, section4Size); |
| tv.horizontalHeader()->resizeSection(5, section5Size); |
| tv.setColumnHidden(5, true); |
| tv.setColumnHidden(6, true); |
| tv.horizontalHeader()->swapSections(8, 10); |
| |
| tv.sortByColumn(1, Qt::AscendingOrder); |
| tm.emitLayoutChanged(); |
| |
| QCOMPARE(tv.isColumnHidden(5), true); |
| QCOMPARE(tv.isColumnHidden(6), true); |
| QCOMPARE(tv.horizontalHeader()->sectionsMoved(), true); |
| QCOMPARE(tv.horizontalHeader()->logicalIndex(8), 10); |
| QCOMPARE(tv.horizontalHeader()->logicalIndex(10), 8); |
| QCOMPARE(tv.horizontalHeader()->sectionSize(4), section4Size); |
| tv.setColumnHidden(5, false); // unhide, section size must be properly restored |
| QCOMPARE(tv.horizontalHeader()->sectionSize(5), section5Size); |
| tv.setColumnHidden(5, true); |
| |
| // adjust |
| tm.rows = 3; |
| tm.emitLayoutChanged(); |
| |
| // remove the row used for QPersistenModelIndexes |
| tm.emitLayoutChangedWithRemoveFirstRow(); |
| QCOMPARE(tv.isColumnHidden(5), true); |
| QCOMPARE(tv.isColumnHidden(6), true); |
| QCOMPARE(tv.horizontalHeader()->sectionsMoved(), true); |
| QCOMPARE(tv.horizontalHeader()->logicalIndex(8), 10); |
| QCOMPARE(tv.horizontalHeader()->logicalIndex(10), 8); |
| QCOMPARE(tv.horizontalHeader()->sectionSize(4), section4Size); |
| tv.setColumnHidden(5, false); // unhide, section size must be properly restored |
| QCOMPARE(tv.horizontalHeader()->sectionSize(5), section5Size); |
| tv.setColumnHidden(5, true); |
| } |
| |
| void tst_QHeaderView::QTBUG8650_crashOnInsertSections() |
| { |
| QStringList headerLabels; |
| QHeaderView view(Qt::Horizontal); |
| QStandardItemModel model(2,2); |
| view.setModel(&model); |
| view.moveSection(1, 0); |
| view.hideSection(0); |
| |
| QList<QStandardItem *> items; |
| items << new QStandardItem("c"); |
| model.insertColumn(0, items); |
| } |
| |
| static void setModelTexts(QStandardItemModel *model) |
| { |
| const int columnCount = model->columnCount(); |
| for (int i = 0, rowCount = model->rowCount(); i < rowCount; ++i) { |
| const QString prefix = QLatin1String("item [") + QString::number(i) + QLatin1Char(','); |
| for (int j = 0; j < columnCount; ++j) |
| model->setData(model->index(i, j), prefix + QString::number(j) + QLatin1Char(']')); |
| } |
| } |
| |
| void tst_QHeaderView::QTBUG12268_hiddenMovedSectionSorting() |
| { |
| QTableView view; // ### this test fails on QTableView &view = *m_tableview; !? + shadowing view member |
| QStandardItemModel *model = new QStandardItemModel(4,3, &view); |
| setModelTexts(model); |
| view.setModel(model); |
| view.horizontalHeader()->setSectionsMovable(true); |
| view.setSortingEnabled(true); |
| view.sortByColumn(1, Qt::AscendingOrder); |
| view.horizontalHeader()->moveSection(0,2); |
| view.setColumnHidden(1, true); |
| view.show(); |
| QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| QCOMPARE(view.horizontalHeader()->hiddenSectionCount(), 1); |
| QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton); |
| QCOMPARE(view.horizontalHeader()->hiddenSectionCount(), 1); |
| } |
| |
| void tst_QHeaderView::QTBUG14242_hideSectionAutoSize() |
| { |
| QTableView qtv; |
| QStandardItemModel amodel(4, 4); |
| qtv.setModel(&amodel); |
| QHeaderView *hv = qtv.verticalHeader(); |
| hv->setDefaultSectionSize(25); |
| hv->setSectionResizeMode(QHeaderView::ResizeToContents); |
| qtv.show(); |
| |
| hv->hideSection(0); |
| int afterlength = hv->length(); |
| |
| int calced_length = 0; |
| for (int u = 0; u < hv->count(); ++u) |
| calced_length += hv->sectionSize(u); |
| |
| QCOMPARE(calced_length, afterlength); |
| } |
| |
| void tst_QHeaderView::QTBUG50171_visualRegionForSwappedItems() |
| { |
| protected_QHeaderView headerView(Qt::Horizontal); |
| QtTestModel model; |
| model.rows = 2; |
| model.cols = 3; |
| headerView.setModel(&model); |
| headerView.swapSections(1, 2); |
| headerView.hideSection(0); |
| headerView.testVisualRegionForSelection(); |
| } |
| |
| class QTBUG53221_Model : public QAbstractItemModel |
| { |
| public: |
| void insertRowAtBeginning() |
| { |
| Q_EMIT layoutAboutToBeChanged(); |
| m_displayNames.insert(0, QStringLiteral("Item %1").arg(m_displayNames.count())); |
| // Rows are always inserted at the beginning, so move all others. |
| foreach (const QModelIndex &persIndex, persistentIndexList()) |
| { |
| // The vertical header view will have a persistent index stored here on the second call to insertRowAtBeginning. |
| changePersistentIndex(persIndex, index(persIndex.row() + 1, persIndex.column(), persIndex.parent())); |
| } |
| Q_EMIT layoutChanged(); |
| } |
| |
| QVariant data(const QModelIndex &index, int role) const override |
| { |
| return (role == Qt::DisplayRole) ? m_displayNames.at(index.row()) : QVariant(); |
| } |
| |
| QModelIndex index(int row, int column, const QModelIndex &) const override { return createIndex(row, column); } |
| QModelIndex parent(const QModelIndex &) const override { return QModelIndex(); } |
| int rowCount(const QModelIndex &) const override { return m_displayNames.count(); } |
| int columnCount(const QModelIndex &) const override { return 1; } |
| |
| private: |
| QStringList m_displayNames; |
| }; |
| |
| void tst_QHeaderView::QTBUG53221_assertShiftHiddenRow() |
| { |
| QTableView tableView; |
| QTBUG53221_Model modelTableView; |
| tableView.setModel(&modelTableView); |
| |
| modelTableView.insertRowAtBeginning(); |
| tableView.setRowHidden(0, true); |
| QCOMPARE(tableView.verticalHeader()->isSectionHidden(0), true); |
| modelTableView.insertRowAtBeginning(); |
| QCOMPARE(tableView.verticalHeader()->isSectionHidden(0), false); |
| QCOMPARE(tableView.verticalHeader()->isSectionHidden(1), true); |
| modelTableView.insertRowAtBeginning(); |
| QCOMPARE(tableView.verticalHeader()->isSectionHidden(0), false); |
| QCOMPARE(tableView.verticalHeader()->isSectionHidden(1), false); |
| QCOMPARE(tableView.verticalHeader()->isSectionHidden(2), true); |
| } |
| |
| void tst_QHeaderView::QTBUG75615_sizeHintWithStylesheet() |
| { |
| QTableView tableView; |
| QStandardItemModel model(1, 1); |
| tableView.setModel(&model); |
| tableView.show(); |
| |
| const auto headerView = tableView.horizontalHeader(); |
| const auto oldSizeHint = headerView->sizeHint(); |
| QVERIFY(oldSizeHint.isValid()); |
| |
| tableView.setStyleSheet("QTableView QHeaderView::section { height: 100px;}"); |
| QCOMPARE(headerView->sizeHint().width(), oldSizeHint.width()); |
| QCOMPARE(headerView->sizeHint().height(), 100); |
| |
| tableView.setStyleSheet("QTableView QHeaderView::section { width: 100px;}"); |
| QCOMPARE(headerView->sizeHint().height(), oldSizeHint.height()); |
| QCOMPARE(headerView->sizeHint().width(), 100); |
| } |
| |
| void protected_QHeaderView::testVisualRegionForSelection() |
| { |
| QRegion r = visualRegionForSelection(QItemSelection(model()->index(1, 0), model()->index(1, 2))); |
| QCOMPARE(r.boundingRect().contains(QRect(1, 1, length() - 2, 1)), true); |
| } |
| |
| void tst_QHeaderView::ensureNoIndexAtLength() |
| { |
| QTableView qtv; |
| QStandardItemModel amodel(4, 4); |
| qtv.setModel(&amodel); |
| QHeaderView *hv = qtv.verticalHeader(); |
| QCOMPARE(hv->visualIndexAt(hv->length()), -1); |
| hv->resizeSection(hv->count() - 1, 0); |
| QCOMPARE(hv->visualIndexAt(hv->length()), -1); |
| } |
| |
| void tst_QHeaderView::offsetConsistent() |
| { |
| // Ensure that a hidden section 'far away' |
| // does not affect setOffsetToSectionPosition .. |
| const int sectionToHide = 513; |
| QTableView qtv; |
| QStandardItemModel amodel(1000, 4); |
| qtv.setModel(&amodel); |
| QHeaderView *hv = qtv.verticalHeader(); |
| for (int u = 0; u < 100; u += 2) |
| hv->resizeSection(u, 0); |
| hv->setOffsetToSectionPosition(150); |
| int offset1 = hv->offset(); |
| hv->hideSection(sectionToHide); |
| hv->setOffsetToSectionPosition(150); |
| int offset2 = hv->offset(); |
| QCOMPARE(offset1, offset2); |
| // Ensure that hidden indexes (still) is considered. |
| hv->resizeSection(sectionToHide, hv->sectionSize(200) * 2); |
| hv->setOffsetToSectionPosition(800); |
| offset1 = hv->offset(); |
| hv->showSection(sectionToHide); |
| hv->setOffsetToSectionPosition(800); |
| offset2 = hv->offset(); |
| QVERIFY(offset2 > offset1); |
| } |
| |
| void tst_QHeaderView::initialSortOrderRole() |
| { |
| QTableView view; // ### Shadowing member view (of type QHeaderView) |
| QStandardItemModel *model = new QStandardItemModel(4, 3, &view); |
| setModelTexts(model); |
| QStandardItem *ascendingItem = new QStandardItem(); |
| QStandardItem *descendingItem = new QStandardItem(); |
| ascendingItem->setData(Qt::AscendingOrder, Qt::InitialSortOrderRole); |
| descendingItem->setData(Qt::DescendingOrder, Qt::InitialSortOrderRole); |
| model->setHorizontalHeaderItem(1, ascendingItem); |
| model->setHorizontalHeaderItem(2, descendingItem); |
| view.setModel(model); |
| view.setSortingEnabled(true); |
| view.sortByColumn(0, Qt::AscendingOrder); |
| view.show(); |
| QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| |
| const int column1Pos = view.horizontalHeader()->sectionViewportPosition(1) + 5; // +5 not to be on the handle |
| QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(column1Pos, 0)); |
| QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 1); |
| QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::AscendingOrder); |
| |
| const int column2Pos = view.horizontalHeader()->sectionViewportPosition(2) + 5; // +5 not to be on the handle |
| QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(column2Pos, 0)); |
| QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 2); |
| QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::DescendingOrder); |
| |
| const int column0Pos = view.horizontalHeader()->sectionViewportPosition(0) + 5; // +5 not to be on the handle |
| QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(column0Pos, 0)); |
| QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 0); |
| QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::AscendingOrder); |
| } |
| |
| const bool block_some_signals = true; // The test should also work with this set to false |
| const int rowcount = 500; |
| const int colcount = 10; |
| |
| QString istr(int n, bool comma = true) |
| { |
| QString s; |
| s.setNum(n); |
| if (comma) |
| s += ", "; |
| return s; |
| } |
| |
| void tst_QHeaderView::calculateAndCheck(int cppline, const int precalced_comparedata[]) |
| { |
| qint64 endtimer = timer.elapsed(); |
| const bool silentmode = true; |
| if (!silentmode) |
| qDebug().nospace() << "(Time:" << endtimer << ")"; |
| |
| QString sline; |
| sline.setNum(cppline - 1); |
| |
| const int p1 = 3133777; // just a prime (maybe not that random ;) ) |
| const int p2 = 135928393; // just a random large prime - a bit less than signed 32-bit |
| |
| int sum_visual = 0; |
| int sum_logical = 0; |
| int sum_size = 0; |
| int sum_hidden_size = 0; |
| int sum_lookup_visual = 0; |
| int sum_lookup_logical = 0; |
| |
| int chk_visual = 1; |
| int chk_logical = 1; |
| int chk_sizes = 1; |
| int chk_hidden_size = 1; |
| int chk_lookup_visual = 1; |
| int chk_lookup_logical = 1; |
| |
| int header_lenght = 0; |
| int lastindex = view->count() - 1; |
| |
| // calculate information based on index |
| for (int i = 0; i <= lastindex; ++i) { |
| int visual = view->visualIndex(i); |
| int logical = view->logicalIndex(i); |
| int ssize = view->sectionSize(i); |
| |
| sum_visual += visual; |
| sum_logical += logical; |
| sum_size += ssize; |
| |
| if (visual >= 0) { |
| chk_visual %= p2; |
| chk_visual *= (visual + 1) * (i + 1) * p1; |
| } |
| |
| if (logical >= 0) { |
| chk_logical %= p2; |
| chk_logical *= (logical + 1) * (i + 1 + (logical != i) ) * p1; |
| } |
| |
| if (ssize >= 0) { |
| chk_sizes %= p2; |
| chk_sizes *= ( (ssize + 2) * (i + 1) * p1); |
| } |
| |
| if (view->isSectionHidden(i)) { |
| view->showSection(i); |
| int hiddensize = view->sectionSize(i); |
| sum_hidden_size += hiddensize; |
| chk_hidden_size %= p2; |
| chk_hidden_size += ( (hiddensize + 1) * (i + 1) * p1); |
| // (hiddensize + 1) in the above to differ between hidden and size 0 |
| // Though it can be changed (why isn't sections with size 0 hidden?) |
| |
| view->hideSection(i); |
| } |
| } |
| |
| // lookup indexes by pixel position |
| const int max_lookup_count = 500; |
| int lookup_to = view->height() + 1; |
| if (lookup_to > max_lookup_count) |
| lookup_to = max_lookup_count; // We limit this lookup - not to spend years when testing. |
| // Notice that lookupTest also has its own extra test |
| for (int u = 0; u < max_lookup_count; ++u) { |
| int visu = view->visualIndexAt(u); |
| int logi = view->logicalIndexAt(u); |
| sum_lookup_visual += logi; |
| sum_lookup_logical += visu; |
| chk_lookup_visual %= p2; |
| chk_lookup_visual *= ( (u + 1) * p1 * (visu + 2)); |
| chk_lookup_logical %= p2; |
| chk_lookup_logical *= ( (u + 1) * p1 * (logi + 2)); |
| } |
| header_lenght = view->length(); |
| |
| // visual and logical indexes. |
| int sum_to_last_index = (lastindex * (lastindex + 1)) / 2; // == 0 + 1 + 2 + 3 + ... + lastindex |
| |
| const bool write_calced_data = false; // Do not write calculated output (unless the test fails) |
| if (write_calced_data) { |
| qDebug().nospace() << "(" << cppline - 1 << ")" // << " const int precalced[] = " |
| << " {" << chk_visual << ", " << chk_logical << ", " << chk_sizes << ", " << chk_hidden_size |
| << ", " << chk_lookup_visual << ", " << chk_lookup_logical << ", " << header_lenght << "};"; |
| } |
| |
| const bool sanity_checks = true; |
| if (sanity_checks) { |
| QString msg = QString("sanity problem at ") + sline; |
| const QScopedArrayPointer<char> holder(QTest::toString(msg)); |
| const auto verifytext = holder.data(); |
| |
| QVERIFY2(m_tableview->model()->rowCount() == view->count() , verifytext); |
| QVERIFY2(view->visualIndex(lastindex + 1) <= 0, verifytext); // there is no such index in model |
| QVERIFY2(view->logicalIndex(lastindex + 1) <= 0, verifytext); // there is no such index in model. |
| QVERIFY2(view->logicalIndex(lastindex + 1) <= 0, verifytext); // there is no such index in model. |
| QVERIFY2(lastindex < 0 || view->visualIndex(0) >= 0, verifytext); // no rows or legal index |
| QVERIFY2(lastindex < 0 || view->logicalIndex(0) >= 0, verifytext); // no rows or legal index |
| QVERIFY2(lastindex < 0 || view->visualIndex(lastindex) >= 0, verifytext); // no rows or legal index |
| QVERIFY2(lastindex < 0 || view->logicalIndex(lastindex) >= 0, verifytext); // no rows or legal index |
| QVERIFY2(view->visualIndexAt(-1) == -1, verifytext); |
| QVERIFY2(view->logicalIndexAt(-1) == -1, verifytext); |
| QVERIFY2(view->visualIndexAt(view->length()) == -1, verifytext); |
| QVERIFY2(view->logicalIndexAt(view->length()) == -1, verifytext); |
| QVERIFY2(sum_visual == sum_logical, verifytext); |
| QVERIFY2(sum_to_last_index == sum_logical, verifytext); |
| } |
| |
| // Semantic test |
| const bool check_semantics = true; // Otherwise there is no 'real' test |
| if (!check_semantics) |
| return; |
| |
| const int *x = precalced_comparedata; |
| |
| QString msg = "semantic problem at " + QString(__FILE__) + " (" + sline + ")"; |
| msg += "\nThe *expected* result was : {" + istr(x[0]) + istr(x[1]) + istr(x[2]) + istr(x[3]) |
| + istr(x[4]) + istr(x[5]) + istr(x[6], false) + QLatin1Char('}'); |
| msg += "\nThe calculated result was : {"; |
| msg += istr(chk_visual) + istr(chk_logical) + istr(chk_sizes) + istr(chk_hidden_size) |
| + istr(chk_lookup_visual) + istr(chk_lookup_logical) + istr(header_lenght, false) + "};"; |
| |
| const QScopedArrayPointer<char> holder(QTest::toString(msg)); |
| const auto verifytext = holder.data(); |
| |
| QVERIFY2(chk_visual == x[0], verifytext); |
| QVERIFY2(chk_logical == x[1], verifytext); |
| QVERIFY2(chk_sizes == x[2], verifytext); |
| QVERIFY2(chk_hidden_size == x[3], verifytext); |
| QVERIFY2(chk_lookup_visual == x[4], verifytext); |
| QVERIFY2(chk_lookup_logical == x[5], verifytext); |
| QVERIFY2(header_lenght == x[6], verifytext); |
| } |
| |
| void tst_QHeaderView::setupTestData(bool also_use_reset_model) |
| { |
| QTest::addColumn<bool>("updates_enabled"); |
| QTest::addColumn<bool>("special_prepare"); |
| QTest::addColumn<bool>("reset_model"); |
| |
| if (also_use_reset_model) { |
| QTest::newRow("no_updates+normal+reset") << false << false << true; |
| QTest::newRow("hasupdates+normal+reset") << true << false << true; |
| QTest::newRow("no_updates+special+reset") << false << true << true; |
| QTest::newRow("hasupdates+special+reset") << true << true << true; |
| } |
| |
| QTest::newRow("no_updates+normal") << false << false << false; |
| QTest::newRow("hasupdates+normal") << true << false << false; |
| QTest::newRow("no_updates+special") << false << true << false; |
| QTest::newRow("hasupdates+special") << true << true << false; |
| } |
| |
| void tst_QHeaderView::additionalInit() |
| { |
| m_tableview->setVerticalHeader(view); |
| |
| QFETCH(bool, updates_enabled); |
| QFETCH(bool, special_prepare); |
| QFETCH(bool, reset_model); |
| |
| m_using_reset_model = reset_model; |
| m_special_prepare = special_prepare; |
| |
| if (m_using_reset_model) { |
| XResetModel *m = new XResetModel(); |
| m_tableview->setModel(m); |
| delete model; |
| model = m; |
| } else { |
| m_tableview->setModel(model); |
| } |
| |
| const int default_section_size = 25; |
| view->setDefaultSectionSize(default_section_size); // Important - otherwise there will be semantic changes |
| |
| model->clear(); |
| |
| if (special_prepare) { |
| |
| for (int u = 0; u <= rowcount; ++u) // ensures fragmented spans in e.g Qt 4.7 |
| model->setRowCount(u); |
| |
| model->setColumnCount(colcount); |
| view->swapSections(0, rowcount - 1); |
| view->swapSections(0, rowcount - 1); // No real change - setup visual and log-indexes |
| view->hideSection(rowcount - 1); |
| view->showSection(rowcount - 1); // No real change - (maybe init hidden vector) |
| } else { |
| model->setColumnCount(colcount); |
| model->setRowCount(rowcount); |
| } |
| |
| QString s; |
| for (int i = 0; i < model->rowCount(); ++i) { |
| model->setData(model->index(i, 0), QVariant(i)); |
| s.setNum(i); |
| s += QLatin1Char('.'); |
| s += 'a' + (i % 25); |
| model->setData(model->index(i, 1), QVariant(s)); |
| } |
| m_tableview->setUpdatesEnabled(updates_enabled); |
| view->blockSignals(block_some_signals); |
| timer.start(); |
| } |
| |
| void tst_QHeaderView::logicalIndexAtTest() |
| { |
| additionalInit(); |
| |
| view->swapSections(4, 9); // Make sure that visual and logical Indexes are not just the same. |
| |
| int check1 = 0; |
| int check2 = 0; |
| for (int u = 0; u < model->rowCount(); ++u) { |
| view->resizeSection(u, 10 + u % 30); |
| int v = view->visualIndexAt(u * 29); |
| view->visualIndexAt(u * 29); |
| check1 += v; |
| check2 += u * v; |
| } |
| view->resizeSection(0, 0); // Make sure that we have a 0 size section - before the result set |
| view->setSectionHidden(6, true); // Make sure we have a real hidden section before result set |
| |
| //qDebug() << "logicalIndexAtTest" << check1 << check2; |
| const int precalced_check1 = 106327; |
| const int precalced_check2 = 29856418; |
| QCOMPARE(precalced_check1, check1); |
| QCOMPARE(precalced_check2, check2); |
| |
| const int precalced_results[] = { 1145298384, -1710423344, -650981936, 372919464, -1544372176, -426463328, 12124 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } |
| |
| void tst_QHeaderView::visualIndexAtTest() |
| { |
| additionalInit(); |
| |
| view->swapSections(4, 9); // Make sure that visual and logical Indexes are not just the same. |
| int check1 = 0; |
| int check2 = 0; |
| |
| for (int u = 0; u < model->rowCount(); ++u) { |
| view->resizeSection(u, 3 + u % 17); |
| int v = view->visualIndexAt(u * 29); |
| check1 += v; |
| check2 += u * v; |
| } |
| |
| view->resizeSection(1, 0); // Make sure that we have a 0 size section - before the result set |
| view->setSectionHidden(5, true); // Make sure we have a real hidden section before result set |
| |
| //qDebug() << "visualIndexAtTest" << check1 << check2; |
| const int precalced_check1 = 72665; |
| const int precalced_check2 = 14015890; |
| QCOMPARE(precalced_check1, check1); |
| QCOMPARE(precalced_check2, check2); |
| |
| const int precalced_results[] = { 1145298384, -1710423344, -1457520212, 169223959, 557466160, -324939600, 5453 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } |
| |
| void tst_QHeaderView::hideShowTest() |
| { |
| additionalInit(); |
| |
| for (int u = model->rowCount(); u >= 0; --u) |
| if (u % 8 != 0) |
| view->hideSection(u); |
| |
| for (int u = model->rowCount(); u >= 0; --u) |
| if (u % 3 == 0) |
| view->showSection(u); |
| |
| view->setSectionHidden(model->rowCount(), true); // invalid hide (should be ignored) |
| view->setSectionHidden(-1, true); // invalid hide (should be ignored) |
| |
| const int precalced_results[] = { -1523279360, -1523279360, -1321506816, 2105322423, 1879611280, 1879611280, 5225 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } |
| |
| void tst_QHeaderView::swapSectionsTest() |
| { |
| additionalInit(); |
| |
| for (int u = 0; u < rowcount / 2; ++u) |
| view->swapSections(u, rowcount - u - 1); |
| |
| for (int u = 0; u < rowcount; u += 2) |
| view->swapSections(u, u + 1); |
| |
| view->swapSections(0, model->rowCount()); // invalid swapsection (should be ignored) |
| |
| const int precalced_results[] = { -1536450048, -1774641430, -1347156568, 1, 1719705216, -240077576, 12500 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } |
| |
| void tst_QHeaderView::moveSectionTest() |
| { |
| additionalInit(); |
| |
| for (int u = 1; u < 5; ++u) |
| view->moveSection(u, model->rowCount() - u); |
| |
| view->moveSection(2, model->rowCount() / 2); |
| view->moveSection(0, 10); |
| view->moveSection(0, model->rowCount() - 10); |
| |
| view->moveSection(0, model->rowCount()); // invalid move (should be ignored) |
| |
| const int precalced_results[] = { 645125952, 577086896, -1347156568, 1, 1719705216, 709383416, 12500 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } |
| |
| void tst_QHeaderView::defaultSizeTest() |
| { |
| additionalInit(); |
| |
| view->hideSection(rowcount / 2); |
| int restore_to = view->defaultSectionSize(); |
| view->setDefaultSectionSize(restore_to + 5); |
| |
| const int precalced_results[] = { -1523279360, -1523279360, -1739688320, -1023807777, 997629696, 997629696, 14970 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| |
| view->setDefaultSectionSize(restore_to); |
| } |
| |
| void tst_QHeaderView::removeTest() |
| { |
| additionalInit(); |
| |
| view->swapSections(0, 5); |
| model->removeRows(0, 1); // remove one row |
| model->removeRows(4, 10); |
| model->setRowCount(model->rowCount() / 2 - 1); |
| |
| if (m_using_reset_model) { |
| const int precalced_results[] = { 1741224292, -135269187, -569519837, 1, 1719705216, -1184395000, 6075 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } else { |
| const int precalced_results[] = { 289162397, 289162397, -569519837, 1, 1719705216, 1719705216, 6075 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } |
| } |
| |
| void tst_QHeaderView::insertTest() |
| { |
| additionalInit(); |
| |
| view->swapSections(0, model->rowCount() - 1); |
| model->insertRows(0, 1); // insert one row |
| model->insertRows(4, 10); |
| model->setRowCount(model->rowCount() * 2 - 1); |
| |
| if (m_using_reset_model) { |
| const int precalced_results[] = { 2040508069, -1280266538, -150350734, 1, 1719705216, 1331312784, 25525 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } else { |
| const int precalced_results[] = { -1909447021, 339092083, -150350734, 1, 1719705216, -969712728, 25525 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } |
| } |
| |
| void tst_QHeaderView::mixedTests() |
| { |
| additionalInit(); |
| |
| model->setRowCount(model->rowCount() + 10); |
| |
| for (int u = 0; u < model->rowCount(); u += 2) |
| view->swapSections(u, u + 1); |
| |
| view->moveSection(0, 5); |
| |
| for (int u = model->rowCount(); u >= 0; --u) { |
| if (u % 5 != 0) { |
| view->hideSection(u); |
| QVERIFY(view->isSectionHidden(u)); |
| } |
| if (u % 3 != 0) { |
| view->showSection(u); |
| QVERIFY(!view->isSectionHidden(u)); |
| } |
| } |
| |
| model->insertRows(3, 7); |
| model->removeRows(8, 3); |
| model->setRowCount(model->rowCount() - 10); |
| |
| // the upper is not visible (when m_using_reset_model is true) |
| // the lower 11 are modified due to insert/removeRows |
| for (int u = model->rowCount() - 1; u >= 11; --u) { |
| // when using reset, the hidden rows will *not* move |
| const int calcMod = m_using_reset_model ? u : u - 4; // 7 added, 3 removed |
| if (calcMod % 5 != 0 && calcMod % 3 == 0) { |
| QVERIFY(view->isSectionHidden(u)); |
| } |
| if (calcMod % 3 != 0) { |
| QVERIFY(!view->isSectionHidden(u)); |
| } |
| } |
| if (m_using_reset_model) { |
| const int precalced_results[] = { 898296472, 337096378, -543340640, -1964432121, -1251526424, -568618976, 9250 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } else { |
| const int precalced_results[] = { 1911338224, 1693514365, -613398968, -1912534953, 1582159424, -1851079000, 9300 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } |
| } |
| |
| void tst_QHeaderView::resizeToContentTest() |
| { |
| additionalInit(); |
| |
| QModelIndex idx = model->index(2, 2); |
| model->setData(idx, QVariant("A normal string")); |
| |
| idx = model->index(1, 3); |
| model->setData(idx, QVariant("A normal longer string to test resize")); |
| |
| QHeaderView *hh = m_tableview->horizontalHeader(); |
| hh->resizeSections(QHeaderView::ResizeToContents); |
| QVERIFY(hh->sectionSize(3) > hh->sectionSize(2)); |
| |
| for (int u = 0; u < 10; ++u) |
| view->resizeSection(u, 1); |
| |
| view->resizeSections(QHeaderView::ResizeToContents); |
| QVERIFY(view->sectionSize(1) > 1); |
| QVERIFY(view->sectionSize(2) > 1); |
| |
| // Check minimum section size |
| hh->setMinimumSectionSize(150); |
| model->setData(idx, QVariant("i")); |
| hh->resizeSections(QHeaderView::ResizeToContents); |
| QCOMPARE(hh->sectionSize(3), 150); |
| hh->setMinimumSectionSize(-1); |
| |
| // Check maximumSection size |
| hh->setMaximumSectionSize(200); |
| model->setData(idx, QVariant("This is a even longer string that is expected to be more than 200 pixels")); |
| hh->resizeSections(QHeaderView::ResizeToContents); |
| QCOMPARE(hh->sectionSize(3), 200); |
| hh->setMaximumSectionSize(-1); |
| |
| view->setDefaultSectionSize(25); // To make sure our precalced data are correct. We do not know font height etc. |
| |
| const int precalced_results[] = { -1523279360, -1523279360, -1347156568, 1, 1719705216, 1719705216, 12500 }; |
| calculateAndCheck(__LINE__, precalced_results); |
| } |
| |
| void tst_QHeaderView::testStreamWithHide() |
| { |
| #ifndef QT_NO_DATASTREAM |
| m_tableview->setVerticalHeader(view); |
| m_tableview->setModel(model); |
| view->setDefaultSectionSize(25); |
| view->hideSection(2); |
| view->swapSections(1, 2); |
| |
| QByteArray s = view->saveState(); |
| view->swapSections(1, 2); |
| view->setDefaultSectionSize(30); // To make sure our precalced data are correct. |
| view->restoreState(s); |
| |
| const int precalced_results[] = { -1116614432, -1528653200, -1914165644, 244434607, -1111214068, 750357900, 75}; |
| calculateAndCheck(__LINE__, precalced_results); |
| #else |
| QSKIP("Datastream required for testStreamWithHide. Skipping this test."); |
| #endif |
| } |
| |
| void tst_QHeaderView::testStylePosition() |
| { |
| topLevel->show(); |
| QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| |
| protected_QHeaderView *header = static_cast<protected_QHeaderView *>(view); |
| |
| TestStyle proxy; |
| header->setStyle(&proxy); |
| |
| QImage image(1, 1, QImage::Format_ARGB32); |
| QPainter p(&image); |
| |
| // 0, 1, 2, 3 |
| header->paintSection(&p, view->rect(), 0); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Beginning); |
| header->paintSection(&p, view->rect(), 1); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Middle); |
| header->paintSection(&p, view->rect(), 2); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Middle); |
| header->paintSection(&p, view->rect(), 3); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::End); |
| |
| // (0),2,1,3 |
| view->setSectionHidden(0, true); |
| view->swapSections(1, 2); |
| header->paintSection(&p, view->rect(), 1); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Middle); |
| header->paintSection(&p, view->rect(), 2); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Beginning); |
| header->paintSection(&p, view->rect(), 3); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::End); |
| |
| // (1),2,0,(3) |
| view->setSectionHidden(3, true); |
| view->setSectionHidden(0, false); |
| view->setSectionHidden(1, true); |
| view->swapSections(0, 1); |
| header->paintSection(&p, view->rect(), 0); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::End); |
| header->paintSection(&p, view->rect(), 2); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Beginning); |
| |
| // (1),2,(0),(3) |
| view->setSectionHidden(0, true); |
| header->paintSection(&p, view->rect(), 2); |
| QCOMPARE(proxy.lastPosition, QStyleOptionHeader::OnlyOneSection); |
| } |
| |
| void tst_QHeaderView::sizeHintCrash() |
| { |
| QTreeView treeView; |
| QStandardItemModel *model = new QStandardItemModel(&treeView); |
| model->appendRow(new QStandardItem("QTBUG-48543")); |
| treeView.setModel(model); |
| treeView.header()->sizeHintForColumn(0); |
| treeView.header()->sizeHintForRow(0); |
| } |
| |
| void tst_QHeaderView::stretchAndRestoreLastSection() |
| { |
| QStandardItemModel m(10, 10); |
| QTableView tv; |
| tv.setModel(&m); |
| tv.showMaximized(); |
| |
| const int minimumSectionSize = 20; |
| const int defaultSectionSize = 30; |
| const int someOtherSectionSize = 40; |
| const int biggerSizeThanAnySection = 50; |
| |
| QVERIFY(QTest::qWaitForWindowExposed(&tv)); |
| |
| QHeaderView &header = *tv.horizontalHeader(); |
| // set minimum size before resizeSections() is called |
| // which is done inside setStretchLastSection |
| header.setMinimumSectionSize(minimumSectionSize); |
| header.setDefaultSectionSize(defaultSectionSize); |
| header.resizeSection(9, someOtherSectionSize); |
| header.setStretchLastSection(true); |
| |
| // Default last section is larger |
| QCOMPARE(header.sectionSize(8), defaultSectionSize); |
| QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| |
| // Moving last section away (restore old last section 9 - and make 8 larger) |
| header.swapSections(9, 8); |
| QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| QVERIFY(header.sectionSize(8) >= biggerSizeThanAnySection); |
| |
| // Make section 9 the large one again |
| header.hideSection(8); |
| QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| |
| // Show section 8 again - and make that one the last one. |
| header.showSection(8); |
| QVERIFY(header.sectionSize(8) > biggerSizeThanAnySection); |
| QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| |
| // Swap the sections so the logical indexes are equal to visible indexes again. |
| header.moveSection(9, 8); |
| QCOMPARE(header.sectionSize(8), defaultSectionSize); |
| QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| |
| // Append sections |
| m.setColumnCount(15); |
| QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| QVERIFY(header.sectionSize(14) >= biggerSizeThanAnySection); |
| |
| // Truncate sections (remove sections with the last section) |
| m.setColumnCount(10); |
| QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| for (int u = 0; u < 9; ++u) |
| QCOMPARE(header.sectionSize(u), defaultSectionSize); |
| |
| // Insert sections |
| m.insertColumns(2, 2); |
| QCOMPARE(header.sectionSize(9), defaultSectionSize); |
| QCOMPARE(header.sectionSize(10), defaultSectionSize); |
| QVERIFY(header.sectionSize(11) >= biggerSizeThanAnySection); |
| |
| // Append an extra section and check restore |
| m.setColumnCount(m.columnCount() + 1); |
| QCOMPARE(header.sectionSize(11), someOtherSectionSize); |
| QVERIFY(header.sectionSize(12) >= biggerSizeThanAnySection); |
| |
| // Remove some sections but not the last one. |
| m.removeColumns(2, 2); |
| QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| QVERIFY(header.sectionSize(10) >= biggerSizeThanAnySection); |
| for (int u = 0; u < 9; ++u) |
| QCOMPARE(header.sectionSize(u), defaultSectionSize); |
| |
| // Empty the header and start over with some more tests |
| m.setColumnCount(0); |
| m.setColumnCount(10); |
| QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| |
| // Check resize of the last section |
| header.resizeSection(9, someOtherSectionSize); |
| QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); // It should still be stretched |
| header.swapSections(9, 8); |
| QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| |
| // Restore the order |
| header.swapSections(9, 8); |
| QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| |
| // Hide the last 3 sections and test stretch last section on swap/move |
| // when hidden sections with a larger visual index exists. |
| header.hideSection(7); |
| header.hideSection(8); |
| header.hideSection(9); |
| QVERIFY(header.sectionSize(6) >= biggerSizeThanAnySection); |
| header.moveSection(2, 7); |
| QVERIFY(header.sectionSize(2) >= biggerSizeThanAnySection); |
| header.swapSections(1, 8); |
| QCOMPARE(header.sectionSize(2), defaultSectionSize); |
| QVERIFY(header.sectionSize(1) >= biggerSizeThanAnySection); |
| |
| // Inserting sections 2 |
| m.setColumnCount(0); |
| m.setColumnCount(10); |
| header.resizeSection(1, someOtherSectionSize); |
| header.swapSections(1, 9); |
| m.insertColumns(9, 2); |
| header.swapSections(1, 11); |
| QCOMPARE(header.sectionSize(1), someOtherSectionSize); |
| |
| // Clear and re-add. This triggers a different code path than seColumnCount(0) |
| m.clear(); |
| m.setColumnCount(3); |
| QVERIFY(header.sectionSize(2) >= biggerSizeThanAnySection); |
| |
| // Test import/export of the original (not stretched) sectionSize. |
| m.setColumnCount(0); |
| m.setColumnCount(10); |
| header.resizeSection(9, someOtherSectionSize); |
| QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| QByteArray b = header.saveState(); |
| m.setColumnCount(0); |
| m.setColumnCount(10); |
| header.restoreState(b); |
| header.setStretchLastSection(false); |
| QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| } |
| |
| void tst_QHeaderView::testMinMaxSectionSize_data() |
| { |
| QTest::addColumn<bool>("stretchLastSection"); |
| QTest::addRow("stretched") << true; |
| QTest::addRow("not stretched") << false; |
| } |
| |
| void tst_QHeaderView::testMinMaxSectionSize() |
| { |
| QFETCH(bool, stretchLastSection); |
| |
| QStandardItemModel m(5, 5); |
| QTableView tv; |
| tv.setModel(&m); |
| tv.show(); |
| |
| const int sectionSizeMin = 20; |
| const int sectionSizeMax = 40; |
| const int defaultSectionSize = 30; |
| |
| QVERIFY(QTest::qWaitForWindowExposed(&tv)); |
| |
| QHeaderView &header = *tv.horizontalHeader(); |
| header.setMinimumSectionSize(sectionSizeMin); |
| header.setMaximumSectionSize(sectionSizeMax); |
| // check bounds for default section size |
| header.setDefaultSectionSize(sectionSizeMin - 1); |
| QCOMPARE(header.defaultSectionSize(), sectionSizeMin); |
| header.setDefaultSectionSize(sectionSizeMax + 1); |
| QCOMPARE(header.defaultSectionSize(), sectionSizeMax); |
| |
| header.setDefaultSectionSize(defaultSectionSize); |
| QCOMPARE(header.defaultSectionSize(), defaultSectionSize); |
| header.setStretchLastSection(stretchLastSection); |
| QCOMPARE(header.stretchLastSection(), stretchLastSection); |
| |
| // check defaults |
| QCOMPARE(header.sectionSize(0), defaultSectionSize); |
| QCOMPARE(header.sectionSize(3), defaultSectionSize); |
| |
| // do not go above maxSectionSize |
| header.resizeSection(0, sectionSizeMax + 1); |
| QCOMPARE(header.sectionSize(0), sectionSizeMax); |
| |
| // do not go below minSectionSize |
| header.resizeSection(0, sectionSizeMin - 1); |
| QCOMPARE(header.sectionSize(0), sectionSizeMin); |
| |
| // change section size on max change |
| header.setMinimumSectionSize(sectionSizeMin); |
| header.setMaximumSectionSize(sectionSizeMax); |
| header.resizeSection(0, sectionSizeMax); |
| QCOMPARE(header.sectionSize(0), sectionSizeMax); |
| header.setMaximumSectionSize(defaultSectionSize); |
| QTRY_COMPARE(header.sectionSize(0), defaultSectionSize); |
| |
| // change section size on min change |
| header.setMinimumSectionSize(sectionSizeMin); |
| header.setMaximumSectionSize(sectionSizeMax); |
| header.resizeSection(0, sectionSizeMin); |
| QCOMPARE(header.sectionSize(0), sectionSizeMin); |
| header.setMinimumSectionSize(defaultSectionSize); |
| QTRY_COMPARE(header.sectionSize(0), defaultSectionSize); |
| } |
| |
| void tst_QHeaderView::testResetCachedSizeHint() |
| { |
| QtTestModel model; |
| model.rows = model.cols = 10; |
| |
| QTableView tv; |
| tv.setModel(&model); |
| tv.show(); |
| QVERIFY(QTest::qWaitForWindowExposed(&tv)); |
| |
| QSize s1 = tv.horizontalHeader()->sizeHint(); |
| model.setMultiLineHeader(true); |
| QSize s2 = tv.horizontalHeader()->sizeHint(); |
| model.setMultiLineHeader(false); |
| QSize s3 = tv.horizontalHeader()->sizeHint(); |
| QCOMPARE(s1, s3); |
| QVERIFY(s1 != s2); |
| } |
| |
| |
| class StatusTipHeaderView : public QHeaderView |
| { |
| public: |
| StatusTipHeaderView(Qt::Orientation orientation = Qt::Horizontal, QWidget *parent = 0) : |
| QHeaderView(orientation, parent), gotStatusTipEvent(false) {} |
| bool gotStatusTipEvent; |
| QString statusTipText; |
| protected: |
| bool event(QEvent *e) |
| { |
| if (e->type() == QEvent::StatusTip) { |
| gotStatusTipEvent = true; |
| statusTipText = static_cast<QStatusTipEvent *>(e)->tip(); |
| } |
| return QHeaderView::event(e); |
| } |
| }; |
| |
| void tst_QHeaderView::statusTips() |
| { |
| StatusTipHeaderView headerView; |
| QtTestModel model; |
| model.rows = model.cols = 5; |
| headerView.setModel(&model); |
| headerView.viewport()->setMouseTracking(true); |
| headerView.setGeometry(QRect(QPoint(QApplication::desktop()->geometry().center() - QPoint(250, 250)), |
| QSize(500, 500))); |
| headerView.show(); |
| qApp->setActiveWindow(&headerView); |
| QVERIFY(QTest::qWaitForWindowActive(&headerView)); |
| |
| // Ensure it is moved away first and then moved to the relevant section |
| QTest::mouseMove(QApplication::desktop(), |
| headerView.rect().bottomLeft() + QPoint(20, 20)); |
| QPoint centerPoint = QRect(headerView.sectionPosition(0), 0, |
| headerView.sectionSize(0), headerView.height()).center(); |
| QTest::mouseMove(headerView.windowHandle(), centerPoint); |
| QTRY_VERIFY(headerView.gotStatusTipEvent); |
| QCOMPARE(headerView.statusTipText, QLatin1String("[0,0,0] -- Header")); |
| |
| headerView.gotStatusTipEvent = false; |
| headerView.statusTipText.clear(); |
| centerPoint = QRect(headerView.sectionPosition(1), 0, |
| headerView.sectionSize(1), headerView.height()).center(); |
| QTest::mouseMove(headerView.windowHandle(), centerPoint); |
| QTRY_VERIFY(headerView.gotStatusTipEvent); |
| QCOMPARE(headerView.statusTipText, QLatin1String("[0,1,0] -- Header")); |
| } |
| |
| void tst_QHeaderView::testRemovingColumnsViaLayoutChanged() |
| { |
| const int persistentSectionSize = 101; |
| |
| QtTestModel model; |
| model.rows = model.cols = 5; |
| view->setModel(&model); |
| for (int i = 0; i < model.cols; ++i) |
| view->resizeSection(i, persistentSectionSize + i); |
| model.cleanup(); // down to 3 via layoutChanged (not columnsRemoved) |
| for (int j = 0; j < model.cols; ++j) |
| QCOMPARE(view->sectionSize(j), persistentSectionSize + j); |
| // The main point of this test is that the section-size restoring code didn't go out of bounds. |
| } |
| |
| QTEST_MAIN(tst_QHeaderView) |
| #include "tst_qheaderview.moc" |