Skip to content
Permalink
Browse files

[tasks] Show estimated time remaining and completion time in status bar

task manager widget

Calculated using a simple linear interpolation based on the elapsed
time and current progress
  • Loading branch information
nyalldawson committed Aug 6, 2018
1 parent e51fed4 commit 87000377253493fb08295853a0cbb1b11afc85e2
@@ -91,6 +91,15 @@ Returns the task's description.
double progress() const;
%Docstring
Returns the task's progress (between 0.0 and 100.0)
%End

qint64 elapsedTime() const;
%Docstring
Returns the elapsed time since the task commenced, in milliseconds.

The value is undefined for tasks which have not begun.

.. versionadded:: 3.4
%End

virtual void cancel();
@@ -41,6 +41,11 @@ QgsTask::~QgsTask()
}
}

qint64 QgsTask::elapsedTime() const
{
return mElapsedTime.elapsed();
}

void QgsTask::start()
{
mNotFinishedMutex.lock();
@@ -52,6 +57,8 @@ void QgsTask::start()

mStatus = Running;
mOverallStatus = Running;
mElapsedTime.start();

emit statusChanged( Running );
emit begun();

@@ -114,6 +114,15 @@ class CORE_EXPORT QgsTask : public QObject
*/
double progress() const { return mTotalProgress; }

/**
* Returns the elapsed time since the task commenced, in milliseconds.
*
* The value is undefined for tasks which have not begun.
*
* \since QGIS 3.4
*/
qint64 elapsedTime() const;

/**
* Notifies the task that it should terminate. Calling this is not guaranteed
* to immediately end the task, rather it sets the isCanceled() flag which
@@ -320,6 +329,8 @@ class CORE_EXPORT QgsTask : public QObject

QgsWeakMapLayerPointerList mDependentLayers;

QElapsedTimer mElapsedTime;


/**
* Starts the task. Should not be public as only QgsTaskManagers can initiate tasks.
@@ -210,30 +210,11 @@ QVariant QgsTaskManagerModel::data( const QModelIndex &index, int role ) const
switch ( index.column() )
{
case Description:
return task->description();
return createTooltip( task, ToolTipDescription );
case Progress:
return createTooltip( task, ToolTipProgress );
case Status:
{
switch ( task->status() )
{
case QgsTask::Queued:
return tr( "Queued" );
case QgsTask::OnHold:
return tr( "On hold" );
case QgsTask::Running:
{
if ( index.column() == Status && !task->canCancel() )
return tr( "Running (cannot cancel)" );
else
return tr( "Running" );
}
case QgsTask::Complete:
return tr( "Complete" );
case QgsTask::Terminated:
return tr( "Terminated" );
}
return QVariant();
}
return createTooltip( task, ToolTipStatus );
default:
return QVariant();
}
@@ -376,6 +357,110 @@ QModelIndex QgsTaskManagerModel::idToIndex( long id, int column ) const
return index( row, column );
}

QString QgsTaskManagerModel::createTooltip( QgsTask *task, ToolTipType type )
{
if ( task->status() != QgsTask::Running )
{
switch ( type )
{
case ToolTipDescription:
return task->description();

case ToolTipStatus:
case ToolTipProgress:
{
switch ( task->status() )
{
case QgsTask::Queued:
return tr( "Queued" );
case QgsTask::OnHold:
return tr( "On hold" );
case QgsTask::Running:
{
if ( type == ToolTipStatus && !task->canCancel() )
return tr( "Running (cannot cancel)" );
else
return tr( "Running" );
}
case QgsTask::Complete:
return tr( "Complete" );
case QgsTask::Terminated:
return tr( "Terminated" );
}
}
}
}

QString formattedTime;

qint64 elapsed = task->elapsedTime();

if ( task->progress() > 0 )
{
// estimate time remaining
qint64 msRemain = static_cast< qint64 >( elapsed * 100.0 / task->progress() - elapsed );
if ( msRemain > 120 * 1000 )
{
long long minutes = msRemain / 1000 / 60;
int seconds = ( msRemain / 1000 ) % 60;
formattedTime = tr( "%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar( '0' ) );
}
else
formattedTime = tr( "%1 seconds" ).arg( msRemain / 1000 );

formattedTime = tr( "Estimated time remaining: %1" ).arg( formattedTime );

QTime estimatedEnd = QTime::currentTime().addMSecs( msRemain );
formattedTime += tr( " (%1)" ).arg( QLocale::system().toString( estimatedEnd, QLocale::ShortFormat ) );
}
else
{
if ( elapsed > 120 * 1000 )
{
long long minutes = elapsed / 1000 / 60;
int seconds = ( elapsed / 1000 ) % 60;
formattedTime = tr( "%1:%2 minutes" ).arg( minutes ).arg( seconds, 2, 10, QChar( '0' ) );
}
else
formattedTime = tr( "%1 seconds" ).arg( elapsed / 1000 );

formattedTime = tr( "Time elapsed: %1" ).arg( formattedTime );
}

switch ( type )
{
case ToolTipDescription:
return tr( "%1<br>%2" ).arg( task->description(), formattedTime );

case ToolTipStatus:
case ToolTipProgress:
{
switch ( task->status() )
{
case QgsTask::Queued:
return tr( "Queued" );
case QgsTask::OnHold:
return tr( "On hold" );
case QgsTask::Running:
{
QString statusDesc;
if ( type == ToolTipStatus && !task->canCancel() )
statusDesc = tr( "Running (cannot cancel)" );
else
statusDesc = tr( "Running" );
return tr( "%1<br>%2" ).arg( statusDesc, formattedTime );
}
case QgsTask::Complete:
return tr( "Complete" );
case QgsTask::Terminated:
return tr( "Terminated" );
}
}
}
// no warnings
return QString();
}


//
// QgsTaskStatusDelegate
@@ -547,7 +632,7 @@ void QgsTaskManagerStatusBarWidget::overallProgressChanged( double progress )
mProgressBar->setMaximum( 0 );
else if ( mProgressBar->maximum() == 0 )
mProgressBar->setMaximum( 100 );
setToolTip( mManager->activeTasks().at( 0 )->description() );
setToolTip( QgsTaskManagerModel::createTooltip( mManager->activeTasks().at( 0 ), QgsTaskManagerModel::ToolTipDescription ) );
}

void QgsTaskManagerStatusBarWidget::countActiveTasksChanged( int count )
@@ -185,13 +185,23 @@ class GUI_EXPORT QgsTaskManagerModel: public QAbstractItemModel

private:

enum ToolTipType
{
ToolTipDescription,
ToolTipStatus,
ToolTipProgress,
};

QgsTaskManager *mManager = nullptr;

QList< long > mRowToTaskIdList;


int idToRow( long id ) const;
QModelIndex idToIndex( long id, int column ) const;
static QString createTooltip( QgsTask *task, ToolTipType type );

friend class QgsTaskManagerStatusBarWidget;
};

/**

0 comments on commit 8700037

Please sign in to comment.
You can’t perform that action at this time.