Merge branch 'qtquick2' into v8
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeboundsignal.cpp
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 ** 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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativeboundsignal_p.h"
43
44 #include "private/qmetaobjectbuilder_p.h"
45 #include "private/qdeclarativeengine_p.h"
46 #include "private/qdeclarativeexpression_p.h"
47 #include "private/qdeclarativecontext_p.h"
48 #include "private/qdeclarativemetatype_p.h"
49 #include "qdeclarative.h"
50 #include "qdeclarativecontext.h"
51 #include "private/qdeclarativeglobal_p.h"
52 #include "private/qdeclarativedebugtrace_p.h"
53
54 #include <QtCore/qstringbuilder.h>
55 #include <QtCore/qdebug.h>
56
57 QT_BEGIN_NAMESPACE
58
59 class QDeclarativeBoundSignalParameters : public QObject
60 {
61 Q_OBJECT
62 public:
63     QDeclarativeBoundSignalParameters(const QMetaMethod &, QObject * = 0);
64     ~QDeclarativeBoundSignalParameters();
65
66     void setValues(void **);
67     void clearValues();
68
69 private:
70     friend class MetaObject;
71     int metaCall(QMetaObject::Call, int _id, void **);
72     struct MetaObject : public QAbstractDynamicMetaObject {
73         MetaObject(QDeclarativeBoundSignalParameters *b)
74             : parent(b) {}
75
76         int metaCall(QMetaObject::Call c, int id, void **a) { 
77             return parent->metaCall(c, id, a);
78         }
79         QDeclarativeBoundSignalParameters *parent;
80     };
81
82     int *types;
83     void **values;
84     QMetaObject *myMetaObject;
85 };
86
87 static int evaluateIdx = -1;
88
89 QDeclarativeAbstractBoundSignal::QDeclarativeAbstractBoundSignal(QObject *parent)
90 : QObject(parent)
91 {
92 }
93
94 QDeclarativeAbstractBoundSignal::~QDeclarativeAbstractBoundSignal()
95 {
96 }
97
98 QDeclarativeBoundSignal::QDeclarativeBoundSignal(QObject *scope, const QMetaMethod &signal, 
99                                QObject *parent)
100 : m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
101 {
102     // This is thread safe.  Although it may be updated by two threads, they
103     // will both set it to the same value - so the worst thing that can happen
104     // is that they both do the work to figure it out.  Boo hoo.
105     if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
106
107     QDeclarative_setParent_noEvent(this, parent);
108     QDeclarativePropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
109 }
110
111 QDeclarativeBoundSignal::QDeclarativeBoundSignal(QDeclarativeContext *ctxt, const QString &val, 
112                                QObject *scope, const QMetaMethod &signal,
113                                QObject *parent)
114 : m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
115 {
116     // This is thread safe.  Although it may be updated by two threads, they
117     // will both set it to the same value - so the worst thing that can happen
118     // is that they both do the work to figure it out.  Boo hoo.
119     if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
120
121     QDeclarative_setParent_noEvent(this, parent);
122     QDeclarativePropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
123
124     m_expression = new QDeclarativeExpression(ctxt, scope, val);
125 }
126
127 QDeclarativeBoundSignal::~QDeclarativeBoundSignal()
128 {
129     delete m_expression;
130     m_expression = 0;
131 }
132
133 int QDeclarativeBoundSignal::index() const 
134
135     return m_signal.methodIndex();
136 }
137
138 /*!
139     Returns the signal expression.
140 */
141 QDeclarativeExpression *QDeclarativeBoundSignal::expression() const
142 {
143     return m_expression;
144 }
145
146 /*!
147     Sets the signal expression to \a e.  Returns the current signal expression,
148     or null if there is no signal expression.
149
150     The QDeclarativeBoundSignal instance takes ownership of \a e.  The caller is 
151     assumes ownership of the returned QDeclarativeExpression.
152 */
153 QDeclarativeExpression *QDeclarativeBoundSignal::setExpression(QDeclarativeExpression *e)
154 {
155     QDeclarativeExpression *rv = m_expression;
156     m_expression = e;
157     if (m_expression) m_expression->setNotifyOnValueChanged(false);
158     return rv;
159 }
160
161 QDeclarativeBoundSignal *QDeclarativeBoundSignal::cast(QObject *o)
162 {
163     QDeclarativeAbstractBoundSignal *s = qobject_cast<QDeclarativeAbstractBoundSignal*>(o);
164     return static_cast<QDeclarativeBoundSignal *>(s);
165 }
166
167 int QDeclarativeBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a)
168 {
169     if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) {
170         if (!m_expression)
171             return -1;
172         if (QDeclarativeDebugService::isDebuggingEnabled()) {
173             QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::HandlingSignal);
174             QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::HandlingSignal, QLatin1String(m_signal.signature()) % QLatin1String(": ") % m_expression->expression());
175             QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::HandlingSignal, m_expression->sourceFile(), m_expression->lineNumber());
176         }
177         m_isEvaluating = true;
178         if (!m_paramsValid) {
179             if (!m_signal.parameterTypes().isEmpty())
180                 m_params = new QDeclarativeBoundSignalParameters(m_signal, this);
181             m_paramsValid = true;
182         }
183
184         if (m_params) m_params->setValues(a);
185         if (m_expression && m_expression->engine()) {
186             QDeclarativeExpressionPrivate::get(m_expression)->value(m_params);
187             if (m_expression && m_expression->hasError())
188                 QDeclarativeEnginePrivate::warning(m_expression->engine(), m_expression->error());
189         }
190         if (m_params) m_params->clearValues();
191         m_isEvaluating = false;
192         QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::HandlingSignal);
193         return -1;
194     } else {
195         return QObject::qt_metacall(c, id, a);
196     }
197 }
198
199 QDeclarativeBoundSignalParameters::QDeclarativeBoundSignalParameters(const QMetaMethod &method, 
200                                                                      QObject *parent)
201 : QObject(parent), types(0), values(0)
202 {
203     MetaObject *mo = new MetaObject(this);
204
205     // ### Optimize!
206     QMetaObjectBuilder mob;
207     mob.setSuperClass(&QDeclarativeBoundSignalParameters::staticMetaObject);
208     mob.setClassName("QDeclarativeBoundSignalParameters");
209
210     QList<QByteArray> paramTypes = method.parameterTypes();
211     QList<QByteArray> paramNames = method.parameterNames();
212     types = new int[paramTypes.count()];
213     for (int ii = 0; ii < paramTypes.count(); ++ii) {
214         const QByteArray &type = paramTypes.at(ii);
215         const QByteArray &name = paramNames.at(ii);
216
217         if (name.isEmpty() || type.isEmpty()) {
218             types[ii] = 0;
219             continue;
220         }
221
222         QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData());
223         if (QDeclarativeMetaType::isQObject(t)) {
224             types[ii] = QMetaType::QObjectStar;
225             QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*");
226             prop.setWritable(false);
227         } else {
228             QByteArray propType = type;
229             if (t >= QVariant::UserType || t == QVariant::Invalid) {
230                 QByteArray scope;
231                 QByteArray name;
232                 int scopeIdx = propType.lastIndexOf("::");
233                 if (scopeIdx != -1) {
234                     scope = propType.left(scopeIdx);
235                     name = propType.mid(scopeIdx + 2);
236                 } else {
237                     name = propType;
238                 }
239                 const QMetaObject *meta;
240                 if (scope == "Qt")
241                     meta = &QObject::staticQtMetaObject;
242                 else
243                     meta = parent->parent()->metaObject();   //### assumes parent->parent()
244                 for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
245                     QMetaEnum m = meta->enumerator(i);
246                     if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) {
247                         t = QVariant::Int;
248                         propType = "int";
249                         break;
250                     }
251                 }
252             }
253             if (QDeclarativeMetaType::canCopy(t)) {
254                 types[ii] = t;
255                 QMetaPropertyBuilder prop = mob.addProperty(name, propType);
256                 prop.setWritable(false);
257             } else {
258                 types[ii] = 0x80000000 | t;
259                 QMetaPropertyBuilder prop = mob.addProperty(name, "QVariant");
260                 prop.setWritable(false);
261             }
262         }
263     }
264     myMetaObject = mob.toMetaObject();
265     *static_cast<QMetaObject *>(mo) = *myMetaObject;
266
267     d_ptr->metaObject = mo;
268 }
269
270 QDeclarativeBoundSignalParameters::~QDeclarativeBoundSignalParameters()
271 {
272     delete [] types;
273     qFree(myMetaObject);
274 }
275
276 void QDeclarativeBoundSignalParameters::setValues(void **v)
277 {
278     values = v;
279 }
280
281 void QDeclarativeBoundSignalParameters::clearValues()
282 {
283     values = 0;
284 }
285
286 int QDeclarativeBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a)
287 {
288     if (!values)
289         return -1;
290
291     if (c == QMetaObject::ReadProperty && id >= 1) {
292         if (types[id - 1] & 0x80000000) {
293             *((QVariant *)a[0]) = QVariant(types[id - 1] & 0x7FFFFFFF, values[id]);
294         } else {
295             QDeclarativeMetaType::copy(types[id - 1], a[0], values[id]);
296         }
297         return -1;
298     } else {
299         return qt_metacall(c, id, a);
300     }
301 }
302
303 QT_END_NAMESPACE
304
305 #include <qdeclarativeboundsignal.moc>