From ba1a657227e8673da709b32f81b428b0441ff31b Mon Sep 17 00:00:00 2001
From: Christian Stenger <christian.stenger@qt.io>
Date: Thu, 2 Feb 2017 15:05:32 +0100
Subject: [PATCH] AutoTest: Make test tree root items checkable

This allows (de)selecting of all test cases of a specific test
framework.

Change-Id: I21357d3dbcfce73387f157b1b40686f437fa260b
Reviewed-by: David Schulz <david.schulz@qt.io>
---
 src/plugins/autotest/gtest/gtesttreeitem.cpp     |  1 +
 src/plugins/autotest/qtest/qttesttreeitem.cpp    |  1 -
 src/plugins/autotest/quick/quicktesttreeitem.cpp |  1 -
 src/plugins/autotest/testtreeitem.cpp            | 15 +++++++++------
 src/plugins/autotest/testtreeitem.h              |  2 ++
 src/plugins/autotest/testtreemodel.cpp           |  8 ++++++++
 src/plugins/autotest/testtreeview.cpp            |  4 ++++
 7 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/src/plugins/autotest/gtest/gtesttreeitem.cpp b/src/plugins/autotest/gtest/gtesttreeitem.cpp
index 5e2766cb30d..b9308a4e737 100644
--- a/src/plugins/autotest/gtest/gtesttreeitem.cpp
+++ b/src/plugins/autotest/gtest/gtesttreeitem.cpp
@@ -57,6 +57,7 @@ QVariant GTestTreeItem::data(int column, int role) const
     }
     case Qt::CheckStateRole:
         switch (type()) {
+        case Root:
         case TestCase:
         case TestFunctionOrSet:
             return checked();
diff --git a/src/plugins/autotest/qtest/qttesttreeitem.cpp b/src/plugins/autotest/qtest/qttesttreeitem.cpp
index 2b4ad6d6c2d..48fa4a9de9e 100644
--- a/src/plugins/autotest/qtest/qttesttreeitem.cpp
+++ b/src/plugins/autotest/qtest/qttesttreeitem.cpp
@@ -49,7 +49,6 @@ QVariant QtTestTreeItem::data(int column, int role) const
         return QVariant(name() + nameSuffix());
     case Qt::CheckStateRole:
         switch (type()) {
-        case Root:
         case TestDataFunction:
         case TestSpecialFunction:
             return QVariant();
diff --git a/src/plugins/autotest/quick/quicktesttreeitem.cpp b/src/plugins/autotest/quick/quicktesttreeitem.cpp
index 5576f97b09f..c4de28c6915 100644
--- a/src/plugins/autotest/quick/quicktesttreeitem.cpp
+++ b/src/plugins/autotest/quick/quicktesttreeitem.cpp
@@ -50,7 +50,6 @@ QVariant QuickTestTreeItem::data(int column, int role) const
         break;
     case Qt::CheckStateRole:
         switch (type()) {
-        case Root:
         case TestDataFunction:
         case TestSpecialFunction:
         case TestDataTag:
diff --git a/src/plugins/autotest/testtreeitem.cpp b/src/plugins/autotest/testtreeitem.cpp
index 7f1992ae583..3bfa4400c5e 100644
--- a/src/plugins/autotest/testtreeitem.cpp
+++ b/src/plugins/autotest/testtreeitem.cpp
@@ -42,7 +42,8 @@ TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type ty
       m_filePath(filePath),
       m_type(type)
 {
-    m_checked = (m_type == TestCase || m_type == TestFunctionOrSet) ? Qt::Checked : Qt::Unchecked;
+    m_checked = (m_type == TestCase || m_type == TestFunctionOrSet || m_type == Root)
+            ? Qt::Checked : Qt::Unchecked;
 }
 
 static QIcon testTreeIcon(TestTreeItem::Type type)
@@ -103,7 +104,7 @@ Qt::ItemFlags TestTreeItem::flags(int /*column*/) const
     static const Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
     switch (m_type) {
     case Root:
-        return Qt::ItemIsEnabled;
+        return Qt::ItemIsEnabled | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
     case TestCase:
         return defaultFlags | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
     case TestFunctionOrSet:
@@ -161,13 +162,14 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState)
             parent->revalidateCheckState();
         break;
     }
+    case Root:
     case TestFunctionOrSet:
     case TestCase: {
         Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked);
         for (int row = 0, count = childCount(); row < count; ++row)
             childItem(row)->setChecked(usedState);
         m_checked = usedState;
-        if (m_type == TestFunctionOrSet) {
+        if (m_type != Root) {
             if (auto parent = parentItem())
                 parent->revalidateCheckState();
         }
@@ -181,6 +183,7 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState)
 Qt::CheckState TestTreeItem::checked() const
 {
     switch (m_type) {
+    case Root:
     case TestCase:
     case TestFunctionOrSet:
     case TestDataTag:
@@ -295,7 +298,7 @@ QSet<QString> TestTreeItem::internalTargets() const
 void TestTreeItem::revalidateCheckState()
 {
     const Type ttiType = type();
-    if (ttiType != TestCase && ttiType != TestFunctionOrSet)
+    if (ttiType != TestCase && ttiType != TestFunctionOrSet && ttiType != Root)
         return;
     if (childCount() == 0) // can this happen? (we're calling revalidateCS() on parentItem()
         return;
@@ -317,13 +320,13 @@ void TestTreeItem::revalidateCheckState()
         foundPartiallyChecked |= (child->checked() == Qt::PartiallyChecked);
         if (foundPartiallyChecked || (foundChecked && foundUnchecked)) {
             m_checked = Qt::PartiallyChecked;
-            if (ttiType == TestFunctionOrSet)
+            if (ttiType == TestFunctionOrSet || ttiType == TestCase)
                 parentItem()->revalidateCheckState();
             return;
         }
     }
     m_checked = (foundUnchecked ? Qt::Unchecked : Qt::Checked);
-    if (ttiType == TestFunctionOrSet)
+    if (ttiType == TestFunctionOrSet || ttiType == TestCase)
         parentItem()->revalidateCheckState();
 }
 
diff --git a/src/plugins/autotest/testtreeitem.h b/src/plugins/autotest/testtreeitem.h
index 530a105e275..2c2c728a2c7 100644
--- a/src/plugins/autotest/testtreeitem.h
+++ b/src/plugins/autotest/testtreeitem.h
@@ -135,6 +135,8 @@ private:
     unsigned m_column = 0;
     QString m_proFile;
     Status m_status = NewlyAdded;
+
+    friend class TestTreeModel; // grant access to (private) revalidateCheckState()
 };
 
 class TestCodeLocationAndType
diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp
index d3cba6c76d1..cd27377b071 100644
--- a/src/plugins/autotest/testtreemodel.cpp
+++ b/src/plugins/autotest/testtreemodel.cpp
@@ -110,6 +110,7 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int
         emit dataChanged(index, index);
         if (role == Qt::CheckStateRole) {
             switch (item->type()) {
+            case TestTreeItem::Root:
             case TestTreeItem::TestCase:
                 if (item->childCount() > 0)
                     emit dataChanged(index.child(0, 0), index.child(item->childCount() - 1, 0));
@@ -228,6 +229,7 @@ bool TestTreeModel::sweepChildren(TestTreeItem *item)
 
         if (child->type() != TestTreeItem::Root && child->markedForRemoval()) {
             destroyItem(child);
+            item->revalidateCheckState();
             hasChanged = true;
         } else if (child->hasChildren()) {
             hasChanged |= sweepChildren(child);
@@ -266,6 +268,12 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
     TestTreeItem *newItem = result->createTestTreeItem();
     QTC_ASSERT(newItem, return);
     parentNode->appendChild(newItem);
+    // new items are checked by default - revalidation of parents might be necessary
+    if (parentNode->checked() != Qt::Checked) {
+        parentNode->revalidateCheckState();
+        const QModelIndex &idx = indexForItem(parentNode);
+        emit dataChanged(idx, idx);
+    }
 }
 
 void TestTreeModel::removeAllTestItems()
diff --git a/src/plugins/autotest/testtreeview.cpp b/src/plugins/autotest/testtreeview.cpp
index 9cd20644f83..a6bbe91b909 100644
--- a/src/plugins/autotest/testtreeview.cpp
+++ b/src/plugins/autotest/testtreeview.cpp
@@ -82,6 +82,10 @@ void TestTreeView::changeCheckStateAll(const Qt::CheckState checkState)
                     item->setChecked(checkState);
             }
         }
+        if (count == 0) {
+            if (auto item = static_cast<TestTreeItem *>(currentRootIndex.internalPointer()))
+                item->setChecked(checkState);
+        }
         emit dataChanged(currentRootIndex, last);
     }
 }
-- 
GitLab