diff --git a/src/plugins/autotest/testnavigationwidget.cpp b/src/plugins/autotest/testnavigationwidget.cpp index 9ccb70df42e..344dc938e9b 100644 --- a/src/plugins/autotest/testnavigationwidget.cpp +++ b/src/plugins/autotest/testnavigationwidget.cpp @@ -200,11 +200,11 @@ void TestNavigationWidget::onSortClicked() if (m_sortAlphabetically) { m_sort->setIcon(Icons::SORT_ALPHABETICALLY.icon()); m_sort->setToolTip(tr("Sort Alphabetically")); - m_sortFilterModel->setSortMode(TestTreeSortFilterModel::Naturally); + m_sortFilterModel->setSortMode(TestTreeItem::Naturally); } else { m_sort->setIcon(Icons::SORT_NATURALLY.icon()); m_sort->setToolTip(tr("Sort Naturally")); - m_sortFilterModel->setSortMode(TestTreeSortFilterModel::Alphabetically); + m_sortFilterModel->setSortMode(TestTreeItem::Alphabetically); } m_sortAlphabetically = !m_sortAlphabetically; } diff --git a/src/plugins/autotest/testtreeitem.cpp b/src/plugins/autotest/testtreeitem.cpp index 50d62c4d35d..a95866c180b 100644 --- a/src/plugins/autotest/testtreeitem.cpp +++ b/src/plugins/autotest/testtreeitem.cpp @@ -102,6 +102,24 @@ bool TestTreeItem::setData(int /*column*/, const QVariant &data, int role) return false; } +Qt::ItemFlags TestTreeItem::flags(int /*column*/) const +{ + static const Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + switch (m_type) { + case Root: + return Qt::ItemIsEnabled; + case TestCase: + return defaultFlags | Qt::ItemIsTristate | Qt::ItemIsUserCheckable; + case TestFunctionOrSet: + return defaultFlags | Qt::ItemIsUserCheckable; + case TestDataFunction: + case TestSpecialFunction: + case TestDataTag: + default: + return defaultFlags; + } +} + bool TestTreeItem::modifyTestCaseContent(const QString &name, unsigned line, unsigned column) { bool hasBeenModified = modifyName(name); @@ -186,6 +204,18 @@ void TestTreeItem::markForRemovalRecursively(bool mark) childItem(row)->markForRemovalRecursively(mark); } +void TestTreeItem::markForRemovalRecursively(const QString &filePath) +{ + if (m_filePath == filePath) { + markForRemovalRecursively(true); + } else { + for (int row = 0, count = childCount(); row < count; ++row) { + TestTreeItem *child = childItem(row); + child->markForRemovalRecursively(filePath); + } + } +} + TestTreeItem *TestTreeItem::parentItem() const { return static_cast(parent()); @@ -227,6 +257,33 @@ QList TestTreeItem::getSelectedTestConfigurations() const return QList(); } +bool TestTreeItem::lessThan(const TestTreeItem *other, SortMode mode) const +{ + const QString &lhs = data(0, Qt::DisplayRole).toString(); + const QString &rhs = other->data(0, Qt::DisplayRole).toString(); + + switch (mode) { + case Alphabetically: + if (lhs == rhs) + return index().row() > other->index().row(); + return lhs > rhs; + case Naturally: { + const TextEditor::TextEditorWidget::Link &leftLink = + data(0, LinkRole).value(); + const TextEditor::TextEditorWidget::Link &rightLink = + other->data(0, LinkRole).value(); + if (leftLink.targetFileName == rightLink.targetFileName) { + return leftLink.targetLine == rightLink.targetLine + ? leftLink.targetColumn > rightLink.targetColumn + : leftLink.targetLine > rightLink.targetLine; + } + return leftLink.targetFileName > rightLink.targetFileName; + } + default: + return true; + } +} + void TestTreeItem::revalidateCheckState() { if (childCount() == 0) @@ -555,6 +612,23 @@ QVariant QuickTestTreeItem::data(int column, int role) const return TestTreeItem::data(column, role); } +Qt::ItemFlags QuickTestTreeItem::flags(int column) const +{ + // handle unnamed quick tests and their functions + switch (type()) { + case TestCase: + if (name().isEmpty()) + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + break; + case TestFunctionOrSet: + if (parentItem()->name().isEmpty()) + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + break; + default: {} // avoid warning regarding unhandled enum values + } + return TestTreeItem::flags(column); +} + bool QuickTestTreeItem::canProvideTestConfiguration() const { switch (type()) { @@ -718,6 +792,16 @@ QList QuickTestTreeItem::getSelectedTestConfigurations() co return result; } +bool QuickTestTreeItem::lessThan(const TestTreeItem *other, TestTreeItem::SortMode mode) const +{ + // handle special item () + if (name().isEmpty()) + return false; + if (other->name().isEmpty()) + return true; + return TestTreeItem::lessThan(other, mode); +} + TestTreeItem *QuickTestTreeItem::unnamedQuickTests() const { if (type() != Root) diff --git a/src/plugins/autotest/testtreeitem.h b/src/plugins/autotest/testtreeitem.h index 44524e7bc53..70a2fbc4381 100644 --- a/src/plugins/autotest/testtreeitem.h +++ b/src/plugins/autotest/testtreeitem.h @@ -52,7 +52,6 @@ class TestConfiguration; class TestTreeItem : public Utils::TreeItem { - public: enum Type { @@ -64,11 +63,17 @@ public: TestSpecialFunction }; + enum SortMode { + Alphabetically, + Naturally + }; + TestTreeItem(const QString &name = QString(), const QString &filePath = QString(), Type type = Root); virtual QVariant data(int column, int role) const override; virtual bool setData(int column, const QVariant &data, int role) override; + virtual Qt::ItemFlags flags(int column) const override; bool modifyTestCaseContent(const QString &name, unsigned line, unsigned column); bool modifyTestFunctionContent(const TestCodeLocationAndType &location); bool modifyDataTagContent(const QString &fileName, const TestCodeLocationAndType &location); @@ -90,6 +95,7 @@ public: Type type() const { return m_type; } void markForRemoval(bool mark); void markForRemovalRecursively(bool mark); + virtual void markForRemovalRecursively(const QString &filePath); bool markedForRemoval() const { return m_status == MarkedForRemoval; } bool newlyAdded() const { return m_status == NewlyAdded; } TestTreeItem *parentItem() const; @@ -103,6 +109,7 @@ public: virtual TestConfiguration *testConfiguration() const { return 0; } virtual QList getAllTestConfigurations() const; virtual QList getSelectedTestConfigurations() const; + virtual bool lessThan(const TestTreeItem *other, SortMode mode) const; protected: bool modifyFilePath(const QString &filePath); @@ -166,10 +173,12 @@ public: const TestParseResult &result); QVariant data(int column, int role) const override; + Qt::ItemFlags flags(int column) const override; bool canProvideTestConfiguration() const override; TestConfiguration *testConfiguration() const override; QList getAllTestConfigurations() const override; QList getSelectedTestConfigurations() const override; + bool lessThan(const TestTreeItem *other, SortMode mode) const override; private: TestTreeItem *unnamedQuickTests() const; diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp index 209326a497e..9d85d4b9840 100644 --- a/src/plugins/autotest/testtreemodel.cpp +++ b/src/plugins/autotest/testtreemodel.cpp @@ -160,23 +160,7 @@ Qt::ItemFlags TestTreeModel::flags(const QModelIndex &index) const return Qt::ItemIsEnabled | Qt::ItemIsSelectable; TestTreeItem *item = static_cast(itemForIndex(index)); - switch(item->type()) { - case TestTreeItem::TestCase: - if (item->name().isEmpty()) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsTristate | Qt::ItemIsUserCheckable; - case TestTreeItem::TestFunctionOrSet: - if (item->parentItem()->name().isEmpty()) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; - case TestTreeItem::Root: - return Qt::ItemIsEnabled; - case TestTreeItem::TestDataFunction: - case TestTreeItem::TestSpecialFunction: - case TestTreeItem::TestDataTag: - default: - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; - } + return item->flags(index.column()); } bool TestTreeModel::hasTests() const @@ -257,19 +241,7 @@ void TestTreeModel::markForRemoval(const QString &filePath) TestTreeItem *root = rootItemForType(type); for (int childRow = root->childCount() - 1; childRow >= 0; --childRow) { TestTreeItem *child = root->childItem(childRow); - // Qt + named Quick Tests - if (child->filePath() == filePath) { - child->markForRemovalRecursively(true); - } else { - // unnamed Quick Tests and GTest and Qt Tests with separated source/header - int grandChildRow = child->childCount() - 1; - for ( ; grandChildRow >= 0; --grandChildRow) { - TestTreeItem *grandChild = child->childItem(grandChildRow); - if (grandChild->filePath() == filePath) { - grandChild->markForRemovalRecursively(true); - } - } - } + child->markForRemovalRecursively(filePath); } } } @@ -573,13 +545,13 @@ QMultiMap TestTreeModel::gtestNamesAndSets() const TestTreeSortFilterModel::TestTreeSortFilterModel(TestTreeModel *sourceModel, QObject *parent) : QSortFilterProxyModel(parent), m_sourceModel(sourceModel), - m_sortMode(Alphabetically), + m_sortMode(TestTreeItem::Alphabetically), m_filterMode(Basic) { setSourceModel(sourceModel); } -void TestTreeSortFilterModel::setSortMode(SortMode sortMode) +void TestTreeSortFilterModel::setSortMode(TestTreeItem::SortMode sortMode) { m_sortMode = sortMode; invalidate(); @@ -613,42 +585,13 @@ TestTreeSortFilterModel::FilterMode TestTreeSortFilterModel::toFilterMode(int f) bool TestTreeSortFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { - // root items keep the intended order: 1st Auto Tests, 2nd Quick Tests + // root items keep the intended order const TestTreeItem *leftItem = static_cast(left.internalPointer()); if (leftItem->type() == TestTreeItem::Root) return left.row() > right.row(); - const QString leftVal = m_sourceModel->data(left, Qt::DisplayRole).toString(); - const QString rightVal = m_sourceModel->data(right, Qt::DisplayRole).toString(); - - // unnamed Quick Tests will always be listed first - if (leftVal == tr(Constants::UNNAMED_QUICKTESTS)) - return false; - if (rightVal == tr(Constants::UNNAMED_QUICKTESTS)) - return true; - - switch (m_sortMode) { - case Alphabetically: - if (leftVal == rightVal) - return left.row() > right.row(); - return leftVal > rightVal; - case Naturally: { - const TextEditor::TextEditorWidget::Link leftLink = - m_sourceModel->data(left, LinkRole).value(); - const TextEditor::TextEditorWidget::Link rightLink = - m_sourceModel->data(right, LinkRole).value(); - - if (leftLink.targetFileName == rightLink.targetFileName) { - return leftLink.targetLine == rightLink.targetLine - ? leftLink.targetColumn > rightLink.targetColumn - : leftLink.targetLine > rightLink.targetLine; - } else { - return leftLink.targetFileName > rightLink.targetFileName; - } - } - default: - return true; - } + const TestTreeItem *rightItem = static_cast(right.internalPointer()); + return leftItem->lessThan(rightItem, m_sortMode); } bool TestTreeSortFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const diff --git a/src/plugins/autotest/testtreemodel.h b/src/plugins/autotest/testtreemodel.h index 15a1591d54b..a87fd78f567 100644 --- a/src/plugins/autotest/testtreemodel.h +++ b/src/plugins/autotest/testtreemodel.h @@ -100,7 +100,6 @@ private: void handleGTestParseResult(const TestParseResultPtr result); void removeAllTestItems(); void removeFiles(const QStringList &files); - void markForRemoval(const QString &filePath, Type type); bool sweepChildren(TestTreeItem *item); TestTreeItem *unnamedQuickTests() const; @@ -121,11 +120,6 @@ class TestTreeSortFilterModel : public QSortFilterProxyModel { Q_OBJECT public: - enum SortMode { - Alphabetically, - Naturally - }; - enum FilterMode { Basic, ShowInitAndCleanup = 0x01, @@ -134,7 +128,7 @@ public: }; TestTreeSortFilterModel(TestTreeModel *sourceModel, QObject *parent = 0); - void setSortMode(SortMode sortMode); + void setSortMode(TestTreeItem::SortMode sortMode); void setFilterMode(FilterMode filterMode); void toggleFilter(FilterMode filterMode); static FilterMode toFilterMode(int f); @@ -145,7 +139,7 @@ protected: private: TestTreeModel *m_sourceModel; - SortMode m_sortMode; + TestTreeItem::SortMode m_sortMode; FilterMode m_filterMode; };