summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/declarative/qml/qml.pri6
-rw-r--r--src/declarative/qml/qmlcompiler.cpp141
-rw-r--r--src/declarative/qml/qmlcompiler_p.h15
-rw-r--r--src/declarative/qml/qmlengine.cpp143
-rw-r--r--src/declarative/qml/qmlengine_p.h24
-rw-r--r--src/declarative/qml/qmlinstruction.cpp6
-rw-r--r--src/declarative/qml/qmlinstruction_p.h9
-rw-r--r--src/declarative/qml/qmlmetaproperty.cpp216
-rw-r--r--src/declarative/qml/qmlmetaproperty.h9
-rw-r--r--src/declarative/qml/qmlmetaproperty_p.h15
-rw-r--r--src/declarative/qml/qmlparser.cpp8
-rw-r--r--src/declarative/qml/qmlparser_p.h2
-rw-r--r--src/declarative/qml/qmlvaluetype.cpp131
-rw-r--r--src/declarative/qml/qmlvaluetype_p.h110
-rw-r--r--src/declarative/qml/qmlvme.cpp47
-rw-r--r--tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt2
-rw-r--r--tests/auto/declarative/qmlparser/testtypes.h17
-rw-r--r--tests/auto/declarative/qmlparser/tst_qmlparser.cpp26
-rw-r--r--tests/auto/declarative/qmlparser/valueTypes.txt12
19 files changed, 813 insertions, 126 deletions
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index b71ca1f..1021dec 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -28,7 +28,8 @@ SOURCES += qml/qmlparser.cpp \
qml/qmlscriptparser.cpp \
qml/qmlenginedebug.cpp \
qml/qmlrewrite.cpp \
- qml/qmlbasicscript.cpp
+ qml/qmlbasicscript.cpp \
+ qml/qmlvaluetype.cpp
HEADERS += qml/qmlparser_p.h \
qml/qmlinstruction_p.h \
@@ -72,7 +73,8 @@ HEADERS += qml/qmlparser_p.h \
qml/qmlbasicscript_p.h \
qml/qmlenginedebug_p.h \
qml/qmlrewrite_p.h \
- qml/qpodvector_p.h
+ qml/qpodvector_p.h \
+ qml/qmlvaluetype_p.h
# for qtscript debugger
contains(QT_CONFIG, scripttools):QT += scripttools
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index 477e6a5..407314a 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -63,6 +63,7 @@
#include <private/qmlcomponent_p.h>
#include "parser/qmljsast_p.h"
#include <private/qmlvmemetaobject_p.h>
+#include "qmlmetaproperty_p.h"
#include "qmlscriptparser_p.h"
@@ -76,7 +77,7 @@ using namespace QmlParser;
Instantiate a new QmlCompiler.
*/
QmlCompiler::QmlCompiler()
-: output(0)
+: output(0), engine(0)
{
}
@@ -571,6 +572,7 @@ bool QmlCompiler::compile(QmlEngine *engine,
Object *root = unit->data.tree();
Q_ASSERT(root);
+ this->engine = engine;
compileTree(root);
if (!isError()) {
@@ -583,6 +585,7 @@ bool QmlCompiler::compile(QmlEngine *engine,
compileState = ComponentCompileState();
savedCompileStates.clear();
output = 0;
+ this->engine = 0;
return !isError();
}
@@ -877,6 +880,27 @@ void QmlCompiler::genObjectBody(QmlParser::Object *obj)
pop.line = prop->location.start.line;
output->bytecode << pop;
}
+
+ foreach(Property *prop, obj->valueTypeProperties) {
+ QmlInstruction fetch;
+ fetch.type = QmlInstruction::FetchValueType;
+ fetch.fetchValue.property = prop->index;
+ fetch.fetchValue.type = prop->type;
+ fetch.line = prop->location.start.line;
+
+ output->bytecode << fetch;
+
+ foreach(Property *vprop, prop->value->valueProperties) {
+ genPropertyAssignment(vprop, prop->value, prop);
+ }
+
+ QmlInstruction pop;
+ pop.type = QmlInstruction::PopValueType;
+ pop.fetchValue.property = prop->index;
+ pop.fetchValue.type = prop->type;
+ pop.line = prop->location.start.line;
+ output->bytecode << pop;
+ }
}
void QmlCompiler::genComponent(QmlParser::Object *obj)
@@ -1273,7 +1297,8 @@ void QmlCompiler::genListProperty(QmlParser::Property *prop,
}
void QmlCompiler::genPropertyAssignment(QmlParser::Property *prop,
- QmlParser::Object *obj)
+ QmlParser::Object *obj,
+ QmlParser::Property *valueTypeProperty)
{
for (int ii = 0; ii < prop->values.count(); ++ii) {
QmlParser::Value *v = prop->values.at(ii);
@@ -1314,12 +1339,19 @@ void QmlCompiler::genPropertyAssignment(QmlParser::Property *prop,
QmlInstruction store;
store.type = QmlInstruction::StoreValueSource;
store.line = v->object->location.start.line;
- store.assignValueSource.property = prop->index;
+ if (valueTypeProperty) {
+ store.assignValueSource.property = QmlMetaPropertyPrivate::saveValueType(valueTypeProperty->index, prop->index);
+ store.assignValueSource.owner = 1;
+ } else {
+ store.assignValueSource.property =
+ QmlMetaPropertyPrivate::saveProperty(prop->index);
+ store.assignValueSource.owner = 0;
+ }
output->bytecode << store;
} else if (v->type == Value::PropertyBinding) {
- genBindingAssignment(v, prop, obj);
+ genBindingAssignment(v, prop, obj, valueTypeProperty);
} else if (v->type == Value::Literal) {
@@ -1419,18 +1451,89 @@ bool QmlCompiler::buildGroupedProperty(QmlParser::Property *prop,
Q_ASSERT(prop->type != 0);
Q_ASSERT(prop->index != -1);
- // Load the nested property's meta type
- prop->value->metatype = QmlMetaType::metaObjectForType(prop->type);
- if (!prop->value->metatype)
- COMPILE_EXCEPTION(prop, "Cannot nest non-QObject property" << prop->name);
+ if (prop->type < QVariant::UserType) {
+ QmlEnginePrivate *ep =
+ static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine));
+ if (ep->valueTypes[prop->type]) {
+ COMPILE_CHECK(buildValueTypeProperty(ep->valueTypes[prop->type],
+ prop->value, ctxt.incr()));
+ obj->addValueTypeProperty(prop);
+ } else {
+ COMPILE_EXCEPTION(prop, "Invalid property access");
+ }
- obj->addGroupedProperty(prop);
+ } else {
+ // Load the nested property's meta type
+ prop->value->metatype = QmlMetaType::metaObjectForType(prop->type);
+ if (!prop->value->metatype)
+ COMPILE_EXCEPTION(prop, "Cannot nest non-QObject property" <<
+ prop->name);
- COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
+ obj->addGroupedProperty(prop);
+
+ COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
+ }
return true;
}
+bool QmlCompiler::buildValueTypeProperty(QObject *type,
+ QmlParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ if (obj->defaultProperty)
+ COMPILE_EXCEPTION(obj, "Invalid property use");
+ obj->metatype = type->metaObject();
+
+ foreach (Property *prop, obj->properties) {
+ int idx = type->metaObject()->indexOfProperty(prop->name.constData());
+ if (idx == -1)
+ COMPILE_EXCEPTION(prop, "Cannot assign to non-existant property");
+ QMetaProperty p = type->metaObject()->property(idx);
+ prop->index = idx;
+ prop->type = p.userType();
+
+ if (prop->value || prop->values.count() != 1)
+ COMPILE_EXCEPTION(prop, "Invalid property use");
+
+ Value *value = prop->values.at(0);
+
+ if (value->object) {
+ const QMetaObject *c =
+ output->types.at(value->object->type).metaObject();
+ bool isPropertyValue = false;
+ while (c && !isPropertyValue) {
+ isPropertyValue =
+ (c == &QmlPropertyValueSource::staticMetaObject);
+ c = c->superClass();
+ }
+
+ if (!isPropertyValue) {
+ COMPILE_EXCEPTION(prop, "Invalid property use");
+ } else {
+ COMPILE_CHECK(buildObject(value->object, ctxt));
+ value->type = Value::ValueSource;
+ }
+
+ } else if (value->value.isScript()) {
+ // ### Check for writability
+ BindingReference reference;
+ reference.expression = value->value;
+ reference.property = prop;
+ reference.value = value;
+ reference.bindingContext = ctxt;
+ reference.bindingContext.owner++;
+ addBindingReference(reference);
+ value->type = Value::PropertyBinding;
+ } else {
+ COMPILE_CHECK(testLiteralAssignment(p, value));
+ value->type = Value::Literal;
+ }
+ obj->addValueProperty(prop);
+ }
+
+ return true;
+}
// Build assignments to QML lists. QML lists are properties of type
// QList<T *> * and QmlList<T *> *.
@@ -1951,14 +2054,13 @@ bool QmlCompiler::buildBinding(QmlParser::Value *value,
void QmlCompiler::genBindingAssignment(QmlParser::Value *binding,
QmlParser::Property *prop,
- QmlParser::Object *obj)
+ QmlParser::Object *obj,
+ QmlParser::Property *valueTypeProperty)
{
Q_ASSERT(compileState.bindings.contains(binding));
const BindingReference &ref = compileState.bindings.value(binding);
- QMetaProperty mp = obj->metaObject()->property(prop->index);
-
QmlInstruction store;
int dataRef;
if (ref.compiledData.isEmpty()) {
@@ -1969,10 +2071,19 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding,
store.type = QmlInstruction::StoreCompiledBinding;
}
- store.assignBinding.property = prop->index;
+ Q_ASSERT(ref.bindingContext.owner == 0 ||
+ (ref.bindingContext.owner != 0 && valueTypeProperty));
+ if (ref.bindingContext.owner) {
+ store.assignBinding.property =
+ QmlMetaPropertyPrivate::saveValueType(valueTypeProperty->index,
+ prop->index);
+ } else {
+ store.assignBinding.property =
+ QmlMetaPropertyPrivate::saveProperty(prop->index);
+ }
store.assignBinding.value = dataRef;
- store.assignBinding.category = QmlMetaProperty::propertyCategory(mp);
store.assignBinding.context = ref.bindingContext.stack;
+ store.assignBinding.owner = ref.bindingContext.owner;
output->bytecode << store;
}
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index 86e6590..094c05a 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -141,9 +141,9 @@ private:
struct BindingContext {
BindingContext()
- : stack(0), object(0) {}
+ : stack(0), owner(0), object(0) {}
BindingContext(QmlParser::Object *o)
- : stack(0), object(o) {}
+ : stack(0), owner(0), object(o) {}
BindingContext incr() const {
BindingContext rv(object);
rv.stack = stack + 1;
@@ -151,6 +151,7 @@ private:
}
bool isSubContext() const { return stack != 0; }
int stack;
+ int owner;
QmlParser::Object *object;
};
@@ -171,6 +172,9 @@ private:
bool buildGroupedProperty(QmlParser::Property *prop,
QmlParser::Object *obj,
const BindingContext &ctxt);
+ bool buildValueTypeProperty(QObject *type,
+ QmlParser::Object *obj,
+ const BindingContext &ctxt);
bool buildListProperty(QmlParser::Property *prop,
QmlParser::Object *obj,
const BindingContext &ctxt);
@@ -208,12 +212,14 @@ private:
void genValueProperty(QmlParser::Property *prop, QmlParser::Object *obj);
void genListProperty(QmlParser::Property *prop, QmlParser::Object *obj);
void genPropertyAssignment(QmlParser::Property *prop,
- QmlParser::Object *obj);
+ QmlParser::Object *obj,
+ QmlParser::Property *valueTypeProperty = 0);
void genLiteralAssignment(const QMetaProperty &prop,
QmlParser::Value *value);
void genBindingAssignment(QmlParser::Value *binding,
QmlParser::Property *prop,
- QmlParser::Object *obj);
+ QmlParser::Object *obj,
+ QmlParser::Property *valueTypeProperty = 0);
int componentTypeRef();
@@ -257,6 +263,7 @@ private:
QList<QmlError> exceptions;
QmlCompiledData *output;
+ QmlEngine *engine;
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index c4b3c0d..6549e5c 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -149,6 +149,7 @@ void QmlEnginePrivate::init()
scriptEngine.installTranslatorFunctions();
contextClass = new QmlContextScriptClass(q);
objectClass = new QmlObjectScriptClass(q);
+ valueTypeClass = new QmlValueTypeScriptClass(q);
rootContext = new QmlContext(q,true);
#ifdef QT_SCRIPTTOOLS_LIB
if (qmlDebugger()){
@@ -190,7 +191,7 @@ Q_GLOBAL_STATIC(FunctionCache, functionCache);
QScriptClass::QueryFlags
QmlEnginePrivate::queryObject(const QString &propName,
- uint *id, QObject *obj)
+ uint *id, QObject *obj)
{
QScriptClass::QueryFlags rv = 0;
@@ -224,8 +225,15 @@ QmlEnginePrivate::queryObject(const QString &propName,
return rv;
}
+struct QmlValueTypeReference {
+ QmlValueType *type;
+ QGuard<QObject> object;
+ int property;
+};
+Q_DECLARE_METATYPE(QmlValueTypeReference);
+
QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName,
- QObject *obj, uint id)
+ QObject *obj, uint id)
{
if (id == QmlScriptClass::FunctionId) {
QScriptValue sobj = scriptEngine.newQObject(obj);
@@ -237,10 +245,20 @@ QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName,
if (!prop.isValid())
return QScriptValue();
- QVariant var = prop.read();
if (prop.needsChangedNotifier())
capturedProperties << CapturedProperty(prop);
- QObject *varobj = QmlMetaType::toQObject(var);
+
+ int propType = prop.propertyType();
+ if (propType < QVariant::UserType && valueTypes[propType]) {
+ QmlValueTypeReference ref;
+ ref.type = valueTypes[propType];
+ ref.object = obj;
+ ref.property = prop.coreIndex();
+ return scriptEngine.newObject(valueTypeClass, scriptEngine.newVariant(QVariant::fromValue(ref)));
+ }
+
+ QVariant var = prop.read();
+ QObject *varobj = (propType < QVariant::UserType)?0:QmlMetaType::toQObject(var);
if (!varobj)
varobj = qvariant_cast<QObject *>(var);
if (varobj) {
@@ -681,6 +699,32 @@ QmlScriptClass::QmlScriptClass(QmlEngine *bindengine)
{
}
+QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val)
+{
+ QmlEnginePrivate *ep =
+ static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine));
+
+ QScriptClass *sc = val.scriptClass();
+ if (!sc) {
+ return val.toVariant();
+ } else if (sc == ep->contextClass) {
+ return QVariant();
+ } else if (sc == ep->objectClass) {
+ return QVariant::fromValue(val.data().toQObject());
+ } else if (sc == ep->valueTypeClass) {
+ QmlValueTypeReference ref =
+ qvariant_cast<QmlValueTypeReference>(val.data().toVariant());
+
+ if (!ref.object)
+ return QVariant();
+
+ QMetaProperty p = ref.object->metaObject()->property(ref.property);
+ return p.read(ref.object);
+ }
+
+ return QVariant();
+}
+
/////////////////////////////////////////////////////////////
/*
The QmlContextScriptClass handles property access for a QmlContext
@@ -807,19 +851,88 @@ void QmlContextScriptClass::setProperty(QScriptValue &object,
QmlMetaProperty prop;
prop.restore(id, obj);
- QVariant v;
- QObject *data = value.data().toQObject();
- if (data) {
- v = QVariant::fromValue(data);
- } else {
- v = value.toVariant();
- }
+ QVariant v = QmlScriptClass::toVariant(engine, value);
prop.write(v);
scriptEngine->currentContext()->setActivationObject(oldact);
}
/////////////////////////////////////////////////////////////
+QmlValueTypeScriptClass::QmlValueTypeScriptClass(QmlEngine *bindEngine)
+: QmlScriptClass(bindEngine)
+{
+}
+
+QmlValueTypeScriptClass::~QmlValueTypeScriptClass()
+{
+}
+
+QmlValueTypeScriptClass::QueryFlags
+QmlValueTypeScriptClass::queryProperty(const QScriptValue &object,
+ const QScriptString &name,
+ QueryFlags flags, uint *id)
+{
+ QmlValueTypeReference ref =
+ qvariant_cast<QmlValueTypeReference>(object.data().toVariant());
+
+ if (!ref.object)
+ return 0;
+
+ QByteArray propName = name.toString().toUtf8();
+
+ int idx = ref.type->metaObject()->indexOfProperty(propName.constData());
+ if (idx == -1)
+ return 0;
+ *id = idx;
+
+ QMetaProperty prop = ref.object->metaObject()->property(idx);
+
+ QmlValueTypeScriptClass::QueryFlags rv =
+ QmlValueTypeScriptClass::HandlesReadAccess;
+ if (prop.isWritable())
+ rv |= QmlValueTypeScriptClass::HandlesWriteAccess;
+
+ return rv;
+}
+
+QScriptValue QmlValueTypeScriptClass::property(const QScriptValue &object,
+ const QScriptString &name,
+ uint id)
+{
+ QmlValueTypeReference ref =
+ qvariant_cast<QmlValueTypeReference>(object.data().toVariant());
+
+ if (!ref.object)
+ return QScriptValue();
+
+ ref.type->read(ref.object, ref.property);
+
+ QMetaProperty p = ref.type->metaObject()->property(id);
+ QVariant rv = p.read(ref.type);
+
+ return static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine))->scriptEngine.newVariant(rv);
+}
+
+void QmlValueTypeScriptClass::setProperty(QScriptValue &object,
+ const QScriptString &name,
+ uint id,
+ const QScriptValue &value)
+{
+ QmlValueTypeReference ref =
+ qvariant_cast<QmlValueTypeReference>(object.data().toVariant());
+
+ if (!ref.object)
+ return;
+
+ QVariant v = QmlScriptClass::toVariant(engine, value);
+
+ ref.type->read(ref.object, ref.property);
+ QMetaProperty p = ref.type->metaObject()->property(id);
+ p.write(ref.type, v);
+ ref.type->write(ref.object, ref.property);
+}
+
+/////////////////////////////////////////////////////////////
/*
The QmlObjectScriptClass handles property access for QObjects
via QtScript. It is also used to provide a more useful API in
@@ -916,13 +1029,7 @@ void QmlObjectScriptClass::setProperty(QScriptValue &object,
QmlMetaProperty prop;
prop.restore(id, obj);
- QVariant v;
- QObject *data = value.data().toQObject();
- if (data) {
- v = QVariant::fromValue(data);
- } else {
- v = value.toVariant();
- }
+ QVariant v = QmlScriptClass::toVariant(engine, value);
prop.write(v);
scriptEngine->currentContext()->setActivationObject(oldact);
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index 47d2397..af561e7 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -66,6 +66,7 @@
#include <private/qpodvector_p.h>
#include <QtDeclarative/qml.h>
#include <private/qmlbasicscript_p.h>
+#include <private/qmlvaluetype_p.h>
#include <QtDeclarative/qmlcontext.h>
#include <QtDeclarative/qmlengine.h>
#include <QtDeclarative/qmlexpression.h>
@@ -80,6 +81,7 @@ class QmlExpression;
class QmlBasicScriptNodeCache;
class QmlContextScriptClass;
class QmlObjectScriptClass;
+class QmlValueTypeScriptClass;
class QScriptEngineDebugger;
class QNetworkReply;
class QNetworkAccessManager;
@@ -120,6 +122,7 @@ public:
QmlContextScriptClass *contextClass;
QmlObjectScriptClass *objectClass;
+ QmlValueTypeScriptClass *valueTypeClass;
QmlContext *setCurrentBindContext(QmlContext *);
QStack<QmlContext *> activeContexts;
@@ -167,6 +170,8 @@ public:
quint32 getUniqueId() const {
return uniqueId++;
}
+
+ QmlValueTypeFactory valueTypes;
};
class QmlScriptClass : public QScriptClass
@@ -187,6 +192,7 @@ public:
QmlScriptClass(QmlEngine *);
+ static QVariant toVariant(QmlEngine *, const QScriptValue &);
protected:
QmlEngine *engine;
};
@@ -230,6 +236,24 @@ public:
const QScriptValue &value);
};
+class QmlValueTypeScriptClass : public QmlScriptClass
+{
+public:
+ QmlValueTypeScriptClass(QmlEngine *);
+ ~QmlValueTypeScriptClass();
+
+ virtual QueryFlags queryProperty(const QScriptValue &object,
+ const QScriptString &name,
+ QueryFlags flags, uint *id);
+ virtual QScriptValue property(const QScriptValue &object,
+ const QScriptString &name,
+ uint id);
+ virtual void setProperty(QScriptValue &object,
+ const QScriptString &name,
+ uint id,
+ const QScriptValue &value);
+};
+
QT_END_NAMESPACE
#endif // QMLENGINE_P_H
diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp
index 83fb18b..761903c 100644
--- a/src/declarative/qml/qmlinstruction.cpp
+++ b/src/declarative/qml/qmlinstruction.cpp
@@ -176,12 +176,18 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx)
case QmlInstruction::FetchObject:
qWarning() << idx << "\t" << line << "\t" << "FETCH\t\t\t" << instr->fetch.property;
break;
+ case QmlInstruction::FetchValueType:
+ qWarning() << idx << "\t" << line << "\t" << "FETCH_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type;
+ break;
case QmlInstruction::PopFetchedObject:
qWarning() << idx << "\t" << line << "\t" << "POP";
break;
case QmlInstruction::PopQList:
qWarning() << idx << "\t" << line << "\t" << "POP_QLIST";
break;
+ case QmlInstruction::PopValueType:
+ qWarning() << idx << "\t" << line << "\t" << "POP_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type;
+ break;
case QmlInstruction::Defer:
qWarning() << idx << "\t" << line << "\t" << "DEFER" << "\t\t" << instr->defer.deferCount;
break;
diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h
index a7221c0..dc118b6 100644
--- a/src/declarative/qml/qmlinstruction_p.h
+++ b/src/declarative/qml/qmlinstruction_p.h
@@ -139,6 +139,7 @@ public:
FetchQmlList, /* fetchQmlList */
FetchQList, /* fetch */
FetchObject, /* fetch */
+ FetchValueType, /* fetchValue */
//
// Stack manipulation
@@ -147,6 +148,7 @@ public:
// PopQList - Remove a list from the list stack
PopFetchedObject,
PopQList,
+ PopValueType, /* fetchValue */
//
// Deferred creation
@@ -177,12 +179,13 @@ public:
} setId;
struct {
int property;
+ int owner;
} assignValueSource;
struct {
int property;
int value;
short context;
- short category;
+ short owner;
} assignBinding;
struct {
int property;
@@ -190,6 +193,10 @@ public:
struct {
int property;
int type;
+ } fetchValue;
+ struct {
+ int property;
+ int type;
} fetchQmlList;
struct {
int castValue;
diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp
index daa4242..60b4ac6 100644
--- a/src/declarative/qml/qmlmetaproperty.cpp
+++ b/src/declarative/qml/qmlmetaproperty.cpp
@@ -49,6 +49,8 @@
#include "qmlboundsignal_p.h"
#include <math.h>
#include <QtCore/qdebug.h>
+#include <QtDeclarative/qmlengine.h>
+#include <private/qmlengine_p.h>
Q_DECLARE_METATYPE(QList<QObject *>);
@@ -162,16 +164,13 @@ void QmlMetaProperty::initDefault(QObject *obj)
\internal
Creates a QmlMetaProperty for the property at index \a idx of \a obj.
-
- The QmlMetaProperty is assigned category \a cat.
*/
-QmlMetaProperty::QmlMetaProperty(QObject *obj, int idx, PropertyCategory cat, QmlContext *ctxt)
+QmlMetaProperty::QmlMetaProperty(QObject *obj, int idx, QmlContext *ctxt)
: d(new QmlMetaPropertyPrivate)
{
d->context = ctxt;
d->object = obj;
d->type = Property;
- d->category = cat;
QMetaPropertyEx p(obj->metaObject()->property(idx));
d->propType = p.propertyType;
d->coreIdx = idx;
@@ -309,36 +308,6 @@ QmlMetaPropertyPrivate::propertyCategory() const
}
/*!
- Returns the property category of \a prop.
-*/
-QmlMetaProperty::PropertyCategory
-QmlMetaProperty::propertyCategory(const QMetaProperty &prop)
-{
- if (prop.name()) {
- int type = 0;
- if (prop.type() == QVariant::LastType)
- type = qMetaTypeId<QVariant>();
- else if (prop.type() == QVariant::UserType)
- type = prop.userType();
- else
- type = prop.type();
-
- if (type == qMetaTypeId<QmlBinding *>())
- return Bindable;
- else if (QmlMetaType::isList(type))
- return List;
- else if (QmlMetaType::isQmlList(type))
- return QmlList;
- else if (QmlMetaType::isObject(type))
- return Object;
- else
- return Normal;
- } else {
- return InvalidProperty;
- }
-}
-
-/*!
Returns the type name of the property, or 0 if the property has no type
name.
*/
@@ -426,12 +395,15 @@ QObject *QmlMetaProperty::object() const
QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other)
{
d->name = other.d->name;
- d->propType = other.d->propType;
- d->type = other.d->type;
d->signal = other.d->signal;
+ d->context = other.d->context;
d->coreIdx = other.d->coreIdx;
+ d->valueTypeIdx = other.d->valueTypeIdx;
+ d->valueTypeId = other.d->valueTypeId;
+ d->type = other.d->type;
d->attachedFunc = other.d->attachedFunc;
d->object = other.d->object;
+ d->propType = other.d->propType;
d->category = other.d->category;
return *this;
}
@@ -615,10 +587,27 @@ QVariant QmlMetaProperty::read() const
return sig->expression();
}
} else if (type() & Property) {
- if (type() & Attached)
+ if (type() & Attached) {
return QVariant::fromValue(d->attachedObject());
- else
+ } else if(type() & ValueTypeProperty) {
+ QmlEnginePrivate *ep = d->context?static_cast<QmlEnginePrivate *>(QObjectPrivate::get(d->context->engine())):0;
+ QmlValueType *valueType = 0;
+ if (ep)
+ valueType = ep->valueTypes[d->valueTypeId];
+ else
+ valueType = QmlValueTypeFactory::valueType(d->valueTypeId);
+ Q_ASSERT(valueType);
+
+ valueType->read(object(), d->coreIdx);
+ QVariant rv =
+ valueType->metaObject()->property(d->valueTypeIdx).read(valueType);
+ if (!ep)
+ delete valueType;
+ return rv;
+
+ } else {
return d->object->metaObject()->property(d->coreIdx).read(object());
+ }
}
return QVariant();
}
@@ -649,7 +638,33 @@ void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value)
void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value)
{
+ QObject *object = this->object;
+ int coreIdx = this->coreIdx;
+
+ QmlValueType *writeBack = 0;
+ QObject *writeBackObj = 0;
+ int writeBackIdx = -1;
+ bool deleteWriteBack = false;
+
+ if (type & QmlMetaProperty::ValueTypeProperty) {
+ QmlEnginePrivate *ep = context?static_cast<QmlEnginePrivate *>(QObjectPrivate::get(context->engine())):0;
+
+ if (ep) {
+ writeBack = ep->valueTypes[valueTypeId];
+ } else {
+ writeBack = QmlValueTypeFactory::valueType(valueTypeId);
+ deleteWriteBack = true;
+ }
+
+ writeBackObj = this->object;
+ writeBackIdx = this->coreIdx;
+ writeBack->read(writeBackObj, writeBackIdx);
+ object = writeBack;
+ coreIdx = valueTypeIdx;
+ }
+
QMetaProperty prop = object->metaObject()->property(coreIdx);
+
if (prop.isEnumType()) {
QVariant v = value;
if (value.type() == QVariant::Double) { //enum values come through the script engine as doubles
@@ -659,6 +674,11 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value)
v.convert(QVariant::Int);
}
prop.write(object, v);
+
+ if (writeBack) {
+ writeBack->write(writeBackObj, writeBackIdx);
+ if (deleteWriteBack) delete writeBack;
+ }
return;
}
@@ -757,18 +777,18 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value)
}
} else if (category == QmlMetaProperty::Normal) {
+ bool found = false;
switch(t) {
case QVariant::Double:
{
double d;
- bool found = true;
if (vt == QVariant::Int) {
d = value.toInt();
+ found = true;
} else if (vt == QVariant::UInt) {
d = value.toUInt();
- } else {
- found = false;
- }
+ found = true;
+ }
if (found) {
void *a[1];
@@ -776,7 +796,6 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value)
QMetaObject::metacall(object,
QMetaObject::WriteProperty,
coreIdx, a);
- return;
}
}
break;
@@ -784,14 +803,13 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value)
case QVariant::Int:
{
int i;
- bool found = true;
if (vt == QVariant::Double) {
i = (int)value.toDouble();
+ found = true;
} else if (vt == QVariant::UInt) {
i = (int)value.toUInt();
- } else {
- found = false;
- }
+ found = true;
+ }
if (found) {
void *a[1];
@@ -799,7 +817,6 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value)
QMetaObject::metacall(object,
QMetaObject::WriteProperty,
coreIdx, a);
- return;
}
}
break;
@@ -807,12 +824,10 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value)
case QVariant::String:
{
QString s;
- bool found = true;
if (vt == QVariant::ByteArray) {
s = QLatin1String(value.toByteArray());
- } else {
- found = false;
- }
+ found = true;
+ }
if (found) {
void *a[1];
@@ -820,7 +835,6 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value)
QMetaObject::metacall(object,
QMetaObject::WriteProperty,
coreIdx, a);
- return;
}
}
break;
@@ -833,15 +847,20 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value)
if (con) {
QVariant v = con(value.toString());
prop.write(object, v);
- return;
+ found = true;
}
}
}
break;
}
- prop.write(object, value);
+ if (!found)
+ prop.write(object, value);
}
+ if (writeBack) {
+ writeBack->write(writeBackObj, writeBackIdx);
+ if (deleteWriteBack) delete writeBack;
+ }
}
/*!
@@ -936,6 +955,8 @@ int QmlMetaProperty::coreIndex() const
return d->coreIdx;
}
+Q_GLOBAL_STATIC(QmlValueTypeFactory, qmlValueTypes);
+
/*!
Returns the property information serialized into a single integer.
QmlMetaProperty uses the bottom 24 bits only.
@@ -949,10 +970,35 @@ quint32 QmlMetaProperty::save() const
rv = d->coreIdx;
}
- Q_ASSERT(rv <= 0xFFFF);
- Q_ASSERT(type() <= 0xFF);
- rv |= (type() << 16);
+ Q_ASSERT(rv <= 0x7FF);
+ Q_ASSERT(type() <= 0x3F);
+ Q_ASSERT(d->valueTypeIdx <= 0x7F);
+
+ rv |= (type() << 18);
+ if (type() & ValueTypeProperty)
+ rv |= (d->valueTypeIdx << 11);
+
+ return rv;
+}
+
+quint32 QmlMetaPropertyPrivate::saveValueType(int core, int valueType)
+{
+ Q_ASSERT(core <= 0x7FF);
+ Q_ASSERT(valueType <= 0x7F);
+ quint32 rv = 0;
+ rv = (QmlMetaProperty::ValueTypeProperty | QmlMetaProperty::Property) << 18;
+ rv |= core;
+ rv |= valueType << 11;
+ return rv;
+}
+
+quint32 QmlMetaPropertyPrivate::saveProperty(int core)
+{
+ Q_ASSERT(core <= 0x7FF);
+ quint32 rv = 0;
+ rv = (QmlMetaProperty::Property) << 18;
+ rv |= core;
return rv;
}
@@ -962,17 +1008,34 @@ quint32 QmlMetaProperty::save() const
to QmlMetaProperty::save(). Only the bottom 24-bits are
used, the high bits can be set to any value.
*/
-void QmlMetaProperty::restore(quint32 id, QObject *obj)
+void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt)
{
- *this = QmlMetaProperty();
d->object = obj;
+ d->context = ctxt;
id &= 0xFFFFFF;
- d->type = id >> 16;
+ d->type = id >> 18;
id &= 0xFFFF;
if (d->type & Attached) {
d->attachedFunc = id;
+ } else if (d->type & ValueTypeProperty) {
+ int coreIdx = id & 0x7FF;
+ int valueTypeIdx = id >> 11;
+
+ QMetaProperty p(obj->metaObject()->property(coreIdx));
+ Q_ASSERT(p.type() < QVariant::UserType);
+
+ QmlValueType *valueType = qmlValueTypes()->valueTypes[p.type()];
+
+ QMetaPropertyEx p2(valueType->metaObject()->property(valueTypeIdx));
+
+ d->name = QLatin1String(p2.name());
+ d->propType = p2.propertyType;
+ d->coreIdx = coreIdx;
+ d->valueTypeIdx = valueTypeIdx;
+ d->valueTypeId = p.type();
+
} else if (d->type & Property) {
QMetaPropertyEx p(obj->metaObject()->property(id));
d->name = QLatin1String(p.name());
@@ -981,7 +1044,9 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj)
} else if (d->type & SignalProperty) {
d->signal = obj->metaObject()->method(id);
d->coreIdx = id;
- }
+ } else {
+ *this = QmlMetaProperty();
+ }
}
/*!
@@ -1000,7 +1065,8 @@ QMetaMethod QmlMetaProperty::method() const
the QmlMetaProperty(QObject*, QString) constructor, this static function
will correctly handle dot properties.
*/
-QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, const QString &name)
+QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj,
+ const QString &name)
{
QStringList path = name.split(QLatin1Char('.'));
@@ -1009,6 +1075,30 @@ QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, const QString &nam
for (int jj = 0; jj < path.count() - 1; ++jj) {
const QString &pathName = path.at(jj);
QmlMetaProperty prop(object, pathName);
+
+ if (jj == path.count() - 2 &&
+ prop.propertyType() < QVariant::UserType &&
+ qmlValueTypes()->valueTypes[prop.propertyType()]) {
+ // We're now at a value type property
+ QObject *typeObject =
+ qmlValueTypes()->valueTypes[prop.propertyType()];
+ int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
+ if (idx == -1)
+ return QmlMetaProperty();
+
+ QmlMetaProperty p;
+ p.d->name = pathName + QLatin1String(".") + path.last();
+ p.d->context = 0;
+ p.d->coreIdx = prop.coreIndex();
+ p.d->valueTypeIdx = idx;
+ p.d->valueTypeId = prop.propertyType();
+ p.d->type = QmlMetaProperty::ValueTypeProperty |
+ QmlMetaProperty::Property;
+ p.d->object = obj;
+ p.d->propType = typeObject->metaObject()->property(idx).userType();
+ return p;
+ }
+
QObject *objVal = QmlMetaType::toQObject(prop.read());
if (!objVal)
return QmlMetaProperty();
diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h
index fdcf9be..2470d5d 100644
--- a/src/declarative/qml/qmlmetaproperty.h
+++ b/src/declarative/qml/qmlmetaproperty.h
@@ -57,6 +57,7 @@ class QStringList;
class QVariant;
struct QMetaObject;
class QmlContext;
+class QmlEngine;
class QmlMetaPropertyPrivate;
class Q_DECLARATIVE_EXPORT QmlMetaProperty
@@ -78,7 +79,7 @@ public:
QmlMetaProperty(QObject *, const QString &, QmlContext *);
QmlMetaProperty(const QmlMetaProperty &);
QmlMetaProperty &operator=(const QmlMetaProperty &);
- QmlMetaProperty(QObject *, int, PropertyCategory = Unknown, QmlContext * = 0);
+ QmlMetaProperty(QObject *, int, QmlContext * = 0);
~QmlMetaProperty();
static QStringList properties(QObject *);
@@ -93,7 +94,7 @@ public:
bool connectNotifier(QObject *dest, int method) const;
quint32 save() const;
- void restore(quint32, QObject *);
+ void restore(quint32, QObject *, QmlContext * = 0);
QMetaMethod method() const;
@@ -101,7 +102,8 @@ public:
Property = 0x01,
SignalProperty = 0x02,
Default = 0x08,
- Attached = 0x10 };
+ Attached = 0x10,
+ ValueTypeProperty = 0x20 };
Type type() const;
bool isProperty() const;
@@ -112,7 +114,6 @@ public:
QObject *object() const;
PropertyCategory propertyCategory() const;
- static PropertyCategory propertyCategory(const QMetaProperty &);
int propertyType() const;
const char *propertyTypeName() const;
diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h
index 69fd5c3..7efdb6e 100644
--- a/src/declarative/qml/qmlmetaproperty_p.h
+++ b/src/declarative/qml/qmlmetaproperty_p.h
@@ -62,18 +62,22 @@ class QmlMetaPropertyPrivate
{
public:
QmlMetaPropertyPrivate()
- : context(0), coreIdx(-1), type(QmlMetaProperty::Invalid), attachedFunc(-1),
+ : context(0), coreIdx(-1), valueTypeIdx(-1), valueTypeId(0),
+ type(QmlMetaProperty::Invalid), attachedFunc(-1),
object(0), propType(-1), category(QmlMetaProperty::Unknown) {}
QmlMetaPropertyPrivate(const QmlMetaPropertyPrivate &other)
: name(other.name), signal(other.signal), context(other.context),
- coreIdx(other.coreIdx), type(other.type), attachedFunc(other.attachedFunc),
- object(other.object), propType(other.propType),
- category(other.category) {}
+ coreIdx(other.coreIdx), valueTypeIdx(other.valueTypeIdx),
+ valueTypeId(other.valueTypeId), type(other.type),
+ attachedFunc(other.attachedFunc), object(other.object),
+ propType(other.propType), category(other.category) {}
QString name;
QMetaMethod signal;
QmlContext *context;
int coreIdx;
+ int valueTypeIdx;
+ int valueTypeId;
uint type;
int attachedFunc;
QObject *object;
@@ -89,6 +93,9 @@ public:
void writeSignalProperty(const QVariant &);
void writeValueProperty(const QVariant &);
+
+ static quint32 saveValueType(int, int);
+ static quint32 saveProperty(int);
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp
index 9eed3f1..2a67c92 100644
--- a/src/declarative/qml/qmlparser.cpp
+++ b/src/declarative/qml/qmlparser.cpp
@@ -78,6 +78,8 @@ QmlParser::Object::~Object()
prop->release();
foreach(Property *prop, groupedProperties)
prop->release();
+ foreach(Property *prop, valueTypeProperties)
+ prop->release();
}
const QMetaObject *Object::metaObject() const
@@ -121,6 +123,12 @@ void QmlParser::Object::addGroupedProperty(Property *p)
groupedProperties << p;
}
+void QmlParser::Object::addValueTypeProperty(Property *p)
+{
+ p->addref();
+ valueTypeProperties << p;
+}
+
Property *QmlParser::Object::getProperty(const QByteArray &name, bool create)
{
if (!properties.contains(name)) {
diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h
index d23b4ea..927c9e6 100644
--- a/src/declarative/qml/qmlparser_p.h
+++ b/src/declarative/qml/qmlparser_p.h
@@ -147,10 +147,12 @@ namespace QmlParser
void addSignalProperty(Property *);
void addAttachedProperty(Property *);
void addGroupedProperty(Property *);
+ void addValueTypeProperty(Property *);
QList<Property *> valueProperties;
QList<Property *> signalProperties;
QList<Property *> attachedProperties;
QList<Property *> groupedProperties;
+ QList<Property *> valueTypeProperties;
// The bytes to cast instances by to get to the QmlParserStatus
// interface. -1 indicates the type doesn't support this interface.
diff --git a/src/declarative/qml/qmlvaluetype.cpp b/src/declarative/qml/qmlvaluetype.cpp
new file mode 100644
index 0000000..a01b4a7
--- /dev/null
+++ b/src/declarative/qml/qmlvaluetype.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** 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 "qmlvaluetype_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QmlValueTypeFactory::QmlValueTypeFactory()
+{
+ // ### Optimize
+ for (int ii = 0; ii < (QVariant::UserType - 1); ++ii)
+ valueTypes[ii] = valueType(ii);
+}
+
+QmlValueTypeFactory::~QmlValueTypeFactory()
+{
+ for (int ii = 0; ii < (QVariant::UserType - 1); ++ii)
+ delete valueTypes[ii];
+}
+
+QmlValueType *QmlValueTypeFactory::valueType(int t)
+{
+ switch (t) {
+ case QVariant::Rect:
+ return new QmlRectValueType;
+ default:
+ return 0;
+ }
+}
+
+QmlValueType::QmlValueType(QObject *parent)
+: QObject(parent)
+{
+}
+
+QmlRectValueType::QmlRectValueType(QObject *parent)
+: QmlValueType(parent)
+{
+}
+
+void QmlRectValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &rect, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QmlRectValueType::write(QObject *obj, int idx)
+{
+ void *a[] = { &rect, 0 };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+int QmlRectValueType::x() const
+{
+ return rect.x();
+}
+
+int QmlRectValueType::y() const
+{
+ return rect.y();
+}
+
+void QmlRectValueType::setX(int x)
+{
+ rect.moveLeft(x);
+}
+
+void QmlRectValueType::setY(int y)
+{
+ rect.moveTop(y);
+}
+
+int QmlRectValueType::width() const
+{
+ return rect.width();
+}
+
+int QmlRectValueType::height() const
+{
+ return rect.height();
+}
+
+void QmlRectValueType::setWidth(int w)
+{
+ rect.setWidth(w);
+}
+
+void QmlRectValueType::setHeight(int h)
+{
+ rect.setHeight(h);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlvaluetype_p.h b/src/declarative/qml/qmlvaluetype_p.h
new file mode 100644
index 0000000..5581df7
--- /dev/null
+++ b/src/declarative/qml/qmlvaluetype_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** 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 QMLVALUETYPE_P_H
+#define QMLVALUETYPE_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 <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlValueType : public QObject
+{
+ Q_OBJECT
+public:
+ QmlValueType(QObject *parent = 0);
+ virtual void read(QObject *, int) = 0;
+ virtual void write(QObject *, int) = 0;
+};
+
+class QmlValueTypeFactory
+{
+public:
+ QmlValueTypeFactory();
+ ~QmlValueTypeFactory();
+ static QmlValueType *valueType(int);
+
+ QmlValueType *valueTypes[QVariant::UserType - 1];
+ QmlValueType *operator[](int idx) const { return valueTypes[idx]; }
+};
+
+class QmlRectValueType : public QmlValueType
+{
+ Q_PROPERTY(int x READ x WRITE setX);
+ Q_PROPERTY(int y READ y WRITE setY);
+ Q_PROPERTY(int width READ width WRITE setWidth);
+ Q_PROPERTY(int height READ height WRITE setHeight);
+ Q_OBJECT
+public:
+ QmlRectValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int);
+
+ int x() const;
+ int y() const;
+ void setX(int);
+ void setY(int);
+
+ int width() const;
+ int height() const;
+ void setWidth(int);
+ void setHeight(int);
+
+private:
+ QRect rect;
+};
+QT_END_NAMESPACE
+
+#endif // QMLVALUETYPE_P_H
diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index 58b8689..ebf0a73 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -142,9 +142,8 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
QStack<ListInstance> qliststack;
- QStack<QmlMetaProperty> pushedProperties;
-
vmeErrors.clear();
+ QmlEnginePrivate *ep = ctxt->engine()->d_func();
for (int ii = start; !isError() && ii < (start + count); ++ii) {
QmlInstruction &instr = comp->bytecode[ii];
@@ -533,12 +532,13 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
case QmlInstruction::StoreCompiledBinding:
{
- QObject *target = stack.top();
+ QObject *target =
+ stack.at(stack.count() - 1 - instr.assignBinding.owner);
QObject *context =
stack.at(stack.count() - 1 - instr.assignBinding.context);
- QmlMetaProperty mp(target, instr.assignBinding.property,
- (QmlMetaProperty::PropertyCategory)instr.assignBinding.category);
+ QmlMetaProperty mp;
+ mp.restore(instr.assignBinding.property, target, ctxt);
QmlBinding *bind = new QmlBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, 0);
bindValues.append(bind);
@@ -553,12 +553,13 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
case QmlInstruction::StoreBinding:
{
- QObject *target = stack.top();
+ QObject *target =
+ stack.at(stack.count() - 1 - instr.assignBinding.owner);
QObject *context =
stack.at(stack.count() - 1 - instr.assignBinding.context);
- QmlMetaProperty mp(target, instr.assignBinding.property,
- (QmlMetaProperty::PropertyCategory)instr.assignBinding.category);
+ QmlMetaProperty mp;
+ mp.restore(instr.assignBinding.property, target, ctxt);
QmlBinding *bind = new QmlBinding(primitives.at(instr.assignBinding.value), context, ctxt);
bindValues.append(bind);
@@ -574,12 +575,14 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
case QmlInstruction::StoreValueSource:
{
- QObject *assign = stack.pop();
QmlPropertyValueSource *vs =
- static_cast<QmlPropertyValueSource *>(assign);
- QObject *target = stack.top();
+ static_cast<QmlPropertyValueSource *>(stack.pop());
+ QObject *target =
+ stack.at(stack.count() - 1 - instr.assignValueSource.owner);
+ QmlMetaProperty prop;
+ prop.restore(instr.assignValueSource.property, target, ctxt);
vs->setParent(target);
- vs->setTarget(QmlMetaProperty(target, instr.assignValueSource.property));
+ vs->setTarget(prop);
}
break;
@@ -762,6 +765,25 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
}
break;
+ case QmlInstruction::FetchValueType:
+ {
+ QObject *target = stack.top();
+ QmlValueType *valueHandler =
+ ep->valueTypes[instr.fetchValue.type];
+ valueHandler->read(target, instr.fetchValue.property);
+ stack.push(valueHandler);
+ }
+ break;
+
+ case QmlInstruction::PopValueType:
+ {
+ QmlValueType *valueHandler =
+ static_cast<QmlValueType *>(stack.pop());
+ QObject *target = stack.top();
+ valueHandler->write(target, instr.fetchValue.property);
+ }
+ break;
+
default:
qFatal("QmlCompiledData: Internal error - unknown instruction %d", instr.type);
break;
@@ -778,7 +800,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
return 0;
}
- QmlEnginePrivate *ep = ctxt->engine()->d_func();
if (bindValues.count)
ep->bindValues << bindValues;
if (parserStatus.count)
diff --git a/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt b/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt
index 25f22ce..989d0e6 100644
--- a/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt
+++ b/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt
@@ -1 +1 @@
-2:5:Cannot nest non-QObject property "value"
+2:5:Invalid property access
diff --git a/tests/auto/declarative/qmlparser/testtypes.h b/tests/auto/declarative/qmlparser/testtypes.h
index 7528331..34f3616 100644
--- a/tests/auto/declarative/qmlparser/testtypes.h
+++ b/tests/auto/declarative/qmlparser/testtypes.h
@@ -128,7 +128,8 @@ class MyTypeObject : public QObject
Q_PROPERTY(QPointF pointFProperty READ pointFProperty WRITE setPointFProperty);
Q_PROPERTY(QSize sizeProperty READ sizeProperty WRITE setSizeProperty);
Q_PROPERTY(QSizeF sizeFProperty READ sizeFProperty WRITE setSizeFProperty);
- Q_PROPERTY(QRect rectProperty READ rectProperty WRITE setRectProperty);
+ Q_PROPERTY(QRect rectProperty READ rectProperty WRITE setRectProperty NOTIFY rectPropertyChanged);
+ Q_PROPERTY(QRect rectProperty2 READ rectProperty2 WRITE setRectProperty2);
Q_PROPERTY(QRectF rectFProperty READ rectFProperty WRITE setRectFProperty);
Q_PROPERTY(bool boolProperty READ boolProperty WRITE setBoolProperty);
Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty);
@@ -290,6 +291,15 @@ public:
}
void setRectProperty(const QRect &v) {
rectPropertyValue = v;
+ emit rectPropertyChanged();
+ }
+
+ QRect rectPropertyValue2;
+ QRect rectProperty2() const {
+ return rectPropertyValue2;
+ }
+ void setRectProperty2(const QRect &v) {
+ rectPropertyValue2 = v;
}
QRectF rectFPropertyValue;
@@ -315,6 +325,11 @@ public:
void setVariantProperty(const QVariant &v) {
variantPropertyValue = v;
}
+
+ void doAction() { emit action(); }
+signals:
+ void action();
+ void rectPropertyChanged();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(MyTypeObject::MyFlags)
QML_DECLARE_TYPE(MyTypeObject);
diff --git a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp
index f722ca3..eaa8267 100644
--- a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp
+++ b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp
@@ -44,6 +44,7 @@ private slots:
void attachedProperties();
void dynamicObjects();
void customVariantTypes();
+ void valueTypes();
// regression tests for crashes
void crash1();
@@ -431,6 +432,31 @@ void tst_qmlparser::customVariantTypes()
QCOMPARE(object->customType().a, 10);
}
+void tst_qmlparser::valueTypes()
+{
+ QmlComponent component(&engine, TEST_FILE("valueTypes.txt"));
+ MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->rectProperty(), QRect(10, 11, 12, 13));
+ QCOMPARE(object->rectProperty2(), QRect(10, 11, 12, 13));
+ QCOMPARE(object->intProperty(), 10);
+ object->doAction();
+ QCOMPARE(object->rectProperty(), QRect(12, 11, 14, 13));
+ QCOMPARE(object->rectProperty2(), QRect(12, 11, 14, 13));
+ QCOMPARE(object->intProperty(), 12);
+
+ QmlMetaProperty p = QmlMetaProperty::createProperty(object, "rectProperty.x");
+ QCOMPARE(p.read(), QVariant(12));
+ p.write(13);
+ QCOMPARE(p.read(), QVariant(13));
+
+ quint32 r = p.save();
+ QmlMetaProperty p2;
+ p2.restore(r, object);
+ QCOMPARE(p2.read(), QVariant(13));
+}
+
void tst_qmlparser::crash1()
{
QmlComponent component(&engine, "Component {}");
diff --git a/tests/auto/declarative/qmlparser/valueTypes.txt b/tests/auto/declarative/qmlparser/valueTypes.txt
new file mode 100644
index 0000000..0d670af
--- /dev/null
+++ b/tests/auto/declarative/qmlparser/valueTypes.txt
@@ -0,0 +1,12 @@
+MyTypeObject {
+ rectProperty.x: 10
+ rectProperty.y: 11
+ rectProperty.width: rectProperty.x + 2
+ rectProperty.height: 13
+
+ intProperty: rectProperty.x
+
+ onAction: { var a = rectProperty; a.x = 12; }
+
+ rectProperty2: rectProperty
+}