e616d0a6d11a5c56a82ab1ed81834f85f99e338d
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeexpression.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativeexpression.h"
43 #include "qdeclarativeexpression_p.h"
44
45 #include "qdeclarativeengine_p.h"
46 #include "qdeclarativecontext_p.h"
47 #include "qdeclarativerewrite_p.h"
48 #include "qdeclarativescriptstring_p.h"
49 #include "qdeclarativecompiler_p.h"
50
51 #include <QtCore/qdebug.h>
52
53 QT_BEGIN_NAMESPACE
54
55 bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e)
56 {
57     if (!e) return false;
58
59     if (e->inProgressCreations == 0) return false; // Not in construction
60
61     if (prevError) return true; // Already in error chain
62
63     prevError = &e->erroredBindings;
64     nextError = e->erroredBindings;
65     e->erroredBindings = this;
66     if (nextError) nextError->prevError = &nextError;
67
68     return true;
69 }
70
71 QDeclarativeJavaScriptExpression::QDeclarativeJavaScriptExpression()
72 : m_requiresThisObject(0), m_useSharedContext(0), m_notifyOnValueChanged(0), 
73   m_scopeObject(0), guardCapture(0)
74 {
75 }
76
77 QDeclarativeJavaScriptExpression::~QDeclarativeJavaScriptExpression()
78 {
79     if (guardCapture) guardCapture->expression = 0;
80     clearGuards();
81 }
82
83 QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
84 : expressionFunctionValid(true), expressionFunctionRewritten(false),
85   extractExpressionFromFunction(false), line(-1), dataRef(0)
86 {
87 }
88
89 QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate()
90 {
91     qPersistentDispose(v8qmlscope);
92     qPersistentDispose(v8function);
93     if (dataRef) dataRef->release();
94     dataRef = 0;
95 }
96
97 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, 
98                                          QObject *me)
99 {
100     expression = expr;
101
102     QDeclarativeAbstractExpression::setContext(ctxt);
103     setScopeObject(me);
104     expressionFunctionValid = false;
105     expressionFunctionRewritten = false;
106 }
107
108 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
109                                          QObject *me)
110 {
111     QDeclarativeAbstractExpression::setContext(ctxt);
112     setScopeObject(me);
113
114     v8function = qPersistentNew<v8::Function>(func);
115     setUseSharedContext(false);
116     expressionFunctionValid = true;
117     expressionFunctionRewritten = false;
118     extractExpressionFromFunction = true;
119 }
120
121 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr,
122                                          bool isRewritten, QObject *me, const QString &srcUrl,
123                                          int lineNumber, int columnNumber)
124 {
125     url = srcUrl;
126     line = lineNumber;
127     column = columnNumber;
128
129     expression = expr;
130
131     expressionFunctionValid = false;
132     expressionFunctionRewritten = isRewritten;
133
134     QDeclarativeAbstractExpression::setContext(ctxt);
135     setScopeObject(me);
136 }
137
138 // Callee owns the persistent handle
139 v8::Persistent<v8::Function> 
140 QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope, 
141                                             const QString &code, const QString &filename, int line,
142                                             v8::Persistent<v8::Object> *qmlscope)
143 {
144     QDeclarativeEngine *engine = ctxt->engine;
145     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
146
147     // XXX TODO: Implement script caching, like we used to do with QScriptProgram in the
148     // QtScript days
149     v8::HandleScope handle_scope;
150     v8::Context::Scope ctxtscope(ep->v8engine()->context());
151     
152     v8::TryCatch tc;
153     v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
154     v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line);
155     if (tc.HasCaught()) return v8::Persistent<v8::Function>();
156     v8::Local<v8::Value> result = script->Run(scopeobject);
157     if (tc.HasCaught()) return v8::Persistent<v8::Function>();
158     if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
159     return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
160 }
161
162 QDeclarativeExpression *QDeclarativeExpressionPrivate::create(QDeclarativeContextData *ctxt, QObject *object, const QString &expr, bool isRewritten,
163                                       const QString &url, int lineNumber, int columnNumber)
164 {
165     return new QDeclarativeExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QDeclarativeExpressionPrivate);
166 }
167
168 /*!
169     \class QDeclarativeExpression
170     \since 4.7
171     \brief The QDeclarativeExpression class evaluates JavaScript in a QML context.
172
173     For example, given a file \c main.qml like this:
174
175     \qml
176     import QtQuick 1.0
177
178     Item {
179         width: 200; height: 200
180     }
181     \endqml
182
183     The following code evaluates a JavaScript expression in the context of the
184     above QML:
185
186     \code
187     QDeclarativeEngine *engine = new QDeclarativeEngine;
188     QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
189
190     QObject *myObject = component.create();
191     QDeclarativeExpression *expr = new QDeclarativeExpression(engine->rootContext(), myObject, "width * 2");
192     int result = expr->evaluate().toInt();  // result = 400
193     \endcode
194 */
195
196 /*!
197     Create an invalid QDeclarativeExpression.
198
199     As the expression will not have an associated QDeclarativeContext, this will be a
200     null expression object and its value will always be an invalid QVariant.
201  */
202 QDeclarativeExpression::QDeclarativeExpression()
203 : QObject(*new QDeclarativeExpressionPrivate, 0)
204 {
205 }
206
207 /*!  \internal */
208 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, 
209                                                QObject *object, const QString &expr, bool isRewritten,
210                                                const QString &url, int lineNumber, int columnNumber,
211                                                QDeclarativeExpressionPrivate &dd)
212 : QObject(dd, 0)
213 {
214     Q_D(QDeclarativeExpression);
215     d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
216 }
217
218 /*!
219     Create a QDeclarativeExpression object that is a child of \a parent.
220
221     The \script provides the expression to be evaluated, the context to evaluate it in,
222     and the scope object to evaluate it with.
223
224     This constructor is functionally equivalent to the following, but in most cases
225     is more efficient.
226     \code
227     QDeclarativeExpression expression(script.context(), script.scopeObject(), script.script(), parent);
228     \endcode
229
230     \sa QDeclarativeScriptString
231 */
232 QDeclarativeExpression::QDeclarativeExpression(const QDeclarativeScriptString &script, QObject *parent)
233 : QObject(*new QDeclarativeExpressionPrivate, parent)
234 {
235     Q_D(QDeclarativeExpression);
236     bool defaultConstruction = false;
237
238     int id = script.d.data()->bindingId;
239     if (id < 0) {
240         defaultConstruction = true;
241     } else {
242         QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(script.context());
243
244         QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(script.context()->engine());
245         QDeclarativeCompiledData *cdata = 0;
246         QDeclarativeTypeData *typeData = 0;
247         if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
248             typeData = engine->typeLoader.get(ctxtdata->url);
249             cdata = typeData->compiledData();
250         }
251
252         if (cdata)
253             d->init(ctxtdata, cdata->primitives.at(id), true, script.scopeObject(),
254                     cdata->name, script.d.data()->lineNumber, script.d.data()->columnNumber);
255         else
256            defaultConstruction = true;
257
258         if (cdata)
259             cdata->release();
260         if (typeData)
261             typeData->release();
262     }
263
264     if (defaultConstruction)
265         d->init(QDeclarativeContextData::get(script.context()), script.script(), script.scopeObject());
266 }
267
268 /*!
269     Create a QDeclarativeExpression object that is a child of \a parent.
270
271     The \a expression JavaScript will be executed in the \a ctxt QDeclarativeContext.
272     If specified, the \a scope object's properties will also be in scope during
273     the expression's execution.
274 */
275 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt,
276                                                QObject *scope,
277                                                const QString &expression,
278                                                QObject *parent)
279 : QObject(*new QDeclarativeExpressionPrivate, parent)
280 {
281     Q_D(QDeclarativeExpression);
282     d->init(QDeclarativeContextData::get(ctxt), expression, scope);
283 }
284
285 /*! 
286     \internal
287 */
288 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
289                                                const QString &expression)
290 : QObject(*new QDeclarativeExpressionPrivate, 0)
291 {
292     Q_D(QDeclarativeExpression);
293     d->init(ctxt, expression, scope);
294 }
295
296 /*!  \internal */
297 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
298                                                const QString &expression, QDeclarativeExpressionPrivate &dd)
299 : QObject(dd, 0)
300 {
301     Q_D(QDeclarativeExpression);
302     d->init(ctxt, expression, scope);
303 }
304
305 /*!  
306     \internal 
307
308     To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.  
309     For example:
310         v8::Handle<v8::Function> function;
311         new QDeclarativeExpression(ctxt, scope, &function, ...);
312  */
313 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr,
314                                                QDeclarativeExpressionPrivate &dd)
315 : QObject(dd, 0)
316 {
317     v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
318
319     Q_D(QDeclarativeExpression);
320     d->init(ctxt, function, scope);
321 }
322
323 /*!
324     Destroy the QDeclarativeExpression instance.
325 */
326 QDeclarativeExpression::~QDeclarativeExpression()
327 {
328 }
329
330 /*!
331     Returns the QDeclarativeEngine this expression is associated with, or 0 if there
332     is no association or the QDeclarativeEngine has been destroyed.
333 */
334 QDeclarativeEngine *QDeclarativeExpression::engine() const
335 {
336     Q_D(const QDeclarativeExpression);
337     return d->context()?d->context()->engine:0;
338 }
339
340 /*!
341     Returns the QDeclarativeContext this expression is associated with, or 0 if there
342     is no association or the QDeclarativeContext has been destroyed.
343 */
344 QDeclarativeContext *QDeclarativeExpression::context() const
345 {
346     Q_D(const QDeclarativeExpression);
347     QDeclarativeContextData *data = d->context();
348     return data?data->asQDeclarativeContext():0;
349 }
350
351 /*!
352     Returns the expression string.
353 */
354 QString QDeclarativeExpression::expression() const
355 {
356     Q_D(const QDeclarativeExpression);
357     if (d->extractExpressionFromFunction && context()->engine()) {
358         QV8Engine *v8engine = QDeclarativeEnginePrivate::getV8Engine(context()->engine());
359         v8::HandleScope handle_scope;
360         v8::Context::Scope scope(v8engine->context());
361
362         return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
363     }
364     return d->expression;
365 }
366
367 /*!
368     Set the expression to \a expression.
369 */
370 void QDeclarativeExpression::setExpression(const QString &expression)
371 {
372     Q_D(QDeclarativeExpression);
373
374     d->resetNotifyOnValueChanged();
375     d->expression = expression;
376     d->expressionFunctionValid = false;
377     d->expressionFunctionRewritten = false;
378     qPersistentDispose(d->v8function);
379     qPersistentDispose(d->v8qmlscope);
380 }
381
382 void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message, 
383                                                      QDeclarativeError &error)
384 {
385     Q_ASSERT(!message.IsEmpty());
386
387     v8::Handle<v8::Value> name = message->GetScriptResourceName();
388     v8::Handle<v8::String> description = message->Get();
389     int lineNumber = message->GetLineNumber();
390
391     v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>();
392     if (file.IsEmpty() || file->Length() == 0) 
393         error.setUrl(QUrl(QLatin1String("<Unknown File>")));
394     else 
395         error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
396
397     error.setLine(lineNumber);
398     error.setColumn(-1);
399
400     QString qDescription = QV8Engine::toStringStatic(description);
401     if (qDescription.startsWith(QLatin1String("Uncaught ")))
402         qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
403
404     error.setDescription(qDescription);
405 }
406
407 void QDeclarativeJavaScriptExpression::setNotifyOnValueChanged(bool v)
408 {
409     m_notifyOnValueChanged = v;
410     if (!v) clearGuards();
411 }
412
413 void QDeclarativeJavaScriptExpression::resetNotifyOnValueChanged()
414 {
415     clearGuards();
416 }
417
418 v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::Function> function, bool *isUndefined)
419 {
420     Q_ASSERT(context() && context()->engine);
421
422     if (function.IsEmpty() || function->IsUndefined()) {
423         if (isUndefined) *isUndefined = true;
424         return v8::Local<v8::Value>();
425     }
426
427     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
428
429     Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
430     GuardCapture capture(this);
431
432     QDeclarativeEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
433     ep->propertyCapture = notifyOnValueChanged()?&capture:0;
434
435
436     if (notifyOnValueChanged())
437         capture.guards.copyAndClear(activeGuards);
438
439     QDeclarativeContextData *lastSharedContext = 0;
440     QObject *lastSharedScope = 0;
441
442     bool sharedContext = useSharedContext();
443
444     // All code that follows must check with watcher before it accesses data members 
445     // incase we have been deleted.
446     QDeleteWatcher watcher(this);
447
448     if (sharedContext) {
449         lastSharedContext = ep->sharedContext;
450         lastSharedScope = ep->sharedScope;
451         ep->sharedContext = context();
452         ep->sharedScope = scopeObject();
453     }
454
455     v8::Local<v8::Value> result;
456     {
457         v8::TryCatch try_catch;
458         v8::Handle<v8::Object> This = ep->v8engine()->global();
459         if (scopeObject() && requiresThisObject()) {
460             v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
461             if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
462         }
463
464         result = function->Call(This, 0, 0);
465
466         if (isUndefined)
467             *isUndefined = try_catch.HasCaught() || result->IsUndefined();
468
469         if (watcher.wasDeleted()) {
470         } else if (try_catch.HasCaught()) {
471             v8::Context::Scope scope(ep->v8engine()->context());
472             v8::Local<v8::Message> message = try_catch.Message();
473             if (!message.IsEmpty()) {
474                 QDeclarativeExpressionPrivate::exceptionToError(message, error);
475             } else {
476                 error = QDeclarativeError();
477             }
478         } else {
479             error = QDeclarativeError();
480         }
481     }
482
483     if (sharedContext) {
484         ep->sharedContext = lastSharedContext;
485         ep->sharedScope = lastSharedScope;
486     }
487
488     if (capture.errorString) {
489         for (int ii = 0; ii < capture.errorString->count(); ++ii)
490             qWarning("%s", qPrintable(capture.errorString->at(ii)));
491         delete capture.errorString;
492         capture.errorString = 0;
493     }
494
495     while (Guard *g = capture.guards.takeFirst())
496         g->Delete();
497
498     ep->propertyCapture = lastPropertyCapture;
499
500     return result;
501 }
502
503 void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QDeclarativeNotifier *n)
504 {
505     if (expression) {
506
507         // Try and find a matching guard
508         while (!guards.isEmpty() && !guards.first()->isConnected(n))
509             guards.takeFirst()->Delete();
510
511         Guard *g = 0;
512         if (!guards.isEmpty()) {
513             g = guards.takeFirst();
514             g->cancelNotify();
515             Q_ASSERT(g->isConnected(n));
516         } else {
517             g = Guard::New(expression);
518             g->connect(n);
519         }
520
521         expression->activeGuards.append(g);
522     }
523 }
524
525 void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
526 {
527     if (expression) {
528         if (n == -1) {
529             if (!errorString) {
530                 errorString = new QStringList;
531                 QString preamble = QLatin1String("QDeclarativeExpression: Expression ") +
532                                    expression->expressionIdentifier() +
533                                    QLatin1String(" depends on non-NOTIFYable properties:");
534                 errorString->append(preamble);
535             }
536
537             const QMetaObject *metaObj = o->metaObject();
538             QMetaProperty metaProp = metaObj->property(c);
539
540             QString error = QLatin1String("    ") +
541                             QString::fromUtf8(metaObj->className()) +
542                             QLatin1String("::") +
543                             QString::fromUtf8(metaProp.name());
544             errorString->append(error);
545         } else {
546
547             // Try and find a matching guard
548             while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
549                 guards.takeFirst()->Delete();
550
551             Guard *g = 0;
552             if (!guards.isEmpty()) {
553                 g = guards.takeFirst();
554                 g->cancelNotify();
555                 Q_ASSERT(g->isConnected(o, n));
556             } else {
557                 g = Guard::New(expression);
558                 g->connect(o, n);
559             }
560
561             expression->activeGuards.append(g);
562         }
563     }
564 }
565
566 void QDeclarativeJavaScriptExpression::clearGuards()
567 {
568     while (Guard *g = activeGuards.takeFirst())
569         g->Delete();
570 }
571
572 // Must be called with a valid handle scope
573 v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
574 {
575     if (!expressionFunctionValid) {
576         bool ok = true;
577
578         QDeclarativeRewrite::RewriteBinding rewriteBinding;
579         rewriteBinding.setName(name);
580         QString code;
581         if (expressionFunctionRewritten)
582             code = expression;
583         else
584             code = rewriteBinding(expression, &ok);
585
586         if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
587         setUseSharedContext(false);
588         expressionFunctionValid = true;
589     }
590
591
592     if (secondaryScope) {
593         v8::Local<v8::Value> result;
594         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
595         QObject *restoreSecondaryScope = 0;
596         restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
597         result = evaluate(v8function, isUndefined);
598         ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
599         return result;
600     } else {
601         return evaluate(v8function, isUndefined);
602     }
603 }
604
605 QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
606 {
607     Q_Q(QDeclarativeExpression);
608
609     if (!context() || !context()->isValid()) {
610         qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
611         return QVariant();
612     }
613
614     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
615     QVariant rv;
616
617     ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
618
619     {
620         v8::HandleScope handle_scope;
621         v8::Context::Scope context_scope(ep->v8engine()->context());
622         v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
623         rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
624     }
625
626     ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
627
628     return rv;
629 }
630
631 /*!
632     Evaulates the expression, returning the result of the evaluation,
633     or an invalid QVariant if the expression is invalid or has an error.
634
635     \a valueIsUndefined is set to true if the expression resulted in an
636     undefined value.
637
638     \sa hasError(), error()
639 */
640 QVariant QDeclarativeExpression::evaluate(bool *valueIsUndefined)
641 {
642     Q_D(QDeclarativeExpression);
643     return d->value(0, valueIsUndefined);
644 }
645
646 /*!
647 Returns true if the valueChanged() signal is emitted when the expression's evaluated
648 value changes.
649 */
650 bool QDeclarativeExpression::notifyOnValueChanged() const
651 {
652     Q_D(const QDeclarativeExpression);
653     return d->notifyOnValueChanged();
654 }
655
656 /*!
657   Sets whether the valueChanged() signal is emitted when the
658   expression's evaluated value changes.
659
660   If \a notifyOnChange is true, the QDeclarativeExpression will
661   monitor properties involved in the expression's evaluation, and emit
662   QDeclarativeExpression::valueChanged() if they have changed.  This
663   allows an application to ensure that any value associated with the
664   result of the expression remains up to date.
665
666   If \a notifyOnChange is false (default), the QDeclarativeExpression
667   will not montitor properties involved in the expression's
668   evaluation, and QDeclarativeExpression::valueChanged() will never be
669   emitted.  This is more efficient if an application wants a "one off"
670   evaluation of the expression.
671 */
672 void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
673 {
674     Q_D(QDeclarativeExpression);
675     d->setNotifyOnValueChanged(notifyOnChange);
676 }
677
678 /*!
679     Returns the source file URL for this expression.  The source location must
680     have been previously set by calling setSourceLocation().
681 */
682 QString QDeclarativeExpression::sourceFile() const
683 {
684     Q_D(const QDeclarativeExpression);
685     return d->url;
686 }
687
688 /*!
689     Returns the source file line number for this expression.  The source location 
690     must have been previously set by calling setSourceLocation().
691 */
692 int QDeclarativeExpression::lineNumber() const
693 {
694     Q_D(const QDeclarativeExpression);
695     return d->line;
696 }
697
698 /*!
699     Returns the source file column number for this expression.  The source location
700     must have been previously set by calling setSourceLocation().
701 */
702 int QDeclarativeExpression::columnNumber() const
703 {
704     Q_D(const QDeclarativeExpression);
705     return d->column;
706 }
707
708 /*!
709     Set the location of this expression to \a line of \a url. This information
710     is used by the script engine.
711 */
712 void QDeclarativeExpression::setSourceLocation(const QString &url, int line, int column)
713 {
714     Q_D(QDeclarativeExpression);
715     d->url = url;
716     d->line = line;
717     d->column = column;
718 }
719
720 /*!
721     Returns the expression's scope object, if provided, otherwise 0.
722
723     In addition to data provided by the expression's QDeclarativeContext, the scope
724     object's properties are also in scope during the expression's evaluation.
725 */
726 QObject *QDeclarativeExpression::scopeObject() const
727 {
728     Q_D(const QDeclarativeExpression);
729     return d->scopeObject();
730 }
731
732 /*!
733     Returns true if the last call to evaluate() resulted in an error,
734     otherwise false.
735     
736     \sa error(), clearError()
737 */
738 bool QDeclarativeExpression::hasError() const
739 {
740     Q_D(const QDeclarativeExpression);
741     return d->error.isValid();
742 }
743
744 /*!
745     Clear any expression errors.  Calls to hasError() following this will
746     return false.
747
748     \sa hasError(), error()
749 */
750 void QDeclarativeExpression::clearError()
751 {
752     Q_D(QDeclarativeExpression);
753     d->error = QDeclarativeError();
754 }
755
756 /*!
757     Return any error from the last call to evaluate().  If there was no error,
758     this returns an invalid QDeclarativeError instance.
759
760     \sa hasError(), clearError()
761 */
762
763 QDeclarativeError QDeclarativeExpression::error() const
764 {
765     Q_D(const QDeclarativeExpression);
766     return d->error;
767 }
768
769 /*!
770     \fn void QDeclarativeExpression::valueChanged()
771
772     Emitted each time the expression value changes from the last time it was
773     evaluated.  The expression must have been evaluated at least once (by
774     calling QDeclarativeExpression::evaluate()) before this signal will be emitted.
775 */
776
777 void QDeclarativeExpressionPrivate::expressionChanged()
778 {
779     Q_Q(QDeclarativeExpression);
780     emit q->valueChanged();
781 }
782
783 QDeclarativeAbstractExpression::QDeclarativeAbstractExpression()
784 : m_context(0), m_prevExpression(0), m_nextExpression(0)
785 {
786 }
787
788 QDeclarativeAbstractExpression::~QDeclarativeAbstractExpression()
789 {
790     if (m_prevExpression) {
791         *m_prevExpression = m_nextExpression;
792         if (m_nextExpression) 
793             m_nextExpression->m_prevExpression = m_prevExpression;
794     }
795 }
796
797 QDeclarativeContextData *QDeclarativeAbstractExpression::context() const
798 {
799     return m_context;
800 }
801
802 void QDeclarativeAbstractExpression::setContext(QDeclarativeContextData *context)
803 {
804     if (m_prevExpression) {
805         *m_prevExpression = m_nextExpression;
806         if (m_nextExpression) 
807             m_nextExpression->m_prevExpression = m_prevExpression;
808         m_prevExpression = 0;
809         m_nextExpression = 0;
810     }
811
812     m_context = context;
813
814     if (m_context) {
815         m_nextExpression = m_context->expressions;
816         if (m_nextExpression) 
817             m_nextExpression->m_prevExpression = &m_nextExpression;
818         m_prevExpression = &context->expressions;
819         m_context->expressions = this;
820     }
821 }
822
823 void QDeclarativeAbstractExpression::refresh()
824 {
825 }
826
827 bool QDeclarativeAbstractExpression::isValid() const
828 {
829     return m_context != 0;
830 }
831
832 QT_END_NAMESPACE
833
834 #include <moc_qdeclarativeexpression.cpp>