Move binding and expression classes to separate files
authorAaron Kennedy <aaron.kennedy@nokia.com>
Thu, 8 Mar 2012 13:25:50 +0000 (14:25 +0100)
committerQt by Nokia <qt-info@nokia.com>
Tue, 13 Mar 2012 04:13:50 +0000 (05:13 +0100)
Change-Id: Ia9c6996a606e140f31681ecd26d93b1b0fdedf02
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
15 files changed:
src/qml/qml/qml.pri
src/qml/qml/qqmlabstractbinding.cpp [new file with mode: 0644]
src/qml/qml/qqmlabstractbinding_p.h [new file with mode: 0644]
src/qml/qml/qqmlabstractexpression.cpp [new file with mode: 0644]
src/qml/qml/qqmlabstractexpression_p.h [new file with mode: 0644]
src/qml/qml/qqmlbinding.cpp
src/qml/qml/qqmlbinding_p.h
src/qml/qml/qqmlexpression.cpp
src/qml/qml/qqmlexpression_p.h
src/qml/qml/qqmljavascriptexpression.cpp [new file with mode: 0644]
src/qml/qml/qqmljavascriptexpression_p.h [new file with mode: 0644]
src/qml/qml/qqmlproperty.cpp
src/qml/qml/qqmlvaluetypeproxybinding.cpp [new file with mode: 0644]
src/qml/qml/qqmlvaluetypeproxybinding_p.h [new file with mode: 0644]
src/qml/qml/qqmlvme.cpp

index 0ce7c7e..763a260 100644 (file)
@@ -47,7 +47,11 @@ SOURCES += \
     $$PWD/qqmlimport.cpp \
     $$PWD/qqmllist.cpp \
     $$PWD/qqmllocale.cpp \
-    $$PWD/qlistmodelinterface.cpp
+    $$PWD/qlistmodelinterface.cpp \
+    $$PWD/qqmlabstractexpression.cpp \
+    $$PWD/qqmljavascriptexpression.cpp \
+    $$PWD/qqmlabstractbinding.cpp \
+    $$PWD/qqmlvaluetypeproxybinding.cpp \
 
 HEADERS += \
     $$PWD/qqmlglobal_p.h \
@@ -116,7 +120,11 @@ HEADERS += \
     $$PWD/qqmlscriptstring_p.h \
     $$PWD/qqmllocale_p.h \
     $$PWD/qlistmodelinterface_p.h \
-    $$PWD/qqmlcomponentattached_p.h
+    $$PWD/qqmlcomponentattached_p.h \
+    $$PWD/qqmlabstractexpression_p.h \
+    $$PWD/qqmljavascriptexpression_p.h \
+    $$PWD/qqmlabstractbinding_p.h \
+    $$PWD/qqmlvaluetypeproxybinding_p.h \
 
 include(parser/parser.pri)
 include(rewriter/rewriter.pri)
diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp
new file mode 100644 (file)
index 0000000..11e4ed2
--- /dev/null
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlabstractbinding_p.h"
+
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlvaluetypeproxybinding_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlAbstractBinding::QQmlAbstractBinding()
+: m_prevBinding(0), m_nextBinding(0)
+{
+}
+
+QQmlAbstractBinding::~QQmlAbstractBinding()
+{
+    Q_ASSERT(m_prevBinding == 0);
+    Q_ASSERT(*m_mePtr == 0);
+}
+
+/*!
+Destroy the binding.  Use this instead of calling delete.
+
+Bindings are free to implement their own memory management, so the delete operator is not
+necessarily safe.  The default implementation clears the binding, removes it from the object
+and calls delete.
+*/
+void QQmlAbstractBinding::destroy()
+{
+    removeFromObject();
+    clear();
+
+    delete this;
+}
+
+/*!
+Add this binding to \a object.
+
+This transfers ownership of the binding to the object, marks the object's property as
+being bound.
+
+However, it does not enable the binding itself or call update() on it.
+*/
+void QQmlAbstractBinding::addToObject()
+{
+    Q_ASSERT(!m_prevBinding);
+
+    QObject *obj = object();
+    Q_ASSERT(obj);
+
+    int index = propertyIndex();
+
+    QQmlData *data = QQmlData::get(obj, true);
+
+    if (index & 0xFF000000) {
+        // Value type
+
+        int coreIndex = index & 0xFFFFFF;
+
+        // Find the value type proxy (if there is one)
+        QQmlValueTypeProxyBinding *proxy = 0;
+        if (data->hasBindingBit(coreIndex)) {
+            QQmlAbstractBinding *b = data->bindings;
+            while (b && b->propertyIndex() != coreIndex)
+                b = b->m_nextBinding;
+            Q_ASSERT(b && b->bindingType() == QQmlAbstractBinding::ValueTypeProxy);
+            proxy = static_cast<QQmlValueTypeProxyBinding *>(b);
+        }
+
+        if (!proxy) {
+            proxy = new QQmlValueTypeProxyBinding(obj, coreIndex);
+
+            Q_ASSERT(proxy->propertyIndex() == coreIndex);
+            Q_ASSERT(proxy->object() == obj);
+
+            proxy->addToObject();
+        }
+
+        m_nextBinding = proxy->m_bindings;
+        if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
+        m_prevBinding = &proxy->m_bindings;
+        proxy->m_bindings = this;
+
+    } else {
+        m_nextBinding = data->bindings;
+        if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
+        m_prevBinding = &data->bindings;
+        data->bindings = this;
+
+        data->setBindingBit(obj, index);
+    }
+}
+
+/*!
+Remove the binding from the object.
+*/
+void QQmlAbstractBinding::removeFromObject()
+{
+    if (m_prevBinding) {
+        int index = propertyIndex();
+
+        *m_prevBinding = m_nextBinding;
+        if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding;
+        m_prevBinding = 0;
+        m_nextBinding = 0;
+
+        if (index & 0xFF000000) {
+            // Value type - we don't remove the proxy from the object.  It will sit their happily
+            // doing nothing until it is removed by a write, a binding change or it is reused
+            // to hold more sub-bindings.
+        } else if (QObject *obj = object()) {
+            QQmlData *data = QQmlData::get(obj, false);
+            if (data) data->clearBindingBit(index);
+        }
+    }
+}
+
+static void bindingDummyDeleter(QQmlAbstractBinding *)
+{
+}
+
+QQmlAbstractBinding::Pointer QQmlAbstractBinding::weakPointer()
+{
+    if (m_mePtr.value().isNull())
+        m_mePtr.value() = QSharedPointer<QQmlAbstractBinding>(this, bindingDummyDeleter);
+
+    return m_mePtr.value().toWeakRef();
+}
+
+void QQmlAbstractBinding::clear()
+{
+    if (!m_mePtr.isNull()) {
+        **m_mePtr = 0;
+        m_mePtr = 0;
+    }
+}
+
+void QQmlAbstractBinding::retargetBinding(QObject *, int)
+{
+    qFatal("QQmlAbstractBinding::retargetBinding() called on illegal binding.");
+}
+
+QString QQmlAbstractBinding::expression() const
+{
+    return QLatin1String("<Unknown>");
+}
+
+void QQmlAbstractBinding::setEnabled(bool enabled, QQmlPropertyPrivate::WriteFlags flags)
+{
+    if (enabled) update(flags);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h
new file mode 100644 (file)
index 0000000..d226e17
--- /dev/null
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLABSTRACTBINDING_P_H
+#define QQMLABSTRACTBINDING_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qsharedpointer.h>
+#include <private/qtqmlglobal_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qpointervaluepair_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding
+{
+public:
+    typedef QWeakPointer<QQmlAbstractBinding> Pointer;
+
+    QQmlAbstractBinding();
+
+    virtual void destroy();
+
+    virtual QString expression() const;
+
+    enum Type { PropertyBinding, ValueTypeProxy };
+    virtual Type bindingType() const { return PropertyBinding; }
+
+    // Should return the encoded property index for the binding.  Should return this value
+    // even if the binding is not enabled or added to an object.
+    // Encoding is:  coreIndex | (valueTypeIndex << 24)
+    virtual int propertyIndex() const = 0;
+    // Should return the object for the binding.  Should return this object even if the
+    // binding is not enabled or added to the object.
+    virtual QObject *object() const = 0;
+
+    void setEnabled(bool e) { setEnabled(e, QQmlPropertyPrivate::DontRemoveBinding); }
+    virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags) = 0;
+
+    void update() { update(QQmlPropertyPrivate::DontRemoveBinding); }
+    virtual void update(QQmlPropertyPrivate::WriteFlags) = 0;
+
+    void addToObject();
+    void removeFromObject();
+
+    static inline Pointer getPointer(QQmlAbstractBinding *p);
+
+protected:
+    virtual ~QQmlAbstractBinding();
+    void clear();
+
+    // Called by QQmlPropertyPrivate to "move" a binding to a different property.
+    // This is only used for alias properties, and only used by QQmlBinding not
+    // V8 or V4 bindings.  The default implementation qFatal()'s to ensure that the
+    // method is never called for V4 or V8 bindings.
+    virtual void retargetBinding(QObject *, int);
+private:
+    Pointer weakPointer();
+
+    friend class QQmlData;
+    friend class QQmlComponentPrivate;
+    friend class QQmlValueTypeProxyBinding;
+    friend class QQmlPropertyPrivate;
+    friend class QQmlVME;
+    friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>;
+
+    typedef QSharedPointer<QQmlAbstractBinding> SharedPointer;
+    // To save memory, we also store the rarely used weakPointer() instance in here
+    QPointerValuePair<QQmlAbstractBinding*, SharedPointer> m_mePtr;
+
+    QQmlAbstractBinding **m_prevBinding;
+    QQmlAbstractBinding  *m_nextBinding;
+};
+
+QQmlAbstractBinding::Pointer
+QQmlAbstractBinding::getPointer(QQmlAbstractBinding *p)
+{
+    return p ? p->weakPointer() : Pointer();
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLABSTRACTBINDING_P_H
diff --git a/src/qml/qml/qqmlabstractexpression.cpp b/src/qml/qml/qqmlabstractexpression.cpp
new file mode 100644 (file)
index 0000000..8319f7a
--- /dev/null
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlabstractexpression_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlAbstractExpression::QQmlAbstractExpression()
+: m_prevExpression(0), m_nextExpression(0)
+{
+}
+
+QQmlAbstractExpression::~QQmlAbstractExpression()
+{
+    if (m_prevExpression) {
+        *m_prevExpression = m_nextExpression;
+        if (m_nextExpression)
+            m_nextExpression->m_prevExpression = m_prevExpression;
+    }
+
+    if (m_context.isT2())
+        m_context.asT2()->_s = 0;
+}
+
+QQmlContextData *QQmlAbstractExpression::context() const
+{
+    if (m_context.isT1()) return m_context.asT1();
+    else return m_context.asT2()->_c;
+}
+
+void QQmlAbstractExpression::setContext(QQmlContextData *context)
+{
+    if (m_prevExpression) {
+        *m_prevExpression = m_nextExpression;
+        if (m_nextExpression)
+            m_nextExpression->m_prevExpression = m_prevExpression;
+        m_prevExpression = 0;
+        m_nextExpression = 0;
+    }
+
+    if (m_context.isT1()) m_context = context;
+    else m_context.asT2()->_c = context;
+
+    if (context) {
+        m_nextExpression = context->expressions;
+        if (m_nextExpression)
+            m_nextExpression->m_prevExpression = &m_nextExpression;
+        m_prevExpression = &context->expressions;
+        context->expressions = this;
+    }
+}
+
+void QQmlAbstractExpression::refresh()
+{
+}
+
+bool QQmlAbstractExpression::isValid() const
+{
+    return context() != 0;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/qqmlabstractexpression_p.h b/src/qml/qml/qqmlabstractexpression_p.h
new file mode 100644 (file)
index 0000000..fe2ee17
--- /dev/null
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLABSTRACTEXPRESSION_P_H
+#define QQMLABSTRACTEXPRESSION_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlcontext_p.h>
+#include <private/qfieldlist_p.h>
+#include <private/qflagpointer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlAbstractExpression
+{
+public:
+    QQmlAbstractExpression();
+    virtual ~QQmlAbstractExpression();
+
+    bool isValid() const;
+
+    QQmlContextData *context() const;
+    void setContext(QQmlContextData *);
+
+    virtual void refresh();
+
+    class DeleteWatcher {
+    public:
+        inline DeleteWatcher(QQmlAbstractExpression *);
+        inline ~DeleteWatcher();
+        inline bool wasDeleted() const;
+    private:
+        friend class QQmlAbstractExpression;
+        QQmlContextData *_c;
+        QQmlAbstractExpression **_w;
+        QQmlAbstractExpression *_s;
+    };
+
+private:
+    friend class QQmlContext;
+    friend class QQmlContextData;
+    friend class QQmlContextPrivate;
+
+    QBiPointer<QQmlContextData, DeleteWatcher> m_context;
+    QQmlAbstractExpression **m_prevExpression;
+    QQmlAbstractExpression  *m_nextExpression;
+};
+
+QQmlAbstractExpression::DeleteWatcher::DeleteWatcher(QQmlAbstractExpression *e)
+: _c(0), _w(0), _s(e)
+{
+    if (e->m_context.isT1()) {
+        _w = &_s;
+        _c = e->m_context.asT1();
+        e->m_context = this;
+    } else {
+        // Another watcher is already registered
+        _w = &e->m_context.asT2()->_s;
+    }
+}
+
+QQmlAbstractExpression::DeleteWatcher::~DeleteWatcher()
+{
+    Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_context.isT2()));
+    if (*_w && _s->m_context.asT2() == this)
+        _s->m_context = _c;
+}
+
+bool QQmlAbstractExpression::DeleteWatcher::wasDeleted() const
+{
+    return *_w == 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLABSTRACTEXPRESSION_P_H
index bb6eb3b..23f5abf 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
-QQmlAbstractBinding::QQmlAbstractBinding()
-: m_prevBinding(0), m_nextBinding(0)
-{
-}
-
-QQmlAbstractBinding::~QQmlAbstractBinding()
-{
-    Q_ASSERT(m_prevBinding == 0);
-    Q_ASSERT(*m_mePtr == 0);
-}
-
-/*!
-Destroy the binding.  Use this instead of calling delete.
-
-Bindings are free to implement their own memory management, so the delete operator is not 
-necessarily safe.  The default implementation clears the binding, removes it from the object
-and calls delete.
-*/
-void QQmlAbstractBinding::destroy()
-{
-    removeFromObject();
-    clear();
-
-    delete this;
-}
-
-/*!
-Add this binding to \a object.
-
-This transfers ownership of the binding to the object, marks the object's property as
-being bound.  
-
-However, it does not enable the binding itself or call update() on it.
-*/
-void QQmlAbstractBinding::addToObject()
-{
-    Q_ASSERT(!m_prevBinding);
-
-    QObject *obj = object();
-    Q_ASSERT(obj);
-
-    int index = propertyIndex();
-
-    QQmlData *data = QQmlData::get(obj, true);
-
-    if (index & 0xFF000000) {
-        // Value type
-
-        int coreIndex = index & 0xFFFFFF;
-
-        // Find the value type proxy (if there is one)
-        QQmlValueTypeProxyBinding *proxy = 0;
-        if (data->hasBindingBit(coreIndex)) {
-            QQmlAbstractBinding *b = data->bindings;
-            while (b && b->propertyIndex() != coreIndex)
-                b = b->m_nextBinding;
-            Q_ASSERT(b && b->bindingType() == QQmlAbstractBinding::ValueTypeProxy);
-            proxy = static_cast<QQmlValueTypeProxyBinding *>(b);
-        }
-
-        if (!proxy) {
-            proxy = new QQmlValueTypeProxyBinding(obj, coreIndex);
-
-            Q_ASSERT(proxy->propertyIndex() == coreIndex);
-            Q_ASSERT(proxy->object() == obj);
-
-            proxy->addToObject();
-        }
-
-        m_nextBinding = proxy->m_bindings;
-        if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
-        m_prevBinding = &proxy->m_bindings;
-        proxy->m_bindings = this;
-
-    } else {
-        m_nextBinding = data->bindings;
-        if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
-        m_prevBinding = &data->bindings;
-        data->bindings = this;
-
-        data->setBindingBit(obj, index);
-    }
-}
-
-/*!
-Remove the binding from the object.
-*/
-void QQmlAbstractBinding::removeFromObject()
-{
-    if (m_prevBinding) {
-        int index = propertyIndex();
-
-        *m_prevBinding = m_nextBinding;
-        if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding;
-        m_prevBinding = 0;
-        m_nextBinding = 0;
-
-        if (index & 0xFF000000) {
-            // Value type - we don't remove the proxy from the object.  It will sit their happily
-            // doing nothing until it is removed by a write, a binding change or it is reused
-            // to hold more sub-bindings.
-        } else if (QObject *obj = object()) {
-            QQmlData *data = QQmlData::get(obj, false);
-            if (data) data->clearBindingBit(index);
-        }
-    }
-}
-
-static void bindingDummyDeleter(QQmlAbstractBinding *)
-{
-}
-
-QQmlAbstractBinding::Pointer QQmlAbstractBinding::weakPointer()
-{
-    if (m_mePtr.value().isNull())
-        m_mePtr.value() = QSharedPointer<QQmlAbstractBinding>(this, bindingDummyDeleter);
-
-    return m_mePtr.value().toWeakRef();
-}
-
-void QQmlAbstractBinding::clear()
-{
-    if (!m_mePtr.isNull()) {
-        **m_mePtr = 0;
-        m_mePtr = 0;
-    }
-}
-
-void QQmlAbstractBinding::retargetBinding(QObject *, int)
-{
-    qFatal("QQmlAbstractBinding::retargetBinding() called on illegal binding.");
-}
-
-QString QQmlAbstractBinding::expression() const
-{
-    return QLatin1String("<Unknown>");
-}
-
-void QQmlAbstractBinding::setEnabled(bool enabled, QQmlPropertyPrivate::WriteFlags flags)
-{
-    if (enabled) update(flags);
-}
-
 QQmlBinding::Identifier QQmlBinding::Invalid = -1;
 
 void QQmlBindingPrivate::refresh()
@@ -457,96 +314,4 @@ void QQmlBinding::retargetBinding(QObject *t, int i)
     d->targetProperty = i;
 }
 
-QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index)
-: m_object(o), m_index(index), m_bindings(0)
-{
-}
-
-QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding()
-{
-    while (m_bindings) {
-        QQmlAbstractBinding *binding = m_bindings;
-        binding->setEnabled(false, 0);
-        binding->destroy();
-    }
-}
-
-void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
-{
-    if (e) {
-        QQmlAbstractBinding *bindings = m_bindings;
-        recursiveEnable(bindings, flags);
-    } else {
-        QQmlAbstractBinding *bindings = m_bindings;
-        recursiveDisable(bindings);
-    }
-}
-
-void QQmlValueTypeProxyBinding::recursiveEnable(QQmlAbstractBinding *b, QQmlPropertyPrivate::WriteFlags flags)
-{
-    if (!b)
-        return;
-
-    recursiveEnable(b->m_nextBinding, flags);
-
-    if (b)
-        b->setEnabled(true, flags);
-}
-
-void QQmlValueTypeProxyBinding::recursiveDisable(QQmlAbstractBinding *b)
-{
-    if (!b)
-        return;
-
-    recursiveDisable(b->m_nextBinding);
-
-    if (b)
-        b->setEnabled(false, 0);
-}
-
-void QQmlValueTypeProxyBinding::update(QQmlPropertyPrivate::WriteFlags)
-{
-}
-
-QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex)
-{
-    QQmlAbstractBinding *binding = m_bindings;
-    
-    while (binding && binding->propertyIndex() != propertyIndex) 
-        binding = binding->m_nextBinding;
-
-    return binding;
-}
-
-/*!
-Removes a collection of bindings, corresponding to the set bits in \a mask.
-*/
-void QQmlValueTypeProxyBinding::removeBindings(quint32 mask)
-{
-    QQmlAbstractBinding *binding = m_bindings;
-    while (binding) {
-        if (mask & (1 << (binding->propertyIndex() >> 24))) {
-            QQmlAbstractBinding *remove = binding;
-            binding = remove->m_nextBinding;
-            *remove->m_prevBinding = remove->m_nextBinding;
-            if (remove->m_nextBinding) remove->m_nextBinding->m_prevBinding = remove->m_prevBinding;
-            remove->m_prevBinding = 0;
-            remove->m_nextBinding = 0;
-            remove->destroy();
-        } else {
-            binding = binding->m_nextBinding;
-        }
-    }
-}
-
-int QQmlValueTypeProxyBinding::propertyIndex() const
-{
-    return m_index;
-}
-
-QObject *QQmlValueTypeProxyBinding::object() const
-{
-    return m_object;
-}
-
 QT_END_NAMESPACE
index 33823d7..785c96f 100644 (file)
 #include <QtCore/QMetaProperty>
 
 #include <private/qpointervaluepair_p.h>
+#include <private/qqmlabstractbinding_p.h>
 
 QT_BEGIN_NAMESPACE
 
-class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding
-{
-public:
-    typedef QWeakPointer<QQmlAbstractBinding> Pointer;
-
-    QQmlAbstractBinding();
-
-    virtual void destroy();
-
-    virtual QString expression() const;
-
-    enum Type { PropertyBinding, ValueTypeProxy };
-    virtual Type bindingType() const { return PropertyBinding; }
-
-    // Should return the encoded property index for the binding.  Should return this value
-    // even if the binding is not enabled or added to an object.
-    // Encoding is:  coreIndex | (valueTypeIndex << 24)
-    virtual int propertyIndex() const = 0;
-    // Should return the object for the binding.  Should return this object even if the
-    // binding is not enabled or added to the object.
-    virtual QObject *object() const = 0;
-
-    void setEnabled(bool e) { setEnabled(e, QQmlPropertyPrivate::DontRemoveBinding); }
-    virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags) = 0;
-
-    void update() { update(QQmlPropertyPrivate::DontRemoveBinding); }
-    virtual void update(QQmlPropertyPrivate::WriteFlags) = 0;
-
-    void addToObject();
-    void removeFromObject();
-
-    static inline Pointer getPointer(QQmlAbstractBinding *p);
-
-protected:
-    virtual ~QQmlAbstractBinding();
-    void clear();
-
-    // Called by QQmlPropertyPrivate to "move" a binding to a different property.
-    // This is only used for alias properties, and only used by QQmlBinding not
-    // V8 or V4 bindings.  The default implementation qFatal()'s to ensure that the
-    // method is never called for V4 or V8 bindings.
-    virtual void retargetBinding(QObject *, int);
-private:
-    Pointer weakPointer();
-
-    friend class QQmlData;
-    friend class QQmlComponentPrivate;
-    friend class QQmlValueTypeProxyBinding;
-    friend class QQmlPropertyPrivate;
-    friend class QQmlVME;
-    friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>;
-
-    typedef QSharedPointer<QQmlAbstractBinding> SharedPointer;
-    // To save memory, we also store the rarely used weakPointer() instance in here
-    QPointerValuePair<QQmlAbstractBinding*, SharedPointer> m_mePtr;
-
-    QQmlAbstractBinding **m_prevBinding;
-    QQmlAbstractBinding  *m_nextBinding;
-};
-
-class QQmlValueTypeProxyBinding : public QQmlAbstractBinding
-{
-public:
-    QQmlValueTypeProxyBinding(QObject *o, int coreIndex);
-
-    virtual Type bindingType() const { return ValueTypeProxy; }
-
-    virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags);
-    virtual void update(QQmlPropertyPrivate::WriteFlags);
-    virtual int propertyIndex() const;
-    virtual QObject *object() const;
-
-    QQmlAbstractBinding *binding(int propertyIndex);
-
-    void removeBindings(quint32 mask);
-
-protected:
-    ~QQmlValueTypeProxyBinding();
-
-private:
-    void recursiveEnable(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags);
-    void recursiveDisable(QQmlAbstractBinding *);
-
-    friend class QQmlAbstractBinding;
-    QObject *m_object;
-    int m_index;
-    QQmlAbstractBinding *m_bindings;
-};
-
 class QQmlContext;
 class QQmlBindingPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlExpression,
-                                                         public QQmlAbstractBinding
+class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlExpression, public QQmlAbstractBinding
 {
 Q_OBJECT
 public:
@@ -206,12 +117,6 @@ private:
 
 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlBinding::EvaluateFlags)
 
-QQmlAbstractBinding::Pointer
-QQmlAbstractBinding::getPointer(QQmlAbstractBinding *p)
-{
-    return p ? p->weakPointer() : Pointer();
-}
-
 QT_END_NAMESPACE
 
 Q_DECLARE_METATYPE(QQmlBinding*)
index ecdbf21..cefde1d 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
-bool QQmlDelayedError::addError(QQmlEnginePrivate *e)
-{
-    if (!e) return false;
-
-    if (e->inProgressCreations == 0) return false; // Not in construction
-
-    if (prevError) return true; // Already in error chain
-
-    prevError = &e->erroredBindings;
-    nextError = e->erroredBindings;
-    e->erroredBindings = this;
-    if (nextError) nextError->prevError = &nextError;
-
-    return true;
-}
-
-QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v)
-: m_vtable(v)
-{
-}
-
-QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
-{
-    clearGuards();
-}
-
 static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = {
     QQmlExpressionPrivate::expressionIdentifier,
     QQmlExpressionPrivate::expressionChanged
@@ -514,192 +488,6 @@ void QQmlExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message,
     error.setDescription(qDescription);
 }
 
-void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
-{
-    activeGuards.setFlagValue(v);
-    if (!v) clearGuards();
-}
-
-void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
-{
-    clearGuards();
-}
-
-v8::Local<v8::Value>
-QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
-                                           v8::Handle<v8::Function> function, bool *isUndefined)
-{
-    Q_ASSERT(context && context->engine);
-
-    if (function.IsEmpty() || function->IsUndefined()) {
-        if (isUndefined) *isUndefined = true;
-        return v8::Local<v8::Value>();
-    }
-
-    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
-
-    Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
-    GuardCapture capture(context->engine, this);
-
-    QQmlEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
-    ep->propertyCapture = notifyOnValueChanged()?&capture:0;
-
-
-    if (notifyOnValueChanged())
-        capture.guards.copyAndClearPrepend(activeGuards);
-
-    QQmlContextData *lastSharedContext = 0;
-    QObject *lastSharedScope = 0;
-
-    bool sharedContext = useSharedContext();
-
-    // All code that follows must check with watcher before it accesses data members 
-    // incase we have been deleted.
-    DeleteWatcher watcher(this);
-
-    if (sharedContext) {
-        lastSharedContext = ep->sharedContext;
-        lastSharedScope = ep->sharedScope;
-        ep->sharedContext = context;
-        ep->sharedScope = scopeObject();
-    }
-
-    v8::Local<v8::Value> result;
-    {
-        v8::TryCatch try_catch;
-        v8::Handle<v8::Object> This = ep->v8engine()->global();
-        if (scopeObject() && requiresThisObject()) {
-            v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
-            if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
-        }
-
-        result = function->Call(This, 0, 0);
-
-        if (isUndefined)
-            *isUndefined = try_catch.HasCaught() || result->IsUndefined();
-
-        if (watcher.wasDeleted()) {
-        } else if (try_catch.HasCaught()) {
-            v8::Context::Scope scope(ep->v8engine()->context());
-            v8::Local<v8::Message> message = try_catch.Message();
-            if (!message.IsEmpty()) {
-                QQmlExpressionPrivate::exceptionToError(message, delayedError()->error);
-            } else {
-                if (hasDelayedError()) delayedError()->error = QQmlError();
-            }
-        } else {
-            if (hasDelayedError()) delayedError()->error = QQmlError();
-        }
-    }
-
-    if (sharedContext) {
-        ep->sharedContext = lastSharedContext;
-        ep->sharedScope = lastSharedScope;
-    }
-
-    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;
-    }
-
-    while (Guard *g = capture.guards.takeFirst())
-        g->Delete();
-
-    ep->propertyCapture = lastPropertyCapture;
-
-    return result;
-}
-
-void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n)
-{
-    if (expression) {
-
-        // Try and find a matching guard
-        while (!guards.isEmpty() && !guards.first()->isConnected(n))
-            guards.takeFirst()->Delete();
-
-        Guard *g = 0;
-        if (!guards.isEmpty()) {
-            g = guards.takeFirst();
-            g->cancelNotify();
-            Q_ASSERT(g->isConnected(n));
-        } else {
-            g = Guard::New(expression, engine);
-            g->connect(n);
-        }
-
-        expression->activeGuards.prepend(g);
-    }
-}
-
-void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
-{
-    if (expression) {
-        if (n == -1) {
-            if (!errorString) {
-                errorString = new QStringList;
-                QString preamble = QLatin1String("QQmlExpression: Expression ") +
-                                   expression->m_vtable->expressionIdentifier(expression) +
-                                   QLatin1String(" depends on non-NOTIFYable properties:");
-                errorString->append(preamble);
-            }
-
-            const QMetaObject *metaObj = o->metaObject();
-            QMetaProperty metaProp = metaObj->property(c);
-
-            QString error = QLatin1String("    ") +
-                            QString::fromUtf8(metaObj->className()) +
-                            QLatin1String("::") +
-                            QString::fromUtf8(metaProp.name());
-            errorString->append(error);
-        } else {
-
-            // 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 {
-                g = Guard::New(expression, engine);
-                g->connect(o, n);
-            }
-
-            expression->activeGuards.prepend(g);
-        }
-    }
-}
-
-void QQmlJavaScriptExpression::clearError()
-{
-    if (m_vtable.hasValue()) {
-        m_vtable.value().error = QQmlError();
-        m_vtable.value().removeError();
-    }
-}
-
-QQmlError QQmlJavaScriptExpression::error() const
-{
-    if (m_vtable.hasValue()) return m_vtable.constValue()->error;
-    else return QQmlError();
-}
-
-QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
-{
-    return &m_vtable.value();
-}
-
-void QQmlJavaScriptExpression::clearGuards()
-{
-    while (Guard *g = activeGuards.takeFirst())
-        g->Delete();
-}
-
 // Must be called with a valid handle scope
 v8::Local<v8::Value> QQmlExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
 {
@@ -923,60 +711,6 @@ QString QQmlExpressionPrivate::expressionIdentifier(QQmlJavaScriptExpression *e)
     return QLatin1String("\"") + This->expression + QLatin1String("\"");
 }
 
-QQmlAbstractExpression::QQmlAbstractExpression()
-: m_prevExpression(0), m_nextExpression(0)
-{
-}
-
-QQmlAbstractExpression::~QQmlAbstractExpression()
-{
-    if (m_prevExpression) {
-        *m_prevExpression = m_nextExpression;
-        if (m_nextExpression) 
-            m_nextExpression->m_prevExpression = m_prevExpression;
-    }
-
-    if (m_context.isT2())
-        m_context.asT2()->_s = 0;
-}
-
-QQmlContextData *QQmlAbstractExpression::context() const
-{
-    if (m_context.isT1()) return m_context.asT1();
-    else return m_context.asT2()->_c;
-}
-
-void QQmlAbstractExpression::setContext(QQmlContextData *context)
-{
-    if (m_prevExpression) {
-        *m_prevExpression = m_nextExpression;
-        if (m_nextExpression) 
-            m_nextExpression->m_prevExpression = m_prevExpression;
-        m_prevExpression = 0;
-        m_nextExpression = 0;
-    }
-
-    if (m_context.isT1()) m_context = context;
-    else m_context.asT2()->_c = context;
-
-    if (context) {
-        m_nextExpression = context->expressions;
-        if (m_nextExpression) 
-            m_nextExpression->m_prevExpression = &m_nextExpression;
-        m_prevExpression = &context->expressions;
-        context->expressions = this;
-    }
-}
-
-void QQmlAbstractExpression::refresh()
-{
-}
-
-bool QQmlAbstractExpression::isValid() const
-{
-    return context() != 0;
-}
-
 QT_END_NAMESPACE
 
 #include <moc_qqmlexpression.cpp>
index deca29a..3b335ba 100644 (file)
 #include "qqmlexpression.h"
 
 #include <private/qv8engine_p.h>
+#include <private/qqmlguard_p.h>
+#include <private/qqmlengine_p.h>
 #include <private/qfieldlist_p.h>
 #include <private/qflagpointer_p.h>
 #include <private/qdeletewatcher_p.h>
-#include <private/qqmlguard_p.h>
 #include <private/qpointervaluepair_p.h>
-#include <private/qqmlengine_p.h>
+#include <private/qqmlabstractexpression_p.h>
+#include <private/qqmljavascriptexpression_p.h>
 
 QT_BEGIN_NAMESPACE
 
-class QQmlAbstractExpression
-{
-public:
-    QQmlAbstractExpression();
-    virtual ~QQmlAbstractExpression();
-
-    bool isValid() const;
-
-    QQmlContextData *context() const;
-    void setContext(QQmlContextData *);
-
-    virtual void refresh();
-
-    class DeleteWatcher {
-    public:
-        inline DeleteWatcher(QQmlAbstractExpression *);
-        inline ~DeleteWatcher();
-        inline bool wasDeleted() const;
-    private:
-        friend class QQmlAbstractExpression;
-        QQmlContextData *_c;
-        QQmlAbstractExpression **_w;
-        QQmlAbstractExpression *_s;
-    };
-
-private:
-    friend class QQmlContext;
-    friend class QQmlContextData;
-    friend class QQmlContextPrivate;
-
-    QBiPointer<QQmlContextData, DeleteWatcher> m_context;
-    QQmlAbstractExpression **m_prevExpression;
-    QQmlAbstractExpression  *m_nextExpression;
-};
-
-class QQmlDelayedError 
-{
-public:
-    inline QQmlDelayedError() : nextError(0), prevError(0) {}
-    inline ~QQmlDelayedError() { removeError(); }
-
-    QQmlError error;
-
-    bool addError(QQmlEnginePrivate *);
-
-    inline void removeError() {
-        if (!prevError) return;
-        if (nextError) nextError->prevError = prevError;
-        *prevError = nextError;
-        nextError = 0;
-        prevError = 0;
-    }
-
-private:
-    QQmlDelayedError  *nextError;
-    QQmlDelayedError **prevError;
-};
-
-class QQmlJavaScriptExpression
-{
-public:
-    // Although this looks crazy, we implement our own "vtable" here, rather than relying on
-    // C++ virtuals, to save memory.  By doing it ourselves, we can overload the storage
-    // location that is use for the vtable to also store the rarely used delayed error.
-    // If we use C++ virtuals, we can't do this and it consts us an extra sizeof(void *) in
-    // memory for every expression.
-    struct VTable {
-        QString (*expressionIdentifier)(QQmlJavaScriptExpression *);
-        void (*expressionChanged)(QQmlJavaScriptExpression *);
-    };
-
-    QQmlJavaScriptExpression(VTable *vtable);
-
-    v8::Local<v8::Value> evaluate(QQmlContextData *, v8::Handle<v8::Function>,
-                                  bool *isUndefined);
-
-    inline bool requiresThisObject() const;
-    inline void setRequiresThisObject(bool v);
-    inline bool useSharedContext() const;
-    inline void setUseSharedContext(bool v);
-    inline bool notifyOnValueChanged() const;
-
-    void setNotifyOnValueChanged(bool v);
-    void resetNotifyOnValueChanged();
-
-    inline QObject *scopeObject() const;
-    inline void setScopeObject(QObject *v);
-
-    class DeleteWatcher {
-    public:
-        inline DeleteWatcher(QQmlJavaScriptExpression *);
-        inline ~DeleteWatcher();
-        inline bool wasDeleted() const;
-    private:
-        friend class QQmlJavaScriptExpression;
-        QObject *_c;
-        QQmlJavaScriptExpression **_w;
-        QQmlJavaScriptExpression *_s;
-    };
-
-    inline bool hasError() const;
-    inline bool hasDelayedError() const;
-    QQmlError error() const;
-    void clearError();
-    QQmlDelayedError *delayedError();
-
-protected:
-    ~QQmlJavaScriptExpression();
-
-private:
-    typedef QQmlJavaScriptExpressionGuard Guard;
-    friend class QQmlJavaScriptExpressionGuard;
-
-    struct GuardCapture : public QQmlEnginePrivate::PropertyCapture {
-        GuardCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e)
-        : engine(engine), expression(e), errorString(0) { }
-
-        ~GuardCapture()  {
-            Q_ASSERT(guards.isEmpty());
-            Q_ASSERT(errorString == 0);
-        }
-
-        virtual void captureProperty(QQmlNotifier *);
-        virtual void captureProperty(QObject *, int, int);
-
-        QQmlEngine *engine;
-        QQmlJavaScriptExpression *expression;
-        QFieldList<Guard, &Guard::next> guards;
-        QStringList *errorString;
-    };
-
-    QPointerValuePair<VTable, QQmlDelayedError> m_vtable;
-
-    // We store some flag bits in the following flag pointers.
-    //    m_scopeObject:flag1 - requiresThisObject
-    //    activeGuards:flag1  - notifyOnValueChanged
-    //    activeGuards:flag2  - useSharedContext
-    QBiPointer<QObject, DeleteWatcher> m_scopeObject;
-    QForwardFieldList<Guard, &Guard::next> activeGuards;
-
-    void clearGuards();
-};
-
 class QQmlExpression;
 class QString;
-class Q_QML_PRIVATE_EXPORT QQmlExpressionPrivate : public QObjectPrivate, public QQmlJavaScriptExpression, public QQmlAbstractExpression
+class Q_QML_PRIVATE_EXPORT QQmlExpressionPrivate : public QObjectPrivate,
+                                                   public QQmlJavaScriptExpression,
+                                                   public QQmlAbstractExpression
 {
     Q_DECLARE_PUBLIC(QQmlExpression)
 public:
@@ -267,103 +128,6 @@ public:
     QQmlRefCount *dataRef;
 };
 
-QQmlAbstractExpression::DeleteWatcher::DeleteWatcher(QQmlAbstractExpression *e)
-: _c(0), _w(0), _s(e)
-{
-    if (e->m_context.isT1()) {
-        _w = &_s;
-        _c = e->m_context.asT1();
-        e->m_context = this;
-    } else {
-        // Another watcher is already registered
-        _w = &e->m_context.asT2()->_s;
-    }
-}
-
-QQmlAbstractExpression::DeleteWatcher::~DeleteWatcher()
-{
-    Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_context.isT2()));
-    if (*_w && _s->m_context.asT2() == this)
-        _s->m_context = _c;
-}
-
-bool QQmlAbstractExpression::DeleteWatcher::wasDeleted() const
-{
-    return *_w == 0;
-}
-
-QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e)
-: _c(0), _w(0), _s(e)
-{
-    if (e->m_scopeObject.isT1()) {
-        _w = &_s;
-        _c = e->m_scopeObject.asT1();
-        e->m_scopeObject = this;
-    } else {
-        // Another watcher is already registered
-        _w = &e->m_scopeObject.asT2()->_s;
-    }
-}
-
-QQmlJavaScriptExpression::DeleteWatcher::~DeleteWatcher()
-{
-    Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_scopeObject.isT2()));
-    if (*_w && _s->m_scopeObject.asT2() == this)
-        _s->m_scopeObject = _c;
-}
-
-bool QQmlJavaScriptExpression::DeleteWatcher::wasDeleted() const
-{
-    return *_w == 0;
-}
-
-bool QQmlJavaScriptExpression::requiresThisObject() const 
-{ 
-    return m_scopeObject.flag();
-}
-
-void QQmlJavaScriptExpression::setRequiresThisObject(bool v) 
-{ 
-    m_scopeObject.setFlagValue(v);
-}
-
-bool QQmlJavaScriptExpression::useSharedContext() const 
-{ 
-    return activeGuards.flag2();
-}
-
-void QQmlJavaScriptExpression::setUseSharedContext(bool v) 
-{ 
-    activeGuards.setFlag2Value(v);
-}
-
-bool QQmlJavaScriptExpression::notifyOnValueChanged() const 
-{ 
-    return activeGuards.flag();
-}
-
-QObject *QQmlJavaScriptExpression::scopeObject() const 
-{ 
-    if (m_scopeObject.isT1()) return m_scopeObject.asT1();
-    else return m_scopeObject.asT2()->_c;
-}
-
-void QQmlJavaScriptExpression::setScopeObject(QObject *v) 
-{ 
-    if (m_scopeObject.isT1()) m_scopeObject = v;
-    else m_scopeObject.asT2()->_c = v;
-}
-
-bool QQmlJavaScriptExpression::hasError() const
-{
-    return m_vtable.hasValue() && m_vtable.constValue()->error.isValid();
-}
-
-bool QQmlJavaScriptExpression::hasDelayedError() const
-{
-    return m_vtable.hasValue();
-}
-
 QQmlExpressionPrivate *QQmlExpressionPrivate::get(QQmlExpression *expr)
 {
     return static_cast<QQmlExpressionPrivate *>(QObjectPrivate::get(expr));
@@ -374,32 +138,6 @@ QQmlExpression *QQmlExpressionPrivate::get(QQmlExpressionPrivate *expr)
     return expr->q_func();
 }
 
-QQmlJavaScriptExpressionGuard::QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *e)
-: expression(e), next(0)
-{ 
-    callback = &endpointCallback;
-}
-
-void QQmlJavaScriptExpressionGuard::endpointCallback(QQmlNotifierEndpoint *e)
-{
-    QQmlJavaScriptExpression *expression =
-        static_cast<QQmlJavaScriptExpressionGuard *>(e)->expression;
-
-    expression->m_vtable->expressionChanged(expression);
-}
-
-QQmlJavaScriptExpressionGuard *
-QQmlJavaScriptExpressionGuard::New(QQmlJavaScriptExpression *e,
-                                           QQmlEngine *engine)
-{
-    Q_ASSERT(e);
-    return QQmlEnginePrivate::get(engine)->jsExpressionGuardPool.New(e);
-}
-
-void QQmlJavaScriptExpressionGuard::Delete()
-{
-    QRecyclePool<QQmlJavaScriptExpressionGuard>::Delete(this);
-}
 
 QT_END_NAMESPACE
 
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
new file mode 100644 (file)
index 0000000..4186b5b
--- /dev/null
@@ -0,0 +1,260 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmljavascriptexpression_p.h"
+
+#include <private/qqmlexpression_p.h>
+
+QT_BEGIN_NAMESPACE
+
+bool QQmlDelayedError::addError(QQmlEnginePrivate *e)
+{
+    if (!e) return false;
+
+    if (e->inProgressCreations == 0) return false; // Not in construction
+
+    if (prevError) return true; // Already in error chain
+
+    prevError = &e->erroredBindings;
+    nextError = e->erroredBindings;
+    e->erroredBindings = this;
+    if (nextError) nextError->prevError = &nextError;
+
+    return true;
+}
+
+QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v)
+: m_vtable(v)
+{
+}
+
+QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
+{
+    clearGuards();
+}
+
+void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
+{
+    activeGuards.setFlagValue(v);
+    if (!v) clearGuards();
+}
+
+void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
+{
+    clearGuards();
+}
+
+v8::Local<v8::Value>
+QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
+                                   v8::Handle<v8::Function> function, bool *isUndefined)
+{
+    Q_ASSERT(context && context->engine);
+
+    if (function.IsEmpty() || function->IsUndefined()) {
+        if (isUndefined) *isUndefined = true;
+        return v8::Local<v8::Value>();
+    }
+
+    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
+
+    Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
+    GuardCapture capture(context->engine, this);
+
+    QQmlEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
+    ep->propertyCapture = notifyOnValueChanged()?&capture:0;
+
+
+    if (notifyOnValueChanged())
+        capture.guards.copyAndClearPrepend(activeGuards);
+
+    QQmlContextData *lastSharedContext = 0;
+    QObject *lastSharedScope = 0;
+
+    bool sharedContext = useSharedContext();
+
+    // All code that follows must check with watcher before it accesses data members
+    // incase we have been deleted.
+    DeleteWatcher watcher(this);
+
+    if (sharedContext) {
+        lastSharedContext = ep->sharedContext;
+        lastSharedScope = ep->sharedScope;
+        ep->sharedContext = context;
+        ep->sharedScope = scopeObject();
+    }
+
+    v8::Local<v8::Value> result;
+    {
+        v8::TryCatch try_catch;
+        v8::Handle<v8::Object> This = ep->v8engine()->global();
+        if (scopeObject() && requiresThisObject()) {
+            v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
+            if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
+        }
+
+        result = function->Call(This, 0, 0);
+
+        if (isUndefined)
+            *isUndefined = try_catch.HasCaught() || result->IsUndefined();
+
+        if (watcher.wasDeleted()) {
+        } else if (try_catch.HasCaught()) {
+            v8::Context::Scope scope(ep->v8engine()->context());
+            v8::Local<v8::Message> message = try_catch.Message();
+            if (!message.IsEmpty()) {
+                QQmlExpressionPrivate::exceptionToError(message, delayedError()->error);
+            } else {
+                if (hasDelayedError()) delayedError()->error = QQmlError();
+            }
+        } else {
+            if (hasDelayedError()) delayedError()->error = QQmlError();
+        }
+    }
+
+    if (sharedContext) {
+        ep->sharedContext = lastSharedContext;
+        ep->sharedScope = lastSharedScope;
+    }
+
+    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;
+    }
+
+    while (Guard *g = capture.guards.takeFirst())
+        g->Delete();
+
+    ep->propertyCapture = lastPropertyCapture;
+
+    return result;
+}
+
+void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n)
+{
+    if (expression) {
+
+        // Try and find a matching guard
+        while (!guards.isEmpty() && !guards.first()->isConnected(n))
+            guards.takeFirst()->Delete();
+
+        Guard *g = 0;
+        if (!guards.isEmpty()) {
+            g = guards.takeFirst();
+            g->cancelNotify();
+            Q_ASSERT(g->isConnected(n));
+        } else {
+            g = Guard::New(expression, engine);
+            g->connect(n);
+        }
+
+        expression->activeGuards.prepend(g);
+    }
+}
+
+void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
+{
+    if (expression) {
+        if (n == -1) {
+            if (!errorString) {
+                errorString = new QStringList;
+                QString preamble = QLatin1String("QQmlExpression: Expression ") +
+                                   expression->m_vtable->expressionIdentifier(expression) +
+                                   QLatin1String(" depends on non-NOTIFYable properties:");
+                errorString->append(preamble);
+            }
+
+            const QMetaObject *metaObj = o->metaObject();
+            QMetaProperty metaProp = metaObj->property(c);
+
+            QString error = QLatin1String("    ") +
+                            QString::fromUtf8(metaObj->className()) +
+                            QLatin1String("::") +
+                            QString::fromUtf8(metaProp.name());
+            errorString->append(error);
+        } else {
+
+            // 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 {
+                g = Guard::New(expression, engine);
+                g->connect(o, n);
+            }
+
+            expression->activeGuards.prepend(g);
+        }
+    }
+}
+
+void QQmlJavaScriptExpression::clearError()
+{
+    if (m_vtable.hasValue()) {
+        m_vtable.value().error = QQmlError();
+        m_vtable.value().removeError();
+    }
+}
+
+QQmlError QQmlJavaScriptExpression::error() const
+{
+    if (m_vtable.hasValue()) return m_vtable.constValue()->error;
+    else return QQmlError();
+}
+
+QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
+{
+    return &m_vtable.value();
+}
+
+void QQmlJavaScriptExpression::clearGuards()
+{
+    while (Guard *g = activeGuards.takeFirst())
+        g->Delete();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
new file mode 100644 (file)
index 0000000..1da1e12
--- /dev/null
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJAVASCRIPTEXPRESSION_P_H
+#define QQMLJAVASCRIPTEXPRESSION_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv8_p.h>
+#include <QtCore/qglobal.h>
+#include <QtQml/qqmlerror.h>
+#include <private/qqmlengine_p.h>
+#include <private/qpointervaluepair_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlDelayedError
+{
+public:
+    inline QQmlDelayedError() : nextError(0), prevError(0) {}
+    inline ~QQmlDelayedError() { removeError(); }
+
+    QQmlError error;
+
+    bool addError(QQmlEnginePrivate *);
+
+    inline void removeError() {
+        if (!prevError) return;
+        if (nextError) nextError->prevError = prevError;
+        *prevError = nextError;
+        nextError = 0;
+        prevError = 0;
+    }
+
+private:
+    QQmlDelayedError  *nextError;
+    QQmlDelayedError **prevError;
+};
+
+class QQmlJavaScriptExpression
+{
+public:
+    // Although this looks crazy, we implement our own "vtable" here, rather than relying on
+    // C++ virtuals, to save memory.  By doing it ourselves, we can overload the storage
+    // location that is use for the vtable to also store the rarely used delayed error.
+    // If we use C++ virtuals, we can't do this and it consts us an extra sizeof(void *) in
+    // memory for every expression.
+    struct VTable {
+        QString (*expressionIdentifier)(QQmlJavaScriptExpression *);
+        void (*expressionChanged)(QQmlJavaScriptExpression *);
+    };
+
+    QQmlJavaScriptExpression(VTable *vtable);
+
+    v8::Local<v8::Value> evaluate(QQmlContextData *, v8::Handle<v8::Function>,
+                                  bool *isUndefined);
+
+    inline bool requiresThisObject() const;
+    inline void setRequiresThisObject(bool v);
+    inline bool useSharedContext() const;
+    inline void setUseSharedContext(bool v);
+    inline bool notifyOnValueChanged() const;
+
+    void setNotifyOnValueChanged(bool v);
+    void resetNotifyOnValueChanged();
+
+    inline QObject *scopeObject() const;
+    inline void setScopeObject(QObject *v);
+
+    class DeleteWatcher {
+    public:
+        inline DeleteWatcher(QQmlJavaScriptExpression *);
+        inline ~DeleteWatcher();
+        inline bool wasDeleted() const;
+    private:
+        friend class QQmlJavaScriptExpression;
+        QObject *_c;
+        QQmlJavaScriptExpression **_w;
+        QQmlJavaScriptExpression *_s;
+    };
+
+    inline bool hasError() const;
+    inline bool hasDelayedError() const;
+    QQmlError error() const;
+    void clearError();
+    QQmlDelayedError *delayedError();
+
+protected:
+    ~QQmlJavaScriptExpression();
+
+private:
+    typedef QQmlJavaScriptExpressionGuard Guard;
+    friend class QQmlJavaScriptExpressionGuard;
+
+    struct GuardCapture : public QQmlEnginePrivate::PropertyCapture {
+        GuardCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e)
+        : engine(engine), expression(e), errorString(0) { }
+
+        ~GuardCapture()  {
+            Q_ASSERT(guards.isEmpty());
+            Q_ASSERT(errorString == 0);
+        }
+
+        virtual void captureProperty(QQmlNotifier *);
+        virtual void captureProperty(QObject *, int, int);
+
+        QQmlEngine *engine;
+        QQmlJavaScriptExpression *expression;
+        QFieldList<Guard, &Guard::next> guards;
+        QStringList *errorString;
+    };
+
+    QPointerValuePair<VTable, QQmlDelayedError> m_vtable;
+
+    // We store some flag bits in the following flag pointers.
+    //    m_scopeObject:flag1 - requiresThisObject
+    //    activeGuards:flag1  - notifyOnValueChanged
+    //    activeGuards:flag2  - useSharedContext
+    QBiPointer<QObject, DeleteWatcher> m_scopeObject;
+    QForwardFieldList<Guard, &Guard::next> activeGuards;
+
+    void clearGuards();
+};
+
+QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e)
+: _c(0), _w(0), _s(e)
+{
+    if (e->m_scopeObject.isT1()) {
+        _w = &_s;
+        _c = e->m_scopeObject.asT1();
+        e->m_scopeObject = this;
+    } else {
+        // Another watcher is already registered
+        _w = &e->m_scopeObject.asT2()->_s;
+    }
+}
+
+QQmlJavaScriptExpression::DeleteWatcher::~DeleteWatcher()
+{
+    Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_scopeObject.isT2()));
+    if (*_w && _s->m_scopeObject.asT2() == this)
+        _s->m_scopeObject = _c;
+}
+
+bool QQmlJavaScriptExpression::DeleteWatcher::wasDeleted() const
+{
+    return *_w == 0;
+}
+
+bool QQmlJavaScriptExpression::requiresThisObject() const
+{
+    return m_scopeObject.flag();
+}
+
+void QQmlJavaScriptExpression::setRequiresThisObject(bool v)
+{
+    m_scopeObject.setFlagValue(v);
+}
+
+bool QQmlJavaScriptExpression::useSharedContext() const
+{
+    return activeGuards.flag2();
+}
+
+void QQmlJavaScriptExpression::setUseSharedContext(bool v)
+{
+    activeGuards.setFlag2Value(v);
+}
+
+bool QQmlJavaScriptExpression::notifyOnValueChanged() const
+{
+    return activeGuards.flag();
+}
+
+QObject *QQmlJavaScriptExpression::scopeObject() const
+{
+    if (m_scopeObject.isT1()) return m_scopeObject.asT1();
+    else return m_scopeObject.asT2()->_c;
+}
+
+void QQmlJavaScriptExpression::setScopeObject(QObject *v)
+{
+    if (m_scopeObject.isT1()) m_scopeObject = v;
+    else m_scopeObject.asT2()->_c = v;
+}
+
+bool QQmlJavaScriptExpression::hasError() const
+{
+    return m_vtable.hasValue() && m_vtable.constValue()->error.isValid();
+}
+
+bool QQmlJavaScriptExpression::hasDelayedError() const
+{
+    return m_vtable.hasValue();
+}
+
+QQmlJavaScriptExpressionGuard::QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *e)
+: expression(e), next(0)
+{
+    callback = &endpointCallback;
+}
+
+void QQmlJavaScriptExpressionGuard::endpointCallback(QQmlNotifierEndpoint *e)
+{
+    QQmlJavaScriptExpression *expression =
+        static_cast<QQmlJavaScriptExpressionGuard *>(e)->expression;
+
+    expression->m_vtable->expressionChanged(expression);
+}
+
+QQmlJavaScriptExpressionGuard *
+QQmlJavaScriptExpressionGuard::New(QQmlJavaScriptExpression *e,
+                                           QQmlEngine *engine)
+{
+    Q_ASSERT(e);
+    return QQmlEnginePrivate::get(engine)->jsExpressionGuardPool.New(e);
+}
+
+void QQmlJavaScriptExpressionGuard::Delete()
+{
+    QRecyclePool<QQmlJavaScriptExpressionGuard>::Delete(this);
+}
+
+
+QT_END_NAMESPACE
+
+#endif // QQMLJAVASCRIPTEXPRESSION_P_H
index 6321592..8d5d83e 100644 (file)
@@ -55,6 +55,7 @@
 #include "qqmlcompiler_p.h"
 #include "qqmlvmemetaobject_p.h"
 #include "qqmlexpression_p.h"
+#include "qqmlvaluetypeproxybinding_p.h"
 
 #include <QStringList>
 #include <QtCore/qdebug.h>
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
new file mode 100644 (file)
index 0000000..2cc15a5
--- /dev/null
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlvaluetypeproxybinding_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index)
+: m_object(o), m_index(index), m_bindings(0)
+{
+}
+
+QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding()
+{
+    while (m_bindings) {
+        QQmlAbstractBinding *binding = m_bindings;
+        binding->setEnabled(false, 0);
+        binding->destroy();
+    }
+}
+
+void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
+{
+    if (e) {
+        QQmlAbstractBinding *bindings = m_bindings;
+        recursiveEnable(bindings, flags);
+    } else {
+        QQmlAbstractBinding *bindings = m_bindings;
+        recursiveDisable(bindings);
+    }
+}
+
+void QQmlValueTypeProxyBinding::recursiveEnable(QQmlAbstractBinding *b, QQmlPropertyPrivate::WriteFlags flags)
+{
+    if (!b)
+        return;
+
+    recursiveEnable(b->m_nextBinding, flags);
+
+    if (b)
+        b->setEnabled(true, flags);
+}
+
+void QQmlValueTypeProxyBinding::recursiveDisable(QQmlAbstractBinding *b)
+{
+    if (!b)
+        return;
+
+    recursiveDisable(b->m_nextBinding);
+
+    if (b)
+        b->setEnabled(false, 0);
+}
+
+void QQmlValueTypeProxyBinding::update(QQmlPropertyPrivate::WriteFlags)
+{
+}
+
+QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex)
+{
+    QQmlAbstractBinding *binding = m_bindings;
+
+    while (binding && binding->propertyIndex() != propertyIndex)
+        binding = binding->m_nextBinding;
+
+    return binding;
+}
+
+/*!
+Removes a collection of bindings, corresponding to the set bits in \a mask.
+*/
+void QQmlValueTypeProxyBinding::removeBindings(quint32 mask)
+{
+    QQmlAbstractBinding *binding = m_bindings;
+    while (binding) {
+        if (mask & (1 << (binding->propertyIndex() >> 24))) {
+            QQmlAbstractBinding *remove = binding;
+            binding = remove->m_nextBinding;
+            *remove->m_prevBinding = remove->m_nextBinding;
+            if (remove->m_nextBinding) remove->m_nextBinding->m_prevBinding = remove->m_prevBinding;
+            remove->m_prevBinding = 0;
+            remove->m_nextBinding = 0;
+            remove->destroy();
+        } else {
+            binding = binding->m_nextBinding;
+        }
+    }
+}
+
+int QQmlValueTypeProxyBinding::propertyIndex() const
+{
+    return m_index;
+}
+
+QObject *QQmlValueTypeProxyBinding::object() const
+{
+    return m_object;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
new file mode 100644 (file)
index 0000000..0135d57
--- /dev/null
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLVALUETYPEPROXYBINDING_P_H
+#define QQMLVALUETYPEPROXYBINDING_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlabstractbinding_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlValueTypeProxyBinding : public QQmlAbstractBinding
+{
+public:
+    QQmlValueTypeProxyBinding(QObject *o, int coreIndex);
+
+    virtual Type bindingType() const { return ValueTypeProxy; }
+
+    virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags);
+    virtual void update(QQmlPropertyPrivate::WriteFlags);
+    virtual int propertyIndex() const;
+    virtual QObject *object() const;
+
+    QQmlAbstractBinding *binding(int propertyIndex);
+
+    void removeBindings(quint32 mask);
+
+protected:
+    ~QQmlValueTypeProxyBinding();
+
+private:
+    void recursiveEnable(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags);
+    void recursiveDisable(QQmlAbstractBinding *);
+
+    friend class QQmlAbstractBinding;
+    QObject *m_object;
+    int m_index;
+    QQmlAbstractBinding *m_bindings;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLVALUETYPEPROXYBINDING_P_H
index 2b66e00..99979ab 100644 (file)
@@ -66,6 +66,7 @@
 #include "qqmlscriptstring.h"
 #include "qqmlscriptstring_p.h"
 #include "qqmlpropertyvalueinterceptor_p.h"
+#include "qqmlvaluetypeproxybinding_p.h"
 
 #include <QStack>
 #include <QColor>