22 #include <QMouseEvent> 26 #include <QProgressBar> 28 #include <QHeaderView> 40 QVBoxLayout *vLayout =
new QVBoxLayout();
41 vLayout->setMargin( 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 );
50 mTreeView->setColumnWidth( QgsTaskManagerModel::Progress, progressColWidth );
52 mTreeView->setColumnWidth( QgsTaskManagerModel::Status, statusColWidth );
53 mTreeView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
54 mTreeView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
55 mTreeView->header()->setStretchLastSection(
false );
56 mTreeView->header()->setSectionResizeMode( QgsTaskManagerModel::Description, QHeaderView::Stretch );
58 connect( mTreeView, &QTreeView::clicked,
this, &QgsTaskManagerWidget::clicked );
60 vLayout->addWidget( mTreeView );
71 void QgsTaskManagerWidget::modelRowsInserted(
const QModelIndex &,
int start,
int end )
73 for (
int row = start; row <= end; ++row )
75 QgsTask *task = mModel->indexToTask( mModel->index( row, 1 ) );
79 QProgressBar *progressBar =
new QProgressBar();
80 progressBar->setAutoFillBackground(
true );
81 progressBar->setRange( 0, 0 );
87 progressBar->setMaximum( 100 );
88 progressBar->setValue( static_cast< int >( std::round( progress ) ) );
91 progressBar->setMaximum( 0 );
94 mTreeView->setIndexWidget( mModel->index( row, QgsTaskManagerModel::Progress ), progressBar );
96 QgsTaskStatusWidget *statusWidget =
new QgsTaskStatusWidget(
nullptr, task->
status(), task->
canCancel() );
97 statusWidget->setAutoFillBackground(
true );
99 connect( statusWidget, &QgsTaskStatusWidget::cancelClicked, task, &
QgsTask::cancel );
100 mTreeView->setIndexWidget( mModel->index( row, QgsTaskManagerModel::Status ), statusWidget );
104 void QgsTaskManagerWidget::clicked(
const QModelIndex &index )
106 QgsTask *task = mModel->indexToTask( index );
118 QgsTaskManagerModel::QgsTaskManagerModel(
QgsTaskManager *manager, QObject *parent )
119 : QAbstractItemModel( parent )
120 , mManager( manager )
122 Q_ASSERT( mManager );
127 mRowToTaskIdList << mManager->
taskId( task );
135 QModelIndex QgsTaskManagerModel::index(
int row,
int column,
const QModelIndex &parent )
const 137 if ( column < 0 || column >= columnCount() )
140 return QModelIndex();
143 if ( !parent.isValid() && row >= 0 && row < mRowToTaskIdList.count() )
146 return createIndex( row, column );
150 return QModelIndex();
154 QModelIndex QgsTaskManagerModel::parent(
const QModelIndex &index )
const 159 return QModelIndex();
162 int QgsTaskManagerModel::rowCount(
const QModelIndex &parent )
const 164 if ( !parent.isValid() )
166 return mRowToTaskIdList.count();
175 int QgsTaskManagerModel::columnCount(
const QModelIndex &parent )
const 181 QVariant QgsTaskManagerModel::data(
const QModelIndex &index,
int role )
const 183 if ( !index.isValid() )
186 QgsTask *task = indexToTask( index );
191 case Qt::DisplayRole:
193 switch ( index.column() )
207 return static_cast<int>( task->
status() );
209 case Qt::ToolTipRole:
210 switch ( index.column() )
213 return createTooltip( task, ToolTipDescription );
215 return createTooltip( task, ToolTipProgress );
217 return createTooltip( task, ToolTipStatus );
231 Qt::ItemFlags QgsTaskManagerModel::flags(
const QModelIndex &index )
const 233 Qt::ItemFlags flags = QAbstractItemModel::flags( index );
235 if ( ! index.isValid() )
240 QgsTask *task = indexToTask( index );
241 if ( index.column() == Status )
244 flags = flags | Qt::ItemIsEditable;
246 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
249 bool QgsTaskManagerModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
253 if ( !index.isValid() )
256 QgsTask *task = indexToTask( index );
260 switch ( index.column() )
264 if ( value.toBool() && task->
canCancel() )
274 void QgsTaskManagerModel::taskAdded(
long id )
276 beginInsertRows( QModelIndex(), mRowToTaskIdList.count(),
277 mRowToTaskIdList.count() );
278 mRowToTaskIdList << id;
282 void QgsTaskManagerModel::taskDeleted(
long id )
284 for (
int row = 0; row < mRowToTaskIdList.count(); ++row )
286 if ( mRowToTaskIdList.at( row ) == id )
288 beginRemoveRows( QModelIndex(), row, row );
289 mRowToTaskIdList.removeAt( row );
296 void QgsTaskManagerModel::progressChanged(
long id,
double progress )
298 Q_UNUSED( progress );
300 QModelIndex index = idToIndex(
id, Progress );
301 if ( !index.isValid() )
306 emit dataChanged( index, index );
309 void QgsTaskManagerModel::statusChanged(
long id,
int status )
317 QModelIndex index = idToIndex(
id, Status );
318 if ( !index.isValid() )
323 emit dataChanged( index, index );
327 QgsTask *QgsTaskManagerModel::indexToTask(
const QModelIndex &index )
const 329 if ( !index.isValid() || index.parent().isValid() )
332 long id = index.row() >= 0 && index.row() < mRowToTaskIdList.count() ? mRowToTaskIdList.at( index.row() ) : -1;
334 return mManager->
task(
id );
339 int QgsTaskManagerModel::idToRow(
long id )
const 341 for (
int row = 0; row < mRowToTaskIdList.count(); ++row )
343 if ( mRowToTaskIdList.at( row ) == id )
351 QModelIndex QgsTaskManagerModel::idToIndex(
long id,
int column )
const 353 int row = idToRow(
id );
355 return QModelIndex();
357 return index( row, column );
360 QString QgsTaskManagerModel::createTooltip(
QgsTask *task, ToolTipType type )
366 case ToolTipDescription:
370 case ToolTipProgress:
375 return tr(
"Queued" );
377 return tr(
"On hold" );
380 if ( type == ToolTipStatus && !task->
canCancel() )
381 return tr(
"Running (cannot cancel)" );
383 return tr(
"Running" );
386 return tr(
"Complete" );
388 return tr(
"Terminated" );
394 QString formattedTime;
401 qint64 msRemain =
static_cast< qint64
>( elapsed * 100.0 / task->
progress() - elapsed );
402 if ( msRemain > 120 * 1000 )
404 long long minutes = msRemain / 1000 / 60;
405 int seconds = ( msRemain / 1000 ) % 60;
406 formattedTime = tr(
"%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar(
'0' ) );
409 formattedTime = tr(
"%1 seconds" ).arg( msRemain / 1000 );
411 formattedTime = tr(
"Estimated time remaining: %1" ).arg( formattedTime );
413 QTime estimatedEnd = QTime::currentTime().addMSecs( msRemain );
414 formattedTime += tr(
" (%1)" ).arg( QLocale::system().toString( estimatedEnd, QLocale::ShortFormat ) );
418 if ( elapsed > 120 * 1000 )
420 long long minutes = elapsed / 1000 / 60;
421 int seconds = ( elapsed / 1000 ) % 60;
422 formattedTime = tr(
"%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar(
'0' ) );
425 formattedTime = tr(
"%1 seconds" ).arg( elapsed / 1000 );
427 formattedTime = tr(
"Time elapsed: %1" ).arg( formattedTime );
432 case ToolTipDescription:
433 return tr(
"%1<br>%2" ).arg( task->
description(), formattedTime );
436 case ToolTipProgress:
441 return tr(
"Queued" );
443 return tr(
"On hold" );
447 if ( type == ToolTipStatus && !task->
canCancel() )
448 statusDesc = tr(
"Running (cannot cancel)" );
450 statusDesc = tr(
"Running" );
451 return tr(
"%1<br>%2" ).arg( statusDesc, formattedTime );
454 return tr(
"Complete" );
456 return tr(
"Terminated" );
469 QgsTaskStatusWidget::QgsTaskStatusWidget( QWidget *parent,
QgsTask::TaskStatus status,
bool canCancel )
471 , mCanCancel( canCancel )
474 setMouseTracking(
true );
477 QSize QgsTaskStatusWidget::sizeHint()
const 479 return QSize( 32, 32 );
482 void QgsTaskStatusWidget::setStatus(
int status )
488 void QgsTaskStatusWidget::paintEvent( QPaintEvent *e )
490 QWidget::paintEvent( e );
520 icon.paint( &p, 1, height() / 2 - 12, 24, 24 );
524 void QgsTaskStatusWidget::mousePressEvent( QMouseEvent * )
527 emit cancelClicked();
530 void QgsTaskStatusWidget::mouseMoveEvent( QMouseEvent * )
539 void QgsTaskStatusWidget::leaveEvent( QEvent * )
568 QgsTaskManagerFloatingWidget::QgsTaskManagerFloatingWidget(
QgsTaskManager *manager, QWidget *parent )
571 setLayout(
new QVBoxLayout() );
575 setMinimumSize( minWidth, minHeight );
576 layout()->addWidget( w );
577 setStyleSheet(
".QgsTaskManagerFloatingWidget { border-top-left-radius: 8px;" 578 "border-top-right-radius: 8px; background-color: rgb(0, 0, 0, 70%); }" );
582 QgsTaskManagerStatusBarWidget::QgsTaskManagerStatusBarWidget(
QgsTaskManager *manager, QWidget *parent )
583 : QToolButton( parent )
584 , mManager( manager )
586 setAutoRaise(
true );
587 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::MinimumExpanding );
588 setLayout(
new QVBoxLayout() );
590 mProgressBar =
new QProgressBar();
591 mProgressBar->setMinimum( 0 );
592 mProgressBar->setMaximum( 0 );
593 layout()->setContentsMargins( 5, 5, 5, 5 );
594 layout()->addWidget( mProgressBar );
596 mFloatingWidget =
new QgsTaskManagerFloatingWidget( manager, parent ? parent->window() : nullptr );
597 mFloatingWidget->setAnchorWidget(
this );
600 mFloatingWidget->hide();
601 connect(
this, &QgsTaskManagerStatusBarWidget::clicked,
this, &QgsTaskManagerStatusBarWidget::toggleDisplay );
610 QSize QgsTaskManagerStatusBarWidget::sizeHint()
const 613 int height = QToolButton::sizeHint().height();
614 return QSize( width, height );
617 void QgsTaskManagerStatusBarWidget::changeEvent( QEvent *event )
619 QToolButton::changeEvent( event );
621 if ( event->type() == QEvent::FontChange )
623 mProgressBar->setFont( font() );
627 void QgsTaskManagerStatusBarWidget::toggleDisplay()
629 if ( mFloatingWidget->isVisible() )
630 mFloatingWidget->hide();
633 mFloatingWidget->show();
634 mFloatingWidget->raise();
638 void QgsTaskManagerStatusBarWidget::overallProgressChanged(
double progress )
640 mProgressBar->setValue( static_cast< int >( std::round( progress ) ) );
642 mProgressBar->setMaximum( 0 );
643 else if ( mProgressBar->maximum() == 0 )
644 mProgressBar->setMaximum( 100 );
645 setToolTip( QgsTaskManagerModel::createTooltip( mManager->
activeTasks().at( 0 ), QgsTaskManagerModel::ToolTipDescription ) );
648 void QgsTaskManagerStatusBarWidget::countActiveTasksChanged(
int count )
652 mProgressBar->setMaximum( 0 );
653 setToolTip( tr(
"%1 active tasks running" ).arg( count ) );
657 void QgsTaskManagerStatusBarWidget::allFinished()
659 mFloatingWidget->hide();
662 mProgressBar->setMaximum( 0 );
663 mProgressBar->setValue( 0 );
666 void QgsTaskManagerStatusBarWidget::showButton()
670 mProgressBar->setMaximum( 0 );
671 mProgressBar->setValue( 0 );
static const double UI_SCALE_FACTOR
UI scaling factor.
void statusChanged(int status)
Will be emitted by task when its status changes.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
qint64 elapsedTime() const
Returns the elapsed time since the task commenced, in milliseconds.
TaskStatus
Status of tasks.
QList< QgsTask * > tasks() const
Returns all tasks tracked by the manager.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void progressChanged(double progress)
Will be emitted by task when its progress changes.
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.
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.
Task is queued but on hold and will not be started.
Abstract base class for long running background tasks.
bool canCancel() const
Returns true if the task can be canceled.
void statusChanged(long taskId, int status)
Will be emitted when a task reports a status change.
Task successfully completed.
Task manager for managing a set of long-running QgsTask tasks.
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)
QList< QgsTask *> activeTasks() const
Returns a list of the active (queued or running) tasks.
Task is currently running.
long taskId(QgsTask *task) const
Returns the unique task ID corresponding to a task managed by the class.
void finalTaskProgressChanged(double progress)
Will be emitted when only a single task remains to complete and that task has reported a progress cha...
TaskStatus status() const
Returns the current task status.