summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Jones <martin.jones@nokia.com>2010-02-16 01:27:24 (GMT)
committerMartin Jones <martin.jones@nokia.com>2010-02-16 01:27:24 (GMT)
commitb77e592cf9709c31f61c3e1d229b2a6c446ab8bc (patch)
treeef3099221a5f35db3a198821b2c5cd464753ec89
parent62d585e8ec6c09406fa28f9edf29b56b2d67c739 (diff)
downloadQt-b77e592cf9709c31f61c3e1d229b2a6c446ab8bc.zip
Qt-b77e592cf9709c31f61c3e1d229b2a6c446ab8bc.tar.gz
Qt-b77e592cf9709c31f61c3e1d229b2a6c446ab8bc.tar.bz2
Add QmlImageProvider to allow asynchronous access to images.
Setting an image source to image://providerid/imageid will pass the request for imageid to the provider registered for providerid. QmlImageProvider::request() is run in a low priority thread, so the main thread is not blocked while the image is loaded/rendered. Reviewed-by: Aaron Kennedy
-rw-r--r--examples/declarative/imageprovider/imageprovider.pro9
-rw-r--r--examples/declarative/imageprovider/imageprovider.qrc5
-rw-r--r--examples/declarative/imageprovider/main.cpp99
-rw-r--r--examples/declarative/imageprovider/view.qml22
-rw-r--r--src/declarative/qml/qml.pri2
-rw-r--r--src/declarative/qml/qmlengine.cpp89
-rw-r--r--src/declarative/qml/qmlengine.h5
-rw-r--r--src/declarative/qml/qmlengine_p.h7
-rw-r--r--src/declarative/qml/qmlimageprovider.cpp68
-rw-r--r--src/declarative/qml/qmlimageprovider.h64
-rw-r--r--src/declarative/util/qmlpixmapcache.cpp38
-rw-r--r--tests/auto/declarative/declarative.pro1
-rw-r--r--tests/auto/declarative/qmlimageprovider/data/exists.pngbin0 -> 2738 bytes
-rw-r--r--tests/auto/declarative/qmlimageprovider/data/exists1.pngbin0 -> 2738 bytes
-rw-r--r--tests/auto/declarative/qmlimageprovider/data/exists2.pngbin0 -> 2738 bytes
-rw-r--r--tests/auto/declarative/qmlimageprovider/qmlimageprovider.pro12
-rw-r--r--tests/auto/declarative/qmlimageprovider/tst_qmlimageprovider.cpp164
17 files changed, 562 insertions, 23 deletions
diff --git a/examples/declarative/imageprovider/imageprovider.pro b/examples/declarative/imageprovider/imageprovider.pro
new file mode 100644
index 0000000..60423ab
--- /dev/null
+++ b/examples/declarative/imageprovider/imageprovider.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+TARGET = imageprovider
+DEPENDPATH += .
+INCLUDEPATH += .
+QT += declarative
+
+# Input
+SOURCES += main.cpp
+RESOURCES += imageprovider.qrc
diff --git a/examples/declarative/imageprovider/imageprovider.qrc b/examples/declarative/imageprovider/imageprovider.qrc
new file mode 100644
index 0000000..17e9301
--- /dev/null
+++ b/examples/declarative/imageprovider/imageprovider.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>view.qml</file>
+</qresource>
+</RCC>
diff --git a/examples/declarative/imageprovider/main.cpp b/examples/declarative/imageprovider/main.cpp
new file mode 100644
index 0000000..718e9bb
--- /dev/null
+++ b/examples/declarative/imageprovider/main.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+
+#include <qmlengine.h>
+#include <qmlcontext.h>
+#include <qml.h>
+#include <qmlgraphicsitem.h>
+#include <qmlimageprovider.h>
+#include <qmlview.h>
+#include <QImage>
+#include <QPainter>
+
+/*
+ This example illustrates using a QmlImageProvider to serve
+ images asynchronously.
+*/
+
+//![0]
+class ColorImageProvider : public QmlImageProvider
+{
+public:
+ // This is run in a low priority thread.
+ QImage request(const QString &id) {
+ QImage image(100, 50, QImage::Format_RGB32);
+ image.fill(QColor(id).rgba());
+ QPainter p(&image);
+ p.setPen(Qt::black);
+ p.drawText(QRectF(0,0,100,50),Qt::AlignCenter,id);
+ return image;
+ }
+};
+
+int main(int argc, char ** argv)
+{
+ QApplication app(argc, argv);
+
+ QmlView view;
+ view.setUrl(QUrl("qrc:view.qml"));
+
+ view.engine()->addImageProvider("colors", new ColorImageProvider);
+
+ QStringList dataList;
+ dataList.append("image://colors/red");
+ dataList.append("image://colors/green");
+ dataList.append("image://colors/blue");
+ dataList.append("image://colors/brown");
+ dataList.append("image://colors/orange");
+ dataList.append("image://colors/purple");
+ dataList.append("image://colors/yellow");
+
+ QmlContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
+
+ view.execute();
+ view.show();
+
+ return app.exec();
+}
+//![0]
diff --git a/examples/declarative/imageprovider/view.qml b/examples/declarative/imageprovider/view.qml
new file mode 100644
index 0000000..2ab729d
--- /dev/null
+++ b/examples/declarative/imageprovider/view.qml
@@ -0,0 +1,22 @@
+import Qt 4.6
+//![0]
+ListView {
+ width: 100
+ height: 100
+ anchors.fill: parent
+ model: myModel
+ delegate: Component {
+ Item {
+ width: 100
+ height: 50
+ Text {
+ text: "Loading..."
+ anchors.centerIn: parent
+ }
+ Image {
+ source: modelData
+ }
+ }
+ }
+}
+//![0]
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index cd2fbff..021ef9e 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -50,6 +50,7 @@ SOURCES += \
$$PWD/qmltypenamescriptclass.cpp \
$$PWD/qmllistscriptclass.cpp \
$$PWD/qmlworkerscript.cpp \
+ $$PWD/qmlimageprovider.cpp \
$$PWD/qmlnetworkaccessmanagerfactory.cpp
HEADERS += \
$$PWD/qmlparser_p.h \
@@ -117,6 +118,7 @@ HEADERS += \
$$PWD/qmlworkerscript_p.h \
$$PWD/qmlscriptclass_p.h \
$$PWD/qmlguard_p.h \
+ $$PWD/qmlimageprovider.h \
$$PWD/qmlnetworkaccessmanagerfactory.h
QT += sql
include(parser/parser.pri)
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index cdbe5f3..4edab4d 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -65,6 +65,7 @@
#include "qmlcomponent_p.h"
#include "qmlscriptclass_p.h"
#include "qmlnetworkaccessmanagerfactory.h"
+#include "qmlimageprovider.h"
#include <qfxperf_p_p.h>
@@ -85,6 +86,7 @@
#include <QtCore/qthread.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdir.h>
+#include <QtCore/qmutex.h>
#include <QtGui/qcolor.h>
#include <QtGui/qvector3d.h>
#include <QtGui/qsound.h>
@@ -424,6 +426,7 @@ QmlContext *QmlEngine::rootContext()
void QmlEngine::setNetworkAccessManagerFactory(QmlNetworkAccessManagerFactory *factory)
{
Q_D(QmlEngine);
+ QMutexLocker locker(&d->mutex);
d->networkAccessManagerFactory = factory;
}
@@ -438,17 +441,24 @@ QmlNetworkAccessManagerFactory *QmlEngine::networkAccessManagerFactory() const
return d->networkAccessManagerFactory;
}
+QNetworkAccessManager *QmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
+{
+ QMutexLocker locker(&mutex);
+ QNetworkAccessManager *nam;
+ if (networkAccessManagerFactory) {
+ nam = networkAccessManagerFactory->create(parent);
+ } else {
+ nam = new QNetworkAccessManager(parent);
+ }
+
+ return nam;
+}
+
QNetworkAccessManager *QmlEnginePrivate::getNetworkAccessManager() const
{
Q_Q(const QmlEngine);
-
- if (!networkAccessManager) {
- if (networkAccessManagerFactory) {
- networkAccessManager = networkAccessManagerFactory->create(const_cast<QmlEngine*>(q));
- } else {
- networkAccessManager = new QNetworkAccessManager(const_cast<QmlEngine*>(q));
- }
- }
+ if (!networkAccessManager)
+ networkAccessManager = createNetworkAccessManager(const_cast<QmlEngine*>(q));
return networkAccessManager;
}
@@ -470,6 +480,69 @@ QNetworkAccessManager *QmlEngine::networkAccessManager() const
}
/*!
+ Sets the \a provider to use for images requested via the \e image: url
+ scheme, with host \a providerId.
+
+ QmlImageProvider allows images to be provided to QML asynchronously.
+ The image request will be run in a low priority thread. This allows
+ potentially costly image loading to be done in the background, without
+ affecting the performance of the UI.
+
+ Note that images loaded from a QmlImageProvider are cached by
+ QPixmapCache, similar to any image loaded by QML.
+
+ The QmlEngine assumes ownership of the provider.
+
+ This example creates a provider with id \e colors:
+
+ \snippet examples/declarative/imageprovider/main.cpp 0
+
+ \snippet examples/declarative/imageprovider/view.qml 0
+
+ \sa removeImageProvider()
+*/
+void QmlEngine::addImageProvider(const QString &providerId, QmlImageProvider *provider)
+{
+ Q_D(QmlEngine);
+ QMutexLocker locker(&d->mutex);
+ d->imageProviders.insert(providerId, provider);
+}
+
+/*!
+ Returns the QmlImageProvider set for \a providerId.
+*/
+QmlImageProvider *QmlEngine::imageProvider(const QString &providerId) const
+{
+ Q_D(const QmlEngine);
+ QMutexLocker locker(&d->mutex);
+ return d->imageProviders.value(providerId);
+}
+
+/*!
+ Removes the QmlImageProvider for \a providerId.
+
+ Returns the provider if it was found; otherwise returns 0.
+
+ \sa addImageProvider()
+*/
+void QmlEngine::removeImageProvider(const QString &providerId)
+{
+ Q_D(QmlEngine);
+ QMutexLocker locker(&d->mutex);
+ delete d->imageProviders.take(providerId);
+}
+
+QImage QmlEnginePrivate::getImageFromProvider(const QUrl &url)
+{
+ QMutexLocker locker(&mutex);
+ QImage image;
+ QmlImageProvider *provider = imageProviders.value(url.host());
+ if (provider)
+ image = provider->request(url.path().mid(1));
+ return image;
+}
+
+/*!
Return the base URL for this engine. The base URL is only used to resolve
components when a relative URL is passed to the QmlComponent constructor.
diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h
index 7ee014a..a59a1ba 100644
--- a/src/declarative/qml/qmlengine.h
+++ b/src/declarative/qml/qmlengine.h
@@ -62,6 +62,7 @@ class QmlType;
class QUrl;
class QScriptEngine;
class QScriptContext;
+class QmlImageProvider;
class QNetworkAccessManager;
class QmlNetworkAccessManagerFactory;
class Q_DECLARATIVE_EXPORT QmlEngine : public QObject
@@ -83,6 +84,10 @@ public:
QNetworkAccessManager *networkAccessManager() const;
+ void addImageProvider(const QString &id, QmlImageProvider *);
+ QmlImageProvider *imageProvider(const QString &id) const;
+ void removeImageProvider(const QString &id);
+
void setOfflineStoragePath(const QString& dir);
QString offlineStoragePath() const;
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index 13ed5ef..87864b7 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -75,6 +75,7 @@
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
#include <QtCore/qstack.h>
+#include <QtCore/qmutex.h>
#include <QtScript/qscriptengine.h>
#include <private/qobject_p.h>
@@ -211,10 +212,16 @@ public:
bool inBeginCreate;
+ QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
QNetworkAccessManager *getNetworkAccessManager() const;
mutable QNetworkAccessManager *networkAccessManager;
mutable QmlNetworkAccessManagerFactory *networkAccessManagerFactory;
+ QHash<QString,QmlImageProvider*> imageProviders;
+ QImage getImageFromProvider(const QUrl &url);
+
+ mutable QMutex mutex;
+
QmlCompositeTypeManager typeManager;
QStringList fileImportPath;
QString offlineStoragePath;
diff --git a/src/declarative/qml/qmlimageprovider.cpp b/src/declarative/qml/qmlimageprovider.cpp
new file mode 100644
index 0000000..ebb8656
--- /dev/null
+++ b/src/declarative/qml/qmlimageprovider.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlimageprovider.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QmlImageProvider
+ \brief The QmlImageProvider class provides an interface for threaded image requests.
+
+ Note: the request() method may be called by multiple threads, so ensure the
+ implementation of this method is reentrant.
+
+ \sa QmlEngine::addImageProvider()
+*/
+QmlImageProvider::~QmlImageProvider()
+{
+}
+
+/*!
+ \fn QImage QmlImageProvider::request(const QString &id)
+
+ Implement this method to return the image with \a id.
+
+ Note: this method may be called by multiple threads, so ensure the
+ implementation of this method is reentrant.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlimageprovider.h b/src/declarative/qml/qmlimageprovider.h
new file mode 100644
index 0000000..9804815
--- /dev/null
+++ b/src/declarative/qml/qmlimageprovider.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLIMAGEPROVIDER_H
+#define QMLIMAGEPROVIDER_H
+
+#include <QtGui/qimage.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QmlImageProvider
+{
+public:
+ virtual ~QmlImageProvider();
+ virtual QImage request(const QString &id) = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLIMAGEPROVIDER
diff --git a/src/declarative/util/qmlpixmapcache.cpp b/src/declarative/util/qmlpixmapcache.cpp
index c03b5df..623aaf0 100644
--- a/src/declarative/util/qmlpixmapcache.cpp
+++ b/src/declarative/util/qmlpixmapcache.cpp
@@ -41,11 +41,13 @@
#include "qmlpixmapcache_p.h"
#include "qmlnetworkaccessmanagerfactory.h"
+#include "qmlimageprovider.h"
#include "qfxperf_p_p.h"
#include <qmlengine.h>
#include <private/qmlglobal_p.h>
+#include <private/qmlengine_p.h>
#include <QCoreApplication>
#include <QImageReader>
@@ -82,7 +84,7 @@ class QmlImageReaderEvent : public QEvent
public:
enum ReadError { NoError, Loading, Decoding };
- QmlImageReaderEvent(QmlImageReaderEvent::ReadError err, const QString &errStr, QImage &img)
+ QmlImageReaderEvent(QmlImageReaderEvent::ReadError err, const QString &errStr, const QImage &img)
: QEvent(QEvent::User), error(err), errorString(errStr), image(img) {}
ReadError error;
@@ -143,13 +145,8 @@ private slots:
private:
QNetworkAccessManager *networkAccessManager() {
- if (!accessManager) {
- if (engine && engine->networkAccessManagerFactory()) {
- accessManager = engine->networkAccessManagerFactory()->create(this);
- } else {
- accessManager = new QNetworkAccessManager(this);
- }
- }
+ if (!accessManager)
+ accessManager = QmlEnginePrivate::get(engine)->createNetworkAccessManager(this);
return accessManager;
}
@@ -197,21 +194,32 @@ bool QmlImageRequestHandler::event(QEvent *event)
break;
}
- QmlPixmapReply *runningJob = reader->jobs.takeFirst();
+ QmlPixmapReply *runningJob = reader->jobs.takeLast();
runningJob->addRef();
runningJob->setLoading();
QUrl url = runningJob->url();
reader->mutex.unlock();
// fetch
- QNetworkRequest req(url);
- req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
- QNetworkReply *reply = networkAccessManager()->get(req);
+ if (url.scheme() == QLatin1String("image")) {
+ QImage image = QmlEnginePrivate::get(engine)->getImageFromProvider(url);
+ QmlImageReaderEvent::ReadError errorCode = QmlImageReaderEvent::NoError;
+ QString errorStr;
+ if (image.isNull()) {
+ errorCode = QmlImageReaderEvent::Loading;
+ errorStr = QLatin1String("Failed to get image from provider: ") + url.toString();
+ }
+ QCoreApplication::postEvent(runningJob, new QmlImageReaderEvent(errorCode, errorStr, image));
+ } else {
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ QNetworkReply *reply = networkAccessManager()->get(req);
- QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress);
- QMetaObject::connect(reply, replyFinished, this, thisNetworkRequestDone);
+ QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress);
+ QMetaObject::connect(reply, replyFinished, this, thisNetworkRequestDone);
- replies.insert(reply, runningJob);
+ replies.insert(reply, runningJob);
+ }
}
return true;
}
diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro
index 8773026..fba63d5 100644
--- a/tests/auto/declarative/declarative.pro
+++ b/tests/auto/declarative/declarative.pro
@@ -57,6 +57,7 @@ SUBDIRS += \
qmlgraphicsrepeater \ # Cover
qmlvaluetypes \ # Cover
qmlxmlhttprequest \ # Cover
+ qmlimageprovider \ # Cover
sql # Cover
diff --git a/tests/auto/declarative/qmlimageprovider/data/exists.png b/tests/auto/declarative/qmlimageprovider/data/exists.png
new file mode 100644
index 0000000..399bd0b
--- /dev/null
+++ b/tests/auto/declarative/qmlimageprovider/data/exists.png
Binary files differ
diff --git a/tests/auto/declarative/qmlimageprovider/data/exists1.png b/tests/auto/declarative/qmlimageprovider/data/exists1.png
new file mode 100644
index 0000000..399bd0b
--- /dev/null
+++ b/tests/auto/declarative/qmlimageprovider/data/exists1.png
Binary files differ
diff --git a/tests/auto/declarative/qmlimageprovider/data/exists2.png b/tests/auto/declarative/qmlimageprovider/data/exists2.png
new file mode 100644
index 0000000..399bd0b
--- /dev/null
+++ b/tests/auto/declarative/qmlimageprovider/data/exists2.png
Binary files differ
diff --git a/tests/auto/declarative/qmlimageprovider/qmlimageprovider.pro b/tests/auto/declarative/qmlimageprovider/qmlimageprovider.pro
new file mode 100644
index 0000000..0ef7739
--- /dev/null
+++ b/tests/auto/declarative/qmlimageprovider/qmlimageprovider.pro
@@ -0,0 +1,12 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+QT += network
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qmlimageprovider.cpp
+
+# QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage
+# LIBS += -lgcov
+
+# Define SRCDIR equal to test's source directory
+DEFINES += SRCDIR=\\\"$$PWD\\\"
diff --git a/tests/auto/declarative/qmlimageprovider/tst_qmlimageprovider.cpp b/tests/auto/declarative/qmlimageprovider/tst_qmlimageprovider.cpp
new file mode 100644
index 0000000..475cb7a
--- /dev/null
+++ b/tests/auto/declarative/qmlimageprovider/tst_qmlimageprovider.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtTest/QtTest>
+#include <QtDeclarative/qmlengine.h>
+#include <QtDeclarative/qmlimageprovider.h>
+#include <private/qmlgraphicsimage_p.h>
+
+#define TRY_WAIT(expr) \
+ do { \
+ for (int ii = 0; ii < 6; ++ii) { \
+ if ((expr)) break; \
+ QTest::qWait(50); \
+ } \
+ QVERIFY((expr)); \
+ } while (false)
+
+
+class tst_qmlimageprovider : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qmlimageprovider()
+ {
+ }
+
+private slots:
+ void imageSource();
+ void imageSource_data();
+ void removeProvider();
+
+private:
+ QmlEngine engine;
+};
+
+class TestProvider : public QmlImageProvider
+{
+public:
+ QImage request(const QString &id) {
+ QImage image;
+ image.load(SRCDIR "/data/" + id);
+ return image;
+ }
+};
+
+void tst_qmlimageprovider::imageSource_data()
+{
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("exists") << "image://test/exists.png" << "";
+ QTest::newRow("missing") << "image://test/no-such-file.png"
+ << "\"Failed to get image from provider: image://test/no-such-file.png\" ";
+ QTest::newRow("unknown provider") << "image://bogus/exists.png"
+ << "\"Failed to get image from provider: image://bogus/exists.png\" ";
+}
+
+void tst_qmlimageprovider::imageSource()
+{
+ QFETCH(QString, source);
+ QFETCH(QString, error);
+
+ if (!error.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
+
+ engine.addImageProvider("test", new TestProvider);
+ QVERIFY(engine.imageProvider("test") != 0);
+
+ QString componentStr = "import Qt 4.6\nImage { source: \"" + source + "\" }";
+ QmlComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QmlGraphicsImage *obj = qobject_cast<QmlGraphicsImage*>(component.create());
+ QVERIFY(obj != 0);
+
+ TRY_WAIT(obj->status() == QmlGraphicsImage::Loading);
+
+ QCOMPARE(obj->source(), QUrl(source));
+
+ if (error.isEmpty()) {
+ TRY_WAIT(obj->status() == QmlGraphicsImage::Ready);
+ QCOMPARE(obj->width(), 100.);
+ QCOMPARE(obj->height(), 100.);
+ QCOMPARE(obj->fillMode(), QmlGraphicsImage::Stretch);
+ QCOMPARE(obj->progress(), 1.0);
+ } else {
+ TRY_WAIT(obj->status() == QmlGraphicsImage::Error);
+ }
+
+ delete obj;
+}
+
+void tst_qmlimageprovider::removeProvider()
+{
+ engine.addImageProvider("test2", new TestProvider);
+ QVERIFY(engine.imageProvider("test2") != 0);
+
+ // add provider, confirm it works
+ QString componentStr = "import Qt 4.6\nImage { source: \"image://test2/exists1.png\" }";
+ QmlComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QmlGraphicsImage *obj = qobject_cast<QmlGraphicsImage*>(component.create());
+ QVERIFY(obj != 0);
+
+ TRY_WAIT(obj->status() == QmlGraphicsImage::Loading);
+ TRY_WAIT(obj->status() == QmlGraphicsImage::Ready);
+
+ QCOMPARE(obj->width(), 100.0);
+
+ // remove the provider and confirm
+ QString error("\"Failed to get image from provider: image://test2/exists2.png\" ");
+ QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
+
+ engine.removeImageProvider("test2");
+
+ obj->setSource(QUrl("image://test2/exists2.png"));
+
+ TRY_WAIT(obj->status() == QmlGraphicsImage::Loading);
+ TRY_WAIT(obj->status() == QmlGraphicsImage::Error);
+
+ delete obj;
+}
+
+
+QTEST_MAIN(tst_qmlimageprovider)
+
+#include "tst_qmlimageprovider.moc"