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"
]
Property { name: "sourceDirectory"; type: "string" }
Property { name: "targetDirectory": type: "string" }
Property { name: "mainFile"; type: "string" }
Property { name: "importPaths"; type: "string"; 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())
projectItem->setImportPaths(importPathsProperty.toStringList());
const QVariant targetDirectoryPropery = rootNode->property("targetDirectory");
if (targetDirectoryPropery.isValid())
projectItem->setTargetDirectory(targetDirectoryPropery.toString());
if (debug)
qDebug() << "importPath:" << importPathsProperty << "mainFile:" << mainFileProperty;

View File

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

View File

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

View File

@@ -36,6 +36,7 @@
#include <coreplugin/messagemanager.h>
#include <coreplugin/documentmanager.h>
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/target.h>
@@ -59,6 +60,10 @@ QmlProject::QmlProject(const Utils::FileName &fileName) :
Project(QString::fromLatin1(Constants::QMLPROJECT_MIMETYPE), fileName,
[this]() { refreshProjectFile(); })
{
const QString normalized
= Utils::FileUtils::normalizePathName(fileName.toFileInfo().canonicalFilePath());
m_canonicalProjectDir = Utils::FileName::fromString(normalized).parentDir();
setId(QmlProjectManager::Constants::QML_PROJECT_ID);
setProjectLanguages(Context(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID));
setDisplayName(fileName.toFileInfo().completeBaseName());
@@ -75,6 +80,7 @@ void QmlProject::addedTarget(Target *target)
this, &QmlProject::addedRunConfiguration);
foreach (RunConfiguration *rc, target->runConfigurations())
addedRunConfiguration(rc);
updateDeploymentData(target);
}
void QmlProject::onActiveTargetChanged(Target *target)
@@ -104,9 +110,9 @@ void QmlProject::addedRunConfiguration(RunConfiguration *rc)
qmlrc->updateEnabledState();
}
QDir QmlProject::projectDir() const
Utils::FileName QmlProject::canonicalProjectDir() const
{
return projectFilePath().toFileInfo().dir();
return m_canonicalProjectDir;
}
void QmlProject::parseProject(RefreshOptions options)
@@ -129,13 +135,17 @@ void QmlProject::parseProject(RefreshOptions options)
}
}
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())
modelManager->updateSourceFiles(m_projectItem.data()->files(), true);
QString mainFilePath = m_projectItem.data()->mainFile();
if (!mainFilePath.isEmpty()) {
mainFilePath = projectDir().absoluteFilePath(mainFilePath);
mainFilePath
= QDir(canonicalProjectDir().toString()).absoluteFilePath(mainFilePath);
Utils::FileReader reader;
QString errorMessage;
if (!reader.fetch(mainFilePath, &errorMessage)) {
@@ -183,6 +193,26 @@ QString QmlProject::mainFile() const
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
{
return !m_projectItem.isNull();
@@ -219,17 +249,18 @@ void QmlProject::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString
if (auto modelManager = QmlJS::ModelManagerInterface::instance())
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
{
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);
if (!version) {
if (errorMessage)
@@ -262,15 +293,28 @@ Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *erro
return false;
IDevice::ConstPtr dev = DeviceKitInformation::device(k);
if (dev.isNull() || dev->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
return false;
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
if (!version || version->type() != QLatin1String(QtSupport::Constants::DESKTOPQT))
if (dev.isNull())
return false;
return version->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0)
&& !static_cast<QtSupport::DesktopQtVersion *>(version)
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
if (!version || version->qtVersion() < QtSupport::QtVersionNumber(5, 0, 0))
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));
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

View File

@@ -60,8 +60,11 @@ public:
void refresh(RefreshOptions options);
QDir projectDir() const;
Utils::FileName canonicalProjectDir() 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;
bool addFiles(const QStringList &filePaths);
@@ -74,7 +77,9 @@ protected:
private:
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();
@@ -86,6 +91,7 @@ private:
ProjectExplorer::Target *m_activeTarget = nullptr;
QPointer<QmlProjectItem> m_projectItem;
Utils::FileName m_canonicalProjectDir;
};
} // namespace QmlProjectManager

View File

@@ -80,8 +80,7 @@ Runnable QmlProjectRunConfiguration::runnable() const
r.commandLineArguments = commandLineArguments();
r.runMode = ApplicationLauncher::Gui;
r.environment = extraAspect<QmlProjectEnvironmentAspect>()->environment();
r.workingDirectory = canonicalCapsPath(target()->project()->projectFilePath()
.toFileInfo().absolutePath());
r.workingDirectory = static_cast<QmlProject *>(project())->targetDirectory(target()).toString();
return r;
}
@@ -89,48 +88,60 @@ QString QmlProjectRunConfiguration::disabledReason() const
{
if (mainScript().isEmpty())
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.");
}
if (executable().isEmpty())
return tr("No qmlscene binary specified for target device.");
return RunConfiguration::disabledReason();
}
QString QmlProjectRunConfiguration::executable() const
{
BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit());
if (!version)
if (!version) // No Qt version in Kit. Don't try to run qmlscene.
return QString();
QTC_ASSERT(version->type() == QLatin1String(QtSupport::Constants::DESKTOPQT), return QString());
return static_cast<QtSupport::DesktopQtVersion *>(version)->qmlsceneCommand();
const Id deviceType = DeviceTypeKitInformation::deviceTypeId(target()->kit());
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
{
// arguments in .user file
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
QmlProject *project = static_cast<QmlProject *>(target()->project());
foreach (const QString &importPath, project->customImportPaths()) {
Utils::QtcProcess::addArg(&args, QLatin1String("-I"));
Utils::QtcProcess::addArg(&args, importPath);
Utils::QtcProcess::addArg(&args, QLatin1String("-I"), osType);
Utils::QtcProcess::addArg(&args, importPath, osType);
}
QString s = mainScript();
if (!s.isEmpty()) {
s = canonicalCapsPath(s);
Utils::QtcProcess::addArg(&args, s);
}
const QString main
= project->targetFile(Utils::FileName::fromString(mainScript()), target()).toString(); ;
if (!main.isEmpty())
Utils::QtcProcess::addArg(&args, main, osType);
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()
{
return new QmlProjectRunConfigurationWidget(this);
@@ -164,7 +175,7 @@ QString QmlProjectRunConfiguration::mainScript() const
if (QFileInfo(pathInProject).isAbsolute())
return pathInProject;
else
return project->projectDir().absoluteFilePath(pathInProject);
return QDir(project->canonicalProjectDir().toString()).absoluteFilePath(pathInProject);
}
if (!m_mainScriptFilename.isEmpty())
@@ -272,17 +283,16 @@ void QmlProjectRunConfiguration::updateEnabledState()
qmlFileFound = !mainScript().isEmpty();
}
if (QFileInfo::exists(executable()) && qmlFileFound)
RunConfiguration::updateEnabledState();
else
if (!qmlFileFound) {
setEnabled(false);
} else {
const QString exe = executable();
if (exe.isEmpty()) {
setEnabled(false);
} else {
RunConfiguration::updateEnabledState();
}
}
bool QmlProjectRunConfiguration::isValidVersion(QtSupport::BaseQtVersion *version)
{
return version
&& version->type() == QLatin1String(QtSupport::Constants::DESKTOPQT)
&& !static_cast<QtSupport::DesktopQtVersion *>(version)->qmlsceneCommand().isEmpty();
}
} // namespace QmlProjectManager

View File

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

View File

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