Files
qt-creator/src/plugins/qmakeprojectmanager/qmakenodes.cpp
hjk 36f4b9a81e Ios: Remove direct compile time dependency of IosRunConfig on qmake
Change-Id: Ieb0cbc71b525972afb66883b010cbf389657c406
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
2019-05-06 08:37:31 +00:00

434 lines
14 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qmakenodes.h"
#include "qmakeproject.h"
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <resourceeditor/resourcenode.h>
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
#include <android/androidconstants.h>
#include <ios/iosconstants.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
using namespace ProjectExplorer;
using namespace Utils;
namespace QmakeProjectManager {
/*!
\class QmakePriFileNode
Implements abstract ProjectNode class
*/
QmakePriFileNode::QmakePriFileNode(QmakeProject *project, QmakeProFileNode *qmakeProFileNode,
const FileName &filePath, QmakePriFile *pf) :
ProjectNode(filePath),
m_project(project),
m_qmakeProFileNode(qmakeProFileNode),
m_qmakePriFile(pf)
{ }
QmakePriFile *QmakePriFileNode::priFile() const
{
if (!m_project->isParsing())
return m_qmakePriFile;
// During a parsing run the qmakePriFile tree will change, so search for the PriFile and
// do not depend on the cached value.
return m_project->rootProFile()->findPriFile(filePath());
}
bool QmakePriFileNode::deploysFolder(const QString &folder) const
{
const QmakePriFile *pri = priFile();
return pri ? pri->deploysFolder(folder) : false;
}
QmakeProFileNode *QmakePriFileNode::proFileNode() const
{
return m_qmakeProFileNode;
}
bool QmakePriFileNode::supportsAction(ProjectAction action, const Node *node) const
{
if (action == Rename || action == DuplicateFile) {
const FileNode *fileNode = node->asFileNode();
return (fileNode && fileNode->fileType() != FileType::Project)
|| dynamic_cast<const ResourceEditor::ResourceTopLevelNode *>(node);
}
const FolderNode *folderNode = this;
const QmakeProFileNode *proFileNode;
while (!(proFileNode = dynamic_cast<const QmakeProFileNode*>(folderNode))) {
folderNode = folderNode->parentFolderNode();
QTC_ASSERT(folderNode, return false);
}
QTC_ASSERT(proFileNode, return false);
const QmakeProFile *pro = proFileNode->proFile();
switch (pro ? pro->projectType() : ProjectType::Invalid) {
case ProjectType::ApplicationTemplate:
case ProjectType::StaticLibraryTemplate:
case ProjectType::SharedLibraryTemplate:
case ProjectType::AuxTemplate: {
// TODO: Some of the file types don't make much sense for aux
// projects (e.g. cpp). It'd be nice if the "add" action could
// work on a subset of the file types according to project type.
if (action == AddNewFile)
return true;
if (action == EraseFile)
return pro && pro->knowsFile(node->filePath());
if (action == RemoveFile)
return !(pro && pro->knowsFile(node->filePath()));
bool addExistingFiles = true;
if (node->isVirtualFolderType()) {
// A virtual folder, we do what the projectexplorer does
const FolderNode *folder = node->asFolderNode();
if (folder) {
QStringList list;
foreach (FolderNode *f, folder->folderNodes())
list << f->filePath().toString() + QLatin1Char('/');
if (deploysFolder(Utils::commonPath(list)))
addExistingFiles = false;
}
}
addExistingFiles = addExistingFiles && !deploysFolder(node->filePath().toString());
if (action == AddExistingFile || action == AddExistingDirectory)
return addExistingFiles;
break;
}
case ProjectType::SubDirsTemplate:
if (action == AddSubProject || action == AddExistingProject)
return true;
break;
default:
break;
}
return false;
}
bool QmakePriFileNode::canAddSubProject(const QString &proFilePath) const
{
const QmakePriFile *pri = priFile();
return pri ? pri->canAddSubProject(proFilePath) : false;
}
bool QmakePriFileNode::addSubProject(const QString &proFilePath)
{
QmakePriFile *pri = priFile();
return pri ? pri->addSubProject(proFilePath) : false;
}
bool QmakePriFileNode::removeSubProject(const QString &proFilePath)
{
QmakePriFile *pri = priFile();
return pri ? pri->removeSubProjects(proFilePath) : false;
}
QStringList QmakePriFileNode::subProjectFileNamePatterns() const
{
return QStringList("*.pro");
}
bool QmakePriFileNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
{
QmakePriFile *pri = priFile();
if (!pri)
return false;
QList<Node *> matchingNodes = findNodes([filePaths](const Node *n) {
return n->asFileNode() && filePaths.contains(n->filePath().toString());
});
matchingNodes = filtered(matchingNodes, [](const Node *n) {
for (const Node *parent = n->parentFolderNode(); parent;
parent = parent->parentFolderNode()) {
if (dynamic_cast<const ResourceEditor::ResourceTopLevelNode *>(parent))
return false;
}
return true;
});
QStringList alreadyPresentFiles = transform<QStringList>(matchingNodes,
[](const Node *n) { return n->filePath().toString(); });
alreadyPresentFiles.removeDuplicates();
QStringList actualFilePaths = filePaths;
for (const QString &e : alreadyPresentFiles)
actualFilePaths.removeOne(e);
if (notAdded)
*notAdded = alreadyPresentFiles;
return pri->addFiles(actualFilePaths, notAdded);
}
bool QmakePriFileNode::removeFiles(const QStringList &filePaths, QStringList *notRemoved)
{
QmakePriFile *pri = priFile();
return pri ? pri->removeFiles(filePaths, notRemoved) : false;
}
bool QmakePriFileNode::deleteFiles(const QStringList &filePaths)
{
QmakePriFile *pri = priFile();
return pri ? pri->deleteFiles(filePaths) : false;
}
bool QmakePriFileNode::canRenameFile(const QString &filePath, const QString &newFilePath)
{
QmakePriFile *pri = priFile();
return pri ? pri->canRenameFile(filePath, newFilePath) : false;
}
bool QmakePriFileNode::renameFile(const QString &filePath, const QString &newFilePath)
{
QmakePriFile *pri = priFile();
return pri ? pri->renameFile(filePath, newFilePath) : false;
}
FolderNode::AddNewInformation QmakePriFileNode::addNewInformation(const QStringList &files, Node *context) const
{
Q_UNUSED(files)
return FolderNode::AddNewInformation(filePath().fileName(), context && context->parentProjectNode() == this ? 120 : 90);
}
/*!
\class QmakeProFileNode
Implements abstract ProjectNode class
*/
QmakeProFileNode::QmakeProFileNode(QmakeProject *project, const FileName &filePath, QmakeProFile *pf) :
QmakePriFileNode(project, this, filePath, pf)
{ }
bool QmakeProFileNode::showInSimpleTree() const
{
return showInSimpleTree(projectType()) || m_project->rootProjectNode() == this;
}
QString QmakeProFileNode::buildKey() const
{
return filePath().toString();
}
bool QmakeProFileNode::parseInProgress() const
{
QmakeProjectManager::QmakeProFile *pro = proFile();
return !pro || pro->parseInProgress();
}
bool QmakeProFileNode::validParse() const
{
QmakeProjectManager::QmakeProFile *pro = proFile();
return pro && pro->validParse();
}
QStringList QmakeProFileNode::targetApplications() const
{
QStringList apps;
if (includedInExactParse() && projectType() == ProjectType::ApplicationTemplate) {
const QString target = targetInformation().target;
if (target.startsWith("lib") && target.endsWith(".so"))
apps << target.mid(3, target.lastIndexOf('.') - 3);
else
apps << target;
}
return apps;
}
QVariant QmakeProFileNode::data(Core::Id role) const
{
if (role == Android::Constants::AndroidPackageSourceDir)
return singleVariableValue(Variable::AndroidPackageSourceDir);
if (role == Android::Constants::AndroidDeploySettingsFile)
return singleVariableValue(Variable::AndroidDeploySettingsFile);
if (role == Android::Constants::AndroidExtraLibs)
return variableValue(Variable::AndroidExtraLibs);
if (role == Android::Constants::AndroidArch)
return singleVariableValue(Variable::AndroidArch);
if (role == Android::Constants::AndroidSoLibPath) {
TargetInformation info = targetInformation();
QStringList res = {info.buildDir.toString()};
Utils::FileName destDir = info.destDir;
if (!destDir.isEmpty()) {
if (destDir.toFileInfo().isRelative())
destDir = Utils::FileName::fromString(QDir::cleanPath(info.buildDir.toString()
+ '/' + destDir.toString()));
res.append(destDir.toString());
}
res.removeDuplicates();
return res;
}
if (role == Android::Constants::AndroidTargets)
return {};
if (role == Ios::Constants::IosTarget) {
const TargetInformation info = targetInformation();
if (info.valid)
return info.target;
}
if (role == Ios::Constants::IosBuildDir) {
const TargetInformation info = targetInformation();
if (info.valid)
return info.buildDir.toString();
}
QTC_CHECK(false);
return {};
}
bool QmakeProFileNode::setData(Core::Id role, const QVariant &value) const
{
QmakeProFile *pro = proFile();
if (!pro)
return false;
const QString arch = pro->singleVariableValue(Variable::AndroidArch);
const QString scope = "contains(ANDROID_TARGET_ARCH," + arch + ')';
auto flags = QmakeProjectManager::Internal::ProWriter::ReplaceValues
| QmakeProjectManager::Internal::ProWriter::MultiLine;
if (role == Android::Constants::AndroidExtraLibs)
return pro->setProVariable("ANDROID_EXTRA_LIBS", value.toStringList(), scope, flags);
if (role == Android::Constants::AndroidPackageSourceDir)
return pro->setProVariable("ANDROID_PACKAGE_SOURCE_DIR", {value.toString()}, scope, flags);
return false;
}
QmakeProFile *QmakeProFileNode::proFile() const
{
return static_cast<QmakeProFile*>(QmakePriFileNode::priFile());
}
QString QmakeProFileNode::makefile() const
{
return singleVariableValue(Variable::Makefile);
}
QString QmakeProFileNode::objectsDirectory() const
{
return singleVariableValue(Variable::ObjectsDir);
}
bool QmakeProFileNode::isDebugAndRelease() const
{
const QStringList configValues = variableValue(Variable::Config);
return configValues.contains(QLatin1String("debug_and_release"));
}
bool QmakeProFileNode::isQtcRunnable() const
{
const QStringList configValues = variableValue(Variable::Config);
return configValues.contains(QLatin1String("qtc_runnable"));
}
bool QmakeProFileNode::includedInExactParse() const
{
const QmakeProFile *pro = proFile();
return pro && pro->includedInExactParse();
}
bool QmakeProFileNode::supportsAction(ProjectAction action, const Node *node) const
{
if (action == RemoveSubProject)
return parentProjectNode() && !parentProjectNode()->asContainerNode();
return QmakePriFileNode::supportsAction(action, node);
}
FolderNode::AddNewInformation QmakeProFileNode::addNewInformation(const QStringList &files, Node *context) const
{
Q_UNUSED(files)
return AddNewInformation(filePath().fileName(), context && context->parentProjectNode() == this ? 120 : 100);
}
bool QmakeProFileNode::showInSimpleTree(ProjectType projectType) const
{
return projectType == ProjectType::ApplicationTemplate
|| projectType == ProjectType::SharedLibraryTemplate
|| projectType == ProjectType::StaticLibraryTemplate;
}
ProjectType QmakeProFileNode::projectType() const
{
const QmakeProFile *pro = proFile();
return pro ? pro->projectType() : ProjectType::Invalid;
}
QStringList QmakeProFileNode::variableValue(const Variable var) const
{
QmakeProFile *pro = proFile();
return pro ? pro->variableValue(var) : QStringList();
}
QString QmakeProFileNode::singleVariableValue(const Variable var) const
{
const QStringList &values = variableValue(var);
return values.isEmpty() ? QString() : values.first();
}
QString QmakeProFileNode::buildDir() const
{
if (Target *target = m_project->activeTarget()) {
if (BuildConfiguration *bc = target->activeBuildConfiguration()) {
const QDir srcDirRoot(m_project->projectDirectory().toString());
const QString relativeDir = srcDirRoot.relativeFilePath(filePath().parentDir().toString());
return QDir::cleanPath(QDir(bc->buildDirectory().toString()).absoluteFilePath(relativeDir));
}
}
return QString();
}
FileName QmakeProFileNode::buildDir(QmakeBuildConfiguration *bc) const
{
const QmakeProFile *pro = proFile();
return pro ? pro->buildDir(bc) : FileName();
}
QString QmakeProFileNode::objectExtension() const
{
QStringList exts = variableValue(Variable::ObjectExt);
if (exts.isEmpty())
return HostOsInfo::isWindowsHost() ? QLatin1String(".obj") : QLatin1String(".o");
return exts.first();
}
TargetInformation QmakeProFileNode::targetInformation() const
{
return proFile() ? proFile()->targetInformation() : TargetInformation();
}
} // namespace QmakeProjectManager