Docs - add missing images and code, clean up sections
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlexpression.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlexpression.h"
43 #include "qqmlexpression_p.h"
44
45 #include "qqmlglobal_p.h"
46 #include "qqmlengine_p.h"
47 #include "qqmlcontext_p.h"
48 #include "qqmlrewrite_p.h"
49 #include "qqmlscriptstring_p.h"
50 #include "qqmlcompiler_p.h"
51
52 #include <QtCore/qdebug.h>
53
54 QT_BEGIN_NAMESPACE
55
56 static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = {
57     QQmlExpressionPrivate::expressionIdentifier,
58     QQmlExpressionPrivate::expressionChanged
59 };
60
61 QQmlExpressionPrivate::QQmlExpressionPrivate()
62 : QQmlJavaScriptExpression(&QQmlExpressionPrivate_jsvtable),
63   expressionFunctionValid(true), expressionFunctionRewritten(false),
64   line(0), column(0)
65 {
66 }
67
68 QQmlExpressionPrivate::~QQmlExpressionPrivate()
69 {
70     qPersistentDispose(v8qmlscope);
71     qPersistentDispose(v8function);
72 }
73
74 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QObject *me)
75 {
76     expression = expr;
77
78     QQmlAbstractExpression::setContext(ctxt);
79     setScopeObject(me);
80     expressionFunctionValid = false;
81     expressionFunctionRewritten = false;
82 }
83
84 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
85                                  bool isRewritten, QObject *me, const QString &srcUrl,
86                                  quint16 lineNumber, quint16 columnNumber)
87 {
88     url = srcUrl;
89     line = lineNumber;
90     column = columnNumber;
91
92     expression = expr;
93
94     expressionFunctionValid = false;
95     expressionFunctionRewritten = isRewritten;
96
97     QQmlAbstractExpression::setContext(ctxt);
98     setScopeObject(me);
99 }
100
101 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QByteArray &expr,
102                                  bool isRewritten, QObject *me, const QString &srcUrl,
103                                  quint16 lineNumber, quint16 columnNumber)
104 {
105     url = srcUrl;
106     line = lineNumber;
107     column = columnNumber;
108
109     if (isRewritten) {
110         expressionFunctionValid = true;
111         expressionFunctionRewritten = true;
112         v8function = evalFunction(ctxt, me, expr.constData(), expr.length(),
113                                   srcUrl, lineNumber, &v8qmlscope);
114         setUseSharedContext(false);
115
116         expressionUtf8 = expr;
117     } else {
118         expression = QString::fromUtf8(expr);
119
120         expressionFunctionValid = false;
121         expressionFunctionRewritten = isRewritten;
122     }
123
124     QQmlAbstractExpression::setContext(ctxt);
125     setScopeObject(me);
126 }
127
128 QQmlExpression *
129 QQmlExpressionPrivate::create(QQmlContextData *ctxt, QObject *object,
130                               const QString &expr, bool isRewritten,
131                               const QString &url, quint16 lineNumber, quint16 columnNumber)
132 {
133     return new QQmlExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber,
134                               *new QQmlExpressionPrivate);
135 }
136
137 /*!
138     \class QQmlExpression
139     \since 5.0
140     \inmodule QtQml
141     \brief The QQmlExpression class evaluates JavaScript in a QML context.
142
143     For example, given a file \c main.qml like this:
144
145     \qml
146     import QtQuick 2.0
147
148     Item {
149         width: 200; height: 200
150     }
151     \endqml
152
153     The following code evaluates a JavaScript expression in the context of the
154     above QML:
155
156     \code
157     QQmlEngine *engine = new QQmlEngine;
158     QQmlComponent component(engine, QUrl::fromLocalFile("main.qml"));
159
160     QObject *myObject = component.create();
161     QQmlExpression *expr = new QQmlExpression(engine->rootContext(), myObject, "width * 2");
162     int result = expr->evaluate().toInt();  // result = 400
163     \endcode
164
165     Note that the QtQuick 1 version is called QDeclarativeExpression.
166 */
167
168 /*!
169     Create an invalid QQmlExpression.
170
171     As the expression will not have an associated QQmlContext, this will be a
172     null expression object and its value will always be an invalid QVariant.
173  */
174 QQmlExpression::QQmlExpression()
175 : QObject(*new QQmlExpressionPrivate, 0)
176 {
177 }
178
179 /*!  \internal */
180 QQmlExpression::QQmlExpression(QQmlContextData *ctxt,
181                                                QObject *object, const QString &expr, bool isRewritten,
182                                                const QString &url, int lineNumber, int columnNumber,
183                                                QQmlExpressionPrivate &dd)
184 : QObject(dd, 0)
185 {
186     Q_D(QQmlExpression);
187     d->init(ctxt, expr, isRewritten, object, url, qmlSourceCoordinate(lineNumber), qmlSourceCoordinate(columnNumber));
188 }
189
190 /*!  \internal */
191 QQmlExpression::QQmlExpression(QQmlContextData *ctxt,
192                                                QObject *object, const QByteArray &expr,
193                                                bool isRewritten,
194                                                const QString &url, int lineNumber, int columnNumber,
195                                                QQmlExpressionPrivate &dd)
196 : QObject(dd, 0)
197 {
198     Q_D(QQmlExpression);
199     d->init(ctxt, expr, isRewritten, object, url, qmlSourceCoordinate(lineNumber), qmlSourceCoordinate(columnNumber));
200 }
201
202 /*!
203     Create a QQmlExpression object that is a child of \a parent.
204
205     The \a script provides the expression to be evaluated, the context to evaluate it in,
206     and the scope object to evaluate it with. If provided, \a ctxt and \a scope will override
207     the context and scope object provided by \a script.
208
209     \sa QQmlScriptString
210 */
211 QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt, QObject *scope, QObject *parent)
212 : QObject(*new QQmlExpressionPrivate, parent)
213 {
214     Q_D(QQmlExpression);
215     if (ctxt && !ctxt->isValid())
216         return;
217
218     const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
219     if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
220         return;
221
222     bool defaultConstruction = true;
223     QQmlContextData *evalCtxtData = QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context);
224     QObject *scopeObject = scope ? scope : scriptPrivate->scope;
225
226     int id = scriptPrivate->bindingId;
227     if (id >= 0) {
228         QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context);
229         QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
230         if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
231             QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
232             Q_ASSERT(typeData);
233
234             if (QQmlCompiledData *cdata = typeData->compiledData()) {
235                 defaultConstruction = false;
236                 d->init(evalCtxtData, cdata->primitives.at(id), true, scopeObject,
237                         cdata->name, scriptPrivate->lineNumber, scriptPrivate->columnNumber);
238             }
239
240             typeData->release();
241         }
242     }
243
244     if (defaultConstruction)
245         d->init(evalCtxtData, scriptPrivate->script, scopeObject);
246 }
247
248 /*!
249     Create a QQmlExpression object that is a child of \a parent.
250
251     The \a expression JavaScript will be executed in the \a ctxt QQmlContext.
252     If specified, the \a scope object's properties will also be in scope during
253     the expression's execution.
254 */
255 QQmlExpression::QQmlExpression(QQmlContext *ctxt,
256                                                QObject *scope,
257                                                const QString &expression,
258                                                QObject *parent)
259 : QObject(*new QQmlExpressionPrivate, parent)
260 {
261     Q_D(QQmlExpression);
262     d->init(QQmlContextData::get(ctxt), expression, scope);
263 }
264
265 /*!
266     \internal
267 */
268 QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
269                                                const QString &expression)
270 : QObject(*new QQmlExpressionPrivate, 0)
271 {
272     Q_D(QQmlExpression);
273     d->init(ctxt, expression, scope);
274 }
275
276 /*!  \internal */
277 QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
278                                                const QString &expression, QQmlExpressionPrivate &dd)
279 : QObject(dd, 0)
280 {
281     Q_D(QQmlExpression);
282     d->init(ctxt, expression, scope);
283 }
284
285 /*!
286     Destroy the QQmlExpression instance.
287 */
288 QQmlExpression::~QQmlExpression()
289 {
290 }
291
292 /*!
293     Returns the QQmlEngine this expression is associated with, or 0 if there
294     is no association or the QQmlEngine has been destroyed.
295 */
296 QQmlEngine *QQmlExpression::engine() const
297 {
298     Q_D(const QQmlExpression);
299     return d->context()?d->context()->engine:0;
300 }
301
302 /*!
303     Returns the QQmlContext this expression is associated with, or 0 if there
304     is no association or the QQmlContext has been destroyed.
305 */
306 QQmlContext *QQmlExpression::context() const
307 {
308     Q_D(const QQmlExpression);
309     QQmlContextData *data = d->context();
310     return data?data->asQQmlContext():0;
311 }
312
313 /*!
314     Returns the expression string.
315 */
316 QString QQmlExpression::expression() const
317 {
318     Q_D(const QQmlExpression);
319     if (!d->expressionUtf8.isEmpty()) {
320         return QString::fromUtf8(d->expressionUtf8);
321     } else {
322         return d->expression;
323     }
324 }
325
326 /*!
327     Set the expression to \a expression.
328 */
329 void QQmlExpression::setExpression(const QString &expression)
330 {
331     Q_D(QQmlExpression);
332
333     d->resetNotifyOnValueChanged();
334     d->expression = expression;
335     d->expressionUtf8.clear();
336     d->expressionFunctionValid = false;
337     d->expressionFunctionRewritten = false;
338     qPersistentDispose(d->v8function);
339     qPersistentDispose(d->v8qmlscope);
340 }
341
342 // Must be called with a valid handle scope
343 v8::Local<v8::Value> QQmlExpressionPrivate::v8value(bool *isUndefined)
344 {
345     if (!expressionFunctionValid) {
346         bool ok = true;
347
348         QQmlRewrite::RewriteBinding rewriteBinding;
349         rewriteBinding.setName(name);
350         QString code;
351         if (expressionFunctionRewritten)
352             code = expression;
353         else
354             code = rewriteBinding(expression, &ok);
355
356         if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
357         setUseSharedContext(false);
358         expressionFunctionValid = true;
359     }
360
361     return evaluate(context(), v8function, isUndefined);
362 }
363
364 QVariant QQmlExpressionPrivate::value(bool *isUndefined)
365 {
366     Q_Q(QQmlExpression);
367
368     if (!context() || !context()->isValid()) {
369         qWarning("QQmlExpression: Attempted to evaluate an expression in an invalid context");
370         return QVariant();
371     }
372
373     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(q->engine());
374     QVariant rv;
375
376     ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
377
378     {
379         v8::HandleScope handle_scope;
380         v8::Context::Scope context_scope(ep->v8engine()->context());
381         v8::Local<v8::Value> result = v8value(isUndefined);
382         rv = ep->v8engine()->toVariant(result, -1);
383     }
384
385     ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
386
387     return rv;
388 }
389
390 /*!
391     Evaulates the expression, returning the result of the evaluation,
392     or an invalid QVariant if the expression is invalid or has an error.
393
394     \a valueIsUndefined is set to true if the expression resulted in an
395     undefined value.
396
397     \sa hasError(), error()
398 */
399 QVariant QQmlExpression::evaluate(bool *valueIsUndefined)
400 {
401     Q_D(QQmlExpression);
402     return d->value(valueIsUndefined);
403 }
404
405 /*!
406 Returns true if the valueChanged() signal is emitted when the expression's evaluated
407 value changes.
408 */
409 bool QQmlExpression::notifyOnValueChanged() const
410 {
411     Q_D(const QQmlExpression);
412     return d->notifyOnValueChanged();
413 }
414
415 /*!
416   Sets whether the valueChanged() signal is emitted when the
417   expression's evaluated value changes.
418
419   If \a notifyOnChange is true, the QQmlExpression will
420   monitor properties involved in the expression's evaluation, and emit
421   QQmlExpression::valueChanged() if they have changed.  This
422   allows an application to ensure that any value associated with the
423   result of the expression remains up to date.
424
425   If \a notifyOnChange is false (default), the QQmlExpression
426   will not montitor properties involved in the expression's
427   evaluation, and QQmlExpression::valueChanged() will never be
428   emitted.  This is more efficient if an application wants a "one off"
429   evaluation of the expression.
430 */
431 void QQmlExpression::setNotifyOnValueChanged(bool notifyOnChange)
432 {
433     Q_D(QQmlExpression);
434     d->setNotifyOnValueChanged(notifyOnChange);
435 }
436
437 /*!
438     Returns the source file URL for this expression.  The source location must
439     have been previously set by calling setSourceLocation().
440 */
441 QString QQmlExpression::sourceFile() const
442 {
443     Q_D(const QQmlExpression);
444     return d->url;
445 }
446
447 /*!
448     Returns the source file line number for this expression.  The source location
449     must have been previously set by calling setSourceLocation().
450 */
451 int QQmlExpression::lineNumber() const
452 {
453     Q_D(const QQmlExpression);
454     return qmlSourceCoordinate(d->line);
455 }
456
457 /*!
458     Returns the source file column number for this expression.  The source location
459     must have been previously set by calling setSourceLocation().
460 */
461 int QQmlExpression::columnNumber() const
462 {
463     Q_D(const QQmlExpression);
464     return qmlSourceCoordinate(d->column);
465 }
466
467 /*!
468     Set the location of this expression to \a line of \a url. This information
469     is used by the script engine.
470 */
471 void QQmlExpression::setSourceLocation(const QString &url, int line, int column)
472 {
473     Q_D(QQmlExpression);
474     d->url = url;
475     d->line = qmlSourceCoordinate(line);
476     d->column = qmlSourceCoordinate(column);
477 }
478
479 /*!
480     Returns the expression's scope object, if provided, otherwise 0.
481
482     In addition to data provided by the expression's QQmlContext, the scope
483     object's properties are also in scope during the expression's evaluation.
484 */
485 QObject *QQmlExpression::scopeObject() const
486 {
487     Q_D(const QQmlExpression);
488     return d->scopeObject();
489 }
490
491 /*!
492     Returns true if the last call to evaluate() resulted in an error,
493     otherwise false.
494
495     \sa error(), clearError()
496 */
497 bool QQmlExpression::hasError() const
498 {
499     Q_D(const QQmlExpression);
500     return d->hasError();
501 }
502
503 /*!
504     Clear any expression errors.  Calls to hasError() following this will
505     return false.
506
507     \sa hasError(), error()
508 */
509 void QQmlExpression::clearError()
510 {
511     Q_D(QQmlExpression);
512     d->clearError();
513 }
514
515 /*!
516     Return any error from the last call to evaluate().  If there was no error,
517     this returns an invalid QQmlError instance.
518
519     \sa hasError(), clearError()
520 */
521
522 QQmlError QQmlExpression::error() const
523 {
524     Q_D(const QQmlExpression);
525     return d->error(engine());
526 }
527
528 /*!
529     \fn void QQmlExpression::valueChanged()
530
531     Emitted each time the expression value changes from the last time it was
532     evaluated.  The expression must have been evaluated at least once (by
533     calling QQmlExpression::evaluate()) before this signal will be emitted.
534 */
535
536 void QQmlExpressionPrivate::expressionChanged(QQmlJavaScriptExpression *e)
537 {
538     QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e);
539     This->expressionChanged();
540 }
541
542 void QQmlExpressionPrivate::expressionChanged()
543 {
544     Q_Q(QQmlExpression);
545     emit q->valueChanged();
546 }
547
548 QString QQmlExpressionPrivate::expressionIdentifier(QQmlJavaScriptExpression *e)
549 {
550     QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e);
551     return QLatin1Char('"') + This->expression + QLatin1Char('"');
552 }
553
554 QT_END_NAMESPACE
555
556 #include <moc_qqmlexpression.cpp>