1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlvaluetypewrapper_p.h"
41
42#include <private/qqmlvaluetype_p.h>
43#include <private/qqmlbinding_p.h>
44#include <private/qqmlglobal_p.h>
45#include <private/qqmlbuiltinfunctions_p.h>
46
47#include <private/qv4engine_p.h>
48#include <private/qv4functionobject_p.h>
49#include <private/qv4variantobject_p.h>
50#include <private/qv4alloca_p.h>
51#include <private/qv4stackframe_p.h>
52#include <private/qv4objectiterator_p.h>
53#include <private/qv4qobjectwrapper_p.h>
54#include <private/qv4identifiertable_p.h>
55#include <private/qv4lookup_p.h>
56#include <QtCore/qloggingcategory.h>
57
58QT_BEGIN_NAMESPACE
59
60Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
61
62DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
63
64namespace QV4 {
65namespace Heap {
66
67struct QQmlValueTypeReference : QQmlValueTypeWrapper
68{
69 void init() {
70 QQmlValueTypeWrapper::init();
71 object.init();
72 }
73 void destroy() {
74 object.destroy();
75 QQmlValueTypeWrapper::destroy();
76 }
77 QQmlQPointer<QObject> object;
78 int property;
79};
80
81}
82
83struct QQmlValueTypeReference : public QQmlValueTypeWrapper
84{
85 V4_OBJECT2(QQmlValueTypeReference, QQmlValueTypeWrapper)
86 V4_NEEDS_DESTROY
87
88 bool readReferenceValue() const;
89};
90
91}
92
93DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeReference);
94
95using namespace QV4;
96
97void Heap::QQmlValueTypeWrapper::destroy()
98{
99 if (gadgetPtr) {
100 valueType->metaType.destruct(gadgetPtr);
101 ::operator delete(gadgetPtr);
102 }
103 if (_propertyCache)
104 _propertyCache->release();
105 Object::destroy();
106}
107
108void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const
109{
110 Q_ASSERT(valueType->metaType.id() == value.userType());
111 if (gadgetPtr)
112 valueType->metaType.destruct(gadgetPtr);
113 if (!gadgetPtr)
114 gadgetPtr = ::operator new(valueType->metaType.sizeOf());
115 valueType->metaType.construct(gadgetPtr, value.constData());
116}
117
118QVariant Heap::QQmlValueTypeWrapper::toVariant() const
119{
120 Q_ASSERT(gadgetPtr);
121 return QVariant(valueType->metaType.id(), gadgetPtr);
122}
123
124
125bool QQmlValueTypeReference::readReferenceValue() const
126{
127 if (!d()->object)
128 return false;
129 // A reference resource may be either a "true" reference (eg, to a QVector3D property)
130 // or a "variant" reference (eg, to a QVariant property which happens to contain a value-type).
131 QMetaProperty writebackProperty = d()->object->metaObject()->property(d()->property);
132 if (writebackProperty.userType() == QMetaType::QVariant) {
133 // variant-containing-value-type reference
134 QVariant variantReferenceValue;
135
136 void *a[] = { &variantReferenceValue, nullptr };
137 QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, a);
138
139 int variantReferenceType = variantReferenceValue.userType();
140 if (variantReferenceType != typeId()) {
141 // This is a stale VariantReference. That is, the variant has been
142 // overwritten with a different type in the meantime.
143 // We need to modify this reference to the updated value type, if
144 // possible, or return false if it is not a value type.
145 if (QQmlValueTypeFactory::isValueType(variantReferenceType)) {
146 QQmlPropertyCache *cache = nullptr;
147 if (const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(variantReferenceType))
148 cache = QJSEnginePrivate::get(engine())->cache(mo);
149 if (d()->gadgetPtr) {
150 d()->valueType->metaType.destruct(d()->gadgetPtr);
151 ::operator delete(d()->gadgetPtr);
152 }
153 d()->gadgetPtr =nullptr;
154 d()->setPropertyCache(cache);
155 d()->valueType = QQmlValueTypeFactory::valueType(variantReferenceType);
156 if (!cache)
157 return false;
158 } else {
159 return false;
160 }
161 }
162 d()->setValue(variantReferenceValue);
163 } else {
164 if (!d()->gadgetPtr) {
165 d()->gadgetPtr = ::operator new(d()->valueType->metaType.sizeOf());
166 d()->valueType->metaType.construct(d()->gadgetPtr, nullptr);
167 }
168 // value-type reference
169 void *args[] = { d()->gadgetPtr, nullptr };
170 QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, args);
171 }
172 return true;
173}
174
175void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4)
176{
177 if (v4->valueTypeWrapperPrototype()->d_unchecked())
178 return;
179
180 Scope scope(v4);
181 ScopedObject o(scope, v4->newObject());
182 o->defineDefaultProperty(v4->id_toString(), method_toString, 1);
183 v4->jsObjects[QV4::ExecutionEngine::ValueTypeProto] = o->d();
184}
185
186ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *object, int property, const QMetaObject *metaObject, int typeId)
187{
188 Scope scope(engine);
189 initProto(engine);
190
191 Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->allocate<QQmlValueTypeReference>());
192 r->d()->object = object;
193 r->d()->property = property;
194 r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
195 r->d()->valueType = QQmlValueTypeFactory::valueType(typeId);
196 r->d()->gadgetPtr = nullptr;
197 return r->asReturnedValue();
198}
199
200ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVariant &value, const QMetaObject *metaObject, int typeId)
201{
202 Scope scope(engine);
203 initProto(engine);
204
205 Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>());
206 r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
207 r->d()->valueType = QQmlValueTypeFactory::valueType(typeId);
208 r->d()->gadgetPtr = nullptr;
209 r->d()->setValue(value);
210 return r->asReturnedValue();
211}
212
213QVariant QQmlValueTypeWrapper::toVariant() const
214{
215 if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
216 if (!ref->readReferenceValue())
217 return QVariant();
218 return d()->toVariant();
219}
220
221bool QQmlValueTypeWrapper::toGadget(void *data) const
222{
223 if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
224 if (!ref->readReferenceValue())
225 return false;
226 const int typeId = d()->valueType->metaType.id();
227 QMetaType::destruct(typeId, data);
228 QMetaType::construct(typeId, data, d()->gadgetPtr);
229 return true;
230}
231
232bool QQmlValueTypeWrapper::virtualIsEqualTo(Managed *m, Managed *other)
233{
234 Q_ASSERT(m && m->as<QQmlValueTypeWrapper>() && other);
235 QV4::QQmlValueTypeWrapper *lv = static_cast<QQmlValueTypeWrapper *>(m);
236
237 if (QV4::VariantObject *rv = other->as<VariantObject>())
238 return lv->isEqual(rv->d()->data());
239
240 if (QV4::QQmlValueTypeWrapper *v = other->as<QQmlValueTypeWrapper>())
241 return lv->isEqual(v->toVariant());
242
243 return false;
244}
245
246PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
247{
248 if (id.isString()) {
249 Scope scope(m);
250 ScopedString n(scope, id.asStringOrSymbol());
251 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
252 QQmlPropertyData *result = r->d()->propertyCache()->property(n.getPointer(), nullptr, nullptr);
253 return result ? Attr_Data : Attr_Invalid;
254 }
255
256 return QV4::Object::virtualGetOwnProperty(m, id, p);
257}
258
259struct QQmlValueTypeWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
260{
261 int propertyIndex = 0;
262 ~QQmlValueTypeWrapperOwnPropertyKeyIterator() override = default;
263 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
264
265};
266
267PropertyKey QQmlValueTypeWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) {
268 const QQmlValueTypeWrapper *that = static_cast<const QQmlValueTypeWrapper *>(o);
269
270 if (const QQmlValueTypeReference *ref = that->as<QQmlValueTypeReference>()) {
271 if (!ref->readReferenceValue())
272 return PropertyKey::invalid();
273 }
274
275 if (that->d()->propertyCache()) {
276 const QMetaObject *mo = that->d()->propertyCache()->createMetaObject();
277 const int propertyCount = mo->propertyCount();
278 if (propertyIndex < propertyCount) {
279 Scope scope(that->engine());
280 ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(propertyIndex).name())));
281 ++propertyIndex;
282 if (attrs)
283 *attrs = QV4::Attr_Data;
284 if (pd)
285 pd->value = that->QV4::Object::get(propName);
286 return propName->toPropertyKey();
287 }
288 }
289
290 return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
291}
292
293
294OwnPropertyKeyIterator *QQmlValueTypeWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
295{
296 *target = *m;
297 return new QQmlValueTypeWrapperOwnPropertyKeyIterator;
298}
299
300bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
301{
302 if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
303 if (!ref->readReferenceValue())
304 return false;
305 return (value == d()->toVariant());
306}
307
308int QQmlValueTypeWrapper::typeId() const
309{
310 return d()->valueType->metaType.id();
311}
312
313bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
314{
315 bool destructGadgetOnExit = false;
316 Q_ALLOCA_DECLARE(void, gadget);
317 if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>()) {
318 if (!d()->gadgetPtr) {
319 Q_ALLOCA_ASSIGN(void, gadget, d()->valueType->metaType.sizeOf());
320 d()->gadgetPtr = gadget;
321 d()->valueType->metaType.construct(d()->gadgetPtr, nullptr);
322 destructGadgetOnExit = true;
323 }
324 if (!ref->readReferenceValue())
325 return false;
326 }
327
328 int flags = 0;
329 int status = -1;
330 void *a[] = { d()->gadgetPtr, nullptr, &status, &flags };
331 QMetaObject::metacall(target, QMetaObject::WriteProperty, propertyIndex, a);
332
333 if (destructGadgetOnExit) {
334 d()->valueType->metaType.destruct(d()->gadgetPtr);
335 d()->gadgetPtr = nullptr;
336 }
337 return true;
338}
339
340ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
341{
342 const Object *o = thisObject->as<Object>();
343 if (!o)
344 return b->engine()->throwTypeError();
345 const QQmlValueTypeWrapper *w = o->as<QQmlValueTypeWrapper>();
346 if (!w)
347 return b->engine()->throwTypeError();
348
349 if (const QQmlValueTypeReference *ref = w->as<QQmlValueTypeReference>())
350 if (!ref->readReferenceValue())
351 RETURN_UNDEFINED();
352
353 QString result;
354 // Prepare a buffer to pass to QMetaType::convert()
355 QString convertResult;
356 convertResult.~QString();
357 if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->metaType.id(), &convertResult, QMetaType::QString)) {
358 result = convertResult;
359 } else {
360 result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType->metaType.id()))
361 + QLatin1Char('(');
362 const QMetaObject *mo = w->d()->propertyCache()->metaObject();
363 const int propCount = mo->propertyCount();
364 for (int i = 0; i < propCount; ++i) {
365 if (mo->property(i).isDesignable()) {
366 QVariant value = mo->property(i).readOnGadget(w->d()->gadgetPtr);
367 if (i > 0)
368 result += QLatin1String(", ");
369 result += value.toString();
370 }
371 }
372 result += QLatin1Char(')');
373 }
374 return Encode(b->engine()->newString(result));
375}
376
377Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
378 Heap::QQmlValueTypeWrapper *valueTypeWrapper,
379 QQmlPropertyData *property)
380{
381 if (property->isFunction()) {
382 // calling a Q_INVOKABLE function of a value type
383 return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, property->coreIndex());
384 }
385
386#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
387 if (property->propType() == metatype) { \
388 cpptype v; \
389 void *args[] = { &v, nullptr }; \
390 metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr), \
391 QMetaObject::ReadProperty, index, args); \
392 return QV4::Encode(constructor(v)); \
393 }
394
395 const QMetaObject *metaObject = valueTypeWrapper->propertyCache()->metaObject();
396
397 int index = property->coreIndex();
398 QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index);
399
400 // These four types are the most common used by the value type wrappers
401 VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal);
402 VALUE_TYPE_LOAD(QMetaType::Int || property->isEnum(), int, int);
403 VALUE_TYPE_LOAD(QMetaType::Int, int, int);
404 VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString);
405 VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
406
407 QVariant v;
408 void *args[] = { nullptr, nullptr };
409 if (property->propType() == QMetaType::QVariant) {
410 args[0] = &v;
411 } else {
412 v = QVariant(property->propType(), static_cast<void *>(nullptr));
413 args[0] = v.data();
414 }
415 metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr), QMetaObject::ReadProperty,
416 index, args);
417 return engine->fromVariant(v);
418#undef VALUE_TYPE_LOAD
419}
420
421ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine,
422 Lookup *lookup)
423{
424 PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->
425 runtimeStrings[lookup->nameIndex]);
426 if (!id.isString())
427 return Object::virtualResolveLookupGetter(object, engine, lookup);
428
429 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(object);
430 QV4::ExecutionEngine *v4 = r->engine();
431 Scope scope(v4);
432 ScopedString name(scope, id.asStringOrSymbol());
433
434 // Note: readReferenceValue() can change the reference->type.
435 if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) {
436 if (!reference->readReferenceValue())
437 return Value::undefinedValue().asReturnedValue();
438 }
439
440 QQmlPropertyData *result = r->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
441 if (!result)
442 return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
443
444 lookup->qgadgetLookup.ic = r->internalClass();
445 lookup->qgadgetLookup.propertyCache = r->d()->propertyCache();
446 lookup->qgadgetLookup.propertyCache->addref();
447 lookup->qgadgetLookup.propertyData = result;
448 lookup->getter = QQmlValueTypeWrapper::lookupGetter;
449 return lookup->getter(lookup, engine, *object);
450}
451
452ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
453{
454 const auto revertLookup = [lookup, engine, &object]() {
455 lookup->qgadgetLookup.propertyCache->release();
456 lookup->qgadgetLookup.propertyCache = nullptr;
457 lookup->getter = Lookup::getterGeneric;
458 return Lookup::getterGeneric(lookup, engine, object);
459 };
460
461 // we can safely cast to a QV4::Object here. If object is something else,
462 // the internal class won't match
463 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
464 if (!o || o->internalClass != lookup->qgadgetLookup.ic)
465 return revertLookup();
466
467 Heap::QQmlValueTypeWrapper *valueTypeWrapper =
468 const_cast<Heap::QQmlValueTypeWrapper*>(static_cast<const Heap::QQmlValueTypeWrapper *>(o));
469 if (valueTypeWrapper->propertyCache() != lookup->qgadgetLookup.propertyCache)
470 return revertLookup();
471
472 if (lookup->qgadgetLookup.ic->vtable == QQmlValueTypeReference::staticVTable()) {
473 Scope scope(engine);
474 Scoped<QQmlValueTypeReference> referenceWrapper(scope, valueTypeWrapper);
475 referenceWrapper->readReferenceValue();
476 }
477
478 QQmlPropertyData *property = lookup->qgadgetLookup.propertyData;
479 return getGadgetProperty(engine, valueTypeWrapper, property);
480}
481
482bool QQmlValueTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
483 const Value &value)
484{
485 return Object::virtualResolveLookupSetter(object, engine, lookup, value);
486}
487
488ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
489{
490 Q_ASSERT(m->as<QQmlValueTypeWrapper>());
491
492 if (!id.isString())
493 return Object::virtualGet(m, id, receiver, hasProperty);
494
495 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
496 QV4::ExecutionEngine *v4 = r->engine();
497 Scope scope(v4);
498 ScopedString name(scope, id.asStringOrSymbol());
499
500 // Note: readReferenceValue() can change the reference->type.
501 if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) {
502 if (!reference->readReferenceValue())
503 return Value::undefinedValue().asReturnedValue();
504 }
505
506 QQmlPropertyData *result = r->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
507 if (!result)
508 return Object::virtualGet(m, id, receiver, hasProperty);
509
510 if (hasProperty)
511 *hasProperty = true;
512
513 return getGadgetProperty(v4, r->d(), result);
514}
515
516bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
517{
518 if (!id.isString())
519 return Object::virtualPut(m, id, value, receiver);
520
521 Q_ASSERT(m->as<QQmlValueTypeWrapper>());
522 ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine();
523 Scope scope(v4);
524 if (scope.hasException())
525 return false;
526
527 Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m));
528 Scoped<QQmlValueTypeReference> reference(scope, m->d());
529
530 int writeBackPropertyType = -1;
531
532 if (reference) {
533 QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property);
534
535 if (!writebackProperty.isWritable() || !reference->readReferenceValue())
536 return false;
537
538 writeBackPropertyType = writebackProperty.userType();
539 }
540
541 ScopedString name(scope, id.asStringOrSymbol());
542
543 const QMetaObject *metaObject = r->d()->propertyCache()->metaObject();
544 const QQmlPropertyData *pd = r->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
545 if (!pd)
546 return false;
547
548 if (reference) {
549 QV4::ScopedFunctionObject f(scope, value);
550 const QQmlQPointer<QObject> &referenceObject = reference->d()->object;
551 const int referencePropertyIndex = reference->d()->property;
552
553 if (f) {
554 if (!f->isBinding()) {
555 // assigning a JS function to a non-var-property is not allowed.
556 QString error = QStringLiteral("Cannot assign JavaScript function to value-type property");
557 ScopedString e(scope, v4->newString(error));
558 v4->throwError(e);
559 return false;
560 }
561
562 QQmlContextData *context = v4->callingQmlContext();
563
564 QQmlPropertyData cacheData;
565 cacheData.setWritable(true);
566 cacheData.setPropType(writeBackPropertyType);
567 cacheData.setCoreIndex(referencePropertyIndex);
568
569 QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
570
571 QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
572 QV4::ScopedContext ctx(scope, f->scope());
573 QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx);
574 newBinding->setSourceLocation(bindingFunction->currentLocation());
575 if (f->isBoundFunction())
576 newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
577 newBinding->setSourceLocation(bindingFunction->currentLocation());
578 newBinding->setTarget(referenceObject, cacheData, pd);
579 QQmlPropertyPrivate::setBinding(newBinding);
580 return true;
581 } else {
582 if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
583 if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()))) {
584 Q_ASSERT(!binding->isValueTypeProxy());
585 const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
586 const auto stackFrame = v4->currentStackFrame;
587 qCInfo(lcBindingRemoval,
588 "Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
589 referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
590 qPrintable(qmlBinding->expressionIdentifier()),
591 metaObject->property(pd->coreIndex()).name(),
592 qPrintable(stackFrame->source()), stackFrame->lineNumber());
593 }
594 }
595 QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()));
596 }
597 }
598
599 QMetaProperty property = metaObject->property(pd->coreIndex());
600 Q_ASSERT(property.isValid());
601
602 QVariant v = v4->toVariant(value, property.userType());
603
604 if (property.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
605 v = v.toInt();
606
607 void *gadget = r->d()->gadgetPtr;
608 property.writeOnGadget(gadget, v);
609
610
611 if (reference) {
612 if (writeBackPropertyType == QMetaType::QVariant) {
613 QVariant variantReferenceValue = r->d()->toVariant();
614
615 int flags = 0;
616 int status = -1;
617 void *a[] = { &variantReferenceValue, nullptr, &status, &flags };
618 QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
619
620 } else {
621 int flags = 0;
622 int status = -1;
623 void *a[] = { r->d()->gadgetPtr, nullptr, &status, &flags };
624 QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
625 }
626 }
627
628 return true;
629}
630
631QT_END_NAMESPACE
632