1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativeconnections_p.h"
44 #include <private/qdeclarativeexpression_p.h>
45 #include <private/qdeclarativeproperty_p.h>
46 #include <private/qdeclarativeboundsignal_p.h>
47 #include <qdeclarativecontext.h>
48 #include <private/qdeclarativecontext_p.h>
49 #include <qdeclarativeinfo.h>
51 #include <QtCore/qdebug.h>
52 #include <QtCore/qstringlist.h>
54 #include <private/qobject_p.h>
58 class QDeclarativeConnectionsPrivate : public QObjectPrivate
61 QDeclarativeConnectionsPrivate() : target(0), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
63 QList<QDeclarativeBoundSignal*> boundsignals;
67 bool ignoreUnknownSignals;
68 bool componentcomplete;
74 \qmlclass Connections QDeclarativeConnections
75 \inqmlmodule QtQuick 2
76 \ingroup qml-utility-elements
77 \brief A Connections element describes generalized connections to signals.
79 A Connections object creates a connection to a QML signal.
81 When connecting to signals in QML, the usual way is to create an
82 "on<Signal>" handler that reacts when a signal is received, like this:
86 onClicked: { foo(parameters) }
90 However, it is not possible to connect to a signal in this way in some
94 \i Multiple connections to the same signal are required
95 \i Creating connections outside the scope of the signal sender
96 \i Connecting to targets not defined in QML
99 When any of these are needed, the Connections element can be used instead.
101 For example, the above code can be changed to use a Connections object,
107 onClicked: foo(parameters)
112 More generally, the Connections object can be a child of some object other than
113 the sender of the signal:
124 onClicked: foo(parameters)
130 QDeclarativeConnections::QDeclarativeConnections(QObject *parent) :
131 QObject(*(new QDeclarativeConnectionsPrivate), parent)
135 QDeclarativeConnections::~QDeclarativeConnections()
140 \qmlproperty Object QtQuick2::Connections::target
141 This property holds the object that sends the signal.
143 If this property is not set, the \c target defaults to the parent of the Connection.
145 If set to null, no connection is made and any signal handlers are ignored
146 until the target is not null.
148 QObject *QDeclarativeConnections::target() const
150 Q_D(const QDeclarativeConnections);
151 return d->targetSet ? d->target : parent();
154 void QDeclarativeConnections::setTarget(QObject *obj)
156 Q_D(QDeclarativeConnections);
157 d->targetSet = true; // even if setting to 0, it is *set*
158 if (d->target == obj)
160 foreach (QDeclarativeBoundSignal *s, d->boundsignals) {
161 // It is possible that target is being changed due to one of our signal
162 // handlers -> use deleteLater().
163 if (s->isEvaluating())
168 d->boundsignals.clear();
171 emit targetChanged();
175 \qmlproperty bool QtQuick2::Connections::ignoreUnknownSignals
177 Normally, a connection to a non-existent signal produces runtime errors.
179 If this property is set to \c true, such errors are ignored.
180 This is useful if you intend to connect to different types of objects, handling
181 a different set of signals for each object.
183 bool QDeclarativeConnections::ignoreUnknownSignals() const
185 Q_D(const QDeclarativeConnections);
186 return d->ignoreUnknownSignals;
189 void QDeclarativeConnections::setIgnoreUnknownSignals(bool ignore)
191 Q_D(QDeclarativeConnections);
192 d->ignoreUnknownSignals = ignore;
198 QDeclarativeConnectionsParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
201 QDataStream ds(&rv, QIODevice::WriteOnly);
203 for(int ii = 0; ii < props.count(); ++ii)
205 QString propName = props.at(ii).name();
206 int propLine = props.at(ii).location().line;
207 int propColumn = props.at(ii).location().column;
209 if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
210 error(props.at(ii), QDeclarativeConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
214 QList<QVariant> values = props.at(ii).assignedValues();
216 for (int i = 0; i < values.count(); ++i) {
217 const QVariant &value = values.at(i);
219 if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
220 error(props.at(ii), QDeclarativeConnections::tr("Connections: nested objects not allowed"));
222 } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
223 error(props.at(ii), QDeclarativeConnections::tr("Connections: syntax error"));
226 QDeclarativeScript::Variant v = qvariant_cast<QDeclarativeScript::Variant>(value);
229 ds << rewriteSignalHandler(v.asScript(), propName);
233 error(props.at(ii), QDeclarativeConnections::tr("Connections: script expected"));
243 void QDeclarativeConnectionsParser::setCustomData(QObject *object,
244 const QByteArray &data)
246 QDeclarativeConnectionsPrivate *p =
247 static_cast<QDeclarativeConnectionsPrivate *>(QObjectPrivate::get(object));
252 void QDeclarativeConnections::connectSignals()
254 Q_D(QDeclarativeConnections);
255 if (!d->componentcomplete || (d->targetSet && !target()))
258 QDataStream ds(d->data);
259 while (!ds.atEnd()) {
269 QDeclarativeProperty prop(target(), propName);
270 if (prop.isValid() && (prop.type() & QDeclarativeProperty::SignalProperty)) {
271 QDeclarativeBoundSignal *signal =
272 new QDeclarativeBoundSignal(target(), prop.method(), this);
275 QDeclarativeContextData *ctxtdata = 0;
276 QDeclarativeData *ddata = QDeclarativeData::get(this);
278 ctxtdata = ddata->outerContext;
279 if (ctxtdata && !ctxtdata->url.isEmpty())
280 location = ddata->outerContext->url.toString();
283 QDeclarativeExpression *expression = ctxtdata ?
284 QDeclarativeExpressionPrivate::create(ctxtdata, 0, script, true, location, line, column) : 0;
285 signal->setExpression(expression);
286 d->boundsignals += signal;
288 if (!d->ignoreUnknownSignals)
289 qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName);
294 void QDeclarativeConnections::classBegin()
296 Q_D(QDeclarativeConnections);
297 d->componentcomplete=false;
300 void QDeclarativeConnections::componentComplete()
302 Q_D(QDeclarativeConnections);
303 d->componentcomplete=true;