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 );
125 const auto constTasks = mManager->
tasks();
126 for (
QgsTask *task : constTasks )
128 mRowToTaskIdList << mManager->
taskId( task );
136 QModelIndex QgsTaskManagerModel::index(
int row,
int column,
const QModelIndex &parent )
const 138 if ( column < 0 || column >= columnCount() )
141 return QModelIndex();
144 if ( !parent.isValid() && row >= 0 && row < mRowToTaskIdList.count() )
147 return createIndex( row, column );
151 return QModelIndex();
155 QModelIndex QgsTaskManagerModel::parent(
const QModelIndex &index )
const 160 return QModelIndex();
163 int QgsTaskManagerModel::rowCount(
const QModelIndex &parent )
const 165 if ( !parent.isValid() )
167 return mRowToTaskIdList.count();
176 int QgsTaskManagerModel::columnCount(
const QModelIndex &parent )
const 182 QVariant QgsTaskManagerModel::data(
const QModelIndex &index,
int role )
const 184 if ( !index.isValid() )
187 QgsTask *task = indexToTask( index );
192 case Qt::DisplayRole:
194 switch ( index.column() )
208 return static_cast<int>( task->
status() );
210 case Qt::ToolTipRole:
211 switch ( index.column() )
214 return createTooltip( task, ToolTipDescription );
216 return createTooltip( task, ToolTipProgress );
218 return createTooltip( task, ToolTipStatus );
232 Qt::ItemFlags QgsTaskManagerModel::flags(
const QModelIndex &index )
const 234 Qt::ItemFlags flags = QAbstractItemModel::flags( index );
236 if ( ! index.isValid() )
241 QgsTask *task = indexToTask( index );
242 if ( index.column() == Status )
245 flags = flags | Qt::ItemIsEditable;
247 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
250 bool QgsTaskManagerModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
254 if ( !index.isValid() )
257 QgsTask *task = indexToTask( index );
261 switch ( index.column() )
265 if ( value.toBool() && task->
canCancel() )
275 void QgsTaskManagerModel::taskAdded(
long id )
277 beginInsertRows( QModelIndex(), mRowToTaskIdList.count(),
278 mRowToTaskIdList.count() );
279 mRowToTaskIdList << id;
283 void QgsTaskManagerModel::taskDeleted(
long id )
285 for (
int row = 0; row < mRowToTaskIdList.count(); ++row )
287 if ( mRowToTaskIdList.at( row ) == id )
289 beginRemoveRows( QModelIndex(), row, row );
290 mRowToTaskIdList.removeAt( row );
297 void QgsTaskManagerModel::progressChanged(
long id,
double progress )
301 QModelIndex index = idToIndex(
id, Progress );
302 if ( !index.isValid() )
307 emit dataChanged( index, index );
310 void QgsTaskManagerModel::statusChanged(
long id,
int status )
318 QModelIndex index = idToIndex(
id, Status );
319 if ( !index.isValid() )
324 emit dataChanged( index, index );
328 QgsTask *QgsTaskManagerModel::indexToTask(
const QModelIndex &index )
const 330 if ( !index.isValid() || index.parent().isValid() )
333 long id = index.row() >= 0 && index.row() < mRowToTaskIdList.count() ? mRowToTaskIdList.at( index.row() ) : -1;
335 return mManager->
task(
id );
340 int QgsTaskManagerModel::idToRow(
long id )
const 342 for (
int row = 0; row < mRowToTaskIdList.count(); ++row )
344 if ( mRowToTaskIdList.at( row ) == id )
352 QModelIndex QgsTaskManagerModel::idToIndex(
long id,
int column )
const 354 int row = idToRow(
id );
356 return QModelIndex();
358 return index( row, column );
361 QString QgsTaskManagerModel::createTooltip(
QgsTask *task, ToolTipType type )
367 case ToolTipDescription:
371 case ToolTipProgress:
376 return tr(
"Queued" );
378 return tr(
"On hold" );
381 if ( type == ToolTipStatus && !task->
canCancel() )
382 return tr(
"Running (cannot cancel)" );
384 return tr(
"Running" );
387 return tr(
"Complete" );
389 return tr(
"Terminated" );
395 QString formattedTime;
402 qint64 msRemain =
static_cast< qint64
>( elapsed * 100.0 / task->
progress() - elapsed );
403 if ( msRemain > 120 * 1000 )
405 long long minutes = msRemain / 1000 / 60;
406 int seconds = ( msRemain / 1000 ) % 60;
407 formattedTime = tr(
"%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar(
'0' ) );
410 formattedTime = tr(
"%1 seconds" ).arg( msRemain / 1000 );
412 formattedTime = tr(
"Estimated time remaining: %1" ).arg( formattedTime );
414 QTime estimatedEnd = QTime::currentTime().addMSecs( msRemain );
415 formattedTime += tr(
" (%1)" ).arg( QLocale::system().toString( estimatedEnd, QLocale::ShortFormat ) );
419 if ( elapsed > 120 * 1000 )
421 long long minutes = elapsed / 1000 / 60;
422 int seconds = ( elapsed / 1000 ) % 60;
423 formattedTime = tr(
"%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar(
'0' ) );
426 formattedTime = tr(
"%1 seconds" ).arg( elapsed / 1000 );
428 formattedTime = tr(
"Time elapsed: %1" ).arg( formattedTime );
433 case ToolTipDescription:
434 return tr(
"%1<br>%2" ).arg( task->
description(), formattedTime );
437 case ToolTipProgress:
442 return tr(
"Queued" );
444 return tr(
"On hold" );
448 if ( type == ToolTipStatus && !task->
canCancel() )
449 statusDesc = tr(
"Running (cannot cancel)" );
451 statusDesc = tr(
"Running" );
452 return tr(
"%1<br>%2" ).arg( statusDesc, formattedTime );
455 return tr(
"Complete" );
457 return tr(
"Terminated" );
470 QgsTaskStatusWidget::QgsTaskStatusWidget( QWidget *parent,
QgsTask::TaskStatus status,
bool canCancel )
472 , mCanCancel( canCancel )
475 setMouseTracking(
true );
478 QSize QgsTaskStatusWidget::sizeHint()
const 480 return QSize( 32, 32 );
483 void QgsTaskStatusWidget::setStatus(
int status )
489 void QgsTaskStatusWidget::paintEvent( QPaintEvent *e )
491 QWidget::paintEvent( e );
521 icon.paint( &p, 1, height() / 2 - 12, 24, 24 );
525 void QgsTaskStatusWidget::mousePressEvent( QMouseEvent * )
528 emit cancelClicked();
531 void QgsTaskStatusWidget::mouseMoveEvent( QMouseEvent * )
540 void QgsTaskStatusWidget::leaveEvent( QEvent * )
569 QgsTaskManagerFloatingWidget::QgsTaskManagerFloatingWidget(
QgsTaskManager *manager, QWidget *parent )
572 setLayout(
new QVBoxLayout() );
576 setMinimumSize( minWidth, minHeight );
577 layout()->addWidget( w );
578 setStyleSheet(
".QgsTaskManagerFloatingWidget { border-top-left-radius: 8px;" 579 "border-top-right-radius: 8px; background-color: rgb(0, 0, 0, 70%); }" );
583 QgsTaskManagerStatusBarWidget::QgsTaskManagerStatusBarWidget(
QgsTaskManager *manager, QWidget *parent )
584 : QToolButton( parent )
585 , mManager( manager )
587 setAutoRaise(
true );
588 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::MinimumExpanding );
589 setLayout(
new QVBoxLayout() );
591 mProgressBar =
new QProgressBar();
592 mProgressBar->setMinimum( 0 );
593 mProgressBar->setMaximum( 0 );
594 layout()->setContentsMargins( 5, 5, 5, 5 );
595 layout()->addWidget( mProgressBar );
597 mFloatingWidget =
new QgsTaskManagerFloatingWidget( manager, parent ? parent->window() : nullptr );
598 mFloatingWidget->setAnchorWidget(
this );
601 mFloatingWidget->hide();
602 connect(
this, &QgsTaskManagerStatusBarWidget::clicked,
this, &QgsTaskManagerStatusBarWidget::toggleDisplay );
611 QSize QgsTaskManagerStatusBarWidget::sizeHint()
const 614 int height = QToolButton::sizeHint().height();
615 return QSize( width, height );
618 void QgsTaskManagerStatusBarWidget::changeEvent( QEvent *event )
620 QToolButton::changeEvent( event );
622 if ( event->type() == QEvent::FontChange )
624 mProgressBar->setFont( font() );
628 void QgsTaskManagerStatusBarWidget::toggleDisplay()
630 if ( mFloatingWidget->isVisible() )
631 mFloatingWidget->hide();
634 mFloatingWidget->show();
635 mFloatingWidget->raise();
639 void QgsTaskManagerStatusBarWidget::overallProgressChanged(
double progress )
641 mProgressBar->setValue( static_cast< int >( std::round( progress ) ) );
643 mProgressBar->setMaximum( 0 );
644 else if ( mProgressBar->maximum() == 0 )
645 mProgressBar->setMaximum( 100 );
646 setToolTip( QgsTaskManagerModel::createTooltip( mManager->
activeTasks().at( 0 ), QgsTaskManagerModel::ToolTipDescription ) );
649 void QgsTaskManagerStatusBarWidget::countActiveTasksChanged(
int count )
653 mProgressBar->setMaximum( 0 );
654 setToolTip( tr(
"%1 active tasks running" ).arg( count ) );
658 void QgsTaskManagerStatusBarWidget::allFinished()
660 mFloatingWidget->hide();
663 mProgressBar->setMaximum( 0 );
664 mProgressBar->setValue( 0 );
667 void QgsTaskManagerStatusBarWidget::showButton()
671 mProgressBar->setMaximum( 0 );
672 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.