Merge branch 'master' of git://gitorious.org/qt/qtdeclarative into merge-master
authorMatthew Vogt <matthew.vogt@nokia.com>
Tue, 13 Mar 2012 05:06:40 +0000 (15:06 +1000)
committerMatthew Vogt <matthew.vogt@nokia.com>
Tue, 13 Mar 2012 05:22:14 +0000 (15:22 +1000)
Change-Id: Iaefec13503dadfa200539b8de7a2d80fc5bb3bcf

52 files changed:
bin/rename-qtdeclarative-symbols.sh
doc/src/qml/basictypes.qdoc
doc/src/qml/javascriptblocks.qdoc
doc/src/qml/propertybinding.qdoc
doc/src/snippets/qml/DynamicText.qml [new file with mode: 0644]
doc/src/snippets/qml/qtBinding.1.qml [new file with mode: 0644]
doc/src/snippets/qml/qtBinding.2.qml [new file with mode: 0644]
doc/src/snippets/qml/qtBinding.3.qml [new file with mode: 0644]
doc/src/snippets/qml/qtBinding.4.qml [new file with mode: 0644]
src/qml/qml/qml.pri
src/qml/qml/qqmlengine.cpp
src/qml/qml/qqmlengine.h
src/qml/qml/qqmlengine_p.h
src/qml/qml/qqmlproperty.cpp
src/qml/qml/v8/qqmlbuiltinfunctions.cpp
src/qml/qml/v8/qqmlbuiltinfunctions_p.h
src/qml/qml/v8/qv8engine.cpp
src/qml/qml/v8/qv8engine_p.h
src/qml/qml/v8/qv8qobjectwrapper.cpp
src/qml/qml/v8/qv8valuetypewrapper.cpp
src/quick/items/qquickcanvas.cpp
src/quick/items/qquickitem.cpp
src/quick/items/qquickitem.h
src/quick/items/qquickrectangle.cpp
src/quick/items/qquickrectangle_p.h
src/quick/scenegraph/qsgcontext.cpp
src/quick/scenegraph/qsgcontextplugin_p.h
src/quick/util/qquickimageprovider.cpp [moved from src/qml/qml/qqmlimageprovider.cpp with 91% similarity]
src/quick/util/qquickimageprovider.h [moved from src/qml/qml/qqmlimageprovider.h with 85% similarity]
src/quick/util/qquickpixmapcache.cpp
src/quick/util/qquickpixmapcache_p.h
src/quick/util/util.pri
tests/auto/qml/qml.pro
tests/auto/qml/qqmlcomponent/data/createObjectWithScript.qml
tests/auto/qml/qqmlecmascript/data/functionAssignment.1.qml
tests/auto/qml/qqmlecmascript/data/functionAssignment.2.qml
tests/auto/qml/qqmlecmascript/data/functionAssignment.3.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/functionAssignment.js
tests/auto/qml/qqmlecmascript/data/propertyVar.11.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/propertyVar.12.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/propertyVar.13.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/propertyVar.14.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/propertyVar.15.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.2.qml [new file with mode: 0644]
tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.qml
tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
tests/auto/quick/qquickimageprovider/qquickimageprovider.pro [moved from tests/auto/qml/qqmlimageprovider/qqmlimageprovider.pro with 66% similarity]
tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp [moved from tests/auto/qml/qqmlimageprovider/tst_qqmlimageprovider.cpp with 87% similarity]
tests/auto/quick/qquickloader/data/initialPropertyValues.binding.qml
tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
tests/auto/quick/quick.pro

index 96633af..78df855 100755 (executable)
@@ -154,8 +154,6 @@ QML_SYMBOLS="\
     QDeclarativeGuardedContextData
     QDeclarativeGuardImpl
     QDeclarativeHandlingSignalProfiler
-    QDeclarativeImageProvider
-    QDeclarativeImageProviderPrivate
     QDeclarativeImportDatabase
     QDeclarativeImportedNamespace
     QDeclarativeImports
@@ -319,6 +317,8 @@ QUICK_SYMBOLS="\
     QDeclarativeGestureAreaParser
     QDeclarativeGestureAreaPrivate
     QDeclarativeGraphics
+    QDeclarativeImageProvider
+    QDeclarativeImageProviderPrivate
     QDeclarativeItem
     QDeclarativeItemAccessor
     QDeclarativeItemChangeListener
index 317dd54..5b207cf 100644 (file)
     \brief A var type is a generic property type.
 
     A var is a generic property type capable of storing any data type.
-    It is equivalent to a regular JavaScript variable, except that you
-    cannot assign a JavaScript function to such a property.
-    For example, var properties can store numbers, strings, objects and
-    arrays:
+    It is equivalent to a regular JavaScript variable.
+    For example, var properties can store numbers, strings, objects,
+    arrays and functions:
 
     \qml
     Item {
         property var aVector3d: Qt.vector3d(100, 100, 100)
         property var anArray: [1, 2, 3, "four", "five", (function() { return "six"; })]
         property var anObject: { "foo": 10, "bar": 20 }
+        property var aFunction: (function() { return "one"; })
     }
     \endqml
 
-    Attempting to assign a JavaScript function to a var property will result in
-    a binding assignment as per other property types.  You can assign a JavaScript
-    array containing a single function element instead.
-
     It is important to note that changes in regular properties of JavaScript
     objects assigned to a var property will \bold{not} trigger updates of bindings
     that access them.  The example below will display "The car has 4 wheels" as
     }
     \endqml
 
+    If the onCompleted handler instead had \tt{"car = new Object({wheels: 6})"}
+    then the text would be updated to say "The car has 6 wheels"., since the
+    car property itself would be changed, which causes a change notification
+    to be emitted.
+
     A \c var type property can also hold an image or pixmap.
     A \c var which contains a QPixmap or QImage is known as a
     "scarce resource" and the declarative engine will attempt to
index 0c1d4c2..5a30324 100644 (file)
@@ -72,7 +72,7 @@ Rectangle {
     id: button
     width: 200; height: 80; color: "lightsteelblue"
 
-    MouseArea {
+    MouseArea {
         id: mousearea
         anchors.fill: parent
 
@@ -103,7 +103,7 @@ Rectangle {
 
     color: mousearea.pressed ? "steelblue" : "lightsteelblue"
 
-    MouseArea {
+    MouseArea {
         id: mousearea
         anchors.fill: parent
     }
@@ -366,6 +366,15 @@ Likewise, the \l {Component::onDestruction} attached property is triggered on
 component destruction.
 
 
+\section1 JavaScript and Property Binding
+
+Property bindings can be created in JavaScript by assigning the property the value returned
+by calling Qt.binding() where the parameter to Qt.binding() is a \c function
+that returns the required value.
+
+See \l {qml-javascript-assignment}{Property Assignment versus Property Binding} for details.
+
+
 \section1 QML JavaScript Restrictions
 
 QML executes standard JavaScript code, with the following restrictions:
index 6dd862f..ce5ad0b 100644 (file)
@@ -87,7 +87,7 @@ The property binding causes the width of the \c Rectangle to update whenever the
 \c {parent}'s width changes.
 
 Assigning a property value (using the equals sign "\c {=}") does not create a
-property binding.
+property binding (unless explicitly assigned, see below).
 \snippet doc/src/snippets/qml/properties.qml property assignment
 
 Instead of creating a property binding, the assignment simply sets the \c Rectangle
@@ -100,9 +100,9 @@ and if any code explicitly re-sets this value, the property binding is removed.
 \section1 Binding to JavaScript Functions
 
 The \c{property : value} syntax for property binding is QML-specific and cannot
-be used in JavaScript. Instead, to bind a property from JavaScript, assign a \c
-function to the property that returns the required value. The following code
-correctly creates
+be used in JavaScript. Instead, to bind a property from JavaScript, assign the
+result returned by the \c{Qt.binding()} function to the property.  This will cause
+a binding assignment on the specified property.  The following code correctly creates
 the binding in JavaScript rather than QML:
 
 \qml
@@ -110,7 +110,7 @@ Item {
     width: 100
 
     Component.onCompleted: {
-        height = (function() { return width * 2 })
+        height = Qt.binding(function() { return width * 2 })
     }
 }
 \endqml
@@ -124,10 +124,8 @@ binding.
 For example, the \c Component.onCompleted handler below is defined within the
 scope of the \l Item, and references to \c width within this scope would refer
 to the \l Item's width, rather than that of the \l Rectangle. To bind the \l
-Rectangle's \c height to its own \c width, the function needs to explicitly
-refer to \c this.width rather than just \c width. Otherwise, the height of the
-\l Rectangle would be bound to the width of the \l Item and not the \l
-Rectangle.
+Rectangle's \c height to its own \c width, the function passed to Qt.binding()
+needs to explicitly refer to \c this.width rather than just \c width.
 
 \qml
 Item {
@@ -141,7 +139,8 @@ Item {
     }
 
     Component.onCompleted: {
-        rect.height = (function() { return this.width * 2 })
+        rect.height = Qt.binding(function() { return this.width * 2 })
+        console.log("rect.height = " + rect.height) // prints 200
     }
 }
 \endqml
diff --git a/doc/src/snippets/qml/DynamicText.qml b/doc/src/snippets/qml/DynamicText.qml
new file mode 100644 (file)
index 0000000..9711702
--- /dev/null
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![0]
+import QtQuick 2.0
+
+Text {
+    id: textElement
+    width: 200
+    height: 200
+    text: "Default text"
+    property string dynamicText: "Dynamic text"
+    onTextChanged: console.log(text)
+}
+//![0]
diff --git a/doc/src/snippets/qml/qtBinding.1.qml b/doc/src/snippets/qml/qtBinding.1.qml
new file mode 100644 (file)
index 0000000..acec88a
--- /dev/null
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//![0]
+Item {
+    property bool someCondition: true
+    property int edgePosition
+
+    Component.onCompleted: {
+        if (someCondition == true) {
+            // bind to the result of the binding expression passed to Qt.binding()
+            edgePosition = Qt.binding(function() { return x + width })
+        }
+    }
+}
+//![0]
diff --git a/doc/src/snippets/qml/qtBinding.2.qml b/doc/src/snippets/qml/qtBinding.2.qml
new file mode 100644 (file)
index 0000000..9b78bc3
--- /dev/null
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//![0]
+Item {
+    id: root
+    property string dynamicText: "Root text"
+
+    Component.onCompleted: {
+        var c = Qt.createComponent("DynamicText.qml")
+
+        var obj1 = c.createObject(root, { 'text': Qt.binding(function() { return dynamicText + ' extra text' }) })
+        root.dynamicText = "Modified root text"
+
+        var obj2 = c.createObject(root, { 'text': Qt.binding(function() { return this.dynamicText + ' extra text' }) })
+        obj2.dynamicText = "Modified text element text"
+    }
+}
+//![0]
diff --git a/doc/src/snippets/qml/qtBinding.3.qml b/doc/src/snippets/qml/qtBinding.3.qml
new file mode 100644 (file)
index 0000000..a27914c
--- /dev/null
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//![0]
+Item {
+    id: root
+    property string dynamicText: "Root text"
+
+    Loader {
+        id: loaderOne
+        onLoaded: root.dynamicText = "Modified root text"
+    }
+
+    Loader {
+        id: loaderTwo
+        onLoaded: item.dynamicText = "Modified dynamic text"
+    }
+
+    Component.onCompleted: {
+        loaderOne.setSource("DynamicText.qml", { 'text': Qt.binding(function() { return dynamicText + ' extra text' }) })
+        loaderTwo.setSource("DynamicText.qml", { 'text': Qt.binding(function() { return this.dynamicText + ' extra text' }) })
+    }
+}
+//![0]
diff --git a/doc/src/snippets/qml/qtBinding.4.qml b/doc/src/snippets/qml/qtBinding.4.qml
new file mode 100644 (file)
index 0000000..0155957
--- /dev/null
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//![0]
+Item {
+    width: 50
+    property var storedBindings: [ Qt.binding(function() { return x + width }) ] // stored
+    property int a: Qt.binding(function() { return x + width }) // error!
+    property int b
+
+    Component.onCompleted: {
+        b = storedBindings[0] // causes binding assignment
+    }
+}
+//![0]
index 0ce7c7e..b389763 100644 (file)
@@ -40,7 +40,6 @@ SOURCES += \
     $$PWD/qqmltypenamecache.cpp \
     $$PWD/qqmlscriptstring.cpp \
     $$PWD/qquickworkerscript.cpp \
-    $$PWD/qqmlimageprovider.cpp \
     $$PWD/qqmlnetworkaccessmanagerfactory.cpp \
     $$PWD/qqmldirparser.cpp \
     $$PWD/qqmlextensionplugin.cpp \
@@ -106,7 +105,6 @@ HEADERS += \
     $$PWD/qqmlscriptstring.h \
     $$PWD/qquickworkerscript_p.h \
     $$PWD/qqmlguard_p.h \
-    $$PWD/qqmlimageprovider.h \
     $$PWD/qqmlnetworkaccessmanagerfactory.h \
     $$PWD/qqmldirparser_p.h \
     $$PWD/qqmlextensioninterface.h \
index d745513..90b8bcd 100644 (file)
@@ -60,7 +60,6 @@
 #include "qquickworkerscript_p.h"
 #include "qqmlcomponent_p.h"
 #include "qqmlnetworkaccessmanagerfactory.h"
-#include "qqmlimageprovider.h"
 #include "qqmldirparser_p.h"
 #include "qqmlextensioninterface.h"
 #include "qqmllist_p.h"
@@ -181,6 +180,12 @@ void QQmlEnginePrivate::defineModule()
     qmlRegisterUncreatableType<QQmlLocale>("QtQuick",2,0,"Locale",QQmlEngine::tr("Locale cannot be instantiated.  Use Qt.locale()"));
 }
 
+
+QQmlImageProviderBase::~QQmlImageProviderBase()
+{
+}
+
+
 /*!
 \qmlclass Qt QQmlEnginePrivate
   \ingroup qml-utility-elements
@@ -672,27 +677,29 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const
   takes ownership of \a provider.
 
   Image providers enable support for pixmap and threaded image
-  requests. See the QQmlImageProvider documentation for details on
+  requests. See the QQuickImageProvider documentation for details on
   implementing and using image providers.
 
   All required image providers should be added to the engine before any
   QML sources files are loaded.
 
-  \sa removeImageProvider()
+  \sa removeImageProvider(), QQuickImageProvider
 */
-void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProvider *provider)
+void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
 {
     Q_D(QQmlEngine);
     QMutexLocker locker(&d->mutex);
-    d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProvider>(provider));
+    d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
 }
 
 /*!
-  Returns the QQmlImageProvider set for \a providerId.
+  Returns the image provider set for \a providerId.
 
   Returns the provider if it was found; otherwise returns 0.
+
+  \sa QQuickImageProvider
 */
-QQmlImageProvider *QQmlEngine::imageProvider(const QString &providerId) const
+QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
 {
     Q_D(const QQmlEngine);
     QMutexLocker locker(&d->mutex);
@@ -700,9 +707,9 @@ QQmlImageProvider *QQmlEngine::imageProvider(const QString &providerId) const
 }
 
 /*!
-  Removes the QQmlImageProvider for \a providerId.
+  Removes the image provider for \a providerId.
 
-  \sa addImageProvider()
+  \sa addImageProvider(), QQuickImageProvider
 */
 void QQmlEngine::removeImageProvider(const QString &providerId)
 {
@@ -711,54 +718,6 @@ void QQmlEngine::removeImageProvider(const QString &providerId)
     d->imageProviders.take(providerId);
 }
 
-QQmlImageProvider::ImageType QQmlEnginePrivate::getImageProviderType(const QUrl &url)
-{
-    QMutexLocker locker(&mutex);
-    QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host());
-    locker.unlock();
-    if (provider)
-        return provider->imageType();
-    return QQmlImageProvider::Invalid;
-}
-
-QQuickTextureFactory *QQmlEnginePrivate::getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
-{
-    QMutexLocker locker(&mutex);
-    QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host());
-    locker.unlock();
-    if (provider) {
-        QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
-        return provider->requestTexture(imageId, size, req_size);
-    }
-    return 0;
-}
-
-QImage QQmlEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
-{
-    QMutexLocker locker(&mutex);
-    QImage image;
-    QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host());
-    locker.unlock();
-    if (provider) {
-        QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
-        image = provider->requestImage(imageId, size, req_size);
-    }
-    return image;
-}
-
-QPixmap QQmlEnginePrivate::getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
-{
-    QMutexLocker locker(&mutex);
-    QPixmap pixmap;
-    QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host());
-    locker.unlock();
-    if (provider) {
-        QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
-        pixmap = provider->requestPixmap(imageId, size, req_size);
-    }
-    return pixmap;
-}
-
 /*!
   Return the base URL for this engine.  The base URL is only used to
   resolve components when a relative URL is passed to the
index 04ac61c..4169692 100644 (file)
@@ -54,6 +54,12 @@ QT_BEGIN_HEADER
 QT_BEGIN_NAMESPACE
 
 
+class Q_QML_EXPORT QQmlImageProviderBase
+{
+public:
+    virtual ~QQmlImageProviderBase();
+};
+
 class QQmlComponent;
 class QQmlEnginePrivate;
 class QQmlImportsPrivate;
@@ -62,7 +68,6 @@ class QQmlContext;
 class QQmlType;
 class QUrl;
 class QScriptContext;
-class QQmlImageProvider;
 class QNetworkAccessManager;
 class QQmlNetworkAccessManagerFactory;
 class QQmlIncubationController;
@@ -94,8 +99,8 @@ public:
 
     QNetworkAccessManager *networkAccessManager() const;
 
-    void addImageProvider(const QString &id, QQmlImageProvider *);
-    QQmlImageProvider *imageProvider(const QString &id) const;
+    void addImageProvider(const QString &id, QQmlImageProviderBase *);
+    QQmlImageProviderBase *imageProvider(const QString &id) const;
     void removeImageProvider(const QString &id);
 
     void setIncubationController(QQmlIncubationController *);
index db83448..73a0b5a 100644 (file)
@@ -63,7 +63,6 @@
 #include "qqmlcontext.h"
 #include "qqmlcontext_p.h"
 #include "qqmlexpression.h"
-#include "qqmlimageprovider.h"
 #include "qqmlproperty_p.h"
 #include "qqmlpropertycache_p.h"
 #include "qqmlmetatype_p.h"
@@ -173,11 +172,7 @@ public:
     mutable QNetworkAccessManager *networkAccessManager;
     mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
 
-    QHash<QString,QSharedPointer<QQmlImageProvider> > imageProviders;
-    QQmlImageProvider::ImageType getImageProviderType(const QUrl &url);
-    QQuickTextureFactory *getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
-    QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
-    QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
+    QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
 
     // Scarce resources are "exceptionally high cost" QVariant types where allowing the
     // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
index 6321592..00cb65d 100644 (file)
@@ -1486,6 +1486,17 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
 
     if (expression->hasError()) {
         return false;
+    } else if (isVmeProperty) {
+        typedef QQmlVMEMetaObject VMEMO;
+        if (!result.IsEmpty() && result->IsFunction()
+                && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
+            // we explicitly disallow this case to avoid confusion.  Users can still store one
+            // in an array in a var property if they need to, but the common case is user error.
+            expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
+            return false;
+        }
+        VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
+        vmemo->setVMEProperty(core.coreIndex, result);
     } else if (isUndefined && core.isResettable()) {
         void *args[] = { 0 };
         QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
@@ -1495,12 +1506,11 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
         expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type)));
         return false;
     } else if (result->IsFunction()) {
-        expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property."));
+        if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
+            expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
+        else
+            expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
         return false;
-    } else if (isVmeProperty) {
-        typedef QQmlVMEMetaObject VMEMO;
-        VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
-        vmemo->setVMEProperty(core.coreIndex, result);
     } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
 
         if (watcher.wasDeleted()) 
index 951bcc5..143ccee 100644 (file)
@@ -1314,6 +1314,65 @@ v8::Handle<v8::Value> locale(const v8::Arguments &args)
     return QQmlLocale::locale(v8engine, code);
 }
 
+/*!
+    \qmlmethod Qt::binding(function)
+
+    Returns a JS object representing a binding expression which may be
+    assigned to any property in imperative code to cause a binding
+    assignment.
+
+    There are two main use-cases for the function: firstly, in imperative
+    JavaScript code to cause a binding assignment:
+
+    \snippet doc/src/snippets/declarative/qtBinding.1.qml 0
+
+    and secondly, when defining initial property values of dynamically
+    constructed objects (via Component.createObject() or
+    Loader.setSource()) as being bound to the result of an expression.
+
+    For example, assuming the existence of a DynamicText component:
+    \snippet doc/src/snippets/declarative/DynamicText.qml 0
+
+    the output from:
+    \snippet doc/src/snippets/declarative/qtBinding.2.qml 0
+
+    and from:
+    \snippet doc/src/snippets/declarative/qtBinding.3.qml 0
+
+    should both be:
+    \code
+    Root text extra text
+    Modified root text extra text
+    Dynamic text extra text
+    Modified dynamic text extra text
+    \endcode
+
+    This function cannot be used in property binding declarations
+    (see the documentation on \l{qml-javascript-assignment}{binding
+    declarations and binding assignments}) except when the result is
+    stored in an array bound to a var property.
+
+    \snippet doc/src/snippets/declarative/qtBinding.4.qml 0
+
+    Note: in QtQuick 1.x, all function assignment was treated as
+    binding assignment, so the Qt.binding() function is new in
+    QtQuick 2.0.
+
+    \since QtQuick 2.0
+*/
+v8::Handle<v8::Value> binding(const v8::Arguments &args)
+{
+    QString code;
+    if (args.Length() != 1)
+        V8THROW_ERROR("binding() requires 1 argument");
+    if (!args[0]->IsFunction())
+        V8THROW_TYPE("binding(): argument (binding expression) must be a function");
+
+    v8::Handle<v8::Object> rv = args[0]->ToObject()->Clone();
+    rv->SetHiddenValue(V8ENGINE()->bindingFlagKey(), v8::Boolean::New(true));
+    return rv;
+}
+
 } // namespace QQmlBuiltinFunctions
 
 QT_END_NAMESPACE
index ddb1c64..bbfe88a 100644 (file)
@@ -103,6 +103,7 @@ v8::Handle<v8::Value> qsTrId(const v8::Arguments &args);
 v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args);
 v8::Handle<v8::Value> stringArg(const v8::Arguments &args);
 v8::Handle<v8::Value> locale(const v8::Arguments &args);
+v8::Handle<v8::Value> binding(const v8::Arguments &args);
 }
 
 QT_END_NAMESPACE
index 8e8223f..e49bc62 100644 (file)
@@ -147,6 +147,8 @@ QV8Engine::QV8Engine(QJSEngine* qq, QJSEngine::ContextOwnership ownership)
     QV8GCCallback::registerGcPrologueCallback();
     m_strongReferencer = qPersistentNew(v8::Object::New());
 
+    m_bindingFlagKey = qPersistentNew(v8::String::New("qml::binding"));
+
     m_stringWrapper.init();
     m_contextWrapper.init(this);
     m_qobjectWrapper.init(this);
@@ -191,6 +193,8 @@ QV8Engine::~QV8Engine()
     m_contextWrapper.destroy();
     m_stringWrapper.destroy();
 
+    qPersistentDispose(m_bindingFlagKey);
+
     m_originalGlobalObject.destroy();
 
     if (m_ownsV8Context)
@@ -598,6 +602,7 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
     qt->Set(v8::String::New("atob"), V8FUNCTION(atob, this));
     qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this));
     qt->Set(v8::String::New("locale"), V8FUNCTION(locale, this));
+    qt->Set(v8::String::New("binding"), V8FUNCTION(binding, this));
 
     if (m_engine) {
         qt->Set(v8::String::New("application"), newQObject(new QQuickApplication(m_engine)));
index bc57b27..825d7a3 100644 (file)
@@ -357,6 +357,9 @@ public:
     // a QVariant wrapper
     inline v8::Handle<v8::Value> newQVariant(const QVariant &);
 
+    // Return the JS string key for the "function is a binding" flag
+    inline v8::Handle<v8::String> bindingFlagKey() const;
+
     // Return the network access manager for this engine.  By default this returns the network
     // access manager of the QQmlEngine.  It is overridden in the case of a threaded v8
     // instance (like in WorkerScript).
@@ -461,6 +464,8 @@ protected:
     v8::Persistent<v8::Context> m_context;
     QScriptOriginalGlobalObject m_originalGlobalObject;
 
+    v8::Persistent<v8::String> m_bindingFlagKey;
+
     QV8StringWrapper m_stringWrapper;
     QV8ContextWrapper m_contextWrapper;
     QV8QObjectWrapper m_qobjectWrapper;
@@ -609,6 +614,11 @@ v8::Handle<v8::Value> QV8Engine::newSequence(int sequenceType, QObject *object,
     return m_sequenceWrapper.newSequence(sequenceType, object, property, succeeded);
 }
 
+v8::Handle<v8::String> QV8Engine::bindingFlagKey() const
+{
+    return m_bindingFlagKey;
+}
+
 // XXX Can this be made more optimal?  It is called prior to resolving each and every 
 // unqualified name in QV8ContextWrapper.
 bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)
index 78b2cb7..4be93d1 100644 (file)
@@ -519,7 +519,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
             return v8::Handle<v8::Value>();
     }
 
-    if (result->isFunction()) {
+    if (result->isFunction() && !result->isVMEProperty()) {
         if (result->isVMEFunction()) {
             return ((QQmlVMEMetaObject *)(object->metaObject()))->vmeMethod(result->coreIndex);
         } else if (result->isV8Function()) {
@@ -579,24 +579,55 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
                                  v8::Handle<v8::Value> value)
 {
     QQmlBinding *newBinding = 0;
-
     if (value->IsFunction()) {
-        QQmlContextData *context = engine->callingContext();
-        v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
-
-        v8::Local<v8::StackTrace> trace = 
-            v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber | 
-                                                                                     v8::StackTrace::kScriptName));
-        v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
-        int lineNumber = frame->GetLineNumber();
-        int columNumber = frame->GetColumn();
-        QString url = engine->toString(frame->GetScriptName());
-
-        newBinding = new QQmlBinding(&function, object, context);
-        newBinding->setSourceLocation(url, lineNumber, columNumber);
-        newBinding->setTarget(object, *property, context);
-        newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
-                                     QQmlBinding::RequiresThisObject);
+        if (value->ToObject()->GetHiddenValue(engine->bindingFlagKey()).IsEmpty()) {
+            if (!property->isVMEProperty()) {
+                // XXX TODO: uncomment the following lines
+                // assigning a JS function to a non-var-property is not allowed.
+                //QString error = QLatin1String("Cannot assign JavaScript function to ") +
+                //                QLatin1String(QMetaType::typeName(property->propType));
+                //v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+                //return;
+                // XXX TODO: remove the following transition behaviour
+                // Temporarily allow assignment of functions to non-var properties
+                // to mean binding assignment (as per old behaviour).
+                QQmlContextData *context = engine->callingContext();
+                v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
+
+                v8::Local<v8::StackTrace> trace =
+                    v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
+                                                                                             v8::StackTrace::kScriptName));
+                v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
+                int lineNumber = frame->GetLineNumber();
+                int columNumber = frame->GetColumn();
+                QString url = engine->toString(frame->GetScriptName());
+
+                newBinding = new QQmlBinding(&function, object, context);
+                newBinding->setSourceLocation(url, lineNumber, columNumber);
+                newBinding->setTarget(object, *property, context);
+                newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
+                                             QQmlBinding::RequiresThisObject);
+                qWarning("WARNING: function assignment is DEPRECATED and will be removed!  Wrap RHS in Qt.binding(): %s:%d", qPrintable(engine->toString(frame->GetScriptName())), frame->GetLineNumber());
+            }
+        } else {
+            // binding assignment.
+            QQmlContextData *context = engine->callingContext();
+            v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
+
+            v8::Local<v8::StackTrace> trace =
+                v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
+                                                                                         v8::StackTrace::kScriptName));
+            v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
+            int lineNumber = frame->GetLineNumber();
+            int columNumber = frame->GetColumn();
+            QString url = engine->toString(frame->GetScriptName());
+
+            newBinding = new QQmlBinding(&function, object, context);
+            newBinding->setSourceLocation(url, lineNumber, columNumber);
+            newBinding->setTarget(object, *property, context);
+            newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
+                                         QQmlBinding::RequiresThisObject);
+        }
     }
 
     QQmlAbstractBinding *oldBinding = 
@@ -604,6 +635,12 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
     if (oldBinding)
         oldBinding->destroy();
 
+    if (!newBinding && property->isVMEProperty()) {
+        // allow assignment of "special" values (null, undefined, function) to var properties
+        static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(object->metaObject()))->setVMEProperty(property->coreIndex, value);
+        return;
+    }
+
 #define PROPERTY_STORE(cpptype, value) \
     cpptype o = value; \
     int status = -1; \
index 54d871d..d54f04a 100644 (file)
@@ -324,6 +324,13 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property
         QQmlBinding *newBinding = 0;
 
         if (value->IsFunction()) {
+            if (value->ToObject()->GetHiddenValue(r->engine->bindingFlagKey()).IsEmpty()) {
+                // assigning a JS function to a non-var-property is not allowed.
+                QString error = QLatin1String("Cannot assign JavaScript function to value-type property");
+                v8::ThrowException(v8::Exception::Error(r->engine->toString(error)));
+                return value;
+            }
+
             QQmlContextData *context = r->engine->callingContext();
             v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
 
index 2636022..f14eccd 100644 (file)
@@ -1707,7 +1707,7 @@ void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
 
         if (item->clip()) {
             Q_ASSERT(itemPriv->clipNode() == 0);
-            itemPriv->extra.value().clipNode = new QQuickDefaultClipNode(item->boundingRect());
+            itemPriv->extra.value().clipNode = new QQuickDefaultClipNode(item->clipRect());
             itemPriv->clipNode()->update();
 
             if (child)
@@ -1799,7 +1799,7 @@ void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
     }
 
     if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) {
-        itemPriv->clipNode()->setRect(item->boundingRect());
+        itemPriv->clipNode()->setRect(item->clipRect());
         itemPriv->clipNode()->update();
     }
 
index f2ec0d6..8e351f1 100644 (file)
@@ -3648,13 +3648,20 @@ void QQuickItem::updateInputMethod(Qt::InputMethodQueries queries)
 
 /*! \internal */
 // XXX todo - do we want/need this anymore?
-// Note that it's now used for varying clip rect
 QRectF QQuickItem::boundingRect() const
 {
     Q_D(const QQuickItem);
     return QRectF(0, 0, d->width, d->height);
 }
 
+/*! \internal */
+QRectF QQuickItem::clipRect() const
+{
+    Q_D(const QQuickItem);
+    return QRectF(0, 0, d->width, d->height);
+}
+
+
 QQuickItem::TransformOrigin QQuickItem::transformOrigin() const
 {
     Q_D(const QQuickItem);
@@ -5835,7 +5842,7 @@ void QQuickItemLayer::updateGeometry()
 {
     QQuickItem *l = m_effect ? (QQuickItem *) m_effect : (QQuickItem *) m_effectSource;
     Q_ASSERT(l);
-    QRectF bounds = m_item->boundingRect();
+    QRectF bounds = m_item->clipRect();
     l->setWidth(bounds.width());
     l->setHeight(bounds.height());
     l->setX(bounds.x() + m_item->x());
index c44192b..f14d60b 100644 (file)
@@ -266,6 +266,7 @@ public:
     void setFlags(Flags flags);
 
     virtual QRectF boundingRect() const;
+    virtual QRectF clipRect() const;
 
     bool hasActiveFocus() const;
     bool hasFocus() const;
index 062df12..13c101d 100644 (file)
@@ -553,4 +553,9 @@ QRectF QQuickRectangle::boundingRect() const
                   d->width + 2 * d->penMargin, d->height + 2 * d->penMargin);
 }
 
+QRectF QQuickRectangle::clipRect() const
+{
+    return QQuickRectangle::boundingRect();
+}
+
 QT_END_NAMESPACE
index eec2b56..52aa9e8 100644 (file)
@@ -159,6 +159,7 @@ public:
     void setRadius(qreal radius);
 
     virtual QRectF boundingRect() const;
+    virtual QRectF clipRect() const;
 
 Q_SIGNALS:
     void colorChanged();
index 6eae5c3..02fbaa1 100644 (file)
@@ -55,7 +55,6 @@
 #include <QGuiApplication>
 #include <QOpenGLContext>
 
-#include <QQmlImageProvider>
 #include <private/qqmlglobal_p.h>
 
 #include <QtQuick/private/qsgtexture_p.h>
index cc7761a..2c4531c 100644 (file)
 #define QSGCONTEXTPLUGIN_H
 
 #include <QtQuick/qtquickglobal.h>
+#include <QtQuick/qquickimageprovider.h>
 #include <QtCore/qplugin.h>
 #include <QtCore/qfactoryinterface.h>
 
-#include <QQmlImageProvider>
-
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
similarity index 91%
rename from src/qml/qml/qqmlimageprovider.cpp
rename to src/quick/util/qquickimageprovider.cpp
index 756b943..dc85230 100644 (file)
 **
 ****************************************************************************/
 
-#include "qqmlimageprovider.h"
+#include "qquickimageprovider.h"
 
 QT_BEGIN_NAMESPACE
 
-class QQmlImageProviderPrivate
+class QQuickImageProviderPrivate
 {
 public:
-    QQmlImageProvider::ImageType type;
+    QQuickImageProvider::ImageType type;
 };
 
 /*!
@@ -109,16 +109,16 @@ QImage QQuickTextureFactory::image() const
 
 
 /*!
-    \class QQmlImageProvider
+    \class QQuickImageProvider
     \since 4.7
-    \brief The QQmlImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML.
+    \brief The QQuickImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML.
 
-    QQmlImageProvider is used to provide advanced image loading features
+    QQuickImageProvider is used to provide advanced image loading features
     in QML applications. It allows images in QML to be:
 
     \list
     \o Loaded using QPixmaps rather than actual image files
-    \o Loaded asynchronously in a separate thread, if imageType() is \l{QQmlImageProvider::ImageType}{ImageType::Image}
+    \o Loaded asynchronously in a separate thread, if imageType() is \l{QQuickImageProvider::ImageType}{ImageType::Image}
     \endlist
 
     To specify that an image should be loaded by an image provider, use the
@@ -210,7 +210,7 @@ QImage QQuickTextureFactory::image() const
 
     \section2 Image caching
 
-    Images returned by a QQmlImageProvider are automatically cached,
+    Images returned by a QQuickImageProvider are automatically cached,
     similar to any image loaded by the QML engine. When an image with a
     "image://" prefix is loaded from cache, requestImage() and requestPixmap()
     will not be called for the relevant image provider. If an image should always
@@ -222,7 +222,7 @@ QImage QQuickTextureFactory::image() const
 */
 
 /*!
-    \enum QQmlImageProvider::ImageType
+    \enum QQuickImageProvider::ImageType
 
     Defines the type of image supported by this image provider.
 
@@ -237,18 +237,18 @@ QImage QQuickTextureFactory::image() const
 /*!
     Creates an image provider that will provide images of the given \a type.
 */
-QQmlImageProvider::QQmlImageProvider(ImageType type)
-    : d(new QQmlImageProviderPrivate)
+QQuickImageProvider::QQuickImageProvider(ImageType type)
+    : d(new QQuickImageProviderPrivate)
 {
     d->type = type;
 }
 
 /*!
-    Destroys the QQmlImageProvider
+    Destroys the QQuickImageProvider
 
     \note The destructor of your derived class need to be thread safe.
 */
-QQmlImageProvider::~QQmlImageProvider()
+QQuickImageProvider::~QQuickImageProvider()
 {
     delete d;
 }
@@ -256,7 +256,7 @@ QQmlImageProvider::~QQmlImageProvider()
 /*!
     Returns the image type supported by this provider.
 */
-QQmlImageProvider::ImageType QQmlImageProvider::imageType() const
+QQuickImageProvider::ImageType QQuickImageProvider::imageType() const
 {
     return d->type;
 }
@@ -280,7 +280,7 @@ QQmlImageProvider::ImageType QQmlImageProvider::imageType() const
     \note this method may be called by multiple threads, so ensure the
     implementation of this method is reentrant.
 */
-QImage QQmlImageProvider::requestImage(const QString &id, QSize *size, const QSize& requestedSize)
+QImage QQuickImageProvider::requestImage(const QString &id, QSize *size, const QSize& requestedSize)
 {
     Q_UNUSED(id);
     Q_UNUSED(size);
@@ -306,7 +306,7 @@ QImage QQmlImageProvider::requestImage(const QString &id, QSize *size, const QSi
     is used to set the \l {Item::}{width} and \l {Item::}{height} of the
     relevant \l Image if these values have not been set explicitly.
 */
-QPixmap QQmlImageProvider::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
+QPixmap QQuickImageProvider::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
 {
     Q_UNUSED(id);
     Q_UNUSED(size);
@@ -337,7 +337,7 @@ QPixmap QQmlImageProvider::requestPixmap(const QString &id, QSize *size, const Q
     implementation of this method is reentrant.
 */
 
-QQuickTextureFactory *QQmlImageProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
+QQuickTextureFactory *QQuickImageProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
 {
     Q_UNUSED(id);
     Q_UNUSED(size);
similarity index 85%
rename from src/qml/qml/qqmlimageprovider.h
rename to src/quick/util/qquickimageprovider.h
index da4d8c8..2a5d146 100644 (file)
 **
 ****************************************************************************/
 
-#ifndef QQMLIMAGEPROVIDER_H
-#define QQMLIMAGEPROVIDER_H
+#ifndef QQUICKIMAGEPROVIDER_H
+#define QQUICKIMAGEPROVIDER_H
 
-#include <QtQml/qtqmlglobal.h>
+#include <QtQuick/qtquickglobal.h>
 #include <QtGui/qimage.h>
 #include <QtGui/qpixmap.h>
+#include <QtQml/qqmlengine.h>
 
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
 
 
-class QQmlImageProviderPrivate;
+class QQuickImageProviderPrivate;
 class QSGTexture;
 class QQuickCanvas;
 
-class Q_QML_EXPORT QQuickTextureFactory : public QObject
+class Q_QUICK_EXPORT QQuickTextureFactory : public QObject
 {
 public:
     QQuickTextureFactory();
@@ -67,7 +68,7 @@ public:
     virtual QImage image() const;
 };
 
-class Q_QML_EXPORT QQmlImageProvider
+class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase
 {
 public:
     enum ImageType {
@@ -77,8 +78,8 @@ public:
         Invalid
     };
 
-    QQmlImageProvider(ImageType type);
-    virtual ~QQmlImageProvider();
+    QQuickImageProvider(ImageType type);
+    virtual ~QQuickImageProvider();
 
     ImageType imageType() const;
 
@@ -87,11 +88,11 @@ public:
     virtual QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize);
 
 private:
-    QQmlImageProviderPrivate *d;
+    QQuickImageProviderPrivate *d;
 };
 
 QT_END_NAMESPACE
 
 QT_END_HEADER
 
-#endif // QQMLIMAGEPROVIDER
+#endif // QQUICKIMAGEPROVIDER_H
index 6ebdf57..5c73e51 100644 (file)
@@ -41,7 +41,7 @@
 
 #include "qquickpixmapcache_p.h"
 #include <qqmlnetworkaccessmanagerfactory.h>
-#include <qqmlimageprovider.h>
+#include <qquickimageprovider.h>
 
 #include <qqmlengine.h>
 #include <private/qqmlglobal_p.h>
@@ -76,6 +76,16 @@ QT_BEGIN_NAMESPACE
 // The cache limit describes the maximum "junk" in the cache.
 static int cache_limit = 2048 * 1024; // 2048 KB cache limit for embedded in qpixmapcache.cpp
 
+static inline QString imageProviderId(const QUrl &url)
+{
+    return url.host();
+}
+
+static inline QString imageId(const QUrl &url)
+{
+    return url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
+}
+
 QSGTexture *QQuickDefaultTextureFactory::createTexture(QQuickCanvas *) const
 {
     QSGPlainTexture *t = new QSGPlainTexture();
@@ -502,11 +512,15 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
 {
     // fetch
     if (url.scheme() == QLatin1String("image")) {
-        // Use QmlImageProvider
+        // Use QQuickImageProvider
         QSize readSize;
-        QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
-        QQmlImageProvider::ImageType imageType = ep->getImageProviderType(url);
-        if (imageType == QQmlImageProvider::Invalid) {
+
+        QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid;
+        QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url)));
+        if (provider)
+            imageType = provider->imageType();
+
+        if (imageType == QQuickImageProvider::Invalid) {
             QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::Loading;
             QString errorStr = QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString());
             QImage image;
@@ -514,8 +528,8 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
             if (!cancelled.contains(runningJob))
                 runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(image));
             mutex.unlock();
-        } else if (imageType == QQmlImageProvider::Image) {
-            QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+        } else if (imageType == QQuickImageProvider::Image) {
+            QImage image = provider->requestImage(imageId(url), &readSize, requestSize);
             QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError;
             QString errorStr;
             if (image.isNull()) {
@@ -527,7 +541,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
                 runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(image));
             mutex.unlock();
         } else {
-            QQuickTextureFactory *t = ep->getTextureFromProvider(url, &readSize, requestSize);
+            QQuickTextureFactory *t = provider->requestTexture(imageId(url), &readSize, requestSize);
             QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError;
             QString errorStr;
             if (!t) {
@@ -919,33 +933,36 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
 {
     if (url.scheme() == QLatin1String("image")) {
         QSize readSize;
-        QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
-        QQmlImageProvider::ImageType imageType = ep->getImageProviderType(url);
+
+        QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid;
+        QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url)));
+        if (provider)
+            imageType = provider->imageType();
 
         switch (imageType) {
-            case QQmlImageProvider::Invalid:
+            case QQuickImageProvider::Invalid:
                 return new QQuickPixmapData(declarativePixmap, url, requestSize,
                     QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString()));
-            case QQmlImageProvider::Texture:
+            case QQuickImageProvider::Texture:
             {
-                QQuickTextureFactory *texture = ep->getTextureFromProvider(url, &readSize, requestSize);
+                QQuickTextureFactory *texture = provider->requestTexture(imageId(url), &readSize, requestSize);
                 if (texture) {
                     *ok = true;
                     return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize);
                 }
             }
 
-            case QQmlImageProvider::Image:
+            case QQuickImageProvider::Image:
             {
-                QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+                QImage image = provider->requestImage(imageId(url), &readSize, requestSize);
                 if (!image.isNull()) {
                     *ok = true;
                     return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(image), readSize, requestSize);
                 }
             }
-            case QQmlImageProvider::Pixmap:
+            case QQuickImageProvider::Pixmap:
             {
-                QPixmap pixmap = ep->getPixmapFromProvider(url, &readSize, requestSize);
+                QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize);
                 if (!pixmap.isNull()) {
                     *ok = true;
                     return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(pixmap.toImage()), readSize, requestSize);
@@ -1154,9 +1171,11 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
     if (iter == store->m_cache.end()) {
         if (options & QQuickPixmap::Asynchronous) {
             // pixmaps can only be loaded synchronously
-            if (url.scheme() == QLatin1String("image") 
-                    && QQmlEnginePrivate::get(engine)->getImageProviderType(url) == QQmlImageProvider::Pixmap) {
-                options &= ~QQuickPixmap::Asynchronous;
+            if (url.scheme() == QLatin1String("image")) {
+                QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url)));
+                if (provider && provider->imageType() == QQuickImageProvider::Pixmap) {
+                    options &= ~QQuickPixmap::Asynchronous;
+                }
             }
         }
 
index b339e6f..03f2e65 100644 (file)
@@ -47,9 +47,9 @@
 #include <QtGui/qpixmap.h>
 #include <QtCore/qurl.h>
 #include <QtQuick/qtquickglobal.h>
+#include <QtQuick/qquickimageprovider.h>
 
 #include <private/qintrusivelist_p.h>
-#include <qqmlimageprovider.h>
 
 QT_BEGIN_HEADER
 
index c3cec91..d720ef0 100644 (file)
@@ -25,6 +25,7 @@ SOURCES += \
     $$PWD/qquickchangeset.cpp \
     $$PWD/qquicklistcompositor.cpp \
     $$PWD/qquickpathinterpolator.cpp \
+    $$PWD/qquickimageprovider.cpp \
     $$PWD/qquicksvgparser.cpp
 
 HEADERS += \
@@ -58,4 +59,5 @@ HEADERS += \
     $$PWD/qquickchangeset_p.h \
     $$PWD/qquicklistcompositor_p.h \
     $$PWD/qquickpathinterpolator_p.h \
+    $$PWD/qquickimageprovider.h \
     $$PWD/qquicksvgparser_p.h
index 6892680..4d1644f 100644 (file)
@@ -32,7 +32,6 @@ PRIVATETESTS += \
     qqmlecmascript \
     qqmlcontext \
     qqmlexpression \
-    qqmlimageprovider \
     qqmlinstruction \
     qqmllanguage \
     qqmlproperty \
index 122c6a8..989b295 100644 (file)
@@ -37,7 +37,7 @@ Item{
         root.declarativerectangle = a.createObject(root, {"x":17,"y":17, "color":"white", "border.width":3, "innerRect.border.width": 20});
         root.declarativeitem = b.createObject(root, {"x":17,"y":17,"testBool":true,"testInt":17,"testObject":root});
 
-        root.bindingTestObject = c.createObject(root, {'testValue': (function(){return width * 3}) })  // use root.width
-        root.bindingThisTestObject = c.createObject(root, {'testValue': (function(){return this.width * 3}) })  // use width of Item within 'c'
+        root.bindingTestObject = c.createObject(root, {'testValue': Qt.binding(function(){return width * 3}) })  // use root.width
+        root.bindingThisTestObject = c.createObject(root, {'testValue': Qt.binding(function(){return this.width * 3}) })  // use width of Item within 'c'
     }
 }
index 09540f1..0b1b45b 100644 (file)
@@ -2,4 +2,6 @@ import Qt.test 1.0
 
 MyQmlObject {
     property variant a: function myFunction() { return 2; }
+    property variant b: Qt.binding(function() { return 2; })
+    property var c: Qt.binding(function() { return 2; })
 }
index 0f78eaf..3d8fd85 100644 (file)
@@ -24,7 +24,7 @@ MyQmlObject {
         function myFunction() {
             return aNumber * 10;
         }
-        a = myFunction;
+        a = Qt.binding(myFunction);
     }
 
     property QtObject obj: QtObject {
@@ -34,7 +34,7 @@ MyQmlObject {
         }
     }
     onAssignWithThisChanged: {
-        a = obj.myFunction;
+        a = Qt.binding(obj.myFunction);
     }
 
     onAssignToPropertyFromJsFileChanged: {
@@ -47,8 +47,8 @@ MyQmlObject {
 
     property Text text: Text { }
     onAssignToValueTypeChanged: {
-        text.font.pixelSize = (function() { return aNumber * 10; })
-        a = (function() { return text.font.pixelSize; })
+        text.font.pixelSize = Qt.binding(function() { return aNumber * 10; })
+        a = Qt.binding(function() { return text.font.pixelSize; })
     }
 
 
@@ -57,17 +57,17 @@ MyQmlObject {
     onAssignFuncWithoutReturnChanged: {
         function myFunction() {
         }
-        a = myFunction;
+        a = Qt.binding(myFunction);
     }
 
     onAssignWrongTypeChanged: {
         function myFunction() {
             return 'a string';
         }
-        aNumber = myFunction;
+        aNumber = Qt.binding(myFunction);
     }
 
     onAssignWrongTypeToValueTypeChanged: {
-        text.font.pixelSize = (function() { return 'a string'; })
+        text.font.pixelSize = Qt.binding(function() { return 'a string'; })
     }
 }
diff --git a/tests/auto/qml/qqmlecmascript/data/functionAssignment.3.qml b/tests/auto/qml/qqmlecmascript/data/functionAssignment.3.qml
new file mode 100644 (file)
index 0000000..c34a868
--- /dev/null
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Item {
+    property int t1: 1
+    property int t2: 2
+
+    function randomNumber() {
+        return 4;
+    }
+
+    Component.onCompleted: {
+        // shouldn't "convert" the randomNumber function into a binding permanently
+        t1 = Qt.binding(randomNumber)
+
+        // therefore, the following assignment should fail.
+        t2 = randomNumber
+   }
+}
index 14daa76..3ba4e19 100644 (file)
@@ -1,6 +1,6 @@
 function bindProperty()
 {
-    a = (function(){ return aNumber * 10 })
+    a = Qt.binding(function(){ return aNumber * 10 })
 }
 
 
@@ -13,5 +13,5 @@ var testObj = new TestObject()
 
 function bindPropertyWithThis()
 {
-    a = testObj.bindFunction
+    a = Qt.binding(testObj.bindFunction)
 }
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.11.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.11.qml
new file mode 100644 (file)
index 0000000..63be267
--- /dev/null
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+Item {
+    property bool test: false
+    property var fnResult: testFunction(5)
+    property var f1: testFunction
+    property var f2
+
+    function testFunction(x) {
+        return x;
+    }
+
+    Component.onCompleted: {
+        f2 = testFunction;
+        if (fnResult != 5) return;
+        if (f1(6) != 6) return;
+        if (f2(7) != 7) return;
+        if (f1 != f2) return;
+        test = true;
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.12.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.12.qml
new file mode 100644 (file)
index 0000000..3510bd2
--- /dev/null
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Item {
+    property bool test: false
+    property var nullOne: null
+    property var nullTwo
+    property var undefOne: undefined
+    property var undefTwo
+
+    Component.onCompleted: {
+        nullTwo = null;
+        undefTwo = undefined;
+        if (nullOne != null) return;
+        if (nullOne != nullTwo) return;
+        if (undefOne != undefined) return;
+        if (undefOne != undefTwo) return;
+        test = true;
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.13.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.13.qml
new file mode 100644 (file)
index 0000000..14c7c67
--- /dev/null
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Item {
+    property bool test: false
+    property var f: b + 12
+    property int a: 100
+    property int b: testFunction()
+
+    function testFunction() {
+        return a * 3;
+    }
+
+    Component.onCompleted: {
+        if (f != 312) return;
+        a = 120;
+        if (f != 372) return;
+        test = true;
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.14.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.14.qml
new file mode 100644 (file)
index 0000000..a1e2666
--- /dev/null
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+Item {
+    property bool test: false
+    property var f
+    property int a: 100
+    property int b
+
+    function testFunction() {
+        return a * 3;
+    }
+
+    Component.onCompleted: {
+        b = Qt.binding(testFunction);
+        f = Qt.binding(function() { return b + 12; });
+        if (f != 312) return;
+        a = 120;
+        if (f != 372) return;
+        test = true;
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.15.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.15.qml
new file mode 100644 (file)
index 0000000..5e5071f
--- /dev/null
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+
+Item {
+    property bool test: false
+    property var storedBinding: [ Qt.binding(function() { return testFunction() + 12; }) ]
+    property int a: 100
+    property int b
+
+    function testFunction() {
+        return a * 3;
+    }
+
+    Component.onCompleted: {
+        b = storedBinding[0];
+        if (b != 312) return;
+        a = 120;
+        if (b != 372) return;
+        test = true;
+    }
+}
index 5770dc4..4389fe5 100644 (file)
@@ -195,6 +195,7 @@ private slots:
     void functionAssignment_fromJS();
     void functionAssignment_fromJS_data();
     void functionAssignmentfromJS_invalid();
+    void functionAssignment_afterBinding();
     void eval();
     void function();
     void functionException();
@@ -3769,6 +3770,11 @@ void tst_qqmlecmascript::propertyVar_data()
     QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
     QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
     QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
+    QTest::newRow("javascript function assignment") << testFileUrl("propertyVar.11.qml");
+    QTest::newRow("javascript special assignment") << testFileUrl("propertyVar.12.qml");
+    QTest::newRow("declarative binding assignment") << testFileUrl("propertyVar.13.qml");
+    QTest::newRow("imperative binding assignment") << testFileUrl("propertyVar.14.qml");
+    QTest::newRow("stored binding assignment") << testFileUrl("propertyVar.15.qml");
 }
 
 void tst_qqmlecmascript::propertyVar()
@@ -5022,8 +5028,12 @@ void tst_qqmlecmascript::functionAssignment_fromBinding()
     QQmlComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
 
     QString url = component.url().toString();
-    QString warning = url + ":4: Unable to assign a function to a property.";
-    QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+    QString w1 = url + ":4: Unable to assign a function to a property of any type other than var.";
+    QString w2 = url + ":5: Invalid use of Qt.binding() in a binding declaration.";
+    QString w3 = url + ":6: Invalid use of Qt.binding() in a binding declaration.";
+    QTest::ignoreMessage(QtWarningMsg, w1.toLatin1().constData());
+    QTest::ignoreMessage(QtWarningMsg, w2.toLatin1().constData());
+    QTest::ignoreMessage(QtWarningMsg, w3.toLatin1().constData());
     
     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
     QVERIFY(o != 0);
@@ -5091,6 +5101,24 @@ void tst_qqmlecmascript::functionAssignmentfromJS_invalid()
     delete o;
 }
 
+void tst_qqmlecmascript::functionAssignment_afterBinding()
+{
+    QQmlComponent component(&engine, testFileUrl("functionAssignment.3.qml"));
+
+    QString url = component.url().toString();
+    //QString w1 = url + ":16: Error: Cannot assign JavaScript function to int"; // for now, function assignment = binding assignment
+    QString w1 = QLatin1String("WARNING: function assignment is DEPRECATED and will be removed!  Wrap RHS in Qt.binding(): ") + url + QLatin1String(":16");
+    QTest::ignoreMessage(QtWarningMsg, w1.toLatin1().constData());
+
+    QObject *o = component.create();
+    QVERIFY(o != 0);
+    QCOMPARE(o->property("t1"), QVariant::fromValue<int>(4)); // should have bound
+    //QCOMPARE(o->property("t2"), QVariant::fromValue<int>(2)); // should not have changed
+    QCOMPARE(o->property("t2"), QVariant::fromValue<int>(4)); // for now, function assignment = binding assignment
+
+    delete o;
+}
+
 void tst_qqmlecmascript::eval()
 {
     QQmlComponent component(&engine, testFileUrl("eval.qml"));
diff --git a/tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.2.qml b/tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.2.qml
new file mode 100644 (file)
index 0000000..0da717b
--- /dev/null
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+import Test 1.0
+
+MyTypeObject {
+    property int value: 10
+    rect.y: Qt.binding(function() { return value; }); // error.
+
+    Component.onCompleted: {
+        rect.x = 5;
+        rect.x = (function() { return value; }); // error.
+    }
+}
index a652186..9b10803 100644 (file)
@@ -1,7 +1,12 @@
+import QtQuick 2.0
 import Test 1.0
 
 MyTypeObject {
     property int value: 10
 
     rect.x: value
+
+    Component.onCompleted: {
+        rect.y = Qt.binding(function() { return value + 5; });
+    }
 }
index 0aa223e..c37a42f 100644 (file)
@@ -871,17 +871,37 @@ void tst_qqmlvaluetypes::color()
 // Test bindings can write to value types
 void tst_qqmlvaluetypes::bindingAssignment()
 {
+    // binding declaration
+    {
     QQmlComponent component(&engine, testFileUrl("bindingAssignment.qml"));
     MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
     QVERIFY(object != 0);
 
     QCOMPARE(object->rect().x(), 10);
+    QCOMPARE(object->rect().y(), 15);
 
     object->setProperty("value", QVariant(92));
 
     QCOMPARE(object->rect().x(), 92);
+    QCOMPARE(object->rect().y(), 97);
 
     delete object;
+    }
+
+    // function assignment should fail without crashing
+    {
+    QString warning1 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":6: Invalid use of Qt.binding() in a binding declaration.");
+    QString warning2 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":10: Error: Cannot assign JavaScript function to value-type property");
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+    QQmlComponent component(&engine, testFileUrl("bindingAssignment.2.qml"));
+    MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->rect().x(), 5);
+    object->setProperty("value", QVariant(92));
+    QCOMPARE(object->rect().x(), 5);
+    delete object;
+    }
 }
 
 // Test bindings can read from value types
@@ -1,8 +1,8 @@
 CONFIG += testcase
-TARGET = tst_qqmlimageprovider
+TARGET = tst_qquickimageprovider
 macx:CONFIG -= app_bundle
 
-SOURCES += tst_qqmlimageprovider.cpp
+SOURCES += tst_qquickimageprovider.cpp
 
 CONFIG += parallel_test
 
 #include <qtest.h>
 #include <QtTest/QtTest>
 #include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlimageprovider.h>
+#include <QtQuick/qquickimageprovider.h>
 #include <private/qquickimage_p.h>
 #include <QImageReader>
 #include <QWaitCondition>
 
-Q_DECLARE_METATYPE(QQmlImageProvider*);
+Q_DECLARE_METATYPE(QQuickImageProvider*);
 
-class tst_qqmlimageprovider : public QObject
+class tst_qquickimageprovider : public QObject
 {
     Q_OBJECT
 public:
-    tst_qqmlimageprovider()
+    tst_qquickimageprovider()
     {
     }
 
@@ -74,15 +74,15 @@ private slots:
 private:
     QString newImageFileName() const;
     void fillRequestTestsData(const QString &id);
-    void runTest(bool async, QQmlImageProvider *provider);
+    void runTest(bool async, QQuickImageProvider *provider);
 };
 
 
-class TestQImageProvider : public QQmlImageProvider
+class TestQImageProvider : public QQuickImageProvider
 {
 public:
     TestQImageProvider(bool *deleteWatch = 0)
-        : QQmlImageProvider(Image), deleteWatch(deleteWatch)
+        : QQuickImageProvider(Image), deleteWatch(deleteWatch)
     {
     }
 
@@ -115,11 +115,11 @@ public:
 Q_DECLARE_METATYPE(TestQImageProvider*);
 
 
-class TestQPixmapProvider : public QQmlImageProvider
+class TestQPixmapProvider : public QQuickImageProvider
 {
 public:
     TestQPixmapProvider(bool *deleteWatch = 0)
-        : QQmlImageProvider(Pixmap), deleteWatch(deleteWatch)
+        : QQuickImageProvider(Pixmap), deleteWatch(deleteWatch)
     {
     }
 
@@ -152,7 +152,7 @@ public:
 Q_DECLARE_METATYPE(TestQPixmapProvider*);
 
 
-QString tst_qqmlimageprovider::newImageFileName() const
+QString tst_qquickimageprovider::newImageFileName() const
 {
     // need to generate new filenames each time or else images are loaded
     // from cache and we won't get loading status changes when testing 
@@ -161,7 +161,7 @@ QString tst_qqmlimageprovider::newImageFileName() const
     return QString("image://test/image-%1.png").arg(count++);
 }
 
-void tst_qqmlimageprovider::fillRequestTestsData(const QString &id)
+void tst_qquickimageprovider::fillRequestTestsData(const QString &id)
 {
     QTest::addColumn<QString>("source");
     QTest::addColumn<QString>("imageId");
@@ -207,7 +207,7 @@ void tst_qqmlimageprovider::fillRequestTestsData(const QString &id)
         << "file::2:1: QML Image: Invalid image provider: image://bogus/exists.png";
 }
 
-void tst_qqmlimageprovider::runTest(bool async, QQmlImageProvider *provider)
+void tst_qquickimageprovider::runTest(bool async, QQuickImageProvider *provider)
 {
     QFETCH(QString, source);
     QFETCH(QString, imageId);
@@ -260,46 +260,46 @@ void tst_qqmlimageprovider::runTest(bool async, QQmlImageProvider *provider)
     delete obj;
 }
 
-void tst_qqmlimageprovider::requestImage_sync_data()
+void tst_qquickimageprovider::requestImage_sync_data()
 {
     fillRequestTestsData("qimage|sync");
 }
 
-void tst_qqmlimageprovider::requestImage_sync()
+void tst_qquickimageprovider::requestImage_sync()
 {
     bool deleteWatch = false;
     runTest(false, new TestQImageProvider(&deleteWatch));
     QVERIFY(deleteWatch);
 }
 
-void tst_qqmlimageprovider::requestImage_async_data()
+void tst_qquickimageprovider::requestImage_async_data()
 {
     fillRequestTestsData("qimage|async");
 }
 
-void tst_qqmlimageprovider::requestImage_async()
+void tst_qquickimageprovider::requestImage_async()
 {
     bool deleteWatch = false;
     runTest(true, new TestQImageProvider(&deleteWatch));
     QVERIFY(deleteWatch);
 }
 
-void tst_qqmlimageprovider::requestPixmap_sync_data()
+void tst_qquickimageprovider::requestPixmap_sync_data()
 {
     fillRequestTestsData("qpixmap");
 }
 
-void tst_qqmlimageprovider::requestPixmap_sync()
+void tst_qquickimageprovider::requestPixmap_sync()
 {
     bool deleteWatch = false;
     runTest(false, new TestQPixmapProvider(&deleteWatch));
     QVERIFY(deleteWatch);
 }
 
-void tst_qqmlimageprovider::requestPixmap_async()
+void tst_qquickimageprovider::requestPixmap_async()
 {
     QQmlEngine engine;
-    QQmlImageProvider *provider = new TestQPixmapProvider();
+    QQuickImageProvider *provider = new TestQPixmapProvider();
 
     engine.addImageProvider("test", provider);
     QVERIFY(engine.imageProvider("test") != 0);
@@ -314,17 +314,17 @@ void tst_qqmlimageprovider::requestPixmap_async()
     delete obj;
 }
 
-void tst_qqmlimageprovider::removeProvider_data()
+void tst_qquickimageprovider::removeProvider_data()
 {
-    QTest::addColumn<QQmlImageProvider*>("provider");
+    QTest::addColumn<QQuickImageProvider*>("provider");
 
-    QTest::newRow("qimage") << static_cast<QQmlImageProvider*>(new TestQImageProvider);
-    QTest::newRow("qpixmap") << static_cast<QQmlImageProvider*>(new TestQPixmapProvider);
+    QTest::newRow("qimage") << static_cast<QQuickImageProvider*>(new TestQImageProvider);
+    QTest::newRow("qpixmap") << static_cast<QQuickImageProvider*>(new TestQPixmapProvider);
 }
 
-void tst_qqmlimageprovider::removeProvider()
+void tst_qquickimageprovider::removeProvider()
 {
-    QFETCH(QQmlImageProvider*, provider);
+    QFETCH(QQuickImageProvider*, provider);
 
     QQmlEngine engine;
 
@@ -353,10 +353,10 @@ void tst_qqmlimageprovider::removeProvider()
     delete obj;
 }
 
-class TestThreadProvider : public QQmlImageProvider
+class TestThreadProvider : public QQuickImageProvider
 {
     public:
-        TestThreadProvider() : QQmlImageProvider(Image), ok(false) {}
+        TestThreadProvider() : QQuickImageProvider(Image), ok(false) {}
 
         ~TestThreadProvider() {}
 
@@ -384,7 +384,7 @@ class TestThreadProvider : public QQmlImageProvider
 };
 
 
-void tst_qqmlimageprovider::threadTest()
+void tst_qquickimageprovider::threadTest()
 {
     QQmlEngine engine;
 
@@ -419,6 +419,6 @@ void tst_qqmlimageprovider::threadTest()
 }
 
 
-QTEST_MAIN(tst_qqmlimageprovider)
+QTEST_MAIN(tst_qquickimageprovider)
 
-#include "tst_qqmlimageprovider.moc"
+#include "tst_qquickimageprovider.moc"
index e0df50a..2ee60b0 100644 (file)
@@ -16,6 +16,6 @@ Item {
     }
 
     Component.onCompleted: {
-        loader.setSource("InitialPropertyValuesComponent.qml", {"canary": (function() { return root.bindable })});
+        loader.setSource("InitialPropertyValuesComponent.qml", {"canary": Qt.binding(function() { return root.bindable })});
     }
 }
index 855322e..8d2eb66 100644 (file)
@@ -42,7 +42,7 @@
 #include <QtTest/QtTest>
 #include <QtQuick/private/qquickpixmapcache_p.h>
 #include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlimageprovider.h>
+#include <QtQuick/qquickimageprovider.h>
 #include <QNetworkReply>
 #include "../../shared/util.h"
 #include "testhttpserver.h"
@@ -335,11 +335,11 @@ void tst_qquickpixmapcache::cancelcrash()
     }
 }
 
-class MyPixmapProvider : public QQmlImageProvider
+class MyPixmapProvider : public QQuickImageProvider
 {
 public:
     MyPixmapProvider()
-    : QQmlImageProvider(Pixmap) {}
+    : QQuickImageProvider(Pixmap) {}
 
     virtual QPixmap requestPixmap(const QString &d, QSize *, const QSize &) {
         Q_UNUSED(d)
index 4065dbf..45fa976 100644 (file)
@@ -15,6 +15,7 @@ PRIVATETESTS += \
     qquickapplication \
     qquickbehaviors \
     qquickfontloader \
+    qquickimageprovider \
     qquickpath \
     qquicksmoothedanimation \
     qquickspringanimation \