#include "qqml.h"
#include "qqmlcontext.h"
#include "qqmlglobal_p.h"
+#include "qqmlrewrite_p.h"
#include <private/qqmlprofilerservice_p.h>
#include <private/qv8debugservice_p.h>
QT_BEGIN_NAMESPACE
+static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = {
+ QQmlBoundSignalExpression::expressionIdentifier,
+ QQmlBoundSignalExpression::expressionChanged
+};
+
+QQmlBoundSignalExpression::QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QByteArray &expression,
+ bool isRewritten, const QString &fileName, int line, int column)
+ : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable)
+{
+ setNotifyOnValueChanged(false);
+ setContext(ctxt);
+ setScopeObject(scope);
+ m_expression = QString::fromUtf8(expression);
+ m_expressionFunctionValid = false;
+ m_expressionFunctionRewritten = isRewritten;
+ m_fileName = fileName;
+ m_line = line;
+ m_column = column;
+}
+
+QQmlBoundSignalExpression::QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QString &expression,
+ bool isRewritten, const QString &fileName, int line, int column)
+ : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable)
+{
+ setNotifyOnValueChanged(false);
+ setContext(ctxt);
+ setScopeObject(scope);
+ m_expression = expression;
+ m_expressionFunctionValid = false;
+ m_expressionFunctionRewritten = isRewritten;
+ m_fileName = fileName;
+ m_line = line;
+ m_column = column;
+}
+
+QQmlBoundSignalExpression::~QQmlBoundSignalExpression()
+{
+ qPersistentDispose(m_v8function);
+ qPersistentDispose(m_v8qmlscope);
+}
+
+QString QQmlBoundSignalExpression::expressionIdentifier(QQmlJavaScriptExpression *e)
+{
+ QQmlBoundSignalExpression *This = static_cast<QQmlBoundSignalExpression *>(e);
+ return QLatin1String("\"") + This->m_expression + QLatin1String("\"");
+}
+
+void QQmlBoundSignalExpression::expressionChanged(QQmlJavaScriptExpression *)
+{
+ // bound signals do not notify on change.
+}
+
+// This mirrors code in QQmlExpressionPrivate::value() and v8value().
+// Any change made here should be made there and vice versa.
+void QQmlBoundSignalExpression::evaluate(QObject *secondaryScope)
+{
+ Q_ASSERT (context() && engine());
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
+
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
+ {
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(ep->v8engine()->context());
+ if (!m_expressionFunctionValid) {
+ bool ok = true;
+ QString code;
+ if (m_expressionFunctionRewritten) {
+ code = m_expression;
+ } else {
+ QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
+ code = rewriteSignalHandler(m_expression, m_functionName, &ok);
+ }
+
+ if (ok)
+ m_v8function = evalFunction(context(), scopeObject(), code, m_fileName, m_line, &m_v8qmlscope);
+
+ if (m_v8function.IsEmpty() || m_v8function->IsNull()) {
+ ep->dereferenceScarceResources();
+ return; // could not evaluate function. Not valid.
+ }
+
+ setUseSharedContext(false);
+ m_expressionFunctionValid = true;
+ }
+
+ if (secondaryScope) {
+ QObject *restoreSecondaryScope = 0;
+ restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(m_v8qmlscope, secondaryScope);
+ QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0);
+ ep->v8engine()->contextWrapper()->setSecondaryScope(m_v8qmlscope, restoreSecondaryScope);
+ } else {
+ QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0);
+ }
+ }
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
+}
+
+////////////////////////////////////////////////////////////////////////
+
class QQmlBoundSignalParameters : public QObject
{
Q_OBJECT
public:
- QQmlBoundSignalParameters(const QMetaMethod &, QObject * = 0);
+ QQmlBoundSignalParameters(const QMetaMethod &, QQmlAbstractBoundSignal*);
~QQmlBoundSignalParameters();
void setValues(void **);
QMetaObject *myMetaObject;
};
-static int evaluateIdx = -1;
-
QQmlAbstractBoundSignal::QQmlAbstractBoundSignal()
: m_prevSignal(0), m_nextSignal(0)
{
QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal()
{
- if (m_prevSignal) {
- *m_prevSignal = m_nextSignal;
- if (m_nextSignal) m_nextSignal->m_prevSignal = m_prevSignal;
- m_prevSignal = 0;
- m_nextSignal = 0;
- }
+ removeFromObject();
}
-void QQmlAbstractBoundSignal::addToObject()
+void QQmlAbstractBoundSignal::addToObject(QObject *obj)
{
Q_ASSERT(!m_prevSignal);
- QObject *obj = object();
Q_ASSERT(obj);
QQmlData *data = QQmlData::get(obj, true);
data->signalHandlers = this;
}
+void QQmlAbstractBoundSignal::removeFromObject()
+{
+ if (m_prevSignal) {
+ *m_prevSignal = m_nextSignal;
+ if (m_nextSignal) m_nextSignal->m_prevSignal = m_prevSignal;
+ m_prevSignal = 0;
+ m_nextSignal = 0;
+ }
+}
+
QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal,
QObject *owner)
-: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0), m_owner(owner)
+: m_expression(0), m_params(0), m_scope(scope), m_index(signal.methodIndex()), m_paramsValid(false), m_isEvaluating(false)
{
- // This is thread safe. Although it may be updated by two threads, they
- // will both set it to the same value - so the worst thing that can happen
- // is that they both do the work to figure it out. Boo hoo.
- if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
-
- QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
+ addToObject(owner);
+ callback = &subscriptionCallback;
+ QQmlNotifierEndpoint::connect(scope, m_index);
}
QQmlBoundSignal::~QQmlBoundSignal()
{
delete m_expression;
m_expression = 0;
+ delete m_params;
}
-int QQmlBoundSignal::index() const
-{
- return m_signal.methodIndex();
+int QQmlBoundSignal::index() const
+{
+ return m_index;
}
/*!
Returns the signal expression.
*/
-QQmlExpression *QQmlBoundSignal::expression() const
+QQmlBoundSignalExpression *QQmlBoundSignal::expression() const
{
return m_expression;
}
The QQmlBoundSignal instance takes ownership of \a e. The caller is
assumes ownership of the returned QQmlExpression.
*/
-QQmlExpression *QQmlBoundSignal::setExpression(QQmlExpression *e)
+QQmlBoundSignalExpression *QQmlBoundSignal::setExpression(QQmlBoundSignalExpression *e)
{
- QQmlExpression *rv = m_expression;
+ QQmlBoundSignalExpression *rv = m_expression;
m_expression = e;
if (m_expression) m_expression->setNotifyOnValueChanged(false);
return rv;
}
-int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a)
+void QQmlBoundSignal::subscriptionCallback(QQmlNotifierEndpoint *e, void **a)
{
- if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) {
- if (!m_expression)
- return -1;
+ QQmlBoundSignal *s = static_cast<QQmlBoundSignal*>(e);
+ if (!s->m_expression)
+ return;
- if (QQmlDebugService::isDebuggingEnabled())
- QV8DebugService::instance()->signalEmitted(QString::fromAscii(m_signal.signature()));
+ if (QQmlDebugService::isDebuggingEnabled())
+ QV8DebugService::instance()->signalEmitted(QString::fromAscii(s->m_scope->metaObject()->method(s->m_index).methodSignature()));
- QQmlHandlingSignalProfiler prof(m_signal, m_expression);
+ QQmlHandlingSignalProfiler prof(s->m_scope, s->m_index, s->m_expression);
- m_isEvaluating = true;
- if (!m_paramsValid) {
- if (!m_signal.parameterTypes().isEmpty())
- m_params = new QQmlBoundSignalParameters(m_signal, this);
- m_paramsValid = true;
- }
+ s->m_isEvaluating = true;
- if (m_params) m_params->setValues(a);
- if (m_expression && m_expression->engine()) {
- QQmlExpressionPrivate::get(m_expression)->value(m_params);
- if (m_expression && m_expression->hasError())
- QQmlEnginePrivate::warning(m_expression->engine(), m_expression->error());
- }
- if (m_params) m_params->clearValues();
- m_isEvaluating = false;
- return -1;
- } else {
- return QObject::qt_metacall(c, id, a);
+ if (!s->m_paramsValid) {
+ QMetaMethod signal = s->m_scope->metaObject()->method(s->m_index);
+ if (!signal.parameterTypes().isEmpty())
+ s->m_params = new QQmlBoundSignalParameters(signal, s);
+ s->m_paramsValid = true;
+ }
+
+ if (s->m_params) s->m_params->setValues(a);
+ if (s->m_expression && s->m_expression->engine()) {
+ s->m_expression->evaluate(s->m_params);
+ if (s->m_expression && s->m_expression->hasError())
+ QQmlEnginePrivate::warning(s->m_expression->engine(), s->m_expression->error());
}
+ if (s->m_params) s->m_params->clearValues();
+
+ s->m_isEvaluating = false;
}
QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method,
- QObject *parent)
-: QObject(parent), types(0), values(0)
+ QQmlAbstractBoundSignal *owner)
+: types(0), values(0)
{
MetaObject *mo = new MetaObject(this);
continue;
}
- QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData());
+ int t = QMetaType::type(type.constData());
if (QQmlMetaType::isQObject(t)) {
types[ii] = QMetaType::QObjectStar;
QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*");
if (flags & QMetaType::IsEnumeration) {
t = QVariant::Int;
propType = "int";
- } else if (t == QVariant::Invalid ||
- (t >= QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
+ } else if (t == QMetaType::UnknownType ||
+ (t >= int(QMetaType::User) && !(flags & QMetaType::PointerToQObject) &&
t != qMetaTypeId<QJSValue>())) {
//the UserType clause is to catch registered QFlags
QByteArray scope;
if (scope == "Qt")
meta = &QObject::staticQtMetaObject;
else
- meta = static_cast<QQmlBoundSignal*>(parent)->object()->metaObject();
+ meta = owner->scope()->metaObject();
for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
QMetaEnum m = meta->enumerator(i);
if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) {
}
}
-////////////////////////////////////////////////////////////////////////
-
-QQmlBoundSignalNoParams::QQmlBoundSignalNoParams(QObject *scope, const QMetaMethod &signal,
- QObject *owner)
-: m_expression(0), m_owner(owner), m_index(signal.methodIndex()), m_isEvaluating(false)
-{
- callback = &subscriptionCallback;
- QQmlNotifierEndpoint::connect(scope, m_index);
-}
-
-QQmlBoundSignalNoParams::~QQmlBoundSignalNoParams()
-{
- delete m_expression;
- m_expression = 0;
-}
-
-int QQmlBoundSignalNoParams::index() const
-{
- return m_index;
-}
-
-/*!
- Returns the signal expression.
-*/
-QQmlExpression *QQmlBoundSignalNoParams::expression() const
-{
- return m_expression;
-}
-
-/*!
- Sets the signal expression to \a e. Returns the current signal expression,
- or null if there is no signal expression.
-
- The QQmlBoundSignalNoParams instance takes ownership of \a e. The caller is
- assumes ownership of the returned QQmlExpression.
-*/
-QQmlExpression *QQmlBoundSignalNoParams::setExpression(QQmlExpression *e)
-{
- QQmlExpression *rv = m_expression;
- m_expression = e;
- if (m_expression) m_expression->setNotifyOnValueChanged(false);
- return rv;
-}
-
-void QQmlBoundSignalNoParams::subscriptionCallback(QQmlNotifierEndpoint *e)
-{
- QQmlBoundSignalNoParams *s = static_cast<QQmlBoundSignalNoParams*>(e);
- if (!s->m_expression)
- return;
-
- if (QQmlDebugService::isDebuggingEnabled())
- QV8DebugService::instance()->signalEmitted(QString::fromAscii(s->m_owner->metaObject()->method(s->m_index).signature()));
-
- QQmlHandlingSignalProfiler prof(s->m_owner, s->m_index, s->m_expression);
-
- s->m_isEvaluating = true;
-
- if (s->m_expression && s->m_expression->engine()) {
- QQmlExpressionPrivate::get(s->m_expression)->value();
- if (s->m_expression && s->m_expression->hasError())
- QQmlEnginePrivate::warning(s->m_expression->engine(), s->m_expression->error());
- }
- s->m_isEvaluating = false;
-}
-
QT_END_NAMESPACE
#include <qqmlboundsignal.moc>