diff options
Diffstat (limited to 'src/quick/util/qquickpropertychanges.cpp')
-rw-r--r-- | src/quick/util/qquickpropertychanges.cpp | 193 |
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, |