summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/declarative/flickr/content/ImageDetails.qml9
-rw-r--r--demos/declarative/flickr/flickr.qml8
-rw-r--r--src/declarative/fx/qfximage.cpp80
-rw-r--r--src/declarative/fx/qfximage.h5
-rw-r--r--src/declarative/fx/qfximage_p.h11
-rw-r--r--src/declarative/fx/qfxpixmap.cpp8
-rw-r--r--src/declarative/fx/qfxpixmap.h3
-rw-r--r--src/declarative/util/qmllistmodel.cpp68
8 files changed, 167 insertions, 25 deletions
diff --git a/demos/declarative/flickr/content/ImageDetails.qml b/demos/declarative/flickr/content/ImageDetails.qml
index d721983..955f85d 100644
--- a/demos/declarative/flickr/content/ImageDetails.qml
+++ b/demos/declarative/flickr/content/ImageDetails.qml
@@ -3,7 +3,6 @@ Flipable {
property var frontContainer: ContainerFront
property var flickableArea: Flickable
- property var fullScreenArea: BigImage
property string photoTitle: ""
property string photoDescription: ""
property string photoTags: ""
@@ -73,7 +72,8 @@ Flipable {
Rect { anchors.fill: parent; color: "black"; opacity: 0.4; pen.color: "white"; pen.width: 2 }
- Loading { anchors.centeredIn: parent; visible: BigImage.status }
+// Loading { anchors.centeredIn: parent; visible: BigImage.status }
+ Progress { anchors.centeredIn: parent; width: 200; height: 18; progress: BigImage.progress; visible: BigImage.status }
Flickable {
id: Flick; width: Container.width - 10; height: Container.height - 10
x: 5; y: 5; clip: true; viewportWidth: (BigImage.width * BigImage.scale) + BigImage.x;
@@ -89,6 +89,11 @@ Flipable {
MediaButton {
id: BackButton2; x: 630; y: 370; text: "Back"; onClicked: { Container.state = '' }
}
+ Text {
+ text: "Image Unavailable"
+ visible: BigImage.status == 'Error'
+ anchors.centeredIn: parent; color: "white"; font.bold: true
+ }
Slider { id: Slider; x: 25; y: 374; imageWidth: Container.photoWidth; imageHeight: Container.photoHeight }
}
diff --git a/demos/declarative/flickr/flickr.qml b/demos/declarative/flickr/flickr.qml
index 83fd845..85af8e3 100644
--- a/demos/declarative/flickr/flickr.qml
+++ b/demos/declarative/flickr/flickr.qml
@@ -37,14 +37,18 @@ Item {
Connection {
sender: ImageDetails; signal: "closed()"
- script: { if (Wrapper.state == 'Details') Wrapper.state = '' }
+ script: {
+ if (Wrapper.state == 'Details') {
+ Wrapper.state = '';
+ ImageDetails.photoUrl = "";
+ }
+ }
}
Script {
function photoClicked() {
ImageDetails.photoTitle = title;
ImageDetails.flickableArea.yPosition = 0;
- ImageDetails.fullScreenArea.source = "";
ImageDetails.photoDescription = description;
ImageDetails.photoTags = tags;
ImageDetails.photoWidth = photoWidth;
diff --git a/src/declarative/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp
index 106d551..657e9a5 100644
--- a/src/declarative/fx/qfximage.cpp
+++ b/src/declarative/fx/qfximage.cpp
@@ -783,6 +783,19 @@ QString QFxImage::propertyInfo() const
return d->url.toString();
}
+/*!
+ \qmlproperty enum Image::status
+
+ This property holds the status of image loading. It can be one of:
+ \list
+ \o Idle - no image has been set, or the image has been loaded
+ \o Loading - the images is currently being loaded
+ \o Error - an error occurred while loading the image
+ \endlist
+
+ \sa progress
+*/
+
QFxImage::Status QFxImage::status() const
{
Q_D(const QFxImage);
@@ -790,6 +803,21 @@ QFxImage::Status QFxImage::status() const
}
/*!
+ \qmlproperty real Image::progress
+
+ This property holds the progress of image loading, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+
+ \sa status
+*/
+
+qreal QFxImage::progress() const
+{
+ Q_D(const QFxImage);
+ return d->progress;
+}
+
+/*!
\qmlproperty string Image::source
Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt.
@@ -844,10 +872,25 @@ void QFxImage::setSource(const QString &url)
d->source = url;
d->url = qmlContext(this)->resolvedUrl(url);
d->sciurl = QUrl();
+ if (d->progress != 0.0) {
+ d->progress = 0.0;
+ emit progressChanged(d->progress);
+ }
if (url.isEmpty()) {
setPixmap(QPixmap());
d->status = Idle;
+ d->progress = 1.0;
+ setImplicitWidth(0);
+ setImplicitHeight(0);
+#if defined(QFX_RENDER_OPENGL)
+ d->_texDirty = true;
+ d->_tex.clear();
+#endif
+ emit statusChanged(d->status);
+ emit sourceChanged(d->source);
+ emit progressChanged(1.0);
+ update();
} else {
d->status = Loading;
if (d->url.path().endsWith(QLatin1String(".sci"))) {
@@ -866,7 +909,14 @@ void QFxImage::setSource(const QString &url)
this, SLOT(sciRequestFinished()));
}
} else {
- QFxPixmap::get(qmlEngine(this), d->url, this, SLOT(requestFinished()));
+ d->reply = QFxPixmap::get(qmlEngine(this), d->url, this, SLOT(requestFinished()));
+ if (d->reply) {
+ connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ } else {
+ d->progress = 1.0;
+ emit progressChanged(d->progress);
+ }
}
}
@@ -879,6 +929,12 @@ void QFxImage::requestFinished()
if (d->url.path().endsWith(QLatin1String(".sci"))) {
d->_pix = QFxPixmap(d->sciurl);
} else {
+ if (d->reply) {
+ disconnect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ if (d->reply->error() != QNetworkReply::NoError)
+ d->status = Error;
+ }
d->_pix = QFxPixmap(d->url);
d->_pix.setOpaque(d->_opaque);
setOptions(QFxImage::SimpleItem, true);
@@ -886,13 +942,16 @@ void QFxImage::requestFinished()
setImplicitWidth(d->_pix.width());
setImplicitHeight(d->_pix.height());
- d->status = Idle;
+ if (d->status == Loading)
+ d->status = Idle;
+ d->progress = 1.0;
#if defined(QFX_RENDER_OPENGL)
d->_texDirty = true;
d->_tex.clear();
#endif
emit statusChanged(d->status);
emit sourceChanged(d->source);
+ emit progressChanged(1.0);
update();
}
@@ -912,6 +971,14 @@ void QFxImage::sciRequestFinished()
}
}
+void QFxImage::requestProgress(qint64 received, qint64 total)
+{
+ Q_D(QFxImage);
+ if (d->status == Loading && total > 0) {
+ d->progress = qreal(received)/total;
+ emit progressChanged(d->progress);
+ }
+}
void QFxImage::setGridScaledImage(const QFxGridScaledImage& sci)
{
@@ -921,7 +988,14 @@ void QFxImage::setGridScaledImage(const QFxGridScaledImage& sci)
emit statusChanged(d->status);
} else {
d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl()));
- QFxPixmap::get(qmlEngine(this), d->sciurl, this, SLOT(requestFinished()));
+ d->reply = QFxPixmap::get(qmlEngine(this), d->sciurl, this, SLOT(requestFinished()));
+ if (d->reply) {
+ connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ } else {
+ d->progress = 1.0;
+ emit progressChanged(d->progress);
+ }
QFxScaleGrid *sg = scaleGrid();
sg->setTop(sci.gridTop());
sg->setBottom(sci.gridBottom());
diff --git a/src/declarative/fx/qfximage.h b/src/declarative/fx/qfximage.h
index 37fe5be..dc13a97 100644
--- a/src/declarative/fx/qfximage.h
+++ b/src/declarative/fx/qfximage.h
@@ -43,6 +43,7 @@
#define QFXIMAGE_H
#include <qfxitem.h>
+#include <QtNetwork/qnetworkreply.h>
QT_BEGIN_HEADER
@@ -58,6 +59,7 @@ class Q_DECLARATIVE_EXPORT QFxImage : public QFxItem
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
Q_PROPERTY(QFxScaleGrid *scaleGrid READ scaleGrid)
Q_PROPERTY(bool tile READ isTiled WRITE setTiled)
@@ -84,6 +86,7 @@ public:
enum Status { Idle, Loading, Error };
Status status() const;
+ qreal progress() const;
QString source() const;
virtual void setSource(const QString &url);
@@ -101,6 +104,7 @@ public:
Q_SIGNALS:
void sourceChanged(const QString &);
void statusChanged(Status);
+ void progressChanged(qreal progress);
protected:
QFxImage(QFxImagePrivate &dd, QFxItem *parent);
@@ -109,6 +113,7 @@ protected:
private Q_SLOTS:
void requestFinished();
void sciRequestFinished();
+ void requestProgress(qint64,qint64);
private:
Q_DISABLE_COPY(QFxImage)
diff --git a/src/declarative/fx/qfximage_p.h b/src/declarative/fx/qfximage_p.h
index fbb4c44..43942fe 100644
--- a/src/declarative/fx/qfximage_p.h
+++ b/src/declarative/fx/qfximage_p.h
@@ -76,7 +76,7 @@ public:
#if defined(QFX_RENDER_OPENGL)
_texDirty(true),
#endif
- status(QFxImage::Idle), reply(0)
+ status(QFxImage::Idle), reply(0), progress(0.0)
{
}
@@ -95,10 +95,10 @@ public:
}
QFxScaleGrid *_scaleGrid;
- bool _tiled;
QFxPixmap _pix;
- bool _smooth;
- bool _opaque;
+ bool _tiled : 1;
+ bool _smooth : 1;
+ bool _opaque : 1;
#if defined(QFX_RENDER_OPENGL)
void checkDirty();
bool _texDirty;
@@ -109,7 +109,8 @@ public:
QString source;
QUrl url;
QUrl sciurl;
- QNetworkReply *reply;
+ QPointer<QNetworkReply> reply;
+ qreal progress;
};
QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxpixmap.cpp b/src/declarative/fx/qfxpixmap.cpp
index 0d456c6..3fdd8e5 100644
--- a/src/declarative/fx/qfxpixmap.cpp
+++ b/src/declarative/fx/qfxpixmap.cpp
@@ -233,8 +233,11 @@ QFxPixmap::operator const QSimpleCanvasConfig::Image &() const
Starts a network request to load \a url. When the URL is loaded,
the given slot is invoked. Note that if the image is already cached,
the slot may be invoked immediately.
+
+ Returns a QNetworkReply if the image is not immediately available, otherwise
+ returns 0. The QNetworkReply must not be stored - it may be destroyed at any time.
*/
-void QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char* slot)
+QNetworkReply *QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char* slot)
{
QString key = url.toString();
QFxPixmapCache::Iterator iter = qfxPixmapCache.find(key);
@@ -259,11 +262,14 @@ void QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char
if ((*iter)->reply) {
// still loading
QObject::connect((*iter)->reply, SIGNAL(finished()), obj, slot);
+ return (*iter)->reply;
} else {
// already loaded
QObject dummy;
QObject::connect(&dummy, SIGNAL(destroyed()), obj, slot);
}
+
+ return 0;
}
/*!
diff --git a/src/declarative/fx/qfxpixmap.h b/src/declarative/fx/qfxpixmap.h
index 9a3ba4e..748991e 100644
--- a/src/declarative/fx/qfxpixmap.h
+++ b/src/declarative/fx/qfxpixmap.h
@@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class QmlEngine;
+class QNetworkReply;
class QFxPixmapPrivate;
class Q_DECLARATIVE_EXPORT QFxPixmap
{
@@ -65,7 +66,7 @@ public:
QFxPixmap &operator=(const QFxPixmap &);
- static void get(QmlEngine *, const QUrl& url, QObject*, const char* slot);
+ static QNetworkReply *get(QmlEngine *, const QUrl& url, QObject*, const char* slot);
static void cancelGet(const QUrl& url, QObject* obj, const char* slot);
bool isNull() const;
diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp
index 1cd2f69..8184bda 100644
--- a/src/declarative/util/qmllistmodel.cpp
+++ b/src/declarative/util/qmllistmodel.cpp
@@ -93,8 +93,7 @@ Q_DECLARE_METATYPE(QListModelInterface *);
}
\endcode
- Elements beginning with a capital are items. Elements beginning
- with lower-case are the data roles. The above example defines a
+ Item roles (properties) must begin with a lower-case letter. The above example defines a
ListModel containing three items, with the roles "name" and "cost".
The defined model can be used in views such as ListView:
@@ -102,15 +101,9 @@ Q_DECLARE_METATYPE(QListModelInterface *);
Component {
id: FruitDelegate
Item {
- width: 200
- height: 50
- Text {
- text: name
- }
- Text {
- text: '$'+cost
- anchors.right: parent.right
- }
+ width: 200; height: 50
+ Text { text: name }
+ Text { text: '$'+cost; anchors.right: parent.right }
}
}
@@ -120,6 +113,59 @@ Q_DECLARE_METATYPE(QListModelInterface *);
anchors.fill: parent
}
\endcode
+
+ It is possible for roles to contain list data. In the example below we create a list of fruit attributes:
+
+ \code
+ ListModel {
+ id: FruitModel
+ ListElement {
+ name: "Apple"
+ cost: 2.45
+ attributes: [
+ ListElement { description: "Core" },
+ ListElement { description: "Deciduous" }
+ ]
+ }
+ ListElement {
+ name: "Orange"
+ cost: 3.25
+ attributes: [
+ ListElement { description: "Citrus" }
+ ]
+ }
+ ListElement {
+ name: "Banana"
+ cost: 1.95
+ attributes: [
+ ListElement { description: "Tropical" }
+ ListElement { description: "Seedless" }
+ ]
+ }
+ }
+ \endcode
+
+ The delegate below will list all the fruit attributes:
+ \code
+ Component {
+ id: FruitDelegate
+ Item {
+ width: 200; height: 50
+ Text { id: Name; text: name }
+ Text { text: '$'+cost; anchors.right: parent.right }
+ HorizontalLayout {
+ anchors.top: Name.bottom
+ spacing: 5
+ Text { text: "Attributes:" }
+ Repeater {
+ dataSource: attributes
+ Component { Text { text: description } }
+ }
+ }
+ }
+ }
+ \endcode
+
*/
struct ModelNode;