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
qqmlengine.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 "qqmlengine_p.h"
5#include "qqmlengine.h"
6
7#include <private/qqmlcontext_p.h>
8#include <private/qqmlpluginimporter_p.h>
9#include <private/qqmlprofiler_p.h>
10#include <private/qqmlscriptdata_p.h>
11#include <private/qqmlsourcecoordinate_p.h>
12#include <private/qqmltype_p.h>
13#include <private/qqmltypedata_p.h>
14#include <private/qqmlvmemetaobject_p.h>
15#include <private/qqmlcomponent_p.h>
16
17#include <QtQml/qqml.h>
18#include <QtQml/qqmlcomponent.h>
19#include <QtQml/qqmlcontext.h>
20#include <QtQml/qqmlincubator.h>
21#include <QtQml/qqmlscriptstring.h>
22
23#include <QtCore/qcoreapplication.h>
24#include <QtCore/qcryptographichash.h>
25#include <QtCore/qdir.h>
26#include <QtCore/qdiriterator.h>
27#include <QtCore/qmetaobject.h>
28#include <QtCore/qmutex.h>
29#include <QtCore/qstandardpaths.h>
30#include <QtCore/qstorageinfo.h>
31#include <QtCore/qthread.h>
32
33#if QT_CONFIG(qml_network)
34#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
35#include <QtNetwork/qnetworkaccessmanager.h>
36#endif
37
38#ifdef Q_OS_WIN // for %APPDATA%
39# include <qt_windows.h>
40# include <shlobj.h>
41# include <QtCore/qlibrary.h>
42# ifndef CSIDL_APPDATA
43# define CSIDL_APPDATA 0x001a // <username>\Application Data
44# endif
45#endif // Q_OS_WIN
46
47#ifdef Q_OS_DARWIN
48# include <unistd.h>
49#endif
50
52
53using namespace Qt::StringLiterals;
54
56
57/*!
58 \qmltype QtObject
59 \nativetype QObject
60 \inqmlmodule QtQml
61 \ingroup qml-utility-elements
62 \brief A basic QML type.
63
64 The QtObject type is a non-visual element which contains only the
65 objectName property.
66
67 It can be useful to create a QtObject if you need an extremely
68 lightweight type to enclose a set of custom properties:
69
70 \snippet qml/qtobject.qml 0
71
72 It can also be useful for C++ integration, as it is just a plain
73 QObject. See the QObject documentation for further details.
74*/
75/*!
76 \qmlproperty string QtObject::objectName
77 This property holds the QObject::objectName for this specific object instance.
78
79 This allows a C++ application to locate an item within a QML component
80 using the QObject::findChild() method. For example, the following C++
81 application locates the child \l Rectangle item and dynamically changes its
82 \c color value:
83
84 \qml
85 // MyRect.qml
86
87 import QtQuick 2.0
88
89 Item {
90 width: 200; height: 200
91
92 Rectangle {
93 anchors.fill: parent
94 color: "red"
95 objectName: "myRect"
96 }
97 }
98 \endqml
99
100 \code
101 // main.cpp
102
103 QQuickView view;
104 view.setSource(QUrl::fromLocalFile("MyRect.qml"));
105 view.show();
106
107 QQuickItem *item = view.rootObject()->findChild<QQuickItem*>("myRect");
108 if (item)
109 item->setProperty("color", QColor(Qt::yellow));
110 \endcode
111*/
112
113Q_CONSTINIT std::atomic<bool> QQmlEnginePrivate::qml_debugging_enabled{false};
114bool QQmlEnginePrivate::s_designerMode = false;
115
116bool QQmlEnginePrivate::designerMode()
117{
118 return s_designerMode;
119}
120
121void QQmlEnginePrivate::activateDesignerMode()
122{
123 s_designerMode = true;
124}
125
126
127/*!
128 \class QQmlImageProviderBase
129 \brief The QQmlImageProviderBase class is used to register image providers in the QML engine.
130 \inmodule QtQml
131
132 Image providers must be registered with the QML engine. The only information the QML
133 engine knows about image providers is the type of image data they provide. To use an
134 image provider to acquire image data, you must cast the QQmlImageProviderBase pointer
135 to a QQuickImageProvider pointer.
136
137 \sa QQuickImageProvider, QQuickTextureFactory
138*/
139
140/*!
141 \enum QQmlImageProviderBase::ImageType
142
143 Defines the type of image supported by this image provider.
144
145 \value Image The Image Provider provides QImage images.
146 The QQuickImageProvider::requestImage() method will be called for all image requests.
147 \value Pixmap The Image Provider provides QPixmap images.
148 The QQuickImageProvider::requestPixmap() method will be called for all image requests.
149 \value Texture The Image Provider provides QSGTextureProvider based images.
150 The QQuickImageProvider::requestTexture() method will be called for all image requests.
151 \value ImageResponse The Image provider provides QQuickTextureFactory based images.
152 Should only be used in QQuickAsyncImageProvider or its subclasses.
153 The QQuickAsyncImageProvider::requestImageResponse() method will be called for all image requests.
154 Since Qt 5.6
155 \omitvalue Invalid
156*/
157
158/*!
159 \enum QQmlImageProviderBase::Flag
160
161 Defines specific requirements or features of this image provider.
162
163 \value ForceAsynchronousImageLoading Ensures that image requests to the provider are
164 run in a separate thread, which allows the provider to spend as much time as needed
165 on producing the image without blocking the main thread.
166*/
167
168/*!
169 \fn QQmlImageProviderBase::imageType() const
170
171 Implement this method to return the image type supported by this image provider.
172*/
173
174/*!
175 \fn QQmlImageProviderBase::flags() const
176
177 Implement this to return the properties of this image provider.
178*/
179
180/*! \internal */
181QQmlImageProviderBase::QQmlImageProviderBase()
182{
183}
184
185/*! \internal */
186QQmlImageProviderBase::~QQmlImageProviderBase()
187{
188}
189
190QQmlEnginePrivate::~QQmlEnginePrivate()
191{
192 if (inProgressCreations)
193 qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
194
195 if (incubationController) incubationController->d = nullptr;
196 incubationController = nullptr;
197
198#if QT_CONFIG(qml_debug)
199 delete profiler;
200#endif
201}
202
203void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
204{
205 QObjectPrivate *p = QObjectPrivate::get(o);
206 if (QQmlData *d = QQmlData::get(p)) {
207 const auto invalidate = [](QQmlContextData *c) {c->invalidate();};
208 if (d->ownContext) {
209 d->ownContext->deepClearContextObject(o, invalidate, invalidate);
210 d->ownContext.reset();
211 d->context = nullptr;
212 Q_ASSERT(!d->outerContext || d->outerContext->contextObject() != o);
213 } else if (d->outerContext && d->outerContext->contextObject() == o) {
214 d->outerContext->deepClearContextObject(o, invalidate, invalidate);
215 }
216
217 if (d->hasVMEMetaObject || d->hasInterceptorMetaObject) {
218 // This is somewhat dangerous because another thread might concurrently
219 // try to resolve the dynamic metaobject. In practice this will then
220 // lead to either the code path that still returns the interceptor
221 // metaobject or the code path that returns the string casted one. Both
222 // is fine if you cannot actually touch the object itself. Since the
223 // other thread is obviously not synchronized to this one, it can't.
224 //
225 // In particular we do this when delivering the frameSwapped() signal
226 // in QQuickWindow. The handler for frameSwapped() is written in a way
227 // that is thread safe as long as QQuickWindow's dtor hasn't finished.
228 // QQuickWindow's dtor does synchronize with the render thread, but it
229 // runs _after_ qdeclarativeelement_destructor.
230 static_cast<QQmlInterceptorMetaObject *>(p->metaObject)->invalidate();
231 d->hasVMEMetaObject = d->hasInterceptorMetaObject = false;
232 }
233
234 // Mark this object as in the process of deletion to
235 // prevent it resolving in bindings
236 QQmlData::markAsDeleted(o);
237 }
238}
239
240template<>
241int qmlRegisterType<void>(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
242{
243 QQmlPrivate::RegisterType type = {
244 QQmlPrivate::RegisterType::CurrentVersion,
245 QMetaType(),
246 QMetaType(),
247 0, nullptr, nullptr,
248 QString(),
249 nullptr,
250 uri,
251 QTypeRevision::fromVersion(versionMajor, versionMinor),
252 qmlName,
253 nullptr,
254 nullptr,
255 nullptr,
256 -1,
257 -1,
258 -1,
259 nullptr,
260 nullptr,
261 nullptr,
262 QTypeRevision::zero(),
263 -1,
264 QQmlPrivate::ValueTypeCreationMethod::None,
265 };
266
267 return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
268}
269
270bool QQmlEnginePrivate::baseModulesUninitialized = true;
271void QQmlEnginePrivate::init()
272{
273 Q_Q(QQmlEngine);
274
275 if (baseModulesUninitialized) {
276 // Register builtins
277 qml_register_types_QML();
278
279 // No need to specifically register those.
280 static_assert(std::is_same_v<QStringList, QList<QString>>);
281 static_assert(std::is_same_v<QVariantList, QList<QVariant>>);
282
283 qRegisterMetaType<QQmlScriptString>();
284 qRegisterMetaType<QQmlComponent::Status>();
285 qRegisterMetaType<QList<QObject*> >();
286 qRegisterMetaType<QQmlBinding*>();
287
288 // Protect the module: We don't want any URL interceptor to mess with the builtins.
289 qmlProtectModule("QML", 1);
290
291 QQmlData::init();
292 baseModulesUninitialized = false;
293 }
294
295 q->handle()->setQmlEngine(q);
296
297 rootContext = new QQmlContext(q,true);
298}
299
300/*!
301 \class QQmlEngine
302 \since 5.0
303 \inmodule QtQml
304 \brief The QQmlEngine class provides an environment for instantiating QML components.
305
306 A QQmlEngine is used to manage \l{QQmlComponent}{components} and objects created from
307 them and execute their bindings and functions. QQmlEngine also inherits from
308 \l{QJSEngine} which allows seamless integration between your QML components and
309 JavaScript code.
310
311 Each QML component is instantiated in a QQmlContext. In QML, contexts are arranged
312 hierarchically and this hierarchy is managed by the QQmlEngine. By default,
313 components are instantiated in the \l {QQmlEngine::rootContext()}{root context}.
314
315 \sa QQmlComponent, QQmlContext, {QML Global Object}, QQmlApplicationEngine
316*/
317
318/*!
319 Create a new QQmlEngine with the given \a parent.
320*/
321QQmlEngine::QQmlEngine(QObject *parent)
322: QJSEngine(*new QQmlEnginePrivate, parent)
323{
324 Q_D(QQmlEngine);
325 d->init();
326 QJSEnginePrivate::addToDebugServer(this);
327}
328
329/*!
330* \internal
331*/
332QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent)
333: QJSEngine(dd, parent)
334{
335 Q_D(QQmlEngine);
336 d->init();
337}
338
339/*!
340 Destroys the QQmlEngine.
341
342 Any QQmlContext's created on this engine will be
343 invalidated, but not destroyed (unless they are parented to the
344 QQmlEngine object).
345
346 See ~QJSEngine() for details on cleaning up the JS engine.
347*/
348QQmlEngine::~QQmlEngine()
349{
350 Q_D(QQmlEngine);
351
352#if QT_CONFIG(qml_worker_script)
353 // Delete the workerscript engine early
354 // so that it won't be able to use the type loader anymore.
355 delete std::exchange(d->workerScriptEngine, nullptr);
356#endif
357
358 QV4::ExecutionEngine *v4 = handle();
359 v4->inShutdown = true;
360 QJSEnginePrivate::removeFromDebugServer(this);
361
362 // Emit onDestruction signals for the root context before
363 // we destroy the contexts, engine, Singleton Types etc. that
364 // may be required to handle the destruction signal.
365 QQmlContextPrivate::get(rootContext())->emitDestruction();
366
367 // clean up all singleton type instances which we own.
368 // we do this here and not in the private dtor since otherwise a crash can
369 // occur (if we are the QObject parent of the QObject singleton instance)
370 // XXX TODO: performance -- store list of singleton types separately?
371 d->singletonInstances.clear();
372
373 delete d->rootContext;
374 d->rootContext = nullptr;
375
376 v4->typeLoader()->invalidate();
377
378 // QQmlGadgetPtrWrapper can have QQmlData with various references.
379 qDeleteAll(d->cachedValueTypeInstances);
380 d->cachedValueTypeInstances.clear();
381
382 v4->resetQmlEngine();
383}
384
385/*! \fn void QQmlEngine::quit()
386 This signal is emitted when the QML loaded by the engine would like to quit.
387
388 \sa exit()
389 */
390
391/*! \fn void QQmlEngine::exit(int retCode)
392 This signal is emitted when the QML loaded by the engine would like to exit
393 from the event loop with the specified return code \a retCode.
394
395 \since 5.8
396 \sa quit()
397 */
398
399
400/*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
401 This signal is emitted when \a warnings messages are generated by QML.
402 */
403
404/*!
405 Clears the engine's internal component cache.
406
407 This function causes the property metadata of most components previously
408 loaded by the engine to be destroyed. It does so by dropping unreferenced
409 components from the engine's component cache. It does not drop components that
410 are still referenced since that would almost certainly lead to crashes further
411 down the line.
412
413 If no components are referenced, this function returns the engine to a state
414 where it does not contain any loaded component data. This may be useful in
415 order to reload a smaller subset of the previous component set, or to load a
416 new version of a previously loaded component.
417
418 Once the component cache has been cleared, components must be loaded before
419 any new objects can be created.
420
421 \note Any existing objects created from QML components retain their types,
422 even if you clear the component cache. This includes singleton objects. If you
423 create more objects from the same QML code after clearing the cache, the new
424 objects will be of different types than the old ones. Assigning such a new
425 object to a property of its declared type belonging to an object created
426 before clearing the cache won't work.
427
428 As a general rule of thumb, make sure that no objects created from QML
429 components are alive when you clear the component cache.
430
431 \sa trimComponentCache(), clearSingletons()
432 */
433void QQmlEngine::clearComponentCache()
434{
435 Q_D(QQmlEngine);
436
437 // QQmlGadgetPtrWrapper can have QQmlData with various references.
438 qDeleteAll(std::exchange(d->cachedValueTypeInstances, {}));
439
440 QV4::ExecutionEngine *v4 = handle();
441
442 // Reset the values of JavaScript libraries and ECMAScript modules
443 // So that they get re-evaluated on next usage.
444 {
445 const auto cus = v4->compilationUnits();
446 for (const auto &cu : cus) {
447 cu->setValue(QV4::Value::emptyValue());
448 delete[] std::exchange(cu->imports, nullptr);
449 }
450 }
451
452 // Contexts can hold on to CUs but live on the JS heap.
453 // Use a non-incremental GC run to get rid of those.
454 QV4::MemoryManager *mm = v4->memoryManager;
455 auto oldLimit = mm->gcStateMachine->timeLimit;
456 mm->setGCTimeLimit(-1);
457 mm->runGC();
458 mm->gcStateMachine->timeLimit = std::move(oldLimit);
459
460 v4->trimCompilationUnits();
461 v4->typeLoader()->clearCache();
462 QQmlMetaType::freeUnusedTypesAndCaches();
463}
464
465/*!
466 Trims the engine's internal component cache.
467
468 This function causes the property metadata of any loaded components which are
469 not currently in use to be destroyed.
470
471 A component is considered to be in use if there are any extant instances of
472 the component itself, any instances of other components that use the component,
473 or any objects instantiated by any of those components.
474
475 \sa clearComponentCache()
476 */
477void QQmlEngine::trimComponentCache()
478{
479 QV4::ExecutionEngine *v4 = handle();
480 v4->trimCompilationUnits();
481 v4->typeLoader()->trimCache();
482}
483
484/*!
485 Clears all singletons the engine owns.
486
487 This function drops all singleton instances, deleting any QObjects owned by
488 the engine among them. This is useful to make sure that no QML-created objects
489 are left before calling clearComponentCache().
490
491 QML properties holding QObject-based singleton instances become null if the
492 engine owns the singleton or retain their value if the engine doesn't own it.
493 The singletons are not automatically re-created by accessing existing
494 QML-created objects. Only when new components are instantiated, the singletons
495 are re-created.
496
497 \sa clearComponentCache()
498 */
499void QQmlEngine::clearSingletons()
500{
501 Q_D(QQmlEngine);
502 d->singletonInstances.clear();
503}
504
505/*!
506 Returns the engine's root context.
507
508 The root context is automatically created by the QQmlEngine.
509 Data that should be available to all QML component instances
510 instantiated by the engine should be put in the root context.
511
512 Additional data that should only be available to a subset of
513 component instances should be added to sub-contexts parented to the
514 root context.
515*/
516QQmlContext *QQmlEngine::rootContext() const
517{
518 Q_D(const QQmlEngine);
519 return d->rootContext;
520}
521
522#if QT_DEPRECATED_SINCE(6, 0)
523/*!
524 \internal
525 \deprecated
526 This API is private for 5.1
527
528 Returns the last QQmlAbstractUrlInterceptor. It must not be modified outside
529 the GUI thread.
530*/
531QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
532{
533 return QQmlTypeLoader::get(this)->urlInterceptors().last();
534}
535#endif
536
537/*!
538 Adds a \a urlInterceptor to be used when resolving URLs in QML.
539 This also applies to URLs used for loading script files and QML types.
540 The URL interceptors should not be modifed while the engine is loading files,
541 or URL selection may be inconsistent. Multiple URL interceptors, when given,
542 will be called in the order they were added for each URL.
543
544 QQmlEngine does not take ownership of the interceptor and won't delete it.
545*/
546void QQmlEngine::addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
547{
548 QQmlTypeLoader::get(this)->addUrlInterceptor(urlInterceptor);
549}
550
551/*!
552 Remove a \a urlInterceptor that was previously added using
553 \l addUrlInterceptor. The URL interceptors should not be modifed while the
554 engine is loading files, or URL selection may be inconsistent.
555
556 This does not delete the interceptor, but merely removes it from the engine.
557 You can re-use it on the same or a different engine afterwards.
558*/
559void QQmlEngine::removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
560{
561 QQmlTypeLoader::get(this)->removeUrlInterceptor(urlInterceptor);
562}
563
564/*!
565 Run the current URL interceptors on the given \a url of the given \a type and
566 return the result.
567 */
568QUrl QQmlEngine::interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const
569{
570 return QQmlTypeLoader::get(this)->interceptUrl(url, type);
571}
572
573/*!
574 Returns the list of currently active URL interceptors.
575 */
576QList<QQmlAbstractUrlInterceptor *> QQmlEngine::urlInterceptors() const
577{
578 return QQmlTypeLoader::get(this)->urlInterceptors();
579}
580
581QSharedPointer<QQmlImageProviderBase> QQmlEnginePrivate::imageProvider(const QString &providerId) const
582{
583 const QString providerIdLower = providerId.toLower();
584 QMutexLocker locker(&imageProviderMutex);
585 return imageProviders.value(providerIdLower);
586}
587
588#if QT_CONFIG(qml_network)
589/*!
590 Sets the \a factory to use for creating QNetworkAccessManager(s).
591
592 QNetworkAccessManager is used for all network access by QML. By
593 implementing a factory it is possible to create custom
594 QNetworkAccessManager with specialized caching, proxy and cookie
595 support.
596
597 The factory must be set before executing the engine.
598
599 \note QQmlEngine does not take ownership of the factory.
600*/
601void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
602{
603 QQmlTypeLoader::get(this)->setNetworkAccessManagerFactory(factory);
604}
605
606class QQmlEnginePublicAPIToken {};
607
608/*!
609 Returns the current QQmlNetworkAccessManagerFactory.
610
611 \sa setNetworkAccessManagerFactory()
612*/
613QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
614{
615 return QQmlTypeLoader::get(this)->networkAccessManagerFactory().get(QQmlEnginePublicAPIToken());
616}
617
618/*!
619 Returns a common QNetworkAccessManager which can be used by any QML
620 type instantiated by this engine.
621
622 If a QQmlNetworkAccessManagerFactory has been set and a
623 QNetworkAccessManager has not yet been created, the
624 QQmlNetworkAccessManagerFactory will be used to create the
625 QNetworkAccessManager; otherwise the returned QNetworkAccessManager
626 will have no proxy or cache set.
627
628 \sa setNetworkAccessManagerFactory()
629*/
630QNetworkAccessManager *QQmlEngine::networkAccessManager() const
631{
632 return handle()->getNetworkAccessManager();
633}
634#endif // qml_network
635
636/*!
637
638 Sets the \a provider to use for images requested via the \e
639 image: url scheme, with host \a providerId. The QQmlEngine
640 takes ownership of \a provider.
641
642 Image providers enable support for pixmap and threaded image
643 requests. See the QQuickImageProvider documentation for details on
644 implementing and using image providers.
645
646 All required image providers should be added to the engine before any
647 QML sources files are loaded.
648
649 \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
650*/
651void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
652{
653 Q_D(QQmlEngine);
654 QString providerIdLower = providerId.toLower();
655 QSharedPointer<QQmlImageProviderBase> sp(provider);
656 QMutexLocker locker(&d->imageProviderMutex);
657 d->imageProviders.insert(std::move(providerIdLower), std::move(sp));
658}
659
660/*!
661 Returns the image provider set for \a providerId if found; otherwise returns \nullptr.
662
663 \sa QQuickImageProvider
664*/
665QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
666{
667 Q_D(const QQmlEngine);
668 const QString providerIdLower = providerId.toLower();
669 QMutexLocker locker(&d->imageProviderMutex);
670 return d->imageProviders.value(providerIdLower).data();
671}
672
673/*!
674 Removes the image provider for \a providerId.
675
676 \sa addImageProvider(), QQuickImageProvider
677*/
678void QQmlEngine::removeImageProvider(const QString &providerId)
679{
680 Q_D(QQmlEngine);
681 const QString providerIdLower = providerId.toLower();
682 QMutexLocker locker(&d->imageProviderMutex);
683 d->imageProviders.take(providerIdLower);
684}
685
686/*!
687 Return the base URL for this engine. The base URL is only used to
688 resolve components when a relative URL is passed to the
689 QQmlComponent constructor.
690
691 If a base URL has not been explicitly set, this method returns the
692 application's current working directory.
693
694 \sa setBaseUrl()
695*/
696QUrl QQmlEngine::baseUrl() const
697{
698 Q_D(const QQmlEngine);
699 if (d->baseUrl.isEmpty()) {
700 const QString currentPath = QDir::currentPath();
701 const QString rootPath = QDir::rootPath();
702 return QUrl::fromLocalFile((currentPath == rootPath) ? rootPath : (currentPath + QDir::separator()));
703 } else {
704 return d->baseUrl;
705 }
706}
707
708/*!
709 Set the base URL for this engine to \a url.
710
711 \sa baseUrl()
712*/
713void QQmlEngine::setBaseUrl(const QUrl &url)
714{
715 Q_D(QQmlEngine);
716 d->baseUrl = url;
717}
718
719/*!
720 Returns true if warning messages will be output to stderr in addition
721 to being emitted by the warnings() signal, otherwise false.
722
723 The default value is true.
724*/
725bool QQmlEngine::outputWarningsToStandardError() const
726{
727 Q_D(const QQmlEngine);
728 return d->outputWarningsToMsgLog;
729}
730
731/*!
732 Set whether warning messages will be output to stderr to \a enabled.
733
734 If \a enabled is true, any warning messages generated by QML will be
735 output to stderr and emitted by the warnings() signal. If \a enabled
736 is false, only the warnings() signal will be emitted. This allows
737 applications to handle warning output themselves.
738
739 The default value is true.
740*/
741void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
742{
743 Q_D(QQmlEngine);
744 d->outputWarningsToMsgLog = enabled;
745}
746
747
748/*!
749 \since 6.6
750 If this method is called inside of a function that is part of
751 a binding in QML, the binding will be treated as a translation binding.
752
753 \code
754 class I18nAwareClass : public QObject {
755
756 //...
757
758 QString text() const
759 {
760 if (auto engine = qmlEngine(this))
761 engine->markCurrentFunctionAsTranslationBinding();
762 return tr("Hello, world!");
763 }
764 };
765 \endcode
766
767 \note This function is mostly useful if you wish to provide your
768 own alternative to the qsTr function. To ensure that properties
769 exposed from C++ classes are updated on language changes, it is
770 instead recommended to react to \c LanguageChange events. That
771 is a more general mechanism which also works when the class is
772 used in a non-QML context, and has slightly less overhead. However,
773 using \c markCurrentFunctionAsTranslationBinding can be acceptable
774 when the class is already closely tied to the QML engine.
775 For more details, see \l {Prepare for Dynamic Language Changes}
776
777 \sa QQmlEngine::retranslate
778*/
779void QQmlEngine::markCurrentFunctionAsTranslationBinding()
780{
781 Q_D(QQmlEngine);
782 if (auto propertyCapture = d->propertyCapture)
783 propertyCapture->captureTranslation();
784}
785
786/*!
787 \internal
788
789 Capture the given property as part of a binding.
790 */
791void QQmlEngine::captureProperty(QObject *object, const QMetaProperty &property) const
792{
793 Q_D(const QQmlEngine);
794 if (d->propertyCapture && !property.isConstant()) {
795 d->propertyCapture->captureProperty(
796 object, property.propertyIndex(),
797 QMetaObjectPrivate::signalIndex(property.notifySignal()));
798 }
799}
800
801/*!
802 \qmlproperty string Qt::uiLanguage
803 \since 5.15
804
805 The uiLanguage holds the name of the language to be used for user interface
806 string translations. It is exposed in C++ as \l QJSEngine::uiLanguage property.
807
808 You can set the value freely and use it in bindings. It is recommended to set it
809 after installing translators in your application. By convention, an empty string
810 means no translation from the language used in the source code is intended to occur.
811
812 If you're using QQmlApplicationEngine and the value changes, QQmlEngine::retranslate()
813 will be called.
814*/
815
816/*!
817 \fn template<typename T> T QQmlEngine::singletonInstance(int qmlTypeId)
818
819 Returns the instance of a singleton type that was registered under \a qmlTypeId.
820
821 The template argument \e T may be either QJSValue or a pointer to a QObject-derived
822 type and depends on how the singleton was registered. If no instance of \e T has been
823 created yet, it is created now. If \a qmlTypeId does not represent a valid singleton
824 type, either a default constructed QJSValue or a \c nullptr is returned.
825
826 QObject* example:
827
828 \snippet code/src_qml_qqmlengine.cpp 0
829 \codeline
830 \snippet code/src_qml_qqmlengine.cpp 1
831 \codeline
832 \snippet code/src_qml_qqmlengine.cpp 2
833
834 QJSValue example:
835
836 \snippet code/src_qml_qqmlengine.cpp 3
837 \codeline
838 \snippet code/src_qml_qqmlengine.cpp 4
839
840 It is recommended to store the QML type id, e.g. as a static member in the
841 singleton class. The lookup via qmlTypeId() is costly.
842
843 \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId()
844 \since 5.12
845*/
846template<>
847QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
848{
849 Q_D(QQmlEngine);
850 QQmlType type = QQmlMetaType::qmlTypeById(qmlTypeId);
851
852 if (!type.isValid() || !type.isSingleton())
853 return QJSValue();
854
855 return d->singletonInstance<QJSValue>(type);
856}
857
858
859/*!
860 \fn template<typename T> T QQmlEngine::singletonInstance(QAnyStringView uri, QAnyStringView typeName)
861
862 \overload
863 Returns the instance of a singleton type named \a typeName from the module specified by \a uri.
864
865 This method can be used as an alternative to calling qmlTypeId followed by the id based overload of
866 singletonInstance. This is convenient when one only needs to do a one time setup of a
867 singleton; if repeated access to the singleton is required, caching its typeId will allow
868 faster subsequent access via the
869 \l {QQmlEngine::singletonInstance(int qmlTypeId)}{type-id based overload}.
870
871 The template argument \e T may be either QJSValue or a pointer to a QObject-derived
872 type and depends on how the singleton was registered. If no instance of \e T has been
873 created yet, it is created now. If \a typeName does not represent a valid singleton
874 type, either a default constructed QJSValue or a \c nullptr is returned.
875
876 \snippet code/src_qml_qqmlengine.cpp 5
877
878 \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId()
879 \since 6.5
880*/
881template<>
882QJSValue QQmlEngine::singletonInstance<QJSValue>(QAnyStringView uri, QAnyStringView typeName)
883{
884 Q_D(QQmlEngine);
885
886 auto loadHelper = QQml::makeRefPointer<LoadHelper>(
887 QQmlTypeLoader::get(this), uri, typeName, QQmlTypeLoader::Synchronous);
888 const QQmlType type = loadHelper->type();
889
890 if (!type.isSingleton())
891 return {};
892
893 return d->singletonInstance<QJSValue>(type);
894}
895
896/*!
897 Refreshes all binding expressions that use strings marked for translation.
898
899 Call this function after you have installed a new translator with
900 QCoreApplication::installTranslator, to ensure that your user-interface
901 shows up-to-date translations.
902
903 \since 5.10
904*/
905void QQmlEngine::retranslate()
906{
907 Q_D(QQmlEngine);
908 d->translationLanguage.notify();
909}
910
911/*!
912 Returns the QQmlContext for the \a object, or nullptr if no
913 context has been set.
914
915 When the QQmlEngine instantiates a QObject, an internal context is assigned
916 to it automatically. Such internal contexts are read-only. You cannot set
917 context properties on them.
918
919 \sa qmlContext(), qmlEngine(), QQmlContext::setContextProperty()
920 */
921QQmlContext *QQmlEngine::contextForObject(const QObject *object)
922{
923 if(!object)
924 return nullptr;
925
926 QQmlData *data = QQmlData::get(object);
927 if (data && data->outerContext)
928 return data->outerContext->asQQmlContext();
929
930 return nullptr;
931}
932
933/*!
934 Sets the QQmlContext for the \a object to \a context.
935 If the \a object already has a context, a warning is
936 output, but the context is not changed.
937
938 When the QQmlEngine instantiates a QObject, the context is
939 set automatically.
940 */
941void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
942{
943 if (!object || !context)
944 return;
945
946 QQmlData *data = QQmlData::get(object, true);
947 if (data->context) {
948 qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
949 return;
950 }
951
952 QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
953 Q_ASSERT(data->context == nullptr);
954 data->context = contextData.data();
955 contextData->addOwnedObject(data);
956}
957
958/*!
959 \reimp
960*/
961bool QQmlEngine::event(QEvent *e)
962{
963 if (e->type() == QEvent::LanguageChange) {
964 retranslate();
965 }
966
967 return QJSEngine::event(e);
968}
969
970void QQmlEnginePrivate::sendQuit()
971{
972 Q_Q(QQmlEngine);
973 emit q->quit();
974 if (q->receivers(SIGNAL(quit())) == 0) {
975 qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
976 }
977}
978
979void QQmlEnginePrivate::sendExit(int retCode)
980{
981 Q_Q(QQmlEngine);
982 if (q->receivers(SIGNAL(exit(int))) == 0)
983 qWarning("Signal QQmlEngine::exit() emitted, but no receivers connected to handle it.");
984 emit q->exit(retCode);
985}
986
987static void dumpwarning(const QQmlError &error)
988{
989 switch (error.messageType()) {
990 case QtDebugMsg:
991 QMessageLogger(error.url().toString().toLatin1().constData(),
992 error.line(), nullptr).debug().noquote().nospace()
993 << error.toString();
994 break;
995 case QtInfoMsg:
996 QMessageLogger(error.url().toString().toLatin1().constData(),
997 error.line(), nullptr).info().noquote().nospace()
998 << error.toString();
999 break;
1000 case QtWarningMsg:
1001 case QtFatalMsg: // fatal does not support streaming, and furthermore, is actually fatal. Probably not desirable for QML.
1002 QMessageLogger(error.url().toString().toLatin1().constData(),
1003 error.line(), nullptr).warning().noquote().nospace()
1004 << error.toString();
1005 break;
1006 case QtCriticalMsg:
1007 QMessageLogger(error.url().toString().toLatin1().constData(),
1008 error.line(), nullptr).critical().noquote().nospace()
1009 << error.toString();
1010 break;
1011 }
1012}
1013
1014static void dumpwarning(const QList<QQmlError> &errors)
1015{
1016 for (int ii = 0; ii < errors.size(); ++ii)
1017 dumpwarning(errors.at(ii));
1018}
1019
1020void QQmlEnginePrivate::warning(const QQmlError &error)
1021{
1022 Q_Q(QQmlEngine);
1023 emit q->warnings(QList<QQmlError>({error}));
1024 if (outputWarningsToMsgLog)
1025 dumpwarning(error);
1026}
1027
1028void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
1029{
1030 Q_Q(QQmlEngine);
1031 emit q->warnings(errors);
1032 if (outputWarningsToMsgLog)
1033 dumpwarning(errors);
1034}
1035
1036void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
1037{
1038 if (engine)
1039 QQmlEnginePrivate::get(engine)->warning(error);
1040 else
1041 dumpwarning(error);
1042}
1043
1044void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
1045{
1046 if (engine)
1047 QQmlEnginePrivate::get(engine)->warning(error);
1048 else
1049 dumpwarning(error);
1050}
1051
1052void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
1053{
1054 if (engine)
1055 engine->warning(error);
1056 else
1057 dumpwarning(error);
1058}
1059
1060void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
1061{
1062 if (engine)
1063 engine->warning(error);
1064 else
1065 dumpwarning(error);
1066}
1067
1068QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(
1069 const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages)
1070{
1071 QList<QQmlError> errors;
1072 for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
1073 if (m.isWarning()) {
1074 qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
1075 continue;
1076 }
1077
1078 QQmlError error;
1079 error.setUrl(QUrl(fileName));
1080 error.setDescription(m.message);
1081 error.setLine(qmlConvertSourceCoordinate<quint32, int>(m.loc.startLine));
1082 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(m.loc.startColumn));
1083 errors << error;
1084 }
1085 return errors;
1086}
1087
1088void QQmlEnginePrivate::cleanupScarceResources()
1089{
1090 // iterate through the list and release them all.
1091 // note that the actual SRD is owned by the JS engine,
1092 // so we cannot delete the SRD; but we can free the
1093 // memory used by the variant in the SRD.
1094 QV4::ExecutionEngine *engine = v4Engine.get();
1095 while (QV4::ExecutionEngine::ScarceResourceData *sr = engine->scarceResources.first()) {
1096 sr->data = QVariant();
1097 engine->scarceResources.remove(sr);
1098 }
1099}
1100
1101/*!
1102 Adds \a path as a directory where the engine searches for
1103 installed modules in a URL-based directory structure.
1104
1105 The \a path may be a local filesystem directory, a
1106 \l {The Qt Resource System}{Qt Resource} path (\c {:/imports}), a
1107 \l {The Qt Resource System}{Qt Resource} url (\c {qrc:/imports}) or a URL.
1108
1109 The \a path will be converted into canonical form before it
1110 is added to the import path list.
1111
1112 The newly added \a path will be first in the importPathList().
1113
1114 \b {See also} \l setImportPathList(), \l {QML Modules},
1115 and \l [QtQml] {QML Import Path}
1116*/
1117void QQmlEngine::addImportPath(const QString& path)
1118{
1119 QQmlTypeLoader::get(this)->addImportPath(path);
1120}
1121
1122/*!
1123 Returns the list of directories where the engine searches for
1124 installed modules in a URL-based directory structure.
1125
1126 For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
1127 imports \c com.mycompany.Feature will cause the QQmlEngine to look
1128 in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
1129 provided by that module. A \c qmldir file is required for defining the
1130 type version mapping and possibly QML extensions plugins.
1131
1132 By default, this list contains the paths mentioned in
1133 \l {QML Import Path}.
1134
1135 \sa addImportPath(), setImportPathList()
1136*/
1137QStringList QQmlEngine::importPathList() const
1138{
1139 return QQmlTypeLoader::get(this)->importPathList();
1140}
1141
1142/*!
1143 Sets \a paths as the list of directories where the engine searches for
1144 installed modules in a URL-based directory structure.
1145
1146 By default, this list contains the paths mentioned in
1147 \l {QML Import Path}.
1148
1149 \warning Calling setImportPathList does not preserve the default
1150 import paths.
1151
1152 \sa importPathList(), addImportPath()
1153 */
1154void QQmlEngine::setImportPathList(const QStringList &paths)
1155{
1156 QQmlTypeLoader::get(this)->setImportPathList(paths);
1157}
1158
1159
1160/*!
1161 Adds \a path as a directory where the engine searches for
1162 native plugins for imported modules (referenced in the \c qmldir file).
1163
1164 By default, the list contains only \c ., i.e. the engine searches
1165 in the directory of the \c qmldir file itself.
1166
1167 The newly added \a path will be first in the pluginPathList().
1168
1169 \sa setPluginPathList()
1170*/
1171void QQmlEngine::addPluginPath(const QString& path)
1172{
1173 QQmlTypeLoader::get(this)->addPluginPath(path);
1174}
1175
1176/*!
1177 Returns the list of directories where the engine searches for
1178 native plugins for imported modules (referenced in the \c qmldir file).
1179
1180 By default, the list contains only \c ., i.e. the engine searches
1181 in the directory of the \c qmldir file itself.
1182
1183 \sa addPluginPath(), setPluginPathList()
1184*/
1185QStringList QQmlEngine::pluginPathList() const
1186{
1187 return QQmlTypeLoader::get(this)->pluginPathList();
1188}
1189
1190/*!
1191 Sets the list of directories where the engine searches for
1192 native plugins for imported modules (referenced in the \c qmldir file)
1193 to \a paths.
1194
1195 By default, the list contains only \c ., i.e. the engine searches
1196 in the directory of the \c qmldir file itself.
1197
1198 \sa pluginPathList(), addPluginPath()
1199 */
1200void QQmlEngine::setPluginPathList(const QStringList &paths)
1201{
1202 QQmlTypeLoader::get(this)->setPluginPathList(paths);
1203}
1204
1205#if QT_CONFIG(library)
1206#if QT_DEPRECATED_SINCE(6, 4)
1207/*!
1208 \deprecated [6.4] Import the module from QML with an "import" statement instead.
1209
1210 Imports the plugin named \a filePath with the \a uri provided.
1211 Returns true if the plugin was successfully imported; otherwise returns false.
1212
1213 On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
1214
1215 The plugin has to be a Qt plugin which implements the QQmlEngineExtensionPlugin interface.
1216
1217 \note Directly loading plugins like this can confuse the module import logic. In order to make
1218 the import logic load plugins from a specific place, you can use \l addPluginPath(). Each
1219 plugin should be part of a QML module that you can import using the "import" statement.
1220*/
1221bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
1222{
1223 QQmlTypeLoaderQmldirContent qmldir;
1224 QQmlPluginImporter importer(uri, QTypeRevision(), &qmldir, QQmlTypeLoader::get(this), errors);
1225 return importer.importDynamicPlugin(filePath, uri, false).isValid();
1226}
1227#endif
1228#endif
1229
1230/*!
1231 \property QQmlEngine::offlineStoragePath
1232 \brief the directory for storing offline user data
1233
1234 Returns the directory where SQL and other offline
1235 storage is placed.
1236
1237 The SQL databases created with \c openDatabaseSync() are stored here.
1238
1239 The default is QML/OfflineStorage in the platform-standard
1240 user application data directory.
1241
1242 Note that the path may not currently exist on the filesystem, so
1243 callers wanting to \e create new files at this location should create
1244 it first - see QDir::mkpath().
1245
1246 \sa {Qt Quick Local Storage QML Types}
1247*/
1248
1249/*!
1250 \fn void QQmlEngine::offlineStoragePathChanged()
1251 This signal is emitted when \l offlineStoragePath changes.
1252 \since 6.5
1253*/
1254
1255void QQmlEngine::setOfflineStoragePath(const QString& dir)
1256{
1257 Q_D(QQmlEngine);
1258 if (dir == d->offlineStoragePath)
1259 return;
1260 d->offlineStoragePath = dir;
1261 Q_EMIT offlineStoragePathChanged();
1262}
1263
1264QString QQmlEngine::offlineStoragePath() const
1265{
1266 Q_D(const QQmlEngine);
1267
1268 if (d->offlineStoragePath.isEmpty()) {
1269 QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
1270 QQmlEnginePrivate *e = const_cast<QQmlEnginePrivate *>(d);
1271 if (!dataLocation.isEmpty()) {
1272 e->offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
1273 + QDir::separator() + QLatin1String("QML")
1274 + QDir::separator() + QLatin1String("OfflineStorage");
1275 Q_EMIT e->q_func()->offlineStoragePathChanged();
1276 }
1277 }
1278
1279 return d->offlineStoragePath;
1280}
1281
1282/*!
1283 Returns the file path where a \l{QtQuick.LocalStorage}{Local Storage}
1284 database with the identifier \a databaseName is (or would be) located.
1285
1286 \sa {openDatabaseSync}{LocalStorage.openDatabaseSync()}
1287 \since 5.9
1288*/
1289QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName) const
1290{
1291 Q_D(const QQmlEngine);
1292 QCryptographicHash md5(QCryptographicHash::Md5);
1293 md5.addData(databaseName.toUtf8());
1294 return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex());
1295}
1296
1297QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
1298{
1299 Q_Q(const QQmlEngine);
1300 return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator();
1301}
1302
1303static bool hasRequiredProperties(const QQmlPropertyCache::ConstPtr &propertyCache)
1304{
1305 bool requiredPropertiesFound = false;
1306 // we don't expect to find any, so the loop has no early termination check
1307 if (propertyCache) {
1308 for (int idx = 0, count = propertyCache->propertyCount(); idx < count; ++idx)
1309 requiredPropertiesFound |= propertyCache->property(idx)->isRequired();
1310 }
1311 return requiredPropertiesFound;
1312}
1313
1314template<>
1315QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
1316{
1317 Q_Q(QQmlEngine);
1318
1319 QQmlType::SingletonInstanceInfo::ConstPtr siinfo = type.singletonInstanceInfo();
1320 Q_ASSERT(siinfo != nullptr);
1321
1322 QJSValue value = singletonInstances.value(siinfo);
1323 if (!value.isUndefined())
1324 return value;
1325
1326 if (siinfo->scriptCallback) {
1327 value = siinfo->scriptCallback(q, q);
1328 if (value.isQObject()) {
1329 QObject *o = value.toQObject();
1330 // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
1331 // should behave identically to QML singleton types.
1332 q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
1333 }
1334 singletonInstances.convertAndInsert(v4Engine.get(), siinfo, &value);
1335
1336 } else if (siinfo->qobjectCallback) {
1337 QObject *o = siinfo->qobjectCallback(q, q);
1338 if (!o) {
1339 QQmlError error;
1340 error.setMessageType(QtMsgType::QtCriticalMsg);
1341 error.setDescription(QString::asprintf("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.",
1342 qPrintable(QString::fromUtf8(type.typeName()))));
1343 warning(error);
1344 } else {
1345 type.createProxy(o);
1346
1347 // if this object can use a property cache, create it now
1348 QQmlPropertyCache::ConstPtr propertyCache = QQmlData::ensurePropertyCache(o);
1349 if (Q_UNLIKELY(hasRequiredProperties(propertyCache))) {
1350 // there's no way to set required properties on a singleton
1351 delete o;
1352 o = nullptr;
1353 QQmlError error;
1354 error.setMessageType(QtMsgType::QtCriticalMsg);
1355 error.setDescription(QString::asprintf("Singleton \"%s\" is not available because the type has unset required properties.",
1356 qPrintable(QString::fromUtf8(type.typeName()))));
1357 warning(error);
1358 } else {
1359 // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
1360 // should behave identically to QML singleton types. You can, however, manually
1361 // assign a context; and clearSingletons() retains the contexts, in which case
1362 // we don't want to see warnings about the object already having a context.
1363 QQmlData *data = QQmlData::get(o, true);
1364 if (!data->context) {
1365 auto contextData = QQmlContextData::get(new QQmlContext(q->rootContext(), q));
1366 data->context = contextData.data();
1367 contextData->addOwnedObject(data);
1368 }
1369 }
1370 }
1371
1372 value = q->newQObject(o);
1373 singletonInstances.convertAndInsert(v4Engine.get(), siinfo, &value);
1374 } else if (!siinfo->url.isEmpty()) {
1375 QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
1376 if (component.isError()) {
1377 warning(component.errors());
1378 v4Engine->throwError(
1379 QLatin1String("Due to the preceding error(s), "
1380 "Singleton \"%1\" could not be loaded.")
1381 .arg(QString::fromUtf8(type.typeName())));
1382
1383 return QJSValue(QJSValue::UndefinedValue);
1384 }
1385 QObject *o = component.beginCreate(q->rootContext());
1386 auto *compPriv = QQmlComponentPrivate::get(&component);
1387 if (compPriv->hasUnsetRequiredProperties()) {
1388 /* We would only get the errors from the component after (complete)Create.
1389 We can't call create, as we need to convertAndInsert before completeCreate (otherwise
1390 tst_qqmllanguage::compositeSingletonCircular fails).
1391 On the other hand, we don't want to call cnovertAndInsert if we have an error
1392 So create the unset required component errors manually.
1393 */
1394 delete o;
1395 const auto requiredProperties = compPriv->requiredProperties();
1396 QList<QQmlError> errors (requiredProperties->size());
1397 for (const auto &reqProp: *requiredProperties)
1398 errors.push_back(QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(reqProp));
1399 warning(errors);
1400 v4Engine->throwError(
1401 QLatin1String("Due to the preceding error(s), "
1402 "Singleton \"%1\" could not be loaded.")
1403 .arg(QString::fromUtf8(type.typeName())));
1404 return QJSValue(QJSValue::UndefinedValue);
1405 }
1406
1407 value = q->newQObject(o);
1408 singletonInstances.convertAndInsert(v4Engine.get(), siinfo, &value);
1409 component.completeCreate();
1410 }
1411
1412 return value;
1413}
1414
1415void QQmlEnginePrivate::executeRuntimeFunction(const QUrl &url, qsizetype functionIndex,
1416 QObject *thisObject, int argc, void **args,
1417 QMetaType *types)
1418{
1419 const auto unit = compilationUnitFromUrl(url);
1420 if (!unit)
1421 return;
1422 executeRuntimeFunction(unit, functionIndex, thisObject, argc, args, types);
1423}
1424
1425void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationUnit *unit,
1426 qsizetype functionIndex, QObject *thisObject,
1427 int argc, void **args, QMetaType *types)
1428{
1429 Q_ASSERT(unit);
1430 Q_ASSERT((functionIndex >= 0) && (functionIndex < unit->runtimeFunctions.size()));
1431 Q_ASSERT(thisObject);
1432
1433 QQmlData *ddata = QQmlData::get(thisObject);
1434 Q_ASSERT(ddata && ddata->context);
1435
1436 QV4::Function *function = unit->runtimeFunctions[functionIndex];
1437 Q_ASSERT(function);
1438 Q_ASSERT(function->compiledFunction);
1439
1440 QV4::ExecutionEngine *v4 = v4Engine.get();
1441
1442 // NB: always use scriptContext() by default as this method ignores whether
1443 // there's already a stack frame (except when dealing with closures). the
1444 // method is called from C++ (through QQmlEngine::executeRuntimeFunction())
1445 // and thus the caller must ensure correct setup
1446 QV4::Scope scope(v4);
1447 QV4::ExecutionContext *ctx = v4->scriptContext();
1448 QV4::Scoped<QV4::ExecutionContext> callContext(scope,
1449 QV4::QmlContext::create(ctx, ddata->context, thisObject));
1450
1451 if (auto nested = function->nestedFunction()) {
1452 // if a nested function is already known, call the closure directly
1453 function = nested;
1454 } else if (function->isClosureWrapper()) {
1455 // if there is a nested function, but we don't know it, we need to call
1456 // an outer function first and then the inner function. we fetch the
1457 // return value of a function call (that is a closure) by calling a
1458 // different version of ExecutionEngine::callInContext() that returns a
1459 // QV4::ReturnedValue with no arguments since they are not needed by the
1460 // outer function anyhow
1461 QV4::Scoped<QV4::JavaScriptFunctionObject> result(scope,
1462 v4->callInContext(function, thisObject, callContext, 0, nullptr));
1463 Q_ASSERT(result->function());
1464 Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
1465
1466 // overwrite the function and its context
1467 function = result->function();
1468 callContext = QV4::Scoped<QV4::ExecutionContext>(scope, result->scope());
1469 }
1470
1471 v4->callInContext(function, thisObject, callContext, argc, args, types);
1472}
1473
1474QV4::ExecutableCompilationUnit *QQmlEnginePrivate::compilationUnitFromUrl(const QUrl &url)
1475{
1476 QV4::ExecutionEngine *v4 = v4Engine.get();
1477 if (auto unit = v4->compilationUnitForUrl(url)) {
1478 if (!unit->runtimeStrings)
1479 unit->populate();
1480 return unit.data();
1481 }
1482
1483 auto unit = v4->typeLoader()->getType(url)->compilationUnit();
1484 if (!unit)
1485 return nullptr;
1486
1487 auto executable = v4->executableCompilationUnit(std::move(unit));
1488 executable->populate();
1489 return executable.data();
1490}
1491
1492QQmlRefPointer<QQmlContextData>
1493QQmlEnginePrivate::createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
1494 const QQmlRefPointer<QQmlContextData> &parentContext,
1495 int subComponentIndex, bool isComponentRoot)
1496{
1497 Q_ASSERT(unit);
1498
1499 QQmlRefPointer<QQmlContextData> context;
1500 context = QQmlContextData::createRefCounted(parentContext);
1501 context->setInternal(true);
1502 context->setImports(unit->typeNameCache());
1503 context->initFromTypeCompilationUnit(unit, subComponentIndex);
1504
1505 const auto *dependentScripts = unit->dependentScriptsPtr();
1506 const qsizetype dependentScriptsSize = dependentScripts->size();
1507 if (isComponentRoot && dependentScriptsSize) {
1508 QV4::ExecutionEngine *v4 = v4Engine.get();
1509 Q_ASSERT(v4);
1510 QV4::Scope scope(v4);
1511
1512 QV4::ScopedObject scripts(scope, v4->newArrayObject(dependentScriptsSize));
1513 context->setImportedScripts(v4, scripts);
1514 QV4::ScopedValue v(scope);
1515 for (qsizetype i = 0; i < dependentScriptsSize; ++i)
1516 scripts->put(i, (v = dependentScripts->at(i)->scriptValueForContext(context)));
1517 }
1518
1519 return context;
1520}
1521
1522/*!
1523 \fn QQmlEngine *qmlEngine(const QObject *object)
1524 \relates QQmlEngine
1525
1526 Returns the QQmlEngine associated with \a object, if any. This is equivalent to
1527 QQmlEngine::contextForObject(object)->engine(), but more efficient.
1528
1529 \note Add \c{#include <QtQml>} to use this function.
1530
1531 \sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlContext()
1532*/
1533
1534/*!
1535 \fn QQmlContext *qmlContext(const QObject *object)
1536 \relates QQmlEngine
1537
1538 Returns the QQmlContext associated with \a object, if any. This is equivalent to
1539 QQmlEngine::contextForObject(object).
1540
1541 \note Add \c{#include <QtQml>} to use this function.
1542
1543 \sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlEngine()
1544*/
1545
1546void hasJsOwnershipIndicator(QQmlGuardImpl *) {};
1547
1548LoadHelper::LoadHelper(
1549 QQmlTypeLoader *loader, QAnyStringView uri, QAnyStringView typeName,
1550 QQmlTypeLoader::Mode mode)
1552 , m_uri(uri.toString())
1554 , m_mode(mode)
1555{
1556 m_typeLoader->loadWithStaticData(this, QByteArray(), m_mode);
1557}
1558
1559void LoadHelper::registerCallback(QQmlComponentPrivate *callback)
1560{
1561 m_callback = callback;
1562}
1563
1564void LoadHelper::unregisterCallback(QQmlComponentPrivate *callback)
1565{
1566 if (m_callback) {
1567 Q_ASSERT(callback == m_callback);
1568 m_callback = nullptr;
1569 }
1570}
1571
1572void LoadHelper::done()
1573{
1574 if (!couldFindModule()) {
1575 m_resolveTypeResult = ResolveTypeResult::NoSuchModule;
1576 return;
1577 }
1578
1579 QQmlTypeModule *module = QQmlMetaType::typeModule(m_uri, QTypeRevision{});
1580 if (module) {
1581 m_type = module->type(m_typeName, {});
1582 if (m_type.isValid()) {
1583 m_resolveTypeResult = ResolveTypeResult::ModuleFound;
1584 return;
1585 }
1586 }
1587
1588 // The module exists (see check above), but there is no QQmlTypeModule
1589 // ==> pure QML module, attempt resolveType
1590 QTypeRevision versionReturn;
1591 QList<QQmlError> errors;
1592 QQmlImportNamespace *ns_return = nullptr;
1593 m_importCache->resolveType(
1594 typeLoader(), m_typeName, &m_type, &versionReturn, &ns_return, &errors);
1595 m_resolveTypeResult = ResolveTypeResult::ModuleFound;
1596}
1597
1598void LoadHelper::completed()
1599{
1600 QQmlTypeLoader::Blob::completed();
1601
1602 if (m_callback) {
1603 m_callback->completeLoadFromModule(m_uri, m_typeName);
1604 m_callback = nullptr;
1605 }
1606}
1607
1608void LoadHelper::dataReceived(const SourceCodeData &)
1609{
1610 auto import = std::make_shared<PendingImport>();
1611 import->uri = m_uri;
1612 QList<QQmlError> errorList;
1613 if (!Blob::addImport(import, &errorList)) {
1614 qCDebug(lcQmlImport) << "LoadHelper: Errors loading " << m_uri << errorList;
1615 m_uri.clear(); // reset m_uri to remember the failure
1616 }
1617}
1618
1619bool LoadHelper::couldFindModule() const
1620{
1621 if (m_uri.isEmpty())
1622 return false;
1623 for (const auto &import: std::as_const(m_unresolvedImports))
1624 if (import->priority == 0) // compare QQmlTypeData::allDependenciesDone
1625 return false;
1626 return true;
1627}
1628
1629QT_END_NAMESPACE
1630
1631#include "moc_qqmlengine.cpp"
Combined button and popup list for selecting options.
static bool hasRequiredProperties(const QQmlPropertyCache::ConstPtr &propertyCache)
static void dumpwarning(const QQmlError &error)
void hasJsOwnershipIndicator(QQmlGuardImpl *)
void qml_register_types_QML()
int qmlRegisterType< void >(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri, QAnyStringView typeName, QQmlTypeLoader::Mode mode)
void dataReceived(const SourceCodeData &) final
Invoked when data for the blob is received.
void completed() final
Invoked on the main thread sometime after done() was called on the load thread.
void registerCallback(QQmlComponentPrivate *callback)
void unregisterCallback(QQmlComponentPrivate *callback)
void done() final
Invoked once data has either been received or a network error occurred, and all dependencies are comp...