Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmlproperty.cpp
Go to the documentation of this file.
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
6#include <private/qjsvalue_p.h>
7#include <private/qmetaobject_p.h>
8#include <private/qproperty_p.h>
9#include <private/qqmlboundsignal_p.h>
10#include <private/qqmlbuiltinfunctions_p.h>
11#include <private/qqmldata_p.h>
12#include <private/qqmlengine_p.h>
13#include <private/qqmlirbuilder_p.h>
14#include <private/qqmllist_p.h>
15#include <private/qqmlproperty_p.h>
16#include <private/qqmlsignalnames_p.h>
17#include <private/qqmlstringconverters_p.h>
18#include <private/qqmlvaluetypeproxybinding_p.h>
19#include <private/qqmlvaluetypewrapper_p.h>
20#include <private/qqmlvmemetaobject_p.h>
21#include <private/qv4functionobject_p.h>
22#include <private/qv4qobjectwrapper_p.h>
23
24#include <QtQml/qqmlcontext.h>
25#include <QtQml/qqmlengine.h>
26#include <QtQml/qqmlpropertymap.h>
27
28#include <QtCore/qdebug.h>
29#include <QtCore/qsequentialiterable.h>
30#include <QtCore/qstringlist.h>
31#include <QtCore/qvector.h>
32
33#include <cmath>
34
36
37DEFINE_BOOL_CONFIG_OPTION(compatResolveUrlsOnAssigment, QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT);
38
84
87{
88 if (d)
89 d->release();
90 d = nullptr;
91}
92
102
111{
112 if (ctxt) {
113 d->context = QQmlContextData::get(ctxt);
114 d->engine = ctxt->engine();
115 }
116 d->initDefault(obj);
117}
118
131
136{
137 if (!obj)
138 return;
139
141 core.load(p);
142 if (core.isValid())
143 object = obj;
144}
145
151{
152 d->initProperty(obj, name);
153 if (!isValid()) d->object = nullptr;
154}
155
165{
166 if (ctxt) {
167 d->context = QQmlContextData::get(ctxt);
168 d->engine = ctxt->engine();
169 }
170
171 d->initProperty(obj, name);
172 if (!isValid()) {
173 d->object = nullptr;
174 d->context.reset();
175 d->engine = nullptr;
176 }
177}
178
186{
187 d->engine = engine;
188 d->initProperty(obj, name);
189 if (!isValid()) {
190 d->object = nullptr;
191 d->context.reset();
192 d->engine = nullptr;
193 }
194}
195
197 const QQmlRefPointer<QQmlContextData> &context,
198 QQmlPropertyPrivate::InitFlags flags)
199{
201 auto d = new QQmlPropertyPrivate;
202 result.d = d;
203 d->context = context;
204 d->engine = context ? context->engine() : nullptr;
205 d->initProperty(target, propertyName, flags);
206 if (!result.isValid()) {
207 d->object = nullptr;
208 d->context.reset();
209 d->engine = nullptr;
210 }
211 return result;
212}
213
215{
216 return ::compatResolveUrlsOnAssigment();
217}
218
219QQmlRefPointer<QQmlContextData> QQmlPropertyPrivate::effectiveContext() const
220{
221 if (context)
222 return context;
223 else if (engine)
225 else
226 return nullptr;
227}
228
229// ### Qt7: Do not accept the "onFoo" syntax for signals anymore, and change the flags accordingly.
231 QQmlPropertyPrivate::InitFlags flags)
232{
233 QQmlRefPointer<QQmlTypeNameCache> typeNameCache = context ? context->imports() : nullptr;
234
235 QObject *currentObject = obj;
236 QList<QStringView> path;
237 QStringView terminal(name);
238
239 if (name.contains(QLatin1Char('.'))) {
241 if (path.isEmpty()) return;
242
243 // Everything up to the last property must be an "object type" property
244 for (int ii = 0; ii < path.size() - 1; ++ii) {
245 const QStringView &pathName = path.at(ii);
246
247 // Types must begin with an uppercase letter (see checkRegistration()
248 // in qqmlmetatype.cpp for the enforcement of this).
249 if (typeNameCache && !pathName.isEmpty() && pathName.at(0).isUpper()) {
251 QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(enginePrivate);
252 QQmlTypeNameCache::Result r = typeNameCache->query(pathName, typeLoader);
253 if (r.isValid()) {
254 if (r.type.isValid()) {
255 QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
256 if (!func) return; // Not an attachable type
257
258 currentObject = qmlAttachedPropertiesObject(currentObject, func);
259 if (!currentObject) return; // Something is broken with the attachable type
260 } else if (r.importNamespace) {
261 if (++ii == path.size())
262 return; // No type following the namespace
263
264 // TODO: Do we really _not_ want to query the namespaced types here?
265 r = typeNameCache->query<QQmlTypeNameCache::QueryNamespaced::No>(
266 path.at(ii), r.importNamespace, typeLoader);
267
268 if (!r.type.isValid())
269 return; // Invalid type in namespace
270
271 QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
272 if (!func)
273 return; // Not an attachable type
274
275 currentObject = qmlAttachedPropertiesObject(currentObject, func);
276 if (!currentObject)
277 return; // Something is broken with the attachable type
278
279 } else if (r.scriptIndex != -1) {
280 return; // Not a type
281 } else {
282 Q_ASSERT(!"Unreachable");
283 }
284 continue;
285 }
286
287 }
288
289 QQmlPropertyData local;
290 const QQmlPropertyData *property = currentObject
291 ? QQmlPropertyCache::property(currentObject, pathName, context, &local)
292 : nullptr;
293
294 if (!property) {
295 // Not a property; Might be an ID
296 // You can't look up an ID on a non-null object, though.
297 if (currentObject || !(flags & InitFlag::AllowId))
298 return;
299
300 for (auto idContext = context; idContext; idContext = idContext->parent()) {
301 const int objectId = idContext->propertyIndex(pathName.toString());
302 if (objectId != -1 && objectId < idContext->numIdValues()) {
303 currentObject = context->idValue(objectId);
304 break;
305 }
306 }
307
308 if (!currentObject)
309 return;
310
311 continue;
312 } else if (property->isFunction()) {
313 return; // Not an object property
314 }
315
316 if (ii == (path.size() - 2) && QQmlMetaType::isValueType(property->propType())) {
317 // We're now at a value type property
318 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(property->propType());
319 if (!valueTypeMetaObject) return; // Not a value type
320
321 int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData());
322 if (idx == -1) return; // Value type property does not exist
323
324 QMetaProperty vtProp = valueTypeMetaObject->property(idx);
325
326 Q_ASSERT(idx <= 0x0000FFFF);
327
328 object = currentObject;
329 core = *property;
331 valueTypeData.setPropType(vtProp.metaType());
333
334 return;
335 } else {
336 if (!property->isQObject()) {
337 if (auto asPropertyMap = qobject_cast<QQmlPropertyMap*>(currentObject))
338 currentObject = asPropertyMap->value(path.at(ii).toString()).value<QObject*>();
339 else
340 return; // Not an object property, and not a property map
341 } else {
342 property->readProperty(currentObject, &currentObject);
343 }
344
345 if (!currentObject) return; // No value
346
347 }
348
349 }
350
351 terminal = path.last();
352 } else if (!currentObject) {
353 return;
354 }
355
356 auto findSignalInMetaObject = [&](const QByteArray &signalName) {
357 const QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName);
358 if (!method.isValid())
359 return false;
360
361 object = currentObject;
363 return true;
364 };
365
366 QQmlData *ddata = QQmlData::get(currentObject, false);
367 auto findChangeSignal = [&](QStringView signalName) {
368 if (auto propName = QQmlSignalNames::changedSignalNameToPropertyName(signalName)) {
369 const QQmlPropertyData *d =
370 ddata->propertyCache->property(*propName, currentObject, context);
371 while (d && d->isFunction())
372 d = ddata->propertyCache->overrideData(d);
373
374 if (d && d->notifyIndex() != -1) {
375 object = currentObject;
376 core = *ddata->propertyCache->signal(d->notifyIndex());
377 return true;
378 }
379 }
380 return false;
381 };
382
383 const auto findSignal = [&](const QString &signalName) {
384 if (ddata && ddata->propertyCache) {
385 // Try method
386 const QQmlPropertyData *d
387 = ddata->propertyCache->property(signalName, currentObject, context);
388
389 // ### Qt7: This code treats methods as signals. It should use d->isSignal().
390 // That would be a change in behavior, though. Right now you can construct a
391 // QQmlProperty from such a thing.
392 while (d && !d->isFunction())
393 d = ddata->propertyCache->overrideData(d);
394
395 if (d) {
396 object = currentObject;
397 core = *d;
398 return true;
399 }
400
401 return findChangeSignal(signalName);
402 }
403
404 return findSignalInMetaObject(signalName.toUtf8());
405 };
406
407 auto signalName = QQmlSignalNames::handlerNameToSignalName(terminal);
408 if (signalName) {
409 if (findSignal(*signalName))
410 return;
411 } else {
412 signalName = QQmlSignalNames::badHandlerNameToSignalName(terminal);
413 if (signalName) {
414 if (findSignal(*signalName)) {
415 qWarning()
416 << terminal
417 << "is not a properly capitalized signal handler name."
419 << "would be correct.";
420 return;
421 }
422 }
423 }
424
425 if (ddata && ddata->propertyCache) {
426 const QQmlPropertyData *property = ddata->propertyCache->property(
427 terminal, currentObject, context);
428
429 // Technically, we might find an override that is not a function.
430 while (property && !property->isSignal()) {
431 if (!property->isFunction()) {
432 object = currentObject;
433 core = *property;
434 nameCache = terminal.toString();
435 return;
436 }
437 property = ddata->propertyCache->overrideData(property);
438 }
439
441 return;
442
443 if (property) {
444 Q_ASSERT(property->isSignal());
445 object = currentObject;
446 core = *property;
447 return;
448 }
449
450 // At last: Try the change signal.
451 findChangeSignal(terminal);
452 } else {
453 // We might still find the property in the metaobject, even without property cache.
454 const QByteArray propertyName = terminal.toUtf8();
455 const QMetaProperty prop = findPropertyByName(currentObject->metaObject(), propertyName);
456
457 if (prop.isValid()) {
458 object = currentObject;
459 core.load(prop);
460 return;
461 }
462
464 findSignalInMetaObject(terminal.toUtf8());
465 }
466}
467
474{
476 QMetaMethod m = object->metaObject()->method(core.coreIndex());
478}
479
484{
485 d = other.d;
486 if (d)
487 d->addref();
488}
489
518
521{
522 uint type = this->type();
523
524 if (isValueType()) {
526 } else if (type & QQmlProperty::Property) {
528 if (!type.isValid())
532 else if (core.isQObject())
534 else if (core.isQList())
535 return QQmlProperty::List;
536 else
538 }
539
541}
542
548{
549 if (!d)
550 return nullptr;
551 if (d->isValueType()) {
552 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(d->core.propType());
553 Q_ASSERT(valueTypeMetaObject);
554 return valueTypeMetaObject->property(d->valueTypeData.coreIndex()).typeName();
555 } else if (d->object && type() & Property && d->core.isValid()) {
556 return d->object->metaObject()->property(d->core.coreIndex()).typeName();
557 } else {
558 return nullptr;
559 }
560}
561
567{
568 if (!d || !other.d)
569 return false;
570 // category is intentially omitted here as it is generated
571 // from the other members
572 return d->object == other.d->object &&
573 d->core.coreIndex() == other.d->core.coreIndex() &&
574 d->valueTypeData.coreIndex() == other.d->valueTypeData.coreIndex();
575}
576
584{
585 return d ? d->propertyType().id() : int(QMetaType::UnknownType);
586}
587
594{
595 return d ? d->propertyType() : QMetaType {};
596}
597
599{
600 return valueTypeData.isValid();
601}
602
604{
605 uint type = this->type();
606 if (isValueType()) {
607 return valueTypeData.propType();
608 } else if (type & QQmlProperty::Property) {
609 return core.propType();
610 } else {
611 return QMetaType();
612 }
613}
614
616{
617 if (core.isFunction())
619 else if (core.isValid())
621 else
623}
624
629{
630 return d ? d->type() : Invalid;
631}
632
637{
638 return type() & Property;
639}
640
645{
646 return type() & SignalProperty;
647}
648
653{
654 return d ? d->object : nullptr;
655}
656
661{
662 QQmlProperty copied(other);
663 qSwap(d, copied.d);
664 return *this;
665}
666
671{
672 if (!d)
673 return false;
674 if (!d->object)
675 return false;
676 if (d->core.isQList()) //list
677 return true;
678 else if (d->core.isFunction()) //signal handler
679 return false;
680 else if (d->core.isValid()) //normal property
681 return d->core.isWritable();
682 else
683 return false;
684}
685
691{
692 if (!d)
693 return false;
694 if (!d->object)
695 return false;
696 if (d->core.isValid())
697 return d->core.isBindable();
698 return false;
699}
700
705{
706 if (!d)
707 return false;
708 if (type() & Property && d->core.isValid() && d->object)
709 return d->object->metaObject()->property(d->core.coreIndex()).isDesignable();
710 else
711 return false;
712}
713
718{
719 if (!d)
720 return false;
721 if (type() & Property && d->core.isValid() && d->object)
722 return d->core.isResettable();
723 else
724 return false;
725}
726
732{
733 if (!d)
734 return false;
735 return type() != Invalid;
736}
737
742{
743 if (!d)
744 return QString();
745 if (d->nameCache.isEmpty()) {
746 if (!d->object) {
747 } else if (d->isValueType()) {
748 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(d->core.propType());
749 Q_ASSERT(valueTypeMetaObject);
750
751 const char *vtName = valueTypeMetaObject->property(d->valueTypeData.coreIndex()).name();
752 d->nameCache = d->core.name(d->object) + QLatin1Char('.') + QString::fromUtf8(vtName);
753 } else if (type() & SignalProperty) {
754 // ### Qt7: Return the original signal name here. Do not prepend "on"
756 } else {
757 d->nameCache = d->core.name(d->object);
758 }
759 }
760
761 return d->nameCache;
762}
763
769{
770 if (!d)
771 return QMetaProperty();
772 if (type() & Property && d->core.isValid() && d->object)
773 return d->object->metaObject()->property(d->core.coreIndex());
774 else
775 return QMetaProperty();
776}
777
783{
784 if (!d)
785 return QMetaMethod();
786 if (type() & SignalProperty && d->object)
787 return d->object->metaObject()->method(d->core.coreIndex());
788 else
789 return QMetaMethod();
790}
791
798{
799 if (!that.d || !that.isProperty() || !that.d->object)
800 return nullptr;
801
802 QQmlPropertyIndex thatIndex(that.d->core.coreIndex(), that.d->valueTypeData.coreIndex());
803 return binding(that.d->object, thatIndex);
804}
805
816void
818{
819 if (!newBinding) {
820 removeBinding(that);
821 return;
822 }
823
824 if (!that.d || !that.isProperty() || !that.d->object) {
825 if (!newBinding->ref)
826 delete newBinding;
827 return;
828 }
829 setBinding(newBinding);
830}
831
832static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPropertyPrivate::BindingFlags flags = QQmlPropertyPrivate::None)
833{
834 int coreIndex = index.coreIndex();
835 int valueTypeIndex = index.valueTypeIndex();
836
837 QQmlData *data = QQmlData::get(object, false);
838
839 if (!data || !data->hasBindingBit(coreIndex))
840 return;
841
842 QQmlAbstractBinding::Ptr oldBinding;
843 oldBinding = data->bindings;
844
845 while (oldBinding && (oldBinding->targetPropertyIndex().coreIndex() != coreIndex ||
846 oldBinding->targetPropertyIndex().hasValueTypeIndex()))
847 oldBinding = oldBinding->nextBinding();
848
849 if (!oldBinding)
850 return;
851
852 if (valueTypeIndex != -1 && oldBinding->kind() == QQmlAbstractBinding::ValueTypeProxy)
853 oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index);
854
855 if (!oldBinding)
856 return;
857
859 oldBinding->setEnabled(false, {});
860 oldBinding->removeFromObject();
861}
862
864{
865 removeBinding(b->targetObject(), b->targetPropertyIndex());
866}
867
869{
870 Q_ASSERT(o);
871
872 auto [target, targetIndex] = findAliasTarget(o, index);
873 removeOldBinding(target, targetIndex);
874}
875
877{
878 if (!that.d || !that.isProperty() || !that.d->object)
879 return;
880
881 removeBinding(that.d->object, that.d->encodedIndex());
882}
883
886{
887 auto aliasTarget = findAliasTarget(object, index);
888 object = aliasTarget.targetObject;
889 index = aliasTarget.targetIndex;
890
891 QQmlData *data = QQmlData::get(object);
892 if (!data)
893 return nullptr;
894
895 const int coreIndex = index.coreIndex();
896 const int valueTypeIndex = index.valueTypeIndex();
897
898 if (coreIndex < 0 || !data->hasBindingBit(coreIndex))
899 return nullptr;
900
901 QQmlAbstractBinding *binding = data->bindings;
902 while (binding && (binding->targetPropertyIndex().coreIndex() != coreIndex ||
903 binding->targetPropertyIndex().hasValueTypeIndex()))
904 binding = binding->nextBinding();
905
906 if (binding && valueTypeIndex != -1) {
909 }
910
911 return binding;
912}
913
915 QObject **targetObject,
916 QQmlPropertyIndex *targetBindingIndex)
917{
918 QQmlData *data = QQmlData::get(object, false);
919 if (data) {
920 int coreIndex = bindingIndex.coreIndex();
921 int valueTypeIndex = bindingIndex.valueTypeIndex();
922
923 const QQmlPropertyData *propertyData =
924 data->propertyCache?data->propertyCache->property(coreIndex):nullptr;
925 if (propertyData && propertyData->isAlias()) {
927
928 QObject *aObject = nullptr; int aCoreIndex = -1; int aValueTypeIndex = -1;
929 if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
930 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
931 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
932
933 QQmlPropertyIndex aBindingIndex(aCoreIndex);
934 if (aValueTypeIndex != -1) {
935 aBindingIndex = QQmlPropertyIndex(aCoreIndex, aValueTypeIndex);
936 } else if (valueTypeIndex != -1) {
937 aBindingIndex = QQmlPropertyIndex(aCoreIndex, valueTypeIndex);
938 }
939
940 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
941 return;
942 }
943 }
944 }
945
946 *targetObject = object;
947 *targetBindingIndex = bindingIndex;
948}
949
951{
952 ResolvedAlias resolved;
953 findAliasTarget(baseObject, baseIndex, &resolved.targetObject, &resolved.targetIndex);
954 return resolved;
955}
956
957
958
959void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags)
960{
962 Q_ASSERT(binding->targetObject());
963
964 QObject *object = binding->targetObject();
965 const QQmlPropertyIndex index = binding->targetPropertyIndex();
966
967#ifndef QT_NO_DEBUG
968 int coreIndex = index.coreIndex();
969 QQmlData *data = QQmlData::get(object, true);
970 if (data->propertyCache) {
971 const QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
972 Q_ASSERT(propertyData);
973 }
974#endif
975
976 removeOldBinding(object, index, flags);
977
978 binding->addToObject();
979 if (!(flags & DontEnable))
980 binding->setEnabled(true, writeFlags);
981
982}
983
990{
991 if (!(that.type() & QQmlProperty::SignalProperty))
992 return nullptr;
993
994 if (!that.d->object)
995 return nullptr;
996 QQmlData *data = QQmlData::get(that.d->object);
997 if (!data)
998 return nullptr;
999
1000 QQmlBoundSignal *signalHandler = data->signalHandlers;
1001
1002 while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(that)->signalIndex())
1003 signalHandler = signalHandler->m_nextSignal;
1004
1005 if (signalHandler)
1006 return signalHandler->expression();
1007
1008 return nullptr;
1009}
1010
1016{
1017 if (expr)
1018 expr->addref();
1020}
1021
1028{
1029 if (!(that.type() & QQmlProperty::SignalProperty)) {
1030 if (expr)
1031 expr->release();
1032 return;
1033 }
1034
1035 if (!that.d->object)
1036 return;
1037 QQmlData *data = QQmlData::get(that.d->object, nullptr != expr);
1038 if (!data)
1039 return;
1040
1041 QQmlBoundSignal *signalHandler = data->signalHandlers;
1042
1043 while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(that)->signalIndex())
1044 signalHandler = signalHandler->m_nextSignal;
1045
1046 if (signalHandler) {
1047 signalHandler->takeExpression(expr);
1048 return;
1049 }
1050
1051 if (expr) {
1052 int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex();
1053 QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, signalIndex, that.d->object,
1054 expr->engine());
1055 signal->takeExpression(expr);
1056 }
1057}
1058
1063{
1064 if (!d)
1065 return QVariant();
1066 if (!d->object)
1067 return QVariant();
1068
1069 if (type() & SignalProperty) {
1070
1071 return QVariant();
1072
1073 } else if (type() & Property) {
1074
1075 return d->readValueProperty();
1076
1077 }
1078 return QVariant();
1079}
1080
1089{
1090 QQmlProperty p(const_cast<QObject *>(object), name);
1091 return p.read();
1092}
1093
1105{
1106 QQmlProperty p(const_cast<QObject *>(object), name, ctxt);
1107 return p.read();
1108}
1109
1122{
1123 QQmlProperty p(const_cast<QObject *>(object), name, engine);
1124 return p.read();
1125}
1126
1128{
1129 auto doRead = [&](QQmlGadgetPtrWrapper *wrapper) {
1130 wrapper->read(object, core.coreIndex());
1131 return wrapper->readOnGadget(wrapper->property(valueTypeData.coreIndex()));
1132 };
1133
1134 if (isValueType()) {
1136 return doRead(wrapper);
1137 if (QQmlValueType *valueType = QQmlMetaType::valueType(core.propType())) {
1138 QQmlGadgetPtrWrapper wrapper(valueType, nullptr);
1139 return doRead(&wrapper);
1140 }
1141 return QVariant();
1142 } else if (core.isQList()) {
1143
1144 QQmlListProperty<QObject> prop;
1145 core.readProperty(object, &prop);
1147
1148 } else if (core.isQObject()) {
1149
1150 QObject *rv = nullptr;
1151 core.readProperty(object, &rv);
1152 return QVariant::fromValue(rv);
1153
1154 } else {
1155
1156 if (!core.propType().isValid()) // Unregistered type
1157 return object->metaObject()->property(core.coreIndex()).read(object);
1158
1160 int status = -1;
1161 void *args[] = { nullptr, &value, &status };
1162 if (core.propType() == QMetaType::fromType<QVariant>()) {
1163 args[0] = &value;
1164 } else {
1165 value = QVariant(core.propType(), (void*)nullptr);
1166 args[0] = value.data();
1167 }
1169 if (core.propType() != QMetaType::fromType<QVariant>() && args[0] != value.data())
1170 return QVariant(QMetaType(core.propType()), args[0]);
1171
1172 return value;
1173 }
1174}
1175
1176// helper function to allow assignment / binding to QList<QUrl> properties.
1178{
1179 if (value.metaType() == QMetaType::fromType<QList<QUrl>>())
1180 return value.value<QList<QUrl> >();
1181
1182 QList<QUrl> urls;
1183 if (value.metaType() == QMetaType::fromType<QUrl>()) {
1184 urls.append(value.toUrl());
1185 } else if (value.metaType() == QMetaType::fromType<QString>()) {
1186 urls.append(QUrl(value.toString()));
1187 } else if (value.metaType() == QMetaType::fromType<QByteArray>()) {
1188 urls.append(QUrl(QString::fromUtf8(value.toByteArray())));
1189 } else if (value.metaType() == QMetaType::fromType<QStringList>()) {
1190 QStringList urlStrings = value.value<QStringList>();
1191 const int urlStringsSize = urlStrings.size();
1192 urls.reserve(urlStringsSize);
1193 for (int i = 0; i < urlStringsSize; ++i)
1194 urls.append(QUrl(urlStrings.at(i)));
1195 } // note: QList<QByteArray> is not currently supported.
1196 return urls;
1197}
1198
1199// ### Qt7: Get rid of this
1201 const QVariant &value, const QQmlRefPointer<QQmlContextData> &ctxt)
1202{
1203 QList<QUrl> urls = urlSequence(value);
1204
1205 for (auto urlIt = urls.begin(); urlIt != urls.end(); ++urlIt)
1206 *urlIt = ctxt->resolvedUrl(*urlIt);
1207
1208 return urls;
1209}
1210
1211//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1212bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1213{
1214 if (!object || !prop.isWritable())
1215 return false;
1216
1217 QVariant v = value;
1218 if (prop.isEnumType() && v.metaType() != prop.metaType()) {
1219 QMetaEnum menum = prop.enumerator();
1220 if (v.userType() == QMetaType::QString) {
1221 bool ok;
1222 if (prop.isFlagType())
1223 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1224 else
1225 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1226 if (!ok)
1227 return false;
1228 }
1229 if (!v.convert(prop.metaType())) // ### TODO: underlyingType might be faster?
1230 return false;
1231 }
1232
1233 // the status variable is changed by qt_metacall to indicate what it did
1234 // this feature is currently only used by QtDBus and should not be depended
1235 // upon. Don't change it without looking into QDBusAbstractInterface first
1236 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1237 // changed: result stored directly in value, return the value of status
1238 int status = -1;
1239 void *argv[] = { v.data(), &v, &status, &flags };
1241 return status;
1242}
1243
1244bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, QQmlPropertyData::WriteFlags flags)
1245{
1247}
1248
1250 QObject *object, const QQmlPropertyData &core,
1251 const QQmlPropertyData &valueTypeData, QQmlPropertyData::WriteFlags flags)
1252{
1253 // Remove any existing bindings on this property
1254 if (!(flags & QQmlPropertyData::DontRemoveBinding) && object) {
1256 object, QQmlPropertyPrivate::encodedIndex(core, valueTypeData));
1257 }
1258}
1259
1260template<typename Op>
1262 QObject *object, int coreIndex, QQmlGadgetPtrWrapper *wrapper,
1263 QQmlPropertyData::WriteFlags flags, int internalIndex, Op op)
1264{
1265 wrapper->read(object, coreIndex);
1266 const bool rv = op(wrapper);
1267 wrapper->write(object, coreIndex, flags, internalIndex);
1268 return rv;
1269}
1270
1271template<typename Op>
1273 QObject *object, const QQmlPropertyData &core,
1274 const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags,
1275 int internalIndex, Op op)
1276{
1279 : nullptr) {
1281 object, core.coreIndex(), wrapper, flags, internalIndex, op);
1282 }
1283
1284 if (QQmlValueType *valueType = QQmlMetaType::valueType(core.propType())) {
1285 QQmlGadgetPtrWrapper wrapper(valueType, nullptr);
1287 object, core.coreIndex(), &wrapper, flags, internalIndex, op);
1288 }
1289
1290 return false;
1291}
1292
1294 QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
1295 const QVariant &value, const QQmlRefPointer<QQmlContextData> &context,
1296 QQmlPropertyData::WriteFlags flags)
1297{
1299
1300 if (!valueTypeData.isValid())
1301 return write(object, core, value, context, flags);
1302
1306 return write(wrapper, valueTypeData, value, context, flags);
1307 });
1308}
1309
1311 QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
1312 const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
1313{
1315
1316 if (!valueTypeData.isValid())
1317 return reset(object, core, flags);
1318
1322 return reset(wrapper, valueTypeData, flags);
1323 });
1324}
1325
1326// We need to prevent new-style bindings from being removed.
1328{
1330
1332 QQmlPropertyData::WriteFlags flags)
1333 {
1334 if (!property.isBindable() || !(flags & QQmlPropertyData::DontRemoveBinding))
1335 return;
1336
1337 QUntypedBindable bindable;
1338 void *argv[] = {&bindable};
1340 untypedBinding = bindable.binding();
1341 if (auto priv = QPropertyBindingPrivate::get(untypedBinding))
1342 priv->setSticky(true);
1343 }
1344
1346 {
1347 if (untypedBinding.isNull())
1348 return;
1349 auto priv = QPropertyBindingPrivate::get(untypedBinding);
1350 priv->setSticky(false);
1351 }
1352
1353private:
1354 QUntypedPropertyBinding untypedBinding;
1355};
1356
1358 bool couldConvert = false;
1359 bool couldWrite = false;
1360
1361 operator bool() const { return couldConvert; }
1362};
1363
1365 QObject *object, const QQmlPropertyData &property, const QVariant &value,
1366 QQmlPropertyData::WriteFlags flags, QMetaType propertyMetaType, QMetaType variantMetaType,
1367 bool isUrl) {
1368
1369 if (isUrl
1370 || variantMetaType == QMetaType::fromType<QString>()
1371 || propertyMetaType == QMetaType::fromType<QList<QUrl>>()
1372 || property.isQList()) {
1373 return {false, false};
1374 }
1375
1376 if (variantMetaType == QMetaType::fromType<QJSValue>()) {
1377 // Handle Qt.binding bindings here to avoid mistaken conversion below
1378 const QJSValue &jsValue = get<QJSValue>(value);
1379 const QV4::FunctionObject *f
1380 = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&jsValue);
1381 if (f && f->isBinding()) {
1383 f->engine(), object, &property, f->asReturnedValue());
1384 return {true, true};
1385 }
1386 }
1387
1388 // common cases:
1389 switch (propertyMetaType.id()) {
1390 case QMetaType::Bool:
1391 if (value.canConvert(propertyMetaType)) {
1392 bool b = value.toBool();
1393 return {true, property.writeProperty(object, &b, flags)};
1394 }
1395 return {false, false};
1396 case QMetaType::Int: {
1397 bool ok = false;
1398 int i = value.toInt(&ok);
1399 return {ok, ok && property.writeProperty(object, &i, flags)};
1400 }
1401 case QMetaType::UInt: {
1402 bool ok = false;
1403 uint u = value.toUInt(&ok);
1404 return {ok, ok && property.writeProperty(object, &u, flags)};
1405 }
1406 case QMetaType::Double: {
1407 bool ok = false;
1408 double d = value.toDouble(&ok);
1409 return {ok, ok && property.writeProperty(object, &d, flags)};
1410 }
1411 case QMetaType::Float: {
1412 bool ok = false;
1413 float f = value.toFloat(&ok);
1414 return {ok, ok && property.writeProperty(object, &f, flags)};
1415 }
1416 case QMetaType::QString:
1417 if (value.canConvert(propertyMetaType)) {
1418 QString s = value.toString();
1419 return {true, property.writeProperty(object, &s, flags)};
1420 }
1421 return {false, false};
1422 case QMetaType::QVariantMap:
1423 if (value.canConvert(propertyMetaType)) {
1424 QVariantMap m = value.toMap();
1425 return {true, property.writeProperty(object, &m, flags)};
1426 }
1427 return {false, false};
1428 default: {
1429 break;
1430 }
1431 }
1432
1433 QVariant converted = QQmlValueTypeProvider::createValueType(value, propertyMetaType);
1434 if (!converted.isValid()) {
1435 converted = QVariant(propertyMetaType);
1436 if (!QMetaType::convert(value.metaType(), value.constData(),
1437 propertyMetaType, converted.data())) {
1438 return {false, false};
1439 }
1440 }
1441 return {true, property.writeProperty(object, converted.data(), flags)};
1442};
1443
1444template<typename Op>
1445bool iterateQObjectContainer(QMetaType metaType, const void *data, Op op)
1446{
1447 QSequentialIterable iterable;
1448 if (!QMetaType::convert(metaType, data, QMetaType::fromType<QSequentialIterable>(), &iterable))
1449 return false;
1450
1451 const QMetaSequence metaSequence = iterable.metaContainer();
1452
1453 if (!metaSequence.hasConstIterator()
1454 || !metaSequence.canGetValueAtConstIterator()
1455 || !iterable.valueMetaType().flags().testFlag(QMetaType::PointerToQObject)) {
1456 return false;
1457 }
1458
1459 const void *container = iterable.constIterable();
1460 void *it = metaSequence.constBegin(container);
1461 const void *end = metaSequence.constEnd(container);
1462 QObject *o = nullptr;
1463 while (!metaSequence.compareConstIterator(it, end)) {
1464 metaSequence.valueAtConstIterator(it, &o);
1465 op(o);
1466 metaSequence.advanceConstIterator(it, 1);
1467 }
1468 metaSequence.destroyConstIterator(it);
1469 metaSequence.destroyConstIterator(end);
1470 return true;
1471}
1472
1474 QObject *object, const QQmlPropertyData &property, const QVariant &value,
1475 const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
1476{
1477 const QMetaType propertyMetaType = property.propType();
1478 const QMetaType variantMetaType = value.metaType();
1479
1480 const BindingFixer bindingFixer(object, property, flags);
1481
1482 if (property.isEnum()) {
1483 QMetaProperty prop = object->metaObject()->property(property.coreIndex());
1484 QVariant v = value;
1485 // Enum values come through the script engine as doubles
1486 if (variantMetaType == QMetaType::fromType<double>()) {
1487 double integral;
1488 double fractional = std::modf(value.toDouble(), &integral);
1489 if (qFuzzyIsNull(fractional))
1490 v.convert(QMetaType::fromType<qint32>());
1491 }
1492 return writeEnumProperty(prop, property.coreIndex(), object, v, flags);
1493 }
1494
1496 const bool isUrl = propertyMetaType == QMetaType::fromType<QUrl>(); // handled separately
1497
1498 // The cases below are in approximate order of likelyhood:
1499 if (propertyMetaType == variantMetaType && !isUrl
1500 && propertyMetaType != QMetaType::fromType<QList<QUrl>>() && !property.isQList()) {
1501 return property.writeProperty(object, const_cast<void *>(value.constData()), flags);
1502 } else if (property.isQObject()) {
1503 QVariant val = value;
1504 QMetaType varType;
1505 if (variantMetaType == QMetaType::fromType<std::nullptr_t>()) {
1506 // This reflects the fact that you can assign a nullptr to a QObject pointer
1507 // Without the change to QObjectStar, rawMetaObjectForType would not give us a QQmlMetaObject
1508 varType = QMetaType::fromType<QObject*>();
1509 val = QVariant(varType, nullptr);
1510 } else {
1511 varType = variantMetaType;
1512 }
1513 QQmlMetaObject valMo = rawMetaObjectForType(varType);
1514 if (valMo.isNull() || !varType.flags().testFlag(QMetaType::PointerToQObject))
1515 return false;
1516 QObject *o = *static_cast<QObject *const *>(val.constData());
1517 QQmlMetaObject propMo = rawMetaObjectForType(propertyMetaType);
1518
1519 if (o)
1520 valMo = o;
1521
1522 if (QQmlMetaObject::canConvert(valMo, propMo)) {
1523 return property.writeProperty(object, &o, flags);
1524 } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
1525 // In the case of a null QObject, we assign the null if there is
1526 // any change that the null variant type could be up or down cast to
1527 // the property type.
1528 return property.writeProperty(object, &o, flags);
1529 } else {
1530 return false;
1531 }
1533 object, property, value, flags, propertyMetaType, variantMetaType, isUrl)) {
1534 return result.couldWrite;
1535 } else if (propertyMetaType == QMetaType::fromType<QVariant>()) {
1536 return property.writeProperty(object, const_cast<QVariant *>(&value), flags);
1537 } else if (isUrl) {
1538 QUrl u;
1539 if (variantMetaType == QMetaType::fromType<QUrl>()) {
1540 u = value.toUrl();
1541 if (compatResolveUrlsOnAssigment() && context && u.isRelative() && !u.isEmpty())
1542 u = context->resolvedUrl(u);
1543 }
1544 else if (variantMetaType == QMetaType::fromType<QByteArray>())
1545 u = QUrl(QString::fromUtf8(value.toByteArray()));
1546 else if (variantMetaType == QMetaType::fromType<QString>())
1547 u = QUrl(value.toString());
1548 else
1549 return false;
1550
1551 return property.writeProperty(object, &u, flags);
1552 } else if (propertyMetaType == QMetaType::fromType<QList<QUrl>>()) {
1553 QList<QUrl> urlSeq = compatResolveUrlsOnAssigment()
1555 : urlSequence(value);
1556 return property.writeProperty(object, &urlSeq, flags);
1557 } else if (property.isQList()) {
1558 if (propertyMetaType.flags() & QMetaType::IsQmlList) {
1559 QMetaType listValueType = QQmlMetaType::listValueType(propertyMetaType);
1560 QQmlMetaObject valueMetaObject = QQmlMetaType::rawMetaObjectForType(listValueType);
1561 if (valueMetaObject.isNull())
1562 return false;
1563
1564 QQmlListProperty<QObject> prop;
1565 property.readProperty(object, &prop);
1566
1567 if (!prop.clear || !prop.append)
1568 return false;
1569
1570 const bool useNonsignalingListOps = prop.clear == &QQmlVMEMetaObject::list_clear
1571 && prop.append == &QQmlVMEMetaObject::list_append;
1572
1573 auto propClear =
1574 useNonsignalingListOps ? &QQmlVMEMetaObject::list_clear_nosignal : prop.clear;
1575 auto propAppend =
1576 useNonsignalingListOps ? &QQmlVMEMetaObject::list_append_nosignal : prop.append;
1577
1578 propClear(&prop);
1579
1580 const auto doAppend = [&](QObject *o) {
1581 if (o && !QQmlMetaObject::canConvert(o, valueMetaObject))
1582 o = nullptr;
1583 propAppend(&prop, o);
1584 };
1585
1586 if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
1588 for (qsizetype ii = 0; ii < qdlr.count(); ++ii)
1589 doAppend(qdlr.at(ii));
1590 } else if (variantMetaType == QMetaType::fromType<QList<QObject *>>()) {
1591 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1592 for (qsizetype ii = 0; ii < list.size(); ++ii)
1593 doAppend(list.at(ii));
1594 } else if (variantMetaType == QMetaType::fromType<QList<QVariant>>()) {
1595 const QList<QVariant> &list
1596 = *static_cast<const QList<QVariant> *>(value.constData());
1597 for (const QVariant &entry : list)
1598 doAppend(QQmlMetaType::toQObject(entry));
1599 } else if (!iterateQObjectContainer(variantMetaType, value.data(), doAppend)) {
1600 doAppend(QQmlMetaType::toQObject(value));
1601 }
1602 if (useNonsignalingListOps) {
1605 }
1606 } else if (variantMetaType == propertyMetaType) {
1607 QVariant v = value;
1608 property.writeProperty(object, v.data(), flags);
1609 } else {
1610 QVariant list(propertyMetaType);
1611 const QQmlType type = QQmlMetaType::qmlType(propertyMetaType);
1612 const QMetaSequence sequence = type.listMetaSequence();
1613 if (sequence.canAddValue())
1614 sequence.addValue(list.data(), value.data());
1615 property.writeProperty(object, list.data(), flags);
1616 }
1617 } else if (enginePriv && propertyMetaType == QMetaType::fromType<QJSValue>()) {
1618 // We can convert everything into a QJSValue if we have an engine.
1620 enginePriv->v4engine()->metaTypeToJS(variantMetaType, value.constData()));
1621 return property.writeProperty(object, &jsValue, flags);
1622 } else {
1623 Q_ASSERT(variantMetaType != propertyMetaType);
1624
1625 bool ok = false;
1626 QVariant v;
1627 if (variantMetaType == QMetaType::fromType<QString>())
1628 v = QQmlStringConverters::variantFromString(value.toString(), propertyMetaType, &ok);
1629
1630 if (!ok) {
1631 v = value;
1632 if (v.convert(propertyMetaType)) {
1633 ok = true;
1634 }
1635 }
1636 if (!ok) {
1637 // the only other options are that they are assigning a single value
1638 // or a QVariantList to a sequence type property (eg, an int to a
1639 // QList<int> property) or that we encountered an interface type.
1640 // Note that we've already handled single-value assignment to QList<QUrl> properties.
1641 QSequentialIterable iterable;
1642 v = QVariant(propertyMetaType);
1643 if (QMetaType::view(
1644 propertyMetaType, v.data(),
1645 QMetaType::fromType<QSequentialIterable>(),
1646 &iterable)) {
1647 const QMetaSequence propertyMetaSequence = iterable.metaContainer();
1648 if (propertyMetaSequence.canAddValueAtEnd()) {
1649 const QMetaType elementMetaType = iterable.valueMetaType();
1650 void *propertyContainer = iterable.mutableIterable();
1651
1652 if (variantMetaType == elementMetaType) {
1653 propertyMetaSequence.addValueAtEnd(propertyContainer, value.constData());
1654 ok = true;
1655 } else if (variantMetaType == QMetaType::fromType<QVariantList>()) {
1657 for (const QVariant &valueElement : list) {
1658 if (valueElement.metaType() == elementMetaType) {
1659 propertyMetaSequence.addValueAtEnd(
1660 propertyContainer, valueElement.constData());
1661 } else {
1662 QVariant converted(elementMetaType);
1664 valueElement.metaType(), valueElement.constData(),
1665 elementMetaType, converted.data());
1666 propertyMetaSequence.addValueAtEnd(
1667 propertyContainer, converted.constData());
1668 }
1669 }
1670 ok = true;
1671 } else if (elementMetaType.flags().testFlag(QMetaType::PointerToQObject)) {
1672 const QMetaObject *elementMetaObject = elementMetaType.metaObject();
1673 Q_ASSERT(elementMetaObject);
1674
1675 const auto doAppend = [&](QObject *o) {
1676 QObject *casted = elementMetaObject->cast(o);
1677 propertyMetaSequence.addValueAtEnd(propertyContainer, &casted);
1678 };
1679
1680 if (variantMetaType.flags().testFlag(QMetaType::PointerToQObject)) {
1681 doAppend(*static_cast<QObject *const *>(value.data()));
1682 ok = true;
1683 } else if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
1685 = static_cast<const QQmlListReference *>(value.constData());
1686 Q_ASSERT(elementMetaObject);
1687 for (int i = 0, end = reference->size(); i < end; ++i)
1688 doAppend(reference->at(i));
1689 ok = true;
1690 } else if (!iterateQObjectContainer(
1691 variantMetaType, value.data(), doAppend)) {
1692 doAppend(QQmlMetaType::toQObject(value));
1693 }
1694 } else {
1695 QVariant converted = value;
1696 if (converted.convert(elementMetaType)) {
1697 propertyMetaSequence.addValueAtEnd(propertyContainer, converted.constData());
1698 ok = true;
1699 }
1700 }
1701 }
1702 }
1703 }
1704
1705 if (!ok && QQmlMetaType::isInterface(propertyMetaType)) {
1706 auto valueAsQObject = qvariant_cast<QObject *>(value);
1707
1708 if (void *iface = valueAsQObject
1709 ? valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(propertyMetaType))
1710 : nullptr;
1711 iface) {
1712 // this case can occur when object has an interface type
1713 // and the variant contains a type implementing the interface
1714 return property.writeProperty(object, &iface, flags);
1715 }
1716 }
1717
1718 if (ok) {
1719 return property.writeProperty(object, const_cast<void *>(v.constData()), flags);
1720 } else {
1721 return false;
1722 }
1723 }
1724
1725 return true;
1726}
1727
1729 QObject *object, const QQmlPropertyData &property,
1730 QQmlPropertyData::WriteFlags flags)
1731{
1732 const BindingFixer bindingFixer(object, property, flags);
1733 property.resetProperty(object, flags);
1734 return true;
1735}
1736
1738{
1739 if (metaType.flags() & QMetaType::PointerToQObject) {
1740 if (const QMetaObject *metaObject = metaType.metaObject())
1741 return metaObject;
1742 }
1743 return QQmlMetaType::rawMetaObjectForType(metaType);
1744}
1745
1752{
1753 return QQmlPropertyPrivate::write(*this, value, {});
1754}
1755
1768{
1769 QQmlProperty p(object, name);
1770 return p.write(value);
1771}
1772
1786 const QString &name,
1787 const QVariant &value,
1788 QQmlContext *ctxt)
1789{
1790 QQmlProperty p(object, name, ctxt);
1791 return p.write(value);
1792}
1793
1809{
1810 QQmlProperty p(object, name, engine);
1811 return p.write(value);
1812}
1813
1820{
1821 if (isResettable()) {
1822 void *args[] = { nullptr };
1824 return true;
1825 } else {
1826 return false;
1827 }
1828}
1829
1831 const QVariant &value, QQmlPropertyData::WriteFlags flags)
1832{
1833 if (!that.d)
1834 return false;
1835 if (that.d->object && that.type() & QQmlProperty::Property &&
1836 that.d->core.isValid() && that.isWritable())
1837 return that.d->writeValueProperty(value, flags);
1838 else
1839 return false;
1840}
1841
1846{
1847 if (type() & Property && d->object) {
1848 return d->object->metaObject()->property(d->core.coreIndex()).hasNotifySignal();
1849 }
1850 return false;
1851}
1852
1861{
1862 return type() & Property && !property().isConstant();
1863}
1864
1874{
1875 if (!(type() & Property) || !d->object)
1876 return false;
1877
1878 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex());
1879 if (prop.hasNotifySignal()) {
1881 } else {
1882 return false;
1883 }
1884}
1885
1897bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1898{
1899 if (!(type() & Property) || !d->object)
1900 return false;
1901
1902 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex());
1903 if (prop.hasNotifySignal()) {
1905 return QObject::connect(d->object, signal.constData(), dest, slot);
1906 } else {
1907 return false;
1908 }
1909}
1910
1915{
1916 return d ? d->core.coreIndex() : -1;
1917}
1918
1920{
1921 return that.d ? that.d->encodedIndex() : QQmlPropertyIndex();
1922}
1923
1926 const QQmlPropertyData *valueTypeData,
1927 const QQmlRefPointer<QQmlContextData> &ctxt)
1928{
1929 QQmlProperty prop;
1930
1931 prop.d = new QQmlPropertyPrivate;
1932 prop.d->object = object;
1933 prop.d->context = ctxt;
1934 prop.d->engine = ctxt ? ctxt->engine() : nullptr;
1935
1936 prop.d->core = data;
1937 if (valueTypeData)
1938 prop.d->valueTypeData = *valueTypeData;
1939
1940 return prop;
1941}
1942
1947{
1948 Q_ASSERT(mo);
1949 int methods = mo->methodCount();
1950 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1951 QMetaMethod method = mo->method(ii);
1952
1953 if (method.name() == name && (method.methodType() & QMetaMethod::Signal))
1954 return method;
1955 }
1956
1957 // If no signal is found, but the signal is of the form "onBlahChanged",
1958 // return the notify signal for the property "Blah"
1960 int propIdx = mo->indexOfProperty(propName->constData());
1961 if (propIdx >= 0) {
1962 QMetaProperty prop = mo->property(propIdx);
1963 if (prop.hasNotifySignal())
1964 return prop.notifySignal();
1965 }
1966 }
1967
1968 return QMetaMethod();
1969}
1970
1975{
1976 Q_ASSERT(mo);
1977 const int i = mo->indexOfProperty(name);
1978 return i < 0 ? QMetaProperty() : mo->property(i);
1979}
1980
1986static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
1987{
1988 QQmlData *data = QQmlData::get(object);
1989 if (data && data->propertyCache) {
1990 const QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
1991 : data->propertyCache->method(index);
1992
1993 if (property && property->isVMESignal()) {
1994 QQmlVMEMetaObject *vme;
1995 if (indexInSignalRange)
1996 vme = QQmlVMEMetaObject::getForSignal(const_cast<QObject *>(object), index);
1997 else
1998 vme = QQmlVMEMetaObject::getForMethod(const_cast<QObject *>(object), index);
1999 vme->connectAliasSignal(index, indexInSignalRange);
2000 }
2001 }
2002}
2003
2011bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
2012 const QObject *receiver, int method_index,
2013 int type, int *types)
2014{
2015 static const bool indexInSignalRange = false;
2016 flush_vme_signal(sender, signal_index, indexInSignalRange);
2017 flush_vme_signal(receiver, method_index, indexInSignalRange);
2018
2019 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
2020}
2021
2026void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
2027{
2028 static const bool indexInSignalRange = true;
2029 flush_vme_signal(sender, signal_index, indexInSignalRange);
2030}
2031
2033
2034#include "moc_qqmlproperty.cpp"
static JNINativeMethod methods[]
\inmodule QtCore
Definition qbytearray.h:57
static QJSValue fromReturnedValue(QV4::ReturnedValue d)
Definition qjsvalue_p.h:197
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
T value(qsizetype i) const
Definition qlist.h:664
pointer data()
Definition qlist.h:431
void advanceConstIterator(void *iterator, qsizetype step) const
Advances the const iterator by step steps.
void * constEnd(const void *container) const
Creates and returns a const iterator pointing to the end of container.
bool compareConstIterator(const void *i, const void *j) const
Returns true if the const iterators i and j point to the same value in the container they are iterati...
void destroyConstIterator(const void *iterator) const
Destroys a const iterator previously created using \l constBegin() or \l constEnd().
void * constBegin(const void *container) const
Creates and returns a const iterator pointing to the beginning of container.
bool hasConstIterator() const
Returns true if the underlying container offers a const iterator, false otherwise.
\inmodule QtCore
int keysToValue(const char *keys, bool *ok=nullptr) const
Returns the value derived from combining together the values of the keys using the OR operator,...
int keyToValue(const char *key, bool *ok=nullptr) const
Returns the integer value of the given enumeration key, or -1 if key is not defined.
\inmodule QtCore
Definition qmetaobject.h:19
QByteArray methodSignature() const
\inmodule QtCore
QMetaType metaType() const
QMetaMethod notifySignal() const
bool isWritable() const
Returns true if this property is writable; otherwise returns false.
bool isConstant() const
QMetaEnum enumerator() const
Returns the enumerator if this property's type is an enumerator type; otherwise the returned value is...
int notifySignalIndex() const
bool isEnumType() const
Returns true if the property's type is an enumeration value; otherwise returns false.
bool isValid() const
Returns true if this property is valid (readable); otherwise returns false.
bool isFlagType() const
Returns true if the property's type is an enumeration value that is used as a flag; otherwise returns...
bool hasNotifySignal() const
Returns true if this property has a corresponding change notify signal; otherwise returns false.
\inmodule QtCore
void valueAtConstIterator(const void *iterator, void *result) const
Retrieves the value pointed to by the const iterator and stores it in the memory location pointed to ...
void addValue(void *container, const void *value) const
Adds value to the container if possible.
bool canGetValueAtConstIterator() const
Returns true if the underlying container can retrieve the value pointed to by a const iterator,...
bool canAddValue() const
Returns true if values can be added to the container, false otherwise.
\inmodule QtCore
Definition qmetatype.h:341
static constexpr QMetaType fromType()
Definition qmetatype.h:2642
constexpr TypeFlags flags() const
Definition qmetatype.h:2658
static bool view(QMetaType fromType, void *from, QMetaType toType, void *to)
Creates a mutable view on the object at from of fromType in the preallocated space at to typed toType...
bool isValid() const
int id(int=0) const
Definition qmetatype.h:475
@ PointerToQObject
Definition qmetatype.h:406
constexpr const QMetaObject * metaObject() const
Definition qmetatype.h:2663
static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to)
Converts the object at from from fromType to the preallocated space at to typed toType.
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
static QPropertyBindingPrivate * get(const QUntypedPropertyBinding &binding)
QQmlAbstractBinding * nextBinding() const
void takeExpression(QQmlBoundSignalExpression *)
Sets the signal expression to e.
QQmlBoundSignalExpression * expression() const
Returns the signal expression.
QObject * idValue(int index) const
QQmlRefPointer< QQmlTypeNameCache > imports() const
static QQmlRefPointer< QQmlContextData > get(QQmlContext *context)
QUrl resolvedUrl(const QUrl &) const
QQmlRefPointer< QQmlContextData > parent() const
QQmlEngine * engine() const
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
QQmlEngine * engine() const
Return the context's QQmlEngine, or \nullptr if the context has no QQmlEngine or the QQmlEngine was d...
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
static QQmlEnginePrivate * get(QQmlEngine *e)
QV4::ExecutionEngine * v4engine() const
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
QQmlContext * rootContext() const
Returns the engine's root context.
static QQmlGadgetPtrWrapper * instance(QQmlEngine *engine, QMetaType type)
static QQmlListReference init(const QQmlListProperty< QObject > &, QMetaType)
Definition qqmllist.cpp:25
The QQmlListReference class allows the manipulation of QQmlListProperty properties.
Definition qqmllist.h:183
static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
static QMetaType listValueType(QMetaType type)
static const char * interfaceIId(QMetaType type)
static const QMetaObject * metaObjectForValueType(QMetaType type)
static QObject * toQObject(const QVariant &, bool *ok=nullptr)
static bool isInterface(QMetaType type)
See qmlRegisterInterface() for information about when this will return true.
static QQmlMetaObject rawMetaObjectForType(QMetaType metaType)
static QQmlValueType * valueType(QMetaType metaType)
static QMetaProperty defaultProperty(const QMetaObject *)
static QQmlType qmlType(const QString &qualifiedName, QTypeRevision version)
Returns the type (if any) of URI-qualified named qualifiedName and version specified by version_major...
static bool isValueType(QMetaType type)
const QQmlPropertyData * property(const K &key, QObject *object, const QQmlRefPointer< QQmlContextData > &context) const
void readProperty(QObject *target, void *property) const
bool isResettable() const
void readPropertyWithArgs(QObject *target, void *args[]) const
QMetaType propType() const
void setCoreIndex(int idx)
void setPropType(QMetaType pt)
static Flags flagsForProperty(const QMetaProperty &)
void load(const QMetaProperty &)
QString name(QObject *) const
static QQmlBoundSignalExpression * signalExpression(const QQmlProperty &that)
Returns the expression associated with this signal property, or 0 if no signal expression exists.
static void takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *)
Set the signal expression associated with this signal property to expr.
static bool resolveUrlsOnAssignment()
QMetaType propertyType() const
QQmlPropertyData core
static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags=None, QQmlPropertyData::WriteFlags writeFlags=QQmlPropertyData::DontRemoveBinding)
static void findAliasTarget(QObject *, QQmlPropertyIndex, QObject **, QQmlPropertyIndex *)
static QQmlMetaObject rawMetaObjectForType(QMetaType metaType)
static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *, const QQmlRefPointer< QQmlContextData > &)
QQmlProperty::PropertyTypeCategory propertyTypeCategory() const
static QQmlProperty create(QObject *target, const QString &propertyName, const QQmlRefPointer< QQmlContextData > &context, QQmlPropertyPrivate::InitFlags flags)
static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
QQmlPropertyIndex encodedIndex() const
static void removeBinding(const QQmlProperty &that)
static bool write(QObject *, const QQmlPropertyData &, const QVariant &, const QQmlRefPointer< QQmlContextData > &, QQmlPropertyData::WriteFlags flags={})
static QQmlPropertyIndex propertyIndex(const QQmlProperty &that)
static bool reset(QObject *, const QQmlPropertyData &, QQmlPropertyData::WriteFlags flags={})
static QMetaProperty findPropertyByName(const QMetaObject *mo, const QByteArray &)
Return the property corresponding to name.
static bool connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Connect sender signal_index to receiver method_index with the specified type and types.
QQmlProperty::Type type() const
static void setSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *)
Set the signal expression associated with this signal property to expr.
QQmlPropertyData valueTypeData
static QQmlPropertyPrivate * get(const QQmlProperty &p)
static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &)
Return the signal corresponding to name.
void initDefault(QObject *obj)
Initialize from the default property of obj.
static void flushSignal(const QObject *sender, int signal_index)
QQmlRefPointer< QQmlContextData > effectiveContext() const
static QQmlAbstractBinding * binding(QObject *, QQmlPropertyIndex index)
static QList< QUrl > urlSequence(const QVariant &value)
bool writeValueProperty(const QVariant &, QQmlPropertyData::WriteFlags)
void initProperty(QObject *obj, const QString &name, InitFlags flags=InitFlag::None)
QQmlRefPointer< QQmlContextData > context
static bool resetValueProperty(QObject *, const QQmlPropertyData &, const QQmlPropertyData &valueTypeData, const QQmlRefPointer< QQmlContextData > &, QQmlPropertyData::WriteFlags flags={})
QPointer< QQmlEngine > engine
QPointer< QObject > object
bool isValueType() const
The QQmlProperty class abstracts accessing properties on objects created from QML.
bool isDesignable() const
Returns true if the property is designable, otherwise false.
bool isBindable() const
QMetaType propertyMetaType() const
Returns the metatype of the property.
bool isValid() const
Returns true if the QQmlProperty refers to a valid property, otherwise false.
QMetaMethod method() const
Return the QMetaMethod for this property if it is a SignalProperty, otherwise returns an invalid QMet...
bool hasNotifySignal() const
Returns true if the property has a change notifier signal, otherwise false.
const char * propertyTypeName() const
Returns the type name of the property, or 0 if the property has no type name.
PropertyTypeCategory propertyTypeCategory() const
Returns the property category.
int index() const
Return the Qt metaobject index of the property.
QQmlProperty & operator=(const QQmlProperty &)
Assign other to this QQmlProperty.
QVariant read() const
Returns the property value.
bool operator==(const QQmlProperty &) const
Returns true if other and this QQmlProperty represent the same property.
QQmlProperty()
Create an invalid QQmlProperty.
bool isProperty() const
Returns true if this QQmlProperty represents a regular Qt property.
Type
This enum specifies a type of QML property.
Type type() const
Returns the type of the property.
QMetaProperty property() const
Returns the \l{QMetaProperty} {Qt property} associated with this QML property.
PropertyTypeCategory
This enum specifies a category of QML property.
QML_ANONYMOUSQObject * object
bool write(const QVariant &) const
Sets the property value to value.
bool needsNotifySignal() const
Returns true if the property needs a change notifier signal for bindings to remain upto date,...
bool isSignalProperty() const
Returns true if this QQmlProperty represents a QML signal property.
bool isWritable() const
Returns true if the property is writable, otherwise false.
bool connectNotifySignal(QObject *dest, const char *slot) const
Connects the property's change notifier signal to the specified slot of the dest object and returns t...
bool isResettable() const
Returns true if the property is resettable, otherwise false.
int propertyType() const
Returns the metatype id of the property, or QMetaType::UnknownType if the property has no metatype.
bool reset() const
Resets the property and returns true if the property is resettable.
void addref() const
void release() const
void reset(T *t=nullptr)
static std::optional< QString > changedSignalNameToPropertyName(QStringView changeSignal)
static QString signalNameToHandlerName(QAnyStringView signal)
static std::optional< QString > badHandlerNameToSignalName(QStringView handler)
static std::optional< QString > handlerNameToSignalName(QStringView handler)
The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
static QQmlTypeLoader * get(Engine *engine)
static void list_append(QQmlListProperty< QObject > *prop, QObject *o)
static void list_clear_nosignal(QQmlListProperty< QObject > *prop)
static QQmlVMEMetaObject * getForSignal(QObject *o, int coreIndex)
static void list_clear(QQmlListProperty< QObject > *prop)
static void list_append_nosignal(QQmlListProperty< QObject > *prop, QObject *o)
static QQmlVMEMetaObject * get(QObject *o)
static QQmlVMEMetaObject * getForProperty(QObject *o, int coreIndex)
static QQmlVMEMetaObject * getForMethod(QObject *o, int coreIndex)
static QVariant createValueType(const QJSValue &, QMetaType)
void setEnabled(bool, QQmlPropertyData::WriteFlags) override
The QSequentialIterable class is an iterable interface for a container in a QVariant.
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
Q_CORE_EXPORT QList< QStringView > split(QStringView sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the view into substring views wherever sep occurs, and returns the list of those string views.
Definition qstring.cpp:8249
constexpr QChar at(qsizetype n) const noexcept
Returns the character at position n in this string view.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
\inmodule QtCore
Definition qproperty.h:679
QUntypedPropertyBinding binding() const
Returns the underlying property's binding if there is any, or a default constructed QUntypedPropertyB...
Definition qproperty.h:757
bool isNull() const
Returns true if the QUntypedPropertyBinding is null.
\inmodule QtCore
Definition qurl.h:94
bool isRelative() const
Returns true if the URL is relative; otherwise returns false.
Definition qurl.cpp:2800
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1896
\inmodule QtCore
Definition qvariant.h:65
void * data()
Returns a pointer to the contained object as a generic void* that can be written to.
bool convert(QMetaType type)
Casts the variant to the requested type, targetType.
bool isValid() const
Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns fal...
Definition qvariant.h:714
const char * typeName() const
Returns the name of the type stored in the variant.
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
const void * constData() const
Definition qvariant.h:451
static void writeFlags(QTextStream &stream, const Provider &provider)
Definition ctf.cpp:269
QSet< QString >::iterator it
auto signal
auto mo
[7]
Q_QML_EXPORT QVariant variantFromString(const QString &, QMetaType preferredType, bool *ok=nullptr)
Combined button and popup list for selecting options.
@ DirectConnection
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
#define qWarning
Definition qlogging.h:166
static const QMetaObjectPrivate * priv(const uint *data)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLsizei GLenum GLenum * types
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLint reference
GLenum type
GLenum target
GLbitfield flags
GLuint name
GLuint bindingIndex
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLboolean reset
GLenum func
Definition qopenglext.h:663
GLuint GLfloat * val
GLuint entry
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
QObject * qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
Definition qqml.cpp:114
#define DEFINE_BOOL_CONFIG_OPTION(name, var)
QQmlPrivate::QQmlAttachedPropertiesFunc< QObject > QQmlAttachedPropertiesFunc
Definition qqmlprivate.h:63
bool changeThroughGadgetPtrWrapper(QObject *object, const QQmlPropertyData &core, const QQmlRefPointer< QQmlContextData > &context, QQmlPropertyData::WriteFlags flags, int internalIndex, Op op)
static ConvertAndAssignResult tryConvertAndAssign(QObject *object, const QQmlPropertyData &property, const QVariant &value, QQmlPropertyData::WriteFlags flags, QMetaType propertyMetaType, QMetaType variantMetaType, bool isUrl)
static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPropertyPrivate::BindingFlags flags=QQmlPropertyPrivate::None)
static void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
static void removeValuePropertyBinding(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, QQmlPropertyData::WriteFlags flags)
bool changePropertyAndWriteBack(QObject *object, int coreIndex, QQmlGadgetPtrWrapper *wrapper, QQmlPropertyData::WriteFlags flags, int internalIndex, Op op)
bool iterateQObjectContainer(QMetaType metaType, const void *data, Op op)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
const char property[13]
Definition qwizard.cpp:101
QList< int > list
[14]
obj metaObject() -> className()
QSharedPointer< T > other(t)
[5]
QJSValueList args
QJSEngine engine
[0]
Q_DISABLE_COPY_MOVE(BindingFixer)
BindingFixer(QObject *object, const QQmlPropertyData &property, QQmlPropertyData::WriteFlags flags)
\inmodule QtCore \reentrant
Definition qchar.h:18
static Q_CORE_EXPORT int signalIndex(const QMetaMethod &m)
\inmodule QtCore
static int metacall(QObject *, Call, int, void **)
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition qobject.cpp:3556
QV4::ReturnedValue metaTypeToJS(QMetaType type, const void *data)
static void setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value)
void wrapper()