/****************************************************************************
**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
**
**
**
+**
** $QT_END_LICENSE$
**
****************************************************************************/
QDeclarativeJavaScriptExpression::QDeclarativeJavaScriptExpression()
: m_requiresThisObject(0), m_useSharedContext(0), m_notifyOnValueChanged(0),
- m_scopeObject(0)
+ m_scopeObject(0), guardCapture(0)
{
}
QDeclarativeJavaScriptExpression::~QDeclarativeJavaScriptExpression()
{
+ if (guardCapture) guardCapture->expression = 0;
+ clearGuards();
}
QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
-: expressionFunctionValid(true), extractExpressionFromFunction(false), line(-1), dataRef(0)
+: expressionFunctionValid(true), expressionFunctionRewritten(false),
+ extractExpressionFromFunction(false), line(-1), dataRef(0)
{
}
QDeclarativeAbstractExpression::setContext(ctxt);
setScopeObject(me);
expressionFunctionValid = false;
+ expressionFunctionRewritten = false;
}
void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
v8function = qPersistentNew<v8::Function>(func);
setUseSharedContext(false);
expressionFunctionValid = true;
+ expressionFunctionRewritten = false;
extractExpressionFromFunction = true;
}
-void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, bool isRewritten,
- QObject *me, const QString &srcUrl, int lineNumber)
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr,
+ bool isRewritten, QObject *me, const QString &srcUrl,
+ int lineNumber, int columnNumber)
{
url = srcUrl;
line = lineNumber;
+ column = columnNumber;
expression = expr;
- if (!isRewritten) {
- expressionFunctionValid = false;
- } else {
- v8function = evalFunction(ctxt, me, expression, url, line, &v8qmlscope);
- expressionFunctionValid = true;
- }
+ expressionFunctionValid = false;
+ expressionFunctionRewritten = isRewritten;
QDeclarativeAbstractExpression::setContext(ctxt);
setScopeObject(me);
v8::TryCatch tc;
v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line);
+ if (tc.HasCaught()) return v8::Persistent<v8::Function>();
v8::Local<v8::Value> result = script->Run(scopeobject);
if (tc.HasCaught()) return v8::Persistent<v8::Function>();
if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
}
+QDeclarativeExpression *QDeclarativeExpressionPrivate::create(QDeclarativeContextData *ctxt, QObject *object, const QString &expr, bool isRewritten,
+ const QString &url, int lineNumber, int columnNumber)
+{
+ return new QDeclarativeExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QDeclarativeExpressionPrivate);
+}
+
/*!
\class QDeclarativeExpression
\since 4.7
/*! \internal */
QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt,
QObject *object, const QString &expr, bool isRewritten,
- const QString &url, int lineNumber,
+ const QString &url, int lineNumber, int columnNumber,
QDeclarativeExpressionPrivate &dd)
: QObject(dd, 0)
{
Q_D(QDeclarativeExpression);
- d->init(ctxt, expr, isRewritten, object, url, lineNumber);
+ d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
}
/*!
if (cdata)
d->init(ctxtdata, cdata->primitives.at(id), true, script.scopeObject(),
- cdata->name, script.d.data()->lineNumber);
+ cdata->name, script.d.data()->lineNumber, script.d.data()->columnNumber);
else
defaultConstruction = true;
d->resetNotifyOnValueChanged();
d->expression = expression;
d->expressionFunctionValid = false;
+ d->expressionFunctionRewritten = false;
qPersistentDispose(d->v8function);
qPersistentDispose(d->v8qmlscope);
}
void QDeclarativeJavaScriptExpression::setNotifyOnValueChanged(bool v)
{
m_notifyOnValueChanged = v;
- if (!v) guardList.clear();
+ if (!v) clearGuards();
}
void QDeclarativeJavaScriptExpression::resetNotifyOnValueChanged()
{
- guardList.clear();
+ clearGuards();
}
v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::Function> function, bool *isUndefined)
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
- bool lastCaptureProperties = ep->captureProperties;
- QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
- ep->captureProperties = notifyOnValueChanged();
+ Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
+ GuardCapture capture(this);
+
+ QDeclarativeEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
+ ep->propertyCapture = notifyOnValueChanged()?&capture:0;
+
- if (ep->capturedProperties.count())
- ep->capturedProperties.copyAndClear(lastCapturedProperties);
+ if (notifyOnValueChanged())
+ capture.guards.copyAndClear(activeGuards);
QDeclarativeContextData *lastSharedContext = 0;
QObject *lastSharedScope = 0;
// All code that follows must check with watcher before it accesses data members
// incase we have been deleted.
- QDeclarativeDeleteWatcher watcher(this);
+ QDeleteWatcher watcher(this);
if (sharedContext) {
lastSharedContext = ep->sharedContext;
ep->sharedScope = lastSharedScope;
}
- if (!watcher.wasDeleted() && notifyOnValueChanged()) {
- guardList.updateGuards(this, ep->capturedProperties);
+ if (capture.errorString) {
+ for (int ii = 0; ii < capture.errorString->count(); ++ii)
+ qWarning("%s", qPrintable(capture.errorString->at(ii)));
+ delete capture.errorString;
+ capture.errorString = 0;
}
- if (lastCapturedProperties.count())
- lastCapturedProperties.copyAndClear(ep->capturedProperties);
- else
- ep->capturedProperties.clear();
+ while (Guard *g = capture.guards.takeFirst())
+ g->Delete();
- ep->captureProperties = lastCaptureProperties;
+ ep->propertyCapture = lastPropertyCapture;
return result;
}
-void
-QDeclarativeJavaScriptExpression::GuardList::updateGuards(QDeclarativeJavaScriptExpression *expression,
- const CapturedProperties &properties)
+void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QDeclarativeNotifier *n)
{
- if (properties.count() == 0) {
- clear();
- return;
- }
+ if (expression) {
- if (properties.count() != length) {
- Endpoint *newGuardList = new Endpoint[properties.count()];
+ // Try and find a matching guard
+ while (!guards.isEmpty() && !guards.first()->isConnected(n))
+ guards.takeFirst()->Delete();
- for (int ii = 0; ii < qMin(length, properties.count()); ++ii)
- endpoints[ii].copyAndClear(newGuardList[ii]);
+ Guard *g = 0;
+ if (!guards.isEmpty()) {
+ g = guards.takeFirst();
+ g->cancelNotify();
+ Q_ASSERT(g->isConnected(n));
+ } else {
+ g = Guard::New(expression);
+ g->connect(n);
+ }
- delete [] endpoints;
- endpoints = newGuardList;
- length = properties.count();
+ expression->activeGuards.append(g);
}
+}
- bool outputWarningHeader = false;
- bool noChanges = true;
- for (int ii = 0; ii < properties.count(); ++ii) {
- Endpoint &guard = endpoints[ii];
- const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
-
- guard.expression = expression;
-
- if (property.notifier != 0) {
-
- if (!noChanges && guard.isConnected(property.notifier)) {
- // Nothing to do
-
- } else {
- noChanges = false;
-
- bool existing = false;
- for (int jj = 0; !existing && jj < ii; ++jj)
- if (endpoints[jj].isConnected(property.notifier))
- existing = true;
-
- if (existing) {
- // duplicate
- guard.disconnect();
- } else {
- guard.connect(property.notifier);
- }
+void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
+{
+ if (expression) {
+ if (n == -1) {
+ if (!errorString) {
+ errorString = new QStringList;
+ QString preamble = QLatin1String("QDeclarativeExpression: Expression ") +
+ expression->expressionIdentifier() +
+ QLatin1String(" depends on non-NOTIFYable properties:");
+ errorString->append(preamble);
}
+ const QMetaObject *metaObj = o->metaObject();
+ QMetaProperty metaProp = metaObj->property(c);
- } else if (property.notifyIndex != -1) {
+ QString error = QLatin1String(" ") +
+ QString::fromUtf8(metaObj->className()) +
+ QLatin1String("::") +
+ QString::fromUtf8(metaProp.name());
+ errorString->append(error);
+ } else {
- if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
- // Nothing to do
+ // Try and find a matching guard
+ while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
+ guards.takeFirst()->Delete();
+ Guard *g = 0;
+ if (!guards.isEmpty()) {
+ g = guards.takeFirst();
+ g->cancelNotify();
+ Q_ASSERT(g->isConnected(o, n));
} else {
- noChanges = false;
-
- bool existing = false;
- for (int jj = 0; !existing && jj < ii; ++jj)
- if (endpoints[jj].isConnected(property.object, property.notifyIndex))
- existing = true;
-
- if (existing) {
- // duplicate
- guard.disconnect();
- } else {
- guard.connect(property.object, property.notifyIndex);
- }
+ g = Guard::New(expression);
+ g->connect(o, n);
}
- } else {
- if (!outputWarningHeader) {
- QString e = expression->expressionIdentifier();
- outputWarningHeader = true;
- qWarning() << "QDeclarativeExpression: Expression" << qPrintable(e)
- << "depends on non-NOTIFYable properties:";
- }
-
- const QMetaObject *metaObj = property.object->metaObject();
- QMetaProperty metaProp = metaObj->property(property.coreIndex);
-
- qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name();
+ expression->activeGuards.append(g);
}
}
}
+void QDeclarativeJavaScriptExpression::clearGuards()
+{
+ while (Guard *g = activeGuards.takeFirst())
+ g->Delete();
+}
+
// Must be called with a valid handle scope
v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
{
if (!expressionFunctionValid) {
+ bool ok = true;
+
QDeclarativeRewrite::RewriteBinding rewriteBinding;
rewriteBinding.setName(name);
- bool ok = true;
- const QString code = rewriteBinding(expression, &ok);
+ QString code;
+ if (expressionFunctionRewritten)
+ code = expression;
+ else
+ code = rewriteBinding(expression, &ok);
+
if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
setUseSharedContext(false);
expressionFunctionValid = true;
}
/*!
+ Returns the source file column number for this expression. The source location
+ must have been previously set by calling setSourceLocation().
+*/
+int QDeclarativeExpression::columnNumber() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->column;
+}
+
+/*!
Set the location of this expression to \a line of \a url. This information
is used by the script engine.
*/
-void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
+void QDeclarativeExpression::setSourceLocation(const QString &url, int line, int column)
{
Q_D(QDeclarativeExpression);
d->url = url;
d->line = line;
+ d->column = column;
}
/*!