1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickanimatedimage_p.h"
43 #include "qquickanimatedimage_p_p.h"
47 #include <QtQml/qqmlinfo.h>
48 #include <QtQml/qqmlfile.h>
49 #include <QtQml/qqmlengine.h>
50 #include <QtGui/qmovie.h>
51 #include <QtNetwork/qnetworkrequest.h>
52 #include <QtNetwork/qnetworkreply.h>
56 \qmltype AnimatedImage
57 \instantiates QQuickAnimatedImage
58 \inqmlmodule QtQuick 2
60 \brief Plays animations stored as a series of images
61 \ingroup qtquick-visual
63 The AnimatedImage type extends the features of the \l Image type, providing
64 a way to play animations stored as images containing a series of frames,
65 such as those stored in GIF files.
67 Information about the current frame and total length of the animation can be
68 obtained using the \l currentFrame and \l frameCount properties. You can
69 start, pause and stop the animation by changing the values of the \l playing
70 and \l paused properties.
72 The full list of supported formats can be determined with QMovie::supportedFormats().
74 \section1 Example Usage
77 \image animatedimageitem.gif
80 The following QML shows how to display an animated image and obtain information
81 about its state, such as the current frame and total number of frames.
82 The result is an animated image with a simple progress indicator underneath it.
84 \b Note: Unlike images, animated images are not cached or shared internally.
87 \snippet qml/animatedimage.qml document
89 \sa BorderImage, Image
93 \qmlproperty url QtQuick2::AnimatedImage::source
95 This property holds the URL that refers to the source image.
97 AnimatedImage can handle any image format supported by Qt, loaded from any
98 URL scheme supported by Qt.
100 \sa QQuickImageProvider
103 QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
104 : QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
108 QQuickAnimatedImage::~QQuickAnimatedImage()
110 Q_D(QQuickAnimatedImage);
112 d->reply->deleteLater();
117 \qmlproperty bool QtQuick2::AnimatedImage::paused
118 This property holds whether the animated image is paused.
120 By default, this property is false. Set it to true when you want to pause
124 bool QQuickAnimatedImage::isPaused() const
126 Q_D(const QQuickAnimatedImage);
129 return d->_movie->state()==QMovie::Paused;
132 void QQuickAnimatedImage::setPaused(bool pause)
134 Q_D(QQuickAnimatedImage);
135 if (pause == d->paused)
139 emit pausedChanged();
141 d->_movie->setPaused(pause);
146 \qmlproperty bool QtQuick2::AnimatedImage::playing
147 This property holds whether the animated image is playing.
149 By default, this property is true, meaning that the animation
150 will start playing immediately.
152 \b Note: this property is affected by changes to the actual playing
153 state of AnimatedImage. If non-animated images are used, \a playing
154 will need to be manually set to \a true in order to animate
158 onStatusChanged: playing = (status == AnimatedImage.Ready)
163 bool QQuickAnimatedImage::isPlaying() const
165 Q_D(const QQuickAnimatedImage);
168 return d->_movie->state()!=QMovie::NotRunning;
171 void QQuickAnimatedImage::setPlaying(bool play)
173 Q_D(QQuickAnimatedImage);
174 if (play == d->playing)
178 emit playingChanged();
188 \qmlproperty int QtQuick2::AnimatedImage::currentFrame
189 \qmlproperty int QtQuick2::AnimatedImage::frameCount
191 currentFrame is the frame that is currently visible. By monitoring this property
192 for changes, you can animate other items at the same time as the image.
194 frameCount is the number of frames in the animation. For some animation formats,
195 frameCount is unknown and has a value of zero.
197 int QQuickAnimatedImage::currentFrame() const
199 Q_D(const QQuickAnimatedImage);
201 return d->preset_currentframe;
202 return d->_movie->currentFrameNumber();
205 void QQuickAnimatedImage::setCurrentFrame(int frame)
207 Q_D(QQuickAnimatedImage);
209 d->preset_currentframe = frame;
212 d->_movie->jumpToFrame(frame);
215 int QQuickAnimatedImage::frameCount() const
217 Q_D(const QQuickAnimatedImage);
220 return d->_movie->frameCount();
223 void QQuickAnimatedImage::setSource(const QUrl &url)
225 Q_D(QQuickAnimatedImage);
230 d->reply->deleteLater();
234 d->oldPlaying = isPlaying();
241 emit sourceChanged(d->url);
243 if (isComponentComplete())
247 void QQuickAnimatedImage::load()
249 Q_D(QQuickAnimatedImage);
251 if (d->url.isEmpty()) {
252 if (d->progress != 0) {
254 emit progressChanged(d->progress);
257 d->setImage(QImage());
259 emit statusChanged(d->status);
261 if (sourceSize() != d->oldSourceSize) {
262 d->oldSourceSize = sourceSize();
263 emit sourceSizeChanged();
265 if (isPlaying() != d->oldPlaying)
266 emit playingChanged();
268 QString lf = QQmlFile::urlToLocalFileOrQrc(d->url);
270 d->_movie = new QMovie(lf);
271 movieRequestFinished();
273 if (d->status != Loading) {
275 emit statusChanged(d->status);
277 if (d->progress != 0) {
279 emit progressChanged(d->progress);
281 QNetworkRequest req(d->url);
282 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
284 d->reply = qmlEngine(this)->networkAccessManager()->get(req);
285 QObject::connect(d->reply, SIGNAL(finished()),
286 this, SLOT(movieRequestFinished()));
287 QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
288 this, SLOT(requestProgress(qint64,qint64)));
293 #define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16
295 void QQuickAnimatedImage::movieRequestFinished()
297 Q_D(QQuickAnimatedImage);
301 if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) {
302 QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
303 if (redirect.isValid()) {
304 QUrl url = d->reply->url().resolved(redirect.toUrl());
305 d->reply->deleteLater();
312 d->_movie = new QMovie(d->reply);
315 if (!d->_movie->isValid()) {
316 qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString();
319 d->setImage(QImage());
320 if (d->progress != 0) {
322 emit progressChanged(d->progress);
325 emit statusChanged(d->status);
327 if (sourceSize() != d->oldSourceSize) {
328 d->oldSourceSize = sourceSize();
329 emit sourceSizeChanged();
331 if (isPlaying() != d->oldPlaying)
332 emit playingChanged();
336 connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
337 this, SLOT(playingStatusChanged()));
338 connect(d->_movie, SIGNAL(frameChanged(int)),
339 this, SLOT(movieUpdate()));
340 d->_movie->setCacheMode(QMovie::CacheAll);
343 emit statusChanged(d->status);
345 if (d->progress != 1.0) {
347 emit progressChanged(d->progress);
350 bool pausedAtStart = d->paused;
355 d->_movie->setPaused(true);
356 if (d->paused || !d->playing) {
357 d->_movie->jumpToFrame(d->preset_currentframe);
358 d->preset_currentframe = 0;
360 d->setImage(d->_movie->currentPixmap().toImage());
362 if (isPlaying() != d->oldPlaying)
363 emit playingChanged();
364 if (sourceSize() != d->oldSourceSize) {
365 d->oldSourceSize = sourceSize();
366 emit sourceSizeChanged();
370 void QQuickAnimatedImage::movieUpdate()
372 Q_D(QQuickAnimatedImage);
375 d->setImage(d->_movie->currentPixmap().toImage());
380 void QQuickAnimatedImage::playingStatusChanged()
382 Q_D(QQuickAnimatedImage);
384 if ((d->_movie->state() != QMovie::NotRunning) != d->playing) {
385 d->playing = (d->_movie->state() != QMovie::NotRunning);
386 emit playingChanged();
388 if ((d->_movie->state() == QMovie::Paused) != d->paused) {
389 d->paused = (d->_movie->state() == QMovie::Paused);
390 emit pausedChanged();
394 QSize QQuickAnimatedImage::sourceSize()
396 Q_D(QQuickAnimatedImage);
399 return QSize(d->_movie->currentPixmap().size());
402 void QQuickAnimatedImage::componentComplete()
404 QQuickItem::componentComplete(); // NOT QQuickImage
410 #endif // QT_NO_MOVIE