QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgstaskmanagerwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstaskmanagerwidget.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 "qgstaskmanagerwidget.h"
19 #include "qgstaskmanager.h"
20 #include "qgsapplication.h"
21 #include <QPainter>
22 #include <QMouseEvent>
23 #include <QTreeView>
24 #include <QLayout>
25 #include <QToolBar>
26 #include <QProgressBar>
27 #include <QAction>
28 #include <QHeaderView>
29 
30 //
31 // QgsTaskManagerWidget
32 //
33 
35  : QWidget( parent )
36  , mManager( manager )
37 {
38  Q_ASSERT( manager );
39 
40  QVBoxLayout *vLayout = new QVBoxLayout();
41  vLayout->setContentsMargins( 0, 0, 0, 0 );
42  mTreeView = new QTreeView();
43  mModel = new QgsTaskManagerModel( manager, this );
44  mTreeView->setModel( mModel );
45  connect( mModel, &QgsTaskManagerModel::rowsInserted, this, &QgsTaskManagerWidget::modelRowsInserted );
46  mTreeView->setHeaderHidden( true );
47  mTreeView->setRootIsDecorated( false );
48  mTreeView->setSelectionBehavior( QAbstractItemView::SelectRows );
49 
50 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
51  int progressColWidth = static_cast< int >( fontMetrics().width( 'X' ) * 10 * Qgis::UI_SCALE_FACTOR );
52 #else
53  int progressColWidth = static_cast< int >( fontMetrics().horizontalAdvance( 'X' ) * 10 * Qgis::UI_SCALE_FACTOR );
54 #endif
55  mTreeView->setColumnWidth( QgsTaskManagerModel::Progress, progressColWidth );
56 
57 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
58  int statusColWidth = static_cast< int >( fontMetrics().width( 'X' ) * 2 * Qgis::UI_SCALE_FACTOR );
59 #else
60  int statusColWidth = static_cast< int >( fontMetrics().horizontalAdvance( 'X' ) * 2 * Qgis::UI_SCALE_FACTOR );
61 #endif
62  mTreeView->setColumnWidth( QgsTaskManagerModel::Status, statusColWidth );
63  mTreeView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
64  mTreeView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
65  mTreeView->header()->setStretchLastSection( false );
66  mTreeView->header()->setSectionResizeMode( QgsTaskManagerModel::Description, QHeaderView::Stretch );
67 
68  connect( mTreeView, &QTreeView::clicked, this, &QgsTaskManagerWidget::clicked );
69 
70  vLayout->addWidget( mTreeView );
71 
72  setLayout( vLayout );
73 }
74 
76 {
77  delete mModel;
78 }
79 
80 
81 void QgsTaskManagerWidget::modelRowsInserted( const QModelIndex &, int start, int end )
82 {
83  for ( int row = start; row <= end; ++row )
84  {
85  QgsTask *task = mModel->indexToTask( mModel->index( row, 1 ) );
86  if ( !task )
87  continue;
88 
89  QProgressBar *progressBar = new QProgressBar();
90  progressBar->setAutoFillBackground( true );
91  progressBar->setRange( 0, 0 );
92  connect( task, &QgsTask::progressChanged, progressBar, [progressBar]( double progress )
93  {
94  //until first progress report, we show a progress bar of interderminant length
95  if ( progress > 0 )
96  {
97  progressBar->setMaximum( 100 );
98  progressBar->setValue( static_cast< int >( std::round( progress ) ) );
99  }
100  else
101  progressBar->setMaximum( 0 );
102  }
103  );
104  mTreeView->setIndexWidget( mModel->index( row, QgsTaskManagerModel::Progress ), progressBar );
105 
106  QgsTaskStatusWidget *statusWidget = new QgsTaskStatusWidget( nullptr, task->status(), task->canCancel() );
107  statusWidget->setAutoFillBackground( true );
108  connect( task, &QgsTask::statusChanged, statusWidget, &QgsTaskStatusWidget::setStatus );
109  connect( statusWidget, &QgsTaskStatusWidget::cancelClicked, task, &QgsTask::cancel );
110  mTreeView->setIndexWidget( mModel->index( row, QgsTaskManagerModel::Status ), statusWidget );
111  }
112 }
113 
114 void QgsTaskManagerWidget::clicked( const QModelIndex &index )
115 {
116  QgsTask *task = mModel->indexToTask( index );
117  if ( !task )
118  return;
119 
120  mManager->triggerTask( task );
121 }
122 
124 //
125 // QgsTaskManagerModel
126 //
127 
128 QgsTaskManagerModel::QgsTaskManagerModel( QgsTaskManager *manager, QObject *parent )
129  : QAbstractItemModel( parent )
130  , mManager( manager )
131 {
132  Q_ASSERT( mManager );
133 
134  //populate row to id map
135  const auto constTasks = mManager->tasks();
136  for ( QgsTask *task : constTasks )
137  {
138  mRowToTaskIdList << mManager->taskId( task );
139  }
140 
141  connect( mManager, &QgsTaskManager::taskAdded, this, &QgsTaskManagerModel::taskAdded );
142  connect( mManager, &QgsTaskManager::progressChanged, this, &QgsTaskManagerModel::progressChanged );
143  connect( mManager, &QgsTaskManager::statusChanged, this, &QgsTaskManagerModel::statusChanged );
144 }
145 
146 QModelIndex QgsTaskManagerModel::index( int row, int column, const QModelIndex &parent ) const
147 {
148  if ( column < 0 || column >= columnCount() )
149  {
150  //column out of bounds
151  return QModelIndex();
152  }
153 
154  if ( !parent.isValid() && row >= 0 && row < mRowToTaskIdList.count() )
155  {
156  //return an index for the task at this position
157  return createIndex( row, column );
158  }
159 
160  //only top level supported
161  return QModelIndex();
162 
163 }
164 
165 QModelIndex QgsTaskManagerModel::parent( const QModelIndex &index ) const
166 {
167  Q_UNUSED( index )
168 
169  //all items are top level
170  return QModelIndex();
171 }
172 
173 int QgsTaskManagerModel::rowCount( const QModelIndex &parent ) const
174 {
175  if ( !parent.isValid() )
176  {
177  return mRowToTaskIdList.count();
178  }
179  else
180  {
181  //no children
182  return 0;
183  }
184 }
185 
186 int QgsTaskManagerModel::columnCount( const QModelIndex &parent ) const
187 {
188  Q_UNUSED( parent )
189  return 3;
190 }
191 
192 QVariant QgsTaskManagerModel::data( const QModelIndex &index, int role ) const
193 {
194  if ( !index.isValid() )
195  return QVariant();
196 
197  QgsTask *task = indexToTask( index );
198  if ( task )
199  {
200  switch ( role )
201  {
202  case Qt::DisplayRole:
203  case Qt::EditRole:
204  switch ( index.column() )
205  {
206  case Description:
207  return task->description();
208  case Progress:
209  return task->progress();
210  case Status:
211  // delegate shows status
212  return QVariant();
213  default:
214  return QVariant();
215  }
216 
217  case StatusRole:
218  return static_cast<int>( task->status() );
219 
220  case Qt::ToolTipRole:
221  switch ( index.column() )
222  {
223  case Description:
224  return createTooltip( task, ToolTipDescription );
225  case Progress:
226  return createTooltip( task, ToolTipProgress );
227  case Status:
228  return createTooltip( task, ToolTipStatus );
229  default:
230  return QVariant();
231  }
232 
233 
234  default:
235  return QVariant();
236  }
237  }
238 
239  return QVariant();
240 }
241 
242 Qt::ItemFlags QgsTaskManagerModel::flags( const QModelIndex &index ) const
243 {
244  Qt::ItemFlags flags = QAbstractItemModel::flags( index );
245 
246  if ( ! index.isValid() )
247  {
248  return flags;
249  }
250 
251  QgsTask *task = indexToTask( index );
252  if ( index.column() == Status )
253  {
254  if ( task && task->canCancel() )
255  flags = flags | Qt::ItemIsEditable;
256  }
257  return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
258 }
259 
260 bool QgsTaskManagerModel::setData( const QModelIndex &index, const QVariant &value, int role )
261 {
262  Q_UNUSED( role )
263 
264  if ( !index.isValid() )
265  return false;
266 
267  QgsTask *task = indexToTask( index );
268  if ( !task )
269  return false;
270 
271  switch ( index.column() )
272  {
273  case Status:
274  {
275  if ( value.toBool() && task->canCancel() )
276  task->cancel();
277  return true;
278  }
279 
280  default:
281  return false;
282  }
283 }
284 
285 void QgsTaskManagerModel::taskAdded( long id )
286 {
287  beginInsertRows( QModelIndex(), mRowToTaskIdList.count(),
288  mRowToTaskIdList.count() );
289  mRowToTaskIdList << id;
290  endInsertRows();
291 }
292 
293 void QgsTaskManagerModel::taskDeleted( long id )
294 {
295  for ( int row = 0; row < mRowToTaskIdList.count(); ++row )
296  {
297  if ( mRowToTaskIdList.at( row ) == id )
298  {
299  beginRemoveRows( QModelIndex(), row, row );
300  mRowToTaskIdList.removeAt( row );
301  endRemoveRows();
302  return;
303  }
304  }
305 }
306 
307 void QgsTaskManagerModel::progressChanged( long id, double progress )
308 {
309  Q_UNUSED( progress )
310 
311  QModelIndex index = idToIndex( id, Progress );
312  if ( !index.isValid() )
313  {
314  return;
315  }
316 
317  emit dataChanged( index, index );
318 }
319 
320 void QgsTaskManagerModel::statusChanged( long id, int status )
321 {
322  if ( status == QgsTask::Complete || status == QgsTask::Terminated )
323  {
324  taskDeleted( id );
325  }
326  else
327  {
328  QModelIndex index = idToIndex( id, Status );
329  if ( !index.isValid() )
330  {
331  return;
332  }
333 
334  emit dataChanged( index, index );
335  }
336 }
337 
338 QgsTask *QgsTaskManagerModel::indexToTask( const QModelIndex &index ) const
339 {
340  if ( !index.isValid() || index.parent().isValid() )
341  return nullptr;
342 
343  long id = index.row() >= 0 && index.row() < mRowToTaskIdList.count() ? mRowToTaskIdList.at( index.row() ) : -1;
344  if ( id >= 0 )
345  return mManager->task( id );
346  else
347  return nullptr;
348 }
349 
350 int QgsTaskManagerModel::idToRow( long id ) const
351 {
352  for ( int row = 0; row < mRowToTaskIdList.count(); ++row )
353  {
354  if ( mRowToTaskIdList.at( row ) == id )
355  {
356  return row;
357  }
358  }
359  return -1;
360 }
361 
362 QModelIndex QgsTaskManagerModel::idToIndex( long id, int column ) const
363 {
364  int row = idToRow( id );
365  if ( row < 0 )
366  return QModelIndex();
367 
368  return index( row, column );
369 }
370 
371 QString QgsTaskManagerModel::createTooltip( QgsTask *task, ToolTipType type )
372 {
373  if ( task->status() != QgsTask::Running )
374  {
375  switch ( type )
376  {
377  case ToolTipDescription:
378  return task->description();
379 
380  case ToolTipStatus:
381  case ToolTipProgress:
382  {
383  switch ( task->status() )
384  {
385  case QgsTask::Queued:
386  return tr( "Queued" );
387  case QgsTask::OnHold:
388  return tr( "On hold" );
389  case QgsTask::Running:
390  {
391  if ( type == ToolTipStatus && !task->canCancel() )
392  return tr( "Running (cannot cancel)" );
393  else
394  return tr( "Running" );
395  }
396  case QgsTask::Complete:
397  return tr( "Complete" );
398  case QgsTask::Terminated:
399  return tr( "Terminated" );
400  }
401  }
402  }
403  }
404 
405  QString formattedTime;
406 
407  qint64 elapsed = task->elapsedTime();
408 
409  if ( task->progress() > 0 )
410  {
411  // estimate time remaining
412  qint64 msRemain = static_cast< qint64 >( elapsed * 100.0 / task->progress() - elapsed );
413  if ( msRemain > 120 * 1000 )
414  {
415  long long minutes = msRemain / 1000 / 60;
416  int seconds = ( msRemain / 1000 ) % 60;
417  formattedTime = tr( "%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar( '0' ) );
418  }
419  else
420  formattedTime = tr( "%1 seconds" ).arg( msRemain / 1000 );
421 
422  formattedTime = tr( "Estimated time remaining: %1" ).arg( formattedTime );
423 
424  QTime estimatedEnd = QTime::currentTime().addMSecs( msRemain );
425  formattedTime += tr( " (%1)" ).arg( QLocale::system().toString( estimatedEnd, QLocale::ShortFormat ) );
426  }
427  else
428  {
429  if ( elapsed > 120 * 1000 )
430  {
431  long long minutes = elapsed / 1000 / 60;
432  int seconds = ( elapsed / 1000 ) % 60;
433  formattedTime = tr( "%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar( '0' ) );
434  }
435  else
436  formattedTime = tr( "%1 seconds" ).arg( elapsed / 1000 );
437 
438  formattedTime = tr( "Time elapsed: %1" ).arg( formattedTime );
439  }
440 
441  switch ( type )
442  {
443  case ToolTipDescription:
444  return tr( "%1<br>%2" ).arg( task->description(), formattedTime );
445 
446  case ToolTipStatus:
447  case ToolTipProgress:
448  {
449  switch ( task->status() )
450  {
451  case QgsTask::Queued:
452  return tr( "Queued" );
453  case QgsTask::OnHold:
454  return tr( "On hold" );
455  case QgsTask::Running:
456  {
457  QString statusDesc;
458  if ( type == ToolTipStatus && !task->canCancel() )
459  statusDesc = tr( "Running (cannot cancel)" );
460  else
461  statusDesc = tr( "Running" );
462  return tr( "%1<br>%2" ).arg( statusDesc, formattedTime );
463  }
464  case QgsTask::Complete:
465  return tr( "Complete" );
466  case QgsTask::Terminated:
467  return tr( "Terminated" );
468  }
469  }
470  }
471  // no warnings
472  return QString();
473 }
474 
475 
476 //
477 // QgsTaskStatusDelegate
478 //
479 
480 QgsTaskStatusWidget::QgsTaskStatusWidget( QWidget *parent, QgsTask::TaskStatus status, bool canCancel )
481  : QWidget( parent )
482  , mCanCancel( canCancel )
483  , mStatus( status )
484 {
485  setMouseTracking( true );
486 }
487 
488 QSize QgsTaskStatusWidget::sizeHint() const
489 {
490  return QSize( 32, 32 );
491 }
492 
493 void QgsTaskStatusWidget::setStatus( int status )
494 {
495  mStatus = static_cast< QgsTask::TaskStatus >( status );
496  update();
497 }
498 
499 void QgsTaskStatusWidget::paintEvent( QPaintEvent *e )
500 {
501  QWidget::paintEvent( e );
502 
503  QIcon icon;
504  if ( mInside && ( mCanCancel || ( mStatus == QgsTask::Queued || mStatus == QgsTask::OnHold ) ) )
505  {
506  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mTaskCancel.svg" ) );
507  }
508  else
509  {
510  switch ( mStatus )
511  {
512  case QgsTask::Queued:
513  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mTaskQueued.svg" ) );
514  break;
515  case QgsTask::OnHold:
516  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mTaskOnHold.svg" ) );
517  break;
518  case QgsTask::Running:
519  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mTaskRunning.svg" ) );
520  break;
521  case QgsTask::Complete:
522  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mTaskComplete.svg" ) );
523  break;
524  case QgsTask::Terminated:
525  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mTaskTerminated.svg" ) );
526  break;
527  }
528  }
529 
530  QPainter p( this );
531  icon.paint( &p, 1, height() / 2 - 12, 24, 24 );
532  p.end();
533 }
534 
535 void QgsTaskStatusWidget::mousePressEvent( QMouseEvent * )
536 {
537  if ( mCanCancel || ( mStatus == QgsTask::Queued || mStatus == QgsTask::OnHold ) )
538  emit cancelClicked();
539 }
540 
541 void QgsTaskStatusWidget::mouseMoveEvent( QMouseEvent * )
542 {
543  if ( !mInside )
544  {
545  mInside = true;
546  update();
547  }
548 }
549 
550 void QgsTaskStatusWidget::leaveEvent( QEvent * )
551 {
552  mInside = false;
553  update();
554 }
555 
556 
557 /*
558 bool QgsTaskStatusWidget::editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index )
559 {
560  Q_UNUSED( option )
561  if ( event->type() == QEvent::MouseButtonPress )
562  {
563  QMouseEvent *e = static_cast<QMouseEvent*>( event );
564  if ( e->button() == Qt::LeftButton )
565  {
566  if ( !index.model()->flags( index ).testFlag( Qt::ItemIsEditable ) )
567  {
568  //item not editable
569  return false;
570  }
571 
572  return model->setData( index, true, Qt::EditRole );
573  }
574  }
575  return false;
576 }
577 */
578 
579 QgsTaskManagerFloatingWidget::QgsTaskManagerFloatingWidget( QgsTaskManager *manager, QWidget *parent )
580  : QgsFloatingWidget( parent )
581 {
582  setLayout( new QVBoxLayout() );
583  QgsTaskManagerWidget *w = new QgsTaskManagerWidget( manager );
584 
585 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
586  int minWidth = static_cast< int >( fontMetrics().width( 'X' ) * 60 * Qgis::UI_SCALE_FACTOR );
587 #else
588  int minWidth = static_cast< int >( fontMetrics().horizontalAdvance( 'X' ) * 60 * Qgis::UI_SCALE_FACTOR );
589 #endif
590  int minHeight = static_cast< int >( fontMetrics().height() * 15 * Qgis::UI_SCALE_FACTOR );
591  setMinimumSize( minWidth, minHeight );
592  layout()->addWidget( w );
593  setStyleSheet( ".QgsTaskManagerFloatingWidget { border-top-left-radius: 8px;"
594  "border-top-right-radius: 8px; background-color: rgba(0, 0, 0, 70%); }" );
595 }
596 
597 
598 QgsTaskManagerStatusBarWidget::QgsTaskManagerStatusBarWidget( QgsTaskManager *manager, QWidget *parent )
599  : QToolButton( parent )
600  , mManager( manager )
601 {
602  setAutoRaise( true );
603  setSizePolicy( QSizePolicy::Fixed, QSizePolicy::MinimumExpanding );
604  setLayout( new QVBoxLayout() );
605 
606  mProgressBar = new QProgressBar();
607  mProgressBar->setMinimum( 0 );
608  mProgressBar->setMaximum( 0 );
609  layout()->setContentsMargins( 5, 5, 5, 5 );
610  layout()->addWidget( mProgressBar );
611 
612  mFloatingWidget = new QgsTaskManagerFloatingWidget( manager, parent ? parent->window() : nullptr );
613  mFloatingWidget->setAnchorWidget( this );
614  mFloatingWidget->setAnchorPoint( QgsFloatingWidget::BottomMiddle );
615  mFloatingWidget->setAnchorWidgetPoint( QgsFloatingWidget::TopMiddle );
616  mFloatingWidget->hide();
617  connect( this, &QgsTaskManagerStatusBarWidget::clicked, this, &QgsTaskManagerStatusBarWidget::toggleDisplay );
618  hide();
619 
620  connect( manager, &QgsTaskManager::taskAdded, this, &QgsTaskManagerStatusBarWidget::showButton );
621  connect( manager, &QgsTaskManager::allTasksFinished, this, &QgsTaskManagerStatusBarWidget::allFinished );
622  connect( manager, &QgsTaskManager::finalTaskProgressChanged, this, &QgsTaskManagerStatusBarWidget::overallProgressChanged );
623  connect( manager, &QgsTaskManager::countActiveTasksChanged, this, &QgsTaskManagerStatusBarWidget::countActiveTasksChanged );
624 
625  if ( manager->countActiveTasks() )
626  showButton();
627 }
628 
629 QSize QgsTaskManagerStatusBarWidget::sizeHint() const
630 {
631 
632 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
633  int width = static_cast< int >( fontMetrics().width( 'X' ) * 20 * Qgis::UI_SCALE_FACTOR );
634 #else
635  int width = static_cast< int >( fontMetrics().horizontalAdvance( 'X' ) * 20 * Qgis::UI_SCALE_FACTOR );
636 #endif
637  int height = QToolButton::sizeHint().height();
638  return QSize( width, height );
639 }
640 
641 void QgsTaskManagerStatusBarWidget::changeEvent( QEvent *event )
642 {
643  QToolButton::changeEvent( event );
644 
645  if ( event->type() == QEvent::FontChange )
646  {
647  mProgressBar->setFont( font() );
648  }
649 }
650 
651 void QgsTaskManagerStatusBarWidget::toggleDisplay()
652 {
653  if ( mFloatingWidget->isVisible() )
654  mFloatingWidget->hide();
655  else
656  {
657  mFloatingWidget->show();
658  mFloatingWidget->raise();
659  }
660 }
661 
662 void QgsTaskManagerStatusBarWidget::overallProgressChanged( double progress )
663 {
664  mProgressBar->setValue( static_cast< int >( std::round( progress ) ) );
665  if ( qgsDoubleNear( progress, 0.0 ) )
666  mProgressBar->setMaximum( 0 );
667  else if ( mProgressBar->maximum() == 0 )
668  mProgressBar->setMaximum( 100 );
669  setToolTip( QgsTaskManagerModel::createTooltip( mManager->activeTasks().at( 0 ), QgsTaskManagerModel::ToolTipDescription ) );
670 }
671 
672 void QgsTaskManagerStatusBarWidget::countActiveTasksChanged( int count )
673 {
674  if ( count > 1 )
675  {
676  mProgressBar->setMaximum( 0 );
677  setToolTip( tr( "%1 active tasks running" ).arg( count ) );
678  }
679 }
680 
681 void QgsTaskManagerStatusBarWidget::allFinished()
682 {
683  mFloatingWidget->hide();
684  hide();
685 
686  mProgressBar->setMaximum( 0 );
687  mProgressBar->setValue( 0 );
688 }
689 
690 void QgsTaskManagerStatusBarWidget::showButton()
691 {
692  if ( !isVisible() )
693  {
694  mProgressBar->setMaximum( 0 );
695  mProgressBar->setValue( 0 );
696  show();
697  }
698 }
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:183
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
A QWidget subclass for creating widgets which float outside of the normal Qt layout system.
@ BottomMiddle
Bottom center of widget.
@ TopMiddle
Top center of widget.
A widget which displays tasks from a QgsTaskManager and allows for interaction with the manager.
QgsTaskManagerWidget(QgsTaskManager *manager, QWidget *parent=nullptr)
Constructor for QgsTaskManagerWidget.
Task manager for managing a set of long-running QgsTask tasks.
QList< QgsTask * > tasks() const
Returns all tasks tracked by the manager.
void finalTaskProgressChanged(double progress)
Will be emitted when only a single task remains to complete and that task has reported a progress cha...
void statusChanged(long taskId, int status)
Will be emitted when a task reports a status change.
void taskAdded(long taskId)
Emitted when a new task has been added to the manager.
int countActiveTasks() const
Returns the number of active (queued or running) tasks.
long taskId(QgsTask *task) const
Returns the unique task ID corresponding to a task managed by the class.
void allTasksFinished()
Emitted when all tasks are complete.
void progressChanged(long taskId, double progress)
Will be emitted when a task reports a progress change.
void triggerTask(QgsTask *task)
Triggers a task, e.g.
void countActiveTasksChanged(int count)
Emitted when the number of active tasks changes.
Abstract base class for long running background tasks.
TaskStatus status() const
Returns the current task status.
double progress() const
Returns the task's progress (between 0.0 and 100.0)
void progressChanged(double progress)
Will be emitted by task when its progress changes.
virtual void cancel()
Notifies the task that it should terminate.
void statusChanged(int status)
Will be emitted by task when its status changes.
qint64 elapsedTime() const
Returns the elapsed time since the task commenced, in milliseconds.
TaskStatus
Status of tasks.
@ Terminated
Task was terminated or errored.
@ Queued
Task is queued and has not begun.
@ OnHold
Task is queued but on hold and will not be started.
@ Running
Task is currently running.
@ Complete
Task successfully completed.
QString description() const
Returns the task's description.
bool canCancel() const
Returns true if the task can be canceled.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316