231void QQmlPropertyPrivate::initProperty(QObject *obj,
const QString &name,
232 QQmlPropertyPrivate::InitFlags flags)
234 QQmlRefPointer<QQmlTypeNameCache> typeNameCache = context ? context->imports() :
nullptr;
236 QObject *currentObject = obj;
237 QList<QStringView> path;
238 QStringView terminal(name);
240 if (name.contains(QLatin1Char(
'.'))) {
241 path = QStringView{name}.split(QLatin1Char(
'.'));
242 if (path.isEmpty())
return;
245 for (
int ii = 0; ii < path.size() - 1; ++ii) {
246 const QStringView &pathName = path.at(ii);
250 if (typeNameCache && !pathName.isEmpty() && pathName.at(0).isUpper()) {
251 QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
252 QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(enginePrivate);
253 QQmlTypeNameCache::Result r = typeNameCache->query(pathName, typeLoader);
255 if (r.type.isValid()) {
256 QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
259 currentObject = qmlAttachedPropertiesObject(currentObject, func);
260 if (!currentObject)
return;
261 }
else if (r.importNamespace) {
262 if (++ii == path.size())
266 r = typeNameCache->query<QQmlTypeNameCache::QueryNamespaced::No>(
267 path.at(ii), r.importNamespace, typeLoader);
269 if (!r.type.isValid())
272 QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
276 currentObject = qmlAttachedPropertiesObject(currentObject, func);
280 }
else if (r.scriptIndex != -1) {
283 Q_ASSERT(!
"Unreachable");
290 QQmlPropertyData local;
291 const QQmlPropertyData *property = currentObject
292 ? QQmlPropertyCache::property(currentObject, pathName, context, &local)
298 if (currentObject || !(flags & InitFlag::AllowId))
301 for (
auto idContext = context; idContext; idContext = idContext->parent()) {
302 const int objectId = idContext->propertyIndex(pathName.toString());
303 if (objectId != -1 && objectId < idContext->numIdValues()) {
304 currentObject = context->idValue(objectId);
313 }
else if (property->isFunction()) {
317 if (ii == (path.size() - 2) && QQmlMetaType::isValueType(property->propType())) {
319 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(property->propType());
320 if (!valueTypeMetaObject)
return;
322 int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData());
323 if (idx == -1)
return;
325 QMetaProperty vtProp = valueTypeMetaObject->property(idx);
327 Q_ASSERT(idx <= 0x0000FFFF);
329 object = currentObject;
331 valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp));
332 valueTypeData.setPropType(vtProp.metaType());
333 valueTypeData.setCoreIndex(idx);
337 if (!property->isQObject()) {
338 if (
auto asPropertyMap = qobject_cast<QQmlPropertyMap*>(currentObject))
339 currentObject = asPropertyMap->value(path.at(ii).toString()).value<QObject*>();
343 property->readProperty(currentObject, ¤tObject);
346 if (!currentObject)
return;
352 terminal = path.last();
353 }
else if (!currentObject) {
357 auto findSignalInMetaObject = [&](
const QByteArray &signalName) {
358 const QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName);
359 if (!method.isValid())
362 object = currentObject;
367 QQmlData *ddata = QQmlData::get(currentObject,
false);
368 auto findChangeSignal = [&](QStringView signalName) {
369 if (
auto propName = QQmlSignalNames::changedSignalNameToPropertyName(signalName)) {
370 const QQmlPropertyData *d =
371 ddata->propertyCache->property(*propName, currentObject, context);
372 while (d && d->isFunction())
373 d = ddata->propertyCache->overrideData(d);
375 if (d && d->notifyIndex() != -1) {
376 object = currentObject;
377 core = *ddata->propertyCache->signal(d->notifyIndex());
384 const auto findSignal = [&](
const QString &signalName) {
385 if (ddata && ddata->propertyCache) {
387 const QQmlPropertyData *d
388 = ddata->propertyCache->property(signalName, currentObject, context);
393 while (d && !d->isFunction())
394 d = ddata->propertyCache->overrideData(d);
397 object = currentObject;
402 return findChangeSignal(signalName);
405 return findSignalInMetaObject(signalName.toUtf8());
408 auto signalName = QQmlSignalNames::handlerNameToSignalName(terminal);
410 if (findSignal(*signalName))
413 signalName = QQmlSignalNames::badHandlerNameToSignalName(terminal);
415 if (findSignal(*signalName)) {
418 <<
"is not a properly capitalized signal handler name."
419 << QQmlSignalNames::signalNameToHandlerName(*signalName)
420 <<
"would be correct.";
426 if (ddata && ddata->propertyCache) {
427 const QQmlPropertyData *property = ddata->propertyCache->property(
428 terminal, currentObject, context);
431 while (property && !property->isSignal()) {
432 if (!property->isFunction()) {
433 object = currentObject;
435 nameCache = terminal.toString();
438 property = ddata->propertyCache->overrideData(property);
441 if (!(flags & InitFlag::AllowSignal))
445 Q_ASSERT(property->isSignal());
446 object = currentObject;
452 findChangeSignal(terminal);
455 const QByteArray propertyName = terminal.toUtf8();
456 const QMetaProperty prop = findPropertyByName(currentObject->metaObject(), propertyName);
458 if (prop.isValid()) {
459 object = currentObject;
464 if (flags & InitFlag::AllowSignal)
465 findSignalInMetaObject(terminal.toUtf8());
1370 QObject *object,
const QQmlPropertyData &property,
const QVariant &value,
1371 QQmlPropertyData::WriteFlags flags, QMetaType propertyMetaType, QMetaType variantMetaType,
1372 bool isUrl, QQmlEnginePrivate *enginePriv) {
1375 || variantMetaType == QMetaType::fromType<QString>()
1376 || propertyMetaType == QMetaType::fromType<QList<QUrl>>()
1377 || property.isQList()) {
1378 return {
false,
false};
1382 switch (propertyMetaType.id()) {
1383 case QMetaType::Bool:
1384 if (value.canConvert(propertyMetaType)) {
1385 bool b = value.toBool();
1386 return {
true, property.writeProperty(object, &b, flags)};
1388 return {
false,
false};
1389 case QMetaType::Int: {
1391 int i = value.toInt(&ok);
1392 return {ok, ok && property.writeProperty(object, &i, flags)};
1394 case QMetaType::UInt: {
1396 uint u = value.toUInt(&ok);
1397 return {ok, ok && property.writeProperty(object, &u, flags)};
1399 case QMetaType::Double: {
1401 double d = value.toDouble(&ok);
1402 return {ok, ok && property.writeProperty(object, &d, flags)};
1404 case QMetaType::Float: {
1406 float f = value.toFloat(&ok);
1407 return {ok, ok && property.writeProperty(object, &f, flags)};
1409 case QMetaType::QString:
1410 if (value.canConvert(propertyMetaType)) {
1411 QString s = value.toString();
1412 return {
true, property.writeProperty(object, &s, flags)};
1414 return {
false,
false};
1415 case QMetaType::QVariantMap:
1416 if (value.canConvert(propertyMetaType)) {
1417 QVariantMap m = value.toMap();
1418 return {
true, property.writeProperty(object, &m, flags)};
1420 return {
false,
false};
1426 QVariant converted = QQmlValueTypeProvider::createValueType(
1427 value, propertyMetaType, enginePriv ? enginePriv->v4engine() :
nullptr);
1428 if (!converted.isValid()) {
1429 converted = QVariant(propertyMetaType);
1430 if (!QMetaType::convert(value.metaType(), value.constData(),
1431 propertyMetaType, converted.data())) {
1432 return {
false,
false};
1435 return {
true, property.writeProperty(object, converted.data(), flags)};
1482bool QQmlPropertyPrivate::write(
1483 QObject *object,
const QQmlPropertyData &property,
const QVariant &value,
1484 const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
1486 const QMetaType propertyMetaType = property.propType();
1487 const QMetaType variantMetaType = value.metaType();
1489 const BindingFixer bindingFixer(object, property, flags);
1491 if (property.isEnum()) {
1492 QMetaProperty prop = object->metaObject()->property(property.coreIndex());
1495 if (variantMetaType == QMetaType::fromType<
double>()) {
1497 double fractional = std::modf(value.toDouble(), &integral);
1498 if (qFuzzyIsNull(fractional))
1499 v.convert(QMetaType::fromType<qint32>());
1501 return writeEnumProperty(prop, property.coreIndex(), object, v, flags);
1504 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
1505 const bool isUrl = propertyMetaType == QMetaType::fromType<QUrl>();
1508 if (tryAssignBinding(object, property, value, variantMetaType))
1512 if (propertyMetaType == variantMetaType && !isUrl
1513 && propertyMetaType != QMetaType::fromType<QList<QUrl>>() && !property.isQList()) {
1514 return property.writeProperty(object,
const_cast<
void *>(value.constData()), flags);
1515 }
else if (property.isQObject()) {
1516 QVariant val = value;
1518 if (variantMetaType == QMetaType::fromType<std::nullptr_t>()) {
1521 varType = QMetaType::fromType<QObject*>();
1522 val = QVariant(varType,
nullptr);
1524 varType = variantMetaType;
1526 QQmlMetaObject valMo = rawMetaObjectForType(varType);
1527 if (valMo.isNull() || !varType.flags().testFlag(QMetaType::PointerToQObject))
1529 QObject *o = *
static_cast<QObject *
const *>(val.constData());
1530 QQmlMetaObject propMo = rawMetaObjectForType(propertyMetaType);
1535 if (QQmlMetaObject::canConvert(valMo, propMo)) {
1536 return property.writeProperty(object, &o, flags);
1537 }
else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
1541 return property.writeProperty(object, &o, flags);
1545 }
else if (ConvertAndAssignResult result = tryConvertAndAssign(
1546 object, property, value, flags, propertyMetaType, variantMetaType, isUrl,
1548 return result.couldWrite;
1549 }
else if (propertyMetaType == QMetaType::fromType<QVariant>()) {
1550 return property.writeProperty(object,
const_cast<QVariant *>(&value), flags);
1553 if (variantMetaType == QMetaType::fromType<QUrl>()) {
1555 if (compatResolveUrlsOnAssigment() && context && u.isRelative() && !u.isEmpty())
1556 u = context->resolvedUrl(u);
1558 else if (variantMetaType == QMetaType::fromType<QByteArray>())
1559 u = QUrl(QString::fromUtf8(value.toByteArray()));
1560 else if (variantMetaType == QMetaType::fromType<QString>())
1561 u = QUrl(value.toString());
1565 return property.writeProperty(object, &u, flags);
1566 }
else if (propertyMetaType == QMetaType::fromType<QList<QUrl>>()) {
1567 QList<QUrl> urlSeq = compatResolveUrlsOnAssigment()
1568 ? urlSequence(value, context)
1569 : urlSequence(value);
1570 return property.writeProperty(object, &urlSeq, flags);
1571 }
else if (property.isQList()) {
1572 if (propertyMetaType.flags() & QMetaType::IsQmlList) {
1573 QMetaType listValueType = QQmlMetaType::listValueType(propertyMetaType);
1574 QQmlMetaObject valueMetaObject = QQmlMetaType::rawMetaObjectForType(listValueType);
1575 if (valueMetaObject.isNull())
1578 QQmlListProperty<QObject> prop;
1579 property.readProperty(object, &prop);
1581 if (!prop.clear || !prop.append)
1584 const bool useNonsignalingListOps = prop.clear == &QQmlVMEMetaObject::list_clear
1585 && prop.append == &QQmlVMEMetaObject::list_append;
1588 useNonsignalingListOps ? &QQmlVMEMetaObject::list_clear_nosignal : prop.clear;
1590 useNonsignalingListOps ? &QQmlVMEMetaObject::list_append_nosignal : prop.append;
1594 const auto doAppend = [&](QObject *o) {
1595 if (Q_UNLIKELY(o && !QQmlMetaObject::canConvert(o, valueMetaObject))) {
1596 qCWarning(lcIncompatibleElement)
1597 <<
"Cannot append" << o <<
"to a QML list of" << listValueType.name();
1600 propAppend(&prop, o);
1603 if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
1604 QQmlListReference qdlr = value.value<QQmlListReference>();
1605 for (qsizetype ii = 0; ii < qdlr.count(); ++ii)
1606 doAppend(qdlr.at(ii));
1607 }
else if (variantMetaType == QMetaType::fromType<QList<QObject *>>()) {
1608 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1609 for (qsizetype ii = 0; ii < list.size(); ++ii)
1610 doAppend(list.at(ii));
1611 }
else if (variantMetaType == QMetaType::fromType<QList<QVariant>>()) {
1612 const QList<QVariant> &list
1613 = *
static_cast<
const QList<QVariant> *>(value.constData());
1614 for (
const QVariant &entry : list)
1615 doAppend(QQmlMetaType::toQObject(entry));
1616 }
else if (!iterateQObjectContainer(variantMetaType, value.data(), doAppend)) {
1617 doAppend(QQmlMetaType::toQObject(value));
1619 if (useNonsignalingListOps) {
1620 Q_ASSERT(QQmlVMEMetaObject::get(object));
1621 QQmlVMEResolvedList(&prop).activateSignal();
1623 }
else if (variantMetaType == propertyMetaType) {
1625 property.writeProperty(object, v.data(), flags);
1627 QVariant list(propertyMetaType);
1628 const QQmlType type = QQmlMetaType::qmlType(propertyMetaType);
1629 const QMetaSequence sequence = type.listMetaSequence();
1630 if (sequence.canAddValue())
1631 sequence.addValue(list.data(), value.data());
1632 property.writeProperty(object, list.data(), flags);
1634 }
else if (enginePriv && propertyMetaType == QMetaType::fromType<QJSValue>()) {
1636 QJSValue jsValue = QJSValuePrivate::fromReturnedValue(
1637 enginePriv->v4engine()->metaTypeToJS(variantMetaType, value.constData()));
1638 return property.writeProperty(object, &jsValue, flags);
1640 Q_ASSERT(variantMetaType != propertyMetaType);
1644 if (variantMetaType == QMetaType::fromType<QString>())
1645 v = QQmlStringConverters::variantFromString(value.toString(), propertyMetaType, &ok);
1649 if (v.convert(propertyMetaType)) {
1658 QSequentialIterable iterable;
1659 v = QVariant(propertyMetaType);
1660 if (QMetaType::view(
1661 propertyMetaType, v.data(),
1662 QMetaType::fromType<QSequentialIterable>(),
1664 const QMetaSequence propertyMetaSequence = iterable.metaContainer();
1665 if (propertyMetaSequence.canAddValueAtEnd()) {
1666 const QMetaType elementMetaType = iterable.valueMetaType();
1667 void *propertyContainer = iterable.mutableIterable();
1669 if (variantMetaType == elementMetaType) {
1670 propertyMetaSequence.addValueAtEnd(propertyContainer, value.constData());
1672 }
else if (variantMetaType == QMetaType::fromType<QVariantList>()) {
1673 const QVariantList list = value.value<QVariantList>();
1674 for (
const QVariant &valueElement : list) {
1675 if (valueElement.metaType() == elementMetaType) {
1676 propertyMetaSequence.addValueAtEnd(
1677 propertyContainer, valueElement.constData());
1679 QVariant converted(elementMetaType);
1681 valueElement.metaType(), valueElement.constData(),
1682 elementMetaType, converted.data());
1683 propertyMetaSequence.addValueAtEnd(
1684 propertyContainer, converted.constData());
1688 }
else if (elementMetaType.flags().testFlag(QMetaType::PointerToQObject)) {
1689 const QMetaObject *elementMetaObject = elementMetaType.metaObject();
1690 Q_ASSERT(elementMetaObject);
1692 const auto doAppend = [&](QObject *o) {
1693 QObject *casted = elementMetaObject->cast(o);
1694 propertyMetaSequence.addValueAtEnd(propertyContainer, &casted);
1697 if (variantMetaType.flags().testFlag(QMetaType::PointerToQObject)) {
1698 doAppend(*
static_cast<QObject *
const *>(value.data()));
1700 }
else if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
1701 const QQmlListReference *reference
1702 =
static_cast<
const QQmlListReference *>(value.constData());
1703 Q_ASSERT(elementMetaObject);
1704 for (
int i = 0, end = reference->size(); i < end; ++i)
1705 doAppend(reference->at(i));
1707 }
else if (!iterateQObjectContainer(
1708 variantMetaType, value.data(), doAppend)) {
1709 doAppend(QQmlMetaType::toQObject(value));
1712 QVariant converted = value;
1713 if (converted.convert(elementMetaType)) {
1714 propertyMetaSequence.addValueAtEnd(propertyContainer, converted.constData());
1722 if (!ok && QQmlMetaType::isInterface(propertyMetaType)) {
1723 auto valueAsQObject = qvariant_cast<QObject *>(value);
1725 if (
void *iface = valueAsQObject
1726 ? valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(propertyMetaType))
1731 return property.writeProperty(object, &iface, flags);
1736 return property.writeProperty(object,
const_cast<
void *>(v.constData()), flags);