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
qquick3dloader.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3dloader_p.h"
5
6#include "qquick3dobject_p.h"
7
8#include <QtQml/qqmlinfo.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{
20 m_loader->incubatorStateChanged(status);
21}
22
24{
25 m_loader->setInitialState(o);
26}
27
51 : QQuick3DNode(parent)
52 , m_item(nullptr)
53 , m_object(nullptr)
54 , m_itemContext(nullptr)
55 , m_incubator(nullptr)
56 , m_active(true)
57 , m_loadingFromSource(false)
58 , m_asynchronous(false)
59{
60}
61
63{
64 delete m_itemContext;
65 m_itemContext = nullptr;
66 delete m_incubator;
67 m_incubator = nullptr;
68 disposeInitialPropertyValues();
69 clear();
70}
71
89{
90 return m_active;
91}
92
94{
95 if (m_active == newVal)
96 return;
97
98 m_active = newVal;
99 if (newVal) {
100 if (m_loadingFromSource) {
101 loadFromSource();
102 } else {
103 loadFromSourceComponent();
104 }
105 } else {
106 // cancel any current incubation
107 if (m_incubator) {
108 m_incubator->clear();
109 delete m_itemContext;
110 m_itemContext = nullptr;
111 }
112
113 // Prevent any bindings from running while waiting for deletion. Without
114 // this we may get transient errors from use of 'parent', for example.
115 QQmlContext *context = qmlContext(m_object);
116 if (context)
117 QQmlContextData::get(context)->clearContextRecursively();
118
119 if (m_item) {
120 // We can't delete immediately because our item may have triggered
121 // the Loader to load a different item.
122 m_item->setParentItem(nullptr);
123 m_item->setVisible(false);
124 m_item = nullptr;
125 }
126 if (m_object) {
127 m_object->deleteLater();
128 m_object = nullptr;
130 }
132 }
134}
135
137{
138 bool ipvError = false;
139 args->setReturnValue(QV4::Encode::undefined());
140 QV4::Scope scope(args->v4engine());
141 QV4::ScopedValue ipv(scope, extractInitialPropertyValues(args, &ipvError));
142 if (ipvError)
143 return;
144
145 clear();
146 QUrl sourceUrl = resolveSourceUrl(args);
147 if (!ipv->isUndefined()) {
148 disposeInitialPropertyValues();
149 m_initialPropertyValues.set(args->v4engine(), ipv);
150 }
151 m_qmlCallingContext.set(scope.engine, scope.engine->qmlContext());
152
153 setSource(sourceUrl, false); // already cleared and set ipv above.
154}
155
168{
169 return m_source;
170}
171
173{
174 setSource(url, true);
175}
176
226{
227 return m_component;
228}
229
231{
232 if (comp == m_component)
233 return;
234
235 clear();
236
237 m_component.setObject(comp, this);
238 m_loadingFromSource = false;
239
240 if (m_active)
241 loadFromSourceComponent();
242 else
244}
245
250
292{
293 if (!m_active)
294 return Null;
295
296 if (m_component) {
297 switch (m_component->status()) {
299 return Loading;
301 return Error;
303 return Null;
304 default:
305 break;
306 }
307 }
308
309 if (m_incubator) {
310 switch (m_incubator->status()) {
312 return Loading;
314 return Error;
315 default:
316 break;
317 }
318 }
319
320 if (m_object)
321 return Ready;
322
323 return m_source.isEmpty() ? Null : Error;
324}
325
348{
349
350 if (m_object)
351 return 1.0;
352
353 if (m_component)
354 return m_component->progress();
355
356 return 0.0;
357}
358
394{
395 return m_asynchronous;
396}
397
399{
400 if (m_asynchronous == a)
401 return;
402
403 m_asynchronous = a;
404
405 if (!m_asynchronous && isComponentComplete() && m_active) {
406 if (m_loadingFromSource && m_component && m_component->isLoading()) {
407 // Force a synchronous component load
408 QUrl currentSource = m_source;
409 clear();
410 m_source = currentSource;
411 loadFromSource();
412 } else if (m_incubator && m_incubator->isLoading()) {
413 m_incubator->forceCompletion();
414 }
415 }
416
418}
419
426{
427 return m_object;
428}
429
431{
433 if (active()) {
434 if (m_loadingFromSource)
435 createComponent();
436 load();
437 }
438}
439
440void QQuick3DLoader::sourceLoaded()
441{
442 if (!m_component || !m_component->errors().isEmpty()) {
443 if (m_component)
444 QQmlEnginePrivate::warning(qmlEngine(this), m_component->errors());
445 if (m_loadingFromSource)
447 else
451 emit itemChanged(); //Like clearing source, emit itemChanged even if previous item was also null
452 disposeInitialPropertyValues(); // cleanup
453 return;
454 }
455
456 QQmlContext *creationContext = m_component->creationContext();
457 if (!creationContext) creationContext = qmlContext(this);
458 m_itemContext = new QQmlContext(creationContext);
459 m_itemContext->setContextObject(this);
460
461 delete m_incubator;
462 m_incubator = new QQuick3DLoaderIncubator(this, m_asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
463
464 m_component->create(*m_incubator, m_itemContext);
465
466 if (m_incubator && m_incubator->status() == QQmlIncubator::Loading)
468}
469
470void QQuick3DLoader::setSource(const QUrl &sourceUrl, bool needsClear)
471{
472 if (m_source == sourceUrl)
473 return;
474
475 if (needsClear)
476 clear();
477
478 m_source = sourceUrl;
479 m_loadingFromSource = true;
480
481 if (m_active)
482 loadFromSource();
483 else
485}
486
487void QQuick3DLoader::loadFromSource()
488{
489 if (m_source.isEmpty()) {
494 return;
495 }
496
497 if (isComponentComplete()) {
498 if (!m_component)
499 createComponent();
500 load();
501 }
502}
503
504void QQuick3DLoader::loadFromSourceComponent()
505{
506 if (!m_component) {
511 return;
512 }
513
515 load();
516}
517
518void QQuick3DLoader::clear()
519{
520 disposeInitialPropertyValues();
521
522 if (m_incubator)
523 m_incubator->clear();
524
525 delete m_itemContext;
526 m_itemContext = nullptr;
527
528 // Prevent any bindings from running while waiting for deletion. Without
529 // this we may get transient errors from use of 'parent', for example.
530 QQmlContext *context = qmlContext(m_object);
531 if (context)
532 QQmlContextData::get(context)->clearContextRecursively();
533
534 if (m_loadingFromSource && m_component) {
535 // disconnect since we deleteLater
537 this, SLOT(sourceLoaded()));
539 this, SIGNAL(progressChanged()));
540 m_component->deleteLater();
541 m_component.setObject(nullptr, this);
542 } else if (m_component) {
543 m_component.setObject(nullptr, this);
544 }
545 m_source = QUrl();
546
547 if (m_item) {
548 // We can't delete immediately because our item may have triggered
549 // the Loader to load a different item.
550 m_item->setParentItem(nullptr);
551 m_item->setVisible(false);
552 m_item = nullptr;
553 }
554 if (m_object) {
555 m_object->deleteLater();
556 m_object = nullptr;
557 }
558}
559
560void QQuick3DLoader::load()
561{
562
563 if (!isComponentComplete() || !m_component)
564 return;
565
566 if (!m_component->isLoading()) {
567 sourceLoaded();
568 } else {
570 this, SLOT(sourceLoaded()));
572 this, SIGNAL(progressChanged()));
575 if (m_loadingFromSource)
577 else
580 }
581}
582
583void QQuick3DLoader::incubatorStateChanged(QQmlIncubator::Status status)
584{
586 return;
587
589 m_object = m_incubator->object();
590 m_item = qmlobject_cast<QQuick3DNode*>(m_object);
592 m_incubator->clear();
593 } else if (status == QQmlIncubator::Error) {
594 if (!m_incubator->errors().isEmpty())
595 QQmlEnginePrivate::warning(qmlEngine(this), m_incubator->errors());
596 delete m_itemContext;
597 m_itemContext = nullptr;
598 delete m_incubator->object();
599 m_source = QUrl();
601 }
602 if (m_loadingFromSource)
604 else
609 emit loaded();
610 disposeInitialPropertyValues(); // cleanup
611}
612
613void QQuick3DLoader::setInitialState(QObject *obj)
614{
615 QQuick3DObject *item = qmlobject_cast<QQuick3DObject*>(obj);
616 if (item) {
617 item->setParentItem(this);
618 }
619 if (obj) {
620 QQml_setParent_noEvent(m_itemContext, obj);
622 m_itemContext = nullptr;
623 }
624
625 if (m_initialPropertyValues.isUndefined())
626 return;
627
629 Q_ASSERT(d && d->engine);
630 QV4::ExecutionEngine *v4 = d->engine->handle();
631 Q_ASSERT(v4);
632 QV4::Scope scope(v4);
633 QV4::ScopedValue ipv(scope, m_initialPropertyValues.value());
634 QV4::Scoped<QV4::QmlContext> qmlContext(scope, m_qmlCallingContext.value());
635 d->initializeObjectWithInitialProperties(qmlContext, ipv, obj, QQmlIncubatorPrivate::get(m_incubator)->requiredProperties());
636}
637
638void QQuick3DLoader::disposeInitialPropertyValues()
639{
640
641}
642
643QUrl QQuick3DLoader::resolveSourceUrl(QQmlV4FunctionPtr args)
644{
645 QV4::Scope scope(args->v4engine());
646 QV4::ScopedValue v(scope, (*args)[0]);
647 QString arg = v->toQString();
648 if (arg.isEmpty())
649 return QUrl();
650
651 auto context = scope.engine->callingQmlContext();
652 Q_ASSERT(!context.isNull());
653 return context->resolvedUrl(QUrl(arg));
654}
655
656QV4::ReturnedValue QQuick3DLoader::extractInitialPropertyValues(QQmlV4FunctionPtr args, bool *error)
657{
658 QV4::Scope scope(args->v4engine());
659 QV4::ScopedValue valuemap(scope, QV4::Encode::undefined());
660 if (args->length() >= 2) {
661 QV4::ScopedValue v(scope, (*args)[1]);
662 if (!v->isObject() || v->as<QV4::ArrayObject>()) {
663 *error = true;
664 qmlWarning(this) << QQuick3DLoader::tr("setSource: value is not an object");
665 } else {
666 *error = false;
667 valuemap = v;
668 }
669 }
670
671 return valuemap->asReturnedValue();
672}
673
674void QQuick3DLoader::createComponent()
675{
676 const QQmlComponent::CompilationMode mode = m_asynchronous
680 m_component.setObject(new QQmlComponent(context->engine(),
681 context->resolvedUrl(m_source),
682 mode,
683 this),
684 this);
685}
686
688
689#include "moc_qquick3dloader_p.cpp"
bool m_active
bool isEmpty() const noexcept
Definition qlist.h:401
qsizetype length() const noexcept
Definition qlist.h:399
\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.
qreal progress
\qmlproperty real Component::progress The progress of loading the component, from 0....
virtual QObject * create(QQmlContext *context=nullptr)
Create an object instance from this component, within the specified context.
static QQmlRefPointer< QQmlContextData > get(QQmlContext *context)
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 &)
static QQmlIncubatorPrivate * get(QQmlIncubator *incubator)
The QQmlIncubator class allows QML objects to be created asynchronously.
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.
bool isLoading() const
Returns true if the incubator's status() is Loading.
void forceCompletion()
Force any in-progress incubation to finish synchronously.
Status status() const
Return the current status of the incubator.
Status
Specifies the status of the QQmlIncubator.
friend class QQmlComponent
void setObject(T *obj, QObject *parent)
Definition qqmlguard_p.h:92
void statusChanged(Status) override
Called when the status of the incubator changes.
void setInitialState(QObject *) override
Called after the object is first created, but before complex property bindings are evaluated and,...
~QQuick3DLoader() override
QQmlComponent * sourceComponent
void activeChanged()
void setSourceComponent(QQmlComponent *)
Q_INVOKABLE void setSource(QQmlV4FunctionPtr)
void asynchronousChanged()
void setActive(bool newVal)
void setAsynchronous(bool a)
void itemChanged()
QQuick3DLoader(QQuick3DNode *parent=nullptr)
\qmltype Loader3D \inqmlmodule QtQuick3D \inherits Node
void statusChanged()
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void sourceChanged()
void sourceComponentChanged()
void progressChanged()
void setVisible(bool visible)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
\qmltype Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DObject \inherits QtObject
void setParentItem(QQuick3DObject *parentItem)
bool isComponentComplete() const
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qurl.h:94
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1896
ReturnedValue value() const
void set(ExecutionEngine *engine, const Value &value)
Combined button and popup list for selecting options.
quint64 ReturnedValue
static void * context
DBusConnection const char DBusError * error
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLsizei const GLfloat * v
[13]
GLenum mode
GLboolean GLboolean GLboolean GLboolean a
[7]
GLhandleARB obj
[2]
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.
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define emit
double qreal
Definition qtypes.h:187
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
QJSValueList args
static constexpr ReturnedValue undefined()
static Heap::ExecutionContext * qmlContext(Heap::ExecutionContext *ctx)
ExecutionEngine * engine