From 8d1ed68714690437070d8875f03e1b6c3588be7e Mon Sep 17 00:00:00 2001
From: Matthias Puchner <github@mpuchner.de>
Date: Tue, 30 Nov 2021 17:57:28 +0100
Subject: [PATCH] refactor parameter tuning items to also accept
 DoubleDescriptors

---
 GUI/Model/Fit/ParameterTreeItems.cpp | 26 ++++++++--------
 GUI/Model/Fit/ParameterTreeItems.h   | 22 ++++++++++++--
 GUI/Model/Job/ParameterTreeUtils.cpp | 45 ++++++++++++++++++++++------
 3 files changed, 68 insertions(+), 25 deletions(-)

diff --git a/GUI/Model/Fit/ParameterTreeItems.cpp b/GUI/Model/Fit/ParameterTreeItems.cpp
index f5e218f8a73..2fc3ceb40ab 100644
--- a/GUI/Model/Fit/ParameterTreeItems.cpp
+++ b/GUI/Model/Fit/ParameterTreeItems.cpp
@@ -14,8 +14,12 @@
 
 #include "GUI/Model/Fit/ParameterTreeItems.h"
 #include "GUI/Model/Job/JobItem.h"
+#include "GUI/Model/Job/JobModelFunctions.h"
+#include "GUI/Model/Material/MaterialItem.h"
+#include "GUI/Model/Material/MaterialModel.h"
 #include "GUI/Model/Session/ModelPath.h"
 #include "GUI/Model/Session/SessionXML.h"
+#include "GUI/Model/Types/VectorDescriptor.h"
 #include "GUI/Util/DeserializationException.h"
 #include <QXmlStreamReader>
 #include <QXmlStreamWriter>
@@ -50,33 +54,29 @@ void ParameterItem::propagateValueToLink(double newValue)
 {
     setValue(newValue);
 
-    if (SessionItem* item = linkedItem())
-        item->setValue(newValue);
+    m_d.set(newValue);
 }
 
-//! Returns corresponding linked item in MultiLayerItem/InstrumentItem
-
-SessionItem* ParameterItem::linkedItem() const
+void ParameterItem::linkToMaterial(MaterialItem* material, DoubleDescriptor d)
 {
-    const SessionItem* jobItem = GUI::Model::Path::ancestor(this, JobItem::M_TYPE);
-    ASSERT(jobItem);
-    QString link = jobItem->itemName() + "/" + m_link;
-    return model()->itemForIndex(GUI::Model::Path::getIndexFromPath(model(), link));
+    m_link = d.path();
+    m_d = d;
 }
 
-void ParameterItem::setLink(const QString& link)
+void ParameterItem::linkToSessionItem(SessionItem* item)
 {
-    m_link = link;
+    m_link = GUI::Model::Path::getPathFromIndex(item->index());
+    m_d = DoubleDescriptor(item, "");
 }
 
 RealLimits ParameterItem::limitsOfLink() const
 {
-    return linkedItem()->limits();
+    return m_d.limits;
 }
 
 int ParameterItem::decimalsOfLink() const
 {
-    return linkedItem()->decimals();
+    return m_d.decimals;
 }
 
 QString ParameterItem::link() const
diff --git a/GUI/Model/Fit/ParameterTreeItems.h b/GUI/Model/Fit/ParameterTreeItems.h
index 54eba628651..a3ae523c94f 100644
--- a/GUI/Model/Fit/ParameterTreeItems.h
+++ b/GUI/Model/Fit/ParameterTreeItems.h
@@ -16,6 +16,9 @@
 #define BORNAGAIN_GUI_MODEL_FIT_PARAMETERTREEITEMS_H
 
 #include "GUI/Model/Session/SessionItem.h"
+#include "GUI/Model/Types/DoubleDescriptor.h"
+
+class MaterialItem;
 
 //! ParameterTreeItems is a collection of items necessary to form a tuning tree for
 //! real time widget.
@@ -39,15 +42,28 @@ public:
     ParameterItem();
 
     void propagateValueToLink(double newValue);
-    void setLink(const QString& link);
+
+    //! Unique string to identify this ParameterItem.
+    //!
+    //! The link is arbitrary. It can't be used for finding the linked item (therefore it does
+    //! not have to be a model path). However, it is used for comparison, also across project
+    //! load/save. Therefore the link is always the same, not e.g. an always generated UUID.
+    //! This link is used for setting backup values and for finding this ParameterItem when
+    //! referring from fit parameters.
     QString link() const;
 
+    //! Links this item to the given value of a material.
+    void linkToMaterial(MaterialItem* material, DoubleDescriptor d);
+
+    //! Links this item to the given session item.
+    void linkToSessionItem(SessionItem* item);
+
     RealLimits limitsOfLink() const;
     int decimalsOfLink() const;
 
 private:
-    SessionItem* linkedItem() const;
-    QString m_link; //!< Link to original PropertyItem
+    QString m_link;       //!< See docu of link()
+    DoubleDescriptor m_d; //!< The linked double value
 };
 
 //! The ParameterContainerItem is a top item to hold all ParameterItem, represents an entry
diff --git a/GUI/Model/Job/ParameterTreeUtils.cpp b/GUI/Model/Job/ParameterTreeUtils.cpp
index 7a7a2ca73c9..4d0bfb8568f 100644
--- a/GUI/Model/Job/ParameterTreeUtils.cpp
+++ b/GUI/Model/Job/ParameterTreeUtils.cpp
@@ -18,9 +18,11 @@
 #include "GUI/Model/Group/PropertyItem.h"
 #include "GUI/Model/Instrument/InstrumentItems.h"
 #include "GUI/Model/Job/JobItem.h"
-#include "GUI/Model/Material/MaterialItemContainer.h"
+#include "GUI/Model/Material/MaterialItem.h"
 #include "GUI/Model/Sample/MultiLayerItem.h"
 #include "GUI/Model/Session/ModelPath.h"
+#include "GUI/Model/Types/VectorDescriptor.h"
+
 #include "GUI/Util/Error.h"
 #include <QStack>
 
@@ -29,7 +31,7 @@ using boost::polymorphic_downcast;
 
 namespace {
 
-void handleItem(ParameterContainerItem* container, SessionItem* tree, const SessionItem* source,
+void handleItem(ParameterContainerItem* container, SessionItem* tree, SessionItem* source,
                 bool recreateBackupValues)
 {
     if (tree->hasModelType<ParameterLabelItem>())
@@ -38,13 +40,10 @@ void handleItem(ParameterContainerItem* container, SessionItem* tree, const Sess
     else if (tree->hasModelType<ParameterItem>()) {
         tree->setDisplayName(source->itemName());
 
-        double sourceValue = source->value().toDouble();
+        const double sourceValue = source->value().toDouble();
         tree->setValue(QVariant(sourceValue));
-        QString path = GUI::Model::Path::getPathFromIndex(source->index());
-        int firstSlash = path.indexOf('/');
-        path = path.mid(firstSlash + 1);
         auto* parItem = polymorphic_downcast<ParameterItem*>(tree);
-        parItem->setLink(path);
+        parItem->linkToSessionItem(source);
         if (recreateBackupValues)
             container->setBackupValue(parItem->link(), sourceValue);
         return;
@@ -78,7 +77,7 @@ void handleItem(ParameterContainerItem* container, SessionItem* tree, const Sess
 //! Populates ParameterContainer with ParameterItem's corresponding to all properties found
 //! in a source item.
 
-void populateParameterContainer(ParameterContainerItem* container, const SessionItem* source,
+void populateParameterContainer(ParameterContainerItem* container, SessionItem* source,
                                 bool recreateBackupValues)
 {
     auto* sourceLabel = container->model()->insertItem<ParameterLabelItem>(container);
@@ -94,9 +93,37 @@ void GUI::Model::ParameterTreeUtils::createParameterTree(JobItem* jobItem,
     if (!container)
         container = jobItem->createParameterContainerItem();
 
-    populateParameterContainer(container, jobItem->materialContainerItem(), recreateBackupValues);
+    // add the job's materials
+    auto* materialTopLabel = container->model()->insertItem<ParameterLabelItem>(container);
+    materialTopLabel->setDisplayName("Materials");
+    for (auto* material : jobItem->materialItems().materialItems()) {
+        auto* materialLabel = container->model()->insertItem<ParameterLabelItem>(container);
+        materialLabel->setDisplayName(material->materialName());
+
+        DoubleDescriptors descriptors;
+        if (material->hasRefractiveIndex())
+            descriptors << material->delta() << material->beta();
+        else
+            descriptors << material->sldRe() << material->sldIm();
+
+        // TODO: remove when specular instrument is ready for magnetization
+        if (!jobItem->isSpecularJob())
+            descriptors << material->magnetizationVector().x << material->magnetizationVector().y
+                        << material->magnetizationVector().z;
+
+        for (auto d : descriptors) {
+            auto* materialValue = materialLabel->model()->insertItem<ParameterItem>(materialLabel);
+            materialValue->setDisplayName(d.label);
+            materialValue->setValue(QVariant(d.get()));
+            materialValue->linkToMaterial(material, d);
+            if (recreateBackupValues)
+                container->setBackupValue(materialValue->link(), d.get());
+        }
+    }
 
+    // add sample
     populateParameterContainer(container, jobItem->sampleItem(), recreateBackupValues);
 
+    // add instrument
     populateParameterContainer(container, jobItem->instrumentItem(), recreateBackupValues);
 }
-- 
GitLab