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