f203f574730a01f28e62bfb8facc97e5c5c04f6b
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickloader.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickloader_p_p.h"
43
44 #include <QtDeclarative/qdeclarativeinfo.h>
45
46 #include <private/qdeclarativeengine_p.h>
47 #include <private/qdeclarativeglobal_p.h>
48
49 #include <private/qdeclarativecomponent_p.h>
50
51 #include <private/qv8_p.h>
52
53 QT_BEGIN_NAMESPACE
54
55 QQuickLoaderPrivate::QQuickLoaderPrivate()
56     : item(0), component(0), itemContext(0), incubator(0), updatingSize(false),
57       itemWidthValid(false), itemHeightValid(false),
58       active(true), loadingFromSource(false), asynchronous(false)
59 {
60 }
61
62 QQuickLoaderPrivate::~QQuickLoaderPrivate()
63 {
64     delete incubator;
65     disposeInitialPropertyValues();
66 }
67
68 void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
69 {
70     if (resizeItem == item) {
71         if (!updatingSize && newGeometry.width() != oldGeometry.width())
72             itemWidthValid = true;
73         if (!updatingSize && newGeometry.height() != oldGeometry.height())
74             itemHeightValid = true;
75         _q_updateSize(false);
76     }
77     QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
78 }
79
80 void QQuickLoaderPrivate::clear()
81 {
82     disposeInitialPropertyValues();
83
84     if (incubator)
85         incubator->clear();
86
87     if (loadingFromSource && component) {
88         component->deleteLater();
89         component = 0;
90     }
91     source = QUrl();
92
93     if (item) {
94         QQuickItemPrivate *p = QQuickItemPrivate::get(item);
95         p->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
96
97         // We can't delete immediately because our item may have triggered
98         // the Loader to load a different item.
99         item->setParentItem(0);
100         item->setVisible(false);
101         item->deleteLater();
102         item = 0;
103     }
104 }
105
106 void QQuickLoaderPrivate::initResize()
107 {
108     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
109     p->addItemChangeListener(this, QQuickItemPrivate::Geometry);
110     // We may override the item's size, so we need to remember
111     // whether the item provided its own valid size.
112     itemWidthValid = p->widthValid;
113     itemHeightValid = p->heightValid;
114     _q_updateSize();
115 }
116
117 /*!
118     \qmlclass Loader QQuickLoader
119     \inqmlmodule QtQuick 2
120     \ingroup qml-utility-elements
121     \inherits Item
122
123     \brief The Loader item allows dynamically loading an Item-based
124     subtree from a URL or Component.
125
126     Loader is used to dynamically load visual QML components. It can load a
127     QML file (using the \l source property) or a \l Component object (using
128     the \l sourceComponent property). It is useful for delaying the creation
129     of a component until it is required: for example, when a component should
130     be created on demand, or when a component should not be created
131     unnecessarily for performance reasons.
132
133     Here is a Loader that loads "Page1.qml" as a component when the
134     \l MouseArea is clicked:
135
136     \snippet doc/src/snippets/declarative/loader/simple.qml 0
137
138     The loaded item can be accessed using the \l item property.
139
140     If the \l source or \l sourceComponent changes, any previously instantiated
141     items are destroyed. Setting \l source to an empty string or setting
142     \l sourceComponent to \c undefined destroys the currently loaded item,
143     freeing resources and leaving the Loader empty.
144
145     \section2 Loader sizing behavior
146
147     Loader is like any other visual item and must be positioned and sized
148     accordingly to become visible.
149
150     \list
151     \o If an explicit size is not specified for the Loader, the Loader
152     is automatically resized to the size of the loaded item once the
153     component is loaded.
154     \o If the size of the Loader is specified explicitly by setting
155     the width, height or by anchoring, the loaded item will be resized
156     to the size of the Loader.
157     \endlist
158
159     In both scenarios the size of the item and the Loader are identical.
160     This ensures that anchoring to the Loader is equivalent to anchoring
161     to the loaded item.
162
163     \table
164     \row
165     \o sizeloader.qml
166     \o sizeitem.qml
167     \row
168     \o \snippet doc/src/snippets/declarative/loader/sizeloader.qml 0
169     \o \snippet doc/src/snippets/declarative/loader/sizeitem.qml 0
170     \row
171     \o The red rectangle will be sized to the size of the root item.
172     \o The red rectangle will be 50x50, centered in the root item.
173     \endtable
174
175
176     \section2 Receiving signals from loaded items
177
178     Any signals emitted from the loaded item can be received using the
179     \l Connections element. For example, the following \c application.qml
180     loads \c MyItem.qml, and is able to receive the \c message signal from
181     the loaded item through a \l Connections object:
182
183     \table
184     \row
185     \o application.qml
186     \o MyItem.qml
187     \row
188     \o \snippet doc/src/snippets/declarative/loader/connections.qml 0
189     \o \snippet doc/src/snippets/declarative/loader/MyItem.qml 0
190     \endtable
191
192     Alternatively, since \c MyItem.qml is loaded within the scope of the
193     Loader, it could also directly call any function defined in the Loader or
194     its parent \l Item.
195
196
197     \section2 Focus and key events
198
199     Loader is a focus scope. Its \l {Item::}{focus} property must be set to
200     \c true for any of its children to get the \e {active focus}. (See
201     \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page}
202     for more details.) Any key events received in the loaded item should likely
203     also be \l {KeyEvent::}{accepted} so they are not propagated to the Loader.
204
205     For example, the following \c application.qml loads \c KeyReader.qml when
206     the \l MouseArea is clicked.  Notice the \l {Item::}{focus} property is
207     set to \c true for the Loader as well as the \l Item in the dynamically
208     loaded object:
209
210     \table
211     \row
212     \o application.qml
213     \o KeyReader.qml
214     \row
215     \o \snippet doc/src/snippets/declarative/loader/focus.qml 0
216     \o \snippet doc/src/snippets/declarative/loader/KeyReader.qml 0
217     \endtable
218
219     Once \c KeyReader.qml is loaded, it accepts key events and sets
220     \c event.accepted to \c true so that the event is not propagated to the
221     parent \l Rectangle.
222
223     \sa {dynamic-object-creation}{Dynamic Object Creation}
224 */
225
226 QQuickLoader::QQuickLoader(QQuickItem *parent)
227   : QQuickImplicitSizeItem(*(new QQuickLoaderPrivate), parent)
228 {
229     setFlag(ItemIsFocusScope);
230 }
231
232 QQuickLoader::~QQuickLoader()
233 {
234     Q_D(QQuickLoader);
235     if (d->item) {
236         QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
237         p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
238     }
239 }
240
241 /*!
242     \qmlproperty bool QtQuick2::Loader::active
243     This property is \c true if the Loader is currently active.
244     The default value for the \l active property is \c true.
245
246     If the Loader is inactive, changing the \l source or \l sourceComponent
247     will not cause the item to be instantiated until the Loader is made active.
248
249     Setting the value to inactive will cause any \l item loaded by the loader
250     to be released, but will not affect the \l source or \l sourceComponent.
251
252     The \l status of an inactive loader is always \c Null.
253
254     \sa source, sourceComponent
255  */
256 bool QQuickLoader::active() const
257 {
258     Q_D(const QQuickLoader);
259     return d->active;
260 }
261
262 void QQuickLoader::setActive(bool newVal)
263 {
264     Q_D(QQuickLoader);
265     if (d->active != newVal) {
266         d->active = newVal;
267         if (newVal == true) {
268             if (d->loadingFromSource) {
269                 loadFromSource();
270             } else {
271                 loadFromSourceComponent();
272             }
273         } else {
274             if (d->item) {
275                 QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
276                 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
277
278                 // We can't delete immediately because our item may have triggered
279                 // the Loader to load a different item.
280                 d->item->setParentItem(0);
281                 d->item->setVisible(false);
282                 d->item->deleteLater();
283                 d->item = 0;
284                 emit itemChanged();
285             }
286             emit statusChanged();
287         }
288         emit activeChanged();
289     }
290 }
291
292
293 /*!
294     \qmlproperty url QtQuick2::Loader::source
295     This property holds the URL of the QML component to instantiate.
296
297     Note the QML component must be an \l{Item}-based component. The loader
298     cannot load non-visual components.
299
300     To unload the currently loaded item, set this property to an empty string,
301     or set \l sourceComponent to \c undefined. Setting \c source to a
302     new URL will also cause the item created by the previous URL to be unloaded.
303
304     \sa sourceComponent, status, progress
305 */
306 QUrl QQuickLoader::source() const
307 {
308     Q_D(const QQuickLoader);
309     return d->source;
310 }
311
312 void QQuickLoader::setSource(const QUrl &url)
313 {
314     setSource(url, true); // clear previous values
315 }
316
317 void QQuickLoader::setSource(const QUrl &url, bool needsClear)
318 {
319     Q_D(QQuickLoader);
320     if (d->source == url)
321         return;
322
323     if (needsClear)
324         d->clear();
325
326     d->source = url;
327     d->loadingFromSource = true;
328
329     if (d->active)
330         loadFromSource();
331     else
332         emit sourceChanged();
333 }
334
335 void QQuickLoader::loadFromSource()
336 {
337     Q_D(QQuickLoader);
338     if (d->source.isEmpty()) {
339         emit sourceChanged();
340         emit statusChanged();
341         emit progressChanged();
342         emit itemChanged();
343         return;
344     }
345
346     if (isComponentComplete()) {
347         d->component = new QDeclarativeComponent(qmlEngine(this), d->source, this);
348         d->load();
349     }
350 }
351
352 /*!
353     \qmlproperty Component QtQuick2::Loader::sourceComponent
354     This property holds the \l{Component} to instantiate.
355
356     \qml
357     Item {
358         Component {
359             id: redSquare
360             Rectangle { color: "red"; width: 10; height: 10 }
361         }
362
363         Loader { sourceComponent: redSquare }
364         Loader { sourceComponent: redSquare; x: 10 }
365     }
366     \endqml
367
368     To unload the currently loaded item, set this property to an empty string
369     or \c undefined.
370
371     \sa source, progress
372 */
373
374 QDeclarativeComponent *QQuickLoader::sourceComponent() const
375 {
376     Q_D(const QQuickLoader);
377     return d->component;
378 }
379
380 void QQuickLoader::setSourceComponent(QDeclarativeComponent *comp)
381 {
382     Q_D(QQuickLoader);
383     if (comp == d->component)
384         return;
385
386     d->clear();
387
388     d->component = comp;
389     d->loadingFromSource = false;
390
391     if (d->active)
392         loadFromSourceComponent();
393     else
394         emit sourceComponentChanged();
395 }
396
397 void QQuickLoader::resetSourceComponent()
398 {
399     setSourceComponent(0);
400 }
401
402 void QQuickLoader::loadFromSourceComponent()
403 {
404     Q_D(QQuickLoader);
405     if (!d->component) {
406         emit sourceComponentChanged();
407         emit statusChanged();
408         emit progressChanged();
409         emit itemChanged();
410         return;
411     }
412
413     if (isComponentComplete())
414         d->load();
415 }
416
417 /*!
418     \qmlmethod object QtQuick2::Loader::setSource(url source, object properties)
419
420     Creates an object instance of the given \a source component that will have
421     the given \a properties. The \a properties argument is optional.  The instance
422     will be accessible via the \l item property once loading and instantiation
423     is complete.
424
425     If the \l active property is \c false at the time when this function is called,
426     the given \a source component will not be loaded but the \a source and initial
427     \a properties will be cached.  When the loader is made \l active, an instance of
428     the \a source component will be created with the initial \a properties set.
429
430     Setting the initial property values of an instance of a component in this manner
431     will \bold{not} trigger any associated \l{Behavior}s.
432
433     Note that the cached \a properties will be cleared if the \l source or \l sourceComponent
434     is changed after calling this function but prior to setting the loader \l active.
435
436     Example:
437     \table
438     \row
439     \o
440     \qml
441     // ExampleComponent.qml
442     import QtQuick 2.0
443     Rectangle {
444         id: rect
445         color: "red"
446         width: 10
447         height: 10
448
449         Behavior on color {
450             NumberAnimation {
451                 target: rect
452                 property: "width"
453                 to: (rect.width + 20)
454                 duration: 0
455             }
456         }
457     }
458     \endqml
459     \o
460     \qml
461     // example.qml
462     import QtQuick 2.0
463     Item {
464         Loader {
465             id: squareLoader
466             onLoaded: console.log(squareLoader.item.width); // prints [10], not [30]
467         }
468
469         Component.onCompleted: {
470             squareLoader.setSource("ExampleComponent.qml", { "color": "blue" });
471             // will trigger the onLoaded code when complete.
472         }
473     }
474     \endqml
475     \endtable
476
477     \sa source, active
478 */
479 void QQuickLoader::setSource(QDeclarativeV8Function *args)
480 {
481     Q_ASSERT(args);
482     Q_D(QQuickLoader);
483
484     bool ipvError = false;
485     args->returnValue(v8::Undefined());
486     v8::Handle<v8::Object> ipv = d->extractInitialPropertyValues(args, this, &ipvError);
487     if (ipvError)
488         return;
489
490     d->clear();
491     QUrl sourceUrl = d->resolveSourceUrl(args);
492     if (!ipv.IsEmpty()) {
493         d->disposeInitialPropertyValues();
494         d->initialPropertyValues = qPersistentNew(ipv);
495         d->qmlGlobalForIpv = qPersistentNew(args->qmlGlobal());
496     }
497
498     setSource(sourceUrl, false); // already cleared and set ipv above.
499 }
500
501 void QQuickLoaderPrivate::disposeInitialPropertyValues()
502 {
503     if (!initialPropertyValues.IsEmpty())
504         qPersistentDispose(initialPropertyValues);
505     if (!qmlGlobalForIpv.IsEmpty())
506         qPersistentDispose(qmlGlobalForIpv);
507 }
508
509 void QQuickLoaderPrivate::load()
510 {
511     Q_Q(QQuickLoader);
512
513     if (!q->isComponentComplete() || !component)
514         return;
515
516     if (!component->isLoading()) {
517         _q_sourceLoaded();
518     } else {
519         QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
520                 q, SLOT(_q_sourceLoaded()));
521         QObject::connect(component, SIGNAL(progressChanged(qreal)),
522                 q, SIGNAL(progressChanged()));
523         emit q->statusChanged();
524         emit q->progressChanged();
525         if (loadingFromSource)
526             emit q->sourceChanged();
527         else
528             emit q->sourceComponentChanged();
529         emit q->itemChanged();
530     }
531 }
532
533 void QQuickLoaderIncubator::setInitialState(QObject *o)
534 {
535     loader->setInitialState(o);
536 }
537
538 void QQuickLoaderPrivate::setInitialState(QObject *obj)
539 {
540     Q_Q(QQuickLoader);
541
542     QQuickItem *item = qobject_cast<QQuickItem*>(obj);
543     if (item) {
544         QDeclarative_setParent_noEvent(itemContext, obj);
545         QDeclarative_setParent_noEvent(item, q);
546         item->setParentItem(q);
547     }
548
549     if (initialPropertyValues.IsEmpty())
550         return;
551
552     QDeclarativeComponentPrivate *d = QDeclarativeComponentPrivate::get(component);
553     Q_ASSERT(d && d->engine);
554     d->initializeObjectWithInitialProperties(qmlGlobalForIpv, initialPropertyValues, obj);
555 }
556
557 void QQuickLoaderIncubator::statusChanged(Status status)
558 {
559     loader->incubatorStateChanged(status);
560 }
561
562 void QQuickLoaderPrivate::incubatorStateChanged(QDeclarativeIncubator::Status status)
563 {
564     Q_Q(QQuickLoader);
565     if (status == QDeclarativeIncubator::Loading || status == QDeclarativeIncubator::Null)
566         return;
567
568     if (status == QDeclarativeIncubator::Ready) {
569         QObject *obj = incubator->object();
570         item = qobject_cast<QQuickItem*>(obj);
571         if (item) {
572             initResize();
573         } else {
574             qmlInfo(q) << QQuickLoader::tr("Loader does not support loading non-visual elements.");
575             delete itemContext;
576             itemContext = 0;
577             delete obj;
578         }
579         incubator->clear();
580     } else if (status == QDeclarativeIncubator::Error) {
581         if (!incubator->errors().isEmpty())
582             QDeclarativeEnginePrivate::warning(qmlEngine(q), incubator->errors());
583         delete itemContext;
584         itemContext = 0;
585         delete incubator->object();
586         source = QUrl();
587     }
588     if (loadingFromSource)
589         emit q->sourceChanged();
590     else
591         emit q->sourceComponentChanged();
592     emit q->statusChanged();
593     emit q->progressChanged();
594     emit q->itemChanged();
595     emit q->loaded();
596     disposeInitialPropertyValues(); // cleanup
597 }
598
599 void QQuickLoaderPrivate::_q_sourceLoaded()
600 {
601     Q_Q(QQuickLoader);
602     if (!component || !component->errors().isEmpty()) {
603         if (component)
604             QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
605         if (loadingFromSource)
606             emit q->sourceChanged();
607         else
608             emit q->sourceComponentChanged();
609         emit q->statusChanged();
610         emit q->progressChanged();
611         disposeInitialPropertyValues(); // cleanup
612         return;
613     }
614
615     QDeclarativeContext *creationContext = component->creationContext();
616     if (!creationContext) creationContext = qmlContext(q);
617     itemContext = new QDeclarativeContext(creationContext);
618     itemContext->setContextObject(q);
619
620     delete incubator;
621     incubator = new QQuickLoaderIncubator(this, asynchronous ? QDeclarativeIncubator::Asynchronous : QDeclarativeIncubator::AsynchronousIfNested);
622
623     component->create(*incubator, itemContext);
624
625     if (incubator && incubator->status() == QDeclarativeIncubator::Loading)
626         emit q->statusChanged();
627 }
628
629 /*!
630     \qmlproperty enumeration QtQuick2::Loader::status
631
632     This property holds the status of QML loading.  It can be one of:
633     \list
634     \o Loader.Null - the loader is inactive or no QML source has been set
635     \o Loader.Ready - the QML source has been loaded
636     \o Loader.Loading - the QML source is currently being loaded
637     \o Loader.Error - an error occurred while loading the QML source
638     \endlist
639
640     Use this status to provide an update or respond to the status change in some way.
641     For example, you could:
642
643     \list
644     \o Trigger a state change:
645     \qml
646         State { name: 'loaded'; when: loader.status == Loader.Ready }
647     \endqml
648
649     \o Implement an \c onStatusChanged signal handler:
650     \qml
651         Loader {
652             id: loader
653             onStatusChanged: if (loader.status == Loader.Ready) console.log('Loaded')
654         }
655     \endqml
656
657     \o Bind to the status value:
658     \qml
659         Text { text: loader.status == Loader.Ready ? 'Loaded' : 'Not loaded' }
660     \endqml
661     \endlist
662
663     Note that if the source is a local file, the status will initially be Ready (or Error). While
664     there will be no onStatusChanged signal in that case, the onLoaded will still be invoked.
665
666     \sa progress
667 */
668
669 QQuickLoader::Status QQuickLoader::status() const
670 {
671     Q_D(const QQuickLoader);
672
673     if (!d->active)
674         return Null;
675
676     if (d->component) {
677         switch (d->component->status()) {
678         case QDeclarativeComponent::Loading:
679             return Loading;
680         case QDeclarativeComponent::Error:
681             return Error;
682         case QDeclarativeComponent::Null:
683             return Null;
684         default:
685             break;
686         }
687     }
688
689     if (d->incubator) {
690         switch (d->incubator->status()) {
691         case QDeclarativeIncubator::Loading:
692             return Loading;
693         case QDeclarativeIncubator::Error:
694             return Error;
695         default:
696             break;
697         }
698     }
699
700     if (d->item)
701         return Ready;
702
703     return d->source.isEmpty() ? Null : Error;
704 }
705
706 void QQuickLoader::componentComplete()
707 {
708     Q_D(QQuickLoader);
709     QQuickItem::componentComplete();
710     if (active()) {
711         if (d->loadingFromSource) {
712             d->component = new QDeclarativeComponent(qmlEngine(this), d->source, this);
713         }
714         d->load();
715     }
716 }
717
718 /*!
719     \qmlsignal QtQuick2::Loader::onLoaded()
720
721     This handler is called when the \l status becomes \c Loader.Ready, or on successful
722     initial load.
723 */
724
725
726 /*!
727 \qmlproperty real QtQuick2::Loader::progress
728
729 This property holds the progress of loading QML data from the network, from
730 0.0 (nothing loaded) to 1.0 (finished).  Most QML files are quite small, so
731 this value will rapidly change from 0 to 1.
732
733 \sa status
734 */
735 qreal QQuickLoader::progress() const
736 {
737     Q_D(const QQuickLoader);
738
739     if (d->item)
740         return 1.0;
741
742     if (d->component)
743         return d->component->progress();
744
745     return 0.0;
746 }
747
748 /*!
749 \qmlproperty bool QtQuick2::Loader::asynchronous
750
751 This property holds whether the component will be instantiated asynchronously.
752
753 Loading asynchronously creates the objects declared by the component
754 across multiple frames, and reduces the
755 likelihood of glitches in animation.  When loading asynchronously the status
756 will change to Loader.Loading.  Once the entire component has been created, the
757 \l item will be available and the status will change to Loader.Ready.
758
759 To avoid seeing the items loading progressively set \c visible appropriately, e.g.
760
761 \code
762 Loader {
763     source: "mycomponent.qml"
764     asynchronous: true
765     visible: status == Loader.Ready
766 }
767 \endcode
768
769 Note that this property affects object instantiation only; it is unrelated to
770 loading a component asynchronously via a network.
771 */
772 bool QQuickLoader::asynchronous() const
773 {
774     Q_D(const QQuickLoader);
775     return d->asynchronous;
776 }
777
778 void QQuickLoader::setAsynchronous(bool a)
779 {
780     Q_D(QQuickLoader);
781     if (d->asynchronous == a)
782         return;
783
784     d->asynchronous = a;
785     emit asynchronousChanged();
786 }
787
788 void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
789 {
790     Q_Q(QQuickLoader);
791     if (!item || updatingSize)
792         return;
793
794     updatingSize = true;
795
796     qreal iWidth = !itemWidthValid ? item->implicitWidth() : item->width();
797     qreal iHeight = !itemHeightValid ? item->implicitHeight() : item->height();
798     q->setImplicitSize(iWidth, iHeight);
799
800     if (loaderGeometryChanged && q->widthValid())
801         item->setWidth(q->width());
802     if (loaderGeometryChanged && q->heightValid())
803         item->setHeight(q->height());
804
805     updatingSize = false;
806 }
807
808 /*!
809     \qmlproperty Item QtQuick2::Loader::item
810     This property holds the top-level item that is currently loaded.
811 */
812 QQuickItem *QQuickLoader::item() const
813 {
814     Q_D(const QQuickLoader);
815     return d->item;
816 }
817
818 void QQuickLoader::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
819 {
820     Q_D(QQuickLoader);
821     if (newGeometry != oldGeometry) {
822         d->_q_updateSize();
823     }
824     QQuickItem::geometryChanged(newGeometry, oldGeometry);
825 }
826
827 QUrl QQuickLoaderPrivate::resolveSourceUrl(QDeclarativeV8Function *args)
828 {
829     QV8Engine *v8engine = args->engine();
830     QString arg = v8engine->toString((*args)[0]->ToString());
831     if (arg.isEmpty())
832         return QUrl();
833
834     QDeclarativeContextData *context = args->context();
835     Q_ASSERT(context);
836     return context->resolvedUrl(QUrl(arg));
837 }
838
839 v8::Handle<v8::Object> QQuickLoaderPrivate::extractInitialPropertyValues(QDeclarativeV8Function *args, QObject *loader, bool *error)
840 {
841     v8::Local<v8::Object> valuemap;
842     if (args->Length() >= 2) {
843         v8::Local<v8::Value> v = (*args)[1];
844         if (!v->IsObject() || v->IsArray()) {
845             *error = true;
846             qmlInfo(loader) << loader->tr("setSource: value is not an object");
847         } else {
848             *error = false;
849             valuemap = v8::Local<v8::Object>::Cast(v);
850         }
851     }
852
853     return valuemap;
854 }
855
856 #include <moc_qquickloader_p.cpp>
857
858 QT_END_NAMESPACE