ProjectExplorer: Move BuildSystem owership to BuildConfiguration

... or Target.

This patch moves build system from conceptually "one per project"
to "one per target (i.e. per project-and-kit)" or "per
BuildConfigurations" for targets where the builds differ
significantly.

Building requires usually items from the kit (Qt version, compiler,
...) so a target-agnostic build is practically almost always wrong.

Moving the build system to the target also has the potential
to solve issues caused by switching targets while parsing, that
used Project::activeTarget() regularly, with potentially different
results before and after the switch.

This patch might create performance/size regressions when several
targets are set up per project as the build system implementation's
internal data are duplicated in this case.

The idea is to fix that by sharing per-project pieces again in
the project implementation once these problems occur.

Change-Id: I87f640ce418b93175b5029124eaa55f3b8721dca
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
hjk
2019-10-25 09:55:32 +02:00
parent 9073c46c9c
commit 2758682723
127 changed files with 2541 additions and 2532 deletions

View File

@@ -24,6 +24,7 @@
****************************************************************************/
#include "qmlproject.h"
#include "fileformat/qmlprojectfileformat.h"
#include "fileformat/qmlprojectitem.h"
#include "qmlprojectrunconfiguration.h"
@@ -31,6 +32,9 @@
#include "qmlprojectmanagerconstants.h"
#include "qmlprojectnodes.h"
#include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
@@ -46,66 +50,84 @@
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <texteditor/textdocument.h>
#include <utils/algorithm.h>
#include <QDebug>
#include <QRegularExpression>
#include <QTextCodec>
using namespace Core;
using namespace ProjectExplorer;
using namespace QmlProjectManager::Internal;
namespace QmlProjectManager {
QmlProject::QmlProject(const Utils::FilePath &fileName)
: Project(QString::fromLatin1(Constants::QMLPROJECT_MIMETYPE), fileName)
{
const QString normalized
= Utils::FileUtils::normalizePathName(fileName.toFileInfo().canonicalFilePath());
m_canonicalProjectDir = Utils::FilePath::fromString(normalized).parentDir();
setId(QmlProjectManager::Constants::QML_PROJECT_ID);
setProjectLanguages(Context(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID));
setDisplayName(fileName.toFileInfo().completeBaseName());
setNeedsBuildConfigurations(false);
setBuildSystemCreator([](Project *p) { return new Internal::QmlBuildSystem(p); });
connect(this, &QmlProject::projectFileIsDirty, this, &QmlProject::refreshProjectFile);
setBuildSystemCreator([](Target *t) { return new QmlBuildSystem(t); });
}
QmlProject::~QmlProject()
QmlBuildSystem::QmlBuildSystem(Target *target)
: BuildSystem(target)
{
const QString normalized
= Utils::FileUtils::normalizePathName(target->project()
->projectFilePath().toFileInfo().canonicalFilePath());
m_canonicalProjectDir = Utils::FilePath::fromString(normalized).parentDir();
connect(target->project(), &Project::projectFileIsDirty,
this, &QmlBuildSystem::refreshProjectFile);
// refresh first - project information is used e.g. to decide the default RC's
refresh(Everything);
// FIXME: Check. Probably bogus after the BuildSystem move.
// // addedTarget calls updateEnabled on the runconfigurations
// // which needs to happen after refresh
// foreach (Target *t, targets())
// addedTarget(t);
connect(target->project(), &Project::activeTargetChanged,
this, &QmlBuildSystem::onActiveTargetChanged);
updateDeploymentData();
}
QmlBuildSystem::~QmlBuildSystem()
{
delete m_projectItem.data();
}
void QmlProject::addedTarget(Target *target)
void QmlBuildSystem::triggerParsing()
{
updateDeploymentData(target);
refresh(Everything);
}
void QmlProject::onActiveTargetChanged(Target *target)
{
if (m_activeTarget)
disconnect(m_activeTarget, &Target::kitChanged, this, &QmlProject::onKitChanged);
m_activeTarget = target;
if (m_activeTarget)
connect(target, &Target::kitChanged, this, &QmlProject::onKitChanged);
// make sure e.g. the default qml imports are adapted
refresh(Configuration);
}
void QmlProject::onKitChanged()
void QmlBuildSystem::onActiveTargetChanged(Target *)
{
// make sure e.g. the default qml imports are adapted
refresh(Configuration);
}
Utils::FilePath QmlProject::canonicalProjectDir() const
void QmlBuildSystem::onKitChanged()
{
// make sure e.g. the default qml imports are adapted
refresh(Configuration);
}
Utils::FilePath QmlBuildSystem::canonicalProjectDir() const
{
return m_canonicalProjectDir;
}
void QmlProject::parseProject(RefreshOptions options)
void QmlBuildSystem::parseProject(RefreshOptions options)
{
if (options & Files) {
if (options & ProjectFile)
@@ -115,7 +137,7 @@ void QmlProject::parseProject(RefreshOptions options)
m_projectItem = QmlProjectFileFormat::parseProjectFile(projectFilePath(), &errorMessage);
if (m_projectItem) {
connect(m_projectItem.data(), &QmlProjectItem::qmlFilesChanged,
this, &QmlProject::refreshFiles);
this, &QmlBuildSystem::refreshFiles);
} else {
MessageManager::write(tr("Error while loading project file %1.")
@@ -153,7 +175,7 @@ void QmlProject::parseProject(RefreshOptions options)
}
}
void QmlProject::refresh(RefreshOptions options)
void QmlBuildSystem::refresh(RefreshOptions options)
{
ParseGuard guard = guardParsingRun();
parseProject(options);
@@ -166,32 +188,32 @@ void QmlProject::refresh(RefreshOptions options)
return;
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
modelManager->defaultProjectInfoForProject(this);
modelManager->defaultProjectInfoForProject(project());
foreach (const QString &searchPath, makeAbsolute(canonicalProjectDir(), customImportPaths()))
projectInfo.importPaths.maybeInsert(Utils::FilePath::fromString(searchPath),
QmlJS::Dialect::Qml);
modelManager->updateProjectInfo(projectInfo, this);
modelManager->updateProjectInfo(projectInfo, project());
guard.markAsSuccess();
}
QString QmlProject::mainFile() const
QString QmlBuildSystem::mainFile() const
{
if (m_projectItem)
return m_projectItem.data()->mainFile();
return QString();
}
void QmlProject::setMainFile(const QString &mainFilePath)
void QmlBuildSystem::setMainFile(const QString &mainFilePath)
{
if (m_projectItem)
m_projectItem.data()->setMainFile(mainFilePath);
}
Utils::FilePath QmlProject::targetDirectory(const Target *target) const
Utils::FilePath QmlBuildSystem::targetDirectory() const
{
if (DeviceTypeKitAspect::deviceTypeId(target->kit())
if (DeviceTypeKitAspect::deviceTypeId(target()->kit())
== ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
return canonicalProjectDir();
@@ -199,53 +221,42 @@ Utils::FilePath QmlProject::targetDirectory(const Target *target) const
: Utils::FilePath();
}
Utils::FilePath QmlProject::targetFile(const Utils::FilePath &sourceFile,
const Target *target) const
Utils::FilePath QmlBuildSystem::targetFile(const Utils::FilePath &sourceFile) const
{
const QDir sourceDir(m_projectItem ? m_projectItem->sourceDirectory()
: canonicalProjectDir().toString());
const QDir targetDir(targetDirectory(target).toString());
const QDir targetDir(targetDirectory().toString());
const QString relative = sourceDir.relativeFilePath(sourceFile.toString());
return Utils::FilePath::fromString(QDir::cleanPath(targetDir.absoluteFilePath(relative)));
}
Utils::EnvironmentItems QmlProject::environment() const
Utils::EnvironmentItems QmlBuildSystem::environment() const
{
if (m_projectItem)
return m_projectItem.data()->environment();
return {};
}
QStringList QmlProject::customImportPaths() const
QStringList QmlBuildSystem::customImportPaths() const
{
if (m_projectItem)
return m_projectItem.data()->importPaths();
return {};
}
QStringList QmlProject::customFileSelectors() const
QStringList QmlBuildSystem::customFileSelectors() const
{
if (m_projectItem)
return m_projectItem.data()->fileSelectors();
return {};
}
bool QmlProject::addFiles(const QStringList &filePaths)
void QmlBuildSystem::refreshProjectFile()
{
QStringList toAdd;
foreach (const QString &filePath, filePaths) {
if (!m_projectItem.data()->matchesFile(filePath))
toAdd << filePaths;
}
return toAdd.isEmpty();
refresh(QmlBuildSystem::ProjectFile | Files);
}
void QmlProject::refreshProjectFile()
{
refresh(QmlProject::ProjectFile | Files);
}
QStringList QmlProject::makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths)
QStringList QmlBuildSystem::makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths)
{
if (path.isEmpty())
return relativePaths;
@@ -256,14 +267,7 @@ QStringList QmlProject::makeAbsolute(const Utils::FilePath &path, const QStringL
});
}
QVariant QmlProject::additionalData(Id id, const Target *) const
{
if (id == Constants::customFileSelectorsData)
return customFileSelectors();
return {};
}
void QmlProject::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString> &removed)
void QmlBuildSystem::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString> &removed)
{
refresh(Files);
if (!removed.isEmpty()) {
@@ -273,11 +277,9 @@ void QmlProject::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString
refreshTargetDirectory();
}
void QmlProject::refreshTargetDirectory()
void QmlBuildSystem::refreshTargetDirectory()
{
const QList<Target *> targetList = targets();
for (Target *target : targetList)
updateDeploymentData(target);
updateDeploymentData();
}
Tasks QmlProject::projectIssues(const Kit *k) const
@@ -324,9 +326,6 @@ Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *erro
if (result != RestoreResult::Ok)
return result;
// refresh first - project information is used e.g. to decide the default RC's
refresh(Everything);
if (!activeTarget()) {
// find a kit that matches prerequisites (prefer default one)
const QList<Kit*> kits = Utils::filtered(KitManager::kits(), [this](const Kit *k) {
@@ -341,18 +340,6 @@ Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *erro
}
}
// addedTarget calls updateEnabled on the runconfigurations
// which needs to happen after refresh
foreach (Target *t, targets())
addedTarget(t);
connect(this, &ProjectExplorer::Project::addedTarget, this, &QmlProject::addedTarget);
connect(this, &ProjectExplorer::Project::activeTargetChanged,
this, &QmlProject::onActiveTargetChanged);
onActiveTargetChanged(activeTarget());
return RestoreResult::Ok;
}
@@ -361,12 +348,12 @@ ProjectExplorer::DeploymentKnowledge QmlProject::deploymentKnowledge() const
return DeploymentKnowledge::Perfect;
}
void QmlProject::generateProjectTree()
void QmlBuildSystem::generateProjectTree()
{
if (!m_projectItem)
return;
auto newRoot = std::make_unique<Internal::QmlProjectNode>(this);
auto newRoot = std::make_unique<QmlProjectNode>(project());
for (const QString &f : m_projectItem.data()->files()) {
const Utils::FilePath fileName = Utils::FilePath::fromString(f);
@@ -376,16 +363,16 @@ void QmlProject::generateProjectTree()
}
newRoot->addNestedNode(std::make_unique<FileNode>(projectFilePath(), FileType::Project));
setRootProjectNode(std::move(newRoot));
project()->setRootProjectNode(std::move(newRoot));
refreshTargetDirectory();
}
void QmlProject::updateDeploymentData(ProjectExplorer::Target *target)
void QmlBuildSystem::updateDeploymentData()
{
if (!m_projectItem)
return;
if (DeviceTypeKitAspect::deviceTypeId(target->kit())
if (DeviceTypeKitAspect::deviceTypeId(target()->kit())
== ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
return;
}
@@ -394,10 +381,109 @@ void QmlProject::updateDeploymentData(ProjectExplorer::Target *target)
for (const QString &file : m_projectItem->files()) {
deploymentData.addFile(
file,
targetFile(Utils::FilePath::fromString(file), target).parentDir().toString());
targetFile(Utils::FilePath::fromString(file)).parentDir().toString());
}
target->setDeploymentData(deploymentData);
setDeploymentData(deploymentData);
}
QVariant QmlBuildSystem::additionalData(Id id) const
{
if (id == Constants::customFileSelectorsData)
return customFileSelectors();
return {};
}
bool QmlBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
{
if (dynamic_cast<QmlProjectNode *>(context)) {
if (action == AddNewFile || action == EraseFile)
return true;
QTC_ASSERT(node, return false);
if (action == Rename && node->asFileNode()) {
const FileNode *fileNode = node->asFileNode();
QTC_ASSERT(fileNode, return false);
return fileNode->fileType() != FileType::Project;
}
return false;
}
return BuildSystem::supportsAction(context, action, node);
}
QmlProject *QmlBuildSystem::qmlProject() const
{
return static_cast<QmlProject *>(BuildSystem::project());
}
bool QmlBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *)
{
if (!dynamic_cast<QmlProjectNode *>(context))
return false;
QStringList toAdd;
foreach (const QString &filePath, filePaths) {
if (!m_projectItem.data()->matchesFile(filePath))
toAdd << filePaths;
}
return toAdd.isEmpty();
}
bool QmlBuildSystem::deleteFiles(Node *context, const QStringList &filePaths)
{
if (dynamic_cast<QmlProjectNode *>(context))
return true;
return BuildSystem::deleteFiles(context, filePaths);
}
bool QmlBuildSystem::renameFile(Node * context, const QString &filePath, const QString &newFilePath)
{
if (dynamic_cast<QmlProjectNode *>(context)) {
if (filePath.endsWith(mainFile())) {
setMainFile(newFilePath);
// make sure to change it also in the qmlproject file
const QString qmlProjectFilePath = project()->projectFilePath().toString();
Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath);
const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath);
TextEditor::TextDocument *document = nullptr;
if (!editors.isEmpty()) {
document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document());
if (document && document->isModified())
if (!Core::DocumentManager::saveDocument(document))
return false;
}
QString fileContent;
QString error;
Utils::TextFileFormat textFileFormat;
const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error)
!= Utils::TextFileFormat::ReadSuccess) {
qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error;
}
// find the mainFile and do the file name with brackets in a capture group and mask the . with \.
QString originalFileName = QFileInfo(filePath).fileName();
originalFileName.replace(".", "\\.");
const QRegularExpression expression(QString("mainFile:\\s*\"(%1)\"").arg(originalFileName));
const QRegularExpressionMatch match = expression.match(fileContent);
fileContent.replace(match.capturedStart(1), match.capturedLength(1), QFileInfo(newFilePath).fileName());
if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error))
qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error;
refresh(Everything);
}
return true;
}
return BuildSystem::renameFile(context, filePath, newFilePath);
}
} // namespace QmlProjectManager

View File

@@ -35,19 +35,18 @@
#include <QPointer>
namespace ProjectExplorer { class RunConfiguration; }
namespace QmlProjectManager {
class QmlProject;
class QmlProjectItem;
namespace Internal {
class QmlBuildSystem : public ProjectExplorer::BuildSystem
{
public:
explicit QmlBuildSystem(ProjectExplorer::Project *project) : BuildSystem(project) {}
explicit QmlBuildSystem(ProjectExplorer::Target *target);
~QmlBuildSystem();
void triggerParsing() final;
bool supportsAction(ProjectExplorer::Node *context,
ProjectExplorer::ProjectAction action,
@@ -59,20 +58,9 @@ public:
bool renameFile(ProjectExplorer::Node *context,
const QString &filePath, const QString &newFilePath) override;
QmlProject *project() const;
};
QmlProject *qmlProject() const;
} // Internal
class QMLPROJECTMANAGER_EXPORT QmlProject : public ProjectExplorer::Project
{
Q_OBJECT
public:
explicit QmlProject(const Utils::FilePath &filename);
~QmlProject() override;
ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final;
QVariant additionalData(Core::Id id) const override;
enum RefreshOption {
ProjectFile = 0x01,
@@ -87,9 +75,8 @@ public:
Utils::FilePath canonicalProjectDir() const;
QString mainFile() const;
void setMainFile(const QString &mainFilePath);
Utils::FilePath targetDirectory(const ProjectExplorer::Target *target) const;
Utils::FilePath targetFile(const Utils::FilePath &sourceFile,
const ProjectExplorer::Target *target) const;
Utils::FilePath targetDirectory() const;
Utils::FilePath targetFile(const Utils::FilePath &sourceFile) const;
Utils::EnvironmentItems environment() const;
QStringList customImportPaths() const;
@@ -101,7 +88,28 @@ public:
static QStringList makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths);
QVariant additionalData(Core::Id id, const ProjectExplorer::Target *target) const override;
void generateProjectTree();
void updateDeploymentData();
void refreshFiles(const QSet<QString> &added, const QSet<QString> &removed);
void refreshTargetDirectory();
void onActiveTargetChanged(ProjectExplorer::Target *target);
void onKitChanged();
// plain format
void parseProject(RefreshOptions options);
QPointer<QmlProjectItem> m_projectItem;
Utils::FilePath m_canonicalProjectDir;
};
class QMLPROJECTMANAGER_EXPORT QmlProject : public ProjectExplorer::Project
{
Q_OBJECT
public:
explicit QmlProject(const Utils::FilePath &filename);
ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final;
protected:
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override;
@@ -109,23 +117,8 @@ protected:
private:
ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override;
void generateProjectTree();
void updateDeploymentData(ProjectExplorer::Target *target);
void refreshFiles(const QSet<QString> &added, const QSet<QString> &removed);
void refreshTargetDirectory();
void addedTarget(ProjectExplorer::Target *target);
void onActiveTargetChanged(ProjectExplorer::Target *target);
void onKitChanged();
// plain format
void parseProject(RefreshOptions options);
ProjectExplorer::Target *m_activeTarget = nullptr;
QPointer<QmlProjectItem> m_projectItem;
Utils::FilePath m_canonicalProjectDir;
};
} // namespace QmlProjectManager
Q_DECLARE_OPERATORS_FOR_FLAGS(QmlProjectManager::QmlProject::RefreshOptions)
Q_DECLARE_OPERATORS_FOR_FLAGS(QmlProjectManager::QmlBuildSystem::RefreshOptions)

View File

@@ -24,28 +24,19 @@
****************************************************************************/
#include "qmlprojectnodes.h"
#include "qmlproject.h"
#include <coreplugin/idocument.h>
#include <coreplugin/fileiconprovider.h>
#include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/editormanager/ieditor.h>
#include <projectexplorer/projectexplorer.h>
#include <texteditor/textdocument.h>
#include <utils/algorithm.h>
#include <utils/textfileformat.h>
#include <QRegularExpression>
#include <QTextCodec>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
using namespace ProjectExplorer;
namespace QmlProjectManager {
namespace Internal {
QmlProjectNode::QmlProjectNode(QmlProject *project) : ProjectNode(project->projectDirectory()),
m_project(project)
QmlProjectNode::QmlProjectNode(Project *project)
: ProjectNode(project->projectDirectory())
{
setDisplayName(project->projectFilePath().toFileInfo().completeBaseName());
@@ -53,91 +44,5 @@ QmlProjectNode::QmlProjectNode(QmlProject *project) : ProjectNode(project->proje
setIcon(qmlProjectIcon);
}
bool QmlBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
{
if (dynamic_cast<QmlProjectNode *>(context)) {
if (action == AddNewFile || action == EraseFile)
return true;
QTC_ASSERT(node, return false);
if (action == Rename && node->asFileNode()) {
const FileNode *fileNode = node->asFileNode();
QTC_ASSERT(fileNode, return false);
return fileNode->fileType() != FileType::Project;
}
return false;
}
return BuildSystem::supportsAction(context, action, node);
}
QmlProject *QmlBuildSystem::project() const
{
return static_cast<QmlProject *>(BuildSystem::project());
}
bool QmlBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded)
{
if (dynamic_cast<QmlProjectNode *>(context))
return project()->addFiles(filePaths);
return BuildSystem::addFiles(context, filePaths, notAdded);
}
bool QmlBuildSystem::deleteFiles(Node *context, const QStringList &filePaths)
{
if (dynamic_cast<QmlProjectNode *>(context))
return true;
return BuildSystem::deleteFiles(context, filePaths);
}
bool QmlBuildSystem::renameFile(Node * context, const QString &filePath, const QString &newFilePath)
{
if (dynamic_cast<QmlProjectNode *>(context)) {
if (filePath.endsWith(project()->mainFile())) {
project()->setMainFile(newFilePath);
// make sure to change it also in the qmlproject file
const QString qmlProjectFilePath = project()->projectFilePath().toString();
Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath);
const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath);
TextEditor::TextDocument *document = nullptr;
if (!editors.isEmpty()) {
document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document());
if (document && document->isModified())
if (!Core::DocumentManager::saveDocument(document))
return false;
}
QString fileContent;
QString error;
Utils::TextFileFormat textFileFormat;
const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error)
!= Utils::TextFileFormat::ReadSuccess) {
qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error;
}
// find the mainFile and do the file name with brackets in a capture group and mask the . with \.
QString originalFileName = QFileInfo(filePath).fileName();
originalFileName.replace(".", "\\.");
const QRegularExpression expression(QString("mainFile:\\s*\"(%1)\"").arg(originalFileName));
const QRegularExpressionMatch match = expression.match(fileContent);
fileContent.replace(match.capturedStart(1), match.capturedLength(1), QFileInfo(newFilePath).fileName());
if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error))
qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error;
project()->refresh(QmlProject::Everything);
}
return true;
}
return BuildSystem::renameFile(context, filePath, newFilePath);
}
} // namespace Internal
} // namespace QmlProjectManager

View File

@@ -28,18 +28,12 @@
#include <projectexplorer/projectnodes.h>
namespace QmlProjectManager {
class QmlProject;
namespace Internal {
class QmlProjectNode : public ProjectExplorer::ProjectNode
{
public:
QmlProjectNode(QmlProject *project);
private:
QmlProject *m_project;
explicit QmlProjectNode(ProjectExplorer::Project *project);
};
} // namespace Internal

View File

@@ -73,7 +73,7 @@ static bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
class MainQmlFileAspect : public ProjectConfigurationAspect
{
public:
explicit MainQmlFileAspect(QmlProject *project);
explicit MainQmlFileAspect(Target *target);
~MainQmlFileAspect() override { delete m_fileListCombo; }
enum MainScriptSource {
@@ -97,7 +97,12 @@ public:
bool isQmlFilePresent();
public:
QmlProject *m_project;
QmlBuildSystem *qmlBuildSystem() const
{
return static_cast<QmlBuildSystem *>(m_target->buildSystem());
}
Target *m_target = nullptr;
QPointer<QComboBox> m_fileListCombo;
QStandardItemModel m_fileListModel;
QString m_scriptFile;
@@ -107,8 +112,8 @@ public:
QString m_mainScriptFilename;
};
MainQmlFileAspect::MainQmlFileAspect(QmlProject *project)
: m_project(project)
MainQmlFileAspect::MainQmlFileAspect(Target *target)
: m_target(target)
, m_scriptFile(M_CURRENT_FILE)
{
connect(EditorManager::instance(), &EditorManager::currentEditorChanged,
@@ -153,7 +158,7 @@ void MainQmlFileAspect::fromMap(const QVariantMap &map)
void MainQmlFileAspect::updateFileComboBox()
{
QDir projectDir(m_project->projectDirectory().toString());
QDir projectDir(m_target->project()->projectDirectory().toString());
if (mainScriptSource() == FileInProjectFile) {
const QString mainScriptInFilePath = projectDir.relativeFilePath(mainScript());
@@ -170,7 +175,7 @@ void MainQmlFileAspect::updateFileComboBox()
m_fileListModel.appendRow(new QStandardItem(QLatin1String(CURRENT_FILE)));
QModelIndex currentIndex;
QStringList sortedFiles = Utils::transform(m_project->files(Project::SourceFiles),
QStringList sortedFiles = Utils::transform(m_target->project()->files(Project::SourceFiles),
&Utils::FilePath::toString);
// make paths relative to project directory
@@ -207,7 +212,7 @@ void MainQmlFileAspect::updateFileComboBox()
MainQmlFileAspect::MainScriptSource MainQmlFileAspect::mainScriptSource() const
{
if (!m_project->mainFile().isEmpty())
if (!qmlBuildSystem()->mainFile().isEmpty())
return FileInProjectFile;
if (!m_mainScriptFilename.isEmpty())
return FileInSettings;
@@ -234,7 +239,7 @@ void MainQmlFileAspect::setScriptSource(MainScriptSource source, const QString &
m_mainScriptFilename.clear();
} else { // FileInSettings
m_scriptFile = settingsPath;
m_mainScriptFilename = m_project->projectDirectory().toString() + '/' + m_scriptFile;
m_mainScriptFilename = m_target->project()->projectDirectory().toString() + '/' + m_scriptFile;
}
emit changed();
@@ -246,12 +251,12 @@ void MainQmlFileAspect::setScriptSource(MainScriptSource source, const QString &
*/
QString MainQmlFileAspect::mainScript() const
{
if (!m_project->mainFile().isEmpty()) {
const QString pathInProject = m_project->mainFile();
if (!qmlBuildSystem()->mainFile().isEmpty()) {
const QString pathInProject = qmlBuildSystem()->mainFile();
if (QFileInfo(pathInProject).isAbsolute())
return pathInProject;
else
return QDir(m_project->canonicalProjectDir().toString()).absoluteFilePath(pathInProject);
return QDir(qmlBuildSystem()->canonicalProjectDir().toString()).absoluteFilePath(pathInProject);
}
if (!m_mainScriptFilename.isEmpty())
@@ -279,9 +284,9 @@ QmlProjectRunConfiguration::QmlProjectRunConfiguration(Target *target, Id id)
{
auto envAspect = addAspect<EnvironmentAspect>();
auto envModifier = [target](Environment env) {
if (auto project = qobject_cast<const QmlProject *>(target->project()))
env.modify(project->environment());
auto envModifier = [this](Environment env) {
if (auto bs = dynamic_cast<const QmlBuildSystem *>(activeBuildSystem()))
env.modify(bs->environment());
return env;
};
@@ -311,9 +316,7 @@ QmlProjectRunConfiguration::QmlProjectRunConfiguration(Target *target, Id id)
CommandLine::Raw);
});
auto qmlProject = qobject_cast<QmlProject *>(target->project());
QTC_ASSERT(qmlProject, return);
m_mainQmlFileAspect = addAspect<MainQmlFileAspect>(qmlProject);
m_mainQmlFileAspect = addAspect<MainQmlFileAspect>(target);
connect(m_mainQmlFileAspect, &MainQmlFileAspect::changed,
this, &QmlProjectRunConfiguration::updateEnabledState);
@@ -329,7 +332,8 @@ Runnable QmlProjectRunConfiguration::runnable() const
Runnable r;
r.setCommandLine(commandLine());
r.environment = aspect<EnvironmentAspect>()->environment();
r.workingDirectory = static_cast<QmlProject *>(project())->targetDirectory(target()).toString();
const QmlBuildSystem *bs = static_cast<QmlBuildSystem *>(activeBuildSystem());
r.workingDirectory = bs->targetDirectory().toString();
return r;
}
@@ -377,38 +381,35 @@ QString QmlProjectRunConfiguration::commandLineArguments() const
{
// arguments in .user file
QString args = aspect<ArgumentsAspect>()->arguments(macroExpander());
const Target *currentTarget = target();
const IDevice::ConstPtr device = DeviceKitAspect::device(currentTarget->kit());
const IDevice::ConstPtr device = DeviceKitAspect::device(target()->kit());
const Utils::OsType osType = device ? device->osType() : Utils::HostOsInfo::hostOs();
// arguments from .qmlproject file
const QmlProject *project = static_cast<QmlProject *>(currentTarget->project());
const QmlBuildSystem *bs = static_cast<QmlBuildSystem *>(target()->buildSystem());
foreach (const QString &importPath,
QmlProject::makeAbsolute(project->targetDirectory(currentTarget), project->customImportPaths())) {
QmlBuildSystem::makeAbsolute(bs->targetDirectory(), bs->customImportPaths())) {
Utils::QtcProcess::addArg(&args, QLatin1String("-I"), osType);
Utils::QtcProcess::addArg(&args, importPath, osType);
}
for (const QString &fileSelector : project->customFileSelectors()) {
for (const QString &fileSelector : bs->customFileSelectors()) {
Utils::QtcProcess::addArg(&args, QLatin1String("-S"), osType);
Utils::QtcProcess::addArg(&args, fileSelector, osType);
}
const QString main = project->targetFile(Utils::FilePath::fromString(mainScript()),
currentTarget).toString();
const QString main = bs->targetFile(FilePath::fromString(mainScript())).toString();
if (!main.isEmpty())
Utils::QtcProcess::addArg(&args, main, osType);
return args;
}
void QmlProjectRunConfiguration::updateEnabledState()
bool QmlProjectRunConfiguration::isEnabled() const
{
bool enabled = false;
if (m_mainQmlFileAspect->isQmlFilePresent() && !commandLine().executable().isEmpty()) {
Project *p = target()->project();
enabled = !p->isParsing() && p->hasParsingData();
BuildSystem *bs = activeBuildSystem();
return !bs->isParsing() && bs->hasParsingData();
}
setEnabled(enabled);
return false;
}
bool MainQmlFileAspect::isQmlFilePresent()
@@ -430,7 +431,7 @@ bool MainQmlFileAspect::isQmlFilePresent()
|| mainScriptMimeType.matchesName(QLatin1String(QmlJSTools::Constants::QMLPROJECT_MIMETYPE))) {
// find a qml file with lowercase filename. This is slow, but only done
// in initialization/other border cases.
const auto files = m_project->files(Project::SourceFiles);
const auto files = m_target->project()->files(Project::SourceFiles);
for (const Utils::FilePath &filename : files) {
const QFileInfo fi = filename.toFileInfo();

View File

@@ -44,7 +44,7 @@ public:
private:
ProjectExplorer::Runnable runnable() const final;
QString disabledReason() const final;
void updateEnabledState() final;
bool isEnabled() const final;
QString mainScript() const;
QString theExecutable() const;