diff options
author | Eike Ziller <eike.ziller@qt.io> | 2016-12-09 13:33:12 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2017-02-28 10:48:23 +0000 |
commit | 1f8b2dc3610635f019b7fef8192171f4e085f814 (patch) | |
tree | 3611fc53841940069d7adc70a42865c781932b4a /src | |
parent | 99a6d78bba07a40a8407f1b7ba44b57f7da1983e (diff) |
Advanced search: Add exclusion patterns
All files with full file path matching one of the exclusion patterns are
ignored in the search.
Searching with "git grep" now requires git >= 1.9
Change-Id: Ied5d11499bc1ff21247e50f8e146e8e5011dd2c1
Reviewed-by: David Schulz <david.schulz@qt.io>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/libs/utils/filesearch.cpp | 74 | ||||
-rw-r--r-- | src/libs/utils/filesearch.h | 16 | ||||
-rw-r--r-- | src/plugins/coreplugin/locator/directoryfilter.cpp | 2 | ||||
-rw-r--r-- | src/plugins/git/gitgrep.cpp | 10 | ||||
-rw-r--r-- | src/plugins/git/gitplugin.cpp | 2 | ||||
-rw-r--r-- | src/plugins/projectexplorer/allprojectsfind.cpp | 54 | ||||
-rw-r--r-- | src/plugins/projectexplorer/allprojectsfind.h | 2 | ||||
-rw-r--r-- | src/plugins/projectexplorer/currentprojectfind.cpp | 7 | ||||
-rw-r--r-- | src/plugins/projectexplorer/currentprojectfind.h | 1 | ||||
-rw-r--r-- | src/plugins/texteditor/basefilefind.cpp | 131 | ||||
-rw-r--r-- | src/plugins/texteditor/basefilefind.h | 11 | ||||
-rw-r--r-- | src/plugins/texteditor/findincurrentfile.cpp | 4 | ||||
-rw-r--r-- | src/plugins/texteditor/findincurrentfile.h | 1 | ||||
-rw-r--r-- | src/plugins/texteditor/findinfiles.cpp | 23 | ||||
-rw-r--r-- | src/plugins/texteditor/findinfiles.h | 1 | ||||
-rw-r--r-- | src/plugins/texteditor/findinopenfiles.cpp | 6 | ||||
-rw-r--r-- | src/plugins/texteditor/findinopenfiles.h | 1 |
17 files changed, 243 insertions, 103 deletions
diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index 1a13378d1c..beac6433bd 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -23,11 +23,14 @@ ** ****************************************************************************/ +#include "algorithm.h" #include "filesearch.h" +#include "fileutils.h" #include "mapreduce.h" #include <QCoreApplication> #include <QMutex> +#include <QRegExp> #include <QRegularExpression> #include <QTextCodec> @@ -457,6 +460,50 @@ QString matchCaseReplacement(const QString &originalText, const QString &replace return replaceText; // mixed } +} // namespace + +static QList<QRegExp> filtersToRegExps(const QStringList &filters) +{ + return Utils::transform(filters, [](const QString &filter) { + return QRegExp(filter, Qt::CaseInsensitive, QRegExp::Wildcard); + }); +} + +static bool matches(const QList<QRegExp> &exprList, const QString &filePath) +{ + return Utils::anyOf(exprList, [&filePath](QRegExp reg) { + return (reg.exactMatch(filePath) + || reg.exactMatch(Utils::FileName::fromString(filePath).fileName())); + }); +} + +static bool isFileIncluded(const QList<QRegExp> &filterRegs, const QList<QRegExp> &exclusionRegs, + const QString &filePath) +{ + const bool isIncluded = filterRegs.isEmpty() || matches(filterRegs, filePath); + return isIncluded && (exclusionRegs.isEmpty() || !matches(exclusionRegs, filePath)); +} + +std::function<bool(const QString &)> +filterFileFunction(const QStringList &filters, const QStringList &exclusionFilters) +{ + const QList<QRegExp> filterRegs = filtersToRegExps(filters); + const QList<QRegExp> exclusionRegs = filtersToRegExps(exclusionFilters); + return [filterRegs, exclusionRegs](const QString &filePath) { + return isFileIncluded(filterRegs, exclusionRegs, filePath); + }; +} + +std::function<QStringList(const QStringList &)> +filterFilesFunction(const QStringList &filters, const QStringList &exclusionFilters) +{ + const QList<QRegExp> filterRegs = filtersToRegExps(filters); + const QList<QRegExp> exclusionRegs = filtersToRegExps(exclusionFilters); + return [filterRegs, exclusionRegs](const QStringList &filePaths) { + return Utils::filtered(filePaths, [&filterRegs, &exclusionRegs](const QString &filePath) { + return isFileIncluded(filterRegs, exclusionRegs, filePath); + }); + }; } QString matchCaseReplacement(const QString &originalText, const QString &replaceText) @@ -562,8 +609,9 @@ namespace { } SubDirFileIterator::SubDirFileIterator(const QStringList &directories, const QStringList &filters, - QTextCodec *encoding) - : m_filters(filters), m_progress(0) + const QStringList &exclusionFilters, QTextCodec *encoding) + : m_filterFiles(filterFilesFunction(filters, exclusionFilters)), + m_progress(0) { m_encoding = (encoding == 0 ? QTextCodec::codecForLocale() : encoding); qreal maxPer = qreal(MAX_PROGRESS) / directories.count(); @@ -591,19 +639,21 @@ void SubDirFileIterator::update(int index) const qreal dirProgressMax = m_progressValues.pop(); const bool processed = m_processedValues.pop(); if (dir.exists()) { + const QString dirPath = dir.path(); QStringList subDirs; if (!processed) subDirs = dir.entryList(QDir::Dirs|QDir::Hidden|QDir::NoDotAndDotDot); if (subDirs.isEmpty()) { - QStringList fileEntries = dir.entryList(m_filters, - QDir::Files|QDir::Hidden); - QStringListIterator it(fileEntries); - it.toBack(); - m_items.reserve(m_items.size() + fileEntries.size()); - while (it.hasPrevious()) { - const QString &file = it.previous(); - m_items.append(new Item(dir.path()+ QLatin1Char('/') + file, m_encoding)); - } + const QStringList allFileEntries = dir.entryList(QDir::Files|QDir::Hidden); + const QStringList allFilePaths = Utils::transform(allFileEntries, + [&dirPath](const QString &entry) { + return QString(dirPath + '/' + entry); + }); + const QStringList filePaths = m_filterFiles(allFilePaths); + m_items.reserve(m_items.size() + filePaths.size()); + Utils::reverseForeach(filePaths, [this](const QString &file) { + m_items.append(new Item(file, m_encoding)); + }); m_progress += dirProgressMax; } else { qreal subProgress = dirProgressMax/(subDirs.size()+1); @@ -614,7 +664,7 @@ void SubDirFileIterator::update(int index) it.toBack(); while (it.hasPrevious()) { const QString &directory = it.previous(); - m_dirs.push(QDir(dir.path()+ QLatin1Char('/') + directory)); + m_dirs.push(QDir(dirPath + QLatin1Char('/') + directory)); m_progressValues.push(subProgress); m_processedValues.push(false); } diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h index 05cadc261d..540cd9304d 100644 --- a/src/libs/utils/filesearch.h +++ b/src/libs/utils/filesearch.h @@ -33,10 +33,20 @@ #include <QStack> #include <QTextDocument> +#include <functional> + QT_FORWARD_DECLARE_CLASS(QTextCodec) namespace Utils { +QTCREATOR_UTILS_EXPORT +std::function<bool(const QString &)> +filterFileFunction(const QStringList &filterRegs, const QStringList &exclusionRegs); + +QTCREATOR_UTILS_EXPORT +std::function<QStringList(const QStringList &)> +filterFilesFunction(const QStringList &filters, const QStringList &exclusionFilters); + class QTCREATOR_UTILS_EXPORT FileIterator { public: @@ -119,7 +129,9 @@ private: class QTCREATOR_UTILS_EXPORT SubDirFileIterator : public FileIterator { public: - SubDirFileIterator(const QStringList &directories, const QStringList &filters, + SubDirFileIterator(const QStringList &directories, + const QStringList &filters, + const QStringList &exclusionFilters, QTextCodec *encoding = 0); ~SubDirFileIterator(); @@ -132,7 +144,7 @@ protected: const Item &itemAt(int index) const override; private: - QStringList m_filters; + std::function<QStringList(const QStringList &)> m_filterFiles; QTextCodec *m_encoding; QStack<QDir> m_dirs; QStack<qreal> m_progressValues; diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 8a3bc2b395..cc95a200ef 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -190,7 +190,7 @@ void DirectoryFilter::refresh(QFutureInterface<void> &future) } directories = m_directories; } - Utils::SubDirFileIterator subDirIterator(directories, m_filters); + Utils::SubDirFileIterator subDirIterator(directories, m_filters, {}); future.setProgressRange(0, subDirIterator.maxProgress()); QStringList filesFound; auto end = subDirIterator.end(); diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index c391fe1a4a..3c0096921f 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -35,6 +35,7 @@ #include <vcsbase/vcscommand.h> #include <vcsbase/vcsbaseconstants.h> +#include <utils/algorithm.h> #include <utils/asconst.h> #include <utils/fancylineedit.h> #include <utils/filesearch.h> @@ -159,7 +160,14 @@ public: arguments << params.ref; m_ref = params.ref + ':'; } - arguments << "--" << m_parameters.nameFilters; + const QStringList filterArgs = + m_parameters.nameFilters.isEmpty() ? QStringList("*") // needed for exclusion filters + : m_parameters.nameFilters; + const QStringList exclusionArgs = + Utils::transform(m_parameters.exclusionFilters, [](const QString &filter) { + return QString(":!" + filter); + }); + arguments << "--" << filterArgs << exclusionArgs; QScopedPointer<VcsCommand> command(GitPlugin::client()->createCommand(m_directory)); command->addFlags(VcsCommand::SilentOutput | VcsCommand::SuppressFailMessage); command->setProgressiveOutput(true); diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 093028c740..08de519e02 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -97,7 +97,7 @@ using namespace VcsBase; namespace Git { namespace Internal { -const unsigned minimumRequiredVersion = 0x010800; +const unsigned minimumRequiredVersion = 0x010900; const VcsBaseEditorParameters editorParameters[] = { { diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp index 7ce05f7495..46b7fbb894 100644 --- a/src/plugins/projectexplorer/allprojectsfind.cpp +++ b/src/plugins/projectexplorer/allprojectsfind.cpp @@ -68,41 +68,28 @@ bool AllProjectsFind::isEnabled() const } Utils::FileIterator *AllProjectsFind::files(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QVariant &additionalParameters) const { Q_UNUSED(additionalParameters) - return filesForProjects(nameFilters, SessionManager::projects()); + return filesForProjects(nameFilters, exclusionFilters, SessionManager::projects()); } Utils::FileIterator *AllProjectsFind::filesForProjects(const QStringList &nameFilters, - const QList<Project *> &projects) const + const QStringList &exclusionFilters, + const QList<Project *> &projects) const { - QList<QRegExp> filterRegs; - foreach (const QString &filter, nameFilters) { - filterRegs << QRegExp(filter, Qt::CaseInsensitive, QRegExp::Wildcard); - } - QMap<QString, QTextCodec *> openEditorEncodings = TextDocument::openedTextDocumentEncodings(); + std::function<QStringList(const QStringList &)> filterFiles = + Utils::filterFilesFunction(nameFilters, exclusionFilters); + const QMap<QString, QTextCodec *> openEditorEncodings = TextDocument::openedTextDocumentEncodings(); QMap<QString, QTextCodec *> encodings; foreach (const Project *project, projects) { - QStringList projectFiles = project->files(Project::AllFiles); - QStringList filteredFiles; - if (!filterRegs.isEmpty()) { - foreach (const QString &file, projectFiles) { - if (Utils::anyOf(filterRegs, - [&file](QRegExp reg) { - return (reg.exactMatch(file) || reg.exactMatch(Utils::FileName::fromString(file).fileName())); - })) { - filteredFiles.append(file); - } - } - } else { - filteredFiles = projectFiles; - } const EditorConfiguration *config = project->editorConfiguration(); QTextCodec *projectCodec = config->useGlobalSettings() ? Core::EditorManager::defaultTextCodec() : config->textCodec(); - foreach (const QString &fileName, filteredFiles) { + const QStringList filteredFiles = filterFiles(project->files(Project::AllFiles)); + for (const QString &fileName : filteredFiles) { QTextCodec *codec = openEditorEncodings.value(fileName); if (!codec) codec = projectCodec; @@ -124,8 +111,10 @@ QString AllProjectsFind::label() const QString AllProjectsFind::toolTip() const { - // %2 is filled by BaseFileFind::runNewSearch - return tr("Filter: %1\n%2").arg(fileNameFilters().join(QLatin1Char(','))); + // last arg is filled by BaseFileFind::runNewSearch + return tr("Filter: %1\nExcluding: %2\n%3") + .arg(fileNameFilters().join(',')) + .arg(fileExclusionFilters().join(',')); } void AllProjectsFind::handleFileListChanged() @@ -140,14 +129,13 @@ QWidget *AllProjectsFind::createConfigWidget() auto gridLayout = new QGridLayout(m_configWidget); gridLayout->setMargin(0); m_configWidget->setLayout(gridLayout); - auto filePatternLabel = new QLabel(tr("Fi&le pattern:")); - filePatternLabel->setMinimumWidth(80); - filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); - filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - QWidget *patternWidget = createPatternWidget(); - filePatternLabel->setBuddy(patternWidget); - gridLayout->addWidget(filePatternLabel, 0, 0, Qt::AlignRight); - gridLayout->addWidget(patternWidget, 0, 1); + const QList<QPair<QWidget *, QWidget *>> patternWidgets = createPatternWidgets(); + int row = 0; + for (const QPair<QWidget *, QWidget *> &p : patternWidgets) { + gridLayout->addWidget(p.first, row, 0, Qt::AlignRight); + gridLayout->addWidget(p.second, row, 1); + ++row; + } m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); } return m_configWidget; @@ -163,6 +151,6 @@ void AllProjectsFind::writeSettings(QSettings *settings) void AllProjectsFind::readSettings(QSettings *settings) { settings->beginGroup(QLatin1String("AllProjectsFind")); - readCommonSettings(settings, QString(QLatin1Char('*'))); + readCommonSettings(settings, "*", ""); settings->endGroup(); } diff --git a/src/plugins/projectexplorer/allprojectsfind.h b/src/plugins/projectexplorer/allprojectsfind.h index b3b9f4f1e0..87f2b77a14 100644 --- a/src/plugins/projectexplorer/allprojectsfind.h +++ b/src/plugins/projectexplorer/allprojectsfind.h @@ -53,8 +53,10 @@ public: protected: Utils::FileIterator *files(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QVariant &additionalParameters) const override; Utils::FileIterator *filesForProjects(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QList<Project *> &projects) const; QVariant additionalParameters() const override; diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp index bffcd83945..c67c26a62f 100644 --- a/src/plugins/projectexplorer/currentprojectfind.cpp +++ b/src/plugins/projectexplorer/currentprojectfind.cpp @@ -73,14 +73,15 @@ QVariant CurrentProjectFind::additionalParameters() const } Utils::FileIterator *CurrentProjectFind::files(const QStringList &nameFilters, - const QVariant &additionalParameters) const + const QStringList &exclusionFilters, + const QVariant &additionalParameters) const { QTC_ASSERT(additionalParameters.isValid(), return new Utils::FileListIterator(QStringList(), QList<QTextCodec *>())); QString projectFile = additionalParameters.toString(); foreach (Project *project, SessionManager::projects()) { if (project->document() && projectFile == project->projectFilePath().toString()) - return filesForProjects(nameFilters, QList<Project *>() << project); + return filesForProjects(nameFilters, exclusionFilters, QList<Project *>() << project); } return new Utils::FileListIterator(QStringList(), QList<QTextCodec *>()); } @@ -123,6 +124,6 @@ void CurrentProjectFind::writeSettings(QSettings *settings) void CurrentProjectFind::readSettings(QSettings *settings) { settings->beginGroup(QLatin1String("CurrentProjectFind")); - readCommonSettings(settings, QString(QLatin1Char('*'))); + readCommonSettings(settings, "*", ""); settings->endGroup(); } diff --git a/src/plugins/projectexplorer/currentprojectfind.h b/src/plugins/projectexplorer/currentprojectfind.h index 301f97ebe3..244777464f 100644 --- a/src/plugins/projectexplorer/currentprojectfind.h +++ b/src/plugins/projectexplorer/currentprojectfind.h @@ -50,6 +50,7 @@ public: protected: Utils::FileIterator *files(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QVariant &additionalParameters) const override; QVariant additionalParameters() const override; QString label() const override; diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index d6a24dd653..96e812c096 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -36,6 +36,7 @@ #include <coreplugin/find/ifindsupport.h> #include <texteditor/texteditor.h> #include <texteditor/refactoringchanges.h> +#include <utils/algorithm.h> #include <utils/fadingindicator.h> #include <utils/filesearch.h> #include <utils/qtcassert.h> @@ -78,7 +79,8 @@ public: : Utils::findInFiles; return func(parameters.text, - baseFileFind->files(parameters.nameFilters, parameters.additionalParameters), + baseFileFind->files(parameters.nameFilters, parameters.exclusionFilters, + parameters.additionalParameters), textDocumentFlagsForFindFlags(parameters.flags), TextDocument::openedTextDocumentContents()); @@ -114,9 +116,14 @@ public: QPointer<IFindSupport> m_currentFindSupport; QLabel *m_resultLabel = 0; + // models in native path format QStringListModel m_filterStrings; + QStringListModel m_exclusionStrings; + // current filter in portable path format QString m_filterSetting; + QString m_exclusionSetting; QPointer<QComboBox> m_filterCombo; + QPointer<QComboBox> m_exclusionCombo; QVector<SearchEngine *> m_searchEngines; SearchEngine *m_internalSearchEngine; int m_currentSearchEngineIndex = -1; @@ -128,9 +135,10 @@ static void syncComboWithSettings(QComboBox *combo, const QString &setting) { if (!combo) return; - int index = combo->findText(setting); + const QString &nativeSettings = QDir::toNativeSeparators(setting); + int index = combo->findText(nativeSettings); if (index < 0) - combo->setEditText(setting); + combo->setEditText(nativeSettings); else combo->setCurrentIndex(index); } @@ -188,18 +196,27 @@ bool BaseFileFind::isEnabled() const return true; } +static QStringList splitFilterUiText(const QString &text) +{ + const QStringList parts = text.split(','); + const QStringList trimmedPortableParts = Utils::transform(parts, [](const QString &s) { + return QDir::fromNativeSeparators(s.trimmed()); + }); + return Utils::filtered(trimmedPortableParts, [](const QString &s) { return !s.isEmpty(); }); +} + QStringList BaseFileFind::fileNameFilters() const { - QStringList filters; - if (d->m_filterCombo && !d->m_filterCombo->currentText().isEmpty()) { - const QStringList parts = d->m_filterCombo->currentText().split(','); - foreach (const QString &part, parts) { - const QString filter = part.trimmed(); - if (!filter.isEmpty()) - filters << filter; - } - } - return filters; + if (d->m_filterCombo) + return splitFilterUiText(d->m_filterCombo->currentText()); + return QStringList(); +} + +QStringList BaseFileFind::fileExclusionFilters() const +{ + if (d->m_exclusionCombo) + return splitFilterUiText(d->m_exclusionCombo->currentText()); + return QStringList(); } SearchEngine *BaseFileFind::currentSearchEngine() const @@ -248,6 +265,8 @@ void BaseFileFind::runNewSearch(const QString &txt, FindFlags findFlags, d->m_currentFindSupport = 0; if (d->m_filterCombo) updateComboEntries(d->m_filterCombo, true); + if (d->m_exclusionCombo) + updateComboEntries(d->m_exclusionCombo, true); QString tooltip = toolTip(); SearchResult *search = SearchResultWindow::instance()->startNewSearch( @@ -261,6 +280,7 @@ void BaseFileFind::runNewSearch(const QString &txt, FindFlags findFlags, parameters.text = txt; parameters.flags = findFlags; parameters.nameFilters = fileNameFilters(); + parameters.exclusionFilters = fileExclusionFilters(); parameters.additionalParameters = additionalParameters(); parameters.searchEngineParameters = currentSearchEngine()->parameters(); parameters.searchEngineIndex = d->m_currentSearchEngineIndex; @@ -340,46 +360,93 @@ void BaseFileFind::doReplace(const QString &text, } } -QWidget *BaseFileFind::createPatternWidget() +static QComboBox *createCombo(QAbstractItemModel *model) { - QString filterToolTip = tr("List of comma separated wildcard filters"); - d->m_filterCombo = new QComboBox; - d->m_filterCombo->setEditable(true); - d->m_filterCombo->setModel(&d->m_filterStrings); - d->m_filterCombo->setMaxCount(10); - d->m_filterCombo->setMinimumContentsLength(10); - d->m_filterCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); - d->m_filterCombo->setInsertPolicy(QComboBox::InsertAtBottom); - d->m_filterCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + auto combo = new QComboBox; + combo->setEditable(true); + combo->setModel(model); + combo->setMaxCount(10); + combo->setMinimumContentsLength(10); + combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); + combo->setInsertPolicy(QComboBox::InsertAtBottom); + combo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + return combo; +} + +static QLabel *createLabel(const QString &text) +{ + auto filePatternLabel = new QLabel(text); + filePatternLabel->setMinimumWidth(80); + filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + return filePatternLabel; +} + +QList<QPair<QWidget *, QWidget *>> BaseFileFind::createPatternWidgets() +{ + static const QString filterToolTip = tr("List of comma separated wildcard filters. " + "Files with file name or full file path matching any filter are included."); + QLabel *filterLabel = createLabel(tr("Fi&le pattern:")); + d->m_filterCombo = createCombo(&d->m_filterStrings); d->m_filterCombo->setToolTip(filterToolTip); + filterLabel->setBuddy(d->m_filterCombo); syncComboWithSettings(d->m_filterCombo, d->m_filterSetting); - return d->m_filterCombo; + QLabel *exclusionLabel = createLabel(tr("Exclusion pattern:")); + d->m_exclusionCombo = createCombo(&d->m_exclusionStrings); + d->m_exclusionCombo->setToolTip(filterToolTip); + exclusionLabel->setBuddy(d->m_exclusionCombo); + syncComboWithSettings(d->m_exclusionCombo, d->m_exclusionSetting); + return { qMakePair(filterLabel, d->m_filterCombo), + qMakePair(exclusionLabel, d->m_exclusionCombo) }; } void BaseFileFind::writeCommonSettings(QSettings *settings) { - settings->setValue("filters", d->m_filterStrings.stringList()); + std::function<QStringList(const QStringList &)> fromNativeSeparators = [](const QStringList &files) { + return Utils::transform(files, &QDir::fromNativeSeparators); + }; + + settings->setValue("filters", fromNativeSeparators(d->m_filterStrings.stringList())); if (d->m_filterCombo) - settings->setValue("currentFilter", d->m_filterCombo->currentText()); + settings->setValue("currentFilter", + QDir::fromNativeSeparators(d->m_filterCombo->currentText())); + settings->setValue("exclusionFilters", fromNativeSeparators(d->m_exclusionStrings.stringList())); + if (d->m_exclusionCombo) + settings->setValue("currentExclusionFilter", + QDir::fromNativeSeparators(d->m_exclusionCombo->currentText())); foreach (SearchEngine *searchEngine, d->m_searchEngines) searchEngine->writeSettings(settings); settings->setValue("currentSearchEngineIndex", d->m_currentSearchEngineIndex); } -void BaseFileFind::readCommonSettings(QSettings *settings, const QString &defaultFilter) +void BaseFileFind::readCommonSettings(QSettings *settings, const QString &defaultFilter, + const QString &defaultExclusionFilter) { + std::function<QStringList(const QStringList &)> toNativeSeparators = [](const QStringList &files) { + return Utils::transform(files, &QDir::toNativeSeparators); + }; + QStringList filters = settings->value("filters").toStringList(); - const QVariant currentFilter = settings->value("currentFilter"); - d->m_filterSetting = currentFilter.toString(); if (filters.isEmpty()) filters << defaultFilter; - if (!currentFilter.isValid()) - d->m_filterSetting = filters.first(); - d->m_filterStrings.setStringList(filters); + const QVariant currentFilter = settings->value("currentFilter"); + d->m_filterSetting = currentFilter.isValid() ? currentFilter.toString() + : filters.first(); + d->m_filterStrings.setStringList(toNativeSeparators(filters)); if (d->m_filterCombo) syncComboWithSettings(d->m_filterCombo, d->m_filterSetting); + QStringList exclusionFilters = settings->value("exclusionFilters").toStringList(); + if (exclusionFilters.isEmpty()) + exclusionFilters << defaultExclusionFilter; + const QVariant currentExclusionFilter = settings->value("currentExclusionFilter"); + d->m_exclusionSetting = currentExclusionFilter.isValid() ? currentExclusionFilter.toString() + : exclusionFilters.first(); + d->m_exclusionStrings.setStringList(toNativeSeparators(exclusionFilters)); + if (d->m_exclusionCombo) + syncComboWithSettings(d->m_exclusionCombo, d->m_exclusionSetting); + foreach (SearchEngine* searchEngine, d->m_searchEngines) searchEngine->readSettings(settings); const int currentSearchEngineIndex = settings->value("currentSearchEngineIndex", 0).toInt(); diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h index 2a7b2bc151..56bbb4e5fd 100644 --- a/src/plugins/texteditor/basefilefind.h +++ b/src/plugins/texteditor/basefilefind.h @@ -57,11 +57,12 @@ class TEXTEDITOR_EXPORT FileFindParameters { public: QString text; - Core::FindFlags flags; QStringList nameFilters; + QStringList exclusionFilters; QVariant additionalParameters; - int searchEngineIndex; QVariant searchEngineParameters; + int searchEngineIndex; + Core::FindFlags flags; }; class BaseFileFind; @@ -111,6 +112,7 @@ public: const QList<Core::SearchResultItem> &items, bool preserveCase = false); virtual Utils::FileIterator *files(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QVariant &additionalParameters) const = 0; protected: @@ -122,9 +124,10 @@ protected: QFuture<Utils::FileSearchResultList> executeSearch(const FileFindParameters ¶meters); void writeCommonSettings(QSettings *settings); - void readCommonSettings(QSettings *settings, const QString &defaultFilter); - QWidget *createPatternWidget(); + void readCommonSettings(QSettings *settings, const QString &defaultFilter, const QString &defaultExclusionFilter); + QList<QPair<QWidget *, QWidget *>> createPatternWidgets(); QStringList fileNameFilters() const; + QStringList fileExclusionFilters() const; SearchEngine *currentSearchEngine() const; QVector<SearchEngine *> searchEngines() const; diff --git a/src/plugins/texteditor/findincurrentfile.cpp b/src/plugins/texteditor/findincurrentfile.cpp index 03395955dd..df568a1311 100644 --- a/src/plugins/texteditor/findincurrentfile.cpp +++ b/src/plugins/texteditor/findincurrentfile.cpp @@ -57,9 +57,11 @@ QString FindInCurrentFile::displayName() const } Utils::FileIterator *FindInCurrentFile::files(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QVariant &additionalParameters) const { Q_UNUSED(nameFilters) + Q_UNUSED(exclusionFilters) QString fileName = additionalParameters.toString(); QMap<QString, QTextCodec *> openEditorEncodings = TextDocument::openedTextDocumentEncodings(); QTextCodec *codec = openEditorEncodings.value(fileName); @@ -116,6 +118,6 @@ void FindInCurrentFile::writeSettings(QSettings *settings) void FindInCurrentFile::readSettings(QSettings *settings) { settings->beginGroup(QLatin1String("FindInCurrentFile")); - readCommonSettings(settings, QLatin1String("*")); + readCommonSettings(settings, "*", ""); settings->endGroup(); } diff --git a/src/plugins/texteditor/findincurrentfile.h b/src/plugins/texteditor/findincurrentfile.h index 354680d63d..4f1295d818 100644 --- a/src/plugins/texteditor/findincurrentfile.h +++ b/src/plugins/texteditor/findincurrentfile.h @@ -52,6 +52,7 @@ public: protected: Utils::FileIterator *files(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QVariant &additionalParameters) const; QVariant additionalParameters() const; QString label() const; diff --git a/src/plugins/texteditor/findinfiles.cpp b/src/plugins/texteditor/findinfiles.cpp index 8c882e2d85..72ec48f204 100644 --- a/src/plugins/texteditor/findinfiles.cpp +++ b/src/plugins/texteditor/findinfiles.cpp @@ -80,10 +80,12 @@ QString FindInFiles::displayName() const } FileIterator *FindInFiles::files(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QVariant &additionalParameters) const { return new SubDirFileIterator(QStringList() << additionalParameters.toString(), nameFilters, + exclusionFilters, EditorManager::defaultTextCodec()); } @@ -107,9 +109,10 @@ QString FindInFiles::label() const QString FindInFiles::toolTip() const { //: the last arg is filled by BaseFileFind::runNewSearch - QString tooltip = tr("Path: %1\nFilter: %2\n%3") + QString tooltip = tr("Path: %1\nFilter: %2\nExcluding: %3\n%4") .arg(path().toUserOutput()) - .arg(fileNameFilters().join(QLatin1Char(','))); + .arg(fileNameFilters().join(',')) + .arg(fileExclusionFilters().join(',')); const QString searchEngineToolTip = currentSearchEngine()->toolTip(); if (!searchEngineToolTip.isEmpty()) @@ -183,14 +186,12 @@ QWidget *FindInFiles::createConfigWidget() dirLabel->setBuddy(m_directory); gridLayout->addWidget(m_directory, row++, 1, 1, 2); - QLabel * const filePatternLabel = new QLabel(tr("Fi&le pattern:")); - filePatternLabel->setMinimumWidth(80); - filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); - filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - QWidget *patternWidget = createPatternWidget(); - filePatternLabel->setBuddy(patternWidget); - gridLayout->addWidget(filePatternLabel, row, 0); - gridLayout->addWidget(patternWidget, row++, 1, 1, 2); + const QList<QPair<QWidget *, QWidget *>> patternWidgets = createPatternWidgets(); + for (const QPair<QWidget *, QWidget *> &p : patternWidgets) { + gridLayout->addWidget(p.first, row, 0, Qt::AlignRight); + gridLayout->addWidget(p.second, row, 1, 1, 2); + ++row; + } m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); // validity @@ -221,7 +222,7 @@ void FindInFiles::writeSettings(QSettings *settings) void FindInFiles::readSettings(QSettings *settings) { settings->beginGroup(QLatin1String("FindInFiles")); - readCommonSettings(settings, QLatin1String("*.cpp,*.h")); + readCommonSettings(settings, "*.cpp,*.h", "*/.git/*,*/.cvs/*,*/.svn/*"); settings->endGroup(); } diff --git a/src/plugins/texteditor/findinfiles.h b/src/plugins/texteditor/findinfiles.h index e27c445b15..eb69ced567 100644 --- a/src/plugins/texteditor/findinfiles.h +++ b/src/plugins/texteditor/findinfiles.h @@ -66,6 +66,7 @@ signals: protected: Utils::FileIterator *files(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QVariant &additionalParameters) const override; QVariant additionalParameters() const override; QString label() const override; diff --git a/src/plugins/texteditor/findinopenfiles.cpp b/src/plugins/texteditor/findinopenfiles.cpp index 8aa8289522..80f0e13097 100644 --- a/src/plugins/texteditor/findinopenfiles.cpp +++ b/src/plugins/texteditor/findinopenfiles.cpp @@ -56,9 +56,11 @@ QString FindInOpenFiles::displayName() const } Utils::FileIterator *FindInOpenFiles::files(const QStringList &nameFilters, - const QVariant &additionalParameters) const + const QStringList &exclusionFilters, + const QVariant &additionalParameters) const { Q_UNUSED(nameFilters) + Q_UNUSED(exclusionFilters) Q_UNUSED(additionalParameters) QMap<QString, QTextCodec *> openEditorEncodings = TextDocument::openedTextDocumentEncodings(); @@ -110,7 +112,7 @@ void FindInOpenFiles::writeSettings(QSettings *settings) void FindInOpenFiles::readSettings(QSettings *settings) { settings->beginGroup(QLatin1String("FindInOpenFiles")); - readCommonSettings(settings, QLatin1String("*")); + readCommonSettings(settings, "*", ""); settings->endGroup(); } diff --git a/src/plugins/texteditor/findinopenfiles.h b/src/plugins/texteditor/findinopenfiles.h index 759636c1ae..6caf7936af 100644 --- a/src/plugins/texteditor/findinopenfiles.h +++ b/src/plugins/texteditor/findinopenfiles.h @@ -45,6 +45,7 @@ public: protected: Utils::FileIterator *files(const QStringList &nameFilters, + const QStringList &exclusionFilters, const QVariant &additionalParameters) const; QVariant additionalParameters() const; QString label() const; |