QDeclarativeGuardedContextData
QDeclarativeGuardImpl
QDeclarativeHandlingSignalProfiler
- QDeclarativeImageProvider
- QDeclarativeImageProviderPrivate
QDeclarativeImportDatabase
QDeclarativeImportedNamespace
QDeclarativeImports
QDeclarativeGestureAreaParser
QDeclarativeGestureAreaPrivate
QDeclarativeGraphics
+ QDeclarativeImageProvider
+ QDeclarativeImageProviderPrivate
QDeclarativeItem
QDeclarativeItemAccessor
QDeclarativeItemChangeListener
\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
id: button
width: 200; height: 80; color: "lightsteelblue"
- MouseArea {
+ MouseArea {
id: mousearea
anchors.fill: parent
color: mousearea.pressed ? "steelblue" : "lightsteelblue"
- MouseArea {
+ MouseArea {
id: mousearea
anchors.fill: parent
}
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:
\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
\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
width: 100
Component.onCompleted: {
- height = (function() { return width * 2 })
+ height = Qt.binding(function() { return width * 2 })
}
}
\endqml
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 {
}
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
--- /dev/null
+/****************************************************************************
+**
+** 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]
--- /dev/null
+/****************************************************************************
+**
+** 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]
--- /dev/null
+/****************************************************************************
+**
+** 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]
--- /dev/null
+/****************************************************************************
+**
+** 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]
--- /dev/null
+/****************************************************************************
+**
+** 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]
$$PWD/qqmltypenamecache.cpp \
$$PWD/qqmlscriptstring.cpp \
$$PWD/qquickworkerscript.cpp \
- $$PWD/qqmlimageprovider.cpp \
$$PWD/qqmlnetworkaccessmanagerfactory.cpp \
$$PWD/qqmldirparser.cpp \
$$PWD/qqmlextensionplugin.cpp \
$$PWD/qqmlscriptstring.h \
$$PWD/qquickworkerscript_p.h \
$$PWD/qqmlguard_p.h \
- $$PWD/qqmlimageprovider.h \
$$PWD/qqmlnetworkaccessmanagerfactory.h \
$$PWD/qqmldirparser_p.h \
$$PWD/qqmlextensioninterface.h \
#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"
qmlRegisterUncreatableType<QQmlLocale>("QtQuick",2,0,"Locale",QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
}
+
+QQmlImageProviderBase::~QQmlImageProviderBase()
+{
+}
+
+
/*!
\qmlclass Qt QQmlEnginePrivate
\ingroup qml-utility-elements
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);
}
/*!
- Removes the QQmlImageProvider for \a providerId.
+ Removes the image provider for \a providerId.
- \sa addImageProvider()
+ \sa addImageProvider(), QQuickImageProvider
*/
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
QT_BEGIN_NAMESPACE
+class Q_QML_EXPORT QQmlImageProviderBase
+{
+public:
+ virtual ~QQmlImageProviderBase();
+};
+
class QQmlComponent;
class QQmlEnginePrivate;
class QQmlImportsPrivate;
class QQmlType;
class QUrl;
class QScriptContext;
-class QQmlImageProvider;
class QNetworkAccessManager;
class QQmlNetworkAccessManagerFactory;
class QQmlIncubationController;
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 *);
#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"
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
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);
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())
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
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
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);
m_contextWrapper.destroy();
m_stringWrapper.destroy();
+ qPersistentDispose(m_bindingFlagKey);
+
m_originalGlobalObject.destroy();
if (m_ownsV8Context)
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)));
// 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).
v8::Persistent<v8::Context> m_context;
QScriptOriginalGlobalObject m_originalGlobalObject;
+ v8::Persistent<v8::String> m_bindingFlagKey;
+
QV8StringWrapper m_stringWrapper;
QV8ContextWrapper m_contextWrapper;
QV8QObjectWrapper m_qobjectWrapper;
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)
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()) {
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 =
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; \
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);
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)
}
if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) {
- itemPriv->clipNode()->setRect(item->boundingRect());
+ itemPriv->clipNode()->setRect(item->clipRect());
itemPriv->clipNode()->update();
}
/*! \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);
{
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());
void setFlags(Flags flags);
virtual QRectF boundingRect() const;
+ virtual QRectF clipRect() const;
bool hasActiveFocus() const;
bool hasFocus() const;
d->width + 2 * d->penMargin, d->height + 2 * d->penMargin);
}
+QRectF QQuickRectangle::clipRect() const
+{
+ return QQuickRectangle::boundingRect();
+}
+
QT_END_NAMESPACE
void setRadius(qreal radius);
virtual QRectF boundingRect() const;
+ virtual QRectF clipRect() const;
Q_SIGNALS:
void colorChanged();
#include <QGuiApplication>
#include <QOpenGLContext>
-#include <QQmlImageProvider>
#include <private/qqmlglobal_p.h>
#include <QtQuick/private/qsgtexture_p.h>
#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
**
****************************************************************************/
-#include "qqmlimageprovider.h"
+#include "qquickimageprovider.h"
QT_BEGIN_NAMESPACE
-class QQmlImageProviderPrivate
+class QQuickImageProviderPrivate
{
public:
- QQmlImageProvider::ImageType type;
+ QQuickImageProvider::ImageType type;
};
/*!
/*!
- \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
\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
*/
/*!
- \enum QQmlImageProvider::ImageType
+ \enum QQuickImageProvider::ImageType
Defines the type of image supported by this image provider.
/*!
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;
}
/*!
Returns the image type supported by this provider.
*/
-QQmlImageProvider::ImageType QQmlImageProvider::imageType() const
+QQuickImageProvider::ImageType QQuickImageProvider::imageType() const
{
return d->type;
}
\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);
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);
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);
**
****************************************************************************/
-#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();
virtual QImage image() const;
};
-class Q_QML_EXPORT QQmlImageProvider
+class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase
{
public:
enum ImageType {
Invalid
};
- QQmlImageProvider(ImageType type);
- virtual ~QQmlImageProvider();
+ QQuickImageProvider(ImageType type);
+ virtual ~QQuickImageProvider();
ImageType imageType() const;
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
#include "qquickpixmapcache_p.h"
#include <qqmlnetworkaccessmanagerfactory.h>
-#include <qqmlimageprovider.h>
+#include <qquickimageprovider.h>
#include <qqmlengine.h>
#include <private/qqmlglobal_p.h>
// 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();
{
// 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;
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()) {
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) {
{
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);
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;
+ }
}
}
#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
$$PWD/qquickchangeset.cpp \
$$PWD/qquicklistcompositor.cpp \
$$PWD/qquickpathinterpolator.cpp \
+ $$PWD/qquickimageprovider.cpp \
$$PWD/qquicksvgparser.cpp
HEADERS += \
$$PWD/qquickchangeset_p.h \
$$PWD/qquicklistcompositor_p.h \
$$PWD/qquickpathinterpolator_p.h \
+ $$PWD/qquickimageprovider.h \
$$PWD/qquicksvgparser_p.h
qqmlecmascript \
qqmlcontext \
qqmlexpression \
- qqmlimageprovider \
qqmlinstruction \
qqmllanguage \
qqmlproperty \
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'
}
}
MyQmlObject {
property variant a: function myFunction() { return 2; }
+ property variant b: Qt.binding(function() { return 2; })
+ property var c: Qt.binding(function() { return 2; })
}
function myFunction() {
return aNumber * 10;
}
- a = myFunction;
+ a = Qt.binding(myFunction);
}
property QtObject obj: QtObject {
}
}
onAssignWithThisChanged: {
- a = obj.myFunction;
+ a = Qt.binding(obj.myFunction);
}
onAssignToPropertyFromJsFileChanged: {
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; })
}
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'; })
}
}
--- /dev/null
+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
+ }
+}
function bindProperty()
{
- a = (function(){ return aNumber * 10 })
+ a = Qt.binding(function(){ return aNumber * 10 })
}
function bindPropertyWithThis()
{
- a = testObj.bindFunction
+ a = Qt.binding(testObj.bindFunction)
}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
void functionAssignment_fromJS();
void functionAssignment_fromJS_data();
void functionAssignmentfromJS_invalid();
+ void functionAssignment_afterBinding();
void eval();
void function();
void functionException();
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()
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);
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"));
--- /dev/null
+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.
+ }
+}
+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; });
+ }
}
// 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
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()
{
}
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)
{
}
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)
{
}
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
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");
<< "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);
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);
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;
delete obj;
}
-class TestThreadProvider : public QQmlImageProvider
+class TestThreadProvider : public QQuickImageProvider
{
public:
- TestThreadProvider() : QQmlImageProvider(Image), ok(false) {}
+ TestThreadProvider() : QQuickImageProvider(Image), ok(false) {}
~TestThreadProvider() {}
};
-void tst_qqmlimageprovider::threadTest()
+void tst_qquickimageprovider::threadTest()
{
QQmlEngine engine;
}
-QTEST_MAIN(tst_qqmlimageprovider)
+QTEST_MAIN(tst_qquickimageprovider)
-#include "tst_qqmlimageprovider.moc"
+#include "tst_qquickimageprovider.moc"
}
Component.onCompleted: {
- loader.setSource("InitialPropertyValuesComponent.qml", {"canary": (function() { return root.bindable })});
+ loader.setSource("InitialPropertyValuesComponent.qml", {"canary": Qt.binding(function() { return root.bindable })});
}
}
#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"
}
}
-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)
qquickapplication \
qquickbehaviors \
qquickfontloader \
+ qquickimageprovider \
qquickpath \
qquicksmoothedanimation \
qquickspringanimation \