diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index dae9d01613c..63ac304d81f 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -298,9 +298,10 @@ void BuildDirManager::resetData() m_reader->resetData(); m_cmakeCache.clear(); + QTC_ASSERT(!m_futureInterface || m_futureInterface->isFinished(), return); m_futureInterface.reset(); - m_reader.reset(nullptr); + m_reader.reset(); } bool BuildDirManager::updateCMakeStateBeforeBuild() @@ -323,7 +324,7 @@ bool BuildDirManager::persistCMakeState() return true; } -void BuildDirManager::generateProjectTree(CMakeProjectNode *root) +void BuildDirManager::generateProjectTree(CMakeListsNode *root) { QTC_ASSERT(m_reader, return); QTC_ASSERT(m_futureInterface, return); diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h index 3d3a98411bb..eb670626622 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.h +++ b/src/plugins/cmakeprojectmanager/builddirmanager.h @@ -72,7 +72,7 @@ public: bool updateCMakeStateBeforeBuild(); bool persistCMakeState(); - void generateProjectTree(CMakeProjectNode *root); + void generateProjectTree(CMakeListsNode *root); QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder); QList buildTargets() const; diff --git a/src/plugins/cmakeprojectmanager/builddirreader.h b/src/plugins/cmakeprojectmanager/builddirreader.h index db0a5bfc463..d76cf9eaf6e 100644 --- a/src/plugins/cmakeprojectmanager/builddirreader.h +++ b/src/plugins/cmakeprojectmanager/builddirreader.h @@ -49,6 +49,7 @@ namespace CMakeProjectManager { namespace Internal { class CMakeBuildConfiguration; +class CMakeListsNode; class BuildDirReader : public QObject { @@ -100,7 +101,7 @@ public: virtual CMakeConfig parsedConfiguration() const = 0; virtual QList buildTargets() const = 0; - virtual void generateProjectTree(CMakeProjectNode *root, + virtual void generateProjectTree(CMakeListsNode *root, const QList &allFiles) = 0; virtual QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) = 0; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 34dac4e1d66..e3770a989ff 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -202,7 +202,7 @@ QList CMakeBuildConfiguration::buildTargets() const return m_buildDirManager->buildTargets(); } -void CMakeBuildConfiguration::generateProjectTree(CMakeProjectNode *root) const +void CMakeBuildConfiguration::generateProjectTree(CMakeListsNode *root) const { if (!m_buildDirManager || m_buildDirManager->isParsing()) return; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index a4cf71d12e7..3ef255907a5 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -46,6 +46,7 @@ namespace Internal { class BuildDirManager; class CMakeBuildConfigurationFactory; class CMakeBuildSettingsWidget; +class CMakeListsNode; class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration { @@ -84,7 +85,7 @@ public: void clearCache(); QList buildTargets() const; - void generateProjectTree(CMakeProjectNode *root) const; + void generateProjectTree(CMakeListsNode *root) const; QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder); static Utils::FileName diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 0c266fbf6b6..5cb22147f2e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -78,7 +78,7 @@ CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName) setDocument(new TextEditor::TextDocument); document()->setFilePath(fileName); - setRootProjectNode(new CMakeProjectNode(FileName::fromString(fileName.toFileInfo().absolutePath()))); + setRootProjectNode(new CMakeListsNode(fileName)); setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT)); setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX)); @@ -104,7 +104,7 @@ void CMakeProject::updateProjectData() return; Kit *k = t->kit(); - cmakeBc->generateProjectTree(static_cast(rootProjectNode())); + cmakeBc->generateProjectTree(static_cast(rootProjectNode())); updateApplicationAndDeploymentTargets(); updateTargetRunConfigurations(t); diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 0cb58b9494a..eab29256775 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -41,9 +41,8 @@ QT_END_NAMESPACE namespace CMakeProjectManager { namespace Internal { -class CMakeBuildSettingsWidget; class CMakeBuildConfiguration; -class CMakeProjectNode; +class CMakeBuildSettingsWidget; class CMakeManager; } // namespace Internal @@ -76,8 +75,7 @@ public: class CMAKE_EXPORT CMakeProject : public ProjectExplorer::Project { Q_OBJECT - // for changeBuildDirectory - friend class Internal::CMakeBuildSettingsWidget; + public: CMakeProject(Internal::CMakeManager *manager, const Utils::FileName &filename); ~CMakeProject() final; @@ -128,6 +126,7 @@ private: QList m_extraCompilers; friend class Internal::CMakeBuildConfiguration; + friend class Internal::CMakeBuildSettingsWidget; }; } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index f42d08c6278..b8c9d43eb87 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -25,22 +25,122 @@ #include "cmakeprojectnodes.h" +#include "cmakeprojectconstants.h" + +#include + +#include + +#include + using namespace CMakeProjectManager; using namespace CMakeProjectManager::Internal; -CMakeProjectNode::CMakeProjectNode(const Utils::FileName &dirName) - : ProjectExplorer::ProjectNode(dirName) +CMakeInputsNode::CMakeInputsNode(const Utils::FileName &cmakeLists) : + ProjectExplorer::ProjectNode(CMakeInputsNode::inputsPathFromCMakeListsPath(cmakeLists)) { + setPriority(Node::DefaultPriority - 10); // Bottom most! + setDisplayName(QCoreApplication::translate("CMakeFilesProjectNode", "CMake Modules")); + setIcon(QIcon(":/projectexplorer/images/session.png")); // TODO: Use a better icon! } -bool CMakeProjectNode::showInSimpleTree() const +Utils::FileName CMakeInputsNode::inputsPathFromCMakeListsPath(const Utils::FileName &cmakeLists) { - // TODO - return true; + Utils::FileName result = cmakeLists; + result.appendPath("cmakeInputs"); // cmakeLists is a file, so this can not exist on disk + return result; } -QList CMakeProjectNode::supportedActions(Node *node) const +bool CMakeInputsNode::showInSimpleTree() const +{ + return false; +} + +QList CMakeInputsNode::supportedActions(ProjectExplorer::Node *node) const { Q_UNUSED(node); return QList(); } + +CMakeListsNode::CMakeListsNode(const Utils::FileName &cmakeListPath) : + ProjectExplorer::ProjectNode(cmakeListPath) +{ + static QIcon folderIcon; + if (folderIcon.isNull()) { + const QIcon overlayIcon(Constants::FILEOVERLAY_CMAKE); + QPixmap dirPixmap = qApp->style()->standardIcon(QStyle::SP_DirIcon).pixmap(QSize(16, 16)); + + folderIcon.addPixmap(Core::FileIconProvider::overlayIcon(dirPixmap, overlayIcon)); + } + setIcon(folderIcon); +} + +bool CMakeListsNode::showInSimpleTree() const +{ + return false; +} + +QList CMakeListsNode::supportedActions(ProjectExplorer::Node *node) const +{ + Q_UNUSED(node); + return QList(); +} + +CMakeProjectNode::CMakeProjectNode(const Utils::FileName &directory) : + ProjectExplorer::ProjectNode(directory) +{ + setPriority(Node::DefaultProjectPriority + 1000); + setIcon(QIcon(":/projectexplorer/images/projectexplorer.png")); // TODO: Use proper icon! +} + +bool CMakeProjectNode::showInSimpleTree() const +{ + return true; +} + +QString CMakeProjectNode::tooltip() const +{ + return QString(); +} + +QList CMakeProjectNode::supportedActions(ProjectExplorer::Node *node) const +{ + Q_UNUSED(node); + return QList(); +} + +CMakeTargetNode::CMakeTargetNode(const Utils::FileName &directory) : + ProjectExplorer::ProjectNode(directory) +{ + setPriority(Node::DefaultProjectPriority + 900); + setIcon(QIcon(":/projectexplorer/images/build.png")); // TODO: Use proper icon! +} + +bool CMakeTargetNode::showInSimpleTree() const +{ + return true; +} + +QString CMakeTargetNode::tooltip() const +{ + return m_tooltip; +} + +QList CMakeTargetNode::supportedActions(ProjectExplorer::Node *node) const +{ + Q_UNUSED(node); + return QList(); +} + +void CMakeTargetNode::setTargetInformation(const QList &artifacts, + const QString &type) +{ + m_tooltip = QCoreApplication::translate("CMakeTargetNode", "Target type: ") + type + "
"; + if (artifacts.count() == 0) { + m_tooltip += QCoreApplication::translate("CMakeTargetNode", "No build artifacts"); + } else { + const QStringList tmp = Utils::transform(artifacts, &Utils::FileName::toUserOutput); + m_tooltip += QCoreApplication::translate("CMakeTargetNode", "Build artifacts:
") + + tmp.join("
"); + } +} diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h index 34a2e73619a..ca1fedd6e82 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h @@ -32,12 +32,49 @@ class CMakeProject; namespace Internal { +class CMakeInputsNode : public ProjectExplorer::ProjectNode +{ +public: + CMakeInputsNode(const Utils::FileName &cmakeLists); + + static Utils::FileName inputsPathFromCMakeListsPath(const Utils::FileName &cmakeLists); + + bool showInSimpleTree() const final; + QList supportedActions(Node *node) const final; +}; + +class CMakeListsNode : public ProjectExplorer::ProjectNode +{ +public: + CMakeListsNode(const Utils::FileName &cmakeListPath); + + bool showInSimpleTree() const final; + QList supportedActions(Node *node) const final; +}; + class CMakeProjectNode : public ProjectExplorer::ProjectNode { public: - CMakeProjectNode(const Utils::FileName &dirName); - bool showInSimpleTree() const override; - QList supportedActions(Node *node) const override; + CMakeProjectNode(const Utils::FileName &directory); + + bool showInSimpleTree() const final; + QString tooltip() const final; + QList supportedActions(Node *node) const final; +}; + +class CMakeTargetNode : public ProjectExplorer::ProjectNode +{ +public: + CMakeTargetNode(const Utils::FileName &directory); + + void setTargetInformation(const QList &artifacts, const QString &type); + + bool showInSimpleTree() const final; + QString tooltip() const final; + QList supportedActions(Node *node) const final; + +private: + QString m_tooltip; }; } // namespace Internal diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp index 5295a07ccd0..08c2df6f22c 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.cpp +++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp @@ -211,24 +211,90 @@ CMakeConfig ServerModeReader::parsedConfiguration() const return m_cmakeCache; } -void ServerModeReader::generateProjectTree(CMakeProjectNode *root, const QList &allFiles) +FolderNode *setupCMakeVFolder(FolderNode *base, const Utils::FileName &basePath, int priority, + const QString &displayName, QList &files) { - Q_UNUSED(allFiles); - QSet knownFiles; - for (auto it = m_cmakeInputsFileNodes.constBegin(); it != m_cmakeInputsFileNodes.constEnd(); ++it) - knownFiles.insert((*it)->filePath()); - - QList fileGroupNodes = m_cmakeInputsFileNodes; - m_cmakeInputsFileNodes.clear(); // Clean out, they are not going to be used anymore! - foreach (const FileGroup *fg, m_fileGroups) { - for (const FileName &s : fg->sources) { - const int oldCount = knownFiles.count(); - knownFiles.insert(s); - if (oldCount != knownFiles.count()) - fileGroupNodes.append(new FileNode(s, FileType::Source, fg->isGenerated)); + FolderNode *folder + = findOrDefault(base->folderNodes(), [basePath](const FolderNode *fn) { + return fn->filePath() == basePath; + }); + if (files.isEmpty()) { + return folder; + } else { + if (!folder) { + folder = new VirtualFolderNode(basePath, priority); + folder->setDisplayName(displayName); + base->addFolderNodes({ folder }); } + folder->buildTree(files); } - root->buildTree(fileGroupNodes); + return nullptr; +} + +static ProjectNode *updateCMakeInputs(CMakeListsNode *root, + const Utils::FileName &sourceDir, + const Utils::FileName &buildDir, + QList &sourceInputs, + QList &buildInputs, + QList &rootInputs) +{ + ProjectNode *cmakeVFolder + = root->projectNode(CMakeInputsNode::inputsPathFromCMakeListsPath(root->filePath())); + if (!cmakeVFolder) { + cmakeVFolder = new CMakeInputsNode(root->filePath()); + root->addProjectNodes({ cmakeVFolder }); + } + + QList foldersToDelete; + foldersToDelete.append(setupCMakeVFolder(cmakeVFolder, sourceDir, 1000, + QCoreApplication::translate("CMakeProjectManager::Internal", "Source Directory"), + sourceInputs)); + foldersToDelete.append(setupCMakeVFolder(cmakeVFolder, buildDir, 100, + QCoreApplication::translate("CMakeProjectManager::Internal", "Build Directory"), + buildInputs)); + foldersToDelete.append(setupCMakeVFolder(cmakeVFolder, Utils::FileName(), 10, + QCoreApplication::translate("CMakeProjectManager::Internal", "Other Locations"), + rootInputs)); + + // Clean out unused nodes in "CMake Files": + const QList tmp = filtered(foldersToDelete, [](const FolderNode *fn) { return fn; }); + cmakeVFolder->removeFolderNodes(tmp); + + return cmakeVFolder; +} + +void ServerModeReader::generateProjectTree(CMakeListsNode *root, const QList &allFiles) +{ + // Split up cmake inputs into useful chunks: + QList cmakeFilesSource; + QList cmakeFilesBuild; + QList cmakeFilesOther; + QList cmakeLists; + foreach (FileNode *fn, m_cmakeInputsFileNodes) { + const FileName path = fn->filePath(); + if (path.fileName().compare("CMakeLists.txt", HostOsInfo::fileNameCaseSensitivity()) == 0) + cmakeLists.append(fn); + else if (path.isChildOf(m_parameters.sourceDirectory)) + cmakeFilesSource.append(fn); + else if (path.isChildOf(m_parameters.buildDirectory)) + cmakeFilesBuild.append(fn); + else + cmakeFilesOther.append(fn); + } + m_cmakeInputsFileNodes.clear(); // Clean out, they are not going to be used anymore! + + if (!m_projects.isEmpty()) + root->setDisplayName(m_projects.at(0)->name); + + QSet usedNodes; + usedNodes.insert(updateCMakeInputs(root, m_parameters.sourceDirectory, m_parameters.buildDirectory, + cmakeFilesSource, cmakeFilesBuild, cmakeFilesOther)); + + usedNodes.unite(updateCMakeLists(root, cmakeLists)); + usedNodes.unite(updateProjects(root, m_projects, allFiles)); + + // Trim out unused nodes: + root->trim(usedNodes); } QSet ServerModeReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) @@ -448,5 +514,231 @@ void ServerModeReader::extractCacheData(const QVariantMap &data) m_cmakeCache = config; } +QSet ServerModeReader::updateCMakeLists(CMakeListsNode *root, + const QList &cmakeLists) +{ + QSet usedNodes; + + const QDir baseDir = QDir(root->filePath().parentDir().toString()); + + QHash nodeHash; + for (FileNode *cm : cmakeLists) { + const QString relPath = baseDir.relativeFilePath(cm->filePath().parentDir().toString()); + QTC_CHECK(!nodeHash.contains(relPath)); + nodeHash[(relPath == ".") ? QString() : relPath ] = cm; + } + QStringList tmp = nodeHash.keys(); + Utils::sort(tmp, [](const QString &a, const QString &b) { return a.count() < b.count(); }); + const QStringList keys = tmp; + + QHash knownNodes; + knownNodes[QString()] = root; + + for (const QString &k : keys) { + FileNode *fn = nodeHash[k]; + CMakeListsNode *parentNode = nullptr; + QString prefix = k; + forever { + if (knownNodes.contains(prefix)) { + parentNode = knownNodes.value(prefix); + break; + } + const int pos = prefix.lastIndexOf('/'); + prefix = (pos < 0) ? QString() : prefix.left(prefix.lastIndexOf('/')); + } + + // Find or create CMakeListsNode: + CMakeListsNode *cmln = nullptr; + if (parentNode->filePath() == fn->filePath()) + cmln = parentNode; // Top level! + else + cmln = static_cast(parentNode->projectNode(fn->filePath())); + if (!cmln) { + cmln = new CMakeListsNode(fn->filePath()); + parentNode->addProjectNodes({ cmln }); + } + + // Find or create CMakeLists.txt filenode below CMakeListsNode: + FileNode *cmFn = cmln->fileNode(fn->filePath()); + if (!cmFn) { + cmFn = fn; + cmln->addFileNodes({ cmFn }); + } + usedNodes.insert(cmFn); // register existing CMakeLists.txt filenode + + // Update displayName of CMakeListsNode: + const QString dn = prefix.isEmpty() ? k : k.mid(prefix.count() + 1); + if (!dn.isEmpty()) + cmln->setDisplayName(dn); // Set partial path as display name + + knownNodes.insert(k, cmln); + } + + return usedNodes; +} + +static CMakeListsNode *findCMakeNode(CMakeListsNode *root, const Utils::FileName &dir) +{ + Utils::FileName stepDir = dir; + + CMakeListsNode *base = root; + forever { + Utils::FileName stepLists = stepDir; + stepLists.appendPath("CMakeLists.txt"); + + CMakeListsNode *cmln = nullptr; + if (base->filePath() == stepLists) { + cmln = base; + } else { + ProjectNode *pcmln = base->projectNode(stepLists); + cmln = static_cast(pcmln); + } + + if (!cmln) { + stepDir = stepDir.parentDir(); + if (stepDir.isEmpty()) + return nullptr; + } else { + if (cmln->filePath().parentDir() == dir) + return cmln; + stepDir = dir; + base = cmln; + } + } +} + +static CMakeProjectNode *findOrCreateProjectNode(CMakeListsNode *root, const Utils::FileName &dir, + const QString &displayName) +{ + CMakeListsNode *cmln = findCMakeNode(root, dir); + QTC_ASSERT(cmln, return nullptr); + + Utils::FileName projectName = dir; + projectName.appendPath(".project::" + displayName); + + CMakeProjectNode *pn = static_cast(cmln->projectNode(projectName)); + if (!pn) { + pn = new CMakeProjectNode(projectName); + cmln->addProjectNodes({ pn }); + } + pn->setDisplayName(displayName); + return pn; +} + +QSet ServerModeReader::updateProjects(CMakeListsNode *root, + const QList &projects, + const QList &allFiles) +{ + QSet usedNodes; + + QHash> includeFiles; + for (FileNode *f : allFiles) { + if (f->fileType() != FileType::Header) + continue; + includeFiles[f->filePath().parentDir()].append(f); + } + + for (const Project *p : projects) { + CMakeProjectNode *pNode = findOrCreateProjectNode(root, p->sourceDirectory, p->name); + QTC_ASSERT(pNode, continue); + usedNodes.insert(pNode); // Mark as leaf to keep. + + usedNodes.unite(updateTargets(root, p->targets, includeFiles)); + } + return usedNodes; +} + +static CMakeTargetNode *findOrCreateTargetNode(CMakeListsNode *root, const Utils::FileName &dir, + const QString &displayName) +{ + CMakeListsNode *cmln = findCMakeNode(root, dir); + QTC_ASSERT(cmln, return nullptr); + + Utils::FileName targetName = dir; + targetName.appendPath(".target::" + displayName); + + CMakeTargetNode *tn = static_cast(cmln->projectNode(targetName)); + if (!tn) { + tn = new CMakeTargetNode(targetName); + cmln->addProjectNodes({ tn }); + } + tn->setDisplayName(displayName); + return tn; +} + +QSet ServerModeReader::updateTargets(CMakeListsNode *root, + const QList &targets, + const QHash > &headers) +{ + QSet usedNodes; + for (const Target *t : targets) { + + CMakeTargetNode *tNode = findOrCreateTargetNode(root, t->sourceDirectory, t->name); + tNode->setTargetInformation(t->artifacts, t->type); + + usedNodes.unite(updateFileGroups(tNode, t->sourceDirectory, t->buildDirectory, + t->fileGroups, headers)); + } + return usedNodes; +} + +static Utils::FileName mapFileName(const Utils::FileName &fn, const Utils::FileName &sourceDirectory, + const Utils::FileName &buildDirectory) +{ + if (fn.isChildOf(buildDirectory)) { + Utils::FileName mapped = sourceDirectory; + mapped.appendPath(QCoreApplication::translate("CMakeProjectManager::Internal", "")); + QDir bd = QDir(buildDirectory.toString()); + mapped.appendPath(bd.relativeFilePath(fn.toString())); + return mapped; + } + return fn; +} + +QSet ServerModeReader::updateFileGroups(ProjectNode *targetRoot, + const Utils::FileName &sourceDirectory, + const Utils::FileName &buildDirectory, + const QList &fileGroups, + const QHash > &headers) +{ + QSet usedNodes; + QList toList; + QSet alreadyListed; + for (const FileGroup *f : fileGroups) { + const QList newSources = Utils::filtered(f->sources, [&alreadyListed](const Utils::FileName &fn) { + const int count = alreadyListed.count(); + alreadyListed.insert(fn); + return count != alreadyListed.count(); + }); + const QList newFileNodes = Utils::transform(newSources, [f, &sourceDirectory, &buildDirectory](const Utils::FileName &fn) { + return new FileNode(mapFileName(fn, sourceDirectory, buildDirectory), FileType::Source, f->isGenerated); + }); + toList.append(newFileNodes); + + // Add scanned header files: + for (const IncludePath *i : f->includePaths) { + const QList &headerFiles = headers.value(i->path); + const QList unseenHeaders = Utils::filtered(headerFiles, [&alreadyListed](const FileNode *fn) { + const int count = alreadyListed.count(); + alreadyListed.insert(fn->filePath()); + return count != alreadyListed.count(); + }); + toList.append(Utils::transform(unseenHeaders, [&sourceDirectory, &buildDirectory](FileNode *fn) -> FileNode * { + const Utils::FileName mappedPath = mapFileName(fn->filePath(), sourceDirectory, buildDirectory); + auto copy = new FileNode(mappedPath, fn->fileType(), fn->isGenerated()); + copy->setEnabled(false); + return copy; + })); + } + } + + targetRoot->buildTree(toList, sourceDirectory); + + foreach (FileNode *fn, toList) + usedNodes.insert(static_cast(fn)); // Mark all leaves as keeper! + + return usedNodes; +} + } // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h index 933542e71d8..d49d3c48dc0 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.h +++ b/src/plugins/cmakeprojectmanager/servermodereader.h @@ -64,7 +64,7 @@ public: QList buildTargets() const final; CMakeConfig parsedConfiguration() const final; - void generateProjectTree(CMakeProjectNode *root, const QList &allFiles) final; + void generateProjectTree(CMakeListsNode *root, const QList &allFiles) final; QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final; private: @@ -119,6 +119,20 @@ private: void extractCMakeInputsData(const QVariantMap &data); void extractCacheData(const QVariantMap &data); + QSet updateCMakeLists(CMakeListsNode *root, + const QList &cmakeLists); + QSet updateProjects(CMakeListsNode *root, + const QList &projects, + const QList &allFiles); + QSet updateTargets(CMakeListsNode *root, + const QList &targets, + const QHash> &headers); + QSet updateFileGroups(ProjectExplorer::ProjectNode *targetRoot, + const Utils::FileName &sourceDirectory, + const Utils::FileName &buildDirectory, + const QList &fileGroups, + const QHash> &headers); + bool m_hasData = false; std::unique_ptr m_cmakeServer; diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp index 9ed8373f522..6b8b1d63832 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.cpp +++ b/src/plugins/cmakeprojectmanager/tealeafreader.cpp @@ -318,7 +318,7 @@ CMakeConfig TeaLeafReader::parseConfiguration(const FileName &cacheFile, QString return result; } -void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList &allFiles) +void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList &allFiles) { root->setDisplayName(m_projectName); diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.h b/src/plugins/cmakeprojectmanager/tealeafreader.h index beecfa6b768..45ecc2486d0 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.h +++ b/src/plugins/cmakeprojectmanager/tealeafreader.h @@ -52,7 +52,7 @@ public: QList buildTargets() const final; CMakeConfig parsedConfiguration() const final; - void generateProjectTree(CMakeProjectNode *root, + void generateProjectTree(CMakeListsNode *root, const QList &allFiles) final; QSet updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final;