forked from qt-creator/qt-creator
The "qmlscene" is called "qml" nowadays. Also give device settings more priority to cover cases where there is no Qt build setup at all. For this case, also demote the missing Qt build version from "Error" to "Warning". Task-number: QTCREATORBUG-28074 Change-Id: Ic44d2bee1965493925d21317d12d5c1f66ace88b Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
807 lines
26 KiB
C++
807 lines
26 KiB
C++
// Copyright (C) 2016 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
|
|
|
#include "qmlproject.h"
|
|
|
|
#include "fileformat/qmlprojectfileformat.h"
|
|
#include "fileformat/qmlprojectitem.h"
|
|
#include "qmlprojectconstants.h"
|
|
#include "qmlprojectmanagerconstants.h"
|
|
#include "qmlprojectnodes.h"
|
|
|
|
#include <coreplugin/documentmanager.h>
|
|
#include <coreplugin/editormanager/documentmodel.h>
|
|
#include <coreplugin/editormanager/editormanager.h>
|
|
#include <coreplugin/editormanager/ieditor.h>
|
|
#include <coreplugin/icontext.h>
|
|
#include <coreplugin/icore.h>
|
|
#include <coreplugin/messagemanager.h>
|
|
|
|
#include <projectexplorer/deploymentdata.h>
|
|
#include <projectexplorer/devicesupport/idevice.h>
|
|
#include <projectexplorer/kitinformation.h>
|
|
#include <projectexplorer/kitmanager.h>
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
#include <projectexplorer/session.h>
|
|
#include <projectexplorer/target.h>
|
|
|
|
#include <qtsupport/baseqtversion.h>
|
|
#include <qtsupport/qtkitinformation.h>
|
|
#include <qtsupport/qtsupportconstants.h>
|
|
|
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
|
|
|
#include <texteditor/textdocument.h>
|
|
|
|
#include <utils/algorithm.h>
|
|
#include <utils/infobar.h>
|
|
#include <utils/qtcassert.h>
|
|
#include <utils/qtcprocess.h>
|
|
|
|
#include <QDebug>
|
|
#include <QLoggingCategory>
|
|
#include <QMessageBox>
|
|
#include <QRegularExpression>
|
|
#include <QTextCodec>
|
|
#include <QTimer>
|
|
|
|
using namespace Core;
|
|
using namespace ProjectExplorer;
|
|
using namespace QmlProjectManager::Internal;
|
|
using namespace Utils;
|
|
|
|
namespace {
|
|
Q_LOGGING_CATEGORY(infoLogger, "QmlProjectManager.QmlBuildSystem", QtInfoMsg)
|
|
}
|
|
|
|
namespace QmlProjectManager {
|
|
|
|
static int preferedQtTarget(Target *target)
|
|
{
|
|
if (target) {
|
|
const QmlBuildSystem *buildSystem = qobject_cast<QmlBuildSystem *>(target->buildSystem());
|
|
if (buildSystem && buildSystem->qt6Project())
|
|
return 6;
|
|
}
|
|
return 5;
|
|
}
|
|
|
|
static bool allowOnlySingleProject()
|
|
{
|
|
QSettings *settings = Core::ICore::settings();
|
|
const QString qdsAllowMultipleProjects = "QML/Designer/AllowMultipleProjects";
|
|
|
|
return !settings->value(qdsAllowMultipleProjects, false).toBool();
|
|
}
|
|
|
|
Utils::FilePaths QmlProject::getUiQmlFilesForFolder(const Utils::FilePath &folder)
|
|
{
|
|
const Utils::FilePaths uiFiles = files([&](const ProjectExplorer::Node *node) {
|
|
return node->filePath().completeSuffix() == "ui.qml"
|
|
&& node->filePath().parentDir() == folder;
|
|
});
|
|
return uiFiles;
|
|
}
|
|
|
|
QmlProject::QmlProject(const Utils::FilePath &fileName)
|
|
: Project(QString::fromLatin1(Constants::QMLPROJECT_MIMETYPE), fileName)
|
|
{
|
|
setId(QmlProjectManager::Constants::QML_PROJECT_ID);
|
|
setProjectLanguages(Context(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID));
|
|
setDisplayName(fileName.completeBaseName());
|
|
|
|
setNeedsBuildConfigurations(false);
|
|
setBuildSystemCreator([](Target *t) { return new QmlBuildSystem(t); });
|
|
|
|
if (QmlProject::isQtDesignStudio()) {
|
|
if (allowOnlySingleProject()) {
|
|
EditorManager::closeAllDocuments();
|
|
SessionManager::closeAllProjects();
|
|
}
|
|
|
|
m_openFileConnection
|
|
= connect(this,
|
|
&QmlProject::anyParsingFinished,
|
|
this,
|
|
[this](Target *target, bool success) {
|
|
if (m_openFileConnection)
|
|
disconnect(m_openFileConnection);
|
|
|
|
if (target && success) {
|
|
|
|
auto target = activeTarget();
|
|
if (!target)
|
|
return;
|
|
|
|
auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
|
|
target->buildSystem());
|
|
|
|
const Utils::FilePath mainUiFile = qmlBuildSystem->mainUiFilePath();
|
|
|
|
if (mainUiFile.completeSuffix() == "ui.qml" && mainUiFile.exists()) {
|
|
QTimer::singleShot(1000, [mainUiFile]() {
|
|
Core::EditorManager::openEditor(mainUiFile,
|
|
Utils::Id());
|
|
});
|
|
} else {
|
|
Utils::FilePaths uiFiles = getUiQmlFilesForFolder(projectDirectory()
|
|
+ "/content");
|
|
if (uiFiles.isEmpty())
|
|
uiFiles = getUiQmlFilesForFolder(projectDirectory());
|
|
|
|
if (!uiFiles.isEmpty()) {
|
|
Utils::FilePath currentFile;
|
|
if (auto cd = Core::EditorManager::currentDocument())
|
|
currentFile = cd->filePath();
|
|
|
|
if (currentFile.isEmpty() || !isKnownFile(currentFile))
|
|
QTimer::singleShot(1000, [uiFiles]() {
|
|
Core::EditorManager::openEditor(uiFiles.first(),
|
|
Utils::Id());
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
QmlBuildSystem::QmlBuildSystem(Target *target)
|
|
: BuildSystem(target)
|
|
{
|
|
m_canonicalProjectDir =
|
|
target->project()->projectFilePath().canonicalPath().normalizedPathName().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() = default;
|
|
|
|
void QmlBuildSystem::triggerParsing()
|
|
{
|
|
refresh(Everything);
|
|
}
|
|
|
|
void QmlBuildSystem::onActiveTargetChanged(Target *)
|
|
{
|
|
// make sure e.g. the default qml imports are adapted
|
|
refresh(Configuration);
|
|
}
|
|
|
|
void QmlBuildSystem::onKitChanged()
|
|
{
|
|
// make sure e.g. the default qml imports are adapted
|
|
refresh(Configuration);
|
|
}
|
|
|
|
Utils::FilePath QmlBuildSystem::canonicalProjectDir() const
|
|
{
|
|
return m_canonicalProjectDir;
|
|
}
|
|
|
|
void QmlBuildSystem::parseProject(RefreshOptions options)
|
|
{
|
|
if (options & Files) {
|
|
if (options & ProjectFile)
|
|
m_projectItem.reset();
|
|
if (!m_projectItem) {
|
|
QString errorMessage;
|
|
m_projectItem = QmlProjectFileFormat::parseProjectFile(projectFilePath(), &errorMessage);
|
|
if (m_projectItem) {
|
|
connect(m_projectItem.get(),
|
|
&QmlProjectItem::qmlFilesChanged,
|
|
this,
|
|
&QmlBuildSystem::refreshFiles);
|
|
|
|
} else {
|
|
MessageManager::writeFlashing(
|
|
tr("Error while loading project file %1.").arg(projectFilePath().toUserOutput()));
|
|
MessageManager::writeSilently(errorMessage);
|
|
}
|
|
}
|
|
if (m_projectItem) {
|
|
m_projectItem->setSourceDirectory(canonicalProjectDir().toString());
|
|
if (m_projectItem->targetDirectory().isEmpty())
|
|
m_projectItem->setTargetDirectory(canonicalProjectDir().toString());
|
|
|
|
if (auto modelManager = QmlJS::ModelManagerInterface::instance()) {
|
|
QStringList files = m_projectItem->files();
|
|
modelManager
|
|
->updateSourceFiles(Utils::transform(files,
|
|
[](const QString &p) {
|
|
return Utils::FilePath::fromString(p);
|
|
}),
|
|
true);
|
|
}
|
|
QString mainFilePath = m_projectItem->mainFile();
|
|
if (!mainFilePath.isEmpty()) {
|
|
mainFilePath
|
|
= QDir(canonicalProjectDir().toString()).absoluteFilePath(mainFilePath);
|
|
Utils::FileReader reader;
|
|
QString errorMessage;
|
|
if (!reader.fetch(Utils::FilePath::fromString(mainFilePath), &errorMessage)) {
|
|
MessageManager::writeFlashing(tr("Warning while loading project file %1.")
|
|
.arg(projectFilePath().toUserOutput()));
|
|
MessageManager::writeSilently(errorMessage);
|
|
}
|
|
}
|
|
}
|
|
generateProjectTree();
|
|
}
|
|
|
|
if (options & Configuration) {
|
|
// update configuration
|
|
}
|
|
}
|
|
|
|
bool QmlBuildSystem::setFileSettingInProjectFile(const QString &setting, const Utils::FilePath &mainFilePath, const QString &oldFile)
|
|
{
|
|
// make sure to change it also in the qmlproject file
|
|
const Utils::FilePath qmlProjectFilePath = project()->projectFilePath();
|
|
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;
|
|
}
|
|
|
|
const QString settingQmlCode = setting + ":";
|
|
|
|
const Utils::FilePath projectDir = project()->projectFilePath().parentDir();
|
|
const QString relativePath = mainFilePath.relativeChildPath(projectDir).path();
|
|
|
|
if (fileContent.indexOf(settingQmlCode) < 0) {
|
|
QString addedText = QString("\n %1 \"%2\"\n").arg(settingQmlCode).arg(relativePath);
|
|
auto index = fileContent.lastIndexOf("}");
|
|
fileContent.insert(index, addedText);
|
|
} else {
|
|
QString originalFileName = oldFile;
|
|
originalFileName.replace(".", "\\.");
|
|
const QRegularExpression expression(QString("%1\\s*\"(%2)\"").arg(settingQmlCode).arg(originalFileName));
|
|
|
|
const QRegularExpressionMatch match = expression.match(fileContent);
|
|
|
|
fileContent.replace(match.capturedStart(1),
|
|
match.capturedLength(1),
|
|
relativePath);
|
|
}
|
|
|
|
if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error))
|
|
qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error;
|
|
|
|
refresh(Everything);
|
|
return true;
|
|
}
|
|
|
|
void QmlBuildSystem::refresh(RefreshOptions options)
|
|
{
|
|
ParseGuard guard = guardParsingRun();
|
|
parseProject(options);
|
|
|
|
if (options & Files)
|
|
generateProjectTree();
|
|
|
|
auto modelManager = QmlJS::ModelManagerInterface::instance();
|
|
if (!modelManager)
|
|
return;
|
|
|
|
QmlJS::ModelManagerInterface::ProjectInfo projectInfo
|
|
= modelManager->defaultProjectInfoForProject(project(),
|
|
project()->files(Project::HiddenRccFolders));
|
|
const QStringList searchPaths = makeAbsolute(canonicalProjectDir(), customImportPaths());
|
|
for (const QString &searchPath : searchPaths)
|
|
projectInfo.importPaths.maybeInsert(Utils::FilePath::fromString(searchPath),
|
|
QmlJS::Dialect::Qml);
|
|
|
|
modelManager->updateProjectInfo(projectInfo, project());
|
|
|
|
guard.markAsSuccess();
|
|
|
|
emit projectChanged();
|
|
}
|
|
|
|
QString QmlBuildSystem::mainFile() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->mainFile();
|
|
return QString();
|
|
}
|
|
|
|
QString QmlBuildSystem::mainUiFile() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->mainUiFile();
|
|
return QString();
|
|
}
|
|
|
|
Utils::FilePath QmlBuildSystem::mainFilePath() const
|
|
{
|
|
return projectDirectory().pathAppended(mainFile());
|
|
}
|
|
|
|
Utils::FilePath QmlBuildSystem::mainUiFilePath() const
|
|
{
|
|
return projectDirectory().pathAppended(mainUiFile());
|
|
}
|
|
|
|
bool QmlBuildSystem::setMainFileInProjectFile(const Utils::FilePath &newMainFilePath)
|
|
{
|
|
|
|
return setFileSettingInProjectFile("mainFile", newMainFilePath, mainFile());
|
|
}
|
|
|
|
bool QmlBuildSystem::setMainUiFileInProjectFile(const Utils::FilePath &newMainUiFilePath)
|
|
{
|
|
return setMainUiFileInMainFile(newMainUiFilePath)
|
|
&& setFileSettingInProjectFile("mainUiFile", newMainUiFilePath, mainUiFile());
|
|
}
|
|
|
|
bool QmlBuildSystem::setMainUiFileInMainFile(const Utils::FilePath &newMainUiFilePath)
|
|
{
|
|
Core::FileChangeBlocker fileChangeBlocker(mainFilePath());
|
|
const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(mainFilePath());
|
|
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(mainFilePath(), codec, &fileContent, &textFileFormat, &error)
|
|
!= Utils::TextFileFormat::ReadSuccess) {
|
|
qWarning() << "Failed to read file" << mainFilePath() << ":" << error;
|
|
}
|
|
|
|
const QString currentMain = QString("%1 {").arg(mainUiFilePath().baseName());
|
|
const QString newMain = QString("%1 {").arg(newMainUiFilePath.baseName());
|
|
|
|
if (fileContent.contains(currentMain))
|
|
fileContent.replace(currentMain, newMain);
|
|
|
|
if (!textFileFormat.writeFile(mainFilePath(), fileContent, &error))
|
|
qWarning() << "Failed to write file" << mainFilePath() << ":" << error;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool QmlBuildSystem::qtForMCUs() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->qtForMCUs();
|
|
return false;
|
|
}
|
|
|
|
bool QmlBuildSystem::qt6Project() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->qt6Project();
|
|
return false;
|
|
}
|
|
|
|
void QmlBuildSystem::setMainFile(const QString &mainFilePath)
|
|
{
|
|
if (m_projectItem)
|
|
m_projectItem->setMainFile(mainFilePath);
|
|
}
|
|
|
|
Utils::FilePath QmlBuildSystem::targetDirectory() const
|
|
{
|
|
if (DeviceTypeKitAspect::deviceTypeId(kit())
|
|
== ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
|
|
return canonicalProjectDir();
|
|
|
|
return m_projectItem ? Utils::FilePath::fromString(m_projectItem->targetDirectory())
|
|
: Utils::FilePath();
|
|
}
|
|
|
|
Utils::FilePath QmlBuildSystem::targetFile(const Utils::FilePath &sourceFile) const
|
|
{
|
|
const QDir sourceDir(m_projectItem ? m_projectItem->sourceDirectory()
|
|
: canonicalProjectDir().toString());
|
|
const QDir targetDir(targetDirectory().toString());
|
|
const QString relative = sourceDir.relativeFilePath(sourceFile.toString());
|
|
return Utils::FilePath::fromString(QDir::cleanPath(targetDir.absoluteFilePath(relative)));
|
|
}
|
|
|
|
Utils::EnvironmentItems QmlBuildSystem::environment() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->environment();
|
|
return {};
|
|
}
|
|
|
|
QStringList QmlBuildSystem::customImportPaths() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->importPaths();
|
|
return {};
|
|
}
|
|
|
|
QStringList QmlBuildSystem::customFileSelectors() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->fileSelectors();
|
|
return {};
|
|
}
|
|
|
|
bool QmlBuildSystem::multilanguageSupport() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->multilanguageSupport();
|
|
return false;
|
|
}
|
|
|
|
QStringList QmlBuildSystem::supportedLanguages() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->supportedLanguages();
|
|
return {};
|
|
}
|
|
|
|
void QmlBuildSystem::setSupportedLanguages(QStringList languages)
|
|
{
|
|
if (m_projectItem)
|
|
m_projectItem->setSupportedLanguages(languages);
|
|
}
|
|
|
|
QString QmlBuildSystem::primaryLanguage() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->primaryLanguage();
|
|
return {};
|
|
}
|
|
|
|
void QmlBuildSystem::setPrimaryLanguage(QString language)
|
|
{
|
|
if (m_projectItem)
|
|
m_projectItem->setPrimaryLanguage(language);
|
|
}
|
|
|
|
void QmlBuildSystem::refreshProjectFile()
|
|
{
|
|
refresh(QmlBuildSystem::ProjectFile | Files);
|
|
}
|
|
|
|
QStringList QmlBuildSystem::makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths)
|
|
{
|
|
if (path.isEmpty())
|
|
return relativePaths;
|
|
|
|
const QDir baseDir(path.toString());
|
|
return Utils::transform(relativePaths, [&baseDir](const QString &path) {
|
|
return QDir::cleanPath(baseDir.absoluteFilePath(path));
|
|
});
|
|
}
|
|
|
|
void QmlBuildSystem::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString> &removed)
|
|
{
|
|
if (m_blockFilesUpdate) {
|
|
qCDebug(infoLogger) << "Auto files refresh blocked.";
|
|
return;
|
|
}
|
|
refresh(Files);
|
|
if (!removed.isEmpty()) {
|
|
if (auto modelManager = QmlJS::ModelManagerInterface::instance()) {
|
|
modelManager->removeFiles(
|
|
Utils::transform<QList<Utils::FilePath>>(removed, [](const QString &s) {
|
|
return Utils::FilePath::fromString(s);
|
|
}));
|
|
}
|
|
}
|
|
refreshTargetDirectory();
|
|
}
|
|
|
|
void QmlBuildSystem::refreshTargetDirectory()
|
|
{
|
|
updateDeploymentData();
|
|
}
|
|
|
|
Tasks QmlProject::projectIssues(const Kit *k) const
|
|
{
|
|
Tasks result = Project::projectIssues(k);
|
|
|
|
const QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(k);
|
|
if (!version)
|
|
result.append(createProjectTask(Task::TaskType::Warning, tr("No Qt version set in kit.")));
|
|
|
|
IDevice::ConstPtr dev = DeviceKitAspect::device(k);
|
|
if (dev.isNull())
|
|
result.append(createProjectTask(Task::TaskType::Error, tr("Kit has no device.")));
|
|
|
|
if (version && version->qtVersion() < QVersionNumber(5, 0, 0))
|
|
result.append(createProjectTask(Task::TaskType::Error, tr("Qt version is too old.")));
|
|
|
|
if (dev.isNull() || !version)
|
|
return result; // No need to check deeper than this
|
|
|
|
if (dev->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
|
|
if (version->type() == QtSupport::Constants::DESKTOPQT) {
|
|
if (version->qmlRuntimeFilePath().isEmpty()) {
|
|
result.append(createProjectTask(Task::TaskType::Error,
|
|
tr("Qt version has no QML utility.")));
|
|
}
|
|
} else {
|
|
// Non-desktop Qt on a desktop device? We don't support that.
|
|
result.append(createProjectTask(Task::TaskType::Error,
|
|
tr("Non-desktop Qt is used with a desktop device.")));
|
|
}
|
|
} else {
|
|
// If not a desktop device, don't check the Qt version for qml runtime binary.
|
|
// The device is responsible for providing it and we assume qml runtime can be found
|
|
// in $PATH if it's not explicitly given.
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool QmlProject::isEditModePreferred() const
|
|
{
|
|
return !isQtDesignStudio();
|
|
}
|
|
|
|
Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *errorMessage)
|
|
{
|
|
RestoreResult result = Project::fromMap(map, errorMessage);
|
|
if (result != RestoreResult::Ok)
|
|
return result;
|
|
|
|
if (!activeTarget()) {
|
|
// find a kit that matches prerequisites (prefer default one)
|
|
const QList<Kit *> kits = Utils::filtered(KitManager::kits(), [this](const Kit *k) {
|
|
return !containsType(projectIssues(k), Task::TaskType::Error)
|
|
&& DeviceTypeKitAspect::deviceTypeId(k)
|
|
== ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
|
|
});
|
|
|
|
if (!kits.isEmpty()) {
|
|
if (kits.contains(KitManager::defaultKit()))
|
|
addTargetForDefaultKit();
|
|
else
|
|
addTargetForKit(kits.first());
|
|
}
|
|
|
|
if (QmlProject::isQtDesignStudio()) {
|
|
auto setKitWithVersion = [&](int qtMajorVersion) {
|
|
const QList<Kit *> qtVersionkits
|
|
= Utils::filtered(kits, [qtMajorVersion](const Kit *k) {
|
|
if (!k->isAutoDetected())
|
|
return false;
|
|
if (k->isReplacementKit())
|
|
return false;
|
|
QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(k);
|
|
return (version && version->qtVersion().majorVersion() == qtMajorVersion);
|
|
});
|
|
if (!qtVersionkits.isEmpty()) {
|
|
if (qtVersionkits.contains(KitManager::defaultKit()))
|
|
addTargetForDefaultKit();
|
|
else
|
|
addTargetForKit(qtVersionkits.first());
|
|
}
|
|
};
|
|
|
|
int preferedVersion = preferedQtTarget(activeTarget());
|
|
|
|
if (activeTarget())
|
|
removeTarget(activeTarget());
|
|
|
|
setKitWithVersion(preferedVersion);
|
|
}
|
|
}
|
|
|
|
return RestoreResult::Ok;
|
|
}
|
|
|
|
bool QmlProject::isQtDesignStudio()
|
|
{
|
|
QSettings *settings = Core::ICore::settings();
|
|
const QString qdsStandaloneEntry = "QML/Designer/StandAloneMode";
|
|
|
|
return settings->value(qdsStandaloneEntry, false).toBool();
|
|
}
|
|
|
|
bool QmlProject::isQtDesignStudioStartedFromQtC()
|
|
{
|
|
return qEnvironmentVariableIsSet(Constants::enviromentLaunchedQDS);
|
|
}
|
|
|
|
ProjectExplorer::DeploymentKnowledge QmlProject::deploymentKnowledge() const
|
|
{
|
|
return DeploymentKnowledge::Perfect;
|
|
}
|
|
|
|
void QmlBuildSystem::generateProjectTree()
|
|
{
|
|
if (!m_projectItem)
|
|
return;
|
|
|
|
auto newRoot = std::make_unique<QmlProjectNode>(project());
|
|
|
|
for (const QString &f : m_projectItem->files()) {
|
|
const Utils::FilePath fileName = Utils::FilePath::fromString(f);
|
|
const FileType fileType = (fileName == projectFilePath())
|
|
? FileType::Project : FileNode::fileTypeForFileName(fileName);
|
|
newRoot->addNestedNode(std::make_unique<FileNode>(fileName, fileType));
|
|
}
|
|
newRoot->addNestedNode(std::make_unique<FileNode>(projectFilePath(), FileType::Project));
|
|
|
|
setRootProjectNode(std::move(newRoot));
|
|
refreshTargetDirectory();
|
|
}
|
|
|
|
void QmlBuildSystem::updateDeploymentData()
|
|
{
|
|
if (!m_projectItem)
|
|
return;
|
|
|
|
if (DeviceTypeKitAspect::deviceTypeId(kit())
|
|
== ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
|
|
return;
|
|
}
|
|
|
|
ProjectExplorer::DeploymentData deploymentData;
|
|
for (const QString &file : m_projectItem->files()) {
|
|
deploymentData.addFile(
|
|
FilePath::fromString(file),
|
|
targetFile(Utils::FilePath::fromString(file)).parentDir().toString());
|
|
}
|
|
|
|
setDeploymentData(deploymentData);
|
|
}
|
|
|
|
QVariant QmlBuildSystem::additionalData(Id id) const
|
|
{
|
|
if (id == Constants::customFileSelectorsData)
|
|
return customFileSelectors();
|
|
if (id == Constants::supportedLanguagesData)
|
|
return supportedLanguages();
|
|
if (id == Constants::primaryLanguageData)
|
|
return primaryLanguage();
|
|
if (id == Constants::customForceFreeTypeData)
|
|
return forceFreeType();
|
|
if (id == Constants::customQtForMCUs)
|
|
return qtForMCUs();
|
|
if (id == Constants::customQt6Project)
|
|
return qt6Project();
|
|
if (id == Constants::mainFilePath)
|
|
return mainFilePath().toString();
|
|
if (id == Constants::customImportPaths)
|
|
return customImportPaths();
|
|
if (id == Constants::canonicalProjectDir)
|
|
return canonicalProjectDir().toString();
|
|
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::forceFreeType() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->forceFreeType();
|
|
return false;
|
|
}
|
|
|
|
bool QmlBuildSystem::widgetApp() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->widgetApp();
|
|
return false;
|
|
}
|
|
|
|
QStringList QmlBuildSystem::shaderToolArgs() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->shaderToolArgs();
|
|
return {};
|
|
}
|
|
|
|
QStringList QmlBuildSystem::shaderToolFiles() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->shaderToolFiles();
|
|
return {};
|
|
}
|
|
|
|
QStringList QmlBuildSystem::importPaths() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->importPaths();
|
|
return {};
|
|
}
|
|
|
|
QStringList QmlBuildSystem::files() const
|
|
{
|
|
if (m_projectItem)
|
|
return m_projectItem->files();
|
|
return {};
|
|
}
|
|
|
|
bool QmlBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *)
|
|
{
|
|
if (!dynamic_cast<QmlProjectNode *>(context))
|
|
return false;
|
|
|
|
FilePaths toAdd;
|
|
for (const FilePath &filePath : filePaths) {
|
|
if (!m_projectItem->matchesFile(filePath.toString()))
|
|
toAdd << filePaths;
|
|
}
|
|
return toAdd.isEmpty();
|
|
}
|
|
|
|
bool QmlBuildSystem::deleteFiles(Node *context, const FilePaths &filePaths)
|
|
{
|
|
if (dynamic_cast<QmlProjectNode *>(context))
|
|
return true;
|
|
|
|
return BuildSystem::deleteFiles(context, filePaths);
|
|
}
|
|
|
|
bool QmlBuildSystem::renameFile(Node * context, const FilePath &oldFilePath, const FilePath &newFilePath)
|
|
{
|
|
if (dynamic_cast<QmlProjectNode *>(context)) {
|
|
if (oldFilePath.endsWith(mainFile()))
|
|
return setMainFileInProjectFile(newFilePath);
|
|
if (oldFilePath.endsWith(mainUiFile()))
|
|
return setMainUiFileInProjectFile(newFilePath);
|
|
|
|
return true;
|
|
}
|
|
|
|
return BuildSystem::renameFile(context, oldFilePath, newFilePath);
|
|
}
|
|
|
|
} // namespace QmlProjectManager
|