Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlpropertytopropertybinding.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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// Qt-Security score:significant
4
6
7#include <private/qqmlanybinding_p.h>
8#include <private/qqmlengine_p.h>
9#include <private/qqmlvmemetaobject_p.h>
10#include <private/qv4alloca_p.h>
11
12#include <QtQml/qqmlinfo.h>
13
15
16/*!
17 * \internal
18 * \class QQmlPropertyToPropertyBinding
19 *
20 * This class can be used to create a direct binding from a source property to
21 * a target property, without going through QQmlJavaScriptExpression and
22 * QV4::Function. In particular you don't need a compilation unit or byte code
23 * to set this up.
24 *
25 * \note The target cannot be a group property, but the source can.
26 */
27
28QQmlAnyBinding QQmlPropertyToPropertyBinding::create(
29 QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target)
30{
31 QQmlAnyBinding result;
32 if (target.isBindable() && !QQmlPropertyPrivate::get(target)->isValueType()) {
33 if (source.isBindable()) {
34 result = QUntypedPropertyBinding(new QQmlBindableToBindablePropertyBinding(
35 engine, source, target));
36 return result;
37 }
38
39 result = QUntypedPropertyBinding(new QQmlUnbindableToBindablePropertyBinding(
40 engine, source, target));
41 return result;
42 }
43
44 if (source.isBindable()) {
45 result = new QQmlBindableToUnbindablePropertyBinding(engine, source, target);
46 return result;
47 }
48
49 result = new QQmlUnbindableToUnbindablePropertyBinding(engine, source, target);
50 return result;
51}
52
53QQmlPropertyToPropertyBinding::QQmlPropertyToPropertyBinding(
54 QQmlEngine *engine, const QQmlProperty &source)
55 : engine(engine)
56 , sourceObject(source.object())
57 , sourcePropertyIndex(QQmlPropertyPrivate::get(source)->encodedIndex())
58{
59}
60
62 QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target)
64 , QQmlPropertyToUnbindablePropertyBinding(engine, source, target)
65{
66}
67
69{
70 return PropertyToPropertyBinding;
71}
72
74 bool e, QQmlPropertyData::WriteFlags flags)
75{
76 const bool wasEnabled = enabledFlag();
77 setEnabledFlag(e);
78 updateCanUseAccessor();
79 if (e && !wasEnabled)
80 update(flags);
81}
82
83void QQmlPropertyToUnbindablePropertyBinding::update(QQmlPropertyData::WriteFlags flags)
84{
85 if (!enabledFlag())
86 return;
87
88 // Check that the target has not been deleted
89 QObject *target = targetObject();
90 if (QQmlData::wasDeleted(target))
91 return;
92
93 const QQmlPropertyData *d = nullptr;
94 QQmlPropertyData vtd;
95 getPropertyData(&d, &vtd);
96 Q_ASSERT(d);
97
98 // Check for a binding update loop
99 if (Q_UNLIKELY(updatingFlag()))
100 return;
101
102 setUpdatingFlag(true);
103
104 if (canUseAccessor())
105 flags.setFlag(QQmlPropertyData::BypassInterceptor);
106
107 QVariant value = m_binding.readSourceValue(
108 [&](const QMetaObject *sourceMetaObject, const QMetaProperty &property) {
109 captureProperty(sourceMetaObject, property);
110 });
111
112 QQmlPropertyPrivate::writeValueProperty(target, *d, vtd, value, {}, flags);
113 setUpdatingFlag(false);
114}
115
117 QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target)
119{
120 setTarget(target);
121}
122
124 QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target)
126 , QQmlPropertyToUnbindablePropertyBinding(engine, source, target)
127{
128}
129
131 QPropertyObserver *observer, QUntypedPropertyData *)
132{
133 static_cast<QQmlBindableToUnbindablePropertyBinding *>(observer)
134 ->QQmlPropertyToUnbindablePropertyBinding::update();
135}
136
138 const QMetaObject *sourceMetaObject, const QMetaProperty &sourceProperty)
139{
140 Q_UNUSED(sourceMetaObject);
141 m_binding.doConnectNotify(this, sourceProperty);
142}
143
145 const QMetaObject *sourceMetaObject, const QMetaProperty &sourceProperty)
146{
147 Q_UNUSED(sourceProperty);
148
149 // We have already captured.
150 if (m_isObserving)
151 return;
152
153 QUntypedBindable bindable;
154 void *argv[] = { &bindable };
155 sourceMetaObject->metacall(
156 m_binding.sourceObject, QMetaObject::BindableProperty,
157 m_binding.sourcePropertyIndex.coreIndex(), argv);
158 bindable.observe(this);
159 m_isObserving = true;
160}
161
162namespace QtPrivate {
163template<typename Binding>
164inline constexpr BindingFunctionVTable
167 [](void *qpropertyBinding) { delete reinterpret_cast<Binding *>(qpropertyBinding); },
168 [](void *, void *){},
169 0
170 };
171}
172
174 QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target,
175 const QtPrivate::BindingFunctionVTable *vtable)
179{
180}
181
191
193{
194 PendingBindingObserverList bindingObservers;
195 evaluateRecursive(bindingObservers);
196
197 if (const QPropertyBindingError error = bindingError();
198 Q_UNLIKELY(error.type() == QPropertyBindingError::BindingLoop)) {
199 return;
200 }
201
202 notifyNonRecursive(bindingObservers);
203}
204
213
214void QQmlUnbindableToUnbindableGuard_callback(QQmlNotifierEndpoint *e, void **)
215{
216 static_cast<QQmlUnbindableToUnbindablePropertyBinding *>(e)->update();
217}
218
219void QQmlUnbindableToBindableGuard_callback(QQmlNotifierEndpoint *e, void **)
220{
222}
223
224QT_END_NAMESPACE
QQmlBindableToBindablePropertyBinding(QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target)
void captureProperty(const QMetaObject *sourceMetaObject, const QMetaProperty &sourceProperty) final
QQmlBindableToUnbindablePropertyBinding(QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target)
QQmlPropertyToBindablePropertyBinding(QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target, const QtPrivate::BindingFunctionVTable *vtable)
void setEnabled(bool e, QQmlPropertyData::WriteFlags flags) final
QQmlPropertyToUnbindablePropertyBinding(QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target)
void update(QQmlPropertyData::WriteFlags flags=QQmlPropertyData::DontRemoveBinding)
QQmlUnbindableToBindablePropertyBinding(QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target)
QQmlUnbindableToUnbindablePropertyBinding(QQmlEngine *engine, const QQmlProperty &source, const QQmlProperty &target)
void captureProperty(const QMetaObject *sourceMetaObject, const QMetaProperty &sourceProperty) final
Combined button and popup list for selecting options.
constexpr BindingFunctionVTable bindingFunctionVTableForQQmlPropertyToBindablePropertyBinding
void QQmlUnbindableToBindableGuard_callback(QQmlNotifierEndpoint *e, void **)
void QQmlUnbindableToUnbindableGuard_callback(QQmlNotifierEndpoint *e, void **)