diff options
author | Eike Ziller <eike.ziller@theqtcompany.com> | 2015-01-07 17:03:39 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@theqtcompany.com> | 2015-01-12 15:03:57 +0100 |
commit | 9c088727a85c0c203529cca14a4c36c745bb348d (patch) | |
tree | 0fac2ca38af07a66284fea782d3a560e98046b87 /src/plugins/coreplugin/locator/basefilefilter.cpp | |
parent | ac77a8d10e351050e66a838040a144717b22a377 (diff) |
Locator: API thread-safety improvements in BaseFileFilter
Make it possible to set or clear the file iterator while a search is
currently running.
Change-Id: I5309a8920057112375ce22e5fd24806fb6f09857
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
Diffstat (limited to 'src/plugins/coreplugin/locator/basefilefilter.cpp')
-rw-r--r-- | src/plugins/coreplugin/locator/basefilefilter.cpp | 130 |
1 files changed, 94 insertions, 36 deletions
diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index 69a25c71aee..470db3e0248 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -36,19 +36,63 @@ #include <QDir> #include <QStringMatcher> +#include <QTimer> using namespace Core; -using namespace Core; using namespace Utils; +namespace Core { +namespace Internal { + +class Data +{ +public: + void clear() + { + iterator.clear(); + previousResultPaths.clear(); + previousResultNames.clear(); + previousEntry.clear(); + } + + QSharedPointer<BaseFileFilter::Iterator> iterator; + QStringList previousResultPaths; + QStringList previousResultNames; + bool forceNewSearchList; + QString previousEntry; +}; + +class BaseFileFilterPrivate +{ +public: + Data m_data; + Data m_current; +}; + +} // Internal +} // Core + BaseFileFilter::BaseFileFilter() - : m_forceNewSearchList(false) + : d(new Internal::BaseFileFilterPrivate) { + d->m_data.forceNewSearchList = true; setFileIterator(new ListIterator(QStringList())); } BaseFileFilter::~BaseFileFilter() { + delete d; +} + +void BaseFileFilter::prepareSearch(const QString &entry) +{ + Q_UNUSED(entry) + d->m_current.iterator = d->m_data.iterator; + d->m_current.previousResultPaths = d->m_data.previousResultPaths; + d->m_current.previousResultNames = d->m_data.previousResultNames; + d->m_current.forceNewSearchList = d->m_data.forceNewSearchList; + d->m_current.previousEntry = d->m_data.previousEntry; + d->m_data.forceNewSearchList = false; } QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFilterEntry> &future, const QString &origEntry) @@ -60,37 +104,39 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil QStringMatcher matcher(needle, Qt::CaseInsensitive); const QChar asterisk = QLatin1Char('*'); QRegExp regexp(asterisk + needle+ asterisk, Qt::CaseInsensitive, QRegExp::Wildcard); - if (!regexp.isValid()) + if (!regexp.isValid()) { + d->m_current.clear(); // free memory return betterEntries; + } const QChar pathSeparator(QLatin1Char('/')); const bool hasPathSeparator = needle.contains(pathSeparator); const bool hasWildcard = needle.contains(asterisk) || needle.contains(QLatin1Char('?')); - const bool containsPreviousEntry = !m_previousEntry.isEmpty() - && needle.contains(m_previousEntry); - const bool pathSeparatorAdded = !m_previousEntry.contains(pathSeparator) + const bool containsPreviousEntry = !d->m_current.previousEntry.isEmpty() + && needle.contains(d->m_current.previousEntry); + const bool pathSeparatorAdded = !d->m_current.previousEntry.contains(pathSeparator) && needle.contains(pathSeparator); - const bool searchInPreviousResults = !m_forceNewSearchList && containsPreviousEntry + const bool searchInPreviousResults = !d->m_current.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; + d->m_current.iterator.reset(new ListIterator(d->m_current.previousResultPaths, + d->m_current.previousResultNames)); + + QTC_ASSERT(d->m_current.iterator.data(), return QList<LocatorFilterEntry>()); + d->m_current.previousResultPaths.clear(); + d->m_current.previousResultNames.clear(); + d->m_current.previousEntry = needle; const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(needle); - iterator->toFront(); - while (iterator->hasNext()) { - if (future.isCanceled()) + d->m_current.iterator->toFront(); + bool canceled = false; + while (d->m_current.iterator->hasNext()) { + if (future.isCanceled()) { + canceled = true; break; + } - iterator->next(); - QString path = iterator->filePath(); - QString name = iterator->fileName(); + d->m_current.iterator->next(); + QString path = d->m_current.iterator->filePath(); + QString name = d->m_current.iterator->fileName(); QString matchText = hasPathSeparator ? path : name; if ((hasWildcard && regexp.exactMatch(matchText)) || (!hasWildcard && matcher.indexIn(matchText) != -1)) { @@ -102,12 +148,21 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil betterEntries.append(entry); else goodEntries.append(entry); - m_previousResultPaths.append(path); - m_previousResultNames.append(name); + d->m_current.previousResultPaths.append(path); + d->m_current.previousResultNames.append(name); } } betterEntries.append(goodEntries); + if (canceled) { + // we keep the old list of previous search results if this search was canceled + // so a later search without foreNewSearchList will use that previous list instead of an + // incomplete list of a canceled search + d->m_current.clear(); // free memory + } else { + d->m_current.iterator.clear(); + QTimer::singleShot(0, this, SLOT(updatePreviousResultData())); + } return betterEntries; } @@ -117,14 +172,6 @@ void BaseFileFilter::accept(LocatorFilterEntry selection) const EditorManager::CanContainLineNumber); } -void BaseFileFilter::invalidateCachedResults() -{ - 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. @@ -132,13 +179,24 @@ void BaseFileFilter::invalidateCachedResults() void BaseFileFilter::setFileIterator(BaseFileFilter::Iterator *iterator) { - invalidateCachedResults(); - m_iterator.reset(iterator); + d->m_data.clear(); + d->m_data.forceNewSearchList = true; + d->m_data.iterator.reset(iterator); } QSharedPointer<BaseFileFilter::Iterator> BaseFileFilter::fileIterator() { - return m_iterator; + return d->m_data.iterator; +} + +void BaseFileFilter::updatePreviousResultData() +{ + if (d->m_data.forceNewSearchList) // in the meantime the iterator was reset / cache invalidated + return; // do not update with the new result list etc + d->m_data.previousEntry = d->m_current.previousEntry; + d->m_data.previousResultPaths = d->m_current.previousResultPaths; + d->m_data.previousResultNames = d->m_current.previousResultNames; + // forceNewSearchList was already reset in prepareSearch } BaseFileFilter::ListIterator::ListIterator(const QStringList &filePaths) |