Skip to content

Commit

Permalink
Merge pull request #5235 from nyalldawson/model_progress2
Browse files Browse the repository at this point in the history
[processing] Proper progress reports during model execution
  • Loading branch information
nyalldawson committed Sep 22, 2017
2 parents 5599737 + 33d2d11 commit cf636dc
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 20 deletions.
2 changes: 1 addition & 1 deletion python/core/core_auto.sip
Expand Up @@ -176,7 +176,6 @@
%Include processing/qgsprocessingoutputs.sip
%Include processing/qgsprocessingparameters.sip
%Include processing/qgsprocessingutils.sip
%Include processing/models/qgsprocessingmodelalgorithm.sip
%Include processing/models/qgsprocessingmodelchildalgorithm.sip
%Include processing/models/qgsprocessingmodelchildparametersource.sip
%Include processing/models/qgsprocessingmodelcomponent.sip
Expand Down Expand Up @@ -384,6 +383,7 @@
%Include processing/qgsprocessingfeedback.sip
%Include processing/qgsprocessingprovider.sip
%Include processing/qgsprocessingregistry.sip
%Include processing/models/qgsprocessingmodelalgorithm.sip
%Include raster/qgsrasterfilewritertask.sip
%Include raster/qgsrasterlayer.sip
%Include raster/qgsrasterdataprovider.sip
Expand Down
2 changes: 2 additions & 0 deletions python/core/processing/models/qgsprocessingmodelalgorithm.sip
Expand Up @@ -374,6 +374,8 @@ Translated description of variable
};




/************************************************************************
* This file has been generated automatically from *
* *
Expand Down
12 changes: 7 additions & 5 deletions python/core/qgsfeedback.sip
Expand Up @@ -38,11 +38,6 @@ class QgsFeedback : QObject
QgsFeedback( QObject *parent /TransferThis/ = 0 );
%Docstring
Construct a feedback object
%End

void cancel();
%Docstring
Tells the internal routines that the current operation should be canceled. This should be run by the main thread
%End

bool isCanceled() const;
Expand Down Expand Up @@ -71,6 +66,13 @@ Tells whether the operation has been canceled already
:rtype: float
%End

public slots:

void cancel();
%Docstring
Tells the internal routines that the current operation should be canceled. This should be run by the main thread
%End

signals:
void canceled();
%Docstring
Expand Down
2 changes: 1 addition & 1 deletion src/core/CMakeLists.txt
Expand Up @@ -682,6 +682,7 @@ SET(QGIS_CORE_MOC_HDRS
processing/qgsprocessingfeedback.h
processing/qgsprocessingprovider.h
processing/qgsprocessingregistry.h
processing/models/qgsprocessingmodelalgorithm.h

providers/memory/qgsmemoryprovider.h

Expand Down Expand Up @@ -978,7 +979,6 @@ SET(QGIS_CORE_HDRS
processing/qgsprocessingoutputs.h
processing/qgsprocessingparameters.h
processing/qgsprocessingutils.h
processing/models/qgsprocessingmodelalgorithm.h
processing/models/qgsprocessingmodelchildalgorithm.h
processing/models/qgsprocessingmodelchildparametersource.h
processing/models/qgsprocessingmodelcomponent.h
Expand Down
85 changes: 81 additions & 4 deletions src/core/processing/models/qgsprocessingmodelalgorithm.cpp
Expand Up @@ -214,6 +214,7 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa
QTime totalTime;
totalTime.start();

QgsProcessingModelFeedback modelFeedback( toExecute.count(), feedback );
QgsExpressionContext baseContext = createExpressionContext( parameters, context );

QVariantMap childResults;
Expand All @@ -225,6 +226,9 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa
executedAlg = false;
Q_FOREACH ( const QString &childId, toExecute )
{
if ( feedback && feedback->isCanceled() )
break;

if ( executed.contains( childId ) )
continue;

Expand Down Expand Up @@ -252,15 +256,23 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa

QVariantMap childParams = parametersForChildAlgorithm( child, parameters, childResults, expContext );
feedback->setProgressText( QObject::tr( "Running %1 [%2/%3]" ).arg( child.description() ).arg( executed.count() + 1 ).arg( toExecute.count() ) );
//feedback->pushDebugInfo( "Parameters: " + ', '.join( [str( p ).strip() +
// '=' + str( p.value ) for p in alg.algorithm.parameters] ) )

QStringList params;
for ( auto childParamIt = childParams.constBegin(); childParamIt != childParams.constEnd(); ++childParamIt )
{
params << QStringLiteral( "%1: %2" ).arg( childParamIt.key(),
child.algorithm()->parameterDefinition( childParamIt.key() )->valueAsPythonString( childParamIt.value(), context ) );
}

feedback->pushInfo( QObject::tr( "Input Parameters:" ) );
feedback->pushCommandInfo( QStringLiteral( "{ %1 }" ).arg( params.join( QStringLiteral( ", " ) ) ) );

QTime childTime;
childTime.start();

bool ok = false;
std::unique_ptr< QgsProcessingAlgorithm > childAlg( child.algorithm()->create( child.configuration() ) );
QVariantMap results = childAlg->run( childParams, context, feedback, &ok );
QVariantMap results = childAlg->run( childParams, context, &modelFeedback, &ok );
childAlg.reset( nullptr );
if ( !ok )
{
Expand All @@ -280,8 +292,12 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa
}

executed.insert( childId );
feedback->pushDebugInfo( QObject::tr( "OK. Execution took %1 s (%2 outputs)." ).arg( childTime.elapsed() / 1000.0 ).arg( results.count() ) );
modelFeedback.setCurrentStep( executed.count() );
feedback->pushInfo( QObject::tr( "OK. Execution took %1 s (%2 outputs)." ).arg( childTime.elapsed() / 1000.0 ).arg( results.count() ) );
}

if ( feedback && feedback->isCanceled() )
break;
}
feedback->pushDebugInfo( QObject::tr( "Model processed OK. Executed %1 algorithms total in %2 s." ).arg( executed.count() ).arg( totalTime.elapsed() / 1000.0 ) );

Expand Down Expand Up @@ -1123,4 +1139,65 @@ QgsProcessingAlgorithm *QgsProcessingModelAlgorithm::createInstance() const
return alg;
}




//
// QgsProcessingModelFeedback
//

QgsProcessingModelFeedback::QgsProcessingModelFeedback( int childAlgorithmCount, QgsProcessingFeedback *feedback )
: mChildSteps( childAlgorithmCount )
, mFeedback( feedback )
{
connect( mFeedback, &QgsFeedback::canceled, this, &QgsFeedback::cancel, Qt::DirectConnection );
connect( this, &QgsFeedback::progressChanged, this, &QgsProcessingModelFeedback::updateOverallProgress );
}

void QgsProcessingModelFeedback::setCurrentStep( int step )
{
mCurrentStep = step;
mFeedback->setProgress( 100.0 * static_cast< double >( mCurrentStep ) / mChildSteps );
}

void QgsProcessingModelFeedback::setProgressText( const QString &text )
{
mFeedback->setProgressText( text );
}

void QgsProcessingModelFeedback::reportError( const QString &error )
{
mFeedback->reportError( error );
}

void QgsProcessingModelFeedback::pushInfo( const QString &info )
{
mFeedback->pushInfo( info );
}

void QgsProcessingModelFeedback::pushCommandInfo( const QString &info )
{
mFeedback->pushCommandInfo( info );
}

void QgsProcessingModelFeedback::pushDebugInfo( const QString &info )
{
mFeedback->pushDebugInfo( info );
}

void QgsProcessingModelFeedback::pushConsoleInfo( const QString &info )
{
mFeedback->pushConsoleInfo( info );
}

void QgsProcessingModelFeedback::updateOverallProgress( double progress )
{
double baseProgress = 100.0 * static_cast< double >( mCurrentStep ) / mChildSteps;
double currentAlgorithmProgress = progress / mChildSteps;
mFeedback->setProgress( baseProgress + currentAlgorithmProgress );
}



///@endcond

47 changes: 47 additions & 0 deletions src/core/processing/models/qgsprocessingmodelalgorithm.h
Expand Up @@ -403,6 +403,53 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
friend class TestQgsProcessing;
};


#ifndef SIP_RUN

/**
* Model algorithm feedback which proxies its calls to an underlying
* feedback object, but scales overall progress reports to account
* for the number of child steps in a model.
*/
class QgsProcessingModelFeedback : public QgsProcessingFeedback
{
Q_OBJECT

public:

/**
* Constructor for QgsProcessingModelFeedback, for a model with the specified
* number of active child algorithms. This feedback object will proxy calls
* to the specified \a feedback object.
*/
QgsProcessingModelFeedback( int childAlgorithmCount, QgsProcessingFeedback *feedback );

/**
* Sets the current child algorithm \a step which is being executed. This is used
* to scale the overall progress to account for progress through the overall model.
*/
void setCurrentStep( int step );

void setProgressText( const QString &text ) override;
void reportError( const QString &error ) override;
void pushInfo( const QString &info ) override;
void pushCommandInfo( const QString &info ) override;
void pushDebugInfo( const QString &info ) override;
void pushConsoleInfo( const QString &info ) override;

private slots:

void updateOverallProgress( double progress );

private:

int mChildSteps = 0;
int mCurrentStep = 0;
QgsProcessingFeedback *mFeedback = nullptr;
};

#endif

///@endcond

#endif // QGSPROCESSINGMODELALGORITHM_H
20 changes: 11 additions & 9 deletions src/core/qgsfeedback.h
Expand Up @@ -50,15 +50,6 @@ class CORE_EXPORT QgsFeedback : public QObject
, mCanceled( false )
{}

//! Tells the internal routines that the current operation should be canceled. This should be run by the main thread
void cancel()
{
if ( mCanceled )
return; // only emit the signal once
mCanceled = true;
emit canceled();
}

//! Tells whether the operation has been canceled already
bool isCanceled() const { return mCanceled; }

Expand Down Expand Up @@ -88,6 +79,17 @@ class CORE_EXPORT QgsFeedback : public QObject
*/
double progress() const { return mProgress; }

public slots:

//! Tells the internal routines that the current operation should be canceled. This should be run by the main thread
void cancel()
{
if ( mCanceled )
return; // only emit the signal once
mCanceled = true;
emit canceled();
}

signals:
//! Internal routines can connect to this signal if they use event loop
void canceled();
Expand Down

0 comments on commit cf636dc

Please sign in to comment.