qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,20 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qabstractitemview)
add_subdirectory(qdatawidgetmapper)
add_subdirectory(qfileiconprovider)
add_subdirectory(qheaderview)
add_subdirectory(qitemdelegate)
add_subdirectory(qitemeditorfactory)
add_subdirectory(qitemview)
add_subdirectory(qlistview)
add_subdirectory(qtableview)
add_subdirectory(qtablewidget)
add_subdirectory(qtreeview)
add_subdirectory(qtreewidget)
add_subdirectory(qtreewidgetitemiterator)
if(QT_FEATURE_private_tests)
add_subdirectory(qcolumnview)
add_subdirectory(qlistwidget)
endif()

View File

@ -0,0 +1,17 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qabstractitemview Test:
#####################################################################
qt_internal_add_test(tst_qabstractitemview
SOURCES
tst_qabstractitemview.cpp
LIBRARIES
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
# QTBUG-41341
[scrollTo]
macos

View File

@ -0,0 +1,19 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qcolumnview Test:
#####################################################################
qt_internal_add_test(tst_qcolumnview
SOURCES
../../../../shared/fakedirmodel.h
tst_qcolumnview.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

View File

@ -0,0 +1,966 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QColumnView>
#include <QScrollBar>
#include <QSignalSpy>
#include <QStringListModel>
#include <QStyledItemDelegate>
#include <QTest>
#include <QtTest/private/qtesthelpers_p.h>
#include <QtWidgets/private/qcolumnviewgrip_p.h>
#include "../../../../shared/fakedirmodel.h"
#define ANIMATION_DELAY 300
class tst_QColumnView : public QObject
{
Q_OBJECT
public:
tst_QColumnView();
private slots:
void initTestCase();
void init();
void rootIndex();
void grips();
void isIndexHidden();
void indexAt();
void scrollContentsBy_data();
void scrollContentsBy();
void scrollTo_data();
void scrollTo();
void moveCursor_data();
void moveCursor();
void selectAll();
void clicked();
void selectedColumns();
void setSelection();
void setSelectionModel();
void visualRegionForSelection();
void dynamicModelChanges();
// grip
void moveGrip_basic();
void moveGrip_data();
void moveGrip();
void doubleClick();
void gripMoved();
void preview();
void swapPreview();
void sizes();
void rowDelegate();
void resize();
void changeSameColumn();
void parentCurrentIndex_data();
void parentCurrentIndex();
void pullRug_data();
void pullRug();
protected slots:
void setPreviewWidget();
private:
QStandardItemModel m_fakeDirModel;
QModelIndex m_fakeDirHomeIndex;
};
class TreeModel : public QStandardItemModel
{
Q_OBJECT
public:
TreeModel()
{
for (int j = 0; j < 10; ++j) {
QStandardItem *parentItem = invisibleRootItem();
for (int i = 0; i < 10; ++i) {
const QString iS = QString::number(i);
const QString itemText = QLatin1String("item ") + iS;
QStandardItem *item = new QStandardItem(itemText);
parentItem->appendRow(item);
QStandardItem *item2 = new QStandardItem(itemText);
parentItem->appendRow(item2);
item2->appendRow(new QStandardItem(itemText));
parentItem->appendRow(new QStandardItem(QLatin1String("file ") + iS));
parentItem = item;
}
}
}
inline QModelIndex firstLevel() { return index(0, 0, QModelIndex()); }
inline QModelIndex secondLevel() { return index(0, 0, firstLevel()); }
inline QModelIndex thirdLevel() { return index(0, 0, secondLevel()); }
};
class ColumnView : public QColumnView
{
Q_OBJECT
public:
using QColumnView::QColumnView;
using QColumnView::horizontalOffset;
using QColumnView::clicked;
using QColumnView::isIndexHidden;
using QColumnView::moveCursor;
using QColumnView::scrollContentsBy;
using QColumnView::setSelection;
using QColumnView::visualRegionForSelection;
friend class tst_QColumnView;
QList<QPointer<QAbstractItemView>> createdColumns;
protected:
QAbstractItemView *createColumn(const QModelIndex &index) override
{
QAbstractItemView *view = QColumnView::createColumn(index);
QPointer<QAbstractItemView> savedView = view;
createdColumns.append(savedView);
return view;
}
};
tst_QColumnView::tst_QColumnView()
{
QStandardItem *homeItem = populateFakeDirModel(&m_fakeDirModel);
m_fakeDirHomeIndex = m_fakeDirModel.indexFromItem(homeItem);
}
void tst_QColumnView::initTestCase()
{
QVERIFY(m_fakeDirHomeIndex.isValid());
QVERIFY(m_fakeDirModel.rowCount(m_fakeDirHomeIndex) > 1); // Needs some entries in 'home'.
}
void tst_QColumnView::init()
{
QGuiApplication::setLayoutDirection(Qt::LeftToRight);
}
void tst_QColumnView::rootIndex()
{
ColumnView view;
// no model
view.setRootIndex(QModelIndex());
TreeModel model;
view.setModel(&model);
// A top level index
QModelIndex drive = model.firstLevel();
QVERIFY(view.visualRect(drive).isValid());
view.setRootIndex(QModelIndex());
QCOMPARE(view.horizontalOffset(), 0);
QCOMPARE(view.rootIndex(), QModelIndex());
QVERIFY(view.visualRect(drive).isValid());
// A item under the rootIndex exists
QModelIndex home = model.thirdLevel();
QModelIndex homeFile = model.index(0, 0, home);
int i = 0;
while (i < model.rowCount(home) - 1 && !model.hasChildren(homeFile))
homeFile = model.index(++i, 0, home);
view.setRootIndex(home);
QCOMPARE(view.horizontalOffset(), 0);
QCOMPARE(view.rootIndex(), home);
QVERIFY(!view.visualRect(drive).isValid());
QVERIFY(!view.visualRect(home).isValid());
if (homeFile.isValid())
QVERIFY(view.visualRect(homeFile).isValid());
// set root when there already is one and everything should still be ok
view.setRootIndex(home);
view.setCurrentIndex(homeFile);
view.scrollTo(model.index(0,0, homeFile));
QCOMPARE(view.horizontalOffset(), 0);
QCOMPARE(view.rootIndex(), home);
QVERIFY(!view.visualRect(drive).isValid());
QVERIFY(!view.visualRect(home).isValid());
if (homeFile.isValid())
QVERIFY(view.visualRect(homeFile).isValid());
//
homeFile = model.thirdLevel();
home = homeFile.parent();
view.setRootIndex(home);
view.setCurrentIndex(homeFile);
view.show();
i = 0;
QModelIndex two = model.index(0, 0, homeFile);
while (i < model.rowCount(homeFile) - 1 && !model.hasChildren(two))
two = model.index(++i, 0, homeFile);
QTest::qWait(ANIMATION_DELAY);
view.setCurrentIndex(two);
view.scrollTo(two);
QTest::qWait(ANIMATION_DELAY);
QVERIFY(two.isValid());
QVERIFY(view.horizontalOffset() != 0);
view.setRootIndex(homeFile);
QCOMPARE(view.horizontalOffset(), 0);
}
void tst_QColumnView::grips()
{
QColumnView view;
view.setModel(&m_fakeDirModel);
QCOMPARE(view.resizeGripsVisible(), true);
view.setResizeGripsVisible(true);
QCOMPARE(view.resizeGripsVisible(), true);
{
const QObjectList list = view.viewport()->children();
for (QObject *obj : list) {
if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(obj))
QVERIFY(view->cornerWidget() != nullptr);
}
}
view.setResizeGripsVisible(false);
QCOMPARE(view.resizeGripsVisible(), false);
{
const QObjectList list = view.viewport()->children();
for (QObject *obj : list) {
if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(obj)) {
if (view->isVisible())
QVERIFY(!view->cornerWidget());
}
}
}
view.setResizeGripsVisible(true);
QCOMPARE(view.resizeGripsVisible(), true);
}
void tst_QColumnView::isIndexHidden()
{
ColumnView view;
QModelIndex idx;
QCOMPARE(view.isIndexHidden(idx), false);
view.setModel(&m_fakeDirModel);
QCOMPARE(view.isIndexHidden(idx), false);
}
void tst_QColumnView::indexAt()
{
QColumnView view;
QCOMPARE(view.indexAt(QPoint(0,0)), QModelIndex());
view.setModel(&m_fakeDirModel);
QModelIndex homeFile = m_fakeDirModel.index(0, 0, m_fakeDirHomeIndex);
if (!homeFile.isValid())
return;
view.setRootIndex(m_fakeDirHomeIndex);
QRect rect = view.visualRect(QModelIndex());
QVERIFY(!rect.isValid());
rect = view.visualRect(homeFile);
QVERIFY(rect.isValid());
QModelIndex child;
for (int i = 0; i < m_fakeDirModel.rowCount(m_fakeDirHomeIndex); ++i) {
child = m_fakeDirModel.index(i, 0, m_fakeDirHomeIndex);
rect = view.visualRect(child);
QVERIFY(rect.isValid());
if (i > 0)
QVERIFY(rect.top() > 0);
QCOMPARE(view.indexAt(rect.center()), child);
view.selectionModel()->select(child, QItemSelectionModel::SelectCurrent);
view.setCurrentIndex(child);
QTest::qWait(200);
// test that the second row doesn't start at 0
if (m_fakeDirModel.rowCount(child) > 0) {
child = m_fakeDirModel.index(0, 0, child);
QVERIFY(child.isValid());
rect = view.visualRect(child);
QVERIFY(rect.isValid());
QVERIFY(rect.left() > 0);
QCOMPARE(view.indexAt(rect.center()), child);
break;
}
}
}
void tst_QColumnView::scrollContentsBy_data()
{
QTest::addColumn<bool>("reverse");
QTest::newRow("normal") << false;
QTest::newRow("reverse") << true;
}
void tst_QColumnView::scrollContentsBy()
{
QFETCH(bool, reverse);
ColumnView view;
if (reverse)
view.setLayoutDirection(Qt::RightToLeft);
view.scrollContentsBy(-1, -1);
view.scrollContentsBy(0, 0);
TreeModel model;
view.setModel(&model);
view.scrollContentsBy(0, 0);
QModelIndex home = model.thirdLevel();
view.setCurrentIndex(home);
QTest::qWait(ANIMATION_DELAY);
view.scrollContentsBy(0, 0);
}
void tst_QColumnView::scrollTo_data()
{
QTest::addColumn<bool>("reverse");
QTest::addColumn<bool>("giveFocus");
/// ### add test later for giveFocus == true
QTest::newRow("normal") << false << false;
QTest::newRow("reverse") << true << false;
}
void tst_QColumnView::scrollTo()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
QFETCH(bool, reverse);
QFETCH(bool, giveFocus);
QWidget topLevel;
if (reverse)
topLevel.setLayoutDirection(Qt::RightToLeft);
ColumnView view(&topLevel);
view.resize(200, 200);
topLevel.show();
topLevel.activateWindow();
QTestPrivate::centerOnScreen(&topLevel);
QVERIFY(QTest::qWaitForWindowActive(&topLevel));
view.scrollTo(QModelIndex(), QAbstractItemView::EnsureVisible);
QCOMPARE(view.horizontalOffset(), 0);
TreeModel model;
view.setModel(&model);
view.scrollTo(QModelIndex(), QAbstractItemView::EnsureVisible);
QModelIndex home;
home = model.index(0, 0, home);
home = model.index(0, 0, home);
home = model.index(0, 0, home);
view.scrollTo(home, QAbstractItemView::EnsureVisible);
view.setRootIndex(home);
QModelIndex index = model.index(0, 0, home);
view.scrollTo(index, QAbstractItemView::EnsureVisible);
QCOMPARE(view.horizontalOffset(), 0);
// Embedded requires that at least one widget have focus
QWidget w;
w.show();
QCOMPARE(view.horizontalOffset(), 0);
if (giveFocus)
view.setFocus(Qt::OtherFocusReason);
else
view.clearFocus();
QCOMPARE(view.horizontalOffset(), 0);
QCoreApplication::processEvents();
QCOMPARE(view.horizontalOffset(), 0);
QTRY_COMPARE(view.hasFocus(), giveFocus);
// scroll to the right
int level = 0;
int last = view.horizontalOffset();
while (model.hasChildren(index) && level < 5) {
view.setCurrentIndex(index);
QTest::qWait(ANIMATION_DELAY);
view.scrollTo(index, QAbstractItemView::EnsureVisible);
QTest::qWait(ANIMATION_DELAY);
index = model.index(0, 0, index);
level++;
if (level >= 2) {
if (!reverse) {
QTRY_VERIFY(view.horizontalOffset() < 0);
qDebug() << "last=" << last
<< " ; horizontalOffset= " << view.horizontalOffset();
QTRY_VERIFY(last > view.horizontalOffset());
} else {
QTRY_VERIFY(view.horizontalOffset() > 0);
QTRY_VERIFY(last < view.horizontalOffset());
}
}
last = view.horizontalOffset();
}
// scroll to the left
int start = level;
while(index.parent().isValid() && index != view.rootIndex()) {
view.setCurrentIndex(index);
QTest::qWait(ANIMATION_DELAY);
view.scrollTo(index, QAbstractItemView::EnsureVisible);
index = index.parent();
if (start != level) {
if (!reverse) {
QTRY_VERIFY(last < view.horizontalOffset());
} else {
if (last <= view.horizontalOffset()) {
qDebug() << "Test failure. last=" << last
<< " ; horizontalOffset= " << view.horizontalOffset();
}
QTRY_VERIFY(last > view.horizontalOffset());
}
}
level--;
last = view.horizontalOffset();
}
// It shouldn't automatically steal focus if it doesn't have it
QTRY_COMPARE(view.hasFocus(), giveFocus);
// Try scrolling to something that is above the root index
home = model.index(0, 0, QModelIndex());
QModelIndex temp = model.index(1, 0, home);
home = model.index(0, 0, home);
home = model.index(0, 0, home);
view.setRootIndex(home);
view.scrollTo(model.index(0, 0, home));
QTest::qWait(ANIMATION_DELAY);
view.scrollTo(temp);
}
void tst_QColumnView::moveCursor_data()
{
QTest::addColumn<bool>("reverse");
QTest::newRow("normal") << false;
QTest::newRow("reverse") << true;
}
void tst_QColumnView::moveCursor()
{
QFETCH(bool, reverse);
ColumnView view;
if (reverse)
view.setLayoutDirection(Qt::RightToLeft);
// don't crash
view.moveCursor(ColumnView::MoveUp, Qt::NoModifier);
// don't do anything
QCOMPARE(view.moveCursor(ColumnView::MoveEnd, Qt::NoModifier), QModelIndex());
view.setModel(&m_fakeDirModel);
QModelIndex ci = view.currentIndex();
QCOMPARE(view.moveCursor(ColumnView::MoveUp, Qt::NoModifier), QModelIndex());
QCOMPARE(view.moveCursor(ColumnView::MoveDown, Qt::NoModifier), QModelIndex());
// left at root
view.setCurrentIndex(m_fakeDirModel.index(0,0));
ColumnView::CursorAction action = reverse ? ColumnView::MoveRight : ColumnView::MoveLeft;
QCOMPARE(view.moveCursor(action, Qt::NoModifier), m_fakeDirModel.index(0,0));
// left shouldn't move up
int i = 0;
ci = m_fakeDirModel.index(0, 0);
while (i < m_fakeDirModel.rowCount() - 1 && !m_fakeDirModel.hasChildren(ci))
ci = m_fakeDirModel.index(++i, 0);
QVERIFY(m_fakeDirModel.hasChildren(ci));
view.setCurrentIndex(ci);
action = reverse ? ColumnView::MoveRight : ColumnView::MoveLeft;
QCOMPARE(view.moveCursor(action, Qt::NoModifier), ci);
// now move to the left (i.e. move over one column)
view.setCurrentIndex(m_fakeDirHomeIndex);
QCOMPARE(view.moveCursor(action, Qt::NoModifier), m_fakeDirHomeIndex.parent());
// right
action = reverse ? ColumnView::MoveLeft : ColumnView::MoveRight;
view.setCurrentIndex(ci);
QModelIndex mc = view.moveCursor(action, Qt::NoModifier);
QCOMPARE(mc, m_fakeDirModel.index(0,0, ci));
// for empty directories (no way to go 'right'), next one should move down
QModelIndex idx = m_fakeDirModel.index(0, 0, ci);
const int rowCount = m_fakeDirModel.rowCount(ci);
while (m_fakeDirModel.hasChildren(idx) && rowCount > idx.row() + 1)
idx = idx.sibling(idx.row() + 1, idx.column());
static const char error[] = "This test requires an empty directory followed by another directory.";
QVERIFY2(idx.isValid(), error);
QVERIFY2(!m_fakeDirModel.hasChildren(idx), error);
QVERIFY2(idx.row() + 1 < rowCount, error);
view.setCurrentIndex(idx);
mc = view.moveCursor(action, Qt::NoModifier);
QCOMPARE(mc, idx.sibling(idx.row() + 1, idx.column()));
}
void tst_QColumnView::selectAll()
{
ColumnView view;
view.selectAll();
view.setModel(&m_fakeDirModel);
view.selectAll();
QVERIFY(view.selectionModel()->selectedIndexes().size() >= 0);
view.setCurrentIndex(m_fakeDirHomeIndex);
view.selectAll();
QVERIFY(view.selectionModel()->selectedIndexes().size() > 0);
QModelIndex file;
for (int i = 0; i < m_fakeDirModel.rowCount(m_fakeDirHomeIndex); ++i) {
if (!m_fakeDirModel.hasChildren(m_fakeDirModel.index(i, 0, m_fakeDirHomeIndex))) {
file = m_fakeDirModel.index(i, 0, m_fakeDirHomeIndex);
break;
}
}
view.setCurrentIndex(file);
view.selectAll();
QVERIFY(view.selectionModel()->selectedIndexes().size() > 0);
view.setCurrentIndex(QModelIndex());
QCOMPARE(view.selectionModel()->selectedIndexes().size(), 0);
}
void tst_QColumnView::clicked()
{
ColumnView view;
view.setModel(&m_fakeDirModel);
view.resize(800, 300);
view.show();
view.setCurrentIndex(m_fakeDirHomeIndex);
QTest::qWait(ANIMATION_DELAY);
QModelIndex parent = m_fakeDirHomeIndex.parent();
QVERIFY(parent.isValid());
QSignalSpy clickedSpy(&view, &QAbstractItemView::clicked);
QPoint localPoint = view.visualRect(m_fakeDirHomeIndex).center();
QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, localPoint);
QCOMPARE(clickedSpy.size(), 1);
QCoreApplication::processEvents();
if (sizeof(qreal) != sizeof(double))
QSKIP("Skipped due to rounding errors");
for (int i = 0; i < view.createdColumns.size(); ++i) {
QAbstractItemView *column = view.createdColumns.at(i);
if (column && column->selectionModel() && (column->rootIndex() == m_fakeDirHomeIndex))
QVERIFY(column->selectionModel()->selectedIndexes().isEmpty());
}
}
void tst_QColumnView::selectedColumns()
{
ColumnView view;
view.setModel(&m_fakeDirModel);
view.resize(800,300);
view.show();
view.setCurrentIndex(m_fakeDirHomeIndex);
QTest::qWait(ANIMATION_DELAY);
for (int i = 0; i < view.createdColumns.size(); ++i) {
QAbstractItemView *column = view.createdColumns.at(i);
if (!column)
continue;
if (!column->rootIndex().isValid() || column->rootIndex() == m_fakeDirHomeIndex)
continue;
QTRY_VERIFY(column->currentIndex().isValid());
}
}
void tst_QColumnView::setSelection()
{
ColumnView view;
// shouldn't do anything, it falls to the columns to handle this
QRect r;
view.setSelection(r, QItemSelectionModel::NoUpdate);
}
void tst_QColumnView::setSelectionModel()
{
ColumnView view;
view.setModel(&m_fakeDirModel);
view.show();
view.setCurrentIndex(m_fakeDirHomeIndex);
QTest::qWait(ANIMATION_DELAY);
QItemSelectionModel *selectionModel = new QItemSelectionModel(&m_fakeDirModel);
view.setSelectionModel(selectionModel);
bool found = false;
for (int i = 0; i < view.createdColumns.size(); ++i) {
if (view.createdColumns.at(i)->selectionModel() == selectionModel) {
found = true;
break;
}
}
QVERIFY(found);
}
void tst_QColumnView::visualRegionForSelection()
{
ColumnView view;
QItemSelection emptyItemSelection;
QCOMPARE(QRegion(), view.visualRegionForSelection(emptyItemSelection));
// a region that isn't empty
view.setModel(&m_fakeDirModel);
QItemSelection itemSelection(m_fakeDirModel.index(0, 0, m_fakeDirHomeIndex), m_fakeDirModel.index(m_fakeDirModel.rowCount(m_fakeDirHomeIndex) - 1, 0, m_fakeDirHomeIndex));
QVERIFY(QRegion() != view.visualRegionForSelection(itemSelection));
}
void tst_QColumnView::moveGrip_basic()
{
QColumnView view;
QColumnViewGrip *grip = new QColumnViewGrip(&view);
QSignalSpy spy(grip, &QColumnViewGrip::gripMoved);
view.setCornerWidget(grip);
int oldX = view.width();
grip->moveGrip(10);
QCOMPARE(oldX + 10, view.width());
grip->moveGrip(-10);
QCOMPARE(oldX, view.width());
grip->moveGrip(-800);
QVERIFY(view.width() == 0 || view.width() == 1);
grip->moveGrip(800);
view.setMinimumWidth(200);
grip->moveGrip(-800);
QCOMPARE(view.width(), 200);
QCOMPARE(spy.size(), 5);
}
void tst_QColumnView::moveGrip_data()
{
QTest::addColumn<bool>("reverse");
QTest::newRow("normal") << false;
QTest::newRow("reverse") << true;
}
void tst_QColumnView::moveGrip()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
QFETCH(bool, reverse);
QWidget topLevel;
if (reverse)
topLevel.setLayoutDirection(Qt::RightToLeft);
ColumnView view(&topLevel);
TreeModel model;
view.setModel(&model);
QModelIndex home = model.thirdLevel();
view.setCurrentIndex(home);
view.resize(640, 200);
topLevel.show();
QVERIFY(QTest::qWaitForWindowActive(&topLevel));
int columnNum = view.createdColumns.size() - 2;
QVERIFY(columnNum >= 0);
const QObjectList list = view.createdColumns[columnNum]->children();
QColumnViewGrip *grip = nullptr;
for (QObject *obj : list) {
if ((grip = qobject_cast<QColumnViewGrip *>(obj)))
break;
}
if (!grip)
return;
QAbstractItemView *column = qobject_cast<QAbstractItemView *>(grip->parent());
int oldX = column->width();
QCOMPARE(view.columnWidths().value(columnNum), oldX);
grip->moveGrip(10);
QCOMPARE(view.columnWidths().value(columnNum), (oldX + (reverse ? -10 : 10)));
}
void tst_QColumnView::doubleClick()
{
QColumnView view;
QColumnViewGrip *grip = new QColumnViewGrip(&view);
QSignalSpy spy(grip, &QColumnViewGrip::gripMoved);
view.setCornerWidget(grip);
view.resize(200, 200);
QCOMPARE(view.width(), 200);
QTest::mouseDClick(grip, Qt::LeftButton);
QCOMPARE(view.width(), view.sizeHint().width());
QCOMPARE(spy.size(), 1);
}
void tst_QColumnView::gripMoved()
{
QColumnView view;
QColumnViewGrip *grip = new QColumnViewGrip(&view);
QSignalSpy spy(grip, &QColumnViewGrip::gripMoved);
view.setCornerWidget(grip);
view.move(300, 300);
view.resize(200, 200);
QCoreApplication::processEvents();
int oldWidth = view.width();
QTest::mousePress(grip, Qt::LeftButton, {}, QPoint(1, 1));
//QTest::mouseMove(grip, QPoint(grip->globalX()+50, y));
QPoint posNew = QPoint(grip->mapToGlobal(QPoint(1, 1)).x() + 65, 0);
QMouseEvent *event = new QMouseEvent(QEvent::MouseMove, posNew, posNew, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
QCoreApplication::postEvent(grip, event);
QCoreApplication::processEvents();
QTest::mouseRelease(grip, Qt::LeftButton);
QTRY_COMPARE(spy.size(), 1);
QCOMPARE(view.width(), oldWidth + 65);
}
void tst_QColumnView::preview()
{
QColumnView view;
QCOMPARE(view.previewWidget(), nullptr);
TreeModel model;
view.setModel(&model);
QCOMPARE(view.previewWidget(), nullptr);
QModelIndex home = model.index(0, 0);
QVERIFY(home.isValid());
QVERIFY(model.hasChildren(home));
view.setCurrentIndex(home);
QCOMPARE(view.previewWidget(), nullptr);
QModelIndex file;
QVERIFY(model.rowCount(home) > 0);
for (int i = 0; i < model.rowCount(home); ++i) {
if (!model.hasChildren(model.index(i, 0, home))) {
file = model.index(i, 0, home);
break;
}
}
QVERIFY(file.isValid());
view.setCurrentIndex(file);
QVERIFY(view.previewWidget() != nullptr);
QWidget *previewWidget = new QWidget(&view);
view.setPreviewWidget(previewWidget);
QCOMPARE(view.previewWidget(), previewWidget);
QVERIFY(previewWidget->parent() != &view);
view.setCurrentIndex(home);
// previewWidget should be marked for deletion
QWidget *previewWidget2 = new QWidget(&view);
view.setPreviewWidget(previewWidget2);
QCOMPARE(view.previewWidget(), previewWidget2);
}
void tst_QColumnView::swapPreview()
{
// swap the preview widget in updatePreviewWidget
QColumnView view;
QStringListModel model({ QLatin1String("test") });
view.setModel(&model);
view.setCurrentIndex(view.indexAt(QPoint(1, 1)));
connect(&view, &QColumnView::updatePreviewWidget,
this, &tst_QColumnView::setPreviewWidget);
view.setCurrentIndex(view.indexAt(QPoint(1, 1)));
QTest::qWait(ANIMATION_DELAY);
QCoreApplication::processEvents();
}
void tst_QColumnView::setPreviewWidget()
{
auto ptr = qobject_cast<QColumnView *>(sender());
QVERIFY(ptr);
ptr->setPreviewWidget(new QWidget);
}
void tst_QColumnView::sizes()
{
QColumnView view;
QCOMPARE(view.columnWidths().size(), 0);
const QList<int> newSizes{ 10, 4, 50, 6 };
QList<int> visibleSizes;
view.setColumnWidths(newSizes);
QCOMPARE(view.columnWidths(), visibleSizes);
view.setModel(&m_fakeDirModel);
view.setCurrentIndex(m_fakeDirHomeIndex);
QList<int> postSizes = view.columnWidths().mid(0, newSizes.size());
QCOMPARE(postSizes, newSizes.mid(0, postSizes.size()));
QVERIFY(view.columnWidths().size() > 1);
QList<int> smallerSizes{ 6 };
view.setColumnWidths(smallerSizes);
QList<int> expectedSizes = newSizes;
expectedSizes[0] = 6;
postSizes = view.columnWidths().mid(0, newSizes.size());
QCOMPARE(postSizes, expectedSizes.mid(0, postSizes.size()));
}
void tst_QColumnView::rowDelegate()
{
ColumnView view;
QStyledItemDelegate *d = new QStyledItemDelegate;
view.setItemDelegateForRow(3, d);
view.setModel(&m_fakeDirModel);
for (int i = 0; i < view.createdColumns.size(); ++i) {
QAbstractItemView *column = view.createdColumns.at(i);
QCOMPARE(column->itemDelegateForRow(3), d);
}
delete d;
}
void tst_QColumnView::resize()
{
QWidget topLevel;
ColumnView view(&topLevel);
view.setModel(&m_fakeDirModel);
view.resize(200, 200);
topLevel.show();
view.setCurrentIndex(m_fakeDirHomeIndex);
QTest::qWait(ANIMATION_DELAY);
view.resize(200, 300);
QTest::qWait(ANIMATION_DELAY);
QVERIFY(view.horizontalScrollBar()->maximum() != 0);
view.resize(view.horizontalScrollBar()->maximum() * 10, 300);
QTest::qWait(ANIMATION_DELAY);
QVERIFY(view.horizontalScrollBar()->maximum() <= 0);
}
void tst_QColumnView::changeSameColumn()
{
ColumnView view;
TreeModel model;
view.setModel(&model);
QModelIndex second;
QModelIndex home = model.secondLevel();
//index(QDir::homePath());
view.setCurrentIndex(home);
for (int i = 0; i < model.rowCount(home.parent()); ++i) {
QModelIndex idx = model.index(i, 0, home.parent());
if (model.hasChildren(idx) && idx != home) {
second = idx;
break;
}
}
QVERIFY(second.isValid());
const auto old = view.createdColumns;
view.setCurrentIndex(second);
QCOMPARE(old, view.createdColumns);
}
void tst_QColumnView::parentCurrentIndex_data()
{
QTest::addColumn<int>("firstRow");
QTest::addColumn<int>("secondRow");
QTest::newRow("down") << 0 << 1;
QTest::newRow("up") << 1 << 0;
}
void tst_QColumnView::parentCurrentIndex()
{
QFETCH(int, firstRow);
QFETCH(int, secondRow);
ColumnView view;
TreeModel model;
view.setModel(&model);
view.show();
QModelIndex first;
QModelIndex second;
QModelIndex third;
first = model.index(0, 0, QModelIndex());
second = model.index(firstRow, 0, first);
third = model.index(0, 0, second);
QVERIFY(first.isValid());
QVERIFY(second.isValid());
QVERIFY(third.isValid());
view.setCurrentIndex(third);
QTRY_COMPARE(view.createdColumns[0]->currentIndex(), first);
QTRY_COMPARE(view.createdColumns[1]->currentIndex(), second);
QTRY_COMPARE(view.createdColumns[2]->currentIndex(), third);
first = model.index(0, 0, QModelIndex());
second = model.index(secondRow, 0, first);
third = model.index(0, 0, second);
QVERIFY(first.isValid());
QVERIFY(second.isValid());
QVERIFY(third.isValid());
view.setCurrentIndex(third);
QTRY_COMPARE(view.createdColumns[0]->currentIndex(), first);
QTRY_COMPARE(view.createdColumns[1]->currentIndex(), second);
// The next two lines should be removed when QTBUG-22707 is resolved.
QEXPECT_FAIL("", "QTBUG-22707", Abort);
QVERIFY(view.createdColumns[2]);
QTRY_COMPARE(view.createdColumns[2]->currentIndex(), third);
}
void tst_QColumnView::pullRug_data()
{
QTest::addColumn<bool>("removeModel");
QTest::newRow("model") << true;
QTest::newRow("index") << false;
}
void tst_QColumnView::pullRug()
{
QFETCH(bool, removeModel);
ColumnView view;
TreeModel model;
view.setModel(&model);
QModelIndex home = model.thirdLevel();
view.setCurrentIndex(home);
if (removeModel)
view.setModel(nullptr);
else
view.setCurrentIndex(QModelIndex());
QTest::qWait(ANIMATION_DELAY);
// don't crash
}
void tst_QColumnView::dynamicModelChanges()
{
struct MyItemDelegate : public QStyledItemDelegate
{
void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const override
{
paintedIndexes += index;
QStyledItemDelegate::paint(painter, option, index);
}
mutable QSet<QModelIndex> paintedIndexes;
} delegate;
QStandardItemModel model;
ColumnView view;
view.setModel(&model);
view.setItemDelegate(&delegate);
QTestPrivate::centerOnScreen(&view);
view.show();
QStandardItem *item = new QStandardItem(QLatin1String("item"));
model.appendRow(item);
QVERIFY(QTest::qWaitForWindowExposed(&view)); //let the time for painting to occur
QTRY_COMPARE(delegate.paintedIndexes.size(), 1);
QCOMPARE(*delegate.paintedIndexes.begin(), model.index(0,0));
}
QTEST_MAIN(tst_QColumnView)
#include "tst_qcolumnview.moc"

View File

@ -0,0 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdatawidgetmapper Test:
#####################################################################
qt_internal_add_test(tst_qdatawidgetmapper
SOURCES
tst_qdatawidgetmapper.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
Qt::WidgetsPrivate
)

View File

@ -0,0 +1,458 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QComboBox>
#include <QDataWidgetMapper>
#include <QLineEdit>
#include <QMetaType>
#include <QStandardItemModel>
#include <QSignalSpy>
#include <QTest>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QtWidgets/private/qapplication_p.h>
class tst_QDataWidgetMapper: public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void setModel();
void navigate();
void addMapping();
void currentIndexChanged();
void changingValues();
void setData();
void mappedWidgetAt();
void comboBox();
void textEditDoesntChangeFocusOnTab_qtbug3305();
};
Q_DECLARE_METATYPE(QAbstractItemDelegate::EndEditHint)
static QStandardItemModel *testModel(QObject *parent)
{
QStandardItemModel *model = new QStandardItemModel(10, 10, parent);
for (int row = 0; row < 10; ++row) {
const QString prefix = QLatin1String("item ") + QString::number(row)
+ QLatin1Char(' ');
for (int col = 0; col < 10; ++col)
model->setData(model->index(row, col), prefix + QString::number(col));
}
return model;
}
void tst_QDataWidgetMapper::initTestCase()
{
qRegisterMetaType<QAbstractItemDelegate::EndEditHint>();
}
void tst_QDataWidgetMapper::setModel()
{
QDataWidgetMapper mapper;
QCOMPARE(mapper.model(), nullptr);
{ // let the model go out of scope firstma
QStandardItemModel model;
mapper.setModel(&model);
QCOMPARE(mapper.model(), &model);
}
QCOMPARE(mapper.model(), nullptr);
{ // let the mapper go out of scope first
QStandardItemModel model2;
QDataWidgetMapper mapper2;
mapper2.setModel(&model2);
}
}
void tst_QDataWidgetMapper::navigate()
{
QDataWidgetMapper mapper;
QAbstractItemModel *model = testModel(&mapper);
mapper.setModel(model);
QLineEdit edit1;
QLineEdit edit2;
QLineEdit edit3;
mapper.addMapping(&edit1, 0);
mapper.toFirst();
mapper.addMapping(&edit2, 1);
mapper.addMapping(&edit3, 2);
QCOMPARE(edit1.text(), QString("item 0 0"));
QVERIFY(edit2.text().isEmpty());
QVERIFY(edit3.text().isEmpty());
QVERIFY(mapper.submit());
edit2.setText(QString("item 0 1"));
edit3.setText(QString("item 0 2"));
QVERIFY(mapper.submit());
mapper.toFirst(); //this will repopulate
QCOMPARE(edit1.text(), QString("item 0 0"));
QCOMPARE(edit2.text(), QString("item 0 1"));
QCOMPARE(edit3.text(), QString("item 0 2"));
mapper.toFirst();
QCOMPARE(edit1.text(), QString("item 0 0"));
QCOMPARE(edit2.text(), QString("item 0 1"));
QCOMPARE(edit3.text(), QString("item 0 2"));
mapper.toPrevious(); // should do nothing
QCOMPARE(edit1.text(), QString("item 0 0"));
QCOMPARE(edit2.text(), QString("item 0 1"));
QCOMPARE(edit3.text(), QString("item 0 2"));
mapper.toNext();
QCOMPARE(edit1.text(), QString("item 1 0"));
QCOMPARE(edit2.text(), QString("item 1 1"));
QCOMPARE(edit3.text(), QString("item 1 2"));
mapper.toLast();
QCOMPARE(edit1.text(), QString("item 9 0"));
QCOMPARE(edit2.text(), QString("item 9 1"));
QCOMPARE(edit3.text(), QString("item 9 2"));
mapper.toNext(); // should do nothing
QCOMPARE(edit1.text(), QString("item 9 0"));
QCOMPARE(edit2.text(), QString("item 9 1"));
QCOMPARE(edit3.text(), QString("item 9 2"));
mapper.setCurrentIndex(4);
QCOMPARE(edit1.text(), QString("item 4 0"));
QCOMPARE(edit2.text(), QString("item 4 1"));
QCOMPARE(edit3.text(), QString("item 4 2"));
mapper.setCurrentIndex(-1); // should do nothing
QCOMPARE(edit1.text(), QString("item 4 0"));
QCOMPARE(edit2.text(), QString("item 4 1"));
QCOMPARE(edit3.text(), QString("item 4 2"));
mapper.setCurrentIndex(10); // should do nothing
QCOMPARE(edit1.text(), QString("item 4 0"));
QCOMPARE(edit2.text(), QString("item 4 1"));
QCOMPARE(edit3.text(), QString("item 4 2"));
mapper.setCurrentModelIndex(QModelIndex()); // should do nothing
QCOMPARE(edit1.text(), QString("item 4 0"));
QCOMPARE(edit2.text(), QString("item 4 1"));
QCOMPARE(edit3.text(), QString("item 4 2"));
mapper.setCurrentModelIndex(model->index(6, 0));
QCOMPARE(edit1.text(), QString("item 6 0"));
QCOMPARE(edit2.text(), QString("item 6 1"));
QCOMPARE(edit3.text(), QString("item 6 2"));
/* now try vertical navigation */
mapper.setOrientation(Qt::Vertical);
mapper.addMapping(&edit1, 0);
mapper.addMapping(&edit2, 1);
mapper.addMapping(&edit3, 2);
mapper.toFirst();
QCOMPARE(edit1.text(), QString("item 0 0"));
QCOMPARE(edit2.text(), QString("item 1 0"));
QCOMPARE(edit3.text(), QString("item 2 0"));
mapper.toPrevious(); // should do nothing
QCOMPARE(edit1.text(), QString("item 0 0"));
QCOMPARE(edit2.text(), QString("item 1 0"));
QCOMPARE(edit3.text(), QString("item 2 0"));
mapper.toNext();
QCOMPARE(edit1.text(), QString("item 0 1"));
QCOMPARE(edit2.text(), QString("item 1 1"));
QCOMPARE(edit3.text(), QString("item 2 1"));
mapper.toLast();
QCOMPARE(edit1.text(), QString("item 0 9"));
QCOMPARE(edit2.text(), QString("item 1 9"));
QCOMPARE(edit3.text(), QString("item 2 9"));
mapper.toNext(); // should do nothing
QCOMPARE(edit1.text(), QString("item 0 9"));
QCOMPARE(edit2.text(), QString("item 1 9"));
QCOMPARE(edit3.text(), QString("item 2 9"));
mapper.setCurrentIndex(4);
QCOMPARE(edit1.text(), QString("item 0 4"));
QCOMPARE(edit2.text(), QString("item 1 4"));
QCOMPARE(edit3.text(), QString("item 2 4"));
mapper.setCurrentIndex(-1); // should do nothing
QCOMPARE(edit1.text(), QString("item 0 4"));
QCOMPARE(edit2.text(), QString("item 1 4"));
QCOMPARE(edit3.text(), QString("item 2 4"));
mapper.setCurrentIndex(10); // should do nothing
QCOMPARE(edit1.text(), QString("item 0 4"));
QCOMPARE(edit2.text(), QString("item 1 4"));
QCOMPARE(edit3.text(), QString("item 2 4"));
mapper.setCurrentModelIndex(QModelIndex()); // should do nothing
QCOMPARE(edit1.text(), QString("item 0 4"));
QCOMPARE(edit2.text(), QString("item 1 4"));
QCOMPARE(edit3.text(), QString("item 2 4"));
mapper.setCurrentModelIndex(model->index(0, 6));
QCOMPARE(edit1.text(), QString("item 0 6"));
QCOMPARE(edit2.text(), QString("item 1 6"));
QCOMPARE(edit3.text(), QString("item 2 6"));
}
void tst_QDataWidgetMapper::addMapping()
{
QDataWidgetMapper mapper;
QAbstractItemModel *model = testModel(&mapper);
mapper.setModel(model);
QLineEdit edit1;
mapper.addMapping(&edit1, 0);
mapper.toFirst();
QCOMPARE(edit1.text(), QString("item 0 0"));
mapper.addMapping(&edit1, 1);
mapper.toFirst();
QCOMPARE(edit1.text(), QString("item 0 1"));
QCOMPARE(mapper.mappedSection(&edit1), 1);
edit1.clear();
mapper.removeMapping(&edit1);
mapper.toFirst();
QCOMPARE(edit1.text(), QString());
{
QLineEdit edit2;
mapper.addMapping(&edit2, 2);
mapper.toFirst();
QCOMPARE(edit2.text(), QString("item 0 2"));
} // let the edit go out of scope
QCOMPARE(mapper.mappedWidgetAt(2), nullptr);
mapper.toLast();
}
void tst_QDataWidgetMapper::currentIndexChanged()
{
QDataWidgetMapper mapper;
QAbstractItemModel *model = testModel(&mapper);
mapper.setModel(model);
QSignalSpy spy(&mapper, &QDataWidgetMapper::currentIndexChanged);
mapper.toFirst();
QCOMPARE(spy.size(), 1);
QCOMPARE(spy.takeFirst().at(0).toInt(), 0);
mapper.toNext();
QCOMPARE(spy.size(), 1);
QCOMPARE(spy.takeFirst().at(0).toInt(), 1);
mapper.setCurrentIndex(7);
QCOMPARE(spy.size(), 1);
QCOMPARE(spy.takeFirst().at(0).toInt(), 7);
mapper.setCurrentIndex(-1);
QCOMPARE(spy.size(), 0);
mapper.setCurrentIndex(42);
QCOMPARE(spy.size(), 0);
}
void tst_QDataWidgetMapper::changingValues()
{
QDataWidgetMapper mapper;
QAbstractItemModel *model = testModel(&mapper);
mapper.setModel(model);
QLineEdit edit1;
mapper.addMapping(&edit1, 0);
mapper.toFirst();
QCOMPARE(edit1.text(), QString("item 0 0"));
QLineEdit edit2;
mapper.addMapping(&edit2, 0, "text");
mapper.toFirst();
QCOMPARE(edit2.text(), QString("item 0 0"));
model->setData(model->index(0, 0), QString("changed"));
QCOMPARE(edit1.text(), QString("changed"));
QCOMPARE(edit2.text(), QString("changed"));
}
void tst_QDataWidgetMapper::setData()
{
QDataWidgetMapper mapper;
QAbstractItemModel *model = testModel(&mapper);
mapper.setModel(model);
QLineEdit edit1;
QLineEdit edit2;
QLineEdit edit3;
mapper.addMapping(&edit1, 0);
mapper.addMapping(&edit2, 1);
mapper.addMapping(&edit3, 0, "text");
mapper.toFirst();
QCOMPARE(edit1.text(), QString("item 0 0"));
QCOMPARE(edit2.text(), QString("item 0 1"));
QCOMPARE(edit3.text(), QString("item 0 0"));
edit1.setText("new text");
mapper.submit();
QCOMPARE(model->data(model->index(0, 0)).toString(), QString("new text"));
edit3.setText("more text");
mapper.submit();
QCOMPARE(model->data(model->index(0, 0)).toString(), QString("more text"));
}
void tst_QDataWidgetMapper::comboBox()
{
QDataWidgetMapper mapper;
QAbstractItemModel *model = testModel(&mapper);
mapper.setModel(model);
mapper.setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
QComboBox readOnlyBox;
readOnlyBox.setEditable(false);
readOnlyBox.addItem("read only item 0");
readOnlyBox.addItem("read only item 1");
readOnlyBox.addItem("read only item 2");
QComboBox readWriteBox;
readWriteBox.setEditable(true);
readWriteBox.addItem("read write item 0");
readWriteBox.addItem("read write item 1");
readWriteBox.addItem("read write item 2");
// populate the combo boxes with data
mapper.addMapping(&readOnlyBox, 0, "currentIndex");
mapper.addMapping(&readWriteBox, 1, "currentText");
mapper.toFirst();
// setCurrentIndex caused the value at index 0 to be displayed
QCOMPARE(readOnlyBox.currentText(), QString("read only item 0"));
// setCurrentText set the value in the line edit since the combobox is editable
QCOMPARE(readWriteBox.currentText(), QString("item 0 1"));
// set some new values on the boxes
readOnlyBox.setCurrentIndex(1);
readWriteBox.setEditText("read write item y");
mapper.submit();
// make sure the new values are in the model
QCOMPARE(model->data(model->index(0, 0)).toInt(), 1);
QCOMPARE(model->data(model->index(0, 1)).toString(), QString("read write item y"));
// now test updating of the widgets
model->setData(model->index(0, 0), 2, Qt::EditRole);
model->setData(model->index(0, 1), QString("read write item z"), Qt::EditRole);
QCOMPARE(readOnlyBox.currentIndex(), 2);
QCOMPARE(readWriteBox.currentText(), QString("read write item z"));
}
void tst_QDataWidgetMapper::mappedWidgetAt()
{
QDataWidgetMapper mapper;
QAbstractItemModel *model = testModel(&mapper);
mapper.setModel(model);
QLineEdit lineEdit1;
QLineEdit lineEdit2;
QCOMPARE(mapper.mappedWidgetAt(432312), nullptr);
mapper.addMapping(&lineEdit1, 1);
mapper.addMapping(&lineEdit2, 2);
QCOMPARE(mapper.mappedWidgetAt(1), &lineEdit1);
QCOMPARE(mapper.mappedWidgetAt(2), &lineEdit2);
mapper.addMapping(&lineEdit2, 4242);
QCOMPARE(mapper.mappedWidgetAt(2), nullptr);
QCOMPARE(mapper.mappedWidgetAt(4242), &lineEdit2);
}
void tst_QDataWidgetMapper::textEditDoesntChangeFocusOnTab_qtbug3305()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
QDataWidgetMapper mapper;
QAbstractItemModel *model = testModel(&mapper);
mapper.setModel(model);
QSignalSpy closeEditorSpy(mapper.itemDelegate(),
&QAbstractItemDelegate::closeEditor);
QVERIFY(closeEditorSpy.isValid());
QWidget container;
container.setLayout(new QVBoxLayout);
QLineEdit *lineEdit = new QLineEdit;
mapper.addMapping(lineEdit, 0);
container.layout()->addWidget(lineEdit);
QTextEdit *textEdit = new QTextEdit;
mapper.addMapping(textEdit, 1);
container.layout()->addWidget(textEdit);
lineEdit->setFocus();
container.show();
QApplicationPrivate::setActiveWindow(&container);
QVERIFY(QTest::qWaitForWindowActive(&container));
int closeEditorSpyCount = 0;
const QString textEditContents = textEdit->toPlainText();
QCOMPARE(closeEditorSpy.size(), closeEditorSpyCount);
QVERIFY(lineEdit->hasFocus());
QVERIFY(!textEdit->hasFocus());
// this will generate a closeEditor for the tab key, and another for the focus out
QTest::keyClick(QApplication::focusWidget(), Qt::Key_Tab);
closeEditorSpyCount += 2;
QTRY_COMPARE(closeEditorSpy.size(), closeEditorSpyCount);
QTRY_VERIFY(textEdit->hasFocus());
QVERIFY(!lineEdit->hasFocus());
// now that the text edit is focused, a tab keypress will insert a tab, not change focus
QTest::keyClick(QApplication::focusWidget(), Qt::Key_Tab);
QTRY_COMPARE(closeEditorSpy.size(), closeEditorSpyCount);
QVERIFY(!lineEdit->hasFocus());
QVERIFY(textEdit->hasFocus());
QCOMPARE(textEdit->toPlainText(), QLatin1Char('\t') + textEditContents);
// now give focus back to the line edit and check closeEditor gets emitted
lineEdit->setFocus();
QTRY_VERIFY(lineEdit->hasFocus());
QVERIFY(!textEdit->hasFocus());
++closeEditorSpyCount;
QCOMPARE(closeEditorSpy.size(), closeEditorSpyCount);
}
QTEST_MAIN(tst_QDataWidgetMapper)
#include "tst_qdatawidgetmapper.moc"

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qfileiconprovider Test:
#####################################################################
qt_internal_add_test(tst_qfileiconprovider
SOURCES
tst_qfileiconprovider.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
)

View File

@ -0,0 +1,119 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QFileIconProvider>
#include <QFileInfo>
#include <QTest>
class tst_QFileIconProvider : public QObject
{
Q_OBJECT
private slots:
void qfileiconprovider();
void iconType_data();
void iconType();
void iconInfo_data();
void iconInfo();
void type_data();
void type();
void iconPixmaps();
};
void tst_QFileIconProvider::qfileiconprovider()
{
// don't crash
QFileIconProvider provider;
}
Q_DECLARE_METATYPE(QFileIconProvider::IconType)
void tst_QFileIconProvider::iconType_data()
{
QTest::addColumn<QFileIconProvider::IconType>("type");
QTest::newRow("computer") << QFileIconProvider::Computer;
QTest::newRow("desktop") << QFileIconProvider::Desktop;
QTest::newRow("trashcan") << QFileIconProvider::Trashcan;
QTest::newRow("network") << QFileIconProvider::Network;
QTest::newRow("drive") << QFileIconProvider::Drive;
QTest::newRow("folder") << QFileIconProvider::Folder;
QTest::newRow("file") << QFileIconProvider::File;
}
// public QIcon icon(QFileIconProvider::IconType const& type) const
void tst_QFileIconProvider::iconType()
{
QFETCH(QFileIconProvider::IconType, type);
QFileIconProvider provider;
QVERIFY(!provider.icon(type).isNull());
}
void tst_QFileIconProvider::iconInfo_data()
{
QTest::addColumn<QFileInfo>("info");
QTest::addColumn<bool>("setPath");
QTest::newRow("null") << QFileInfo() << false;
QTest::newRow("drive") << QFileInfo(QDir::rootPath()) << true;
QTest::newRow("home") << QFileInfo(QDir::homePath()) << true;
QTest::newRow("current") << QFileInfo(QDir::currentPath()) << true;
}
// public QIcon icon(QFileInfo const& info) const
void tst_QFileIconProvider::iconInfo()
{
QFETCH(QFileInfo, info);
QFETCH(bool, setPath);
if (setPath)
QVERIFY(info.exists());
QFileIconProvider provider;
// we should always get an icon
QVERIFY(!provider.icon(info).isNull());
}
void tst_QFileIconProvider::type_data()
{
QTest::addColumn<QFileInfo>("info");
// Return value is _very_ system dependent, hard to test
// QTest::addColumn<QString>("type");
QTest::newRow("null") << QFileInfo();
QTest::newRow("drive") << QFileInfo(QDir::rootPath());
QTest::newRow("home") << QFileInfo(QDir::homePath());
QTest::newRow("current") << QFileInfo(QDir::currentPath());
QTest::newRow("exe") << QFileInfo(QCoreApplication::applicationFilePath());
}
// public QString type(QFileInfo const& info) const
void tst_QFileIconProvider::type()
{
QFETCH(QFileInfo, info);
QFileIconProvider provider;
QVERIFY(!provider.type(info).isEmpty());
}
static QIcon getIcon()
{
QFileIconProvider fip;
return fip.icon(QFileInfo(QDir::currentPath()));
}
void tst_QFileIconProvider::iconPixmaps()
{
const QIcon &icon = getIcon();
const auto sizes = icon.availableSizes();
for (const QSize &size : sizes) {
QPixmap pixmap = icon.pixmap(size);
QVERIFY(!pixmap.isNull());
}
}
QTEST_MAIN(tst_QFileIconProvider)
#include "tst_qfileiconprovider.moc"

View File

@ -0,0 +1,3 @@
# QTBUG-87406
[stretchAndRestoreLastSection]
android

View File

@ -0,0 +1,17 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qheaderview Test:
#####################################################################
qt_internal_add_test(tst_qheaderview
SOURCES
tst_qheaderview.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
[editorKeyPress]
ubuntu-20.04

View File

@ -0,0 +1,23 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qitemdelegate Test:
#####################################################################
qt_internal_add_test(tst_qitemdelegate
SOURCES
tst_qitemdelegate.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
Qt::WidgetsPrivate
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qitemdelegate CONDITION WIN32
LIBRARIES
user32
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qitemeditorfactory Test:
#####################################################################
qt_internal_add_test(tst_qitemeditorfactory
SOURCES
tst_qitemeditorfactory.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
)

View File

@ -0,0 +1,88 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QDoubleSpinBox>
#include <QItemEditorFactory>
#include <QTest>
class tst_QItemEditorFactory: public QObject
{
Q_OBJECT
private slots:
void createEditor();
void createCustomEditor();
void uintValues();
};
void tst_QItemEditorFactory::createEditor()
{
const QItemEditorFactory *factory = QItemEditorFactory::defaultFactory();
QWidget parent;
QWidget *w = factory->createEditor(QMetaType::QString, &parent);
QCOMPARE(w->metaObject()->className(), "QExpandingLineEdit");
}
//we make it inherit from QObject so that we can use QPointer
class MyEditor : public QObject, public QStandardItemEditorCreator<QDoubleSpinBox>
{
};
void tst_QItemEditorFactory::createCustomEditor()
{
QPointer<MyEditor> creator = new MyEditor;
QPointer<MyEditor> creator2 = new MyEditor;
{
QItemEditorFactory editorFactory;
editorFactory.registerEditor(QMetaType::QRect, creator);
editorFactory.registerEditor(QMetaType::QRectF, creator);
//creator should not be deleted as a result of calling the next line
editorFactory.registerEditor(QMetaType::QRect, creator2);
QVERIFY(creator);
//this should erase creator2
editorFactory.registerEditor(QMetaType::QRect, creator);
QVERIFY(creator2.isNull());
QWidget parent;
QWidget *w = editorFactory.createEditor(QMetaType::QRect, &parent);
QCOMPARE(w->metaObject()->className(), "QDoubleSpinBox");
QCOMPARE(w->metaObject()->userProperty().userType(), QMetaType::Double);
}
//editorFactory has been deleted, so should be creator
//because editorFActory has the ownership
QVERIFY(creator.isNull());
QVERIFY(creator2.isNull());
delete creator;
}
void tst_QItemEditorFactory::uintValues()
{
QItemEditorFactory editorFactory;
QWidget parent;
{
QWidget *editor = editorFactory.createEditor(QMetaType::UInt, &parent);
QCOMPARE(editor->metaObject()->className(), "QUIntSpinBox");
QCOMPARE(editor->metaObject()->userProperty().userType(), QMetaType::UInt);
}
{
QWidget *editor = editorFactory.createEditor(QMetaType::Int, &parent);
QCOMPARE(editor->metaObject()->className(), "QSpinBox");
QCOMPARE(editor->metaObject()->userProperty().userType(), QMetaType::Int);
}
}
QTEST_MAIN(tst_QItemEditorFactory)
#include "tst_qitemeditorfactory.moc"

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qitemview Test:
#####################################################################
qt_internal_add_test(tst_qitemview
SOURCES
tst_qitemview.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
)

View File

@ -0,0 +1,804 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QRandomGenerator>
#include <QStack>
#include <QStandardItemModel>
#include <QTest>
#include "viewstotest.cpp"
/*!
See viewstotest.cpp for instructions on how to have your view tested with these tests.
Each test such as visualRect have a _data() function which populate the QTest data with
tests specified by viewstotest.cpp and any extra data needed for that particular test.
setupWithNoTestData() fills QTest data with only the tests it is used by most tests.
There are some basic qDebug statements sprikled about that might be helpfull for
fixing your issues.
*/
class tst_QItemView : public QObject
{
Q_OBJECT
private slots:
void init();
void cleanup();
void nonDestructiveBasicTest_data();
void nonDestructiveBasicTest();
void spider_data();
void spider();
void resize_data();
void resize();
void visualRect_data();
void visualRect();
void indexAt_data();
void indexAt();
void scrollTo_data();
void scrollTo();
void moveCursor_data();
void moveCursor();
private:
void setupWithNoTestData();
void populate();
void walkScreen(QAbstractItemView *view);
QAbstractItemView *view;
QAbstractItemModel *treeModel;
ViewsToTest *testViews;
};
/*!
* Views should not make invalid requests, sense a model might not check all the bad cases.
*/
class CheckerModel : public QStandardItemModel
{
Q_OBJECT
public:
using QStandardItemModel::QStandardItemModel;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
{
if (!index.isValid()) {
qWarning("%s: index is not valid", Q_FUNC_INFO);
return QVariant();
}
return QStandardItemModel::data(index, role);
}
Qt::ItemFlags flags(const QModelIndex &index) const override
{
if (!index.isValid()) {
qWarning("%s: index is not valid", Q_FUNC_INFO);
return Qt::ItemFlags();
}
if (index.row() == 2 || index.row() == rowCount() - 3
|| index.column() == 2 || index.column() == columnCount() - 3) {
Qt::ItemFlags f = QStandardItemModel::flags(index);
f.setFlag(Qt::ItemIsEnabled, false);
return f;
}
return QStandardItemModel::flags(index);
}
QModelIndex parent(const QModelIndex &child) const override
{
if (!child.isValid()) {
qWarning("%s: child index is not valid", Q_FUNC_INFO);
return QModelIndex();
}
return QStandardItemModel::parent(child);
}
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override
{
if (orientation == Qt::Horizontal
&& (section < 0 || section > columnCount())) {
qWarning("%s: invalid section %d, must be in range 0..%d",
Q_FUNC_INFO, section, columnCount());
return QVariant();
}
if (orientation == Qt::Vertical
&& (section < 0 || section > rowCount())) {
qWarning("%s: invalid section %d, must be in range 0..%d",
Q_FUNC_INFO, section, rowCount());
return QVariant();
}
return QStandardItemModel::headerData(section, orientation, role);
}
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) override
{
if (!index.isValid()) {
qWarning("%s: index is not valid", Q_FUNC_INFO);
return false;
}
return QStandardItemModel::setData(index, value, role);
}
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override
{
if (column < 0 || column > columnCount())
qWarning("%s: invalid column %d, must be in range 0..%d",
Q_FUNC_INFO, column, columnCount());
else
QStandardItemModel::sort(column, order);
}
QModelIndexList match(const QModelIndex &start, int role,
const QVariant &value, int hits = 1,
Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override
{
if (hits <= 0) {
qWarning("%s: hits must be greater than zero", Q_FUNC_INFO);
return QModelIndexList();
}
if (!value.isValid()) {
qWarning("%s: value is not valid", Q_FUNC_INFO);
return QModelIndexList();
}
return QAbstractItemModel::match(start, role, value, hits, flags);
}
bool setHeaderData(int section, Qt::Orientation orientation,
const QVariant &value, int role = Qt::EditRole) override
{
if (orientation == Qt::Horizontal
&& (section < 0 || section > columnCount())) {
qWarning("%s: invalid section %d, must be in range 0..%d",
Q_FUNC_INFO, section, columnCount());
return false;
}
if (orientation == Qt::Vertical
&& (section < 0 || section > rowCount())) {
qWarning("%s: invalid section %d, must be in range 0..%d",
Q_FUNC_INFO, section, rowCount());
return false;
}
return QAbstractItemModel::setHeaderData(section, orientation, value, role);
}
};
void tst_QItemView::init()
{
testViews = new ViewsToTest();
populate();
}
void tst_QItemView::cleanup()
{
delete testViews;
delete view;
delete treeModel;
view = nullptr;
testViews = nullptr;
treeModel = nullptr;
}
void tst_QItemView::setupWithNoTestData()
{
ViewsToTest testViews;
QTest::addColumn<QString>("viewType");
QTest::addColumn<bool>("displays");
QTest::addColumn<QAbstractItemView::ScrollMode>("vscroll");
QTest::addColumn<QAbstractItemView::ScrollMode>("hscroll");
for (int i = 0; i < testViews.tests.size(); ++i) {
QString view = testViews.tests.at(i).viewType;
QString test = view + " ScrollPerPixel";
bool displayIndexes = (testViews.tests.at(i).display == ViewsToTest::DisplayRoot);
QTest::newRow(test.toLatin1().data()) << view << displayIndexes
<< QAbstractItemView::ScrollPerPixel
<< QAbstractItemView::ScrollPerPixel
;
}
for (int i = 0; i < testViews.tests.size(); ++i) {
QString view = testViews.tests.at(i).viewType;
QString test = view + " ScrollPerItem";
bool displayIndexes = (testViews.tests.at(i).display == ViewsToTest::DisplayRoot);
QTest::newRow(test.toLatin1().data()) << view << displayIndexes
<< QAbstractItemView::ScrollPerItem
<< QAbstractItemView::ScrollPerItem
;
}
}
void tst_QItemView::populate()
{
treeModel = new CheckerModel;
QModelIndex parent;
#if defined(Q_PROCESSOR_ARM)
const int baseInsert = 4;
#else
const int baseInsert = 26;
#endif
for (int i = 0; i < 40; ++i) {
const QString iS = QString::number(i);
parent = treeModel->index(0, 0, parent);
treeModel->insertRows(0, baseInsert + i, parent);
treeModel->insertColumns(0, baseInsert + i, parent);
// Fill in some values to make it easier to debug
for (int x = 0; x < treeModel->rowCount(); ++x) {
const QString xS = QString::number(x);
for (int y = 0; y < treeModel->columnCount(); ++y) {
QModelIndex index = treeModel->index(x, y, parent);
treeModel->setData(index, xS + QLatin1Char('_') + QString::number(y) + QLatin1Char('_') + iS);
treeModel->setData(index, QVariant(QColor(Qt::blue)), Qt::ForegroundRole);
}
}
}
}
void tst_QItemView::nonDestructiveBasicTest_data()
{
setupWithNoTestData();
}
/*!
nonDestructiveBasicTest tries to call a number of the basic functions (not all)
to make sure the view doesn't segfault, testing the functions that makes sense.
*/
void tst_QItemView::nonDestructiveBasicTest()
{
QFETCH(QString, viewType);
QFETCH(QAbstractItemView::ScrollMode, vscroll);
QFETCH(QAbstractItemView::ScrollMode, hscroll);
view = testViews->createView(viewType);
QVERIFY(view);
view->setVerticalScrollMode(vscroll);
view->setHorizontalScrollMode(hscroll);
// setSelectionModel() will assert
//view->setSelectionModel(0);
// setItemDelegate() will assert
//view->setItemDelegate(0);
// setSelectionMode
view->setSelectionMode(QAbstractItemView::SingleSelection);
QCOMPARE(view->selectionMode(), QAbstractItemView::SingleSelection);
view->setSelectionMode(QAbstractItemView::ContiguousSelection);
QCOMPARE(view->selectionMode(), QAbstractItemView::ContiguousSelection);
view->setSelectionMode(QAbstractItemView::ExtendedSelection);
QCOMPARE(view->selectionMode(), QAbstractItemView::ExtendedSelection);
view->setSelectionMode(QAbstractItemView::MultiSelection);
QCOMPARE(view->selectionMode(), QAbstractItemView::MultiSelection);
view->setSelectionMode(QAbstractItemView::NoSelection);
QCOMPARE(view->selectionMode(), QAbstractItemView::NoSelection);
// setSelectionBehavior
view->setSelectionBehavior(QAbstractItemView::SelectItems);
QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectItems);
view->setSelectionBehavior(QAbstractItemView::SelectRows);
QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectRows);
view->setSelectionBehavior(QAbstractItemView::SelectColumns);
QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectColumns);
// setEditTriggers
view->setEditTriggers(QAbstractItemView::EditKeyPressed);
QCOMPARE(view->editTriggers(), QAbstractItemView::EditKeyPressed);
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
QCOMPARE(view->editTriggers(), QAbstractItemView::NoEditTriggers);
view->setEditTriggers(QAbstractItemView::CurrentChanged);
QCOMPARE(view->editTriggers(), QAbstractItemView::CurrentChanged);
view->setEditTriggers(QAbstractItemView::DoubleClicked);
QCOMPARE(view->editTriggers(), QAbstractItemView::DoubleClicked);
view->setEditTriggers(QAbstractItemView::SelectedClicked);
QCOMPARE(view->editTriggers(), QAbstractItemView::SelectedClicked);
view->setEditTriggers(QAbstractItemView::AnyKeyPressed);
QCOMPARE(view->editTriggers(), QAbstractItemView::AnyKeyPressed);
view->setEditTriggers(QAbstractItemView::AllEditTriggers);
QCOMPARE(view->editTriggers(), QAbstractItemView::AllEditTriggers);
// setAutoScroll
view->setAutoScroll(false);
QCOMPARE(view->hasAutoScroll(), false);
view->setAutoScroll(true);
QCOMPARE(view->hasAutoScroll(), true);
// setTabKeyNavigation
view->setTabKeyNavigation(false);
QCOMPARE(view->tabKeyNavigation(), false);
view->setTabKeyNavigation(true);
QCOMPARE(view->tabKeyNavigation(), true);
#if QT_CONFIG(draganddrop)
// setDropIndicatorShown
view->setDropIndicatorShown(false);
QCOMPARE(view->showDropIndicator(), false);
view->setDropIndicatorShown(true);
QCOMPARE(view->showDropIndicator(), true);
// setDragEnabled
view->setDragEnabled(false);
QCOMPARE(view->dragEnabled(), false);
view->setDragEnabled(true);
QCOMPARE(view->dragEnabled(), true);
#endif
// setAlternatingRowColors
view->setAlternatingRowColors(false);
QCOMPARE(view->alternatingRowColors(), false);
view->setAlternatingRowColors(true);
QCOMPARE(view->alternatingRowColors(), true);
// setIconSize
view->setIconSize(QSize(16, 16));
QCOMPARE(view->iconSize(), QSize(16, 16));
view->setIconSize(QSize(32, 32));
QCOMPARE(view->iconSize(), QSize(32, 32));
// Should this happen?
view->setIconSize(QSize(-1, -1));
QCOMPARE(view->iconSize(), QSize(-1, -1));
QCOMPARE(view->currentIndex(), QModelIndex());
QCOMPARE(view->rootIndex(), QModelIndex());
view->keyboardSearch("");
view->keyboardSearch("foo");
view->keyboardSearch("1");
QCOMPARE(view->visualRect(QModelIndex()), QRect());
view->scrollTo(QModelIndex());
QCOMPARE(view->sizeHintForIndex(QModelIndex()), QSize());
QCOMPARE(view->indexAt(QPoint(-1, -1)), QModelIndex());
if (!view->model()){
QCOMPARE(view->indexAt(QPoint(10, 10)), QModelIndex());
QCOMPARE(view->sizeHintForRow(0), -1);
QCOMPARE(view->sizeHintForColumn(0), -1);
} else if (view->itemDelegate()){
view->sizeHintForRow(0);
view->sizeHintForColumn(0);
}
view->openPersistentEditor(QModelIndex());
view->closePersistentEditor(QModelIndex());
view->reset();
view->setRootIndex(QModelIndex());
view->doItemsLayout();
view->selectAll();
// edit() causes warning by default
//view->edit(QModelIndex());
view->clearSelection();
view->setCurrentIndex(QModelIndex());
}
void tst_QItemView::spider_data()
{
setupWithNoTestData();
}
void touch(QWidget *widget, Qt::KeyboardModifier modifier, Qt::Key keyPress)
{
int width = widget->width();
int height = widget->height();
for (int i = 0; i < 5; ++i) {
QTest::mouseClick(widget, Qt::LeftButton, modifier,
QPoint(QRandomGenerator::global()->bounded(width), QRandomGenerator::global()->bounded(height)));
QTest::mouseDClick(widget, Qt::LeftButton, modifier,
QPoint(QRandomGenerator::global()->bounded(width), QRandomGenerator::global()->bounded(height)));
QPoint press(QRandomGenerator::global()->bounded(width), QRandomGenerator::global()->bounded(height));
QPoint releasePoint(QRandomGenerator::global()->bounded(width), QRandomGenerator::global()->bounded(height));
QTest::mousePress(widget, Qt::LeftButton, modifier, press);
QTest::mouseMove(widget, releasePoint);
if (QRandomGenerator::global()->bounded(1) == 0)
QTest::mouseRelease(widget, Qt::LeftButton, {}, releasePoint);
else
QTest::mouseRelease(widget, Qt::LeftButton, modifier, releasePoint);
QTest::keyClick(widget, keyPress);
}
}
/*!
This is a basic stress testing application that tries a few basics such as clicking around
the screen, and key presses.
The main goal is to catch any easy segfaults, not to test every case.
*/
void tst_QItemView::spider()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
QFETCH(QString, viewType);
QFETCH(QAbstractItemView::ScrollMode, vscroll);
QFETCH(QAbstractItemView::ScrollMode, hscroll);
view = testViews->createView(viewType);
QVERIFY(view);
view->setVerticalScrollMode(vscroll);
view->setHorizontalScrollMode(hscroll);
view->setModel(treeModel);
view->show();
QVERIFY(QTest::qWaitForWindowActive(view));
touch(view->viewport(), Qt::NoModifier, Qt::Key_Left);
touch(view->viewport(), Qt::ShiftModifier, Qt::Key_Enter);
touch(view->viewport(), Qt::ControlModifier, Qt::Key_Backspace);
touch(view->viewport(), Qt::AltModifier, Qt::Key_Up);
}
void tst_QItemView::resize_data()
{
setupWithNoTestData();
}
/*!
The main goal is to catch any infinite loops from layouting
*/
void tst_QItemView::resize()
{
QSKIP("This test needs to be re-thought out, it takes too long and doesn't really catch the problem.");
QFETCH(QString, viewType);
QFETCH(QAbstractItemView::ScrollMode, vscroll);
QFETCH(QAbstractItemView::ScrollMode, hscroll);
view = testViews->createView(viewType);
QVERIFY(view);
view->setVerticalScrollMode(vscroll);
view->setHorizontalScrollMode(hscroll);
view->setModel(treeModel);
view->show();
for (int w = 100; w < 400; w += 10) {
for (int h = 100; h < 400; h += 10) {
view->resize(w, h);
QTest::qWait(1);
QCoreApplication::processEvents();
}
}
}
void tst_QItemView::visualRect_data()
{
setupWithNoTestData();
}
void tst_QItemView::visualRect()
{
QFETCH(QString, viewType);
QFETCH(QAbstractItemView::ScrollMode, vscroll);
QFETCH(QAbstractItemView::ScrollMode, hscroll);
view = testViews->createView(viewType);
QVERIFY(view);
view->setVerticalScrollMode(vscroll);
view->setHorizontalScrollMode(hscroll);
QCOMPARE(view->visualRect(QModelIndex()), QRect());
// Add model
view->setModel(treeModel);
QCOMPARE(view->visualRect(QModelIndex()), QRect());
QModelIndex topIndex = treeModel->index(0,0);
QFETCH(bool, displays);
if (!displays){
QCOMPARE(view->visualRect(topIndex), QRect());
return;
}
QVERIFY(view->visualRect(topIndex) != QRect());
view->show();
QVERIFY(view->visualRect(topIndex) != QRect());
QCOMPARE(topIndex, view->indexAt(view->visualRect(topIndex).center()));
QCOMPARE(topIndex, view->indexAt(view->visualRect(topIndex).bottomLeft()));
QCOMPARE(topIndex, view->indexAt(view->visualRect(topIndex).bottomRight()));
QCOMPARE(topIndex, view->indexAt(view->visualRect(topIndex).topLeft()));
QCOMPARE(topIndex, view->indexAt(view->visualRect(topIndex).topRight()));
testViews->hideIndexes(view);
QModelIndex hiddenIndex = treeModel->index(1, 0);
QCOMPARE(view->visualRect(hiddenIndex), QRect());
}
void tst_QItemView::walkScreen(QAbstractItemView *view)
{
QModelIndex hiddenIndex = view->model() ? view->model()->index(1, 0) : QModelIndex();
int width = view->width();
int height = view->height();
for (int w = 0; w < width; ++w)
{
for (int h = 0; h < height; ++h)
{
QPoint point(w, h);
QModelIndex index = view->indexAt(point);
// If we have no model then we should *never* get a valid index
if (!view->model() || !view->isVisible())
QVERIFY(!index.isValid());
// index should not be the hidden one
if (hiddenIndex.isValid())
QVERIFY(hiddenIndex != index);
// If we are valid then check the visualRect for that index
if (index.isValid()){
QRect visualRect = view->visualRect(index);
if (!visualRect.contains(point))
qDebug() << point << visualRect;
QVERIFY(visualRect.contains(point));
}
}
}
}
void walkIndex(const QModelIndex &index, const QAbstractItemView *view)
{
const QRect visualRect = view->visualRect(index);
const int width = visualRect.width();
const int height = visualRect.height();
if (width == 0 || height == 0)
return;
const auto widths = (width < 2) ? QList<int>({ 0, 1 })
: QList<int>({ 0, 1, width / 2, width - 2, width - 1 });
const auto heights = (height < 2) ? QList<int>({ 0, 1 })
: QList<int>({ 0, 1, height / 2, height - 2, height - 1 });
for (int w : widths)
{
for (int h : heights)
{
const QPoint point(visualRect.x() + w, visualRect.y() + h);
const auto idxAt = view->indexAt(point);
if (idxAt != index)
qDebug() << "index" << index << "visualRect" << visualRect << point << view->indexAt(point);
QCOMPARE(idxAt, index);
}
}
}
/*!
A model that returns an index of parent X should also return X when asking
for the parent of the index.
This recursive function does pretty extensive testing on the whole model in an
effort to catch edge cases.
This function assumes that rowCount(), columnCount() and index() work. If they have
a bug it will point it out, but the above tests should have already found the basic bugs
because it is easier to figure out the problem in those tests then this one.
*/
void checkChildren(const QAbstractItemView *currentView, const QModelIndex &parent = QModelIndex(), int currentDepth = 0)
{
QAbstractItemModel *currentModel = currentView->model();
int rows = currentModel->rowCount(parent);
int columns = currentModel->columnCount(parent);
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < columns; ++c) {
QModelIndex index = currentModel->index(r, c, parent);
walkIndex(index, currentView);
if (QTest::currentTestFailed())
return;
// recursivly go down
if (currentModel->hasChildren(index) && currentDepth < 2) {
checkChildren(currentView, index, ++currentDepth);
// Because this is recursive we will return at the first failure rather then
// reporting it over and over
if (QTest::currentTestFailed())
return;
}
}
}
}
void tst_QItemView::indexAt_data()
{
setupWithNoTestData();
}
void tst_QItemView::indexAt()
{
QFETCH(QString, viewType);
QFETCH(QAbstractItemView::ScrollMode, vscroll);
QFETCH(QAbstractItemView::ScrollMode, hscroll);
view = testViews->createView(viewType);
QVERIFY(view);
view->setVerticalScrollMode(vscroll);
view->setHorizontalScrollMode(hscroll);
view->show();
view->setModel(treeModel);
checkChildren(view);
QModelIndex index = view->model()->index(0, 0);
while (view->model()->hasChildren(index))
index = view->model()->index(0, 0, index);
QCOMPARE(view->model()->hasChildren(index), false);
QVERIFY(index.isValid());
view->setRootIndex(index);
//qDebug() << view->indexAt(QPoint(view->width()/2, view->height()/2)) << view->rootIndex();
QPoint p(1, view->height()/2);
QModelIndex idx = view->indexAt(p);
QCOMPARE(idx, QModelIndex());
}
void tst_QItemView::scrollTo_data()
{
setupWithNoTestData();
}
void tst_QItemView::scrollTo()
{
QFETCH(QString, viewType);
QFETCH(QAbstractItemView::ScrollMode, vscroll);
QFETCH(QAbstractItemView::ScrollMode, hscroll);
view = testViews->createView(viewType);
QVERIFY(view);
view->setVerticalScrollMode(vscroll);
view->setHorizontalScrollMode(hscroll);
view->setModel(treeModel);
view->show();
QModelIndex parent;
for (int row = 0; row < treeModel->rowCount(parent); ++row) {
for (int column = 0; column < treeModel->columnCount(parent); ++column) {
QModelIndex idx = treeModel->index(row, column, parent);
view->scrollTo(idx);
QRect rect = view->visualRect(idx);
view->scrollTo(idx);
QCOMPARE(rect, view->visualRect(idx));
}
}
QModelIndex idx = treeModel->index(0, 0, parent);
view->scrollTo(idx);
QRect rect = view->visualRect(idx);
view->scrollToBottom();
view->scrollTo(idx);
QCOMPARE(rect, view->visualRect(idx));
}
void tst_QItemView::moveCursor_data()
{
setupWithNoTestData();
}
struct Event
{
Event(Qt::Key k, const QModelIndex &s, const QModelIndex &e, const QString &n)
: key(k), start(s), end(e), name(n){}
Qt::Key key;
QModelIndex start;
QModelIndex end;
QString name;
};
void tst_QItemView::moveCursor()
{
QFETCH(QString, viewType);
view = testViews->createView(viewType);
QVERIFY(view);
if (view->objectName() == "QHeaderView")
return;
view->setModel(treeModel);
testViews->hideIndexes(view);
view->resize(100, 100);
QModelIndex invalidIndex = QModelIndex();
QModelIndex firstRow = treeModel->index(0, 0);
QModelIndex hiddenRowT = treeModel->index(1, 0);
QModelIndex disabledRowT = treeModel->index(2, 0);
QModelIndex secondRow = treeModel->index(3, 0);
QModelIndex secondToLastRow = treeModel->index(treeModel->rowCount() - 4, 0);
QModelIndex disabledRowB = treeModel->index(treeModel->rowCount() - 3, 0);
QModelIndex hiddenRowB = treeModel->index(treeModel->rowCount() - 2, 0);
QModelIndex lastRow = treeModel->index(treeModel->rowCount() - 1, 0);
QStack<Event> events;
events.push(Event(Qt::Key_Up, invalidIndex, firstRow, "inv, first"));
events.push(Event(Qt::Key_Up, hiddenRowT, firstRow, "hid, first"));
events.push(Event(Qt::Key_Up, disabledRowT, firstRow, "dis, first"));
events.push(Event(Qt::Key_Up, firstRow, firstRow, "first, first"));
events.push(Event(Qt::Key_Up, secondRow, firstRow, "sec, first"));
events.push(Event(Qt::Key_Up, hiddenRowB, firstRow, "hidB, first"));
events.push(Event(Qt::Key_Up, disabledRowB, secondToLastRow, "disB, secLast"));
events.push(Event(Qt::Key_Up, lastRow, secondToLastRow, "last, secLast"));
events.push(Event(Qt::Key_Down, invalidIndex, firstRow, "inv, first"));
events.push(Event(Qt::Key_Down, hiddenRowT, firstRow, "hid, first"));
events.push(Event(Qt::Key_Down, disabledRowT, secondRow, "dis, sec"));
events.push(Event(Qt::Key_Down, firstRow, secondRow, "first, sec"));
events.push(Event(Qt::Key_Down, secondToLastRow, lastRow, "secLast, last" ));
events.push(Event(Qt::Key_Down, disabledRowB, lastRow, "disB, last"));
events.push(Event(Qt::Key_Down, hiddenRowB, firstRow, "hidB, first"));
events.push(Event(Qt::Key_Down, lastRow, lastRow, "last, last"));
events.push(Event(Qt::Key_Home, invalidIndex, firstRow, "inv, first"));
events.push(Event(Qt::Key_End, invalidIndex, firstRow, "inv, first"));
if (view->objectName() == "QTableView") {
// In a table we move to the first/last column
events.push(Event(Qt::Key_Home, hiddenRowT, firstRow, "hid, first"));
events.push(Event(Qt::Key_Home, disabledRowT, disabledRowT, "dis, dis"));
events.push(Event(Qt::Key_Home, firstRow, firstRow, "first, first"));
events.push(Event(Qt::Key_Home, secondRow, secondRow, "sec, sec"));
events.push(Event(Qt::Key_Home, disabledRowB, disabledRowB, "disB, disB"));
events.push(Event(Qt::Key_Home, hiddenRowB, firstRow, "hidB, first"));
events.push(Event(Qt::Key_Home, secondToLastRow, secondToLastRow, "secLast, secLast"));
events.push(Event(Qt::Key_Home, lastRow, lastRow, "last, last"));
int col = treeModel->columnCount() - 1;
events.push(Event(Qt::Key_End, hiddenRowT, firstRow, "hidT, hidT"));
events.push(Event(Qt::Key_End, disabledRowT, disabledRowT, "disT, disT"));
events.push(Event(Qt::Key_End, firstRow, firstRow.sibling(firstRow.row(), col), "first, first_C"));
events.push(Event(Qt::Key_End, secondRow, secondRow.sibling(secondRow.row(), col), "sec, sec_C"));
events.push(Event(Qt::Key_End, disabledRowB, disabledRowB, "disB, disB"));
events.push(Event(Qt::Key_End, hiddenRowB, firstRow, "hidB, hidB"));
events.push(Event(Qt::Key_End, secondToLastRow, secondToLastRow.sibling(secondToLastRow.row(), col), "secLast, secLast_C"));
events.push(Event(Qt::Key_End, lastRow, lastRow.sibling(lastRow.row(), col), "last, last_C"));
} else {
events.push(Event(Qt::Key_Home, hiddenRowT, firstRow, "hid, first"));
events.push(Event(Qt::Key_Home, disabledRowT, firstRow, "dis, first"));
events.push(Event(Qt::Key_Home, firstRow, firstRow, "first, first"));
events.push(Event(Qt::Key_Home, secondRow, firstRow, "sec, first"));
events.push(Event(Qt::Key_Home, disabledRowB, firstRow, "disB, first"));
events.push(Event(Qt::Key_Home, hiddenRowB, firstRow, "hidB, first"));
events.push(Event(Qt::Key_Home, secondToLastRow, firstRow, "sec, first"));
events.push(Event(Qt::Key_Home, lastRow, firstRow, "last, first"));
events.push(Event(Qt::Key_End, hiddenRowT, firstRow, "hid, last"));
events.push(Event(Qt::Key_End, disabledRowT, lastRow, "dis, last"));
events.push(Event(Qt::Key_End, firstRow, lastRow, "first, last"));
events.push(Event(Qt::Key_End, secondRow, lastRow, "sec, last"));
events.push(Event(Qt::Key_End, disabledRowB, lastRow, "disB, last"));
events.push(Event(Qt::Key_End, hiddenRowB, firstRow, "hidB, last"));
events.push(Event(Qt::Key_End, secondToLastRow, lastRow, "sec, last"));
events.push(Event(Qt::Key_End, lastRow, lastRow, "last, last"));
}
events.push(Event(Qt::Key_PageDown, invalidIndex, firstRow, "inv, first"));
events.push(Event(Qt::Key_PageDown, firstRow, QModelIndex(), "first, x"));
events.push(Event(Qt::Key_PageDown, secondRow, QModelIndex(), "sec, x"));
events.push(Event(Qt::Key_PageDown, hiddenRowT, QModelIndex(), "hid, x"));
events.push(Event(Qt::Key_PageDown, disabledRowT, QModelIndex(), "dis, x"));
events.push(Event(Qt::Key_PageDown, disabledRowB, lastRow, "disB, last"));
events.push(Event(Qt::Key_PageDown, hiddenRowB, lastRow, "hidB, last"));
events.push(Event(Qt::Key_PageDown, secondToLastRow, lastRow, "secLast, last"));
events.push(Event(Qt::Key_PageDown, lastRow, lastRow, "last, last"));
events.push(Event(Qt::Key_PageUp, invalidIndex, firstRow, "inv, first"));
events.push(Event(Qt::Key_PageUp, firstRow, firstRow, "first, first"));
events.push(Event(Qt::Key_PageUp, secondRow, firstRow, "sec, first"));
events.push(Event(Qt::Key_PageUp, secondToLastRow, QModelIndex(), "secLast, x"));
events.push(Event(Qt::Key_PageUp, lastRow, QModelIndex(), "last, x"));
if (view->objectName() == "QTableView") {
events.push(Event(Qt::Key_Left, firstRow, firstRow, "first_0, first"));
events.push(Event(Qt::Key_Left, firstRow.sibling(0, 1), firstRow, "first_1, first"));
events.push(Event(Qt::Key_Left, firstRow.sibling(0, 2), firstRow, "first_2, first"));
events.push(Event(Qt::Key_Left, firstRow.sibling(0, 3), firstRow, "first_3, first"));
events.push(Event(Qt::Key_Left, secondRow, secondRow, "sec, sec"));
events.push(Event(Qt::Key_Right, firstRow, firstRow.sibling(0, 3), "first, first_3"));
events.push(Event(Qt::Key_Right, firstRow.sibling(0, 1), firstRow, "first_1, first"));
events.push(Event(Qt::Key_Right, firstRow.sibling(0, 2), firstRow.sibling(0, 3), "first_2, first_3"));
events.push(Event(Qt::Key_Right, firstRow.sibling(0, treeModel->columnCount()-1), firstRow.sibling(0, treeModel->columnCount()-1), "first_3, sec"));
}
}
QTEST_MAIN(tst_QItemView)
#include "tst_qitemview.moc"

View File

@ -0,0 +1,126 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QHeaderView>
#include <QListView>
#include <QTableView>
#include <QTreeView>
/*
To add a view to be tested add the header file to the includes
and impliment what is needed in the functions below.
You can add more then one view, several Qt views are included as examples.
In tst_qitemview.cpp a new ViewsToTest object is created for each test.
When you have errors fix the first ones first. Later tests depend upon them working
*/
class ViewsToTest
{
public:
ViewsToTest();
QAbstractItemView *createView(const QString &viewType);
void hideIndexes(QAbstractItemView *view);
enum Display { DisplayNone, DisplayRoot };
struct test {
test(const QString &m, Display d) : viewType(m), display(d) {}
QString viewType;
Display display;
};
QList<test> tests;
};
/*!
Add new tests, they can be the same view, but in a different state.
*/
ViewsToTest::ViewsToTest()
{
tests.append(test("QTreeView_ScrollPerItem", DisplayRoot));
tests.append(test("QTreeView_ScrollPerPixel", DisplayRoot));
tests.append(test("QListView_ScrollPerItem", DisplayRoot));
tests.append(test("QListView_ScrollPerPixel", DisplayRoot));
tests.append(test("QHeaderViewHorizontal", DisplayNone));
tests.append(test("QHeaderViewVertical", DisplayNone));
tests.append(test("QTableView_ScrollPerItem", DisplayRoot));
tests.append(test("QTableView_ScrollPerPixel", DisplayRoot));
tests.append(test("QTableViewNoGrid", DisplayRoot));
}
/*!
Return a new viewType.
*/
QAbstractItemView *ViewsToTest::createView(const QString &viewType)
{
QAbstractItemView *view = nullptr;
if (viewType == "QListView_ScrollPerItem") {
view = new QListView();
view->setObjectName("QListView");
view->setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
view->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
} else if (viewType == "QListView_ScrollPerPixel") {
view = new QListView();
view->setObjectName("QListView");
view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
} else if (viewType == "QHeaderViewHorizontal") {
view = new QHeaderView(Qt::Horizontal);
view->setObjectName("QHeaderView");
} else if (viewType == "QHeaderViewVertical") {
view = new QHeaderView(Qt::Vertical);
view->setObjectName("QHeaderView");
} else if (viewType == "QTableView_ScrollPerItem") {
view = new QTableView();
view->setObjectName("QTableView");
view->setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
view->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
} else if (viewType == "QTableView_ScrollPerPixel") {
view = new QTableView();
view->setObjectName("QTableView");
view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
} else if (viewType == "QTableViewNoGrid") {
QTableView *table = new QTableView();
table->setObjectName("QTableView");
table->setShowGrid(false);
view = table;
} else if (viewType == "QTreeView_ScrollPerItem") {
view = new QTreeView();
view->setObjectName("QTreeView");
view->setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
view->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
view->setSelectionBehavior(QAbstractItemView::SelectItems);
} else if (viewType == "QTreeView_ScrollPerPixel") {
view = new QTreeView();
view->setObjectName("QTreeView");
view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
view->setSelectionBehavior(QAbstractItemView::SelectItems);
}
return view;
}
void ViewsToTest::hideIndexes(QAbstractItemView *view)
{
if (QTableView *tableView = qobject_cast<QTableView *>(view)) {
tableView->setColumnHidden(1, true);
tableView->setRowHidden(1, true);
tableView->setRowHidden(tableView->model()->rowCount() - 2, true);
}
if (QTreeView *treeView = qobject_cast<QTreeView *>(view)) {
treeView->setColumnHidden(1, true);
treeView->setRowHidden(1, QModelIndex(), true);
treeView->setRowHidden(treeView->model()->rowCount() - 2, QModelIndex(), true);
}
if (QListView *listView = qobject_cast<QListView *>(view)) {
listView->setRowHidden(1, true);
listView->setRowHidden(listView->model()->rowCount() - 2, true);
}
}

View File

@ -0,0 +1,3 @@
# QTBUG-94250
[internalDragDropMove]
opensuse-leap

View File

@ -0,0 +1,26 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qlistview Test:
#####################################################################
qt_internal_add_test(tst_qlistview
SOURCES
tst_qlistview.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qlistview CONDITION WIN32
LIBRARIES
user32
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qlistwidget Test:
#####################################################################
qt_internal_add_test(tst_qlistwidget
SOURCES
tst_qlistwidget.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
[moveCursorBiggerJump]
osx
[mouseWheel:scroll down per pixel]
macos

View File

@ -0,0 +1,18 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtableview Test:
#####################################################################
qt_internal_add_test(tst_qtableview
SOURCES
tst_qtableview.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtablewidget Test:
#####################################################################
qt_internal_add_test(tst_qtablewidget
SOURCES
tst_qtablewidget.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtreeview Test:
#####################################################################
qt_internal_add_test(tst_qtreeview
SOURCES
../../../../shared/fakedirmodel.h
tst_qtreeview.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtreewidget Test:
#####################################################################
qt_internal_add_test(tst_qtreewidget
SOURCES
tst_qtreewidget.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtreewidgetitemiterator Test:
#####################################################################
qt_internal_add_test(tst_qtreewidgetitemiterator
SOURCES
tst_qtreewidgetitemiterator.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
)