From: Matthew Vogt Date: Wed, 18 Jan 2012 07:12:25 +0000 (+1000) Subject: Allow JS API in modules X-Git-Tag: qt-v5.0.0-alpha1~598 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=149f6afe321ce59aebe4ce2f9dddd1881d0ac22b;p=profile%2Fivi%2Fqtdeclarative.git Allow JS API in modules Allow modules to export verisoned javascript code into specified namespaces. Task-number: QTBUG-20857 Change-Id: Ic968c697ba36cbc4535870ed5eed2fe7f01af11d Reviewed-by: Roberto Raggi --- diff --git a/doc/src/declarative/modules.qdoc b/doc/src/declarative/modules.qdoc index 92a2c0d..437b41b 100644 --- a/doc/src/declarative/modules.qdoc +++ b/doc/src/declarative/modules.qdoc @@ -297,6 +297,38 @@ Item { The qualifier ("MyScript" in the above example) must be unique within the QML document. Unlike ordinary modules, multiple scripts cannot be imported into the same namespace. +Javascript files can be provided by modules, by adding Namespace definitions to the +\l{Writing a qmldir file}{qmldir file} for the module. For example: + +\code +SystemFunctions 1.0 SystemFunctions.js +UserFunctions 1.0 UserFunctions.js +\endcode + +Javascript can be imported from a module, where they will have the namespace defined +for them in the module's \c qmldir file: + +\qml +import projects.MyQMLProject.MyFunctions 1.0 + +Window { + Component.onCompleted: { SystemFunctions.cleanUp(); } +} +\endqml + +Javascript provided by modules can also be imported into namespaces: + +\qml +import projects.MyQMLProject.MyFunctions 1.0 as MyFuncs +import org.example.Functions 1.0 as TheirFuncs + +Window { + Component.onCompleted: { + MyFuncs.SystemFunctions.cleanUp(); + TheirFuncs.SystemFunctions.shutdown(); + } +} +\endqml \section1 Writing a qmldir File @@ -310,6 +342,7 @@ It is defined by a plain text file named "qmldir" that contains one or more line # [] internal + plugin [] typeinfo \endcode @@ -343,6 +376,11 @@ of installed software, since a versioned import \i only imports types for that v leaving other identifiers available, even if the actual installed version might otherwise provide those identifiers. +\bold { } lines are used to import javascript files +into a Namespace exported by the module. The contents of the script file are made +available inside the namespace , which has the version number +. + \bold {plugin []} lines are used to add \l{QDeclarativeExtensionPlugin}{QML C++ plugins} to the module. is the name of the library. It is usually not the same as the file name of the plugin binary, which is platform dependent; e.g. the library \c MyAppTypes would produce \c libMyAppTypes.so on Linux and \c MyAppTypes.dll on Windows. @@ -360,7 +398,6 @@ file. Without such a file QML tools may be unable to offer features such as code completion for the types defined in your plugins. - \section1 Debugging The \c QML_IMPORT_TRACE environment variable can be useful for debugging diff --git a/src/declarative/qml/ftw/qhashedstring_p.h b/src/declarative/qml/ftw/qhashedstring_p.h index 00c9e34..f4dd6ee 100644 --- a/src/declarative/qml/ftw/qhashedstring_p.h +++ b/src/declarative/qml/ftw/qhashedstring_p.h @@ -104,6 +104,8 @@ public: inline v8::Handle string() const; + inline QString toString() const; + private: v8::String::CompleteHashData m_hash; v8::Handle m_string; @@ -917,6 +919,17 @@ v8::Handle QHashedV8String::string() const return m_string; } +QString QHashedV8String::toString() const +{ + QString result; + result.reserve(m_hash.length); + + for (int i = 0; i < m_hash.length; ++i) + result.append(m_string->GetCharacter(i)); + + return result; +} + QHashedStringRef::QHashedStringRef() : m_data(0), m_length(0), m_utf8length(-1), m_hash(0) { diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index aec3993..07e381c 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -859,19 +859,28 @@ void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree) if (componentStats) componentStats->componentStat.lineNumber = tree->location.start.line; - // Build global import scripts - QStringList importedScriptIndexes; - - foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) { - importedScriptIndexes.append(script.qualifier); - } - // We generate the importCache before we build the tree so that // it can be used in the binding compiler. Given we "expect" the // QML compilation to succeed, this isn't a waste. output->importCache = new QDeclarativeTypeNameCache(); - for (int ii = 0; ii < importedScriptIndexes.count(); ++ii) - output->importCache->add(importedScriptIndexes.at(ii), ii); + foreach (const QString &ns, unit->namespaces()) { + output->importCache->add(ns); + } + + int scriptIndex = 0; + foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) { + QString qualifier = script.qualifier; + QString enclosingNamespace; + + const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); + if (lastDotIndex != -1) { + enclosingNamespace = qualifier.left(lastDotIndex); + qualifier = qualifier.mid(lastDotIndex+1); + } + + output->importCache->add(qualifier, scriptIndex++, enclosingNamespace); + } + unit->imports().populateCache(output->importCache, engine); if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) diff --git a/src/declarative/qml/qdeclarativedirparser.cpp b/src/declarative/qml/qdeclarativedirparser.cpp index d7c44e4..c4a11a9 100644 --- a/src/declarative/qml/qdeclarativedirparser.cpp +++ b/src/declarative/qml/qdeclarativedirparser.cpp @@ -103,6 +103,7 @@ bool QDeclarativeDirParser::parse() _errors.clear(); _plugins.clear(); _components.clear(); + _scripts.clear(); if (_source.isEmpty() && !_filePathSouce.isEmpty()) { QFile file(_filePathSouce); @@ -220,9 +221,16 @@ bool QDeclarativeDirParser::parse() const int minorVersion = version.mid(dotIndex + 1).toInt(&validVersionNumber); if (validVersionNumber) { - const Component entry(sections[0], sections[2], majorVersion, minorVersion); - - _components.append(entry); + const QString &fileName = sections[2]; + + if (fileName.endsWith(QLatin1String(".js"))) { + // A 'js' extension indicates a namespaced script import + const Script entry(sections[0], fileName, majorVersion, minorVersion); + _scripts.append(entry); + } else { + const Component entry(sections[0], fileName, majorVersion, minorVersion); + _components.append(entry); + } } } } @@ -275,6 +283,11 @@ QList QDeclarativeDirParser::components() cons return _components; } +QList QDeclarativeDirParser::scripts() const +{ + return _scripts; +} + #ifdef QT_CREATOR QList QDeclarativeDirParser::typeInfos() const { diff --git a/src/declarative/qml/qdeclarativedirparser_p.h b/src/declarative/qml/qdeclarativedirparser_p.h index d31666c..0f726b7 100644 --- a/src/declarative/qml/qdeclarativedirparser_p.h +++ b/src/declarative/qml/qdeclarativedirparser_p.h @@ -109,7 +109,22 @@ public: bool internal; }; + struct Script + { + Script() + : majorVersion(0), minorVersion(0) {} + + Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion) + : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) {} + + QString nameSpace; + QString fileName; + int majorVersion; + int minorVersion; + }; + QList components() const; + QList