1// Copyright (C) 2021 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 "qqmlcppbinding_p.h"
5
6#include <QtQml/qqmlengine.h>
7#include <QtQml/qqmlcontext.h>
8#include <QtCore/qmetaobject.h>
9
10#include <private/qqmltypedata_p.h>
11#include <private/qqmlpropertybinding_p.h>
12#include <private/qqmlbinding_p.h>
13#include <private/qv4qmlcontext_p.h>
14#include <private/qqmlproperty_p.h>
15#include <private/qqmlbinding_p.h>
16
17QT_BEGIN_NAMESPACE
18
19template<typename CreateBinding>
20inline decltype(auto) createBindingInScope(QObject *thisObject, CreateBinding create)
21{
22 QQmlEngine *qmlengine = qmlEngine(thisObject);
23 Q_ASSERT(qmlengine);
24 QV4::ExecutionEngine *v4 = qmlengine->handle();
25 Q_ASSERT(v4);
26
27 QQmlData *ddata = QQmlData::get(object: thisObject);
28 Q_ASSERT(ddata && ddata->outerContext);
29 QQmlRefPointer<QQmlContextData> ctxtdata = QQmlRefPointer<QQmlContextData>(ddata->outerContext);
30
31 QV4::Scope scope(v4);
32 QV4::ExecutionContext *executionCtx = v4->scriptContext();
33 QV4::Scoped<QV4::QmlContext> qmlContext(
34 scope, QV4::QmlContext::create(parent: executionCtx, context: ctxtdata, scopeObject: thisObject));
35
36 return create(ctxtdata, qmlContext);
37}
38
39QUntypedPropertyBinding
40QQmlCppBinding::createBindingForBindable(const QV4::ExecutableCompilationUnit *unit,
41 QObject *thisObject, qsizetype functionIndex,
42 QObject *bindingTarget, int metaPropertyIndex,
43 int valueTypePropertyIndex, const QString &propertyName)
44{
45 Q_UNUSED(propertyName);
46
47 QV4::Function *v4Function = unit->runtimeFunctions.value(i: functionIndex, defaultValue: nullptr);
48 if (!v4Function) {
49 // TODO: align with existing logging of such
50 qCritical() << "invalid JavaScript function index (internal error)";
51 return QUntypedPropertyBinding();
52 }
53 if (metaPropertyIndex < 0) {
54 // TODO: align with existing logging of such
55 qCritical() << "invalid meta property index (internal error)";
56 return QUntypedPropertyBinding();
57 }
58
59 const QMetaObject *mo = bindingTarget->metaObject();
60 Q_ASSERT(mo);
61 QMetaProperty property = mo->property(index: metaPropertyIndex);
62 Q_ASSERT(valueTypePropertyIndex == -1 || QString::fromUtf8(property.name()) == propertyName);
63
64 return createBindingInScope(
65 thisObject,
66 create: [&](const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope) {
67 auto index = QQmlPropertyIndex(property.propertyIndex(), valueTypePropertyIndex);
68 return QQmlPropertyBinding::create(propertyType: property.metaType(), function: v4Function, obj: thisObject,
69 ctxt, scope, target: bindingTarget, targetIndex: index);
70 });
71}
72
73void QQmlCppBinding::createBindingForNonBindable(const QV4::ExecutableCompilationUnit *unit,
74 QObject *thisObject, qsizetype functionIndex,
75 QObject *bindingTarget, int metaPropertyIndex,
76 int valueTypePropertyIndex,
77 const QString &propertyName)
78{
79 Q_UNUSED(propertyName);
80
81 QV4::Function *v4Function = unit->runtimeFunctions.value(i: functionIndex, defaultValue: nullptr);
82 if (!v4Function) {
83 // TODO: align with existing logging of such
84 qCritical() << "invalid JavaScript function index (internal error)";
85 return;
86 }
87 if (metaPropertyIndex < 0) {
88 // TODO: align with existing logging of such
89 qCritical() << "invalid meta property index (internal error)";
90 return;
91 }
92
93 const QMetaObject *mo = bindingTarget->metaObject();
94 Q_ASSERT(mo);
95 QMetaProperty property = mo->property(index: metaPropertyIndex);
96 Q_ASSERT(valueTypePropertyIndex != -1 || QString::fromUtf8(property.name()) == propertyName);
97
98 createBindingInScope(
99 thisObject,
100 create: [&](const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope) -> void {
101 QQmlBinding *binding = QQmlBinding::create(propertyType: property.metaType(), function: v4Function,
102 obj: thisObject, ctxt, scope);
103 // almost as in qv4objectwrapper.cpp:535
104 Q_ASSERT(!property.isAlias()); // we convert aliases to (almost) real properties
105 binding->setTarget(bindingTarget, coreIndex: property.propertyIndex(), coreIsAlias: false,
106 valueTypeIndex: valueTypePropertyIndex);
107 QQmlPropertyPrivate::setBinding(binding);
108 });
109}
110
111QUntypedPropertyBinding QQmlCppBinding::createTranslationBindingForBindable(
112 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, QObject *bindingTarget,
113 int metaPropertyIndex, const QQmlTranslation &translationData, const QString &propertyName)
114{
115 Q_UNUSED(propertyName);
116
117 if (metaPropertyIndex < 0) {
118 // TODO: align with existing logging of such
119 qCritical() << "invalid meta property index (internal error)";
120 return QUntypedPropertyBinding();
121 }
122
123 const QMetaObject *mo = bindingTarget->metaObject();
124 Q_ASSERT(mo);
125 QMetaProperty property = mo->property(index: metaPropertyIndex);
126 Q_ASSERT(QString::fromUtf8(property.name()) == propertyName);
127
128 return QQmlTranslationPropertyBinding::create(pd: property.metaType(), compilationUnit: unit, translationData);
129}
130
131void QQmlCppBinding::createTranslationBindingForNonBindable(
132 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
133 const QQmlSourceLocation &location, const QQmlTranslation &translationData,
134 QObject *thisObject, QObject *bindingTarget, int metaPropertyIndex,
135 const QString &propertyName, int valueTypePropertyIndex)
136{
137 Q_UNUSED(propertyName);
138
139 if (metaPropertyIndex < 0) {
140 // TODO: align with existing logging of such
141 qCritical() << "invalid meta property index (internal error)";
142 return;
143 }
144
145 const QMetaObject *mo = bindingTarget->metaObject();
146 Q_ASSERT(mo);
147 QMetaProperty property = mo->property(index: metaPropertyIndex);
148 Q_ASSERT(QString::fromUtf8(property.name()) == propertyName);
149
150 createBindingInScope(
151 thisObject,
152 create: [&](const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *) -> void {
153 QQmlBinding *binding = QQmlBinding::createTranslationBinding(
154 unit, ctxt, propertyName, translationData, location, obj: thisObject);
155 // almost as in qv4objectwrapper.cpp:535
156 Q_ASSERT(!property.isAlias()); // we convert aliases to (almost) real properties
157 binding->setTarget(bindingTarget, coreIndex: property.propertyIndex(), coreIsAlias: false,
158 valueTypeIndex: valueTypePropertyIndex);
159 QQmlPropertyPrivate::setBinding(binding);
160 });
161}
162
163QT_END_NAMESPACE
164

source code of qtdeclarative/src/qml/qmltc/supportlibrary/qqmlcppbinding.cpp