diff options
author | Bea Lam <bea.lam@nokia.com> | 2011-01-27 05:34:34 (GMT) |
---|---|---|
committer | Bea Lam <bea.lam@nokia.com> | 2011-01-27 05:37:10 (GMT) |
commit | 43b8305367156c1ceb09eb4a056bdae3f325b5eb (patch) | |
tree | 8d792838920476495cba22c802939b719619a55d /src/declarative | |
parent | 357f1163f75e4b23a5b87dd6b3d742d167cd9c10 (diff) | |
download | Qt-43b8305367156c1ceb09eb4a056bdae3f325b5eb.zip Qt-43b8305367156c1ceb09eb4a056bdae3f325b5eb.tar.gz Qt-43b8305367156c1ceb09eb4a056bdae3f325b5eb.tar.bz2 |
Allow property bindings to be easily created from JavaScript
Properties can now be assigned a function that returns the binding
value.
Task-number: QTBUG-14964
Reviewed-by: Aaron Kennedy
Diffstat (limited to 'src/declarative')
-rw-r--r-- | src/declarative/qml/qdeclarativebinding.cpp | 20 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativebinding_p.h | 9 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeexpression.cpp | 41 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeexpression.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeexpression_p.h | 12 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeobjectscriptclass.cpp | 19 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeproperty.cpp | 25 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeproperty_p.h | 5 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativevaluetypescriptclass.cpp | 32 |
9 files changed, 149 insertions, 17 deletions
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index b2d0738..a5bd604 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -274,6 +274,13 @@ QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDecl setNotifyOnValueChanged(true); } +QDeclarativeBinding::QDeclarativeBinding(const QScriptValue &func, QObject *obj, QDeclarativeContextData *ctxt, QObject *parent) +: QDeclarativeExpression(ctxt, obj, func, *new QDeclarativeBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + QDeclarativeBinding::~QDeclarativeBinding() { } @@ -292,6 +299,19 @@ QDeclarativeProperty QDeclarativeBinding::property() const return d->property; } +void QDeclarativeBinding::setEvaluateFlags(EvaluateFlags flags) +{ + Q_D(QDeclarativeBinding); + d->setEvaluateFlags(QDeclarativeQtScriptExpression::EvaluateFlags(static_cast<int>(flags))); +} + +QDeclarativeBinding::EvaluateFlags QDeclarativeBinding::evaluateFlags() const +{ + Q_D(const QDeclarativeBinding); + return QDeclarativeBinding::EvaluateFlags(static_cast<int>(d->evaluateFlags())); +} + + class QDeclarativeBindingProfiler { public: QDeclarativeBindingProfiler(QDeclarativeBinding *bind) diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h index 19e7099..0260b95 100644 --- a/src/declarative/qml/qdeclarativebinding_p.h +++ b/src/declarative/qml/qdeclarativebinding_p.h @@ -147,14 +147,21 @@ class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeBinding : public QDeclarativeExpr { Q_OBJECT public: + enum EvaluateFlag { RequiresThisObject = 0x01 }; + Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag) + QDeclarativeBinding(const QString &, QObject *, QDeclarativeContext *, QObject *parent=0); QDeclarativeBinding(const QString &, QObject *, QDeclarativeContextData *, QObject *parent=0); QDeclarativeBinding(void *, QDeclarativeRefCount *, QObject *, QDeclarativeContextData *, const QString &, int, QObject *parent); + QDeclarativeBinding(const QScriptValue &, QObject *, QDeclarativeContextData *, QObject *parent=0); void setTarget(const QDeclarativeProperty &); QDeclarativeProperty property() const; + void setEvaluateFlags(EvaluateFlags flags); + EvaluateFlags evaluateFlags() const; + bool enabled() const; // Inherited from QDeclarativeAbstractBinding @@ -177,6 +184,8 @@ private: Q_DECLARE_PRIVATE(QDeclarativeBinding) }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeBinding::EvaluateFlags) + QT_END_NAMESPACE Q_DECLARE_METATYPE(QDeclarativeBinding*) diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp index 26c91a5..7a85ada 100644 --- a/src/declarative/qml/qdeclarativeexpression.cpp +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -103,6 +103,19 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QS expressionFunctionValid = false; } +void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QScriptValue &func, + QObject *me) +{ + expression = func.toString(); + + QDeclarativeAbstractExpression::setContext(ctxt); + scopeObject = me; + + expressionFunction = func; + expressionFunctionMode = ExplicitContext; + expressionFunctionValid = true; +} + void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, QDeclarativeRefCount *rc, QObject *me, const QString &srcUrl, int lineNumber) @@ -304,6 +317,19 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } +/*! \internal */ +QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QScriptValue &func, + QDeclarativeExpressionPrivate &dd) +: QObject(dd, 0) +{ + Q_D(QDeclarativeExpression); + d->init(ctxt, func, scope); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); +} + /*! Destroy the QDeclarativeExpression instance. */ @@ -412,6 +438,16 @@ void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notify } } +void QDeclarativeQtScriptExpression::setEvaluateFlags(EvaluateFlags flags) +{ + evalFlags = flags; +} + +QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::evaluateFlags() const +{ + return evalFlags; +} + QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined) { Q_ASSERT(context() && context()->engine); @@ -476,7 +512,10 @@ QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope); } - QScriptValue svalue = expressionFunction.call(); // This could cause this to be deleted + QScriptValue thisObject; + if (evalFlags & RequiresThisObject) + thisObject = ep->objectClass->newQObject(scopeObject); + QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted if (isShared) { ep->sharedContext = oldSharedContext; diff --git a/src/declarative/qml/qdeclarativeexpression.h b/src/declarative/qml/qdeclarativeexpression.h index 72c5947..d40094b 100644 --- a/src/declarative/qml/qdeclarativeexpression.h +++ b/src/declarative/qml/qdeclarativeexpression.h @@ -59,6 +59,7 @@ class QDeclarativeEngine; class QDeclarativeContext; class QDeclarativeExpressionPrivate; class QDeclarativeContextData; +class QScriptValue; class Q_DECLARATIVE_EXPORT QDeclarativeExpression : public QObject { Q_OBJECT @@ -94,6 +95,8 @@ Q_SIGNALS: protected: QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &, QDeclarativeExpressionPrivate &dd); + QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QScriptValue &, + QDeclarativeExpressionPrivate &dd); QDeclarativeExpression(QDeclarativeContextData *, void *, QDeclarativeRefCount *rc, QObject *me, const QString &, int, QDeclarativeExpressionPrivate &dd); diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h index 1d25609..51cae0f 100644 --- a/src/declarative/qml/qdeclarativeexpression_p.h +++ b/src/declarative/qml/qdeclarativeexpression_p.h @@ -113,6 +113,9 @@ class QDeclarativeQtScriptExpression : public QDeclarativeAbstractExpression, public: enum Mode { SharedContext, ExplicitContext }; + enum EvaluateFlag { RequiresThisObject = 0x01 }; + Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag) + QDeclarativeQtScriptExpression(); virtual ~QDeclarativeQtScriptExpression(); @@ -131,6 +134,9 @@ public: void resetNotifyOnChange(); void setNotifyObject(QObject *, int ); + void setEvaluateFlags(EvaluateFlags flags); + EvaluateFlags evaluateFlags() const; + QScriptValue scriptValue(QObject *secondaryScope, bool *isUndefined); class DeleteWatcher { @@ -157,8 +163,13 @@ private: QObject *guardObject; int guardObjectNotifyIndex; bool *deleted; + + EvaluateFlags evalFlags; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeQtScriptExpression::EvaluateFlags) + + class QDeclarativeExpression; class QString; class QDeclarativeExpressionPrivate : public QObjectPrivate, public QDeclarativeQtScriptExpression @@ -169,6 +180,7 @@ public: ~QDeclarativeExpressionPrivate(); void init(QDeclarativeContextData *, const QString &, QObject *); + void init(QDeclarativeContextData *, const QScriptValue &, QObject *); void init(QDeclarativeContextData *, void *, QDeclarativeRefCount *, QObject *, const QString &, int); QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index cbbf2b9..7701a23 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -359,8 +359,20 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj, } } + QDeclarativeBinding *newBinding = 0; + if (value.isFunction() && !value.isRegExp()) { + QScriptContextInfo ctxtInfo(context); + QDeclarativePropertyCache::ValueTypeData valueTypeData; + + newBinding = new QDeclarativeBinding(value, obj, evalContext); + newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber()); + newBinding->setTarget(QDeclarativePropertyPrivate::restore(*lastData, valueTypeData, obj, evalContext)); + if (newBinding->expression().contains("this")) + newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject); + } + QDeclarativeAbstractBinding *delBinding = - QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, 0); + QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, newBinding); if (delBinding) delBinding->destroy(); @@ -379,10 +391,7 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj, QString error = QLatin1String("Cannot assign [undefined] to ") + QLatin1String(QMetaType::typeName(lastData->propType)); context->throwError(error); - } else if (!value.isRegExp() && value.isFunction()) { - QString error = QLatin1String("Cannot assign a function to a property."); - context->throwError(error); - } else { + } else if (!value.isFunction()) { QVariant v; if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >()); diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index 76829b7..61e3002 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -1480,19 +1480,28 @@ QDeclarativePropertyPrivate::restore(const QByteArray &data, QObject *object, QD if (data.isEmpty()) return prop; - prop.d = new QDeclarativePropertyPrivate; - prop.d->object = object; - prop.d->context = ctxt; - prop.d->engine = ctxt->engine; - const SerializedData *sd = (const SerializedData *)data.constData(); if (sd->isValueType) { const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd; - prop.d->core = vt->core; - prop.d->valueType = vt->valueType; + return restore(vt->core, vt->valueType, object, ctxt); } else { - prop.d->core = sd->core; + QDeclarativePropertyCache::ValueTypeData data; + return restore(sd->core, data, object, ctxt); } +} + +QDeclarativeProperty +QDeclarativePropertyPrivate::restore(const QDeclarativePropertyCache::Data &data, const QDeclarativePropertyCache::ValueTypeData &valueType, QObject *object, QDeclarativeContextData *ctxt) +{ + QDeclarativeProperty prop; + + prop.d = new QDeclarativePropertyPrivate; + prop.d->object = object; + prop.d->context = ctxt; + prop.d->engine = ctxt->engine; + + prop.d->core = data; + prop.d->valueType = valueType; return prop; } diff --git a/src/declarative/qml/qdeclarativeproperty_p.h b/src/declarative/qml/qdeclarativeproperty_p.h index fa0fef4..bd2c891 100644 --- a/src/declarative/qml/qdeclarativeproperty_p.h +++ b/src/declarative/qml/qdeclarativeproperty_p.h @@ -112,7 +112,12 @@ public: static QByteArray saveValueType(const QMetaObject *, int, const QMetaObject *, int); static QByteArray saveProperty(const QMetaObject *, int); + static QDeclarativeProperty restore(const QByteArray &, QObject *, QDeclarativeContextData *); + static QDeclarativeProperty restore(const QDeclarativePropertyCache::Data &, + const QDeclarativePropertyCache::ValueTypeData &, + QObject *, + QDeclarativeContextData *); static bool equal(const QMetaObject *, const QMetaObject *); static bool canConvert(const QMetaObject *from, const QMetaObject *to); diff --git a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp index 558ef90..200cc1c 100644 --- a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp +++ b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp @@ -46,6 +46,8 @@ #include "private/qdeclarativeengine_p.h" #include "private/qdeclarativeguard_p.h" +#include <QtScript/qscriptcontextinfo.h> + QT_BEGIN_NAMESPACE struct QDeclarativeValueTypeObject : public QScriptDeclarativeClass::Object { @@ -161,17 +163,41 @@ void QDeclarativeValueTypeScriptClass::setProperty(Object *obj, const Identifier if (o->objectType == QDeclarativeValueTypeObject::Reference) { QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj); + ref->type->read(ref->object, ref->property); + QMetaProperty p = ref->type->metaObject()->property(m_lastIndex); + + QDeclarativeBinding *newBinding = 0; + if (value.isFunction() && !value.isRegExp()) { + QDeclarativeContextData *ctxt = QDeclarativeEnginePrivate::get(engine)->getContext(context()); + + QDeclarativePropertyCache::Data cacheData; + cacheData.flags = QDeclarativePropertyCache::Data::IsWritable; + cacheData.propType = ref->object->metaObject()->property(ref->property).userType(); + cacheData.coreIndex = ref->property; + + QDeclarativePropertyCache::ValueTypeData valueTypeData; + valueTypeData.valueTypeCoreIdx = m_lastIndex; + valueTypeData.valueTypePropType = p.userType(); + + newBinding = new QDeclarativeBinding(value, ref->object, ctxt); + QScriptContextInfo ctxtInfo(context()); + newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber()); + QDeclarativeProperty prop = QDeclarativePropertyPrivate::restore(cacheData, valueTypeData, ref->object, ctxt); + newBinding->setTarget(prop); + if (newBinding->expression().contains("this")) + newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject); + } + QDeclarativeAbstractBinding *delBinding = - QDeclarativePropertyPrivate::setBinding(ref->object, ref->property, m_lastIndex, 0); + QDeclarativePropertyPrivate::setBinding(ref->object, ref->property, m_lastIndex, newBinding); if (delBinding) delBinding->destroy(); - ref->type->read(ref->object, ref->property); - QMetaProperty p = ref->type->metaObject()->property(m_lastIndex); if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double) v = v.toInt(); p.write(ref->type, v); ref->type->write(ref->object, ref->property, 0); + } else { QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj); copy->type->setValue(copy->value); |