Skip to content

Commit

Permalink
Allow JS API in modules
Browse files Browse the repository at this point in the history
Allow modules to export verisoned javascript code into specified
namespaces.

Task-number: QTBUG-20857
Change-Id: Ic968c697ba36cbc4535870ed5eed2fe7f01af11d
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
  • Loading branch information
Matthew Vogt authored and Qt by Nokia committed Jan 24, 2012
1 parent 49212ef commit 149f6af
Show file tree
Hide file tree
Showing 42 changed files with 580 additions and 83 deletions.
39 changes: 38 additions & 1 deletion doc/src/declarative/modules.qdoc
Expand Up @@ -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

Expand All @@ -310,6 +342,7 @@ It is defined by a plain text file named "qmldir" that contains one or more line
# <Comment>
<TypeName> [<InitialVersion>] <File>
internal <TypeName> <File>
<Namespace> <InitialVersion> <File>
plugin <Name> [<Path>]
typeinfo <File>
\endcode
Expand Down Expand Up @@ -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 {<Namespace> <InitialVersion> <File>} 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 <Namespace>, which has the version number
<InitialVersion>.

\bold {plugin <Name> [<Path>]} lines are used to add \l{QDeclarativeExtensionPlugin}{QML C++ plugins} to the module. <Name> 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.
Expand All @@ -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
Expand Down
13 changes: 13 additions & 0 deletions src/declarative/qml/ftw/qhashedstring_p.h
Expand Up @@ -104,6 +104,8 @@ class Q_AUTOTEST_EXPORT QHashedV8String

inline v8::Handle<v8::String> string() const;

inline QString toString() const;

private:
v8::String::CompleteHashData m_hash;
v8::Handle<v8::String> m_string;
Expand Down Expand Up @@ -917,6 +919,17 @@ v8::Handle<v8::String> 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)
{
Expand Down
27 changes: 18 additions & 9 deletions src/declarative/qml/qdeclarativecompiler.cpp
Expand Up @@ -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())
Expand Down
19 changes: 16 additions & 3 deletions src/declarative/qml/qdeclarativedirparser.cpp
Expand Up @@ -103,6 +103,7 @@ bool QDeclarativeDirParser::parse()
_errors.clear();
_plugins.clear();
_components.clear();
_scripts.clear();

if (_source.isEmpty() && !_filePathSouce.isEmpty()) {
QFile file(_filePathSouce);
Expand Down Expand Up @@ -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);
}
}
}
}
Expand Down Expand Up @@ -275,6 +283,11 @@ QList<QDeclarativeDirParser::Component> QDeclarativeDirParser::components() cons
return _components;
}

QList<QDeclarativeDirParser::Script> QDeclarativeDirParser::scripts() const
{
return _scripts;
}

#ifdef QT_CREATOR
QList<QDeclarativeDirParser::TypeInfo> QDeclarativeDirParser::typeInfos() const
{
Expand Down
17 changes: 17 additions & 0 deletions src/declarative/qml/qdeclarativedirparser_p.h
Expand Up @@ -109,7 +109,22 @@ class QDeclarativeDirParser
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<Component> components() const;
QList<Script> scripts() const;
QList<Plugin> plugins() const;

#ifdef QT_CREATOR
Expand All @@ -134,6 +149,7 @@ class QDeclarativeDirParser
QString _source;
QString _filePathSouce;
QList<Component> _components;
QList<Script> _scripts;
QList<Plugin> _plugins;
#ifdef QT_CREATOR
QList<TypeInfo> _typeInfos;
Expand All @@ -142,6 +158,7 @@ class QDeclarativeDirParser
};

typedef QList<QDeclarativeDirParser::Component> QDeclarativeDirComponents;
typedef QList<QDeclarativeDirParser::Script> QDeclarativeDirScripts;


QT_END_NAMESPACE
Expand Down

0 comments on commit 149f6af

Please sign in to comment.