summaryrefslogtreecommitdiffstats
path: root/tests/manual/examples/widgets/itemviews
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/examples/widgets/itemviews')
-rw-r--r--tests/manual/examples/widgets/itemviews/chart/CMakeLists.txt56
-rw-r--r--tests/manual/examples/widgets/itemviews/chart/chart.pro14
-rw-r--r--tests/manual/examples/widgets/itemviews/chart/chart.qrc5
-rw-r--r--tests/manual/examples/widgets/itemviews/chart/main.cpp14
-rw-r--r--tests/manual/examples/widgets/itemviews/chart/mainwindow.cpp136
-rw-r--r--tests/manual/examples/widgets/itemviews/chart/mainwindow.h34
-rw-r--r--tests/manual/examples/widgets/itemviews/chart/pieview.cpp506
-rw-r--r--tests/manual/examples/widgets/itemviews/chart/pieview.h66
-rw-r--r--tests/manual/examples/widgets/itemviews/chart/qtdata.cht14
-rw-r--r--tests/manual/examples/widgets/itemviews/dirview/CMakeLists.txt36
-rw-r--r--tests/manual/examples/widgets/itemviews/dirview/dirview.pro8
-rw-r--r--tests/manual/examples/widgets/itemviews/dirview/main.cpp62
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/CMakeLists.txt51
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/README2
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/images/folder.pngbin0 -> 3910 bytes
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/images/interview.pngbin0 -> 174 bytes
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/images/services.pngbin0 -> 3749 bytes
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/interview.pro16
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/interview.qrc7
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/main.cpp55
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/model.cpp110
-rw-r--r--tests/manual/examples/widgets/itemviews/interview/model.h53
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/CMakeLists.txt58
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/imagemodel.cpp53
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/imagemodel.h31
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/images.qrc5
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/images/qt.pngbin0 -> 1506 bytes
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/main.cpp15
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/mainwindow.cpp214
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/mainwindow.h37
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/pixelator.pro16
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/pixeldelegate.cpp68
-rw-r--r--tests/manual/examples/widgets/itemviews/pixelator/pixeldelegate.h41
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/CMakeLists.txt51
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/example.jpgbin0 -> 42654 bytes
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/main.cpp15
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/mainwindow.cpp115
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/mainwindow.h41
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.cpp168
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.h45
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/puzzle.pro15
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/puzzle.qrc5
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.cpp163
-rw-r--r--tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.h56
-rw-r--r--tests/manual/examples/widgets/itemviews/simpledommodel/CMakeLists.txt40
-rw-r--r--tests/manual/examples/widgets/itemviews/simpledommodel/domitem.cpp62
-rw-r--r--tests/manual/examples/widgets/itemviews/simpledommodel/domitem.h29
-rw-r--r--tests/manual/examples/widgets/itemviews/simpledommodel/dommodel.cpp153
-rw-r--r--tests/manual/examples/widgets/itemviews/simpledommodel/dommodel.h38
-rw-r--r--tests/manual/examples/widgets/itemviews/simpledommodel/main.cpp15
-rw-r--r--tests/manual/examples/widgets/itemviews/simpledommodel/mainwindow.cpp47
-rw-r--r--tests/manual/examples/widgets/itemviews/simpledommodel/mainwindow.h33
-rw-r--r--tests/manual/examples/widgets/itemviews/simpledommodel/simpledommodel.pro14
-rw-r--r--tests/manual/examples/widgets/itemviews/simplewidgetmapper/CMakeLists.txt37
-rw-r--r--tests/manual/examples/widgets/itemviews/simplewidgetmapper/main.cpp14
-rw-r--r--tests/manual/examples/widgets/itemviews/simplewidgetmapper/simplewidgetmapper.pro10
-rw-r--r--tests/manual/examples/widgets/itemviews/simplewidgetmapper/window.cpp93
-rw-r--r--tests/manual/examples/widgets/itemviews/simplewidgetmapper/window.h47
-rw-r--r--tests/manual/examples/widgets/itemviews/storageview/CMakeLists.txt37
-rw-r--r--tests/manual/examples/widgets/itemviews/storageview/main.cpp32
-rw-r--r--tests/manual/examples/widgets/itemviews/storageview/storagemodel.cpp164
-rw-r--r--tests/manual/examples/widgets/itemviews/storageview/storagemodel.h46
-rw-r--r--tests/manual/examples/widgets/itemviews/storageview/storageview.pro12
63 files changed, 3380 insertions, 0 deletions
diff --git a/tests/manual/examples/widgets/itemviews/chart/CMakeLists.txt b/tests/manual/examples/widgets/itemviews/chart/CMakeLists.txt
new file mode 100644
index 0000000000..57e52d84fc
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/chart/CMakeLists.txt
@@ -0,0 +1,56 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(chart LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/chart")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(chart
+ main.cpp
+ mainwindow.cpp mainwindow.h
+ pieview.cpp pieview.h
+)
+
+set_target_properties(chart PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(chart PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+# Resources:
+set(chart_resource_files
+ "qtdata.cht"
+)
+
+qt_add_resources(chart "chart"
+ PREFIX
+ "/Charts"
+ FILES
+ ${chart_resource_files}
+)
+
+if(UNIX AND NOT APPLE AND NOT HAIKU AND NOT INTEGRITY AND NOT VXWORKS)
+ target_link_libraries(chart PRIVATE
+ m
+ )
+endif()
+
+install(TARGETS chart
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/itemviews/chart/chart.pro b/tests/manual/examples/widgets/itemviews/chart/chart.pro
new file mode 100644
index 0000000000..323f6202e4
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/chart/chart.pro
@@ -0,0 +1,14 @@
+QT += widgets
+requires(qtConfig(filedialog))
+
+HEADERS = mainwindow.h \
+ pieview.h
+RESOURCES = chart.qrc
+SOURCES = main.cpp \
+ mainwindow.cpp \
+ pieview.cpp
+unix:!mac:!vxworks:!integrity:!haiku:LIBS += -lm
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/chart
+INSTALLS += target
diff --git a/tests/manual/examples/widgets/itemviews/chart/chart.qrc b/tests/manual/examples/widgets/itemviews/chart/chart.qrc
new file mode 100644
index 0000000000..7401d4d2f8
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/chart/chart.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/Charts" >
+ <file>qtdata.cht</file>
+</qresource>
+</RCC>
diff --git a/tests/manual/examples/widgets/itemviews/chart/main.cpp b/tests/manual/examples/widgets/itemviews/chart/main.cpp
new file mode 100644
index 0000000000..7d7cf3e573
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/chart/main.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QApplication>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow window;
+ window.show();
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/itemviews/chart/mainwindow.cpp b/tests/manual/examples/widgets/itemviews/chart/mainwindow.cpp
new file mode 100644
index 0000000000..450f2e3a56
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/chart/mainwindow.cpp
@@ -0,0 +1,136 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "pieview.h"
+#include "mainwindow.h"
+
+#include <QtWidgets>
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+{
+ QMenu *fileMenu = new QMenu(tr("&File"), this);
+ QAction *openAction = fileMenu->addAction(tr("&Open..."));
+ openAction->setShortcuts(QKeySequence::Open);
+ QAction *saveAction = fileMenu->addAction(tr("&Save As..."));
+ saveAction->setShortcuts(QKeySequence::SaveAs);
+ QAction *quitAction = fileMenu->addAction(tr("E&xit"));
+ quitAction->setShortcuts(QKeySequence::Quit);
+
+ setupModel();
+ setupViews();
+
+ connect(openAction, &QAction::triggered, this, &MainWindow::openFile);
+ connect(saveAction, &QAction::triggered, this, &MainWindow::saveFile);
+ connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
+
+ menuBar()->addMenu(fileMenu);
+ statusBar();
+
+ loadFile(":/Charts/qtdata.cht");
+
+ setWindowTitle(tr("Chart"));
+ resize(870, 550);
+}
+
+void MainWindow::setupModel()
+{
+ model = new QStandardItemModel(8, 2, this);
+ model->setHeaderData(0, Qt::Horizontal, tr("Label"));
+ model->setHeaderData(1, Qt::Horizontal, tr("Quantity"));
+}
+
+void MainWindow::setupViews()
+{
+ QSplitter *splitter = new QSplitter;
+ QTableView *table = new QTableView;
+ pieChart = new PieView;
+ splitter->addWidget(table);
+ splitter->addWidget(pieChart);
+ splitter->setStretchFactor(0, 0);
+ splitter->setStretchFactor(1, 1);
+
+ table->setModel(model);
+ pieChart->setModel(model);
+
+ QItemSelectionModel *selectionModel = new QItemSelectionModel(model);
+ table->setSelectionModel(selectionModel);
+ pieChart->setSelectionModel(selectionModel);
+
+ QHeaderView *headerView = table->horizontalHeader();
+ headerView->setStretchLastSection(true);
+
+ setCentralWidget(splitter);
+}
+
+void MainWindow::openFile()
+{
+ const QString fileName =
+ QFileDialog::getOpenFileName(this, tr("Choose a data file"), "", "*.cht");
+ if (!fileName.isEmpty())
+ loadFile(fileName);
+}
+
+void MainWindow::loadFile(const QString &fileName)
+{
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly | QFile::Text))
+ return;
+
+ QTextStream stream(&file);
+
+ model->removeRows(0, model->rowCount(QModelIndex()), QModelIndex());
+
+ int row = 0;
+ while (!stream.atEnd()) {
+ const QString line = stream.readLine();
+ if (!line.isEmpty()) {
+ model->insertRows(row, 1, QModelIndex());
+
+ const QStringList pieces = line.split(QLatin1Char(','), Qt::SkipEmptyParts);
+ if (pieces.size() < 3)
+ continue;
+ model->setData(model->index(row, 0, QModelIndex()),
+ pieces.value(0));
+ model->setData(model->index(row, 1, QModelIndex()),
+ pieces.value(1));
+ model->setData(model->index(row, 0, QModelIndex()),
+ QColor(pieces.value(2)), Qt::DecorationRole);
+ row++;
+ }
+ };
+
+ file.close();
+ statusBar()->showMessage(tr("Loaded %1").arg(fileName), 2000);
+}
+
+void MainWindow::saveFile()
+{
+ QString fileName = QFileDialog::getSaveFileName(this,
+ tr("Save file as"), "", "*.cht");
+
+ if (fileName.isEmpty())
+ return;
+
+ QFile file(fileName);
+ if (!file.open(QFile::WriteOnly | QFile::Text))
+ return;
+
+ QTextStream stream(&file);
+ for (int row = 0; row < model->rowCount(QModelIndex()); ++row) {
+
+ QStringList pieces;
+
+ pieces.append(model->data(model->index(row, 0, QModelIndex()),
+ Qt::DisplayRole).toString());
+ pieces.append(model->data(model->index(row, 1, QModelIndex()),
+ Qt::DisplayRole).toString());
+ pieces.append(model->data(model->index(row, 0, QModelIndex()),
+ Qt::DecorationRole).toString());
+
+ stream << pieces.join(',') << "\n";
+ }
+
+ file.close();
+ statusBar()->showMessage(tr("Saved %1").arg(fileName), 2000);
+}
diff --git a/tests/manual/examples/widgets/itemviews/chart/mainwindow.h b/tests/manual/examples/widgets/itemviews/chart/mainwindow.h
new file mode 100644
index 0000000000..f2a639c952
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/chart/mainwindow.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+class QAbstractItemModel;
+class QAbstractItemView;
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+
+private slots:
+ void openFile();
+ void saveFile();
+
+private:
+ void setupModel();
+ void setupViews();
+ void loadFile(const QString &path);
+
+ QAbstractItemModel *model = nullptr;
+ QAbstractItemView *pieChart = nullptr;
+};
+
+#endif // MAINWINDOW_H
diff --git a/tests/manual/examples/widgets/itemviews/chart/pieview.cpp b/tests/manual/examples/widgets/itemviews/chart/pieview.cpp
new file mode 100644
index 0000000000..e681207f38
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/chart/pieview.cpp
@@ -0,0 +1,506 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "pieview.h"
+
+#include <QtWidgets>
+
+PieView::PieView(QWidget *parent)
+ : QAbstractItemView(parent)
+{
+ horizontalScrollBar()->setRange(0, 0);
+ verticalScrollBar()->setRange(0, 0);
+}
+
+void PieView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &roles)
+{
+ QAbstractItemView::dataChanged(topLeft, bottomRight, roles);
+
+ if (!roles.contains(Qt::DisplayRole))
+ return;
+
+ validItems = 0;
+ totalValue = 0.0;
+
+ for (int row = 0; row < model()->rowCount(rootIndex()); ++row) {
+
+ QModelIndex index = model()->index(row, 1, rootIndex());
+ double value = model()->data(index, Qt::DisplayRole).toDouble();
+
+ if (value > 0.0) {
+ totalValue += value;
+ validItems++;
+ }
+ }
+ viewport()->update();
+}
+
+bool PieView::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
+{
+ if (index.column() == 0)
+ return QAbstractItemView::edit(index, trigger, event);
+ else
+ return false;
+}
+
+/*
+ Returns the item that covers the coordinate given in the view.
+*/
+
+QModelIndex PieView::indexAt(const QPoint &point) const
+{
+ if (validItems == 0)
+ return QModelIndex();
+
+ // Transform the view coordinates into contents widget coordinates.
+ int wx = point.x() + horizontalScrollBar()->value();
+ int wy = point.y() + verticalScrollBar()->value();
+
+ if (wx < totalSize) {
+ double cx = wx - totalSize / 2;
+ double cy = totalSize / 2 - wy; // positive cy for items above the center
+
+ // Determine the distance from the center point of the pie chart.
+ double d = std::sqrt(std::pow(cx, 2) + std::pow(cy, 2));
+
+ if (d == 0 || d > pieSize / 2)
+ return QModelIndex();
+
+ // Determine the angle of the point.
+ double angle = qRadiansToDegrees(std::atan2(cy, cx));
+ if (angle < 0)
+ angle = 360 + angle;
+
+ // Find the relevant slice of the pie.
+ double startAngle = 0.0;
+
+ for (int row = 0; row < model()->rowCount(rootIndex()); ++row) {
+
+ QModelIndex index = model()->index(row, 1, rootIndex());
+ double value = model()->data(index).toDouble();
+
+ if (value > 0.0) {
+ double sliceAngle = 360 * value / totalValue;
+
+ if (angle >= startAngle && angle < (startAngle + sliceAngle))
+ return model()->index(row, 1, rootIndex());
+
+ startAngle += sliceAngle;
+ }
+ }
+ } else {
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+ double itemHeight = QFontMetrics(option.font).height();
+ int listItem = int((wy - margin) / itemHeight);
+ int validRow = 0;
+
+ for (int row = 0; row < model()->rowCount(rootIndex()); ++row) {
+
+ QModelIndex index = model()->index(row, 1, rootIndex());
+ if (model()->data(index).toDouble() > 0.0) {
+
+ if (listItem == validRow)
+ return model()->index(row, 0, rootIndex());
+
+ // Update the list index that corresponds to the next valid row.
+ ++validRow;
+ }
+ }
+ }
+
+ return QModelIndex();
+}
+
+bool PieView::isIndexHidden(const QModelIndex & /*index*/) const
+{
+ return false;
+}
+
+/*
+ Returns the rectangle of the item at position \a index in the
+ model. The rectangle is in contents coordinates.
+*/
+
+QRect PieView::itemRect(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QRect();
+
+ // Check whether the index's row is in the list of rows represented
+ // by slices.
+ QModelIndex valueIndex;
+
+ if (index.column() != 1)
+ valueIndex = model()->index(index.row(), 1, rootIndex());
+ else
+ valueIndex = index;
+
+ if (model()->data(valueIndex).toDouble() <= 0.0)
+ return QRect();
+
+ int listItem = 0;
+ for (int row = index.row()-1; row >= 0; --row) {
+ if (model()->data(model()->index(row, 1, rootIndex())).toDouble() > 0.0)
+ listItem++;
+ }
+
+ switch (index.column()) {
+ case 0: {
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+ const qreal itemHeight = QFontMetricsF(option.font).height();
+ return QRect(totalSize,
+ qRound(margin + listItem * itemHeight),
+ totalSize - margin, qRound(itemHeight));
+ }
+ case 1:
+ return viewport()->rect();
+ }
+ return QRect();
+}
+
+QRegion PieView::itemRegion(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QRegion();
+
+ if (index.column() != 1)
+ return itemRect(index);
+
+ if (model()->data(index).toDouble() <= 0.0)
+ return QRegion();
+
+ double startAngle = 0.0;
+ for (int row = 0; row < model()->rowCount(rootIndex()); ++row) {
+
+ QModelIndex sliceIndex = model()->index(row, 1, rootIndex());
+ double value = model()->data(sliceIndex).toDouble();
+
+ if (value > 0.0) {
+ double angle = 360 * value / totalValue;
+
+ if (sliceIndex == index) {
+ QPainterPath slicePath;
+ slicePath.moveTo(totalSize / 2, totalSize / 2);
+ slicePath.arcTo(margin, margin, margin + pieSize, margin + pieSize,
+ startAngle, angle);
+ slicePath.closeSubpath();
+
+ return QRegion(slicePath.toFillPolygon().toPolygon());
+ }
+
+ startAngle += angle;
+ }
+ }
+
+ return QRegion();
+}
+
+int PieView::horizontalOffset() const
+{
+ return horizontalScrollBar()->value();
+}
+
+void PieView::mousePressEvent(QMouseEvent *event)
+{
+ QAbstractItemView::mousePressEvent(event);
+ origin = event->position().toPoint();
+ if (!rubberBand)
+ rubberBand = new QRubberBand(QRubberBand::Rectangle, viewport());
+ rubberBand->setGeometry(QRect(origin, QSize()));
+ rubberBand->show();
+}
+
+void PieView::mouseMoveEvent(QMouseEvent *event)
+{
+ if (rubberBand)
+ rubberBand->setGeometry(QRect(origin, event->position().toPoint()).normalized());
+ QAbstractItemView::mouseMoveEvent(event);
+}
+
+void PieView::mouseReleaseEvent(QMouseEvent *event)
+{
+ QAbstractItemView::mouseReleaseEvent(event);
+ if (rubberBand)
+ rubberBand->hide();
+ viewport()->update();
+}
+
+QModelIndex PieView::moveCursor(QAbstractItemView::CursorAction cursorAction,
+ Qt::KeyboardModifiers /*modifiers*/)
+{
+ QModelIndex current = currentIndex();
+
+ switch (cursorAction) {
+ case MoveLeft:
+ case MoveUp:
+ if (current.row() > 0)
+ current = model()->index(current.row() - 1, current.column(),
+ rootIndex());
+ else
+ current = model()->index(0, current.column(), rootIndex());
+ break;
+ case MoveRight:
+ case MoveDown:
+ if (current.row() < rows(current) - 1)
+ current = model()->index(current.row() + 1, current.column(),
+ rootIndex());
+ else
+ current = model()->index(rows(current) - 1, current.column(),
+ rootIndex());
+ break;
+ default:
+ break;
+ }
+
+ viewport()->update();
+ return current;
+}
+
+void PieView::paintEvent(QPaintEvent *event)
+{
+ QItemSelectionModel *selections = selectionModel();
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+
+ QBrush background = option.palette.base();
+ QPen foreground(option.palette.color(QPalette::WindowText));
+
+ QPainter painter(viewport());
+ painter.setRenderHint(QPainter::Antialiasing);
+
+ painter.fillRect(event->rect(), background);
+ painter.setPen(foreground);
+
+ // Viewport rectangles
+ QRect pieRect = QRect(margin, margin, pieSize, pieSize);
+
+ if (validItems <= 0)
+ return;
+
+ painter.save();
+ painter.translate(pieRect.x() - horizontalScrollBar()->value(),
+ pieRect.y() - verticalScrollBar()->value());
+ painter.drawEllipse(0, 0, pieSize, pieSize);
+ double startAngle = 0.0;
+ int row;
+
+ for (row = 0; row < model()->rowCount(rootIndex()); ++row) {
+ QModelIndex index = model()->index(row, 1, rootIndex());
+ double value = model()->data(index).toDouble();
+
+ if (value > 0.0) {
+ double angle = 360 * value / totalValue;
+
+ QModelIndex colorIndex = model()->index(row, 0, rootIndex());
+ QColor color = QColor(model()->data(colorIndex, Qt::DecorationRole).toString());
+
+ if (currentIndex() == index)
+ painter.setBrush(QBrush(color, Qt::Dense4Pattern));
+ else if (selections->isSelected(index))
+ painter.setBrush(QBrush(color, Qt::Dense3Pattern));
+ else
+ painter.setBrush(QBrush(color));
+
+ painter.drawPie(0, 0, pieSize, pieSize, int(startAngle*16), int(angle*16));
+
+ startAngle += angle;
+ }
+ }
+ painter.restore();
+
+ for (row = 0; row < model()->rowCount(rootIndex()); ++row) {
+ QModelIndex index = model()->index(row, 1, rootIndex());
+ double value = model()->data(index).toDouble();
+
+ if (value > 0.0) {
+ QModelIndex labelIndex = model()->index(row, 0, rootIndex());
+
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+
+ option.rect = visualRect(labelIndex);
+ if (selections->isSelected(labelIndex))
+ option.state |= QStyle::State_Selected;
+ if (currentIndex() == labelIndex)
+ option.state |= QStyle::State_HasFocus;
+ itemDelegate()->paint(&painter, option, labelIndex);
+ }
+ }
+}
+
+void PieView::resizeEvent(QResizeEvent * /* event */)
+{
+ updateGeometries();
+}
+
+int PieView::rows(const QModelIndex &index) const
+{
+ return model()->rowCount(model()->parent(index));
+}
+
+void PieView::rowsInserted(const QModelIndex &parent, int start, int end)
+{
+ for (int row = start; row <= end; ++row) {
+ QModelIndex index = model()->index(row, 1, rootIndex());
+ double value = model()->data(index).toDouble();
+
+ if (value > 0.0) {
+ totalValue += value;
+ ++validItems;
+ }
+ }
+
+ QAbstractItemView::rowsInserted(parent, start, end);
+}
+
+void PieView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+{
+ for (int row = start; row <= end; ++row) {
+ QModelIndex index = model()->index(row, 1, rootIndex());
+ double value = model()->data(index).toDouble();
+ if (value > 0.0) {
+ totalValue -= value;
+ --validItems;
+ }
+ }
+
+ QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
+}
+
+void PieView::scrollContentsBy(int dx, int dy)
+{
+ viewport()->scroll(dx, dy);
+}
+
+void PieView::scrollTo(const QModelIndex &index, ScrollHint)
+{
+ QRect area = viewport()->rect();
+ QRect rect = visualRect(index);
+
+ if (rect.left() < area.left()) {
+ horizontalScrollBar()->setValue(
+ horizontalScrollBar()->value() + rect.left() - area.left());
+ } else if (rect.right() > area.right()) {
+ horizontalScrollBar()->setValue(
+ horizontalScrollBar()->value() + qMin(
+ rect.right() - area.right(), rect.left() - area.left()));
+ }
+
+ if (rect.top() < area.top()) {
+ verticalScrollBar()->setValue(
+ verticalScrollBar()->value() + rect.top() - area.top());
+ } else if (rect.bottom() > area.bottom()) {
+ verticalScrollBar()->setValue(
+ verticalScrollBar()->value() + qMin(
+ rect.bottom() - area.bottom(), rect.top() - area.top()));
+ }
+
+ update();
+}
+
+/*
+ Find the indices corresponding to the extent of the selection.
+*/
+
+void PieView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
+{
+ // Use content widget coordinates because we will use the itemRegion()
+ // function to check for intersections.
+
+ QRect contentsRect = rect.translated(
+ horizontalScrollBar()->value(),
+ verticalScrollBar()->value()).normalized();
+
+ int rows = model()->rowCount(rootIndex());
+ int columns = model()->columnCount(rootIndex());
+ QModelIndexList indexes;
+
+ for (int row = 0; row < rows; ++row) {
+ for (int column = 0; column < columns; ++column) {
+ QModelIndex index = model()->index(row, column, rootIndex());
+ QRegion region = itemRegion(index);
+ if (region.intersects(contentsRect))
+ indexes.append(index);
+ }
+ }
+
+ if (indexes.size() > 0) {
+ int firstRow = indexes.at(0).row();
+ int lastRow = firstRow;
+ int firstColumn = indexes.at(0).column();
+ int lastColumn = firstColumn;
+
+ for (int i = 1; i < indexes.size(); ++i) {
+ firstRow = qMin(firstRow, indexes.at(i).row());
+ lastRow = qMax(lastRow, indexes.at(i).row());
+ firstColumn = qMin(firstColumn, indexes.at(i).column());
+ lastColumn = qMax(lastColumn, indexes.at(i).column());
+ }
+
+ QItemSelection selection(
+ model()->index(firstRow, firstColumn, rootIndex()),
+ model()->index(lastRow, lastColumn, rootIndex()));
+ selectionModel()->select(selection, command);
+ } else {
+ QModelIndex noIndex;
+ QItemSelection selection(noIndex, noIndex);
+ selectionModel()->select(selection, command);
+ }
+
+ update();
+}
+
+void PieView::updateGeometries()
+{
+ horizontalScrollBar()->setPageStep(viewport()->width());
+ horizontalScrollBar()->setRange(0, qMax(0, 2 * totalSize - viewport()->width()));
+ verticalScrollBar()->setPageStep(viewport()->height());
+ verticalScrollBar()->setRange(0, qMax(0, totalSize - viewport()->height()));
+}
+
+int PieView::verticalOffset() const
+{
+ return verticalScrollBar()->value();
+}
+
+/*
+ Returns the position of the item in viewport coordinates.
+*/
+
+QRect PieView::visualRect(const QModelIndex &index) const
+{
+ QRect rect = itemRect(index);
+ if (!rect.isValid())
+ return rect;
+
+ return QRect(rect.left() - horizontalScrollBar()->value(),
+ rect.top() - verticalScrollBar()->value(),
+ rect.width(), rect.height());
+}
+
+/*
+ Returns a region corresponding to the selection in viewport coordinates.
+*/
+
+QRegion PieView::visualRegionForSelection(const QItemSelection &selection) const
+{
+ int ranges = selection.count();
+
+ if (ranges == 0)
+ return QRect();
+
+ QRegion region;
+ for (int i = 0; i < ranges; ++i) {
+ const QItemSelectionRange &range = selection.at(i);
+ for (int row = range.top(); row <= range.bottom(); ++row) {
+ for (int col = range.left(); col <= range.right(); ++col) {
+ QModelIndex index = model()->index(row, col, rootIndex());
+ region += visualRect(index);
+ }
+ }
+ }
+ return region;
+}
diff --git a/tests/manual/examples/widgets/itemviews/chart/pieview.h b/tests/manual/examples/widgets/itemviews/chart/pieview.h
new file mode 100644
index 0000000000..19c4a18ed0
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/chart/pieview.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef PIEVIEW_H
+#define PIEVIEW_H
+
+#include <QAbstractItemView>
+
+//! [0]
+class PieView : public QAbstractItemView
+{
+ Q_OBJECT
+
+public:
+ PieView(QWidget *parent = nullptr);
+
+ QRect visualRect(const QModelIndex &index) const override;
+ void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override;
+ QModelIndex indexAt(const QPoint &point) const override;
+
+protected slots:
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &roles = QList<int>()) override;
+ void rowsInserted(const QModelIndex &parent, int start, int end) override;
+ void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
+
+protected:
+ bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event) override;
+ QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction,
+ Qt::KeyboardModifiers modifiers) override;
+
+ int horizontalOffset() const override;
+ int verticalOffset() const override;
+
+ bool isIndexHidden(const QModelIndex &index) const override;
+
+ void setSelection(const QRect&, QItemSelectionModel::SelectionFlags command) override;
+
+ void mousePressEvent(QMouseEvent *event) override;
+
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+
+ void paintEvent(QPaintEvent *event) override;
+ void resizeEvent(QResizeEvent *event) override;
+ void scrollContentsBy(int dx, int dy) override;
+
+ QRegion visualRegionForSelection(const QItemSelection &selection) const override;
+
+private:
+ QRect itemRect(const QModelIndex &item) const;
+ QRegion itemRegion(const QModelIndex &index) const;
+ int rows(const QModelIndex &index = QModelIndex()) const;
+ void updateGeometries() override;
+
+ int margin = 0;
+ int totalSize = 300;
+ int pieSize = totalSize - 2 * margin;
+ int validItems = 0;
+ double totalValue = 0.0;
+ QRubberBand *rubberBand = nullptr;
+ QPoint origin;
+};
+//! [0]
+
+#endif // PIEVIEW_H
diff --git a/tests/manual/examples/widgets/itemviews/chart/qtdata.cht b/tests/manual/examples/widgets/itemviews/chart/qtdata.cht
new file mode 100644
index 0000000000..6386246c4b
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/chart/qtdata.cht
@@ -0,0 +1,14 @@
+Scientific Research,21,#99e600
+Engineering & Design,18,#99cc00
+Automotive,14,#99b300
+Aerospace,13,#9f991a
+Automation & Machine Tools,13,#a48033
+Medical & Bioinformatics,13,#a9664d
+Imaging & Special Effects,12,#ae4d66
+Defense,11,#b33380
+Test & Measurement Systems,9,#a64086
+Oil & Gas,9,#994d8d
+Entertainment & Broadcasting,7,#8d5a93
+Financial,6,#806699
+Consumer Electronics,4,#8073a6
+Other,38,#8080b3
diff --git a/tests/manual/examples/widgets/itemviews/dirview/CMakeLists.txt b/tests/manual/examples/widgets/itemviews/dirview/CMakeLists.txt
new file mode 100644
index 0000000000..e7261fc4e6
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/dirview/CMakeLists.txt
@@ -0,0 +1,36 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(dirview LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/dirview")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(dirview
+ main.cpp
+)
+
+set_target_properties(dirview PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(dirview PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+install(TARGETS dirview
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/itemviews/dirview/dirview.pro b/tests/manual/examples/widgets/itemviews/dirview/dirview.pro
new file mode 100644
index 0000000000..981a64a7d6
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/dirview/dirview.pro
@@ -0,0 +1,8 @@
+QT += widgets
+requires(qtConfig(treeview))
+
+SOURCES = main.cpp
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/dirview
+INSTALLS += target
diff --git a/tests/manual/examples/widgets/itemviews/dirview/main.cpp b/tests/manual/examples/widgets/itemviews/dirview/main.cpp
new file mode 100644
index 0000000000..5db9338b67
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/dirview/main.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QApplication>
+#include <QFileSystemModel>
+#include <QFileIconProvider>
+#include <QScreen>
+#include <QScroller>
+#include <QTreeView>
+#include <QCommandLineParser>
+#include <QCommandLineOption>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ QCoreApplication::setApplicationVersion(QT_VERSION_STR);
+ QCommandLineParser parser;
+ parser.setApplicationDescription("Qt Dir View Example");
+ parser.addHelpOption();
+ parser.addVersionOption();
+ QCommandLineOption dontUseCustomDirectoryIconsOption("c", "Set QFileSystemModel::DontUseCustomDirectoryIcons");
+ parser.addOption(dontUseCustomDirectoryIconsOption);
+ QCommandLineOption dontWatchOption("w", "Set QFileSystemModel::DontWatch");
+ parser.addOption(dontWatchOption);
+ parser.addPositionalArgument("directory", "The directory to start in.");
+ parser.process(app);
+ const QString rootPath = parser.positionalArguments().isEmpty()
+ ? QString() : parser.positionalArguments().first();
+
+ QFileSystemModel model;
+ QFileIconProvider iconProvider;
+ model.setIconProvider(&iconProvider);
+ model.setRootPath("");
+ if (parser.isSet(dontUseCustomDirectoryIconsOption))
+ model.setOption(QFileSystemModel::DontUseCustomDirectoryIcons);
+ if (parser.isSet(dontWatchOption))
+ model.setOption(QFileSystemModel::DontWatchForChanges);
+ QTreeView tree;
+ tree.setModel(&model);
+ if (!rootPath.isEmpty()) {
+ const QModelIndex rootIndex = model.index(QDir::cleanPath(rootPath));
+ if (rootIndex.isValid())
+ tree.setRootIndex(rootIndex);
+ }
+
+ // Demonstrating look and feel features
+ tree.setAnimated(false);
+ tree.setIndentation(20);
+ tree.setSortingEnabled(true);
+ const QSize availableSize = tree.screen()->availableGeometry().size();
+ tree.resize(availableSize / 2);
+ tree.setColumnWidth(0, tree.width() / 3);
+
+ // Make it flickable on touchscreens
+ QScroller::grabGesture(&tree, QScroller::TouchGesture);
+
+ tree.setWindowTitle(QObject::tr("Dir View"));
+ tree.show();
+
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/itemviews/interview/CMakeLists.txt b/tests/manual/examples/widgets/itemviews/interview/CMakeLists.txt
new file mode 100644
index 0000000000..8bab5798ad
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/CMakeLists.txt
@@ -0,0 +1,51 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(interview LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/interview")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(interview
+ main.cpp
+ model.cpp model.h
+)
+
+set_target_properties(interview PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(interview PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+# Resources:
+set(interview_resource_files
+ "images/folder.png"
+ "images/interview.png"
+ "images/services.png"
+)
+
+qt_add_resources(interview "interview"
+ PREFIX
+ "/"
+ FILES
+ ${interview_resource_files}
+)
+
+install(TARGETS interview
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/itemviews/interview/README b/tests/manual/examples/widgets/itemviews/interview/README
new file mode 100644
index 0000000000..50894428f6
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/README
@@ -0,0 +1,2 @@
+The interview example shows the same model and selection being shared
+between three different views.
diff --git a/tests/manual/examples/widgets/itemviews/interview/images/folder.png b/tests/manual/examples/widgets/itemviews/interview/images/folder.png
new file mode 100644
index 0000000000..589fd2df59
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/images/folder.png
Binary files differ
diff --git a/tests/manual/examples/widgets/itemviews/interview/images/interview.png b/tests/manual/examples/widgets/itemviews/interview/images/interview.png
new file mode 100644
index 0000000000..0c3d690258
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/images/interview.png
Binary files differ
diff --git a/tests/manual/examples/widgets/itemviews/interview/images/services.png b/tests/manual/examples/widgets/itemviews/interview/images/services.png
new file mode 100644
index 0000000000..6b2ad969d4
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/images/services.png
Binary files differ
diff --git a/tests/manual/examples/widgets/itemviews/interview/interview.pro b/tests/manual/examples/widgets/itemviews/interview/interview.pro
new file mode 100644
index 0000000000..6d64f23eb9
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/interview.pro
@@ -0,0 +1,16 @@
+TEMPLATE = app
+QT += widgets
+requires(qtConfig(treeview))
+
+HEADERS += model.h
+SOURCES += model.cpp main.cpp
+RESOURCES += interview.qrc
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/interview
+INSTALLS += target
diff --git a/tests/manual/examples/widgets/itemviews/interview/interview.qrc b/tests/manual/examples/widgets/itemviews/interview/interview.qrc
new file mode 100644
index 0000000000..b28ea34d8a
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/interview.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>images/folder.png</file>
+ <file>images/services.png</file>
+ <file>images/interview.png</file>
+</qresource>
+</RCC>
diff --git a/tests/manual/examples/widgets/itemviews/interview/main.cpp b/tests/manual/examples/widgets/itemviews/interview/main.cpp
new file mode 100644
index 0000000000..3446ff1dc4
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/main.cpp
@@ -0,0 +1,55 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "model.h"
+
+#include <QApplication>
+#include <QHeaderView>
+#include <QListView>
+#include <QSplitter>
+#include <QTableView>
+#include <QTreeView>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QSplitter page;
+
+ QAbstractItemModel *data = new Model(1000, 10, &page);
+ QItemSelectionModel *selections = new QItemSelectionModel(data);
+
+ QTableView *table = new QTableView;
+ table->setModel(data);
+ table->setSelectionModel(selections);
+ table->horizontalHeader()->setSectionsMovable(true);
+ table->verticalHeader()->setSectionsMovable(true);
+ // Set StaticContents to enable minimal repaints on resizes.
+ table->viewport()->setAttribute(Qt::WA_StaticContents);
+ page.addWidget(table);
+
+ QTreeView *tree = new QTreeView;
+ tree->setModel(data);
+ tree->setSelectionModel(selections);
+ tree->setUniformRowHeights(true);
+ tree->header()->setStretchLastSection(false);
+ tree->viewport()->setAttribute(Qt::WA_StaticContents);
+ // Disable the focus rect to get minimal repaints when scrolling on Mac.
+ tree->setAttribute(Qt::WA_MacShowFocusRect, false);
+ page.addWidget(tree);
+
+ QListView *list = new QListView;
+ list->setModel(data);
+ list->setSelectionModel(selections);
+ list->setViewMode(QListView::IconMode);
+ list->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ list->setAlternatingRowColors(false);
+ list->viewport()->setAttribute(Qt::WA_StaticContents);
+ list->setAttribute(Qt::WA_MacShowFocusRect, false);
+ page.addWidget(list);
+
+ page.setWindowIcon(QPixmap(":/images/interview.png"));
+ page.setWindowTitle("Interview");
+ page.show();
+
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/itemviews/interview/model.cpp b/tests/manual/examples/widgets/itemviews/interview/model.cpp
new file mode 100644
index 0000000000..9050ae6cc1
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/model.cpp
@@ -0,0 +1,110 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "model.h"
+
+#include <QPixmap>
+
+Model::Model(int rows, int columns, QObject *parent)
+ : QAbstractItemModel(parent),
+ services(QPixmap(":/images/services.png")),
+ rc(rows),
+ cc(columns),
+ tree(new QList<Node>(rows, Node()))
+{
+
+}
+
+Model::~Model()
+{
+ delete tree;
+}
+
+QModelIndex Model::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < rc && row >= 0 && column < cc && column >= 0) {
+ Node *parentNode = static_cast<Node*>(parent.internalPointer());
+ Node *childNode = node(row, parentNode);
+ if (childNode)
+ return createIndex(row, column, childNode);
+ }
+ return QModelIndex();
+}
+
+QModelIndex Model::parent(const QModelIndex &child) const
+{
+ if (child.isValid()) {
+ Node *childNode = static_cast<Node*>(child.internalPointer());
+ Node *parentNode = parent(childNode);
+ if (parentNode)
+ return createIndex(row(parentNode), 0, parentNode);
+ }
+ return QModelIndex();
+}
+
+int Model::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid() && parent.column() != 0) ? 0 : rc;
+}
+
+int Model::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return cc;
+}
+
+QVariant Model::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+ if (role == Qt::DisplayRole)
+ return QVariant("Item " + QString::number(index.row()) + ':' + QString::number(index.column()));
+ if (role == Qt::DecorationRole) {
+ if (index.column() == 0)
+ return iconProvider.icon(QFileIconProvider::Folder);
+ return iconProvider.icon(QFileIconProvider::File);
+ }
+ return QVariant();
+}
+
+QVariant Model::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::DisplayRole)
+ return QString::number(section);
+ if (role == Qt::DecorationRole)
+ return QVariant::fromValue(services);
+ return QAbstractItemModel::headerData(section, orientation, role);
+}
+
+bool Model::hasChildren(const QModelIndex &parent) const
+{
+ if (parent.isValid() && parent.column() != 0)
+ return false;
+ return rc > 0 && cc > 0;
+}
+
+Qt::ItemFlags Model::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return {};
+ return Qt::ItemIsDragEnabled|QAbstractItemModel::flags(index);
+}
+
+Model::Node *Model::node(int row, Node *parent) const
+{
+ if (parent && !parent->children)
+ parent->children = new QList<Node>(rc, Node(parent));
+ QList<Node> *v = parent ? parent->children : tree;
+ return const_cast<Node*>(&(v->at(row)));
+}
+
+Model::Node *Model::parent(Node *child) const
+{
+ return child ? child->parent : nullptr;
+}
+
+int Model::row(Node *node) const
+{
+ const Node *first = node->parent ? &(node->parent->children->at(0)) : &(tree->at(0));
+ return node - first;
+}
diff --git a/tests/manual/examples/widgets/itemviews/interview/model.h b/tests/manual/examples/widgets/itemviews/interview/model.h
new file mode 100644
index 0000000000..87ee740792
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/interview/model.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MODEL_H
+#define MODEL_H
+
+#include <QAbstractItemModel>
+#include <QFileIconProvider>
+#include <QIcon>
+#include <QList>
+
+class Model : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ Model(int rows, int columns, QObject *parent = nullptr);
+ ~Model();
+
+ QModelIndex index(int row, int column, const QModelIndex &parent) const override;
+ QModelIndex parent(const QModelIndex &child) const override;
+
+ int rowCount(const QModelIndex &parent) const override;
+ int columnCount(const QModelIndex &parent) const override;
+
+ QVariant data(const QModelIndex &index, int role) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+
+ bool hasChildren(const QModelIndex &parent) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+
+private:
+
+ struct Node
+ {
+ Node(Node *parent = nullptr) : parent(parent), children(nullptr) {}
+ ~Node() { delete children; }
+ Node *parent;
+ QList<Node> *children;
+ };
+
+ Node *node(int row, Node *parent) const;
+ Node *parent(Node *child) const;
+ int row(Node *node) const;
+
+ QIcon services;
+ int rc;
+ int cc;
+ QList<Node> *tree;
+ QFileIconProvider iconProvider;
+};
+
+#endif // MODEL_H
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/CMakeLists.txt b/tests/manual/examples/widgets/itemviews/pixelator/CMakeLists.txt
new file mode 100644
index 0000000000..0a2671b13c
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/CMakeLists.txt
@@ -0,0 +1,58 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(pixelator LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/pixelator")
+
+find_package(Qt6
+ REQUIRED COMPONENTS Core Gui Widgets
+ OPTIONAL_COMPONENTS PrintSupport
+)
+
+qt_standard_project_setup()
+
+qt_add_executable(pixelator
+ imagemodel.cpp imagemodel.h
+ main.cpp
+ mainwindow.cpp mainwindow.h
+ pixeldelegate.cpp pixeldelegate.h
+)
+
+set_target_properties(pixelator PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(pixelator PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+if(TARGET Qt6::PrintSupport)
+ target_link_libraries(pixelator PRIVATE Qt6::PrintSupport)
+endif()
+
+# Resources:
+set(images_resource_files
+ "images/qt.png"
+)
+
+qt_add_resources(pixelator "images"
+ PREFIX
+ "/"
+ FILES
+ ${images_resource_files}
+)
+
+install(TARGETS pixelator
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/imagemodel.cpp b/tests/manual/examples/widgets/itemviews/pixelator/imagemodel.cpp
new file mode 100644
index 0000000000..6b5b866522
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/imagemodel.cpp
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "imagemodel.h"
+
+//! [0]
+ImageModel::ImageModel(QObject *parent)
+ : QAbstractTableModel(parent)
+{
+}
+//! [0]
+
+//! [1]
+void ImageModel::setImage(const QImage &image)
+{
+ beginResetModel();
+ modelImage = image;
+ endResetModel();
+}
+//! [1]
+
+//! [2]
+int ImageModel::rowCount(const QModelIndex & /* parent */) const
+{
+ return modelImage.height();
+}
+
+int ImageModel::columnCount(const QModelIndex & /* parent */) const
+//! [2] //! [3]
+{
+ return modelImage.width();
+}
+//! [3]
+
+//! [4]
+QVariant ImageModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || role != Qt::DisplayRole)
+ return QVariant();
+ return qGray(modelImage.pixel(index.column(), index.row()));
+}
+//! [4]
+
+//! [5]
+QVariant ImageModel::headerData(int /* section */,
+ Qt::Orientation /* orientation */,
+ int role) const
+{
+ if (role == Qt::SizeHintRole)
+ return QSize(1, 1);
+ return QVariant();
+}
+//! [5]
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/imagemodel.h b/tests/manual/examples/widgets/itemviews/pixelator/imagemodel.h
new file mode 100644
index 0000000000..050ac6b790
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/imagemodel.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef IMAGEMODEL_H
+#define IMAGEMODEL_H
+
+#include <QAbstractTableModel>
+#include <QImage>
+
+//! [0]
+class ImageModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ ImageModel(QObject *parent = nullptr);
+
+ void setImage(const QImage &image);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+
+private:
+ QImage modelImage;
+};
+//! [0]
+
+#endif // IMAGEMODEL_H
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/images.qrc b/tests/manual/examples/widgets/itemviews/pixelator/images.qrc
new file mode 100644
index 0000000000..c105e13895
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/images.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>images/qt.png</file>
+</qresource>
+</RCC>
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/images/qt.png b/tests/manual/examples/widgets/itemviews/pixelator/images/qt.png
new file mode 100644
index 0000000000..dd197cb59c
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/images/qt.png
Binary files differ
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/main.cpp b/tests/manual/examples/widgets/itemviews/pixelator/main.cpp
new file mode 100644
index 0000000000..26783b02fc
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/main.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QApplication>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow window;
+ window.show();
+ window.openImage(":/images/qt.png");
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/mainwindow.cpp b/tests/manual/examples/widgets/itemviews/pixelator/mainwindow.cpp
new file mode 100644
index 0000000000..42f0a43844
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/mainwindow.cpp
@@ -0,0 +1,214 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+#include "imagemodel.h"
+#include "pixeldelegate.h"
+
+#include <QtWidgets>
+#if defined(QT_PRINTSUPPORT_LIB)
+#include <QtPrintSupport/qtprintsupportglobal.h>
+#if QT_CONFIG(printdialog)
+#include <QPrinter>
+#include <QPrintDialog>
+#endif
+#endif
+
+//! [0]
+MainWindow::MainWindow()
+{
+//! [0]
+ currentPath = QDir::homePath();
+ model = new ImageModel(this);
+
+ QWidget *centralWidget = new QWidget;
+
+//! [1]
+ view = new QTableView;
+ view->setShowGrid(false);
+ view->horizontalHeader()->hide();
+ view->verticalHeader()->hide();
+ view->horizontalHeader()->setMinimumSectionSize(1);
+ view->verticalHeader()->setMinimumSectionSize(1);
+ view->setModel(model);
+//! [1]
+
+//! [2]
+ PixelDelegate *delegate = new PixelDelegate(this);
+ view->setItemDelegate(delegate);
+//! [2]
+
+//! [3]
+ QLabel *pixelSizeLabel = new QLabel(tr("Pixel size:"));
+ QSpinBox *pixelSizeSpinBox = new QSpinBox;
+ pixelSizeSpinBox->setMinimum(4);
+ pixelSizeSpinBox->setMaximum(32);
+ pixelSizeSpinBox->setValue(12);
+//! [3]
+
+ QMenu *fileMenu = new QMenu(tr("&File"), this);
+ QAction *openAction = fileMenu->addAction(tr("&Open..."));
+ openAction->setShortcuts(QKeySequence::Open);
+
+ printAction = fileMenu->addAction(tr("&Print..."));
+ printAction->setEnabled(false);
+ printAction->setShortcut(QKeySequence::Print);
+
+ QAction *quitAction = fileMenu->addAction(tr("E&xit"));
+ quitAction->setShortcuts(QKeySequence::Quit);
+
+ QMenu *helpMenu = new QMenu(tr("&Help"), this);
+ QAction *aboutAction = helpMenu->addAction(tr("&About"));
+
+ menuBar()->addMenu(fileMenu);
+ menuBar()->addSeparator();
+ menuBar()->addMenu(helpMenu);
+
+ connect(openAction, &QAction::triggered, this, &MainWindow::chooseImage);
+ connect(printAction, &QAction::triggered, this, &MainWindow::printImage);
+ connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
+ connect(aboutAction, &QAction::triggered, this, &MainWindow::showAboutBox);
+//! [4]
+ connect(pixelSizeSpinBox, &QSpinBox::valueChanged,
+ delegate, &PixelDelegate::setPixelSize);
+ connect(pixelSizeSpinBox, &QSpinBox::valueChanged,
+ this, &MainWindow::updateView);
+//! [4]
+
+ QHBoxLayout *controlsLayout = new QHBoxLayout;
+ controlsLayout->addWidget(pixelSizeLabel);
+ controlsLayout->addWidget(pixelSizeSpinBox);
+ controlsLayout->addStretch(1);
+
+ QVBoxLayout *mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(view);
+ mainLayout->addLayout(controlsLayout);
+ centralWidget->setLayout(mainLayout);
+
+ setCentralWidget(centralWidget);
+
+ setWindowTitle(tr("Pixelator"));
+ resize(640, 480);
+//! [5]
+}
+//! [5]
+
+void MainWindow::chooseImage()
+{
+ QString fileName = QFileDialog::getOpenFileName(this,
+ tr("Choose an image"), currentPath, "*");
+
+ if (!fileName.isEmpty())
+ openImage(fileName);
+}
+
+void MainWindow::openImage(const QString &fileName)
+{
+ QImage image;
+
+ if (image.load(fileName)) {
+ model->setImage(image);
+ if (!fileName.startsWith(":/")) {
+ currentPath = fileName;
+ setWindowTitle(tr("%1 - Pixelator").arg(currentPath));
+ }
+
+ printAction->setEnabled(true);
+ updateView();
+ }
+}
+
+void MainWindow::printImage()
+{
+#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
+ if (model->rowCount(QModelIndex())*model->columnCount(QModelIndex()) > 90000) {
+ QMessageBox::StandardButton answer;
+ answer = QMessageBox::question(this, tr("Large Image Size"),
+ tr("The printed image may be very large. Are you sure that "
+ "you want to print it?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (answer == QMessageBox::No)
+ return;
+ }
+
+ QPrinter printer(QPrinter::HighResolution);
+
+ QPrintDialog dlg(&printer, this);
+ dlg.setWindowTitle(tr("Print Image"));
+
+ if (dlg.exec() != QDialog::Accepted) {
+ return;
+ }
+
+ QPainter painter;
+ painter.begin(&printer);
+
+ int rows = model->rowCount(QModelIndex());
+ int columns = model->columnCount(QModelIndex());
+ int sourceWidth = (columns + 1) * ItemSize;
+ int sourceHeight = (rows + 1) * ItemSize;
+
+ painter.save();
+
+ double xscale = printer.pageRect(QPrinter::DevicePixel).width() / double(sourceWidth);
+ double yscale = printer.pageRect(QPrinter::DevicePixel).height() / double(sourceHeight);
+ double scale = qMin(xscale, yscale);
+
+ painter.translate(printer.paperRect(QPrinter::DevicePixel).x() + printer.pageRect(QPrinter::DevicePixel).width() / 2,
+ printer.paperRect(QPrinter::DevicePixel).y() + printer.pageRect(QPrinter::DevicePixel).height() / 2);
+ painter.scale(scale, scale);
+ painter.translate(-sourceWidth / 2, -sourceHeight / 2);
+
+ QStyleOptionViewItem option;
+ QModelIndex parent = QModelIndex();
+
+ QProgressDialog progress(tr("Printing..."), tr("Cancel"), 0, rows, this);
+ progress.setWindowModality(Qt::ApplicationModal);
+ float y = ItemSize / 2;
+
+ for (int row = 0; row < rows; ++row) {
+ progress.setValue(row);
+ qApp->processEvents();
+ if (progress.wasCanceled())
+ break;
+
+ float x = ItemSize / 2;
+
+ for (int column = 0; column < columns; ++column) {
+ option.rect = QRect(int(x), int(y), ItemSize, ItemSize);
+ view->itemDelegate()->paint(&painter, option,
+ model->index(row, column, parent));
+ x = x + ItemSize;
+ }
+ y = y + ItemSize;
+ }
+ progress.setValue(rows);
+
+ painter.restore();
+ painter.end();
+
+ if (progress.wasCanceled()) {
+ QMessageBox::information(this, tr("Printing canceled"),
+ tr("The printing process was canceled."), QMessageBox::Cancel);
+ }
+#else
+ QMessageBox::information(this, tr("Printing canceled"),
+ tr("Printing is not supported on this Qt build"), QMessageBox::Cancel);
+#endif
+}
+
+void MainWindow::showAboutBox()
+{
+ QMessageBox::about(this, tr("About the Pixelator example"),
+ tr("This example demonstrates how a standard view and a custom\n"
+ "delegate can be used to produce a specialized representation\n"
+ "of data in a simple custom model."));
+}
+
+//! [6]
+void MainWindow::updateView()
+{
+ view->resizeColumnsToContents();
+ view->resizeRowsToContents();
+}
+//! [6]
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/mainwindow.h b/tests/manual/examples/widgets/itemviews/pixelator/mainwindow.h
new file mode 100644
index 0000000000..9929e2f5af
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/mainwindow.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+class ImageModel;
+QT_BEGIN_NAMESPACE
+class QAction;
+class QTableView;
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+ void openImage(const QString &fileName);
+
+public slots:
+ void chooseImage();
+ void printImage();
+ void showAboutBox();
+ void updateView();
+
+private:
+ ImageModel *model;
+ QAction *printAction;
+ QString currentPath;
+ QTableView *view;
+};
+
+#endif // MAINWINDOW_H
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/pixelator.pro b/tests/manual/examples/widgets/itemviews/pixelator/pixelator.pro
new file mode 100644
index 0000000000..421f626e28
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/pixelator.pro
@@ -0,0 +1,16 @@
+QT += widgets
+requires(qtConfig(tableview))
+qtHaveModule(printsupport): QT += printsupport
+
+HEADERS = imagemodel.h \
+ mainwindow.h \
+ pixeldelegate.h
+SOURCES = imagemodel.cpp \
+ main.cpp \
+ mainwindow.cpp \
+ pixeldelegate.cpp
+RESOURCES += images.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/pixelator
+INSTALLS += target
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/pixeldelegate.cpp b/tests/manual/examples/widgets/itemviews/pixelator/pixeldelegate.cpp
new file mode 100644
index 0000000000..3a104cd2c2
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/pixeldelegate.cpp
@@ -0,0 +1,68 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "pixeldelegate.h"
+
+#include <QPainter>
+
+//! [0]
+PixelDelegate::PixelDelegate(QObject *parent)
+ : QAbstractItemDelegate(parent), pixelSize(12)
+{}
+//! [0]
+
+//! [1]
+void PixelDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+//! [2]
+ if (option.state & QStyle::State_Selected)
+ painter->fillRect(option.rect, option.palette.highlight());
+//! [1]
+
+//! [3]
+ const int size = qMin(option.rect.width(), option.rect.height());
+//! [3] //! [4]
+ const int brightness = index.model()->data(index, Qt::DisplayRole).toInt();
+ const double radius = (size / 2.0) - (brightness / 255.0 * size / 2.0);
+ if (qFuzzyIsNull(radius))
+ return;
+//! [4]
+
+//! [5]
+ painter->save();
+//! [5] //! [6]
+ painter->setRenderHint(QPainter::Antialiasing, true);
+//! [6] //! [7]
+ painter->setPen(Qt::NoPen);
+//! [7] //! [8]
+ if (option.state & QStyle::State_Selected)
+//! [8] //! [9]
+ painter->setBrush(option.palette.highlightedText());
+ else
+//! [2]
+ painter->setBrush(option.palette.text());
+//! [9]
+
+//! [10]
+ painter->drawEllipse(QRectF(option.rect.x() + option.rect.width() / 2 - radius,
+ option.rect.y() + option.rect.height() / 2 - radius,
+ 2 * radius, 2 * radius));
+ painter->restore();
+}
+//! [10]
+
+//! [11]
+QSize PixelDelegate::sizeHint(const QStyleOptionViewItem & /* option */,
+ const QModelIndex & /* index */) const
+{
+ return QSize(pixelSize, pixelSize);
+}
+//! [11]
+
+//! [12]
+void PixelDelegate::setPixelSize(int size)
+{
+ pixelSize = size;
+}
+//! [12]
diff --git a/tests/manual/examples/widgets/itemviews/pixelator/pixeldelegate.h b/tests/manual/examples/widgets/itemviews/pixelator/pixeldelegate.h
new file mode 100644
index 0000000000..a4c435ce69
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/pixelator/pixeldelegate.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef PIXELDELEGATE_H
+#define PIXELDELEGATE_H
+
+#include <QAbstractItemDelegate>
+#include <QModelIndex>
+#include <QSize>
+
+QT_BEGIN_NAMESPACE
+class QAbstractItemModel;
+class QObject;
+class QPainter;
+QT_END_NAMESPACE
+
+static constexpr int ItemSize = 256;
+
+//! [0]
+class PixelDelegate : public QAbstractItemDelegate
+{
+ Q_OBJECT
+
+public:
+ PixelDelegate(QObject *parent = nullptr);
+
+ void paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+
+ QSize sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+
+public slots:
+ void setPixelSize(int size);
+
+private:
+ int pixelSize;
+};
+//! [0]
+
+#endif // PIXELDELEGATE_H
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/CMakeLists.txt b/tests/manual/examples/widgets/itemviews/puzzle/CMakeLists.txt
new file mode 100644
index 0000000000..21989f1a83
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/CMakeLists.txt
@@ -0,0 +1,51 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(puzzle LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/puzzle")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(itemviews_puzzle
+ main.cpp
+ mainwindow.cpp mainwindow.h
+ piecesmodel.cpp piecesmodel.h
+ puzzlewidget.cpp puzzlewidget.h
+)
+
+set_target_properties(itemviews_puzzle PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(itemviews_puzzle PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+# Resources:
+set(puzzle_resource_files
+ "example.jpg"
+)
+
+qt_add_resources(itemviews_puzzle "puzzle"
+ PREFIX
+ "/images"
+ FILES
+ ${puzzle_resource_files}
+)
+
+install(TARGETS itemviews_puzzle
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/example.jpg b/tests/manual/examples/widgets/itemviews/puzzle/example.jpg
new file mode 100644
index 0000000000..023203c57a
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/example.jpg
Binary files differ
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/main.cpp b/tests/manual/examples/widgets/itemviews/puzzle/main.cpp
new file mode 100644
index 0000000000..32e219256a
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/main.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow window;
+ window.loadImage(QStringLiteral(":/images/example.jpg"));
+ window.show();
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/mainwindow.cpp b/tests/manual/examples/widgets/itemviews/puzzle/mainwindow.cpp
new file mode 100644
index 0000000000..f4b221df20
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/mainwindow.cpp
@@ -0,0 +1,115 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+#include "piecesmodel.h"
+#include "puzzlewidget.h"
+
+#include <QtWidgets>
+#include <stdlib.h>
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+{
+ setupMenus();
+ setupWidgets();
+ model = new PiecesModel(puzzleWidget->pieceSize(), this);
+ piecesList->setModel(model);
+
+ setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ setWindowTitle(tr("Puzzle"));
+}
+
+void MainWindow::openImage()
+{
+ const QString directory =
+ QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath());
+ QFileDialog dialog(this, tr("Open Image"), directory);
+ dialog.setAcceptMode(QFileDialog::AcceptOpen);
+ dialog.setFileMode(QFileDialog::ExistingFile);
+ QStringList mimeTypeFilters;
+ for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes())
+ mimeTypeFilters.append(mimeTypeName);
+ mimeTypeFilters.sort();
+ dialog.setMimeTypeFilters(mimeTypeFilters);
+ dialog.selectMimeTypeFilter("image/jpeg");
+ if (dialog.exec() == QDialog::Accepted)
+ loadImage(dialog.selectedFiles().constFirst());
+}
+
+void MainWindow::loadImage(const QString &fileName)
+{
+ QPixmap newImage;
+ if (!newImage.load(fileName)) {
+ QMessageBox::warning(this, tr("Open Image"),
+ tr("The image file could not be loaded."),
+ QMessageBox::Close);
+ return;
+ }
+ puzzleImage = newImage;
+ setupPuzzle();
+}
+
+void MainWindow::setCompleted()
+{
+ QMessageBox::information(this, tr("Puzzle Completed"),
+ tr("Congratulations! You have completed the puzzle!\n"
+ "Click OK to start again."),
+ QMessageBox::Ok);
+
+ setupPuzzle();
+}
+
+void MainWindow::setupPuzzle()
+{
+ int size = qMin(puzzleImage.width(), puzzleImage.height());
+ puzzleImage = puzzleImage.copy((puzzleImage.width() - size) / 2,
+ (puzzleImage.height() - size) / 2, size, size).scaled(puzzleWidget->imageSize(),
+ puzzleWidget->imageSize(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+ model->addPieces(puzzleImage);
+ puzzleWidget->clear();
+}
+
+void MainWindow::setupMenus()
+{
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
+
+ QAction *openAction = fileMenu->addAction(tr("&Open..."), this, &MainWindow::openImage);
+ openAction->setShortcuts(QKeySequence::Open);
+
+ QAction *exitAction = fileMenu->addAction(tr("E&xit"), qApp, &QCoreApplication::quit);
+ exitAction->setShortcuts(QKeySequence::Quit);
+
+ QMenu *gameMenu = menuBar()->addMenu(tr("&Game"));
+
+ gameMenu->addAction(tr("&Restart"), this, &MainWindow::setupPuzzle);
+}
+
+void MainWindow::setupWidgets()
+{
+ QFrame *frame = new QFrame;
+ QHBoxLayout *frameLayout = new QHBoxLayout(frame);
+
+ puzzleWidget = new PuzzleWidget(400);
+
+ piecesList = new QListView;
+ piecesList->setDragEnabled(true);
+ piecesList->setViewMode(QListView::IconMode);
+ piecesList->setIconSize(QSize(puzzleWidget->pieceSize() - 20, puzzleWidget->pieceSize() - 20));
+ piecesList->setGridSize(QSize(puzzleWidget->pieceSize(), puzzleWidget->pieceSize()));
+ piecesList->setSpacing(10);
+ piecesList->setMovement(QListView::Snap);
+ piecesList->setAcceptDrops(true);
+ piecesList->setDropIndicatorShown(true);
+
+ PiecesModel *model = new PiecesModel(puzzleWidget->pieceSize(), this);
+ piecesList->setModel(model);
+
+ connect(puzzleWidget, &PuzzleWidget::puzzleCompleted,
+ this, &MainWindow::setCompleted, Qt::QueuedConnection);
+
+ frameLayout->addWidget(piecesList);
+ frameLayout->addWidget(puzzleWidget);
+ setCentralWidget(frame);
+}
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/mainwindow.h b/tests/manual/examples/widgets/itemviews/puzzle/mainwindow.h
new file mode 100644
index 0000000000..56a59b805c
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/mainwindow.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QPixmap>
+
+class PuzzleWidget;
+class PiecesModel;
+QT_BEGIN_NAMESPACE
+class QListView;
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = nullptr);
+
+public slots:
+ void openImage();
+ void loadImage(const QString &path);
+ void setupPuzzle();
+
+private slots:
+ void setCompleted();
+
+private:
+ void setupMenus();
+ void setupWidgets();
+
+ QPixmap puzzleImage;
+ QListView *piecesList;
+ PuzzleWidget *puzzleWidget;
+ PiecesModel *model;
+};
+
+#endif // MAINWINDOW_H
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.cpp b/tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.cpp
new file mode 100644
index 0000000000..8e3ccf4aa3
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.cpp
@@ -0,0 +1,168 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "piecesmodel.h"
+
+#include <QIcon>
+#include <QMimeData>
+#include <QRandomGenerator>
+
+PiecesModel::PiecesModel(int pieceSize, QObject *parent)
+ : QAbstractListModel(parent), m_PieceSize(pieceSize)
+{
+}
+
+QVariant PiecesModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == Qt::DecorationRole)
+ return QIcon(pixmaps.value(index.row()).scaled(m_PieceSize, m_PieceSize,
+ Qt::KeepAspectRatio, Qt::SmoothTransformation));
+ else if (role == Qt::UserRole)
+ return pixmaps.value(index.row());
+ else if (role == Qt::UserRole + 1)
+ return locations.value(index.row());
+
+ return QVariant();
+}
+
+void PiecesModel::addPiece(const QPixmap &pixmap, const QPoint &location)
+{
+ int row;
+ if (QRandomGenerator::global()->bounded(2) == 1)
+ row = 0;
+ else
+ row = pixmaps.size();
+
+ beginInsertRows(QModelIndex(), row, row);
+ pixmaps.insert(row, pixmap);
+ locations.insert(row, location);
+ endInsertRows();
+}
+
+Qt::ItemFlags PiecesModel::flags(const QModelIndex &index) const
+{
+ if (index.isValid())
+ return (QAbstractListModel::flags(index)|Qt::ItemIsDragEnabled);
+
+ return Qt::ItemIsDropEnabled;
+}
+
+bool PiecesModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid())
+ return false;
+
+ if (row >= pixmaps.size() || row + count <= 0)
+ return false;
+
+ int beginRow = qMax(0, row);
+ int endRow = qMin(row + count - 1, pixmaps.size() - 1);
+
+ beginRemoveRows(parent, beginRow, endRow);
+
+ while (beginRow <= endRow) {
+ pixmaps.removeAt(beginRow);
+ locations.removeAt(beginRow);
+ ++beginRow;
+ }
+
+ endRemoveRows();
+ return true;
+}
+
+QStringList PiecesModel::mimeTypes() const
+{
+ QStringList types;
+ types << "image/x-puzzle-piece";
+ return types;
+}
+
+QMimeData *PiecesModel::mimeData(const QModelIndexList &indexes) const
+{
+ QMimeData *mimeData = new QMimeData();
+ QByteArray encodedData;
+
+ QDataStream stream(&encodedData, QDataStream::WriteOnly);
+
+ for (const QModelIndex &index : indexes) {
+ if (index.isValid()) {
+ QPixmap pixmap = qvariant_cast<QPixmap>(data(index, Qt::UserRole));
+ QPoint location = data(index, Qt::UserRole+1).toPoint();
+ stream << pixmap << location;
+ }
+ }
+
+ mimeData->setData("image/x-puzzle-piece", encodedData);
+ return mimeData;
+}
+
+bool PiecesModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
+ int row, int column, const QModelIndex &parent)
+{
+ if (!data->hasFormat("image/x-puzzle-piece"))
+ return false;
+
+ if (action == Qt::IgnoreAction)
+ return true;
+
+ if (column > 0)
+ return false;
+
+ int endRow;
+
+ if (!parent.isValid()) {
+ if (row < 0)
+ endRow = pixmaps.size();
+ else
+ endRow = qMin(row, pixmaps.size());
+ } else {
+ endRow = parent.row();
+ }
+
+ QByteArray encodedData = data->data("image/x-puzzle-piece");
+ QDataStream stream(&encodedData, QDataStream::ReadOnly);
+
+ while (!stream.atEnd()) {
+ QPixmap pixmap;
+ QPoint location;
+ stream >> pixmap >> location;
+
+ beginInsertRows(QModelIndex(), endRow, endRow);
+ pixmaps.insert(endRow, pixmap);
+ locations.insert(endRow, location);
+ endInsertRows();
+
+ ++endRow;
+ }
+
+ return true;
+}
+
+int PiecesModel::rowCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : pixmaps.size();
+}
+
+Qt::DropActions PiecesModel::supportedDropActions() const
+{
+ return Qt::CopyAction | Qt::MoveAction;
+}
+
+void PiecesModel::addPieces(const QPixmap &pixmap)
+{
+ if (!pixmaps.isEmpty()) {
+ beginRemoveRows(QModelIndex(), 0, pixmaps.size() - 1);
+ pixmaps.clear();
+ locations.clear();
+ endRemoveRows();
+ }
+ for (int y = 0; y < 5; ++y) {
+ for (int x = 0; x < 5; ++x) {
+ QPixmap pieceImage = pixmap.copy(x*m_PieceSize, y*m_PieceSize, m_PieceSize, m_PieceSize);
+ addPiece(pieceImage, QPoint(x, y));
+ }
+ }
+}
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.h b/tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.h
new file mode 100644
index 0000000000..878ed73a70
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef PIECESLIST_H
+#define PIECESLIST_H
+
+#include <QAbstractListModel>
+#include <QPixmap>
+#include <QPoint>
+#include <QStringList>
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+class QMimeData;
+QT_END_NAMESPACE
+
+class PiecesModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ explicit PiecesModel(int pieceSize, QObject *parent = nullptr);
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ bool removeRows(int row, int count, const QModelIndex &parent) override;
+
+ bool dropMimeData(const QMimeData *data, Qt::DropAction action,
+ int row, int column, const QModelIndex &parent) override;
+ QMimeData *mimeData(const QModelIndexList &indexes) const override;
+ QStringList mimeTypes() const override;
+ int rowCount(const QModelIndex &parent) const override;
+ Qt::DropActions supportedDropActions() const override;
+
+ void addPiece(const QPixmap &pixmap, const QPoint &location);
+ void addPieces(const QPixmap &pixmap);
+
+private:
+ QList<QPoint> locations;
+ QList<QPixmap> pixmaps;
+
+ int m_PieceSize;
+};
+
+#endif // PIECESLIST_H
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/puzzle.pro b/tests/manual/examples/widgets/itemviews/puzzle/puzzle.pro
new file mode 100644
index 0000000000..dcc27aae6a
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/puzzle.pro
@@ -0,0 +1,15 @@
+QT += widgets
+requires(qtConfig(listview))
+
+HEADERS = mainwindow.h \
+ piecesmodel.h \
+ puzzlewidget.h
+RESOURCES = puzzle.qrc
+SOURCES = main.cpp \
+ mainwindow.cpp \
+ piecesmodel.cpp \
+ puzzlewidget.cpp
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/puzzle
+INSTALLS += target
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/puzzle.qrc b/tests/manual/examples/widgets/itemviews/puzzle/puzzle.qrc
new file mode 100644
index 0000000000..4076cec026
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/puzzle.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/images">
+ <file>example.jpg</file>
+</qresource>
+</RCC>
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.cpp b/tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.cpp
new file mode 100644
index 0000000000..15aa6ac94f
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.cpp
@@ -0,0 +1,163 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "puzzlewidget.h"
+
+#include <QtWidgets>
+
+PuzzleWidget::PuzzleWidget(int imageSize, QWidget *parent)
+ : QWidget(parent), m_ImageSize(imageSize)
+{
+ setAcceptDrops(true);
+ setMinimumSize(m_ImageSize, m_ImageSize);
+ setMaximumSize(m_ImageSize, m_ImageSize);
+}
+
+void PuzzleWidget::clear()
+{
+ pieces.clear();
+ highlightedRect = QRect();
+ inPlace = 0;
+ update();
+}
+
+void PuzzleWidget::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasFormat("image/x-puzzle-piece"))
+ event->accept();
+ else
+ event->ignore();
+}
+
+void PuzzleWidget::dragLeaveEvent(QDragLeaveEvent *event)
+{
+ QRect updateRect = highlightedRect;
+ highlightedRect = QRect();
+ update(updateRect);
+ event->accept();
+}
+
+void PuzzleWidget::dragMoveEvent(QDragMoveEvent *event)
+{
+ QRect updateRect = highlightedRect.united(targetSquare(event->position().toPoint()));
+
+ if (event->mimeData()->hasFormat("image/x-puzzle-piece")
+ && findPiece(targetSquare(event->position().toPoint())) == -1) {
+
+ highlightedRect = targetSquare(event->position().toPoint());
+ event->setDropAction(Qt::MoveAction);
+ event->accept();
+ } else {
+ highlightedRect = QRect();
+ event->ignore();
+ }
+
+ update(updateRect);
+}
+
+void PuzzleWidget::dropEvent(QDropEvent *event)
+{
+ if (event->mimeData()->hasFormat("image/x-puzzle-piece")
+ && findPiece(targetSquare(event->position().toPoint())) == -1) {
+
+ QByteArray pieceData = event->mimeData()->data("image/x-puzzle-piece");
+ QDataStream dataStream(&pieceData, QIODevice::ReadOnly);
+ Piece piece;
+ piece.rect = targetSquare(event->position().toPoint());
+ dataStream >> piece.pixmap >> piece.location;
+
+ pieces.append(piece);
+
+ highlightedRect = QRect();
+ update(piece.rect);
+
+ event->setDropAction(Qt::MoveAction);
+ event->accept();
+
+ if (piece.location == piece.rect.topLeft() / pieceSize()) {
+ inPlace++;
+ if (inPlace == 25)
+ emit puzzleCompleted();
+ }
+ } else {
+ highlightedRect = QRect();
+ event->ignore();
+ }
+}
+
+int PuzzleWidget::findPiece(const QRect &pieceRect) const
+{
+ for (int i = 0, size = pieces.size(); i < size; ++i) {
+ if (pieces.at(i).rect == pieceRect)
+ return i;
+ }
+ return -1;
+}
+
+void PuzzleWidget::mousePressEvent(QMouseEvent *event)
+{
+ QRect square = targetSquare(event->position().toPoint());
+ int found = findPiece(square);
+
+ if (found == -1)
+ return;
+
+ Piece piece = pieces.takeAt(found);
+
+ if (piece.location == square.topLeft() / pieceSize())
+ inPlace--;
+
+ update(square);
+
+ QByteArray itemData;
+ QDataStream dataStream(&itemData, QIODevice::WriteOnly);
+
+ dataStream << piece.pixmap << piece.location;
+
+ QMimeData *mimeData = new QMimeData;
+ mimeData->setData("image/x-puzzle-piece", itemData);
+
+ QDrag *drag = new QDrag(this);
+ drag->setMimeData(mimeData);
+ drag->setHotSpot(event->position().toPoint() - square.topLeft());
+ drag->setPixmap(piece.pixmap);
+
+ if (drag->exec(Qt::MoveAction) == Qt::IgnoreAction) {
+ pieces.insert(found, piece);
+ update(targetSquare(event->position().toPoint()));
+
+ if (piece.location == QPoint(square.x() / pieceSize(), square.y() / pieceSize()))
+ inPlace++;
+ }
+}
+
+void PuzzleWidget::paintEvent(QPaintEvent *event)
+{
+ QPainter painter(this);
+ painter.fillRect(event->rect(), Qt::white);
+
+ if (highlightedRect.isValid()) {
+ painter.setBrush(QColor("#ffcccc"));
+ painter.setPen(Qt::NoPen);
+ painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1));
+ }
+
+ for (const Piece &piece : pieces)
+ painter.drawPixmap(piece.rect, piece.pixmap);
+}
+
+const QRect PuzzleWidget::targetSquare(const QPoint &position) const
+{
+ QPoint topLeft = QPoint(position.x() / pieceSize(), position.y() / pieceSize()) * pieceSize();
+ return QRect(topLeft, QSize(pieceSize(), pieceSize()));
+}
+
+int PuzzleWidget::pieceSize() const
+{
+ return m_ImageSize / 5;
+}
+
+int PuzzleWidget::imageSize() const
+{
+ return m_ImageSize;
+}
diff --git a/tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.h b/tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.h
new file mode 100644
index 0000000000..d1c00872ec
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef PUZZLEWIDGET_H
+#define PUZZLEWIDGET_H
+
+#include <QPoint>
+#include <QPixmap>
+#include <QList>
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QDragEnterEvent;
+class QDropEvent;
+class QMouseEvent;
+QT_END_NAMESPACE
+
+class PuzzleWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit PuzzleWidget(int imageSize, QWidget *parent = nullptr);
+ void clear();
+
+ int pieceSize() const;
+ int imageSize() const;
+
+signals:
+ void puzzleCompleted();
+
+protected:
+ void dragEnterEvent(QDragEnterEvent *event) override;
+ void dragLeaveEvent(QDragLeaveEvent *event) override;
+ void dragMoveEvent(QDragMoveEvent *event) override;
+ void dropEvent(QDropEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void paintEvent(QPaintEvent *event) override;
+
+private:
+ struct Piece {
+ QPixmap pixmap;
+ QRect rect;
+ QPoint location;
+ };
+
+ int findPiece(const QRect &pieceRect) const;
+ const QRect targetSquare(const QPoint &position) const;
+
+ QList<Piece> pieces;
+ QRect highlightedRect;
+ int inPlace;
+ int m_ImageSize;
+};
+
+#endif // PUZZLEWIDGET_H
diff --git a/tests/manual/examples/widgets/itemviews/simpledommodel/CMakeLists.txt b/tests/manual/examples/widgets/itemviews/simpledommodel/CMakeLists.txt
new file mode 100644
index 0000000000..20d0aeedde
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simpledommodel/CMakeLists.txt
@@ -0,0 +1,40 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(simpledommodel LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/simpledommodel")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Xml)
+
+qt_standard_project_setup()
+
+qt_add_executable(simpledommodel
+ domitem.cpp domitem.h
+ dommodel.cpp dommodel.h
+ main.cpp
+ mainwindow.cpp mainwindow.h
+)
+
+set_target_properties(simpledommodel PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(simpledommodel PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+ Qt6::Xml
+)
+
+install(TARGETS simpledommodel
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/itemviews/simpledommodel/domitem.cpp b/tests/manual/examples/widgets/itemviews/simpledommodel/domitem.cpp
new file mode 100644
index 0000000000..b3e197b3db
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simpledommodel/domitem.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "domitem.h"
+
+#include <QtXml>
+
+//! [0]
+DomItem::DomItem(const QDomNode &node, int row, DomItem *parent)
+ : domNode(node),
+//! [0]
+ // Record the item's location within its parent.
+//! [1]
+ parentItem(parent),
+ rowNumber(row)
+{}
+//! [1]
+
+//! [2]
+DomItem::~DomItem()
+{
+ qDeleteAll(childItems);
+}
+//! [2]
+
+//! [3]
+QDomNode DomItem::node() const
+{
+ return domNode;
+}
+//! [3]
+
+//! [4]
+DomItem *DomItem::parent()
+{
+ return parentItem;
+}
+//! [4]
+
+//! [5]
+DomItem *DomItem::child(int i)
+{
+ DomItem *childItem = childItems.value(i);
+ if (childItem)
+ return childItem;
+
+ // if child does not yet exist, create it
+ if (i >= 0 && i < domNode.childNodes().count()) {
+ QDomNode childNode = domNode.childNodes().item(i);
+ childItem = new DomItem(childNode, i, this);
+ childItems[i] = childItem;
+ }
+ return childItem;
+}
+//! [5]
+
+//! [6]
+int DomItem::row() const
+{
+ return rowNumber;
+}
+//! [6]
diff --git a/tests/manual/examples/widgets/itemviews/simpledommodel/domitem.h b/tests/manual/examples/widgets/itemviews/simpledommodel/domitem.h
new file mode 100644
index 0000000000..9b02d8e88c
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simpledommodel/domitem.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef DOMITEM_H
+#define DOMITEM_H
+
+#include <QDomNode>
+#include <QHash>
+
+//! [0]
+class DomItem
+{
+public:
+ DomItem(const QDomNode &node, int row, DomItem *parent = nullptr);
+ ~DomItem();
+ DomItem *child(int i);
+ DomItem *parent();
+ QDomNode node() const;
+ int row() const;
+
+private:
+ QDomNode domNode;
+ QHash<int, DomItem *> childItems;
+ DomItem *parentItem;
+ int rowNumber;
+};
+//! [0]
+
+#endif // DOMITEM_H
diff --git a/tests/manual/examples/widgets/itemviews/simpledommodel/dommodel.cpp b/tests/manual/examples/widgets/itemviews/simpledommodel/dommodel.cpp
new file mode 100644
index 0000000000..17f05c8be3
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simpledommodel/dommodel.cpp
@@ -0,0 +1,153 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "dommodel.h"
+#include "domitem.h"
+
+#include <QtXml>
+
+//! [0]
+DomModel::DomModel(const QDomDocument &document, QObject *parent)
+ : QAbstractItemModel(parent),
+ domDocument(document),
+ rootItem(new DomItem(domDocument, 0))
+{
+}
+//! [0]
+
+//! [1]
+DomModel::~DomModel()
+{
+ delete rootItem;
+}
+//! [1]
+
+//! [2]
+int DomModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 3;
+}
+//! [2]
+
+//! [3]
+QVariant DomModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ const DomItem *item = static_cast<DomItem*>(index.internalPointer());
+
+ const QDomNode node = item->node();
+//! [3] //! [4]
+
+ switch (index.column()) {
+ case 0:
+ return node.nodeName();
+ case 1:
+ {
+ const QDomNamedNodeMap attributeMap = node.attributes();
+ QStringList attributes;
+ for (int i = 0; i < attributeMap.count(); ++i) {
+ QDomNode attribute = attributeMap.item(i);
+ attributes << attribute.nodeName() + "=\""
+ + attribute.nodeValue() + '"';
+ }
+ return attributes.join(' ');
+ }
+ case 2:
+ return node.nodeValue().split('\n').join(' ');
+ default:
+ break;
+ }
+ return QVariant();
+}
+//! [4]
+
+//! [5]
+Qt::ItemFlags DomModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ return QAbstractItemModel::flags(index);
+}
+//! [5]
+
+//! [6]
+QVariant DomModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ switch (section) {
+ case 0:
+ return tr("Name");
+ case 1:
+ return tr("Attributes");
+ case 2:
+ return tr("Value");
+ default:
+ break;
+ }
+ }
+ return QVariant();
+}
+//! [6]
+
+//! [7]
+QModelIndex DomModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (!hasIndex(row, column, parent))
+ return QModelIndex();
+
+ DomItem *parentItem;
+
+ if (!parent.isValid())
+ parentItem = rootItem;
+ else
+ parentItem = static_cast<DomItem*>(parent.internalPointer());
+//! [7]
+
+//! [8]
+ DomItem *childItem = parentItem->child(row);
+ if (childItem)
+ return createIndex(row, column, childItem);
+ return QModelIndex();
+}
+//! [8]
+
+//! [9]
+QModelIndex DomModel::parent(const QModelIndex &child) const
+{
+ if (!child.isValid())
+ return QModelIndex();
+
+ DomItem *childItem = static_cast<DomItem*>(child.internalPointer());
+ DomItem *parentItem = childItem->parent();
+
+ if (!parentItem || parentItem == rootItem)
+ return QModelIndex();
+
+ return createIndex(parentItem->row(), 0, parentItem);
+}
+//! [9]
+
+//! [10]
+int DomModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.column() > 0)
+ return 0;
+
+ DomItem *parentItem;
+
+ if (!parent.isValid())
+ parentItem = rootItem;
+ else
+ parentItem = static_cast<DomItem*>(parent.internalPointer());
+
+ return parentItem->node().childNodes().count();
+}
+//! [10]
diff --git a/tests/manual/examples/widgets/itemviews/simpledommodel/dommodel.h b/tests/manual/examples/widgets/itemviews/simpledommodel/dommodel.h
new file mode 100644
index 0000000000..109ab33e58
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simpledommodel/dommodel.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef DOMMODEL_H
+#define DOMMODEL_H
+
+#include <QAbstractItemModel>
+#include <QDomDocument>
+#include <QModelIndex>
+
+class DomItem;
+
+//! [0]
+class DomModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ explicit DomModel(const QDomDocument &document, QObject *parent = nullptr);
+ ~DomModel();
+
+ QVariant data(const QModelIndex &index, int role) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const override;
+ QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &child) const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+
+private:
+ QDomDocument domDocument;
+ DomItem *rootItem;
+};
+//! [0]
+
+#endif // DOMMODEL_H
diff --git a/tests/manual/examples/widgets/itemviews/simpledommodel/main.cpp b/tests/manual/examples/widgets/itemviews/simpledommodel/main.cpp
new file mode 100644
index 0000000000..2ea03356f2
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simpledommodel/main.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow window;
+ window.resize(640, 480);
+ window.show();
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/itemviews/simpledommodel/mainwindow.cpp b/tests/manual/examples/widgets/itemviews/simpledommodel/mainwindow.cpp
new file mode 100644
index 0000000000..ad64863fbb
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simpledommodel/mainwindow.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+#include "dommodel.h"
+
+#include <QDomDocument>
+#include <QTreeView>
+#include <QMenuBar>
+#include <QFileDialog>
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent),
+ model(new DomModel(QDomDocument(), this)),
+ view(new QTreeView(this))
+{
+ fileMenu = menuBar()->addMenu(tr("&File"));
+ fileMenu->addAction(tr("&Open..."), QKeySequence::Open, this, &MainWindow::openFile);
+ fileMenu->addAction(tr("E&xit"), QKeySequence::Quit, this, &QWidget::close);
+
+ view->setModel(model);
+
+ setCentralWidget(view);
+ setWindowTitle(tr("Simple DOM Model"));
+}
+
+void MainWindow::openFile()
+{
+ QString filePath = QFileDialog::getOpenFileName(this, tr("Open File"),
+ xmlPath, tr("XML files (*.xml);;HTML files (*.html);;"
+ "SVG files (*.svg);;User Interface files (*.ui)"));
+
+ if (!filePath.isEmpty()) {
+ QFile file(filePath);
+ if (file.open(QIODevice::ReadOnly)) {
+ QDomDocument document;
+ if (document.setContent(&file)) {
+ DomModel *newModel = new DomModel(document, this);
+ view->setModel(newModel);
+ delete model;
+ model = newModel;
+ xmlPath = filePath;
+ }
+ file.close();
+ }
+ }
+}
diff --git a/tests/manual/examples/widgets/itemviews/simpledommodel/mainwindow.h b/tests/manual/examples/widgets/itemviews/simpledommodel/mainwindow.h
new file mode 100644
index 0000000000..a82f3956c8
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simpledommodel/mainwindow.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QString>
+
+class DomModel;
+QT_BEGIN_NAMESPACE
+class QMenu;
+class QTreeView;
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+
+public slots:
+ void openFile();
+
+private:
+ DomModel *model;
+ QMenu *fileMenu;
+ QString xmlPath;
+ QTreeView *view;
+};
+
+#endif // MAINWINDOW_H
diff --git a/tests/manual/examples/widgets/itemviews/simpledommodel/simpledommodel.pro b/tests/manual/examples/widgets/itemviews/simpledommodel/simpledommodel.pro
new file mode 100644
index 0000000000..3d45920e36
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simpledommodel/simpledommodel.pro
@@ -0,0 +1,14 @@
+HEADERS = domitem.h \
+ dommodel.h \
+ mainwindow.h
+SOURCES = domitem.cpp \
+ dommodel.cpp \
+ main.cpp \
+ mainwindow.cpp
+QT += xml widgets
+requires(qtConfig(filedialog))
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/simpledommodel
+INSTALLS += target
+
diff --git a/tests/manual/examples/widgets/itemviews/simplewidgetmapper/CMakeLists.txt b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/CMakeLists.txt
new file mode 100644
index 0000000000..c62dbc0306
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(simplewidgetmapper LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/simplewidgetmapper")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(simplewidgetmapper
+ main.cpp
+ window.cpp window.h
+)
+
+set_target_properties(simplewidgetmapper PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(simplewidgetmapper PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+install(TARGETS simplewidgetmapper
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/itemviews/simplewidgetmapper/main.cpp b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/main.cpp
new file mode 100644
index 0000000000..2709c948f9
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/main.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "window.h"
+
+#include <QApplication>
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ Window window;
+ window.show();
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/itemviews/simplewidgetmapper/simplewidgetmapper.pro b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/simplewidgetmapper.pro
new file mode 100644
index 0000000000..f86a16bd3f
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/simplewidgetmapper.pro
@@ -0,0 +1,10 @@
+QT += widgets
+requires(qtConfig(datawidgetmapper))
+
+HEADERS = window.h
+SOURCES = main.cpp \
+ window.cpp
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/simplewidgetmapper
+INSTALLS += target
diff --git a/tests/manual/examples/widgets/itemviews/simplewidgetmapper/window.cpp b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/window.cpp
new file mode 100644
index 0000000000..f7ef05dbd5
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/window.cpp
@@ -0,0 +1,93 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "window.h"
+
+#include <QtWidgets>
+
+//! [Set up widgets]
+Window::Window(QWidget *parent)
+ : QWidget(parent)
+{
+ setupModel();
+
+ nameLabel = new QLabel(tr("Na&me:"));
+ nameEdit = new QLineEdit();
+ addressLabel = new QLabel(tr("&Address:"));
+ addressEdit = new QTextEdit();
+ ageLabel = new QLabel(tr("A&ge (in years):"));
+ ageSpinBox = new QSpinBox();
+ nextButton = new QPushButton(tr("&Next"));
+ previousButton = new QPushButton(tr("&Previous"));
+
+ nameLabel->setBuddy(nameEdit);
+ addressLabel->setBuddy(addressEdit);
+ ageLabel->setBuddy(ageSpinBox);
+//! [Set up widgets]
+
+//! [Set up the mapper]
+ mapper = new QDataWidgetMapper(this);
+ mapper->setModel(model);
+ mapper->addMapping(nameEdit, 0);
+ mapper->addMapping(addressEdit, 1);
+ mapper->addMapping(ageSpinBox, 2);
+
+ connect(previousButton, &QAbstractButton::clicked, mapper, &QDataWidgetMapper::toPrevious);
+ connect(nextButton, &QAbstractButton::clicked, mapper, &QDataWidgetMapper::toNext);
+ connect(mapper, &QDataWidgetMapper::currentIndexChanged, this, &Window::updateButtons);
+//! [Set up the mapper]
+
+//! [Set up the layout]
+ QGridLayout *layout = new QGridLayout();
+ layout->addWidget(nameLabel, 0, 0, 1, 1);
+ layout->addWidget(nameEdit, 0, 1, 1, 1);
+ layout->addWidget(previousButton, 0, 2, 1, 1);
+ layout->addWidget(addressLabel, 1, 0, 1, 1);
+ layout->addWidget(addressEdit, 1, 1, 2, 1);
+ layout->addWidget(nextButton, 1, 2, 1, 1);
+ layout->addWidget(ageLabel, 3, 0, 1, 1);
+ layout->addWidget(ageSpinBox, 3, 1, 1, 1);
+ setLayout(layout);
+
+ setWindowTitle(tr("Simple Widget Mapper"));
+ mapper->toFirst();
+}
+//! [Set up the layout]
+
+//! [Set up the model]
+void Window::setupModel()
+{
+ model = new QStandardItemModel(5, 3, this);
+
+ QStringList names;
+ names << "Alice" << "Bob" << "Carol" << "Donald" << "Emma";
+
+ QStringList addresses;
+ addresses << "<qt>123 Main Street<br/>Market Town</qt>"
+ << "<qt>PO Box 32<br/>Mail Handling Service"
+ "<br/>Service City</qt>"
+ << "<qt>The Lighthouse<br/>Remote Island</qt>"
+ << "<qt>47338 Park Avenue<br/>Big City</qt>"
+ << "<qt>Research Station<br/>Base Camp<br/>Big Mountain</qt>";
+
+ QStringList ages;
+ ages << "20" << "31" << "32" << "19" << "26";
+
+ for (int row = 0; row < 5; ++row) {
+ QStandardItem *item = new QStandardItem(names[row]);
+ model->setItem(row, 0, item);
+ item = new QStandardItem(addresses[row]);
+ model->setItem(row, 1, item);
+ item = new QStandardItem(ages[row]);
+ model->setItem(row, 2, item);
+ }
+}
+//! [Set up the model]
+
+//! [Slot for updating the buttons]
+void Window::updateButtons(int row)
+{
+ previousButton->setEnabled(row > 0);
+ nextButton->setEnabled(row < model->rowCount() - 1);
+}
+//! [Slot for updating the buttons]
diff --git a/tests/manual/examples/widgets/itemviews/simplewidgetmapper/window.h b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/window.h
new file mode 100644
index 0000000000..1502c00df1
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/simplewidgetmapper/window.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QDataWidgetMapper;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QSpinBox;
+class QStandardItemModel;
+class QTextEdit;
+QT_END_NAMESPACE
+
+//! [Window definition]
+class Window : public QWidget
+{
+ Q_OBJECT
+
+public:
+ Window(QWidget *parent = nullptr);
+
+private slots:
+ void updateButtons(int row);
+
+private:
+ void setupModel();
+
+ QLabel *nameLabel;
+ QLabel *addressLabel;
+ QLabel *ageLabel;
+ QLineEdit *nameEdit;
+ QTextEdit *addressEdit;
+ QSpinBox *ageSpinBox;
+ QPushButton *nextButton;
+ QPushButton *previousButton;
+
+ QStandardItemModel *model;
+ QDataWidgetMapper *mapper;
+};
+//! [Window definition]
+
+#endif // WINDOW_H
diff --git a/tests/manual/examples/widgets/itemviews/storageview/CMakeLists.txt b/tests/manual/examples/widgets/itemviews/storageview/CMakeLists.txt
new file mode 100644
index 0000000000..36c37d037f
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/storageview/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(storageview LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/storageview")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(storageview
+ main.cpp
+ storagemodel.cpp storagemodel.h
+)
+
+set_target_properties(storageview PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(storageview PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+install(TARGETS storageview
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/itemviews/storageview/main.cpp b/tests/manual/examples/widgets/itemviews/storageview/main.cpp
new file mode 100644
index 0000000000..3bd5392736
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/storageview/main.cpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Ivan Komissarov
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QApplication>
+#include <QShortcut>
+#include <QTreeView>
+
+#include "storagemodel.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ QTreeView view;
+ view.resize(640, 480);
+ view.setWindowTitle("Storage View");
+ view.setSelectionBehavior(QAbstractItemView::SelectRows);
+
+ StorageModel *model = new StorageModel(&view);
+ model->refresh();
+ QShortcut *refreshShortcut = new QShortcut(QKeySequence::Refresh, &view);
+ QObject::connect(refreshShortcut, &QShortcut::activated, model, &StorageModel::refresh);
+ view.setModel(model);
+
+ int columnCount = view.model()->columnCount();
+ for (int c = 0; c < columnCount; ++c)
+ view.resizeColumnToContents(c);
+ view.show();
+
+ return a.exec();
+}
diff --git a/tests/manual/examples/widgets/itemviews/storageview/storagemodel.cpp b/tests/manual/examples/widgets/itemviews/storageview/storagemodel.cpp
new file mode 100644
index 0000000000..194f8723f6
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/storageview/storagemodel.cpp
@@ -0,0 +1,164 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Ivan Komissarov
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "storagemodel.h"
+
+#include <QDir>
+#include <QLocale>
+
+void StorageModel::refresh()
+{
+ beginResetModel();
+ m_volumes = QStorageInfo::mountedVolumes();
+ std::sort(m_volumes.begin(), m_volumes.end(),
+ [](const QStorageInfo &st1, const QStorageInfo &st2) {
+ static const QString rootSortString = QStringLiteral(" ");
+ return (st1.isRoot() ? rootSortString : st1.rootPath())
+ < (st2.isRoot() ? rootSortString : st2.rootPath());
+ });
+ endResetModel();
+}
+
+int StorageModel::columnCount(const QModelIndex &/*parent*/) const
+{
+ return ColumnCount;
+}
+
+int StorageModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return m_volumes.count();
+}
+
+Qt::ItemFlags StorageModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags result = QAbstractTableModel::flags(index);
+ switch (index.column()) {
+ case ColumnAvailable:
+ case ColumnIsReady:
+ case ColumnIsReadOnly:
+ case ColumnIsValid:
+ result |= Qt::ItemIsUserCheckable;
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+QVariant StorageModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == Qt::DisplayRole) {
+ const QStorageInfo &volume = m_volumes.at(index.row());
+ switch (index.column()) {
+ case ColumnRootPath:
+ return QDir::toNativeSeparators(volume.rootPath());
+ case ColumnName:
+ return volume.name();
+ case ColumnDevice:
+ return volume.device();
+ case ColumnFileSystemName:
+ return volume.fileSystemType();
+ case ColumnTotal:
+ return QLocale().formattedDataSize(volume.bytesTotal());
+ case ColumnFree:
+ return QLocale().formattedDataSize(volume.bytesFree());
+ case ColumnAvailable:
+ return QLocale().formattedDataSize(volume.bytesAvailable());
+ default:
+ break;
+ }
+ } else if (role == Qt::CheckStateRole) {
+ const QStorageInfo &volume = m_volumes.at(index.row());
+ switch (index.column()) {
+ case ColumnIsReady:
+ return volume.isReady();
+ case ColumnIsReadOnly:
+ return volume.isReadOnly();
+ case ColumnIsValid:
+ return volume.isValid();
+ default:
+ break;
+ }
+ } else if (role == Qt::TextAlignmentRole) {
+ switch (index.column()) {
+ case ColumnTotal:
+ case ColumnFree:
+ case ColumnAvailable:
+ return Qt::AlignTrailing;
+ default:
+ break;
+ }
+ return Qt::AlignLeading;
+ } else if (role == Qt::ToolTipRole) {
+ QLocale locale;
+ const QStorageInfo &volume = m_volumes.at(index.row());
+ return tr("Root path : %1\n"
+ "Name: %2\n"
+ "Display Name: %3\n"
+ "Device: %4\n"
+ "FileSystem: %5\n"
+ "Total size: %6\n"
+ "Free size: %7\n"
+ "Available size: %8\n"
+ "Is Ready: %9\n"
+ "Is Read-only: %10\n"
+ "Is Valid: %11\n"
+ "Is Root: %12"
+ ).
+ arg(QDir::toNativeSeparators(volume.rootPath())).
+ arg(volume.name()).
+ arg(volume.displayName()).
+ arg(QString::fromUtf8(volume.device())).
+ arg(QString::fromUtf8(volume.fileSystemType())).
+ arg(locale.formattedDataSize(volume.bytesTotal())).
+ arg(locale.formattedDataSize(volume.bytesFree())).
+ arg(locale.formattedDataSize(volume.bytesAvailable())).
+ arg(volume.isReady() ? tr("true") : tr("false")).
+ arg(volume.isReadOnly() ? tr("true") : tr("false")).
+ arg(volume.isValid() ? tr("true") : tr("false")).
+ arg(volume.isRoot() ? tr("true") : tr("false"));
+ }
+ return QVariant();
+}
+
+QVariant StorageModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation != Qt::Horizontal)
+ return QVariant();
+
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ switch (section) {
+ case ColumnRootPath:
+ return tr("Root Path");
+ case ColumnName:
+ return tr("Volume Name");
+ case ColumnDevice:
+ return tr("Device");
+ case ColumnFileSystemName:
+ return tr("File System");
+ case ColumnTotal:
+ return tr("Total");
+ case ColumnFree:
+ return tr("Free");
+ case ColumnAvailable:
+ return tr("Available");
+ case ColumnIsReady:
+ return tr("Ready");
+ case ColumnIsReadOnly:
+ return tr("Read-only");
+ case ColumnIsValid:
+ return tr("Valid");
+ default:
+ break;
+ }
+
+ return QVariant();
+}
diff --git a/tests/manual/examples/widgets/itemviews/storageview/storagemodel.h b/tests/manual/examples/widgets/itemviews/storageview/storagemodel.h
new file mode 100644
index 0000000000..f8cc3289c8
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/storageview/storagemodel.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Ivan Komissarov
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef STORAGEMODEL_H
+#define STORAGEMODEL_H
+
+#include <QAbstractTableModel>
+#include <QStorageInfo>
+
+class StorageModel : public QAbstractTableModel
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(StorageModel)
+public:
+ enum Column {
+ ColumnRootPath = 0,
+ ColumnName,
+ ColumnDevice,
+ ColumnFileSystemName,
+ ColumnTotal,
+ ColumnFree,
+ ColumnAvailable,
+ ColumnIsReady,
+ ColumnIsReadOnly,
+ ColumnIsValid,
+ ColumnCount
+ };
+
+ using QAbstractTableModel::QAbstractTableModel;
+
+ int columnCount(const QModelIndex &parent) const override;
+ int rowCount(const QModelIndex &parent) const override;
+
+ QVariant data(const QModelIndex &index, int role) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+
+public slots:
+ void refresh();
+
+private:
+ QList<QStorageInfo> m_volumes;
+};
+
+#endif // STORAGEMODEL_H
diff --git a/tests/manual/examples/widgets/itemviews/storageview/storageview.pro b/tests/manual/examples/widgets/itemviews/storageview/storageview.pro
new file mode 100644
index 0000000000..2fdb78e7b8
--- /dev/null
+++ b/tests/manual/examples/widgets/itemviews/storageview/storageview.pro
@@ -0,0 +1,12 @@
+QT += core gui widgets
+requires(qtConfig(treeview))
+TARGET = storageview
+TEMPLATE = app
+SOURCES += storagemodel.cpp \
+ main.cpp
+HEADERS += \
+ storagemodel.h
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/storageview
+INSTALLS += target