/**************************************************************************** ** ** 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$ ** GNU Lesser General Public License Usage ** 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 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** 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. ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qdeclarativeexpression.h" #include "qdeclarativeexpression_p.h" #include "qdeclarativeengine_p.h" #include "qdeclarativecontext_p.h" #include "qdeclarativerewrite_p.h" #include "qdeclarativescriptstring_p.h" #include "qdeclarativecompiler_p.h" #include QT_BEGIN_NAMESPACE bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e) { if (!e) return false; if (e->inProgressCreations == 0) return false; // Not in construction if (prevError) return true; // Already in error chain prevError = &e->erroredBindings; nextError = e->erroredBindings; e->erroredBindings = this; if (nextError) nextError->prevError = &nextError; return true; } QDeclarativeJavaScriptExpression::QDeclarativeJavaScriptExpression(VTable *v) : m_vtable(v) { } QDeclarativeJavaScriptExpression::~QDeclarativeJavaScriptExpression() { clearGuards(); } static QDeclarativeJavaScriptExpression::VTable QDeclarativeExpressionPrivate_jsvtable = { QDeclarativeExpressionPrivate::expressionIdentifier, QDeclarativeExpressionPrivate::expressionChanged }; QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate() : QDeclarativeJavaScriptExpression(&QDeclarativeExpressionPrivate_jsvtable), 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, QObject *me) { expression = expr; QDeclarativeAbstractExpression::setContext(ctxt); setScopeObject(me); expressionFunctionValid = false; expressionFunctionRewritten = false; } void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle func, QObject *me) { QDeclarativeAbstractExpression::setContext(ctxt); setScopeObject(me); v8function = qPersistentNew(func); setUseSharedContext(false); expressionFunctionValid = true; expressionFunctionRewritten = false; extractExpressionFromFunction = true; } 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; expression = expr; expressionFunctionValid = false; expressionFunctionRewritten = isRewritten; QDeclarativeAbstractExpression::setContext(ctxt); setScopeObject(me); } void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QByteArray &expr, bool isRewritten, QObject *me, const QString &srcUrl, int lineNumber, int columnNumber) { url = srcUrl; line = lineNumber; column = columnNumber; if (isRewritten) { expressionFunctionValid = true; expressionFunctionRewritten = true; v8function = evalFunction(ctxt, me, expr.constData(), expr.length(), srcUrl, lineNumber, &v8qmlscope); setUseSharedContext(false); expressionUtf8 = expr; } else { expression = QString::fromUtf8(expr); expressionFunctionValid = false; expressionFunctionRewritten = isRewritten; } QDeclarativeAbstractExpression::setContext(ctxt); setScopeObject(me); } // Callee owns the persistent handle v8::Persistent QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope, const char *code, int codeLength, const QString &filename, int line, v8::Persistent *qmlscope) { QDeclarativeEngine *engine = ctxt->engine; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); v8::HandleScope handle_scope; v8::Context::Scope ctxtscope(ep->v8engine()->context()); v8::TryCatch tc; v8::Local scopeobject = ep->v8engine()->qmlScope(ctxt, scope); v8::Local script = ep->v8engine()->qmlModeCompile(code, codeLength, filename, line); if (tc.HasCaught()) { QDeclarativeError error; error.setDescription(QLatin1String("Exception occurred during function compilation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); v8::Local message = tc.Message(); if (!message.IsEmpty()) QDeclarativeExpressionPrivate::exceptionToError(message, error); ep->warning(error); return v8::Persistent(); } v8::Local result = script->Run(scopeobject); if (tc.HasCaught()) { QDeclarativeError error; error.setDescription(QLatin1String("Exception occurred during function evaluation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); v8::Local message = tc.Message(); if (!message.IsEmpty()) QDeclarativeExpressionPrivate::exceptionToError(message, error); ep->warning(error); return v8::Persistent(); } if (qmlscope) *qmlscope = qPersistentNew(scopeobject); return qPersistentNew(v8::Local::Cast(result)); } // Callee owns the persistent handle v8::Persistent QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope, const QString &code, const QString &filename, int line, v8::Persistent *qmlscope) { QDeclarativeEngine *engine = ctxt->engine; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); v8::HandleScope handle_scope; v8::Context::Scope ctxtscope(ep->v8engine()->context()); v8::TryCatch tc; v8::Local scopeobject = ep->v8engine()->qmlScope(ctxt, scope); v8::Local script = ep->v8engine()->qmlModeCompile(code, filename, line); if (tc.HasCaught()) { QDeclarativeError error; error.setDescription(QLatin1String("Exception occurred during function compilation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); v8::Local message = tc.Message(); if (!message.IsEmpty()) QDeclarativeExpressionPrivate::exceptionToError(message, error); ep->warning(error); return v8::Persistent(); } v8::Local result = script->Run(scopeobject); if (tc.HasCaught()) { QDeclarativeError error; error.setDescription(QLatin1String("Exception occurred during function evaluation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); v8::Local message = tc.Message(); if (!message.IsEmpty()) QDeclarativeExpressionPrivate::exceptionToError(message, error); ep->warning(error); return v8::Persistent(); } if (qmlscope) *qmlscope = qPersistentNew(scopeobject); return qPersistentNew(v8::Local::Cast(result)); } QDeclarativeExpression * QDeclarativeExpressionPrivate::create(QDeclarativeContextData *ctxt, QObject *object, const QString &expr, bool isRewritten, const QString &url, int lineNumber, int columnNumber) { return new QDeclarativeExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QDeclarativeExpressionPrivate); } /*! \class QDeclarativeExpression \since 4.7 \brief The QDeclarativeExpression class evaluates JavaScript in a QML context. For example, given a file \c main.qml like this: \qml import QtQuick 2.0 Item { width: 200; height: 200 } \endqml The following code evaluates a JavaScript expression in the context of the above QML: \code QDeclarativeEngine *engine = new QDeclarativeEngine; QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml")); QObject *myObject = component.create(); QDeclarativeExpression *expr = new QDeclarativeExpression(engine->rootContext(), myObject, "width * 2"); int result = expr->evaluate().toInt(); // result = 400 \endcode */ /*! Create an invalid QDeclarativeExpression. As the expression will not have an associated QDeclarativeContext, this will be a null expression object and its value will always be an invalid QVariant. */ QDeclarativeExpression::QDeclarativeExpression() : QObject(*new QDeclarativeExpressionPrivate, 0) { } /*! \internal */ 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, isRewritten, object, url, lineNumber, columnNumber); } /*! \internal */ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *object, const QByteArray &expr, bool isRewritten, const QString &url, int lineNumber, int columnNumber, QDeclarativeExpressionPrivate &dd) : QObject(dd, 0) { Q_D(QDeclarativeExpression); 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 (cdata) cdata->release(); if (typeData) typeData->release(); } if (defaultConstruction) d->init(QDeclarativeContextData::get(script.context()), script.script(), script.scopeObject()); } /*! Create a QDeclarativeExpression object that is a child of \a parent. The \a expression JavaScript will be executed in the \a ctxt QDeclarativeContext. If specified, the \a scope object's properties will also be in scope during the expression's execution. */ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt, QObject *scope, const QString &expression, QObject *parent) : QObject(*new QDeclarativeExpressionPrivate, parent) { Q_D(QDeclarativeExpression); d->init(QDeclarativeContextData::get(ctxt), expression, scope); } /*! \internal */ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QString &expression) : QObject(*new QDeclarativeExpressionPrivate, 0) { Q_D(QDeclarativeExpression); d->init(ctxt, expression, scope); } /*! \internal */ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QString &expression, QDeclarativeExpressionPrivate &dd) : QObject(dd, 0) { Q_D(QDeclarativeExpression); d->init(ctxt, expression, scope); } /*! \internal To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle. For example: v8::Handle function; new QDeclarativeExpression(ctxt, scope, &function, ...); */ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr, QDeclarativeExpressionPrivate &dd) : QObject(dd, 0) { v8::Handle function = *(v8::Handle *)functionPtr; Q_D(QDeclarativeExpression); d->init(ctxt, function, scope); } /*! Destroy the QDeclarativeExpression instance. */ QDeclarativeExpression::~QDeclarativeExpression() { } /*! Returns the QDeclarativeEngine this expression is associated with, or 0 if there is no association or the QDeclarativeEngine has been destroyed. */ QDeclarativeEngine *QDeclarativeExpression::engine() const { Q_D(const QDeclarativeExpression); return d->context()?d->context()->engine:0; } /*! Returns the QDeclarativeContext this expression is associated with, or 0 if there is no association or the QDeclarativeContext has been destroyed. */ QDeclarativeContext *QDeclarativeExpression::context() const { Q_D(const QDeclarativeExpression); QDeclarativeContextData *data = d->context(); return data?data->asQDeclarativeContext():0; } /*! Returns the expression string. */ 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)); } else if (!d->expressionUtf8.isEmpty()) { return QString::fromUtf8(d->expressionUtf8); } else { return d->expression; } } /*! Set the expression to \a expression. */ void QDeclarativeExpression::setExpression(const QString &expression) { Q_D(QDeclarativeExpression); d->resetNotifyOnValueChanged(); d->expression = expression; d->expressionUtf8.clear(); d->expressionFunctionValid = false; d->expressionFunctionRewritten = false; qPersistentDispose(d->v8function); qPersistentDispose(d->v8qmlscope); } void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle message, QDeclarativeError &error) { Q_ASSERT(!message.IsEmpty()); v8::Handle name = message->GetScriptResourceName(); v8::Handle description = message->Get(); int lineNumber = message->GetLineNumber(); 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))); error.setLine(lineNumber); error.setColumn(-1); QString qDescription = QV8Engine::toStringStatic(description); if (qDescription.startsWith(QLatin1String("Uncaught "))) qDescription = qDescription.mid(9 /* strlen("Uncaught ") */); error.setDescription(qDescription); } void QDeclarativeJavaScriptExpression::setNotifyOnValueChanged(bool v) { activeGuards.setFlagValue(v); if (!v) clearGuards(); } void QDeclarativeJavaScriptExpression::resetNotifyOnValueChanged() { clearGuards(); } v8::Local QDeclarativeJavaScriptExpression::evaluate(QDeclarativeContextData *context, v8::Handle function, bool *isUndefined) { Q_ASSERT(context && context->engine); if (function.IsEmpty() || function->IsUndefined()) { if (isUndefined) *isUndefined = true; return v8::Local(); } QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine); Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty()); GuardCapture capture(context->engine, this); QDeclarativeEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture; ep->propertyCapture = notifyOnValueChanged()?&capture:0; if (notifyOnValueChanged()) capture.guards.copyAndClearPrepend(activeGuards); QDeclarativeContextData *lastSharedContext = 0; QObject *lastSharedScope = 0; bool sharedContext = useSharedContext(); // All code that follows must check with watcher before it accesses data members // incase we have been deleted. DeleteWatcher watcher(this); if (sharedContext) { lastSharedContext = ep->sharedContext; lastSharedScope = ep->sharedScope; ep->sharedContext = context; ep->sharedScope = scopeObject(); } 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); } result = function->Call(This, 0, 0); if (isUndefined) *isUndefined = try_catch.HasCaught() || result->IsUndefined(); 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, delayedError()->error); } else { if (hasDelayedError()) delayedError()->error = QDeclarativeError(); } } else { if (hasDelayedError()) delayedError()->error = QDeclarativeError(); } } if (sharedContext) { ep->sharedContext = lastSharedContext; ep->sharedScope = lastSharedScope; } 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; } while (Guard *g = capture.guards.takeFirst()) g->Delete(); ep->propertyCapture = lastPropertyCapture; return result; } void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QDeclarativeNotifier *n) { if (expression) { // Try and find a matching guard while (!guards.isEmpty() && !guards.first()->isConnected(n)) guards.takeFirst()->Delete(); Guard *g = 0; if (!guards.isEmpty()) { g = guards.takeFirst(); g->cancelNotify(); Q_ASSERT(g->isConnected(n)); } else { g = Guard::New(expression, engine); g->connect(n); } expression->activeGuards.prepend(g); } } 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->m_vtable->expressionIdentifier(expression) + QLatin1String(" depends on non-NOTIFYable properties:"); errorString->append(preamble); } const QMetaObject *metaObj = o->metaObject(); QMetaProperty metaProp = metaObj->property(c); QString error = QLatin1String(" ") + QString::fromUtf8(metaObj->className()) + QLatin1String("::") + QString::fromUtf8(metaProp.name()); errorString->append(error); } else { // 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 { g = Guard::New(expression, engine); g->connect(o, n); } expression->activeGuards.prepend(g); } } } void QDeclarativeJavaScriptExpression::clearError() { if (m_vtable.hasValue()) { m_vtable.value().error = QDeclarativeError(); m_vtable.value().removeError(); } } QDeclarativeError QDeclarativeJavaScriptExpression::error() const { if (m_vtable.hasValue()) return m_vtable.constValue()->error; else return QDeclarativeError(); } QDeclarativeDelayedError *QDeclarativeJavaScriptExpression::delayedError() { return &m_vtable.value(); } 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) { bool ok = true; QDeclarativeRewrite::RewriteBinding rewriteBinding; rewriteBinding.setName(name); 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; } if (secondaryScope) { v8::Local result; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::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); } } QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) { Q_Q(QDeclarativeExpression); if (!context() || !context()->isValid()) { qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context"); return QVariant(); } QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine()); QVariant rv; ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. { v8::HandleScope handle_scope; v8::Context::Scope context_scope(ep->v8engine()->context()); v8::Local result = v8value(secondaryScope, isUndefined); rv = ep->v8engine()->toVariant(result, qMetaTypeId >()); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. return rv; } /*! Evaulates the expression, returning the result of the evaluation, or an invalid QVariant if the expression is invalid or has an error. \a valueIsUndefined is set to true if the expression resulted in an undefined value. \sa hasError(), error() */ QVariant QDeclarativeExpression::evaluate(bool *valueIsUndefined) { Q_D(QDeclarativeExpression); return d->value(0, valueIsUndefined); } /*! Returns true if the valueChanged() signal is emitted when the expression's evaluated value changes. */ bool QDeclarativeExpression::notifyOnValueChanged() const { Q_D(const QDeclarativeExpression); return d->notifyOnValueChanged(); } /*! Sets whether the valueChanged() signal is emitted when the expression's evaluated value changes. If \a notifyOnChange is true, the QDeclarativeExpression will monitor properties involved in the expression's evaluation, and emit QDeclarativeExpression::valueChanged() if they have changed. This allows an application to ensure that any value associated with the result of the expression remains up to date. If \a notifyOnChange is false (default), the QDeclarativeExpression will not montitor properties involved in the expression's evaluation, and QDeclarativeExpression::valueChanged() will never be emitted. This is more efficient if an application wants a "one off" evaluation of the expression. */ void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange) { Q_D(QDeclarativeExpression); d->setNotifyOnValueChanged(notifyOnChange); } /*! Returns the source file URL for this expression. The source location must have been previously set by calling setSourceLocation(). */ QString QDeclarativeExpression::sourceFile() const { Q_D(const QDeclarativeExpression); return d->url; } /*! Returns the source file line number for this expression. The source location must have been previously set by calling setSourceLocation(). */ int QDeclarativeExpression::lineNumber() const { Q_D(const QDeclarativeExpression); return d->line; } /*! 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, int column) { Q_D(QDeclarativeExpression); d->url = url; d->line = line; d->column = column; } /*! Returns the expression's scope object, if provided, otherwise 0. In addition to data provided by the expression's QDeclarativeContext, the scope object's properties are also in scope during the expression's evaluation. */ QObject *QDeclarativeExpression::scopeObject() const { Q_D(const QDeclarativeExpression); return d->scopeObject(); } /*! Returns true if the last call to evaluate() resulted in an error, otherwise false. \sa error(), clearError() */ bool QDeclarativeExpression::hasError() const { Q_D(const QDeclarativeExpression); return d->hasError(); } /*! Clear any expression errors. Calls to hasError() following this will return false. \sa hasError(), error() */ void QDeclarativeExpression::clearError() { Q_D(QDeclarativeExpression); d->clearError(); } /*! Return any error from the last call to evaluate(). If there was no error, this returns an invalid QDeclarativeError instance. \sa hasError(), clearError() */ QDeclarativeError QDeclarativeExpression::error() const { Q_D(const QDeclarativeExpression); return d->error(); } /*! \fn void QDeclarativeExpression::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 QDeclarativeExpression::evaluate()) before this signal will be emitted. */ void QDeclarativeExpressionPrivate::expressionChanged(QDeclarativeJavaScriptExpression *e) { QDeclarativeExpressionPrivate *This = static_cast(e); This->expressionChanged(); } void QDeclarativeExpressionPrivate::expressionChanged() { Q_Q(QDeclarativeExpression); emit q->valueChanged(); } QString QDeclarativeExpressionPrivate::expressionIdentifier(QDeclarativeJavaScriptExpression *e) { QDeclarativeExpressionPrivate *This = static_cast(e); return QLatin1String("\"") + This->expression + QLatin1String("\""); } QDeclarativeAbstractExpression::QDeclarativeAbstractExpression() : m_prevExpression(0), m_nextExpression(0) { } QDeclarativeAbstractExpression::~QDeclarativeAbstractExpression() { if (m_prevExpression) { *m_prevExpression = m_nextExpression; if (m_nextExpression) m_nextExpression->m_prevExpression = m_prevExpression; } if (m_context.isT2()) m_context.asT2()->_s = 0; } QDeclarativeContextData *QDeclarativeAbstractExpression::context() const { if (m_context.isT1()) return m_context.asT1(); else return m_context.asT2()->_c; } void QDeclarativeAbstractExpression::setContext(QDeclarativeContextData *context) { if (m_prevExpression) { *m_prevExpression = m_nextExpression; if (m_nextExpression) m_nextExpression->m_prevExpression = m_prevExpression; m_prevExpression = 0; m_nextExpression = 0; } if (m_context.isT1()) m_context = context; else m_context.asT2()->_c = context; if (context) { m_nextExpression = context->expressions; if (m_nextExpression) m_nextExpression->m_prevExpression = &m_nextExpression; m_prevExpression = &context->expressions; context->expressions = this; } } void QDeclarativeAbstractExpression::refresh() { } bool QDeclarativeAbstractExpression::isValid() const { return context() != 0; } QT_END_NAMESPACE #include