summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Jones <martin.jones@nokia.com>2010-01-29 01:58:52 (GMT)
committerMartin Jones <martin.jones@nokia.com>2010-01-29 01:58:52 (GMT)
commit741d21719b942faa22a4bdf1a951d82d9fe73a68 (patch)
tree83b7edcff3fe208b311442490da708a651c8a640
parent7081c571a33480cb6bb3db7391c9570e4b4e4be1 (diff)
downloadQt-741d21719b942faa22a4bdf1a951d82d9fe73a68.zip
Qt-741d21719b942faa22a4bdf1a951d82d9fe73a68.tar.gz
Qt-741d21719b942faa22a4bdf1a951d82d9fe73a68.tar.bz2
Move image network access into a separate thread, with decoding.
-rw-r--r--src/declarative/qml/qml.pri11
-rw-r--r--src/declarative/qml/qmlengine.cpp62
-rw-r--r--src/declarative/qml/qmlengine.h8
-rw-r--r--src/declarative/qml/qmlengine_p.h3
-rw-r--r--src/declarative/util/qmlpixmapcache.cpp321
-rw-r--r--src/declarative/util/qmlpixmapcache_p.h10
-rw-r--r--tools/qmlviewer/qmlviewer.cpp162
-rw-r--r--tools/qmlviewer/qmlviewer.h6
8 files changed, 388 insertions, 195 deletions
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index 6f2f57f..cd2fbff 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -1,5 +1,4 @@
INCLUDEPATH += $$PWD
-
SOURCES += \
$$PWD/qmlparser.cpp \
$$PWD/qmlinstruction.cpp \
@@ -50,8 +49,8 @@ SOURCES += \
$$PWD/qmlvaluetypescriptclass.cpp \
$$PWD/qmltypenamescriptclass.cpp \
$$PWD/qmllistscriptclass.cpp \
- $$PWD/qmlworkerscript.cpp
-
+ $$PWD/qmlworkerscript.cpp \
+ $$PWD/qmlnetworkaccessmanagerfactory.cpp
HEADERS += \
$$PWD/qmlparser_p.h \
$$PWD/qmlglobal_p.h \
@@ -117,10 +116,8 @@ HEADERS += \
$$PWD/qmllistscriptclass_p.h \
$$PWD/qmlworkerscript_p.h \
$$PWD/qmlscriptclass_p.h \
- $$PWD/qmlguard_p.h
-
+ $$PWD/qmlguard_p.h \
+ $$PWD/qmlnetworkaccessmanagerfactory.h
QT += sql
-
include(parser/parser.pri)
include(rewriter/rewriter.pri)
-
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index 5a40468..b3ac1bb 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -64,6 +64,7 @@
#include "qmlworkerscript_p.h"
#include "qmlcomponent_p.h"
#include "qmlscriptclass_p.h"
+#include "qmlnetworkaccessmanagerfactory.h"
#include <qfxperf_p_p.h>
@@ -121,7 +122,8 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e)
contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0),
globalClass(0), cleanup(0), erroredBindings(0), inProgressCreations(0),
scriptEngine(this), workerScriptEngine(0), componentAttacheds(0), inBeginCreate(false),
- networkAccessManager(0), typeManager(e), uniqueId(1)
+ networkAccessManager(0), networkAccessManagerFactory(0), accessManagerValid(false),
+ typeManager(e), uniqueId(1)
{
globalClass = new QmlGlobalScriptClass(&scriptEngine);
fileImportPath.append(QLibraryInfo::location(QLibraryInfo::DataPath)+QDir::separator()+QLatin1String("qml"));
@@ -386,34 +388,64 @@ QmlContext *QmlEngine::rootContext()
}
/*!
- Sets the common QNetworkAccessManager, \a network, used by all QML elements
- instantiated by this engine.
+ Sets the \a factory to use for creating QNetworkAccessManager(s).
+
+ QNetworkAccessManager is used for all network access by QML.
+ By implementing a factory it is possible to create custom
+ QNetworkAccessManager with specialized caching, proxy and
+ cookie support.
+*/
+void QmlEngine::setNetworkAccessManagerFactory(QmlNetworkAccessManagerFactory *factory)
+{
+ Q_D(QmlEngine);
+ d->networkAccessManagerFactory = factory;
+}
- If the parent of \a network is this engine, the engine takes ownership and
- will delete it as needed. Otherwise, ownership remains with the caller.
+/*!
+ Returns the current QmlNetworkAccessManagerFactory.
- This method should only be called before any QmlComponents are instantiated.
+ \sa setNetworkAccessManagerFactory()
*/
-void QmlEngine::setNetworkAccessManager(QNetworkAccessManager *network)
+QmlNetworkAccessManagerFactory *QmlEngine::networkAccessManagerFactory() const
+{
+ Q_D(const QmlEngine);
+ return d->networkAccessManagerFactory;
+}
+
+void QmlEngine::namInvalidated()
{
Q_D(QmlEngine);
- if (d->networkAccessManager && d->networkAccessManager->parent() == this)
- delete d->networkAccessManager;
- d->networkAccessManager = network;
+ d->accessManagerValid = false;
}
/*!
- Returns the common QNetworkAccessManager used by all QML elements
+ Returns a common QNetworkAccessManager which can be used by any QML element
instantiated by this engine.
- The default implements no caching, cookiejar, etc., just a default
- QNetworkAccessManager.
+ If a QmlNetworkAccessManagerFactory has been set and a QNetworkAccessManager
+ has not yet been created, the QmlNetworkAccessManagerFactory will be used
+ to create the QNetworkAccessManager; otherwise the returned QNetworkAccessManager
+ will have no proxy or cache set.
+
+ \sa setNetworkAccessManagerFactory()
*/
QNetworkAccessManager *QmlEngine::networkAccessManager() const
{
Q_D(const QmlEngine);
- if (!d->networkAccessManager)
- d->networkAccessManager = new QNetworkAccessManager(const_cast<QmlEngine*>(this));
+ if (!d->accessManagerValid) {
+ delete d->networkAccessManagerFactory;
+ d->networkAccessManagerFactory = 0;
+ }
+ if (!d->networkAccessManager) {
+ if (d->networkAccessManagerFactory) {
+ connect(d->networkAccessManagerFactory, SIGNAL(invalidated())
+ , this, SLOT(namInvalidated()), Qt::UniqueConnection);
+ d->networkAccessManager = d->networkAccessManagerFactory->create(const_cast<QmlEngine*>(this));
+ } else {
+ d->networkAccessManager = new QNetworkAccessManager(const_cast<QmlEngine*>(this));
+ }
+ d->accessManagerValid = true;
+ }
return d->networkAccessManager;
}
diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h
index 7cbbcac..b9ec277 100644
--- a/src/declarative/qml/qmlengine.h
+++ b/src/declarative/qml/qmlengine.h
@@ -63,6 +63,7 @@ class QUrl;
class QScriptEngine;
class QScriptContext;
class QNetworkAccessManager;
+class QmlNetworkAccessManagerFactory;
class Q_DECLARATIVE_EXPORT QmlEngine : public QObject
{
Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath)
@@ -77,7 +78,9 @@ public:
void addImportPath(const QString& dir);
- void setNetworkAccessManager(QNetworkAccessManager *);
+ void setNetworkAccessManagerFactory(QmlNetworkAccessManagerFactory *);
+ QmlNetworkAccessManagerFactory *networkAccessManagerFactory() const;
+
QNetworkAccessManager *networkAccessManager() const;
void setOfflineStoragePath(const QString& dir);
@@ -92,6 +95,9 @@ public:
Q_SIGNALS:
void quit ();
+private Q_SLOTS:
+ void namInvalidated();
+
private:
Q_DECLARE_PRIVATE(QmlEngine)
};
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index 85e8c80..6f62b40 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -92,6 +92,7 @@ class QmlValueTypeScriptClass;
class QScriptEngineDebugger;
class QNetworkReply;
class QNetworkAccessManager;
+class QmlNetworkAccessManagerFactory;
class QmlAbstractBinding;
class QScriptDeclarativeClass;
class QmlTypeNameScriptClass;
@@ -209,6 +210,8 @@ public:
bool inBeginCreate;
mutable QNetworkAccessManager *networkAccessManager;
+ mutable QmlNetworkAccessManagerFactory *networkAccessManagerFactory;
+ mutable bool accessManagerValid;
QmlCompositeTypeManager typeManager;
QStringList fileImportPath;
diff --git a/src/declarative/util/qmlpixmapcache.cpp b/src/declarative/util/qmlpixmapcache.cpp
index 4c1d448..c058408 100644
--- a/src/declarative/util/qmlpixmapcache.cpp
+++ b/src/declarative/util/qmlpixmapcache.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qmlpixmapcache_p.h"
+#include "qmlnetworkaccessmanagerfactory.h"
#include "qfxperf_p_p.h"
@@ -57,6 +58,15 @@
#include <QWaitCondition>
#include <QtCore/qdebug.h>
#include <private/qobject_p.h>
+#include <QSslError>
+
+#ifdef Q_OS_LINUX
+#include <pthread.h>
+#include <linux/sched.h>
+#endif
+
+// Maximum number of simultaneous image requests to send.
+static const int maxImageRequestCount = 8;
QT_BEGIN_NAMESPACE
@@ -69,105 +79,231 @@ class QmlImageReader : public QThread
{
Q_OBJECT
public:
- QmlImageReader(QObject *parent=0);
+ QmlImageReader(QmlEngine *eng);
~QmlImageReader();
- void read(QmlPixmapReply *rep);
+ QmlPixmapReply *getImage(const QUrl &url);
void cancel(QmlPixmapReply *rep);
+ static QmlImageReader *instance(QmlEngine *engine);
+
protected:
void run();
+ bool event(QEvent *event);
-private:
- struct Job {
- Job() : reply(0), error(false) {}
- QmlPixmapReply *reply;
- QImage img;
- bool error;
- };
+private slots:
+ void networkRequestDone();
+ void namInvalidated() {
+ accessManagerValid = false;
+ }
- void loadImage(Job &job);
+private:
+ QNetworkAccessManager *networkAccessManager() {
+ if (!accessManagerValid) {
+ delete accessManager;
+ accessManager = 0;
+ }
+ if (!accessManager) {
+ if (engine && engine->networkAccessManagerFactory()) {
+ connect(engine->networkAccessManagerFactory(), SIGNAL(invalidated())
+ , this, SLOT(namInvalidated()), Qt::UniqueConnection);
+ accessManager = engine->networkAccessManagerFactory()->create(this);
+ } else {
+ accessManager = new QNetworkAccessManager(this);
+ }
+ accessManagerValid = true;
+ }
+ return accessManager;
+ }
- QList<Job> jobs;
+ QList<QmlPixmapReply*> jobs;
+ QList<QmlPixmapReply*> cancelled;
+ QHash<QNetworkReply*,QmlPixmapReply*> replies;
+ QNetworkAccessManager *accessManager;
+ bool accessManagerValid;
+ QmlEngine *engine;
QMutex mutex;
- QWaitCondition haveJob;
- bool quit;
+ static QHash<QmlEngine *,QmlImageReader*> readers;
};
-class QmlImageDecodeEvent : public QEvent
+QHash<QmlEngine *,QmlImageReader*> QmlImageReader::readers;
+
+class QmlImageReaderEvent : public QEvent
{
public:
- QmlImageDecodeEvent(bool err, QImage &img) : QEvent(QEvent::User), error(err), image(img) {}
+ enum ReadError { NoError, Loading, Decoding };
- bool error;
+ QmlImageReaderEvent(QmlImageReaderEvent::ReadError err, QImage &img)
+ : QEvent(QEvent::User), error(err), image(img) {}
+
+ ReadError error;
QImage image;
};
-Q_GLOBAL_STATIC(QmlImageReader, qmlImageReader)
-
-QmlImageReader::QmlImageReader(QObject *parent) : QThread(parent), quit(false)
+QmlImageReader::QmlImageReader(QmlEngine *eng)
+ : QThread(eng), accessManager(0), accessManagerValid(false), engine(eng)
{
start(QThread::LowPriority);
}
QmlImageReader::~QmlImageReader()
{
- quit = true;
- haveJob.wakeOne();
}
-void QmlImageReader::read(QmlPixmapReply *reply)
+QmlImageReader *QmlImageReader::instance(QmlEngine *engine)
+{
+ QmlImageReader *reader = readers.value(engine);
+ if (!reader) {
+ static QMutex rmutex;
+ rmutex.lock();
+ reader = new QmlImageReader(engine);
+ readers.insert(engine, reader);
+ rmutex.unlock();
+ }
+
+ return reader;
+}
+
+QmlPixmapReply *QmlImageReader::getImage(const QUrl &url)
{
mutex.lock();
- Job job;
- job.reply = reply;
- jobs.append(job);
+ QmlPixmapReply *reply = new QmlPixmapReply(engine, url);
+ jobs.append(reply);
if (jobs.count() == 1)
- haveJob.wakeOne();
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
mutex.unlock();
+ return reply;
}
void QmlImageReader::cancel(QmlPixmapReply *reply)
{
mutex.lock();
- QList<Job>::iterator it = jobs.begin();
- while (it != jobs.end()) {
- if ((*it).reply == reply) {
- jobs.erase(it);
- break;
+ if (reply->isLoading()) {
+ // Already requested. Add to cancel list to be cancelled in reader thread.
+ cancelled.append(reply);
+ if (cancelled.count() == 1)
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ } else {
+ // Not yet processed - just remove from waiting list
+ QList<QmlPixmapReply*>::iterator it = jobs.begin();
+ while (it != jobs.end()) {
+ QmlPixmapReply *job = *it;
+ if (job == reply) {
+ jobs.erase(it);
+ break;
+ }
+ ++it;
}
- ++it;
}
mutex.unlock();
}
-void QmlImageReader::loadImage(Job &job)
+void QmlImageReader::run()
{
- QImageReader imgio(job.reply->device());
- if (imgio.read(&job.img)) {
- job.error = false;
- } else {
- job.error = true;
- qWarning() << imgio.errorString();
+#ifdef Q_OS_LINUX
+ struct sched_param param;
+ int policy;
+
+ pthread_getschedparam(pthread_self(), &policy, &param);
+ pthread_setschedparam(pthread_self(), SCHED_IDLE, &param);
+#endif
+
+ exec();
+}
+
+bool QmlImageReader::event(QEvent *event)
+{
+ if (event->type() == QEvent::User) {
+ static int replyDownloadProgress = -1;
+ static int replyFinished = -1;
+ static int downloadProgress = -1;
+ static int thisNetworkRequestDone = -1;
+
+ if (replyDownloadProgress == -1) {
+ replyDownloadProgress = QNetworkReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
+ replyFinished = QNetworkReply::staticMetaObject.indexOfSignal("finished()");
+ downloadProgress = QmlPixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
+ thisNetworkRequestDone = QmlImageReader::staticMetaObject.indexOfSlot("networkRequestDone()");
+ }
+
+ while (1) {
+ mutex.lock();
+
+ if (cancelled.count()) {
+ for (int i = 0; i < cancelled.count(); ++i) {
+ QmlPixmapReply *job = cancelled.at(i);
+ QNetworkReply *reply = replies.key(job, 0);
+ if (reply && reply->isRunning()) {
+ replies.remove(reply);
+ reply->close();
+ job->release(true);
+ }
+ }
+ cancelled.clear();
+ }
+
+ if (!accessManagerValid) {
+ // throw away existing requests and reschedule.
+ QHash<QNetworkReply*,QmlPixmapReply*>::iterator it = replies.begin();
+ for (; it != replies.end(); ++it) {
+ delete it.key();
+ jobs.prepend(*it);
+ }
+ replies.clear();
+ }
+
+ if (!jobs.count() || replies.count() > maxImageRequestCount) {
+ mutex.unlock();
+ break;
+ }
+
+ QmlPixmapReply *runningJob = jobs.takeFirst();
+ runningJob->addRef();
+ runningJob->setLoading();
+ QUrl url = runningJob->url();
+ mutex.unlock();
+
+ // fetch
+ 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);
+
+ replies.insert(reply, runningJob);
+ }
+ return true;
}
+
+ return QObject::event(event);
}
-void QmlImageReader::run()
+void QmlImageReader::networkRequestDone()
{
- while (1) {
- mutex.lock();
- if (!jobs.count())
- haveJob.wait(&mutex);
- if (quit)
- break;
- Job runningJob = jobs.takeFirst();
- runningJob.reply->addRef();
- mutex.unlock();
-
- loadImage(runningJob);
- QCoreApplication::postEvent(runningJob.reply, new QmlImageDecodeEvent(runningJob.error, runningJob.img));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ QmlPixmapReply *job = replies.take(reply);
+ if (job) {
+ QImage image;
+ QmlImageReaderEvent::ReadError error;
+ if (reply->error()) {
+ error = QmlImageReaderEvent::Loading;
+ } else {
+ QImageReader imgio(reply);
+ if (imgio.read(&image)) {
+ error = QmlImageReaderEvent::NoError;
+ } else {
+ error = QmlImageReaderEvent::Decoding;
+ }
+ }
+ // send completion event to the QmlPixmapReply
+ QCoreApplication::postEvent(job, new QmlImageReaderEvent(error, image));
}
+ // kick off event loop again if we have dropped below max request count
+ if (replies.count() == maxImageRequestCount)
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ reply->deleteLater();
}
static bool readImage(QIODevice *dev, QPixmap *pixmap)
@@ -228,46 +364,26 @@ class QmlPixmapReplyPrivate : public QObjectPrivate
Q_DECLARE_PUBLIC(QmlPixmapReply)
public:
- QmlPixmapReplyPrivate(const QUrl &u, QNetworkReply *r)
- : QObjectPrivate(), refCount(1), url(u), reply(r), status(QmlPixmapReply::Loading) {
+ QmlPixmapReplyPrivate(QmlEngine *e, const QUrl &u)
+ : QObjectPrivate(), refCount(1), url(u), status(QmlPixmapReply::Loading), loading(false), engine(e) {
}
int refCount;
QUrl url;
- QNetworkReply *reply;
QPixmap pixmap; // ensure reference to pixmap so QPixmapCache does not discard
- QImage image;
QmlPixmapReply::Status status;
+ bool loading;
+ QmlEngine *engine;
};
-QmlPixmapReply::QmlPixmapReply(const QUrl &url, QNetworkReply *reply)
- : QObject(*new QmlPixmapReplyPrivate(url, reply), 0)
+QmlPixmapReply::QmlPixmapReply(QmlEngine *engine, const QUrl &url)
+ : QObject(*new QmlPixmapReplyPrivate(engine, url), 0)
{
- Q_D(QmlPixmapReply);
-
- static int replyDownloadProgress = -1;
- static int replyFinished = -1;
- static int thisDownloadProgress = -1;
- static int thisNetworkRequestDone = -1;
-
- if (replyDownloadProgress == -1) {
- replyDownloadProgress = QNetworkReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
- replyFinished = QNetworkReply::staticMetaObject.indexOfSignal("finished()");
- thisDownloadProgress = QmlPixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
- thisNetworkRequestDone = QmlPixmapReply::staticMetaObject.indexOfSlot("networkRequestDone()");
- }
-
- QMetaObject::connect(d->reply, replyDownloadProgress, this, thisDownloadProgress, Qt::DirectConnection);
- QMetaObject::connect(d->reply, replyFinished, this, thisNetworkRequestDone);
}
QmlPixmapReply::~QmlPixmapReply()
{
- Q_D(QmlPixmapReply);
- if (d->status == Decoding)
- qmlImageReader()->cancel(this);
- delete d->reply;
}
const QUrl &QmlPixmapReply::url() const
@@ -276,36 +392,16 @@ const QUrl &QmlPixmapReply::url() const
return d->url;
}
-void QmlPixmapReply::networkRequestDone()
-{
- Q_D(QmlPixmapReply);
- if (d->reply->error()) {
- d->pixmap = QPixmap();
- d->status = Error;
- QByteArray key = d->url.toEncoded(QUrl::FormattingOption(0x100));
- QString strKey = QString::fromLatin1(key.constData(), key.count());
- QPixmapCache::insert(strKey, d->pixmap);
- qWarning() << "Network error loading" << d->url << d->reply->errorString();
- emit finished();
- } else {
- qmlImageReader()->read(this);
- d->status = Decoding;
- }
-}
-
bool QmlPixmapReply::event(QEvent *event)
{
Q_D(QmlPixmapReply);
if (event->type() == QEvent::User) {
+ d->loading = false;
if (!release(true)) {
- QmlImageDecodeEvent *de = static_cast<QmlImageDecodeEvent*>(event);
- d->status = de->error ? Error : Ready;
- if (d->status == Ready) {
+ QmlImageReaderEvent *de = static_cast<QmlImageReaderEvent*>(event);
+ d->status = (de->error == QmlImageReaderEvent::NoError) ? Ready : Error;
+ if (d->status == Ready)
d->pixmap = QPixmap::fromImage(de->image);
- d->image = QImage();
- } else {
- qWarning() << "Error decoding" << d->url;
- }
QByteArray key = d->url.toEncoded(QUrl::FormattingOption(0x100));
QString strKey = QString::fromLatin1(key.constData(), key.count());
QPixmapCache::insert(strKey, d->pixmap);
@@ -323,10 +419,16 @@ QmlPixmapReply::Status QmlPixmapReply::status() const
return d->status;
}
-QIODevice *QmlPixmapReply::device()
+bool QmlPixmapReply::isLoading() const
+{
+ Q_D(const QmlPixmapReply);
+ return d->loading;
+}
+
+void QmlPixmapReply::setLoading()
{
Q_D(QmlPixmapReply);
- return d->reply;
+ d->loading = true;
}
void QmlPixmapReply::addRef()
@@ -342,11 +444,17 @@ bool QmlPixmapReply::release(bool defer)
--d->refCount;
if (d->refCount == 0) {
qmlActivePixmapReplies()->remove(d->url);
+ if (d->status == Loading && !d->loading)
+ QmlImageReader::instance(d->engine)->cancel(this);
if (defer)
deleteLater();
else
delete this;
return true;
+ } else if (d->refCount == 1 && d->loading) {
+ // The only reference left is the reader thread.
+ qmlActivePixmapReplies()->remove(d->url);
+ QmlImageReader::instance(d->engine)->cancel(this);
}
return false;
@@ -418,9 +526,8 @@ QmlPixmapReply *QmlPixmapCache::request(QmlEngine *engine, const QUrl &url)
{
QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
if (iter == qmlActivePixmapReplies()->end()) {
- QNetworkRequest req(url);
- req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
- QmlPixmapReply *item = new QmlPixmapReply(url, engine->networkAccessManager()->get(req));
+ QmlImageReader *reader = QmlImageReader::instance(engine);
+ QmlPixmapReply *item = reader->getImage(url);
iter = qmlActivePixmapReplies()->insert(url, item);
} else {
(*iter)->addRef();
diff --git a/src/declarative/util/qmlpixmapcache_p.h b/src/declarative/util/qmlpixmapcache_p.h
index 711e902..0140352 100644
--- a/src/declarative/util/qmlpixmapcache_p.h
+++ b/src/declarative/util/qmlpixmapcache_p.h
@@ -59,10 +59,10 @@ class Q_DECLARATIVE_EXPORT QmlPixmapReply : public QObject
{
Q_OBJECT
public:
- QmlPixmapReply(const QUrl &url, QNetworkReply *reply);
+ QmlPixmapReply(QmlEngine *engine, const QUrl &url);
~QmlPixmapReply();
- enum Status { Ready, Error, Unrequested, Loading, Decoding };
+ enum Status { Ready, Error, Unrequested, Loading };
Status status() const;
const QUrl &url() const;
@@ -75,12 +75,10 @@ protected:
bool event(QEvent *event);
private:
- QIODevice *device();
void addRef();
bool release(bool defer=false);
-
-private Q_SLOTS:
- void networkRequestDone();
+ bool isLoading() const;
+ void setLoading();
private:
Q_DISABLE_COPY(QmlPixmapReply)
diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp
index 7dfecc8..71ba81c 100644
--- a/tools/qmlviewer/qmlviewer.cpp
+++ b/tools/qmlviewer/qmlviewer.cpp
@@ -45,6 +45,7 @@
#include "qmlviewer.h"
#include <qmlcontext.h>
#include <qmlengine.h>
+#include <qmlnetworkaccessmanagerfactory.h>
#include "qml.h"
#include <private/qperformancelog_p_p.h>
#include <private/qabstractanimation_p.h>
@@ -80,6 +81,8 @@
#include <QTimer>
#include <QNetworkProxyFactory>
#include <QKeyEvent>
+#include <QMutex>
+#include <QMutexLocker>
#include "proxysettings.h"
#include "deviceorientation.h"
@@ -298,9 +301,22 @@ public:
PersistentCookieJar(QObject *parent) : QNetworkCookieJar(parent) { load(); }
~PersistentCookieJar() { save(); }
+ virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const
+ {
+ QMutexLocker lock(&mutex);
+ return QNetworkCookieJar::cookiesForUrl(url);
+ }
+
+ virtual bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
+ {
+ QMutexLocker lock(&mutex);
+ return QNetworkCookieJar::setCookiesFromUrl(cookieList, url);
+ }
+
private:
void save()
{
+ QMutexLocker lock(&mutex);
QList<QNetworkCookie> list = allCookies();
QByteArray data;
foreach (QNetworkCookie cookie, list) {
@@ -315,12 +331,90 @@ private:
void load()
{
+ QMutexLocker lock(&mutex);
QSettings settings("Nokia", "QtQmlViewer");
QByteArray data = settings.value("Cookies").toByteArray();
setAllCookies(QNetworkCookie::parseCookies(data));
}
+
+ mutable QMutex mutex;
};
+class NetworkAccessManagerFactory : public QmlNetworkAccessManagerFactory
+{
+public:
+ NetworkAccessManagerFactory() : cookieJar(0), cacheSize(0) {}
+
+ QNetworkAccessManager *create(QObject *parent) {
+ QMutexLocker lock(&mutex);
+ QNetworkAccessManager *manager = new QNetworkAccessManager(parent);
+ if (!cookieJar)
+ cookieJar = new PersistentCookieJar(this);
+ manager->setCookieJar(cookieJar);
+ cookieJar->setParent(this);
+ setupProxy(manager);
+ if (cacheSize > 0) {
+ QNetworkDiskCache *cache = new QNetworkDiskCache;
+ cache->setCacheDirectory(QDir::tempPath()+QLatin1String("/qml-duiviewer-network-cache"));
+ cache->setMaximumCacheSize(cacheSize);
+ manager->setCache(cache);
+ } else {
+ manager->setCache(0);
+ }
+ qDebug() << "created new manager for" << parent;
+ return manager;
+ }
+
+ void setupProxy(QNetworkAccessManager *nam)
+ {
+ class SystemProxyFactory : public QNetworkProxyFactory
+ {
+ public:
+ virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
+ {
+ QString protocolTag = query.protocolTag();
+ if (httpProxyInUse && (protocolTag == "http" || protocolTag == "https")) {
+ QList<QNetworkProxy> ret;
+ ret << httpProxy;
+ return ret;
+ }
+ return QNetworkProxyFactory::systemProxyForQuery(query);
+ }
+ void setHttpProxy (QNetworkProxy proxy)
+ {
+ httpProxy = proxy;
+ httpProxyInUse = true;
+ }
+ void unsetHttpProxy ()
+ {
+ httpProxyInUse = false;
+ }
+ private:
+ bool httpProxyInUse;
+ QNetworkProxy httpProxy;
+ };
+
+ SystemProxyFactory *proxyFactory = new SystemProxyFactory;
+ if (ProxySettings::httpProxyInUse())
+ proxyFactory->setHttpProxy(ProxySettings::httpProxy());
+ else
+ proxyFactory->unsetHttpProxy();
+ nam->setProxyFactory(proxyFactory);
+ }
+
+ void setCacheSize(int size) {
+ if (size != cacheSize) {
+ cacheSize = size;
+ invalidate();
+ }
+ }
+
+ PersistentCookieJar *cookieJar;
+ QMutex mutex;
+ int cacheSize;
+};
+
+
QString QmlViewer::getVideoFileName()
{
QString title = convertAvailable || ffmpegAvailable ? tr("Save Video File") : tr("Save PNG Frames");
@@ -397,8 +491,8 @@ QmlViewer::QmlViewer(QWidget *parent, Qt::WindowFlags flags)
setCentralWidget(canvas);
#endif
- setupProxy();
- canvas->engine()->networkAccessManager()->setCookieJar(new PersistentCookieJar(this));
+ namFactory = new NetworkAccessManagerFactory;
+ canvas->engine()->setNetworkAccessManagerFactory(namFactory);
connect(&autoStartTimer, SIGNAL(triggered()), this, SLOT(autoStartRecording()));
connect(&autoStopTimer, SIGNAL(triggered()), this, SLOT(autoStopRecording()));
@@ -409,6 +503,12 @@ QmlViewer::QmlViewer(QWidget *parent, Qt::WindowFlags flags)
recordTimer.setRepeating(true);
}
+QmlViewer::~QmlViewer()
+{
+ canvas->engine()->setNetworkAccessManagerFactory(0);
+ delete namFactory;
+}
+
void QmlViewer::adjustSizeSlot()
{
resize(sizeHint());
@@ -591,7 +691,7 @@ void QmlViewer::showProxySettings()
void QmlViewer::proxySettingsChanged()
{
- setupProxy ();
+ namFactory->invalidate();
reload ();
}
@@ -1325,63 +1425,9 @@ void QmlViewer::setDeviceKeys(bool on)
devicemode = on;
}
-void QmlViewer::setupProxy()
-{
- class SystemProxyFactory : public QNetworkProxyFactory
- {
- public:
- virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
- {
- QString protocolTag = query.protocolTag();
- if (httpProxyInUse && (protocolTag == "http" || protocolTag == "https")) {
- QList<QNetworkProxy> ret;
- ret << httpProxy;
- return ret;
- }
- return QNetworkProxyFactory::systemProxyForQuery(query);
- }
- void setHttpProxy (QNetworkProxy proxy)
- {
- httpProxy = proxy;
- httpProxyInUse = true;
- }
- void unsetHttpProxy ()
- {
- httpProxyInUse = false;
- }
- private:
- bool httpProxyInUse;
- QNetworkProxy httpProxy;
- };
-
- QNetworkAccessManager * nam = canvas->engine()->networkAccessManager();
- SystemProxyFactory *proxyFactory = new SystemProxyFactory;
- if (ProxySettings::httpProxyInUse())
- proxyFactory->setHttpProxy(ProxySettings::httpProxy());
- else
- proxyFactory->unsetHttpProxy();
- nam->setProxyFactory(proxyFactory);
-}
-
void QmlViewer::setNetworkCacheSize(int size)
{
- QNetworkAccessManager * nam = canvas->engine()->networkAccessManager();
- QNetworkDiskCache *cache = qobject_cast<QNetworkDiskCache*>(nam->cache());
- if (!cache) {
- if (size==0)
- return;
- cache = new QNetworkDiskCache;
- cache->setCacheDirectory(QDir::tempPath()+QLatin1String("/qml-duiviewer-network-cache"));
- nam->setCache(cache);
- }
- if (size == cache->maximumCacheSize())
- return;
- if (size>0) {
- // Setup a caching network manager
- cache->setMaximumCacheSize(size);
- } else {
- nam->setCache(0);
- }
+ namFactory->setCacheSize(size);
}
void QmlViewer::setUseGL(bool useGL)
diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h
index 3b14d39..6b05584 100644
--- a/tools/qmlviewer/qmlviewer.h
+++ b/tools/qmlviewer/qmlviewer.h
@@ -57,6 +57,8 @@ class QProcess;
class RecordingDialog;
class QmlGraphicsTester;
class QNetworkReply;
+class QNetworkCookieJar;
+class NetworkAccessManagerFactory;
class QmlViewer
#if defined(Q_OS_SYMBIAN)
@@ -68,6 +70,7 @@ class QmlViewer
Q_OBJECT
public:
QmlViewer(QWidget *parent=0, Qt::WindowFlags flags=0);
+ ~QmlViewer();
enum ScriptOption {
Play = 0x00000001,
@@ -138,7 +141,6 @@ private slots:
void unpackWgt();
private:
- void setupProxy();
QString getVideoFileName();
PreviewDeviceSkin *skin;
@@ -181,6 +183,8 @@ private:
QNetworkReply *wgtreply;
QString wgtdir;
+ NetworkAccessManagerFactory *namFactory;
+
bool useQmlFileBrowser;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QmlViewer::ScriptOptions)