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
qqmlabstractbinding.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
5
6#include <QtQml/qqmlinfo.h>
7#include <private/qqmlbinding_p.h>
8#include <private/qqmlvaluetypeproxybinding_p.h>
9#include <private/qqmlvmemetaobject_p.h>
10
12
14 : m_targetIndex(-1)
15{
17}
18
27
37{
39 Q_ASSERT(isAddedToObject() == false);
40
43
45
46 int coreIndex = targetPropertyIndex().coreIndex();
47 if (targetPropertyIndex().hasValueTypeIndex()) {
48 // Value type
49
50 // Find the value type proxy (if there is one)
52 if (data->hasBindingBit(coreIndex)) {
53 QQmlAbstractBinding *b = data->bindings;
54 while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
55 b->targetPropertyIndex().hasValueTypeIndex()))
56 b = b->nextBinding();
58 proxy = static_cast<QQmlValueTypeProxyBinding *>(b);
59 }
60
61 if (!proxy) {
63
64 Q_ASSERT(proxy->targetPropertyIndex().coreIndex() == coreIndex);
65 Q_ASSERT(!proxy->targetPropertyIndex().hasValueTypeIndex());
66 Q_ASSERT(proxy->targetObject() == obj);
67
68 proxy->addToObject();
69 }
70
71 setNextBinding(proxy->m_bindings.data());
72 proxy->m_bindings = this;
73
74 } else {
75 setNextBinding(data->bindings);
76 if (data->bindings) {
77 data->bindings->ref.deref();
78 Q_ASSERT(data->bindings->ref.refCount > 0);
79 }
80 data->bindings = this;
81 ref.ref();
82
83 data->setBindingBit(obj, coreIndex);
84 }
85
86 setAddedToObject(true);
87}
88
93{
94 if (!isAddedToObject())
95 return;
96
97 setAddedToObject(false);
98
100 QQmlData *data = QQmlData::get(obj, false);
101 Q_ASSERT(data);
102
104 next = nextBinding();
105 setNextBinding(nullptr);
106
107 int coreIndex = targetPropertyIndex().coreIndex();
108 if (targetPropertyIndex().hasValueTypeIndex()) {
109
110 // Find the value type binding
111 QQmlAbstractBinding *vtbinding = data->bindings;
112 Q_ASSERT(vtbinding);
113 while (vtbinding->targetPropertyIndex().coreIndex() != coreIndex
114 || vtbinding->targetPropertyIndex().hasValueTypeIndex()) {
115 vtbinding = vtbinding->nextBinding();
116 Q_ASSERT(vtbinding);
117 }
118 Q_ASSERT(vtbinding->kind() == QQmlAbstractBinding::ValueTypeProxy);
119
120 QQmlValueTypeProxyBinding *vtproxybinding =
121 static_cast<QQmlValueTypeProxyBinding *>(vtbinding);
122
123 QQmlAbstractBinding *binding = vtproxybinding->m_bindings.data();
124 if (binding == this) {
125 vtproxybinding->m_bindings = next;
126 } else {
127 while (binding->nextBinding() != this) {
128 binding = binding->nextBinding();
129 Q_ASSERT(binding);
130 }
131 binding->setNextBinding(next.data());
132 }
133
134 // Value type - we don't remove the proxy from the object. It will sit their happily
135 // doing nothing until it is removed by a write, a binding change or it is reused
136 // to hold more sub-bindings.
137 return;
138 }
139
140 if (data->bindings == this) {
141 if (next.data())
142 next->ref.ref();
143 data->bindings = next.data();
144 if (!ref.deref())
145 delete this;
146 } else {
147 QQmlAbstractBinding *binding = data->bindings;
148 while (binding->nextBinding() != this) {
149 binding = binding->nextBinding();
150 Q_ASSERT(binding);
151 }
152 binding->setNextBinding(next.data());
153 }
154
155 data->clearBindingBit(coreIndex);
156}
157
159{
160 qmlWarning(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name());
161}
162
164 const QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
165{
166 Q_ASSERT(propertyData);
167
169 Q_ASSERT(data);
170
171 if (Q_UNLIKELY(!data->propertyCache))
172 data->propertyCache = QQmlMetaType::propertyCache(m_target->metaObject());
173
174 *propertyData = data->propertyCache->property(m_targetIndex.coreIndex());
175 Q_ASSERT(*propertyData);
176
177 if (Q_UNLIKELY(m_targetIndex.hasValueTypeIndex() && valueTypeData)) {
178 const QMetaObject *valueTypeMetaObject
179 = QQmlMetaType::metaObjectForValueType((*propertyData)->propType());
180 Q_ASSERT(valueTypeMetaObject);
181 QMetaProperty vtProp = valueTypeMetaObject->property(m_targetIndex.valueTypeIndex());
182 valueTypeData->setFlags(QQmlPropertyData::flagsForProperty(vtProp));
183 valueTypeData->setPropType(vtProp.metaType());
184 valueTypeData->setCoreIndex(m_targetIndex.valueTypeIndex());
185 }
186}
187
189{
190 setCanUseAccessor(true); // Always use accessors, except when:
191 if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
192 if (!m_targetIndex.isValid() || interceptorMetaObject->intercepts(m_targetIndex))
193 setCanUseAccessor(false);
194 }
195}
196
198{
199 auto pd = QQmlPropertyPrivate::get(prop);
200 setTarget(prop.object(), pd->core, &pd->valueTypeData);
201}
202
204 QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
205{
206 return setTarget(object, core.coreIndex(), core.isAlias(),
207 valueType ? valueType->coreIndex() : -1);
208}
209
210static const QQmlPropertyData *getObjectPropertyData(QObject *object, int coreIndex)
211{
212 QQmlData *data = QQmlData::get(object, true);
213 if (!data)
214 return nullptr;
215
216 if (!data->propertyCache) {
217 data->propertyCache = QQmlMetaType::propertyCache(object);
218 if (!data->propertyCache)
219 return nullptr;
220 }
221
222 const QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
223 Q_ASSERT(propertyData);
224 return propertyData;
225}
226
228 QObject *object, int coreIndex, bool coreIsAlias, int valueTypeIndex)
229{
230 auto invalidate = [this]() {
231 m_target = nullptr;
233 return false;
234 };
235
236 if (!object)
237 return invalidate();
238
240
241 for (bool isAlias = coreIsAlias; isAlias;) {
243
244 int aValueTypeIndex;
245 if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
246 // can't resolve id (yet)
247 return invalidate();
248 }
249
250 const QQmlPropertyData *propertyData = getObjectPropertyData(object, coreIndex);
251 if (!propertyData)
252 return invalidate();
253
254 if (aValueTypeIndex != -1) {
255 if (propertyData->propType().flags().testFlag(QMetaType::PointerToQObject)) {
256 // deep alias
257 propertyData->readProperty(object, &object);
258 coreIndex = aValueTypeIndex;
259 valueTypeIndex = -1;
260 propertyData = getObjectPropertyData(object, coreIndex);
261 if (!propertyData)
262 return invalidate();
263 } else {
264 valueTypeIndex = aValueTypeIndex;
265 }
266 }
267
269 isAlias = propertyData->isAlias();
270 coreIndex = propertyData->coreIndex();
271 }
272 m_targetIndex = QQmlPropertyIndex(coreIndex, valueTypeIndex);
273
275 if (!data->propertyCache)
276 data->propertyCache = QQmlMetaType::propertyCache(m_target->metaObject());
277
278 return true;
279}
280
281
283{
284 return QLatin1String("<Unknown>");
285}
286
\inmodule QtCore
constexpr TypeFlags flags() const
Definition qmetatype.h:2658
@ PointerToQObject
Definition qmetatype.h:406
\inmodule QtCore
Definition qobject.h:103
QQmlPropertyIndex targetPropertyIndex() const
QTaggedPointer< QQmlAbstractBinding, NextBindingTags > m_nextBinding
void setCanUseAccessor(bool canUseAccessor)
QQmlPropertyIndex m_targetIndex
static void printBindingLoopError(const QQmlProperty &prop)
friend class QQmlValueTypeProxyBinding
void setNextBinding(QQmlAbstractBinding *)
void removeFromObject()
Remove the binding from the object.
QQmlAbstractBinding * nextBinding() const
QTaggedPointer< QObject, TargetTags > m_target
QObject * targetObject() const
void addToObject()
Add this binding to object.
void setTarget(const QQmlProperty &)
void getPropertyData(const QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
virtual QString expression() const
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
static QQmlInterceptorMetaObject * get(QObject *obj)
static const QMetaObject * metaObjectForValueType(QMetaType type)
static QQmlPropertyCache::ConstPtr propertyCache(QObject *object, QTypeRevision version=QTypeRevision())
Returns a QQmlPropertyCache for obj if one is available.
void readProperty(QObject *target, void *property) const
QMetaType propType() const
void setCoreIndex(int idx)
void setPropType(QMetaType pt)
static Flags flagsForProperty(const QMetaProperty &)
bool hasValueTypeIndex() const
static QQmlPropertyPrivate * get(const QQmlProperty &p)
The QQmlProperty class abstracts accessing properties on objects created from QML.
QML_ANONYMOUSQObject * object
static QQmlVMEMetaObject * getForProperty(QObject *o, int coreIndex)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8870
T * data() const noexcept
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
#define Q_UNLIKELY(x)
GLboolean GLboolean GLboolean b
GLuint object
[3]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint ref
GLhandleARB obj
[2]
static const QQmlPropertyData * getObjectPropertyData(QObject *object, int coreIndex)
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
QNetworkProxy proxy
[0]
\inmodule QtCore