1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlproperty.h"
5#include "qqmlproperty_p.h"
6
7#include "qqmlboundsignal_p.h"
8#include "qqmlcontext.h"
9#include "qqmlboundsignal_p.h"
10#include "qqmlengine.h"
11#include "qqmlengine_p.h"
12#include "qqmldata_p.h"
13#include "qqmlstringconverters_p.h"
14
15#include "qqmlvmemetaobject_p.h"
16#include "qqmlvaluetypeproxybinding_p.h"
17#include <private/qjsvalue_p.h>
18#include <private/qv4functionobject_p.h>
19#include <private/qv4qobjectwrapper_p.h>
20#include <private/qqmlbuiltinfunctions_p.h>
21#include <private/qqmlirbuilder_p.h>
22#include <QtQml/private/qqmllist_p.h>
23
24#include <QStringList>
25#include <QVector>
26#include <private/qmetaobject_p.h>
27#include <private/qqmlvaluetypewrapper_p.h>
28#include <QtCore/qdebug.h>
29#include <cmath>
30#include <QtQml/QQmlPropertyMap>
31#include <QtCore/private/qproperty_p.h>
32#include <QtCore/qsequentialiterable.h>
33
34QT_BEGIN_NAMESPACE
35
36DEFINE_BOOL_CONFIG_OPTION(compatResolveUrlsOnAssigment, QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT);
37
38/*!
39\class QQmlProperty
40\since 5.0
41\inmodule QtQml
42\brief The QQmlProperty class abstracts accessing properties on objects created from QML.
43
44As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
45and interact with objects created by QML. However, some of the new features provided by QML - such
46as type safety and attached properties - are most easily used through the QQmlProperty class
47that simplifies some of their natural complexity.
48
49Unlike QMetaProperty which represents a property on a class type, QQmlProperty encapsulates
50a property on a specific object instance. To read a property's value, programmers create a
51QQmlProperty instance and call the read() method. Likewise to write a property value the
52write() method is used.
53
54For example, for the following QML code:
55
56\qml
57// MyItem.qml
58import QtQuick 2.0
59
60Text { text: "A bit of text" }
61\endqml
62
63The \l Text object's properties could be accessed using QQmlProperty, like this:
64
65\code
66#include <QQmlProperty>
67#include <QGraphicsObject>
68
69...
70
71QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
72QQmlProperty property(view.rootObject(), "font.pixelSize");
73qWarning() << "Current pixel size:" << property.read().toInt();
74property.write(24);
75qWarning() << "Pixel size should now be 24:" << property.read().toInt();
76\endcode
77*/
78
79/*!
80 Create an invalid QQmlProperty.
81*/
82QQmlProperty::QQmlProperty() = default;
83
84/*! \internal */
85QQmlProperty::~QQmlProperty()
86{
87 if (d)
88 d->release();
89 d = nullptr;
90}
91
92/*!
93 Creates a QQmlProperty for the default property of \a obj. If there is no
94 default property, an invalid QQmlProperty will be created.
95 */
96QQmlProperty::QQmlProperty(QObject *obj)
97: d(new QQmlPropertyPrivate)
98{
99 d->initDefault(obj);
100}
101
102/*!
103 Creates a QQmlProperty for the default property of \a obj
104 using the \l{QQmlContext} {context} \a ctxt. If there is
105 no default property, an invalid QQmlProperty will be
106 created.
107 */
108QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
109: d(new QQmlPropertyPrivate)
110{
111 if (ctxt) {
112 d->context = QQmlContextData::get(context: ctxt);
113 d->engine = ctxt->engine();
114 }
115 d->initDefault(obj);
116}
117
118/*!
119 Creates a QQmlProperty for the default property of \a obj
120 using the environment for instantiating QML components that is
121 provided by \a engine. If there is no default property, an
122 invalid QQmlProperty will be created.
123 */
124QQmlProperty::QQmlProperty(QObject *obj, QQmlEngine *engine)
125 : d(new QQmlPropertyPrivate)
126{
127 d->engine = engine;
128 d->initDefault(obj);
129}
130
131/*!
132 Initialize from the default property of \a obj
133*/
134void QQmlPropertyPrivate::initDefault(QObject *obj)
135{
136 if (!obj)
137 return;
138
139 QMetaProperty p = QQmlMetaType::defaultProperty(obj);
140 core.load(p);
141 if (core.isValid())
142 object = obj;
143}
144
145/*!
146 Creates a QQmlProperty for the property \a name of \a obj.
147 */
148QQmlProperty::QQmlProperty(QObject *obj, const QString &name)
149: d(new QQmlPropertyPrivate)
150{
151 d->initProperty(obj, name);
152 if (!isValid()) d->object = nullptr;
153}
154
155/*!
156 Creates a QQmlProperty for the property \a name of \a obj
157 using the \l{QQmlContext} {context} \a ctxt.
158
159 Creating a QQmlProperty without a context will render some
160 properties - like attached properties - inaccessible.
161*/
162QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
163: d(new QQmlPropertyPrivate)
164{
165 if (ctxt) {
166 d->context = QQmlContextData::get(context: ctxt);
167 d->engine = ctxt->engine();
168 }
169
170 d->initProperty(obj, name);
171 if (!isValid()) {
172 d->object = nullptr;
173 d->context.reset();
174 d->engine = nullptr;
175 }
176}
177
178/*!
179 Creates a QQmlProperty for the property \a name of \a obj
180 using the environment for instantiating QML components that is
181 provided by \a engine.
182 */
183QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine)
184: d(new QQmlPropertyPrivate)
185{
186 d->engine = engine;
187 d->initProperty(obj, name);
188 if (!isValid()) {
189 d->object = nullptr;
190 d->context.reset();
191 d->engine = nullptr;
192 }
193}
194
195QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propertyName,
196 const QQmlRefPointer<QQmlContextData> &context,
197 QQmlPropertyPrivate::InitFlags flags)
198{
199 QQmlProperty result;
200 auto d = new QQmlPropertyPrivate;
201 result.d = d;
202 d->context = context;
203 d->engine = context ? context->engine() : nullptr;
204 d->initProperty(obj: target, name: propertyName, flags);
205 if (!result.isValid()) {
206 d->object = nullptr;
207 d->context.reset();
208 d->engine = nullptr;
209 }
210 return result;
211}
212
213bool QQmlPropertyPrivate::resolveUrlsOnAssignment()
214{
215 return ::compatResolveUrlsOnAssigment();
216}
217
218QQmlRefPointer<QQmlContextData> QQmlPropertyPrivate::effectiveContext() const
219{
220 if (context)
221 return context;
222 else if (engine)
223 return QQmlContextData::get(context: engine->rootContext());
224 else
225 return nullptr;
226}
227
228// ### Qt7: Do not accept the "onFoo" syntax for signals anymore, and change the flags accordingly.
229void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
230 QQmlPropertyPrivate::InitFlags flags)
231{
232 QQmlRefPointer<QQmlTypeNameCache> typeNameCache = context ? context->imports() : nullptr;
233
234 QObject *currentObject = obj;
235 QList<QStringView> path;
236 QStringView terminal(name);
237
238 if (name.contains(c: QLatin1Char('.'))) {
239 path = QStringView{name}.split(sep: QLatin1Char('.'));
240 if (path.isEmpty()) return;
241
242 // Everything up to the last property must be an "object type" property
243 for (int ii = 0; ii < path.size() - 1; ++ii) {
244 const QStringView &pathName = path.at(i: ii);
245
246 // Types must begin with an uppercase letter (see checkRegistration()
247 // in qqmlmetatype.cpp for the enforcement of this).
248 if (typeNameCache && !pathName.isEmpty() && pathName.at(n: 0).isUpper()) {
249 QQmlTypeNameCache::Result r = typeNameCache->query(key: pathName);
250 if (r.isValid()) {
251 if (r.type.isValid()) {
252 QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(e: engine);
253 QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(engine: enginePrivate);
254 if (!func) return; // Not an attachable type
255
256 currentObject = qmlAttachedPropertiesObject(currentObject, func);
257 if (!currentObject) return; // Something is broken with the attachable type
258 } else if (r.importNamespace) {
259 if (++ii == path.size())
260 return; // No type following the namespace
261
262 // TODO: Do we really _not_ want to query the namespaced types here?
263 r = typeNameCache->query<QQmlTypeNameCache::QueryNamespaced::No>(
264 key: path.at(i: ii), importNamespace: r.importNamespace);
265
266 if (!r.type.isValid())
267 return; // Invalid type in namespace
268
269 QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(e: engine);
270 QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(engine: enginePrivate);
271 if (!func)
272 return; // Not an attachable type
273
274 currentObject = qmlAttachedPropertiesObject(currentObject, func);
275 if (!currentObject)
276 return; // Something is broken with the attachable type
277
278 } else if (r.scriptIndex != -1) {
279 return; // Not a type
280 } else {
281 Q_ASSERT(!"Unreachable");
282 }
283 continue;
284 }
285
286 }
287
288 QQmlPropertyData local;
289 const QQmlPropertyData *property = currentObject
290 ? QQmlPropertyCache::property(currentObject, pathName, context, &local)
291 : nullptr;
292
293 if (!property) {
294 // Not a property; Might be an ID
295 // You can't look up an ID on a non-null object, though.
296 if (currentObject || !(flags & InitFlag::AllowId))
297 return;
298
299 for (auto idContext = context; idContext; idContext = idContext->parent()) {
300 const int objectId = idContext->propertyIndex(name: pathName.toString());
301 if (objectId != -1 && objectId < idContext->numIdValues()) {
302 currentObject = context->idValue(index: objectId);
303 break;
304 }
305 }
306
307 if (!currentObject)
308 return;
309
310 continue;
311 } else if (property->isFunction()) {
312 return; // Not an object property
313 }
314
315 if (ii == (path.size() - 2) && QQmlMetaType::isValueType(type: property->propType())) {
316 // We're now at a value type property
317 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(type: property->propType());
318 if (!valueTypeMetaObject) return; // Not a value type
319
320 int idx = valueTypeMetaObject->indexOfProperty(name: path.last().toUtf8().constData());
321 if (idx == -1) return; // Value type property does not exist
322
323 QMetaProperty vtProp = valueTypeMetaObject->property(index: idx);
324
325 Q_ASSERT(idx <= 0x0000FFFF);
326
327 object = currentObject;
328 core = *property;
329 valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp));
330 valueTypeData.setPropType(vtProp.metaType());
331 valueTypeData.setCoreIndex(idx);
332
333 return;
334 } else {
335 if (!property->isQObject()) {
336 if (auto asPropertyMap = qobject_cast<QQmlPropertyMap*>(object: currentObject))
337 currentObject = asPropertyMap->value(key: path.at(i: ii).toString()).value<QObject*>();
338 else
339 return; // Not an object property, and not a property map
340 } else {
341 property->readProperty(target: currentObject, property: &currentObject);
342 }
343
344 if (!currentObject) return; // No value
345
346 }
347
348 }
349
350 terminal = path.last();
351 } else if (!currentObject) {
352 return;
353 }
354
355 auto findSignalInMetaObject = [&](const QByteArray &signalName) {
356 const QMetaMethod method = findSignalByName(mo: currentObject->metaObject(), signalName);
357 if (!method.isValid())
358 return false;
359
360 object = currentObject;
361 core.load(method);
362 return true;
363 };
364
365 QQmlData *ddata = QQmlData::get(object: currentObject, create: false);
366 auto findChangeSignal = [&](QStringView signalName) {
367 const QString changed = QStringLiteral("Changed");
368 if (signalName.endsWith(s: changed)) {
369 const QStringView propName = signalName.first(n: signalName.size() - changed.size());
370 const QQmlPropertyData *d = ddata->propertyCache->property(key: propName, object: currentObject, context);
371 while (d && d->isFunction())
372 d = ddata->propertyCache->overrideData(data: d);
373
374 if (d && d->notifyIndex() != -1) {
375 object = currentObject;
376 core = *ddata->propertyCache->signal(index: d->notifyIndex());
377 return true;
378 }
379 }
380 return false;
381 };
382
383 static constexpr QLatin1String On("on");
384 static constexpr qsizetype StrlenOn = On.size();
385
386 const QString terminalString = terminal.toString();
387 if (QmlIR::IRBuilder::isSignalPropertyName(name: terminalString)) {
388 QString signalName = terminalString.mid(position: 2);
389 int firstNon_;
390 int length = signalName.size();
391 for (firstNon_ = 0; firstNon_ < length; ++firstNon_)
392 if (signalName.at(i: firstNon_) != u'_')
393 break;
394 signalName[firstNon_] = signalName.at(i: firstNon_).toLower();
395
396 if (ddata && ddata->propertyCache) {
397 // Try method
398 const QQmlPropertyData *d = ddata->propertyCache->property(
399 key: signalName, object: currentObject, context);
400
401 // ### Qt7: This code treats methods as signals. It should use d->isSignal().
402 // That would be a change in behavior, though. Right now you can construct a
403 // QQmlProperty from such a thing.
404 while (d && !d->isFunction())
405 d = ddata->propertyCache->overrideData(data: d);
406
407 if (d) {
408 object = currentObject;
409 core = *d;
410 return;
411 }
412
413 if (findChangeSignal(signalName))
414 return;
415 } else if (findSignalInMetaObject(signalName.toUtf8())) {
416 return;
417 }
418 } else if (terminalString.size() > StrlenOn && terminalString.startsWith(s: On)) {
419 // This is quite wrong. But we need it for backwards compatibility.
420 QString signalName = terminalString.sliced(pos: 2);
421 signalName.front() = signalName.front().toLower();
422
423 QString handlerName = On + signalName;
424 const auto end = handlerName.end();
425 auto result = std::find_if(
426 first: std::next(x: handlerName.begin(), n: StrlenOn), last: end,
427 pred: [](const QChar &c) { return c.isLetter(); });
428 if (result != end)
429 *result = result->toUpper();
430
431 qWarning()
432 << terminalString
433 << "is not a properly capitalized signal handler name."
434 << handlerName
435 << "would be correct.";
436 if (findSignalInMetaObject(signalName.toUtf8()))
437 return;
438 }
439
440 if (ddata && ddata->propertyCache) {
441 const QQmlPropertyData *property = ddata->propertyCache->property(
442 key: terminal, object: currentObject, context);
443
444 // Technically, we might find an override that is not a function.
445 while (property && !property->isSignal()) {
446 if (!property->isFunction()) {
447 object = currentObject;
448 core = *property;
449 nameCache = terminalString;
450 return;
451 }
452 property = ddata->propertyCache->overrideData(data: property);
453 }
454
455 if (!(flags & InitFlag::AllowSignal))
456 return;
457
458 if (property) {
459 Q_ASSERT(property->isSignal());
460 object = currentObject;
461 core = *property;
462 return;
463 }
464
465 // At last: Try the change signal.
466 findChangeSignal(terminal);
467 } else {
468 // We might still find the property in the metaobject, even without property cache.
469 const QByteArray propertyName = terminal.toUtf8();
470 const QMetaProperty prop = findPropertyByName(mo: currentObject->metaObject(), propertyName);
471
472 if (prop.isValid()) {
473 object = currentObject;
474 core.load(prop);
475 return;
476 }
477
478 if (flags & InitFlag::AllowSignal)
479 findSignalInMetaObject(terminal.toUtf8());
480 }
481}
482
483/*! \internal
484 Returns the index of this property's signal, in the signal index range
485 (see QObjectPrivate::signalIndex()). This is different from
486 QMetaMethod::methodIndex().
487*/
488int QQmlPropertyPrivate::signalIndex() const
489{
490 Q_ASSERT(type() == QQmlProperty::SignalProperty);
491 QMetaMethod m = object->metaObject()->method(index: core.coreIndex());
492 return QMetaObjectPrivate::signalIndex(m);
493}
494
495/*!
496 Create a copy of \a other.
497*/
498QQmlProperty::QQmlProperty(const QQmlProperty &other)
499{
500 d = other.d;
501 if (d)
502 d->addref();
503}
504
505/*!
506 \enum QQmlProperty::PropertyTypeCategory
507
508 This enum specifies a category of QML property.
509
510 \value InvalidCategory The property is invalid, or is a signal property.
511 \value List The property is a QQmlListProperty list property
512 \value Object The property is a QObject derived type pointer
513 \value Normal The property is a normal value property.
514 */
515
516/*!
517 \enum QQmlProperty::Type
518
519 This enum specifies a type of QML property.
520
521 \value Invalid The property is invalid.
522 \value Property The property is a regular Qt property.
523 \value SignalProperty The property is a signal property.
524*/
525
526/*!
527 Returns the property category.
528*/
529QQmlProperty::PropertyTypeCategory QQmlProperty::propertyTypeCategory() const
530{
531 return d ? d->propertyTypeCategory() : InvalidCategory;
532}
533
534QQmlProperty::PropertyTypeCategory
535QQmlPropertyPrivate::propertyTypeCategory() const
536{
537 uint type = this->type();
538
539 if (isValueType()) {
540 return QQmlProperty::Normal;
541 } else if (type & QQmlProperty::Property) {
542 QMetaType type = propertyType();
543 if (!type.isValid())
544 return QQmlProperty::InvalidCategory;
545 else if (QQmlMetaType::isValueType(type))
546 return QQmlProperty::Normal;
547 else if (core.isQObject())
548 return QQmlProperty::Object;
549 else if (core.isQList())
550 return QQmlProperty::List;
551 else
552 return QQmlProperty::Normal;
553 }
554
555 return QQmlProperty::InvalidCategory;
556}
557
558/*!
559 Returns the type name of the property, or 0 if the property has no type
560 name.
561*/
562const char *QQmlProperty::propertyTypeName() const
563{
564 if (!d)
565 return nullptr;
566 if (d->isValueType()) {
567 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(type: d->core.propType());
568 Q_ASSERT(valueTypeMetaObject);
569 return valueTypeMetaObject->property(index: d->valueTypeData.coreIndex()).typeName();
570 } else if (d->object && type() & Property && d->core.isValid()) {
571 return d->object->metaObject()->property(index: d->core.coreIndex()).typeName();
572 } else {
573 return nullptr;
574 }
575}
576
577/*!
578 Returns true if \a other and this QQmlProperty represent the same
579 property.
580*/
581bool QQmlProperty::operator==(const QQmlProperty &other) const
582{
583 if (!d || !other.d)
584 return false;
585 // category is intentially omitted here as it is generated
586 // from the other members
587 return d->object == other.d->object &&
588 d->core.coreIndex() == other.d->core.coreIndex() &&
589 d->valueTypeData.coreIndex() == other.d->valueTypeData.coreIndex();
590}
591
592/*!
593 Returns the metatype id of the property, or QMetaType::UnknownType if the
594 property has no metatype.
595
596 \sa propertyMetaType
597*/
598int QQmlProperty::propertyType() const
599{
600 return d ? d->propertyType().id() : int(QMetaType::UnknownType);
601}
602
603/*!
604 Returns the metatype of the property.
605
606 \sa propertyType
607 */
608QMetaType QQmlProperty::propertyMetaType() const
609{
610 return d ? d->propertyType() : QMetaType {};
611}
612
613bool QQmlPropertyPrivate::isValueType() const
614{
615 return valueTypeData.isValid();
616}
617
618QMetaType QQmlPropertyPrivate::propertyType() const
619{
620 uint type = this->type();
621 if (isValueType()) {
622 return valueTypeData.propType();
623 } else if (type & QQmlProperty::Property) {
624 return core.propType();
625 } else {
626 return QMetaType();
627 }
628}
629
630QQmlProperty::Type QQmlPropertyPrivate::type() const
631{
632 if (core.isFunction())
633 return QQmlProperty::SignalProperty;
634 else if (core.isValid())
635 return QQmlProperty::Property;
636 else
637 return QQmlProperty::Invalid;
638}
639
640/*!
641 Returns the type of the property.
642*/
643QQmlProperty::Type QQmlProperty::type() const
644{
645 return d ? d->type() : Invalid;
646}
647
648/*!
649 Returns true if this QQmlProperty represents a regular Qt property.
650*/
651bool QQmlProperty::isProperty() const
652{
653 return type() & Property;
654}
655
656/*!
657 Returns true if this QQmlProperty represents a QML signal property.
658*/
659bool QQmlProperty::isSignalProperty() const
660{
661 return type() & SignalProperty;
662}
663
664/*!
665 Returns the QQmlProperty's QObject.
666*/
667QObject *QQmlProperty::object() const
668{
669 return d ? d->object : nullptr;
670}
671
672/*!
673 Assign \a other to this QQmlProperty.
674*/
675QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
676{
677 QQmlProperty copied(other);
678 qSwap(value1&: d, value2&: copied.d);
679 return *this;
680}
681
682/*!
683 Returns true if the property is writable, otherwise false.
684*/
685bool QQmlProperty::isWritable() const
686{
687 if (!d)
688 return false;
689 if (!d->object)
690 return false;
691 if (d->core.isQList()) //list
692 return true;
693 else if (d->core.isFunction()) //signal handler
694 return false;
695 else if (d->core.isValid()) //normal property
696 return d->core.isWritable();
697 else
698 return false;
699}
700
701/*!
702 \internal
703 Returns true if the property is bindable, otherwise false.
704 */
705bool QQmlProperty::isBindable() const
706{
707 if (!d)
708 return false;
709 if (!d->object)
710 return false;
711 if (d->core.isValid())
712 return d->core.isBindable();
713 return false;
714}
715
716/*!
717 Returns true if the property is designable, otherwise false.
718*/
719bool QQmlProperty::isDesignable() const
720{
721 if (!d)
722 return false;
723 if (type() & Property && d->core.isValid() && d->object)
724 return d->object->metaObject()->property(index: d->core.coreIndex()).isDesignable();
725 else
726 return false;
727}
728
729/*!
730 Returns true if the property is resettable, otherwise false.
731*/
732bool QQmlProperty::isResettable() const
733{
734 if (!d)
735 return false;
736 if (type() & Property && d->core.isValid() && d->object)
737 return d->core.isResettable();
738 else
739 return false;
740}
741
742/*!
743 Returns true if the QQmlProperty refers to a valid property, otherwise
744 false.
745*/
746bool QQmlProperty::isValid() const
747{
748 if (!d)
749 return false;
750 return type() != Invalid;
751}
752
753/*!
754 Return the name of this QML property.
755*/
756QString QQmlProperty::name() const
757{
758 if (!d)
759 return QString();
760 if (d->nameCache.isEmpty()) {
761 if (!d->object) {
762 } else if (d->isValueType()) {
763 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(type: d->core.propType());
764 Q_ASSERT(valueTypeMetaObject);
765
766 const char *vtName = valueTypeMetaObject->property(index: d->valueTypeData.coreIndex()).name();
767 d->nameCache = d->core.name(d->object) + QLatin1Char('.') + QString::fromUtf8(utf8: vtName);
768 } else if (type() & SignalProperty) {
769 // ### Qt7: Return the original signal name here. Do not prepend "on"
770 QString name = QStringLiteral("on") + d->core.name(d->object);
771 for (int i = 2, end = name.size(); i != end; ++i) {
772 const QChar c = name.at(i);
773 if (c != u'_') {
774 name[i] = c.toUpper();
775 break;
776 }
777 }
778 d->nameCache = name;
779 } else {
780 d->nameCache = d->core.name(d->object);
781 }
782 }
783
784 return d->nameCache;
785}
786
787/*!
788 Returns the \l{QMetaProperty} {Qt property} associated with
789 this QML property.
790 */
791QMetaProperty QQmlProperty::property() const
792{
793 if (!d)
794 return QMetaProperty();
795 if (type() & Property && d->core.isValid() && d->object)
796 return d->object->metaObject()->property(index: d->core.coreIndex());
797 else
798 return QMetaProperty();
799}
800
801/*!
802 Return the QMetaMethod for this property if it is a SignalProperty,
803 otherwise returns an invalid QMetaMethod.
804*/
805QMetaMethod QQmlProperty::method() const
806{
807 if (!d)
808 return QMetaMethod();
809 if (type() & SignalProperty && d->object)
810 return d->object->metaObject()->method(index: d->core.coreIndex());
811 else
812 return QMetaMethod();
813}
814
815/*!
816 Returns the binding associated with this property, or 0 if no binding
817 exists.
818*/
819QQmlAbstractBinding *
820QQmlPropertyPrivate::binding(const QQmlProperty &that)
821{
822 if (!that.d || !that.isProperty() || !that.d->object)
823 return nullptr;
824
825 QQmlPropertyIndex thatIndex(that.d->core.coreIndex(), that.d->valueTypeData.coreIndex());
826 return binding(that.d->object, index: thatIndex);
827}
828
829/*!
830 Set the binding associated with this property to \a newBinding. Returns
831 the existing binding (if any), otherwise 0.
832
833 \a newBinding will be enabled, and the returned binding (if any) will be
834 disabled.
835
836 Ownership of \a newBinding transfers to QML. Ownership of the return value
837 is assumed by the caller.
838*/
839void
840QQmlPropertyPrivate::setBinding(const QQmlProperty &that, QQmlAbstractBinding *newBinding)
841{
842 if (!newBinding) {
843 removeBinding(that);
844 return;
845 }
846
847 if (!that.d || !that.isProperty() || !that.d->object) {
848 if (!newBinding->ref)
849 delete newBinding;
850 return;
851 }
852 setBinding(binding: newBinding);
853}
854
855static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPropertyPrivate::BindingFlags flags = QQmlPropertyPrivate::None)
856{
857 int coreIndex = index.coreIndex();
858 int valueTypeIndex = index.valueTypeIndex();
859
860 QQmlData *data = QQmlData::get(object, create: false);
861
862 if (!data || !data->hasBindingBit(coreIndex))
863 return;
864
865 QQmlAbstractBinding::Ptr oldBinding;
866 oldBinding = data->bindings;
867
868 while (oldBinding && (oldBinding->targetPropertyIndex().coreIndex() != coreIndex ||
869 oldBinding->targetPropertyIndex().hasValueTypeIndex()))
870 oldBinding = oldBinding->nextBinding();
871
872 if (!oldBinding)
873 return;
874
875 if (valueTypeIndex != -1 && oldBinding->kind() == QQmlAbstractBinding::ValueTypeProxy)
876 oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(targetPropertyIndex: index);
877
878 if (!oldBinding)
879 return;
880
881 if (!(flags & QQmlPropertyPrivate::DontEnable))
882 oldBinding->setEnabled(e: false, f: {});
883 oldBinding->removeFromObject();
884}
885
886void QQmlPropertyPrivate::removeBinding(QQmlAbstractBinding *b)
887{
888 removeBinding(o: b->targetObject(), index: b->targetPropertyIndex());
889}
890
891void QQmlPropertyPrivate::removeBinding(QObject *o, QQmlPropertyIndex index)
892{
893 Q_ASSERT(o);
894
895 auto [target, targetIndex] = findAliasTarget(baseObject: o, baseIndex: index);
896 removeOldBinding(object: target, index: targetIndex);
897}
898
899void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that)
900{
901 if (!that.d || !that.isProperty() || !that.d->object)
902 return;
903
904 removeBinding(o: that.d->object, index: that.d->encodedIndex());
905}
906
907QQmlAbstractBinding *
908QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index)
909{
910 auto aliasTarget = findAliasTarget(baseObject: object, baseIndex: index);
911 object = aliasTarget.targetObject;
912 index = aliasTarget.targetIndex;
913
914 QQmlData *data = QQmlData::get(object);
915 if (!data)
916 return nullptr;
917
918 const int coreIndex = index.coreIndex();
919 const int valueTypeIndex = index.valueTypeIndex();
920
921 if (coreIndex < 0 || !data->hasBindingBit(coreIndex))
922 return nullptr;
923
924 QQmlAbstractBinding *binding = data->bindings;
925 while (binding && (binding->targetPropertyIndex().coreIndex() != coreIndex ||
926 binding->targetPropertyIndex().hasValueTypeIndex()))
927 binding = binding->nextBinding();
928
929 if (binding && valueTypeIndex != -1) {
930 if (binding->kind() == QQmlAbstractBinding::ValueTypeProxy)
931 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(targetPropertyIndex: index);
932 }
933
934 return binding;
935}
936
937void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bindingIndex,
938 QObject **targetObject,
939 QQmlPropertyIndex *targetBindingIndex)
940{
941 QQmlData *data = QQmlData::get(object, create: false);
942 if (data) {
943 int coreIndex = bindingIndex.coreIndex();
944 int valueTypeIndex = bindingIndex.valueTypeIndex();
945
946 const QQmlPropertyData *propertyData =
947 data->propertyCache?data->propertyCache->property(index: coreIndex):nullptr;
948 if (propertyData && propertyData->isAlias()) {
949 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(o: object, coreIndex);
950
951 QObject *aObject = nullptr; int aCoreIndex = -1; int aValueTypeIndex = -1;
952 if (vme->aliasTarget(index: coreIndex, target: &aObject, coreIndex: &aCoreIndex, valueTypeIndex: &aValueTypeIndex)) {
953 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
954 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
955
956 QQmlPropertyIndex aBindingIndex(aCoreIndex);
957 if (aValueTypeIndex != -1) {
958 aBindingIndex = QQmlPropertyIndex(aCoreIndex, aValueTypeIndex);
959 } else if (valueTypeIndex != -1) {
960 aBindingIndex = QQmlPropertyIndex(aCoreIndex, valueTypeIndex);
961 }
962
963 findAliasTarget(object: aObject, bindingIndex: aBindingIndex, targetObject, targetBindingIndex);
964 return;
965 }
966 }
967 }
968
969 *targetObject = object;
970 *targetBindingIndex = bindingIndex;
971}
972
973QQmlPropertyPrivate::ResolvedAlias QQmlPropertyPrivate::findAliasTarget(QObject *baseObject, QQmlPropertyIndex baseIndex)
974{
975 ResolvedAlias resolved;
976 findAliasTarget(object: baseObject, bindingIndex: baseIndex, targetObject: &resolved.targetObject, targetBindingIndex: &resolved.targetIndex);
977 return resolved;
978}
979
980
981
982void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags)
983{
984 Q_ASSERT(binding);
985 Q_ASSERT(binding->targetObject());
986
987 QObject *object = binding->targetObject();
988 const QQmlPropertyIndex index = binding->targetPropertyIndex();
989
990#ifndef QT_NO_DEBUG
991 int coreIndex = index.coreIndex();
992 QQmlData *data = QQmlData::get(object, create: true);
993 if (data->propertyCache) {
994 const QQmlPropertyData *propertyData = data->propertyCache->property(index: coreIndex);
995 Q_ASSERT(propertyData);
996 }
997#endif
998
999 removeOldBinding(object, index, flags);
1000
1001 binding->addToObject();
1002 if (!(flags & DontEnable))
1003 binding->setEnabled(e: true, f: writeFlags);
1004
1005}
1006
1007/*!
1008 Returns the expression associated with this signal property, or 0 if no
1009 signal expression exists.
1010*/
1011QQmlBoundSignalExpression *
1012QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
1013{
1014 if (!(that.type() & QQmlProperty::SignalProperty))
1015 return nullptr;
1016
1017 if (!that.d->object)
1018 return nullptr;
1019 QQmlData *data = QQmlData::get(object: that.d->object);
1020 if (!data)
1021 return nullptr;
1022
1023 QQmlBoundSignal *signalHandler = data->signalHandlers;
1024
1025 while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(p: that)->signalIndex())
1026 signalHandler = signalHandler->m_nextSignal;
1027
1028 if (signalHandler)
1029 return signalHandler->expression();
1030
1031 return nullptr;
1032}
1033
1034/*!
1035 Set the signal expression associated with this signal property to \a expr.
1036 A reference to \a expr will be added by QML.
1037*/
1038void QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *expr)
1039{
1040 if (expr)
1041 expr->addref();
1042 QQmlPropertyPrivate::takeSignalExpression(that, expr);
1043}
1044
1045/*!
1046 Set the signal expression associated with this signal property to \a expr.
1047 Ownership of \a expr transfers to QML.
1048*/
1049void QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
1050 QQmlBoundSignalExpression *expr)
1051{
1052 if (!(that.type() & QQmlProperty::SignalProperty)) {
1053 if (expr)
1054 expr->release();
1055 return;
1056 }
1057
1058 if (!that.d->object)
1059 return;
1060 QQmlData *data = QQmlData::get(object: that.d->object, create: nullptr != expr);
1061 if (!data)
1062 return;
1063
1064 QQmlBoundSignal *signalHandler = data->signalHandlers;
1065
1066 while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(p: that)->signalIndex())
1067 signalHandler = signalHandler->m_nextSignal;
1068
1069 if (signalHandler) {
1070 signalHandler->takeExpression(expr);
1071 return;
1072 }
1073
1074 if (expr) {
1075 int signalIndex = QQmlPropertyPrivate::get(p: that)->signalIndex();
1076 QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, signalIndex, that.d->object,
1077 expr->engine());
1078 signal->takeExpression(expr);
1079 }
1080}
1081
1082/*!
1083 Returns the property value.
1084*/
1085QVariant QQmlProperty::read() const
1086{
1087 if (!d)
1088 return QVariant();
1089 if (!d->object)
1090 return QVariant();
1091
1092 if (type() & SignalProperty) {
1093
1094 return QVariant();
1095
1096 } else if (type() & Property) {
1097
1098 return d->readValueProperty();
1099
1100 }
1101 return QVariant();
1102}
1103
1104/*!
1105Return the \a name property value of \a object. This method is equivalent to:
1106\code
1107 QQmlProperty p(object, name);
1108 p.read();
1109\endcode
1110*/
1111QVariant QQmlProperty::read(const QObject *object, const QString &name)
1112{
1113 QQmlProperty p(const_cast<QObject *>(object), name);
1114 return p.read();
1115}
1116
1117/*!
1118 Return the \a name property value of \a object using the
1119 \l{QQmlContext} {context} \a ctxt. This method is
1120 equivalent to:
1121
1122 \code
1123 QQmlProperty p(object, name, context);
1124 p.read();
1125 \endcode
1126*/
1127QVariant QQmlProperty::read(const QObject *object, const QString &name, QQmlContext *ctxt)
1128{
1129 QQmlProperty p(const_cast<QObject *>(object), name, ctxt);
1130 return p.read();
1131}
1132
1133/*!
1134
1135 Return the \a name property value of \a object using the environment
1136 for instantiating QML components that is provided by \a engine. .
1137 This method is equivalent to:
1138
1139 \code
1140 QQmlProperty p(object, name, engine);
1141 p.read();
1142 \endcode
1143*/
1144QVariant QQmlProperty::read(const QObject *object, const QString &name, QQmlEngine *engine)
1145{
1146 QQmlProperty p(const_cast<QObject *>(object), name, engine);
1147 return p.read();
1148}
1149
1150QVariant QQmlPropertyPrivate::readValueProperty()
1151{
1152 auto doRead = [&](QQmlGadgetPtrWrapper *wrapper) {
1153 wrapper->read(obj: object, idx: core.coreIndex());
1154 return wrapper->readOnGadget(property: wrapper->property(index: valueTypeData.coreIndex()));
1155 };
1156
1157 if (isValueType()) {
1158 if (QQmlGadgetPtrWrapper *wrapper = QQmlGadgetPtrWrapper::instance(engine, type: core.propType()))
1159 return doRead(wrapper);
1160 if (QQmlValueType *valueType = QQmlMetaType::valueType(metaType: core.propType())) {
1161 QQmlGadgetPtrWrapper wrapper(valueType, nullptr);
1162 return doRead(&wrapper);
1163 }
1164 return QVariant();
1165 } else if (core.isQList()) {
1166
1167 QQmlListProperty<QObject> prop;
1168 core.readProperty(target: object, property: &prop);
1169 return QVariant::fromValue(value: QQmlListReferencePrivate::init(prop, core.propType()));
1170
1171 } else if (core.isQObject()) {
1172
1173 QObject *rv = nullptr;
1174 core.readProperty(target: object, property: &rv);
1175 return QVariant::fromValue(value: rv);
1176
1177 } else {
1178
1179 if (!core.propType().isValid()) // Unregistered type
1180 return object->metaObject()->property(index: core.coreIndex()).read(obj: object);
1181
1182 QVariant value;
1183 int status = -1;
1184 void *args[] = { nullptr, &value, &status };
1185 if (core.propType() == QMetaType::fromType<QVariant>()) {
1186 args[0] = &value;
1187 } else {
1188 value = QVariant(core.propType(), (void*)nullptr);
1189 args[0] = value.data();
1190 }
1191 core.readPropertyWithArgs(target: object, args);
1192 if (core.propType() != QMetaType::fromType<QVariant>() && args[0] != value.data())
1193 return QVariant(QMetaType(core.propType()), args[0]);
1194
1195 return value;
1196 }
1197}
1198
1199// helper function to allow assignment / binding to QList<QUrl> properties.
1200QList<QUrl> QQmlPropertyPrivate::urlSequence(const QVariant &value)
1201{
1202 if (value.metaType() == QMetaType::fromType<QList<QUrl>>())
1203 return value.value<QList<QUrl> >();
1204
1205 QList<QUrl> urls;
1206 if (value.metaType() == QMetaType::fromType<QUrl>()) {
1207 urls.append(t: value.toUrl());
1208 } else if (value.metaType() == QMetaType::fromType<QString>()) {
1209 urls.append(t: QUrl(value.toString()));
1210 } else if (value.metaType() == QMetaType::fromType<QByteArray>()) {
1211 urls.append(t: QUrl(QString::fromUtf8(ba: value.toByteArray())));
1212 } else if (value.metaType() == QMetaType::fromType<QStringList>()) {
1213 QStringList urlStrings = value.value<QStringList>();
1214 const int urlStringsSize = urlStrings.size();
1215 urls.reserve(size: urlStringsSize);
1216 for (int i = 0; i < urlStringsSize; ++i)
1217 urls.append(t: QUrl(urlStrings.at(i)));
1218 } // note: QList<QByteArray> is not currently supported.
1219 return urls;
1220}
1221
1222// ### Qt7: Get rid of this
1223QList<QUrl> QQmlPropertyPrivate::urlSequence(
1224 const QVariant &value, const QQmlRefPointer<QQmlContextData> &ctxt)
1225{
1226 QList<QUrl> urls = urlSequence(value);
1227
1228 for (auto urlIt = urls.begin(); urlIt != urls.end(); ++urlIt)
1229 *urlIt = ctxt->resolvedUrl(*urlIt);
1230
1231 return urls;
1232}
1233
1234//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1235bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1236{
1237 if (!object || !prop.isWritable())
1238 return false;
1239
1240 QVariant v = value;
1241 if (prop.isEnumType() && v.metaType() != prop.metaType()) {
1242 QMetaEnum menum = prop.enumerator();
1243 if (v.userType() == QMetaType::QString) {
1244 bool ok;
1245 if (prop.isFlagType())
1246 v = QVariant(menum.keysToValue(keys: value.toByteArray(), ok: &ok));
1247 else
1248 v = QVariant(menum.keyToValue(key: value.toByteArray(), ok: &ok));
1249 if (!ok)
1250 return false;
1251 }
1252 if (!v.convert(type: prop.metaType())) // ### TODO: underlyingType might be faster?
1253 return false;
1254 }
1255
1256 // the status variable is changed by qt_metacall to indicate what it did
1257 // this feature is currently only used by QtDBus and should not be depended
1258 // upon. Don't change it without looking into QDBusAbstractInterface first
1259 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1260 // changed: result stored directly in value, return the value of status
1261 int status = -1;
1262 void *argv[] = { v.data(), &v, &status, &flags };
1263 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1264 return status;
1265}
1266
1267bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, QQmlPropertyData::WriteFlags flags)
1268{
1269 return writeValueProperty(object, core, valueTypeData, value, effectiveContext(), flags);
1270}
1271
1272static void removeValuePropertyBinding(
1273 QObject *object, const QQmlPropertyData &core,
1274 const QQmlPropertyData &valueTypeData, QQmlPropertyData::WriteFlags flags)
1275{
1276 // Remove any existing bindings on this property
1277 if (!(flags & QQmlPropertyData::DontRemoveBinding) && object) {
1278 QQmlPropertyPrivate::removeBinding(
1279 o: object, index: QQmlPropertyPrivate::encodedIndex(core, valueTypeData));
1280 }
1281}
1282
1283template<typename Op>
1284bool changePropertyAndWriteBack(
1285 QObject *object, int coreIndex, QQmlGadgetPtrWrapper *wrapper,
1286 QQmlPropertyData::WriteFlags flags, int internalIndex, Op op)
1287{
1288 wrapper->read(obj: object, idx: coreIndex);
1289 const bool rv = op(wrapper);
1290 wrapper->write(obj: object, idx: coreIndex, flags, internalIndex);
1291 return rv;
1292}
1293
1294template<typename Op>
1295bool changeThroughGadgetPtrWrapper(
1296 QObject *object, const QQmlPropertyData &core,
1297 const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags,
1298 int internalIndex, Op op)
1299{
1300 if (QQmlGadgetPtrWrapper *wrapper = context
1301 ? QQmlGadgetPtrWrapper::instance(engine: context->engine(), type: core.propType())
1302 : nullptr) {
1303 return changePropertyAndWriteBack(
1304 object, core.coreIndex(), wrapper, flags, internalIndex, op);
1305 }
1306
1307 if (QQmlValueType *valueType = QQmlMetaType::valueType(metaType: core.propType())) {
1308 QQmlGadgetPtrWrapper wrapper(valueType, nullptr);
1309 return changePropertyAndWriteBack(
1310 object, core.coreIndex(), &wrapper, flags, internalIndex, op);
1311 }
1312
1313 return false;
1314}
1315
1316bool QQmlPropertyPrivate::writeValueProperty(
1317 QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
1318 const QVariant &value, const QQmlRefPointer<QQmlContextData> &context,
1319 QQmlPropertyData::WriteFlags flags)
1320{
1321 removeValuePropertyBinding(object, core, valueTypeData, flags);
1322
1323 if (!valueTypeData.isValid())
1324 return write(object, core, value, context, flags);
1325
1326 return changeThroughGadgetPtrWrapper(
1327 object, core, context, flags: flags | QQmlPropertyData::HasInternalIndex,
1328 internalIndex: valueTypeData.coreIndex(), op: [&](QQmlGadgetPtrWrapper *wrapper) {
1329 return write(wrapper, valueTypeData, value, context, flags);
1330 });
1331}
1332
1333bool QQmlPropertyPrivate::resetValueProperty(
1334 QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
1335 const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
1336{
1337 removeValuePropertyBinding(object, core, valueTypeData, flags);
1338
1339 if (!valueTypeData.isValid())
1340 return reset(object, core, flags);
1341
1342 return changeThroughGadgetPtrWrapper(
1343 object, core, context, flags: flags | QQmlPropertyData::HasInternalIndex,
1344 internalIndex: valueTypeData.coreIndex(), op: [&](QQmlGadgetPtrWrapper *wrapper) {
1345 return reset(wrapper, valueTypeData, flags);
1346 });
1347}
1348
1349// We need to prevent new-style bindings from being removed.
1350struct BindingFixer
1351{
1352 Q_DISABLE_COPY_MOVE(BindingFixer);
1353
1354 BindingFixer(QObject *object, const QQmlPropertyData &property,
1355 QQmlPropertyData::WriteFlags flags)
1356 {
1357 if (!property.isBindable() || !(flags & QQmlPropertyData::DontRemoveBinding))
1358 return;
1359
1360 QUntypedBindable bindable;
1361 void *argv[] = {&bindable};
1362 QMetaObject::metacall(object, QMetaObject::BindableProperty, property.coreIndex(), argv);
1363 untypedBinding = bindable.binding();
1364 if (auto priv = QPropertyBindingPrivate::get(binding: untypedBinding))
1365 priv->setSticky(true);
1366 }
1367
1368 ~BindingFixer()
1369 {
1370 if (untypedBinding.isNull())
1371 return;
1372 auto priv = QPropertyBindingPrivate::get(binding: untypedBinding);
1373 priv->setSticky(false);
1374 }
1375
1376private:
1377 QUntypedPropertyBinding untypedBinding;
1378};
1379
1380struct ConvertAndAssignResult {
1381 bool couldConvert = false;
1382 bool couldWrite = false;
1383
1384 operator bool() const { return couldConvert; }
1385};
1386
1387static ConvertAndAssignResult tryConvertAndAssign(
1388 QObject *object, const QQmlPropertyData &property, const QVariant &value,
1389 QQmlPropertyData::WriteFlags flags, QMetaType propertyMetaType, QMetaType variantMetaType,
1390 bool isUrl) {
1391
1392 if (isUrl
1393 || variantMetaType == QMetaType::fromType<QString>()
1394 || propertyMetaType == QMetaType::fromType<QList<QUrl>>()
1395 || property.isQList()) {
1396 return {.couldConvert: false, .couldWrite: false};
1397 }
1398
1399 if (variantMetaType == QMetaType::fromType<QJSValue>()) {
1400 // Handle Qt.binding bindings here to avoid mistaken conversion below
1401 const QJSValue &jsValue = get<QJSValue>(v: value);
1402 const QV4::FunctionObject *f
1403 = QJSValuePrivate::asManagedType<QV4::FunctionObject>(jsval: &jsValue);
1404 if (f && f->isBinding()) {
1405 QV4::QObjectWrapper::setProperty(
1406 engine: f->engine(), object, property: &property, value: f->asReturnedValue());
1407 return {.couldConvert: true, .couldWrite: true};
1408 }
1409 }
1410
1411 // common cases:
1412 switch (propertyMetaType.id()) {
1413 case QMetaType::Bool:
1414 if (value.canConvert(targetType: propertyMetaType)) {
1415 bool b = value.toBool();
1416 return {.couldConvert: true, .couldWrite: property.writeProperty(target: object, value: &b, flags)};
1417 }
1418 return {.couldConvert: false, .couldWrite: false};
1419 case QMetaType::Int: {
1420 bool ok = false;
1421 int i = value.toInt(ok: &ok);
1422 return {.couldConvert: ok, .couldWrite: ok && property.writeProperty(target: object, value: &i, flags)};
1423 }
1424 case QMetaType::UInt: {
1425 bool ok = false;
1426 uint u = value.toUInt(ok: &ok);
1427 return {.couldConvert: ok, .couldWrite: ok && property.writeProperty(target: object, value: &u, flags)};
1428 }
1429 case QMetaType::Double: {
1430 bool ok = false;
1431 double d = value.toDouble(ok: &ok);
1432 return {.couldConvert: ok, .couldWrite: ok && property.writeProperty(target: object, value: &d, flags)};
1433 }
1434 case QMetaType::Float: {
1435 bool ok = false;
1436 float f = value.toFloat(ok: &ok);
1437 return {.couldConvert: ok, .couldWrite: ok && property.writeProperty(target: object, value: &f, flags)};
1438 }
1439 case QMetaType::QString:
1440 if (value.canConvert(targetType: propertyMetaType)) {
1441 QString s = value.toString();
1442 return {.couldConvert: true, .couldWrite: property.writeProperty(target: object, value: &s, flags)};
1443 }
1444 return {.couldConvert: false, .couldWrite: false};
1445 case QMetaType::QVariantMap:
1446 if (value.canConvert(targetType: propertyMetaType)) {
1447 QVariantMap m = value.toMap();
1448 return {.couldConvert: true, .couldWrite: property.writeProperty(target: object, value: &m, flags)};
1449 }
1450 return {.couldConvert: false, .couldWrite: false};
1451 default: {
1452 break;
1453 }
1454 }
1455
1456 QVariant converted = QQmlValueTypeProvider::createValueType(value, propertyMetaType);
1457 if (!converted.isValid()) {
1458 converted = QVariant(propertyMetaType);
1459 if (!QMetaType::convert(fromType: value.metaType(), from: value.constData(),
1460 toType: propertyMetaType, to: converted.data())) {
1461 return {.couldConvert: false, .couldWrite: false};
1462 }
1463 }
1464 return {.couldConvert: true, .couldWrite: property.writeProperty(target: object, value: converted.data(), flags)};
1465};
1466
1467template<typename Op>
1468bool iterateQObjectContainer(QMetaType metaType, const void *data, Op op)
1469{
1470 QSequentialIterable iterable;
1471 if (!QMetaType::convert(fromType: metaType, from: data, toType: QMetaType::fromType<QSequentialIterable>(), to: &iterable))
1472 return false;
1473
1474 const QMetaSequence metaSequence = iterable.metaContainer();
1475
1476 if (!metaSequence.hasConstIterator()
1477 || !metaSequence.canGetValueAtConstIterator()
1478 || !iterable.valueMetaType().flags().testFlag(flag: QMetaType::PointerToQObject)) {
1479 return false;
1480 }
1481
1482 const void *container = iterable.constIterable();
1483 void *it = metaSequence.constBegin(container);
1484 const void *end = metaSequence.constEnd(container);
1485 QObject *o = nullptr;
1486 while (!metaSequence.compareConstIterator(i: it, j: end)) {
1487 metaSequence.valueAtConstIterator(iterator: it, result: &o);
1488 op(o);
1489 metaSequence.advanceConstIterator(iterator: it, step: 1);
1490 }
1491 metaSequence.destroyConstIterator(iterator: it);
1492 metaSequence.destroyConstIterator(iterator: end);
1493 return true;
1494}
1495
1496bool QQmlPropertyPrivate::write(
1497 QObject *object, const QQmlPropertyData &property, const QVariant &value,
1498 const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
1499{
1500 const QMetaType propertyMetaType = property.propType();
1501 const QMetaType variantMetaType = value.metaType();
1502
1503 const BindingFixer bindingFixer(object, property, flags);
1504
1505 if (property.isEnum()) {
1506 QMetaProperty prop = object->metaObject()->property(index: property.coreIndex());
1507 QVariant v = value;
1508 // Enum values come through the script engine as doubles
1509 if (variantMetaType == QMetaType::fromType<double>()) {
1510 double integral;
1511 double fractional = std::modf(x: value.toDouble(), iptr: &integral);
1512 if (qFuzzyIsNull(d: fractional))
1513 v.convert(type: QMetaType::fromType<qint32>());
1514 }
1515 return writeEnumProperty(prop, idx: property.coreIndex(), object, value: v, flags);
1516 }
1517
1518 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(c: context);
1519 const bool isUrl = propertyMetaType == QMetaType::fromType<QUrl>(); // handled separately
1520
1521 // The cases below are in approximate order of likelyhood:
1522 if (propertyMetaType == variantMetaType && !isUrl
1523 && propertyMetaType != QMetaType::fromType<QList<QUrl>>() && !property.isQList()) {
1524 return property.writeProperty(target: object, value: const_cast<void *>(value.constData()), flags);
1525 } else if (property.isQObject()) {
1526 QVariant val = value;
1527 QMetaType varType;
1528 if (variantMetaType == QMetaType::fromType<std::nullptr_t>()) {
1529 // This reflects the fact that you can assign a nullptr to a QObject pointer
1530 // Without the change to QObjectStar, rawMetaObjectForType would not give us a QQmlMetaObject
1531 varType = QMetaType::fromType<QObject*>();
1532 val = QVariant(varType, nullptr);
1533 } else {
1534 varType = variantMetaType;
1535 }
1536 QQmlMetaObject valMo = rawMetaObjectForType(metaType: varType);
1537 if (valMo.isNull() || !varType.flags().testFlag(flag: QMetaType::PointerToQObject))
1538 return false;
1539 QObject *o = *static_cast<QObject *const *>(val.constData());
1540 QQmlMetaObject propMo = rawMetaObjectForType(metaType: propertyMetaType);
1541
1542 if (o)
1543 valMo = o;
1544
1545 if (QQmlMetaObject::canConvert(from: valMo, to: propMo)) {
1546 return property.writeProperty(target: object, value: &o, flags);
1547 } else if (!o && QQmlMetaObject::canConvert(from: propMo, to: valMo)) {
1548 // In the case of a null QObject, we assign the null if there is
1549 // any change that the null variant type could be up or down cast to
1550 // the property type.
1551 return property.writeProperty(target: object, value: &o, flags);
1552 } else {
1553 return false;
1554 }
1555 } else if (ConvertAndAssignResult result = tryConvertAndAssign(
1556 object, property, value, flags, propertyMetaType, variantMetaType, isUrl)) {
1557 return result.couldWrite;
1558 } else if (propertyMetaType == QMetaType::fromType<QVariant>()) {
1559 return property.writeProperty(target: object, value: const_cast<QVariant *>(&value), flags);
1560 } else if (isUrl) {
1561 QUrl u;
1562 if (variantMetaType == QMetaType::fromType<QUrl>()) {
1563 u = value.toUrl();
1564 if (compatResolveUrlsOnAssigment() && context && u.isRelative() && !u.isEmpty())
1565 u = context->resolvedUrl(u);
1566 }
1567 else if (variantMetaType == QMetaType::fromType<QByteArray>())
1568 u = QUrl(QString::fromUtf8(ba: value.toByteArray()));
1569 else if (variantMetaType == QMetaType::fromType<QString>())
1570 u = QUrl(value.toString());
1571 else
1572 return false;
1573
1574 return property.writeProperty(target: object, value: &u, flags);
1575 } else if (propertyMetaType == QMetaType::fromType<QList<QUrl>>()) {
1576 QList<QUrl> urlSeq = compatResolveUrlsOnAssigment()
1577 ? urlSequence(value, ctxt: context)
1578 : urlSequence(value);
1579 return property.writeProperty(target: object, value: &urlSeq, flags);
1580 } else if (property.isQList()) {
1581 if (propertyMetaType.flags() & QMetaType::IsQmlList) {
1582 QMetaType listValueType = QQmlMetaType::listValueType(type: propertyMetaType);
1583 QQmlMetaObject valueMetaObject = QQmlMetaType::rawMetaObjectForType(metaType: listValueType);
1584 if (valueMetaObject.isNull())
1585 return false;
1586
1587 QQmlListProperty<QObject> prop;
1588 property.readProperty(target: object, property: &prop);
1589
1590 if (!prop.clear || !prop.append)
1591 return false;
1592
1593 const bool useNonsignalingListOps = prop.clear == &QQmlVMEMetaObject::list_clear
1594 && prop.append == &QQmlVMEMetaObject::list_append;
1595
1596 auto propClear =
1597 useNonsignalingListOps ? &QQmlVMEMetaObject::list_clear_nosignal : prop.clear;
1598 auto propAppend =
1599 useNonsignalingListOps ? &QQmlVMEMetaObject::list_append_nosignal : prop.append;
1600
1601 propClear(&prop);
1602
1603 const auto doAppend = [&](QObject *o) {
1604 if (o && !QQmlMetaObject::canConvert(from: o, to: valueMetaObject))
1605 o = nullptr;
1606 propAppend(&prop, o);
1607 };
1608
1609 if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
1610 QQmlListReference qdlr = value.value<QQmlListReference>();
1611 for (qsizetype ii = 0; ii < qdlr.count(); ++ii)
1612 doAppend(qdlr.at(ii));
1613 } else if (variantMetaType == QMetaType::fromType<QList<QObject *>>()) {
1614 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(v: value);
1615 for (qsizetype ii = 0; ii < list.size(); ++ii)
1616 doAppend(list.at(i: ii));
1617 } else if (variantMetaType == QMetaType::fromType<QList<QVariant>>()) {
1618 const QList<QVariant> &list
1619 = *static_cast<const QList<QVariant> *>(value.constData());
1620 for (const QVariant &entry : list)
1621 doAppend(QQmlMetaType::toQObject(entry));
1622 } else if (!iterateQObjectContainer(metaType: variantMetaType, data: value.data(), op: doAppend)) {
1623 doAppend(QQmlMetaType::toQObject(value));
1624 }
1625 if (useNonsignalingListOps) {
1626 Q_ASSERT(QQmlVMEMetaObject::get(object));
1627 QQmlVMEResolvedList(&prop).activateSignal();
1628 }
1629 } else if (variantMetaType == propertyMetaType) {
1630 QVariant v = value;
1631 property.writeProperty(target: object, value: v.data(), flags);
1632 } else {
1633 QVariant list(propertyMetaType);
1634 const QQmlType type = QQmlMetaType::qmlType(metaType: propertyMetaType);
1635 const QMetaSequence sequence = type.listMetaSequence();
1636 if (sequence.canAddValue())
1637 sequence.addValue(container: list.data(), value: value.data());
1638 property.writeProperty(target: object, value: list.data(), flags);
1639 }
1640 } else if (enginePriv && propertyMetaType == QMetaType::fromType<QJSValue>()) {
1641 // We can convert everything into a QJSValue if we have an engine.
1642 QJSValue jsValue = QJSValuePrivate::fromReturnedValue(
1643 d: enginePriv->v4engine()->metaTypeToJS(type: variantMetaType, data: value.constData()));
1644 return property.writeProperty(target: object, value: &jsValue, flags);
1645 } else {
1646 Q_ASSERT(variantMetaType != propertyMetaType);
1647
1648 bool ok = false;
1649 QVariant v;
1650 if (variantMetaType == QMetaType::fromType<QString>())
1651 v = QQmlStringConverters::variantFromString(value.toString(), preferredType: propertyMetaType, ok: &ok);
1652
1653 if (!ok) {
1654 v = value;
1655 if (v.convert(type: propertyMetaType)) {
1656 ok = true;
1657 }
1658 }
1659 if (!ok) {
1660 // the only other options are that they are assigning a single value
1661 // or a QVariantList to a sequence type property (eg, an int to a
1662 // QList<int> property) or that we encountered an interface type.
1663 // Note that we've already handled single-value assignment to QList<QUrl> properties.
1664 QSequentialIterable iterable;
1665 v = QVariant(propertyMetaType);
1666 if (QMetaType::view(
1667 fromType: propertyMetaType, from: v.data(),
1668 toType: QMetaType::fromType<QSequentialIterable>(),
1669 to: &iterable)) {
1670 const QMetaSequence propertyMetaSequence = iterable.metaContainer();
1671 if (propertyMetaSequence.canAddValueAtEnd()) {
1672 const QMetaType elementMetaType = iterable.valueMetaType();
1673 void *propertyContainer = iterable.mutableIterable();
1674
1675 if (variantMetaType == elementMetaType) {
1676 propertyMetaSequence.addValueAtEnd(container: propertyContainer, value: value.constData());
1677 ok = true;
1678 } else if (variantMetaType == QMetaType::fromType<QVariantList>()) {
1679 const QVariantList list = value.value<QVariantList>();
1680 for (const QVariant &valueElement : list) {
1681 if (valueElement.metaType() == elementMetaType) {
1682 propertyMetaSequence.addValueAtEnd(
1683 container: propertyContainer, value: valueElement.constData());
1684 } else {
1685 QVariant converted(elementMetaType);
1686 QMetaType::convert(
1687 fromType: valueElement.metaType(), from: valueElement.constData(),
1688 toType: elementMetaType, to: converted.data());
1689 propertyMetaSequence.addValueAtEnd(
1690 container: propertyContainer, value: converted.constData());
1691 }
1692 }
1693 ok = true;
1694 } else if (elementMetaType.flags().testFlag(flag: QMetaType::PointerToQObject)) {
1695 const QMetaObject *elementMetaObject = elementMetaType.metaObject();
1696 Q_ASSERT(elementMetaObject);
1697
1698 const auto doAppend = [&](QObject *o) {
1699 QObject *casted = elementMetaObject->cast(obj: o);
1700 propertyMetaSequence.addValueAtEnd(container: propertyContainer, value: &casted);
1701 };
1702
1703 if (variantMetaType.flags().testFlag(flag: QMetaType::PointerToQObject)) {
1704 doAppend(*static_cast<QObject *const *>(value.data()));
1705 ok = true;
1706 } else if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
1707 const QQmlListReference *reference
1708 = static_cast<const QQmlListReference *>(value.constData());
1709 Q_ASSERT(elementMetaObject);
1710 for (int i = 0, end = reference->size(); i < end; ++i)
1711 doAppend(reference->at(i));
1712 ok = true;
1713 } else if (!iterateQObjectContainer(
1714 metaType: variantMetaType, data: value.data(), op: doAppend)) {
1715 doAppend(QQmlMetaType::toQObject(value));
1716 }
1717 } else {
1718 QVariant converted = value;
1719 if (converted.convert(type: elementMetaType)) {
1720 propertyMetaSequence.addValueAtEnd(container: propertyContainer, value: converted.constData());
1721 ok = true;
1722 }
1723 }
1724 }
1725 }
1726 }
1727
1728 if (!ok && QQmlMetaType::isInterface(type: propertyMetaType)) {
1729 auto valueAsQObject = qvariant_cast<QObject *>(v: value);
1730
1731 if (void *iface = valueAsQObject
1732 ? valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(type: propertyMetaType))
1733 : nullptr;
1734 iface) {
1735 // this case can occur when object has an interface type
1736 // and the variant contains a type implementing the interface
1737 return property.writeProperty(target: object, value: &iface, flags);
1738 }
1739 }
1740
1741 if (ok) {
1742 return property.writeProperty(target: object, value: const_cast<void *>(v.constData()), flags);
1743 } else {
1744 return false;
1745 }
1746 }
1747
1748 return true;
1749}
1750
1751bool QQmlPropertyPrivate::reset(
1752 QObject *object, const QQmlPropertyData &property,
1753 QQmlPropertyData::WriteFlags flags)
1754{
1755 const BindingFixer bindingFixer(object, property, flags);
1756 property.resetProperty(target: object, flags);
1757 return true;
1758}
1759
1760QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QMetaType metaType)
1761{
1762 if (metaType.flags() & QMetaType::PointerToQObject) {
1763 if (const QMetaObject *metaObject = metaType.metaObject())
1764 return metaObject;
1765 }
1766 return QQmlMetaType::rawMetaObjectForType(metaType);
1767}
1768
1769/*!
1770 Sets the property value to \a value. Returns \c true on success, or
1771 \c false if the property can't be set because the \a value is the
1772 wrong type, for example.
1773 */
1774bool QQmlProperty::write(const QVariant &value) const
1775{
1776 return QQmlPropertyPrivate::write(that: *this, value, {});
1777}
1778
1779/*!
1780 Writes \a value to the \a name property of \a object. This method
1781 is equivalent to:
1782
1783 \code
1784 QQmlProperty p(object, name);
1785 p.write(value);
1786 \endcode
1787
1788 Returns \c true on success, \c false otherwise.
1789*/
1790bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1791{
1792 QQmlProperty p(object, name);
1793 return p.write(value);
1794}
1795
1796/*!
1797 Writes \a value to the \a name property of \a object using the
1798 \l{QQmlContext} {context} \a ctxt. This method is
1799 equivalent to:
1800
1801 \code
1802 QQmlProperty p(object, name, ctxt);
1803 p.write(value);
1804 \endcode
1805
1806 Returns \c true on success, \c false otherwise.
1807*/
1808bool QQmlProperty::write(QObject *object,
1809 const QString &name,
1810 const QVariant &value,
1811 QQmlContext *ctxt)
1812{
1813 QQmlProperty p(object, name, ctxt);
1814 return p.write(value);
1815}
1816
1817/*!
1818
1819 Writes \a value to the \a name property of \a object using the
1820 environment for instantiating QML components that is provided by
1821 \a engine. This method is equivalent to:
1822
1823 \code
1824 QQmlProperty p(object, name, engine);
1825 p.write(value);
1826 \endcode
1827
1828 Returns \c true on success, \c false otherwise.
1829*/
1830bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1831 QQmlEngine *engine)
1832{
1833 QQmlProperty p(object, name, engine);
1834 return p.write(value);
1835}
1836
1837/*!
1838 Resets the property and returns true if the property is
1839 resettable. If the property is not resettable, nothing happens
1840 and false is returned.
1841*/
1842bool QQmlProperty::reset() const
1843{
1844 if (isResettable()) {
1845 void *args[] = { nullptr };
1846 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex(), args);
1847 return true;
1848 } else {
1849 return false;
1850 }
1851}
1852
1853bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1854 const QVariant &value, QQmlPropertyData::WriteFlags flags)
1855{
1856 if (!that.d)
1857 return false;
1858 if (that.d->object && that.type() & QQmlProperty::Property &&
1859 that.d->core.isValid() && that.isWritable())
1860 return that.d->writeValueProperty(value, flags);
1861 else
1862 return false;
1863}
1864
1865/*!
1866 Returns true if the property has a change notifier signal, otherwise false.
1867*/
1868bool QQmlProperty::hasNotifySignal() const
1869{
1870 if (type() & Property && d->object) {
1871 return d->object->metaObject()->property(index: d->core.coreIndex()).hasNotifySignal();
1872 }
1873 return false;
1874}
1875
1876/*!
1877 Returns true if the property needs a change notifier signal for bindings
1878 to remain upto date, false otherwise.
1879
1880 Some properties, such as attached properties or those whose value never
1881 changes, do not require a change notifier.
1882*/
1883bool QQmlProperty::needsNotifySignal() const
1884{
1885 return type() & Property && !property().isConstant();
1886}
1887
1888/*!
1889 Connects the property's change notifier signal to the
1890 specified \a method of the \a dest object and returns
1891 true. Returns false if this metaproperty does not
1892 represent a regular Qt property or if it has no
1893 change notifier signal, or if the \a dest object does
1894 not have the specified \a method.
1895*/
1896bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1897{
1898 if (!(type() & Property) || !d->object)
1899 return false;
1900
1901 QMetaProperty prop = d->object->metaObject()->property(index: d->core.coreIndex());
1902 if (prop.hasNotifySignal()) {
1903 return QQmlPropertyPrivate::connect(sender: d->object, signal_index: prop.notifySignalIndex(), receiver: dest, method_index: method, type: Qt::DirectConnection);
1904 } else {
1905 return false;
1906 }
1907}
1908
1909/*!
1910 Connects the property's change notifier signal to the
1911 specified \a slot of the \a dest object and returns
1912 true. Returns false if this metaproperty does not
1913 represent a regular Qt property or if it has no
1914 change notifier signal, or if the \a dest object does
1915 not have the specified \a slot.
1916
1917 \note \a slot should be passed using the SLOT() macro so it is
1918 correctly identified.
1919*/
1920bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1921{
1922 if (!(type() & Property) || !d->object)
1923 return false;
1924
1925 QMetaProperty prop = d->object->metaObject()->property(index: d->core.coreIndex());
1926 if (prop.hasNotifySignal()) {
1927 QByteArray signal('2' + prop.notifySignal().methodSignature());
1928 return QObject::connect(sender: d->object, signal: signal.constData(), receiver: dest, member: slot);
1929 } else {
1930 return false;
1931 }
1932}
1933
1934/*!
1935 Return the Qt metaobject index of the property.
1936*/
1937int QQmlProperty::index() const
1938{
1939 return d ? d->core.coreIndex() : -1;
1940}
1941
1942QQmlPropertyIndex QQmlPropertyPrivate::propertyIndex(const QQmlProperty &that)
1943{
1944 return that.d ? that.d->encodedIndex() : QQmlPropertyIndex();
1945}
1946
1947QQmlProperty
1948QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1949 const QQmlPropertyData *valueTypeData,
1950 const QQmlRefPointer<QQmlContextData> &ctxt)
1951{
1952 QQmlProperty prop;
1953
1954 prop.d = new QQmlPropertyPrivate;
1955 prop.d->object = object;
1956 prop.d->context = ctxt;
1957 prop.d->engine = ctxt ? ctxt->engine() : nullptr;
1958
1959 prop.d->core = data;
1960 if (valueTypeData)
1961 prop.d->valueTypeData = *valueTypeData;
1962
1963 return prop;
1964}
1965
1966/*!
1967 Return the signal corresponding to \a name
1968*/
1969QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1970{
1971 Q_ASSERT(mo);
1972 int methods = mo->methodCount();
1973 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1974 QMetaMethod method = mo->method(index: ii);
1975
1976 if (method.name() == name && (method.methodType() & QMetaMethod::Signal))
1977 return method;
1978 }
1979
1980 // If no signal is found, but the signal is of the form "onBlahChanged",
1981 // return the notify signal for the property "Blah"
1982 if (name.endsWith(bv: "Changed")) {
1983 QByteArray propName = name.mid(index: 0, len: name.size() - 7);
1984 int propIdx = mo->indexOfProperty(name: propName.constData());
1985 if (propIdx >= 0) {
1986 QMetaProperty prop = mo->property(index: propIdx);
1987 if (prop.hasNotifySignal())
1988 return prop.notifySignal();
1989 }
1990 }
1991
1992 return QMetaMethod();
1993}
1994
1995/*!
1996 Return the property corresponding to \a name
1997*/
1998QMetaProperty QQmlPropertyPrivate::findPropertyByName(const QMetaObject *mo, const QByteArray &name)
1999{
2000 Q_ASSERT(mo);
2001 const int i = mo->indexOfProperty(name);
2002 return i < 0 ? QMetaProperty() : mo->property(index: i);
2003}
2004
2005/*! \internal
2006 If \a indexInSignalRange is true, \a index is treated as a signal index
2007 (see QObjectPrivate::signalIndex()), otherwise it is treated as a
2008 method index (QMetaMethod::methodIndex()).
2009*/
2010static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
2011{
2012 QQmlData *data = QQmlData::get(object);
2013 if (data && data->propertyCache) {
2014 const QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
2015 : data->propertyCache->method(index);
2016
2017 if (property && property->isVMESignal()) {
2018 QQmlVMEMetaObject *vme;
2019 if (indexInSignalRange)
2020 vme = QQmlVMEMetaObject::getForSignal(o: const_cast<QObject *>(object), coreIndex: index);
2021 else
2022 vme = QQmlVMEMetaObject::getForMethod(o: const_cast<QObject *>(object), coreIndex: index);
2023 vme->connectAliasSignal(index, indexInSignalRange);
2024 }
2025 }
2026}
2027
2028/*!
2029Connect \a sender \a signal_index to \a receiver \a method_index with the specified
2030\a type and \a types. This behaves identically to QMetaObject::connect() except that
2031it connects any lazy "proxy" signal connections set up by QML.
2032
2033It is possible that this logic should be moved to QMetaObject::connect().
2034*/
2035bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
2036 const QObject *receiver, int method_index,
2037 int type, int *types)
2038{
2039 static const bool indexInSignalRange = false;
2040 flush_vme_signal(object: sender, index: signal_index, indexInSignalRange);
2041 flush_vme_signal(object: receiver, index: method_index, indexInSignalRange);
2042
2043 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
2044}
2045
2046/*! \internal
2047 \a signal_index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
2048 This is different from QMetaMethod::methodIndex().
2049*/
2050void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
2051{
2052 static const bool indexInSignalRange = true;
2053 flush_vme_signal(object: sender, index: signal_index, indexInSignalRange);
2054}
2055
2056QT_END_NAMESPACE
2057
2058#include "moc_qqmlproperty.cpp"
2059

source code of qtdeclarative/src/qml/qml/qqmlproperty.cpp