Initial import from the monolithic Qt.
[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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
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
634         QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
635
636         QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
637         expressionContext = ep->contextClass->newContext(context(), scopeObject);
638         scriptContext->pushScope(expressionContext);
639         scriptContext->pushScope(ep->globalClass->staticGlobalObject());
640
641         QDeclarativeRewrite::RewriteBinding rewriteBinding;
642         rewriteBinding.setName(name);
643         bool ok = true;
644         const QString code = rewriteBinding(expression, &ok);
645         if (ok) 
646             expressionFunction = scriptEngine->evaluate(code, url, line);
647
648         scriptEngine->popContext();
649         expressionFunctionMode = ExplicitContext;
650         expressionFunctionValid = true;
651     }
652
653     return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined);
654 }
655
656 QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
657 {
658     Q_Q(QDeclarativeExpression);
659
660     if (!context() || !context()->isValid()) {
661         qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
662         return QVariant();
663     }
664
665     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
666
667     return ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >());
668 }
669
670 /*!
671     Evaulates the expression, returning the result of the evaluation,
672     or an invalid QVariant if the expression is invalid or has an error.
673
674     \a valueIsUndefined is set to true if the expression resulted in an
675     undefined value.
676
677     \sa hasError(), error()
678 */
679 QVariant QDeclarativeExpression::evaluate(bool *valueIsUndefined)
680 {
681     Q_D(QDeclarativeExpression);
682     return d->value(0, valueIsUndefined);
683 }
684
685 /*!
686 Returns true if the valueChanged() signal is emitted when the expression's evaluated
687 value changes.
688 */
689 bool QDeclarativeExpression::notifyOnValueChanged() const
690 {
691     Q_D(const QDeclarativeExpression);
692     return d->notifyOnValueChange();
693 }
694
695 /*!
696   Sets whether the valueChanged() signal is emitted when the
697   expression's evaluated value changes.
698
699   If \a notifyOnChange is true, the QDeclarativeExpression will
700   monitor properties involved in the expression's evaluation, and emit
701   QDeclarativeExpression::valueChanged() if they have changed.  This
702   allows an application to ensure that any value associated with the
703   result of the expression remains up to date.
704
705   If \a notifyOnChange is false (default), the QDeclarativeExpression
706   will not montitor properties involved in the expression's
707   evaluation, and QDeclarativeExpression::valueChanged() will never be
708   emitted.  This is more efficient if an application wants a "one off"
709   evaluation of the expression.
710 */
711 void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
712 {
713     Q_D(QDeclarativeExpression);
714     d->setNotifyOnValueChange(notifyOnChange);
715 }
716
717 /*!
718     Returns the source file URL for this expression.  The source location must
719     have been previously set by calling setSourceLocation().
720 */
721 QString QDeclarativeExpression::sourceFile() const
722 {
723     Q_D(const QDeclarativeExpression);
724     return d->url;
725 }
726
727 /*!
728     Returns the source file line number for this expression.  The source location 
729     must have been previously set by calling setSourceLocation().
730 */
731 int QDeclarativeExpression::lineNumber() const
732 {
733     Q_D(const QDeclarativeExpression);
734     return d->line;
735 }
736
737 /*!
738     Set the location of this expression to \a line of \a url. This information
739     is used by the script engine.
740 */
741 void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
742 {
743     Q_D(QDeclarativeExpression);
744     d->url = url;
745     d->line = line;
746 }
747
748 /*!
749     Returns the expression's scope object, if provided, otherwise 0.
750
751     In addition to data provided by the expression's QDeclarativeContext, the scope
752     object's properties are also in scope during the expression's evaluation.
753 */
754 QObject *QDeclarativeExpression::scopeObject() const
755 {
756     Q_D(const QDeclarativeExpression);
757     return d->scopeObject;
758 }
759
760 /*!
761     Returns true if the last call to evaluate() resulted in an error,
762     otherwise false.
763     
764     \sa error(), clearError()
765 */
766 bool QDeclarativeExpression::hasError() const
767 {
768     Q_D(const QDeclarativeExpression);
769     return d->error.isValid();
770 }
771
772 /*!
773     Clear any expression errors.  Calls to hasError() following this will
774     return false.
775
776     \sa hasError(), error()
777 */
778 void QDeclarativeExpression::clearError()
779 {
780     Q_D(QDeclarativeExpression);
781     d->error = QDeclarativeError();
782 }
783
784 /*!
785     Return any error from the last call to evaluate().  If there was no error,
786     this returns an invalid QDeclarativeError instance.
787
788     \sa hasError(), clearError()
789 */
790
791 QDeclarativeError QDeclarativeExpression::error() const
792 {
793     Q_D(const QDeclarativeExpression);
794     return d->error;
795 }
796
797 /*! \internal */
798 void QDeclarativeExpressionPrivate::_q_notify()
799 {
800     emitValueChanged();
801 }
802
803 void QDeclarativeQtScriptExpression::clearGuards()
804 {
805     delete [] guardList; 
806     guardList = 0; 
807     guardListLength = 0;
808 }
809
810 /*!
811     \fn void QDeclarativeExpression::valueChanged()
812
813     Emitted each time the expression value changes from the last time it was
814     evaluated.  The expression must have been evaluated at least once (by
815     calling QDeclarativeExpression::evaluate()) before this signal will be emitted.
816 */
817
818 void QDeclarativeExpressionPrivate::emitValueChanged()
819 {
820     Q_Q(QDeclarativeExpression);
821     emit q->valueChanged();
822 }
823
824 QDeclarativeAbstractExpression::QDeclarativeAbstractExpression()
825 : m_context(0), m_prevExpression(0), m_nextExpression(0)
826 {
827 }
828
829 QDeclarativeAbstractExpression::~QDeclarativeAbstractExpression()
830 {
831     if (m_prevExpression) {
832         *m_prevExpression = m_nextExpression;
833         if (m_nextExpression) 
834             m_nextExpression->m_prevExpression = m_prevExpression;
835     }
836 }
837
838 QDeclarativeContextData *QDeclarativeAbstractExpression::context() const
839 {
840     return m_context;
841 }
842
843 void QDeclarativeAbstractExpression::setContext(QDeclarativeContextData *context)
844 {
845     if (m_prevExpression) {
846         *m_prevExpression = m_nextExpression;
847         if (m_nextExpression) 
848             m_nextExpression->m_prevExpression = m_prevExpression;
849         m_prevExpression = 0;
850         m_nextExpression = 0;
851     }
852
853     m_context = context;
854
855     if (m_context) {
856         m_nextExpression = m_context->expressions;
857         if (m_nextExpression) 
858             m_nextExpression->m_prevExpression = &m_nextExpression;
859         m_prevExpression = &context->expressions;
860         m_context->expressions = this;
861     }
862 }
863
864 void QDeclarativeAbstractExpression::refresh()
865 {
866 }
867
868 bool QDeclarativeAbstractExpression::isValid() const
869 {
870     return m_context != 0;
871 }
872
873 QT_END_NAMESPACE
874
875 #include <moc_qdeclarativeexpression.cpp>