247bde9a6cca089d6aebdc01c88a9726411cb9a4
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeexpression.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
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 "private/qdeclarativeexpression_p.h"
44
45 #include "private/qdeclarativeengine_p.h"
46 #include "private/qdeclarativecontext_p.h"
47 #include "private/qdeclarativerewrite_p.h"
48 #include "private/qdeclarativecompiler_p.h"
49 #include "private/qdeclarativeglobalscriptclass_p.h"
50
51 #include <QtCore/qdebug.h>
52 #include <QtScript/qscriptprogram.h>
53
54 #include <private/qscriptdeclarativeclass_p.h>
55
56 QT_BEGIN_NAMESPACE
57
58 bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e)
59 {
60     if (!e) return false;
61
62     if (e->inProgressCreations == 0) return false; // Not in construction
63
64     if (prevError) return true; // Already in error chain
65
66     prevError = &e->erroredBindings;
67     nextError = e->erroredBindings;
68     e->erroredBindings = this;
69     if (nextError) nextError->prevError = &nextError;
70
71     return true;
72 }
73
74 QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression()
75 : dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false), 
76   guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0)
77 {
78 }
79
80 QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
81 {
82     if (guardList) { delete [] guardList; guardList = 0; }
83     if (dataRef) dataRef->release();
84     if (deleted) *deleted = true;
85 }
86
87 QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
88 : expressionFunctionValid(true), line(-1)
89 {
90 }
91
92 QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate()
93 {
94 }
95
96 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, 
97                                          QObject *me)
98 {
99     expression = expr;
100
101     QDeclarativeAbstractExpression::setContext(ctxt);
102     scopeObject = me;
103     expressionFunctionValid = false;
104 }
105
106 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QScriptValue &func,
107                                          QObject *me)
108 {
109     expression = func.toString();
110
111     QDeclarativeAbstractExpression::setContext(ctxt);
112     scopeObject = me;
113
114     expressionFunction = func;
115     expressionFunctionMode = ExplicitContext;
116     expressionFunctionValid = true;
117 }
118
119 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, 
120                                          QDeclarativeRefCount *rc, 
121                                          QObject *me, const QString &srcUrl, int lineNumber)
122 {
123     url = srcUrl;
124     line = lineNumber;
125
126     if (dataRef) dataRef->release();
127     dataRef = rc;
128     if (dataRef) dataRef->addref();
129
130     quint32 *exprData = (quint32 *)expr;
131     QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc;
132
133     expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]);
134
135     int progIdx = *(exprData);
136     bool isSharedProgram = progIdx & 0x80000000;
137     progIdx &= 0x7FFFFFFF;
138
139     QDeclarativeEngine *engine = ctxt->engine;
140     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
141     QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
142
143     if (isSharedProgram) {
144
145         if (!dd->cachedClosures.at(progIdx)) {
146             QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
147             scriptContext->pushScope(ep->contextClass->newSharedContext());
148             scriptContext->pushScope(ep->globalClass->staticGlobalObject());
149             dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(expression, url, line));
150             scriptEngine->popContext();
151         }
152
153         expressionFunction = *dd->cachedClosures.at(progIdx);
154         expressionFunctionMode = SharedContext;
155         expressionFunctionValid = true;
156
157     } else {
158
159         if (!dd->cachedPrograms.at(progIdx)) {
160             dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line);
161         }
162
163         expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx), 
164                                                      &expressionContext);
165
166         expressionFunctionMode = ExplicitContext;
167         expressionFunctionValid = true;
168     }
169
170     QDeclarativeAbstractExpression::setContext(ctxt);
171     scopeObject = me;
172 }
173
174 QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, 
175                                                               const QString &program, const QString &fileName,
176                                                               int lineNumber, QScriptValue *contextObject)
177 {
178     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
179     QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
180     if (contextObject) {
181         *contextObject = ep->contextClass->newContext(context, object);
182         scriptContext->pushScope(*contextObject);
183     } else {
184         scriptContext->pushScope(ep->contextClass->newContext(context, object));
185     }
186     scriptContext->pushScope(ep->globalClass->staticGlobalObject());
187     QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
188     ep->scriptEngine.popContext();
189     return rv;
190 }
191
192 QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, 
193                                                               const QScriptProgram &program, 
194                                                               QScriptValue *contextObject)
195 {
196     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
197     QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
198     if (contextObject) {
199         *contextObject = ep->contextClass->newContext(context, object);
200         scriptContext->pushScope(*contextObject);
201     } else {
202         scriptContext->pushScope(ep->contextClass->newContext(context, object));
203     }
204     scriptContext->pushScope(ep->globalClass->staticGlobalObject());
205     QScriptValue rv = ep->scriptEngine.evaluate(program);
206     ep->scriptEngine.popContext();
207     return rv;
208 }
209
210 /*!
211     \class QDeclarativeExpression
212     \since 4.7
213     \brief The QDeclarativeExpression class evaluates JavaScript in a QML context.
214
215     For example, given a file \c main.qml like this:
216
217     \qml
218     import QtQuick 1.0
219
220     Item {
221         width: 200; height: 200
222     }
223     \endqml
224
225     The following code evaluates a JavaScript expression in the context of the
226     above QML:
227
228     \code
229     QDeclarativeEngine *engine = new QDeclarativeEngine;
230     QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
231
232     QObject *myObject = component.create();
233     QDeclarativeExpression *expr = new QDeclarativeExpression(engine->rootContext(), myObject, "width * 2");
234     int result = expr->evaluate().toInt();  // result = 400
235     \endcode
236 */
237
238 static int QDeclarativeExpression_notifyIdx = -1;
239
240 /*!
241     Create an invalid QDeclarativeExpression.
242
243     As the expression will not have an associated QDeclarativeContext, this will be a
244     null expression object and its value will always be an invalid QVariant.
245  */
246 QDeclarativeExpression::QDeclarativeExpression()
247 : QObject(*new QDeclarativeExpressionPrivate, 0)
248 {
249     Q_D(QDeclarativeExpression);
250
251     if (QDeclarativeExpression_notifyIdx == -1) 
252         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
253     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
254 }
255
256 /*!  \internal */
257 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, void *expr,
258                                                QDeclarativeRefCount *rc, QObject *me, 
259                                                const QString &url, int lineNumber,
260                                                QDeclarativeExpressionPrivate &dd)
261 : QObject(dd, 0)
262 {
263     Q_D(QDeclarativeExpression);
264     d->init(ctxt, expr, rc, me, url, lineNumber);
265
266     if (QDeclarativeExpression_notifyIdx == -1) 
267         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
268     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
269 }
270
271 /*!
272     Create a QDeclarativeExpression object that is a child of \a parent.
273
274     The \a expression JavaScript will be executed in the \a ctxt QDeclarativeContext.
275     If specified, the \a scope object's properties will also be in scope during
276     the expression's execution.
277 */
278 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt,
279                                                QObject *scope,
280                                                const QString &expression,
281                                                QObject *parent)
282 : QObject(*new QDeclarativeExpressionPrivate, parent)
283 {
284     Q_D(QDeclarativeExpression);
285     d->init(QDeclarativeContextData::get(ctxt), expression, scope);
286
287     if (QDeclarativeExpression_notifyIdx == -1) 
288         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
289     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
290 }
291
292 /*! 
293     \internal
294 */
295 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
296                                                const QString &expression)
297 : QObject(*new QDeclarativeExpressionPrivate, 0)
298 {
299     Q_D(QDeclarativeExpression);
300     d->init(ctxt, expression, scope);
301
302     if (QDeclarativeExpression_notifyIdx == -1) 
303         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
304     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
305 }
306
307 /*!  \internal */
308 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
309                                                const QString &expression, QDeclarativeExpressionPrivate &dd)
310 : QObject(dd, 0)
311 {
312     Q_D(QDeclarativeExpression);
313     d->init(ctxt, expression, scope);
314
315     if (QDeclarativeExpression_notifyIdx == -1) 
316         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
317     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
318 }
319
320 /*!  \internal */
321 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QScriptValue &func,
322                        QDeclarativeExpressionPrivate &dd)
323 : QObject(dd, 0)
324 {
325     Q_D(QDeclarativeExpression);
326     d->init(ctxt, func, scope);
327
328     if (QDeclarativeExpression_notifyIdx == -1)
329         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
330     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
331 }
332
333 /*!
334     Destroy the QDeclarativeExpression instance.
335 */
336 QDeclarativeExpression::~QDeclarativeExpression()
337 {
338 }
339
340 /*!
341     Returns the QDeclarativeEngine this expression is associated with, or 0 if there
342     is no association or the QDeclarativeEngine has been destroyed.
343 */
344 QDeclarativeEngine *QDeclarativeExpression::engine() const
345 {
346     Q_D(const QDeclarativeExpression);
347     return d->context()?d->context()->engine:0;
348 }
349
350 /*!
351     Returns the QDeclarativeContext this expression is associated with, or 0 if there
352     is no association or the QDeclarativeContext has been destroyed.
353 */
354 QDeclarativeContext *QDeclarativeExpression::context() const
355 {
356     Q_D(const QDeclarativeExpression);
357     QDeclarativeContextData *data = d->context();
358     return data?data->asQDeclarativeContext():0;
359 }
360
361 /*!
362     Returns the expression string.
363 */
364 QString QDeclarativeExpression::expression() const
365 {
366     Q_D(const QDeclarativeExpression);
367     return d->expression;
368 }
369
370 /*!
371     Set the expression to \a expression.
372 */
373 void QDeclarativeExpression::setExpression(const QString &expression)
374 {
375     Q_D(QDeclarativeExpression);
376
377     d->resetNotifyOnChange();
378     d->expression = expression;
379     d->expressionFunctionValid = false;
380     d->expressionFunction = QScriptValue();
381 }
382
383 void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, 
384                                             QDeclarativeError &error)
385 {
386     if (scriptEngine->hasUncaughtException() && 
387         scriptEngine->uncaughtException().isError()) {
388
389         QString fileName;
390         int lineNumber = scriptEngine->uncaughtExceptionLineNumber();
391
392         QScriptValue exception = scriptEngine->uncaughtException();
393         QLatin1String fileNameProp("fileName");
394
395         if (!exception.property(fileNameProp).toString().isEmpty()){
396             fileName = exception.property(fileNameProp).toString();
397         } else {
398             fileName = QLatin1String("<Unknown File>");
399         }
400
401         error.setUrl(QUrl(fileName));
402         error.setLine(lineNumber);
403         error.setColumn(-1);
404         error.setDescription(exception.toString());
405     } else {
406         error = QDeclarativeError();
407     }
408 }
409
410 bool QDeclarativeQtScriptExpression::notifyOnValueChange() const
411 {
412     return trackChange;
413 }
414
415 void QDeclarativeQtScriptExpression::setNotifyOnValueChange(bool notify)
416 {
417     trackChange = notify;
418     if (!notify && guardList) 
419         clearGuards();
420 }
421
422 void QDeclarativeQtScriptExpression::resetNotifyOnChange()
423 {
424     clearGuards();
425 }
426
427 void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notifyIndex)
428 {
429     if (guardList) clearGuards();
430
431     if (!object || notifyIndex == -1) {
432         guardObject = 0;
433         notifyIndex = -1;
434     } else {
435         guardObject = object;
436         guardObjectNotifyIndex = notifyIndex;
437
438     }
439 }
440
441 void QDeclarativeQtScriptExpression::setEvaluateFlags(EvaluateFlags flags)
442 {
443     evalFlags = flags;
444 }
445
446 QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::evaluateFlags() const
447 {
448     return evalFlags;
449 }
450
451 QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined)
452 {
453     Q_ASSERT(context() && context()->engine);
454     Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1));
455
456     if (!expressionFunction.isValid()) {
457         if (isUndefined) *isUndefined = true;
458         return QScriptValue();
459     }
460
461     DeleteWatcher watcher(this);
462
463     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
464
465     bool lastCaptureProperties = ep->captureProperties;
466     QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
467     ep->captureProperties = trackChange;
468     ep->capturedProperties.copyAndClear(lastCapturedProperties);
469
470     QScriptValue value = eval(secondaryScope, isUndefined);
471
472     if (!watcher.wasDeleted() && trackChange) {
473         if (ep->capturedProperties.count() == 0) {
474
475             if (guardList) clearGuards();
476
477         } else {
478
479             updateGuards(ep->capturedProperties);
480
481         }
482     }
483
484     lastCapturedProperties.copyAndClear(ep->capturedProperties);
485     ep->captureProperties = lastCaptureProperties;
486
487     return value;
488 }
489
490 QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
491 {
492     Q_ASSERT(context() && context()->engine);
493
494     DeleteWatcher watcher(this);
495
496     QDeclarativeEngine *engine = context()->engine;
497     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
498
499     QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
500
501     QDeclarativeContextData *oldSharedContext = 0;
502     QObject *oldSharedScope = 0;
503     QObject *oldOverride = 0;
504     bool isShared = (expressionFunctionMode == SharedContext);
505
506     if (isShared) {
507         oldSharedContext = ep->sharedContext;
508         oldSharedScope = ep->sharedScope;
509         ep->sharedContext = context();
510         ep->sharedScope = scopeObject;
511     } else {
512         oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope);
513     }
514
515     QScriptValue thisObject;
516     if (evalFlags & RequiresThisObject)
517         thisObject = ep->objectClass->newQObject(scopeObject);
518     QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted
519
520     if (isShared) {
521         ep->sharedContext = oldSharedContext;
522         ep->sharedScope = oldSharedScope;
523     } else if (!watcher.wasDeleted()) {
524         ep->contextClass->setOverrideObject(expressionContext, oldOverride);
525     }
526
527     if (isUndefined)
528         *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException();
529
530     // Handle exception
531     if (scriptEngine->hasUncaughtException()) {
532         if (!watcher.wasDeleted()) 
533            QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
534
535        scriptEngine->clearExceptions();
536        return QScriptValue();
537     } else {
538         if (!watcher.wasDeleted())
539             error = QDeclarativeError();
540
541         return svalue;
542     }
543 }
544
545 void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
546 {
547     Q_ASSERT(guardObject);
548     Q_ASSERT(guardObjectNotifyIndex != -1);
549
550     if (properties.count() != guardListLength) {
551         QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()];
552
553         for (int ii = 0; ii < qMin(guardListLength, properties.count()); ++ii) 
554            guardList[ii].copyAndClear(newGuardList[ii]);
555
556         delete [] guardList;
557         guardList = newGuardList;
558         guardListLength = properties.count();
559     }
560
561     bool outputWarningHeader = false;
562     bool noChanges = true;
563     for (int ii = 0; ii < properties.count(); ++ii) {
564         QDeclarativeNotifierEndpoint &guard = guardList[ii];
565         const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
566
567         guard.target = guardObject;
568         guard.targetMethod = guardObjectNotifyIndex;
569
570         if (property.notifier != 0) {
571
572             if (!noChanges && guard.isConnected(property.notifier)) {
573                 // Nothing to do
574
575             } else {
576                 noChanges = false;
577
578                 bool existing = false;
579                 for (int jj = 0; !existing && jj < ii; ++jj) 
580                     if (guardList[jj].isConnected(property.notifier)) 
581                         existing = true;
582
583                 if (existing) {
584                     // duplicate
585                     guard.disconnect();
586                 } else {
587                     guard.connect(property.notifier);
588                 }
589             }
590
591
592         } else if (property.notifyIndex != -1) {
593
594             if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
595                 // Nothing to do
596
597             } else {
598                 noChanges = false;
599
600                 bool existing = false;
601                 for (int jj = 0; !existing && jj < ii; ++jj) 
602                     if (guardList[jj].isConnected(property.object, property.notifyIndex)) 
603                         existing = true;
604
605                 if (existing) {
606                     // duplicate
607                     guard.disconnect();
608                 } else {
609                     guard.connect(property.object, property.notifyIndex);
610                 }
611             }
612
613         } else {
614             if (!outputWarningHeader) {
615                 outputWarningHeader = true;
616                 qWarning() << "QDeclarativeExpression: Expression" << expression
617                            << "depends on non-NOTIFYable properties:";
618             }
619
620             const QMetaObject *metaObj = property.object->metaObject();
621             QMetaProperty metaProp = metaObj->property(property.coreIndex);
622
623             qWarning().nospace() << "    " << metaObj->className() << "::" << metaProp.name();
624         }
625     }
626 }
627
628 QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
629 {
630     if (!expressionFunctionValid) {
631         QDeclarativeEngine *engine = context()->engine;
632         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
633         QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
634
635         QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
636         expressionContext = ep->contextClass->newContext(context(), scopeObject);
637         scriptContext->pushScope(expressionContext);
638         scriptContext->pushScope(ep->globalClass->staticGlobalObject());
639
640         QDeclarativeRewrite::RewriteBinding rewriteBinding;
641         rewriteBinding.setName(name);
642         bool ok = true;
643         const QString code = rewriteBinding(expression, &ok);
644         if (ok) 
645             expressionFunction = scriptEngine->evaluate(code, url, line);
646
647         scriptEngine->popContext();
648         expressionFunctionMode = ExplicitContext;
649         expressionFunctionValid = true;
650     }
651
652     return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined);
653 }
654
655 QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
656 {
657     Q_Q(QDeclarativeExpression);
658
659     if (!context() || !context()->isValid()) {
660         qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
661         return QVariant();
662     }
663
664     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
665     ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
666     QVariant retn(ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()));
667     ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
668     return retn;
669 }
670
671 /*!
672     Evaulates the expression, returning the result of the evaluation,
673     or an invalid QVariant if the expression is invalid or has an error.
674
675     \a valueIsUndefined is set to true if the expression resulted in an
676     undefined value.
677
678     \sa hasError(), error()
679 */
680 QVariant QDeclarativeExpression::evaluate(bool *valueIsUndefined)
681 {
682     Q_D(QDeclarativeExpression);
683     return d->value(0, valueIsUndefined);
684 }
685
686 /*!
687 Returns true if the valueChanged() signal is emitted when the expression's evaluated
688 value changes.
689 */
690 bool QDeclarativeExpression::notifyOnValueChanged() const
691 {
692     Q_D(const QDeclarativeExpression);
693     return d->notifyOnValueChange();
694 }
695
696 /*!
697   Sets whether the valueChanged() signal is emitted when the
698   expression's evaluated value changes.
699
700   If \a notifyOnChange is true, the QDeclarativeExpression will
701   monitor properties involved in the expression's evaluation, and emit
702   QDeclarativeExpression::valueChanged() if they have changed.  This
703   allows an application to ensure that any value associated with the
704   result of the expression remains up to date.
705
706   If \a notifyOnChange is false (default), the QDeclarativeExpression
707   will not montitor properties involved in the expression's
708   evaluation, and QDeclarativeExpression::valueChanged() will never be
709   emitted.  This is more efficient if an application wants a "one off"
710   evaluation of the expression.
711 */
712 void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
713 {
714     Q_D(QDeclarativeExpression);
715     d->setNotifyOnValueChange(notifyOnChange);
716 }
717
718 /*!
719     Returns the source file URL for this expression.  The source location must
720     have been previously set by calling setSourceLocation().
721 */
722 QString QDeclarativeExpression::sourceFile() const
723 {
724     Q_D(const QDeclarativeExpression);
725     return d->url;
726 }
727
728 /*!
729     Returns the source file line number for this expression.  The source location 
730     must have been previously set by calling setSourceLocation().
731 */
732 int QDeclarativeExpression::lineNumber() const
733 {
734     Q_D(const QDeclarativeExpression);
735     return d->line;
736 }
737
738 /*!
739     Set the location of this expression to \a line of \a url. This information
740     is used by the script engine.
741 */
742 void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
743 {
744     Q_D(QDeclarativeExpression);
745     d->url = url;
746     d->line = line;
747 }
748
749 /*!
750     Returns the expression's scope object, if provided, otherwise 0.
751
752     In addition to data provided by the expression's QDeclarativeContext, the scope
753     object's properties are also in scope during the expression's evaluation.
754 */
755 QObject *QDeclarativeExpression::scopeObject() const
756 {
757     Q_D(const QDeclarativeExpression);
758     return d->scopeObject;
759 }
760
761 /*!
762     Returns true if the last call to evaluate() resulted in an error,
763     otherwise false.
764     
765     \sa error(), clearError()
766 */
767 bool QDeclarativeExpression::hasError() const
768 {
769     Q_D(const QDeclarativeExpression);
770     return d->error.isValid();
771 }
772
773 /*!
774     Clear any expression errors.  Calls to hasError() following this will
775     return false.
776
777     \sa hasError(), error()
778 */
779 void QDeclarativeExpression::clearError()
780 {
781     Q_D(QDeclarativeExpression);
782     d->error = QDeclarativeError();
783 }
784
785 /*!
786     Return any error from the last call to evaluate().  If there was no error,
787     this returns an invalid QDeclarativeError instance.
788
789     \sa hasError(), clearError()
790 */
791
792 QDeclarativeError QDeclarativeExpression::error() const
793 {
794     Q_D(const QDeclarativeExpression);
795     return d->error;
796 }
797
798 /*! \internal */
799 void QDeclarativeExpressionPrivate::_q_notify()
800 {
801     emitValueChanged();
802 }
803
804 void QDeclarativeQtScriptExpression::clearGuards()
805 {
806     delete [] guardList; 
807     guardList = 0; 
808     guardListLength = 0;
809 }
810
811 /*!
812     \fn void QDeclarativeExpression::valueChanged()
813
814     Emitted each time the expression value changes from the last time it was
815     evaluated.  The expression must have been evaluated at least once (by
816     calling QDeclarativeExpression::evaluate()) before this signal will be emitted.
817 */
818
819 void QDeclarativeExpressionPrivate::emitValueChanged()
820 {
821     Q_Q(QDeclarativeExpression);
822     emit q->valueChanged();
823 }
824
825 QDeclarativeAbstractExpression::QDeclarativeAbstractExpression()
826 : m_context(0), m_prevExpression(0), m_nextExpression(0)
827 {
828 }
829
830 QDeclarativeAbstractExpression::~QDeclarativeAbstractExpression()
831 {
832     if (m_prevExpression) {
833         *m_prevExpression = m_nextExpression;
834         if (m_nextExpression) 
835             m_nextExpression->m_prevExpression = m_prevExpression;
836     }
837 }
838
839 QDeclarativeContextData *QDeclarativeAbstractExpression::context() const
840 {
841     return m_context;
842 }
843
844 void QDeclarativeAbstractExpression::setContext(QDeclarativeContextData *context)
845 {
846     if (m_prevExpression) {
847         *m_prevExpression = m_nextExpression;
848         if (m_nextExpression) 
849             m_nextExpression->m_prevExpression = m_prevExpression;
850         m_prevExpression = 0;
851         m_nextExpression = 0;
852     }
853
854     m_context = context;
855
856     if (m_context) {
857         m_nextExpression = m_context->expressions;
858         if (m_nextExpression) 
859             m_nextExpression->m_prevExpression = &m_nextExpression;
860         m_prevExpression = &context->expressions;
861         m_context->expressions = this;
862     }
863 }
864
865 void QDeclarativeAbstractExpression::refresh()
866 {
867 }
868
869 bool QDeclarativeAbstractExpression::isValid() const
870 {
871     return m_context != 0;
872 }
873
874 QT_END_NAMESPACE
875
876 #include <moc_qdeclarativeexpression.cpp>