Add helper code to generate trees of project nodes

Add helper code to FolderNode that enables the creation of a tree
of File- and FolderNodes from a FolderNode and a list of FileNodes.

Change-Id: Iba4b6a768fc3d0501851f141372e7e34913ba518
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Tobias Hunger
2016-09-30 20:33:34 +02:00
committed by Tobias Hunger
parent 0ca288f518
commit 69627e494b
6 changed files with 106 additions and 107 deletions

View File

@@ -91,7 +91,7 @@ CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName)
setProjectManager(manager); setProjectManager(manager);
setDocument(new Internal::CMakeFile(this, fileName)); setDocument(new Internal::CMakeFile(this, fileName));
setRootProjectNode(new CMakeProjectNode(fileName)); setRootProjectNode(new CMakeProjectNode(Utils::FileName::fromString(fileName.toFileInfo().absolutePath())));
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT)); setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX)); setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX));
@@ -244,7 +244,8 @@ void CMakeProject::updateProjectData()
m_watchedFiles.insert(cm); m_watchedFiles.insert(cm);
} }
buildTree(static_cast<CMakeProjectNode *>(rootProjectNode()), bdm->files()); QList<FileNode *> fileNodes = bdm->files();
rootProjectNode()->buildTree(fileNodes);
bdm->clearFiles(); // Some of the FileNodes in files() were deleted! bdm->clearFiles(); // Some of the FileNodes in files() were deleted!
updateApplicationAndDeploymentTargets(); updateApplicationAndDeploymentTargets();
@@ -416,98 +417,6 @@ bool CMakeProject::hasBuildTarget(const QString &title) const
return Utils::anyOf(buildTargets(), [title](const CMakeBuildTarget &ct) { return ct.title == title; }); return Utils::anyOf(buildTargets(), [title](const CMakeBuildTarget &ct) { return ct.title == title; });
} }
void CMakeProject::gatherFileNodes(ProjectExplorer::FolderNode *parent, QList<ProjectExplorer::FileNode *> &list) const
{
foreach (ProjectExplorer::FolderNode *folder, parent->subFolderNodes())
gatherFileNodes(folder, list);
foreach (ProjectExplorer::FileNode *file, parent->fileNodes())
list.append(file);
}
bool sortNodesByPath(Node *a, Node *b)
{
return a->filePath() < b->filePath();
}
void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> newList)
{
// Gather old list
QList<ProjectExplorer::FileNode *> oldList;
gatherFileNodes(rootNode, oldList);
Utils::sort(oldList, sortNodesByPath);
Utils::sort(newList, sortNodesByPath);
QList<ProjectExplorer::FileNode *> added;
QList<ProjectExplorer::FileNode *> deleted;
ProjectExplorer::compareSortedLists(oldList, newList, deleted, added, sortNodesByPath);
qDeleteAll(ProjectExplorer::subtractSortedList(newList, added, sortNodesByPath));
QHash<ProjectExplorer::FolderNode *, QList<ProjectExplorer::FileNode *> > addedFolderMapping;
QHash<ProjectExplorer::FolderNode *, QList<ProjectExplorer::FileNode *> > deletedFolderMapping;
// add added nodes
foreach (ProjectExplorer::FileNode *fn, added) {
// Get relative path to rootNode
QString parentDir = fn->filePath().toFileInfo().absolutePath();
ProjectExplorer::FolderNode *folder = findOrCreateFolder(rootNode, parentDir);
addedFolderMapping[folder] << fn;
}
for (auto i = addedFolderMapping.constBegin(); i != addedFolderMapping.constEnd(); ++i)
i.key()->addFileNodes(i.value());
// remove old file nodes and check whether folder nodes can be removed
foreach (ProjectExplorer::FileNode *fn, deleted)
deletedFolderMapping[fn->parentFolderNode()] << fn;
for (auto i = deletedFolderMapping.constBegin(); i != deletedFolderMapping.constEnd(); ++i) {
ProjectExplorer::FolderNode *parent = i.key();
parent->removeFileNodes(i.value());
// Check for empty parent
while (parent->subFolderNodes().isEmpty() && parent->fileNodes().isEmpty()) {
ProjectExplorer::FolderNode *grandparent = parent->parentFolderNode();
grandparent->removeFolderNodes(QList<ProjectExplorer::FolderNode *>() << parent);
parent = grandparent;
if (parent == rootNode)
break;
}
}
}
ProjectExplorer::FolderNode *CMakeProject::findOrCreateFolder(CMakeProjectNode *rootNode, QString directory)
{
FileName path = rootNode->filePath().parentDir();
QDir rootParentDir(path.toString());
QString relativePath = rootParentDir.relativeFilePath(directory);
if (relativePath == QLatin1String("."))
relativePath.clear();
QStringList parts = relativePath.split(QLatin1Char('/'), QString::SkipEmptyParts);
ProjectExplorer::FolderNode *parent = rootNode;
foreach (const QString &part, parts) {
path.appendPath(part);
// Find folder in subFolders
bool found = false;
foreach (ProjectExplorer::FolderNode *folder, parent->subFolderNodes()) {
if (folder->filePath() == path) {
// yeah found something :)
parent = folder;
found = true;
break;
}
}
if (!found) {
// No FolderNode yet, so create it
auto tmp = new ProjectExplorer::FolderNode(path);
tmp->setDisplayName(part);
parent->addFolderNodes(QList<ProjectExplorer::FolderNode *>() << tmp);
parent = tmp;
}
}
return parent;
}
QString CMakeProject::displayName() const QString CMakeProject::displayName() const
{ {
return rootProjectNode()->displayName(); return rootProjectNode()->displayName();
@@ -515,9 +424,8 @@ QString CMakeProject::displayName() const
QStringList CMakeProject::files(FilesMode fileMode) const QStringList CMakeProject::files(FilesMode fileMode) const
{ {
QList<FileNode *> nodes; const QList<FileNode *> nodes = Utils::filtered(rootProjectNode()->recursiveFileNodes(),
gatherFileNodes(rootProjectNode(), nodes); [fileMode](const FileNode *fn) {
nodes = Utils::filtered(nodes, [fileMode](const FileNode *fn) {
const bool isGenerated = fn->isGenerated(); const bool isGenerated = fn->isGenerated();
switch (fileMode) switch (fileMode)
{ {

View File

@@ -118,9 +118,6 @@ private:
void updateProjectData(); void updateProjectData();
void updateQmlJSCodeModel(); void updateQmlJSCodeModel();
void buildTree(Internal::CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> list);
void gatherFileNodes(ProjectExplorer::FolderNode *parent, QList<ProjectExplorer::FileNode *> &list) const;
ProjectExplorer::FolderNode *findOrCreateFolder(Internal::CMakeProjectNode *rootNode, QString directory);
void createGeneratedCodeModelSupport(); void createGeneratedCodeModelSupport();
QStringList filesGeneratedFrom(const QString &sourceFile) const final; QStringList filesGeneratedFrom(const QString &sourceFile) const final;
void updateTargetRunConfigurations(ProjectExplorer::Target *t); void updateTargetRunConfigurations(ProjectExplorer::Target *t);

View File

@@ -28,8 +28,8 @@
using namespace CMakeProjectManager; using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal; using namespace CMakeProjectManager::Internal;
CMakeProjectNode::CMakeProjectNode(const Utils::FileName &fileName) CMakeProjectNode::CMakeProjectNode(const Utils::FileName &dirName)
: ProjectExplorer::ProjectNode(fileName) : ProjectExplorer::ProjectNode(dirName)
{ {
} }

View File

@@ -35,7 +35,7 @@ namespace Internal {
class CMakeProjectNode : public ProjectExplorer::ProjectNode class CMakeProjectNode : public ProjectExplorer::ProjectNode
{ {
public: public:
CMakeProjectNode(const Utils::FileName &fileName); CMakeProjectNode(const Utils::FileName &dirName);
bool showInSimpleTree() const override; bool showInSimpleTree() const override;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override; QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
}; };

View File

@@ -269,11 +269,102 @@ QList<FileNode*> FolderNode::fileNodes() const
return m_fileNodes; return m_fileNodes;
} }
QList<FileNode *> FolderNode::recursiveFileNodes() const
{
QList<FileNode *> result = fileNodes();
foreach (ProjectExplorer::FolderNode *folder, subFolderNodes())
result.append(folder->recursiveFileNodes());
return result;
}
QList<FolderNode*> FolderNode::subFolderNodes() const QList<FolderNode*> FolderNode::subFolderNodes() const
{ {
return m_subFolderNodes; return m_subFolderNodes;
} }
FolderNode *FolderNode::findOrCreateSubFolderNode(const QString &directory)
{
Utils::FileName path = filePath();
QDir parentDir(path.toString());
QString relativePath = parentDir.relativeFilePath(directory);
if (relativePath == ".")
relativePath.clear();
QStringList parts = relativePath.split('/', QString::SkipEmptyParts);
ProjectExplorer::FolderNode *parent = this;
foreach (const QString &part, parts) {
path.appendPath(part);
// Find folder in subFolders
bool found = false;
foreach (ProjectExplorer::FolderNode *folder, parent->subFolderNodes()) {
if (folder->filePath() == path) {
// yeah found something :)
parent = folder;
found = true;
break;
}
}
if (!found) {
// No FolderNode yet, so create it
auto tmp = new ProjectExplorer::FolderNode(path);
tmp->setDisplayName(part);
parent->addFolderNodes(QList<ProjectExplorer::FolderNode *>({ tmp }));
parent = tmp;
}
}
return parent;
}
static bool sortNodesByPath(Node *a, Node *b)
{
return a->filePath() < b->filePath();
}
void FolderNode::buildTree(QList<FileNode *> &files)
{
// Gather old list
QList<ProjectExplorer::FileNode *> oldFiles = recursiveFileNodes();
Utils::sort(oldFiles, sortNodesByPath);
Utils::sort(files, sortNodesByPath);
QList<ProjectExplorer::FileNode *> added;
QList<ProjectExplorer::FileNode *> deleted;
ProjectExplorer::compareSortedLists(oldFiles, files, deleted, added, sortNodesByPath);
qDeleteAll(ProjectExplorer::subtractSortedList(files, added, sortNodesByPath));
QHash<ProjectExplorer::FolderNode *, QList<ProjectExplorer::FileNode *> > addedFolderMapping;
QHash<ProjectExplorer::FolderNode *, QList<ProjectExplorer::FileNode *> > deletedFolderMapping;
// add added nodes
foreach (ProjectExplorer::FileNode *fn, added) {
// Get relative path to rootNode
QString parentDir = fn->filePath().toFileInfo().absolutePath();
ProjectExplorer::FolderNode *folder = findOrCreateSubFolderNode(parentDir);
addedFolderMapping[folder] << fn;
}
for (auto i = addedFolderMapping.constBegin(); i != addedFolderMapping.constEnd(); ++i)
i.key()->addFileNodes(i.value());
// remove old file nodes and check whether folder nodes can be removed
foreach (ProjectExplorer::FileNode *fn, deleted)
deletedFolderMapping[fn->parentFolderNode()] << fn;
for (auto i = deletedFolderMapping.constBegin(); i != deletedFolderMapping.constEnd(); ++i) {
ProjectExplorer::FolderNode *parent = i.key();
parent->removeFileNodes(i.value());
// Check for empty parent
while (parent->subFolderNodes().isEmpty() && parent->fileNodes().isEmpty()) {
ProjectExplorer::FolderNode *grandparent = parent->parentFolderNode();
grandparent->removeFolderNodes(QList<ProjectExplorer::FolderNode *>() << parent);
parent = grandparent;
if (parent == this)
break;
}
}
}
void FolderNode::accept(NodesVisitor *visitor) void FolderNode::accept(NodesVisitor *visitor)
{ {
visitor->visitFolderNode(this); visitor->visitFolderNode(this);
@@ -707,7 +798,7 @@ ProjectNode *ProjectNode::asProjectNode()
*/ */
SessionNode::SessionNode() : SessionNode::SessionNode() :
FolderNode(Utils::FileName::fromString(QLatin1String("session")), SessionNodeType) FolderNode(Utils::FileName::fromString("session"), SessionNodeType)
{ } { }
QList<ProjectAction> SessionNode::supportedActions(Node *node) const QList<ProjectAction> SessionNode::supportedActions(Node *node) const
@@ -747,7 +838,7 @@ QList<ProjectNode*> SessionNode::projectNodes() const
QString SessionNode::addFileFilter() const QString SessionNode::addFileFilter() const
{ {
return QLatin1String("*.c; *.cc; *.cpp; *.cp; *.cxx; *.c++; *.h; *.hh; *.hpp; *.hxx;"); return QString::fromLatin1("*.c; *.cc; *.cpp; *.cp; *.cxx; *.c++; *.h; *.hh; *.hpp; *.hxx;");
} }
void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes) void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes)

View File

@@ -172,8 +172,11 @@ public:
QString displayName() const override; QString displayName() const override;
QIcon icon() const; QIcon icon() const;
QList<FileNode*> fileNodes() const; QList<FileNode *> fileNodes() const;
QList<FolderNode*> subFolderNodes() const; QList<FileNode *> recursiveFileNodes() const;
QList<FolderNode *> subFolderNodes() const;
FolderNode *findOrCreateSubFolderNode(const QString &directory);
void buildTree(QList<FileNode *> &files);
virtual void accept(NodesVisitor *visitor); virtual void accept(NodesVisitor *visitor);