48#include <QActionGroup>
51#include <QKeySequence>
57#include <QSvgGenerator>
63#include "moc_qgsmodeldesignerdialog.cpp"
65using namespace Qt::StringLiterals;
70QgsModelerToolboxModel::QgsModelerToolboxModel( QObject *parent )
75Qt::ItemFlags QgsModelerToolboxModel::flags(
const QModelIndex &index )
const
77 Qt::ItemFlags f = QgsProcessingToolboxProxyModel::flags( index );
78 const QModelIndex sourceIndex = mapToSource( index );
79 if ( toolboxModel()->isAlgorithm( sourceIndex ) || toolboxModel()->isParameter( sourceIndex ) )
81 f = f | Qt::ItemIsDragEnabled;
86Qt::DropActions QgsModelerToolboxModel::supportedDragActions()
const
88 return Qt::CopyAction;
91QgsModelDesignerDialog::QgsModelDesignerDialog( QWidget *parent, Qt::WindowFlags flags )
92 : QMainWindow( parent, flags )
93 , mToolsActionGroup( new QActionGroup( this ) )
101 setAttribute( Qt::WA_DeleteOnClose );
102 setDockOptions( dockOptions() | QMainWindow::GroupedDragging );
103 setWindowFlags( Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint );
107 mModel = std::make_unique<QgsProcessingModelAlgorithm>();
110 mUndoStack =
new QUndoStack(
this );
111 connect( mUndoStack, &QUndoStack::indexChanged,
this, [
this] {
112 if ( mIgnoreUndoStackChanges )
115 mBlockUndoCommands++;
116 updateVariablesGui();
117 mGroupEdit->setText( mModel->group() );
118 mNameEdit->setText( mModel->displayName() );
119 mBlockUndoCommands--;
124 mConfigWidgetDock->setWindowTitle( tr(
"Configuration" ) );
125 mConfigWidgetDock->setObjectName( u
"ModelConfigDock"_s );
128 mConfigWidgetDock->setWidget( mConfigWidget );
129 mConfigWidgetDock->setFeatures( QDockWidget::NoDockWidgetFeatures );
130 addDockWidget( Qt::RightDockWidgetArea, mConfigWidgetDock );
132 mPropertiesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
133 mInputsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
134 mAlgorithmsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
135 mVariablesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
137 mToolboxTree->header()->setVisible(
false );
138 mToolboxSearchEdit->setShowSearchIcon(
true );
139 mToolboxSearchEdit->setPlaceholderText( tr(
"Search…" ) );
140 connect( mToolboxSearchEdit, &QgsFilterLineEdit::textChanged, mToolboxTree, &QgsProcessingToolboxTreeView::setFilterString );
142 mInputsTreeWidget->header()->setVisible(
false );
143 mInputsTreeWidget->setAlternatingRowColors(
true );
144 mInputsTreeWidget->setDragDropMode( QTreeWidget::DragOnly );
145 mInputsTreeWidget->setDropIndicatorShown(
true );
147 mNameEdit->setPlaceholderText( tr(
"Enter model name here" ) );
148 mGroupEdit->setPlaceholderText( tr(
"Enter group name here" ) );
151 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
152 mainLayout->insertWidget( 0, mMessageBar );
154 mView->setAcceptDrops(
true );
157 connect( mActionClose, &QAction::triggered,
this, &QWidget::close );
158 connect( mActionNew, &QAction::triggered,
this, &QgsModelDesignerDialog::newModel );
159 connect( mActionZoomIn, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomIn );
160 connect( mActionZoomOut, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomOut );
161 connect( mActionZoomActual, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomActual );
162 connect( mActionZoomToItems, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomFull );
163 connect( mActionExportImage, &QAction::triggered,
this, &QgsModelDesignerDialog::exportToImage );
164 connect( mActionExportPdf, &QAction::triggered,
this, &QgsModelDesignerDialog::exportToPdf );
165 connect( mActionExportSvg, &QAction::triggered,
this, &QgsModelDesignerDialog::exportToSvg );
166 connect( mActionExportPython, &QAction::triggered,
this, &QgsModelDesignerDialog::exportAsPython );
167 connect( mActionSave, &QAction::triggered,
this, [
this] { saveModel(
false ); } );
168 connect( mActionSaveAs, &QAction::triggered,
this, [
this] { saveModel(
true ); } );
169 connect( mActionDeleteComponents, &QAction::triggered,
this, &QgsModelDesignerDialog::deleteSelected );
170 connect( mActionSnapSelected, &QAction::triggered, mView, &QgsModelGraphicsView::snapSelected );
171 connect( mActionValidate, &QAction::triggered,
this, &QgsModelDesignerDialog::validate );
172 connect( mActionReorderInputs, &QAction::triggered,
this, &QgsModelDesignerDialog::reorderInputs );
173 connect( mActionReorderOutputs, &QAction::triggered,
this, &QgsModelDesignerDialog::reorderOutputs );
174 connect( mActionEditHelp, &QAction::triggered,
this, &QgsModelDesignerDialog::editHelp );
175 connect( mReorderInputsButton, &QPushButton::clicked,
this, &QgsModelDesignerDialog::reorderInputs );
176 connect( mActionRun, &QAction::triggered,
this, [
this] { run(); } );
177 connect( mActionRunSelectedSteps, &QAction::triggered,
this, &QgsModelDesignerDialog::runSelectedSteps );
179 mActionSnappingEnabled->setChecked( settings.
value( u
"/Processing/Modeler/enableSnapToGrid"_s,
false ).toBool() );
180 connect( mActionSnappingEnabled, &QAction::toggled,
this, [
this](
bool enabled ) {
181 mView->snapper()->setSnapToGrid( enabled );
184 mView->snapper()->setSnapToGrid( mActionSnappingEnabled->isChecked() );
186 connect( mView, &QgsModelGraphicsView::itemFocused,
this, &QgsModelDesignerDialog::onItemFocused );
188 connect( mActionSelectAll, &QAction::triggered,
this, [
this] {
192 QStringList docksTitle = settings.
value( u
"ModelDesigner/hiddenDocksTitle"_s, QStringList(),
QgsSettings::App ).toStringList();
193 QStringList docksActive = settings.
value( u
"ModelDesigner/hiddenDocksActive"_s, QStringList(),
QgsSettings::App ).toStringList();
194 if ( !docksTitle.isEmpty() )
196 for (
const auto &title : docksTitle )
198 mPanelStatus.insert( title, PanelStatus(
true, docksActive.contains( title ) ) );
201 mActionHidePanels->setChecked( !docksTitle.isEmpty() );
202 connect( mActionHidePanels, &QAction::toggled,
this, &QgsModelDesignerDialog::setPanelVisibility );
204 mUndoAction = mUndoStack->createUndoAction(
this );
206 mUndoAction->setShortcuts( QKeySequence::Undo );
207 mRedoAction = mUndoStack->createRedoAction(
this );
209 mRedoAction->setShortcuts( QKeySequence::Redo );
211 mMenuEdit->insertAction( mActionDeleteComponents, mRedoAction );
212 mMenuEdit->insertAction( mActionDeleteComponents, mUndoAction );
213 mMenuEdit->insertSeparator( mActionDeleteComponents );
214 mToolbar->insertAction( mActionZoomIn, mUndoAction );
215 mToolbar->insertAction( mActionZoomIn, mRedoAction );
216 mToolbar->insertSeparator( mActionZoomIn );
218 mGroupMenu =
new QMenu( tr(
"Zoom To" ),
this );
219 mMenuView->insertMenu( mActionZoomIn, mGroupMenu );
220 connect( mGroupMenu, &QMenu::aboutToShow,
this, &QgsModelDesignerDialog::populateZoomToMenu );
224 mActionCut =
new QAction( tr(
"Cu&t" ),
this );
225 mActionCut->setShortcuts( QKeySequence::Cut );
226 mActionCut->setStatusTip( tr(
"Cut" ) );
228 connect( mActionCut, &QAction::triggered,
this, [
this] {
229 mView->copySelectedItems( QgsModelGraphicsView::ClipboardCut );
232 mActionCopy =
new QAction( tr(
"&Copy" ),
this );
233 mActionCopy->setShortcuts( QKeySequence::Copy );
234 mActionCopy->setStatusTip( tr(
"Copy" ) );
236 connect( mActionCopy, &QAction::triggered,
this, [
this] {
237 mView->copySelectedItems( QgsModelGraphicsView::ClipboardCopy );
240 mActionPaste =
new QAction( tr(
"&Paste" ),
this );
241 mActionPaste->setShortcuts( QKeySequence::Paste );
242 mActionPaste->setStatusTip( tr(
"Paste" ) );
244 connect( mActionPaste, &QAction::triggered,
this, [
this] {
245 mView->pasteItems( QgsModelGraphicsView::PasteModeCursor );
247 mMenuEdit->insertAction( mActionDeleteComponents, mActionCut );
248 mMenuEdit->insertAction( mActionDeleteComponents, mActionCopy );
249 mMenuEdit->insertAction( mActionDeleteComponents, mActionPaste );
250 mMenuEdit->insertSeparator( mActionDeleteComponents );
252 mAlgorithmsModel =
new QgsModelerToolboxModel(
this );
253 mToolboxTree->setToolboxProxyModel( mAlgorithmsModel );
256 if ( settings.
value( u
"Processing/Configuration/SHOW_ALGORITHMS_KNOWN_ISSUES"_s,
false ).toBool() )
260 mToolboxTree->setFilters( filters );
261 mToolboxTree->setDragDropMode( QTreeWidget::DragOnly );
262 mToolboxTree->setDropIndicatorShown(
true );
264 connect( mView, &QgsModelGraphicsView::algorithmDropped,
this, [
this](
const QString &algorithmId,
const QPointF &pos ) {
265 addAlgorithm( algorithmId, pos );
267 connect( mView, &QgsModelGraphicsView::inputDropped,
this, &QgsModelDesignerDialog::addInput );
269 connect( mToolboxTree, &QgsProcessingToolboxTreeView::doubleClicked,
this, [
this](
const QModelIndex & ) {
270 if ( mToolboxTree->selectedAlgorithm() )
271 addAlgorithm( mToolboxTree->selectedAlgorithm()->id(), QPointF() );
272 if ( mToolboxTree->selectedParameterType() )
273 addInput( mToolboxTree->selectedParameterType()->id(), QPointF() );
276 connect( mInputsTreeWidget, &QgsModelDesignerInputsTreeWidget::doubleClicked,
this, [
this](
const QModelIndex & ) {
277 const QString parameterType = mInputsTreeWidget->currentItem()->data( 0, Qt::UserRole ).toString();
278 addInput( parameterType, QPointF() );
282 QShortcut *ctrlEquals =
new QShortcut( QKeySequence( u
"Ctrl+="_s ),
this );
283 connect( ctrlEquals, &QShortcut::activated,
this, &QgsModelDesignerDialog::zoomIn );
286 mUndoDock->setObjectName( u
"UndoDock"_s );
287 mUndoView =
new QUndoView( mUndoStack,
this );
288 mUndoDock->setWidget( mUndoView );
289 mUndoDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
290 addDockWidget( Qt::DockWidgetArea::LeftDockWidgetArea, mUndoDock );
292 tabifyDockWidget( mUndoDock, mPropertiesDock );
293 tabifyDockWidget( mVariablesDock, mPropertiesDock );
294 mPropertiesDock->raise();
295 tabifyDockWidget( mInputsDock, mAlgorithmsDock );
296 mInputsDock->raise();
301 beginUndoCommand( tr(
"Change Model Variables" ) );
302 mModel->setVariables( mVariablesEditor->variablesInActiveScope() );
306 connect( mNameEdit, &QLineEdit::textChanged,
this, [
this](
const QString &name ) {
309 beginUndoCommand( tr(
"Change Model Name" ), QString(), QgsModelUndoCommand::CommandOperation::NameChanged );
310 mModel->setName( name );
315 connect( mGroupEdit, &QLineEdit::textChanged,
this, [
this](
const QString &group ) {
318 beginUndoCommand( tr(
"Change Model Group" ), QString(), QgsModelUndoCommand::CommandOperation::GroupChanged );
319 mModel->setGroup( group );
327 QToolButton *toolbuttonExportToScript =
new QToolButton();
328 toolbuttonExportToScript->setPopupMode( QToolButton::InstantPopup );
329 toolbuttonExportToScript->addAction( mActionExportAsScriptAlgorithm );
330 toolbuttonExportToScript->setDefaultAction( mActionExportAsScriptAlgorithm );
331 mToolbar->insertWidget( mActionExportImage, toolbuttonExportToScript );
332 connect( mActionExportAsScriptAlgorithm, &QAction::triggered,
this, &QgsModelDesignerDialog::exportAsScriptAlgorithm );
334 mActionShowComments->setChecked( settings.
value( u
"/Processing/Modeler/ShowComments"_s,
true ).toBool() );
335 connect( mActionShowComments, &QAction::toggled,
this, &QgsModelDesignerDialog::toggleComments );
337 mActionShowFeatureCount->setChecked( settings.
value( u
"/Processing/Modeler/ShowFeatureCount"_s,
true ).toBool() );
338 connect( mActionShowFeatureCount, &QAction::toggled,
this, &QgsModelDesignerDialog::toggleFeatureCount );
341 mPanTool->setAction( mActionPan );
343 mToolsActionGroup->addAction( mActionPan );
344 connect( mActionPan, &QAction::triggered, mPanTool, [
this] { mView->setTool( mPanTool ); } );
347 mSelectTool->setAction( mActionSelectMoveItem );
349 mToolsActionGroup->addAction( mActionSelectMoveItem );
350 connect( mActionSelectMoveItem, &QAction::triggered, mSelectTool, [
this] { mView->setTool( mSelectTool ); } );
352 mView->setTool( mSelectTool );
355 connect( mView, &QgsModelGraphicsView::macroCommandStarted,
this, [
this](
const QString &text ) {
356 mIgnoreUndoStackChanges++;
357 mUndoStack->beginMacro( text );
358 mIgnoreUndoStackChanges--;
360 connect( mView, &QgsModelGraphicsView::macroCommandEnded,
this, [
this] {
361 mIgnoreUndoStackChanges++;
362 mUndoStack->endMacro();
363 mIgnoreUndoStackChanges--;
365 connect( mView, &QgsModelGraphicsView::commandBegun,
this, [
this](
const QString &text ) {
366 beginUndoCommand( text );
368 connect( mView, &QgsModelGraphicsView::commandEnded,
this, [
this] {
371 connect( mView, &QgsModelGraphicsView::commandAborted,
this, [
this] {
374 connect( mView, &QgsModelGraphicsView::deleteSelectedItems,
this, [
this] {
378 connect( mActionAddGroupBox, &QAction::triggered,
this, [
this] {
379 const QPointF viewCenter = mView->mapToScene( mView->viewport()->rect().center() );
380 QgsProcessingModelGroupBox group;
381 group.setPosition( viewCenter );
382 group.setDescription( tr(
"New Group" ) );
384 beginUndoCommand( tr(
"Add Group Box" ) );
385 model()->addGroupBox( group );
393 restoreState( settings.
value( u
"ModelDesigner/state"_s, QByteArray(),
QgsSettings::App ).toByteArray() );
396QgsModelDesignerDialog::~QgsModelDesignerDialog()
399 if ( !mPanelStatus.isEmpty() )
401 QStringList docksTitle;
402 QStringList docksActive;
404 for (
const auto &panel : mPanelStatus.toStdMap() )
406 if ( panel.second.isVisible )
407 docksTitle << panel.first;
408 if ( panel.second.isActive )
409 docksActive << panel.first;
423 mIgnoreUndoStackChanges++;
427void QgsModelDesignerDialog::closeEvent( QCloseEvent *event )
429 if ( checkForUnsavedChanges() )
435void QgsModelDesignerDialog::beginUndoCommand(
const QString &text,
const QString &
id, QgsModelUndoCommand::CommandOperation operation )
437 if ( mBlockUndoCommands || !mUndoStack )
440 if ( mActiveCommand )
445 mActiveCommand = std::make_unique<QgsModelUndoCommand>( mModel.get(), text,
id );
449 mActiveCommand = std::make_unique<QgsModelUndoCommand>( mModel.get(), text, operation );
453void QgsModelDesignerDialog::endUndoCommand()
455 if ( mBlockUndoCommands || !mActiveCommand || !mUndoStack )
458 mActiveCommand->saveAfterState();
459 mIgnoreUndoStackChanges++;
460 mUndoStack->push( mActiveCommand.release() );
461 mIgnoreUndoStackChanges--;
465void QgsModelDesignerDialog::abortUndoCommand()
467 if ( mActiveCommand )
468 mActiveCommand->setObsolete(
true );
471QgsProcessingModelAlgorithm *QgsModelDesignerDialog::model()
476void QgsModelDesignerDialog::setModel( QgsProcessingModelAlgorithm *model )
478 mModel.reset( model );
480 mGroupEdit->setText( mModel->group() );
481 mNameEdit->setText( mModel->displayName() );
482 repaintModel(
true );
483 updateVariablesGui();
485 mView->centerOn( 0, 0 );
488 mIgnoreUndoStackChanges++;
490 mIgnoreUndoStackChanges--;
495void QgsModelDesignerDialog::loadModel(
const QString &path )
497 auto alg = std::make_unique<QgsProcessingModelAlgorithm>();
498 if ( alg->fromFile( path ) )
501 alg->setSourceFilePath( path );
502 setModel( alg.release() );
507 QMessageBox::critical(
this, tr(
"Open Model" ), tr(
"The selected model could not be loaded.\n"
508 "See the log for more information." ) );
512void QgsModelDesignerDialog::setModelScene( QgsModelGraphicsScene *scene )
514 QgsModelGraphicsScene *oldScene = mScene;
517 mScene->setParent(
this );
518 mScene->setLastRunResult( mLastResult, mLayerStore );
519 mScene->setModel( mModel.get() );
520 mScene->setMessageBar( mMessageBar );
523 const bool showFeatureCount = settings.
value( u
"/Processing/Modeler/ShowFeatureCount"_s,
true ).toBool();
524 if ( !showFeatureCount )
525 mScene->setFlag( QgsModelGraphicsScene::FlagHideFeatureCount );
527 mView->setModelScene( mScene );
529 mSelectTool->resetCache();
530 mSelectTool->setScene( mScene );
532 connect( mScene, &QgsModelGraphicsScene::rebuildRequired,
this, [
this] {
533 if ( mBlockRepaints )
538 connect( mScene, &QgsModelGraphicsScene::componentAboutToChange,
this, [
this](
const QString &description,
const QString &
id ) { beginUndoCommand( description,
id ); } );
539 connect( mScene, &QgsModelGraphicsScene::componentChanged,
this, [
this] { endUndoCommand(); } );
540 connect( mScene, &QgsModelGraphicsScene::runFromChild,
this, &QgsModelDesignerDialog::runFromChild );
541 connect( mScene, &QgsModelGraphicsScene::runSelected,
this, &QgsModelDesignerDialog::runSelectedSteps );
542 connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmOutputs,
this, &QgsModelDesignerDialog::showChildAlgorithmOutputs );
543 connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmLog,
this, &QgsModelDesignerDialog::showChildAlgorithmLog );
546 oldScene->deleteLater();
549QgsModelGraphicsScene *QgsModelDesignerDialog::modelScene()
554void QgsModelDesignerDialog::activate()
558 setWindowState( windowState() & ~Qt::WindowMinimized );
564 mProcessingContextGenerator = generator;
567void QgsModelDesignerDialog::updateVariablesGui()
569 mBlockUndoCommands++;
571 auto variablesScope = std::make_unique<QgsExpressionContextScope>( tr(
"Model Variables" ) );
572 const QVariantMap modelVars = mModel->variables();
573 for (
auto it = modelVars.constBegin(); it != modelVars.constEnd(); ++it )
575 variablesScope->setVariable( it.key(), it.value() );
578 variablesContext.
appendScope( variablesScope.release() );
579 mVariablesEditor->setContext( &variablesContext );
580 mVariablesEditor->setEditableScopeIndex( 0 );
582 mBlockUndoCommands--;
585void QgsModelDesignerDialog::setDirty(
bool dirty )
591bool QgsModelDesignerDialog::validateSave( SaveAction action )
595 case QgsModelDesignerDialog::SaveAction::SaveAsFile:
597 case QgsModelDesignerDialog::SaveAction::SaveInProject:
598 if ( mNameEdit->text().trimmed().isEmpty() )
600 mMessageBar->pushWarning( QString(), tr(
"Please enter a model name before saving" ) );
609bool QgsModelDesignerDialog::checkForUnsavedChanges()
613 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 );
616 case QMessageBox::Save:
617 return saveModel(
false );
619 case QMessageBox::Discard:
634 mLastResult.mergeWith( result );
636 mScene->setLastRunResult( mLastResult, mLayerStore );
639void QgsModelDesignerDialog::setModelName(
const QString &name )
641 mNameEdit->setText( name );
644void QgsModelDesignerDialog::zoomIn()
646 mView->setTransformationAnchor( QGraphicsView::NoAnchor );
647 QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
649 const double factor = settings.
value( u
"/qgis/zoom_favor"_s, 2.0 ).toDouble();
650 mView->scale( factor, factor );
651 mView->centerOn( point );
654void QgsModelDesignerDialog::zoomOut()
656 mView->setTransformationAnchor( QGraphicsView::NoAnchor );
657 QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
659 const double factor = 1.0 / settings.
value( u
"/qgis/zoom_favor"_s, 2.0 ).toDouble();
660 mView->scale( factor, factor );
661 mView->centerOn( point );
664void QgsModelDesignerDialog::zoomActual()
666 QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
667 mView->resetTransform();
668 mView->scale( mScreenHelper->screenDpi() / 96, mScreenHelper->screenDpi() / 96 );
669 mView->centerOn( point );
672void QgsModelDesignerDialog::zoomFull()
674 QRectF totalRect = mView->scene()->itemsBoundingRect();
675 totalRect.adjust( -10, -10, 10, 10 );
676 mView->fitInView( totalRect, Qt::KeepAspectRatio );
679void QgsModelDesignerDialog::newModel()
681 if ( !checkForUnsavedChanges() )
684 auto alg = std::make_unique<QgsProcessingModelAlgorithm>();
686 setModel( alg.release() );
689void QgsModelDesignerDialog::exportToImage()
692 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
694 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as Image" ), lastExportDir, tr(
"PNG files (*.png *.PNG)" ) );
698 if ( filename.isEmpty() )
703 const QFileInfo saveFileInfo( filename );
706 repaintModel(
false );
708 QRectF totalRect = mView->scene()->itemsBoundingRect();
709 totalRect.adjust( -10, -10, 10, 10 );
710 const QRectF imageRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
712 QImage img( totalRect.width(), totalRect.height(), QImage::Format_ARGB32_Premultiplied );
713 img.fill( Qt::white );
715 painter.setRenderHint( QPainter::Antialiasing );
716 painter.begin( &img );
717 mView->scene()->render( &painter, imageRect, totalRect );
720 img.save( filename );
722 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 );
723 repaintModel(
true );
726void QgsModelDesignerDialog::exportToPdf()
729 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
731 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as PDF" ), lastExportDir, tr(
"PDF files (*.pdf *.PDF)" ) );
735 if ( filename.isEmpty() )
740 const QFileInfo saveFileInfo( filename );
743 repaintModel(
false );
745 QRectF totalRect = mView->scene()->itemsBoundingRect();
746 totalRect.adjust( -10, -10, 10, 10 );
747 const QRectF printerRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
749 QPdfWriter pdfWriter( filename );
751 const double scaleFactor = 96 / 25.4;
753 QPageLayout pageLayout( QPageSize( totalRect.size() / scaleFactor, QPageSize::Millimeter ), QPageLayout::Portrait, QMarginsF( 0, 0, 0, 0 ) );
754 pageLayout.setMode( QPageLayout::FullPageMode );
755 pdfWriter.setPageLayout( pageLayout );
757 QPainter painter( &pdfWriter );
758 mView->scene()->render( &painter, printerRect, totalRect );
761 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 );
762 repaintModel(
true );
765void QgsModelDesignerDialog::exportToSvg()
768 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
770 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as SVG" ), lastExportDir, tr(
"SVG files (*.svg *.SVG)" ) );
774 if ( filename.isEmpty() )
779 const QFileInfo saveFileInfo( filename );
782 repaintModel(
false );
784 QRectF totalRect = mView->scene()->itemsBoundingRect();
785 totalRect.adjust( -10, -10, 10, 10 );
786 const QRectF svgRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
789 svg.setFileName( filename );
790 svg.setSize( QSize( totalRect.width(), totalRect.height() ) );
791 svg.setViewBox( svgRect );
792 svg.setTitle( mModel->displayName() );
794 QPainter painter( &svg );
795 mView->scene()->render( &painter, svgRect, totalRect );
798 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 );
799 repaintModel(
true );
802void QgsModelDesignerDialog::exportAsPython()
805 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
807 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as Python Script" ), lastExportDir, tr(
"Processing scripts (*.py *.PY)" ) );
811 if ( filename.isEmpty() )
816 const QFileInfo saveFileInfo( filename );
821 QFile outFile( filename );
822 if ( !outFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
826 QTextStream fout( &outFile );
830 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 );
833void QgsModelDesignerDialog::toggleComments(
bool show )
837 repaintModel(
true );
840void QgsModelDesignerDialog::toggleFeatureCount(
bool show )
844 repaintModel(
true );
847void QgsModelDesignerDialog::updateWindowTitle()
849 QString title = tr(
"Model Designer" );
850 if ( !mModel->name().isEmpty() )
851 title = mModel->group().isEmpty()
852 ? u
"%1: %2"_s.arg( title, mModel->name() )
853 : u
"%1: %2 - %3"_s.arg( title, mModel->group(), mModel->name() );
856 title.prepend(
'*' );
858 setWindowTitle( title );
861void QgsModelDesignerDialog::deleteSelected()
863 QList<QgsModelComponentGraphicItem *> items = mScene->selectedComponentItems();
867 if ( items.size() == 1 )
869 items.at( 0 )->deleteComponent();
873 std::sort( items.begin(), items.end(), []( QgsModelComponentGraphicItem *p1, QgsModelComponentGraphicItem *p2 ) {
878 if ( dynamic_cast<QgsModelCommentGraphicItem *>( p1 ) && dynamic_cast<QgsModelCommentGraphicItem *>( p2 ) )
880 else if ( dynamic_cast<QgsModelCommentGraphicItem *>( p1 ) )
882 else if ( dynamic_cast<QgsModelCommentGraphicItem *>( p2 ) )
885 else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p1 ) && dynamic_cast<QgsModelGroupBoxGraphicItem *>( p2 ) )
887 else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p1 ) )
889 else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p2 ) )
892 else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p1 ) && dynamic_cast<QgsModelOutputGraphicItem *>( p2 ) )
894 else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p1 ) )
896 else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p2 ) )
899 else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p1 ) && dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p2 ) )
901 else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p1 ) )
903 else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p2 ) )
910 beginUndoCommand( tr(
"Delete Components" ) );
912 QVariant prevState = mModel->toVariant();
913 mBlockUndoCommands++;
914 mBlockRepaints =
true;
916 while ( !items.empty() )
918 QgsModelComponentGraphicItem *toDelete =
nullptr;
919 for ( QgsModelComponentGraphicItem *item : items )
921 if ( item->canDeleteComponent() )
934 toDelete->deleteComponent();
935 items.removeAll( toDelete );
940 mModel->loadVariant( prevState );
941 QMessageBox::warning(
nullptr, QObject::tr(
"Could not remove components" ), QObject::tr(
"Components depend on the selected items.\n"
942 "Try to remove them before trying deleting these components." ) );
943 mBlockUndoCommands--;
944 mActiveCommand.reset();
948 mBlockUndoCommands--;
952 mBlockRepaints =
false;
956void QgsModelDesignerDialog::populateZoomToMenu()
959 for (
const QgsProcessingModelGroupBox &box : model()->groupBoxes() )
961 if ( QgsModelComponentGraphicItem *item = mScene->groupBoxItem( box.uuid() ) )
963 QAction *zoomAction =
new QAction( box.description(), mGroupMenu );
964 connect( zoomAction, &QAction::triggered,
this, [
this, item] {
965 QRectF groupRect = item->mapToScene( item->boundingRect() ).boundingRect();
966 groupRect.adjust( -10, -10, 10, 10 );
967 mView->fitInView( groupRect, Qt::KeepAspectRatio );
968 mView->centerOn( item );
970 mGroupMenu->addAction( zoomAction );
975void QgsModelDesignerDialog::setPanelVisibility(
bool hidden )
977 const QList<QDockWidget *> docks = findChildren<QDockWidget *>();
978 const QList<QTabBar *> tabBars = findChildren<QTabBar *>();
982 mPanelStatus.clear();
984 for ( QDockWidget *dock : docks )
986 mPanelStatus.insert( dock->windowTitle(), PanelStatus( dock->isVisible(),
false ) );
987 dock->setVisible(
false );
991 for ( QTabBar *tabBar : tabBars )
993 QString currentTabTitle = tabBar->tabText( tabBar->currentIndex() );
994 mPanelStatus[currentTabTitle].isActive =
true;
1000 for ( QDockWidget *dock : docks )
1002 if ( mPanelStatus.contains( dock->windowTitle() ) )
1004 dock->setVisible( mPanelStatus.value( dock->windowTitle() ).isVisible );
1009 for ( QTabBar *tabBar : tabBars )
1012 for (
int i = 0; i < tabBar->count(); ++i )
1014 QString tabTitle = tabBar->tabText( i );
1015 if ( mPanelStatus.contains( tabTitle ) && mPanelStatus.value( tabTitle ).isActive )
1017 tabBar->setCurrentIndex( i );
1021 mPanelStatus.clear();
1025void QgsModelDesignerDialog::editHelp()
1027 QgsProcessingHelpEditorDialog dialog(
this );
1028 dialog.setWindowTitle( tr(
"Edit Model Help" ) );
1029 dialog.setAlgorithm( mModel.get() );
1030 if ( dialog.exec() )
1032 beginUndoCommand( tr(
"Edit Model Help" ) );
1033 mModel->setHelpContent( dialog.helpContent() );
1038void QgsModelDesignerDialog::runSelectedSteps()
1040 QSet<QString> children;
1041 const QList<QgsModelComponentGraphicItem *> items = mScene->selectedComponentItems();
1042 for ( QgsModelComponentGraphicItem *item : items )
1044 if ( QgsProcessingModelChildAlgorithm *childAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( item->component() ) )
1046 children.insert( childAlgorithm->childId() );
1050 if ( children.isEmpty() )
1052 mMessageBar->pushWarning( QString(), tr(
"No steps are selected" ) );
1059void QgsModelDesignerDialog::runFromChild(
const QString &
id )
1061 QSet<QString> children = mModel->dependentChildAlgorithms(
id );
1062 children.insert(
id );
1066void QgsModelDesignerDialog::run(
const QSet<QString> &childAlgorithmSubset )
1069 const bool isValid = model()->validate( errors );
1072 QMessageBox messageBox;
1073 messageBox.setWindowTitle( tr(
"Model is Invalid" ) );
1074 messageBox.setIcon( QMessageBox::Icon::Warning );
1075 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?" ) );
1076 messageBox.setStandardButtons( QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::Cancel );
1077 messageBox.setDefaultButton( QMessageBox::StandardButton::Cancel );
1079 QString errorString;
1080 for (
const QString &error : std::as_const( errors ) )
1082 QString cleanedError = error;
1083 const thread_local QRegularExpression re( u
"<[^>]*>"_s );
1084 cleanedError.replace( re, QString() );
1085 errorString += u
"• %1\n"_s.arg( cleanedError );
1088 messageBox.setDetailedText( errorString );
1089 if ( messageBox.exec() == QMessageBox::StandardButton::Cancel )
1093 if ( !childAlgorithmSubset.isEmpty() )
1095 for (
const QString &child : childAlgorithmSubset )
1098 const QSet<QString> requirements = mModel->dependsOnChildAlgorithms( child );
1099 for (
const QString &requirement : requirements )
1101 if ( !mLastResult.executedChildIds().contains( requirement ) )
1103 QMessageBox messageBox;
1104 messageBox.setWindowTitle( tr(
"Run Model" ) );
1105 messageBox.setIcon( QMessageBox::Icon::Warning );
1106 messageBox.setText( tr(
"Prerequisite parts of this model have not yet been run (try running the full model first)." ) );
1107 messageBox.setStandardButtons( QMessageBox::StandardButton::Ok );
1115 std::unique_ptr<QgsProcessingAlgorithmDialogBase> dialog( createExecutionDialog() );
1120 dialog->setParameters( mModel->designerParameterValues() );
1122 connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmAboutToRun,
this, [
this, &childAlgorithmSubset](
QgsProcessingContext *context ) {
1123 if ( !childAlgorithmSubset.empty() )
1126 auto modelConfig = std::make_unique<QgsProcessingModelInitialRunConfig>();
1127 modelConfig->setChildAlgorithmSubset( childAlgorithmSubset );
1128 modelConfig->setPreviouslyExecutedChildAlgorithms( mLastResult.executedChildIds() );
1129 modelConfig->setInitialChildInputs( mLastResult.rawChildInputs() );
1130 modelConfig->setInitialChildOutputs( mLastResult.rawChildOutputs() );
1134 const QMap<QString, QgsMapLayer *> previousOutputLayers = mLayerStore.temporaryLayerStore()->mapLayers();
1135 auto previousResultStore = std::make_unique<QgsMapLayerStore>();
1136 for ( auto it = previousOutputLayers.constBegin(); it != previousOutputLayers.constEnd(); ++it )
1138 std::unique_ptr<QgsMapLayer> clone( it.value()->clone() );
1139 clone->setId( it.value()->id() );
1140 previousResultStore->addMapLayer( clone.release() );
1142 previousResultStore->moveToThread( nullptr );
1143 modelConfig->setPreviousLayerStore( std::move( previousResultStore ) );
1144 context->setModelInitialRunConfig( std::move( modelConfig ) );
1148 connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmFinished,
this, [
this, &dialog](
bool,
const QVariantMap & ) {
1149 QgsProcessingContext *context = dialog->processingContext();
1151 mLayerStore.temporaryLayerStore()->removeAllMapLayers();
1152 mLayerStore.takeResultsFrom( *context );
1154 mModel->setDesignerParameterValues( dialog->createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipDefaultValueParameters ) );
1155 setLastRunResult( context->modelResult() );
1161void QgsModelDesignerDialog::showChildAlgorithmOutputs(
const QString &childId )
1163 const QString childDescription = mModel->childAlgorithm( childId ).description();
1166 const QVariantMap childAlgorithmOutputs = result.
outputs();
1167 if ( childAlgorithmOutputs.isEmpty() )
1169 mMessageBar->pushWarning( QString(), tr(
"No results are available for %1" ).arg( childDescription ) );
1176 mMessageBar->pushCritical( QString(), tr(
"Results cannot be shown for an invalid model component" ) );
1180 const QList<const QgsProcessingParameterDefinition *> outputParams =
algorithm->destinationParameterDefinitions();
1181 if ( outputParams.isEmpty() )
1184 QgsDebugError(
"Cannot show results for algorithms with no outputs" );
1188 bool foundResults =
false;
1191 const QVariant output = childAlgorithmOutputs.value( outputParam->name() );
1192 if ( !output.isValid() )
1195 if ( output.type() == QVariant::String )
1199 QgsDebugMsgLevel( u
"Loading previous result for %1: %2"_s.arg( outputParam->name(), output.toString() ), 2 );
1201 std::unique_ptr<QgsMapLayer> layer( resultLayer->clone() );
1204 if ( outputParams.size() > 1 )
1205 baseName = tr(
"%1 — %2" ).arg( childDescription, outputParam->name() );
1207 baseName = childDescription;
1211 QString name = baseName;
1216 name = tr(
"%1 (%2)" ).arg( baseName ).arg( counter );
1219 layer->setName( name );
1222 foundResults =
true;
1227 QgsDebugError( u
"Could not load previous result for %1: %2"_s.arg( outputParam->name(), output.toString() ) );
1232 if ( !foundResults )
1234 mMessageBar->pushWarning( QString(), tr(
"No results are available for %1" ).arg( childDescription ) );
1239void QgsModelDesignerDialog::showChildAlgorithmLog(
const QString &childId )
1241 const QString childDescription = mModel->childAlgorithm( childId ).description();
1244 if ( result.
htmlLog().isEmpty() )
1246 mMessageBar->pushWarning( QString(), tr(
"No log is available for %1" ).arg( childDescription ) );
1251 m.setWindowTitle( childDescription );
1252 m.setCheckBoxVisible(
false );
1253 m.setMessageAsHtml( result.
htmlLog() );
1257void QgsModelDesignerDialog::onItemFocused( QgsModelComponentGraphicItem *item )
1264 if ( !item || !item->component() )
1266 mConfigWidget->showComponentConfig(
nullptr, *context, widgetContext );
1270 mConfigWidget->showComponentConfig( item->component(), *context, widgetContext );
1274void QgsModelDesignerDialog::validate()
1277 if ( model()->validate( issues ) )
1279 mMessageBar->pushSuccess( QString(), tr(
"Model is valid!" ) );
1284 QPushButton *detailsButton =
new QPushButton( tr(
"Details" ) );
1285 connect( detailsButton, &QPushButton::clicked, detailsButton, [detailsButton, issues] {
1287 dialog->
setTitle( tr(
"Model is Invalid" ) );
1289 QString longMessage = tr(
"<p>This model is not valid:</p>" ) + u
"<ul>"_s;
1290 for (
const QString &issue : issues )
1292 longMessage += u
"<li>%1</li>"_s.arg( issue );
1294 longMessage +=
"</ul>"_L1;
1299 messageWidget->layout()->addWidget( detailsButton );
1300 mMessageBar->clearWidgets();
1305void QgsModelDesignerDialog::reorderInputs()
1307 QgsModelInputReorderDialog dlg(
this );
1308 dlg.setModel( mModel.get() );
1311 const QStringList inputOrder = dlg.inputOrder();
1312 beginUndoCommand( tr(
"Reorder Inputs" ) );
1313 mModel->setParameterOrder( inputOrder );
1318void QgsModelDesignerDialog::reorderOutputs()
1320 QgsModelOutputReorderDialog dlg(
this );
1321 dlg.setModel( mModel.get() );
1324 const QStringList outputOrder = dlg.outputOrder();
1325 beginUndoCommand( tr(
"Reorder Outputs" ) );
1326 mModel->setOutputOrder( outputOrder );
1327 mModel->setOutputGroup( dlg.outputGroup() );
1332bool QgsModelDesignerDialog::isDirty()
const
1334 return mHasChanged && mUndoStack->index() != -1;
1337void QgsModelDesignerDialog::fillInputsTree()
1340 auto parametersItem = std::make_unique<QTreeWidgetItem>();
1341 parametersItem->setText( 0, tr(
"Parameters" ) );
1344 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
1351 auto paramItem = std::make_unique<QTreeWidgetItem>();
1352 paramItem->setText( 0, param->name() );
1353 paramItem->setData( 0, Qt::UserRole, param->id() );
1354 paramItem->setIcon( 0, icon );
1355 paramItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
1356 paramItem->setToolTip( 0, param->description() );
1357 parametersItem->addChild( paramItem.release() );
1360 mInputsTreeWidget->addTopLevelItem( parametersItem.release() );
1361 mInputsTreeWidget->topLevelItem( 0 )->setExpanded(
true );
1369QgsModelChildDependenciesWidget::QgsModelChildDependenciesWidget( QWidget *parent, QgsProcessingModelAlgorithm *model,
const QString &childId )
1372 , mChildId( childId )
1374 QHBoxLayout *hl =
new QHBoxLayout();
1375 hl->setContentsMargins( 0, 0, 0, 0 );
1377 mLineEdit =
new QLineEdit();
1378 mLineEdit->setEnabled(
false );
1379 hl->addWidget( mLineEdit, 1 );
1381 mToolButton =
new QToolButton();
1382 mToolButton->setText( QString( QChar( 0x2026 ) ) );
1383 hl->addWidget( mToolButton );
1387 mLineEdit->setText( tr(
"%1 dependencies selected" ).arg( 0 ) );
1389 connect( mToolButton, &QToolButton::clicked,
this, &QgsModelChildDependenciesWidget::showDialog );
1392void QgsModelChildDependenciesWidget::setValue(
const QList<QgsProcessingModelChildDependency> &value )
1396 updateSummaryText();
1399void QgsModelChildDependenciesWidget::showDialog()
1401 const QList<QgsProcessingModelChildDependency> available = mModel->availableDependenciesForChildAlgorithm( mChildId );
1403 QVariantList availableOptions;
1404 for (
const QgsProcessingModelChildDependency &dep : available )
1405 availableOptions << QVariant::fromValue( dep );
1406 QVariantList selectedOptions;
1407 for (
const QgsProcessingModelChildDependency &dep : mValue )
1408 selectedOptions << QVariant::fromValue( dep );
1413 QgsProcessingMultipleSelectionPanelWidget *widget =
new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
1414 widget->setPanelTitle( tr(
"Algorithm Dependencies" ) );
1416 widget->setValueFormatter( [
this](
const QVariant &v ) -> QString {
1417 const QgsProcessingModelChildDependency dep = v.value<QgsProcessingModelChildDependency>();
1419 const QString description = mModel->childAlgorithm( dep.childId ).description();
1420 if ( dep.conditionalBranch.isEmpty() )
1423 return tr(
"Condition “%1” from algorithm “%2”" ).arg( dep.conditionalBranch, description );
1426 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged,
this, [
this, widget]() {
1427 QList<QgsProcessingModelChildDependency> res;
1428 for (
const QVariant &v : widget->selectedOptions() )
1430 res << v.value<QgsProcessingModelChildDependency>();
1439void QgsModelChildDependenciesWidget::updateSummaryText()
1441 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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
A generic message view for displaying QGIS messages.
void setMessage(const QString &message, Qgis::StringFormat format) override
Sets message, it won't be displayed until.
void setTitle(const QString &title) override
Sets title for the messages.
void showMessage(bool blocking=true) override
display the message to the user and deletes itself
Abstract base class for processing algorithms.
An interface for objects which can create Processing contexts.
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.
Contains settings which reflect the context in which a Processing parameter widget is shown.
void setModelDesignerDialog(QgsModelDesignerDialog *dialog)
Sets the associated model designer dialog, if applicable.
void registerProcessingContextGenerator(QgsProcessingContextGenerator *generator)
Registers a Processing context generator class that will be used to retrieve a Processing context for...
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)