aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util/qquickpropertychanges.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/util/qquickpropertychanges.cpp')
-rw-r--r--src/quick/util/qquickpropertychanges.cpp193
1 files changed, 88 insertions, 105 deletions
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index 1a631703fb..5b5b8cac3c 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -204,7 +204,7 @@ public:
isExplicit(false) {}
QPointer<QObject> object;
- QByteArray data;
+ QList<const QV4::CompiledData::Binding *> bindings;
QQmlRefPointer<QQmlCompiledData> cdata;
bool decoded : 1;
@@ -212,6 +212,7 @@ public:
bool isExplicit : 1;
void decode();
+ void decodeBinding(const QString &propertyPrefix, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding);
class ExpressionChange {
public:
@@ -237,10 +238,8 @@ public:
QQmlProperty property(const QString &);
};
-void QQuickPropertyChangesParser::compileList(QList<QPair<QString, const QV4::CompiledData::Binding*> > &list, const QString &pre, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding)
+void QQuickPropertyChangesParser::verifyList(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding)
{
- QString propName = pre + qmlUnit->header.stringAt(binding->propertyNameIndex);
-
if (binding->type == QV4::CompiledData::Binding::Type_Object) {
error(qmlUnit->objectAt(binding->value.objectIndex), QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
return;
@@ -248,129 +247,105 @@ void QQuickPropertyChangesParser::compileList(QList<QPair<QString, const QV4::Co
if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
|| binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- QString pre = propName + QLatin1Char('.');
const QV4::CompiledData::Object *subObj = qmlUnit->objectAt(binding->value.objectIndex);
const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
- compileList(list, pre, qmlUnit, subBinding);
+ verifyList(qmlUnit, subBinding);
}
- return;
}
-
- list << qMakePair(propName, binding);
}
-QByteArray QQuickPropertyChangesParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
+void QQuickPropertyChangesPrivate::decode()
{
- QList<QPair<QString, const QV4::CompiledData::Binding *> > data;
- for (int ii = 0; ii < props.count(); ++ii)
- compileList(data, QString(), qmlUnit, props.at(ii));
-
- QByteArray rv;
- QDataStream ds(&rv, QIODevice::WriteOnly);
-
- ds << data.count();
- for (int ii = 0; ii < data.count(); ++ii) {
- const QV4::CompiledData::Binding *binding = data.at(ii).second;
- ds << data.at(ii).first << int(binding->type);
- QVariant var;
- switch (binding->type) {
- case QV4::CompiledData::Binding::Type_Script:
- ds << bindingIdentifier(binding);
- // Fall through as we also need the expression string.
- // Signal handlers still need to be constructed by string ;(
- case QV4::CompiledData::Binding::Type_String:
- var = binding->valueAsString(&qmlUnit->header);
- break;
- case QV4::CompiledData::Binding::Type_Number:
- var = binding->valueAsNumber();
- break;
- case QV4::CompiledData::Binding::Type_Boolean:
- var = binding->valueAsBoolean();
- break;
- case QV4::CompiledData::Binding::Type_Translation:
- case QV4::CompiledData::Binding::Type_TranslationById:
- ds << binding->value.translationData.commentIndex << binding->value.translationData.number;
- var = binding->stringIndex;
- default:
- break;
- }
- ds << var;
- }
+ if (decoded)
+ return;
+
+ foreach (const QV4::CompiledData::Binding *binding, bindings)
+ decodeBinding(QString(), cdata->qmlUnit, binding);
+
+ bindings.clear();
- return rv;
+ decoded = true;
}
-void QQuickPropertyChangesPrivate::decode()
+void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding)
{
Q_Q(QQuickPropertyChanges);
- if (decoded)
- return;
- QDataStream ds(&data, QIODevice::ReadOnly);
+ QString propertyName = propertyPrefix + qmlUnit->header.stringAt(binding->propertyNameIndex);
- int count;
- ds >> count;
- for (int ii = 0; ii < count; ++ii) {
- QString name;
- int type;
- QVariant data;
- QQmlBinding::Identifier id = QQmlBinding::Invalid;
- QV4::CompiledData::TranslationData tsd;
- ds >> name;
- ds >> type;
-
- if (type == QV4::CompiledData::Binding::Type_Script) {
- ds >> id;
- } else if (type == QV4::CompiledData::Binding::Type_Translation
- || type == QV4::CompiledData::Binding::Type_TranslationById) {
- ds >> tsd.commentIndex >> tsd.number;
+ if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
+ || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ QString pre = propertyName + QLatin1Char('.');
+ const QV4::CompiledData::Object *subObj = qmlUnit->objectAt(binding->value.objectIndex);
+ const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
+ for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
+ decodeBinding(pre, qmlUnit, subBinding);
}
+ return;
+ }
- ds >> data;
-
- QQmlProperty prop = property(name); //### better way to check for signal property?
- if (prop.type() & QQmlProperty::SignalProperty) {
- QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
- handler->property = prop;
- handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
- QQmlContextData::get(qmlContext(q)), object, cdata->functionForBindingId(id)));
- signalReplacements << handler;
- } else if (type == QV4::CompiledData::Binding::Type_Script) { // binding
- QString expression = data.toString();
- QUrl url = QUrl();
- int line = -1;
- int column = -1;
-
- QQmlData *ddata = QQmlData::get(q);
- if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
- url = ddata->outerContext->url;
- line = ddata->lineNumber;
- column = ddata->columnNumber;
- }
+ QQmlProperty prop = property(propertyName); //### better way to check for signal property?
- expressions << ExpressionChange(name, id, expression, url, line, column);
- } else {
- if (type == QV4::CompiledData::Binding::Type_Translation
- || type == QV4::CompiledData::Binding::Type_TranslationById) {
- QV4::CompiledData::Binding tmpBinding;
- tmpBinding.type = type;
- tmpBinding.stringIndex = data.toInt();
- tmpBinding.value.translationData = tsd;
- data = tmpBinding.valueAsString(&cdata->qmlUnit->header);
- }
- properties << qMakePair(name, data);
+ if (prop.type() & QQmlProperty::SignalProperty) {
+ QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
+ handler->property = prop;
+ handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
+ QQmlContextData::get(qmlContext(q)), object, cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]));
+ signalReplacements << handler;
+ return;
+ }
+
+ if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ QString expression = binding->valueAsString(&qmlUnit->header);
+ QUrl url = QUrl();
+ int line = -1;
+ int column = -1;
+
+ QQmlData *ddata = QQmlData::get(q);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
+ url = ddata->outerContext->url;
+ line = ddata->lineNumber;
+ column = ddata->columnNumber;
}
+
+ expressions << ExpressionChange(propertyName, binding->value.compiledScriptIndex, expression, url, line, column);
+ return;
}
- decoded = true;
- data.clear();
+
+ QVariant var;
+ switch (binding->type) {
+ case QV4::CompiledData::Binding::Type_Script:
+ Q_UNREACHABLE();
+ case QV4::CompiledData::Binding::Type_Translation:
+ case QV4::CompiledData::Binding::Type_TranslationById:
+ case QV4::CompiledData::Binding::Type_String:
+ var = binding->valueAsString(&qmlUnit->header);
+ break;
+ case QV4::CompiledData::Binding::Type_Number:
+ var = binding->valueAsNumber();
+ break;
+ case QV4::CompiledData::Binding::Type_Boolean:
+ var = binding->valueAsBoolean();
+ break;
+ default:
+ break;
+ }
+
+ properties << qMakePair(propertyName, var);
}
-void QQuickPropertyChangesParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *cdata)
+void QQuickPropertyChangesParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
+{
+ for (int ii = 0; ii < props.count(); ++ii)
+ verifyList(qmlUnit, props.at(ii));
+}
+
+void QQuickPropertyChangesParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
{
QQuickPropertyChangesPrivate *p =
- static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(object));
- p->data = data;
+ static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(obj));
+ p->bindings = bindings;
p->cdata = cdata;
p->decoded = false;
}
@@ -479,9 +454,17 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
a.specifiedObject = d->object;
a.specifiedProperty = property;
- QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0;
+ QQmlContextData *context = QQmlContextData::get(qmlContext(this));
+
+ QQmlBinding *newBinding = 0;
+ if (e.id != QQmlBinding::Invalid) {
+ QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
+ QV4::ScopedValue function(scope, QV4::QmlBindingWrapper::createQmlCallableForFunction(context, object(), d->cdata->compilationUnit->runtimeFunctions[e.id]));
+ newBinding = new QQmlBinding(function, object(), context);
+ }
+// QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0;
if (!newBinding)
- newBinding = new QQmlBinding(e.expression, object(), QQmlContextData::get(qmlContext(this)), e.url.toString(), e.line, e.column);
+ newBinding = new QQmlBinding(e.expression, object(), context, e.url.toString(), e.line, e.column);
if (d->isExplicit) {
// in this case, we don't want to assign a binding, per se,