diff --git a/Fit/Kernel/MinimizerFactory.cpp b/Fit/Kernel/MinimizerFactory.cpp index 7710f5a2633f9dde0eb4c135f389ab1fa8200243..8785830c0eae74b02d490aed55a764bad1991f19 100644 --- a/Fit/Kernel/MinimizerFactory.cpp +++ b/Fit/Kernel/MinimizerFactory.cpp @@ -18,7 +18,6 @@ #include "Fit/Adapter/GeneticMinimizer.h" #include "Fit/Adapter/Minuit2Minimizer.h" #include "Fit/Adapter/SimAnMinimizer.h" -#include "Fit/Minimizer/TestMinimizer.h" #include <boost/format.hpp> #include <iomanip> #include <iostream> @@ -51,10 +50,6 @@ IMinimizer* MinimizerFactory::createMinimizer(const std::string& minimizerName, result = new GeneticMinimizer(); } - else if (minimizerName == "Test") { - result = new TestMinimizer(); - } - if (!result) { std::ostringstream ostr; ostr << "MinimizerFactory::MinimizerFactory() -> Error! Can't create minimizer for given " diff --git a/Fit/Minimizer/MinimizerCatalog.cpp b/Fit/Minimizer/MinimizerCatalog.cpp index 26c0538af798f2ff810967ac4e2a6c99ea26b8d2..8e55210d20f16fec6055404218eafbc1a82d64c2 100644 --- a/Fit/Minimizer/MinimizerCatalog.cpp +++ b/Fit/Minimizer/MinimizerCatalog.cpp @@ -24,7 +24,6 @@ MinimizerCatalog::MinimizerCatalog() addMinimizerInfo(MinimizerInfo::buildGSLLMAInfo()); addMinimizerInfo(MinimizerInfo::buildGSLSimAnInfo()); addMinimizerInfo(MinimizerInfo::buildGeneticInfo()); - addMinimizerInfo(MinimizerInfo::buildTestMinimizerInfo()); } //! Returns multiline string representing catalog content. diff --git a/Fit/Minimizer/MinimizerInfo.cpp b/Fit/Minimizer/MinimizerInfo.cpp index d4f386b89aa3c53acc8868b03394dea9c37f74b8..e5421a7c74807b39daec1c19bff606be60a3d715 100644 --- a/Fit/Minimizer/MinimizerInfo.cpp +++ b/Fit/Minimizer/MinimizerInfo.cpp @@ -130,15 +130,6 @@ MinimizerInfo MinimizerInfo::buildGeneticInfo() return result; } -//! Creates information for simple test minimizer - -MinimizerInfo MinimizerInfo::buildTestMinimizerInfo() -{ - MinimizerInfo result("Test", "One-shot minimizer to test whole chain"); - result.addAlgorithm("Default", "Default algorithm"); - return result; -} - //! Adds minimizer algorithm to the list of defined algorithms. void MinimizerInfo::addAlgorithm(const AlgorithmInfo& algorithm) diff --git a/Fit/Minimizer/MinimizerInfo.h b/Fit/Minimizer/MinimizerInfo.h index e3b5091e2d7c815677410cac777595eb3d12ce71..92bebd33e44a67ddb29e4f33f06905e086729696 100644 --- a/Fit/Minimizer/MinimizerInfo.h +++ b/Fit/Minimizer/MinimizerInfo.h @@ -66,7 +66,6 @@ public: static MinimizerInfo buildGSLLMAInfo(); static MinimizerInfo buildGSLSimAnInfo(); static MinimizerInfo buildGeneticInfo(); - static MinimizerInfo buildTestMinimizerInfo(); private: void addAlgorithm(const AlgorithmInfo& algorithm); diff --git a/Fit/Minimizer/TestMinimizer.cpp b/Fit/Minimizer/TestMinimizer.cpp deleted file mode 100644 index 5ec62fd458a19d9511431a216fec34b6acd3b64a..0000000000000000000000000000000000000000 --- a/Fit/Minimizer/TestMinimizer.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file Fit/Minimizer/TestMinimizer.cpp -//! @brief Implements class TrivialMinimizer. -//! -//! @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 "Fit/Minimizer/TestMinimizer.h" -#include <sstream> - -using namespace mumufit; - -TestMinimizer::TestMinimizer() = default; - -TestMinimizer::~TestMinimizer() = default; - -std::string TestMinimizer::minimizerName() const -{ - return "Test"; -} - -MinimizerResult TestMinimizer::minimize_scalar(fcn_scalar_t fcn, mumufit::Parameters parameters) -{ - // calling user function once - auto min_value = fcn(parameters); - - MinimizerResult result; - result.setParameters(parameters); - result.setMinValue(min_value); - - std::ostringstream report; - report << "TestMinimizer::printOutcome() -> Done. Objective function value = " << min_value - << std::endl; - - result.setReport(report.str()); - result.setNumberOfCalls(1); - - return result; -} diff --git a/Fit/Minimizer/TestMinimizer.h b/Fit/Minimizer/TestMinimizer.h deleted file mode 100644 index 52a83c28f3f396423a02c01ed3f63985e035d171..0000000000000000000000000000000000000000 --- a/Fit/Minimizer/TestMinimizer.h +++ /dev/null @@ -1,44 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file Fit/Minimizer/TestMinimizer.h -//! @brief Defines class TestMinimizer. -//! -//! @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) -// -// ************************************************************************************************ - -#ifdef SWIG -#error no need to expose this header to Swig -#endif - -#ifndef USER_API -#ifndef BORNAGAIN_FIT_MINIMIZER_TESTMINIMIZER_H -#define BORNAGAIN_FIT_MINIMIZER_TESTMINIMIZER_H - -#include "Fit/Minimizer/IMinimizer.h" - -//! A trivial minimizer that calls the objective function once. Used to test the whole chain. - -class TestMinimizer : public IMinimizer { -public: - TestMinimizer(); - ~TestMinimizer() override; - - std::string minimizerName() const override; - std::string algorithmName() const override { return ""; } - - mumufit::MinimizerResult minimize_scalar(fcn_scalar_t fcn, - mumufit::Parameters parameters) override; - -private: - std::vector<double> m_parameter_values; - scalar_function_t m_fcn; -}; - -#endif // BORNAGAIN_FIT_MINIMIZER_TESTMINIMIZER_H -#endif // USER_API diff --git a/Fit/Test/Functional/MinimizerTests.cpp b/Fit/Test/Functional/MinimizerTests.cpp index a7f6b436876bcfa198a3c328946c3951d7fd7dae..4090648dd658ad2de315bd1b62276b127185889d 100644 --- a/Fit/Test/Functional/MinimizerTests.cpp +++ b/Fit/Test/Functional/MinimizerTests.cpp @@ -143,9 +143,3 @@ TEST_F(Minimize, LevenbergMarquardtV3) DecayingSinPlanV2 plan; EXPECT_TRUE(run("GSLLMA", "Default", plan)); } - -TEST_F(Minimize, TestMinimizerV1) -{ - TestMinimizerPlan plan; - EXPECT_TRUE(run("Test", "Default", plan)); -} diff --git a/GUI/Model/Component/ComponentProxyModel.cpp b/GUI/Model/Component/ComponentProxyModel.cpp deleted file mode 100644 index 7a210cfd0609d6932065733564a3f9bee68970d9..0000000000000000000000000000000000000000 --- a/GUI/Model/Component/ComponentProxyModel.cpp +++ /dev/null @@ -1,189 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Component/ComponentProxyModel.cpp -//! @brief Implements class ComponentProxyModel -//! -//! @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/Component/ComponentProxyModel.h" -#include "GUI/Model/Component/ComponentProxyStrategy.h" -#include "GUI/Model/Group/GroupItem.h" -#include "GUI/Model/Session/SessionModel.h" -#include <QSet> -#include <functional> - -ComponentProxyModel::ComponentProxyModel(QObject* parent) - : QAbstractProxyModel(parent) - , m_model(nullptr) - // , m_proxyStrategy(new IndentityProxyStrategy) - , m_proxyStrategy(new ComponentProxyStrategy) -{ -} - -void ComponentProxyModel::setSessionModel(SessionModel* model) -{ - beginResetModel(); - - if (sourceModel()) { - disconnect(sourceModel(), &QAbstractItemModel::dataChanged, this, - &ComponentProxyModel::sourceDataChanged); - disconnect(sourceModel(), &QAbstractItemModel::rowsInserted, this, - &ComponentProxyModel::sourceRowsInserted); - disconnect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, - &ComponentProxyModel::sourceRowsRemoved); - } - - QAbstractProxyModel::setSourceModel(model); - - if (sourceModel()) { - connect(sourceModel(), &QAbstractItemModel::dataChanged, this, - &ComponentProxyModel::sourceDataChanged); - connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, - &ComponentProxyModel::sourceRowsInserted); - connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, - &ComponentProxyModel::sourceRowsRemoved); - } - - endResetModel(); - - m_model = model; - buildModelMap(); -} - -void ComponentProxyModel::setRootIndex(const QModelIndex& sourceRootIndex) -{ - m_proxyStrategy->setRootIndex(sourceRootIndex); - buildModelMap(); -} - -void ComponentProxyModel::setProxyStrategy(ProxyModelStrategy* strategy) -{ - m_proxyStrategy.reset(strategy); - buildModelMap(); -} - -QModelIndex ComponentProxyModel::mapToSource(const QModelIndex& proxyIndex) const -{ - if (!proxyIndex.isValid()) - return QModelIndex(); - - return m_proxyStrategy->sourceToProxy().key(proxyIndex); -} - -QModelIndex ComponentProxyModel::mapFromSource(const QModelIndex& sourceIndex) const -{ - if (!sourceIndex.isValid()) - return QModelIndex(); - - return m_proxyStrategy->sourceToProxy().value(sourceIndex); -} - -QModelIndex ComponentProxyModel::index(int row, int column, const QModelIndex& parent) const -{ - QModelIndex sourceParent; - if (parent.isValid()) - sourceParent = mapToSource(parent); - - QMapIterator<QPersistentModelIndex, QPersistentModelIndex> it( - m_proxyStrategy->proxySourceParent()); - while (it.hasNext()) { - it.next(); - if (it.value() == sourceParent && it.key().row() == row && it.key().column() == column) - return it.key(); - } - return QModelIndex(); -} - -QModelIndex ComponentProxyModel::parent(const QModelIndex& child) const -{ - QModelIndex sourceParent = m_proxyStrategy->proxySourceParent().value(child); - if (sourceParent.isValid()) - return mapFromSource(sourceParent); - - return QModelIndex(); -} - -int ComponentProxyModel::rowCount(const QModelIndex& parent) const -{ - QModelIndex sourceParent; - if (parent.isValid()) - sourceParent = mapToSource(parent); - QMapIterator<QPersistentModelIndex, QPersistentModelIndex> it( - m_proxyStrategy->proxySourceParent()); - - QSet<int> rows; - while (it.hasNext()) { - it.next(); - if (it.value() == sourceParent) - rows.insert(it.key().row()); - } - return rows.size(); -} - -int ComponentProxyModel::columnCount(const QModelIndex& parent) const -{ - if (parent.isValid() && parent.column() != 0) - return 0; - return SessionFlags::MAX_COLUMNS; -} - -bool ComponentProxyModel::hasChildren(const QModelIndex& parent) const -{ - QModelIndex source_parent = mapToSource(parent); - if (parent.isValid() && !source_parent.isValid()) - return false; - - return rowCount(parent) != 0; -} - -void ComponentProxyModel::sourceDataChanged(const QModelIndex& topLeft, - const QModelIndex& bottomRight, - const QVector<int>& roles) -{ - ASSERT(topLeft.isValid() ? topLeft.model() == sourceModel() : true); - ASSERT(bottomRight.isValid() ? bottomRight.model() == sourceModel() : true); - - if (SessionItem* item = m_model->itemForIndex(topLeft)) { - if (item->hasModelType<GroupItem>()) - updateModelMap(); - } - dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); -} - -void ComponentProxyModel::sourceRowsInserted(const QModelIndex& parent, int start, int end) -{ - Q_UNUSED(parent); - Q_UNUSED(start); - Q_UNUSED(end); - buildModelMap(); -} - -void ComponentProxyModel::sourceRowsRemoved(const QModelIndex& parent, int start, int end) -{ - Q_UNUSED(parent); - Q_UNUSED(start); - Q_UNUSED(end); - buildModelMap(); -} - -//! Main method to build the map of persistent indeses. - -void ComponentProxyModel::buildModelMap() -{ - if (!m_model) - return; - m_proxyStrategy->buildModelMap(m_model, this); - layoutChanged(); -} - -void ComponentProxyModel::updateModelMap() -{ - m_proxyStrategy->onDataChanged(m_model, this); -} diff --git a/GUI/Model/Component/ComponentProxyModel.h b/GUI/Model/Component/ComponentProxyModel.h deleted file mode 100644 index 24afc194b90196001141555b469e082b00c805a0..0000000000000000000000000000000000000000 --- a/GUI/Model/Component/ComponentProxyModel.h +++ /dev/null @@ -1,71 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Component/ComponentProxyModel.h -//! @brief Defines class ComponentProxyModel -//! -//! @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_COMPONENT_COMPONENTPROXYMODEL_H -#define BORNAGAIN_GUI_MODEL_COMPONENT_COMPONENTPROXYMODEL_H - -#include "GUI/Model/Component/ProxyModelStrategy.h" -#include <QAbstractProxyModel> -#include <QMap> -#include <QPersistentModelIndex> -#include <memory> - -class SessionModel; -class ProxyModelStrategy; - -//! Proxy model to adjust SessionModel for component editor -//! -//! The model hides all SessionItems which are not PropertyItems. -//! The model hides GroupPropertyItem children and shows grand-children of currently selected item -//! one level up. - -class ComponentProxyModel : public QAbstractProxyModel { - Q_OBJECT - - friend class ProxyModelStrategy; - -public: - ComponentProxyModel(QObject* parent = nullptr); - - void setSessionModel(SessionModel* model); - - void setRootIndex(const QModelIndex& sourceRootIndex); - - void setProxyStrategy(ProxyModelStrategy* strategy); - - QModelIndex mapToSource(const QModelIndex& proxyIndex) const override; - QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override; - - QModelIndex index(int row, int column, const QModelIndex& parent = {}) const override; - QModelIndex parent(const QModelIndex& child) const override; - int rowCount(const QModelIndex& parent = {}) const override; - int columnCount(const QModelIndex& parent = {}) const override; - - bool hasChildren(const QModelIndex& parent) const override; - -private slots: - void sourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, - const QVector<int>& roles = {}); - void sourceRowsInserted(const QModelIndex& parent, int start, int end); - void sourceRowsRemoved(const QModelIndex& parent, int start, int end); - -private: - void buildModelMap(); - void updateModelMap(); - - SessionModel* m_model; - std::unique_ptr<ProxyModelStrategy> m_proxyStrategy; -}; - -#endif // BORNAGAIN_GUI_MODEL_COMPONENT_COMPONENTPROXYMODEL_H diff --git a/GUI/Model/Component/ComponentProxyStrategy.cpp b/GUI/Model/Component/ComponentProxyStrategy.cpp deleted file mode 100644 index 250f43f028c334948f660ef1abb87297b848cb29..0000000000000000000000000000000000000000 --- a/GUI/Model/Component/ComponentProxyStrategy.cpp +++ /dev/null @@ -1,187 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Component/ComponentProxyStrategy.cpp -//! @brief Implements class ComponentProxyStrategy -//! -//! @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/Component/ComponentProxyStrategy.h" -#include "GUI/Model/Component/ComponentProxyModel.h" -#include "GUI/Model/Component/ComponentUtils.h" -#include "GUI/Model/Group/GroupItem.h" -#include "GUI/Model/Session/ModelPath.h" -#include "GUI/Model/Session/SessionModel.h" - -void ComponentProxyStrategy::onDataChanged(SessionModel* source, ComponentProxyModel* proxy) -{ - buildModelMap(source, proxy); - proxy->layoutChanged(); -} - -bool ComponentProxyStrategy::processSourceIndex(const QModelIndex& index) -{ - QPersistentModelIndex sourceIndex = {index}; - - SessionItem* item = m_source->itemForIndex(index); - - QString tag; - if (item->parent()) - tag = item->parent()->tagFromItem(item); - - if (!isPropertyRelated(item)) - return false; // not going to visit non-property items - - if (isNewRootItem(item)) { - processRootItem(item, sourceIndex); - - } else if (isSubGroup(item)) { - processSubGroupItem(item, sourceIndex); - - } else if (isGroupChildren(item)) { - processGroupItem(item, sourceIndex); - - } else { - processDefaultItem(item, sourceIndex); - } - - return true; -} - -//! Returns true if item is property related to exclude top level items (ParticleLayout, Particle -//! etc from the tree). - -bool ComponentProxyStrategy::isPropertyRelated(SessionItem* item) -{ - static const QStringList& propertyRelated = GUI::Model::ComponentUtils::propertyRelatedTypes(); - - if (m_sourceRootIndex.isValid() && item->parent()->index() == m_sourceRootIndex - && !item->parent()->hasModelType<GroupItem>()) - return propertyRelated.contains(item->modelType()); - - return true; -} - -//! Returns true if item should become new root item. -//! This is used when we want to show single item (Layer, Particle) on top of the tree. - -bool ComponentProxyStrategy::isNewRootItem(SessionItem* item) -{ - return item->index() == m_sourceRootIndex; -} - -//! Makes SessionItem to become the only one item in a tree. - -void ComponentProxyStrategy::processRootItem(SessionItem* item, - const QPersistentModelIndex& sourceIndex) -{ - const int nrows = 0; // invisible root item will contain only single item - QPersistentModelIndex proxyIndex = createProxyIndex(nrows, sourceIndex.column(), item); - m_sourceToProxy.insert(sourceIndex, proxyIndex); - m_proxySourceParent.insert(proxyIndex, QModelIndex()); // new parent will be root -} - -//! Returns true if item is a group property which in turn is inside of another group property. - -bool ComponentProxyStrategy::isSubGroup(SessionItem* item) -{ - const SessionItem* ancestor = GUI::Model::Path::ancestor(item->parent(), GroupItem::M_TYPE); - return item->hasModelType<GroupItem>() && ancestor && ancestor->hasModelType<GroupItem>(); -} - -//! Returns true if item is a children/grandchildrent of some group item. - -bool ComponentProxyStrategy::isGroupChildren(SessionItem* item) -{ - if (item->parent() && item->parent()->hasModelType<GroupItem>()) - return true; - - if (const SessionItem* ancestor = GUI::Model::Path::ancestor(item, GroupItem::M_TYPE)) { - if (ancestor != item) - return true; - } - - return false; -} - -//! All properties of current item of group item - -void ComponentProxyStrategy::processGroupItem(SessionItem* item, - const QPersistentModelIndex& sourceIndex) -{ - if (const SessionItem* ancestor = GUI::Model::Path::ancestor(item, GroupItem::M_TYPE)) { - if (ancestor == item) - return; - - const auto* groupItem = dynamic_cast<const GroupItem*>(ancestor); - if (item->parent() == groupItem->currentItem()) { - QPersistentModelIndex proxyIndex = createProxyIndex( - parentVisibleRow(*item), sourceIndex.column(), sourceIndex.internalPointer()); - - m_sourceToProxy.insert(sourceIndex, proxyIndex); - m_proxySourceParent.insert(proxyIndex, groupItem->index()); - } - } -} - -//! Process group property which is inside of other group property. - -void ComponentProxyStrategy::processSubGroupItem(SessionItem* item, - const QPersistentModelIndex& sourceIndex) -{ - if (const SessionItem* ancestor = - GUI::Model::Path::ancestor(item->parent(), GroupItem::M_TYPE)) { - const auto* groupItem = dynamic_cast<const GroupItem*>(ancestor); - - if (item->parent() == groupItem->currentItem()) { - QPersistentModelIndex proxyIndex = createProxyIndex( - parentVisibleRow(*item), sourceIndex.column(), sourceIndex.internalPointer()); - - m_sourceToProxy.insert(sourceIndex, proxyIndex); - m_proxySourceParent.insert(proxyIndex, groupItem->index()); - } - } -} - -void ComponentProxyStrategy::processDefaultItem(SessionItem* item, - const QPersistentModelIndex& sourceIndex) -{ - ASSERT(item); - if (!item->isVisible()) - return; - - QPersistentModelIndex proxyIndex = - createProxyIndex(parentVisibleRow(*item), sourceIndex.column(), item); - - m_sourceToProxy.insert(sourceIndex, proxyIndex); - - QPersistentModelIndex sourceParent; - if (sourceIndex.parent().isValid()) - sourceParent = sourceIndex.parent(); - - m_proxySourceParent.insert(proxyIndex, sourceParent); -} - -int ComponentProxyStrategy::parentVisibleRow(const SessionItem& item) -{ - int result(-1); - - if (!item.parent() || !item.isVisible()) - return result; - - for (auto* child : item.parent()->children()) { - if (child->isVisible() && isPropertyRelated(child)) - ++result; - - if (&item == child) - return result; - } - - return result; -} diff --git a/GUI/Model/Component/ComponentProxyStrategy.h b/GUI/Model/Component/ComponentProxyStrategy.h deleted file mode 100644 index 52cafeb8b41eacfd56945176e55267768b870634..0000000000000000000000000000000000000000 --- a/GUI/Model/Component/ComponentProxyStrategy.h +++ /dev/null @@ -1,42 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Component/ComponentProxyStrategy.h -//! @brief Defines class ComponentProxyStrategy -//! -//! @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_COMPONENT_COMPONENTPROXYSTRATEGY_H -#define BORNAGAIN_GUI_MODEL_COMPONENT_COMPONENTPROXYSTRATEGY_H - -#include "GUI/Model/Component/ProxyModelStrategy.h" - -//! Strategy for ComponentProxyModel which hides extra level of GroupProperty. - -class ComponentProxyStrategy : public ProxyModelStrategy { -public: - void onDataChanged(SessionModel* source, ComponentProxyModel* proxy) override; - -protected: - bool processSourceIndex(const QModelIndex& index) override; - -private: - bool isPropertyRelated(SessionItem* item); - bool isNewRootItem(SessionItem* item); - void processRootItem(SessionItem* item, const QPersistentModelIndex& sourceIndex); - bool isSubGroup(SessionItem* item); - bool isGroupChildren(SessionItem* item); - void processGroupItem(SessionItem* item, const QPersistentModelIndex& sourceIndex); - void processSubGroupItem(SessionItem* item, const QPersistentModelIndex& sourceIndex); - void processDefaultItem(SessionItem* item, const QPersistentModelIndex& sourceIndex); - - int parentVisibleRow(const SessionItem& item); -}; - -#endif // BORNAGAIN_GUI_MODEL_COMPONENT_COMPONENTPROXYSTRATEGY_H diff --git a/GUI/Model/Component/ComponentUtils.cpp b/GUI/Model/Component/ComponentUtils.cpp deleted file mode 100644 index 07e908e718348a13fe64042c3a40584edeb0693d..0000000000000000000000000000000000000000 --- a/GUI/Model/Component/ComponentUtils.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Component/ComponentUtils.cpp -//! @brief Implements ComponentUtils namespace -//! -//! @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/Component/ComponentUtils.h" -#include "GUI/Model/Data/AxesItems.h" -#include "GUI/Model/Group/GroupItem.h" -#include "GUI/Model/Group/PropertyItem.h" -#include "GUI/Model/Material/MaterialDataItems.h" -#include "GUI/Model/Types/VectorItem.h" - -namespace { - -QList<const SessionItem*> groupItems(const GroupItem& item) -{ - QList<const SessionItem*> result; - for (auto* grandchild : item.children()) - if (grandchild->isVisible()) - result += GUI::Model::ComponentUtils::componentItems(*grandchild); - return result; -} - -} // namespace - - -const QStringList& GUI::Model::ComponentUtils::propertyRelatedTypes() -{ - static const QStringList result = { - PropertyItem::M_TYPE, GroupItem::M_TYPE, VectorItem::M_TYPE, - BasicAxisItem::M_TYPE, AmplitudeAxisItem::M_TYPE, MaterialRefractiveDataItem::M_TYPE}; - return result; -} - -QList<const SessionItem*> GUI::Model::ComponentUtils::componentItems(const SessionItem& item) -{ - static const QStringList& propertyRelated = GUI::Model::ComponentUtils::propertyRelatedTypes(); - - QList<const SessionItem*> result; - - if (item.hasModelType<PropertyItem>()) { - result.push_back(&item); - - } else if (item.hasModelType<GroupItem>()) { - result.push_back(&item); - result += groupItems(dynamic_cast<const GroupItem&>(item)); - - } else { - - for (auto* child : item.children()) { - if (!child->isVisible()) - continue; - - if (propertyRelated.contains(child->modelType())) - result.append(child); - - if (child->hasModelType<GroupItem>()) - result += groupItems(*dynamic_cast<GroupItem*>(child)); - } - } - - return result; -} diff --git a/GUI/Model/Component/ComponentUtils.h b/GUI/Model/Component/ComponentUtils.h deleted file mode 100644 index e5a6c5513ef160868c0c5d8acd714f9718445cb3..0000000000000000000000000000000000000000 --- a/GUI/Model/Component/ComponentUtils.h +++ /dev/null @@ -1,35 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Component/ComponentUtils.h -//! @brief Defines namespace GUI::Model::ComponentUtils -//! -//! @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_COMPONENT_COMPONENTUTILS_H -#define BORNAGAIN_GUI_MODEL_COMPONENT_COMPONENTUTILS_H - -#include <QList> -#include <QStringList> - -class SessionItem; - -//! Contains collection of utility functions to support editing of SessionItem's components. - -namespace GUI::Model::ComponentUtils { - -//! Returns list of strings representing modelTypes suitable for editing in component editors. -const QStringList& propertyRelatedTypes(); - -//! Returns list of SessionItem's children suitable for editing in property editors. -QList<const SessionItem*> componentItems(const SessionItem& item); - -} // namespace GUI::Model::ComponentUtils - -#endif // BORNAGAIN_GUI_MODEL_COMPONENT_COMPONENTUTILS_H diff --git a/GUI/Model/Component/ProxyModelStrategy.cpp b/GUI/Model/Component/ProxyModelStrategy.cpp deleted file mode 100644 index b710199532c97ff9e24c656533c8b6245e28339b..0000000000000000000000000000000000000000 --- a/GUI/Model/Component/ProxyModelStrategy.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Component/ProxyModelStrategy.cpp -//! @brief Implements class ProxyModelStrategy -//! -//! @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/Component/ComponentProxyModel.h" -#include "GUI/Model/Session/ModelUtils.h" -#include "GUI/Model/Session/SessionModel.h" - -ProxyModelStrategy::ProxyModelStrategy() : m_source(nullptr), m_proxy(nullptr) {} - -void ProxyModelStrategy::buildModelMap(SessionModel* source, ComponentProxyModel* proxy) -{ - m_sourceToProxy.clear(); - m_proxySourceParent.clear(); - m_source = source; - m_proxy = proxy; - - GUI::Model::ItemUtils::iterate_if( - m_sourceRootIndex, source, - [=](const QModelIndex& index) -> bool { return processSourceIndex(index); }); - - // kind of hack since we have to visit col=1 which has QModelIndex() parent - if (m_sourceRootIndex.isValid()) - processSourceIndex(m_sourceRootIndex.sibling(m_sourceRootIndex.row(), 1)); -} - -void ProxyModelStrategy::onDataChanged(SessionModel* source, ComponentProxyModel* proxy) -{ - Q_UNUSED(source); - Q_UNUSED(proxy); - // we do not expect here change of model layout -} - -const ProxyModelStrategy::map_t& ProxyModelStrategy::sourceToProxy() -{ - return m_sourceToProxy; -} - -const ProxyModelStrategy::map_t& ProxyModelStrategy::proxySourceParent() -{ - return m_proxySourceParent; -} - -void ProxyModelStrategy::setRootIndex(const QModelIndex& sourceRootIndex) -{ - m_sourceRootIndex = QPersistentModelIndex(sourceRootIndex); -} - -//! Method to ask proxy to create an index using friendship of ProxyModelStrategy -//! and ComponentProxyModel. - -QModelIndex ProxyModelStrategy::createProxyIndex(int nrow, int ncol, void* adata) -{ - ASSERT(m_proxy); - return m_proxy->createIndex(nrow, ncol, adata); -} - -//! Builds one-to-one mapping for source and proxy. - -bool IndentityProxyStrategy::processSourceIndex(const QModelIndex& index) -{ - QPersistentModelIndex proxyIndex = - createProxyIndex(index.row(), index.column(), index.internalPointer()); - m_sourceToProxy.insert(QPersistentModelIndex(index), proxyIndex); - - QPersistentModelIndex sourceParent; - if (index.parent().isValid()) - sourceParent = index.parent(); - - m_proxySourceParent.insert(proxyIndex, sourceParent); - - return true; -} diff --git a/GUI/Model/Component/ProxyModelStrategy.h b/GUI/Model/Component/ProxyModelStrategy.h deleted file mode 100644 index c418dd247ca879d2da0f65d0ab1585e9aa89c4ea..0000000000000000000000000000000000000000 --- a/GUI/Model/Component/ProxyModelStrategy.h +++ /dev/null @@ -1,62 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Component/ProxyModelStrategy.h -//! @brief Defines class ProxyModelStrategy -//! -//! @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_COMPONENT_PROXYMODELSTRATEGY_H -#define BORNAGAIN_GUI_MODEL_COMPONENT_PROXYMODELSTRATEGY_H - -#include <QPersistentModelIndex> - -class SessionModel; -class ComponentProxyModel; -class SessionItem; - -//! Base class for proxy strategies in ComponentProxyModel. - -class ProxyModelStrategy { -public: - using map_t = QMap<QPersistentModelIndex, QPersistentModelIndex>; - - ProxyModelStrategy(); - virtual ~ProxyModelStrategy() = default; - - void buildModelMap(SessionModel* source, ComponentProxyModel* proxy); - virtual void onDataChanged(SessionModel* source, ComponentProxyModel* proxy); - - const map_t& sourceToProxy(); - const map_t& proxySourceParent(); - - void setRootIndex(const QModelIndex& sourceRootIndex); - -protected: - QModelIndex createProxyIndex(int nrow, int ncol, void* adata); - virtual bool processSourceIndex(const QModelIndex& index) = 0; - - //!< Mapping of proxy model indices to indices in source model - QMap<QPersistentModelIndex, QPersistentModelIndex> m_sourceToProxy; - //!< Mapping of proxy model indices to indices of parent in source model - QMap<QPersistentModelIndex, QPersistentModelIndex> m_proxySourceParent; - - QPersistentModelIndex m_sourceRootIndex; - SessionModel* m_source; - ComponentProxyModel* m_proxy; -}; - -//! Strategy for ComponentProxyModel which makes it identical to source model. - -class IndentityProxyStrategy : public ProxyModelStrategy { -protected: - bool processSourceIndex(const QModelIndex& index) override; -}; - -#endif // BORNAGAIN_GUI_MODEL_COMPONENT_PROXYMODELSTRATEGY_H diff --git a/GUI/Model/Fit/MinimizerItem.cpp b/GUI/Model/Fit/MinimizerItem.cpp index 284db396da020a405821a10a8e74fbbaf006a523..967c3a0f6b97a108883c07ce206cfbf83af61e97 100644 --- a/GUI/Model/Fit/MinimizerItem.cpp +++ b/GUI/Model/Fit/MinimizerItem.cpp @@ -20,7 +20,6 @@ #include "Fit/Adapter/GeneticMinimizer.h" #include "Fit/Adapter/Minuit2Minimizer.h" #include "Fit/Adapter/SimAnMinimizer.h" -#include "Fit/Minimizer/TestMinimizer.h" #include "GUI/Model/Fit/MinimizerItemCatalog.h" #include "GUI/Model/Group/GroupInfo.h" @@ -34,7 +33,6 @@ GroupInfo createMinimizerLibraryGroup() info.add(GeneticMinimizerItem::M_TYPE, "TMVA Genetic"); info.add(SimAnMinimizerItem::M_TYPE, "GSL Simulated Annealing"); info.add(GSLLMAMinimizerItem::M_TYPE, "GSL Levenberg-Marquardt"); - info.add(TestMinimizerItem::M_TYPE, "Test minimizer"); info.setDefaultType(MinuitMinimizerItem::M_TYPE); return info; } @@ -68,6 +66,21 @@ MinimizerContainerItem::MinimizerContainerItem() : MinimizerItem(M_TYPE) "experimental data."); } +SelectionDescriptor<MinimizerItem*> MinimizerContainerItem::minimizers() const +{ + return SelectionDescriptor<MinimizerItem*>(item<GroupItem>(P_MINIMIZERS)); +} + +SelectionDescriptor<QString> MinimizerContainerItem::normFunction() const +{ + return SelectionDescriptor<QString>(getItem(P_NORM)); +} + +SelectionDescriptor<QString> MinimizerContainerItem::objectiveMetric() const +{ + return SelectionDescriptor<QString>(getItem(P_METRIC)); +} + std::unique_ptr<IMinimizer> MinimizerContainerItem::createMinimizer() const { return groupItem<MinimizerItem>(P_MINIMIZERS).createMinimizer(); @@ -116,6 +129,18 @@ std::unique_ptr<IMinimizer> MinuitMinimizerItem::createMinimizer() const return std::unique_ptr<IMinimizer>(domainMinimizer); } +ValueDescriptors MinuitMinimizerItem::valueDescriptorsForUI() const +{ + return { + SelectionDescriptor<QString>(getItem(P_ALGORITHMS)), + UIntDescriptor(getItem(P_STRATEGY), Unit::unitless), + DoubleDescriptor(getItem(P_ERRORDEF), Unit::unitless), + DoubleDescriptor(getItem(P_TOLERANCE), Unit::unitless), + DoubleDescriptor(getItem(P_PRECISION), Unit::unitless), + UIntDescriptor(getItem(P_MAXFUNCTIONCALLS), Unit::unitless), + }; +} + // ---------------------------------------------------------------------------- GSLMultiMinimizerItem::GSLMultiMinimizerItem() : MinimizerItem(M_TYPE) @@ -133,6 +158,14 @@ std::unique_ptr<IMinimizer> GSLMultiMinimizerItem::createMinimizer() const return std::unique_ptr<IMinimizer>(domainMinimizer); } +ValueDescriptors GSLMultiMinimizerItem::valueDescriptorsForUI() const +{ + return { + SelectionDescriptor<QString>(getItem(P_ALGORITHMS)), + UIntDescriptor(getItem(P_MAXITERATIONS), Unit::unitless), + }; +} + // ---------------------------------------------------------------------------- GeneticMinimizerItem::GeneticMinimizerItem() : MinimizerItem(M_TYPE) @@ -153,6 +186,16 @@ std::unique_ptr<IMinimizer> GeneticMinimizerItem::createMinimizer() const return std::unique_ptr<IMinimizer>(domainMinimizer); } +ValueDescriptors GeneticMinimizerItem::valueDescriptorsForUI() const +{ + return { + DoubleDescriptor(getItem(P_TOLERANCE), Unit::unitless), + UIntDescriptor(getItem(P_MAXITERATIONS), Unit::unitless), + UIntDescriptor(getItem(P_POPULATIONSIZE), Unit::unitless), + UIntDescriptor(getItem(P_RANDOMSEED), Unit::unitless), + }; +} + // ---------------------------------------------------------------------------- SimAnMinimizerItem::SimAnMinimizerItem() : MinimizerItem(M_TYPE) @@ -179,6 +222,19 @@ std::unique_ptr<IMinimizer> SimAnMinimizerItem::createMinimizer() const return std::unique_ptr<IMinimizer>(domainMinimizer); } +ValueDescriptors SimAnMinimizerItem::valueDescriptorsForUI() const +{ + return { + UIntDescriptor(getItem(P_MAXITERATIONS), Unit::unitless), + UIntDescriptor(getItem(P_ITERATIONSTEMP), Unit::unitless), + DoubleDescriptor(getItem(P_STEPSIZE), Unit::unitless), + DoubleDescriptor(getItem(P_BOLTZMANN_K), Unit::unitless), + DoubleDescriptor(getItem(P_BOLTZMANN_TINIT), Unit::unitless), + DoubleDescriptor(getItem(P_BOLTZMANN_MU), Unit::unitless), + DoubleDescriptor(getItem(P_BOLTZMANN_TMIN), Unit::unitless), + }; +} + // ---------------------------------------------------------------------------- GSLLMAMinimizerItem::GSLLMAMinimizerItem() : MinimizerItem(M_TYPE) @@ -195,11 +251,10 @@ std::unique_ptr<IMinimizer> GSLLMAMinimizerItem::createMinimizer() const return std::unique_ptr<IMinimizer>(domainMinimizer); } -// ---------------------------------------------------------------------------- - -TestMinimizerItem::TestMinimizerItem() : MinimizerItem(M_TYPE) {} - -std::unique_ptr<IMinimizer> TestMinimizerItem::createMinimizer() const +ValueDescriptors GSLLMAMinimizerItem::valueDescriptorsForUI() const { - return std::unique_ptr<IMinimizer>(new TestMinimizer()); + return { + DoubleDescriptor(getItem(P_TOLERANCE), Unit::unitless), + UIntDescriptor(getItem(P_MAXITERATIONS), Unit::unitless), + }; } diff --git a/GUI/Model/Fit/MinimizerItem.h b/GUI/Model/Fit/MinimizerItem.h index 2eb74b3af68ab8d7333fd1d3707a93058485cc82..45935d037f55ca962273bd75c00947f59f5b3fba 100644 --- a/GUI/Model/Fit/MinimizerItem.h +++ b/GUI/Model/Fit/MinimizerItem.h @@ -15,17 +15,26 @@ #ifndef BORNAGAIN_GUI_MODEL_FIT_MINIMIZERITEM_H #define BORNAGAIN_GUI_MODEL_FIT_MINIMIZERITEM_H +#include "GUI/Model/Group/SelectionDescriptor.h" #include "GUI/Model/Session/SessionItem.h" +#include "GUI/Model/Types/DoubleDescriptor.h" +#include "GUI/Model/Types/UIntDescriptor.h" +#include <variant> class IMinimizer; class ObjectiveMetric; +using ValueDescriptors = + QList<std::variant<DoubleDescriptor, UIntDescriptor, SelectionDescriptor<QString>>>; + //! The MinimizerItem class is the base item to hold minimizer settings. class BA_CORE_API_ MinimizerItem : public SessionItem { public: virtual std::unique_ptr<IMinimizer> createMinimizer() const = 0; + virtual ValueDescriptors valueDescriptorsForUI() const { return {}; } + protected: explicit MinimizerItem(const QString& model_type); }; @@ -43,6 +52,10 @@ public: MinimizerContainerItem(); + SelectionDescriptor<MinimizerItem*> minimizers() const; + SelectionDescriptor<QString> normFunction() const; + SelectionDescriptor<QString> objectiveMetric() const; + std::unique_ptr<IMinimizer> createMinimizer() const override; std::unique_ptr<ObjectiveMetric> createMetric() const; }; @@ -63,6 +76,7 @@ public: MinuitMinimizerItem(); std::unique_ptr<IMinimizer> createMinimizer() const override; + ValueDescriptors valueDescriptorsForUI() const override; }; //! The GSLMinimizerItem class represents settings for GSL MultiMin minimizer family. @@ -77,6 +91,7 @@ public: GSLMultiMinimizerItem(); std::unique_ptr<IMinimizer> createMinimizer() const override; + ValueDescriptors valueDescriptorsForUI() const override; }; //! The GeneticMinimizerItem class represents settings for TMVA/Genetic minimizer. @@ -93,6 +108,7 @@ public: GeneticMinimizerItem(); std::unique_ptr<IMinimizer> createMinimizer() const override; + ValueDescriptors valueDescriptorsForUI() const override; }; //! The SimAnMinimizerItem class represents settings for GSL's simulated annealing minimizer. @@ -113,6 +129,7 @@ public: SimAnMinimizerItem(); std::unique_ptr<IMinimizer> createMinimizer() const override; + ValueDescriptors valueDescriptorsForUI() const override; }; //! The GSLLMAMinimizerItem class represents settings for GSL's version of Levenberg-Marquardt. @@ -127,16 +144,7 @@ public: GSLLMAMinimizerItem(); std::unique_ptr<IMinimizer> createMinimizer() const override; -}; - -//! The TestMinimizerItem class represents domain's TestMinimizer to test whole chain - -class TestMinimizerItem : public MinimizerItem { -public: - static constexpr auto M_TYPE{"Test"}; - - TestMinimizerItem(); - std::unique_ptr<IMinimizer> createMinimizer() const override; + ValueDescriptors valueDescriptorsForUI() const override; }; #endif // BORNAGAIN_GUI_MODEL_FIT_MINIMIZERITEM_H diff --git a/GUI/Model/Group/ItemCatalog.cpp b/GUI/Model/Group/ItemCatalog.cpp index 8fdc90dd53786fe1868c92271e8e7b4119ab4020..bf0b112236cd491062ac8264fe81de9fe49c17f6 100644 --- a/GUI/Model/Group/ItemCatalog.cpp +++ b/GUI/Model/Group/ItemCatalog.cpp @@ -23,8 +23,8 @@ #include "GUI/Model/Data/ProjectionItems.h" #include "GUI/Model/Data/RealDataItem.h" #include "GUI/Model/Data/SpecularDataItem.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/FitSuiteItem.h" #include "GUI/Model/Fit/MinimizerItem.h" @@ -319,7 +319,6 @@ ItemCatalog::ItemCatalog() addItem<GeneticMinimizerItem>(); addItem<SimAnMinimizerItem>(); addItem<GSLLMAMinimizerItem>(); - addItem<TestMinimizerItem>(); addItem<LimitlessItem>(); addItem<PositiveItem>(); diff --git a/GUI/View/Fit/MinimizerSettingsWidget.cpp b/GUI/View/Fit/MinimizerSettingsWidget.cpp index 866c1610e107ad28c2dbd46e33c002cb6a8f9740..4b37576ae7297cc457a7b25aec2c6ee31adcce37 100644 --- a/GUI/View/Fit/MinimizerSettingsWidget.cpp +++ b/GUI/View/Fit/MinimizerSettingsWidget.cpp @@ -16,27 +16,23 @@ #include "GUI/Model/Fit/FitSuiteItem.h" #include "GUI/Model/Fit/MinimizerItem.h" #include "GUI/Model/Job/JobItem.h" -#include "GUI/View/PropertyEditor/ComponentTreeView.h" +#include "GUI/View/Edit/DoubleSpinBox.h" +#include "GUI/View/Tool/LayoutUtils.h" +#include <QComboBox> +#include <QFormLayout> #include <QPushButton> #include <QVBoxLayout> MinimizerSettingsWidget::MinimizerSettingsWidget(QWidget* parent) - : QWidget(parent), m_currentItem(nullptr), m_componentEditor(new ComponentTreeView) + : QWidget(parent), m_currentItem(nullptr) { setWindowTitle(QLatin1String("Minimizer Settings")); + setAttribute(Qt::WA_StyledBackground, true); + setProperty("stylable", true); // for stylesheet addressing - auto* layout = new QVBoxLayout; - layout->setMargin(0); - layout->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(m_componentEditor); - - setLayout(layout); -} - -QSize MinimizerSettingsWidget::minimumSizeHint() const -{ - return QSize(25, 25); + m_mainLayout = new QFormLayout(this); + m_mainLayout->setContentsMargins(8, 8, 8, 8); + m_mainLayout->setSpacing(5); } void MinimizerSettingsWidget::setItem(JobItem* jobItem) @@ -48,6 +44,120 @@ void MinimizerSettingsWidget::setItem(JobItem* jobItem) void MinimizerSettingsWidget::setItem(MinimizerContainerItem* minimizerItem) { ASSERT(minimizerItem); + if (m_currentItem) + m_currentItem->mapper()->unsubscribe(this); + + GUI::Util::Layout::clearLayout(m_mainLayout); + m_updaters.clear(); m_currentItem = minimizerItem; - m_componentEditor->setItem(minimizerItem); + + if (!m_currentItem) + return; + + auto minimizerDescriptor = m_currentItem->minimizers(); + auto* minimizerCombo = new QComboBox(this); + minimizerCombo->addItems(minimizerDescriptor.options); + minimizerCombo->setMaxCount(minimizerDescriptor.options.size()); + minimizerCombo->setToolTip(minimizerDescriptor.tooltip); + + connect(minimizerCombo, qOverload<int>(&QComboBox::currentIndexChanged), [=](int newIndex) { + minimizerDescriptor.setCurrentIndex(newIndex); + createMimimizerEdits(); + }); + + m_updaters << [=]() { + QSignalBlocker b(minimizerCombo); + minimizerCombo->setCurrentIndex(minimizerDescriptor.currentIndex()); + }; + m_mainLayout->addRow("Minimizer:", minimizerCombo); + + auto* w = new QWidget(this); + m_minimizerLayout = new QFormLayout(w); + m_minimizerLayout->setContentsMargins(10, 8, 0, 8); + m_mainLayout->addRow("", w); + + m_mainLayout->addRow("Objective metric:", createComboBox(m_currentItem->objectiveMetric())); + m_mainLayout->addRow("Norm function:", createComboBox(m_currentItem->normFunction())); + + createMimimizerEdits(); + updateUIValues(); +} + +QWidget* MinimizerSettingsWidget::createComboBox(SelectionDescriptor<QString> d) +{ + auto* combo = new QComboBox(this); + combo->addItems(d.options); + combo->setMaxCount(d.options.size()); + combo->setToolTip(d.tooltip); + + connect(combo, qOverload<int>(&QComboBox::currentIndexChanged), + [=](int newIndex) { d.setCurrentIndex(newIndex); }); + + m_updaters << [=]() { + QSignalBlocker b(combo); + combo->setCurrentIndex(d.currentIndex()); + }; + + return combo; +} + +QWidget* MinimizerSettingsWidget::createDoubleSpinbox(DoubleDescriptor d) +{ + auto* spinBox = new DoubleSpinBox(this, d); + spinBox->setToolTip(d.tooltip); + QObject::connect(spinBox, &DoubleSpinBox::baseValueChanged, + [=](double newValue) { d.set(newValue); }); + + m_updaters << [=]() { spinBox->updateValue(); }; + + return spinBox; +} + +QWidget* MinimizerSettingsWidget::createSpinbox(UIntDescriptor d) +{ + auto* spinBox = new QSpinBox(this); + spinBox->setToolTip(d.tooltip); + spinBox->setMaximum(std::numeric_limits<int>::max()); + spinBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + + if (d.limits.hasLowerLimit()) + spinBox->setMinimum(static_cast<int>(d.limits.lowerLimit())); + if (d.limits.hasUpperLimit()) + spinBox->setMaximum(static_cast<int>(d.limits.upperLimit())); + + spinBox->setValue(d.get()); + + QObject::connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), + [=](int newValue) { d.set(newValue); }); + + m_updaters << [=]() { + QSignalBlocker b(spinBox); + spinBox->setValue(d.get()); + }; + + return spinBox; +} + +void MinimizerSettingsWidget::createMimimizerEdits() +{ + GUI::Util::Layout::clearLayout(m_minimizerLayout); + + for (auto v : m_currentItem->minimizers().currentItem()->valueDescriptorsForUI()) { + if (std::holds_alternative<DoubleDescriptor>(v)) { + auto d = std::get<DoubleDescriptor>(v); + m_minimizerLayout->addRow(d.label + ":", createDoubleSpinbox(d)); + } else if (std::holds_alternative<SelectionDescriptor<QString>>(v)) { + auto d = std::get<SelectionDescriptor<QString>>(v); + m_minimizerLayout->addRow(d.label + ":", createComboBox(d)); + } else if (std::holds_alternative<UIntDescriptor>(v)) { + auto d = std::get<UIntDescriptor>(v); + m_minimizerLayout->addRow(d.label + ":", createSpinbox(d)); + } + } +} + +void MinimizerSettingsWidget::updateUIValues() +{ + for (auto updater : m_updaters) + updater(); } diff --git a/GUI/View/Fit/MinimizerSettingsWidget.h b/GUI/View/Fit/MinimizerSettingsWidget.h index b8dfcd805f660728c2842942c95e833d13d91f0e..392645dfa8503ea6f34751b2c23338fc724262bf 100644 --- a/GUI/View/Fit/MinimizerSettingsWidget.h +++ b/GUI/View/Fit/MinimizerSettingsWidget.h @@ -15,13 +15,20 @@ #ifndef BORNAGAIN_GUI_VIEW_FIT_MINIMIZERSETTINGSWIDGET_H #define BORNAGAIN_GUI_VIEW_FIT_MINIMIZERSETTINGSWIDGET_H +#include "GUI/Model/Group/SelectionDescriptor.h" +#include <QList> #include <QWidget> +#include <functional> -class ComponentTreeView; class JobItem; class MinimizerContainerItem; +class DoubleDescriptor; +class UIntDescriptor; +class QFormLayout; -//! The MinimizerSettingsWidget contains editor for all minnimizer settings and related fit +using std::function; + +//! The MinimizerSettingsWidget contains editor for all minimizer settings and related fit //! options. Part of FitSuiteWidget. class MinimizerSettingsWidget : public QWidget { @@ -30,15 +37,24 @@ class MinimizerSettingsWidget : public QWidget { public: MinimizerSettingsWidget(QWidget* parent = nullptr); - QSize minimumSizeHint() const override; - public slots: void setItem(JobItem* jobItem); void setItem(MinimizerContainerItem* minimizerItem); +private: + QWidget* createComboBox(SelectionDescriptor<QString> d); + QWidget* createDoubleSpinbox(DoubleDescriptor d); + QWidget* createSpinbox(UIntDescriptor d); + void createMimimizerEdits(); + + void updateUIValues(); + + private: MinimizerContainerItem* m_currentItem; - ComponentTreeView* m_componentEditor; + QFormLayout* m_mainLayout; + QFormLayout* m_minimizerLayout; + QList<function<void()>> m_updaters; }; #endif // BORNAGAIN_GUI_VIEW_FIT_MINIMIZERSETTINGSWIDGET_H diff --git a/GUI/View/PropertyEditor/ComponentTreeView.cpp b/GUI/View/PropertyEditor/ComponentTreeView.cpp deleted file mode 100644 index 667f95f41a7e78e5166d6082c3f35042e224c9b3..0000000000000000000000000000000000000000 --- a/GUI/View/PropertyEditor/ComponentTreeView.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/View/PropertyEditor/ComponentTreeView.cpp -//! @brief Implements class ComponentTreeView -//! -//! @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/View/PropertyEditor/ComponentTreeView.h" -#include "GUI/Model/Component/ComponentProxyModel.h" -#include "GUI/Model/Session/SessionModel.h" -#include "GUI/View/PropertyEditor/CustomEventFilters.h" -#include "GUI/View/PropertyEditor/SessionModelDelegate.h" -#include "GUI/View/Tool/StyleUtils.h" -#include <QAction> -#include <QBoxLayout> -#include <QMenu> -#include <QStandardItemModel> -#include <QTreeView> - -ComponentTreeView::ComponentTreeView(QWidget* parent) - : QWidget(parent) - , m_tree(new QTreeView) - , m_delegate(new SessionModelDelegate(this)) - , m_proxyModel(new ComponentProxyModel(this)) - , m_placeHolderModel(new QStandardItemModel(this)) - , m_eventFilter(new RightMouseButtonEater) -{ - auto* layout = new QVBoxLayout; - - layout->setMargin(0); - layout->setSpacing(0); - layout->addWidget(m_tree); - - setLayout(layout); - - QStringList labels = {"Name", "Value"}; - m_placeHolderModel->setHorizontalHeaderLabels(labels); - - GUI::Util::Style::setPropertyStyle(m_tree); - m_tree->setRootIsDecorated(false); - m_tree->setModel(m_placeHolderModel); - m_tree->setItemDelegate(m_delegate); - - // provide one click editing, but still keeping custom context menu alive - m_tree->setEditTriggers(QAbstractItemView::AllEditTriggers); - m_tree->viewport()->installEventFilter(m_eventFilter.get()); - - // custom context menu setup - m_tree->setContextMenuPolicy(Qt::CustomContextMenu); - connect(m_tree, &QTreeView::customContextMenuRequested, this, - &ComponentTreeView::onCustomContextMenuRequested); - - setShowHeader(true); -} - -void ComponentTreeView::setItem(SessionItem* item) -{ - if (!item) { - setModel(nullptr); - return; - } - setModel(item->model()); - setRootIndex(item->index()); - m_tree->expandAll(); -} - -void ComponentTreeView::clearEditor() -{ - m_tree->setModel(m_placeHolderModel); -} - -void ComponentTreeView::setModel(SessionModel* model) -{ - m_proxyModel->setSessionModel(model); - if (model) - m_tree->setModel(m_proxyModel); - else - m_tree->setModel(m_placeHolderModel); -} - -void ComponentTreeView::setRootIndex(const QModelIndex& index) -{ - if (QWidget* editor = m_tree->indexWidget(m_tree->currentIndex())) - m_delegate->closeEditor(editor, QAbstractItemDelegate::NoHint); - ASSERT(m_proxyModel); - m_proxyModel->setRootIndex(index); - m_tree->setRootIndex(m_proxyModel->mapFromSource(index)); -} - -void ComponentTreeView::setShowHeader(bool show) -{ - m_tree->setHeaderHidden(!show); -} - -void ComponentTreeView::onCustomContextMenuRequested(const QPoint& pos) -{ - auto point = m_tree->mapToGlobal(pos); - auto treeIndex = m_tree->indexAt(pos); - if (!treeIndex.isValid()) - return; - - auto index = m_proxyModel->mapToSource(treeIndex); - - auto* item = static_cast<SessionItem*>(index.internalPointer()); - if (item->value().type() != QVariant::Double) - return; - - const bool sc_editor = item->editorType() == "ScientificDouble"; - - // Creates right-mouse-click context menu on top of ComponentTreeView - // which will allow user to switch between scientific notation and the notation - // with a specified number of decimals. - QMenu menu; - QAction* scientificAction = menu.addAction("Scientific presentation"); - scientificAction->setCheckable(true); - auto* doubleMenu = menu.addMenu("Double presentation"); - - // To select scientific notation - scientificAction->setChecked(sc_editor); - connect(scientificAction, &QAction::triggered, [&]() { - if (scientificAction->isChecked()) - item->setEditorType("ScientificDouble"); - else - item->setEditorType("Default"); - }); - - // to select number of decimals - const int nmaxdigits = 8; - for (int i = 1; i <= nmaxdigits; ++i) { - auto* action = doubleMenu->addAction(QString("%1 digits").arg(i)); - if (!sc_editor && item->decimals() == i) - action->setChecked(true); - connect(action, &QAction::triggered, [i, &item] { - item->setEditorType("Default"); - item->setDecimals(i); - }); - } - menu.exec(point); -} diff --git a/GUI/View/PropertyEditor/ComponentTreeView.h b/GUI/View/PropertyEditor/ComponentTreeView.h deleted file mode 100644 index ac1f96a39c7956df043b5d3e9e5838635ba008a5..0000000000000000000000000000000000000000 --- a/GUI/View/PropertyEditor/ComponentTreeView.h +++ /dev/null @@ -1,57 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/View/PropertyEditor/ComponentTreeView.h -//! @brief Defines class ComponentTreeView -//! -//! @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_VIEW_PROPERTYEDITOR_COMPONENTTREEVIEW_H -#define BORNAGAIN_GUI_VIEW_PROPERTYEDITOR_COMPONENTTREEVIEW_H - -#include <QWidget> -#include <memory> - -class QTreeView; -class SessionModel; -class SessionModelDelegate; -class ComponentProxyModel; -class QModelIndex; -class SessionItem; -class QStandardItemModel; -class RightMouseButtonEater; - -//! Component property tree for SessionItems. -//! Shows only PropertyItems and current items of GroupProperties. - -class ComponentTreeView : public QWidget { - Q_OBJECT -public: - ComponentTreeView(QWidget* parent = nullptr); - - void setItem(SessionItem* item); - void clearEditor(); - - void setShowHeader(bool show); - -private slots: - void onCustomContextMenuRequested(const QPoint& pos); - -private: - void setModel(SessionModel* model); - void setRootIndex(const QModelIndex& index); - - QTreeView* m_tree; - SessionModelDelegate* m_delegate; - ComponentProxyModel* m_proxyModel; - QStandardItemModel* m_placeHolderModel; - std::unique_ptr<RightMouseButtonEater> m_eventFilter; -}; - -#endif // BORNAGAIN_GUI_VIEW_PROPERTYEDITOR_COMPONENTTREEVIEW_H diff --git a/Tests/Functional/PyFit/minimizer_api.py b/Tests/Functional/PyFit/minimizer_api.py index ccee6af2cc9859aff3cdeed2ffb8f63c544d02bc..e9cf02c23826d1b2b9fc4890dc7ce94f36bb5059 100644 --- a/Tests/Functional/PyFit/minimizer_api.py +++ b/Tests/Functional/PyFit/minimizer_api.py @@ -64,28 +64,5 @@ class MinimizerAPITest(unittest.TestCase): self.assertTrue(params["par4"].limits().isFixed()) - def test_SimpleMinimizer(self): - minimizer = ba.Minimizer() - minimizer.setMinimizer("Test") - - pars = ba.Parameters() - pars.add(ba.Parameter("par0", 0)) - pars.add(ba.Parameter("par1", 1)) - pars.add(ba.Parameter("par2", 2)) - - helper = TestMinimizerHelper() - result = minimizer.minimize(helper.objective_function, pars) - - # return value of objective function was propagated to MinimizerResult - self.assertEqual(result.minValue(), 42) - - # objective function was called twice - #(once by test minimizer, and second time during return type deduction) - self.assertEqual(helper.m_ncalls, 2) - - # starting values of fit parameters were correctly send to objective func - self.assertEqual(list(helper.m_pars.values()), [0, 1, 2.0]) - - if __name__ == '__main__': unittest.main() diff --git a/Tests/Unit/GUI/TestComponentProxyModel.cpp b/Tests/Unit/GUI/TestComponentProxyModel.cpp deleted file mode 100644 index 297f38a187f2108a8bb7f7b6cf560dd142b326c2..0000000000000000000000000000000000000000 --- a/Tests/Unit/GUI/TestComponentProxyModel.cpp +++ /dev/null @@ -1,381 +0,0 @@ -#include "GUI/Model/Component/ComponentProxyModel.h" -#include "GUI/Model/Component/ComponentProxyStrategy.h" -#include "GUI/Model/Sample/FormFactorItems.h" -#include "GUI/Model/Sample/LayerItem.h" -#include "GUI/Model/Sample/MultiLayerItem.h" -#include "GUI/Model/Sample/ParticleItem.h" -#include "GUI/Model/Sample/ParticleLayoutItem.h" -#include "GUI/Model/Session/ModelUtils.h" -#include "GUI/Model/Types/VectorItem.h" -#include "Tests/GTestWrapper/google_test.h" -#include "Tests/Unit/GUI/Utils.h" -#include <QSignalSpy> - -class TestComponentProxyModel : public ::testing::Test { -}; - -//! Empty proxy model. - -TEST_F(TestComponentProxyModel, emptyModel) -{ - ComponentProxyModel proxy; - EXPECT_EQ(proxy.rowCount(QModelIndex()), 0); - EXPECT_EQ(proxy.columnCount(QModelIndex()), static_cast<int>(SessionFlags::MAX_COLUMNS)); - EXPECT_TRUE(proxy.sourceModel() == nullptr); -} - -//! Set empty model to proxy. - -TEST_F(TestComponentProxyModel, setModel) -{ - SessionModel model("TestModel"); - ComponentProxyModel proxy; - - QSignalSpy spy(&proxy, &ComponentProxyModel::modelReset); - proxy.setSessionModel(&model); - - EXPECT_EQ(spy.count(), 1); - EXPECT_EQ(proxy.rowCount(QModelIndex()), 0); - EXPECT_EQ(proxy.columnCount(QModelIndex()), static_cast<int>(SessionFlags::MAX_COLUMNS)); - EXPECT_EQ(proxy.sourceModel(), &model); -} - -//! Set model to proxy. Model already contains simple item. - -TEST_F(TestComponentProxyModel, setModelWithItem) -{ - SessionModel model("TestModel"); - model.insertItem<PropertyItem>(); - - ComponentProxyModel proxy; - proxy.setSessionModel(&model); - - EXPECT_EQ(model.rowCount(QModelIndex()), 1); - EXPECT_EQ(model.columnCount(QModelIndex()), static_cast<int>(SessionFlags::MAX_COLUMNS)); - EXPECT_EQ(proxy.rowCount(QModelIndex()), 1); - EXPECT_EQ(proxy.columnCount(QModelIndex()), static_cast<int>(SessionFlags::MAX_COLUMNS)); -} - -//! Set model to proxy. Model already contains VectorItem. - -TEST_F(TestComponentProxyModel, setModelWithVector) -{ - const int ncols = static_cast<int>(SessionFlags::MAX_COLUMNS); - - SessionModel model("TestModel"); - auto* item = model.insertItem<VectorItem>(); - item->setX(1.0); - item->setY(2.0); - item->setZ(3.0); - - ComponentProxyModel proxy; - proxy.setSessionModel(&model); - - // rows, cols of root index - EXPECT_EQ(model.rowCount(QModelIndex()), 1); - EXPECT_EQ(model.columnCount(QModelIndex()), ncols); - EXPECT_EQ(proxy.rowCount(QModelIndex()), 1); - EXPECT_EQ(proxy.columnCount(QModelIndex()), ncols); - - // mapFromSource, mapToSource for VectorItem - QModelIndex sourceVector = model.index(0, 0, QModelIndex()); - QModelIndex proxyVector = proxy.index(0, 0, QModelIndex()); - EXPECT_TRUE(sourceVector != proxyVector); - EXPECT_TRUE(sourceVector.internalPointer() == proxyVector.internalPointer()); - EXPECT_EQ(proxyVector, proxy.mapFromSource(sourceVector)); - EXPECT_EQ(sourceVector, proxy.mapToSource(proxyVector)); - - // rows, cols of VectorItem - EXPECT_EQ(model.rowCount(sourceVector), 3); // x,y,z - EXPECT_EQ(model.columnCount(sourceVector), ncols); - EXPECT_EQ(proxy.rowCount(proxyVector), 3); // x,y,z - EXPECT_EQ(proxy.columnCount(proxyVector), ncols); - - // second col for VectorItem - QModelIndex sourceVector1 = model.index(0, 1, QModelIndex()); - QModelIndex proxyVector1 = proxy.index(0, 1, QModelIndex()); - EXPECT_TRUE(sourceVector1 != proxyVector1); - EXPECT_TRUE(sourceVector1.internalPointer() == proxyVector1.internalPointer()); - EXPECT_EQ(proxyVector1, proxy.mapFromSource(sourceVector1)); - EXPECT_EQ(sourceVector1, proxy.mapToSource(proxyVector1)); - EXPECT_EQ(model.rowCount(sourceVector1), 0); - EXPECT_EQ(model.columnCount(sourceVector1), 0); - EXPECT_EQ(proxy.rowCount(proxyVector1), 0); - EXPECT_EQ(proxy.columnCount(proxyVector1), 0); - - // mapFromSource, mapToSource for P_X - QModelIndex sourceX = model.index(0, 0, sourceVector); - QModelIndex proxyX = proxy.index(0, 0, proxyVector); - EXPECT_TRUE(sourceX != proxyX); - EXPECT_TRUE(sourceX.internalPointer() == proxyX.internalPointer()); - EXPECT_EQ(proxyX, proxy.mapFromSource(sourceX)); - EXPECT_EQ(sourceX, proxy.mapToSource(proxyX)); - EXPECT_TRUE(model.parent(sourceX) == sourceVector); - EXPECT_TRUE(proxy.parent(proxyX) == proxyVector); - - // rows, cols of P_X - EXPECT_EQ(model.rowCount(sourceX), 0); - EXPECT_EQ(model.columnCount(sourceX), ncols); - EXPECT_EQ(proxy.rowCount(proxyX), 0); - EXPECT_EQ(proxy.columnCount(proxyX), ncols); - - // second col for P_X - QModelIndex sourceX1 = model.index(0, 1, sourceVector); - QModelIndex proxyX1 = proxy.index(0, 1, proxyVector); - EXPECT_TRUE(sourceX1 != proxyX1); - EXPECT_TRUE(sourceX1.internalPointer() == proxyX1.internalPointer()); - EXPECT_EQ(proxyX1, proxy.mapFromSource(sourceX1)); - EXPECT_EQ(sourceX1, proxy.mapToSource(proxyX1)); - EXPECT_EQ(model.rowCount(sourceX1), 0); - EXPECT_EQ(model.columnCount(sourceX1), 0); - EXPECT_EQ(proxy.rowCount(proxyX1), 0); - EXPECT_EQ(proxy.columnCount(proxyX1), 0); - - EXPECT_TRUE(sourceX.sibling(sourceX.row(), 1) == sourceX1); - EXPECT_TRUE(proxyX.sibling(proxyX.row(), 1) == proxyX1); - - // mapFromSource, mapToSource for P_Z - QModelIndex sourceZ = model.index(2, 0, sourceVector); - QModelIndex proxyZ = proxy.index(2, 0, proxyVector); - EXPECT_TRUE(sourceZ != proxyZ); - EXPECT_TRUE(sourceZ.internalPointer() == proxyZ.internalPointer()); - EXPECT_EQ(proxyZ, proxy.mapFromSource(sourceZ)); - EXPECT_EQ(sourceZ, proxy.mapToSource(proxyZ)); - - // rows, cols of P_Z - EXPECT_EQ(model.rowCount(sourceZ), 0); - EXPECT_EQ(model.columnCount(sourceZ), ncols); - EXPECT_EQ(proxy.rowCount(proxyZ), 0); - EXPECT_EQ(proxy.columnCount(proxyZ), ncols); -} - -//! Set model to proxy. Model already contains two PropertyItems. Checking data() method. - -TEST_F(TestComponentProxyModel, displayRole) -{ - SessionModel model("TestModel"); - auto* item1 = model.insertItem<PropertyItem>(); - item1->setValue(1.0); - auto* item2 = model.insertItem<PropertyItem>(); - item2->setValue(2.0); - - EXPECT_EQ(model.data(model.index(0, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 1.0); - EXPECT_EQ(model.data(model.index(1, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 2.0); - - ComponentProxyModel proxy; - proxy.setSessionModel(&model); - - EXPECT_EQ(proxy.data(proxy.index(0, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 1.0); - EXPECT_EQ(proxy.data(proxy.index(1, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 2.0); -} - -//! Set model with item to proxy. Changing the data on source and checking change propagation. - -TEST_F(TestComponentProxyModel, setData) -{ - SessionModel model("TestModel"); - auto* item = model.insertItem<PropertyItem>(); - item->setValue(1.0); - - ComponentProxyModel proxy; - proxy.setSessionModel(&model); - - // checking initial data - EXPECT_EQ(model.data(model.index(0, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 1.0); - EXPECT_EQ(proxy.data(proxy.index(0, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 1.0); - - // changing data in source and listening - QSignalSpy spySource(&model, &SessionModel::dataChanged); - QSignalSpy spyProxy(&proxy, &ComponentProxyModel::dataChanged); - EXPECT_TRUE(model.setData(model.index(0, 1, QModelIndex()), 2.0, Qt::DisplayRole)); - EXPECT_EQ(item->value().toDouble(), 2.0); - - // checking signaling of source - EXPECT_EQ(spySource.count(), 1); - QList<QVariant> arguments = spySource.takeFirst(); - EXPECT_EQ(arguments.size(), 3); - EXPECT_EQ(arguments[0].toModelIndex(), model.index(0, 0, QModelIndex())); - EXPECT_EQ(arguments[1].toModelIndex(), model.index(0, 1, QModelIndex())); - - // checking signaling of proxy - EXPECT_EQ(spyProxy.count(), 1); - EXPECT_EQ(proxy.data(proxy.index(0, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 2.0); - - // changing data in proxy - EXPECT_TRUE(proxy.setData(proxy.index(0, 1, QModelIndex()), 3.0, Qt::DisplayRole)); - EXPECT_EQ(item->value().toDouble(), 3.0); - EXPECT_EQ(spySource.count(), 1); // ?, sould be 2 - EXPECT_EQ(spyProxy.count(), 2); - EXPECT_EQ(model.data(model.index(0, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 3.0); - EXPECT_EQ(proxy.data(proxy.index(0, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 3.0); -} - -//! Checks norification of proxy model then source inserts rows. - -TEST_F(TestComponentProxyModel, insertRows) -{ - SessionModel model("TestModel"); - - ComponentProxyModel proxy; - proxy.setSessionModel(&model); - - EXPECT_FALSE(model.hasChildren(QModelIndex())); - EXPECT_FALSE(proxy.hasChildren(QModelIndex())); - - QSignalSpy spyProxy(&proxy, &ComponentProxyModel::layoutChanged); - - // inserting item in the source - model.insertItem<PropertyItem>(); - EXPECT_EQ(spyProxy.count(), 1); - EXPECT_EQ(proxy.rowCount(QModelIndex()), 1); -} - -//! Checking the mapping of ComponentProxyStrategy in the case of ParticleItem inserted in -//! the source. - -TEST_F(TestComponentProxyModel, componentStrategy) -{ - SessionModel model("TestModel"); - - ComponentProxyModel proxy; - proxy.setProxyStrategy(new ComponentProxyStrategy); - proxy.setSessionModel(&model); - - // inserting particle - auto* item = model.insertItem<ParticleItem>(); - auto* group = item->formFactorItem(); - SessionItem* ffItem = item->formFactor(); - EXPECT_TRUE(ffItem->parent() == group); - EXPECT_TRUE(ffItem->hasModelType<CylinderItem>()); - - // original indices - QModelIndex particleIndex = model.indexOfItem(item); - QModelIndex groupIndex = model.indexOfItem(group); - QModelIndex ffIndex = model.indexOfItem(ffItem); - QModelIndex radiusIndex = model.indexOfItem(dynamic_cast<CylinderItem*>(ffItem)->radiusItem()); - - // proxy indices - QModelIndex particleProxyIndex = proxy.mapFromSource(particleIndex); - EXPECT_TRUE(particleProxyIndex.isValid()); - - // Properties of CylinderItem should belong to group property - QModelIndex groupProxyIndex = proxy.mapFromSource(groupIndex); - EXPECT_TRUE(groupProxyIndex.isValid()); - EXPECT_TRUE(groupProxyIndex.parent() == particleProxyIndex); - EXPECT_EQ(proxy.rowCount(groupProxyIndex), 2); // ff radius and height - EXPECT_EQ(proxy.columnCount(groupProxyIndex), 2); - - // CylinderItem shouldn't exist anymore in proxy - QModelIndex ffProxyIndex = proxy.mapFromSource(ffIndex); - EXPECT_FALSE(ffProxyIndex.isValid()); - - QModelIndex radiusProxyIndex = proxy.mapFromSource(radiusIndex); - EXPECT_TRUE(radiusProxyIndex.isValid()); - EXPECT_TRUE(radiusProxyIndex.parent() == groupProxyIndex); -} - -//! Checking the mapping of ComponentProxyStrategy in the case of ParticleItem inserted in -//! the source. We are changing Particle's form factor back and forth and checking for change -//! in GroupProperty. - -TEST_F(TestComponentProxyModel, componentStrategyFormFactorChanges) -{ - SessionModel model("TestModel"); - - ComponentProxyModel proxy; - proxy.setProxyStrategy(new ComponentProxyStrategy); - proxy.setSessionModel(&model); - - // inserting particle - auto* item = model.insertItem<ParticleItem>(); - auto* group = item->formFactorItem(); - SessionItem* ffItem = item->formFactor(); - EXPECT_TRUE(ffItem->parent() == group); - EXPECT_TRUE(ffItem->hasModelType<CylinderItem>()); - - // changing form factor type - group->setCurrentType(FullSphereItem::M_TYPE); - - QModelIndex groupProxyIndex = proxy.mapFromSource(model.indexOfItem(group)); - EXPECT_EQ(proxy.rowCount(groupProxyIndex), 1); // sphere radius - EXPECT_EQ(proxy.columnCount(groupProxyIndex), 2); - - // changing back to Cylinder - group->setCurrentType(CylinderItem::M_TYPE); - groupProxyIndex = proxy.mapFromSource(model.indexOfItem(group)); - EXPECT_EQ(proxy.rowCount(groupProxyIndex), 2); // cylinder radius, length - EXPECT_EQ(proxy.columnCount(groupProxyIndex), 2); -} - -//! Checking setRootIndex: proxy model should contain only items corresponding -//! to rootIndex and its children. Adding simple PropertyItem. - -TEST_F(TestComponentProxyModel, setRootPropertyItem) -{ - const int ncols = static_cast<int>(SessionFlags::MAX_COLUMNS); - SessionModel model("TestModel"); - - ComponentProxyModel proxy; - proxy.setProxyStrategy(new ComponentProxyStrategy); - proxy.setSessionModel(&model); - - // inserting simple property item - auto* item = model.insertItem<PropertyItem>(); - item->setValue(42.0); - proxy.setRootIndex(model.indexOfItem(item)); - - EXPECT_EQ(model.rowCount(QModelIndex()), 1); - EXPECT_EQ(model.columnCount(QModelIndex()), ncols); - EXPECT_EQ(proxy.rowCount(QModelIndex()), 1); - EXPECT_EQ(proxy.columnCount(QModelIndex()), ncols); - - EXPECT_TRUE(proxy.index(0, 0, QModelIndex()) - == proxy.mapFromSource(model.index(0, 0, QModelIndex()))); - EXPECT_TRUE(proxy.index(0, 1, QModelIndex()) - == proxy.mapFromSource(model.index(0, 1, QModelIndex()))); - EXPECT_TRUE(model.index(0, 0, QModelIndex()) - == proxy.mapToSource(proxy.index(0, 0, QModelIndex()))); - EXPECT_TRUE(proxy.index(0, 1, QModelIndex()).isValid()); - EXPECT_TRUE(model.index(0, 1, QModelIndex()) - == proxy.mapToSource(proxy.index(0, 1, QModelIndex()))); - - EXPECT_EQ(model.data(model.index(0, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 42.0); - EXPECT_EQ(proxy.data(proxy.index(0, 1, QModelIndex()), Qt::DisplayRole).toDouble(), 42.0); -} - -//! Checking setRootIndex: proxy model should contain only items corresponding -//! to rootIndex and its children. Adding MultiLayer with two layers and setting rootIndex -//! to one of the layer. - -TEST_F(TestComponentProxyModel, setRootIndexLayer) -{ - - SessionModel model("TestModel"); - - ComponentProxyModel proxy; - proxy.setProxyStrategy(new ComponentProxyStrategy); - proxy.setSessionModel(&model); - - // inserting multilayer with two layers - auto* multilayer = model.insertItem<MultiLayerItem>(); - auto* layer1 = model.insertItem<LayerItem>(multilayer); - auto* layout = model.insertItem<ParticleLayoutItem>(layer1); - model.insertItem<LayerItem>(multilayer); - - proxy.setRootIndex(model.indexOfItem(layer1)); - EXPECT_EQ(proxy.rowCount(QModelIndex()), 1); - EXPECT_EQ(proxy.columnCount(QModelIndex()), 2); - - QModelIndex multilayerProxyIndex = proxy.mapFromSource(model.indexOfItem(multilayer)); - EXPECT_FALSE(multilayerProxyIndex.isValid()); - - QModelIndex layerProxyIndex = proxy.mapFromSource(model.indexOfItem(layer1)); - EXPECT_EQ(proxy.rowCount(layerProxyIndex), 5); // thickness, material, slices, roughness, color - EXPECT_EQ(proxy.columnCount(layerProxyIndex), 2); - EXPECT_TRUE(layerProxyIndex.isValid()); - EXPECT_TRUE(layerProxyIndex.parent() == QModelIndex()); - - // ParticleLayout should be excluded from proxy tree - QModelIndex layoutProxyIndex = proxy.mapFromSource(model.indexOfItem(layout)); - EXPECT_FALSE(layoutProxyIndex.isValid()); -} diff --git a/Tests/Unit/GUI/TestComponentUtils.cpp b/Tests/Unit/GUI/TestComponentUtils.cpp deleted file mode 100644 index 4d05f4cc9f5c6f50ba36f05bf3b907ae1a1e5d18..0000000000000000000000000000000000000000 --- a/Tests/Unit/GUI/TestComponentUtils.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "GUI/Model/Component/ComponentUtils.h" -#include "GUI/Model/Sample/FormFactorItems.h" -#include "GUI/Model/Sample/ParticleItem.h" -#include "GUI/Model/Session/SessionModel.h" -#include "GUI/Model/Types/VectorItem.h" -#include "Tests/GTestWrapper/google_test.h" - -class TestComponentUtils : public ::testing::Test { -}; - -//! Testing component items of particle item. - -TEST_F(TestComponentUtils, componentItems) -{ - SessionModel model("TestModel"); - - auto* particle = model.insertItem<ParticleItem>(); - SessionItem* group = particle->formFactorItem(); - SessionItem* ffItem = particle->formFactor(); - auto* ffCylinder = dynamic_cast<CylinderItem*>(ffItem); - EXPECT_NE(ffCylinder, nullptr); - - auto itemList = GUI::Model::ComponentUtils::componentItems(*particle); - EXPECT_EQ(itemList.size(), 6); - EXPECT_TRUE(itemList.contains(particle->abundanceItem())); - EXPECT_TRUE(itemList.contains(particle->positionItem())); - EXPECT_TRUE(itemList.contains(group)); - EXPECT_TRUE(itemList.contains(ffCylinder->radiusItem())); - EXPECT_TRUE(itemList.contains(ffCylinder->heightItem())); - // the 6th is material item (holds material identifier) -} - -TEST_F(TestComponentUtils, componentItemsFFChange) -{ - SessionModel model("TestModel"); - - auto* particle = model.insertItem<ParticleItem>(); - SessionItem* group = particle->formFactorItem(); - - particle->setFormFactorType<FullSphereItem>(); - auto* sphereItem = dynamic_cast<FullSphereItem*>(particle->formFactor()); - - auto itemList = GUI::Model::ComponentUtils::componentItems(*particle); - EXPECT_EQ(itemList.size(), 5); - EXPECT_TRUE(itemList.contains(particle->abundanceItem())); - EXPECT_TRUE(itemList.contains(particle->positionItem())); - EXPECT_TRUE(itemList.contains(group)); - EXPECT_TRUE(itemList.contains(sphereItem->radiusItem())); - // the 5th is material item (holds material identifier) -} diff --git a/Tests/Unit/GUI/TestProxyModelStrategy.cpp b/Tests/Unit/GUI/TestProxyModelStrategy.cpp deleted file mode 100644 index 3175f48a4efe62d7728e1ff10fa7968add24369a..0000000000000000000000000000000000000000 --- a/Tests/Unit/GUI/TestProxyModelStrategy.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "GUI/Model/Component/ComponentProxyModel.h" -#include "GUI/Model/Component/ComponentProxyStrategy.h" -#include "GUI/Model/Group/PropertyItem.h" -#include "GUI/Model/Sample/FormFactorItems.h" -#include "GUI/Model/Sample/ParticleItem.h" -#include "GUI/Model/Session/ModelUtils.h" -#include "GUI/Model/Session/SessionModel.h" -#include "GUI/Model/Types/VectorItem.h" -#include "Tests/GTestWrapper/google_test.h" - -class TestProxyModelStrategy : public ::testing::Test { -}; - -//! Checking the mapping in the case of PropertyItem inserted in the source. - -TEST_F(TestProxyModelStrategy, identityStrategy) -{ - SessionModel model("TestModel"); - ComponentProxyModel proxy; - IndentityProxyStrategy strategy; - - EXPECT_EQ(strategy.sourceToProxy().size(), 0); - EXPECT_EQ(strategy.proxySourceParent().size(), 0); - - // building the map of empty source - strategy.buildModelMap(&model, &proxy); - EXPECT_EQ(strategy.sourceToProxy().size(), 0); - EXPECT_EQ(strategy.proxySourceParent().size(), 0); - - // building map when simple item - auto* item = model.insertItem<PropertyItem>(); - strategy.buildModelMap(&model, &proxy); - EXPECT_EQ(strategy.sourceToProxy().size(), 2); - EXPECT_EQ(strategy.proxySourceParent().size(), 2); - - // Checking of persistent indices of source and proxy - auto it = strategy.sourceToProxy().begin(); - // index of source, col=0 - EXPECT_EQ(it.key().row(), 0); - EXPECT_EQ(it.key().column(), 0); - EXPECT_EQ(it.key().internalPointer(), item); - // index of proxy, col=0 - EXPECT_EQ(it.value().row(), 0); - EXPECT_EQ(it.value().column(), 0); - EXPECT_EQ(it.value().internalPointer(), item); - ++it; - // index of source, col=1 - EXPECT_EQ(it.key().row(), 0); - EXPECT_EQ(it.key().column(), 1); - EXPECT_EQ(it.key().internalPointer(), item); - // index of proxy, col=1 - EXPECT_EQ(it.value().row(), 0); - EXPECT_EQ(it.value().column(), 1); - EXPECT_EQ(it.value().internalPointer(), item); - - // Checking parent of proxy - it = strategy.proxySourceParent().begin(); - EXPECT_EQ(it.key().row(), 0); - EXPECT_EQ(it.key().column(), 0); - EXPECT_EQ(it.key().internalPointer(), item); - EXPECT_TRUE(it.value() == QModelIndex()); -} - -//! Checking the mapping in the case of ParticleItem inserted in the source. - -TEST_F(TestProxyModelStrategy, identityStrategyParticle) -{ - SessionModel model("TestModel"); - ComponentProxyModel proxy; - IndentityProxyStrategy strategy; - - auto* item = model.insertItem<ParticleItem>(); - - // building the map of source - strategy.buildModelMap(&model, &proxy); - SessionItem* group = item->formFactorItem(); - SessionItem* ffItem = item->formFactor(); - EXPECT_TRUE(ffItem->parent() == group); - EXPECT_TRUE(ffItem->hasModelType<CylinderItem>()); - - // Checking "real" parent of proxy index related to form factor. - // For identity model we are testing, it has to be just group property. - auto ffProxyIndex = strategy.sourceToProxy().value(model.indexOfItem(ffItem)); - auto parentOfProxy = strategy.proxySourceParent().value(ffProxyIndex); - EXPECT_TRUE(parentOfProxy == model.indexOfItem(group)); - - // Checking "real" parent of Cylinders radius. It has to be CylinderItem - auto* ffCylinder = dynamic_cast<CylinderItem*>(ffItem); - EXPECT_NE(ffCylinder, nullptr); - SessionItem* radiusItem = ffCylinder->radiusItem(); - auto radiusProxyIndex = strategy.sourceToProxy().value(model.indexOfItem(radiusItem)); - parentOfProxy = strategy.proxySourceParent().value(radiusProxyIndex); - EXPECT_TRUE(parentOfProxy == model.indexOfItem(ffItem)); -} - -//! Checking the mapping of ComponentProxyStrategy in the case of ParticleItem inserted in -//! the source. - -TEST_F(TestProxyModelStrategy, componentStrategyParticle) -{ - SessionModel model("TestModel"); - ComponentProxyModel proxy; - ComponentProxyStrategy strategy; - - auto* item = model.insertItem<ParticleItem>(); - - // building the map of source - strategy.buildModelMap(&model, &proxy); - SessionItem* group = item->formFactorItem(); - SessionItem* ffItem = item->formFactor(); - EXPECT_TRUE(ffItem->parent() == group); - EXPECT_TRUE(ffItem->hasModelType<CylinderItem>()); - auto* ffCylinder = dynamic_cast<CylinderItem*>(ffItem); - - // original indices - QModelIndex particleIndex = model.indexOfItem(item); - QModelIndex groupIndex = model.indexOfItem(group); - QModelIndex ffIndex = model.indexOfItem(ffItem); - QModelIndex radiusIndex = model.indexOfItem(ffCylinder->radiusItem()); - - // proxy indices - QModelIndex particleProxyIndex = strategy.sourceToProxy().value(particleIndex); - QModelIndex groupProxyIndex = strategy.sourceToProxy().value(groupIndex); - QModelIndex ffProxyIndex = strategy.sourceToProxy().value(ffIndex); - QModelIndex radiusProxyIndex = strategy.sourceToProxy().value(radiusIndex); - EXPECT_TRUE(particleProxyIndex.isValid()); - EXPECT_TRUE(groupProxyIndex.isValid()); - EXPECT_FALSE(ffProxyIndex.isValid()); // ff is excluded from hierarchy - EXPECT_TRUE(radiusProxyIndex.isValid()); - - // Checking "real" parents of indices - EXPECT_TRUE(strategy.proxySourceParent().value(ffProxyIndex) == QModelIndex()); - EXPECT_TRUE(strategy.proxySourceParent().value(radiusProxyIndex) == groupIndex); - EXPECT_TRUE(strategy.proxySourceParent().value(groupProxyIndex) == particleIndex); -} - -//! Checking setRootIndex: proxy model should contain only items corresponding -//! to rootIndex and its children. - -TEST_F(TestProxyModelStrategy, setRootIndex) -{ - SessionModel model("TestModel"); - ComponentProxyModel proxy; - ComponentProxyStrategy strategy; - - auto* item = model.insertItem<ParticleItem>(); - SessionItem* group = item->formFactorItem(); - SessionItem* ffItem = item->formFactor(); - auto* ffCylinder = dynamic_cast<CylinderItem*>(ffItem); - EXPECT_NE(ffCylinder, nullptr); - - QModelIndex particleIndex = model.indexOfItem(item); - QModelIndex groupIndex = model.indexOfItem(group); - QModelIndex ffIndex = model.indexOfItem(ffItem); - QModelIndex radiusIndex = model.indexOfItem(ffCylinder->radiusItem()); - - // building the map of source, groupItem will be rootIndex - strategy.setRootIndex(model.indexOfItem(group)); - strategy.buildModelMap(&model, &proxy); - - // proxy indices - QModelIndex particleProxyIndex = strategy.sourceToProxy().value(particleIndex); - QModelIndex groupProxyIndex = strategy.sourceToProxy().value(groupIndex); - QModelIndex ffProxyIndex = strategy.sourceToProxy().value(ffIndex); - QModelIndex radiusProxyIndex = strategy.sourceToProxy().value(radiusIndex); - EXPECT_FALSE(particleProxyIndex.isValid()); // particle is not in a tree - EXPECT_TRUE(groupProxyIndex.isValid()); - EXPECT_EQ(groupProxyIndex.row(), 0); - EXPECT_EQ(groupProxyIndex.column(), 0); - EXPECT_TRUE(groupProxyIndex.parent() == QModelIndex()); - EXPECT_FALSE(ffProxyIndex.isValid()); // ff is excluded from hierarchy - EXPECT_TRUE(radiusProxyIndex.isValid()); - - // checking that new parent of groupItem is root - EXPECT_TRUE(strategy.proxySourceParent().value(groupProxyIndex) == QModelIndex()); - EXPECT_TRUE(strategy.proxySourceParent().value(ffProxyIndex) == QModelIndex()); - EXPECT_TRUE(strategy.proxySourceParent().value(radiusProxyIndex) == groupIndex); -}