Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / qtquick1 / util / qdeclarativeconnections.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "QtQuick1/private/qdeclarativeconnections_p.h"
43
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>
50
51 #include <QtCore/qdebug.h>
52 #include <QtCore/qstringlist.h>
53
54 #include <private/qobject_p.h>
55
56 QT_BEGIN_NAMESPACE
57
58
59
60 class QDeclarative1ConnectionsPrivate : public QObjectPrivate
61 {
62 public:
63     QDeclarative1ConnectionsPrivate() : target(0), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
64
65     QList<QDeclarativeBoundSignal*> boundsignals;
66     QObject *target;
67
68     bool targetSet;
69     bool ignoreUnknownSignals;
70     bool componentcomplete;
71
72     QByteArray data;
73 };
74
75 /*!
76     \qmlclass Connections QDeclarative1Connections
77     \inqmlmodule QtQuick 1
78     \ingroup qml-utility-elements
79     \since QtQuick 1.0
80     \brief A Connections element describes generalized connections to signals.
81
82     A Connections object creates a connection to a QML signal.
83
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:
86
87     \qml
88     MouseArea {
89         onClicked: { foo(parameters) }
90     }
91     \endqml
92
93     However, it is not possible to connect to a signal in this way in some 
94     cases, such as when:
95
96     \list
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
100     \endlist
101
102     When any of these are needed, the Connections element can be used instead.
103
104     For example, the above code can be changed to use a Connections object,
105     like this:
106
107     \qml
108     MouseArea {
109         Connections {
110             onClicked: foo(parameters)
111         }
112     }
113     \endqml
114
115     More generally, the Connections object can be a child of some object other than
116     the sender of the signal:
117
118     \qml
119     MouseArea {
120         id: area
121     }
122     // ...
123     \endqml
124     \qml
125     Connections {
126         target: area
127         onClicked: foo(parameters)
128     }
129     \endqml
130
131     \sa QtDeclarative
132 */
133 QDeclarative1Connections::QDeclarative1Connections(QObject *parent) :
134     QObject(*(new QDeclarative1ConnectionsPrivate), parent)
135 {
136 }
137
138 QDeclarative1Connections::~QDeclarative1Connections()
139 {
140 }
141
142 /*!
143     \qmlproperty Object QtQuick1::Connections::target
144     This property holds the object that sends the signal.
145
146     If this property is not set, the \c target defaults to the parent of the Connection.
147
148     If set to null, no connection is made and any signal handlers are ignored
149     until the target is not null.
150 */
151 QObject *QDeclarative1Connections::target() const
152 {
153     Q_D(const QDeclarative1Connections);
154     return d->targetSet ? d->target : parent();
155 }
156
157 void QDeclarative1Connections::setTarget(QObject *obj)
158 {
159     Q_D(QDeclarative1Connections);
160     d->targetSet = true; // even if setting to 0, it is *set*
161     if (d->target == obj)
162         return;
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())
167             s->deleteLater();
168         else
169             delete s;
170     }
171     d->boundsignals.clear();
172     d->target = obj;
173     connectSignals();
174     emit targetChanged();
175 }
176
177 /*!
178     \qmlproperty bool QtQuick1::Connections::ignoreUnknownSignals
179
180     Normally, a connection to a non-existent signal produces runtime errors.
181
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.
185 */
186 bool QDeclarative1Connections::ignoreUnknownSignals() const
187 {
188     Q_D(const QDeclarative1Connections);
189     return d->ignoreUnknownSignals;
190 }
191
192 void QDeclarative1Connections::setIgnoreUnknownSignals(bool ignore)
193 {
194     Q_D(QDeclarative1Connections);
195     d->ignoreUnknownSignals = ignore;
196 }
197
198
199
200 QByteArray
201 QDeclarative1ConnectionsParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
202 {
203     QByteArray rv;
204     QDataStream ds(&rv, QIODevice::WriteOnly);
205
206     for(int ii = 0; ii < props.count(); ++ii)
207     {
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));
211             return QByteArray();
212         }
213
214         QList<QVariant> values = props.at(ii).assignedValues();
215
216         for (int i = 0; i < values.count(); ++i) {
217             const QVariant &value = values.at(i);
218
219             if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
220                 error(props.at(ii), QDeclarative1Connections::tr("Connections: nested objects not allowed"));
221                 return QByteArray();
222             } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
223                 error(props.at(ii), QDeclarative1Connections::tr("Connections: syntax error"));
224                 return QByteArray();
225             } else {
226                 QDeclarativeScript::Variant v = qvariant_cast<QDeclarativeScript::Variant>(value);
227                 if (v.isScript()) {
228                     ds << propName;
229                     ds << v.asScript();
230                 } else {
231                     error(props.at(ii), QDeclarative1Connections::tr("Connections: script expected"));
232                     return QByteArray();
233                 }
234             }
235         }
236     }
237
238     return rv;
239 }
240
241 void QDeclarative1ConnectionsParser::setCustomData(QObject *object,
242                                             const QByteArray &data)
243 {
244     QDeclarative1ConnectionsPrivate *p =
245         static_cast<QDeclarative1ConnectionsPrivate *>(QObjectPrivate::get(object));
246     p->data = data;
247 }
248
249
250 void QDeclarative1Connections::connectSignals()
251 {
252     Q_D(QDeclarative1Connections);
253     if (!d->componentcomplete || (d->targetSet && !target()))
254         return;
255
256     QDataStream ds(d->data);
257     while (!ds.atEnd()) {
258         QString propName;
259         ds >> propName;
260         QString script;
261         ds >> script;
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;
272         } else {
273             if (!d->ignoreUnknownSignals)
274                 qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName);
275         }
276     }
277 }
278
279 void QDeclarative1Connections::classBegin()
280 {
281     Q_D(QDeclarative1Connections);
282     d->componentcomplete=false;
283 }
284
285 void QDeclarative1Connections::componentComplete()
286 {
287     Q_D(QDeclarative1Connections);
288     d->componentcomplete=true;
289     connectSignals();
290 }
291
292
293
294 QT_END_NAMESPACE