source: trunk/src/declarative/util/qdeclarativeconnections.cpp@ 1008

Last change on this file since 1008 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 8.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtDeclarative module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
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.
23**
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.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "private/qdeclarativeconnections_p.h"
43
44#include <qdeclarativeexpression.h>
45#include <qdeclarativeproperty_p.h>
46#include <qdeclarativeboundsignal_p.h>
47#include <qdeclarativecontext.h>
48#include <qdeclarativeinfo.h>
49
50#include <QtCore/qdebug.h>
51#include <QtCore/qstringlist.h>
52
53#include <private/qobject_p.h>
54
55QT_BEGIN_NAMESPACE
56
57class QDeclarativeConnectionsPrivate : public QObjectPrivate
58{
59public:
60 QDeclarativeConnectionsPrivate() : target(0), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
61
62 QList<QDeclarativeBoundSignal*> boundsignals;
63 QObject *target;
64
65 bool targetSet;
66 bool ignoreUnknownSignals;
67 bool componentcomplete;
68
69 QByteArray data;
70};
71
72/*!
73 \qmlclass Connections QDeclarativeConnections
74 \ingroup qml-utility-elements
75 \since 4.7
76 \brief A Connections element describes generalized connections to signals.
77
78 A Connections object creates a connection to a QML signal.
79
80 When connecting to signals in QML, the usual way is to create an
81 "on<Signal>" handler that reacts when a signal is received, like this:
82
83 \qml
84 MouseArea {
85 onClicked: { foo(...) }
86 }
87 \endqml
88
89 However, it is not possible to connect to a signal in this way in some
90 cases, such as when:
91
92 \list
93 \i Multiple connections to the same signal are required
94 \i Creating connections outside the scope of the signal sender
95 \i Connecting to targets not defined in QML
96 \endlist
97
98 When any of these are needed, the Connections element can be used instead.
99
100 For example, the above code can be changed to use a Connections object,
101 like this:
102
103 \qml
104 MouseArea {
105 Connections {
106 onClicked: foo(...)
107 }
108 }
109 \endqml
110
111 More generally, the Connections object can be a child of some object other than
112 the sender of the signal:
113
114 \qml
115 MouseArea {
116 id: area
117 }
118 ...
119 Connections {
120 target: area
121 onClicked: foo(...)
122 }
123 \endqml
124
125 \sa QtDeclarative
126*/
127QDeclarativeConnections::QDeclarativeConnections(QObject *parent) :
128 QObject(*(new QDeclarativeConnectionsPrivate), parent)
129{
130}
131
132QDeclarativeConnections::~QDeclarativeConnections()
133{
134}
135
136/*!
137 \qmlproperty Object Connections::target
138 This property holds the object that sends the signal.
139
140 If this property is not set, the \c target defaults to the parent of the Connection.
141
142 If set to null, no connection is made and any signal handlers are ignored
143 until the target is not null.
144*/
145QObject *QDeclarativeConnections::target() const
146{
147 Q_D(const QDeclarativeConnections);
148 return d->targetSet ? d->target : parent();
149}
150
151void QDeclarativeConnections::setTarget(QObject *obj)
152{
153 Q_D(QDeclarativeConnections);
154 d->targetSet = true; // even if setting to 0, it is *set*
155 if (d->target == obj)
156 return;
157 foreach (QDeclarativeBoundSignal *s, d->boundsignals) {
158 // It is possible that target is being changed due to one of our signal
159 // handlers -> use deleteLater().
160 if (s->isEvaluating())
161 s->deleteLater();
162 else
163 delete s;
164 }
165 d->boundsignals.clear();
166 d->target = obj;
167 connectSignals();
168 emit targetChanged();
169}
170
171/*!
172 \qmlproperty bool Connections::ignoreUnknownSignals
173
174 Normally, a connection to a non-existent signal produces runtime errors.
175
176 If this property is set to \c true, such errors are ignored.
177 This is useful if you intend to connect to different types of objects, handling
178 a different set of signals for each object.
179*/
180bool QDeclarativeConnections::ignoreUnknownSignals() const
181{
182 Q_D(const QDeclarativeConnections);
183 return d->ignoreUnknownSignals;
184}
185
186void QDeclarativeConnections::setIgnoreUnknownSignals(bool ignore)
187{
188 Q_D(QDeclarativeConnections);
189 d->ignoreUnknownSignals = ignore;
190}
191
192
193
194QByteArray
195QDeclarativeConnectionsParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
196{
197 QByteArray rv;
198 QDataStream ds(&rv, QIODevice::WriteOnly);
199
200 for(int ii = 0; ii < props.count(); ++ii)
201 {
202 QString propName = QString::fromUtf8(props.at(ii).name());
203 if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
204 error(props.at(ii), QDeclarativeConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
205 return QByteArray();
206 }
207
208 QList<QVariant> values = props.at(ii).assignedValues();
209
210 for (int i = 0; i < values.count(); ++i) {
211 const QVariant &value = values.at(i);
212
213 if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
214 error(props.at(ii), QDeclarativeConnections::tr("Connections: nested objects not allowed"));
215 return QByteArray();
216 } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
217 error(props.at(ii), QDeclarativeConnections::tr("Connections: syntax error"));
218 return QByteArray();
219 } else {
220 QDeclarativeParser::Variant v = qvariant_cast<QDeclarativeParser::Variant>(value);
221 if (v.isScript()) {
222 ds << propName;
223 ds << v.asScript();
224 } else {
225 error(props.at(ii), QDeclarativeConnections::tr("Connections: script expected"));
226 return QByteArray();
227 }
228 }
229 }
230 }
231
232 return rv;
233}
234
235void QDeclarativeConnectionsParser::setCustomData(QObject *object,
236 const QByteArray &data)
237{
238 QDeclarativeConnectionsPrivate *p =
239 static_cast<QDeclarativeConnectionsPrivate *>(QObjectPrivate::get(object));
240 p->data = data;
241}
242
243
244void QDeclarativeConnections::connectSignals()
245{
246 Q_D(QDeclarativeConnections);
247 if (!d->componentcomplete || (d->targetSet && !target()))
248 return;
249
250 QDataStream ds(d->data);
251 while (!ds.atEnd()) {
252 QString propName;
253 ds >> propName;
254 QString script;
255 ds >> script;
256 QDeclarativeProperty prop(target(), propName);
257 if (prop.isValid() && (prop.type() & QDeclarativeProperty::SignalProperty)) {
258 QDeclarativeBoundSignal *signal =
259 new QDeclarativeBoundSignal(target(), prop.method(), this);
260 signal->setExpression(new QDeclarativeExpression(qmlContext(this), 0, script));
261 d->boundsignals += signal;
262 } else {
263 if (!d->ignoreUnknownSignals)
264 qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName);
265 }
266 }
267}
268
269void QDeclarativeConnections::classBegin()
270{
271 Q_D(QDeclarativeConnections);
272 d->componentcomplete=false;
273}
274
275void QDeclarativeConnections::componentComplete()
276{
277 Q_D(QDeclarativeConnections);
278 d->componentcomplete=true;
279 connectSignals();
280}
281
282QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.