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 "qqmlrewrite_p.h"
53 #include <private/qqmlprofilerservice_p.h>
54 #include <private/qv8debugservice_p.h>
56 #include <QtCore/qstringbuilder.h>
57 #include <QtCore/qdebug.h>
59 Q_DECLARE_METATYPE(QJSValue)
63 static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = {
64 QQmlBoundSignalExpression::expressionIdentifier,
65 QQmlBoundSignalExpression::expressionChanged
68 QQmlBoundSignalExpression::QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QByteArray &expression,
69 bool isRewritten, const QString &fileName, int line, int column)
70 : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable)
72 setNotifyOnValueChanged(false);
74 setScopeObject(scope);
75 m_expression = QString::fromUtf8(expression);
76 m_expressionFunctionValid = false;
77 m_expressionFunctionRewritten = isRewritten;
78 m_fileName = fileName;
83 QQmlBoundSignalExpression::QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QString &expression,
84 bool isRewritten, const QString &fileName, int line, int column)
85 : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable)
87 setNotifyOnValueChanged(false);
89 setScopeObject(scope);
90 m_expression = expression;
91 m_expressionFunctionValid = false;
92 m_expressionFunctionRewritten = isRewritten;
93 m_fileName = fileName;
98 QQmlBoundSignalExpression::~QQmlBoundSignalExpression()
100 qPersistentDispose(m_v8function);
101 qPersistentDispose(m_v8qmlscope);
104 QString QQmlBoundSignalExpression::expressionIdentifier(QQmlJavaScriptExpression *e)
106 QQmlBoundSignalExpression *This = static_cast<QQmlBoundSignalExpression *>(e);
107 return QLatin1String("\"") + This->m_expression + QLatin1String("\"");
110 void QQmlBoundSignalExpression::expressionChanged(QQmlJavaScriptExpression *)
112 // bound signals do not notify on change.
115 // This mirrors code in QQmlExpressionPrivate::value() and v8value().
116 // Any change made here should be made there and vice versa.
117 void QQmlBoundSignalExpression::evaluate(QObject *secondaryScope)
119 Q_ASSERT (context() && engine());
120 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
122 ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
124 v8::HandleScope handle_scope;
125 v8::Context::Scope context_scope(ep->v8engine()->context());
126 if (!m_expressionFunctionValid) {
129 if (m_expressionFunctionRewritten) {
132 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
133 code = rewriteSignalHandler(m_expression, m_functionName, &ok);
137 m_v8function = evalFunction(context(), scopeObject(), code, m_fileName, m_line, &m_v8qmlscope);
139 if (m_v8function.IsEmpty() || m_v8function->IsNull()) {
140 ep->dereferenceScarceResources();
141 return; // could not evaluate function. Not valid.
144 setUseSharedContext(false);
145 m_expressionFunctionValid = true;
148 if (secondaryScope) {
149 QObject *restoreSecondaryScope = 0;
150 restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(m_v8qmlscope, secondaryScope);
151 QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0);
152 ep->v8engine()->contextWrapper()->setSecondaryScope(m_v8qmlscope, restoreSecondaryScope);
154 QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0);
157 ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
160 ////////////////////////////////////////////////////////////////////////
162 class QQmlBoundSignalParameters : public QObject
166 QQmlBoundSignalParameters(const QMetaMethod &, QQmlAbstractBoundSignal*);
167 ~QQmlBoundSignalParameters();
169 void setValues(void **);
173 friend class MetaObject;
174 int metaCall(QMetaObject::Call, int _id, void **);
175 struct MetaObject : public QAbstractDynamicMetaObject {
176 MetaObject(QQmlBoundSignalParameters *b)
179 int metaCall(QMetaObject::Call c, int id, void **a) {
180 return parent->metaCall(c, id, a);
182 QQmlBoundSignalParameters *parent;
187 QMetaObject *myMetaObject;
190 QQmlAbstractBoundSignal::QQmlAbstractBoundSignal()
191 : m_prevSignal(0), m_nextSignal(0)
195 QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal()
200 void QQmlAbstractBoundSignal::addToObject(QObject *obj)
202 Q_ASSERT(!m_prevSignal);
205 QQmlData *data = QQmlData::get(obj, true);
207 m_nextSignal = data->signalHandlers;
208 if (m_nextSignal) m_nextSignal->m_prevSignal = &m_nextSignal;
209 m_prevSignal = &data->signalHandlers;
210 data->signalHandlers = this;
213 void QQmlAbstractBoundSignal::removeFromObject()
216 *m_prevSignal = m_nextSignal;
217 if (m_nextSignal) m_nextSignal->m_prevSignal = m_prevSignal;
223 QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal,
225 : m_expression(0), m_params(0), m_scope(scope), m_index(signal.methodIndex())
227 setParamsValid(false);
228 setIsEvaluating(false);
230 callback = &subscriptionCallback;
231 QQmlNotifierEndpoint::connect(scope, m_index);
234 QQmlBoundSignal::~QQmlBoundSignal()
240 int QQmlBoundSignal::index() const
246 Returns the signal expression.
248 QQmlBoundSignalExpression *QQmlBoundSignal::expression() const
254 Sets the signal expression to \a e. Returns the current signal expression,
255 or null if there is no signal expression.
257 The QQmlBoundSignal instance adds a reference to \a e. The caller
258 assumes ownership of the returned QQmlBoundSignalExpression reference.
260 QQmlBoundSignalExpressionPointer QQmlBoundSignal::setExpression(QQmlBoundSignalExpression *e)
262 QQmlBoundSignalExpressionPointer rv = m_expression;
264 if (m_expression) m_expression->setNotifyOnValueChanged(false);
269 Sets the signal expression to \a e. Returns the current signal expression,
270 or null if there is no signal expression.
272 The QQmlBoundSignal instance takes ownership of \a e (and does not add a reference). The caller
273 assumes ownership of the returned QQmlBoundSignalExpression reference.
275 QQmlBoundSignalExpressionPointer QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e)
277 QQmlBoundSignalExpressionPointer rv = m_expression;
278 m_expression.take(e);
279 if (m_expression) m_expression->setNotifyOnValueChanged(false);
283 void QQmlBoundSignal::subscriptionCallback(QQmlNotifierEndpoint *e, void **a)
285 QQmlBoundSignal *s = static_cast<QQmlBoundSignal*>(e);
286 if (!s->m_expression)
289 if (QQmlDebugService::isDebuggingEnabled())
290 QV8DebugService::instance()->signalEmitted(QString::fromLatin1(s->m_scope->metaObject()->method(s->m_index).methodSignature()));
292 QQmlHandlingSignalProfiler prof(*(s->m_scope), s->m_index, s->m_expression);
294 s->setIsEvaluating(true);
296 if (!s->paramsValid()) {
297 QMetaMethod signal = s->m_scope->metaObject()->method(s->m_index);
298 if (!signal.parameterTypes().isEmpty())
299 s->m_params = new QQmlBoundSignalParameters(signal, s);
300 s->setParamsValid(true);
303 if (s->m_params) s->m_params->setValues(a);
304 if (s->m_expression && s->m_expression->engine()) {
305 s->m_expression->evaluate(s->m_params);
306 if (s->m_expression && s->m_expression->hasError())
307 QQmlEnginePrivate::warning(s->m_expression->engine(), s->m_expression->error());
309 if (s->m_params) s->m_params->clearValues();
311 s->setIsEvaluating(false);
314 QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method,
315 QQmlAbstractBoundSignal *owner)
316 : types(0), values(0)
318 MetaObject *mo = new MetaObject(this);
321 QMetaObjectBuilder mob;
322 mob.setSuperClass(&QQmlBoundSignalParameters::staticMetaObject);
323 mob.setClassName("QQmlBoundSignalParameters");
325 QList<QByteArray> paramTypes = method.parameterTypes();
326 QList<QByteArray> paramNames = method.parameterNames();
327 types = new int[paramTypes.count()];
328 for (int ii = 0; ii < paramTypes.count(); ++ii) {
329 const QByteArray &type = paramTypes.at(ii);
330 const QByteArray &name = paramNames.at(ii);
332 if (name.isEmpty() || type.isEmpty()) {
337 int t = QMetaType::type(type.constData());
338 if (QQmlMetaType::isQObject(t)) {
339 types[ii] = QMetaType::QObjectStar;
340 QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*");
341 prop.setWritable(false);
343 QByteArray propType = type;
344 QMetaType::TypeFlags flags = QMetaType::typeFlags(t);
345 if (flags & QMetaType::IsEnumeration) {
348 } else if (t == QMetaType::UnknownType ||
349 (t >= int(QMetaType::User) && !(flags & QMetaType::PointerToQObject) &&
350 t != qMetaTypeId<QJSValue>())) {
351 //the UserType clause is to catch registered QFlags
354 int scopeIdx = propType.lastIndexOf("::");
355 if (scopeIdx != -1) {
356 scope = propType.left(scopeIdx);
357 name = propType.mid(scopeIdx + 2);
361 const QMetaObject *meta;
363 meta = &QObject::staticQtMetaObject;
365 meta = owner->scope()->metaObject();
366 for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
367 QMetaEnum m = meta->enumerator(i);
368 if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) {
376 QMetaPropertyBuilder prop = mob.addProperty(name, propType);
377 prop.setWritable(false);
380 myMetaObject = mob.toMetaObject();
381 *static_cast<QMetaObject *>(mo) = *myMetaObject;
383 d_ptr->metaObject = mo;
386 QQmlBoundSignalParameters::~QQmlBoundSignalParameters()
392 void QQmlBoundSignalParameters::setValues(void **v)
397 void QQmlBoundSignalParameters::clearValues()
402 int QQmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a)
407 if (c == QMetaObject::ReadProperty && id >= 1) {
408 int t = types[id - 1];
410 QMetaType::destruct(t, p);
411 QMetaType::construct(t, p, values[id]);
414 return qt_metacall(c, id, a);
418 ////////////////////////////////////////////////////////////////////////
420 QQmlBoundSignalExpressionPointer::QQmlBoundSignalExpressionPointer(QQmlBoundSignalExpression *o)
426 QQmlBoundSignalExpressionPointer::QQmlBoundSignalExpressionPointer(const QQmlBoundSignalExpressionPointer &other)
432 QQmlBoundSignalExpressionPointer::~QQmlBoundSignalExpressionPointer()
437 QQmlBoundSignalExpressionPointer &QQmlBoundSignalExpressionPointer::operator=(const QQmlBoundSignalExpressionPointer &other)
439 if (other.o) other.o->addref();
445 QQmlBoundSignalExpressionPointer &QQmlBoundSignalExpressionPointer::operator=(QQmlBoundSignalExpression *other)
447 if (other) other->addref();
454 Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership
455 of the callers reference of other.
457 QQmlBoundSignalExpressionPointer &QQmlBoundSignalExpressionPointer::take(QQmlBoundSignalExpression *other)
466 #include <qqmlboundsignal.moc>