aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarek Kobus <jaroslaw.kobus@qt.io>2023-06-03 01:34:32 +0200
committerJarek Kobus <jaroslaw.kobus@qt.io>2023-06-07 09:27:40 +0000
commit04b86eb3db9a42b2e3bf0e5c23f2bcb261002dbb (patch)
tree4263ba8e4fe69eabc5c51cd90182aaa344dd1393
parent2d128e9c707791f3ea127322c18fdee828e685ab (diff)
ImageScaling: Implement the example using TaskTree
Change-Id: Iac54157955d5dffe12a7fdeed904fbcf62a2b667 Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
-rw-r--r--tests/manual/tasking/imagescaling/imagescaling.cpp205
-rw-r--r--tests/manual/tasking/imagescaling/imagescaling.h29
2 files changed, 73 insertions, 161 deletions
diff --git a/tests/manual/tasking/imagescaling/imagescaling.cpp b/tests/manual/tasking/imagescaling/imagescaling.cpp
index 362a30287e..e3acda749b 100644
--- a/tests/manual/tasking/imagescaling/imagescaling.cpp
+++ b/tests/manual/tasking/imagescaling/imagescaling.cpp
@@ -3,19 +3,24 @@
#include "imagescaling.h"
#include "downloaddialog.h"
+#include <tasking/concurrentcall.h>
+#include <tasking/networkquery.h>
-#include <QNetworkReply>
+using namespace Tasking;
Images::Images(QWidget *parent) : QWidget(parent), downloadDialog(new DownloadDialog(this))
{
resize(800, 600);
- addUrlsButton = new QPushButton(tr("Add URLs"));
+ QPushButton *addUrlsButton = new QPushButton(tr("Add URLs"));
connect(addUrlsButton, &QPushButton::clicked, this, &Images::process);
cancelButton = new QPushButton(tr("Cancel"));
cancelButton->setEnabled(false);
- connect(cancelButton, &QPushButton::clicked, this, &Images::cancel);
+ connect(cancelButton, &QPushButton::clicked, this, [this] {
+ statusBar->showMessage(tr("Canceled."));
+ taskTree.reset();
+ });
QHBoxLayout *buttonLayout = new QHBoxLayout();
buttonLayout->addWidget(addUrlsButton);
@@ -32,141 +37,77 @@ Images::Images(QWidget *parent) : QWidget(parent), downloadDialog(new DownloadDi
mainLayout->addStretch();
mainLayout->addWidget(statusBar);
setLayout(mainLayout);
-
- connect(&scalingWatcher, &QFutureWatcher<QList<QImage>>::finished,
- this, &Images::scaleFinished);
}
-Images::~Images()
+static void scale(QPromise<QImage> &promise, const QByteArray &data)
{
- cancel();
+ const auto image = QImage::fromData(data);
+ if (image.isNull())
+ promise.future().cancel();
+ else
+ promise.addResult(image.scaled(100, 100, Qt::KeepAspectRatio));
}
void Images::process()
{
- // Clean previous state
- replies.clear();
- addUrlsButton->setEnabled(false);
-
- if (downloadDialog->exec() == QDialog::Accepted) {
+ if (downloadDialog->exec() != QDialog::Accepted)
+ return;
- const auto urls = downloadDialog->getUrls();
- if (urls.empty())
- return;
+ const auto urls = downloadDialog->getUrls();
+ initLayout(urls.size());
+ const auto onRootSetup = [this] {
+ statusBar->showMessage(tr("Downloading and Scaling..."));
cancelButton->setEnabled(true);
-
- initLayout(urls.size());
-
- downloadFuture = download(urls);
- statusBar->showMessage(tr("Downloading..."));
-
- downloadFuture
- .then([this](auto) {
- cancelButton->setEnabled(false);
- updateStatus(tr("Scaling..."));
- scalingWatcher.setFuture(QtConcurrent::run(Images::scaled,
- downloadFuture.results()));
- })
- .onCanceled([this] {
- updateStatus(tr("Download has been canceled."));
- })
- .onFailed([this](QNetworkReply::NetworkError error) {
- updateStatus(tr("Download finished with error: %1").arg(error));
- // Abort all pending requests
- abortDownload();
- })
- .onFailed([this](const std::exception &ex) {
- updateStatus(tr(ex.what()));
- })
- .then([this]() {
- cancelButton->setEnabled(false);
- addUrlsButton->setEnabled(true);
- });
- }
-}
-
-void Images::cancel()
-{
- statusBar->showMessage(tr("Canceling..."));
-
- downloadFuture.cancel();
- abortDownload();
-}
-
-void Images::scaleFinished()
-{
- const OptionalImages result = scalingWatcher.result();
- if (result.has_value()) {
- const auto scaled = result.value();
- showImages(scaled);
- updateStatus(tr("Finished"));
- } else {
- updateStatus(tr("Failed to extract image data."));
- }
- addUrlsButton->setEnabled(true);
-}
-
-QFuture<QByteArray> Images::download(const QList<QUrl> &urls)
-{
- QSharedPointer<QPromise<QByteArray>> promise(new QPromise<QByteArray>());
- promise->start();
-
- for (const auto &url : urls) {
- QSharedPointer<QNetworkReply> reply(qnam.get(QNetworkRequest(url)));
- replies.push_back(reply);
-
- QtFuture::connect(reply.get(), &QNetworkReply::finished).then([=] {
- if (promise->isCanceled()) {
- if (!promise->future().isFinished())
- promise->finish();
- return;
- }
-
- if (reply->error() != QNetworkReply::NoError) {
- if (!promise->future().isFinished())
- throw reply->error();
- }
- promise->addResult(reply->readAll());
-
- // Report finished on the last download
- if (promise->future().resultCount() == urls.size())
- promise->finish();
- }).onFailed([promise] (QNetworkReply::NetworkError error) {
- promise->setException(std::make_exception_ptr(error));
- promise->finish();
- }).onFailed([promise] {
- const auto ex = std::make_exception_ptr(
- std::runtime_error("Unknown error occurred while downloading."));
- promise->setException(ex);
- promise->finish();
- });
+ };
+ const auto onRootDone = [this] {
+ statusBar->showMessage(tr("Finished."));
+ cancelButton->setEnabled(false);
+ };
+ QList<GroupItem> tasks {
+ finishAllAndDone,
+ parallel,
+ onGroupSetup(onRootSetup),
+ onGroupDone(onRootDone)
+ };
+
+ int i = 0;
+ for (const QUrl &url : urls) {
+ TreeStorage<QByteArray> storage;
+
+ const auto onDownloadSetup = [this, url](NetworkQuery &query) {
+ query.setNetworkAccessManager(&qnam);
+ query.setRequest(QNetworkRequest(url));
+ };
+ const auto onDownloadDone = [storage](const NetworkQuery &query) {
+ *storage = query.reply()->readAll();
+ };
+ const auto onDownloadError = [this, i](const NetworkQuery &query) {
+ labels[i]->setText(tr("Download\nError.\nCode: %1.").arg(query.reply()->error()));
+ };
+
+ const auto onScalingSetup = [storage](ConcurrentCall<QImage> &data) {
+ data.setConcurrentCallData(&scale, *storage);
+ };
+ const auto onScalingDone = [this, i](const ConcurrentCall<QImage> &data) {
+ labels[i]->setPixmap(QPixmap::fromImage(data.result()));
+ };
+ const auto onScalingError = [this, i](const ConcurrentCall<QImage> &) {
+ labels[i]->setText(tr("Image\nData\nError."));
+ };
+
+ const Group group {
+ Storage(storage),
+ NetworkQueryTask(onDownloadSetup, onDownloadDone, onDownloadError),
+ ConcurrentCallTask<QImage>(onScalingSetup, onScalingDone, onScalingError)
+ };
+ tasks.append(group);
+ ++i;
}
- return promise->future();
-}
-
-Images::OptionalImages Images::scaled(const QList<QByteArray> &data)
-{
- QList<QImage> scaled;
- for (const auto &imgData : data) {
- QImage image;
- image.loadFromData(imgData);
- if (image.isNull())
- return std::nullopt;
-
- scaled.push_back(image.scaled(100, 100, Qt::KeepAspectRatio));
- }
-
- return scaled;
-}
-
-void Images::showImages(const QList<QImage> &images)
-{
- for (int i = 0; i < images.size(); ++i) {
- labels[i]->setAlignment(Qt::AlignCenter);
- labels[i]->setPixmap(QPixmap::fromImage(images[i]));
- }
+ taskTree.reset(new TaskTree(tasks));
+ connect(taskTree.get(), &TaskTree::done, this, [this] { taskTree.release()->deleteLater(); });
+ taskTree->start();
}
void Images::initLayout(qsizetype count)
@@ -186,19 +127,9 @@ void Images::initLayout(qsizetype count)
for (int j = 0; j < dim; ++j) {
QLabel *imageLabel = new QLabel;
imageLabel->setFixedSize(100, 100);
+ imageLabel->setAlignment(Qt::AlignCenter);
imagesLayout->addWidget(imageLabel, i, j);
labels.append(imageLabel);
}
}
}
-
-void Images::updateStatus(const QString &msg)
-{
- statusBar->showMessage(msg);
-}
-
-void Images::abortDownload()
-{
- for (auto reply : replies)
- reply->abort();
-}
diff --git a/tests/manual/tasking/imagescaling/imagescaling.h b/tests/manual/tasking/imagescaling/imagescaling.h
index d3409e60a0..91e89c13b2 100644
--- a/tests/manual/tasking/imagescaling/imagescaling.h
+++ b/tests/manual/tasking/imagescaling/imagescaling.h
@@ -4,10 +4,9 @@
#ifndef IMAGESCALING_H
#define IMAGESCALING_H
-#include <QtWidgets>
-#include <QtConcurrent>
#include <QNetworkAccessManager>
-#include <optional>
+#include <QtWidgets>
+#include <tasking/tasktree.h>
class DownloadDialog;
class Images : public QWidget
@@ -15,27 +14,11 @@ class Images : public QWidget
Q_OBJECT
public:
Images(QWidget *parent = nullptr);
- ~Images();
-
- void initLayout(qsizetype count);
-
- QFuture<QByteArray> download(const QList<QUrl> &urls);
- void updateStatus(const QString &msg);
- void showImages(const QList<QImage> &images);
- void abortDownload();
-
-public slots:
- void process();
- void cancel();
-
-private slots:
- void scaleFinished();
private:
- using OptionalImages = std::optional<QList<QImage>>;
- static OptionalImages scaled(const QList<QByteArray> &data);
+ void process();
+ void initLayout(qsizetype count);
- QPushButton *addUrlsButton;
QPushButton *cancelButton;
QVBoxLayout *mainLayout;
QList<QLabel *> labels;
@@ -44,9 +27,7 @@ private:
DownloadDialog *downloadDialog;
QNetworkAccessManager qnam;
- QList<QSharedPointer<QNetworkReply>> replies;
- QFuture<QByteArray> downloadFuture;
- QFutureWatcher<OptionalImages> scalingWatcher;
+ std::unique_ptr<Tasking::TaskTree> taskTree;
};
#endif // IMAGESCALING_H