diff --git a/GUI/Model/Data/ApplicationModels.cpp b/GUI/Model/Data/ApplicationModels.cpp index aaaf1338c91561c249a1d605972aa6f61f81af3e..b6b1a083daa90a6de3315accd8bceca3b1051d50 100644 --- a/GUI/Model/Data/ApplicationModels.cpp +++ b/GUI/Model/Data/ApplicationModels.cpp @@ -16,28 +16,24 @@ #include "GUI/Model/Data/RealDataModel.h" #include "GUI/Model/Instrument/InstrumentModel.h" #include "GUI/Model/Job/JobModel.h" -#include "GUI/Model/Material/MaterialModel.h" #include "GUI/Model/Sample/SampleModel.h" #include "GUI/Model/Session/SimulationOptionsItem.h" #include "GUI/Util/DeserializationException.h" -#include <QtCore/QXmlStreamWriter> +#include <QXmlStreamWriter> ApplicationModels::ApplicationModels(QObject* parent) : QObject(parent) - , m_materialModel(nullptr) , m_instrumentModel(nullptr) , m_sampleModel(nullptr) , m_realDataModel(nullptr) , m_jobModel(nullptr) { //! creates and initializes models, order is important - m_materialModel = new MaterialModel(this); m_sampleModel = new SampleModel(this); m_instrumentModel = new InstrumentModel(this); m_realDataModel = new RealDataModel(this); m_jobModel = new JobModel(this); - connectModel(m_materialModel); connectModel(m_sampleModel); connectModel(m_instrumentModel); connectModel(m_realDataModel); @@ -48,11 +44,6 @@ ApplicationModels::ApplicationModels(QObject* parent) ApplicationModels::~ApplicationModels() = default; -MaterialModel* ApplicationModels::materialModel() const -{ - return m_materialModel; -} - InstrumentModel* ApplicationModels::instrumentModel() const { return m_instrumentModel; @@ -76,12 +67,6 @@ JobModel* ApplicationModels::jobModel() const //! reset all models to initial state void ApplicationModels::resetModels() { - m_materialModel->clear(); - m_materialModel->addRefractiveMaterial("Default", 1e-3, 1e-5); - m_materialModel->addRefractiveMaterial("Vacuum", 0.0, 0.0); - m_materialModel->addRefractiveMaterial("Particle", 6e-4, 2e-8); - m_materialModel->addRefractiveMaterial("Substrate", 6e-6, 2e-8); - m_sampleModel->clear(); m_realDataModel->clear(); m_jobModel->clear(); @@ -104,6 +89,10 @@ void ApplicationModels::readFrom(QXmlStreamReader* reader, MessageService* messa reader->skipCurrentElement(); break; } + if (reader->name().toString() == "MaterialModel") { + reader->skipCurrentElement(); + break; + } if (model->getModelTag() == reader->name()) { model->readFrom(reader, messageService); @@ -121,7 +110,6 @@ void ApplicationModels::readFrom(QXmlStreamReader* reader, MessageService* messa QList<SessionModel*> ApplicationModels::modelList() { QList<SessionModel*> result; - result.append(m_materialModel); result.append(m_instrumentModel); result.append(m_sampleModel); result.append(m_realDataModel); diff --git a/GUI/Model/Data/ApplicationModels.h b/GUI/Model/Data/ApplicationModels.h index 500878004c388283e94dbb82740d7c2f2c3612dc..a127bf60511b900f84cfaf9778aaed41efbe0284 100644 --- a/GUI/Model/Data/ApplicationModels.h +++ b/GUI/Model/Data/ApplicationModels.h @@ -20,7 +20,6 @@ class SessionModel; class SessionItem; class DocumentModel; -class MaterialModel; class InstrumentModel; class RealDataModel; class SampleModel; @@ -33,7 +32,6 @@ public: explicit ApplicationModels(QObject* parent = nullptr); ~ApplicationModels() override; - MaterialModel* materialModel() const; InstrumentModel* instrumentModel() const; SampleModel* sampleModel() const; RealDataModel* realDataModel() const; @@ -56,7 +54,6 @@ private: void connectModel(SessionModel* model) const; DocumentModel* m_documentModel; - MaterialModel* m_materialModel; InstrumentModel* m_instrumentModel; SampleModel* m_sampleModel; RealDataModel* m_realDataModel; diff --git a/GUI/Model/Fit/FitParameterContainerItem.cpp b/GUI/Model/Fit/FitParameterContainerItem.cpp index e4673cdc8d34ee3f3e15153d2e12ad107d332d8c..8165853658a145525193ed18f71c312c426c24e2 100644 --- a/GUI/Model/Fit/FitParameterContainerItem.cpp +++ b/GUI/Model/Fit/FitParameterContainerItem.cpp @@ -15,6 +15,7 @@ #include "GUI/Model/Fit/FitParameterContainerItem.h" #include "Base/Util/Assert.h" #include "Fit/Param/Parameters.h" +#include "GUI/Model/Fit/FitParameterHelper.h" #include "GUI/Model/Fit/FitParameterItem.h" #include "GUI/Model/Fit/FitParameterLinkItem.h" #include "GUI/Model/Fit/ParameterTreeItems.h" @@ -29,7 +30,7 @@ FitParameterContainerItem::FitParameterContainerItem() : SessionItem(M_TYPE) //! returns FitParameterItem for given link (path in model) -FitParameterItem* FitParameterContainerItem::fitParameterItem(const QString& link) +FitParameterItem* FitParameterContainerItem::fitParameterItem(const QString& link) const { for (FitParameterItem* item : items<FitParameterItem>(T_FIT_PARAMETERS)) { for (FitParameterLinkItem* linkItem : item->linkItems()) { @@ -40,6 +41,12 @@ FitParameterItem* FitParameterContainerItem::fitParameterItem(const QString& lin return nullptr; } +FitParameterItem* +FitParameterContainerItem::fitParameterItem(const ParameterItem* parameterItem) const +{ + return fitParameterItem(FitParameterHelper::getParameterItemPath(parameterItem)); +} + QVector<FitParameterItem*> FitParameterContainerItem::fitParameterItems() { return items<FitParameterItem>(T_FIT_PARAMETERS); diff --git a/GUI/Model/Fit/FitParameterContainerItem.h b/GUI/Model/Fit/FitParameterContainerItem.h index 7d059150169d3c2c5beb6db9421ec3b9a4729439..0e9c6de103cc7a5b6979e864ef4e19f9417648f0 100644 --- a/GUI/Model/Fit/FitParameterContainerItem.h +++ b/GUI/Model/Fit/FitParameterContainerItem.h @@ -21,6 +21,7 @@ namespace mumufit { class Parameters; } class FitParameterItem; +class ParameterItem; //! The FitParameterContainerItem class is a collection of all defined fit parameters in JobItem. @@ -32,7 +33,15 @@ public: static constexpr auto M_TYPE{"FitParameterContainer"}; FitParameterContainerItem(); - FitParameterItem* fitParameterItem(const QString& link); + + //! get the fit parameter item whose link matches the given link. + //! + //! The link is a ParameterItem's path + FitParameterItem* fitParameterItem(const QString& link) const; + + //! get the fit parameter item which links the given parameterItem. + FitParameterItem* fitParameterItem(const ParameterItem* parameterItem) const; + QVector<FitParameterItem*> fitParameterItems(); bool isEmpty(); void setValuesInParameterContainer(const QVector<double>& values, diff --git a/GUI/Model/Fit/FitParameterHelper.cpp b/GUI/Model/Fit/FitParameterHelper.cpp index 1331f7956626cc100dde94a49d95b41e8048f185..0a61bdcdff32805ae7c07ae38bbced52982d54be 100644 --- a/GUI/Model/Fit/FitParameterHelper.cpp +++ b/GUI/Model/Fit/FitParameterHelper.cpp @@ -13,8 +13,8 @@ // ************************************************************************************************ #include "GUI/Model/Fit/FitParameterHelper.h" -#include "GUI/Model/Fit/FitParameterItem.h" #include "GUI/Model/Fit/FitParameterContainerItem.h" +#include "GUI/Model/Fit/FitParameterItem.h" #include "GUI/Model/Fit/FitParameterLinkItem.h" #include "GUI/Model/Fit/ParameterTreeItems.h" #include "GUI/Model/Job/JobItem.h" @@ -39,7 +39,7 @@ void FitParameterHelper::createFitParameter(FitParameterContainerItem* container fitPar->setStartValue(parameterItem->value().toDouble()); link->setLink(getParameterItemPath(parameterItem)); - fitPar->initMinMaxValues(parameterItem->linkedItem()->limits()); + fitPar->initMinMaxValues(parameterItem->limitsOfLink()); } //! Removes link to given parameterItem from fit parameters @@ -47,7 +47,7 @@ void FitParameterHelper::createFitParameter(FitParameterContainerItem* container void FitParameterHelper::removeFromFitParameters(FitParameterContainerItem* container, ParameterItem* parameterItem) { - FitParameterItem* fitParItem = getFitParameterItem(container, parameterItem); + FitParameterItem* fitParItem = container->fitParameterItem(parameterItem); if (fitParItem) { for (auto* linkItem : fitParItem->linkItems()) { @@ -77,15 +77,6 @@ void FitParameterHelper::addToFitParameter(FitParameterContainerItem* container, } } -//! Returns fFitParameterItem corresponding to given ParameterItem - -FitParameterItem* FitParameterHelper::getFitParameterItem(FitParameterContainerItem* container, - ParameterItem* parameterItem) -{ - ASSERT(container); - return container->fitParameterItem(getParameterItemPath(parameterItem)); -} - //! Returns list of fit parameter display names QStringList FitParameterHelper::getFitParameterNames(FitParameterContainerItem* container) diff --git a/GUI/Model/Fit/FitParameterHelper.h b/GUI/Model/Fit/FitParameterHelper.h index 75f52c226f4de9172fa8dae070e41bd55279dccc..5d7d7e5547e5251b2f82f04a1dfd291436e142e5 100644 --- a/GUI/Model/Fit/FitParameterHelper.h +++ b/GUI/Model/Fit/FitParameterHelper.h @@ -31,9 +31,6 @@ void removeFromFitParameters(FitParameterContainerItem* container, ParameterItem void addToFitParameter(FitParameterContainerItem* container, ParameterItem* parameterItem, const QString& fitParName); -FitParameterItem* getFitParameterItem(FitParameterContainerItem* container, - ParameterItem* parameterItem); - QStringList getFitParameterNames(FitParameterContainerItem* container); QString getParameterItemPath(const ParameterItem* parameterItem); ParameterItem* getParameterItem(FitParameterContainerItem* container, const QString& link); diff --git a/GUI/Model/Fit/ParameterTreeItems.cpp b/GUI/Model/Fit/ParameterTreeItems.cpp index 98dd051f8482d4e2caf97a7eca9d7bca4a6d0207..d1107ff06fce27ffe46ca7cc04eb01b04f606c3c 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,23 +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 +void ParameterItem::linkToDescriptor(DoubleDescriptor d) +{ + m_link = d.path(); + m_d = d; +} + +void ParameterItem::linkToSessionItem(SessionItem* item) +{ + m_link = GUI::Model::Path::getPathFromIndex(item->index()); + m_d = DoubleDescriptor(item, ""); +} -SessionItem* ParameterItem::linkedItem() +RealLimits ParameterItem::limitsOfLink() const { - 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)); + return m_d.limits; } -void ParameterItem::setLink(const QString& link) +int ParameterItem::decimalsOfLink() const { - m_link = link; + return m_d.decimals; } QString ParameterItem::link() const diff --git a/GUI/Model/Fit/ParameterTreeItems.h b/GUI/Model/Fit/ParameterTreeItems.h index 78f8bf46a23a4c83529e7e3b356adf2b7c32b211..07a591c2d0cef64a0e1da2cca2afa23504f98da1 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,12 +42,28 @@ public: ParameterItem(); void propagateValueToLink(double newValue); - SessionItem* linkedItem(); - 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 defined by a descriptor. + void linkToDescriptor(DoubleDescriptor d); + + //! Links this item to the given session item. + void linkToSessionItem(SessionItem* item); + + RealLimits limitsOfLink() const; + int decimalsOfLink() const; + private: - 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/Group/ItemCatalog.cpp b/GUI/Model/Group/ItemCatalog.cpp index 9b9a3c560caecbb5502be6ffb828374757307dbc..ecdc4f3610a7b03a4f8e42ca8d142dfb624675b5 100644 --- a/GUI/Model/Group/ItemCatalog.cpp +++ b/GUI/Model/Group/ItemCatalog.cpp @@ -40,9 +40,6 @@ #include "GUI/Model/Instrument/SpecularBeamInclinationItem.h" #include "GUI/Model/Instrument/SphericalDetectorItem.h" #include "GUI/Model/Job/JobItem.h" -#include "GUI/Model/Material/MaterialDataItems.h" -#include "GUI/Model/Material/MaterialItem.h" -#include "GUI/Model/Material/MaterialItemContainer.h" #include "GUI/Model/Sample/FTDecayFunctionItems.h" #include "GUI/Model/Sample/FTDistributionItems.h" #include "GUI/Model/Sample/FormFactorItems.h" @@ -260,12 +257,6 @@ ItemCatalog::ItemCatalog() addItem<SquareLattice2DItem>("Square"); addItem<HexagonalLattice2DItem>("Hexagonal"); - addItem<MaterialItem>(); - addItem<MaterialItemContainer>(); - - addItem<MaterialRefractiveDataItem>(); - addItem<MaterialSLDDataItem>(); - addItem<JobItem>(); addItem<IntensityDataItem>(); diff --git a/GUI/Model/Job/JobItem.cpp b/GUI/Model/Job/JobItem.cpp index 90df6955523c3e83b4307d5ce0f27930e556ec9f..23ca2f32d1abcd5a6decc7dcb960212440fa6b1f 100644 --- a/GUI/Model/Job/JobItem.cpp +++ b/GUI/Model/Job/JobItem.cpp @@ -23,7 +23,6 @@ #include "GUI/Model/IO/ItemFileNameUtils.h" #include "GUI/Model/Instrument/InstrumentItems.h" #include "GUI/Model/Job/JobItemUtils.h" -#include "GUI/Model/Material/MaterialItemContainer.h" #include "GUI/Model/Sample/ItemWithMaterial.h" #include "GUI/Model/Sample/MultiLayerItem.h" #include "GUI/Model/Session/SessionXML.h" @@ -35,6 +34,7 @@ using namespace GUI::Session::XML; namespace { const QString SimulationOptionsTag("SimulationOptions"); +const QString MaterialsTag("Materials"); } // namespace @@ -56,7 +56,6 @@ JobItem::JobItem() : SessionItem(M_TYPE) addProperty(P_PRESENTATION_TYPE, QVariant::Type::Invalid)->setVisible(false); registerTag(T_SAMPLE, 1, 1, {MultiLayerItem::M_TYPE}); - registerTag(T_MATERIAL_CONTAINER, 1, 1, {MaterialItemContainer::M_TYPE}); registerTag(T_INSTRUMENT, 1, 1, {GISASInstrumentItem::M_TYPE, OffSpecularInstrumentItem::M_TYPE, SpecularInstrumentItem::M_TYPE, DepthProbeInstrumentItem::M_TYPE}); @@ -252,7 +251,7 @@ MultiLayerItem* JobItem::copySampleIntoJob(const MultiLayerItem* sample) // initialize finder-function of items with material for (auto* itemWithMaterial : sampleItem()->itemsWithMaterial()) { itemWithMaterial->setMaterialFinder( - [=](const QString& id) { return materialContainerItem()->findMaterialById(id); }); + [=](const QString& id) { return materialItems().materialFromIdentifier(id); }); } return sampleItem(); @@ -339,16 +338,6 @@ RealDataItem* JobItem::createRealDataItem() return model()->insertItem<RealDataItem>(this, -1, T_REALDATA); } -MaterialItemContainer* JobItem::materialContainerItem() const -{ - return dynamic_cast<MaterialItemContainer*>(getItem(JobItem::T_MATERIAL_CONTAINER)); -} - -MaterialItemContainer* JobItem::createMaterialContainer() -{ - return model()->insertItem<MaterialItemContainer>(this, -1, T_MATERIAL_CONTAINER); -} - Data1DViewItem* JobItem::dataItemView() { return dynamic_cast<Data1DViewItem*>(getItem(JobItem::T_DATAVIEW)); @@ -401,6 +390,10 @@ void JobItem::writeNonSessionItems(QXmlStreamWriter* writer) const writer->writeStartElement(SimulationOptionsTag); m_simulationOptionsItem.writeContentTo(writer); writer->writeEndElement(); + + writer->writeStartElement(MaterialsTag); + m_materials.writeContentTo(writer); + writer->writeEndElement(); } void JobItem::readNonSessionItems(QXmlStreamReader* reader) @@ -417,10 +410,28 @@ void JobItem::readNonSessionItems(QXmlStreamReader* reader) if (reader->name() == SimulationOptionsTag) { m_simulationOptionsItem.readContentFrom(reader); reader->skipCurrentElement(); + } else if (reader->name() == MaterialsTag) { + m_materials.readContentFrom(reader); + reader->skipCurrentElement(); } } } +const MaterialModel& JobItem::materialItems() const +{ + return m_materials; +} + +MaterialModel& JobItem::materialItems() +{ + return m_materials; +} + +bool JobItem::isSpecularJob() const +{ + return instrumentItem()->is<SpecularInstrumentItem>(); +} + //! Updates the name of file to store intensity data. void JobItem::updateIntensityDataFileName() diff --git a/GUI/Model/Job/JobItem.h b/GUI/Model/Job/JobItem.h index 16d34064e0ec0db3afcdfa3d88cedf3d44008d44..8d0230c359dd8a817938f696e176041e62b24c2a 100644 --- a/GUI/Model/Job/JobItem.h +++ b/GUI/Model/Job/JobItem.h @@ -16,6 +16,7 @@ #define BORNAGAIN_GUI_MODEL_JOB_JOBITEM_H #include "GUI/Model/Job/JobStatus.h" // enum cannot be forward declared +#include "GUI/Model/Material/MaterialModel.h" #include "GUI/Model/Session/SessionItem.h" #include "GUI/Model/Session/SessionModel.h" // call to model() from templated fct #include "GUI/Model/Session/SimulationOptionsItem.h" @@ -130,9 +131,6 @@ public: void addRealDataItem(RealDataItem* real_data); RealDataItem* createRealDataItem(); - MaterialItemContainer* materialContainerItem() const; - MaterialItemContainer* createMaterialContainer(); - Data1DViewItem* dataItemView(); void addDataViewItem(Data1DViewItem* data_view); Data1DViewItem* createDataViewItem(); @@ -149,10 +147,15 @@ public: void writeNonSessionItems(QXmlStreamWriter* writer) const override; void readNonSessionItems(QXmlStreamReader* reader) override; + const MaterialModel& materialItems() const; + MaterialModel& materialItems(); + bool isSpecularJob() const; + private: void updateIntensityDataFileName(); SimulationOptionsItem m_simulationOptionsItem; + MaterialModel m_materials; }; template <typename T> T* JobItem::setDataType() diff --git a/GUI/Model/Job/JobModel.cpp b/GUI/Model/Job/JobModel.cpp index 9f882e1d76d093c9e86bd948209b5db9583c0a08..8130489f427dd85ff244fa85fa2264f82dcf8942 100644 --- a/GUI/Model/Job/JobModel.cpp +++ b/GUI/Model/Job/JobModel.cpp @@ -23,7 +23,6 @@ #include "GUI/Model/Job/JobModelFunctions.h" #include "GUI/Model/Job/JobQueueData.h" #include "GUI/Model/Job/ParameterTreeUtils.h" -#include "GUI/Model/Material/MaterialItemContainer.h" #include "GUI/Model/Sample/ItemWithMaterial.h" #include "GUI/Model/Sample/MultiLayerItem.h" #include "GUI/Util/Path.h" @@ -170,7 +169,7 @@ void JobModel::readFrom(QXmlStreamReader* reader, MessageService* messageService // initialize the material finder functions for (auto* itemWithMaterial : jobItem->sampleItem()->itemsWithMaterial()) itemWithMaterial->setMaterialFinder([=](const QString& id) { - return jobItem->materialContainerItem()->findMaterialById(id); + return jobItem->materialItems().materialFromIdentifier(id); }); // Create the not stored parameter tuning tree diff --git a/GUI/Model/Job/JobModelFunctions.cpp b/GUI/Model/Job/JobModelFunctions.cpp index e7f99ef7ed3fb615d0d41a87a846e7b35cc20a5b..b57df4b4f5b64afbbb32087038a43d12568f1b08 100644 --- a/GUI/Model/Job/JobModelFunctions.cpp +++ b/GUI/Model/Job/JobModelFunctions.cpp @@ -29,7 +29,6 @@ #include "GUI/Model/Job/JobItem.h" #include "GUI/Model/Job/JobItemUtils.h" #include "GUI/Model/Material/MaterialItem.h" -#include "GUI/Model/Material/MaterialItemContainer.h" #include "GUI/Model/Sample/ItemWithMaterial.h" #include "GUI/Model/Sample/MultiLayerItem.h" #include "GUI/Util/Error.h" @@ -130,14 +129,10 @@ void GUI::Model::JobFunctions::setupJobItemSampleData(JobItem* jobItem, multilayer->setItemName(MultiLayerItem::M_TYPE); // copy used materials into material container - MaterialItemContainer* container = jobItem->createMaterialContainer(); - for (auto* itemWithMaterial : sampleItem->itemsWithMaterial()) { auto* material = itemWithMaterial->materialItem(); - if (!container->findMaterialById(material->identifier())) { - auto* materialCopy = container->insertCopy(material); - materialCopy->setIdentifier(material->identifier()); // insertCopy() doesn't do this - } + if (!jobItem->materialItems().findMaterialItem(material->identifier())) + jobItem->materialItems().addMaterial(new MaterialItem(*material)); } } @@ -206,10 +201,6 @@ void GUI::Model::JobFunctions::setupJobItemForFit(JobItem* jobItem, void GUI::Model::JobFunctions::muteMagnetizationData(JobItem* jobItem) { - MaterialItemContainer* container = jobItem->materialContainerItem(); - for (MaterialItem* material : container->getMaterials()) - material->hideMagnetization(); - MultiLayerItem* sample = jobItem->sampleItem(); sample->externalFieldItem()->setVisible(false); } diff --git a/GUI/Model/Job/ParameterTreeUtils.cpp b/GUI/Model/Job/ParameterTreeUtils.cpp index 7a7a2ca73c92b64f342682cf6fbbd028aee19fe5..f64a7423aba98cc1717addea2cfa9adab1f1028d 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->linkToDescriptor(d); + if (recreateBackupValues) + container->setBackupValue(materialValue->link(), d.get()); + } + } + // add sample populateParameterContainer(container, jobItem->sampleItem(), recreateBackupValues); + // add instrument populateParameterContainer(container, jobItem->instrumentItem(), recreateBackupValues); } diff --git a/GUI/Model/Material/MaterialDataItems.cpp b/GUI/Model/Material/MaterialDataItems.cpp deleted file mode 100644 index ebd044005cd1ac27dd506bb7006e11145e996649..0000000000000000000000000000000000000000 --- 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 ea25e70dd7583d41a8f4d4e20589076ed3f44651..0000000000000000000000000000000000000000 --- 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 03257f1983719f6e9d2d76e126b794dde353e06f..a9defd62f76b1838020d34f8560a0692382951b0 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 af486c7f1fbf43b5894f2197495d5d5ccd7f7755..106cf4b2cb712683ea590d0ff359e78d33997747 100644 --- a/GUI/Model/Material/MaterialItem.h +++ b/GUI/Model/Material/MaterialItem.h @@ -15,29 +15,34 @@ #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 <memory> +#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 +54,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 +67,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/Material/MaterialItemContainer.cpp b/GUI/Model/Material/MaterialItemContainer.cpp deleted file mode 100644 index 8e0c528b79d50f8d3b89de9ab20f14cbfea60c20..0000000000000000000000000000000000000000 --- a/GUI/Model/Material/MaterialItemContainer.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Material/MaterialItemContainer.cpp -//! @brief Implements class MaterialItemContainer -//! -//! @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/MaterialItemContainer.h" -#include "GUI/Model/Material/MaterialItem.h" -#include "GUI/Model/Session/SessionModel.h" -#include <QUuid> - -MaterialItemContainer::MaterialItemContainer() : SessionItem(M_TYPE) -{ - setItemName("Materials"); - registerTag(T_MATERIALS, 0, -1, {MaterialItem::M_TYPE}); -} - -MaterialItem* MaterialItemContainer::insertCopy(MaterialItem* material_item) -{ - MaterialItem* item_copy = model()->copyItem(material_item, this, T_MATERIALS); - item_copy->setIdentifier(QUuid::createUuid().toString()); - - return item_copy; -} - -MaterialItem* MaterialItemContainer::findMaterialById(QString id) -{ - return const_cast<MaterialItem*>( - static_cast<const MaterialItemContainer*>(this)->findMaterialById(id)); -} - -const MaterialItem* MaterialItemContainer::findMaterialById(QString id) const -{ - auto materials = getItems(T_MATERIALS); - for (auto* item : materials) { - auto* material = dynamic_cast<MaterialItem*>(item); - if (material->identifier() == id) - return material; - } - return nullptr; -} - -QVector<MaterialItem*> MaterialItemContainer::getMaterials() -{ - return items<MaterialItem>(T_MATERIALS); -} diff --git a/GUI/Model/Material/MaterialItemContainer.h b/GUI/Model/Material/MaterialItemContainer.h deleted file mode 100644 index 8ef61c64c4336ba509a6ced5862906ae6fd99b63..0000000000000000000000000000000000000000 --- a/GUI/Model/Material/MaterialItemContainer.h +++ /dev/null @@ -1,44 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Material/MaterialItemContainer.h -//! @brief Defines class MaterialItemContainer -//! -//! @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_MATERIALITEMCONTAINER_H -#define BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALITEMCONTAINER_H - -#include "GUI/Model/Session/SessionItem.h" - -class MaterialItem; - -class MaterialItemContainer : public SessionItem { -private: - static constexpr auto T_MATERIALS{"MaterialVector"}; - -public: - static constexpr auto M_TYPE{"MaterialContainer"}; - - MaterialItemContainer(); - - //! Copies MaterialItem, inserts it into the container - //! and returns a pointer to the copy. - MaterialItem* insertCopy(MaterialItem* material_item); - - //! Can be nullptr if not found - const MaterialItem* findMaterialById(QString id) const; - - //! Can be nullptr if not found - MaterialItem* findMaterialById(QString id); - - QVector<MaterialItem*> getMaterials(); -}; - -#endif // BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALITEMCONTAINER_H diff --git a/GUI/Model/Material/MaterialModel.cpp b/GUI/Model/Material/MaterialModel.cpp index 9a6eb9099dbab6cf7afd33d19a8a3b51e05de04d..b0ccfbb5aa025183f7322bd0527bb833118f38fa 100644 --- a/GUI/Model/Material/MaterialModel.cpp +++ b/GUI/Model/Material/MaterialModel.cpp @@ -13,11 +13,18 @@ // ************************************************************************************************ #include "GUI/Model/Material/MaterialModel.h" +#include "Base/Util/Assert.h" #include "GUI/Model/Material/MaterialItem.h" +#include "GUI/Model/Session/SessionXML.h" +#include "GUI/Util/DeserializationException.h" #include <QColor> #include <QUuid> +#include <QXmlStreamWriter> #include <random> +using namespace GUI::Session::XML; + + namespace { QColor suggestMaterialColor(const QString& name) @@ -42,45 +49,70 @@ QColor suggestMaterialColor(const QString& name) } // namespace -MaterialModel::MaterialModel(QObject* parent) - : SessionModel(GUI::Session::XML::MaterialModelTag, parent) +MaterialModel::MaterialModel(QObject* parent) : QObject(parent) {} + +MaterialModel::~MaterialModel() { - setObjectName(GUI::Session::XML::MaterialModelTag); + clear(); } void MaterialModel::clear() { - SessionModel::clear(); + qDeleteAll(m_materialItems); + m_materialItems.clear(); +} + +void MaterialModel::addMaterial(MaterialItem* material) +{ + addMaterial(material, true); } -MaterialModel* MaterialModel::createCopy(SessionItem* parent) +void MaterialModel::addMaterial(MaterialItem* material, bool signalAdding) +{ + ASSERT(material); + material->disconnect(this); + m_materialItems << material; + connect(material, &MaterialItem::dataChanged, this, [=] { emit materialChanged(material); }); + + if (signalAdding) + emit materialAddedOrRemoved(); +} + +MaterialModel* MaterialModel::createCopy() const { auto* result = new MaterialModel(); - result->initFrom(this, parent); + + for (const auto* m : m_materialItems) + result->addMaterial(new MaterialItem(*m)); + return result; } MaterialItem* MaterialModel::addRefractiveMaterial(const QString& name, double delta, double beta) { - auto* materialItem = insertItem<MaterialItem>(); + auto* materialItem = new MaterialItem(); materialItem->setMaterialName(name); materialItem->setColor(suggestMaterialColor(name)); materialItem->setRefractiveIndex(delta, beta); + addMaterial(materialItem); + return materialItem; } MaterialItem* MaterialModel::addSLDMaterial(const QString& name, double sld, double abs_term) { - auto* materialItem = insertItem<MaterialItem>(); + auto* materialItem = new MaterialItem(); materialItem->setMaterialName(name); materialItem->setColor(suggestMaterialColor(name)); materialItem->setScatteringLengthDensity(complex_t(sld, abs_term)); + addMaterial(materialItem); + return materialItem; } MaterialItem* MaterialModel::materialFromName(const QString& name) const { - for (auto* materialItem : topItems<MaterialItem>()) + for (auto* materialItem : m_materialItems) if (materialItem->materialName() == name) return materialItem; @@ -89,33 +121,31 @@ MaterialItem* MaterialModel::materialFromName(const QString& name) const MaterialItem* MaterialModel::materialFromIdentifier(const QString& identifier) const { - for (auto* materialItem : topItems<MaterialItem>()) + for (auto* materialItem : m_materialItems) if (materialItem->identifier() == identifier) return materialItem; return nullptr; } -MaterialItem* MaterialModel::cloneMaterial(MaterialItem* material) +MaterialItem* MaterialModel::insertCopy(const MaterialItem& material) { - if (!material) - return nullptr; + auto* newMaterial = new MaterialItem(material); + newMaterial->createNewIdentifier(); + newMaterial->setMaterialName(material.materialName() + " (copy)"); + addMaterial(newMaterial); - auto* clonedMaterial = copyItem(material, nullptr); - clonedMaterial->setIdentifier(QUuid::createUuid().toString()); - clonedMaterial->setMaterialName(material->materialName() + " (copy)"); - return clonedMaterial; + return newMaterial; } -QVector<MaterialItem*> MaterialModel::materialItems() const +const QVector<MaterialItem*>& MaterialModel::materialItems() const { - return topItems<MaterialItem>(); + return m_materialItems; } - MaterialItem* MaterialModel::findMaterialItem(const QString& identifier) const { - for (auto* m : materialItems()) + for (auto* m : m_materialItems) if (m->identifier() == identifier) return m; @@ -135,69 +165,84 @@ void MaterialModel::removeMaterial(const QString& identifier) void MaterialModel::removeMaterial(MaterialItem* materialItem) { - if (materialItem != nullptr) - if (const auto index = indexOfItem(materialItem); index.isValid()) - removeRows(index.row(), 1, index.parent()); + m_materialItems.removeAll(materialItem); + delete materialItem; + emit materialAddedOrRemoved(); } -void MaterialModel::readFrom(QXmlStreamReader* reader, MessageService* messageService /*= 0*/) +void MaterialModel::writeContentTo(QXmlStreamWriter* writer) const { - // do not send added-notifications until completely read - otherwise partially - // initialized items will be notified - disconnect(this, &SessionModel::rowsInserted, this, &MaterialModel::onRowsChange); - - SessionModel::readFrom(reader, messageService); - - connect(this, &SessionModel::rowsInserted, this, &MaterialModel::onRowsChange); - - for (auto* materialItem : materialItems()) { - materialItem->mapper()->setOnAnyChildChange( - [this, materialItem](SessionItem*) { materialChanged(materialItem); }, this); + writeAttribute(writer, GUI::Session::XML::Version, int(1)); + for (auto m : m_materialItems) { + writer->writeStartElement("Material"); + m->writeContentTo(writer); + writer->writeEndElement(); } } -void MaterialModel::initFrom(SessionModel* model, SessionItem* parent) +void MaterialModel::readContentFrom(QXmlStreamReader* reader) { - // since initFrom does not send materialChanged signals, this has to be done manually. + const int version = reader->attributes().value(GUI::Session::XML::Version).toInt(); - QStringList identifiersOfChangedMaterials; - auto* sourceModel = dynamic_cast<MaterialModel*>(model); - for (auto* destItem : materialItems()) { - auto* srcItem = sourceModel->findMaterialItem(destItem->identifier()); - if (srcItem && (*srcItem != *destItem)) - identifiersOfChangedMaterials << destItem->identifier(); - } + if (version < 1) + throw DeserializationException::tooOld(); - clear(); - SessionModel::initFrom(model, parent); + if (version > 1) + throw DeserializationException::tooNew(); - for (const auto& identifier : identifiersOfChangedMaterials) - emit materialChanged(findMaterialItem(identifier)); + while (reader->readNextStartElement()) { + if (reader->name() == "Material") { + MaterialItem* m = new MaterialItem; + m->readContentFrom(reader); + addMaterial(m, false); + reader->skipCurrentElement(); + } + } } -void MaterialModel::onRowsChange(const QModelIndex& parent, int, int) +void MaterialModel::initFrom(const MaterialModel& from) { - // valid parent means not a material (which is top level item) but something below - if (parent.isValid()) - return; + // update existing to new contents (do not delete and recreate to keep references valid) + for (auto* destItem : m_materialItems) + if (auto* fromItem = from.findMaterialItem(destItem->identifier())) + destItem->updateFrom(*fromItem); - for (auto* materialItem : materialItems()) { - materialItem->mapper()->unsubscribe(this); + bool anyAddedOrRemoved = false; - materialItem->mapper()->setOnAnyChildChange( - [this, materialItem](SessionItem*) { materialChanged(materialItem); }, this); - } + // remove non-existing + auto iter = m_materialItems.begin(); + while (iter != m_materialItems.end()) + if (!from.findMaterialItem((*iter)->identifier())) { + delete *iter; + iter = m_materialItems.erase(iter); + anyAddedOrRemoved = true; + } else + iter++; + + // copy new ones + for (const auto* m : from.materialItems()) + if (!findMaterialItem(m->identifier())) { + addMaterial(new MaterialItem(*m), false); + anyAddedOrRemoved = true; + } + + // copy order + QVector<MaterialItem*> tmp; + for (const auto* m : from.materialItems()) + tmp << findMaterialItem(m->identifier()); + m_materialItems = tmp; + + if (anyAddedOrRemoved) + emit materialAddedOrRemoved(); } bool MaterialModel::operator==(const MaterialModel& other) const { - const auto myItems = materialItems(); - const auto otherItems = other.materialItems(); - if (myItems.size() != otherItems.size()) + if (m_materialItems.size() != other.m_materialItems.size()) return false; - for (int i = 0; i < myItems.size(); i++) - if (*myItems[i] != *otherItems[i]) + for (int i = 0; i < m_materialItems.size(); i++) + if (*m_materialItems[i] != *other.m_materialItems[i]) return false; return true; diff --git a/GUI/Model/Material/MaterialModel.h b/GUI/Model/Material/MaterialModel.h index cc7d36761850ec8c659bbdb37a2593bdbf736819..96ff5b68f7214ef40b3364750463dab798b2a696 100644 --- a/GUI/Model/Material/MaterialModel.h +++ b/GUI/Model/Material/MaterialModel.h @@ -15,19 +15,26 @@ #ifndef BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALMODEL_H #define BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALMODEL_H -#include "GUI/Model/Session/SessionModel.h" +#include <QObject> +#include <QVector> class MaterialItem; +class QXmlStreamReader; +class QXmlStreamWriter; -class MaterialModel : public SessionModel { +class MaterialModel : public QObject { Q_OBJECT public: explicit MaterialModel(QObject* parent = nullptr); + ~MaterialModel(); - void clear() override; + void clear(); - MaterialModel* createCopy(SessionItem* parent = nullptr) override; + //! Add the material and take ownership of it. + void addMaterial(MaterialItem* material); + + MaterialModel* createCopy() const; MaterialItem* addRefractiveMaterial(const QString& name, double delta, double beta); MaterialItem* addSLDMaterial(const QString& name, double sld, double abs_term); @@ -35,10 +42,12 @@ public: MaterialItem* materialFromName(const QString& name) const; MaterialItem* materialFromIdentifier(const QString& identifier) const; - //! Returns clone of given material. Clone will get the same material identifier! - MaterialItem* cloneMaterial(MaterialItem* material); + //! Inserts a copy of the given material and returns the newly inserted item. + //! + //! The copy will have a different material identifier and a different name. + MaterialItem* insertCopy(const MaterialItem& material); - QVector<MaterialItem*> materialItems() const; + const QVector<MaterialItem*>& materialItems() const; MaterialItem* findMaterialItem(const QString& identifier) const; MaterialItem* defaultMaterial() const; @@ -46,18 +55,28 @@ public: void removeMaterial(const QString& identifier); void removeMaterial(MaterialItem* materialItem); - void readFrom(QXmlStreamReader* reader, MessageService* messageService = nullptr) override; - void initFrom(SessionModel* model, SessionItem* parent) override; + void writeContentTo(QXmlStreamWriter* writer) const; + void readContentFrom(QXmlStreamReader* reader); + + //! Copies the complete content, emitting signals for existing and changed materials + void initFrom(const MaterialModel& from); //! Compares for complete equality (same material identifiers, same order of materials,...) bool operator==(const MaterialModel& other) const; bool operator!=(const MaterialModel& other) const; signals: + void materialAddedOrRemoved(); void materialChanged(MaterialItem* materialItem); private: - void onRowsChange(const QModelIndex& parent, int, int); + //! Add the material and take ownership of it. + //! + //! In the given flag the signal "materialAddedOrRemoved" can be suppressed. + void addMaterial(MaterialItem* material, bool signalAdding); + +private: + QVector<MaterialItem*> m_materialItems; //!< all materials (owned by this class) }; #endif // BORNAGAIN_GUI_MODEL_MATERIAL_MATERIALMODEL_H diff --git a/GUI/Model/Project/ProjectDocument.cpp b/GUI/Model/Project/ProjectDocument.cpp index 8b1c182f678c9eb01ae243cea9c022b08da5a7dd..4dc755ab5faa9f23459f106f8821f6473fc440cf 100644 --- a/GUI/Model/Project/ProjectDocument.cpp +++ b/GUI/Model/Project/ProjectDocument.cpp @@ -16,6 +16,7 @@ #include "GUI/Model/IO/ProjectUtils.h" #include "GUI/Model/Instrument/LinkInstrumentManager.h" #include "GUI/Model/Job/JobModel.h" +#include "GUI/Model/Material/MaterialItem.h" #include "GUI/Model/Material/MaterialModel.h" #include "GUI/Model/Project/OutputDataIOService.h" #include "GUI/Model/Sample/ItemWithMaterial.h" @@ -39,6 +40,7 @@ const QString BornAgainVersionAttribute("Version"); const QString InfoTag("DocumentInfo"); const QString InfoNameAttribute("ProjectName"); const QString SimulationOptionsTag("SimulationOptions"); +const QString MaterialsTag("Materials"); } // namespace @@ -50,6 +52,17 @@ ProjectDocument::ProjectDocument(const QString& projectFileName) , m_singleSampleMode(false) , m_functionalities(All) { + m_materials.addRefractiveMaterial("Default", 1e-3, 1e-5); + m_materials.addRefractiveMaterial("Vacuum", 0.0, 0.0); + m_materials.addRefractiveMaterial("Particle", 6e-4, 2e-8); + m_materials.addRefractiveMaterial("Substrate", 6e-6, 2e-8); + + + connect(&m_materials, &MaterialModel::materialAddedOrRemoved, this, + &ProjectDocument::onModelChanged, Qt::UniqueConnection); + connect(&m_materials, &MaterialModel::materialChanged, this, &ProjectDocument::onModelChanged, + Qt::UniqueConnection); + m_linkManager = std::make_unique<LinkInstrumentManager>(instrumentModel(), realDataModel()); setObjectName("ProjectDocument"); if (!projectFileName.isEmpty()) @@ -123,9 +136,9 @@ SampleModel* ProjectDocument::sampleModel() const return m_applicationModels.sampleModel(); } -MaterialModel* ProjectDocument::materialModel() const +MaterialModel* ProjectDocument::materialModel() { - return m_applicationModels.materialModel(); + return &m_materials; } RealDataModel* ProjectDocument::realDataModel() const @@ -326,6 +339,10 @@ ProjectDocument::ReadResult ProjectDocument::readProject(QIODevice* device, else if (reader.name() == SimulationOptionsTag) { m_simulationOptionsItem.readContentFrom(&reader); reader.skipCurrentElement(); + ASSERT(reader.name() == SimulationOptionsTag); + } else if (reader.name() == MaterialsTag) { + m_materials.readContentFrom(&reader); + ASSERT(reader.name() == MaterialsTag); } else m_applicationModels.readFrom(&reader, &messageService); } @@ -335,7 +352,17 @@ ProjectDocument::ReadResult ProjectDocument::readProject(QIODevice* device, // initialize all items with materials to find the materials for (auto multiLayerItem : m_applicationModels.sampleModel()->multiLayerItems()) for (auto itemWithMaterial : multiLayerItem->itemsWithMaterial()) - itemWithMaterial->setMaterialModel(m_applicationModels.materialModel()); + itemWithMaterial->setMaterialModel(materialModel()); + + // make a sanity check whether all materials are present + for (auto multiLayerItem : m_applicationModels.sampleModel()->multiLayerItems()) + for (auto itemWithMaterial : multiLayerItem->itemsWithMaterial()) + if (itemWithMaterial->materialItem() == nullptr) { + QString message = QString("Material link is broken (id: '%1')") + .arg(itemWithMaterial->materialIdentifier()); + messageService.addError(this, message); + return ReadResult::error; + } if (reader.hasError()) { QString message = QString("Format error '%1'").arg(reader.errorString()); @@ -365,6 +392,10 @@ void ProjectDocument::writeTo(QIODevice* device) m_simulationOptionsItem.writeContentTo(&writer); writer.writeEndElement(); + writer.writeStartElement(MaterialsTag); + m_materials.writeContentTo(&writer); + writer.writeEndElement(); + m_applicationModels.writeTo(&writer); writer.writeEndElement(); // BornAgain tag diff --git a/GUI/Model/Project/ProjectDocument.h b/GUI/Model/Project/ProjectDocument.h index fcac92afdac9cd0fdf9df828365b6b2a4ec129fe..40d02a5c9c11b01c47ea8ed462000409fe96b595 100644 --- a/GUI/Model/Project/ProjectDocument.h +++ b/GUI/Model/Project/ProjectDocument.h @@ -16,6 +16,7 @@ #define BORNAGAIN_GUI_MODEL_PROJECT_PROJECTDOCUMENT_H #include "GUI/Model/Data/ApplicationModels.h" +#include "GUI/Model/Material/MaterialModel.h" #include "GUI/Model/Session/SimulationOptionsItem.h" #include <QObject> #include <QVariant> @@ -30,7 +31,6 @@ class MaterialModel; class RealDataModel; class JobModel; class LinkInstrumentManager; -class SimulationOptionsItem; //! Project document class handles all data related to the opened project //! (sample, jobModel, project specific windows settings) @@ -72,7 +72,7 @@ public: InstrumentModel* instrumentModel() const; SampleModel* sampleModel() const; - MaterialModel* materialModel() const; + MaterialModel* materialModel(); RealDataModel* realDataModel() const; JobModel* jobModel() const; SimulationOptionsItem* simulationOptionsItem(); @@ -136,6 +136,7 @@ private: bool m_singleSampleMode; Functionalities m_functionalities; SimulationOptionsItem m_simulationOptionsItem; + MaterialModel m_materials; }; Q_DECLARE_OPERATORS_FOR_FLAGS(ProjectDocument::Functionalities) diff --git a/GUI/Model/Sample/ItemWithMaterial.cpp b/GUI/Model/Sample/ItemWithMaterial.cpp index 2a78c677afcf4a2f773076efd08c012b3b69f5b3..e84498d867dff5429ece43c550eb0b97ec1f0dd4 100644 --- a/GUI/Model/Sample/ItemWithMaterial.cpp +++ b/GUI/Model/Sample/ItemWithMaterial.cpp @@ -16,7 +16,6 @@ #include "GUI/Model/Job/JobItem.h" #include "GUI/Model/Job/JobModelFunctions.h" #include "GUI/Model/Material/MaterialItem.h" -#include "GUI/Model/Material/MaterialItemContainer.h" #include "GUI/Model/Material/MaterialModel.h" #include <QColor> diff --git a/GUI/Model/Session/ModelPath.cpp b/GUI/Model/Session/ModelPath.cpp index 905a5b8487ff1165117b8a4d33a35a24a6df9f9b..5f74fd2790d485371e88551adbdbb5d397c47a65 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 b1bfa2206dc72a99161a6664ffca293a0ec2ad34..6959793cd73445105bb7baee9681eabf2768539a 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); diff --git a/GUI/Model/Session/SessionXML.cpp b/GUI/Model/Session/SessionXML.cpp index ce963bbd23242cec0c12c5b1789c5f285f546b4b..bca4da3f09bda2cc48a745326ac136952ad81176 100644 --- a/GUI/Model/Session/SessionXML.cpp +++ b/GUI/Model/Session/SessionXML.cpp @@ -157,7 +157,7 @@ void GUI::Session::XML::writeAttribute(QXmlStreamWriter* writer, const QString& void GUI::Session::XML::writeAttribute(QXmlStreamWriter* writer, const QString& attributeName, double d) { - writer->writeAttribute(attributeName, QString::number(d, 'e', 12)); + writer->writeAttribute(attributeName, d == 0.0 ? "0" : QString::number(d, 'e', 12)); } void GUI::Session::XML::writeAttribute(QXmlStreamWriter* writer, const QString& attributeName, diff --git a/GUI/Model/Types/DoubleDescriptor.cpp b/GUI/Model/Types/DoubleDescriptor.cpp index 361f0bd374800ee633afaa4c2a3d56617c6b73f0..7e0bbb8eb351455da8af4f15f8543a842bba071e 100644 --- a/GUI/Model/Types/DoubleDescriptor.cpp +++ b/GUI/Model/Types/DoubleDescriptor.cpp @@ -70,6 +70,14 @@ DoubleDescriptor::DoubleDescriptor(const QString& label, const QString& tooltip, { } +DoubleDescriptor::DoubleDescriptor(const QString& label, double* var, + const variant<QString, Unit>& unit) + : label(label), decimals(3), limits(RealLimits::nonnegative()), unit(unit) +{ + set = [=](double v) { *var = v; }; + get = [=]() { return *var; }; +} + DoubleDescriptor::operator double() const { return get(); diff --git a/GUI/Model/Types/DoubleDescriptor.h b/GUI/Model/Types/DoubleDescriptor.h index 80c0aeb5a88837eb90b8cf5ad84d7b26759797c5..3fd1f54416d0e530fdac8ac8d9d23f91b6b91081 100644 --- a/GUI/Model/Types/DoubleDescriptor.h +++ b/GUI/Model/Types/DoubleDescriptor.h @@ -35,6 +35,8 @@ using std::variant; class DoubleDescriptor { public: + DoubleDescriptor(const DoubleDescriptor& other) = default; + //! Operates on a session item. The settings (like decimals, limits) are taken from the session //! item. //! Only for easier migration. Should be removed after SessionItem refactoring. @@ -45,6 +47,15 @@ public: //! Only for easier migration. Should be removed after SessionItem refactoring. DoubleDescriptor(const QString& label, SessionItem* item, const variant<QString, Unit>& unit); + DoubleDescriptor(const QString& label, double* var, const variant<QString, Unit>& unit); + + //! Operates on any kind of storage (e.g. session items), by using setter/getter methods + DoubleDescriptor(QString label, QString tooltip, int decimals, const RealLimits& limits, + function<void(double)> setter, function<double()> getter, + const variant<QString, Unit>& unit); + + DoubleDescriptor() = default; + private: // private as long as path initialization is not included in params (to be done after // SessionItem migration) //! Operates on a double value (e.g a member variable). @@ -56,11 +67,6 @@ private: // private as long as path initialization is not included in params (to DoubleDescriptor(const QString& label, const QString& tooltip, double* var, const variant<QString, Unit>& unit); - //! Operates on any kind of storage (e.g. session items), by using setter/getter methods - DoubleDescriptor(QString label, QString tooltip, int decimals, const RealLimits& limits, - function<void(double)> setter, function<double()> getter, - const variant<QString, Unit>& unit); - //! Operates on any kind of storage (e.g. session items), by using setter/getter methods //! decimals is set to 3, limits is set to nonnegative DoubleDescriptor(const QString& label, const QString& tooltip, function<void(double)> setter, diff --git a/GUI/Model/Types/VectorDescriptor.h b/GUI/Model/Types/VectorDescriptor.h index 46eb6b17ba21f61e133e9d4d286c52697857a4f7..567acf7369b6826ba8679a85c63ea9c4ba4d050c 100644 --- a/GUI/Model/Types/VectorDescriptor.h +++ b/GUI/Model/Types/VectorDescriptor.h @@ -38,6 +38,39 @@ public: { } + VectorDescriptor(const QString& label, const QString& tooltip, double* xVar, double* yVar, + double* zVar, const variant<QString, Unit>& unit) + : label(label), tooltip(tooltip), x("X", xVar, unit), y("Y", yVar, unit), z("Z", zVar, unit) + { + x.limits = RealLimits::limitless(); + y.limits = RealLimits::limitless(); + z.limits = RealLimits::limitless(); + x.decimals = 3; + y.decimals = 3; + z.decimals = 3; + x.tooltip = tooltip; + y.tooltip = tooltip; + z.tooltip = tooltip; + } + + VectorDescriptor(const QString& label, const QString& tooltip, + const variant<QString, Unit>& unit) + : label(label), tooltip(tooltip) + { + x.limits = RealLimits::limitless(); + y.limits = RealLimits::limitless(); + z.limits = RealLimits::limitless(); + x.decimals = 3; + y.decimals = 3; + z.decimals = 3; + x.tooltip = tooltip; + y.tooltip = tooltip; + z.tooltip = tooltip; + x.unit = unit; + y.unit = unit; + z.unit = unit; + } + QString label; //!< A label text (short, no trailing colon) QString tooltip; //!< Tooltip text DoubleDescriptor x; diff --git a/GUI/View/Fit/FitParameterWidget.cpp b/GUI/View/Fit/FitParameterWidget.cpp index 8197ff867e0fb507e8bf57f793ee0c74bbf7e5e2..c0b3b7d99e918a0433620a54749cb2429c194ec1 100644 --- a/GUI/View/Fit/FitParameterWidget.cpp +++ b/GUI/View/Fit/FitParameterWidget.cpp @@ -13,9 +13,9 @@ // ************************************************************************************************ #include "GUI/View/Fit/FitParameterWidget.h" +#include "GUI/Model/Fit/FitParameterContainerItem.h" #include "GUI/Model/Fit/FitParameterHelper.h" #include "GUI/Model/Fit/FitParameterItem.h" -#include "GUI/Model/Fit/FitParameterContainerItem.h" #include "GUI/Model/Fit/FitParameterLinkItem.h" #include "GUI/Model/Fit/FitParameterProxyModel.h" #include "GUI/Model/Fit/FitSuiteItem.h" @@ -151,10 +151,8 @@ void FitParameterWidget::onFitParametersSelectionChanged(const QItemSelection& s void FitParameterWidget::onCreateFitParAction() { for (auto* item : m_tuningWidget->getSelectedParameters()) { - if (!FitParameterHelper::getFitParameterItem(jobItem()->fitParameterContainerItem(), - item)) { + if (!jobItem()->fitParameterContainerItem()->fitParameterItem(item)) FitParameterHelper::createFitParameter(jobItem()->fitParameterContainerItem(), item); - } } } @@ -164,10 +162,9 @@ void FitParameterWidget::onCreateFitParAction() void FitParameterWidget::onRemoveFromFitParAction() { for (auto* item : m_tuningWidget->getSelectedParameters()) { - if (FitParameterHelper::getFitParameterItem(jobItem()->fitParameterContainerItem(), item)) { + if (jobItem()->fitParameterContainerItem()->fitParameterItem(item)) FitParameterHelper::removeFromFitParameters(jobItem()->fitParameterContainerItem(), item); - } } } @@ -313,8 +310,7 @@ bool FitParameterWidget::canCreateFitParameter() { QVector<ParameterItem*> selected = m_tuningWidget->getSelectedParameters(); for (auto* item : selected) { - if (FitParameterHelper::getFitParameterItem(jobItem()->fitParameterContainerItem(), item) - == nullptr) + if (jobItem()->fitParameterContainerItem()->fitParameterItem(item) == nullptr) return true; } return false; @@ -327,7 +323,7 @@ bool FitParameterWidget::canRemoveFromFitParameters() { QVector<ParameterItem*> selected = m_tuningWidget->getSelectedParameters(); for (auto* item : selected) { - if (FitParameterHelper::getFitParameterItem(jobItem()->fitParameterContainerItem(), item)) + if (jobItem()->fitParameterContainerItem()->fitParameterItem(item)) return true; } return false; diff --git a/GUI/View/Fit/ParameterTuningDelegate.cpp b/GUI/View/Fit/ParameterTuningDelegate.cpp index cc3d3758fe5b7edefdd7210f08a12ebdfd60052e..16521fca7febf33c90797e02d5e471d3697e3195 100644 --- a/GUI/View/Fit/ParameterTuningDelegate.cpp +++ b/GUI/View/Fit/ParameterTuningDelegate.cpp @@ -147,7 +147,7 @@ QWidget* ParameterTuningDelegate::createEditor(QWidget* parent, const QStyleOpti return nullptr; double value = data.toDouble(); - RealLimits limits = m_currentItem->linkedItem()->limits(); + RealLimits limits = m_currentItem->limitsOfLink(); m_tuning_info.setItemLimits(limits); m_tuning_info.value_to_slider(value); @@ -155,7 +155,7 @@ QWidget* ParameterTuningDelegate::createEditor(QWidget* parent, const QStyleOpti m_valueBox = new ScientificSpinBox(); m_valueBox->setKeyboardTracking(false); m_valueBox->setFixedWidth(105); - m_valueBox->setDecimals(m_currentItem->linkedItem()->decimals()); + m_valueBox->setDecimals(m_currentItem->decimalsOfLink()); m_valueBox->setSingleStep(m_tuning_info.step()); if (limits.hasLowerLimit()) { diff --git a/GUI/View/MaterialEditor/MaterialEditorDialog.cpp b/GUI/View/MaterialEditor/MaterialEditorDialog.cpp index 2299291f3e6977de61ca1e0f23c8666f462239eb..c499ca1c72704416a2fef26d23e8e56700c77119 100644 --- a/GUI/View/MaterialEditor/MaterialEditorDialog.cpp +++ b/GUI/View/MaterialEditor/MaterialEditorDialog.cpp @@ -19,6 +19,7 @@ #include "GUI/Model/Project/ProjectDocument.h" #include "GUI/Model/Sample/ItemWithMaterial.h" #include "GUI/Model/Sample/SampleModel.h" +#include "GUI/Model/Types/DoubleDescriptor.h" #include "GUI/Model/Types/VectorItem.h" #include "GUI/View/MaterialEditor/MaterialEditorModel.h" #include "GUI/View/Tool/EditUtil.h" @@ -145,12 +146,9 @@ MaterialEditorDialog::~MaterialEditorDialog() appSettings->saveWindowSizeAndPos(this); } -//! replaces original material model with the model modified by MaterialEditor void MaterialEditorDialog::accept() { - if (*m_document->materialModel() != *m_tmpMaterialModel) - m_document->materialModel()->initFrom(m_tmpMaterialModel.get(), nullptr); - + m_document->materialModel()->initFrom(*m_tmpMaterialModel); QDialog::accept(); } @@ -251,13 +249,11 @@ void MaterialEditorDialog::fill() m_ui->selectColorButton->setIcon(pixmap); if (materialItem->hasRefractiveIndex()) { - m_ui->deltaEdit->setText(QString::number(materialItem->refractiveIndexDelta(), 'g')); - m_ui->betaEdit->setText(QString::number(materialItem->refractiveIndexBeta(), 'g')); + m_ui->deltaEdit->setText(QString::number(materialItem->delta().get(), 'g')); + m_ui->betaEdit->setText(QString::number(materialItem->beta().get(), 'g')); } else { - m_ui->realEdit->setText( - QString::number(materialItem->scatteringLengthDensity().real(), 'g')); - m_ui->imaginaryEdit->setText( - QString::number(materialItem->scatteringLengthDensity().imag(), 'g')); + m_ui->realEdit->setText(QString::number(materialItem->sldRe().get(), 'g')); + m_ui->imaginaryEdit->setText(QString::number(materialItem->sldIm().get(), 'g')); } m_ui->xSpinBox->setValue(materialItem->magnetization().x()); diff --git a/GUI/View/MaterialEditor/MaterialEditorDialog.h b/GUI/View/MaterialEditor/MaterialEditorDialog.h index 11f0e7e9e0129fbeba099bd3274857e28d590d45..bf37d20260d359f32624ff68bcb17c5bc2b93834 100644 --- a/GUI/View/MaterialEditor/MaterialEditorDialog.h +++ b/GUI/View/MaterialEditor/MaterialEditorDialog.h @@ -49,6 +49,7 @@ private: MaterialEditorDialog(ProjectDocument* document, QWidget* parent = nullptr); ~MaterialEditorDialog() override; + //! updates original material model with the edited model void accept() override; void addRefractiveMaterial(); diff --git a/GUI/View/MaterialEditor/MaterialEditorModel.cpp b/GUI/View/MaterialEditor/MaterialEditorModel.cpp index 607cab48710de4a33fb1309b4ff142f4ee1f0807..6bf828f20ccf03a95ef834e2ced6350cc1a95859 100644 --- a/GUI/View/MaterialEditor/MaterialEditorModel.cpp +++ b/GUI/View/MaterialEditor/MaterialEditorModel.cpp @@ -15,6 +15,7 @@ #include "GUI/View/MaterialEditor/MaterialEditorModel.h" #include "GUI/Model/Material/MaterialItem.h" #include "GUI/Model/Material/MaterialModel.h" +#include "GUI/Model/Types/DoubleDescriptor.h" #include "GUI/Model/Types/VectorItem.h" #include <QApplication> #include <QFontMetrics> @@ -69,13 +70,9 @@ QVariant MaterialEditorModel::data(const QModelIndex& index, int role /*= Qt::Di case PARAMETERS: if (material->hasRefractiveIndex()) - return QString("delta: %1, beta: %2") - .arg(material->refractiveIndexDelta()) - .arg(material->refractiveIndexBeta()); + return QString("delta: %1, beta: %2").arg(material->delta()).arg(material->beta()); else - return QString("re: %1, im: %2") - .arg(material->scatteringLengthDensity().real()) - .arg(material->scatteringLengthDensity().imag()); + return QString("re: %1, im: %2").arg(material->sldRe()).arg(material->sldIm()); case MAGNETIZATION: return QString("%1/%2/%3") @@ -142,7 +139,7 @@ void MaterialEditorModel::setZ(const QModelIndex& index, double value) void MaterialEditorModel::setDelta(const QModelIndex& index, double value) { auto* m = materialFromIndex(index); - m->setRefractiveIndex(value, m->refractiveIndexBeta()); + m->setRefractiveIndex(value, m->beta()); const auto paramIndex = this->index(index.row(), PARAMETERS); emit dataChanged(paramIndex, paramIndex); } @@ -150,7 +147,7 @@ void MaterialEditorModel::setDelta(const QModelIndex& index, double value) void MaterialEditorModel::setBeta(const QModelIndex& index, double value) { auto* m = materialFromIndex(index); - m->setRefractiveIndex(m->refractiveIndexDelta(), value); + m->setRefractiveIndex(m->delta(), value); const auto paramIndex = this->index(index.row(), PARAMETERS); emit dataChanged(paramIndex, paramIndex); } @@ -158,7 +155,7 @@ void MaterialEditorModel::setBeta(const QModelIndex& index, double value) void MaterialEditorModel::setRe(const QModelIndex& index, double value) { auto* m = materialFromIndex(index); - m->setScatteringLengthDensity(complex_t(value, m->scatteringLengthDensity().imag())); + m->setScatteringLengthDensity(complex_t(value, m->sldIm())); auto paramIndex = this->index(index.row(), PARAMETERS); emit dataChanged(paramIndex, paramIndex); } @@ -166,7 +163,7 @@ void MaterialEditorModel::setRe(const QModelIndex& index, double value) void MaterialEditorModel::setIm(const QModelIndex& index, double value) { auto* m = materialFromIndex(index); - m->setScatteringLengthDensity(complex_t(m->scatteringLengthDensity().real(), value)); + m->setScatteringLengthDensity(complex_t(m->sldRe(), value)); auto paramIndex = this->index(index.row(), PARAMETERS); emit dataChanged(paramIndex, paramIndex); } @@ -219,7 +216,7 @@ MaterialItem* MaterialEditorModel::addSLDMaterial(const QString& name, double sl MaterialItem* MaterialEditorModel::cloneMaterial(const QModelIndex& index) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); - auto* m = m_model->cloneMaterial(materialFromIndex(index)); + auto* m = m_model->insertCopy(*materialFromIndex(index)); endInsertRows(); return m; } diff --git a/GUI/View/MaterialEditor/MaterialEditorModel.h b/GUI/View/MaterialEditor/MaterialEditorModel.h index 8b24d45d31439e02e7ed7a0cfc873dda7913a874..92486aac46beba13d95556deca2688126962c23c 100644 --- a/GUI/View/MaterialEditor/MaterialEditorModel.h +++ b/GUI/View/MaterialEditor/MaterialEditorModel.h @@ -21,9 +21,7 @@ class MaterialItem; class MaterialModel; //! Model for list of materials, used in MaterialEditorDialog. -//! This model is not derived from QAbstractProxyModel, despite the handled material list is -//! of type SessionModel and therefore a QAbstractItemModel. The reason is to ease a later -//! migration away from SessionModel. +//! //! This model is also used for changing values of a material, therefore the list can be //! updated accordingly. class MaterialEditorModel : public QAbstractTableModel { diff --git a/GUI/View/SampleDesigner/LayerForm.cpp b/GUI/View/SampleDesigner/LayerForm.cpp index 8d424affb24ef23aec8ba8b49000e59ae2836f3b..32237a2958fc4ee52c893e6a77ae6b3094ff06e3 100644 --- a/GUI/View/SampleDesigner/LayerForm.cpp +++ b/GUI/View/SampleDesigner/LayerForm.cpp @@ -13,6 +13,8 @@ // ************************************************************************************************ #include "GUI/View/SampleDesigner/LayerForm.h" +#include "GUI/Model/Material/MaterialItem.h" +#include "GUI/Model/Material/MaterialModel.h" #include "GUI/Model/Sample/LayerItem.h" #include "GUI/Model/Sample/MultiLayerItem.h" #include "GUI/Model/Types/UIntDescriptor.h" @@ -90,6 +92,10 @@ LayerForm::LayerForm(QWidget* parent, LayerItem* layer, SampleEditorController* m_structureEditingWidgets << btn; m_layouter->addStructureEditingRow(btn); + // listen to changes in materials to update the title (contains the material name). Necessary + // to reflect e.g. a name change done in the material editor. + connect(ec->materialModel(), &MaterialModel::materialChanged, this, &LayerForm::updateTitle); + updateLayerPositionDependentElements(); } diff --git a/GUI/View/SampleDesigner/LayerOrientedSampleEditor.cpp b/GUI/View/SampleDesigner/LayerOrientedSampleEditor.cpp index 0cb348c5e0ae2956d9bb7f8975663bf7483e57b3..485f3bfb6dfd80f31ada4398a8cb28e6baf7f52d 100644 --- a/GUI/View/SampleDesigner/LayerOrientedSampleEditor.cpp +++ b/GUI/View/SampleDesigner/LayerOrientedSampleEditor.cpp @@ -110,9 +110,8 @@ void LayerOrientedSampleEditor::setCurrentSample(MultiLayerItem* multiLayerItem) } if (!m_editControllers.contains(m_currentMultiLayerItem)) - m_editControllers.insert( - m_currentMultiLayerItem, - new SampleEditorController(m_document->materialModel(), m_currentMultiLayerItem)); + m_editControllers.insert(m_currentMultiLayerItem, + new SampleEditorController(m_document, m_currentMultiLayerItem)); auto* ec = m_editControllers[m_currentMultiLayerItem]; connect(ec, &SampleEditorController::requestViewInRealSpace, this, &LayerOrientedSampleEditor::requestViewInRealSpace); diff --git a/GUI/View/SampleDesigner/MaterialInplaceForm.cpp b/GUI/View/SampleDesigner/MaterialInplaceForm.cpp index b5e638a814dc0b68e07bdfe4362c59f4af39bc58..7a123f8a54c847645211b4f0e3f6a284c5077ab9 100644 --- a/GUI/View/SampleDesigner/MaterialInplaceForm.cpp +++ b/GUI/View/SampleDesigner/MaterialInplaceForm.cpp @@ -17,7 +17,6 @@ #include "GUI/Model/Material/MaterialModel.h" #include "GUI/Model/Sample/ItemWithMaterial.h" #include "GUI/Model/Session/ModelPath.h" -#include "GUI/Model/State/SessionData.h" #include "GUI/Model/Types/DoubleDescriptor.h" #include "GUI/Model/Types/VectorDescriptor.h" #include "GUI/View/Edit/DoubleLineEdit.h" @@ -40,7 +39,7 @@ MaterialInplaceForm::MaterialInplaceForm(QWidget* parent, ItemWithMaterial* item m_layout->setContentsMargins(0, 0, 0, 0); createWidgets(); - connect(gSessionData->projectDocument->materialModel(), &MaterialModel::materialChanged, this, + connect(itemWithMaterial()->materialItem(), &MaterialItem::dataChanged, this, &MaterialInplaceForm::onMaterialChanged); } @@ -64,12 +63,15 @@ void MaterialInplaceForm::updateValues() void MaterialInplaceForm::selectMaterial() { const QString newMaterialIdentifier = MaterialEditorDialog::chooseMaterial( - baWin, gSessionData->projectDocument, m_item->materialIdentifier()); + baWin, m_ec->projectDocument(), m_item->materialIdentifier()); if (!newMaterialIdentifier.isEmpty() && newMaterialIdentifier != m_item->materialIdentifier()) { + itemWithMaterial()->materialItem()->disconnect(this); GUI::Util::Layout::clearLayout(m_layout, true); m_ec->selectMaterial(m_item, newMaterialIdentifier); createWidgets(); + connect(itemWithMaterial()->materialItem(), &MaterialItem::dataChanged, this, + &MaterialInplaceForm::onMaterialChanged); } else updateValues(); // necessary, since in the material editor the values could have been // changed without selecting a different material @@ -77,44 +79,15 @@ void MaterialInplaceForm::selectMaterial() void MaterialInplaceForm::createWidgets() { - // We can not use the DoubleDescriptors from the MaterialItem itself, because e.g. when editing - // a material in the material editor, the whole material model will be created from scratch. - // This means, that all SessionItems will be deleted. If we would use these SessionItems, a - // crash will happen once an access takes place. - // What not changes is the material identifier (it is not changed when - // material is edited in the material editor dialog). Therefore DoubleDescriptors have to be - // created which use the material identifier for every access. - // In the following, first the descriptors are copied - // from the MaterialItem descriptors to get the labels, tooltips etc. Then for set, get & - // path the functions are redefined to use the material identifier. + auto* material = m_item->materialItem(); + ASSERT(material); // -- Create UI for delta/beta resp. sldRe/sldIm DoubleDescriptors values; - if (material()->hasRefractiveIndex()) { - DoubleDescriptor delta = material()->delta(); - delta.set = [=](double value) { material()->delta().set(value); }; - delta.get = [=]() { return material()->delta(); }; - delta.path = [=] { return GUI::Model::Path::getPathFromItem(m_item) + "/delta"; }; - - DoubleDescriptor beta = material()->beta(); - beta.set = [=](double value) { material()->beta().set(value); }; - beta.get = [=]() { return material()->beta(); }; - beta.path = [=] { return GUI::Model::Path::getPathFromItem(m_item) + "/beta"; }; - - values << delta << beta; - } else { - DoubleDescriptor re = material()->sldRe(); - re.set = [=](double value) { material()->sldRe().set(value); }; - re.get = [=]() { return material()->sldRe(); }; - re.path = [=] { return GUI::Model::Path::getPathFromItem(m_item) + "/re"; }; - - DoubleDescriptor im = material()->sldIm(); - im.set = [=](double value) { material()->sldIm().set(value); }; - im.get = [=]() { return material()->sldIm(); }; - im.path = [=] { return GUI::Model::Path::getPathFromItem(m_item) + "/im"; }; - - values << re << im; - } + if (material->hasRefractiveIndex()) + values << material->delta() << material->beta(); + else + values << material->sldRe() << material->sldIm(); int col = 0; for (const auto& d : values) { @@ -130,23 +103,10 @@ void MaterialInplaceForm::createWidgets() } // -- Create UI for magnetization vector - VectorDescriptor mag = material()->magnetizationVector(); - mag.x.set = [=](double value) { material()->magnetizationVector().x.set(value); }; - mag.x.get = [=]() { return material()->magnetizationVector().x; }; - mag.x.path = [=] { return GUI::Model::Path::getPathFromItem(m_item) + "/x"; }; - - mag.y.set = [=](double value) { material()->magnetizationVector().y.set(value); }; - mag.y.get = [=]() { return material()->magnetizationVector().y; }; - mag.y.path = [=] { return GUI::Model::Path::getPathFromItem(m_item) + "/y"; }; - - mag.z.set = [=](double value) { material()->magnetizationVector().z.set(value); }; - mag.z.get = [=]() { return material()->magnetizationVector().z; }; - mag.z.path = [=] { return GUI::Model::Path::getPathFromItem(m_item) + "/z"; }; - + VectorDescriptor mag = material->magnetizationVector(); const auto setNewValue = [=](double value, DoubleDescriptor d) { m_ec->setMaterialValue(m_item, value, d); }; - LayerEditorUtils::addVectorToGrid(m_layout, col, mag, setNewValue, true, false); // -- Create UI for material selection button @@ -158,13 +118,7 @@ void MaterialInplaceForm::createWidgets() m_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, m_layout->columnCount()); } -MaterialItem* MaterialInplaceForm::material() -{ - return m_item->materialItem(); -} - -void MaterialInplaceForm::onMaterialChanged(MaterialItem* materialItem) +void MaterialInplaceForm::onMaterialChanged() { - if (materialItem->identifier() == m_item->materialIdentifier()) - updateValues(); + updateValues(); } diff --git a/GUI/View/SampleDesigner/MaterialInplaceForm.h b/GUI/View/SampleDesigner/MaterialInplaceForm.h index 0d1faa4fc1256e84660e5dc611b468e8bf4ae4fb..db0fd6b063cc45b1df8c457018ff5e2b668b4272 100644 --- a/GUI/View/SampleDesigner/MaterialInplaceForm.h +++ b/GUI/View/SampleDesigner/MaterialInplaceForm.h @@ -34,8 +34,7 @@ public: private: void selectMaterial(); void createWidgets(); - MaterialItem* material(); - void onMaterialChanged(MaterialItem* materialItem); + void onMaterialChanged(); ItemWithMaterial* m_item; SampleEditorController* m_ec; diff --git a/GUI/View/SampleDesigner/SampleEditorController.cpp b/GUI/View/SampleDesigner/SampleEditorController.cpp index 6f9cabb02146b474e9a134cbfa16bf66fea24a75..b7a2376ecc31a46f87aa4543060636127a879cfb 100644 --- a/GUI/View/SampleDesigner/SampleEditorController.cpp +++ b/GUI/View/SampleDesigner/SampleEditorController.cpp @@ -14,6 +14,7 @@ #include "GUI/View/SampleDesigner/SampleEditorController.h" #include "GUI/Model/Material/MaterialModel.h" +#include "GUI/Model/Project/ProjectDocument.h" #include "GUI/Model/Sample/InterferenceItems.h" #include "GUI/Model/Sample/LayerItem.h" #include "GUI/Model/Sample/MesoCrystalItem.h" @@ -35,8 +36,8 @@ #include "GUI/View/SampleDesigner/ParticleLayoutForm.h" #include "GUI/View/SampleDesigner/SampleEditorCommands.h" -SampleEditorController::SampleEditorController(MaterialModel* materialModel, MultiLayerItem* multi) - : m_multiLayerItem(multi), m_multiLayerForm(nullptr), m_materialModel(materialModel) +SampleEditorController::SampleEditorController(ProjectDocument* document, MultiLayerItem* multi) + : m_multiLayerItem(multi), m_multiLayerForm(nullptr), m_document(document) { } @@ -96,8 +97,8 @@ void SampleEditorController::addLayer(LayerItem* before) // - create new layer LayerItem* layer = m_multiLayerItem->addLayer(rowInMultiLayer); - layer->setMaterialModel(m_materialModel); - layer->setMaterial(m_materialModel->defaultMaterial()); + layer->setMaterialModel(materialModel()); + layer->setMaterial(materialModel()->defaultMaterial()); layer->setColor(color); ASSERT(m_multiLayerForm); @@ -129,9 +130,9 @@ void SampleEditorController::addParticle(ParticleLayoutItem* layoutItem, const Q SessionItem* newItem = nullptr; if (ItemCatalog::isFormFactorModelType(classname)) { auto* new_particle = layoutItem->model()->insertItem<ParticleItem>(layoutItem); - new_particle->setMaterialModel(m_materialModel); + new_particle->setMaterialModel(materialModel()); new_particle->setFormFactor(classname); - new_particle->setMaterial(m_materialModel->defaultMaterial()); + new_particle->setMaterial(materialModel()->defaultMaterial()); newItem = new_particle; } else newItem = layoutItem->model()->insertNewItem(classname, layoutItem); @@ -155,9 +156,9 @@ void SampleEditorController::addParticle(ParticleCompositionItem* compositionIte SessionItem* newItem = nullptr; if (ItemCatalog::isFormFactorModelType(classname)) { auto* new_particle = compositionItem->model()->insertItem<ParticleItem>(compositionItem); - new_particle->setMaterialModel(m_materialModel); + new_particle->setMaterialModel(materialModel()); new_particle->setFormFactor(classname); - new_particle->setMaterial(m_materialModel->defaultMaterial()); + new_particle->setMaterial(materialModel()->defaultMaterial()); newItem = new_particle; } else newItem = compositionItem->model()->insertNewItem(classname, compositionItem); @@ -293,7 +294,12 @@ QUndoStack* SampleEditorController::undoStack() MaterialModel* SampleEditorController::materialModel() const { - return m_materialModel; + return m_document->materialModel(); +} + +ProjectDocument* SampleEditorController::projectDocument() const +{ + return m_document; } void SampleEditorController::selectMaterial(ItemWithMaterial* item, diff --git a/GUI/View/SampleDesigner/SampleEditorController.h b/GUI/View/SampleDesigner/SampleEditorController.h index 0988bb028797766227e736f05cb864a4e51cbcf0..d8884055c0e092df7e715a20d0ab0c72262d187a 100644 --- a/GUI/View/SampleDesigner/SampleEditorController.h +++ b/GUI/View/SampleDesigner/SampleEditorController.h @@ -37,6 +37,7 @@ class InterferenceItem; class AbstractSelectionContainerForm; class LatticeTypeSelectionForm; class MaterialModel; +class ProjectDocument; //! Class to modify a sample from the layer oriented sample editor. //! @@ -46,7 +47,7 @@ class MaterialModel; class SampleEditorController : public QObject { Q_OBJECT public: - SampleEditorController(MaterialModel* materialModel, MultiLayerItem* multi); + SampleEditorController(ProjectDocument* document, MultiLayerItem* multi); //! Set the current form. //! @@ -66,6 +67,9 @@ public: //! The materials of the current document MaterialModel* materialModel() const; + //! The current document + ProjectDocument* projectDocument() const; + void addLayer(LayerItem* before); void removeLayer(LayerItem* layerItem); void addLayout(LayerForm* layerItem); @@ -109,7 +113,7 @@ private: QUndoStack m_undoStack; MultiLayerItem* m_multiLayerItem; MultiLayerForm* m_multiLayerForm; - MaterialModel* m_materialModel; + ProjectDocument* m_document; }; diff --git a/GUI/View/SampleDesigner/SampleListView.cpp b/GUI/View/SampleDesigner/SampleListView.cpp index 1b322e941459a6cd00caa67ac0358167fe9b57e5..7021d7b8d8b968d15baba0dcad14b452a80592db 100644 --- a/GUI/View/SampleDesigner/SampleListView.cpp +++ b/GUI/View/SampleDesigner/SampleListView.cpp @@ -15,9 +15,9 @@ #include "GUI/View/SampleDesigner/SampleListView.h" #include "GUI/Application/ApplicationSettings.h" #include "GUI/Model/From/GUIExamplesFactory.h" -#include "GUI/Model/Sample/MultiLayerItem.h" #include "GUI/Model/From/SampleListModel.h" -#include "GUI/Model/State/SessionData.h" +#include "GUI/Model/Project/ProjectDocument.h" +#include "GUI/Model/Sample/MultiLayerItem.h" #include "GUI/View/Common/ItemViewOverlayButtons.h" #include "GUI/View/Tool/ItemDelegateForHTML.h" #include <QAction> @@ -63,9 +63,10 @@ protected: } // namespace -SampleListView::SampleListView(QWidget* parent, SampleModel* sampleModel) : QListView(parent) +SampleListView::SampleListView(QWidget* parent, ProjectDocument* document) + : QListView(parent), m_document(document) { - m_model = new SampleListModel(this, sampleModel); + m_model = new SampleListModel(this, document->sampleModel()); setContextMenuPolicy(Qt::CustomContextMenu); setModel(m_model); @@ -143,8 +144,8 @@ void SampleListView::createNewSample() void SampleListView::createSampleFromLibrary(const QString& classname, const QString& title, const QString& description) { - const QModelIndex newIndex = m_model->createSampleFromExamples( - classname, title, description, gSessionData->projectDocument->materialModel()); + const QModelIndex newIndex = m_model->createSampleFromExamples(classname, title, description, + m_document->materialModel()); setCurrentIndex(newIndex); } diff --git a/GUI/View/SampleDesigner/SampleListView.h b/GUI/View/SampleDesigner/SampleListView.h index 1a39f4c031a731624e00ca1c0ced1627ff2f2345..1c5ce889ef1fb0c25431632c387ef10e862c4a8c 100644 --- a/GUI/View/SampleDesigner/SampleListView.h +++ b/GUI/View/SampleDesigner/SampleListView.h @@ -17,15 +17,15 @@ #include <QListView> -class SampleModel; class SampleListModel; class MultiLayerItem; +class ProjectDocument; //! List view to select one sample (left side of layer-oriented sample editor) class SampleListView : public QListView { Q_OBJECT public: - SampleListView(QWidget* parent, SampleModel* sampleModel); + SampleListView(QWidget* parent, ProjectDocument* document); void setCurrentSample(MultiLayerItem* multiLayer); MultiLayerItem* currentSample(); @@ -53,6 +53,7 @@ private: private: SampleListModel* m_model; + ProjectDocument* m_document; QAction* m_newSampleAction; QAction* m_chooseFromLibraryAction; }; diff --git a/GUI/View/SampleDesigner/SampleView.cpp b/GUI/View/SampleDesigner/SampleView.cpp index 8b86b36743956e90ee40a6e76d370f535b3ec39c..6ccb40759cc433f9df350d0ff066051279b9f4bd 100644 --- a/GUI/View/SampleDesigner/SampleView.cpp +++ b/GUI/View/SampleDesigner/SampleView.cpp @@ -47,7 +47,7 @@ SampleView::SampleView(QWidget* parent, ProjectDocument* document) sampleSelectionLayout->setSpacing(0); auto* sampleSelectionToolbar = new StyledToolBar(sampleSelectionPane); - auto* sampleSelectionView = new SampleListView(this, m_document->sampleModel()); + auto* sampleSelectionView = new SampleListView(this, m_document); sampleSelectionToolbar->addAction(sampleSelectionView->newSampleAction()); sampleSelectionToolbar->addAction(sampleSelectionView->chooseFromLibraryAction()); if (auto* btn = dynamic_cast<QToolButton*>(sampleSelectionToolbar->widgetForAction( diff --git a/GUI/View/Toplevel/SessionModelView.cpp b/GUI/View/Toplevel/SessionModelView.cpp index df58eb8ce370d97c0cbc1d55552a1c77fcbfd6f6..bba330a1fcc2dc7e406fd76a5b34094dd40717c2 100644 --- a/GUI/View/Toplevel/SessionModelView.cpp +++ b/GUI/View/Toplevel/SessionModelView.cpp @@ -105,8 +105,7 @@ SessionModelView::SessionModelView(QWidget* parent, ProjectDocument* document) : layout->addWidget(tabs); QList<SessionModel*> models{document->instrumentModel(), document->sampleModel(), - document->realDataModel(), document->materialModel(), - document->jobModel()}; + document->realDataModel(), document->jobModel()}; for (auto* model : models) { auto* treeView = new QTreeView(this); diff --git a/Tests/Unit/GUI/TestMaterialModel.cpp b/Tests/Unit/GUI/TestMaterialModel.cpp index c71d7bff5d3268861568266693f1cd4e7161616a..28c755a7e975e25e58dcc3cf1762f053273a27fb 100644 --- a/Tests/Unit/GUI/TestMaterialModel.cpp +++ b/Tests/Unit/GUI/TestMaterialModel.cpp @@ -1,6 +1,6 @@ -#include "GUI/Model/Material/MaterialDataItems.h" #include "GUI/Model/Material/MaterialItem.h" #include "GUI/Model/Material/MaterialModel.h" +#include "GUI/Model/Types/DoubleDescriptor.h" #include "Tests/GTestWrapper/google_test.h" #include <memory> @@ -18,12 +18,11 @@ TEST_F(TestMaterialModel, addRefractiveMaterial) MaterialItem* material = model->addRefractiveMaterial(name, delta, beta); EXPECT_EQ(model->materialItems().size(), 1); - EXPECT_EQ(model->itemForIndex(material->index()), material); EXPECT_EQ(material->materialName(), name); EXPECT_TRUE(material->hasRefractiveIndex()); - EXPECT_EQ(material->refractiveIndexDelta(), delta); - EXPECT_EQ(material->refractiveIndexBeta(), beta); + EXPECT_EQ(material->delta(), delta); + EXPECT_EQ(material->beta(), beta); } TEST_F(TestMaterialModel, addSLDMaterial) @@ -37,11 +36,11 @@ TEST_F(TestMaterialModel, addSLDMaterial) MaterialItem* material = model->addSLDMaterial(name, sld_real, sld_imag); EXPECT_EQ(model->materialItems().size(), 1); - EXPECT_EQ(model->itemForIndex(material->index()), material); EXPECT_EQ(material->materialName(), name); EXPECT_FALSE(material->hasRefractiveIndex()); - EXPECT_EQ(material->scatteringLengthDensity(), complex_t(sld_real, sld_imag)); + EXPECT_EQ(material->sldRe(), sld_real); + EXPECT_EQ(material->sldIm(), sld_imag); } TEST_F(TestMaterialModel, cloneMaterialRefractive) @@ -55,7 +54,7 @@ TEST_F(TestMaterialModel, cloneMaterialRefractive) MaterialItem* material = model->addRefractiveMaterial(name, delta, beta); const QString origIdentifier = material->identifier(); - MaterialItem* clonedMaterial = model->cloneMaterial(material); + MaterialItem* clonedMaterial = model->insertCopy(*material); EXPECT_EQ(model->materialItems().size(), 2); // clone should not change identifier of original material (as it once happened) @@ -67,8 +66,8 @@ TEST_F(TestMaterialModel, cloneMaterialRefractive) // checking name of cloned material EXPECT_EQ(material->materialName() + " (copy)", clonedMaterial->materialName()); EXPECT_EQ(material->hasRefractiveIndex(), clonedMaterial->hasRefractiveIndex()); - EXPECT_EQ(material->refractiveIndexDelta(), delta); - EXPECT_EQ(material->refractiveIndexBeta(), beta); + EXPECT_EQ(material->delta(), delta); + EXPECT_EQ(material->beta(), beta); } TEST_F(TestMaterialModel, cloneMaterialSLD) @@ -82,7 +81,7 @@ TEST_F(TestMaterialModel, cloneMaterialSLD) MaterialItem* material = model->addSLDMaterial(name, real, imag); const QString origIdentifier = material->identifier(); - MaterialItem* clonedMaterial = model->cloneMaterial(material); + MaterialItem* clonedMaterial = model->insertCopy(*material); EXPECT_EQ(model->materialItems().size(), 2); // clone should not change identifier of original material (as it once happened) @@ -94,7 +93,8 @@ TEST_F(TestMaterialModel, cloneMaterialSLD) // checking name of cloned material EXPECT_EQ(material->materialName() + " (copy)", clonedMaterial->materialName()); EXPECT_EQ(material->hasRefractiveIndex(), clonedMaterial->hasRefractiveIndex()); - EXPECT_EQ(material->scatteringLengthDensity(), complex_t(real, imag)); + EXPECT_EQ(material->sldRe(), real); + EXPECT_EQ(material->sldIm(), imag); } //! Checks the method which returns MaterialItem from known identifier. diff --git a/Tests/Unit/GUI/TestRealSpaceBuilderUtils.cpp b/Tests/Unit/GUI/TestRealSpaceBuilderUtils.cpp index 2ab7fb5f9dca93d1a49bd194f2f47a7282fad8f6..94999baa23debefc6290a828750d7286a98330a8 100644 --- a/Tests/Unit/GUI/TestRealSpaceBuilderUtils.cpp +++ b/Tests/Unit/GUI/TestRealSpaceBuilderUtils.cpp @@ -154,11 +154,13 @@ TEST_F(TestRealSpaceBuilderUtils, Particle3DContainer) TEST_F(TestRealSpaceBuilderUtils, singleParticle3DContainer) { ApplicationModels models; + MaterialModel materialModel; + materialModel.addRefractiveMaterial("Default", 1e-3, 1e-5); SampleModel* sampleModel = models.sampleModel(); auto* particleItem = sampleModel->insertItem<ParticleItem>(); - particleItem->setMaterial(models.materialModel()->defaultMaterial()); - particleItem->setMaterialModel(models.materialModel()); + particleItem->setMaterial(materialModel.defaultMaterial()); + particleItem->setMaterialModel(&materialModel); EXPECT_EQ(particleItem->abundance(), 1.0); EXPECT_TRUE(particleItem->formFactor()->hasModelType<CylinderItem>()); @@ -170,8 +172,8 @@ TEST_F(TestRealSpaceBuilderUtils, singleParticle3DContainer) // Create a 3D particle from particleItem and associate it to a Particle3DContainer object const auto* pItem = dynamic_cast<const ParticleItem*>(particleItem); auto particle = pItem->createParticle(); - auto singleParticle3DContainer = GUI::RealSpace::BuilderUtils(models.materialModel()) - .singleParticle3DContainer(*particle, 8); + auto singleParticle3DContainer = + GUI::RealSpace::BuilderUtils(&materialModel).singleParticle3DContainer(*particle, 8); EXPECT_EQ(singleParticle3DContainer.containerSize(), 1u); EXPECT_EQ(singleParticle3DContainer.cumulativeAbundance(), 1); @@ -182,18 +184,20 @@ TEST_F(TestRealSpaceBuilderUtils, singleParticle3DContainer) TEST_F(TestRealSpaceBuilderUtils, particle3DContainerVector) { ApplicationModels models; + MaterialModel materialModel; + materialModel.addRefractiveMaterial("Default", 1e-3, 1e-5); SampleModel* sampleModel = models.sampleModel(); auto* layout = sampleModel->insertItem<ParticleLayoutItem>(); auto* particle1 = sampleModel->insertItem<ParticleItem>(); auto* particle2 = sampleModel->insertItem<ParticleItem>(); auto* particle3 = sampleModel->insertItem<ParticleItem>(); - particle1->setMaterial(models.materialModel()->defaultMaterial()); - particle2->setMaterial(models.materialModel()->defaultMaterial()); - particle3->setMaterial(models.materialModel()->defaultMaterial()); - particle1->setMaterialModel(models.materialModel()); - particle2->setMaterialModel(models.materialModel()); - particle3->setMaterialModel(models.materialModel()); + particle1->setMaterial(materialModel.defaultMaterial()); + particle2->setMaterial(materialModel.defaultMaterial()); + particle3->setMaterial(materialModel.defaultMaterial()); + particle1->setMaterialModel(&materialModel); + particle2->setMaterialModel(&materialModel); + particle3->setMaterialModel(&materialModel); layout->addParticle(particle1); layout->addParticle(particle2); @@ -203,9 +207,8 @@ TEST_F(TestRealSpaceBuilderUtils, particle3DContainerVector) particle2->setAbundance(3.0); particle3->setAbundance(2.0); - double total_abundance = GUI::RealSpace::BuilderUtils(models.materialModel()) - .computeCumulativeAbundances(*layout) - .last(); + double total_abundance = + GUI::RealSpace::BuilderUtils(&materialModel).computeCumulativeAbundances(*layout).last(); EXPECT_EQ(total_abundance, 10.0); particle1->setFormFactorType<BoxItem>(); @@ -213,7 +216,7 @@ TEST_F(TestRealSpaceBuilderUtils, particle3DContainerVector) particle3->setFormFactorType<PyramidItem>(); auto particle3DContainer_vector = - GUI::RealSpace::BuilderUtils(models.materialModel()).particle3DContainerVector(*layout); + GUI::RealSpace::BuilderUtils(&materialModel).particle3DContainerVector(*layout); EXPECT_EQ(particle3DContainer_vector.size(), static_cast<size_t>(3));