forked from qt-creator/qt-creator
TreeScanner: Inline scanForFiles() method
Make scanForFiles() a non-template method and hide it in treescanner.cpp. Inline scanForFilesRecursively(). Change-Id: I10e07f190e1a4a65cd7045c625a364350964afb9 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -140,7 +140,6 @@ add_qtc_plugin(ProjectExplorer
|
||||
projectmanager.cpp projectmanager.h
|
||||
projectmodels.cpp projectmodels.h
|
||||
projectnodes.cpp projectnodes.h
|
||||
projectnodeshelper.h
|
||||
projectpanelfactory.cpp projectpanelfactory.h
|
||||
projectsettingswidget.cpp projectsettingswidget.h
|
||||
projecttree.cpp projecttree.h
|
||||
|
@@ -115,7 +115,6 @@ QtcPlugin {
|
||||
"projectmanager.cpp", "projectmanager.h",
|
||||
"projectmodels.cpp", "projectmodels.h",
|
||||
"projectnodes.cpp", "projectnodes.h",
|
||||
"projectnodeshelper.h",
|
||||
"projectpanelfactory.cpp", "projectpanelfactory.h",
|
||||
"projectsettingswidget.cpp", "projectsettingswidget.h",
|
||||
"projecttree.cpp",
|
||||
|
@@ -1,141 +0,0 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "projectnodes.h"
|
||||
|
||||
#include <coreplugin/iversioncontrol.h>
|
||||
#include <coreplugin/vcsmanager.h>
|
||||
|
||||
#include <solutions/tasking/tasktreerunner.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/async.h>
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
|
||||
#include <QPromise>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
|
||||
struct DirectoryScanResult
|
||||
{
|
||||
QList<FileNode *> nodes;
|
||||
Utils::FilePaths subDirectories;
|
||||
};
|
||||
|
||||
static DirectoryScanResult scanForFiles(
|
||||
const QFuture<void> &future,
|
||||
const Utils::FilePath &directory,
|
||||
QDir::Filters filter,
|
||||
const std::function<FileNode *(const Utils::FilePath &)> &factory,
|
||||
const QList<Core::IVersionControl *> &versionControls)
|
||||
{
|
||||
DirectoryScanResult result;
|
||||
|
||||
const Utils::FilePaths entries = directory.dirEntries(filter);
|
||||
for (const Utils::FilePath &entry : entries) {
|
||||
if (future.isCanceled())
|
||||
return result;
|
||||
|
||||
if (Utils::anyOf(versionControls, [entry](const Core::IVersionControl *vc) {
|
||||
return vc->isVcsFileOrDirectory(entry);
|
||||
})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.isDir())
|
||||
result.subDirectories.append(entry);
|
||||
else if (FileNode *node = factory(entry))
|
||||
result.nodes.append(node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Result>
|
||||
QList<FileNode *> scanForFilesRecursively(
|
||||
QPromise<Result> &promise,
|
||||
int progressRange,
|
||||
const Utils::FilePath &directory,
|
||||
QDir::Filters filter,
|
||||
const std::function<FileNode *(const Utils::FilePath &)> &factory,
|
||||
const QList<Core::IVersionControl *> &versionControls)
|
||||
{
|
||||
const QFuture<void> future(promise.future());
|
||||
|
||||
QSet<Utils::FilePath> visited;
|
||||
const DirectoryScanResult result
|
||||
= scanForFiles(future, directory, filter, factory, versionControls);
|
||||
QList<FileNode *> fileNodes = result.nodes;
|
||||
const int progressIncrement = int(
|
||||
progressRange / static_cast<double>(fileNodes.count() + result.subDirectories.count()));
|
||||
promise.setProgressValue(int(fileNodes.count() * progressIncrement));
|
||||
QList<QPair<Utils::FilePath, int>> subDirectories;
|
||||
auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) {
|
||||
for (const Utils::FilePath &subdir : subdirs) {
|
||||
if (Utils::insert(visited, subdir.canonicalPath()))
|
||||
subDirectories.append(qMakePair(subdir, progressIncrement));
|
||||
else
|
||||
promise.setProgressValue(promise.future().progressValue() + progressIncrement);
|
||||
}
|
||||
};
|
||||
addSubDirectories(result.subDirectories, progressIncrement);
|
||||
|
||||
while (!subDirectories.isEmpty()) {
|
||||
using namespace Tasking;
|
||||
const LoopList iterator(subDirectories);
|
||||
subDirectories.clear();
|
||||
|
||||
auto onSetup = [&, iterator](Utils::Async<DirectoryScanResult> &task) {
|
||||
task.setConcurrentCallData(
|
||||
scanForFiles, future, iterator->first, filter, factory, versionControls);
|
||||
};
|
||||
|
||||
auto onDone = [&, iterator](const Utils::Async<DirectoryScanResult> &task) {
|
||||
const int progressRange = iterator->second;
|
||||
const DirectoryScanResult result = task.result();
|
||||
fileNodes.append(result.nodes);
|
||||
const qsizetype subDirCount = result.subDirectories.count();
|
||||
if (subDirCount == 0) {
|
||||
promise.setProgressValue(promise.future().progressValue() + progressRange);
|
||||
} else {
|
||||
const qsizetype fileCount = result.nodes.count();
|
||||
const int increment = int(
|
||||
progressRange / static_cast<double>(fileCount + subDirCount));
|
||||
promise.setProgressValue(
|
||||
promise.future().progressValue() + increment * fileCount);
|
||||
addSubDirectories(result.subDirectories, increment);
|
||||
}
|
||||
};
|
||||
|
||||
const Group group{
|
||||
Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit,
|
||||
iterator,
|
||||
Utils::AsyncTask<DirectoryScanResult>(onSetup, onDone)
|
||||
};
|
||||
TaskTree::runBlocking(group);
|
||||
}
|
||||
return fileNodes;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
template<typename Result>
|
||||
QList<FileNode *> scanForFiles(
|
||||
QPromise<Result> &promise,
|
||||
const Utils::FilePath &directory,
|
||||
QDir::Filters filter,
|
||||
const std::function<FileNode *(const Utils::FilePath &)> &factory)
|
||||
{
|
||||
promise.setProgressRange(0, 1000000);
|
||||
return Internal::scanForFilesRecursively(promise,
|
||||
1000000,
|
||||
directory,
|
||||
filter,
|
||||
factory,
|
||||
Core::VcsManager::versionControls());
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
@@ -3,15 +3,17 @@
|
||||
|
||||
#include "treescanner.h"
|
||||
|
||||
#include "projectnodeshelper.h"
|
||||
#include "projecttree.h"
|
||||
|
||||
#include <coreplugin/iversioncontrol.h>
|
||||
#include <coreplugin/vcsmanager.h>
|
||||
|
||||
#include <utils/async.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <solutions/tasking/tasktreerunner.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/async.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -146,14 +148,113 @@ static std::unique_ptr<FolderNode> createFolderNode(const Utils::FilePath &direc
|
||||
return fileSystemNode;
|
||||
}
|
||||
|
||||
struct DirectoryScanResult
|
||||
{
|
||||
QList<FileNode *> nodes;
|
||||
Utils::FilePaths subDirectories;
|
||||
};
|
||||
|
||||
static DirectoryScanResult scanForFilesImpl(
|
||||
const QFuture<void> &future,
|
||||
const Utils::FilePath &directory,
|
||||
QDir::Filters filter,
|
||||
const std::function<FileNode *(const Utils::FilePath &)> &factory,
|
||||
const QList<Core::IVersionControl *> &versionControls)
|
||||
{
|
||||
DirectoryScanResult result;
|
||||
|
||||
const Utils::FilePaths entries = directory.dirEntries(filter);
|
||||
for (const Utils::FilePath &entry : entries) {
|
||||
if (future.isCanceled())
|
||||
return result;
|
||||
|
||||
if (Utils::anyOf(versionControls, [entry](const Core::IVersionControl *vc) {
|
||||
return vc->isVcsFileOrDirectory(entry);
|
||||
})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.isDir())
|
||||
result.subDirectories.append(entry);
|
||||
else if (FileNode *node = factory(entry))
|
||||
result.nodes.append(node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static QList<FileNode *> scanForFilesHelper(
|
||||
TreeScanner::Promise &promise,
|
||||
const Utils::FilePath &directory,
|
||||
QDir::Filters filter,
|
||||
const std::function<FileNode *(const Utils::FilePath &)> &factory)
|
||||
{
|
||||
const QFuture<void> future(promise.future());
|
||||
|
||||
const int progressRange = 1000000;
|
||||
const QList<Core::IVersionControl *> &versionControls = Core::VcsManager::versionControls();
|
||||
promise.setProgressRange(0, progressRange);
|
||||
|
||||
QSet<Utils::FilePath> visited;
|
||||
const DirectoryScanResult result = scanForFilesImpl(future, directory, filter, factory, versionControls);
|
||||
QList<FileNode *> fileNodes = result.nodes;
|
||||
const int progressIncrement = int(
|
||||
progressRange / static_cast<double>(fileNodes.count() + result.subDirectories.count()));
|
||||
promise.setProgressValue(int(fileNodes.count() * progressIncrement));
|
||||
QList<QPair<Utils::FilePath, int>> subDirectories;
|
||||
auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) {
|
||||
for (const Utils::FilePath &subdir : subdirs) {
|
||||
if (Utils::insert(visited, subdir.canonicalPath()))
|
||||
subDirectories.append(qMakePair(subdir, progressIncrement));
|
||||
else
|
||||
promise.setProgressValue(future.progressValue() + progressIncrement);
|
||||
}
|
||||
};
|
||||
addSubDirectories(result.subDirectories, progressIncrement);
|
||||
|
||||
while (!subDirectories.isEmpty()) {
|
||||
using namespace Tasking;
|
||||
const LoopList iterator(subDirectories);
|
||||
subDirectories.clear();
|
||||
|
||||
auto onSetup = [&, iterator](Utils::Async<DirectoryScanResult> &task) {
|
||||
task.setConcurrentCallData(
|
||||
scanForFilesImpl, future, iterator->first, filter, factory, versionControls);
|
||||
};
|
||||
|
||||
auto onDone = [&, iterator](const Utils::Async<DirectoryScanResult> &task) {
|
||||
const int progressRange = iterator->second;
|
||||
const DirectoryScanResult result = task.result();
|
||||
fileNodes.append(result.nodes);
|
||||
const qsizetype subDirCount = result.subDirectories.count();
|
||||
if (subDirCount == 0) {
|
||||
promise.setProgressValue(future.progressValue() + progressRange);
|
||||
} else {
|
||||
const qsizetype fileCount = result.nodes.count();
|
||||
const int increment = int(
|
||||
progressRange / static_cast<double>(fileCount + subDirCount));
|
||||
promise.setProgressValue(future.progressValue() + increment * fileCount);
|
||||
addSubDirectories(result.subDirectories, increment);
|
||||
}
|
||||
};
|
||||
|
||||
const Group group{
|
||||
Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit,
|
||||
iterator,
|
||||
Utils::AsyncTask<DirectoryScanResult>(onSetup, onDone)
|
||||
};
|
||||
TaskTree::runBlocking(group);
|
||||
}
|
||||
return fileNodes;
|
||||
}
|
||||
|
||||
void TreeScanner::scanForFiles(
|
||||
Promise &promise,
|
||||
const Utils::FilePath &directory,
|
||||
const FileFilter &filter,
|
||||
const QDir::Filters &dirFilter,
|
||||
QDir::Filters dirFilter,
|
||||
const FileTypeFactory &factory)
|
||||
{
|
||||
QList<FileNode *> nodes = ProjectExplorer::scanForFiles(
|
||||
QList<FileNode *> nodes = scanForFilesHelper(
|
||||
promise, directory, dirFilter, [&filter, &factory](const Utils::FilePath &fn) -> FileNode * {
|
||||
const Utils::MimeType mimeType = Utils::mimeTypesForFileName(fn.path()).value(0);
|
||||
|
||||
|
@@ -75,7 +75,7 @@ private:
|
||||
static void scanForFiles(Promise &fi,
|
||||
const Utils::FilePath &directory,
|
||||
const FileFilter &filter,
|
||||
const QDir::Filters &dirFilter,
|
||||
QDir::Filters dirFilter,
|
||||
const FileTypeFactory &factory);
|
||||
|
||||
private:
|
||||
|
Reference in New Issue
Block a user