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 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
53 int progressColWidth =
static_cast< int >( fontMetrics().horizontalAdvance(
'X' ) * 10 *
Qgis::UI_SCALE_FACTOR );
55 mTreeView->setColumnWidth( QgsTaskManagerModel::Progress, progressColWidth );
57 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
60 int statusColWidth =
static_cast< int >( fontMetrics().horizontalAdvance(
'X' ) * 2 *
Qgis::UI_SCALE_FACTOR );
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 );
68 connect( mTreeView, &QTreeView::clicked,
this, &QgsTaskManagerWidget::clicked );
70 vLayout->addWidget( mTreeView );
81 void QgsTaskManagerWidget::modelRowsInserted(
const QModelIndex &,
int start,
int end )
83 for (
int row = start; row <= end; ++row )
85 QgsTask *task = mModel->indexToTask( mModel->index( row, 1 ) );
89 QProgressBar *progressBar =
new QProgressBar();
90 progressBar->setAutoFillBackground(
true );
91 progressBar->setRange( 0, 0 );
97 progressBar->setMaximum( 100 );
98 progressBar->setValue(
static_cast< int >( std::round( progress ) ) );
101 progressBar->setMaximum( 0 );
104 mTreeView->setIndexWidget( mModel->index( row, QgsTaskManagerModel::Progress ), progressBar );
106 QgsTaskStatusWidget *statusWidget =
new QgsTaskStatusWidget(
nullptr, task->
status(), task->
canCancel() );
107 statusWidget->setAutoFillBackground(
true );
109 connect( statusWidget, &QgsTaskStatusWidget::cancelClicked, task, &
QgsTask::cancel );
110 mTreeView->setIndexWidget( mModel->index( row, QgsTaskManagerModel::Status ), statusWidget );
114 void QgsTaskManagerWidget::clicked(
const QModelIndex &index )
116 QgsTask *task = mModel->indexToTask( index );
128 QgsTaskManagerModel::QgsTaskManagerModel(
QgsTaskManager *manager, QObject *parent )
129 : QAbstractItemModel( parent )
130 , mManager( manager )
132 Q_ASSERT( mManager );
135 const auto constTasks = mManager->
tasks();
136 for (
QgsTask *task : constTasks )
138 mRowToTaskIdList << mManager->
taskId( task );
146 QModelIndex QgsTaskManagerModel::index(
int row,
int column,
const QModelIndex &parent )
const
148 if ( column < 0 || column >= columnCount() )
151 return QModelIndex();
154 if ( !parent.isValid() && row >= 0 && row < mRowToTaskIdList.count() )
157 return createIndex( row, column );
161 return QModelIndex();
165 QModelIndex QgsTaskManagerModel::parent(
const QModelIndex &index )
const
170 return QModelIndex();
173 int QgsTaskManagerModel::rowCount(
const QModelIndex &parent )
const
175 if ( !parent.isValid() )
177 return mRowToTaskIdList.count();
186 int QgsTaskManagerModel::columnCount(
const QModelIndex &parent )
const
192 QVariant QgsTaskManagerModel::data(
const QModelIndex &index,
int role )
const
194 if ( !index.isValid() )
197 QgsTask *task = indexToTask( index );
202 case Qt::DisplayRole:
204 switch ( index.column() )
218 return static_cast<int>( task->
status() );
220 case Qt::ToolTipRole:
221 switch ( index.column() )
224 return createTooltip( task, ToolTipDescription );
226 return createTooltip( task, ToolTipProgress );
228 return createTooltip( task, ToolTipStatus );
242 Qt::ItemFlags QgsTaskManagerModel::flags(
const QModelIndex &index )
const
244 Qt::ItemFlags flags = QAbstractItemModel::flags( index );
246 if ( ! index.isValid() )
251 QgsTask *task = indexToTask( index );
252 if ( index.column() == Status )
255 flags = flags | Qt::ItemIsEditable;
257 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
260 bool QgsTaskManagerModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
264 if ( !index.isValid() )
267 QgsTask *task = indexToTask( index );
271 switch ( index.column() )
275 if ( value.toBool() && task->
canCancel() )
285 void QgsTaskManagerModel::taskAdded(
long id )
287 beginInsertRows( QModelIndex(), mRowToTaskIdList.count(),
288 mRowToTaskIdList.count() );
289 mRowToTaskIdList << id;
293 void QgsTaskManagerModel::taskDeleted(
long id )
295 for (
int row = 0; row < mRowToTaskIdList.count(); ++row )
297 if ( mRowToTaskIdList.at( row ) ==
id )
299 beginRemoveRows( QModelIndex(), row, row );
300 mRowToTaskIdList.removeAt( row );
307 void QgsTaskManagerModel::progressChanged(
long id,
double progress )
311 QModelIndex index = idToIndex(
id, Progress );
312 if ( !index.isValid() )
317 emit dataChanged( index, index );
320 void QgsTaskManagerModel::statusChanged(
long id,
int status )
328 QModelIndex index = idToIndex(
id, Status );
329 if ( !index.isValid() )
334 emit dataChanged( index, index );
338 QgsTask *QgsTaskManagerModel::indexToTask(
const QModelIndex &index )
const
340 if ( !index.isValid() || index.parent().isValid() )
343 long id = index.row() >= 0 && index.row() < mRowToTaskIdList.count() ? mRowToTaskIdList.at( index.row() ) : -1;
345 return mManager->task(
id );
350 int QgsTaskManagerModel::idToRow(
long id )
const
352 for (
int row = 0; row < mRowToTaskIdList.count(); ++row )
354 if ( mRowToTaskIdList.at( row ) ==
id )
362 QModelIndex QgsTaskManagerModel::idToIndex(
long id,
int column )
const
364 int row = idToRow(
id );
366 return QModelIndex();
368 return index( row, column );
371 QString QgsTaskManagerModel::createTooltip(
QgsTask *task, ToolTipType type )
377 case ToolTipDescription:
381 case ToolTipProgress:
386 return tr(
"Queued" );
388 return tr(
"On hold" );
391 if ( type == ToolTipStatus && !task->
canCancel() )
392 return tr(
"Running (cannot cancel)" );
394 return tr(
"Running" );
397 return tr(
"Complete" );
399 return tr(
"Terminated" );
405 QString formattedTime;
412 qint64 msRemain =
static_cast< qint64
>( elapsed * 100.0 / task->
progress() - elapsed );
413 if ( msRemain > 120 * 1000 )
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' ) );
420 formattedTime = tr(
"%1 seconds" ).arg( msRemain / 1000 );
422 formattedTime = tr(
"Estimated time remaining: %1" ).arg( formattedTime );
424 QTime estimatedEnd = QTime::currentTime().addMSecs( msRemain );
425 formattedTime += tr(
" (%1)" ).arg( QLocale::system().toString( estimatedEnd, QLocale::ShortFormat ) );
429 if ( elapsed > 120 * 1000 )
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' ) );
436 formattedTime = tr(
"%1 seconds" ).arg( elapsed / 1000 );
438 formattedTime = tr(
"Time elapsed: %1" ).arg( formattedTime );
443 case ToolTipDescription:
444 return tr(
"%1<br>%2" ).arg( task->
description(), formattedTime );
447 case ToolTipProgress:
452 return tr(
"Queued" );
454 return tr(
"On hold" );
458 if ( type == ToolTipStatus && !task->
canCancel() )
459 statusDesc = tr(
"Running (cannot cancel)" );
461 statusDesc = tr(
"Running" );
462 return tr(
"%1<br>%2" ).arg( statusDesc, formattedTime );
465 return tr(
"Complete" );
467 return tr(
"Terminated" );
480 QgsTaskStatusWidget::QgsTaskStatusWidget( QWidget *parent,
QgsTask::TaskStatus status,
bool canCancel )
482 , mCanCancel( canCancel )
485 setMouseTracking(
true );
488 QSize QgsTaskStatusWidget::sizeHint()
const
490 return QSize( 32, 32 );
493 void QgsTaskStatusWidget::setStatus(
int status )
499 void QgsTaskStatusWidget::paintEvent( QPaintEvent *e )
501 QWidget::paintEvent( e );
531 icon.paint( &p, 1, height() / 2 - 12, 24, 24 );
535 void QgsTaskStatusWidget::mousePressEvent( QMouseEvent * )
538 emit cancelClicked();
541 void QgsTaskStatusWidget::mouseMoveEvent( QMouseEvent * )
550 void QgsTaskStatusWidget::leaveEvent( QEvent * )
579 QgsTaskManagerFloatingWidget::QgsTaskManagerFloatingWidget(
QgsTaskManager *manager, QWidget *parent )
582 setLayout(
new QVBoxLayout() );
585 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
588 int minWidth =
static_cast< int >( fontMetrics().horizontalAdvance(
'X' ) * 60 *
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%); }" );
598 QgsTaskManagerStatusBarWidget::QgsTaskManagerStatusBarWidget(
QgsTaskManager *manager, QWidget *parent )
599 : QToolButton( parent )
600 , mManager( manager )
602 setAutoRaise(
true );
603 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::MinimumExpanding );
604 setLayout(
new QVBoxLayout() );
606 mProgressBar =
new QProgressBar();
607 mProgressBar->setMinimum( 0 );
608 mProgressBar->setMaximum( 0 );
609 layout()->setContentsMargins( 5, 5, 5, 5 );
610 layout()->addWidget( mProgressBar );
612 mFloatingWidget =
new QgsTaskManagerFloatingWidget( manager, parent ? parent->window() :
nullptr );
613 mFloatingWidget->setAnchorWidget(
this );
616 mFloatingWidget->hide();
617 connect(
this, &QgsTaskManagerStatusBarWidget::clicked,
this, &QgsTaskManagerStatusBarWidget::toggleDisplay );
629 QSize QgsTaskManagerStatusBarWidget::sizeHint()
const
632 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
635 int width =
static_cast< int >( fontMetrics().horizontalAdvance(
'X' ) * 20 *
Qgis::UI_SCALE_FACTOR );
637 int height = QToolButton::sizeHint().height();
638 return QSize( width, height );
641 void QgsTaskManagerStatusBarWidget::changeEvent( QEvent *event )
643 QToolButton::changeEvent( event );
645 if ( event->type() == QEvent::FontChange )
647 mProgressBar->setFont( font() );
651 void QgsTaskManagerStatusBarWidget::toggleDisplay()
653 if ( mFloatingWidget->isVisible() )
654 mFloatingWidget->hide();
657 mFloatingWidget->show();
658 mFloatingWidget->raise();
662 void QgsTaskManagerStatusBarWidget::overallProgressChanged(
double progress )
664 mProgressBar->setValue(
static_cast< int >( std::round( progress ) ) );
666 mProgressBar->setMaximum( 0 );
667 else if ( mProgressBar->maximum() == 0 )
668 mProgressBar->setMaximum( 100 );
669 setToolTip( QgsTaskManagerModel::createTooltip( mManager->activeTasks().at( 0 ), QgsTaskManagerModel::ToolTipDescription ) );
672 void QgsTaskManagerStatusBarWidget::countActiveTasksChanged(
int count )
676 mProgressBar->setMaximum( 0 );
677 setToolTip( tr(
"%1 active tasks running" ).arg( count ) );
681 void QgsTaskManagerStatusBarWidget::allFinished()
683 mFloatingWidget->hide();
686 mProgressBar->setMaximum( 0 );
687 mProgressBar->setValue( 0 );
690 void QgsTaskManagerStatusBarWidget::showButton()
694 mProgressBar->setMaximum( 0 );
695 mProgressBar->setValue( 0 );