ba6e0e4aac
If columns are removed and we get notified via layoutChanged, the code tries to restore old section sizes, and went out of bounds, leading to an assert in QVector. Simply add an if() to skip restoring out-of-bounds columns. This comes from https://bugs.kde.org/show_bug.cgi?id=395181, which translates into the unittest that is part of this commit. Change-Id: Ide42176a758f87b21957c40508127d67f1d5a2d9 Reviewed-by: Christian Ehrlicher <ch.ehrlicher@gmx.de> Reviewed-by: Thorbjørn Lund Martsum <tmartsum@gmail.com>
3511 lines
111 KiB
C++
3511 lines
111 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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);
|
|
emit beginResetModel();
|
|
emit 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);
|
|
emit beginResetModel();
|
|
emit endResetModel();
|
|
return r;
|
|
}
|
|
};
|
|
|
|
class tst_QHeaderView : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
tst_QHeaderView();
|
|
|
|
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 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;
|
|
};
|
|
|
|
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 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"
|