17#include "moc_qgsmodeldesignerdialog.cpp" 
   45#include <QKeySequence> 
   48#include <QSvgGenerator> 
   56#include <QActionGroup> 
   61QgsModelerToolboxModel::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 ) || toolboxModel()->isParameter( sourceIndex ) )
 
   72    f = f | Qt::ItemIsDragEnabled;
 
   77Qt::DropActions QgsModelerToolboxModel::supportedDragActions()
 const 
   79  return Qt::CopyAction;
 
   82QgsModelDesignerDialog::QgsModelDesignerDialog( QWidget *parent, Qt::WindowFlags flags )
 
   83  : QMainWindow( parent, flags )
 
   84  , mToolsActionGroup( new QActionGroup( this ) )
 
   92  setAttribute( Qt::WA_DeleteOnClose );
 
   93  setDockOptions( dockOptions() | QMainWindow::GroupedDragging );
 
   94  setWindowFlags( Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint );
 
   98  mModel = std::make_unique<QgsProcessingModelAlgorithm>();
 
  101  mUndoStack = 
new QUndoStack( 
this );
 
  102  connect( mUndoStack, &QUndoStack::indexChanged, 
this, [
this] {
 
  103    if ( mIgnoreUndoStackChanges )
 
  106    mBlockUndoCommands++;
 
  107    updateVariablesGui();
 
  108    mGroupEdit->setText( mModel->group() );
 
  109    mNameEdit->setText( mModel->displayName() );
 
  110    mBlockUndoCommands--;
 
  114  mPropertiesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable );
 
  115  mInputsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable );
 
  116  mAlgorithmsDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable );
 
  117  mVariablesDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
 
  119  mToolboxTree->header()->setVisible( 
false );
 
  120  mToolboxSearchEdit->setShowSearchIcon( 
true );
 
  121  mToolboxSearchEdit->setPlaceholderText( tr( 
"Search…" ) );
 
  122  connect( mToolboxSearchEdit, &QgsFilterLineEdit::textChanged, mToolboxTree, &QgsProcessingToolboxTreeView::setFilterString );
 
  124  mInputsTreeWidget->header()->setVisible( 
false );
 
  125  mInputsTreeWidget->setAlternatingRowColors( 
true );
 
  126  mInputsTreeWidget->setDragDropMode( QTreeWidget::DragOnly );
 
  127  mInputsTreeWidget->setDropIndicatorShown( 
true );
 
  129  mNameEdit->setPlaceholderText( tr( 
"Enter model name here" ) );
 
  130  mGroupEdit->setPlaceholderText( tr( 
"Enter group name here" ) );
 
  133  mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
 
  134  mainLayout->insertWidget( 0, mMessageBar );
 
  136  mView->setAcceptDrops( 
true );
 
  139  connect( mActionClose, &QAction::triggered, 
this, &QWidget::close );
 
  140  connect( mActionNew, &QAction::triggered, 
this, &QgsModelDesignerDialog::newModel );
 
  141  connect( mActionZoomIn, &QAction::triggered, 
this, &QgsModelDesignerDialog::zoomIn );
 
  142  connect( mActionZoomOut, &QAction::triggered, 
this, &QgsModelDesignerDialog::zoomOut );
 
  143  connect( mActionZoomActual, &QAction::triggered, 
this, &QgsModelDesignerDialog::zoomActual );
 
  144  connect( mActionZoomToItems, &QAction::triggered, 
this, &QgsModelDesignerDialog::zoomFull );
 
  145  connect( mActionExportImage, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportToImage );
 
  146  connect( mActionExportPdf, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportToPdf );
 
  147  connect( mActionExportSvg, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportToSvg );
 
  148  connect( mActionExportPython, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportAsPython );
 
  149  connect( mActionSave, &QAction::triggered, 
this, [
this] { saveModel( 
false ); } );
 
  150  connect( mActionSaveAs, &QAction::triggered, 
this, [
this] { saveModel( 
true ); } );
 
  151  connect( mActionDeleteComponents, &QAction::triggered, 
this, &QgsModelDesignerDialog::deleteSelected );
 
  152  connect( mActionSnapSelected, &QAction::triggered, mView, &QgsModelGraphicsView::snapSelected );
 
  153  connect( mActionValidate, &QAction::triggered, 
this, &QgsModelDesignerDialog::validate );
 
  154  connect( mActionReorderInputs, &QAction::triggered, 
this, &QgsModelDesignerDialog::reorderInputs );
 
  155  connect( mActionReorderOutputs, &QAction::triggered, 
this, &QgsModelDesignerDialog::reorderOutputs );
 
  156  connect( mActionEditHelp, &QAction::triggered, 
this, &QgsModelDesignerDialog::editHelp );
 
  157  connect( mReorderInputsButton, &QPushButton::clicked, 
this, &QgsModelDesignerDialog::reorderInputs );
 
  158  connect( mActionRun, &QAction::triggered, 
this, [
this] { run(); } );
 
  159  connect( mActionRunSelectedSteps, &QAction::triggered, 
this, &QgsModelDesignerDialog::runSelectedSteps );
 
  161  mActionSnappingEnabled->setChecked( settings.
value( QStringLiteral( 
"/Processing/Modeler/enableSnapToGrid" ), 
false ).toBool() );
 
  162  connect( mActionSnappingEnabled, &QAction::toggled, 
this, [
this]( 
bool enabled ) {
 
  163    mView->snapper()->setSnapToGrid( enabled );
 
  164    QgsSettings().
setValue( QStringLiteral( 
"/Processing/Modeler/enableSnapToGrid" ), enabled );
 
  166  mView->snapper()->setSnapToGrid( mActionSnappingEnabled->isChecked() );
 
  168  connect( mActionSelectAll, &QAction::triggered, 
this, [
this] {
 
  172  QStringList docksTitle = settings.
value( QStringLiteral( 
"ModelDesigner/hiddenDocksTitle" ), QStringList(), 
QgsSettings::App ).toStringList();
 
  173  QStringList docksActive = settings.
value( QStringLiteral( 
"ModelDesigner/hiddenDocksActive" ), QStringList(), 
QgsSettings::App ).toStringList();
 
  174  if ( !docksTitle.isEmpty() )
 
  176    for ( 
const auto &title : docksTitle )
 
  178      mPanelStatus.insert( title, PanelStatus( 
true, docksActive.contains( title ) ) );
 
  181  mActionHidePanels->setChecked( !docksTitle.isEmpty() );
 
  182  connect( mActionHidePanels, &QAction::toggled, 
this, &QgsModelDesignerDialog::setPanelVisibility );
 
  184  mUndoAction = mUndoStack->createUndoAction( 
this );
 
  186  mUndoAction->setShortcuts( QKeySequence::Undo );
 
  187  mRedoAction = mUndoStack->createRedoAction( 
this );
 
  189  mRedoAction->setShortcuts( QKeySequence::Redo );
 
  191  mMenuEdit->insertAction( mActionDeleteComponents, mRedoAction );
 
  192  mMenuEdit->insertAction( mActionDeleteComponents, mUndoAction );
 
  193  mMenuEdit->insertSeparator( mActionDeleteComponents );
 
  194  mToolbar->insertAction( mActionZoomIn, mUndoAction );
 
  195  mToolbar->insertAction( mActionZoomIn, mRedoAction );
 
  196  mToolbar->insertSeparator( mActionZoomIn );
 
  198  mGroupMenu = 
new QMenu( tr( 
"Zoom To" ), 
this );
 
  199  mMenuView->insertMenu( mActionZoomIn, mGroupMenu );
 
  200  connect( mGroupMenu, &QMenu::aboutToShow, 
this, &QgsModelDesignerDialog::populateZoomToMenu );
 
  204  mActionCut = 
new QAction( tr( 
"Cu&t" ), 
this );
 
  205  mActionCut->setShortcuts( QKeySequence::Cut );
 
  206  mActionCut->setStatusTip( tr( 
"Cut" ) );
 
  208  connect( mActionCut, &QAction::triggered, 
this, [
this] {
 
  209    mView->copySelectedItems( QgsModelGraphicsView::ClipboardCut );
 
  212  mActionCopy = 
new QAction( tr( 
"&Copy" ), 
this );
 
  213  mActionCopy->setShortcuts( QKeySequence::Copy );
 
  214  mActionCopy->setStatusTip( tr( 
"Copy" ) );
 
  216  connect( mActionCopy, &QAction::triggered, 
this, [
this] {
 
  217    mView->copySelectedItems( QgsModelGraphicsView::ClipboardCopy );
 
  220  mActionPaste = 
new QAction( tr( 
"&Paste" ), 
this );
 
  221  mActionPaste->setShortcuts( QKeySequence::Paste );
 
  222  mActionPaste->setStatusTip( tr( 
"Paste" ) );
 
  224  connect( mActionPaste, &QAction::triggered, 
this, [
this] {
 
  225    mView->pasteItems( QgsModelGraphicsView::PasteModeCursor );
 
  227  mMenuEdit->insertAction( mActionDeleteComponents, mActionCut );
 
  228  mMenuEdit->insertAction( mActionDeleteComponents, mActionCopy );
 
  229  mMenuEdit->insertAction( mActionDeleteComponents, mActionPaste );
 
  230  mMenuEdit->insertSeparator( mActionDeleteComponents );
 
  232  mAlgorithmsModel = 
new QgsModelerToolboxModel( 
this );
 
  233  mToolboxTree->setToolboxProxyModel( mAlgorithmsModel );
 
  236  if ( settings.
value( QStringLiteral( 
"Processing/Configuration/SHOW_ALGORITHMS_KNOWN_ISSUES" ), 
false ).toBool() )
 
  240  mToolboxTree->setFilters( filters );
 
  241  mToolboxTree->setDragDropMode( QTreeWidget::DragOnly );
 
  242  mToolboxTree->setDropIndicatorShown( 
true );
 
  244  connect( mView, &QgsModelGraphicsView::algorithmDropped, 
this, [
this]( 
const QString &algorithmId, 
const QPointF &pos ) {
 
  245    addAlgorithm( algorithmId, pos );
 
  247  connect( mView, &QgsModelGraphicsView::inputDropped, 
this, &QgsModelDesignerDialog::addInput );
 
  249  connect( mToolboxTree, &QgsProcessingToolboxTreeView::doubleClicked, 
this, [
this]( 
const QModelIndex & ) {
 
  250    if ( mToolboxTree->selectedAlgorithm() )
 
  251      addAlgorithm( mToolboxTree->selectedAlgorithm()->id(), QPointF() );
 
  252    if ( mToolboxTree->selectedParameterType() )
 
  253      addInput( mToolboxTree->selectedParameterType()->id(), QPointF() );
 
  256  connect( mInputsTreeWidget, &QgsModelDesignerInputsTreeWidget::doubleClicked, 
this, [
this]( 
const QModelIndex & ) {
 
  257    const QString parameterType = mInputsTreeWidget->currentItem()->data( 0, Qt::UserRole ).toString();
 
  258    addInput( parameterType, QPointF() );
 
  262  QShortcut *ctrlEquals = 
new QShortcut( QKeySequence( QStringLiteral( 
"Ctrl+=" ) ), 
this );
 
  263  connect( ctrlEquals, &QShortcut::activated, 
this, &QgsModelDesignerDialog::zoomIn );
 
  266  mUndoDock->setObjectName( QStringLiteral( 
"UndoDock" ) );
 
  267  mUndoView = 
new QUndoView( mUndoStack, 
this );
 
  268  mUndoDock->setWidget( mUndoView );
 
  269  mUndoDock->setFeatures( QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable );
 
  270  addDockWidget( Qt::DockWidgetArea::LeftDockWidgetArea, mUndoDock );
 
  272  tabifyDockWidget( mUndoDock, mPropertiesDock );
 
  273  tabifyDockWidget( mVariablesDock, mPropertiesDock );
 
  274  mPropertiesDock->raise();
 
  275  tabifyDockWidget( mInputsDock, mAlgorithmsDock );
 
  276  mInputsDock->raise();
 
  281      beginUndoCommand( tr( 
"Change Model Variables" ) );
 
  282      mModel->setVariables( mVariablesEditor->variablesInActiveScope() );
 
  286  connect( mNameEdit, &QLineEdit::textChanged, 
this, [
this]( 
const QString &name ) {
 
  289      beginUndoCommand( tr( 
"Change Model Name" ), NameChanged );
 
  290      mModel->setName( name );
 
  295  connect( mGroupEdit, &QLineEdit::textChanged, 
this, [
this]( 
const QString &group ) {
 
  298      beginUndoCommand( tr( 
"Change Model Group" ), GroupChanged );
 
  299      mModel->setGroup( group );
 
  307  QToolButton *toolbuttonExportToScript = 
new QToolButton();
 
  308  toolbuttonExportToScript->setPopupMode( QToolButton::InstantPopup );
 
  309  toolbuttonExportToScript->addAction( mActionExportAsScriptAlgorithm );
 
  310  toolbuttonExportToScript->setDefaultAction( mActionExportAsScriptAlgorithm );
 
  311  mToolbar->insertWidget( mActionExportImage, toolbuttonExportToScript );
 
  312  connect( mActionExportAsScriptAlgorithm, &QAction::triggered, 
this, &QgsModelDesignerDialog::exportAsScriptAlgorithm );
 
  314  mActionShowComments->setChecked( settings.
value( QStringLiteral( 
"/Processing/Modeler/ShowComments" ), 
true ).toBool() );
 
  315  connect( mActionShowComments, &QAction::toggled, 
this, &QgsModelDesignerDialog::toggleComments );
 
  318  mPanTool->setAction( mActionPan );
 
  320  mToolsActionGroup->addAction( mActionPan );
 
  321  connect( mActionPan, &QAction::triggered, mPanTool, [
this] { mView->setTool( mPanTool ); } );
 
  324  mSelectTool->setAction( mActionSelectMoveItem );
 
  326  mToolsActionGroup->addAction( mActionSelectMoveItem );
 
  327  connect( mActionSelectMoveItem, &QAction::triggered, mSelectTool, [
this] { mView->setTool( mSelectTool ); } );
 
  329  mView->setTool( mSelectTool );
 
  332  connect( mView, &QgsModelGraphicsView::macroCommandStarted, 
this, [
this]( 
const QString &text ) {
 
  333    mIgnoreUndoStackChanges++;
 
  334    mUndoStack->beginMacro( text );
 
  335    mIgnoreUndoStackChanges--;
 
  337  connect( mView, &QgsModelGraphicsView::macroCommandEnded, 
this, [
this] {
 
  338    mIgnoreUndoStackChanges++;
 
  339    mUndoStack->endMacro();
 
  340    mIgnoreUndoStackChanges--;
 
  342  connect( mView, &QgsModelGraphicsView::commandBegun, 
this, [
this]( 
const QString &text ) {
 
  343    beginUndoCommand( text );
 
  345  connect( mView, &QgsModelGraphicsView::commandEnded, 
this, [
this] {
 
  348  connect( mView, &QgsModelGraphicsView::deleteSelectedItems, 
this, [
this] {
 
  352  connect( mActionAddGroupBox, &QAction::triggered, 
this, [
this] {
 
  353    const QPointF viewCenter = mView->mapToScene( mView->viewport()->rect().center() );
 
  354    QgsProcessingModelGroupBox group;
 
  355    group.setPosition( viewCenter );
 
  356    group.setDescription( tr( 
"New Group" ) );
 
  358    beginUndoCommand( tr( 
"Add Group Box" ) );
 
  359    model()->addGroupBox( group );
 
  367  restoreState( settings.
value( QStringLiteral( 
"ModelDesigner/state" ), QByteArray(), 
QgsSettings::App ).toByteArray() );
 
  370QgsModelDesignerDialog::~QgsModelDesignerDialog()
 
  373  if ( !mPanelStatus.isEmpty() )
 
  375    QStringList docksTitle;
 
  376    QStringList docksActive;
 
  378    for ( 
const auto &panel : mPanelStatus.toStdMap() )
 
  380      if ( panel.second.isVisible )
 
  381        docksTitle << panel.first;
 
  382      if ( panel.second.isActive )
 
  383        docksActive << panel.first;
 
  397  mIgnoreUndoStackChanges++;
 
  401void QgsModelDesignerDialog::closeEvent( QCloseEvent *event )
 
  403  if ( checkForUnsavedChanges() )
 
  409void QgsModelDesignerDialog::beginUndoCommand( 
const QString &text, 
int id )
 
  411  if ( mBlockUndoCommands || !mUndoStack )
 
  414  if ( mActiveCommand )
 
  417  mActiveCommand = std::make_unique<QgsModelUndoCommand>( mModel.get(), text, 
id );
 
  420void QgsModelDesignerDialog::endUndoCommand()
 
  422  if ( mBlockUndoCommands || !mActiveCommand || !mUndoStack )
 
  425  mActiveCommand->saveAfterState();
 
  426  mIgnoreUndoStackChanges++;
 
  427  mUndoStack->push( mActiveCommand.release() );
 
  428  mIgnoreUndoStackChanges--;
 
  432QgsProcessingModelAlgorithm *QgsModelDesignerDialog::model()
 
  437void QgsModelDesignerDialog::setModel( QgsProcessingModelAlgorithm *model )
 
  439  mModel.reset( model );
 
  441  mGroupEdit->setText( mModel->group() );
 
  442  mNameEdit->setText( mModel->displayName() );
 
  444  updateVariablesGui();
 
  446  mView->centerOn( 0, 0 );
 
  449  mIgnoreUndoStackChanges++;
 
  451  mIgnoreUndoStackChanges--;
 
  456void QgsModelDesignerDialog::loadModel( 
const QString &path )
 
  458  auto alg = std::make_unique<QgsProcessingModelAlgorithm>();
 
  459  if ( alg->fromFile( path ) )
 
  462    alg->setSourceFilePath( path );
 
  463    setModel( alg.release() );
 
  468    QMessageBox::critical( 
this, tr( 
"Open Model" ), tr( 
"The selected model could not be loaded.\n" 
  469                                                         "See the log for more information." ) );
 
  473void QgsModelDesignerDialog::setModelScene( QgsModelGraphicsScene *scene )
 
  475  QgsModelGraphicsScene *oldScene = mScene;
 
  478  mScene->setParent( 
this );
 
  479  mScene->setLastRunResult( mLastResult );
 
  480  mScene->setModel( mModel.get() );
 
  481  mScene->setMessageBar( mMessageBar );
 
  483  const QPointF center = mView->mapToScene( mView->viewport()->rect().center() );
 
  484  mView->setModelScene( mScene );
 
  486  mSelectTool->resetCache();
 
  487  mSelectTool->setScene( mScene );
 
  489  connect( mScene, &QgsModelGraphicsScene::rebuildRequired, 
this, [
this] {
 
  490    if ( mBlockRepaints )
 
  495  connect( mScene, &QgsModelGraphicsScene::componentAboutToChange, 
this, [
this]( 
const QString &description, 
int id ) { beginUndoCommand( description, 
id ); } );
 
  496  connect( mScene, &QgsModelGraphicsScene::componentChanged, 
this, [
this] { endUndoCommand(); } );
 
  497  connect( mScene, &QgsModelGraphicsScene::runFromChild, 
this, &QgsModelDesignerDialog::runFromChild );
 
  498  connect( mScene, &QgsModelGraphicsScene::runSelected, 
this, &QgsModelDesignerDialog::runSelectedSteps );
 
  499  connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmOutputs, 
this, &QgsModelDesignerDialog::showChildAlgorithmOutputs );
 
  500  connect( mScene, &QgsModelGraphicsScene::showChildAlgorithmLog, 
this, &QgsModelDesignerDialog::showChildAlgorithmLog );
 
  502  mView->centerOn( center );
 
  505    oldScene->deleteLater();
 
  508void QgsModelDesignerDialog::activate()
 
  512  setWindowState( windowState() & ~Qt::WindowMinimized );
 
  516void QgsModelDesignerDialog::updateVariablesGui()
 
  518  mBlockUndoCommands++;
 
  520  auto variablesScope = std::make_unique<QgsExpressionContextScope>( tr( 
"Model Variables" ) );
 
  521  const QVariantMap modelVars = mModel->variables();
 
  522  for ( 
auto it = modelVars.constBegin(); it != modelVars.constEnd(); ++it )
 
  524    variablesScope->setVariable( it.key(), it.value() );
 
  527  variablesContext.
appendScope( variablesScope.release() );
 
  528  mVariablesEditor->setContext( &variablesContext );
 
  529  mVariablesEditor->setEditableScopeIndex( 0 );
 
  531  mBlockUndoCommands--;
 
  534void QgsModelDesignerDialog::setDirty( 
bool dirty )
 
  540bool QgsModelDesignerDialog::validateSave( SaveAction action )
 
  544    case QgsModelDesignerDialog::SaveAction::SaveAsFile:
 
  546    case QgsModelDesignerDialog::SaveAction::SaveInProject:
 
  547      if ( mNameEdit->text().trimmed().isEmpty() )
 
  549        mMessageBar->pushWarning( QString(), tr( 
"Please enter a model name before saving" ) );
 
  558bool QgsModelDesignerDialog::checkForUnsavedChanges()
 
  562    QMessageBox::StandardButton ret = QMessageBox::question( 
this, tr( 
"Save Model?" ), tr( 
"There are unsaved changes in this model. Do you want to keep those?" ), QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard, QMessageBox::Cancel );
 
  565      case QMessageBox::Save:
 
  566        return saveModel( 
false );
 
  568      case QMessageBox::Discard:
 
  583  mLastResult.mergeWith( result );
 
  585    mScene->setLastRunResult( mLastResult );
 
  588void QgsModelDesignerDialog::setModelName( 
const QString &name )
 
  590  mNameEdit->setText( name );
 
  593void QgsModelDesignerDialog::zoomIn()
 
  595  mView->setTransformationAnchor( QGraphicsView::NoAnchor );
 
  596  QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
 
  598  const double factor = settings.
value( QStringLiteral( 
"/qgis/zoom_favor" ), 2.0 ).toDouble();
 
  599  mView->scale( factor, factor );
 
  600  mView->centerOn( point );
 
  603void QgsModelDesignerDialog::zoomOut()
 
  605  mView->setTransformationAnchor( QGraphicsView::NoAnchor );
 
  606  QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
 
  608  const double factor = 1.0 / settings.
value( QStringLiteral( 
"/qgis/zoom_favor" ), 2.0 ).toDouble();
 
  609  mView->scale( factor, factor );
 
  610  mView->centerOn( point );
 
  613void QgsModelDesignerDialog::zoomActual()
 
  615  QPointF point = mView->mapToScene( QPoint( mView->viewport()->width() / 2.0, mView->viewport()->height() / 2 ) );
 
  616  mView->resetTransform();
 
  617  mView->scale( mScreenHelper->screenDpi() / 96, mScreenHelper->screenDpi() / 96 );
 
  618  mView->centerOn( point );
 
  621void QgsModelDesignerDialog::zoomFull()
 
  623  QRectF totalRect = mView->scene()->itemsBoundingRect();
 
  624  totalRect.adjust( -10, -10, 10, 10 );
 
  625  mView->fitInView( totalRect, Qt::KeepAspectRatio );
 
  628void QgsModelDesignerDialog::newModel()
 
  630  if ( !checkForUnsavedChanges() )
 
  633  auto alg = std::make_unique<QgsProcessingModelAlgorithm>();
 
  635  setModel( alg.release() );
 
  638void QgsModelDesignerDialog::exportToImage()
 
  641  QString lastExportDir = settings.
value( QStringLiteral( 
"lastModelDesignerExportDir" ), QDir::homePath(), 
QgsSettings::App ).toString();
 
  643  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save Model as Image" ), lastExportDir, tr( 
"PNG files (*.png *.PNG)" ) );
 
  647  if ( filename.isEmpty() )
 
  652  const QFileInfo saveFileInfo( filename );
 
  655  repaintModel( 
false );
 
  657  QRectF totalRect = mView->scene()->itemsBoundingRect();
 
  658  totalRect.adjust( -10, -10, 10, 10 );
 
  659  const QRectF imageRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
 
  661  QImage img( totalRect.width(), totalRect.height(), QImage::Format_ARGB32_Premultiplied );
 
  662  img.fill( Qt::white );
 
  664  painter.setRenderHint( QPainter::Antialiasing );
 
  665  painter.begin( &img );
 
  666  mView->scene()->render( &painter, imageRect, totalRect );
 
  669  img.save( filename );
 
  671  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 );
 
  672  repaintModel( 
true );
 
  675void QgsModelDesignerDialog::exportToPdf()
 
  678  QString lastExportDir = settings.
value( QStringLiteral( 
"lastModelDesignerExportDir" ), QDir::homePath(), 
QgsSettings::App ).toString();
 
  680  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save Model as PDF" ), lastExportDir, tr( 
"PDF files (*.pdf *.PDF)" ) );
 
  684  if ( filename.isEmpty() )
 
  689  const QFileInfo saveFileInfo( filename );
 
  692  repaintModel( 
false );
 
  694  QRectF totalRect = mView->scene()->itemsBoundingRect();
 
  695  totalRect.adjust( -10, -10, 10, 10 );
 
  696  const QRectF printerRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
 
  698  QPdfWriter pdfWriter( filename );
 
  700  const double scaleFactor = 96 / 25.4; 
 
  702  QPageLayout pageLayout( QPageSize( totalRect.size() / scaleFactor, QPageSize::Millimeter ), QPageLayout::Portrait, QMarginsF( 0, 0, 0, 0 ) );
 
  703  pageLayout.setMode( QPageLayout::FullPageMode );
 
  704  pdfWriter.setPageLayout( pageLayout );
 
  706  QPainter painter( &pdfWriter );
 
  707  mView->scene()->render( &painter, printerRect, totalRect );
 
  710  mMessageBar->pushMessage( QString(), tr( 
"Successfully exported model as PDF to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( filename ).toString(), QDir::toNativeSeparators( filename ) ), 
Qgis::MessageLevel::Success, 0 );
 
  711  repaintModel( 
true );
 
  714void QgsModelDesignerDialog::exportToSvg()
 
  717  QString lastExportDir = settings.
value( QStringLiteral( 
"lastModelDesignerExportDir" ), QDir::homePath(), 
QgsSettings::App ).toString();
 
  719  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save Model as SVG" ), lastExportDir, tr( 
"SVG files (*.svg *.SVG)" ) );
 
  723  if ( filename.isEmpty() )
 
  728  const QFileInfo saveFileInfo( filename );
 
  731  repaintModel( 
false );
 
  733  QRectF totalRect = mView->scene()->itemsBoundingRect();
 
  734  totalRect.adjust( -10, -10, 10, 10 );
 
  735  const QRectF svgRect = QRectF( 0, 0, totalRect.width(), totalRect.height() );
 
  738  svg.setFileName( filename );
 
  739  svg.setSize( QSize( totalRect.width(), totalRect.height() ) );
 
  740  svg.setViewBox( svgRect );
 
  741  svg.setTitle( mModel->displayName() );
 
  743  QPainter painter( &svg );
 
  744  mView->scene()->render( &painter, svgRect, totalRect );
 
  747  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 );
 
  748  repaintModel( 
true );
 
  751void QgsModelDesignerDialog::exportAsPython()
 
  754  QString lastExportDir = settings.
value( QStringLiteral( 
"lastModelDesignerExportDir" ), QDir::homePath(), 
QgsSettings::App ).toString();
 
  756  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save Model as Python Script" ), lastExportDir, tr( 
"Processing scripts (*.py *.PY)" ) );
 
  760  if ( filename.isEmpty() )
 
  765  const QFileInfo saveFileInfo( filename );
 
  770  QFile outFile( filename );
 
  771  if ( !outFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
 
  775  QTextStream fout( &outFile );
 
  779  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 );
 
  782void QgsModelDesignerDialog::toggleComments( 
bool show )
 
  786  repaintModel( 
true );
 
  789void QgsModelDesignerDialog::updateWindowTitle()
 
  791  QString title = tr( 
"Model Designer" );
 
  792  if ( !mModel->name().isEmpty() )
 
  793    title = mModel->group().isEmpty()
 
  794              ? QStringLiteral( 
"%1: %2" ).arg( title, mModel->name() )
 
  795              : QStringLiteral( 
"%1: %2 - %3" ).arg( title, mModel->group(), mModel->name() );
 
  798    title.prepend( 
'*' );
 
  800  setWindowTitle( title );
 
  803void QgsModelDesignerDialog::deleteSelected()
 
  805  QList<QgsModelComponentGraphicItem *> items = mScene->selectedComponentItems();
 
  809  if ( items.size() == 1 )
 
  811    items.at( 0 )->deleteComponent();
 
  815  std::sort( items.begin(), items.end(), []( QgsModelComponentGraphicItem *p1, QgsModelComponentGraphicItem *p2 ) {
 
  820    if ( dynamic_cast<QgsModelCommentGraphicItem *>( p1 ) && dynamic_cast<QgsModelCommentGraphicItem *>( p2 ) )
 
  822    else if ( dynamic_cast<QgsModelCommentGraphicItem *>( p1 ) )
 
  824    else if ( dynamic_cast<QgsModelCommentGraphicItem *>( p2 ) )
 
  827    else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p1 ) && dynamic_cast<QgsModelGroupBoxGraphicItem *>( p2 ) )
 
  829    else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p1 ) )
 
  831    else if ( dynamic_cast<QgsModelGroupBoxGraphicItem *>( p2 ) )
 
  834    else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p1 ) && dynamic_cast<QgsModelOutputGraphicItem *>( p2 ) )
 
  836    else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p1 ) )
 
  838    else if ( dynamic_cast<QgsModelOutputGraphicItem *>( p2 ) )
 
  841    else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p1 ) && dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p2 ) )
 
  843    else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p1 ) )
 
  845    else if ( dynamic_cast<QgsModelChildAlgorithmGraphicItem *>( p2 ) )
 
  852  beginUndoCommand( tr( 
"Delete Components" ) );
 
  854  QVariant prevState = mModel->toVariant();
 
  855  mBlockUndoCommands++;
 
  856  mBlockRepaints = 
true;
 
  858  while ( !items.empty() )
 
  860    QgsModelComponentGraphicItem *toDelete = 
nullptr;
 
  861    for ( QgsModelComponentGraphicItem *item : items )
 
  863      if ( item->canDeleteComponent() )
 
  876    toDelete->deleteComponent();
 
  877    items.removeAll( toDelete );
 
  882    mModel->loadVariant( prevState );
 
  883    QMessageBox::warning( 
nullptr, QObject::tr( 
"Could not remove components" ), QObject::tr( 
"Components depend on the selected items.\n" 
  884                                                                                              "Try to remove them before trying deleting these components." ) );
 
  885    mBlockUndoCommands--;
 
  886    mActiveCommand.reset();
 
  890    mBlockUndoCommands--;
 
  894  mBlockRepaints = 
false;
 
  898void QgsModelDesignerDialog::populateZoomToMenu()
 
  901  for ( 
const QgsProcessingModelGroupBox &box : model()->groupBoxes() )
 
  903    if ( QgsModelComponentGraphicItem *item = mScene->groupBoxItem( box.uuid() ) )
 
  905      QAction *zoomAction = 
new QAction( box.description(), mGroupMenu );
 
  906      connect( zoomAction, &QAction::triggered, 
this, [
this, item] {
 
  907        QRectF groupRect = item->mapToScene( item->boundingRect() ).boundingRect();
 
  908        groupRect.adjust( -10, -10, 10, 10 );
 
  909        mView->fitInView( groupRect, Qt::KeepAspectRatio );
 
  910        mView->centerOn( item );
 
  912      mGroupMenu->addAction( zoomAction );
 
  917void QgsModelDesignerDialog::setPanelVisibility( 
bool hidden )
 
  919  const QList<QDockWidget *> docks = findChildren<QDockWidget *>();
 
  920  const QList<QTabBar *> tabBars = findChildren<QTabBar *>();
 
  924    mPanelStatus.clear();
 
  926    for ( QDockWidget *dock : docks )
 
  928      mPanelStatus.insert( dock->windowTitle(), PanelStatus( dock->isVisible(), 
false ) );
 
  929      dock->setVisible( 
false );
 
  933    for ( QTabBar *tabBar : tabBars )
 
  935      QString currentTabTitle = tabBar->tabText( tabBar->currentIndex() );
 
  936      mPanelStatus[currentTabTitle].isActive = 
true;
 
  942    for ( QDockWidget *dock : docks )
 
  944      if ( mPanelStatus.contains( dock->windowTitle() ) )
 
  946        dock->setVisible( mPanelStatus.value( dock->windowTitle() ).isVisible );
 
  951    for ( QTabBar *tabBar : tabBars )
 
  954      for ( 
int i = 0; i < tabBar->count(); ++i )
 
  956        QString tabTitle = tabBar->tabText( i );
 
  957        if ( mPanelStatus.contains( tabTitle ) && mPanelStatus.value( tabTitle ).isActive )
 
  959          tabBar->setCurrentIndex( i );
 
  963    mPanelStatus.clear();
 
  967void QgsModelDesignerDialog::editHelp()
 
  969  QgsProcessingHelpEditorDialog dialog( 
this );
 
  970  dialog.setWindowTitle( tr( 
"Edit Model Help" ) );
 
  971  dialog.setAlgorithm( mModel.get() );
 
  974    beginUndoCommand( tr( 
"Edit Model Help" ) );
 
  975    mModel->setHelpContent( dialog.helpContent() );
 
  980void QgsModelDesignerDialog::runSelectedSteps()
 
  982  QSet<QString> children;
 
  983  const QList<QgsModelComponentGraphicItem *> items = mScene->selectedComponentItems();
 
  984  for ( QgsModelComponentGraphicItem *item : items )
 
  986    if ( QgsProcessingModelChildAlgorithm *childAlgorithm = 
dynamic_cast<QgsProcessingModelChildAlgorithm *
>( item->component() ) )
 
  988      children.insert( childAlgorithm->childId() );
 
  992  if ( children.isEmpty() )
 
  994    mMessageBar->pushWarning( QString(), tr( 
"No steps are selected" ) );
 
 1001void QgsModelDesignerDialog::runFromChild( 
const QString &
id )
 
 1003  QSet<QString> children = mModel->dependentChildAlgorithms( 
id );
 
 1004  children.insert( 
id );
 
 1008void QgsModelDesignerDialog::run( 
const QSet<QString> &childAlgorithmSubset )
 
 1011  const bool isValid = model()->validate( errors );
 
 1014    QMessageBox messageBox;
 
 1015    messageBox.setWindowTitle( tr( 
"Model is Invalid" ) );
 
 1016    messageBox.setIcon( QMessageBox::Icon::Warning );
 
 1017    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?" ) );
 
 1018    messageBox.setStandardButtons( QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::Cancel );
 
 1019    messageBox.setDefaultButton( QMessageBox::StandardButton::Cancel );
 
 1021    QString errorString;
 
 1022    for ( 
const QString &error : std::as_const( errors ) )
 
 1024      QString cleanedError = error;
 
 1025      const thread_local QRegularExpression re( QStringLiteral( 
"<[^>]*>" ) );
 
 1026      cleanedError.replace( re, QString() );
 
 1027      errorString += QStringLiteral( 
"• %1\n" ).arg( cleanedError );
 
 1030    messageBox.setDetailedText( errorString );
 
 1031    if ( messageBox.exec() == QMessageBox::StandardButton::Cancel )
 
 1035  if ( !childAlgorithmSubset.isEmpty() )
 
 1037    for ( 
const QString &child : childAlgorithmSubset )
 
 1040      const QSet<QString> requirements = mModel->dependsOnChildAlgorithms( child );
 
 1041      for ( 
const QString &requirement : requirements )
 
 1043        if ( !mLastResult.executedChildIds().contains( requirement ) )
 
 1045          QMessageBox messageBox;
 
 1046          messageBox.setWindowTitle( tr( 
"Run Model" ) );
 
 1047          messageBox.setIcon( QMessageBox::Icon::Warning );
 
 1048          messageBox.setText( tr( 
"Prerequisite parts of this model have not yet been run (try running the full model first)." ) );
 
 1049          messageBox.setStandardButtons( QMessageBox::StandardButton::Ok );
 
 1057  std::unique_ptr<QgsProcessingAlgorithmDialogBase> dialog( createExecutionDialog() );
 
 1062  dialog->setParameters( mModel->designerParameterValues() );
 
 1064  connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmAboutToRun, 
this, [
this, &childAlgorithmSubset]( 
QgsProcessingContext *context ) {
 
 1065    if ( !childAlgorithmSubset.empty() )
 
 1068      auto modelConfig = std::make_unique<QgsProcessingModelInitialRunConfig>();
 
 1069      modelConfig->setChildAlgorithmSubset( childAlgorithmSubset );
 
 1070      modelConfig->setPreviouslyExecutedChildAlgorithms( mLastResult.executedChildIds() );
 
 1071      modelConfig->setInitialChildInputs( mLastResult.rawChildInputs() );
 
 1072      modelConfig->setInitialChildOutputs( mLastResult.rawChildOutputs() );
 
 1076      const QMap<QString, QgsMapLayer *> previousOutputLayers = mLayerStore.temporaryLayerStore()->mapLayers();
 
 1077      auto previousResultStore = std::make_unique<QgsMapLayerStore>();
 
 1078      for ( auto it = previousOutputLayers.constBegin(); it != previousOutputLayers.constEnd(); ++it )
 
 1080        std::unique_ptr<QgsMapLayer> clone( it.value()->clone() );
 
 1081        clone->setId( it.value()->id() );
 
 1082        previousResultStore->addMapLayer( clone.release() );
 
 1084      previousResultStore->moveToThread( nullptr );
 
 1085      modelConfig->setPreviousLayerStore( std::move( previousResultStore ) );
 
 1086      context->setModelInitialRunConfig( std::move( modelConfig ) );
 
 1090  connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmFinished, 
this, [
this, &dialog]( 
bool, 
const QVariantMap & ) {
 
 1091    QgsProcessingContext *context = dialog->processingContext();
 
 1093    setLastRunResult( context->modelResult() );
 
 1095    mModel->setDesignerParameterValues( dialog->createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipDefaultValueParameters ) );
 
 1098    mLayerStore.temporaryLayerStore()->removeAllMapLayers();
 
 1099    mLayerStore.takeResultsFrom( *context );
 
 1105void QgsModelDesignerDialog::showChildAlgorithmOutputs( 
const QString &childId )
 
 1107  const QString childDescription = mModel->childAlgorithm( childId ).description();
 
 1110  const QVariantMap childAlgorithmOutputs = result.
outputs();
 
 1111  if ( childAlgorithmOutputs.isEmpty() )
 
 1113    mMessageBar->pushWarning( QString(), tr( 
"No results are available for %1" ).arg( childDescription ) );
 
 1120    mMessageBar->pushCritical( QString(), tr( 
"Results cannot be shown for an invalid model component" ) );
 
 1125  if ( outputParams.isEmpty() )
 
 1128    QgsDebugError( 
"Cannot show results for algorithms with no outputs" );
 
 1132  bool foundResults = 
false;
 
 1135    const QVariant output = childAlgorithmOutputs.value( outputParam->name() );
 
 1136    if ( !output.isValid() )
 
 1139    if ( output.type() == QVariant::String )
 
 1143        QgsDebugMsgLevel( QStringLiteral( 
"Loading previous result for %1: %2" ).arg( outputParam->name(), output.toString() ), 2 );
 
 1145        std::unique_ptr<QgsMapLayer> layer( resultLayer->clone() );
 
 1148        if ( outputParams.size() > 1 )
 
 1149          baseName = tr( 
"%1 — %2" ).arg( childDescription, outputParam->name() );
 
 1151          baseName = childDescription;
 
 1155        QString name = baseName;
 
 1160          name = tr( 
"%1 (%2)" ).arg( baseName ).arg( counter );
 
 1163        layer->setName( name );
 
 1166        foundResults = 
true;
 
 1171        QgsDebugError( QStringLiteral( 
"Could not load previous result for %1: %2" ).arg( outputParam->name(), output.toString() ) );
 
 1176  if ( !foundResults )
 
 1178    mMessageBar->pushWarning( QString(), tr( 
"No results are available for %1" ).arg( childDescription ) );
 
 1183void QgsModelDesignerDialog::showChildAlgorithmLog( 
const QString &childId )
 
 1185  const QString childDescription = mModel->childAlgorithm( childId ).description();
 
 1188  if ( result.
htmlLog().isEmpty() )
 
 1190    mMessageBar->pushWarning( QString(), tr( 
"No log is available for %1" ).arg( childDescription ) );
 
 1195  m.setWindowTitle( childDescription );
 
 1196  m.setCheckBoxVisible( 
false );
 
 1197  m.setMessageAsHtml( result.
htmlLog() );
 
 1201void QgsModelDesignerDialog::validate()
 
 1204  if ( model()->validate( issues ) )
 
 1206    mMessageBar->pushSuccess( QString(), tr( 
"Model is valid!" ) );
 
 1211    QPushButton *detailsButton = 
new QPushButton( tr( 
"Details" ) );
 
 1212    connect( detailsButton, &QPushButton::clicked, detailsButton, [detailsButton, issues] {
 
 1214      dialog->
setTitle( tr( 
"Model is Invalid" ) );
 
 1216      QString longMessage = tr( 
"<p>This model is not valid:</p>" ) + QStringLiteral( 
"<ul>" );
 
 1217      for ( 
const QString &issue : issues )
 
 1219        longMessage += QStringLiteral( 
"<li>%1</li>" ).arg( issue );
 
 1221      longMessage += QLatin1String( 
"</ul>" );
 
 1226    messageWidget->layout()->addWidget( detailsButton );
 
 1227    mMessageBar->clearWidgets();
 
 1232void QgsModelDesignerDialog::reorderInputs()
 
 1234  QgsModelInputReorderDialog dlg( 
this );
 
 1235  dlg.setModel( mModel.get() );
 
 1238    const QStringList inputOrder = dlg.inputOrder();
 
 1239    beginUndoCommand( tr( 
"Reorder Inputs" ) );
 
 1240    mModel->setParameterOrder( inputOrder );
 
 1245void QgsModelDesignerDialog::reorderOutputs()
 
 1247  QgsModelOutputReorderDialog dlg( 
this );
 
 1248  dlg.setModel( mModel.get() );
 
 1251    const QStringList outputOrder = dlg.outputOrder();
 
 1252    beginUndoCommand( tr( 
"Reorder Outputs" ) );
 
 1253    mModel->setOutputOrder( outputOrder );
 
 1254    mModel->setOutputGroup( dlg.outputGroup() );
 
 1259bool QgsModelDesignerDialog::isDirty()
 const 
 1261  return mHasChanged && mUndoStack->index() != -1;
 
 1264void QgsModelDesignerDialog::fillInputsTree()
 
 1267  auto parametersItem = std::make_unique<QTreeWidgetItem>();
 
 1268  parametersItem->setText( 0, tr( 
"Parameters" ) );
 
 1271    return QString::localeAwareCompare( a->name(), b->name() ) < 0;
 
 1278      auto paramItem = std::make_unique<QTreeWidgetItem>();
 
 1279      paramItem->setText( 0, param->name() );
 
 1280      paramItem->setData( 0, Qt::UserRole, param->id() );
 
 1281      paramItem->setIcon( 0, icon );
 
 1282      paramItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
 
 1283      paramItem->setToolTip( 0, param->description() );
 
 1284      parametersItem->addChild( paramItem.release() );
 
 1287  mInputsTreeWidget->addTopLevelItem( parametersItem.release() );
 
 1288  mInputsTreeWidget->topLevelItem( 0 )->setExpanded( 
true );
 
 1296QgsModelChildDependenciesWidget::QgsModelChildDependenciesWidget( QWidget *parent, QgsProcessingModelAlgorithm *model, 
const QString &childId )
 
 1299  , mChildId( childId )
 
 1301  QHBoxLayout *hl = 
new QHBoxLayout();
 
 1302  hl->setContentsMargins( 0, 0, 0, 0 );
 
 1304  mLineEdit = 
new QLineEdit();
 
 1305  mLineEdit->setEnabled( 
false );
 
 1306  hl->addWidget( mLineEdit, 1 );
 
 1308  mToolButton = 
new QToolButton();
 
 1309  mToolButton->setText( QString( QChar( 0x2026 ) ) );
 
 1310  hl->addWidget( mToolButton );
 
 1314  mLineEdit->setText( tr( 
"%1 dependencies selected" ).arg( 0 ) );
 
 1316  connect( mToolButton, &QToolButton::clicked, 
this, &QgsModelChildDependenciesWidget::showDialog );
 
 1319void QgsModelChildDependenciesWidget::setValue( 
const QList<QgsProcessingModelChildDependency> &value )
 
 1323  updateSummaryText();
 
 1326void QgsModelChildDependenciesWidget::showDialog()
 
 1328  const QList<QgsProcessingModelChildDependency> available = mModel->availableDependenciesForChildAlgorithm( mChildId );
 
 1330  QVariantList availableOptions;
 
 1331  for ( 
const QgsProcessingModelChildDependency &dep : available )
 
 1332    availableOptions << QVariant::fromValue( dep );
 
 1333  QVariantList selectedOptions;
 
 1334  for ( 
const QgsProcessingModelChildDependency &dep : mValue )
 
 1335    selectedOptions << QVariant::fromValue( dep );
 
 1340    QgsProcessingMultipleSelectionPanelWidget *widget = 
new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
 
 1341    widget->setPanelTitle( tr( 
"Algorithm Dependencies" ) );
 
 1343    widget->setValueFormatter( [
this]( 
const QVariant &v ) -> QString {
 
 1344      const QgsProcessingModelChildDependency dep = v.value<QgsProcessingModelChildDependency>();
 
 1346      const QString description = mModel->childAlgorithm( dep.childId ).description();
 
 1347      if ( dep.conditionalBranch.isEmpty() )
 
 1350        return tr( 
"Condition “%1” from algorithm “%2”" ).arg( dep.conditionalBranch, description );
 
 1353    connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, 
this, [
this, widget]() {
 
 1354      QList<QgsProcessingModelChildDependency> res;
 
 1355      for ( 
const QVariant &v : widget->selectedOptions() )
 
 1357        res << v.value<QgsProcessingModelChildDependency>();
 
 1366void QgsModelChildDependenciesWidget::updateSummaryText()
 
 1368  mLineEdit->setText( tr( 
"%n dependencies selected", 
nullptr, mValue.count() ) );
 
@ ExposeToModeler
Is this parameter available in the modeler. Is set to on by default.
 
@ Warning
Warning message.
 
@ Critical
Critical/error message.
 
@ Success
Used for reporting a successful operation.
 
@ ModelDebug
Model debug level logging. Includes verbose logging and other outputs useful for debugging models.
 
static QgsProcessingRegistry * processingRegistry()
Returns the application's processing registry, used for managing processing providers,...
 
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
 
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
 
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
 
Base class for all map layer types.
 
Represents an item shown within a QgsMessageBar widget.
 
A bar for displaying non-blocking messages to the user.
 
static QgsMessageBarItem * createMessage(const QString &text, QWidget *parent=nullptr)
Creates message bar item widget containing a message text to be displayed on the bar.
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
 
A generic message view for displaying QGIS messages.
 
void setTitle(const QString &title) override
Sets title for the messages.
 
void setMessage(const QString &message, MessageType msgType) override
Sets message, it won't be displayed until.
 
void showMessage(bool blocking=true) override
display the message to the user and deletes itself
 
Abstract base class for processing algorithms.
 
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.
 
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)