Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
try:
QgsProcessingAlgorithmDialogBase.__attribute_docs__ = {'algorithmAboutToRun': 'Emitted when the algorithm is about to run in the specified ``context``.\n\nThis signal can be used to tweak the ``context`` prior to the algorithm\nexecution.\n\n.. versionadded:: 3.38\n', 'algorithmFinished': 'Emitted whenever an algorithm has finished executing in the dialog.\n\n.. versionadded:: 3.14\n'}
QgsProcessingAlgorithmDialogBase.formatStringForLog = staticmethod(QgsProcessingAlgorithmDialogBase.formatStringForLog)
QgsProcessingAlgorithmDialogBase.__virtual_methods__ = ['setParameters', 'resetAdditionalGui', 'blockAdditionalControlsWhileRunning', 'isFinalized', 'finished', 'runAlgorithm', 'algExecuted']
QgsProcessingAlgorithmDialogBase.__virtual_methods__ = ['setParameters', 'isRunning', 'resetAdditionalGui', 'blockAdditionalControlsWhileRunning', 'isFinalized', 'finished', 'runAlgorithm', 'algExecuted']
QgsProcessingAlgorithmDialogBase.__overridden_methods__ = ['reject', 'closeEvent']
QgsProcessingAlgorithmDialogBase.__signal_arguments__ = {'algorithmAboutToRun': ['context: QgsProcessingContext'], 'algorithmFinished': ['successful: bool', 'result: Dict[str, object]']}
QgsProcessingAlgorithmDialogBase.__group__ = ['processing']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ Returns the main widget for the dialog, usually a panel for configuring
algorithm parameters.

.. seealso:: :py:func:`setMainWidget`
%End

void showDialog();
%Docstring
Shows and raises the dialog

.. versionadded:: 4.0
%End

void showLog();
Expand Down Expand Up @@ -143,6 +150,12 @@ Sets the parameter ``values`` to show in the dialog.
.. versionadded:: 3.24
%End


QPushButton *cancelButton();
%Docstring
Returns the dialog's cancel button.
%End

public slots:

void reportError( const QString &error, bool fatalError );
Expand Down Expand Up @@ -229,6 +242,26 @@ Copies the current log contents to the clipboard.
void showParameters();
%Docstring
Switches the dialog to the parameters page.
%End

void resetGui();
%Docstring
Resets the dialog's gui, ready for another algorithm execution.
%End

virtual bool isRunning();
%Docstring
Returns if the dialog is considered running an algorithm.

.. versionadded:: 4.0
%End

void forceClose();
%Docstring
Forces the dialog to close by detaching any running task of the dialog
THEN closing the dialog.

.. versionadded:: 4.0
%End

virtual void reject();
Expand All @@ -243,10 +276,6 @@ Switches the dialog to the parameters page.
Returns the dialog's run button.
%End

QPushButton *cancelButton();
%Docstring
Returns the dialog's cancel button.
%End

QPushButton *changeParametersButton();
%Docstring
Expand Down Expand Up @@ -295,11 +324,6 @@ Sets the algorithm results.
void setInfo( const QString &message, bool isError = false, bool escapeHtml = true, bool isWarning = false );
%Docstring
Displays an info ``message`` in the dialog's log.
%End

void resetGui();
%Docstring
Resets the dialog's gui, ready for another algorithm execution.
%End

virtual void resetAdditionalGui();
Expand Down
7 changes: 7 additions & 0 deletions python/plugins/processing/gui/AlgorithmDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ def __init__(self, alg, in_place=False, parent=None):
self.history_log_id = None
self.history_details = {}

self._is_running = False

self.setAlgorithm(alg)
self.setMainWidget(self.getParametersPanel(alg, self))

Expand Down Expand Up @@ -223,6 +225,7 @@ def runAlgorithm(self):
self.cancelButton().setEnabled(False)

self.iterateParam = None
self._is_running = True

for param in self.algorithm().parameterDefinitions():
if (
Expand Down Expand Up @@ -455,6 +458,7 @@ def finish(self, successful, result, context, feedback, in_place=False):
self.resetGui()
return

self._is_running = False
self.setExecuted(True)
self.setResults(result)
self.setInfo(
Expand All @@ -475,3 +479,6 @@ def finish(self, successful, result, context, feedback, in_place=False):
),
escapeHtml=False,
)

def isRunning(self):
return self._is_running
1 change: 1 addition & 0 deletions python/plugins/processing/modeler/ModelerDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def processingContext(self):

def createExecutionDialog(self):
dlg = AlgorithmDialog(self.model().create(), parent=self)

return dlg

def saveInProject(self):
Expand Down
125 changes: 89 additions & 36 deletions src/gui/processing/models/qgsmodeldesignerdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1112,50 +1112,103 @@ void QgsModelDesignerDialog::run( const QSet<QString> &childAlgorithmSubset )
}
}

std::unique_ptr<QgsProcessingAlgorithmDialogBase> dialog( createExecutionDialog() );
if ( !dialog )
return;

dialog->setLogLevel( Qgis::ProcessingLogLevel::ModelDebug );
dialog->setParameters( mModel->designerParameterValues() );
if ( mAlgorithmDialog && mAlgorithmDialog->isRunning() ) // Switch to is running
{
QMessageBox messageBox;
messageBox.setWindowTitle( tr( "The model is already running" ) );
messageBox.setText( tr( "The model is already running" ) );
messageBox.setStandardButtons( QMessageBox::StandardButton::Cancel | QMessageBox::StandardButton::RestoreDefaults | QMessageBox::StandardButton::Ok );

QAbstractButton *buttonShowRunningAlg = messageBox.button( QMessageBox::StandardButton::Ok );
buttonShowRunningAlg->setText( tr( "Show algorithm" ) );

connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmAboutToRun, this, [this, &childAlgorithmSubset]( QgsProcessingContext *context ) {
if ( !childAlgorithmSubset.empty() )
QAbstractButton *buttonReRun = messageBox.button( QMessageBox::StandardButton::RestoreDefaults );
buttonReRun->setText( tr( "Re-run algorithm" ) );

int r = messageBox.exec();

switch ( r )
{
// start from previous state
auto modelConfig = std::make_unique<QgsProcessingModelInitialRunConfig>();
modelConfig->setChildAlgorithmSubset( childAlgorithmSubset );
modelConfig->setPreviouslyExecutedChildAlgorithms( mLastResult.executedChildIds() );
modelConfig->setInitialChildInputs( mLastResult.rawChildInputs() );
modelConfig->setInitialChildOutputs( mLastResult.rawChildOutputs() );

// add copies of layers from previous runs to context's layer store, so that they can be used
// when running the subset
const QMap<QString, QgsMapLayer *> previousOutputLayers = mLayerStore.temporaryLayerStore()->mapLayers();
auto previousResultStore = std::make_unique<QgsMapLayerStore>();
for ( auto it = previousOutputLayers.constBegin(); it != previousOutputLayers.constEnd(); ++it )
case QMessageBox::StandardButton::Cancel:
return;
case QMessageBox::StandardButton::RestoreDefaults:
// Simulate a cancel and close
mAlgorithmDialog->show();
mAlgorithmDialog->cancelButton()->click();

mAlgorithmDialog->forceClose();

//Stop tracking change to the previous dialog in the QPointer
mAlgorithmDialog.clear();
break;
case QMessageBox::StandardButton::Ok:
mAlgorithmDialog->showDialog();
return;
break;
default:
break;
}
}
else if ( mAlgorithmDialog )
{
// Close and create a new one
mAlgorithmDialog->close();
//Stop tracking change to the previous dialog in the QPointer
mAlgorithmDialog.clear();
}


if ( !mAlgorithmDialog )
{
mAlgorithmDialog = createExecutionDialog();

mAlgorithmDialog->setLogLevel( Qgis::ProcessingLogLevel::ModelDebug );
mAlgorithmDialog->setParameters( mModel->designerParameterValues() );

Qt::WindowFlags flags = Qt::Window | Qt::WindowSystemMenuHint
| Qt::WindowMinimizeButtonHint
| Qt::WindowCloseButtonHint;
mAlgorithmDialog->setWindowFlags( flags );

connect( mAlgorithmDialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmAboutToRun, this, [this, childAlgorithmSubset]( QgsProcessingContext *context ) {
if ( !childAlgorithmSubset.empty() )
{
std::unique_ptr<QgsMapLayer> clone( it.value()->clone() );
clone->setId( it.value()->id() );
previousResultStore->addMapLayer( clone.release() );
// start from previous state
auto modelConfig = std::make_unique<QgsProcessingModelInitialRunConfig>();
modelConfig->setChildAlgorithmSubset( childAlgorithmSubset );
modelConfig->setPreviouslyExecutedChildAlgorithms( mLastResult.executedChildIds() );
modelConfig->setInitialChildInputs( mLastResult.rawChildInputs() );
modelConfig->setInitialChildOutputs( mLastResult.rawChildOutputs() );

// add copies of layers from previous runs to context's layer store, so that they can be used
// when running the subset
const QMap<QString, QgsMapLayer *> previousOutputLayers = mLayerStore.temporaryLayerStore()->mapLayers();
auto previousResultStore = std::make_unique<QgsMapLayerStore>();
for ( auto it = previousOutputLayers.constBegin(); it != previousOutputLayers.constEnd(); ++it )
{
std::unique_ptr<QgsMapLayer> clone( it.value()->clone() );
clone->setId( it.value()->id() );
previousResultStore->addMapLayer( clone.release() );
}
previousResultStore->moveToThread( nullptr );
modelConfig->setPreviousLayerStore( std::move( previousResultStore ) );
context->setModelInitialRunConfig( std::move( modelConfig ) );
}
previousResultStore->moveToThread( nullptr );
modelConfig->setPreviousLayerStore( std::move( previousResultStore ) );
context->setModelInitialRunConfig( std::move( modelConfig ) );
}
} );
} );

connect( dialog.get(), &QgsProcessingAlgorithmDialogBase::algorithmFinished, this, [this, &dialog]( bool, const QVariantMap & ) {
QgsProcessingContext *context = dialog->processingContext();
// take child output layers
mLayerStore.temporaryLayerStore()->removeAllMapLayers();
mLayerStore.takeResultsFrom( *context );
connect( mAlgorithmDialog, &QgsProcessingAlgorithmDialogBase::algorithmFinished, this, [this]( bool, const QVariantMap & ) {
QgsProcessingContext *context = mAlgorithmDialog->processingContext();

mModel->setDesignerParameterValues( dialog->createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipDefaultValueParameters ) );
setLastRunResult( context->modelResult() );
} );
// take child output layers
mLayerStore.temporaryLayerStore()->removeAllMapLayers();
mLayerStore.takeResultsFrom( *context );

dialog->exec();
mModel->setDesignerParameterValues( mAlgorithmDialog->createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipDefaultValueParameters ) );
setLastRunResult( context->modelResult() );
} );
}
mAlgorithmDialog->showDialog();
}

void QgsModelDesignerDialog::showChildAlgorithmOutputs( const QString &childId )
Expand Down
2 changes: 2 additions & 0 deletions src/gui/processing/models/qgsmodeldesignerdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ class GUI_EXPORT QgsModelDesignerDialog : public QMainWindow, public Ui::QgsMode
QgsMessageBar *mMessageBar = nullptr;
QgsModelerToolboxModel *mAlgorithmsModel = nullptr;

QPointer<QgsProcessingAlgorithmDialogBase> mAlgorithmDialog;

QActionGroup *mToolsActionGroup = nullptr;

QgsModelViewToolPan *mPanTool = nullptr;
Expand Down
36 changes: 28 additions & 8 deletions src/gui/processing/qgsprocessingalgorithmdialogbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ QgsProcessingAlgorithmDialogBase::QgsProcessingAlgorithmDialogBase( QWidget *par

QgsGui::enableAutoGeometryRestore( this );

setWindowModality( Qt::WindowModality::NonModal );
setWindowFlags( windowFlags() | Qt::WindowMinimizeButtonHint | Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint );

txtLog->setOpenLinks( false );
connect( txtLog, &QTextBrowser::anchorClicked, this, &QgsProcessingAlgorithmDialogBase::urlClicked );

Expand Down Expand Up @@ -552,10 +555,7 @@ void QgsProcessingAlgorithmDialogBase::algExecuted( bool successful, const QVari
if ( !successful )
{
// show dialog to display errors
show();
raise();
setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
activateWindow();
showDialog();
showLog();
}
else
Expand All @@ -577,14 +577,19 @@ void QgsProcessingAlgorithmDialogBase::taskTriggered( QgsTask *task )
{
if ( task == mAlgorithmTask )
{
show();
raise();
setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
activateWindow();
showDialog();
showLog();
}
}

void QgsProcessingAlgorithmDialogBase::showDialog()
{
show();
raise();
setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
activateWindow();
}

void QgsProcessingAlgorithmDialogBase::closeClicked()
{
reject();
Expand Down Expand Up @@ -744,6 +749,7 @@ void QgsProcessingAlgorithmDialogBase::runAlgorithm()
{
}


void QgsProcessingAlgorithmDialogBase::setPercentage( double percent )
{
// delay setting maximum progress value until we know algorithm reports progress
Expand Down Expand Up @@ -909,6 +915,12 @@ bool QgsProcessingAlgorithmDialogBase::isFinalized()
return true;
}

bool QgsProcessingAlgorithmDialogBase::isRunning()
{
return true;
}


void QgsProcessingAlgorithmDialogBase::applyContextOverrides( QgsProcessingContext *context )
{
if ( !context )
Expand Down Expand Up @@ -957,6 +969,14 @@ void QgsProcessingAlgorithmDialogBase::reject()
QDialog::reject();
}


void QgsProcessingAlgorithmDialogBase::forceClose()
{
mAlgorithmTask = nullptr;
close();
}


//
// QgsProcessingAlgorithmProgressDialog
//
Expand Down
Loading