summaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/qml/qmlbasicscript.cpp11
-rw-r--r--src/declarative/qml/qmlbinding.cpp13
-rw-r--r--src/declarative/qml/qmlexpression.cpp41
-rw-r--r--src/declarative/qml/qmlexpression.h2
-rw-r--r--src/declarative/qml/qmlmetaproperty.cpp130
-rw-r--r--src/declarative/qml/qmlmetaproperty.h4
-rw-r--r--src/declarative/qml/qmlmetaproperty_p.h5
-rw-r--r--src/declarative/qml/qmlmetatype.cpp3
-rw-r--r--src/declarative/qml/qmlobjectscriptclass.cpp23
-rw-r--r--src/declarative/qml/qmlobjectscriptclass_p.h3
10 files changed, 156 insertions, 79 deletions
diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp
index a0d749f..b7aac54 100644
--- a/src/declarative/qml/qmlbasicscript.cpp
+++ b/src/declarative/qml/qmlbasicscript.cpp
@@ -181,19 +181,24 @@ static QVariant fetch_value(QObject *o, int idx, int type)
break;
default:
{
+ // If the object is null, we extract the predicted type. While this isn't
+ // 100% reliable, in many cases it gives us better error messages if we
+ // assign this null-object to an incompatible property
if (QmlMetaType::isObject(type)) {
// NOTE: This assumes a cast to QObject does not alter the
// object pointer
QObject *val = 0;
void *args[] = { &val, 0 };
QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args);
- return QVariant::fromValue(val);
+ if (!val) return QVariant(type, &val);
+ else return QVariant::fromValue(val);
} else {
QVariant var = o->metaObject()->property(idx).read(o);
if (QmlMetaType::isObject(var.userType())) {
QObject *obj = 0;
obj = *(QObject **)var.data();
- var = QVariant::fromValue(obj);
+ if (!obj) var = QVariant(var.userType(), &obj);
+ else var = QVariant::fromValue(obj);
}
return var;
}
@@ -665,7 +670,7 @@ QVariant QmlBasicScript::run(QmlContext *context, QObject *me)
case ScriptInstruction::FetchConstant:
{
QVariant o = stack.pop();
- QObject *obj = qvariant_cast<QObject *>(o);
+ QObject *obj = *(QObject **)o.constData();
stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type));
if (obj && instr.constant.notify != 0)
diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp
index 6a70c1e..2b4e723 100644
--- a/src/declarative/qml/qmlbinding.cpp
+++ b/src/declarative/qml/qmlbinding.cpp
@@ -129,7 +129,18 @@ void QmlBinding::update(QmlMetaProperty::WriteFlags flags)
} else {
QVariant value = this->value();
- data->property.write(value, flags);
+ if (data->property.object() && !data->property.write(value, flags)) {
+ QString fileName = data->fileName;
+ int line = data->line;
+ if (fileName.isEmpty()) fileName = QLatin1String("<Unknown File>");
+
+ const char *valueType = 0;
+ if (value.userType() == QVariant::Invalid) valueType = "null";
+ else valueType = QMetaType::typeName(value.userType());
+ qWarning().nospace() << qPrintable(fileName) << ":" << line
+ << " Unable to assign " << valueType << " to "
+ << QMetaType::typeName(data->property.propertyType());
+ }
}
data->updating = false;
diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp
index 76ca2c1..3698417 100644
--- a/src/declarative/qml/qmlexpression.cpp
+++ b/src/declarative/qml/qmlexpression.cpp
@@ -332,20 +332,17 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope)
rv = QVariant::fromValue(list);
}
} else if (svalue.isObject() &&
- !svalue.isNumber() &&
- !svalue.isString() &&
- !svalue.isDate() &&
- !svalue.isError() &&
- !svalue.isFunction() &&
- !svalue.isNull() &&
- !svalue.isQMetaObject() &&
- !svalue.isQObject() &&
- !svalue.isRegExp()) {
-
+ ep->objectClass->scriptClass(svalue) == ep->objectClass) {
QObject *o = svalue.toQObject();
- if (o)
- return qVariantFromValue(o);
+ int type = QMetaType::QObjectStar;
+ // If the object is null, we extract the predicted type. While this isn't
+ // 100% reliable, in many cases it gives us better error messages if we
+ // assign this null-object to an incompatible property
+ if (!o) type = ep->objectClass->objectType(svalue);
+
+ return QVariant(type, &o);
}
+
if (rv.isNull())
rv = svalue.toVariant();
@@ -452,6 +449,26 @@ void QmlExpression::setTrackChange(bool trackChange)
}
/*!
+ Returns the source file URL for this expression. The source location must
+ have been previously set by calling setSourceLocation().
+*/
+QUrl QmlExpression::sourceFile() const
+{
+ Q_D(const QmlExpression);
+ return QUrl(d->data->fileName);
+}
+
+/*!
+ Returns the source file line number for this expression. The source location
+ must have been previously set by calling setSourceLocation().
+*/
+int QmlExpression::lineNumber() const
+{
+ Q_D(const QmlExpression);
+ return d->data->line;
+}
+
+/*!
Set the location of this expression to \a line of \a fileName. This information
is used by the script engine.
*/
diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h
index b85e0a7..73682f1 100644
--- a/src/declarative/qml/qmlexpression.h
+++ b/src/declarative/qml/qmlexpression.h
@@ -76,6 +76,8 @@ public:
bool trackChange() const;
void setTrackChange(bool);
+ QUrl sourceFile() const;
+ int lineNumber() const;
void setSourceLocation(const QUrl &fileName, int line);
QObject *scopeObject() const;
diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp
index 5635016..feedf13 100644
--- a/src/declarative/qml/qmlmetaproperty.cpp
+++ b/src/declarative/qml/qmlmetaproperty.cpp
@@ -768,13 +768,14 @@ bool QmlMetaPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int id
return status;
}
-void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value,
+bool QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value,
QmlMetaProperty::WriteFlags flags)
{
// Remove any existing bindings on this property
if (!(flags & QmlMetaProperty::DontRemoveBinding))
delete q->setBinding(0);
+ bool rv = false;
uint type = q->type();
if (type & QmlMetaProperty::ValueTypeProperty) {
QmlEnginePrivate *ep =
@@ -792,20 +793,23 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value,
QmlPropertyCache::Data data = core;
data.coreIndex = valueTypeCoreIdx;
data.propType = valueTypePropType;
- write(writeBack, data, value, context, flags);
+ rv = write(writeBack, data, value, context, flags);
writeBack->write(object, core.coreIndex, flags);
if (!ep) delete writeBack;
} else {
- write(object, core, value, context, flags);
+ rv = write(object, core, value, context, flags);
}
+
+ return rv;
}
-void QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data &property,
- const QVariant &value, QmlContext *context, QmlMetaProperty::WriteFlags flags)
+bool QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data &property,
+ const QVariant &value, QmlContext *context,
+ QmlMetaProperty::WriteFlags flags)
{
int coreIdx = property.coreIndex;
int status = -1; //for dbus
@@ -820,14 +824,16 @@ void QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data
if (qFuzzyCompare(fractional, (double)0.0))
v.convert(QVariant::Int);
}
- writeEnumProperty(prop, coreIdx, object, v, flags);
-
- return;
+ return writeEnumProperty(prop, coreIdx, object, v, flags);
}
int t = property.propType;
int vt = value.userType();
+ QmlEnginePrivate *enginePriv = 0;
+ if (context && context->engine())
+ enginePriv = QmlEnginePrivate::get(context->engine());
+
if (t == QVariant::Url) {
QUrl u;
@@ -843,13 +849,14 @@ void QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data
found = true;
}
- if (found) {
- if (context && u.isRelative() && !u.isEmpty())
- u = context->baseUrl().resolved(u);
- int status = -1;
- void *argv[] = { &u, 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
- }
+ if (!found)
+ return false;
+
+ if (context && u.isRelative() && !u.isEmpty())
+ u = context->baseUrl().resolved(u);
+ int status = -1;
+ void *argv[] = { &u, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
} else if (vt == t) {
@@ -863,29 +870,33 @@ void QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data
} else if (property.flags & QmlPropertyCache::Data::IsQObjectDerived) {
- QObject *o = QmlMetaType::toQObject(value);
-
const QMetaObject *valMo = 0;
+ if (enginePriv) valMo = enginePriv->rawMetaObjectForType(value.userType());
+ else valMo = QmlMetaType::rawMetaObjectForType(value.userType());
+
+ if (!valMo)
+ return false;
- if (o) {
+ QObject *o = *(QObject **)value.constData();
+ const QMetaObject *propMo = 0;
+ if (enginePriv) propMo = enginePriv->rawMetaObjectForType(t);
+ else propMo = QmlMetaType::rawMetaObjectForType(t);
- valMo = o->metaObject();
- const QMetaObject *propMo = QmlMetaType::rawMetaObjectForType(t);
-
- while (valMo) {
- if (equal(valMo, propMo))
- break;
- valMo = valMo->superClass();
- }
-
- }
-
- if (valMo || !o) {
+ if (o) valMo = o->metaObject();
+ if (canConvert(valMo, propMo)) {
void *args[] = { &o, 0, &status, &flags };
QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
args);
-
+ } else if (!o && canConvert(propMo, valMo)) {
+ // In the case of a null QObject, we assign the null if there is
+ // any change that the null variant type could be up or down cast to
+ // the property type.
+ void *args[] = { &o, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
+ args);
+ } else {
+ return false;
}
} else if (property.flags & QmlPropertyCache::Data::IsQList) {
@@ -932,10 +943,8 @@ void QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data
objMo = objMo->superClass();
}
- if (!found) {
- qWarning() << "Unable to assign object to list";
- return;
- }
+ if (!found)
+ return false;
// NOTE: This assumes a cast to QObject does not alter
// the object pointer
@@ -951,35 +960,36 @@ void QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data
QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
} else if ((uint)t >= QVariant::UserType && vt == QVariant::String) {
QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(t);
- if (con) {
- QVariant v = con(value.toString());
- if (v.userType() == t) {
- void *a[] = { (void *)v.constData(), 0, &status, &flags};
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
- }
+ if (!con)
+ return false;
+
+ QVariant v = con(value.toString());
+ if (v.userType() == t) {
+ void *a[] = { (void *)v.constData(), 0, &status, &flags};
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
}
+ } else {
+ return false;
}
}
+
+ return true;
}
/*!
Set the property value to \a value.
*/
-void QmlMetaProperty::write(const QVariant &value) const
+bool QmlMetaProperty::write(const QVariant &value) const
{
- write(value, 0);
+ return write(value, 0);
}
-void QmlMetaProperty::write(const QVariant &value, QmlMetaProperty::WriteFlags flags) const
+bool QmlMetaProperty::write(const QVariant &value, QmlMetaProperty::WriteFlags flags) const
{
- if (!d->object)
- return;
-
- if (type() & Property && d->core.isValid()) {
-
- d->writeValueProperty(value, flags);
-
- }
+ if (d->object && type() & Property && d->core.isValid())
+ return d->writeValueProperty(value, flags);
+ else
+ return false;
}
/*!
@@ -1217,5 +1227,21 @@ bool QmlMetaPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rh
return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
}
+/*!
+ Returns true if from inherits to.
+*/
+bool QmlMetaPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
+{
+ if (from && to == &QObject::staticMetaObject)
+ return true;
+
+ while (from) {
+ if (equal(from, to))
+ return true;
+ from = from->superClass();
+ }
+
+ return false;
+}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h
index b0ae28c..fcc020e 100644
--- a/src/declarative/qml/qmlmetaproperty.h
+++ b/src/declarative/qml/qmlmetaproperty.h
@@ -87,10 +87,10 @@ public:
QString name() const;
QVariant read() const;
- void write(const QVariant &) const;
+ bool write(const QVariant &) const;
enum WriteFlag { BypassInterceptor = 0x01, DontRemoveBinding = 0x02 };
Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
- void write(const QVariant &, QmlMetaProperty::WriteFlags) const;
+ bool write(const QVariant &, QmlMetaProperty::WriteFlags) const;
bool hasChangedNotifier() const;
bool needsChangedNotifier() const;
diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h
index 7288266..368ca30 100644
--- a/src/declarative/qml/qmlmetaproperty_p.h
+++ b/src/declarative/qml/qmlmetaproperty_p.h
@@ -97,9 +97,9 @@ public:
QmlMetaProperty::PropertyCategory propertyCategory() const;
QVariant readValueProperty();
- void writeValueProperty(const QVariant &, QmlMetaProperty::WriteFlags);
+ bool writeValueProperty(const QVariant &, QmlMetaProperty::WriteFlags);
static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags);
- static void write(QObject *, const QmlPropertyCache::Data &, const QVariant &, QmlContext *,
+ static bool write(QObject *, const QmlPropertyCache::Data &, const QVariant &, QmlContext *,
QmlMetaProperty::WriteFlags flags = 0);
static QmlAbstractBinding *setBinding(QObject *, const QmlPropertyCache::Data &, QmlAbstractBinding *,
QmlMetaProperty::WriteFlags flags = QmlMetaProperty::DontRemoveBinding);
@@ -108,6 +108,7 @@ public:
static quint32 saveProperty(int);
static bool equal(const QMetaObject *, const QMetaObject *);
+ static bool canConvert(const QMetaObject *from, const QMetaObject *to);
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp
index 5198f9f..1ab7aff 100644
--- a/src/declarative/qml/qmlmetatype.cpp
+++ b/src/declarative/qml/qmlmetatype.cpp
@@ -642,6 +642,9 @@ QVariant QmlMetaType::fromObject(QObject *obj, int typeId)
const QMetaObject *QmlMetaType::rawMetaObjectForType(int id)
{
+ if (id == QMetaType::QObjectStar)
+ return &QObject::staticMetaObject;
+
QReadLocker lock(metaTypeDataLock());
QmlMetaTypeData *data = metaTypeData();
diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp
index c356a3f..a6edd3b 100644
--- a/src/declarative/qml/qmlobjectscriptclass.cpp
+++ b/src/declarative/qml/qmlobjectscriptclass.cpp
@@ -52,8 +52,9 @@
QT_BEGIN_NAMESPACE
struct ObjectData : public QScriptDeclarativeClass::Object {
- ObjectData(QObject *o) : object(o) {}
+ ObjectData(QObject *o, int t) : object(o), type(t) {}
QGuard<QObject> object;
+ int type;
};
/*
@@ -77,22 +78,22 @@ QmlObjectScriptClass::~QmlObjectScriptClass()
{
}
-QScriptValue QmlObjectScriptClass::newQObject(QObject *object)
+QScriptValue QmlObjectScriptClass::newQObject(QObject *object, int type)
{
QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);
if (!object)
- return newObject(scriptEngine, this, new ObjectData(object));
+ return newObject(scriptEngine, this, new ObjectData(object, type));
QmlDeclarativeData *ddata = QmlDeclarativeData::get(object, true);
if (!ddata->scriptValue.isValid()) {
- ddata->scriptValue = newObject(scriptEngine, this, new ObjectData(object));
+ ddata->scriptValue = newObject(scriptEngine, this, new ObjectData(object, type));
return ddata->scriptValue;
} else if (ddata->scriptValue.engine() == QmlEnginePrivate::getScriptEngine(engine)) {
return ddata->scriptValue;
} else {
- return newObject(scriptEngine, this, new ObjectData(object));
+ return newObject(scriptEngine, this, new ObjectData(object, type));
}
}
@@ -101,6 +102,15 @@ QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const
return value.toQObject();
}
+int QmlObjectScriptClass::objectType(const QScriptValue &value) const
+{
+ if (scriptClass(value) != this)
+ return QVariant::Invalid;
+
+ Object *o = object(value);
+ return ((ObjectData*)(o))->type;
+}
+
QScriptClass::QueryFlags
QmlObjectScriptClass::queryProperty(Object *object, const Identifier &name,
QScriptClass::QueryFlags flags)
@@ -224,7 +234,8 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name
QObject *rv = 0;
void *args[] = { &rv, 0 };
QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return newQObject(rv);
+
+ return newQObject(rv, lastData->propType);
} else {
QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj);
return enginePriv->scriptValueFromVariant(var);
diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h
index 8d5b5f6..7fb727e 100644
--- a/src/declarative/qml/qmlobjectscriptclass_p.h
+++ b/src/declarative/qml/qmlobjectscriptclass_p.h
@@ -70,8 +70,9 @@ public:
QmlObjectScriptClass(QmlEngine *);
~QmlObjectScriptClass();
- QScriptValue newQObject(QObject *);
+ QScriptValue newQObject(QObject *, int type = QMetaType::QObjectStar);
QObject *toQObject(const QScriptValue &) const;
+ int objectType(const QScriptValue &) const;
enum QueryMode { IncludeAttachedProperties, SkipAttachedProperties };