summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml
diff options
context:
space:
mode:
authorWarwick Allison <warwick.allison@nokia.com>2009-07-09 07:10:11 (GMT)
committerWarwick Allison <warwick.allison@nokia.com>2009-07-09 07:10:11 (GMT)
commit5b56189c9a6c322fa595b716a9f17e39a35bcbc0 (patch)
tree2e8b4fc397d631207aa32a8c68c94100a54f0f61 /src/declarative/qml
parent888f57107e698731c4a1dd2c46745c6293b2222e (diff)
parent7343bbb230161d563b0226011e4519f695fdc593 (diff)
downloadQt-5b56189c9a6c322fa595b716a9f17e39a35bcbc0.zip
Qt-5b56189c9a6c322fa595b716a9f17e39a35bcbc0.tar.gz
Qt-5b56189c9a6c322fa595b716a9f17e39a35bcbc0.tar.bz2
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Conflicts: src/declarative/qml/qmlengine.cpp
Diffstat (limited to 'src/declarative/qml')
-rw-r--r--src/declarative/qml/qml.h6
-rw-r--r--src/declarative/qml/qml.pri2
-rw-r--r--src/declarative/qml/qmlbasicscript.cpp34
-rw-r--r--src/declarative/qml/qmlbindablevalue.cpp2
-rw-r--r--src/declarative/qml/qmlcompiler.cpp179
-rw-r--r--src/declarative/qml/qmlcompiler_p.h17
-rw-r--r--src/declarative/qml/qmlcomponent.cpp30
-rw-r--r--src/declarative/qml/qmlcomponent.h5
-rw-r--r--src/declarative/qml/qmlcontext.cpp4
-rw-r--r--src/declarative/qml/qmlcontext.h1
-rw-r--r--src/declarative/qml/qmlengine.cpp625
-rw-r--r--src/declarative/qml/qmlengine.h6
-rw-r--r--src/declarative/qml/qmlengine_p.h78
-rw-r--r--src/declarative/qml/qmlexpression.cpp624
-rw-r--r--src/declarative/qml/qmlexpression.h2
-rw-r--r--src/declarative/qml/qmlexpression_p.h138
-rw-r--r--src/declarative/qml/qmlinstruction_p.h1
-rw-r--r--src/declarative/qml/qmlmetaproperty.cpp7
-rw-r--r--src/declarative/qml/qmlparser.cpp4
-rw-r--r--src/declarative/qml/qmlparser_p.h3
-rw-r--r--src/declarative/qml/qmlscriptparser.cpp23
-rw-r--r--src/declarative/qml/qmlvme.cpp5
-rw-r--r--src/declarative/qml/qmlvmemetaobject.cpp227
-rw-r--r--src/declarative/qml/qmlvmemetaobject_p.h50
-rw-r--r--src/declarative/qml/rewriter/rewriter.cpp9
-rw-r--r--src/declarative/qml/rewriter/rewriter_p.h3
26 files changed, 1296 insertions, 789 deletions
diff --git a/src/declarative/qml/qml.h b/src/declarative/qml/qml.h
index 1990b7f..cd01f6a 100644
--- a/src/declarative/qml/qml.h
+++ b/src/declarative/qml/qml.h
@@ -93,10 +93,10 @@ class QmlEngine;
Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *);
Q_DECLARATIVE_EXPORT QmlContext *qmlContext(const QObject *);
Q_DECLARATIVE_EXPORT QmlEngine *qmlEngine(const QObject *);
-Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *);
+Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
template<typename T>
-QObject *qmlAttachedPropertiesObject(const QObject *obj)
+QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
{
// ### is this threadsafe?
static int idx = -1;
@@ -107,7 +107,7 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj)
if (idx == -1 || !obj)
return 0;
- return qmlAttachedPropertiesObjectById(idx, obj);
+ return qmlAttachedPropertiesObjectById(idx, obj, create);
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index efe4d3f..fa09935 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -2,6 +2,7 @@ SOURCES += qml/qmlparser.cpp \
qml/qmlinstruction.cpp \
qml/qmlvmemetaobject.cpp \
qml/qmlengine.cpp \
+ qml/qmlexpression.cpp \
qml/qmlbindablevalue.cpp \
qml/qmlmetaproperty.cpp \
qml/qmlcomponent.cpp \
@@ -45,6 +46,7 @@ HEADERS += qml/qmlparser_p.h \
qml/qmlvme_p.h \
qml/qmlcompiler_p.h \
qml/qmlengine_p.h \
+ qml/qmlexpression_p.h \
qml/qmlprivate.h \
qml/qmldom.h \
qml/qmldom_p.h \
diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp
index 8b0cb42..478491f 100644
--- a/src/declarative/qml/qmlbasicscript.cpp
+++ b/src/declarative/qml/qmlbasicscript.cpp
@@ -45,7 +45,7 @@
#include <private/qmlengine_p.h>
#include <private/qmlcontext_p.h>
#include <QStack>
-#include <qfxperf.h>
+#include <private/qfxperf_p.h>
#include <private/qmlrefcount_p.h>
#include <private/qmljsast_p.h>
#include <private/qmljsengine_p.h>
@@ -603,7 +603,10 @@ bool QmlBasicScriptCompiler::parseName(AST::Node *node,
instr.type = ScriptInstruction::FetchD0Constant;
instr.constant.idx = d0Idx;
QMetaProperty prop = context->metaObject()->property(d0Idx);
- instr.constant.notify = prop.notifySignalIndex();
+ if (prop.isConstant())
+ instr.constant.notify = 0;
+ else
+ instr.constant.notify = prop.notifySignalIndex();
instr.constant.type = prop.userType();
} else if (d1Idx != -1) {
@@ -611,7 +614,10 @@ bool QmlBasicScriptCompiler::parseName(AST::Node *node,
instr.type = ScriptInstruction::FetchD1Constant;
instr.constant.idx = d1Idx;
QMetaProperty prop = component->metaObject()->property(d1Idx);
- instr.constant.notify = prop.notifySignalIndex();
+ if (prop.isConstant())
+ instr.constant.notify = 0;
+ else
+ instr.constant.notify = prop.notifySignalIndex();
instr.constant.type = prop.userType();
} else {
@@ -635,7 +641,10 @@ bool QmlBasicScriptCompiler::parseName(AST::Node *node,
instr.type = ScriptInstruction::FetchConstant;
instr.constant.idx = idx;
QMetaProperty prop = loadedType->metaObject()->property(idx);
- instr.constant.notify = prop.notifySignalIndex();
+ if (prop.isConstant())
+ instr.constant.notify = 0;
+ else
+ instr.constant.notify = prop.notifySignalIndex();
instr.constant.type = prop.userType();
} else {
int nref = data.count();
@@ -804,7 +813,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c
{
stack.push(contextPrivate->propertyValues.at(instr.fetch.idx));
enginePrivate->capturedProperties <<
- QmlEnginePrivate::CapturedProperty(context, contextPrivate->notifyIndex + instr.fetch.idx);
+ QmlEnginePrivate::CapturedProperty(context, -1, contextPrivate->notifyIndex + instr.fetch.idx);
state = Reset;
}
break;
@@ -814,8 +823,9 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c
QObject *obj = contextPrivate->defaultObjects.at(0);
stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type));
- enginePrivate->capturedProperties <<
- QmlEnginePrivate::CapturedProperty(obj, instr.constant.notify);
+ if (instr.constant.notify != 0)
+ enginePrivate->capturedProperties <<
+ QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify);
state = Reset;
}
break;
@@ -825,8 +835,9 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c
QObject *obj = contextPrivate->defaultObjects.at(1);
stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type));
- enginePrivate->capturedProperties <<
- QmlEnginePrivate::CapturedProperty(obj, instr.constant.notify);
+ if (instr.constant.notify != 0)
+ enginePrivate->capturedProperties <<
+ QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify);
state = Reset;
}
break;
@@ -837,8 +848,9 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c
QObject *obj = qvariant_cast<QObject *>(o);
stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type));
- enginePrivate->capturedProperties <<
- QmlEnginePrivate::CapturedProperty(obj, instr.constant.notify);
+ if (instr.constant.notify != 0)
+ enginePrivate->capturedProperties <<
+ QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify);
state = Reset;
}
break;
diff --git a/src/declarative/qml/qmlbindablevalue.cpp b/src/declarative/qml/qmlbindablevalue.cpp
index ef9eb55..6dda5e3 100644
--- a/src/declarative/qml/qmlbindablevalue.cpp
+++ b/src/declarative/qml/qmlbindablevalue.cpp
@@ -45,7 +45,7 @@
#include <qmlcontext.h>
#include <qmlinfo.h>
#include <QVariant>
-#include <qfxperf.h>
+#include <private/qfxperf_p.h>
#include <QtCore/qdebug.h>
Q_DECLARE_METATYPE(QList<QObject *>);
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index 47f69a0..b04c932 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -40,7 +40,7 @@
****************************************************************************/
#include "private/qmlcompiler_p.h"
-#include <qfxperf.h>
+#include <private/qfxperf_p.h>
#include "qmlparser_p.h"
#include "private/qmlscriptparser_p.h"
#include <qmlpropertyvaluesource.h>
@@ -63,6 +63,7 @@
#include <private/qmlcontext_p.h>
#include <private/qmlcomponent_p.h>
#include "parser/qmljsast_p.h"
+#include <private/qmlvmemetaobject_p.h>
#include "qmlscriptparser_p.h"
@@ -554,17 +555,18 @@ void QmlCompiler::compileTree(Object *tree)
if (!compileObject(tree, 0)) // Compile failed
return;
- if (tree->metatype)
- static_cast<QMetaObject &>(output->root) = *tree->metaObject();
- else
- static_cast<QMetaObject &>(output->root) = *output->types.at(tree->type).metaObject();
-
QmlInstruction def;
init.line = 0;
def.type = QmlInstruction::SetDefault;
output->bytecode << def;
finalizeComponent(0);
+
+ if (tree->metatype)
+ static_cast<QMetaObject &>(output->root) = *tree->metaObject();
+ else
+ static_cast<QMetaObject &>(output->root) = *output->types.at(tree->type).metaObject();
+
}
bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt)
@@ -798,13 +800,12 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, const BindingContext &ct
if (obj)
COMPILE_CHECK(compileObject(obj, ctxt));
- finalizeComponent(count);
+ COMPILE_CHECK(finalizeComponent(count));
create.createComponent.count = output->bytecode.count() - count;
compileState = oldComponentCompileState;
return true;
}
-
bool QmlCompiler::compileFetchedObject(Object *obj, const BindingContext &ctxt)
{
Q_ASSERT(obj->metatype);
@@ -1398,7 +1399,7 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop,
return true;
}
-bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj)
+bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias)
{
// ### FIXME - Check that there is only one default property etc.
if (obj->dynamicProperties.isEmpty() &&
@@ -1406,49 +1407,81 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj)
obj->dynamicSlots.isEmpty())
return true;
+ QByteArray dynamicData(sizeof(QmlVMEMetaData), (char)0);
+
QMetaObjectBuilder builder;
if (obj->metatype)
builder.setClassName(QByteArray(obj->metatype->className()) + "QML");
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+ bool hasAlias = false;
for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
- if (p.isDefaultProperty)
+ if (p.isDefaultProperty &&
+ (p.type != Object::DynamicProperty::Alias || preAlias != -1))
builder.addClassInfo("DefaultProperty", p.name);
QByteArray type;
+ int propertyType;
switch(p.type) {
+ case Object::DynamicProperty::Alias:
+ hasAlias = true;
+ continue;
+ break;
case Object::DynamicProperty::Variant:
+ propertyType = -1;
type = "QVariant";
break;
case Object::DynamicProperty::Int:
+ propertyType = QVariant::Int;
type = "int";
break;
case Object::DynamicProperty::Bool:
+ propertyType = QVariant::Bool;
type = "bool";
break;
case Object::DynamicProperty::Real:
+ propertyType = QVariant::Double;
type = "double";
break;
case Object::DynamicProperty::String:
+ propertyType = QVariant::String;
type = "QString";
break;
case Object::DynamicProperty::Url:
+ propertyType = QVariant::Url;
type = "QUrl";
break;
case Object::DynamicProperty::Color:
+ propertyType = QVariant::Color;
type = "QColor";
break;
case Object::DynamicProperty::Date:
+ propertyType = QVariant::Date;
type = "QDate";
break;
}
+ ((QmlVMEMetaData *)dynamicData.data())->propertyCount++;
+ QmlVMEMetaData::PropertyData propertyData = { propertyType };
+ dynamicData.append((char *)&propertyData, sizeof(propertyData));
+
builder.addSignal(p.name + "Changed()");
builder.addProperty(p.name, type, ii);
}
+ if (preAlias != -1) {
+ for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
+ const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
+
+ if (p.type == Object::DynamicProperty::Alias) {
+ ((QmlVMEMetaData *)dynamicData.data())->aliasCount++;
+ compileAlias(builder, dynamicData, obj, p);
+ }
+ }
+ }
+
for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
QByteArray sig(s.name + "(");
@@ -1459,14 +1492,28 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj)
sig.append(")");
QMetaMethodBuilder b = builder.addSignal(sig);
b.setParameterNames(s.parameterNames);
+ ((QmlVMEMetaData *)dynamicData.data())->signalCount++;
}
int slotStart = obj->dynamicSlots.isEmpty()?-1:output->primitives.count();
for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
const Object::DynamicSlot &s = obj->dynamicSlots.at(ii);
- builder.addSlot(s.name + "()");
- output->primitives << s.body;
+ QByteArray sig(s.name + "(");
+ for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
+ if (jj) sig.append(",");
+ sig.append("QVariant");
+ }
+ sig.append(")");
+ QMetaMethodBuilder b = builder.addSlot(sig);
+ b.setParameterNames(s.parameterNames);
+
+ ((QmlVMEMetaData *)dynamicData.data())->methodCount++;
+ QmlVMEMetaData::MethodData methodData = { s.parameterNames.count() };
+ dynamicData.append((char *)&methodData, sizeof(methodData));
+
+ if (preAlias == -1)
+ output->primitives << s.body;
}
if (obj->metatype)
@@ -1475,17 +1522,37 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj)
obj->extObjectData = builder.toMetaObject();
static_cast<QMetaObject &>(obj->extObject) = *obj->extObjectData;
- output->synthesizedMetaObjects << obj->extObjectData;
- QmlInstruction store;
- store.type = QmlInstruction::StoreMetaObject;
- store.storeMeta.data = output->synthesizedMetaObjects.count() - 1;
- store.storeMeta.slotData = slotStart;
- store.line = obj->location.start.line;
- output->bytecode << store;
+ if (preAlias != -1) {
+ QmlInstruction &store = output->bytecode[preAlias];
+
+ store.storeMeta.aliasData = output->indexForByteArray(dynamicData);
+ qFree(output->synthesizedMetaObjects.at(store.storeMeta.data));
+ output->synthesizedMetaObjects[store.storeMeta.data] = obj->extObjectData;
+
+ } else {
+ output->synthesizedMetaObjects << obj->extObjectData;
+ QmlInstruction store;
+ store.type = QmlInstruction::StoreMetaObject;
+ store.storeMeta.data = output->synthesizedMetaObjects.count() - 1;
+ store.storeMeta.slotData = slotStart;
+ store.storeMeta.aliasData = output->indexForByteArray(dynamicData);
+ store.line = obj->location.start.line;
+ output->bytecode << store;
+
+ if (hasAlias) {
+ AliasReference alias;
+ alias.object = obj;
+ alias.instructionIdx = output->bytecode.count() - 1;
+ compileState.aliases << alias;
+ }
+ }
for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
+ if (p.type == Object::DynamicProperty::Alias)
+ continue;
+
if (p.defaultValue) {
p.defaultValue->name = p.name;
p.defaultValue->isDefault = false;
@@ -1496,6 +1563,66 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj)
return true;
}
+#include <private/qmljsparser_p.h>
+static QStringList astNodeToStringList(QmlJS::AST::Node *node)
+{
+ if (node->kind == QmlJS::AST::Node::Kind_IdentifierExpression) {
+ QString name =
+ static_cast<QmlJS::AST::IdentifierExpression *>(node)->name->asString();
+ return QStringList() << name;
+ } else if (node->kind == QmlJS::AST::Node::Kind_FieldMemberExpression) {
+ QmlJS::AST::FieldMemberExpression *expr = static_cast<QmlJS::AST::FieldMemberExpression *>(node);
+
+ QStringList rv = astNodeToStringList(expr->base);
+ if (rv.isEmpty())
+ return rv;
+ rv.append(expr->name->asString());
+ return rv;
+ }
+ return QStringList();
+}
+
+bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder,
+ QByteArray &data,
+ Object *obj,
+ const Object::DynamicProperty &prop)
+{
+ if (!prop.defaultValue)
+ COMPILE_EXCEPTION("No property alias location");
+
+ if (prop.defaultValue->values.count() != 1 ||
+ prop.defaultValue->values.at(0)->object ||
+ !prop.defaultValue->values.at(0)->value.isScript())
+ COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location");
+
+ QmlJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
+ if (!node)
+ COMPILE_EXCEPTION("No property alias location"); // ### Can this happen?
+
+ QStringList alias = astNodeToStringList(node);
+
+ if (alias.count() != 2)
+ COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location");
+
+ if (!compileState.ids.contains(alias.at(0)))
+ COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location");
+
+ const IdReference &id = compileState.ids[alias.at(0)];
+ int propIdx = id.object->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData());
+
+ if (-1 == propIdx)
+ COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location");
+
+ QMetaProperty aliasProperty = id.object->metaObject()->property(propIdx);
+
+ data.append((const char *)&id.idx, sizeof(id.idx));
+ data.append((const char *)&propIdx, sizeof(propIdx));
+
+ builder.addSignal(prop.name + "Changed()");
+ builder.addProperty(prop.name, aliasProperty.typeName(), builder.methodCount() - 1);
+ return true;
+}
+
bool QmlCompiler::compileBinding(QmlParser::Value *value,
QmlParser::Property *prop,
const BindingContext &ctxt)
@@ -1564,17 +1691,29 @@ protected:
// Update the init instruction with final data, and optimize some simple
// bindings
-void QmlCompiler::finalizeComponent(int patch)
+bool QmlCompiler::finalizeComponent(int patch)
{
for (int ii = 0; ii < compileState.bindings.count(); ++ii) {
const BindingReference &binding = compileState.bindings.at(ii);
finalizeBinding(binding);
}
+ for (int ii = 0; ii < compileState.aliases.count(); ++ii) {
+ const AliasReference &alias = compileState.aliases.at(ii);
+ COMPILE_CHECK(finalizeAlias(alias));
+ }
+
output->bytecode[patch].init.dataSize = compileState.savedObjects;;
output->bytecode[patch].init.bindingsSize = compileState.bindings.count();
output->bytecode[patch].init.parserStatusSize =
compileState.parserStatusCount;
+
+ return true;
+}
+
+bool QmlCompiler::finalizeAlias(const AliasReference &alias)
+{
+ COMPILE_CHECK(compileDynamicMeta(alias.object, alias.instructionIdx));
}
void QmlCompiler::finalizeBinding(const BindingReference &binding)
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index 819c4ad..1c45f57 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -118,6 +118,7 @@ private:
int indexForLocation(const QmlParser::LocationSpan &);
};
+class QMetaObjectBuilder;
class Q_DECLARATIVE_EXPORT QmlCompiler
{
public:
@@ -181,13 +182,19 @@ private:
const QMetaProperty &prop,
QmlParser::Value *value);
- bool compileDynamicMeta(QmlParser::Object *obj);
+ bool compileDynamicMeta(QmlParser::Object *obj, int preAlias = -1);
+ bool compileAlias(QMetaObjectBuilder &,
+ QByteArray &data,
+ QmlParser::Object *obj,
+ const QmlParser::Object::DynamicProperty &);
bool compileBinding(QmlParser::Value *, QmlParser::Property *prop,
const BindingContext &ctxt);
- void finalizeComponent(int patch);
+ bool finalizeComponent(int patch);
struct BindingReference;
void finalizeBinding(const BindingReference &);
+ struct AliasReference;
+ bool finalizeAlias(const AliasReference &);
bool canConvert(int, QmlParser::Object *);
QStringList deferredProperties(QmlParser::Object *);
@@ -199,6 +206,11 @@ private:
int idx;
};
+ struct AliasReference {
+ QmlParser::Object *object;
+ int instructionIdx;
+ };
+
struct BindingReference {
QmlParser::Variant expression;
QmlParser::Property *property;
@@ -215,6 +227,7 @@ private:
int savedObjects;
int pushedProperties;
QList<BindingReference> bindings;
+ QList<AliasReference> aliases;
QmlParser::Object *root;
};
ComponentCompileState compileState;
diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp
index 988d7c2..b55d77b 100644
--- a/src/declarative/qml/qmlcomponent.cpp
+++ b/src/declarative/qml/qmlcomponent.cpp
@@ -46,7 +46,7 @@
#include "qmlvme_p.h"
#include "qml.h"
#include <QStack>
-#include <qfxperf.h>
+#include <private/qfxperf_p.h>
#include <QStringList>
#include <qmlengine.h>
#include <QFileInfo>
@@ -270,10 +270,25 @@ QmlComponent::QmlComponent(QmlEngine *engine, const QUrl &url, QObject *parent)
}
/*!
+ Create a QmlComponent from the given \a url and give it the specified
+ \a parent and \a engine.
+
+ \sa loadUrl()
+*/
+QmlComponent::QmlComponent(QmlEngine *engine, const QString &url,
+ QObject *parent)
+: QObject(*(new QmlComponentPrivate), parent)
+{
+ Q_D(QmlComponent);
+ d->engine = engine;
+ loadUrl(QUrl(url));
+}
+
+/*!
Create a QmlComponent from the given QML \a data and give it the
- specified \a parent and \a engine. If \a url is provided, it is used to set
- the component name, and to provide a base path for items resolved
- by this component.
+ specified \a parent and \a engine. \a url is used to provide a base path
+ for items resolved by this component, and may be an empty url if the
+ component contains no items to resolve.
\sa setData()
*/
@@ -339,10 +354,13 @@ void QmlComponent::loadUrl(const QUrl &url)
d->clear();
- d->url = url;
+ if (url.isRelative())
+ d->url = d->engine->baseUrl().resolved(url);
+ else
+ d->url = url;
QmlCompositeTypeData *data =
- d->engine->d_func()->typeManager.get(url);
+ d->engine->d_func()->typeManager.get(d->url);
if (data->status == QmlCompositeTypeData::Waiting) {
diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h
index b29c123..5e6dce9 100644
--- a/src/declarative/qml/qmlcomponent.h
+++ b/src/declarative/qml/qmlcomponent.h
@@ -67,9 +67,10 @@ class Q_DECLARATIVE_EXPORT QmlComponent : public QObject
public:
QmlComponent(QObject *parent = 0);
QmlComponent(QmlEngine *, QObject *parent=0);
+ QmlComponent(QmlEngine *, const QString &url, QObject *parent = 0);
QmlComponent(QmlEngine *, const QUrl &url, QObject *parent = 0);
QmlComponent(QmlEngine *, const QByteArray &data,
- const QUrl &baseUrl=QUrl(), QObject *parent=0);
+ const QUrl &baseUrl, QObject *parent=0);
virtual ~QmlComponent();
Q_ENUMS(Status)
@@ -92,7 +93,7 @@ public:
virtual void completeCreate();
void loadUrl(const QUrl &url);
- void setData(const QByteArray &, const QUrl &baseUrl = QUrl());
+ void setData(const QByteArray &, const QUrl &baseUrl);
Q_SIGNALS:
void statusChanged(QmlComponent::Status);
diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp
index 60cb231..e97d2e9 100644
--- a/src/declarative/qml/qmlcontext.cpp
+++ b/src/declarative/qml/qmlcontext.cpp
@@ -41,12 +41,12 @@
#include <qmlcontext.h>
#include <private/qmlcontext_p.h>
+#include <private/qmlexpression_p.h>
#include <private/qmlengine_p.h>
#include <qmlengine.h>
#include <qscriptengine.h>
#include <QtCore/qvarlengtharray.h>
-
-#include <qdebug.h>
+#include <QtCore/qdebug.h>
// 6-bits
#define MAXIMUM_DEFAULT_OBJECTS 63
diff --git a/src/declarative/qml/qmlcontext.h b/src/declarative/qml/qmlcontext.h
index 44d8caa..e0b6d7b 100644
--- a/src/declarative/qml/qmlcontext.h
+++ b/src/declarative/qml/qmlcontext.h
@@ -88,6 +88,7 @@ private:
friend class QmlEngine;
friend class QmlEnginePrivate;
friend class QmlExpression;
+ friend class QmlExpressionPrivate;
friend class QmlBasicScript;
friend class QmlContextScriptClass;
friend class QmlObjectScriptClass;
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index fcbda95..4acdd0c 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -57,7 +57,7 @@
#include <QDebug>
#include <QMetaObject>
#include "qml.h"
-#include <qfxperf.h>
+#include <private/qfxperf_p.h>
#include <QStack>
#include "private/qmlbasicscript_p.h"
#include "private/qmlcompiledcomponent_p.h"
@@ -194,8 +194,8 @@ void QmlEnginePrivate::init()
//###needed for the other funcs, but should it be exposed?
scriptEngine.globalObject().setProperty(QLatin1String("qmlEngine"),
scriptEngine.newQObject(q));
- scriptEngine.globalObject().setProperty(QLatin1String("evalQml"),
- scriptEngine.newFunction(QmlEngine::createQMLObject, 1));
+ scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"),
+ scriptEngine.newFunction(QmlEngine::createQmlObject, 1));
scriptEngine.globalObject().setProperty(QLatin1String("createComponent"),
scriptEngine.newFunction(QmlEngine::createComponent, 1));
}
@@ -208,7 +208,7 @@ QmlContext *QmlEnginePrivate::setCurrentBindContext(QmlContext *c)
}
QmlEnginePrivate::CapturedProperty::CapturedProperty(const QmlMetaProperty &p)
-: object(p.object()), notifyIndex(p.property().notifySignalIndex())
+: object(p.object()), coreIndex(p.coreIndex()), notifyIndex(p.property().notifySignalIndex())
{
}
@@ -357,7 +357,7 @@ bool QmlEnginePrivate::loadCache(QmlBasicScriptNodeCache &cache, const QString &
cache.type = QmlBasicScriptNodeCache::Variant;
cache.context = context;
cache.contextIndex = *iter;
- capturedProperties << CapturedProperty(context->q_ptr, *iter + context->notifyIndex);
+ capturedProperties << CapturedProperty(context->q_ptr, -1, *iter + context->notifyIndex);
return true;
}
@@ -512,6 +512,36 @@ QNetworkAccessManager *QmlEngine::networkAccessManager() const
}
/*!
+ Return the base URL for this engine. The base URL is only used to resolve
+ components when a relative URL is passed to the QmlComponent constructor.
+
+ If a base URL has not been explicitly set, this method returns the
+ application's current working directory.
+
+ \sa setBaseUrl()
+*/
+QUrl QmlEngine::baseUrl() const
+{
+ Q_D(const QmlEngine);
+ if (d->baseUrl.isEmpty()) {
+ return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
+ } else {
+ return d->baseUrl;
+ }
+}
+
+/*!
+ Set the base URL for this engine to \a url.
+
+ \sa baseUrl()
+*/
+void QmlEngine::setBaseUrl(const QUrl &url)
+{
+ Q_D(QmlEngine);
+ d->baseUrl = url;
+}
+
+/*!
Returns the QmlContext for the \a object, or 0 if no context has been set.
When the QmlEngine instantiates a QObject, the context is set automatically.
@@ -581,13 +611,13 @@ QmlEngine *qmlEngine(const QObject *obj)
return context?context->engine():0;
}
-QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object)
+QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
{
QmlExtendedDeclarativeData *edata =
QmlExtendedDeclarativeData::get(const_cast<QObject *>(object), true);
QObject *rv = edata->attachedProperties.value(id);
- if (rv)
+ if (rv || !create)
return rv;
QmlAttachedPropertiesFunc pf = QmlMetaType::attachedPropertiesFuncById(id);
@@ -718,8 +748,8 @@ QScriptValue QmlEngine::qmlScriptObject(QObject* object, QmlEngine* engine)
\endcode
If you want to just create an arbitrary string of QML, instead of
- loading a qml file, consider the evalQML() function.
- \sa QmlComponent::createObject(), QmlEngine::createQMLObject()
+ loading a qml file, consider the createQmlObject() function.
+ \sa QmlComponent::createObject(), QmlEngine::createQmlObject()
*/
QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *engine)
{
@@ -729,21 +759,31 @@ QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *eng
if(ctxt->argumentCount() != 1 || !activeEngine){
c = new QmlComponent(activeEngine);
}else{
- //### This url needs to be resolved in the context that the function
- //### is called - it can't be done here.
- QUrl url = QUrl(ctxt->argument(0).toString());
+ QUrl url = QUrl(activeEngine->d_func()->currentExpression->context()
+ ->resolvedUrl(ctxt->argument(0).toString()));
+ if(!url.isValid()){
+ qDebug() << "Error A:" << url << activeEngine->activeContext() << QmlEngine::activeEngine() << activeEngine;
+ url = QUrl(ctxt->argument(0).toString());
+ }
c = new QmlComponent(activeEngine, url, activeEngine);
}
return engine->newQObject(c);
}
/*!
- Creates a new object from the specified string of qml. If a second argument
- is provided, this is treated as the filepath that the qml came from.
+ Creates a new object from the specified string of QML. It requires a
+ second argument, which is the id of an existing QML object to use as
+ the new object's parent. If a third argument is provided, this is used
+ as the filepath that the qml came from.
+
+ Example (where targetItem is the id of an existing QML item):
+ \code
+ newObject = createQmlObject('Rect {color: "red"; width: 20; height: 20}',
+ targetItem, "dynamicSnippet1");
+ \endcode
This function is intended for use inside QML only. It is intended to behave
- similarly to eval, but for creating QML elements. Thus, it is called as
- evalQml() in QtScript.
+ similarly to eval, but for creating QML elements.
Returns the created object, or null if there is an error. In the case of an
error, details of the error are output using qWarning().
@@ -752,504 +792,59 @@ QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *eng
the QML loads new components. If you are trying to load a new component,
for example from a QML file, consider the createComponent() function
instead. 'New components' refers to external QML files that have not yet
- been loaded, and so it is safe to use evalQml to load built-in components.
+ been loaded, and so it is safe to use createQmlObject to load built-in
+ components.
\sa QmlEngine::createComponent()
*/
-QScriptValue QmlEngine::createQMLObject(QScriptContext *ctxt, QScriptEngine *engine)
+QScriptValue QmlEngine::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine)
{
QmlEngine* activeEngine = qobject_cast<QmlEngine*>(
engine->globalObject().property(QLatin1String("qmlEngine")).toQObject());
- if(ctxt->argumentCount() < 1 || !activeEngine){
- if(ctxt->argumentCount() < 1){
- qWarning() << "createQMLObject requires a string argument.";
+ if(ctxt->argumentCount() < 2 || !activeEngine){
+ if(ctxt->argumentCount() < 2){
+ qWarning() << "createQmlObject requires two arguments, A QML string followed by an existing QML item id.";
}else{
- qWarning() << "createQMLObject cannot find engine.";
+ qWarning() << "createQmlObject cannot find engine.";
}
return engine->nullValue();
}
QString qml = ctxt->argument(0).toString();
QUrl url;
- if(ctxt->argumentCount() > 1)
- url = QUrl(ctxt->argument(1).toString());
+ if(ctxt->argumentCount() > 2)
+ url = QUrl(ctxt->argument(2).toString());
+ QObject *parentArg = ctxt->argument(1).data().toQObject();
+ QmlContext *qmlCtxt = qmlContext(parentArg);
+ url = qmlCtxt->resolvedUrl(url);
QmlComponent component(activeEngine, qml.toUtf8(), url);
if(component.isError()) {
QList<QmlError> errors = component.errors();
foreach (const QmlError &error, errors) {
- qWarning() << error;
+ qWarning() <<"Error in createQmlObject(): "<< error;
}
return engine->nullValue();
}
- QObject *obj = component.create();
+ QObject *obj = component.create(qmlCtxt);
if(component.isError()) {
QList<QmlError> errors = component.errors();
foreach (const QmlError &error, errors) {
- qWarning() << error;
+ qWarning() <<"Error in createQmlObject(): "<< error;
}
return engine->nullValue();
}
if(obj){
+ obj->setParent(parentArg);
+ obj->setProperty("parent", QVariant::fromValue<QObject*>(parentArg));
return qmlScriptObject(obj, activeEngine);
}
return engine->nullValue();
}
-QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b)
-: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0)
-{
-}
-
-QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc)
-: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0)
-{
-}
-
-QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr)
-: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0)
-{
-}
-
-QmlExpressionPrivate::~QmlExpressionPrivate()
-{
- sse.deleteScriptState(sseData);
- sseData = 0;
- delete proxy;
- delete log;
-}
-
-/*!
- Create an invalid QmlExpression.
-
- As the expression will not have an associated QmlContext, this will be a
- null expression object and its value will always be an invalid QVariant.
- */
-QmlExpression::QmlExpression()
-: d(new QmlExpressionPrivate(this))
-{
-}
-
-/*! \internal */
-QmlExpression::QmlExpression(QmlContext *ctxt, void *expr,
- QmlRefCount *rc, QObject *me)
-: d(new QmlExpressionPrivate(this, expr, rc))
-{
- d->ctxt = ctxt;
- if(ctxt && ctxt->engine())
- d->id = ctxt->engine()->d_func()->getUniqueId();
- if(ctxt)
- ctxt->d_func()->childExpressions.insert(this);
- d->me = me;
-}
-
-/*!
- Create a QmlExpression object.
-
- The \a expression ECMAScript will be executed in the \a ctxt QmlContext.
- If specified, the \a scope object's properties will also be in scope during
- the expression's execution.
-*/
-QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression,
- QObject *scope)
-: d(new QmlExpressionPrivate(this, expression))
-{
- d->ctxt = ctxt;
- if(ctxt && ctxt->engine())
- d->id = ctxt->engine()->d_func()->getUniqueId();
- if(ctxt)
- ctxt->d_func()->childExpressions.insert(this);
- d->me = scope;
-}
-
-/*!
- Destroy the QmlExpression instance.
-*/
-QmlExpression::~QmlExpression()
-{
- if (d->ctxt)
- d->ctxt->d_func()->childExpressions.remove(this);
- delete d; d = 0;
-}
-
-/*!
- Returns the QmlEngine this expression is associated with, or 0 if there
- is no association or the QmlEngine has been destroyed.
-*/
-QmlEngine *QmlExpression::engine() const
-{
- return d->ctxt?d->ctxt->engine():0;
-}
-
-/*!
- Returns the QmlContext this expression is associated with, or 0 if there
- is no association or the QmlContext has been destroyed.
-*/
-QmlContext *QmlExpression::context() const
-{
- return d->ctxt;
-}
-
-/*!
- Returns the expression string.
-*/
-QString QmlExpression::expression() const
-{
- if (d->sse.isValid())
- return QLatin1String(d->sse.expression());
- else
- return d->expression;
-}
-
-/*!
- Clear the expression.
-*/
-void QmlExpression::clearExpression()
-{
- setExpression(QString());
-}
-
-/*!
- Set the expression to \a expression.
-*/
-void QmlExpression::setExpression(const QString &expression)
-{
- if (d->sseData) {
- d->sse.deleteScriptState(d->sseData);
- d->sseData = 0;
- }
-
- delete d->proxy; d->proxy = 0;
-
- d->expression = expression;
-
- d->sse.clear();
-}
-
-/*!
- Called by QmlExpression each time the expression value changes from the
- last time it was evaluated. The expression must have been evaluated at
- least once (by calling QmlExpression::value()) before this callback will
- be made.
-
- The default implementation does nothing.
-*/
-void QmlExpression::valueChanged()
-{
-}
-
-void BindExpressionProxy::changed()
-{
- e->valueChanged();
-}
-
-/*!
- Returns the value of the expression, or an invalid QVariant if the
- expression is invalid or has an error.
-*/
-QVariant QmlExpression::value()
-{
- QVariant rv;
- if (!d->ctxt || !engine() || (!d->sse.isValid() && d->expression.isEmpty()))
- return rv;
-
-#ifdef Q_ENABLE_PERFORMANCE_LOG
- QFxPerfTimer<QFxPerf::BindValue> perf;
-#endif
-
- QmlBasicScript::CacheState cacheState = QmlBasicScript::Reset;
-
- QmlEnginePrivate *ep = engine()->d_func();
- QmlExpression *lastCurrentExpression = ep->currentExpression;
- ep->currentExpression = this;
- if (d->sse.isValid()) {
-#ifdef Q_ENABLE_PERFORMANCE_LOG
- QFxPerfTimer<QFxPerf::BindValueSSE> perfsse;
-#endif
-
- context()->d_func()->defaultObjects.insert(context()->d_func()->highPriorityCount, d->me);
-
- if (!d->sseData)
- d->sseData = d->sse.newScriptState();
- rv = d->sse.run(context(), d->sseData, &cacheState);
-
- context()->d_func()->defaultObjects.removeAt(context()->d_func()->highPriorityCount);
- } else {
-#ifdef Q_ENABLE_PERFORMANCE_LOG
- QFxPerfTimer<QFxPerf::BindValueQt> perfqt;
-#endif
- context()->d_func()->defaultObjects.insert(context()->d_func()->highPriorityCount, d->me);
-
- QScriptEngine *scriptEngine = engine()->scriptEngine();
- QScriptValueList oldScopeChain = scriptEngine->currentContext()->scopeChain();
- for (int i = 0; i < oldScopeChain.size(); ++i) {
- scriptEngine->currentContext()->popScope();
- }
- for (int i = context()->d_func()->scopeChain.size() - 1; i > -1; --i) {
- scriptEngine->currentContext()->pushScope(context()->d_func()->scopeChain.at(i));
- }
- QScriptValue svalue = scriptEngine->evaluate(expression(), d->fileName.toString(), d->line);
- 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 {
- qWarning() << exception.toString();
- }
- }
- }
-
- context()->d_func()->defaultObjects.removeAt(context()->d_func()->highPriorityCount);
- if (svalue.isArray()) {
- int length = svalue.property(QLatin1String("length")).toInt32();
- if (length && svalue.property(0).isObject()) {
- QList<QObject *> list;
- for (int ii = 0; ii < length; ++ii) {
- QScriptValue arrayItem = svalue.property(ii);
- QObject *d = qvariant_cast<QObject *>(arrayItem.data().toVariant());
- if (d) {
- list << d;
- } else {
- list << 0;
- }
- }
- rv = QVariant::fromValue(list);
- }
- } else if (svalue.isObject() &&
- !svalue.isNumber() &&
- !svalue.isString() &&
- !svalue.isDate() &&
- !svalue.isError() &&
- !svalue.isFunction() &&
- !svalue.isNull() &&
- !svalue.isQMetaObject() &&
- !svalue.isQObject() &&
- !svalue.isRegExp()) {
- QScriptValue objValue = svalue.data();
- if (objValue.isValid()) {
- QVariant var = objValue.toVariant();
- if (var.userType() >= (int)QVariant::UserType &&
- QmlMetaType::isObject(var.userType()))
- rv = var;
- }
- }
- if (rv.isNull())
- rv = svalue.toVariant();
-
- for (int i = 0; i < context()->d_func()->scopeChain.size(); ++i) {
- scriptEngine->currentContext()->popScope();
- }
- for (int i = oldScopeChain.size() - 1; i > -1; --i) {
- scriptEngine->currentContext()->pushScope(oldScopeChain.at(i));
- }
- }
- ep->currentExpression = lastCurrentExpression;
-
- if (cacheState != QmlBasicScript::NoChange) {
- if (cacheState != QmlBasicScript::Incremental && d->proxy) {
- delete d->proxy;
- d->proxy = 0;
- }
-
- if (trackChange() && ep->capturedProperties.count()) {
- if (!d->proxy)
- d->proxy = new BindExpressionProxy(this);
-
- static int changedIndex = -1;
- if (changedIndex == -1)
- changedIndex = BindExpressionProxy::staticMetaObject.indexOfSlot("changed()");
-
- if(qmlDebugger()) {
- QmlExpressionLog log;
- log.setTime(engine()->d_func()->getUniqueId());
- log.setExpression(expression());
- log.setResult(rv);
-
- for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) {
- const QmlEnginePrivate::CapturedProperty &prop =
- ep->capturedProperties.at(ii);
-
- if (prop.notifyIndex != -1) {
- QMetaObject::connect(prop.object, prop.notifyIndex,
- d->proxy, changedIndex);
- } else {
- // ### FIXME
- //QString warn = QLatin1String("Expression depends on property without a NOTIFY signal: [") + QLatin1String(prop.object->metaObject()->className()) + QLatin1String("].") + prop.name;
- //log.addWarning(warn);
- }
- }
- d->addLog(log);
-
- } else {
- for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) {
- const QmlEnginePrivate::CapturedProperty &prop =
- ep->capturedProperties.at(ii);
-
- if (prop.notifyIndex != -1)
- QMetaObject::connect(prop.object, prop.notifyIndex,
- d->proxy, changedIndex);
- }
- }
- } else {
- QmlExpressionLog log;
- log.setTime(engine()->d_func()->getUniqueId());
- log.setExpression(expression());
- log.setResult(rv);
- d->addLog(log);
- }
-
- } else {
- if(qmlDebugger()) {
- QmlExpressionLog log;
- log.setTime(engine()->d_func()->getUniqueId());
- log.setExpression(expression());
- log.setResult(rv);
- d->addLog(log);
- }
- }
-
- ep->capturedProperties.clear();
-
- return rv;
-}
-
-/*!
- Returns true if the expression results in a constant value.
- QmlExpression::value() must have been invoked at least once before the
- return from this method is valid.
- */
-bool QmlExpression::isConstant() const
-{
- return d->proxy == 0;
-}
-
-/*!
- Returns true if the changes are tracked in the expression's value.
-*/
-bool QmlExpression::trackChange() const
-{
- return d->trackChange;
-}
-
-/*!
- Set whether changes are tracked in the expression's value to \a trackChange.
-
- If true, the QmlExpression will monitor properties involved in the
- expression's evaluation, and call QmlExpression::valueChanged() if they have
- changed. This allows an application to ensure that any value associated
- with the result of the expression remains up to date.
-
- If false, the QmlExpression will not montitor properties involved in the
- expression's evaluation, and QmlExpression::valueChanged() will never be
- called. This is more efficient if an application wants a "one off"
- evaluation of the expression.
-
- By default, trackChange is true.
-*/
-void QmlExpression::setTrackChange(bool trackChange)
-{
- d->trackChange = trackChange;
-}
-
-/*!
- Set the location of this expression to \a line of \a fileName. This information
- is used by the script engine.
-*/
-void QmlExpression::setSourceLocation(const QUrl &fileName, int line)
-{
- d->fileName = fileName;
- d->line = line;
-}
-
-/*!
- Returns the expression's scope object, if provided, otherwise 0.
-
- In addition to data provided by the expression's QmlContext, the scope
- object's properties are also in scope during the expression's evaluation.
-*/
-QObject *QmlExpression::scopeObject() const
-{
- return d->me;
-}
-
-/*!
- \internal
-*/
-quint32 QmlExpression::id() const
-{
- return d->id;
-}
-
-/*!
- \class QmlExpression
- \brief The QmlExpression class evaluates ECMAScript in a QML context.
-*/
-
-/*!
- \class QmlExpressionObject
- \brief The QmlExpressionObject class extends QmlExpression with signals and slots.
-
- To remain as lightweight as possible, QmlExpression does not inherit QObject
- and consequently cannot use signals or slots. For the cases where this is
- more convenient in an application, QmlExpressionObject can be used instead.
-
- QmlExpressionObject behaves identically to QmlExpression, except that the
- QmlExpressionObject::value() method is a slot, and the
- QmlExpressionObject::valueChanged() callback is a signal.
-*/
-/*!
- Create a QmlExpression with the specified \a parent.
-
- As the expression will not have an associated QmlContext, this will be a
- null expression object and its value will always be an invalid QVariant.
-*/
-QmlExpressionObject::QmlExpressionObject(QObject *parent)
-: QObject(parent)
-{
-}
-
-/*!
- Create a QmlExpressionObject with the specified \a parent.
-
- The \a expression ECMAScript will be executed in the \a ctxt QmlContext.
- If specified, the \a scope object's properties will also be in scope during
- the expression's execution.
-*/
-QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expression, QObject *scope, QObject *parent)
-: QObject(parent), QmlExpression(ctxt, expression, scope)
-{
-}
-
-/*! \internal */
-QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, void *d, QmlRefCount *rc, QObject *me)
-: QmlExpression(ctxt, d, rc, me)
-{
-}
-
-/*!
- Returns the value of the expression, or an invalid QVariant if the
- expression is invalid or has an error.
-*/
-QVariant QmlExpressionObject::value()
-{
- return QmlExpression::value();
-}
-
-/*!
- \fn void QmlExpressionObject::valueChanged()
-
- Emitted each time the expression value changes from the last time it was
- evaluated. The expression must have been evaluated at least once (by
- calling QmlExpressionObject::value()) before this signal will be emitted.
-*/
-
QmlScriptClass::QmlScriptClass(QmlEngine *bindengine)
: QScriptClass(bindengine->scriptEngine()), engine(bindengine)
{
@@ -1333,7 +928,7 @@ QScriptValue QmlContextScriptClass::property(const QScriptValue &object,
} else {
rv = scriptEngine->newVariant(value);
}
- engine->d_func()->capturedProperties << QmlEnginePrivate::CapturedProperty(bindContext, index + bindContext->d_func()->notifyIndex);
+ engine->d_func()->capturedProperties << QmlEnginePrivate::CapturedProperty(bindContext, -1, index + bindContext->d_func()->notifyIndex);
return rv;
}
default:
@@ -1502,77 +1097,6 @@ void QmlObjectScriptClass::setProperty(QScriptValue &object,
scriptEngine->currentContext()->setActivationObject(oldact);
}
-void QmlExpressionPrivate::addLog(const QmlExpressionLog &l)
-{
- if (!log)
- log = new QList<QmlExpressionLog>();
- log->append(l);
-}
-
-QmlExpressionLog::QmlExpressionLog()
-{
-}
-
-QmlExpressionLog::QmlExpressionLog(const QmlExpressionLog &o)
-: m_time(o.m_time),
- m_expression(o.m_expression),
- m_result(o.m_result),
- m_warnings(o.m_warnings)
-{
-}
-
-QmlExpressionLog::~QmlExpressionLog()
-{
-}
-
-QmlExpressionLog &QmlExpressionLog::operator=(const QmlExpressionLog &o)
-{
- m_time = o.m_time;
- m_expression = o.m_expression;
- m_result = o.m_result;
- m_warnings = o.m_warnings;
- return *this;
-}
-
-void QmlExpressionLog::setTime(quint32 time)
-{
- m_time = time;
-}
-
-quint32 QmlExpressionLog::time() const
-{
- return m_time;
-}
-
-QString QmlExpressionLog::expression() const
-{
- return m_expression;
-}
-
-void QmlExpressionLog::setExpression(const QString &e)
-{
- m_expression = e;
-}
-
-QStringList QmlExpressionLog::warnings() const
-{
- return m_warnings;
-}
-
-void QmlExpressionLog::addWarning(const QString &w)
-{
- m_warnings << w;
-}
-
-QVariant QmlExpressionLog::result() const
-{
- return m_result;
-}
-
-void QmlExpressionLog::setResult(const QVariant &r)
-{
- m_result = r;
-}
class QmlImportsPrivate {
public:
@@ -1688,5 +1212,4 @@ QmlType* QmlEngine::resolveBuiltInType(const Imports& imports, const QByteArray&
return imports.d->findBuiltin(imports.base,type);
}
-
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h
index a07ea96..0c9da39 100644
--- a/src/declarative/qml/qmlengine.h
+++ b/src/declarative/qml/qmlengine.h
@@ -94,13 +94,16 @@ public:
void setNetworkAccessManager(QNetworkAccessManager *);
QNetworkAccessManager *networkAccessManager() const;
+ QUrl baseUrl() const;
+ void setBaseUrl(const QUrl &);
+
static QmlContext *contextForObject(const QObject *);
static void setContextForObject(QObject *, QmlContext *);
static QScriptValue qmlScriptObject(QObject*, QmlEngine*);
static QScriptValue createComponent(QScriptContext*, QScriptEngine*);
- static QScriptValue createQMLObject(QScriptContext*, QScriptEngine*);
+ static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*);
private:
// LK: move to the private class
@@ -113,6 +116,7 @@ private:
friend class QmlContext;
friend class QmlContextPrivate;
friend class QmlExpression;
+ friend class QmlExpressionPrivate;
friend class QmlBasicScript;
friend class QmlVME;
friend class QmlComponent;
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index ca65e3e..9a8b9fb 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -103,11 +103,12 @@ public:
QScriptValue propertyObject(const QScriptString &propName, QObject *, uint id = 0);
struct CapturedProperty {
- CapturedProperty(QObject *o, int n)
- : object(o), notifyIndex(n) {}
+ CapturedProperty(QObject *o, int c, int n)
+ : object(o), coreIndex(c), notifyIndex(n) {}
CapturedProperty(const QmlMetaProperty &);
QObject *object;
+ int coreIndex;
int notifyIndex;
};
QPODVector<CapturedProperty> capturedProperties;
@@ -128,6 +129,8 @@ public:
QScriptEngine scriptEngine;
+ QUrl baseUrl;
+
template<class T>
struct SimpleList {
SimpleList()
@@ -168,23 +171,6 @@ public:
}
};
-
-class BindExpressionProxy : public QObject
-{
-Q_OBJECT
-public:
- BindExpressionProxy(QmlExpression *be)
- :e(be)
- {
- }
-
-private:
- QmlExpression *e;
-
-private Q_SLOTS:
- void changed();
-};
-
class QmlScriptClass : public QScriptClass
{
public:
@@ -246,60 +232,6 @@ public:
const QScriptValue &value);
};
-class QmlExpressionLog
-{
-public:
- QmlExpressionLog();
- QmlExpressionLog(const QmlExpressionLog &);
- ~QmlExpressionLog();
-
- QmlExpressionLog &operator=(const QmlExpressionLog &);
-
- void setTime(quint32);
- quint32 time() const;
-
- QString expression() const;
- void setExpression(const QString &);
-
- QStringList warnings() const;
- void addWarning(const QString &);
-
- QVariant result() const;
- void setResult(const QVariant &);
-
-private:
- quint32 m_time;
- QString m_expression;
- QVariant m_result;
- QStringList m_warnings;
-};
-
-class QmlExpressionPrivate
-{
-public:
- QmlExpressionPrivate(QmlExpression *);
- QmlExpressionPrivate(QmlExpression *, const QString &expr);
- QmlExpressionPrivate(QmlExpression *, void *expr, QmlRefCount *rc);
- ~QmlExpressionPrivate();
-
- QmlExpression *q;
- QmlContext *ctxt;
- QString expression;
- QmlBasicScript sse;
- void *sseData;
- BindExpressionProxy *proxy;
- QObject *me;
- bool trackChange;
-
- QUrl fileName;
- int line;
-
- quint32 id;
-
- void addLog(const QmlExpressionLog &);
- QList<QmlExpressionLog> *log;
-};
-
QT_END_NAMESPACE
#endif // QMLENGINE_P_H
diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp
new file mode 100644
index 0000000..84352b8
--- /dev/null
+++ b/src/declarative/qml/qmlexpression.cpp
@@ -0,0 +1,624 @@
+/****************************************************************************
+**
+** 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 "qmlexpression.h"
+#include "qmlexpression_p.h"
+#include "qmlengine_p.h"
+#include "qmlcontext_p.h"
+#include "QtCore/qdebug.h"
+
+Q_DECLARE_METATYPE(QList<QObject *>);
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlDebugger, QML_DEBUGGER)
+
+QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b)
+: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0)
+{
+}
+
+QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc)
+: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0)
+{
+}
+
+QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr)
+: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0)
+{
+}
+
+QmlExpressionPrivate::~QmlExpressionPrivate()
+{
+ sse.deleteScriptState(sseData);
+ sseData = 0;
+ delete proxy;
+ delete log;
+}
+
+/*!
+ Create an invalid QmlExpression.
+
+ As the expression will not have an associated QmlContext, this will be a
+ null expression object and its value will always be an invalid QVariant.
+ */
+QmlExpression::QmlExpression()
+: d(new QmlExpressionPrivate(this))
+{
+}
+
+/*! \internal */
+QmlExpression::QmlExpression(QmlContext *ctxt, void *expr,
+ QmlRefCount *rc, QObject *me)
+: d(new QmlExpressionPrivate(this, expr, rc))
+{
+ d->ctxt = ctxt;
+ if(ctxt && ctxt->engine())
+ d->id = ctxt->engine()->d_func()->getUniqueId();
+ if(ctxt)
+ ctxt->d_func()->childExpressions.insert(this);
+ d->me = me;
+}
+
+/*!
+ Create a QmlExpression object.
+
+ The \a expression ECMAScript will be executed in the \a ctxt QmlContext.
+ If specified, the \a scope object's properties will also be in scope during
+ the expression's execution.
+*/
+QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression,
+ QObject *scope)
+: d(new QmlExpressionPrivate(this, expression))
+{
+ d->ctxt = ctxt;
+ if(ctxt && ctxt->engine())
+ d->id = ctxt->engine()->d_func()->getUniqueId();
+ if(ctxt)
+ ctxt->d_func()->childExpressions.insert(this);
+ d->me = scope;
+}
+
+/*!
+ Destroy the QmlExpression instance.
+*/
+QmlExpression::~QmlExpression()
+{
+ if (d->ctxt)
+ d->ctxt->d_func()->childExpressions.remove(this);
+ delete d; d = 0;
+}
+
+/*!
+ Returns the QmlEngine this expression is associated with, or 0 if there
+ is no association or the QmlEngine has been destroyed.
+*/
+QmlEngine *QmlExpression::engine() const
+{
+ return d->ctxt?d->ctxt->engine():0;
+}
+
+/*!
+ Returns the QmlContext this expression is associated with, or 0 if there
+ is no association or the QmlContext has been destroyed.
+*/
+QmlContext *QmlExpression::context() const
+{
+ return d->ctxt;
+}
+
+/*!
+ Returns the expression string.
+*/
+QString QmlExpression::expression() const
+{
+ if (d->sse.isValid())
+ return QLatin1String(d->sse.expression());
+ else
+ return d->expression;
+}
+
+/*!
+ Clear the expression.
+*/
+void QmlExpression::clearExpression()
+{
+ setExpression(QString());
+}
+
+/*!
+ Set the expression to \a expression.
+*/
+void QmlExpression::setExpression(const QString &expression)
+{
+ if (d->sseData) {
+ d->sse.deleteScriptState(d->sseData);
+ d->sseData = 0;
+ }
+
+ delete d->proxy; d->proxy = 0;
+
+ d->expression = expression;
+
+ d->sse.clear();
+}
+
+/*!
+ Called by QmlExpression each time the expression value changes from the
+ last time it was evaluated. The expression must have been evaluated at
+ least once (by calling QmlExpression::value()) before this callback will
+ be made.
+
+ The default implementation does nothing.
+*/
+void QmlExpression::valueChanged()
+{
+}
+
+QVariant QmlExpressionPrivate::evalSSE(QmlBasicScript::CacheState &cacheState)
+{
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::BindValueSSE> perfsse;
+#endif
+
+ QmlContextPrivate *ctxtPriv = ctxt->d_func();
+ if (me)
+ ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount , me);
+
+ if (!sseData)
+ sseData = sse.newScriptState();
+ QVariant rv = sse.run(ctxt, sseData, &cacheState);
+
+ if (me)
+ ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount);
+
+ return rv;
+}
+
+QVariant QmlExpressionPrivate::evalQtScript()
+{
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::BindValueQt> perfqt;
+#endif
+
+ QmlContextPrivate *ctxtPriv = ctxt->d_func();
+ QmlEngine *engine = ctxt->engine();
+
+ if (me)
+ ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, me);
+
+ QScriptEngine *scriptEngine = engine->scriptEngine();
+ QScriptValueList oldScopeChain =
+ scriptEngine->currentContext()->scopeChain();
+
+ for (int i = 0; i < oldScopeChain.size(); ++i)
+ scriptEngine->currentContext()->popScope();
+ for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i)
+ scriptEngine->currentContext()->pushScope(ctxtPriv->scopeChain.at(i));
+
+ QScriptValue svalue =
+ scriptEngine->evaluate(expression, fileName.toString(), line);
+
+ if (scriptEngine->hasUncaughtException()) {
+ if (scriptEngine->uncaughtException().isError()){
+ QScriptValue exception = scriptEngine->uncaughtException();
+ QLatin1String fileNameProp("fileName");
+ if (!exception.property(fileNameProp).toString().isEmpty()){
+ qWarning() << exception.property(fileNameProp).toString()
+ << scriptEngine->uncaughtExceptionLineNumber()
+ << exception.toString();
+ } else {
+ qWarning() << exception.toString();
+ }
+ }
+ }
+
+ if (me)
+ ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount);
+
+ QVariant rv;
+
+ if (svalue.isArray()) {
+ int length = svalue.property(QLatin1String("length")).toInt32();
+ if (length && svalue.property(0).isObject()) {
+ QList<QObject *> list;
+ for (int ii = 0; ii < length; ++ii) {
+ QScriptValue arrayItem = svalue.property(ii);
+ QObject *d =
+ qvariant_cast<QObject *>(arrayItem.data().toVariant());
+ if (d) {
+ list << d;
+ } else {
+ list << 0;
+ }
+ }
+ rv = QVariant::fromValue(list);
+ }
+ } else if (svalue.isObject() &&
+ !svalue.isNumber() &&
+ !svalue.isString() &&
+ !svalue.isDate() &&
+ !svalue.isError() &&
+ !svalue.isFunction() &&
+ !svalue.isNull() &&
+ !svalue.isQMetaObject() &&
+ !svalue.isQObject() &&
+ !svalue.isRegExp()) {
+ QScriptValue objValue = svalue.data();
+ if (objValue.isValid()) {
+ QVariant var = objValue.toVariant();
+ if (var.userType() >= (int)QVariant::UserType &&
+ QmlMetaType::isObject(var.userType()))
+ rv = var;
+ }
+ }
+ if (rv.isNull())
+ rv = svalue.toVariant();
+
+ for (int i = 0; i < ctxtPriv->scopeChain.size(); ++i)
+ scriptEngine->currentContext()->popScope();
+ for (int i = oldScopeChain.size() - 1; i > -1; --i)
+ scriptEngine->currentContext()->pushScope(oldScopeChain.at(i));
+
+ return rv;
+}
+
+/*!
+ Returns the value of the expression, or an invalid QVariant if the
+ expression is invalid or has an error.
+*/
+QVariant QmlExpression::value()
+{
+ QVariant rv;
+ if (!d->ctxt || !engine() || (!d->sse.isValid() && d->expression.isEmpty()))
+ return rv;
+
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::BindValue> perf;
+#endif
+
+ QmlBasicScript::CacheState cacheState = QmlBasicScript::Reset;
+
+ QmlEnginePrivate *ep = engine()->d_func();
+ QmlExpression *lastCurrentExpression = ep->currentExpression;
+ ep->currentExpression = this;
+
+ if (d->sse.isValid()) {
+ rv = d->evalSSE(cacheState);
+ } else {
+ rv = d->evalQtScript();
+ }
+
+ ep->currentExpression = lastCurrentExpression;
+
+ if (cacheState != QmlBasicScript::NoChange) {
+ if (cacheState != QmlBasicScript::Incremental && d->proxy) {
+ delete d->proxy;
+ d->proxy = 0;
+ }
+
+ if (trackChange() && ep->capturedProperties.count()) {
+ if (!d->proxy)
+ d->proxy = new QmlExpressionBindProxy(this);
+
+ static int changedIndex = -1;
+ if (changedIndex == -1)
+ changedIndex = QmlExpressionBindProxy::staticMetaObject.indexOfSlot("changed()");
+
+ if(qmlDebugger()) {
+ QmlExpressionLog log;
+ log.setTime(engine()->d_func()->getUniqueId());
+ log.setExpression(expression());
+ log.setResult(rv);
+
+ for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) {
+ const QmlEnginePrivate::CapturedProperty &prop =
+ ep->capturedProperties.at(ii);
+
+ if (prop.notifyIndex != -1) {
+ QMetaObject::connect(prop.object, prop.notifyIndex,
+ d->proxy, changedIndex);
+ } else {
+ const QMetaObject *metaObj = prop.object->metaObject();
+ QMetaProperty metaProp =
+ metaObj->property(prop.coreIndex);
+
+ QString warn = QLatin1String("Expression depends on non-NOTIFYable property: ") +
+ QLatin1String(metaObj->className()) +
+ QLatin1String("::") +
+ QLatin1String(metaProp.name());
+ log.addWarning(warn);
+ }
+ }
+ d->addLog(log);
+
+ } else {
+ bool outputWarningHeader = false;
+ for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) {
+ const QmlEnginePrivate::CapturedProperty &prop =
+ ep->capturedProperties.at(ii);
+
+ if (prop.notifyIndex != -1) {
+ QMetaObject::connect(prop.object, prop.notifyIndex,
+ d->proxy, changedIndex);
+ } else {
+ if (!outputWarningHeader) {
+ outputWarningHeader = true;
+ qWarning() << "QmlExpression: Expression" << expression() << "depends on non-NOTIFYable properties:";
+ }
+
+ const QMetaObject *metaObj = prop.object->metaObject();
+ QMetaProperty metaProp =
+ metaObj->property(prop.coreIndex);
+
+ qWarning().nospace() << " " << metaObj->className()
+ << "::" << metaProp.name();
+ }
+ }
+ }
+ } else {
+ QmlExpressionLog log;
+ log.setTime(engine()->d_func()->getUniqueId());
+ log.setExpression(expression());
+ log.setResult(rv);
+ d->addLog(log);
+ }
+
+ } else {
+ if(qmlDebugger()) {
+ QmlExpressionLog log;
+ log.setTime(engine()->d_func()->getUniqueId());
+ log.setExpression(expression());
+ log.setResult(rv);
+ d->addLog(log);
+ }
+ }
+
+ ep->capturedProperties.clear();
+
+ return rv;
+}
+
+/*!
+ Returns true if the expression results in a constant value.
+ QmlExpression::value() must have been invoked at least once before the
+ return from this method is valid.
+ */
+bool QmlExpression::isConstant() const
+{
+ return d->proxy == 0;
+}
+
+/*!
+ Returns true if the changes are tracked in the expression's value.
+*/
+bool QmlExpression::trackChange() const
+{
+ return d->trackChange;
+}
+
+/*!
+ Set whether changes are tracked in the expression's value to \a trackChange.
+
+ If true, the QmlExpression will monitor properties involved in the
+ expression's evaluation, and call QmlExpression::valueChanged() if they have
+ changed. This allows an application to ensure that any value associated
+ with the result of the expression remains up to date.
+
+ If false, the QmlExpression will not montitor properties involved in the
+ expression's evaluation, and QmlExpression::valueChanged() will never be
+ called. This is more efficient if an application wants a "one off"
+ evaluation of the expression.
+
+ By default, trackChange is true.
+*/
+void QmlExpression::setTrackChange(bool trackChange)
+{
+ d->trackChange = trackChange;
+}
+
+/*!
+ Set the location of this expression to \a line of \a fileName. This information
+ is used by the script engine.
+*/
+void QmlExpression::setSourceLocation(const QUrl &fileName, int line)
+{
+ d->fileName = fileName;
+ d->line = line;
+}
+
+/*!
+ Returns the expression's scope object, if provided, otherwise 0.
+
+ In addition to data provided by the expression's QmlContext, the scope
+ object's properties are also in scope during the expression's evaluation.
+*/
+QObject *QmlExpression::scopeObject() const
+{
+ return d->me;
+}
+
+/*!
+ \internal
+*/
+quint32 QmlExpression::id() const
+{
+ return d->id;
+}
+
+/*!
+ \class QmlExpression
+ \brief The QmlExpression class evaluates ECMAScript in a QML context.
+*/
+
+/*!
+ \class QmlExpressionObject
+ \brief The QmlExpressionObject class extends QmlExpression with signals and slots.
+
+ To remain as lightweight as possible, QmlExpression does not inherit QObject
+ and consequently cannot use signals or slots. For the cases where this is
+ more convenient in an application, QmlExpressionObject can be used instead.
+
+ QmlExpressionObject behaves identically to QmlExpression, except that the
+ QmlExpressionObject::value() method is a slot, and the
+ QmlExpressionObject::valueChanged() callback is a signal.
+*/
+/*!
+ Create a QmlExpression with the specified \a parent.
+
+ As the expression will not have an associated QmlContext, this will be a
+ null expression object and its value will always be an invalid QVariant.
+*/
+QmlExpressionObject::QmlExpressionObject(QObject *parent)
+: QObject(parent)
+{
+}
+
+/*!
+ Create a QmlExpressionObject with the specified \a parent.
+
+ The \a expression ECMAScript will be executed in the \a ctxt QmlContext.
+ If specified, the \a scope object's properties will also be in scope during
+ the expression's execution.
+*/
+QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expression, QObject *scope, QObject *parent)
+: QObject(parent), QmlExpression(ctxt, expression, scope)
+{
+}
+
+/*! \internal */
+QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, void *d, QmlRefCount *rc, QObject *me)
+: QmlExpression(ctxt, d, rc, me)
+{
+}
+
+/*!
+ Returns the value of the expression, or an invalid QVariant if the
+ expression is invalid or has an error.
+*/
+QVariant QmlExpressionObject::value()
+{
+ return QmlExpression::value();
+}
+
+/*!
+ \fn void QmlExpressionObject::valueChanged()
+
+ Emitted each time the expression value changes from the last time it was
+ evaluated. The expression must have been evaluated at least once (by
+ calling QmlExpressionObject::value()) before this signal will be emitted.
+*/
+
+void QmlExpressionPrivate::addLog(const QmlExpressionLog &l)
+{
+ if (!log)
+ log = new QList<QmlExpressionLog>();
+ log->append(l);
+}
+
+QmlExpressionLog::QmlExpressionLog()
+{
+}
+
+QmlExpressionLog::QmlExpressionLog(const QmlExpressionLog &o)
+: m_time(o.m_time),
+ m_expression(o.m_expression),
+ m_result(o.m_result),
+ m_warnings(o.m_warnings)
+{
+}
+
+QmlExpressionLog::~QmlExpressionLog()
+{
+}
+
+QmlExpressionLog &QmlExpressionLog::operator=(const QmlExpressionLog &o)
+{
+ m_time = o.m_time;
+ m_expression = o.m_expression;
+ m_result = o.m_result;
+ m_warnings = o.m_warnings;
+ return *this;
+}
+
+void QmlExpressionLog::setTime(quint32 time)
+{
+ m_time = time;
+}
+
+quint32 QmlExpressionLog::time() const
+{
+ return m_time;
+}
+
+QString QmlExpressionLog::expression() const
+{
+ return m_expression;
+}
+
+void QmlExpressionLog::setExpression(const QString &e)
+{
+ m_expression = e;
+}
+
+QStringList QmlExpressionLog::warnings() const
+{
+ return m_warnings;
+}
+
+void QmlExpressionLog::addWarning(const QString &w)
+{
+ m_warnings << w;
+}
+
+QVariant QmlExpressionLog::result() const
+{
+ return m_result;
+}
+
+void QmlExpressionLog::setResult(const QVariant &r)
+{
+ m_result = r;
+}
+
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h
index e8cac7a..3d8f8df 100644
--- a/src/declarative/qml/qmlexpression.h
+++ b/src/declarative/qml/qmlexpression.h
@@ -86,7 +86,7 @@ protected:
virtual void valueChanged();
private:
- friend class BindExpressionProxy;
+ friend class QmlExpressionBindProxy;
friend class QmlDebugger;
friend class QmlContext;
QmlExpressionPrivate *d;
diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h
new file mode 100644
index 0000000..5883125
--- /dev/null
+++ b/src/declarative/qml/qmlexpression_p.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QMLEXPRESSION_P_H
+#define QMLEXPRESSION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qmlbasicscript_p.h"
+#include "qmlexpression.h"
+
+QT_BEGIN_NAMESPACE
+
+class QmlExpression;
+class QString;
+class QmlExpressionLog;
+class QmlExpressionBindProxy;
+class QmlExpressionPrivate
+{
+public:
+ QmlExpressionPrivate(QmlExpression *);
+ QmlExpressionPrivate(QmlExpression *, const QString &expr);
+ QmlExpressionPrivate(QmlExpression *, void *expr, QmlRefCount *rc);
+ ~QmlExpressionPrivate();
+
+ QmlExpression *q;
+ QmlContext *ctxt;
+ QString expression;
+ QmlBasicScript sse;
+ void *sseData;
+ QmlExpressionBindProxy *proxy;
+ QObject *me;
+ bool trackChange;
+
+ QUrl fileName;
+ int line;
+
+ quint32 id;
+
+ void addLog(const QmlExpressionLog &);
+ QList<QmlExpressionLog> *log;
+
+ QVariant evalSSE(QmlBasicScript::CacheState &cacheState);
+ QVariant evalQtScript();
+};
+
+class QmlExpressionBindProxy : public QObject
+{
+Q_OBJECT
+public:
+ QmlExpressionBindProxy(QmlExpression *be)
+ :e(be) { }
+
+private:
+ QmlExpression *e;
+
+private Q_SLOTS:
+ void changed() { e->valueChanged(); }
+};
+
+class QmlExpressionLog
+{
+public:
+ QmlExpressionLog();
+ QmlExpressionLog(const QmlExpressionLog &);
+ ~QmlExpressionLog();
+
+ QmlExpressionLog &operator=(const QmlExpressionLog &);
+
+ void setTime(quint32);
+ quint32 time() const;
+
+ QString expression() const;
+ void setExpression(const QString &);
+
+ QStringList warnings() const;
+ void addWarning(const QString &);
+
+ QVariant result() const;
+ void setResult(const QVariant &);
+
+private:
+ quint32 m_time;
+ QString m_expression;
+ QVariant m_result;
+ QStringList m_warnings;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMLEXPRESSION_P_H
diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h
index f2f3ac2..40f9a32 100644
--- a/src/declarative/qml/qmlinstruction_p.h
+++ b/src/declarative/qml/qmlinstruction_p.h
@@ -181,6 +181,7 @@ public:
struct {
int data;
int slotData;
+ int aliasData;
} storeMeta;
struct {
int value;
diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp
index 307f76f..ee24074 100644
--- a/src/declarative/qml/qmlmetaproperty.cpp
+++ b/src/declarative/qml/qmlmetaproperty.cpp
@@ -42,7 +42,7 @@
#include "qmlmetaproperty.h"
#include "qmlmetaproperty_p.h"
#include <qml.h>
-#include <qfxperf.h>
+#include <private/qfxperf_p.h>
#include <QStringList>
#include <qmlbindablevalue.h>
#include <qmlcontext.h>
@@ -882,7 +882,8 @@ bool QmlMetaProperty::hasChangedNotifier() const
*/
bool QmlMetaProperty::needsChangedNotifier() const
{
- return type() & Property && !(type() & Attached);
+ return type() & Property && !(type() & Attached) &&
+ !property().isConstant();
}
/*!
@@ -1002,7 +1003,7 @@ QMetaMethod QmlMetaProperty::method() const
*/
QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, const QString &name)
{
- QStringList path = name.split('.');
+ QStringList path = name.split(QLatin1Char('.'));
QObject *object = obj;
diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp
index df5e26e..8daab6a 100644
--- a/src/declarative/qml/qmlparser.cpp
+++ b/src/declarative/qml/qmlparser.cpp
@@ -48,7 +48,7 @@
#include <QRectF>
#include <private/qmlvme_p.h>
#include <qmlbindablevalue.h>
-#include <qfxperf.h>
+#include <private/qfxperf_p.h>
#include <qml.h>
#include "private/qmlcomponent_p.h"
#include <qmlcomponent.h>
@@ -133,7 +133,7 @@ QmlParser::Object::DynamicSlot::DynamicSlot()
}
QmlParser::Object::DynamicSlot::DynamicSlot(const DynamicSlot &o)
-: name(o.name), body(o.body)
+: name(o.name), body(o.body), parameterNames(o.parameterNames)
{
}
diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h
index 9daa336..7550870 100644
--- a/src/declarative/qml/qmlparser_p.h
+++ b/src/declarative/qml/qmlparser_p.h
@@ -144,7 +144,7 @@ namespace QmlParser
DynamicProperty();
DynamicProperty(const DynamicProperty &);
- enum Type { Variant, Int, Bool, Real, String, Url, Color, Date };
+ enum Type { Variant, Int, Bool, Real, String, Url, Color, Date, Alias };
bool isDefaultProperty;
Type type;
@@ -166,6 +166,7 @@ namespace QmlParser
QByteArray name;
QString body;
+ QList<QByteArray> parameterNames;
};
// The list of dynamic properties
diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp
index 4358a3e..cd0a255 100644
--- a/src/declarative/qml/qmlscriptparser.cpp
+++ b/src/declarative/qml/qmlscriptparser.cpp
@@ -55,7 +55,7 @@
#include <QCoreApplication>
#include <QtDebug>
-#include <qfxperf.h>
+#include <private/qfxperf_p.h>
QT_BEGIN_NAMESPACE
@@ -537,6 +537,12 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
bool typeFound = false;
Object::DynamicProperty::Type type;
+
+ if (memberType == QLatin1String("alias")) {
+ type = Object::DynamicProperty::Alias;
+ typeFound = true;
+ }
+
for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
if(QLatin1String(propTypeNameToTypes[ii].name) == memberType) {
type = propTypeNameToTypes[ii].type;
@@ -720,20 +726,19 @@ bool ProcessAST::visit(AST::UiSourceElement *node)
if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) {
- if(funDecl->formals) {
- QmlError error;
- error.setDescription(QCoreApplication::translate("QmlParser","Slot declarations must be parameterless"));
- error.setLine(funDecl->lparenToken.startLine);
- error.setColumn(funDecl->lparenToken.startColumn);
- _parser->_errors << error;
- return false;
+ Object::DynamicSlot slot;
+
+ AST::FormalParameterList *f = funDecl->formals;
+ while (f) {
+ slot.parameterNames << f->name->asString().toUtf8();
+ f = f->finish();
}
QString body = textAt(funDecl->lbraceToken, funDecl->rbraceToken);
- Object::DynamicSlot slot;
slot.name = funDecl->name->asString().toUtf8();
slot.body = body;
obj->dynamicSlots << slot;
+
} else {
QmlError error;
error.setDescription(QCoreApplication::translate("QmlParser","QmlJS declaration outside Script element"));
diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index 962d917..a11caeb 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -40,14 +40,13 @@
****************************************************************************/
#include "qmlvme_p.h"
-#include <qfxperf.h>
+#include <private/qfxperf_p.h>
#include <private/qmlboundsignal_p.h>
#include <private/qmlstringconverters_p.h>
#include "private/qmetaobjectbuilder_p.h"
#include "private/qmldeclarativedata_p.h"
#include <qml.h>
#include <private/qmlcustomparser_p.h>
-#include <qperformancelog.h>
#include <QStack>
#include <QWidget>
#include <private/qmlcompiledcomponent_p.h>
@@ -240,7 +239,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp
case QmlInstruction::StoreMetaObject:
{
QObject *target = stack.top();
- new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, comp);
+ new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(), comp);
}
break;
diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp
index ec269b8..6d14689 100644
--- a/src/declarative/qml/qmlvmemetaobject.cpp
+++ b/src/declarative/qml/qmlvmemetaobject.cpp
@@ -47,6 +47,7 @@
#include <QtCore/qlist.h>
#include <QtCore/qdebug.h>
#include <qmlexpression.h>
+#include <private/qmlcontext_p.h>
QT_BEGIN_NAMESPACE
@@ -54,8 +55,10 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj,
const QMetaObject *other,
QList<QString> *strData,
int slotData,
+ const QmlVMEMetaData *meta,
QmlRefCount *rc)
-: object(obj), ref(rc), slotData(strData), slotDataIdx(slotData), parent(0)
+: object(obj), ref(rc), metaData(meta), slotData(strData),
+ slotDataIdx(slotData), parent(0)
{
if (ref)
ref->addref();
@@ -68,37 +71,18 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj,
parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
op->metaObject = this;
- baseProp = propertyOffset();
- baseSig = methodOffset();
- data = new QVariant[propertyCount() - baseProp];
- vTypes.resize(propertyCount() - baseProp);
+ propOffset = QAbstractDynamicMetaObject::propertyOffset();
+ methodOffset = QAbstractDynamicMetaObject::methodOffset();
- // ### Optimize
- for (int ii = baseProp; ii < propertyCount(); ++ii) {
- QMetaProperty prop = property(ii);
- if ((int)prop.type() != -1) {
- data[ii - baseProp] = QVariant((QVariant::Type)prop.userType());
- } else {
- vTypes.setBit(ii - baseProp, true);
- }
- }
+ data = new QVariant[metaData->propertyCount];
+ aConnected.resize(metaData->aliasCount);
- baseSlot = -1;
- slotCount = 0;
- for (int ii = baseSig; ii < methodCount(); ++ii) {
- QMetaMethod m = method(ii);
- if (m.methodType() == QMetaMethod::Slot) {
- if (baseSlot == -1)
- baseSlot = ii;
- } else {
- if (baseSlot != -1) {
- slotCount = ii - baseSlot;
- break;
- }
- }
+ // ### Optimize
+ for (int ii = 0; ii < metaData->propertyCount; ++ii) {
+ int t = (metaData->propertyData() + ii)->propertyType;
+ if (t != -1)
+ data[ii] = QVariant((QVariant::Type)t);
}
- if(baseSlot != -1 && !slotCount)
- slotCount = methodCount() - baseSlot;
}
QmlVMEMetaObject::~QmlVMEMetaObject()
@@ -110,81 +94,146 @@ QmlVMEMetaObject::~QmlVMEMetaObject()
delete [] data;
}
-int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
+int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
{
+ int id = _id;
if(c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) {
- if (id >= baseProp) {
- int propId = id - baseProp;
- bool needActivate = false;
-
- if (vTypes.testBit(propId)) {
- if (c == QMetaObject::ReadProperty) {
- *reinterpret_cast<QVariant *>(a[0]) = data[propId];
- } else if (c == QMetaObject::WriteProperty) {
- needActivate =
- (data[propId] != *reinterpret_cast<QVariant *>(a[0]));
- data[propId] = *reinterpret_cast<QVariant *>(a[0]);
- }
- } else {
- if (c == QMetaObject::ReadProperty) {
- switch(data[propId].type()) {
- case QVariant::Int:
- *reinterpret_cast<int *>(a[0]) = data[propId].toInt();
- break;
- case QVariant::Bool:
- *reinterpret_cast<bool *>(a[0]) = data[propId].toBool();
- break;
- case QVariant::Double:
- *reinterpret_cast<double *>(a[0]) = data[propId].toDouble();
- break;
- case QVariant::String:
- *reinterpret_cast<QString *>(a[0]) = data[propId].toString();
- break;
- case QVariant::Url:
- *reinterpret_cast<QUrl *>(a[0]) = data[propId].toUrl();
- break;
- case QVariant::Color:
- *reinterpret_cast<QColor *>(a[0]) = data[propId].value<QColor>();
- break;
- case QVariant::Date:
- *reinterpret_cast<QDate *>(a[0]) = data[propId].toDate();
- break;
- default:
- qFatal("Unknown type");
- break;
+ if (id >= propOffset) {
+ id -= propOffset;
+
+ if (id < metaData->propertyCount) {
+ int t = (metaData->propertyData() + id)->propertyType;
+ bool needActivate = false;
+
+ if (t == -1) {
+
+ if (c == QMetaObject::ReadProperty) {
+ *reinterpret_cast<QVariant *>(a[0]) = data[id];
+ } else if (c == QMetaObject::WriteProperty) {
+ needActivate =
+ (data[id] != *reinterpret_cast<QVariant *>(a[0]));
+ data[id] = *reinterpret_cast<QVariant *>(a[0]);
+ }
+
+ } else {
+
+ if (c == QMetaObject::ReadProperty) {
+ switch(t) {
+ case QVariant::Int:
+ *reinterpret_cast<int *>(a[0]) = data[id].toInt();
+ break;
+ case QVariant::Bool:
+ *reinterpret_cast<bool *>(a[0]) = data[id].toBool();
+ break;
+ case QVariant::Double:
+ *reinterpret_cast<double *>(a[0]) = data[id].toDouble();
+ break;
+ case QVariant::String:
+ *reinterpret_cast<QString *>(a[0]) = data[id].toString();
+ break;
+ case QVariant::Url:
+ *reinterpret_cast<QUrl *>(a[0]) = data[id].toUrl();
+ break;
+ case QVariant::Color:
+ *reinterpret_cast<QColor *>(a[0]) = data[id].value<QColor>();
+ break;
+ case QVariant::Date:
+ *reinterpret_cast<QDate *>(a[0]) = data[id].toDate();
+ break;
+ default:
+ break;
+ }
+
+ } else if (c == QMetaObject::WriteProperty) {
+
+ QVariant value = QVariant((QVariant::Type)data[id].type(), a[0]);
+ needActivate = (data[id] != value);
+ data[id] = value;
}
- } else if (c == QMetaObject::WriteProperty) {
- QVariant value = QVariant((QVariant::Type)data[propId].type(), a[0]);
- needActivate = (data[propId] != value);
- data[propId] = value;
}
+
+ if (c == QMetaObject::WriteProperty && needActivate) {
+ activate(object, methodOffset + id, 0);
+ }
+
+ return -1;
}
- if (c == QMetaObject::WriteProperty && needActivate) {
- activate(object, baseSig + propId, 0);
+ id -= metaData->propertyCount;
+
+ if (id < metaData->aliasCount) {
+
+ QmlContext *ctxt = qmlContext(object);
+
+ if (!ctxt) return -1;
+ QmlVMEMetaData::AliasData *d = metaData->aliasData() + id;
+ QmlContextPrivate *ctxtPriv =
+ (QmlContextPrivate *)QObjectPrivate::get(ctxt);
+
+ QObject *target =
+ *(QObject **)ctxtPriv->propertyValues[d->contextIdx].data();
+ if (!target) return -1;
+
+ if (c == QMetaObject::ReadProperty && !aConnected.testBit(id)) {
+ int sigIdx = methodOffset + id + metaData->propertyCount;
+ QMetaObject::connect(ctxt, d->contextIdx + ctxtPriv->notifyIndex, object, sigIdx);
+
+ QMetaProperty prop =
+ target->metaObject()->property(d->propertyIdx);
+ if (prop.hasNotifySignal())
+ QMetaObject::connect(target, prop.notifySignalIndex(),
+ object, sigIdx);
+ aConnected.setBit(id);
+ }
+ return QMetaObject::metacall(target, c, d->propertyIdx, a);
+
}
+ return -1;
+
+ }
- return id;
- }
} else if(c == QMetaObject::InvokeMetaMethod) {
- if (id >= baseSig && (baseSlot == -1 || id < baseSlot)) {
- QMetaObject::activate(object, id, a);
- return id;
- } else if (id >= baseSlot && id < (baseSlot + slotCount)) {
- int idx = id - baseSlot + slotDataIdx;
- QmlContext *ctxt = qmlContext(object);
- QmlExpression expr(ctxt, slotData->at(idx), object);
- expr.setTrackChange(false);
- expr.value();
- return id;
+
+ if (id >= methodOffset) {
+
+ id -= methodOffset;
+ int plainSignals = metaData->signalCount + metaData->propertyCount +
+ metaData->aliasCount;
+ if (id < plainSignals) {
+ QMetaObject::activate(object, _id, a);
+ return -1;
+ }
+
+ id -= plainSignals;
+
+ if (id < metaData->methodCount) {
+ QString code = slotData->at(id + slotDataIdx);
+ QmlContext *ctxt = qmlContext(object);
+
+ if (0 == (metaData->methodData() + id)->parameterCount) {
+ QmlExpression expr(ctxt, code, object);
+ expr.setTrackChange(false);
+ expr.value();
+ } else {
+ QmlContext newCtxt(ctxt);
+ QMetaMethod m = method(_id);
+ QList<QByteArray> names = m.parameterNames();
+ for (int ii = 0; ii < names.count(); ++ii)
+ newCtxt.setContextProperty(names.at(ii), *(QVariant *)a[ii + 1]);
+ QmlExpression expr(&newCtxt, code, object);
+ expr.setTrackChange(false);
+ expr.value();
+ }
+ }
+ return -1;
}
}
if (parent)
- return parent->metaCall(c, id, a);
+ return parent->metaCall(c, _id, a);
else
- return object->qt_metacall(c, id, a);
+ return object->qt_metacall(c, _id, a);
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h
index 7b6fd2d..6421c3f 100644
--- a/src/declarative/qml/qmlvmemetaobject_p.h
+++ b/src/declarative/qml/qmlvmemetaobject_p.h
@@ -59,11 +59,45 @@
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
+
+struct QmlVMEMetaData
+{
+ short propertyCount;
+ short aliasCount;
+ short signalCount;
+ short methodCount;
+
+ struct AliasData {
+ int contextIdx;
+ int propertyIdx;
+ };
+
+ struct PropertyData {
+ int propertyType;
+ };
+
+ struct MethodData {
+ int parameterCount;
+ };
+
+ PropertyData *propertyData() const {
+ return (PropertyData *)(((const char *)this) + sizeof(QmlVMEMetaData));
+ }
+
+ AliasData *aliasData() const {
+ return (AliasData *)(propertyData() + propertyCount);
+ }
+
+ MethodData *methodData() const {
+ return (MethodData *)(aliasData() + propertyCount);
+ }
+};
+
class QmlRefCount;
class QmlVMEMetaObject : public QAbstractDynamicMetaObject
{
public:
- QmlVMEMetaObject(QObject *, const QMetaObject *, QList<QString> *, int slotData, QmlRefCount * = 0);
+ QmlVMEMetaObject(QObject *, const QMetaObject *, QList<QString> *, int slotData, const QmlVMEMetaData *data, QmlRefCount * = 0);
~QmlVMEMetaObject();
protected:
@@ -72,15 +106,19 @@ protected:
private:
QObject *object;
QmlRefCount *ref;
- int baseProp;
- int baseSig;
- int baseSlot;
- int slotCount;
+
+ const QmlVMEMetaData *metaData;
+ int propOffset;
+ int methodOffset;
+
QVariant *data;
- QBitArray vTypes;
+ QBitArray aConnected;
+
QList<QString> *slotData;
int slotDataIdx;
+
QAbstractDynamicMetaObject *parent;
+
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/rewriter/rewriter.cpp b/src/declarative/qml/rewriter/rewriter.cpp
index 2ce927c..ed45f16 100644
--- a/src/declarative/qml/rewriter/rewriter.cpp
+++ b/src/declarative/qml/rewriter/rewriter.cpp
@@ -83,14 +83,19 @@ void Rewriter::moveTextBefore(const AST::SourceLocation &firstLoc,
const AST::SourceLocation &lastLoc,
const AST::SourceLocation &loc)
{
- textWriter.move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset);
+ move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset);
}
void Rewriter::moveTextAfter(const AST::SourceLocation &firstLoc,
const AST::SourceLocation &lastLoc,
const AST::SourceLocation &loc)
{
- textWriter.move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset + loc.length);
+ move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset + loc.length);
+}
+
+void Rewriter::move(int pos, int length, int to)
+{
+ textWriter.move(pos, length, to);
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/rewriter/rewriter_p.h b/src/declarative/qml/rewriter/rewriter_p.h
index fcb9ca5..44f3cce 100644
--- a/src/declarative/qml/rewriter/rewriter_p.h
+++ b/src/declarative/qml/rewriter/rewriter_p.h
@@ -121,7 +121,8 @@ public:
//
// low-level offset based API
//
- void replace(int offset, int length, const QString &text);
+ virtual void replace(int offset, int length, const QString &text);
+ virtual void move(int pos, int length, int to);
void insertText(int offset, const QString &text);
void removeText(int offset, int length);