Doc: Sanitized QML types
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickanimatedimage.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickanimatedimage_p.h"
43 #include "qquickanimatedimage_p_p.h"
44
45 #ifndef QT_NO_MOVIE
46
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>
53
54 QT_BEGIN_NAMESPACE
55 /*!
56     \qmlclass AnimatedImage QQuickAnimatedImage
57     \inqmlmodule QtQuick 2
58     \inherits Image
59     \ingroup basic-visual-elements
60     \brief Plays animations stored as a series of images
61
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.
65
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.
70
71     The full list of supported formats can be determined with QMovie::supportedFormats().
72
73     \section1 Example Usage
74
75     \beginfloatleft
76     \image animatedimageitem.gif
77     \endfloat
78
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.
82
83     \b Note: Unlike images, animated images are not cached or shared internally.
84
85     \clearfloat
86     \snippet doc/snippets/qml/animatedimage.qml document
87
88     \sa BorderImage, Image
89 */
90
91 /*!
92     \qmlproperty url QtQuick2::AnimatedImage::source
93
94     This property holds the URL that refers to the source image.
95
96     AnimatedImage can handle any image format supported by Qt, loaded from any
97     URL scheme supported by Qt.
98
99     \sa QQuickImageProvider
100 */
101
102 /*!
103     \qmlproperty bool QtQuick2::AnimatedImage::asynchronous
104
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.
111
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.
115 */
116
117 /*!
118     \qmlproperty bool QtQuick2::AnimatedImage::mirror
119
120     This property holds whether the image should be horizontally inverted
121     (effectively displaying a mirrored image).
122
123     The default value is false.
124 */
125
126 QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
127     : QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
128 {
129 }
130
131 QQuickAnimatedImage::~QQuickAnimatedImage()
132 {
133     Q_D(QQuickAnimatedImage);
134     delete d->_movie;
135 }
136
137 /*!
138   \qmlproperty bool QtQuick2::AnimatedImage::paused
139   This property holds whether the animated image is paused.
140
141   By default, this property is false. Set it to true when you want to pause
142   the animation.
143 */
144
145 bool QQuickAnimatedImage::isPaused() const
146 {
147     Q_D(const QQuickAnimatedImage);
148     if (!d->_movie)
149         return false;
150     return d->_movie->state()==QMovie::Paused;
151 }
152
153 void QQuickAnimatedImage::setPaused(bool pause)
154 {
155     Q_D(QQuickAnimatedImage);
156     if (pause == d->paused)
157         return;
158     d->paused = pause;
159     if (!d->_movie)
160         return;
161     d->_movie->setPaused(pause);
162 }
163
164 /*!
165   \qmlproperty bool QtQuick2::AnimatedImage::playing
166   This property holds whether the animated image is playing.
167
168   By default, this property is true, meaning that the animation
169   will start playing immediately.
170 */
171
172 bool QQuickAnimatedImage::isPlaying() const
173 {
174     Q_D(const QQuickAnimatedImage);
175     if (!d->_movie)
176         return false;
177     return d->_movie->state()!=QMovie::NotRunning;
178 }
179
180 void QQuickAnimatedImage::setPlaying(bool play)
181 {
182     Q_D(QQuickAnimatedImage);
183     if (play == d->playing)
184         return;
185     d->playing = play;
186     if (!d->_movie)
187         return;
188     if (play)
189         d->_movie->start();
190     else
191         d->_movie->stop();
192 }
193
194 /*!
195   \qmlproperty int QtQuick2::AnimatedImage::currentFrame
196   \qmlproperty int QtQuick2::AnimatedImage::frameCount
197
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.
200
201   frameCount is the number of frames in the animation. For some animation formats,
202   frameCount is unknown and has a value of zero.
203 */
204 int QQuickAnimatedImage::currentFrame() const
205 {
206     Q_D(const QQuickAnimatedImage);
207     if (!d->_movie)
208         return d->preset_currentframe;
209     return d->_movie->currentFrameNumber();
210 }
211
212 void QQuickAnimatedImage::setCurrentFrame(int frame)
213 {
214     Q_D(QQuickAnimatedImage);
215     if (!d->_movie) {
216         d->preset_currentframe = frame;
217         return;
218     }
219     d->_movie->jumpToFrame(frame);
220 }
221
222 int QQuickAnimatedImage::frameCount() const
223 {
224     Q_D(const QQuickAnimatedImage);
225     if (!d->_movie)
226         return 0;
227     return d->_movie->frameCount();
228 }
229
230 void QQuickAnimatedImage::setSource(const QUrl &url)
231 {
232     Q_D(QQuickAnimatedImage);
233     if (url == d->url)
234         return;
235
236     delete d->_movie;
237     d->_movie = 0;
238
239     if (d->reply) {
240         d->reply->deleteLater();
241         d->reply = 0;
242     }
243
244     d->url = url;
245     emit sourceChanged(d->url);
246
247     if (isComponentComplete())
248         load();
249 }
250
251 void QQuickAnimatedImage::load()
252 {
253     Q_D(QQuickAnimatedImage);
254
255     QQuickImageBase::Status oldStatus = d->status;
256     qreal oldProgress = d->progress;
257
258     if (d->url.isEmpty()) {
259         delete d->_movie;
260         d->setImage(QImage());
261         d->progress = 0;
262         d->status = Null;
263         if (d->status != oldStatus)
264             emit statusChanged(d->status);
265         if (d->progress != oldProgress)
266             emit progressChanged(d->progress);
267     } else {
268         QString lf = QQmlFile::urlToLocalFileOrQrc(d->url);
269         if (!lf.isEmpty()) {
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();
274                 delete d->_movie;
275                 d->_movie = 0;
276                 d->status = Error;
277                 if (d->status != oldStatus)
278                     emit statusChanged(d->status);
279                 return;
280             }
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);
286             if (d->playing)
287                 d->_movie->start();
288             else
289                 d->_movie->jumpToFrame(0);
290             if (d->paused)
291                 d->_movie->setPaused(true);
292             d->setImage(d->_movie->currentPixmap().toImage());
293             d->status = Ready;
294             d->progress = 1.0;
295             if (d->status != oldStatus)
296                 emit statusChanged(d->status);
297             if (d->progress != oldProgress)
298                 emit progressChanged(d->progress);
299             return;
300         }
301
302         d->status = Loading;
303         d->progress = 0;
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)));
313     }
314 }
315
316 #define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16
317
318 void QQuickAnimatedImage::movieRequestFinished()
319 {
320     Q_D(QQuickAnimatedImage);
321
322     d->redirectCount++;
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();
328             d->reply = 0;
329             setSource(url);
330             return;
331         }
332     }
333     d->redirectCount=0;
334
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;
339 #endif
340         delete d->_movie;
341         d->_movie = 0;
342         d->status = Error;
343         emit statusChanged(d->status);
344         return;
345     }
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);
351     if (d->playing)
352         d->_movie->start();
353     if (d->paused || !d->playing) {
354         d->_movie->jumpToFrame(d->preset_currentframe);
355         d->preset_currentframe = 0;
356     }
357     if (d->paused)
358         d->_movie->setPaused(true);
359     d->setImage(d->_movie->currentPixmap().toImage());
360     d->status = Ready;
361     emit statusChanged(d->status);
362 }
363
364 void QQuickAnimatedImage::movieUpdate()
365 {
366     Q_D(QQuickAnimatedImage);
367     d->setImage(d->_movie->currentPixmap().toImage());
368     emit frameChanged();
369 }
370
371 void QQuickAnimatedImage::playingStatusChanged()
372 {
373     Q_D(QQuickAnimatedImage);
374     if ((d->_movie->state() != QMovie::NotRunning) != d->playing) {
375         d->playing = (d->_movie->state() != QMovie::NotRunning);
376         emit playingChanged();
377     }
378     if ((d->_movie->state() == QMovie::Paused) != d->paused) {
379         d->playing = (d->_movie->state() == QMovie::Paused);
380         emit pausedChanged();
381     }
382 }
383
384 void QQuickAnimatedImage::componentComplete()
385 {
386     Q_D(QQuickAnimatedImage);
387     QQuickItem::componentComplete(); // NOT QQuickImage
388     if (d->url.isValid())
389         load();
390     if (!d->reply) {
391         setCurrentFrame(d->preset_currentframe);
392         d->preset_currentframe = 0;
393     }
394 }
395
396 QT_END_NAMESPACE
397
398 #endif // QT_NO_MOVIE