Commit e81c5186 authored by Alessandro Portale's avatar Alessandro Portale
Browse files

Deployment of Qml modules.

Application logic implemented. The Wizard Ui does not expose
this feature, yet.
parent 3108d14f
......@@ -6,8 +6,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
QmlApplicationView qmlApp(QLatin1String("qml/app/app.qml")); // MAINQML
QStringList importPaths; // IMPORTPATHSLIST
qmlApp.setImportPathList(importPaths); // SETIMPORTPATHLIST
qmlApp.addImportPath(QLatin1String("modules")); // ADDIMPORTPATH
qmlApp.setOrientation(QmlApplicationView::Auto); // ORIENTATION
qmlApp.setLoadDummyData(false); // LOADDUMMYDATA
......
......@@ -44,9 +44,9 @@ QmlApplicationView::~QmlApplicationView()
delete m_d;
}
void QmlApplicationView::setImportPathList(const QStringList &importPaths)
void QmlApplicationView::addImportPath(const QString &importPath)
{
engine()->setImportPathList(importPaths);
engine()->addImportPath(importPath);
}
void QmlApplicationView::setOrientation(Orientation orientation)
......
......@@ -19,7 +19,7 @@ public:
QmlApplicationView(const QString &mainQmlFile, QWidget *parent = 0);
virtual ~QmlApplicationView();
void setImportPathList(const QStringList &importPaths);
void addImportPath(const QString &importPath);
void setOrientation(Orientation orientation);
void setLoadDummyData(bool loadDummyData);
......
......@@ -41,6 +41,52 @@
namespace QmlProjectManager {
namespace Internal {
const QLatin1String qmldir("qmldir");
const QLatin1String qmldir_plugin("plugin");
QmlModule::QmlModule(const QString &name, const QFileInfo &rootDir, const QFileInfo &qmldir,
bool isExternal, QmlStandaloneApp *qmlStandaloneApp)
: name(name)
, rootDir(rootDir)
, qmldir(qmldir)
, isExternal(isExternal)
, qmlStandaloneApp(qmlStandaloneApp)
{}
QString QmlModule::path(Location location) const
{
switch (location) {
case Root: {
return rootDir.canonicalFilePath();
}
case ContentDir: {
const QDir proFile(qmlStandaloneApp->path(QmlStandaloneApp::AppProfilePath));
return proFile.relativeFilePath(qmldir.canonicalPath());
}
case ContentBase: {
const QString localRoot = rootDir.canonicalFilePath() + QLatin1Char('/');
QDir contentDir = qmldir.dir();
contentDir.cdUp();
const QString localContentDir = contentDir.canonicalPath();
return localContentDir.right(localContentDir.length() - localRoot.length());
}
case DeployedContentBase: {
const QString modulesDir = qmlStandaloneApp->path(QmlStandaloneApp::ModulesDir);
return modulesDir + QLatin1Char('/') + path(ContentBase);
}
default: qFatal("QmlModule::path() needs more work");
}
return QString();
}
QmlCppPlugin::QmlCppPlugin(const QString &name, const QFileInfo &path,
const QmlModule *module, const QFileInfo &proFile)
: name(name)
, path(path)
, module(module)
, proFile(proFile)
{}
QmlStandaloneApp::QmlStandaloneApp()
: m_loadDummyData(false)
, m_orientation(Auto)
......@@ -48,6 +94,11 @@ QmlStandaloneApp::QmlStandaloneApp()
{
}
QmlStandaloneApp::~QmlStandaloneApp()
{
clearModulesAndPlugins();
}
QString QmlStandaloneApp::symbianUidForPath(const QString &path)
{
quint32 hash = 5381;
......@@ -135,6 +186,43 @@ bool QmlStandaloneApp::networkEnabled() const
return m_networkEnabled;
}
bool QmlStandaloneApp::setExternalModules(const QStringList &moduleNames,
const QStringList &importPaths)
{
clearModulesAndPlugins();
m_importPaths.clear();
foreach (const QFileInfo &importPath, importPaths) {
if (!importPath.exists()) {
m_error = tr("The Qml import path '%1' cannot be found.")
.arg(QDir::toNativeSeparators(importPath.filePath()));
return false;
} else {
m_importPaths.append(importPath.canonicalFilePath());
}
}
foreach (const QString &moduleName, moduleNames) {
QString modulePath = moduleName;
modulePath.replace(QLatin1Char('.'), QLatin1Char('/'));
const int modulesCount = m_modules.count();
foreach (const QFileInfo &importPath, m_importPaths) {
const QFileInfo qmlDirFile(
importPath.absoluteFilePath() + QLatin1Char('/')
+ modulePath + QLatin1Char('/') + qmldir);
if (qmlDirFile.exists()) {
if (!addExternalModule(moduleName, importPath, qmlDirFile))
return false;
break;
}
}
if (modulesCount == m_modules.count()) { // no module was added
m_error = tr("The Qml module '%1' cannot be found.").arg(moduleName);
return false;
}
}
m_error.clear();
return true;
}
QString QmlStandaloneApp::path(Path path) const
{
const QString qmlSubDir = QLatin1String("qml/")
......@@ -150,7 +238,6 @@ QString QmlStandaloneApp::path(Path path) const
const QString appViewHFileName = QLatin1String("qmlapplicationview.h");
const QString symbianIconFileName = QLatin1String("symbianicon.svg");
const char* const errorMessage = "QmlStandaloneApp::path() needs more work";
const QString pathBase = m_projectPath.absoluteFilePath() + QLatin1Char('/')
+ m_projectName + QLatin1Char('/');
const QDir appProFilePath(pathBase);
......@@ -182,12 +269,12 @@ QString QmlStandaloneApp::path(Path path) const
case QmlDir: return pathBase + qmlSubDir;
case QmlDirProFileRelative: return useExistingMainQml() ? appProFilePath.relativeFilePath(m_mainQmlFile.canonicalPath())
: QString(qmlSubDir).remove(qmlSubDir.length() - 1, 1);
case ModulesDir: return QLatin1String("modules");
default: qFatal(errorMessage);
}
return QString();
}
static QString insertParameter(const QString &line, const QString &parameter)
{
return QString(line).replace(QRegExp(QLatin1String("\\([^()]+\\)")),
......@@ -211,10 +298,9 @@ QByteArray QmlStandaloneApp::generateMainCpp(const QString *errorMessage) const
line = in.readLine();
if (line.contains(QLatin1String("// MAINQML"))) {
line = insertParameter(line, QLatin1Char('"') + path(MainQmlDeployed) + QLatin1Char('"'));
} else if (line.contains(QLatin1String("// IMPORTPATHSLIST"))) {
continue;
} else if (line.contains(QLatin1String("// SETIMPORTPATHLIST"))) {
continue;
} else if (line.contains(QLatin1String("// ADDIMPORTPATH"))) {
if (!m_modules.isEmpty())
line = insertParameter(line, QLatin1Char('"') + path(ModulesDir) + QLatin1Char('"'));
} else if (line.contains(QLatin1String("// ORIENTATION"))) {
if (m_orientation == Auto)
continue;
......@@ -260,9 +346,22 @@ QByteArray QmlStandaloneApp::generateProFile(const QString *errorMessage) const
do {
line = in.readLine();
} while (!(line.isNull() || line.contains(QLatin1String("# DEPLOYMENTFOLDERS_END"))));
QStringList folders;
out << "folder_01.source = " << path(QmlDirProFileRelative) << endl;
out << "folder_01.target = qml" << endl;
out << "DEPLOYMENTFOLDERS = folder_01" << endl;
folders.append(QLatin1String("folder_01"));
int foldersCount = 1;
foreach (const QmlModule *module, m_modules) {
if (module->isExternal) {
foldersCount ++;
const QString folder =
QString::fromLatin1("folder_%1").arg(foldersCount, 2, 10, QLatin1Char('0'));
folders.append(folder);
out << folder << ".source = " << module->path(QmlModule::ContentDir) << endl;
out << folder << ".target = " << module->path(QmlModule::DeployedContentBase) << endl;
}
}
out << "DEPLOYMENTFOLDERS = " << folders.join(QLatin1String(" ")) << endl;
} else if (line.contains(QLatin1String("# ORIENTATIONLOCK")) && m_orientation == QmlStandaloneApp::Auto) {
uncommentNextLine = true;
} else if (line.contains(QLatin1String("# NETWORKACCESS")) && !m_networkEnabled) {
......@@ -295,6 +394,79 @@ QByteArray QmlStandaloneApp::generateProFile(const QString *errorMessage) const
return proFileContent;
}
void QmlStandaloneApp::clearModulesAndPlugins()
{
qDeleteAll(m_modules);
m_modules.clear();
qDeleteAll(m_cppPlugins);
m_cppPlugins.clear();
}
bool QmlStandaloneApp::addCppPlugin(const QString &qmldirLine, QmlModule *module)
{
const QStringList qmldirLineElements =
qmldirLine.split(QLatin1Char(' '), QString::SkipEmptyParts);
if (qmldirLineElements.count() < 2) {
m_error = tr("Invalid '%1' entry in '%2' of module '%3'.")
.arg(qmldir_plugin).arg(qmldir).arg(module->name);
return false;
}
const QString name = qmldirLineElements.at(1);
const QFileInfo path(module->qmldir.dir(), qmldirLineElements.value(2, QString()));
// TODO: Add more magic to find a good .pro file..
const QString proFileName = name + QLatin1String(".pro");
const QFileInfo proFile_guess1(module->qmldir.dir(), proFileName);
const QFileInfo proFile_guess2(QString(module->qmldir.dir().absolutePath() + QLatin1String("/../")),
proFileName);
const QFileInfo proFile_guess3(module->qmldir.dir(),
QFileInfo(module->qmldir.path()).fileName() + QLatin1String(".pro"));
const QFileInfo proFile_guess4(proFile_guess3.absolutePath() + QLatin1String("/../")
+ proFile_guess3.fileName());
QFileInfo foundProFile;
if (proFile_guess1.exists()) {
foundProFile = proFile_guess1.canonicalFilePath();
} else if (proFile_guess2.exists()) {
foundProFile = proFile_guess2.canonicalFilePath();
} else if (proFile_guess3.exists()) {
foundProFile = proFile_guess3.canonicalFilePath();
} else if (proFile_guess4.exists()) {
foundProFile = proFile_guess4.canonicalFilePath();
} else {
m_error = tr("No .pro file for plugin '%1' cannot be found.").arg(name);
return false;
}
QmlCppPlugin *plugin =
new QmlCppPlugin(name, path, module, foundProFile);
m_cppPlugins.append(plugin);
module->cppPlugins.insert(name, plugin);
return true;
}
bool QmlStandaloneApp::addCppPlugins(QmlModule *module)
{
QFile qmlDirFile(module->qmldir.absoluteFilePath());
if (qmlDirFile.open(QIODevice::ReadOnly)) {
QTextStream ts(&qmlDirFile);
QString line;
do {
line = ts.readLine().trimmed();
if (line.startsWith(qmldir_plugin) && !addCppPlugin(line, module))
return false;
} while (!line.isNull());
}
return true;
}
bool QmlStandaloneApp::addExternalModule(const QString &name, const QFileInfo &dir,
const QFileInfo &contentDir)
{
QmlModule *module = new QmlModule(name, dir, contentDir, true, this);
m_modules.append(module);
return addCppPlugins(module);
}
#ifndef CREATORLESSTEST
QString QmlStandaloneApp::templatesRoot()
{
......@@ -346,5 +518,15 @@ bool QmlStandaloneApp::useExistingMainQml() const
return !m_mainQmlFile.filePath().isEmpty();
}
QString QmlStandaloneApp::error() const
{
return m_error;
}
const QList<QmlModule*> QmlStandaloneApp::modules() const
{
return m_modules;
}
} // namespace Internal
} // namespace QmlProjectManager
......@@ -30,8 +30,9 @@
#ifndef QMLSTANDALONEAPP_H
#define QMLSTANDALONEAPP_H
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QFileInfo>
#include <QtCore/QHash>
#ifndef CREATORLESSTEST
#include <coreplugin/basefilewizard.h>
......@@ -40,7 +41,42 @@
namespace QmlProjectManager {
namespace Internal {
class QmlStandaloneApp
class QmlStandaloneApp;
struct QmlModule
{
enum Location {
// Example: Module "com.foo.bar" in "c:/modules/".
// "qmldir" file is in "c:/modules/com/foo/bar/".
// Application .pro file is "c:/app/app.pro".
Root, // "c:/modules/" (absolute)
ContentDir, // "../modules/com/foo/bar" (relative form .pro file)
ContentBase, // "com/foo/"
DeployedContentBase // "<qmlmodules>/com/foo" (on deploy target)
};
QmlModule(const QString &name, const QFileInfo &rootDir, const QFileInfo &qmldir,
bool isExternal, QmlStandaloneApp *qmlStandaloneApp);
QString path(Location location) const;
const QString name; // "com.foo.bar"
const QFileInfo rootDir; // Location of "com/"
const QFileInfo qmldir; // 'qmldir' file.
const bool isExternal; // Either external or inside a source paths
const QmlStandaloneApp *qmlStandaloneApp;
QHash<QString, struct QmlCppPlugin*> cppPlugins; // Just as info. No ownership.
};
struct QmlCppPlugin
{
QmlCppPlugin(const QString &name, const QFileInfo &path,
const QmlModule *module, const QFileInfo &proFile);
const QString name; // Original name
const QFileInfo path; // Plugin path where qmldir points to
const QmlModule *module;
const QFileInfo proFile; // .pro file for the plugin
};
class QmlStandaloneApp: public QObject
{
public:
enum Orientation {
......@@ -72,10 +108,12 @@ public:
SymbianSvgIconOrigin,
SymbianSvgIconProFileRelative,
QmlDir,
QmlDirProFileRelative
QmlDirProFileRelative,
ModulesDir
};
QmlStandaloneApp();
~QmlStandaloneApp();
void setMainQmlFile(const QString &qmlFile);
QString mainQmlFile() const;
......@@ -93,6 +131,9 @@ public:
void setNetworkEnabled(bool enabled);
bool networkEnabled() const;
bool setExternalModules(const QStringList &moduleNames,
const QStringList &importPaths);
static QString symbianUidForPath(const QString &path);
#ifndef CREATORLESSTEST
Core::GeneratedFiles generateFiles(QString *errorMessage) const;
......@@ -101,11 +142,18 @@ public:
#endif // CREATORLESSTEST
QString path(Path path) const;
bool useExistingMainQml() const;
QString error() const;
const QList<QmlModule*> modules() const;
private:
QByteArray generateMainCpp(const QString *errorMessage) const;
QByteArray generateProFile(const QString *errorMessage) const;
static QString templatesRoot();
bool addExternalModule(const QString &name, const QFileInfo &dir,
const QFileInfo &contentDir);
bool addCppPlugins(QmlModule *module);
bool addCppPlugin(const QString &qmldirLine, QmlModule *module);
void clearModulesAndPlugins();
QString m_projectName;
QFileInfo m_projectPath;
......@@ -115,6 +163,10 @@ private:
Orientation m_orientation;
bool m_networkEnabled;
QFileInfo m_mainQmlFile;
QStringList m_importPaths;
QList <QmlModule*> m_modules;
QList <QmlCppPlugin*> m_cppPlugins;
QString m_error;
};
} // end of namespace Internal
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment