44#include <QKeySequence> 
   47#include <QSvgGenerator> 
   55#include <QActionGroup> 
   60QgsModelerToolboxModel::QgsModelerToolboxModel( QObject *parent )
 
   66Qt::ItemFlags QgsModelerToolboxModel::flags( 
const QModelIndex &index )
 const 
   68  Qt::ItemFlags f = QgsProcessingToolboxProxyModel::flags( index );
 
   69  const QModelIndex sourceIndex = mapToSource( index );
 
   70  if ( toolboxModel()->isAlgorithm( sourceIndex ) )
 
   72    f = f | Qt::ItemIsDragEnabled;
 
   77Qt::DropActions QgsModelerToolboxModel::supportedDragActions()
 const 
   79  return Qt::CopyAction;
 
   84QgsModelDesignerDialog::QgsModelDesignerDialog( QWidget *parent, Qt::WindowFlags flags )
 
   85  : QMainWindow( parent, flags )
 
   86  , mToolsActionGroup( new QActionGroup( this ) )
 
   94  setAttribute( Qt::WA_DeleteOnClose );
 
   95  setDockOptions( dockOptions() | QMainWindow::GroupedDragging );
 
   96  setWindowFlags( Qt::WindowMinimizeButtonHint |
 
   97                  Qt::WindowMaximizeButtonHint |
 
   98                  Qt::WindowCloseButtonHint );
 
  102  mModel = std::make_unique< QgsProcessingModelAlgorithm >();
 
  105  mUndoStack = 
new QUndoStack( 
this );
 
  106  connect( mUndoStack, &QUndoStack::indexChanged, 
this, [ = ]
 
  108    if ( mIgnoreUndoStackChanges )
 
  111    mBlockUndoCommands++;
 
  112    updateVariablesGui();
 
  113    mGroupEdit->setText( mModel->group() );
 
  114    mNameEdit->setText( mModel->displayName() );
 
  115    mBlockUndoCommands--;
 
  119  mPropertiesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable );
 
  120  mInputsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable );
 
  121  mAlgorithmsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable );
 
  122  mVariablesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
 
  124  mAlgorithmsTree->header()->setVisible( 
false );
 
  125  mAlgorithmSearchEdit->setShowSearchIcon( 
true );
 
  126  mAlgorithmSearchEdit->setPlaceholderText( tr( 
"Search…" ) );
 
  127  connect( mAlgorithmSearchEdit, &QgsFilterLineEdit::textChanged, mAlgorithmsTree, &QgsProcessingToolboxTreeView::setFilterString );
 
  129  mInputsTreeWidget->header()->setVisible( 
false );
 
  130  mInputsTreeWidget->setAlternatingRowColors( 
true );
 
  131  mInputsTreeWidget->setDragDropMode( QTreeWidget::DragOnly );
 
  132  mInputsTreeWidget->setDropIndicatorShown( 
true );
 
  134  mNameEdit->setPlaceholderText( tr( 
"Enter model name here" ) );
 
  135  mGroupEdit->setPlaceholderText( tr( 
"Enter group name here" ) );
 
  138  mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
 
  139  mainLayout->insertWidget( 0, mMessageBar );
 
  141  mView->setAcceptDrops( 
true );
 
  144  connect( mActionClose, &QAction::triggered, 
this, &QWidget::close );
 
  145  connect( mActionNew, &QAction::triggered, 
this, &QgsModelDesignerDialog::newModel );
 
  146  connect( mActionZoomIn, &QAction::triggered, 
this, &QgsModelDesignerDialog::zoomIn );
 
  147  connect( mActionZoomOut, &QAction::triggered, 
this, &QgsModelDesignerDialog::zoomOut );
 
  148  connect( mActionZoomActual, &QAction::triggered, 
this, &QgsModelDesignerDialog::zoomActual );
 
  149  connect( mActionZoomToItems, &QAction::triggered, 
this, &QgsModelDesignerDialog::zoomFull );
 
  150  connect( mActionExportImage, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportToImage );
 
  151  connect( mActionExportPdf, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportToPdf );
 
  152  connect( mActionExportSvg, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportToSvg );
 
  153  connect( mActionExportPython, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportAsPython );
 
  154  connect( mActionSave, &QAction::triggered, 
this, [ = ] { saveModel( 
false ); } );
 
  155  connect( mActionSaveAs, &QAction::triggered, 
this, [ = ] { saveModel( 
true ); } );
 
  156  connect( mActionDeleteComponents, &QAction::triggered, 
this, &QgsModelDesignerDialog::deleteSelected );
 
  157  connect( mActionSnapSelected, &QAction::triggered, mView, &QgsModelGraphicsView::snapSelected );
 
  158  connect( mActionValidate, &QAction::triggered, 
this, &QgsModelDesignerDialog::validate );
 
  159  connect( mActionReorderInputs, &QAction::triggered, 
this, &QgsModelDesignerDialog::reorderInputs );
 
  160  connect( mActionReorderOutputs, &QAction::triggered, 
this, &QgsModelDesignerDialog::reorderOutputs );
 
  161  connect( mActionEditHelp, &QAction::triggered, 
this, &QgsModelDesignerDialog::editHelp );
 
  162  connect( mReorderInputsButton, &QPushButton::clicked, 
this, &QgsModelDesignerDialog::reorderInputs );
 
  163  connect( mActionRun, &QAction::triggered, 
this, [
this] { run(); } );
 
  164  connect( mActionRunSelectedSteps, &QAction::triggered, 
this, &QgsModelDesignerDialog::runSelectedSteps );
 
  166  mActionSnappingEnabled->setChecked( settings.
value( QStringLiteral( 
"/Processing/Modeler/enableSnapToGrid" ), 
false ).toBool() );
 
  167  connect( mActionSnappingEnabled, &QAction::toggled, 
this, [ = ]( 
bool enabled )
 
  169    mView->snapper()->setSnapToGrid( enabled );
 
  170    QgsSettings().
setValue( QStringLiteral( 
"/Processing/Modeler/enableSnapToGrid" ), enabled );
 
  172  mView->snapper()->setSnapToGrid( mActionSnappingEnabled->isChecked() );
 
  174  connect( mActionSelectAll, &QAction::triggered, 
this, [ = ]
 
  179  QStringList docksTitle = settings.
value( QStringLiteral( 
"ModelDesigner/hiddenDocksTitle" ), QStringList(), 
QgsSettings::App ).toStringList();
 
  180  QStringList docksActive = settings.
value( QStringLiteral( 
"ModelDesigner/hiddenDocksActive" ), QStringList(), 
QgsSettings::App ).toStringList();
 
  181  if ( !docksTitle.isEmpty() )
 
  183    for ( 
const auto &title : docksTitle )
 
  185      mPanelStatus.insert( title, PanelStatus( 
true, docksActive.contains( title ) ) );
 
  188  mActionHidePanels->setChecked( !docksTitle.isEmpty() );
 
  189  connect( mActionHidePanels, &QAction::toggled, 
this, &QgsModelDesignerDialog::setPanelVisibility );
 
  191  mUndoAction = mUndoStack->createUndoAction( 
this );
 
  193  mUndoAction->setShortcuts( QKeySequence::Undo );
 
  194  mRedoAction = mUndoStack->createRedoAction( 
this );
 
  196  mRedoAction->setShortcuts( QKeySequence::Redo );
 
  198  mMenuEdit->insertAction( mActionDeleteComponents, mRedoAction );
 
  199  mMenuEdit->insertAction( mActionDeleteComponents, mUndoAction );
 
  200  mMenuEdit->insertSeparator( mActionDeleteComponents );
 
  201  mToolbar->insertAction( mActionZoomIn, mUndoAction );
 
  202  mToolbar->insertAction( mActionZoomIn, mRedoAction );
 
  203  mToolbar->insertSeparator( mActionZoomIn );
 
  205  mGroupMenu = 
new QMenu( tr( 
"Zoom To" ), 
this );
 
  206  mMenuView->insertMenu( mActionZoomIn, mGroupMenu );
 
  207  connect( mGroupMenu, &QMenu::aboutToShow, 
this, &QgsModelDesignerDialog::populateZoomToMenu );
 
  211  mActionCut = 
new QAction( tr( 
"Cu&t" ), 
this );
 
  212  mActionCut->setShortcuts( QKeySequence::Cut );
 
  213  mActionCut->setStatusTip( tr( 
"Cut" ) );
 
  215  connect( mActionCut, &QAction::triggered, 
this, [ = ]
 
  217    mView->copySelectedItems( QgsModelGraphicsView::ClipboardCut );
 
  220  mActionCopy = 
new QAction( tr( 
"&Copy" ), 
this );
 
  221  mActionCopy->setShortcuts( QKeySequence::Copy );
 
  222  mActionCopy->setStatusTip( tr( 
"Copy" ) );
 
  224  connect( mActionCopy, &QAction::triggered, 
this, [ = ]
 
  226    mView->copySelectedItems( QgsModelGraphicsView::ClipboardCopy );
 
  229  mActionPaste = 
new QAction( tr( 
"&Paste" ), 
this );
 
  230  mActionPaste->setShortcuts( QKeySequence::Paste );
 
  231  mActionPaste->setStatusTip( tr( 
"Paste" ) );
 
  233  connect( mActionPaste, &QAction::triggered, 
this, [ = ]
 
  235    mView->pasteItems( QgsModelGraphicsView::PasteModeCursor );
 
  237  mMenuEdit->insertAction( mActionDeleteComponents, mActionCut );
 
  238  mMenuEdit->insertAction( mActionDeleteComponents, mActionCopy );
 
  239  mMenuEdit->insertAction( mActionDeleteComponents, mActionPaste );
 
  240  mMenuEdit->insertSeparator( mActionDeleteComponents );
 
  242  mAlgorithmsModel = 
new QgsModelerToolboxModel( 
this );
 
  243  mAlgorithmsTree->setToolboxProxyModel( mAlgorithmsModel );
 
  246  if ( settings.
value( QStringLiteral( 
"Processing/Configuration/SHOW_ALGORITHMS_KNOWN_ISSUES" ), 
false ).toBool() )
 
  250  mAlgorithmsTree->setFilters( filters );
 
  251  mAlgorithmsTree->setDragDropMode( QTreeWidget::DragOnly );
 
  252  mAlgorithmsTree->setDropIndicatorShown( 
true );
 
  254  connect( mView, &QgsModelGraphicsView::algorithmDropped, 
this, [ = ]( 
const QString & algorithmId, 
const QPointF & pos )
 
  256    addAlgorithm( algorithmId, pos );
 
  258  connect( mAlgorithmsTree, &QgsProcessingToolboxTreeView::doubleClicked, 
this, [ = ]()
 
  260    if ( mAlgorithmsTree->selectedAlgorithm() )
 
  261      addAlgorithm( mAlgorithmsTree->selectedAlgorithm()->id(), QPointF() );
 
  263  connect( mInputsTreeWidget, &QgsModelDesignerInputsTreeWidget::doubleClicked, 
this, [ = ]( 
const QModelIndex & )
 
  265    const QString parameterType = mInputsTreeWidget->currentItem()->data( 0, Qt::UserRole ).toString();
 
  266    addInput( parameterType, QPointF() );
 
  269  connect( mView, &QgsModelGraphicsView::inputDropped, 
this, &QgsModelDesignerDialog::addInput );
 
  272  QShortcut *ctrlEquals = 
new QShortcut( QKeySequence( QStringLiteral( 
"Ctrl+=" ) ), 
this );
 
  273  connect( ctrlEquals, &QShortcut::activated, 
this, &QgsModelDesignerDialog::zoomIn );
 
  276  mUndoDock->setObjectName( QStringLiteral( 
"UndoDock" ) );
 
  277  mUndoView = 
new QUndoView( mUndoStack, 
this );
 
  278  mUndoDock->setWidget( mUndoView );
 
  279  mUndoDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
 
  280  addDockWidget( Qt::DockWidgetArea::LeftDockWidgetArea, mUndoDock );
 
  282  tabifyDockWidget( mUndoDock, mPropertiesDock );
 
  283  tabifyDockWidget( mVariablesDock, mPropertiesDock );
 
  284  mPropertiesDock->raise();
 
  285  tabifyDockWidget( mInputsDock, mAlgorithmsDock );
 
  286  mInputsDock->raise();
 
  292      beginUndoCommand( tr( 
"Change Model Variables" ) );
 
  293      mModel->setVariables( mVariablesEditor->variablesInActiveScope() );
 
  297  connect( mNameEdit, &QLineEdit::textChanged, 
this, [ = ]( 
const QString & name )
 
  301      beginUndoCommand( tr( 
"Change Model Name" ), NameChanged );
 
  302      mModel->setName( name );
 
  307  connect( mGroupEdit, &QLineEdit::textChanged, 
this, [ = ]( 
const QString & group )
 
  311      beginUndoCommand( tr( 
"Change Model Group" ), GroupChanged );
 
  312      mModel->setGroup( group );
 
  319  QToolButton *toolbuttonExportToScript = 
new QToolButton();
 
  320  toolbuttonExportToScript->setPopupMode( QToolButton::InstantPopup );
 
  321  toolbuttonExportToScript->addAction( mActionExportAsScriptAlgorithm );
 
  322  toolbuttonExportToScript->setDefaultAction( mActionExportAsScriptAlgorithm );
 
  323  mToolbar->insertWidget( mActionExportImage, toolbuttonExportToScript );
 
  324  connect( mActionExportAsScriptAlgorithm, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportAsScriptAlgorithm );
 
  326  mActionShowComments->setChecked( settings.
value( QStringLiteral( 
"/Processing/Modeler/ShowComments" ), 
true ).toBool() );
 
  327  connect( mActionShowComments, &QAction::toggled, 
this, &QgsModelDesignerDialog::toggleComments );
 
  330  mPanTool->setAction( mActionPan );
 
  332  mToolsActionGroup->addAction( mActionPan );
 
  333  connect( mActionPan, &QAction::triggered, mPanTool, [ = ] { mView->setTool( mPanTool ); } );
 
  336  mSelectTool->setAction( mActionSelectMoveItem );
 
  338  mToolsActionGroup->addAction( mActionSelectMoveItem );
 
  339  connect( mActionSelectMoveItem, &QAction::triggered, mSelectTool, [ = ] { mView->setTool( mSelectTool ); } );
 
  341  mView->setTool( mSelectTool );
 
  344  connect( mView, &QgsModelGraphicsView::macroCommandStarted, 
this, [ = ]( 
const QString & text )
 
  346    mIgnoreUndoStackChanges++;
 
  347    mUndoStack->beginMacro( text );
 
  348    mIgnoreUndoStackChanges--;
 
  350  connect( mView, &QgsModelGraphicsView::macroCommandEnded, 
this, [ = ]
 
  352    mIgnoreUndoStackChanges++;
 
  353    mUndoStack->endMacro();
 
  354    mIgnoreUndoStackChanges--;
 
  356  connect( mView, &QgsModelGraphicsView::beginCommand, 
this, [ = ]( 
const QString & text )
 
  358    beginUndoCommand( text );
 
  360  connect( mView, &QgsModelGraphicsView::endCommand, 
this, [ = ]
 
  364  connect( mView, &QgsModelGraphicsView::deleteSelectedItems, 
this, [ = ]
 
  369  connect( mActionAddGroupBox, &QAction::triggered, 
this, [ = ]
 
  371    const QPointF viewCenter = mView->mapToScene( mView->viewport()->rect().center() );
 
  372    QgsProcessingModelGroupBox group;
 
  373    group.setPosition( viewCenter );
 
  374    group.setDescription( tr( 
"New Group" ) );
 
  376    beginUndoCommand( tr( 
"Add Group Box" ) );
 
  377    model()->addGroupBox( group );
 
  385  restoreState( settings.
value( QStringLiteral( 
"ModelDesigner/state" ), QByteArray(), 
QgsSettings::App ).toByteArray() );
 
  388QgsModelDesignerDialog::~QgsModelDesignerDialog()
 
  391  if ( !mPanelStatus.isEmpty() )
 
  393    QStringList docksTitle;
 
  394    QStringList docksActive;
 
  396    for ( 
const auto &panel : mPanelStatus.toStdMap() )
 
  398      if ( panel.second.isVisible )
 
  399        docksTitle << panel.first;
 
  400      if ( panel.second.isActive )
 
  401        docksActive << panel.first;
 
  415  mIgnoreUndoStackChanges++;
 
  419void QgsModelDesignerDialog::closeEvent( QCloseEvent *event )
 
  421  if ( checkForUnsavedChanges() )
 
  427void QgsModelDesignerDialog::beginUndoCommand( 
const QString &text, 
int id )
 
  429  if ( mBlockUndoCommands || !mUndoStack )
 
  432  if ( mActiveCommand )
 
  435  mActiveCommand = std::make_unique< QgsModelUndoCommand >( mModel.get(), text, 
id );
 
  438void QgsModelDesignerDialog::endUndoCommand()
 
  440  if ( mBlockUndoCommands || !mActiveCommand || !mUndoStack )
 
  443  mActiveCommand->saveAfterState();
 
  444  mIgnoreUndoStackChanges++;
 
  445  mUndoStack->push( mActiveCommand.release() );
 
  446  mIgnoreUndoStackChanges--;
 
  450QgsProcessingModelAlgorithm *QgsModelDesignerDialog::model()
 
  455void QgsModelDesignerDialog::setModel( QgsProcessingModelAlgorithm *model )
 
  457  mModel.reset( model );
 
  459  mGroupEdit->setText( mModel->group() );
 
  460  mNameEdit->setText( mModel->displayName() );
 
  462  updateVariablesGui();
 
  464  mView->centerOn( 0, 0 );
 
  467  mIgnoreUndoStackChanges++;
 
  469  mIgnoreUndoStackChanges--;
 
  474void QgsModelDesignerDialog::loadModel( 
const QString &path )
 
  476  std::unique_ptr< QgsProcessingModelAlgorithm > 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 );
 
  498  mScene->setModel( mModel.get() );
 
  499  mScene->setMessageBar( mMessageBar );
 
  501  const QPointF center = mView->mapToScene( mView->viewport()->rect().center() );
 
  502  mView->setModelScene( mScene );
 
  504  mSelectTool->resetCache();
 
  505  mSelectTool->setScene( mScene );
 
  507  connect( mScene, &QgsModelGraphicsScene::rebuildRequired, 
this, [ = ]
 
  509    if ( mBlockRepaints )
 
  514  connect( mScene, &QgsModelGraphicsScene::componentAboutToChange, 
this, [ = ]( 
const QString & description, 
int id ) { beginUndoCommand( description, 
id ); } );
 
  515  connect( mScene, &QgsModelGraphicsScene::componentChanged, 
this, [ = ] { endUndoCommand(); } );
 
  516  connect( mScene, &QgsModelGraphicsScene::runFromChild, 
this, &QgsModelDesignerDialog::runFromChild );
 
  517  connect( mScene, &QgsModelGraphicsScene::runSelected, 
this, &QgsModelDesignerDialog::runSelectedSteps );
 
  518  connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmOutputs, 
this, &QgsModelDesignerDialog::showChildAlgorithmOutputs );
 
  519  connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmLog, 
this, &QgsModelDesignerDialog::showChildAlgorithmLog );
 
  521  mView->centerOn( center );
 
  524    oldScene->deleteLater();
 
  527void QgsModelDesignerDialog::activate()
 
  531  setWindowState( windowState() & ~Qt::WindowMinimized );
 
  535void QgsModelDesignerDialog::updateVariablesGui()
 
  537  mBlockUndoCommands++;
 
  539  std::unique_ptr< QgsExpressionContextScope > variablesScope = std::make_unique< QgsExpressionContextScope >( tr( 
"Model Variables" ) );
 
  540  const QVariantMap modelVars = mModel->variables();
 
  541  for ( 
auto it = modelVars.constBegin(); it != modelVars.constEnd(); ++it )
 
  543    variablesScope->setVariable( it.key(), it.value() );
 
  546  variablesContext.
appendScope( variablesScope.release() );
 
  547  mVariablesEditor->setContext( &variablesContext );
 
  548  mVariablesEditor->setEditableScopeIndex( 0 );
 
  550  mBlockUndoCommands--;
 
  553void QgsModelDesignerDialog::setDirty( 
bool dirty )
 
  559bool QgsModelDesignerDialog::validateSave( SaveAction action )
 
  563    case QgsModelDesignerDialog::SaveAction::SaveAsFile:
 
  565    case QgsModelDesignerDialog::SaveAction::SaveInProject:
 
  566      if ( mNameEdit->text().trimmed().isEmpty() )
 
  568        mMessageBar->pushWarning( QString(), tr( 
"Please enter a model name before saving" ) );
 
  577bool QgsModelDesignerDialog::checkForUnsavedChanges()
 
  581    QMessageBox::StandardButton ret = QMessageBox::question( 
this, tr( 
"Save Model?" ),
 
  582                                      tr( 
"There are unsaved changes in this model. Do you want to keep those?" ),
 
  583                                      QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard, QMessageBox::Cancel );
 
  586      case QMessageBox::Save:
 
  587        return saveModel( 
false );
 
  589      case QMessageBox::Discard:
 
  604  mLastResult.mergeWith( result );
 
  606    mScene->setLastRunResult( mLastResult );
 
  609void QgsModelDesignerDialog::setModelName( 
const QString &name )
 
  611  mNameEdit->setText( name );
 
  614void QgsModelDesignerDialog::zoomIn()
 
  616  mView->setTransformationAnchor( QGraphicsView::NoAnchor );
 
  617  QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
 
  619  const double factor = settings.
value( QStringLiteral( 
"/qgis/zoom_favor" ), 2.0 ).toDouble();
 
  620  mView->scale( factor, factor );
 
  621  mView->centerOn( point );
 
  624void QgsModelDesignerDialog::zoomOut()
 
  626  mView->setTransformationAnchor( QGraphicsView::NoAnchor );
 
  627  QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
 
  629  const double factor = 1.0 / settings.
value( QStringLiteral( 
"/qgis/zoom_favor" ), 2.0 ).toDouble();
 
  630  mView->scale( factor, factor );
 
  631  mView->centerOn( point );
 
  634void QgsModelDesignerDialog::zoomActual()
 
  636  QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
 
  637  mView->resetTransform();
 
  638  mView->scale( mScreenHelper->screenDpi() / 96, mScreenHelper->screenDpi() / 96 );
 
  639  mView->centerOn( point );
 
  642void QgsModelDesignerDialog::zoomFull()
 
  644  QRectF totalRect = mView->scene()->itemsBoundingRect();
 
  645  totalRect.adjust( -10, -10, 10, 10 );
 
  646  mView->fitInView( totalRect, Qt::KeepAspectRatio );
 
  649void QgsModelDesignerDialog::newModel()
 
  651  if ( !checkForUnsavedChanges() )
 
  654  std::unique_ptr< QgsProcessingModelAlgorithm > alg = std::make_unique< QgsProcessingModelAlgorithm >();
 
  656  setModel( alg.release() );
 
  659void QgsModelDesignerDialog::exportToImage()
 
  662  QString lastExportDir = settings.
value( QStringLiteral( 
"lastModelDesignerExportDir" ), QDir::homePath(), 
QgsSettings::App ).toString();
 
  664  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save Model as Image" ),
 
  666                     tr( 
"PNG files (*.png *.PNG)" ) );
 
  670  if ( filename.isEmpty() )
 
  675  const QFileInfo saveFileInfo( filename );
 
  678  repaintModel( 
false );
 
  680  QRectF totalRect = mView->scene()->itemsBoundingRect();
 
  681  totalRect.adjust( -10, -10, 10, 10 );
 
  682  const QRectF imageRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
 
  684  QImage img( totalRect.width(), totalRect.height(),
 
  685              QImage::Format_ARGB32_Premultiplied );
 
  686  img.fill( Qt::white );
 
  688  painter.setRenderHint( QPainter::Antialiasing );
 
  689  painter.begin( &img );
 
  690  mView->scene()->render( &painter, imageRect, totalRect );
 
  693  img.save( filename );
 
  695  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 );
 
  696  repaintModel( 
true );
 
  699void QgsModelDesignerDialog::exportToPdf()
 
  702  QString lastExportDir = settings.
value( QStringLiteral( 
"lastModelDesignerExportDir" ), QDir::homePath(), 
QgsSettings::App ).toString();
 
  704  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save Model as PDF" ),
 
  706                     tr( 
"PDF files (*.pdf *.PDF)" ) );
 
  710  if ( filename.isEmpty() )
 
  715  const QFileInfo saveFileInfo( filename );
 
  718  repaintModel( 
false );
 
  720  QRectF totalRect = mView->scene()->itemsBoundingRect();
 
  721  totalRect.adjust( -10, -10, 10, 10 );
 
  722  const QRectF printerRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
 
  724  QPdfWriter pdfWriter( filename );
 
  726  const double scaleFactor = 96 / 25.4; 
 
  728  QPageLayout pageLayout( QPageSize( totalRect.size() / scaleFactor, QPageSize::Millimeter ),
 
  729                          QPageLayout::Portrait,
 
  730                          QMarginsF( 0, 0, 0, 0 ) );
 
  731  pageLayout.setMode( QPageLayout::FullPageMode );
 
  732  pdfWriter.setPageLayout( pageLayout );
 
  734  QPainter painter( &pdfWriter );
 
  735  mView->scene()->render( &painter, printerRect, totalRect );
 
  738  mMessageBar->pushMessage( QString(), tr( 
"Successfully exported model as PDF to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( filename ).toString(),
 
  740  repaintModel( 
true );
 
  743void QgsModelDesignerDialog::exportToSvg()
 
  746  QString lastExportDir = settings.
value( QStringLiteral( 
"lastModelDesignerExportDir" ), QDir::homePath(), 
QgsSettings::App ).toString();
 
  748  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save Model as SVG" ),
 
  750                     tr( 
"SVG files (*.svg *.SVG)" ) );
 
  754  if ( filename.isEmpty() )
 
  759  const QFileInfo saveFileInfo( filename );
 
  762  repaintModel( 
false );
 
  764  QRectF totalRect = mView->scene()->itemsBoundingRect();
 
  765  totalRect.adjust( -10, -10, 10, 10 );
 
  766  const QRectF svgRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
 
  769  svg.setFileName( filename );
 
  770  svg.setSize( QSize( totalRect.width(), totalRect.height() ) );
 
  771  svg.setViewBox( svgRect );
 
  772  svg.setTitle( mModel->displayName() );
 
  774  QPainter painter( &svg );
 
  775  mView->scene()->render( &painter, svgRect, totalRect );
 
  778  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 );
 
  779  repaintModel( 
true );
 
  782void QgsModelDesignerDialog::exportAsPython()
 
  785  QString lastExportDir = settings.
value( QStringLiteral( 
"lastModelDesignerExportDir" ), QDir::homePath(), 
QgsSettings::App ).toString();
 
  787  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save Model as Python Script" ),
 
  789                     tr( 
"Processing scripts (*.py *.PY)" ) );
 
  793  if ( filename.isEmpty() )
 
  798  const QFileInfo saveFileInfo( filename );
 
  803  QFile outFile( filename );
 
  804  if ( !outFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
 
  808  QTextStream fout( &outFile );
 
  812  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 );
 
  815void QgsModelDesignerDialog::toggleComments( 
bool show )
 
  819  repaintModel( 
true );
 
  822void QgsModelDesignerDialog::updateWindowTitle()
 
  824  QString title = tr( 
"Model Designer" );
 
  825  if ( !mModel->name().isEmpty() )
 
  826    title = QStringLiteral( 
"%1 - %2" ).arg( title, mModel->name() );
 
  829    title.prepend( 
'*' );
 
  831  setWindowTitle( title );
 
  834void QgsModelDesignerDialog::deleteSelected()
 
  836  QList< QgsModelComponentGraphicItem * > items = mScene->selectedComponentItems();
 
  840  if ( items.size() == 1 )
 
  842    items.at( 0 )->deleteComponent();
 
  846  std::sort( items.begin(), items.end(), []( QgsModelComponentGraphicItem * p1, QgsModelComponentGraphicItem * p2 )
 
  849    if ( dynamic_cast< QgsModelCommentGraphicItem *>( p1 ) )
 
  851    else if ( dynamic_cast< QgsModelCommentGraphicItem *>( p2 ) )
 
  853    else if ( dynamic_cast< QgsModelGroupBoxGraphicItem *>( p1 ) )
 
  855    else if ( dynamic_cast< QgsModelGroupBoxGraphicItem *>( p2 ) )
 
  857    else if ( dynamic_cast< QgsModelOutputGraphicItem *>( p1 ) )
 
  859    else if ( dynamic_cast< QgsModelOutputGraphicItem *>( p2 ) )
 
  861    else if ( dynamic_cast< QgsModelChildAlgorithmGraphicItem *>( p1 ) )
 
  863    else if ( dynamic_cast< QgsModelChildAlgorithmGraphicItem *>( p2 ) )
 
  869  beginUndoCommand( tr( 
"Delete Components" ) );
 
  871  QVariant prevState = mModel->toVariant();
 
  872  mBlockUndoCommands++;
 
  873  mBlockRepaints = 
true;
 
  875  while ( !items.empty() )
 
  877    QgsModelComponentGraphicItem *toDelete = 
nullptr;
 
  878    for ( QgsModelComponentGraphicItem *item : items )
 
  880      if ( item->canDeleteComponent() )
 
  893    toDelete->deleteComponent();
 
  894    items.removeAll( toDelete );
 
  899    mModel->loadVariant( prevState );
 
  900    QMessageBox::warning( 
nullptr, QObject::tr( 
"Could not remove components" ),
 
  901                          QObject::tr( 
"Components depend on the selected items.\n" 
  902                                       "Try to remove them before trying deleting these components." ) );
 
  903    mBlockUndoCommands--;
 
  904    mActiveCommand.reset();
 
  908    mBlockUndoCommands--;
 
  912  mBlockRepaints = 
false;
 
  916void QgsModelDesignerDialog::populateZoomToMenu()
 
  919  for ( 
const QgsProcessingModelGroupBox &box : model()->groupBoxes() )
 
  921    if ( QgsModelComponentGraphicItem *item = mScene->groupBoxItem( box.uuid() ) )
 
  923      QAction *zoomAction = 
new QAction( box.description(), mGroupMenu );
 
  924      connect( zoomAction, &QAction::triggered, 
this, [ = ]
 
  926        QRectF groupRect = item->mapToScene( item->boundingRect() ).boundingRect();
 
  927        groupRect.adjust( -10, -10, 10, 10 );
 
  928        mView->fitInView( groupRect, Qt::KeepAspectRatio );
 
  929        mView->centerOn( item );
 
  931      mGroupMenu->addAction( zoomAction );
 
  936void QgsModelDesignerDialog::setPanelVisibility( 
bool hidden )
 
  938  const QList<QDockWidget *> docks = findChildren<QDockWidget *>();
 
  939  const QList<QTabBar *> tabBars = findChildren<QTabBar *>();
 
  943    mPanelStatus.clear();
 
  945    for ( QDockWidget *dock : docks )
 
  947      mPanelStatus.insert( dock->windowTitle(), PanelStatus( dock->isVisible(), 
false ) );
 
  948      dock->setVisible( 
false );
 
  952    for ( QTabBar *tabBar : tabBars )
 
  954      QString currentTabTitle = tabBar->tabText( tabBar->currentIndex() );
 
  955      mPanelStatus[ currentTabTitle ].isActive = 
true;
 
  961    for ( QDockWidget *dock : docks )
 
  963      if ( mPanelStatus.contains( dock->windowTitle() ) )
 
  965        dock->setVisible( mPanelStatus.value( dock->windowTitle() ).isVisible );
 
  970    for ( QTabBar *tabBar : tabBars )
 
  973      for ( 
int i = 0; i < tabBar->count(); ++i )
 
  975        QString tabTitle = tabBar->tabText( i );
 
  976        if ( mPanelStatus.contains( tabTitle ) && mPanelStatus.value( tabTitle ).isActive )
 
  978          tabBar->setCurrentIndex( i );
 
  982    mPanelStatus.clear();
 
  986void QgsModelDesignerDialog::editHelp()
 
  988  QgsProcessingHelpEditorDialog dialog( 
this );
 
  989  dialog.setWindowTitle( tr( 
"Edit Model Help" ) );
 
  990  dialog.setAlgorithm( mModel.get() );
 
  993    beginUndoCommand( tr( 
"Edit Model Help" ) );
 
  994    mModel->setHelpContent( dialog.helpContent() );
 
  999void QgsModelDesignerDialog::runSelectedSteps()
 
 1001  QSet<QString> children;
 
 1002  const QList< QgsModelComponentGraphicItem * > items = mScene->selectedComponentItems();
 
 1003  for ( QgsModelComponentGraphicItem *item : items )
 
 1005    if ( QgsProcessingModelChildAlgorithm *childAlgorithm = 
dynamic_cast< QgsProcessingModelChildAlgorithm *
>( item->component() ) )
 
 1007      children.insert( childAlgorithm->childId() );
 
 1011  if ( children.isEmpty() )
 
 1013    mMessageBar->pushWarning( QString(), tr( 
"No steps are selected" ) );
 
 1020void QgsModelDesignerDialog::runFromChild( 
const QString &
id )
 
 1022  QSet<QString> children = mModel->dependentChildAlgorithms( 
id );
 
 1023  children.insert( 
id );
 
 1027void QgsModelDesignerDialog::run( 
const QSet<QString> &childAlgorithmSubset )
 
 1030  const bool isValid = model()->validate( errors );
 
 1033    QMessageBox messageBox;
 
 1034    messageBox.setWindowTitle( tr( 
"Model is Invalid" ) );
 
 1035    messageBox.setIcon( QMessageBox::Icon::Warning );
 
 1036    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?" ) );
 
 1037    messageBox.setStandardButtons( QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::Cancel );
 
 1038    messageBox.setDefaultButton( QMessageBox::StandardButton::Cancel );
 
 1040    QString errorString;
 
 1041    for ( 
const QString &error : std::as_const( errors ) )
 
 1043      QString cleanedError = error;
 
 1044      const thread_local QRegularExpression re( QStringLiteral( 
"<[^>]*>" ) );
 
 1045      cleanedError.replace( re, QString() );
 
 1046      errorString += QStringLiteral( 
"• %1\n" ).arg( cleanedError );
 
 1049    messageBox.setDetailedText( errorString );
 
 1050    if ( messageBox.exec() == QMessageBox::StandardButton::Cancel )
 
 1054  if ( !childAlgorithmSubset.isEmpty() )
 
 1056    for ( 
const QString &child : childAlgorithmSubset )
 
 1059      const QSet< QString > requirements = mModel->dependsOnChildAlgorithms( child );
 
 1060      for ( 
const QString &requirement : requirements )
 
 1062        if ( !mLastResult.executedChildIds().contains( requirement ) )
 
 1064          QMessageBox messageBox;
 
 1065          messageBox.setWindowTitle( tr( 
"Run Model" ) );
 
 1066          messageBox.setIcon( QMessageBox::Icon::Warning );
 
 1067          messageBox.setText( tr( 
"Prerequisite parts of this model have not yet been run (try running the full model first)." ) );
 
 1068          messageBox.setStandardButtons( QMessageBox::StandardButton::Ok );
 
 1076  std::unique_ptr< QgsProcessingAlgorithmDialogBase > dialog( createExecutionDialog() );
 
 1081  dialog->setParameters( mModel->designerParameterValues() );
 
 1083  connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmAboutToRun, 
this, [
this, &childAlgorithmSubset]( 
QgsProcessingContext * context )
 
 1085    if ( ! childAlgorithmSubset.empty() )
 
 1088      std::unique_ptr< QgsProcessingModelInitialRunConfig > modelConfig = std::make_unique< QgsProcessingModelInitialRunConfig >();
 
 1089      modelConfig->setChildAlgorithmSubset( childAlgorithmSubset );
 
 1090      modelConfig->setPreviouslyExecutedChildAlgorithms( mLastResult.executedChildIds() );
 
 1091      modelConfig->setInitialChildInputs( mLastResult.rawChildInputs() );
 
 1092      modelConfig->setInitialChildOutputs( mLastResult.rawChildOutputs() );
 
 1096      const QMap<QString, QgsMapLayer *> previousOutputLayers = mLayerStore.temporaryLayerStore()->mapLayers();
 
 1097      std::unique_ptr<QgsMapLayerStore> previousResultStore = std::make_unique< QgsMapLayerStore >();
 
 1098      for ( auto it = previousOutputLayers.constBegin(); it != previousOutputLayers.constEnd(); ++it )
 
 1100        std::unique_ptr< QgsMapLayer > clone( it.value()->clone() );
 
 1101        clone->setId( it.value()->id() );
 
 1102        previousResultStore->addMapLayer( clone.release() );
 
 1104      previousResultStore->moveToThread( nullptr );
 
 1105      modelConfig->setPreviousLayerStore( std::move( previousResultStore ) );
 
 1106      context->setModelInitialRunConfig( std::move( modelConfig ) );
 
 1110  connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmFinished, 
this, [
this, &dialog]( 
bool, 
const QVariantMap & )
 
 1112    QgsProcessingContext *context = dialog->processingContext();
 
 1114    setLastRunResult( context->modelResult() );
 
 1116    mModel->setDesignerParameterValues( dialog->createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipDefaultValueParameters ) );
 
 1119    mLayerStore.temporaryLayerStore()->removeAllMapLayers();
 
 1120    mLayerStore.takeResultsFrom( *context );
 
 1126void QgsModelDesignerDialog::showChildAlgorithmOutputs( 
const QString &childId )
 
 1128  const QString childDescription = mModel->childAlgorithm( childId ).description();
 
 1131  const QVariantMap childAlgorithmOutputs = result.
outputs();
 
 1132  if ( childAlgorithmOutputs.isEmpty() )
 
 1134    mMessageBar->pushWarning( QString(), tr( 
"No results are available for %1" ).arg( childDescription ) );
 
 1141    mMessageBar->pushCritical( QString(), tr( 
"Results cannot be shown for an invalid model component" ) );
 
 1146  if ( outputParams.isEmpty() )
 
 1149    QgsDebugError( 
"Cannot show results for algorithms with no outputs" );
 
 1153  bool foundResults = 
false;
 
 1156    const QVariant output = childAlgorithmOutputs.value( outputParam->name() );
 
 1157    if ( !output.isValid() )
 
 1160    if ( output.type() == QVariant::String )
 
 1164        QgsDebugMsgLevel( QStringLiteral( 
"Loading previous result for %1: %2" ).arg( outputParam->name(), output.toString() ), 2 );
 
 1166        std::unique_ptr< QgsMapLayer > layer( resultLayer->clone() );
 
 1169        if ( outputParams.size() > 1 )
 
 1170          baseName = tr( 
"%1 — %2" ).arg( childDescription, outputParam->name() );
 
 1172          baseName = childDescription;
 
 1176        QString name = baseName;
 
 1181          name = tr( 
"%1 (%2)" ).arg( baseName ).arg( counter );
 
 1184        layer->setName( name );
 
 1187        foundResults = 
true;
 
 1192        QgsDebugError( QStringLiteral( 
"Could not load previous result for %1: %2" ).arg( outputParam->name(), output.toString() ) );
 
 1197  if ( !foundResults )
 
 1199    mMessageBar->pushWarning( QString(), tr( 
"No results are available for %1" ).arg( childDescription ) );
 
 1204void QgsModelDesignerDialog::showChildAlgorithmLog( 
const QString &childId )
 
 1206  const QString childDescription = mModel->childAlgorithm( childId ).description();
 
 1209  if ( result.
htmlLog().isEmpty() )
 
 1211    mMessageBar->pushWarning( QString(), tr( 
"No log is available for %1" ).arg( childDescription ) );
 
 1216  m.setWindowTitle( childDescription );
 
 1217  m.setCheckBoxVisible( 
false );
 
 1218  m.setMessageAsHtml( result.
htmlLog() );
 
 1222void QgsModelDesignerDialog::validate()
 
 1225  if ( model()->validate( issues ) )
 
 1227    mMessageBar->pushSuccess( QString(), tr( 
"Model is valid!" ) );
 
 1232    QPushButton *detailsButton = 
new QPushButton( tr( 
"Details" ) );
 
 1233    connect( detailsButton, &QPushButton::clicked, detailsButton, [ = ]
 
 1236      dialog->
setTitle( tr( 
"Model is Invalid" ) );
 
 1238      QString longMessage = tr( 
"<p>This model is not valid:</p>" ) + QStringLiteral( 
"<ul>" );
 
 1239      for ( 
const QString &issue : issues )
 
 1241        longMessage += QStringLiteral( 
"<li>%1</li>" ).arg( issue );
 
 1243      longMessage += QLatin1String( 
"</ul>" );
 
 1248    messageWidget->layout()->addWidget( detailsButton );
 
 1249    mMessageBar->clearWidgets();
 
 1254void QgsModelDesignerDialog::reorderInputs()
 
 1256  QgsModelInputReorderDialog dlg( 
this );
 
 1257  dlg.setModel( mModel.get() );
 
 1260    const QStringList inputOrder = dlg.inputOrder();
 
 1261    beginUndoCommand( tr( 
"Reorder Inputs" ) );
 
 1262    mModel->setParameterOrder( inputOrder );
 
 1267void QgsModelDesignerDialog::reorderOutputs()
 
 1269  QgsModelOutputReorderDialog dlg( 
this );
 
 1270  dlg.setModel( mModel.get() );
 
 1273    const QStringList outputOrder = dlg.outputOrder();
 
 1274    beginUndoCommand( tr( 
"Reorder Outputs" ) );
 
 1275    mModel->setOutputOrder( outputOrder );
 
 1276    mModel->setOutputGroup( dlg.outputGroup() );
 
 1281bool QgsModelDesignerDialog::isDirty()
 const 
 1283  return mHasChanged && mUndoStack->index() != -1;
 
 1286void QgsModelDesignerDialog::fillInputsTree()
 
 1289  std::unique_ptr< QTreeWidgetItem > parametersItem = std::make_unique< QTreeWidgetItem >();
 
 1290  parametersItem->setText( 0, tr( 
"Parameters" ) );
 
 1294    return QString::localeAwareCompare( a->name(), b->name() ) < 0;
 
 1301      std::unique_ptr< QTreeWidgetItem > paramItem = std::make_unique< QTreeWidgetItem >();
 
 1302      paramItem->setText( 0, param->name() );
 
 1303      paramItem->setData( 0, Qt::UserRole, param->id() );
 
 1304      paramItem->setIcon( 0, icon );
 
 1305      paramItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
 
 1306      paramItem->setToolTip( 0, param->description() );
 
 1307      parametersItem->addChild( paramItem.release() );
 
 1310  mInputsTreeWidget->addTopLevelItem( parametersItem.release() );
 
 1311  mInputsTreeWidget->topLevelItem( 0 )->setExpanded( 
true );
 
 1319QgsModelChildDependenciesWidget::QgsModelChildDependenciesWidget( QWidget *parent,  QgsProcessingModelAlgorithm *model, 
const QString &childId )
 
 1322  , mChildId( childId )
 
 1324  QHBoxLayout *hl = 
new QHBoxLayout();
 
 1325  hl->setContentsMargins( 0, 0, 0, 0 );
 
 1327  mLineEdit = 
new QLineEdit();
 
 1328  mLineEdit->setEnabled( 
false );
 
 1329  hl->addWidget( mLineEdit, 1 );
 
 1331  mToolButton = 
new QToolButton();
 
 1332  mToolButton->setText( QString( QChar( 0x2026 ) ) );
 
 1333  hl->addWidget( mToolButton );
 
 1337  mLineEdit->setText( tr( 
"%1 dependencies selected" ).arg( 0 ) );
 
 1339  connect( mToolButton, &QToolButton::clicked, 
this, &QgsModelChildDependenciesWidget::showDialog );
 
 1342void QgsModelChildDependenciesWidget::setValue( 
const QList<QgsProcessingModelChildDependency> &value )
 
 1346  updateSummaryText();
 
 1349void QgsModelChildDependenciesWidget::showDialog()
 
 1351  const QList<QgsProcessingModelChildDependency> available = mModel->availableDependenciesForChildAlgorithm( mChildId );
 
 1353  QVariantList availableOptions;
 
 1354  for ( 
const QgsProcessingModelChildDependency &dep : available )
 
 1355    availableOptions << QVariant::fromValue( dep );
 
 1356  QVariantList selectedOptions;
 
 1357  for ( 
const QgsProcessingModelChildDependency &dep : mValue )
 
 1358    selectedOptions << QVariant::fromValue( dep );
 
 1363    QgsProcessingMultipleSelectionPanelWidget *widget = 
new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
 
 1364    widget->setPanelTitle( tr( 
"Algorithm Dependencies" ) );
 
 1366    widget->setValueFormatter( [ = ]( 
const QVariant & v ) -> QString
 
 1368      const QgsProcessingModelChildDependency dep = v.value< QgsProcessingModelChildDependency >();
 
 1370      const QString description = mModel->childAlgorithm( dep.childId ).description();
 
 1371      if ( dep.conditionalBranch.isEmpty() )
 
 1374        return tr( 
"Condition “%1” from algorithm “%2”" ).arg( dep.conditionalBranch, description );
 
 1377    connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, 
this, [ = ]()
 
 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 (si...
 
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)
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.
 
QgsProcessingParameterDefinitions destinationParameterDefinitions() const
Returns a list of destination parameters definitions utilized by the algorithm.
 
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.
 
This class is a composition of two QSettings instances:
 
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)