/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** 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 General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #ifndef MULTITASK_H #define MULTITASK_H #include "utils_global.h" #include "runextensions.h" #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace QtConcurrent { class QTCREATOR_UTILS_EXPORT MultiTaskBase : public QObject, public QRunnable { Q_OBJECT protected slots: virtual void cancelSelf() = 0; virtual void setFinished() = 0; virtual void setProgressRange(int min, int max) = 0; virtual void setProgressValue(int value) = 0; virtual void setProgressText(QString value) = 0; }; template class MultiTask : public MultiTaskBase { public: MultiTask(void (Class::*fn)(QFutureInterface &), const QList &objects) : fn(fn), objects(objects) { maxProgress = 100*objects.size(); } QFuture future() { futureInterface.reportStarted(); return futureInterface.future(); } void run() { QThreadPool::globalInstance()->releaseThread(); futureInterface.setProgressRange(0, maxProgress); foreach (Class *object, objects) { QFutureWatcher *watcher = new QFutureWatcher(); watchers.insert(object, watcher); finished.insert(watcher, false); connect(watcher, &QFutureWatcherBase::finished, this, &MultiTask::setFinished); connect(watcher, &QFutureWatcherBase::progressRangeChanged, this, &MultiTask::setProgressRange); connect(watcher, &QFutureWatcherBase::progressValueChanged, this, &MultiTask::setProgressValue); connect(watcher, &QFutureWatcherBase::progressTextChanged, this, &MultiTask::setProgressText); watcher->setFuture(QtConcurrent::run(fn, object)); } selfWatcher = new QFutureWatcher(); connect(selfWatcher, &QFutureWatcherBase::canceled, this, &MultiTask::cancelSelf); selfWatcher->setFuture(futureInterface.future()); loop = new QEventLoop; loop->exec(); futureInterface.reportFinished(); QThreadPool::globalInstance()->reserveThread(); qDeleteAll(watchers); delete selfWatcher; delete loop; } protected: void cancelSelf() { foreach (QFutureWatcher *watcher, watchers) watcher->future().cancel(); } void setFinished() { updateProgress(); QFutureWatcher *watcher = static_cast *>(sender()); if (finished.contains(watcher)) finished[watcher] = true; bool allFinished = true; foreach (bool isFinished, finished) { if (!isFinished) { allFinished = false; break; } } if (allFinished) loop->quit(); } void setProgressRange(int min, int max) { Q_UNUSED(min) Q_UNUSED(max) updateProgress(); } void setProgressValue(int value) { Q_UNUSED(value) updateProgress(); } void setProgressText(QString value) { Q_UNUSED(value) updateProgressText(); } private: void updateProgress() { int progressSum = 0; foreach (QFutureWatcher *watcher, watchers) { if (watcher->progressMinimum() == watcher->progressMaximum()) { if (watcher->future().isFinished() && !watcher->future().isCanceled()) progressSum += 100; } else { progressSum += 100*(watcher->progressValue()-watcher->progressMinimum())/(watcher->progressMaximum()-watcher->progressMinimum()); } } futureInterface.setProgressValue(progressSum); } void updateProgressText() { QString text; foreach (QFutureWatcher *watcher, watchers) { if (!watcher->progressText().isEmpty()) { text += watcher->progressText(); text += QLatin1Char('\n'); } } text = text.trimmed(); futureInterface.setProgressValueAndText(futureInterface.progressValue(), text); } QFutureInterface futureInterface; void (Class::*fn)(QFutureInterface &); QList objects; QFutureWatcher *selfWatcher; QMap *> watchers; QMap *, bool> finished; QEventLoop *loop; int maxProgress; }; template QFuture run(void (Class::*fn)(QFutureInterface &), const QList &objects, int priority = 0) { MultiTask *task = new MultiTask(fn, objects); QFuture future = task->future(); QThreadPool::globalInstance()->start(task, priority); return future; } } // namespace QtConcurrent QT_END_NAMESPACE #endif // MULTITASK_H