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
|
||||
#define AUTOTESTCONSTANTS_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace Autotest {
|
||||
namespace Constants {
|
||||
|
||||
@@ -27,6 +29,7 @@ const char MENU_ID[] = "AutoTest.Menu";
|
||||
const char AUTOTEST_ID[] = "AutoTest.ATP";
|
||||
const char AUTOTEST_CONTEXT[] = "Auto Tests";
|
||||
const char TASK_INDEX[] = "AutoTest.Task.Index";
|
||||
const char UNNAMED_QUICKTESTS[] = QT_TR_NOOP("<unnamed>");
|
||||
|
||||
} // namespace Autotest
|
||||
} // namespace Constants
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "autotestconstants.h"
|
||||
#include "testcodeparser.h"
|
||||
#include "testinfo.h"
|
||||
#include "testtreeitem.h"
|
||||
@@ -385,25 +386,35 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr doc)
|
||||
m_model->removeQuickTestSubtreeByFilePath(d->fileName());
|
||||
m_quickDocMap.remove(d->fileName());
|
||||
}
|
||||
bool hadUnnamedTestsBefore;
|
||||
TestTreeItem *ttItem = m_model->unnamedQuickTests();
|
||||
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;
|
||||
TestTreeItem *unnamedQTItem = m_model->unnamedQuickTests();
|
||||
if (unnamedQTItem) {
|
||||
// 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
|
||||
TestInfo ti = m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)];
|
||||
QStringList tiFunctions = ti.testFunctions();
|
||||
foreach (const QString &func, testFunctions.keys())
|
||||
tiFunctions.removeOne(func);
|
||||
ti.setTestFunctions(tiFunctions);
|
||||
if (tiFunctions.size() == 0)
|
||||
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const QString &func, testFunctions.keys()) {
|
||||
const TestCodeLocation location = testFunctions.value(func);
|
||||
@@ -414,22 +425,21 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr doc)
|
||||
ttSub->setMainFile(doc->fileName());
|
||||
ttItem->appendChild(ttSub);
|
||||
}
|
||||
}
|
||||
TestInfo info = m_quickDocMap.contains(QLatin1String("<unnamed>"))
|
||||
? m_quickDocMap[QLatin1String("<unnamed>")]
|
||||
TestInfo info = m_quickDocMap.contains(tr(Constants::UNNAMED_QUICKTESTS))
|
||||
? m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)]
|
||||
: TestInfo(QString(), QStringList(), 666);
|
||||
QStringList originalFunctions(info.testFunctions());
|
||||
foreach (const QString &func, testFunctions.keys()) {
|
||||
if (!originalFunctions.contains(func))
|
||||
foreach (const QString &func, testFunctions.keys())
|
||||
originalFunctions.append(func);
|
||||
}
|
||||
info.setTestFunctions(originalFunctions);
|
||||
|
||||
if (hadUnnamedTestsBefore)
|
||||
m_model->modifyQuickTestSubtree(ttItem->row(), ttItem);
|
||||
else
|
||||
if (unnamedQTItem) {
|
||||
m_model->modifyQuickTestSubtree(unnamedQTItem->row(), ttItem);
|
||||
delete ttItem;
|
||||
} else {
|
||||
m_model->addQuickTest(ttItem);
|
||||
m_quickDocMap.insert(QLatin1String("<unnamed>"), info);
|
||||
}
|
||||
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), info);
|
||||
|
||||
continue;
|
||||
} // end of handling test cases without name property
|
||||
@@ -468,15 +478,20 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr doc)
|
||||
delete ttItem;
|
||||
} else {
|
||||
// if it was formerly unnamed remove the respective items
|
||||
if (m_quickDocMap.contains(QLatin1String("<unnamed>"))) {
|
||||
m_model->removeUnnamedQuickTest(d->fileName());
|
||||
TestInfo unnamedInfo = m_quickDocMap[QLatin1String("<unnamed>")];
|
||||
if (m_quickDocMap.contains(tr(Constants::UNNAMED_QUICKTESTS))) {
|
||||
if (m_model->removeUnnamedQuickTests(d->fileName())) {
|
||||
// make sure m_quickDocMap does not have a inconsistent state now
|
||||
TestInfo unnamedInfo = m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)];
|
||||
QStringList functions = unnamedInfo.testFunctions();
|
||||
foreach (const QString &func, testFunctions.keys())
|
||||
if (functions.contains(func))
|
||||
functions.removeOne(func);
|
||||
unnamedInfo.setTestFunctions(functions);
|
||||
m_quickDocMap.insert(QLatin1String("<unnamed>"), unnamedInfo);
|
||||
if (functions.size() == 0)
|
||||
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
||||
else
|
||||
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), unnamedInfo);
|
||||
}
|
||||
}
|
||||
|
||||
m_model->addQuickTest(ttItem);
|
||||
@@ -523,7 +538,7 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &doc)
|
||||
&& snapshot.contains(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;
|
||||
|
||||
// special case of having unnamed TestCases
|
||||
|
||||
@@ -55,18 +55,53 @@ ResultType TestResult::resultFromString(const QString &resultString)
|
||||
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)
|
||||
{
|
||||
switch(type) {
|
||||
case PASS: return QLatin1String("PASS");
|
||||
case FAIL: return QLatin1String("FAIL");
|
||||
case EXPECTED_FAIL: return QLatin1String("XFAIL");
|
||||
case UNEXPECTED_PASS: return QLatin1String("XPASS");
|
||||
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();
|
||||
case PASS:
|
||||
return QLatin1String("PASS");
|
||||
case FAIL:
|
||||
return QLatin1String("FAIL");
|
||||
case EXPECTED_FAIL:
|
||||
return QLatin1String("XFAIL");
|
||||
case UNEXPECTED_PASS:
|
||||
return QLatin1String("XPASS");
|
||||
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:
|
||||
return QLatin1String("UNKNOWN");
|
||||
}
|
||||
@@ -75,15 +110,24 @@ QString TestResult::resultToString(const ResultType type)
|
||||
QColor TestResult::colorForType(const ResultType type)
|
||||
{
|
||||
switch(type) {
|
||||
case PASS: return QColor("#009900");
|
||||
case FAIL: return QColor("#a00000");
|
||||
case EXPECTED_FAIL: return QColor("#00ff00");
|
||||
case UNEXPECTED_PASS: return QColor("#ff0000");
|
||||
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");
|
||||
case PASS:
|
||||
return QColor("#009900");
|
||||
case FAIL:
|
||||
return QColor("#a00000");
|
||||
case EXPECTED_FAIL:
|
||||
return QColor("#00ff00");
|
||||
case UNEXPECTED_PASS:
|
||||
return QColor("#ff0000");
|
||||
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:
|
||||
return QColor("#000000");
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
void setLine(int line) { m_line = line; }
|
||||
|
||||
static ResultType resultFromString(const QString &resultString);
|
||||
static ResultType toResultType(int rt);
|
||||
static QString resultToString(const ResultType type);
|
||||
static QColor colorForType(const ResultType type);
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ void TestResultsPane::updateFilterMenu()
|
||||
foreach (QAction *action, m_filterMenu->actions()) {
|
||||
if (action->isCheckable())
|
||||
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)
|
||||
{
|
||||
m_filterModel->toggleTestResultType(static_cast<ResultType>(action->data().value<int>()));
|
||||
m_filterModel->toggleTestResultType(TestResult::toResultType(action->data().value<int>()));
|
||||
navigateStateChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,23 @@ TestTreeItem::~TestTreeItem()
|
||||
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)
|
||||
{
|
||||
return m_children.at(row);
|
||||
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
|
||||
TestTreeItem(const QString &name, const QString &filePath, Type type, TestTreeItem *parent = 0);
|
||||
virtual ~TestTreeItem();
|
||||
TestTreeItem(const TestTreeItem& other);
|
||||
|
||||
TestTreeItem *child(int row);
|
||||
TestTreeItem *parent() const;
|
||||
@@ -58,6 +59,7 @@ public:
|
||||
void setChecked(const Qt::CheckState checked);
|
||||
Qt::CheckState checked() const { return m_checked; }
|
||||
Type type() const { return m_type; }
|
||||
void setParent(TestTreeItem *parent) { m_parent = parent; }
|
||||
|
||||
private:
|
||||
void revalidateCheckState();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "autotestconstants.h"
|
||||
#include "testcodeparser.h"
|
||||
#include "testtreeitem.h"
|
||||
#include "testtreemodel.h"
|
||||
@@ -152,7 +153,7 @@ QVariant TestTreeModel::data(const QModelIndex &index, int role) const
|
||||
return QString(item->name() + tr(" (none)"));
|
||||
} else {
|
||||
if (item->name().isEmpty())
|
||||
return tr("<unnamed>");
|
||||
return tr(Constants::UNNAMED_QUICKTESTS);
|
||||
return item->name();
|
||||
}
|
||||
|
||||
@@ -535,19 +536,24 @@ void TestTreeModel::removeAllQuickTests()
|
||||
emit testTreeModelChanged();
|
||||
}
|
||||
|
||||
void TestTreeModel::removeUnnamedQuickTest(const QString &filePath)
|
||||
bool TestTreeModel::removeUnnamedQuickTests(const QString &filePath)
|
||||
{
|
||||
TestTreeItem *unnamedQT = unnamedQuickTests();
|
||||
if (!unnamedQT)
|
||||
return;
|
||||
return false;
|
||||
|
||||
bool removed = false;
|
||||
const QModelIndex unnamedQTIndex = index(1, 0).child(unnamedQT->row(), 0);
|
||||
for (int childRow = unnamedQT->childCount() - 1; childRow >= 0; --childRow) {
|
||||
const TestTreeItem *child = unnamedQT->child(childRow);
|
||||
if (filePath == child->filePath())
|
||||
removeRow(childRow, unnamedQTIndex);
|
||||
removed |= removeRow(childRow, unnamedQTIndex);
|
||||
}
|
||||
|
||||
if (unnamedQT->childCount() == 0)
|
||||
removeRow(unnamedQT->row(), unnamedQTIndex.parent());
|
||||
emit testTreeModelChanged();
|
||||
return removed;
|
||||
}
|
||||
|
||||
void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeItem *newItem)
|
||||
@@ -566,6 +572,7 @@ void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeIt
|
||||
const int newChildCount = newItem->childCount();
|
||||
|
||||
// for keeping the CheckState on modifications
|
||||
// TODO might still fail for duplicate entries (e.g. unnamed Quick Tests)
|
||||
QHash<QString, Qt::CheckState> originalItems;
|
||||
for (int row = 0; row < childCount; ++row) {
|
||||
const TestTreeItem *child = toBeModifiedItem->child(row);
|
||||
@@ -594,9 +601,8 @@ void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeIt
|
||||
if (childCount < newChildCount) { // add aditional items
|
||||
for (int row = childCount; row < newChildCount; ++row) {
|
||||
TestTreeItem *newChild = newItem->child(row);
|
||||
TestTreeItem *toBeAdded = new TestTreeItem(newChild->name(), newChild->filePath(),
|
||||
newChild->type(), toBeModifiedItem);
|
||||
toBeAdded->setLine(newChild->line());
|
||||
TestTreeItem *toBeAdded = new TestTreeItem(*newChild);
|
||||
toBeAdded->setParent(toBeModifiedItem);
|
||||
beginInsertRows(toBeModifiedIndex, row, row);
|
||||
toBeModifiedItem->appendChild(toBeAdded);
|
||||
endInsertRows();
|
||||
@@ -628,5 +634,97 @@ void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeIt
|
||||
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 Autotest
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <cplusplus/CppDocument.h>
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace {
|
||||
enum ItemRole {
|
||||
@@ -71,7 +72,7 @@ public:
|
||||
void removeQuickTestSubtreeByFilePath(const QString &file);
|
||||
void addQuickTest(TestTreeItem *newItem);
|
||||
void removeAllQuickTests();
|
||||
void removeUnnamedQuickTest(const QString &filePath);
|
||||
bool removeUnnamedQuickTests(const QString &filePath);
|
||||
|
||||
signals:
|
||||
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 Autotest
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "testtreemodel.h"
|
||||
#include "testtreeview.h"
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <coreplugin/find/itemviewfind.h>
|
||||
@@ -47,8 +48,11 @@ TestTreeViewWidget::TestTreeViewWidget(QWidget *parent) :
|
||||
{
|
||||
setWindowTitle(tr("Tests"));
|
||||
m_model = TestTreeModel::instance();
|
||||
m_sortFilterModel = new TestTreeSortFilterModel(m_model, m_model);
|
||||
m_sortFilterModel->setDynamicSortFilter(true);
|
||||
m_view = new TestTreeView(this);
|
||||
m_view->setModel(m_model);
|
||||
m_view->setModel(m_sortFilterModel);
|
||||
m_view->setSortingEnabled(true);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->setMargin(0);
|
||||
@@ -116,10 +120,21 @@ QList<QToolButton *> TestTreeViewWidget::createToolButtons()
|
||||
{
|
||||
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_sort = new QToolButton(this);
|
||||
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);
|
||||
expand->setIcon(QIcon(QLatin1String(":/images/expand.png")));
|
||||
@@ -133,7 +148,7 @@ QList<QToolButton *> TestTreeViewWidget::createToolButtons()
|
||||
connect(collapse, &QToolButton::clicked, m_view, &TestTreeView::collapseAll);
|
||||
connect(m_sort, &QToolButton::clicked, this, &TestTreeViewWidget::onSortClicked);
|
||||
|
||||
list << m_sort << expand << collapse;
|
||||
list << m_filterButton << m_sort << expand << collapse;
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -167,14 +182,37 @@ void TestTreeViewWidget::onSortClicked()
|
||||
if (m_sortAlphabetically) {
|
||||
m_sort->setIcon((QIcon(QLatin1String(":/images/sort.png"))));
|
||||
m_sort->setToolTip(tr("Sort Alphabetically"));
|
||||
m_sortFilterModel->setSortMode(TestTreeSortFilterModel::Naturally);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
setDisplayName(tr("Tests"));
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <utils/navigationtreeview.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
class QMenu;
|
||||
class QModelIndex;
|
||||
class QToolButton;
|
||||
QT_END_NAMESPACE
|
||||
@@ -36,6 +38,7 @@ namespace Autotest {
|
||||
namespace Internal {
|
||||
|
||||
class TestTreeModel;
|
||||
class TestTreeSortFilterModel;
|
||||
|
||||
class TestTreeView : public Utils::NavigationTreeView
|
||||
{
|
||||
@@ -71,11 +74,17 @@ private slots:
|
||||
void onRunAllTriggered();
|
||||
void onRunSelectedTriggered();
|
||||
void onSortClicked();
|
||||
void onFilterMenuTriggered(QAction *action);
|
||||
|
||||
private:
|
||||
void initializeFilterMenu();
|
||||
|
||||
TestTreeModel *m_model;
|
||||
TestTreeSortFilterModel *m_sortFilterModel;
|
||||
TestTreeView *m_view;
|
||||
QToolButton *m_sort;
|
||||
QToolButton *m_filterButton;
|
||||
QMenu *m_filterMenu;
|
||||
bool m_sortAlphabetically;
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user