aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlboundsignal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlboundsignal.cpp')
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp318
1 files changed, 120 insertions, 198 deletions
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 766e657c59..477a517e32 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -43,11 +43,12 @@
#include "qqmlcontext.h"
#include "qqmlglobal_p.h"
#include <private/qqmlprofiler_p.h>
-#include <private/qv4debugservice_p.h>
+#include <private/qqmldebugconnector_p.h>
+#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmlcompiler_p.h>
#include "qqmlinfo.h"
-#include <private/qv4value_inl_p.h>
+#include <private/qv4value_p.h>
#include <QtCore/qstringbuilder.h>
#include <QtCore/qdebug.h>
@@ -55,71 +56,79 @@
QT_BEGIN_NAMESPACE
-static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = {
- QQmlBoundSignalExpression::expressionIdentifier,
- QQmlBoundSignalExpression::expressionChanged
-};
-
-QQmlBoundSignalExpression::ExtraData::ExtraData(const QString &handlerName, const QString &parameterString,
- const QString &expression, const QString &fileName,
- quint16 line, quint16 column)
- : m_handlerName(handlerName),
- m_parameterString(parameterString),
- m_expression(expression),
- m_sourceLocation(fileName, line, column)
-{
-}
-
QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
QQmlContextData *ctxt, QObject *scope, const QString &expression,
const QString &fileName, quint16 line, quint16 column,
const QString &handlerName,
const QString &parameterString)
- : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
+ : QQmlJavaScriptExpression(),
m_index(index),
- m_target(target),
- m_extra(new ExtraData(handlerName, parameterString, expression, fileName, line, column))
+ m_target(target)
{
- setExpressionFunctionValid(false);
- setInvalidParameterName(false);
-
init(ctxt, scope);
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
+ QV4::ExecutionEngine *v4 = ep->v4engine();
+
+ QString function;
+
+ // Add some leading whitespace to account for the binding's column offset.
+ // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted.
+ function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2);
+ function += QStringLiteral("(function ");
+ function += handlerName;
+ function += QLatin1Char('(');
+
+ if (parameterString.isEmpty()) {
+ QString error;
+ //TODO: look at using the property cache here (as in the compiler)
+ // for further optimization
+ QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
+ function += QQmlPropertyCache::signalParameterStringForJS(v4, signal.parameterNames(), &error);
+
+ if (!error.isEmpty()) {
+ qmlInfo(scopeObject()) << error;
+ return;
+ }
+ } else
+ function += parameterString;
+
+ function += QStringLiteral(") { ");
+ function += expression;
+ function += QStringLiteral(" })");
+
+ m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line));
+
+ if (m_function.isNullOrUndefined())
+ return; // could not evaluate function. Not valid.
+
}
QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::Value &function)
- : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
+ : QQmlJavaScriptExpression(),
m_index(index),
- m_function(function.asObject()->engine(), function),
- m_target(target),
- m_extra(0)
+ m_target(target)
{
- setExpressionFunctionValid(true);
- setInvalidParameterName(false);
-
+ m_function.set(function.as<QV4::Object>()->engine(), function);
init(ctxt, scope);
}
QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction)
- : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
+ : QQmlJavaScriptExpression(),
m_index(index),
- m_target(target),
- m_extra(0)
+ m_target(target)
{
- setExpressionFunctionValid(true);
- setInvalidParameterName(false);
-
// It's important to call init first, because m_index gets remapped in case of cloned signals.
init(ctxt, scope);
QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
QString error;
QV4::ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(ctxt->engine);
- m_function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error));
+ m_function.set(engine, QV4::FunctionObject::createQmlFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error));
if (!error.isEmpty()) {
qmlInfo(scopeObject()) << error;
- setInvalidParameterName(true);
- } else
- setInvalidParameterName(false);
+ m_function.clear();
+ }
}
void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope)
@@ -134,34 +143,30 @@ void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope)
QQmlBoundSignalExpression::~QQmlBoundSignalExpression()
{
- delete m_extra.data();
}
-QString QQmlBoundSignalExpression::expressionIdentifier(QQmlJavaScriptExpression *e)
+QString QQmlBoundSignalExpression::expressionIdentifier()
{
- QQmlBoundSignalExpression *This = static_cast<QQmlBoundSignalExpression *>(e);
- QQmlSourceLocation loc = This->sourceLocation();
+ QQmlSourceLocation loc = sourceLocation();
return loc.sourceFile + QLatin1Char(':') + QString::number(loc.line);
}
-void QQmlBoundSignalExpression::expressionChanged(QQmlJavaScriptExpression *)
+void QQmlBoundSignalExpression::expressionChanged()
{
// bound signals do not notify on change.
}
QQmlSourceLocation QQmlBoundSignalExpression::sourceLocation() const
{
- if (expressionFunctionValid()) {
- QV4::Function *f = function();
- Q_ASSERT(f);
+ QV4::Function *f = function();
+ if (f) {
QQmlSourceLocation loc;
loc.sourceFile = f->sourceFile();
loc.line = f->compiledFunction->location.line;
loc.column = f->compiledFunction->location.column;
return loc;
}
- Q_ASSERT(!m_extra.isNull());
- return m_extra->m_sourceLocation;
+ return QQmlSourceLocation();
}
QString QQmlBoundSignalExpression::expression() const
@@ -171,10 +176,8 @@ QString QQmlBoundSignalExpression::expression() const
QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine());
QV4::ScopedValue v(scope, m_function.value());
return v->toQStringNoThrow();
- } else {
- Q_ASSERT(!m_extra.isNull());
- return m_extra->m_expression;
}
+ return QString();
}
QV4::Function *QQmlBoundSignalExpression::function() const
@@ -194,108 +197,79 @@ void QQmlBoundSignalExpression::evaluate(void **a)
{
Q_ASSERT (context() && engine());
- if (invalidParameterName())
+ if (!expressionFunctionValid())
return;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
QV4::Scope scope(ep->v4engine());
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- {
- if (!expressionFunctionValid()) {
- Q_ASSERT(!m_extra.isNull());
- QString expression;
-
- // Add some leading whitespace to account for the binding's column offset.
- // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted.
- expression.fill(QChar(QChar::Space), qMax(m_extra->m_sourceLocation.column, (quint16)2) - 2);
- expression += QStringLiteral("(function ");
- expression += m_extra->m_handlerName;
- expression += QLatin1Char('(');
-
- if (m_extra->m_parameterString.isEmpty()) {
- QString error;
- //TODO: look at using the property cache here (as in the compiler)
- // for further optimization
- QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
- expression += QQmlPropertyCache::signalParameterStringForJS(scope.engine, signal.parameterNames(), &error);
-
- if (!error.isEmpty()) {
- qmlInfo(scopeObject()) << error;
- setInvalidParameterName(true);
- ep->dereferenceScarceResources();
- return;
- }
- } else
- expression += m_extra->m_parameterString;
-
- expression += QStringLiteral(") { ");
- expression += m_extra->m_expression;
- expression += QStringLiteral(" })");
-
- m_extra->m_expression.clear();
- m_extra->m_handlerName.clear();
- m_extra->m_parameterString.clear();
-
- m_function.set(scope.engine, evalFunction(context(), scopeObject(), expression,
- m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_extra->m_v8qmlscope));
-
- if (m_function.isNullOrUndefined()) {
- ep->dereferenceScarceResources();
- return; // could not evaluate function. Not valid.
- }
-
- setExpressionFunctionValid(true);
- }
- QVarLengthArray<int, 9> dummy;
- //TODO: lookup via signal index rather than method index as an optimization
- int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
- int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0);
- int argCount = argsTypes ? *argsTypes : 0;
-
- QV4::ScopedValue f(scope, m_function.value());
- QV4::ScopedCallData callData(scope, argCount);
- for (int ii = 0; ii < argCount; ++ii) {
- int type = argsTypes[ii + 1];
- //### ideally we would use metaTypeToJS, however it currently gives different results
- // for several cases (such as QVariant type and QObject-derived types)
- //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
- if (type == QMetaType::QVariant) {
- callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1]));
- } else if (type == QMetaType::Int) {
- //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
- callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1]));
- } else if (type == qMetaTypeId<QQmlV4Handle>()) {
- callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]);
- } else if (ep->isQObject(type)) {
- if (!*reinterpret_cast<void* const *>(a[ii + 1]))
- callData->args[ii] = QV4::Primitive::nullValue();
- else
- callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1]));
- } else {
- callData->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1]));
- }
+ QVarLengthArray<int, 9> dummy;
+ //TODO: lookup via signal index rather than method index as an optimization
+ int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
+ int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0);
+ int argCount = argsTypes ? *argsTypes : 0;
+
+ QV4::ScopedCallData callData(scope, argCount);
+ for (int ii = 0; ii < argCount; ++ii) {
+ int type = argsTypes[ii + 1];
+ //### ideally we would use metaTypeToJS, however it currently gives different results
+ // for several cases (such as QVariant type and QObject-derived types)
+ //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
+ if (type == QMetaType::QVariant) {
+ callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1]));
+ } else if (type == QMetaType::Int) {
+ //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
+ callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1]));
+ } else if (type == qMetaTypeId<QQmlV4Handle>()) {
+ callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]);
+ } else if (ep->isQObject(type)) {
+ if (!*reinterpret_cast<void* const *>(a[ii + 1]))
+ callData->args[ii] = QV4::Primitive::nullValue();
+ else
+ callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1]));
+ } else {
+ callData->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1]));
}
-
- QQmlJavaScriptExpression::evaluate(context(), f, callData, 0);
}
+
+ QQmlJavaScriptExpression::evaluate(callData, 0);
+
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
////////////////////////////////////////////////////////////////////////
-QQmlAbstractBoundSignal::QQmlAbstractBoundSignal()
-: m_prevSignal(0), m_nextSignal(0)
+
+/*! \internal
+ \a signal MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+ This is different from QMetaMethod::methodIndex().
+*/
+QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner,
+ QQmlEngine *engine)
+ : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlBoundSignal),
+ m_prevSignal(0), m_nextSignal(0),
+ m_expression(0)
{
+ addToObject(owner);
+
+ /*
+ If this is a cloned method, connect to the 'original'. For example,
+ for the signal 'void aSignal(int parameter = 0)', if the method
+ index refers to 'aSignal()', get the index of 'aSignal(int)'.
+ This ensures that 'parameter' will be available from QML.
+ */
+ signal = QQmlPropertyCache::originalClone(target, signal);
+ QQmlNotifierEndpoint::connect(target, signal, engine);
}
-QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal()
+QQmlBoundSignal::~QQmlBoundSignal()
{
removeFromObject();
}
-void QQmlAbstractBoundSignal::addToObject(QObject *obj)
+void QQmlBoundSignal::addToObject(QObject *obj)
{
Q_ASSERT(!m_prevSignal);
Q_ASSERT(obj);
@@ -308,7 +282,7 @@ void QQmlAbstractBoundSignal::addToObject(QObject *obj)
data->signalHandlers = this;
}
-void QQmlAbstractBoundSignal::removeFromObject()
+void QQmlBoundSignal::removeFromObject()
{
if (m_prevSignal) {
*m_prevSignal = m_nextSignal;
@@ -318,40 +292,6 @@ void QQmlAbstractBoundSignal::removeFromObject()
}
}
-/*! \internal
- \a signal MUST be in the signal index range (see QObjectPrivate::signalIndex()).
- This is different from QMetaMethod::methodIndex().
-*/
-QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner,
- QQmlEngine *engine)
-: m_expression(0), m_index(signal), m_isEvaluating(false)
-{
- addToObject(owner);
- setCallback(QQmlNotifierEndpoint::QQmlBoundSignal);
-
- /*
- If this is a cloned method, connect to the 'original'. For example,
- for the signal 'void aSignal(int parameter = 0)', if the method
- index refers to 'aSignal()', get the index of 'aSignal(int)'.
- This ensures that 'parameter' will be available from QML.
- */
- m_index = QQmlPropertyCache::originalClone(target, m_index);
- QQmlNotifierEndpoint::connect(target, m_index, engine);
-}
-
-QQmlBoundSignal::~QQmlBoundSignal()
-{
- m_expression = 0;
-}
-
-/*!
- Returns the signal index in the range returned by QObjectPrivate::signalIndex().
- This is different from QMetaMethod::methodIndex().
-*/
-int QQmlBoundSignal::index() const
-{
- return m_index;
-}
/*!
Returns the signal expression.
@@ -362,45 +302,29 @@ QQmlBoundSignalExpression *QQmlBoundSignal::expression() const
}
/*!
- Sets the signal expression to \a e. Returns the current signal expression,
- or null if there is no signal expression.
+ Sets the signal expression to \a e.
- The QQmlBoundSignal instance adds a reference to \a e. The caller
- assumes ownership of the returned QQmlBoundSignalExpression reference.
+ The QQmlBoundSignal instance takes ownership of \a e (and does not add a reference).
*/
-QQmlBoundSignalExpressionPointer QQmlBoundSignal::setExpression(QQmlBoundSignalExpression *e)
+void QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e)
{
- QQmlBoundSignalExpressionPointer rv = m_expression;
- m_expression = e;
- if (m_expression) m_expression->setNotifyOnValueChanged(false);
- return rv;
-}
-
-/*!
- Sets the signal expression to \a e. Returns the current signal expression,
- or null if there is no signal expression.
-
- The QQmlBoundSignal instance takes ownership of \a e (and does not add a reference). The caller
- assumes ownership of the returned QQmlBoundSignalExpression reference.
-*/
-QQmlBoundSignalExpressionPointer QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e)
-{
- QQmlBoundSignalExpressionPointer rv = m_expression;
m_expression.take(e);
- if (m_expression) m_expression->setNotifyOnValueChanged(false);
- return rv;
+ if (m_expression)
+ m_expression->setNotifyOnValueChanged(false);
}
void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a)
{
QQmlBoundSignal *s = static_cast<QQmlBoundSignal*>(e);
+
if (!s->m_expression)
return;
- if (QQmlDebugService::isDebuggingEnabled())
- QV4DebugService::instance()->signalEmitted(QString::fromLatin1(QMetaObjectPrivate::signal(s->m_expression->target()->metaObject(), s->m_index).methodSignature()));
-
- s->m_isEvaluating = true;
+ QV4DebugService *service = QQmlDebugConnector::service<QV4DebugService>();
+ if (service)
+ service->signalEmitted(QString::fromLatin1(QMetaObjectPrivate::signal(
+ s->m_expression->target()->metaObject(),
+ s->signalIndex()).methodSignature()));
QQmlEngine *engine;
if (s->m_expression && (engine = s->m_expression->engine())) {
@@ -410,8 +334,6 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a)
QQmlEnginePrivate::warning(engine, s->m_expression->error(engine));
}
}
-
- s->m_isEvaluating = false;
}
////////////////////////////////////////////////////////////////////////