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