1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qqmlboundsignal_p.h"
44 #include <private/qmetaobjectbuilder_p.h>
45 #include "qqmlengine_p.h"
46 #include "qqmlexpression_p.h"
47 #include "qqmlcontext_p.h"
48 #include "qqmlmetatype_p.h"
50 #include "qqmlcontext.h"
51 #include "qqmlglobal_p.h"
52 #include <private/qqmlprofilerservice_p.h>
53 #include <private/qv8debugservice_p.h>
55 #include <QtCore/qstringbuilder.h>
56 #include <QtCore/qdebug.h>
60 class QQmlBoundSignalParameters : public QObject
64 QQmlBoundSignalParameters(const QMetaMethod &, QObject * = 0);
65 ~QQmlBoundSignalParameters();
67 void setValues(void **);
71 friend class MetaObject;
72 int metaCall(QMetaObject::Call, int _id, void **);
73 struct MetaObject : public QAbstractDynamicMetaObject {
74 MetaObject(QQmlBoundSignalParameters *b)
77 int metaCall(QMetaObject::Call c, int id, void **a) {
78 return parent->metaCall(c, id, a);
80 QQmlBoundSignalParameters *parent;
85 QMetaObject *myMetaObject;
88 static int evaluateIdx = -1;
90 QQmlAbstractBoundSignal::QQmlAbstractBoundSignal(QObject *parent)
95 QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal()
99 QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal,
101 : m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
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();
108 QQml_setParent_noEvent(this, parent);
109 QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
112 QQmlBoundSignal::QQmlBoundSignal(QQmlContext *ctxt, const QString &val,
113 QObject *scope, const QMetaMethod &signal,
115 : m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
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();
122 QQml_setParent_noEvent(this, parent);
123 QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
125 m_expression = new QQmlExpression(ctxt, scope, val);
128 QQmlBoundSignal::~QQmlBoundSignal()
134 int QQmlBoundSignal::index() const
136 return m_signal.methodIndex();
140 Returns the signal expression.
142 QQmlExpression *QQmlBoundSignal::expression() const
148 Sets the signal expression to \a e. Returns the current signal expression,
149 or null if there is no signal expression.
151 The QQmlBoundSignal instance takes ownership of \a e. The caller is
152 assumes ownership of the returned QQmlExpression.
154 QQmlExpression *QQmlBoundSignal::setExpression(QQmlExpression *e)
156 QQmlExpression *rv = m_expression;
158 if (m_expression) m_expression->setNotifyOnValueChanged(false);
162 QQmlBoundSignal *QQmlBoundSignal::cast(QObject *o)
164 QQmlAbstractBoundSignal *s = qobject_cast<QQmlAbstractBoundSignal*>(o);
165 return static_cast<QQmlBoundSignal *>(s);
168 int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a)
170 if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) {
174 if (QQmlDebugService::isDebuggingEnabled())
175 QV8DebugService::instance()->signalEmitted(QString::fromAscii(m_signal.signature()));
177 QQmlHandlingSignalProfiler prof;
179 prof.setSignalInfo(QString::fromLatin1(m_signal.signature()),
180 m_expression->expression());
181 prof.setLocation(m_expression->sourceFile(), m_expression->lineNumber(),
182 m_expression->columnNumber());
185 m_isEvaluating = true;
186 if (!m_paramsValid) {
187 if (!m_signal.parameterTypes().isEmpty())
188 m_params = new QQmlBoundSignalParameters(m_signal, this);
189 m_paramsValid = true;
192 if (m_params) m_params->setValues(a);
193 if (m_expression && m_expression->engine()) {
194 QQmlExpressionPrivate::get(m_expression)->value(m_params);
195 if (m_expression && m_expression->hasError())
196 QQmlEnginePrivate::warning(m_expression->engine(), m_expression->error());
198 if (m_params) m_params->clearValues();
199 m_isEvaluating = false;
202 return QObject::qt_metacall(c, id, a);
206 QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method,
208 : QObject(parent), types(0), values(0)
210 MetaObject *mo = new MetaObject(this);
213 QMetaObjectBuilder mob;
214 mob.setSuperClass(&QQmlBoundSignalParameters::staticMetaObject);
215 mob.setClassName("QQmlBoundSignalParameters");
217 QList<QByteArray> paramTypes = method.parameterTypes();
218 QList<QByteArray> paramNames = method.parameterNames();
219 types = new int[paramTypes.count()];
220 for (int ii = 0; ii < paramTypes.count(); ++ii) {
221 const QByteArray &type = paramTypes.at(ii);
222 const QByteArray &name = paramNames.at(ii);
224 if (name.isEmpty() || type.isEmpty()) {
229 QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData());
230 if (QQmlMetaType::isQObject(t)) {
231 types[ii] = QMetaType::QObjectStar;
232 QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*");
233 prop.setWritable(false);
235 QByteArray propType = type;
236 if (t >= QVariant::UserType || t == QVariant::Invalid) {
239 int scopeIdx = propType.lastIndexOf("::");
240 if (scopeIdx != -1) {
241 scope = propType.left(scopeIdx);
242 name = propType.mid(scopeIdx + 2);
246 const QMetaObject *meta;
248 meta = &QObject::staticQtMetaObject;
250 meta = parent->parent()->metaObject(); //### assumes parent->parent()
251 for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
252 QMetaEnum m = meta->enumerator(i);
253 if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) {
261 QMetaPropertyBuilder prop = mob.addProperty(name, propType);
262 prop.setWritable(false);
265 myMetaObject = mob.toMetaObject();
266 *static_cast<QMetaObject *>(mo) = *myMetaObject;
268 d_ptr->metaObject = mo;
271 QQmlBoundSignalParameters::~QQmlBoundSignalParameters()
277 void QQmlBoundSignalParameters::setValues(void **v)
282 void QQmlBoundSignalParameters::clearValues()
287 int QQmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a)
292 if (c == QMetaObject::ReadProperty && id >= 1) {
293 int t = types[id - 1];
295 QMetaType::destruct(t, p);
296 QMetaType::construct(t, p, values[id]);
299 return qt_metacall(c, id, a);
305 #include <qqmlboundsignal.moc>