48#include <QActionGroup>
51#include <QKeySequence>
57#include <QSvgGenerator>
63#include "moc_qgsmodeldesignerdialog.cpp"
65using namespace Qt::StringLiterals;
70QgsModelerToolboxModel::QgsModelerToolboxModel( QObject *parent )
74Qt::ItemFlags QgsModelerToolboxModel::flags(
const QModelIndex &index )
const
76 Qt::ItemFlags f = QgsProcessingToolboxProxyModel::flags( index );
77 const QModelIndex sourceIndex = mapToSource( index );
78 if ( toolboxModel()->isAlgorithm( sourceIndex ) || toolboxModel()->isParameter( sourceIndex ) )
80 f = f | Qt::ItemIsDragEnabled;
85Qt::DropActions QgsModelerToolboxModel::supportedDragActions()
const
87 return Qt::CopyAction;
90QgsModelDesignerDialog::QgsModelDesignerDialog( QWidget *parent, Qt::WindowFlags flags )
91 : QMainWindow( parent, flags )
92 , mToolsActionGroup( new QActionGroup( this ) )
100 setAttribute( Qt::WA_DeleteOnClose );
101 setDockOptions( dockOptions() | QMainWindow::GroupedDragging );
102 setWindowFlags( Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint );
106 mModel = std::make_unique<QgsProcessingModelAlgorithm>();
109 mUndoStack =
new QUndoStack(
this );
110 connect( mUndoStack, &QUndoStack::indexChanged,
this, [
this] {
111 if ( mIgnoreUndoStackChanges )
114 mBlockUndoCommands++;
115 updateVariablesGui();
116 mGroupEdit->setText( mModel->group() );
117 mNameEdit->setText( mModel->displayName() );
118 mBlockUndoCommands--;
123 mConfigWidgetDock->setWindowTitle( tr(
"Configuration" ) );
124 mConfigWidgetDock->setObjectName( u
"ModelConfigDock"_s );
127 mConfigWidgetDock->setWidget( mConfigWidget );
128 mConfigWidgetDock->setFeatures( QDockWidget::NoDockWidgetFeatures );
129 addDockWidget( Qt::RightDockWidgetArea, mConfigWidgetDock );
131 mPropertiesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
132 mInputsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
133 mAlgorithmsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
134 mVariablesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
136 mToolboxTree->header()->setVisible(
false );
137 mToolboxSearchEdit->setShowSearchIcon(
true );
138 mToolboxSearchEdit->setPlaceholderText( tr(
"Search…" ) );
139 connect( mToolboxSearchEdit, &QgsFilterLineEdit::textChanged, mToolboxTree, &QgsProcessingToolboxTreeView::setFilterString );
141 mInputsTreeWidget->header()->setVisible(
false );
142 mInputsTreeWidget->setAlternatingRowColors(
true );
143 mInputsTreeWidget->setDragDropMode( QTreeWidget::DragOnly );
144 mInputsTreeWidget->setDropIndicatorShown(
true );
146 mNameEdit->setPlaceholderText( tr(
"Enter model name here" ) );
147 mGroupEdit->setPlaceholderText( tr(
"Enter group name here" ) );
150 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
151 mainLayout->insertWidget( 0, mMessageBar );
153 mView->setAcceptDrops(
true );
156 connect( mActionClose, &QAction::triggered,
this, &QWidget::close );
157 connect( mActionNew, &QAction::triggered,
this, &QgsModelDesignerDialog::newModel );
158 connect( mActionZoomIn, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomIn );
159 connect( mActionZoomOut, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomOut );
160 connect( mActionZoomActual, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomActual );
161 connect( mActionZoomToItems, &QAction::triggered,
this, &QgsModelDesignerDialog::zoomFull );
162 connect( mActionExportImage, &QAction::triggered,
this, &QgsModelDesignerDialog::exportToImage );
163 connect( mActionExportPdf, &QAction::triggered,
this, &QgsModelDesignerDialog::exportToPdf );
164 connect( mActionExportSvg, &QAction::triggered,
this, &QgsModelDesignerDialog::exportToSvg );
165 connect( mActionExportPython, &QAction::triggered,
this, &QgsModelDesignerDialog::exportAsPython );
166 connect( mActionSave, &QAction::triggered,
this, [
this] { saveModel(
false ); } );
167 connect( mActionSaveAs, &QAction::triggered,
this, [
this] { saveModel(
true ); } );
168 connect( mActionDeleteComponents, &QAction::triggered,
this, &QgsModelDesignerDialog::deleteSelected );
169 connect( mActionSnapSelected, &QAction::triggered, mView, &QgsModelGraphicsView::snapSelected );
170 connect( mActionValidate, &QAction::triggered,
this, &QgsModelDesignerDialog::validate );
171 connect( mActionReorderInputs, &QAction::triggered,
this, &QgsModelDesignerDialog::reorderInputs );
172 connect( mActionReorderOutputs, &QAction::triggered,
this, &QgsModelDesignerDialog::reorderOutputs );
173 connect( mActionEditHelp, &QAction::triggered,
this, &QgsModelDesignerDialog::editHelp );
174 connect( mReorderInputsButton, &QPushButton::clicked,
this, &QgsModelDesignerDialog::reorderInputs );
175 connect( mActionRun, &QAction::triggered,
this, [
this] { run(); } );
176 connect( mActionRunSelectedSteps, &QAction::triggered,
this, &QgsModelDesignerDialog::runSelectedSteps );
178 mActionSnappingEnabled->setChecked( settings.
value( u
"/Processing/Modeler/enableSnapToGrid"_s,
false ).toBool() );
179 connect( mActionSnappingEnabled, &QAction::toggled,
this, [
this](
bool enabled ) {
180 mView->snapper()->setSnapToGrid( enabled );
183 mView->snapper()->setSnapToGrid( mActionSnappingEnabled->isChecked() );
185 connect( mView, &QgsModelGraphicsView::itemFocused,
this, &QgsModelDesignerDialog::onItemFocused );
187 connect( mActionSelectAll, &QAction::triggered,
this, [
this] { mScene->selectAll(); } );
189 QStringList docksTitle = settings.
value( u
"ModelDesigner/hiddenDocksTitle"_s, QStringList(),
QgsSettings::App ).toStringList();
190 QStringList docksActive = settings.
value( u
"ModelDesigner/hiddenDocksActive"_s, QStringList(),
QgsSettings::App ).toStringList();
191 if ( !docksTitle.isEmpty() )
193 for (
const auto &title : docksTitle )
195 mPanelStatus.insert( title, PanelStatus(
true, docksActive.contains( title ) ) );
198 mActionHidePanels->setChecked( !docksTitle.isEmpty() );
199 connect( mActionHidePanels, &QAction::toggled,
this, &QgsModelDesignerDialog::setPanelVisibility );
201 mUndoAction = mUndoStack->createUndoAction(
this );
203 mUndoAction->setShortcuts( QKeySequence::Undo );
204 mRedoAction = mUndoStack->createRedoAction(
this );
206 mRedoAction->setShortcuts( QKeySequence::Redo );
208 mMenuEdit->insertAction( mActionDeleteComponents, mRedoAction );
209 mMenuEdit->insertAction( mActionDeleteComponents, mUndoAction );
210 mMenuEdit->insertSeparator( mActionDeleteComponents );
211 mToolbar->insertAction( mActionZoomIn, mUndoAction );
212 mToolbar->insertAction( mActionZoomIn, mRedoAction );
213 mToolbar->insertSeparator( mActionZoomIn );
215 mGroupMenu =
new QMenu( tr(
"Zoom To" ),
this );
216 mMenuView->insertMenu( mActionZoomIn, mGroupMenu );
217 connect( mGroupMenu, &QMenu::aboutToShow,
this, &QgsModelDesignerDialog::populateZoomToMenu );
221 mActionCut =
new QAction( tr(
"Cu&t" ),
this );
222 mActionCut->setShortcuts( QKeySequence::Cut );
223 mActionCut->setStatusTip( tr(
"Cut" ) );
225 connect( mActionCut, &QAction::triggered,
this, [
this] { mView->copySelectedItems( QgsModelGraphicsView::ClipboardCut ); } );
227 mActionCopy =
new QAction( tr(
"&Copy" ),
this );
228 mActionCopy->setShortcuts( QKeySequence::Copy );
229 mActionCopy->setStatusTip( tr(
"Copy" ) );
231 connect( mActionCopy, &QAction::triggered,
this, [
this] { mView->copySelectedItems( QgsModelGraphicsView::ClipboardCopy ); } );
233 mActionPaste =
new QAction( tr(
"&Paste" ),
this );
234 mActionPaste->setShortcuts( QKeySequence::Paste );
235 mActionPaste->setStatusTip( tr(
"Paste" ) );
237 connect( mActionPaste, &QAction::triggered,
this, [
this] { mView->pasteItems( QgsModelGraphicsView::PasteModeCursor ); } );
238 mMenuEdit->insertAction( mActionDeleteComponents, mActionCut );
239 mMenuEdit->insertAction( mActionDeleteComponents, mActionCopy );
240 mMenuEdit->insertAction( mActionDeleteComponents, mActionPaste );
241 mMenuEdit->insertSeparator( mActionDeleteComponents );
243 mAlgorithmsModel =
new QgsModelerToolboxModel(
this );
244 mToolboxTree->setToolboxProxyModel( mAlgorithmsModel );
247 if ( settings.
value( u
"Processing/Configuration/SHOW_ALGORITHMS_KNOWN_ISSUES"_s,
false ).toBool() )
251 mToolboxTree->setFilters( filters );
252 mToolboxTree->setDragDropMode( QTreeWidget::DragOnly );
253 mToolboxTree->setDropIndicatorShown(
true );
255 connect( mView, &QgsModelGraphicsView::algorithmDropped,
this, [
this](
const QString &algorithmId,
const QPointF &pos ) { addAlgorithm( algorithmId, pos ); } );
256 connect( mView, &QgsModelGraphicsView::inputDropped,
this, &QgsModelDesignerDialog::addInput );
258 connect( mToolboxTree, &QgsProcessingToolboxTreeView::doubleClicked,
this, [
this](
const QModelIndex & ) {
259 if ( mToolboxTree->selectedAlgorithm() )
260 addAlgorithm( mToolboxTree->selectedAlgorithm()->id(), QPointF() );
261 if ( mToolboxTree->selectedParameterType() )
262 addInput( mToolboxTree->selectedParameterType()->id(), QPointF() );
265 connect( mInputsTreeWidget, &QgsModelDesignerInputsTreeWidget::doubleClicked,
this, [
this](
const QModelIndex & ) {
266 const QString parameterType = mInputsTreeWidget->currentItem()->data( 0, Qt::UserRole ).toString();
267 addInput( parameterType, QPointF() );
271 QShortcut *ctrlEquals =
new QShortcut( QKeySequence( u
"Ctrl+="_s ),
this );
272 connect( ctrlEquals, &QShortcut::activated,
this, &QgsModelDesignerDialog::zoomIn );
275 mUndoDock->setObjectName( u
"UndoDock"_s );
276 mUndoView =
new QUndoView( mUndoStack,
this );
277 mUndoDock->setWidget( mUndoView );
278 mUndoDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
279 addDockWidget( Qt::DockWidgetArea::LeftDockWidgetArea, mUndoDock );
281 tabifyDockWidget( mUndoDock, mPropertiesDock );
282 tabifyDockWidget( mVariablesDock, mPropertiesDock );
283 mPropertiesDock->raise();
284 tabifyDockWidget( mInputsDock, mAlgorithmsDock );
285 mInputsDock->raise();
290 beginUndoCommand( tr(
"Change Model Variables" ) );
291 mModel->setVariables( mVariablesEditor->variablesInActiveScope() );
295 connect( mNameEdit, &QLineEdit::textChanged,
this, [
this](
const QString &name ) {
298 beginUndoCommand( tr(
"Change Model Name" ), QString(), QgsModelUndoCommand::CommandOperation::NameChanged );
299 mModel->setName( name );
304 connect( mGroupEdit, &QLineEdit::textChanged,
this, [
this](
const QString &group ) {
307 beginUndoCommand( tr(
"Change Model Group" ), QString(), QgsModelUndoCommand::CommandOperation::GroupChanged );
308 mModel->setGroup( group );
316 QToolButton *toolbuttonExportToScript =
new QToolButton();
317 toolbuttonExportToScript->setPopupMode( QToolButton::InstantPopup );
318 toolbuttonExportToScript->addAction( mActionExportAsScriptAlgorithm );
319 toolbuttonExportToScript->setDefaultAction( mActionExportAsScriptAlgorithm );
320 mToolbar->insertWidget( mActionExportImage, toolbuttonExportToScript );
321 connect( mActionExportAsScriptAlgorithm, &QAction::triggered,
this, &QgsModelDesignerDialog::exportAsScriptAlgorithm );
323 mActionShowComments->setChecked( settings.
value( u
"/Processing/Modeler/ShowComments"_s,
true ).toBool() );
324 connect( mActionShowComments, &QAction::toggled,
this, &QgsModelDesignerDialog::toggleComments );
326 mActionShowFeatureCount->setChecked( settings.
value( u
"/Processing/Modeler/ShowFeatureCount"_s,
true ).toBool() );
327 connect( mActionShowFeatureCount, &QAction::toggled,
this, &QgsModelDesignerDialog::toggleFeatureCount );
330 mPanTool->setAction( mActionPan );
332 mToolsActionGroup->addAction( mActionPan );
333 connect( mActionPan, &QAction::triggered, mPanTool, [
this] { mView->setTool( mPanTool ); } );
336 mSelectTool->setAction( mActionSelectMoveItem );
338 mToolsActionGroup->addAction( mActionSelectMoveItem );
339 connect( mActionSelectMoveItem, &QAction::triggered, mSelectTool, [
this] { mView->setTool( mSelectTool ); } );
341 mView->setTool( mSelectTool );
344 connect( mView, &QgsModelGraphicsView::macroCommandStarted,
this, [
this](
const QString &text ) {
345 mIgnoreUndoStackChanges++;
346 mUndoStack->beginMacro( text );
347 mIgnoreUndoStackChanges--;
349 connect( mView, &QgsModelGraphicsView::macroCommandEnded,
this, [
this] {
350 mIgnoreUndoStackChanges++;
351 mUndoStack->endMacro();
352 mIgnoreUndoStackChanges--;
354 connect( mView, &QgsModelGraphicsView::commandBegun,
this, [
this](
const QString &text ) { beginUndoCommand( text ); } );
355 connect( mView, &QgsModelGraphicsView::commandEnded,
this, [
this] { endUndoCommand(); } );
356 connect( mView, &QgsModelGraphicsView::commandAborted,
this, [
this] { abortUndoCommand(); } );
357 connect( mView, &QgsModelGraphicsView::deleteSelectedItems,
this, [
this] { deleteSelected(); } );
359 connect( mActionAddGroupBox, &QAction::triggered,
this, [
this] {
360 const QPointF viewCenter = mView->mapToScene( mView->viewport()->rect().center() );
361 QgsProcessingModelGroupBox group;
362 group.setPosition( viewCenter );
363 group.setDescription( tr(
"New Group" ) );
365 beginUndoCommand( tr(
"Add Group Box" ) );
366 model()->addGroupBox( group );
374 restoreState( settings.
value( u
"ModelDesigner/state"_s, QByteArray(),
QgsSettings::App ).toByteArray() );
377QgsModelDesignerDialog::~QgsModelDesignerDialog()
380 if ( !mPanelStatus.isEmpty() )
382 QStringList docksTitle;
383 QStringList docksActive;
385 for (
const auto &panel : mPanelStatus.toStdMap() )
387 if ( panel.second.isVisible )
388 docksTitle << panel.first;
389 if ( panel.second.isActive )
390 docksActive << panel.first;
404 mIgnoreUndoStackChanges++;
408void QgsModelDesignerDialog::closeEvent( QCloseEvent *event )
410 if ( checkForUnsavedChanges() )
416void QgsModelDesignerDialog::beginUndoCommand(
const QString &text,
const QString &
id, QgsModelUndoCommand::CommandOperation operation )
418 if ( mBlockUndoCommands || !mUndoStack )
421 if ( mActiveCommand )
426 mActiveCommand = std::make_unique<QgsModelUndoCommand>( mModel.get(), text,
id );
430 mActiveCommand = std::make_unique<QgsModelUndoCommand>( mModel.get(), text, operation );
434void QgsModelDesignerDialog::endUndoCommand()
436 if ( mBlockUndoCommands || !mActiveCommand || !mUndoStack )
439 mActiveCommand->saveAfterState();
440 mIgnoreUndoStackChanges++;
441 mUndoStack->push( mActiveCommand.release() );
442 mIgnoreUndoStackChanges--;
446void QgsModelDesignerDialog::abortUndoCommand()
448 if ( mActiveCommand )
449 mActiveCommand->setObsolete(
true );
452QgsProcessingModelAlgorithm *QgsModelDesignerDialog::model()
457void QgsModelDesignerDialog::setModel( QgsProcessingModelAlgorithm *model )
459 mModel.reset( model );
461 mGroupEdit->setText( mModel->group() );
462 mNameEdit->setText( mModel->displayName() );
463 repaintModel(
true );
464 updateVariablesGui();
468 mIgnoreUndoStackChanges++;
470 mIgnoreUndoStackChanges--;
476 QMetaObject::invokeMethod(
this, &QgsModelDesignerDialog::zoomFull, Qt::QueuedConnection );
479void QgsModelDesignerDialog::loadModel(
const QString &path )
481 auto alg = std::make_unique<QgsProcessingModelAlgorithm>();
482 if ( alg->fromFile( path ) )
485 alg->setSourceFilePath( path );
486 setModel( alg.release() );
491 QMessageBox::critical(
495 "The selected model could not be loaded.\n"
496 "See the log for more information."
502void QgsModelDesignerDialog::setModelScene( QgsModelGraphicsScene *scene )
504 QgsModelGraphicsScene *oldScene = mScene;
507 mScene->setParent(
this );
508 mScene->setLastRunResult( mLastResult, mLayerStore );
509 mScene->setModel( mModel.get() );
510 mScene->setMessageBar( mMessageBar );
513 const bool showFeatureCount = settings.
value( u
"/Processing/Modeler/ShowFeatureCount"_s,
true ).toBool();
514 if ( !showFeatureCount )
515 mScene->setFlag( QgsModelGraphicsScene::FlagHideFeatureCount );
517 mView->setModelScene( mScene );
519 mSelectTool->resetCache();
520 mSelectTool->setScene( mScene );
522 connect( mScene, &QgsModelGraphicsScene::rebuildRequired,
this, [
this] {
523 if ( mBlockRepaints )
528 connect( mScene, &QgsModelGraphicsScene::componentAboutToChange,
this, [
this](
const QString &description,
const QString &
id ) { beginUndoCommand( description,
id ); } );
529 connect( mScene, &QgsModelGraphicsScene::componentChanged,
this, [
this] { endUndoCommand(); } );
530 connect( mScene, &QgsModelGraphicsScene::runFromChild,
this, &QgsModelDesignerDialog::runFromChild );
531 connect( mScene, &QgsModelGraphicsScene::runSelected,
this, &QgsModelDesignerDialog::runSelectedSteps );
532 connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmOutputs,
this, &QgsModelDesignerDialog::showChildAlgorithmOutputs );
533 connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmLog,
this, &QgsModelDesignerDialog::showChildAlgorithmLog );
536 oldScene->deleteLater();
539QgsModelGraphicsScene *QgsModelDesignerDialog::modelScene()
544void QgsModelDesignerDialog::activate()
548 setWindowState( windowState() & ~Qt::WindowMinimized );
554 mProcessingContextGenerator = generator;
557void QgsModelDesignerDialog::updateVariablesGui()
559 mBlockUndoCommands++;
561 auto variablesScope = std::make_unique<QgsExpressionContextScope>( tr(
"Model Variables" ) );
562 const QVariantMap modelVars = mModel->variables();
563 for (
auto it = modelVars.constBegin(); it != modelVars.constEnd(); ++it )
565 variablesScope->setVariable( it.key(), it.value() );
568 variablesContext.
appendScope( variablesScope.release() );
569 mVariablesEditor->setContext( &variablesContext );
570 mVariablesEditor->setEditableScopeIndex( 0 );
572 mBlockUndoCommands--;
575void QgsModelDesignerDialog::setDirty(
bool dirty )
581bool QgsModelDesignerDialog::validateSave( SaveAction action )
585 case QgsModelDesignerDialog::SaveAction::SaveAsFile:
587 case QgsModelDesignerDialog::SaveAction::SaveInProject:
588 if ( mNameEdit->text().trimmed().isEmpty() )
590 mMessageBar->pushWarning( QString(), tr(
"Please enter a model name before saving" ) );
599bool QgsModelDesignerDialog::checkForUnsavedChanges()
603 QMessageBox::StandardButton ret = QMessageBox::
604 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 );
607 case QMessageBox::Save:
608 return saveModel(
false );
610 case QMessageBox::Discard:
625 mLastResult.mergeWith( result );
627 mScene->setLastRunResult( mLastResult, mLayerStore );
630void QgsModelDesignerDialog::setModelName(
const QString &name )
632 mNameEdit->setText( name );
635void QgsModelDesignerDialog::zoomIn()
637 mView->setTransformationAnchor( QGraphicsView::NoAnchor );
638 QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
640 const double factor = settings.
value( u
"/qgis/zoom_favor"_s, 2.0 ).toDouble();
641 mView->scale( factor, factor );
642 mView->centerOn( point );
645void QgsModelDesignerDialog::zoomOut()
647 mView->setTransformationAnchor( QGraphicsView::NoAnchor );
648 QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
650 const double factor = 1.0 / settings.
value( u
"/qgis/zoom_favor"_s, 2.0 ).toDouble();
651 mView->scale( factor, factor );
652 mView->centerOn( point );
655void QgsModelDesignerDialog::zoomActual()
657 QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
658 mView->resetTransform();
659 mView->scale( mScreenHelper->screenDpi() / 96, mScreenHelper->screenDpi() / 96 );
660 mView->centerOn( point );
663void QgsModelDesignerDialog::zoomFull()
665 QRectF totalRect = mView->scene()->itemsBoundingRect();
666 totalRect.adjust( -10, -10, 10, 10 );
667 mView->fitInView( totalRect, Qt::KeepAspectRatio );
670void QgsModelDesignerDialog::newModel()
672 if ( !checkForUnsavedChanges() )
675 auto alg = std::make_unique<QgsProcessingModelAlgorithm>();
677 setModel( alg.release() );
680void QgsModelDesignerDialog::exportToImage()
683 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
685 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as Image" ), lastExportDir, tr(
"PNG files (*.png *.PNG)" ) );
689 if ( filename.isEmpty() )
694 const QFileInfo saveFileInfo( filename );
697 repaintModel(
false );
699 QRectF totalRect = mView->scene()->itemsBoundingRect();
700 totalRect.adjust( -10, -10, 10, 10 );
701 const QRectF imageRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
703 QImage img( totalRect.width(), totalRect.height(), QImage::Format_ARGB32_Premultiplied );
704 img.fill( Qt::white );
706 painter.setRenderHint( QPainter::Antialiasing );
707 painter.begin( &img );
708 mView->scene()->render( &painter, imageRect, totalRect );
711 img.save( filename );
714 ->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 );
715 repaintModel(
true );
718void QgsModelDesignerDialog::exportToPdf()
721 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
723 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as PDF" ), lastExportDir, tr(
"PDF files (*.pdf *.PDF)" ) );
727 if ( filename.isEmpty() )
732 const QFileInfo saveFileInfo( filename );
735 repaintModel(
false );
737 QRectF totalRect = mView->scene()->itemsBoundingRect();
738 totalRect.adjust( -10, -10, 10, 10 );
739 const QRectF printerRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
741 QPdfWriter pdfWriter( filename );
743 const double scaleFactor = 96 / 25.4;
745 QPageLayout pageLayout( QPageSize( totalRect.size() / scaleFactor, QPageSize::Millimeter ), QPageLayout::Portrait, QMarginsF( 0, 0, 0, 0 ) );
746 pageLayout.setMode( QPageLayout::FullPageMode );
747 pdfWriter.setPageLayout( pageLayout );
749 QPainter painter( &pdfWriter );
750 mView->scene()->render( &painter, printerRect, totalRect );
754 ->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 );
755 repaintModel(
true );
758void QgsModelDesignerDialog::exportToSvg()
761 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
763 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as SVG" ), lastExportDir, tr(
"SVG files (*.svg *.SVG)" ) );
767 if ( filename.isEmpty() )
772 const QFileInfo saveFileInfo( filename );
775 repaintModel(
false );
777 QRectF totalRect = mView->scene()->itemsBoundingRect();
778 totalRect.adjust( -10, -10, 10, 10 );
779 const QRectF svgRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
782 svg.setFileName( filename );
783 svg.setSize( QSize( totalRect.width(), totalRect.height() ) );
784 svg.setViewBox( svgRect );
785 svg.setTitle( mModel->displayName() );
787 QPainter painter( &svg );
788 mView->scene()->render( &painter, svgRect, totalRect );
792 ->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 );
793 repaintModel(
true );
796void QgsModelDesignerDialog::exportAsPython()
799 QString lastExportDir = settings.
value( u
"lastModelDesignerExportDir"_s, QDir::homePath(),
QgsSettings::App ).toString();
801 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save Model as Python Script" ), lastExportDir, tr(
"Processing scripts (*.py *.PY)" ) );
805 if ( filename.isEmpty() )
810 const QFileInfo saveFileInfo( filename );
815 QFile outFile( filename );
816 if ( !outFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
820 QTextStream fout( &outFile );
825 ->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 );
828void QgsModelDesignerDialog::toggleComments(
bool show )
832 repaintModel(
true );
835void QgsModelDesignerDialog::toggleFeatureCount(
bool show )
839 repaintModel(
true );
842void QgsModelDesignerDialog::updateWindowTitle()
844 QString title = tr(
"Model Designer" );
845 if ( !mModel->name().isEmpty() )
846 title = mModel->group().isEmpty() ? u
"%1: %2"_s.arg( title, mModel->name() ) : u
"%1: %2 - %3"_s.arg( title, mModel->group(), mModel->name() );
849 title.prepend(
'*' );
851 setWindowTitle( title );
854void QgsModelDesignerDialog::deleteSelected()
856 QList<QgsModelComponentGraphicItem *> items = mScene->selectedComponentItems();
860 if ( items.size() == 1 )
862 items.at( 0 )->deleteComponent();
866 std::sort( items.begin(), items.end(), []( QgsModelComponentGraphicItem *p1, QgsModelComponentGraphicItem *p2 ) {
871 if ( dynamic_cast<QgsModelCommentGraphicItem *>( p1 ) && dynamic_cast<QgsModelCommentGraphicItem *>( p2 ) )
873 else if ( dynamic_cast<QgsModelCommentGraphicItem *>( p1 ) )
875 else if ( dynamic_cast<QgsModelCommentGraphicItem *>( p2 ) )
878 else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p1 ) && dynamic_cast<QgsModelGroupBoxGraphicItem *>( p2 ) )
880 else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p1 ) )
882 else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p2 ) )
885 else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p1 ) && dynamic_cast<QgsModelOutputGraphicItem *>( p2 ) )
887 else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p1 ) )
889 else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p2 ) )
892 else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p1 ) && dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p2 ) )
894 else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p1 ) )
896 else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p2 ) )
903 beginUndoCommand( tr(
"Delete Components" ) );
905 QVariant prevState = mModel->toVariant();
906 mBlockUndoCommands++;
907 mBlockRepaints =
true;
909 while ( !items.empty() )
911 QgsModelComponentGraphicItem *toDelete =
nullptr;
912 for ( QgsModelComponentGraphicItem *item : items )
914 if ( item->canDeleteComponent() )
927 toDelete->deleteComponent();
928 items.removeAll( toDelete );
933 mModel->loadVariant( prevState );
934 QMessageBox::warning(
936 QObject::tr(
"Could not remove components" ),
938 "Components depend on the selected items.\n"
939 "Try to remove them before trying deleting these components."
942 mBlockUndoCommands--;
943 mActiveCommand.reset();
947 mBlockUndoCommands--;
951 mBlockRepaints =
false;
955void QgsModelDesignerDialog::populateZoomToMenu()
958 for (
const QgsProcessingModelGroupBox &box : model()->groupBoxes() )
960 if ( QgsModelComponentGraphicItem *item = mScene->groupBoxItem( box.uuid() ) )
962 QAction *zoomAction =
new QAction( box.description(), mGroupMenu );
963 connect( zoomAction, &QAction::triggered,
this, [
this, item] {
964 QRectF groupRect = item->mapToScene( item->boundingRect() ).boundingRect();
965 groupRect.adjust( -10, -10, 10, 10 );
966 mView->fitInView( groupRect, Qt::KeepAspectRatio );
967 mView->centerOn( item );
969 mGroupMenu->addAction( zoomAction );
974void QgsModelDesignerDialog::setPanelVisibility(
bool hidden )
976 const QList<QDockWidget *> docks = findChildren<QDockWidget *>();
977 const QList<QTabBar *> tabBars = findChildren<QTabBar *>();
981 mPanelStatus.clear();
983 for ( QDockWidget *dock : docks )
985 mPanelStatus.insert( dock->windowTitle(), PanelStatus( dock->isVisible(),
false ) );
986 dock->setVisible(
false );
990 for ( QTabBar *tabBar : tabBars )
992 QString currentTabTitle = tabBar->tabText( tabBar->currentIndex() );
993 mPanelStatus[currentTabTitle].isActive =
true;
999 for ( QDockWidget *dock : docks )
1001 if ( mPanelStatus.contains( dock->windowTitle() ) )
1003 dock->setVisible( mPanelStatus.value( dock->windowTitle() ).isVisible );
1008 for ( QTabBar *tabBar : tabBars )
1011 for (
int i = 0; i < tabBar->count(); ++i )
1013 QString tabTitle = tabBar->tabText( i );
1014 if ( mPanelStatus.contains( tabTitle ) && mPanelStatus.value( tabTitle ).isActive )
1016 tabBar->setCurrentIndex( i );
1020 mPanelStatus.clear();
1024void QgsModelDesignerDialog::editHelp()
1026 QgsProcessingHelpEditorDialog dialog(
this );
1027 dialog.setWindowTitle( tr(
"Edit Model Help" ) );
1028 dialog.setAlgorithm( mModel.get() );
1029 if ( dialog.exec() )
1031 beginUndoCommand( tr(
"Edit Model Help" ) );
1032 mModel->setHelpContent( dialog.helpContent() );
1037void QgsModelDesignerDialog::runSelectedSteps()
1039 QSet<QString> children;
1040 const QList<QgsModelComponentGraphicItem *> items = mScene->selectedComponentItems();
1041 for ( QgsModelComponentGraphicItem *item : items )
1043 if ( QgsProcessingModelChildAlgorithm *childAlgorithm =
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( item->component() ) )
1045 children.insert( childAlgorithm->childId() );
1049 if ( children.isEmpty() )
1051 mMessageBar->pushWarning( QString(), tr(
"No steps are selected" ) );
1058void QgsModelDesignerDialog::runFromChild(
const QString &
id )
1060 QSet<QString> children = mModel->dependentChildAlgorithms(
id );
1061 children.insert(
id );
1065void QgsModelDesignerDialog::run(
const QSet<QString> &childAlgorithmSubset )
1068 const bool isValid = model()->validate( errors );
1071 QMessageBox messageBox;
1072 messageBox.setWindowTitle( tr(
"Model is Invalid" ) );
1073 messageBox.setIcon( QMessageBox::Icon::Warning );
1074 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?" ) );
1075 messageBox.setStandardButtons( QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::Cancel );
1076 messageBox.setDefaultButton( QMessageBox::StandardButton::Cancel );
1078 QString errorString;
1079 for (
const QString &error : std::as_const( errors ) )
1081 QString cleanedError = error;
1082 const thread_local QRegularExpression re( u
"<[^>]*>"_s );
1083 cleanedError.replace( re, QString() );
1084 errorString += u
"• %1\n"_s.arg( cleanedError );
1087 messageBox.setDetailedText( errorString );
1088 if ( messageBox.exec() == QMessageBox::StandardButton::Cancel )
1092 if ( !childAlgorithmSubset.isEmpty() )
1094 for (
const QString &child : childAlgorithmSubset )
1097 const QSet<QString> requirements = mModel->dependsOnChildAlgorithms( child );
1098 for (
const QString &requirement : requirements )
1100 if ( !mLastResult.executedChildIds().contains( requirement ) )
1102 QMessageBox messageBox;
1103 messageBox.setWindowTitle( tr(
"Run Model" ) );
1104 messageBox.setIcon( QMessageBox::Icon::Warning );
1105 messageBox.setText( tr(
"Prerequisite parts of this model have not yet been run (try running the full model first)." ) );
1106 messageBox.setStandardButtons( QMessageBox::StandardButton::Ok );
1114 std::unique_ptr<QgsProcessingAlgorithmDialogBase> dialog( createExecutionDialog() );
1119 dialog->setParameters( mModel->designerParameterValues() );
1121 connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmAboutToRun,
this, [
this, &childAlgorithmSubset](
QgsProcessingContext *context ) {
1122 if ( !childAlgorithmSubset.empty() )
1125 auto modelConfig = std::make_unique<QgsProcessingModelInitialRunConfig>();
1126 modelConfig->setChildAlgorithmSubset( childAlgorithmSubset );
1127 modelConfig->setPreviouslyExecutedChildAlgorithms( mLastResult.executedChildIds() );
1128 modelConfig->setInitialChildInputs( mLastResult.rawChildInputs() );
1129 modelConfig->setInitialChildOutputs( mLastResult.rawChildOutputs() );
1133 const QMap<QString, QgsMapLayer *> previousOutputLayers = mLayerStore.temporaryLayerStore()->mapLayers();
1134 auto previousResultStore = std::make_unique<QgsMapLayerStore>();
1135 for ( auto it = previousOutputLayers.constBegin(); it != previousOutputLayers.constEnd(); ++it )
1137 std::unique_ptr<QgsMapLayer> clone( it.value()->clone() );
1138 clone->setId( it.value()->id() );
1139 previousResultStore->addMapLayer( clone.release() );
1141 previousResultStore->moveToThread( nullptr );
1142 modelConfig->setPreviousLayerStore( std::move( previousResultStore ) );
1143 context->setModelInitialRunConfig( std::move( modelConfig ) );
1147 connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmFinished,
this, [
this, &dialog](
bool,
const QVariantMap & ) {
1148 QgsProcessingContext *context = dialog->processingContext();
1150 mLayerStore.temporaryLayerStore()->removeAllMapLayers();
1151 mLayerStore.takeResultsFrom( *context );
1153 mModel->setDesignerParameterValues( dialog->createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipDefaultValueParameters ) );
1154 setLastRunResult( context->modelResult() );
1160void QgsModelDesignerDialog::showChildAlgorithmOutputs(
const QString &childId )
1162 const QString childDescription = mModel->childAlgorithm( childId ).description();
1165 const QVariantMap childAlgorithmOutputs = result.
outputs();
1166 if ( childAlgorithmOutputs.isEmpty() )
1168 mMessageBar->pushWarning( QString(), tr(
"No results are available for %1" ).arg( childDescription ) );
1175 mMessageBar->pushCritical( QString(), tr(
"Results cannot be shown for an invalid model component" ) );
1179 const QList<const QgsProcessingParameterDefinition *> outputParams =
algorithm->destinationParameterDefinitions();
1180 if ( outputParams.isEmpty() )
1183 QgsDebugError(
"Cannot show results for algorithms with no outputs" );
1187 bool foundResults =
false;
1190 const QVariant output = childAlgorithmOutputs.value( outputParam->name() );
1191 if ( !output.isValid() )
1194 if ( output.type() == QVariant::String )
1198 QgsDebugMsgLevel( u
"Loading previous result for %1: %2"_s.arg( outputParam->name(), output.toString() ), 2 );
1200 std::unique_ptr<QgsMapLayer> layer( resultLayer->clone() );
1203 if ( outputParams.size() > 1 )
1204 baseName = tr(
"%1 — %2" ).arg( childDescription, outputParam->name() );
1206 baseName = childDescription;
1210 QString name = baseName;
1215 name = tr(
"%1 (%2)" ).arg( baseName ).arg( counter );
1218 layer->setName( name );
1221 foundResults =
true;
1226 QgsDebugError( u
"Could not load previous result for %1: %2"_s.arg( outputParam->name(), output.toString() ) );
1231 if ( !foundResults )
1233 mMessageBar->pushWarning( QString(), tr(
"No results are available for %1" ).arg( childDescription ) );
1238void QgsModelDesignerDialog::showChildAlgorithmLog(
const QString &childId )
1240 const QString childDescription = mModel->childAlgorithm( childId ).description();
1243 if ( result.
htmlLog().isEmpty() )
1245 mMessageBar->pushWarning( QString(), tr(
"No log is available for %1" ).arg( childDescription ) );
1250 m.setWindowTitle( childDescription );
1251 m.setCheckBoxVisible(
false );
1252 m.setMessageAsHtml( result.
htmlLog() );
1256void QgsModelDesignerDialog::onItemFocused( QgsModelComponentGraphicItem *item )
1263 if ( !item || !item->component() )
1265 mConfigWidget->showComponentConfig(
nullptr, *context, widgetContext );
1269 mConfigWidget->showComponentConfig( item->component(), *context, widgetContext );
1273void QgsModelDesignerDialog::validate()
1276 if ( model()->validate( issues ) )
1278 mMessageBar->pushSuccess( QString(), tr(
"Model is valid!" ) );
1283 QPushButton *detailsButton =
new QPushButton( tr(
"Details" ) );
1284 connect( detailsButton, &QPushButton::clicked, detailsButton, [detailsButton, issues] {
1286 dialog->
setTitle( tr(
"Model is Invalid" ) );
1288 QString longMessage = tr(
"<p>This model is not valid:</p>" ) + u
"<ul>"_s;
1289 for (
const QString &issue : issues )
1291 longMessage += u
"<li>%1</li>"_s.arg( issue );
1293 longMessage +=
"</ul>"_L1;
1298 messageWidget->layout()->addWidget( detailsButton );
1299 mMessageBar->clearWidgets();
1304void QgsModelDesignerDialog::reorderInputs()
1306 QgsModelInputReorderDialog dlg(
this );
1307 dlg.setModel( mModel.get() );
1310 const QStringList inputOrder = dlg.inputOrder();
1311 beginUndoCommand( tr(
"Reorder Inputs" ) );
1312 mModel->setParameterOrder( inputOrder );
1317void QgsModelDesignerDialog::reorderOutputs()
1319 QgsModelOutputReorderDialog dlg(
this );
1320 dlg.setModel( mModel.get() );
1323 const QStringList outputOrder = dlg.outputOrder();
1324 beginUndoCommand( tr(
"Reorder Outputs" ) );
1325 mModel->setOutputOrder( outputOrder );
1326 mModel->setOutputGroup( dlg.outputGroup() );
1331bool QgsModelDesignerDialog::isDirty()
const
1333 return mHasChanged && mUndoStack->index() != -1;
1336void QgsModelDesignerDialog::fillInputsTree()
1339 auto parametersItem = std::make_unique<QTreeWidgetItem>();
1340 parametersItem->setText( 0, tr(
"Parameters" ) );
1343 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
1350 auto paramItem = std::make_unique<QTreeWidgetItem>();
1351 paramItem->setText( 0, param->name() );
1352 paramItem->setData( 0, Qt::UserRole, param->id() );
1353 paramItem->setIcon( 0, icon );
1354 paramItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
1355 paramItem->setToolTip( 0, param->description() );
1356 parametersItem->addChild( paramItem.release() );
1359 mInputsTreeWidget->addTopLevelItem( parametersItem.release() );
1360 mInputsTreeWidget->topLevelItem( 0 )->setExpanded(
true );
1368QgsModelChildDependenciesWidget::QgsModelChildDependenciesWidget( QWidget *parent, QgsProcessingModelAlgorithm *model,
const QString &childId )
1371 , mChildId( childId )
1373 QHBoxLayout *hl =
new QHBoxLayout();
1374 hl->setContentsMargins( 0, 0, 0, 0 );
1376 mLineEdit =
new QLineEdit();
1377 mLineEdit->setEnabled(
false );
1378 hl->addWidget( mLineEdit, 1 );
1380 mToolButton =
new QToolButton();
1381 mToolButton->setText( QString( QChar( 0x2026 ) ) );
1382 hl->addWidget( mToolButton );
1386 mLineEdit->setText( tr(
"%1 dependencies selected" ).arg( 0 ) );
1388 connect( mToolButton, &QToolButton::clicked,
this, &QgsModelChildDependenciesWidget::showDialog );
1391void QgsModelChildDependenciesWidget::setValue(
const QList<QgsProcessingModelChildDependency> &value )
1395 updateSummaryText();
1398void QgsModelChildDependenciesWidget::showDialog()
1400 const QList<QgsProcessingModelChildDependency> available = mModel->availableDependenciesForChildAlgorithm( mChildId );
1402 QVariantList availableOptions;
1403 for (
const QgsProcessingModelChildDependency &dep : available )
1404 availableOptions << QVariant::fromValue( dep );
1405 QVariantList selectedOptions;
1406 for (
const QgsProcessingModelChildDependency &dep : mValue )
1407 selectedOptions << QVariant::fromValue( dep );
1412 QgsProcessingMultipleSelectionPanelWidget *widget =
new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
1413 widget->setPanelTitle( tr(
"Algorithm Dependencies" ) );
1415 widget->setValueFormatter( [
this](
const QVariant &v ) -> QString {
1416 const QgsProcessingModelChildDependency dep = v.value<QgsProcessingModelChildDependency>();
1418 const QString description = mModel->childAlgorithm( dep.childId ).description();
1419 if ( dep.conditionalBranch.isEmpty() )
1422 return tr(
"Condition “%1” from algorithm “%2”" ).arg( dep.conditionalBranch, description );
1425 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged,
this, [
this, widget]() {
1426 QList<QgsProcessingModelChildDependency> res;
1427 for (
const QVariant &v : widget->selectedOptions() )
1429 res << v.value<QgsProcessingModelChildDependency>();
1438void QgsModelChildDependenciesWidget::updateSummaryText()
1440 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)