From a2a8cea2835ef24104fe784b6ce0f508cc5637c0 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 24 Feb 2010 15:06:56 +1000 Subject: Automatically connect to a notify signal if the requested signal is in the "onFooChanged" form, even if the notify signal is not called "fooChanged". Task-number: QT-2783 --- src/declarative/qml/qdeclarativecompiler.cpp | 10 ++++++++++ .../qdeclarativelanguage/data/autoNotifyConnection.qml | 6 ++++++ tests/auto/declarative/qdeclarativelanguage/testtypes.h | 6 ++++++ .../qdeclarativelanguage/tst_qdeclarativelanguage.cpp | 17 +++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/autoNotifyConnection.qml diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 0593a5d..b6ebd60 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -1326,6 +1326,16 @@ int QDeclarativeCompiler::findSignalByName(const QMetaObject *mo, const QByteArr if (methodName == name) return ii; } + + // If no signal is found, but the signal is of the form "onBlahChanged", + // return the notify signal for the property "Blah" + if (name.endsWith("Changed")) { + QByteArray propName = name.mid(0, name.length() - 7); + int propIdx = mo->indexOfProperty(propName.constData()); + if (propIdx >= 0) + return mo->property(propIdx).notifySignalIndex(); + } + return -1; } diff --git a/tests/auto/declarative/qdeclarativelanguage/data/autoNotifyConnection.qml b/tests/auto/declarative/qdeclarativelanguage/data/autoNotifyConnection.qml new file mode 100644 index 0000000..640fb54 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/autoNotifyConnection.qml @@ -0,0 +1,6 @@ +import Test 1.0 +MyQmlObject { + property bool receivedNotify : false + onPropertyWithNotifyChanged: { receivedNotify = true; } +} + diff --git a/tests/auto/declarative/qdeclarativelanguage/testtypes.h b/tests/auto/declarative/qdeclarativelanguage/testtypes.h index 21f3e70..fa62eb4 100644 --- a/tests/auto/declarative/qdeclarativelanguage/testtypes.h +++ b/tests/auto/declarative/qdeclarativelanguage/testtypes.h @@ -102,6 +102,7 @@ class MyQmlObject : public QObject, public MyInterface, public QDeclarativeParse Q_PROPERTY(int onLiteralSignal READ onLiteralSignal WRITE setOnLiteralSignal); Q_PROPERTY(MyCustomVariantType customType READ customType WRITE setCustomType); Q_PROPERTY(MyQmlObject *qmlobjectProperty READ qmlobject WRITE setQmlobject) + Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal) Q_INTERFACES(MyInterface QDeclarativeParserStatus) public: @@ -137,6 +138,9 @@ public: MyCustomVariantType customType() const { return m_custom; } void setCustomType(const MyCustomVariantType &v) { m_custom = v; } + + int propertyWithNotify() const { return m_propertyWithNotify; } + void setPropertyWithNotify(int i) { m_propertyWithNotify = i; emit oddlyNamedNotifySignal(); } public slots: void basicSlot() { qWarning("MyQmlObject::basicSlot"); } void basicSlotWithArgs(int v) { qWarning("MyQmlObject::basicSlotWithArgs(%d)", v); } @@ -144,6 +148,7 @@ public slots: signals: void basicSignal(); void basicParameterizedSignal(int parameter); + void oddlyNamedNotifySignal(); private: friend class tst_qmllanguage; @@ -151,6 +156,7 @@ private: MyInterface *m_interface; MyQmlObject *m_qmlobject; MyCustomVariantType m_custom; + int m_propertyWithNotify; }; QML_DECLARE_TYPEINFO(MyQmlObject, QML_HAS_ATTACHED_PROPERTIES) QML_DECLARE_TYPE(MyQmlObject); diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index cb59f47..b177636 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -88,6 +88,7 @@ private slots: void rootAsQmlComponent(); void inlineQmlComponents(); void idProperty(); + void autoNotifyConnection(); void assignSignal(); void dynamicProperties(); void dynamicPropertiesNested(); @@ -511,6 +512,22 @@ void tst_qmllanguage::idProperty() QCOMPARE(object->property("object"), QVariant::fromValue((QObject *)child)); } +// Tests automatic connection to notify signals if "onBlahChanged" syntax is used +// even if the notify signal for "blah" is not called "blahChanged" +void tst_qmllanguage::autoNotifyConnection() +{ + QDeclarativeComponent component(&engine, TEST_FILE("autoNotifyConnection.qml")); + VERIFY_ERRORS(0); + MyQmlObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QMetaProperty prop = object->metaObject()->property(object->metaObject()->indexOfProperty("receivedNotify")); + QVERIFY(prop.isValid()); + + QCOMPARE(prop.read(object), QVariant::fromValue(false)); + object->setPropertyWithNotify(1); + QCOMPARE(prop.read(object), QVariant::fromValue(true)); +} + // Tests that signals can be assigned to void tst_qmllanguage::assignSignal() { -- cgit v0.12 From fcfb08e40264c3417da91f4e187758d85f190a4f Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 24 Feb 2010 15:17:14 +1000 Subject: Make compile following renaming of class. --- .../auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index 72e0437..9d68ba9 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -514,7 +514,7 @@ void tst_qdeclarativelanguage::idProperty() // Tests automatic connection to notify signals if "onBlahChanged" syntax is used // even if the notify signal for "blah" is not called "blahChanged" -void tst_qmllanguage::autoNotifyConnection() +void tst_qdeclarativelanguage::autoNotifyConnection() { QDeclarativeComponent component(&engine, TEST_FILE("autoNotifyConnection.qml")); VERIFY_ERRORS(0); -- cgit v0.12 From 915ab7d8c75a190003db97bc0a92656ee65f5b4b Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Wed, 24 Feb 2010 14:26:43 +1000 Subject: Removed unnecessary update calls in qmlgraphicsitem Reviewed-by: akennedy --- src/declarative/graphicsitems/qdeclarativeitem.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp index 5dd44fa..3db60ee 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp @@ -2604,7 +2604,6 @@ void QDeclarativeItem::setWidth(qreal w) prepareGeometryChange(); d->width = w; - update(); geometryChanged(QRectF(x(), y(), width(), height()), QRectF(x(), y(), oldWidth, height())); @@ -2641,7 +2640,6 @@ void QDeclarativeItem::setImplicitWidth(qreal w) prepareGeometryChange(); d->width = w; - update(); geometryChanged(QRectF(x(), y(), width(), height()), QRectF(x(), y(), oldWidth, height())); @@ -2676,7 +2674,6 @@ void QDeclarativeItem::setHeight(qreal h) prepareGeometryChange(); d->height = h; - update(); geometryChanged(QRectF(x(), y(), width(), height()), QRectF(x(), y(), width(), oldHeight)); @@ -2713,7 +2710,6 @@ void QDeclarativeItem::setImplicitHeight(qreal h) prepareGeometryChange(); d->height = h; - update(); geometryChanged(QRectF(x(), y(), width(), height()), QRectF(x(), y(), width(), oldHeight)); -- cgit v0.12 From 8848b63187cf1b073891bdd6998273a8869bb033 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 24 Feb 2010 15:23:23 +1000 Subject: Add an "asynchonous" property to Image. Allows loading/decoding local images in an asynchronous thread (already the case for network images). --- examples/declarative/scrollbar/display.qml | 1 + .../graphicsitems/qdeclarativeborderimage.cpp | 60 +++++++++--- .../graphicsitems/qdeclarativeborderimage_p.h | 3 + .../graphicsitems/qdeclarativeimage.cpp | 15 +++ .../graphicsitems/qdeclarativeimagebase.cpp | 42 +++++++-- .../graphicsitems/qdeclarativeimagebase_p.h | 7 ++ .../graphicsitems/qdeclarativeimagebase_p_p.h | 6 +- src/declarative/util/qdeclarativepixmapcache.cpp | 101 ++++++++++++++------- src/declarative/util/qdeclarativepixmapcache_p.h | 2 +- .../declarative/qdeclarativeimage/data/colors1.png | Bin 0 -> 1655 bytes .../qdeclarativeimage/tst_qdeclarativeimage.cpp | 18 ++-- 11 files changed, 191 insertions(+), 64 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeimage/data/colors1.png diff --git a/examples/declarative/scrollbar/display.qml b/examples/declarative/scrollbar/display.qml index 536a8b7..a96db6e 100644 --- a/examples/declarative/scrollbar/display.qml +++ b/examples/declarative/scrollbar/display.qml @@ -10,6 +10,7 @@ Rectangle { Image { id: picture source: "pics/niagara_falls.jpg" + asynchronous: true } viewportWidth: picture.width viewportHeight: picture.height 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 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(); diff --git a/tests/auto/declarative/qdeclarativeimage/data/colors1.png b/tests/auto/declarative/qdeclarativeimage/data/colors1.png new file mode 100644 index 0000000..dfb62f3 Binary files /dev/null and b/tests/auto/declarative/qdeclarativeimage/data/colors1.png differ diff --git a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp index f38fca9..62793e7 100644 --- a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp +++ b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp @@ -112,13 +112,17 @@ void tst_qdeclarativeimage::imageSource_data() { QTest::addColumn("source"); QTest::addColumn("remote"); + QTest::addColumn("async"); QTest::addColumn("error"); - QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() << false << ""; + QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() << false << false << ""; + QTest::newRow("local async") << QUrl::fromLocalFile(SRCDIR "/data/colors1.png").toString() << false << true << ""; QTest::newRow("local not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString() << false - << "Cannot open QUrl( \"" + QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString() + "\" ) "; - QTest::newRow("remote") << SERVER_ADDR "/colors.png" << true << ""; - QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << true + << false << "Cannot open QUrl( \"" + QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString() + "\" ) "; + QTest::newRow("local async not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file-1.png").toString() << false + << true << "\"Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/no-such-file-1.png").toString() + "\" "; + QTest::newRow("remote") << SERVER_ADDR "/colors.png" << true << false << ""; + QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << true << false << "\"Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found\" "; } @@ -126,6 +130,7 @@ void tst_qdeclarativeimage::imageSource() { QFETCH(QString, source); QFETCH(bool, remote); + QFETCH(bool, async); QFETCH(QString, error); TestHTTPServer server(SERVER_PORT); @@ -137,13 +142,14 @@ void tst_qdeclarativeimage::imageSource() if (!error.isEmpty()) QTest::ignoreMessage(QtWarningMsg, error.toUtf8()); - QString componentStr = "import Qt 4.6\nImage { source: \"" + source + "\" }"; + QString componentStr = "import Qt 4.6\nImage { source: \"" + source + "\"; asynchronous: " + + (async ? QLatin1String("true") : QLatin1String("false")) + " }"; QDeclarativeComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QDeclarativeImage *obj = qobject_cast(component.create()); QVERIFY(obj != 0); - if (remote) + if (remote || async) TRY_WAIT(obj->status() == QDeclarativeImage::Loading); QCOMPARE(obj->source(), remote ? source : QUrl(source)); -- cgit v0.12