summaryrefslogtreecommitdiffstats
path: root/examples/qtconcurrent
diff options
context:
space:
mode:
Diffstat (limited to 'examples/qtconcurrent')
-rw-r--r--examples/qtconcurrent/CMakeLists.txt17
-rw-r--r--examples/qtconcurrent/imagescaling/CMakeLists.txt50
-rw-r--r--examples/qtconcurrent/imagescaling/doc/images/imagescaling.webpbin0 -> 46826 bytes
-rw-r--r--examples/qtconcurrent/imagescaling/doc/images/imagescaling_example.pngbin21049 -> 0 bytes
-rw-r--r--examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc142
-rw-r--r--examples/qtconcurrent/imagescaling/downloaddialog.cpp51
-rw-r--r--examples/qtconcurrent/imagescaling/downloaddialog.h51
-rw-r--r--examples/qtconcurrent/imagescaling/imagescaling.cpp150
-rw-r--r--examples/qtconcurrent/imagescaling/imagescaling.h62
-rw-r--r--examples/qtconcurrent/imagescaling/main.cpp58
-rw-r--r--examples/qtconcurrent/map/.prev_CMakeLists.txt39
-rw-r--r--examples/qtconcurrent/map/CMakeLists.txt38
-rw-r--r--examples/qtconcurrent/map/doc/src/qtconcurrent-map.qdoc38
-rw-r--r--examples/qtconcurrent/map/main.cpp82
-rw-r--r--examples/qtconcurrent/map/map.pro9
-rw-r--r--examples/qtconcurrent/primecounter/CMakeLists.txt41
-rw-r--r--examples/qtconcurrent/primecounter/doc/images/primecounter.pngbin0 -> 9732 bytes
-rw-r--r--examples/qtconcurrent/primecounter/doc/src/qtconcurrent-primecounter.qdoc89
-rw-r--r--examples/qtconcurrent/primecounter/main.cpp18
-rw-r--r--examples/qtconcurrent/primecounter/primecounter.cpp139
-rw-r--r--examples/qtconcurrent/primecounter/primecounter.h49
-rw-r--r--examples/qtconcurrent/primecounter/primecounter.pro9
-rw-r--r--examples/qtconcurrent/primecounter/primecounter.ui177
-rw-r--r--examples/qtconcurrent/progressdialog/CMakeLists.txt41
-rw-r--r--examples/qtconcurrent/progressdialog/doc/images/qtconcurrent-progressdialog.pngbin4608 -> 0 bytes
-rw-r--r--examples/qtconcurrent/progressdialog/doc/src/qtconcurrent-progressdialog.qdoc38
-rw-r--r--examples/qtconcurrent/progressdialog/main.cpp100
-rw-r--r--examples/qtconcurrent/progressdialog/progressdialog.pro7
-rw-r--r--examples/qtconcurrent/qtconcurrent.pro13
-rw-r--r--examples/qtconcurrent/runfunction/CMakeLists.txt41
-rw-r--r--examples/qtconcurrent/runfunction/doc/src/qtconcurrent-runfunction.qdoc39
-rw-r--r--examples/qtconcurrent/runfunction/main.cpp71
-rw-r--r--examples/qtconcurrent/runfunction/runfunction.pro7
-rw-r--r--examples/qtconcurrent/wordcount/CMakeLists.txt50
-rw-r--r--examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc70
-rw-r--r--examples/qtconcurrent/wordcount/main.cpp195
36 files changed, 860 insertions, 1121 deletions
diff --git a/examples/qtconcurrent/CMakeLists.txt b/examples/qtconcurrent/CMakeLists.txt
index ed1be7ec4d..13e78678d8 100644
--- a/examples/qtconcurrent/CMakeLists.txt
+++ b/examples/qtconcurrent/CMakeLists.txt
@@ -1,14 +1,11 @@
-# Generated from qtconcurrent.pro.
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-if(NOT TARGET Qt::Concurrent)
+if(NOT TARGET Qt6::Concurrent)
return()
endif()
-if(TARGET Qt::Widgets)
- add_subdirectory(imagescaling)
- add_subdirectory(progressdialog)
- add_subdirectory(runfunction)
- add_subdirectory(wordcount)
-endif()
-if(TARGET Qt::Gui)
- add_subdirectory(map)
+if(TARGET Qt6::Widgets)
+ qt_internal_add_example(imagescaling)
+ qt_internal_add_example(primecounter)
+ qt_internal_add_example(wordcount)
endif()
diff --git a/examples/qtconcurrent/imagescaling/CMakeLists.txt b/examples/qtconcurrent/imagescaling/CMakeLists.txt
index caca16da12..d053d04fc1 100644
--- a/examples/qtconcurrent/imagescaling/CMakeLists.txt
+++ b/examples/qtconcurrent/imagescaling/CMakeLists.txt
@@ -1,45 +1,41 @@
-# Generated from imagescaling.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-cmake_minimum_required(VERSION 3.14)
+cmake_minimum_required(VERSION 3.16)
project(imagescaling LANGUAGES CXX)
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
+find_package(Qt6 REQUIRED COMPONENTS Concurrent Core Gui Network Widgets)
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/imagescaling")
-
-find_package(Qt6 COMPONENTS Core)
-find_package(Qt6 COMPONENTS Gui)
-find_package(Qt6 COMPONENTS Concurrent)
-find_package(Qt6 COMPONENTS Widgets)
-find_package(Qt6 COMPONENTS Network)
+qt_standard_project_setup()
qt_add_executable(imagescaling
downloaddialog.cpp downloaddialog.h downloaddialog.ui
imagescaling.cpp imagescaling.h
main.cpp
)
+
set_target_properties(imagescaling PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
-target_link_libraries(imagescaling PUBLIC
- Qt::Concurrent
- Qt::Core
- Qt::Gui
- Qt::Network
- Qt::Widgets
+
+target_link_libraries(imagescaling PRIVATE
+ Qt6::Concurrent
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Network
+ Qt6::Widgets
)
install(TARGETS imagescaling
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET imagescaling
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/qtconcurrent/imagescaling/doc/images/imagescaling.webp b/examples/qtconcurrent/imagescaling/doc/images/imagescaling.webp
new file mode 100644
index 0000000000..56999faaa7
--- /dev/null
+++ b/examples/qtconcurrent/imagescaling/doc/images/imagescaling.webp
Binary files differ
diff --git a/examples/qtconcurrent/imagescaling/doc/images/imagescaling_example.png b/examples/qtconcurrent/imagescaling/doc/images/imagescaling_example.png
deleted file mode 100644
index a3860e1974..0000000000
--- a/examples/qtconcurrent/imagescaling/doc/images/imagescaling_example.png
+++ /dev/null
Binary files differ
diff --git a/examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc b/examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc
index 8814c826ed..499cb165c8 100644
--- a/examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc
+++ b/examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc
@@ -1,41 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example imagescaling
- \title Image Scaling Example
- \brief Demonstrates how to asynchronously download and scale images.
+ \meta tags {widgets, threads, network}
+ \title Image Scaling
\ingroup qtconcurrentexamples
- \image imagescaling_example.png
+ \examplecategory {Networking}
+ \brief Demonstrates how to asynchronously download and scale images.
- This example shows how to use the QFuture and QPromise classes to download a
- collection of images from the network and scale them, without blocking the UI.
+ This example shows how to use the QFuture, QPromise, and QFutureWatcher
+ classes to download a collection of images from the network and scale them,
+ without blocking the UI.
- The application consists of the the following steps:
+ \image imagescaling.webp
+
+ The application consists of the following steps:
\list 1
\li Download images form the list of URLs specified by the user.
@@ -68,7 +48,6 @@
And here starts the interesting part:
- \dots
\snippet imagescaling/imagescaling.cpp 11
\dots
@@ -78,12 +57,14 @@
QNetworkReply::finished() signal is emitted. This allows us to attach continuations
and failure handlers, as it is done in the example.
- In the continuation attached via \b{.then()}, we check if the user has requested to
- cancel the download. If that's the case, we stop processing the request. By calling
- the \c QPromise::finish() method, we notify the user that processing has been finished.
+ In the continuation attached via \l{QFuture::then}{.then()}, we check if the
+ user has requested to cancel the download. If that's the case, we stop
+ processing the request. By calling the \l QPromise::finish() method, we notify
+ the user that processing has been finished.
In case the network request has ended with an error, we throw an exception. The
- exception will be handled in the failure handler attached using the \b{.onFailed()}
- method. Note that we have two failure handlers: the first one captures the network
+ exception will be handled in the failure handler attached using the
+ \l{QFuture::onFailed}{.onFailed()} method.
+ Note that we have two failure handlers: the first one captures the network
errors, the second one all other exceptions thrown during the execution. Both handlers
save the exception inside the promise object (to be handled by the caller of the
\c download() method) and report that the computation has finished. Also note that,
@@ -105,7 +86,7 @@
we need to copy and use the promise object in multiple places simultaneously. Hence,
a QSharedPointer is used.
- \c download() method is called from the \c QImage::process method. It is invoked
+ The \c download() method is called from the \c Images::process method. It is invoked
when the user presses the \e {"Add URLs"} button:
\dots
@@ -121,38 +102,20 @@
\snippet imagescaling/imagescaling.cpp 3
\dots
- Next, we attach a continuation to handle the scaling step:
+ Next, we attach a continuation to handle the scaling step.
+ More on that later:
\snippet imagescaling/imagescaling.cpp 4
\dots
- Since the scaling may be computationally heavy, and we don't want to block the main
- thread, we pass the \c QtFuture::Launch::Async option, to launch the scaling step in
- a new thread. The \c scaled() method returns a list of the scaled images to the next
- step, which takes care of showing images in the layout.
+ After that we attach \l {QFuture::}{onCanceled()} and \l {QFuture::}{onFailed()}
+ handlers:
- Note that \c updateStatus() is called through QMetaObject::invokeMethod(),
- because it updates the UI and needs to be invoked from the main thread.
-
- \dots
\snippet imagescaling/imagescaling.cpp 5
\dots
- For the same reason \c showImages() also needs to be invoked from the main thread, so
- we pass \c this as a context to \c .then(). By default, \c .then() is launched in the
- parent's thread, but if a context object is specified, it is launched in the context
- object's thread.
-
- Then we add cancellation and failure handlers:
-
- \dots
- \snippet imagescaling/imagescaling.cpp 6
-
- We don't need to specify the context anymore, because \c .onCanceled() and the next
- handlers will be launched in their parent's context.
-
- The handler attached via the \c .onCanceled() method will be called if the user has
- pressed the \e "Cancel" button:
+ The handler attached via the \l {QFuture::onCanceled}{.onCanceled()} method
+ will be called if the user has pressed the \e "Cancel" button:
\dots
\snippet imagescaling/imagescaling.cpp 2
@@ -162,14 +125,57 @@
\snippet imagescaling/imagescaling.cpp 7
- The handlers attached via \c .onFailed() method will be called in case an
- error occurred during one of the previous steps. For example, if a network error
- has been saved inside the promise during the download step, it will be propagated to
- the handler that takes \c QNetworkReply::NetworkError as argument. A failure can
- happen also during the scaling step:
+ The handlers attached via \l {QFuture::onFailed}{.onFailed()} method will be
+ called in case an error occurred during one of the previous steps.
+ For example, if a network error has been saved inside the promise during the
+ download step, it will be propagated to the handler that takes
+ \l QNetworkReply::NetworkError as argument.
+
+ If the \c downloadFuture is not canceled, and didn't report any error, the
+ scaling continuation is executed.
+
+ Since the scaling may be computationally heavy, and we don't want to block
+ the main thread, we use \l QtConcurrent::run(), to launch the scaling step
+ in a new thread.
+
+ \snippet imagescaling/imagescaling.cpp 16
+
+ Since the scaling is launched in a separate thread, the user can potentially
+ decide to close the application while the scaling operation is in progress.
+ To handle such situations gracefully, we pass the \l QFuture returned by
+ \l QtConcurrent::run() to the \l QFutureWatcher instance.
+
+ The watcher's \l QFutureWatcher::finished signal is connected to the
+ \c Images::scaleFinished slot:
+
+ \snippet imagescaling/imagescaling.cpp 6
+
+ This slot is responsible for showing the scaled images in the UI, and also
+ for handling the errors that could potentially happen during scaling:
+
+ \snippet imagescaling/imagescaling.cpp 15
+
+ The error reporting is implemented by returning an optional from the
+ \c Images::scaled() method:
\snippet imagescaling/imagescaling.cpp 14
+ The \c Images::OptionalImages type here is simply a typedef for \c std::optional:
+
+ \snippet imagescaling/imagescaling.h 1
+
+ \note We cannot handle the errors from the async scaling operation using
+ the \l {QFuture::onFailed}{.onFailed()} handler, because the handler needs
+ to be executed in the context of \c Images object in the UI thread.
+ If the user closes the application while the async computation is done,
+ the \c Images object will be destroyed, and accessing its members from the
+ continuation will lead to a crash. Using \l QFutureWatcher and its signals
+ allows us to avoid the problem, because the signals are disconnected when
+ the \l QFutureWatcher is destroyed, so the related slots will never be
+ executed in a destroyed context.
+
The rest of the code is straightforward, you can check the example project for
more details.
+
+ \include examples-run.qdocinc
*/
diff --git a/examples/qtconcurrent/imagescaling/downloaddialog.cpp b/examples/qtconcurrent/imagescaling/downloaddialog.cpp
index 2f2f901b0e..c3ec550038 100644
--- a/examples/qtconcurrent/imagescaling/downloaddialog.cpp
+++ b/examples/qtconcurrent/imagescaling/downloaddialog.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "downloaddialog.h"
#include "ui_downloaddialog.h"
diff --git a/examples/qtconcurrent/imagescaling/downloaddialog.h b/examples/qtconcurrent/imagescaling/downloaddialog.h
index 9e5d478d7d..e4a6482907 100644
--- a/examples/qtconcurrent/imagescaling/downloaddialog.h
+++ b/examples/qtconcurrent/imagescaling/downloaddialog.h
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef DOWNLOADDIALOG_H
#define DOWNLOADDIALOG_H
diff --git a/examples/qtconcurrent/imagescaling/imagescaling.cpp b/examples/qtconcurrent/imagescaling/imagescaling.cpp
index 66bb0686c3..f380ae9d90 100644
--- a/examples/qtconcurrent/imagescaling/imagescaling.cpp
+++ b/examples/qtconcurrent/imagescaling/imagescaling.cpp
@@ -1,64 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#include "imagescaling.h"
#include "downloaddialog.h"
#include <QNetworkReply>
-#include <qmath.h>
-
-#include <functional>
-
-Images::Images(QWidget *parent) : QWidget(parent), downloadDialog(new DownloadDialog())
+Images::Images(QWidget *parent) : QWidget(parent), downloadDialog(new DownloadDialog(this))
{
- setWindowTitle(tr("Image downloading and scaling example"));
resize(800, 600);
addUrlsButton = new QPushButton(tr("Add URLs"));
@@ -87,6 +36,11 @@ Images::Images(QWidget *parent) : QWidget(parent), downloadDialog(new DownloadDi
mainLayout->addStretch();
mainLayout->addWidget(statusBar);
setLayout(mainLayout);
+
+//! [6]
+ connect(&scalingWatcher, &QFutureWatcher<QList<QImage>>::finished,
+ this, &Images::scaleFinished);
+//! [6]
}
Images::~Images()
@@ -99,6 +53,7 @@ void Images::process()
{
// Clean previous state
replies.clear();
+ addUrlsButton->setEnabled(false);
if (downloadDialog->exec() == QDialog::Accepted) {
@@ -114,33 +69,34 @@ void Images::process()
statusBar->showMessage(tr("Downloading..."));
//! [3]
-//! [4]
- downloadFuture.then([this](auto) { cancelButton->setEnabled(false); })
- .then(QtFuture::Launch::Async,
- [this] {
- QMetaObject::invokeMethod(this,
- [this] { updateStatus(tr("Scaling...")); });
- return scaled();
- })
-//! [4]
-//! [5]
- .then(this, [this](const QList<QImage> &scaled) {
- showImages(scaled);
- updateStatus(tr("Finished"));
+ //! [4]
+ downloadFuture
+ .then([this](auto) {
+ cancelButton->setEnabled(false);
+ updateStatus(tr("Scaling..."));
+ //! [16]
+ scalingWatcher.setFuture(QtConcurrent::run(Images::scaled,
+ downloadFuture.results()));
+ //! [16]
+ })
+ //! [4]
+ //! [5]
+ .onCanceled([this] {
+ updateStatus(tr("Download has been canceled."));
})
-//! [5]
-//! [6]
- .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) {
+ .onFailed([this](const std::exception &ex) {
updateStatus(tr(ex.what()));
+ })
+ //! [5]
+ .then([this]() {
+ cancelButton->setEnabled(false);
+ addUrlsButton->setEnabled(true);
});
-//! [6]
}
}
@@ -154,22 +110,37 @@ void Images::cancel()
}
//! [7]
+//! [15]
+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);
+}
+//! [15]
+
//! [8]
QFuture<QByteArray> Images::download(const QList<QUrl> &urls)
-//! [8]
{
+//! [8]
//! [9]
QSharedPointer<QPromise<QByteArray>> promise(new QPromise<QByteArray>());
promise->start();
//! [9]
-//! [10]
- for (auto url : urls) {
+ //! [10]
+ for (const auto &url : urls) {
QSharedPointer<QNetworkReply> reply(qnam.get(QNetworkRequest(url)));
replies.push_back(reply);
-//! [10]
+ //! [10]
-//! [11]
+ //! [11]
QtFuture::connect(reply.get(), &QNetworkReply::finished).then([=] {
if (promise->isCanceled()) {
if (!promise->future().isFinished())
@@ -181,25 +152,24 @@ QFuture<QByteArray> Images::download(const QList<QUrl> &urls)
if (!promise->future().isFinished())
throw reply->error();
}
-//! [12]
+ //! [12]
promise->addResult(reply->readAll());
// Report finished on the last download
- if (promise->future().resultCount() == urls.size()) {
+ if (promise->future().resultCount() == urls.size())
promise->finish();
- }
-//! [12]
- }).onFailed([=] (QNetworkReply::NetworkError error) {
+ //! [12]
+ }).onFailed([promise] (QNetworkReply::NetworkError error) {
promise->setException(std::make_exception_ptr(error));
promise->finish();
- }).onFailed([=] {
+ }).onFailed([promise] {
const auto ex = std::make_exception_ptr(
std::runtime_error("Unknown error occurred while downloading."));
promise->setException(ex);
promise->finish();
});
}
-//! [11]
+ //! [11]
//! [13]
return promise->future();
@@ -207,15 +177,14 @@ QFuture<QByteArray> Images::download(const QList<QUrl> &urls)
//! [13]
//! [14]
-QList<QImage> Images::scaled() const
+Images::OptionalImages Images::scaled(const QList<QByteArray> &data)
{
QList<QImage> scaled;
- const auto data = downloadFuture.results();
- for (auto imgData : data) {
+ for (const auto &imgData : data) {
QImage image;
image.loadFromData(imgData);
if (image.isNull())
- throw std::runtime_error("Failed to load image.");
+ return std::nullopt;
scaled.push_back(image.scaled(100, 100, Qt::KeepAspectRatio));
}
@@ -238,6 +207,7 @@ void Images::initLayout(qsizetype count)
QLayoutItem *child;
while ((child = imagesLayout->takeAt(0)) != nullptr) {
child->widget()->setParent(nullptr);
+ delete child->widget();
delete child;
}
labels.clear();
diff --git a/examples/qtconcurrent/imagescaling/imagescaling.h b/examples/qtconcurrent/imagescaling/imagescaling.h
index 0c0d90870e..bc25161a85 100644
--- a/examples/qtconcurrent/imagescaling/imagescaling.h
+++ b/examples/qtconcurrent/imagescaling/imagescaling.h
@@ -1,58 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef IMAGESCALING_H
#define IMAGESCALING_H
#include <QtWidgets>
#include <QtConcurrent>
#include <QNetworkAccessManager>
+#include <optional>
class DownloadDialog;
class Images : public QWidget
@@ -65,7 +19,6 @@ public:
void initLayout(qsizetype count);
QFuture<QByteArray> download(const QList<QUrl> &urls);
- QList<QImage> scaled() const;
void updateStatus(const QString &msg);
void showImages(const QList<QImage> &images);
void abortDownload();
@@ -74,7 +27,15 @@ public slots:
void process();
void cancel();
+private slots:
+ void scaleFinished();
+
private:
+ //! [1]
+ using OptionalImages = std::optional<QList<QImage>>;
+ //! [1]
+ static OptionalImages scaled(const QList<QByteArray> &data);
+
QPushButton *addUrlsButton;
QPushButton *cancelButton;
QVBoxLayout *mainLayout;
@@ -86,6 +47,7 @@ private:
QNetworkAccessManager qnam;
QList<QSharedPointer<QNetworkReply>> replies;
QFuture<QByteArray> downloadFuture;
+ QFutureWatcher<OptionalImages> scalingWatcher;
};
#endif // IMAGESCALING_H
diff --git a/examples/qtconcurrent/imagescaling/main.cpp b/examples/qtconcurrent/imagescaling/main.cpp
index 01390499f5..67b543a961 100644
--- a/examples/qtconcurrent/imagescaling/main.cpp
+++ b/examples/qtconcurrent/imagescaling/main.cpp
@@ -1,62 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <QtWidgets>
-#include <QtConcurrent>
-
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "imagescaling.h"
+#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
+ app.setOrganizationName("QtProject");
+ app.setApplicationName(QObject::tr("Image Downloading and Scaling"));
Images imageView;
+ imageView.setWindowTitle(QObject::tr("Image Downloading and Scaling"));
imageView.show();
return app.exec();
diff --git a/examples/qtconcurrent/map/.prev_CMakeLists.txt b/examples/qtconcurrent/map/.prev_CMakeLists.txt
deleted file mode 100644
index 0e3215c225..0000000000
--- a/examples/qtconcurrent/map/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-# Generated from map.pro.
-
-cmake_minimum_required(VERSION 3.14)
-project(mapdemo LANGUAGES CXX)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/map")
-
-find_package(Qt6 COMPONENTS Core)
-find_package(Qt6 COMPONENTS Gui)
-find_package(Qt6 COMPONENTS Concurrent)
-
-qt_add_executable(mapdemo
- main.cpp
-)
-set_target_properties(mapdemo PROPERTIES
- WIN32_EXECUTABLE FALSE
- MACOSX_BUNDLE FALSE
-)
-target_link_libraries(mapdemo PUBLIC
- Qt::Concurrent
- Qt::Core
- Qt::Gui
-)
-
-install(TARGETS mapdemo
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
-)
diff --git a/examples/qtconcurrent/map/CMakeLists.txt b/examples/qtconcurrent/map/CMakeLists.txt
deleted file mode 100644
index 08589f1b3f..0000000000
--- a/examples/qtconcurrent/map/CMakeLists.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-# Generated from map.pro.
-
-cmake_minimum_required(VERSION 3.14)
-project(mapdemo LANGUAGES CXX)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/map")
-
-find_package(Qt6 COMPONENTS Core)
-find_package(Qt6 COMPONENTS Gui)
-find_package(Qt6 COMPONENTS Concurrent)
-
-qt_add_executable(mapdemo
- main.cpp
-)
-set_target_properties(mapdemo PROPERTIES
- WIN32_EXECUTABLE FALSE
- MACOSX_BUNDLE FALSE
-)
-target_link_libraries(mapdemo PUBLIC
- Qt::Concurrent
- Qt::Core
- Qt::Gui
-)
-install(TARGETS mapdemo
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
-)
diff --git a/examples/qtconcurrent/map/doc/src/qtconcurrent-map.qdoc b/examples/qtconcurrent/map/doc/src/qtconcurrent-map.qdoc
deleted file mode 100644
index 2cc66e932e..0000000000
--- a/examples/qtconcurrent/map/doc/src/qtconcurrent-map.qdoc
+++ /dev/null
@@ -1,38 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \example map
- \title Map Example
- \brief Demonstrates how to scale images synchronously.
- \ingroup qtconcurrentexamples
-
- The QtConcurrent Map example shows how to use the synchronous (blocking)
- QtConcurrent API to scale a collection of images.
-
- This is a command-line application.
-*/
diff --git a/examples/qtconcurrent/map/main.cpp b/examples/qtconcurrent/map/main.cpp
deleted file mode 100644
index 8fc670b64b..0000000000
--- a/examples/qtconcurrent/map/main.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QImage>
-#include <QList>
-#include <QThread>
-#include <QDebug>
-#include <QGuiApplication>
-#include <qtconcurrentmap.h>
-
-#include <functional>
-
-int main(int argc, char *argv[])
-{
- QGuiApplication app(argc, argv);
-
- const int imageCount = 20;
-
- // Create a list containing imageCount images.
- QList<QImage> images;
- for (int i = 0; i < imageCount; ++i)
- images.append(QImage(1600, 1200, QImage::Format_ARGB32_Premultiplied));
-
- std::function<QImage(const QImage&)> scale = [](const QImage &image) -> QImage
- {
- qDebug() << "Scaling image in thread" << QThread::currentThread();
- return image.scaled(QSize(100, 100), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
- };
-
- // Use QtConcurrentBlocking::mapped to apply the scale function to all the
- // images in the list.
- QList<QImage> thumbnails = QtConcurrent::blockingMapped(images, scale);
-
- return 0;
-}
diff --git a/examples/qtconcurrent/map/map.pro b/examples/qtconcurrent/map/map.pro
deleted file mode 100644
index 7f267beb22..0000000000
--- a/examples/qtconcurrent/map/map.pro
+++ /dev/null
@@ -1,9 +0,0 @@
-TEMPLATE = app
-TARGET = mapdemo
-QT += concurrent
-CONFIG += cmdline
-
-SOURCES += main.cpp
-
-target.path = $$[QT_INSTALL_EXAMPLES]/qtconcurrent/map
-INSTALLS += target
diff --git a/examples/qtconcurrent/primecounter/CMakeLists.txt b/examples/qtconcurrent/primecounter/CMakeLists.txt
new file mode 100644
index 0000000000..c8ac5f20e8
--- /dev/null
+++ b/examples/qtconcurrent/primecounter/CMakeLists.txt
@@ -0,0 +1,41 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(primecounter LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS Concurrent Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(primecounter
+ main.cpp
+ primecounter.ui
+ primecounter.cpp
+ primecounter.h
+)
+
+set_target_properties(primecounter PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(primecounter PRIVATE
+ Qt6::Concurrent
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+install(TARGETS primecounter
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET primecounter
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
+)
+install(SCRIPT ${deploy_script})
diff --git a/examples/qtconcurrent/primecounter/doc/images/primecounter.png b/examples/qtconcurrent/primecounter/doc/images/primecounter.png
new file mode 100644
index 0000000000..d611a507b5
--- /dev/null
+++ b/examples/qtconcurrent/primecounter/doc/images/primecounter.png
Binary files differ
diff --git a/examples/qtconcurrent/primecounter/doc/src/qtconcurrent-primecounter.qdoc b/examples/qtconcurrent/primecounter/doc/src/qtconcurrent-primecounter.qdoc
new file mode 100644
index 0000000000..de6c94b0cf
--- /dev/null
+++ b/examples/qtconcurrent/primecounter/doc/src/qtconcurrent-primecounter.qdoc
@@ -0,0 +1,89 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example primecounter
+ \meta tags {widgets, threads}
+ \title Prime Counter
+ \ingroup qtconcurrentexamples
+ \examplecategory {Data Processing & I/O}
+ \brief Demonstrates how to monitor the progress of concurrent operations.
+
+ The following example demonstrates how to create an interactive and
+ non-blocking QtWidgets application using the QFutureWatcher class and the
+ \l {Concurrent Filter-Reduce} {filteredReduced} functions from
+ \l {Qt Concurrent}. With this example, the user can create a QList of
+ integers that can be resized. The list will be automatically filled with
+ natural numbers starting from 1 up to n. The program will then check for
+ prime numbers within the list and display the total count of prime numbers
+ found.
+
+ \image primecounter.png
+
+ \include examples-run.qdocinc
+
+ \section1 Setting up the connections
+
+ The \l {Qt Concurrent} library provides the
+ \l {Concurrent Filter-Reduce} {filteredReduced} functions, which can operate
+ in two modes:
+ \l {QtConcurrent::ReduceOption} {OrderedReduce and UnorderedReduce}. In
+ \c OrderedReduce mode, the reducing function is called in the order of the
+ original sequence, whereas in \c UnorderedReduce mode, the elements are
+ accessed randomly.
+
+ After configuring the UI with the desired elements, it is necessary to
+ connect them to the signals of the concurrent operations using the Qt
+ \l {Signals & Slots} mechanism. In this example, we use the QFutureWatcher
+ class to monitor the progress of the concurrent operations and provide the
+ signals required to implement the interactive GUI.
+
+ \dots
+ \snippet primecounter/primecounter.cpp 1
+ \dots
+
+ The QFutureWatcher class plays a vital role in this example as it provides
+ the signals required to update the UI in response to changes in the
+ concurrent operations.
+
+ \section1 Starting the concurrent operation
+
+ After connecting all the \l {Signals & Slots}, and when the user presses
+ the QPushButton, the \c {start()} function is called.
+
+ In the \c {start()} function, we call the
+ \l {Concurrent Filter-Reduce} {filteredReduced} function from Qt Concurrent
+ and set the future on the QFutureWatcher member. To ensure that this
+ operation runs truly concurrently, we specify a separate QThreadPool as the
+ first parameter. This approach also avoids any possible blocking in the
+ global thread pool. We pass the QList of integers as the container, a
+ static filter and reduce function, and finally the
+ \l {QtConcurrent::} {ReduceOption} flag.
+
+ \dots
+ \snippet primecounter/primecounter.cpp 2
+ \dots
+
+ Let's examine the filter and reduce functions. These functions are declared
+ static in this example since they do not depend on any member variable.
+ However, they could easily be specified as lambdas or member functions.
+
+ The filter function marks elements for subsequent reduction with the reduce
+ function. This implementation is a simple prime filter. As this function
+ takes a const reference as an argument, it allows thread-safe operation on
+ the container it operates on.
+
+ \dots
+ \snippet primecounter/primecounter.cpp 3
+ \dots
+
+ The reduce function takes a modifiable reference of the same type as the
+ container it operates on as its first parameter. The second parameter is the
+ previously filtered element from the filter function. In this example, we
+ count the number of primes.
+
+ \dots
+ \snippet primecounter/primecounter.cpp 4
+ \dots
+
+*/
diff --git a/examples/qtconcurrent/primecounter/main.cpp b/examples/qtconcurrent/primecounter/main.cpp
new file mode 100644
index 0000000000..acfd581341
--- /dev/null
+++ b/examples/qtconcurrent/primecounter/main.cpp
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtWidgets/qapplication.h>
+#include "primecounter.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ app.setOrganizationName("QtProject");
+ app.setApplicationName(QApplication::translate("main", "Prime Counter"));
+
+ PrimeCounter dialog;
+ dialog.setWindowTitle(QApplication::translate("main", "Prime Counter"));
+ dialog.show();
+
+ return app.exec();
+}
diff --git a/examples/qtconcurrent/primecounter/primecounter.cpp b/examples/qtconcurrent/primecounter/primecounter.cpp
new file mode 100644
index 0000000000..01bde5d87f
--- /dev/null
+++ b/examples/qtconcurrent/primecounter/primecounter.cpp
@@ -0,0 +1,139 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "primecounter.h"
+#include "ui_primecounter.h"
+
+PrimeCounter::PrimeCounter(QWidget *parent)
+ : QDialog(parent), stepSize(100000), ui(setupUi())
+{
+ // Control the concurrent operation with the QFutureWatcher
+ //! [1]
+ connect(ui->pushButton, &QPushButton::clicked,
+ this, [this] { start(); });
+ connect(&watcher, &QFutureWatcher<Element>::finished,
+ this, [this] { finish(); });
+ connect(&watcher, &QFutureWatcher<Element>::progressRangeChanged,
+ ui->progressBar, &QProgressBar::setRange);
+ connect(&watcher, &QFutureWatcher<Element>::progressValueChanged,
+ ui->progressBar, &QProgressBar::setValue);
+ //! [1]
+}
+
+PrimeCounter::~PrimeCounter()
+{
+ watcher.cancel();
+ delete ui;
+}
+
+//! [3]
+bool PrimeCounter::filterFunction(const Element &element)
+{
+ // Filter for primes
+ if (element <= 1)
+ return false;
+ for (Element i = 2; i*i <= element; ++i) {
+ if (element % i == 0)
+ return false;
+ }
+ return true;
+}
+//! [3]
+
+//! [4]
+void PrimeCounter::reduceFunction(Element &out, const Element &value)
+{
+ // Count the amount of primes.
+ Q_UNUSED(value);
+ ++out;
+}
+//! [4]
+
+//! [2]
+void PrimeCounter::start()
+{
+ if (ui->pushButton->isChecked()) {
+ ui->comboBox->setEnabled(false);
+ ui->pushButton->setText(tr("Cancel"));
+ ui->labelResult->setText(tr("Calculating ..."));
+ ui->labelFilter->setText(tr("Selected Reduce Option: %1").arg(ui->comboBox->currentText()));
+ fillElementList(ui->horizontalSlider->value() * stepSize);
+
+ timer.start();
+ watcher.setFuture(
+ QtConcurrent::filteredReduced(
+ &pool,
+ elementList,
+ filterFunction,
+ reduceFunction,
+ currentReduceOpt | QtConcurrent::SequentialReduce));
+//! [2]
+ } else {
+ watcher.cancel();
+ ui->progressBar->setValue(0);
+ ui->comboBox->setEnabled(true);
+ ui->labelResult->setText(tr(""));
+ ui->pushButton->setText(tr("Start"));
+ ui->labelFilter->setText(tr("Operation Canceled"));
+ }
+}
+
+void PrimeCounter::finish()
+{
+ // The finished signal from the QFutureWatcher is also emitted when cancelling.
+ if (watcher.isCanceled())
+ return;
+
+ auto elapsedTime = timer.elapsed();
+ ui->progressBar->setValue(0);
+ ui->comboBox->setEnabled(true);
+ ui->pushButton->setChecked(false);
+ ui->pushButton->setText(tr("Start"));
+ ui->labelFilter->setText(
+ tr("Filter '%1' took %2 ms to calculate").arg(ui->comboBox->currentText())
+ .arg(elapsedTime));
+ ui->labelResult->setText(
+ tr("Found %1 primes in the range of elements").arg(watcher.result()));
+}
+
+void PrimeCounter::fillElementList(unsigned int count)
+{
+ // Fill elementList with values from [1, count] when starting the calculations.
+ auto prevSize = elementList.size();
+ if (prevSize == count)
+ return; // Nothing to do here.
+
+ auto startVal = elementList.empty() ? 1 : elementList.back() + 1;
+ elementList.resize(count);
+ if (elementList.begin() + prevSize < elementList.end())
+ std::iota(elementList.begin() + prevSize, elementList.end(), startVal);
+}
+
+Ui::PrimeCounter* PrimeCounter::setupUi()
+{
+ Ui::PrimeCounter *setupUI = new Ui::PrimeCounter;
+ setupUI->setupUi(this);
+ setModal(true);
+
+ // Set up the slider
+ connect(setupUI->horizontalSlider, &QSlider::valueChanged,
+ this, [setupUI, this] (const int &pos) {
+ setupUI->labelResult->setText("");
+ setupUI->labelSize->setText(tr("Elements in list: %1").arg(pos * stepSize));
+ });
+ setupUI->horizontalSlider->setValue(30);
+
+ // Set up the combo box
+ setupUI->comboBox->insertItem(0, tr("Unordered Reduce"), QtConcurrent::UnorderedReduce);
+ setupUI->comboBox->insertItem(1, tr("Ordered Reduce"), QtConcurrent::OrderedReduce);
+
+ auto comboBoxChange = [this, setupUI](int pos) {
+ currentReduceOpt = setupUI->comboBox->itemData(pos).value<QtConcurrent::ReduceOptions>();
+ setupUI->labelFilter->setText(tr("Selected Reduce Option: %1")
+ .arg(setupUI->comboBox->currentText()));
+ };
+ comboBoxChange(setupUI->comboBox->currentIndex());
+ connect(setupUI->comboBox, &QComboBox::currentIndexChanged, this, comboBoxChange);
+
+ return setupUI;
+}
diff --git a/examples/qtconcurrent/primecounter/primecounter.h b/examples/qtconcurrent/primecounter/primecounter.h
new file mode 100644
index 0000000000..5b6d442cc8
--- /dev/null
+++ b/examples/qtconcurrent/primecounter/primecounter.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef PRIMECOUNTER_H
+#define PRIMECOUNTER_H
+
+#include <QtWidgets/qdialog.h>
+#include <QtCore/qfuturewatcher.h>
+#include <QtConcurrent/qtconcurrentfilter.h>
+#include <QtConcurrent/qtconcurrentreducekernel.h>
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+class QProgressBar;
+namespace Ui {
+class PrimeCounter;
+}
+
+QT_END_NAMESPACE
+
+class PrimeCounter : public QDialog
+{
+ Q_OBJECT
+ using Element = unsigned long long;
+public:
+ explicit PrimeCounter(QWidget* parent = nullptr);
+ ~PrimeCounter() override;
+
+private:
+ static bool filterFunction(const Element &element);
+ static void reduceFunction(Element &out, const Element &value);
+ void fillElementList(unsigned int count);
+ Ui::PrimeCounter* setupUi();
+
+private slots:
+ void start();
+ void finish();
+
+private:
+ QList<Element> elementList;
+ QFutureWatcher<Element> watcher;
+ QtConcurrent::ReduceOptions currentReduceOpt;
+ QElapsedTimer timer;
+ QThreadPool pool;
+ unsigned int stepSize;
+ Ui::PrimeCounter *ui;
+};
+
+#endif //PRIMECOUNTER_H
diff --git a/examples/qtconcurrent/primecounter/primecounter.pro b/examples/qtconcurrent/primecounter/primecounter.pro
new file mode 100644
index 0000000000..bb5a740688
--- /dev/null
+++ b/examples/qtconcurrent/primecounter/primecounter.pro
@@ -0,0 +1,9 @@
+QT += concurrent widgets
+
+SOURCES += main.cpp primecounter.cpp
+HEADERS += primecounter.h
+
+target.path = $$[QT_INSTALL_EXAMPLES]/qtconcurrent/primecounter
+INSTALLS += target
+
+FORMS += primecounter.ui
diff --git a/examples/qtconcurrent/primecounter/primecounter.ui b/examples/qtconcurrent/primecounter/primecounter.ui
new file mode 100644
index 0000000000..625462e05e
--- /dev/null
+++ b/examples/qtconcurrent/primecounter/primecounter.ui
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PrimeCounter</class>
+ <widget class="QDialog" name="PrimeCounter">
+ <property name="windowModality">
+ <enum>Qt::WindowModal</enum>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>454</width>
+ <height>320</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="leftMargin">
+ <number>20</number>
+ </property>
+ <property name="topMargin">
+ <number>20</number>
+ </property>
+ <property name="rightMargin">
+ <number>20</number>
+ </property>
+ <property name="bottomMargin">
+ <number>20</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelInfo">
+ <property name="font">
+ <font>
+ <pointsize>11</pointsize>
+ <bold>false</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Select a reducing option and measure the speed</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer1">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout2">
+ <property name="topMargin">
+ <number>10</number>
+ </property>
+ <property name="bottomMargin">
+ <number>10</number>
+ </property>
+ <item>
+ <widget class="QComboBox" name="comboBox"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout1">
+ <property name="topMargin">
+ <number>10</number>
+ </property>
+ <property name="bottomMargin">
+ <number>10</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>Start</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="progressBar">
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelFilter">
+ <property name="text">
+ <string>Filter Label</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout3">
+ <item>
+ <widget class="QSlider" name="horizontalSlider">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelSize">
+ <property name="text">
+ <string>size</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="margin">
+ <number>5</number>
+ </property>
+ <property name="indent">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelResult">
+ <property name="text">
+ <string>Result Label</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/qtconcurrent/progressdialog/CMakeLists.txt b/examples/qtconcurrent/progressdialog/CMakeLists.txt
deleted file mode 100644
index 00dd8215ef..0000000000
--- a/examples/qtconcurrent/progressdialog/CMakeLists.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-# Generated from progressdialog.pro.
-
-cmake_minimum_required(VERSION 3.14)
-project(progressdialog LANGUAGES CXX)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/progressdialog")
-
-find_package(Qt6 COMPONENTS Core)
-find_package(Qt6 COMPONENTS Gui)
-find_package(Qt6 COMPONENTS Concurrent)
-find_package(Qt6 COMPONENTS Widgets)
-
-qt_add_executable(progressdialog
- main.cpp
-)
-set_target_properties(progressdialog PROPERTIES
- WIN32_EXECUTABLE FALSE
- MACOSX_BUNDLE TRUE
-)
-target_link_libraries(progressdialog PUBLIC
- Qt::Concurrent
- Qt::Core
- Qt::Gui
- Qt::Widgets
-)
-
-install(TARGETS progressdialog
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
-)
diff --git a/examples/qtconcurrent/progressdialog/doc/images/qtconcurrent-progressdialog.png b/examples/qtconcurrent/progressdialog/doc/images/qtconcurrent-progressdialog.png
deleted file mode 100644
index 2e8b7735ad..0000000000
--- a/examples/qtconcurrent/progressdialog/doc/images/qtconcurrent-progressdialog.png
+++ /dev/null
Binary files differ
diff --git a/examples/qtconcurrent/progressdialog/doc/src/qtconcurrent-progressdialog.qdoc b/examples/qtconcurrent/progressdialog/doc/src/qtconcurrent-progressdialog.qdoc
deleted file mode 100644
index 816bbd5170..0000000000
--- a/examples/qtconcurrent/progressdialog/doc/src/qtconcurrent-progressdialog.qdoc
+++ /dev/null
@@ -1,38 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \example progressdialog
- \title QtConcurrent Progress Dialog Example
- \brief Demonstrates how to monitor the progress of the active processes.
- \ingroup qtconcurrentexamples
-
- The QtConcurrent Progress Dialog example shows how to use the
- QFutureWatcher class to monitor the progress of a long-running operation.
-
- \image qtconcurrent-progressdialog.png
-*/
diff --git a/examples/qtconcurrent/progressdialog/main.cpp b/examples/qtconcurrent/progressdialog/main.cpp
deleted file mode 100644
index cf4fd7e456..0000000000
--- a/examples/qtconcurrent/progressdialog/main.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtWidgets>
-#include <QtConcurrent>
-
-#include <functional>
-
-using namespace QtConcurrent;
-
-int main(int argc, char **argv)
-{
- QApplication app(argc, argv);
-
- const int iterations = 20;
-
- // Prepare the list.
- QList<int> list;
- for (int i = 0; i < iterations; ++i)
- list.append(i);
-
- // Create a progress dialog.
- QProgressDialog dialog;
- dialog.setLabelText(QString("Progressing using %1 thread(s)...").arg(QThread::idealThreadCount()));
-
- // Create a QFutureWatcher and connect signals and slots.
- QFutureWatcher<void> futureWatcher;
- QObject::connect(&futureWatcher, &QFutureWatcher<void>::finished, &dialog, &QProgressDialog::reset);
- QObject::connect(&dialog, &QProgressDialog::canceled, &futureWatcher, &QFutureWatcher<void>::cancel);
- QObject::connect(&futureWatcher, &QFutureWatcher<void>::progressRangeChanged, &dialog, &QProgressDialog::setRange);
- QObject::connect(&futureWatcher, &QFutureWatcher<void>::progressValueChanged, &dialog, &QProgressDialog::setValue);
-
- // Our function to compute
- std::function<void(int&)> spin = [](int &iteration) {
- const int work = 1000 * 1000 * 40;
- volatile int v = 0;
- for (int j = 0; j < work; ++j)
- ++v;
-
- qDebug() << "iteration" << iteration << "in thread" << QThread::currentThreadId();
- };
-
- // Start the computation.
- futureWatcher.setFuture(QtConcurrent::map(list, spin));
-
- // Display the dialog and start the event loop.
- dialog.exec();
-
- futureWatcher.waitForFinished();
-
- // Query the future to check if was canceled.
- qDebug() << "Canceled?" << futureWatcher.future().isCanceled();
-}
diff --git a/examples/qtconcurrent/progressdialog/progressdialog.pro b/examples/qtconcurrent/progressdialog/progressdialog.pro
deleted file mode 100644
index 8a5b3aabb7..0000000000
--- a/examples/qtconcurrent/progressdialog/progressdialog.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-QT += concurrent widgets
-CONFIG += console
-
-SOURCES += main.cpp
-
-target.path = $$[QT_INSTALL_EXAMPLES]/qtconcurrent/progressdialog
-INSTALLS += target
diff --git a/examples/qtconcurrent/qtconcurrent.pro b/examples/qtconcurrent/qtconcurrent.pro
index bdf41b03ea..ea7618fa00 100644
--- a/examples/qtconcurrent/qtconcurrent.pro
+++ b/examples/qtconcurrent/qtconcurrent.pro
@@ -2,21 +2,12 @@ requires(qtHaveModule(concurrent))
TEMPLATE = subdirs
SUBDIRS = imagescaling \
- map \
- progressdialog \
- runfunction \
+ primecounter \
wordcount
-
-!qtHaveModule(gui) {
- SUBDIRS -= \
- map
-}
-
!qtHaveModule(widgets) {
SUBDIRS -= \
imagescaling \
- progressdialog \
- runfunction \
+ primecounter \
wordcount
}
diff --git a/examples/qtconcurrent/runfunction/CMakeLists.txt b/examples/qtconcurrent/runfunction/CMakeLists.txt
deleted file mode 100644
index d1f0321648..0000000000
--- a/examples/qtconcurrent/runfunction/CMakeLists.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-# Generated from runfunction.pro.
-
-cmake_minimum_required(VERSION 3.14)
-project(runfunction LANGUAGES CXX)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/runfunction")
-
-find_package(Qt6 COMPONENTS Core)
-find_package(Qt6 COMPONENTS Gui)
-find_package(Qt6 COMPONENTS Concurrent)
-find_package(Qt6 COMPONENTS Widgets)
-
-qt_add_executable(runfunction
- main.cpp
-)
-set_target_properties(runfunction PROPERTIES
- WIN32_EXECUTABLE FALSE
- MACOSX_BUNDLE FALSE
-)
-target_link_libraries(runfunction PUBLIC
- Qt::Concurrent
- Qt::Core
- Qt::Gui
- Qt::Widgets
-)
-
-install(TARGETS runfunction
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
-)
diff --git a/examples/qtconcurrent/runfunction/doc/src/qtconcurrent-runfunction.qdoc b/examples/qtconcurrent/runfunction/doc/src/qtconcurrent-runfunction.qdoc
deleted file mode 100644
index 4459976a2c..0000000000
--- a/examples/qtconcurrent/runfunction/doc/src/qtconcurrent-runfunction.qdoc
+++ /dev/null
@@ -1,39 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \example runfunction
- \title Run Function Example
- \brief Demonstrates how to run standard functions concurrently.
- \ingroup qtconcurrentexamples
-
- The QtConcurrent Run Function example shows how to apply concurrency to
- a standard function, using QFuture instances to retrieve return values
- at a later time.
-
- This is a command-line application.
-*/
diff --git a/examples/qtconcurrent/runfunction/main.cpp b/examples/qtconcurrent/runfunction/main.cpp
deleted file mode 100644
index b349f886ba..0000000000
--- a/examples/qtconcurrent/runfunction/main.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QDebug>
-#include <QThread>
-#include <QString>
-#include <qtconcurrentrun.h>
-#include <QApplication>
-
-using namespace QtConcurrent;
-
-void hello(QString name)
-{
- qDebug() << "Hello" << name << "from" << QThread::currentThread();
-}
-
-int main(int argc, char **argv)
-{
- QApplication app(argc, argv);
- QFuture<void> f1 = run(hello, QString("Alice"));
- QFuture<void> f2 = run(hello, QString("Bob"));
- f1.waitForFinished();
- f2.waitForFinished();
-}
diff --git a/examples/qtconcurrent/runfunction/runfunction.pro b/examples/qtconcurrent/runfunction/runfunction.pro
deleted file mode 100644
index 42c05551ba..0000000000
--- a/examples/qtconcurrent/runfunction/runfunction.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-QT += concurrent widgets
-CONFIG += cmdline
-
-SOURCES += main.cpp
-
-target.path = $$[QT_INSTALL_EXAMPLES]/qtconcurrent/runfunction
-INSTALLS += target
diff --git a/examples/qtconcurrent/wordcount/CMakeLists.txt b/examples/qtconcurrent/wordcount/CMakeLists.txt
index 10e09bf0f6..0be10c3f35 100644
--- a/examples/qtconcurrent/wordcount/CMakeLists.txt
+++ b/examples/qtconcurrent/wordcount/CMakeLists.txt
@@ -1,41 +1,33 @@
-# Generated from wordcount.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-cmake_minimum_required(VERSION 3.14)
+cmake_minimum_required(VERSION 3.16)
project(wordcount LANGUAGES CXX)
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
+find_package(Qt6 REQUIRED COMPONENTS Concurrent Core Gui Widgets)
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/wordcount")
-
-find_package(Qt6 COMPONENTS Core)
-find_package(Qt6 COMPONENTS Gui)
-find_package(Qt6 COMPONENTS Concurrent)
-find_package(Qt6 COMPONENTS Widgets)
+qt_standard_project_setup()
qt_add_executable(wordcount
main.cpp
)
-set_target_properties(wordcount PROPERTIES
- WIN32_EXECUTABLE FALSE
- MACOSX_BUNDLE FALSE
-)
-target_link_libraries(wordcount PUBLIC
- Qt::Concurrent
- Qt::Core
- Qt::Gui
- Qt::Widgets
+
+target_link_libraries(wordcount PRIVATE
+ Qt6::Concurrent
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
)
install(TARGETS wordcount
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET wordcount
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc b/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc
index 7486340c7b..adefdfdc59 100644
--- a/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc
+++ b/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc
@@ -1,39 +1,45 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example wordcount
- \title QtConcurrent Word Count Example
- \brief Demonstrates how to use the map-reduce algorithm.
+ \meta tags {threads, console}
+ \title Word Count
\ingroup qtconcurrentexamples
+ \examplecategory {Data Processing & I/O}
+ \brief Demonstrates how to use the map-reduce algorithm.
+
+ The Qt Concurrent \e {Word Count} example demonstrates the use of the
+ map-reduce algorithm when applied to the problem of counting words in a
+ collection of files.
+
+ First, the Application starts a QFileDialog to select a starting
+ path, and then prints the output to the console.
+
+ \include examples-run.qdocinc
+
+ \section1 Comparing the operations
+
+ Compare a single-threaded, sequential approach to counting the words in
+ the text files to a multithreaded approach with mappedReduced():
+
+ \dots
+ \snippet wordcount/main.cpp 1
+ \dots
+ \snippet wordcount/main.cpp 2
+ \dots
+
+ The first argument to the \l {QtConcurrent::}{mappedReduced} function is the
+ container to operate on. The second argument is the mapping function
+ \c {countWords()}. It is called in parallel by multiple threads. The
+ third argument is the reducing function \c {reduce()}. It is called
+ once for each result returned by the mapping function, and generates the
+ final computation result.
- The QtConcurrent Word Count example demonstrates the use of the map-reduce
- algorithm when applied to the problem of counting words in a collection
- of files.
+ The function returns a QFuture object of type \c WordCount. Call the
+ \l {QFuture::}{result} function immediately on this QFuture to block further
+ execution until the result becomes available.
- This is a command-line application.
+ \note The mapping function must be thread-safe since it is called from
+ multiple threads.
*/
diff --git a/examples/qtconcurrent/wordcount/main.cpp b/examples/qtconcurrent/wordcount/main.cpp
index f4de2886a8..4175641ce9 100644
--- a/examples/qtconcurrent/wordcount/main.cpp
+++ b/examples/qtconcurrent/wordcount/main.cpp
@@ -1,90 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QList>
-#include <QMap>
-#include <QTextStream>
-#include <QString>
-#include <QStringList>
-#include <QDir>
-#include <QElapsedTimer>
-#include <QApplication>
-#include <QDebug>
-
-#include <qtconcurrentmap.h>
-
-using namespace QtConcurrent;
-
-/*
- Utility function that recursivily searches for files.
-*/
-QStringList findFiles(const QString &startDir, const QStringList &filters)
-{
- QStringList names;
- QDir dir(startDir);
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
- const auto files = dir.entryList(filters, QDir::Files);
- for (const QString &file : files)
- names += startDir + '/' + file;
-
- const auto subdirs = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
- for (const QString &subdir : subdirs)
- names += findFiles(startDir + '/' + subdir, filters);
- return names;
-}
+#include <QtWidgets/qfiledialog.h>
+#include <QtWidgets/qapplication.h>
+#include <QtCore/qmimedatabase.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtConcurrent/qtconcurrentmap.h>
typedef QMap<QString, int> WordCount;
-/*
- Single threaded word counter function.
-*/
+void printHighestResult(const WordCount &, qsizetype);
+QStringList findFiles(const QString &);
+
+// Single threaded word counter function.
WordCount singleThreadedWordCount(const QStringList &files)
{
WordCount wordCount;
@@ -93,7 +21,7 @@ WordCount singleThreadedWordCount(const QStringList &files)
f.open(QIODevice::ReadOnly);
QTextStream textStream(&f);
while (!textStream.atEnd()) {
- const auto words = textStream.readLine().split(' ');
+ const auto words = textStream.readLine().split(' ', Qt::SkipEmptyParts);
for (const QString &word : words)
wordCount[word] += 1;
}
@@ -101,7 +29,6 @@ WordCount singleThreadedWordCount(const QStringList &files)
return wordCount;
}
-
// countWords counts the words in a single file. This function is
// called in parallel by several threads and must be thread
// safe.
@@ -113,7 +40,7 @@ WordCount countWords(const QString &file)
WordCount wordCount;
while (!textStream.atEnd()) {
- const auto words = textStream.readLine().split(' ');
+ const auto words = textStream.readLine().split(' ', Qt::SkipEmptyParts);
for (const QString &word : words)
wordCount[word] += 1;
}
@@ -133,33 +60,93 @@ void reduce(WordCount &result, const WordCount &w)
int main(int argc, char** argv)
{
QApplication app(argc, argv);
- qDebug() << "finding files...";
- QStringList files = findFiles("../../", QStringList() << "*.cpp" << "*.h");
- qDebug() << files.count() << "files";
-
- qDebug() << "warmup";
- {
- WordCount total = singleThreadedWordCount(files);
- }
-
- qDebug() << "warmup done";
-
- int singleThreadTime = 0;
+ app.setOrganizationName("QtProject");
+ app.setApplicationName(QCoreApplication::translate("main", "Word Count"));
+
+ QFileDialog fileDialog;
+ fileDialog.setOption(QFileDialog::ReadOnly);
+ // Grab the directory path from the dialog
+ auto dirPath = QFileDialog::getExistingDirectory(nullptr,
+ QCoreApplication::translate("main","Select a Folder"),
+ QDir::currentPath());
+
+ QStringList files = findFiles(dirPath);
+ qDebug() << QCoreApplication::translate("main", "Indexing %1 files in %2")
+ .arg(files.size()).arg(dirPath);
+
+ // Start the single threaded operation
+ qint64 singleThreadTime;
{
QElapsedTimer timer;
timer.start();
+ //! [1]
WordCount total = singleThreadedWordCount(files);
+ //! [1]
singleThreadTime = timer.elapsed();
- qDebug() << "single thread" << singleThreadTime;
+ qDebug() << QCoreApplication::translate("main", "Single threaded scanning took %1 ms")
+ .arg(singleThreadTime);
}
-
- int mapReduceTime = 0;
+ // Start the multithreaded mappedReduced operation.
+ qint64 mapReduceTime;
{
QElapsedTimer timer;
timer.start();
- WordCount total = mappedReduced(files, countWords, reduce).result();
+ //! [2]
+ WordCount total = QtConcurrent::mappedReduced(files, countWords, reduce).result();
+ //! [2]
mapReduceTime = timer.elapsed();
- qDebug() << "MapReduce" << mapReduceTime;
+ qDebug() << QCoreApplication::translate("main", "MapReduce scanning took %1 ms")
+ .arg(mapReduceTime);
+ qDebug() << QCoreApplication::translate("main", "MapReduce speedup: %1")
+ .arg(((double)singleThreadTime - (double)mapReduceTime) / (double)mapReduceTime + 1);
+ printHighestResult(total, 10);
}
- qDebug() << "MapReduce speedup x" << ((double)singleThreadTime - (double)mapReduceTime) / (double)mapReduceTime + 1;
+}
+
+// Utility function that recursively searches for text files.
+QStringList findFiles(const QString &startDir)
+{
+ QStringList names;
+ QDir dir(startDir);
+ static const QMimeDatabase db;
+
+ const auto files = dir.entryList(QDir::Files);
+ for (const QString &file : files) {
+ const auto path = startDir + QDir::separator() + file;
+ const QMimeType mime = db.mimeTypeForFile(QFileInfo(path));
+ const auto mimeTypesForFile = mime.parentMimeTypes();
+
+ for (const auto &i : mimeTypesForFile) {
+ if (i.contains("text", Qt::CaseInsensitive)
+ || mime.comment().contains("text", Qt::CaseInsensitive)) {
+ names += startDir + QDir::separator() + file;
+ }
+ }
+ }
+
+ const auto subdirs = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
+ for (const QString &subdir : subdirs) {
+ if (names.length() >= 20000) {
+ qDebug() << QCoreApplication::translate("main", "Too many files! Aborting ...");
+ exit(-1);
+ }
+ names += findFiles(startDir + QDir::separator() + subdir);
+ }
+ return names;
+}
+
+// Utility function that prints the results of the map in decreasing order based on the value.
+void printHighestResult(const WordCount &countedWords, qsizetype nResults)
+{
+ using pair = QPair<QString, int>;
+ QList<pair> vec;
+
+ std::copy(countedWords.keyValueBegin(), countedWords.keyValueEnd(),
+ std::back_inserter<QList<pair>>(vec));
+ std::sort(vec.begin(), vec.end(),
+ [](const pair &l, const pair &r) { return l.second > r.second; });
+
+ qDebug() << QCoreApplication::translate("main", "Most occurring words are:");
+ for (qsizetype i = 0; i < qMin(vec.size(), nResults); ++i)
+ qDebug() << vec[i].first << " : " << vec[i].second;
}