aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/autotest/projectsettingswidget.cpp89
-rw-r--r--src/plugins/autotest/testcodeparser.cpp34
-rw-r--r--src/plugins/autotest/testprojectsettings.cpp6
-rw-r--r--src/plugins/autotest/testprojectsettings.h7
4 files changed, 136 insertions, 0 deletions
diff --git a/src/plugins/autotest/projectsettingswidget.cpp b/src/plugins/autotest/projectsettingswidget.cpp
index c5a8b41059..5ee3dcac5d 100644
--- a/src/plugins/autotest/projectsettingswidget.cpp
+++ b/src/plugins/autotest/projectsettingswidget.cpp
@@ -6,6 +6,7 @@
#include "autotestconstants.h"
#include "autotestplugin.h"
#include "autotesttr.h"
+#include "testcodeparser.h"
#include "testprojectsettings.h"
#include "testtreemodel.h"
@@ -13,10 +14,12 @@
#include <projectexplorer/projectsettingswidget.h>
#include <utils/algorithm.h>
+#include <utils/aspects.h>
#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
#include <QComboBox>
+#include <QPushButton>
#include <QTimer>
#include <QTreeWidget>
@@ -37,10 +40,13 @@ public:
private:
void populateFrameworks(const QHash<Autotest::ITestFramework *, bool> &frameworks,
const QHash<Autotest::ITestTool *, bool> &testTools);
+ void populatePathFilters(const QStringList &filters);
void onActiveFrameworkChanged(QTreeWidgetItem *item, int column);
TestProjectSettings *m_projectSettings;
QTreeWidget *m_activeFrameworks = nullptr;
QComboBox *m_runAfterBuild = nullptr;
+ Utils::BoolAspect m_applyFilter;
+ QTreeWidget *m_pathFilters = nullptr;
QTimer m_syncTimer;
int m_syncType = 0;
};
@@ -59,6 +65,14 @@ ProjectTestSettingsWidget::ProjectTestSettingsWidget(Project *project)
m_runAfterBuild->addItem(Tr::tr("All"));
m_runAfterBuild->addItem(Tr::tr("Selected"));
m_runAfterBuild->setCurrentIndex(int(m_projectSettings->runAfterBuild()));
+ m_applyFilter.setToolTip(Tr::tr("Apply path filters before scanning for tests."));
+ m_pathFilters = new QTreeWidget;
+ m_pathFilters->setHeaderHidden(true);
+ m_pathFilters->setRootIsDecorated(false);
+ QLabel *filterLabel = new QLabel(Tr::tr("Wildcard expressions for filtering"), this);
+ QPushButton *addFilter = new QPushButton(Tr::tr("Add"), this);
+ QPushButton *removeFilter = new QPushButton(Tr::tr("Remove"), this);
+ removeFilter->setEnabled(false);
using namespace Layouting;
Column {
@@ -80,6 +94,19 @@ ProjectTestSettingsWidget::ProjectTestSettingsWidget(Project *project)
noMargin(),
},
},
+ Row { // explicitly outside of the global settings
+ Group {
+ title(Tr::tr("Limit files to path patterns")),
+ m_applyFilter.groupChecker(),
+ Column {
+ filterLabel,
+ Row {
+ Column { m_pathFilters },
+ Column { addFilter, removeFilter, st },
+ },
+ },
+ },
+ },
noMargin(),
}.attachTo(this);
@@ -88,7 +115,9 @@ ProjectTestSettingsWidget::ProjectTestSettingsWidget(Project *project)
populateFrameworks(m_projectSettings->activeFrameworks(),
m_projectSettings->activeTestTools());
+ populatePathFilters(m_projectSettings->pathFilters());
setUseGlobalSettings(m_projectSettings->useGlobalSettings());
+ m_applyFilter.setValue(m_projectSettings->limitToFilters());
connect(this, &ProjectSettingsWidget::useGlobalSettingsChanged,
this, [this, generalWidget](bool useGlobalSettings) {
generalWidget->setEnabled(!useGlobalSettings);
@@ -102,6 +131,56 @@ ProjectTestSettingsWidget::ProjectTestSettingsWidget(Project *project)
connect(m_runAfterBuild, &QComboBox::currentIndexChanged, this, [this](int index) {
m_projectSettings->setRunAfterBuild(RunAfterBuildMode(index));
});
+
+ auto itemsToStringList = [this] {
+ QStringList items;
+ const QTreeWidgetItem *rootItem = m_pathFilters->invisibleRootItem();
+ for (int i = 0, count = rootItem->childCount(); i < count; ++i) {
+ auto expr = rootItem->child(i)->data(0, Qt::DisplayRole).toString();
+ items.append(expr);
+ }
+ return items;
+ };
+ auto triggerRescan = [this] {
+ TestCodeParser *parser = TestTreeModel::instance()->parser();
+ parser->emitUpdateTestTree();
+ };
+
+ connect(&m_applyFilter, &Utils::BoolAspect::changed,
+ this, [this, triggerRescan] {
+ m_projectSettings->setLimitToFilter(m_applyFilter.value());
+ triggerRescan();
+ });
+ connect(m_pathFilters, &QTreeWidget::itemSelectionChanged,
+ this, [this, removeFilter] {
+ removeFilter->setEnabled(!m_pathFilters->selectedItems().isEmpty());
+ });
+ connect(m_pathFilters->model(), &QAbstractItemModel::dataChanged,
+ this, [this, itemsToStringList, triggerRescan]
+ (const QModelIndex &tl, const QModelIndex &br, const QList<int> &roles) {
+ if (!roles.contains(Qt::DisplayRole))
+ return;
+ if (tl != br)
+ return;
+ m_projectSettings->setPathFilters(itemsToStringList());
+ triggerRescan();
+ });
+ connect(addFilter, &QPushButton::clicked, this, [this] {
+ m_projectSettings->addPathFilter("*");
+ populatePathFilters(m_projectSettings->pathFilters());
+ const QTreeWidgetItem *root = m_pathFilters->invisibleRootItem();
+ QTreeWidgetItem *lastChild = root->child(root->childCount() - 1);
+ const QModelIndex index = m_pathFilters->indexFromItem(lastChild, 0);
+ m_pathFilters->edit(index);
+ });
+ connect(removeFilter, &QPushButton::clicked, this, [this, itemsToStringList, triggerRescan] {
+ const QList<QTreeWidgetItem *> selected = m_pathFilters->selectedItems();
+ QTC_ASSERT(selected.size() == 1, return);
+ m_pathFilters->invisibleRootItem()->removeChild(selected.first());
+ delete selected.first();
+ m_projectSettings->setPathFilters(itemsToStringList());
+ triggerRescan();
+ });
m_syncTimer.setSingleShot(true);
connect(&m_syncTimer, &QTimer::timeout, this, [this] {
auto testTreeModel = TestTreeModel::instance();
@@ -136,6 +215,16 @@ void ProjectTestSettingsWidget::populateFrameworks(const QHash<ITestFramework *,
generateItem(it.key(), it.value());
}
+void ProjectTestSettingsWidget::populatePathFilters(const QStringList &filters)
+{
+ m_pathFilters->clear();
+ for (const QString &filter : filters) {
+ auto item = new QTreeWidgetItem(m_pathFilters, {filter});
+ item->setData(0, Qt::ToolTipRole, filter);
+ item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
+ }
+}
+
void ProjectTestSettingsWidget::onActiveFrameworkChanged(QTreeWidgetItem *item, int column)
{
auto id = Utils::Id::fromSetting(item->data(column, BaseIdRole));
diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp
index 9962a08c62..817768e176 100644
--- a/src/plugins/autotest/testcodeparser.cpp
+++ b/src/plugins/autotest/testcodeparser.cpp
@@ -4,7 +4,9 @@
#include "testcodeparser.h"
#include "autotestconstants.h"
+#include "autotestplugin.h"
#include "autotesttr.h"
+#include "testprojectsettings.h"
#include "testsettings.h"
#include "testtreemodel.h"
@@ -336,6 +338,38 @@ void TestCodeParser::scanForTests(const QSet<FilePath> &filePaths,
emit requestRemoval(files);
}
+ const TestProjectSettings *settings = projectSettings(project);
+ if (settings->limitToFilters()) {
+ qCDebug(LOG) << "Applying project path filters - currently" << files.size() << "files";
+ const QStringList filters = settings->pathFilters();
+ if (!filters.isEmpty()) {
+ // we cannot rely on QRegularExpression::fromWildcard() as we want handle paths
+ const QList<QRegularExpression> regexes
+ = Utils::transform(filters, [] (const QString &filter) {
+ return QRegularExpression(wildcardPatternFromString(filter));
+ });
+
+ files = Utils::filtered(files, [&regexes](const FilePath &fn) {
+ for (const QRegularExpression &regex : regexes) {
+ if (!regex.isValid()) {
+ qCDebug(LOG) << "Skipping invalid pattern? Pattern:" << regex.pattern();
+ continue;
+ }
+ if (regex.match(fn.path()).hasMatch())
+ return true;
+ }
+ return false;
+ });
+ }
+ qCDebug(LOG) << "After applying filters" << files.size() << "files";
+
+ if (files.isEmpty()) {
+ qCDebug(LOG) << "No filter matched a file - canceling scan immediately";
+ onFinished(true);
+ return;
+ }
+ }
+
QTC_ASSERT(!(isFullParse && files.isEmpty()), onFinished(true); return);
// use only a single parser or all current active?
diff --git a/src/plugins/autotest/testprojectsettings.cpp b/src/plugins/autotest/testprojectsettings.cpp
index 0b75dd9804..a8ae11f6d5 100644
--- a/src/plugins/autotest/testprojectsettings.cpp
+++ b/src/plugins/autotest/testprojectsettings.cpp
@@ -22,6 +22,8 @@ namespace Internal {
static const char SK_ACTIVE_FRAMEWORKS[] = "AutoTest.ActiveFrameworks";
static const char SK_RUN_AFTER_BUILD[] = "AutoTest.RunAfterBuild";
static const char SK_CHECK_STATES[] = "AutoTest.CheckStates";
+static const char SK_APPLY_FILTER[] = "AutoTest.ApplyFilter";
+static const char SK_PATH_FILTERS[] = "AutoTest.PathFilters";
static Q_LOGGING_CATEGORY(LOG, "qtc.autotest.projectsettings", QtWarningMsg)
@@ -100,6 +102,8 @@ void TestProjectSettings::load()
m_runAfterBuild = runAfterBuild.isValid() ? RunAfterBuildMode(runAfterBuild.toInt())
: RunAfterBuildMode::None;
m_checkStateCache.fromSettings(m_project->namedSettings(SK_CHECK_STATES).toMap());
+ m_limitToFilter = m_project->namedSettings(SK_APPLY_FILTER).toBool();
+ m_pathFilters = m_project->namedSettings(SK_PATH_FILTERS).toStringList();
}
void TestProjectSettings::save()
@@ -115,6 +119,8 @@ void TestProjectSettings::save()
m_project->setNamedSettings(SK_ACTIVE_FRAMEWORKS, activeFrameworks);
m_project->setNamedSettings(SK_RUN_AFTER_BUILD, int(m_runAfterBuild));
m_project->setNamedSettings(SK_CHECK_STATES, m_checkStateCache.toSettings(Qt::Checked));
+ m_project->setNamedSettings(SK_APPLY_FILTER, m_limitToFilter);
+ m_project->setNamedSettings(SK_PATH_FILTERS, m_pathFilters);
}
} // namespace Internal
diff --git a/src/plugins/autotest/testprojectsettings.h b/src/plugins/autotest/testprojectsettings.h
index 09528e5aee..29d126e38b 100644
--- a/src/plugins/autotest/testprojectsettings.h
+++ b/src/plugins/autotest/testprojectsettings.h
@@ -31,15 +31,22 @@ public:
QHash<ITestTool *, bool> activeTestTools() const { return m_activeTestTools; }
void activateTestTool(const Utils::Id &id, bool activate);
Internal::ItemDataCache<Qt::CheckState> *checkStateCache() { return &m_checkStateCache; }
+ bool limitToFilters() const { return m_limitToFilter; }
+ void setLimitToFilter(bool enable) { m_limitToFilter = enable; }
+ const QStringList pathFilters() const { return m_pathFilters; }
+ void setPathFilters(const QStringList &filters) { m_pathFilters = filters; }
+ void addPathFilter(const QString &filter) { m_pathFilters.append(filter); }
private:
void load();
void save();
ProjectExplorer::Project *m_project;
bool m_useGlobalSettings = true;
+ bool m_limitToFilter = false;
RunAfterBuildMode m_runAfterBuild = RunAfterBuildMode::None;
QHash<ITestFramework *, bool> m_activeTestFrameworks;
QHash<ITestTool *, bool> m_activeTestTools;
+ QStringList m_pathFilters;
Internal::ItemDataCache<Qt::CheckState> m_checkStateCache;
};