src/declarative/qml/qdeclarativeexpression.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 QDeclarativeExpressionData::QDeclarativeExpressionData()
       
    75 : q(0), dataRef(0), expressionFunctionValid(false), expressionRewritten(false), me(0), 
       
    76   trackChange(false), isShared(false), line(-1), guardList(0), guardListLength(0)
       
    77 {
       
    78 }
       
    79 
       
    80 QDeclarativeExpressionData::~QDeclarativeExpressionData()
       
    81 {
       
    82     if (guardList) { delete [] guardList; guardList = 0; }
       
    83     if (dataRef) dataRef->release();
       
    84 }
       
    85 
       
    86 QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
       
    87 : data(new QDeclarativeExpressionData)
       
    88 {
       
    89     data->q = this;
       
    90 }
       
    91 
       
    92 QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate(QDeclarativeExpressionData *d)
       
    93 : data(d)
       
    94 {
       
    95     data->q = this;
       
    96 }
       
    97 
       
    98 QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate()
       
    99 {
       
   100     if (data) { 
       
   101         delete [] data->guardList; 
       
   102         data->guardList = 0; 
       
   103         data->guardListLength = 0; 
       
   104         data->q = 0; 
       
   105         data->release(); 
       
   106         data = 0; 
       
   107     }
       
   108 }
       
   109 
       
   110 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, 
       
   111                                          QObject *me)
       
   112 {
       
   113     data->expression = expr;
       
   114 
       
   115     data->QDeclarativeAbstractExpression::setContext(ctxt);
       
   116     data->me = me;
       
   117 }
       
   118 
       
   119 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, QDeclarativeRefCount *rc, 
       
   120                                          QObject *me, const QString &url, int lineNumber)
       
   121 {
       
   122     data->url = url;
       
   123     data->line = lineNumber;
       
   124 
       
   125     if (data->dataRef) data->dataRef->release();
       
   126     data->dataRef = rc;
       
   127     if (data->dataRef) data->dataRef->addref();
       
   128 
       
   129     quint32 *exprData = (quint32 *)expr;
       
   130     QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc;
       
   131 
       
   132     data->expressionRewritten = true;
       
   133     data->expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]);
       
   134 
       
   135     int progIdx = *(exprData);
       
   136     bool isShared = 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 (isShared) {
       
   144 
       
   145         if (!dd->cachedClosures.at(progIdx)) {
       
   146             QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
       
   147             scriptContext->pushScope(ep->contextClass->newSharedContext());
       
   148             scriptContext->pushScope(ep->globalClass->globalObject());
       
   149             dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(data->expression, data->url, data->line));
       
   150             scriptEngine->popContext();
       
   151         }
       
   152 
       
   153         data->expressionFunction = *dd->cachedClosures.at(progIdx);
       
   154         data->isShared = true;
       
   155         data->expressionFunctionValid = true;
       
   156 
       
   157     } else {
       
   158 
       
   159 #if !defined(Q_OS_SYMBIAN) //XXX Why doesn't this work?
       
   160         if (!dd->cachedPrograms.at(progIdx)) {
       
   161             dd->cachedPrograms[progIdx] =
       
   162                 new QScriptProgram(data->expression, data->url, data->line);
       
   163         }
       
   164 
       
   165         data->expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx), 
       
   166                                                      &data->expressionContext);
       
   167 #else
       
   168         data->expressionFunction = evalInObjectScope(ctxt, me, data->expression, 
       
   169                                                      &data->expressionContext);
       
   170 #endif
       
   171 
       
   172         data->expressionFunctionValid = true;
       
   173     }
       
   174 
       
   175     data->QDeclarativeAbstractExpression::setContext(ctxt);
       
   176     data->me = me;
       
   177 }
       
   178 
       
   179 QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, 
       
   180                                                               const QString &program, const QString &fileName,
       
   181                                                               int lineNumber, QScriptValue *contextObject)
       
   182 {
       
   183     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
       
   184     QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
       
   185     if (contextObject) {
       
   186         *contextObject = ep->contextClass->newContext(context, object);
       
   187         scriptContext->pushScope(*contextObject);
       
   188     } else {
       
   189         scriptContext->pushScope(ep->contextClass->newContext(context, object));
       
   190     }
       
   191     scriptContext->pushScope(ep->globalClass->globalObject());
       
   192     QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
       
   193     ep->scriptEngine.popContext();
       
   194     return rv;
       
   195 }
       
   196 
       
   197 QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, 
       
   198                                                               const QScriptProgram &program, 
       
   199                                                               QScriptValue *contextObject)
       
   200 {
       
   201     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
       
   202     QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
       
   203     if (contextObject) {
       
   204         *contextObject = ep->contextClass->newContext(context, object);
       
   205         scriptContext->pushScope(*contextObject);
       
   206     } else {
       
   207         scriptContext->pushScope(ep->contextClass->newContext(context, object));
       
   208     }
       
   209     scriptContext->pushScope(ep->globalClass->globalObject());
       
   210     QScriptValue rv = ep->scriptEngine.evaluate(program);
       
   211     ep->scriptEngine.popContext();
       
   212     return rv;
       
   213 }
       
   214 
       
   215 /*!
       
   216     \class QDeclarativeExpression
       
   217   \since 4.7
       
   218     \brief The QDeclarativeExpression class evaluates JavaScript in a QML context.
       
   219 */
       
   220 
       
   221 /*!
       
   222     Create an invalid QDeclarativeExpression.
       
   223 
       
   224     As the expression will not have an associated QDeclarativeContext, this will be a
       
   225     null expression object and its value will always be an invalid QVariant.
       
   226  */
       
   227 QDeclarativeExpression::QDeclarativeExpression()
       
   228 : QObject(*new QDeclarativeExpressionPrivate, 0)
       
   229 {
       
   230 }
       
   231 
       
   232 /*!  \internal */
       
   233 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, void *expr,
       
   234                                                QDeclarativeRefCount *rc, QObject *me, 
       
   235                                                const QString &url, int lineNumber,
       
   236                                                QDeclarativeExpressionPrivate &dd)
       
   237 : QObject(dd, 0)
       
   238 {
       
   239     Q_D(QDeclarativeExpression);
       
   240     d->init(ctxt, expr, rc, me, url, lineNumber);
       
   241 }
       
   242 
       
   243 /*!
       
   244     Create a QDeclarativeExpression object that is a child of \a parent.
       
   245 
       
   246     The \a expression JavaScript will be executed in the \a ctxt QDeclarativeContext.
       
   247     If specified, the \a scope object's properties will also be in scope during
       
   248     the expression's execution.
       
   249 */
       
   250 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt,
       
   251                                                QObject *scope,
       
   252                                                const QString &expression,
       
   253                                                QObject *parent)
       
   254 : QObject(*new QDeclarativeExpressionPrivate, parent)
       
   255 {
       
   256     Q_D(QDeclarativeExpression);
       
   257     d->init(QDeclarativeContextData::get(ctxt), expression, scope);
       
   258 }
       
   259 
       
   260 /*! 
       
   261     \internal
       
   262 */
       
   263 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
       
   264                                                const QString &expression)
       
   265 : QObject(*new QDeclarativeExpressionPrivate, 0)
       
   266 {
       
   267     Q_D(QDeclarativeExpression);
       
   268     d->init(ctxt, expression, scope);
       
   269 }
       
   270 
       
   271 /*!  \internal */
       
   272 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
       
   273                                                const QString &expression, QDeclarativeExpressionPrivate &dd)
       
   274 : QObject(dd, 0)
       
   275 {
       
   276     Q_D(QDeclarativeExpression);
       
   277     d->init(ctxt, expression, scope);
       
   278 }
       
   279 
       
   280 /*!
       
   281     Destroy the QDeclarativeExpression instance.
       
   282 */
       
   283 QDeclarativeExpression::~QDeclarativeExpression()
       
   284 {
       
   285 }
       
   286 
       
   287 /*!
       
   288     Returns the QDeclarativeEngine this expression is associated with, or 0 if there
       
   289     is no association or the QDeclarativeEngine has been destroyed.
       
   290 */
       
   291 QDeclarativeEngine *QDeclarativeExpression::engine() const
       
   292 {
       
   293     Q_D(const QDeclarativeExpression);
       
   294     return d->data->context()?d->data->context()->engine:0;
       
   295 }
       
   296 
       
   297 /*!
       
   298     Returns the QDeclarativeContext this expression is associated with, or 0 if there
       
   299     is no association or the QDeclarativeContext has been destroyed.
       
   300 */
       
   301 QDeclarativeContext *QDeclarativeExpression::context() const
       
   302 {
       
   303     Q_D(const QDeclarativeExpression);
       
   304     QDeclarativeContextData *data = d->data->context();
       
   305     return data?data->asQDeclarativeContext():0;
       
   306 }
       
   307 
       
   308 /*!
       
   309     Returns the expression string.
       
   310 */
       
   311 QString QDeclarativeExpression::expression() const
       
   312 {
       
   313     Q_D(const QDeclarativeExpression);
       
   314     return d->data->expression;
       
   315 }
       
   316 
       
   317 /*!
       
   318     Set the expression to \a expression.
       
   319 */
       
   320 void QDeclarativeExpression::setExpression(const QString &expression)
       
   321 {
       
   322     Q_D(QDeclarativeExpression);
       
   323 
       
   324     d->clearGuards();
       
   325 
       
   326     d->data->expression = expression;
       
   327     d->data->expressionFunctionValid = false;
       
   328     d->data->expressionRewritten = false;
       
   329     d->data->expressionFunction = QScriptValue();
       
   330 }
       
   331 
       
   332 void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, 
       
   333                                             QDeclarativeError &error)
       
   334 {
       
   335     if (scriptEngine->hasUncaughtException() && 
       
   336         scriptEngine->uncaughtException().isError()) {
       
   337 
       
   338         QString fileName;
       
   339         int lineNumber = scriptEngine->uncaughtExceptionLineNumber();
       
   340 
       
   341         QScriptValue exception = scriptEngine->uncaughtException();
       
   342         QLatin1String fileNameProp("fileName");
       
   343 
       
   344         if (!exception.property(fileNameProp).toString().isEmpty()){
       
   345             fileName = exception.property(fileNameProp).toString();
       
   346         } else {
       
   347             fileName = QLatin1String("<Unknown File>");
       
   348         }
       
   349 
       
   350         error.setUrl(QUrl(fileName));
       
   351         error.setLine(lineNumber);
       
   352         error.setColumn(-1);
       
   353         error.setDescription(exception.toString());
       
   354     } else {
       
   355         error = QDeclarativeError();
       
   356     }
       
   357 }
       
   358 
       
   359 QScriptValue QDeclarativeExpressionPrivate::eval(QObject *secondaryScope, bool *isUndefined)
       
   360 {
       
   361     QDeclarativeExpressionData *data = this->data;
       
   362     QDeclarativeEngine *engine = data->context()->engine;
       
   363     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
       
   364 
       
   365     QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
       
   366 
       
   367     if (!data->expressionFunctionValid) {
       
   368 
       
   369         QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
       
   370         data->expressionContext = ep->contextClass->newContext(data->context(), data->me);
       
   371         scriptContext->pushScope(data->expressionContext);
       
   372         scriptContext->pushScope(ep->globalClass->globalObject());
       
   373 
       
   374         if (data->expressionRewritten) {
       
   375             data->expressionFunction = scriptEngine->evaluate(data->expression, 
       
   376                                                               data->url, data->line);
       
   377         } else {
       
   378             QDeclarativeRewrite::RewriteBinding rewriteBinding;
       
   379 
       
   380             bool ok = true;
       
   381             const QString code = rewriteBinding(data->expression, &ok);
       
   382             if (!ok) {
       
   383                 scriptEngine->popContext();
       
   384                 return QScriptValue();
       
   385             }
       
   386             data->expressionFunction = scriptEngine->evaluate(code, data->url, data->line);
       
   387         }
       
   388 
       
   389         scriptEngine->popContext();
       
   390         data->expressionFunctionValid = true;
       
   391     }
       
   392 
       
   393     QDeclarativeContextData *oldSharedContext = 0;
       
   394     QObject *oldSharedScope = 0;
       
   395     QObject *oldOverride = 0;
       
   396     if (data->isShared) {
       
   397         oldSharedContext = ep->sharedContext;
       
   398         oldSharedScope = ep->sharedScope;
       
   399         ep->sharedContext = data->context();
       
   400         ep->sharedScope = data->me;
       
   401     } else {
       
   402         oldOverride = ep->contextClass->setOverrideObject(data->expressionContext, secondaryScope);
       
   403     }
       
   404 
       
   405     QScriptValue svalue = data->expressionFunction.call();
       
   406 
       
   407     if (data->isShared) {
       
   408         ep->sharedContext = oldSharedContext;
       
   409         ep->sharedScope = oldSharedScope;
       
   410     } else {
       
   411         ep->contextClass->setOverrideObject(data->expressionContext, oldOverride);
       
   412     }
       
   413 
       
   414     if (isUndefined)
       
   415         *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException();
       
   416 
       
   417     // Handle exception
       
   418     if (scriptEngine->hasUncaughtException()) {
       
   419        exceptionToError(scriptEngine, data->error);
       
   420        scriptEngine->clearExceptions();
       
   421        return QScriptValue();
       
   422     } else {
       
   423         data->error = QDeclarativeError();
       
   424         return svalue;
       
   425     }
       
   426 }
       
   427 
       
   428 QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
       
   429 {
       
   430     Q_Q(QDeclarativeExpression);
       
   431     Q_ASSERT(q->engine());
       
   432 
       
   433     if (data->expression.isEmpty())
       
   434         return QScriptValue();
       
   435 
       
   436     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
       
   437 
       
   438     QDeclarativeExpression *lastCurrentExpression = ep->currentExpression;
       
   439     bool lastCaptureProperties = ep->captureProperties;
       
   440     QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
       
   441     ep->capturedProperties.copyAndClear(lastCapturedProperties);
       
   442 
       
   443     ep->currentExpression = q;
       
   444     ep->captureProperties = data->trackChange;
       
   445 
       
   446     // This object might be deleted during the eval
       
   447     QDeclarativeExpressionData *localData = data;
       
   448     localData->addref();
       
   449 
       
   450     QScriptValue value = eval(secondaryScope, isUndefined);
       
   451 
       
   452     ep->currentExpression = lastCurrentExpression;
       
   453     ep->captureProperties = lastCaptureProperties;
       
   454 
       
   455     // Check if we were deleted
       
   456     if (localData->q) {
       
   457         if ((!data->trackChange || !ep->capturedProperties.count()) && data->guardList) {
       
   458             clearGuards();
       
   459         } else if(data->trackChange) {
       
   460             updateGuards(ep->capturedProperties);
       
   461         }
       
   462     }
       
   463 
       
   464     localData->release();
       
   465 
       
   466     lastCapturedProperties.copyAndClear(ep->capturedProperties);
       
   467 
       
   468     return value;
       
   469 }
       
   470 
       
   471 QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
       
   472 {
       
   473     Q_Q(QDeclarativeExpression);
       
   474 
       
   475     if (!data || !data->context() || !data->context()->isValid()) {
       
   476         qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
       
   477         return QVariant();
       
   478     }
       
   479 
       
   480     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
       
   481 
       
   482     return ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >());
       
   483 }
       
   484 
       
   485 /*!
       
   486     Evaulates the expression, returning the result of the evaluation,
       
   487     or an invalid QVariant if the expression is invalid or has an error.
       
   488 
       
   489     \a valueIsUndefined is set to true if the expression resulted in an
       
   490     undefined value.
       
   491 
       
   492     \sa hasError(), error()
       
   493 */
       
   494 QVariant QDeclarativeExpression::evaluate(bool *valueIsUndefined)
       
   495 {
       
   496     Q_D(QDeclarativeExpression);
       
   497     return d->value(0, valueIsUndefined);
       
   498 }
       
   499 
       
   500 /*!
       
   501 Returns true if the valueChanged() signal is emitted when the expression's evaluated
       
   502 value changes.
       
   503 */
       
   504 bool QDeclarativeExpression::notifyOnValueChanged() const
       
   505 {
       
   506     Q_D(const QDeclarativeExpression);
       
   507     return d->data->trackChange;
       
   508 }
       
   509 
       
   510 /*!
       
   511   Sets whether the valueChanged() signal is emitted when the
       
   512   expression's evaluated value changes.
       
   513 
       
   514   If \a notifyOnChange is true, the QDeclarativeExpression will
       
   515   monitor properties involved in the expression's evaluation, and emit
       
   516   QDeclarativeExpression::valueChanged() if they have changed.  This
       
   517   allows an application to ensure that any value associated with the
       
   518   result of the expression remains up to date.
       
   519 
       
   520   If \a notifyOnChange is false (default), the QDeclarativeExpression
       
   521   will not montitor properties involved in the expression's
       
   522   evaluation, and QDeclarativeExpression::valueChanged() will never be
       
   523   emitted.  This is more efficient if an application wants a "one off"
       
   524   evaluation of the expression.
       
   525 */
       
   526 void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
       
   527 {
       
   528     Q_D(QDeclarativeExpression);
       
   529     d->data->trackChange = notifyOnChange;
       
   530 }
       
   531 
       
   532 /*!
       
   533     Returns the source file URL for this expression.  The source location must
       
   534     have been previously set by calling setSourceLocation().
       
   535 */
       
   536 QString QDeclarativeExpression::sourceFile() const
       
   537 {
       
   538     Q_D(const QDeclarativeExpression);
       
   539     return d->data->url;
       
   540 }
       
   541 
       
   542 /*!
       
   543     Returns the source file line number for this expression.  The source location 
       
   544     must have been previously set by calling setSourceLocation().
       
   545 */
       
   546 int QDeclarativeExpression::lineNumber() const
       
   547 {
       
   548     Q_D(const QDeclarativeExpression);
       
   549     return d->data->line;
       
   550 }
       
   551 
       
   552 /*!
       
   553     Set the location of this expression to \a line of \a url. This information
       
   554     is used by the script engine.
       
   555 */
       
   556 void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
       
   557 {
       
   558     Q_D(QDeclarativeExpression);
       
   559     d->data->url = url;
       
   560     d->data->line = line;
       
   561 }
       
   562 
       
   563 /*!
       
   564     Returns the expression's scope object, if provided, otherwise 0.
       
   565 
       
   566     In addition to data provided by the expression's QDeclarativeContext, the scope
       
   567     object's properties are also in scope during the expression's evaluation.
       
   568 */
       
   569 QObject *QDeclarativeExpression::scopeObject() const
       
   570 {
       
   571     Q_D(const QDeclarativeExpression);
       
   572     return d->data->me;
       
   573 }
       
   574 
       
   575 /*!
       
   576     Returns true if the last call to evaluate() resulted in an error,
       
   577     otherwise false.
       
   578     
       
   579     \sa error(), clearError()
       
   580 */
       
   581 bool QDeclarativeExpression::hasError() const
       
   582 {
       
   583     Q_D(const QDeclarativeExpression);
       
   584     return d->data->error.isValid();
       
   585 }
       
   586 
       
   587 /*!
       
   588     Clear any expression errors.  Calls to hasError() following this will
       
   589     return false.
       
   590 
       
   591     \sa hasError(), error()
       
   592 */
       
   593 void QDeclarativeExpression::clearError()
       
   594 {
       
   595     Q_D(QDeclarativeExpression);
       
   596     d->data->error = QDeclarativeError();
       
   597 }
       
   598 
       
   599 /*!
       
   600     Return any error from the last call to evaluate().  If there was no error,
       
   601     this returns an invalid QDeclarativeError instance.
       
   602 
       
   603     \sa hasError(), clearError()
       
   604 */
       
   605 
       
   606 QDeclarativeError QDeclarativeExpression::error() const
       
   607 {
       
   608     Q_D(const QDeclarativeExpression);
       
   609     return d->data->error;
       
   610 }
       
   611 
       
   612 /*! \internal */
       
   613 void QDeclarativeExpressionPrivate::_q_notify()
       
   614 {
       
   615     emitValueChanged();
       
   616 }
       
   617 
       
   618 void QDeclarativeExpressionPrivate::clearGuards()
       
   619 {
       
   620     delete [] data->guardList; 
       
   621     data->guardList = 0; 
       
   622     data->guardListLength = 0;
       
   623 }
       
   624 
       
   625 void QDeclarativeExpressionPrivate::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
       
   626 {
       
   627     Q_Q(QDeclarativeExpression);
       
   628 
       
   629     static int notifyIdx = -1;
       
   630     if (notifyIdx == -1) 
       
   631         notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
       
   632 
       
   633     if (properties.count() != data->guardListLength) {
       
   634         QDeclarativeNotifierEndpoint *newGuardList = 
       
   635             new QDeclarativeNotifierEndpoint[properties.count()];
       
   636 
       
   637         for (int ii = 0; ii < qMin(data->guardListLength, properties.count()); ++ii) 
       
   638            data->guardList[ii].copyAndClear(newGuardList[ii]);
       
   639 
       
   640         delete [] data->guardList;
       
   641         data->guardList = newGuardList;
       
   642         data->guardListLength = properties.count();
       
   643     }
       
   644 
       
   645     bool outputWarningHeader = false;
       
   646     bool noChanges = true;
       
   647     for (int ii = 0; ii < properties.count(); ++ii) {
       
   648         QDeclarativeNotifierEndpoint &guard = data->guardList[ii];
       
   649         const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
       
   650 
       
   651         guard.target = q;
       
   652         guard.targetMethod = notifyIdx;
       
   653 
       
   654         if (property.notifier != 0) {
       
   655 
       
   656             if (!noChanges && guard.isConnected(property.notifier)) {
       
   657                 // Nothing to do
       
   658 
       
   659             } else {
       
   660                 noChanges = false;
       
   661 
       
   662                 bool existing = false;
       
   663                 for (int jj = 0; !existing && jj < ii; ++jj) 
       
   664                     if (data->guardList[jj].isConnected(property.notifier)) 
       
   665                         existing = true;
       
   666 
       
   667                 if (existing) {
       
   668                     // duplicate
       
   669                     guard.disconnect();
       
   670                 } else {
       
   671                     guard.connect(property.notifier);
       
   672                 }
       
   673             }
       
   674 
       
   675 
       
   676         } else if (property.notifyIndex != -1) {
       
   677 
       
   678             if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
       
   679                 // Nothing to do
       
   680 
       
   681             } else {
       
   682                 noChanges = false;
       
   683 
       
   684                 bool existing = false;
       
   685                 for (int jj = 0; !existing && jj < ii; ++jj) 
       
   686                     if (data->guardList[jj].isConnected(property.object, property.notifyIndex)) 
       
   687                         existing = true;
       
   688 
       
   689                 if (existing) {
       
   690                     // duplicate
       
   691                     guard.disconnect();
       
   692                 } else {
       
   693                     guard.connect(property.object, property.notifyIndex);
       
   694                 }
       
   695             }
       
   696 
       
   697         } else {
       
   698             if (!outputWarningHeader) {
       
   699                 outputWarningHeader = true;
       
   700                 qWarning() << "QDeclarativeExpression: Expression" << q->expression()
       
   701                            << "depends on non-NOTIFYable properties:";
       
   702             }
       
   703 
       
   704             const QMetaObject *metaObj = property.object->metaObject();
       
   705             QMetaProperty metaProp = metaObj->property(property.coreIndex);
       
   706 
       
   707             qWarning().nospace() << "    " << metaObj->className() << "::" << metaProp.name();
       
   708         }
       
   709     }
       
   710 }
       
   711 
       
   712 /*!
       
   713     \fn void QDeclarativeExpression::valueChanged()
       
   714 
       
   715     Emitted each time the expression value changes from the last time it was
       
   716     evaluated.  The expression must have been evaluated at least once (by
       
   717     calling QDeclarativeExpression::evaluate()) before this signal will be emitted.
       
   718 */
       
   719 
       
   720 void QDeclarativeExpressionPrivate::emitValueChanged()
       
   721 {
       
   722     Q_Q(QDeclarativeExpression);
       
   723     emit q->valueChanged();
       
   724 }
       
   725 
       
   726 QDeclarativeAbstractExpression::QDeclarativeAbstractExpression()
       
   727 : m_context(0), m_prevExpression(0), m_nextExpression(0)
       
   728 {
       
   729 }
       
   730 
       
   731 QDeclarativeAbstractExpression::~QDeclarativeAbstractExpression()
       
   732 {
       
   733     if (m_prevExpression) {
       
   734         *m_prevExpression = m_nextExpression;
       
   735         if (m_nextExpression) 
       
   736             m_nextExpression->m_prevExpression = m_prevExpression;
       
   737     }
       
   738 }
       
   739 
       
   740 QDeclarativeContextData *QDeclarativeAbstractExpression::context() const
       
   741 {
       
   742     return m_context;
       
   743 }
       
   744 
       
   745 void QDeclarativeAbstractExpression::setContext(QDeclarativeContextData *context)
       
   746 {
       
   747     if (m_prevExpression) {
       
   748         *m_prevExpression = m_nextExpression;
       
   749         if (m_nextExpression) 
       
   750             m_nextExpression->m_prevExpression = m_prevExpression;
       
   751         m_prevExpression = 0;
       
   752         m_nextExpression = 0;
       
   753     }
       
   754 
       
   755     m_context = context;
       
   756 
       
   757     if (m_context) {
       
   758         m_nextExpression = m_context->expressions;
       
   759         if (m_nextExpression) 
       
   760             m_nextExpression->m_prevExpression = &m_nextExpression;
       
   761         m_prevExpression = &context->expressions;
       
   762         m_context->expressions = this;
       
   763     }
       
   764 }
       
   765 
       
   766 void QDeclarativeAbstractExpression::refresh()
       
   767 {
       
   768 }
       
   769 
       
   770 bool QDeclarativeAbstractExpression::isValid() const
       
   771 {
       
   772     return m_context != 0;
       
   773 }
       
   774 
       
   775 QT_END_NAMESPACE
       
   776 
       
   777 #include <moc_qdeclarativeexpression.cpp>