summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2009-07-03 06:14:22 (GMT)
committerAlan Alpert <alan.alpert@nokia.com>2009-07-03 06:14:22 (GMT)
commit26fab96a7827cf7ac250fb434715840195258608 (patch)
treef43816824fb34db0db29210ac4c1803d1baeff5f /src/declarative/qml
parentc329d989054ba21698a2de9b73a1e005e49ba916 (diff)
parent6c7b88af807cbd2b4d824b8fca0f199ae1413432 (diff)
downloadQt-26fab96a7827cf7ac250fb434715840195258608.zip
Qt-26fab96a7827cf7ac250fb434715840195258608.tar.gz
Qt-26fab96a7827cf7ac250fb434715840195258608.tar.bz2
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Diffstat (limited to 'src/declarative/qml')
-rw-r--r--src/declarative/qml/qml.pri2
-rw-r--r--src/declarative/qml/qmlbasicscript.cpp32
-rw-r--r--src/declarative/qml/qmlcompiler.cpp65
-rw-r--r--src/declarative/qml/qmlcontext.cpp4
-rw-r--r--src/declarative/qml/qmlcontext.h1
-rw-r--r--src/declarative/qml/qmlengine.cpp529
-rw-r--r--src/declarative/qml/qmlengine.h1
-rw-r--r--src/declarative/qml/qmlengine_p.h76
-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/qmlmetaproperty.cpp3
-rw-r--r--src/declarative/qml/qmlparser.cpp2
-rw-r--r--src/declarative/qml/qmlparser_p.h1
-rw-r--r--src/declarative/qml/qmlscriptparser.cpp15
-rw-r--r--src/declarative/qml/qmlvme.cpp2
-rw-r--r--src/declarative/qml/qmlvmemetaobject.cpp243
-rw-r--r--src/declarative/qml/qmlvmemetaobject_p.h59
-rw-r--r--src/declarative/qml/rewriter/rewriter.cpp9
-rw-r--r--src/declarative/qml/rewriter/rewriter_p.h3
20 files changed, 1029 insertions, 782 deletions
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 0cfb587..478491f 100644
--- a/src/declarative/qml/qmlbasicscript.cpp
+++ b/src/declarative/qml/qmlbasicscript.cpp
@@ -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/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index aa2cf84..b04c932 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -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"
@@ -1406,6 +1407,8 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias)
obj->dynamicSlots.isEmpty())
return true;
+ QByteArray dynamicData(sizeof(QmlVMEMetaData), (char)0);
+
QMetaObjectBuilder builder;
if (obj->metatype)
builder.setClassName(QByteArray(obj->metatype->className()) + "QML");
@@ -1420,41 +1423,65 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias)
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 + "(");
@@ -1465,38 +1492,30 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias)
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 + "()");
+ 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;
}
- QByteArray aliasData;
- if (preAlias != -1) {
- int dynProperties = 0;
- QByteArray data;
- int propCount = builder.propertyCount();
- int signalCount = builder.methodCount();
- for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
- const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
-
- if (p.type == Object::DynamicProperty::Alias) {
- dynProperties++;
- compileAlias(builder, data, obj, p);
- }
- }
- aliasData.append((const char *)&dynProperties, sizeof(int));
- aliasData.append((const char *)&propCount, sizeof(int));
- aliasData.append((const char *)&signalCount, sizeof(int));
- aliasData.append(data);
- }
-
if (obj->metatype)
builder.setSuperClass(obj->metatype);
@@ -1506,7 +1525,7 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias)
if (preAlias != -1) {
QmlInstruction &store = output->bytecode[preAlias];
- store.storeMeta.aliasData = output->indexForByteArray(aliasData);
+ store.storeMeta.aliasData = output->indexForByteArray(dynamicData);
qFree(output->synthesizedMetaObjects.at(store.storeMeta.data));
output->synthesizedMetaObjects[store.storeMeta.data] = obj->extObjectData;
@@ -1516,7 +1535,7 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias)
store.type = QmlInstruction::StoreMetaObject;
store.storeMeta.data = output->synthesizedMetaObjects.count() - 1;
store.storeMeta.slotData = slotStart;
- store.storeMeta.aliasData = -1;
+ store.storeMeta.aliasData = output->indexForByteArray(dynamicData);
store.line = obj->location.start.line;
output->bytecode << store;
diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp
index e5016f2..b590596 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 ce5fe52..f5858cb 100644
--- a/src/declarative/qml/qmlcontext.h
+++ b/src/declarative/qml/qmlcontext.h
@@ -89,6 +89,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 9b74472..5c9273a 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -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;
}
@@ -946,457 +946,6 @@ QScriptValue QmlEngine::createQmlObject(QScriptContext *ctxt, QScriptEngine *eng
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)
{
@@ -1480,7 +1029,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:
@@ -1649,76 +1198,4 @@ 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;
-}
-
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h
index f600520..c4259ce 100644
--- a/src/declarative/qml/qmlengine.h
+++ b/src/declarative/qml/qmlengine.h
@@ -104,6 +104,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 93ae704..25f6edf 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;
@@ -169,23 +170,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:
@@ -247,60 +231,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/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp
index 90acd72..ee24074 100644
--- a/src/declarative/qml/qmlmetaproperty.cpp
+++ b/src/declarative/qml/qmlmetaproperty.cpp
@@ -882,7 +882,8 @@ bool QmlMetaProperty::hasChangedNotifier() const
*/
bool QmlMetaProperty::needsChangedNotifier() const
{
- return type() & Property && !(type() & Attached);
+ return type() & Property && !(type() & Attached) &&
+ !property().isConstant();
}
/*!
diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp
index 2e7eb69..8daab6a 100644
--- a/src/declarative/qml/qmlparser.cpp
+++ b/src/declarative/qml/qmlparser.cpp
@@ -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 803c73e..7550870 100644
--- a/src/declarative/qml/qmlparser_p.h
+++ b/src/declarative/qml/qmlparser_p.h
@@ -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 1c88018..82f6a60 100644
--- a/src/declarative/qml/qmlscriptparser.cpp
+++ b/src/declarative/qml/qmlscriptparser.cpp
@@ -723,20 +723,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 0d88e02..a11caeb 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -239,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, (instr.storeMeta.aliasData != -1)?datas.at(instr.storeMeta.aliasData):QByteArray(), 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 dc06bc5..6d14689 100644
--- a/src/declarative/qml/qmlvmemetaobject.cpp
+++ b/src/declarative/qml/qmlvmemetaobject.cpp
@@ -55,10 +55,10 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj,
const QMetaObject *other,
QList<QString> *strData,
int slotData,
- const QByteArray &alias,
+ const QmlVMEMetaData *meta,
QmlRefCount *rc)
-: object(obj), ref(rc), slotData(strData), slotDataIdx(slotData), parent(0),
- aliasData(alias), aliases(0), aliasArray(0)
+: object(obj), ref(rc), metaData(meta), slotData(strData),
+ slotDataIdx(slotData), parent(0)
{
if (ref)
ref->addref();
@@ -71,44 +71,18 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj,
parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
op->metaObject = this;
- if (!aliasData.isEmpty()) {
- aliases = (Aliases *)aliasData.constData();
- aliasArray = (AliasArray *)(aliasData.constData() + 3 * sizeof(int));
- aConnected.resize(aliases->aliasCount);
- }
+ propOffset = QAbstractDynamicMetaObject::propertyOffset();
+ methodOffset = QAbstractDynamicMetaObject::methodOffset();
- baseProp = propertyOffset();
- baseSig = methodOffset();
- int propCount = propertyCount() - (aliases?aliases->aliasCount:0);
- data = new QVariant[propCount - baseProp];
- vTypes.resize(propCount - baseProp);
+ data = new QVariant[metaData->propertyCount];
+ aConnected.resize(metaData->aliasCount);
// ### Optimize
- for (int ii = baseProp; ii < propCount; ++ii) {
- QMetaProperty prop = property(ii);
- if ((int)prop.type() != -1) {
- data[ii - baseProp] = QVariant((QVariant::Type)prop.userType());
- } else {
- vTypes.setBit(ii - baseProp, true);
- }
+ for (int ii = 0; ii < metaData->propertyCount; ++ii) {
+ int t = (metaData->propertyData() + ii)->propertyType;
+ if (t != -1)
+ data[ii] = QVariant((QVariant::Type)t);
}
-
- 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;
- }
- }
- }
- if(baseSlot != -1 && !slotCount)
- slotCount = methodCount() - baseSlot;
}
QmlVMEMetaObject::~QmlVMEMetaObject()
@@ -120,111 +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 (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;
+ }
+
+ }
+
+ if (c == QMetaObject::WriteProperty && needActivate) {
+ activate(object, methodOffset + id, 0);
+ }
+
+ return -1;
+ }
+
+ id -= metaData->propertyCount;
+
+ if (id < metaData->aliasCount) {
- if (aliases && propId >= aliases->propCount) {
QmlContext *ctxt = qmlContext(object);
if (!ctxt) return -1;
- int aliasId = propId - aliases->propCount;
- AliasArray *d = aliasArray + aliasId;
+ QmlVMEMetaData::AliasData *d = metaData->aliasData() + id;
QmlContextPrivate *ctxtPriv =
(QmlContextPrivate *)QObjectPrivate::get(ctxt);
- QObject *target = *(QObject **)ctxtPriv->propertyValues[d->contextIdx].data();
+ QObject *target =
+ *(QObject **)ctxtPriv->propertyValues[d->contextIdx].data();
if (!target) return -1;
- if (c == QMetaObject::ReadProperty &&
- !aConnected.testBit(aliasId)) {
-
- int mySigIdx = baseSig + aliasId + aliases->signalOffset;
- QMetaObject::connect(ctxt, d->contextIdx + ctxtPriv->notifyIndex, object, mySigIdx);
+ 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->propIdx);
+ QMetaProperty prop =
+ target->metaObject()->property(d->propertyIdx);
if (prop.hasNotifySignal())
QMetaObject::connect(target, prop.notifySignalIndex(),
- object, mySigIdx);
- aConnected.setBit(aliasId);
-
- }
- return QMetaObject::metacall(target, c, d->propIdx, a);
-
- } else 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]);
+ object, sigIdx);
+ aConnected.setBit(id);
}
- } 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;
- }
- } else if (c == QMetaObject::WriteProperty) {
+ return QMetaObject::metacall(target, c, d->propertyIdx, a);
- QVariant value = QVariant((QVariant::Type)data[propId].type(), a[0]);
- needActivate = (data[propId] != value);
- data[propId] = value;
- }
}
+ return -1;
- if (c == QMetaObject::WriteProperty && needActivate) {
- activate(object, baseSig + propId, 0);
- }
+ }
- return id;
- }
} else if(c == QMetaObject::InvokeMetaMethod) {
- if (id >= baseSig && (aliases && id >= baseSig + aliases->signalOffset)) {
- QMetaObject::activate(object, id, a);
- return id;
- } else 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 45fb33d..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, const QByteArray &aliasData, QmlRefCount * = 0);
+ QmlVMEMetaObject(QObject *, const QMetaObject *, QList<QString> *, int slotData, const QmlVMEMetaData *data, QmlRefCount * = 0);
~QmlVMEMetaObject();
protected:
@@ -72,26 +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;
- QByteArray aliasData;
- struct Aliases {
- int aliasCount;
- int propCount;
- int signalOffset;
- } *aliases;
- struct AliasArray {
- int contextIdx;
- int propIdx;
- } *aliasArray;
+
};
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);