diff options
Diffstat (limited to 'tests/manual/examples/widgets/itemviews')
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 Binary files differnew file mode 100644 index 0000000000..589fd2df59 --- /dev/null +++ b/tests/manual/examples/widgets/itemviews/interview/images/folder.png diff --git a/tests/manual/examples/widgets/itemviews/interview/images/interview.png b/tests/manual/examples/widgets/itemviews/interview/images/interview.png Binary files differnew file mode 100644 index 0000000000..0c3d690258 --- /dev/null +++ b/tests/manual/examples/widgets/itemviews/interview/images/interview.png diff --git a/tests/manual/examples/widgets/itemviews/interview/images/services.png b/tests/manual/examples/widgets/itemviews/interview/images/services.png Binary files differnew file mode 100644 index 0000000000..6b2ad969d4 --- /dev/null +++ b/tests/manual/examples/widgets/itemviews/interview/images/services.png 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 Binary files differnew file mode 100644 index 0000000000..dd197cb59c --- /dev/null +++ b/tests/manual/examples/widgets/itemviews/pixelator/images/qt.png 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 Binary files differnew file mode 100644 index 0000000000..023203c57a --- /dev/null +++ b/tests/manual/examples/widgets/itemviews/puzzle/example.jpg 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 |