1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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;
208 if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
209 error(props.at(ii), QDeclarativeConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
213 QList<QVariant> values = props.at(ii).assignedValues();
215 for (int i = 0; i < values.count(); ++i) {
216 const QVariant &value = values.at(i);
218 if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
219 error(props.at(ii), QDeclarativeConnections::tr("Connections: nested objects not allowed"));
221 } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
222 error(props.at(ii), QDeclarativeConnections::tr("Connections: syntax error"));
225 QDeclarativeScript::Variant v = qvariant_cast<QDeclarativeScript::Variant>(value);
228 ds << rewriteSignalHandler(v.asScript(), propName);
231 error(props.at(ii), QDeclarativeConnections::tr("Connections: script expected"));
241 void QDeclarativeConnectionsParser::setCustomData(QObject *object,
242 const QByteArray &data)
244 QDeclarativeConnectionsPrivate *p =
245 static_cast<QDeclarativeConnectionsPrivate *>(QObjectPrivate::get(object));
250 void QDeclarativeConnections::connectSignals()
252 Q_D(QDeclarativeConnections);
253 if (!d->componentcomplete || (d->targetSet && !target()))
256 QDataStream ds(d->data);
257 while (!ds.atEnd()) {
264 QDeclarativeProperty prop(target(), propName);
265 if (prop.isValid() && (prop.type() & QDeclarativeProperty::SignalProperty)) {
266 QDeclarativeBoundSignal *signal =
267 new QDeclarativeBoundSignal(target(), prop.method(), this);
270 QDeclarativeContextData *ctxtdata = 0;
271 QDeclarativeData *ddata = QDeclarativeData::get(this);
273 ctxtdata = ddata->outerContext;
274 if (ctxtdata && !ctxtdata->url.isEmpty())
275 location = ddata->outerContext->url.toString();
278 QDeclarativeExpression *expression = ctxtdata ?
279 QDeclarativeExpressionPrivate::create(ctxtdata, 0, script, true, location, line) : 0;
280 signal->setExpression(expression);
281 d->boundsignals += signal;
283 if (!d->ignoreUnknownSignals)
284 qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName);
289 void QDeclarativeConnections::classBegin()
291 Q_D(QDeclarativeConnections);
292 d->componentcomplete=false;
295 void QDeclarativeConnections::componentComplete()
297 Q_D(QDeclarativeConnections);
298 d->componentcomplete=true;