From 53d5deb5034bf5adb8719723bc66eb3a61638a32 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Tue, 27 Mar 2012 16:56:08 +1000 Subject: Use minimal javascript expression for bound signals Previously, QQmlBoundSignal used QQmlExpression internally. This commit adds a new, more optimal QQmlJavaScriptExpression subclass specifically designed for QQmlBoundSignal, and converts the code to use it instead of QQmlExpression where appropriate. Task-number: QTBUG-24460 Change-Id: I2865a119ce840235e27a7722d8052ca61c265f69 Reviewed-by: Michael Brasser --- src/qml/debugger/qqmlenginedebugservice.cpp | 6 +- src/qml/debugger/qqmlprofilerservice_p.h | 8 +- src/qml/qml/qqmlabstractexpression_p.h | 2 +- src/qml/qml/qqmlboundsignal.cpp | 119 +++++++++++++++++++++++--- src/qml/qml/qqmlboundsignal_p.h | 57 ++++++++++--- src/qml/qml/qqmlexpression.cpp | 21 ++--- src/qml/qml/qqmlexpression_p.h | 4 +- src/qml/qml/qqmlproperty.cpp | 8 +- src/qml/qml/qqmlproperty_p.h | 8 +- src/qml/qml/qqmlrewrite.cpp | 15 ++++ src/qml/qml/qqmlrewrite_p.h | 1 + src/qml/qml/qqmlvme.cpp | 4 +- src/quick/util/qquickconnections.cpp | 4 +- src/quick/util/qquickpropertychanges.cpp | 124 +++++++++++++++++++--------- 14 files changed, 282 insertions(+), 99 deletions(-) (limited to 'src') diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp index 2dbabdbf56..4ae956a14f 100644 --- a/src/qml/debugger/qqmlenginedebugservice.cpp +++ b/src/qml/debugger/qqmlenginedebugservice.cpp @@ -264,7 +264,7 @@ void QQmlEngineDebugService::buildObjectDump(QDataStream &message, QQmlObjectProperty prop; prop.type = QQmlObjectProperty::SignalProperty; prop.hasNotifySignal = false; - QQmlExpression *expr = signalHandler->expression(); + QQmlBoundSignalExpression *expr = signalHandler->expression(); if (expr) { prop.value = expr->expression(); QObject *scope = expr->scopeObject(); @@ -605,9 +605,9 @@ bool QQmlEngineDebugService::setBinding(int objectId, if (isLiteralValue) { property.write(expression); } else if (hasValidSignal(object, propertyName)) { - QQmlExpression *qmlExpression = new QQmlExpression(context, object, expression.toString()); + QQmlBoundSignalExpression *qmlExpression = new QQmlBoundSignalExpression(QQmlContextData::get(context), object, expression.toString(), + false, filename, line, column); QQmlPropertyPrivate::setSignalExpression(property, qmlExpression); - qmlExpression->setSourceLocation(filename, line, column); } else if (property.isProperty()) { QQmlBinding *binding = new QQmlBinding(expression.toString(), false, object, QQmlContextData::get(context), filename, line, column);; binding->setTarget(property); diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h index 20376433f0..a9882463d4 100644 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ b/src/qml/debugger/qqmlprofilerservice_p.h @@ -54,7 +54,7 @@ // #include -#include "qqmlexpression.h" +#include #include #include @@ -201,7 +201,7 @@ struct QQmlBindingProfiler { }; struct QQmlHandlingSignalProfiler { - QQmlHandlingSignalProfiler(const QMetaMethod &signal, QQmlExpression *expression) + QQmlHandlingSignalProfiler(const QMetaMethod &signal, QQmlBoundSignalExpression *expression) { enabled = QQmlProfilerService::instance ? QQmlProfilerService::instance->profilingEnabled() : false; @@ -209,7 +209,7 @@ struct QQmlHandlingSignalProfiler { init(signal, expression); } - QQmlHandlingSignalProfiler(QObject *object, int index, QQmlExpression *expression) + QQmlHandlingSignalProfiler(QObject *object, int index, QQmlBoundSignalExpression *expression) { enabled = QQmlProfilerService::instance ? QQmlProfilerService::instance->profilingEnabled() : false; @@ -226,7 +226,7 @@ struct QQmlHandlingSignalProfiler { bool enabled; private: - void init(const QMetaMethod &signal, QQmlExpression *expression) + void init(const QMetaMethod &signal, QQmlBoundSignalExpression *expression) { QQmlProfilerService *service = QQmlProfilerService::instance; service->startRange(QQmlProfilerService::HandlingSignal); diff --git a/src/qml/qml/qqmlabstractexpression_p.h b/src/qml/qml/qqmlabstractexpression_p.h index fe2ee1762b..1d5ecac08e 100644 --- a/src/qml/qml/qqmlabstractexpression_p.h +++ b/src/qml/qml/qqmlabstractexpression_p.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE -class QQmlAbstractExpression +class Q_QML_PRIVATE_EXPORT QQmlAbstractExpression { public: QQmlAbstractExpression(); diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index b375a70d50..446bad855a 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -49,6 +49,7 @@ #include "qqml.h" #include "qqmlcontext.h" #include "qqmlglobal_p.h" +#include "qqmlrewrite_p.h" #include #include @@ -59,6 +60,105 @@ Q_DECLARE_METATYPE(QJSValue) 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(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 @@ -144,7 +244,7 @@ int QQmlBoundSignal::index() const /*! Returns the signal expression. */ -QQmlExpression *QQmlBoundSignal::expression() const +QQmlBoundSignalExpression *QQmlBoundSignal::expression() const { return m_expression; } @@ -156,9 +256,9 @@ QQmlExpression *QQmlBoundSignal::expression() const 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; @@ -183,8 +283,8 @@ int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) } 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->context() && m_expression->engine()) { + m_expression->evaluate(m_params); if (m_expression && m_expression->hasError()) QQmlEnginePrivate::warning(m_expression->engine(), m_expression->error()); } @@ -324,7 +424,7 @@ int QQmlBoundSignalNoParams::index() const /*! Returns the signal expression. */ -QQmlExpression *QQmlBoundSignalNoParams::expression() const +QQmlBoundSignalExpression *QQmlBoundSignalNoParams::expression() const { return m_expression; } @@ -336,9 +436,9 @@ QQmlExpression *QQmlBoundSignalNoParams::expression() const The QQmlBoundSignalNoParams instance takes ownership of \a e. The caller is assumes ownership of the returned QQmlExpression. */ -QQmlExpression *QQmlBoundSignalNoParams::setExpression(QQmlExpression *e) +QQmlBoundSignalExpression *QQmlBoundSignalNoParams::setExpression(QQmlBoundSignalExpression *e) { - QQmlExpression *rv = m_expression; + QQmlBoundSignalExpression *rv = m_expression; m_expression = e; if (m_expression) m_expression->setNotifyOnValueChanged(false); return rv; @@ -356,9 +456,8 @@ void QQmlBoundSignalNoParams::subscriptionCallback(QQmlNotifierEndpoint *e) 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(); + s->m_expression->evaluate(); // evaluate signal expression. if (s->m_expression && s->m_expression->hasError()) QQmlEnginePrivate::warning(s->m_expression->engine(), s->m_expression->error()); } diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index 5fc8c3522f..22cc5a9f83 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -53,15 +53,52 @@ // We mean it. // -#include "qqmlexpression.h" - #include +#include +#include #include #include QT_BEGIN_NAMESPACE +class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlAbstractExpression, public QQmlJavaScriptExpression +{ +public: + QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QByteArray &expression, + bool isRewritten, const QString &fileName, int line, int column); + QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QString &expression, + bool isRewritten, const QString &fileName, int line, int column); + ~QQmlBoundSignalExpression(); + + // "inherited" from QQmlJavaScriptExpression. + static QString expressionIdentifier(QQmlJavaScriptExpression *); + static void expressionChanged(QQmlJavaScriptExpression *); + + // evaluation of a bound signal expression doesn't return any value + void evaluate(QObject *secondaryScope = 0); + + QString sourceFile() const { return m_fileName; } + int lineNumber() const { return m_line; } + int columnNumber() const { return m_column; } + QString expression() const { return m_expression; } + + QQmlEngine *engine() const { return context() ? context()->engine : 0; } + +private: + v8::Persistent m_v8qmlscope; + v8::Persistent m_v8function; + + QString m_expression; + QString m_functionName; // hint for debugger + QString m_fileName; + int m_line; + int m_column; + + bool m_expressionFunctionValid:1; + bool m_expressionFunctionRewritten:1; +}; + class Q_QML_EXPORT QQmlAbstractBoundSignal { public: @@ -69,8 +106,8 @@ public: virtual ~QQmlAbstractBoundSignal(); virtual int index() const = 0; - virtual QQmlExpression *expression() const = 0; - virtual QQmlExpression *setExpression(QQmlExpression *) = 0; + virtual QQmlBoundSignalExpression *expression() const = 0; + virtual QQmlBoundSignalExpression *setExpression(QQmlBoundSignalExpression *) = 0; virtual QObject *object() = 0; void addToObject(); @@ -93,8 +130,8 @@ public: int index() const; - QQmlExpression *expression() const; - QQmlExpression *setExpression(QQmlExpression *); + QQmlBoundSignalExpression *expression() const; + QQmlBoundSignalExpression *setExpression(QQmlBoundSignalExpression *); QObject *object() { return m_owner; } bool isEvaluating() const { return m_isEvaluating; } @@ -103,7 +140,7 @@ protected: virtual int qt_metacall(QMetaObject::Call c, int id, void **a); private: - QQmlExpression *m_expression; + QQmlBoundSignalExpression *m_expression; QMetaMethod m_signal; bool m_paramsValid : 1; bool m_isEvaluating : 1; @@ -120,8 +157,8 @@ public: int index() const; - QQmlExpression *expression() const; - QQmlExpression *setExpression(QQmlExpression *); + QQmlBoundSignalExpression *expression() const; + QQmlBoundSignalExpression *setExpression(QQmlBoundSignalExpression *); QObject *object() { return m_owner; } static void subscriptionCallback(QQmlNotifierEndpoint *e); @@ -129,7 +166,7 @@ public: bool isEvaluating() const { return m_isEvaluating; } private: - QQmlExpression *m_expression; + QQmlBoundSignalExpression *m_expression; QObject *m_owner; int m_index; bool m_isEvaluating; diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index d760486605..6e20047cf0 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -351,7 +351,7 @@ void QQmlExpression::setExpression(const QString &expression) } // Must be called with a valid handle scope -v8::Local QQmlExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined) +v8::Local QQmlExpressionPrivate::v8value(bool *isUndefined) { if (!expressionFunctionValid) { bool ok = true; @@ -369,21 +369,10 @@ v8::Local QQmlExpressionPrivate::v8value(QObject *secondaryScope, boo expressionFunctionValid = true; } - - if (secondaryScope) { - v8::Local result; - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); - QObject *restoreSecondaryScope = 0; - restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope); - result = evaluate(context(), v8function, isUndefined); - ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope); - return result; - } else { - return evaluate(context(), v8function, isUndefined); - } + return evaluate(context(), v8function, isUndefined); } -QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) +QVariant QQmlExpressionPrivate::value(bool *isUndefined) { Q_Q(QQmlExpression); @@ -400,7 +389,7 @@ QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined { v8::HandleScope handle_scope; v8::Context::Scope context_scope(ep->v8engine()->context()); - v8::Local result = v8value(secondaryScope, isUndefined); + v8::Local result = v8value(isUndefined); rv = ep->v8engine()->toVariant(result, qMetaTypeId >()); } @@ -421,7 +410,7 @@ QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined QVariant QQmlExpression::evaluate(bool *valueIsUndefined) { Q_D(QQmlExpression); - return d->value(0, valueIsUndefined); + return d->value(valueIsUndefined); } /*! diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index 186e3aebf9..d3d27f259d 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -82,9 +82,9 @@ public: void init(QQmlContextData *, const QString &, bool, QObject *, const QString &, int, int); void init(QQmlContextData *, const QByteArray &, bool, QObject *, const QString &, int, int); - QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); + QVariant value(bool *isUndefined = 0); - v8::Local v8value(QObject *secondaryScope = 0, bool *isUndefined = 0); + v8::Local v8value(bool *isUndefined = 0); static inline QQmlExpressionPrivate *get(QQmlExpression *expr); static inline QQmlExpression *get(QQmlExpressionPrivate *expr); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index b798215fa5..1b01a7d7c1 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -920,7 +920,7 @@ QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valu Returns the expression associated with this signal property, or 0 if no signal expression exists. */ -QQmlExpression * +QQmlBoundSignalExpression * QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) { if (!(that.type() & QQmlProperty::SignalProperty)) @@ -948,9 +948,9 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) Ownership of \a expr transfers to QML. Ownership of the return value is assumed by the caller. */ -QQmlExpression * +QQmlBoundSignalExpression * QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, - QQmlExpression *expr) + QQmlBoundSignalExpression *expr) { if (!(that.type() & QQmlProperty::SignalProperty)) { delete expr; @@ -975,7 +975,7 @@ QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object); else signal = new QQmlBoundSignalNoParams(that.d->object, that.method(), that.d->object); - QQmlExpression *oldExpr = signal->setExpression(expr); + QQmlBoundSignalExpression *oldExpr = signal->setExpression(expr); signal->addToObject(); return oldExpr; } else { diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index f4a9ced53b..e33c95ae41 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE class QQmlContext; -class QQmlExpression; +class QQmlBoundSignalExpression; class QQmlEnginePrivate; class QQmlJavaScriptExpression; class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount @@ -140,9 +140,9 @@ public: static QQmlAbstractBinding *setBinding(const QQmlProperty &that, QQmlAbstractBinding *, WriteFlags flags = DontRemoveBinding); - static QQmlExpression *signalExpression(const QQmlProperty &that); - static QQmlExpression *setSignalExpression(const QQmlProperty &that, - QQmlExpression *) ; + static QQmlBoundSignalExpression *signalExpression(const QQmlProperty &that); + static QQmlBoundSignalExpression *setSignalExpression(const QQmlProperty &that, + QQmlBoundSignalExpression *) ; static bool write(const QQmlProperty &that, const QVariant &, WriteFlags); static bool writeBinding(QObject *, const QQmlPropertyData &, QQmlContextData *context, diff --git a/src/qml/qml/qqmlrewrite.cpp b/src/qml/qml/qqmlrewrite.cpp index 72bd23955b..0bd8597ec4 100644 --- a/src/qml/qml/qqmlrewrite.cpp +++ b/src/qml/qml/qqmlrewrite.cpp @@ -419,6 +419,21 @@ QString RewriteSignalHandler::operator()(QQmlJS::AST::Node *node, const QString return rewritten; } +QString RewriteSignalHandler::operator()(const QString &code, const QString &name, bool *ok) +{ + Engine engine; + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + if (!parser.statement()) { + if (ok) *ok = false; + return QString(); + } + if (ok) *ok = true; + return operator()(parser.statement(), code, name); +} + } // namespace QQmlRewrite QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlrewrite_p.h b/src/qml/qml/qqmlrewrite_p.h index 1d69839878..73ff50a040 100644 --- a/src/qml/qml/qqmlrewrite_p.h +++ b/src/qml/qml/qqmlrewrite_p.h @@ -133,6 +133,7 @@ class RewriteSignalHandler: protected AST::Visitor public: RewriteSignalHandler(); QString operator()(QQmlJS::AST::Node *node, const QString &code, const QString &name); + QString operator()(const QString &code, const QString &name, bool *ok = 0); protected: void rewriteMultilineStrings(QString &code); diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 6010adfcfc..5a9fa40771 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -716,8 +716,8 @@ QObject *QQmlVME::run(QList *errors, bs = new QQmlBoundSignal(target, signal, target); else bs = new QQmlBoundSignalNoParams(target, signal, target); - QQmlExpression *expr = - new QQmlExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column, *new QQmlExpressionPrivate); + QQmlBoundSignalExpression *expr = + new QQmlBoundSignalExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column); bs->setExpression(expr); bs->addToObject(); QML_END_INSTR(StoreSignal) diff --git a/src/quick/util/qquickconnections.cpp b/src/quick/util/qquickconnections.cpp index acc9738f2c..2ba34a24c3 100644 --- a/src/quick/util/qquickconnections.cpp +++ b/src/quick/util/qquickconnections.cpp @@ -280,8 +280,8 @@ void QQuickConnections::connectSignals() location = ddata->outerContext->urlString; } - QQmlExpression *expression = ctxtdata ? - QQmlExpressionPrivate::create(ctxtdata, 0, script, true, location, line, column) : 0; + QQmlBoundSignalExpression *expression = ctxtdata ? + new QQmlBoundSignalExpression(ctxtdata, 0, script, true, location, line, column) : 0; signal->setExpression(expression); signal->addToObject(); d->boundsignals += signal; diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index 8b0818c96c..4bff006d9b 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include @@ -139,7 +140,7 @@ class QQuickReplaceSignalHandler : public QQuickActionEvent { public: QQuickReplaceSignalHandler() : expression(0), reverseExpression(0), - rewindExpression(0), ownedExpression(0) {} + rewindExpression(0), ownedExpression(0), ownedExpressionWatcher(0) {} ~QQuickReplaceSignalHandler() { delete ownedExpression; } @@ -147,22 +148,35 @@ public: virtual EventType type() const { return SignalHandler; } QQmlProperty property; - QQmlExpression *expression; - QQmlExpression *reverseExpression; - QQmlExpression *rewindExpression; - QQmlGuard ownedExpression; + QQmlBoundSignalExpression *expression; + QQmlBoundSignalExpression *reverseExpression; + QQmlBoundSignalExpression *rewindExpression; + QQmlBoundSignalExpression *ownedExpression; + QQmlAbstractExpression::DeleteWatcher *ownedExpressionWatcher; // TODO: refactor the ownership impl. virtual void execute(Reason) { ownedExpression = QQmlPropertyPrivate::setSignalExpression(property, expression); - if (ownedExpression == expression) + if (ownedExpression == expression) { + delete ownedExpressionWatcher; + ownedExpressionWatcher = 0; ownedExpression = 0; + } else if (ownedExpression) { + delete ownedExpressionWatcher; + ownedExpressionWatcher = new QQmlAbstractExpression::DeleteWatcher(ownedExpression); + } } virtual bool isReversable() { return true; } virtual void reverse(Reason) { ownedExpression = QQmlPropertyPrivate::setSignalExpression(property, reverseExpression); - if (ownedExpression == reverseExpression) + if (ownedExpression == reverseExpression) { + delete ownedExpressionWatcher; + ownedExpressionWatcher = 0; ownedExpression = 0; + } else if (ownedExpression) { + delete ownedExpressionWatcher; + ownedExpressionWatcher = new QQmlAbstractExpression::DeleteWatcher(ownedExpression); + } } virtual void saveOriginals() { @@ -181,6 +195,8 @@ public: if (rsh->ownedExpression == reverseExpression) { ownedExpression = rsh->ownedExpression; rsh->ownedExpression = 0; + delete ownedExpressionWatcher; + ownedExpressionWatcher = new QQmlAbstractExpression::DeleteWatcher(ownedExpression); } } @@ -225,11 +241,17 @@ public: public: ExpressionChange(const QString &_name, QQmlBinding::Identifier _id, - QQmlExpression *_expr) - : name(_name), id(_id), expression(_expr) {} + const QString& _expr, + const QUrl &_url, + int _line, + int _column) + : name(_name), id(_id), expression(_expr), url(_url), line(_line), column(_column) {} QString name; QQmlBinding::Identifier id; - QQmlExpression *expression; + QString expression; + QUrl url; + int line; + int column; }; QList > properties; @@ -334,20 +356,36 @@ void QQuickPropertyChangesPrivate::decode() QQmlProperty prop = property(name); //### better way to check for signal property? if (prop.type() & QQmlProperty::SignalProperty) { - QQmlExpression *expression = new QQmlExpression(qmlContext(q), object, data.toString()); + QString expression = data.toString(); + QUrl url = QUrl(); + int line = -1; + int column = -1; + QQmlData *ddata = QQmlData::get(q); - if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) - expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber, ddata->columnNumber); + if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) { + url = ddata->outerContext->url; + line = ddata->lineNumber; + column = ddata->columnNumber; + } + QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler; handler->property = prop; - handler->expression = expression; + handler->expression = new QQmlBoundSignalExpression(QQmlContextData::get(qmlContext(q)), object, expression, false, url.toString(), line, column); signalReplacements << handler; - } else if (isScript) { - QQmlExpression *expression = new QQmlExpression(qmlContext(q), object, data.toString()); + } else if (isScript) { // binding + QString expression = data.toString(); + QUrl url = QUrl(); + int line = -1; + int column = -1; + QQmlData *ddata = QQmlData::get(q); - if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) - expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber, ddata->columnNumber); - expressions << ExpressionChange(name, id, expression); + if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) { + url = ddata->outerContext->url; + line = ddata->lineNumber; + column = ddata->columnNumber; + } + + expressions << ExpressionChange(name, id, expression, url, line, column); } else { properties << qMakePair(name, data); } @@ -374,8 +412,6 @@ QQuickPropertyChanges::QQuickPropertyChanges() QQuickPropertyChanges::~QQuickPropertyChanges() { Q_D(QQuickPropertyChanges); - for(int ii = 0; ii < d->expressions.count(); ++ii) - delete d->expressions.at(ii).expression; for(int ii = 0; ii < d->signalReplacements.count(); ++ii) delete d->signalReplacements.at(ii); } @@ -460,7 +496,8 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions() for (int ii = 0; ii < d->expressions.count(); ++ii) { - const QString &property = d->expressions.at(ii).name; + QQuickPropertyChangesPrivate::ExpressionChange e = d->expressions.at(ii); + const QString &property = e.name; QQmlProperty prop = d->property(property); if (prop.isValid()) { @@ -471,16 +508,18 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions() a.specifiedObject = d->object; a.specifiedProperty = property; + QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this), e.url.toString(), e.column) : 0; + if (!newBinding) + newBinding = new QQmlBinding(e.expression, false, object(), QQmlContextData::get(qmlContext(this)), e.url.toString(), e.line, e.column); + if (d->isExplicit) { - a.toValue = d->expressions.at(ii).expression->evaluate(); + // in this case, we don't want to assign a binding, per se, + // so we evaluate the expression and assign the result. + // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString) + // so that we can avoid creating then destroying the binding in this case. + a.toValue = newBinding->evaluate(); + newBinding->destroy(); } else { - QQmlExpression *e = d->expressions.at(ii).expression; - - QQmlBinding::Identifier id = d->expressions.at(ii).id; - QQmlBinding *newBinding = id != QQmlBinding::Invalid ? QQmlBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()) : 0; - if (!newBinding) - newBinding = new QQmlBinding(e->expression(), false, object(), QQmlContextData::get(qmlContext(this)), - e->sourceFile(), e->lineNumber(), e->columnNumber()); newBinding->setTarget(prop); a.toBinding = QQmlAbstractBinding::getPointer(newBinding); a.deletableToBinding = true; @@ -635,14 +674,14 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString QMutableListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { - const ExpressionEntry &entry = expressionIterator.next(); + ExpressionEntry &entry = expressionIterator.next(); if (entry.name == name) { - entry.expression->setExpression(expression); + entry.expression = expression; if (state() && state()->isStateActive()) { QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name)); if (oldBinding) { - QQmlPropertyPrivate::setBinding(d->property(name), 0); - oldBinding->destroy(); + QQmlPropertyPrivate::setBinding(d->property(name), 0); + oldBinding->destroy(); } QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this)); @@ -653,8 +692,8 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString } } - QQmlExpression *newExpression = new QQmlExpression(qmlContext(this), d->object, expression); - expressionIterator.insert(ExpressionEntry(name, QQmlBinding::Invalid, newExpression)); + // adding a new expression. + expressionIterator.insert(ExpressionEntry(name, QQmlBinding::Invalid, expression, QUrl(), -1, -1)); if (state() && state()->isStateActive()) { if (hadValue) { @@ -675,11 +714,14 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString action.specifiedObject = object(); action.specifiedProperty = name; - + QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this)); if (d->isExplicit) { - action.toValue = newExpression->evaluate(); + // don't assign the binding, merely evaluate the expression. + // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString) + // so that we can avoid creating then destroying the binding in this case. + action.toValue = newBinding->evaluate(); + newBinding->destroy(); } else { - QQmlBinding *newBinding = new QQmlBinding(newExpression->expression(), object(), qmlContext(this)); newBinding->setTarget(d->property(name)); action.toBinding = QQmlAbstractBinding::getPointer(newBinding); action.deletableToBinding = true; @@ -714,7 +756,7 @@ QVariant QQuickPropertyChanges::property(const QString &name) const while (expressionIterator.hasNext()) { const ExpressionEntry &entry = expressionIterator.next(); if (entry.name == name) { - return QVariant(entry.expression->expression()); + return QVariant(entry.expression); } } @@ -773,7 +815,7 @@ QString QQuickPropertyChanges::expression(const QString &name) const while (expressionIterator.hasNext()) { const ExpressionEntry &entry = expressionIterator.next(); if (entry.name == name) { - return entry.expression->expression(); + return entry.expression; } } -- cgit v1.2.3