diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index 677a678959d3e26be858a73055b65b833614c908..396321547747ab1056d3c1f4d69eeb0b5abe1179 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -70,11 +70,11 @@ namespace { void runFileSearch(QFutureInterface<FileSearchResult> &future, QString searchTerm, - QStringList files, + FileIterator *files, QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap) { - future.setProgressRange(0, files.size()); + future.setProgressRange(0, files->maxProgress()); int numFilesSearched = 0; int numMatches = 0; @@ -95,11 +95,13 @@ void runFileSearch(QFutureInterface<FileSearchResult> &future, QFile file; QBuffer buffer; - foreach (const QString &s, files) { + while (files->hasNext()) { + const QString &s = files->next(); + future.setProgressRange(0, files->maxProgress()); if (future.isPaused()) future.waitForResume(); if (future.isCanceled()) { - future.setProgressValueAndText(numFilesSearched, msgCanceled(searchTerm, numMatches, numFilesSearched)); + future.setProgressValueAndText(files->currentProgress(), msgCanceled(searchTerm, numMatches, numFilesSearched)); break; } QIODevice *device; @@ -180,20 +182,22 @@ void runFileSearch(QFutureInterface<FileSearchResult> &future, firstChunk = false; } ++numFilesSearched; - future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched, files.size())); + if (future.isProgressUpdateNeeded()) + future.setProgressValueAndText(files->currentProgress(), msgFound(searchTerm, numMatches, numFilesSearched)); device->close(); } if (!future.isCanceled()) - future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched)); + future.setProgressValueAndText(files->currentProgress(), msgFound(searchTerm, numMatches, numFilesSearched)); + delete files; } void runFileSearchRegExp(QFutureInterface<FileSearchResult> &future, QString searchTerm, - QStringList files, + FileIterator *files, QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap) { - future.setProgressRange(0, files.size()); + future.setProgressRange(0, files->maxProgress()); int numFilesSearched = 0; int numMatches = 0; if (flags & QTextDocument::FindWholeWords) @@ -204,11 +208,13 @@ void runFileSearchRegExp(QFutureInterface<FileSearchResult> &future, QFile file; QString str; QTextStream stream; - foreach (const QString &s, files) { + while (files->hasNext()) { + const QString &s = files->next(); + future.setProgressRange(0, files->maxProgress()); if (future.isPaused()) future.waitForResume(); if (future.isCanceled()) { - future.setProgressValueAndText(numFilesSearched, msgCanceled(searchTerm, numMatches, numFilesSearched)); + future.setProgressValueAndText(files->currentProgress(), msgCanceled(searchTerm, numMatches, numFilesSearched)); break; } @@ -237,28 +243,30 @@ void runFileSearchRegExp(QFutureInterface<FileSearchResult> &future, ++lineNr; } ++numFilesSearched; - future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched, files.size())); + if (future.isProgressUpdateNeeded()) + future.setProgressValueAndText(files->currentProgress(), msgFound(searchTerm, numMatches, numFilesSearched)); if (needsToCloseFile) file.close(); } if (!future.isCanceled()) - future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched)); + future.setProgressValueAndText(files->currentProgress(), msgFound(searchTerm, numMatches, numFilesSearched)); + delete files; } } // namespace -QFuture<FileSearchResult> Utils::findInFiles(const QString &searchTerm, const QStringList &files, +QFuture<FileSearchResult> Utils::findInFiles(const QString &searchTerm, FileIterator *files, QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap) { - return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags, QMap<QString, QString> > + return QtConcurrent::run<FileSearchResult, QString, FileIterator *, QTextDocument::FindFlags, QMap<QString, QString> > (runFileSearch, searchTerm, files, flags, fileToContentsMap); } -QFuture<FileSearchResult> Utils::findInFilesRegExp(const QString &searchTerm, const QStringList &files, +QFuture<FileSearchResult> Utils::findInFilesRegExp(const QString &searchTerm, FileIterator *files, QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap) { - return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags, QMap<QString, QString> > + return QtConcurrent::run<FileSearchResult, QString, FileIterator *, QTextDocument::FindFlags, QMap<QString, QString> > (runFileSearchRegExp, searchTerm, files, flags, fileToContentsMap); } @@ -294,3 +302,133 @@ QString Utils::expandRegExpReplacement(const QString &replaceText, const QString } return result; } + +// #pragma mark -- FileIterator + +FileIterator::FileIterator() + : m_list(QStringList()), + m_iterator(0), + m_index(0) +{ +} + +FileIterator::FileIterator(const QStringList &fileList) + : m_list(fileList), + m_iterator(new QStringListIterator(m_list)), + m_index(0) +{ +} + +FileIterator::~FileIterator() +{ + if (m_iterator) + delete m_iterator; +} + +bool FileIterator::hasNext() const +{ + Q_ASSERT(m_iterator); + return m_iterator->hasNext(); +} + +QString FileIterator::next() +{ + Q_ASSERT(m_iterator); + ++m_index; + return m_iterator->next(); +} + +int FileIterator::maxProgress() const +{ + return m_list.size(); +} + +int FileIterator::currentProgress() const +{ + return m_index; +} + +// #pragma mark -- SubDirFileIterator + +namespace { + const int MAX_PROGRESS = 360; +} + +SubDirFileIterator::SubDirFileIterator(const QStringList &directories, const QStringList &filters) + : m_filters(filters), m_progress(0) +{ + int maxPer = MAX_PROGRESS/directories.count(); + foreach (const QString &directoryEntry, directories) { + if (!directoryEntry.isEmpty()) { + m_dirs.push(QDir(directoryEntry)); + m_progressValues.push(maxPer); + m_processedValues.push(false); + } + } +} + +bool SubDirFileIterator::hasNext() const +{ + if (!m_currentFiles.isEmpty()) + return true; + while(!m_dirs.isEmpty() && m_currentFiles.isEmpty()) { + QDir dir = m_dirs.pop(); + int dirProgressMax = m_progressValues.pop(); + bool processed = m_processedValues.pop(); + if (dir.exists()) { + 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(); + while (it.hasPrevious()) { + const QString &file = it.previous(); + m_currentFiles.append(dir.path()+ QLatin1Char('/') +file); + } + m_progress += dirProgressMax; + } else { + int subProgress = dirProgressMax/(subDirs.size()+1); + int selfProgress = subProgress + dirProgressMax%(subDirs.size()+1); + m_dirs.push(dir); + m_progressValues.push(selfProgress); + m_processedValues.push(true); + QStringListIterator it(subDirs); + it.toBack(); + while (it.hasPrevious()) { + const QString &directory = it.previous(); + m_dirs.push(QDir(dir.path()+ QLatin1Char('/') + directory)); + m_progressValues.push(subProgress); + m_processedValues.push(false); + } + } + } else { + m_progress += dirProgressMax; + } + } + if (m_currentFiles.isEmpty()) { + m_progress = MAX_PROGRESS; + return false; + } + + return true; +} + +QString SubDirFileIterator::next() +{ + Q_ASSERT(!m_currentFiles.isEmpty()); + return m_currentFiles.takeFirst(); +} + +int SubDirFileIterator::maxProgress() const +{ + return MAX_PROGRESS; +} + +int SubDirFileIterator::currentProgress() const +{ + return m_progress; +} diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h index f2860e34e0147c4bb6990326ca53ef1da539f360..0b3f895387028be30191ee656a90abd26a15a309 100644 --- a/src/libs/utils/filesearch.h +++ b/src/libs/utils/filesearch.h @@ -35,10 +35,49 @@ #include <QtCore/QStringList> #include <QtCore/QFuture> #include <QtCore/QMap> +#include <QtCore/QStack> +#include <QtCore/QDir> #include <QtGui/QTextDocument> namespace Utils { +class QTCREATOR_UTILS_EXPORT FileIterator +{ +public: + FileIterator(); + explicit FileIterator(const QStringList &fileList); + ~FileIterator(); + + virtual bool hasNext() const; + virtual QString next(); + virtual int maxProgress() const; + virtual int currentProgress() const; + +private: + QStringList m_list; + QStringListIterator *m_iterator; + int m_index; +}; + +class QTCREATOR_UTILS_EXPORT SubDirFileIterator : public FileIterator +{ +public: + SubDirFileIterator(const QStringList &directories, const QStringList &filters); + + bool hasNext() const; + QString next(); + int maxProgress() const; + int currentProgress() const; + +private: + QStringList m_filters; + mutable QStack<QDir> m_dirs; + mutable QStack<int> m_progressValues; + mutable QStack<bool> m_processedValues; + mutable int m_progress; + mutable QStringList m_currentFiles; +}; + class QTCREATOR_UTILS_EXPORT FileSearchResult { public: @@ -62,10 +101,10 @@ public: QStringList regexpCapturedTexts; }; -QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFiles(const QString &searchTerm, const QStringList &files, +QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFiles(const QString &searchTerm, FileIterator *files, QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap = QMap<QString, QString>()); -QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFilesRegExp(const QString &searchTerm, const QStringList &files, +QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFilesRegExp(const QString &searchTerm, FileIterator *files, QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap = QMap<QString, QString>()); QTCREATOR_UTILS_EXPORT QString expandRegExpReplacement(const QString &replaceText, const QStringList &capturedTexts); diff --git a/src/plugins/locator/directoryfilter.cpp b/src/plugins/locator/directoryfilter.cpp index 7049d50c0661a6d257aa12f91c6546bddd3f9360..b41cd6c59390713751c62f428c876248b011129c 100644 --- a/src/plugins/locator/directoryfilter.cpp +++ b/src/plugins/locator/directoryfilter.cpp @@ -36,6 +36,7 @@ #include <QtGui/QMessageBox> #include <qtconcurrent/QtConcurrentTools> +#include <utils/filesearch.h> using namespace Locator; using namespace Locator::Internal; @@ -181,76 +182,35 @@ void DirectoryFilter::updateOptionButtons() void DirectoryFilter::refresh(QFutureInterface<void> &future) { - const int MAX = 360; - future.setProgressRange(0, MAX); - if (m_directories.count() < 1) { + QStringList directories; + { QMutexLocker locker(&m_lock); - files().clear(); - generateFileNames(); - future.setProgressValueAndText(MAX, tr("%1 filter update: 0 files").arg(m_name)); - return; - } - int progress = 0; - int MAX_PER = MAX; - QStringList filesFound; - QStack<QDir> dirs; - QStack<int> progressValues; - QStack<bool> processedValues; - { // initialize - QMutexLocker locker(&m_lock); - MAX_PER = MAX/m_directories.count(); - foreach (const QString &directoryEntry, m_directories) { - if (!directoryEntry.isEmpty()) { - dirs.push(QDir(directoryEntry)); - progressValues.push(MAX_PER); - processedValues.push(false); - } + if (m_directories.count() < 1) { + files().clear(); + generateFileNames(); + future.setProgressRange(0, 1); + future.setProgressValueAndText(1, tr("%1 filter update: 0 files").arg(m_name)); + return; } + directories = m_directories; } - while (!dirs.isEmpty() && !future.isCanceled()) { + Utils::SubDirFileIterator it(directories, m_filters); + future.setProgressRange(0, it.maxProgress()); + QStringList filesFound; + while (!future.isCanceled() && it.hasNext()) { + filesFound << it.next(); if (future.isProgressUpdateNeeded()) { - future.setProgressValueAndText(progress, + future.setProgressValueAndText(it.currentProgress(), tr("%1 filter update: %n files", 0, filesFound.size()).arg(m_name)); } - QDir dir = dirs.pop(); - int dirProgressMax = progressValues.pop(); - bool processed = processedValues.pop(); - if (dir.exists()) { - QStringList subDirs; - if (!processed) { - subDirs = dir.entryList(QDir::Dirs|QDir::Hidden|QDir::NoDotAndDotDot, - QDir::Name|QDir::IgnoreCase|QDir::LocaleAware); - } - if (subDirs.isEmpty()) { - QStringList fileEntries = dir.entryList(m_filters, - QDir::Files|QDir::Hidden, - QDir::Name|QDir::IgnoreCase|QDir::LocaleAware); - foreach (const QString &file, fileEntries) - filesFound.append(dir.path()+ QLatin1Char('/') +file); - progress += dirProgressMax; - } else { - int subProgress = dirProgressMax/(subDirs.size()+1); - int selfProgress = subProgress + dirProgressMax%(subDirs.size()+1); - dirs.push(dir); - progressValues.push(selfProgress); - processedValues.push(true); - foreach (const QString &directory, subDirs) { - dirs.push(QDir(dir.path()+ QLatin1Char('/') + directory)); - progressValues.push(subProgress); - processedValues.push(false); - } - } - } else { - progress += dirProgressMax; - } } if (!future.isCanceled()) { QMutexLocker locker(&m_lock); files() = filesFound; generateFileNames(); - future.setProgressValue(MAX); + future.setProgressValue(it.maxProgress()); } else { - future.setProgressValueAndText(progress, tr("%1 filter update: canceled").arg(m_name)); + future.setProgressValueAndText(it.currentProgress(), tr("%1 filter update: canceled").arg(m_name)); } } diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp index d621662c87d897c656f37e4919eb632fcb9d35b2..abb1b90b23ad302a8e8ae018d1cf1f2ca38ad9c5 100644 --- a/src/plugins/projectexplorer/allprojectsfind.cpp +++ b/src/plugins/projectexplorer/allprojectsfind.cpp @@ -77,7 +77,7 @@ QKeySequence AllProjectsFind::defaultShortcut() const return QKeySequence(); } -QStringList AllProjectsFind::files() +Utils::FileIterator *AllProjectsFind::files() { Q_ASSERT(m_plugin->session()); QList<QRegExp> filterRegs; @@ -103,7 +103,7 @@ QStringList AllProjectsFind::files() } } files.removeDuplicates(); - return files; + return new Utils::FileIterator(files); } QWidget *AllProjectsFind::createConfigWidget() diff --git a/src/plugins/projectexplorer/allprojectsfind.h b/src/plugins/projectexplorer/allprojectsfind.h index 613c63abd3690d5afcab344633db29de41590bae..2f78757c1564c798a3db0bd635b2a8c36c3b5bc6 100644 --- a/src/plugins/projectexplorer/allprojectsfind.h +++ b/src/plugins/projectexplorer/allprojectsfind.h @@ -61,7 +61,7 @@ public: void readSettings(QSettings *settings); protected: - QStringList files(); + Utils::FileIterator *files(); private: ProjectExplorerPlugin *m_plugin; diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp index cae569bbdf45d43d756997808af6105b404ef1e2..7256a8603b304d075aec1fa6c22c35f6be5b8105 100644 --- a/src/plugins/projectexplorer/currentprojectfind.cpp +++ b/src/plugins/projectexplorer/currentprojectfind.cpp @@ -75,7 +75,7 @@ QKeySequence CurrentProjectFind::defaultShortcut() const return QKeySequence(); } -QStringList CurrentProjectFind::files() +Utils::FileIterator *CurrentProjectFind::files() { Project *project = m_plugin->currentProject(); Q_ASSERT(project); @@ -98,7 +98,7 @@ QStringList CurrentProjectFind::files() files += project->files(Project::AllFiles); } files.removeDuplicates(); - return files; + return new Utils::FileIterator(files); } QWidget *CurrentProjectFind::createConfigWidget() diff --git a/src/plugins/projectexplorer/currentprojectfind.h b/src/plugins/projectexplorer/currentprojectfind.h index 53d57ff2646dce766106954aa1a8296d73de5a2f..2e98e49e1b1756c72ae11f86a907fd11bd7f530a 100644 --- a/src/plugins/projectexplorer/currentprojectfind.h +++ b/src/plugins/projectexplorer/currentprojectfind.h @@ -64,7 +64,7 @@ public: void readSettings(QSettings *settings); protected: - QStringList files(); + Utils::FileIterator *files(); private: ProjectExplorerPlugin *m_plugin; diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h index c0fdaa82f6113db632a0cbf0db38d3acfaf642a8..b423eb8b531cf0ef2cfb3f7bb1209c2b94ddab96 100644 --- a/src/plugins/texteditor/basefilefind.h +++ b/src/plugins/texteditor/basefilefind.h @@ -71,7 +71,7 @@ public: const QList<Find::SearchResultItem> &items); protected: - virtual QStringList files() = 0; + virtual Utils::FileIterator *files() = 0; void writeCommonSettings(QSettings *settings); void readCommonSettings(QSettings *settings, const QString &defaultFilter); QWidget *createPatternWidget(); diff --git a/src/plugins/texteditor/findincurrentfile.cpp b/src/plugins/texteditor/findincurrentfile.cpp index 22170f35e5c67a592e2d4c50f957303f6f746aae..736bc78ae4d6eb8f038b4d37a557da3e6785cb2d 100644 --- a/src/plugins/texteditor/findincurrentfile.cpp +++ b/src/plugins/texteditor/findincurrentfile.cpp @@ -67,12 +67,12 @@ QKeySequence FindInCurrentFile::defaultShortcut() const return QKeySequence(); } -QStringList FindInCurrentFile::files() +Utils::FileIterator *FindInCurrentFile::files() { QStringList fileList; if (isEnabled()) fileList << m_currentFile->fileName(); - return fileList; + return new Utils::FileIterator(fileList); } bool FindInCurrentFile::isEnabled() const diff --git a/src/plugins/texteditor/findincurrentfile.h b/src/plugins/texteditor/findincurrentfile.h index 1f5ec7ba5d7651cb979e92bfd209d0705bb29112..7c6f28c93a676913e90a6cff174e08f3837d7124 100644 --- a/src/plugins/texteditor/findincurrentfile.h +++ b/src/plugins/texteditor/findincurrentfile.h @@ -62,7 +62,7 @@ public: void readSettings(QSettings *settings); protected: - QStringList files(); + Utils::FileIterator *files(); private slots: void handleFileChange(Core::IEditor *editor); diff --git a/src/plugins/texteditor/findinfiles.cpp b/src/plugins/texteditor/findinfiles.cpp index e2c28b417f11506e7256265cc58648e05b05570b..963cb0dea135313afb8272762a9c9d90af4effc4 100644 --- a/src/plugins/texteditor/findinfiles.cpp +++ b/src/plugins/texteditor/findinfiles.cpp @@ -68,18 +68,10 @@ void FindInFiles::findAll(const QString &txt, QTextDocument::FindFlags findFlags BaseFileFind::findAll(txt, findFlags); } -QStringList FindInFiles::files() +Utils::FileIterator *FindInFiles::files() { - QStringList fileList; - QDirIterator it(m_directory->currentText(), - fileNameFilters(), - QDir::Files|QDir::Readable, - QDirIterator::Subdirectories); - - while (it.hasNext()) - fileList << it.next(); - - return fileList; + return new Utils::SubDirFileIterator(QStringList() << m_directory->currentText(), + fileNameFilters()); } QWidget *FindInFiles::createConfigWidget() diff --git a/src/plugins/texteditor/findinfiles.h b/src/plugins/texteditor/findinfiles.h index 91e4c484746cd3f07ab1818e4bec161751f731c6..baf899439d10f99a1d6dfbe104a76cba34865325 100644 --- a/src/plugins/texteditor/findinfiles.h +++ b/src/plugins/texteditor/findinfiles.h @@ -60,7 +60,7 @@ public: void readSettings(QSettings *settings); protected: - QStringList files(); + Utils::FileIterator *files(); private slots: void openFileBrowser();