diff --git a/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in b/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in index 19753616008..2954f71db46 100644 --- a/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in +++ b/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in @@ -88,6 +88,12 @@ Emitted when a change in the model requires a full rebuild of the scene. Emitted whenever a component of the model is changed. %End + protected: + + virtual QgsModelComponentGraphicItem *createParameterGraphicItem( QgsProcessingModelParameter *param ) const /Factory/; + virtual QgsModelComponentGraphicItem *createChildAlgGraphicItem( QgsProcessingModelChildAlgorithm *child ) const /Factory/; + virtual QgsModelComponentGraphicItem *createOutputGraphicItem( QgsProcessingModelOutput *output ) const /Factory/; + }; diff --git a/src/gui/processing/models/qgsmodelgraphicsscene.cpp b/src/gui/processing/models/qgsmodelgraphicsscene.cpp index d352f9bed84..23eca68e233 100644 --- a/src/gui/processing/models/qgsmodelgraphicsscene.cpp +++ b/src/gui/processing/models/qgsmodelgraphicsscene.cpp @@ -14,6 +14,10 @@ ***************************************************************************/ #include "qgsmodelgraphicsscene.h" +#include "qgsprocessingmodelchildparametersource.h" +#include "qgsprocessingmodelalgorithm.h" +#include "qgsmodelcomponentgraphicitem.h" +#include "qgsmodelarrowitem.h" #include ///@cond NOT_STABLE @@ -39,5 +43,191 @@ void QgsModelGraphicsScene::mousePressEvent( QGraphicsSceneMouseEvent *event ) QGraphicsScene::mousePressEvent( event ); } +QgsModelComponentGraphicItem *QgsModelGraphicsScene::createParameterGraphicItem( QgsProcessingModelParameter *param ) const +{ + return new QgsModelParameterGraphicItem( param, mModel, nullptr ); +} + +QgsModelComponentGraphicItem *QgsModelGraphicsScene::createChildAlgGraphicItem( QgsProcessingModelChildAlgorithm *child ) const +{ + return new QgsModelChildAlgorithmGraphicItem( child, mModel, nullptr ); +} + +QgsModelComponentGraphicItem *QgsModelGraphicsScene::createOutputGraphicItem( QgsProcessingModelOutput *output ) const +{ + return new QgsModelOutputGraphicItem( output, mModel, nullptr ); +} + +void QgsModelGraphicsScene::createItems( QgsProcessingContext &context ) +{ + const QMap params = mModel->parameterComponents(); + for ( auto it = params.constBegin(); it != params.constEnd(); ++it ) + { + QgsModelComponentGraphicItem *item = createParameterGraphicItem( it.value().clone() ); + addItem( item ); + item->setPos( it.value().position().x(), it.value().position().y() ); + mParameterItems.insert( it.value().parameterName(), item ); + connect( item, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired ); + connect( item, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged ); + } + + const QMap childAlgs = mModel->childAlgorithms(); + for ( auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it ) + { + QgsModelComponentGraphicItem *item = createChildAlgGraphicItem( it.value().clone() ); + addItem( item ); + item->setPos( it.value().position().x(), it.value().position().y() ); + mChildAlgorithmItems.insert( it.value().childId(), item ); + connect( item, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired ); + connect( item, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged ); + } + + for ( auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it ) + { + int idx = 0; + const QgsProcessingParameterDefinitions parameters = it.value().algorithm()->parameterDefinitions(); + for ( const QgsProcessingParameterDefinition *parameter : parameters ) + { + if ( !parameter->isDestination() && !( parameter->flags() & QgsProcessingParameterDefinition::FlagHidden ) ) + { + QList< QgsProcessingModelChildParameterSource > sources; + if ( it.value().parameterSources().contains( parameter->name() ) ) + sources = it.value().parameterSources()[parameter->name()]; + for ( const QgsProcessingModelChildParameterSource &source : sources ) + { + const QList< LinkSource > sourceItems = linkSourcesForParameterValue( QVariant::fromValue( source ), it.value().childId(), context ); + for ( const LinkSource &link : sourceItems ) + { + QgsModelArrowItem *arrow = nullptr; + if ( link.linkIndex == -1 ) + arrow = new QgsModelArrowItem( link.item, mChildAlgorithmItems.value( it.value().childId() ), Qt::TopEdge, idx ); + else + arrow = new QgsModelArrowItem( link.item, link.edge, link.linkIndex, mChildAlgorithmItems.value( it.value().childId() ), Qt::TopEdge, idx ); + addItem( arrow ); + } + idx += 1; + } + } + } + const QStringList dependencies = it.value().dependencies(); + for ( const QString &depend : dependencies ) + { + addItem( new QgsModelArrowItem( mChildAlgorithmItems.value( depend ), mChildAlgorithmItems.value( it.value().childId() ) ) ); + } + } + + for ( auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it ) + { + const QMap outputs = it.value().modelOutputs(); + QMap< QString, QgsModelComponentGraphicItem * > outputItems; + + for ( auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); ++outputIt ) + { + QgsModelComponentGraphicItem *item = createOutputGraphicItem( outputIt.value().clone() ); + addItem( item ); + connect( item, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired ); + connect( item, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged ); + + QPointF pos = outputIt.value().position(); + + // find the actual index of the linked output from the child algorithm it comes from + const QgsProcessingOutputDefinitions sourceChildAlgOutputs = it.value().algorithm()->outputDefinitions(); + int idx = -1; + int i = 0; + for ( const QgsProcessingOutputDefinition *childAlgOutput : sourceChildAlgOutputs ) + { + if ( childAlgOutput->name() == outputIt.value().childOutputName() ) + { + idx = i; + break; + } + i++; + } + +#if 0 + if pos is None: + pos = ( alg.position() + QPointF( alg.size().width(), 0 ) + + self.algItems[alg.childId()].linkPoint( Qt.BottomEdge, idx ) ) +#endif + item->setPos( pos ); + outputItems.insert( outputIt.key(), item ); + addItem( new QgsModelArrowItem( mChildAlgorithmItems[it.value().childId()], Qt::BottomEdge, idx, item ) ); + } + mOutputItems.insert( it.value().childId(), outputItems ); + } +} + +QList QgsModelGraphicsScene::linkSourcesForParameterValue( const QVariant &value, const QString &childId, QgsProcessingContext &context ) const +{ + QList res; + if ( value.type() == QVariant::List ) + { + const QVariantList list = value.toList(); + for ( const QVariant &v : list ) + res.append( linkSourcesForParameterValue( v, childId, context ) ); + } + else if ( value.type() == QVariant::StringList ) + { + const QStringList list = value.toStringList(); + for ( const QString &v : list ) + res.append( linkSourcesForParameterValue( v, childId, context ) ); + } + else if ( value.canConvert< QgsProcessingModelChildParameterSource >() ) + { + const QgsProcessingModelChildParameterSource source = value.value< QgsProcessingModelChildParameterSource >(); + switch ( source.source() ) + { + case QgsProcessingModelChildParameterSource::ModelParameter: + { + LinkSource l; + l.item = mParameterItems.value( source.parameterName() ); + res.append( l ); + break; + } + case QgsProcessingModelChildParameterSource::ChildOutput: + { + const QgsProcessingOutputDefinitions outputs = mModel->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions(); + int i = 0; + for ( const QgsProcessingOutputDefinition *output : outputs ) + { + if ( output->name() == source.outputName() ) + break; + i++; + } + if ( mChildAlgorithmItems.contains( source.outputChildId() ) ) + { + LinkSource l; + l.item = mChildAlgorithmItems.value( source.outputChildId() ); + l.edge = Qt::BottomEdge; + l.linkIndex = i; + res.append( l ); + } + + break; + } + + case QgsProcessingModelChildParameterSource::Expression: + { + const QMap variables = mModel->variablesForChildAlgorithm( childId, context ); + QgsExpression exp( source.expression() ); + const QSet vars = exp.referencedVariables(); + for ( const QString &v : vars ) + { + if ( variables.contains( v ) ) + { + res.append( linkSourcesForParameterValue( QVariant::fromValue( variables.value( v ).source ), childId, context ) ); + } + } + break; + } + + case QgsProcessingModelChildParameterSource::StaticValue: + case QgsProcessingModelChildParameterSource::ExpressionText: + break; + } + } + return res; +} + ///@endcond diff --git a/src/gui/processing/models/qgsmodelgraphicsscene.h b/src/gui/processing/models/qgsmodelgraphicsscene.h index 0c1971f4157..0ecf11a2ca7 100644 --- a/src/gui/processing/models/qgsmodelgraphicsscene.h +++ b/src/gui/processing/models/qgsmodelgraphicsscene.h @@ -18,8 +18,14 @@ #include "qgis.h" #include "qgis_gui.h" +#include "qgsprocessingcontext.h" #include +class QgsProcessingModelAlgorithm; +class QgsModelComponentGraphicItem; +class QgsProcessingModelParameter; +class QgsProcessingModelChildAlgorithm; +class QgsProcessingModelOutput; ///@cond NOT_STABLE @@ -90,10 +96,33 @@ class GUI_EXPORT QgsModelGraphicsScene : public QGraphicsScene */ void componentChanged(); + protected: + + virtual QgsModelComponentGraphicItem *createParameterGraphicItem( QgsProcessingModelParameter *param ) const SIP_FACTORY; + virtual QgsModelComponentGraphicItem *createChildAlgGraphicItem( QgsProcessingModelChildAlgorithm *child ) const SIP_FACTORY; + virtual QgsModelComponentGraphicItem *createOutputGraphicItem( QgsProcessingModelOutput *output ) const SIP_FACTORY; + private: + void createItems( QgsProcessingContext &context ); + + struct LinkSource + { + QgsModelComponentGraphicItem *item = nullptr; + Qt::Edge edge = Qt::LeftEdge; + int linkIndex = -1; + }; + QList< LinkSource > linkSourcesForParameterValue( const QVariant &value, const QString &childId, QgsProcessingContext &context ) const; + + Flags mFlags = nullptr; + QgsProcessingModelAlgorithm *mModel = nullptr; + + QMap< QString, QgsModelComponentGraphicItem * > mParameterItems; + QMap< QString, QgsModelComponentGraphicItem * > mChildAlgorithmItems; + QMap< QString, QMap< QString, QgsModelComponentGraphicItem * > > mOutputItems; + }; Q_DECLARE_METATYPE( QgsModelGraphicsScene::Flags )