From 21e37e1ca97871601ca64c06b0791d709b04c403 Mon Sep 17 00:00:00 2001
From: David Fairbrother <DavidFair@users.noreply.github.com>
Date: Wed, 20 Jun 2018 17:07:32 +0100
Subject: [PATCH] Re #0 Add Project recovery to config

---
 .../Properties/Mantid.properties.template     |  3 ++
 MantidPlot/src/ProjectRecoveryThread.cpp      | 51 +++++++++++++++++--
 MantidPlot/src/ProjectRecoveryThread.h        | 14 +++++
 3 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/Framework/Properties/Mantid.properties.template b/Framework/Properties/Mantid.properties.template
index d77b4e226d3..44461931420 100644
--- a/Framework/Properties/Mantid.properties.template
+++ b/Framework/Properties/Mantid.properties.template
@@ -252,3 +252,6 @@ cluster.submission=Off
 
 # Used to stop a catalog asynchronous algorithm after the timeout period
 catalog.timeout.value=30
+
+# Indicates if project recovery should automatically save in the background
+projectRecovery.enabled=true
\ No newline at end of file
diff --git a/MantidPlot/src/ProjectRecoveryThread.cpp b/MantidPlot/src/ProjectRecoveryThread.cpp
index 0fb437478d8..7bcde944874 100644
--- a/MantidPlot/src/ProjectRecoveryThread.cpp
+++ b/MantidPlot/src/ProjectRecoveryThread.cpp
@@ -6,8 +6,10 @@
 #include "globals.h"
 
 #include "MantidAPI/FileProperty.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/Logger.h"
 
+#include "Poco/NObserver.h"
 #include "Poco/Path.h"
 #include "qmetaobject.h"
 
@@ -18,7 +20,17 @@
 #include <thread>
 
 namespace {
+Mantid::Kernel::Logger g_log("Project Recovery Thread");
 const std::chrono::seconds TIME_BETWEEN_SAVING = std::chrono::seconds(30);
+const std::string SAVING_ENABLED_CONFIG_KEY = "projectRecovery.enabled";
+
+bool isRecoveryEnabled() {
+  std::string isEnabled;
+  int valueIsGood = Mantid::Kernel::ConfigService::Instance().getValue<std::string>(
+      SAVING_ENABLED_CONFIG_KEY, isEnabled);
+  
+  return (valueIsGood == 1) && isEnabled.find("true") != std::string::npos;
+}
 
 std::string getOutputPath() {
   static bool isInitalised = false;
@@ -35,16 +47,19 @@ std::string getOutputPath() {
 
 std::string getOutputProjectName() { return "recovery.project"; }
 
-Mantid::Kernel::Logger g_log("Project Recovery Thread");
 } // namespace
 
 namespace MantidQt {
 namespace API {
 
 ProjectRecoveryThread::ProjectRecoveryThread(ApplicationWindow *windowHandle)
-    : m_windowPtr(windowHandle), m_backgroundSavingThread(),
-      m_stopBackgroundThread(true) {
-  startProjectSaving();
+    : m_backgroundSavingThread(), m_stopBackgroundThread(true),
+      m_configKeyObserver(*this, &ProjectRecoveryThread::configKeyChanged),
+      m_windowPtr(windowHandle) {
+
+  if (isRecoveryEnabled()) {
+    startProjectSaving();
+  }
 }
 
 ProjectRecoveryThread::~ProjectRecoveryThread() { stopProjectSaving(); }
@@ -52,7 +67,20 @@ ProjectRecoveryThread::~ProjectRecoveryThread() { stopProjectSaving(); }
 std::thread ProjectRecoveryThread::createBackgroundThread() {
   // Using a lambda helps the compiler deduce the this pointer
   // otherwise the resolution is ambiguous
-  return std::thread([this] { projectSavingThread(); });
+  return std::thread([this] { projectSavingThreadWrapper(); });
+}
+
+void ProjectRecoveryThread::configKeyChanged(
+    Mantid::Kernel::ConfigValChangeNotification_ptr notif) {
+  if (notif->key() != (SAVING_ENABLED_CONFIG_KEY)) {
+    return;
+  }
+
+  if (notif->curValue() == "True") {
+    startProjectSaving();
+  } else {
+    stopProjectSaving();
+  }
 }
 
 void ProjectRecoveryThread::startProjectSaving() {
@@ -80,6 +108,19 @@ void ProjectRecoveryThread::stopProjectSaving() {
   }
 }
 
+void ProjectRecoveryThread::projectSavingThreadWrapper() {
+  try {
+    projectSavingThread();
+  } catch (std::exception const &e) {
+    std::string preamble("Project recovery has stopped. Please report"
+                         " this to the development team.\nException:\n");
+    g_log.warning(preamble + e.what());
+  } catch (...) {
+    g_log.warning("Project recovery has stopped. Please report"
+                  " this to the development team.");
+  }
+}
+
 void ProjectRecoveryThread::projectSavingThread() {
   while (!m_stopBackgroundThread) {
     std::unique_lock<std::mutex> lock(m_notifierMutex);
diff --git a/MantidPlot/src/ProjectRecoveryThread.h b/MantidPlot/src/ProjectRecoveryThread.h
index 520a1b53622..3669194bfe7 100644
--- a/MantidPlot/src/ProjectRecoveryThread.h
+++ b/MantidPlot/src/ProjectRecoveryThread.h
@@ -1,6 +1,10 @@
 #ifndef PROJECT_RECOVERY_THREAD_H_
 #define PROJECT_RECOVERY_THREAD_H_
 
+#include "MantidKernel/ConfigService.h"
+
+#include <Poco/NObserver.h>
+
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -55,12 +59,17 @@ private:
   /// Captures the current object in the background thread
   std::thread createBackgroundThread();
 
+  /// Triggers when the config key is updated to a new value
+  void configKeyChanged(Mantid::Kernel::ConfigValChangeNotification_ptr notif);
+
   /// Loads a project recovery file back into Mantid
   void loadOpenWindows(const std::string &projectFolder);
   /// Saves a project recovery file in Mantid
   void saveOpenWindows(const std::string &projectDestFolder);
   /// Saves the current workspace's histories from Mantid
   void saveWsHistories(const std::string &projectDestFile);
+  /// Wraps the thread in a try catch to log any failures
+  void projectSavingThreadWrapper();
   /// Main body of saving thread
   void projectSavingThread();
 
@@ -74,6 +83,11 @@ private:
   /// Atomic to detect when the thread should fire or exit
   std::condition_variable m_threadNotifier;
 
+  /// Config observer to monitor the key
+  Poco::NObserver<ProjectRecoveryThread,
+                  Mantid::Kernel::ConfigValChangeNotification>
+      m_configKeyObserver;
+
   /// Pointer to main GUI window
   ApplicationWindow *m_windowPtr;
 };
-- 
GitLab