1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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 "QtQuick1/private/qdeclarativeconnections_p.h"
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/private/qdeclarativeproperty_p.h>
46 #include <QtDeclarative/private/qdeclarativeboundsignal_p.h>
47 #include <QtDeclarative/qdeclarativecontext.h>
48 #include <QtDeclarative/private/qdeclarativecontext_p.h>
49 #include <QtDeclarative/qdeclarativeinfo.h>
51 #include <QtCore/qdebug.h>
52 #include <QtCore/qstringlist.h>
54 #include <private/qobject_p.h>
60 class QDeclarative1ConnectionsPrivate : public QObjectPrivate
63 QDeclarative1ConnectionsPrivate() : target(0), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
65 QList<QDeclarativeBoundSignal*> boundsignals;
69 bool ignoreUnknownSignals;
70 bool componentcomplete;
76 \qmlclass Connections QDeclarative1Connections
77 \inqmlmodule QtQuick 1
78 \ingroup qml-utility-elements
80 \brief A Connections element describes generalized connections to signals.
82 A Connections object creates a connection to a QML signal.
84 When connecting to signals in QML, the usual way is to create an
85 "on<Signal>" handler that reacts when a signal is received, like this:
89 onClicked: { foo(parameters) }
93 However, it is not possible to connect to a signal in this way in some
97 \i Multiple connections to the same signal are required
98 \i Creating connections outside the scope of the signal sender
99 \i Connecting to targets not defined in QML
102 When any of these are needed, the Connections element can be used instead.
104 For example, the above code can be changed to use a Connections object,
110 onClicked: foo(parameters)
115 More generally, the Connections object can be a child of some object other than
116 the sender of the signal:
127 onClicked: foo(parameters)
133 QDeclarative1Connections::QDeclarative1Connections(QObject *parent) :
134 QObject(*(new QDeclarative1ConnectionsPrivate), parent)
138 QDeclarative1Connections::~QDeclarative1Connections()
143 \qmlproperty Object QtQuick1::Connections::target
144 This property holds the object that sends the signal.
146 If this property is not set, the \c target defaults to the parent of the Connection.
148 If set to null, no connection is made and any signal handlers are ignored
149 until the target is not null.
151 QObject *QDeclarative1Connections::target() const
153 Q_D(const QDeclarative1Connections);
154 return d->targetSet ? d->target : parent();
157 void QDeclarative1Connections::setTarget(QObject *obj)
159 Q_D(QDeclarative1Connections);
160 d->targetSet = true; // even if setting to 0, it is *set*
161 if (d->target == obj)
163 foreach (QDeclarativeBoundSignal *s, d->boundsignals) {
164 // It is possible that target is being changed due to one of our signal
165 // handlers -> use deleteLater().
166 if (s->isEvaluating())
171 d->boundsignals.clear();
174 emit targetChanged();
178 \qmlproperty bool QtQuick1::Connections::ignoreUnknownSignals
180 Normally, a connection to a non-existent signal produces runtime errors.
182 If this property is set to \c true, such errors are ignored.
183 This is useful if you intend to connect to different types of objects, handling
184 a different set of signals for each object.
186 bool QDeclarative1Connections::ignoreUnknownSignals() const
188 Q_D(const QDeclarative1Connections);
189 return d->ignoreUnknownSignals;
192 void QDeclarative1Connections::setIgnoreUnknownSignals(bool ignore)
194 Q_D(QDeclarative1Connections);
195 d->ignoreUnknownSignals = ignore;
201 QDeclarative1ConnectionsParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
204 QDataStream ds(&rv, QIODevice::WriteOnly);
206 for(int ii = 0; ii < props.count(); ++ii)
208 QString propName = props.at(ii).name();
209 if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
210 error(props.at(ii), QDeclarative1Connections::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), QDeclarative1Connections::tr("Connections: nested objects not allowed"));
222 } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
223 error(props.at(ii), QDeclarative1Connections::tr("Connections: syntax error"));
226 QDeclarativeScript::Variant v = qvariant_cast<QDeclarativeScript::Variant>(value);
231 error(props.at(ii), QDeclarative1Connections::tr("Connections: script expected"));
241 void QDeclarative1ConnectionsParser::setCustomData(QObject *object,
242 const QByteArray &data)
244 QDeclarative1ConnectionsPrivate *p =
245 static_cast<QDeclarative1ConnectionsPrivate *>(QObjectPrivate::get(object));
250 void QDeclarative1Connections::connectSignals()
252 Q_D(QDeclarative1Connections);
253 if (!d->componentcomplete || (d->targetSet && !target()))
256 QDataStream ds(d->data);
257 while (!ds.atEnd()) {
262 QDeclarativeProperty prop(target(), propName);
263 if (prop.isValid() && (prop.type() & QDeclarativeProperty::SignalProperty)) {
264 QDeclarativeBoundSignal *signal =
265 new QDeclarativeBoundSignal(target(), prop.method(), this);
266 QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(this), 0, script);
267 QDeclarativeData *ddata = QDeclarativeData::get(this);
268 if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
269 expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber, ddata->columnNumber);
270 signal->setExpression(expression);
271 d->boundsignals += signal;
273 if (!d->ignoreUnknownSignals)
274 qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName);
279 void QDeclarative1Connections::classBegin()
281 Q_D(QDeclarative1Connections);
282 d->componentcomplete=false;
285 void QDeclarative1Connections::componentComplete()
287 Q_D(QDeclarative1Connections);
288 d->componentcomplete=true;