Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
4#include "qquickloader_p_p.h"
5
6#include <QtQml/qqmlinfo.h>
7
8#include <private/qqmlengine_p.h>
9#include <private/qqmlglobal_p.h>
10
11#include <private/qqmlcomponent_p.h>
12#include <private/qqmlincubator_p.h>
13
15
17
18static const QQuickItemPrivate::ChangeTypes watchedChanges
19 = QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
20
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
48
54
56{
57 Q_Q(QQuickLoader);
59
60 if (incubator)
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.
69 if (context)
70 QQmlContextData::get(context)->clearContextRecursively();
71
73 // disconnect since we deleteLater
76 QObject::disconnect(component, SIGNAL(progressChanged(qreal)),
77 q, SIGNAL(progressChanged()));
79 component.setObject(nullptr, q);
80 } else if (component) {
81 component.setObject(nullptr, q);
82 }
83 source = QUrl();
84
85 if (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;
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();
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();
130}
131
276
278{
279 Q_D(QQuickLoader);
280 d->clear();
281}
282
299{
300 Q_D(const QQuickLoader);
301 return d->active;
302}
303
304void QQuickLoader::setActive(bool newVal)
305{
306 Q_D(QQuickLoader);
307 if (d->active == newVal)
308 return;
309
310 d->active = newVal;
311 if (newVal == true) {
312 if (d->loadingFromSource) {
313 loadFromSource();
314 } else {
315 loadFromSourceComponent();
316 }
317 } else {
318 // cancel any current incubation
319 if (d->incubator) {
320 d->incubator->clear();
321 delete d->itemContext;
322 d->itemContext = nullptr;
323 }
324
325 // Prevent any bindings from running while waiting for deletion. Without
326 // this we may get transient errors from use of 'parent', for example.
327 QQmlContext *context = qmlContext(d->object);
328 if (context)
329 QQmlContextData::get(context)->clearContextRecursively();
330
331 if (d->item) {
333 p->removeItemChangeListener(d, watchedChanges);
334
335 // We can't delete immediately because our item may have triggered
336 // the Loader to load a different item.
337 d->item->setParentItem(nullptr);
338 d->item->setVisible(false);
339 d->item = nullptr;
340 }
341 if (d->object) {
342 d->object->deleteLater();
343 d->object = nullptr;
345 }
346 d->updateStatus();
347 }
349}
350
351
366{
367 Q_D(const QQuickLoader);
368 return d->source;
369}
370
372{
373 setSource(url, true); // clear previous values
374}
375
376void QQuickLoader::setSource(const QUrl &url, bool needsClear)
377{
378 Q_D(QQuickLoader);
379 if (d->source == url)
380 return;
381
382 if (needsClear)
383 d->clear();
384
385 d->source = url;
386 d->loadingFromSource = true;
387
388 if (d->active)
389 loadFromSource();
390 else
392}
393
394void QQuickLoader::loadFromSource()
395{
396 Q_D(QQuickLoader);
397 if (d->source.isEmpty()) {
399 d->updateStatus();
402 return;
403 }
404
405 if (isComponentComplete()) {
406 if (!d->component)
407 d->createComponent();
408 d->load();
409 }
410}
411
437{
438 Q_D(const QQuickLoader);
439 return d->component;
440}
441
443{
444 Q_D(QQuickLoader);
445 if (comp == d->component)
446 return;
447
448 d->clear();
449
450 d->component.setObject(comp, this);
451 d->loadingFromSource = false;
452
453 if (d->active)
454 loadFromSourceComponent();
455 else
457}
458
463
464void QQuickLoader::loadFromSourceComponent()
465{
466 Q_D(QQuickLoader);
467 if (!d->component) {
469 d->updateStatus();
472 return;
473 }
474
476 d->load();
477}
478
479
480QUrl QQuickLoader::setSourceUrlHelper(const QUrl &unresolvedUrl)
481{
482 Q_D(QQuickLoader);
483
484 // 1. If setSource is called with a valid url, clear the old component and its corresponding url
485 // 2. If setSource is called with an invalid url(e.g. empty url), clear the old component but
486 // hold the url for old one.(we will compare it with new url later and may update status of loader to Loader.Null)
487 QUrl oldUrl = d->source;
488 d->clear();
489 QUrl sourceUrl = qmlEngine(this)->handle()->callingQmlContext()->resolvedUrl(unresolvedUrl);
490 if (!sourceUrl.isValid())
491 d->source = oldUrl;
492 return sourceUrl;
493}
494
560{
561 Q_D(QQuickLoader);
562
563 if (!(properties.isArray() || properties.isObject())) {
564 qmlWarning(this) << QQuickLoader::tr("setSource: value is not an object");
565 return;
566 }
567
568 QUrl sourceUrl = setSourceUrlHelper(source);
569
570 d->disposeInitialPropertyValues();
571 auto engine = qmlEngine(this)->handle();
572 d->initialPropertyValues.set(engine, QJSValuePrivate::takeManagedValue(&properties)->asReturnedValue());
573 d->qmlCallingContext.set(engine, engine->qmlContext());
574
575 setSource(sourceUrl, false); // already cleared and set ipv above.
576}
577
579{
580 Q_D(QQuickLoader);
581
582 QUrl sourceUrl = setSourceUrlHelper(source);
583
584 d->disposeInitialPropertyValues();
585 auto engine = qmlEngine(this)->handle();
586 d->qmlCallingContext.set(engine, engine->qmlContext());
587
588 setSource(sourceUrl, false); // already cleared and set ipv above.
589}
590
595
597{
598 Q_Q(QQuickLoader);
599
600 if (!q->isComponentComplete() || !component)
601 return;
602
603 if (!component->isLoading()) {
605 } else {
608 QObject::connect(component, SIGNAL(progressChanged(qreal)),
609 q, SIGNAL(progressChanged()));
610 updateStatus();
611 emit q->progressChanged();
613 emit q->sourceChanged();
614 else
615 emit q->sourceComponentChanged();
616 emit q->itemChanged();
617 }
618}
619
624
626{
627 Q_Q(QQuickLoader);
628
630 if (item) {
631 // If the item doesn't have an explicit size, but the Loader
632 // does, then set the item's size now before bindings are
633 // evaluated, otherwise we will end up resizing the item
634 // later and triggering any affected bindings/anchors.
636 item->setWidth(q->width());
638 item->setHeight(q->height());
640 }
641 if (obj) {
642 if (itemContext)
645 itemContext = nullptr;
646 }
647
649 return;
650
652 Q_ASSERT(d && d->engine);
653 QV4::ExecutionEngine *v4 = d->engine->handle();
654 Q_ASSERT(v4);
655 QV4::Scope scope(v4);
658 auto incubatorPriv = QQmlIncubatorPrivate::get(incubator);
659 d->initializeObjectWithInitialProperties(qmlContext, ipv, obj, incubatorPriv->requiredProperties());
660}
661
666
668{
669 Q_Q(QQuickLoader);
671 return;
672
674 object = incubator->object();
676 emit q->itemChanged();
677 initResize();
678 incubator->clear();
679 } else if (status == QQmlIncubator::Error) {
680 if (!incubator->errors().isEmpty())
682 delete itemContext;
683 itemContext = nullptr;
684 delete incubator->object();
685 source = QUrl();
686 emit q->itemChanged();
687 }
689 emit q->sourceChanged();
690 else
691 emit q->sourceComponentChanged();
692 updateStatus();
693 emit q->progressChanged();
695 emit q->loaded();
696}
697
699{
700 Q_Q(QQuickLoader);
701 if (!component || !component->errors().isEmpty()) {
702 if (component)
705 emit q->sourceChanged();
706 else
707 emit q->sourceComponentChanged();
708 updateStatus();
709 emit q->progressChanged();
710 emit q->itemChanged(); //Like clearing source, emit itemChanged even if previous item was also null
711 disposeInitialPropertyValues(); // cleanup
712 return;
713 }
714
715 if (!active)
716 return;
717
718 QQmlContext *creationContext = component->creationContext();
719 if (!creationContext)
720 creationContext = qmlContext(q);
721
723 QQmlContext *context = [&](){
724 if (cp->isBound())
725 return creationContext;
726 itemContext = new QQmlContext(creationContext);
728 return itemContext;
729 }();
730
731 delete incubator;
733
735
737 updateStatus();
738}
739
781{
782 Q_D(const QQuickLoader);
783
784 return static_cast<Status>(d->status);
785}
786
788{
789 Q_D(QQuickLoader);
791 if (active() && (status() != Ready)) {
792 if (d->loadingFromSource)
793 d->createComponent();
794 d->load();
795 }
796}
797
799{
800 switch (change) {
802 Q_ASSERT(value.item);
803 if (value.item->flags().testFlag(QQuickItem::ItemObservesViewport))
804 // Re-trigger the parent traversal to get subtreeTransformChangedEnabled turned on
806 break;
807 default:
808 break;
809 }
811}
812
831{
832 Q_D(const QQuickLoader);
833
834 if (d->object)
835 return 1.0;
836
837 if (d->component)
838 return d->component->progress();
839
840 return 0.0;
841}
842
877{
878 Q_D(const QQuickLoader);
879 return d->asynchronous;
880}
881
883{
884 Q_D(QQuickLoader);
885 if (d->asynchronous == a)
886 return;
887
888 d->asynchronous = a;
889
890 if (!d->asynchronous && isComponentComplete() && d->active) {
891 if (d->loadingFromSource && d->component && d->component->isLoading()) {
892 // Force a synchronous component load
893 QUrl currentSource = d->source;
894 d->clear();
895 d->source = currentSource;
896 loadFromSource();
897 } else if (d->incubator && d->incubator->isLoading()) {
898 d->incubator->forceCompletion();
899 }
900 }
901
903}
904
905void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
906{
907 Q_Q(QQuickLoader);
908 if (!item)
909 return;
910
911 const bool needToUpdateWidth = loaderGeometryChanged && q->widthValid();
912 const bool needToUpdateHeight = loaderGeometryChanged && q->heightValid();
913
914 if (needToUpdateWidth && needToUpdateHeight) {
915 /* setSize keeps bindings intact (for backwards compatibility reasons),
916 but here we actually want the loader to control the size, so any
917 prexisting bindings ought to be removed
918 */
919 auto *itemPriv = QQuickItemPrivate::get(item);
920 // takeBinding would work without the check, but this is more efficient
921 // for the common case where we don't have a binding
922 if (itemPriv->width.hasBinding())
923 itemPriv->width.takeBinding();
924 if (itemPriv->height.hasBinding())
925 itemPriv->height.takeBinding();
926 item->setSize(QSizeF(q->width(), q->height()));
927 } else if (needToUpdateWidth) {
928 item->setWidth(q->width());
929 } else if (needToUpdateHeight) {
930 item->setHeight(q->height());
931 }
932
933 if (updatingSize)
934 return;
935
936 updatingSize = true;
937
938 q->setImplicitSize(getImplicitWidth(), getImplicitHeight());
939
940 updatingSize = false;
941}
942
950{
951 Q_D(const QQuickLoader);
952 return d->object;
953}
954
955void QQuickLoader::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
956{
957 Q_D(QQuickLoader);
958 if (newGeometry != oldGeometry) {
959 d->_q_updateSize();
960 }
961 QQuickItem::geometryChange(newGeometry, oldGeometry);
962}
963
965{
966 if (!active)
968
969 if (component) {
970 switch (component->status()) {
977 default:
978 break;
979 }
980 }
981
982 if (incubator) {
983 switch (incubator->status()) {
988 default:
989 break;
990 }
991 }
992
993 if (object)
995
997}
998
1000{
1001 Q_Q(QQuickLoader);
1002 auto newStatus = computeStatus();
1003 if (status != newStatus) {
1004 status = newStatus;
1005 emit q->statusChanged();
1006 }
1007}
1008
1010{
1011 Q_Q(QQuickLoader);
1015 if (QQmlContext *context = qmlContext(q)) {
1016 if (QQmlEngine *engine = context->engine()) {
1018 engine, context->resolvedUrl(source), mode, q), q);
1019 return;
1020 }
1021 }
1022
1023 qmlWarning(q) << "createComponent: Cannot find a QML engine.";
1024}
1025
1027
1028#include <moc_qquickloader_p.cpp>
QV4::ExecutionEngine * handle() const
Definition qjsengine.h:298
static QV4::Value * takeManagedValue(QJSValue *jsval)
Definition qjsvalue_p.h:215
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
bool isEmpty() const noexcept
Definition qlist.h:401
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
static QQmlComponentPrivate * get(QQmlComponent *c)
The QQmlComponent class encapsulates a QML component definition.
Status
\qmltype Component \instantiates QQmlComponent\inqmlmodule QtQml
bool isLoading() const
Returns true if status() == QQmlComponent::Loading.
QQmlContext * creationContext() const
Returns the QQmlContext the component was created in.
Status status
\qmlproperty enumeration Component::status
QList< QQmlError > errors() const
Returns the list of errors that occurred during the last compile or create operation.
CompilationMode
Specifies whether the QQmlComponent should load the component immediately, or asynchonously.
virtual QObject * create(QQmlContext *context=nullptr)
Create an object instance from this component, within the specified context.
static QQmlRefPointer< QQmlContextData > get(QQmlContext *context)
QUrl resolvedUrl(const QUrl &) const
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
void setContextObject(QObject *)
Set the context object.
void warning(const QQmlError &)
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
static QQmlIncubatorPrivate * get(QQmlIncubator *incubator)
QList< QQmlError > errors() const
Return the list of errors encountered while incubating the object.
void clear()
Clears the incubator.
QObject * object() const
Return the incubated object if the status is Ready, otherwise 0.
Status status() const
Return the current status of the incubator.
Status
Specifies the status of the QQmlIncubator.
void setObject(T *obj, QObject *parent)
Definition qqmlguard_p.h:92
virtual void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
bool widthValid() const
virtual qreal getImplicitWidth() const
bool heightValid() const
virtual qreal getImplicitHeight() const
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void setSize(const QSizeF &size)
void setFlag(Flag flag, bool enabled=true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disable...
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
qreal implicitWidth
Definition qquickitem.h:114
void setParentItem(QQuickItem *parent)
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
void setHeight(qreal)
qreal width
This property holds the width of this item.
Definition qquickitem.h:75
void setVisible(bool)
virtual void itemChange(ItemChange, const ItemChangeData &)
Called when change occurs for this item.
bool isComponentComplete() const
Returns true if construction of the QML component is complete; otherwise returns false.
qreal implicitHeight
Definition qquickitem.h:115
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
void setWidth(qreal)
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
@ ItemChildAddedChange
Definition qquickitem.h:145
@ ItemObservesViewport
Definition qquickitem.h:138
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.
QQmlStrongJSQObjectReference< QQmlComponent > component
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry) override
void disposeInitialPropertyValues()
void itemImplicitWidthChanged(QQuickItem *) override
QV4::PersistentValue qmlCallingContext
qreal getImplicitWidth() const override
QQuickLoader::Status computeStatus() const
QV4::PersistentValue initialPropertyValues
QQmlContext * itemContext
void setInitialState(QObject *o)
QQuickLoaderIncubator * incubator
void _q_updateSize(bool loaderGeometryChanged=true)
void itemImplicitHeightChanged(QQuickItem *) override
void incubatorStateChanged(QQmlIncubator::Status status)
qreal getImplicitHeight() const override
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
void itemChange(ItemChange change, const ItemChangeData &value) override
Called when change occurs for this item.
void activeChanged()
void resetSourceComponent()
void setSourceWithoutResolve(const QUrl &source)
QObject * item
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
void itemChanged()
QQuickLoader(QQuickItem *parent=nullptr)
\qmltype Loader \instantiates QQuickLoader \inqmlmodule QtQuick\inherits Item
virtual ~QQuickLoader()
Q_INVOKABLE void setSource(const QUrl &source, QJSValue initialProperties)
void progressChanged()
void sourceChanged()
void asynchronousChanged()
void setSourceComponent(QQmlComponent *)
void setAsynchronous(bool a)
QQmlComponent * sourceComponent
void sourceComponentChanged()
void setActive(bool newVal)
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
Definition qurl.h:94
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1882
ReturnedValue value() const
void statusChanged(QQmlComponent::Status status)
[1]
Definition qlogging.cpp:11
Combined button and popup list for selecting options.
static void * context
static const QCssKnownValue properties[NumProperties - 1]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLenum mode
GLboolean GLboolean GLboolean GLboolean a
[7]
GLsizei GLsizei GLchar * source
GLhandleARB obj
[2]
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:80
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
void QQml_setParent_noEvent(QObject *object, QObject *parent)
Makes the object a child of parent.
QQuickItem * qmlobject_cast< QQuickItem * >(QObject *object)
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
static QT_BEGIN_NAMESPACE const QQuickItemPrivate::ChangeTypes watchedChanges
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
double qreal
Definition qtypes.h:187
QUrl url("example.com")
[constructor-url-reference]
QGraphicsItem * item
QJSEngine engine
[0]
QQmlRefPointer< QQmlContextData > callingQmlContext() const
\inmodule QtQuick
Definition qquickitem.h:159