21 #include <QtConcurrentRun> 30 , mDescription( name )
36 Q_ASSERT_X( mStatus !=
Running,
"delete", QStringLiteral(
"status was %1" ).arg( mStatus ).toLatin1() );
37 mNotFinishedMutex.tryLock();
38 Q_FOREACH (
const SubTask &subTask, mSubTasks )
42 mNotFinishedMutex.unlock();
47 return mElapsedTime.elapsed();
52 mNotFinishedMutex.lock();
54 Q_ASSERT( mStartCount == 1 );
84 mShouldTerminate =
true;
86 #if QT_VERSION >= 0x050500 97 processSubTasksForTermination();
100 Q_FOREACH (
const SubTask &subTask, mSubTasks )
102 subTask.task->cancel();
111 processSubTasksForHold();
114 Q_FOREACH (
const SubTask &subTask, mSubTasks )
116 subTask.task->hold();
129 Q_FOREACH (
const SubTask &subTask, mSubTasks )
131 subTask.task->unhold();
138 mSubTasks << SubTask( subTask, dependencies, subTaskDependency );
145 return _qgis_listQPointerToRaw( mDependentLayers );
158 timeout = std::numeric_limits< int >::max();
159 if ( mNotFinishedMutex.tryLock( timeout ) )
161 mNotFinishedMutex.unlock();
174 mDependentLayers = _qgis_listRawToQPointer( dependentLayers );
177 void QgsTask::subTaskStatusChanged(
int status )
190 processSubTasksForCompletion();
195 processSubTasksForTermination();
199 processSubTasksForHold();
212 if ( !mSubTasks.isEmpty() )
216 double totalProgress = 0.0;
217 Q_FOREACH (
const SubTask &subTask, mSubTasks )
221 totalProgress += 100.0;
225 totalProgress += subTask.task->progress();
228 progress = ( progress + totalProgress ) / ( mSubTasks.count() + 1 );
232 double prevProgress = mTotalProgress;
236 if ( static_cast< int >( prevProgress * 10 ) !=
static_cast< int >( mTotalProgress * 10 ) )
240 void QgsTask::completed()
243 processSubTasksForCompletion();
246 void QgsTask::processSubTasksForCompletion()
248 bool subTasksCompleted =
true;
249 Q_FOREACH (
const SubTask &subTask, mSubTasks )
251 if ( subTask.task->status() !=
Complete )
253 subTasksCompleted =
false;
258 if ( mStatus ==
Complete && subTasksCompleted )
265 mNotFinishedMutex.tryLock();
266 mNotFinishedMutex.unlock();
275 void QgsTask::processSubTasksForTermination()
277 bool subTasksTerminated =
true;
278 Q_FOREACH (
const SubTask &subTask, mSubTasks )
282 subTasksTerminated =
false;
293 mNotFinishedMutex.tryLock();
294 mNotFinishedMutex.unlock();
296 else if ( mStatus ==
Terminated && !subTasksTerminated )
303 void QgsTask::processSubTasksForHold()
305 bool subTasksRunning =
false;
306 Q_FOREACH (
const SubTask &subTask, mSubTasks )
308 if ( subTask.task->status() ==
Running )
310 subTasksRunning =
true;
315 if ( mStatus ==
OnHold && !subTasksRunning && mOverallStatus !=
OnHold )
320 else if ( mStatus ==
OnHold && subTasksRunning )
327 void QgsTask::terminated()
330 processSubTasksForTermination();
343 setAutoDelete(
true );
368 , mTaskMutex( new QMutex( QMutex::Recursive ) )
371 this, &QgsTaskManager::layersWillBeRemoved );
381 QMap< long, TaskInfo >
tasks = mTasks;
383 mTaskMutex->unlock();
384 QMap< long, TaskInfo >::const_iterator it = tasks.constBegin();
385 for ( ; it != tasks.constEnd(); ++it )
387 cleanupAndDeleteTask( it.value().task );
395 return addTaskPrivate( task,
QgsTaskList(),
false, priority );
400 return addTaskPrivate( definition.
task,
412 long taskId = mNextTaskId++;
415 mTasks.insert( taskId, TaskInfo( task, priority ) );
422 mParentTasks <<
task;
425 mLayerDependencies.insert( taskId, _qgis_listRawToQPointer( task->
dependentLayers() ) );
426 mTaskMutex->unlock();
435 Q_FOREACH (
const QgsTask::SubTask &subTask, task->mSubTasks )
437 switch ( subTask.dependency )
448 addTaskPrivate( subTask.task, subTask.dependencies,
true, priority );
456 if ( hasCircularDependencies( taskId ) )
472 QMutexLocker ml( mTaskMutex );
474 if ( mTasks.contains(
id ) )
475 t = mTasks.value(
id ).task;
481 QMutexLocker ml( mTaskMutex );
482 return mParentTasks.toList();
487 QMutexLocker ml( mTaskMutex );
488 return mParentTasks.count();
496 QMutexLocker ml( mTaskMutex );
497 QMap< long, TaskInfo >::const_iterator it = mTasks.constBegin();
498 for ( ; it != mTasks.constEnd(); ++it )
500 if ( it.value().task ==
task )
511 QSet< QgsTask * > parents = mParentTasks;
513 mTaskMutex->unlock();
515 Q_FOREACH (
QgsTask *task, parents )
524 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
525 dependencies.detach();
526 mTaskMutex->unlock();
528 if ( !dependencies.contains( taskId ) )
531 Q_FOREACH (
QgsTask *task, dependencies.value( taskId ) )
543 if ( resolveDependencies( taskId, taskId, results ) )
549 bool QgsTaskManager::resolveDependencies(
long firstTaskId,
long currentTaskId, QSet<long> &results )
const 552 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
553 dependencies.detach();
554 mTaskMutex->unlock();
556 if ( !dependencies.contains( currentTaskId ) )
559 Q_FOREACH (
QgsTask *task, dependencies.value( currentTaskId ) )
561 long dependentTaskId =
taskId( task );
562 if ( dependentTaskId >= 0 )
564 if ( dependentTaskId == firstTaskId )
569 results.insert( dependentTaskId );
571 QSet< long > newTaskDeps;
572 if ( !resolveDependencies( firstTaskId, dependentTaskId, newTaskDeps ) )
575 if ( newTaskDeps.contains( firstTaskId ) )
581 results.unite( newTaskDeps );
588 bool QgsTaskManager::hasCircularDependencies(
long taskId )
const 591 return !resolveDependencies( taskId, taskId, d );
596 QMutexLocker ml( mTaskMutex );
602 QMutexLocker ml( mTaskMutex );
603 QList< QgsTask * >
tasks;
604 QMap< long, QgsWeakMapLayerPointerList >::const_iterator layerIt = mLayerDependencies.constBegin();
605 for ( ; layerIt != mLayerDependencies.constEnd(); ++layerIt )
607 if ( _qgis_listQPointerToRaw( layerIt.value() ).contains( layer ) )
619 QMutexLocker ml( mTaskMutex );
621 activeTasks.intersect( mParentTasks );
622 return activeTasks.toList();
627 QMutexLocker ml( mTaskMutex );
628 QSet< QgsTask * >
tasks = mActiveTasks;
629 return tasks.intersect( mParentTasks ).count();
638 void QgsTaskManager::taskProgressChanged(
double progress )
655 void QgsTaskManager::taskStatusChanged(
int status )
665 #if QT_VERSION >= 0x050500 667 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
668 mTaskMutex->unlock();
670 QThreadPool::globalInstance()->cancel( runnable );
682 cancelDependentTasks(
id );
686 bool isParent = mParentTasks.contains( task );
687 mTaskMutex->unlock();
698 cleanupAndDeleteTask( task );
703 void QgsTaskManager::layersWillBeRemoved(
const QList< QgsMapLayer * > &layers )
707 QMap< long, QgsWeakMapLayerPointerList > layerDependencies = mLayerDependencies;
708 layerDependencies.detach();
709 mTaskMutex->unlock();
714 for ( QMap< long, QgsWeakMapLayerPointerList >::const_iterator it = layerDependencies.constBegin();
715 it != layerDependencies.constEnd(); ++it )
717 if ( !( _qgis_listQPointerToRaw( it.value() ).contains( layer ) ) )
734 bool QgsTaskManager::cleanupAndDeleteTask(
QgsTask *task )
743 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
745 task->disconnect(
this );
748 if ( mTaskDependencies.contains(
id ) )
749 mTaskDependencies.remove(
id );
750 mTaskMutex->unlock();
755 bool isParent = mParentTasks.contains( task );
756 mParentTasks.remove( task );
757 mSubTasks.remove( task );
759 mLayerDependencies.remove(
id );
773 #if QT_VERSION >= 0x050500 775 QThreadPool::globalInstance()->cancel( runnable );
785 for ( QMap< long, QgsTaskList >::iterator it = mTaskDependencies.begin(); it != mTaskDependencies.end(); ++it )
787 if ( it.value().contains( task ) )
789 it.value().removeAll( task );
792 mTaskMutex->unlock();
797 void QgsTaskManager::processQueue()
801 mActiveTasks.clear();
802 for ( QMap< long, TaskInfo >::iterator it = mTasks.begin(); it != mTasks.end(); ++it )
804 QgsTask *task = it.value().task;
807 it.value().createRunnable();
808 QThreadPool::globalInstance()->start( it.value().runnable, it.value().priority );
813 mActiveTasks <<
task;
817 bool allFinished = mActiveTasks.isEmpty();
818 mTaskMutex->unlock();
826 if ( prevActiveCount != newActiveCount )
832 void QgsTaskManager::cancelDependentTasks(
long taskId )
838 QMap< long, QgsTaskList > taskDependencies = mTaskDependencies;
839 taskDependencies.detach();
840 mTaskMutex->unlock();
842 QMap< long, QgsTaskList >::const_iterator it = taskDependencies.constBegin();
843 for ( ; it != taskDependencies.constEnd(); ++it )
845 if ( it.value().contains( canceledTask ) )
858 QgsTaskManager::TaskInfo::TaskInfo(
QgsTask *task,
int priority )
861 , priority( priority )
864 void QgsTaskManager::TaskInfo::createRunnable()
866 Q_ASSERT( !runnable );
867 runnable =
new QgsTaskRunnableWrapper( task );
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.
double progress() const
Returns the task's progress (between 0.0 and 100.0)
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.
Subtask must complete before parent can begin.
void setDependentLayers(const QList< QgsMapLayer * > &dependentLayers)
Sets a list of layers on which the task depends.
QgsTaskManager(QObject *parent=nullptr)
Constructor for QgsTaskManager.
bool waitForFinished(int timeout=30000)
Blocks the current thread until the task finishes or a maximum of timeout milliseconds.
void begun()
Will be emitted by task to indicate its commencement.
QList< QgsMapLayer * > dependentLayers(long taskId) const
Returns a list of layers on which as task is dependent.
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.
long taskId(QgsTask *task) const
Returns the unique task ID corresponding to a task managed by the class.
QList< QgsTask * > tasksDependentOnLayer(QgsMapLayer *layer) const
Returns a list of tasks which depend on a layer.
void progressChanged(double progress)
Will be emitted by task when its progress changes.
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.
void progressChanged(long taskId, double progress)
Will be emitted when a task reports a progress change.
int countActiveTasks() const
Returns the number of active (queued or running) tasks.
Definition of a task for inclusion in the manager.
Task is queued but on hold and will not be started.
int count() const
Returns the number of tasks tracked by the manager.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Abstract base class for long running background tasks.
qint64 elapsedTime() const
Returns the elapsed time since the task commenced, in milliseconds.
Reads and writes project states.
friend class QgsTaskRunnableWrapper
void statusChanged(long taskId, int status)
Will be emitted when a task reports a status change.
bool dependenciesSatisfied(long taskId) const
Returns true if all dependencies for the specified task are satisfied.
Task successfully completed.
void taskAdded(long taskId)
Emitted when a new task has been added to the manager.
QList< QgsTask * > activeTasks() const
Returns a list of the active (queued or running) tasks.
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.
QList< QgsTask * > tasks() const
Returns all tasks tracked by the manager.
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
Task is currently running.
~QgsTaskManager() override
QList< QgsWeakMapLayerPointer > QgsWeakMapLayerPointerList
A list of weak pointers to QgsMapLayers.
static QgsProject * instance()
Returns the QgsProject singleton instance.
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.
QgsTask * task(long id) const
Returns the task with matching ID.
void unhold()
Releases the task from being held.
QList< QgsMapLayer * > dependentLayers() const
Returns the list of layers on which the task depends.
TaskStatus status() const
Returns the current task status.
QSet< long > dependencies(long taskId) const
Returns the set of task IDs on which a task is dependent.