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(m_signal, m_expression);
179 m_isEvaluating = true;
180 if (!m_paramsValid) {
181 if (!m_signal.parameterTypes().isEmpty())
182 m_params = new QQmlBoundSignalParameters(m_signal, this);
183 m_paramsValid = true;
186 if (m_params) m_params->setValues(a);
187 if (m_expression && m_expression->engine()) {
188 QQmlExpressionPrivate::get(m_expression)->value(m_params);
189 if (m_expression && m_expression->hasError())
190 QQmlEnginePrivate::warning(m_expression->engine(), m_expression->error());
192 if (m_params) m_params->clearValues();
193 m_isEvaluating = false;
196 return QObject::qt_metacall(c, id, a);
200 QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method,
202 : QObject(parent), types(0), values(0)
204 MetaObject *mo = new MetaObject(this);
207 QMetaObjectBuilder mob;
208 mob.setSuperClass(&QQmlBoundSignalParameters::staticMetaObject);
209 mob.setClassName("QQmlBoundSignalParameters");
211 QList<QByteArray> paramTypes = method.parameterTypes();
212 QList<QByteArray> paramNames = method.parameterNames();
213 types = new int[paramTypes.count()];
214 for (int ii = 0; ii < paramTypes.count(); ++ii) {
215 const QByteArray &type = paramTypes.at(ii);
216 const QByteArray &name = paramNames.at(ii);
218 if (name.isEmpty() || type.isEmpty()) {
223 QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData());
224 if (QQmlMetaType::isQObject(t)) {
225 types[ii] = QMetaType::QObjectStar;
226 QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*");
227 prop.setWritable(false);
229 QByteArray propType = type;
230 if ((QMetaType::typeFlags(t) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration) {
233 } else if (t == QVariant::Invalid) {
236 int scopeIdx = propType.lastIndexOf("::");
237 if (scopeIdx != -1) {
238 scope = propType.left(scopeIdx);
239 name = propType.mid(scopeIdx + 2);
243 const QMetaObject *meta;
245 meta = &QObject::staticQtMetaObject;
247 meta = parent->parent()->metaObject(); //### assumes parent->parent()
248 for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
249 QMetaEnum m = meta->enumerator(i);
250 if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) {
258 QMetaPropertyBuilder prop = mob.addProperty(name, propType);
259 prop.setWritable(false);
262 myMetaObject = mob.toMetaObject();
263 *static_cast<QMetaObject *>(mo) = *myMetaObject;
265 d_ptr->metaObject = mo;
268 QQmlBoundSignalParameters::~QQmlBoundSignalParameters()
274 void QQmlBoundSignalParameters::setValues(void **v)
279 void QQmlBoundSignalParameters::clearValues()
284 int QQmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a)
289 if (c == QMetaObject::ReadProperty && id >= 1) {
290 int t = types[id - 1];
292 QMetaType::destruct(t, p);
293 QMetaType::construct(t, p, values[id]);
296 return qt_metacall(c, id, a);
302 #include <qqmlboundsignal.moc>