From 8302259463e14ee0b5e32711b673281e23690025 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 19 Apr 2024 09:59:54 +1000 Subject: [PATCH] Make child results handling API more flexible --- CMakeLists.txt | 2 +- .../processing/qgsprocessingcontext.sip.in | 64 ++++++++++--- .../qgsmodelcomponentgraphicitem.sip.in | 9 +- .../models/qgsmodeldesignerdialog.sip.in | 9 +- .../models/qgsmodelgraphicsscene.sip.in | 9 +- .../processing/qgsprocessingcontext.sip.in | 64 ++++++++++--- .../qgsmodelcomponentgraphicitem.sip.in | 9 +- .../models/qgsmodeldesignerdialog.sip.in | 9 +- .../models/qgsmodelgraphicsscene.sip.in | 9 +- .../models/qgsprocessingmodelalgorithm.cpp | 23 +++-- src/core/processing/qgsprocessingcontext.cpp | 14 ++- src/core/processing/qgsprocessingcontext.h | 89 ++++++++++++++----- .../models/qgsmodelcomponentgraphicitem.cpp | 24 ++--- .../models/qgsmodelcomponentgraphicitem.h | 13 +-- .../models/qgsmodeldesignerdialog.cpp | 21 ++--- .../models/qgsmodeldesignerdialog.h | 12 +-- .../models/qgsmodelgraphicsscene.cpp | 20 +---- .../processing/models/qgsmodelgraphicsscene.h | 12 +-- tests/src/analysis/testqgsprocessing.cpp | 32 ++++--- .../testqgsprocessingmodelalgorithm.cpp | 6 +- 20 files changed, 261 insertions(+), 189 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e69f5558320..e6f1278f7bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1102,7 +1102,7 @@ if (WITH_CORE AND WITH_BINDINGS) include(SIPMacros) set(SIP_INCLUDES ${PYQT_SIP_DIR} ${CMAKE_SOURCE_DIR}/python) - set(SIP_CONCAT_PARTS 25) + set(SIP_CONCAT_PARTS 26) if (NOT BINDINGS_GLOBAL_INSTALL) set(Python_SITEARCH ${QGIS_DATA_DIR}/python) diff --git a/python/PyQt6/core/auto_generated/processing/qgsprocessingcontext.sip.in b/python/PyQt6/core/auto_generated/processing/qgsprocessingcontext.sip.in index 382ddb07018..340299fd85e 100644 --- a/python/PyQt6/core/auto_generated/processing/qgsprocessingcontext.sip.in +++ b/python/PyQt6/core/auto_generated/processing/qgsprocessingcontext.sip.in @@ -12,6 +12,55 @@ +class QgsProcessingModelChildAlgorithmResult +{ +%Docstring(signature="appended") +Encapsulates the results of running a child algorithm within a model + +.. versionadded:: 3.38 +%End + +%TypeHeaderCode +#include "qgsprocessingcontext.h" +%End + public: + + QgsProcessingModelChildAlgorithmResult(); + + QVariantMap inputs() const; +%Docstring +Returns the inputs used for the child algorithm. + +.. seealso:: :py:func:`setInputs` +%End + + void setInputs( const QVariantMap &inputs ); +%Docstring +Sets the ``inputs`` used for the child algorithm. + +.. seealso:: :py:func:`inputs` +%End + + QVariantMap outputs() const; +%Docstring +Returns the outputs generated by the child algorithm. + +.. seealso:: :py:func:`setOutputs` +%End + + void setOutputs( const QVariantMap &outputs ); +%Docstring +Sets the ``outputs`` used for the child algorithm. + +.. seealso:: :py:func:`outputs` +%End + + bool operator==( const QgsProcessingModelChildAlgorithmResult &other ) const; + bool operator!=( const QgsProcessingModelChildAlgorithmResult &other ) const; + +}; + + class QgsProcessingContext { @@ -658,24 +707,15 @@ Returns list of the equivalent qgis_process arguments representing the settings .. versionadded:: 3.24 %End - QVariantMap modelChildResults() const; + QMap< QString, QgsProcessingModelChildAlgorithmResult > modelChildResults() const; %Docstring Returns the map of child algorithm results, populated when the context is used to run a model algorithm. +Map keys refer to the child algorithm IDs. + .. seealso:: :py:func:`modelChildInputs` -.. versionadded:: 3.38 -%End - - - QVariantMap modelChildInputs() const; -%Docstring -Returns the map of child algorithm inputs, populated when the context is used -to run a model algorithm. - -.. seealso:: :py:func:`modelChildResults` - .. versionadded:: 3.38 %End diff --git a/python/PyQt6/gui/auto_generated/processing/models/qgsmodelcomponentgraphicitem.sip.in b/python/PyQt6/gui/auto_generated/processing/models/qgsmodelcomponentgraphicitem.sip.in index e58f4674f61..e8265886976 100644 --- a/python/PyQt6/gui/auto_generated/processing/models/qgsmodelcomponentgraphicitem.sip.in +++ b/python/PyQt6/gui/auto_generated/processing/models/qgsmodelcomponentgraphicitem.sip.in @@ -396,14 +396,9 @@ Ownership of ``child`` is transferred to the item. virtual bool canDeleteComponent(); - void setResults( const QVariantMap &results ); + void setResults( const QgsProcessingModelChildAlgorithmResult &results ); %Docstring -Sets the results obtained for this child algorithm for the last model execution through the dialog. -%End - - void setInputs( const QVariantMap &inputs ); -%Docstring -Sets the inputs used for this child algorithm for the last model execution through the dialog. +Sets the ``results`` obtained for this child algorithm for the last model execution through the dialog. %End signals: diff --git a/python/PyQt6/gui/auto_generated/processing/models/qgsmodeldesignerdialog.sip.in b/python/PyQt6/gui/auto_generated/processing/models/qgsmodeldesignerdialog.sip.in index 89d56d3ece8..75523aabd4a 100644 --- a/python/PyQt6/gui/auto_generated/processing/models/qgsmodeldesignerdialog.sip.in +++ b/python/PyQt6/gui/auto_generated/processing/models/qgsmodeldesignerdialog.sip.in @@ -117,14 +117,9 @@ Checks if there are unsaved changes in the model, and if so, prompts the user to Returns ``False`` if the cancel option was selected %End - void setLastRunChildAlgorithmResults( const QVariantMap &results ); + void setLastRunChildAlgorithmResults( const QMap< QString, QgsProcessingModelChildAlgorithmResult > &results ); %Docstring -Sets the results of child algorithms for the last run of the model through the designer window. -%End - - void setLastRunChildAlgorithmInputs( const QVariantMap &inputs ); -%Docstring -Sets the inputs for child algorithms for the last run of the model through the designer window. +Sets the ``results`` of child algorithms for the last run of the model through the designer window. %End void setModelName( const QString &name ); diff --git a/python/PyQt6/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in b/python/PyQt6/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in index aa6648a85e1..b97e646a511 100644 --- a/python/PyQt6/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in +++ b/python/PyQt6/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in @@ -124,14 +124,9 @@ not correctly emit signals to allow the scene's model to update. Clears any selected items and sets ``item`` as the current selection. %End - void setChildAlgorithmResults( const QVariantMap &results ); + void setLastRunChildAlgorithmResults( const QMap< QString, QgsProcessingModelChildAlgorithmResult > &results ); %Docstring -Sets the results for child algorithms for the last model execution. -%End - - void setChildAlgorithmInputs( const QVariantMap &inputs ); -%Docstring -Sets the inputs for child algorithms for the last model execution. +Sets the ``results`` of child algorithms for the last run of the model through the designer window. %End QgsMessageBar *messageBar() const; diff --git a/python/core/auto_generated/processing/qgsprocessingcontext.sip.in b/python/core/auto_generated/processing/qgsprocessingcontext.sip.in index 358f4d3cfdb..ff37951de8c 100644 --- a/python/core/auto_generated/processing/qgsprocessingcontext.sip.in +++ b/python/core/auto_generated/processing/qgsprocessingcontext.sip.in @@ -12,6 +12,55 @@ +class QgsProcessingModelChildAlgorithmResult +{ +%Docstring(signature="appended") +Encapsulates the results of running a child algorithm within a model + +.. versionadded:: 3.38 +%End + +%TypeHeaderCode +#include "qgsprocessingcontext.h" +%End + public: + + QgsProcessingModelChildAlgorithmResult(); + + QVariantMap inputs() const; +%Docstring +Returns the inputs used for the child algorithm. + +.. seealso:: :py:func:`setInputs` +%End + + void setInputs( const QVariantMap &inputs ); +%Docstring +Sets the ``inputs`` used for the child algorithm. + +.. seealso:: :py:func:`inputs` +%End + + QVariantMap outputs() const; +%Docstring +Returns the outputs generated by the child algorithm. + +.. seealso:: :py:func:`setOutputs` +%End + + void setOutputs( const QVariantMap &outputs ); +%Docstring +Sets the ``outputs`` used for the child algorithm. + +.. seealso:: :py:func:`outputs` +%End + + bool operator==( const QgsProcessingModelChildAlgorithmResult &other ) const; + bool operator!=( const QgsProcessingModelChildAlgorithmResult &other ) const; + +}; + + class QgsProcessingContext { @@ -658,24 +707,15 @@ Returns list of the equivalent qgis_process arguments representing the settings .. versionadded:: 3.24 %End - QVariantMap modelChildResults() const; + QMap< QString, QgsProcessingModelChildAlgorithmResult > modelChildResults() const; %Docstring Returns the map of child algorithm results, populated when the context is used to run a model algorithm. +Map keys refer to the child algorithm IDs. + .. seealso:: :py:func:`modelChildInputs` -.. versionadded:: 3.38 -%End - - - QVariantMap modelChildInputs() const; -%Docstring -Returns the map of child algorithm inputs, populated when the context is used -to run a model algorithm. - -.. seealso:: :py:func:`modelChildResults` - .. versionadded:: 3.38 %End diff --git a/python/gui/auto_generated/processing/models/qgsmodelcomponentgraphicitem.sip.in b/python/gui/auto_generated/processing/models/qgsmodelcomponentgraphicitem.sip.in index ff591ffb348..72a74d0a9ae 100644 --- a/python/gui/auto_generated/processing/models/qgsmodelcomponentgraphicitem.sip.in +++ b/python/gui/auto_generated/processing/models/qgsmodelcomponentgraphicitem.sip.in @@ -396,14 +396,9 @@ Ownership of ``child`` is transferred to the item. virtual bool canDeleteComponent(); - void setResults( const QVariantMap &results ); + void setResults( const QgsProcessingModelChildAlgorithmResult &results ); %Docstring -Sets the results obtained for this child algorithm for the last model execution through the dialog. -%End - - void setInputs( const QVariantMap &inputs ); -%Docstring -Sets the inputs used for this child algorithm for the last model execution through the dialog. +Sets the ``results`` obtained for this child algorithm for the last model execution through the dialog. %End signals: diff --git a/python/gui/auto_generated/processing/models/qgsmodeldesignerdialog.sip.in b/python/gui/auto_generated/processing/models/qgsmodeldesignerdialog.sip.in index 89d56d3ece8..75523aabd4a 100644 --- a/python/gui/auto_generated/processing/models/qgsmodeldesignerdialog.sip.in +++ b/python/gui/auto_generated/processing/models/qgsmodeldesignerdialog.sip.in @@ -117,14 +117,9 @@ Checks if there are unsaved changes in the model, and if so, prompts the user to Returns ``False`` if the cancel option was selected %End - void setLastRunChildAlgorithmResults( const QVariantMap &results ); + void setLastRunChildAlgorithmResults( const QMap< QString, QgsProcessingModelChildAlgorithmResult > &results ); %Docstring -Sets the results of child algorithms for the last run of the model through the designer window. -%End - - void setLastRunChildAlgorithmInputs( const QVariantMap &inputs ); -%Docstring -Sets the inputs for child algorithms for the last run of the model through the designer window. +Sets the ``results`` of child algorithms for the last run of the model through the designer window. %End void setModelName( const QString &name ); diff --git a/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in b/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in index 9e9373749dc..230cd0d7584 100644 --- a/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in +++ b/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in @@ -124,14 +124,9 @@ not correctly emit signals to allow the scene's model to update. Clears any selected items and sets ``item`` as the current selection. %End - void setChildAlgorithmResults( const QVariantMap &results ); + void setLastRunChildAlgorithmResults( const QMap< QString, QgsProcessingModelChildAlgorithmResult > &results ); %Docstring -Sets the results for child algorithms for the last model execution. -%End - - void setChildAlgorithmInputs( const QVariantMap &inputs ); -%Docstring -Sets the inputs for child algorithms for the last model execution. +Sets the ``results`` of child algorithms for the last run of the model through the designer window. %End QgsMessageBar *messageBar() const; diff --git a/src/core/processing/models/qgsprocessingmodelalgorithm.cpp b/src/core/processing/models/qgsprocessingmodelalgorithm.cpp index deae41568dd..dc2dc9809bc 100644 --- a/src/core/processing/models/qgsprocessingmodelalgorithm.cpp +++ b/src/core/processing/models/qgsprocessingmodelalgorithm.cpp @@ -320,6 +320,9 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa QgsProcessingMultiStepFeedback modelFeedback( toExecute.count(), feedback ); QgsExpressionContext baseContext = createExpressionContext( parameters, context ); + QVariantMap childResults; + QVariantMap childInputs; + QVariantMap finalResults; QSet< QString > executed; bool executedAlg = true; @@ -377,18 +380,23 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa QgsExpressionContext expContext = baseContext; expContext << QgsExpressionContextUtils::processingAlgorithmScope( child.algorithm(), parameters, context ) - << createExpressionContextScopeForChildAlgorithm( childId, context, parameters, context.modelChildResults() ); + << createExpressionContextScopeForChildAlgorithm( childId, context, parameters, childResults ); context.setExpressionContext( expContext ); QString error; - QVariantMap childParams = parametersForChildAlgorithm( child, parameters, context.modelChildResults(), expContext, error, &context ); + QVariantMap childParams = parametersForChildAlgorithm( child, parameters, childResults, expContext, error, &context ); if ( !error.isEmpty() ) throw QgsProcessingException( error ); if ( feedback && !skipGenericLogging ) feedback->setProgressText( QObject::tr( "Running %1 [%2/%3]" ).arg( child.description() ).arg( executed.count() + 1 ).arg( toExecute.count() ) ); - context.modelChildInputs().insert( childId, QgsProcessingUtils::removePointerValuesFromMap( childParams ) ); + QgsProcessingModelChildAlgorithmResult childResult; + + const QVariantMap thisChildParams = QgsProcessingUtils::removePointerValuesFromMap( childParams ); + childInputs.insert( childId, thisChildParams ); + childResult.setInputs( thisChildParams ); + QStringList params; for ( auto childParamIt = childParams.constBegin(); childParamIt != childParams.constEnd(); ++childParamIt ) { @@ -508,7 +516,10 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa feedback->pushCommandInfo( QStringLiteral( "{ %1 }" ).arg( formattedOutputs.join( QLatin1String( ", " ) ) ) ); } - context.modelChildResults().insert( childId, results ); + childResults.insert( childId, results ); + childResult.setOutputs( results ); + + context.modelChildResults().insert( childId, childResult ); // look through child alg's outputs to determine whether any of these should be copied // to the final model outputs @@ -617,8 +628,8 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa feedback->pushDebugInfo( QObject::tr( "Model processed OK. Executed %n algorithm(s) total in %1 s.", nullptr, executed.count() ).arg( totalTime.elapsed() / 1000.0 ) ); mResults = finalResults; - mResults.insert( QStringLiteral( "CHILD_RESULTS" ), context.modelChildResults() ); - mResults.insert( QStringLiteral( "CHILD_INPUTS" ), context.modelChildInputs() ); + mResults.insert( QStringLiteral( "CHILD_RESULTS" ), childResults ); + mResults.insert( QStringLiteral( "CHILD_INPUTS" ), childInputs ); return mResults; } diff --git a/src/core/processing/qgsprocessingcontext.cpp b/src/core/processing/qgsprocessingcontext.cpp index 9a6e2365047..c274f3b5c0a 100644 --- a/src/core/processing/qgsprocessingcontext.cpp +++ b/src/core/processing/qgsprocessingcontext.cpp @@ -21,6 +21,17 @@ #include "qgsproviderregistry.h" #include "qgsprocessing.h" +// +// QgsProcessingModelChildResult +// + +QgsProcessingModelChildAlgorithmResult::QgsProcessingModelChildAlgorithmResult() = default; + + +// +// QgsProcessingContext +// + QgsProcessingContext::QgsProcessingContext() : mPreferredVectorFormat( QgsProcessingUtils::defaultVectorExtension() ) , mPreferredRasterFormat( QgsProcessingUtils::defaultRasterExtension() ) @@ -123,7 +134,6 @@ std::function QgsProcessingContext::defaultInvalidG void QgsProcessingContext::takeResultsFrom( QgsProcessingContext &context ) { setLayersToLoadOnCompletion( context.mLayersToLoadOnCompletion ); - mModelChildInputs = context.mModelChildInputs; mModelChildResults = context.mModelChildResults; context.mLayersToLoadOnCompletion.clear(); tempLayerStore.transferLayersFromStore( context.temporaryLayerStore() ); @@ -306,3 +316,5 @@ void QgsProcessingContext::LayerDetails::setOutputLayerName( QgsMapLayer *layer layer->setName( name ); } } + + diff --git a/src/core/processing/qgsprocessingcontext.h b/src/core/processing/qgsprocessingcontext.h index f9a0d938c4a..2dfacc70587 100644 --- a/src/core/processing/qgsprocessingcontext.h +++ b/src/core/processing/qgsprocessingcontext.h @@ -31,6 +31,64 @@ class QgsProcessingLayerPostProcessorInterface; +/** + * \class QgsProcessingModelChildResult + * \ingroup core + * \brief Encapsulates the results of running a child algorithm within a model + * + * \since QGIS 3.38 +*/ +class CORE_EXPORT QgsProcessingModelChildAlgorithmResult +{ + public: + + QgsProcessingModelChildAlgorithmResult(); + + /** + * Returns the inputs used for the child algorithm. + * + * \see setInputs() + */ + QVariantMap inputs() const { return mInputs; } + + /** + * Sets the \a inputs used for the child algorithm. + * + * \see inputs() + */ + void setInputs( const QVariantMap &inputs ) { mInputs = inputs; } + + /** + * Returns the outputs generated by the child algorithm. + * + * \see setOutputs() + */ + QVariantMap outputs() const { return mOutputs; } + + /** + * Sets the \a outputs used for the child algorithm. + * + * \see outputs() + */ + void setOutputs( const QVariantMap &outputs ) { mOutputs = outputs; } + + bool operator==( const QgsProcessingModelChildAlgorithmResult &other ) const + { + return mInputs == other.mInputs && mOutputs == other.mOutputs; + } + bool operator!=( const QgsProcessingModelChildAlgorithmResult &other ) const + { + return !( *this == other ); + } + + private: + + QVariantMap mInputs; + QVariantMap mOutputs; + +}; + + /** * \class QgsProcessingContext * \ingroup core @@ -89,7 +147,6 @@ class CORE_EXPORT QgsProcessingContext mLogLevel = other.mLogLevel; mTemporaryFolderOverride = other.mTemporaryFolderOverride; mMaximumThreads = other.mMaximumThreads; - mModelChildInputs = other.mModelChildInputs; mModelChildResults = other.mModelChildResults; } @@ -740,39 +797,24 @@ class CORE_EXPORT QgsProcessingContext * Returns the map of child algorithm results, populated when the context is used * to run a model algorithm. * + * Map keys refer to the child algorithm IDs. + * * \see modelChildInputs() * \since QGIS 3.38 */ - QVariantMap modelChildResults() const { return mModelChildResults; } + QMap< QString, QgsProcessingModelChildAlgorithmResult > modelChildResults() const { return mModelChildResults; } /** * Returns a reference to the map of child algorithm results, populated when the context is used * to run a model algorithm. * + * Map keys refer to the child algorithm IDs. + * * \note Not available in Python bindings * \see modelChildInputs() * \since QGIS 3.38 */ - QVariantMap &modelChildResults() SIP_SKIP { return mModelChildResults; } - - /** - * Returns the map of child algorithm inputs, populated when the context is used - * to run a model algorithm. - * - * \see modelChildResults() - * \since QGIS 3.38 - */ - QVariantMap modelChildInputs() const { return mModelChildInputs; } - - /** - * Returns a reference to the map of child algorithm inputs, populated when the context is used - * to run a model algorithm. - * - * \note Not available in Python bindings - * \see modelChildResults() - * \since QGIS 3.38 - */ - QVariantMap &modelChildInputs() SIP_SKIP { return mModelChildInputs; } + QMap< QString, QgsProcessingModelChildAlgorithmResult > &modelChildResults() SIP_SKIP { return mModelChildResults; } private: @@ -808,8 +850,7 @@ class CORE_EXPORT QgsProcessingContext QString mTemporaryFolderOverride; int mMaximumThreads = QThread::idealThreadCount(); - QVariantMap mModelChildResults; - QVariantMap mModelChildInputs; + QMap< QString, QgsProcessingModelChildAlgorithmResult > mModelChildResults; #ifdef SIP_RUN QgsProcessingContext( const QgsProcessingContext &other ); diff --git a/src/gui/processing/models/qgsmodelcomponentgraphicitem.cpp b/src/gui/processing/models/qgsmodelcomponentgraphicitem.cpp index 02cbb26bfdd..251fa4c4dbb 100644 --- a/src/gui/processing/models/qgsmodelcomponentgraphicitem.cpp +++ b/src/gui/processing/models/qgsmodelcomponentgraphicitem.cpp @@ -901,7 +901,7 @@ void QgsModelChildAlgorithmGraphicItem::contextMenuEvent( QGraphicsSceneContextM QAction *viewOutputLayersAction = popupmenu->addAction( QObject::tr( "View Output Layers" ) ); viewOutputLayersAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionShowSelectedLayers.svg" ) ) ); connect( viewOutputLayersAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::showPreviousResults ); - if ( mResults.empty() ) + if ( mResults.outputs().empty() ) viewOutputLayersAction->setEnabled( false ); } } @@ -1001,6 +1001,8 @@ QString QgsModelChildAlgorithmGraphicItem::linkPointText( Qt::Edge edge, int ind if ( !child->algorithm() ) return QString(); + const QVariantMap inputs = mResults.inputs(); + const QVariantMap outputs = mResults.outputs(); switch ( edge ) { case Qt::BottomEdge: @@ -1016,9 +1018,9 @@ QString QgsModelChildAlgorithmGraphicItem::linkPointText( Qt::Edge edge, int ind const QgsProcessingOutputDefinition *output = child->algorithm()->outputDefinitions().at( index ); QString title = output->description(); - if ( mResults.contains( output->name() ) ) + if ( outputs.contains( output->name() ) ) { - title += QStringLiteral( ": %1" ).arg( mResults.value( output->name() ).toString() ); + title += QStringLiteral( ": %1" ).arg( outputs.value( output->name() ).toString() ); } return truncatedTextForItem( title ); } @@ -1041,8 +1043,8 @@ QString QgsModelChildAlgorithmGraphicItem::linkPointText( Qt::Edge edge, int ind } QString title = params.at( index )->description(); - if ( !mInputs.value( params.at( index )->name() ).toString().isEmpty() ) - title += QStringLiteral( ": %1" ).arg( mInputs.value( params.at( index )->name() ).toString() ); + if ( !inputs.value( params.at( index )->name() ).toString().isEmpty() ) + title += QStringLiteral( ": %1" ).arg( inputs.value( params.at( index )->name() ).toString() ); return truncatedTextForItem( title ); } @@ -1072,7 +1074,7 @@ bool QgsModelChildAlgorithmGraphicItem::canDeleteComponent() return false; } -void QgsModelChildAlgorithmGraphicItem::setResults( const QVariantMap &results ) +void QgsModelChildAlgorithmGraphicItem::setResults( const QgsProcessingModelChildAlgorithmResult &results ) { if ( mResults == results ) return; @@ -1082,16 +1084,6 @@ void QgsModelChildAlgorithmGraphicItem::setResults( const QVariantMap &results ) emit updateArrowPaths(); } -void QgsModelChildAlgorithmGraphicItem::setInputs( const QVariantMap &inputs ) -{ - if ( mInputs == inputs ) - return; - - mInputs = inputs; - update(); - emit updateArrowPaths(); -} - void QgsModelChildAlgorithmGraphicItem::deleteComponent() { if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast< const QgsProcessingModelChildAlgorithm * >( component() ) ) diff --git a/src/gui/processing/models/qgsmodelcomponentgraphicitem.h b/src/gui/processing/models/qgsmodelcomponentgraphicitem.h index 2499526c275..27849685eb9 100644 --- a/src/gui/processing/models/qgsmodelcomponentgraphicitem.h +++ b/src/gui/processing/models/qgsmodelcomponentgraphicitem.h @@ -18,6 +18,7 @@ #include "qgis.h" #include "qgis_gui.h" +#include "qgsprocessingcontext.h" #include #include #include @@ -461,14 +462,9 @@ class GUI_EXPORT QgsModelChildAlgorithmGraphicItem : public QgsModelComponentGra bool canDeleteComponent() override; /** - * Sets the results obtained for this child algorithm for the last model execution through the dialog. + * Sets the \a results obtained for this child algorithm for the last model execution through the dialog. */ - void setResults( const QVariantMap &results ); - - /** - * Sets the inputs used for this child algorithm for the last model execution through the dialog. - */ - void setInputs( const QVariantMap &inputs ); + void setResults( const QgsProcessingModelChildAlgorithmResult &results ); signals: @@ -502,8 +498,7 @@ class GUI_EXPORT QgsModelChildAlgorithmGraphicItem : public QgsModelComponentGra private: QPicture mPicture; QPixmap mPixmap; - QVariantMap mResults; - QVariantMap mInputs; + QgsProcessingModelChildAlgorithmResult mResults; bool mIsValid = true; }; diff --git a/src/gui/processing/models/qgsmodeldesignerdialog.cpp b/src/gui/processing/models/qgsmodeldesignerdialog.cpp index 8cc5168cae0..e23dd69819e 100644 --- a/src/gui/processing/models/qgsmodeldesignerdialog.cpp +++ b/src/gui/processing/models/qgsmodeldesignerdialog.cpp @@ -493,7 +493,7 @@ void QgsModelDesignerDialog::setModelScene( QgsModelGraphicsScene *scene ) mScene = scene; mScene->setParent( this ); - mScene->setChildAlgorithmResults( mChildResults ); + mScene->setLastRunChildAlgorithmResults( mChildResults ); mScene->setModel( mModel.get() ); mScene->setMessageBar( mMessageBar ); @@ -595,18 +595,11 @@ bool QgsModelDesignerDialog::checkForUnsavedChanges() } } -void QgsModelDesignerDialog::setLastRunChildAlgorithmResults( const QVariantMap &results ) +void QgsModelDesignerDialog::setLastRunChildAlgorithmResults( const QMap< QString, QgsProcessingModelChildAlgorithmResult > &results ) { mChildResults = results; if ( mScene ) - mScene->setChildAlgorithmResults( mChildResults ); -} - -void QgsModelDesignerDialog::setLastRunChildAlgorithmInputs( const QVariantMap &inputs ) -{ - mChildInputs = inputs; - if ( mScene ) - mScene->setChildAlgorithmInputs( mChildInputs ); + mScene->setLastRunChildAlgorithmResults( mChildResults ); } void QgsModelDesignerDialog::setModelName( const QString &name ) @@ -1038,7 +1031,6 @@ void QgsModelDesignerDialog::run() QgsProcessingContext *context = dialog->processingContext(); setLastRunChildAlgorithmResults( context->modelChildResults() ); - setLastRunChildAlgorithmInputs( context->modelChildInputs() ); mModel->setDesignerParameterValues( dialog->createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipDefaultValueParameters ) ); @@ -1054,8 +1046,9 @@ void QgsModelDesignerDialog::showPreviousResults( const QString &childId ) { const QString childDescription = mModel->childAlgorithm( childId ).description(); - const QVariantMap childAlgorithmResults = mChildResults.value( childId ).toMap(); - if ( childAlgorithmResults.isEmpty() ) + const QgsProcessingModelChildAlgorithmResult result = mChildResults.value( childId ); + const QVariantMap childAlgorithmOutputs = result.outputs(); + if ( childAlgorithmOutputs.isEmpty() ) { mMessageBar->pushWarning( QString(), tr( "No results are available for %1" ).arg( childDescription ) ); return; @@ -1079,7 +1072,7 @@ void QgsModelDesignerDialog::showPreviousResults( const QString &childId ) bool foundResults = false; for ( const QgsProcessingParameterDefinition *outputParam : outputParams ) { - const QVariant output = childAlgorithmResults.value( outputParam->name() ); + const QVariant output = childAlgorithmOutputs.value( outputParam->name() ); if ( !output.isValid() ) continue; diff --git a/src/gui/processing/models/qgsmodeldesignerdialog.h b/src/gui/processing/models/qgsmodeldesignerdialog.h index 256d8bc482b..74ba526497f 100644 --- a/src/gui/processing/models/qgsmodeldesignerdialog.h +++ b/src/gui/processing/models/qgsmodeldesignerdialog.h @@ -152,14 +152,9 @@ class GUI_EXPORT QgsModelDesignerDialog : public QMainWindow, public Ui::QgsMode bool checkForUnsavedChanges(); /** - * Sets the results of child algorithms for the last run of the model through the designer window. + * Sets the \a results of child algorithms for the last run of the model through the designer window. */ - void setLastRunChildAlgorithmResults( const QVariantMap &results ); - - /** - * Sets the inputs for child algorithms for the last run of the model through the designer window. - */ - void setLastRunChildAlgorithmInputs( const QVariantMap &inputs ); + void setLastRunChildAlgorithmResults( const QMap< QString, QgsProcessingModelChildAlgorithmResult > &results ); /** * Sets the model \a name. @@ -234,8 +229,7 @@ class GUI_EXPORT QgsModelDesignerDialog : public QMainWindow, public Ui::QgsMode int mBlockRepaints = 0; - QVariantMap mChildResults; - QVariantMap mChildInputs; + QMap< QString, QgsProcessingModelChildAlgorithmResult > mChildResults; bool isDirty() const; diff --git a/src/gui/processing/models/qgsmodelgraphicsscene.cpp b/src/gui/processing/models/qgsmodelgraphicsscene.cpp index 359d8298101..2ac1a0aeb52 100644 --- a/src/gui/processing/models/qgsmodelgraphicsscene.cpp +++ b/src/gui/processing/models/qgsmodelgraphicsscene.cpp @@ -140,8 +140,7 @@ void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, Qgs item->setPos( it.value().position().x(), it.value().position().y() ); const QString childId = it.value().childId(); - item->setResults( mChildResults.value( childId ).toMap() ); - item->setInputs( mChildInputs.value( childId ).toMap() ); + item->setResults( mChildResults.value( childId ) ); mChildAlgorithmItems.insert( childId, item ); connect( item, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired ); connect( item, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged ); @@ -360,7 +359,7 @@ void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item emit selectedItemChanged( item ); } -void QgsModelGraphicsScene::setChildAlgorithmResults( const QVariantMap &results ) +void QgsModelGraphicsScene::setLastRunChildAlgorithmResults( const QMap< QString, QgsProcessingModelChildAlgorithmResult > &results ) { mChildResults = results; @@ -368,20 +367,7 @@ void QgsModelGraphicsScene::setChildAlgorithmResults( const QVariantMap &results { if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) ) { - item->setResults( it.value().toMap() ); - } - } -} - -void QgsModelGraphicsScene::setChildAlgorithmInputs( const QVariantMap &inputs ) -{ - mChildInputs = inputs; - - for ( auto it = mChildInputs.constBegin(); it != mChildInputs.constEnd(); ++it ) - { - if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) ) - { - item->setInputs( it.value().toMap() ); + item->setResults( it.value() ); } } } diff --git a/src/gui/processing/models/qgsmodelgraphicsscene.h b/src/gui/processing/models/qgsmodelgraphicsscene.h index ed31e46469c..84044323a68 100644 --- a/src/gui/processing/models/qgsmodelgraphicsscene.h +++ b/src/gui/processing/models/qgsmodelgraphicsscene.h @@ -138,14 +138,9 @@ class GUI_EXPORT QgsModelGraphicsScene : public QGraphicsScene void setSelectedItem( QgsModelComponentGraphicItem *item ); /** - * Sets the results for child algorithms for the last model execution. + * Sets the \a results of child algorithms for the last run of the model through the designer window. */ - void setChildAlgorithmResults( const QVariantMap &results ); - - /** - * Sets the inputs for child algorithms for the last model execution. - */ - void setChildAlgorithmInputs( const QVariantMap &inputs ); + void setLastRunChildAlgorithmResults( const QMap< QString, QgsProcessingModelChildAlgorithmResult > &results ); /** * Returns the message bar associated with the scene. @@ -247,8 +242,7 @@ class GUI_EXPORT QgsModelGraphicsScene : public QGraphicsScene QMap< QString, QgsModelChildAlgorithmGraphicItem * > mChildAlgorithmItems; QMap< QString, QMap< QString, QgsModelComponentGraphicItem * > > mOutputItems; QMap< QString, QgsModelComponentGraphicItem * > mGroupBoxItems; - QVariantMap mChildResults; - QVariantMap mChildInputs; + QMap< QString, QgsProcessingModelChildAlgorithmResult > mChildResults; QgsMessageBar *mMessageBar = nullptr; diff --git a/tests/src/analysis/testqgsprocessing.cpp b/tests/src/analysis/testqgsprocessing.cpp index ea5afb81126..8dddccceffc 100644 --- a/tests/src/analysis/testqgsprocessing.cpp +++ b/tests/src/analysis/testqgsprocessing.cpp @@ -1309,10 +1309,16 @@ void TestQgsProcessing::context() context.temporaryLayerStore()->addMapLayer( vector ); QCOMPARE( context.temporaryLayerStore()->mapLayer( vector->id() ), vector ); - context.modelChildInputs().insert( QStringLiteral( "CHILD1" ), 1 ); - context.modelChildInputs().insert( QStringLiteral( "CHILD2" ), 2 ); - context.modelChildResults().insert( QStringLiteral( "RESULT1" ), 1 ); - context.modelChildResults().insert( QStringLiteral( "RESULT2" ), 2 ); + QgsProcessingModelChildAlgorithmResult res1; + res1.setInputs( {{ QStringLiteral( "INPUT1" ), 1 }} ); + res1.setOutputs( {{ QStringLiteral( "RESULT1" ), 1 }} ); + + QgsProcessingModelChildAlgorithmResult res2; + res2.setInputs( {{ QStringLiteral( "INPUT2" ), 2 }} ); + res2.setOutputs( {{ QStringLiteral( "RESULT2" ), 2 }} ); + + context.modelChildResults().insert( QStringLiteral( "CHILD1" ), res1 ); + context.modelChildResults().insert( QStringLiteral( "CHILD2" ), res2 ); QgsProcessingContext context2; context2.copyThreadSafeSettings( context ); @@ -1320,12 +1326,11 @@ void TestQgsProcessing::context() QCOMPARE( context2.invalidGeometryCheck(), context.invalidGeometryCheck() ); QCOMPARE( context2.flags(), context.flags() ); QCOMPARE( context2.project(), context.project() ); - QCOMPARE( context2.modelChildInputs().count(), 2 ); - QCOMPARE( context2.modelChildInputs().value( QStringLiteral( "CHILD1" ) ).toInt(), 1 ); - QCOMPARE( context2.modelChildInputs().value( QStringLiteral( "CHILD2" ) ).toInt(), 2 ); QCOMPARE( context2.modelChildResults().count(), 2 ); - QCOMPARE( context2.modelChildResults().value( QStringLiteral( "RESULT1" ) ).toInt(), 1 ); - QCOMPARE( context2.modelChildResults().value( QStringLiteral( "RESULT2" ) ).toInt(), 2 ); + QCOMPARE( context2.modelChildResults().value( QStringLiteral( "CHILD1" ) ).inputs().value( QStringLiteral( "INPUT1" ) ).toInt(), 1 ); + QCOMPARE( context2.modelChildResults().value( QStringLiteral( "CHILD2" ) ).inputs().value( QStringLiteral( "INPUT2" ) ).toInt(), 2 ); + QCOMPARE( context2.modelChildResults().value( QStringLiteral( "CHILD1" ) ).outputs().value( QStringLiteral( "RESULT1" ) ).toInt(), 1 ); + QCOMPARE( context2.modelChildResults().value( QStringLiteral( "CHILD2" ) ).outputs().value( QStringLiteral( "RESULT2" ) ).toInt(), 2 ); QCOMPARE( static_cast< int >( context2.logLevel() ), static_cast< int >( Qgis::ProcessingLogLevel::Verbose ) ); // layers from temporaryLayerStore must not be copied by copyThreadSafeSettings QVERIFY( context2.temporaryLayerStore()->mapLayers().isEmpty() ); @@ -1405,12 +1410,11 @@ void TestQgsProcessing::context() QgsProcessingContext context3; context3.takeResultsFrom( context ); - QCOMPARE( context3.modelChildInputs().count(), 2 ); - QCOMPARE( context3.modelChildInputs().value( QStringLiteral( "CHILD1" ) ).toInt(), 1 ); - QCOMPARE( context3.modelChildInputs().value( QStringLiteral( "CHILD2" ) ).toInt(), 2 ); QCOMPARE( context3.modelChildResults().count(), 2 ); - QCOMPARE( context3.modelChildResults().value( QStringLiteral( "RESULT1" ) ).toInt(), 1 ); - QCOMPARE( context3.modelChildResults().value( QStringLiteral( "RESULT2" ) ).toInt(), 2 ); + QCOMPARE( context3.modelChildResults().value( QStringLiteral( "CHILD1" ) ).inputs().value( QStringLiteral( "INPUT1" ) ).toInt(), 1 ); + QCOMPARE( context3.modelChildResults().value( QStringLiteral( "CHILD2" ) ).inputs().value( QStringLiteral( "INPUT2" ) ).toInt(), 2 ); + QCOMPARE( context3.modelChildResults().value( QStringLiteral( "CHILD1" ) ).outputs().value( QStringLiteral( "RESULT1" ) ).toInt(), 1 ); + QCOMPARE( context3.modelChildResults().value( QStringLiteral( "CHILD2" ) ).outputs().value( QStringLiteral( "RESULT2" ) ).toInt(), 2 ); // make sure postprocessor is correctly deleted ppDeleted = false; diff --git a/tests/src/analysis/testqgsprocessingmodelalgorithm.cpp b/tests/src/analysis/testqgsprocessingmodelalgorithm.cpp index bc60b78e113..755853092b0 100644 --- a/tests/src/analysis/testqgsprocessingmodelalgorithm.cpp +++ b/tests/src/analysis/testqgsprocessingmodelalgorithm.cpp @@ -2356,9 +2356,9 @@ void TestQgsProcessingModelAlgorithm::modelWithChildException() QVERIFY( !DummyRaiseExceptionAlgorithm::postProcessAlgorithmCalled ); // results and inputs from buffer child should be available through the context - QCOMPARE( context.modelChildInputs().value( "buffer" ).toMap().value( "INPUT" ).toString(), QStringLiteral( "v1" ) ); - QCOMPARE( context.modelChildInputs().value( "buffer" ).toMap().value( "OUTPUT" ).toString(), QStringLiteral( "memory:Buffered" ) ); - QVERIFY( context.temporaryLayerStore()->mapLayer( context.modelChildResults().value( "buffer" ).toMap().value( "OUTPUT" ).toString() ) ); + QCOMPARE( context.modelChildResults().value( "buffer" ).inputs().value( "INPUT" ).toString(), QStringLiteral( "v1" ) ); + QCOMPARE( context.modelChildResults().value( "buffer" ).inputs().value( "OUTPUT" ).toString(), QStringLiteral( "memory:Buffered" ) ); + QVERIFY( context.temporaryLayerStore()->mapLayer( context.modelChildResults().value( "buffer" ).outputs().value( "OUTPUT" ).toString() ) ); } void TestQgsProcessingModelAlgorithm::modelDependencies()