Initial import from qtquick2.
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgloader.cpp
1 // Commit: 501180c6fbed0857126da2bb0ff1f17ee35472c6
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 "qsgloader_p_p.h"
44
45 #include <QtDeclarative/qdeclarativeinfo.h>
46
47 #include <private/qdeclarativeengine_p.h>
48 #include <private/qdeclarativeglobal_p.h>
49
50 QT_BEGIN_NAMESPACE
51
52 QSGLoaderPrivate::QSGLoaderPrivate()
53     : item(0), component(0), ownComponent(false), updatingSize(false),
54       itemWidthValid(false), itemHeightValid(false)
55 {
56 }
57
58 QSGLoaderPrivate::~QSGLoaderPrivate()
59 {
60 }
61
62 void QSGLoaderPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
63 {
64     if (resizeItem == item) {
65         if (!updatingSize && newGeometry.width() != oldGeometry.width())
66             itemWidthValid = true;
67         if (!updatingSize && newGeometry.height() != oldGeometry.height())
68             itemHeightValid = true;
69         _q_updateSize(false);
70     }
71     QSGItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
72 }
73
74 void QSGLoaderPrivate::clear()
75 {
76     if (ownComponent) {
77         component->deleteLater();
78         component = 0;
79         ownComponent = false;
80     }
81     source = QUrl();
82
83     if (item) {
84         QSGItemPrivate *p = QSGItemPrivate::get(item);
85         p->removeItemChangeListener(this, QSGItemPrivate::Geometry);
86
87         // We can't delete immediately because our item may have triggered
88         // the Loader to load a different item.
89         item->setParentItem(0);
90         item->setVisible(false);
91         item->deleteLater();
92         item = 0;
93     }
94 }
95
96 void QSGLoaderPrivate::initResize()
97 {
98     QSGItemPrivate *p = QSGItemPrivate::get(item);
99     p->addItemChangeListener(this, QSGItemPrivate::Geometry);
100     // We may override the item's size, so we need to remember
101     // whether the item provided its own valid size.
102     itemWidthValid = p->widthValid;
103     itemHeightValid = p->heightValid;
104     _q_updateSize();
105 }
106
107 QSGLoader::QSGLoader(QSGItem *parent)
108   : QSGImplicitSizeItem(*(new QSGLoaderPrivate), parent)
109 {
110     setFlag(ItemIsFocusScope);
111 }
112
113 QSGLoader::~QSGLoader()
114 {
115     Q_D(QSGLoader);
116     if (d->item) {
117         QSGItemPrivate *p = QSGItemPrivate::get(d->item);
118         p->removeItemChangeListener(d, QSGItemPrivate::Geometry);
119     }
120 }
121
122 QUrl QSGLoader::source() const
123 {
124     Q_D(const QSGLoader);
125     return d->source;
126 }
127
128 void QSGLoader::setSource(const QUrl &url)
129 {
130     Q_D(QSGLoader);
131     if (d->source == url)
132         return;
133
134     d->clear();
135
136     d->source = url;
137     if (d->source.isEmpty()) {
138         emit sourceChanged();
139         emit statusChanged();
140         emit progressChanged();
141         emit itemChanged();
142         return;
143     }
144
145     d->component = new QDeclarativeComponent(qmlEngine(this), d->source, this);
146     d->ownComponent = true;
147
148     if (isComponentComplete())
149         d->load();
150 }
151
152 QDeclarativeComponent *QSGLoader::sourceComponent() const
153 {
154     Q_D(const QSGLoader);
155     return d->component;
156 }
157
158 void QSGLoader::setSourceComponent(QDeclarativeComponent *comp)
159 {
160     Q_D(QSGLoader);
161     if (comp == d->component)
162         return;
163
164     d->clear();
165
166     d->component = comp;
167     d->ownComponent = false;
168     if (!d->component) {
169         emit sourceChanged();
170         emit statusChanged();
171         emit progressChanged();
172         emit itemChanged();
173         return;
174     }
175
176     if (isComponentComplete())
177         d->load();
178 }
179
180 void QSGLoader::resetSourceComponent()
181 {
182     setSourceComponent(0);
183 }
184
185 void QSGLoaderPrivate::load()
186 {
187     Q_Q(QSGLoader);
188
189     if (!q->isComponentComplete() || !component)
190         return;
191
192     if (!component->isLoading()) {
193         _q_sourceLoaded();
194     } else {
195         QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
196                 q, SLOT(_q_sourceLoaded()));
197         QObject::connect(component, SIGNAL(progressChanged(qreal)),
198                 q, SIGNAL(progressChanged()));
199         emit q->statusChanged();
200         emit q->progressChanged();
201         emit q->sourceChanged();
202         emit q->itemChanged();
203     }
204 }
205
206 void QSGLoaderPrivate::_q_sourceLoaded()
207 {
208     Q_Q(QSGLoader);
209
210     if (component) {
211         if (!component->errors().isEmpty()) {
212             QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
213             emit q->sourceChanged();
214             emit q->statusChanged();
215             emit q->progressChanged();
216             return;
217         }
218
219         QDeclarativeContext *creationContext = component->creationContext();
220         if (!creationContext) creationContext = qmlContext(q);
221         QDeclarativeContext *ctxt = new QDeclarativeContext(creationContext);
222         ctxt->setContextObject(q);
223
224         QDeclarativeGuard<QDeclarativeComponent> c = component;
225         QObject *obj = component->beginCreate(ctxt);
226         if (component != c) {
227             // component->create could trigger a change in source that causes
228             // component to be set to something else. In that case we just
229             // need to cleanup.
230             if (c)
231                 c->completeCreate();
232             delete obj;
233             delete ctxt;
234             return;
235         }
236         if (obj) {
237             item = qobject_cast<QSGItem *>(obj);
238             if (item) {
239                 QDeclarative_setParent_noEvent(ctxt, obj);
240                 QDeclarative_setParent_noEvent(item, q);
241                 item->setParentItem(q);
242 //                item->setFocus(true);
243                 initResize();
244             } else {
245                 qmlInfo(q) << QSGLoader::tr("Loader does not support loading non-visual elements.");
246                 delete obj;
247                 delete ctxt;
248             }
249         } else {
250             if (!component->errors().isEmpty())
251                 QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
252             delete obj;
253             delete ctxt;
254             source = QUrl();
255         }
256         component->completeCreate();
257         emit q->sourceChanged();
258         emit q->statusChanged();
259         emit q->progressChanged();
260         emit q->itemChanged();
261         emit q->loaded();
262     }
263 }
264
265 QSGLoader::Status QSGLoader::status() const
266 {
267     Q_D(const QSGLoader);
268
269     if (d->component)
270         return static_cast<QSGLoader::Status>(d->component->status());
271
272     if (d->item)
273         return Ready;
274
275     return d->source.isEmpty() ? Null : Error;
276 }
277
278 void QSGLoader::componentComplete()
279 {
280     Q_D(QSGLoader);
281     QSGItem::componentComplete();
282     d->load();
283 }
284
285 qreal QSGLoader::progress() const
286 {
287     Q_D(const QSGLoader);
288
289     if (d->item)
290         return 1.0;
291
292     if (d->component)
293         return d->component->progress();
294
295     return 0.0;
296 }
297
298 void QSGLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
299 {
300     Q_Q(QSGLoader);
301     if (!item || updatingSize)
302         return;
303
304     updatingSize = true;
305
306     if (!itemWidthValid)
307         q->setImplicitWidth(item->implicitWidth());
308     else
309         q->setImplicitWidth(item->width());
310     if (loaderGeometryChanged && q->widthValid())
311         item->setWidth(q->width());
312
313     if (!itemHeightValid)
314         q->setImplicitHeight(item->implicitHeight());
315     else
316         q->setImplicitHeight(item->height());
317     if (loaderGeometryChanged && q->heightValid())
318         item->setHeight(q->height());
319
320     updatingSize = false;
321 }
322
323 QSGItem *QSGLoader::item() const
324 {
325     Q_D(const QSGLoader);
326     return d->item;
327 }
328
329 void QSGLoader::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
330 {
331     Q_D(QSGLoader);
332     if (newGeometry != oldGeometry) {
333         d->_q_updateSize();
334     }
335     QSGItem::geometryChanged(newGeometry, oldGeometry);
336 }
337
338 #include <moc_qsgloader_p.cpp>
339
340 QT_END_NAMESPACE