diff --git a/qt/scientific_interfaces/Indirect/ConvFit.cpp b/qt/scientific_interfaces/Indirect/ConvFit.cpp
index ab3b816fc6eff0dbe4d26e9baa13b9c75d7e37e8..3eacac55992e4793438b3365952725ce7e9f32a8 100644
--- a/qt/scientific_interfaces/Indirect/ConvFit.cpp
+++ b/qt/scientific_interfaces/Indirect/ConvFit.cpp
@@ -6,6 +6,7 @@
 // SPDX - License - Identifier: GPL - 3.0 +
 #include "ConvFit.h"
 #include "ConvFitDataPresenter.h"
+#include "IndirectFunctionBrowser/ConvTemplateBrowser.h"
 
 #include "MantidQtWidgets/Common/UserInputValidator.h"
 
@@ -22,6 +23,10 @@
 #include <QDoubleValidator>
 #include <QMenu>
 
+#include <qwt_plot.h>
+#include <qwt_plot_curve.h>
+
+using namespace Mantid;
 using namespace Mantid::API;
 
 namespace {
@@ -33,23 +38,30 @@ namespace CustomInterfaces {
 namespace IDA {
 
 ConvFit::ConvFit(QWidget *parent)
-    : IndirectFitAnalysisTabLegacy(new ConvFitModel, parent),
+    : IndirectFitAnalysisTab(new ConvFitModel, parent),
       m_uiForm(new Ui::ConvFit) {
   m_uiForm->setupUi(parent);
   m_convFittingModel = dynamic_cast<ConvFitModel *>(fittingModel());
-
-  setFitDataPresenter(std::make_unique<ConvFitDataPresenter>(
-      m_convFittingModel, m_uiForm->fitDataView));
   setPlotView(m_uiForm->pvFitPlotView);
   setSpectrumSelectionView(m_uiForm->svSpectrumView);
   setOutputOptionsView(m_uiForm->ovOutputOptionsView);
+  m_uiForm->fitPropertyBrowser->setFunctionTemplateBrowser(
+      new ConvTemplateBrowser);
   setFitPropertyBrowser(m_uiForm->fitPropertyBrowser);
+  auto dataPresenter = std::make_unique<ConvFitDataPresenter>(
+      m_convFittingModel, m_uiForm->fitDataView);
+  connect(
+      dataPresenter.get(),
+      SIGNAL(modelResolutionAdded(std::string const &, DatasetIndex const &)),
+      this,
+      SLOT(setModelResolution(std::string const &, DatasetIndex const &)));
+  setFitDataPresenter(std::move(dataPresenter));
 
   setEditResultVisible(true);
 }
 
 void ConvFit::setupFitTab() {
-  setDefaultPeakType("Lorentzian");
+  // setDefaultPeakType("Lorentzian");
   setConvolveMembers(true);
 
   // Initialise fitTypeStrings
@@ -80,27 +92,27 @@ void ConvFit::setupFitTab() {
 
   auto deltaFunction = functionFactory.createFunction("DeltaFunction");
 
-  addCheckBoxFunctionGroup("Use Delta Function", {deltaFunction});
+  // addCheckBoxFunctionGroup("Use Delta Function", {deltaFunction});
 
-  addComboBoxFunctionGroup("One Lorentzian", {lorentzian});
-  addComboBoxFunctionGroup("Two Lorentzians", {lorentzian, lorentzian});
-  addComboBoxFunctionGroup("Teixeira Water", {teixeiraWater});
-  addComboBoxFunctionGroup("InelasticDiffSphere", {inelasticDiffSphere});
-  addComboBoxFunctionGroup("InelasticDiffRotDiscreteCircle",
-                           {inelasticDiffRotDiscCircle});
-  addComboBoxFunctionGroup("ElasticDiffSphere", {elasticDiffSphere});
-  addComboBoxFunctionGroup("ElasticDiffRotDiscreteCircle",
-                           {elasticDiffRotDiscCircle});
-  addComboBoxFunctionGroup("StretchedExpFT", {stretchedExpFT});
+  // addComboBoxFunctionGroup("One Lorentzian", {lorentzian});
+  // addComboBoxFunctionGroup("Two Lorentzians", {lorentzian, lorentzian});
+  // addComboBoxFunctionGroup("Teixeira Water", {teixeiraWater});
+  // addComboBoxFunctionGroup("InelasticDiffSphere", {inelasticDiffSphere});
+  // addComboBoxFunctionGroup("InelasticDiffRotDiscreteCircle",
+  //                         {inelasticDiffRotDiscCircle});
+  // addComboBoxFunctionGroup("ElasticDiffSphere", {elasticDiffSphere});
+  // addComboBoxFunctionGroup("ElasticDiffRotDiscreteCircle",
+  //                         {elasticDiffRotDiscCircle});
+  // addComboBoxFunctionGroup("StretchedExpFT", {stretchedExpFT});
 
-  // Set available background options
-  setBackgroundOptions({"None", "FlatBackground", "LinearBackground"});
+  //// Set available background options
+  // setBackgroundOptions({"None", "FlatBackground", "LinearBackground"});
 
-  addBoolCustomSetting("ExtractMembers", "Extract Members");
-  addOptionalDoubleSetting("TempCorrection", "Temp. Correction",
-                           "UseTempCorrection", "Use Temp. Correction");
-  setCustomSettingChangesFunction("TempCorrection", true);
-  setCustomSettingChangesFunction("UseTempCorrection", true);
+  // addBoolCustomSetting("ExtractMembers", "Extract Members");
+  // addOptionalDoubleSetting("TempCorrection", "Temp. Correction",
+  //                         "UseTempCorrection", "Use Temp. Correction");
+  // setCustomSettingChangesFunction("TempCorrection", true);
+  // setCustomSettingChangesFunction("UseTempCorrection", true);
 
   // Instrument resolution
   m_properties["InstrumentResolution"] =
@@ -112,20 +124,33 @@ void ConvFit::setupFitTab() {
 }
 
 void ConvFit::setupFit(Mantid::API::IAlgorithm_sptr fitAlgorithm) {
-  if (boolSettingValue("UseTempCorrection"))
-    m_convFittingModel->setTemperature(doubleSettingValue("TempCorrection"));
-  else
-    m_convFittingModel->setTemperature(boost::none);
-  fitAlgorithm->setProperty("ExtractMembers",
-                            boolSettingValue("ExtractMembers"));
-  IndirectFitAnalysisTabLegacy::setupFit(fitAlgorithm);
+  // if (boolSettingValue("UseTempCorrection"))
+  //  m_convFittingModel->setTemperature(doubleSettingValue("TempCorrection"));
+  // else
+  //  m_convFittingModel->setTemperature(boost::none);
+  // fitAlgorithm->setProperty("ExtractMembers",
+  //                          boolSettingValue("ExtractMembers"));
+  IndirectFitAnalysisTab::setupFit(fitAlgorithm);
+}
+
+EstimationDataSelector ConvFit::getEstimationDataSelector() const {
+  return
+      [](const MantidVec &, const MantidVec &) -> DataForParameterEstimation {
+        return DataForParameterEstimation{};
+      };
+}
+
+void ConvFit::setModelResolution(const std::string &resolutionName) {
+  setModelResolution(resolutionName, DatasetIndex{0});
 }
 
-void ConvFit::setModelResolution(const QString &resolutionName) {
-  const auto name = resolutionName.toStdString();
+void ConvFit::setModelResolution(const std::string &resolutionName,
+                                 DatasetIndex index) {
   const auto resolution =
-      AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(name);
-  m_convFittingModel->setResolution(resolution, 0);
+      AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+          resolutionName);
+  m_convFittingModel->setResolution(resolution, index);
+  m_uiForm->fitPropertyBrowser->setModelResolution(resolutionName, index);
   setModelFitFunction();
 }
 
diff --git a/qt/scientific_interfaces/Indirect/ConvFit.h b/qt/scientific_interfaces/Indirect/ConvFit.h
index 9caa438a6171e383309a34b40efec981951b670b..0fcd325f75ca43e175bd4348bc23292aeb909db9 100644
--- a/qt/scientific_interfaces/Indirect/ConvFit.h
+++ b/qt/scientific_interfaces/Indirect/ConvFit.h
@@ -8,8 +8,9 @@
 #define MANTIDQTCUSTOMINTERFACESIDA_CONVFIT_H_
 
 #include "ConvFitModel.h"
-#include "IndirectFitAnalysisTabLegacy.h"
-#include "IndirectSpectrumSelectionPresenterLegacy.h"
+#include "IndirectFitAnalysisTab.h"
+#include "IndirectSpectrumSelectionPresenter.h"
+#include "ParameterEstimation.h"
 
 #include "MantidAPI/CompositeFunction.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
@@ -18,7 +19,7 @@
 namespace MantidQt {
 namespace CustomInterfaces {
 namespace IDA {
-class DLLExport ConvFit : public IndirectFitAnalysisTabLegacy {
+class DLLExport ConvFit : public IndirectFitAnalysisTab {
   Q_OBJECT
 
 public:
@@ -29,7 +30,9 @@ public:
   bool hasResolution() const override { return true; }
 
 protected slots:
-  void setModelResolution(const QString &resolutionName);
+  void setModelResolution(const std::string &resolutionName);
+  void setModelResolution(const std::string &resolutionName,
+                          DatasetIndex index);
   void runClicked();
   void fitFunctionChanged();
 
@@ -40,6 +43,7 @@ protected:
 private:
   void setupFitTab() override;
   void setupFit(Mantid::API::IAlgorithm_sptr fitAlgorithm) override;
+  EstimationDataSelector getEstimationDataSelector() const override;
 
   std::string fitTypeString() const;
 
diff --git a/qt/scientific_interfaces/Indirect/ConvFit.ui b/qt/scientific_interfaces/Indirect/ConvFit.ui
index 58fc9dbe4d5c2d37990814d4b768d1ec17042b98..87e1da640fc769c6ce4e9fe267388e445a630edf 100644
--- a/qt/scientific_interfaces/Indirect/ConvFit.ui
+++ b/qt/scientific_interfaces/Indirect/ConvFit.ui
@@ -22,7 +22,7 @@
      <property name="childrenCollapsible">
       <bool>false</bool>
      </property>
-     <widget class="MantidQt::CustomInterfaces::IDA::IndirectFitDataViewLegacy" name="fitDataView" native="true">
+     <widget class="MantidQt::CustomInterfaces::IDA::IndirectFitDataView" name="fitDataView" native="true">
       <property name="minimumSize">
        <size>
         <width>0</width>
@@ -38,12 +38,12 @@
           <enum>QLayout::SetNoConstraint</enum>
          </property>
          <item>
-          <widget class="MantidQt::MantidWidgets::IndirectFitPropertyBrowserLegacy" name="fitPropertyBrowser">
+          <widget class="MantidQt::CustomInterfaces::IDA::IndirectFitPropertyBrowser" name="fitPropertyBrowser">
            <widget class="QWidget" name="dockWidgetContents_2"/>
           </widget>
          </item>
          <item>
-          <widget class="MantidQt::CustomInterfaces::IDA::IndirectFitPlotViewLegacy" name="pvFitPlotView" native="true"/>
+          <widget class="MantidQt::CustomInterfaces::IDA::IndirectFitPlotView" name="pvFitPlotView" native="true"/>
          </item>
         </layout>
        </item>
@@ -71,7 +71,7 @@
              <number>0</number>
             </property>
             <item>
-             <widget class="MantidQt::CustomInterfaces::IDA::IndirectSpectrumSelectionViewLegacy" name="svSpectrumView" native="true">
+             <widget class="MantidQt::CustomInterfaces::IDA::IndirectSpectrumSelectionView" name="svSpectrumView" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
                 <horstretch>1</horstretch>
@@ -150,27 +150,27 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::CustomInterfaces::IDA::IndirectSpectrumSelectionViewLegacy</class>
+   <class>MantidQt::CustomInterfaces::IDA::IndirectSpectrumSelectionView</class>
    <extends>QWidget</extends>
-   <header>IndirectSpectrumSelectionViewLegacy.h</header>
+   <header>IndirectSpectrumSelectionView.h</header>
    <container>1</container>
   </customwidget>
   <customwidget>
-   <class>MantidQt::MantidWidgets::IndirectFitPropertyBrowserLegacy</class>
+   <class>MantidQt::CustomInterfaces::IDA::IndirectFitPropertyBrowser</class>
    <extends>QDockWidget</extends>
-   <header>MantidQtWidgets/Common/IndirectFitPropertyBrowserLegacy.h</header>
+   <header>IndirectFitPropertyBrowser.h</header>
    <container>1</container>
   </customwidget>
   <customwidget>
-   <class>MantidQt::CustomInterfaces::IDA::IndirectFitPlotViewLegacy</class>
+   <class>MantidQt::CustomInterfaces::IDA::IndirectFitPlotView</class>
    <extends>QWidget</extends>
-   <header>IndirectFitPlotViewLegacy.h</header>
+   <header>IndirectFitPlotView.h</header>
    <container>1</container>
   </customwidget>
   <customwidget>
-   <class>MantidQt::CustomInterfaces::IDA::IndirectFitDataViewLegacy</class>
+   <class>MantidQt::CustomInterfaces::IDA::IndirectFitDataView</class>
    <extends>QWidget</extends>
-   <header>IndirectFitDataViewLegacy.h</header>
+   <header>IndirectFitDataView.h</header>
    <container>1</container>
   </customwidget>
   <customwidget>
diff --git a/qt/scientific_interfaces/Indirect/ConvFitAddWorkspaceDialog.ui b/qt/scientific_interfaces/Indirect/ConvFitAddWorkspaceDialog.ui
index a0a25e0a49091019764c39e960d363c52259d962..602567fff90348a59e4f43ae38bc14d97ebb45d3 100644
--- a/qt/scientific_interfaces/Indirect/ConvFitAddWorkspaceDialog.ui
+++ b/qt/scientific_interfaces/Indirect/ConvFitAddWorkspaceDialog.ui
@@ -100,16 +100,7 @@
    <item>
     <widget class="QFrame" name="frame">
      <layout class="QHBoxLayout" name="horizontalLayout">
-      <property name="leftMargin">
-       <number>0</number>
-      </property>
-      <property name="topMargin">
-       <number>0</number>
-      </property>
-      <property name="rightMargin">
-       <number>0</number>
-      </property>
-      <property name="bottomMargin">
+      <property name="margin">
        <number>0</number>
       </property>
       <item>
@@ -152,40 +143,7 @@
   </customwidget>
  </customwidgets>
  <resources/>
- <connections>
-  <connection>
-   <sender>pbAdd</sender>
-   <signal>clicked()</signal>
-   <receiver>ConvFitAddWorkspaceDialog</receiver>
-   <slot>addData()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>276</x>
-     <y>160</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>269</x>
-     <y>319</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>pbClose</sender>
-   <signal>clicked()</signal>
-   <receiver>ConvFitAddWorkspaceDialog</receiver>
-   <slot>closeDialog()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>340</x>
-     <y>171</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>335</x>
-     <y>251</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
+ <connections/>
  <slots>
   <slot>addData()</slot>
   <slot>closeDialog()</slot>
diff --git a/qt/scientific_interfaces/Indirect/ConvFitDataPresenter.cpp b/qt/scientific_interfaces/Indirect/ConvFitDataPresenter.cpp
index 045f78b0462f9d4632cc4acbdfa4195d54d9a6c3..ba5647328188f8e12f7d1b556e610c6f70c18755 100644
--- a/qt/scientific_interfaces/Indirect/ConvFitDataPresenter.cpp
+++ b/qt/scientific_interfaces/Indirect/ConvFitDataPresenter.cpp
@@ -24,11 +24,10 @@ namespace CustomInterfaces {
 namespace IDA {
 
 ConvFitDataPresenter::ConvFitDataPresenter(ConvFitModel *model,
-                                           IIndirectFitDataViewLegacy *view)
-    : IndirectFitDataPresenterLegacy(
-          model, view,
-          std::make_unique<ConvFitDataTablePresenter>(model,
-                                                      view->getDataTable())),
+                                           IIndirectFitDataView *view)
+    : IndirectFitDataPresenter(model, view,
+                               std::make_unique<ConvFitDataTablePresenter>(
+                                   model, view->getDataTable())),
       m_convModel(model) {
   setResolutionHidden(false);
 
@@ -40,15 +39,17 @@ ConvFitDataPresenter::ConvFitDataPresenter(ConvFitModel *model,
 
 void ConvFitDataPresenter::setModelResolution(const QString &name) {
   auto const workspaceCount = m_convModel->numberOfWorkspaces();
-  auto const index =
-      m_convModel->getWorkspace(0) ? workspaceCount - 1 : workspaceCount;
+  auto const index = m_convModel->getWorkspace(DatasetIndex{0})
+                         ? workspaceCount - DatasetIndex{1}
+                         : workspaceCount;
   setModelResolution(name.toStdString(), index);
 }
 
 void ConvFitDataPresenter::setModelResolution(std::string const &name,
-                                              std::size_t const &index) {
+                                              DatasetIndex const &index) {
   try {
     m_convModel->setResolution(name, index);
+    emit modelResolutionAdded(name, index);
   } catch (std::exception const &ex) {
     displayWarning(ex.what());
   }
@@ -58,21 +59,26 @@ void ConvFitDataPresenter::addDataToModel(IAddWorkspaceDialog const *dialog) {
   if (const auto convDialog =
           dynamic_cast<ConvFitAddWorkspaceDialog const *>(dialog)) {
     addWorkspace(convDialog, m_convModel);
-    m_convModel->setResolution(convDialog->resolutionName(),
-                               m_convModel->numberOfWorkspaces() - 1);
+    auto const name = convDialog->resolutionName();
+    auto const index = m_convModel->numberOfWorkspaces() - DatasetIndex{1};
+    m_convModel->setResolution(name, index);
+    emit modelResolutionAdded(name, index);
   }
 }
 
 void ConvFitDataPresenter::addWorkspace(ConvFitAddWorkspaceDialog const *dialog,
-                                        IndirectFittingModelLegacy *model) {
+                                        IndirectFittingModel *model) {
   model->addWorkspace(dialog->workspaceName(), dialog->workspaceIndices());
 }
 
 void ConvFitDataPresenter::addModelData(const std::string &name) {
-  IndirectFitDataPresenterLegacy::addModelData(name);
+  IndirectFitDataPresenter::addModelData(name);
   const auto resolution = getView()->getSelectedResolution();
-  if (!resolution.empty() && isWorkspaceLoaded(resolution))
-    m_convModel->setResolution(resolution, 0);
+  if (!resolution.empty() && isWorkspaceLoaded(resolution)) {
+    auto const index = DatasetIndex{0};
+    m_convModel->setResolution(resolution, index);
+    emit modelResolutionAdded(resolution, index);
+  }
 }
 
 std::unique_ptr<IAddWorkspaceDialog>
diff --git a/qt/scientific_interfaces/Indirect/ConvFitDataPresenter.h b/qt/scientific_interfaces/Indirect/ConvFitDataPresenter.h
index 744a5f0239b4ae5557e94e9f9061e883fbe640b1..526397afafdd45d317fa069a795c5127491df07b 100644
--- a/qt/scientific_interfaces/Indirect/ConvFitDataPresenter.h
+++ b/qt/scientific_interfaces/Indirect/ConvFitDataPresenter.h
@@ -8,7 +8,7 @@
 #define MANTIDQTCUSTOMINTERFACESIDA_CONVFITDATAPRESENTER_H_
 
 #include "ConvFitModel.h"
-#include "IndirectFitDataPresenterLegacy.h"
+#include "IndirectFitDataPresenter.h"
 
 namespace MantidQt {
 namespace CustomInterfaces {
@@ -17,10 +17,13 @@ namespace IDA {
 class ConvFitAddWorkspaceDialog;
 
 class MANTIDQT_INDIRECT_DLL ConvFitDataPresenter
-    : public IndirectFitDataPresenterLegacy {
+    : public IndirectFitDataPresenter {
   Q_OBJECT
 public:
-  ConvFitDataPresenter(ConvFitModel *model, IIndirectFitDataViewLegacy *view);
+  ConvFitDataPresenter(ConvFitModel *model, IIndirectFitDataView *view);
+
+signals:
+  void modelResolutionAdded(std::string const &name, DatasetIndex const &index);
 
 private slots:
   void setModelResolution(const QString &name);
@@ -29,12 +32,12 @@ protected:
   void addModelData(const std::string &name) override;
 
 private:
-  void setModelResolution(std::string const &name, std::size_t const &index);
+  void setModelResolution(std::string const &name, DatasetIndex const &index);
   void addDataToModel(IAddWorkspaceDialog const *dialog) override;
   std::unique_ptr<IAddWorkspaceDialog>
   getAddWorkspaceDialog(QWidget *parent) const override;
   void addWorkspace(ConvFitAddWorkspaceDialog const *dialog,
-                    IndirectFittingModelLegacy *model);
+                    IndirectFittingModel *model);
 
   void setMultiInputResolutionFBSuffixes(IAddWorkspaceDialog *dialog) override;
   void setMultiInputResolutionWSSuffixes(IAddWorkspaceDialog *dialog) override;
diff --git a/qt/scientific_interfaces/Indirect/ConvFitDataTablePresenter.cpp b/qt/scientific_interfaces/Indirect/ConvFitDataTablePresenter.cpp
index e0d489873ca51f541ea6a34f4611eecce27e4685..d31727338e4ef08bb4b868debcf37606af41bb9f 100644
--- a/qt/scientific_interfaces/Indirect/ConvFitDataTablePresenter.cpp
+++ b/qt/scientific_interfaces/Indirect/ConvFitDataTablePresenter.cpp
@@ -28,14 +28,10 @@ namespace IDA {
 
 ConvFitDataTablePresenter::ConvFitDataTablePresenter(ConvFitModel *model,
                                                      QTableWidget *dataTable)
-    : IndirectDataTablePresenterLegacy(model, dataTable, convFitHeaders()),
+    : IndirectDataTablePresenter(model, dataTable, convFitHeaders()),
       m_convFitModel(model) {
   auto header = dataTable->horizontalHeader();
-#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
   header->setResizeMode(1, QHeaderView::Stretch);
-#elif QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
-  header->setSectionResizeMode(1, QHeaderView::Stretch);
-#endif
 }
 
 int ConvFitDataTablePresenter::workspaceIndexColumn() const { return 2; }
@@ -46,13 +42,15 @@ int ConvFitDataTablePresenter::endXColumn() const { return 4; }
 
 int ConvFitDataTablePresenter::excludeColumn() const { return 5; }
 
-std::string ConvFitDataTablePresenter::getResolutionName(int row) const {
+std::string
+ConvFitDataTablePresenter::getResolutionName(SpectrumRowIndex row) const {
   return getString(row, 1);
 }
 
-void ConvFitDataTablePresenter::addTableEntry(std::size_t dataIndex,
-                                              std::size_t spectrum, int row) {
-  IndirectDataTablePresenterLegacy::addTableEntry(dataIndex, spectrum, row);
+void ConvFitDataTablePresenter::addTableEntry(DatasetIndex dataIndex,
+                                              WorkspaceIndex spectrum,
+                                              SpectrumRowIndex row) {
+  IndirectDataTablePresenter::addTableEntry(dataIndex, spectrum, row);
 
   const auto resolution = m_convFitModel->getResolution(dataIndex);
   const auto name = resolution ? resolution->getName() : "";
@@ -63,10 +61,10 @@ void ConvFitDataTablePresenter::addTableEntry(std::size_t dataIndex,
   setCell(std::move(cell), row, 1);
 }
 
-void ConvFitDataTablePresenter::updateTableEntry(std::size_t dataIndex,
-                                                 std::size_t spectrum,
-                                                 int row) {
-  IndirectDataTablePresenterLegacy::updateTableEntry(dataIndex, spectrum, row);
+void ConvFitDataTablePresenter::updateTableEntry(DatasetIndex dataIndex,
+                                                 WorkspaceIndex spectrum,
+                                                 SpectrumRowIndex row) {
+  IndirectDataTablePresenter::updateTableEntry(dataIndex, spectrum, row);
 
   const auto &name = m_convFitModel->getResolution(dataIndex)->getName();
   setCellText(QString::fromStdString(name), row, 1);
diff --git a/qt/scientific_interfaces/Indirect/ConvFitDataTablePresenter.h b/qt/scientific_interfaces/Indirect/ConvFitDataTablePresenter.h
index 1baf7f0b9c405862f0a8751b9f2d4ca8f10d1a7f..11c35bce64b65e07a4902131d019c288df13aa8a 100644
--- a/qt/scientific_interfaces/Indirect/ConvFitDataTablePresenter.h
+++ b/qt/scientific_interfaces/Indirect/ConvFitDataTablePresenter.h
@@ -8,7 +8,7 @@
 #define MANTIDQTCUSTOMINTERFACES_CONVFITDATATABLEPRESENTER_H_
 
 #include "ConvFitModel.h"
-#include "IndirectDataTablePresenterLegacy.h"
+#include "IndirectDataTablePresenter.h"
 
 #include <QTableWidget>
 
@@ -22,24 +22,23 @@ namespace IDA {
 /**
   Presenter for a table of convolution fitting data.
 */
-class DLLExport ConvFitDataTablePresenter
-    : public IndirectDataTablePresenterLegacy {
+class DLLExport ConvFitDataTablePresenter : public IndirectDataTablePresenter {
   Q_OBJECT
 public:
   ConvFitDataTablePresenter(ConvFitModel *model, QTableWidget *dataTable);
 
 protected:
-  void addTableEntry(std::size_t dataIndex, std::size_t spectrum,
-                     int row) override;
-  void updateTableEntry(std::size_t dataIndex, std::size_t spectrum,
-                        int row) override;
+  void addTableEntry(DatasetIndex dataIndex, WorkspaceIndex spectrum,
+                     SpectrumRowIndex row) override;
+  void updateTableEntry(DatasetIndex dataIndex, WorkspaceIndex spectrum,
+                        SpectrumRowIndex row) override;
 
 private:
   int workspaceIndexColumn() const override;
   int startXColumn() const override;
   int endXColumn() const override;
   int excludeColumn() const override;
-  std::string getResolutionName(int row) const;
+  std::string getResolutionName(SpectrumRowIndex row) const;
 
   ConvFitModel *m_convFitModel;
 };
diff --git a/qt/scientific_interfaces/Indirect/ConvFitModel.cpp b/qt/scientific_interfaces/Indirect/ConvFitModel.cpp
index d1b88ccdfc16b9ee6c6b24ee43144915cd7576ca..e1d17e4de6306a1dcf80585ea35aab8f9e93dc91 100644
--- a/qt/scientific_interfaces/Indirect/ConvFitModel.cpp
+++ b/qt/scientific_interfaces/Indirect/ConvFitModel.cpp
@@ -7,8 +7,8 @@
 #include "ConvFitModel.h"
 
 #include "MantidAPI/AlgorithmManager.h"
-#include "MantidAPI/CompositeFunction.h"
 #include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/MultiDomainFunction.h"
 #include "MantidGeometry/Instrument.h"
 
 #include <boost/algorithm/string/join.hpp>
@@ -28,96 +28,96 @@ bool doesExistInADS(std::string const &workspaceName) {
   return AnalysisDataService::Instance().doesExist(workspaceName);
 }
 
-boost::optional<std::size_t>
-getFirstInCategory(CompositeFunction_const_sptr composite,
-                   const std::string &category) {
-  if (!composite)
-    return boost::none;
-
-  for (auto i = 0u; i < composite->nFunctions(); ++i) {
-    if (composite->getFunction(i)->category() == category)
-      return i;
-  }
-  return boost::none;
-}
-
-IFunction_sptr removeFunction(CompositeFunction_sptr composite,
-                              std::size_t index) {
-  auto function = composite->getFunction(index);
-  composite->removeFunction(index);
-  return function;
-}
-
-CompositeFunction_sptr shallowCopy(CompositeFunction_sptr composite) {
-  CompositeFunction_sptr copy(new CompositeFunction);
-  for (auto i = 0u; i < composite->nFunctions(); ++i)
-    copy->addFunction(composite->getFunction(i));
-  copy->addTies(composite->writeTies());
-  return copy;
-}
-
-IFunction_sptr shallowCopy(IFunction_sptr function) {
-  auto composite = boost::dynamic_pointer_cast<CompositeFunction>(function);
-  if (composite)
-    return shallowCopy(composite);
-  return function;
-}
-
-IFunction_sptr createResolutionFunction(const std::string &resolutionName) {
-  auto func = FunctionFactory::Instance().createFunction("Resolution");
-  // add resolution file
-  IFunction::Attribute attr(resolutionName);
-  func->setAttribute("Workspace", attr);
-  return func;
-}
-
-CompositeFunction_sptr applyTemperatureCorrection(IFunction_sptr function,
-                                                  IFunction_sptr correction,
-                                                  double value) {
-  auto product = boost::dynamic_pointer_cast<CompositeFunction>(
-      FunctionFactory::Instance().createFunction("ProductFunction"));
-  product->addFunction(correction);
-  product->addFunction(function);
-  product->tie("f0.Temp", std::to_string(value));
-  product->applyTies();
-  return product;
-}
-
-IFunction_sptr createTemperatureCorrection(double correction) {
-  // create temperature correction function to multiply with the lorentzians
-  IFunction_sptr tempFunc;
-
-  // create user function for the exponential correction
-  // (x*temp) / 1-exp(-(x*temp))
-  tempFunc = FunctionFactory::Instance().createFunction("UserFunction");
-  // 11.606 is the conversion factor from meV to K
-  std::string formula = "((x*11.606)/Temp) / (1 - exp(-((x*11.606)/Temp)))";
-  IFunction::Attribute att(formula);
-  tempFunc->setAttribute("Formula", att);
-  tempFunc->setParameter("Temp", correction);
-  return tempFunc;
-}
-
-CompositeFunction_sptr addTemperatureCorrection(CompositeFunction_sptr model,
-                                                double value) {
-  auto correction = createTemperatureCorrection(value);
-
-  for (auto i = 0u; i < model->nFunctions(); ++i) {
-    auto function = model->getFunction(i);
-
-    if (function->name() != "DeltaFunction") {
-      auto corrected = applyTemperatureCorrection(function, correction, value);
-      model->replaceFunction(i, corrected);
-    }
-  }
-  return model;
-}
-
-CompositeFunction_sptr addTemperatureCorrection(IFunction_sptr model,
-                                                double value) {
-  auto correction = createTemperatureCorrection(value);
-  return applyTemperatureCorrection(model, correction, value);
-}
+// boost::optional<std::size_t>
+// getFirstInCategory(CompositeFunction_const_sptr composite,
+//                   const std::string &category) {
+//  if (!composite)
+//    return boost::none;
+//
+//  for (auto i = 0u; i < composite->nFunctions(); ++i) {
+//    if (composite->getFunction(i)->category() == category)
+//      return i;
+//  }
+//  return boost::none;
+//}
+
+// IFunction_sptr removeFunction(CompositeFunction_sptr composite,
+//                              std::size_t index) {
+//  auto function = composite->getFunction(index);
+//  composite->removeFunction(index);
+//  return function;
+//}
+
+// CompositeFunction_sptr shallowCopy(CompositeFunction_sptr composite) {
+//  CompositeFunction_sptr copy(new CompositeFunction);
+//  for (auto i = 0u; i < composite->nFunctions(); ++i)
+//    copy->addFunction(composite->getFunction(i));
+//  copy->addTies(composite->writeTies());
+//  return copy;
+//}
+//
+// IFunction_sptr shallowCopy(IFunction_sptr function) {
+//  auto composite = boost::dynamic_pointer_cast<CompositeFunction>(function);
+//  if (composite)
+//    return shallowCopy(composite);
+//  return function;
+//}
+
+// IFunction_sptr createResolutionFunction(const std::string &resolutionName) {
+//  auto func = FunctionFactory::Instance().createFunction("Resolution");
+//  // add resolution file
+//  IFunction::Attribute attr(resolutionName);
+//  func->setAttribute("Workspace", attr);
+//  return func;
+//}
+
+// CompositeFunction_sptr applyTemperatureCorrection(IFunction_sptr function,
+//                                                  IFunction_sptr correction,
+//                                                  double value) {
+//  auto product = boost::dynamic_pointer_cast<CompositeFunction>(
+//      FunctionFactory::Instance().createFunction("ProductFunction"));
+//  product->addFunction(correction);
+//  product->addFunction(function);
+//  product->tie("f0.Temp", std::to_string(value));
+//  product->applyTies();
+//  return product;
+//}
+
+// IFunction_sptr createTemperatureCorrection(double correction) {
+//  // create temperature correction function to multiply with the lorentzians
+//  IFunction_sptr tempFunc;
+//
+//  // create user function for the exponential correction
+//  // (x*temp) / 1-exp(-(x*temp))
+//  tempFunc = FunctionFactory::Instance().createFunction("UserFunction");
+//  // 11.606 is the conversion factor from meV to K
+//  std::string formula = "((x*11.606)/Temp) / (1 - exp(-((x*11.606)/Temp)))";
+//  IFunction::Attribute att(formula);
+//  tempFunc->setAttribute("Formula", att);
+//  tempFunc->setParameter("Temp", correction);
+//  return tempFunc;
+//}
+
+// CompositeFunction_sptr addTemperatureCorrection(CompositeFunction_sptr model,
+//                                                double value) {
+//  auto correction = createTemperatureCorrection(value);
+//
+//  for (auto i = 0u; i < model->nFunctions(); ++i) {
+//    auto function = model->getFunction(i);
+//
+//    if (function->name() != "DeltaFunction") {
+//      auto corrected = applyTemperatureCorrection(function, correction,
+//      value); model->replaceFunction(i, corrected);
+//    }
+//  }
+//  return model;
+//}
+//
+// CompositeFunction_sptr addTemperatureCorrection(IFunction_sptr model,
+//                                                double value) {
+//  auto correction = createTemperatureCorrection(value);
+//  return applyTemperatureCorrection(model, correction, value);
+//}
 
 IAlgorithm_sptr loadParameterFileAlgorithm(std::string const &workspaceName,
                                            std::string const &filename) {
@@ -376,10 +376,10 @@ private:
 };
 
 std::vector<std::string>
-getNames(const std::vector<boost::weak_ptr<Mantid::API::MatrixWorkspace>>
+getNames(const MantidQt::CustomInterfaces::IDA::ResolutionCollectionType
              &workspaces) {
   std::vector<std::string> names;
-  names.reserve(workspaces.size());
+  names.reserve(workspaces.size().value);
   std::transform(workspaces.begin(), workspaces.end(),
                  std::back_inserter(names),
                  [](boost::weak_ptr<Mantid::API::MatrixWorkspace> workspace) {
@@ -388,53 +388,55 @@ getNames(const std::vector<boost::weak_ptr<Mantid::API::MatrixWorkspace>>
   return names;
 }
 
-std::string backgroundString(IFunction_sptr function) {
-  const auto functionName = function->name();
-
-  if (functionName == "FlatBackground") {
-    if (function->isFixed(0))
-      return "FixF";
-    return "FitF";
-  } else if (functionName == "LinearBackground")
-    return "FitL";
-  return "";
-}
-
-IFunction_sptr createConvolutionFitModel(IFunction_sptr model,
-                                         IFunction_sptr background,
-                                         boost::optional<double> temperature) {
-  CompositeFunction_sptr comp(new CompositeFunction);
-
-  if (!(model &&
-        AnalysisDataService::Instance().doesExist("__ConvFitResolution0")))
-    return model ? model : comp;
-
-  if (auto compModel = boost::dynamic_pointer_cast<CompositeFunction>(model)) {
-    if (compModel->nFunctions() == 1) {
-      model = compModel->getFunction(0);
-    }
-  }
-
-  auto conv = boost::dynamic_pointer_cast<CompositeFunction>(
-      FunctionFactory::Instance().createFunction("Convolution"));
-  conv->addFunction(createResolutionFunction("__ConvFitResolution0"));
-
-  if (temperature) {
-    auto compositeModel = boost::dynamic_pointer_cast<CompositeFunction>(model);
-    if (compositeModel)
-      model = addTemperatureCorrection(compositeModel, *temperature);
-    else
-      model = addTemperatureCorrection(model, *temperature);
-  }
-  conv->addFunction(model);
-
-  if (background) {
-    comp->addFunction(background);
-    comp->addFunction(conv);
-  } else
-    comp = conv;
-  return comp;
-}
+// std::string backgroundString(IFunction_sptr function) {
+//  const auto functionName = function->name();
+//
+//  if (functionName == "FlatBackground") {
+//    if (function->isFixed(0))
+//      return "FixF";
+//    return "FitF";
+//  } else if (functionName == "LinearBackground")
+//    return "FitL";
+//  return "";
+//}
+
+// IFunction_sptr createConvolutionFitModel(IFunction_sptr model,
+//                                         IFunction_sptr background,
+//                                         boost::optional<double> temperature)
+//                                         {
+//  CompositeFunction_sptr comp(new CompositeFunction);
+//
+//  if (!(model &&
+//        AnalysisDataService::Instance().doesExist("__ConvFitResolution0")))
+//    return model ? model : comp;
+//
+//  if (auto compModel = boost::dynamic_pointer_cast<CompositeFunction>(model))
+//  {
+//    if (compModel->nFunctions() == 1) {
+//      model = compModel->getFunction(0);
+//    }
+//  }
+//
+//  auto conv = boost::dynamic_pointer_cast<CompositeFunction>(
+//      FunctionFactory::Instance().createFunction("Convolution"));
+//  conv->addFunction(createResolutionFunction("__ConvFitResolution0"));
+//
+//  if (temperature) {
+//    auto compositeModel =
+//    boost::dynamic_pointer_cast<CompositeFunction>(model); if (compositeModel)
+//      model = addTemperatureCorrection(compositeModel, *temperature);
+//    else
+//      model = addTemperatureCorrection(model, *temperature);
+//  }
+//  conv->addFunction(model);
+//
+//  if (background) {
+//    comp->addFunction(background);
+//    comp->addFunction(conv);
+//  } else
+//    comp = conv;
+//  return comp;
+//}
 
 void setResolutionAttribute(CompositeFunction_sptr convolutionModel,
                             const IFunction::Attribute &attr) {
@@ -470,50 +472,52 @@ IAlgorithm_sptr ConvFitModel::simultaneousFitAlgorithm() const {
 std::string ConvFitModel::sequentialFitOutputName() const {
   if (isMultiFit())
     return "MultiConvFit_" + m_fitType + m_backgroundString + "_Results";
-  return createOutputName(
-      "%1%_conv_" + m_fitType + m_backgroundString + "_s%2%", "_to_", 0);
+  return createOutputName("%1%_conv_" + m_fitType + m_backgroundString +
+                              "_s%2%",
+                          "_to_", DatasetIndex{0});
 }
 
 std::string ConvFitModel::simultaneousFitOutputName() const {
   return sequentialFitOutputName();
 }
 
-std::string ConvFitModel::singleFitOutputName(std::size_t index,
-                                              std::size_t spectrum) const {
+std::string ConvFitModel::singleFitOutputName(DatasetIndex index,
+                                              WorkspaceIndex spectrum) const {
   return createSingleFitOutputName("%1%_conv_" + m_fitType +
                                        m_backgroundString + "_s%2%_Results",
                                    index, spectrum);
 }
 
-Mantid::API::IFunction_sptr ConvFitModel::getFittingFunction() const {
-  auto function = shallowCopy(IndirectFittingModelLegacy::getFittingFunction());
-  auto composite = boost::dynamic_pointer_cast<CompositeFunction>(function);
+Mantid::API::MultiDomainFunction_sptr ConvFitModel::getFittingFunction() const {
+  // auto function = shallowCopy(IndirectFittingModel::getFittingFunction());
+  // auto composite = boost::dynamic_pointer_cast<CompositeFunction>(function);
 
-  IFunction_sptr background(nullptr);
-  if (composite && m_backgroundIndex)
-    background = removeFunction(composite, *m_backgroundIndex);
-  return createConvolutionFitModel(function, background, m_temperature);
+  // IFunction_sptr background(nullptr);
+  // if (composite && m_backgroundIndex)
+  //  background = removeFunction(composite, *m_backgroundIndex);
+  // return createConvolutionFitModel(function, background, m_temperature);
+  return IndirectFittingModel::getFittingFunction();
 }
 
 boost::optional<double>
-ConvFitModel::getInstrumentResolution(std::size_t dataIndex) const {
+ConvFitModel::getInstrumentResolution(DatasetIndex dataIndex) const {
   if (dataIndex < numberOfWorkspaces())
     return instrumentResolution(getWorkspace(dataIndex));
   return boost::none;
 }
 
-std::size_t ConvFitModel::getNumberHistograms(std::size_t index) const {
+std::size_t ConvFitModel::getNumberHistograms(DatasetIndex index) const {
   return getWorkspace(index)->getNumberHistograms();
 }
 
-MatrixWorkspace_sptr ConvFitModel::getResolution(std::size_t index) const {
+MatrixWorkspace_sptr ConvFitModel::getResolution(DatasetIndex index) const {
   if (index < m_resolution.size())
     return m_resolution[index].lock();
   return nullptr;
 }
 
-CompositeFunction_sptr ConvFitModel::getMultiDomainFunction() const {
-  auto function = IndirectFittingModelLegacy::getMultiDomainFunction();
+MultiDomainFunction_sptr ConvFitModel::getMultiDomainFunction() const {
+  auto function = IndirectFittingModel::getMultiDomainFunction();
   const std::string base = "__ConvFitResolution";
 
   for (auto i = 0u; i < function->nFunctions(); ++i)
@@ -528,18 +532,18 @@ std::vector<std::string> ConvFitModel::getSpectrumDependentAttributes() const {
   return {"WorkspaceIndex"};
 }
 
-void ConvFitModel::setFitFunction(IFunction_sptr function) {
-  auto const composite =
-      boost::dynamic_pointer_cast<CompositeFunction>(function);
-  m_backgroundIndex = getFirstInCategory(composite, "Background");
-  setParameterNameChanges(*function, m_backgroundIndex);
+void ConvFitModel::setFitFunction(MultiDomainFunction_sptr function) {
+  // auto const composite =
+  //    boost::dynamic_pointer_cast<CompositeFunction>(function);
+  // m_backgroundIndex = getFirstInCategory(composite, "Background");
+  // setParameterNameChanges(*function, m_backgroundIndex);
 
-  IFunction_sptr background(nullptr);
-  if (composite && m_backgroundIndex)
-    background = composite->getFunction(*m_backgroundIndex);
-  m_backgroundString = background ? backgroundString(background) : "";
+  // IFunction_sptr background(nullptr);
+  // if (composite && m_backgroundIndex)
+  //  background = composite->getFunction(*m_backgroundIndex);
+  // m_backgroundString = background ? backgroundString(background) : "";
 
-  IndirectFittingModelLegacy::setFitFunction(function);
+  IndirectFittingModel::setFitFunction(function);
 }
 
 void ConvFitModel::setTemperature(const boost::optional<double> &temperature) {
@@ -547,32 +551,32 @@ void ConvFitModel::setTemperature(const boost::optional<double> &temperature) {
 }
 
 void ConvFitModel::addWorkspace(MatrixWorkspace_sptr workspace,
-                                const SpectraLegacy &spectra) {
-  IndirectFittingModelLegacy::addWorkspace(workspace, spectra);
+                                const Spectra &spectra) {
+  IndirectFittingModel::addWorkspace(workspace, spectra);
 
   const auto dataSize = numberOfWorkspaces();
   if (m_resolution.size() < dataSize)
     m_resolution.emplace_back(MatrixWorkspace_sptr());
   else if (m_resolution.size() == dataSize &&
-           m_resolution[dataSize - 1].lock() &&
+           m_resolution[dataSize - DatasetIndex{1}].lock() &&
            m_extendedResolution.size() < dataSize)
-    addExtendedResolution(dataSize - 1);
+    addExtendedResolution(dataSize - DatasetIndex{1});
 }
 
-void ConvFitModel::removeWorkspace(std::size_t index) {
-  IndirectFittingModelLegacy::removeWorkspace(index);
+void ConvFitModel::removeWorkspace(DatasetIndex index) {
+  IndirectFittingModel::removeWorkspace(index);
 
   const auto newSize = numberOfWorkspaces();
   while (m_resolution.size() > newSize)
-    m_resolution.erase(m_resolution.begin() + index);
+    m_resolution.remove(index);
 
   while (m_extendedResolution.size() > newSize) {
     AnalysisDataService::Instance().remove(m_extendedResolution[index]);
-    m_extendedResolution.erase(m_extendedResolution.begin() + index);
+    m_extendedResolution.remove(index);
   }
 }
 
-void ConvFitModel::setResolution(const std::string &name, std::size_t index) {
+void ConvFitModel::setResolution(const std::string &name, DatasetIndex index) {
   if (!name.empty() && doesExistInADS(name))
     setResolution(getADSMatrixWorkspace(name), index);
   else
@@ -580,21 +584,22 @@ void ConvFitModel::setResolution(const std::string &name, std::size_t index) {
 }
 
 void ConvFitModel::setResolution(MatrixWorkspace_sptr resolution,
-                                 std::size_t index) {
+                                 DatasetIndex index) {
   if (m_resolution.size() > index)
     m_resolution[index] = resolution;
   else if (m_resolution.size() == index)
     m_resolution.emplace_back(resolution);
   else
     throw std::out_of_range("Provided resolution index '" +
-                            std::to_string(index) + "' was out of range.");
+                            std::to_string(index.value) +
+                            "' was out of range.");
 
   if (numberOfWorkspaces() > index)
     addExtendedResolution(index);
 }
 
-void ConvFitModel::addExtendedResolution(std::size_t index) {
-  const std::string name = "__ConvFitResolution" + std::to_string(index);
+void ConvFitModel::addExtendedResolution(DatasetIndex index) {
+  const std::string name = "__ConvFitResolution" + std::to_string(index.value);
 
   extendResolutionWorkspace(m_resolution[index].lock(),
                             getNumberHistograms(index), name);
@@ -609,31 +614,30 @@ void ConvFitModel::setFitTypeString(const std::string &fitType) {
   m_fitType = fitType;
 }
 
-std::unordered_map<std::string, ParameterValueLegacy>
-ConvFitModel::createDefaultParameters(std::size_t index) const {
-  std::unordered_map<std::string, ParameterValueLegacy> defaultValues;
-  defaultValues["PeakCentre"] = ParameterValueLegacy(0.0);
-  defaultValues["Centre"] = ParameterValueLegacy(0.0);
+std::unordered_map<std::string, ParameterValue>
+ConvFitModel::createDefaultParameters(DatasetIndex index) const {
+  std::unordered_map<std::string, ParameterValue> defaultValues;
+  defaultValues["PeakCentre"] = ParameterValue(0.0);
+  defaultValues["Centre"] = ParameterValue(0.0);
   // Reset all parameters to default of 1
-  defaultValues["Amplitude"] = ParameterValueLegacy(1.0);
-  defaultValues["beta"] = ParameterValueLegacy(1.0);
-  defaultValues["Decay"] = ParameterValueLegacy(1.0);
-  defaultValues["Diffusion"] = ParameterValueLegacy(1.0);
-  defaultValues["Height"] = ParameterValueLegacy(1.0);
-  defaultValues["Intensity"] = ParameterValueLegacy(1.0);
-  defaultValues["Radius"] = ParameterValueLegacy(1.0);
-  defaultValues["Tau"] = ParameterValueLegacy(1.0);
+  defaultValues["Amplitude"] = ParameterValue(1.0);
+  defaultValues["beta"] = ParameterValue(1.0);
+  defaultValues["Decay"] = ParameterValue(1.0);
+  defaultValues["Diffusion"] = ParameterValue(1.0);
+  defaultValues["Height"] = ParameterValue(1.0);
+  defaultValues["Intensity"] = ParameterValue(1.0);
+  defaultValues["Radius"] = ParameterValue(1.0);
+  defaultValues["Tau"] = ParameterValue(1.0);
 
   auto resolution = getInstrumentResolution(index);
   if (resolution)
-    defaultValues["FWHM"] = ParameterValueLegacy(*resolution);
+    defaultValues["FWHM"] = ParameterValue(*resolution);
   return defaultValues;
 }
 
 std::unordered_map<std::string, std::string>
 ConvFitModel::mapDefaultParameterNames() const {
-  const auto initialMapping =
-      IndirectFittingModelLegacy::mapDefaultParameterNames();
+  const auto initialMapping = IndirectFittingModel::mapDefaultParameterNames();
   std::unordered_map<std::string, std::string> mapping;
   for (const auto &map : initialMapping) {
     auto mapped = m_parameterNameChanges.find(map.second);
@@ -657,53 +661,51 @@ void ConvFitModel::addSampleLogs() {
   }
 }
 
-IndirectFitOutputLegacy
-ConvFitModel::createFitOutput(WorkspaceGroup_sptr resultGroup,
-                              ITableWorkspace_sptr parameterTable,
-                              WorkspaceGroup_sptr resultWorkspace,
-                              const FitDataIteratorLegacy &fitDataBegin,
-                              const FitDataIteratorLegacy &fitDataEnd) const {
-  auto output = IndirectFitOutputLegacy(
-      resultGroup, parameterTable, resultWorkspace, fitDataBegin, fitDataEnd);
+IndirectFitOutput ConvFitModel::createFitOutput(
+    WorkspaceGroup_sptr resultGroup, ITableWorkspace_sptr parameterTable,
+    WorkspaceGroup_sptr resultWorkspace, const FitDataIterator &fitDataBegin,
+    const FitDataIterator &fitDataEnd) const {
+  auto output = IndirectFitOutput(resultGroup, parameterTable, resultWorkspace,
+                                  fitDataBegin, fitDataEnd);
   output.mapParameterNames(m_parameterNameChanges, fitDataBegin, fitDataEnd);
   return output;
 }
 
-IndirectFitOutputLegacy
+IndirectFitOutput
 ConvFitModel::createFitOutput(Mantid::API::WorkspaceGroup_sptr resultGroup,
                               Mantid::API::ITableWorkspace_sptr parameterTable,
                               Mantid::API::WorkspaceGroup_sptr resultWorkspace,
-                              IndirectFitDataLegacy *fitData,
-                              std::size_t spectrum) const {
-  auto output = IndirectFitOutputLegacy(resultGroup, parameterTable,
-                                        resultWorkspace, fitData, spectrum);
+                              IndirectFitData *fitData,
+                              WorkspaceIndex spectrum) const {
+  auto output = IndirectFitOutput(resultGroup, parameterTable, resultWorkspace,
+                                  fitData, spectrum);
   output.mapParameterNames(m_parameterNameChanges, fitData, spectrum);
   return output;
 }
 
 void ConvFitModel::addOutput(Mantid::API::IAlgorithm_sptr fitAlgorithm) {
-  IndirectFittingModelLegacy::addOutput(fitAlgorithm);
+  IndirectFittingModel::addOutput(fitAlgorithm);
   addSampleLogs();
 }
 
-void ConvFitModel::addOutput(IndirectFitOutputLegacy *fitOutput,
+void ConvFitModel::addOutput(IndirectFitOutput *fitOutput,
                              WorkspaceGroup_sptr resultGroup,
                              ITableWorkspace_sptr parameterTable,
                              WorkspaceGroup_sptr resultWorkspace,
-                             const FitDataIteratorLegacy &fitDataBegin,
-                             const FitDataIteratorLegacy &fitDataEnd) const {
+                             const FitDataIterator &fitDataBegin,
+                             const FitDataIterator &fitDataEnd) const {
   fitOutput->addOutput(resultGroup, parameterTable, resultWorkspace,
                        fitDataBegin, fitDataEnd);
   fitOutput->mapParameterNames(m_parameterNameChanges, fitDataBegin,
                                fitDataEnd);
 }
 
-void ConvFitModel::addOutput(IndirectFitOutputLegacy *fitOutput,
+void ConvFitModel::addOutput(IndirectFitOutput *fitOutput,
                              WorkspaceGroup_sptr resultGroup,
                              ITableWorkspace_sptr parameterTable,
                              WorkspaceGroup_sptr resultWorkspace,
-                             IndirectFitDataLegacy *fitData,
-                             std::size_t spectrum) const {
+                             IndirectFitData *fitData,
+                             WorkspaceIndex spectrum) const {
   fitOutput->addOutput(resultGroup, parameterTable, resultWorkspace, fitData,
                        spectrum);
   fitOutput->mapParameterNames(m_parameterNameChanges, fitData, spectrum);
diff --git a/qt/scientific_interfaces/Indirect/ConvFitModel.h b/qt/scientific_interfaces/Indirect/ConvFitModel.h
index 3502ed51d7e6eb3edef7aa57a379fd079db787a7..bdd62f81a287cc88c2a84f0dbe84c4f5caf8cfda 100644
--- a/qt/scientific_interfaces/Indirect/ConvFitModel.h
+++ b/qt/scientific_interfaces/Indirect/ConvFitModel.h
@@ -7,35 +7,40 @@
 #ifndef MANTIDQTCUSTOMINTERFACESIDA_CONVFITMODEL_H_
 #define MANTIDQTCUSTOMINTERFACESIDA_CONVFITMODEL_H_
 
-#include "IndirectFittingModelLegacy.h"
+#include "IndirectFittingModel.h"
 
 namespace MantidQt {
 namespace CustomInterfaces {
 namespace IDA {
 
-class DLLExport ConvFitModel : public IndirectFittingModelLegacy {
+using ResolutionCollectionType =
+    IndexCollectionType<DatasetIndex,
+                        boost::weak_ptr<Mantid::API::MatrixWorkspace>>;
+using ExtendedResolutionType = IndexCollectionType<DatasetIndex, std::string>;
+
+class DLLExport ConvFitModel : public IndirectFittingModel {
 public:
-  using IndirectFittingModelLegacy::addWorkspace;
+  using IndirectFittingModel::addWorkspace;
 
   ConvFitModel();
   ~ConvFitModel() override;
 
-  Mantid::API::IFunction_sptr getFittingFunction() const override;
-  boost::optional<double> getInstrumentResolution(std::size_t dataIndex) const;
-  std::size_t getNumberHistograms(std::size_t index) const;
-  Mantid::API::MatrixWorkspace_sptr getResolution(std::size_t index) const;
+  Mantid::API::MultiDomainFunction_sptr getFittingFunction() const override;
+  boost::optional<double> getInstrumentResolution(DatasetIndex dataIndex) const;
+  std::size_t getNumberHistograms(DatasetIndex index) const;
+  Mantid::API::MatrixWorkspace_sptr getResolution(DatasetIndex index) const;
 
   std::vector<std::string> getSpectrumDependentAttributes() const override;
 
-  void setFitFunction(Mantid::API::IFunction_sptr function) override;
+  void setFitFunction(Mantid::API::MultiDomainFunction_sptr function) override;
   void setTemperature(const boost::optional<double> &temperature);
 
   void addWorkspace(Mantid::API::MatrixWorkspace_sptr workspace,
-                    const SpectraLegacy &spectra) override;
-  void removeWorkspace(std::size_t index) override;
-  void setResolution(const std::string &name, std::size_t index);
+                    const Spectra &spectra) override;
+  void removeWorkspace(DatasetIndex index) override;
+  void setResolution(const std::string &name, DatasetIndex index);
   void setResolution(Mantid::API::MatrixWorkspace_sptr resolution,
-                     std::size_t index);
+                     DatasetIndex index);
   void setFitTypeString(const std::string &fitType);
 
   void addOutput(Mantid::API::IAlgorithm_sptr fitAlgorithm) override;
@@ -45,47 +50,47 @@ private:
   Mantid::API::IAlgorithm_sptr simultaneousFitAlgorithm() const override;
   std::string sequentialFitOutputName() const override;
   std::string simultaneousFitOutputName() const override;
-  std::string singleFitOutputName(std::size_t index,
-                                  std::size_t spectrum) const override;
-  Mantid::API::CompositeFunction_sptr getMultiDomainFunction() const override;
-  std::unordered_map<std::string, ParameterValueLegacy>
-  createDefaultParameters(std::size_t index) const override;
+  std::string singleFitOutputName(DatasetIndex index,
+                                  WorkspaceIndex spectrum) const override;
+  Mantid::API::MultiDomainFunction_sptr getMultiDomainFunction() const override;
+  std::unordered_map<std::string, ParameterValue>
+  createDefaultParameters(DatasetIndex index) const override;
   std::unordered_map<std::string, std::string>
   mapDefaultParameterNames() const override;
 
-  IndirectFitOutputLegacy
+  IndirectFitOutput
   createFitOutput(Mantid::API::WorkspaceGroup_sptr resultGroup,
                   Mantid::API::ITableWorkspace_sptr parameterTable,
                   Mantid::API::WorkspaceGroup_sptr resultWorkspace,
-                  const FitDataIteratorLegacy &fitDataBegin,
-                  const FitDataIteratorLegacy &fitDataEnd) const override;
-  IndirectFitOutputLegacy
+                  const FitDataIterator &fitDataBegin,
+                  const FitDataIterator &fitDataEnd) const override;
+  IndirectFitOutput
   createFitOutput(Mantid::API::WorkspaceGroup_sptr resultGroup,
                   Mantid::API::ITableWorkspace_sptr parameterTable,
                   Mantid::API::WorkspaceGroup_sptr resultWorkspace,
-                  IndirectFitDataLegacy *fitData,
-                  std::size_t spectrum) const override;
+                  IndirectFitData *fitData,
+                  WorkspaceIndex spectrum) const override;
 
-  void addOutput(IndirectFitOutputLegacy *fitOutput,
+  void addOutput(IndirectFitOutput *fitOutput,
                  Mantid::API::WorkspaceGroup_sptr resultGroup,
                  Mantid::API::ITableWorkspace_sptr parameterTable,
                  Mantid::API::WorkspaceGroup_sptr resultWorkspace,
-                 const FitDataIteratorLegacy &fitDataBegin,
-                 const FitDataIteratorLegacy &fitDataEnd) const override;
-  void addOutput(IndirectFitOutputLegacy *fitOutput,
+                 const FitDataIterator &fitDataBegin,
+                 const FitDataIterator &fitDataEnd) const override;
+  void addOutput(IndirectFitOutput *fitOutput,
                  Mantid::API::WorkspaceGroup_sptr resultGroup,
                  Mantid::API::ITableWorkspace_sptr parameterTable,
                  Mantid::API::WorkspaceGroup_sptr resultWorkspace,
-                 IndirectFitDataLegacy *fitData,
-                 std::size_t spectrum) const override;
-  void addExtendedResolution(std::size_t index);
+                 IndirectFitData *fitData,
+                 WorkspaceIndex spectrum) const override;
+  void addExtendedResolution(DatasetIndex index);
   void addSampleLogs();
 
   void setParameterNameChanges(const Mantid::API::IFunction &model,
                                boost::optional<std::size_t> backgroundIndex);
 
-  std::vector<boost::weak_ptr<Mantid::API::MatrixWorkspace>> m_resolution;
-  std::vector<std::string> m_extendedResolution;
+  ResolutionCollectionType m_resolution;
+  ExtendedResolutionType m_extendedResolution;
   std::unordered_map<std::string, std::string> m_parameterNameChanges;
   boost::optional<double> m_temperature;
   boost::optional<std::size_t> m_backgroundIndex;
diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f331fff9f2db98be5f2653312bfd7a1a2ad28b2c
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp
@@ -0,0 +1,604 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#include "ConvFunctionModel.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/IFunction.h"
+#include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/MultiDomainFunction.h"
+#include "MantidQtWidgets/Common/FunctionBrowser/FunctionBrowserUtils.h"
+#include <map>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+namespace IDA {
+
+using namespace MantidWidgets;
+using namespace Mantid::API;
+
+namespace {}
+
+ConvFunctionModel::ConvFunctionModel() {}
+
+void ConvFunctionModel::clearData() {
+  m_fitType = FitType::None;
+  m_hasDeltaFunction = false;
+  m_backgroundType = BackgroundType::None;
+  m_model.clear();
+}
+
+void ConvFunctionModel::setModel() {
+  m_model.setModel(buildBackgroundFunctionString(), m_resolutionName,
+                   m_resolutionIndex.value, buildPeaksFunctionString(),
+                   m_hasDeltaFunction);
+  m_model.setGlobalParameters(makeGlobalList());
+}
+
+void ConvFunctionModel::setFunction(IFunction_sptr fun) {
+  clearData();
+  if (!fun)
+    return;
+  if (fun->nFunctions() == 0) {
+    auto const name = fun->name();
+    if (name == "Lorentzian") {
+      m_fitType = FitType::OneLorentzian;
+    } else if (name == "DeltaFunction") {
+      m_hasDeltaFunction = true;
+    } else if (name == "FlatBackground") {
+      m_backgroundType = BackgroundType::Flat;
+    } else if (name == "LinearBackground") {
+      m_backgroundType = BackgroundType::Linear;
+    } else {
+      throw std::runtime_error("Cannot set function " + name);
+    }
+    m_model.setFunction(fun);
+    return;
+  }
+  bool isFitTypeSet = false;
+  int numberLorentzians = 0;
+  bool isBackgroundSet = false;
+  for (size_t i = 0; i < fun->nFunctions(); ++i) {
+    auto f = fun->getFunction(i);
+    auto const name = f->name();
+    if (name == "Lorentzian") {
+      if (isFitTypeSet) {
+        throw std::runtime_error("Function has wrong structure.");
+      }
+      if (numberLorentzians == 0) {
+        numberLorentzians = 1;
+      } else {
+        numberLorentzians = 2;
+        isFitTypeSet = true;
+      }
+    } else if (name == "DeltaFunction") {
+      if (m_hasDeltaFunction || isBackgroundSet) {
+        throw std::runtime_error("Function has wrong structure.");
+      }
+      m_hasDeltaFunction = true;
+      isFitTypeSet = true;
+    } else if (isBackgroundSet) {
+      throw std::runtime_error("Function has wrong structure.");
+    } else if (name == "FlatBackground") {
+      m_backgroundType = BackgroundType::Flat;
+      isFitTypeSet = true;
+      isBackgroundSet = true;
+    } else if (name == "LinearBackground") {
+      m_backgroundType = BackgroundType::Linear;
+      isFitTypeSet = true;
+      isBackgroundSet = true;
+    } else {
+      clear();
+      throw std::runtime_error("Function has wrong structure.");
+    }
+  }
+  m_model.setFunction(fun);
+}
+
+IFunction_sptr ConvFunctionModel::getFitFunction() const {
+  return m_model.getFitFunction();
+}
+
+bool ConvFunctionModel::hasFunction() const { return m_model.hasFunction(); }
+
+void ConvFunctionModel::addFunction(const QString &prefix,
+                                    const QString &funStr) {
+  if (!prefix.isEmpty())
+    throw std::runtime_error(
+        "Function doesn't have member function with prefix " +
+        prefix.toStdString());
+  auto fun =
+      FunctionFactory::Instance().createInitialized(funStr.toStdString());
+  auto const name = fun->name();
+  QString newPrefix;
+  if (name == "Lorentzian") {
+    if (m_fitType == FitType::TwoLorentzians) {
+      throw std::runtime_error("Cannot add more Lorentzians.");
+    } else if (m_fitType == FitType::OneLorentzian) {
+      m_fitType = FitType::TwoLorentzians;
+      newPrefix = *getLor2Prefix();
+    } else if (m_fitType == FitType::None) {
+      m_fitType = FitType::OneLorentzian;
+      newPrefix = *getLor1Prefix();
+    } else {
+      throw std::runtime_error("Cannot add more Lorentzians.");
+    }
+  } else if (name == "DeltaFunction") {
+    if (m_hasDeltaFunction)
+      throw std::runtime_error("Cannot add a DeltaFunction.");
+    setDeltaFunction(true);
+    newPrefix = *getDeltaPrefix();
+  } else if (name == "FlatBackground" || name == "LinearBackground") {
+    if (hasBackground())
+      throw std::runtime_error("Cannot add more backgrounds.");
+    if (name == "FlatBackground") {
+      setBackground(BackgroundType::Flat);
+    } else if (name == "LinearBackground") {
+      setBackground(BackgroundType::Linear);
+    }
+    newPrefix = *getBackgroundPrefix();
+  } else {
+    throw std::runtime_error("Cannot add funtion " + name);
+  }
+  auto newFun = getFunctionWithPrefix(newPrefix, getSingleFunction(0));
+  copyParametersAndErrors(*fun, *newFun);
+  if (getNumberLocalFunctions() > 1) {
+    copyParametersAndErrorsToAllLocalFunctions(*getSingleFunction(0));
+  }
+}
+
+void ConvFunctionModel::removeFunction(const QString &prefix) {
+  if (prefix.isEmpty()) {
+    clear();
+    return;
+  }
+  auto prefix1 = getLor1Prefix();
+  if (prefix1 && *prefix1 == prefix) {
+    setFitType(FitType::None);
+    return;
+  }
+  prefix1 = getLor2Prefix();
+  if (prefix1 && *prefix1 == prefix) {
+    setFitType(FitType::OneLorentzian);
+    return;
+  }
+  prefix1 = getDeltaPrefix();
+  if (prefix1 && *prefix1 == prefix) {
+    setDeltaFunction(false);
+    return;
+  }
+  prefix1 = getBackgroundPrefix();
+  if (prefix1 && *prefix1 == prefix) {
+    removeBackground();
+    return;
+  }
+  throw std::runtime_error(
+      "Function doesn't have member function with prefix " +
+      prefix.toStdString());
+}
+
+void ConvFunctionModel::setDeltaFunction(bool on) {
+  auto oldValues = getCurrentValues();
+  m_hasDeltaFunction = on;
+  setModel();
+  setCurrentValues(oldValues);
+}
+
+bool ConvFunctionModel::hasDeltaFunction() const { return m_hasDeltaFunction; }
+
+void ConvFunctionModel::setBackground(BackgroundType bgType) {
+  auto oldValues = getCurrentValues();
+  m_backgroundType = bgType;
+  setModel();
+  setCurrentValues(oldValues);
+}
+
+void ConvFunctionModel::removeBackground() {
+  auto oldValues = getCurrentValues();
+  m_backgroundType = BackgroundType::None;
+  setModel();
+  setCurrentValues(oldValues);
+}
+
+bool ConvFunctionModel::hasBackground() const {
+  return m_backgroundType != BackgroundType::None;
+}
+
+void ConvFunctionModel::updateParameterEstimationData(
+    DataForParameterEstimationCollection &&data) {
+  m_estimationData = std::move(data);
+}
+
+void ConvFunctionModel::setResolution(std::string const &name,
+                                      DatasetIndex const &index) {
+  m_resolutionName = name;
+  m_resolutionIndex = index;
+  setModel();
+}
+
+QString ConvFunctionModel::setBackgroundA0(double value) {
+  if (hasBackground()) {
+    auto const paramID = (m_backgroundType == BackgroundType::Flat)
+                             ? ParamID::FLAT_BG_A0
+                             : ParamID::LINEAR_BG_A0;
+    setParameter(paramID, value);
+    return *getParameterName(paramID);
+  }
+  return "";
+}
+
+void ConvFunctionModel::setNumberDomains(int n) { m_model.setNumberDomains(n); }
+
+int ConvFunctionModel::getNumberDomains() const {
+  return m_model.getNumberDomains();
+}
+
+void ConvFunctionModel::setParameter(const QString &paramName, double value) {
+  m_model.setParameter(paramName, value);
+}
+
+void ConvFunctionModel::setParameterError(const QString &paramName,
+                                          double value) {
+  m_model.setParameterError(paramName, value);
+}
+
+double ConvFunctionModel::getParameter(const QString &paramName) const {
+  return m_model.getParameter(paramName);
+}
+
+double ConvFunctionModel::getParameterError(const QString &paramName) const {
+  return m_model.getParameterError(paramName);
+}
+
+QString
+ConvFunctionModel::getParameterDescription(const QString &paramName) const {
+  return m_model.getParameterDescription(paramName);
+}
+
+QStringList ConvFunctionModel::getParameterNames() const {
+  return m_model.getParameterNames();
+}
+
+IFunction_sptr ConvFunctionModel::getSingleFunction(int index) const {
+  return m_model.getSingleFunction(index);
+}
+
+IFunction_sptr ConvFunctionModel::getCurrentFunction() const {
+  return m_model.getCurrentFunction();
+}
+
+QStringList ConvFunctionModel::getGlobalParameters() const {
+  return m_model.getGlobalParameters();
+}
+
+QStringList ConvFunctionModel::getLocalParameters() const {
+  return m_model.getLocalParameters();
+}
+
+void ConvFunctionModel::setGlobalParameters(const QStringList &globals) {
+  m_globals.clear();
+  for (auto const &name : globals) {
+    addGlobal(name);
+  }
+  auto newGlobals = makeGlobalList();
+  m_model.setGlobalParameters(newGlobals);
+}
+
+bool ConvFunctionModel::isGlobal(const QString &parName) const {
+  return m_model.isGlobal(parName);
+}
+
+void ConvFunctionModel::setGlobal(const QString &parName, bool on) {
+  if (parName.isEmpty())
+    return;
+  if (on)
+    addGlobal(parName);
+  else
+    removeGlobal(parName);
+  auto globals = makeGlobalList();
+  m_model.setGlobalParameters(globals);
+}
+
+void ConvFunctionModel::addGlobal(const QString &parName) {
+  auto const pid = getParameterId(parName);
+  if (pid && !m_globals.contains(*pid)) {
+    m_globals.push_back(*pid);
+  }
+}
+
+void ConvFunctionModel::removeGlobal(const QString &parName) {
+  auto const pid = getParameterId(parName);
+  if (pid && m_globals.contains(*pid)) {
+    m_globals.removeOne(*pid);
+  }
+}
+
+QStringList ConvFunctionModel::makeGlobalList() const {
+  QStringList globals;
+  for (auto const id : m_globals) {
+    auto const name = getParameterName(id);
+    if (name)
+      globals << *name;
+  }
+  return globals;
+}
+
+void ConvFunctionModel::setFitType(FitType fitType) {
+  auto oldValues = getCurrentValues();
+  m_fitType = fitType;
+  setModel();
+  setCurrentValues(oldValues);
+}
+
+int ConvFunctionModel::getNumberOfPeaks() const {
+  if (m_fitType == FitType::None)
+    return 0;
+  if (m_fitType == FitType::TwoLorentzians)
+    return 2;
+  return 1;
+}
+
+void ConvFunctionModel::updateMultiDatasetParameters(const IFunction &fun) {
+  m_model.updateMultiDatasetParameters(fun);
+}
+
+void ConvFunctionModel::updateMultiDatasetParameters(
+    const ITableWorkspace &paramTable) {
+  auto const nRows = paramTable.rowCount();
+  if (nRows == 0)
+    return;
+
+  auto const globalParameterNames = getGlobalParameters();
+  for (auto &&name : globalParameterNames) {
+    auto valueColumn = paramTable.getColumn((name).toStdString());
+    auto errorColumn = paramTable.getColumn((name + "_Err").toStdString());
+    m_model.setParameter(name, valueColumn->toDouble(0));
+    m_model.setParameterError(name, errorColumn->toDouble(0));
+  }
+
+  auto const localParameterNames = getLocalParameters();
+  for (auto &&name : localParameterNames) {
+    auto valueColumn = paramTable.getColumn((name).toStdString());
+    auto errorColumn = paramTable.getColumn((name + "_Err").toStdString());
+    if (nRows > 1) {
+      for (size_t i = 0; i < nRows; ++i) {
+        m_model.setLocalParameterValue(name, static_cast<int>(i),
+                                       valueColumn->toDouble(i),
+                                       errorColumn->toDouble(i));
+      }
+    } else {
+      auto const i = m_model.currentDomainIndex();
+      m_model.setLocalParameterValue(name, static_cast<int>(i),
+                                     valueColumn->toDouble(0),
+                                     errorColumn->toDouble(0));
+    }
+  }
+}
+
+void ConvFunctionModel::updateParameters(const IFunction &fun) {
+  m_model.updateParameters(fun);
+}
+
+void ConvFunctionModel::setCurrentDomainIndex(int i) {
+  m_model.setCurrentDomainIndex(i);
+}
+
+int ConvFunctionModel::currentDomainIndex() const {
+  return m_model.currentDomainIndex();
+}
+
+void ConvFunctionModel::changeTie(const QString &paramName,
+                                  const QString &tie) {
+  m_model.changeTie(paramName, tie);
+}
+
+void ConvFunctionModel::addConstraint(const QString &functionIndex,
+                                      const QString &constraint) {
+  m_model.addConstraint(functionIndex, constraint);
+}
+
+void ConvFunctionModel::removeConstraint(const QString &paramName) {
+  m_model.removeConstraint(paramName);
+}
+
+void ConvFunctionModel::setDatasetNames(const QStringList &names) {
+  m_model.setDatasetNames(names);
+}
+
+QStringList ConvFunctionModel::getDatasetNames() const {
+  return m_model.getDatasetNames();
+}
+
+double ConvFunctionModel::getLocalParameterValue(const QString &parName,
+                                                 int i) const {
+  return m_model.getLocalParameterValue(parName, i);
+}
+
+bool ConvFunctionModel::isLocalParameterFixed(const QString &parName,
+                                              int i) const {
+  return m_model.isLocalParameterFixed(parName, i);
+}
+
+QString ConvFunctionModel::getLocalParameterTie(const QString &parName,
+                                                int i) const {
+  return m_model.getLocalParameterTie(parName, i);
+}
+
+QString ConvFunctionModel::getLocalParameterConstraint(const QString &parName,
+                                                       int i) const {
+  return m_model.getLocalParameterConstraint(parName, i);
+}
+
+void ConvFunctionModel::setLocalParameterValue(const QString &parName, int i,
+                                               double value) {
+  m_model.setLocalParameterValue(parName, i, value);
+}
+
+void ConvFunctionModel::setLocalParameterValue(const QString &parName, int i,
+                                               double value, double error) {
+  m_model.setLocalParameterValue(parName, i, value, error);
+}
+
+void ConvFunctionModel::setLocalParameterTie(const QString &parName, int i,
+                                             const QString &tie) {
+  m_model.setLocalParameterTie(parName, i, tie);
+}
+
+void ConvFunctionModel::setLocalParameterConstraint(const QString &parName,
+                                                    int i,
+                                                    const QString &constraint) {
+  m_model.setLocalParameterConstraint(parName, i, constraint);
+}
+
+void ConvFunctionModel::setLocalParameterFixed(const QString &parName, int i,
+                                               bool fixed) {
+  m_model.setLocalParameterFixed(parName, i, fixed);
+}
+
+void ConvFunctionModel::setParameter(ParamID name, double value) {
+  auto const prefix = getPrefix(name);
+  if (prefix) {
+    m_model.setParameter(*prefix + paramName(name), value);
+  }
+}
+
+boost::optional<double> ConvFunctionModel::getParameter(ParamID name) const {
+  auto const paramName = getParameterName(name);
+  return paramName ? m_model.getParameter(*paramName)
+                   : boost::optional<double>();
+}
+
+boost::optional<double>
+ConvFunctionModel::getParameterError(ParamID name) const {
+  auto const paramName = getParameterName(name);
+  return paramName ? m_model.getParameterError(*paramName)
+                   : boost::optional<double>();
+}
+
+boost::optional<QString>
+ConvFunctionModel::getParameterName(ParamID name) const {
+  auto const prefix = getPrefix(name);
+  return prefix ? *prefix + paramName(name) : boost::optional<QString>();
+}
+
+boost::optional<QString>
+ConvFunctionModel::getParameterDescription(ParamID name) const {
+  auto const paramName = getParameterName(name);
+  return paramName ? m_model.getParameterDescription(*paramName)
+                   : boost::optional<QString>();
+}
+
+boost::optional<QString> ConvFunctionModel::getPrefix(ParamID name) const {
+  if (name >= ParamID::FLAT_BG_A0) {
+    return m_model.backgroundPrefix();
+  } else {
+    auto const prefixes = m_model.peakPrefixes();
+    if (!prefixes)
+      return boost::optional<QString>();
+    auto const index =
+        name > ParamID::LOR2_FWHM_1 && name <= ParamID::LOR2_FWHM_2 ? 1 : 0;
+    return m_model.peakPrefixes()->at(index);
+  }
+}
+
+QMap<ParamID, double> ConvFunctionModel::getCurrentValues() const {
+  QMap<ParamID, double> values;
+  auto store = [&values, this](ParamID name) {
+    values[name] = *getParameter(name);
+  };
+  applyParameterFunction(store);
+  return values;
+}
+
+QMap<ParamID, double> ConvFunctionModel::getCurrentErrors() const {
+  QMap<ParamID, double> errors;
+  auto store = [&errors, this](ParamID name) {
+    errors[name] = *getParameterError(name);
+  };
+  applyParameterFunction(store);
+  return errors;
+}
+
+QMap<int, QString> ConvFunctionModel::getParameterNameMap() const {
+  QMap<int, QString> out;
+  auto addToMap = [&out, this](ParamID name) {
+    out[static_cast<int>(name)] = *getParameterName(name);
+  };
+  applyParameterFunction(addToMap);
+  return out;
+}
+
+void ConvFunctionModel::setCurrentValues(const QMap<ParamID, double> &values) {
+  for (auto const name : values.keys()) {
+    setParameter(name, values[name]);
+  }
+}
+
+void ConvFunctionModel::applyParameterFunction(
+    std::function<void(ParamID)> paramFun) const {
+  applyToFitType(m_fitType, paramFun);
+  applyToBackground(m_backgroundType, paramFun);
+}
+
+boost::optional<ParamID>
+ConvFunctionModel::getParameterId(const QString &parName) {
+  boost::optional<ParamID> result;
+  auto getter = [&result, parName, this](ParamID pid) {
+    if (parName == *getParameterName(pid))
+      result = pid;
+  };
+  applyParameterFunction(getter);
+  return result;
+}
+
+std::string ConvFunctionModel::buildLorentzianFunctionString() const {
+  return "name=Lorentzian,Amplitude=1,FWHM=1,constraints=(Amplitude>0,FWHM>0)";
+}
+
+std::string ConvFunctionModel::buildTeixeiraFunctionString() const {
+  return "name=TeixeiraWaterSQE";
+}
+
+std::string ConvFunctionModel::buildPeaksFunctionString() const {
+  std::string functions;
+  if (m_fitType == FitType::OneLorentzian) {
+    functions.append(buildLorentzianFunctionString());
+  } else if (m_fitType == FitType::TwoLorentzians) {
+    auto const lorentzian = buildLorentzianFunctionString();
+    functions.append(lorentzian);
+    functions.append(";");
+    functions.append(lorentzian);
+  } else if (m_fitType == FitType::TeixeiraWater) {
+    functions.append(buildTeixeiraFunctionString());
+  }
+  return functions;
+}
+
+std::string ConvFunctionModel::buildBackgroundFunctionString() const {
+  if (m_backgroundType == BackgroundType::None)
+    return "";
+  return "name=" + m_backgroundSubtype.getFunctionName(m_backgroundType) +
+         ",A0=0,constraints=(A0>0)";
+}
+
+boost::optional<QString> ConvFunctionModel::getLor1Prefix() const {
+  return m_model.peakPrefixes()->at(0);
+}
+
+boost::optional<QString> ConvFunctionModel::getLor2Prefix() const {
+  return m_model.peakPrefixes()->at(1);
+}
+
+boost::optional<QString> ConvFunctionModel::getDeltaPrefix() const {
+  return m_model.deltaFunctionPrefix();
+}
+
+boost::optional<QString> ConvFunctionModel::getBackgroundPrefix() const {
+  return m_model.backgroundPrefix();
+}
+
+} // namespace IDA
+} // namespace CustomInterfaces
+} // namespace MantidQt
diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h
new file mode 100644
index 0000000000000000000000000000000000000000..79faaec62813f572b46d8ff8512ba4ca460ac5bf
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h
@@ -0,0 +1,138 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef MANTIDQT_INDIRECT_CONVFUNCTIONMODEL_H_
+#define MANTIDQT_INDIRECT_CONVFUNCTIONMODEL_H_
+
+#include "ConvTypes.h"
+#include "DllConfig.h"
+#include "IndexTypes.h"
+#include "MantidAPI/IFunction_fwd.h"
+#include "MantidAPI/ITableWorkspace_fwd.h"
+#include "MantidQtWidgets/Common/ConvolutionFunctionModel.h"
+#include "ParameterEstimation.h"
+
+#include <QMap>
+#include <boost/optional.hpp>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+namespace IDA {
+
+using namespace ConvTypes;
+using namespace Mantid::API;
+using namespace MantidWidgets;
+
+class MANTIDQT_INDIRECT_DLL ConvFunctionModel : public IFunctionModel {
+public:
+  ConvFunctionModel();
+  void setFunction(IFunction_sptr fun) override;
+  IFunction_sptr getFitFunction() const override;
+  bool hasFunction() const override;
+  void addFunction(const QString &prefix, const QString &funStr) override;
+  void removeFunction(const QString &prefix) override;
+  void setParameter(const QString &paramName, double value) override;
+  void setParameterError(const QString &paramName, double value) override;
+  double getParameter(const QString &paramName) const override;
+  double getParameterError(const QString &paramName) const override;
+  QString getParameterDescription(const QString &paramName) const override;
+  QStringList getParameterNames() const override;
+  IFunction_sptr getSingleFunction(int index) const override;
+  IFunction_sptr getCurrentFunction() const override;
+  void setNumberDomains(int) override;
+  void setDatasetNames(const QStringList &names) override;
+  QStringList getDatasetNames() const override;
+  int getNumberDomains() const override;
+  void setCurrentDomainIndex(int i) override;
+  int currentDomainIndex() const override;
+  void changeTie(const QString &paramName, const QString &tie) override;
+  void addConstraint(const QString &functionIndex,
+                     const QString &constraint) override;
+  void removeConstraint(const QString &paramName) override;
+  QStringList getGlobalParameters() const override;
+  void setGlobalParameters(const QStringList &globals) override;
+  bool isGlobal(const QString &parName) const override;
+  void setGlobal(const QString &parName, bool on);
+  QStringList getLocalParameters() const override;
+  void updateMultiDatasetParameters(const IFunction &fun) override;
+  void updateParameters(const IFunction &fun) override;
+
+  double getLocalParameterValue(const QString &parName, int i) const override;
+  bool isLocalParameterFixed(const QString &parName, int i) const override;
+  QString getLocalParameterTie(const QString &parName, int i) const override;
+  QString getLocalParameterConstraint(const QString &parName,
+                                      int i) const override;
+  void setLocalParameterValue(const QString &parName, int i,
+                              double value) override;
+  void setLocalParameterValue(const QString &parName, int i, double value,
+                              double error) override;
+  void setLocalParameterFixed(const QString &parName, int i,
+                              bool fixed) override;
+  void setLocalParameterTie(const QString &parName, int i,
+                            const QString &tie) override;
+  void setLocalParameterConstraint(const QString &parName, int i,
+                                   const QString &constraint) override;
+  QString setBackgroundA0(double value) override;
+
+  void updateMultiDatasetParameters(const ITableWorkspace &paramTable);
+
+  void setFitType(FitType fitType);
+  void setDeltaFunction(bool);
+  bool hasDeltaFunction() const;
+  void setBackground(BackgroundType bgType);
+  void removeBackground();
+  bool hasBackground() const;
+  void
+  updateParameterEstimationData(DataForParameterEstimationCollection &&data);
+  void setResolution(std::string const &name, DatasetIndex const &index);
+
+  QMap<ParamID, double> getCurrentValues() const;
+  QMap<ParamID, double> getCurrentErrors() const;
+  QMap<int, QString> getParameterNameMap() const;
+
+private:
+  void clearData();
+  void setModel();
+  // QString buildFunctionString() const;
+  boost::optional<QString> getLor1Prefix() const;
+  boost::optional<QString> getLor2Prefix() const;
+  boost::optional<QString> getDeltaPrefix() const;
+  boost::optional<QString> getBackgroundPrefix() const;
+  void setParameter(ParamID name, double value);
+  boost::optional<double> getParameter(ParamID name) const;
+  boost::optional<double> getParameterError(ParamID name) const;
+  boost::optional<QString> getParameterName(ParamID name) const;
+  boost::optional<QString> getParameterDescription(ParamID name) const;
+  boost::optional<QString> getPrefix(ParamID name) const;
+  void setCurrentValues(const QMap<ParamID, double> &);
+  void applyParameterFunction(std::function<void(ParamID)> paramFun) const;
+  boost::optional<ParamID> getParameterId(const QString &parName);
+  std::string buildLorentzianFunctionString() const;
+  std::string buildTeixeiraFunctionString() const;
+  std::string buildPeaksFunctionString() const;
+  std::string buildBackgroundFunctionString() const;
+  void addGlobal(const QString &parName);
+  void removeGlobal(const QString &parName);
+  QStringList makeGlobalList() const;
+  int getNumberOfPeaks() const;
+
+  ConvolutionFunctionModel m_model;
+  FitType m_fitType = FitType::None;
+  BackgroundType m_backgroundType = BackgroundType::None;
+  bool m_hasDeltaFunction = false;
+  DataForParameterEstimationCollection m_estimationData;
+  QList<ParamID> m_globals;
+  FitSubType m_fitSubType;
+  BackgroundSubType m_backgroundSubtype;
+  std::string m_resolutionName;
+  DatasetIndex m_resolutionIndex;
+};
+
+} // namespace IDA
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif /* MANTIDQT_INDIRECT_CONVFUNCTIONMODEL_H_ */
diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3f8966d21d68d8515cc086f795174e19d887ea53
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp
@@ -0,0 +1,284 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#include "ConvTemplateBrowser.h"
+
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/IFunction.h"
+
+#include "MantidQtWidgets/Common/QtPropertyBrowser/ButtonEditorFactory.h"
+#include "MantidQtWidgets/Common/QtPropertyBrowser/CompositeEditorFactory.h"
+#include "MantidQtWidgets/Common/QtPropertyBrowser/DoubleEditorFactory.h"
+#include "MantidQtWidgets/Common/QtPropertyBrowser/qteditorfactory.h"
+#include "MantidQtWidgets/Common/QtPropertyBrowser/qtpropertymanager.h"
+#include "MantidQtWidgets/Common/QtPropertyBrowser/qttreepropertybrowser.h"
+
+#include <QMessageBox>
+#include <QSettings>
+#include <QVBoxLayout>
+
+#include <iostream>
+#include <limits>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+namespace IDA {
+
+namespace {
+class ScopedFalse {
+  bool &m_ref;
+  bool m_oldValue;
+
+public:
+  explicit ScopedFalse(bool &variable) : m_ref(variable), m_oldValue(variable) {
+    m_ref = false;
+  }
+  ~ScopedFalse() { m_ref = m_oldValue; }
+};
+} // namespace
+
+ConvTemplateBrowser::ConvTemplateBrowser(QWidget *parent)
+    : FunctionTemplateBrowser(parent), m_presenter(this) {
+  m_templateSubTypes.emplace_back(std::make_unique<FitSubType>());
+  m_templateSubTypes.emplace_back(std::make_unique<BackgroundSubType>());
+  connect(&m_presenter, SIGNAL(functionStructureChanged()), this,
+          SIGNAL(functionStructureChanged()));
+}
+
+void ConvTemplateBrowser::createProperties() {
+  m_parameterManager->blockSignals(true);
+  m_boolManager->blockSignals(true);
+  m_enumManager->blockSignals(true);
+
+  createFunctionParameterProperties();
+  createDeltaFunctionProperties();
+
+  m_browser->addProperty(m_subTypeProperties[0]);
+  m_browser->addProperty(m_deltaFunctionOn);
+  m_browser->addProperty(m_subTypeProperties[1]);
+
+  m_parameterManager->blockSignals(false);
+  m_enumManager->blockSignals(false);
+  m_boolManager->blockSignals(false);
+  // updateState();
+}
+
+void ConvTemplateBrowser::setFunction(const QString &funStr) {
+  m_presenter.setFunction(funStr);
+}
+
+IFunction_sptr ConvTemplateBrowser::getGlobalFunction() const {
+  return m_presenter.getGlobalFunction();
+}
+
+IFunction_sptr ConvTemplateBrowser::getFunction() const {
+  return m_presenter.getFunction();
+}
+
+void ConvTemplateBrowser::setNumberOfDatasets(int n) {
+  m_presenter.setNumberOfDatasets(n);
+}
+
+int ConvTemplateBrowser::getNumberOfDatasets() const {
+  return m_presenter.getNumberOfDatasets();
+}
+
+void ConvTemplateBrowser::setDatasetNames(const QStringList &names) {
+  m_presenter.setDatasetNames(names);
+}
+
+QStringList ConvTemplateBrowser::getGlobalParameters() const {
+  return m_presenter.getGlobalParameters();
+}
+
+QStringList ConvTemplateBrowser::getLocalParameters() const {
+  return m_presenter.getLocalParameters();
+}
+
+void ConvTemplateBrowser::setGlobalParameters(const QStringList &globals) {
+  m_presenter.setGlobalParameters(globals);
+}
+
+void ConvTemplateBrowser::intChanged(QtProperty *prop) {}
+
+void ConvTemplateBrowser::boolChanged(QtProperty *prop) {
+  if (prop == m_deltaFunctionOn) {
+    m_presenter.setDeltaFunction(m_boolManager->value(prop));
+  }
+}
+
+void ConvTemplateBrowser::enumChanged(QtProperty *prop) {
+  auto const index = m_enumManager->value(prop);
+  auto propIt =
+      std::find(m_subTypeProperties.begin(), m_subTypeProperties.end(), prop);
+  if (propIt != m_subTypeProperties.end()) {
+    auto const subTypeIndex =
+        std::distance(m_subTypeProperties.begin(), propIt);
+    m_presenter.setSubType(subTypeIndex, index);
+  }
+}
+
+void ConvTemplateBrowser::globalChanged(QtProperty *prop, const QString &name,
+                                        bool on) {
+  std::cerr << "Global " << name.toStdString() << ' ' << on << std::endl;
+}
+
+void ConvTemplateBrowser::parameterChanged(QtProperty *prop) {
+  auto isGlobal = m_parameterManager->isGlobal(prop);
+  m_presenter.setGlobal(m_actualParameterNames[prop], isGlobal);
+  if (m_emitParameterValueChange) {
+    emit parameterValueChanged(m_actualParameterNames[prop],
+                               m_parameterManager->value(prop));
+  }
+}
+
+void ConvTemplateBrowser::parameterButtonClicked(QtProperty *prop) {
+  emit localParameterButtonClicked(m_actualParameterNames[prop]);
+}
+
+void ConvTemplateBrowser::updateMultiDatasetParameters(const IFunction &fun) {
+  m_presenter.updateMultiDatasetParameters(fun);
+}
+
+void ConvTemplateBrowser::updateMultiDatasetParameters(
+    const ITableWorkspace &paramTable) {
+  m_presenter.updateMultiDatasetParameters(paramTable);
+}
+
+void ConvTemplateBrowser::updateParameters(const IFunction &fun) {
+  m_presenter.updateParameters(fun);
+}
+
+void ConvTemplateBrowser::setCurrentDataset(int i) {
+  m_presenter.setCurrentDataset(i);
+}
+
+void ConvTemplateBrowser::updateParameterNames(
+    const QMap<int, QString> &parameterNames) {
+  m_actualParameterNames.clear();
+  ScopedFalse _false(m_emitParameterValueChange);
+  for (auto const prop : m_parameterMap.keys()) {
+    auto const i = m_parameterMap[prop];
+    auto const name = parameterNames[static_cast<int>(i)];
+    m_actualParameterNames[prop] = name;
+    if (!name.isEmpty()) {
+      prop->setPropertyName(name);
+    }
+  }
+}
+
+void ConvTemplateBrowser::setErrorsEnabled(bool enabled) {
+  ScopedFalse _(m_emitParameterValueChange);
+  m_parameterManager->setErrorsEnabled(enabled);
+}
+
+void ConvTemplateBrowser::clear() {
+  // removeBackground();
+  // removeStretchExponential();
+  // removeExponentialTwo();
+  // removeExponentialOne();
+}
+
+void ConvTemplateBrowser::popupMenu(const QPoint &) {
+  std::cerr << "Popup" << std::endl;
+}
+
+void ConvTemplateBrowser::setParameterPropertyValue(QtProperty *prop,
+                                                    double value,
+                                                    double error) {
+  if (prop) {
+    ScopedFalse _(m_emitParameterValueChange);
+    m_parameterManager->setValue(prop, value);
+    m_parameterManager->setError(prop, error);
+  }
+}
+
+void ConvTemplateBrowser::setGlobalParametersQuiet(const QStringList &globals) {
+  ScopedFalse _(m_emitParameterValueChange);
+  auto parameterProperies = m_parameterMap.keys();
+  for (auto const prop : m_parameterMap.keys()) {
+    auto const name = m_actualParameterNames[prop];
+    if (globals.contains(name)) {
+      m_parameterManager->setGlobal(prop, true);
+      parameterProperies.removeOne(prop);
+    }
+  }
+  for (auto const prop : parameterProperies) {
+    if (!m_actualParameterNames[prop].isEmpty()) {
+      m_parameterManager->setGlobal(prop, false);
+    }
+  }
+}
+
+void ConvTemplateBrowser::createFunctionParameterProperties() {
+  m_subTypeParameters.resize(m_templateSubTypes.size());
+  m_currentSubTypeParameters.resize(m_templateSubTypes.size());
+  for (size_t isub = 0; isub < m_templateSubTypes.size(); ++isub) {
+    auto const &subType = m_templateSubTypes[isub];
+    auto &parameters = m_subTypeParameters[isub];
+    for (int index = 0; index < subType->getNTypes(); ++index) {
+      auto const paramIDs = subType->getParameterIDs(index);
+      auto const names = subType->getParameterNames(index);
+      auto const descriptions = subType->getParameterDescriptions(index);
+      QList<QtProperty *> props;
+      auto const np = names.size();
+      for (int i = 0; i < np; ++i) {
+        auto prop = m_parameterManager->addProperty(names[i]);
+        m_parameterManager->setDescription(prop, descriptions[i]);
+        m_parameterManager->setDecimals(prop, 6);
+        props.append(prop);
+        auto const id = paramIDs[i];
+        m_parameterMap[prop] = id;
+        m_parameterReverseMap[id] = prop;
+      }
+      parameters[index] = props;
+    }
+    auto subTypeProp = m_enumManager->addProperty(subType->name());
+    m_enumManager->setEnumNames(subTypeProp,
+                                m_templateSubTypes[isub]->getTypeNames());
+    m_subTypeProperties.push_back(subTypeProp);
+  }
+}
+
+void ConvTemplateBrowser::createDeltaFunctionProperties() {
+  m_deltaFunctionOn = m_boolManager->addProperty("Delta Function");
+}
+
+void ConvTemplateBrowser::setSubType(size_t subTypeIndex, int typeIndex) {
+  auto subTypeProp = m_subTypeProperties[subTypeIndex];
+  auto &currentParameters = m_currentSubTypeParameters[subTypeIndex];
+  for (auto &&prop : currentParameters) {
+    subTypeProp->removeSubProperty(prop);
+  }
+  currentParameters.clear();
+  auto &subTypeParameters = m_subTypeParameters[subTypeIndex];
+  for (auto &&prop : subTypeParameters[typeIndex]) {
+    subTypeProp->addSubProperty(prop);
+    currentParameters.append(prop);
+  }
+}
+
+void ConvTemplateBrowser::setParameterValueQuiet(ParamID id, double value,
+                                                 double error) {
+  ScopedFalse _(m_emitParameterValueChange);
+  auto prop = m_parameterReverseMap[id];
+  m_parameterManager->setValue(prop, value);
+  m_parameterManager->setError(prop, error);
+}
+
+void ConvTemplateBrowser::updateParameterEstimationData(
+    DataForParameterEstimationCollection &&data) {}
+
+void ConvTemplateBrowser::setBackgroundA0(double value) {}
+
+void ConvTemplateBrowser::setResolution(std::string const &name,
+                                        DatasetIndex const &index) {
+  m_presenter.setResolution(name, index);
+}
+
+} // namespace IDA
+} // namespace CustomInterfaces
+} // namespace MantidQt
diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h
new file mode 100644
index 0000000000000000000000000000000000000000..69185eb6584e3b592f8e023333f7591530b85f08
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h
@@ -0,0 +1,99 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef INDIRECT_CONVTEMPLATEBROWSER_H_
+#define INDIRECT_CONVTEMPLATEBROWSER_H_
+
+#include "ConvTemplatePresenter.h"
+#include "ConvTypes.h"
+#include "DllConfig.h"
+#include "FunctionTemplateBrowser.h"
+
+#include <QMap>
+#include <QWidget>
+
+class QtProperty;
+
+namespace MantidQt {
+namespace CustomInterfaces {
+namespace IDA {
+
+using namespace ConvTypes;
+/**
+ * Class FunctionTemplateBrowser implements QtPropertyBrowser to display
+ * and set properties that can be used to generate a fit function.
+ *
+ */
+class MANTIDQT_INDIRECT_DLL ConvTemplateBrowser
+    : public FunctionTemplateBrowser {
+  Q_OBJECT
+public:
+  explicit ConvTemplateBrowser(QWidget *parent = nullptr);
+  void setFunction(const QString &funStr) override;
+  IFunction_sptr getGlobalFunction() const override;
+  IFunction_sptr getFunction() const override;
+  void setNumberOfDatasets(int) override;
+  int getNumberOfDatasets() const override;
+  void setDatasetNames(const QStringList &names) override;
+  QStringList getGlobalParameters() const override;
+  QStringList getLocalParameters() const override;
+  void setGlobalParameters(const QStringList &globals) override;
+  void updateMultiDatasetParameters(const IFunction &fun) override;
+  void updateMultiDatasetParameters(const ITableWorkspace &paramTable) override;
+  void updateParameters(const IFunction &fun) override;
+  void setCurrentDataset(int i) override;
+  void updateParameterNames(const QMap<int, QString> &parameterNames) override;
+  void setErrorsEnabled(bool enabled) override;
+  void clear() override;
+  void updateParameterEstimationData(
+      DataForParameterEstimationCollection &&data) override;
+  void setBackgroundA0(double value) override;
+  void setResolution(std::string const &name,
+                     DatasetIndex const &index) override;
+
+protected slots:
+  void intChanged(QtProperty *) override;
+  void boolChanged(QtProperty *) override;
+  void enumChanged(QtProperty *) override;
+  void globalChanged(QtProperty *, const QString &, bool) override;
+  void parameterChanged(QtProperty *) override;
+  void parameterButtonClicked(QtProperty *) override;
+
+private:
+  void createProperties() override;
+  void popupMenu(const QPoint &) override;
+  void setParameterPropertyValue(QtProperty *prop, double value, double error);
+  void setGlobalParametersQuiet(const QStringList &globals);
+  void createFunctionParameterProperties();
+  void createDeltaFunctionProperties();
+  void setSubType(size_t subTypeIndex, int typeIndex);
+  void setParameterValueQuiet(ParamID id, double value, double error);
+
+  std::vector<std::unique_ptr<TemplateSubType>> m_templateSubTypes;
+  // Map fit type to a list of function parameters (QtProperties for those
+  // parameters)
+  std::vector<QMap<int, QList<QtProperty *>>> m_subTypeParameters;
+  std::vector<QList<QtProperty *>> m_currentSubTypeParameters;
+  std::vector<QtProperty *> m_subTypeProperties;
+
+  QtProperty *m_deltaFunctionOn;
+
+  QMap<QtProperty *, ParamID> m_parameterMap;
+  QMap<ParamID, QtProperty *> m_parameterReverseMap;
+  QMap<QtProperty *, QString> m_actualParameterNames;
+  QMap<QtProperty *, std::string> m_parameterDescriptions;
+
+private:
+  ConvTemplatePresenter m_presenter;
+  bool m_emitParameterValueChange = true;
+  friend class ConvTemplatePresenter;
+};
+
+} // namespace IDA
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif /*INDIRECT_CONVTEMPLATEBROWSER_H_*/
diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..81c62dcbedcc7bc315a1f19139ff2c6b70c7a255
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp
@@ -0,0 +1,276 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#include "ConvTemplatePresenter.h"
+#include "ConvTemplateBrowser.h"
+#include "MantidQtWidgets/Common/EditLocalParameterDialog.h"
+
+#include <cmath>
+#include <iostream>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+namespace IDA {
+
+using namespace MantidWidgets;
+
+/**
+ * Constructor
+ * @param parent :: The parent widget.
+ */
+ConvTemplatePresenter::ConvTemplatePresenter(ConvTemplateBrowser *view)
+    : QObject(view), m_view(view) {
+  connect(m_view, SIGNAL(localParameterButtonClicked(const QString &)), this,
+          SLOT(editLocalParameter(const QString &)));
+  connect(m_view, SIGNAL(parameterValueChanged(const QString &, double)), this,
+          SLOT(viewChangedParameterValue(const QString &, double)));
+}
+
+void ConvTemplatePresenter::setSubType(size_t subTypeIndex, int typeIndex) {
+  if (subTypeIndex == 0) {
+    m_model.setFitType(static_cast<FitType>(typeIndex));
+  } else {
+    m_model.setBackground(static_cast<BackgroundType>(typeIndex));
+  }
+  m_view->setSubType(subTypeIndex, typeIndex);
+  setErrorsEnabled(false);
+  updateViewParameterNames();
+  updateViewParameters();
+  emit functionStructureChanged();
+}
+
+void ConvTemplatePresenter::setDeltaFunction(bool on) {
+  if (on == m_model.hasDeltaFunction())
+    return;
+  m_model.setDeltaFunction(on);
+  setErrorsEnabled(false);
+  updateViewParameterNames();
+  updateViewParameters();
+  emit functionStructureChanged();
+}
+
+void ConvTemplatePresenter::setNumberOfDatasets(int n) {
+  m_model.setNumberDomains(n);
+}
+
+int ConvTemplatePresenter::getNumberOfDatasets() const {
+  return m_model.getNumberDomains();
+}
+
+void ConvTemplatePresenter::setFunction(const QString &funStr) {
+  m_model.setFunctionString(funStr);
+  m_view->clear();
+  setErrorsEnabled(false);
+  // if (m_model.hasBackground()) {
+  //  m_view->addFlatBackground();
+  //}
+  // if (m_model.hasStretchExponential()) {
+  //  m_view->addStretchExponential();
+  //}
+  // auto const nExp = m_model.getNumberOfExponentials();
+  // if (nExp > 0) {
+  //  m_view->addExponentialOne();
+  //}
+  // if (nExp > 1) {
+  //  m_view->addExponentialTwo();
+  //}
+  updateViewParameterNames();
+  updateViewParameters();
+  emit functionStructureChanged();
+}
+
+IFunction_sptr ConvTemplatePresenter::getGlobalFunction() const {
+  return m_model.getFitFunction();
+}
+
+IFunction_sptr ConvTemplatePresenter::getFunction() const {
+  return m_model.getCurrentFunction();
+}
+
+QStringList ConvTemplatePresenter::getGlobalParameters() const {
+  return m_model.getGlobalParameters();
+}
+
+QStringList ConvTemplatePresenter::getLocalParameters() const {
+  return m_model.getLocalParameters();
+}
+
+void ConvTemplatePresenter::setGlobalParameters(const QStringList &globals) {
+  m_model.setGlobalParameters(globals);
+  // if (m_model.hasStretchExponential()) {
+  //  m_view->setGlobalParametersQuiet(globals);
+  //}
+}
+
+void ConvTemplatePresenter::setGlobal(const QString &parName, bool on) {
+  auto globals = m_model.getGlobalParameters();
+  if (on) {
+    if (!globals.contains(parName)) {
+      globals.push_back(parName);
+    }
+  } else if (globals.contains(parName)) {
+    globals.removeOne(parName);
+  }
+  setGlobalParameters(globals);
+}
+
+void ConvTemplatePresenter::updateMultiDatasetParameters(const IFunction &fun) {
+  m_model.updateMultiDatasetParameters(fun);
+  updateViewParameters();
+}
+
+void ConvTemplatePresenter::updateMultiDatasetParameters(
+    const ITableWorkspace &paramTable) {
+  m_model.updateMultiDatasetParameters(paramTable);
+  updateViewParameters();
+}
+
+void ConvTemplatePresenter::updateParameters(const IFunction &fun) {
+  m_model.updateParameters(fun);
+  updateViewParameters();
+}
+
+void ConvTemplatePresenter::setCurrentDataset(int i) {
+  m_model.setCurrentDomainIndex(i);
+  updateViewParameters();
+}
+
+void ConvTemplatePresenter::setDatasetNames(const QStringList &names) {
+  m_model.setDatasetNames(names);
+}
+
+void ConvTemplatePresenter::setErrorsEnabled(bool enabled) {
+  m_view->setErrorsEnabled(enabled);
+}
+
+void ConvTemplatePresenter::setResolution(std::string const &name,
+                                          DatasetIndex const &index) {
+  m_model.setResolution(name, index);
+}
+
+void ConvTemplatePresenter::updateViewParameters() {
+  auto values = m_model.getCurrentValues();
+  auto errors = m_model.getCurrentErrors();
+  for (auto const id : values.keys()) {
+    m_view->setParameterValueQuiet(id, values[id], errors[id]);
+  }
+}
+
+QStringList ConvTemplatePresenter::getDatasetNames() const {
+  return m_model.getDatasetNames();
+}
+
+double ConvTemplatePresenter::getLocalParameterValue(const QString &parName,
+                                                     int i) const {
+  return m_model.getLocalParameterValue(parName, i);
+}
+
+bool ConvTemplatePresenter::isLocalParameterFixed(const QString &parName,
+                                                  int i) const {
+  return m_model.isLocalParameterFixed(parName, i);
+}
+
+QString ConvTemplatePresenter::getLocalParameterTie(const QString &parName,
+                                                    int i) const {
+  return m_model.getLocalParameterTie(parName, i);
+}
+
+QString
+ConvTemplatePresenter::getLocalParameterConstraint(const QString &parName,
+                                                   int i) const {
+  return m_model.getLocalParameterConstraint(parName, i);
+}
+
+void ConvTemplatePresenter::setLocalParameterValue(const QString &parName,
+                                                   int i, double value) {
+  m_model.setLocalParameterValue(parName, i, value);
+}
+
+void ConvTemplatePresenter::setLocalParameterTie(const QString &parName, int i,
+                                                 const QString &tie) {
+  m_model.setLocalParameterTie(parName, i, tie);
+}
+
+void ConvTemplatePresenter::updateViewParameterNames() {
+  m_view->updateParameterNames(m_model.getParameterNameMap());
+}
+
+void ConvTemplatePresenter::setLocalParameterFixed(const QString &parName,
+                                                   int i, bool fixed) {
+  m_model.setLocalParameterFixed(parName, i, fixed);
+}
+
+void ConvTemplatePresenter::editLocalParameter(const QString &parName) {
+  auto const wsNames = getDatasetNames();
+  QList<double> values;
+  QList<bool> fixes;
+  QStringList ties;
+  QStringList constraints;
+  const int n = wsNames.size();
+  for (int i = 0; i < n; ++i) {
+    const double value = getLocalParameterValue(parName, i);
+    values.push_back(value);
+    const bool fixed = isLocalParameterFixed(parName, i);
+    fixes.push_back(fixed);
+    const auto tie = getLocalParameterTie(parName, i);
+    ties.push_back(tie);
+    const auto constraint = getLocalParameterConstraint(parName, i);
+    constraints.push_back(constraint);
+  }
+
+  m_editLocalParameterDialog = new EditLocalParameterDialog(
+      m_view, parName, wsNames, values, fixes, ties, constraints);
+  connect(m_editLocalParameterDialog, SIGNAL(finished(int)), this,
+          SLOT(editLocalParameterFinish(int)));
+  m_editLocalParameterDialog->open();
+}
+
+void ConvTemplatePresenter::editLocalParameterFinish(int result) {
+  if (result == QDialog::Accepted) {
+    auto parName = m_editLocalParameterDialog->getParameterName();
+    auto values = m_editLocalParameterDialog->getValues();
+    auto fixes = m_editLocalParameterDialog->getFixes();
+    auto ties = m_editLocalParameterDialog->getTies();
+    assert(values.size() == getNumberOfDatasets());
+    for (int i = 0; i < values.size(); ++i) {
+      setLocalParameterValue(parName, i, values[i]);
+      if (!ties[i].isEmpty()) {
+        setLocalParameterTie(parName, i, ties[i]);
+      } else if (fixes[i]) {
+        setLocalParameterFixed(parName, i, fixes[i]);
+      } else {
+        setLocalParameterTie(parName, i, "");
+      }
+    }
+  }
+  m_editLocalParameterDialog = nullptr;
+  updateViewParameters();
+  emit functionStructureChanged();
+}
+
+void ConvTemplatePresenter::viewChangedParameterValue(const QString &parName,
+                                                      double value) {
+  if (parName.isEmpty())
+    return;
+  if (m_model.isGlobal(parName)) {
+    auto const n = getNumberOfDatasets();
+    for (int i = 0; i < n; ++i) {
+      setLocalParameterValue(parName, i, value);
+    }
+  } else {
+    auto const i = m_model.currentDomainIndex();
+    auto const oldValue = m_model.getLocalParameterValue(parName, i);
+    if (fabs(value - oldValue) > 1e-6) {
+      setErrorsEnabled(false);
+    }
+    setLocalParameterValue(parName, i, value);
+  }
+  emit functionStructureChanged();
+}
+
+} // namespace IDA
+} // namespace CustomInterfaces
+} // namespace MantidQt
diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h
new file mode 100644
index 0000000000000000000000000000000000000000..bdca7a3a17547dd499e8f777e2ef1236ef97c9bf
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h
@@ -0,0 +1,83 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef INDIRECT_CONVTEMPLATEPRESENTER_H_
+#define INDIRECT_CONVTEMPLATEPRESENTER_H_
+
+#include "ConvFunctionModel.h"
+#include "DllConfig.h"
+
+#include <QMap>
+#include <QWidget>
+
+class QtProperty;
+
+namespace MantidQt {
+namespace MantidWidgets {
+class EditLocalParameterDialog;
+}
+namespace CustomInterfaces {
+namespace IDA {
+
+class ConvTemplateBrowser;
+
+/**
+ * Class FunctionTemplateBrowser implements QtPropertyBrowser to display
+ * and set properties that can be used to generate a fit function.
+ *
+ */
+class MANTIDQT_INDIRECT_DLL ConvTemplatePresenter : public QObject {
+  Q_OBJECT
+public:
+  explicit ConvTemplatePresenter(ConvTemplateBrowser *view);
+  void setSubType(size_t subTypeIndex, int typeIndex);
+  void setDeltaFunction(bool);
+  void setNumberOfDatasets(int);
+  int getNumberOfDatasets() const;
+  void setFunction(const QString &funStr);
+  IFunction_sptr getGlobalFunction() const;
+  IFunction_sptr getFunction() const;
+  QStringList getGlobalParameters() const;
+  QStringList getLocalParameters() const;
+  void setGlobalParameters(const QStringList &globals);
+  void setGlobal(const QString &parName, bool on);
+  void updateMultiDatasetParameters(const IFunction &fun);
+  void updateMultiDatasetParameters(const ITableWorkspace &paramTable);
+  void updateParameters(const IFunction &fun);
+  void setCurrentDataset(int i);
+  void setDatasetNames(const QStringList &names);
+  void setErrorsEnabled(bool enabled);
+  void setResolution(std::string const &name, DatasetIndex const &index);
+
+signals:
+  void functionStructureChanged();
+
+private slots:
+  void editLocalParameter(const QString &parName);
+  void editLocalParameterFinish(int result);
+  void viewChangedParameterValue(const QString &parName, double value);
+
+private:
+  void updateViewParameters();
+  QStringList getDatasetNames() const;
+  double getLocalParameterValue(const QString &parName, int i) const;
+  bool isLocalParameterFixed(const QString &parName, int i) const;
+  QString getLocalParameterTie(const QString &parName, int i) const;
+  QString getLocalParameterConstraint(const QString &parName, int i) const;
+  void setLocalParameterValue(const QString &parName, int i, double value);
+  void setLocalParameterFixed(const QString &parName, int i, bool fixed);
+  void setLocalParameterTie(const QString &parName, int i, const QString &tie);
+  void updateViewParameterNames();
+  ConvTemplateBrowser *m_view;
+  ConvFunctionModel m_model;
+  EditLocalParameterDialog *m_editLocalParameterDialog;
+};
+
+} // namespace IDA
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif /*INDIRECT_CONVTEMPLATEPRESENTER_H_*/
diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..617110e1483cedc1c061e6e9229bb8f019498f03
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.cpp
@@ -0,0 +1,81 @@
+#include "ConvTypes.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/IFunction.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+namespace IDA {
+namespace ConvTypes {
+
+using namespace Mantid::API;
+
+std::map<ParamID, QString> g_paramName{
+    {ParamID::LOR1_AMPLITUDE, "Amplitude"},
+    {ParamID::LOR1_PEAKCENTRE, "PeakCentre"},
+    {ParamID::LOR1_FWHM, "FWHM"},
+    {ParamID::LOR2_AMPLITUDE_1, "Amplitude"},
+    {ParamID::LOR2_PEAKCENTRE_1, "PeakCentre"},
+    {ParamID::LOR2_FWHM_1, "FWHM"},
+    {ParamID::LOR2_AMPLITUDE_2, "Amplitude"},
+    {ParamID::LOR2_PEAKCENTRE_2, "PeakCentre"},
+    {ParamID::LOR2_FWHM_2, "FWHM"},
+    {ParamID::TW_HEIGHT, "Height"},
+    {ParamID::TW_DIFFCOEFF, "DiffCoeff"},
+    {ParamID::TW_TAU, "Tau"},
+    {ParamID::TW_CENTRE, "Centre"},
+    {ParamID::FLAT_BG_A0, "A0"},
+    {ParamID::LINEAR_BG_A0, "A0"},
+    {ParamID::LINEAR_BG_A1, "A1"}};
+
+template <>
+std::map<FitType, TemplateSubTypeDescriptor>
+    TemplateSubTypeImpl<FitType>::g_typeMap{
+        {FitType::None, {"None", "", {ParamID::NONE, ParamID::NONE}}},
+        {FitType::OneLorentzian,
+         {"One Lorentzian",
+          "Lorentzian",
+          {ParamID::LOR1_AMPLITUDE, ParamID::LOR1_FWHM}}},
+        {FitType::TwoLorentzians,
+         {"Two Lorentzians",
+          "Lorentzian",
+          {ParamID::LOR2_AMPLITUDE_1, ParamID::LOR2_FWHM_1,
+           ParamID::LOR2_FWHM_2}}},
+        {FitType::TeixeiraWater,
+         {"Teixeira Water",
+          "TeixeiraWaterSQE",
+          {ParamID::TW_HEIGHT, ParamID::TW_CENTRE}}},
+    };
+
+template <>
+std::map<BackgroundType, TemplateSubTypeDescriptor>
+    TemplateSubTypeImpl<BackgroundType>::g_typeMap{
+        {BackgroundType::None, {"None", "", {ParamID::NONE, ParamID::NONE}}},
+        {BackgroundType::Flat,
+         {"FlatBackground",
+          "FlatBackground",
+          {ParamID::FLAT_BG_A0, ParamID::FLAT_BG_A0}}},
+        {BackgroundType::Linear,
+         {"LinearBackground",
+          "LinearBackground",
+          {ParamID::LINEAR_BG_A0, ParamID::LINEAR_BG_A1}}},
+    };
+
+QString paramName(ParamID id) { return g_paramName.at(id); }
+
+void applyToFitType(FitType fitType,
+                    const std::function<void(ParamID)> &paramFun) {
+  applyToParamIDRange(FitSubType::g_typeMap[fitType].blocks.front(),
+                      FitSubType::g_typeMap[fitType].blocks.back(), paramFun);
+}
+
+void applyToBackground(BackgroundType bgType,
+                       const std::function<void(ParamID)> &paramFun) {
+  applyToParamIDRange(BackgroundSubType::g_typeMap[bgType].blocks.front(),
+                      BackgroundSubType::g_typeMap[bgType].blocks.back(),
+                      paramFun);
+}
+
+} // namespace ConvTypes
+} // namespace IDA
+} // namespace CustomInterfaces
+} // namespace MantidQt
diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.h
new file mode 100644
index 0000000000000000000000000000000000000000..ccea683d412577453da0f315bbf4acab4a590dc1
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.h
@@ -0,0 +1,153 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef MANTIDQT_INDIRECT_CONVTYPES_H_
+#define MANTIDQT_INDIRECT_CONVTYPES_H_
+
+#include "DllConfig.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/IFunction.h"
+
+#include <QMap>
+#include <QStringList>
+#include <boost/optional.hpp>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+namespace IDA {
+namespace ConvTypes {
+
+using namespace Mantid::API;
+
+enum class FitType { None, OneLorentzian, TwoLorentzians, TeixeiraWater };
+enum class BackgroundType { None, Flat, Linear };
+
+enum class ParamID {
+  NONE,
+  LOR1_AMPLITUDE,
+  LOR1_PEAKCENTRE,
+  LOR1_FWHM,
+  LOR2_AMPLITUDE_1,
+  LOR2_PEAKCENTRE_1,
+  LOR2_FWHM_1,
+  LOR2_AMPLITUDE_2,
+  LOR2_PEAKCENTRE_2,
+  LOR2_FWHM_2,
+  TW_HEIGHT,
+  TW_DIFFCOEFF,
+  TW_TAU,
+  TW_CENTRE,
+  FLAT_BG_A0,
+  LINEAR_BG_A0,
+  LINEAR_BG_A1
+};
+
+QString paramName(ParamID id);
+
+inline ParamID &operator++(ParamID &id) {
+  id = ParamID(static_cast<std::underlying_type<ParamID>::type>(id) + 1);
+  return id;
+}
+
+inline void applyToParamIDRange(ParamID from, ParamID to,
+                                std::function<void(ParamID)> fun) {
+  if (from == ParamID::NONE || to == ParamID::NONE)
+    return;
+  for (auto i = from; i <= to; ++i)
+    fun(i);
+}
+
+struct TemplateSubType {
+  virtual QString name() const = 0;
+  virtual QStringList getTypeNames() const = 0;
+  virtual int getTypeIndex(const QString &typeName) const = 0;
+  virtual int getNTypes() const = 0;
+  virtual QList<ParamID> getParameterIDs(int typeIndex) const = 0;
+  virtual QStringList getParameterNames(int typeIndex) const = 0;
+  virtual QList<std::string> getParameterDescriptions(int typeIndex) const = 0;
+};
+
+struct TemplateSubTypeDescriptor {
+  QString name;
+  std::string function;
+  std::vector<ParamID> blocks;
+};
+
+template <class Type> struct TemplateSubTypeImpl : public TemplateSubType {
+  QStringList getTypeNames() const override {
+    QStringList out;
+    for (auto &&it : g_typeMap) {
+      out << it.second.name;
+    }
+    return out;
+  }
+  int getTypeIndex(const QString &typeName) const override {
+    for (auto &&it : g_typeMap) {
+      if (it.second.name == typeName)
+        return static_cast<int>(it.first);
+    }
+    return static_cast<int>(FitType::None);
+  }
+  int getNTypes() const override { return static_cast<int>(g_typeMap.size()); }
+  QList<ParamID> getParameterIDs(int typeIndex) const override {
+    QList<ParamID> ids;
+    auto fillIDs = [&ids](ParamID id) { ids << id; };
+    applyToType(static_cast<Type>(typeIndex), fillIDs);
+    return ids;
+  }
+  QStringList getParameterNames(int typeIndex) const override {
+    QStringList names;
+    auto fillNames = [&names](ParamID id) { names << paramName(id); };
+    applyToType(static_cast<Type>(typeIndex), fillNames);
+    return names;
+  }
+  QList<std::string> getParameterDescriptions(int typeIndex) const override {
+    auto const type = static_cast<Type>(typeIndex);
+    QList<std::string> descriptions;
+    auto const function = g_typeMap[type].function;
+    if (!function.empty()) {
+      IFunction_sptr fun = FunctionFactory::Instance().createFunction(function);
+      auto fillDescriptions = [&descriptions, &fun](ParamID id) {
+        descriptions << fun->parameterDescription(
+            fun->parameterIndex(paramName(id).toStdString()));
+      };
+      applyToParamIDRange(g_typeMap[type].blocks.front(),
+                          g_typeMap[type].blocks.back(), fillDescriptions);
+    }
+    return descriptions;
+  }
+
+  std::string getFunctionName(Type type) const {
+    return g_typeMap[type].function;
+  }
+
+  void applyToType(Type type, std::function<void(ParamID)> paramFun) const {
+    applyToParamIDRange(g_typeMap[type].blocks.front(),
+                        g_typeMap[type].blocks.back(), paramFun);
+  }
+
+  static std::map<Type, TemplateSubTypeDescriptor> g_typeMap;
+};
+
+struct FitSubType : public TemplateSubTypeImpl<FitType> {
+  QString name() const override { return "Fit Type"; }
+};
+
+struct BackgroundSubType : public TemplateSubTypeImpl<BackgroundType> {
+  QString name() const override { return "Background"; }
+};
+
+void applyToFitType(FitType fitType,
+                    const std::function<void(ParamID)> &paramFun);
+void applyToBackground(BackgroundType bgType,
+                       const std::function<void(ParamID)> &paramFun);
+
+} // namespace ConvTypes
+} // namespace IDA
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif /* MANTIDQT_INDIRECT_CONVTYPES_H_ */
diff --git a/qt/scientific_interfaces/Indirect/test/ConvFitDataPresenterTest.h b/qt/scientific_interfaces/Indirect/test/ConvFitDataPresenterTest.h
index 52a50add47796edf0559814cba1e3e95aa76e894..1ca85c05a54d2ae753c279b7e7d9af6254be8e43 100644
--- a/qt/scientific_interfaces/Indirect/test/ConvFitDataPresenterTest.h
+++ b/qt/scientific_interfaces/Indirect/test/ConvFitDataPresenterTest.h
@@ -12,7 +12,7 @@
 
 #include "ConvFitDataPresenter.h"
 #include "ConvFitModel.h"
-#include "IIndirectFitDataViewLegacy.h"
+#include "IIndirectFitDataView.h"
 
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidKernel/WarningSuppressions.h"
@@ -39,7 +39,7 @@ std::unique_ptr<QTableWidget> createEmptyTableWidget(int columns, int rows) {
 GNU_DIAG_OFF_SUGGEST_OVERRIDE
 
 /// Mock object to mock the view
-class MockConvFitDataView : public IIndirectFitDataViewLegacy {
+class MockConvFitDataView : public IIndirectFitDataView {
 public:
   /// Signals
   void emitResolutionLoaded(QString const &workspaceName) {
@@ -51,7 +51,6 @@ public:
   MOCK_CONST_METHOD0(isMultipleDataTabSelected, bool());
   MOCK_CONST_METHOD0(isResolutionHidden, bool());
   MOCK_METHOD1(setResolutionHidden, void(bool hide));
-  MOCK_METHOD1(setStartAndEndHidden, void(bool hidden));
   MOCK_METHOD0(disableMultipleDataTab, void());
 
   MOCK_CONST_METHOD0(getSelectedSample, std::string());
@@ -73,9 +72,12 @@ public:
 
   MOCK_METHOD1(readSettings, void(QSettings const &settings));
   MOCK_METHOD1(validate, UserInputValidator &(UserInputValidator &validator));
+  MOCK_METHOD1(setXRange, void(std::pair<double, double> const &range));
 
   /// Public slots
   MOCK_METHOD1(displayWarning, void(std::string const &warning));
+  MOCK_METHOD1(setStartX, void(double));
+  MOCK_METHOD1(setEndX, void(double));
 };
 
 /// Mock object to mock the model
@@ -137,7 +139,7 @@ public:
 
   void
   test_that_the_model_contains_the_correct_number_of_workspace_after_instantiation() {
-    TS_ASSERT_EQUALS(m_model->numberOfWorkspaces(), 1);
+    TS_ASSERT_EQUALS(m_model->numberOfWorkspaces(), DatasetIndex{1});
   }
 
   ///----------------------------------------------------------------------
diff --git a/qt/scientific_interfaces/Indirect/test/ConvFitModelTest.h b/qt/scientific_interfaces/Indirect/test/ConvFitModelTest.h
index 8b19d6831ddb378a99076eced5fec6f7c8dc66d2..56f1484e6a4fe66613a2ec0c40e63d0f62096134 100644
--- a/qt/scientific_interfaces/Indirect/test/ConvFitModelTest.h
+++ b/qt/scientific_interfaces/Indirect/test/ConvFitModelTest.h
@@ -16,6 +16,7 @@
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IFunction.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
+#include "MantidAPI/MultiDomainFunction.h"
 #include "MantidTestHelpers/IndirectFitDataCreationHelper.h"
 
 using namespace Mantid::API;
@@ -25,7 +26,8 @@ using namespace MantidQt::CustomInterfaces::IDA;
 namespace {
 
 std::string getFunctionString(std::string const &workspaceName) {
-  return "name=LinearBackground,A0=0,A1=0,ties=(A0=0.000000,A1=0.0);"
+  return "composite=CompositeFunction,$domains=i;name=LinearBackground,A0=0,A1="
+         "0,ties=(A0=0.000000,A1=0.0);"
          "(composite=Convolution,FixResolution=true,NumDeriv=true;"
          "name=Resolution,Workspace=" +
          workspaceName +
@@ -34,8 +36,10 @@ std::string getFunctionString(std::string const &workspaceName) {
          "0175)))";
 }
 
-IFunction_sptr getFunction(std::string const &functionString) {
-  return FunctionFactory::Instance().createInitialized(functionString);
+MultiDomainFunction_sptr getFunction(std::string const &functionString) {
+  auto fun = FunctionFactory::Instance().createInitialized(
+      "composite=MultiDomainFunction;" + functionString + ";" + functionString);
+  return boost::dynamic_pointer_cast<MultiDomainFunction>(fun);
 }
 
 } // namespace
@@ -64,15 +68,15 @@ public:
   }
 
   void test_that_the_model_is_instantiated_and_can_hold_a_workspace() {
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
 
     m_model->addWorkspace(m_workspace, spectra);
 
-    TS_ASSERT_EQUALS(m_model->numberOfWorkspaces(), 1);
+    TS_ASSERT_EQUALS(m_model->numberOfWorkspaces(), DatasetIndex{1});
   }
 
   void test_that_addWorkspace_will_add_multiple_workspaces() {
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
     auto const workspace2 = createWorkspace(3, 3);
     auto const workspace3 = createWorkspace(3, 2);
     auto const workspace4 = createWorkspace(3, 6);
@@ -81,12 +85,12 @@ public:
     addWorkspacesToModel(spectra, m_workspace, workspace2, workspace3,
                          workspace4, workspace5);
 
-    TS_ASSERT_EQUALS(m_model->numberOfWorkspaces(), 5);
+    TS_ASSERT_EQUALS(m_model->numberOfWorkspaces(), DatasetIndex{5});
   }
 
   void
   test_that_getFittingFunction_will_return_the_fitting_function_which_has_been_set() {
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
 
     addWorkspacesToModel(spectra, m_workspace);
     m_model->setFitFunction(getFunction(getFunctionString("Name")));
@@ -98,13 +102,13 @@ public:
 
   void
   test_that_getInstrumentResolution_will_return_none_if_the_index_provided_is_larger_than_the_number_of_workspaces() {
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
     auto const workspace2 = createWorkspace(3, 3);
     m_ads->addOrReplace("Name2", workspace2);
 
     addWorkspacesToModel(spectra, m_workspace, workspace2);
 
-    TS_ASSERT(!m_model->getInstrumentResolution(3));
+    TS_ASSERT(!m_model->getInstrumentResolution(DatasetIndex{3}));
   }
 
   void
@@ -112,55 +116,55 @@ public:
     /// A unit test for a positive response from getInstrumentResolution needs
     /// to be added. The workspace used in the test will need to have an
     /// analyser attached to its instrument
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
     auto const workspace2 = createWorkspace(3, 3);
     m_ads->addOrReplace("Name2", workspace2);
 
     addWorkspacesToModel(spectra, m_workspace, workspace2);
 
-    TS_ASSERT(!m_model->getInstrumentResolution(0));
+    TS_ASSERT(!m_model->getInstrumentResolution(DatasetIndex{0}));
   }
 
   void
   test_that_getNumberHistograms_will_get_the_number_of_spectra_for_the_workspace_specified() {
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
     auto const workspace2 = createWorkspace(5, 3);
     m_ads->addOrReplace("Name2", workspace2);
 
     addWorkspacesToModel(spectra, m_workspace, workspace2);
 
-    TS_ASSERT_EQUALS(m_model->getNumberHistograms(1), 5);
+    TS_ASSERT_EQUALS(m_model->getNumberHistograms(DatasetIndex{1}), 5);
   }
 
   void
   test_that_getResolution_will_return_the_a_nullptr_when_the_resolution_has_not_been_set() {
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
     auto const resolution = createWorkspace(5, 3);
 
     addWorkspacesToModel(spectra, m_workspace);
 
-    TS_ASSERT(!m_model->getResolution(0));
+    TS_ASSERT(!m_model->getResolution(DatasetIndex{0}));
   }
 
   void test_that_getResolution_will_return_the_workspace_which_it_was_set_at() {
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
     auto const resolution = createWorkspace(6, 3);
 
     addWorkspacesToModel(spectra, m_workspace);
-    m_model->setResolution(resolution, 0);
+    m_model->setResolution(resolution, DatasetIndex{0});
 
-    TS_ASSERT_EQUALS(m_model->getResolution(0), resolution);
+    TS_ASSERT_EQUALS(m_model->getResolution(DatasetIndex{0}), resolution);
   }
 
   void
   test_that_getResolution_will_return_the_a_nullptr_when_the_index_provided_is_out_of_range() {
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
     auto const resolution = createWorkspace(6, 3);
 
     addWorkspacesToModel(spectra, m_workspace);
-    m_model->setResolution(resolution, 0);
+    m_model->setResolution(resolution, DatasetIndex{0});
 
-    TS_ASSERT(!m_model->getResolution(2));
+    TS_ASSERT(!m_model->getResolution(DatasetIndex{2}));
   }
 
   void test_that_getSpectrumDependentAttributes_returns_workspace_index() {
@@ -174,42 +178,41 @@ public:
 
   void
   test_that_removeWorkspace_will_remove_the_workspace_specified_from_the_model() {
-    SpectraLegacy const spectra = DiscontinuousSpectra<std::size_t>("0-1");
+    Spectra const spectra = Spectra("0-1");
 
     addWorkspacesToModel(spectra, m_workspace);
-    m_model->removeWorkspace(0);
+    m_model->removeWorkspace(DatasetIndex{0});
 
-    TS_ASSERT_EQUALS(m_model->numberOfWorkspaces(), 0);
+    TS_ASSERT_EQUALS(m_model->numberOfWorkspaces(), DatasetIndex{0});
   }
 
   void
   test_that_setResolution_will_throw_when_provided_the_name_of_a_workspace_which_does_not_exist() {
-    TS_ASSERT_THROWS(m_model->setResolution("InvalidName", 0),
+    TS_ASSERT_THROWS(m_model->setResolution("InvalidName", DatasetIndex{0}),
                      const std::runtime_error &);
   }
 
   void
   test_that_setResolution_will_set_the_resolution_when_provided_a_correct_workspace_name() {
-    m_model->setResolution("Name", 0);
-    TS_ASSERT_EQUALS(m_model->getResolution(0), m_workspace);
+    m_model->setResolution("Name", DatasetIndex{0});
+    TS_ASSERT_EQUALS(m_model->getResolution(DatasetIndex{0}), m_workspace);
   }
 
   void
   test_that_setResolution_will_throw_when_provided_an_index_that_is_out_of_range() {
-    TS_ASSERT_THROWS(m_model->setResolution(m_workspace, 5),
+    TS_ASSERT_THROWS(m_model->setResolution(m_workspace, DatasetIndex{5}),
                      const std::out_of_range &);
   }
 
 private:
   template <typename Workspace, typename... Workspaces>
-  void addWorkspacesToModel(SpectraLegacy const &spectra,
-                            Workspace const &workspace,
+  void addWorkspacesToModel(Spectra const &spectra, Workspace const &workspace,
                             Workspaces const &... workspaces) {
     m_model->addWorkspace(workspace, spectra);
     addWorkspacesToModel(spectra, workspaces...);
   }
 
-  void addWorkspacesToModel(SpectraLegacy const &spectra,
+  void addWorkspacesToModel(Spectra const &spectra,
                             MatrixWorkspace_sptr const &workspace) {
     m_model->addWorkspace(workspace, spectra);
   }
@@ -219,4 +222,4 @@ private:
   std::unique_ptr<ConvFitModel> m_model;
 };
 
-#endif /* MANTIDQT_CONVFITMODELTEST_H_ */
+#endif /* MANTIDQT_CONVFITMODELTEST_H_ */
\ No newline at end of file