diff options
Diffstat (limited to 'src')
8 files changed, 178 insertions, 58 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index 1f26338..de16668 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -168,18 +168,26 @@ void QDeclarativeBorderImage::setSource(const QUrl &url) d->url = url; d->sciurl = QUrl(); + emit sourceChanged(d->url); + + if (isComponentComplete()) + load(); +} + +void QDeclarativeBorderImage::load() +{ + Q_D(QDeclarativeBorderImage); if (d->progress != 0.0) { d->progress = 0.0; emit progressChanged(d->progress); } - if (url.isEmpty()) { + if (d->url.isEmpty()) { d->pix = QPixmap(); d->status = Null; setImplicitWidth(0); setImplicitHeight(0); emit statusChanged(d->status); - emit sourceChanged(d->url); update(); } else { d->status = Loading; @@ -195,11 +203,21 @@ void QDeclarativeBorderImage::setSource(const QUrl &url) { QNetworkRequest req(d->url); d->sciReply = qmlEngine(this)->networkAccessManager()->get(req); - QObject::connect(d->sciReply, SIGNAL(finished()), - this, SLOT(sciRequestFinished())); + + static int sciReplyFinished = -1; + static int thisSciRequestFinished = -1; + if (sciReplyFinished == -1) { + sciReplyFinished = + QNetworkReply::staticMetaObject.indexOfSignal("finished()"); + thisSciRequestFinished = + QDeclarativeBorderImage::staticMetaObject.indexOfSlot("sciRequestFinished()"); + } + + QMetaObject::connect(d->sciReply, sciReplyFinished, this, + thisSciRequestFinished, Qt::DirectConnection); } } else { - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix); + QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix, d->async); if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url); d->pendingPixmapCache = true; @@ -217,7 +235,6 @@ void QDeclarativeBorderImage::setSource(const QUrl &url) d->status = Ready; d->progress = 1.0; emit statusChanged(d->status); - emit sourceChanged(d->url); emit progressChanged(d->progress); update(); } @@ -319,13 +336,30 @@ void QDeclarativeBorderImage::setGridScaledImage(const QDeclarativeGridScaledIma d->verticalTileMode = sci.verticalTileRule(); d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl())); - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->sciurl, &d->pix); + QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->sciurl, &d->pix, d->async); if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->sciurl); d->sciPendingPixmapCache = true; - connect(reply, SIGNAL(finished()), this, SLOT(requestFinished())); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), - this, SLOT(requestProgress(qint64,qint64))); + + static int replyDownloadProgress = -1; + static int replyFinished = -1; + static int thisRequestProgress = -1; + static int thisRequestFinished = -1; + if (replyDownloadProgress == -1) { + replyDownloadProgress = + QDeclarativePixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); + replyFinished = + QDeclarativePixmapReply::staticMetaObject.indexOfSignal("finished()"); + thisRequestProgress = + QDeclarativeBorderImage::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)"); + thisRequestFinished = + QDeclarativeBorderImage::staticMetaObject.indexOfSlot("requestFinished()"); + } + + QMetaObject::connect(reply, replyFinished, this, + thisRequestFinished, Qt::DirectConnection); + QMetaObject::connect(reply, replyDownloadProgress, this, + thisRequestProgress, Qt::DirectConnection); } else { //### should be unified with requestFinished setImplicitWidth(d->pix.width()); @@ -337,7 +371,6 @@ void QDeclarativeBorderImage::setGridScaledImage(const QDeclarativeGridScaledIma d->status = Ready; d->progress = 1.0; emit statusChanged(d->status); - emit sourceChanged(d->url); emit progressChanged(1.0); update(); } @@ -350,10 +383,10 @@ void QDeclarativeBorderImage::requestFinished() if (d->url.path().endsWith(QLatin1String(".sci"))) { d->sciPendingPixmapCache = false; - QDeclarativePixmapCache::get(d->sciurl, &d->pix); + QDeclarativePixmapCache::get(d->sciurl, &d->pix, d->async); } else { d->pendingPixmapCache = false; - if (QDeclarativePixmapCache::get(d->url, &d->pix) != QDeclarativePixmapReply::Ready) + if (QDeclarativePixmapCache::get(d->url, &d->pix, d->async) != QDeclarativePixmapReply::Ready) d->status = Error; } setImplicitWidth(d->pix.width()); @@ -363,7 +396,6 @@ void QDeclarativeBorderImage::requestFinished() d->status = Ready; d->progress = 1.0; emit statusChanged(d->status); - emit sourceChanged(d->url); emit progressChanged(1.0); update(); } diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage_p.h b/src/declarative/graphicsitems/qdeclarativeborderimage_p.h index db81fd8..a759e67 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage_p.h +++ b/src/declarative/graphicsitems/qdeclarativeborderimage_p.h @@ -84,6 +84,9 @@ Q_SIGNALS: void horizontalTileModeChanged(); void verticalTileModeChanged(); +protected: + virtual void load(); + private: void setGridScaledImage(const QDeclarativeGridScaledImage& sci); diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp index 33b38e0..338b086 100644 --- a/src/declarative/graphicsitems/qdeclarativeimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp @@ -300,6 +300,21 @@ void QDeclarativeImage::geometryChanged(const QRectF &newGeometry, const QRectF The URL may be absolute, or relative to the URL of the component. */ +/*! + \qmlproperty bool Image::asynchronous + + Specifies that images on the local filesystem should be loaded + asynchronously in a separate thread. The default value is + false, causing the user interface thread to block while the + image is loaded. Setting \a asynchronous to true is useful where + maintaining a responsive user interface is more desireable + than having images immediately visible. + + Note that this property is only valid for images read from the + local filesystem. Images loaded via a network resource (e.g. HTTP) + are always loaded asynchonously. +*/ + void QDeclarativeImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) { Q_D(QDeclarativeImage); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp index 18053d3..a8cce3f 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp @@ -75,6 +75,23 @@ qreal QDeclarativeImageBase::progress() const return d->progress; } + +bool QDeclarativeImageBase::asynchronous() const +{ + Q_D(const QDeclarativeImageBase); + return d->async; +} + +void QDeclarativeImageBase::setAsynchronous(bool async) +{ + Q_D(QDeclarativeImageBase); + if (d->async != async) { + d->async = async; + emit asynchronousChanged(); + } +} + + QUrl QDeclarativeImageBase::source() const { Q_D(const QDeclarativeImageBase); @@ -94,23 +111,31 @@ void QDeclarativeImageBase::setSource(const QUrl &url) } d->url = url; + emit sourceChanged(d->url); + + if (isComponentComplete()) + load(); +} + +void QDeclarativeImageBase::load() +{ + Q_D(QDeclarativeImageBase); if (d->progress != 0.0) { d->progress = 0.0; emit progressChanged(d->progress); } - if (url.isEmpty()) { + if (d->url.isEmpty()) { d->pix = QPixmap(); d->status = Null; setImplicitWidth(0); setImplicitHeight(0); emit statusChanged(d->status); - emit sourceChanged(d->url); emit pixmapChanged(); update(); } else { d->status = Loading; - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix); + QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix, d->async); if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url); d->pendingPixmapCache = true; @@ -147,7 +172,6 @@ void QDeclarativeImageBase::setSource(const QUrl &url) } d->progress = 1.0; emit statusChanged(d->status); - emit sourceChanged(d->url); emit progressChanged(d->progress); emit pixmapChanged(); update(); @@ -163,7 +187,7 @@ void QDeclarativeImageBase::requestFinished() d->pendingPixmapCache = false; - if (QDeclarativePixmapCache::get(d->url, &d->pix) != QDeclarativePixmapReply::Ready) + if (QDeclarativePixmapCache::get(d->url, &d->pix, d->async) != QDeclarativePixmapReply::Ready) d->status = Error; setImplicitWidth(d->pix.width()); setImplicitHeight(d->pix.height()); @@ -172,7 +196,6 @@ void QDeclarativeImageBase::requestFinished() d->status = Ready; d->progress = 1.0; emit statusChanged(d->status); - emit sourceChanged(d->url); emit progressChanged(1.0); emit pixmapChanged(); update(); @@ -187,5 +210,12 @@ void QDeclarativeImageBase::requestProgress(qint64 received, qint64 total) } } +void QDeclarativeImageBase::componentComplete() +{ + Q_D(QDeclarativeImageBase); + QDeclarativeItem::componentComplete(); + if (d->url.isValid()) + load(); +} QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h index 47be139..c8c50ac 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h @@ -57,6 +57,7 @@ class Q_DECLARATIVE_EXPORT QDeclarativeImageBase : public QDeclarativeItem Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) + Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged) public: ~QDeclarativeImageBase(); @@ -67,13 +68,19 @@ public: QUrl source() const; virtual void setSource(const QUrl &url); + bool asynchronous() const; + void setAsynchronous(bool); + Q_SIGNALS: void sourceChanged(const QUrl &); void statusChanged(Status); void progressChanged(qreal progress); void pixmapChanged(); + void asynchronousChanged(); protected: + virtual void load(); + virtual void componentComplete(); QDeclarativeImageBase(QDeclarativeImageBasePrivate &dd, QDeclarativeItem *parent); private Q_SLOTS: diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h index d540e40..2e062a8 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h @@ -68,7 +68,8 @@ public: QDeclarativeImageBasePrivate() : status(QDeclarativeImageBase::Null), progress(0.0), - pendingPixmapCache(false) + pendingPixmapCache(false), + async(false) { } @@ -76,7 +77,8 @@ public: QDeclarativeImageBase::Status status; QUrl url; qreal progress; - bool pendingPixmapCache; + bool pendingPixmapCache : 1; + bool async : 1; }; QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp index c4b07cc..cfb25dd 100644 --- a/src/declarative/util/qdeclarativepixmapcache.cpp +++ b/src/declarative/util/qdeclarativepixmapcache.cpp @@ -79,6 +79,14 @@ inline uint qHash(const QUrl &uri) } #endif +static QString toLocalFileOrQrc(const QUrl& url) +{ + QString r = url.toLocalFile(); + if (r.isEmpty() && url.scheme() == QLatin1String("qrc")) + r = QLatin1Char(':') + url.path(); + return r; +} + class QDeclarativeImageReaderEvent : public QEvent { public: @@ -208,6 +216,7 @@ bool QDeclarativeImageRequestHandler::event(QEvent *event) // fetch if (url.scheme() == QLatin1String("image")) { + // Use QmlImageProvider QImage image = QDeclarativeEnginePrivate::get(engine)->getImageFromProvider(url); QDeclarativeImageReaderEvent::ReadError errorCode = QDeclarativeImageReaderEvent::NoError; QString errorStr; @@ -217,14 +226,36 @@ bool QDeclarativeImageRequestHandler::event(QEvent *event) } QCoreApplication::postEvent(runningJob, new QDeclarativeImageReaderEvent(errorCode, errorStr, image)); } else { - QNetworkRequest req(url); - req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); - QNetworkReply *reply = networkAccessManager()->get(req); + QString lf = toLocalFileOrQrc(url); + if (!lf.isEmpty()) { + // Image is local - load/decode immediately + QImage image; + QDeclarativeImageReaderEvent::ReadError errorCode = QDeclarativeImageReaderEvent::NoError; + QString errorStr; + QFile f(lf); + if (f.open(QIODevice::ReadOnly)) { + QImageReader imgio(&f); + if (!imgio.read(&image)) { + errorStr = QLatin1String("Error decoding: ") + url.toString() + + QLatin1String(" \"") + imgio.errorString() + QLatin1String("\""); + errorCode = QDeclarativeImageReaderEvent::Loading; + } + } else { + errorStr = QLatin1String("Cannot open: ") + url.toString(); + errorCode = QDeclarativeImageReaderEvent::Loading; + } + QCoreApplication::postEvent(runningJob, new QDeclarativeImageReaderEvent(errorCode, errorStr, image)); + } else { + // Network resource + 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; @@ -381,14 +412,6 @@ static bool readImage(QIODevice *dev, QPixmap *pixmap, QString &errorString) This class is NOT reentrant. */ -static QString toLocalFileOrQrc(const QUrl& url) -{ - QString r = url.toLocalFile(); - if (r.isEmpty() && url.scheme() == QLatin1String("qrc")) - r = QLatin1Char(':') + url.path(); - return r; -} - typedef QHash<QUrl, QDeclarativePixmapReply *> QDeclarativePixmapReplyHash; Q_GLOBAL_STATIC(QDeclarativePixmapReplyHash, qmlActivePixmapReplies); @@ -500,40 +523,48 @@ bool QDeclarativePixmapReply::release(bool defer) Returns Ready, or Error if the image has been retrieved, otherwise the current retrieval status. + + If \a async is false the image will be loaded and decoded immediately; + otherwise the image will be loaded and decoded in a separate thread. + + Note that images sourced from the network will always be loaded and + decoded asynchonously. */ -QDeclarativePixmapReply::Status QDeclarativePixmapCache::get(const QUrl& url, QPixmap *pixmap) +QDeclarativePixmapReply::Status QDeclarativePixmapCache::get(const QUrl& url, QPixmap *pixmap, bool async) { QDeclarativePixmapReply::Status status = QDeclarativePixmapReply::Unrequested; + QByteArray key = url.toEncoded(QUrl::FormattingOption(0x100)); + QString strKey = QString::fromLatin1(key.constData(), key.count()); #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML - QString lf = toLocalFileOrQrc(url); - if (!lf.isEmpty()) { - status = QDeclarativePixmapReply::Ready; - if (!QPixmapCache::find(lf,pixmap)) { - QFile f(lf); - if (f.open(QIODevice::ReadOnly)) { - QString errorString; - if (!readImage(&f, pixmap, errorString)) { - errorString = QLatin1String("Error decoding: ") + url.toString() - + QLatin1String(" \"") + errorString + QLatin1String("\""); - qWarning() << errorString; + if (!async) { + QString lf = toLocalFileOrQrc(url); + if (!lf.isEmpty()) { + status = QDeclarativePixmapReply::Ready; + if (!QPixmapCache::find(strKey,pixmap)) { + QFile f(lf); + if (f.open(QIODevice::ReadOnly)) { + QString errorString; + if (!readImage(&f, pixmap, errorString)) { + errorString = QLatin1String("Error decoding: ") + url.toString() + + QLatin1String(" \"") + errorString + QLatin1String("\""); + qWarning() << errorString; + *pixmap = QPixmap(); + status = QDeclarativePixmapReply::Error; + } + } else { + qWarning() << "Cannot open" << url; *pixmap = QPixmap(); status = QDeclarativePixmapReply::Error; } - } else { - qWarning() << "Cannot open" << url; - *pixmap = QPixmap(); - status = QDeclarativePixmapReply::Error; + if (status == QDeclarativePixmapReply::Ready) + QPixmapCache::insert(strKey, *pixmap); } - if (status == QDeclarativePixmapReply::Ready) - QPixmapCache::insert(lf, *pixmap); + return status; } - return status; } #endif - QByteArray key = url.toEncoded(QUrl::FormattingOption(0x100)); - QString strKey = QString::fromLatin1(key.constData(), key.count()); QDeclarativePixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url); if (iter != qmlActivePixmapReplies()->end() && (*iter)->status() == QDeclarativePixmapReply::Ready) { // Must check this, since QPixmapCache::insert may have failed. diff --git a/src/declarative/util/qdeclarativepixmapcache_p.h b/src/declarative/util/qdeclarativepixmapcache_p.h index c615254..b8949db 100644 --- a/src/declarative/util/qdeclarativepixmapcache_p.h +++ b/src/declarative/util/qdeclarativepixmapcache_p.h @@ -92,7 +92,7 @@ private: class Q_DECLARATIVE_EXPORT QDeclarativePixmapCache { public: - static QDeclarativePixmapReply::Status get(const QUrl& url, QPixmap *pixmap); + static QDeclarativePixmapReply::Status get(const QUrl& url, QPixmap *pixmap, bool async=false); static QDeclarativePixmapReply *request(QDeclarativeEngine *, const QUrl& url); static void cancel(const QUrl& url, QObject *obj); static int pendingRequests(); |