45#include <QActionGroup>
48#include <QKeySequence>
54#include <QSvgGenerator>
60#include "moc_qgsmodeldesignerdialog.cpp"
62using namespace Qt::StringLiterals;
67QgsModelerToolboxModel::QgsModelerToolboxModel( QObject *parent )
72Qt::ItemFlags QgsModelerToolboxModel::flags(
const QModelIndex &index )
const
74 Qt::ItemFlags f = QgsProcessingToolboxProxyModel::flags( index );
75 const QModelIndex sourceIndex = mapToSource( index );
76 if ( toolboxModel()->isAlgorithm( sourceIndex ) || toolboxModel()->isParameter( sourceIndex ) )
78 f = f | Qt::ItemIsDragEnabled;
83Qt::DropActions QgsModelerToolboxModel::supportedDragActions()
const
85 return Qt::CopyAction;
88QgsModelDesignerDialog::QgsModelDesignerDialog( QWidget *parent, Qt::WindowFlags flags )
89 : QMainWindow( parent, flags )
90 , mToolsActionGroup( new QActionGroup( this ) )
98 setAttribute( Qt::WA_DeleteOnClose );
99 setDockOptions( dockOptions() | QMainWindow::GroupedDragging );
100 setWindowFlags( Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint );
104 mModel = std::make_unique<QgsProcessingModelAlgorithm>();
107 mUndoStack =
new QUndoStack(
this );
108 connect( mUndoStack, &QUndoStack::indexChanged,
this, [
this] {
109 if ( mIgnoreUndoStackChanges )
112 mBlockUndoCommands++;
113 updateVariablesGui();
114 mGroupEdit->setText( mModel->group() );
115 mNameEdit->setText( mModel->displayName() );
116 mBlockUndoCommands--;
120 mPropertiesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable );
121 mInputsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable );
122 mAlgorithmsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable );
123 mVariablesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
125 mToolboxTree->header()->setVisible(
false );
126 mToolboxSearchEdit->setShowSearchIcon(
true );
127 mToolboxSearchEdit->setPlaceholderText( tr(
"Search…" ) );
128 connect( mToolboxSearchEdit, &QgsFilterLineEdit::textChanged, mToolboxTree, &QgsProcessingToolboxTreeView::setFilterString );
130 mInputsTreeWidget->header()->setVisible(
false );
131 mInputsTreeWidget->setAlternatingRowColors(
true );
132 mInputsTreeWidget->setDragDropMode( QTreeWidget::DragOnly );
133 mInputsTreeWidget->setDropIndicatorShown(
true );
135 mNameEdit->setPlaceholderText( tr(
"Enter model name here" ) );
136 mGroupEdit->setPlaceholderText( tr(
"Enter group name here" ) );
139 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
140 mainLayout->insertWidget( 0, mMessageBar );
142 mView->setAcceptDrops(
true );
145 connect( mActionClose, &QAction::triggered,
this, &QWidget::close );
146 connect( mActionNew, &QAction::triggered,
this, &QgsModelDesignerDialog::newModel );
147 connect( mActionZoomIn, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomIn );
148 connect( mActionZoomOut, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomOut );
149 connect( mActionZoomActual, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomActual );
150 connect( mActionZoomToItems, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomFull );
151 connect( mActionExportImage, &QAction::triggered,
this, &QgsModelDesignerDialog::exportToImage );
152 connect( mActionExportPdf, &QAction::triggered,
this, &QgsModelDesignerDialog::exportToPdf );
153 connect( mActionExportSvg, &QAction::triggered,
this, &QgsModelDesignerDialog::exportToSvg );
154 connect( mActionExportPython, &QAction::triggered,
this, &QgsModelDesignerDialog::exportAsPython );
155 connect( mActionSave, &QAction::triggered,
this, [
this] { saveModel(
false ); } );
156 connect( mActionSaveAs, &QAction::triggered,
this, [
this] { saveModel(
true ); } );
157 connect( mActionDeleteComponents, &QAction::triggered,
this, &QgsModelDesignerDialog::deleteSelected );
158 connect( mActionSnapSelected, &QAction::triggered, mView, &QgsModelGraphicsView::snapSelected );
159 connect( mActionValidate, &QAction::triggered,
this, &QgsModelDesignerDialog::validate );
160 connect( mActionReorderInputs, &QAction::triggered,
this, &QgsModelDesignerDialog::reorderInputs );
161 connect( mActionReorderOutputs, &QAction::triggered,
this, &QgsModelDesignerDialog::reorderOutputs );
162 connect( mActionEditHelp, &QAction::triggered,
this, &QgsModelDesignerDialog::editHelp );
163 connect( mReorderInputsButton, &QPushButton::clicked,
this, &QgsModelDesignerDialog::reorderInputs );
164 connect( mActionRun, &QAction::triggered,
this, [
this] { run(); } );
165 connect( mActionRunSelectedSteps, &QAction::triggered,
this, &QgsModelDesignerDialog::runSelectedSteps );
167 mActionSnappingEnabled->setChecked( settings.
value( u
"/Processing/Modeler/enableSnapToGrid"_s,
false ).toBool() );
168 connect( mActionSnappingEnabled, &QAction::toggled,
this, [
this](
bool enabled ) {
169 mView->snapper()->setSnapToGrid( enabled );
172 mView->snapper()->setSnapToGrid( mActionSnappingEnabled->isChecked() );
174 connect( mActionSelectAll, &QAction::triggered,
this, [
this] {
178 QStringList docksTitle = settings.
value( u
"ModelDesigner/hiddenDocksTitle"_s, QStringList(),
QgsSettings::App ).toStringList();
179 QStringList docksActive = settings.
value( u
"ModelDesigner/hiddenDocksActive"_s, QStringList(),
QgsSettings::App ).toStringList();
180 if ( !docksTitle.isEmpty() )
182 for (
const auto &title : docksTitle )
184 mPanelStatus.insert( title, PanelStatus(
true, docksActive.contains( title ) ) );
187 mActionHidePanels->setChecked( !docksTitle.isEmpty() );
188 connect( mActionHidePanels, &QAction::toggled,
this, &QgsModelDesignerDialog::setPanelVisibility );
190 mUndoAction = mUndoStack->createUndoAction(
this );
192 mUndoAction->setShortcuts( QKeySequence::Undo );
193 mRedoAction = mUndoStack->createRedoAction(
this );
195 mRedoAction->setShortcuts( QKeySequence::Redo );
197 mMenuEdit->insertAction( mActionDeleteComponents, mRedoAction );
198 mMenuEdit->insertAction( mActionDeleteComponents, mUndoAction );
199 mMenuEdit->insertSeparator( mActionDeleteComponents );
200 mToolbar->insertAction( mActionZoomIn, mUndoAction );
201 mToolbar->insertAction( mActionZoomIn, mRedoAction );
202 mToolbar->insertSeparator( mActionZoomIn );
204 mGroupMenu =
new QMenu( tr(
"Zoom To" ),
this );
205 mMenuView->insertMenu( mActionZoomIn, mGroupMenu );
206 connect( mGroupMenu, &QMenu::aboutToShow,
this, &QgsModelDesignerDialog::populateZoomToMenu );
210 mActionCut =
new QAction( tr(
"Cu&t" ),
this );
211 mActionCut->setShortcuts( QKeySequence::Cut );
212 mActionCut->setStatusTip( tr(
"Cut" ) );
214 connect( mActionCut, &QAction::triggered,
this, [
this] {
215 mView->copySelectedItems( QgsModelGraphicsView::ClipboardCut );
218 mActionCopy =
new QAction( tr(
"&Copy" ),
this );
219 mActionCopy->setShortcuts( QKeySequence::Copy );
220 mActionCopy->setStatusTip( tr(
"Copy" ) );
222 connect( mActionCopy, &QAction::triggered,
this, [
this] {
223 mView->copySelectedItems( QgsModelGraphicsView::ClipboardCopy );
226 mActionPaste =
new QAction( tr(
"&Paste" ),
this );
227 mActionPaste->setShortcuts( QKeySequence::Paste );
228 mActionPaste->setStatusTip( tr(
"Paste" ) );
230 connect( mActionPaste, &QAction::triggered,
this, [
this] {
231 mView->pasteItems( QgsModelGraphicsView::PasteModeCursor );
233 mMenuEdit->insertAction( mActionDeleteComponents, mActionCut );
234 mMenuEdit->insertAction( mActionDeleteComponents, mActionCopy );
235 mMenuEdit->insertAction( mActionDeleteComponents, mActionPaste );
236 mMenuEdit->insertSeparator( mActionDeleteComponents );
238 mAlgorithmsModel =
new QgsModelerToolboxModel(
this );
239 mToolboxTree->setToolboxProxyModel( mAlgorithmsModel );
242 if ( settings.
value( u
"Processing/Configuration/SHOW_ALGORITHMS_KNOWN_ISSUES"_s,
false ).toBool() )
246 mToolboxTree->setFilters( filters );
247 mToolboxTree->setDragDropMode( QTreeWidget::DragOnly );
248 mToolboxTree->setDropIndicatorShown(
true );
250 connect( mView, &QgsModelGraphicsView::algorithmDropped,
this, [
this](
const QString &algorithmId,
const QPointF &pos ) {
251 addAlgorithm( algorithmId, pos );
253 connect( mView, &QgsModelGraphicsView::inputDropped,
this, &QgsModelDesignerDialog::addInput );
255 connect( mToolboxTree, &QgsProcessingToolboxTreeView::doubleClicked,
this, [
this](
const QModelIndex & ) {
256 if ( mToolboxTree->selectedAlgorithm() )
257 addAlgorithm( mToolboxTree->selectedAlgorithm()->id(), QPointF() );
258 if ( mToolboxTree->selectedParameterType() )
259 addInput( mToolboxTree->selectedParameterType()->id(), QPointF() );
262 connect( mInputsTreeWidget, &QgsModelDesignerInputsTreeWidget::doubleClicked,
this, [
this](
const QModelIndex & ) {
263 const QString parameterType = mInputsTreeWidget->currentItem()->data( 0, Qt::UserRole ).toString();
264 addInput( parameterType, QPointF() );
268 QShortcut *ctrlEquals =
new QShortcut( QKeySequence( u
"Ctrl+="_s ),
this );
269 connect( ctrlEquals, &QShortcut::activated,
this, &QgsModelDesignerDialog::zoomIn );
272 mUndoDock->setObjectName( u
"UndoDock"_s );
273 mUndoView =
new QUndoView( mUndoStack,
this );
274 mUndoDock->setWidget( mUndoView );
275 mUndoDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
276 addDockWidget( Qt::DockWidgetArea::LeftDockWidgetArea, mUndoDock );
278 tabifyDockWidget( mUndoDock, mPropertiesDock );
279 tabifyDockWidget( mVariablesDock, mPropertiesDock );
280 mPropertiesDock->raise();
281 tabifyDockWidget( mInputsDock, mAlgorithmsDock );
282 mInputsDock->raise();
287 beginUndoCommand( tr(
"Change Model Variables" ) );
288 mModel->setVariables( mVariablesEditor->variablesInActiveScope() );
292 connect( mNameEdit, &QLineEdit::textChanged,
this, [
this](
const QString &name ) {
295 beginUndoCommand( tr(
"Change Model Name" ), NameChanged );
296 mModel->setName( name );
301 connect( mGroupEdit, &QLineEdit::textChanged,
this, [
this](
const QString &group ) {
304 beginUndoCommand( tr(
"Change Model Group" ), GroupChanged );
305 mModel->setGroup( group );
313 QToolButton *toolbuttonExportToScript =
new QToolButton();
314 toolbuttonExportToScript->setPopupMode( QToolButton::InstantPopup );
315 toolbuttonExportToScript->addAction( mActionExportAsScriptAlgorithm );
316 toolbuttonExportToScript->setDefaultAction( mActionExportAsScriptAlgorithm );
317 mToolbar->insertWidget( mActionExportImage, toolbuttonExportToScript );
318 connect( mActionExportAsScriptAlgorithm, &QAction::triggered,
this, &QgsModelDesignerDialog::exportAsScriptAlgorithm );
320 mActionShowComments->setChecked( settings.
value( u
"/Processing/Modeler/ShowComments"_s,
true ).toBool() );
321 connect( mActionShowComments, &QAction::toggled,
this, &QgsModelDesignerDialog::toggleComments );
323 mActionShowFeatureCount->setChecked( settings.
value( u
"/Processing/Modeler/ShowFeatureCount"_s,
true ).toBool() );
324 connect( mActionShowFeatureCount, &QAction::toggled,
this, &QgsModelDesignerDialog::toggleFeatureCount );
327 mPanTool->setAction( mActionPan );
329 mToolsActionGroup->addAction( mActionPan );
330 connect( mActionPan, &QAction::triggered, mPanTool, [
this] { mView->setTool( mPanTool ); } );
333 mSelectTool->setAction( mActionSelectMoveItem );
335 mToolsActionGroup->addAction( mActionSelectMoveItem );
336 connect( mActionSelectMoveItem, &QAction::triggered, mSelectTool, [
this] { mView->setTool( mSelectTool ); } );
338 mView->setTool( mSelectTool );
341 connect( mView, &QgsModelGraphicsView::macroCommandStarted,
this, [
this](
const QString &text ) {
342 mIgnoreUndoStackChanges++;
343 mUndoStack->beginMacro( text );
344 mIgnoreUndoStackChanges--;
346 connect( mView, &QgsModelGraphicsView::macroCommandEnded,
this, [
this] {
347 mIgnoreUndoStackChanges++;
348 mUndoStack->endMacro();
349 mIgnoreUndoStackChanges--;
351 connect( mView, &QgsModelGraphicsView::commandBegun,
this, [
this](
const QString &text ) {
352 beginUndoCommand( text );
354 connect( mView, &QgsModelGraphicsView::commandEnded,
this, [
this] {
357 connect( mView, &QgsModelGraphicsView::commandAborted,
this, [
this] {
360 connect( mView, &QgsModelGraphicsView::deleteSelectedItems,
this, [
this] {
364 connect( mActionAddGroupBox, &QAction::triggered,
this, [
this] {
365 const QPointF viewCenter = mView->mapToScene( mView->viewport()->rect().center() );
366 QgsProcessingModelGroupBox group;
367 group.setPosition( viewCenter );
368 group.setDescription( tr(
"New Group" ) );
370 beginUndoCommand( tr(
"Add Group Box" ) );
371 model()->addGroupBox( group );
379 restoreState( settings.
value( u
"ModelDesigner/state"_s, QByteArray(),
QgsSettings::App ).toByteArray() );
382QgsModelDesignerDialog::~QgsModelDesignerDialog()
385 if ( !mPanelStatus.isEmpty() )
387 QStringList docksTitle;
388 QStringList docksActive;
390 for (
const auto &panel : mPanelStatus.toStdMap() )
392 if ( panel.second.isVisible )
393 docksTitle << panel.first;
394 if ( panel.second.isActive )
395 docksActive << panel.first;
409 mIgnoreUndoStackChanges++;
413void QgsModelDesignerDialog::closeEvent( QCloseEvent *event )
415 if ( checkForUnsavedChanges() )
421void QgsModelDesignerDialog::beginUndoCommand(
const QString &text,
int id )
423 if ( mBlockUndoCommands || !mUndoStack )
426 if ( mActiveCommand )
429 mActiveCommand = std::make_unique<QgsModelUndoCommand>( mModel.get(), text,
id );
432void QgsModelDesignerDialog::endUndoCommand()
434 if ( mBlockUndoCommands || !mActiveCommand || !mUndoStack )
437 mActiveCommand->saveAfterState();
438 mIgnoreUndoStackChanges++;
439 mUndoStack->push( mActiveCommand.release() );
440 mIgnoreUndoStackChanges--;
444void QgsModelDesignerDialog::abortUndoCommand()
446 if ( mActiveCommand )
447 mActiveCommand->setObsolete(
true );
450QgsProcessingModelAlgorithm *QgsModelDesignerDialog::model()
455void QgsModelDesignerDialog::setModel( QgsProcessingModelAlgorithm *model )
457 mModel.reset( model );
459 mGroupEdit->setText( mModel->group() );
460 mNameEdit->setText( mModel->displayName() );
461 repaintModel(
true );
462 updateVariablesGui();
464 mView->centerOn( 0, 0 );
467 mIgnoreUndoStackChanges++;
469 mIgnoreUndoStackChanges--;
474void QgsModelDesignerDialog::loadModel(
const QString &path )
476 auto alg = std::make_unique<QgsProcessingModelAlgorithm>();
477 if ( alg->fromFile( path ) )
480 alg->setSourceFilePath( path );
481 setModel( alg.release() );
486 QMessageBox::critical(
this, tr(
"Open Model" ), tr(
"The selected model could not be loaded.\n"
487 "See the log for more information." ) );
491void QgsModelDesignerDialog::setModelScene( QgsModelGraphicsScene *scene )
493 QgsModelGraphicsScene *oldScene = mScene;
496 mScene->setParent(
this );
497 mScene->setLastRunResult( mLastResult, mLayerStore );
498 mScene->setModel( mModel.get() );
499 mScene->setMessageBar( mMessageBar );
502 const bool showFeatureCount = settings.
value( u
"/Processing/Modeler/ShowFeatureCount"_s,
true ).toBool();
503 if ( !showFeatureCount )
504 mScene->setFlag( QgsModelGraphicsScene::FlagHideFeatureCount );
506 mView->setModelScene( mScene );
508 mSelectTool->resetCache();
509 mSelectTool->setScene( mScene );
511 connect( mScene, &QgsModelGraphicsScene::rebuildRequired,
this, [
this] {
512 if ( mBlockRepaints )
517 connect( mScene, &QgsModelGraphicsScene::componentAboutToChange,
this, [
this](
const QString &description,
int id ) { beginUndoCommand( description,
id ); } );
518 connect( mScene, &QgsModelGraphicsScene::componentChanged,
this, [
this] { endUndoCommand(); } );
519 connect( mScene, &QgsModelGraphicsScene::runFromChild,
this, &QgsModelDesignerDialog::runFromChild );
520 connect( mScene, &QgsModelGraphicsScene::runSelected,
this, &QgsModelDesignerDialog::runSelectedSteps );
521 connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmOutputs,
this, &QgsModelDesignerDialog::showChildAlgorithmOutputs );
522 connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmLog,
this, &QgsModelDesignerDialog::showChildAlgorithmLog );
525 oldScene->deleteLater();
528void QgsModelDesignerDialog::activate()
532 setWindowState( windowState() & ~Qt::WindowMinimized );
536void QgsModelDesignerDialog::updateVariablesGui()
538 mBlockUndoCommands++;
540 auto variablesScope = std::make_unique<QgsExpressionContextScope>( tr(
"Model Variables" ) );
541 const QVariantMap modelVars = mModel->variables();
542 for (
auto it = modelVars.constBegin(); it != modelVars.constEnd(); ++it )
544 variablesScope->setVariable( it.key(), it.value() );
547 variablesContext.
appendScope( variablesScope.release() );
548 mVariablesEditor->setContext( &variablesContext );
549 mVariablesEditor->setEditableScopeIndex( 0 );
551 mBlockUndoCommands--;
554void QgsModelDesignerDialog::setDirty(
bool dirty )
560bool QgsModelDesignerDialog::validateSave( SaveAction action )
564 case QgsModelDesignerDialog::SaveAction::SaveAsFile:
566 case QgsModelDesignerDialog::SaveAction::SaveInProject:
567 if ( mNameEdit->text().trimmed().isEmpty() )
569 mMessageBar->pushWarning( QString(), tr(
"Please enter a model name before saving" ) );
578bool QgsModelDesignerDialog::checkForUnsavedChanges()
582 QMessageBox::StandardButton ret = QMessageBox::question(
this, tr(
"Save Model?" ), tr(
"There are unsaved changes in this model. Do you want to keep those?" ), QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard, QMessageBox::Cancel );
585 case QMessageBox::Save:
586 return saveModel(
false );
588 case QMessageBox::Discard:
603 mLastResult.mergeWith( result );
605 mScene->setLastRunResult( mLastResult, mLayerStore );
608void QgsModelDesignerDialog::setModelName(
const QString &name )
610 mNameEdit->setText( name );
613void QgsModelDesignerDialog::zoomIn()
615 mView->setTransformationAnchor( QGraphicsView::NoAnchor );
616 QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
618 const double factor = settings.
value( u
"/qgis/zoom_favor"_s, 2.0 ).toDouble();
619 mView->scale( factor, factor );
620 mView->centerOn( point );
623void QgsModelDesignerDialog::zoomOut()
625 mView->setTransformationAnchor( QGraphicsView::NoAnchor );
626 QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
628 const double factor = 1.0 / settings.
value( u
"/qgis/zoom_favor"_s, 2.0 ).toDouble();
629 mView->scale( factor, factor );
630 mView->centerOn( point );
633void QgsModelDesignerDialog::zoomActual()
635 QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
636 mView->resetTransform();
637 mView->scale( mScreenHelper->screenDpi() / 96, mScreenHelper->screenDpi() / 96 );
638 mView->centerOn( point );
641void QgsModelDesignerDialog::zoomFull()
643 QRectF totalRect = mView->scene()->itemsBoundingRect();
644 totalRect.adjust( -10, -10, 10, 10 );
645 mView->fitInView( totalRect, Qt::KeepAspectRatio );
648void QgsModelDesignerDialog::newModel()
650 if ( !checkForUnsavedChanges() )
653 auto alg = std::make_unique<QgsProcessingModelAlgorithm>();
655 setModel( alg.release() );
658void QgsModelDesignerDialog::exportToImage()
661 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
663 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as Image" ), lastExportDir, tr(
"PNG files (*.png *.PNG)" ) );
667 if ( filename.isEmpty() )
672 const QFileInfo saveFileInfo( filename );
675 repaintModel(
false );
677 QRectF totalRect = mView->scene()->itemsBoundingRect();
678 totalRect.adjust( -10, -10, 10, 10 );
679 const QRectF imageRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
681 QImage img( totalRect.width(), totalRect.height(), QImage::Format_ARGB32_Premultiplied );
682 img.fill( Qt::white );
684 painter.setRenderHint( QPainter::Antialiasing );
685 painter.begin( &img );
686 mView->scene()->render( &painter, imageRect, totalRect );
689 img.save( filename );
691 mMessageBar->pushMessage( QString(), tr(
"Successfully exported model as image to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( filename ).toString(), QDir::toNativeSeparators( filename ) ),
Qgis::MessageLevel::Success, 0 );
692 repaintModel(
true );
695void QgsModelDesignerDialog::exportToPdf()
698 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
700 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as PDF" ), lastExportDir, tr(
"PDF files (*.pdf *.PDF)" ) );
704 if ( filename.isEmpty() )
709 const QFileInfo saveFileInfo( filename );
712 repaintModel(
false );
714 QRectF totalRect = mView->scene()->itemsBoundingRect();
715 totalRect.adjust( -10, -10, 10, 10 );
716 const QRectF printerRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
718 QPdfWriter pdfWriter( filename );
720 const double scaleFactor = 96 / 25.4;
722 QPageLayout pageLayout( QPageSize( totalRect.size() / scaleFactor, QPageSize::Millimeter ), QPageLayout::Portrait, QMarginsF( 0, 0, 0, 0 ) );
723 pageLayout.setMode( QPageLayout::FullPageMode );
724 pdfWriter.setPageLayout( pageLayout );
726 QPainter painter( &pdfWriter );
727 mView->scene()->render( &painter, printerRect, totalRect );
730 mMessageBar->pushMessage( QString(), tr(
"Successfully exported model as PDF to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( filename ).toString(), QDir::toNativeSeparators( filename ) ),
Qgis::MessageLevel::Success, 0 );
731 repaintModel(
true );
734void QgsModelDesignerDialog::exportToSvg()
737 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
739 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as SVG" ), lastExportDir, tr(
"SVG files (*.svg *.SVG)" ) );
743 if ( filename.isEmpty() )
748 const QFileInfo saveFileInfo( filename );
751 repaintModel(
false );
753 QRectF totalRect = mView->scene()->itemsBoundingRect();
754 totalRect.adjust( -10, -10, 10, 10 );
755 const QRectF svgRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
758 svg.setFileName( filename );
759 svg.setSize( QSize( totalRect.width(), totalRect.height() ) );
760 svg.setViewBox( svgRect );
761 svg.setTitle( mModel->displayName() );
763 QPainter painter( &svg );
764 mView->scene()->render( &painter, svgRect, totalRect );
767 mMessageBar->pushMessage( QString(), tr(
"Successfully exported model as SVG to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( filename ).toString(), QDir::toNativeSeparators( filename ) ),
Qgis::MessageLevel::Success, 0 );
768 repaintModel(
true );
771void QgsModelDesignerDialog::exportAsPython()
774 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
776 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as Python Script" ), lastExportDir, tr(
"Processing scripts (*.py *.PY)" ) );
780 if ( filename.isEmpty() )
785 const QFileInfo saveFileInfo( filename );
790 QFile outFile( filename );
791 if ( !outFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
795 QTextStream fout( &outFile );
799 mMessageBar->pushMessage( QString(), tr(
"Successfully exported model as Python script to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( filename ).toString(), QDir::toNativeSeparators( filename ) ),
Qgis::MessageLevel::Success, 0 );
802void QgsModelDesignerDialog::toggleComments(
bool show )
806 repaintModel(
true );
809void QgsModelDesignerDialog::toggleFeatureCount(
bool show )
813 repaintModel(
true );
816void QgsModelDesignerDialog::updateWindowTitle()
818 QString title = tr(
"Model Designer" );
819 if ( !mModel->name().isEmpty() )
820 title = mModel->group().isEmpty()
821 ? u
"%1: %2"_s.arg( title, mModel->name() )
822 : u
"%1: %2 - %3"_s.arg( title, mModel->group(), mModel->name() );
825 title.prepend(
'*' );
827 setWindowTitle( title );
830void QgsModelDesignerDialog::deleteSelected()
832 QList<QgsModelComponentGraphicItem *> items = mScene->selectedComponentItems();
836 if ( items.size() == 1 )
838 items.at( 0 )->deleteComponent();
842 std::sort( items.begin(), items.end(), []( QgsModelComponentGraphicItem *p1, QgsModelComponentGraphicItem *p2 ) {
847 if ( dynamic_cast<QgsModelCommentGraphicItem *>( p1 ) && dynamic_cast<QgsModelCommentGraphicItem *>( p2 ) )
849 else if ( dynamic_cast<QgsModelCommentGraphicItem *>( p1 ) )
851 else if ( dynamic_cast<QgsModelCommentGraphicItem *>( p2 ) )
854 else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p1 ) && dynamic_cast<QgsModelGroupBoxGraphicItem *>( p2 ) )
856 else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p1 ) )
858 else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p2 ) )
861 else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p1 ) && dynamic_cast<QgsModelOutputGraphicItem *>( p2 ) )
863 else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p1 ) )
865 else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p2 ) )
868 else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p1 ) && dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p2 ) )
870 else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p1 ) )
872 else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p2 ) )
879 beginUndoCommand( tr(
"Delete Components" ) );
881 QVariant prevState = mModel->toVariant();
882 mBlockUndoCommands++;
883 mBlockRepaints =
true;
885 while ( !items.empty() )
887 QgsModelComponentGraphicItem *toDelete =
nullptr;
888 for ( QgsModelComponentGraphicItem *item : items )
890 if ( item->canDeleteComponent() )
903 toDelete->deleteComponent();
904 items.removeAll( toDelete );
909 mModel->loadVariant( prevState );
910 QMessageBox::warning(
nullptr, QObject::tr(
"Could not remove components" ), QObject::tr(
"Components depend on the selected items.\n"
911 "Try to remove them before trying deleting these components." ) );
912 mBlockUndoCommands--;
913 mActiveCommand.reset();
917 mBlockUndoCommands--;
921 mBlockRepaints =
false;
925void QgsModelDesignerDialog::populateZoomToMenu()
928 for (
const QgsProcessingModelGroupBox &box : model()->groupBoxes() )
930 if ( QgsModelComponentGraphicItem *item = mScene->groupBoxItem( box.uuid() ) )
932 QAction *zoomAction =
new QAction( box.description(), mGroupMenu );
933 connect( zoomAction, &QAction::triggered,
this, [
this, item] {
934 QRectF groupRect = item->mapToScene( item->boundingRect() ).boundingRect();
935 groupRect.adjust( -10, -10, 10, 10 );
936 mView->fitInView( groupRect, Qt::KeepAspectRatio );
937 mView->centerOn( item );
939 mGroupMenu->addAction( zoomAction );
944void QgsModelDesignerDialog::setPanelVisibility(
bool hidden )
946 const QList<QDockWidget *> docks = findChildren<QDockWidget *>();
947 const QList<QTabBar *> tabBars = findChildren<QTabBar *>();
951 mPanelStatus.clear();
953 for ( QDockWidget *dock : docks )
955 mPanelStatus.insert( dock->windowTitle(), PanelStatus( dock->isVisible(),
false ) );
956 dock->setVisible(
false );
960 for ( QTabBar *tabBar : tabBars )
962 QString currentTabTitle = tabBar->tabText( tabBar->currentIndex() );
963 mPanelStatus[currentTabTitle].isActive =
true;
969 for ( QDockWidget *dock : docks )
971 if ( mPanelStatus.contains( dock->windowTitle() ) )
973 dock->setVisible( mPanelStatus.value( dock->windowTitle() ).isVisible );
978 for ( QTabBar *tabBar : tabBars )
981 for (
int i = 0; i < tabBar->count(); ++i )
983 QString tabTitle = tabBar->tabText( i );
984 if ( mPanelStatus.contains( tabTitle ) && mPanelStatus.value( tabTitle ).isActive )
986 tabBar->setCurrentIndex( i );
990 mPanelStatus.clear();
994void QgsModelDesignerDialog::editHelp()
996 QgsProcessingHelpEditorDialog dialog(
this );
997 dialog.setWindowTitle( tr(
"Edit Model Help" ) );
998 dialog.setAlgorithm( mModel.get() );
1001 beginUndoCommand( tr(
"Edit Model Help" ) );
1002 mModel->setHelpContent( dialog.helpContent() );
1007void QgsModelDesignerDialog::runSelectedSteps()
1009 QSet<QString> children;
1010 const QList<QgsModelComponentGraphicItem *> items = mScene->selectedComponentItems();
1011 for ( QgsModelComponentGraphicItem *item : items )
1013 if ( QgsProcessingModelChildAlgorithm *childAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( item->component() ) )
1015 children.insert( childAlgorithm->childId() );
1019 if ( children.isEmpty() )
1021 mMessageBar->pushWarning( QString(), tr(
"No steps are selected" ) );
1028void QgsModelDesignerDialog::runFromChild(
const QString &
id )
1030 QSet<QString> children = mModel->dependentChildAlgorithms(
id );
1031 children.insert(
id );
1035void QgsModelDesignerDialog::run(
const QSet<QString> &childAlgorithmSubset )
1038 const bool isValid = model()->validate( errors );
1041 QMessageBox messageBox;
1042 messageBox.setWindowTitle( tr(
"Model is Invalid" ) );
1043 messageBox.setIcon( QMessageBox::Icon::Warning );
1044 messageBox.setText( tr(
"This model is not valid and contains one or more issues. Are you sure you want to run it in this state?" ) );
1045 messageBox.setStandardButtons( QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::Cancel );
1046 messageBox.setDefaultButton( QMessageBox::StandardButton::Cancel );
1048 QString errorString;
1049 for (
const QString &error : std::as_const( errors ) )
1051 QString cleanedError = error;
1052 const thread_local QRegularExpression re( u
"<[^>]*>"_s );
1053 cleanedError.replace( re, QString() );
1054 errorString += u
"• %1\n"_s.arg( cleanedError );
1057 messageBox.setDetailedText( errorString );
1058 if ( messageBox.exec() == QMessageBox::StandardButton::Cancel )
1062 if ( !childAlgorithmSubset.isEmpty() )
1064 for (
const QString &child : childAlgorithmSubset )
1067 const QSet<QString> requirements = mModel->dependsOnChildAlgorithms( child );
1068 for (
const QString &requirement : requirements )
1070 if ( !mLastResult.executedChildIds().contains( requirement ) )
1072 QMessageBox messageBox;
1073 messageBox.setWindowTitle( tr(
"Run Model" ) );
1074 messageBox.setIcon( QMessageBox::Icon::Warning );
1075 messageBox.setText( tr(
"Prerequisite parts of this model have not yet been run (try running the full model first)." ) );
1076 messageBox.setStandardButtons( QMessageBox::StandardButton::Ok );
1084 std::unique_ptr<QgsProcessingAlgorithmDialogBase> dialog( createExecutionDialog() );
1089 dialog->setParameters( mModel->designerParameterValues() );
1091 connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmAboutToRun,
this, [
this, &childAlgorithmSubset](
QgsProcessingContext *context ) {
1092 if ( !childAlgorithmSubset.empty() )
1095 auto modelConfig = std::make_unique<QgsProcessingModelInitialRunConfig>();
1096 modelConfig->setChildAlgorithmSubset( childAlgorithmSubset );
1097 modelConfig->setPreviouslyExecutedChildAlgorithms( mLastResult.executedChildIds() );
1098 modelConfig->setInitialChildInputs( mLastResult.rawChildInputs() );
1099 modelConfig->setInitialChildOutputs( mLastResult.rawChildOutputs() );
1103 const QMap<QString, QgsMapLayer *> previousOutputLayers = mLayerStore.temporaryLayerStore()->mapLayers();
1104 auto previousResultStore = std::make_unique<QgsMapLayerStore>();
1105 for ( auto it = previousOutputLayers.constBegin(); it != previousOutputLayers.constEnd(); ++it )
1107 std::unique_ptr<QgsMapLayer> clone( it.value()->clone() );
1108 clone->setId( it.value()->id() );
1109 previousResultStore->addMapLayer( clone.release() );
1111 previousResultStore->moveToThread( nullptr );
1112 modelConfig->setPreviousLayerStore( std::move( previousResultStore ) );
1113 context->setModelInitialRunConfig( std::move( modelConfig ) );
1117 connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmFinished,
this, [
this, &dialog](
bool,
const QVariantMap & ) {
1118 QgsProcessingContext *context = dialog->processingContext();
1120 mLayerStore.temporaryLayerStore()->removeAllMapLayers();
1121 mLayerStore.takeResultsFrom( *context );
1123 mModel->setDesignerParameterValues( dialog->createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipDefaultValueParameters ) );
1124 setLastRunResult( context->modelResult() );
1130void QgsModelDesignerDialog::showChildAlgorithmOutputs(
const QString &childId )
1132 const QString childDescription = mModel->childAlgorithm( childId ).description();
1135 const QVariantMap childAlgorithmOutputs = result.
outputs();
1136 if ( childAlgorithmOutputs.isEmpty() )
1138 mMessageBar->pushWarning( QString(), tr(
"No results are available for %1" ).arg( childDescription ) );
1145 mMessageBar->pushCritical( QString(), tr(
"Results cannot be shown for an invalid model component" ) );
1149 const QList<const QgsProcessingParameterDefinition *> outputParams =
algorithm->destinationParameterDefinitions();
1150 if ( outputParams.isEmpty() )
1153 QgsDebugError(
"Cannot show results for algorithms with no outputs" );
1157 bool foundResults =
false;
1160 const QVariant output = childAlgorithmOutputs.value( outputParam->name() );
1161 if ( !output.isValid() )
1164 if ( output.type() == QVariant::String )
1168 QgsDebugMsgLevel( u
"Loading previous result for %1: %2"_s.arg( outputParam->name(), output.toString() ), 2 );
1170 std::unique_ptr<QgsMapLayer> layer( resultLayer->clone() );
1173 if ( outputParams.size() > 1 )
1174 baseName = tr(
"%1 — %2" ).arg( childDescription, outputParam->name() );
1176 baseName = childDescription;
1180 QString name = baseName;
1185 name = tr(
"%1 (%2)" ).arg( baseName ).arg( counter );
1188 layer->setName( name );
1191 foundResults =
true;
1196 QgsDebugError( u
"Could not load previous result for %1: %2"_s.arg( outputParam->name(), output.toString() ) );
1201 if ( !foundResults )
1203 mMessageBar->pushWarning( QString(), tr(
"No results are available for %1" ).arg( childDescription ) );
1208void QgsModelDesignerDialog::showChildAlgorithmLog(
const QString &childId )
1210 const QString childDescription = mModel->childAlgorithm( childId ).description();
1213 if ( result.
htmlLog().isEmpty() )
1215 mMessageBar->pushWarning( QString(), tr(
"No log is available for %1" ).arg( childDescription ) );
1220 m.setWindowTitle( childDescription );
1221 m.setCheckBoxVisible(
false );
1222 m.setMessageAsHtml( result.
htmlLog() );
1226void QgsModelDesignerDialog::validate()
1229 if ( model()->validate( issues ) )
1231 mMessageBar->pushSuccess( QString(), tr(
"Model is valid!" ) );
1236 QPushButton *detailsButton =
new QPushButton( tr(
"Details" ) );
1237 connect( detailsButton, &QPushButton::clicked, detailsButton, [detailsButton, issues] {
1239 dialog->
setTitle( tr(
"Model is Invalid" ) );
1241 QString longMessage = tr(
"<p>This model is not valid:</p>" ) + u
"<ul>"_s;
1242 for (
const QString &issue : issues )
1244 longMessage += u
"<li>%1</li>"_s.arg( issue );
1246 longMessage +=
"</ul>"_L1;
1251 messageWidget->layout()->addWidget( detailsButton );
1252 mMessageBar->clearWidgets();
1257void QgsModelDesignerDialog::reorderInputs()
1259 QgsModelInputReorderDialog dlg(
this );
1260 dlg.setModel( mModel.get() );
1263 const QStringList inputOrder = dlg.inputOrder();
1264 beginUndoCommand( tr(
"Reorder Inputs" ) );
1265 mModel->setParameterOrder( inputOrder );
1270void QgsModelDesignerDialog::reorderOutputs()
1272 QgsModelOutputReorderDialog dlg(
this );
1273 dlg.setModel( mModel.get() );
1276 const QStringList outputOrder = dlg.outputOrder();
1277 beginUndoCommand( tr(
"Reorder Outputs" ) );
1278 mModel->setOutputOrder( outputOrder );
1279 mModel->setOutputGroup( dlg.outputGroup() );
1284bool QgsModelDesignerDialog::isDirty()
const
1286 return mHasChanged && mUndoStack->index() != -1;
1289void QgsModelDesignerDialog::fillInputsTree()
1292 auto parametersItem = std::make_unique<QTreeWidgetItem>();
1293 parametersItem->setText( 0, tr(
"Parameters" ) );
1296 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
1303 auto paramItem = std::make_unique<QTreeWidgetItem>();
1304 paramItem->setText( 0, param->name() );
1305 paramItem->setData( 0, Qt::UserRole, param->id() );
1306 paramItem->setIcon( 0, icon );
1307 paramItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
1308 paramItem->setToolTip( 0, param->description() );
1309 parametersItem->addChild( paramItem.release() );
1312 mInputsTreeWidget->addTopLevelItem( parametersItem.release() );
1313 mInputsTreeWidget->topLevelItem( 0 )->setExpanded(
true );
1321QgsModelChildDependenciesWidget::QgsModelChildDependenciesWidget( QWidget *parent, QgsProcessingModelAlgorithm *model,
const QString &childId )
1324 , mChildId( childId )
1326 QHBoxLayout *hl =
new QHBoxLayout();
1327 hl->setContentsMargins( 0, 0, 0, 0 );
1329 mLineEdit =
new QLineEdit();
1330 mLineEdit->setEnabled(
false );
1331 hl->addWidget( mLineEdit, 1 );
1333 mToolButton =
new QToolButton();
1334 mToolButton->setText( QString( QChar( 0x2026 ) ) );
1335 hl->addWidget( mToolButton );
1339 mLineEdit->setText( tr(
"%1 dependencies selected" ).arg( 0 ) );
1341 connect( mToolButton, &QToolButton::clicked,
this, &QgsModelChildDependenciesWidget::showDialog );
1344void QgsModelChildDependenciesWidget::setValue(
const QList<QgsProcessingModelChildDependency> &value )
1348 updateSummaryText();
1351void QgsModelChildDependenciesWidget::showDialog()
1353 const QList<QgsProcessingModelChildDependency> available = mModel->availableDependenciesForChildAlgorithm( mChildId );
1355 QVariantList availableOptions;
1356 for (
const QgsProcessingModelChildDependency &dep : available )
1357 availableOptions << QVariant::fromValue( dep );
1358 QVariantList selectedOptions;
1359 for (
const QgsProcessingModelChildDependency &dep : mValue )
1360 selectedOptions << QVariant::fromValue( dep );
1365 QgsProcessingMultipleSelectionPanelWidget *widget =
new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
1366 widget->setPanelTitle( tr(
"Algorithm Dependencies" ) );
1368 widget->setValueFormatter( [
this](
const QVariant &v ) -> QString {
1369 const QgsProcessingModelChildDependency dep = v.value<QgsProcessingModelChildDependency>();
1371 const QString description = mModel->childAlgorithm( dep.childId ).description();
1372 if ( dep.conditionalBranch.isEmpty() )
1375 return tr(
"Condition “%1” from algorithm “%2”" ).arg( dep.conditionalBranch, description );
1378 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged,
this, [
this, widget]() {
1379 QList<QgsProcessingModelChildDependency> res;
1380 for (
const QVariant &v : widget->selectedOptions() )
1382 res << v.value<QgsProcessingModelChildDependency>();
1391void QgsModelChildDependenciesWidget::updateSummaryText()
1393 mLineEdit->setText( tr(
"%n dependencies selected",
nullptr, mValue.count() ) );
@ ExposeToModeler
Is this parameter available in the modeler. Is set to on by default.
@ Warning
Warning message.
@ Critical
Critical/error message.
@ Success
Used for reporting a successful operation.
@ ModelDebug
Model debug level logging. Includes verbose logging and other outputs useful for debugging models.
static QgsProcessingRegistry * processingRegistry()
Returns the application's processing registry, used for managing processing providers,...
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Base class for all map layer types.
Represents an item shown within a QgsMessageBar widget.
A bar for displaying non-blocking messages to the user.
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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
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
Abstract base class for processing algorithms.
Contains information about the context in which a processing algorithm is executed.
Encapsulates the results of running a child algorithm within a model.
QString htmlLog() const
Returns the HTML formatted contents of logged messages which occurred while running the child.
QVariantMap outputs() const
Returns the outputs generated by the child algorithm.
Encapsulates the results of running a Processing model.
QMap< QString, QgsProcessingModelChildAlgorithmResult > childResults() const
Returns the map of child algorithm results.
Base class for the definition of processing parameters.
Makes metadata of processing parameters available.
QList< QgsProcessingParameterType * > parameterTypes() const
Returns a list with all known parameter types.
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Interprets a string as a map layer within the supplied context.
@ PythonQgsProcessingAlgorithmSubclass
Full Python QgsProcessingAlgorithm subclass.
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsMapLayer * addMapLayer(QgsMapLayer *mapLayer, bool addToLegend=true, bool takeOwnership=true)
Add a layer to the map of loaded layers.
A utility class for dynamic handling of changes to screen properties.
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.
void remove(const QString &key, QgsSettings::Section section=QgsSettings::NoSection)
Removes the setting key and any sub-settings of key in a section.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)