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 );
216 if ( static_cast< int >( mTotalProgress * 10 ) !=
static_cast< int >( progress * 10 ) )
222 void QgsTask::completed()
225 processSubTasksForCompletion();
228 void QgsTask::processSubTasksForCompletion()
230 bool subTasksCompleted =
true;
231 Q_FOREACH (
const SubTask &subTask, mSubTasks )
233 if ( subTask.task->status() !=
Complete )
235 subTasksCompleted =
false;
240 if ( mStatus ==
Complete && subTasksCompleted )
247 mTaskFinished.wakeAll();
248 mNotFinishedMutex.unlock();
249 mTaskFinished.wakeAll();
258 void QgsTask::processSubTasksForTermination()
260 bool subTasksTerminated =
true;
261 Q_FOREACH (
const SubTask &subTask, mSubTasks )
265 subTasksTerminated =
false;
276 mTaskFinished.wakeAll();
277 mNotFinishedMutex.unlock();
278 mTaskFinished.wakeAll();
280 else if ( mStatus ==
Terminated && !subTasksTerminated )
287 void QgsTask::processSubTasksForHold()
289 bool subTasksRunning =
false;
290 Q_FOREACH (
const SubTask &subTask, mSubTasks )
292 if ( subTask.task->status() ==
Running )
294 subTasksRunning =
true;
299 if ( mStatus ==
OnHold && !subTasksRunning && mOverallStatus !=
OnHold )
304 else if ( mStatus ==
OnHold && subTasksRunning )
311 void QgsTask::terminated()
314 processSubTasksForTermination();
327 setAutoDelete(
true );
352 , mTaskMutex( new QMutex( QMutex::Recursive ) )
355 this, &QgsTaskManager::layersWillBeRemoved );
365 QMap< long, TaskInfo >
tasks = mTasks;
367 mTaskMutex->unlock();
368 QMap< long, TaskInfo >::const_iterator it = tasks.constBegin();
369 for ( ; it != tasks.constEnd(); ++it )
371 cleanupAndDeleteTask( it.value().task );
379 return addTaskPrivate( task,
QgsTaskList(),
false, priority );
384 return addTaskPrivate( definition.
task,
396 long taskId = mNextTaskId++;
399 mTasks.insert( taskId, TaskInfo( task, priority ) );
406 mParentTasks <<
task;
409 mLayerDependencies.insert( taskId, _qgis_listRawToQPointer( task->
dependentLayers() ) );
410 mTaskMutex->unlock();
419 Q_FOREACH (
const QgsTask::SubTask &subTask, task->mSubTasks )
421 switch ( subTask.dependency )
432 addTaskPrivate( subTask.task, subTask.dependencies,
true, priority );
440 if ( hasCircularDependencies( taskId ) )
456 QMutexLocker ml( mTaskMutex );
458 if ( mTasks.contains(
id ) )
459 t = mTasks.value(
id ).task;
465 QMutexLocker ml( mTaskMutex );
466 return mParentTasks.toList();
471 QMutexLocker ml( mTaskMutex );
472 return mParentTasks.count();
480 QMutexLocker ml( mTaskMutex );
481 QMap< long, TaskInfo >::const_iterator it = mTasks.constBegin();
482 for ( ; it != mTasks.constEnd(); ++it )
484 if ( it.value().task ==
task )
495 QSet< QgsTask * > parents = mParentTasks;
497 mTaskMutex->unlock();
499 Q_FOREACH (
QgsTask *task, parents )
508 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
509 dependencies.detach();
510 mTaskMutex->unlock();
512 if ( !dependencies.contains( taskId ) )
515 Q_FOREACH (
QgsTask *task, dependencies.value( taskId ) )
527 if ( resolveDependencies( taskId, taskId, results ) )
533 bool QgsTaskManager::resolveDependencies(
long firstTaskId,
long currentTaskId, QSet<long> &results )
const 536 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
537 dependencies.detach();
538 mTaskMutex->unlock();
540 if ( !dependencies.contains( currentTaskId ) )
543 Q_FOREACH (
QgsTask *task, dependencies.value( currentTaskId ) )
545 long dependentTaskId =
taskId( task );
546 if ( dependentTaskId >= 0 )
548 if ( dependentTaskId == firstTaskId )
553 results.insert( dependentTaskId );
555 QSet< long > newTaskDeps;
556 if ( !resolveDependencies( firstTaskId, dependentTaskId, newTaskDeps ) )
559 if ( newTaskDeps.contains( firstTaskId ) )
565 results.unite( newTaskDeps );
572 bool QgsTaskManager::hasCircularDependencies(
long taskId )
const 575 return !resolveDependencies( taskId, taskId, d );
580 QMutexLocker ml( mTaskMutex );
586 QMutexLocker ml( mTaskMutex );
587 QList< QgsTask * >
tasks;
588 QMap< long, QgsWeakMapLayerPointerList >::const_iterator layerIt = mLayerDependencies.constBegin();
589 for ( ; layerIt != mLayerDependencies.constEnd(); ++layerIt )
591 if ( _qgis_listQPointerToRaw( layerIt.value() ).contains( layer ) )
603 QMutexLocker ml( mTaskMutex );
605 activeTasks.intersect( mParentTasks );
606 return activeTasks.toList();
611 QMutexLocker ml( mTaskMutex );
612 QSet< QgsTask * >
tasks = mActiveTasks;
613 return tasks.intersect( mParentTasks ).count();
622 void QgsTaskManager::taskProgressChanged(
double progress )
639 void QgsTaskManager::taskStatusChanged(
int status )
649 #if QT_VERSION >= 0x050500 651 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
652 mTaskMutex->unlock();
654 QThreadPool::globalInstance()->cancel( runnable );
666 cancelDependentTasks(
id );
670 bool isParent = mParentTasks.contains( task );
671 mTaskMutex->unlock();
682 cleanupAndDeleteTask( task );
687 void QgsTaskManager::layersWillBeRemoved(
const QList< QgsMapLayer * > &layers )
691 QMap< long, QgsWeakMapLayerPointerList > layerDependencies = mLayerDependencies;
692 layerDependencies.detach();
693 mTaskMutex->unlock();
698 for ( QMap< long, QgsWeakMapLayerPointerList >::const_iterator it = layerDependencies.constBegin();
699 it != layerDependencies.constEnd(); ++it )
701 if ( !( _qgis_listQPointerToRaw( it.value() ).contains( layer ) ) )
718 bool QgsTaskManager::cleanupAndDeleteTask(
QgsTask *task )
727 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
729 task->disconnect(
this );
732 if ( mTaskDependencies.contains(
id ) )
733 mTaskDependencies.remove(
id );
734 mTaskMutex->unlock();
739 bool isParent = mParentTasks.contains( task );
740 mParentTasks.remove( task );
741 mSubTasks.remove( task );
743 mLayerDependencies.remove(
id );
757 #if QT_VERSION >= 0x050500 759 QThreadPool::globalInstance()->cancel( runnable );
769 for ( QMap< long, QgsTaskList >::iterator it = mTaskDependencies.begin(); it != mTaskDependencies.end(); ++it )
771 if ( it.value().contains( task ) )
773 it.value().removeAll( task );
776 mTaskMutex->unlock();
781 void QgsTaskManager::processQueue()
785 mActiveTasks.clear();
786 for ( QMap< long, TaskInfo >::iterator it = mTasks.begin(); it != mTasks.end(); ++it )
788 QgsTask *task = it.value().task;
791 it.value().createRunnable();
792 QThreadPool::globalInstance()->start( it.value().runnable, it.value().priority );
797 mActiveTasks <<
task;
801 bool allFinished = mActiveTasks.isEmpty();
802 mTaskMutex->unlock();
810 if ( prevActiveCount != newActiveCount )
816 void QgsTaskManager::cancelDependentTasks(
long taskId )
822 QMap< long, QgsTaskList > taskDependencies = mTaskDependencies;
823 taskDependencies.detach();
824 mTaskMutex->unlock();
826 QMap< long, QgsTaskList >::const_iterator it = taskDependencies.constBegin();
827 for ( ; it != taskDependencies.constEnd(); ++it )
829 if ( it.value().contains( canceledTask ) )
842 QgsTaskManager::TaskInfo::TaskInfo(
QgsTask *task,
int priority )
845 , priority( priority )
848 void QgsTaskManager::TaskInfo::createRunnable()
850 Q_ASSERT( !runnable );
851 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.