21 #include <QtConcurrentRun>    30   , mDescription( name )
    31   , mNotStartedMutex( 1 )
    33   mNotStartedMutex.acquire();
    38   Q_ASSERT_X( mStatus != 
Running, 
"delete", QStringLiteral( 
"status was %1" ).arg( mStatus ).toLatin1() );
    39   mNotFinishedMutex.tryLock(); 
    40   const auto constMSubTasks = mSubTasks;
    41   for ( 
const SubTask &subTask : constMSubTasks )
    45   mNotFinishedMutex.unlock();
    46   mNotStartedMutex.release();
    56   return mElapsedTime.elapsed();
    61   mNotFinishedMutex.lock();
    62   mNotStartedMutex.release();
    64   Q_ASSERT( mStartCount == 1 );
    94   mShouldTerminate = 
true;
    99     mNotStartedMutex.release();
   104     processSubTasksForTermination();
   107   const auto constMSubTasks = mSubTasks;
   108   for ( 
const SubTask &subTask : constMSubTasks )
   110     subTask.task->cancel();
   119     processSubTasksForHold();
   122   const auto constMSubTasks = mSubTasks;
   123   for ( 
const SubTask &subTask : constMSubTasks )
   125     subTask.task->hold();
   138   const auto constMSubTasks = mSubTasks;
   139   for ( 
const SubTask &subTask : constMSubTasks )
   141     subTask.task->unhold();
   148   mSubTasks << SubTask( subTask, dependencies, subTaskDependency );
   155   return _qgis_listQPointerToRaw( mDependentLayers );
   161   mNotStartedMutex.acquire();
   171       timeout = std::numeric_limits< int >::max();
   172     if ( mNotFinishedMutex.tryLock( timeout ) )
   174       mNotFinishedMutex.unlock();
   187   mDependentLayers = _qgis_listRawToQPointer( dependentLayers );
   190 void QgsTask::subTaskStatusChanged( 
int status )
   203     processSubTasksForCompletion();
   208     processSubTasksForTermination();
   212     processSubTasksForHold();
   225   if ( !mSubTasks.isEmpty() )
   229     double totalProgress = 0.0;
   230     const auto constMSubTasks = mSubTasks;
   231     for ( 
const SubTask &subTask : constMSubTasks )
   235         totalProgress += 100.0;
   239         totalProgress += subTask.task->progress();
   242     progress = ( progress + totalProgress ) / ( mSubTasks.count() + 1 );
   246   double prevProgress = mTotalProgress;
   250   if ( static_cast< int >( prevProgress * 10 ) != 
static_cast< int >( mTotalProgress * 10 ) )
   254 void QgsTask::completed()
   257   processSubTasksForCompletion();
   260 void QgsTask::processSubTasksForCompletion()
   262   bool subTasksCompleted = 
true;
   263   const auto constMSubTasks = mSubTasks;
   264   for ( 
const SubTask &subTask : constMSubTasks )
   266     if ( subTask.task->status() != 
Complete )
   268       subTasksCompleted = 
false;
   273   if ( mStatus == 
Complete && subTasksCompleted )
   280     mNotFinishedMutex.tryLock(); 
   281     mNotFinishedMutex.unlock();
   290 void QgsTask::processSubTasksForTermination()
   292   bool subTasksTerminated = 
true;
   293   const auto constMSubTasks = mSubTasks;
   294   for ( 
const SubTask &subTask : constMSubTasks )
   298       subTasksTerminated = 
false;
   309     mNotFinishedMutex.tryLock(); 
   310     mNotFinishedMutex.unlock();
   312   else if ( mStatus == 
Terminated && !subTasksTerminated )
   319 void QgsTask::processSubTasksForHold()
   321   bool subTasksRunning = 
false;
   322   const auto constMSubTasks = mSubTasks;
   323   for ( 
const SubTask &subTask : constMSubTasks )
   325     if ( subTask.task->status() == 
Running )
   327       subTasksRunning = 
true;
   332   if ( mStatus == 
OnHold && !subTasksRunning && mOverallStatus != 
OnHold )
   337   else if ( mStatus == 
OnHold && subTasksRunning )
   344 void QgsTask::terminated()
   347   processSubTasksForTermination();
   360       setAutoDelete( 
true );
   385   , mTaskMutex( new QMutex( QMutex::Recursive ) )
   388            this, &QgsTaskManager::layersWillBeRemoved );
   398   QMap< long, TaskInfo > 
tasks = mTasks;
   400   mTaskMutex->unlock();
   401   QMap< long, TaskInfo >::const_iterator it = tasks.constBegin();
   402   for ( ; it != tasks.constEnd(); ++it )
   404     cleanupAndDeleteTask( it.value().task );
   412   return addTaskPrivate( task, 
QgsTaskList(), 
false, priority );
   417   return addTaskPrivate( definition.
task,
   429   long taskId = mNextTaskId++;
   432   mTasks.insert( taskId, TaskInfo( task, priority ) );
   439     mParentTasks << 
task;
   442     mLayerDependencies.insert( taskId, _qgis_listRawToQPointer( task->
dependentLayers() ) );
   443   mTaskMutex->unlock();
   452   for ( 
const QgsTask::SubTask &subTask : qgis::as_const( task->mSubTasks ) )
   454     switch ( subTask.dependency )
   465     addTaskPrivate( subTask.task, subTask.dependencies, 
true, priority );
   473   if ( hasCircularDependencies( taskId ) )
   489   QMutexLocker ml( mTaskMutex );
   491   if ( mTasks.contains( 
id ) )
   492     t = mTasks.value( 
id ).task;
   498   QMutexLocker ml( mTaskMutex );
   499   return mParentTasks.toList();
   504   QMutexLocker ml( mTaskMutex );
   505   return mParentTasks.count();
   513   QMutexLocker ml( mTaskMutex );
   514   QMap< long, TaskInfo >::const_iterator it = mTasks.constBegin();
   515   for ( ; it != mTasks.constEnd(); ++it )
   517     if ( it.value().task == 
task )
   528   QSet< QgsTask * > parents = mParentTasks;
   530   mTaskMutex->unlock();
   532   const auto constParents = parents;
   533   for ( 
QgsTask *task : constParents )
   542   QMap< long, QgsTaskList > 
dependencies = mTaskDependencies;
   543   dependencies.detach();
   544   mTaskMutex->unlock();
   546   if ( !dependencies.contains( taskId ) )
   549   const auto constValue = dependencies.value( taskId );
   550   for ( 
QgsTask *task : constValue )
   562   if ( resolveDependencies( taskId, taskId, results ) )
   568 bool QgsTaskManager::resolveDependencies( 
long firstTaskId, 
long currentTaskId, QSet<long> &results )
 const   571   QMap< long, QgsTaskList > 
dependencies = mTaskDependencies;
   572   dependencies.detach();
   573   mTaskMutex->unlock();
   575   if ( !dependencies.contains( currentTaskId ) )
   578   const auto constValue = dependencies.value( currentTaskId );
   579   for ( 
QgsTask *task : constValue )
   581     long dependentTaskId = 
taskId( task );
   582     if ( dependentTaskId >= 0 )
   584       if ( dependentTaskId == firstTaskId )
   589       results.insert( dependentTaskId );
   591       QSet< long > newTaskDeps;
   592       if ( !resolveDependencies( firstTaskId, dependentTaskId, newTaskDeps ) )
   595       if ( newTaskDeps.contains( firstTaskId ) )
   601       results.unite( newTaskDeps );
   608 bool QgsTaskManager::hasCircularDependencies( 
long taskId )
 const   611   return !resolveDependencies( taskId, taskId, d );
   616   QMutexLocker ml( mTaskMutex );
   622   QMutexLocker ml( mTaskMutex );
   623   QList< QgsTask * > 
tasks;
   624   QMap< long, QgsWeakMapLayerPointerList >::const_iterator layerIt = mLayerDependencies.constBegin();
   625   for ( ; layerIt != mLayerDependencies.constEnd(); ++layerIt )
   627     if ( _qgis_listQPointerToRaw( layerIt.value() ).contains( layer ) )
   639   QMutexLocker ml( mTaskMutex );
   641   activeTasks.intersect( mParentTasks );
   642   return activeTasks.toList();
   647   QMutexLocker ml( mTaskMutex );
   648   QSet< QgsTask * > 
tasks = mActiveTasks;
   649   return tasks.intersect( mParentTasks ).count();
   658 void QgsTaskManager::taskProgressChanged( 
double progress )
   675 void QgsTaskManager::taskStatusChanged( 
int status )
   685   QgsTaskRunnableWrapper *runnable = mTasks.value( 
id ).runnable;
   686   mTaskMutex->unlock();
   687   if ( runnable && QThreadPool::globalInstance()->tryTake( runnable ) )
   690     mTasks[ id ].runnable = 
nullptr;
   702     cancelDependentTasks( 
id );
   706   bool isParent = mParentTasks.contains( task );
   707   mTaskMutex->unlock();
   718     cleanupAndDeleteTask( task );
   723 void QgsTaskManager::layersWillBeRemoved( 
const QList< QgsMapLayer * > &layers )
   727   QMap< long, QgsWeakMapLayerPointerList > layerDependencies = mLayerDependencies;
   728   layerDependencies.detach();
   729   mTaskMutex->unlock();
   731   const auto constLayers = layers;
   735     for ( QMap< long, QgsWeakMapLayerPointerList >::const_iterator it = layerDependencies.constBegin();
   736           it != layerDependencies.constEnd(); ++it )
   738       if ( !( _qgis_listQPointerToRaw( it.value() ).contains( layer ) ) )
   755 bool QgsTaskManager::cleanupAndDeleteTask( 
QgsTask *task )
   764   QgsTaskRunnableWrapper *runnable = mTasks.value( 
id ).runnable;
   766   task->disconnect( 
this );
   769   if ( mTaskDependencies.contains( 
id ) )
   770     mTaskDependencies.remove( 
id );
   771   mTaskMutex->unlock();
   776   bool isParent = mParentTasks.contains( task );
   777   mParentTasks.remove( task );
   778   mSubTasks.remove( task );
   780   mLayerDependencies.remove( 
id );
   794     if ( runnable && QThreadPool::globalInstance()->tryTake( runnable ) )
   797       mTasks[ id ].runnable = 
nullptr;
   808   for ( QMap< long, QgsTaskList >::iterator it = mTaskDependencies.begin(); it != mTaskDependencies.end(); ++it )
   810     if ( it.value().contains( task ) )
   812       it.value().removeAll( task );
   815   mTaskMutex->unlock();
   820 void QgsTaskManager::processQueue()
   824   mActiveTasks.clear();
   825   for ( QMap< long, TaskInfo >::iterator it = mTasks.begin(); it != mTasks.end(); ++it )
   827     QgsTask *task = it.value().task;
   830       it.value().createRunnable();
   831       QThreadPool::globalInstance()->start( it.value().runnable, it.value().priority );
   836       mActiveTasks << 
task;
   840   bool allFinished = mActiveTasks.isEmpty();
   841   mTaskMutex->unlock();
   849   if ( prevActiveCount != newActiveCount )
   855 void QgsTaskManager::cancelDependentTasks( 
long taskId )
   861   QMap< long, QgsTaskList > taskDependencies = mTaskDependencies;
   862   taskDependencies.detach();
   863   mTaskMutex->unlock();
   865   QMap< long, QgsTaskList >::const_iterator it = taskDependencies.constBegin();
   866   for ( ; it != taskDependencies.constEnd(); ++it )
   868     if ( it.value().contains( canceledTask ) )
   881 QgsTaskManager::TaskInfo::TaskInfo( 
QgsTask *task, 
int priority )
   884   , priority( priority )
   887 void QgsTaskManager::TaskInfo::createRunnable()
   889   Q_ASSERT( !runnable );
   890   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 setDescription(const QString &description)
Sets the task's description. 
 
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. 
 
qint64 elapsedTime() const
Returns the elapsed time since the task commenced, in milliseconds. 
 
QgsTaskManager(QObject *parent=nullptr)
Constructor for QgsTaskManager. 
 
void setDependentLayers(const QList< QgsMapLayer *> &dependentLayers)
Sets a list of layers on which the task depends. 
 
bool waitForFinished(int timeout=30000)
Blocks the current thread until the task finishes or a maximum of timeout milliseconds. 
 
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. 
 
QString description() const
Returns the task's description. 
 
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. 
 
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc. 
 
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. 
 
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.