From dfbe83b4fe511e9a37e7d3b448672d9235547080 Mon Sep 17 00:00:00 2001
From: Federico Montesino Pouzols <federico.montesino-pouzols@stfc.ac.uk>
Date: Fri, 25 Sep 2015 13:06:39 +0100
Subject: [PATCH] new focusing modes (cropped, texture) in view-presenter, re
 #13486

---
 .../EnggDiffractionPresWorker.h               |  23 +-
 .../EnggDiffractionPresenter.h                |  40 ++-
 .../EnggDiffractionViewQtGUI.h                |  17 +-
 .../IEnggDiffractionPresenter.h               |   5 +-
 .../EnggDiffraction/IEnggDiffractionView.h    |  42 ++-
 .../EnggDiffractionPresenter.cpp              | 323 ++++++++++++++----
 .../EnggDiffractionViewQtGUI.cpp              |  76 ++++-
 7 files changed, 413 insertions(+), 113 deletions(-)

diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h
index d241b2dd136..37c95579f4b 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h
+++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h
@@ -41,15 +41,15 @@ public:
   /// for calibration
   EnggDiffWorker(EnggDiffractionPresenter *pres, const std::string &outFilename,
                  const std::string &vanNo, const std::string &ceriaNo)
-      : m_pres(pres), m_outFilename(outFilename), m_vanNo(vanNo),
-        m_ceriaNo(ceriaNo), m_bank(-1) {}
+      : m_pres(pres), m_outFilenames(), m_outCalibFilename(outFilename),
+        m_vanNo(vanNo), m_ceriaNo(ceriaNo), m_banks() {}
 
   /// for focusing
   EnggDiffWorker(EnggDiffractionPresenter *pres, const std::string &outDir,
-                 const std::string &outFilename, const std::string &runNo,
-                 int bank)
-      : m_pres(pres), m_outFilename(outFilename), m_runNo(runNo),
-        m_outDir(outDir), m_bank(bank) {}
+                 const std::vector<std::string> &outFilenames,
+                 const std::string &runNo, const std::vector<bool> &banks)
+      : m_pres(pres), m_outFilenames(outFilenames), m_outCalibFilename(),
+        m_runNo(runNo), m_outDir(outDir), m_banks(banks) {}
 
 private slots:
 
@@ -58,7 +58,7 @@ private slots:
    * signal.
    */
   void calibrate() {
-    m_pres->doNewCalibration(m_outFilename, m_vanNo, m_ceriaNo);
+    m_pres->doNewCalibration(m_outCalibFilename, m_vanNo, m_ceriaNo);
     emit finished();
   }
 
@@ -67,7 +67,7 @@ private slots:
    * signal.
    */
   void focus() {
-    m_pres->doFocusRun(m_outDir, m_outFilename, m_runNo, m_bank);
+    m_pres->doFocusRun(m_outDir, m_outFilenames, m_runNo, m_banks);
     emit finished();
   }
 
@@ -77,13 +77,14 @@ signals:
 private:
   EnggDiffractionPresenter *m_pres;
   /// parameters for calibration
-  std::string m_outFilename, m_vanNo, m_ceriaNo;
+  const std::vector<std::string> m_outFilenames;
+  const std::string m_outCalibFilename, m_vanNo, m_ceriaNo;
   /// sample run to process
   const std::string m_runNo;
   /// Output directory
   const std::string m_outDir;
-  /// instrument bank
-  int m_bank;
+  /// instrument banks: do focus/don't
+  const std::vector<bool> m_banks;
 };
 
 } // namespace CustomInterfaces
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h
index 2f476cbde73..4fe5cf1c340 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h
+++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h
@@ -64,8 +64,9 @@ public:
                         const std::string &vanNo, const std::string &ceriaNo);
 
   /// the focusing hard work that a worker / thread will run
-  void doFocusRun(const std::string &dir, const std::string &outFilename,
-                  const std::string &runNo, int bank);
+  void doFocusRun(const std::string &dir,
+                  const std::vector<std::string> &outFilenames,
+                  const std::string &runNo, const std::vector<bool> &banks);
 
 protected:
   void initialize();
@@ -76,7 +77,10 @@ protected:
   void processStart();
   void processLoadExistingCalib();
   void processCalcCalib();
-  void processFocusRun();
+  void processFocusBasic();
+  void processFocusCropped();
+  void processFocusTexture();
+  void processResetFocus();
   void processLogMsg();
   void processInstChange();
   void processShutDown();
@@ -112,17 +116,29 @@ private:
   /// @name Focusing related private methods
   //@{
   /// this may also need to be mocked up in tests
-  virtual void startAsyncFocusWorker(const std::string &dir,
-                                     const std::string &outFilename,
-                                     const std::string &runNo, int bank);
-
-  void inputChecksBeforeFocus(const std::string &runNo, int bank);
-
-  std::string outputFocusFilename(const std::string &runNo, int bank);
+  void startFocusing(const std::string &runNo, const std::vector<bool> banks,
+                const std::string &specIDs, const std::string &dgFile);
+
+  void startAsyncFocusWorker(const std::string &dir,
+                        const std::vector<std::string> &outFilenames,
+                        const std::string &runNo, const std::vector<bool> &banks);
+
+  void inputChecksBeforeFocusBasic(const std::string &runNo,
+                                   const std::vector<bool> &banks);
+  void inputChecksBeforeFocusCropped(const std::string &runNo,
+                                     const std::vector<bool> &banks,
+                                     const std::string &specIDs);
+  void inputChecksBeforeFocusTexture(const std::string &runNo,
+                                     const std::string &dgfile);
+  void inputChecksBeforeFocus();
+  void inputChecksBanks(const std::vector<bool> &banks);
+
+  std::vector<std::string> outputFocusFilename(const std::string &runNo,
+                                               const std::vector<bool> &banks);
 
   void doFocusing(const EnggDiffCalibSettings &cs,
                   const std::string &fullFilename, const std::string &runNo,
-                  int bank);
+                  size_t bank);
 
   void loadOrCalcVanadiumWorkspaces(
       const std::string &vanNo, const std::string &inputDirCalib,
@@ -167,4 +183,4 @@ private:
 } // namespace CustomInterfaces
 } // namespace MantidQt
 
-# endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_ENGGDIFFRACTIONPRESENTER_H_
+#endif // MANTIDQTCUSTOMINTERFACES_ENGGDIFFRACTION_ENGGDIFFRACTIONPRESENTER_H_
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h
index c9b25715a36..5adb43c683b 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h
+++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h
@@ -105,18 +105,31 @@ public:
 
   virtual std::string focusingRunNo() const;
 
-  virtual int focusingBank() const;
+  virtual std::string focusingCroppedRunNo() const;
+
+  virtual std::string focusingTextureRunNo() const;
+
+  virtual std::vector<bool> focusingBanks() const;
+
+  virtual std::string focusingCroppedSpectrumIDs() const;
+
+  virtual std::string focusingTextureGroupingFile() const;
 
   virtual bool focusedOutWorkspace() const;
 
+  virtual void resetFocus();
+
   virtual void plotFocusedSpectrum();
 
 private slots:
-  /// for buttons, do calibrate and similar
+  /// for buttons, do calibrate, focus and similar
   void loadCalibrationClicked();
   void calibrateClicked();
   void focusClicked();
+  void focusCroppedClicked();
+  void focusTextureClicked();
 
+  void focusResetClicked();
 
   // slots of the settings tab/section of the interface
   void browseInputDirCalib();
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h
index 42020a4c53e..a2c0240d4ce 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h
+++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionPresenter.h
@@ -41,7 +41,10 @@ public:
     Start,                 ///< Start and setup interface
     LoadExistingCalib,     ///< Load a calibration already availble on disk
     CalcCalib,             ///< Calculate a (new) calibration
-    FocusRun,              ///< Focus a run file
+    FocusRun,              ///< Focus one or more run files
+    FocusCropped,          ///< Focus one or more run files, cropped variant
+    FocusTexture,          ///< Focus one or more run files, texture variant
+    ResetFocus,            ///< Re-set / clear all focus inputs and options
     LogMsg,                ///< need to send a message to the Mantid log system
     InstrumentChange,      ///< Instrument selection updated
     ShutDown               ///< closing the interface
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h
index 5785b8db630..41c6cda7cdf 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h
+++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h
@@ -206,19 +206,55 @@ public:
   virtual std::string focusingRunNo() const = 0;
 
   /**
-   * Bank to consider when focusing
+   * A (sample) run to focus, in "cropped" mode
    *
-   * @return instrument bank number
+   * @return run number, as a string
+   */
+  virtual std::string focusingCroppedRunNo() const = 0;
+
+  /**
+   * A (sample) run to focus, in "texture" mode
+   *
+   * @return run number, as a string
+   */
+  virtual std::string focusingTextureRunNo() const = 0;
+
+  /**
+   * Banks to consider when focusing
+   *
+   * @return vector with a boolean value that tells if the
+   * corresponding instrument bank numbers should be focused
+   */
+  virtual std::vector<bool> focusingBanks() const = 0;
+
+  /**
+   * Specification of spectrum IDs for focus in "cropped" mode.
+   *
+   * @return spectrum IDs, expected as a comma separated list of
+   * integers or ranges of integers.
    */
-  virtual int focusingBank() const = 0;
+  virtual std::string focusingCroppedSpectrumIDs() const = 0;
+
+  /**
+   * Detector grouping file, used when focusing in "texture" mode.
+   *
+   * @return name of the grouping file with texture bank definitions
+   */
+  virtual std::string focusingTextureGroupingFile() const = 0;
 
   /**
    * Check box to consider when focusing
    * whether to plot focused workspace
+   *
    * @return bool
    */
   virtual bool focusedOutWorkspace() const = 0;
 
+  /**
+   * Reset all focus inputs/options
+   */
+  virtual void resetFocus() = 0;
+
   /**
    * Save settings (normally when closing the interface). This
    * concerns only GUI settings, such as window max/min status and
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp
index 2f2d9ab63e3..1ce0532e649 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp
+++ b/Code/Mantid/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp
@@ -53,8 +53,7 @@ void EnggDiffractionPresenter::cleanup() {
   if (m_workerThread) {
     if (m_workerThread->isRunning()) {
       g_log.notice() << "A calibration process is currently running, shutting "
-                        "it down immediately..."
-                     << std::endl;
+                        "it down immediately..." << std::endl;
       m_workerThread->wait(10);
     }
     delete m_workerThread;
@@ -80,7 +79,19 @@ void EnggDiffractionPresenter::notify(
     break;
 
   case IEnggDiffractionPresenter::FocusRun:
-    processFocusRun();
+    processFocusBasic();
+    break;
+
+  case IEnggDiffractionPresenter::FocusCropped:
+    processFocusCropped();
+    break;
+
+  case IEnggDiffractionPresenter::FocusTexture:
+    processFocusTexture();
+    break;
+
+  case IEnggDiffractionPresenter::ResetFocus:
+    processResetFocus();
     break;
 
   case IEnggDiffractionPresenter::LogMsg:
@@ -130,10 +141,8 @@ void EnggDiffractionPresenter::processCalcCalib() {
                         ia.what());
     return;
   }
-
   g_log.notice() << "EnggDiffraction GUI: starting new calibration. This may "
-                    "take a few seconds... "
-                 << std::endl;
+                    "take a few seconds... " << std::endl;
 
   const std::string outFilename = outputCalibFilename(vanNo, ceriaNo);
 
@@ -144,31 +153,96 @@ void EnggDiffractionPresenter::processCalcCalib() {
   startAsyncCalibWorker(outFilename, vanNo, ceriaNo);
 }
 
-void EnggDiffractionPresenter::processFocusRun() {
-  std::string runNo = m_view->focusingRunNo();
-  int bank = m_view->focusingBank();
+void EnggDiffractionPresenter::processFocusBasic() {
+  const std::string runNo = m_view->focusingRunNo();
+  const std::vector<bool> banks = m_view->focusingBanks();
+
   try {
-    inputChecksBeforeFocus(runNo, bank);
+    inputChecksBeforeFocusBasic(runNo, banks);
   } catch (std::invalid_argument &ia) {
     m_view->userWarning("Error in the inputs required to focus a run",
                         ia.what());
     return;
   }
 
-  g_log.notice() << "EnggDiffraction GUI: starting new focusing. This may take "
-                    "some seconds... "
-                 << std::endl;
+  startFocusing(runNo, banks, "", "");
+}
+
+void EnggDiffractionPresenter::processFocusCropped() {
+  const std::string runNo = m_view->focusingCroppedRunNo();
+  const std::vector<bool> banks = m_view->focusingBanks();
+  const std::string specIDs = m_view->focusingCroppedSpectrumIDs();
+
+  try {
+    inputChecksBeforeFocusCropped(runNo, banks, specIDs);
+  } catch (std::invalid_argument &ia) {
+    m_view->userWarning(
+        "Error in the inputs required to focus a run in cropped mode",
+        ia.what());
+    return;
+  }
+
+  startFocusing(runNo, banks, specIDs, "");
+}
+
+void EnggDiffractionPresenter::processFocusTexture() {
+  std::string runNo = m_view->focusingTextureRunNo();
+  const std::vector<bool> banks = m_view->focusingBanks();
+  std::string dgFile = m_view->focusingTextureGroupingFile();
+
+  try {
+    inputChecksBeforeFocusTexture(runNo, dgFile);
+  } catch (std::invalid_argument &ia) {
+    m_view->userWarning(
+        "Error in the inputs required to focus a run in texture mode",
+        ia.what());
+    return;
+  }
+
+  startFocusing(runNo, banks, "", dgFile);
+}
+
+/**
+ * Starts a focusing worker, for different modes depending on the
+ * inputs provided. Assumes that the inputs have been checked by the
+ * respective specific processFocus methods (for normal, cropped,
+ * texture, etc. focusing).
+ *
+ * @param runNo run/file number to focus
+ * @param banks banks to include in the focusing, processed one at a time
+ *
+ * @param specIDs list of spectra to use when focusing. If not empty
+ * this is focusing in cropped mode.
+ *
+ * @param dgFile detector grouping file to define banks (texture). If
+ * not empty, this is focusing in texture mode.
+ */
+void EnggDiffractionPresenter::startFocusing(const std::string &runNo,
+                                             const std::vector<bool> banks,
+                                             const std::string &specIDs,
+                                             const std::string &dgFile) {
+  std::string optMsg = "";
+  if (!specIDs.empty()) {
+    optMsg = " (cropped)";
+  } else if (!dgFile.empty()) {
+    optMsg = " (texture)";
+  }
+  g_log.notice() << "EnggDiffraction GUI: starting new focusing" << optMsg
+                 << ". This may take some seconds... " << std::endl;
 
   const std::string focusDir = m_view->focusingDir();
-  const std::string outFilename = outputFocusFilename(runNo, bank);
+  const std::vector<std::string> outFilenames =
+      outputFocusFilename(runNo, banks);
 
   m_view->enableCalibrateAndFocusActions(false);
   // GUI-blocking alternative:
-  // doFocusRun(focusDir, outFilename, runNo, bank)
+  // doFocusRun(focusDir, outFilenames, runNo, banks)
   // focusingFinished()
-  startAsyncFocusWorker(focusDir, outFilename, runNo, bank);
+  startAsyncFocusWorker(focusDir, outFilenames, runNo, banks);
 }
 
+void EnggDiffractionPresenter::processResetFocus() { m_view->resetFocus(); }
+
 void EnggDiffractionPresenter::processLogMsg() {
   std::vector<std::string> msgs = m_view->logMsgs();
   for (size_t i = 0; i < msgs.size(); i++) {
@@ -336,9 +410,10 @@ void EnggDiffractionPresenter::parseCalibrateFilename(const std::string &path,
  * @param vanNo vanadium run number
  * @param ceriaNo ceria run number
  */
-void EnggDiffractionPresenter::startAsyncCalibWorker(
-    const std::string &outFilename, const std::string &vanNo,
-    const std::string &ceriaNo) {
+void
+EnggDiffractionPresenter::startAsyncCalibWorker(const std::string &outFilename,
+                                                const std::string &vanNo,
+                                                const std::string &ceriaNo) {
   delete m_workerThread;
   m_workerThread = new QThread(this);
   EnggDiffWorker *worker =
@@ -387,13 +462,11 @@ void EnggDiffractionPresenter::doNewCalibration(const std::string &outFilename,
   } catch (std::runtime_error &) {
     g_log.error() << "The calibration calculations failed. One of the "
                      "algorithms did not execute correctly. See log messages "
-                     "for details. "
-                  << std::endl;
+                     "for details. " << std::endl;
   } catch (std::invalid_argument &) {
     g_log.error()
         << "The calibration calculations failed. Some input properties "
-           "were not valid. See log messages for details. "
-        << std::endl;
+           "were not valid. See log messages for details. " << std::endl;
   }
   // restore normal data search paths
   conf.setDataSearchDirs(tmpDirs);
@@ -548,26 +621,111 @@ void EnggDiffractionPresenter::doCalib(const EnggDiffCalibSettings &cs,
 }
 
 /**
- * Performs several checks on the current focusing inputs and
- * settings. This should be done before starting any focus work. The
- * message return should be shown to the user as a visible message
- * (pop-up, error log, etc.)
+ * Perform checks specific to normal/basic run focusing in addition to
+ * the general checks for any focusing (as done by
+ * inputChecksBeforeFocus() which is called from this method). Use
+ * always before running 'Focus'
  *
  * @param runNo run number to focus
- * @param bank bank to focus
+ * @param banks which banks to consider in the focusing
  *
  * @throws std::invalid_argument with an informative message.
  */
-void EnggDiffractionPresenter::inputChecksBeforeFocus(const std::string &runNo,
-                                                      int bank) {
+void EnggDiffractionPresenter::inputChecksBeforeFocusBasic(
+    const std::string &runNo, const std::vector<bool> &banks) {
   if (runNo.empty()) {
-    throw std::invalid_argument(
-        "The sample run number cannot be empty and must be an integer number.");
+    const std::string msg = "The sample run number to focus cannot be "
+                            "empty and must be an integer number.";
+    throw std::invalid_argument(msg);
+  }
+
+  inputChecksBanks(banks);
+
+  inputChecksBeforeFocus();
+}
+
+/**
+ * Perform checks specific to focusing in "cropped" mode, in addition
+ * to the general checks for any focusing (as done by
+ * inputChecksBeforeFocus() which is called from this method). Use
+ * always before running 'FocusCropped'
+ *
+ * @param runNo run number to focus
+ * @param banks which banks to consider in the focusing
+ * @param specIDs list of spectra (as usual csv list of spectra in Mantid)
+ *
+ * @throws std::invalid_argument with an informative message.
+ */
+void EnggDiffractionPresenter::inputChecksBeforeFocusCropped(
+    const std::string &runNo, const std::vector<bool> &banks,
+    const std::string &specIDs) {
+  if (runNo.empty()) {
+    throw std::invalid_argument("To focus cropped the sample run number cannot "
+                                "be empty and must be an integer number.");
   }
-  if (bank < 1) {
-    throw std::invalid_argument("The bank number must be a positive integer.");
+
+  if (specIDs.empty()) {
+    throw std::invalid_argument("The list of spectrum IDs cannot be empty when "
+                                "focusing in 'cropped' mode.");
   }
 
+  inputChecksBanks(banks);
+
+  inputChecksBeforeFocus();
+}
+
+/**
+ * Perform checks specific to focusing in "texture" mode, in addition
+ * to the general checks for any focusing (as done by
+ * inputChecksBeforeFocus() which is called from this method). Use
+ * always before running 'FocusCropped'
+ *
+ * @param runNo run number to focus
+ * @param dgFile file with detector grouping info
+ *
+ * @throws std::invalid_argument with an informative message.
+ */
+void EnggDiffractionPresenter::inputChecksBeforeFocusTexture(
+    const std::string &runNo, const std::string &dgFile) {
+  if (runNo.empty()) {
+    throw std::invalid_argument("To focus texture banks the sample run number "
+                                "cannot be empty and must be an integer "
+                                "number.");
+  }
+
+  if (dgFile.empty()) {
+    throw std::invalid_argument("A detector grouping file needs to be "
+                                "specified when focusing texture banks.");
+  }
+  inputChecksBeforeFocus();
+}
+
+void EnggDiffractionPresenter::inputChecksBanks(const std::vector<bool> &banks) {
+  if (0 == banks.size()) {
+    const std::string msg =
+        "Error in specification of banks found when starting the "
+        "focusing process. Cannot continue.";
+    g_log.error() << msg << std::endl;
+    throw std::invalid_argument(msg);
+  }
+  if (banks.end() == std::find(banks.begin(), banks.end(), true)) {
+    const std::string msg =
+        "EnggDiffraction GUI: not focusing, as all the banks "
+        "have been unselected. You probably forgot to select at least one.";
+    g_log.warning() << msg << std::endl;
+    throw std::invalid_argument(msg);
+  }
+}
+
+/**
+ * Performs several checks on the current focusing inputs and
+ * settings. This should be done before starting any focus work. The
+ * message return should be shown to the user as a visible message
+ * (pop-up, error log, etc.)
+ *
+ * @throws std::invalid_argument with an informative message.
+ */
+void EnggDiffractionPresenter::inputChecksBeforeFocus() {
   EnggDiffCalibSettings cs = m_view->currentCalibSettings();
   const std::string pixelCalib = cs.m_pixelCalibFilename;
   if (pixelCalib.empty()) {
@@ -577,23 +735,28 @@ void EnggDiffractionPresenter::inputChecksBeforeFocus(const std::string &runNo,
 }
 
 /**
- * Builds the name of the output focused file, given the sample run
- * number and the bank to focus.
+ * Builds the names of the output focused files (one per bank), given
+ * the sample run number and which banks should be focused.
  *
  * @param runNo number of the run for which we want a focused output
  * file name
  *
- * @param bank bank number which is normally used as a suffix
+ * @param banks for every bank, (true/false) to consider it or not for
+ * the focusing
  *
- * @return filename (without the full path)
+ * @return filenames (without the full path)
  */
-std::string
+std::vector<std::string>
 EnggDiffractionPresenter::outputFocusFilename(const std::string &runNo,
-                                              int bank) {
+                                              const std::vector<bool> &banks) {
   const std::string instStr = m_view->currentInstrument();
 
-  return instStr + runNo + "_focused_bank_" +
-         boost::lexical_cast<std::string>(bank);
+  std::vector<std::string> res;
+  for (size_t b = 1; b <= banks.size(); b++) {
+    res.push_back(instStr + runNo + "_focused_bank_" +
+                  boost::lexical_cast<std::string>(banks[b]));
+  }
+  return res;
 }
 
 /**
@@ -603,17 +766,17 @@ EnggDiffractionPresenter::outputFocusFilename(const std::string &runNo,
  * Q_OBJECT.
  *
  * @param dir directory (full path) for the focused output files
- * @param outFilename full name for the output focused run
-o * @param runNo input run number
+ * @param outFilenames full names for the output focused runs
+ * @param runNo input run number
  * @param bank instrument bank to focus
  */
 void EnggDiffractionPresenter::startAsyncFocusWorker(
-    const std::string &dir, const std::string &outFilename,
-    const std::string &runNo, int bank) {
+    const std::string &dir, const std::vector<std::string> &outFilenames,
+    const std::string &runNo, const std::vector<bool> &banks) {
   delete m_workerThread;
   m_workerThread = new QThread(this);
   EnggDiffWorker *worker =
-      new EnggDiffWorker(this, dir, outFilename, runNo, bank);
+      new EnggDiffWorker(this, dir, outFilenames, runNo, banks);
   worker->moveToThread(m_workerThread);
 
   connect(m_workerThread, SIGNAL(started()), worker, SLOT(focus()));
@@ -631,20 +794,19 @@ void EnggDiffractionPresenter::startAsyncFocusWorker(
  * push or similar from the user.
  *
  * @param dir directory (full path) for the output focused files
- * @param outFilename name for the output focused file
+ * @param outFilenames names for the output focused files (one per bank)
  * @param runNo input run number
- * @param bank bank number for the focusing
+ *
+ * @param banks for every bank, (true/false) to consider it or not for
+ * the focusing
  */
-void EnggDiffractionPresenter::doFocusRun(const std::string &dir,
-                                          const std::string &outFilename,
-                                          const std::string &runNo, int bank) {
-  g_log.notice() << "Generating new focused file (bank " +
-                        boost::lexical_cast<std::string>(bank) + ") for run " +
-                        runNo + " into: "
-                 << outFilename << std::endl;
+void EnggDiffractionPresenter::doFocusRun(
+    const std::string &dir, const std::vector<std::string> &outFilenames,
+    const std::string &runNo, const std::vector<bool> &banks) {
+  g_log.notice() << "Generating new focusing workspace(s) and file(s) "
+                 << std::endl;
 
   Poco::Path fpath(dir);
-  const std::string fullFilename = fpath.append(outFilename).toString();
 
   // TODO: this is almost 100% common with doNewCalibrate() - refactor
   EnggDiffCalibSettings cs = m_view->currentCalibSettings();
@@ -660,18 +822,30 @@ void EnggDiffractionPresenter::doFocusRun(const std::string &dir,
     conf.appendDataSearchDir(cs.m_inputDirRaw);
   }
 
-  try {
-    doFocusing(cs, fullFilename, runNo, bank);
-    m_focusFinishedOK = true;
-  } catch (std::runtime_error &) {
-    g_log.error() << "The focusing calculations failed. One of the algorithms"
-                     "did not execute correctly. See log messages for details."
-                  << std::endl;
-  } catch (std::invalid_argument &ia) {
-    g_log.error()
-        << "The focusing failed. Some input properties were not valid. "
-           "See log messages for details. Error: "
-        << ia.what() << std::endl;
+  // focus all requested banks
+  for (size_t bidx = 0; bidx < banks.size(); bidx++) {
+    if (!banks[bidx])
+      continue;
+
+    const std::string fullFilename =
+        fpath.append(outFilenames[bidx]).toString();
+    g_log.notice() << "Generating new focused file (bank " +
+                          boost::lexical_cast<std::string>(bidx + 1) +
+                          ") for run " + runNo +
+                          " into: " << outFilenames[bidx] << std::endl;
+    try {
+      doFocusing(cs, fullFilename, runNo, bidx + 1);
+      m_focusFinishedOK = true;
+    } catch (std::runtime_error &) {
+      g_log.error()
+          << "The focusing calculations failed. One of the algorithms"
+             "did not execute correctly. See log messages for details."
+          << std::endl;
+    } catch (std::invalid_argument &ia) {
+      g_log.error()
+          << "The focusing failed. Some input properties were not valid. "
+             "See log messages for details. Error: " << ia.what() << std::endl;
+    }
   }
 
   // restore initial data search paths
@@ -707,13 +881,14 @@ void EnggDiffractionPresenter::focusingFinished() {
  * @param cs user settings for calibration (this does not calibrate but
  * uses calibration input files such as vanadium runs
  *
- * @param fullFilename full paht for the output (focused) filename
+ * @param fullFilename full path for the output (focused) filename
  * @param runNo input run to focus
  * @param bank instrument bank to focus
  */
 void EnggDiffractionPresenter::doFocusing(const EnggDiffCalibSettings &cs,
                                           const std::string &fullFilename,
-                                          const std::string &runNo, int bank) {
+                                          const std::string &runNo,
+                                          size_t bank) {
   ITableWorkspace_sptr vanIntegWS;
   MatrixWorkspace_sptr vanCurvesWS;
   MatrixWorkspace_sptr inWS;
@@ -833,8 +1008,7 @@ void EnggDiffractionPresenter::loadOrCalcVanadiumWorkspaces(
                        "This is possibly because some of the settings are not "
                        "consistent. Please check the log messages for "
                        "details. Details: " +
-                           std::string(ia.what())
-                    << std::endl;
+                           std::string(ia.what()) << std::endl;
       throw;
     } catch (std::runtime_error &re) {
       g_log.error() << "Failed to calculate Vanadium corrections. "
@@ -843,8 +1017,7 @@ void EnggDiffractionPresenter::loadOrCalcVanadiumWorkspaces(
                        "There was no obvious error in the input properties "
                        "but the algorithm failed. Please check the log "
                        "messages for details." +
-                           std::string(re.what())
-                    << std::endl;
+                           std::string(re.what()) << std::endl;
       throw;
     }
   } else {
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp
index 956e47f54fc..f80bbf9ab0c 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp
+++ b/Code/Mantid/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp
@@ -146,6 +146,15 @@ void EnggDiffractionViewQtGUI::doSetupTabSettings() {
 void EnggDiffractionViewQtGUI::doSetupTabFocus() {
   connect(m_uiTabFocus.pushButton_focus, SIGNAL(released()), this,
           SLOT(focusClicked()));
+
+  connect(m_uiTabFocus.pushButton_focus_cropped, SIGNAL(released()), this,
+          SLOT(focusCroppedClicked()));
+
+  connect(m_uiTabFocus.pushButton_focus_texture, SIGNAL(released()), this,
+          SLOT(focusTextureClicked()));
+
+  connect(m_uiTabFocus.pushButton_reset, SIGNAL(released()), this,
+          SLOT(focusResetClicked()));
 }
 
 void EnggDiffractionViewQtGUI::doSetupGeneralWidgets() {
@@ -340,20 +349,38 @@ void EnggDiffractionViewQtGUI::enableCalibrateAndFocusActions(bool enable) {
   m_uiTabFocus.lineEdit_run_num->setEnabled(enable);
   m_uiTabFocus.pushButton_focus->setEnabled(enable);
   m_uiTabFocus.checkBox_FocusedWS->setEnabled(enable);
+
+  m_uiTabFocus.pushButton_focus->setEnabled(enable);
+  m_uiTabFocus.pushButton_focus_cropped->setEnabled(enable);
+  m_uiTabFocus.pushButton_focus_texture->setEnabled(enable);
 }
 
 void EnggDiffractionViewQtGUI::plotFocusedSpectrum() {
   std::string pyCode = "plotSpectrum('engggui_focusing_output_ws', 0)";
 
-  std::string status = runPythonCode(QString::fromStdString(pyCode), false).toStdString();
-  m_logMsgs.push_back(
-      "Run Python code to save output file, with status string: " + status);
+  std::string status =
+      runPythonCode(QString::fromStdString(pyCode), false).toStdString();
+  m_logMsgs.push_back("Plotted output focused data, with status string " +
+                      status);
   m_presenter->notify(IEnggDiffractionPresenter::LogMsg);
 }
 
-void EnggDiffractionViewQtGUI::writeOutCalibFile(
-    const std::string &outFilename, const std::vector<double> &difc,
-    const std::vector<double> &tzero) {
+void EnggDiffractionViewQtGUI::resetFocus() {
+  m_uiTabFocus.lineEdit_run_num->setText("");
+  m_uiTabFocus.checkBox_focus_bank1->setChecked(true);
+  m_uiTabFocus.checkBox_focus_bank2->setChecked(true);
+
+  m_uiTabFocus.lineEdit_cropped_run_num->setText("");
+  m_uiTabFocus.lineEdit_cropped_spec_ids->setText("");
+
+  m_uiTabFocus.lineEdit_texture_run_num->setText("");
+  m_uiTabFocus.lineEdit_texture_grouping_file->setText("");
+}
+
+void
+EnggDiffractionViewQtGUI::writeOutCalibFile(const std::string &outFilename,
+                                            const std::vector<double> &difc,
+                                            const std::vector<double> &tzero) {
   // TODO: this is horrible and should not last much here.
   // Avoid running Python code
   // Update this as soon as we have a more stable way of generating IPARM files
@@ -421,6 +448,19 @@ void EnggDiffractionViewQtGUI::focusClicked() {
   m_presenter->notify(IEnggDiffractionPresenter::FocusRun);
 }
 
+void EnggDiffractionViewQtGUI::focusCroppedClicked() {
+  m_presenter->notify(IEnggDiffractionPresenter::FocusCropped);
+}
+
+void EnggDiffractionViewQtGUI::focusTextureClicked() {
+  m_presenter->notify(IEnggDiffractionPresenter::FocusTexture);
+}
+
+void EnggDiffractionViewQtGUI::focusResetClicked() {
+  m_presenter->notify(IEnggDiffractionPresenter::ResetFocus);
+  // TODO
+}
+
 void EnggDiffractionViewQtGUI::browseInputDirCalib() {
   QString prevPath = QString::fromStdString(m_calibSettings.m_inputDirCalib);
   if (prevPath.isEmpty()) {
@@ -521,13 +561,31 @@ std::string EnggDiffractionViewQtGUI::focusingRunNo() const {
   return m_uiTabFocus.lineEdit_run_num->text().toStdString();
 }
 
+std::string EnggDiffractionViewQtGUI::focusingCroppedRunNo() const {
+  return m_uiTabFocus.lineEdit_cropped_run_num->text().toStdString();
+}
+
+std::string EnggDiffractionViewQtGUI::focusingTextureRunNo() const {
+  return m_uiTabFocus.lineEdit_texture_run_num->text().toStdString();
+}
+
 std::string EnggDiffractionViewQtGUI::focusingDir() const {
   return m_uiTabSettings.lineEdit_dir_focusing->text().toStdString();
 }
 
-int EnggDiffractionViewQtGUI::focusingBank() const {
-  int idx = m_uiTabFocus.comboBox_bank_num->currentIndex();
-  return m_uiTabFocus.comboBox_bank_num->itemData(idx).toInt() + 1;
+std::vector<bool> EnggDiffractionViewQtGUI::focusingBanks() const {
+  std::vector<bool> res;
+  res.push_back(m_uiTabFocus.checkBox_focus_bank1->isChecked());
+  res.push_back(m_uiTabFocus.checkBox_focus_bank1->isChecked());
+  return res;
+}
+
+std::string EnggDiffractionViewQtGUI::focusingCroppedSpectrumIDs() const {
+  return m_uiTabFocus.lineEdit_cropped_spec_ids->text().toStdString();
+}
+
+std::string EnggDiffractionViewQtGUI::focusingTextureGroupingFile() const {
+  return m_uiTabFocus.lineEdit_texture_grouping_file->text().toStdString();
 }
 
 bool EnggDiffractionViewQtGUI::focusedOutWorkspace() const {
-- 
GitLab