X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fdeclarative%2Fqml%2Fqdeclarativeexpression.cpp;h=25d85f407ba8eb3fa03e2358bd72d52956a87a49;hb=45b14259fc0cf704692df1c00da511527d1fba1d;hp=a210e4e1d7ee56398c78d22d8a6fe4afb4bd35fb;hpb=6b54de600ce74025bc8ada20bea95ad183a6cd8d;p=profile%2Fivi%2Fqtdeclarative.git diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp index a210e4e..25d85f4 100644 --- a/src/declarative/qml/qdeclarativeexpression.cpp +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -1,34 +1,34 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ ** ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** ** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. ** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. ** ** ** @@ -40,17 +40,15 @@ ****************************************************************************/ #include "qdeclarativeexpression.h" -#include "private/qdeclarativeexpression_p.h" +#include "qdeclarativeexpression_p.h" -#include "private/qdeclarativeengine_p.h" -#include "private/qdeclarativecontext_p.h" -#include "private/qdeclarativerewrite_p.h" -#include "private/qdeclarativecompiler_p.h" +#include "qdeclarativeengine_p.h" +#include "qdeclarativecontext_p.h" +#include "qdeclarativerewrite_p.h" +#include "qdeclarativescriptstring_p.h" +#include "qdeclarativecompiler_p.h" #include -#include - -#include QT_BEGIN_NAMESPACE @@ -70,31 +68,30 @@ bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e) return true; } -QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression() -: dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false), - guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0) +QDeclarativeJavaScriptExpression::QDeclarativeJavaScriptExpression() +: m_requiresThisObject(0), m_useSharedContext(0), m_notifyOnValueChanged(0), + m_scopeObject(0), guardCapture(0) { } -QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression() +QDeclarativeJavaScriptExpression::~QDeclarativeJavaScriptExpression() { - v8function.Dispose(); - v8qmlscope.Dispose(); - v8function = v8::Persistent(); - v8qmlscope = v8::Persistent(); - - if (guardList) { delete [] guardList; guardList = 0; } - if (dataRef) dataRef->release(); - if (deleted) *deleted = true; + if (guardCapture) guardCapture->expression = 0; + clearGuards(); } QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate() -: expressionFunctionValid(true), line(-1) +: expressionFunctionValid(true), expressionFunctionRewritten(false), + extractExpressionFromFunction(false), line(-1), dataRef(0) { } QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate() { + qPersistentDispose(v8qmlscope); + qPersistentDispose(v8function); + if (dataRef) dataRef->release(); + dataRef = 0; } void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, @@ -103,52 +100,39 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QS expression = expr; QDeclarativeAbstractExpression::setContext(ctxt); - scopeObject = me; + setScopeObject(me); expressionFunctionValid = false; + expressionFunctionRewritten = false; } void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle func, QObject *me) { - // XXX aakenned - // expression = func.toString(); - QDeclarativeAbstractExpression::setContext(ctxt); - scopeObject = me; + setScopeObject(me); - v8function = v8::Persistent::New(func); - expressionFunctionMode = ExplicitContext; + v8function = qPersistentNew(func); + setUseSharedContext(false); expressionFunctionValid = true; + expressionFunctionRewritten = false; + extractExpressionFromFunction = true; } -void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, - QDeclarativeRefCount *rc, - QObject *me, const QString &srcUrl, int lineNumber) +void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, + bool isRewritten, QObject *me, const QString &srcUrl, + int lineNumber, int columnNumber) { url = srcUrl; line = lineNumber; + column = columnNumber; - Q_ASSERT(!dataRef); - - dataRef = rc; - if (dataRef) dataRef->addref(); - - quint32 *exprData = (quint32 *)expr; - QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc; - - expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]); - - int progIdx = *(exprData); - bool isSharedProgram = progIdx & 0x80000000; - progIdx &= 0x7FFFFFFF; - - v8function = evalFunction(ctxt, me, expression, url, line, &v8qmlscope); + expression = expr; - expressionFunctionMode = ExplicitContext; - expressionFunctionValid = true; + expressionFunctionValid = false; + expressionFunctionRewritten = isRewritten; QDeclarativeAbstractExpression::setContext(ctxt); - scopeObject = me; + setScopeObject(me); } // Callee owns the persistent handle @@ -160,61 +144,25 @@ QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObje QDeclarativeEngine *engine = ctxt->engine; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); - // XXX aakenned optimize + // XXX TODO: Implement script caching, like we used to do with QScriptProgram in the + // QtScript days v8::HandleScope handle_scope; - v8::Context::Scope ctxtscope(ep->v8engine.context()); + v8::Context::Scope ctxtscope(ep->v8engine()->context()); - // XXX try/catch? - - v8::Local scopeobject = ep->v8engine.qmlScope(ctxt, scope); - v8::Local script = ep->v8engine.qmlModeCompile(code, filename, line); + v8::TryCatch tc; + v8::Local scopeobject = ep->v8engine()->qmlScope(ctxt, scope); + v8::Local script = ep->v8engine()->qmlModeCompile(code, filename, line); + if (tc.HasCaught()) return v8::Persistent(); v8::Local result = script->Run(scopeobject); - if (qmlscope) *qmlscope = v8::Persistent::New(scopeobject); - return v8::Persistent::New(v8::Local::Cast(result)); + if (tc.HasCaught()) return v8::Persistent(); + if (qmlscope) *qmlscope = qPersistentNew(scopeobject); + return qPersistentNew(v8::Local::Cast(result)); } -QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, - const QString &program, const QString &fileName, - int lineNumber, QScriptValue *contextObject) +QDeclarativeExpression *QDeclarativeExpressionPrivate::create(QDeclarativeContextData *ctxt, QObject *object, const QString &expr, bool isRewritten, + const QString &url, int lineNumber, int columnNumber) { -#if 0 - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine); - QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine); - if (contextObject) { - *contextObject = ep->contextClass->newContext(context, object); - scriptContext->pushScope(*contextObject); - } else { - scriptContext->pushScope(ep->contextClass->newContext(context, object)); - } - scriptContext->pushScope(ep->globalClass->staticGlobalObject()); - QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber); - ep->scriptEngine.popContext(); - return rv; -#else - qFatal("Not impl"); -#endif -} - -QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, - const QScriptProgram &program, - QScriptValue *contextObject) -{ -#if 0 - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine); - QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine); - if (contextObject) { - *contextObject = ep->contextClass->newContext(context, object); - scriptContext->pushScope(*contextObject); - } else { - scriptContext->pushScope(ep->contextClass->newContext(context, object)); - } - scriptContext->pushScope(ep->globalClass->staticGlobalObject()); - QScriptValue rv = ep->scriptEngine.evaluate(program); - ep->scriptEngine.popContext(); - return rv; -#else - qFatal("Not impl"); -#endif + return new QDeclarativeExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QDeclarativeExpressionPrivate); } /*! @@ -245,8 +193,6 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex \endcode */ -static int QDeclarativeExpression_notifyIdx = -1; - /*! Create an invalid QDeclarativeExpression. @@ -256,26 +202,67 @@ static int QDeclarativeExpression_notifyIdx = -1; QDeclarativeExpression::QDeclarativeExpression() : QObject(*new QDeclarativeExpressionPrivate, 0) { - Q_D(QDeclarativeExpression); - - if (QDeclarativeExpression_notifyIdx == -1) - QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); - d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! \internal */ -QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, void *expr, - QDeclarativeRefCount *rc, QObject *me, - const QString &url, int lineNumber, +QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, + QObject *object, const QString &expr, bool isRewritten, + const QString &url, int lineNumber, int columnNumber, QDeclarativeExpressionPrivate &dd) : QObject(dd, 0) { Q_D(QDeclarativeExpression); - d->init(ctxt, expr, rc, me, url, lineNumber); + d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber); +} + +/*! + Create a QDeclarativeExpression object that is a child of \a parent. + + The \script provides the expression to be evaluated, the context to evaluate it in, + and the scope object to evaluate it with. + + This constructor is functionally equivalent to the following, but in most cases + is more efficient. + \code + QDeclarativeExpression expression(script.context(), script.scopeObject(), script.script(), parent); + \endcode + + \sa QDeclarativeScriptString +*/ +QDeclarativeExpression::QDeclarativeExpression(const QDeclarativeScriptString &script, QObject *parent) +: QObject(*new QDeclarativeExpressionPrivate, parent) +{ + Q_D(QDeclarativeExpression); + bool defaultConstruction = false; + + int id = script.d.data()->bindingId; + if (id < 0) { + defaultConstruction = true; + } else { + QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(script.context()); + + QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(script.context()->engine()); + QDeclarativeCompiledData *cdata = 0; + QDeclarativeTypeData *typeData = 0; + if (engine && ctxtdata && !ctxtdata->url.isEmpty()) { + typeData = engine->typeLoader.get(ctxtdata->url); + cdata = typeData->compiledData(); + } + + if (cdata) + d->init(ctxtdata, cdata->primitives.at(id), true, script.scopeObject(), + cdata->name, script.d.data()->lineNumber, script.d.data()->columnNumber); + else + defaultConstruction = true; - if (QDeclarativeExpression_notifyIdx == -1) - QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); - d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); + if (cdata) + cdata->release(); + if (typeData) + typeData->release(); + } + + if (defaultConstruction) + d->init(QDeclarativeContextData::get(script.context()), script.script(), script.scopeObject()); } /*! @@ -293,10 +280,6 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt, { Q_D(QDeclarativeExpression); d->init(QDeclarativeContextData::get(ctxt), expression, scope); - - if (QDeclarativeExpression_notifyIdx == -1) - QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); - d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! @@ -308,10 +291,6 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO { Q_D(QDeclarativeExpression); d->init(ctxt, expression, scope); - - if (QDeclarativeExpression_notifyIdx == -1) - QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); - d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! \internal */ @@ -321,10 +300,6 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO { Q_D(QDeclarativeExpression); d->init(ctxt, expression, scope); - - if (QDeclarativeExpression_notifyIdx == -1) - QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); - d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! @@ -336,18 +311,13 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO new QDeclarativeExpression(ctxt, scope, &function, ...); */ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr, - QDeclarativeExpressionPrivate &dd) + QDeclarativeExpressionPrivate &dd) : QObject(dd, 0) { v8::Handle function = *(v8::Handle *)functionPtr; Q_D(QDeclarativeExpression); d->init(ctxt, function, scope); - - if (QDeclarativeExpression_notifyIdx == -1) - QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); - - d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! @@ -384,6 +354,13 @@ QDeclarativeContext *QDeclarativeExpression::context() const QString QDeclarativeExpression::expression() const { Q_D(const QDeclarativeExpression); + if (d->extractExpressionFromFunction && context()->engine()) { + QV8Engine *v8engine = QDeclarativeEnginePrivate::getV8Engine(context()->engine()); + v8::HandleScope handle_scope; + v8::Context::Scope scope(v8engine->context()); + + return v8engine->toString(v8::Handle(d->v8function)); + } return d->expression; } @@ -394,13 +371,12 @@ void QDeclarativeExpression::setExpression(const QString &expression) { Q_D(QDeclarativeExpression); - d->resetNotifyOnChange(); + d->resetNotifyOnValueChanged(); d->expression = expression; d->expressionFunctionValid = false; - d->v8function.Dispose(); - d->v8qmlscope.Dispose(); - d->v8function = v8::Persistent(); - d->v8qmlscope = v8::Persistent(); + d->expressionFunctionRewritten = false; + qPersistentDispose(d->v8function); + qPersistentDispose(d->v8qmlscope); } void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle message, @@ -412,10 +388,8 @@ void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle mes v8::Handle description = message->Get(); int lineNumber = message->GetLineNumber(); - Q_ASSERT(name->IsString()); - - v8::Local file = name->ToString(); - if (file->Length() == 0) + v8::Local file = name->IsString()?name->ToString():v8::Local(); + if (file.IsEmpty() || file->Length() == 0) error.setUrl(QUrl(QLatin1String(""))); else error.setUrl(QUrl(QV8Engine::toStringStatic(file))); @@ -430,240 +404,202 @@ void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle mes error.setDescription(qDescription); } -void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, - QDeclarativeError &error) -{ - qFatal("Not implemented - we use v8 now"); -} - -bool QDeclarativeQtScriptExpression::notifyOnValueChange() const +void QDeclarativeJavaScriptExpression::setNotifyOnValueChanged(bool v) { - return trackChange; + m_notifyOnValueChanged = v; + if (!v) clearGuards(); } -void QDeclarativeQtScriptExpression::setNotifyOnValueChange(bool notify) -{ - trackChange = notify; - if (!notify && guardList) - clearGuards(); -} - -void QDeclarativeQtScriptExpression::resetNotifyOnChange() +void QDeclarativeJavaScriptExpression::resetNotifyOnValueChanged() { clearGuards(); } -void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notifyIndex) -{ - if (guardList) clearGuards(); - - if (!object || notifyIndex == -1) { - guardObject = 0; - notifyIndex = -1; - } else { - guardObject = object; - guardObjectNotifyIndex = notifyIndex; - - } -} - -void QDeclarativeQtScriptExpression::setEvaluateFlags(EvaluateFlags flags) -{ - evalFlags = flags; -} - -QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::evaluateFlags() const -{ - return evalFlags; -} - -v8::Local QDeclarativeQtScriptExpression::v8value(QObject *secondaryScope, bool *isUndefined) +v8::Local QDeclarativeJavaScriptExpression::evaluate(v8::Handle function, bool *isUndefined) { Q_ASSERT(context() && context()->engine); - Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1)); - if (v8function.IsEmpty() || v8function->IsUndefined()) { + if (function.IsEmpty() || function->IsUndefined()) { if (isUndefined) *isUndefined = true; return v8::Local(); } - DeleteWatcher watcher(this); - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine); - bool lastCaptureProperties = ep->captureProperties; - QPODVector lastCapturedProperties; - ep->captureProperties = trackChange; - ep->capturedProperties.copyAndClear(lastCapturedProperties); + Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty()); + GuardCapture capture(this); - v8::Local value = eval(secondaryScope, isUndefined); + QDeclarativeEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture; + ep->propertyCapture = notifyOnValueChanged()?&capture:0; - if (!watcher.wasDeleted() && trackChange) { - if (ep->capturedProperties.count() == 0) { - if (guardList) clearGuards(); + if (notifyOnValueChanged()) + capture.guards.copyAndClear(activeGuards); - } else { - - updateGuards(ep->capturedProperties); - - } - } + QDeclarativeContextData *lastSharedContext = 0; + QObject *lastSharedScope = 0; - lastCapturedProperties.copyAndClear(ep->capturedProperties); - ep->captureProperties = lastCaptureProperties; + bool sharedContext = useSharedContext(); - return value; -} - -v8::Local QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined) -{ - Q_ASSERT(context() && context()->engine); - DeleteWatcher watcher(this); + // All code that follows must check with watcher before it accesses data members + // incase we have been deleted. + QDeleteWatcher watcher(this); - QDeclarativeEngine *engine = context()->engine; - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); - - QObject *restoreSecondaryScope = 0; - if (secondaryScope) - restoreSecondaryScope = ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope); - - v8::TryCatch try_catch; - v8::Context::Scope scope(ep->v8engine.context()); // XXX is this needed? - - v8::Handle This; - - if (evaluateFlags() & RequiresThisObject) { - v8::Handle value = ep->v8engine.newQObject(scopeObject); - if (value->IsObject()) This = v8::Handle::Cast(value); - } - if (This.IsEmpty()) { - This = ep->v8engine.global(); + if (sharedContext) { + lastSharedContext = ep->sharedContext; + lastSharedScope = ep->sharedScope; + ep->sharedContext = context(); + ep->sharedScope = scopeObject(); } - v8::Local result = v8function->Call(This, 0, 0); + v8::Local result; + { + v8::TryCatch try_catch; + v8::Handle This = ep->v8engine()->global(); + if (scopeObject() && requiresThisObject()) { + v8::Handle value = ep->v8engine()->newQObject(scopeObject()); + if (value->IsObject()) This = v8::Handle::Cast(value); + } - if (secondaryScope) - ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope); + result = function->Call(This, 0, 0); - if (isUndefined) - *isUndefined = try_catch.HasCaught() || result->IsUndefined(); + if (isUndefined) + *isUndefined = try_catch.HasCaught() || result->IsUndefined(); - if (watcher.wasDeleted()) { - } else if (try_catch.HasCaught()) { - v8::Local message = try_catch.Message(); - if (!message.IsEmpty()) { - QDeclarativeExpressionPrivate::exceptionToError(message, error); + if (watcher.wasDeleted()) { + } else if (try_catch.HasCaught()) { + v8::Context::Scope scope(ep->v8engine()->context()); + v8::Local message = try_catch.Message(); + if (!message.IsEmpty()) { + QDeclarativeExpressionPrivate::exceptionToError(message, error); + } else { + error = QDeclarativeError(); + } } else { error = QDeclarativeError(); } - } else { - error = QDeclarativeError(); } - return result; -} + if (sharedContext) { + ep->sharedContext = lastSharedContext; + ep->sharedScope = lastSharedScope; + } -void QDeclarativeQtScriptExpression::updateGuards(const QPODVector &properties) -{ - Q_ASSERT(guardObject); - Q_ASSERT(guardObjectNotifyIndex != -1); + if (capture.errorString) { + for (int ii = 0; ii < capture.errorString->count(); ++ii) + qWarning("%s", qPrintable(capture.errorString->at(ii))); + delete capture.errorString; + capture.errorString = 0; + } - if (properties.count() != guardListLength) { - QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()]; + while (Guard *g = capture.guards.takeFirst()) + g->Delete(); - for (int ii = 0; ii < qMin(guardListLength, properties.count()); ++ii) - guardList[ii].copyAndClear(newGuardList[ii]); + ep->propertyCapture = lastPropertyCapture; - delete [] guardList; - guardList = newGuardList; - guardListLength = properties.count(); - } + return result; +} - bool outputWarningHeader = false; - bool noChanges = true; - for (int ii = 0; ii < properties.count(); ++ii) { - QDeclarativeNotifierEndpoint &guard = guardList[ii]; - const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii); +void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QDeclarativeNotifier *n) +{ + if (expression) { - guard.target = guardObject; - guard.targetMethod = guardObjectNotifyIndex; + // Try and find a matching guard + while (!guards.isEmpty() && !guards.first()->isConnected(n)) + guards.takeFirst()->Delete(); - if (property.notifier != 0) { + Guard *g = 0; + if (!guards.isEmpty()) { + g = guards.takeFirst(); + g->cancelNotify(); + Q_ASSERT(g->isConnected(n)); + } else { + g = Guard::New(expression); + g->connect(n); + } - if (!noChanges && guard.isConnected(property.notifier)) { - // Nothing to do + expression->activeGuards.append(g); + } +} - } else { - noChanges = false; - - bool existing = false; - for (int jj = 0; !existing && jj < ii; ++jj) - if (guardList[jj].isConnected(property.notifier)) - existing = true; - - if (existing) { - // duplicate - guard.disconnect(); - } else { - guard.connect(property.notifier); - } +void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n) +{ + if (expression) { + if (n == -1) { + if (!errorString) { + errorString = new QStringList; + QString preamble = QLatin1String("QDeclarativeExpression: Expression ") + + expression->expressionIdentifier() + + QLatin1String(" depends on non-NOTIFYable properties:"); + errorString->append(preamble); } + const QMetaObject *metaObj = o->metaObject(); + QMetaProperty metaProp = metaObj->property(c); - } else if (property.notifyIndex != -1) { + QString error = QLatin1String(" ") + + QString::fromUtf8(metaObj->className()) + + QLatin1String("::") + + QString::fromUtf8(metaProp.name()); + errorString->append(error); + } else { - if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) { - // Nothing to do + // Try and find a matching guard + while (!guards.isEmpty() && !guards.first()->isConnected(o, n)) + guards.takeFirst()->Delete(); + Guard *g = 0; + if (!guards.isEmpty()) { + g = guards.takeFirst(); + g->cancelNotify(); + Q_ASSERT(g->isConnected(o, n)); } else { - noChanges = false; - - bool existing = false; - for (int jj = 0; !existing && jj < ii; ++jj) - if (guardList[jj].isConnected(property.object, property.notifyIndex)) - existing = true; - - if (existing) { - // duplicate - guard.disconnect(); - } else { - guard.connect(property.object, property.notifyIndex); - } + g = Guard::New(expression); + g->connect(o, n); } - } else { - if (!outputWarningHeader) { - outputWarningHeader = true; - qWarning() << "QDeclarativeExpression: Expression" << expression - << "depends on non-NOTIFYable properties:"; - } - - const QMetaObject *metaObj = property.object->metaObject(); - QMetaProperty metaProp = metaObj->property(property.coreIndex); - - qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name(); + expression->activeGuards.append(g); } } } +void QDeclarativeJavaScriptExpression::clearGuards() +{ + while (Guard *g = activeGuards.takeFirst()) + g->Delete(); +} + // Must be called with a valid handle scope v8::Local QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined) { if (!expressionFunctionValid) { - QDeclarativeEngine *engine = context()->engine; - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + bool ok = true; QDeclarativeRewrite::RewriteBinding rewriteBinding; rewriteBinding.setName(name); - bool ok = true; - const QString code = rewriteBinding(expression, &ok); - if (ok) v8function = evalFunction(context(), scopeObject, code, url, line, &v8qmlscope); - expressionFunctionMode = ExplicitContext; + QString code; + if (expressionFunctionRewritten) + code = expression; + else + code = rewriteBinding(expression, &ok); + + if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope); + setUseSharedContext(false); expressionFunctionValid = true; } - return QDeclarativeQtScriptExpression::v8value(secondaryScope, isUndefined); + + if (secondaryScope) { + v8::Local result; + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine); + QObject *restoreSecondaryScope = 0; + restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope); + result = evaluate(v8function, isUndefined); + ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope); + return result; + } else { + return evaluate(v8function, isUndefined); + } } QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) @@ -682,8 +618,9 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU { v8::HandleScope handle_scope; + v8::Context::Scope context_scope(ep->v8engine()->context()); v8::Local result = v8value(secondaryScope, isUndefined); - rv = ep->v8engine.toVariant(result, qMetaTypeId >()); + rv = ep->v8engine()->toVariant(result, qMetaTypeId >()); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. @@ -713,7 +650,7 @@ value changes. bool QDeclarativeExpression::notifyOnValueChanged() const { Q_D(const QDeclarativeExpression); - return d->notifyOnValueChange(); + return d->notifyOnValueChanged(); } /*! @@ -735,7 +672,7 @@ bool QDeclarativeExpression::notifyOnValueChanged() const void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange) { Q_D(QDeclarativeExpression); - d->setNotifyOnValueChange(notifyOnChange); + d->setNotifyOnValueChanged(notifyOnChange); } /*! @@ -759,14 +696,25 @@ int QDeclarativeExpression::lineNumber() const } /*! + Returns the source file column number for this expression. The source location + must have been previously set by calling setSourceLocation(). +*/ +int QDeclarativeExpression::columnNumber() const +{ + Q_D(const QDeclarativeExpression); + return d->column; +} + +/*! Set the location of this expression to \a line of \a url. This information is used by the script engine. */ -void QDeclarativeExpression::setSourceLocation(const QString &url, int line) +void QDeclarativeExpression::setSourceLocation(const QString &url, int line, int column) { Q_D(QDeclarativeExpression); d->url = url; d->line = line; + d->column = column; } /*! @@ -778,7 +726,7 @@ void QDeclarativeExpression::setSourceLocation(const QString &url, int line) QObject *QDeclarativeExpression::scopeObject() const { Q_D(const QDeclarativeExpression); - return d->scopeObject; + return d->scopeObject(); } /*! @@ -818,19 +766,6 @@ QDeclarativeError QDeclarativeExpression::error() const return d->error; } -/*! \internal */ -void QDeclarativeExpressionPrivate::_q_notify() -{ - emitValueChanged(); -} - -void QDeclarativeQtScriptExpression::clearGuards() -{ - delete [] guardList; - guardList = 0; - guardListLength = 0; -} - /*! \fn void QDeclarativeExpression::valueChanged() @@ -839,7 +774,7 @@ void QDeclarativeQtScriptExpression::clearGuards() calling QDeclarativeExpression::evaluate()) before this signal will be emitted. */ -void QDeclarativeExpressionPrivate::emitValueChanged() +void QDeclarativeExpressionPrivate::expressionChanged() { Q_Q(QDeclarativeExpression); emit q->valueChanged();