Initial import from qtquick2.
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgborderimage.cpp
1 // Commit: 462429f5692f810bdd4e04b916db5f9af428d9e4
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 "qsgborderimage_p.h"
44 #include "qsgborderimage_p_p.h"
45 #include "qsgninepatchnode_p.h"
46
47 #include <QtDeclarative/qdeclarativeinfo.h>
48 #include <QtCore/qfile.h>
49
50 #include <private/qdeclarativeengine_p.h>
51
52 QT_BEGIN_NAMESPACE
53
54 QSGBorderImage::QSGBorderImage(QSGItem *parent)
55 : QSGImageBase(*(new QSGBorderImagePrivate), parent)
56 {
57 }
58
59 QSGBorderImage::~QSGBorderImage()
60 {
61     Q_D(QSGBorderImage);
62     if (d->sciReply)
63         d->sciReply->deleteLater();
64 }
65
66 void QSGBorderImage::setSource(const QUrl &url)
67 {
68     Q_D(QSGBorderImage);
69     //equality is fairly expensive, so we bypass for simple, common case
70     if ((d->url.isEmpty() == url.isEmpty()) && url == d->url)
71         return;
72
73     if (d->sciReply) {
74         d->sciReply->deleteLater();
75         d->sciReply = 0;
76     }
77
78     d->url = url;
79     d->sciurl = QUrl();
80     emit sourceChanged(d->url);
81
82     if (isComponentComplete())
83         load();
84 }
85
86 void QSGBorderImage::load()
87 {
88     Q_D(QSGBorderImage);
89     if (d->progress != 0.0) {
90         d->progress = 0.0;
91         emit progressChanged(d->progress);
92     }
93
94     if (d->url.isEmpty()) {
95         d->pix.clear(this);
96         d->status = Null;
97         setImplicitWidth(0);
98         setImplicitHeight(0);
99         emit statusChanged(d->status);
100         update();
101     } else {
102         d->status = Loading;
103         if (d->url.path().endsWith(QLatin1String("sci"))) {
104 #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
105             QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
106             if (!lf.isEmpty()) {
107                 QFile file(lf);
108                 file.open(QIODevice::ReadOnly);
109                 setGridScaledImage(QSGGridScaledImage(&file));
110             } else
111 #endif
112             {
113                 QNetworkRequest req(d->url);
114                 d->sciReply = qmlEngine(this)->networkAccessManager()->get(req);
115
116                 static int sciReplyFinished = -1;
117                 static int thisSciRequestFinished = -1;
118                 if (sciReplyFinished == -1) {
119                     sciReplyFinished =
120                         QNetworkReply::staticMetaObject.indexOfSignal("finished()");
121                     thisSciRequestFinished =
122                         QSGBorderImage::staticMetaObject.indexOfSlot("sciRequestFinished()");
123                 }
124
125                 QMetaObject::connect(d->sciReply, sciReplyFinished, this,
126                                      thisSciRequestFinished, Qt::DirectConnection);
127             }
128         } else {
129
130             QDeclarativePixmap::Options options;
131             if (d->async)
132                 options |= QDeclarativePixmap::Asynchronous;
133             if (d->cache)
134                 options |= QDeclarativePixmap::Cache;
135             d->pix.clear(this);
136             d->pix.load(qmlEngine(this), d->url, options);
137
138             if (d->pix.isLoading()) {
139                 d->pix.connectFinished(this, SLOT(requestFinished()));
140                 d->pix.connectDownloadProgress(this, SLOT(requestProgress(qint64,qint64)));
141             } else {
142                 QSize impsize = d->pix.implicitSize();
143                 setImplicitWidth(impsize.width());
144                 setImplicitHeight(impsize.height());
145
146                 if (d->pix.isReady()) {
147                     d->status = Ready;
148                 } else {
149                     d->status = Error;
150                     qmlInfo(this) << d->pix.error();
151                 }
152
153                 d->progress = 1.0;
154                 emit statusChanged(d->status);
155                 emit progressChanged(d->progress);
156                 update();
157             }
158         }
159     }
160
161     emit statusChanged(d->status);
162 }
163
164 QSGScaleGrid *QSGBorderImage::border()
165 {
166     Q_D(QSGBorderImage);
167     return d->getScaleGrid();
168 }
169
170 QSGBorderImage::TileMode QSGBorderImage::horizontalTileMode() const
171 {
172     Q_D(const QSGBorderImage);
173     return d->horizontalTileMode;
174 }
175
176 void QSGBorderImage::setHorizontalTileMode(TileMode t)
177 {
178     Q_D(QSGBorderImage);
179     if (t != d->horizontalTileMode) {
180         d->horizontalTileMode = t;
181         emit horizontalTileModeChanged();
182         update();
183     }
184 }
185
186 QSGBorderImage::TileMode QSGBorderImage::verticalTileMode() const
187 {
188     Q_D(const QSGBorderImage);
189     return d->verticalTileMode;
190 }
191
192 void QSGBorderImage::setVerticalTileMode(TileMode t)
193 {
194     Q_D(QSGBorderImage);
195     if (t != d->verticalTileMode) {
196         d->verticalTileMode = t;
197         emit verticalTileModeChanged();
198         update();
199     }
200 }
201
202 void QSGBorderImage::setGridScaledImage(const QSGGridScaledImage& sci)
203 {
204     Q_D(QSGBorderImage);
205     if (!sci.isValid()) {
206         d->status = Error;
207         emit statusChanged(d->status);
208     } else {
209         QSGScaleGrid *sg = border();
210         sg->setTop(sci.gridTop());
211         sg->setBottom(sci.gridBottom());
212         sg->setLeft(sci.gridLeft());
213         sg->setRight(sci.gridRight());
214         d->horizontalTileMode = sci.horizontalTileRule();
215         d->verticalTileMode = sci.verticalTileRule();
216
217         d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl()));
218
219         QDeclarativePixmap::Options options;
220         if (d->async)
221             options |= QDeclarativePixmap::Asynchronous;
222         if (d->cache)
223             options |= QDeclarativePixmap::Cache;
224         d->pix.clear(this);
225         d->pix.load(qmlEngine(this), d->sciurl, options);
226
227         if (d->pix.isLoading()) {
228             static int thisRequestProgress = -1;
229             static int thisRequestFinished = -1;
230             if (thisRequestProgress == -1) {
231                 thisRequestProgress =
232                     QSGBorderImage::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
233                 thisRequestFinished =
234                     QSGBorderImage::staticMetaObject.indexOfSlot("requestFinished()");
235             }
236
237             d->pix.connectFinished(this, thisRequestFinished);
238             d->pix.connectDownloadProgress(this, thisRequestProgress);
239
240         } else {
241
242             QSize impsize = d->pix.implicitSize();
243             setImplicitWidth(impsize.width());
244             setImplicitHeight(impsize.height());
245
246             if (d->pix.isReady()) {
247                 d->status = Ready;
248             } else {
249                 d->status = Error;
250                 qmlInfo(this) << d->pix.error();
251             }
252
253             d->progress = 1.0;
254             emit statusChanged(d->status);
255             emit progressChanged(1.0);
256             update();
257
258         }
259     }
260 }
261
262 void QSGBorderImage::requestFinished()
263 {
264     Q_D(QSGBorderImage);
265
266     QSize impsize = d->pix.implicitSize();
267     if (d->pix.isError()) {
268         d->status = Error;
269         qmlInfo(this) << d->pix.error();
270     } else {
271         d->status = Ready;
272     }
273
274     setImplicitWidth(impsize.width());
275     setImplicitHeight(impsize.height());
276
277     if (d->sourcesize.width() != d->pix.width() || d->sourcesize.height() != d->pix.height())
278         emit sourceSizeChanged();
279
280     d->progress = 1.0;
281     emit statusChanged(d->status);
282     emit progressChanged(1.0);
283     update();
284 }
285
286 #define BORDERIMAGE_MAX_REDIRECT 16
287
288 void QSGBorderImage::sciRequestFinished()
289 {
290     Q_D(QSGBorderImage);
291
292     d->redirectCount++;
293     if (d->redirectCount < BORDERIMAGE_MAX_REDIRECT) {
294         QVariant redirect = d->sciReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
295         if (redirect.isValid()) {
296             QUrl url = d->sciReply->url().resolved(redirect.toUrl());
297             setSource(url);
298             return;
299         }
300     }
301     d->redirectCount=0;
302
303     if (d->sciReply->error() != QNetworkReply::NoError) {
304         d->status = Error;
305         d->sciReply->deleteLater();
306         d->sciReply = 0;
307         emit statusChanged(d->status);
308     } else {
309         QSGGridScaledImage sci(d->sciReply);
310         d->sciReply->deleteLater();
311         d->sciReply = 0;
312         setGridScaledImage(sci);
313     }
314 }
315
316 void QSGBorderImage::doUpdate()
317 {
318     update();
319 }
320
321 QSGNode *QSGBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
322 {
323     Q_D(QSGBorderImage);
324
325     if (!d->pix.texture() || width() <= 0 || height() <= 0) {
326         delete oldNode;
327         return 0;
328     }
329
330     QSGNinePatchNode *node = static_cast<QSGNinePatchNode *>(oldNode);
331
332     if (!node) {
333         node = new QSGNinePatchNode();
334     }
335
336     node->setTexture(d->pix.texture());
337
338     const QSGScaleGrid *border = d->getScaleGrid();
339     node->setInnerRect(QRectF(border->left(),
340                               border->top(),
341                               d->pix.width() - border->right() - border->left(),
342                               d->pix.height() - border->bottom() - border->top()));
343     node->setRect(QRectF(0, 0, width(), height()));
344     node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
345     node->setHorzontalTileMode(d->horizontalTileMode);
346     node->setVerticalTileMode(d->verticalTileMode);
347     node->update();
348
349     return node;
350 }
351
352 void QSGBorderImage::pixmapChange()
353 {
354     Q_D(QSGBorderImage);
355
356     d->pixmapChanged = true;
357 }
358
359 QT_END_NAMESPACE