21 #include <QtConcurrentRun> 30 , mDescription( name )
36 Q_ASSERT_X( mStatus !=
Running,
"delete", QString(
"status was %1" ).arg( mStatus ).toLatin1() );
38 Q_FOREACH (
const SubTask &subTask, mSubTasks )
46 mNotFinishedMutex.lock();
48 Q_ASSERT( mStartCount == 1 );
76 mShouldTerminate =
true;
78 #if QT_VERSION >= 0x050500 89 processSubTasksForTermination();
92 Q_FOREACH (
const SubTask &subTask, mSubTasks )
94 subTask.task->cancel();
103 processSubTasksForHold();
106 Q_FOREACH (
const SubTask &subTask, mSubTasks )
108 subTask.task->hold();
121 Q_FOREACH (
const SubTask &subTask, mSubTasks )
123 subTask.task->unhold();
130 mSubTasks << SubTask( subTask, dependencies, subTaskDependency );
137 return _qgis_listQPointerToRaw( mDependentLayers );
151 rv = mTaskFinished.wait( &mNotFinishedMutex, timeout );
158 mDependentLayers = _qgis_listRawToQPointer( dependentLayers );
161 void QgsTask::subTaskStatusChanged(
int status )
174 processSubTasksForCompletion();
179 processSubTasksForTermination();
183 processSubTasksForHold();
196 if ( !mSubTasks.isEmpty() )
200 double totalProgress = 0.0;
201 Q_FOREACH (
const SubTask &subTask, mSubTasks )
205 totalProgress += 100.0;
209 totalProgress += subTask.task->progress();
212 progress = ( progress + totalProgress ) / ( mSubTasks.count() + 1 );
219 void QgsTask::completed()
222 processSubTasksForCompletion();
225 void QgsTask::processSubTasksForCompletion()
227 bool subTasksCompleted =
true;
228 Q_FOREACH (
const SubTask &subTask, mSubTasks )
230 if ( subTask.task->status() !=
Complete )
232 subTasksCompleted =
false;
237 if ( mStatus ==
Complete && subTasksCompleted )
244 mTaskFinished.wakeAll();
245 mNotFinishedMutex.unlock();
246 mTaskFinished.wakeAll();
255 void QgsTask::processSubTasksForTermination()
257 bool subTasksTerminated =
true;
258 Q_FOREACH (
const SubTask &subTask, mSubTasks )
262 subTasksTerminated =
false;
273 mTaskFinished.wakeAll();
274 mNotFinishedMutex.unlock();
275 mTaskFinished.wakeAll();
277 else if ( mStatus ==
Terminated && !subTasksTerminated )
284 void QgsTask::processSubTasksForHold()
286 bool subTasksRunning =
false;
287 Q_FOREACH (
const SubTask &subTask, mSubTasks )
289 if ( subTask.task->status() ==
Running )
291 subTasksRunning =
true;
296 if ( mStatus ==
OnHold && !subTasksRunning && mOverallStatus !=
OnHold )
301 else if ( mStatus ==
OnHold && subTasksRunning )
308 void QgsTask::terminated()
311 processSubTasksForTermination();
324 setAutoDelete(
true );
349 , mTaskMutex( new QMutex( QMutex::Recursive ) )
352 this, &QgsTaskManager::layersWillBeRemoved );
362 QMap< long, TaskInfo >
tasks = mTasks;
364 mTaskMutex->unlock();
365 QMap< long, TaskInfo >::const_iterator it = tasks.constBegin();
366 for ( ; it != tasks.constEnd(); ++it )
368 cleanupAndDeleteTask( it.value().task );
376 return addTaskPrivate( task,
QgsTaskList(),
false, priority );
381 return addTaskPrivate( definition.
task,
390 long taskId = mNextTaskId++;
393 mTasks.insert( taskId, TaskInfo( task, priority ) );
400 mParentTasks <<
task;
403 mLayerDependencies.insert( taskId, _qgis_listRawToQPointer( task->
dependentLayers() ) );
404 mTaskMutex->unlock();
413 Q_FOREACH (
const QgsTask::SubTask &subTask, task->mSubTasks )
415 switch ( subTask.dependency )
426 addTaskPrivate( subTask.task, subTask.dependencies,
true, priority );
434 if ( hasCircularDependencies( taskId ) )
450 QMutexLocker ml( mTaskMutex );
452 if ( mTasks.contains(
id ) )
453 t = mTasks.value(
id ).task;
459 QMutexLocker ml( mTaskMutex );
460 return mParentTasks.toList();
465 QMutexLocker ml( mTaskMutex );
466 return mParentTasks.count();
474 QMutexLocker ml( mTaskMutex );
475 QMap< long, TaskInfo >::const_iterator it = mTasks.constBegin();
476 for ( ; it != mTasks.constEnd(); ++it )
478 if ( it.value().task ==
task )
489 QSet< QgsTask * > parents = mParentTasks;
491 mTaskMutex->unlock();
493 Q_FOREACH (
QgsTask *task, parents )
502 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
503 dependencies.detach();
504 mTaskMutex->unlock();
506 if ( !dependencies.contains( taskId ) )
509 Q_FOREACH (
QgsTask *task, dependencies.value( taskId ) )
521 if ( resolveDependencies( taskId, taskId, results ) )
527 bool QgsTaskManager::resolveDependencies(
long firstTaskId,
long currentTaskId, QSet<long> &results )
const 530 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
531 dependencies.detach();
532 mTaskMutex->unlock();
534 if ( !dependencies.contains( currentTaskId ) )
537 Q_FOREACH (
QgsTask *task, dependencies.value( currentTaskId ) )
539 long dependentTaskId =
taskId( task );
540 if ( dependentTaskId >= 0 )
542 if ( dependentTaskId == firstTaskId )
547 results.insert( dependentTaskId );
549 QSet< long > newTaskDeps;
550 if ( !resolveDependencies( firstTaskId, dependentTaskId, newTaskDeps ) )
553 if ( newTaskDeps.contains( firstTaskId ) )
559 results.unite( newTaskDeps );
566 bool QgsTaskManager::hasCircularDependencies(
long taskId )
const 569 return !resolveDependencies( taskId, taskId, d );
574 QMutexLocker ml( mTaskMutex );
580 QMutexLocker ml( mTaskMutex );
581 QList< QgsTask * >
tasks;
582 QMap< long, QgsWeakMapLayerPointerList >::const_iterator layerIt = mLayerDependencies.constBegin();
583 for ( ; layerIt != mLayerDependencies.constEnd(); ++layerIt )
585 if ( _qgis_listQPointerToRaw( layerIt.value() ).contains( layer ) )
597 QMutexLocker ml( mTaskMutex );
599 activeTasks.intersect( mParentTasks );
600 return activeTasks.toList();
605 QMutexLocker ml( mTaskMutex );
606 QSet< QgsTask * >
tasks = mActiveTasks;
607 return tasks.intersect( mParentTasks ).count();
616 void QgsTaskManager::taskProgressChanged(
double progress )
633 void QgsTaskManager::taskStatusChanged(
int status )
643 #if QT_VERSION >= 0x050500 645 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
646 mTaskMutex->unlock();
648 QThreadPool::globalInstance()->cancel( runnable );
660 cancelDependentTasks(
id );
664 bool isParent = mParentTasks.contains( task );
665 mTaskMutex->unlock();
676 cleanupAndDeleteTask( task );
681 void QgsTaskManager::layersWillBeRemoved(
const QList< QgsMapLayer * > &layers )
685 QMap< long, QgsWeakMapLayerPointerList > layerDependencies = mLayerDependencies;
686 layerDependencies.detach();
687 mTaskMutex->unlock();
692 for ( QMap< long, QgsWeakMapLayerPointerList >::const_iterator it = layerDependencies.constBegin();
693 it != layerDependencies.constEnd(); ++it )
695 if ( !( _qgis_listQPointerToRaw( it.value() ).contains( layer ) ) )
712 bool QgsTaskManager::cleanupAndDeleteTask(
QgsTask *task )
721 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
723 task->disconnect(
this );
726 if ( mTaskDependencies.contains(
id ) )
727 mTaskDependencies.remove(
id );
728 mTaskMutex->unlock();
733 bool isParent = mParentTasks.contains( task );
734 mParentTasks.remove( task );
735 mSubTasks.remove( task );
737 mLayerDependencies.remove(
id );
751 #if QT_VERSION >= 0x050500 753 QThreadPool::globalInstance()->cancel( runnable );
763 for ( QMap< long, QgsTaskList >::iterator it = mTaskDependencies.begin(); it != mTaskDependencies.end(); ++it )
765 if ( it.value().contains( task ) )
767 it.value().removeAll( task );
770 mTaskMutex->unlock();
775 void QgsTaskManager::processQueue()
779 mActiveTasks.clear();
780 for ( QMap< long, TaskInfo >::iterator it = mTasks.begin(); it != mTasks.end(); ++it )
782 QgsTask *task = it.value().task;
785 it.value().createRunnable();
786 QThreadPool::globalInstance()->start( it.value().runnable, it.value().priority );
791 mActiveTasks <<
task;
795 bool allFinished = mActiveTasks.isEmpty();
796 mTaskMutex->unlock();
804 if ( prevActiveCount != newActiveCount )
810 void QgsTaskManager::cancelDependentTasks(
long taskId )
816 QMap< long, QgsTaskList > taskDependencies = mTaskDependencies;
817 taskDependencies.detach();
818 mTaskMutex->unlock();
820 QMap< long, QgsTaskList >::const_iterator it = taskDependencies.constBegin();
821 for ( ; it != taskDependencies.constEnd(); ++it )
823 if ( it.value().contains( canceledTask ) )
836 QgsTaskManager::TaskInfo::TaskInfo(
QgsTask *task,
int priority )
839 , priority( priority )
842 void QgsTaskManager::TaskInfo::createRunnable()
844 Q_ASSERT( !runnable );
845 runnable =
new QgsTaskRunnableWrapper( task );
bool dependenciesSatisfied(long taskId) const
Returns true if all dependencies for the specified task are satisfied.
int countActiveTasks() const
Returns the number of active (queued or running) tasks.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e...
void setProgress(double progress)
Sets the task's current progress.
Base class for all map layer types.
void hold()
Places the task on hold.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
void taskTriggered(QgsTask *task)
Emitted when a task is triggered.
QList< QgsMapLayer *> dependentLayers() const
Returns the list of layers on which the task depends.
QgsTask(const QString &description=QString(), QgsTask::Flags flags=AllFlags)
Constructor for QgsTask.
void statusChanged(int status)
Will be emitted by task when its status changes.
QList< QgsTask *> QgsTaskList
List of QgsTask objects.
int count() const
Returns the number of tasks tracked by the manager.
Subtask must complete before parent can begin.
QgsTaskManager(QObject *parent=nullptr)
Constructor for QgsTaskManager.
void setDependentLayers(const QList< QgsMapLayer *> &dependentLayers)
Sets a list of layers on which the task depends.
QList< QgsTask * > tasks() const
Returns all tasks tracked by the manager.
void begun()
Will be emitted by task to indicate its commencement.
SubTaskDependency
Controls how subtasks relate to their parent task.
void cancelAll()
Instructs all tasks tracked by the manager to terminate.
QgsTaskList dependentTasks
List of dependent tasks which must be completed before task can run.
void progressChanged(double progress)
Will be emitted by task when its progress changes.
QSet< long > dependencies(long taskId) const
Returns the set of task IDs on which a task is dependent.
void taskAboutToBeDeleted(long taskId)
Emitted when a task is about to be deleted.
Task was terminated or errored.
void countActiveTasksChanged(int count)
Emitted when the number of active tasks changes.
void triggerTask(QgsTask *task)
Triggers a task, e.g.
QList< QgsTask *> tasksDependentOnLayer(QgsMapLayer *layer) const
Returns a list of tasks which depend on a layer.
QgsTask * task(long id) const
Returns the task with matching ID.
void progressChanged(long taskId, double progress)
Will be emitted when a task reports a progress change.
Definition of a task for inclusion in the manager.
Task is queued but on hold and will not be started.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Abstract base class for long running background tasks.
Reads and writes project states.
friend class QgsTaskRunnableWrapper
void statusChanged(long taskId, int status)
Will be emitted when a task reports a status change.
Task successfully completed.
void taskAdded(long taskId)
Emitted when a new task has been added to the manager.
virtual void cancel()
Notifies the task that it should terminate.
void allTasksFinished()
Emitted when all tasks are complete.
Task is queued and has not begun.
double progress() const
Returns the task's progress (between 0.0 and 100.0)
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
QList< QgsTask *> activeTasks() const
Returns a list of the active (queued or running) tasks.
Task is currently running.
~QgsTaskManager() override
QList< QgsWeakMapLayerPointer > QgsWeakMapLayerPointerList
A list of weak pointers to QgsMapLayers.
static QgsProject * instance()
Returns the QgsProject singleton instance.
long taskId(QgsTask *task) const
Returns the unique task ID corresponding to a task managed by the class.
virtual void finished(bool result)
If the task is managed by a QgsTaskManager, this will be called after the task has finished (whether ...
virtual bool run()=0
Performs the task's operation.
void finalTaskProgressChanged(double progress)
Will be emitted when only a single task remains to complete and that task has reported a progress cha...
Subtask is independent of the parent, and can run before, after or at the same time as the parent...
void addSubTask(QgsTask *subTask, const QgsTaskList &dependencies=QgsTaskList(), SubTaskDependency subTaskDependency=SubTaskIndependent)
Adds a subtask to this task.
void unhold()
Releases the task from being held.
bool waitForFinished(unsigned long timeout=30000)
Blocks the current thread until the task finishes or a maximum of timeout milliseconds.
TaskStatus status() const
Returns the current task status.
QList< QgsMapLayer *> dependentLayers(long taskId) const
Returns a list of layers on which as task is dependent.