QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) { Q_Q(QDeclarativeExpression); if (!context() || !context()->isValid()) { qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context"); return QVariant(); } QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine()); return ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()); }
void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) { Q_D(QDeclarativeBinding); if (!d->enabled || !d->context() || !d->context()->isValid()) return; if (!d->updating) { d->updating = true; bool wasDeleted = false; d->deleted = &wasDeleted; if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) { int idx = d->property.index(); Q_ASSERT(idx != -1); QDeclarativeBinding *t = this; int status = -1; void *a[] = { &t, 0, &status, &flags }; QMetaObject::metacall(d->property.object(), QMetaObject::WriteProperty, idx, a); if (wasDeleted) return; } else { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine); bool isUndefined = false; QVariant value; QScriptValue scriptValue = d->scriptValue(0, &isUndefined); if (wasDeleted) return; if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) { value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >()); } else if (scriptValue.isNull() && d->property.propertyTypeCategory() == QDeclarativeProperty::Object) { value = QVariant::fromValue((QObject *)0); } else { value = ep->scriptValueToVariant(scriptValue, d->property.propertyType()); if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) { // 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 int type = ep->objectClass->objectType(scriptValue); QObject *o = 0; value = QVariant(type, (void *)&o); } } if (d->error.isValid()) { } else if (isUndefined && d->property.isResettable()) { d->property.reset(); } else if (isUndefined && d->property.propertyType() == qMetaTypeId<QVariant>()) { QDeclarativePropertyPrivate::write(d->property, QVariant(), flags); } else if (isUndefined) { QUrl url = QUrl(d->url); int line = d->line; if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>")); d->error.setUrl(url); d->error.setLine(line); d->error.setColumn(-1); d->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(d->property.propertyType())) + QLatin1String(" ") + d->property.name()); } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) { QUrl url = QUrl(d->url); int line = d->line; if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>")); d->error.setUrl(url); d->error.setLine(line); d->error.setColumn(-1); d->error.setDescription(QLatin1String("Unable to assign a function to a property.")); } else if (d->property.object() && !QDeclarativePropertyPrivate::write(d->property, value, flags)) { if (wasDeleted) return; QUrl url = QUrl(d->url); int line = d->line; if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>")); const char *valueType = 0; if (value.userType() == QVariant::Invalid) valueType = "null"; else valueType = QMetaType::typeName(value.userType()); d->error.setUrl(url); d->error.setLine(line); d->error.setColumn(-1); d->error.setDescription(QLatin1String("Unable to assign ") + QLatin1String(valueType) + QLatin1String(" to ") + QLatin1String(QMetaType::typeName(d->property.propertyType()))); } if (wasDeleted) return; if (d->error.isValid()) { if (!d->addError(ep)) ep->warning(this->error()); } else { d->removeError(); } } d->updating = false; d->deleted = 0; } else { qmlInfo(d->property.object()) << tr("Binding loop detected for property \"%1\"").arg(d->property.name()); } }
int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) { int id = _id; if(c == QMetaObject::WriteProperty) { int flags = *reinterpret_cast<int*>(a[3]); if (!(flags & QDeclarativePropertyPrivate::BypassInterceptor) && !aInterceptors.isEmpty() && aInterceptors.testBit(id)) { QPair<int, QDeclarativePropertyValueInterceptor*> pair = interceptors.value(id); int valueIndex = pair.first; QDeclarativePropertyValueInterceptor *vi = pair.second; int type = property(id).userType(); if (type != QVariant::Invalid) { if (valueIndex != -1) { QDeclarativeEnginePrivate *ep = ctxt?QDeclarativeEnginePrivate::get(ctxt->engine):0; QDeclarativeValueType *valueType = 0; if (ep) valueType = ep->valueTypes[type]; else valueType = QDeclarativeValueTypeFactory::valueType(type); Q_ASSERT(valueType); valueType->setValue(QVariant(type, a[0])); QMetaProperty valueProp = valueType->metaObject()->property(valueIndex); vi->write(valueProp.read(valueType)); if (!ep) delete valueType; return -1; } else { vi->write(QVariant(type, a[0])); return -1; } } } } if(c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) { if (id >= propOffset) { id -= propOffset; if (id < metaData->propertyCount) { int t = (metaData->propertyData() + id)->propertyType; bool needActivate = false; if (t == -1) { if (c == QMetaObject::ReadProperty) { *reinterpret_cast<QVariant *>(a[0]) = readVarPropertyAsVariant(id); } else if (c == QMetaObject::WriteProperty) { writeVarProperty(id, *reinterpret_cast<QVariant *>(a[0])); } } else { if (c == QMetaObject::ReadProperty) { switch(t) { case QVariant::Int: *reinterpret_cast<int *>(a[0]) = data[id].asInt(); break; case QVariant::Bool: *reinterpret_cast<bool *>(a[0]) = data[id].asBool(); break; case QVariant::Double: *reinterpret_cast<double *>(a[0]) = data[id].asDouble(); break; case QVariant::String: *reinterpret_cast<QString *>(a[0]) = data[id].asQString(); break; case QVariant::Url: *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl(); break; case QVariant::Color: *reinterpret_cast<QColor *>(a[0]) = data[id].asQColor(); break; case QVariant::Date: *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate(); break; case QVariant::DateTime: *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime(); break; case QMetaType::QObjectStar: *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject(); break; default: break; } if (t == qMetaTypeId<QDeclarativeListProperty<QObject> >()) { int listIndex = data[id].asInt(); const List *list = &listProperties.at(listIndex); *reinterpret_cast<QDeclarativeListProperty<QObject> *>(a[0]) = QDeclarativeListProperty<QObject>(object, (void *)list, list_append, list_count, list_at, list_clear); } } else if (c == QMetaObject::WriteProperty) { switch(t) { case QVariant::Int: needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt(); data[id].setValue(*reinterpret_cast<int *>(a[0])); break; case QVariant::Bool: needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool(); data[id].setValue(*reinterpret_cast<bool *>(a[0])); break; case QVariant::Double: needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble(); data[id].setValue(*reinterpret_cast<double *>(a[0])); break; case QVariant::String: needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString(); data[id].setValue(*reinterpret_cast<QString *>(a[0])); break; case QVariant::Url: needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl(); data[id].setValue(*reinterpret_cast<QUrl *>(a[0])); break; case QVariant::Color: needActivate = *reinterpret_cast<QColor *>(a[0]) != data[id].asQColor(); data[id].setValue(*reinterpret_cast<QColor *>(a[0])); break; case QVariant::Date: needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate(); data[id].setValue(*reinterpret_cast<QDate *>(a[0])); break; case QVariant::DateTime: needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime(); data[id].setValue(*reinterpret_cast<QDateTime *>(a[0])); break; case QMetaType::QObjectStar: needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject(); data[id].setValue(*reinterpret_cast<QObject **>(a[0])); break; default: break; } } } if (c == QMetaObject::WriteProperty && needActivate) { activate(object, methodOffset + id, 0); } return -1; } id -= metaData->propertyCount; if (id < metaData->aliasCount) { QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + id; if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) *reinterpret_cast<void **>(a[0]) = 0; if (!ctxt) return -1; QDeclarativeContext *context = ctxt->asQDeclarativeContext(); QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context); QObject *target = ctxtPriv->data->idValues[d->contextIdx].data(); if (!target) return -1; connectAlias(id); if (d->isObjectAlias()) { *reinterpret_cast<QObject **>(a[0]) = target; return -1; } // Remove binding (if any) on write if(c == QMetaObject::WriteProperty) { int flags = *reinterpret_cast<int*>(a[3]); if (flags & QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite) { QDeclarativeData *targetData = QDeclarativeData::get(target); if (targetData && targetData->hasBindingBit(d->propertyIndex())) { QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0); if (binding) binding->destroy(); } } } if (d->isValueTypeAlias()) { // Value type property QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine); QDeclarativeValueType *valueType = ep->valueTypes[d->valueType()]; Q_ASSERT(valueType); valueType->read(target, d->propertyIndex()); int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a); if (c == QMetaObject::WriteProperty) valueType->write(target, d->propertyIndex(), 0x00); return rv; } else { return QMetaObject::metacall(target, c, d->propertyIndex(), a); } } return -1; } } else if(c == QMetaObject::InvokeMetaMethod) { if (id >= methodOffset) { id -= methodOffset; int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; if (id < plainSignals) { QMetaObject::activate(object, _id, a); return -1; } id -= plainSignals; if (id < metaData->methodCount) { if (!ctxt->engine) return -1; // We can't run the method QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine); QScriptValue function = method(id); QScriptValueList args; QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id; if (data->parameterCount) { for (int ii = 0; ii < data->parameterCount; ++ii) { args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]); } } QScriptValue rv = function.call(ep->objectClass->newQObject(object), args); if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv); return -1; } return -1; } } if (parent) return parent->metaCall(c, _id, a); else return object->qt_metacall(c, _id, a); }
void QDeclarativeObjectScriptClass::setProperty(QObject *obj, const Identifier &name, const QScriptValue &value, QScriptContext *context, QDeclarativeContextData *evalContext) { Q_UNUSED(name); Q_ASSERT(obj); Q_ASSERT(lastData); Q_ASSERT(context); if (!lastData->isValid()) { QString error = QLatin1String("Cannot assign to non-existent property \"") + toString(name) + QLatin1Char('\"'); context->throwError(error); return; } if (!(lastData->flags & QDeclarativePropertyCache::Data::IsWritable) && !(lastData->flags & QDeclarativePropertyCache::Data::IsQList)) { QString error = QLatin1String("Cannot assign to read-only property \"") + toString(name) + QLatin1Char('\"'); context->throwError(error); return; } QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); if (!evalContext) { // Global object, QScriptContext activation object, QDeclarativeContext object QScriptValue scopeNode = scopeChainValue(context, -3); if (scopeNode.isValid()) { Q_ASSERT(scriptClass(scopeNode) == enginePriv->contextClass); evalContext = enginePriv->contextClass->contextFromValue(scopeNode); } } QDeclarativeAbstractBinding *delBinding = QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, 0); if (delBinding) delBinding->destroy(); if (value.isNull() && lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { QObject *o = 0; int status = -1; int flags = 0; void *argv[] = { &o, 0, &status, &flags }; QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, argv); } else if (value.isUndefined() && lastData->flags & QDeclarativePropertyCache::Data::IsResettable) { void *a[] = { 0 }; QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a); } else if (value.isUndefined() && lastData->propType == qMetaTypeId<QVariant>()) { QDeclarativePropertyPrivate::write(obj, *lastData, QVariant(), evalContext); } else if (value.isUndefined()) { QString error = QLatin1String("Cannot assign [undefined] to ") + QLatin1String(QMetaType::typeName(lastData->propType)); context->throwError(error); } else { QVariant v; if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >()); else v = enginePriv->scriptValueToVariant(value, lastData->propType); if (!QDeclarativePropertyPrivate::write(obj, *lastData, v, evalContext)) { const char *valueType = 0; if (v.userType() == QVariant::Invalid) valueType = "null"; else valueType = QMetaType::typeName(v.userType()); QString error = QLatin1String("Cannot assign ") + QLatin1String(valueType) + QLatin1String(" to ") + QLatin1String(QMetaType::typeName(lastData->propType)); context->throwError(error); } } }
void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, const QScriptValue &value) { if (type != 0) { cleanup(); type = 0; } if (callType == qMetaTypeId<QScriptValue>()) { qscriptValuePtr = new (&allocData) QScriptValue(value); type = qMetaTypeId<QScriptValue>(); } else if (callType == QMetaType::Int) { intValue = quint32(value.toInt32()); type = callType; } else if (callType == QMetaType::UInt) { intValue = quint32(value.toUInt32()); type = callType; } else if (callType == QMetaType::Bool) { boolValue = value.toBool(); type = callType; } else if (callType == QMetaType::Double) { doubleValue = double(value.toNumber()); type = callType; } else if (callType == QMetaType::Float) { floatValue = float(value.toNumber()); type = callType; } else if (callType == QMetaType::QString) { if (value.isNull() || value.isUndefined()) qstringPtr = new (&allocData) QString(); else qstringPtr = new (&allocData) QString(value.toString()); type = callType; } else if (callType == QMetaType::QObjectStar) { qobjectPtr = value.toQObject(); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { QVariant other = QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value); qvariantPtr = new (&allocData) QVariant(other); type = callType; } else if (callType == qMetaTypeId<QList<QObject*> >()) { qlistPtr = new (&allocData) QList<QObject *>(); if (value.isArray()) { int length = value.property(QLatin1String("length")).toInt32(); for (int ii = 0; ii < length; ++ii) { QScriptValue arrayItem = value.property(ii); QObject *d = arrayItem.toQObject(); qlistPtr->append(d); } } else if (QObject *d = value.toQObject()) { qlistPtr->append(d); } type = callType; } else { qvariantPtr = new (&allocData) QVariant(); type = -1; QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine); QVariant v = priv->scriptValueToVariant(value); if (v.userType() == callType) { *qvariantPtr = v; } else if (v.canConvert((QVariant::Type)callType)) { *qvariantPtr = v; qvariantPtr->convert((QVariant::Type)callType); } else if (const QMetaObject *mo = priv->rawMetaObjectForType(callType)) { QObject *obj = priv->toQObject(v); if (obj) { const QMetaObject *objMo = obj->metaObject(); while (objMo && objMo != mo) objMo = objMo->superClass(); if (!objMo) obj = 0; } *qvariantPtr = QVariant(callType, &obj); } else { *qvariantPtr = QVariant(callType, (void *)0); } } }
void QDeclarativeObjectScriptClass::setProperty(QObject *obj, const Identifier &name, const QScriptValue &value, QScriptContext *context, QDeclarativeContextData *evalContext) { Q_UNUSED(name); Q_ASSERT(obj); Q_ASSERT(lastData); Q_ASSERT(context); if (!lastData->isValid()) { QString error = QLatin1String("Cannot assign to non-existent property \"") + toString(name) + QLatin1Char('\"'); context->throwError(error); return; } if (!(lastData->flags & QDeclarativePropertyCache::Data::IsWritable) && !(lastData->flags & QDeclarativePropertyCache::Data::IsQList)) { QString error = QLatin1String("Cannot assign to read-only property \"") + toString(name) + QLatin1Char('\"'); context->throwError(error); return; } QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); if (!evalContext) { // Global object, QScriptContext activation object, QDeclarativeContext object QScriptValue scopeNode = scopeChainValue(context, -3); if (scopeNode.isValid()) { Q_ASSERT(scriptClass(scopeNode) == enginePriv->contextClass); evalContext = enginePriv->contextClass->contextFromValue(scopeNode); } } 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(QLatin1String("this"))) newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject); } QDeclarativeAbstractBinding *delBinding = QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, newBinding); if (delBinding) delBinding->destroy(); if (value.isNull() && lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { QObject *o = 0; int status = -1; int flags = 0; void *argv[] = { &o, 0, &status, &flags }; QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, argv); } else if (value.isUndefined() && lastData->flags & QDeclarativePropertyCache::Data::IsResettable) { void *a[] = { 0 }; QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a); } else if (value.isUndefined() && lastData->propType == qMetaTypeId<QVariant>()) { QDeclarativePropertyPrivate::write(obj, *lastData, QVariant(), evalContext); } else if (value.isUndefined()) { QString error = QLatin1String("Cannot assign [undefined] to ") + QLatin1String(QMetaType::typeName(lastData->propType)); context->throwError(error); } else if (value.isFunction() && !value.isRegExp()) { // this is handled by the binding creation above } else { //### expand optimization for other known types if (lastData->propType == QMetaType::Int && value.isNumber()) { int rawValue = qRoundDouble(value.toNumber()); int status = -1; int flags = 0; void *a[] = { (void *)&rawValue, 0, &status, &flags }; QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); return; } else if (lastData->propType == QMetaType::QReal && value.isNumber()) { qreal rawValue = qreal(value.toNumber()); int status = -1; int flags = 0; void *a[] = { (void *)&rawValue, 0, &status, &flags }; QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); return; } else if (lastData->propType == QMetaType::QString && value.isString()) { const QString &rawValue = value.toString(); int status = -1; int flags = 0; void *a[] = { (void *)&rawValue, 0, &status, &flags }; QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); return; } QVariant v; if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >()); else v = enginePriv->scriptValueToVariant(value, lastData->propType); if (!QDeclarativePropertyPrivate::write(obj, *lastData, v, evalContext)) { const char *valueType = 0; if (v.userType() == QVariant::Invalid) valueType = "null"; else valueType = QMetaType::typeName(v.userType()); QString error = QLatin1String("Cannot assign ") + QLatin1String(valueType) + QLatin1String(" to ") + QLatin1String(QMetaType::typeName(lastData->propType)); context->throwError(error); } } }