22 #include <QMouseEvent>
26 #include <QProgressBar>
28 #include <QHeaderView>
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 );
50 const int progressColWidth =
static_cast< int >( fontMetrics().horizontalAdvance(
'X' ) * 10 *
Qgis::UI_SCALE_FACTOR );
51 mTreeView->setColumnWidth( QgsTaskManagerModel::Progress, progressColWidth );
53 const int statusColWidth =
static_cast< int >( fontMetrics().horizontalAdvance(
'X' ) * 2 *
Qgis::UI_SCALE_FACTOR );
54 mTreeView->setColumnWidth( QgsTaskManagerModel::Status, statusColWidth );
55 mTreeView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
56 mTreeView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
57 mTreeView->header()->setStretchLastSection(
false );
58 mTreeView->header()->setSectionResizeMode( QgsTaskManagerModel::Description, QHeaderView::Stretch );
60 connect( mTreeView, &QTreeView::clicked,
this, &QgsTaskManagerWidget::clicked );
62 vLayout->addWidget( mTreeView );
73 void QgsTaskManagerWidget::modelRowsInserted(
const QModelIndex &,
int start,
int end )
75 for (
int row = start; row <= end; ++row )
77 QgsTask *task = mModel->indexToTask( mModel->index( row, 1 ) );
81 QProgressBar *progressBar =
new QProgressBar();
82 progressBar->setAutoFillBackground(
true );
83 progressBar->setRange( 0, 0 );
89 progressBar->setMaximum( 100 );
90 progressBar->setValue(
static_cast< int >( std::round( progress ) ) );
93 progressBar->setMaximum( 0 );
96 mTreeView->setIndexWidget( mModel->index( row, QgsTaskManagerModel::Progress ), progressBar );
98 QgsTaskStatusWidget *statusWidget =
new QgsTaskStatusWidget(
nullptr, task->
status(), task->
canCancel() );
99 statusWidget->setAutoFillBackground(
true );
101 connect( statusWidget, &QgsTaskStatusWidget::cancelClicked, task, &
QgsTask::cancel );
102 mTreeView->setIndexWidget( mModel->index( row, QgsTaskManagerModel::Status ), statusWidget );
106 void QgsTaskManagerWidget::clicked(
const QModelIndex &index )
108 QgsTask *task = mModel->indexToTask( index );
120 QgsTaskManagerModel::QgsTaskManagerModel(
QgsTaskManager *manager, QObject *parent )
121 : QAbstractItemModel( parent )
122 , mManager( manager )
124 Q_ASSERT( mManager );
127 const auto constTasks = mManager->
tasks();
128 for (
QgsTask *task : constTasks )
130 mRowToTaskIdList << mManager->
taskId( task );
138 QModelIndex QgsTaskManagerModel::index(
int row,
int column,
const QModelIndex &parent )
const
140 if ( column < 0 || column >= columnCount() )
143 return QModelIndex();
146 if ( !parent.isValid() && row >= 0 && row < mRowToTaskIdList.count() )
149 return createIndex( row, column );
153 return QModelIndex();
157 QModelIndex QgsTaskManagerModel::parent(
const QModelIndex &index )
const
162 return QModelIndex();
165 int QgsTaskManagerModel::rowCount(
const QModelIndex &parent )
const
167 if ( !parent.isValid() )
169 return mRowToTaskIdList.count();
178 int QgsTaskManagerModel::columnCount(
const QModelIndex &parent )
const
184 QVariant QgsTaskManagerModel::data(
const QModelIndex &index,
int role )
const
186 if ( !index.isValid() )
189 QgsTask *task = indexToTask( index );
194 case Qt::DisplayRole:
196 switch ( index.column() )
210 return static_cast<int>( task->
status() );
212 case Qt::ToolTipRole:
213 switch ( index.column() )
216 return createTooltip( task, ToolTipDescription );
218 return createTooltip( task, ToolTipProgress );
220 return createTooltip( task, ToolTipStatus );
234 Qt::ItemFlags QgsTaskManagerModel::flags(
const QModelIndex &index )
const
236 Qt::ItemFlags flags = QAbstractItemModel::flags( index );
238 if ( ! index.isValid() )
243 QgsTask *task = indexToTask( index );
244 if ( index.column() == Status )
247 flags = flags | Qt::ItemIsEditable;
249 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
252 bool QgsTaskManagerModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
256 if ( !index.isValid() )
259 QgsTask *task = indexToTask( index );
263 switch ( index.column() )
267 if ( value.toBool() && task->
canCancel() )
277 void QgsTaskManagerModel::taskAdded(
long id )
279 beginInsertRows( QModelIndex(), mRowToTaskIdList.count(),
280 mRowToTaskIdList.count() );
281 mRowToTaskIdList << id;
285 void QgsTaskManagerModel::taskDeleted(
long id )
287 for (
int row = 0; row < mRowToTaskIdList.count(); ++row )
289 if ( mRowToTaskIdList.at( row ) ==
id )
291 beginRemoveRows( QModelIndex(), row, row );
292 mRowToTaskIdList.removeAt( row );
299 void QgsTaskManagerModel::progressChanged(
long id,
double progress )
303 const QModelIndex index = idToIndex(
id, Progress );
304 if ( !index.isValid() )
309 emit dataChanged( index, index );
312 void QgsTaskManagerModel::statusChanged(
long id,
int status )
320 const QModelIndex index = idToIndex(
id, Status );
321 if ( !index.isValid() )
326 emit dataChanged( index, index );
330 QgsTask *QgsTaskManagerModel::indexToTask(
const QModelIndex &index )
const
332 if ( !index.isValid() || index.parent().isValid() )
335 const long id = index.row() >= 0 && index.row() < mRowToTaskIdList.count() ? mRowToTaskIdList.at( index.row() ) : -1;
337 return mManager->task(
id );
342 int QgsTaskManagerModel::idToRow(
long id )
const
344 for (
int row = 0; row < mRowToTaskIdList.count(); ++row )
346 if ( mRowToTaskIdList.at( row ) ==
id )
354 QModelIndex QgsTaskManagerModel::idToIndex(
long id,
int column )
const
356 const int row = idToRow(
id );
358 return QModelIndex();
360 return index( row, column );
363 QString QgsTaskManagerModel::createTooltip(
QgsTask *task, ToolTipType type )
369 case ToolTipDescription:
373 case ToolTipProgress:
378 return tr(
"Queued" );
380 return tr(
"On hold" );
383 if ( type == ToolTipStatus && !task->
canCancel() )
384 return tr(
"Running (cannot cancel)" );
386 return tr(
"Running" );
389 return tr(
"Complete" );
391 return tr(
"Terminated" );
397 QString formattedTime;
404 const qint64 msRemain =
static_cast< qint64
>( elapsed * 100.0 / task->
progress() - elapsed );
405 if ( msRemain > 120 * 1000 )
407 const long long minutes = msRemain / 1000 / 60;
408 const int seconds = ( msRemain / 1000 ) % 60;
409 formattedTime = tr(
"%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar(
'0' ) );
412 formattedTime = tr(
"%1 seconds" ).arg( msRemain / 1000 );
414 formattedTime = tr(
"Estimated time remaining: %1" ).arg( formattedTime );
416 const QTime estimatedEnd = QTime::currentTime().addMSecs( msRemain );
417 formattedTime += tr(
" (%1)" ).arg( QLocale::system().toString( estimatedEnd, QLocale::ShortFormat ) );
421 if ( elapsed > 120 * 1000 )
423 const long long minutes = elapsed / 1000 / 60;
424 const int seconds = ( elapsed / 1000 ) % 60;
425 formattedTime = tr(
"%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar(
'0' ) );
428 formattedTime = tr(
"%1 seconds" ).arg( elapsed / 1000 );
430 formattedTime = tr(
"Time elapsed: %1" ).arg( formattedTime );
435 case ToolTipDescription:
436 return tr(
"%1<br>%2" ).arg( task->
description(), formattedTime );
439 case ToolTipProgress:
444 return tr(
"Queued" );
446 return tr(
"On hold" );
450 if ( type == ToolTipStatus && !task->
canCancel() )
451 statusDesc = tr(
"Running (cannot cancel)" );
453 statusDesc = tr(
"Running" );
454 return tr(
"%1<br>%2" ).arg( statusDesc, formattedTime );
457 return tr(
"Complete" );
459 return tr(
"Terminated" );
472 QgsTaskStatusWidget::QgsTaskStatusWidget( QWidget *parent,
QgsTask::TaskStatus status,
bool canCancel )
474 , mCanCancel( canCancel )
477 setMouseTracking(
true );
480 QSize QgsTaskStatusWidget::sizeHint()
const
482 return QSize( 32, 32 );
485 void QgsTaskStatusWidget::setStatus(
int status )
491 void QgsTaskStatusWidget::paintEvent( QPaintEvent *e )
493 QWidget::paintEvent( e );
523 icon.paint( &p, 1, height() / 2 - 12, 24, 24 );
527 void QgsTaskStatusWidget::mousePressEvent( QMouseEvent * )
530 emit cancelClicked();
533 void QgsTaskStatusWidget::mouseMoveEvent( QMouseEvent * )
542 void QgsTaskStatusWidget::leaveEvent( QEvent * )
571 QgsTaskManagerFloatingWidget::QgsTaskManagerFloatingWidget(
QgsTaskManager *manager, QWidget *parent )
574 setLayout(
new QVBoxLayout() );
577 const int minWidth =
static_cast< int >( fontMetrics().horizontalAdvance(
'X' ) * 60 *
Qgis::UI_SCALE_FACTOR );
579 setMinimumSize( minWidth, minHeight );
580 layout()->addWidget( w );
581 setStyleSheet(
".QgsTaskManagerFloatingWidget { border-top-left-radius: 8px;"
582 "border-top-right-radius: 8px; background-color: rgba(0, 0, 0, 70%); }" );
586 QgsTaskManagerStatusBarWidget::QgsTaskManagerStatusBarWidget(
QgsTaskManager *manager, QWidget *parent )
587 : QToolButton( parent )
588 , mManager( manager )
590 setAutoRaise(
true );
591 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::MinimumExpanding );
592 setLayout(
new QVBoxLayout() );
594 mProgressBar =
new QProgressBar();
595 mProgressBar->setMinimum( 0 );
596 mProgressBar->setMaximum( 0 );
597 layout()->setContentsMargins( 5, 5, 5, 5 );
598 layout()->addWidget( mProgressBar );
600 mFloatingWidget =
new QgsTaskManagerFloatingWidget( manager, parent ? parent->window() :
nullptr );
601 mFloatingWidget->setAnchorWidget(
this );
604 mFloatingWidget->hide();
605 connect(
this, &QgsTaskManagerStatusBarWidget::clicked,
this, &QgsTaskManagerStatusBarWidget::toggleDisplay );
617 QSize QgsTaskManagerStatusBarWidget::sizeHint()
const
619 const int width =
static_cast< int >( fontMetrics().horizontalAdvance(
'X' ) * 20 *
Qgis::UI_SCALE_FACTOR );
620 const int height = QToolButton::sizeHint().height();
621 return QSize( width, height );
624 void QgsTaskManagerStatusBarWidget::changeEvent( QEvent *event )
626 QToolButton::changeEvent( event );
628 if ( event->type() == QEvent::FontChange )
630 mProgressBar->setFont( font() );
634 void QgsTaskManagerStatusBarWidget::toggleDisplay()
636 if ( mFloatingWidget->isVisible() )
637 mFloatingWidget->hide();
640 mFloatingWidget->show();
641 mFloatingWidget->raise();
645 void QgsTaskManagerStatusBarWidget::overallProgressChanged(
double progress )
647 mProgressBar->setValue(
static_cast< int >( std::round( progress ) ) );
649 mProgressBar->setMaximum( 0 );
650 else if ( mProgressBar->maximum() == 0 )
651 mProgressBar->setMaximum( 100 );
652 setToolTip( QgsTaskManagerModel::createTooltip( mManager->activeTasks().at( 0 ), QgsTaskManagerModel::ToolTipDescription ) );
655 void QgsTaskManagerStatusBarWidget::countActiveTasksChanged(
int count )
659 mProgressBar->setMaximum( 0 );
660 setToolTip( tr(
"%n active task(s) running",
nullptr, count ) );
664 void QgsTaskManagerStatusBarWidget::allFinished()
666 mFloatingWidget->hide();
669 mProgressBar->setMaximum( 0 );
670 mProgressBar->setValue( 0 );
673 void QgsTaskManagerStatusBarWidget::showButton()
677 mProgressBar->setMaximum( 0 );
678 mProgressBar->setValue( 0 );