forked from qt-creator/qt-creator
Change-Id: I7165fa1d219a0c59bc519a9af1cd194414c4311c Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
225 lines
8.2 KiB
C++
225 lines
8.2 KiB
C++
// Copyright (C) 2016 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
#include "projecttreehelper.h"
|
|
|
|
#include "cmakeproject.h"
|
|
#include "cmakeprojectconstants.h"
|
|
#include "cmakeprojectmanagertr.h"
|
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
#include <projectexplorer/projectmanager.h>
|
|
|
|
#include <utils/algorithm.h>
|
|
#include <utils/fsengine/fileiconprovider.h>
|
|
#include <utils/qtcassert.h>
|
|
|
|
using namespace ProjectExplorer;
|
|
|
|
namespace CMakeProjectManager::Internal {
|
|
|
|
std::unique_ptr<FolderNode> createCMakeVFolder(const Utils::FilePath &basePath,
|
|
int priority,
|
|
const QString &displayName,
|
|
bool sourcesOrHeaders)
|
|
{
|
|
auto newFolder = std::make_unique<VirtualFolderNode>(basePath);
|
|
newFolder->setPriority(priority);
|
|
newFolder->setDisplayName(displayName);
|
|
newFolder->setIsSourcesOrHeaders(sourcesOrHeaders);
|
|
return newFolder;
|
|
}
|
|
|
|
void addCMakeVFolder(FolderNode *base,
|
|
const Utils::FilePath &basePath,
|
|
int priority,
|
|
const QString &displayName,
|
|
std::vector<std::unique_ptr<FileNode>> &&files,
|
|
bool sourcesOrHeaders)
|
|
{
|
|
if (files.size() == 0)
|
|
return;
|
|
FolderNode *folder = base;
|
|
if (!displayName.isEmpty()) {
|
|
auto newFolder = createCMakeVFolder(basePath, priority, displayName, sourcesOrHeaders);
|
|
folder = newFolder.get();
|
|
base->addNode(std::move(newFolder));
|
|
}
|
|
folder->addNestedNodes(std::move(files));
|
|
folder->forEachFolderNode([] (FolderNode *fn) { fn->compress(); });
|
|
}
|
|
|
|
std::vector<std::unique_ptr<FileNode>> &&removeKnownNodes(
|
|
const QSet<Utils::FilePath> &knownFiles, std::vector<std::unique_ptr<FileNode>> &&files)
|
|
{
|
|
Utils::erase(files, [&knownFiles](const std::unique_ptr<FileNode> &n) {
|
|
return knownFiles.contains(n->filePath());
|
|
});
|
|
return std::move(files);
|
|
}
|
|
|
|
void addCMakeInputs(FolderNode *root,
|
|
const Utils::FilePath &sourceDir,
|
|
const Utils::FilePath &buildDir,
|
|
std::vector<std::unique_ptr<FileNode>> &&sourceInputs,
|
|
std::vector<std::unique_ptr<FileNode>> &&buildInputs,
|
|
std::vector<std::unique_ptr<FileNode>> &&rootInputs)
|
|
{
|
|
std::unique_ptr<ProjectNode> cmakeVFolder = std::make_unique<CMakeInputsNode>(root->filePath());
|
|
|
|
QSet<Utils::FilePath> knownFiles;
|
|
root->forEachGenericNode([&knownFiles](const Node *n) {
|
|
if (n->listInProject())
|
|
knownFiles.insert(n->filePath());
|
|
});
|
|
|
|
addCMakeVFolder(cmakeVFolder.get(),
|
|
sourceDir,
|
|
1000,
|
|
QString(),
|
|
removeKnownNodes(knownFiles, std::move(sourceInputs)));
|
|
addCMakeVFolder(cmakeVFolder.get(),
|
|
buildDir,
|
|
100,
|
|
Tr::tr("<Build Directory>"),
|
|
removeKnownNodes(knownFiles, std::move(buildInputs)));
|
|
addCMakeVFolder(cmakeVFolder.get(),
|
|
Utils::FilePath(),
|
|
10,
|
|
Tr::tr("<Other Locations>"),
|
|
removeKnownNodes(knownFiles, std::move(rootInputs)));
|
|
|
|
root->addNode(std::move(cmakeVFolder));
|
|
}
|
|
|
|
void addCMakePresets(FolderNode *root, const Utils::FilePath &sourceDir)
|
|
{
|
|
QStringList presetFileNames;
|
|
presetFileNames << "CMakePresets.json";
|
|
presetFileNames << "CMakeUserPresets.json";
|
|
|
|
const CMakeProject *cp = static_cast<const CMakeProject *>(
|
|
ProjectManager::projectForFile(sourceDir.pathAppended(Constants::CMAKE_LISTS_TXT)));
|
|
|
|
if (cp && cp->presetsData().include)
|
|
presetFileNames.append(cp->presetsData().include.value());
|
|
|
|
std::vector<std::unique_ptr<FileNode>> presets;
|
|
for (const auto &fileName : presetFileNames) {
|
|
Utils::FilePath file = sourceDir.pathAppended(fileName);
|
|
if (file.exists())
|
|
presets.push_back(std::make_unique<FileNode>(file, Node::fileTypeForFileName(file)));
|
|
}
|
|
|
|
if (presets.empty())
|
|
return;
|
|
|
|
std::unique_ptr<ProjectNode> cmakeVFolder = std::make_unique<CMakePresetsNode>(root->filePath());
|
|
addCMakeVFolder(cmakeVFolder.get(), sourceDir, 1000, QString(), std::move(presets));
|
|
|
|
root->addNode(std::move(cmakeVFolder));
|
|
}
|
|
|
|
QHash<Utils::FilePath, ProjectNode *> addCMakeLists(
|
|
CMakeProjectNode *root, std::vector<std::unique_ptr<FileNode>> &&cmakeLists)
|
|
{
|
|
QHash<Utils::FilePath, ProjectNode *> cmakeListsNodes;
|
|
cmakeListsNodes.insert(root->filePath(), root);
|
|
|
|
const QSet<Utils::FilePath> cmakeDirs
|
|
= Utils::transform<QSet>(cmakeLists, [](const std::unique_ptr<FileNode> &n) {
|
|
return n->filePath().parentDir();
|
|
});
|
|
root->addNestedNodes(std::move(cmakeLists),
|
|
Utils::FilePath(),
|
|
[&cmakeDirs, &cmakeListsNodes](const Utils::FilePath &fp)
|
|
-> std::unique_ptr<ProjectExplorer::FolderNode> {
|
|
if (cmakeDirs.contains(fp)) {
|
|
auto fn = std::make_unique<CMakeListsNode>(fp);
|
|
cmakeListsNodes.insert(fp, fn.get());
|
|
return fn;
|
|
}
|
|
|
|
return std::make_unique<FolderNode>(fp);
|
|
});
|
|
root->compress();
|
|
return cmakeListsNodes;
|
|
}
|
|
|
|
void createProjectNode(const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes,
|
|
const Utils::FilePath &dir,
|
|
const QString &displayName)
|
|
{
|
|
ProjectNode *cmln = cmakeListsNodes.value(dir);
|
|
QTC_ASSERT(cmln, return );
|
|
|
|
const Utils::FilePath projectName = dir.pathAppended(".project::" + displayName);
|
|
|
|
ProjectNode *pn = cmln->projectNode(projectName);
|
|
if (!pn) {
|
|
auto newNode = std::make_unique<CMakeProjectNode>(projectName);
|
|
pn = newNode.get();
|
|
cmln->addNode(std::move(newNode));
|
|
}
|
|
pn->setDisplayName(displayName);
|
|
}
|
|
|
|
CMakeTargetNode *createTargetNode(const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes,
|
|
const Utils::FilePath &dir,
|
|
const QString &displayName)
|
|
{
|
|
ProjectNode *cmln = cmakeListsNodes.value(dir);
|
|
QTC_ASSERT(cmln, return nullptr);
|
|
|
|
QString targetId = displayName;
|
|
|
|
CMakeTargetNode *tn = static_cast<CMakeTargetNode *>(
|
|
cmln->findNode([&targetId](const Node *n) { return n->buildKey() == targetId; }));
|
|
if (!tn) {
|
|
auto newNode = std::make_unique<CMakeTargetNode>(dir, displayName);
|
|
tn = newNode.get();
|
|
cmln->addNode(std::move(newNode));
|
|
}
|
|
tn->setDisplayName(displayName);
|
|
return tn;
|
|
}
|
|
|
|
template<typename Result>
|
|
static std::unique_ptr<Result> cloneFolderNode(FolderNode *node)
|
|
{
|
|
auto folderNode = std::make_unique<Result>(node->filePath());
|
|
folderNode->setDisplayName(node->displayName());
|
|
for (Node *node : node->nodes()) {
|
|
if (FileNode *fn = node->asFileNode()) {
|
|
folderNode->addNode(std::unique_ptr<FileNode>(fn->clone()));
|
|
} else if (FolderNode *fn = node->asFolderNode()) {
|
|
folderNode->addNode(cloneFolderNode<FolderNode>(fn));
|
|
} else {
|
|
QTC_CHECK(false);
|
|
}
|
|
}
|
|
return folderNode;
|
|
}
|
|
|
|
void addFileSystemNodes(ProjectNode *root, const std::shared_ptr<FolderNode> &folderNode)
|
|
{
|
|
QTC_ASSERT(root, return );
|
|
|
|
auto fileSystemNode = cloneFolderNode<VirtualFolderNode>(folderNode.get());
|
|
// just before special nodes like "CMake Modules"
|
|
fileSystemNode->setPriority(Node::DefaultPriority - 6);
|
|
fileSystemNode->setDisplayName(Tr::tr("<File System>"));
|
|
fileSystemNode->setIcon(DirectoryIcon(ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN));
|
|
|
|
if (!fileSystemNode->isEmpty()) {
|
|
// make file system nodes less probable to be selected when syncing with the current document
|
|
fileSystemNode->forEachGenericNode([](Node *n) {
|
|
n->setPriority(n->priority() + Node::DefaultProjectFilePriority + 1);
|
|
n->setEnabled(false);
|
|
});
|
|
root->addNode(std::move(fileSystemNode));
|
|
}
|
|
}
|
|
|
|
} // CMakeProjectManager::Internal
|