1 /****************************************************************************
3 ** Copyright (C) 2011 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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "private/qdeclarativeconnections_p.h"
44 #include <qdeclarativeexpression.h>
45 #include <qdeclarativeproperty_p.h>
46 #include <qdeclarativeboundsignal_p.h>
47 #include <qdeclarativecontext.h>
48 #include <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 \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 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 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 = QString::fromUtf8(props.at(ii).name());
206 if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
207 error(props.at(ii), QDeclarativeConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
211 QList<QVariant> values = props.at(ii).assignedValues();
213 for (int i = 0; i < values.count(); ++i) {
214 const QVariant &value = values.at(i);
216 if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
217 error(props.at(ii), QDeclarativeConnections::tr("Connections: nested objects not allowed"));
219 } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
220 error(props.at(ii), QDeclarativeConnections::tr("Connections: syntax error"));
223 QDeclarativeParser::Variant v = qvariant_cast<QDeclarativeParser::Variant>(value);
228 error(props.at(ii), QDeclarativeConnections::tr("Connections: script expected"));
238 void QDeclarativeConnectionsParser::setCustomData(QObject *object,
239 const QByteArray &data)
241 QDeclarativeConnectionsPrivate *p =
242 static_cast<QDeclarativeConnectionsPrivate *>(QObjectPrivate::get(object));
247 void QDeclarativeConnections::connectSignals()
249 Q_D(QDeclarativeConnections);
250 if (!d->componentcomplete || (d->targetSet && !target()))
253 QDataStream ds(d->data);
254 while (!ds.atEnd()) {
259 QDeclarativeProperty prop(target(), propName);
260 if (prop.isValid() && (prop.type() & QDeclarativeProperty::SignalProperty)) {
261 QDeclarativeBoundSignal *signal =
262 new QDeclarativeBoundSignal(target(), prop.method(), this);
263 QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(this), 0, script);
264 QDeclarativeData *ddata = QDeclarativeData::get(this);
265 if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
266 expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
267 signal->setExpression(expression);
268 d->boundsignals += signal;
270 if (!d->ignoreUnknownSignals)
271 qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName);
276 void QDeclarativeConnections::classBegin()
278 Q_D(QDeclarativeConnections);
279 d->componentcomplete=false;
282 void QDeclarativeConnections::componentComplete()
284 Q_D(QDeclarativeConnections);
285 d->componentcomplete=true;