Merged master into qtquick2.
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsganimatedimage.cpp
1 // Commit: af33f9f2e7ec433b81f5c18e3e7395db4a56c5fe
2 /****************************************************************************
3 **
4 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
5 ** All rights reserved.
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 **
8 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** No Commercial Usage
12 ** This file contains pre-release code and may not be distributed.
13 ** You may use this file in accordance with the terms and conditions
14 ** contained in the Technology Preview License Agreement accompanying
15 ** this package.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 **
39 ** $QT_END_LICENSE$
40 **
41 ****************************************************************************/
42
43 #include "qsganimatedimage_p.h"
44 #include "qsganimatedimage_p_p.h"
45
46 #ifndef QT_NO_MOVIE
47
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qmovie.h>
50 #include <QtNetwork/qnetworkrequest.h>
51 #include <QtNetwork/qnetworkreply.h>
52
53 #include <private/qdeclarativeengine_p.h>
54
55 QT_BEGIN_NAMESPACE
56
57 QSGAnimatedImage::QSGAnimatedImage(QSGItem *parent)
58     : QSGImage(*(new QSGAnimatedImagePrivate), parent)
59 {
60 }
61
62 QSGAnimatedImage::~QSGAnimatedImage()
63 {
64     Q_D(QSGAnimatedImage);
65     delete d->_movie;
66 }
67
68 bool QSGAnimatedImage::isPaused() const
69 {
70     Q_D(const QSGAnimatedImage);
71     if(!d->_movie)
72         return false;
73     return d->_movie->state()==QMovie::Paused;
74 }
75
76 void QSGAnimatedImage::setPaused(bool pause)
77 {
78     Q_D(QSGAnimatedImage);
79     if(pause == d->paused)
80         return;
81     d->paused = pause;
82     if(!d->_movie)
83         return;
84     d->_movie->setPaused(pause);
85 }
86
87 bool QSGAnimatedImage::isPlaying() const
88 {
89     Q_D(const QSGAnimatedImage);
90     if (!d->_movie)
91         return false;
92     return d->_movie->state()!=QMovie::NotRunning;
93 }
94
95 void QSGAnimatedImage::setPlaying(bool play)
96 {
97     Q_D(QSGAnimatedImage);
98     if(play == d->playing)
99         return;
100     d->playing = play;
101     if (!d->_movie)
102         return;
103     if (play)
104         d->_movie->start();
105     else
106         d->_movie->stop();
107 }
108
109 int QSGAnimatedImage::currentFrame() const
110 {
111     Q_D(const QSGAnimatedImage);
112     if (!d->_movie)
113         return d->preset_currentframe;
114     return d->_movie->currentFrameNumber();
115 }
116
117 void QSGAnimatedImage::setCurrentFrame(int frame)
118 {
119     Q_D(QSGAnimatedImage);
120     if (!d->_movie) {
121         d->preset_currentframe = frame;
122         return;
123     }
124     d->_movie->jumpToFrame(frame);
125 }
126
127 int QSGAnimatedImage::frameCount() const
128 {
129     Q_D(const QSGAnimatedImage);
130     if (!d->_movie)
131         return 0;
132     return d->_movie->frameCount();
133 }
134
135 void QSGAnimatedImage::setSource(const QUrl &url)
136 {
137     Q_D(QSGAnimatedImage);
138     if (url == d->url)
139         return;
140
141     delete d->_movie;
142     d->_movie = 0;
143
144     if (d->reply) {
145         d->reply->deleteLater();
146         d->reply = 0;
147     }
148
149     d->url = url;
150     emit sourceChanged(d->url);
151
152     if (isComponentComplete())
153         load();
154 }
155
156 void QSGAnimatedImage::load()
157 {
158     Q_D(QSGAnimatedImage);
159
160     QSGImageBase::Status oldStatus = d->status;
161     qreal oldProgress = d->progress;
162
163     if (d->url.isEmpty()) {
164         delete d->_movie;
165         d->setPixmap(QPixmap());
166         d->progress = 0;
167         d->status = Null;
168         if (d->status != oldStatus)
169             emit statusChanged(d->status);
170         if (d->progress != oldProgress)
171             emit progressChanged(d->progress);
172     } else {
173 #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
174         QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
175         if (!lf.isEmpty()) {
176             //### should be unified with movieRequestFinished
177             d->_movie = new QMovie(lf);
178             if (!d->_movie->isValid()){
179                 qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString();
180                 delete d->_movie;
181                 d->_movie = 0;
182                 d->status = Error;
183                 if (d->status != oldStatus)
184                     emit statusChanged(d->status);
185                 return;
186             }
187             connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
188                     this, SLOT(playingStatusChanged()));
189             connect(d->_movie, SIGNAL(frameChanged(int)),
190                     this, SLOT(movieUpdate()));
191             d->_movie->setCacheMode(QMovie::CacheAll);
192             if(d->playing)
193                 d->_movie->start();
194             else
195                 d->_movie->jumpToFrame(0);
196             if(d->paused)
197                 d->_movie->setPaused(true);
198             d->setPixmap(d->_movie->currentPixmap());
199             d->status = Ready;
200             d->progress = 1.0;
201             if (d->status != oldStatus)
202                 emit statusChanged(d->status);
203             if (d->progress != oldProgress)
204                 emit progressChanged(d->progress);
205             return;
206         }
207 #endif
208         d->status = Loading;
209         d->progress = 0;
210         emit statusChanged(d->status);
211         emit progressChanged(d->progress);
212         QNetworkRequest req(d->url);
213         req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
214         d->reply = qmlEngine(this)->networkAccessManager()->get(req);
215         QObject::connect(d->reply, SIGNAL(finished()),
216                          this, SLOT(movieRequestFinished()));
217         QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
218                          this, SLOT(requestProgress(qint64,qint64)));
219     }
220 }
221
222 #define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16
223
224 void QSGAnimatedImage::movieRequestFinished()
225 {
226     Q_D(QSGAnimatedImage);
227
228     d->redirectCount++;
229     if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) {
230         QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
231         if (redirect.isValid()) {
232             QUrl url = d->reply->url().resolved(redirect.toUrl());
233             d->reply->deleteLater();
234             d->reply = 0;
235             setSource(url);
236             return;
237         }
238     }
239     d->redirectCount=0;
240
241     d->_movie = new QMovie(d->reply);
242     if (!d->_movie->isValid()){
243 #ifndef QT_NO_DEBUG_STREAM
244         qmlInfo(this) << "Error Reading Animated Image File " << d->url;
245 #endif
246         delete d->_movie;
247         d->_movie = 0;
248         d->status = Error;
249         emit statusChanged(d->status);
250         return;
251     }
252     connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
253             this, SLOT(playingStatusChanged()));
254     connect(d->_movie, SIGNAL(frameChanged(int)),
255             this, SLOT(movieUpdate()));
256     d->_movie->setCacheMode(QMovie::CacheAll);
257     if(d->playing)
258         d->_movie->start();
259     if (d->paused || !d->playing) {
260         d->_movie->jumpToFrame(d->preset_currentframe);
261         d->preset_currentframe = 0;
262     }
263     if(d->paused)
264         d->_movie->setPaused(true);
265     d->setPixmap(d->_movie->currentPixmap());
266     d->status = Ready;
267     emit statusChanged(d->status);
268 }
269
270 void QSGAnimatedImage::movieUpdate()
271 {
272     Q_D(QSGAnimatedImage);
273     d->setPixmap(d->_movie->currentPixmap());
274     emit frameChanged();
275 }
276
277 void QSGAnimatedImage::playingStatusChanged()
278 {
279     Q_D(QSGAnimatedImage);
280     if((d->_movie->state() != QMovie::NotRunning) != d->playing){
281         d->playing = (d->_movie->state() != QMovie::NotRunning);
282         emit playingChanged();
283     }
284     if((d->_movie->state() == QMovie::Paused) != d->paused){
285         d->playing = (d->_movie->state() == QMovie::Paused);
286         emit pausedChanged();
287     }
288 }
289
290 void QSGAnimatedImage::componentComplete()
291 {
292     Q_D(QSGAnimatedImage);
293     QSGItem::componentComplete(); // NOT QSGImage
294     if (d->url.isValid())
295         load();
296     if (!d->reply) {
297         setCurrentFrame(d->preset_currentframe);
298         d->preset_currentframe = 0;
299     }
300 }
301
302 QT_END_NAMESPACE
303
304 #endif // QT_NO_MOVIE