diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/autotest/projectsettingswidget.cpp | 89 | ||||
-rw-r--r-- | src/plugins/autotest/testcodeparser.cpp | 34 | ||||
-rw-r--r-- | src/plugins/autotest/testprojectsettings.cpp | 6 | ||||
-rw-r--r-- | src/plugins/autotest/testprojectsettings.h | 7 |
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, [®exes](const FilePath &fn) { + for (const QRegularExpression ®ex : 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; }; |