Commit 69627e49 authored by Tobias Hunger's avatar Tobias Hunger Committed by Tobias Hunger

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: default avatarhjk <hjk@qt.io>
parent 0ca288f5
...@@ -91,7 +91,7 @@ CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName) ...@@ -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() ...@@ -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 ...@@ -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 ...@@ -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)
{ {
......
...@@ -118,9 +118,6 @@ private: ...@@ -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);
......
...@@ -28,8 +28,8 @@ ...@@ -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)
{ {
} }
......
...@@ -35,7 +35,7 @@ namespace Internal { ...@@ -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;
}; };
......
...@@ -269,11 +269,102 @@ QList<FileNode*> FolderNode::fileNodes() const ...@@ -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() ...@@ -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 ...@@ -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)
......
...@@ -172,8 +172,11 @@ public: ...@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment