From 2a601a3e3388663f275ecf4be980610c5992a7b4 Mon Sep 17 00:00:00 2001
From: Gennady Pospelov <g.pospelov@fz-juelich.de>
Date: Tue, 14 Nov 2017 15:42:48 +0100
Subject: [PATCH] New ModelUtils function to iterate through children only if
 user callback allows.

---
 GUI/coregui/Models/ModelUtils.cpp    | 16 ++++++++++++
 GUI/coregui/Models/ModelUtils.h      |  6 ++++-
 Tests/UnitTests/GUI/TestGUI.cpp      |  2 +-
 Tests/UnitTests/GUI/TestModelUtils.h | 39 +++++++++++++++++++++++++++-
 4 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/GUI/coregui/Models/ModelUtils.cpp b/GUI/coregui/Models/ModelUtils.cpp
index 9f34a10d6a5..eaf53ab916c 100644
--- a/GUI/coregui/Models/ModelUtils.cpp
+++ b/GUI/coregui/Models/ModelUtils.cpp
@@ -31,3 +31,19 @@ void ModelUtils::iterate(const QModelIndex& index, const QAbstractItemModel* mod
         for (int j = 0; j < model->columnCount(index); ++j)
             iterate(model->index(i, j, index), model, fun);
 }
+
+void ModelUtils::iterate_if(const QModelIndex& index, const QAbstractItemModel* model,
+                            const std::function<bool (const QModelIndex&)>& fun)
+{
+    bool proceed_with_children(true);
+    if (index.isValid())
+        proceed_with_children = fun(index);
+
+    if (!model->hasChildren(index) || !proceed_with_children)
+        return;
+
+    for (int i = 0; i < model->rowCount(index); ++i)
+        for (int j = 0; j < model->columnCount(index); ++j)
+            iterate_if(model->index(i, j, index), model, fun);
+
+}
diff --git a/GUI/coregui/Models/ModelUtils.h b/GUI/coregui/Models/ModelUtils.h
index c99f7d399dd..ef9306dca27 100644
--- a/GUI/coregui/Models/ModelUtils.h
+++ b/GUI/coregui/Models/ModelUtils.h
@@ -30,7 +30,11 @@ namespace ModelUtils
 BA_CORE_API_ void iterate(const QModelIndex& index, const QAbstractItemModel* model,
                           const std::function<void(const QModelIndex&)>& fun);
 
-}
+//! Iterates through all model indices and calls user function.
+//! If function returns false for given index, iteration will not go down to children.
+BA_CORE_API_ void iterate_if(const QModelIndex& index, const QAbstractItemModel* model,
+                          const std::function<bool(const QModelIndex&)>& fun);
 
+}
 
 #endif  //  MODELUTILS_H
diff --git a/Tests/UnitTests/GUI/TestGUI.cpp b/Tests/UnitTests/GUI/TestGUI.cpp
index fa44f095501..96afb70d414 100644
--- a/Tests/UnitTests/GUI/TestGUI.cpp
+++ b/Tests/UnitTests/GUI/TestGUI.cpp
@@ -96,7 +96,7 @@ 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>();
 
diff --git a/Tests/UnitTests/GUI/TestModelUtils.h b/Tests/UnitTests/GUI/TestModelUtils.h
index d5f9ed6b75f..46e27303743 100644
--- a/Tests/UnitTests/GUI/TestModelUtils.h
+++ b/Tests/UnitTests/GUI/TestModelUtils.h
@@ -3,17 +3,32 @@
 #include "SessionModel.h"
 #include "item_constants.h"
 #include "VectorItem.h"
+#include "LayerItem.h"
 #include <QVector>
 #include <QDebug>
 
 class TestModelUtils : public QObject
 {
     Q_OBJECT
-public:
+private:
+
+    //! Returns true if model contains given item using iterate_if procedure.
+    bool modelContainsItem(SessionModel* model, SessionItem* selectedItem)
+    {
+        bool result = false;
+        ModelUtils::iterate_if(QModelIndex(), model, [&](const QModelIndex& index) -> bool {
+            SessionItem* item = model->itemForIndex(index);
+            if(item == selectedItem)
+                result = true;
+            return item->isVisible();
+        });
+        return result;
+    }
 
 private slots:
     void test_emptyModel();
     void test_vectorItem();
+    void test_iterateIf();
 };
 
 //! Testing iteration over empty model.
@@ -57,3 +72,25 @@ inline void TestModelUtils::test_vectorItem()
     QCOMPARE(model.itemForIndex(indices.front()), vectorItem);
     QCOMPARE(model.itemForIndex(indices.back()), vectorItem->getItem(VectorItem::P_Z));
 }
+
+//! Tests iteration when some children is invisible.
+
+inline void TestModelUtils::test_iterateIf()
+{
+    SessionModel model("TestModel");
+    SessionItem* multilayer = model.insertNewItem(Constants::MultiLayerType);
+    SessionItem* layer = model.insertNewItem(Constants::LayerType, model.indexOfItem(multilayer));
+    SessionItem* thicknessItem = layer->getItem(LayerItem::P_THICKNESS);
+
+    layer->setVisible(true);
+    QVERIFY(modelContainsItem(&model, layer) == true);
+    QVERIFY(modelContainsItem(&model, thicknessItem) == true);
+
+    // Setting layer invisible will hide its children from iteration.
+    // Layer itself still will be visible.
+    layer->setVisible(false);
+
+    layer->setVisible(false);
+    QVERIFY(modelContainsItem(&model, layer) == true);
+    QVERIFY(modelContainsItem(&model, thicknessItem) == false);
+}
-- 
GitLab