1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertytopropertybinding_p.h"
#include <private/qqmlvmemetaobject_p.h>
QT_BEGIN_NAMESPACE
/*!
* \internal
* \class QQmlPropertyToPropertyBinding
*
* This class can be used to create a direct binding from a source property to
* a target property, without going through QQmlJavaScriptExpression and
* QV4::Function. In particular you don't need a compilation unit or byte code
* to set this up.
*/
QQmlPropertyToPropertyBinding::QQmlPropertyToPropertyBinding(
QQmlEngine *engine, QObject *sourceObject, int sourcePropertyIndex,
QObject *targetObject, int targetPropertyIndex)
: QQmlNotifierEndpoint(QQmlPropertyGuard)
, m_engine(engine)
, m_sourceObject(sourceObject)
, m_sourcePropertyIndex(sourcePropertyIndex)
{
setTarget(targetObject, targetPropertyIndex, false, -1);
}
QQmlAbstractBinding::Kind QQmlPropertyToPropertyBinding::kind() const
{
return PropertyToPropertyBinding;
}
void QQmlPropertyToPropertyBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
{
const bool wasEnabled = enabledFlag();
setEnabledFlag(e);
updateCanUseAccessor();
if (e && !wasEnabled)
update(flags);
}
void QQmlPropertyToPropertyBinding::captureProperty(
const QMetaObject *sourceMetaObject, int notifyIndex,
bool isSourceBindable, bool isTargetBindable)
{
if (isSourceBindable) {
// if the property is a QPropery, and we're binding to a QProperty
// the automatic capturing process already takes care of everything
if (isTargetBindable)
return;
// We have already captured.
if (observer)
return;
observer = std::make_unique<Observer>(this);
QUntypedBindable bindable;
void *argv[] = { &bindable };
sourceMetaObject->metacall(
m_sourceObject, QMetaObject::BindableProperty, m_sourcePropertyIndex, argv);
bindable.observe(observer.get());
return;
}
// We cannot capture non-bindable properties without signals
if (notifyIndex == -1)
return;
if (isConnected(m_sourceObject, notifyIndex))
cancelNotify();
else
connect(m_sourceObject, notifyIndex, m_engine, true);
}
void QQmlPropertyToPropertyBinding::update(QQmlPropertyData::WriteFlags flags)
{
if (!enabledFlag())
return;
// Check that the target has not been deleted
QObject *target = targetObject();
if (QQmlData::wasDeleted(target))
return;
const QQmlPropertyData *d = nullptr;
QQmlPropertyData vtd;
getPropertyData(&d, &vtd);
Q_ASSERT(d);
// Check for a binding update loop
if (Q_UNLIKELY(updatingFlag())) {
QQmlAbstractBinding::printBindingLoopError(
QQmlPropertyPrivate::restore(target, *d, &vtd, nullptr));
return;
}
setUpdatingFlag(true);
if (canUseAccessor())
flags.setFlag(QQmlPropertyData::BypassInterceptor);
const QMetaObject *sourceMetaObject = m_sourceObject->metaObject();
const QMetaProperty property = sourceMetaObject->property(m_sourcePropertyIndex);
if (!property.isConstant()) {
captureProperty(sourceMetaObject, QMetaObjectPrivate::signalIndex(property.notifySignal()),
property.isBindable(), !vtd.isValid() && d->isBindable());
}
QQmlPropertyPrivate::writeValueProperty(
target, *d, vtd, property.read(m_sourceObject), {}, flags);
setUpdatingFlag(false);
}
void QQmlPropertyGuard_callback(QQmlNotifierEndpoint *e, void **)
{
static_cast<QQmlPropertyToPropertyBinding *>(e)->update();
}
void QQmlPropertyToPropertyBinding::Observer::trigger(
QPropertyObserver *observer, QUntypedPropertyData *)
{
static_cast<Observer *>(observer)->binding->update();
}
QT_END_NAMESPACE
|