From 1eaf50b6b9fb6cbf4c5b21326c0e8d54028d690c Mon Sep 17 00:00:00 2001
From: JJ <69144954+jonjenssen@users.noreply.github.com>
Date: Sat, 18 Oct 2025 02:42:11 +0200
Subject: [PATCH] Support running jobs without blocking GUI (#13040)
* Add view job log command.
* Add stop job command.
* Do not block ui while job is running.
* Show progress while job is running
* Make sure user gets notified of running jobs when exiting ResInsight or closing current project.
---
ApplicationExeCode/Resources/ResInsight.qrc | 3 +-
ApplicationExeCode/Resources/stop.svg | 5 +
.../Application/RiaGuiApplication.cpp | 29 +++
.../Application/RiaGuiApplication.h | 7 +-
.../RicCloseProjectFeature.cpp | 8 +-
.../RicExitApplicationFeature.cpp | 3 +-
.../RicOpenLastUsedFileFeature.cpp | 2 +-
.../RicOpenProjectFeature.cpp | 2 +-
.../JobCommands/CMakeLists_files.cmake | 4 +
.../JobCommands/RicStopJobFeature.cpp | 60 ++++++
.../Commands/JobCommands/RicStopJobFeature.h | 38 ++++
.../JobCommands/RicViewJobLogFeature.cpp | 60 ++++++
.../JobCommands/RicViewJobLogFeature.h | 33 +++
.../Jobs/CMakeLists_files.cmake | 2 +
.../ProjectDataModel/Jobs/RimGenericJob.cpp | 190 +++++++++++++++---
.../ProjectDataModel/Jobs/RimGenericJob.h | 30 ++-
.../Jobs/RimJobCollection.cpp | 22 ++
.../ProjectDataModel/Jobs/RimJobCollection.h | 2 +
.../ProjectDataModel/Jobs/RimJobMonitor.cpp | 70 +++++++
.../ProjectDataModel/Jobs/RimJobMonitor.h | 41 ++++
.../ProjectDataModel/Jobs/RimOpmFlowJob.cpp | 137 ++++++++++---
.../ProjectDataModel/Jobs/RimOpmFlowJob.h | 7 +-
.../ProcessControl/RimProcess.cpp | 98 ++++++---
.../ProcessControl/RimProcess.h | 10 +-
.../ProcessControl/RimProcessMonitor.cpp | 48 +++--
.../ProcessControl/RimProcessMonitor.h | 14 +-
.../UserInterface/RiuMainWindow.cpp | 2 +-
.../UserInterface/RiuPlotMainWindow.cpp | 2 +-
.../RiuRecentFileActionProvider.cpp | 2 +-
29 files changed, 809 insertions(+), 122 deletions(-)
create mode 100644 ApplicationExeCode/Resources/stop.svg
create mode 100644 ApplicationLibCode/Commands/JobCommands/RicStopJobFeature.cpp
create mode 100644 ApplicationLibCode/Commands/JobCommands/RicStopJobFeature.h
create mode 100644 ApplicationLibCode/Commands/JobCommands/RicViewJobLogFeature.cpp
create mode 100644 ApplicationLibCode/Commands/JobCommands/RicViewJobLogFeature.h
create mode 100644 ApplicationLibCode/ProjectDataModel/Jobs/RimJobMonitor.cpp
create mode 100644 ApplicationLibCode/ProjectDataModel/Jobs/RimJobMonitor.h
diff --git a/ApplicationExeCode/Resources/ResInsight.qrc b/ApplicationExeCode/Resources/ResInsight.qrc
index 5a827a61d2..c939613301 100644
--- a/ApplicationExeCode/Resources/ResInsight.qrc
+++ b/ApplicationExeCode/Resources/ResInsight.qrc
@@ -302,7 +302,8 @@
Select.svg
NavigationProperty.svg
user-defined-view.svg
- gear.svg
+ stop.svg
+ gear.svg
Parameter.svg
diff --git a/ApplicationExeCode/Resources/stop.svg b/ApplicationExeCode/Resources/stop.svg
new file mode 100644
index 0000000000..dd499fe9c0
--- /dev/null
+++ b/ApplicationExeCode/Resources/stop.svg
@@ -0,0 +1,5 @@
+
+
diff --git a/ApplicationLibCode/Application/RiaGuiApplication.cpp b/ApplicationLibCode/Application/RiaGuiApplication.cpp
index c45b80339c..4f3bb60deb 100644
--- a/ApplicationLibCode/Application/RiaGuiApplication.cpp
+++ b/ApplicationLibCode/Application/RiaGuiApplication.cpp
@@ -48,6 +48,7 @@
#include "SummaryPlotCommands/RicSummaryPlotFeatureImpl.h"
#include "Formations/RimFormationNamesCollection.h"
+#include "Jobs/RimJobCollection.h"
#include "Rim2dIntersectionViewCollection.h"
#include "RimAnnotationCollection.h"
#include "RimAnnotationInViewCollection.h"
@@ -289,6 +290,34 @@ bool RiaGuiApplication::saveProjectAs( const QString& fileName )
return true;
}
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+bool RiaGuiApplication::notifyUserAboutRunningJobs()
+{
+ if ( m_project->jobCollection()->numberOfRunningJobs() > 0 )
+ {
+ QMessageBox::critical( nullptr,
+ "Active running jobs",
+ "One or more jobs are still running, you need to stop all jobs before continuing." );
+ return false;
+ }
+ return true;
+}
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+bool RiaGuiApplication::checkWithUserBeforeClose()
+{
+ // check for any running jobs
+ if ( !notifyUserAboutRunningJobs() ) return false;
+ // ask user to save modified project if needed
+ if ( !askUserToSaveModifiedProject() ) return false;
+
+ return true;
+}
+
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
diff --git a/ApplicationLibCode/Application/RiaGuiApplication.h b/ApplicationLibCode/Application/RiaGuiApplication.h
index 7d4a97a58f..3784ea24d2 100644
--- a/ApplicationLibCode/Application/RiaGuiApplication.h
+++ b/ApplicationLibCode/Application/RiaGuiApplication.h
@@ -88,9 +88,10 @@ public:
bool saveProject();
QString promptForProjectSaveAsFileName() const;
- bool askUserToSaveModifiedProject();
bool saveProjectAs( const QString& fileName );
+ bool checkWithUserBeforeClose();
+
void runMultiCaseSnapshots( const QString& templateProjectFileName, std::vector gridFileNames, const QString& snapshotFolderName );
bool useShaders() const;
@@ -127,6 +128,10 @@ public:
protected:
bool notify( QObject* receiver, QEvent* event ) override;
+ // use the checkWithUserBeforeClose function, to get all checks in one go
+ bool notifyUserAboutRunningJobs();
+ bool askUserToSaveModifiedProject();
+
// Protected RiaApplication overrides
void invokeProcessEvents( QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents ) override;
void onFileSuccessfullyLoaded( const QString& fileName, RiaDefines::ImportFileType fileType ) override;
diff --git a/ApplicationLibCode/Commands/ApplicationCommands/RicCloseProjectFeature.cpp b/ApplicationLibCode/Commands/ApplicationCommands/RicCloseProjectFeature.cpp
index 4a6e83fc53..414eb070ab 100644
--- a/ApplicationLibCode/Commands/ApplicationCommands/RicCloseProjectFeature.cpp
+++ b/ApplicationLibCode/Commands/ApplicationCommands/RicCloseProjectFeature.cpp
@@ -31,10 +31,12 @@ void RicCloseProjectFeature::onActionTriggered( bool isChecked )
{
disableModelChangeContribution();
- RiaGuiApplication* app = RiaGuiApplication::instance();
- if ( !app || !app->askUserToSaveModifiedProject() ) return;
+ if ( RiaGuiApplication* app = RiaGuiApplication::instance() )
+ {
+ if ( !app->checkWithUserBeforeClose() ) return;
- app->closeProject();
+ app->closeProject();
+ }
}
//--------------------------------------------------------------------------------------------------
diff --git a/ApplicationLibCode/Commands/ApplicationCommands/RicExitApplicationFeature.cpp b/ApplicationLibCode/Commands/ApplicationCommands/RicExitApplicationFeature.cpp
index 4fb91901f2..36ce30e144 100644
--- a/ApplicationLibCode/Commands/ApplicationCommands/RicExitApplicationFeature.cpp
+++ b/ApplicationLibCode/Commands/ApplicationCommands/RicExitApplicationFeature.cpp
@@ -35,7 +35,8 @@ void RicExitApplicationFeature::onActionTriggered( bool isChecked )
disableModelChangeContribution();
RiaGuiApplication* app = RiaGuiApplication::instance();
- if ( !app->askUserToSaveModifiedProject() ) return;
+
+ if ( !app->checkWithUserBeforeClose() ) return;
if ( app->mainPlotWindow() )
{
diff --git a/ApplicationLibCode/Commands/ApplicationCommands/RicOpenLastUsedFileFeature.cpp b/ApplicationLibCode/Commands/ApplicationCommands/RicOpenLastUsedFileFeature.cpp
index bfeb4a10f9..23799287c2 100644
--- a/ApplicationLibCode/Commands/ApplicationCommands/RicOpenLastUsedFileFeature.cpp
+++ b/ApplicationLibCode/Commands/ApplicationCommands/RicOpenLastUsedFileFeature.cpp
@@ -34,7 +34,7 @@ void RicOpenLastUsedFileFeature::onActionTriggered( bool isChecked )
{
RiaGuiApplication* app = RiaGuiApplication::instance();
- if ( !app->askUserToSaveModifiedProject() ) return;
+ if ( !app->checkWithUserBeforeClose() ) return;
QString fileName = RiaPreferences::current()->lastUsedProjectFileName;
diff --git a/ApplicationLibCode/Commands/ApplicationCommands/RicOpenProjectFeature.cpp b/ApplicationLibCode/Commands/ApplicationCommands/RicOpenProjectFeature.cpp
index 136dc2cb67..e79b6878cd 100644
--- a/ApplicationLibCode/Commands/ApplicationCommands/RicOpenProjectFeature.cpp
+++ b/ApplicationLibCode/Commands/ApplicationCommands/RicOpenProjectFeature.cpp
@@ -36,7 +36,7 @@ void RicOpenProjectFeature::onActionTriggered( bool isChecked )
{
RiaGuiApplication* app = RiaGuiApplication::instance();
- if ( !app->askUserToSaveModifiedProject() ) return;
+ if ( !app->checkWithUserBeforeClose() ) return;
QString defaultDir = app->lastUsedDialogDirectory( "BINARY_GRID" );
QString fileName =
diff --git a/ApplicationLibCode/Commands/JobCommands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/JobCommands/CMakeLists_files.cmake
index 69f434e612..5cedf6268d 100644
--- a/ApplicationLibCode/Commands/JobCommands/CMakeLists_files.cmake
+++ b/ApplicationLibCode/Commands/JobCommands/CMakeLists_files.cmake
@@ -2,12 +2,16 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicRunJobFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewOpmFlowJobFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicDuplicateJobFeature.h
+ ${CMAKE_CURRENT_LIST_DIR}/RicViewJobLogFeature.h
+ ${CMAKE_CURRENT_LIST_DIR}/RicStopJobFeature.h
)
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicRunJobFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewOpmFlowJobFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicDuplicateJobFeature.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/RicViewJobLogFeature.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/RicStopJobFeature.cpp
)
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
diff --git a/ApplicationLibCode/Commands/JobCommands/RicStopJobFeature.cpp b/ApplicationLibCode/Commands/JobCommands/RicStopJobFeature.cpp
new file mode 100644
index 0000000000..480b9186e8
--- /dev/null
+++ b/ApplicationLibCode/Commands/JobCommands/RicStopJobFeature.cpp
@@ -0,0 +1,60 @@
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2025 Equinor ASA
+//
+// ResInsight is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.
+//
+// See the GNU General Public License at
+// for more details.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "RicStopJobFeature.h"
+
+#include "Jobs/RimGenericJob.h"
+
+#include "cafSelectionManager.h"
+
+#include
+#include
+
+CAF_CMD_SOURCE_INIT( RicStopJobFeature, "RicStopJobFeature" );
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+void RicStopJobFeature::onActionTriggered( bool isChecked )
+{
+ stopJob( dynamic_cast( caf::SelectionManager::instance()->selectedItem() ) );
+}
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+void RicStopJobFeature::setupActionLook( QAction* actionToSetup )
+{
+ actionToSetup->setIcon( QIcon( ":/stop.svg" ) );
+ actionToSetup->setText( "Stop..." );
+}
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+bool RicStopJobFeature::stopJob( RimGenericJob* job )
+{
+ if ( job == nullptr ) return false;
+
+ if ( QMessageBox::question( nullptr, job->name(), "Do you want to stop this job?", QMessageBox::Yes | QMessageBox::No ) == QMessageBox::Yes )
+ {
+ return job->stop();
+ }
+
+ return false;
+}
diff --git a/ApplicationLibCode/Commands/JobCommands/RicStopJobFeature.h b/ApplicationLibCode/Commands/JobCommands/RicStopJobFeature.h
new file mode 100644
index 0000000000..62a3003529
--- /dev/null
+++ b/ApplicationLibCode/Commands/JobCommands/RicStopJobFeature.h
@@ -0,0 +1,38 @@
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2025 Equinor ASA
+//
+// ResInsight is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.
+//
+// See the GNU General Public License at
+// for more details.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "cafCmdFeature.h"
+
+class RimGenericJob;
+
+//==================================================================================================
+///
+//==================================================================================================
+class RicStopJobFeature : public caf::CmdFeature
+{
+ CAF_CMD_HEADER_INIT;
+
+public:
+ static bool stopJob( RimGenericJob* job );
+
+protected:
+ void onActionTriggered( bool isChecked ) override;
+ void setupActionLook( QAction* actionToSetup ) override;
+};
diff --git a/ApplicationLibCode/Commands/JobCommands/RicViewJobLogFeature.cpp b/ApplicationLibCode/Commands/JobCommands/RicViewJobLogFeature.cpp
new file mode 100644
index 0000000000..10a53ced11
--- /dev/null
+++ b/ApplicationLibCode/Commands/JobCommands/RicViewJobLogFeature.cpp
@@ -0,0 +1,60 @@
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2025 Equinor ASA
+//
+// ResInsight is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.
+//
+// See the GNU General Public License at
+// for more details.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "RicViewJobLogFeature.h"
+
+#include "RiuTextDialog.h"
+
+#include "Jobs/RimGenericJob.h"
+
+#include "cafSelectionManager.h"
+
+#include
+#include
+
+CAF_CMD_SOURCE_INIT( RicViewJobLogFeature, "RicViewJobLogFeature" );
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+void RicViewJobLogFeature::onActionTriggered( bool isChecked )
+{
+ if ( auto job = dynamic_cast( caf::SelectionManager::instance()->selectedItem() ) )
+ {
+ const QStringList log = job->jobLog();
+
+ QString text = log.join( "\n" );
+
+ auto* textDlg = new RiuTextDialog();
+ textDlg->setMinimumSize( 600, 800 );
+
+ textDlg->setWindowTitle( "Job log for \"" + job->name() + "\"" );
+ textDlg->setText( text );
+
+ textDlg->exec();
+ }
+}
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+void RicViewJobLogFeature::setupActionLook( QAction* actionToSetup )
+{
+ actionToSetup->setIcon( QIcon( ":/inspect.svg" ) );
+ actionToSetup->setText( "View Log..." );
+}
diff --git a/ApplicationLibCode/Commands/JobCommands/RicViewJobLogFeature.h b/ApplicationLibCode/Commands/JobCommands/RicViewJobLogFeature.h
new file mode 100644
index 0000000000..74419125b3
--- /dev/null
+++ b/ApplicationLibCode/Commands/JobCommands/RicViewJobLogFeature.h
@@ -0,0 +1,33 @@
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2025 Equinor ASA
+//
+// ResInsight is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.
+//
+// See the GNU General Public License at
+// for more details.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "cafCmdFeature.h"
+
+//==================================================================================================
+///
+//==================================================================================================
+class RicViewJobLogFeature : public caf::CmdFeature
+{
+ CAF_CMD_HEADER_INIT;
+
+protected:
+ void onActionTriggered( bool isChecked ) override;
+ void setupActionLook( QAction* actionToSetup ) override;
+};
diff --git a/ApplicationLibCode/ProjectDataModel/Jobs/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/Jobs/CMakeLists_files.cmake
index 3cace000c5..69b8114747 100644
--- a/ApplicationLibCode/ProjectDataModel/Jobs/CMakeLists_files.cmake
+++ b/ApplicationLibCode/ProjectDataModel/Jobs/CMakeLists_files.cmake
@@ -5,6 +5,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimDeckPositionDlg.h
${CMAKE_CURRENT_LIST_DIR}/RimKeywordWconprod.h
${CMAKE_CURRENT_LIST_DIR}/RimKeywordWconinje.h
+ ${CMAKE_CURRENT_LIST_DIR}/RimJobMonitor.h
)
set(SOURCE_GROUP_SOURCE_FILES
@@ -14,6 +15,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimDeckPositionDlg.cpp
${CMAKE_CURRENT_LIST_DIR}/RimKeywordWconprod.cpp
${CMAKE_CURRENT_LIST_DIR}/RimKeywordWconinje.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/RimJobMonitor.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
diff --git a/ApplicationLibCode/ProjectDataModel/Jobs/RimGenericJob.cpp b/ApplicationLibCode/ProjectDataModel/Jobs/RimGenericJob.cpp
index 62188afb89..c1e98377ab 100644
--- a/ApplicationLibCode/ProjectDataModel/Jobs/RimGenericJob.cpp
+++ b/ApplicationLibCode/ProjectDataModel/Jobs/RimGenericJob.cpp
@@ -18,9 +18,16 @@
#include "RimGenericJob.h"
+#include "RiaColorTools.h"
+#include "RiaLogging.h"
+
+#include "RimJobMonitor.h"
#include "RimProcess.h"
+#include "RiuGuiTheme.h"
+
#include "cafCmdFeatureMenuBuilder.h"
+#include "cafPdmUiTreeAttributes.h"
#include "cafProgressInfo.h"
#include
@@ -31,6 +38,10 @@ CAF_PDM_XML_ABSTRACT_SOURCE_INIT( RimGenericJob, "GenericJob" ); // Do not use.
///
//--------------------------------------------------------------------------------------------------
RimGenericJob::RimGenericJob()
+ : m_percentageDone( 0.0 )
+ , m_lastRunFailed( false )
+ , m_isRunning( false )
+ , m_process( nullptr )
{
CAF_PDM_InitObject( "Generic Job" );
}
@@ -42,13 +53,29 @@ RimGenericJob::~RimGenericJob()
{
}
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+double RimGenericJob::percentageDone() const
+{
+ return m_percentageDone;
+}
+
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGenericJob::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
- menuBuilder << "RicRunJobFeature";
+ if ( isRunning() )
+ {
+ menuBuilder << "RicStopJobFeature";
+ }
+ else
+ {
+ menuBuilder << "RicRunJobFeature";
+ }
menuBuilder << "RicDuplicateJobFeature";
+ menuBuilder << "RicViewJobLogFeature";
}
//--------------------------------------------------------------------------------------------------
@@ -59,52 +86,157 @@ QString RimGenericJob::workingDirectory() const
return "";
}
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+bool RimGenericJob::isRunning() const
+{
+ return m_isRunning;
+}
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+bool RimGenericJob::stop()
+{
+ if ( !m_process.isNull() )
+ {
+ m_process->terminate();
+ RiaLogging::info( "Job \"" + name() + "\" stopped by user." );
+ return true;
+ }
+ return false;
+}
+
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimGenericJob::execute()
{
+ if ( isRunning() ) return false;
+
+ m_process = nullptr;
+ m_percentageDone = 0.0;
+
// job preparations
{
- caf::ProgressInfo prepProgress( 1, title(), false );
+ caf::ProgressInfo prepProgress( 1, name(), false );
auto prepRun = prepProgress.task( "Preparing for run, please wait..." );
- if ( !onPrepare() ) return false;
+ if ( !onPrepare() )
+ {
+ m_lastRunFailed = true;
+ onProgress( m_percentageDone );
+ return false;
+ }
}
// check if we should run
if ( !onRun() ) return false;
- // run job
- bool runOk = false;
+ QStringList cmdLine = command();
+ if ( cmdLine.isEmpty() ) return false;
+
+ // cannot delete job while running
+ setDeletable( false );
+
+ m_process = new RimProcess( true, new RimJobMonitor( this ) );
+
+ m_isRunning = true;
+ m_lastRunFailed = false;
+
+ onProgress( m_percentageDone );
+
+ // build process to run
+ QString cmd = cmdLine.takeFirst();
+ m_process->setCommand( cmd );
+ if ( !cmdLine.isEmpty() ) m_process->addParameters( cmdLine );
+ m_process->setWorkingDirectory( workingDirectory() );
+ for ( const auto& [name, value] : environment() )
{
- caf::ProgressInfo runProgress( 1, title() );
-
- auto taskRun = runProgress.task( "Running job, please wait..." );
-
- QStringList cmdLine = command();
- if ( cmdLine.isEmpty() ) return false;
-
- QString cmd = cmdLine.takeFirst();
-
- RimProcess process;
- process.setCommand( cmd );
- if ( !cmdLine.isEmpty() ) process.addParameters( cmdLine );
- process.setWorkingDirectory( workingDirectory() );
- for ( const auto& [name, value] : environment() )
- {
- process.addEnvironmentVariable( name, value );
- }
-
- runOk = process.execute();
+ m_process->addEnvironmentVariable( name, value );
}
+ // run process
+ bool startOk = m_process->start();
+ if ( !startOk )
+ {
+ onCompleted( false );
+ m_lastRunFailed = true;
+ m_isRunning = false;
+ setDeletable( true );
+ QMessageBox::critical( nullptr, name(), "Failed to start job. Check log window for additional information." );
+ }
+
+ return startOk;
+}
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+bool RimGenericJob::setFinished( bool runOk )
+{
+ m_isRunning = false;
+
+ m_lastRunFailed = !runOk;
+
+ m_percentageDone = 100.0;
+ onProgress( m_percentageDone );
+ setDeletable( true );
+
onCompleted( runOk );
- if ( !runOk )
- {
- QMessageBox::critical( nullptr, title(), "Failed to run job. Check log window for additional information." );
- }
return runOk;
-}
\ No newline at end of file
+}
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+void RimGenericJob::defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
+{
+ if ( auto* treeItemAttribute = dynamic_cast( attribute ) )
+ {
+ if ( m_lastRunFailed )
+ {
+ auto tag = caf::PdmUiTreeViewItemAttribute::createTag( QColor( Qt::red ),
+ RiuGuiTheme::getColorByVariableName( "backgroundColor1" ),
+ "!!!" );
+ treeItemAttribute->tags.push_back( std::move( tag ) );
+ }
+ else
+ {
+ if ( ( m_percentageDone == 0.0 ) && ( !m_isRunning ) ) return;
+
+ auto tag = caf::PdmUiTreeViewItemAttribute::createTag();
+
+ if ( m_isRunning )
+ {
+ tag->text = QString( "%1 %" ).arg( m_percentageDone, 0, 'f', 1 );
+ }
+ else
+ {
+ tag->text = "Done";
+ }
+
+ double factor = m_percentageDone / 100.0;
+
+ cvf::Color3f viewColor = cvf::Color3f( cvf::Color3f::GREEN );
+ viewColor.set( viewColor.r() * factor, viewColor.g() * factor, viewColor.b() * factor );
+ cvf::Color3f viewTextColor = RiaColorTools::contrastColor( viewColor );
+ tag->bgColor = QColor( RiaColorTools::toQColor( viewColor ) );
+ tag->fgColor = QColor( RiaColorTools::toQColor( viewTextColor ) );
+ treeItemAttribute->tags.push_back( std::move( tag ) );
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+const QStringList RimGenericJob::jobLog() const
+{
+ if ( m_process.isNull() ) return QStringList();
+
+ return m_process->stdOut();
+}
diff --git a/ApplicationLibCode/ProjectDataModel/Jobs/RimGenericJob.h b/ApplicationLibCode/ProjectDataModel/Jobs/RimGenericJob.h
index c92abeceb3..186e1ccdcc 100644
--- a/ApplicationLibCode/ProjectDataModel/Jobs/RimGenericJob.h
+++ b/ApplicationLibCode/ProjectDataModel/Jobs/RimGenericJob.h
@@ -20,11 +20,15 @@
#include "RimNamedObject.h"
+#include "cafPdmPointer.h"
+
#include
#include
#include