Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmlconnections.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 "qqmlconnections_p.h"
5
6#include <private/qqmlexpression_p.h>
7#include <private/qqmlproperty_p.h>
8#include <private/qqmlboundsignal_p.h>
9#include <qqmlcontext.h>
10#include <private/qqmlcontext_p.h>
11#include <private/qqmlvmemetaobject_p.h>
12#include <qqmlinfo.h>
13
14#include <QtCore/qloggingcategory.h>
15#include <QtCore/qdebug.h>
16#include <QtCore/qstringlist.h>
17
18#include <private/qobject_p.h>
19
21
22Q_LOGGING_CATEGORY(lcQmlConnections, "qt.qml.connections")
23
25{
26public:
29
30 bool enabled = true;
31 bool targetSet = false;
32 bool ignoreUnknownSignals = false;
33 bool componentcomplete = true;
34
37};
38
105{
106}
107
118{
119 Q_D(const QQmlConnections);
120 return d->targetSet ? d->target.data() : parent();
121}
122
124{
125public:
127 ~QQmlBoundSignalDeleter() { delete m_signal; }
128
129private:
130 QQmlBoundSignal *m_signal;
131};
132
134{
135 Q_D(QQmlConnections);
136 if (d->targetSet && d->target == obj)
137 return;
138 d->targetSet = true; // even if setting to 0, it is *set*
139 for (QQmlBoundSignal *s : std::as_const(d->boundsignals)) {
140 // It is possible that target is being changed due to one of our signal
141 // handlers -> use deleteLater().
142 if (s->isNotifying())
144 else
145 delete s;
146 }
147 d->boundsignals.clear();
148 d->target = obj;
149 connectSignals();
151}
152
162{
163 Q_D(const QQmlConnections);
164 return d->enabled;
165}
166
168{
169 Q_D(QQmlConnections);
170 if (d->enabled == enabled)
171 return;
172
173 d->enabled = enabled;
174
175 for (QQmlBoundSignal *s : std::as_const(d->boundsignals))
176 s->setEnabled(d->enabled);
177
178 emit enabledChanged();
179}
180
191{
192 Q_D(const QQmlConnections);
193 return d->ignoreUnknownSignals;
194}
195
197{
198 Q_D(QQmlConnections);
199 d->ignoreUnknownSignals = ignore;
200}
201
203{
204 for (int ii = 0; ii < props.size(); ++ii) {
205 const QV4::CompiledData::Binding *binding = props.at(ii);
206 const QString &propName = compilationUnit->stringAt(binding->propertyNameIndex);
207
208 const bool thirdCharacterIsValid = (propName.size() >= 2)
209 && (propName.at(2).isUpper() || propName.at(2) == u'_');
210 if (!propName.startsWith(QLatin1String("on")) || !thirdCharacterIsValid) {
211 error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
212 return;
213 }
214
216 continue;
217
219 const QV4::CompiledData::Object *target = compilationUnit->objectAt(binding->value.objectIndex);
220 if (!compilationUnit->stringAt(target->inheritedTypeNameIndex).isEmpty())
221 error(binding, QQmlConnections::tr("Connections: nested objects not allowed"));
222 else
223 error(binding, QQmlConnections::tr("Connections: syntax error"));
224 return;
225 }
226
227 error(binding, QQmlConnections::tr("Connections: script expected"));
228 return;
229 }
230}
231
233{
235 static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object));
236 p->compilationUnit = compilationUnit;
237 p->bindings = bindings;
238}
239
240void QQmlConnections::connectSignals()
241{
242 Q_D(QQmlConnections);
243 if (!d->componentcomplete || (d->targetSet && !target()))
244 return;
245
246 if (d->bindings.isEmpty()) {
247 connectSignalsToMethods();
248 } else {
249 if (lcQmlConnections().isWarningEnabled()) {
250 qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. "
251 "Use this syntax instead: function onFoo(<arguments>) { ... }");
252 }
253 connectSignalsToBindings();
254 }
255}
256
257void QQmlConnections::connectSignalsToMethods()
258{
259 Q_D(QQmlConnections);
260
261 QObject *target = this->target();
262 QQmlData *ddata = QQmlData::get(this);
263 if (!ddata)
264 return;
265
267
269 for (int i = ddata->propertyCache->methodOffset(),
270 end = ddata->propertyCache->methodOffset() + ddata->propertyCache->methodCount();
271 i < end;
272 ++i) {
273
274 const QQmlPropertyData *handler = ddata->propertyCache->method(i);
275 if (!handler || !handler->isVMEFunction())
276 continue;
277
278 const QString propName = handler->name(this);
279
280 QQmlProperty prop(target, propName);
281 if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
283 auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
284 signal->setEnabled(d->enabled);
285
286 QV4::Scope scope(engine);
287 QV4::ScopedContext global(scope, engine->rootContext());
288
289 QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(this);
290 Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
291
292 QV4::ScopedFunctionObject method(scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
293
294 QQmlBoundSignalExpression *expression =
295 ctxtdata ? new QQmlBoundSignalExpression(
296 target, signalIndex, ctxtdata, this,
298 : nullptr;
299
300 signal->takeExpression(expression);
301 d->boundsignals += signal;
302 } else if (!d->ignoreUnknownSignals
303 && propName.startsWith(QLatin1String("on")) && propName.size() > 2
304 && propName.at(2).isUpper()) {
305 qmlWarning(this) << tr("Detected function \"%1\" in Connections element. "
306 "This is probably intended to be a signal handler but no "
307 "signal of the target matches the name.").arg(propName);
308 }
309 }
310}
311
312// TODO: Drop this as soon as we can
313void QQmlConnections::connectSignalsToBindings()
314{
315 Q_D(QQmlConnections);
316 QObject *target = this->target();
317 QQmlData *ddata = QQmlData::get(this);
318 QQmlRefPointer<QQmlContextData> ctxtdata = ddata ? ddata->outerContext : nullptr;
319
320 for (const QV4::CompiledData::Binding *binding : std::as_const(d->bindings)) {
322 QString propName = d->compilationUnit->stringAt(binding->propertyNameIndex);
323
324 QQmlProperty prop(target, propName);
325 if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
328 new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
329 signal->setEnabled(d->enabled);
330
331 auto f = d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
332 QQmlBoundSignalExpression *expression =
333 ctxtdata ? new QQmlBoundSignalExpression(target, signalIndex, ctxtdata, this, f)
334 : nullptr;
335 signal->takeExpression(expression);
336 d->boundsignals += signal;
337 } else {
338 if (!d->ignoreUnknownSignals)
339 qmlWarning(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName);
340 }
341 }
342}
343
345{
346 Q_D(QQmlConnections);
347 d->componentcomplete=false;
348}
349
351{
352 Q_D(QQmlConnections);
353 d->componentcomplete=true;
354 connectSignals();
355}
356
358
359#include "moc_qqmlconnections_p.cpp"
constexpr bool isUpper() const noexcept
Returns true if the character is an uppercase letter, for example category() is Letter_Uppercase.
Definition qchar.h:475
QV4::ExecutionEngine * handle() const
Definition qjsengine.h:292
Definition qlist.h:74
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
QQmlBoundSignalDeleter(QQmlBoundSignal *signal)
void applyBindings(QObject *object, const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, const QList< const QV4::CompiledData::Binding * > &bindings) override
void verifyBindings(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, const QList< const QV4::CompiledData::Binding * > &props) override
QList< QQmlBoundSignal * > boundsignals
QQmlRefPointer< QV4::ExecutableCompilationUnit > compilationUnit
QList< const QV4::CompiledData::Binding * > bindings
QQmlGuard< QObject > target
bool isEnabled() const
\qmlproperty bool QtQml::Connections::enabled
void setEnabled(bool enabled)
void setTarget(QObject *)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void setIgnoreUnknownSignals(bool ignore)
void targetChanged()
void classBegin() override
Invoked after class creation, but before any properties have been set.
QQmlConnections(QObject *parent=nullptr)
QQmlEngine * engine() const
QQmlPropertyCache::ConstPtr propertyCache
Definition qqmldata_p.h:195
QQmlContextData * context
Definition qqmldata_p.h:147
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
QQmlContextData * outerContext
Definition qqmldata_p.h:149
bool isVMEFunction() const
QString name(QObject *) const
static QQmlPropertyPrivate * get(const QQmlProperty &p)
The QQmlProperty class abstracts accessing properties on objects created from QML.
QV4::ReturnedValue vmeMethod(int index) const
static QQmlVMEMetaObject * get(QObject *o)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
auto signalIndex
auto signal
Combined button and popup list for selecting options.
DBusConnection const char DBusError * error
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
#define Q_LOGGING_CATEGORY(name,...)
GLuint GLuint end
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLfloat GLfloat f
GLenum target
GLenum GLuint GLsizei const GLenum * props
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:76
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define tr(X)
#define emit
QObject::connect nullptr
QJSValue global
QJSEngine engine
[0]
union QV4::CompiledData::Binding::@543 value
Function * function() const
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent