QmlProjectManager: Prepare for running on remote devices

We add a "targetDirectory" property to the file format and fill in the
deployment data.

Change-Id: I372f2c9f5f3c4252431963eeab7b8b420f8bccd5
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Ulf Hermann
2017-11-28 15:57:15 +01:00
parent f1138920b9
commit fba61c5b55
9 changed files with 143 additions and 55 deletions

View File

@@ -11,6 +11,7 @@ Module {
"QmlProject/Project 1.1" "QmlProject/Project 1.1"
] ]
Property { name: "sourceDirectory"; type: "string" } Property { name: "sourceDirectory"; type: "string" }
Property { name: "targetDirectory": type: "string" }
Property { name: "mainFile"; type: "string" } Property { name: "mainFile"; type: "string" }
Property { name: "importPaths"; type: "string"; isList: true } Property { name: "importPaths"; type: "string"; isList: true }
Property { name: "content"; type: "QmlProjectItem"; isList: true } Property { name: "content"; type: "QmlProjectItem"; isList: true }

View File

@@ -88,6 +88,10 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FileName &fi
if (importPathsProperty.isValid()) if (importPathsProperty.isValid())
projectItem->setImportPaths(importPathsProperty.toStringList()); projectItem->setImportPaths(importPathsProperty.toStringList());
const QVariant targetDirectoryPropery = rootNode->property("targetDirectory");
if (targetDirectoryPropery.isValid())
projectItem->setTargetDirectory(targetDirectoryPropery.toString());
if (debug) if (debug)
qDebug() << "importPath:" << importPathsProperty << "mainFile:" << mainFileProperty; qDebug() << "importPath:" << importPathsProperty << "mainFile:" << mainFileProperty;

View File

@@ -51,6 +51,11 @@ void QmlProjectItem::setSourceDirectory(const QString &directoryPath)
setImportPaths(m_importPaths); setImportPaths(m_importPaths);
} }
void QmlProjectItem::setTargetDirectory(const QString &directoryPath)
{
m_targetDirectory = directoryPath;
}
void QmlProjectItem::setImportPaths(const QStringList &importPaths) void QmlProjectItem::setImportPaths(const QStringList &importPaths)
{ {
if (m_importPaths != importPaths) if (m_importPaths != importPaths)

View File

@@ -46,6 +46,8 @@ class QmlProjectItem : public QObject
public: public:
QString sourceDirectory() const { return m_sourceDirectory; } QString sourceDirectory() const { return m_sourceDirectory; }
void setSourceDirectory(const QString &directoryPath); void setSourceDirectory(const QString &directoryPath);
QString targetDirectory() const { return m_targetDirectory; }
void setTargetDirectory(const QString &directoryPath);
QStringList importPaths() const { return m_absoluteImportPaths; } QStringList importPaths() const { return m_absoluteImportPaths; }
void setImportPaths(const QStringList &paths); void setImportPaths(const QStringList &paths);
@@ -63,6 +65,7 @@ signals:
protected: protected:
QString m_sourceDirectory; QString m_sourceDirectory;
QString m_targetDirectory;
QStringList m_importPaths; QStringList m_importPaths;
QStringList m_absoluteImportPaths; QStringList m_absoluteImportPaths;
QString m_mainFile; QString m_mainFile;

View File

@@ -36,6 +36,7 @@
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h> #include <projectexplorer/kitmanager.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
@@ -59,6 +60,10 @@ QmlProject::QmlProject(const Utils::FileName &fileName) :
Project(QString::fromLatin1(Constants::QMLPROJECT_MIMETYPE), fileName, Project(QString::fromLatin1(Constants::QMLPROJECT_MIMETYPE), fileName,
[this]() { refreshProjectFile(); }) [this]() { refreshProjectFile(); })
{ {
const QString normalized
= Utils::FileUtils::normalizePathName(fileName.toFileInfo().canonicalFilePath());
m_canonicalProjectDir = Utils::FileName::fromString(normalized).parentDir();
setId(QmlProjectManager::Constants::QML_PROJECT_ID); setId(QmlProjectManager::Constants::QML_PROJECT_ID);
setProjectLanguages(Context(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID)); setProjectLanguages(Context(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID));
setDisplayName(fileName.toFileInfo().completeBaseName()); setDisplayName(fileName.toFileInfo().completeBaseName());
@@ -75,6 +80,7 @@ void QmlProject::addedTarget(Target *target)
this, &QmlProject::addedRunConfiguration); this, &QmlProject::addedRunConfiguration);
foreach (RunConfiguration *rc, target->runConfigurations()) foreach (RunConfiguration *rc, target->runConfigurations())
addedRunConfiguration(rc); addedRunConfiguration(rc);
updateDeploymentData(target);
} }
void QmlProject::onActiveTargetChanged(Target *target) void QmlProject::onActiveTargetChanged(Target *target)
@@ -104,9 +110,9 @@ void QmlProject::addedRunConfiguration(RunConfiguration *rc)
qmlrc->updateEnabledState(); qmlrc->updateEnabledState();
} }
QDir QmlProject::projectDir() const Utils::FileName QmlProject::canonicalProjectDir() const
{ {
return projectFilePath().toFileInfo().dir(); return m_canonicalProjectDir;
} }
void QmlProject::parseProject(RefreshOptions options) void QmlProject::parseProject(RefreshOptions options)
@@ -129,13 +135,17 @@ void QmlProject::parseProject(RefreshOptions options)
} }
} }
if (m_projectItem) { if (m_projectItem) {
m_projectItem.data()->setSourceDirectory(projectDir().path()); m_projectItem.data()->setSourceDirectory(canonicalProjectDir().toString());
if (m_projectItem->targetDirectory().isEmpty())
m_projectItem->setTargetDirectory(canonicalProjectDir().toString());
if (auto modelManager = QmlJS::ModelManagerInterface::instance()) if (auto modelManager = QmlJS::ModelManagerInterface::instance())
modelManager->updateSourceFiles(m_projectItem.data()->files(), true); modelManager->updateSourceFiles(m_projectItem.data()->files(), true);
QString mainFilePath = m_projectItem.data()->mainFile(); QString mainFilePath = m_projectItem.data()->mainFile();
if (!mainFilePath.isEmpty()) { if (!mainFilePath.isEmpty()) {
mainFilePath = projectDir().absoluteFilePath(mainFilePath); mainFilePath
= QDir(canonicalProjectDir().toString()).absoluteFilePath(mainFilePath);
Utils::FileReader reader; Utils::FileReader reader;
QString errorMessage; QString errorMessage;
if (!reader.fetch(mainFilePath, &errorMessage)) { if (!reader.fetch(mainFilePath, &errorMessage)) {
@@ -183,6 +193,26 @@ QString QmlProject::mainFile() const
return QString(); return QString();
} }
Utils::FileName QmlProject::targetDirectory(const Target *target) const
{
if (DeviceTypeKitInformation::deviceTypeId(target->kit())
== ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
return canonicalProjectDir();
return m_projectItem ? Utils::FileName::fromString(m_projectItem->targetDirectory())
: Utils::FileName();
}
Utils::FileName QmlProject::targetFile(const Utils::FileName &sourceFile,
const Target *target) const
{
const QDir sourceDir(m_projectItem ? m_projectItem->sourceDirectory()
: canonicalProjectDir().toString());
const QDir targetDir(targetDirectory(target).toString());
const QString relative = sourceDir.relativeFilePath(sourceFile.toString());
return Utils::FileName::fromString(QDir::cleanPath(targetDir.absoluteFilePath(relative)));
}
bool QmlProject::validProjectFile() const bool QmlProject::validProjectFile() const
{ {
return !m_projectItem.isNull(); return !m_projectItem.isNull();
@@ -219,17 +249,18 @@ void QmlProject::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString
if (auto modelManager = QmlJS::ModelManagerInterface::instance()) if (auto modelManager = QmlJS::ModelManagerInterface::instance())
modelManager->removeFiles(removed.toList()); modelManager->removeFiles(removed.toList());
} }
refreshTargetDirectory();
}
void QmlProject::refreshTargetDirectory()
{
const QList<Target *> targetList = targets();
for (Target *target : targetList)
updateDeploymentData(target);
} }
bool QmlProject::supportsKit(Kit *k, QString *errorMessage) const bool QmlProject::supportsKit(Kit *k, QString *errorMessage) const
{ {
Id deviceType = DeviceTypeKitInformation::deviceTypeId(k);
if (deviceType != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
if (errorMessage)
*errorMessage = tr("Device type is not desktop.");
return false;
}
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k); QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
if (!version) { if (!version) {
if (errorMessage) if (errorMessage)
@@ -262,15 +293,28 @@ Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *erro
return false; return false;
IDevice::ConstPtr dev = DeviceKitInformation::device(k); IDevice::ConstPtr dev = DeviceKitInformation::device(k);
if (dev.isNull() || dev->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) if (dev.isNull())
return false;
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
if (!version || version->type() != QLatin1String(QtSupport::Constants::DESKTOPQT))
return false; return false;
return version->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0) QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
&& !static_cast<QtSupport::DesktopQtVersion *>(version) if (!version || version->qtVersion() < QtSupport::QtVersionNumber(5, 0, 0))
->qmlsceneCommand().isEmpty(); return false;
if (dev->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
if (version->type() != QLatin1String(QtSupport::Constants::DESKTOPQT)) {
return !static_cast<QtSupport::DesktopQtVersion *>(version)
->qmlsceneCommand().isEmpty();
} else {
// Non-desktop Qt on a desktop device? We don't support that.
return false;
}
}
// If not a desktop device, don't check the Qt version for qmlscene.
// The device is responsible for providing it and we assume qmlscene can be found
// in $PATH if it's not explicitly given.
return true;
}) })
); );
@@ -322,7 +366,27 @@ void QmlProject::generateProjectTree()
newRoot->addNestedNode(new FileNode(projectFilePath(), FileType::Project, false)); newRoot->addNestedNode(new FileNode(projectFilePath(), FileType::Project, false));
setRootProjectNode(newRoot); setRootProjectNode(newRoot);
refreshTargetDirectory();
} }
void QmlProject::updateDeploymentData(ProjectExplorer::Target *target)
{
if (!m_projectItem)
return;
if (DeviceTypeKitInformation::deviceTypeId(target->kit())
== ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
return;
}
ProjectExplorer::DeploymentData deploymentData;
for (const QString &file : m_projectItem->files()) {
deploymentData.addFile(
file,
targetFile(Utils::FileName::fromString(file), target).parentDir().toString());
}
target->setDeploymentData(deploymentData);
}
} // namespace QmlProjectManager } // namespace QmlProjectManager

View File

@@ -60,8 +60,11 @@ public:
void refresh(RefreshOptions options); void refresh(RefreshOptions options);
QDir projectDir() const; Utils::FileName canonicalProjectDir() const;
QString mainFile() const; QString mainFile() const;
Utils::FileName targetDirectory(const ProjectExplorer::Target *target) const;
Utils::FileName targetFile(const Utils::FileName &sourceFile,
const ProjectExplorer::Target *target) const;
QStringList customImportPaths() const; QStringList customImportPaths() const;
bool addFiles(const QStringList &filePaths); bool addFiles(const QStringList &filePaths);
@@ -74,7 +77,9 @@ protected:
private: private:
void generateProjectTree(); void generateProjectTree();
void updateDeploymentData(ProjectExplorer::Target *target);
void refreshFiles(const QSet<QString> &added, const QSet<QString> &removed); void refreshFiles(const QSet<QString> &added, const QSet<QString> &removed);
void refreshTargetDirectory();
void addedTarget(ProjectExplorer::Target *target); void addedTarget(ProjectExplorer::Target *target);
void onActiveTargetChanged(ProjectExplorer::Target *target); void onActiveTargetChanged(ProjectExplorer::Target *target);
void onKitChanged(); void onKitChanged();
@@ -86,6 +91,7 @@ private:
ProjectExplorer::Target *m_activeTarget = nullptr; ProjectExplorer::Target *m_activeTarget = nullptr;
QPointer<QmlProjectItem> m_projectItem; QPointer<QmlProjectItem> m_projectItem;
Utils::FileName m_canonicalProjectDir;
}; };
} // namespace QmlProjectManager } // namespace QmlProjectManager

View File

@@ -80,8 +80,7 @@ Runnable QmlProjectRunConfiguration::runnable() const
r.commandLineArguments = commandLineArguments(); r.commandLineArguments = commandLineArguments();
r.runMode = ApplicationLauncher::Gui; r.runMode = ApplicationLauncher::Gui;
r.environment = extraAspect<QmlProjectEnvironmentAspect>()->environment(); r.environment = extraAspect<QmlProjectEnvironmentAspect>()->environment();
r.workingDirectory = canonicalCapsPath(target()->project()->projectFilePath() r.workingDirectory = static_cast<QmlProject *>(project())->targetDirectory(target()).toString();
.toFileInfo().absolutePath());
return r; return r;
} }
@@ -89,48 +88,60 @@ QString QmlProjectRunConfiguration::disabledReason() const
{ {
if (mainScript().isEmpty()) if (mainScript().isEmpty())
return tr("No script file to execute."); return tr("No script file to execute.");
if (!QFileInfo::exists(executable())) if (DeviceTypeKitInformation::deviceTypeId(target()->kit())
== ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE
&& !QFileInfo::exists(executable())) {
return tr("No qmlscene found."); return tr("No qmlscene found.");
}
if (executable().isEmpty())
return tr("No qmlscene binary specified for target device.");
return RunConfiguration::disabledReason(); return RunConfiguration::disabledReason();
} }
QString QmlProjectRunConfiguration::executable() const QString QmlProjectRunConfiguration::executable() const
{ {
BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit()); BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit());
if (!version) if (!version) // No Qt version in Kit. Don't try to run qmlscene.
return QString(); return QString();
QTC_ASSERT(version->type() == QLatin1String(QtSupport::Constants::DESKTOPQT), return QString()); const Id deviceType = DeviceTypeKitInformation::deviceTypeId(target()->kit());
return static_cast<QtSupport::DesktopQtVersion *>(version)->qmlsceneCommand(); if (deviceType == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
// If not given explicitly by Qt Version, try to pick it from $PATH.
return version->type() == QtSupport::Constants::DESKTOPQT
? static_cast<QtSupport::DesktopQtVersion *>(version)->qmlsceneCommand()
: QString("qmlscene");
}
IDevice::ConstPtr dev = DeviceKitInformation::device(target()->kit());
if (dev.isNull()) // No device set. We don't know where to run qmlscene.
return QString();
const QString qmlscene = dev->qmlsceneCommand();
// If not given explicitly by device, try to pick it from $PATH.
return qmlscene.isEmpty() ? QString("qmlscene") : qmlscene;
} }
QString QmlProjectRunConfiguration::commandLineArguments() const QString QmlProjectRunConfiguration::commandLineArguments() const
{ {
// arguments in .user file // arguments in .user file
QString args = m_qmlViewerArgs; QString args = m_qmlViewerArgs;
const IDevice::ConstPtr device = DeviceKitInformation::device(target()->kit());
const Utils::OsType osType = device ? device->osType() : Utils::HostOsInfo::hostOs();
// arguments from .qmlproject file // arguments from .qmlproject file
QmlProject *project = static_cast<QmlProject *>(target()->project()); QmlProject *project = static_cast<QmlProject *>(target()->project());
foreach (const QString &importPath, project->customImportPaths()) { foreach (const QString &importPath, project->customImportPaths()) {
Utils::QtcProcess::addArg(&args, QLatin1String("-I")); Utils::QtcProcess::addArg(&args, QLatin1String("-I"), osType);
Utils::QtcProcess::addArg(&args, importPath); Utils::QtcProcess::addArg(&args, importPath, osType);
} }
QString s = mainScript(); const QString main
if (!s.isEmpty()) { = project->targetFile(Utils::FileName::fromString(mainScript()), target()).toString(); ;
s = canonicalCapsPath(s); if (!main.isEmpty())
Utils::QtcProcess::addArg(&args, s); Utils::QtcProcess::addArg(&args, main, osType);
}
return args; return args;
} }
/* QtDeclarative checks explicitly that the capitalization for any URL / path
is exactly like the capitalization on disk.*/
QString QmlProjectRunConfiguration::canonicalCapsPath(const QString &fileName)
{
return Utils::FileUtils::normalizePathName(QFileInfo(fileName).canonicalFilePath());
}
QWidget *QmlProjectRunConfiguration::createConfigurationWidget() QWidget *QmlProjectRunConfiguration::createConfigurationWidget()
{ {
return new QmlProjectRunConfigurationWidget(this); return new QmlProjectRunConfigurationWidget(this);
@@ -164,7 +175,7 @@ QString QmlProjectRunConfiguration::mainScript() const
if (QFileInfo(pathInProject).isAbsolute()) if (QFileInfo(pathInProject).isAbsolute())
return pathInProject; return pathInProject;
else else
return project->projectDir().absoluteFilePath(pathInProject); return QDir(project->canonicalProjectDir().toString()).absoluteFilePath(pathInProject);
} }
if (!m_mainScriptFilename.isEmpty()) if (!m_mainScriptFilename.isEmpty())
@@ -272,17 +283,16 @@ void QmlProjectRunConfiguration::updateEnabledState()
qmlFileFound = !mainScript().isEmpty(); qmlFileFound = !mainScript().isEmpty();
} }
if (QFileInfo::exists(executable()) && qmlFileFound) if (!qmlFileFound) {
RunConfiguration::updateEnabledState();
else
setEnabled(false); setEnabled(false);
} } else {
const QString exe = executable();
bool QmlProjectRunConfiguration::isValidVersion(QtSupport::BaseQtVersion *version) if (exe.isEmpty()) {
{ setEnabled(false);
return version } else {
&& version->type() == QLatin1String(QtSupport::Constants::DESKTOPQT) RunConfiguration::updateEnabledState();
&& !static_cast<QtSupport::DesktopQtVersion *>(version)->qmlsceneCommand().isEmpty(); }
}
} }
} // namespace QmlProjectManager } // namespace QmlProjectManager

View File

@@ -80,10 +80,6 @@ private:
QString executable() const; QString executable() const;
QString commandLineArguments() const; QString commandLineArguments() const;
static bool isValidVersion(QtSupport::BaseQtVersion *version);
static QString canonicalCapsPath(const QString &filePath);
// absolute path to current file (if being used) // absolute path to current file (if being used)
QString m_currentFileFilename; QString m_currentFileFilename;
// absolute path to selected main script (if being used) // absolute path to selected main script (if being used)

View File

@@ -37,7 +37,6 @@ QmlProjectRunConfigurationFactory::QmlProjectRunConfigurationFactory(QObject *pa
setObjectName("QmlProjectRunConfigurationFactory"); setObjectName("QmlProjectRunConfigurationFactory");
registerRunConfiguration<QmlProjectRunConfiguration>(Constants::QML_SCENE_RC_ID); registerRunConfiguration<QmlProjectRunConfiguration>(Constants::QML_SCENE_RC_ID);
addSupportedProjectType(QmlProjectManager::Constants::QML_PROJECT_ID); addSupportedProjectType(QmlProjectManager::Constants::QML_PROJECT_ID);
setSupportedTargetDeviceTypes({ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE});
addFixedBuildTarget(tr("QML Scene")); addFixedBuildTarget(tr("QML Scene"));
} }