Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/qtdeclarative/src/qtdeclarative/src/qml/types/qqmlconnections.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /**************************************************************************** | - | ||||||||||||||||||
2 | ** | - | ||||||||||||||||||
3 | ** Copyright (C) 2016 The Qt Company Ltd. | - | ||||||||||||||||||
4 | ** Contact: https://www.qt.io/licensing/ | - | ||||||||||||||||||
5 | ** | - | ||||||||||||||||||
6 | ** This file is part of the QtQml module of the Qt Toolkit. | - | ||||||||||||||||||
7 | ** | - | ||||||||||||||||||
8 | ** $QT_BEGIN_LICENSE:LGPL$ | - | ||||||||||||||||||
9 | ** Commercial License Usage | - | ||||||||||||||||||
10 | ** Licensees holding valid commercial Qt licenses may use this file in | - | ||||||||||||||||||
11 | ** accordance with the commercial license agreement provided with the | - | ||||||||||||||||||
12 | ** Software or, alternatively, in accordance with the terms contained in | - | ||||||||||||||||||
13 | ** a written agreement between you and The Qt Company. For licensing terms | - | ||||||||||||||||||
14 | ** and conditions see https://www.qt.io/terms-conditions. For further | - | ||||||||||||||||||
15 | ** information use the contact form at https://www.qt.io/contact-us. | - | ||||||||||||||||||
16 | ** | - | ||||||||||||||||||
17 | ** GNU Lesser General Public License Usage | - | ||||||||||||||||||
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | - | ||||||||||||||||||
19 | ** General Public License version 3 as published by the Free Software | - | ||||||||||||||||||
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | - | ||||||||||||||||||
21 | ** packaging of this file. Please review the following information to | - | ||||||||||||||||||
22 | ** ensure the GNU Lesser General Public License version 3 requirements | - | ||||||||||||||||||
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | - | ||||||||||||||||||
24 | ** | - | ||||||||||||||||||
25 | ** GNU General Public License Usage | - | ||||||||||||||||||
26 | ** Alternatively, this file may be used under the terms of the GNU | - | ||||||||||||||||||
27 | ** General Public License version 2.0 or (at your option) the GNU General | - | ||||||||||||||||||
28 | ** Public license version 3 or any later version approved by the KDE Free | - | ||||||||||||||||||
29 | ** Qt Foundation. The licenses are as published by the Free Software | - | ||||||||||||||||||
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | - | ||||||||||||||||||
31 | ** included in the packaging of this file. Please review the following | - | ||||||||||||||||||
32 | ** information to ensure the GNU General Public License requirements will | - | ||||||||||||||||||
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | - | ||||||||||||||||||
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | - | ||||||||||||||||||
35 | ** | - | ||||||||||||||||||
36 | ** $QT_END_LICENSE$ | - | ||||||||||||||||||
37 | ** | - | ||||||||||||||||||
38 | ****************************************************************************/ | - | ||||||||||||||||||
39 | - | |||||||||||||||||||
40 | #include "qqmlconnections_p.h" | - | ||||||||||||||||||
41 | - | |||||||||||||||||||
42 | #include <private/qqmlexpression_p.h> | - | ||||||||||||||||||
43 | #include <private/qqmlproperty_p.h> | - | ||||||||||||||||||
44 | #include <private/qqmlboundsignal_p.h> | - | ||||||||||||||||||
45 | #include <qqmlcontext.h> | - | ||||||||||||||||||
46 | #include <private/qqmlcontext_p.h> | - | ||||||||||||||||||
47 | #include <qqmlinfo.h> | - | ||||||||||||||||||
48 | - | |||||||||||||||||||
49 | #include <QtCore/qdebug.h> | - | ||||||||||||||||||
50 | #include <QtCore/qstringlist.h> | - | ||||||||||||||||||
51 | - | |||||||||||||||||||
52 | #include <private/qobject_p.h> | - | ||||||||||||||||||
53 | - | |||||||||||||||||||
54 | QT_BEGIN_NAMESPACE | - | ||||||||||||||||||
55 | - | |||||||||||||||||||
56 | class QQmlConnectionsPrivate : public QObjectPrivate | - | ||||||||||||||||||
57 | { | - | ||||||||||||||||||
58 | public: | - | ||||||||||||||||||
59 | QQmlConnectionsPrivate() : target(nullptr), enabled(true), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {} executed 136 times by 10 tests: end of block Executed by:
| 136 | ||||||||||||||||||
60 | - | |||||||||||||||||||
61 | QList<QQmlBoundSignal*> boundsignals; | - | ||||||||||||||||||
62 | QObject *target; | - | ||||||||||||||||||
63 | - | |||||||||||||||||||
64 | bool enabled; | - | ||||||||||||||||||
65 | bool targetSet; | - | ||||||||||||||||||
66 | bool ignoreUnknownSignals; | - | ||||||||||||||||||
67 | bool componentcomplete; | - | ||||||||||||||||||
68 | - | |||||||||||||||||||
69 | QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; | - | ||||||||||||||||||
70 | QList<const QV4::CompiledData::Binding *> bindings; | - | ||||||||||||||||||
71 | }; | - | ||||||||||||||||||
72 | - | |||||||||||||||||||
73 | /*! | - | ||||||||||||||||||
74 | \qmltype Connections | - | ||||||||||||||||||
75 | \instantiates QQmlConnections | - | ||||||||||||||||||
76 | \inqmlmodule QtQml | - | ||||||||||||||||||
77 | \ingroup qtquick-interceptors | - | ||||||||||||||||||
78 | \brief Describes generalized connections to signals. | - | ||||||||||||||||||
79 | - | |||||||||||||||||||
80 | A Connections object creates a connection to a QML signal. | - | ||||||||||||||||||
81 | - | |||||||||||||||||||
82 | When connecting to signals in QML, the usual way is to create an | - | ||||||||||||||||||
83 | "on<Signal>" handler that reacts when a signal is received, like this: | - | ||||||||||||||||||
84 | - | |||||||||||||||||||
85 | \qml | - | ||||||||||||||||||
86 | MouseArea { | - | ||||||||||||||||||
87 | onClicked: { foo(parameters) } | - | ||||||||||||||||||
88 | } | - | ||||||||||||||||||
89 | \endqml | - | ||||||||||||||||||
90 | - | |||||||||||||||||||
91 | However, it is not possible to connect to a signal in this way in some | - | ||||||||||||||||||
92 | cases, such as when: | - | ||||||||||||||||||
93 | - | |||||||||||||||||||
94 | \list | - | ||||||||||||||||||
95 | \li Multiple connections to the same signal are required | - | ||||||||||||||||||
96 | \li Creating connections outside the scope of the signal sender | - | ||||||||||||||||||
97 | \li Connecting to targets not defined in QML | - | ||||||||||||||||||
98 | \endlist | - | ||||||||||||||||||
99 | - | |||||||||||||||||||
100 | When any of these are needed, the Connections type can be used instead. | - | ||||||||||||||||||
101 | - | |||||||||||||||||||
102 | For example, the above code can be changed to use a Connections object, | - | ||||||||||||||||||
103 | like this: | - | ||||||||||||||||||
104 | - | |||||||||||||||||||
105 | \qml | - | ||||||||||||||||||
106 | MouseArea { | - | ||||||||||||||||||
107 | Connections { | - | ||||||||||||||||||
108 | onClicked: foo(parameters) | - | ||||||||||||||||||
109 | } | - | ||||||||||||||||||
110 | } | - | ||||||||||||||||||
111 | \endqml | - | ||||||||||||||||||
112 | - | |||||||||||||||||||
113 | More generally, the Connections object can be a child of some object other than | - | ||||||||||||||||||
114 | the sender of the signal: | - | ||||||||||||||||||
115 | - | |||||||||||||||||||
116 | \qml | - | ||||||||||||||||||
117 | MouseArea { | - | ||||||||||||||||||
118 | id: area | - | ||||||||||||||||||
119 | } | - | ||||||||||||||||||
120 | // ... | - | ||||||||||||||||||
121 | \endqml | - | ||||||||||||||||||
122 | \qml | - | ||||||||||||||||||
123 | Connections { | - | ||||||||||||||||||
124 | target: area | - | ||||||||||||||||||
125 | onClicked: foo(parameters) | - | ||||||||||||||||||
126 | } | - | ||||||||||||||||||
127 | \endqml | - | ||||||||||||||||||
128 | - | |||||||||||||||||||
129 | \sa {Qt QML} | - | ||||||||||||||||||
130 | */ | - | ||||||||||||||||||
131 | QQmlConnections::QQmlConnections(QObject *parent) : | - | ||||||||||||||||||
132 | QObject(*(new QQmlConnectionsPrivate), parent) | - | ||||||||||||||||||
133 | { | - | ||||||||||||||||||
134 | } executed 136 times by 10 tests: end of block Executed by:
| 136 | ||||||||||||||||||
135 | - | |||||||||||||||||||
136 | QQmlConnections::~QQmlConnections() | - | ||||||||||||||||||
137 | { | - | ||||||||||||||||||
138 | } | - | ||||||||||||||||||
139 | - | |||||||||||||||||||
140 | /*! | - | ||||||||||||||||||
141 | \qmlproperty Object QtQml::Connections::target | - | ||||||||||||||||||
142 | This property holds the object that sends the signal. | - | ||||||||||||||||||
143 | - | |||||||||||||||||||
144 | If this property is not set, the \c target defaults to the parent of the Connection. | - | ||||||||||||||||||
145 | - | |||||||||||||||||||
146 | If set to null, no connection is made and any signal handlers are ignored | - | ||||||||||||||||||
147 | until the target is not null. | - | ||||||||||||||||||
148 | */ | - | ||||||||||||||||||
149 | QObject *QQmlConnections::target() const | - | ||||||||||||||||||
150 | { | - | ||||||||||||||||||
151 | Q_D(const QQmlConnections); | - | ||||||||||||||||||
152 | return d->targetSet ? d->target : parent(); executed 266 times by 9 tests: return d->targetSet ? d->target : parent(); Executed by:
| 266 | ||||||||||||||||||
153 | } | - | ||||||||||||||||||
154 | - | |||||||||||||||||||
155 | class QQmlBoundSignalDeleter : public QObject | - | ||||||||||||||||||
156 | { | - | ||||||||||||||||||
157 | public: | - | ||||||||||||||||||
158 | QQmlBoundSignalDeleter(QQmlBoundSignal *signal) : m_signal(signal) { m_signal->removeFromObject(); } executed 2 times by 1 test: end of block Executed by:
| 2 | ||||||||||||||||||
159 | ~QQmlBoundSignalDeleter() { delete m_signal; } executed 2 times by 1 test: end of block Executed by:
| 2 | ||||||||||||||||||
160 | - | |||||||||||||||||||
161 | private: | - | ||||||||||||||||||
162 | QQmlBoundSignal *m_signal; | - | ||||||||||||||||||
163 | }; | - | ||||||||||||||||||
164 | - | |||||||||||||||||||
165 | void QQmlConnections::setTarget(QObject *obj) | - | ||||||||||||||||||
166 | { | - | ||||||||||||||||||
167 | Q_D(QQmlConnections); | - | ||||||||||||||||||
168 | if (d->targetSet && d->target == obj)
| 0-122 | ||||||||||||||||||
169 | return; never executed: return; | 0 | ||||||||||||||||||
170 | d->targetSet = true; // even if setting to 0, it is *set* | - | ||||||||||||||||||
171 | for (QQmlBoundSignal *s : qAsConst(d->boundsignals)) { | - | ||||||||||||||||||
172 | // It is possible that target is being changed due to one of our signal | - | ||||||||||||||||||
173 | // handlers -> use deleteLater(). | - | ||||||||||||||||||
174 | if (s->isNotifying())
| 2 | ||||||||||||||||||
175 | (new QQmlBoundSignalDeleter(s))->deleteLater(); executed 2 times by 1 test: (new QQmlBoundSignalDeleter(s))->deleteLater(); Executed by:
| 2 | ||||||||||||||||||
176 | else | - | ||||||||||||||||||
177 | delete s; executed 2 times by 1 test: delete s; Executed by:
| 2 | ||||||||||||||||||
178 | } | - | ||||||||||||||||||
179 | d->boundsignals.clear(); | - | ||||||||||||||||||
180 | d->target = obj; | - | ||||||||||||||||||
181 | connectSignals(); | - | ||||||||||||||||||
182 | emit targetChanged(); | - | ||||||||||||||||||
183 | } executed 128 times by 9 tests: end of block Executed by:
| 128 | ||||||||||||||||||
184 | - | |||||||||||||||||||
185 | /*! | - | ||||||||||||||||||
186 | \qmlproperty bool QtQml::Connections::enabled | - | ||||||||||||||||||
187 | \since 5.7 | - | ||||||||||||||||||
188 | - | |||||||||||||||||||
189 | This property holds whether the item accepts change events. | - | ||||||||||||||||||
190 | - | |||||||||||||||||||
191 | By default, this property is \c true. | - | ||||||||||||||||||
192 | */ | - | ||||||||||||||||||
193 | bool QQmlConnections::isEnabled() const | - | ||||||||||||||||||
194 | { | - | ||||||||||||||||||
195 | Q_D(const QQmlConnections); | - | ||||||||||||||||||
196 | return d->enabled; never executed: return d->enabled; | 0 | ||||||||||||||||||
197 | } | - | ||||||||||||||||||
198 | - | |||||||||||||||||||
199 | void QQmlConnections::setEnabled(bool enabled) | - | ||||||||||||||||||
200 | { | - | ||||||||||||||||||
201 | Q_D(QQmlConnections); | - | ||||||||||||||||||
202 | if (d->enabled == enabled)
| 0-6 | ||||||||||||||||||
203 | return; never executed: return; | 0 | ||||||||||||||||||
204 | - | |||||||||||||||||||
205 | d->enabled = enabled; | - | ||||||||||||||||||
206 | - | |||||||||||||||||||
207 | for (QQmlBoundSignal *s : qAsConst(d->boundsignals)) | - | ||||||||||||||||||
208 | s->setEnabled(d->enabled); executed 4 times by 1 test: s->setEnabled(d->enabled); Executed by:
| 4 | ||||||||||||||||||
209 | - | |||||||||||||||||||
210 | emit enabledChanged(); | - | ||||||||||||||||||
211 | } executed 6 times by 1 test: end of block Executed by:
| 6 | ||||||||||||||||||
212 | - | |||||||||||||||||||
213 | /*! | - | ||||||||||||||||||
214 | \qmlproperty bool QtQml::Connections::ignoreUnknownSignals | - | ||||||||||||||||||
215 | - | |||||||||||||||||||
216 | Normally, a connection to a non-existent signal produces runtime errors. | - | ||||||||||||||||||
217 | - | |||||||||||||||||||
218 | If this property is set to \c true, such errors are ignored. | - | ||||||||||||||||||
219 | This is useful if you intend to connect to different types of objects, handling | - | ||||||||||||||||||
220 | a different set of signals for each object. | - | ||||||||||||||||||
221 | */ | - | ||||||||||||||||||
222 | bool QQmlConnections::ignoreUnknownSignals() const | - | ||||||||||||||||||
223 | { | - | ||||||||||||||||||
224 | Q_D(const QQmlConnections); | - | ||||||||||||||||||
225 | return d->ignoreUnknownSignals; executed 2 times by 1 test: return d->ignoreUnknownSignals; Executed by:
| 2 | ||||||||||||||||||
226 | } | - | ||||||||||||||||||
227 | - | |||||||||||||||||||
228 | void QQmlConnections::setIgnoreUnknownSignals(bool ignore) | - | ||||||||||||||||||
229 | { | - | ||||||||||||||||||
230 | Q_D(QQmlConnections); | - | ||||||||||||||||||
231 | d->ignoreUnknownSignals = ignore; | - | ||||||||||||||||||
232 | } executed 4 times by 1 test: end of block Executed by:
| 4 | ||||||||||||||||||
233 | - | |||||||||||||||||||
234 | void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) | - | ||||||||||||||||||
235 | { | - | ||||||||||||||||||
236 | for (int ii = 0; ii < props.count(); ++ii) {
| 130-146 | ||||||||||||||||||
237 | const QV4::CompiledData::Binding *binding = props.at(ii); | - | ||||||||||||||||||
238 | const QString &propName = qmlUnit->stringAt(binding->propertyNameIndex); | - | ||||||||||||||||||
239 | - | |||||||||||||||||||
240 | if (!propName.startsWith(QLatin1String("on")) || (propName.length() < 3 || !propName.at(2).isUpper())) {
| 2-144 | ||||||||||||||||||
241 | error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName)); | - | ||||||||||||||||||
242 | return; executed 6 times by 1 test: return; Executed by:
| 6 | ||||||||||||||||||
243 | } | - | ||||||||||||||||||
244 | - | |||||||||||||||||||
245 | if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
| 4-136 | ||||||||||||||||||
246 | const QV4::CompiledData::Object *target = qmlUnit->objectAt(binding->value.objectIndex); | - | ||||||||||||||||||
247 | if (!qmlUnit->stringAt(target->inheritedTypeNameIndex).isEmpty())
| 2 | ||||||||||||||||||
248 | error(binding, QQmlConnections::tr("Connections: nested objects not allowed")); executed 2 times by 1 test: error(binding, QQmlConnections::tr("Connections: nested objects not allowed")); Executed by:
| 2 | ||||||||||||||||||
249 | else | - | ||||||||||||||||||
250 | error(binding, QQmlConnections::tr("Connections: syntax error")); executed 2 times by 1 test: error(binding, QQmlConnections::tr("Connections: syntax error")); Executed by:
| 2 | ||||||||||||||||||
251 | return; executed 4 times by 1 test: return; Executed by:
| 4 | ||||||||||||||||||
252 | } if (binding->type != QV4::CompiledData::Binding::Type_Script) {
| 0-136 | ||||||||||||||||||
253 | error(binding, QQmlConnections::tr("Connections: script expected")); | - | ||||||||||||||||||
254 | return; never executed: return; | 0 | ||||||||||||||||||
255 | } | - | ||||||||||||||||||
256 | } executed 136 times by 9 tests: end of block Executed by:
| 136 | ||||||||||||||||||
257 | } executed 130 times by 9 tests: end of block Executed by:
| 130 | ||||||||||||||||||
258 | - | |||||||||||||||||||
259 | void QQmlConnectionsParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) | - | ||||||||||||||||||
260 | { | - | ||||||||||||||||||
261 | QQmlConnectionsPrivate *p = | - | ||||||||||||||||||
262 | static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object)); | - | ||||||||||||||||||
263 | p->compilationUnit = compilationUnit; | - | ||||||||||||||||||
264 | p->bindings = bindings; | - | ||||||||||||||||||
265 | } executed 132 times by 9 tests: end of block Executed by:
| 132 | ||||||||||||||||||
266 | - | |||||||||||||||||||
267 | void QQmlConnections::connectSignals() | - | ||||||||||||||||||
268 | { | - | ||||||||||||||||||
269 | Q_D(QQmlConnections); | - | ||||||||||||||||||
270 | if (!d->componentcomplete || (d->targetSet && !target()))
| 8-144 | ||||||||||||||||||
271 | return; executed 128 times by 9 tests: return; Executed by:
| 128 | ||||||||||||||||||
272 | - | |||||||||||||||||||
273 | if (d->bindings.isEmpty())
| 4-132 | ||||||||||||||||||
274 | return; executed 4 times by 2 tests: return; Executed by:
| 4 | ||||||||||||||||||
275 | QObject *target = this->target(); | - | ||||||||||||||||||
276 | QQmlData *ddata = QQmlData::get(this); | - | ||||||||||||||||||
277 | QQmlContextData *ctxtdata = ddata ? ddata->outerContext : nullptr;
| 0-132 | ||||||||||||||||||
278 | - | |||||||||||||||||||
279 | const QV4::CompiledData::Unit *qmlUnit = d->compilationUnit->data; | - | ||||||||||||||||||
280 | for (const QV4::CompiledData::Binding *binding : qAsConst(d->bindings)) { | - | ||||||||||||||||||
281 | Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); | - | ||||||||||||||||||
282 | QString propName = qmlUnit->stringAt(binding->propertyNameIndex); | - | ||||||||||||||||||
283 | - | |||||||||||||||||||
284 | QQmlProperty prop(target, propName); | - | ||||||||||||||||||
285 | if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
| 0-130 | ||||||||||||||||||
286 | int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex(); | - | ||||||||||||||||||
287 | QQmlBoundSignal *signal = | - | ||||||||||||||||||
288 | new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this)); | - | ||||||||||||||||||
289 | signal->setEnabled(d->enabled); | - | ||||||||||||||||||
290 | - | |||||||||||||||||||
291 | auto f = d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; | - | ||||||||||||||||||
292 | QQmlBoundSignalExpression *expression = | - | ||||||||||||||||||
293 | ctxtdata ? new QQmlBoundSignalExpression(target, signalIndex, ctxtdata, this, f)
| 0-130 | ||||||||||||||||||
294 | : nullptr; | - | ||||||||||||||||||
295 | signal->takeExpression(expression); | - | ||||||||||||||||||
296 | d->boundsignals += signal; | - | ||||||||||||||||||
297 | } else { executed 130 times by 9 tests: end of block Executed by:
| 130 | ||||||||||||||||||
298 | if (!d->ignoreUnknownSignals)
| 4 | ||||||||||||||||||
299 | qmlWarning(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName); executed 4 times by 1 test: qmlWarning(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName); Executed by:
| 4 | ||||||||||||||||||
300 | } executed 8 times by 1 test: end of block Executed by:
| 8 | ||||||||||||||||||
301 | } | - | ||||||||||||||||||
302 | } executed 132 times by 9 tests: end of block Executed by:
| 132 | ||||||||||||||||||
303 | - | |||||||||||||||||||
304 | void QQmlConnections::classBegin() | - | ||||||||||||||||||
305 | { | - | ||||||||||||||||||
306 | Q_D(QQmlConnections); | - | ||||||||||||||||||
307 | d->componentcomplete=false; | - | ||||||||||||||||||
308 | } executed 136 times by 10 tests: end of block Executed by:
| 136 | ||||||||||||||||||
309 | - | |||||||||||||||||||
310 | void QQmlConnections::componentComplete() | - | ||||||||||||||||||
311 | { | - | ||||||||||||||||||
312 | Q_D(QQmlConnections); | - | ||||||||||||||||||
313 | d->componentcomplete=true; | - | ||||||||||||||||||
314 | connectSignals(); | - | ||||||||||||||||||
315 | } executed 136 times by 10 tests: end of block Executed by:
| 136 | ||||||||||||||||||
316 | - | |||||||||||||||||||
317 | QT_END_NAMESPACE | - | ||||||||||||||||||
318 | - | |||||||||||||||||||
319 | #include "moc_qqmlconnections_p.cpp" | - | ||||||||||||||||||
Source code | Switch to Preprocessed file |