aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/qml.pri13
-rw-r--r--src/qml/qml/qqmlabstractbinding.cpp200
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h132
-rw-r--r--src/qml/qml/qqmlabstractexpression.cpp101
-rw-r--r--src/qml/qml/qqmlabstractexpression_p.h124
-rw-r--r--src/qml/qml/qqmlbinding.cpp478
-rw-r--r--src/qml/qml/qqmlbinding_p.h170
-rw-r--r--src/qml/qml/qqmlcomponent.cpp138
-rw-r--r--src/qml/qml/qqmlcomponent.h6
-rw-r--r--src/qml/qml/qqmlcomponent_p.h2
-rw-r--r--src/qml/qml/qqmlcontext.cpp2
-rw-r--r--src/qml/qml/qqmldata_p.h7
-rw-r--r--src/qml/qml/qqmlengine.cpp50
-rw-r--r--src/qml/qml/qqmlexpression.cpp425
-rw-r--r--src/qml/qml/qqmlexpression.h2
-rw-r--r--src/qml/qml/qqmlexpression_p.h289
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp6
-rw-r--r--src/qml/qml/qqmlimport.cpp18
-rw-r--r--src/qml/qml/qqmlincubator.cpp10
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp371
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h283
-rw-r--r--src/qml/qml/qqmllocale.cpp28
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp4
-rw-r--r--src/qml/qml/qqmlproperty.cpp19
-rw-r--r--src/qml/qml/qqmlproperty_p.h8
-rw-r--r--src/qml/qml/qqmltypeloader.cpp39
-rw-r--r--src/qml/qml/qqmltypeloader_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding.cpp138
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding_p.h (renamed from src/qml/qml/qqmlbinding_p_p.h)42
-rw-r--r--src/qml/qml/qqmlvme.cpp10
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp67
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h16
-rw-r--r--src/qml/qml/qquickworkerscript.cpp6
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp68
-rw-r--r--src/qml/qml/v4/qv4compiler.cpp32
-rw-r--r--src/qml/qml/v4/qv4instruction.cpp18
-rw-r--r--src/qml/qml/v4/qv4instruction_p.h12
-rw-r--r--src/qml/qml/v4/qv4ir.cpp13
-rw-r--r--src/qml/qml/v4/qv4ir_p.h2
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp91
-rw-r--r--src/qml/qml/v4/qv4program_p.h1
-rw-r--r--src/qml/qml/v8/qjsengine.cpp2
-rw-r--r--src/qml/qml/v8/qjsvalue.cpp44
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp107
-rw-r--r--src/qml/qml/v8/qv8bindings.cpp6
-rw-r--r--src/qml/qml/v8/qv8contextwrapper.cpp18
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp21
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper.cpp4
48 files changed, 2206 insertions, 1439 deletions
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index b3897637e8..5d26197b1c 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -46,7 +46,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 \
@@ -59,7 +63,6 @@ HEADERS += \
$$PWD/qqml.h \
$$PWD/qquickapplication_p.h \
$$PWD/qqmlbinding_p.h \
- $$PWD/qqmlbinding_p_p.h \
$$PWD/qqmlproperty.h \
$$PWD/qqmlcomponent.h \
$$PWD/qqmlcomponent_p.h \
@@ -114,7 +117,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
index 0000000000..acc207e970
--- /dev/null
+++ b/src/qml/qml/qqmlabstractbinding.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** 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 <QtQml/qqmlinfo.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);
+ }
+ }
+}
+
+void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop)
+{
+ qmlInfo(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name());
+}
+
+
+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
index 0000000000..8c4aa4affc
--- /dev/null
+++ b/src/qml/qml/qqmlabstractbinding_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** 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);
+ static void printBindingLoopError(QQmlProperty &prop);
+
+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
index 0000000000..8319f7a619
--- /dev/null
+++ b/src/qml/qml/qqmlabstractexpression.cpp
@@ -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
index 0000000000..fe2ee1762b
--- /dev/null
+++ b/src/qml/qml/qqmlabstractexpression_p.h
@@ -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
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index bb6eb3b723..f43822ed0e 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -40,7 +40,6 @@
****************************************************************************/
#include "qqmlbinding_p.h"
-#include "qqmlbinding_p_p.h"
#include "qqml.h"
#include "qqmlcontext.h"
@@ -49,175 +48,19 @@
#include "qqmldata_p.h"
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmltrace_p.h>
+#include <private/qqmlexpression_p.h>
+#include <private/qqmlrewrite_p.h>
#include <QVariant>
#include <QtCore/qdebug.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);
-}
-
QQmlBinding::Identifier QQmlBinding::Invalid = -1;
-void QQmlBindingPrivate::refresh()
-{
- Q_Q(QQmlBinding);
- q->update();
-}
-
-QQmlBindingPrivate::QQmlBindingPrivate()
-: updating(false), enabled(false), target(), targetProperty(0)
-{
-}
-
-QQmlBindingPrivate::~QQmlBindingPrivate()
-{
-}
-
QQmlBinding *
QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt,
- const QString &url, int lineNumber, QObject *parent)
+ const QString &url, int lineNumber)
{
if (id < 0)
return 0;
@@ -231,7 +74,8 @@ QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt,
typeData = engine->typeLoader.get(ctxtdata->url);
cdata = typeData->compiledData();
}
- QQmlBinding *rv = cdata ? new QQmlBinding(cdata->primitives.at(id), true, obj, ctxtdata, url, lineNumber, 0, parent) : 0;
+ QQmlBinding *rv = cdata ? new QQmlBinding(cdata->primitives.at(id), true, obj, ctxtdata,
+ url, lineNumber, 0) : 0;
if (cdata)
cdata->release();
if (typeData)
@@ -239,30 +83,62 @@ QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt,
return rv;
}
-QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt,
- QObject *parent)
-: QQmlExpression(QQmlContextData::get(ctxt), obj, str, *new QQmlBindingPrivate)
+static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = {
+ QQmlBinding::expressionIdentifier,
+ QQmlBinding::expressionChanged
+};
+
+QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt)
+: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), m_lineNumber(-1), m_columnNumber(-1)
{
- setParent(parent);
setNotifyOnValueChanged(true);
+ QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt));
+ setScopeObject(obj);
+
+ QQmlRewrite::RewriteBinding rewriteBinding;
+ QString code = rewriteBinding(str);
+
+ m_expression = str.toUtf8();
+ v8function = evalFunction(context(), obj, code, QString(), 0);
}
-QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt,
- QObject *parent)
-: QQmlExpression(ctxt, obj, str, *new QQmlBindingPrivate)
+QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt)
+: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), m_lineNumber(-1), m_columnNumber(-1)
{
- setParent(parent);
setNotifyOnValueChanged(true);
+ QQmlAbstractExpression::setContext(ctxt);
+ setScopeObject(obj);
+
+ QQmlRewrite::RewriteBinding rewriteBinding;
+ QString code = rewriteBinding(str);
+
+ m_expression = str.toUtf8();
+ v8function = evalFunction(ctxt, obj, code, QString(), 0);
}
QQmlBinding::QQmlBinding(const QString &str, bool isRewritten, QObject *obj,
- QQmlContextData *ctxt,
- const QString &url, int lineNumber, int columnNumber,
- QObject *parent)
-: QQmlExpression(ctxt, obj, str, isRewritten, url, lineNumber, columnNumber, *new QQmlBindingPrivate)
+ QQmlContextData *ctxt,
+ const QString &url, int lineNumber, int columnNumber)
+: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), m_lineNumber(-1), m_columnNumber(-1)
{
- setParent(parent);
setNotifyOnValueChanged(true);
+ QQmlAbstractExpression::setContext(ctxt);
+ setScopeObject(obj);
+
+ QString code;
+ if (isRewritten) {
+ code = str;
+ } else {
+ QQmlRewrite::RewriteBinding rewriteBinding;
+ code = rewriteBinding(str);
+ }
+
+ m_url = url;
+ m_lineNumber = lineNumber;
+ m_columnNumber = columnNumber;
+ m_expression = str.toUtf8();
+
+ v8function = evalFunction(ctxt, obj, code, url, lineNumber);
}
/*!
@@ -273,124 +149,100 @@ QQmlBinding::QQmlBinding(const QString &str, bool isRewritten, QObject *obj,
v8::Handle<v8::Function> function;
new QQmlBinding(&function, scope, ctxt);
*/
-QQmlBinding::QQmlBinding(void *functionPtr, QObject *obj, QQmlContextData *ctxt,
- QObject *parent)
-: QQmlExpression(ctxt, obj, functionPtr, *new QQmlBindingPrivate)
+QQmlBinding::QQmlBinding(void *functionPtr, QObject *obj, QQmlContextData *ctxt,
+ const QString &url, int lineNumber, int columnNumber)
+: QQmlJavaScriptExpression(&QQmlBinding_jsvtable),
+ m_url(url), m_lineNumber(lineNumber), m_columnNumber(columnNumber)
{
- setParent(parent);
setNotifyOnValueChanged(true);
-}
-
-QQmlBinding::~QQmlBinding()
-{
-}
-
-void QQmlBinding::setTarget(const QQmlProperty &prop)
-{
- Q_D(QQmlBinding);
- d->property = prop;
- d->target = d->property.object();
- d->targetProperty = QQmlPropertyPrivate::get(d->property)->core.encodedIndex();
+ QQmlAbstractExpression::setContext(ctxt);
+ setScopeObject(obj);
- update();
+ v8function = qPersistentNew<v8::Function>(*(v8::Handle<v8::Function> *)functionPtr);
}
-void QQmlBinding::setTarget(QObject *object,
- const QQmlPropertyData &core,
- QQmlContextData *ctxt)
+QQmlBinding::~QQmlBinding()
{
- Q_D(QQmlBinding);
- d->property = QQmlPropertyPrivate::restore(object, core, ctxt);
- d->target = d->property.object();
- d->targetProperty = QQmlPropertyPrivate::get(d->property)->core.encodedIndex();
-
- update();
+ qPersistentDispose(v8function);
}
-QQmlProperty QQmlBinding::property() const
+void QQmlBinding::setEvaluateFlags(EvaluateFlags flags)
{
- Q_D(const QQmlBinding);
- return d->property;
+ setRequiresThisObject(flags & RequiresThisObject);
}
-void QQmlBinding::setEvaluateFlags(EvaluateFlags flags)
+QQmlBinding::EvaluateFlags QQmlBinding::evaluateFlags() const
{
- Q_D(QQmlBinding);
- d->setRequiresThisObject(flags & RequiresThisObject);
+ return requiresThisObject()?RequiresThisObject:None;
}
-QQmlBinding::EvaluateFlags QQmlBinding::evaluateFlags() const
+void QQmlBinding::setNotifyOnValueChanged(bool v)
{
- Q_D(const QQmlBinding);
- return d->requiresThisObject()?RequiresThisObject:None;
+ QQmlJavaScriptExpression::setNotifyOnValueChanged(v);
}
void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
{
- Q_D(QQmlBinding);
-
- if (!d->enabled || !d->context() || !d->context()->isValid())
+ if (!enabledFlag() || !context() || !context()->isValid())
return;
QQmlTrace trace("General Binding Update");
- trace.addDetail("URL", d->url);
- trace.addDetail("Line", d->line);
- trace.addDetail("Column", d->columnNumber);
+ trace.addDetail("URL", m_url);
+ trace.addDetail("Line", m_lineNumber);
+ trace.addDetail("Column", m_columnNumber);
- if (!d->updating) {
- QQmlBindingProfiler prof(d->url, d->line, d->column);
+ if (!updatingFlag()) {
+ QQmlBindingProfiler prof(m_url, m_lineNumber, m_columnNumber);
if (prof.enabled)
prof.addDetail(expression());
- d->updating = true;
+ setUpdatingFlag(true);
- QQmlAbstractExpression::DeleteWatcher watcher(d);
+ QQmlAbstractExpression::DeleteWatcher watcher(this);
- if (d->property.propertyType() == qMetaTypeId<QQmlBinding *>()) {
+ if (m_core.propType == qMetaTypeId<QQmlBinding *>()) {
- int idx = d->property.index();
+ int idx = m_core.coreIndex;
Q_ASSERT(idx != -1);
QQmlBinding *t = this;
int status = -1;
void *a[] = { &t, 0, &status, &flags };
- QMetaObject::metacall(d->property.object(),
- QMetaObject::WriteProperty,
- idx, a);
+ QMetaObject::metacall(*m_coreObject, QMetaObject::WriteProperty, idx, a);
} else {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(d->context()->engine);
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
ep->referenceScarceResources();
bool isUndefined = false;
v8::HandleScope handle_scope;
v8::Context::Scope scope(ep->v8engine()->context());
- v8::Local<v8::Value> result = d->v8value(0, &isUndefined);
+ v8::Local<v8::Value> result =
+ QQmlJavaScriptExpression::evaluate(context(), v8function, &isUndefined);
trace.event("writing binding result");
bool needsErrorData = false;
- if (!watcher.wasDeleted() && !d->hasError())
- needsErrorData = !QQmlPropertyPrivate::writeBinding(d->property, d->context(),
- d, result,
- isUndefined, flags);
+ if (!watcher.wasDeleted() && !hasError())
+ needsErrorData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(),
+ this, result, isUndefined, flags);
if (!watcher.wasDeleted()) {
if (needsErrorData) {
- QUrl url = QUrl(d->url);
- int line = d->line;
+ QUrl url = QUrl(m_url);
+
if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
- d->delayedError()->error.setUrl(url);
- d->delayedError()->error.setLine(line);
- d->delayedError()->error.setColumn(-1);
+ delayedError()->error.setUrl(url);
+ delayedError()->error.setLine(m_lineNumber);
+ delayedError()->error.setColumn(m_columnNumber);
}
- if (d->hasError()) {
- if (!d->delayedError()->addError(ep)) ep->warning(this->error());
+ if (hasError()) {
+ if (!delayedError()->addError(ep)) ep->warning(this->error());
} else {
- d->clearError();
+ clearError();
}
}
@@ -399,154 +251,96 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
}
if (!watcher.wasDeleted())
- d->updating = false;
+ setUpdatingFlag(false);
} else {
- QQmlBindingPrivate::printBindingLoopError(d->property);
+ QQmlProperty p = property();
+ QQmlAbstractBinding::printBindingLoopError(p);
}
}
-void QQmlBindingPrivate::printBindingLoopError(QQmlProperty &prop)
+QVariant QQmlBinding::evaluate()
{
- qmlInfo(prop.object()) << QQmlBinding::tr("Binding loop detected for property \"%1\"").arg(prop.name());
-}
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
+ ep->referenceScarceResources();
-void QQmlBindingPrivate::expressionChanged()
-{
- Q_Q(QQmlBinding);
- q->update();
-}
+ bool isUndefined = false;
-void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
-{
- Q_D(QQmlBinding);
- d->enabled = e;
- setNotifyOnValueChanged(e);
-
- if (e)
- update(flags);
-}
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(ep->v8engine()->context());
+ v8::Local<v8::Value> result =
+ QQmlJavaScriptExpression::evaluate(context(), v8function, &isUndefined);
-bool QQmlBinding::enabled() const
-{
- Q_D(const QQmlBinding);
+ ep->dereferenceScarceResources();
- return d->enabled;
+ return ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
}
-QString QQmlBinding::expression() const
+QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e)
{
- return QQmlExpression::expression();
-}
+ QQmlBinding *This = static_cast<QQmlBinding *>(e);
-int QQmlBinding::propertyIndex() const
-{
- Q_D(const QQmlBinding);
- return d->targetProperty;
+ return QLatin1String("\"") + QString::fromUtf8(This->m_expression) + QLatin1String("\"");
}
-QObject *QQmlBinding::object() const
-{
- Q_D(const QQmlBinding);
- return d->target;
-}
-
-void QQmlBinding::retargetBinding(QObject *t, int i)
+void QQmlBinding::expressionChanged(QQmlJavaScriptExpression *e)
{
- Q_D(QQmlBinding);
- d->target = t;
- d->targetProperty = i;
+ QQmlBinding *This = static_cast<QQmlBinding *>(e);
+ This->update();
}
-QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index)
-: m_object(o), m_index(index), m_bindings(0)
+void QQmlBinding::refresh()
{
+ update();
}
-QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding()
+void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
{
- while (m_bindings) {
- QQmlAbstractBinding *binding = m_bindings;
- binding->setEnabled(false, 0);
- binding->destroy();
- }
-}
+ setEnabledFlag(e);
+ setNotifyOnValueChanged(e);
-void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
-{
- if (e) {
- QQmlAbstractBinding *bindings = m_bindings;
- recursiveEnable(bindings, flags);
- } else {
- QQmlAbstractBinding *bindings = m_bindings;
- recursiveDisable(bindings);
- }
+ if (e)
+ update(flags);
}
-void QQmlValueTypeProxyBinding::recursiveEnable(QQmlAbstractBinding *b, QQmlPropertyPrivate::WriteFlags flags)
+QString QQmlBinding::expression() const
{
- if (!b)
- return;
-
- recursiveEnable(b->m_nextBinding, flags);
-
- if (b)
- b->setEnabled(true, flags);
+ return QString::fromUtf8(m_expression);
}
-void QQmlValueTypeProxyBinding::recursiveDisable(QQmlAbstractBinding *b)
+QObject *QQmlBinding::object() const
{
- if (!b)
- return;
-
- recursiveDisable(b->m_nextBinding);
-
- if (b)
- b->setEnabled(false, 0);
+ if (m_coreObject.hasValue()) return m_coreObject.constValue()->target;
+ else return *m_coreObject;
}
-void QQmlValueTypeProxyBinding::update(QQmlPropertyPrivate::WriteFlags)
+int QQmlBinding::propertyIndex() const
{
+ if (m_coreObject.hasValue()) return m_coreObject.constValue()->targetProperty;
+ else return m_core.encodedIndex();
}
-QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex)
+void QQmlBinding::retargetBinding(QObject *t, int i)
{
- QQmlAbstractBinding *binding = m_bindings;
-
- while (binding && binding->propertyIndex() != propertyIndex)
- binding = binding->m_nextBinding;
-
- return binding;
+ m_coreObject.value().target = t;
+ m_coreObject.value().targetProperty = i;
}
-/*!
-Removes a collection of bindings, corresponding to the set bits in \a mask.
-*/
-void QQmlValueTypeProxyBinding::removeBindings(quint32 mask)
+void QQmlBinding::setTarget(const QQmlProperty &prop)
{
- 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;
- }
- }
+ setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core,
+ QQmlPropertyPrivate::get(prop)->context);
}
-int QQmlValueTypeProxyBinding::propertyIndex() const
+void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, QQmlContextData *ctxt)
{
- return m_index;
+ m_coreObject = object;
+ m_core = core;
+ m_ctxt = ctxt;
}
-QObject *QQmlValueTypeProxyBinding::object() const
+QQmlProperty QQmlBinding::property() const
{
- return m_object;
+ return QQmlPropertyPrivate::restore(object(), m_core, *m_ctxt);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 33823d7e7e..2cf7b80290 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -63,113 +63,27 @@
#include <QtCore/QMetaProperty>
#include <private/qpointervaluepair_p.h>
+#include <private/qqmlabstractbinding_p.h>
+#include <private/qqmlabstractexpression_p.h>
+#include <private/qqmljavascriptexpression_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 QQmlJavaScriptExpression,
+ public QQmlAbstractExpression,
+ public QQmlAbstractBinding
{
-Q_OBJECT
public:
enum EvaluateFlag { None = 0x00, RequiresThisObject = 0x01 };
Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag)
- QQmlBinding(const QString &, QObject *, QQmlContext *, QObject *parent=0);
- QQmlBinding(const QString &, QObject *, QQmlContextData *, QObject *parent=0);
+ QQmlBinding(const QString &, QObject *, QQmlContext *);
+ QQmlBinding(const QString &, QObject *, QQmlContextData *);
QQmlBinding(const QString &, bool isRewritten, QObject *, QQmlContextData *,
- const QString &url, int lineNumber, int columnNumber = 0, QObject *parent=0);
- QQmlBinding(void *, QObject *, QQmlContextData *, QObject *parent=0);
+ const QString &url, int lineNumber, int columnNumber);
+ QQmlBinding(void *, QObject *, QQmlContextData *,
+ const QString &url, int lineNumber, int columnNumber);
void setTarget(const QQmlProperty &);
void setTarget(QObject *, const QQmlPropertyData &, QQmlContextData *);
@@ -178,40 +92,82 @@ public:
void setEvaluateFlags(EvaluateFlags flags);
EvaluateFlags evaluateFlags() const;
- bool enabled() const;
+ void setNotifyOnValueChanged(bool);
+
+ // Inherited from QQmlAbstractExpression
+ virtual void refresh();
// Inherited from QQmlAbstractBinding
virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags);
virtual void update(QQmlPropertyPrivate::WriteFlags flags);
virtual QString expression() const;
- virtual int propertyIndex() const;
virtual QObject *object() const;
+ virtual int propertyIndex() const;
virtual void retargetBinding(QObject *, int);
typedef int Identifier;
static Identifier Invalid;
- static QQmlBinding *createBinding(Identifier, QObject *, QQmlContext *,
- const QString &, int, QObject *parent=0);
+ static QQmlBinding *createBinding(Identifier, QObject *, QQmlContext *, const QString &, int);
-public Q_SLOTS:
+ QVariant evaluate();
void update() { update(QQmlPropertyPrivate::DontRemoveBinding); }
+ static QString expressionIdentifier(QQmlJavaScriptExpression *);
+ static void expressionChanged(QQmlJavaScriptExpression *);
+
protected:
~QQmlBinding();
private:
- Q_DECLARE_PRIVATE(QQmlBinding)
+ v8::Persistent<v8::Function> v8function;
+
+ inline bool updatingFlag() const;
+ inline void setUpdatingFlag(bool);
+ inline bool enabledFlag() const;
+ inline void setEnabledFlag(bool);
+
+ struct Retarget {
+ QObject *target;
+ int targetProperty;
+ };
+
+ QPointerValuePair<QObject, Retarget> m_coreObject;
+ QQmlPropertyData m_core;
+ // We store some flag bits in the following flag pointers.
+ // m_ctxt:flag1 - updatingFlag
+ // m_ctxt:flag2 - enabledFlag
+ QFlagPointer<QQmlContextData> m_ctxt;
+
+ // XXX It would be good if we could get rid of these in most circumstances
+ QString m_url;
+ int m_lineNumber;
+ int m_columnNumber;
+ QByteArray m_expression;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlBinding::EvaluateFlags)
+bool QQmlBinding::updatingFlag() const
+{
+ return m_ctxt.flag();
+}
-QQmlAbstractBinding::Pointer
-QQmlAbstractBinding::getPointer(QQmlAbstractBinding *p)
+void QQmlBinding::setUpdatingFlag(bool v)
{
- return p ? p->weakPointer() : Pointer();
+ m_ctxt.setFlagValue(v);
}
+bool QQmlBinding::enabledFlag() const
+{
+ return m_ctxt.flag2();
+}
+
+void QQmlBinding::setEnabledFlag(bool v)
+{
+ m_ctxt.setFlag2Value(v);
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlBinding::EvaluateFlags)
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQmlBinding*)
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 5dd8fc8ae9..6cd5cf6cec 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -50,13 +50,13 @@
#include "qqml.h"
#include "qqmlengine.h"
#include "qqmlbinding_p.h"
-#include "qqmlbinding_p_p.h"
#include "qqmlglobal_p.h"
#include "qqmlscript_p.h"
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlenginedebugservice_p.h>
#include "qqmlincubator.h"
#include "qqmlincubator_p.h"
+#include <private/qqmljavascriptexpression_p.h>
#include <private/qv8engine_p.h>
#include <private/qv8include_p.h>
@@ -280,6 +280,16 @@ static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
\value Error An error has occurred. Call errors() to retrieve a list of \{QQmlError}{errors}.
*/
+/*!
+ \enum QQmlComponent::CompilationMode
+
+ Specifies whether the QQmlComponent should load the component immediately, or asynchonously.
+
+ \value PreferSynchronous Prefer loading/compiling the component immediately, blocking the thread.
+ This is not always possible, e.g. remote URLs will always load asynchronously.
+ \value Asynchronous Load/compile the component in a background thread.
+*/
+
void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
{
Q_Q(QQmlComponent);
@@ -288,8 +298,10 @@ void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
fromTypeData(typeData);
typeData = 0;
+ progress = 1.0;
emit q->statusChanged(q->status());
+ emit q->progressChanged(progress);
}
void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
@@ -362,10 +374,10 @@ QQmlComponent::~QQmlComponent()
\qmlproperty enumeration Component::status
This property holds the status of component loading. It can be one of:
\list
- \o Component.Null - no data is available for the component
- \o Component.Ready - the component has been loaded, and can be used to create instances.
- \o Component.Loading - the component is currently being loaded
- \o Component.Error - an error occurred while loading the component.
+ \li Component.Null - no data is available for the component
+ \li Component.Ready - the component has been loaded, and can be used to create instances.
+ \li Component.Loading - the component is currently being loaded
+ \li Component.Error - an error occurred while loading the component.
Calling errorString() will provide a human-readable description of any errors.
\endlist
*/
@@ -476,7 +488,24 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *paren
{
Q_D(QQmlComponent);
d->engine = engine;
- loadUrl(url);
+ d->loadUrl(url);
+}
+
+/*!
+ Create a QQmlComponent from the given \a url and give it the
+ specified \a parent and \a engine. If \a mode is \l Asynchronous,
+ the component will be loaded and compiled asynchronously.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+
+ \sa loadUrl()
+*/QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMode mode, QObject *parent)
+: QObject(*(new QQmlComponentPrivate), parent)
+{
+ Q_D(QQmlComponent);
+ d->engine = engine;
+ d->loadUrl(url, mode);
}
/*!
@@ -491,7 +520,23 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
{
Q_D(QQmlComponent);
d->engine = engine;
- loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
+ d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
+}
+
+/*!
+ Create a QQmlComponent from the given \a fileName and give it the specified
+ \a parent and \a engine. If \a mode is \l Asynchronous,
+ the component will be loaded and compiled asynchronously.
+
+ \sa loadUrl()
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
+ CompilationMode mode, QObject *parent)
+: QObject(*(new QQmlComponentPrivate), parent)
+{
+ Q_D(QQmlComponent);
+ d->engine = engine;
+ d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)), mode);
}
/*!
@@ -558,35 +603,63 @@ QQmlContext *QQmlComponent::creationContext() const
void QQmlComponent::loadUrl(const QUrl &url)
{
Q_D(QQmlComponent);
+ d->loadUrl(url);
+}
- d->clear();
+/*!
+ Load the QQmlComponent from the provided \a url.
+ If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+*/
+void QQmlComponent::loadUrl(const QUrl &url, QQmlComponent::CompilationMode mode)
+{
+ Q_D(QQmlComponent);
+ d->loadUrl(url, mode);
+}
+
+void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode)
+{
+ Q_Q(QQmlComponent);
+ clear();
- if ((url.isRelative() && !url.isEmpty())
- || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
- d->url = d->engine->baseUrl().resolved(url);
+ if ((newUrl.isRelative() && !newUrl.isEmpty())
+ || newUrl.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
+ url = engine->baseUrl().resolved(newUrl);
else
- d->url = url;
+ url = newUrl;
- if (url.isEmpty()) {
+ if (newUrl.isEmpty()) {
QQmlError error;
- error.setDescription(tr("Invalid empty URL"));
- d->state.errors << error;
+ error.setDescription(q->tr("Invalid empty URL"));
+ state.errors << error;
return;
}
- QQmlTypeData *data = QQmlEnginePrivate::get(d->engine)->typeLoader.get(d->url);
+ if (progress != 0.0) {
+ progress = 0.0;
+ emit q->progressChanged(progress);
+ }
+
+ QQmlDataLoader::Mode loaderMode = (mode == QQmlComponent::Asynchronous)
+ ? QQmlDataLoader::Asynchronous
+ : QQmlDataLoader::PreferSynchronous;
+
+ QQmlTypeData *data = QQmlEnginePrivate::get(engine)->typeLoader.get(url, loaderMode);
if (data->isCompleteOrError()) {
- d->fromTypeData(data);
- d->progress = 1.0;
+ fromTypeData(data);
+ progress = 1.0;
} else {
- d->typeData = data;
- d->typeData->registerCallback(d);
- d->progress = data->progress();
+ typeData = data;
+ typeData->registerCallback(this);
+ progress = data->progress();
}
- emit statusChanged(status());
- emit progressChanged(d->progress);
+ emit q->statusChanged(q->status());
+ if (progress != 0.0)
+ emit q->progressChanged(progress);
}
/*!
@@ -686,9 +759,9 @@ QObject *QQmlComponent::create(QQmlContext *context)
When QQmlComponent constructs an instance, it occurs in three steps:
\list 1
- \i The object hierarchy is created, and constant values are assigned.
- \i Property bindings are evaluated for the the first time.
- \i If applicable, QQmlParserStatus::componentComplete() is called on objects.
+ \li The object hierarchy is created, and constant values are assigned.
+ \li Property bindings are evaluated for the the first time.
+ \li If applicable, QQmlParserStatus::componentComplete() is called on objects.
\endlist
QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it
only performs step 1. QQmlComponent::completeCreate() must be called to
@@ -1079,13 +1152,13 @@ void QQmlComponent::createObject(QQmlV8Function *args)
properties:
\list
- \i status The status of the incubator. Valid values are Component.Ready, Component.Loading and
+ \li status The status of the incubator. Valid values are Component.Ready, Component.Loading and
Component.Error.
- \i object The created object instance. Will only be available once the incubator is in the
+ \li object The created object instance. Will only be available once the incubator is in the
Ready status.
- \i onStatusChanged Specifies a callback function to be invoked when the status changes. The
+ \li onStatusChanged Specifies a callback function to be invoked when the status changes. The
status is passed as a parameter to the callback.
- \i forceCompletion() Call to complete incubation synchronously.
+ \li forceCompletion() Call to complete incubation synchronously.
\endlist
The following example demonstrates how to use an incubator:
@@ -1337,9 +1410,8 @@ void QV8IncubatorResource::statusChanged(Status s)
f->Call(me, 1, args);
if (tc.HasCaught()) {
QQmlError error;
- QQmlExpressionPrivate::exceptionToError(tc.Message(), error);
- QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()),
- error);
+ QQmlJavaScriptExpression::exceptionToError(tc.Message(), error);
+ QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error);
}
}
}
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index 1265fb1c7d..9fc9388e41 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -73,10 +73,15 @@ class Q_QML_EXPORT QQmlComponent : public QObject
Q_PROPERTY(QUrl url READ url CONSTANT)
public:
+ Q_ENUMS(CompilationMode)
+ enum CompilationMode { PreferSynchronous, Asynchronous };
+
QQmlComponent(QObject *parent = 0);
QQmlComponent(QQmlEngine *, QObject *parent=0);
QQmlComponent(QQmlEngine *, const QString &fileName, QObject *parent = 0);
+ QQmlComponent(QQmlEngine *, const QString &fileName, CompilationMode mode, QObject *parent = 0);
QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = 0);
+ QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = 0);
virtual ~QQmlComponent();
Q_ENUMS(Status)
@@ -108,6 +113,7 @@ public:
public Q_SLOTS:
void loadUrl(const QUrl &url);
+ void loadUrl(const QUrl &url, CompilationMode mode);
void setData(const QByteArray &, const QUrl &baseUrl);
Q_SIGNALS:
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index dda5bd0b71..9e220b5e95 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -86,6 +86,8 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public
public:
QQmlComponentPrivate() : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0), profiler(0) {}
+ void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
+
QObject *beginCreate(QQmlContextData *);
void completeCreate();
void initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate);
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 38acc0b0c3..cbb8430f40 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -329,7 +329,7 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
/*!
Set the \a value of the \a name property on this context.
- QQmlContext does \bold not take ownership of \a value.
+ QQmlContext does \b not take ownership of \a value.
*/
void QQmlContext::setContextProperty(const QString &name, QObject *value)
{
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index e4ba44583d..09d1a23510 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -78,8 +78,8 @@ class Q_QML_EXPORT QQmlData : public QAbstractDeclarativeData
public:
QQmlData()
: ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
- hasTaintedV8Object(false), notifyList(0), context(0), outerContext(0), bindings(0),
- nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0),
+ hasTaintedV8Object(false), isQueuedForDeletion(false), notifyList(0), context(0), outerContext(0),
+ bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0),
lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), v8objectid(0),
propertyCache(0), guards(0), extendedData(0) {
init();
@@ -110,7 +110,8 @@ public:
quint32 indestructible:1;
quint32 explicitIndestructibleSet:1;
quint32 hasTaintedV8Object:1;
- quint32 dummy:27;
+ quint32 isQueuedForDeletion:1;
+ quint32 dummy:26;
struct NotifyList {
quint64 connectionMask;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 90b8bcd8bb..16cd1ecde6 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -49,7 +49,6 @@
#include "qqmlcontext.h"
#include "qqmlexpression.h"
#include "qqmlcomponent.h"
-#include "qqmlbinding_p_p.h"
#include "qqmlvme_p.h"
#include <private/qqmlenginedebugservice_p.h>
#include "qqmlstringconverters_p.h"
@@ -175,7 +174,6 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int
void QQmlEnginePrivate::defineModule()
{
registerBaseTypes("QtQuick", 2, 0);
- qmlRegisterType<QQmlBinding>();
qmlRegisterUncreatableType<QQuickApplication>("QtQuick",2,0,"Application", QQuickApplication::tr("Application is an abstract class"));
qmlRegisterUncreatableType<QQmlLocale>("QtQuick",2,0,"Locale",QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
}
@@ -222,11 +220,11 @@ data types. This is primarily useful when setting the properties of an item
when the property has one of the following types:
\list
-\o \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
-\o \c rect - use \l{Qt::rect()}{Qt.rect()}
-\o \c point - use \l{Qt::point()}{Qt.point()}
-\o \c size - use \l{Qt::size()}{Qt.size()}
-\o \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
+\li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
+\li \c rect - use \l{Qt::rect()}{Qt.rect()}
+\li \c point - use \l{Qt::point()}{Qt.point()}
+\li \c size - use \l{Qt::size()}{Qt.size()}
+\li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
\endlist
There are also string based constructors for these types. See \l{qdeclarativebasictypes.html}{QML Basic Types} for more information.
@@ -236,9 +234,9 @@ There are also string based constructors for these types. See \l{qdeclarativebas
The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
\list
- \o \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
- \o \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
- \o \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
+ \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
+ \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
+ \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
\endlist
The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
@@ -250,8 +248,8 @@ items from files or strings. See \l{Dynamic Object Management in QML} for an ove
of their use.
\list
- \o \l{Qt::createComponent()}{object Qt.createComponent(url)}
- \o \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
+ \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
+ \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
\endlist
*/
@@ -267,8 +265,8 @@ of their use.
\table
\row
- \o \c application.active
- \o
+ \li \c application.active
+ \li
This read-only property indicates whether the application is the top-most and focused
application, and the user is able to interact with the application. The property
is false when the application is in the background, the device keylock or screen
@@ -279,8 +277,8 @@ of their use.
active.
\row
- \o \c application.layoutDirection
- \o
+ \li \c application.layoutDirection
+ \li
This read-only property can be used to query the default layout direction of the
application. On system start-up, the default layout direction depends on the
application's language. The property has a value of \c Qt.RightToLeft in locales
@@ -291,15 +289,15 @@ of their use.
Possible values are:
\list
- \o Qt.LeftToRight - Text and graphics elements should be positioned
+ \li Qt.LeftToRight - Text and graphics elements should be positioned
from left to right.
- \o Qt.RightToLeft - Text and graphics elements should be positioned
+ \li Qt.RightToLeft - Text and graphics elements should be positioned
from right to left.
\endlist
\row
- \o \c application.inputPanel
- \o
+ \li \c application.inputPanel
+ \li
This read-only property allows access to application's QInputPanel object
and all its properties and slots. See the QInputPanel documentation for
further details. Deprecated in favor of Qt.InputMethod
@@ -331,11 +329,11 @@ Qt.include() returns an object that describes the status of the operation. The
a single property, \c {status}, that is set to one of the following values:
\table
-\header \o Symbol \o Value \o Description
-\row \o result.OK \o 0 \o The include completed successfully.
-\row \o result.LOADING \o 1 \o Data is being loaded from the network.
-\row \o result.NETWORK_ERROR \o 2 \o A network error occurred while fetching the url.
-\row \o result.EXCEPTION \o 3 \o A JavaScript exception occurred while executing the included code.
+\header \li Symbol \li Value \li Description
+\row \li result.OK \li 0 \li The include completed successfully.
+\row \li result.LOADING \li 1 \li Data is being loaded from the network.
+\row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
+\row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
An additional \c exception property will be set in this case.
\endtable
@@ -996,7 +994,7 @@ QQmlDebuggingEnabler::QQmlDebuggingEnabler()
{
#ifndef QQML_NO_DEBUG_PROTOCOL
if (!QQmlEnginePrivate::qml_debugging_enabled) {
- qWarning("QML debugging is enabled. Only use this in a safe environment.");
+ qDebug("QML debugging is enabled. Only use this in a safe environment.");
}
QQmlEnginePrivate::qml_debugging_enabled = true;
#endif
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index ecdbf21d4b..60a0fe1c89 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -52,32 +52,6 @@
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
@@ -98,8 +72,7 @@ QQmlExpressionPrivate::~QQmlExpressionPrivate()
dataRef = 0;
}
-void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
- QObject *me)
+void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QObject *me)
{
expression = expr;
@@ -109,22 +82,9 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
expressionFunctionRewritten = false;
}
-void QQmlExpressionPrivate::init(QQmlContextData *ctxt, v8::Handle<v8::Function> func,
- QObject *me)
-{
- QQmlAbstractExpression::setContext(ctxt);
- setScopeObject(me);
-
- v8function = qPersistentNew<v8::Function>(func);
- setUseSharedContext(false);
- expressionFunctionValid = true;
- expressionFunctionRewritten = false;
- extractExpressionFromFunction = true;
-}
-
void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
- bool isRewritten, QObject *me, const QString &srcUrl,
- int lineNumber, int columnNumber)
+ bool isRewritten, QObject *me, const QString &srcUrl,
+ int lineNumber, int columnNumber)
{
url = srcUrl;
line = lineNumber;
@@ -140,8 +100,8 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
}
void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QByteArray &expr,
- bool isRewritten, QObject *me, const QString &srcUrl,
- int lineNumber, int columnNumber)
+ bool isRewritten, QObject *me, const QString &srcUrl,
+ int lineNumber, int columnNumber)
{
url = srcUrl;
line = lineNumber;
@@ -166,97 +126,13 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QByteArray &expr,
setScopeObject(me);
}
-// Callee owns the persistent handle
-v8::Persistent<v8::Function>
-QQmlExpressionPrivate::evalFunction(QQmlContextData *ctxt, QObject *scope,
- const char *code, int codeLength,
- const QString &filename, int line,
- v8::Persistent<v8::Object> *qmlscope)
-{
- QQmlEngine *engine = ctxt->engine;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
-
- v8::HandleScope handle_scope;
- v8::Context::Scope ctxtscope(ep->v8engine()->context());
-
- v8::TryCatch tc;
- v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
- v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, codeLength, filename, line);
- if (tc.HasCaught()) {
- QQmlError error;
- error.setDescription(QLatin1String("Exception occurred during function compilation"));
- error.setLine(line);
- error.setUrl(QUrl::fromLocalFile(filename));
- v8::Local<v8::Message> message = tc.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
- ep->warning(error);
- return v8::Persistent<v8::Function>();
- }
- v8::Local<v8::Value> result = script->Run(scopeobject);
- if (tc.HasCaught()) {
- QQmlError error;
- error.setDescription(QLatin1String("Exception occurred during function evaluation"));
- error.setLine(line);
- error.setUrl(QUrl::fromLocalFile(filename));
- v8::Local<v8::Message> message = tc.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
- ep->warning(error);
- return v8::Persistent<v8::Function>();
- }
- if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
- return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
-}
-
-// Callee owns the persistent handle
-v8::Persistent<v8::Function>
-QQmlExpressionPrivate::evalFunction(QQmlContextData *ctxt, QObject *scope,
- const QString &code, const QString &filename, int line,
- v8::Persistent<v8::Object> *qmlscope)
-{
- QQmlEngine *engine = ctxt->engine;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
-
- v8::HandleScope handle_scope;
- v8::Context::Scope ctxtscope(ep->v8engine()->context());
-
- 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()) {
- QQmlError error;
- error.setDescription(QLatin1String("Exception occurred during function compilation"));
- error.setLine(line);
- error.setUrl(QUrl::fromLocalFile(filename));
- v8::Local<v8::Message> message = tc.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
- ep->warning(error);
- return v8::Persistent<v8::Function>();
- }
- v8::Local<v8::Value> result = script->Run(scopeobject);
- if (tc.HasCaught()) {
- QQmlError error;
- error.setDescription(QLatin1String("Exception occurred during function evaluation"));
- error.setLine(line);
- error.setUrl(QUrl::fromLocalFile(filename));
- v8::Local<v8::Message> message = tc.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
- ep->warning(error);
- return v8::Persistent<v8::Function>();
- }
- if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
- return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
-}
-
QQmlExpression *
QQmlExpressionPrivate::create(QQmlContextData *ctxt, QObject *object,
- const QString &expr, bool isRewritten,
- const QString &url, int lineNumber, int columnNumber)
+ const QString &expr, bool isRewritten,
+ const QString &url, int lineNumber, int columnNumber)
{
- return new QQmlExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QQmlExpressionPrivate);
+ return new QQmlExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber,
+ *new QQmlExpressionPrivate);
}
/*!
@@ -408,24 +284,6 @@ QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
d->init(ctxt, expression, scope);
}
-/*!
- \internal
-
- To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
- For example:
- v8::Handle<v8::Function> function;
- new QQmlExpression(ctxt, scope, &function, ...);
- */
-QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope, void *functionPtr,
- QQmlExpressionPrivate &dd)
-: QObject(dd, 0)
-{
- v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
-
- Q_D(QQmlExpression);
- d->init(ctxt, function, scope);
-}
-
/*!
Destroy the QQmlExpression instance.
*/
@@ -489,217 +347,6 @@ void QQmlExpression::setExpression(const QString &expression)
qPersistentDispose(d->v8qmlscope);
}
-void QQmlExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message,
- QQmlError &error)
-{
- Q_ASSERT(!message.IsEmpty());
-
- v8::Handle<v8::Value> name = message->GetScriptResourceName();
- v8::Handle<v8::String> description = message->Get();
- int lineNumber = message->GetLineNumber();
-
- v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>();
- if (file.IsEmpty() || file->Length() == 0)
- error.setUrl(QUrl(QLatin1String("<Unknown File>")));
- else
- error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
-
- error.setLine(lineNumber);
- error.setColumn(-1);
-
- QString qDescription = QV8Engine::toStringStatic(description);
- if (qDescription.startsWith(QLatin1String("Uncaught ")))
- qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
-
- 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 +570,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>
diff --git a/src/qml/qml/qqmlexpression.h b/src/qml/qml/qqmlexpression.h
index 4044546fbf..b60d9f1f86 100644
--- a/src/qml/qml/qqmlexpression.h
+++ b/src/qml/qml/qqmlexpression.h
@@ -96,8 +96,6 @@ Q_SIGNALS:
protected:
QQmlExpression(QQmlContextData *, QObject *, const QString &,
QQmlExpressionPrivate &dd);
- QQmlExpression(QQmlContextData *, QObject *, void *,
- QQmlExpressionPrivate &dd);
QQmlExpression(QQmlContextData *, QObject *, const QString &, bool,
const QString &, int, int, QQmlExpressionPrivate &dd);
QQmlExpression(QQmlContextData *, QObject *, const QByteArray &, bool,
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index deca29ab60..186e3aebf9 100644
--- a/src/qml/qml/qqmlexpression_p.h
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -56,161 +56,22 @@
#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:
@@ -218,7 +79,6 @@ public:
~QQmlExpressionPrivate();
void init(QQmlContextData *, const QString &, QObject *);
- void init(QQmlContextData *, v8::Handle<v8::Function>, QObject *);
void init(QQmlContextData *, const QString &, bool, QObject *, const QString &, int, int);
void init(QQmlContextData *, const QByteArray &, bool, QObject *, const QString &, int, int);
@@ -231,18 +91,8 @@ public:
void _q_notify();
- static void exceptionToError(v8::Handle<v8::Message>, QQmlError &);
- static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
- const QString &code, const QString &filename,
- int line,
- v8::Persistent<v8::Object> *qmlscope = 0);
- static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
- const char *code, int codeLength,
- const QString &filename, int line,
- v8::Persistent<v8::Object> *qmlscope = 0);
-
static QQmlExpression *create(QQmlContextData *, QObject *, const QString &, bool,
- const QString &, int, int);
+ const QString &, int, int);
bool expressionFunctionValid:1;
bool expressionFunctionRewritten:1;
@@ -267,103 +117,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 +127,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/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index c3d8f0b34f..b69fa5da7a 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -57,10 +57,10 @@ QT_BEGIN_NAMESPACE
To write a QML extension plugin:
\list
- \o Subclass QQmlExtensionPlugin, implement registerTypes() method
+ \li Subclass QQmlExtensionPlugin, implement registerTypes() method
to register types using qmlRegisterType(), and export the class using the Q_EXPORT_PLUGIN2() macro
- \o Write an appropriate project file for the plugin
- \o Create a \l{Writing a qmldir file}{qmldir file} to describe the plugin
+ \li Write an appropriate project file for the plugin
+ \li Create a \l{Writing a qmldir file}{qmldir file} to describe the plugin
\endlist
QML extension plugins can be used to provide either application-specific or
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 6e74536fa3..0c1fb3bd93 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -268,9 +268,9 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
The given (namespace qualified) \a type is resolved to either
\list
- \o a QQmlImportedNamespace stored at \a ns_return,
- \o a QQmlType stored at \a type_return, or
- \o a component located at \a url_return.
+ \li a QQmlImportedNamespace stored at \a ns_return,
+ \li a QQmlType stored at \a type_return, or
+ \li a component located at \a url_return.
\endlist
If any return pointer is 0, the corresponding search is not done.
@@ -956,12 +956,12 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
Returns the result of the merge of \a baseName with \a dir and the platform suffix.
\table
- \header \i Platform \i Valid suffixes
- \row \i Windows \i \c .dll
- \row \i Unix/Linux \i \c .so
- \row \i AIX \i \c .a
- \row \i HP-UX \i \c .sl, \c .so (HP-UXi)
- \row \i Mac OS X \i \c .dylib, \c .bundle, \c .so
+ \header \li Platform \li Valid suffixes
+ \row \li Windows \li \c .dll
+ \row \li Unix/Linux \li \c .so
+ \row \li AIX \li \c .a
+ \row \li HP-UX \li \c .sl, \c .so (HP-UXi)
+ \row \li Mac OS X \li \c .dylib, \c .bundle, \c .so
\endtable
Version number on unix are ignored.
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 834d4bbb97..aa9777d89e 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -427,14 +427,14 @@ specified IncubationMode.
QQmlIncubator supports three incubation modes:
\list
-\i Synchronous The creation occurs synchronously. That is, once the
+\li Synchronous The creation occurs synchronously. That is, once the
QQmlComponent::create() call returns, the incubator will already be in either the
Error or Ready state. A synchronous incubator has no real advantage compared to using
the synchronous creation methods on QQmlComponent directly, but it may simplify an
application's implementation to use the same API for both synchronous and asynchronous
creations.
-\i Asynchronous (default) The creation occurs asynchronously, assuming a
+\li Asynchronous (default) The creation occurs asynchronously, assuming a
QQmlIncubatorController is set on the QQmlEngine.
The incubator will remain in the Loading state until either the creation is complete or an error
@@ -446,7 +446,7 @@ that are slightly off screen while the list is being scrolled. If, during async
the object is needed immediately the QQmlIncubator::forceCompletion() method can be called
to complete the creation process synchronously.
-\i AsynchronousIfNested The creation will occur asynchronously if part of a nested asynchronous
+\li AsynchronousIfNested The creation will occur asynchronously if part of a nested asynchronous
creation, or synchronously if not.
In most scenarios where a QML element or component wants the appearance of a synchronous
@@ -542,6 +542,10 @@ void QQmlIncubator::clear()
d->clear();
+ // if we're waiting on any incubators then they should be cleared too.
+ while (d->waitingFor.first())
+ static_cast<QQmlIncubatorPrivate*>(d->waitingFor.first())->q->clear();
+
d->vme.reset();
d->vmeGuard.clear();
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
new file mode 100644
index 0000000000..aad6a04714
--- /dev/null
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -0,0 +1,371 @@
+/****************************************************************************
+**
+** 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();
+ if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion.
+ m_scopeObject.asT2()->_s = 0;
+}
+
+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::exceptionToError(v8::Handle<v8::Message> message, QQmlError &error)
+{
+ Q_ASSERT(!message.IsEmpty());
+
+ v8::Handle<v8::Value> name = message->GetScriptResourceName();
+ v8::Handle<v8::String> description = message->Get();
+ int lineNumber = message->GetLineNumber();
+
+ v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>();
+ if (file.IsEmpty() || file->Length() == 0)
+ error.setUrl(QUrl(QLatin1String("<Unknown File>")));
+ else
+ error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
+
+ error.setLine(lineNumber);
+ error.setColumn(-1);
+
+ QString qDescription = QV8Engine::toStringStatic(description);
+ if (qDescription.startsWith(QLatin1String("Uncaught ")))
+ qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
+
+ error.setDescription(qDescription);
+}
+
+// Callee owns the persistent handle
+v8::Persistent<v8::Function>
+QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope,
+ const char *code, int codeLength,
+ const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope)
+{
+ QQmlEngine *engine = ctxt->engine;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope ctxtscope(ep->v8engine()->context());
+
+ v8::TryCatch tc;
+ v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
+ v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, codeLength, filename, line);
+ if (tc.HasCaught()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Exception occurred during function compilation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ v8::Local<v8::Value> result = script->Run(scopeobject);
+ if (tc.HasCaught()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Exception occurred during function evaluation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
+ return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
+}
+
+// Callee owns the persistent handle
+v8::Persistent<v8::Function>
+QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope)
+{
+ QQmlEngine *engine = ctxt->engine;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope ctxtscope(ep->v8engine()->context());
+
+ 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()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Exception occurred during function compilation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ v8::Local<v8::Value> result = script->Run(scopeobject);
+ if (tc.HasCaught()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Exception occurred during function evaluation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
+ return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
+}
+
+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
index 0000000000..5d790e4570
--- /dev/null
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** 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();
+
+ static void exceptionToError(v8::Handle<v8::Message>, QQmlError &);
+ static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename,
+ int line,
+ v8::Persistent<v8::Object> *qmlscope = 0);
+ static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
+ const char *code, int codeLength,
+ const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope = 0);
+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
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index d684378832..4a4563ccd4 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -1023,13 +1023,13 @@ v8::Handle<v8::Value> QQmlLocale::localeCompare(const v8::Arguments &args)
Holds the first day of the week according to the current locale.
\list
- \o Locale.Sunday = 0
- \o Locale.Monday = 1
- \o Locale.Tuesday = 2
- \o Locale.Wednesday = 3
- \o Locale.Thursday = 4
- \o Locale.Friday = 5
- \o Locale.Saturday = 6
+ \li Locale.Sunday = 0
+ \li Locale.Monday = 1
+ \li Locale.Tuesday = 2
+ \li Locale.Wednesday = 3
+ \li Locale.Thursday = 4
+ \li Locale.Friday = 5
+ \li Locale.Saturday = 6
\endlist
\note that these values match the JS Date API which is different
@@ -1062,8 +1062,8 @@ v8::Handle<v8::Value> QQmlLocale::localeCompare(const v8::Arguments &args)
Holds the text direction of the language:
\list
- \o Qt.LeftToRight
- \o Qt.RightToLeft
+ \li Qt.LeftToRight
+ \li Qt.RightToLeft
\endlist
*/
@@ -1084,9 +1084,9 @@ v8::Handle<v8::Value> QQmlLocale::localeCompare(const v8::Arguments &args)
Returns the currency symbol for the specified \a format:
\list
- \o Locale.CurrencyIsoCode a ISO-4217 code of the currency.
- \o Locale.CurrencySymbol a currency symbol.
- \o Locale.CurrencyDisplayName a user readable name of the currency.
+ \li Locale.CurrencyIsoCode a ISO-4217 code of the currency.
+ \li Locale.CurrencySymbol a currency symbol.
+ \li Locale.CurrencyDisplayName a user readable name of the currency.
\endlist
\sa Number::toLocaleCurrencyString()
*/
@@ -1115,9 +1115,9 @@ v8::Handle<v8::Value> QQmlLocale::localeCompare(const v8::Arguments &args)
This property defines which units are used for measurement.
\list
- \o Locale.MetricSystem This value indicates metric units, such as meters,
+ \li Locale.MetricSystem This value indicates metric units, such as meters,
centimeters and millimeters.
- \o Locale.ImperialSystem This value indicates imperial units, such as inches and
+ \li Locale.ImperialSystem This value indicates imperial units, such as inches and
miles. There are several distinct imperial systems in the world; this
value stands for the official United States imperial units.
\endlist
diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
index cc33f387d9..e5d0d708e2 100644
--- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
+++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
@@ -65,12 +65,12 @@ QT_BEGIN_NAMESPACE
be created in a different thread:
\list
- \o The QML engine internally handles all requests, and cleans up any
+ \li The QML engine internally handles all requests, and cleans up any
QNetworkReply objects it creates. Receiving the
QNetworkAccessManager::finished() signal in another thread may not
provide the receiver with a valid reply object if it has already
been deleted.
- \o Authentication details provided to QNetworkAccessManager::authenticationRequired()
+ \li Authentication details provided to QNetworkAccessManager::authenticationRequired()
must be provided immediately, so this signal cannot be connected as a
Qt::QueuedConnection (or as the default Qt::AutoConnection from another
thread).
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 34d9d0a5f5..d3778fa5c5 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -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>
@@ -1530,24 +1531,6 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
return true;
}
-bool QQmlPropertyPrivate::writeBinding(const QQmlProperty &that,
- QQmlContextData *context,
- QQmlJavaScriptExpression *expression,
- v8::Handle<v8::Value> result, bool isUndefined,
- WriteFlags flags)
-{
- QQmlPropertyPrivate *pp = that.d;
-
- if (!pp)
- return true;
-
- QObject *object = that.object();
- if (!object)
- return true;
-
- return writeBinding(object, pp->core, context, expression, result, isUndefined, flags);
-}
-
const QMetaObject *QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
{
if (engine) {
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 0f97a63155..f4a9ced53b 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -54,6 +54,7 @@
//
#include "qqmlproperty.h"
+#include "qqmlengine.h"
#include <private/qobject_p.h>
#include <private/qtqmlglobal_p.h>
@@ -77,7 +78,7 @@ public:
Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
QQmlContextData *context;
- QQmlEngine *engine;
+ QQmlGuard<QQmlEngine> engine;
QQmlGuard<QObject> object;
QQmlPropertyData core;
@@ -143,11 +144,6 @@ public:
static QQmlExpression *setSignalExpression(const QQmlProperty &that,
QQmlExpression *) ;
static bool write(const QQmlProperty &that, const QVariant &, WriteFlags);
- static bool writeBinding(const QQmlProperty &that,
- QQmlContextData *context,
- QQmlJavaScriptExpression *expression,
- v8::Handle<v8::Value> result, bool isUndefined,
- WriteFlags flags);
static bool writeBinding(QObject *, const QQmlPropertyData &,
QQmlContextData *context,
QQmlJavaScriptExpression *expression,
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 5cbb2f6943..781915e23e 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -63,6 +63,19 @@
#include <dirent.h>
#endif
+#if defined (QT_LINUXBASE)
+// LSB doesn't declare NAME_MAX. Use SYMLINK_MAX instead, which seems to
+// always be identical to NAME_MAX
+#ifndef NAME_MAX
+# define NAME_MAX _POSIX_SYMLINK_MAX
+#endif
+
+// LSB has a broken version of offsetof that can't be used at compile time
+// https://lsbbugs.linuxfoundation.org/show_bug.cgi?id=3462
+#undef offsetof
+#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
+#endif
+
// #define DATABLOB_DEBUG
#ifdef DATABLOB_DEBUG
@@ -248,14 +261,14 @@ The QQmlDataLoader invokes callbacks on the QQmlDataBlob as data becomes availab
This enum describes the status of the data blob.
\list
-\o Null The blob has not yet been loaded by a QQmlDataLoader
-\o Loading The blob is loading network data. The QQmlDataBlob::setData() callback has not yet been
+\li Null The blob has not yet been loaded by a QQmlDataLoader
+\li Loading The blob is loading network data. The QQmlDataBlob::setData() callback has not yet been
invoked or has not yet returned.
-\o WaitingForDependencies The blob is waiting for dependencies to be done before continueing. This status
+\li WaitingForDependencies The blob is waiting for dependencies to be done before continueing. This status
only occurs after the QQmlDataBlob::setData() callback has been made, and when the blob has outstanding
dependencies.
-\o Complete The blob's data has been loaded and all dependencies are done.
-\o Error An error has been set on this blob.
+\li Complete The blob's data has been loaded and all dependencies are done.
+\li Error An error has been set on this blob.
\endlist
*/
@@ -265,9 +278,9 @@ dependencies.
This enum describes the type of the data blob.
\list
-\o QmlFile This is a QQmlTypeData
-\o JavaScriptFile This is a QQmlScriptData
-\o QmldirFile This is a QQmlQmldirData
+\li QmlFile This is a QQmlTypeData
+\li JavaScriptFile This is a QQmlScriptData
+\li QmldirFile This is a QQmlQmldirData
\endlist
*/
@@ -877,9 +890,9 @@ To complete processing, the QQmlDataBlob::done() callback is invoked. done() is
one of these three preconditions are met.
\list 1
-\o The QQmlDataBlob has no dependencies.
-\o The QQmlDataBlob has an error set.
-\o All the QQmlDataBlob's dependencies are themselves "done()".
+\li The QQmlDataBlob has no dependencies.
+\li The QQmlDataBlob has an error set.
+\li All the QQmlDataBlob's dependencies are themselves "done()".
\endlist
Thus QQmlDataBlob::done() will always eventually be called, even if the blob has an error set.
@@ -1171,7 +1184,7 @@ This enum defines the options that control the way type data is handled.
/*!
Returns a QQmlTypeData for the specified \a url. The QQmlTypeData may be cached.
*/
-QQmlTypeData *QQmlTypeLoader::get(const QUrl &url)
+QQmlTypeData *QQmlTypeLoader::get(const QUrl &url, Mode mode)
{
Q_ASSERT(!url.isRelative() &&
(QQmlEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
@@ -1184,7 +1197,7 @@ QQmlTypeData *QQmlTypeLoader::get(const QUrl &url)
if (!typeData) {
typeData = new QQmlTypeData(url, None, this);
m_typeCache.insert(url, typeData);
- QQmlDataLoader::load(typeData);
+ QQmlDataLoader::load(typeData, mode);
}
typeData->addref();
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 0dd7adecac..c8c2756bd5 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -236,7 +236,7 @@ public:
};
Q_DECLARE_FLAGS(Options, Option)
- QQmlTypeData *get(const QUrl &url);
+ QQmlTypeData *get(const QUrl &url, Mode mode = PreferSynchronous);
QQmlTypeData *get(const QByteArray &, const QUrl &url, Options = None);
void clearCache();
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
new file mode 100644
index 0000000000..2cc15a50f5
--- /dev/null
+++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
@@ -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/qqmlbinding_p_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
index b53c903916..0135d575df 100644
--- a/src/qml/qml/qqmlbinding_p_p.h
+++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QQMLBINDING_P_P_H
-#define QQMLBINDING_P_P_H
+#ifndef QQMLVALUETYPEPROXYBINDING_P_H
+#define QQMLVALUETYPEPROXYBINDING_P_H
//
// W A R N I N G
@@ -53,37 +53,39 @@
// We mean it.
//
-#include "qqmlbinding_p.h"
-
-#include "qqmlproperty.h"
-#include "qqmlexpression_p.h"
+#include <private/qqmlabstractbinding_p.h>
QT_BEGIN_NAMESPACE
-class QQmlBindingPrivate : public QQmlExpressionPrivate
+class QQmlValueTypeProxyBinding : public QQmlAbstractBinding
{
- Q_DECLARE_PUBLIC(QQmlBinding)
public:
- QQmlBindingPrivate();
- ~QQmlBindingPrivate();
+ 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;
- virtual void expressionChanged();
+ QQmlAbstractBinding *binding(int propertyIndex);
- static void printBindingLoopError(QQmlProperty &prop);
+ void removeBindings(quint32 mask);
protected:
- virtual void refresh();
+ ~QQmlValueTypeProxyBinding();
private:
- bool updating:1;
- bool enabled:1;
- int columnNumber;
- QQmlProperty property;
+ void recursiveEnable(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags);
+ void recursiveDisable(QQmlAbstractBinding *);
- QObject *target;
- int targetProperty;
+ friend class QQmlAbstractBinding;
+ QObject *m_object;
+ int m_index;
+ QQmlAbstractBinding *m_bindings;
};
QT_END_NAMESPACE
-#endif // QQMLBINDING_P_P_H
+#endif // QQMLVALUETYPEPROXYBINDING_P_H
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 9ef9ca96ef..86e9f0963a 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -57,7 +57,6 @@
#include "qqmlengine_p.h"
#include "qqmlcomponent_p.h"
#include "qqmlvmemetaobject_p.h"
-#include "qqmlbinding_p_p.h"
#include "qqmlcontext_p.h"
#include <private/qv4bindings_p.h>
#include <private/qv8bindings_p.h>
@@ -66,6 +65,7 @@
#include "qqmlscriptstring.h"
#include "qqmlscriptstring_p.h"
#include "qqmlpropertyvalueinterceptor_p.h"
+#include "qqmlvaluetypeproxybinding_p.h"
#include <QStack>
#include <QColor>
@@ -767,8 +767,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_NEXT_INSTR(StoreBinding);
QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true,
- context, CTXT, COMP->name, instr.line,
- instr.column);
+ context, CTXT, COMP->name, instr.line,
+ instr.column);
bindValues.push(bind);
bind->m_mePtr = &bindValues.top();
bind->setTarget(target, instr.property, CTXT);
@@ -790,8 +790,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_NEXT_INSTR(StoreBindingOnAlias);
QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true,
- context, CTXT, COMP->name, instr.line,
- instr.column);
+ context, CTXT, COMP->name, instr.line,
+ instr.column);
bindValues.push(bind);
bind->m_mePtr = &bindValues.top();
bind->setTarget(target, instr.property, CTXT);
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index a7af2db837..c4e801f2db 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -56,6 +56,28 @@ Q_DECLARE_METATYPE(QJSValue);
QT_BEGIN_NAMESPACE
+QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
+ : QQmlGuard<QObject>(0), m_target(0), m_index(-1)
+{
+}
+
+QQmlVMEVariantQObjectPtr::~QQmlVMEVariantQObjectPtr()
+{
+}
+
+void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
+{
+ if (m_target && m_index >= 0)
+ m_target->activate(m_target->object, m_target->methodOffset + m_index, 0);
+}
+
+void QQmlVMEVariantQObjectPtr::setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index)
+{
+ m_target = target;
+ m_index = index;
+ setObject(obj);
+}
+
class QQmlVMEVariant
{
public:
@@ -79,7 +101,7 @@ public:
inline const QDateTime &asQDateTime();
inline const QJSValue &asQJSValue();
- inline void setValue(QObject *);
+ inline void setValue(QObject *v, QQmlVMEMetaObject *target, int index);
inline void setValue(const QVariant &);
inline void setValue(int);
inline void setValue(bool);
@@ -93,7 +115,7 @@ public:
inline void setValue(const QJSValue &);
private:
int type;
- void *data[4]; // Large enough to hold all types
+ void *data[6]; // Large enough to hold all types
inline void cleanup();
};
@@ -127,7 +149,7 @@ void QQmlVMEVariant::cleanup()
type == QMetaType::Double) {
type = QVariant::Invalid;
} else if (type == QMetaType::QObjectStar) {
- ((QQmlGuard<QObject>*)dataPtr())->~QQmlGuard<QObject>();
+ ((QQmlVMEVariantQObjectPtr*)dataPtr())->~QQmlVMEVariantQObjectPtr();
type = QVariant::Invalid;
} else if (type == QMetaType::QString) {
((QString *)dataPtr())->~QString();
@@ -174,8 +196,8 @@ void *QQmlVMEVariant::dataPtr()
QObject *QQmlVMEVariant::asQObject()
{
- if (type != QMetaType::QObjectStar)
- setValue((QObject *)0);
+ if (type != QMetaType::QObjectStar)
+ setValue((QObject *)0, 0, -1);
return *(QQmlGuard<QObject> *)(dataPtr());
}
@@ -268,14 +290,14 @@ const QJSValue &QQmlVMEVariant::asQJSValue()
return *(QJSValue *)(dataPtr());
}
-void QQmlVMEVariant::setValue(QObject *v)
+void QQmlVMEVariant::setValue(QObject *v, QQmlVMEMetaObject *target, int index)
{
if (type != QMetaType::QObjectStar) {
cleanup();
type = QMetaType::QObjectStar;
- new (dataPtr()) QQmlGuard<QObject>();
+ new (dataPtr()) QQmlVMEVariantQObjectPtr;
}
- *(QQmlGuard<QObject>*)(dataPtr()) = v;
+ reinterpret_cast<QQmlVMEVariantQObjectPtr*>(dataPtr())->setGuardedValue(v, target, index);
}
void QQmlVMEVariant::setValue(const QVariant &v)
@@ -629,7 +651,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
break;
case QMetaType::QObjectStar:
needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject();
- data[id].setValue(*reinterpret_cast<QObject **>(a[0]));
+ data[id].setValue(*reinterpret_cast<QObject **>(a[0]), this, id);
break;
case QMetaType::QVariant:
writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
@@ -810,15 +832,17 @@ v8::Handle<v8::Value> QQmlVMEMetaObject::readVarProperty(int id)
{
Q_ASSERT(id >= firstVarPropertyIndex);
- ensureVarPropertiesAllocated();
- return varProperties->Get(id - firstVarPropertyIndex);
+ if (ensureVarPropertiesAllocated())
+ return varProperties->Get(id - firstVarPropertyIndex);
+ return v8::Handle<v8::Value>();
}
QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
{
if (id >= firstVarPropertyIndex) {
- ensureVarPropertiesAllocated();
- return QQmlEnginePrivate::get(ctxt->engine)->v8engine()->toVariant(varProperties->Get(id - firstVarPropertyIndex), -1);
+ if (ensureVarPropertiesAllocated())
+ return QQmlEnginePrivate::get(ctxt->engine)->v8engine()->toVariant(varProperties->Get(id - firstVarPropertyIndex), -1);
+ return QVariant();
} else {
if (data[id].dataType() == QMetaType::QObjectStar) {
return QVariant::fromValue(data[id].asQObject());
@@ -831,7 +855,8 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
{
Q_ASSERT(id >= firstVarPropertyIndex);
- ensureVarPropertiesAllocated();
+ if (!ensureVarPropertiesAllocated())
+ return;
// Importantly, if the current value is a scarce resource, we need to ensure that it
// gets automatically released by the engine if no other references to it exist.
@@ -860,7 +885,8 @@ void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
{
if (id >= firstVarPropertyIndex) {
- ensureVarPropertiesAllocated();
+ if (!ensureVarPropertiesAllocated())
+ return;
// Importantly, if the current value is a scarce resource, we need to ensure that it
// gets automatically released by the engine if no other references to it exist.
@@ -892,7 +918,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
if (value.userType() == QMetaType::QObjectStar) {
QObject *o = qvariant_cast<QObject *>(value);
needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o);
- data[id].setValue(qvariant_cast<QObject *>(value));
+ data[id].setValue(qvariant_cast<QObject *>(value), this, id);
} else {
needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() ||
data[id].asQVariant().userType() != value.userType() ||
@@ -1007,10 +1033,17 @@ void QQmlVMEMetaObject::setVMEProperty(int index, v8::Handle<v8::Value> v)
return writeVarProperty(index - propOffset, v);
}
-void QQmlVMEMetaObject::ensureVarPropertiesAllocated()
+bool QQmlVMEMetaObject::ensureVarPropertiesAllocated()
{
if (!varPropertiesInitialized)
allocateVarPropertiesArray();
+
+ // in some situations, the QObject's v8object (and associated v8 data,
+ // such as the varProperties array) will have been cleaned up, but the
+ // QObject ptr will not yet have been deleted (eg, waiting on deleteLater).
+ // In this situation, the varProperties handle will be (and should remain)
+ // empty.
+ return !varProperties.IsEmpty();
}
// see also: QV8GCCallback::garbageCollectorPrologueCallback()
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index deee989383..1b5ceb8203 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -136,6 +136,19 @@ struct QQmlVMEMetaData
}
};
+class QQmlVMEMetaObject;
+class QQmlVMEVariantQObjectPtr : public QQmlGuard<QObject>
+{
+public:
+ inline QQmlVMEVariantQObjectPtr();
+ inline ~QQmlVMEVariantQObjectPtr();
+ inline void objectDestroyed(QObject *);
+ inline void setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index);
+
+ QQmlVMEMetaObject *m_target;
+ int m_index;
+};
+
class QV8QObjectWrapper;
class QQmlVMEVariant;
class QQmlRefCount;
@@ -163,6 +176,7 @@ protected:
private:
friend class QQmlVMEMetaObjectEndpoint;
+ friend class QQmlVMEVariantQObjectPtr;
QObject *object;
QQmlCompiledData *compiledData;
@@ -181,7 +195,7 @@ private:
static void VarPropertiesWeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter);
static void GcPrologueCallback(QV8GCCallback::Node *node);
inline void allocateVarPropertiesArray();
- inline void ensureVarPropertiesAllocated();
+ inline bool ensureVarPropertiesAllocated();
void connectAlias(int aliasId);
QBitArray aConnected;
diff --git a/src/qml/qml/qquickworkerscript.cpp b/src/qml/qml/qquickworkerscript.cpp
index 529f181e7a..e689f9da72 100644
--- a/src/qml/qml/qquickworkerscript.cpp
+++ b/src/qml/qml/qquickworkerscript.cpp
@@ -640,9 +640,9 @@ void QQuickWorkerScript::setSource(const QUrl &source)
types:
\list
- \o boolean, number, string
- \o JavaScript objects and arrays
- \o ListModel objects (any other type of QObject* is not allowed)
+ \li boolean, number, string
+ \li JavaScript objects and arrays
+ \li ListModel objects (any other type of QObject* is not allowed)
\endlist
All objects and arrays are copied to the \c message. With the exception
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
index 93c7820ca2..5d367f2ae6 100644
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -66,6 +66,7 @@ struct Register {
typedef QQmlRegisterType Type;
void setUndefined() { dataType = UndefinedType; }
+ void setNull() { dataType = NullType; }
void setNaN() { setqreal(qSNaN()); }
bool isUndefined() const { return dataType == UndefinedType; }
@@ -820,6 +821,29 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
registers[instr->load.reg].setQObject(context->contextObject);
QML_V4_END_INSTR(LoadRoot, load)
+ QML_V4_BEGIN_INSTR(LoadModuleObject, load)
+ {
+ Register &reg = registers[instr->load.reg];
+
+ const QString *name = reg.getstringptr();
+ QQmlTypeNameCache::Result r = context->imports->query(*name);
+ reg.cleanupString();
+
+ if (r.isValid() && r.importNamespace) {
+ QQmlMetaType::ModuleApiInstance *moduleApi = context->imports->moduleApi(r.importNamespace);
+ if (moduleApi) {
+ if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(context->engine, context->engine);
+ moduleApi->qobjectCallback = 0;
+ moduleApi->scriptCallback = 0;
+ }
+ if (moduleApi->qobjectApi)
+ reg.setQObject(moduleApi->qobjectApi);
+ }
+ }
+ }
+ QML_V4_END_INSTR(LoadModuleObject, load)
+
QML_V4_BEGIN_INSTR(LoadAttached, attached)
{
const Register &input = registers[instr->attached.reg];
@@ -1216,6 +1240,10 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(MathPIReal, unaryop)
+ QML_V4_BEGIN_INSTR(LoadNull, null_value)
+ registers[instr->null_value.reg].setNull();
+ QML_V4_END_INSTR(LoadNull, null_value)
+
QML_V4_BEGIN_INSTR(LoadReal, real_value)
registers[instr->real_value.reg].setqreal(instr->real_value.value);
QML_V4_END_INSTR(LoadReal, real_value)
@@ -1498,6 +1526,46 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(StrictNotEqualString, binaryop)
+ QML_V4_BEGIN_INSTR(EqualObject, binaryop)
+ {
+ const Register &left = registers[instr->binaryop.left];
+ const Register &right = registers[instr->binaryop.right];
+ QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
+ QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
+ registers[instr->binaryop.output].setbool(leftobj == rightobj);
+ }
+ QML_V4_END_INSTR(EqualObject, binaryop)
+
+ QML_V4_BEGIN_INSTR(NotEqualObject, binaryop)
+ {
+ const Register &left = registers[instr->binaryop.left];
+ const Register &right = registers[instr->binaryop.right];
+ QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
+ QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
+ registers[instr->binaryop.output].setbool(leftobj != rightobj);
+ }
+ QML_V4_END_INSTR(NotEqualObject, binaryop)
+
+ QML_V4_BEGIN_INSTR(StrictEqualObject, binaryop)
+ {
+ const Register &left = registers[instr->binaryop.left];
+ const Register &right = registers[instr->binaryop.right];
+ QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
+ QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
+ registers[instr->binaryop.output].setbool(leftobj == rightobj);
+ }
+ QML_V4_END_INSTR(StrictEqualObject, binaryop)
+
+ QML_V4_BEGIN_INSTR(StrictNotEqualObject, binaryop)
+ {
+ const Register &left = registers[instr->binaryop.left];
+ const Register &right = registers[instr->binaryop.right];
+ QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
+ QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
+ registers[instr->binaryop.output].setbool(leftobj != rightobj);
+ }
+ QML_V4_END_INSTR(StrictNotEqualObject, binaryop)
+
QML_V4_BEGIN_INSTR(MathMaxReal, binaryop)
{
const Register &left = registers[instr->binaryop.left];
diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp
index 620d260053..09b0f3861b 100644
--- a/src/qml/qml/v4/qv4compiler.cpp
+++ b/src/qml/qml/v4/qv4compiler.cpp
@@ -234,6 +234,12 @@ void QV4CompilerPrivate::visitConst(IR::Const *e)
gen(i);
} break;
+ case IR::NullType: {
+ Instr::LoadNull i;
+ i.reg = currentReg;
+ gen(i);
+ } break;
+
default:
if (qmlVerboseCompiler())
qWarning() << Q_FUNC_INFO << "unexpected type";
@@ -318,6 +324,22 @@ void QV4CompilerPrivate::visitName(IR::Name *e)
gen(attached);
} break;
+ case IR::Name::ModuleObject: {
+ /*
+ Existing module object lookup methods include:
+ 1. string -> module object (search via importCache->query(name))
+ 2. QQmlMetaType::ModuleApi -> module object (via QQmlEnginePrivate::moduleApiInstance() cache)
+ We currently use 1, which is not ideal for performance
+ */
+ _subscribeName << *e->id;
+
+ registerLiteralString(currentReg, e->id);
+
+ Instr::LoadModuleObject module;
+ module.reg = currentReg;
+ gen(module);
+ } break;
+
case IR::Name::Property: {
_subscribeName << *e->id;
@@ -666,21 +688,29 @@ quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e)
return V4Instr::LeReal;
case IR::OpEqual:
+ if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
+ return V4Instr::EqualObject;
if (e->left->type == IR::StringType)
return V4Instr::EqualString;
return V4Instr::EqualReal;
case IR::OpNotEqual:
+ if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
+ return V4Instr::NotEqualObject;
if (e->left->type == IR::StringType)
return V4Instr::NotEqualString;
return V4Instr::NotEqualReal;
case IR::OpStrictEqual:
+ if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
+ return V4Instr::StrictEqualObject;
if (e->left->type == IR::StringType)
return V4Instr::StrictEqualString;
return V4Instr::StrictEqualReal;
case IR::OpStrictNotEqual:
+ if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
+ return V4Instr::StrictNotEqualObject;
if (e->left->type == IR::StringType)
return V4Instr::StrictNotEqualString;
return V4Instr::StrictNotEqualReal;
@@ -758,7 +788,7 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e)
case IR::OpNotEqual:
case IR::OpStrictEqual:
case IR::OpStrictNotEqual:
- if (e->left->type != IR::StringType) {
+ if (e->left->type >= IR::FirstNumberType) {
convertToReal(e->left, left);
convertToReal(e->right, right);
}
diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp
index a392c9392c..1ed8bd245e 100644
--- a/src/qml/qml/v4/qv4instruction.cpp
+++ b/src/qml/qml/v4/qv4instruction.cpp
@@ -114,6 +114,9 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::LoadRoot:
INSTR_DUMP << "\t" << "LoadRoot" << "\t\t" << "-> Output_Reg(" << i->load.reg << ")";
break;
+ case V4Instr::LoadModuleObject:
+ INSTR_DUMP << "\t" << "LoadModuleObject" << "\t\t" << ") -> Output_Reg(" << i->load.reg << ")";
+ break;
case V4Instr::LoadAttached:
INSTR_DUMP << "\t" << "LoadAttached" << "\t\t" << "Object_Reg(" << i->attached.reg << ") Attached_Index(" << i->attached.id << ") -> Output_Reg(" << i->attached.output << ")";
break;
@@ -210,6 +213,9 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::MathPIReal:
INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
+ case V4Instr::LoadNull:
+ INSTR_DUMP << "\t" << "LoadNull" << "\t\t" << "Constant(null) -> Output_Reg(" << i->null_value.reg << ")";
+ break;
case V4Instr::LoadReal:
INSTR_DUMP << "\t" << "LoadReal" << "\t\t" << "Constant(" << i->real_value.value << ") -> Output_Reg(" << i->real_value.reg << ")";
break;
@@ -312,6 +318,18 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::StrictNotEqualString:
INSTR_DUMP << "\t" << "StrictNotEqualString" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
+ case V4Instr::EqualObject:
+ INSTR_DUMP << "\t" << "EqualObject" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::NotEqualObject:
+ INSTR_DUMP << "\t" << "NotEqualObject" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::StrictEqualObject:
+ INSTR_DUMP << "\t" << "StrictEqualObject" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::StrictNotEqualObject:
+ INSTR_DUMP << "\t" << "StrictNotEqualObject" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
case V4Instr::MathMaxReal:
INSTR_DUMP << "\t" << "MathMaxReal" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h
index 9727c23959..d6c790e46f 100644
--- a/src/qml/qml/v4/qv4instruction_p.h
+++ b/src/qml/qml/v4/qv4instruction_p.h
@@ -73,6 +73,7 @@ QT_BEGIN_NAMESPACE
F(LoadId, load) \
F(LoadScope, load) \
F(LoadRoot, load) \
+ F(LoadModuleObject, load) \
F(LoadAttached, attached) \
F(UnaryNot, unaryop) \
F(UnaryMinusReal, unaryop) \
@@ -105,6 +106,7 @@ QT_BEGIN_NAMESPACE
F(MathFloorReal, unaryop) \
F(MathCeilReal, unaryop) \
F(MathPIReal, unaryop) \
+ F(LoadNull, null_value) \
F(LoadReal, real_value) \
F(LoadInt, int_value) \
F(LoadBool, bool_value) \
@@ -139,6 +141,10 @@ QT_BEGIN_NAMESPACE
F(NotEqualString, binaryop) \
F(StrictEqualString, binaryop) \
F(StrictNotEqualString, binaryop) \
+ F(EqualObject, binaryop) \
+ F(NotEqualObject, binaryop) \
+ F(StrictEqualObject, binaryop) \
+ F(StrictNotEqualObject, binaryop) \
F(MathMaxReal, binaryop) \
F(MathMinReal, binaryop) \
F(NewString, construct) \
@@ -270,6 +276,11 @@ union V4Instr {
qint8 reg;
};
+ struct instr_null_value {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ };
+
struct instr_real_value {
QML_V4_INSTR_HEADER
qint8 reg;
@@ -357,6 +368,7 @@ union V4Instr {
instr_fetch fetch;
instr_copy copy;
instr_construct construct;
+ instr_null_value null_value;
instr_real_value real_value;
instr_int_value int_value;
instr_bool_value bool_value;
diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp
index 54679c3d8c..34245f5bf4 100644
--- a/src/qml/qml/v4/qv4ir.cpp
+++ b/src/qml/qml/v4/qv4ir.cpp
@@ -543,6 +543,17 @@ Name *BasicBlock::ATTACH_TYPE(const QString &id, const QQmlType *attachType, Nam
return name;
}
+Name *BasicBlock::MODULE_OBJECT(const QString &id, const QMetaObject *meta, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = function->pool->New<Name>();
+ name->init(/*base = */ 0, IR::ObjectType,
+ function->newString(id),
+ Name::ModuleObject, line, column);
+ name->meta = meta;
+ name->storage = storage;
+ return name;
+}
Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
{
@@ -675,6 +686,8 @@ static const char *symbolname(Name::Symbol s)
return "IdObject";
case Name::AttachType:
return "AttachType";
+ case Name::ModuleObject:
+ return "ModuleObject";
case Name::Object:
return "Object";
case Name::Property:
diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h
index 79f50cd6c9..4e9f9faacd 100644
--- a/src/qml/qml/v4/qv4ir_p.h
+++ b/src/qml/qml/v4/qv4ir_p.h
@@ -252,6 +252,7 @@ struct Name: Expr {
Unbound,
IdObject, // This is a load of a id object. Storage will always be IdStorage
AttachType, // This is a load of an attached object
+ ModuleObject, // This is a load of a module object
Object, // XXX what is this for?
Property, // This is a load of a regular property
Slot // XXX what is this for?
@@ -538,6 +539,7 @@ struct BasicBlock {
Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, Name::Storage storage, quint32 line, quint32 column);
Name *ID_OBJECT(const QString &id, const QQmlScript::Object *object, quint32 line, quint32 column);
Name *ATTACH_TYPE(const QString &id, const QQmlType *attachType, Name::Storage storage, quint32 line, quint32 column);
+ Name *MODULE_OBJECT(const QString &id, const QMetaObject *meta, Name::Storage storage, quint32 line, quint32 column);
Expr *UNOP(AluOp op, Expr *expr);
Expr *BINOP(AluOp op, Expr *left, Expr *right);
diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp
index 06f4024423..481b23eb4a 100644
--- a/src/qml/qml/v4/qv4irbuilder.cpp
+++ b/src/qml/qml/v4/qv4irbuilder.cpp
@@ -428,6 +428,17 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast)
if (r.isValid()) {
if (r.type) {
_expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column);
+ } else if (r.importNamespace) {
+ QQmlMetaType::ModuleApiInstance *moduleApi = m_expression->importCache->moduleApi(r.importNamespace);
+ if (moduleApi) {
+ if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(QQmlEnginePrivate::get(m_engine), QQmlEnginePrivate::get(m_engine));
+ moduleApi->qobjectCallback = 0;
+ moduleApi->scriptCallback = 0;
+ }
+ if (moduleApi->qobjectApi)
+ _expr.code = _block->MODULE_OBJECT(name, moduleApi->qobjectApi->metaObject(), IR::Name::MemberStorage, line, column);
+ }
}
// We don't support anything else
} else {
@@ -603,6 +614,46 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
}
break;
+ case IR::Name::ModuleObject: {
+ if (name.at(0).isUpper()) {
+ QByteArray utf8Name = name.toUtf8();
+ const char *enumName = utf8Name.constData();
+
+ const QMetaObject *meta = baseName->meta;
+ bool found = false;
+ for (int ii = 0; !found && ii < meta->enumeratorCount(); ++ii) {
+ QMetaEnum e = meta->enumerator(ii);
+ for (int jj = 0; !found && jj < e.keyCount(); ++jj) {
+ if (0 == strcmp(e.key(jj), enumName)) {
+ found = true;
+ _expr.code = _block->CONST(IR::IntType, e.value(jj));
+ }
+ }
+ }
+ if (!found && qmlVerboseCompiler())
+ qWarning() << "*** unresolved enum:"
+ << (*baseName->id + QLatin1String(".") + ast->name.toString());
+ } else {
+ QQmlPropertyCache *cache = m_engine->cache(baseName->meta);
+ if (!cache) return false;
+ QQmlPropertyData *data = cache->property(name);
+
+ if (!data || data->isFunction())
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if (!data->isFinal()) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** non-final attached property:"
+ << (*baseName->id + QLatin1String(".") + ast->name.toString());
+ return false; // We don't know enough about this property
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, baseName->meta);
+ _expr.code = _block->SYMBOL(baseName, irType, name, baseName->meta, data, line, column);
+ }
+ }
+ break;
+
case IR::Name::IdObject: {
const QQmlScript::Object *idObject = baseName->idObject;
QQmlPropertyCache *cache =
@@ -830,13 +881,15 @@ void QV4IRBuilder::binop(AST::BinaryExpression *ast, ExprResult left, ExprResult
implicitCvt(left, t);
implicitCvt(right, t);
}
+ } else if ((left.type() != IR::ObjectType && left.type() != IR::NullType) ||
+ (right.type() != IR::ObjectType && right.type() != IR::NullType))
+ return;
- if (_expr.hint == ExprResult::cx) {
- _expr.format = ExprResult::cx;
- _block->CJUMP(_block->BINOP(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
- } else {
- _expr.code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
- }
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->CJUMP(_block->BINOP(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
+ } else {
+ _expr.code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
}
}
@@ -860,12 +913,15 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
IR::BasicBlock *iffalse = _function->newBasicBlock();
IR::BasicBlock *endif = _function->newBasicBlock();
- condition(ast->left, iftrue, iffalse);
+ ExprResult left = expression(ast->left);
+ IR::Temp *cond = _block->TEMP(IR::BoolType);
+ _block->MOVE(cond, left);
+ _block->CJUMP(cond, iftrue, iffalse);
IR::Temp *r = _block->TEMP(IR::InvalidType);
_block = iffalse;
- _block->MOVE(r, _block->CONST(IR::BoolType, 0)); // ### use the right null value
+ _block->MOVE(r, cond);
_block->JUMP(endif);
_block = iftrue;
@@ -873,9 +929,12 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
_block->MOVE(r, right);
_block->JUMP(endif);
+ if (left.type() != right.type())
+ discard();
+
_block = endif;
- r->type = right.type(); // ### not exactly, it can be IR::BoolType.
+ r->type = right.type();
_expr.code = r;
}
} break;
@@ -942,9 +1001,6 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
implicitCvt(left, IR::RealType);
implicitCvt(right, IR::RealType);
binop(ast, left, right);
- } else if (left.type() == IR::BoolType || right.type() == IR::BoolType) {
- implicitCvt(left, IR::BoolType);
- implicitCvt(right, IR::BoolType);
} else if (left.isValid() && right.isValid()) {
binop(ast, left, right);
}
@@ -956,16 +1012,21 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
ExprResult right = expression(ast->right);
if (left.type() == right.type()) {
binop(ast, left, right);
- } else if (left.type() >= IR::BoolType && right.type() >= IR::BoolType) {
+ } else if (left.type() > IR::BoolType && right.type() > IR::BoolType) {
// left and right have numeric type (int or real)
binop(ast, left, right);
+ } else if ((left.type() == IR::ObjectType && right.type() == IR::NullType) ||
+ (right.type() == IR::ObjectType && left.type() == IR::NullType)) {
+ // comparing a qobject with null
+ binop(ast, left, right);
} else if (left.isValid() && right.isValid()) {
+ // left and right have different types
const bool isEq = ast->op == QSOperator::StrictEqual;
if (_expr.hint == ExprResult::cx) {
_expr.format = ExprResult::cx;
- _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
+ _block->JUMP(isEq ? _expr.iffalse : _expr.iftrue);
} else {
- _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
+ _expr.code = _block->CONST(IR::BoolType, isEq ? 0 : 1);
}
}
} break;
diff --git a/src/qml/qml/v4/qv4program_p.h b/src/qml/qml/v4/qv4program_p.h
index d23cc6192f..60e7403786 100644
--- a/src/qml/qml/v4/qv4program_p.h
+++ b/src/qml/qml/v4/qv4program_p.h
@@ -85,6 +85,7 @@ struct QV4Program {
enum QQmlRegisterType {
UndefinedType,
+ NullType,
QObjectStarType,
QRealType,
IntType,
diff --git a/src/qml/qml/v8/qjsengine.cpp b/src/qml/qml/v8/qjsengine.cpp
index 3121d1b361..92c968f9aa 100644
--- a/src/qml/qml/v8/qjsengine.cpp
+++ b/src/qml/qml/v8/qjsengine.cpp
@@ -92,7 +92,7 @@ Q_DECLARE_METATYPE(QList<int>)
\section1 Engine Configuration
- The globalObject() function returns the \bold {Global Object}
+ The globalObject() function returns the \b {Global Object}
associated with the script engine. Properties of the Global Object
are accessible from any script code (i.e. they are global
variables). Typically, before evaluating "user" scripts, you will
diff --git a/src/qml/qml/v8/qjsvalue.cpp b/src/qml/qml/v8/qjsvalue.cpp
index e0a925c3bb..4471e68a61 100644
--- a/src/qml/qml/v8/qjsvalue.cpp
+++ b/src/qml/qml/v8/qjsvalue.cpp
@@ -426,18 +426,18 @@ quint32 QJSValue::toUInt() const
The conversion is performed according to the following table:
\table
- \header \o Input Type \o Result
- \row \o Undefined \o An invalid QVariant.
- \row \o Null \o An invalid QVariant.
- \row \o Boolean \o A QVariant containing the value of the boolean.
- \row \o Number \o A QVariant containing the value of the number.
- \row \o String \o A QVariant containing the value of the string.
- \row \o QVariant Object \o The result is the QVariant value of the object (no conversion).
- \row \o QObject Object \o A QVariant containing a pointer to the QObject.
- \row \o Date Object \o A QVariant containing the date value (toDateTime()).
- \row \o RegExp Object \o A QVariant containing the regular expression value.
- \row \o Array Object \o The array is converted to a QVariantList. Each element is converted to a QVariant, recursively; cyclic references are not followed.
- \row \o Object \o The object is converted to a QVariantMap. Each property is converted to a QVariant, recursively; cyclic references are not followed.
+ \header \li Input Type \li Result
+ \row \li Undefined \li An invalid QVariant.
+ \row \li Null \li An invalid QVariant.
+ \row \li Boolean \li A QVariant containing the value of the boolean.
+ \row \li Number \li A QVariant containing the value of the number.
+ \row \li String \li A QVariant containing the value of the string.
+ \row \li QVariant Object \li The result is the QVariant value of the object (no conversion).
+ \row \li QObject Object \li A QVariant containing a pointer to the QObject.
+ \row \li Date Object \li A QVariant containing the date value (toDateTime()).
+ \row \li RegExp Object \li A QVariant containing the regular expression value.
+ \row \li Array Object \li The array is converted to a QVariantList. Each element is converted to a QVariant, recursively; cyclic references are not followed.
+ \row \li Object \li The object is converted to a QVariantMap. Each property is converted to a QVariant, recursively; cyclic references are not followed.
\endtable
\sa isVariant()
@@ -634,13 +634,13 @@ bool QJSValue::equals(const QJSValue& other) const
the result depends on the type, as shown in the following table:
\table
- \header \o Type \o Result
- \row \o Undefined \o true
- \row \o Null \o true
- \row \o Boolean \o true if both values are true, false otherwise
- \row \o Number \o false if either value is NaN (Not-a-Number); true if values are equal, false otherwise
- \row \o String \o true if both values are exactly the same sequence of characters, false otherwise
- \row \o Object \o true if both values refer to the same object, false otherwise
+ \header \li Type \li Result
+ \row \li Undefined \li true
+ \row \li Null \li true
+ \row \li Boolean \li true if both values are true, false otherwise
+ \row \li Number \li false if either value is NaN (Not-a-Number); true if values are equal, false otherwise
+ \row \li String \li true if both values are exactly the same sequence of characters, false otherwise
+ \row \li Object \li true if both values refer to the same object, false otherwise
\endtable
\sa equals()
@@ -737,11 +737,11 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
delete operator. In particular:
\list
- \o Non-configurable properties cannot be deleted.
- \o This function will return true even if this object doesn't
+ \li Non-configurable properties cannot be deleted.
+ \li This function will return true even if this object doesn't
have a property of the given \a name (i.e., non-existent
properties are "trivially deletable").
- \o If this object doesn't have an own property of the given
+ \li If this object doesn't have an own property of the given
\a name, but an object in the prototype() chain does, the
prototype object's property is not deleted, and this function
returns true.
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 143ccee960..68c62ef240 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -797,54 +797,54 @@ If \a format is not provided, \a dateTime is formatted using
\a format should be either:
\list
-\o One of the Qt::DateFormat enumeration values, such as
+\li One of the Qt::DateFormat enumeration values, such as
\c Qt.DefaultLocaleShortDate or \c Qt.ISODate
-\o A string that specifies the format of the returned string, as detailed below.
+\li A string that specifies the format of the returned string, as detailed below.
\endlist
If \a format specifies a format string, it should use the following expressions
to specify the date:
\table
- \header \i Expression \i Output
- \row \i d \i the day as number without a leading zero (1 to 31)
- \row \i dd \i the day as number with a leading zero (01 to 31)
- \row \i ddd
- \i the abbreviated localized day name (e.g. 'Mon' to 'Sun').
+ \header \li Expression \li Output
+ \row \li d \li the day as number without a leading zero (1 to 31)
+ \row \li dd \li the day as number with a leading zero (01 to 31)
+ \row \li ddd
+ \li the abbreviated localized day name (e.g. 'Mon' to 'Sun').
Uses QDate::shortDayName().
- \row \i dddd
- \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
+ \row \li dddd
+ \li the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
Uses QDate::longDayName().
- \row \i M \i the month as number without a leading zero (1-12)
- \row \i MM \i the month as number with a leading zero (01-12)
- \row \i MMM
- \i the abbreviated localized month name (e.g. 'Jan' to 'Dec').
+ \row \li M \li the month as number without a leading zero (1-12)
+ \row \li MM \li the month as number with a leading zero (01-12)
+ \row \li MMM
+ \li the abbreviated localized month name (e.g. 'Jan' to 'Dec').
Uses QDate::shortMonthName().
- \row \i MMMM
- \i the long localized month name (e.g. 'January' to 'December').
+ \row \li MMMM
+ \li the long localized month name (e.g. 'January' to 'December').
Uses QDate::longMonthName().
- \row \i yy \i the year as two digit number (00-99)
- \row \i yyyy \i the year as four digit number
+ \row \li yy \li the year as two digit number (00-99)
+ \row \li yyyy \li the year as four digit number
\endtable
In addition the following expressions can be used to specify the time:
\table
- \header \i Expression \i Output
- \row \i h
- \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
- \row \i hh
- \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
- \row \i m \i the minute without a leading zero (0 to 59)
- \row \i mm \i the minute with a leading zero (00 to 59)
- \row \i s \i the second without a leading zero (0 to 59)
- \row \i ss \i the second with a leading zero (00 to 59)
- \row \i z \i the milliseconds without leading zeroes (0 to 999)
- \row \i zzz \i the milliseconds with leading zeroes (000 to 999)
- \row \i AP
- \i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
- \row \i ap
- \i use am/pm display. \e ap will be replaced by either "am" or "pm".
+ \header \li Expression \li Output
+ \row \li h
+ \li the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
+ \row \li hh
+ \li the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
+ \row \li m \li the minute without a leading zero (0 to 59)
+ \row \li mm \li the minute with a leading zero (00 to 59)
+ \row \li s \li the second without a leading zero (0 to 59)
+ \row \li ss \li the second with a leading zero (00 to 59)
+ \row \li z \li the milliseconds without leading zeroes (0 to 999)
+ \row \li zzz \li the milliseconds with leading zeroes (000 to 999)
+ \row \li AP
+ \li use AM/PM display. \e AP will be replaced by either "AM" or "PM".
+ \row \li ap
+ \li use am/pm display. \e ap will be replaced by either "am" or "pm".
\endtable
All other input characters will be ignored. Any sequence of characters that
@@ -864,11 +864,11 @@ This \a dateTime value could be passed to \c Qt.formatDateTime(),
with the \a format values below to produce the following results:
\table
- \header \i Format \i Result
- \row \i "dd.MM.yyyy" \i 21.05.2001
- \row \i "ddd MMMM d yy" \i Tue May 21 01
- \row \i "hh:mm:ss.zzz" \i 14:13:09.042
- \row \i "h:m:s ap" \i 2:13:9 pm
+ \header \li Format \li Result
+ \row \li "dd.MM.yyyy" \li 21.05.2001
+ \row \li "ddd MMMM d yy" \li Tue May 21 01
+ \row \li "hh:mm:ss.zzz" \li 14:13:09.042
+ \row \li "h:m:s ap" \li 2:13:9 pm
\endtable
\sa Locale
@@ -1120,7 +1120,7 @@ v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args)
}
/*!
-\qmlmethod object Qt::createComponent(url)
+\qmlmethod object Qt::createComponent(url, mode)
Returns a \l Component object created using the QML file at the specified \a url,
or \c null if an empty string was given.
@@ -1129,6 +1129,12 @@ The returned component's \l Component::status property indicates whether the
component was successfully created. If the status is \c Component.Error,
see \l Component::errorString() for an error description.
+If the optional \a mode parameter is set to \c Component.Asynchronous, the
+component will be loaded in a background thread. The Component::status property
+will be \c Component.Loading while it is loading. The status will change to
+\c Component.Ready if the component loads successfully, or \c Component.Error
+if loading fails.
+
Call \l {Component::createObject()}{Component.createObject()} on the returned
component to create an object instance of the component.
@@ -1143,8 +1149,9 @@ use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
{
- if (args.Length() != 1)
- V8THROW_ERROR("Qt.createComponent(): Invalid arguments");
+ const char *invalidArgs = "Qt.createComponent(): Invalid arguments";
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR(invalidArgs);
QV8Engine *v8engine = V8ENGINE();
QQmlEngine *engine = v8engine->engine();
@@ -1159,8 +1166,20 @@ v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
if (arg.isEmpty())
return v8::Null();
+ QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous;
+ if (args.Length() == 2) {
+ if (args[1]->IsInt32()) {
+ int mode = args[1]->Int32Value();
+ if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
+ V8THROW_ERROR(invalidArgs);
+ compileMode = QQmlComponent::CompilationMode(mode);
+ } else {
+ V8THROW_ERROR(invalidArgs);
+ }
+ }
+
QUrl url = context->resolvedUrl(QUrl(arg));
- QQmlComponent *c = new QQmlComponent(engine, url, engine);
+ QQmlComponent *c = new QQmlComponent(engine, url, compileMode, engine);
QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
QQmlData::get(c, true)->setImplicitDestructible();
return v8engine->newQObject(c);
@@ -1287,9 +1306,9 @@ v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args)
or "C", where:
\list
- \o language is a lowercase, two-letter, ISO 639 language code,
- \o territory is an uppercase, two-letter, ISO 3166 country code,
- \o and codeset and modifier are ignored.
+ \li language is a lowercase, two-letter, ISO 639 language code,
+ \li territory is an uppercase, two-letter, ISO 3166 country code,
+ \li and codeset and modifier are ignored.
\endlist
If the string violates the locale format, or language is not a
diff --git a/src/qml/qml/v8/qv8bindings.cpp b/src/qml/qml/v8/qv8bindings.cpp
index 76fbea137e..4b96679cf3 100644
--- a/src/qml/qml/v8/qv8bindings.cpp
+++ b/src/qml/qml/v8/qv8bindings.cpp
@@ -45,7 +45,6 @@
#include <private/qqmlbinding_p.h>
#include <private/qqmlcompiler_p.h>
#include <private/qqmlproperty_p.h>
-#include <private/qqmlbinding_p_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qobject_p.h>
#include <private/qqmltrace_p.h>
@@ -157,9 +156,8 @@ void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags)
ep->dereferenceScarceResources();
} else {
- QQmlProperty p = QQmlPropertyPrivate::restore(target, instruction->property,
- context);
- QQmlBindingPrivate::printBindingLoopError(p);
+ QQmlProperty p = QQmlPropertyPrivate::restore(target, instruction->property, context);
+ QQmlAbstractBinding::printBindingLoopError(p);
}
}
diff --git a/src/qml/qml/v8/qv8contextwrapper.cpp b/src/qml/qml/v8/qv8contextwrapper.cpp
index 246b716aa0..39392b8984 100644
--- a/src/qml/qml/v8/qv8contextwrapper.cpp
+++ b/src/qml/qml/v8/qv8contextwrapper.cpp
@@ -238,16 +238,11 @@ QQmlContextData *QV8ContextWrapper::context(v8::Handle<v8::Value> value)
return r?r->getContext():0;
}
-v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
+v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo &)
{
- QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
-
- QV8Engine *engine = resource->engine;
-
- QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
- v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
- return v8::Undefined();
+ // V8 will throw a ReferenceError if appropriate ("typeof" should not throw)
+ return v8::Handle<v8::Value>();
}
v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
@@ -365,9 +360,8 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
expressionContext->unresolvedNames = true;
- QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
- v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
- return v8::Undefined();
+ // V8 will throw a ReferenceError if appropriate ("typeof" should not throw)
+ return v8::Handle<v8::Value>();
}
v8::Handle<v8::Value> QV8ContextWrapper::NullSetter(v8::Local<v8::String> property,
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
index 61cfa242c9..2350b9dc2c 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -599,11 +599,10 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
v8::StackTrace::kScriptName));
v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
int lineNumber = frame->GetLineNumber();
- int columNumber = frame->GetColumn();
+ int columnNumber = frame->GetColumn();
QString url = engine->toString(frame->GetScriptName());
- newBinding = new QQmlBinding(&function, object, context);
- newBinding->setSourceLocation(url, lineNumber, columNumber);
+ newBinding = new QQmlBinding(&function, object, context, url, lineNumber, columnNumber);
newBinding->setTarget(object, *property, context);
newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
QQmlBinding::RequiresThisObject);
@@ -619,11 +618,10 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
v8::StackTrace::kScriptName));
v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
int lineNumber = frame->GetLineNumber();
- int columNumber = frame->GetColumn();
+ int columnNumber = frame->GetColumn();
QString url = engine->toString(frame->GetScriptName());
- newBinding = new QQmlBinding(&function, object, context);
- newBinding->setSourceLocation(url, lineNumber, columNumber);
+ newBinding = new QQmlBinding(&function, object, context, url, lineNumber, columnNumber);
newBinding->setTarget(object, *property, context);
newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
QQmlBinding::RequiresThisObject);
@@ -925,8 +923,10 @@ static void WeakQObjectReferenceCallback(v8::Persistent<v8::Value> handle, void
QQmlData *ddata = QQmlData::get(object, false);
if (ddata) {
ddata->v8object.Clear();
- if (!object->parent() && !ddata->indestructible)
+ if (!object->parent() && !ddata->indestructible) {
+ ddata->isQueuedForDeletion = true;
object->deleteLater();
+ }
}
}
@@ -1084,13 +1084,16 @@ v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
return v8::Null();
if (QObjectPrivate::get(object)->wasDeleted)
- return v8::Undefined();
-
+ return v8::Null();
+
QQmlData *ddata = QQmlData::get(object, true);
if (!ddata)
return v8::Undefined();
+ if (ddata->isQueuedForDeletion)
+ return v8::Null();
+
if (ddata->v8objectid == m_id && !ddata->v8object.IsEmpty()) {
// We own the v8object
return v8::Local<v8::Object>::New(ddata->v8object);
diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp
index d54f04a9b0..cf2c13fce9 100644
--- a/src/qml/qml/v8/qv8valuetypewrapper.cpp
+++ b/src/qml/qml/v8/qv8valuetypewrapper.cpp
@@ -352,8 +352,8 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property
int columnNumber = frame->GetColumn();
QString url = r->engine->toString(frame->GetScriptName());
- newBinding = new QQmlBinding(&function, reference->object, context);
- newBinding->setSourceLocation(url, lineNumber, columnNumber);
+ newBinding = new QQmlBinding(&function, reference->object, context,
+ url, lineNumber, columnNumber);
newBinding->setTarget(reference->object, cacheData, context);
newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
QQmlBinding::RequiresThisObject);