From 6f0da2899d581ca77c1389e2c2736cf77d50f564 Mon Sep 17 00:00:00 2001
From: Tobias Knopff <t.knopff@fz-juelich.de>
Date: Tue, 11 May 2021 12:48:27 +0200
Subject: [PATCH] Use string constant for PointwiseAxisItem type name

---
 GUI/Models/BeamItems.cpp                      |  4 ++--
 GUI/Models/GroupInfoCatalog.cpp               |  3 ++-
 GUI/Models/GroupItem.cpp                      |  1 -
 GUI/Models/GroupItem.h                        |  8 +++++++
 GUI/Models/InstrumentModel.cpp                |  3 ++-
 GUI/Models/ItemCatalog.cpp                    |  2 +-
 GUI/Models/JobModel.cpp                       |  3 ++-
 GUI/Models/JobModelFunctions.cpp              |  6 ++---
 GUI/Models/PointwiseAxisItem.cpp              |  3 ++-
 GUI/Models/PointwiseAxisItem.h                |  1 +
 GUI/Models/SessionItem.h                      | 10 ++++++++
 GUI/Models/SpecularBeamInclinationItem.cpp    | 11 +++++----
 .../InstrumentViewActions.cpp                 | 12 ++++------
 .../UnitTests/GUI/TestSavingSpecularData.cpp  | 23 +++++++++----------
 14 files changed, 55 insertions(+), 35 deletions(-)

diff --git a/GUI/Models/BeamItems.cpp b/GUI/Models/BeamItems.cpp
index ebad6c5523e..ee595bebdfc 100644
--- a/GUI/Models/BeamItems.cpp
+++ b/GUI/Models/BeamItems.cpp
@@ -242,9 +242,9 @@ void SpecularBeamItem::updateToData(const IAxis& axis, QString units)
     }
 
     auto axis_group = inclinationAxisGroup();
-    auto axis_item = static_cast<PointwiseAxisItem*>(axis_group->getChildOfType("PointwiseAxis"));
+    auto axis_item = axis_group->firstChildOfType<PointwiseAxisItem>();
     axis_item->init(axis, units);
-    axis_group->setCurrentType("PointwiseAxis"); // calls updateWavelength()
+    axis_group->setCurrentType(PointwiseAxisItem::M_TYPE); // calls updateWavelength()
     axis_item->updateIndicators();
 }
 
diff --git a/GUI/Models/GroupInfoCatalog.cpp b/GUI/Models/GroupInfoCatalog.cpp
index fcca8814bf4..069a0109416 100644
--- a/GUI/Models/GroupInfoCatalog.cpp
+++ b/GUI/Models/GroupInfoCatalog.cpp
@@ -15,6 +15,7 @@
 #include "GUI/Models/GroupInfoCatalog.h"
 #include "GUI/Models/AxesItems.h"
 #include "GUI/Models/MaterialDataItems.h"
+#include "GUI/Models/PointwiseAxisItem.h"
 #include "GUI/utils/GUIHelpers.h"
 
 GroupInfoCatalog::GroupInfoCatalog()
@@ -189,7 +190,7 @@ GroupInfoCatalog::GroupInfoCatalog()
 
     info = GroupInfo("Axes group");
     info.add(BasicAxisItem::M_TYPE, "Uniform axis");
-    info.add("PointwiseAxis", "Non-uniform axis");
+    info.add(PointwiseAxisItem::M_TYPE, "Non-uniform axis");
     info.setDefaultType(BasicAxisItem::M_TYPE);
     addInfo(info);
 
diff --git a/GUI/Models/GroupItem.cpp b/GUI/Models/GroupItem.cpp
index 8631924deb2..4d828fc77ee 100644
--- a/GUI/Models/GroupItem.cpp
+++ b/GUI/Models/GroupItem.cpp
@@ -14,7 +14,6 @@
 
 #include "GUI/Models/GroupItem.h"
 #include "GUI/Models/ComboProperty.h"
-#include "GUI/Models/GroupItemController.h"
 #include "GUI/utils/GUIHelpers.h"
 
 const QString GroupItem::T_ITEMS = "Item tag";
diff --git a/GUI/Models/GroupItem.h b/GUI/Models/GroupItem.h
index 9376d00ddd6..b6cb094a034 100644
--- a/GUI/Models/GroupItem.h
+++ b/GUI/Models/GroupItem.h
@@ -16,6 +16,7 @@
 #define BORNAGAIN_GUI_MODELS_GROUPITEM_H
 
 #include "GUI/Models/GroupInfo.h"
+#include "GUI/Models/GroupItemController.h"
 #include "GUI/Models/SessionItem.h"
 #include <memory>
 
@@ -37,10 +38,17 @@ public:
 
     SessionItem* getItemOfType(const QString& type);
 
+    template <typename T> T* itemOfType() const;
+
 private:
     void onValueChange();
     void updateComboValue();
     std::unique_ptr<GroupItemController> m_controller;
 };
 
+template <typename T> T* GroupItem::itemOfType() const
+{
+    return dynamic_cast<T*>(m_controller->getItemOfType(T::M_TYPE));
+}
+
 #endif // BORNAGAIN_GUI_MODELS_GROUPITEM_H
diff --git a/GUI/Models/InstrumentModel.cpp b/GUI/Models/InstrumentModel.cpp
index 9382b817e8a..721f7687440 100644
--- a/GUI/Models/InstrumentModel.cpp
+++ b/GUI/Models/InstrumentModel.cpp
@@ -14,6 +14,7 @@
 
 #include "GUI/Models/InstrumentModel.h"
 #include "GUI/Models/InstrumentItems.h"
+#include "GUI/Models/PointwiseAxisItem.h"
 #include "GUI/Models/SpecularBeamInclinationItem.h"
 
 InstrumentModel::InstrumentModel(QObject* parent)
@@ -43,7 +44,7 @@ QVector<SessionItem*> InstrumentModel::nonXMLItems() const
                               ->inclinationAngleItem()
                               ->getItem(SpecularBeamInclinationItem::P_ALPHA_AXIS);
 
-        if (auto pointwise_axis = axis_group->getChildOfType("PointwiseAxis"))
+        if (auto pointwise_axis = axis_group->firstChildOfType<PointwiseAxisItem>())
             result.push_back(pointwise_axis);
     }
 
diff --git a/GUI/Models/ItemCatalog.cpp b/GUI/Models/ItemCatalog.cpp
index 976e533e87b..461b1a726a4 100644
--- a/GUI/Models/ItemCatalog.cpp
+++ b/GUI/Models/ItemCatalog.cpp
@@ -180,7 +180,7 @@ ItemCatalog::ItemCatalog()
     add("DataItem1DProperties", create_new<Data1DProperties>);
 
     addItem<BasicAxisItem>();
-    add("PointwiseAxis", create_new<PointwiseAxisItem>);
+    addItem<PointwiseAxisItem>();
     addItem<AmplitudeAxisItem>();
 
     add("BeamWavelength", create_new<BeamWavelengthItem>);
diff --git a/GUI/Models/JobModel.cpp b/GUI/Models/JobModel.cpp
index 8c0f945741d..e85f29cd28b 100644
--- a/GUI/Models/JobModel.cpp
+++ b/GUI/Models/JobModel.cpp
@@ -25,6 +25,7 @@
 #include "GUI/Models/MultiLayerItem.h"
 #include "GUI/Models/ParameterTreeItems.h"
 #include "GUI/Models/ParameterTreeUtils.h"
+#include "GUI/Models/PointwiseAxisItem.h"
 #include "GUI/Models/RealDataItem.h"
 #include "GUI/Models/SimulationOptionsItem.h"
 #include "GUI/utils/GUIHelpers.h"
@@ -151,7 +152,7 @@ QVector<SessionItem*> JobModel::nonXMLItems() const
             dynamic_cast<SpecularInstrumentItem*>(jobItem->getItem(JobItem::T_INSTRUMENT));
         if (instrument) {
             auto axis_group = instrument->beamItem()->inclinationAxisGroup();
-            result.push_back(axis_group->getChildOfType("PointwiseAxis"));
+            result.push_back(axis_group->firstChildOfType<PointwiseAxisItem>());
         }
     }
 
diff --git a/GUI/Models/JobModelFunctions.cpp b/GUI/Models/JobModelFunctions.cpp
index 5958b2ba63f..4020bba81ae 100644
--- a/GUI/Models/JobModelFunctions.cpp
+++ b/GUI/Models/JobModelFunctions.cpp
@@ -129,7 +129,7 @@ void JobModelFunctions::setupJobItemInstrument(JobItem* jobItem, const Instrumen
     auto spec_from = static_cast<const SpecularInstrumentItem*>(from);
     auto axis_origin = getPointwiseAxisItem(spec_from);
     const QString current_axis_type = spec_from->beamItem()->inclinationAxisGroup()->currentType();
-    if (current_axis_type == "PointwiseAxis")
+    if (current_axis_type == PointwiseAxisItem::M_TYPE)
         spec_to->beamItem()->updateToData(*axis_origin->axis(), axis_origin->getUnitsLabel());
     else if (axis_origin->containsNonXMLData())
         getPointwiseAxisItem(spec_to)->init(*axis_origin->axis(), axis_origin->getUnitsLabel());
@@ -291,7 +291,7 @@ void createFitContainers(JobItem* jobItem)
 
 PointwiseAxisItem* getPointwiseAxisItem(const SpecularInstrumentItem* instrument)
 {
-    return dynamic_cast<PointwiseAxisItem*>(
-        instrument->beamItem()->inclinationAxisGroup()->getChildOfType("PointwiseAxis"));
+    return instrument->beamItem()->inclinationAxisGroup()
+        ->firstChildOfType<PointwiseAxisItem>();
 }
 } // namespace
diff --git a/GUI/Models/PointwiseAxisItem.cpp b/GUI/Models/PointwiseAxisItem.cpp
index 0fe9796f7c6..cd26fbf58e9 100644
--- a/GUI/Models/PointwiseAxisItem.cpp
+++ b/GUI/Models/PointwiseAxisItem.cpp
@@ -34,8 +34,9 @@ std::unique_ptr<OutputData<double>> makeOutputData(const IAxis& axis)
 const QString PointwiseAxisItem::P_NATIVE_AXIS_UNITS = "NativeAxisUnits";
 const QString PointwiseAxisItem::P_FILE_NAME = "FileName";
 
+const QString PointwiseAxisItem::M_TYPE = "PointwiseAxis";
 
-PointwiseAxisItem::PointwiseAxisItem() : BasicAxisItem("PointwiseAxis"), m_instrument(nullptr)
+PointwiseAxisItem::PointwiseAxisItem() : BasicAxisItem(M_TYPE), m_instrument(nullptr)
 {
     lowerBoundItem()->setEnabled(false);
     binsItem()->setEnabled(false);
diff --git a/GUI/Models/PointwiseAxisItem.h b/GUI/Models/PointwiseAxisItem.h
index 375b58df969..b68771bdc43 100644
--- a/GUI/Models/PointwiseAxisItem.h
+++ b/GUI/Models/PointwiseAxisItem.h
@@ -29,6 +29,7 @@ private:
     static const QString P_FILE_NAME;
 
 public:
+    static const QString M_TYPE;
 
     explicit PointwiseAxisItem();
     ~PointwiseAxisItem() override;
diff --git a/GUI/Models/SessionItem.h b/GUI/Models/SessionItem.h
index 6351cf97a5d..0ff1ede2fdc 100644
--- a/GUI/Models/SessionItem.h
+++ b/GUI/Models/SessionItem.h
@@ -50,6 +50,7 @@ public:
     int rowOfChild(SessionItem* child) const;
     SessionItem* getChildOfType(const QString& type) const;
     QVector<SessionItem*> getChildrenOfType(const QString& model_type) const;
+    template <typename T> T* firstChildOfType() const;
     SessionItem* takeRow(int row);
 
     // manage and check tags
@@ -161,6 +162,15 @@ template <typename T> QVector<T*> SessionItem::items(const QString& tag) const
     return result;
 }
 
+template <typename T> T* SessionItem::firstChildOfType() const
+{
+    for (auto child : m_children)
+        if (child->modelType() == T::M_TYPE)
+            return dynamic_cast<T*>(child);
+
+    return nullptr;
+}
+
 template <typename T> T* SessionItem::addProperty(const QString& tagname)
 {
     auto property = new T;
diff --git a/GUI/Models/SpecularBeamInclinationItem.cpp b/GUI/Models/SpecularBeamInclinationItem.cpp
index 058a1727a50..dd972931d8a 100644
--- a/GUI/Models/SpecularBeamInclinationItem.cpp
+++ b/GUI/Models/SpecularBeamInclinationItem.cpp
@@ -44,8 +44,8 @@ double SpecularBeamInclinationItem::scaleFactor() const
 void SpecularBeamInclinationItem::updateFileName(const QString& filename)
 {
     auto group_item = item<GroupItem>(P_ALPHA_AXIS);
-    SessionItem* item = group_item->getChildOfType("PointwiseAxis");
-    PointwiseAxisItem* axis_item = dynamic_cast<PointwiseAxisItem*>(item);
+    PointwiseAxisItem* axis_item =
+        group_item->firstChildOfType<PointwiseAxisItem>();
     ASSERT(axis_item);
     axis_item->setFileName(filename);
 }
@@ -59,7 +59,7 @@ void SpecularBeamInclinationItem::setupAxisGroup()
     // handling (no signal emulation required).
     // Basic axis item is the default one.
 
-    group_item->setCurrentType("PointwiseAxis");
+    group_item->setCurrentType(PointwiseAxisItem::M_TYPE);
     setAxisPresentationDefaults(group_item->currentItem(), group_item->currentType());
 
     group_item->setCurrentType(BasicAxisItem::M_TYPE);
@@ -70,7 +70,8 @@ void SpecularBeamInclinationItem::setupAxisGroup()
     group_item->setEnabled(false);
     group_item->mapper()->setOnValueChange(
         [group_item]() {
-            if (group_item->currentItem()->modelType() == "PointwiseAxis")
+            if (group_item->currentItem()->modelType()
+                == PointwiseAxisItem::M_TYPE)
                 group_item->setEnabled(true);
         },
         this);
@@ -106,7 +107,7 @@ void setAxisPresentationDefaults(SessionItem* item, const QString& type)
         axis_item->setLowerBound(0.0);
         axis_item->setUpperBound(3.0);
         axis_item->setBinCount(500);
-    } else if (type == "PointwiseAxis") {
+    } else if (type == PointwiseAxisItem::M_TYPE) {
         axis_item->lowerBoundItem()->setEnabled(false);
         axis_item->upperBoundItem()->setEnabled(false);
         axis_item->binsItem()->setEnabled(false);
diff --git a/GUI/Views/InstrumentWidgets/InstrumentViewActions.cpp b/GUI/Views/InstrumentWidgets/InstrumentViewActions.cpp
index 7ab423affae..143b7a9bbb0 100644
--- a/GUI/Views/InstrumentWidgets/InstrumentViewActions.cpp
+++ b/GUI/Views/InstrumentWidgets/InstrumentViewActions.cpp
@@ -104,16 +104,14 @@ void InstrumentViewActions::onCloneInstrument()
         if (auto instrument = dynamic_cast<SpecularInstrumentItem*>(item)) {
             auto axis_group = instrument->beamItem()->inclinationAxisGroup();
 
-            auto donor_axis =
-                dynamic_cast<PointwiseAxisItem*>(axis_group->getItemOfType("PointwiseAxis"));
+            auto donor_axis = axis_group->itemOfType<PointwiseAxisItem>();
             if (!donor_axis->containsNonXMLData())
                 return;
 
-            auto acceptor_axis =
-                dynamic_cast<PointwiseAxisItem*>(dynamic_cast<SpecularInstrumentItem*>(clone)
-                                                     ->beamItem()
-                                                     ->inclinationAxisGroup()
-                                                     ->getItemOfType("PointwiseAxis"));
+            auto acceptor_axis = dynamic_cast<SpecularInstrumentItem*>(clone)
+                                     ->beamItem()
+                                     ->inclinationAxisGroup()
+                                     ->itemOfType<PointwiseAxisItem>();
             acceptor_axis->init(*donor_axis->axis(), donor_axis->getUnitsLabel());
         }
     }
diff --git a/Tests/UnitTests/GUI/TestSavingSpecularData.cpp b/Tests/UnitTests/GUI/TestSavingSpecularData.cpp
index b4a4eb2d9fd..5efe5c93ea8 100644
--- a/Tests/UnitTests/GUI/TestSavingSpecularData.cpp
+++ b/Tests/UnitTests/GUI/TestSavingSpecularData.cpp
@@ -45,8 +45,7 @@ SpecularInstrumentItem* TestSavingSpecularData::createSpecularInstrument(Applica
 PointwiseAxisItem* TestSavingSpecularData::createPointwiseAxisItem(SessionModel& model)
 {
     auto instrument_item = model.insertItem<SpecularInstrumentItem>();
-    return dynamic_cast<PointwiseAxisItem*>(
-        getAxisGroup(instrument_item)->getChildOfType("PointwiseAxis"));
+    return getAxisGroup(instrument_item)->firstChildOfType<PointwiseAxisItem>();
 }
 
 GroupItem* TestSavingSpecularData::getAxisGroup(SpecularInstrumentItem* instrument)
@@ -82,7 +81,7 @@ TEST_F(TestSavingSpecularData, test_SpecularInsturment)
 
     // explicitly switching to pointwise axis item
     auto axis_group = getAxisGroup(instrument);
-    axis_group->setCurrentType("PointwiseAxis");
+    axis_group->setCurrentType(PointwiseAxisItem::M_TYPE);
     EXPECT_EQ(models.instrumentModel()->nonXMLItems().size(), 1);
 
     // hiding pointwise axis item back
@@ -116,7 +115,7 @@ TEST_F(TestSavingSpecularData, test_InstrumentInJobItem)
 
     // explicitly switching to pointwise axis item
     auto axis_group = getAxisGroup(instrument);
-    axis_group->setCurrentType("PointwiseAxis");
+    axis_group->setCurrentType(PointwiseAxisItem::M_TYPE);
     EXPECT_EQ(models.jobModel()->nonXMLItems().size(), 2);
 
     OutputDataIOService service(&models);
@@ -202,13 +201,13 @@ TEST_F(TestSavingSpecularData, test_OutputDataIOService)
     auto instrument2 = createSpecularInstrument(models);
 
     auto axis_group1 = getAxisGroup(instrument1);
-    auto pointwise_axis_item1 =
-        dynamic_cast<PointwiseAxisItem*>(axis_group1->getChildOfType("PointwiseAxis"));
+    PointwiseAxisItem* pointwise_axis_item1 =
+        axis_group1->firstChildOfType<PointwiseAxisItem>();
     pointwise_axis_item1->init(*m_axis, "Degrees");
 
     auto axis_group2 = getAxisGroup(instrument2);
-    auto pointwise_axis_item2 =
-        dynamic_cast<PointwiseAxisItem*>(axis_group2->getChildOfType("PointwiseAxis"));
+    PointwiseAxisItem* pointwise_axis_item2 =
+        axis_group2->firstChildOfType<PointwiseAxisItem>();
     PointwiseAxis tmp("y", std::vector<double>{1.0, 2.0, 3.0});
     pointwise_axis_item2->init(tmp, "Radians");
 
@@ -260,8 +259,8 @@ TEST_F(TestSavingSpecularData, test_CopyInstrumentToJobItem)
     // adding instrument and initializing pointwise axis
     auto instrument = createSpecularInstrument(models);
     auto axis_group = getAxisGroup(instrument);
-    auto pointwise_axis_item =
-        dynamic_cast<PointwiseAxisItem*>(axis_group->getChildOfType("PointwiseAxis"));
+    PointwiseAxisItem* pointwise_axis_item =
+        axis_group->firstChildOfType<PointwiseAxisItem>();
     pointwise_axis_item->init(*m_axis, "q-space");
 
     // adding JobItem and copying instrument
@@ -269,8 +268,8 @@ TEST_F(TestSavingSpecularData, test_CopyInstrumentToJobItem)
     JobModelFunctions::setupJobItemInstrument(jobItem, instrument);
     auto job_instrument =
         dynamic_cast<SpecularInstrumentItem*>(jobItem->getItem(JobItem::T_INSTRUMENT));
-    auto job_axis_item = dynamic_cast<PointwiseAxisItem*>(
-        getAxisGroup(job_instrument)->getChildOfType("PointwiseAxis"));
+    PointwiseAxisItem* job_axis_item =
+        getAxisGroup(job_instrument)->firstChildOfType<PointwiseAxisItem>();
 
     // checking filenames
     EXPECT_EQ(pointwise_axis_item->fileName(),
-- 
GitLab