1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlexpression.h"
43 #include "qqmlexpression_p.h"
45 #include "qqmlengine_p.h"
46 #include "qqmlcontext_p.h"
47 #include "qqmlrewrite_p.h"
48 #include "qqmlscriptstring_p.h"
49 #include "qqmlcompiler_p.h"
51 #include <QtCore/qdebug.h>
55 bool QQmlDelayedError::addError(QQmlEnginePrivate *e)
59 if (e->inProgressCreations == 0) return false; // Not in construction
61 if (prevError) return true; // Already in error chain
63 prevError = &e->erroredBindings;
64 nextError = e->erroredBindings;
65 e->erroredBindings = this;
66 if (nextError) nextError->prevError = &nextError;
71 QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v)
76 QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
81 static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = {
82 QQmlExpressionPrivate::expressionIdentifier,
83 QQmlExpressionPrivate::expressionChanged
86 QQmlExpressionPrivate::QQmlExpressionPrivate()
87 : QQmlJavaScriptExpression(&QQmlExpressionPrivate_jsvtable),
88 expressionFunctionValid(true), expressionFunctionRewritten(false),
89 extractExpressionFromFunction(false), line(-1), dataRef(0)
93 QQmlExpressionPrivate::~QQmlExpressionPrivate()
95 qPersistentDispose(v8qmlscope);
96 qPersistentDispose(v8function);
97 if (dataRef) dataRef->release();
101 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
106 QQmlAbstractExpression::setContext(ctxt);
108 expressionFunctionValid = false;
109 expressionFunctionRewritten = false;
112 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, v8::Handle<v8::Function> func,
115 QQmlAbstractExpression::setContext(ctxt);
118 v8function = qPersistentNew<v8::Function>(func);
119 setUseSharedContext(false);
120 expressionFunctionValid = true;
121 expressionFunctionRewritten = false;
122 extractExpressionFromFunction = true;
125 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
126 bool isRewritten, QObject *me, const QString &srcUrl,
127 int lineNumber, int columnNumber)
131 column = columnNumber;
135 expressionFunctionValid = false;
136 expressionFunctionRewritten = isRewritten;
138 QQmlAbstractExpression::setContext(ctxt);
142 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QByteArray &expr,
143 bool isRewritten, QObject *me, const QString &srcUrl,
144 int lineNumber, int columnNumber)
148 column = columnNumber;
151 expressionFunctionValid = true;
152 expressionFunctionRewritten = true;
153 v8function = evalFunction(ctxt, me, expr.constData(), expr.length(),
154 srcUrl, lineNumber, &v8qmlscope);
155 setUseSharedContext(false);
157 expressionUtf8 = expr;
159 expression = QString::fromUtf8(expr);
161 expressionFunctionValid = false;
162 expressionFunctionRewritten = isRewritten;
165 QQmlAbstractExpression::setContext(ctxt);
169 // Callee owns the persistent handle
170 v8::Persistent<v8::Function>
171 QQmlExpressionPrivate::evalFunction(QQmlContextData *ctxt, QObject *scope,
172 const char *code, int codeLength,
173 const QString &filename, int line,
174 v8::Persistent<v8::Object> *qmlscope)
176 QQmlEngine *engine = ctxt->engine;
177 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
179 v8::HandleScope handle_scope;
180 v8::Context::Scope ctxtscope(ep->v8engine()->context());
183 v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
184 v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, codeLength, filename, line);
185 if (tc.HasCaught()) {
187 error.setDescription(QLatin1String("Exception occurred during function compilation"));
189 error.setUrl(QUrl::fromLocalFile(filename));
190 v8::Local<v8::Message> message = tc.Message();
191 if (!message.IsEmpty())
192 QQmlExpressionPrivate::exceptionToError(message, error);
194 return v8::Persistent<v8::Function>();
196 v8::Local<v8::Value> result = script->Run(scopeobject);
197 if (tc.HasCaught()) {
199 error.setDescription(QLatin1String("Exception occurred during function evaluation"));
201 error.setUrl(QUrl::fromLocalFile(filename));
202 v8::Local<v8::Message> message = tc.Message();
203 if (!message.IsEmpty())
204 QQmlExpressionPrivate::exceptionToError(message, error);
206 return v8::Persistent<v8::Function>();
208 if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
209 return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
212 // Callee owns the persistent handle
213 v8::Persistent<v8::Function>
214 QQmlExpressionPrivate::evalFunction(QQmlContextData *ctxt, QObject *scope,
215 const QString &code, const QString &filename, int line,
216 v8::Persistent<v8::Object> *qmlscope)
218 QQmlEngine *engine = ctxt->engine;
219 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
221 v8::HandleScope handle_scope;
222 v8::Context::Scope ctxtscope(ep->v8engine()->context());
225 v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
226 v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line);
227 if (tc.HasCaught()) {
229 error.setDescription(QLatin1String("Exception occurred during function compilation"));
231 error.setUrl(QUrl::fromLocalFile(filename));
232 v8::Local<v8::Message> message = tc.Message();
233 if (!message.IsEmpty())
234 QQmlExpressionPrivate::exceptionToError(message, error);
236 return v8::Persistent<v8::Function>();
238 v8::Local<v8::Value> result = script->Run(scopeobject);
239 if (tc.HasCaught()) {
241 error.setDescription(QLatin1String("Exception occurred during function evaluation"));
243 error.setUrl(QUrl::fromLocalFile(filename));
244 v8::Local<v8::Message> message = tc.Message();
245 if (!message.IsEmpty())
246 QQmlExpressionPrivate::exceptionToError(message, error);
248 return v8::Persistent<v8::Function>();
250 if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
251 return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
255 QQmlExpressionPrivate::create(QQmlContextData *ctxt, QObject *object,
256 const QString &expr, bool isRewritten,
257 const QString &url, int lineNumber, int columnNumber)
259 return new QQmlExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QQmlExpressionPrivate);
263 \class QQmlExpression
265 \brief The QQmlExpression class evaluates JavaScript in a QML context.
267 For example, given a file \c main.qml like this:
273 width: 200; height: 200
277 The following code evaluates a JavaScript expression in the context of the
281 QQmlEngine *engine = new QQmlEngine;
282 QQmlComponent component(engine, QUrl::fromLocalFile("main.qml"));
284 QObject *myObject = component.create();
285 QQmlExpression *expr = new QQmlExpression(engine->rootContext(), myObject, "width * 2");
286 int result = expr->evaluate().toInt(); // result = 400
291 Create an invalid QQmlExpression.
293 As the expression will not have an associated QQmlContext, this will be a
294 null expression object and its value will always be an invalid QVariant.
296 QQmlExpression::QQmlExpression()
297 : QObject(*new QQmlExpressionPrivate, 0)
302 QQmlExpression::QQmlExpression(QQmlContextData *ctxt,
303 QObject *object, const QString &expr, bool isRewritten,
304 const QString &url, int lineNumber, int columnNumber,
305 QQmlExpressionPrivate &dd)
309 d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
313 QQmlExpression::QQmlExpression(QQmlContextData *ctxt,
314 QObject *object, const QByteArray &expr,
316 const QString &url, int lineNumber, int columnNumber,
317 QQmlExpressionPrivate &dd)
321 d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
325 Create a QQmlExpression object that is a child of \a parent.
327 The \script provides the expression to be evaluated, the context to evaluate it in,
328 and the scope object to evaluate it with.
330 This constructor is functionally equivalent to the following, but in most cases
333 QQmlExpression expression(script.context(), script.scopeObject(), script.script(), parent);
338 QQmlExpression::QQmlExpression(const QQmlScriptString &script, QObject *parent)
339 : QObject(*new QQmlExpressionPrivate, parent)
342 bool defaultConstruction = false;
344 int id = script.d.data()->bindingId;
346 defaultConstruction = true;
348 QQmlContextData *ctxtdata = QQmlContextData::get(script.context());
350 QQmlEnginePrivate *engine = QQmlEnginePrivate::get(script.context()->engine());
351 QQmlCompiledData *cdata = 0;
352 QQmlTypeData *typeData = 0;
353 if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
354 typeData = engine->typeLoader.get(ctxtdata->url);
355 cdata = typeData->compiledData();
359 d->init(ctxtdata, cdata->primitives.at(id), true, script.scopeObject(),
360 cdata->name, script.d.data()->lineNumber, script.d.data()->columnNumber);
362 defaultConstruction = true;
370 if (defaultConstruction)
371 d->init(QQmlContextData::get(script.context()), script.script(), script.scopeObject());
375 Create a QQmlExpression object that is a child of \a parent.
377 The \a expression JavaScript will be executed in the \a ctxt QQmlContext.
378 If specified, the \a scope object's properties will also be in scope during
379 the expression's execution.
381 QQmlExpression::QQmlExpression(QQmlContext *ctxt,
383 const QString &expression,
385 : QObject(*new QQmlExpressionPrivate, parent)
388 d->init(QQmlContextData::get(ctxt), expression, scope);
394 QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
395 const QString &expression)
396 : QObject(*new QQmlExpressionPrivate, 0)
399 d->init(ctxt, expression, scope);
403 QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
404 const QString &expression, QQmlExpressionPrivate &dd)
408 d->init(ctxt, expression, scope);
414 To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
416 v8::Handle<v8::Function> function;
417 new QQmlExpression(ctxt, scope, &function, ...);
419 QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope, void *functionPtr,
420 QQmlExpressionPrivate &dd)
423 v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
426 d->init(ctxt, function, scope);
430 Destroy the QQmlExpression instance.
432 QQmlExpression::~QQmlExpression()
437 Returns the QQmlEngine this expression is associated with, or 0 if there
438 is no association or the QQmlEngine has been destroyed.
440 QQmlEngine *QQmlExpression::engine() const
442 Q_D(const QQmlExpression);
443 return d->context()?d->context()->engine:0;
447 Returns the QQmlContext this expression is associated with, or 0 if there
448 is no association or the QQmlContext has been destroyed.
450 QQmlContext *QQmlExpression::context() const
452 Q_D(const QQmlExpression);
453 QQmlContextData *data = d->context();
454 return data?data->asQQmlContext():0;
458 Returns the expression string.
460 QString QQmlExpression::expression() const
462 Q_D(const QQmlExpression);
463 if (d->extractExpressionFromFunction && context()->engine()) {
464 QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(context()->engine());
465 v8::HandleScope handle_scope;
466 v8::Context::Scope scope(v8engine->context());
468 return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
469 } else if (!d->expressionUtf8.isEmpty()) {
470 return QString::fromUtf8(d->expressionUtf8);
472 return d->expression;
477 Set the expression to \a expression.
479 void QQmlExpression::setExpression(const QString &expression)
483 d->resetNotifyOnValueChanged();
484 d->expression = expression;
485 d->expressionUtf8.clear();
486 d->expressionFunctionValid = false;
487 d->expressionFunctionRewritten = false;
488 qPersistentDispose(d->v8function);
489 qPersistentDispose(d->v8qmlscope);
492 void QQmlExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message,
495 Q_ASSERT(!message.IsEmpty());
497 v8::Handle<v8::Value> name = message->GetScriptResourceName();
498 v8::Handle<v8::String> description = message->Get();
499 int lineNumber = message->GetLineNumber();
501 v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>();
502 if (file.IsEmpty() || file->Length() == 0)
503 error.setUrl(QUrl(QLatin1String("<Unknown File>")));
505 error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
507 error.setLine(lineNumber);
510 QString qDescription = QV8Engine::toStringStatic(description);
511 if (qDescription.startsWith(QLatin1String("Uncaught ")))
512 qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
514 error.setDescription(qDescription);
517 void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
519 activeGuards.setFlagValue(v);
520 if (!v) clearGuards();
523 void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
529 QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
530 v8::Handle<v8::Function> function, bool *isUndefined)
532 Q_ASSERT(context && context->engine);
534 if (function.IsEmpty() || function->IsUndefined()) {
535 if (isUndefined) *isUndefined = true;
536 return v8::Local<v8::Value>();
539 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
541 Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
542 GuardCapture capture(context->engine, this);
544 QQmlEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
545 ep->propertyCapture = notifyOnValueChanged()?&capture:0;
548 if (notifyOnValueChanged())
549 capture.guards.copyAndClearPrepend(activeGuards);
551 QQmlContextData *lastSharedContext = 0;
552 QObject *lastSharedScope = 0;
554 bool sharedContext = useSharedContext();
556 // All code that follows must check with watcher before it accesses data members
557 // incase we have been deleted.
558 DeleteWatcher watcher(this);
561 lastSharedContext = ep->sharedContext;
562 lastSharedScope = ep->sharedScope;
563 ep->sharedContext = context;
564 ep->sharedScope = scopeObject();
567 v8::Local<v8::Value> result;
569 v8::TryCatch try_catch;
570 v8::Handle<v8::Object> This = ep->v8engine()->global();
571 if (scopeObject() && requiresThisObject()) {
572 v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
573 if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
576 result = function->Call(This, 0, 0);
579 *isUndefined = try_catch.HasCaught() || result->IsUndefined();
581 if (watcher.wasDeleted()) {
582 } else if (try_catch.HasCaught()) {
583 v8::Context::Scope scope(ep->v8engine()->context());
584 v8::Local<v8::Message> message = try_catch.Message();
585 if (!message.IsEmpty()) {
586 QQmlExpressionPrivate::exceptionToError(message, delayedError()->error);
588 if (hasDelayedError()) delayedError()->error = QQmlError();
591 if (hasDelayedError()) delayedError()->error = QQmlError();
596 ep->sharedContext = lastSharedContext;
597 ep->sharedScope = lastSharedScope;
600 if (capture.errorString) {
601 for (int ii = 0; ii < capture.errorString->count(); ++ii)
602 qWarning("%s", qPrintable(capture.errorString->at(ii)));
603 delete capture.errorString;
604 capture.errorString = 0;
607 while (Guard *g = capture.guards.takeFirst())
610 ep->propertyCapture = lastPropertyCapture;
615 void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n)
619 // Try and find a matching guard
620 while (!guards.isEmpty() && !guards.first()->isConnected(n))
621 guards.takeFirst()->Delete();
624 if (!guards.isEmpty()) {
625 g = guards.takeFirst();
627 Q_ASSERT(g->isConnected(n));
629 g = Guard::New(expression, engine);
633 expression->activeGuards.prepend(g);
637 void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
642 errorString = new QStringList;
643 QString preamble = QLatin1String("QQmlExpression: Expression ") +
644 expression->m_vtable->expressionIdentifier(expression) +
645 QLatin1String(" depends on non-NOTIFYable properties:");
646 errorString->append(preamble);
649 const QMetaObject *metaObj = o->metaObject();
650 QMetaProperty metaProp = metaObj->property(c);
652 QString error = QLatin1String(" ") +
653 QString::fromUtf8(metaObj->className()) +
654 QLatin1String("::") +
655 QString::fromUtf8(metaProp.name());
656 errorString->append(error);
659 // Try and find a matching guard
660 while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
661 guards.takeFirst()->Delete();
664 if (!guards.isEmpty()) {
665 g = guards.takeFirst();
667 Q_ASSERT(g->isConnected(o, n));
669 g = Guard::New(expression, engine);
673 expression->activeGuards.prepend(g);
678 void QQmlJavaScriptExpression::clearError()
680 if (m_vtable.hasValue()) {
681 m_vtable.value().error = QQmlError();
682 m_vtable.value().removeError();
686 QQmlError QQmlJavaScriptExpression::error() const
688 if (m_vtable.hasValue()) return m_vtable.constValue()->error;
689 else return QQmlError();
692 QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
694 return &m_vtable.value();
697 void QQmlJavaScriptExpression::clearGuards()
699 while (Guard *g = activeGuards.takeFirst())
703 // Must be called with a valid handle scope
704 v8::Local<v8::Value> QQmlExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
706 if (!expressionFunctionValid) {
709 QQmlRewrite::RewriteBinding rewriteBinding;
710 rewriteBinding.setName(name);
712 if (expressionFunctionRewritten)
715 code = rewriteBinding(expression, &ok);
717 if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
718 setUseSharedContext(false);
719 expressionFunctionValid = true;
723 if (secondaryScope) {
724 v8::Local<v8::Value> result;
725 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
726 QObject *restoreSecondaryScope = 0;
727 restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
728 result = evaluate(context(), v8function, isUndefined);
729 ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
732 return evaluate(context(), v8function, isUndefined);
736 QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
740 if (!context() || !context()->isValid()) {
741 qWarning("QQmlExpression: Attempted to evaluate an expression in an invalid context");
745 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(q->engine());
748 ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
751 v8::HandleScope handle_scope;
752 v8::Context::Scope context_scope(ep->v8engine()->context());
753 v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
754 rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
757 ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
763 Evaulates the expression, returning the result of the evaluation,
764 or an invalid QVariant if the expression is invalid or has an error.
766 \a valueIsUndefined is set to true if the expression resulted in an
769 \sa hasError(), error()
771 QVariant QQmlExpression::evaluate(bool *valueIsUndefined)
774 return d->value(0, valueIsUndefined);
778 Returns true if the valueChanged() signal is emitted when the expression's evaluated
781 bool QQmlExpression::notifyOnValueChanged() const
783 Q_D(const QQmlExpression);
784 return d->notifyOnValueChanged();
788 Sets whether the valueChanged() signal is emitted when the
789 expression's evaluated value changes.
791 If \a notifyOnChange is true, the QQmlExpression will
792 monitor properties involved in the expression's evaluation, and emit
793 QQmlExpression::valueChanged() if they have changed. This
794 allows an application to ensure that any value associated with the
795 result of the expression remains up to date.
797 If \a notifyOnChange is false (default), the QQmlExpression
798 will not montitor properties involved in the expression's
799 evaluation, and QQmlExpression::valueChanged() will never be
800 emitted. This is more efficient if an application wants a "one off"
801 evaluation of the expression.
803 void QQmlExpression::setNotifyOnValueChanged(bool notifyOnChange)
806 d->setNotifyOnValueChanged(notifyOnChange);
810 Returns the source file URL for this expression. The source location must
811 have been previously set by calling setSourceLocation().
813 QString QQmlExpression::sourceFile() const
815 Q_D(const QQmlExpression);
820 Returns the source file line number for this expression. The source location
821 must have been previously set by calling setSourceLocation().
823 int QQmlExpression::lineNumber() const
825 Q_D(const QQmlExpression);
830 Returns the source file column number for this expression. The source location
831 must have been previously set by calling setSourceLocation().
833 int QQmlExpression::columnNumber() const
835 Q_D(const QQmlExpression);
840 Set the location of this expression to \a line of \a url. This information
841 is used by the script engine.
843 void QQmlExpression::setSourceLocation(const QString &url, int line, int column)
852 Returns the expression's scope object, if provided, otherwise 0.
854 In addition to data provided by the expression's QQmlContext, the scope
855 object's properties are also in scope during the expression's evaluation.
857 QObject *QQmlExpression::scopeObject() const
859 Q_D(const QQmlExpression);
860 return d->scopeObject();
864 Returns true if the last call to evaluate() resulted in an error,
867 \sa error(), clearError()
869 bool QQmlExpression::hasError() const
871 Q_D(const QQmlExpression);
872 return d->hasError();
876 Clear any expression errors. Calls to hasError() following this will
879 \sa hasError(), error()
881 void QQmlExpression::clearError()
888 Return any error from the last call to evaluate(). If there was no error,
889 this returns an invalid QQmlError instance.
891 \sa hasError(), clearError()
894 QQmlError QQmlExpression::error() const
896 Q_D(const QQmlExpression);
901 \fn void QQmlExpression::valueChanged()
903 Emitted each time the expression value changes from the last time it was
904 evaluated. The expression must have been evaluated at least once (by
905 calling QQmlExpression::evaluate()) before this signal will be emitted.
908 void QQmlExpressionPrivate::expressionChanged(QQmlJavaScriptExpression *e)
910 QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e);
911 This->expressionChanged();
914 void QQmlExpressionPrivate::expressionChanged()
917 emit q->valueChanged();
920 QString QQmlExpressionPrivate::expressionIdentifier(QQmlJavaScriptExpression *e)
922 QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e);
923 return QLatin1String("\"") + This->expression + QLatin1String("\"");
926 QQmlAbstractExpression::QQmlAbstractExpression()
927 : m_prevExpression(0), m_nextExpression(0)
931 QQmlAbstractExpression::~QQmlAbstractExpression()
933 if (m_prevExpression) {
934 *m_prevExpression = m_nextExpression;
935 if (m_nextExpression)
936 m_nextExpression->m_prevExpression = m_prevExpression;
939 if (m_context.isT2())
940 m_context.asT2()->_s = 0;
943 QQmlContextData *QQmlAbstractExpression::context() const
945 if (m_context.isT1()) return m_context.asT1();
946 else return m_context.asT2()->_c;
949 void QQmlAbstractExpression::setContext(QQmlContextData *context)
951 if (m_prevExpression) {
952 *m_prevExpression = m_nextExpression;
953 if (m_nextExpression)
954 m_nextExpression->m_prevExpression = m_prevExpression;
955 m_prevExpression = 0;
956 m_nextExpression = 0;
959 if (m_context.isT1()) m_context = context;
960 else m_context.asT2()->_c = context;
963 m_nextExpression = context->expressions;
964 if (m_nextExpression)
965 m_nextExpression->m_prevExpression = &m_nextExpression;
966 m_prevExpression = &context->expressions;
967 context->expressions = this;
971 void QQmlAbstractExpression::refresh()
975 bool QQmlAbstractExpression::isValid() const
977 return context() != 0;
982 #include <moc_qqmlexpression.cpp>