1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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 <QtDeclarative/qdeclarativeinfo.h>
48 #include <QtGui/qmovie.h>
49 #include <QtNetwork/qnetworkrequest.h>
50 #include <QtNetwork/qnetworkreply.h>
52 #include <private/qdeclarativeengine_p.h>
56 \qmlclass AnimatedImage QQuickAnimatedImage
57 \inqmlmodule QtQuick 2
59 \ingroup basic-visual-elements
61 The AnimatedImage element extends the features of the \l Image element, providing
62 a way to play animations stored as images containing a series of frames,
63 such as those stored in GIF files.
65 Information about the current frame and total length of the animation can be
66 obtained using the \l currentFrame and \l frameCount properties. You can
67 start, pause and stop the animation by changing the values of the \l playing
68 and \l paused properties.
70 The full list of supported formats can be determined with QMovie::supportedFormats().
72 \section1 Example Usage
75 \image animatedimageitem.gif
78 The following QML shows how to display an animated image and obtain information
79 about its state, such as the current frame and total number of frames.
80 The result is an animated image with a simple progress indicator underneath it.
82 \bold Note: Unlike images, animated images are not cached or shared internally.
85 \snippet doc/src/snippets/declarative/animatedimage.qml document
87 \sa BorderImage, Image
91 \qmlproperty url QtQuick2::AnimatedImage::source
93 This property holds the URL that refers to the source image.
95 AnimatedImage can handle any image format supported by Qt, loaded from any
96 URL scheme supported by Qt.
98 \sa QDeclarativeImageProvider
102 \qmlproperty bool QtQuick2::AnimatedImage::asynchronous
104 Specifies that images on the local filesystem should be loaded
105 asynchronously in a separate thread. The default value is
106 false, causing the user interface thread to block while the
107 image is loaded. Setting \a asynchronous to true is useful where
108 maintaining a responsive user interface is more desirable
109 than having images immediately visible.
111 Note that this property is only valid for images read from the
112 local filesystem. Images loaded via a network resource (e.g. HTTP)
113 are always loaded asynchronously.
117 \qmlproperty bool QtQuick2::AnimatedImage::mirror
119 This property holds whether the image should be horizontally inverted
120 (effectively displaying a mirrored image).
122 The default value is false.
125 QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
126 : QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
130 QQuickAnimatedImage::~QQuickAnimatedImage()
132 Q_D(QQuickAnimatedImage);
137 \qmlproperty bool QtQuick2::AnimatedImage::paused
138 This property holds whether the animated image is paused.
140 By default, this property is false. Set it to true when you want to pause
144 bool QQuickAnimatedImage::isPaused() const
146 Q_D(const QQuickAnimatedImage);
149 return d->_movie->state()==QMovie::Paused;
152 void QQuickAnimatedImage::setPaused(bool pause)
154 Q_D(QQuickAnimatedImage);
155 if (pause == d->paused)
160 d->_movie->setPaused(pause);
164 \qmlproperty bool QtQuick2::AnimatedImage::playing
165 This property holds whether the animated image is playing.
167 By default, this property is true, meaning that the animation
168 will start playing immediately.
171 bool QQuickAnimatedImage::isPlaying() const
173 Q_D(const QQuickAnimatedImage);
176 return d->_movie->state()!=QMovie::NotRunning;
179 void QQuickAnimatedImage::setPlaying(bool play)
181 Q_D(QQuickAnimatedImage);
182 if (play == d->playing)
194 \qmlproperty int QtQuick2::AnimatedImage::currentFrame
195 \qmlproperty int QtQuick2::AnimatedImage::frameCount
197 currentFrame is the frame that is currently visible. By monitoring this property
198 for changes, you can animate other items at the same time as the image.
200 frameCount is the number of frames in the animation. For some animation formats,
201 frameCount is unknown and has a value of zero.
203 int QQuickAnimatedImage::currentFrame() const
205 Q_D(const QQuickAnimatedImage);
207 return d->preset_currentframe;
208 return d->_movie->currentFrameNumber();
211 void QQuickAnimatedImage::setCurrentFrame(int frame)
213 Q_D(QQuickAnimatedImage);
215 d->preset_currentframe = frame;
218 d->_movie->jumpToFrame(frame);
221 int QQuickAnimatedImage::frameCount() const
223 Q_D(const QQuickAnimatedImage);
226 return d->_movie->frameCount();
229 void QQuickAnimatedImage::setSource(const QUrl &url)
231 Q_D(QQuickAnimatedImage);
239 d->reply->deleteLater();
244 emit sourceChanged(d->url);
246 if (isComponentComplete())
250 void QQuickAnimatedImage::load()
252 Q_D(QQuickAnimatedImage);
254 QQuickImageBase::Status oldStatus = d->status;
255 qreal oldProgress = d->progress;
257 if (d->url.isEmpty()) {
259 d->setImage(QImage());
262 if (d->status != oldStatus)
263 emit statusChanged(d->status);
264 if (d->progress != oldProgress)
265 emit progressChanged(d->progress);
267 QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
269 //### should be unified with movieRequestFinished
270 d->_movie = new QMovie(lf);
271 if (!d->_movie->isValid()){
272 qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString();
276 if (d->status != oldStatus)
277 emit statusChanged(d->status);
280 connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
281 this, SLOT(playingStatusChanged()));
282 connect(d->_movie, SIGNAL(frameChanged(int)),
283 this, SLOT(movieUpdate()));
284 d->_movie->setCacheMode(QMovie::CacheAll);
288 d->_movie->jumpToFrame(0);
290 d->_movie->setPaused(true);
291 d->setImage(d->_movie->currentPixmap().toImage());
294 if (d->status != oldStatus)
295 emit statusChanged(d->status);
296 if (d->progress != oldProgress)
297 emit progressChanged(d->progress);
303 emit statusChanged(d->status);
304 emit progressChanged(d->progress);
305 QNetworkRequest req(d->url);
306 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
307 d->reply = qmlEngine(this)->networkAccessManager()->get(req);
308 QObject::connect(d->reply, SIGNAL(finished()),
309 this, SLOT(movieRequestFinished()));
310 QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
311 this, SLOT(requestProgress(qint64,qint64)));
315 #define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16
317 void QQuickAnimatedImage::movieRequestFinished()
319 Q_D(QQuickAnimatedImage);
322 if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) {
323 QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
324 if (redirect.isValid()) {
325 QUrl url = d->reply->url().resolved(redirect.toUrl());
326 d->reply->deleteLater();
334 d->_movie = new QMovie(d->reply);
335 if (!d->_movie->isValid()){
336 #ifndef QT_NO_DEBUG_STREAM
337 qmlInfo(this) << "Error Reading Animated Image File " << d->url;
342 emit statusChanged(d->status);
345 connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
346 this, SLOT(playingStatusChanged()));
347 connect(d->_movie, SIGNAL(frameChanged(int)),
348 this, SLOT(movieUpdate()));
349 d->_movie->setCacheMode(QMovie::CacheAll);
352 if (d->paused || !d->playing) {
353 d->_movie->jumpToFrame(d->preset_currentframe);
354 d->preset_currentframe = 0;
357 d->_movie->setPaused(true);
358 d->setImage(d->_movie->currentPixmap().toImage());
360 emit statusChanged(d->status);
363 void QQuickAnimatedImage::movieUpdate()
365 Q_D(QQuickAnimatedImage);
366 d->setImage(d->_movie->currentPixmap().toImage());
370 void QQuickAnimatedImage::playingStatusChanged()
372 Q_D(QQuickAnimatedImage);
373 if ((d->_movie->state() != QMovie::NotRunning) != d->playing) {
374 d->playing = (d->_movie->state() != QMovie::NotRunning);
375 emit playingChanged();
377 if ((d->_movie->state() == QMovie::Paused) != d->paused) {
378 d->playing = (d->_movie->state() == QMovie::Paused);
379 emit pausedChanged();
383 void QQuickAnimatedImage::componentComplete()
385 Q_D(QQuickAnimatedImage);
386 QQuickItem::componentComplete(); // NOT QQuickImage
387 if (d->url.isValid())
390 setCurrentFrame(d->preset_currentframe);
391 d->preset_currentframe = 0;
397 #endif // QT_NO_MOVIE