Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickloader.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtQml/qqmlinfo.h>
8#include <QtQml/qqmlcomponent.h>
9
10#include <private/qqmlengine_p.h>
11#include <private/qqmlglobal_p.h>
12
13#include <private/qqmlcomponent_p.h>
14#include <private/qqmlincubator_p.h>
15
17
19 = QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
20
21QQuickLoaderPrivate::QQuickLoaderPrivate()
22 : item(nullptr), object(nullptr), itemContext(nullptr), incubator(nullptr), updatingSize(false),
23 active(true), loadingFromSource(false), asynchronous(false), status(computeStatus())
24{
25}
26
34
36 const QRectF &oldGeometry)
37{
38 if (resizeItem == item)
39 _q_updateSize(false);
40 QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry);
41}
42
44{
45 Q_Q(QQuickLoader);
46 q->setImplicitWidth(getImplicitWidth());
47}
48
50{
51 Q_Q(QQuickLoader);
52 q->setImplicitHeight(getImplicitHeight());
53}
54
56{
57 Q_Q(QQuickLoader);
59
60 if (incubator)
61 incubator->clear();
62
63 delete itemContext;
64 itemContext = nullptr;
65
66 // Prevent any bindings from running while waiting for deletion. Without
67 // this we may get transient errors from use of 'parent', for example.
68 QQmlContext *context = qmlContext(object);
69 if (context)
70 QQmlContextData::get(context)->clearContextRecursively();
71
72 if (loadingFromSource && component) {
73 // disconnect since we deleteLater
74 QObject::disconnect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
75 q, SLOT(_q_sourceLoaded()));
76 QObject::disconnect(component, SIGNAL(progressChanged(qreal)),
77 q, SIGNAL(progressChanged()));
78 component->deleteLater();
79 component.setObject(nullptr, q);
80 } else if (component) {
81 component.setObject(nullptr, q);
82 }
83 source = QUrl();
84
85 if (item) {
86 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
87 p->removeItemChangeListener(this, watchedChanges);
88
89 // We can't delete immediately because our item may have triggered
90 // the Loader to load a different item.
91 item->setParentItem(nullptr);
92 item->setVisible(false);
93 item = nullptr;
94 }
95 if (object) {
96 object->deleteLater();
97 object = nullptr;
98 }
99}
100
102{
103 if (!item)
104 return;
105 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
106 p->addItemChangeListener(this, watchedChanges);
108}
109
111{
112 Q_Q(const QQuickLoader);
113 // If the Loader has a valid width then Loader has set an explicit width on the
114 // item, and we want the item's implicitWidth. If the Loader's width has
115 // not been set then its implicitWidth is the width of the item.
116 if (item)
117 return q->widthValid() ? item->implicitWidth() : item->width();
118 return QQuickImplicitSizeItemPrivate::getImplicitWidth();
119}
120
122{
123 Q_Q(const QQuickLoader);
124 // If the Loader has a valid height then Loader has set an explicit height on the
125 // item, and we want the item's implicitHeight. If the Loader's height has
126 // not been set then its implicitHeight is the height of the item.
127 if (item)
128 return q->heightValid() ? item->implicitHeight() : item->height();
129 return QQuickImplicitSizeItemPrivate::getImplicitHeight();
130}
131
132/*!
133 \qmltype Loader
134 \nativetype QQuickLoader
135 \inqmlmodule QtQuick
136 \ingroup qtquick-dynamic
137 \inherits Item
138
139 \brief Allows dynamic loading of a subtree from a URL or Component.
140
141 Loader is used to dynamically load QML components.
142
143 Loader can load a
144 QML file (using the \l source property) or a \l Component object (using
145 the \l sourceComponent property). It is useful for delaying the creation
146 of a component until it is required: for example, when a component should
147 be created on demand, or when a component should not be created
148 unnecessarily for performance reasons.
149
150 Here is a Loader that loads "Page1.qml" as a component when the
151 \l MouseArea is clicked:
152
153 \snippet qml/loader/simple.qml 0
154
155 The loaded object can be accessed using the \l item property.
156
157 If the \l source or \l sourceComponent changes, any previously instantiated
158 items are destroyed. Setting \l source to an empty string or setting
159 \l sourceComponent to \c undefined destroys the currently loaded object,
160 freeing resources and leaving the Loader empty.
161
162 \section2 Loader Sizing Behavior
163
164 When used to load visual types, Loader applies the following sizing rules:
165
166 \list
167 \li If an explicit size is not specified for the Loader, the Loader
168 is automatically resized to the size of the loaded item once the
169 component is loaded.
170 \li If the size of the Loader is specified explicitly by setting
171 the width, height or by anchoring, the loaded item will be resized
172 to the size of the Loader.
173 \endlist
174
175 In both scenarios the size of the item and the Loader are identical.
176 This ensures that anchoring to the Loader is equivalent to anchoring
177 to the loaded item.
178
179 \table
180 \row
181 \li sizeloader.qml
182 \li sizeitem.qml
183 \row
184 \li \snippet qml/loader/sizeloader.qml 0
185 \li \snippet qml/loader/sizeitem.qml 0
186 \row
187 \li The red rectangle will be sized to the size of the root item.
188 \li The red rectangle will be 50x50, centered in the root item.
189 \endtable
190
191 If the source component is not an Item type, Loader does not apply any
192 special sizing rules.
193
194 \section2 Receiving Signals from Loaded Objects
195
196 Any signals emitted from the loaded object can be received using the
197 \l Connections type. For example, the following \c application.qml
198 loads \c MyItem.qml, and is able to receive the \c message signal from
199 the loaded item through a \l Connections object:
200
201 \table 70%
202 \row
203 \li application.qml
204 \li MyItem.qml
205 \row
206 \li \snippet qml/loader/connections.qml 0
207 \li \snippet qml/loader/MyItem.qml 0
208 \endtable
209
210 \section2 Focus and Key Events
211
212 Loader is a focus scope. Its \l {Item::}{focus} property must be set to
213 \c true for any of its children to get the \e {active focus}. (See
214 \l{Keyboard Focus in Qt Quick}
215 for more details.) Any key events received in the loaded item should likely
216 also be \l {KeyEvent::}{accepted} so they are not propagated to the Loader.
217
218 For example, the following \c application.qml loads \c KeyReader.qml when
219 the \l MouseArea is clicked. Notice the \l {Item::}{focus} property is
220 set to \c true for the Loader as well as the \l Item in the dynamically
221 loaded object:
222
223 \table
224 \row
225 \li application.qml
226 \li KeyReader.qml
227 \row
228 \li \snippet qml/loader/focus.qml 0
229 \li \snippet qml/loader/KeyReader.qml 0
230 \endtable
231
232 Once \c KeyReader.qml is loaded, it accepts key events and sets
233 \c event.accepted to \c true so that the event is not propagated to the
234 parent \l Rectangle.
235
236 Since \c {QtQuick 2.0}, Loader can also load non-visual components.
237
238 \section2 Using a Loader within a View Delegate
239
240 In some cases you may wish to use a Loader within a view delegate to improve delegate
241 loading performance. This works well in most cases, but there is one important issue to
242 be aware of related to the \l{QtQml::Component#Creation Context}{creation context} of a Component.
243
244 In the following example, the \c index context property inserted by the ListView into \c delegateComponent's
245 context will be inaccessible to Text, as the Loader will use the creation context of \c myComponent as the parent
246 context when instantiating it, and \c index does not refer to anything within that context chain.
247
248 \snippet qml/loader/creationContext1.qml 0
249
250 In this situation we can either move the component inline,
251
252 \snippet qml/loader/creationContext2.qml 0
253
254 into a separate file,
255
256 \snippet qml/loader/creationContext3.qml 0
257
258 or explicitly set the required information as a property of the Loader (this works because the
259 Loader sets itself as the context object for the component it is loading).
260
261 \snippet qml/loader/creationContext4.qml 0
262
263 \sa {dynamic-object-creation}{Dynamic Object Creation}
264*/
265
266QQuickLoader::QQuickLoader(QQuickItem *parent)
267 : QQuickImplicitSizeItem(*(new QQuickLoaderPrivate), parent)
268{
269 setFlag(ItemIsFocusScope);
270}
271
272QQuickLoader::~QQuickLoader()
273{
274 Q_D(QQuickLoader);
275 d->clear();
276}
277
278/*!
279 \qmlproperty bool QtQuick::Loader::active
280 This property is \c true if the Loader is currently active.
281 The default value for this property is \c true.
282
283 If the Loader is inactive, changing the \l source or \l sourceComponent
284 will not cause the item to be instantiated until the Loader is made active.
285
286 Setting the value to inactive will cause any \l item loaded by the loader
287 to be released, but will not affect the \l source or \l sourceComponent.
288
289 The \l status of an inactive loader is always \c Null.
290
291 \sa source, sourceComponent
292 */
293bool QQuickLoader::active() const
294{
295 Q_D(const QQuickLoader);
296 return d->active;
297}
298
299void QQuickLoader::setActive(bool newVal)
300{
301 Q_D(QQuickLoader);
302 if (d->active == newVal)
303 return;
304
305 d->active = newVal;
306 if (newVal == true) {
307 if (d->loadingFromSource) {
308 loadFromSource();
309 } else {
310 loadFromSourceComponent();
311 }
312 } else {
313 // cancel any current incubation
314 if (d->incubator) {
315 d->incubator->clear();
316 delete d->itemContext;
317 d->itemContext = nullptr;
318 }
319
320 // Prevent any bindings from running while waiting for deletion. Without
321 // this we may get transient errors from use of 'parent', for example.
322 QQmlContext *context = qmlContext(d->object);
323 if (context)
324 QQmlContextData::get(context)->clearContextRecursively();
325
326 if (d->item) {
327 QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
328 p->removeItemChangeListener(d, watchedChanges);
329
330 // We can't delete immediately because our item may have triggered
331 // the Loader to load a different item.
332 d->item->setParentItem(nullptr);
333 d->item->setVisible(false);
334 d->item = nullptr;
335 }
336 if (d->object) {
337 d->object->deleteLater();
338 d->object = nullptr;
339 emit itemChanged();
340 }
341 d->updateStatus();
342 }
343 emit activeChanged();
344}
345
346
347/*!
348 \qmlproperty url QtQuick::Loader::source
349 This property holds the URL of the QML component to instantiate.
350
351 Since \c {QtQuick 2.0}, Loader is able to load any type of object; it
352 is not restricted to Item types.
353
354 To unload the currently loaded object, set this property to an empty string,
355 or set \l sourceComponent to \c undefined. Setting \c source to a
356 new URL will also cause the item created by the previous URL to be unloaded.
357
358 \sa sourceComponent, status, progress
359*/
360QUrl QQuickLoader::source() const
361{
362 Q_D(const QQuickLoader);
363 return d->source;
364}
365
366void QQuickLoader::setSourceWithoutResolve(const QUrl &url)
367{
368 setSource(url, true); // clear previous values
369}
370
371void QQuickLoader::setSource(const QUrl &url, bool needsClear)
372{
373 Q_D(QQuickLoader);
374 if (d->source == url)
375 return;
376
377 if (needsClear)
378 d->clear();
379
380 d->source = url;
381 d->loadingFromSource = true;
382
383 if (d->active)
384 loadFromSource();
385 else
386 emit sourceChanged();
387}
388
389void QQuickLoader::loadFromSource()
390{
391 Q_D(QQuickLoader);
392 if (d->source.isEmpty()) {
393 emit sourceChanged();
394 d->updateStatus();
395 emit progressChanged();
396 emit itemChanged();
397 return;
398 }
399
400 if (isComponentComplete()) {
401 if (!d->component)
402 d->createComponent();
403 d->load();
404 }
405}
406
407/*!
408 \qmlproperty Component QtQuick::Loader::sourceComponent
409 This property holds the \l{Component} to instantiate.
410
411 \qml
412 Item {
413 Component {
414 id: redSquare
415 Rectangle { color: "red"; width: 10; height: 10 }
416 }
417
418 Loader { sourceComponent: redSquare }
419 Loader { sourceComponent: redSquare; x: 10 }
420 }
421 \endqml
422
423 To unload the currently loaded object, set this property to \c undefined.
424
425 Since \c {QtQuick 2.0}, Loader is able to load any type of object; it
426 is not restricted to Item types.
427
428 \sa source, progress
429*/
430
431QQmlComponent *QQuickLoader::sourceComponent() const
432{
433 Q_D(const QQuickLoader);
434 return d->component;
435}
436
437void QQuickLoader::setSourceComponent(QQmlComponent *comp)
438{
439 Q_D(QQuickLoader);
440 if (comp == d->component)
441 return;
442
443 d->clear();
444
445 d->component.setObject(comp, this);
446 d->loadingFromSource = false;
447
448 if (d->active)
449 loadFromSourceComponent();
450 else
451 emit sourceComponentChanged();
452}
453
454void QQuickLoader::resetSourceComponent()
455{
456 setSourceComponent(nullptr);
457}
458
459void QQuickLoader::loadFromSourceComponent()
460{
461 Q_D(QQuickLoader);
462 if (!d->component) {
463 emit sourceComponentChanged();
464 d->updateStatus();
465 emit progressChanged();
466 emit itemChanged();
467 return;
468 }
469
470 if (isComponentComplete())
471 d->load();
472}
473
474
475QUrl QQuickLoader::setSourceUrlHelper(const QUrl &unresolvedUrl)
476{
477 Q_D(QQuickLoader);
478
479 // 1. If setSource is called with a valid url, clear the old component and its corresponding url
480 // 2. If setSource is called with an invalid url(e.g. empty url), clear the old component but
481 // hold the url for old one.(we will compare it with new url later and may update status of loader to Loader.Null)
482 QUrl oldUrl = d->source;
483 d->clear();
484 QUrl sourceUrl = qmlEngine(this)->handle()->callingQmlContext()->resolvedUrl(unresolvedUrl);
485 if (!sourceUrl.isValid())
486 d->source = oldUrl;
487 return sourceUrl;
488}
489
490/*!
491 \qmlmethod object QtQuick::Loader::setSource(url source, object properties)
492
493 Creates an object instance of the given \a source component that will have
494 the given \a properties. The \a properties argument is optional. The instance
495 will be accessible via the \l item property once loading and instantiation
496 is complete.
497
498 If the \l active property is \c false at the time when this function is called,
499 the given \a source component will not be loaded but the \a source and initial
500 \a properties will be cached. When the loader is made \l active, an instance of
501 the \a source component will be created with the initial \a properties set.
502
503 Setting the initial property values of an instance of a component in this manner
504 will \b{not} trigger any associated \l{Behavior}s.
505
506 Note that the cached \a properties will be cleared if the \l source or \l sourceComponent
507 is changed after calling this function but prior to setting the loader \l active.
508
509 Example:
510 \table 70%
511 \row
512 \li
513 \qml
514 // ExampleComponent.qml
515 import QtQuick 2.0
516 Rectangle {
517 id: rect
518 color: "red"
519 width: 10
520 height: 10
521
522 Behavior on color {
523 NumberAnimation {
524 target: rect
525 property: "width"
526 to: (rect.width + 20)
527 duration: 0
528 }
529 }
530 }
531 \endqml
532 \li
533 \qml
534 // example.qml
535 import QtQuick 2.0
536 Item {
537 Loader {
538 id: squareLoader
539 onLoaded: console.log(squareLoader.item.width);
540 // prints [10], not [30]
541 }
542
543 Component.onCompleted: {
544 squareLoader.setSource("ExampleComponent.qml",
545 { "color": "blue" });
546 // will trigger the onLoaded code when complete.
547 }
548 }
549 \endqml
550 \endtable
551
552 \sa source, active
553*/
554void QQuickLoader::setSource(const QUrl &source, QJSValue properties)
555{
556 Q_D(QQuickLoader);
557
558 if (!(properties.isArray() || properties.isObject())) {
559 qmlWarning(this) << QQuickLoader::tr("setSource: value is not an object");
560 return;
561 }
562
563 QUrl sourceUrl = setSourceUrlHelper(source);
564
565 d->disposeInitialPropertyValues();
566 auto engine = qmlEngine(this)->handle();
567 d->initialPropertyValues.set(engine, QJSValuePrivate::takeManagedValue(&properties)->asReturnedValue());
568 d->qmlCallingContext.set(engine, engine->qmlContext());
569
570 setSource(sourceUrl, false); // already cleared and set ipv above.
571}
572
573void QQuickLoader::setSource(const QUrl &source)
574{
575 Q_D(QQuickLoader);
576
577 QUrl sourceUrl = setSourceUrlHelper(source);
578
579 d->disposeInitialPropertyValues();
580 auto engine = qmlEngine(this)->handle();
581 d->qmlCallingContext.set(engine, engine->qmlContext());
582
583 setSource(sourceUrl, false); // already cleared and set ipv above.
584}
585
587{
588 initialPropertyValues.clear();
589}
590
592{
593 Q_Q(QQuickLoader);
594
595 if (!q->isComponentComplete() || !component)
596 return;
597
598 if (!component->isLoading()) {
600 } else {
601 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
602 q, SLOT(_q_sourceLoaded()));
603 QObject::connect(component, SIGNAL(progressChanged(qreal)),
604 q, SIGNAL(progressChanged()));
606 emit q->progressChanged();
608 emit q->sourceChanged();
609 else
610 emit q->sourceComponentChanged();
611 emit q->itemChanged();
612 }
613}
614
616{
617 loader->setInitialState(o);
618}
619
621{
622 Q_Q(QQuickLoader);
623
624 QQuickItem *item = qmlobject_cast<QQuickItem*>(obj);
625 if (item) {
626 // If the item doesn't have an explicit size, but the Loader
627 // does, then set the item's size now before bindings are
628 // evaluated, otherwise we will end up resizing the item
629 // later and triggering any affected bindings/anchors.
630 if (widthValid() && !QQuickItemPrivate::get(item)->widthValid())
631 item->setWidth(q->width());
632 if (heightValid() && !QQuickItemPrivate::get(item)->heightValid())
633 item->setHeight(q->height());
634 item->setParentItem(q);
635 }
636 if (obj) {
637 if (itemContext)
638 QQml_setParent_noEvent(itemContext, obj);
639 QQml_setParent_noEvent(obj, q);
640 itemContext = nullptr;
641 }
642
643 if (initialPropertyValues.isUndefined())
644 return;
645
646 QQmlComponentPrivate *d = QQmlComponentPrivate::get(component);
647 Q_ASSERT(d && d->engine());
648 QV4::ExecutionEngine *v4 = d->engine()->handle();
649 Q_ASSERT(v4);
650 QV4::Scope scope(v4);
651 QV4::ScopedValue ipv(scope, initialPropertyValues.value());
652 QV4::Scoped<QV4::QmlContext> qmlContext(scope, qmlCallingContext.value());
653 auto incubatorPriv = QQmlIncubatorPrivate::get(incubator);
654 d->initializeObjectWithInitialProperties(qmlContext, ipv, obj, incubatorPriv->requiredProperties());
655}
656
658{
659 loader->incubatorStateChanged(status);
660}
661
662void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status)
663{
664 Q_Q(QQuickLoader);
665 if (status == QQmlIncubator::Loading || status == QQmlIncubator::Null)
666 return;
667
668 if (status == QQmlIncubator::Ready) {
669 object = incubator->object();
670 item = qmlobject_cast<QQuickItem*>(object);
671 emit q->itemChanged();
672 initResize();
673 incubator->clear();
674 } else if (status == QQmlIncubator::Error) {
675 if (!incubator->errors().isEmpty())
676 QQmlEnginePrivate::warning(qmlEngine(q), incubator->errors());
677 delete itemContext;
678 itemContext = nullptr;
679 delete incubator->object();
680 source = QUrl();
681 emit q->itemChanged();
682 }
683 if (loadingFromSource)
684 emit q->sourceChanged();
685 else
686 emit q->sourceComponentChanged();
687 updateStatus();
688 emit q->progressChanged();
689 if (status == QQmlIncubator::Ready)
690 emit q->loaded();
691}
692
694{
695 Q_Q(QQuickLoader);
696 if (!component || !component->errors().isEmpty()) {
697 if (component)
698 QQmlEnginePrivate::warning(qmlEngine(q), component->errors());
700 emit q->sourceChanged();
701 else
702 emit q->sourceComponentChanged();
704 emit q->progressChanged();
705 emit q->itemChanged(); //Like clearing source, emit itemChanged even if previous item was also null
707 return;
708 }
709
710 if (!active)
711 return;
712
713 QQmlContext *creationContext = component->creationContext();
714 if (!creationContext)
715 creationContext = qmlContext(q);
716
717 QQmlComponentPrivate *cp = QQmlComponentPrivate::get(component);
718 QQmlContext *context = [&](){
719 if (cp->isBound())
720 return creationContext;
721 itemContext = new QQmlContext(creationContext);
722 itemContext->setContextObject(q);
723 return itemContext;
724 }();
725
726 delete incubator;
727 incubator = new QQuickLoaderIncubator(this, asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
728
729 component->create(*incubator, context);
730
731 if (incubator && incubator->status() == QQmlIncubator::Loading)
733}
734
735/*!
736 \qmlproperty enumeration QtQuick::Loader::status
737
738 This property holds the status of QML loading. It can be one of:
739 \list
740 \li Loader.Null - the loader is inactive or no QML source has been set
741 \li Loader.Ready - the QML source has been loaded
742 \li Loader.Loading - the QML source is currently being loaded
743 \li Loader.Error - an error occurred while loading the QML source
744 \endlist
745
746 Use this status to provide an update or respond to the status change in some way.
747 For example, you could:
748
749 \list
750 \li Trigger a state change:
751 \qml
752 State { name: 'loaded'; when: loader.status == Loader.Ready }
753 \endqml
754
755 \li Implement an \c onStatusChanged signal handler:
756 \qml
757 Loader {
758 id: loader
759 onStatusChanged: if (loader.status == Loader.Ready) console.log('Loaded')
760 }
761 \endqml
762
763 \li Bind to the status value:
764 \qml
765 Text { text: loader.status == Loader.Ready ? 'Loaded' : 'Not loaded' }
766 \endqml
767 \endlist
768
769 Note that if the source is a local file, the status will initially be Ready (or Error). While
770 there will be no onStatusChanged signal in that case, the onLoaded will still be invoked.
771
772 \sa progress
773*/
774
775QQuickLoader::Status QQuickLoader::status() const
776{
777 Q_D(const QQuickLoader);
778
779 return static_cast<Status>(d->status);
780}
781
782void QQuickLoader::componentComplete()
783{
784 Q_D(QQuickLoader);
785 QQuickItem::componentComplete();
786 if (active() && (status() != Ready)) {
787 if (d->loadingFromSource)
788 d->createComponent();
789 d->load();
790 }
791}
792
793void QQuickLoader::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
794{
795 switch (change) {
796 case ItemChildAddedChange:
797 Q_ASSERT(value.item);
798 if (value.item->flags().testFlag(QQuickItem::ItemObservesViewport))
799 // Re-trigger the parent traversal to get subtreeTransformChangedEnabled turned on
800 value.item->setFlag(QQuickItem::ItemObservesViewport);
801 break;
802 default:
803 break;
804 }
805 QQuickItem::itemChange(change, value);
806}
807
808/*!
809 \qmlsignal QtQuick::Loader::loaded()
810
811 This signal is emitted when the \l status becomes \c Loader.Ready, or on successful
812 initial load.
813*/
814
815
816/*!
817\qmlproperty real QtQuick::Loader::progress
818
819This property holds the progress of loading QML data from the network, from
8200.0 (nothing loaded) to 1.0 (finished). Most QML files are quite small, so
821this value will rapidly change from 0 to 1.
822
823\sa status
824*/
825qreal QQuickLoader::progress() const
826{
827 Q_D(const QQuickLoader);
828
829 if (d->object)
830 return 1.0;
831
832 if (d->component)
833 return d->component->progress();
834
835 return 0.0;
836}
837
838/*!
839\qmlproperty bool QtQuick::Loader::asynchronous
840
841This property holds whether the component will be instantiated asynchronously.
842By default it is \c false.
843
844When used in conjunction with the \l source property, loading and compilation
845will also be performed in a background thread.
846
847Loading asynchronously creates the objects declared by the component
848across multiple frames, and reduces the
849likelihood of glitches in animation. When loading asynchronously the status
850will change to Loader.Loading. Once the entire component has been created, the
851\l item will be available and the status will change to Loader.Ready.
852
853Changing the value of this property to \c false while an asynchronous load is in
854progress will force immediate, synchronous completion. This allows beginning an
855asynchronous load and then forcing completion if the Loader content must be
856accessed before the asynchronous load has completed.
857
858To avoid seeing the items loading progressively set \c visible appropriately, e.g.
859
860\code
861Loader {
862 source: "mycomponent.qml"
863 asynchronous: true
864 visible: status == Loader.Ready
865}
866\endcode
867
868Note that this property affects object instantiation only; it is unrelated to
869loading a component asynchronously via a network.
870*/
871bool QQuickLoader::asynchronous() const
872{
873 Q_D(const QQuickLoader);
874 return d->asynchronous;
875}
876
877void QQuickLoader::setAsynchronous(bool a)
878{
879 Q_D(QQuickLoader);
880 if (d->asynchronous == a)
881 return;
882
883 d->asynchronous = a;
884
885 if (!d->asynchronous && isComponentComplete() && d->active) {
886 if (d->loadingFromSource && d->component && d->component->isLoading()) {
887 // Force a synchronous component load
888 QUrl currentSource = d->source;
889 d->clear();
890 d->source = currentSource;
891 loadFromSource();
892 } else if (d->incubator && d->incubator->isLoading()) {
893 d->incubator->forceCompletion();
894 }
895 }
896
897 emit asynchronousChanged();
898}
899
900void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
901{
902 Q_Q(QQuickLoader);
903 if (!item)
904 return;
905
906 const bool needToUpdateWidth = loaderGeometryChanged && q->widthValid();
907 const bool needToUpdateHeight = loaderGeometryChanged && q->heightValid();
908
909 if (needToUpdateWidth && needToUpdateHeight) {
910 /* setSize keeps bindings intact (for backwards compatibility reasons),
911 but here we actually want the loader to control the size, so any
912 prexisting bindings ought to be removed
913 */
914 auto *itemPriv = QQuickItemPrivate::get(item);
915 // takeBinding would work without the check, but this is more efficient
916 // for the common case where we don't have a binding
917 if (itemPriv->width.hasBinding())
918 itemPriv->width.takeBinding();
919 if (itemPriv->height.hasBinding())
920 itemPriv->height.takeBinding();
921 item->setSize(QSizeF(q->width(), q->height()));
922 } else if (needToUpdateWidth) {
923 item->setWidth(q->width());
924 } else if (needToUpdateHeight) {
925 item->setHeight(q->height());
926 }
927
928 if (updatingSize)
929 return;
930
931 updatingSize = true;
932
933 q->setImplicitSize(getImplicitWidth(), getImplicitHeight());
934
935 updatingSize = false;
936}
937
938/*!
939 \qmlproperty QtObject QtQuick::Loader::item
940 This property holds the top-level object that is currently loaded.
941
942 Since \c {QtQuick 2.0}, Loader can load any object type.
943*/
944QObject *QQuickLoader::item() const
945{
946 Q_D(const QQuickLoader);
947 return d->object;
948}
949
950void QQuickLoader::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
951{
952 Q_D(QQuickLoader);
953 if (newGeometry != oldGeometry) {
954 d->_q_updateSize();
955 }
956 QQuickItem::geometryChange(newGeometry, oldGeometry);
957}
958
959QQuickLoader::Status QQuickLoaderPrivate::computeStatus() const
960{
961 if (!active)
962 return QQuickLoader::Status::Null;
963
964 if (component) {
965 switch (component->status()) {
966 case QQmlComponent::Loading:
967 return QQuickLoader::Status::Loading;
968 case QQmlComponent::Error:
969 return QQuickLoader::Status::Error;
970 case QQmlComponent::Null:
971 return QQuickLoader::Status::Null;
972 default:
973 break;
974 }
975 }
976
977 if (incubator) {
978 switch (incubator->status()) {
979 case QQmlIncubator::Loading:
980 return QQuickLoader::Status::Loading;
981 case QQmlIncubator::Error:
982 return QQuickLoader::Status::Error;
983 default:
984 break;
985 }
986 }
987
988 if (object)
989 return QQuickLoader::Status::Ready;
990
991 return source.isEmpty() ? QQuickLoader::Status::Null : QQuickLoader::Status::Error;
992}
993
995{
996 Q_Q(QQuickLoader);
997 auto newStatus = computeStatus();
998 if (status != newStatus) {
999 status = newStatus;
1000 emit q->statusChanged();
1001 }
1002}
1003
1005{
1006 Q_Q(QQuickLoader);
1007 const QQmlComponent::CompilationMode mode = asynchronous
1008 ? QQmlComponent::Asynchronous
1009 : QQmlComponent::PreferSynchronous;
1010 if (QQmlContext *context = qmlContext(q)) {
1011 if (QQmlEngine *engine = context->engine()) {
1012 component.setObject(new QQmlComponent(
1013 engine, context->resolvedUrl(source), mode, q), q);
1014 return;
1015 }
1016 }
1017
1018 qmlWarning(q) << "createComponent: Cannot find a QML engine.";
1019}
1020
1021QT_END_NAMESPACE
1022
1023#include <moc_qquickloader_p.cpp>
Status
Specifies the status of the QQmlIncubator.
void setInitialState(QObject *) override
Called after the object is first created, but before complex property bindings are evaluated and,...
void statusChanged(Status) override
Called when the status of the incubator changes.
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry) override
void disposeInitialPropertyValues()
void itemImplicitWidthChanged(QQuickItem *) override
qreal getImplicitWidth() const override
QQmlContext * itemContext
void setInitialState(QObject *o)
QQuickLoaderIncubator * incubator
void _q_updateSize(bool loaderGeometryChanged=true)
void itemImplicitHeightChanged(QQuickItem *) override
qreal getImplicitHeight() const override
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE const QQuickItemPrivate::ChangeTypes watchedChanges