From 0eeb590fdfbbdc9f94f456444d65aa3c73b14c8b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 10 Dec 2014 11:29:33 +0100 Subject: [PATCH] Locator BaseFileFilter: Iterator based API for list of files There are situations where we can generate the list of files on the fly in the worker thread instead of generating the full file list in the UI thread beforehand. Change the API to support that. Change-Id: I331336f4b019184ba0da311b66e6283029c612c4 Reviewed-by: Nikolai Kosjar --- .../coreplugin/locator/basefilefilter.cpp | 111 +++++++++++++++--- .../coreplugin/locator/basefilefilter.h | 41 +++++-- .../coreplugin/locator/directoryfilter.cpp | 14 +-- .../coreplugin/locator/directoryfilter.h | 1 + .../coreplugin/locator/locator_test.cpp | 4 +- .../projectexplorer/allprojectsfilter.cpp | 9 +- .../projectexplorer/currentprojectfilter.cpp | 13 +- 7 files changed, 147 insertions(+), 46 deletions(-) diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index 9a3b219fc70..69a25c71aee 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -42,6 +43,11 @@ using namespace Utils; BaseFileFilter::BaseFileFilter() : m_forceNewSearchList(false) +{ + setFileIterator(new ListIterator(QStringList())); +} + +BaseFileFilter::~BaseFileFilter() { } @@ -59,32 +65,32 @@ QList BaseFileFilter::matchesFor(QFutureInterface iterator; + if (searchInPreviousResults) + iterator.reset(new ListIterator(m_previousResultPaths, m_previousResultNames)); + else + iterator = fileIterator(); + + QTC_ASSERT(iterator.data(), return QList()); m_previousResultPaths.clear(); m_previousResultNames.clear(); m_forceNewSearchList = false; m_previousEntry = needle; const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(needle); - QStringListIterator paths(searchListPaths); - QStringListIterator names(searchListNames); - while (paths.hasNext() && names.hasNext()) { + iterator->toFront(); + while (iterator->hasNext()) { if (future.isCanceled()) break; - QString path = paths.next(); - QString name = names.next(); + iterator->next(); + QString path = iterator->filePath(); + QString name = iterator->fileName(); QString matchText = hasPathSeparator ? path : name; if ((hasWildcard && regexp.exactMatch(matchText)) || (!hasWildcard && matcher.indexIn(matchText) != -1)) { @@ -111,12 +117,79 @@ void BaseFileFilter::accept(LocatorFilterEntry selection) const EditorManager::CanContainLineNumber); } -void BaseFileFilter::generateFileNames() +void BaseFileFilter::invalidateCachedResults() { - m_fileNames.clear(); - foreach (const QString &fileName, m_files) { - QFileInfo fi(fileName); + m_forceNewSearchList = true; + m_previousEntry.clear(); + m_previousResultPaths.clear(); + m_previousResultNames.clear(); +} + +/*! + Takes ownership of the \a iterator. The previously set iterator might not be deleted until + a currently running search is finished. +*/ + +void BaseFileFilter::setFileIterator(BaseFileFilter::Iterator *iterator) +{ + invalidateCachedResults(); + m_iterator.reset(iterator); +} + +QSharedPointer BaseFileFilter::fileIterator() +{ + return m_iterator; +} + +BaseFileFilter::ListIterator::ListIterator(const QStringList &filePaths) +{ + m_filePaths = filePaths; + foreach (const QString &path, m_filePaths) { + QFileInfo fi(path); m_fileNames.append(fi.fileName()); } - m_forceNewSearchList = true; + toFront(); +} + +BaseFileFilter::ListIterator::ListIterator(const QStringList &filePaths, + const QStringList &fileNames) +{ + m_filePaths = filePaths; + m_fileNames = fileNames; + toFront(); +} + +void BaseFileFilter::ListIterator::toFront() +{ + m_pathPosition = m_filePaths.constBegin() - 1; + m_namePosition = m_fileNames.constBegin() - 1; +} + +bool BaseFileFilter::ListIterator::hasNext() const +{ + QTC_ASSERT(m_pathPosition != m_filePaths.constEnd(), return false); + return m_pathPosition + 1 != m_filePaths.constEnd(); +} + +QString BaseFileFilter::ListIterator::next() +{ + QTC_ASSERT(m_pathPosition != m_filePaths.constEnd(), return QString()); + QTC_ASSERT(m_namePosition != m_fileNames.constEnd(), return QString()); + ++m_pathPosition; + ++m_namePosition; + QTC_ASSERT(m_pathPosition != m_filePaths.constEnd(), return QString()); + QTC_ASSERT(m_namePosition != m_fileNames.constEnd(), return QString()); + return *m_pathPosition; +} + +QString BaseFileFilter::ListIterator::filePath() const +{ + QTC_ASSERT(m_pathPosition != m_filePaths.constEnd(), return QString()); + return *m_pathPosition; +} + +QString BaseFileFilter::ListIterator::fileName() const +{ + QTC_ASSERT(m_namePosition != m_fileNames.constEnd(), return QString()); + return *m_namePosition; } diff --git a/src/plugins/coreplugin/locator/basefilefilter.h b/src/plugins/coreplugin/locator/basefilefilter.h index 4d97fa11426..99ce10a5410 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.h +++ b/src/plugins/coreplugin/locator/basefilefilter.h @@ -33,6 +33,7 @@ #include "ilocatorfilter.h" +#include #include namespace Core { @@ -42,21 +43,47 @@ class CORE_EXPORT BaseFileFilter : public ILocatorFilter Q_OBJECT public: + class Iterator { + public: + virtual ~Iterator() { } + virtual void toFront() = 0; + virtual bool hasNext() const = 0; + virtual QString next() = 0; + virtual QString filePath() const = 0; + virtual QString fileName() const = 0; + }; + + class ListIterator : public Iterator { + public: + ListIterator(const QStringList &filePaths); + ListIterator(const QStringList &filePaths, const QStringList &fileNames); + + void toFront(); + bool hasNext() const; + QString next(); + QString filePath() const; + QString fileName() const; + + private: + QStringList m_filePaths; + QStringList m_fileNames; + QStringList::const_iterator m_pathPosition; + QStringList::const_iterator m_namePosition; + }; + BaseFileFilter(); + ~BaseFileFilter(); QList matchesFor(QFutureInterface &future, const QString &entry); void accept(LocatorFilterEntry selection) const; protected: - /* Generates the file names from the list of file paths in m_files. */ - void generateFileNames(); + void invalidateCachedResults(); - /* Subclasses should update the file list latest in their prepareSearch method. */ - inline QStringList &files() { return m_files; } - inline const QStringList &files() const { return m_files; } + void setFileIterator(Iterator *iterator); + QSharedPointer fileIterator(); private: - QStringList m_files; - QStringList m_fileNames; + QSharedPointer m_iterator; QStringList m_previousResultPaths; QStringList m_previousResultNames; bool m_forceNewSearchList; diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 13eff6a9878..47bd87b4fae 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -59,7 +59,7 @@ QByteArray DirectoryFilter::saveState() const out << m_filters; out << shortcutString(); out << isIncludedByDefault(); - out << files(); + out << m_files; return value; } @@ -77,13 +77,13 @@ bool DirectoryFilter::restoreState(const QByteArray &state) in >> m_filters; in >> shortcut; in >> defaultFilter; - in >> files(); + in >> m_files; setDisplayName(name); setShortcutString(shortcut); setIncludedByDefault(defaultFilter); - generateFileNames(); + setFileIterator(new BaseFileFilter::ListIterator(m_files)); return true; } @@ -175,8 +175,8 @@ void DirectoryFilter::refresh(QFutureInterface &future) { QMutexLocker locker(&m_lock); if (m_directories.count() < 1) { - files().clear(); - generateFileNames(); + m_files.clear(); + setFileIterator(new BaseFileFilter::ListIterator(m_files)); future.setProgressRange(0, 1); future.setProgressValueAndText(1, tr("%1 filter update: 0 files").arg(displayName())); return; @@ -197,8 +197,8 @@ void DirectoryFilter::refresh(QFutureInterface &future) if (!future.isCanceled()) { QMutexLocker locker(&m_lock); - files() = filesFound; - generateFileNames(); + m_files = filesFound; + setFileIterator(new BaseFileFilter::ListIterator(m_files)); future.setProgressValue(it.maxProgress()); } else { future.setProgressValueAndText(it.currentProgress(), tr("%1 filter update: canceled").arg(displayName())); diff --git a/src/plugins/coreplugin/locator/directoryfilter.h b/src/plugins/coreplugin/locator/directoryfilter.h index 914c4e678db..7b1018dc23e 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.h +++ b/src/plugins/coreplugin/locator/directoryfilter.h @@ -67,6 +67,7 @@ private: QDialog *m_dialog; Ui::DirectoryFilterOptions m_ui; mutable QMutex m_lock; + QStringList m_files; }; } // namespace Internal diff --git a/src/plugins/coreplugin/locator/locator_test.cpp b/src/plugins/coreplugin/locator/locator_test.cpp index 698fb8159bb..59ae6884045 100644 --- a/src/plugins/coreplugin/locator/locator_test.cpp +++ b/src/plugins/coreplugin/locator/locator_test.cpp @@ -52,9 +52,7 @@ class MyBaseFileFilter : public Core::BaseFileFilter public: MyBaseFileFilter(const QStringList &theFiles) { - files().clear(); - files().append(theFiles); - BaseFileFilter::generateFileNames(); + setFileIterator(new BaseFileFilter::ListIterator(theFiles)); } void refresh(QFutureInterface &) {} diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp index db3ae2365c0..83bf8caf34e 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.cpp +++ b/src/plugins/projectexplorer/allprojectsfilter.cpp @@ -56,6 +56,7 @@ void AllProjectsFilter::markFilesAsOutOfDate() { QMutexLocker lock(&m_mutex); Q_UNUSED(lock) m_filesUpToDate = false; + invalidateCachedResults(); } void AllProjectsFilter::prepareSearch(const QString &entry) @@ -64,11 +65,11 @@ void AllProjectsFilter::prepareSearch(const QString &entry) QMutexLocker lock(&m_mutex); Q_UNUSED(lock) if (m_filesUpToDate) return; - files().clear(); + QStringList paths; foreach (Project *project, SessionManager::projects()) - files().append(project->files(Project::AllFiles)); - Utils::sort(files()); - generateFileNames(); + paths.append(project->files(Project::AllFiles)); + Utils::sort(paths); + setFileIterator(new BaseFileFilter::ListIterator(paths)); m_filesUpToDate = true; } diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp index 783fd42230f..25815f22740 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.cpp +++ b/src/plugins/projectexplorer/currentprojectfilter.cpp @@ -56,6 +56,7 @@ void CurrentProjectFilter::markFilesAsOutOfDate() { QMutexLocker lock(&m_filesUpToDateMutex); Q_UNUSED(lock) m_filesUpToDate = false; + invalidateCachedResults(); } void CurrentProjectFilter::prepareSearch(const QString &entry) @@ -64,13 +65,13 @@ void CurrentProjectFilter::prepareSearch(const QString &entry) QMutexLocker lock(&m_filesUpToDateMutex); Q_UNUSED(lock) if (m_filesUpToDate) return; - files().clear(); m_filesUpToDate = true; - if (!m_project) - return; - files() = m_project->files(Project::AllFiles); - Utils::sort(files()); - generateFileNames(); + QStringList paths; + if (m_project) { + paths = m_project->files(Project::AllFiles); + Utils::sort(paths); + } + setFileIterator(new BaseFileFilter::ListIterator(paths)); } void CurrentProjectFilter::currentProjectChanged(ProjectExplorer::Project *project)