/************************************************************************** ** ** This file is part of the Qt Build Suite ** ** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (info@qt.nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. ** Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** **************************************************************************/ #ifndef MULTITASK_H #define MULTITASK_H #include "qtconcurrent_global.h" #include "runextensions.h" #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace QtConcurrent { class QTCONCURRENT_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, SIGNAL(finished()), this, SLOT(setFinished())); connect(watcher, SIGNAL(progressRangeChanged(int,int)), this, SLOT(setProgressRange(int,int))); connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(setProgressValue(int))); connect(watcher, SIGNAL(progressTextChanged(QString)), this, SLOT(setProgressText(QString))); watcher->setFuture(QtConcurrent::run(fn, object)); } selfWatcher = new QFutureWatcher(); connect(selfWatcher, SIGNAL(canceled()), this, SLOT(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() + "\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