diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp index 1dd93b009fd..13c0d308dbd 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.cpp +++ b/src/plugins/projectexplorer/currentprojectfilter.cpp @@ -57,10 +57,8 @@ void CurrentProjectFilter::prepareSearch(const QString &entry) Q_UNUSED(entry) if (!fileIterator()) { QStringList paths; - if (m_project) { + if (m_project) paths = Utils::transform(m_project->files(Project::AllFiles), &Utils::FileName::toString); - Utils::sort(paths); - } setFileIterator(new BaseFileFilter::ListIterator(paths)); } BaseFileFilter::prepareSearch(entry); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 2c149a3646f..913c9d673dd 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -91,6 +92,11 @@ static bool isListedFileNode(const Node *node) return node->nodeType() == NodeType::File && node->listInProject(); } +static bool nodeLessThan(const Node *n1, const Node *n2) +{ + return n1->filePath() < n2->filePath(); +} + const Project::NodeMatcher Project::AllFiles = [](const Node *node) { return isListedFileNode(node); }; @@ -172,6 +178,7 @@ public: Kit::Predicate m_preferredKitPredicate; Utils::MacroExpander m_macroExpander; + mutable QVector m_sortedNodeList; }; ProjectPrivate::~ProjectPrivate() @@ -520,11 +527,21 @@ void Project::setRootProjectNode(ProjectNode *root) ProjectNode *oldNode = d->m_rootProjectNode; d->m_rootProjectNode = root; if (root) { + QVector nodeList; + root->forEachGenericNode([&nodeList](const Node *n) { + nodeList.append(n); + }); + Utils::sort(nodeList, &nodeLessThan); + d->m_sortedNodeList = nodeList; root->setParentFolderNode(d->m_containerNode.get()); // Only announce non-null root, null is only used when project is destroyed. // In that case SessionManager::projectRemoved() triggers the update. ProjectTree::emitSubtreeChanged(root); emit fileListChanged(); + } else { + d->m_sortedNodeList.clear(); + if (oldNode != nullptr) + emit fileListChanged(); } delete oldNode; @@ -574,6 +591,9 @@ Project::RestoreResult Project::restoreSettings(QString *errorMessage) return result; } +/*! + * Returns a sorted list of all files matching the predicate \a filter. + */ Utils::FileNameList Project::files(const Project::NodeMatcher &filter) const { Utils::FileNameList result; @@ -581,19 +601,19 @@ Utils::FileNameList Project::files(const Project::NodeMatcher &filter) const if (!rootProjectNode()) return result; - QSet alreadySeen; - rootProjectNode()->forEachGenericNode([&](const Node *n) { + Utils::FileName lastAdded; + for (const Node *n : Utils::asConst(d->m_sortedNodeList)) { if (filter && !filter(n)) - return; + continue; + // Remove duplicates: const Utils::FileName path = n->filePath(); - const int count = alreadySeen.count(); - alreadySeen.insert(path); - if (count == alreadySeen.count()) - return; // skip duplicates + if (path == lastAdded) + continue; // skip duplicates + lastAdded = path; result.append(path); - }); + }; return result; } @@ -715,6 +735,14 @@ QStringList Project::filesGeneratedFrom(const QString &file) const return QStringList(); } +bool Project::isKnownFile(const Utils::FileName &filename) const +{ + const auto end = std::end(d->m_sortedNodeList); + const FileNode element(filename, FileType::Unknown, false); + const auto it = std::lower_bound(std::begin(d->m_sortedNodeList), end, &element, &nodeLessThan); + return (it == end) ? false : (*it)->filePath() != filename; +} + void Project::setProjectContext(Core::Context context) { if (d->m_projectContext == context) diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index 33e212864ff..c50841648b4 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -137,6 +137,7 @@ public: Utils::FileNameList files(const NodeMatcher &matcher) const; virtual QStringList filesGeneratedFrom(const QString &sourceFile) const; + bool isKnownFile(const Utils::FileName &filename) const; static QString makeUnique(const QString &preferredName, const QStringList &usedNames); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index f1143f317c2..74c530d7b90 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -101,8 +101,6 @@ public: mutable QStringList m_sessions; mutable QHash m_sessionDateTimes; - mutable QHash m_projectFileCache; - Project *m_startupProject = nullptr; QList m_projects; QStringList m_failedProjects; @@ -178,17 +176,6 @@ void SessionManager::saveActiveMode(Id mode) setValue(QLatin1String("ActiveMode"), mode.toString()); } -void SessionManager::clearProjectFileCache() -{ - // If triggered by the fileListChanged signal of one project - // only invalidate cache for this project - auto pro = qobject_cast(m_instance->sender()); - if (pro) - d->m_projectFileCache.remove(pro); - else - d->m_projectFileCache.clear(); -} - bool SessionManagerPrivate::recursiveDependencyCheck(const QString &newDep, const QString &checkDep) const { if (newDep == checkDep) @@ -388,7 +375,6 @@ void SessionManager::addProject(Project *pro) d->m_projects.append(pro); - connect(pro, &Project::fileListChanged, m_instance, &SessionManager::clearProjectFileCache); connect(pro, &Project::displayNameChanged, m_instance, [pro]() { m_instance->projectDisplayNameChanged(pro); }); @@ -689,10 +675,7 @@ Project *SessionManager::projectForFile(const Utils::FileName &fileName) bool SessionManager::projectContainsFile(Project *p, const Utils::FileName &fileName) { - if (!d->m_projectFileCache.contains(p)) - d->m_projectFileCache.insert(p, Utils::transform(p->files(Project::AllFiles), &Utils::FileName::toString)); - - return d->m_projectFileCache.value(p).contains(fileName.toString()); + return p && p->isKnownFile(fileName); } void SessionManager::configureEditor(IEditor *editor, const QString &fileName) @@ -757,9 +740,6 @@ void SessionManager::removeProjects(const QList &remove) if (pro == d->m_startupProject) changeStartupProject = true; - disconnect(pro, &Project::fileListChanged, - m_instance, &SessionManager::clearProjectFileCache); - d->m_projectFileCache.remove(pro); emit m_instance->projectRemoved(pro); FolderNavigationWidgetFactory::removeRootDirectory(projectFolderId(pro)); } diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 864bd7c4225..c54bc6d9eee 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -140,7 +140,6 @@ signals: // for tests only private: static void saveActiveMode(Core::Id mode); - void clearProjectFileCache(); static void configureEditor(Core::IEditor *editor, const QString &fileName); static void markSessionFileDirty(bool makeDefaultVirginDirty = true); static void configureEditors(Project *project);