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