summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2010-07-14 12:24:38 +1000
committerAaron Kennedy <aaron.kennedy@nokia.com>2010-07-14 12:32:08 +1000
commita675b9ef9f85fa4a2fa245cd164d1e330b703bd9 (patch)
tree82fcb858776f6134e2d8e783df8f49f88de5d55d
parent400b0d43830dfdcefb2f8bd91440ab6f4130ce0f (diff)
downloadqt4-tools-a675b9ef9f85fa4a2fa245cd164d1e330b703bd9.tar.gz
Split responsibilities in QDeclarativeExpression more cleanly
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp139
-rw-r--r--src/declarative/qml/qdeclarativebinding_p_p.h28
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h1
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp2
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h1
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp478
-rw-r--r--src/declarative/qml/qdeclarativeexpression_p.h83
7 files changed, 401 insertions, 331 deletions
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
index 882e981555..e3b33c07a9 100644
--- a/src/declarative/qml/qdeclarativebinding.cpp
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -54,27 +54,20 @@
QT_BEGIN_NAMESPACE
-QDeclarativeBindingData::QDeclarativeBindingData()
-: updating(false), enabled(false)
+void QDeclarativeBindingPrivate::refresh()
{
+ Q_Q(QDeclarativeBinding);
+ q->update();
}
-QDeclarativeBindingData::~QDeclarativeBindingData()
-{
- removeError();
-}
-
-void QDeclarativeBindingData::refresh()
+QDeclarativeBindingPrivate::QDeclarativeBindingPrivate()
+: updating(false), enabled(false), deleted(0)
{
- if (enabled && !updating && q) {
- QDeclarativeBinding *b = static_cast<QDeclarativeBinding *>(QDeclarativeExpressionPrivate::get(q));
- b->update();
- }
}
-QDeclarativeBindingPrivate::QDeclarativeBindingPrivate()
-: QDeclarativeExpressionPrivate(new QDeclarativeBindingData)
+QDeclarativeBindingPrivate::~QDeclarativeBindingPrivate()
{
+ if (deleted) *deleted = true;
}
QDeclarativeBinding::QDeclarativeBinding(void *data, QDeclarativeRefCount *rc, QObject *obj,
@@ -109,7 +102,7 @@ QDeclarativeBinding::~QDeclarativeBinding()
void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop)
{
Q_D(QDeclarativeBinding);
- d->bindingData()->property = prop;
+ d->property = prop;
update();
}
@@ -117,50 +110,53 @@ void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop)
QDeclarativeProperty QDeclarativeBinding::property() const
{
Q_D(const QDeclarativeBinding);
- return d->bindingData()->property;
+ return d->property;
}
void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
{
Q_D(QDeclarativeBinding);
- QDeclarativeBindingData *data = d->bindingData();
-
- if (!data->enabled || !data->context() || !data->context()->isValid())
+ if (!d->enabled || !d->context() || !d->context()->isValid())
return;
- data->addref();
+ if (!d->updating) {
+ d->updating = true;
+ bool wasDeleted = false;
+ d->deleted = &wasDeleted;
- if (!data->updating) {
- data->updating = true;
+ if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
- if (data->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
-
- int idx = data->property.index();
+ int idx = d->property.index();
Q_ASSERT(idx != -1);
-
QDeclarativeBinding *t = this;
int status = -1;
void *a[] = { &t, 0, &status, &flags };
- QMetaObject::metacall(data->property.object(),
+ QMetaObject::metacall(d->property.object(),
QMetaObject::WriteProperty,
idx, a);
+ if (wasDeleted)
+ return;
+
} else {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(data->context()->engine);
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
bool isUndefined = false;
QVariant value;
QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
- if (data->property.propertyTypeCategory() == QDeclarativeProperty::List) {
+ if (wasDeleted)
+ return;
+
+ if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
} else if (scriptValue.isNull() &&
- data->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
+ d->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
value = QVariant::fromValue((QObject *)0);
} else {
- value = ep->scriptValueToVariant(scriptValue, data->property.propertyType());
+ value = ep->scriptValueToVariant(scriptValue, d->property.propertyType());
if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) {
// If the object is null, we extract the predicted type. While this isn't
// 100% reliable, in many cases it gives us better error messages if we
@@ -172,73 +168,72 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
}
- if (data->error.isValid()) {
+ if (d->error.isValid()) {
- } else if (isUndefined && data->property.isResettable()) {
+ } else if (isUndefined && d->property.isResettable()) {
- data->property.reset();
+ d->property.reset();
- } else if (isUndefined && data->property.propertyType() == qMetaTypeId<QVariant>()) {
+ } else if (isUndefined && d->property.propertyType() == qMetaTypeId<QVariant>()) {
- QDeclarativePropertyPrivate::write(data->property, QVariant(), flags);
+ QDeclarativePropertyPrivate::write(d->property, QVariant(), flags);
} else if (isUndefined) {
- QUrl url = QUrl(data->url);
- int line = data->line;
+ QUrl url = QUrl(d->url);
+ int line = d->line;
if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
- data->error.setUrl(url);
- data->error.setLine(line);
- data->error.setColumn(-1);
- data->error.setDescription(QLatin1String("Unable to assign [undefined] to ")
- + QLatin1String(QMetaType::typeName(data->property.propertyType()))
- + QLatin1String(" ") + data->property.name());
+ d->error.setUrl(url);
+ d->error.setLine(line);
+ d->error.setColumn(-1);
+ d->error.setDescription(QLatin1String("Unable to assign [undefined] to ") +
+ QLatin1String(QMetaType::typeName(d->property.propertyType())) +
+ QLatin1String(" ") + d->property.name());
} else if (!scriptValue.isRegExp() && scriptValue.isFunction()) {
- QUrl url = QUrl(data->url);
- int line = data->line;
+ QUrl url = QUrl(d->url);
+ int line = d->line;
if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
- data->error.setUrl(url);
- data->error.setLine(line);
- data->error.setColumn(-1);
- data->error.setDescription(QLatin1String("Unable to assign a function to a property."));
+ d->error.setUrl(url);
+ d->error.setLine(line);
+ d->error.setColumn(-1);
+ d->error.setDescription(QLatin1String("Unable to assign a function to a property."));
- } else if (data->property.object() &&
- !QDeclarativePropertyPrivate::write(data->property, value, flags)) {
+ } else if (d->property.object() &&
+ !QDeclarativePropertyPrivate::write(d->property, value, flags)) {
- QUrl url = QUrl(data->url);
- int line = data->line;
+ QUrl url = QUrl(d->url);
+ int line = d->line;
if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
const char *valueType = 0;
if (value.userType() == QVariant::Invalid) valueType = "null";
else valueType = QMetaType::typeName(value.userType());
- data->error.setUrl(url);
- data->error.setLine(line);
- data->error.setColumn(-1);
- data->error.setDescription(QLatin1String("Unable to assign ") +
- QLatin1String(valueType) +
- QLatin1String(" to ") +
- QLatin1String(QMetaType::typeName(data->property.propertyType())));
+ d->error.setUrl(url);
+ d->error.setLine(line);
+ d->error.setColumn(-1);
+ d->error.setDescription(QLatin1String("Unable to assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(QMetaType::typeName(d->property.propertyType())));
}
- if (data->error.isValid()) {
- if (!data->addError(ep)) ep->warning(this->error());
+ if (d->error.isValid()) {
+ if (!d->addError(ep)) ep->warning(this->error());
} else {
- data->removeError();
+ d->removeError();
}
}
- data->updating = false;
+ d->updating = false;
+ d->deleted = 0;
} else {
- qmlInfo(data->property.object()) << tr("Binding loop detected for property \"%1\"").arg(data->property.name());
+ qmlInfo(d->property.object()) << tr("Binding loop detected for property \"%1\"").arg(d->property.name());
}
-
- data->release();
}
void QDeclarativeBindingPrivate::emitValueChanged()
@@ -250,13 +245,13 @@ void QDeclarativeBindingPrivate::emitValueChanged()
void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
{
Q_D(QDeclarativeBinding);
- d->bindingData()->enabled = e;
+ d->enabled = e;
setNotifyOnValueChanged(e);
QDeclarativeAbstractBinding::setEnabled(e, flags);
if (e) {
- addToObject(d->bindingData()->property.object());
+ addToObject(d->property.object());
update(flags);
} else {
removeFromObject();
@@ -266,14 +261,14 @@ void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteF
int QDeclarativeBinding::propertyIndex()
{
Q_D(QDeclarativeBinding);
- return QDeclarativePropertyPrivate::bindingIndex(d->bindingData()->property);
+ return QDeclarativePropertyPrivate::bindingIndex(d->property);
}
bool QDeclarativeBinding::enabled() const
{
Q_D(const QDeclarativeBinding);
- return d->bindingData()->enabled;
+ return d->enabled;
}
QString QDeclarativeBinding::expression() const
diff --git a/src/declarative/qml/qdeclarativebinding_p_p.h b/src/declarative/qml/qdeclarativebinding_p_p.h
index 617ec4bd73..6926158edb 100644
--- a/src/declarative/qml/qdeclarativebinding_p_p.h
+++ b/src/declarative/qml/qdeclarativebinding_p_p.h
@@ -60,30 +60,24 @@
QT_BEGIN_NAMESPACE
-class QDeclarativeBindingData : public QDeclarativeExpressionData
-{
-public:
- QDeclarativeBindingData();
- virtual ~QDeclarativeBindingData();
-
- bool updating:1;
- bool enabled:1;
-
- QDeclarativeProperty property;
-
- virtual void refresh();
-};
-
class QDeclarativeBindingPrivate : public QDeclarativeExpressionPrivate
{
Q_DECLARE_PUBLIC(QDeclarativeBinding)
public:
QDeclarativeBindingPrivate();
-
- QDeclarativeBindingData *bindingData() { return static_cast<QDeclarativeBindingData *>(data); }
- const QDeclarativeBindingData *bindingData() const { return static_cast<const QDeclarativeBindingData *>(data); }
+ ~QDeclarativeBindingPrivate();
virtual void emitValueChanged();
+
+protected:
+ virtual void refresh();
+
+private:
+ bool updating:1;
+ bool enabled:1;
+ QDeclarativeProperty property;
+
+ bool *deleted;
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index 1f5aaf1cae..c5a039a3c9 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -198,6 +198,7 @@ public:
// context
QDeclarativeComponentAttached *componentAttached;
+ // Return the outermost id for obj, if any.
QString findObjectId(const QObject *obj) const;
static QDeclarativeContextData *get(QDeclarativeContext *context) {
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index 00bc1b7aef..97ef99c1cf 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -219,7 +219,7 @@ of their use.
QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
-: captureProperties(false), rootContext(0), currentExpression(0), isDebugging(false),
+: captureProperties(false), rootContext(0), isDebugging(false),
outputWarningsToStdErr(true), contextClass(0), sharedContext(0), sharedScope(0),
objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0),
inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttached(0),
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index f457b536e2..a5c8c388d1 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -162,7 +162,6 @@ public:
QPODVector<CapturedProperty> capturedProperties;
QDeclarativeContext *rootContext;
- QDeclarativeExpression *currentExpression;
bool isDebugging;
bool outputWarningsToStdErr;
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index 96cdec15e9..9935e384a7 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -71,109 +71,95 @@ bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e)
return true;
}
-QDeclarativeExpressionData::QDeclarativeExpressionData()
-: q(0), dataRef(0), expressionFunctionValid(false), expressionRewritten(false), me(0),
- trackChange(false), isShared(false), line(-1), guardList(0), guardListLength(0)
+QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression()
+: dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false),
+ guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0)
{
}
-QDeclarativeExpressionData::~QDeclarativeExpressionData()
+QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
{
if (guardList) { delete [] guardList; guardList = 0; }
if (dataRef) dataRef->release();
+ if (deleted) *deleted = true;
}
QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
-: data(new QDeclarativeExpressionData)
+: expressionFunctionValid(true), line(-1)
{
- data->q = this;
-}
-
-QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate(QDeclarativeExpressionData *d)
-: data(d)
-{
- data->q = this;
}
QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate()
{
- if (data) {
- delete [] data->guardList;
- data->guardList = 0;
- data->guardListLength = 0;
- data->q = 0;
- data->release();
- data = 0;
- }
}
void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr,
QObject *me)
{
- data->expression = expr;
+ expression = expr;
- data->QDeclarativeAbstractExpression::setContext(ctxt);
- data->me = me;
+ QDeclarativeAbstractExpression::setContext(ctxt);
+ scopeObject = me;
+ expressionFunctionValid = false;
}
-void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, QDeclarativeRefCount *rc,
- QObject *me, const QString &url, int lineNumber)
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr,
+ QDeclarativeRefCount *rc,
+ QObject *me, const QString &srcUrl, int lineNumber)
{
- data->url = url;
- data->line = lineNumber;
+ url = srcUrl;
+ line = lineNumber;
- if (data->dataRef) data->dataRef->release();
- data->dataRef = rc;
- if (data->dataRef) data->dataRef->addref();
+ if (dataRef) dataRef->release();
+ dataRef = rc;
+ if (dataRef) dataRef->addref();
quint32 *exprData = (quint32 *)expr;
QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc;
- data->expressionRewritten = true;
- data->expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]);
+ expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]);
int progIdx = *(exprData);
- bool isShared = progIdx & 0x80000000;
+ bool isSharedProgram = progIdx & 0x80000000;
progIdx &= 0x7FFFFFFF;
QDeclarativeEngine *engine = ctxt->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- if (isShared) {
+ if (isSharedProgram) {
if (!dd->cachedClosures.at(progIdx)) {
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
scriptContext->pushScope(ep->contextClass->newSharedContext());
scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(data->expression, data->url, data->line));
+ dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(expression, url, line));
scriptEngine->popContext();
}
- data->expressionFunction = *dd->cachedClosures.at(progIdx);
- data->isShared = true;
- data->expressionFunctionValid = true;
+ expressionFunction = *dd->cachedClosures.at(progIdx);
+ expressionFunctionMode = SharedContext;
+ expressionFunctionValid = true;
} else {
#if !defined(Q_OS_SYMBIAN) //XXX Why doesn't this work?
if (!dd->cachedPrograms.at(progIdx)) {
- dd->cachedPrograms[progIdx] =
- new QScriptProgram(data->expression, data->url, data->line);
+ dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line);
}
- data->expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx),
- &data->expressionContext);
+ expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx),
+ &expressionContext);
#else
- data->expressionFunction = evalInObjectScope(ctxt, me, data->expression,
- &data->expressionContext);
+ expressionFunction = evalInObjectScope(ctxt, me, expression, &expressionContext);
#endif
- data->expressionFunctionValid = true;
+ expressionFunctionMode = ExplicitContext;
+ expressionFunctionValid = true;
}
- data->QDeclarativeAbstractExpression::setContext(ctxt);
- data->me = me;
+ QDeclarativeAbstractExpression::setContext(ctxt);
+ scopeObject = me;
}
QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
@@ -240,6 +226,8 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex
\endcode
*/
+static int QDeclarativeExpression_notifyIdx = -1;
+
/*!
Create an invalid QDeclarativeExpression.
@@ -249,6 +237,11 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex
QDeclarativeExpression::QDeclarativeExpression()
: QObject(*new QDeclarativeExpressionPrivate, 0)
{
+ Q_D(QDeclarativeExpression);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
/*! \internal */
@@ -260,6 +253,10 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, vo
{
Q_D(QDeclarativeExpression);
d->init(ctxt, expr, rc, me, url, lineNumber);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
/*!
@@ -277,6 +274,10 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt,
{
Q_D(QDeclarativeExpression);
d->init(QDeclarativeContextData::get(ctxt), expression, scope);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
/*!
@@ -288,6 +289,10 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO
{
Q_D(QDeclarativeExpression);
d->init(ctxt, expression, scope);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
/*! \internal */
@@ -297,6 +302,10 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO
{
Q_D(QDeclarativeExpression);
d->init(ctxt, expression, scope);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
/*!
@@ -313,7 +322,7 @@ QDeclarativeExpression::~QDeclarativeExpression()
QDeclarativeEngine *QDeclarativeExpression::engine() const
{
Q_D(const QDeclarativeExpression);
- return d->data->context()?d->data->context()->engine:0;
+ return d->context()?d->context()->engine:0;
}
/*!
@@ -323,7 +332,7 @@ QDeclarativeEngine *QDeclarativeExpression::engine() const
QDeclarativeContext *QDeclarativeExpression::context() const
{
Q_D(const QDeclarativeExpression);
- QDeclarativeContextData *data = d->data->context();
+ QDeclarativeContextData *data = d->context();
return data?data->asQDeclarativeContext():0;
}
@@ -333,7 +342,7 @@ QDeclarativeContext *QDeclarativeExpression::context() const
QString QDeclarativeExpression::expression() const
{
Q_D(const QDeclarativeExpression);
- return d->data->expression;
+ return d->expression;
}
/*!
@@ -343,12 +352,10 @@ void QDeclarativeExpression::setExpression(const QString &expression)
{
Q_D(QDeclarativeExpression);
- d->clearGuards();
-
- d->data->expression = expression;
- d->data->expressionFunctionValid = false;
- d->data->expressionRewritten = false;
- d->data->expressionFunction = QScriptValue();
+ d->resetNotifyOnChange();
+ d->expression = expression;
+ d->expressionFunctionValid = false;
+ d->expressionFunction = QScriptValue();
}
void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine,
@@ -378,59 +385,108 @@ void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine
}
}
-QScriptValue QDeclarativeExpressionPrivate::eval(QObject *secondaryScope, bool *isUndefined)
+bool QDeclarativeQtScriptExpression::notifyOnValueChange() const
{
- QDeclarativeExpressionData *data = this->data;
- QDeclarativeEngine *engine = data->context()->engine;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ return trackChange;
+}
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+void QDeclarativeQtScriptExpression::setNotifyOnValueChange(bool notify)
+{
+ trackChange = notify;
+ if (!notify && guardList)
+ clearGuards();
+}
- if (!data->expressionFunctionValid) {
+void QDeclarativeQtScriptExpression::resetNotifyOnChange()
+{
+ clearGuards();
+}
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- data->expressionContext = ep->contextClass->newContext(data->context(), data->me);
- scriptContext->pushScope(data->expressionContext);
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
+void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notifyIndex)
+{
+ if (guardList) clearGuards();
+
+ if (!object || notifyIndex == -1) {
+ guardObject = 0;
+ notifyIndex = -1;
+ } else {
+ guardObject = object;
+ guardObjectNotifyIndex = notifyIndex;
+
+ }
+}
+
+QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined)
+{
+ Q_ASSERT(context() && context()->engine);
+ Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1));
+
+ if (!expressionFunction.isValid()) {
+ if (isUndefined) *isUndefined = true;
+ return QScriptValue();
+ }
+
+ DeleteWatcher watcher(this);
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
+
+ bool lastCaptureProperties = ep->captureProperties;
+ QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
+ ep->captureProperties = trackChange;
+ ep->capturedProperties.copyAndClear(lastCapturedProperties);
+
+ QScriptValue value = eval(secondaryScope, isUndefined);
+
+ if (!watcher.wasDeleted() && trackChange) {
+ if (ep->capturedProperties.count() == 0) {
+
+ if (guardList) clearGuards();
- if (data->expressionRewritten) {
- data->expressionFunction = scriptEngine->evaluate(data->expression,
- data->url, data->line);
} else {
- QDeclarativeRewrite::RewriteBinding rewriteBinding;
- bool ok = true;
- const QString code = rewriteBinding(data->expression, &ok);
- if (!ok) {
- scriptEngine->popContext();
- return QScriptValue();
- }
- data->expressionFunction = scriptEngine->evaluate(code, data->url, data->line);
- }
+ updateGuards(ep->capturedProperties);
- scriptEngine->popContext();
- data->expressionFunctionValid = true;
+ }
}
+ lastCapturedProperties.copyAndClear(ep->capturedProperties);
+ ep->captureProperties = lastCaptureProperties;
+
+ return value;
+}
+
+QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
+{
+ Q_ASSERT(context() && context()->engine);
+
+ DeleteWatcher watcher(this);
+
+ QDeclarativeEngine *engine = context()->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
QDeclarativeContextData *oldSharedContext = 0;
QObject *oldSharedScope = 0;
QObject *oldOverride = 0;
- if (data->isShared) {
+ bool isShared = (expressionFunctionMode == SharedContext);
+
+ if (isShared) {
oldSharedContext = ep->sharedContext;
oldSharedScope = ep->sharedScope;
- ep->sharedContext = data->context();
- ep->sharedScope = data->me;
+ ep->sharedContext = context();
+ ep->sharedScope = scopeObject;
} else {
- oldOverride = ep->contextClass->setOverrideObject(data->expressionContext, secondaryScope);
+ oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope);
}
- QScriptValue svalue = data->expressionFunction.call();
+ QScriptValue svalue = expressionFunction.call(); // This could cause this to be deleted
- if (data->isShared) {
+ if (isShared) {
ep->sharedContext = oldSharedContext;
ep->sharedScope = oldSharedScope;
- } else {
- ep->contextClass->setOverrideObject(data->expressionContext, oldOverride);
+ } else if (!watcher.wasDeleted()) {
+ ep->contextClass->setOverrideObject(expressionContext, oldOverride);
}
if (isUndefined)
@@ -438,63 +494,134 @@ QScriptValue QDeclarativeExpressionPrivate::eval(QObject *secondaryScope, bool *
// Handle exception
if (scriptEngine->hasUncaughtException()) {
- exceptionToError(scriptEngine, data->error);
+ if (!watcher.wasDeleted())
+ QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
+
scriptEngine->clearExceptions();
return QScriptValue();
} else {
- data->error = QDeclarativeError();
+ if (!watcher.wasDeleted())
+ error = QDeclarativeError();
+
return svalue;
}
}
-QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
+void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
{
- Q_Q(QDeclarativeExpression);
- Q_ASSERT(q->engine());
+ Q_ASSERT(guardObject);
+ Q_ASSERT(guardObjectNotifyIndex != -1);
- if (data->expression.isEmpty())
- return QScriptValue();
+ if (properties.count() != guardListLength) {
+ QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()];
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
+ for (int ii = 0; ii < qMin(guardListLength, properties.count()); ++ii)
+ guardList[ii].copyAndClear(newGuardList[ii]);
- QDeclarativeExpression *lastCurrentExpression = ep->currentExpression;
- bool lastCaptureProperties = ep->captureProperties;
- QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
- ep->capturedProperties.copyAndClear(lastCapturedProperties);
+ delete [] guardList;
+ guardList = newGuardList;
+ guardListLength = properties.count();
+ }
- ep->currentExpression = q;
- ep->captureProperties = data->trackChange;
+ bool outputWarningHeader = false;
+ bool noChanges = true;
+ for (int ii = 0; ii < properties.count(); ++ii) {
+ QDeclarativeNotifierEndpoint &guard = guardList[ii];
+ const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
- // This object might be deleted during the eval
- QDeclarativeExpressionData *localData = data;
- localData->addref();
+ guard.target = guardObject;
+ guard.targetMethod = guardObjectNotifyIndex;
- QScriptValue value = eval(secondaryScope, isUndefined);
+ if (property.notifier != 0) {
- ep->currentExpression = lastCurrentExpression;
- ep->captureProperties = lastCaptureProperties;
+ if (!noChanges && guard.isConnected(property.notifier)) {
+ // Nothing to do
- // Check if we were deleted
- if (localData->q) {
- if ((!data->trackChange || !ep->capturedProperties.count()) && data->guardList) {
- clearGuards();
- } else if(data->trackChange) {
- updateGuards(ep->capturedProperties);
+ } else {
+ noChanges = false;
+
+ bool existing = false;
+ for (int jj = 0; !existing && jj < ii; ++jj)
+ if (guardList[jj].isConnected(property.notifier))
+ existing = true;
+
+ if (existing) {
+ // duplicate
+ guard.disconnect();
+ } else {
+ guard.connect(property.notifier);
+ }
+ }
+
+
+ } else if (property.notifyIndex != -1) {
+
+ if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
+ // Nothing to do
+
+ } else {
+ noChanges = false;
+
+ bool existing = false;
+ for (int jj = 0; !existing && jj < ii; ++jj)
+ if (guardList[jj].isConnected(property.object, property.notifyIndex))
+ existing = true;
+
+ if (existing) {
+ // duplicate
+ guard.disconnect();
+ } else {
+ guard.connect(property.object, property.notifyIndex);
+ }
+ }
+
+ } else {
+ if (!outputWarningHeader) {
+ outputWarningHeader = true;
+ qWarning() << "QDeclarativeExpression: Expression" << expression
+ << "depends on non-NOTIFYable properties:";
+ }
+
+ const QMetaObject *metaObj = property.object->metaObject();
+ QMetaProperty metaProp = metaObj->property(property.coreIndex);
+
+ qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name();
}
}
+}
- localData->release();
+QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
+{
+ if (!expressionFunctionValid) {
+ QDeclarativeEngine *engine = context()->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- lastCapturedProperties.copyAndClear(ep->capturedProperties);
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- return value;
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
+ expressionContext = ep->contextClass->newContext(context(), scopeObject);
+ scriptContext->pushScope(expressionContext);
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
+
+ QDeclarativeRewrite::RewriteBinding rewriteBinding;
+ bool ok = true;
+ const QString code = rewriteBinding(expression, &ok);
+ if (ok)
+ expressionFunction = scriptEngine->evaluate(code, url, line);
+
+ scriptEngine->popContext();
+ expressionFunctionMode = ExplicitContext;
+ expressionFunctionValid = true;
+ }
+
+ return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined);
}
QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
{
Q_Q(QDeclarativeExpression);
- if (!data || !data->context() || !data->context()->isValid()) {
+ if (!context() || !context()->isValid()) {
qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
return QVariant();
}
@@ -526,7 +653,7 @@ value changes.
bool QDeclarativeExpression::notifyOnValueChanged() const
{
Q_D(const QDeclarativeExpression);
- return d->data->trackChange;
+ return d->notifyOnValueChange();
}
/*!
@@ -548,7 +675,7 @@ bool QDeclarativeExpression::notifyOnValueChanged() const
void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
{
Q_D(QDeclarativeExpression);
- d->data->trackChange = notifyOnChange;
+ d->setNotifyOnValueChange(notifyOnChange);
}
/*!
@@ -558,7 +685,7 @@ void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
QString QDeclarativeExpression::sourceFile() const
{
Q_D(const QDeclarativeExpression);
- return d->data->url;
+ return d->url;
}
/*!
@@ -568,7 +695,7 @@ QString QDeclarativeExpression::sourceFile() const
int QDeclarativeExpression::lineNumber() const
{
Q_D(const QDeclarativeExpression);
- return d->data->line;
+ return d->line;
}
/*!
@@ -578,8 +705,8 @@ int QDeclarativeExpression::lineNumber() const
void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
{
Q_D(QDeclarativeExpression);
- d->data->url = url;
- d->data->line = line;
+ d->url = url;
+ d->line = line;
}
/*!
@@ -591,7 +718,7 @@ void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
QObject *QDeclarativeExpression::scopeObject() const
{
Q_D(const QDeclarativeExpression);
- return d->data->me;
+ return d->scopeObject;
}
/*!
@@ -603,7 +730,7 @@ QObject *QDeclarativeExpression::scopeObject() const
bool QDeclarativeExpression::hasError() const
{
Q_D(const QDeclarativeExpression);
- return d->data->error.isValid();
+ return d->error.isValid();
}
/*!
@@ -615,7 +742,7 @@ bool QDeclarativeExpression::hasError() const
void QDeclarativeExpression::clearError()
{
Q_D(QDeclarativeExpression);
- d->data->error = QDeclarativeError();
+ d->error = QDeclarativeError();
}
/*!
@@ -628,7 +755,7 @@ void QDeclarativeExpression::clearError()
QDeclarativeError QDeclarativeExpression::error() const
{
Q_D(const QDeclarativeExpression);
- return d->data->error;
+ return d->error;
}
/*! \internal */
@@ -637,98 +764,11 @@ void QDeclarativeExpressionPrivate::_q_notify()
emitValueChanged();
}
-void QDeclarativeExpressionPrivate::clearGuards()
-{
- delete [] data->guardList;
- data->guardList = 0;
- data->guardListLength = 0;
-}
-
-void QDeclarativeExpressionPrivate::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
+void QDeclarativeQtScriptExpression::clearGuards()
{
- Q_Q(QDeclarativeExpression);
-
- static int notifyIdx = -1;
- if (notifyIdx == -1)
- notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
-
- if (properties.count() != data->guardListLength) {
- QDeclarativeNotifierEndpoint *newGuardList =
- new QDeclarativeNotifierEndpoint[properties.count()];
-
- for (int ii = 0; ii < qMin(data->guardListLength, properties.count()); ++ii)
- data->guardList[ii].copyAndClear(newGuardList[ii]);
-
- delete [] data->guardList;
- data->guardList = newGuardList;
- data->guardListLength = properties.count();
- }
-
- bool outputWarningHeader = false;
- bool noChanges = true;
- for (int ii = 0; ii < properties.count(); ++ii) {
- QDeclarativeNotifierEndpoint &guard = data->guardList[ii];
- const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
-
- guard.target = q;
- guard.targetMethod = notifyIdx;
-
- 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 (data->guardList[jj].isConnected(property.notifier))
- existing = true;
-
- if (existing) {
- // duplicate
- guard.disconnect();
- } else {
- guard.connect(property.notifier);
- }
- }
-
-
- } else if (property.notifyIndex != -1) {
-
- if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
- // Nothing to do
-
- } else {
- noChanges = false;
-
- bool existing = false;
- for (int jj = 0; !existing && jj < ii; ++jj)
- if (data->guardList[jj].isConnected(property.object, property.notifyIndex))
- existing = true;
-
- if (existing) {
- // duplicate
- guard.disconnect();
- } else {
- guard.connect(property.object, property.notifyIndex);
- }
- }
-
- } else {
- if (!outputWarningHeader) {
- outputWarningHeader = true;
- qWarning() << "QDeclarativeExpression: Expression" << q->expression()
- << "depends on non-NOTIFYable properties:";
- }
-
- const QMetaObject *metaObj = property.object->metaObject();
- QMetaProperty metaProp = metaObj->property(property.coreIndex);
-
- qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name();
- }
- }
+ delete [] guardList;
+ guardList = 0;
+ guardListLength = 0;
}
/*!
diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h
index 4ff3162af7..b629e204f1 100644
--- a/src/declarative/qml/qdeclarativeexpression_p.h
+++ b/src/declarative/qml/qdeclarativeexpression_p.h
@@ -107,56 +107,73 @@ private:
QDeclarativeDelayedError **prevError;
};
-class QDeclarativeExpressionData : public QDeclarativeAbstractExpression, public QDeclarativeDelayedError, public QDeclarativeRefCount
+class QDeclarativeQtScriptExpression : public QDeclarativeAbstractExpression,
+ public QDeclarativeDelayedError
{
public:
- QDeclarativeExpressionData();
- virtual ~QDeclarativeExpressionData();
+ enum Mode { SharedContext, ExplicitContext };
- QDeclarativeExpressionPrivate *q;
+ QDeclarativeQtScriptExpression();
+ virtual ~QDeclarativeQtScriptExpression();
QDeclarativeRefCount *dataRef;
+
QString expression;
- bool expressionFunctionValid:1;
- bool expressionRewritten:1;
+
+ Mode expressionFunctionMode;
QScriptValue expressionFunction;
- QScriptValue expressionContext;
- QObject *me;
- bool trackChange;
+ QScriptValue expressionContext; // Only used in ExplicitContext
+ QObject *scopeObject; // Only used in SharedContext
- bool isShared;
+ bool notifyOnValueChange() const;
+ void setNotifyOnValueChange(bool);
+ void resetNotifyOnChange();
+ void setNotifyObject(QObject *, int );
- QString url; // This is a QString for a reason. QUrls are slooooooow...
- int line;
+ QScriptValue scriptValue(QObject *secondaryScope, bool *isUndefined);
+
+ class DeleteWatcher {
+ public:
+ inline DeleteWatcher(QDeclarativeQtScriptExpression *data);
+ inline ~DeleteWatcher();
+ inline bool wasDeleted() const;
+ private:
+ bool *m_wasDeleted;
+ bool m_wasDeletedStorage;
+ QDeclarativeQtScriptExpression *m_d;
+ };
+
+private:
+ void clearGuards();
+ QScriptValue eval(QObject *secondaryScope, bool *isUndefined);
+ void updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties);
+
+ bool trackChange;
QDeclarativeNotifierEndpoint *guardList;
int guardListLength;
+
+ QObject *guardObject;
+ int guardObjectNotifyIndex;
+ bool *deleted;
};
class QDeclarativeExpression;
class QString;
-class QDeclarativeExpressionPrivate : public QObjectPrivate
+class QDeclarativeExpressionPrivate : public QObjectPrivate, public QDeclarativeQtScriptExpression
{
Q_DECLARE_PUBLIC(QDeclarativeExpression)
public:
QDeclarativeExpressionPrivate();
- QDeclarativeExpressionPrivate(QDeclarativeExpressionData *);
~QDeclarativeExpressionPrivate();
void init(QDeclarativeContextData *, const QString &, QObject *);
void init(QDeclarativeContextData *, void *, QDeclarativeRefCount *, QObject *, const QString &, int);
- QDeclarativeExpressionData *data;
-
QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0);
QScriptValue scriptValue(QObject *secondaryScope = 0, bool *isUndefined = 0);
- QScriptValue eval(QObject *secondaryScope, bool *isUndefined = 0);
-
- void updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties);
- void clearGuards();
-
static QDeclarativeExpressionPrivate *get(QDeclarativeExpression *expr) {
return static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr));
}
@@ -172,8 +189,32 @@ public:
int, QScriptValue *);
static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QScriptProgram &,
QScriptValue *);
+
+ bool expressionFunctionValid:1;
+
+ QString url; // This is a QString for a reason. QUrls are slooooooow...
+ int line;
};
+QDeclarativeQtScriptExpression::DeleteWatcher::DeleteWatcher(QDeclarativeQtScriptExpression *data)
+: m_wasDeletedStorage(false), m_d(data)
+{
+ if (!m_d->deleted)
+ m_d->deleted = &m_wasDeletedStorage;
+ m_wasDeleted = m_d->deleted;
+}
+
+QDeclarativeQtScriptExpression::DeleteWatcher::~DeleteWatcher()
+{
+ if (false == *m_wasDeleted && m_wasDeleted == m_d->deleted)
+ m_d->deleted = 0;
+}
+
+bool QDeclarativeQtScriptExpression::DeleteWatcher::wasDeleted() const
+{
+ return *m_wasDeleted;
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVEEXPRESSION_P_H