diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index 7b99214f04..df5f7f8ee9 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -295,4 +295,18 @@ QList QQmlDirParser::typeInfos() const } #endif +QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component) +{ + return debug << qPrintable(QString("{%1 %2.%3}").arg(component.typeName) + .arg(component.majorVersion) + .arg(component.minorVersion)); +} + +QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script) +{ + return debug << qPrintable(QString("{%1 %2.%3}").arg(script.nameSpace) + .arg(script.majorVersion) + .arg(script.minorVersion)); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h index 8c681309ac..f46e1781da 100644 --- a/src/qml/qml/qqmldirparser_p.h +++ b/src/qml/qml/qqmldirparser_p.h @@ -55,6 +55,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -160,6 +161,8 @@ class QQmlDirParser typedef QList QQmlDirComponents; typedef QList QQmlDirScripts; +QDebug &operator<< (QDebug &, const QQmlDirParser::Component &); +QDebug &operator<< (QDebug &, const QQmlDirParser::Script &); QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 0c1fb3bd93..1224efdaac 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -117,7 +117,7 @@ class QQmlImportsPrivate { QList *errors); QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database); - bool add(const QQmlDirComponents &qmldircomponentsnetwork, + QString add(const QQmlDirComponents &qmldircomponentsnetwork, const QString& uri_arg, const QString& prefix, int vmaj, int vmin, QQmlScript::Import::Type importType, QQmlImportDatabase *database, QList *errors); @@ -493,7 +493,7 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba return stableRelativePath; } -bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, +QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, const QString& uri_arg, const QString& prefix, int vmaj, int vmin, QQmlScript::Import::Type importType, QQmlImportDatabase *database, QList *errors) @@ -540,7 +540,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, url = QUrl::fromLocalFile(fi.absolutePath()).toString(); uri = resolvedUri(dir, database); if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return false; + return QString(); break; } } @@ -564,7 +564,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, url = QUrl::fromLocalFile(fi.absolutePath()).toString(); uri = resolvedUri(dir, database); if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return false; + return QString(); break; } } @@ -586,7 +586,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, url = QUrl::fromLocalFile(absolutePath).toString(); uri = resolvedUri(dir, database); if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return false; + return QString(); break; } } @@ -604,7 +604,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg)); errors->prepend(error); } - return false; + return QString(); } } else { if (importType == QQmlScript::Import::File && qmldircomponents.isEmpty()) { @@ -619,14 +619,14 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, error.setUrl(QUrl(importUrl)); errors->prepend(error); } - return false; // local import dirs must exist + return QString(); // local import dirs must exist } uri = resolvedUri(dir, database); if (uri.endsWith(Slash)) uri.chop(1); if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) { if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,&qmldirscripts,errors)) - return false; + return QString(); } } else { if (prefix.isEmpty()) { @@ -642,7 +642,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, error.setUrl(QUrl(importUrl)); errors->prepend(error); } - return false; + return QString(); } } } @@ -669,7 +669,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin)); errors->prepend(error); } - return false; + return QString(); } } @@ -686,7 +686,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, QQmlError error; error.setDescription(QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url)); errors->prepend(error); - return false; + return QString(); } } @@ -716,7 +716,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, s->imports.prepend(data); - return true; + return data.url; } bool QQmlImportsPrivate::find(const QString& type, int *vmajor, int *vminor, QQmlType** type_return, @@ -874,9 +874,11 @@ QQmlImportDatabase::~QQmlImportDatabase() The \a prefix may be empty, in which case the import location is considered for unqualified types. + Returns the resolved URL of the import on success. + The base URL must already have been set with Import::setBaseUrl(). */ -bool QQmlImports::addImport(QQmlImportDatabase *importDb, +QString QQmlImports::addImport(QQmlImportDatabase *importDb, const QString& uri, const QString& prefix, int vmaj, int vmin, QQmlScript::Import::Type importType, const QQmlDirComponents &qmldircomponentsnetwork, diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index ff19510525..422f2429a0 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -93,7 +93,7 @@ class Q_QML_EXPORT QQmlImports QQmlType** type_return, QString* url_return, int *version_major, int *version_minor) const; - bool addImport(QQmlImportDatabase *, + QString addImport(QQmlImportDatabase *, const QString& uri, const QString& prefix, int vmaj, int vmin, QQmlScript::Import::Type importType, const QQmlDirComponents &qmldircomponentsnetwork, diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 781915e23e..abe2c0bfa4 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1558,7 +1558,6 @@ void QQmlTypeData::dataReceived(const QByteArray &data) ref.qualifier = import.qualifier; ref.script = blob; m_scripts << ref; - } } @@ -1657,8 +1656,8 @@ void QQmlTypeData::resolveTypes() import.extractVersion(&vmaj, &vmin); QList errors; - if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, - vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) { + if (m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin, + import.type, qmldircomponentsnetwork, &errors).isNull()) { QQmlError error; if (errors.size()) { error = errors.takeFirst(); @@ -1859,8 +1858,9 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data) import.extractVersion(&vmaj, &vmin); QList errors; - if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin, - import.type, QQmlDirComponents(), &errors)) { + QString importUrl = m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin, + import.type, QQmlDirComponents(), &errors); + if (importUrl.isNull()) { QQmlError error = errors.takeFirst(); // description should be set by addImport(). error.setUrl(m_imports.baseUrl()); @@ -1871,6 +1871,22 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data) setError(errors); return; } + + // Does this library contain any scripts? + QUrl libraryUrl(importUrl); + const QQmlDirParser *dirParser = typeLoader()->qmlDirParser(libraryUrl.path() + QLatin1String("qmldir")); + foreach (const QQmlDirParser::Script &script, dirParser->scripts()) { + QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName)); + QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl); + addDependency(blob); + + ScriptReference ref; + ref.location = import.location.start; + ref.qualifier = script.nameSpace; + ref.nameSpace = import.qualifier; + ref.script = blob; + m_scripts << ref; + } } } } @@ -1902,11 +1918,20 @@ void QQmlScriptBlob::done() m_scriptData->urlString = finalUrlString(); m_scriptData->importCache = new QQmlTypeNameCache(); - for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) { - const ScriptReference &script = m_scripts.at(ii); + QSet ns; + + for (int scriptIndex = 0; !isError() && scriptIndex < m_scripts.count(); ++scriptIndex) { + const ScriptReference &script = m_scripts.at(scriptIndex); m_scriptData->scripts.append(script.script); - m_scriptData->importCache->add(script.qualifier, ii); + + if (!script.nameSpace.isNull()) { + if (!ns.contains(script.nameSpace)) { + ns.insert(script.nameSpace); + m_scriptData->importCache->add(script.nameSpace); + } + } + m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace); } m_imports.populateCache(m_scriptData->importCache, engine); diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index c8c2756bd5..319b2e7a10 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -390,6 +390,7 @@ class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlDataBlob QQmlScript::Location location; QString qualifier; + QString nameSpace; QQmlScriptBlob *script; }; diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml new file mode 100644 index 0000000000..ae43e90210 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +import com.nokia.JsModule 1.0 +import com.nokia.JsModule 1.0 as RenamedModule +import "testJsModuleImport.js" as TestJsModuleImport + +QtObject { + id: testQtObject + + property string importedScriptStringValue: ScriptAPI.greeting(); + property string renamedScriptStringValue: RenamedModule.ScriptAPI.greeting(); + property string reimportedScriptStringValue: TestJsModuleImport.importedValue(); +} diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js new file mode 100644 index 0000000000..2d21953d2c --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js @@ -0,0 +1,5 @@ +.import com.nokia.JsModule 1.0 as JsModule + +function importedValue() { + return JsModule.ScriptAPI.greeting(); +} diff --git a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/ScriptAPI.js b/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/ScriptAPI.js new file mode 100644 index 0000000000..b90033eeb4 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/ScriptAPI.js @@ -0,0 +1,5 @@ +var major = 1 +var minor = 0 + +function greeting() { return "Hello" } + diff --git a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/qmldir b/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/qmldir new file mode 100644 index 0000000000..c33d1e7a0d --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/qmldir @@ -0,0 +1 @@ +ScriptAPI 1.0 ScriptAPI.js diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 79eaa3316f..2f27ccee31 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -254,6 +254,9 @@ void tst_qqmlecmascript::initTestCase() { QQmlDataTest::initTestCase(); registerTypes(); + + QString dataDir(dataDirectory() + QLatin1Char('/') + QLatin1String("lib")); + engine.addImportPath(dataDir); } void tst_qqmlecmascript::assignBasicTypes() @@ -3298,6 +3301,17 @@ void tst_qqmlecmascript::importScripts_data() << QStringList() << (QStringList() << QLatin1String("testValue")) << (QVariantList() << QVariant(20)); + + QTest::newRow("import module which exports a script") + << testFileUrl("jsimport/testJsImport.qml") + << QString() + << QStringList() + << (QStringList() << QLatin1String("importedScriptStringValue") + << QLatin1String("renamedScriptStringValue") + << QLatin1String("reimportedScriptStringValue")) + << (QVariantList() << QVariant(QString("Hello")) + << QVariant(QString("Hello")) + << QVariant(QString("Hello"))); } void tst_qqmlecmascript::importScripts()