From aafc92f68f2058a11b67a38a7867b33f008206c4 Mon Sep 17 00:00:00 2001 From: Gennady Pospelov <g.pospelov@fz-juelich.de> Date: Fri, 10 Nov 2017 14:20:12 +0100 Subject: [PATCH] Identity proxy strategy was extracted to separate class. --- GUI/coregui/Models/ComponentProxyModel.cpp | 32 ++---- GUI/coregui/Models/ComponentProxyModel.h | 10 +- GUI/coregui/Models/ProxyModelStrategy.cpp | 58 +++++++++++ GUI/coregui/Models/ProxyModelStrategy.h | 56 ++++++++++ Tests/UnitTests/GUI/TestGUI.cpp | 4 +- Tests/UnitTests/GUI/TestProxyModelStrategy.h | 102 +++++++++++++++++++ 6 files changed, 233 insertions(+), 29 deletions(-) create mode 100644 GUI/coregui/Models/ProxyModelStrategy.cpp create mode 100644 GUI/coregui/Models/ProxyModelStrategy.h create mode 100644 Tests/UnitTests/GUI/TestProxyModelStrategy.h diff --git a/GUI/coregui/Models/ComponentProxyModel.cpp b/GUI/coregui/Models/ComponentProxyModel.cpp index 10689537afb..1bea981d90e 100644 --- a/GUI/coregui/Models/ComponentProxyModel.cpp +++ b/GUI/coregui/Models/ComponentProxyModel.cpp @@ -17,12 +17,14 @@ #include "ComponentProxyModel.h" #include "SessionModel.h" #include "ModelUtils.h" +#include "ProxyModelStrategy.h" #include <functional> #include <QDebug> ComponentProxyModel::ComponentProxyModel(QObject* parent) : QAbstractProxyModel(parent) , m_model(nullptr) + , m_proxyStrategy(new IndentityProxyStrategy) { } @@ -70,7 +72,7 @@ QModelIndex ComponentProxyModel::mapToSource(const QModelIndex& proxyIndex) cons if (!proxyIndex.isValid()) return QModelIndex(); - return m_sourceToProxy.key(proxyIndex); + return m_proxyStrategy->sourceToProxy().key(proxyIndex); } QModelIndex ComponentProxyModel::mapFromSource(const QModelIndex& sourceIndex) const @@ -78,7 +80,7 @@ QModelIndex ComponentProxyModel::mapFromSource(const QModelIndex& sourceIndex) c if (!sourceIndex.isValid()) return QModelIndex(); - return m_sourceToProxy.value(sourceIndex); + return m_proxyStrategy->sourceToProxy().value(sourceIndex); } QModelIndex ComponentProxyModel::index(int row, int column, const QModelIndex& parent) const @@ -87,7 +89,7 @@ QModelIndex ComponentProxyModel::index(int row, int column, const QModelIndex& p if (parent.isValid()) sourceParent = mapToSource(parent); - QMapIterator<QPersistentModelIndex, QPersistentModelIndex> it(m_proxySourceParent); + QMapIterator<QPersistentModelIndex, QPersistentModelIndex> it(m_proxyStrategy->proxySourceParent()); while (it.hasNext()) { it.next(); if (it.value() == sourceParent && it.key().row() == row && @@ -99,7 +101,7 @@ QModelIndex ComponentProxyModel::index(int row, int column, const QModelIndex& p QModelIndex ComponentProxyModel::parent(const QModelIndex& child) const { - QModelIndex sourceParent = m_proxySourceParent.value(child); + QModelIndex sourceParent = m_proxyStrategy->proxySourceParent().value(child); if (sourceParent.isValid()) return mapFromSource(sourceParent); @@ -111,7 +113,7 @@ int ComponentProxyModel::rowCount(const QModelIndex& parent) const QModelIndex sourceParent; if (parent.isValid()) sourceParent = mapToSource(parent); - QMapIterator<QPersistentModelIndex, QPersistentModelIndex> it(m_proxySourceParent); + QMapIterator<QPersistentModelIndex, QPersistentModelIndex> it(m_proxyStrategy->proxySourceParent()); QSet<int> rows; while (it.hasNext()) { @@ -177,24 +179,6 @@ void ComponentProxyModel::sourceRowsInserted(const QModelIndex& parent, int star void ComponentProxyModel::buildModelMap() { - m_sourceToProxy.clear(); - m_proxySourceParent.clear(); - - ModelUtils::iterate(QModelIndex(), m_model, [=](const QModelIndex& index){ - SessionItem* item = m_model->itemForIndex(index); - -// qDebug() << "XXX index" << index << "index.parent" << index.parent(); - QPersistentModelIndex proxy = createIndex(index.row(), index.column(), item); - m_sourceToProxy.insert(QPersistentModelIndex(index), proxy); - - QPersistentModelIndex sourceParent; - if (index.parent().isValid()) - sourceParent = index.parent(); - -// qDebug() << "YYY proxy" << proxy << "sourceParent" << sourceParent; - m_proxySourceParent.insert(proxy, sourceParent); -// qDebug() << " "; - }); - + m_proxyStrategy->buildModelMap(m_model, this); layoutChanged(); } diff --git a/GUI/coregui/Models/ComponentProxyModel.h b/GUI/coregui/Models/ComponentProxyModel.h index 403061e0cca..d8640ce3373 100644 --- a/GUI/coregui/Models/ComponentProxyModel.h +++ b/GUI/coregui/Models/ComponentProxyModel.h @@ -18,11 +18,14 @@ #define COMPONENTPROXYMODEL_H #include "WinDllMacros.h" +#include "ProxyModelStrategy.h" #include <QAbstractProxyModel> #include <QPersistentModelIndex> #include <QMap> +#include <memory> class SessionModel; +class ProxyModelStrategy; //! Proxy model to adjust SessionModel for component editor (right bottom corner of SampleView //! and similar). @@ -33,6 +36,8 @@ class SessionModel; class BA_CORE_API_ ComponentProxyModel : public QAbstractProxyModel { Q_OBJECT + + friend class ProxyModelStrategy; public: ComponentProxyModel(QObject* parent = nullptr); @@ -60,11 +65,8 @@ private slots: private: void buildModelMap(); - //!< 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; SessionModel* m_model; + std::unique_ptr<ProxyModelStrategy> m_proxyStrategy; }; #endif // COMPONENTPROXYMODEL_H diff --git a/GUI/coregui/Models/ProxyModelStrategy.cpp b/GUI/coregui/Models/ProxyModelStrategy.cpp new file mode 100644 index 00000000000..769537a1d83 --- /dev/null +++ b/GUI/coregui/Models/ProxyModelStrategy.cpp @@ -0,0 +1,58 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file GUI/coregui/Models/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 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#include "ProxyModelStrategy.h" +#include "ModelUtils.h" +#include "ComponentProxyModel.h" + +const ProxyModelStrategy::map_t& ProxyModelStrategy::sourceToProxy() +{ + return m_sourceToProxy; +} + +const ProxyModelStrategy::map_t& ProxyModelStrategy::proxySourceParent() +{ + return m_proxySourceParent; +} + +//! Method to ask proxy to create an index using friendship of ProxyModelStrategy +//! and ComponentProxyModel. + +QModelIndex ProxyModelStrategy::createIndex(ComponentProxyModel* proxy, int nrow, int ncol, + void* adata) +{ + return proxy->createIndex(nrow, ncol, adata); +} + +//! Builds one-to-one mapping for source and proxy. + +void IndentityProxyStrategy::buildModelMap(QAbstractItemModel* source, ComponentProxyModel* proxy) +{ + m_sourceToProxy.clear(); + m_proxySourceParent.clear(); + + ModelUtils::iterate(QModelIndex(), source, [=](const QModelIndex& index) { + QPersistentModelIndex proxyIndex + = createIndex(proxy, 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); + }); +} diff --git a/GUI/coregui/Models/ProxyModelStrategy.h b/GUI/coregui/Models/ProxyModelStrategy.h new file mode 100644 index 00000000000..fbb1eb2b704 --- /dev/null +++ b/GUI/coregui/Models/ProxyModelStrategy.h @@ -0,0 +1,56 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file GUI/coregui/Models/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 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#ifndef PROXYMODELSTRATEGY_H +#define PROXYMODELSTRATEGY_H + +#include "WinDllMacros.h" +#include <QPersistentModelIndex> + +class QAbstractItemModel; +class ComponentProxyModel; + +//! Base class for proxy strategies in ComponentProxyModel. + +class BA_CORE_API_ ProxyModelStrategy +{ +public: + using map_t = QMap<QPersistentModelIndex, QPersistentModelIndex>; + + virtual ~ProxyModelStrategy() = default; + virtual void buildModelMap(QAbstractItemModel* source, ComponentProxyModel* proxy) = 0; + + const map_t& sourceToProxy(); + const map_t& proxySourceParent(); + +protected: + QModelIndex createIndex(ComponentProxyModel* proxy, int nrow, int ncol, void* adata); + + //!< 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; +}; + +//! Strategy for ComponentProxyModel which makes it identical to source model. + +class BA_CORE_API_ IndentityProxyStrategy : public ProxyModelStrategy +{ +public: + void buildModelMap(QAbstractItemModel* source, ComponentProxyModel* proxy); +}; + +#endif // ProxyModelStrategy diff --git a/Tests/UnitTests/GUI/TestGUI.cpp b/Tests/UnitTests/GUI/TestGUI.cpp index b327e99aea8..fa44f095501 100644 --- a/Tests/UnitTests/GUI/TestGUI.cpp +++ b/Tests/UnitTests/GUI/TestGUI.cpp @@ -33,6 +33,7 @@ #include "TestSessionItemController.h" #include "TestModelUtils.h" #include "TestComponentProxyModel.h" +#include "TestProxyModelStrategy.h" #include <memory> class GUITestFactory { @@ -95,8 +96,9 @@ int main(int argc, char** argv) { // tests.add<TestParticleCoreShell>(); // tests.add<TestPropertyRepeater>(); // tests.add<TestSessionItemController>(); - tests.add<TestModelUtils>(); +// tests.add<TestModelUtils>(); tests.add<TestComponentProxyModel>(); + tests.add<TestProxyModelStrategy>(); return tests.runAll(argc, argv); } diff --git a/Tests/UnitTests/GUI/TestProxyModelStrategy.h b/Tests/UnitTests/GUI/TestProxyModelStrategy.h new file mode 100644 index 00000000000..d1878667b4a --- /dev/null +++ b/Tests/UnitTests/GUI/TestProxyModelStrategy.h @@ -0,0 +1,102 @@ +#include <QtTest> +#include "ModelUtils.h" +#include "SessionModel.h" +#include "item_constants.h" +#include "ComponentProxyModel.h" +#include "ProxyModelStrategy.h" +#include "VectorItem.h" +#include "ParticleItem.h" +#include "FormFactorItems.h" +#include <QSignalSpy> +#include <QDebug> + +class TestProxyModelStrategy : public QObject +{ + Q_OBJECT +public: + +private slots: + void test_identityStrategy(); + void test_identityStrategyParticle(); +}; + +//! Checking the mapping in the case of PropertyItem inserted in the source. + +inline void TestProxyModelStrategy::test_identityStrategy() +{ + SessionModel model("TestModel"); + ComponentProxyModel proxy; + IndentityProxyStrategy strategy; + + QCOMPARE(strategy.sourceToProxy().size(), 0); + QCOMPARE(strategy.proxySourceParent().size(), 0); + + // building the map of empty source + strategy.buildModelMap(&model, &proxy); + QCOMPARE(strategy.sourceToProxy().size(), 0); + QCOMPARE(strategy.proxySourceParent().size(), 0); + + // building map when simple item + SessionItem* item = model.insertNewItem(Constants::PropertyType); + strategy.buildModelMap(&model, &proxy); + QCOMPARE(strategy.sourceToProxy().size(), 2); + QCOMPARE(strategy.proxySourceParent().size(), 2); + + // Checking of persistent indices of source and proxy + auto it = strategy.sourceToProxy().begin(); + // index of source, col=0 + QCOMPARE(it.key().row(), 0); + QCOMPARE(it.key().column(), 0); + QCOMPARE(it.key().internalPointer(), item); + // index of proxy, col=0 + QCOMPARE(it.value().row(), 0); + QCOMPARE(it.value().column(), 0); + QCOMPARE(it.value().internalPointer(), item); + ++it; + // index of source, col=1 + QCOMPARE(it.key().row(), 0); + QCOMPARE(it.key().column(), 1); + QCOMPARE(it.key().internalPointer(), item); + // index of proxy, col=1 + QCOMPARE(it.value().row(), 0); + QCOMPARE(it.value().column(), 1); + QCOMPARE(it.value().internalPointer(), item); + + // Checking parent of proxy + it = strategy.proxySourceParent().begin(); + QCOMPARE(it.key().row(), 0); + QCOMPARE(it.key().column(), 0); + QCOMPARE(it.key().internalPointer(), item); + QVERIFY(it.value() == QModelIndex()); +} + +//! Checking the mapping in the case of ParticleItem inserted in the source. + +inline void TestProxyModelStrategy::test_identityStrategyParticle() +{ + SessionModel model("TestModel"); + ComponentProxyModel proxy; + IndentityProxyStrategy strategy; + + SessionItem* item = model.insertNewItem(Constants::ParticleType); + + // building the map of empty source + strategy.buildModelMap(&model, &proxy); + SessionItem* group = item->getItem(ParticleItem::P_FORM_FACTOR); + SessionItem* ffItem = item->getGroupItem(ParticleItem::P_FORM_FACTOR); + QVERIFY(ffItem->parent() == group); + QVERIFY(ffItem->modelType() == Constants::CylinderType); + + // 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); + QVERIFY(parentOfProxy == model.indexOfItem(group)); + + // Checking "real" parent of Cylinders radius. It has to be CylinderItem + SessionItem* radiusItem = ffItem->getItem(CylinderItem::P_RADIUS); + auto radiusProxyIndex = strategy.sourceToProxy().value(model.indexOfItem(radiusItem)); + parentOfProxy = strategy.proxySourceParent().value(radiusProxyIndex); + QVERIFY(parentOfProxy == model.indexOfItem(ffItem)); +} + -- GitLab