From 52a93f3213eace337c45b1e0d8afca0a4e277dcb Mon Sep 17 00:00:00 2001
From: Alice Russell <Alice.Russell@tessella.com>
Date: Mon, 10 Feb 2020 16:15:32 +0000
Subject: [PATCH] Re #27587 Add search box to selectFunctionDialog

---
 .../widgets/algorithmselector/widget.py       |  2 +-
 .../Common/SelectFunctionDialog.h             |  5 +++
 .../Common/SelectFunctionDialog.ui            | 38 ++++++++++++++----
 qt/widgets/common/src/FitPropertyBrowser.cpp  |  3 ++
 qt/widgets/common/src/FunctionTreeView.cpp    |  1 +
 .../common/src/SelectFunctionDialog.cpp       | 40 ++++++++++++++++---
 6 files changed, 76 insertions(+), 13 deletions(-)

diff --git a/qt/python/mantidqt/widgets/algorithmselector/widget.py b/qt/python/mantidqt/widgets/algorithmselector/widget.py
index c045540ea58..0621d996bb6 100644
--- a/qt/python/mantidqt/widgets/algorithmselector/widget.py
+++ b/qt/python/mantidqt/widgets/algorithmselector/widget.py
@@ -170,7 +170,7 @@ class AlgorithmSelectorWidget(IAlgorithmSelectorView, QWidget):
     def _on_search_box_selection_changed(self, text):
         """
         Called when text in the search box is changed by the user or script.
-        :param text: New text in the search box.
+        :param text: New text in the search box .
         """
         # if the function is called without text, avoid doing anything
         if text == '':
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/SelectFunctionDialog.h b/qt/widgets/common/inc/MantidQtWidgets/Common/SelectFunctionDialog.h
index 6dd0cb89943..e92ef5133a1 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/SelectFunctionDialog.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/SelectFunctionDialog.h
@@ -37,6 +37,8 @@ public:
   ~SelectFunctionDialog() override;
   /// Return selected function
   QString getFunction() const;
+  /// Clear the text in the search box
+  void clearSearchBoxText() const;
 
 protected:
   /// Ui elements form
@@ -48,6 +50,9 @@ private:
   constructFunctionTree(const std::map<std::string, std::vector<std::string>>
                             &categoryFunctionsMap,
                         const std::vector<std::string> &restrictions);
+
+private slots:
+  void searchBoxChanged(const QString &text);
 };
 
 } // namespace MantidWidgets
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/SelectFunctionDialog.ui b/qt/widgets/common/inc/MantidQtWidgets/Common/SelectFunctionDialog.ui
index 3b45639cc89..9d941b7e3df 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/SelectFunctionDialog.ui
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/SelectFunctionDialog.ui
@@ -15,13 +15,37 @@
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
-    <widget class="QTreeWidget" name="fitTree">
-     <column>
-      <property name="text">
-       <string>Fit - Select function type</string>
-      </property>
-     </column>
-    </widget>
+    <layout class="QVBoxLayout" name="verticalLayout_2">
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Fit - Select function type</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="searchBox">
+       <property name="editable">
+        <bool>true</bool>
+       </property>
+       <property name="insertPolicy">
+        <enum>QComboBox::NoInsert</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QTreeWidget" name="fitTree">
+       <attribute name="headerVisible">
+        <bool>false</bool>
+       </attribute>
+       <column>
+        <property name="text">
+         <string notr="true">1</string>
+        </property>
+       </column>
+      </widget>
+     </item>
+    </layout>
    </item>
    <item>
     <widget class="QDialogButtonBox" name="buttonBox">
diff --git a/qt/widgets/common/src/FitPropertyBrowser.cpp b/qt/widgets/common/src/FitPropertyBrowser.cpp
index 763326d7962..4c50a066310 100644
--- a/qt/widgets/common/src/FitPropertyBrowser.cpp
+++ b/qt/widgets/common/src/FitPropertyBrowser.cpp
@@ -757,6 +757,9 @@ void FitPropertyBrowser::acceptFit() {
   if (!cf)
     return;
   auto function = m_fitSelector->getFunction();
+  if (function.isEmpty()) {
+    return;
+  }
   PropertyHandler *h = getHandler()->findHandler(cf);
   h->addFunction(function.toStdString());
   emit functionChanged();
diff --git a/qt/widgets/common/src/FunctionTreeView.cpp b/qt/widgets/common/src/FunctionTreeView.cpp
index df5efa6c406..748715f2c85 100644
--- a/qt/widgets/common/src/FunctionTreeView.cpp
+++ b/qt/widgets/common/src/FunctionTreeView.cpp
@@ -1170,6 +1170,7 @@ void FunctionTreeView::addFunctionBegin() {
     connect(m_selectFunctionDialog, SIGNAL(finished(int)), this,
             SLOT(addFunctionEnd(int)));
   }
+  m_selectFunctionDialog->clearSearchBoxText();
   m_selectedFunctionProperty = prop;
   m_selectFunctionDialog->open();
 }
diff --git a/qt/widgets/common/src/SelectFunctionDialog.cpp b/qt/widgets/common/src/SelectFunctionDialog.cpp
index b5bd7db0180..05d92008784 100644
--- a/qt/widgets/common/src/SelectFunctionDialog.cpp
+++ b/qt/widgets/common/src/SelectFunctionDialog.cpp
@@ -18,6 +18,7 @@
 #include <QButtonGroup>
 #include <QCheckBox>
 #include <QComboBox>
+#include <QCompleter>
 #include <QGridLayout>
 #include <QGroupBox>
 #include <QLabel>
@@ -60,6 +61,15 @@ SelectFunctionDialog::SelectFunctionDialog(
     }
   }
 
+  // Set up the search box
+  m_form->searchBox->completer()->setCompletionMode(
+      QCompleter::PopupCompletion);
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+  m_form->searchBox->completer()->setFilterMode(Qt::MatchContains);
+#endif
+  connect(m_form->searchBox, SIGNAL(editTextChanged(const QString &)), this,
+          SLOT(searchBoxChanged(const QString &)));
+
   // Construct the QTreeWidget based on the map information of categories and
   // their respective fit functions.
   constructFunctionTree(categories, restrictions);
@@ -67,6 +77,8 @@ SelectFunctionDialog::SelectFunctionDialog(
   connect(m_form->fitTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
           this, SLOT(accept()));
   m_form->fitTree->setToolTip("Select a function type and press OK.");
+
+  m_form->searchBox->setCurrentIndex(-1);
 }
 
 /**
@@ -106,6 +118,7 @@ void SelectFunctionDialog::constructFunctionTree(
           for (const auto &function : entry.second) {
             QTreeWidgetItem *fit = new QTreeWidgetItem(catItem);
             fit->setText(0, QString::fromStdString(function));
+            m_form->searchBox->addItem(QString::fromStdString(function));
           }
         }
       } else {
@@ -141,6 +154,7 @@ void SelectFunctionDialog::constructFunctionTree(
               for (const auto &function : entry.second) {
                 QTreeWidgetItem *fit = new QTreeWidgetItem(catItem);
                 fit->setText(0, QString::fromStdString(function));
+                m_form->searchBox->addItem(QString::fromStdString(function));
               }
             }
           }
@@ -156,16 +170,32 @@ SelectFunctionDialog::~SelectFunctionDialog() { delete m_form; }
  * Return selected function
  */
 QString SelectFunctionDialog::getFunction() const {
+  const auto searchText = m_form->searchBox->currentText();
   QList<QTreeWidgetItem *> items(m_form->fitTree->selectedItems());
-  if (items.size() != 1) {
-    return "";
+  if (items.size() == 1 && items[0]->parent() != nullptr) {
+    return items[0]->text(0);
+  } else if (m_form->searchBox->findText(searchText) >= 0) {
+    return searchText;
   }
+  return "";
+}
 
-  if (items[0]->parent() == nullptr) {
-    return "";
+void SelectFunctionDialog::clearSearchBoxText() const {
+  m_form->searchBox->clearEditText();
+}
+
+/**
+ * Called when the text in the search box changes
+ */
+void SelectFunctionDialog::searchBoxChanged(const QString &text) {
+  if (text.isEmpty()) {
+    return;
   }
+  m_form->fitTree->setCurrentIndex(QModelIndex());
 
-  return items[0]->text(0);
+  const auto index = m_form->searchBox->findText(text);
+  if (index >= 0)
+    m_form->searchBox->setCurrentIndex(index);
 }
 
 } // namespace MantidWidgets
-- 
GitLab