39#include "moc_qgsmodelviewtoollink.cpp"
41using namespace Qt::StringLiterals;
45class PopupToolboxWidget :
public QWidget
49 PopupToolboxWidget( QWidget *parent =
nullptr )
52 QVBoxLayout *layout =
new QVBoxLayout();
53 layout->setSpacing( 0 );
54 layout->setContentsMargins( 0, 0, 0, 0 );
56 mLineEdit =
new QgsFilterLineEdit(
this );
57 mLineEdit->setShowSearchIcon(
true );
58 mLineEdit->setPlaceholderText( tr(
"Search…" ) );
59 mLineEdit->setFocus();
61 mToolboxTreeView =
new QgsProcessingToolboxTreeView(
this );
62 mToolboxTreeView->header()->setVisible(
false );
63 mToolboxTreeView->setAlternatingRowColors(
true );
64 const QFontMetrics fm( font() );
65 mToolboxTreeView->setFixedSize( fm.horizontalAdvance(
'X' ) * 40, fm.height() * 10 );
67 connect( mLineEdit, &QgsFilterLineEdit::textChanged, mToolboxTreeView, &QgsProcessingToolboxTreeView::setFilterString );
69 layout->addWidget( mLineEdit );
70 layout->addWidget( mToolboxTreeView );
74 connect( mLineEdit, &QgsFilterLineEdit::returnPressed,
this, [
this]() { itemSelected(); } );
75 connect( mToolboxTreeView, &QgsProcessingToolboxTreeView::clicked,
this, [
this](
const QModelIndex & ) { itemSelected(); } );
76 connect( mToolboxTreeView, &QgsProcessingToolboxTreeView::doubleClicked,
this, [
this](
const QModelIndex & ) { itemSelected(); } );
79 QgsProcessingToolboxTreeView *toolboxView()
const {
return mToolboxTreeView; }
82 void algorithmAdded(
const QString &algorithmId );
83 void parameterAdded(
const QString ¶meterTypeId );
87 QgsFilterLineEdit *mLineEdit =
nullptr;
88 QgsProcessingToolboxTreeView *mToolboxTreeView =
nullptr;
92 if ( mToolboxTreeView->selectedAlgorithm() )
94 emit algorithmAdded( mToolboxTreeView->selectedAlgorithm()->id() );
97 if ( mToolboxTreeView->selectedParameterType() )
99 emit parameterAdded( mToolboxTreeView->selectedParameterType()->id() );
106#include "qgsmodelviewtoollink.moc"
115 mBezierRubberBand = std::make_unique<QgsModelViewBezierRubberBand>(
view );
117 mBezierRubberBand->setBrush( QBrush( QColor( 0, 0, 0, 63 ) ) );
118 mBezierRubberBand->setPen( QPen( QBrush( QColor( 0, 0, 0, 100 ) ), 0, Qt::SolidLine ) );
123 mBezierRubberBand->update( event->
modelPoint(), Qt::KeyboardModifiers() );
126 const QList<QGraphicsItem *> items =
scene()->items( event->
modelPoint() );
128 QgsModelDesignerSocketGraphicItem *socket =
nullptr;
129 for ( QGraphicsItem *item : items )
131 socket =
dynamic_cast<QgsModelDesignerSocketGraphicItem *
>( item );
132 if ( !socket || mFromSocket == socket || mFromSocket->edge() == socket->edge() || mFromSocket->component() == socket->component() )
136 socket->modelHoverEnterEvent( event );
137 const QPointF rubberEndPos = socket->mapToScene( socket->position() );
138 mBezierRubberBand->update( rubberEndPos, Qt::KeyboardModifiers() );
142 if ( mLastHoveredSocket && socket != mLastHoveredSocket )
144 mLastHoveredSocket->modelHoverLeaveEvent( event );
145 mLastHoveredSocket =
nullptr;
148 if ( socket && socket != mLastHoveredSocket )
150 mLastHoveredSocket = socket;
156 if ( event->button() != Qt::LeftButton )
160 mBezierRubberBand->finish( event->
modelPoint() );
161 if ( mLastHoveredSocket )
163 mLastHoveredSocket->modelHoverLeaveEvent(
nullptr );
164 mLastHoveredSocket =
nullptr;
167 view()->setTool( mPreviousViewTool );
170 const QList<QGraphicsItem *> items =
scene()->items( event->
modelPoint() );
174 for ( QGraphicsItem *item : items )
176 if ( QgsModelDesignerSocketGraphicItem *socket =
dynamic_cast<QgsModelDesignerSocketGraphicItem *
>( item ) )
179 if ( mFromSocket->edge() == socket->edge() || mFromSocket->component() == socket->component() )
188 if ( !mToSocket && mPreviousInputSocketNumber != -1 )
191 view()->endCommand();
196 view()->abortCommand();
200 PopupToolboxWidget *widget =
new PopupToolboxWidget();
201 widget->setAttribute( Qt::WA_DeleteOnClose );
202 widget->setWindowFlags( Qt::Popup );
203 widget->move( event->globalPos() );
207 if ( settings.
value( u
"Processing/Configuration/SHOW_ALGORITHMS_KNOWN_ISSUES"_s,
false ).toBool() )
212 if ( !mFromSocket->isInput() )
214 QgsProcessingModelComponent *outputComponent = mFromSocket->component();
215 if (
const QgsProcessingModelChildAlgorithm *outputChildAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( outputComponent ) )
217 widget->toolboxView()->setFilterOutput( outputChildAlgorithm->algorithm()->outputDefinitions().at( mFromSocket->index() ) );
219 else if (
const QgsProcessingModelParameter *paramFrom =
dynamic_cast<QgsProcessingModelParameter *
>( outputComponent ) )
221 widget->toolboxView()->setFilterParameter(
scene()->model()->parameterDefinition( paramFrom->parameterName() ) );
227 QgsProcessingModelComponent *outputComponent = mFromSocket->component();
228 if (
const QgsProcessingModelChildAlgorithm *outputChildAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( outputComponent ) )
231 widget->toolboxView()->setFilterParameter( paramDef );
236 widget->toolboxView()->setFilters( filters );
238 const QPointF modelPoint =
event->modelPoint();
239 connect( widget, &PopupToolboxWidget::algorithmAdded,
this, [
this, modelPoint](
const QString &algorithmId ) { addAlgorithm( algorithmId, modelPoint, mFromSocket ); } );
240 connect( widget, &PopupToolboxWidget::parameterAdded,
this, [
this, modelPoint](
const QString ¶meterTypeId ) { addParameter( parameterTypeId, modelPoint, mFromSocket ); } );
247 if ( mFromSocket->edge() == mToSocket->edge() )
261 if ( !mToSocket->isInput() )
263 std::swap( mFromSocket, mToSocket );
266 QgsProcessingModelComponent *outputComponent = mFromSocket->component();
267 QgsProcessingModelChildAlgorithm *inputChildAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( mToSocket->component() );
268 if ( !inputChildAlgorithm )
271 QgsDebugError( u
"Input is not a QgsProcessingModelChildAlgorithm"_s );
275 QgsProcessingModelChildParameterSource newInputParamSource;
277 QString outParamDescription;
278 if (
const QgsProcessingModelChildAlgorithm *outputChildAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( outputComponent ) )
282 const QString outParamName = outputDef->
name();
283 newInputParamSource = QgsProcessingModelChildParameterSource::fromChildOutput( outputChildAlgorithm->childId(), outParamName );
286 else if (
const QgsProcessingModelParameter *paramFrom =
dynamic_cast<QgsProcessingModelParameter *
>( outputComponent ) )
288 newInputParamSource = QgsProcessingModelChildParameterSource::fromModelParameter( paramFrom->parameterName() );
289 outParamDescription = paramFrom->description();
293 const QList<QgsProcessingModelChildParameterSource> compatibleInputParamSources =
scene()->model()->availableSourcesForChild( inputChildAlgorithm->childId(), inputParam );
294 if ( !compatibleInputParamSources.contains( newInputParamSource ) )
297 const QString title = tr(
"Sockets cannot be connected" );
298 const QString message = tr(
"Either the sockets are incompatible or there is a circular dependency" );
299 scene()->showWarning( message, title, message );
302 if ( mPreviousInputSocketNumber != -1 )
304 QgsProcessingModelChildAlgorithm previousChildAlgorithm =
scene()->model()->childAlgorithm( mPreviousInputChildId );
306 previousChildAlgorithm.addParameterSources( previousInputParam->
name(), { newInputParamSource } );
307 scene()->model()->setChildAlgorithm( previousChildAlgorithm );
308 scene()->requestRebuildRequired();
313 view()->beginCommand( tr(
"Link %1: %2 to %3: %4" ).arg( outputComponent->description(), outParamDescription, inputChildAlgorithm->description(), inputParam->
description() ) );
315 inputChildAlgorithm->addParameterSources( inputParam->
name(), { newInputParamSource } );
318 scene()->model()->setChildAlgorithm( *inputChildAlgorithm );
320 if ( inputChildAlgorithm->childId() == mPreviousInputChildId && mToSocket->index() == mPreviousInputSocketNumber )
323 view()->abortCommand();
327 view()->endCommand();
331 scene()->requestRebuildRequired();
345 mPreviousViewTool = tool;
348 const QPointF rubberStartPos = mFromSocket->mapToScene( mFromSocket->position() );
349 mBezierRubberBand->start( rubberStartPos, Qt::KeyboardModifiers() );
356 mBezierRubberBand->finish();
362 mFromSocket = socket;
363 mPreviousInputChildId.clear();
364 mPreviousInputSocketNumber = -1;
367 if ( mFromSocket->isInput() )
369 QgsProcessingModelChildAlgorithm *childFrom =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( mFromSocket->component() );
374 const QList<QgsProcessingModelChildParameterSource> currentSources = childFrom->parameterSources().value( param->
name() );
376 for (
const QgsProcessingModelChildParameterSource &source : currentSources )
383 switch ( source.source() )
388 view()->beginCommand( tr(
"Unlink %1: %2",
"Unlink Algorithm: Input" ).arg( childFrom->description(), param->
description() ) );
391 QList<QgsProcessingModelChildParameterSource> newSources;
404 newSources << QgsProcessingModelChildParameterSource::fromModelParameter( QString() );
409 newSources << QgsProcessingModelChildParameterSource::fromStaticValue( param->
defaultValue() );
412 childFrom->addParameterSources( param->
name(), newSources );
414 scene()->model()->setChildAlgorithm( *childFrom );
416 scene()->requestRebuildRequired();
419 QgsModelComponentGraphicItem *item =
nullptr;
420 int socketIndex = -1;
423 item =
scene()->childAlgorithmItem( source.outputChildId() );
424 auto algSource =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( item->component() );
434 item =
scene()->parameterItem( source.parameterName() );
444 mPreviousInputChildId = childFrom->childId();
445 mPreviousInputSocketNumber = mFromSocket->index();
446 mFromSocket = item->outSocketAt( socketIndex );
463void QgsModelViewToolLink::addAlgorithm(
const QString &algorithmId,
const QPointF &pos,
const QgsModelDesignerSocketGraphicItem *socket )
465 std::unique_ptr<QgsProcessingAlgorithm> alg;
471 QgsProcessingModelChildAlgorithm childAlg( algorithmId );
473 childAlg.setDescription( alg->displayName() );
475 const double offsetX = socket->isInput() ? -childAlg.size().width() / 2 : childAlg.size().width() / 2;
476 const QPointF offset( offsetX, 0 );
477 childAlg.setPosition( pos + offset );
479 QgsProcessingModelComponent *outputComponent =
const_cast<QgsProcessingModelComponent *
>( socket->component() );
482 if ( !socket->isInput() )
484 if ( QgsProcessingModelChildAlgorithm *outputChildAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( outputComponent ) )
487 const QString outputName = outputDef->
name();
489 const QList<const QgsProcessingParameterDefinition *> definitions = alg->parameterDefinitions();
498 QgsProcessingModelChildParameterSource newInputParamSource = QgsProcessingModelChildParameterSource::fromChildOutput( outputChildAlgorithm->childId(), outputName );
499 childAlg.addParameterSources( paramDef->name(), { newInputParamSource } );
504 else if ( QgsProcessingModelParameter *outputParam =
dynamic_cast<QgsProcessingModelParameter *
>( outputComponent ) )
506 const QgsProcessingParameterDefinition *outputParamDef =
scene()->model()->parameterDefinition( outputParam->parameterName() );
508 const QList<const QgsProcessingParameterDefinition *> definitions = alg->parameterDefinitions();
509 for (
const QgsProcessingParameterDefinition *paramDef : definitions )
517 QgsProcessingModelChildParameterSource newInputParamSource = QgsProcessingModelChildParameterSource::fromModelParameter( outputParam->parameterName() );
518 childAlg.addParameterSources( paramDef->name(), { newInputParamSource } );
525 view()->beginCommand( tr(
"Add Algorithm" ) );
526 QString childAlgorithmId =
scene()->model()->addChildAlgorithm( childAlg );
527 view()->endCommand();
530 if ( socket->isInput() )
532 QgsProcessingModelChildAlgorithm *outputChildAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( outputComponent );
533 if ( !outputChildAlgorithm || !outputChildAlgorithm->algorithm() )
536 const QgsProcessingParameterDefinition *parameter = outputChildAlgorithm->algorithm()->parameterDefinitions().at( socket->index() );
537 const QString parameterName = parameter->
name();
539 const QList<const QgsProcessingOutputDefinition *> definitions = childAlg.algorithm()->outputDefinitions();
540 for (
const QgsProcessingOutputDefinition *outputDef : definitions )
544 QgsProcessingModelChildParameterSource newInputParamSource = QgsProcessingModelChildParameterSource::fromChildOutput( childAlgorithmId, outputDef->
name() );
545 outputChildAlgorithm->addParameterSources( parameterName, { newInputParamSource } );
546 scene()->model()->setChildAlgorithm( *outputChildAlgorithm );
552 scene()->requestRebuildRequired();
555void QgsModelViewToolLink::addParameter(
const QString ¶meterId,
const QPointF &pos,
const QgsModelDesignerSocketGraphicItem *socket )
557 QgsProcessingModelComponent *outputComponent =
const_cast<QgsProcessingModelComponent *
>( socket->component() );
558 QgsProcessingModelChildAlgorithm *outputChildAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( outputComponent );
559 if ( !outputChildAlgorithm || !outputChildAlgorithm->algorithm() )
562 const QgsProcessingParameterDefinition *socketParameter = outputChildAlgorithm->algorithm()->parameterDefinitions().at( socket->index() );
564 QString nameCandidate = socketParameter->
name();
565 QString descriptionCandidate = socketParameter->
description();
567 while (
scene()->model()->parameterDefinition( nameCandidate ) )
569 nameCandidate = u
"%1 (%2)"_s.arg( socketParameter->
name() ).arg( i );
570 descriptionCandidate = u
"%1 (%2)"_s.arg( socketParameter->
description() ).arg( i );
573 QgsProcessingParameterDefinition *newParameter;
574 if ( socketParameter->
type() == parameterId )
577 newParameter = socketParameter->
clone();
584 newParameter->
setName( nameCandidate );
587 QgsProcessingModelParameter component = QgsProcessingModelParameter( newParameter->
name() );
589 component.setDescription( newParameter->
description() );
590 const double offsetX = -component.size().width() / 2;
591 const QPointF offset( offsetX, 0 );
592 component.setPosition( pos + offset );
594 view()->beginCommand( tr(
"Add input" ) );
595 scene()->model()->addModelParameter( newParameter, component );
596 view()->endCommand();
598 QgsProcessingModelChildParameterSource newInputParamSource = QgsProcessingModelChildParameterSource::fromModelParameter( newParameter->
name() );
599 outputChildAlgorithm->addParameterSources( socketParameter->
name(), { newInputParamSource } );
600 scene()->model()->setChildAlgorithm( *outputChildAlgorithm );
603 scene()->requestRebuildRequired();
@ ExpressionText
Parameter value is taken from a text with expressions, evaluated just before the algorithm runs.
@ ModelOutput
Parameter value is linked to an output parameter for the model.
@ ChildOutput
Parameter value is taken from an output generated by a child algorithm.
@ ModelParameter
Parameter value is taken from a parent model parameter.
@ StaticValue
Parameter value is a static value.
@ Expression
Parameter value is taken from an expression, evaluated just before the algorithm runs.
@ Hidden
Parameter is hidden and should not be shown to users.
static QgsProcessingRegistry * processingRegistry()
Returns the application's processing registry, used for managing processing providers,...
A mouse event which is the result of a user interaction with a QgsModelGraphicsView.
QPointF modelPoint() const
Returns the event point location in model coordinates.
QgsProcessingParameterDefinitions parameterDefinitions() const
Returns an ordered list of parameter definitions utilized by the algorithm.
Base class for the definition of processing outputs.
QString name() const
Returns the name of the output.
QString description() const
Returns the description for the output.
Base class for the definition of processing parameters.
QVariant defaultValue() const
Returns the default value for the parameter.
QgsProcessingAlgorithm * algorithm() const
Returns a pointer to the algorithm which owns this parameter.
QString description() const
Returns the description for the parameter.
void setDescription(const QString &description)
Sets the description for the parameter.
void setName(const QString &name)
Sets the name of the parameter.
virtual QgsProcessingParameterDefinition * clone() const =0
Creates a clone of the parameter definition.
virtual QString type() const =0
Unique parameter type name.
QString name() const
Returns the name of the parameter.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
virtual QgsProcessingParameterDefinition * create(const QString &name) const =0
Creates a new parameter of this type.
static QString typeName()
Returns the type name for the parameter class.
QgsProcessingParameterType * parameterType(const QString &id) const
Returns the parameter type registered for id.
static int outputDefinitionIndex(const QgsProcessingAlgorithm *algorithm, const QString &name)
Returns the index of the output matching name for a specified algorithm.
Stores settings for use within QGIS.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugError(str)