Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeexpression.cpp
index 27979af..25d85f4 100644 (file)
@@ -1,8 +1,7 @@
 /****************************************************************************
 **
-** 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.
 **
@@ -35,6 +34,7 @@
 **
 **
 **
+**
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
@@ -70,16 +70,19 @@ bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e)
 
 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)
 {
 }
 
@@ -99,6 +102,7 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QS
     QDeclarativeAbstractExpression::setContext(ctxt);
     setScopeObject(me);
     expressionFunctionValid = false;
+    expressionFunctionRewritten = false;
 }
 
 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
@@ -110,23 +114,22 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Hand
     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);
@@ -149,12 +152,19 @@ QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObje
     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
@@ -197,12 +207,12 @@ QDeclarativeExpression::QDeclarativeExpression()
 /*!  \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);
 }
 
 /*!
@@ -241,7 +251,7 @@ QDeclarativeExpression::QDeclarativeExpression(const QDeclarativeScriptString &s
 
         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;
 
@@ -364,6 +374,7 @@ void QDeclarativeExpression::setExpression(const QString &expression)
     d->resetNotifyOnValueChanged();
     d->expression = expression;
     d->expressionFunctionValid = false;
+    d->expressionFunctionRewritten = false;
     qPersistentDispose(d->v8function);
     qPersistentDispose(d->v8qmlscope);
 }
@@ -396,12 +407,12 @@ void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> mes
 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)
@@ -415,12 +426,15 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F
 
     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;
@@ -429,7 +443,7 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F
 
     // 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;
@@ -471,115 +485,104 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F
         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;
@@ -693,14 +696,25 @@ int QDeclarativeExpression::lineNumber() const
 }
 
 /*!
+    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;
 }
 
 /*!