QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
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 item->component()->setPosition( pos );
269 outputItems.insert( outputIt.key(), item );
270 addItem( new QgsModelArrowItem( mChildAlgorithmItems[it.value().childId()], Qt::BottomEdge, idx, QgsModelArrowItem::Marker::Circle, item, QgsModelArrowItem::Marker::Circle ) );
271
272 addCommentItemForComponent( model, outputIt.value(), item );
273 }
274 mOutputItems.insert( it.value().childId(), outputItems );
275 }
276}
277
278QList<QgsModelComponentGraphicItem *> QgsModelGraphicsScene::selectedComponentItems()
279{
280 QList<QgsModelComponentGraphicItem *> componentItemList;
281
282 const QList<QGraphicsItem *> graphicsItemList = selectedItems();
283 for ( QGraphicsItem *item : graphicsItemList )
284 {
285 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item ) )
286 {
287 componentItemList.push_back( componentItem );
288 }
289 }
290
291 return componentItemList;
292}
293
294QgsModelComponentGraphicItem *QgsModelGraphicsScene::componentItemAt( QPointF position ) const
295{
296 //get a list of items which intersect the specified position, in descending z order
297 const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
298
299 for ( QGraphicsItem *graphicsItem : itemList )
300 {
301 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( graphicsItem ) )
302 {
303 return componentItem;
304 }
305 }
306 return nullptr;
307}
308
309QgsModelComponentGraphicItem *QgsModelGraphicsScene::groupBoxItem( const QString &uuid )
310{
311 return mGroupBoxItems.value( uuid );
312}
313
314void QgsModelGraphicsScene::selectAll()
315{
316 //select all items in scene
317 QgsModelComponentGraphicItem *focusedItem = nullptr;
318 const QList<QGraphicsItem *> itemList = items();
319 for ( QGraphicsItem *graphicsItem : itemList )
320 {
321 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( graphicsItem ) )
322 {
323 componentItem->setSelected( true );
324 if ( !focusedItem )
325 focusedItem = componentItem;
326 }
327 }
328 emit selectedItemChanged( focusedItem );
329}
330
331void QgsModelGraphicsScene::deselectAll()
332{
333 //we can't use QGraphicsScene::clearSelection, as that emits no signals
334 //and we don't know which items are being deselected
335 //instead, do the clear selection manually...
336 const QList<QGraphicsItem *> selectedItemList = selectedItems();
337 for ( QGraphicsItem *item : selectedItemList )
338 {
339 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item ) )
340 {
341 componentItem->setSelected( false );
342 }
343 }
344 emit selectedItemChanged( nullptr );
345}
346
347void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item )
348{
349 whileBlocking( this )->deselectAll();
350 if ( item )
351 {
352 item->setSelected( true );
353 }
354 emit selectedItemChanged( item );
355}
356
357void QgsModelGraphicsScene::setChildAlgorithmResults( const QVariantMap &results )
358{
359 mChildResults = results;
360
361 for ( auto it = mChildResults.constBegin(); it != mChildResults.constEnd(); ++it )
362 {
363 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
364 {
365 item->setResults( it.value().toMap() );
366 }
367 }
368}
369
370void QgsModelGraphicsScene::setChildAlgorithmInputs( const QVariantMap &inputs )
371{
372 mChildInputs = inputs;
373
374 for ( auto it = mChildInputs.constBegin(); it != mChildInputs.constEnd(); ++it )
375 {
376 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
377 {
378 item->setInputs( it.value().toMap() );
379 }
380 }
381}
382
383QList<QgsModelGraphicsScene::LinkSource> QgsModelGraphicsScene::linkSourcesForParameterValue( QgsProcessingModelAlgorithm *model, const QVariant &value, const QString &childId, QgsProcessingContext &context ) const
384{
385 QList<QgsModelGraphicsScene::LinkSource> res;
386 if ( value.type() == QVariant::List )
387 {
388 const QVariantList list = value.toList();
389 for ( const QVariant &v : list )
390 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
391 }
392 else if ( value.type() == QVariant::StringList )
393 {
394 const QStringList list = value.toStringList();
395 for ( const QString &v : list )
396 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
397 }
398 else if ( value.userType() == QMetaType::type( "QgsProcessingModelChildParameterSource" ) )
399 {
400 const QgsProcessingModelChildParameterSource source = value.value< QgsProcessingModelChildParameterSource >();
401 switch ( source.source() )
402 {
403 case QgsProcessingModelChildParameterSource::ModelParameter:
404 {
405 LinkSource l;
406 l.item = mParameterItems.value( source.parameterName() );
407 res.append( l );
408 break;
409 }
410 case QgsProcessingModelChildParameterSource::ChildOutput:
411 {
412 if ( !model->childAlgorithm( source.outputChildId() ).algorithm() )
413 break;
414
415 const QgsProcessingOutputDefinitions outputs = model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions();
416 int i = 0;
417 for ( const QgsProcessingOutputDefinition *output : outputs )
418 {
419 if ( output->name() == source.outputName() )
420 break;
421 i++;
422 }
423 if ( mChildAlgorithmItems.contains( source.outputChildId() ) )
424 {
425 LinkSource l;
426 l.item = mChildAlgorithmItems.value( source.outputChildId() );
427 l.edge = Qt::BottomEdge;
428
429 // do sanity check of linked index
430 if ( i >= model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions().length() )
431 {
432 QString short_message = tr( "Check output links for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
433 QString long_message = tr( "Cannot link output for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
434 QString title( tr( "Algorithm link error" ) );
435 if ( messageBar() )
436 showWarning( const_cast<QString &>( short_message ), const_cast<QString &>( title ), const_cast<QString &>( long_message ) );
437 else
438 QgsMessageLog::logMessage( long_message, "QgsModelGraphicsScene", Qgis::MessageLevel::Warning, true );
439 break;
440 }
441
442 l.linkIndex = i;
443 res.append( l );
444 }
445
446 break;
447 }
448
449 case QgsProcessingModelChildParameterSource::Expression:
450 {
451 const QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables = model->variablesForChildAlgorithm( childId, context );
452 const QgsExpression exp( source.expression() );
453 const QSet<QString> vars = exp.referencedVariables();
454 for ( const QString &v : vars )
455 {
456 if ( variables.contains( v ) )
457 {
458 res.append( linkSourcesForParameterValue( model, QVariant::fromValue( variables.value( v ).source ), childId, context ) );
459 }
460 }
461 break;
462 }
463
464 case QgsProcessingModelChildParameterSource::StaticValue:
465 case QgsProcessingModelChildParameterSource::ExpressionText:
466 case QgsProcessingModelChildParameterSource::ModelOutput:
467 break;
468 }
469 }
470 return res;
471}
472
473void QgsModelGraphicsScene::addCommentItemForComponent( QgsProcessingModelAlgorithm *model, const QgsProcessingModelComponent &component, QgsModelComponentGraphicItem *parentItem )
474{
475 if ( mFlags & FlagHideComments || !component.comment() || component.comment()->description().isEmpty() )
476 return;
477
478 QgsModelComponentGraphicItem *commentItem = createCommentGraphicItem( model, component.comment()->clone(), parentItem );
479 commentItem->setPos( component.comment()->position().x(), component.comment()->position().y() );
480 addItem( commentItem );
481 connect( commentItem, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired );
482 connect( commentItem, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged );
483 connect( commentItem, &QgsModelComponentGraphicItem::aboutToChange, this, &QgsModelGraphicsScene::componentAboutToChange );
484
485 std::unique_ptr< QgsModelArrowItem > arrow = std::make_unique< QgsModelArrowItem >( parentItem, QgsModelArrowItem::Circle, commentItem, QgsModelArrowItem::Circle );
486 arrow->setPenStyle( Qt::DotLine );
487 addItem( arrow.release() );
488}
489
490QgsMessageBar *QgsModelGraphicsScene::messageBar() const
491{
492 return mMessageBar;
493}
494
495void QgsModelGraphicsScene::setMessageBar( QgsMessageBar *messageBar )
496{
497 mMessageBar = messageBar;
498}
499
500void QgsModelGraphicsScene::showWarning( const QString &shortMessage, const QString &title, const QString &longMessage, Qgis::MessageLevel level ) const
501{
502 QgsMessageBarItem *messageWidget = QgsMessageBar::createMessage( QString(), shortMessage );
503 QPushButton *detailsButton = new QPushButton( tr( "Details" ) );
504 connect( detailsButton, &QPushButton::clicked, detailsButton, [ = ]
505 {
506 QgsMessageViewer *dialog = new QgsMessageViewer( detailsButton );
507 dialog->setTitle( title );
508 dialog->setMessage( longMessage, QgsMessageOutput::MessageHtml );
509 dialog->showMessage();
510 } );
511 messageWidget->layout()->addWidget( detailsButton );
512 mMessageBar->clearWidgets();
513 mMessageBar->pushWidget( messageWidget, level, 0 );
514}
515
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:99
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:3914
QList< const QgsProcessingOutputDefinition * > QgsProcessingOutputDefinitions
List of processing parameters.
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.