Improve documentation.
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlexpression.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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>