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
qqmlboundsignal.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 "qqmlboundsignal_p.h"
5
6#include <private/qmetaobject_p.h>
7#include <private/qmetaobjectbuilder_p.h>
8#include "qqmlengine_p.h"
9#include "qqmlglobal_p.h"
10#include <private/qqmlprofiler_p.h>
11#include <private/qqmldebugconnector_p.h>
12#include <private/qqmldebugserviceinterfaces_p.h>
13#include "qqmlinfo.h"
14
15#include <private/qjsvalue_p.h>
16#include <private/qv4value_p.h>
17#include <private/qv4jscall_p.h>
18#include <private/qv4qobjectwrapper_p.h>
19#include <private/qv4qmlcontext_p.h>
20
21#include <QtCore/qdebug.h>
22
23#include <qtqml_tracepoints_p.h>
24
26
27Q_TRACE_POINT(qtqml, QQmlHandlingSignal_entry, const QQmlEngine *engine, const QString &function,
28 const QString &fileName, int line, int column)
29Q_TRACE_POINT(qtqml, QQmlHandlingSignal_exit)
30
31QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope,
32 const QString &expression, const QString &fileName, quint16 line, quint16 column,
33 const QString &handlerName, const QString &parameterString)
35 m_index(index),
36 m_target(target)
37{
38 init(ctxt, scope);
39
41
43
44 // Add some leading whitespace to account for the binding's column offset.
45 // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted.
46 function += QString(qMax(column, (quint16)2) - 2, QChar(QChar::Space))
47 + QLatin1String("(function ") + handlerName + QLatin1Char('(');
48
49 if (parameterString.isEmpty()) {
51 //TODO: look at using the property cache here (as in the compiler)
52 // for further optimization
53 QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
54 function += QQmlPropertyCache::signalParameterStringForJS(v4, signal.parameterNames(), &error);
55
56 if (!error.isEmpty()) {
57 qmlWarning(scopeObject()) << error;
58 return;
59 }
60 } else
61 function += parameterString;
62
63 function += QLatin1String(") { ") + expression + QLatin1String(" })");
64 QV4::Scope valueScope(v4);
66 valueScope, evalFunction(context(), scopeObject(), function, fileName, line));
67 QV4::ScopedContext context(valueScope, f->scope());
68 setupFunction(context, f->function());
69}
70
71QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt,
72 QObject *scopeObject, QV4::Function *function, QV4::ExecutionContext *scope)
74 m_index(index),
75 m_target(target)
76{
77 // It's important to call init first, because m_index gets remapped in case of cloned signals.
78 init(ctxt, scopeObject);
80 QV4::ExecutionEngine *engine = ctxt->engine()->handle();
81
82 if (!function->isClosureWrapper()) {
83 QList<QByteArray> signalParameters = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).parameterNames();
84 if (!signalParameters.isEmpty()) {
87 if (!error.isEmpty()) {
89 return;
90 }
91 function->updateInternalClass(engine, signalParameters);
92 }
93 }
94
95 QV4::Scope valueScope(engine);
97 if (!qmlContext)
99 if (auto closure = function->nestedFunction()) {
100 // If the function is marked as having a nested function, then the user wrote:
101 // onSomeSignal: function() { /*....*/ }
102 // So take that nested function:
103 setupFunction(qmlContext, closure);
104 } else {
105 setupFunction(qmlContext, function);
106
107 // If it's a closure wrapper but we cannot directly access the nested function
108 // we need to run the outer function to get the nested one.
109 if (function->isClosureWrapper()) {
110 bool isUndefined = false;
112 valueScope, QQmlJavaScriptExpression::evaluate(&isUndefined));
113
114 Q_ASSERT(!isUndefined);
115 Q_ASSERT(result->function());
116 Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
117
118 QV4::Scoped<QV4::ExecutionContext> callContext(valueScope, result->scope());
119 setupFunction(callContext, result->function());
120 }
121 }
122}
123
124void QQmlBoundSignalExpression::init(const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope)
125{
127 setContext(ctxt);
128 setScopeObject(scope);
129
130 Q_ASSERT(m_target && m_index > -1);
131 m_index = QQmlPropertyCache::originalClone(m_target, m_index);
132}
133
137
143
145{
146 // bound signals do not notify on change.
147}
148
150{
151 if (expressionFunctionValid())
152 return QStringLiteral("function() { [native code] }");
153 return QString();
154}
155
156// Parts of this function mirror code in QQmlExpressionPrivate::value() and v4Value().
157// Changes made here may need to be made there and vice versa.
159{
160 if (!expressionFunctionValid())
161 return;
162
163 QQmlEngine *qmlengine = engine();
164
165 // If there is no engine, we have no way to evaluate anything.
166 // This can happen on destruction.
167 if (!qmlengine)
168 return;
169
171 QV4::ExecutionEngine *v4 = qmlengine->handle();
172 QV4::Scope scope(v4);
173
174 ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
175
176 if (a) {
177 //TODO: lookup via signal index rather than method index as an optimization
178 const QMetaObject *targetMeta = m_target->metaObject();
179 const QMetaMethod metaMethod = targetMeta->method(
180 QMetaObjectPrivate::signal(targetMeta, m_index).methodIndex());
181
182 int argCount = metaMethod.parameterCount();
184 storage.reserve(argCount + 1);
185 storage.append(QMetaType()); // We're not interested in the return value
186 for (int i = 0; i < argCount; ++i) {
187 const QMetaType type = metaMethod.parameterMetaType(i);
188 if (!type.isValid())
189 argCount = 0;
190 else if (type.flags().testFlag(QMetaType::IsEnumeration))
191 storage.append(type.underlyingType());
192 else
193 storage.append(type);
194 }
195
196 QQmlJavaScriptExpression::evaluate(a, storage.constData(), argCount);
197 } else {
198 void *ignoredResult = nullptr;
199 QMetaType invalidType;
200 QQmlJavaScriptExpression::evaluate(&ignoredResult, &invalidType, 0);
201 }
202
203 ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
204}
205
207
208
216 m_prevSignal(nullptr), m_nextSignal(nullptr),
217 m_enabled(true)
218{
219 addToObject(owner);
220
221 /*
222 If this is a cloned method, connect to the 'original'. For example,
223 for the signal 'void aSignal(int parameter = 0)', if the method
224 index refers to 'aSignal()', get the index of 'aSignal(int)'.
225 This ensures that 'parameter' will be available from QML.
226 */
229}
230
235
236void QQmlBoundSignal::addToObject(QObject *obj)
237{
238 Q_ASSERT(!m_prevSignal);
239 Q_ASSERT(obj);
240
241 QQmlData *data = QQmlData::get(obj, true);
242
243 m_nextSignal = data->signalHandlers;
244 if (m_nextSignal) m_nextSignal->m_prevSignal = &m_nextSignal;
245 m_prevSignal = &data->signalHandlers;
246 data->signalHandlers = this;
247}
248
250{
251 if (m_prevSignal) {
252 *m_prevSignal = m_nextSignal;
253 if (m_nextSignal) m_nextSignal->m_prevSignal = m_prevSignal;
254 m_prevSignal = nullptr;
255 m_nextSignal = nullptr;
256 }
257}
258
263{
264 return m_expression.data();
265}
266
273{
274 m_expression.adopt(e);
275 if (m_expression)
276 m_expression->setNotifyOnValueChanged(false);
277}
278
287{
288 if (m_enabled == enabled)
289 return;
290
291 m_enabled = enabled;
292}
293
295{
296 QQmlBoundSignal *s = static_cast<QQmlBoundSignal*>(e);
297
298 if (!s->m_expression || !s->m_enabled)
299 return;
300
301 QV4DebugService *service = QQmlDebugConnector::service<QV4DebugService>();
302 if (service)
303 service->signalEmitted(QString::fromUtf8(QMetaObjectPrivate::signal(
304 s->m_expression->target()->metaObject(),
305 s->signalIndex()).methodSignature()));
306
308 if (s->m_expression && (engine = s->m_expression->engine())) {
309 Q_TRACE_SCOPE(QQmlHandlingSignal, engine,
310 s->m_expression->function() ? s->m_expression->function()->name()->toQString() : QString(),
311 s->m_expression->sourceLocation().sourceFile, s->m_expression->sourceLocation().line,
312 s->m_expression->sourceLocation().column);
314 s->m_expression.data());
315 s->m_expression->evaluate(a);
316 if (s->m_expression && s->m_expression->hasError()) {
317 QQmlEnginePrivate::warning(engine, s->m_expression->error(engine));
318 }
319 }
320}
321
323
326 auto This = static_cast<QQmlPropertyObserver*>(self);
327 This->expression->evaluate(nullptr);
328 })
329{
330 expression.adopt(expr);
331}
332
\inmodule QtCore
QV4::ExecutionEngine * handle() const
Definition qjsengine.h:298
\inmodule QtCore
Definition qmetaobject.h:19
int parameterCount() const
QMetaType parameterMetaType(int index) const
\inmodule QtCore
Definition qmetatype.h:341
@ IsEnumeration
Definition qmetatype.h:407
\inmodule QtCore
Definition qobject.h:103
QString expressionIdentifier() const override
QQmlBoundSignalExpression(const QObject *target, int index, const QQmlRefPointer< QQmlContextData > &ctxt, QObject *scope, const QString &expression, const QString &fileName, quint16 line, quint16 column, const QString &handlerName=QString(), const QString &parameterString=QString())
void setEnabled(bool enabled)
This property holds whether the item will emit signals.
void takeExpression(QQmlBoundSignalExpression *)
Sets the signal expression to e.
QQmlBoundSignalExpression * expression() const
Returns the signal expression.
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
void warning(const QQmlError &)
static QQmlEnginePrivate * get(QQmlEngine *e)
void referenceScarceResources()
void dereferenceScarceResources()
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
QQmlContext * rootContext() const
Returns the engine's root context.
void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f)
QV4::ReturnedValue evaluate(bool *isUndefined)
void setContext(const QQmlRefPointer< QQmlContextData > &context)
virtual QQmlSourceLocation sourceLocation() const
QVarLengthArray< QMetaType, Prealloc > ArgTypeStorage
void connect(QObject *source, int sourceSignal, QQmlEngine *engine, bool doNotify=true)
static QString signalParameterStringForJS(QV4::ExecutionEngine *engine, const QList< QByteArray > &parameterNameList, QString *errorString=nullptr)
int originalClone(int index) const
QQmlPropertyObserver(QQmlBoundSignalExpression *expr)
T * data() const
QQmlRefPointer< T > & adopt(T *)
Takes ownership of other.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
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
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
auto signal
Combined button and popup list for selecting options.
Scoped< ExecutionContext > ScopedContext
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLfloat GLfloat f
GLenum type
GLenum target
GLenum GLenum GLsizei void GLsizei void * column
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLuint64EXT * result
[6]
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a)
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
unsigned short quint16
Definition qtypes.h:48
#define enabled
QStorageInfo storage
[1]
QObject::connect nullptr
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
static Q_CORE_EXPORT QMetaMethod signal(const QMetaObject *m, int signal_index)
\inmodule QtCore
static Heap::QmlContext * create(QV4::ExecutionContext *parent, QQmlRefPointer< QQmlContextData > context, QObject *scopeObject)