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