forked from qt-creator/qt-creator
Avoid registering individual files for watching
if we can do it en bloc. This reduces the freeze happening after loading a project, at least on macOS with QFSEventsFileSystemWatcher, which doesn't like getting 1000 files added one by one. Task-number: QTCREATORBUG-25783 Change-Id: I2d508ac3334520cb8805a2179d42b86c9ba840d6 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
@@ -300,9 +300,9 @@ DocumentManager *DocumentManager::instance()
|
|||||||
return m_instance;
|
return m_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only called from addFileInfo(IDocument *) */
|
/* Only called from addFileInfo(IDocument *). Adds the document & state to various caches/lists,
|
||||||
static void addFileInfo(IDocument *document, const QString &filePath,
|
but does not actually add a watcher. */
|
||||||
const QString &filePathKey, bool isLink)
|
static void addFileInfo(IDocument *document, const QString &filePath, const QString &filePathKey)
|
||||||
{
|
{
|
||||||
FileStateItem state;
|
FileStateItem state;
|
||||||
if (!filePath.isEmpty()) {
|
if (!filePath.isEmpty()) {
|
||||||
@@ -316,43 +316,51 @@ static void addFileInfo(IDocument *document, const QString &filePath,
|
|||||||
state.watchedFilePath = filePath;
|
state.watchedFilePath = filePath;
|
||||||
d->m_states.insert(filePathKey, state);
|
d->m_states.insert(filePathKey, state);
|
||||||
}
|
}
|
||||||
// Add or update watcher on file path
|
|
||||||
// This is also used to update the watcher in case of saved (==replaced) files or
|
|
||||||
// update link targets, even if there are multiple documents registered for it
|
|
||||||
const QString watchedFilePath = d->m_states.value(filePathKey).watchedFilePath;
|
|
||||||
qCDebug(log) << "adding (" << (isLink ? "link" : "full") << ") watch for"
|
|
||||||
<< watchedFilePath;
|
|
||||||
QFileSystemWatcher *watcher = nullptr;
|
|
||||||
if (isLink)
|
|
||||||
watcher = d->linkWatcher();
|
|
||||||
else
|
|
||||||
watcher = d->fileWatcher();
|
|
||||||
watcher->addPath(watchedFilePath);
|
|
||||||
|
|
||||||
d->m_states[filePathKey].lastUpdatedState.insert(document, state);
|
d->m_states[filePathKey].lastUpdatedState.insert(document, state);
|
||||||
}
|
}
|
||||||
d->m_documentsWithWatch[document].append(filePathKey); // inserts a new QStringList if not already there
|
d->m_documentsWithWatch[document].append(filePathKey); // inserts a new QStringList if not already there
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adds the IDocument's file and possibly it's final link target to both m_states
|
/* Adds the IDocuments' file and possibly it's final link target to both m_states
|
||||||
(if it's file name is not empty), and the m_filesWithWatch list,
|
(if it's file name is not empty), and the m_filesWithWatch list,
|
||||||
and adds a file watcher for each if not already done.
|
and adds a file watcher for each if not already done.
|
||||||
(The added file names are guaranteed to be absolute and cleaned.) */
|
(The added file names are guaranteed to be absolute and cleaned.) */
|
||||||
static void addFileInfo(IDocument *document)
|
static void addFileInfos(const QList<IDocument *> &documents)
|
||||||
{
|
{
|
||||||
|
QStringList pathsToWatch;
|
||||||
|
QStringList linkPathsToWatch;
|
||||||
|
for (IDocument *document : documents) {
|
||||||
const QString documentFilePath = document->filePath().toString();
|
const QString documentFilePath = document->filePath().toString();
|
||||||
const QString filePath = DocumentManager::cleanAbsoluteFilePath(
|
const QString filePath = DocumentManager::cleanAbsoluteFilePath(documentFilePath,
|
||||||
documentFilePath, DocumentManager::KeepLinks);
|
DocumentManager::KeepLinks);
|
||||||
const QString filePathKey = DocumentManager::filePathKey(
|
const QString filePathKey = DocumentManager::filePathKey(documentFilePath,
|
||||||
documentFilePath, DocumentManager::KeepLinks);
|
DocumentManager::KeepLinks);
|
||||||
const QString resolvedFilePath = DocumentManager::cleanAbsoluteFilePath(
|
const QString resolvedFilePath
|
||||||
documentFilePath, DocumentManager::ResolveLinks);
|
= DocumentManager::cleanAbsoluteFilePath(documentFilePath,
|
||||||
const QString resolvedFilePathKey = DocumentManager::filePathKey(
|
DocumentManager::ResolveLinks);
|
||||||
documentFilePath, DocumentManager::ResolveLinks);
|
const QString resolvedFilePathKey
|
||||||
|
= DocumentManager::filePathKey(documentFilePath, DocumentManager::ResolveLinks);
|
||||||
const bool isLink = filePath != resolvedFilePath;
|
const bool isLink = filePath != resolvedFilePath;
|
||||||
addFileInfo(document, filePath, filePathKey, isLink);
|
addFileInfo(document, filePath, filePathKey);
|
||||||
if (isLink)
|
if (isLink) {
|
||||||
addFileInfo(document, resolvedFilePath, resolvedFilePathKey, false);
|
addFileInfo(document, resolvedFilePath, resolvedFilePathKey);
|
||||||
|
linkPathsToWatch.append(d->m_states.value(filePathKey).watchedFilePath);
|
||||||
|
pathsToWatch.append(d->m_states.value(resolvedFilePathKey).watchedFilePath);
|
||||||
|
} else {
|
||||||
|
pathsToWatch.append(d->m_states.value(filePathKey).watchedFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add or update watcher on file path
|
||||||
|
// This is also used to update the watcher in case of saved (==replaced) files or
|
||||||
|
// update link targets, even if there are multiple documents registered for it
|
||||||
|
if (!pathsToWatch.isEmpty()) {
|
||||||
|
qCDebug(log) << "adding full watch for" << pathsToWatch;
|
||||||
|
d->fileWatcher()->addPaths(pathsToWatch);
|
||||||
|
}
|
||||||
|
if (!linkPathsToWatch.isEmpty()) {
|
||||||
|
qCDebug(log) << "adding link watch for" << linkPathsToWatch;
|
||||||
|
d->linkWatcher()->addPaths(linkPathsToWatch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -378,16 +386,17 @@ void DocumentManager::addDocuments(const QList<IDocument *> &documents, bool add
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (IDocument *document, documents) {
|
const QList<IDocument *> documentsToWatch = Utils::filtered(documents, [](IDocument *document) {
|
||||||
if (document && !d->m_documentsWithWatch.contains(document)) {
|
return document && !d->m_documentsWithWatch.contains(document);
|
||||||
|
});
|
||||||
|
for (IDocument *document : documentsToWatch) {
|
||||||
connect(document, &IDocument::changed, m_instance, &DocumentManager::checkForNewFileName);
|
connect(document, &IDocument::changed, m_instance, &DocumentManager::checkForNewFileName);
|
||||||
connect(document, &QObject::destroyed, m_instance, &DocumentManager::documentDestroyed);
|
connect(document, &QObject::destroyed, m_instance, &DocumentManager::documentDestroyed);
|
||||||
connect(document, &IDocument::filePathChanged,
|
connect(document, &IDocument::filePathChanged,
|
||||||
m_instance, &DocumentManager::filePathChanged);
|
m_instance, &DocumentManager::filePathChanged);
|
||||||
connect(document, &IDocument::changed, m_instance, &DocumentManager::updateSaveAll);
|
connect(document, &IDocument::changed, m_instance, &DocumentManager::updateSaveAll);
|
||||||
addFileInfo(document);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
addFileInfos(documentsToWatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -483,7 +492,7 @@ void DocumentManager::renamedFile(const QString &from, const QString &to)
|
|||||||
d->m_blockedIDocument = document;
|
d->m_blockedIDocument = document;
|
||||||
removeFileInfo(document);
|
removeFileInfo(document);
|
||||||
document->setFilePath(FilePath::fromString(to));
|
document->setFilePath(FilePath::fromString(to));
|
||||||
addFileInfo(document);
|
addFileInfos({document});
|
||||||
d->m_blockedIDocument = nullptr;
|
d->m_blockedIDocument = nullptr;
|
||||||
}
|
}
|
||||||
emit m_instance->allDocumentsRenamed(from, to);
|
emit m_instance->allDocumentsRenamed(from, to);
|
||||||
@@ -558,7 +567,7 @@ void DocumentManager::checkForNewFileName()
|
|||||||
// Maybe the name has changed or file has been deleted and created again ...
|
// Maybe the name has changed or file has been deleted and created again ...
|
||||||
// This also updates the state to the on disk state
|
// This also updates the state to the on disk state
|
||||||
removeFileInfo(document);
|
removeFileInfo(document);
|
||||||
addFileInfo(document);
|
addFileInfos({document});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1193,7 +1202,7 @@ void DocumentManager::checkForReload()
|
|||||||
// doesn't matter, because in that case we then reload the new version of the file already
|
// doesn't matter, because in that case we then reload the new version of the file already
|
||||||
// anyhow.
|
// anyhow.
|
||||||
removeFileInfo(document);
|
removeFileInfo(document);
|
||||||
addFileInfo(document);
|
addFileInfos({document});
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
QString errorString;
|
QString errorString;
|
||||||
|
@@ -150,7 +150,6 @@ ProjectDocument::ProjectDocument(const QString &mimeType,
|
|||||||
|
|
||||||
setFilePath(fileName);
|
setFilePath(fileName);
|
||||||
setMimeType(mimeType);
|
setMimeType(mimeType);
|
||||||
Core::DocumentManager::addDocument(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::IDocument::ReloadBehavior
|
Core::IDocument::ReloadBehavior
|
||||||
@@ -223,6 +222,7 @@ Project::Project(const QString &mimeType,
|
|||||||
: d(new ProjectPrivate)
|
: d(new ProjectPrivate)
|
||||||
{
|
{
|
||||||
d->m_document = std::make_unique<ProjectDocument>(mimeType, fileName, this);
|
d->m_document = std::make_unique<ProjectDocument>(mimeType, fileName, this);
|
||||||
|
Core::DocumentManager::addDocument(d->m_document.get());
|
||||||
|
|
||||||
d->m_macroExpander.setDisplayName(tr("Project"));
|
d->m_macroExpander.setDisplayName(tr("Project"));
|
||||||
d->m_macroExpander.registerVariable("Project:Name", tr("Project Name"),
|
d->m_macroExpander.registerVariable("Project:Name", tr("Project Name"),
|
||||||
@@ -389,16 +389,19 @@ void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentP
|
|||||||
for (const auto &doc : qAsConst(d->m_extraProjectDocuments))
|
for (const auto &doc : qAsConst(d->m_extraProjectDocuments))
|
||||||
docUpdater(doc.get());
|
docUpdater(doc.get());
|
||||||
}
|
}
|
||||||
|
QList<Core::IDocument *> toRegister;
|
||||||
for (const Utils::FilePath &p : toAdd) {
|
for (const Utils::FilePath &p : toAdd) {
|
||||||
if (docGenerator) {
|
if (docGenerator) {
|
||||||
std::unique_ptr<Core::IDocument> doc = docGenerator(p);
|
std::unique_ptr<Core::IDocument> doc = docGenerator(p);
|
||||||
QTC_ASSERT(doc, continue);
|
QTC_ASSERT(doc, continue);
|
||||||
d->m_extraProjectDocuments.push_back(std::move(doc));
|
d->m_extraProjectDocuments.push_back(std::move(doc));
|
||||||
} else {
|
} else {
|
||||||
d->m_extraProjectDocuments.emplace_back(std::make_unique<ProjectDocument>(
|
auto document = std::make_unique<ProjectDocument>(d->m_document->mimeType(), p, this);
|
||||||
d->m_document->mimeType(), p, this));
|
toRegister.append(document.get());
|
||||||
|
d->m_extraProjectDocuments.emplace_back(std::move(document));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Core::DocumentManager::addDocuments(toRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Project::updateExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths,
|
void Project::updateExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths,
|
||||||
|
Reference in New Issue
Block a user