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