QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsmodelgraphicsscene.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmodelgraphicsscene.cpp
3 ----------------------------------
4 Date : March 2020
5 Copyright : (C) 2020 Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
20#include "qgsmodelarrowitem.h"
22#include "qgsmessagebar.h"
23#include "qgsmessagebaritem.h"
24#include "qgsmessageviewer.h"
25#include "qgsapplication.h"
26#include <QGraphicsSceneMouseEvent>
27#include <QPushButton>
28
30
31QgsModelGraphicsScene::QgsModelGraphicsScene( QObject *parent )
32 : QGraphicsScene( parent )
33{
34 setItemIndexMethod( QGraphicsScene::NoIndex );
35}
36
37QgsProcessingModelAlgorithm *QgsModelGraphicsScene::model()
38{
39 return mModel;
40}
41
42void QgsModelGraphicsScene::setModel( QgsProcessingModelAlgorithm *model )
43{
44 mModel = model;
45}
46
47void QgsModelGraphicsScene::setFlag( QgsModelGraphicsScene::Flag flag, bool on )
48{
49 if ( on )
50 mFlags |= flag;
51 else
52 mFlags &= ~flag;
53}
54
55void QgsModelGraphicsScene::mousePressEvent( QGraphicsSceneMouseEvent *event )
56{
57 if ( event->button() != Qt::LeftButton )
58 return;
59 QGraphicsScene::mousePressEvent( event );
60}
61
62QgsModelComponentGraphicItem *QgsModelGraphicsScene::createParameterGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelParameter *param ) const
63{
64 return new QgsModelParameterGraphicItem( param, model, nullptr );
65}
66
67QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::createChildAlgGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelChildAlgorithm *child ) const
68{
69 return new QgsModelChildAlgorithmGraphicItem( child, model, nullptr );
70}
71
72QgsModelComponentGraphicItem *QgsModelGraphicsScene::createOutputGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelOutput *output ) const
73{
74 return new QgsModelOutputGraphicItem( output, model, nullptr );
75}
76
77QgsModelComponentGraphicItem *QgsModelGraphicsScene::createCommentGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem ) const
78{
79 return new QgsModelCommentGraphicItem( comment, parentItem, model, nullptr );
80}
81
82QgsModelComponentGraphicItem *QgsModelGraphicsScene::createGroupBoxGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelGroupBox *box ) const
83{
84 return new QgsModelGroupBoxGraphicItem( box, model, nullptr );
85}
86
87void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, QgsProcessingContext &context )
88{
89 // model group boxes
90 const QList<QgsProcessingModelGroupBox> boxes = model->groupBoxes();
91 mGroupBoxItems.clear();
92 for ( const QgsProcessingModelGroupBox &box : boxes )
93 {
94 QgsModelComponentGraphicItem *item = createGroupBoxGraphicItem( model, box.clone() );
95 addItem( item );
96 item->setPos( box.position().x(), box.position().y() );
97 mGroupBoxItems.insert( box.uuid(), item );
98 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired );
99 connect( item, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged );
100 connect( item, &QgsModelComponentGraphicItem::aboutToChange, this, &QgsModelGraphicsScene::componentAboutToChange );
101 }
102
103 // model input parameters
104 const QMap<QString, QgsProcessingModelParameter> params = model->parameterComponents();
105 for ( auto it = params.constBegin(); it != params.constEnd(); ++it )
106 {
107 QgsModelComponentGraphicItem *item = createParameterGraphicItem( model, it.value().clone() );
108 addItem( item );
109 item->setPos( it.value().position().x(), it.value().position().y() );
110 mParameterItems.insert( it.value().parameterName(), item );
111 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired );
112 connect( item, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged );
113 connect( item, &QgsModelComponentGraphicItem::aboutToChange, this, &QgsModelGraphicsScene::componentAboutToChange );
114
115 addCommentItemForComponent( model, it.value(), item );
116 }
117
118 // input dependency arrows
119 for ( auto it = params.constBegin(); it != params.constEnd(); ++it )
120 {
121 const QgsProcessingParameterDefinition *parameterDef = model->parameterDefinition( it.key() );
122 const QStringList parameterLinks = parameterDef->dependsOnOtherParameters();
123 for ( const QString &otherName : parameterLinks )
124 {
125 if ( mParameterItems.contains( it.key() ) && mParameterItems.contains( otherName ) )
126 {
127 std::unique_ptr< QgsModelArrowItem > arrow = std::make_unique< QgsModelArrowItem >( mParameterItems.value( otherName ), QgsModelArrowItem::Marker::Circle, mParameterItems.value( it.key() ), QgsModelArrowItem::Marker::ArrowHead );
128 arrow->setPenStyle( Qt::DotLine );
129 addItem( arrow.release() );
130 }
131 }
132 }
133
134 // child algorithms
135 const QMap<QString, QgsProcessingModelChildAlgorithm> childAlgs = model->childAlgorithms();
136 for ( auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
137 {
138 QgsModelChildAlgorithmGraphicItem *item = createChildAlgGraphicItem( model, it.value().clone() );
139 addItem( item );
140 item->setPos( it.value().position().x(), it.value().position().y() );
141 item->setResults( mChildResults.value( it.value().childId() ).toMap() );
142 item->setInputs( mChildInputs.value( it.value().childId() ).toMap() );
143 mChildAlgorithmItems.insert( it.value().childId(), item );
144 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired );
145 connect( item, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged );
146 connect( item, &QgsModelComponentGraphicItem::aboutToChange, this, &QgsModelGraphicsScene::componentAboutToChange );
147
148 addCommentItemForComponent( model, it.value(), item );
149 }
150
151 // arrows linking child algorithms
152 for ( auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
153 {
154 int topIdx = 0;
155 int bottomIdx = 0;
156 if ( !it.value().algorithm() )
157 continue;
158
159 const QgsProcessingParameterDefinitions parameters = it.value().algorithm()->parameterDefinitions();
160 for ( const QgsProcessingParameterDefinition *parameter : parameters )
161 {
162 if ( !( parameter->flags() & QgsProcessingParameterDefinition::FlagHidden ) )
163 {
164 QList< QgsProcessingModelChildParameterSource > sources;
165 if ( it.value().parameterSources().contains( parameter->name() ) )
166 sources = it.value().parameterSources()[parameter->name()];
167 for ( const QgsProcessingModelChildParameterSource &source : sources )
168 {
169 const QList< LinkSource > sourceItems = linkSourcesForParameterValue( model, QVariant::fromValue( source ), it.value().childId(), context );
170 for ( const LinkSource &link : sourceItems )
171 {
172 if ( !link.item )
173 continue;
174 QgsModelArrowItem *arrow = nullptr;
175 if ( link.linkIndex == -1 )
176 arrow = new QgsModelArrowItem( link.item, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge, parameter->isDestination() ? bottomIdx : topIdx, QgsModelArrowItem::Marker::Circle );
177 else
178 arrow = new QgsModelArrowItem( link.item, link.edge, link.linkIndex, true, QgsModelArrowItem::Marker::Circle,
179 mChildAlgorithmItems.value( it.value().childId() ),
180 parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge,
181 parameter->isDestination() ? bottomIdx : topIdx,
182 true,
183 QgsModelArrowItem::Marker::Circle );
184 addItem( arrow );
185 }
186 }
187 if ( parameter->isDestination() )
188 bottomIdx++;
189 else
190 topIdx++;
191 }
192 }
193 const QList< QgsProcessingModelChildDependency > dependencies = it.value().dependencies();
194 for ( const QgsProcessingModelChildDependency &depend : dependencies )
195 {
196 if ( depend.conditionalBranch.isEmpty() || !model->childAlgorithm( depend.childId ).algorithm() )
197 {
198 addItem( new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
199 }
200 else
201 {
202 // find branch link point
203 const QgsProcessingOutputDefinitions outputs = model->childAlgorithm( depend.childId ).algorithm()->outputDefinitions();
204 int i = 0;
205 bool found = false;
206 for ( const QgsProcessingOutputDefinition *output : outputs )
207 {
208 if ( output->name() == depend.conditionalBranch )
209 {
210 found = true;
211 break;
212 }
213 i++;
214 }
215 if ( found )
216 addItem( new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), Qt::BottomEdge, i, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
217 }
218 }
219 }
220
221 // and finally the model outputs
222 for ( auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
223 {
224 const QMap<QString, QgsProcessingModelOutput> outputs = it.value().modelOutputs();
225 QMap< QString, QgsModelComponentGraphicItem * > outputItems;
226
227 // offsets from algorithm item needed to correctly place output items
228 // which does not have valid position assigned (https://github.com/qgis/QGIS/issues/48132)
229 QgsProcessingModelComponent *algItem = mChildAlgorithmItems[it.value().childId()]->component();
230 const double outputOffsetX = algItem->size().width();
231 double outputOffsetY = 1.5 * algItem->size().height();
232
233 for ( auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); ++outputIt )
234 {
235 QgsModelComponentGraphicItem *item = createOutputGraphicItem( model, outputIt.value().clone() );
236 addItem( item );
237 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired );
238 connect( item, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged );
239 connect( item, &QgsModelComponentGraphicItem::aboutToChange, this, &QgsModelGraphicsScene::componentAboutToChange );
240
241 // if output added not at the same time as algorithm then it does not have
242 // valid position and will be placed at (0,0). We need to calculate better position.
243 // See https://github.com/qgis/QGIS/issues/48132.
244 QPointF pos = outputIt.value().position();
245 if ( pos.isNull() )
246 {
247 pos = algItem->position() + QPointF( outputOffsetX, outputOffsetY );
248 outputOffsetY += 1.5 * outputIt.value().size().height();
249 }
250 int idx = -1;
251 int i = 0;
252 // find the actual index of the linked output from the child algorithm it comes from
253 if ( it.value().algorithm() )
254 {
255 const QgsProcessingOutputDefinitions sourceChildAlgOutputs = it.value().algorithm()->outputDefinitions();
256 for ( const QgsProcessingOutputDefinition *childAlgOutput : sourceChildAlgOutputs )
257 {
258 if ( childAlgOutput->name() == outputIt.value().childOutputName() )
259 {
260 idx = i;
261 break;
262 }
263 i++;
264 }
265 }
266
267 item->setPos( pos );
268 outputItems.insert( outputIt.key(), item );
269 addItem( new QgsModelArrowItem( mChildAlgorithmItems[it.value().childId()], Qt::BottomEdge, idx, QgsModelArrowItem::Marker::Circle, item, QgsModelArrowItem::Marker::Circle ) );
270
271 addCommentItemForComponent( model, outputIt.value(), item );
272 }
273 mOutputItems.insert( it.value().childId(), outputItems );
274 }
275}
276
277QList<QgsModelComponentGraphicItem *> QgsModelGraphicsScene::selectedComponentItems()
278{
279 QList<QgsModelComponentGraphicItem *> componentItemList;
280
281 const QList<QGraphicsItem *> graphicsItemList = selectedItems();
282 for ( QGraphicsItem *item : graphicsItemList )
283 {
284 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item ) )
285 {
286 componentItemList.push_back( componentItem );
287 }
288 }
289
290 return componentItemList;
291}
292
293QgsModelComponentGraphicItem *QgsModelGraphicsScene::componentItemAt( QPointF position ) const
294{
295 //get a list of items which intersect the specified position, in descending z order
296 const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
297
298 for ( QGraphicsItem *graphicsItem : itemList )
299 {
300 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( graphicsItem ) )
301 {
302 return componentItem;
303 }
304 }
305 return nullptr;
306}
307
308QgsModelComponentGraphicItem *QgsModelGraphicsScene::groupBoxItem( const QString &uuid )
309{
310 return mGroupBoxItems.value( uuid );
311}
312
313void QgsModelGraphicsScene::selectAll()
314{
315 //select all items in scene
316 QgsModelComponentGraphicItem *focusedItem = nullptr;
317 const QList<QGraphicsItem *> itemList = items();
318 for ( QGraphicsItem *graphicsItem : itemList )
319 {
320 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( graphicsItem ) )
321 {
322 componentItem->setSelected( true );
323 if ( !focusedItem )
324 focusedItem = componentItem;
325 }
326 }
327 emit selectedItemChanged( focusedItem );
328}
329
330void QgsModelGraphicsScene::deselectAll()
331{
332 //we can't use QGraphicsScene::clearSelection, as that emits no signals
333 //and we don't know which items are being deselected
334 //instead, do the clear selection manually...
335 const QList<QGraphicsItem *> selectedItemList = selectedItems();
336 for ( QGraphicsItem *item : selectedItemList )
337 {
338 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item ) )
339 {
340 componentItem->setSelected( false );
341 }
342 }
343 emit selectedItemChanged( nullptr );
344}
345
346void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item )
347{
348 whileBlocking( this )->deselectAll();
349 if ( item )
350 {
351 item->setSelected( true );
352 }
353 emit selectedItemChanged( item );
354}
355
356void QgsModelGraphicsScene::setChildAlgorithmResults( const QVariantMap &results )
357{
358 mChildResults = results;
359
360 for ( auto it = mChildResults.constBegin(); it != mChildResults.constEnd(); ++it )
361 {
362 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
363 {
364 item->setResults( it.value().toMap() );
365 }
366 }
367}
368
369void QgsModelGraphicsScene::setChildAlgorithmInputs( const QVariantMap &inputs )
370{
371 mChildInputs = inputs;
372
373 for ( auto it = mChildInputs.constBegin(); it != mChildInputs.constEnd(); ++it )
374 {
375 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
376 {
377 item->setInputs( it.value().toMap() );
378 }
379 }
380}
381
382QList<QgsModelGraphicsScene::LinkSource> QgsModelGraphicsScene::linkSourcesForParameterValue( QgsProcessingModelAlgorithm *model, const QVariant &value, const QString &childId, QgsProcessingContext &context ) const
383{
384 QList<QgsModelGraphicsScene::LinkSource> res;
385 if ( value.type() == QVariant::List )
386 {
387 const QVariantList list = value.toList();
388 for ( const QVariant &v : list )
389 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
390 }
391 else if ( value.type() == QVariant::StringList )
392 {
393 const QStringList list = value.toStringList();
394 for ( const QString &v : list )
395 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
396 }
397 else if ( value.userType() == QMetaType::type( "QgsProcessingModelChildParameterSource" ) )
398 {
399 const QgsProcessingModelChildParameterSource source = value.value< QgsProcessingModelChildParameterSource >();
400 switch ( source.source() )
401 {
402 case QgsProcessingModelChildParameterSource::ModelParameter:
403 {
404 LinkSource l;
405 l.item = mParameterItems.value( source.parameterName() );
406 res.append( l );
407 break;
408 }
409 case QgsProcessingModelChildParameterSource::ChildOutput:
410 {
411 if ( !model->childAlgorithm( source.outputChildId() ).algorithm() )
412 break;
413
414 const QgsProcessingOutputDefinitions outputs = model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions();
415 int i = 0;
416 for ( const QgsProcessingOutputDefinition *output : outputs )
417 {
418 if ( output->name() == source.outputName() )
419 break;
420 i++;
421 }
422 if ( mChildAlgorithmItems.contains( source.outputChildId() ) )
423 {
424 LinkSource l;
425 l.item = mChildAlgorithmItems.value( source.outputChildId() );
426 l.edge = Qt::BottomEdge;
427
428 // do sanity check of linked index
429 if ( i >= model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions().length() )
430 {
431 QString short_message = tr( "Check output links for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
432 QString long_message = tr( "Cannot link output for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
433 QString title( tr( "Algorithm link error" ) );
434 if ( messageBar() )
435 showWarning( const_cast<QString &>( short_message ), const_cast<QString &>( title ), const_cast<QString &>( long_message ) );
436 else
437 QgsMessageLog::logMessage( long_message, "QgsModelGraphicsScene", Qgis::MessageLevel::Warning, true );
438 break;
439 }
440
441 l.linkIndex = i;
442 res.append( l );
443 }
444
445 break;
446 }
447
448 case QgsProcessingModelChildParameterSource::Expression:
449 {
450 const QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables = model->variablesForChildAlgorithm( childId, context );
451 const QgsExpression exp( source.expression() );
452 const QSet<QString> vars = exp.referencedVariables();
453 for ( const QString &v : vars )
454 {
455 if ( variables.contains( v ) )
456 {
457 res.append( linkSourcesForParameterValue( model, QVariant::fromValue( variables.value( v ).source ), childId, context ) );
458 }
459 }
460 break;
461 }
462
463 case QgsProcessingModelChildParameterSource::StaticValue:
464 case QgsProcessingModelChildParameterSource::ExpressionText:
465 case QgsProcessingModelChildParameterSource::ModelOutput:
466 break;
467 }
468 }
469 return res;
470}
471
472void QgsModelGraphicsScene::addCommentItemForComponent( QgsProcessingModelAlgorithm *model, const QgsProcessingModelComponent &component, QgsModelComponentGraphicItem *parentItem )
473{
474 if ( mFlags & FlagHideComments || !component.comment() || component.comment()->description().isEmpty() )
475 return;
476
477 QgsModelComponentGraphicItem *commentItem = createCommentGraphicItem( model, component.comment()->clone(), parentItem );
478 commentItem->setPos( component.comment()->position().x(), component.comment()->position().y() );
479 addItem( commentItem );
480 connect( commentItem, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired );
481 connect( commentItem, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged );
482 connect( commentItem, &QgsModelComponentGraphicItem::aboutToChange, this, &QgsModelGraphicsScene::componentAboutToChange );
483
484 std::unique_ptr< QgsModelArrowItem > arrow = std::make_unique< QgsModelArrowItem >( parentItem, QgsModelArrowItem::Circle, commentItem, QgsModelArrowItem::Circle );
485 arrow->setPenStyle( Qt::DotLine );
486 addItem( arrow.release() );
487}
488
489QgsMessageBar *QgsModelGraphicsScene::messageBar() const
490{
491 return mMessageBar;
492}
493
494void QgsModelGraphicsScene::setMessageBar( QgsMessageBar *messageBar )
495{
496 mMessageBar = messageBar;
497}
498
499void QgsModelGraphicsScene::showWarning( const QString &shortMessage, const QString &title, const QString &longMessage, Qgis::MessageLevel level ) const
500{
501 QgsMessageBarItem *messageWidget = QgsMessageBar::createMessage( QString(), shortMessage );
502 QPushButton *detailsButton = new QPushButton( tr( "Details" ) );
503 connect( detailsButton, &QPushButton::clicked, detailsButton, [ = ]
504 {
505 QgsMessageViewer *dialog = new QgsMessageViewer( detailsButton );
506 dialog->setTitle( title );
507 dialog->setMessage( longMessage, QgsMessageOutput::MessageHtml );
508 dialog->showMessage();
509 } );
510 messageWidget->layout()->addWidget( detailsButton );
511 mMessageBar->clearWidgets();
512 mMessageBar->pushWidget( messageWidget, level, 0 );
513}
514
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:115
Class for parsing and evaluation of expressions (formerly called "search strings").
Represents an item shown within a QgsMessageBar widget.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
static QgsMessageBarItem * createMessage(const QString &text, QWidget *parent=nullptr)
Creates message bar item widget containing a message text to be displayed on the bar.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
A generic message view for displaying QGIS messages.
void setTitle(const QString &title) override
Sets title for the messages.
void setMessage(const QString &message, MessageType msgType) override
Sets message, it won't be displayed until.
void showMessage(bool blocking=true) override
display the message to the user and deletes itself
QgsProcessingOutputDefinitions outputDefinitions() const
Returns an ordered list of output definitions utilized by the algorithm.
Contains information about the context in which a processing algorithm is executed.
Base class for the definition of processing outputs.
Base class for the definition of processing parameters.
@ FlagHidden
Parameter is hidden and should not be shown to users.
virtual QStringList dependsOnOtherParameters() const
Returns a list of other parameter names on which this parameter is dependent (e.g.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:2453
QList< const QgsProcessingOutputDefinition * > QgsProcessingOutputDefinitions
List of processing parameters.
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.