Qt 6.x
The Qt SDK
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
28{
29 delete itemContext;
30 itemContext = nullptr;
31 delete incubator;
33}
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)
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)
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
273{
275}
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)
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
460{
461 setSourceComponent(nullptr);
462}
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
592{
594}
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
621{
622 loader->setInitialState(o);
623}
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
663{
665}
666
668{
669 Q_Q(QQuickLoader);
671 return;
672
674 object = incubator->object();
676 if (!item) {
677 QQuickWindow *window = qmlobject_cast<QQuickWindow*>(object);
678 if (window) {
679 qCDebug(lcTransient) << window << "is transient for" << q->window();
680 window->setTransientParent(q->window());
681 }
682 }
683 emit q->itemChanged();
684 initResize();
685 incubator->clear();
686 } else if (status == QQmlIncubator::Error) {
687 if (!incubator->errors().isEmpty())
689 delete itemContext;
690 itemContext = nullptr;
691 delete incubator->object();
692 source = QUrl();
693 emit q->itemChanged();
694 }
696 emit q->sourceChanged();
697 else
698 emit q->sourceComponentChanged();
699 updateStatus();
700 emit q->progressChanged();
702 emit q->loaded();
703}
704
706{
707 Q_Q(QQuickLoader);
708 if (!component || !component->errors().isEmpty()) {
709 if (component)
712 emit q->sourceChanged();
713 else
714 emit q->sourceComponentChanged();
715 updateStatus();
716 emit q->progressChanged();
717 emit q->itemChanged(); //Like clearing source, emit itemChanged even if previous item was also null
718 disposeInitialPropertyValues(); // cleanup
719 return;
720 }
721
722 if (!active)
723 return;
724
725 QQmlContext *creationContext = component->creationContext();
726 if (!creationContext)
727 creationContext = qmlContext(q);
728
730 QQmlContext *context = [&](){
731 if (cp->isBound())
732 return creationContext;
733 itemContext = new QQmlContext(creationContext);
735 return itemContext;
736 }();
737
738 delete incubator;
740
742
744 updateStatus();
745}
746
788{
789 Q_D(const QQuickLoader);
790
791 return static_cast<Status>(d->status);
792}
793
795{
796 Q_D(QQuickLoader);
798 if (active() && (status() != Ready)) {
799 if (d->loadingFromSource)
800 d->createComponent();
801 d->load();
802 }
803}
804
806{
807 if (change == ItemSceneChange) {
808 QQuickWindow *loadedWindow = qmlobject_cast<QQuickWindow *>(item());
809 if (loadedWindow) {
810 qCDebug(lcTransient) << loadedWindow << "is transient for" << value.window;
811 loadedWindow->setTransientParent(value.window);
812 }
813 }
815}
816
835{
836 Q_D(const QQuickLoader);
837
838 if (d->object)
839 return 1.0;
840
841 if (d->component)
842 return d->component->progress();
843
844 return 0.0;
845}
846
881{
882 Q_D(const QQuickLoader);
883 return d->asynchronous;
884}
885
887{
888 Q_D(QQuickLoader);
889 if (d->asynchronous == a)
890 return;
891
892 d->asynchronous = a;
893
894 if (!d->asynchronous && isComponentComplete() && d->active) {
895 if (d->loadingFromSource && d->component && d->component->isLoading()) {
896 // Force a synchronous component load
897 QUrl currentSource = d->source;
898 d->clear();
899 d->source = currentSource;
900 loadFromSource();
901 } else if (d->incubator && d->incubator->isLoading()) {
902 d->incubator->forceCompletion();
903 }
904 }
905
907}
908
909void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
910{
911 Q_Q(QQuickLoader);
912 if (!item)
913 return;
914
915 const bool needToUpdateWidth = loaderGeometryChanged && q->widthValid();
916 const bool needToUpdateHeight = loaderGeometryChanged && q->heightValid();
917
918 if (needToUpdateWidth && needToUpdateHeight)
919 item->setSize(QSizeF(q->width(), q->height()));
920 else if (needToUpdateWidth)
921 item->setWidth(q->width());
922 else if (needToUpdateHeight)
923 item->setHeight(q->height());
924
925 if (updatingSize)
926 return;
927
928 updatingSize = true;
929
930 q->setImplicitSize(getImplicitWidth(), getImplicitHeight());
931
932 updatingSize = false;
933}
934
942{
943 Q_D(const QQuickLoader);
944 return d->object;
945}
946
947void QQuickLoader::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
948{
949 Q_D(QQuickLoader);
950 if (newGeometry != oldGeometry) {
951 d->_q_updateSize();
952 }
953 QQuickItem::geometryChange(newGeometry, oldGeometry);
954}
955
957{
958 if (!active)
960
961 if (component) {
962 switch (component->status()) {
969 default:
970 break;
971 }
972 }
973
974 if (incubator) {
975 switch (incubator->status()) {
980 default:
981 break;
982 }
983 }
984
985 if (object)
987
989}
990
992{
993 Q_Q(QQuickLoader);
994 auto newStatus = computeStatus();
995 if (status != newStatus) {
996 status = newStatus;
997 emit q->statusChanged();
998 }
999}
1000
1002{
1003 Q_Q(QQuickLoader);
1007 if (QQmlContext *context = qmlContext(q)) {
1008 if (QQmlEngine *engine = context->engine()) {
1010 engine, context->resolvedUrl(source), mode, q), q);
1011 return;
1012 }
1013 }
1014
1015 qmlWarning(q) << "createComponent: Cannot find a QML engine.";
1016}
1017
1019
1020#include <moc_qquickloader_p.cpp>
QV4::ExecutionEngine * handle() const
Definition qjsengine.h:292
static QV4::Value * takeManagedValue(QJSValue *jsval)
Definition qjsvalue_p.h:207
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
bool isEmpty() const noexcept
Definition qlist.h:390
\inmodule QtCore
Definition qobject.h:90
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
static QQmlComponentPrivate * get(QQmlComponent *c)
The QQmlComponent class encapsulates a QML component definition.
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
QQuickWindow * window
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:64
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:113
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:76
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:114
qreal height
This property holds the height of this item.
Definition qquickitem.h:77
void setWidth(qreal)
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:143
void setInitialState(QObject *) override
Called after the object is first created, but before 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)
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore\reentrant
Definition qrect.h:483
\inmodule QtCore
Definition qsize.h:207
\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:1874
ReturnedValue value() const
void statusChanged(QDeclarativeComponent::Status status)
[1]
Definition qlogging.cpp:9
Combined button and popup list for selecting options.
static void * context
static const QCssKnownValue properties[NumProperties - 1]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
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:76
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:71
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:92
QUrl url("example.com")
[constructor-url-reference]
QGraphicsItem * item
QJSEngine engine
[0]
QQmlRefPointer< QQmlContextData > callingQmlContext() const
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
\inmodule QtQuick
Definition qquickitem.h:158