/*************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Qt Software Information (qt-info@nokia.com) ** ** ** Non-Open Source Usage ** ** Licensees may use this file in accordance with the Qt Beta Version ** License Agreement, Agreement version 2.2 provided with the Software or, ** alternatively, in accordance with the terms contained in a written ** agreement between you and Nokia. ** ** GNU General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU General ** Public License versions 2.0 or 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 GNU ** General Public Licensing requirements will be met: ** ** http://www.fsf.org/licensing/licenses/info/GPLv2.html and ** http://www.gnu.org/copyleft/gpl.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt GPL Exception ** version 1.3, included in the file GPL_EXCEPTION.txt in this package. ** ***************************************************************************/ #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.values()); 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; const QList finishedValues = finished.values(); foreach (bool isFinished, finishedValues) { 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; const QList *> watchersValues = watchers.values(); foreach (QFutureWatcher *watcher, watchersValues) { 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; const QList *> watchersValues = watchers.values(); foreach (QFutureWatcher *watcher, watchersValues) { 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