Commit 0eeb590f authored by Eike Ziller's avatar Eike Ziller

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: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent 94e85778
......@@ -32,6 +32,7 @@
#include <coreplugin/editormanager/editormanager.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <QDir>
#include <QStringMatcher>
......@@ -42,6 +43,11 @@ using namespace Utils;
BaseFileFilter::BaseFileFilter()
: m_forceNewSearchList(false)
{
setFileIterator(new ListIterator(QStringList()));
}
BaseFileFilter::~BaseFileFilter()
{
}
......@@ -59,32 +65,32 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
const QChar pathSeparator(QLatin1Char('/'));
const bool hasPathSeparator = needle.contains(pathSeparator);
const bool hasWildcard = needle.contains(asterisk) || needle.contains(QLatin1Char('?'));
QStringList searchListPaths;
QStringList searchListNames;
const bool containsPreviousEntry = !m_previousEntry.isEmpty()
&& needle.contains(m_previousEntry);
const bool pathSeparatorAdded = !m_previousEntry.contains(pathSeparator)
&& needle.contains(pathSeparator);
if (!m_forceNewSearchList && containsPreviousEntry && !pathSeparatorAdded) {
searchListPaths = m_previousResultPaths;
searchListNames = m_previousResultNames;
} else {
searchListPaths = m_files;
searchListNames = m_fileNames;
}
const bool searchInPreviousResults = !m_forceNewSearchList && containsPreviousEntry
&& !pathSeparatorAdded;
QSharedPointer<Iterator> iterator;
if (searchInPreviousResults)
iterator.reset(new ListIterator(m_previousResultPaths, m_previousResultNames));
else
iterator = fileIterator();
QTC_ASSERT(iterator.data(), return QList<LocatorFilterEntry>());
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::Iterator> 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;
}
......@@ -33,6 +33,7 @@
#include "ilocatorfilter.h"
#include <QSharedPointer>
#include <QStringList>
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<LocatorFilterEntry> matchesFor(QFutureInterface<LocatorFilterEntry> &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<Iterator> fileIterator();
private:
QStringList m_files;
QStringList m_fileNames;
QSharedPointer<Iterator> m_iterator;
QStringList m_previousResultPaths;
QStringList m_previousResultNames;
bool m_forceNewSearchList;
......
......@@ -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<void> &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<void> &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()));
......
......@@ -67,6 +67,7 @@ private:
QDialog *m_dialog;
Ui::DirectoryFilterOptions m_ui;
mutable QMutex m_lock;
QStringList m_files;
};
} // namespace Internal
......
......@@ -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<void> &) {}
......
......@@ -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;
}
......
......@@ -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)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment