Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / qtquick1 / graphicsitems / qdeclarativeanimatedimage.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 QtDeclarative 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 "QtQuick1/private/qdeclarativeanimatedimage_p.h"
43 #include "QtQuick1/private/qdeclarativeanimatedimage_p_p.h"
44
45 #ifndef QT_NO_MOVIE
46
47 #include <QtDeclarative/qdeclarativeinfo.h>
48 #include <QtDeclarative/private/qdeclarativeengine_p.h>
49
50 #include <QMovie>
51 #include <QNetworkRequest>
52 #include <QNetworkReply>
53
54 QT_BEGIN_NAMESPACE
55
56
57
58 /*!
59     \qmlclass AnimatedImage QDeclarative1AnimatedImage
60     \inqmlmodule QtQuick 1
61     \inherits Image
62     \since QtQuick 1.0
63     \ingroup basic-visual-elements
64
65     The AnimatedImage element extends the features of the \l Image element, providing
66     a way to play animations stored as images containing a series of frames,
67     such as those stored in GIF files.
68
69     Information about the current frame and totla length of the animation can be
70     obtained using the \l currentFrame and \l frameCount properties. You can
71     start, pause and stop the animation by changing the values of the \l playing
72     and \l paused properties.
73
74     The full list of supported formats can be determined with QMovie::supportedFormats().
75
76     \section1 Example Usage
77
78     \beginfloatleft
79     \image animatedimageitem.gif
80     \endfloat
81
82     The following QML shows how to display an animated image and obtain information
83     about its state, such as the current frame and total number of frames.
84     The result is an animated image with a simple progress indicator underneath it.
85
86     \bold Note: Unlike images, animated images are not cached or shared internally.
87
88     \clearfloat
89     \snippet doc/src/snippets/qtquick1/animatedimage.qml document
90
91     \sa BorderImage, Image
92 */
93
94 /*!
95     \qmlproperty url QtQuick1::AnimatedImage::source
96
97     This property holds the URL that refers to the source image.
98
99     AnimatedImage can handle any image format supported by Qt, loaded from any
100     URL scheme supported by Qt.
101
102     \sa QDeclarativeImageProvider
103 */
104
105 /*!
106     \qmlproperty bool QtQuick1::AnimatedImage::asynchronous
107
108     Specifies that images on the local filesystem should be loaded
109     asynchronously in a separate thread.  The default value is
110     false, causing the user interface thread to block while the
111     image is loaded.  Setting \a asynchronous to true is useful where
112     maintaining a responsive user interface is more desirable
113     than having images immediately visible.
114
115     Note that this property is only valid for images read from the
116     local filesystem.  Images loaded via a network resource (e.g. HTTP)
117     are always loaded asynchonously.
118 */
119
120 /*!
121     \qmlproperty bool QtQuick1::AnimatedImage::mirror
122     \since Quick 1.1
123
124     This property holds whether the image should be horizontally inverted
125     (effectively displaying a mirrored image).
126
127     The default value is false.
128 */
129
130 QDeclarative1AnimatedImage::QDeclarative1AnimatedImage(QDeclarativeItem *parent)
131     : QDeclarative1Image(*(new QDeclarative1AnimatedImagePrivate), parent)
132 {
133 }
134
135 QDeclarative1AnimatedImage::~QDeclarative1AnimatedImage()
136 {
137     Q_D(QDeclarative1AnimatedImage);
138     delete d->_movie;
139 }
140
141 /*!
142   \qmlproperty bool QtQuick1::AnimatedImage::paused
143   This property holds whether the animated image is paused.
144
145   By default, this property is false. Set it to true when you want to pause
146   the animation.
147 */
148 bool QDeclarative1AnimatedImage::isPaused() const
149 {
150     Q_D(const QDeclarative1AnimatedImage);
151     if(!d->_movie)
152         return false;
153     return d->_movie->state()==QMovie::Paused;
154 }
155
156 void QDeclarative1AnimatedImage::setPaused(bool pause)
157 {
158     Q_D(QDeclarative1AnimatedImage);
159     if(pause == d->paused)
160         return;
161     d->paused = pause;
162     if(!d->_movie)
163         return;
164     d->_movie->setPaused(pause);
165 }
166 /*!
167   \qmlproperty bool QtQuick1::AnimatedImage::playing
168   This property holds whether the animated image is playing.
169
170   By default, this property is true, meaning that the animation
171   will start playing immediately.
172 */
173 bool QDeclarative1AnimatedImage::isPlaying() const
174 {
175     Q_D(const QDeclarative1AnimatedImage);
176     if (!d->_movie)
177         return false;
178     return d->_movie->state()!=QMovie::NotRunning;
179 }
180
181 void QDeclarative1AnimatedImage::setPlaying(bool play)
182 {
183     Q_D(QDeclarative1AnimatedImage);
184     if(play == d->playing)
185         return;
186     d->playing = play;
187     if (!d->_movie)
188         return;
189     if (play)
190         d->_movie->start();
191     else
192         d->_movie->stop();
193 }
194
195 /*!
196   \qmlproperty int QtQuick1::AnimatedImage::currentFrame
197   \qmlproperty int QtQuick1::AnimatedImage::frameCount
198
199   currentFrame is the frame that is currently visible. By monitoring this property
200   for changes, you can animate other items at the same time as the image.
201
202   frameCount is the number of frames in the animation. For some animation formats,
203   frameCount is unknown and has a value of zero.
204 */
205 int QDeclarative1AnimatedImage::currentFrame() const
206 {
207     Q_D(const QDeclarative1AnimatedImage);
208     if (!d->_movie)
209         return d->preset_currentframe;
210     return d->_movie->currentFrameNumber();
211 }
212
213 void QDeclarative1AnimatedImage::setCurrentFrame(int frame)
214 {
215     Q_D(QDeclarative1AnimatedImage);
216     if (!d->_movie) {
217         d->preset_currentframe = frame;
218         return;
219     }
220     d->_movie->jumpToFrame(frame);
221 }
222
223 int QDeclarative1AnimatedImage::frameCount() const
224 {
225     Q_D(const QDeclarative1AnimatedImage);
226     if (!d->_movie)
227         return 0;
228     return d->_movie->frameCount();
229 }
230
231 void QDeclarative1AnimatedImage::setSource(const QUrl &url)
232 {
233     Q_D(QDeclarative1AnimatedImage);
234     if (url == d->url)
235         return;
236
237     delete d->_movie;
238     d->_movie = 0;
239
240     if (d->reply) {
241         d->reply->deleteLater();
242         d->reply = 0;
243     }
244
245     d->url = url;
246     emit sourceChanged(d->url);
247
248     if (isComponentComplete())
249         load();
250 }
251
252 void QDeclarative1AnimatedImage::load()
253 {
254     Q_D(QDeclarative1AnimatedImage);
255
256     QDeclarative1ImageBase::Status oldStatus = d->status;
257     qreal oldProgress = d->progress;
258
259     if (d->url.isEmpty()) {
260         delete d->_movie;
261         d->setPixmap(QPixmap());
262         d->progress = 0;
263         d->status = Null;
264         if (d->status != oldStatus)
265             emit statusChanged(d->status);
266         if (d->progress != oldProgress)
267             emit progressChanged(d->progress);
268     } else {
269 #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
270         QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
271         if (!lf.isEmpty()) {
272             //### should be unified with movieRequestFinished
273             d->_movie = new QMovie(lf);
274             if (!d->_movie->isValid()){
275                 qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString();
276                 delete d->_movie;
277                 d->_movie = 0;
278                 d->status = Error;
279                 if (d->status != oldStatus)
280                     emit statusChanged(d->status);
281                 return;
282             }
283             connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
284                     this, SLOT(playingStatusChanged()));
285             connect(d->_movie, SIGNAL(frameChanged(int)),
286                     this, SLOT(movieUpdate()));
287             d->_movie->setCacheMode(QMovie::CacheAll);
288             if(d->playing)
289                 d->_movie->start();
290             else
291                 d->_movie->jumpToFrame(0);
292             if(d->paused)
293                 d->_movie->setPaused(true);
294             d->setPixmap(d->_movie->currentPixmap());
295             d->status = Ready;
296             d->progress = 1.0;
297             if (d->status != oldStatus)
298                 emit statusChanged(d->status);
299             if (d->progress != oldProgress)
300                 emit progressChanged(d->progress);
301             return;
302         }
303 #endif
304         d->status = Loading;
305         d->progress = 0;
306         emit statusChanged(d->status);
307         emit progressChanged(d->progress);
308         QNetworkRequest req(d->url);
309         req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
310         d->reply = qmlEngine(this)->networkAccessManager()->get(req);
311         QObject::connect(d->reply, SIGNAL(finished()),
312                          this, SLOT(movieRequestFinished()));
313         QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
314                          this, SLOT(requestProgress(qint64,qint64)));
315     }
316 }
317
318 #define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16
319
320 void QDeclarative1AnimatedImage::movieRequestFinished()
321 {
322     Q_D(QDeclarative1AnimatedImage);
323
324     d->redirectCount++;
325     if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) {
326         QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
327         if (redirect.isValid()) {
328             QUrl url = d->reply->url().resolved(redirect.toUrl());
329             d->reply->deleteLater();
330             d->reply = 0;
331             setSource(url);
332             return;
333         }
334     }
335     d->redirectCount=0;
336
337     d->_movie = new QMovie(d->reply);
338     if (!d->_movie->isValid()){
339 #ifndef QT_NO_DEBUG_STREAM
340         qmlInfo(this) << "Error Reading Animated Image File " << d->url;
341 #endif
342         delete d->_movie;
343         d->_movie = 0;
344         d->status = Error;
345         emit statusChanged(d->status);
346         return;
347     }
348     connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
349             this, SLOT(playingStatusChanged()));
350     connect(d->_movie, SIGNAL(frameChanged(int)),
351             this, SLOT(movieUpdate()));
352     d->_movie->setCacheMode(QMovie::CacheAll);
353     if(d->playing)
354         d->_movie->start();
355     if (d->paused || !d->playing) {
356         d->_movie->jumpToFrame(d->preset_currentframe);
357         d->preset_currentframe = 0;
358     }
359     if(d->paused)
360         d->_movie->setPaused(true);
361     d->setPixmap(d->_movie->currentPixmap());
362     d->status = Ready;
363     emit statusChanged(d->status);
364 }
365
366 void QDeclarative1AnimatedImage::movieUpdate()
367 {
368     Q_D(QDeclarative1AnimatedImage);
369     d->setPixmap(d->_movie->currentPixmap());
370     emit frameChanged();
371 }
372
373 void QDeclarative1AnimatedImage::playingStatusChanged()
374 {
375     Q_D(QDeclarative1AnimatedImage);
376     if((d->_movie->state() != QMovie::NotRunning) != d->playing){
377         d->playing = (d->_movie->state() != QMovie::NotRunning);
378         emit playingChanged();
379     }
380     if((d->_movie->state() == QMovie::Paused) != d->paused){
381         d->playing = (d->_movie->state() == QMovie::Paused);
382         emit pausedChanged();
383     }
384 }
385
386 void QDeclarative1AnimatedImage::componentComplete()
387 {
388     Q_D(QDeclarative1AnimatedImage);
389     QDeclarativeItem::componentComplete(); // NOT QDeclarative1Image
390     if (d->url.isValid())
391         load();
392     if (!d->reply) {
393         setCurrentFrame(d->preset_currentframe);
394         d->preset_currentframe = 0;
395     }
396 }
397
398
399
400 QT_END_NAMESPACE
401
402 #endif // QT_NO_MOVIE