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 \qmlclass AnimatedImage QQuickAnimatedImage
57 \inqmlmodule QtQuick 2
59 \ingroup basic-visual-elements
60 \brief Plays animations stored as a series of images
62 The AnimatedImage element extends the features of the \l Image element, providing
63 a way to play animations stored as images containing a series of frames,
64 such as those stored in GIF files.
66 Information about the current frame and total length of the animation can be
67 obtained using the \l currentFrame and \l frameCount properties. You can
68 start, pause and stop the animation by changing the values of the \l playing
69 and \l paused properties.
71 The full list of supported formats can be determined with QMovie::supportedFormats().
73 \section1 Example Usage
76 \image animatedimageitem.gif
79 The following QML shows how to display an animated image and obtain information
80 about its state, such as the current frame and total number of frames.
81 The result is an animated image with a simple progress indicator underneath it.
83 \b Note: Unlike images, animated images are not cached or shared internally.
86 \snippet doc/snippets/qml/animatedimage.qml document
88 \sa BorderImage, Image
92 \qmlproperty url QtQuick2::AnimatedImage::source
94 This property holds the URL that refers to the source image.
96 AnimatedImage can handle any image format supported by Qt, loaded from any
97 URL scheme supported by Qt.
99 \sa QQuickImageProvider
103 \qmlproperty bool QtQuick2::AnimatedImage::asynchronous
105 Specifies that images on the local filesystem should be loaded
106 asynchronously in a separate thread. The default value is
107 false, causing the user interface thread to block while the
108 image is loaded. Setting \a asynchronous to true is useful where
109 maintaining a responsive user interface is more desirable
110 than having images immediately visible.
112 Note that this property is only valid for images read from the
113 local filesystem. Images loaded via a network resource (e.g. HTTP)
114 are always loaded asynchronously.
118 \qmlproperty bool QtQuick2::AnimatedImage::mirror
120 This property holds whether the image should be horizontally inverted
121 (effectively displaying a mirrored image).
123 The default value is false.
126 QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
127 : QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
131 QQuickAnimatedImage::~QQuickAnimatedImage()
133 Q_D(QQuickAnimatedImage);
138 \qmlproperty bool QtQuick2::AnimatedImage::paused
139 This property holds whether the animated image is paused.
141 By default, this property is false. Set it to true when you want to pause
145 bool QQuickAnimatedImage::isPaused() const
147 Q_D(const QQuickAnimatedImage);
150 return d->_movie->state()==QMovie::Paused;
153 void QQuickAnimatedImage::setPaused(bool pause)
155 Q_D(QQuickAnimatedImage);
156 if (pause == d->paused)
161 d->_movie->setPaused(pause);
165 \qmlproperty bool QtQuick2::AnimatedImage::playing
166 This property holds whether the animated image is playing.
168 By default, this property is true, meaning that the animation
169 will start playing immediately.
172 bool QQuickAnimatedImage::isPlaying() const
174 Q_D(const QQuickAnimatedImage);
177 return d->_movie->state()!=QMovie::NotRunning;
180 void QQuickAnimatedImage::setPlaying(bool play)
182 Q_D(QQuickAnimatedImage);
183 if (play == d->playing)
195 \qmlproperty int QtQuick2::AnimatedImage::currentFrame
196 \qmlproperty int QtQuick2::AnimatedImage::frameCount
198 currentFrame is the frame that is currently visible. By monitoring this property
199 for changes, you can animate other items at the same time as the image.
201 frameCount is the number of frames in the animation. For some animation formats,
202 frameCount is unknown and has a value of zero.
204 int QQuickAnimatedImage::currentFrame() const
206 Q_D(const QQuickAnimatedImage);
208 return d->preset_currentframe;
209 return d->_movie->currentFrameNumber();
212 void QQuickAnimatedImage::setCurrentFrame(int frame)
214 Q_D(QQuickAnimatedImage);
216 d->preset_currentframe = frame;
219 d->_movie->jumpToFrame(frame);
222 int QQuickAnimatedImage::frameCount() const
224 Q_D(const QQuickAnimatedImage);
227 return d->_movie->frameCount();
230 void QQuickAnimatedImage::setSource(const QUrl &url)
232 Q_D(QQuickAnimatedImage);
240 d->reply->deleteLater();
245 emit sourceChanged(d->url);
247 if (isComponentComplete())
251 void QQuickAnimatedImage::load()
253 Q_D(QQuickAnimatedImage);
255 QQuickImageBase::Status oldStatus = d->status;
256 qreal oldProgress = d->progress;
258 if (d->url.isEmpty()) {
260 d->setImage(QImage());
263 if (d->status != oldStatus)
264 emit statusChanged(d->status);
265 if (d->progress != oldProgress)
266 emit progressChanged(d->progress);
268 QString lf = QQmlFile::urlToLocalFileOrQrc(d->url);
270 //### should be unified with movieRequestFinished
271 d->_movie = new QMovie(lf);
272 if (!d->_movie->isValid()){
273 qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString();
277 if (d->status != oldStatus)
278 emit statusChanged(d->status);
281 connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
282 this, SLOT(playingStatusChanged()));
283 connect(d->_movie, SIGNAL(frameChanged(int)),
284 this, SLOT(movieUpdate()));
285 d->_movie->setCacheMode(QMovie::CacheAll);
289 d->_movie->jumpToFrame(0);
291 d->_movie->setPaused(true);
292 d->setImage(d->_movie->currentPixmap().toImage());
295 if (d->status != oldStatus)
296 emit statusChanged(d->status);
297 if (d->progress != oldProgress)
298 emit progressChanged(d->progress);
304 emit statusChanged(d->status);
305 emit progressChanged(d->progress);
306 QNetworkRequest req(d->url);
307 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
308 d->reply = qmlEngine(this)->networkAccessManager()->get(req);
309 QObject::connect(d->reply, SIGNAL(finished()),
310 this, SLOT(movieRequestFinished()));
311 QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
312 this, SLOT(requestProgress(qint64,qint64)));
316 #define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16
318 void QQuickAnimatedImage::movieRequestFinished()
320 Q_D(QQuickAnimatedImage);
323 if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) {
324 QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
325 if (redirect.isValid()) {
326 QUrl url = d->reply->url().resolved(redirect.toUrl());
327 d->reply->deleteLater();
335 d->_movie = new QMovie(d->reply);
336 if (!d->_movie->isValid()){
337 #ifndef QT_NO_DEBUG_STREAM
338 qmlInfo(this) << "Error Reading Animated Image File " << d->url;
343 emit statusChanged(d->status);
346 connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
347 this, SLOT(playingStatusChanged()));
348 connect(d->_movie, SIGNAL(frameChanged(int)),
349 this, SLOT(movieUpdate()));
350 d->_movie->setCacheMode(QMovie::CacheAll);
353 if (d->paused || !d->playing) {
354 d->_movie->jumpToFrame(d->preset_currentframe);
355 d->preset_currentframe = 0;
358 d->_movie->setPaused(true);
359 d->setImage(d->_movie->currentPixmap().toImage());
361 emit statusChanged(d->status);
364 void QQuickAnimatedImage::movieUpdate()
366 Q_D(QQuickAnimatedImage);
367 d->setImage(d->_movie->currentPixmap().toImage());
371 void QQuickAnimatedImage::playingStatusChanged()
373 Q_D(QQuickAnimatedImage);
374 if ((d->_movie->state() != QMovie::NotRunning) != d->playing) {
375 d->playing = (d->_movie->state() != QMovie::NotRunning);
376 emit playingChanged();
378 if ((d->_movie->state() == QMovie::Paused) != d->paused) {
379 d->playing = (d->_movie->state() == QMovie::Paused);
380 emit pausedChanged();
384 void QQuickAnimatedImage::componentComplete()
386 Q_D(QQuickAnimatedImage);
387 QQuickItem::componentComplete(); // NOT QQuickImage
388 if (d->url.isValid())
391 setCurrentFrame(d->preset_currentframe);
392 d->preset_currentframe = 0;
398 #endif // QT_NO_MOVIE