From 072e02cfb1835999359ea66725bec5bebfffaaf9 Mon Sep 17 00:00:00 2001
From: Matthias Puchner <github@mpuchner.de>
Date: Tue, 30 Nov 2021 15:46:02 +0100
Subject: [PATCH] rm SessionItem from MaterialItem

---
 GUI/Model/Material/MaterialDataItems.cpp |  48 ----
 GUI/Model/Material/MaterialDataItems.h   |  51 ----
 GUI/Model/Material/MaterialItem.cpp      | 322 +++++++++++++++--------
 GUI/Model/Material/MaterialItem.h        |  63 +++--
 GUI/Model/Session/ModelPath.cpp          |   6 +
 GUI/Model/Session/ModelPath.h            |   3 +
 6 files changed, 264 insertions(+), 229 deletions(-)
 delete mode 100644 GUI/Model/Material/MaterialDataItems.cpp
 delete mode 100644 GUI/Model/Material/MaterialDataItems.h

diff --git a/GUI/Model/Material/MaterialDataItems.cpp b/GUI/Model/Material/MaterialDataItems.cpp
deleted file mode 100644
index ebd044005cd..00000000000
--- a/GUI/Model/Material/MaterialDataItems.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      GUI/Model/Material/MaterialDataItems.cpp
-//! @brief     Implements MaterialDataItems classes
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#include "GUI/Model/Material/MaterialDataItems.h"
-
-MaterialDataItem::MaterialDataItem(const QString& modelType) : SessionItem(modelType)
-{
-    setEditable(false); // empty label, non-editable
-}
-
-// ------------------------------------------------------------------------------------------------
-
-MaterialRefractiveDataItem::MaterialRefractiveDataItem() : MaterialDataItem(M_TYPE)
-{
-    addProperty(P_DELTA, 0.0)
-        ->setEditorType("ScientificDouble")
-        .setLimits(RealLimits::limitless())
-        .setToolTip("Delta of refractive index (n = 1 - delta + i*beta)");
-    addProperty(P_BETA, 0.0)
-        ->setEditorType("ScientificDouble")
-        .setLimits(RealLimits::limitless())
-        .setToolTip("Beta of refractive index (n = 1 - delta + i*beta)");
-}
-
-// ------------------------------------------------------------------------------------------------
-
-MaterialSLDDataItem::MaterialSLDDataItem() : MaterialDataItem(M_TYPE)
-{
-    addProperty(P_SLD_REAL, 0.0)
-        ->setEditorType("ScientificDouble")
-        .setLimits(RealLimits::limitless())
-        .setToolTip("Real part of SLD (SLD = real - i*imag), AA^{-2}");
-    addProperty(P_SLD_IMAG, 0.0)
-        ->setEditorType("ScientificDouble")
-        .setLimits(RealLimits::limitless())
-        .setToolTip("Imaginary part of SLD (SLD = real - i*imag), AA^{-2}");
-}
diff --git a/GUI/Model/Material/MaterialDataItems.h b/GUI/Model/Material/MaterialDataItems.h
deleted file mode 100644
index ea25e70dd75..00000000000
--- a/GUI/Model/Material/MaterialDataItems.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      GUI/Model/Material/MaterialDataItems.h
-//! @brief     Defines MaterialDataItems classes
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#ifndef BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALDATAITEMS_H
-#define BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALDATAITEMS_H
-
-#include "GUI/Model/Session/SessionItem.h"
-
-class BA_CORE_API_ MaterialDataItem : public SessionItem {
-protected:
-    MaterialDataItem(const QString& modelType);
-};
-
-class MaterialRefractiveDataItem : public MaterialDataItem {
-private:
-    static constexpr auto P_DELTA{"Delta"};
-    static constexpr auto P_BETA{"Beta"};
-
-public:
-    static constexpr auto M_TYPE{"MaterialRefractiveData"};
-
-    MaterialRefractiveDataItem();
-
-    friend class MaterialItem;
-};
-
-class MaterialSLDDataItem : public MaterialDataItem {
-private:
-    static constexpr auto P_SLD_REAL{"SLD, real"};
-    static constexpr auto P_SLD_IMAG{"SLD, imaginary"};
-
-public:
-    static constexpr auto M_TYPE{"MaterialSLDData"};
-
-    MaterialSLDDataItem();
-
-    friend class MaterialItem;
-};
-
-#endif // BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALDATAITEMS_H
diff --git a/GUI/Model/Material/MaterialItem.cpp b/GUI/Model/Material/MaterialItem.cpp
index 03257f19837..a9defd62f76 100644
--- a/GUI/Model/Material/MaterialItem.cpp
+++ b/GUI/Model/Material/MaterialItem.cpp
@@ -14,179 +14,293 @@
 
 #include "GUI/Model/Material/MaterialItem.h"
 #include "Base/Util/Assert.h"
-#include "GUI/Model/Group/GroupInfo.h"
-#include "GUI/Model/Material/MaterialDataItems.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 "Sample/Material/MaterialFactoryFuncs.h"
 #include <QColor>
 #include <QUuid>
+#include <QXmlStreamReader>
 
-namespace {
-
-const QString magnetization_tooltip = "Magnetization (A/m)";
+using namespace GUI::Session::XML;
 
+namespace {
+namespace Tags {
+const QString Color("Color");
+const QString Id("Id");
+const QString Name("Name");
+const QString Delta("Delta");
+const QString Beta("Beta");
+const QString Sld("Sld");
+const QString Magnetization("Magnetization");
+} // namespace Tags
+} // namespace
+
+#define m_delta std::get<Refractive>(m_data).delta
+#define m_beta std::get<Refractive>(m_data).beta
+
+#define m_real std ::get<complex_t>(m_data).real()
+#define m_imag std ::get<complex_t>(m_data).imag()
+
+MaterialItem::MaterialItem() : m_data(Refractive(0.0, 0.0))
+{
+    m_color = Qt::red;
+    m_id = QUuid::createUuid().toString();
 }
 
-
-MaterialItem::MaterialItem() : SessionItem(M_TYPE)
+MaterialItem::MaterialItem(const MaterialItem& other)
+    : m_name(other.m_name)
+    , m_id(other.m_id)
+    , m_color(other.m_color)
+    , m_data(other.m_data)
+    , m_magnetization(other.m_magnetization)
 {
-    setItemName("Material");
-
-    addProperty(P_COLOR, QColor(Qt::red));
-
-    GroupInfo info;
-    info.add(MaterialRefractiveDataItem::M_TYPE, "Refractive index based");
-    info.add(MaterialSLDDataItem::M_TYPE, "SLD based");
-    info.setDefaultType(MaterialRefractiveDataItem::M_TYPE);
-    addGroupProperty(P_MATERIAL_DATA, info);
-
-    addProperty<VectorItem>(P_MAGNETIZATION)->setToolTip(magnetization_tooltip);
-    addProperty(P_IDENTIFIER, QUuid::createUuid().toString());
-    getItem(P_IDENTIFIER)->setVisible(false);
 }
 
-//! Turns material into refractive index material.
-
 void MaterialItem::setRefractiveIndex(const double delta, const double beta)
 {
-    auto* refractiveData = setGroupProperty(P_MATERIAL_DATA, MaterialRefractiveDataItem::M_TYPE);
-    refractiveData->setItemValue(MaterialRefractiveDataItem::P_DELTA, delta);
-    refractiveData->setItemValue(MaterialRefractiveDataItem::P_BETA, beta);
-}
+    const Refractive r(delta, beta);
+    if (hasRefractiveIndex() && std::get<Refractive>(m_data) == r)
+        return;
 
-//! Turns material into SLD based material.
+    m_data = r;
+    emit dataChanged();
+}
 
 void MaterialItem::setScatteringLengthDensity(const complex_t sld)
 {
-    auto* sldData = setGroupProperty(P_MATERIAL_DATA, MaterialSLDDataItem::M_TYPE);
-    sldData->setItemValue(MaterialSLDDataItem::P_SLD_REAL, sld.real());
-    sldData->setItemValue(MaterialSLDDataItem::P_SLD_IMAG, sld.imag());
+    if (!hasRefractiveIndex() && std::get<complex_t>(m_data) == sld)
+        return;
+
+    m_data = sld;
+    emit dataChanged();
 }
 
 DoubleDescriptor MaterialItem::delta()
 {
-    return DoubleDescriptor(
-        getGroupItem(P_MATERIAL_DATA)->getItem(MaterialRefractiveDataItem::P_DELTA),
-        Unit::unitless);
+    ASSERT(hasRefractiveIndex());
+    const auto setter = [=](double v) {
+        if (m_delta != v) {
+            m_delta = v;
+            emit dataChanged();
+        }
+    };
+
+    DoubleDescriptor d(
+        "Delta", "Delta of refractive index (n = 1 - delta + i*beta)", 3, RealLimits::limitless(),
+        setter, [=] { return m_delta; }, Unit::unitless);
+    d.path = [=] { return GUI::Model::Path::getPathFromItem(this) + "/delta"; };
+    return d;
 }
 
 DoubleDescriptor MaterialItem::beta()
 {
-    return DoubleDescriptor(
-        getGroupItem(P_MATERIAL_DATA)->getItem(MaterialRefractiveDataItem::P_BETA), Unit::unitless);
+    ASSERT(hasRefractiveIndex());
+    const auto setter = [=](double v) {
+        if (m_beta != v) {
+            m_beta = v;
+            emit dataChanged();
+        }
+    };
+
+    DoubleDescriptor d(
+        "Beta", "Beta of refractive index (n = 1 - delta + i*beta)", 3, RealLimits::limitless(),
+        setter, [=] { return m_beta; }, Unit::unitless);
+    d.path = [=] { return GUI::Model::Path::getPathFromItem(this) + "/beta"; };
+    return d;
 }
 
 DoubleDescriptor MaterialItem::sldRe()
 {
-    return DoubleDescriptor(getGroupItem(P_MATERIAL_DATA)->getItem(MaterialSLDDataItem::P_SLD_REAL),
-                            Unit::unitless);
+    ASSERT(!hasRefractiveIndex());
+    const auto setter = [=](double v) {
+        if (m_real != v) {
+            std::get<complex_t>(m_data).real(v);
+            emit dataChanged();
+        }
+    };
+
+    DoubleDescriptor d(
+        "SLD, real", "Real part of SLD (SLD = real - i*imag), AA^{-2}", 3, RealLimits::limitless(),
+        setter, [=] { return m_real; }, Unit::unitless);
+    d.path = [=] { return GUI::Model::Path::getPathFromItem(this) + "/re"; };
+    return d;
 }
 
 DoubleDescriptor MaterialItem::sldIm()
 {
-    return DoubleDescriptor(getGroupItem(P_MATERIAL_DATA)->getItem(MaterialSLDDataItem::P_SLD_IMAG),
-                            Unit::unitless);
+    ASSERT(!hasRefractiveIndex());
+    const auto setter = [=](double v) {
+        if (m_imag != v) {
+            std::get<complex_t>(m_data).imag(v);
+            emit dataChanged();
+        }
+    };
+
+    DoubleDescriptor d(
+        "SLD, imaginary", "Imaginary part of SLD (SLD = real - i*imag), AA^{-2}", 3,
+        RealLimits::limitless(), setter, [=] { return m_imag; }, Unit::unitless);
+    d.path = [=] { return GUI::Model::Path::getPathFromItem(this) + "/im"; };
+    return d;
 }
 
 VectorDescriptor MaterialItem::magnetizationVector()
 {
-    return VectorDescriptor(item<VectorItem>(P_MAGNETIZATION), "A/m");
+    VectorDescriptor d("Magnetization", "Magnetization (A/m)", "A/m");
+
+    d.x.set = [=](double v) {
+        if (m_magnetization.x() != v) {
+            m_magnetization.setX(v);
+            emit dataChanged();
+        }
+    };
+    d.x.get = [=]() { return m_magnetization.x(); };
+    d.x.path = [=] { return GUI::Model::Path::getPathFromItem(this) + "/mx"; };
+
+    d.y.set = [=](double v) {
+        if (m_magnetization.y() != v) {
+            m_magnetization.setY(v);
+            emit dataChanged();
+        }
+    };
+    d.y.get = [=]() { return m_magnetization.y(); };
+    d.y.path = [=] { return GUI::Model::Path::getPathFromItem(this) + "/my"; };
+
+    d.z.set = [=](double v) {
+        if (m_magnetization.z() != v) {
+            m_magnetization.setZ(v);
+            emit dataChanged();
+        }
+    };
+    d.z.get = [=]() { return m_magnetization.z(); };
+    d.z.path = [=] { return GUI::Model::Path::getPathFromItem(this) + "/mz"; };
+
+    return d;
 }
 
 bool MaterialItem::hasRefractiveIndex() const
 {
-    SessionItem* data = getGroupItem(P_MATERIAL_DATA);
-    ASSERT(data);
-    return dynamic_cast<MaterialRefractiveDataItem*>(data) != nullptr;
-}
-
-double MaterialItem::refractiveIndexDelta() const
-{
-    ASSERT(hasRefractiveIndex());
-    return getGroupItem(P_MATERIAL_DATA)
-        ->getItemValue(MaterialRefractiveDataItem::P_DELTA)
-        .toDouble();
-}
-
-double MaterialItem::refractiveIndexBeta() const
-{
-    ASSERT(hasRefractiveIndex());
-    return getGroupItem(P_MATERIAL_DATA)
-        ->getItemValue(MaterialRefractiveDataItem::P_BETA)
-        .toDouble();
-}
-
-complex_t MaterialItem::scatteringLengthDensity() const
-{
-    ASSERT(!hasRefractiveIndex());
-    SessionItem* ri = getGroupItem(P_MATERIAL_DATA);
-    double real = ri->getItemValue(MaterialSLDDataItem::P_SLD_REAL).toDouble();
-    double imag = ri->getItemValue(MaterialSLDDataItem::P_SLD_IMAG).toDouble();
-    return complex_t(real, imag);
+    return std::holds_alternative<Refractive>(m_data);
 }
 
 QString MaterialItem::materialName() const
 {
-    return itemName();
+    return m_name;
 }
 
 void MaterialItem::setMaterialName(const QString& name)
 {
-    setItemName(name);
+    if (m_name != name) {
+        m_name = name;
+        emit dataChanged();
+    }
 }
 
 QString MaterialItem::identifier() const
 {
-    return getItemValue(P_IDENTIFIER).toString();
+    return m_id;
 }
 
 void MaterialItem::setIdentifier(const QString& id)
 {
-    setItemValue(P_IDENTIFIER, id);
+    m_id = id;
+    // no "emit dataChanged()" here
+}
+
+void MaterialItem::createNewIdentifier()
+{
+    m_id = QUuid::createUuid().toString();
+    // no "emit dataChanged()" here
 }
 
 QColor MaterialItem::color() const
 {
-    return getItemValue(P_COLOR).value<QColor>();
+    return m_color;
 }
 
 void MaterialItem::setColor(const QColor& color)
 {
-    setItemValue(P_COLOR, color);
+    if (m_color != color) {
+        m_color = color;
+        emit dataChanged();
+    }
 }
 
 R3 MaterialItem::magnetization() const
 {
-    return item<VectorItem>(P_MAGNETIZATION)->getVector();
+    return m_magnetization;
 }
 
 void MaterialItem::setMagnetization(const R3& magnetization)
 {
-    item<VectorItem>(P_MAGNETIZATION)->setVector(magnetization);
+    if (m_magnetization != magnetization) {
+        m_magnetization = magnetization;
+        emit dataChanged();
+    }
 }
 
-void MaterialItem::hideMagnetization()
+std::unique_ptr<Material> MaterialItem::createMaterial() const
 {
-    getItem(MaterialItem::P_MAGNETIZATION)->setVisible(false);
+    if (hasRefractiveIndex())
+        return std::make_unique<Material>(
+            HomogeneousMaterial(materialName().toStdString(), m_delta, m_beta, m_magnetization));
+
+    return std::make_unique<Material>(
+        MaterialBySLD(materialName().toStdString(), m_real, m_imag, m_magnetization));
 }
 
-std::unique_ptr<Material> MaterialItem::createMaterial() const
+void MaterialItem::writeContentTo(QXmlStreamWriter* writer) const
 {
-    auto* dataItem = getGroupItem(P_MATERIAL_DATA);
-    auto magnetization = item<VectorItem>(P_MAGNETIZATION)->getVector();
-    auto name = itemName().toStdString();
+    writeAttribute(writer, GUI::Session::XML::Version, int(1));
+
+    writeAttribute(writer, Tags::Id, m_id);
+    writeAttribute(writer, Tags::Color, m_color);
+    writeAttribute(writer, Tags::Name, m_name);
+    writeAttribute(writer, Tags::Magnetization, m_magnetization);
 
-    if (dataItem->modelType() == MaterialRefractiveDataItem::M_TYPE) {
-        double delta = dataItem->getItemValue(MaterialRefractiveDataItem::P_DELTA).toDouble();
-        double beta = dataItem->getItemValue(MaterialRefractiveDataItem::P_BETA).toDouble();
-        return std::make_unique<Material>(HomogeneousMaterial(name, delta, beta, magnetization));
+    if (hasRefractiveIndex()) {
+        writeAttribute(writer, Tags::Delta, m_delta);
+        writeAttribute(writer, Tags::Beta, m_beta);
+    } else
+        writeAttribute(writer, Tags::Sld, std::get<complex_t>(m_data));
+}
+
+void MaterialItem::readContentFrom(QXmlStreamReader* reader)
+{
+    const int version = reader->attributes().value(GUI::Session::XML::Version).toInt();
+
+    if (version < 1)
+        throw DeserializationException::tooOld();
+
+    if (version > 1)
+        throw DeserializationException::tooNew();
+
+    readAttribute(reader, Tags::Id, &m_id);
+    readAttribute(reader, Tags::Color, &m_color);
+    readAttribute(reader, Tags::Name, &m_name);
+    readAttribute(reader, Tags::Magnetization, &m_magnetization);
+    if (reader->attributes().hasAttribute(Tags::Delta)) {
+        double d, b;
+        readAttribute(reader, Tags::Delta, &d);
+        readAttribute(reader, Tags::Beta, &b);
+        m_data = Refractive(d, b);
+    } else {
+        complex_t c;
+        readAttribute(reader, Tags::Sld, &c);
+        m_data = c;
     }
-    if (dataItem->modelType() == MaterialSLDDataItem::M_TYPE) {
-        double sld_real = dataItem->getItemValue(MaterialSLDDataItem::P_SLD_REAL).toDouble();
-        double sld_imag = dataItem->getItemValue(MaterialSLDDataItem::P_SLD_IMAG).toDouble();
-        return std::make_unique<Material>(MaterialBySLD(name, sld_real, sld_imag, magnetization));
+}
+
+void MaterialItem::updateFrom(const MaterialItem& other)
+{
+    if (operator!=(other)) {
+        m_name = other.m_name;
+        m_color = other.m_color;
+        m_data = other.m_data;
+        m_magnetization = other.m_magnetization;
+        emit dataChanged();
     }
-    ASSERT(0);
 }
 
 bool MaterialItem::operator!=(const MaterialItem& other) const
@@ -196,27 +310,13 @@ bool MaterialItem::operator!=(const MaterialItem& other) const
 
 bool MaterialItem::operator==(const MaterialItem& other) const
 {
-    if (identifier() != other.identifier())
-        return false;
-    if (itemName() != other.itemName())
-        return false;
-    if (color() != other.color())
-        return false;
-    if (magnetization() != other.magnetization())
-        return false;
-
-    if (hasRefractiveIndex() != other.hasRefractiveIndex())
-        return false;
-
     if (hasRefractiveIndex()) {
-        if (refractiveIndexBeta() != other.refractiveIndexBeta())
-            return false;
-        if (refractiveIndexDelta() != other.refractiveIndexDelta())
-            return false;
-    } else {
-        if (scatteringLengthDensity() != other.scatteringLengthDensity())
+        if (std::get<Refractive>(m_data) != std::get<Refractive>(other.m_data))
             return false;
-    }
+    } else if (std::get<complex_t>(m_data) != std::get<complex_t>(other.m_data))
+        return false;
+
 
-    return true;
+    return (m_id == other.m_id) && (m_name == other.m_name) && (m_color == other.m_color)
+           && (m_magnetization == other.m_magnetization);
 }
diff --git a/GUI/Model/Material/MaterialItem.h b/GUI/Model/Material/MaterialItem.h
index af486c7f1fb..af17bab0e5f 100644
--- a/GUI/Model/Material/MaterialItem.h
+++ b/GUI/Model/Material/MaterialItem.h
@@ -15,29 +15,33 @@
 #ifndef BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALITEM_H
 #define BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALITEM_H
 
-#include "GUI/Model/Session/SessionItem.h"
-
+#include <QColor>
+#include <QObject>
 #include <heinz/Complex.h>
 #include <heinz/Vectors3D.h>
+#include <variant>
 
 class Material;
 class DoubleDescriptor;
 class VectorDescriptor;
+class QXmlStreamReader;
+class QXmlStreamWriter;
 
-class BA_CORE_API_ MaterialItem : public SessionItem {
-private:
-    static constexpr auto P_COLOR{"Color"};
-    static constexpr auto P_MATERIAL_DATA{"Material data"};
-    static constexpr auto P_MAGNETIZATION{"Magnetization"};
-    static constexpr auto P_IDENTIFIER{"Identifier"};
+class MaterialItem : public QObject {
+    Q_OBJECT
 
 public:
-    static constexpr auto M_TYPE{"Material"};
-
     MaterialItem();
 
-    /// set refractive index as in 1 - delta + i * beta
+    //! Creates a complete copy, also the identifier is the same.
+    MaterialItem(const MaterialItem& other);
+
+    //! Turns material into refractive index material.
+    //!
+    //! Set refractive index as in 1 - delta + i * beta
     void setRefractiveIndex(double delta, double beta);
+
+    //! Turns material into SLD based material.
     void setScatteringLengthDensity(complex_t sld);
 
     DoubleDescriptor delta();
@@ -49,17 +53,12 @@ public:
     /// \return true if refractive index was given, otherwise SLD was given
     bool hasRefractiveIndex() const;
 
-    double refractiveIndexDelta() const;
-    double refractiveIndexBeta() const;
-
-    /// \pre ! hasRefractiveIndex
-    complex_t scatteringLengthDensity() const;
-
     QString materialName() const;
     void setMaterialName(const QString& name);
 
     QString identifier() const;
     void setIdentifier(const QString& id);
+    void createNewIdentifier();
 
     QColor color() const;
     void setColor(const QColor& color);
@@ -67,14 +66,40 @@ public:
     R3 magnetization() const;
     void setMagnetization(const R3& magnetization);
 
-    void hideMagnetization();
-
     std::unique_ptr<Material> createMaterial() const;
 
     //! Compares all contents. The inactive contents (e.g. SLD in case of refractive) are not taken
     //! into account.
     bool operator==(const MaterialItem& other) const;
     bool operator!=(const MaterialItem& other) const;
+
+    void writeContentTo(QXmlStreamWriter* writer) const;
+    void readContentFrom(QXmlStreamReader* reader);
+
+    //! Updates content from the other material.
+    //!
+    //! Does NOT change the identifier.
+    //! emits dataChanged, if differences exist.
+    void updateFrom(const MaterialItem& other);
+
+signals:
+    void dataChanged() const;
+
+private:
+    QString m_name;
+    QString m_id;
+    QColor m_color;
+
+    struct Refractive {
+        Refractive(double d, double b) : delta(d), beta(b) {}
+        double delta = 0.0;
+        double beta = 0.0;
+        bool operator==(const Refractive& o) const { return delta == o.delta && beta == o.beta; }
+        bool operator!=(const Refractive& o) const { return !operator==(o); }
+    };
+
+    std::variant<Refractive, complex_t> m_data;
+    R3 m_magnetization;
 };
 
 #endif // BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALITEM_H
diff --git a/GUI/Model/Session/ModelPath.cpp b/GUI/Model/Session/ModelPath.cpp
index 905a5b8487f..5f74fd2790d 100644
--- a/GUI/Model/Session/ModelPath.cpp
+++ b/GUI/Model/Session/ModelPath.cpp
@@ -15,6 +15,7 @@
 #include "GUI/Model/Session/ModelPath.h"
 #include "GUI/Model/Instrument/InstrumentItems.h"
 #include "GUI/Model/Job/JobItem.h"
+#include "GUI/Model/Material/MaterialItem.h"
 
 QString GUI::Model::Path::getPathFromIndex(const QModelIndex& index)
 {
@@ -97,3 +98,8 @@ QString GUI::Model::Path::getPathFromItem(SessionItem* item)
     ASSERT(item->model()); // if assert, item is not completely initialized
     return getPathFromIndex(item->model()->indexOfItem(item));
 }
+
+QString GUI::Model::Path::getPathFromItem(const MaterialItem* item)
+{
+    return "material/" + item->identifier();
+}
diff --git a/GUI/Model/Session/ModelPath.h b/GUI/Model/Session/ModelPath.h
index b1bfa2206dc..6959793cd73 100644
--- a/GUI/Model/Session/ModelPath.h
+++ b/GUI/Model/Session/ModelPath.h
@@ -22,6 +22,7 @@ class SessionItem;
 class QModelIndex;
 class SessionModel;
 class QString;
+class MaterialItem;
 
 namespace GUI::Model::Path {
 
@@ -29,6 +30,8 @@ QString getPathFromIndex(const QModelIndex& index);
 
 QString getPathFromItem(SessionItem* item);
 
+QString getPathFromItem(const MaterialItem* item);
+
 QModelIndex getIndexFromPath(const SessionModel* model, const QString& path);
 
 SessionItem* getItemFromPath(const QString& relPath, const SessionItem* parent);
-- 
GitLab