forked from qt-creator/qt-creator
Support sorting of test tree
Additionally preparation of filtering has been done.
This commit is contained in:
committed by
Christian Stenger
parent
0357b0e98b
commit
9a644d1257
@@ -19,6 +19,8 @@
|
|||||||
#ifndef AUTOTESTCONSTANTS_H
|
#ifndef AUTOTESTCONSTANTS_H
|
||||||
#define AUTOTESTCONSTANTS_H
|
#define AUTOTESTCONSTANTS_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
namespace Autotest {
|
namespace Autotest {
|
||||||
namespace Constants {
|
namespace Constants {
|
||||||
|
|
||||||
@@ -27,6 +29,7 @@ const char MENU_ID[] = "AutoTest.Menu";
|
|||||||
const char AUTOTEST_ID[] = "AutoTest.ATP";
|
const char AUTOTEST_ID[] = "AutoTest.ATP";
|
||||||
const char AUTOTEST_CONTEXT[] = "Auto Tests";
|
const char AUTOTEST_CONTEXT[] = "Auto Tests";
|
||||||
const char TASK_INDEX[] = "AutoTest.Task.Index";
|
const char TASK_INDEX[] = "AutoTest.Task.Index";
|
||||||
|
const char UNNAMED_QUICKTESTS[] = QT_TR_NOOP("<unnamed>");
|
||||||
|
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
} // namespace Constants
|
} // namespace Constants
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "autotestconstants.h"
|
||||||
#include "testcodeparser.h"
|
#include "testcodeparser.h"
|
||||||
#include "testinfo.h"
|
#include "testinfo.h"
|
||||||
#include "testtreeitem.h"
|
#include "testtreeitem.h"
|
||||||
@@ -385,51 +386,60 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr doc)
|
|||||||
m_model->removeQuickTestSubtreeByFilePath(d->fileName());
|
m_model->removeQuickTestSubtreeByFilePath(d->fileName());
|
||||||
m_quickDocMap.remove(d->fileName());
|
m_quickDocMap.remove(d->fileName());
|
||||||
}
|
}
|
||||||
bool hadUnnamedTestsBefore;
|
TestTreeItem *unnamedQTItem = m_model->unnamedQuickTests();
|
||||||
TestTreeItem *ttItem = m_model->unnamedQuickTests();
|
if (unnamedQTItem) {
|
||||||
if (!ttItem) {
|
|
||||||
hadUnnamedTestsBefore = false;
|
|
||||||
ttItem = new TestTreeItem(QString(), QString(), TestTreeItem::TEST_CLASS,
|
|
||||||
quickTestRootItem);
|
|
||||||
foreach (const QString &func, testFunctions.keys()) {
|
|
||||||
const TestCodeLocation location = testFunctions.value(func);
|
|
||||||
TestTreeItem *ttSub = new TestTreeItem(func, location.m_fileName,
|
|
||||||
TestTreeItem::TEST_FUNCTION, ttItem);
|
|
||||||
ttSub->setLine(location.m_line);
|
|
||||||
ttSub->setColumn(location.m_column);
|
|
||||||
ttSub->setMainFile(doc->fileName());
|
|
||||||
ttItem->appendChild(ttSub);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hadUnnamedTestsBefore = true;
|
|
||||||
// remove unnamed quick tests that are already found for this qml file
|
// remove unnamed quick tests that are already found for this qml file
|
||||||
m_model->removeUnnamedQuickTest(d->fileName());
|
if (m_model->removeUnnamedQuickTests(d->fileName())) {
|
||||||
|
// make sure m_quickDocMap does not have a inconsistent state now
|
||||||
foreach (const QString &func, testFunctions.keys()) {
|
TestInfo ti = m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)];
|
||||||
const TestCodeLocation location = testFunctions.value(func);
|
QStringList tiFunctions = ti.testFunctions();
|
||||||
TestTreeItem *ttSub = new TestTreeItem(func, location.m_fileName,
|
foreach (const QString &func, testFunctions.keys())
|
||||||
TestTreeItem::TEST_FUNCTION, ttItem);
|
tiFunctions.removeOne(func);
|
||||||
ttSub->setLine(location.m_line);
|
ti.setTestFunctions(tiFunctions);
|
||||||
ttSub->setColumn(location.m_column);
|
if (tiFunctions.size() == 0)
|
||||||
ttSub->setMainFile(doc->fileName());
|
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
||||||
ttItem->appendChild(ttSub);
|
else
|
||||||
|
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), ti);
|
||||||
|
}
|
||||||
|
// as removeUnnamedQuickTests() could delete this item itself try to get it again
|
||||||
|
unnamedQTItem = m_model->unnamedQuickTests();
|
||||||
|
}
|
||||||
|
// construct new/modified TestTreeItem
|
||||||
|
TestTreeItem *ttItem = new TestTreeItem(QString(), QString(),
|
||||||
|
TestTreeItem::TEST_CLASS,
|
||||||
|
quickTestRootItem);
|
||||||
|
if (unnamedQTItem) {
|
||||||
|
for (int i = 0, count = unnamedQTItem->childCount(); i < count; ++i) {
|
||||||
|
TestTreeItem *child = new TestTreeItem(*unnamedQTItem->child(i));
|
||||||
|
child->setParent(ttItem);
|
||||||
|
ttItem->appendChild(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TestInfo info = m_quickDocMap.contains(QLatin1String("<unnamed>"))
|
|
||||||
? m_quickDocMap[QLatin1String("<unnamed>")]
|
foreach (const QString &func, testFunctions.keys()) {
|
||||||
|
const TestCodeLocation location = testFunctions.value(func);
|
||||||
|
TestTreeItem *ttSub = new TestTreeItem(func, location.m_fileName,
|
||||||
|
TestTreeItem::TEST_FUNCTION, ttItem);
|
||||||
|
ttSub->setLine(location.m_line);
|
||||||
|
ttSub->setColumn(location.m_column);
|
||||||
|
ttSub->setMainFile(doc->fileName());
|
||||||
|
ttItem->appendChild(ttSub);
|
||||||
|
}
|
||||||
|
TestInfo info = m_quickDocMap.contains(tr(Constants::UNNAMED_QUICKTESTS))
|
||||||
|
? m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)]
|
||||||
: TestInfo(QString(), QStringList(), 666);
|
: TestInfo(QString(), QStringList(), 666);
|
||||||
QStringList originalFunctions(info.testFunctions());
|
QStringList originalFunctions(info.testFunctions());
|
||||||
foreach (const QString &func, testFunctions.keys()) {
|
foreach (const QString &func, testFunctions.keys())
|
||||||
if (!originalFunctions.contains(func))
|
originalFunctions.append(func);
|
||||||
originalFunctions.append(func);
|
|
||||||
}
|
|
||||||
info.setTestFunctions(originalFunctions);
|
info.setTestFunctions(originalFunctions);
|
||||||
|
|
||||||
if (hadUnnamedTestsBefore)
|
if (unnamedQTItem) {
|
||||||
m_model->modifyQuickTestSubtree(ttItem->row(), ttItem);
|
m_model->modifyQuickTestSubtree(unnamedQTItem->row(), ttItem);
|
||||||
else
|
delete ttItem;
|
||||||
|
} else {
|
||||||
m_model->addQuickTest(ttItem);
|
m_model->addQuickTest(ttItem);
|
||||||
m_quickDocMap.insert(QLatin1String("<unnamed>"), info);
|
}
|
||||||
|
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), info);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} // end of handling test cases without name property
|
} // end of handling test cases without name property
|
||||||
@@ -468,15 +478,20 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr doc)
|
|||||||
delete ttItem;
|
delete ttItem;
|
||||||
} else {
|
} else {
|
||||||
// if it was formerly unnamed remove the respective items
|
// if it was formerly unnamed remove the respective items
|
||||||
if (m_quickDocMap.contains(QLatin1String("<unnamed>"))) {
|
if (m_quickDocMap.contains(tr(Constants::UNNAMED_QUICKTESTS))) {
|
||||||
m_model->removeUnnamedQuickTest(d->fileName());
|
if (m_model->removeUnnamedQuickTests(d->fileName())) {
|
||||||
TestInfo unnamedInfo = m_quickDocMap[QLatin1String("<unnamed>")];
|
// make sure m_quickDocMap does not have a inconsistent state now
|
||||||
QStringList functions = unnamedInfo.testFunctions();
|
TestInfo unnamedInfo = m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)];
|
||||||
foreach (const QString &func, testFunctions.keys())
|
QStringList functions = unnamedInfo.testFunctions();
|
||||||
if (functions.contains(func))
|
foreach (const QString &func, testFunctions.keys())
|
||||||
functions.removeOne(func);
|
if (functions.contains(func))
|
||||||
unnamedInfo.setTestFunctions(functions);
|
functions.removeOne(func);
|
||||||
m_quickDocMap.insert(QLatin1String("<unnamed>"), unnamedInfo);
|
unnamedInfo.setTestFunctions(functions);
|
||||||
|
if (functions.size() == 0)
|
||||||
|
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
||||||
|
else
|
||||||
|
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), unnamedInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_model->addQuickTest(ttItem);
|
m_model->addQuickTest(ttItem);
|
||||||
@@ -523,7 +538,7 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &doc)
|
|||||||
&& snapshot.contains(m_quickDocMap[fileName].referencingFile())) {
|
&& snapshot.contains(m_quickDocMap[fileName].referencingFile())) {
|
||||||
checkDocumentForTestCode(snapshot.document(m_quickDocMap[fileName].referencingFile()));
|
checkDocumentForTestCode(snapshot.document(m_quickDocMap[fileName].referencingFile()));
|
||||||
}
|
}
|
||||||
if (!m_quickDocMap.contains(QLatin1String("<unnamed>")))
|
if (!m_quickDocMap.contains(tr(Constants::UNNAMED_QUICKTESTS)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// special case of having unnamed TestCases
|
// special case of having unnamed TestCases
|
||||||
|
|||||||
@@ -55,18 +55,53 @@ ResultType TestResult::resultFromString(const QString &resultString)
|
|||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultType TestResult::toResultType(int rt)
|
||||||
|
{
|
||||||
|
switch(rt) {
|
||||||
|
case PASS:
|
||||||
|
return PASS;
|
||||||
|
case FAIL:
|
||||||
|
return FAIL;
|
||||||
|
case EXPECTED_FAIL:
|
||||||
|
return EXPECTED_FAIL;
|
||||||
|
case UNEXPECTED_PASS:
|
||||||
|
return UNEXPECTED_PASS;
|
||||||
|
case SKIP:
|
||||||
|
return SKIP;
|
||||||
|
case MESSAGE_DEBUG:
|
||||||
|
return MESSAGE_DEBUG;
|
||||||
|
case MESSAGE_WARN:
|
||||||
|
return MESSAGE_WARN;
|
||||||
|
case MESSAGE_FATAL:
|
||||||
|
return MESSAGE_FATAL;
|
||||||
|
case MESSAGE_INTERNAL:
|
||||||
|
return MESSAGE_INTERNAL;
|
||||||
|
default:
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString TestResult::resultToString(const ResultType type)
|
QString TestResult::resultToString(const ResultType type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PASS: return QLatin1String("PASS");
|
case PASS:
|
||||||
case FAIL: return QLatin1String("FAIL");
|
return QLatin1String("PASS");
|
||||||
case EXPECTED_FAIL: return QLatin1String("XFAIL");
|
case FAIL:
|
||||||
case UNEXPECTED_PASS: return QLatin1String("XPASS");
|
return QLatin1String("FAIL");
|
||||||
case SKIP: return QLatin1String("SKIP");
|
case EXPECTED_FAIL:
|
||||||
case MESSAGE_DEBUG: return QLatin1String("DEBUG");
|
return QLatin1String("XFAIL");
|
||||||
case MESSAGE_WARN: return QLatin1String("WARN");
|
case UNEXPECTED_PASS:
|
||||||
case MESSAGE_FATAL: return QLatin1String("FATAL");
|
return QLatin1String("XPASS");
|
||||||
case MESSAGE_INTERNAL: return QString();
|
case SKIP:
|
||||||
|
return QLatin1String("SKIP");
|
||||||
|
case MESSAGE_DEBUG:
|
||||||
|
return QLatin1String("DEBUG");
|
||||||
|
case MESSAGE_WARN:
|
||||||
|
return QLatin1String("WARN");
|
||||||
|
case MESSAGE_FATAL:
|
||||||
|
return QLatin1String("FATAL");
|
||||||
|
case MESSAGE_INTERNAL:
|
||||||
|
return QString();
|
||||||
default:
|
default:
|
||||||
return QLatin1String("UNKNOWN");
|
return QLatin1String("UNKNOWN");
|
||||||
}
|
}
|
||||||
@@ -75,15 +110,24 @@ QString TestResult::resultToString(const ResultType type)
|
|||||||
QColor TestResult::colorForType(const ResultType type)
|
QColor TestResult::colorForType(const ResultType type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PASS: return QColor("#009900");
|
case PASS:
|
||||||
case FAIL: return QColor("#a00000");
|
return QColor("#009900");
|
||||||
case EXPECTED_FAIL: return QColor("#00ff00");
|
case FAIL:
|
||||||
case UNEXPECTED_PASS: return QColor("#ff0000");
|
return QColor("#a00000");
|
||||||
case SKIP: return QColor("#787878");
|
case EXPECTED_FAIL:
|
||||||
case MESSAGE_DEBUG: return QColor("#329696");
|
return QColor("#00ff00");
|
||||||
case MESSAGE_WARN: return QColor("#d0bb00");
|
case UNEXPECTED_PASS:
|
||||||
case MESSAGE_FATAL: return QColor("#640000");
|
return QColor("#ff0000");
|
||||||
case MESSAGE_INTERNAL: return QColor("transparent");
|
case SKIP:
|
||||||
|
return QColor("#787878");
|
||||||
|
case MESSAGE_DEBUG:
|
||||||
|
return QColor("#329696");
|
||||||
|
case MESSAGE_WARN:
|
||||||
|
return QColor("#d0bb00");
|
||||||
|
case MESSAGE_FATAL:
|
||||||
|
return QColor("#640000");
|
||||||
|
case MESSAGE_INTERNAL:
|
||||||
|
return QColor("transparent");
|
||||||
default:
|
default:
|
||||||
return QColor("#000000");
|
return QColor("#000000");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public:
|
|||||||
void setLine(int line) { m_line = line; }
|
void setLine(int line) { m_line = line; }
|
||||||
|
|
||||||
static ResultType resultFromString(const QString &resultString);
|
static ResultType resultFromString(const QString &resultString);
|
||||||
|
static ResultType toResultType(int rt);
|
||||||
static QString resultToString(const ResultType type);
|
static QString resultToString(const ResultType type);
|
||||||
static QColor colorForType(const ResultType type);
|
static QColor colorForType(const ResultType type);
|
||||||
|
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ void TestResultsPane::updateFilterMenu()
|
|||||||
foreach (QAction *action, m_filterMenu->actions()) {
|
foreach (QAction *action, m_filterMenu->actions()) {
|
||||||
if (action->isCheckable())
|
if (action->isCheckable())
|
||||||
action->setEnabled(m_model->hasResultType(
|
action->setEnabled(m_model->hasResultType(
|
||||||
static_cast<ResultType>(action->data().value<int>())));
|
TestResult::toResultType(action->data().value<int>())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +337,7 @@ void TestResultsPane::enableAllFilter()
|
|||||||
|
|
||||||
void TestResultsPane::filterMenuTriggered(QAction *action)
|
void TestResultsPane::filterMenuTriggered(QAction *action)
|
||||||
{
|
{
|
||||||
m_filterModel->toggleTestResultType(static_cast<ResultType>(action->data().value<int>()));
|
m_filterModel->toggleTestResultType(TestResult::toResultType(action->data().value<int>()));
|
||||||
navigateStateChanged();
|
navigateStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,23 @@ TestTreeItem::~TestTreeItem()
|
|||||||
removeChildren();
|
removeChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestTreeItem::TestTreeItem(const TestTreeItem &other)
|
||||||
|
: m_name(other.m_name),
|
||||||
|
m_filePath(other.m_filePath),
|
||||||
|
m_checked(other.m_checked),
|
||||||
|
m_type(other.m_type),
|
||||||
|
m_line(other.m_line),
|
||||||
|
m_column(other.m_column),
|
||||||
|
m_mainFile(other.m_mainFile),
|
||||||
|
m_parent(other.m_parent)
|
||||||
|
{
|
||||||
|
foreach (const TestTreeItem *child, other.m_children) {
|
||||||
|
TestTreeItem *reparentedChild = new TestTreeItem(*child);
|
||||||
|
reparentedChild->m_parent = this;
|
||||||
|
m_children.append(reparentedChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TestTreeItem *TestTreeItem::child(int row)
|
TestTreeItem *TestTreeItem::child(int row)
|
||||||
{
|
{
|
||||||
return m_children.at(row);
|
return m_children.at(row);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public:
|
|||||||
|
|
||||||
TestTreeItem(const QString &name, const QString &filePath, Type type, TestTreeItem *parent = 0);
|
TestTreeItem(const QString &name, const QString &filePath, Type type, TestTreeItem *parent = 0);
|
||||||
virtual ~TestTreeItem();
|
virtual ~TestTreeItem();
|
||||||
|
TestTreeItem(const TestTreeItem& other);
|
||||||
|
|
||||||
TestTreeItem *child(int row);
|
TestTreeItem *child(int row);
|
||||||
TestTreeItem *parent() const;
|
TestTreeItem *parent() const;
|
||||||
@@ -58,6 +59,7 @@ public:
|
|||||||
void setChecked(const Qt::CheckState checked);
|
void setChecked(const Qt::CheckState checked);
|
||||||
Qt::CheckState checked() const { return m_checked; }
|
Qt::CheckState checked() const { return m_checked; }
|
||||||
Type type() const { return m_type; }
|
Type type() const { return m_type; }
|
||||||
|
void setParent(TestTreeItem *parent) { m_parent = parent; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void revalidateCheckState();
|
void revalidateCheckState();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "autotestconstants.h"
|
||||||
#include "testcodeparser.h"
|
#include "testcodeparser.h"
|
||||||
#include "testtreeitem.h"
|
#include "testtreeitem.h"
|
||||||
#include "testtreemodel.h"
|
#include "testtreemodel.h"
|
||||||
@@ -152,7 +153,7 @@ QVariant TestTreeModel::data(const QModelIndex &index, int role) const
|
|||||||
return QString(item->name() + tr(" (none)"));
|
return QString(item->name() + tr(" (none)"));
|
||||||
} else {
|
} else {
|
||||||
if (item->name().isEmpty())
|
if (item->name().isEmpty())
|
||||||
return tr("<unnamed>");
|
return tr(Constants::UNNAMED_QUICKTESTS);
|
||||||
return item->name();
|
return item->name();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -535,19 +536,24 @@ void TestTreeModel::removeAllQuickTests()
|
|||||||
emit testTreeModelChanged();
|
emit testTreeModelChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestTreeModel::removeUnnamedQuickTest(const QString &filePath)
|
bool TestTreeModel::removeUnnamedQuickTests(const QString &filePath)
|
||||||
{
|
{
|
||||||
TestTreeItem *unnamedQT = unnamedQuickTests();
|
TestTreeItem *unnamedQT = unnamedQuickTests();
|
||||||
if (!unnamedQT)
|
if (!unnamedQT)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
|
bool removed = false;
|
||||||
const QModelIndex unnamedQTIndex = index(1, 0).child(unnamedQT->row(), 0);
|
const QModelIndex unnamedQTIndex = index(1, 0).child(unnamedQT->row(), 0);
|
||||||
for (int childRow = unnamedQT->childCount() - 1; childRow >= 0; --childRow) {
|
for (int childRow = unnamedQT->childCount() - 1; childRow >= 0; --childRow) {
|
||||||
const TestTreeItem *child = unnamedQT->child(childRow);
|
const TestTreeItem *child = unnamedQT->child(childRow);
|
||||||
if (filePath == child->filePath())
|
if (filePath == child->filePath())
|
||||||
removeRow(childRow, unnamedQTIndex);
|
removed |= removeRow(childRow, unnamedQTIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unnamedQT->childCount() == 0)
|
||||||
|
removeRow(unnamedQT->row(), unnamedQTIndex.parent());
|
||||||
emit testTreeModelChanged();
|
emit testTreeModelChanged();
|
||||||
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeItem *newItem)
|
void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeItem *newItem)
|
||||||
@@ -566,6 +572,7 @@ void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeIt
|
|||||||
const int newChildCount = newItem->childCount();
|
const int newChildCount = newItem->childCount();
|
||||||
|
|
||||||
// for keeping the CheckState on modifications
|
// for keeping the CheckState on modifications
|
||||||
|
// TODO might still fail for duplicate entries (e.g. unnamed Quick Tests)
|
||||||
QHash<QString, Qt::CheckState> originalItems;
|
QHash<QString, Qt::CheckState> originalItems;
|
||||||
for (int row = 0; row < childCount; ++row) {
|
for (int row = 0; row < childCount; ++row) {
|
||||||
const TestTreeItem *child = toBeModifiedItem->child(row);
|
const TestTreeItem *child = toBeModifiedItem->child(row);
|
||||||
@@ -594,9 +601,8 @@ void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeIt
|
|||||||
if (childCount < newChildCount) { // add aditional items
|
if (childCount < newChildCount) { // add aditional items
|
||||||
for (int row = childCount; row < newChildCount; ++row) {
|
for (int row = childCount; row < newChildCount; ++row) {
|
||||||
TestTreeItem *newChild = newItem->child(row);
|
TestTreeItem *newChild = newItem->child(row);
|
||||||
TestTreeItem *toBeAdded = new TestTreeItem(newChild->name(), newChild->filePath(),
|
TestTreeItem *toBeAdded = new TestTreeItem(*newChild);
|
||||||
newChild->type(), toBeModifiedItem);
|
toBeAdded->setParent(toBeModifiedItem);
|
||||||
toBeAdded->setLine(newChild->line());
|
|
||||||
beginInsertRows(toBeModifiedIndex, row, row);
|
beginInsertRows(toBeModifiedIndex, row, row);
|
||||||
toBeModifiedItem->appendChild(toBeAdded);
|
toBeModifiedItem->appendChild(toBeAdded);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
@@ -628,5 +634,97 @@ void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeIt
|
|||||||
emit testTreeModelChanged();
|
emit testTreeModelChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************** Sort/Filter Model **********************************/
|
||||||
|
|
||||||
|
TestTreeSortFilterModel::TestTreeSortFilterModel(TestTreeModel *sourceModel, QObject *parent)
|
||||||
|
: QSortFilterProxyModel(parent),
|
||||||
|
m_sourceModel(sourceModel),
|
||||||
|
m_sortMode(Alphabetically),
|
||||||
|
m_filterMode(Basic)
|
||||||
|
{
|
||||||
|
setSourceModel(sourceModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeSortFilterModel::setSortMode(SortMode sortMode)
|
||||||
|
{
|
||||||
|
m_sortMode = sortMode;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeSortFilterModel::setFilterMode(FilterMode filterMode)
|
||||||
|
{
|
||||||
|
m_filterMode = filterMode;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeSortFilterModel::toggleFilter(FilterMode filterMode)
|
||||||
|
{
|
||||||
|
m_filterMode = toFilterMode(m_filterMode ^ filterMode);
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
TestTreeSortFilterModel::FilterMode TestTreeSortFilterModel::toFilterMode(int f)
|
||||||
|
{
|
||||||
|
switch (f) {
|
||||||
|
case TestTreeSortFilterModel::ShowInitAndCleanup:
|
||||||
|
return TestTreeSortFilterModel::ShowInitAndCleanup;
|
||||||
|
case TestTreeSortFilterModel::ShowTestData:
|
||||||
|
return TestTreeSortFilterModel::ShowTestData;
|
||||||
|
case TestTreeSortFilterModel::ShowAll:
|
||||||
|
return TestTreeSortFilterModel::ShowAll;
|
||||||
|
default:
|
||||||
|
return TestTreeSortFilterModel::Basic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestTreeSortFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||||
|
{
|
||||||
|
// root items keep the intended order: 1st Auto Tests, 2nd Quick Tests
|
||||||
|
const TestTreeItem *leftItem = static_cast<TestTreeItem *>(left.internalPointer());
|
||||||
|
if (leftItem->type() == TestTreeItem::ROOT)
|
||||||
|
return left.row() > right.row();
|
||||||
|
|
||||||
|
const QString leftVal = m_sourceModel->data(left).toString();
|
||||||
|
const QString rightVal = m_sourceModel->data(right).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:
|
||||||
|
return leftVal > rightVal;
|
||||||
|
case Naturally: {
|
||||||
|
const TextEditor::TextEditorWidget::Link leftLink =
|
||||||
|
m_sourceModel->data(left, LinkRole).value<TextEditor::TextEditorWidget::Link>();
|
||||||
|
const TextEditor::TextEditorWidget::Link rightLink =
|
||||||
|
m_sourceModel->data(right, LinkRole).value<TextEditor::TextEditorWidget::Link>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestTreeSortFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||||
|
{
|
||||||
|
// TODO add filtering capabilities
|
||||||
|
QModelIndex index = m_sourceModel->index(sourceRow, 0,sourceParent);
|
||||||
|
if (!index.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <cplusplus/CppDocument.h>
|
#include <cplusplus/CppDocument.h>
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
enum ItemRole {
|
enum ItemRole {
|
||||||
@@ -71,7 +72,7 @@ public:
|
|||||||
void removeQuickTestSubtreeByFilePath(const QString &file);
|
void removeQuickTestSubtreeByFilePath(const QString &file);
|
||||||
void addQuickTest(TestTreeItem *newItem);
|
void addQuickTest(TestTreeItem *newItem);
|
||||||
void removeAllQuickTests();
|
void removeAllQuickTests();
|
||||||
void removeUnnamedQuickTest(const QString &filePath);
|
bool removeUnnamedQuickTests(const QString &filePath);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void testTreeModelChanged();
|
void testTreeModelChanged();
|
||||||
@@ -89,6 +90,39 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TestTreeSortFilterModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum SortMode {
|
||||||
|
Alphabetically,
|
||||||
|
Naturally
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FilterMode {
|
||||||
|
Basic,
|
||||||
|
ShowInitAndCleanup = 0x01,
|
||||||
|
ShowTestData = 0x02,
|
||||||
|
ShowAll = ShowInitAndCleanup | ShowTestData
|
||||||
|
};
|
||||||
|
|
||||||
|
TestTreeSortFilterModel(TestTreeModel *sourceModel, QObject *parent = 0);
|
||||||
|
void setSortMode(SortMode sortMode);
|
||||||
|
void setFilterMode(FilterMode filterMode);
|
||||||
|
void toggleFilter(FilterMode filterMode);
|
||||||
|
static FilterMode toFilterMode(int f);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
||||||
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TestTreeModel *m_sourceModel;
|
||||||
|
SortMode m_sortMode;
|
||||||
|
FilterMode m_filterMode;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "testtreemodel.h"
|
#include "testtreemodel.h"
|
||||||
#include "testtreeview.h"
|
#include "testtreeview.h"
|
||||||
|
|
||||||
|
#include <coreplugin/coreconstants.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <coreplugin/find/itemviewfind.h>
|
#include <coreplugin/find/itemviewfind.h>
|
||||||
@@ -47,8 +48,11 @@ TestTreeViewWidget::TestTreeViewWidget(QWidget *parent) :
|
|||||||
{
|
{
|
||||||
setWindowTitle(tr("Tests"));
|
setWindowTitle(tr("Tests"));
|
||||||
m_model = TestTreeModel::instance();
|
m_model = TestTreeModel::instance();
|
||||||
|
m_sortFilterModel = new TestTreeSortFilterModel(m_model, m_model);
|
||||||
|
m_sortFilterModel->setDynamicSortFilter(true);
|
||||||
m_view = new TestTreeView(this);
|
m_view = new TestTreeView(this);
|
||||||
m_view->setModel(m_model);
|
m_view->setModel(m_sortFilterModel);
|
||||||
|
m_view->setSortingEnabled(true);
|
||||||
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout;
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
layout->setMargin(0);
|
layout->setMargin(0);
|
||||||
@@ -116,10 +120,21 @@ QList<QToolButton *> TestTreeViewWidget::createToolButtons()
|
|||||||
{
|
{
|
||||||
QList<QToolButton *> list;
|
QList<QToolButton *> list;
|
||||||
|
|
||||||
|
m_filterButton = new QToolButton(m_view);
|
||||||
|
m_filterButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_FILTER)));
|
||||||
|
m_filterButton->setToolTip(tr("Filter Test Tree"));
|
||||||
|
m_filterButton->setProperty("noArrow", true);
|
||||||
|
m_filterButton->setAutoRaise(true);
|
||||||
|
m_filterButton->setPopupMode(QToolButton::InstantPopup);
|
||||||
|
m_filterMenu = new QMenu(m_filterButton);
|
||||||
|
initializeFilterMenu();
|
||||||
|
connect(m_filterMenu, &QMenu::triggered, this, &TestTreeViewWidget::onFilterMenuTriggered);
|
||||||
|
m_filterButton->setMenu(m_filterMenu);
|
||||||
|
|
||||||
m_sortAlphabetically = true;
|
m_sortAlphabetically = true;
|
||||||
m_sort = new QToolButton(this);
|
m_sort = new QToolButton(this);
|
||||||
m_sort->setIcon((QIcon(QLatin1String(":/images/leafsort.png"))));
|
m_sort->setIcon((QIcon(QLatin1String(":/images/leafsort.png"))));
|
||||||
m_sort->setToolTip(tr("Sort Naturally (not implemented yet)"));
|
m_sort->setToolTip(tr("Sort Naturally"));
|
||||||
|
|
||||||
QToolButton *expand = new QToolButton(this);
|
QToolButton *expand = new QToolButton(this);
|
||||||
expand->setIcon(QIcon(QLatin1String(":/images/expand.png")));
|
expand->setIcon(QIcon(QLatin1String(":/images/expand.png")));
|
||||||
@@ -133,7 +148,7 @@ QList<QToolButton *> TestTreeViewWidget::createToolButtons()
|
|||||||
connect(collapse, &QToolButton::clicked, m_view, &TestTreeView::collapseAll);
|
connect(collapse, &QToolButton::clicked, m_view, &TestTreeView::collapseAll);
|
||||||
connect(m_sort, &QToolButton::clicked, this, &TestTreeViewWidget::onSortClicked);
|
connect(m_sort, &QToolButton::clicked, this, &TestTreeViewWidget::onSortClicked);
|
||||||
|
|
||||||
list << m_sort << expand << collapse;
|
list << m_filterButton << m_sort << expand << collapse;
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,14 +182,37 @@ void TestTreeViewWidget::onSortClicked()
|
|||||||
if (m_sortAlphabetically) {
|
if (m_sortAlphabetically) {
|
||||||
m_sort->setIcon((QIcon(QLatin1String(":/images/sort.png"))));
|
m_sort->setIcon((QIcon(QLatin1String(":/images/sort.png"))));
|
||||||
m_sort->setToolTip(tr("Sort Alphabetically"));
|
m_sort->setToolTip(tr("Sort Alphabetically"));
|
||||||
|
m_sortFilterModel->setSortMode(TestTreeSortFilterModel::Naturally);
|
||||||
} else {
|
} else {
|
||||||
m_sort->setIcon((QIcon(QLatin1String(":/images/leafsort.png"))));
|
m_sort->setIcon((QIcon(QLatin1String(":/images/leafsort.png"))));
|
||||||
m_sort->setToolTip(tr("Sort Naturally (not implemented yet)"));
|
m_sort->setToolTip(tr("Sort Naturally"));
|
||||||
|
m_sortFilterModel->setSortMode(TestTreeSortFilterModel::Alphabetically);
|
||||||
}
|
}
|
||||||
// TODO trigger the sorting change..
|
|
||||||
m_sortAlphabetically = !m_sortAlphabetically;
|
m_sortAlphabetically = !m_sortAlphabetically;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestTreeViewWidget::onFilterMenuTriggered(QAction *action)
|
||||||
|
{
|
||||||
|
m_sortFilterModel->toggleFilter(
|
||||||
|
TestTreeSortFilterModel::toFilterMode(action->data().value<int>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeViewWidget::initializeFilterMenu()
|
||||||
|
{
|
||||||
|
QAction *action = new QAction(m_filterMenu);
|
||||||
|
action->setText(tr("Show init and cleanup functions"));
|
||||||
|
action->setCheckable(true);
|
||||||
|
action->setChecked(false);
|
||||||
|
action->setData(TestTreeSortFilterModel::ShowInitAndCleanup);
|
||||||
|
m_filterMenu->addAction(action);
|
||||||
|
action = new QAction(m_filterMenu);
|
||||||
|
action->setText(tr("Show data functions"));
|
||||||
|
action->setCheckable(true);
|
||||||
|
action->setChecked(false);
|
||||||
|
action->setData(TestTreeSortFilterModel::ShowTestData);
|
||||||
|
m_filterMenu->addAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
TestViewFactory::TestViewFactory()
|
TestViewFactory::TestViewFactory()
|
||||||
{
|
{
|
||||||
setDisplayName(tr("Tests"));
|
setDisplayName(tr("Tests"));
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include <utils/navigationtreeview.h>
|
#include <utils/navigationtreeview.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QAction;
|
||||||
|
class QMenu;
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
class QToolButton;
|
class QToolButton;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
@@ -36,6 +38,7 @@ namespace Autotest {
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class TestTreeModel;
|
class TestTreeModel;
|
||||||
|
class TestTreeSortFilterModel;
|
||||||
|
|
||||||
class TestTreeView : public Utils::NavigationTreeView
|
class TestTreeView : public Utils::NavigationTreeView
|
||||||
{
|
{
|
||||||
@@ -71,11 +74,17 @@ private slots:
|
|||||||
void onRunAllTriggered();
|
void onRunAllTriggered();
|
||||||
void onRunSelectedTriggered();
|
void onRunSelectedTriggered();
|
||||||
void onSortClicked();
|
void onSortClicked();
|
||||||
|
void onFilterMenuTriggered(QAction *action);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void initializeFilterMenu();
|
||||||
|
|
||||||
TestTreeModel *m_model;
|
TestTreeModel *m_model;
|
||||||
|
TestTreeSortFilterModel *m_sortFilterModel;
|
||||||
TestTreeView *m_view;
|
TestTreeView *m_view;
|
||||||
QToolButton *m_sort;
|
QToolButton *m_sort;
|
||||||
|
QToolButton *m_filterButton;
|
||||||
|
QMenu *m_filterMenu;
|
||||||
bool m_sortAlphabetically;
|
bool m_sortAlphabetically;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user