Merge branch 'v8'
[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/qdeclarativescriptstring_p.h"
49 #include "private/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), m_notifyObject(0), m_notifyIndex(-1)
74 {
75 }
76
77 QDeclarativeJavaScriptExpression::~QDeclarativeJavaScriptExpression()
78 {
79 }
80
81 QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
82 : expressionFunctionValid(true), extractExpressionFromFunction(false), line(-1), dataRef(0)
83 {
84 }
85
86 QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate()
87 {
88     qPersistentDispose(v8qmlscope);
89     qPersistentDispose(v8function);
90     if (dataRef) dataRef->release();
91     dataRef = 0;
92 }
93
94 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, 
95                                          QObject *me)
96 {
97     expression = expr;
98
99     QDeclarativeAbstractExpression::setContext(ctxt);
100     setScopeObject(me);
101     expressionFunctionValid = false;
102 }
103
104 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
105                                          QObject *me)
106 {
107     QDeclarativeAbstractExpression::setContext(ctxt);
108     setScopeObject(me);
109
110     v8function = qPersistentNew<v8::Function>(func);
111     setUseSharedContext(false);
112     expressionFunctionValid = true;
113     extractExpressionFromFunction = true;
114 }
115
116 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, bool isRewritten,
117                                          QObject *me, const QString &srcUrl, int lineNumber)
118 {
119     url = srcUrl;
120     line = lineNumber;
121
122     expression = expr;
123
124     if (!isRewritten) {
125         expressionFunctionValid = false;
126     } else {
127         v8function = evalFunction(ctxt, me, expression, url, line, &v8qmlscope);
128         expressionFunctionValid = true;
129     }
130
131     QDeclarativeAbstractExpression::setContext(ctxt);
132     setScopeObject(me);
133 }
134
135 // Callee owns the persistent handle
136 v8::Persistent<v8::Function> 
137 QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope, 
138                                             const QString &code, const QString &filename, int line,
139                                             v8::Persistent<v8::Object> *qmlscope)
140 {
141     QDeclarativeEngine *engine = ctxt->engine;
142     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
143
144     // XXX TODO: Implement script caching, like we used to do with QScriptProgram in the
145     // QtScript days
146     v8::HandleScope handle_scope;
147     v8::Context::Scope ctxtscope(ep->v8engine.context());
148     
149     v8::TryCatch tc;
150     v8::Local<v8::Object> scopeobject = ep->v8engine.qmlScope(ctxt, scope);
151     v8::Local<v8::Script> script = ep->v8engine.qmlModeCompile(code, filename, line);
152     v8::Local<v8::Value> result = script->Run(scopeobject);
153     if (tc.HasCaught()) return v8::Persistent<v8::Function>();
154     if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
155     return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
156 }
157
158 /*!
159     \class QDeclarativeExpression
160     \since 4.7
161     \brief The QDeclarativeExpression class evaluates JavaScript in a QML context.
162
163     For example, given a file \c main.qml like this:
164
165     \qml
166     import QtQuick 1.0
167
168     Item {
169         width: 200; height: 200
170     }
171     \endqml
172
173     The following code evaluates a JavaScript expression in the context of the
174     above QML:
175
176     \code
177     QDeclarativeEngine *engine = new QDeclarativeEngine;
178     QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
179
180     QObject *myObject = component.create();
181     QDeclarativeExpression *expr = new QDeclarativeExpression(engine->rootContext(), myObject, "width * 2");
182     int result = expr->evaluate().toInt();  // result = 400
183     \endcode
184 */
185
186 static int QDeclarativeExpression_notifyIdx = -1;
187
188 /*!
189     Create an invalid QDeclarativeExpression.
190
191     As the expression will not have an associated QDeclarativeContext, this will be a
192     null expression object and its value will always be an invalid QVariant.
193  */
194 QDeclarativeExpression::QDeclarativeExpression()
195 : QObject(*new QDeclarativeExpressionPrivate, 0)
196 {
197     Q_D(QDeclarativeExpression);
198
199     if (QDeclarativeExpression_notifyIdx == -1) 
200         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
201     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
202 }
203
204 /*!  \internal */
205 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, 
206                                                QObject *object, const QString &expr, bool isRewritten,
207                                                const QString &url, int lineNumber, 
208                                                QDeclarativeExpressionPrivate &dd)
209 : QObject(dd, 0)
210 {
211     Q_D(QDeclarativeExpression);
212     d->init(ctxt, expr, isRewritten, object, url, lineNumber);
213
214     if (QDeclarativeExpression_notifyIdx == -1) 
215         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
216     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
217 }
218
219 /*!
220     Create a QDeclarativeExpression object that is a child of \a parent.
221
222     The \script provides the expression to be evaluated, the context to evaluate it in,
223     and the scope object to evaluate it with.
224
225     This constructor is functionally equivalent to the following, but in most cases
226     is more efficient.
227     \code
228     QDeclarativeExpression expression(script.context(), script.scopeObject(), script.script(), parent);
229     \endcode
230
231     \sa QDeclarativeScriptString
232 */
233 QDeclarativeExpression::QDeclarativeExpression(const QDeclarativeScriptString &script, QObject *parent)
234 : QObject(*new QDeclarativeExpressionPrivate, parent)
235 {
236     Q_D(QDeclarativeExpression);
237     bool defaultConstruction = false;
238
239     int id = script.d.data()->bindingId;
240     if (id < 0) {
241         defaultConstruction = true;
242     } else {
243         QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(script.context());
244
245         QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(qmlEngine(script.scopeObject()));
246         QDeclarativeCompiledData *cdata = 0;
247         QDeclarativeTypeData *typeData = 0;
248         if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
249             typeData = engine->typeLoader.get(ctxtdata->url);
250             cdata = typeData->compiledData();
251         }
252
253         if (cdata)
254             d->init(ctxtdata, cdata->primitives.at(id), cdata, script.scopeObject(),
255                     cdata->name, script.d.data()->lineNumber);
256         else
257            defaultConstruction = true;
258
259         if (typeData)
260             typeData->release();
261     }
262
263     if (defaultConstruction)
264         d->init(QDeclarativeContextData::get(script.context()), script.script(), script.scopeObject());
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 /*!  
321     \internal 
322
323     To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.  
324     For example:
325         v8::Handle<v8::Function> function;
326         new QDeclarativeExpression(ctxt, scope, &function, ...);
327  */
328 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr,
329                                                QDeclarativeExpressionPrivate &dd)
330 : QObject(dd, 0)
331 {
332     v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
333
334     Q_D(QDeclarativeExpression);
335     d->init(ctxt, function, scope);
336
337     if (QDeclarativeExpression_notifyIdx == -1)
338         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
339
340     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
341 }
342
343 /*!
344     Destroy the QDeclarativeExpression instance.
345 */
346 QDeclarativeExpression::~QDeclarativeExpression()
347 {
348 }
349
350 /*!
351     Returns the QDeclarativeEngine this expression is associated with, or 0 if there
352     is no association or the QDeclarativeEngine has been destroyed.
353 */
354 QDeclarativeEngine *QDeclarativeExpression::engine() const
355 {
356     Q_D(const QDeclarativeExpression);
357     return d->context()?d->context()->engine:0;
358 }
359
360 /*!
361     Returns the QDeclarativeContext this expression is associated with, or 0 if there
362     is no association or the QDeclarativeContext has been destroyed.
363 */
364 QDeclarativeContext *QDeclarativeExpression::context() const
365 {
366     Q_D(const QDeclarativeExpression);
367     QDeclarativeContextData *data = d->context();
368     return data?data->asQDeclarativeContext():0;
369 }
370
371 /*!
372     Returns the expression string.
373 */
374 QString QDeclarativeExpression::expression() const
375 {
376     Q_D(const QDeclarativeExpression);
377     if (d->extractExpressionFromFunction && context()->engine()) {
378         QV8Engine *v8engine = QDeclarativeEnginePrivate::getV8Engine(context()->engine());
379         v8::HandleScope handle_scope;
380         v8::Context::Scope scope(v8engine->context());
381
382         return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
383     }
384     return d->expression;
385 }
386
387 /*!
388     Set the expression to \a expression.
389 */
390 void QDeclarativeExpression::setExpression(const QString &expression)
391 {
392     Q_D(QDeclarativeExpression);
393
394     d->resetNotifyOnValueChanged();
395     d->expression = expression;
396     d->expressionFunctionValid = false;
397     qPersistentDispose(d->v8function);
398     qPersistentDispose(d->v8qmlscope);
399 }
400
401 void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message, 
402                                                      QDeclarativeError &error)
403 {
404     Q_ASSERT(!message.IsEmpty());
405
406     v8::Handle<v8::Value> name = message->GetScriptResourceName();
407     v8::Handle<v8::String> description = message->Get();
408     int lineNumber = message->GetLineNumber();
409
410     Q_ASSERT(name->IsString());
411
412     v8::Local<v8::String> file = name->ToString();
413     if (file->Length() == 0) 
414         error.setUrl(QUrl(QLatin1String("<Unknown File>")));
415     else 
416         error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
417
418     error.setLine(lineNumber);
419     error.setColumn(-1);
420
421     QString qDescription = QV8Engine::toStringStatic(description);
422     if (qDescription.startsWith(QLatin1String("Uncaught ")))
423         qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
424
425     error.setDescription(qDescription);
426 }
427
428 void QDeclarativeJavaScriptExpression::setNotifyOnValueChanged(bool v)
429 {
430     m_notifyOnValueChanged = v;
431     if (!v) guardList.clear();
432 }
433
434 void QDeclarativeJavaScriptExpression::resetNotifyOnValueChanged()
435 {
436     guardList.clear();
437 }
438
439 void QDeclarativeJavaScriptExpression::setNotifyObject(QObject *object, int index)
440 {
441     guardList.clear();
442
443     m_notifyObject = object;
444     m_notifyIndex = index;
445
446     if (!object || index == -1) {
447         m_notifyObject = 0;
448         m_notifyIndex = -1;
449     }
450 }
451
452 v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::Function> function, bool *isUndefined)
453 {
454     Q_ASSERT(context() && context()->engine);
455     Q_ASSERT(!notifyOnValueChanged() || (m_notifyObject && m_notifyIndex != -1));
456
457     if (function.IsEmpty() || function->IsUndefined()) {
458         if (isUndefined) *isUndefined = true;
459         return v8::Local<v8::Value>();
460     }
461
462     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
463
464     bool lastCaptureProperties = ep->captureProperties;
465     QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
466     ep->captureProperties = notifyOnValueChanged();
467
468     if (ep->capturedProperties.count())
469         ep->capturedProperties.copyAndClear(lastCapturedProperties);
470
471     QDeclarativeContextData *lastSharedContext = 0;
472     QObject *lastSharedScope = 0;
473
474     bool sharedContext = useSharedContext();
475
476     // All code that follows must check with watcher before it accesses data members 
477     // incase we have been deleted.
478     QDeclarativeDeleteWatcher watcher(this);
479
480     if (sharedContext) {
481         lastSharedContext = ep->sharedContext;
482         lastSharedScope = ep->sharedScope;
483         ep->sharedContext = context();
484         ep->sharedScope = scopeObject();
485     }
486
487     v8::Local<v8::Value> result;
488     {
489         v8::TryCatch try_catch;
490         v8::Handle<v8::Object> This = ep->v8engine.global();
491         if (scopeObject() && requiresThisObject()) {
492             v8::Handle<v8::Value> value = ep->v8engine.newQObject(scopeObject());
493             if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
494         }
495
496         result = function->Call(This, 0, 0);
497
498         if (isUndefined)
499             *isUndefined = try_catch.HasCaught() || result->IsUndefined();
500
501         if (watcher.wasDeleted()) {
502         } else if (try_catch.HasCaught()) {
503             v8::Context::Scope scope(ep->v8engine.context());
504             v8::Local<v8::Message> message = try_catch.Message();
505             if (!message.IsEmpty()) {
506                 QDeclarativeExpressionPrivate::exceptionToError(message, error);
507             } else {
508                 error = QDeclarativeError();
509             }
510         } else {
511             error = QDeclarativeError();
512         }
513     }
514
515     if (sharedContext) {
516         ep->sharedContext = lastSharedContext;
517         ep->sharedScope = lastSharedScope;
518     }
519
520     if (!watcher.wasDeleted() && notifyOnValueChanged()) {
521         guardList.updateGuards(m_notifyObject, m_notifyIndex, expressionString(), 
522                                ep->capturedProperties);
523     }
524
525     if (lastCapturedProperties.count())
526         lastCapturedProperties.copyAndClear(ep->capturedProperties);
527     else
528         ep->capturedProperties.clear();
529
530     ep->captureProperties = lastCaptureProperties;
531
532     return result;
533 }
534
535 void QDeclarativeJavaScriptExpression::GuardList::updateGuards(QObject *notifyObject, int notifyIndex,
536                                                                const QStringRef &expression,
537                                                                const CapturedProperties &properties)
538 {
539     Q_ASSERT(notifyObject);
540     Q_ASSERT(notifyIndex != -1);
541
542     if (properties.count() == 0) {
543         clear();
544         return;
545     }
546
547     if (properties.count() != length) {
548         QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()];
549
550         for (int ii = 0; ii < qMin(length, properties.count()); ++ii) 
551            endpoints[ii].copyAndClear(newGuardList[ii]);
552
553         delete [] endpoints;
554         endpoints = newGuardList;
555         length = properties.count();
556     }
557
558     bool outputWarningHeader = false;
559     bool noChanges = true;
560     for (int ii = 0; ii < properties.count(); ++ii) {
561         QDeclarativeNotifierEndpoint &guard = endpoints[ii];
562         const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
563
564         guard.target = notifyObject;
565         guard.targetMethod = notifyIndex;
566
567         if (property.notifier != 0) {
568
569             if (!noChanges && guard.isConnected(property.notifier)) {
570                 // Nothing to do
571
572             } else {
573                 noChanges = false;
574
575                 bool existing = false;
576                 for (int jj = 0; !existing && jj < ii; ++jj) 
577                     if (endpoints[jj].isConnected(property.notifier)) 
578                         existing = true;
579
580                 if (existing) {
581                     // duplicate
582                     guard.disconnect();
583                 } else {
584                     guard.connect(property.notifier);
585                 }
586             }
587
588
589         } else if (property.notifyIndex != -1) {
590
591             if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
592                 // Nothing to do
593
594             } else {
595                 noChanges = false;
596
597                 bool existing = false;
598                 for (int jj = 0; !existing && jj < ii; ++jj) 
599                     if (endpoints[jj].isConnected(property.object, property.notifyIndex)) 
600                         existing = true;
601
602                 if (existing) {
603                     // duplicate
604                     guard.disconnect();
605                 } else {
606                     guard.connect(property.object, property.notifyIndex);
607                 }
608             }
609
610         } else if (!expression.isEmpty()) {
611             if (!outputWarningHeader) {
612                 outputWarningHeader = true;
613                 qWarning() << "QDeclarativeExpression: Expression" << expression
614                            << "depends on non-NOTIFYable properties:";
615             }
616
617             const QMetaObject *metaObj = property.object->metaObject();
618             QMetaProperty metaProp = metaObj->property(property.coreIndex);
619
620             qWarning().nospace() << "    " << metaObj->className() << "::" << metaProp.name();
621         }
622     }
623 }
624
625 // Must be called with a valid handle scope
626 v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
627 {
628     if (!expressionFunctionValid) {
629         QDeclarativeRewrite::RewriteBinding rewriteBinding;
630         rewriteBinding.setName(name);
631         bool ok = true;
632         const QString code = rewriteBinding(expression, &ok);
633         if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
634         setUseSharedContext(false);
635         expressionFunctionValid = true;
636     }
637
638
639     if (secondaryScope) {
640         v8::Local<v8::Value> result;
641         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
642         QObject *restoreSecondaryScope = 0;
643         restoreSecondaryScope = ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
644         result = evaluate(v8function, isUndefined);
645         ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
646         return result;
647     } else {
648         return evaluate(v8function, isUndefined);
649     }
650 }
651
652 QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
653 {
654     Q_Q(QDeclarativeExpression);
655
656     if (!context() || !context()->isValid()) {
657         qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
658         return QVariant();
659     }
660
661     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
662     QVariant rv;
663
664     ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
665
666     {
667         v8::HandleScope handle_scope;
668         v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
669         rv = ep->v8engine.toVariant(result, qMetaTypeId<QList<QObject*> >());
670     }
671
672     ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
673
674     return rv;
675 }
676
677 /*!
678     Evaulates the expression, returning the result of the evaluation,
679     or an invalid QVariant if the expression is invalid or has an error.
680
681     \a valueIsUndefined is set to true if the expression resulted in an
682     undefined value.
683
684     \sa hasError(), error()
685 */
686 QVariant QDeclarativeExpression::evaluate(bool *valueIsUndefined)
687 {
688     Q_D(QDeclarativeExpression);
689     return d->value(0, valueIsUndefined);
690 }
691
692 /*!
693 Returns true if the valueChanged() signal is emitted when the expression's evaluated
694 value changes.
695 */
696 bool QDeclarativeExpression::notifyOnValueChanged() const
697 {
698     Q_D(const QDeclarativeExpression);
699     return d->notifyOnValueChanged();
700 }
701
702 /*!
703   Sets whether the valueChanged() signal is emitted when the
704   expression's evaluated value changes.
705
706   If \a notifyOnChange is true, the QDeclarativeExpression will
707   monitor properties involved in the expression's evaluation, and emit
708   QDeclarativeExpression::valueChanged() if they have changed.  This
709   allows an application to ensure that any value associated with the
710   result of the expression remains up to date.
711
712   If \a notifyOnChange is false (default), the QDeclarativeExpression
713   will not montitor properties involved in the expression's
714   evaluation, and QDeclarativeExpression::valueChanged() will never be
715   emitted.  This is more efficient if an application wants a "one off"
716   evaluation of the expression.
717 */
718 void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
719 {
720     Q_D(QDeclarativeExpression);
721     d->setNotifyOnValueChanged(notifyOnChange);
722 }
723
724 /*!
725     Returns the source file URL for this expression.  The source location must
726     have been previously set by calling setSourceLocation().
727 */
728 QString QDeclarativeExpression::sourceFile() const
729 {
730     Q_D(const QDeclarativeExpression);
731     return d->url;
732 }
733
734 /*!
735     Returns the source file line number for this expression.  The source location 
736     must have been previously set by calling setSourceLocation().
737 */
738 int QDeclarativeExpression::lineNumber() const
739 {
740     Q_D(const QDeclarativeExpression);
741     return d->line;
742 }
743
744 /*!
745     Set the location of this expression to \a line of \a url. This information
746     is used by the script engine.
747 */
748 void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
749 {
750     Q_D(QDeclarativeExpression);
751     d->url = url;
752     d->line = line;
753 }
754
755 /*!
756     Returns the expression's scope object, if provided, otherwise 0.
757
758     In addition to data provided by the expression's QDeclarativeContext, the scope
759     object's properties are also in scope during the expression's evaluation.
760 */
761 QObject *QDeclarativeExpression::scopeObject() const
762 {
763     Q_D(const QDeclarativeExpression);
764     return d->scopeObject();
765 }
766
767 /*!
768     Returns true if the last call to evaluate() resulted in an error,
769     otherwise false.
770     
771     \sa error(), clearError()
772 */
773 bool QDeclarativeExpression::hasError() const
774 {
775     Q_D(const QDeclarativeExpression);
776     return d->error.isValid();
777 }
778
779 /*!
780     Clear any expression errors.  Calls to hasError() following this will
781     return false.
782
783     \sa hasError(), error()
784 */
785 void QDeclarativeExpression::clearError()
786 {
787     Q_D(QDeclarativeExpression);
788     d->error = QDeclarativeError();
789 }
790
791 /*!
792     Return any error from the last call to evaluate().  If there was no error,
793     this returns an invalid QDeclarativeError instance.
794
795     \sa hasError(), clearError()
796 */
797
798 QDeclarativeError QDeclarativeExpression::error() const
799 {
800     Q_D(const QDeclarativeExpression);
801     return d->error;
802 }
803
804 /*! \internal */
805 void QDeclarativeExpressionPrivate::_q_notify()
806 {
807     emitValueChanged();
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>