bool EnumTypeResolver::resolveEnumBindings() { for (int i = 0; i < qmlObjects.count(); ++i) { QQmlPropertyCache *propertyCache = propertyCaches.at(i); if (!propertyCache) continue; const QmlIR::Object *obj = qmlObjects.at(i); QmlIR::PropertyResolver resolver(propertyCache); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) continue; if (binding->type != QV4::CompiledData::Binding::Type_Script) continue; const QString propertyName = compiler->stringAt(binding->propertyNameIndex); bool notInRevision = false; QQmlPropertyData *pd = resolver.property(propertyName, ¬InRevision); if (!pd) continue; if (!pd->isEnum() && pd->propType != QMetaType::Int) continue; if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding)) return false; } } return true; }
/*! Returns the value of the \a name property for this context as a QVariant. */ QVariant QQmlContext::contextProperty(const QString &name) const { Q_D(const QQmlContext); QVariant value; int idx = -1; QQmlContextData *data = d->data; const QV4::IdentifierHash<int> &properties = data->propertyNames(); if (properties.count()) idx = properties.value(name); if (idx == -1) { if (data->contextObject) { QObject *obj = data->contextObject; QQmlPropertyData local; QQmlPropertyData *property = QQmlPropertyCache::property(data->engine, obj, name, data, local); if (property) value = obj->metaObject()->property(property->coreIndex()).read(obj); } if (!value.isValid() && parentContext()) value = parentContext()->contextProperty(name); } else { if (idx >= d->propertyValues.count()) value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data()); else value = d->propertyValues[idx]; } return value; }
ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QQmlValueTypeWrapper>()); const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m); QV4::ExecutionEngine *v4 = r->engine(); // Note: readReferenceValue() can change the reference->type. if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) { if (!reference->readReferenceValue()) return Primitive::undefinedValue().asReturnedValue(); } QQmlPropertyData *result = r->d()->propertyCache->property(name, 0, 0); if (!result) return Object::get(m, name, hasProperty); if (hasProperty) *hasProperty = true; if (result->isFunction()) // calling a Q_INVOKABLE function of a value type return QV4::QObjectMethod::create(v4->rootContext(), r, result->coreIndex); #define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \ if (result->propType == metatype) { \ cpptype v; \ void *args[] = { &v, 0 }; \ metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args); \ return QV4::Encode(constructor(v)); \ } const QMetaObject *metaObject = r->d()->propertyCache->metaObject(); int index = result->coreIndex; QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index); void *gadget = r->d()->gadgetPtr; // These four types are the most common used by the value type wrappers VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal); VALUE_TYPE_LOAD(QMetaType::Int, int, int); VALUE_TYPE_LOAD(QMetaType::QString, QString, v4->newString); VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool); QVariant v; void *args[] = { Q_NULLPTR, Q_NULLPTR }; if (result->propType == QMetaType::QVariant) { args[0] = &v; } else { v = QVariant(result->propType, static_cast<void *>(Q_NULLPTR)); args[0] = v.data(); } metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args); return v4->fromVariant(v); #undef VALUE_TYPE_ACCESSOR }
void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType) { QQmlPropertyCache *propCache = QQmlData::ensurePropertyCache(qmlEngine(item), item); for (int i = 0; i < uniformData[shaderType].size(); ++i) { if (signalMappers[shaderType].at(i) == 0) continue; const UniformData &d = uniformData[shaderType].at(i); QQmlPropertyData *pd = propCache->property(QString::fromUtf8(d.name), nullptr, nullptr); if (pd && !pd->isFunction()) { if (pd->notifyIndex() == -1) { qWarning("QQuickOpenGLShaderEffect: property '%s' does not have notification method!", d.name.constData()); } else { auto *mapper = signalMappers[shaderType].at(i); mapper->setSignalIndex(itemMetaObject->property(d.propertyIndex).notifySignal().methodIndex()); Q_ASSERT(item->metaObject() == itemMetaObject); bool ok = QObjectPrivate::connectImpl(item, pd->notifyIndex(), item, nullptr, mapper, Qt::AutoConnection, nullptr, itemMetaObject); if (!ok) qWarning() << "Failed to connect to property" << itemMetaObject->property(d.propertyIndex).name() << "(" << d.propertyIndex << ", signal index" << pd->notifyIndex() << ") of item" << item; } } else { // If the source is set via a dynamic property, like the layer is, then we need this // check to disable the warning. if (!item->property(d.name).isValid()) qWarning("QQuickOpenGLShaderEffect: '%s' does not have a matching property!", d.name.constData()); } if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) { QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value)); if (source) { if (item->window()) QQuickItemPrivate::get(source)->refWindow(item->window()); QObject::connect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*))); } } } }
/*! Constructs a QQmlListReference for \a object's \a property. If \a property is not a list property, an invalid QQmlListReference is created. If \a object is destroyed after the reference is constructed, it will automatically become invalid. That is, it is safe to hold QQmlListReference instances even after \a object is deleted. Passing \a engine is required to access some QML created list properties. If in doubt, and an engine is available, pass it. */ QQmlListReference::QQmlListReference(QObject *object, const char *property, QQmlEngine *engine) : d(0) { if (!object || !property) return; QQmlPropertyData local; QQmlPropertyData *data = QQmlPropertyCache::property(engine, object, QLatin1String(property), 0, local); if (!data || !data->isQList()) return; QQmlEnginePrivate *p = engine?QQmlEnginePrivate::get(engine):0; int listType = p?p->listType(data->propType):QQmlMetaType::listType(data->propType); if (listType == -1) return; d = new QQmlListReferencePrivate; d->object = object; d->elementType = p?p->rawMetaObjectForType(listType):QQmlMetaType::qmlType(listType)->baseMetaObject(); d->propertyType = data->propType; void *args[] = { &d->property, 0 }; QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex, args); }
bool PropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding) { const QmlIR::Object *obj = qmlObjects.at(objectIndex); QQmlPropertyCache *baseTypeCache = 0; QQmlPropertyData *instantiatingProperty = 0; if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) { Q_ASSERT(referencingObjectIndex >= 0); QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex); Q_ASSERT(parentCache); Q_ASSERT(instantiatingBinding->propertyNameIndex != 0); bool notInRevision = false; instantiatingProperty = QmlIR::PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), ¬InRevision); if (instantiatingProperty) { if (instantiatingProperty->isQObject()) { baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType); Q_ASSERT(baseTypeCache); } else if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(instantiatingProperty->propType)) { baseTypeCache = enginePrivate->cache(vt->metaObject()); Q_ASSERT(baseTypeCache); } } } bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0; if (!needVMEMetaObject) { for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) { // On assignments are implemented using value interceptors, which require a VME meta object. needVMEMetaObject = true; // If the on assignment is inside a group property, we need to distinguish between QObject based // group properties and value type group properties. For the former the base type is derived from // the property that references us, for the latter we only need a meta-object on the referencing object // because interceptors can't go to the shared value type instances. if (instantiatingProperty && QQmlValueTypeFactory::isValueType(instantiatingProperty->propType)) { needVMEMetaObject = false; if (!ensureMetaObject(referencingObjectIndex)) return false; } break; } } } if (obj->inheritedTypeNameIndex != 0) { QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); if (typeRef->isFullyDynamicType) { if (obj->propertyCount() > 0) { compiler->recordError(obj->location, tr("Fully dynamic types cannot declare new properties.")); return false; } if (obj->signalCount() > 0) { compiler->recordError(obj->location, tr("Fully dynamic types cannot declare new signals.")); return false; } if (obj->functionCount() > 0) { compiler->recordError(obj->location, tr("Fully Dynamic types cannot declare new functions.")); return false; } } baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); Q_ASSERT(baseTypeCache); } else if (instantiatingBinding && instantiatingBinding->isAttachedProperty()) { QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(instantiatingBinding->propertyNameIndex); Q_ASSERT(typeRef); const QMetaObject *attachedMo = typeRef->type ? typeRef->type->attachedPropertiesType() : 0; if (!attachedMo) { compiler->recordError(instantiatingBinding->location, tr("Non-existent attached object")); return false; } baseTypeCache = enginePrivate->cache(attachedMo); Q_ASSERT(baseTypeCache); } if (needVMEMetaObject) { if (!createMetaObject(objectIndex, obj, baseTypeCache)) return false; } else if (baseTypeCache) { propertyCaches[objectIndex] = baseTypeCache; baseTypeCache->addref(); } if (propertyCaches.at(objectIndex)) { for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) if (binding->type >= QV4::CompiledData::Binding::Type_Object) { if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding)) return false; } } return true; }
bool PropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache) { QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate), obj->propertyCount(), obj->functionCount() + obj->propertyCount() + obj->signalCount(), obj->signalCount() + obj->propertyCount()); propertyCaches[objectIndex] = cache; struct TypeData { QV4::CompiledData::Property::Type dtype; int metaType; } builtinTypes[] = { { QV4::CompiledData::Property::Var, qMetaTypeId<QJSValue>() }, { QV4::CompiledData::Property::Variant, QMetaType::QVariant }, { QV4::CompiledData::Property::Int, QMetaType::Int }, { QV4::CompiledData::Property::Bool, QMetaType::Bool }, { QV4::CompiledData::Property::Real, QMetaType::Double }, { QV4::CompiledData::Property::String, QMetaType::QString }, { QV4::CompiledData::Property::Url, QMetaType::QUrl }, { QV4::CompiledData::Property::Color, QMetaType::QColor }, { QV4::CompiledData::Property::Font, QMetaType::QFont }, { QV4::CompiledData::Property::Time, QMetaType::QTime }, { QV4::CompiledData::Property::Date, QMetaType::QDate }, { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime }, { QV4::CompiledData::Property::Rect, QMetaType::QRectF }, { QV4::CompiledData::Property::Point, QMetaType::QPointF }, { QV4::CompiledData::Property::Size, QMetaType::QSizeF }, { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D }, { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D }, { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D }, { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 }, { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion } }; static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); QByteArray newClassName; if (objectIndex == compiler->rootObjectIndex()) { QString path = compiler->data()->url.path(); int lastSlash = path.lastIndexOf(QLatin1Char('/')); if (lastSlash > -1) { QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); } } if (newClassName.isEmpty()) { newClassName = QQmlMetaObject(baseTypeCache).className(); newClassName.append("_QML_"); newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1))); } cache->_dynamicClassName = newClassName; int aliasCount = 0; int varPropCount = 0; QmlIR::PropertyResolver resolver(baseTypeCache); for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { if (p->type == QV4::CompiledData::Property::Alias) aliasCount++; else if (p->type == QV4::CompiledData::Property::Var) varPropCount++; // No point doing this for both the alias and non alias cases bool notInRevision = false; QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), ¬InRevision); if (d && d->isFinal()) { compiler->recordError(p->location, tr("Cannot override FINAL property")); return false; } } typedef QQmlVMEMetaData VMD; QByteArray &dynamicData = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData) + obj->propertyCount() * sizeof(VMD::PropertyData) + obj->functionCount() * sizeof(VMD::MethodData) + aliasCount * sizeof(VMD::AliasData), 0); int effectivePropertyIndex = cache->propertyIndexCacheStart; int effectiveMethodIndex = cache->methodIndexCacheStart; // For property change signal override detection. // We prepopulate a set of signal names which already exist in the object, // and throw an error if there is a signal/method defined as an override. QSet<QString> seenSignals; seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged"); QQmlPropertyCache *parentCache = cache; while ((parentCache = parentCache->parent())) { if (int pSigCount = parentCache->signalCount()) { int pSigOffset = parentCache->signalOffset(); for (int i = pSigOffset; i < pSigCount; ++i) { QQmlPropertyData *currPSig = parentCache->signal(i); // XXX TODO: find a better way to get signal name from the property data :-/ for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin(); iter != parentCache->stringCache.end(); ++iter) { if (currPSig == (*iter).second) { seenSignals.insert(iter.key()); break; } } } } } // First set up notify signals for properties - first normal, then var, then alias enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 }; for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias if (ii == NSS_Var && varPropCount == 0) continue; else if (ii == NSS_Alias && aliasCount == 0) continue; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias || p->type == QV4::CompiledData::Property::Var)) || ((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) || ((ii == NSS_Alias) && (p->type != QV4::CompiledData::Property::Alias))) continue; quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMESignal; QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed"); seenSignals.insert(changedSigName); cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); } } // Dynamic signals for (const QmlIR::Signal *s = obj->firstSignal(); s; s = s->next) { const int paramCount = s->parameters->count; QList<QByteArray> names; QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0); if (paramCount) { paramTypes[0] = paramCount; QmlIR::SignalParameter *param = s->parameters->first; for (int i = 0; i < paramCount; ++i, param = param->next) { names.append(stringAt(param->nameIndex).toUtf8()); if (param->type < builtinTypeCount) { // built-in type paramTypes[i + 1] = builtinTypes[param->type].metaType; } else { // lazily resolved type Q_ASSERT(param->type == QV4::CompiledData::Property::Custom); const QString customTypeName = stringAt(param->customTypeNameIndex); QQmlType *qmltype = 0; if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0)) { compiler->recordError(s->location, tr("Invalid signal parameter type: %1").arg(customTypeName)); return false; } if (qmltype->isComposite()) { // Composite type usage qDebug() << "Composite type usage2" << qmltype->sourceUrl() << "Line" << param->location.line << "Col" << param->location.column; QmlCompilation::TypeReference *typeRef = compiler->findTypeRef(param->customTypeNameIndex); Q_ASSERT(typeRef->component->compiledData != NULL); paramTypes[i + 1] = typeRef->component->compiledData->metaTypeId; } else { paramTypes[i + 1] = qmltype->typeId(); } } } } ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMESignal; if (paramCount) flags |= QQmlPropertyData::HasArguments; QString signalName = stringAt(s->nameIndex); if (seenSignals.contains(signalName)) { compiler->recordError(s->location, tr("Duplicate signal name: invalid override of property change signal or superclass signal")); return false; } seenSignals.insert(signalName); cache->appendSignal(signalName, flags, effectiveMethodIndex++, paramCount?paramTypes.constData():0, names); } // Dynamic slots for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) { QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration; quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction; if (astFunction->formals) flags |= QQmlPropertyData::HasArguments; QString slotName = astFunction->name.toString(); if (seenSignals.contains(slotName)) { compiler->recordError(s->location, tr("Duplicate method name: invalid override of property change signal or superclass signal")); return false; } // Note: we don't append slotName to the seenSignals list, since we don't // protect against overriding change signals or methods with properties. QList<QByteArray> parameterNames; QQmlJS::AST::FormalParameterList *param = astFunction->formals; while (param) { parameterNames << param->name.toUtf8(); param = param->next; } cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames); } // Dynamic properties (except var and aliases) int effectiveSignalIndex = cache->signalHandlerIndexCacheStart; int propertyIdx = 0; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) { if (p->type == QV4::CompiledData::Property::Alias || p->type == QV4::CompiledData::Property::Var) continue; int propertyType = 0; int vmePropertyType = 0; quint32 propertyFlags = 0; if (p->type < builtinTypeCount) { propertyType = builtinTypes[p->type].metaType; vmePropertyType = propertyType; if (p->type == QV4::CompiledData::Property::Variant) propertyFlags |= QQmlPropertyData::IsQVariant; } else { Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList || p->type == QV4::CompiledData::Property::Custom); QQmlType *qmltype = 0; if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) { compiler->recordError(p->location, tr("Invalid property type")); return false; } Q_ASSERT(qmltype); if (qmltype->isComposite()) { // Composite type usage QmlCompilation::TypeReference *typeRef = compiler->findTypeRef(p->customTypeNameIndex); Q_ASSERT(typeRef->component->compiledData != NULL); QQmlCompiledData *data = typeRef->component->compiledData; if (p->type == QV4::CompiledData::Property::Custom) { propertyType = data->metaTypeId; vmePropertyType = QMetaType::QObjectStar; } else { propertyType = data->listMetaTypeId; vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); } } else { if (p->type == QV4::CompiledData::Property::Custom) { propertyType = qmltype->typeId(); vmePropertyType = QMetaType::QObjectStar; } else { propertyType = qmltype->qListTypeId(); vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); } } if (p->type == QV4::CompiledData::Property::Custom) propertyFlags |= QQmlPropertyData::IsQObjectDerived; else propertyFlags |= QQmlPropertyData::IsQList; } if ((!p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList) propertyFlags |= QQmlPropertyData::IsWritable; QString propertyName = stringAt(p->nameIndex); if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, propertyType, effectiveSignalIndex); effectiveSignalIndex++; VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType; vmd->propertyCount++; } // Now do var properties propertyIdx = 0; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) { if (p->type != QV4::CompiledData::Property::Var) continue; quint32 propertyFlags = QQmlPropertyData::IsVarProperty; if (!p->flags & QV4::CompiledData::Property::IsReadOnly) propertyFlags |= QQmlPropertyData::IsWritable; VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant; vmd->propertyCount++; ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++; QString propertyName = stringAt(p->nameIndex); if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, QMetaType::QVariant, effectiveSignalIndex); effectiveSignalIndex++; } // Alias property count. Actual data is setup in buildDynamicMetaAliases ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; // Dynamic slot data - comes after the property data for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) { QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration; int formalsCount = 0; QQmlJS::AST::FormalParameterList *param = astFunction->formals; while (param) { formalsCount++; param = param->next; } VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ### formalsCount, /* s->location.start.line */0 }; // ### VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount); vmd->methodCount++; md = methodData; } return true; }
void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) { Q_ASSERT(m->as<QQmlValueTypeWrapper>()); ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine(); Scope scope(v4); if (scope.hasException()) return; Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m)); Scoped<QQmlValueTypeReference> reference(scope, m->d()); int writeBackPropertyType = -1; if (reference) { QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property); if (!writebackProperty.isWritable() || !reference->readReferenceValue()) return; writeBackPropertyType = writebackProperty.userType(); } const QMetaObject *metaObject = r->d()->propertyCache->metaObject(); const QQmlPropertyData *pd = r->d()->propertyCache->property(name, 0, 0); if (!pd) return; QMetaProperty property = metaObject->property(pd->coreIndex); Q_ASSERT(property.isValid()); QQmlBinding *newBinding = 0; QV4::ScopedFunctionObject f(scope, value); if (reference && f) { if (!f->isBinding()) { // assigning a JS function to a non-var-property is not allowed. QString error = QStringLiteral("Cannot assign JavaScript function to value-type property"); ScopedString e(scope, v4->newString(error)); v4->throwError(e); return; } QQmlContextData *context = QmlContextWrapper::callingContext(v4); QQmlPropertyData cacheData; cacheData.setFlags(QQmlPropertyData::IsWritable | QQmlPropertyData::IsValueTypeVirtual); cacheData.propType = writeBackPropertyType; cacheData.coreIndex = reference->d()->property; cacheData.valueTypeFlags = 0; cacheData.valueTypeCoreIndex = pd->coreIndex; cacheData.valueTypePropType = property.userType(); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); bindingFunction->initBindingLocation(); newBinding = new QQmlBinding(value, reference->d()->object, context); newBinding->setTarget(reference->d()->object, cacheData, context); } if (reference) { QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(reference->d()->object, reference->d()->property, pd->coreIndex, newBinding); if (oldBinding) oldBinding->destroy(); } if (newBinding) return; QVariant v = v4->toVariant(value, property.userType()); if (property.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double) v = v.toInt(); void *gadget = r->d()->gadgetPtr; property.writeOnGadget(gadget, v); if (reference) { if (writeBackPropertyType == QMetaType::QVariant) { QVariant variantReferenceValue = r->d()->toVariant(); int flags = 0; int status = -1; void *a[] = { &variantReferenceValue, 0, &status, &flags }; QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a); } else { int flags = 0; int status = -1; void *a[] = { r->d()->gadgetPtr, 0, &status, &flags }; QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a); } } }
bool QmcTypeUnitComponentAndAliasResolver::addAliases() { // add aliases //QmcUnitAlias al = {0, 0, 0, 8, 0, 0, 24}; //qmcTypeUnit->unit->aliases.append(al); // see QQmlComponentAndAliasResolver::resolve int effectiveAliasIndex = -1; int effectivePropertyIndex = -1; int effectiveSignalIndex = -1; int currentObjectIndex = -1; QQmlPropertyCache *propertyCache = NULL; foreach (const QmcUnitAlias &alias, qmcTypeUnit->unit->aliases) { if ((int)alias.objectIndex != currentObjectIndex) { currentObjectIndex = alias.objectIndex; effectiveAliasIndex = 0; propertyCache = qmcTypeUnit->propertyCaches.at(alias.objectIndex); effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count(); effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count(); } Q_ASSERT(propertyCache); QQmlVMEMetaData::AliasData aliasData; aliasData.contextIdx = alias.contextIndex; aliasData.propertyIdx = alias.targetPropertyIndex; aliasData.propType = alias.propertyType; aliasData.flags = alias.flags; aliasData.notifySignal = alias.notifySignal; typedef QQmlVMEMetaData VMD; QByteArray &dynamicData = qmcTypeUnit->vmeMetaObjects[alias.objectIndex]; Q_ASSERT(!dynamicData.isEmpty()); VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); *(vmd->aliasData() + effectiveAliasIndex++) = aliasData; Q_ASSERT(dynamicData.isDetached()); // TBD: propertyCache const QV4::CompiledData::Object *obj = qmcTypeUnit->compiledData->qmlUnit->objectAt(alias.objectIndex); Q_ASSERT(obj); Q_ASSERT(alias.propertyIndex < obj->nProperties); const QV4::CompiledData::Property *p = &obj->propertyTable()[alias.propertyIndex]; Q_ASSERT(p); QString propertyName = qmcTypeUnit->stringAt(p->nameIndex); const QString aliasPropertyValue = qmcTypeUnit->stringAt(p->aliasPropertyValueIndex); //const int idIndex = p->aliasIdValueIndex; const int targetObjectIndex = alias.targetObjectIndex; #if 0 const int idIndex = p->aliasIdValueIndex; const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1); if (targetObjectIndex == -1) { recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); return false; } #endif QStringRef property; QStringRef subProperty; const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.')); if (propertySeparator != -1) { property = aliasPropertyValue.leftRef(propertySeparator); subProperty = aliasPropertyValue.midRef(propertySeparator + 1); } else property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length()); quint32 propertyFlags = QQmlPropertyData::IsAlias; int type = 0; bool writable = false; bool resettable = false; if (property.isEmpty()) { const QV4::CompiledData::Object *targetObject = qmcTypeUnit->compiledData->qmlUnit->objectAt(targetObjectIndex); QQmlCompiledData::TypeReference *typeRef = qmcTypeUnit->compiledData->resolvedTypes.value(targetObject->inheritedTypeNameIndex); Q_ASSERT(typeRef); if (typeRef->type) type = typeRef->type->typeId(); else type = typeRef->component->metaTypeId; //flags |= QML_ALIAS_FLAG_PTR; propertyFlags |= QQmlPropertyData::IsQObjectDerived; } else { QQmlPropertyCache *targetCache = qmcTypeUnit->propertyCaches.at(targetObjectIndex); Q_ASSERT(targetCache); QmlIR::PropertyResolver resolver(targetCache); QQmlPropertyData *targetProperty = resolver.property(property.toString()); if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) { return false; } //propIdx = targetProperty->coreIndex; type = targetProperty->propType; writable = targetProperty->isWritable(); resettable = targetProperty->isResettable(); //notifySignal = targetProperty->notifyIndex; if (!subProperty.isEmpty()) { QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type); if (!valueType) { return false; } //propType = type; int valueTypeIndex = valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData()); if (valueTypeIndex == -1) { return false; } Q_ASSERT(valueTypeIndex <= 0x0000FFFF); //propIdx |= (valueTypeIndex << 16); if (valueType->metaObject()->property(valueTypeIndex).isEnumType()) type = QVariant::Int; else type = valueType->metaObject()->property(valueTypeIndex).userType(); } else { if (targetProperty->isEnum()) { type = QVariant::Int; } else { // Copy type flags propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask; if (targetProperty->isVarProperty()) propertyFlags |= QQmlPropertyData::IsQVariant; #if 0 if (targetProperty->isQObject()) flags |= QML_ALIAS_FLAG_PTR; #endif } } } if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable) propertyFlags |= QQmlPropertyData::IsWritable; else propertyFlags &= ~QQmlPropertyData::IsWritable; if (resettable) propertyFlags |= QQmlPropertyData::IsResettable; else propertyFlags &= ~QQmlPropertyData::IsResettable; if ((int)alias.propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName; propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, type, effectiveSignalIndex++); } return true; }