summaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-10-07 05:37:44 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-10-07 05:37:44 (GMT)
commit99573a8e81fcea38c5f68b340068fff266315c03 (patch)
tree42f71fa7727fa4036096b07f15d2e9ba27ec8ef9 /src/declarative
parent50a4a8ec76b98cc860de9b6e6aaf25c87e690eed (diff)
downloadQt-99573a8e81fcea38c5f68b340068fff266315c03.zip
Qt-99573a8e81fcea38c5f68b340068fff266315c03.tar.gz
Qt-99573a8e81fcea38c5f68b340068fff266315c03.tar.bz2
Make Script an instrinsic type
This allows us to delay the QML load until external script files have been loaded from the network, and to correctly scope these scripts.
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/qml/qml.pri1
-rw-r--r--src/declarative/qml/qmlcompiler.cpp78
-rw-r--r--src/declarative/qml/qmlcompiler_p.h1
-rw-r--r--src/declarative/qml/qmlcompositetypedata_p.h22
-rw-r--r--src/declarative/qml/qmlcompositetypemanager.cpp152
-rw-r--r--src/declarative/qml/qmlcompositetypemanager_p.h6
-rw-r--r--src/declarative/qml/qmlcontext.cpp39
-rw-r--r--src/declarative/qml/qmlcontext_p.h1
-rw-r--r--src/declarative/qml/qmlinstruction_p.h4
-rw-r--r--src/declarative/qml/qmlmetaproperty.cpp2
-rw-r--r--src/declarative/qml/qmlparser.cpp2
-rw-r--r--src/declarative/qml/qmlparser_p.h5
-rw-r--r--src/declarative/qml/qmlscript.cpp (renamed from src/declarative/util/qmlscript.h)70
-rw-r--r--src/declarative/qml/qmlscriptparser.cpp51
-rw-r--r--src/declarative/qml/qmlscriptparser_p.h2
-rw-r--r--src/declarative/qml/qmlvme.cpp7
-rw-r--r--src/declarative/util/qmlscript.cpp209
-rw-r--r--src/declarative/util/util.pri2
18 files changed, 393 insertions, 261 deletions
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index e46dd3f..a2e2050 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -35,6 +35,7 @@ SOURCES += qml/qmlparser.cpp \
qml/qmlsqldatabase.cpp \
qml/qmetaobjectbuilder.cpp \
qml/qmlwatcher.cpp \
+ qml/qmlscript.cpp \
qml/qmlpropertycache.cpp \
qml/qmlintegercache.cpp \
qml/qmltypenamecache.cpp \
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index 4b5c5bf..12e8101 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -669,7 +669,11 @@ bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt)
if (obj->metatype == &QmlComponent::staticMetaObject) {
COMPILE_CHECK(buildComponent(obj, ctxt));
return true;
- }
+ }
+
+ // Build any script blocks for this type
+ for (int ii = 0; ii < obj->scriptBlockObjects.count(); ++ii)
+ COMPILE_CHECK(buildScript(obj, obj->scriptBlockObjects.at(ii)));
// Object instantiations reset the binding context
BindingContext objCtxt(obj);
@@ -824,6 +828,15 @@ void QmlCompiler::genObject(QmlParser::Object *obj)
output->bytecode << id;
}
+ // Set any script blocks
+ for (int ii = 0; ii < obj->scriptBlocks.count(); ++ii) {
+ QmlInstruction script;
+ script.type = QmlInstruction::StoreScript;
+ script.line = -1; // ###
+ script.storeScript.value = output->indexForString(obj->scriptBlocks.at(ii));
+ output->bytecode << script;
+ }
+
// Begin the class
if (obj->parserStatusCast != -1) {
QmlInstruction begin;
@@ -1000,7 +1013,8 @@ bool QmlCompiler::buildComponent(QmlParser::Object *obj,
// Find, check and set the "id" property (if any)
Property *idProp = 0;
if (obj->properties.count() > 1 ||
- (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
+ (obj->properties.count() == 1 && obj->properties.begin().key() != "id") ||
+ !obj->scriptBlockObjects.isEmpty())
COMPILE_EXCEPTION(obj, "Invalid component specification");
if (obj->properties.count())
@@ -1037,6 +1051,66 @@ bool QmlCompiler::buildComponent(QmlParser::Object *obj,
return true;
}
+bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script)
+{
+ QString scriptCode;
+
+ if (script->properties.count() == 1 &&
+ script->properties.begin().key() == QByteArray("source")) {
+
+ Property *source = *script->properties.begin();
+ if (script->defaultProperty)
+ COMPILE_EXCEPTION(source, "Invalid Script block. Specify either the source property or inline script.");
+
+ if (source->value || source->values.count() != 1 ||
+ source->values.at(0)->object || !source->values.at(0)->value.isString())
+ COMPILE_EXCEPTION(source, "Invalid Script source value");
+
+ QString sourceUrl =
+ output->url.resolved(QUrl(source->values.at(0)->value.asString())).toString();
+
+ for (int ii = 0; ii < unit->resources.count(); ++ii) {
+ if (unit->resources.at(ii)->url == sourceUrl) {
+ scriptCode = QString::fromUtf8(unit->resources.at(ii)->data);
+ break;
+ }
+ }
+
+ } else if (!script->properties.isEmpty()) {
+ COMPILE_EXCEPTION(*script->properties.begin(), "Properties cannot be set on Script block");
+ } else if (script->defaultProperty) {
+ QmlParser::Location currentLocation;
+
+ for (int ii = 0; ii < script->defaultProperty->values.count(); ++ii) {
+ Value *v = script->defaultProperty->values.at(ii);
+ if (v->object || !v->value.isString())
+ COMPILE_EXCEPTION(v, "Invalid Script block");
+
+ if (ii == 0) {
+ currentLocation = v->location.start;
+ scriptCode.append(QString(currentLocation.column, QLatin1Char(' ')));
+ }
+
+ while (currentLocation.line < v->location.start.line) {
+ scriptCode.append(QLatin1String("\n"));
+ currentLocation.line++;
+ currentLocation.column = 0;
+ }
+
+ scriptCode.append(QString(v->location.start.column - currentLocation.column, QLatin1Char(' ')));
+
+ scriptCode += v->value.asString();
+ currentLocation = v->location.end;
+ currentLocation.column++;
+ }
+ }
+
+ if (!scriptCode.isEmpty())
+ obj->scriptBlocks.append(scriptCode);
+
+ return true;
+}
+
bool QmlCompiler::buildComponentFromRoot(QmlParser::Object *obj,
const BindingContext &ctxt)
{
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index fd361fd..1d27342 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -171,6 +171,7 @@ private:
bool buildObject(QmlParser::Object *obj, const BindingContext &);
+ bool buildScript(QmlParser::Object *obj, QmlParser::Object *script);
bool buildComponent(QmlParser::Object *obj, const BindingContext &);
bool buildSubObject(QmlParser::Object *obj, const BindingContext &);
bool buildSignal(QmlParser::Property *prop, QmlParser::Object *obj,
diff --git a/src/declarative/qml/qmlcompositetypedata_p.h b/src/declarative/qml/qmlcompositetypedata_p.h
index 48c6c2b..fa11137 100644
--- a/src/declarative/qml/qmlcompositetypedata_p.h
+++ b/src/declarative/qml/qmlcompositetypedata_p.h
@@ -58,6 +58,7 @@
QT_BEGIN_NAMESPACE
+class QmlCompositeTypeResource;
class QmlCompositeTypeData : public QmlRefCount
{
public:
@@ -101,6 +102,7 @@ public:
};
QList<TypeReference> types;
+ QList<QmlCompositeTypeResource *> resources;
// Add or remove p as a waiter. When the QmlCompositeTypeData becomes
// ready, the QmlComponentPrivate::typeDataReady() method will be invoked on
@@ -122,5 +124,25 @@ private:
QmlCompiledData *compiledComponent;
};
+class QmlCompositeTypeResource : public QmlRefCount
+{
+public:
+ QmlCompositeTypeResource();
+ virtual ~QmlCompositeTypeResource();
+
+ enum Status {
+ Invalid,
+ Complete,
+ Error,
+ Waiting
+ };
+ Status status;
+
+ QList<QmlCompositeTypeData *> dependants;
+
+ QString url;
+ QByteArray data;
+};
+
#endif // QMLCOMPOSITETYPEDATA_P_H
diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp
index a99cff0..71b4ef0 100644
--- a/src/declarative/qml/qmlcompositetypemanager.cpp
+++ b/src/declarative/qml/qmlcompositetypemanager.cpp
@@ -63,6 +63,9 @@ QmlCompositeTypeData::~QmlCompositeTypeData()
for (int ii = 0; ii < dependants.count(); ++ii)
dependants.at(ii)->release();
+ for (int ii = 0; ii < resources.count(); ++ii)
+ resources.at(ii)->release();
+
if (compiledComponent)
compiledComponent->release();
@@ -70,6 +73,16 @@ QmlCompositeTypeData::~QmlCompositeTypeData()
delete component;
}
+QmlCompositeTypeResource::QmlCompositeTypeResource()
+{
+}
+
+QmlCompositeTypeResource::~QmlCompositeTypeResource()
+{
+ for (int ii = 0; ii < dependants.count(); ++ii)
+ dependants.at(ii)->release();
+}
+
void QmlCompositeTypeData::addWaiter(QmlComponentPrivate *p)
{
waiters << p;
@@ -142,6 +155,10 @@ QmlCompositeTypeManager::~QmlCompositeTypeManager()
(*iter)->release();
iter = components.erase(iter);
}
+ for (Resources::Iterator iter = resources.begin(); iter != resources.end();) {
+ (*iter)->release();
+ iter = resources.erase(iter);
+ }
}
QmlCompositeTypeData *QmlCompositeTypeManager::get(const QUrl &url)
@@ -181,8 +198,16 @@ void QmlCompositeTypeManager::clearCache()
++iter;
}
}
-}
+ for (Resources::Iterator iter = resources.begin(); iter != resources.end();) {
+ if ((*iter)->status != QmlCompositeTypeResource::Waiting) {
+ (*iter)->release();
+ iter = resources.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+}
void QmlCompositeTypeManager::replyFinished()
{
@@ -215,6 +240,52 @@ void QmlCompositeTypeManager::replyFinished()
reply->deleteLater();
}
+void QmlCompositeTypeManager::resourceReplyFinished()
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+
+ QmlCompositeTypeResource *resource = resources.value(reply->url().toString());
+ Q_ASSERT(resource);
+
+ if (reply->error() != QNetworkReply::NoError) {
+
+ resource->status = QmlCompositeTypeResource::Error;
+
+ } else {
+
+ resource->status = QmlCompositeTypeResource::Complete;
+ resource->data = reply->readAll();
+
+ }
+
+ doComplete(resource);
+ reply->deleteLater();
+}
+
+void QmlCompositeTypeManager::loadResource(QmlCompositeTypeResource *resource)
+{
+ QUrl url(resource->url);
+
+ if (url.scheme() == QLatin1String("file")) {
+
+ QFile file(url.toLocalFile());
+ if (file.open(QFile::ReadOnly)) {
+ resource->data = file.readAll();
+ resource->status = QmlCompositeTypeResource::Complete;
+ } else {
+ resource->status = QmlCompositeTypeResource::Error;
+ }
+
+ } else {
+
+ QNetworkReply *reply =
+ engine->networkAccessManager()->get(QNetworkRequest(url));
+ QObject::connect(reply, SIGNAL(finished()),
+ this, SLOT(resourceReplyFinished()));
+
+ }
+}
+
void QmlCompositeTypeManager::loadSource(QmlCompositeTypeData *unit)
{
QUrl url(unit->imports.baseUrl());
@@ -308,6 +379,15 @@ void QmlCompositeTypeManager::doComplete(QmlCompositeTypeData *unit)
}
}
+void QmlCompositeTypeManager::doComplete(QmlCompositeTypeResource *resource)
+{
+ for (int ii = 0; ii < resource->dependants.count(); ++ii) {
+ checkComplete(resource->dependants.at(ii));
+ resource->dependants.at(ii)->release();
+ }
+ resource->dependants.clear();
+}
+
void QmlCompositeTypeManager::checkComplete(QmlCompositeTypeData *unit)
{
if (unit->status != QmlCompositeTypeData::Waiting)
@@ -329,12 +409,33 @@ void QmlCompositeTypeManager::checkComplete(QmlCompositeTypeData *unit)
waiting++;
}
}
+ for (int ii = 0; ii < unit->resources.count(); ++ii) {
+ QmlCompositeTypeResource *r = unit->resources.at(ii);
+
+ if (!r)
+ continue;
+
+ if (r->status == QmlCompositeTypeResource::Error) {
+ unit->status = QmlCompositeTypeData::Error;
+ QmlError error;
+ error.setUrl(unit->imports.baseUrl());
+ error.setDescription(QLatin1String("Resource ") + r->url +
+ QLatin1String(" unavailable"));
+ unit->errors << error;
+ doComplete(unit);
+ return;
+ } else if (r->status == QmlCompositeTypeData::Waiting) {
+ waiting++;
+ }
+ }
+
if (!waiting) {
unit->status = QmlCompositeTypeData::Complete;
doComplete(unit);
}
}
+// ### Check ref counting in here
void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit)
{
QList<QmlScriptParser::TypeReference*> types = unit->data.referencedTypes();
@@ -346,12 +447,6 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit)
QmlCompositeTypeData::TypeReference ref;
- if (typeName == QByteArray("Property") ||
- typeName == QByteArray("Signal")) {
- unit->types << ref;
- continue;
- }
-
QUrl url;
int majorVersion;
int minorVersion;
@@ -431,6 +526,49 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit)
unit->types << ref;
}
+ QList<QUrl> resourceList = unit->data.referencedResources();
+ for (int ii = 0; ii < resourceList.count(); ++ii) {
+ QUrl url = unit->imports.baseUrl().resolved(resourceList.at(ii));
+
+ QmlCompositeTypeResource *resource = resources.value(url.toString());
+
+ if (!resource) {
+ resource = new QmlCompositeTypeResource;
+ resource->status = QmlCompositeTypeResource::Waiting;
+ resource->url = url.toString();
+ resources.insert(resource->url, resource);
+
+ loadResource(resource);
+ }
+
+ switch(resource->status) {
+ case QmlCompositeTypeResource::Invalid:
+ case QmlCompositeTypeResource::Error:
+ unit->status = QmlCompositeTypeData::Error;
+ {
+ QmlError error;
+ error.setUrl(unit->imports.baseUrl());
+ error.setDescription(QLatin1String("Resource ") + resource->url +
+ QLatin1String(" unavailable"));
+ unit->errors << error;
+ }
+ doComplete(unit);
+ return;
+
+ case QmlCompositeTypeData::Complete:
+ break;
+
+ case QmlCompositeTypeData::Waiting:
+ unit->addref();
+ resource->dependants << unit;
+ waiting++;
+ break;
+ }
+
+ resource->addref();
+ unit->resources << resource;
+ }
+
if (waiting) {
unit->status = QmlCompositeTypeData::Waiting;
} else {
diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h
index 8f16998..843a9cf 100644
--- a/src/declarative/qml/qmlcompositetypemanager_p.h
+++ b/src/declarative/qml/qmlcompositetypemanager_p.h
@@ -67,6 +67,7 @@ class QmlComponent;
class QmlDomDocument;
class QmlCompositeTypeData;
+class QmlCompositeTypeResource;
class QmlCompositeTypeManager : public QObject
{
@@ -88,19 +89,24 @@ public:
private Q_SLOTS:
void replyFinished();
+ void resourceReplyFinished();
void requestProgress(qint64 received, qint64 total);
private:
void loadSource(QmlCompositeTypeData *);
+ void loadResource(QmlCompositeTypeResource *);
void compile(QmlCompositeTypeData *);
void setData(QmlCompositeTypeData *, const QByteArray &, const QUrl &);
void doComplete(QmlCompositeTypeData *);
+ void doComplete(QmlCompositeTypeResource *);
void checkComplete(QmlCompositeTypeData *);
QmlEngine *engine;
typedef QHash<QString, QmlCompositeTypeData *> Components;
Components components;
+ typedef QHash<QString, QmlCompositeTypeResource *> Resources;
+ Resources resources;
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp
index a1eb5de..549925f 100644
--- a/src/declarative/qml/qmlcontext.cpp
+++ b/src/declarative/qml/qmlcontext.cpp
@@ -48,6 +48,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qdebug.h>
#include <private/qmlbindingoptimizations_p.h>
+#include <QtDeclarative/qmlinfo.h>
// 6-bits
#define MAXIMUM_DEFAULT_OBJECTS 63
@@ -60,6 +61,44 @@ QmlContextPrivate::QmlContextPrivate()
{
}
+void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject)
+{
+ if (!engine)
+ return;
+
+ QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine);
+ QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);
+
+ QScriptContext *scriptContext = scriptEngine->pushCleanContext();
+ scriptContext->pushScope(scriptValue);
+
+ if (scopeObject)
+ scriptContext->pushScope(enginePriv->objectClass->newQObject(scopeObject));
+
+ QScriptValue scope = scriptEngine->newObject();
+ scriptContext->setActivationObject(scope);
+
+ QScriptValue val = scriptEngine->evaluate(script);
+
+ if (scriptEngine->hasUncaughtException()) {
+ if (scriptEngine->uncaughtException().isError()){
+ QScriptValue exception = scriptEngine->uncaughtException();
+ if (!exception.property(QLatin1String("fileName")).toString().isEmpty()){
+ qWarning() << exception.property(QLatin1String("fileName")).toString()
+ << scriptEngine->uncaughtExceptionLineNumber()
+ << exception.toString();
+
+ } else {
+ qmlInfo(scopeObject) << exception.toString();
+ }
+ }
+ }
+
+ scriptEngine->popContext();
+
+ scripts.append(scope);
+}
+
void QmlContextPrivate::dump()
{
dump(0);
diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h
index 22e5895..d18bfda 100644
--- a/src/declarative/qml/qmlcontext_p.h
+++ b/src/declarative/qml/qmlcontext_p.h
@@ -94,6 +94,7 @@ public:
QScriptValue scriptValue;
QList<QScriptValue> scripts;
+ void addScript(const QString &script, QObject *scope);
QUrl url;
diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h
index 38b3191..1dcdace 100644
--- a/src/declarative/qml/qmlinstruction_p.h
+++ b/src/declarative/qml/qmlinstruction_p.h
@@ -118,6 +118,7 @@ public:
StoreInterface, /* storeObject */
StoreSignal, /* storeSignal */
+ StoreScript, /* storeScript */
//
// Unresolved single assignment
@@ -238,6 +239,9 @@ public:
int value;
} storeString;
struct {
+ int value;
+ } storeScript;
+ struct {
int propertyIndex;
int value;
} storeUrl;
diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp
index 155b34a..302ce8c 100644
--- a/src/declarative/qml/qmlmetaproperty.cpp
+++ b/src/declarative/qml/qmlmetaproperty.cpp
@@ -564,7 +564,7 @@ QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding) const
if (!isProperty() || (type() & Attached) || !d->object)
return 0;
- d->setBinding(d->object, d->core, newBinding);
+ return d->setBinding(d->object, d->core, newBinding);
}
QmlAbstractBinding *
diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp
index 39fe1e2..8c46939 100644
--- a/src/declarative/qml/qmlparser.cpp
+++ b/src/declarative/qml/qmlparser.cpp
@@ -82,6 +82,8 @@ QmlParser::Object::~Object()
prop->release();
foreach(const DynamicProperty &prop, dynamicProperties)
if (prop.defaultValue) prop.defaultValue->release();
+ foreach(Object *obj, scriptBlockObjects)
+ obj->release();
}
void Object::setBindingBit(int b)
diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h
index e0579b0..16862eb 100644
--- a/src/declarative/qml/qmlparser_p.h
+++ b/src/declarative/qml/qmlparser_p.h
@@ -151,6 +151,8 @@ namespace QmlParser
Property *defaultProperty;
QHash<QByteArray, Property *> properties;
+ QList<Object *> scriptBlockObjects;
+
// Output of the compilation phase (these properties continue to exist
// in either the defaultProperty or properties members too)
void addValueProperty(Property *);
@@ -164,6 +166,9 @@ namespace QmlParser
QList<Property *> groupedProperties;
QList<Property *> valueTypeProperties;
+ // Script blocks that were nested under this object
+ QStringList scriptBlocks;
+
// The bytes to cast instances by to get to the QmlParserStatus
// interface. -1 indicates the type doesn't support this interface.
// Set by the QmlCompiler.
diff --git a/src/declarative/util/qmlscript.h b/src/declarative/qml/qmlscript.cpp
index 4ba4f6b..307d72f 100644
--- a/src/declarative/util/qmlscript.h
+++ b/src/declarative/qml/qmlscript.cpp
@@ -39,46 +39,44 @@
**
****************************************************************************/
-#ifndef QMLSCRIPT_H
-#define QMLSCRIPT_H
+// This is just a dummy file to include the documentation
-#include <QtDeclarative/qfxglobal.h>
-#include <QtCore/qobject.h>
-#include <QtDeclarative/qml.h>
+/*!
+ \qmlclass Script QmlScript
+ \brief The Script element adds JavaScript snippets.
+ \ingroup group_utility
-QT_BEGIN_HEADER
+ QmlScript is used to add convenient JavaScript "glue" methods to
+ your Qt Declarative application or component. While you can have any JavaScript code
+ within a QmlScript, it is best to limit yourself to defining functions.
-QT_BEGIN_NAMESPACE
+ \qml
+ Script {
+ function debugMyComponent() {
+ print(text.text);
+ print(otherinterestingitem.property);
+ }
+ }
+ MouseRegion { onClicked: debugMyComponent() }
+ \endqml
-QT_MODULE(Declarative)
+ \note QmlScript executes JavaScript as soon as it is specified.
+ When defining a component, this may be before the execution context is
+ fully specified. As a result some properties or items may not be
+ accessible. By limiting your JavaScript to defining functions that are
+ only executed later once the context is fully defined, this problem is
+ avoided.
+*/
-class QmlScriptPrivate;
-class Q_DECLARATIVE_EXPORT QmlScript : public QObject
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QmlScript)
+/*!
+ \qmlproperty string Script::script
+ \default
+ JavaScript code to execute.
+*/
- Q_PROPERTY(QString script READ script WRITE setScript)
- Q_PROPERTY(QUrl source READ source WRITE setSource)
- Q_CLASSINFO("DefaultProperty", "script")
+/*!
+ \qmlproperty url Script::source
-public:
- QmlScript(QObject *parent=0);
-
- QString script() const;
- void setScript(const QString &);
-
- QUrl source() const;
- void setSource(const QUrl &);
-
-private Q_SLOTS:
- void replyFinished();
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QmlScript)
-
-QT_END_HEADER
-
-#endif
+ Setting this property causes the Script element to read JavaScript code from
+ the file specified.
+*/
diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp
index c126830..1c7bf83 100644
--- a/src/declarative/qml/qmlscriptparser.cpp
+++ b/src/declarative/qml/qmlscriptparser.cpp
@@ -289,12 +289,26 @@ ProcessAST::defineObjectBinding_helper(AST::UiQualifiedId *propertyName,
if (lastTypeDot >= 0)
resolvableObjectType.replace(QLatin1Char('.'),QLatin1Char('/'));
- QmlScriptParser::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType);
+ bool isScript = resolvableObjectType == QLatin1String("Script");
+
+ if (isScript) {
+ if (_stateStack.isEmpty() || _stateStack.top().property) {
+ QmlError error;
+ error.setDescription(QLatin1String("Invalid use of Script block"));
+ error.setLine(typeLocation.startLine);
+ error.setColumn(typeLocation.startColumn);
+ _parser->_errors << error;
+ }
+ }
Object *obj = new Object;
- obj->type = typeRef->id;
- typeRef->refObjects.append(obj);
+ if (!isScript) {
+ QmlScriptParser::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType);
+ obj->type = typeRef->id;
+
+ typeRef->refObjects.append(obj);
+ }
// XXX this doesn't do anything (_scope never builds up)
_scope.append(resolvableObjectType);
@@ -303,7 +317,11 @@ ProcessAST::defineObjectBinding_helper(AST::UiQualifiedId *propertyName,
obj->location = location;
- if (propertyCount) {
+ if (isScript) {
+
+ _stateStack.top().object->scriptBlockObjects.append(obj);
+
+ } else if (propertyCount) {
Property *prop = currentProperty();
Value *v = new Value;
@@ -385,6 +403,26 @@ Object *ProcessAST::defineObjectBinding(AST::UiQualifiedId *qualifiedId,
_stateStack.pop(); // object
return obj;
+ } else if (objectType == QLatin1String("Script")) {
+
+ AST::UiObjectMemberList *it = initializer->members;
+ for (; it; it = it->next) {
+ AST::UiScriptBinding *scriptBinding = AST::cast<AST::UiScriptBinding *>(it->member);
+ if (! scriptBinding)
+ continue;
+
+ QString propertyName = asString(scriptBinding->qualifiedId);
+ if (propertyName == QLatin1String("source")) {
+ if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(scriptBinding->statement)) {
+ AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(stmt->expression);
+ if (string) {
+ // We need to add this as a resource
+ _parser->_refUrls << QUrl(string->value->asString());
+ }
+ }
+ }
+ }
+
}
return defineObjectBinding_helper(qualifiedId, objectType, typeLocation, location, initializer);
@@ -867,6 +905,11 @@ QList<QmlScriptParser::TypeReference*> QmlScriptParser::referencedTypes() const
return _refTypes;
}
+QList<QUrl> QmlScriptParser::referencedResources() const
+{
+ return _refUrls;
+}
+
Object *QmlScriptParser::tree() const
{
return root;
diff --git a/src/declarative/qml/qmlscriptparser_p.h b/src/declarative/qml/qmlscriptparser_p.h
index d489610..b25d6bf 100644
--- a/src/declarative/qml/qmlscriptparser_p.h
+++ b/src/declarative/qml/qmlscriptparser_p.h
@@ -102,6 +102,7 @@ public:
bool parse(const QByteArray &data, const QUrl &url = QUrl());
QList<TypeReference*> referencedTypes() const;
+ QList<QUrl> referencedResources() const;
QmlParser::Object *tree() const;
QList<Import> imports() const;
@@ -123,6 +124,7 @@ public:
QmlParser::Object *root;
QList<Import> _imports;
QList<TypeReference*> _refTypes;
+ QList<QUrl> _refUrls;
QString _scriptFile;
QmlScriptParserJsASTData *data;
};
diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index 4ba412b..e4eef64 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -564,6 +564,13 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt,
}
break;
+ case QmlInstruction::StoreScript:
+ {
+ QObject *target = stack.top();
+ cp->addScript(primitives.at(instr.storeScript.value), target);
+ }
+ break;
+
case QmlInstruction::BeginObject:
{
QObject *target = stack.top();
diff --git a/src/declarative/util/qmlscript.cpp b/src/declarative/util/qmlscript.cpp
deleted file mode 100644
index 5d58f64..0000000
--- a/src/declarative/util/qmlscript.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Qt Software Information (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain
-** additional rights. These rights are described in the Nokia Qt LGPL
-** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtDeclarative/qmlengine.h>
-#include <QtDeclarative/qmlcontext.h>
-#include <private/qobject_p.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qdebug.h>
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptcontext.h>
-#include <QtScript/qscriptengine.h>
-#include <private/qmlnullablevalue_p.h>
-#include <private/qmlengine_p.h>
-#include <private/qmlcontext_p.h>
-#include "qmlscript.h"
-#include <QNetworkReply>
-#include <QNetworkRequest>
-#include <QtDeclarative/qmlinfo.h>
-#include <private/qfxperf_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QmlScriptPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QmlScript);
-
-public:
- QmlScriptPrivate() : reply(0) {}
-
- void addScriptToEngine(const QString &, const QString &source=QString());
-
- QString script;
- QNetworkReply *reply;
- QUrl url;
-};
-
-/*!
- \qmlclass Script QmlScript
- \brief The Script element adds JavaScript snippets.
- \ingroup group_utility
-
- QmlScript is used to add convenient JavaScript "glue" methods to
- your Qt Declarative application or component. While you can have any JavaScript code
- within a QmlScript, it is best to limit yourself to defining functions.
-
- \qml
- Script {
- function debugMyComponent() {
- print(text.text);
- print(otherinterestingitem.property);
- }
- }
- MouseRegion { onClicked: debugMyComponent() }
- \endqml
-
- \note QmlScript executes JavaScript as soon as it is specified.
- When defining a component, this may be before the execution context is
- fully specified. As a result some properties or items may not be
- accessible. By limiting your JavaScript to defining functions that are
- only executed later once the context is fully defined, this problem is
- avoided.
-*/
-
-QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Script,QmlScript)
-QmlScript::QmlScript(QObject *parent) : QObject(*(new QmlScriptPrivate), parent)
-{
-}
-
-/*!
- \qmlproperty string Script::script
- \default
- JavaScript code to execute.
-*/
-QString QmlScript::script() const
-{
- Q_D(const QmlScript);
- return d->script;
-}
-
-void QmlScript::setScript(const QString &script)
-{
- Q_D(QmlScript);
- d->script = script;
- d->addScriptToEngine(d->script);
-}
-
-/*!
- \qmlproperty url Script::source
-
- Setting this property causes the Script element to read JavaScript code from
- the file specified.
-*/
-QUrl QmlScript::source() const
-{
- Q_D(const QmlScript);
- return d->url;
-}
-
-void QmlScript::setSource(const QUrl &source)
-{
- Q_D(QmlScript);
- if (d->url == source)
- return;
- d->url = qmlContext(this)->resolvedUrl(source);
-
-#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
- if (d->url.scheme() == QLatin1String("file")) {
- QFile file(d->url.toLocalFile());
- file.open(QIODevice::ReadOnly);
- QByteArray ba = file.readAll();
- d->addScriptToEngine(QString::fromUtf8(ba), file.fileName());
- } else
-#endif
- {
- QNetworkRequest req(d->url);
- d->reply = qmlEngine(this)->networkAccessManager()->get(req);
- QObject::connect(d->reply, SIGNAL(finished()),
- this, SLOT(replyFinished()));
- }
-}
-
-void QmlScript::replyFinished()
-{
- Q_D(QmlScript);
- if (!d->reply->error()) {
- QByteArray ba = d->reply->readAll();
- d->addScriptToEngine(QString::fromUtf8(ba), d->url.toString());
- }
- d->reply->deleteLater();
- d->reply = 0;
-}
-
-void QmlScriptPrivate::addScriptToEngine(const QString &script, const QString &source)
-{
-#ifdef Q_ENABLE_PERFORMANCE_LOG
- QFxPerfTimer<QFxPerf::AddScript> pt;
-#endif
- Q_Q(QmlScript);
- QmlEngine *engine = qmlEngine(q);
- QmlContext *context = qmlContext(q);
- QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);
-
- QScriptContext *scriptContext = scriptEngine->pushCleanContext();
- scriptContext->pushScope(QmlContextPrivate::get(context)->scriptValue);
-
- QScriptValue scope = scriptEngine->newObject();
- scriptContext->pushScope(scope);
-
- scriptContext->setActivationObject(scope);
-
- QScriptValue val = scriptEngine->evaluate(script, source);
- if (scriptEngine->hasUncaughtException()) {
- if (scriptEngine->uncaughtException().isError()){
- QScriptValue exception = scriptEngine->uncaughtException();
- if (!exception.property(QLatin1String("fileName")).toString().isEmpty()){
- qWarning() << exception.property(QLatin1String("fileName")).toString()
- << scriptEngine->uncaughtExceptionLineNumber()
- << exception.toString();
-
- } else {
- qmlInfo(q) << exception.toString();
- }
- }
- }
-
- scriptEngine->popContext();
-
- context->d_func()->scripts.append(scope);
-}
-
-QT_END_NAMESPACE
diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri
index 41c9019..ec9967c 100644
--- a/src/declarative/util/util.pri
+++ b/src/declarative/util/util.pri
@@ -4,7 +4,6 @@ SOURCES += \
util/qperformancelog.cpp \
util/qmlconnection.cpp \
util/qmlpackage.cpp \
- util/qmlscript.cpp \
util/qmlanimation.cpp \
util/qmlsystempalette.cpp \
util/qmlspringfollow.cpp \
@@ -29,7 +28,6 @@ HEADERS += \
util/qperformancelog_p.h \
util/qmlconnection.h \
util/qmlpackage.h \
- util/qmlscript.h \
util/qmlanimation.h \
util/qmlanimation_p.h \
util/qmlsystempalette.h \