aboutsummaryrefslogtreecommitdiffstats
path: root/tests/manual/tasking/imagescaling/imagescaling.cpp
blob: e3acda749b29fc5bef412ceaf0ad84f59eb73c60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

#include "imagescaling.h"
#include "downloaddialog.h"
#include <tasking/concurrentcall.h>
#include <tasking/networkquery.h>

using namespace Tasking;

Images::Images(QWidget *parent) : QWidget(parent), downloadDialog(new DownloadDialog(this))
{
    resize(800, 600);

    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, [this] {
        statusBar->showMessage(tr("Canceled."));
        taskTree.reset();
    });

    QHBoxLayout *buttonLayout = new QHBoxLayout();
    buttonLayout->addWidget(addUrlsButton);
    buttonLayout->addWidget(cancelButton);
    buttonLayout->addStretch();

    statusBar = new QStatusBar();

    imagesLayout = new QGridLayout();

    mainLayout = new QVBoxLayout();
    mainLayout->addLayout(buttonLayout);
    mainLayout->addLayout(imagesLayout);
    mainLayout->addStretch();
    mainLayout->addWidget(statusBar);
    setLayout(mainLayout);
}

static void scale(QPromise<QImage> &promise, const QByteArray &data)
{
    const auto image = QImage::fromData(data);
    if (image.isNull())
        promise.future().cancel();
    else
        promise.addResult(image.scaled(100, 100, Qt::KeepAspectRatio));
}

void Images::process()
{
    if (downloadDialog->exec() != QDialog::Accepted)
        return;

    const auto urls = downloadDialog->getUrls();
    initLayout(urls.size());

    const auto onRootSetup = [this] {
        statusBar->showMessage(tr("Downloading and Scaling..."));
        cancelButton->setEnabled(true);
    };
    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;
    }

    taskTree.reset(new TaskTree(tasks));
    connect(taskTree.get(), &TaskTree::done, this, [this] { taskTree.release()->deleteLater(); });
    taskTree->start();
}

void Images::initLayout(qsizetype count)
{
    // Clean old images
    QLayoutItem *child;
    while ((child = imagesLayout->takeAt(0)) != nullptr) {
        child->widget()->setParent(nullptr);
        delete child->widget();
        delete child;
    }
    labels.clear();

    // Init the images layout for the new images
    const auto dim = int(qSqrt(qreal(count))) + 1;
    for (int i = 0; i < dim; ++i) {
        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);
        }
    }
}