public:
QQmlValueType(int userType, QObject *parent = 0);
virtual void read(QObject *, int) = 0;
+ virtual void readVariantValue(QObject *, int, QVariant *) = 0;
virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags flags) = 0;
+ virtual void writeVariantValue(QObject *, int, QQmlPropertyPrivate::WriteFlags, QVariant *) = 0;
virtual QVariant value() = 0;
virtual void setValue(const QVariant &) = 0;
readProperty(obj, idx, &v);
}
+ virtual void readVariantValue(QObject *obj, int idx, QVariant *into)
+ {
+ // important: must not change the userType of the variant
+ readProperty(obj, idx, into);
+ }
+
virtual void write(QObject *obj, int idx, QQmlPropertyPrivate::WriteFlags flags)
{
writeProperty(obj, idx, flags, &v);
}
+ virtual void writeVariantValue(QObject *obj, int idx, QQmlPropertyPrivate::WriteFlags flags, QVariant *from)
+ {
+ writeProperty(obj, idx, flags, from);
+ }
+
virtual QVariant value()
{
- return QVariant(v);
+ return QVariant::fromValue(v);
}
virtual void setValue(const QVariant &value)
virtual bool isEqual(const QVariant &other) const
{
- return QVariant(v) == other;
+ return QVariant::fromValue(v) == other;
}
protected:
return rv;
}
+static bool readReferenceValue(QV8ValueTypeReferenceResource *reference)
+{
+ // A reference resource may be either a "true" reference (eg, to a QVector3D property)
+ // or a "variant" reference (eg, to a QVariant property which happens to contain a value-type).
+ QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property);
+ if (writebackProperty.userType() == QMetaType::QVariant) {
+ // variant-containing-value-type reference
+ QVariant variantReferenceValue;
+ reference->type->readVariantValue(reference->object, reference->property, &variantReferenceValue);
+ int variantReferenceType = variantReferenceValue.userType();
+ if (variantReferenceType != reference->type->userType()) {
+ // This is a stale VariantReference. That is, the variant has been
+ // overwritten with a different type in the meantime.
+ // We need to modify this reference to the updated value type, if
+ // possible, or return false if it is not a value type.
+ QQmlEngine *e = reference->engine->engine();
+ if (QQmlValueTypeFactory::isValueType(variantReferenceType) && e) {
+ reference->type = QQmlEnginePrivate::get(e)->valueTypes[variantReferenceType];
+ if (!reference->type) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ reference->type->setValue(variantReferenceValue);
+ } else {
+ // value-type reference
+ reference->type->read(reference->object, reference->property);
+ }
+ return true;
+}
+
QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj, int typeHint, bool *succeeded)
{
// NOTE: obj must not be an external resource object (ie, wrapper object)
if (resource->objectType == QV8ValueTypeResource::Reference) {
QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
- if (reference->object) {
- reference->type->read(reference->object, reference->property);
+ if (reference->object && readReferenceValue(reference)) {
return reference->type->value();
} else {
return QVariant();
if (resource->objectType == QV8ValueTypeResource::Reference) {
QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
- if (reference->object) {
- reference->type->read(reference->object, reference->property);
+ if (reference->object && readReferenceValue(reference)) {
return reference->type->isEqual(value);
} else {
return false;
if (resource) {
if (resource->objectType == QV8ValueTypeResource::Reference) {
QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
- if (reference->object) {
- reference->type->read(reference->object, reference->property);
+ if (reference->object && readReferenceValue(reference)) {
return resource->engine->toString(resource->type->toString());
} else {
return v8::Undefined();
}
}
+ // Note: readReferenceValue() can change the reference->type.
+ if (r->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
+
+ if (!reference->object || !readReferenceValue(reference))
+ return v8::Handle<v8::Value>();
+
+ } else {
+ Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
+
+ r->type->setValue(copy->value);
+ }
+
QQmlPropertyData local;
QQmlPropertyData *result = 0;
{
if (!result)
return v8::Handle<v8::Value>();
- if (r->objectType == QV8ValueTypeResource::Reference) {
- QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
-
- if (!reference->object)
- return v8::Handle<v8::Value>();
-
- r->type->read(reference->object, reference->property);
- } else {
- Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
-
- QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
-
- r->type->setValue(copy->value);
- }
-
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
if (result->propType == metatype) { \
cpptype v; \
if (!r) return value;
QByteArray propName = r->engine->toString(property).toUtf8();
- int index = r->type->metaObject()->indexOfProperty(propName.constData());
- if (index == -1)
- return value;
-
if (r->objectType == QV8ValueTypeResource::Reference) {
QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
+ QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property);
- if (!reference->object ||
- !reference->object->metaObject()->property(reference->property).isWritable())
+ if (!reference->object || !writebackProperty.isWritable() || !readReferenceValue(reference))
return value;
- r->type->read(reference->object, reference->property);
+ // we lookup the index after readReferenceValue() since it can change the reference->type.
+ int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ if (index == -1)
+ return value;
QMetaProperty p = r->type->metaObject()->property(index);
QQmlBinding *newBinding = 0;
p.write(reference->type, v);
- reference->type->write(reference->object, reference->property, 0);
+ if (writebackProperty.userType() == QMetaType::QVariant) {
+ QVariant variantReferenceValue = r->type->value();
+ reference->type->writeVariantValue(reference->object, reference->property, 0, &variantReferenceValue);
+ } else {
+ reference->type->write(reference->object, reference->property, 0);
+ }
}
} else {
QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
+ int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ if (index == -1)
+ return value;
+
QVariant v = r->engine->toVariant(value, -1);
r->type->setValue(copy->value);
--- /dev/null
+import QtQuick 2.0
+
+Item {
+ property bool complete: false
+ property bool success: false
+
+ property variant v1
+
+ Component.onCompleted: {
+ complete = false;
+ success = true;
+
+ // store a js reference to the VariantReference vt in a temp var.
+ v1 = Qt.vector3d(1,2,3)
+ var ref = v1;
+ ref.z = 5
+ if (v1 != Qt.vector3d(1,2,5)) success = false;
+
+ // now change the type of a reference, and attempt a valid write.
+ v1 = Qt.vector2d(1,2);
+ ref.x = 5;
+ if (v1 != Qt.vector2d(5,2)) success = false;
+
+ // now change the type of a reference, and attempt an invalid write.
+ v1 = Qt.rgba(1,0,0,1);
+ ref.x = 5;
+ if (v1.toString() != Qt.rgba(1,0,0,1).toString()) success = false;
+ v1 = 6;
+ ref.x = 5;
+ if (v1 != 6) success = false;
+
+ // now change the type of a reference, and attempt an invalid read.
+ v1 = Qt.vector3d(1,2,3);
+ ref = v1;
+ v1 = Qt.vector2d(1,2);
+ if (ref.z == 3) success = false;
+
+ complete = true;
+ }
+}