From 86529642cfdc5cc5a94b735042d0807e3b57e9e1 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 20 Jul 2009 16:06:19 +1000 Subject: Rework expression stuff to use a more efficient notify handler --- src/corelib/kernel/qguard.cpp | 1 + src/declarative/qml/qmlbasicscript.cpp | 12 +- src/declarative/qml/qmlbasicscript_p.h | 3 +- src/declarative/qml/qmlbinding.cpp | 6 +- src/declarative/qml/qmlbinding.h | 3 +- src/declarative/qml/qmlbinding_p.h | 4 +- src/declarative/qml/qmlboundsignal.cpp | 6 +- src/declarative/qml/qmlboundsignal_p.h | 2 +- src/declarative/qml/qmlcontext.cpp | 2 +- src/declarative/qml/qmlexpression.cpp | 412 ++++++++++++++------------------- src/declarative/qml/qmlexpression.h | 39 ++-- src/declarative/qml/qmlexpression_p.h | 81 +++---- src/declarative/qml/qpodvector_p.h | 2 +- tools/qmlviewer/qmlviewer.cpp | 1 - 14 files changed, 246 insertions(+), 328 deletions(-) diff --git a/src/corelib/kernel/qguard.cpp b/src/corelib/kernel/qguard.cpp index c61be00..ae4f3a5 100644 --- a/src/corelib/kernel/qguard.cpp +++ b/src/corelib/kernel/qguard.cpp @@ -19,6 +19,7 @@ void q_guard_addGuard(QGuard *g) void q_guard_removeGuard(QGuard *g) { + if (g->next) g->next->prev = g->prev; *g->prev = g->next; g->next = 0; g->prev = 0; diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index fb52b91..073642f 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -265,7 +265,7 @@ QmlBasicScript::QmlBasicScript() } /*! - Create a new QmlBasicScript instance from saved \a data. + Load the QmlBasicScript instance with saved \a data. \a data \b must be data previously acquired from calling compileData() on a previously created QmlBasicScript instance. Any other data will almost @@ -277,9 +277,12 @@ QmlBasicScript::QmlBasicScript() If \a owner is set, it is referenced on creation and dereferenced on destruction of this instance. */ -QmlBasicScript::QmlBasicScript(const char *data, QmlRefCount *owner) -: flags(0), d((QmlBasicScriptPrivate *)data), rc(owner) + +void QmlBasicScript::load(const char *data, QmlRefCount *owner) { + clear(); + d = (QmlBasicScriptPrivate *)data; + rc = owner; if (rc) rc->addref(); } @@ -504,7 +507,6 @@ QmlBasicScriptCompiler::fetch(int type, const QMetaObject *mo, int idx) bool QmlBasicScriptCompiler::parseName(AST::Node *node) { - QStringList nameParts; if (!buildName(nameParts, node)) return false; @@ -550,6 +552,8 @@ bool QmlBasicScriptCompiler::parseName(AST::Node *node) return false; } + } else { + return false; } } else { diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h index eacd1d8..539227f 100644 --- a/src/declarative/qml/qmlbasicscript_p.h +++ b/src/declarative/qml/qmlbasicscript_p.h @@ -70,9 +70,10 @@ class QmlBasicScript { public: QmlBasicScript(); - QmlBasicScript(const char *, QmlRefCount * = 0); ~QmlBasicScript(); + void load(const char *, QmlRefCount * = 0); + // Always 4-byte aligned const char *compileData() const; unsigned int compileDataSize() const; diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index 6a8a027..e2f4682 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -61,13 +61,15 @@ QmlBindingPrivate::QmlBindingPrivate() QML_DEFINE_NOCREATE_TYPE(QmlBinding); QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, QObject *parent) -: QmlPropertyValueSource(*new QmlBindingPrivate, parent), QmlExpression(ctxt, data, rc, obj) +: QmlExpression(ctxt, data, rc, obj, *new QmlBindingPrivate) { + setParent(parent); } QmlBinding::QmlBinding(const QString &str, QObject *obj, QmlContext *ctxt, QObject *parent) -: QmlPropertyValueSource(*new QmlBindingPrivate, parent), QmlExpression(ctxt, str, obj) +: QmlExpression(ctxt, str, obj, *new QmlBindingPrivate) { + setParent(parent); } QmlBinding::~QmlBinding() diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h index e208277..10d81b8 100644 --- a/src/declarative/qml/qmlbinding.h +++ b/src/declarative/qml/qmlbinding.h @@ -57,8 +57,7 @@ QT_MODULE(Declarative) class QmlExpression; class QmlContext; class QmlBindingPrivate; -class Q_DECLARATIVE_EXPORT QmlBinding : public QmlPropertyValueSource, - public QmlExpression +class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression { Q_OBJECT public: diff --git a/src/declarative/qml/qmlbinding_p.h b/src/declarative/qml/qmlbinding_p.h index 470a62a..ec1a04a 100644 --- a/src/declarative/qml/qmlbinding_p.h +++ b/src/declarative/qml/qmlbinding_p.h @@ -53,13 +53,13 @@ // We mean it. // -#include #include #include +#include "qmlexpression_p.h" QT_BEGIN_NAMESPACE -class QmlBindingPrivate : public QObjectPrivate +class QmlBindingPrivate : public QmlExpressionPrivate { Q_DECLARE_PUBLIC(QmlBinding) public: diff --git a/src/declarative/qml/qmlboundsignal.cpp b/src/declarative/qml/qmlboundsignal.cpp index 9779e46..9af4003 100644 --- a/src/declarative/qml/qmlboundsignal.cpp +++ b/src/declarative/qml/qmlboundsignal.cpp @@ -53,14 +53,14 @@ QT_BEGIN_NAMESPACE int QmlBoundSignal::evaluateIdx = -1; QmlBoundSignal::QmlBoundSignal(QmlContext *ctxt, const QString &val, QObject *me, int idx, QObject *parent) -: QmlExpressionObject(ctxt, val, me, false), _idx(idx) +: QmlExpression(ctxt, val, me), _idx(idx) { - // A cached evaluation of the QmlExpressionObject::value() slot index. + // A cached evaluation of the QmlExpression::value() slot index. // // 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 = QmlExpressionObject::staticMetaObject.indexOfMethod("value()"); + if (evaluateIdx == -1) evaluateIdx = QmlExpression::staticMetaObject.indexOfMethod("value()"); setTrackChange(false); QFx_setParent_noEvent(this, parent); diff --git a/src/declarative/qml/qmlboundsignal_p.h b/src/declarative/qml/qmlboundsignal_p.h index 39c0c46..de8f91d 100644 --- a/src/declarative/qml/qmlboundsignal_p.h +++ b/src/declarative/qml/qmlboundsignal_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE -class QmlBoundSignal : public QmlExpressionObject +class QmlBoundSignal : public QmlExpression { Q_OBJECT public: diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 5bc70bc..bc2e6bf 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -292,7 +292,7 @@ QmlContext::~QmlContext() d->childExpressions.begin(); iter != d->childExpressions.end(); ++iter) { - (*iter)->d->ctxt = 0; + (*iter)->d_func()->ctxt = 0; } for (int ii = 0; ii < d->contextObjects.count(); ++ii) { diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 2aa1a8a..b4f57eb 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -50,53 +50,72 @@ Q_DECLARE_METATYPE(QList); QT_BEGIN_NAMESPACE -DEFINE_BOOL_CONFIG_OPTION(qmlDebugger, QML_DEBUGGER) - -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) +QmlExpressionPrivate::QmlExpressionPrivate() +: ctxt(0), expressionFunctionValid(false), sseData(0), me(0), trackChange(true), line(-1), id(0), guardList(0), guardListLength(0) { } -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) -: q(b), ctxt(0), expressionFunctionValid(false), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +void QmlExpressionPrivate::init(QmlContext *ctxt, const QString &expr, + QObject *me) { + Q_Q(QmlExpression); + + expression = expr; + + this->ctxt = ctxt; + if (ctxt && ctxt->engine()) + id = ctxt->engine()->d_func()->getUniqueId(); + if (ctxt) + ctxt->d_func()->childExpressions.insert(q); + this->me = me; } -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr) -: q(b), ctxt(0), expression(expr), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, + QObject *me) { + Q_Q(QmlExpression); + + sse.load((const char *)expr, rc); + + this->ctxt = ctxt; + if (ctxt && ctxt->engine()) + id = ctxt->engine()->d_func()->getUniqueId(); + if (ctxt) + ctxt->d_func()->childExpressions.insert(q); + this->me = me; } QmlExpressionPrivate::~QmlExpressionPrivate() { sse.deleteScriptState(sseData); sseData = 0; - delete proxy; - delete log; + if (guardList) { delete [] guardList; guardList = 0; } } /*! + \class QmlExpression + \brief The QmlExpression class evaluates ECMAScript in a QML context. +*/ + +/*! Create an invalid QmlExpression. As the expression will not have an associated QmlContext, this will be a null expression object and its value will always be an invalid QVariant. */ QmlExpression::QmlExpression() -: d(new QmlExpressionPrivate(this)) +: QObject(*new QmlExpressionPrivate, 0) { } -/*! \internal */ +/*! \internal */ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, - QmlRefCount *rc, QObject *me) -: d(new QmlExpressionPrivate(this, expr, rc)) + QmlRefCount *rc, QObject *me, + QmlExpressionPrivate &dd) +: QObject(dd, 0) { - d->ctxt = ctxt; - if(ctxt && ctxt->engine()) - d->id = ctxt->engine()->d_func()->getUniqueId(); - if(ctxt) - ctxt->d_func()->childExpressions.insert(this); - d->me = me; + Q_D(QmlExpression); + d->init(ctxt, expr, rc, me); } /*! @@ -108,14 +127,19 @@ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, */ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, QObject *scope) -: d(new QmlExpressionPrivate(this, expression)) +: QObject(*new QmlExpressionPrivate, 0) +{ + Q_D(QmlExpression); + d->init(ctxt, expression, scope); +} + +/*! \internal */ +QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, + QObject *scope, QmlExpressionPrivate &dd) +: QObject(dd, 0) { - d->ctxt = ctxt; - if(ctxt && ctxt->engine()) - d->id = ctxt->engine()->d_func()->getUniqueId(); - if(ctxt) - ctxt->d_func()->childExpressions.insert(this); - d->me = scope; + Q_D(QmlExpression); + d->init(ctxt, expression, scope); } /*! @@ -123,9 +147,9 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, */ QmlExpression::~QmlExpression() { + Q_D(QmlExpression); if (d->ctxt) d->ctxt->d_func()->childExpressions.remove(this); - delete d; d = 0; } /*! @@ -134,6 +158,7 @@ QmlExpression::~QmlExpression() */ QmlEngine *QmlExpression::engine() const { + Q_D(const QmlExpression); return d->ctxt?d->ctxt->engine():0; } @@ -143,6 +168,7 @@ QmlEngine *QmlExpression::engine() const */ QmlContext *QmlExpression::context() const { + Q_D(const QmlExpression); return d->ctxt; } @@ -151,6 +177,7 @@ QmlContext *QmlExpression::context() const */ QString QmlExpression::expression() const { + Q_D(const QmlExpression); if (d->sse.isValid()) return QLatin1String(d->sse.expression()); else @@ -170,12 +197,13 @@ void QmlExpression::clearExpression() */ void QmlExpression::setExpression(const QString &expression) { + Q_D(QmlExpression); if (d->sseData) { d->sse.deleteScriptState(d->sseData); d->sseData = 0; } - delete d->proxy; d->proxy = 0; + d->clearGuards(); d->expression = expression; d->expressionFunctionValid = false; @@ -184,18 +212,6 @@ void QmlExpression::setExpression(const QString &expression) d->sse.clear(); } -/*! - Called by QmlExpression each time the expression value changes from the - last time it was evaluated. The expression must have been evaluated at - least once (by calling QmlExpression::value()) before this callback will - be made. - - The default implementation does nothing. -*/ -void QmlExpression::valueChanged() -{ -} - QVariant QmlExpressionPrivate::evalSSE(QmlBasicScript::CacheState &cacheState) { #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -318,6 +334,8 @@ QVariant QmlExpressionPrivate::evalQtScript() */ QVariant QmlExpression::value() { + Q_D(QmlExpression); + QVariant rv; if (!d->ctxt || !engine() || (!d->sse.isValid() && d->expression.isEmpty())) return rv; @@ -340,87 +358,10 @@ QVariant QmlExpression::value() ep->currentExpression = lastCurrentExpression; - if (cacheState != QmlBasicScript::NoChange) { - if (cacheState != QmlBasicScript::Incremental && d->proxy) { - delete d->proxy; - d->proxy = 0; - } - - if (trackChange() && ep->capturedProperties.count()) { - if (!d->proxy) - d->proxy = new QmlExpressionBindProxy(this); - - static int changedIndex = -1; - if (changedIndex == -1) - changedIndex = QmlExpressionBindProxy::staticMetaObject.indexOfSlot("changed()"); - - if(qmlDebugger()) { - QmlExpressionLog log; - log.setTime(engine()->d_func()->getUniqueId()); - log.setExpression(expression()); - log.setResult(rv); - - for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) { - const QmlEnginePrivate::CapturedProperty &prop = - ep->capturedProperties.at(ii); - - if (prop.notifyIndex != -1) { - QMetaObject::connect(prop.object, prop.notifyIndex, - d->proxy, changedIndex); - } else { - const QMetaObject *metaObj = prop.object->metaObject(); - QMetaProperty metaProp = - metaObj->property(prop.coreIndex); - - QString warn = QLatin1String("Expression depends on non-NOTIFYable property: ") + - QLatin1String(metaObj->className()) + - QLatin1String("::") + - QLatin1String(metaProp.name()); - log.addWarning(warn); - } - } - d->addLog(log); - - } else { - bool outputWarningHeader = false; - for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) { - const QmlEnginePrivate::CapturedProperty &prop = - ep->capturedProperties.at(ii); - - if (prop.notifyIndex != -1) { - QMetaObject::connect(prop.object, prop.notifyIndex, - d->proxy, changedIndex); - } else { - if (!outputWarningHeader) { - outputWarningHeader = true; - qWarning() << "QmlExpression: Expression" << expression() << "depends on non-NOTIFYable properties:"; - } - - const QMetaObject *metaObj = prop.object->metaObject(); - QMetaProperty metaProp = - metaObj->property(prop.coreIndex); - - qWarning().nospace() << " " << metaObj->className() - << "::" << metaProp.name(); - } - } - } - } else { - QmlExpressionLog log; - log.setTime(engine()->d_func()->getUniqueId()); - log.setExpression(expression()); - log.setResult(rv); - d->addLog(log); - } - - } else { - if(qmlDebugger()) { - QmlExpressionLog log; - log.setTime(engine()->d_func()->getUniqueId()); - log.setExpression(expression()); - log.setResult(rv); - d->addLog(log); - } + if ((!trackChange() || !ep->capturedProperties.count()) && d->guardList) { + d->clearGuards(); + } else if(trackChange()) { + d->updateGuards(ep->capturedProperties); } ep->capturedProperties.clear(); @@ -435,7 +376,8 @@ QVariant QmlExpression::value() */ bool QmlExpression::isConstant() const { - return d->proxy == 0; + Q_D(const QmlExpression); + return !d->guardList; } /*! @@ -443,6 +385,7 @@ bool QmlExpression::isConstant() const */ bool QmlExpression::trackChange() const { + Q_D(const QmlExpression); return d->trackChange; } @@ -463,6 +406,7 @@ bool QmlExpression::trackChange() const */ void QmlExpression::setTrackChange(bool trackChange) { + Q_D(QmlExpression); d->trackChange = trackChange; } @@ -472,6 +416,7 @@ void QmlExpression::setTrackChange(bool trackChange) */ void QmlExpression::setSourceLocation(const QUrl &fileName, int line) { + Q_D(QmlExpression); d->fileName = fileName; d->line = line; } @@ -484,6 +429,7 @@ void QmlExpression::setSourceLocation(const QUrl &fileName, int line) */ QObject *QmlExpression::scopeObject() const { + Q_D(const QmlExpression); return d->me; } @@ -492,144 +438,138 @@ QObject *QmlExpression::scopeObject() const */ quint32 QmlExpression::id() const { + Q_D(const QmlExpression); return d->id; } -/*! - \class QmlExpression - \brief The QmlExpression class evaluates ECMAScript in a QML context. -*/ - -/*! - \class QmlExpressionObject - \brief The QmlExpressionObject class extends QmlExpression with signals and slots. - - To remain as lightweight as possible, QmlExpression does not inherit QObject - and consequently cannot use signals or slots. For the cases where this is - more convenient in an application, QmlExpressionObject can be used instead. - - QmlExpressionObject behaves identically to QmlExpression, except that the - QmlExpressionObject::value() method is a slot, and the - QmlExpressionObject::valueChanged() callback is a signal. -*/ -/*! - Create a QmlExpression with the specified \a parent. - - As the expression will not have an associated QmlContext, this will be a - null expression object and its value will always be an invalid QVariant. -*/ -QmlExpressionObject::QmlExpressionObject(QObject *parent) -: QObject(parent) -{ -} - -/*! - Create a QmlExpressionObject with the specified \a parent. - - The \a expression ECMAScript will be executed in the \a ctxt QmlContext. - If specified, the \a scope object's properties will also be in scope during - the expression's execution. -*/ -QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expression, QObject *scope, QObject *parent) -: QObject(parent), QmlExpression(ctxt, expression, scope) -{ -} - -/*! \internal */ -QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, void *d, QmlRefCount *rc, QObject *me) -: QmlExpression(ctxt, d, rc, me) +/*! \internal */ +void QmlExpression::__q_notify() { + valueChanged(); } -/*! - Returns the value of the expression, or an invalid QVariant if the - expression is invalid or has an error. -*/ -QVariant QmlExpressionObject::value() +void QmlExpressionPrivate::clearGuards() { - return QmlExpression::value(); -} - -/*! - \fn void QmlExpressionObject::valueChanged() + Q_Q(QmlExpression); - Emitted each time the expression value changes from the last time it was - evaluated. The expression must have been evaluated at least once (by - calling QmlExpressionObject::value()) before this signal will be emitted. -*/ + static int notifyIdx = -1; + if (notifyIdx == -1) + notifyIdx = + QmlExpression::staticMetaObject.indexOfMethod("__q_notify()"); -void QmlExpressionPrivate::addLog(const QmlExpressionLog &l) -{ - if (!log) - log = new QList(); - log->append(l); -} + for (int ii = 0; ii < guardListLength; ++ii) { + if (guardList[ii].data()) { + QMetaObject::disconnect(guardList[ii].data(), + guardList[ii].notifyIndex, + q, notifyIdx); + } + } -QmlExpressionLog::QmlExpressionLog() -{ + delete [] guardList; guardList = 0; + guardListLength = 0; } -QmlExpressionLog::QmlExpressionLog(const QmlExpressionLog &o) -: m_time(o.m_time), - m_expression(o.m_expression), - m_result(o.m_result), - m_warnings(o.m_warnings) +void QmlExpressionPrivate::updateGuards(const QPODVector &properties) { -} + Q_Q(QmlExpression); -QmlExpressionLog::~QmlExpressionLog() -{ -} + static int notifyIdx = -1; + if (notifyIdx == -1) + notifyIdx = + QmlExpression::staticMetaObject.indexOfMethod("__q_notify()"); -QmlExpressionLog &QmlExpressionLog::operator=(const QmlExpressionLog &o) -{ - m_time = o.m_time; - m_expression = o.m_expression; - m_result = o.m_result; - m_warnings = o.m_warnings; - return *this; -} + SignalGuard *newGuardList = 0; + + if (properties.count() != guardListLength) + newGuardList = new SignalGuard[properties.count()]; -void QmlExpressionLog::setTime(quint32 time) -{ - m_time = time; -} + bool outputWarningHeader = false; + int hit = 0; + for (int ii = 0; ii < properties.count(); ++ii) { + const QmlEnginePrivate::CapturedProperty &property = properties.at(ii); -quint32 QmlExpressionLog::time() const -{ - return m_time; -} + bool needGuard = true; + if (ii >= guardListLength) { + // New guard + } else if(guardList[ii].data() == property.object && + guardList[ii].notifyIndex == property.notifyIndex) { + // Cache hit + if (!guardList[ii].isDuplicate || + (guardList[ii].isDuplicate && hit == ii)) { + needGuard = false; + ++hit; + } + } else if(guardList[ii].data()) { + // Cache miss + QMetaObject::disconnect(guardList[ii].data(), + guardList[ii].notifyIndex, + q, notifyIdx); + } + /* else { + // Cache miss, but nothing to do + } */ + + if (needGuard) { + if (!newGuardList) { + newGuardList = new SignalGuard[properties.count()]; + for (int jj = 0; jj < ii; ++jj) + newGuardList[jj] = guardList[jj]; + } -QString QmlExpressionLog::expression() const -{ - return m_expression; -} + if (property.notifyIndex != -1) { + bool existing = false; + for (int jj = 0; !existing && jj < ii; ++jj) + existing = newGuardList[jj].data() == property.object && + newGuardList[jj].notifyIndex == property.notifyIndex; + + newGuardList[ii] = property.object; + newGuardList[ii].notifyIndex = property.notifyIndex; + if (existing) + newGuardList[ii].isDuplicate = true; + else + QMetaObject::connect(property.object, property.notifyIndex, + q, notifyIdx); + } else { + if (!outputWarningHeader) { + outputWarningHeader = true; + qWarning() << "QmlExpression: Expression" << q->expression() + << "depends on non-NOTIFYable properties:"; + } -void QmlExpressionLog::setExpression(const QString &e) -{ - m_expression = e; -} + const QMetaObject *metaObj = property.object->metaObject(); + QMetaProperty metaProp = metaObj->property(property.coreIndex); -QStringList QmlExpressionLog::warnings() const -{ - return m_warnings; -} + qWarning().nospace() << " " << metaObj->className() + << "::" << metaProp.name(); + } + } else if (newGuardList) { + newGuardList[ii] = guardList[ii]; + } + } -void QmlExpressionLog::addWarning(const QString &w) -{ - m_warnings << w; -} + for (int ii = properties.count(); ii < guardListLength; ++ii) { + if (guardList[ii].data()) { + QMetaObject::disconnect(guardList[ii].data(), + guardList[ii].notifyIndex, + q, notifyIdx); + } + } -QVariant QmlExpressionLog::result() const -{ - return m_result; + if (newGuardList) { + if (guardList) delete [] guardList; + guardList = newGuardList; + guardListLength = properties.count(); + } + //qWarning() << hit << properties.count() << q->expression(); } -void QmlExpressionLog::setResult(const QVariant &r) -{ - m_result = r; -} +/*! + \fn void QmlExpression::valueChanged() + Emitted each time the expression value changes from the last time it was + evaluated. The expression must have been evaluated at least once (by + calling QmlExpression::value()) before this signal will be emitted. +*/ QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index 3d8f8df..6db6ef9 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -57,12 +57,12 @@ class QmlEngine; class QmlContext; class QmlExpressionPrivate; class QmlBasicScript; -class Q_DECLARATIVE_EXPORT QmlExpression +class Q_DECLARATIVE_EXPORT QmlExpression : public QObject { + Q_OBJECT public: QmlExpression(); QmlExpression(QmlContext *, const QString &, QObject *); - QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me); virtual ~QmlExpression(); QmlEngine *engine() const; @@ -71,7 +71,6 @@ public: QString expression() const; void clearExpression(); virtual void setExpression(const QString &); - QVariant value(); bool isConstant() const; bool trackChange() const; @@ -82,31 +81,27 @@ public: QObject *scopeObject() const; quint32 id() const; -protected: + +public Q_SLOTS: + QVariant value(); + +Q_SIGNALS: virtual void valueChanged(); +protected: + QmlExpression(QmlContext *, const QString &, QObject *, + QmlExpressionPrivate &dd); + QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me, + QmlExpressionPrivate &dd); + +private Q_SLOTS: + void __q_notify(); + private: + Q_DECLARE_PRIVATE(QmlExpression) friend class QmlExpressionBindProxy; friend class QmlDebugger; friend class QmlContext; - QmlExpressionPrivate *d; -}; - -// LK: can't we merge with QmlExpression???? -class Q_DECLARATIVE_EXPORT QmlExpressionObject : public QObject, - public QmlExpression -{ - Q_OBJECT -public: - QmlExpressionObject(QObject *parent = 0); - QmlExpressionObject(QmlContext *, const QString &, QObject *scope, QObject *parent = 0); - QmlExpressionObject(QmlContext *, void *, QmlRefCount *, QObject *); - -public Q_SLOTS: - QVariant value(); - -Q_SIGNALS: - void valueChanged(); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 09745a3..41b7749 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -55,23 +55,24 @@ #include "qmlbasicscript_p.h" #include "qmlexpression.h" +#include "qmlengine_p.h" +#include #include QT_BEGIN_NAMESPACE class QmlExpression; class QString; -class QmlExpressionLog; -class QmlExpressionBindProxy; -class QmlExpressionPrivate +class QmlExpressionPrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QmlExpression) public: - QmlExpressionPrivate(QmlExpression *); - QmlExpressionPrivate(QmlExpression *, const QString &expr); - QmlExpressionPrivate(QmlExpression *, void *expr, QmlRefCount *rc); + QmlExpressionPrivate(); ~QmlExpressionPrivate(); - QmlExpression *q; + void init(QmlContext *, const QString &, QObject *); + void init(QmlContext *, void *, QmlRefCount *, QObject *); + QmlContext *ctxt; QString expression; bool expressionFunctionValid; @@ -79,7 +80,6 @@ public: QmlBasicScript sse; void *sseData; - QmlExpressionBindProxy *proxy; QObject *me; bool trackChange; @@ -88,53 +88,30 @@ public: quint32 id; - void addLog(const QmlExpressionLog &); - QList *log; - QVariant evalSSE(QmlBasicScript::CacheState &cacheState); QVariant evalQtScript(); -}; - -class QmlExpressionBindProxy : public QObject -{ -Q_OBJECT -public: - QmlExpressionBindProxy(QmlExpression *be) - :e(be) { } - -private: - QmlExpression *e; - -private Q_SLOTS: - void changed() { e->valueChanged(); } -}; - -class QmlExpressionLog -{ -public: - QmlExpressionLog(); - QmlExpressionLog(const QmlExpressionLog &); - ~QmlExpressionLog(); - - QmlExpressionLog &operator=(const QmlExpressionLog &); - - void setTime(quint32); - quint32 time() const; - - QString expression() const; - void setExpression(const QString &); - - QStringList warnings() const; - void addWarning(const QString &); - - QVariant result() const; - void setResult(const QVariant &); -private: - quint32 m_time; - QString m_expression; - QVariant m_result; - QStringList m_warnings; + struct SignalGuard : public QGuard { + SignalGuard() : isDuplicate(false), notifyIndex(-1) {} + + SignalGuard &operator=(QObject *obj) { + QGuard::operator=(obj); + return *this; + } + SignalGuard &operator=(const SignalGuard &o) { + QGuard::operator=(o); + isDuplicate = o.isDuplicate; + notifyIndex = o.notifyIndex; + return *this; + } + + bool isDuplicate:1; + int notifyIndex:31; + }; + SignalGuard *guardList; + int guardListLength; + void updateGuards(const QPODVector &properties); + void clearGuards(); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qpodvector_p.h b/src/declarative/qml/qpodvector_p.h index 101c62d..e74f9f6 100644 --- a/src/declarative/qml/qpodvector_p.h +++ b/src/declarative/qml/qpodvector_p.h @@ -64,7 +64,7 @@ public: QPODVector() : m_count(0), m_capacity(0), m_data(0) {} - const T &at(int idx) { + const T &at(int idx) const { return m_data[idx]; } diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index c9d70e8..2eb8845 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -13,7 +13,6 @@ #include -#include "qmlbindablevalue.h" #include "qmlviewer.h" #include #include -- cgit v0.12