ProjectExplorer: Slim down user side ProjectNode handling

Change-Id: If727ff6cd09cc127e031c49c47f61ffda631a80e
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
hjk
2017-01-26 11:58:57 +01:00
parent cd70da5dcd
commit beaba559a5
8 changed files with 46 additions and 148 deletions

View File

@@ -33,6 +33,7 @@
#include "cmakeprojectconstants.h" #include "cmakeprojectconstants.h"
#include "cmakebuildsettingswidget.h" #include "cmakebuildsettingswidget.h"
#include "cmakeprojectmanager.h" #include "cmakeprojectmanager.h"
#include "cmakeprojectnodes.h"
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
@@ -216,6 +217,9 @@ void CMakeBuildConfiguration::generateProjectTree(CMakeListsNode *root,
if (!m_buildDirManager || m_buildDirManager->isParsing()) if (!m_buildDirManager || m_buildDirManager->isParsing())
return; return;
root->removeProjectNodes();
root->setFolderNodes({});
root->setFileNodes({});
m_buildDirManager->generateProjectTree(root, allFiles); m_buildDirManager->generateProjectTree(root, allFiles);
} }

View File

@@ -250,11 +250,11 @@ static ProjectNode *updateCMakeInputs(CMakeListsNode *root,
if (!cmakeVFolder) { if (!cmakeVFolder) {
if (hasInputs) { if (hasInputs) {
cmakeVFolder = new CMakeInputsNode(root->filePath()); cmakeVFolder = new CMakeInputsNode(root->filePath());
root->addProjectNodes({ cmakeVFolder }); root->addProjectNode(cmakeVFolder);
} }
} else { } else {
if (!hasInputs) if (!hasInputs)
root->removeProjectNodes({ cmakeVFolder }); root->removeProjectNode(cmakeVFolder);
} }
if (!hasInputs) if (!hasInputs)
return nullptr; return nullptr;
@@ -304,15 +304,11 @@ void ServerModeReader::generateProjectTree(CMakeListsNode *root,
if (!m_projects.isEmpty()) if (!m_projects.isEmpty())
root->setDisplayName(m_projects.at(0)->name); root->setDisplayName(m_projects.at(0)->name);
QSet<Node *> usedNodes; updateCMakeInputs(root, m_parameters.sourceDirectory, m_parameters.buildDirectory,
usedNodes.insert(updateCMakeInputs(root, m_parameters.sourceDirectory, m_parameters.buildDirectory, cmakeFilesSource, cmakeFilesBuild, cmakeFilesOther);
cmakeFilesSource, cmakeFilesBuild, cmakeFilesOther));
usedNodes.unite(updateCMakeLists(root, cmakeLists)); updateCMakeLists(root, cmakeLists);
usedNodes.unite(updateProjects(root, m_projects, allFiles)); updateProjects(root, m_projects, allFiles);
// Trim out unused nodes:
root->trim(usedNodes);
} }
QSet<Core::Id> ServerModeReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) QSet<Core::Id> ServerModeReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
@@ -583,7 +579,7 @@ QSet<Node *> ServerModeReader::updateCMakeLists(CMakeListsNode *root,
cmln = static_cast<CMakeListsNode *>(parentNode->projectNode(fn->filePath())); cmln = static_cast<CMakeListsNode *>(parentNode->projectNode(fn->filePath()));
if (!cmln) { if (!cmln) {
cmln = new CMakeListsNode(fn->filePath()); cmln = new CMakeListsNode(fn->filePath());
parentNode->addProjectNodes({ cmln }); parentNode->addProjectNode(cmln);
} }
// Find or create CMakeLists.txt filenode below CMakeListsNode: // Find or create CMakeLists.txt filenode below CMakeListsNode:
@@ -647,7 +643,7 @@ static CMakeProjectNode *findOrCreateProjectNode(CMakeListsNode *root, const Uti
CMakeProjectNode *pn = static_cast<CMakeProjectNode *>(cmln->projectNode(projectName)); CMakeProjectNode *pn = static_cast<CMakeProjectNode *>(cmln->projectNode(projectName));
if (!pn) { if (!pn) {
pn = new CMakeProjectNode(projectName); pn = new CMakeProjectNode(projectName);
cmln->addProjectNodes({ pn }); cmln->addProjectNode(pn);
} }
pn->setDisplayName(displayName); pn->setDisplayName(displayName);
return pn; return pn;
@@ -688,7 +684,7 @@ static CMakeTargetNode *findOrCreateTargetNode(CMakeListsNode *root, const Utils
CMakeTargetNode *tn = static_cast<CMakeTargetNode *>(cmln->projectNode(targetName)); CMakeTargetNode *tn = static_cast<CMakeTargetNode *>(cmln->projectNode(targetName));
if (!tn) { if (!tn) {
tn = new CMakeTargetNode(targetName); tn = new CMakeTargetNode(targetName);
cmln->addProjectNodes({ tn }); cmln->addProjectNode(tn);
} }
tn->setDisplayName(displayName); tn->setDisplayName(displayName);
return tn; return tn;

View File

@@ -243,20 +243,6 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration()
return result; return result;
} }
static void sanitizeTree(CMakeListsNode *root)
{
QSet<FileName> uniqueFileNames;
QSet<Node *> uniqueNodes;
foreach (FileNode *fn, root->recursiveFileNodes()) {
const int count = uniqueFileNames.count();
uniqueFileNames.insert(fn->filePath());
if (count != uniqueFileNames.count())
uniqueNodes.insert(static_cast<Node *>(fn));
}
root->trim(uniqueNodes);
root->removeProjectNodes(root->projectNodes()); // Remove all project nodes
}
void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList<const FileNode *> &allFiles) void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList<const FileNode *> &allFiles)
{ {
root->setDisplayName(m_projectName); root->setDisplayName(m_projectName);
@@ -308,7 +294,6 @@ void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList<const
QList<FileNode *> fileNodes = m_files + Utils::transform(missingHeaders, [](const FileNode *fn) { return new FileNode(*fn); }); QList<FileNode *> fileNodes = m_files + Utils::transform(missingHeaders, [](const FileNode *fn) { return new FileNode(*fn); });
sanitizeTree(root); // Filter out duplicate nodes that e.g. the servermode reader introduces:
root->buildTree(fileNodes, m_parameters.sourceDirectory); root->buildTree(fileNodes, m_parameters.sourceDirectory);
m_files.clear(); // Some of the FileNodes in files() were deleted! m_files.clear(); // Some of the FileNodes in files() were deleted!
} }

View File

@@ -185,11 +185,6 @@ void Node::emitTreeChanged()
ProjectTree::emitDataChanged(); ProjectTree::emitDataChanged();
} }
Node *Node::trim(const QSet<Node *> &keepers)
{
return keepers.contains(this) ? nullptr : this;
}
bool Node::sortByPath(const Node *a, const Node *b) bool Node::sortByPath(const Node *a, const Node *b)
{ {
return a->filePath() < b->filePath(); return a->filePath() < b->filePath();
@@ -339,26 +334,6 @@ QIcon FolderNode::icon() const
return m_icon; return m_icon;
} }
Node *FolderNode::trim(const QSet<Node *> &keepers)
{
if (keepers.contains(this))
return nullptr;
bool keepThis = false;
QList<Node *> toTrim = Utils::transform(m_fileNodes, [&keepers](Node *n) { return n->trim(keepers); });
int count = toTrim.count();
toTrim = Utils::filtered(toTrim, [](const Node *n) { return n; });
keepThis = (count != toTrim.count());
removeFileNodes(Utils::transform(toTrim, [](Node *n) { return static_cast<FileNode *>(n); }));
toTrim = Utils::transform(m_folderNodes, [&keepers](Node *n) { return n->trim(keepers); });
count = toTrim.count();
toTrim = Utils::filtered(toTrim, [](const Node *n) { return n; });
keepThis = keepThis || (count != toTrim.count());
removeFolderNodes(Utils::transform(toTrim, [](Node *n) { return static_cast<FolderNode *>(n); }));
return keepThis ? nullptr : this;
}
QList<FileNode*> FolderNode::fileNodes() const QList<FileNode*> FolderNode::fileNodes() const
{ {
return m_fileNodes; return m_fileNodes;
@@ -829,25 +804,19 @@ QList<ProjectNode*> ProjectNode::projectNodes() const
Adds project nodes specified by \a subProjects to the node hierarchy and Adds project nodes specified by \a subProjects to the node hierarchy and
emits the corresponding signals. emits the corresponding signals.
*/ */
void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects) void ProjectNode::addProjectNode(ProjectNode *subProject)
{ {
if (!subProjects.isEmpty()) { QTC_ASSERT(subProject, return);
QList<FolderNode*> folderNodes; QTC_ASSERT(!subProject->parentFolderNode(), return);
foreach (ProjectNode *projectNode, subProjects)
folderNodes << projectNode;
foreach (ProjectNode *project, subProjects) { subProject->setParentFolderNode(this);
QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this, m_folderNodes.append(subProject);
qDebug("Project node has already a parent")); m_projectNodes.append(subProject);
project->setParentFolderNode(this);
m_folderNodes.append(project);
m_projectNodes.append(project);
}
Utils::sort(m_folderNodes); Utils::sort(m_folderNodes);
Utils::sort(m_projectNodes); Utils::sort(m_projectNodes);
} }
}
/*! /*!
Removes project nodes specified by \a subProjects from the node hierarchy Removes project nodes specified by \a subProjects from the node hierarchy
@@ -856,50 +825,20 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
All objects in the \a subProjects list are deleted. All objects in the \a subProjects list are deleted.
*/ */
void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects) void ProjectNode::removeProjectNodes()
{ {
if (!subProjects.isEmpty()) { foreach (ProjectNode *subProject, m_projectNodes)
QList<FolderNode*> toRemove; m_folderNodes.removeAll(subProject);
foreach (ProjectNode *projectNode, subProjects)
toRemove << projectNode;
Utils::sort(toRemove);
auto toRemoveIter = toRemove.constBegin(); qDeleteAll(m_projectNodes);
auto folderIter = m_folderNodes.begin(); m_projectNodes.clear();
auto projectIter = m_projectNodes.begin();
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
while (*projectIter != *toRemoveIter) {
++projectIter;
QTC_ASSERT(projectIter != m_projectNodes.end(),
qDebug("Project to remove is not part of specified folder!"));
}
while (*folderIter != *toRemoveIter) {
++folderIter;
QTC_ASSERT(folderIter != m_folderNodes.end(),
qDebug("Project to remove is not part of specified folder!"));
}
delete *projectIter;
projectIter = m_projectNodes.erase(projectIter);
folderIter = m_folderNodes.erase(folderIter);
}
}
} }
Node *ProjectNode::trim(const QSet<Node *> &keepers) void ProjectNode::removeProjectNode(ProjectNode *subProject)
{ {
if (keepers.contains(this)) m_projectNodes.removeOne(subProject);
return nullptr; m_folderNodes.removeOne(subProject);
delete subProject;
QList<Node *> toTrim
= Utils::transform(m_projectNodes, [&keepers](Node *n) { return n->trim(keepers); });
int count = toTrim.count();
toTrim = Utils::filtered(toTrim, [](Node *n) { return n; });
removeProjectNodes(Utils::transform(toTrim, [](Node *n) { return static_cast<ProjectNode *>(n); }));
if (!FolderNode::trim(keepers))
return nullptr;
return (toTrim.count() != count) ? nullptr : this;
} }
/*! /*!

View File

@@ -144,8 +144,6 @@ public:
void emitNodeUpdated(); void emitNodeUpdated();
void emitTreeChanged(); void emitTreeChanged();
virtual Node *trim(const QSet<Node *> &keepers);
virtual FileNode *asFileNode() { return nullptr; } virtual FileNode *asFileNode() { return nullptr; }
virtual const FileNode *asFileNode() const { return nullptr; } virtual const FileNode *asFileNode() const { return nullptr; }
virtual FolderNode *asFolderNode() { return nullptr; } virtual FolderNode *asFolderNode() { return nullptr; }
@@ -208,8 +206,6 @@ public:
QString displayName() const override; QString displayName() const override;
QIcon icon() const; QIcon icon() const;
Node *trim(const QSet<Node *> &keepers) override;
QList<FileNode *> fileNodes() const; QList<FileNode *> fileNodes() const;
FileNode *fileNode(const Utils::FileName &file) const; FileNode *fileNode(const Utils::FileName &file) const;
FileNode *recursiveFileNode(const Utils::FileName &file) const; FileNode *recursiveFileNode(const Utils::FileName &file) const;
@@ -304,14 +300,13 @@ public:
ProjectNode *projectNode(const Utils::FileName &file) const; ProjectNode *projectNode(const Utils::FileName &file) const;
// all subFolders that are projects // all subFolders that are projects
QList<ProjectNode*> projectNodes() const; QList<ProjectNode*> projectNodes() const;
void addProjectNodes(const QList<ProjectNode*> &subProjects); void addProjectNode(ProjectNode *subProject);
void removeProjectNodes(const QList<ProjectNode*> &subProjects); void removeProjectNodes();
void removeProjectNode(ProjectNode *subProject);
ProjectNode *asProjectNode() final { return this; } ProjectNode *asProjectNode() final { return this; }
const ProjectNode *asProjectNode() const final { return this; } const ProjectNode *asProjectNode() const final { return this; }
Node *trim(const QSet<Node *> &keepers) override;
protected: protected:
// this is just the in-memory representation, a subclass // this is just the in-memory representation, a subclass
// will add the persistent stuff // will add the persistent stuff

View File

@@ -681,7 +681,6 @@ void QbsProductNode::setQbsProductData(const qbs::Project &project, const qbs::P
idx->setAbsoluteFilePathAndLine(Utils::FileName::fromString(prd.location().filePath()), idx->setAbsoluteFilePathAndLine(Utils::FileName::fromString(prd.location().filePath()),
prd.location().line()); prd.location().line());
QList<ProjectExplorer::ProjectNode *> toAdd;
QList<ProjectExplorer::ProjectNode *> toRemove = projectNodes(); QList<ProjectExplorer::ProjectNode *> toRemove = projectNodes();
foreach (const qbs::GroupData &grp, prd.groups()) { foreach (const qbs::GroupData &grp, prd.groups()) {
@@ -697,7 +696,7 @@ void QbsProductNode::setQbsProductData(const qbs::Project &project, const qbs::P
gn->updateQbsGroupData(grp, productPath, productWasEnabled, productIsEnabled); gn->updateQbsGroupData(grp, productPath, productWasEnabled, productIsEnabled);
} else { } else {
gn = new QbsGroupNode(grp, productPath); gn = new QbsGroupNode(grp, productPath);
toAdd.append(gn); addProjectNode(gn);
} }
} }
@@ -708,8 +707,8 @@ void QbsProductNode::setQbsProductData(const qbs::Project &project, const qbs::P
prd.buildDirectory(), true, true); prd.buildDirectory(), true, true);
} }
addProjectNodes(toAdd); for (ProjectNode *node : toRemove)
removeProjectNodes(toRemove); removeProjectNode(node);
m_qbsProductData = prd; m_qbsProductData = prd;
if (updateExisting) if (updateExisting)
@@ -761,7 +760,6 @@ QbsProjectNode::~QbsProjectNode()
void QbsProjectNode::update(const qbs::Project &qbsProject, const qbs::ProjectData &prjData) void QbsProjectNode::update(const qbs::Project &qbsProject, const qbs::ProjectData &prjData)
{ {
QList<ProjectExplorer::ProjectNode *> toAdd;
QList<ProjectExplorer::ProjectNode *> toRemove = projectNodes(); QList<ProjectExplorer::ProjectNode *> toRemove = projectNodes();
foreach (const qbs::ProjectData &subData, prjData.subProjects()) { foreach (const qbs::ProjectData &subData, prjData.subProjects()) {
@@ -770,7 +768,7 @@ void QbsProjectNode::update(const qbs::Project &qbsProject, const qbs::ProjectDa
auto subProject = auto subProject =
new QbsProjectNode(Utils::FileName::fromString(subData.location().filePath())); new QbsProjectNode(Utils::FileName::fromString(subData.location().filePath()));
subProject->update(qbsProject, subData); subProject->update(qbsProject, subData);
toAdd << subProject; addProjectNode(subProject);
} else { } else {
qn->update(qbsProject, subData); qn->update(qbsProject, subData);
toRemove.removeOne(qn); toRemove.removeOne(qn);
@@ -780,7 +778,7 @@ void QbsProjectNode::update(const qbs::Project &qbsProject, const qbs::ProjectDa
foreach (const qbs::ProductData &prd, prjData.products()) { foreach (const qbs::ProductData &prd, prjData.products()) {
QbsProductNode *qn = findProductNode(QbsProject::uniqueProductName(prd)); QbsProductNode *qn = findProductNode(QbsProject::uniqueProductName(prd));
if (!qn) { if (!qn) {
toAdd << new QbsProductNode(qbsProject, prd); addProjectNode(new QbsProductNode(qbsProject, prd));
} else { } else {
qn->setQbsProductData(qbsProject, prd); qn->setQbsProductData(qbsProject, prd);
toRemove.removeOne(qn); toRemove.removeOne(qn);
@@ -792,8 +790,8 @@ void QbsProjectNode::update(const qbs::Project &qbsProject, const qbs::ProjectDa
else else
setDisplayName(project()->displayName()); setDisplayName(project()->displayName());
removeProjectNodes(toRemove); foreach (ProjectNode *node, toRemove)
addProjectNodes(toAdd); removeProjectNode(node);
m_projectData = prjData; m_projectData = prjData;
} }

View File

@@ -2043,7 +2043,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
// delete files && folders && projects // delete files && folders && projects
setFileNodes({}); setFileNodes({});
removeProjectNodes(projectNodes()); removeProjectNodes();
setFolderNodes({}); setFolderNodes({});
m_projectType = InvalidProject; m_projectType = InvalidProject;
@@ -2065,7 +2065,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
} }
setFileNodes({}); setFileNodes({});
removeProjectNodes(projectNodes()); removeProjectNodes();
setFolderNodes({}); setFolderNodes({});
m_projectType = result->projectType; m_projectType = result->projectType;
@@ -2091,7 +2091,6 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
Utils::sort(existingProjectNodes, sortByPath); Utils::sort(existingProjectNodes, sortByPath);
// result is already sorted // result is already sorted
QList<ProjectNode*> toAdd;
QList<ProjectNode*> toRemove; QList<ProjectNode*> toRemove;
QList<ProjectNode*>::const_iterator existingIt = existingProjectNodes.constBegin(); QList<ProjectNode*>::const_iterator existingIt = existingProjectNodes.constBegin();
@@ -2130,21 +2129,19 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
} else { } else {
if (nodeToAdd->proFile) { if (nodeToAdd->proFile) {
QmakePriFileNode *qmakePriFileNode = new QmakePriFileNode(m_project, this, nodeToAdd->name); QmakePriFileNode *qmakePriFileNode = new QmakePriFileNode(m_project, this, nodeToAdd->name);
qmakePriFileNode->setParentFolderNode(pn); // Needed for loop detection pn->addProjectNode(qmakePriFileNode);
qmakePriFileNode->setIncludedInExactParse( qmakePriFileNode->setIncludedInExactParse(
(result->state == EvalResult::EvalOk) && pn->includedInExactParse()); (result->state == EvalResult::EvalOk) && pn->includedInExactParse());
toAdd << qmakePriFileNode;
qmakePriFileNode->update(nodeToAdd->result); qmakePriFileNode->update(nodeToAdd->result);
toCompare.append(qMakePair(qmakePriFileNode, nodeToAdd)); toCompare.append(qMakePair(qmakePriFileNode, nodeToAdd));
} else { } else {
QmakeProFileNode *qmakeProFileNode = new QmakeProFileNode(m_project, nodeToAdd->name); QmakeProFileNode *qmakeProFileNode = new QmakeProFileNode(m_project, nodeToAdd->name);
qmakeProFileNode->setParentFolderNode(pn); // Needed for loop detection pn->addProjectNode(qmakeProFileNode);
qmakeProFileNode->setIncludedInExactParse( qmakeProFileNode->setIncludedInExactParse(
result->exactSubdirs.contains(qmakeProFileNode->filePath()) result->exactSubdirs.contains(qmakeProFileNode->filePath())
&& pn->includedInExactParse()); && pn->includedInExactParse());
qmakeProFileNode->setParseInProgress(true); qmakeProFileNode->setParseInProgress(true);
qmakeProFileNode->asyncUpdate(); qmakeProFileNode->asyncUpdate();
toAdd << qmakeProFileNode;
} }
} }
} else { } else {
@@ -2176,12 +2173,8 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
qmakeProFileNode->setValidParseRecursive(false); qmakeProFileNode->setValidParseRecursive(false);
qmakeProFileNode->setParseInProgressRecursive(false); qmakeProFileNode->setParseInProgressRecursive(false);
} }
pn->removeProjectNode(node);
} }
if (!toRemove.isEmpty())
pn->removeProjectNodes(toRemove);
if (!toAdd.isEmpty())
pn->addProjectNodes(toAdd);
} }
QmakePriFileNode::update(result->includedFiles.result); QmakePriFileNode::update(result->includedFiles.result);

View File

@@ -91,18 +91,6 @@ static bool addFilesToResource(const Utils::FileName &resourceFile,
return true; return true;
} }
static bool sortByPrefixAndLang(ProjectExplorer::FolderNode *a, ProjectExplorer::FolderNode *b)
{
ResourceFolderNode *aa = static_cast<ResourceFolderNode *>(a);
ResourceFolderNode *bb = static_cast<ResourceFolderNode *>(b);
if (aa->prefix() < bb->prefix())
return true;
if (bb->prefix() < aa->prefix())
return false;
return aa->lang() < bb->lang();
}
ResourceTopLevelNode::ResourceTopLevelNode( ResourceTopLevelNode::ResourceTopLevelNode(
const Utils::FileName &filePath, const QString &contents, const Utils::FileName &filePath, const QString &contents,
ProjectExplorer::FolderNode *parent) ProjectExplorer::FolderNode *parent)