QGIS API Documentation  3.4.3-Madeira (2f64a3c)
qgstaskmanager.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstaskmanager.cpp
3  ------------------
4  begin : April 2016
5  copyright : (C) 2016 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgstaskmanager.h"
19 #include "qgsproject.h"
20 #include "qgsmaplayerlistutils.h"
21 #include <QtConcurrentRun>
22 
23 
24 //
25 // QgsTask
26 //
27 
28 QgsTask::QgsTask( const QString &name, Flags flags )
29  : mFlags( flags )
30  , mDescription( name )
31 {
32 }
33 
35 {
36  Q_ASSERT_X( mStatus != Running, "delete", QStringLiteral( "status was %1" ).arg( mStatus ).toLatin1() );
37  mNotFinishedMutex.tryLock(); // we're not guaranteed to already have the lock in place here
38  Q_FOREACH ( const SubTask &subTask, mSubTasks )
39  {
40  delete subTask.task;
41  }
42  mNotFinishedMutex.unlock();
43 }
44 
45 qint64 QgsTask::elapsedTime() const
46 {
47  return mElapsedTime.elapsed();
48 }
49 
50 void QgsTask::start()
51 {
52  mNotFinishedMutex.lock();
53  mStartCount++;
54  Q_ASSERT( mStartCount == 1 );
55 
56  if ( mStatus != Queued )
57  return;
58 
59  mStatus = Running;
60  mOverallStatus = Running;
61  mElapsedTime.start();
62 
63  emit statusChanged( Running );
64  emit begun();
65 
66  // force initial emission of progressChanged, but respect if task has had initial progress manually set
67  setProgress( mProgress );
68 
69  if ( run() )
70  {
71  completed();
72  }
73  else
74  {
75  terminated();
76  }
77 }
78 
80 {
81  if ( mOverallStatus == Complete || mOverallStatus == Terminated )
82  return;
83 
84  mShouldTerminate = true;
85 
86 #if QT_VERSION >= 0x050500
87  //can't cancel queued tasks with qt < 5.5
88  if ( mStatus == Queued || mStatus == OnHold )
89  {
90  // immediately terminate unstarted jobs
91  terminated();
92  }
93 #endif
94 
95  if ( mStatus == Terminated )
96  {
97  processSubTasksForTermination();
98  }
99 
100  Q_FOREACH ( const SubTask &subTask, mSubTasks )
101  {
102  subTask.task->cancel();
103  }
104 }
105 
107 {
108  if ( mStatus == Queued )
109  {
110  mStatus = OnHold;
111  processSubTasksForHold();
112  }
113 
114  Q_FOREACH ( const SubTask &subTask, mSubTasks )
115  {
116  subTask.task->hold();
117  }
118 }
119 
121 {
122  if ( mStatus == OnHold )
123  {
124  mStatus = Queued;
125  mOverallStatus = Queued;
126  emit statusChanged( Queued );
127  }
128 
129  Q_FOREACH ( const SubTask &subTask, mSubTasks )
130  {
131  subTask.task->unhold();
132  }
133 }
134 
135 void QgsTask::addSubTask( QgsTask *subTask, const QgsTaskList &dependencies,
136  SubTaskDependency subTaskDependency )
137 {
138  mSubTasks << SubTask( subTask, dependencies, subTaskDependency );
139  connect( subTask, &QgsTask::progressChanged, this, [ = ] { setProgress( mProgress ); } );
140  connect( subTask, &QgsTask::statusChanged, this, &QgsTask::subTaskStatusChanged );
141 }
142 
143 QList<QgsMapLayer *> QgsTask::dependentLayers() const
144 {
145  return _qgis_listQPointerToRaw( mDependentLayers );
146 }
147 
148 bool QgsTask::waitForFinished( int timeout )
149 {
150  bool rv = true;
151  if ( mOverallStatus == Complete || mOverallStatus == Terminated )
152  {
153  rv = true;
154  }
155  else
156  {
157  if ( timeout == 0 )
158  timeout = std::numeric_limits< int >::max();
159  if ( mNotFinishedMutex.tryLock( timeout ) )
160  {
161  mNotFinishedMutex.unlock();
162  rv = true;
163  }
164  else
165  {
166  rv = false;
167  }
168  }
169  return rv;
170 }
171 
172 void QgsTask::setDependentLayers( const QList< QgsMapLayer * > &dependentLayers )
173 {
174  mDependentLayers = _qgis_listRawToQPointer( dependentLayers );
175 }
176 
177 void QgsTask::subTaskStatusChanged( int status )
178 {
179  QgsTask *subTask = qobject_cast< QgsTask * >( sender() );
180  if ( !subTask )
181  return;
182 
183  if ( status == Running && mStatus == Queued )
184  {
185  mOverallStatus = Running;
186  }
187  else if ( status == Complete && mStatus == Complete )
188  {
189  //check again if all subtasks are complete
190  processSubTasksForCompletion();
191  }
192  else if ( ( status == Complete || status == Terminated ) && mStatus == Terminated )
193  {
194  //check again if all subtasks are terminated
195  processSubTasksForTermination();
196  }
197  else if ( ( status == Complete || status == Terminated || status == OnHold ) && mStatus == OnHold )
198  {
199  processSubTasksForHold();
200  }
201  else if ( status == Terminated )
202  {
203  //uh oh...
204  cancel();
205  }
206 }
207 
209 {
210  mProgress = progress;
211 
212  if ( !mSubTasks.isEmpty() )
213  {
214  // calculate total progress including subtasks
215 
216  double totalProgress = 0.0;
217  Q_FOREACH ( const SubTask &subTask, mSubTasks )
218  {
219  if ( subTask.task->status() == QgsTask::Complete )
220  {
221  totalProgress += 100.0;
222  }
223  else
224  {
225  totalProgress += subTask.task->progress();
226  }
227  }
228  progress = ( progress + totalProgress ) / ( mSubTasks.count() + 1 );
229  }
230 
231  // avoid flooding with too many events
232  double prevProgress = mTotalProgress;
233  mTotalProgress = progress;
234 
235  // avoid spamming with too many progressChanged reports
236  if ( static_cast< int >( prevProgress * 10 ) != static_cast< int >( mTotalProgress * 10 ) )
237  emit progressChanged( progress );
238 }
239 
240 void QgsTask::completed()
241 {
242  mStatus = Complete;
243  processSubTasksForCompletion();
244 }
245 
246 void QgsTask::processSubTasksForCompletion()
247 {
248  bool subTasksCompleted = true;
249  Q_FOREACH ( const SubTask &subTask, mSubTasks )
250  {
251  if ( subTask.task->status() != Complete )
252  {
253  subTasksCompleted = false;
254  break;
255  }
256  }
257 
258  if ( mStatus == Complete && subTasksCompleted )
259  {
260  mOverallStatus = Complete;
261 
262  setProgress( 100.0 );
263  emit statusChanged( Complete );
264  emit taskCompleted();
265  mNotFinishedMutex.tryLock(); // we're not guaranteed to already have the lock in place here
266  mNotFinishedMutex.unlock();
267  }
268  else if ( mStatus == Complete )
269  {
270  // defer completion until all subtasks are complete
271  mOverallStatus = Running;
272  }
273 }
274 
275 void QgsTask::processSubTasksForTermination()
276 {
277  bool subTasksTerminated = true;
278  Q_FOREACH ( const SubTask &subTask, mSubTasks )
279  {
280  if ( subTask.task->status() != Terminated && subTask.task->status() != Complete )
281  {
282  subTasksTerminated = false;
283  break;
284  }
285  }
286 
287  if ( mStatus == Terminated && subTasksTerminated && mOverallStatus != Terminated )
288  {
289  mOverallStatus = Terminated;
290 
291  emit statusChanged( Terminated );
292  emit taskTerminated();
293  mNotFinishedMutex.tryLock(); // we're not guaranteed to already have the lock in place here
294  mNotFinishedMutex.unlock();
295  }
296  else if ( mStatus == Terminated && !subTasksTerminated )
297  {
298  // defer termination until all subtasks are terminated (or complete)
299  mOverallStatus = Running;
300  }
301 }
302 
303 void QgsTask::processSubTasksForHold()
304 {
305  bool subTasksRunning = false;
306  Q_FOREACH ( const SubTask &subTask, mSubTasks )
307  {
308  if ( subTask.task->status() == Running )
309  {
310  subTasksRunning = true;
311  break;
312  }
313  }
314 
315  if ( mStatus == OnHold && !subTasksRunning && mOverallStatus != OnHold )
316  {
317  mOverallStatus = OnHold;
318  emit statusChanged( OnHold );
319  }
320  else if ( mStatus == OnHold && subTasksRunning )
321  {
322  // defer hold until all subtasks finish running
323  mOverallStatus = Running;
324  }
325 }
326 
327 void QgsTask::terminated()
328 {
329  mStatus = Terminated;
330  processSubTasksForTermination();
331 }
332 
333 
335 
336 class QgsTaskRunnableWrapper : public QRunnable
337 {
338  public:
339 
340  explicit QgsTaskRunnableWrapper( QgsTask *task )
341  : mTask( task )
342  {
343  setAutoDelete( true );
344  }
345 
346  void run() override
347  {
348  Q_ASSERT( mTask );
349  mTask->start();
350  }
351 
352  private:
353 
354  QgsTask *mTask = nullptr;
355 
356 };
357 
359 
360 
361 
362 //
363 // QgsTaskManager
364 //
365 
367  : QObject( parent )
368  , mTaskMutex( new QMutex( QMutex::Recursive ) )
369 {
370  connect( QgsProject::instance(), static_cast < void ( QgsProject::* )( const QList< QgsMapLayer * >& ) > ( &QgsProject::layersWillBeRemoved ),
371  this, &QgsTaskManager::layersWillBeRemoved );
372 }
373 
375 {
376  //first tell all tasks to cancel
377  cancelAll();
378 
379  //then clean them up, including waiting for them to terminate
380  mTaskMutex->lock();
381  QMap< long, TaskInfo > tasks = mTasks;
382  mTasks.detach();
383  mTaskMutex->unlock();
384  QMap< long, TaskInfo >::const_iterator it = tasks.constBegin();
385  for ( ; it != tasks.constEnd(); ++it )
386  {
387  cleanupAndDeleteTask( it.value().task );
388  }
389 
390  delete mTaskMutex;
391 }
392 
393 long QgsTaskManager::addTask( QgsTask *task, int priority )
394 {
395  return addTaskPrivate( task, QgsTaskList(), false, priority );
396 }
397 
398 long QgsTaskManager::addTask( const QgsTaskManager::TaskDefinition &definition, int priority )
399 {
400  return addTaskPrivate( definition.task,
401  definition.dependentTasks,
402  false,
403  priority );
404 }
405 
406 
407 long QgsTaskManager::addTaskPrivate( QgsTask *task, QgsTaskList dependencies, bool isSubTask, int priority )
408 {
409  if ( !task )
410  return 0;
411 
412  long taskId = mNextTaskId++;
413 
414  mTaskMutex->lock();
415  mTasks.insert( taskId, TaskInfo( task, priority ) );
416  if ( isSubTask )
417  {
418  mSubTasks << task;
419  }
420  else
421  {
422  mParentTasks << task;
423  }
424  if ( !task->dependentLayers().isEmpty() )
425  mLayerDependencies.insert( taskId, _qgis_listRawToQPointer( task->dependentLayers() ) );
426  mTaskMutex->unlock();
427 
428  connect( task, &QgsTask::statusChanged, this, &QgsTaskManager::taskStatusChanged );
429  if ( !isSubTask )
430  {
431  connect( task, &QgsTask::progressChanged, this, &QgsTaskManager::taskProgressChanged );
432  }
433 
434  // add all subtasks, must be done before dependency resolution
435  Q_FOREACH ( const QgsTask::SubTask &subTask, task->mSubTasks )
436  {
437  switch ( subTask.dependency )
438  {
440  dependencies << subTask.task;
441  break;
442 
444  //nothing
445  break;
446  }
447  //recursively add sub tasks
448  addTaskPrivate( subTask.task, subTask.dependencies, true, priority );
449  }
450 
451  if ( !dependencies.isEmpty() )
452  {
453  mTaskDependencies.insert( taskId, dependencies );
454  }
455 
456  if ( hasCircularDependencies( taskId ) )
457  {
458  task->cancel();
459  }
460 
461  if ( !isSubTask )
462  {
463  emit taskAdded( taskId );
464  processQueue();
465  }
466 
467  return taskId;
468 }
469 
470 QgsTask *QgsTaskManager::task( long id ) const
471 {
472  QMutexLocker ml( mTaskMutex );
473  QgsTask *t = nullptr;
474  if ( mTasks.contains( id ) )
475  t = mTasks.value( id ).task;
476  return t;
477 }
478 
479 QList<QgsTask *> QgsTaskManager::tasks() const
480 {
481  QMutexLocker ml( mTaskMutex );
482  return mParentTasks.toList();
483 }
484 
486 {
487  QMutexLocker ml( mTaskMutex );
488  return mParentTasks.count();
489 }
490 
491 long QgsTaskManager::taskId( QgsTask *task ) const
492 {
493  if ( !task )
494  return -1;
495 
496  QMutexLocker ml( mTaskMutex );
497  QMap< long, TaskInfo >::const_iterator it = mTasks.constBegin();
498  for ( ; it != mTasks.constEnd(); ++it )
499  {
500  if ( it.value().task == task )
501  {
502  return it.key();
503  }
504  }
505  return -1;
506 }
507 
509 {
510  mTaskMutex->lock();
511  QSet< QgsTask * > parents = mParentTasks;
512  parents.detach();
513  mTaskMutex->unlock();
514 
515  Q_FOREACH ( QgsTask *task, parents )
516  {
517  task->cancel();
518  }
519 }
520 
522 {
523  mTaskMutex->lock();
524  QMap< long, QgsTaskList > dependencies = mTaskDependencies;
525  dependencies.detach();
526  mTaskMutex->unlock();
527 
528  if ( !dependencies.contains( taskId ) )
529  return true;
530 
531  Q_FOREACH ( QgsTask *task, dependencies.value( taskId ) )
532  {
533  if ( task->status() != QgsTask::Complete )
534  return false;
535  }
536 
537  return true;
538 }
539 
540 QSet<long> QgsTaskManager::dependencies( long taskId ) const
541 {
542  QSet<long> results;
543  if ( resolveDependencies( taskId, taskId, results ) )
544  return results;
545  else
546  return QSet<long>();
547 }
548 
549 bool QgsTaskManager::resolveDependencies( long firstTaskId, long currentTaskId, QSet<long> &results ) const
550 {
551  mTaskMutex->lock();
552  QMap< long, QgsTaskList > dependencies = mTaskDependencies;
553  dependencies.detach();
554  mTaskMutex->unlock();
555 
556  if ( !dependencies.contains( currentTaskId ) )
557  return true;
558 
559  Q_FOREACH ( QgsTask *task, dependencies.value( currentTaskId ) )
560  {
561  long dependentTaskId = taskId( task );
562  if ( dependentTaskId >= 0 )
563  {
564  if ( dependentTaskId == firstTaskId )
565  // circular
566  return false;
567 
568  //add task as dependent
569  results.insert( dependentTaskId );
570  //plus all its other dependencies
571  QSet< long > newTaskDeps;
572  if ( !resolveDependencies( firstTaskId, dependentTaskId, newTaskDeps ) )
573  return false;
574 
575  if ( newTaskDeps.contains( firstTaskId ) )
576  {
577  // circular
578  return false;
579  }
580 
581  results.unite( newTaskDeps );
582  }
583  }
584 
585  return true;
586 }
587 
588 bool QgsTaskManager::hasCircularDependencies( long taskId ) const
589 {
590  QSet< long > d;
591  return !resolveDependencies( taskId, taskId, d );
592 }
593 
594 QList<QgsMapLayer *> QgsTaskManager::dependentLayers( long taskId ) const
595 {
596  QMutexLocker ml( mTaskMutex );
597  return _qgis_listQPointerToRaw( mLayerDependencies.value( taskId, QgsWeakMapLayerPointerList() ) );
598 }
599 
600 QList<QgsTask *> QgsTaskManager::tasksDependentOnLayer( QgsMapLayer *layer ) const
601 {
602  QMutexLocker ml( mTaskMutex );
603  QList< QgsTask * > tasks;
604  QMap< long, QgsWeakMapLayerPointerList >::const_iterator layerIt = mLayerDependencies.constBegin();
605  for ( ; layerIt != mLayerDependencies.constEnd(); ++layerIt )
606  {
607  if ( _qgis_listQPointerToRaw( layerIt.value() ).contains( layer ) )
608  {
609  QgsTask *layerTask = task( layerIt.key() );
610  if ( layerTask )
611  tasks << layerTask;
612  }
613  }
614  return tasks;
615 }
616 
617 QList<QgsTask *> QgsTaskManager::activeTasks() const
618 {
619  QMutexLocker ml( mTaskMutex );
620  QSet< QgsTask * > activeTasks = mActiveTasks;
621  activeTasks.intersect( mParentTasks );
622  return activeTasks.toList();
623 }
624 
626 {
627  QMutexLocker ml( mTaskMutex );
628  QSet< QgsTask * > tasks = mActiveTasks;
629  return tasks.intersect( mParentTasks ).count();
630 }
631 
633 {
634  if ( task )
635  emit taskTriggered( task );
636 }
637 
638 void QgsTaskManager::taskProgressChanged( double progress )
639 {
640  QgsTask *task = qobject_cast< QgsTask * >( sender() );
641 
642  //find ID of task
643  long id = taskId( task );
644  if ( id < 0 )
645  return;
646 
647  emit progressChanged( id, progress );
648 
649  if ( countActiveTasks() == 1 )
650  {
651  emit finalTaskProgressChanged( progress );
652  }
653 }
654 
655 void QgsTaskManager::taskStatusChanged( int status )
656 {
657  QgsTask *task = qobject_cast< QgsTask * >( sender() );
658 
659  //find ID of task
660  long id = taskId( task );
661  if ( id < 0 )
662  return;
663 
664 
665 #if QT_VERSION >= 0x050500
666  mTaskMutex->lock();
667  QgsTaskRunnableWrapper *runnable = mTasks.value( id ).runnable;
668  mTaskMutex->unlock();
669  if ( runnable )
670  QThreadPool::globalInstance()->cancel( runnable );
671 #endif
672 
673  if ( status == QgsTask::Terminated || status == QgsTask::Complete )
674  {
675  bool result = status == QgsTask::Complete;
676  task->finished( result );
677  }
678 
679  if ( status == QgsTask::Terminated )
680  {
681  //recursively cancel dependent tasks
682  cancelDependentTasks( id );
683  }
684 
685  mTaskMutex->lock();
686  bool isParent = mParentTasks.contains( task );
687  mTaskMutex->unlock();
688  if ( isParent )
689  {
690  // don't emit status changed for subtasks
691  emit statusChanged( id, status );
692  }
693 
694  processQueue();
695 
696  if ( status == QgsTask::Terminated || status == QgsTask::Complete )
697  {
698  cleanupAndDeleteTask( task );
699  }
700 
701 }
702 
703 void QgsTaskManager::layersWillBeRemoved( const QList< QgsMapLayer * > &layers )
704 {
705  mTaskMutex->lock();
706  // scan through layers to be removed
707  QMap< long, QgsWeakMapLayerPointerList > layerDependencies = mLayerDependencies;
708  layerDependencies.detach();
709  mTaskMutex->unlock();
710 
711  Q_FOREACH ( QgsMapLayer *layer, layers )
712  {
713  // scan through tasks with layer dependencies
714  for ( QMap< long, QgsWeakMapLayerPointerList >::const_iterator it = layerDependencies.constBegin();
715  it != layerDependencies.constEnd(); ++it )
716  {
717  if ( !( _qgis_listQPointerToRaw( it.value() ).contains( layer ) ) )
718  {
719  //task not dependent on this layer
720  continue;
721  }
722 
723  QgsTask *dependentTask = task( it.key() );
724  if ( dependentTask && ( dependentTask->status() != QgsTask::Complete && dependentTask->status() != QgsTask::Terminated ) )
725  {
726  // incomplete task is dependent on this layer!
727  dependentTask->cancel();
728  }
729  }
730  }
731 }
732 
733 
734 bool QgsTaskManager::cleanupAndDeleteTask( QgsTask *task )
735 {
736  if ( !task )
737  return false;
738 
739  long id = taskId( task );
740  if ( id < 0 )
741  return false;
742 
743  QgsTaskRunnableWrapper *runnable = mTasks.value( id ).runnable;
744 
745  task->disconnect( this );
746 
747  mTaskMutex->lock();
748  if ( mTaskDependencies.contains( id ) )
749  mTaskDependencies.remove( id );
750  mTaskMutex->unlock();
751 
752  emit taskAboutToBeDeleted( id );
753 
754  mTaskMutex->lock();
755  bool isParent = mParentTasks.contains( task );
756  mParentTasks.remove( task );
757  mSubTasks.remove( task );
758  mTasks.remove( id );
759  mLayerDependencies.remove( id );
760 
761  if ( task->status() != QgsTask::Complete && task->status() != QgsTask::Terminated )
762  {
763  if ( isParent )
764  {
765  // delete task when it's terminated
766  connect( task, &QgsTask::taskCompleted, task, &QgsTask::deleteLater );
767  connect( task, &QgsTask::taskTerminated, task, &QgsTask::deleteLater );
768  }
769  task->cancel();
770  }
771  else
772  {
773 #if QT_VERSION >= 0x050500
774  if ( runnable )
775  QThreadPool::globalInstance()->cancel( runnable );
776 #endif
777  if ( isParent )
778  {
779  //task already finished, kill it
780  task->deleteLater();
781  }
782  }
783 
784  // at this stage (hopefully) dependent tasks have been canceled or queued
785  for ( QMap< long, QgsTaskList >::iterator it = mTaskDependencies.begin(); it != mTaskDependencies.end(); ++it )
786  {
787  if ( it.value().contains( task ) )
788  {
789  it.value().removeAll( task );
790  }
791  }
792  mTaskMutex->unlock();
793 
794  return true;
795 }
796 
797 void QgsTaskManager::processQueue()
798 {
799  int prevActiveCount = countActiveTasks();
800  mTaskMutex->lock();
801  mActiveTasks.clear();
802  for ( QMap< long, TaskInfo >::iterator it = mTasks.begin(); it != mTasks.end(); ++it )
803  {
804  QgsTask *task = it.value().task;
805  if ( task && task->mStatus == QgsTask::Queued && dependenciesSatisfied( it.key() ) && it.value().added.testAndSetRelaxed( 0, 1 ) )
806  {
807  it.value().createRunnable();
808  QThreadPool::globalInstance()->start( it.value().runnable, it.value().priority );
809  }
810 
811  if ( task && ( task->mStatus != QgsTask::Complete && task->mStatus != QgsTask::Terminated ) )
812  {
813  mActiveTasks << task;
814  }
815  }
816 
817  bool allFinished = mActiveTasks.isEmpty();
818  mTaskMutex->unlock();
819 
820  if ( allFinished )
821  {
822  emit allTasksFinished();
823  }
824 
825  int newActiveCount = countActiveTasks();
826  if ( prevActiveCount != newActiveCount )
827  {
828  emit countActiveTasksChanged( newActiveCount );
829  }
830 }
831 
832 void QgsTaskManager::cancelDependentTasks( long taskId )
833 {
834  QgsTask *canceledTask = task( taskId );
835 
836  //deep copy
837  mTaskMutex->lock();
838  QMap< long, QgsTaskList > taskDependencies = mTaskDependencies;
839  taskDependencies.detach();
840  mTaskMutex->unlock();
841 
842  QMap< long, QgsTaskList >::const_iterator it = taskDependencies.constBegin();
843  for ( ; it != taskDependencies.constEnd(); ++it )
844  {
845  if ( it.value().contains( canceledTask ) )
846  {
847  // found task with this dependency
848 
849  // cancel it - note that this will be recursive, so any tasks dependent
850  // on this one will also be canceled
851  QgsTask *dependentTask = task( it.key() );
852  if ( dependentTask )
853  dependentTask->cancel();
854  }
855  }
856 }
857 
858 QgsTaskManager::TaskInfo::TaskInfo( QgsTask *task, int priority )
859  : task( task )
860  , added( 0 )
861  , priority( priority )
862 {}
863 
864 void QgsTaskManager::TaskInfo::createRunnable()
865 {
866  Q_ASSERT( !runnable );
867  runnable = new QgsTaskRunnableWrapper( task ); // auto deleted
868 }
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&#39;s current progress.
Base class for all map layer types.
Definition: qgsmaplayer.h:63
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.
QgsTask * task(long id) const
Returns the task with matching ID.
~QgsTask() override
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.
Definition: qgsproject.h:89
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&#39;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.
Definition: qgsmaplayer.h:1489
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:411
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&#39;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.