1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlengine_p.h"
41#include "qqmlengine.h"
42#include "qqmlcomponentattached_p.h"
43
44#include "qqmlcontext_p.h"
45#include "qqml.h"
46#include "qqmlcontext.h"
47#include "qqmlexpression.h"
48#include "qqmlcomponent.h"
49#include "qqmlvme_p.h"
50#include "qqmlstringconverters_p.h"
51#include "qqmlscriptstring.h"
52#include "qqmlglobal_p.h"
53#include "qqmlcomponent_p.h"
54#include "qqmlextensioninterface.h"
55#include "qqmllist_p.h"
56#include "qqmltypenamecache_p.h"
57#include "qqmlnotifier_p.h"
58#include "qqmlincubator.h"
59#include "qqmlabstracturlinterceptor.h"
60#include "qqmlsourcecoordinate_p.h"
61#include <private/qqmldirparser_p.h>
62#include <private/qqmlboundsignal_p.h>
63#include <private/qqmljsdiagnosticmessage_p.h>
64#include <QtCore/qstandardpaths.h>
65#include <QtCore/qsettings.h>
66#include <QtCore/qmetaobject.h>
67#include <QDebug>
68#include <QtCore/qcoreapplication.h>
69#include <QtCore/qcryptographichash.h>
70#include <QtCore/qdir.h>
71#include <QtCore/qmutex.h>
72#include <QtCore/qthread.h>
73#include <private/qthread_p.h>
74
75#if QT_CONFIG(qml_network)
76#include "qqmlnetworkaccessmanagerfactory.h"
77#include <QNetworkAccessManager>
78#include <QtNetwork/qnetworkconfigmanager.h>
79#endif
80
81#include <private/qobject_p.h>
82#include <private/qmetaobject_p.h>
83#if QT_CONFIG(qml_locale)
84#include <private/qqmllocale_p.h>
85#endif
86#include <private/qqmlbind_p.h>
87#include <private/qqmlconnections_p.h>
88#if QT_CONFIG(qml_animation)
89#include <private/qqmltimer_p.h>
90#endif
91#include <private/qqmlplatform_p.h>
92#include <private/qqmlloggingcategory_p.h>
93
94#ifdef Q_OS_WIN // for %APPDATA%
95# include <qt_windows.h>
96# ifndef Q_OS_WINRT
97# include <shlobj.h>
98# endif
99# include <qlibrary.h>
100# ifndef CSIDL_APPDATA
101# define CSIDL_APPDATA 0x001a // <username>\Application Data
102# endif
103#endif // Q_OS_WIN
104
105QT_BEGIN_NAMESPACE
106
107// Declared in qqml.h
108int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
109 const char *uri, int versionMajor,
110 int versionMinor, const char *qmlName,
111 const QString& reason)
112{
113 QQmlPrivate::RegisterType type = {
114 .version: 0,
115
116 .typeId: 0,
117 .listId: 0,
118 .objectSize: 0,
119 .create: nullptr,
120 .noCreationReason: reason,
121
122 .uri: uri, .versionMajor: versionMajor, .versionMinor: versionMinor, .elementName: qmlName, .metaObject: &staticMetaObject,
123
124 .attachedPropertiesFunction: QQmlAttachedPropertiesFunc(),
125 .attachedPropertiesMetaObject: nullptr,
126
127 .parserStatusCast: 0,
128 .valueSourceCast: 0,
129 .valueInterceptorCast: 0,
130
131 .extensionObjectCreate: nullptr, .extensionMetaObject: nullptr,
132
133 .customParser: nullptr,
134 .revision: 0
135 };
136
137 return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
138}
139
140/*!
141 \qmltype QtObject
142 \instantiates QObject
143 \inqmlmodule QtQml
144 \ingroup qml-utility-elements
145 \brief A basic QML type.
146
147 The QtObject type is a non-visual element which contains only the
148 objectName property.
149
150 It can be useful to create a QtObject if you need an extremely
151 lightweight type to enclose a set of custom properties:
152
153 \snippet qml/qtobject.qml 0
154
155 It can also be useful for C++ integration, as it is just a plain
156 QObject. See the QObject documentation for further details.
157*/
158/*!
159 \qmlproperty string QtObject::objectName
160 This property holds the QObject::objectName for this specific object instance.
161
162 This allows a C++ application to locate an item within a QML component
163 using the QObject::findChild() method. For example, the following C++
164 application locates the child \l Rectangle item and dynamically changes its
165 \c color value:
166
167 \qml
168 // MyRect.qml
169
170 import QtQuick 2.0
171
172 Item {
173 width: 200; height: 200
174
175 Rectangle {
176 anchors.fill: parent
177 color: "red"
178 objectName: "myRect"
179 }
180 }
181 \endqml
182
183 \code
184 // main.cpp
185
186 QQuickView view;
187 view.setSource(QUrl::fromLocalFile("MyRect.qml"));
188 view.show();
189
190 QQuickItem *item = view.rootObject()->findChild<QQuickItem*>("myRect");
191 if (item)
192 item->setProperty("color", QColor(Qt::yellow));
193 \endcode
194*/
195
196bool QQmlEnginePrivate::qml_debugging_enabled = false;
197bool QQmlEnginePrivate::s_designerMode = false;
198
199#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
200void QQmlEnginePrivate::registerQuickTypes()
201{
202 // Don't add anything here. These are only for backwards compatibility.
203 // Also, don't use qmlRegisterTypesAndRevisions as that will auto-add future revisions.
204
205 const char uri[] = "QtQuick";
206
207 qmlRegisterType<QQmlComponent>(uri, versionMajor: 2, versionMinor: 0, qmlName: "Component");
208 qmlRegisterType<QObject>(uri, versionMajor: 2, versionMinor: 0, qmlName: "QtObject");
209 qmlRegisterType<QQmlBind>(uri, versionMajor: 2, versionMinor: 0, qmlName: "Binding");
210 qmlRegisterType<QQmlBind, 8>(uri, versionMajor: 2, versionMinor: 8, qmlName: "Binding");
211 qmlRegisterCustomType<QQmlConnections>(uri, versionMajor: 2, versionMinor: 0, qmlName: "Connections", parser: new QQmlConnectionsParser);
212
213 // Connections revision 3 was added in QtQml 2.3, but only in QtQuick 2.7.
214 qmlRegisterCustomType<QQmlConnections, 3>(uri, versionMajor: 2, versionMinor: 7, qmlName: "Connections", parser: new QQmlConnectionsParser);
215
216#if QT_CONFIG(qml_animation)
217 qmlRegisterType<QQmlTimer>(uri, versionMajor: 2, versionMinor: 0,qmlName: "Timer");
218#endif
219 qmlRegisterType<QQmlLoggingCategory>(uri, versionMajor: 2, versionMinor: 8, qmlName: "LoggingCategory");
220 qmlRegisterType<QQmlLoggingCategory, 12>(uri, versionMajor: 2, versionMinor: 12, qmlName: "LoggingCategory");
221#if QT_CONFIG(qml_locale)
222 // Locale was added in QtQuick 2.0 and in QtQml 2.2
223 qmlRegisterUncreatableType<QQmlLocale>(uri, versionMajor: 2, versionMinor: 0, qmlName: "Locale", reason: QQmlEngine::tr(s: "Locale cannot be instantiated. Use Qt.locale()"));
224#endif
225}
226#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
227
228bool QQmlEnginePrivate::designerMode()
229{
230 return s_designerMode;
231}
232
233void QQmlEnginePrivate::activateDesignerMode()
234{
235 s_designerMode = true;
236}
237
238
239/*!
240 \class QQmlImageProviderBase
241 \brief The QQmlImageProviderBase class is used to register image providers in the QML engine.
242 \inmodule QtQml
243
244 Image providers must be registered with the QML engine. The only information the QML
245 engine knows about image providers is the type of image data they provide. To use an
246 image provider to acquire image data, you must cast the QQmlImageProviderBase pointer
247 to a QQuickImageProvider pointer.
248
249 \sa QQuickImageProvider, QQuickTextureFactory
250*/
251
252/*!
253 \enum QQmlImageProviderBase::ImageType
254
255 Defines the type of image supported by this image provider.
256
257 \value Image The Image Provider provides QImage images.
258 The QQuickImageProvider::requestImage() method will be called for all image requests.
259 \value Pixmap The Image Provider provides QPixmap images.
260 The QQuickImageProvider::requestPixmap() method will be called for all image requests.
261 \value Texture The Image Provider provides QSGTextureProvider based images.
262 The QQuickImageProvider::requestTexture() method will be called for all image requests.
263 \value ImageResponse The Image provider provides QQuickTextureFactory based images.
264 Should only be used in QQuickAsyncImageProvider or its subclasses.
265 The QQuickAsyncImageProvider::requestImageResponse() method will be called for all image requests.
266 Since Qt 5.6
267 \omitvalue Invalid
268*/
269
270/*!
271 \enum QQmlImageProviderBase::Flag
272
273 Defines specific requirements or features of this image provider.
274
275 \value ForceAsynchronousImageLoading Ensures that image requests to the provider are
276 run in a separate thread, which allows the provider to spend as much time as needed
277 on producing the image without blocking the main thread.
278*/
279
280/*!
281 \fn QQmlImageProviderBase::imageType() const
282
283 Implement this method to return the image type supported by this image provider.
284*/
285
286/*!
287 \fn QQmlImageProviderBase::flags() const
288
289 Implement this to return the properties of this image provider.
290*/
291
292/*! \internal */
293QQmlImageProviderBase::QQmlImageProviderBase()
294{
295}
296
297/*! \internal */
298QQmlImageProviderBase::~QQmlImageProviderBase()
299{
300}
301
302
303/*!
304\qmltype Qt
305\inqmlmodule QtQml
306\instantiates QQmlEnginePrivate
307\ingroup qml-utility-elements
308\keyword QmlGlobalQtObject
309\brief Provides a global object with useful enums and functions from Qt.
310
311The \c Qt object is a global object with utility functions, properties and enums.
312
313It is not instantiable; to use it, call the members of the global \c Qt object directly.
314For example:
315
316\qml
317import QtQuick 2.0
318
319Text {
320 color: Qt.rgba(1, 0, 0, 1)
321 text: Qt.md5("hello, world")
322}
323\endqml
324
325
326\section1 Enums
327
328The Qt object contains the enums available in the \l [QtCore]{Qt}{Qt Namespace}. For example, you can access
329the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftButton and \c Qt.RightButton.
330
331
332\section1 Types
333
334The Qt object also contains helper functions for creating objects of specific
335data types. This is primarily useful when setting the properties of an item
336when the property has one of the following types:
337\list
338\li \c rect - use \l{Qt::rect()}{Qt.rect()}
339\li \c point - use \l{Qt::point()}{Qt.point()}
340\li \c size - use \l{Qt::size()}{Qt.size()}
341\endlist
342
343If the \c QtQuick module has been imported, the following helper functions for
344creating objects of specific data types are also available for clients to use:
345\list
346\li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
347\li \c font - use \l{Qt::font()}{Qt.font()}
348\li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()}
349\li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
350\li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()}
351\li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()}
352\li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()}
353\endlist
354
355There are also string based constructors for these types. See \l{qtqml-typesystem-basictypes.html}{QML Basic Types} for more information.
356
357\section1 Date/Time Formatters
358
359The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
360
361\list
362 \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
363 \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
364 \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
365\endlist
366
367The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
368
369
370\section1 Dynamic Object Creation
371The following functions on the global object allow you to dynamically create QML
372items from files or strings. See \l{Dynamic QML Object Creation from JavaScript} for an overview
373of their use.
374
375\list
376 \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
377 \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
378\endlist
379
380
381\section1 Other Functions
382
383The following functions are also on the Qt object.
384
385\list
386 \li \l{Qt::quit()}{Qt.quit()}
387 \li \l{Qt::md5()}{Qt.md5(string)}
388 \li \l{Qt::btoa()}{string Qt.btoa(string)}
389 \li \l{Qt::atob()}{string Qt.atob(string)}
390 \li \l{Qt::binding()}{object Qt.binding(function)}
391 \li \l{Qt::locale()}{object Qt.locale()}
392 \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
393 \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
394 \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
395\endlist
396*/
397
398/*!
399 \qmlproperty object Qt::platform
400 \since 5.1
401
402 The \c platform object provides info about the underlying platform.
403
404 Its properties are:
405
406 \table
407 \row
408 \li \c platform.os
409 \li
410
411 This read-only property contains the name of the operating system.
412
413 Possible values are:
414
415 \list
416 \li \c "android" - Android
417 \li \c "ios" - iOS
418 \li \c "tvos" - tvOS
419 \li \c "linux" - Linux
420 \li \c "osx" - \macos
421 \li \c "qnx" - QNX (since Qt 5.9.3)
422 \li \c "unix" - Other Unix-based OS
423 \li \c "windows" - Windows
424 \li \c "winrt" - WinRT / UWP
425 \li \c "wasm" - WebAssembly
426 \endlist
427
428 \row
429 \li \c platform.pluginName
430 \li This is the name of the platform set on the QGuiApplication instance
431 as returned by \l QGuiApplication::platformName()
432
433 \endtable
434*/
435
436/*!
437 \qmlproperty object Qt::application
438 \since 5.1
439
440 The \c application object provides access to global application state
441 properties shared by many QML components.
442
443 Its properties are:
444
445 \table
446 \row
447 \li \c application.active
448 \li
449 Deprecated, use Qt.application.state == Qt.ApplicationActive instead.
450
451 \row
452 \li \c application.state
453 \li
454 This read-only property indicates the current state of the application.
455
456 Possible values are:
457
458 \list
459 \li Qt.ApplicationActive - The application is the top-most and focused application, and the
460 user is able to interact with the application.
461 \li Qt.ApplicationInactive - The application is visible or partially visible, but not selected
462 to be in front, the user cannot interact with the application.
463 On desktop platforms, this typically means that the user activated
464 another application. On mobile platforms, it is more common to
465 enter this state when the OS is interrupting the user with for
466 example incoming calls, SMS-messages or dialogs. This is usually a
467 transient state during which the application is paused. The user
468 may return focus to your application, but most of the time it will
469 be the first indication that the application is going to be suspended.
470 While in this state, consider pausing or stopping any activity that
471 should not continue when the user cannot interact with your
472 application, such as a video, a game, animations, or sensors.
473 You should also avoid performing CPU-intensive tasks which might
474 slow down the application in front.
475 \li Qt.ApplicationSuspended - The application is suspended and not visible to the user. On
476 mobile platforms, the application typically enters this state when
477 the user returns to the home screen or switches to another
478 application. While in this state, the application should ensure
479 that the user perceives it as always alive and does not lose his
480 progress, saving any persistent data. The application should cease
481 all activities and be prepared for code execution to stop. While
482 suspended, the application can be killed at any time without
483 further warnings (for example when low memory forces the OS to purge
484 suspended applications).
485 \li Qt.ApplicationHidden - The application is hidden and runs in the background. This is the
486 normal state for applications that need to do background processing,
487 like playing music, while the user interacts with other applications.
488 The application should free up all graphical resources when entering
489 this state. A Qt Quick application should not usually handle this state
490 at the QML level. Instead, you should unload the entire UI and reload
491 the QML files whenever the application becomes active again.
492 \endlist
493
494 \row
495 \li \c application.layoutDirection
496 \li
497 This read-only property can be used to query the default layout direction of the
498 application. On system start-up, the default layout direction depends on the
499 application's language. The property has a value of \c Qt.RightToLeft in locales
500 where text and graphic elements are read from right to left, and \c Qt.LeftToRight
501 where the reading direction flows from left to right. You can bind to this
502 property to customize your application layouts to support both layout directions.
503
504 Possible values are:
505
506 \list
507 \li Qt.LeftToRight - Text and graphics elements should be positioned
508 from left to right.
509 \li Qt.RightToLeft - Text and graphics elements should be positioned
510 from right to left.
511 \endlist
512 \row
513 \li \c application.font
514 \li This read-only property holds the default application font as
515 returned by \l QGuiApplication::font().
516 \row
517 \li \c application.arguments
518 \li This is a string list of the arguments the executable was invoked with.
519 \row
520 \li \c application.name
521 \li This is the application name set on the QCoreApplication instance. This property can be written
522 to in order to set the application name.
523 \row
524 \li \c application.displayName (since Qt 5.9)
525 \li This is the application display name set on the QGuiApplication instance. This property can be written
526 to in order to set the application display name.
527 \row
528 \li \c application.version
529 \li This is the application version set on the QCoreApplication instance. This property can be written
530 to in order to set the application version.
531 \row
532 \li \c application.organization
533 \li This is the organization name set on the QCoreApplication instance. This property can be written
534 to in order to set the organization name.
535 \row
536 \li \c application.domain
537 \li This is the organization domain set on the QCoreApplication instance. This property can be written
538 to in order to set the organization domain.
539
540 \row
541 \li \c application.supportsMultipleWindows
542 \li This read-only property can be used to determine whether or not the
543 platform supports multiple windows. Some embedded platforms do not support
544 multiple windows, for example.
545
546 \row
547 \li \c application.screens
548 \li An array containing the descriptions of all connected screens. The
549 elements of the array are objects with the same properties as the
550 \l{Screen} attached object. In practice the array corresponds to the screen
551 list returned by QGuiApplication::screens(). In addition to examining
552 properties like name, width, height, etc., the array elements can also be
553 assigned to the screen property of Window items, thus serving as an
554 alternative to the C++ side's QWindow::setScreen(). This property has been
555 added in Qt 5.9.
556
557 \endtable
558
559 The object also has one signal, aboutToQuit(), which is the same as \l QCoreApplication::aboutToQuit().
560
561 The following example uses the \c application object to indicate
562 whether the application is currently active:
563
564 \snippet qml/application.qml document
565
566 Note that when using QML without a QGuiApplication, the following properties will be undefined:
567 \list
568 \li application.active
569 \li application.state
570 \li application.layoutDirection
571 \li application.font
572 \endlist
573
574 \sa Screen, Window, {QtQuick.Window::Window::screen}{Window.screen}
575*/
576
577/*!
578 \qmlproperty object Qt::inputMethod
579 \since 5.0
580
581 The \c inputMethod object allows access to application's QInputMethod object
582 and all its properties and slots. See the QInputMethod documentation for
583 further details.
584*/
585
586/*!
587 \qmlproperty object Qt::styleHints
588 \since 5.5
589
590 The \c styleHints object provides platform-specific style hints and settings.
591 See the QStyleHints documentation for further details.
592
593 \note The \c styleHints object is only available when using the Qt Quick module.
594
595 The following example uses the \c styleHints object to determine whether an
596 item should gain focus on mouse press or touch release:
597 \code
598 import QtQuick 2.4
599
600 MouseArea {
601 id: button
602
603 onPressed: {
604 if (!Qt.styleHints.setFocusOnTouchRelease)
605 button.forceActiveFocus()
606 }
607 onReleased: {
608 if (Qt.styleHints.setFocusOnTouchRelease)
609 button.forceActiveFocus()
610 }
611 }
612 \endcode
613*/
614
615/*!
616\qmlmethod object Qt::include(string url, jsobject callback)
617\deprecated
618
619This method should not be used. Use ECMAScript modules instead and the native
620JavaScript \c import and \c export statements instead.
621
622Includes another JavaScript file. This method can only be used from within JavaScript files,
623and not regular QML files.
624
625This imports all functions from \a url into the current script's namespace.
626
627Qt.include() returns an object that describes the status of the operation. The object has
628a single property, \c {status}, that is set to one of the following values:
629
630\table
631\header \li Symbol \li Value \li Description
632\row \li result.OK \li 0 \li The include completed successfully.
633\row \li result.LOADING \li 1 \li Data is being loaded from the network.
634\row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
635\row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
636An additional \c exception property will be set in this case.
637\endtable
638
639The \c status property will be updated as the operation progresses.
640
641If provided, \a callback is invoked when the operation completes. The callback is passed
642the same object as is returned from the Qt.include() call.
643*/
644// Qt.include() is implemented in qv4include.cpp
645
646QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
647: propertyCapture(nullptr), rootContext(nullptr),
648#if QT_CONFIG(qml_debug)
649 profiler(nullptr),
650#endif
651 outputWarningsToMsgLog(true),
652 cleanup(nullptr), erroredBindings(nullptr), inProgressCreations(0),
653#if QT_CONFIG(qml_worker_script)
654 workerScriptEngine(nullptr),
655#endif
656 activeObjectCreator(nullptr),
657#if QT_CONFIG(qml_network)
658 networkAccessManager(nullptr), networkAccessManagerFactory(nullptr),
659#endif
660 urlInterceptor(nullptr), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e),
661 uniqueId(1), incubatorCount(0), incubationController(nullptr)
662{
663}
664
665QQmlEnginePrivate::~QQmlEnginePrivate()
666{
667 if (inProgressCreations)
668 qWarning() << QQmlEngine::tr(s: "There are still \"%1\" items in the process of being created at engine destruction.").arg(a: inProgressCreations);
669
670 while (cleanup) {
671 QQmlCleanup *c = cleanup;
672 cleanup = c->next;
673 if (cleanup) cleanup->prev = &cleanup;
674 c->next = nullptr;
675 c->prev = nullptr;
676 c->clear();
677 }
678
679 doDeleteInEngineThread();
680
681 if (incubationController) incubationController->d = nullptr;
682 incubationController = nullptr;
683
684 QQmlMetaType::freeUnusedTypesAndCaches();
685
686 for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) {
687 iter.value()->isRegisteredWithEngine = false;
688 QQmlMetaType::unregisterInternalCompositeType(typeIds: {iter.value()->metaTypeId, iter.value()->listMetaTypeId});
689 }
690#if QT_CONFIG(qml_debug)
691 delete profiler;
692#endif
693}
694
695void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
696{
697 if (QQmlData *d = QQmlData::get(object: o)) {
698 if (d->ownContext) {
699 for (QQmlContextData *lc = d->ownContext->linkedContext; lc; lc = lc->linkedContext) {
700 lc->invalidate();
701 if (lc->contextObject == o)
702 lc->contextObject = nullptr;
703 }
704 d->ownContext->invalidate();
705 if (d->ownContext->contextObject == o)
706 d->ownContext->contextObject = nullptr;
707 d->ownContext = nullptr;
708 d->context = nullptr;
709 }
710
711 if (d->outerContext && d->outerContext->contextObject == o)
712 d->outerContext->contextObject = nullptr;
713
714 // Mark this object as in the process of deletion to
715 // prevent it resolving in bindings
716 QQmlData::markAsDeleted(o);
717
718 // Disconnect the notifiers now - during object destruction this would be too late, since
719 // the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
720 // get the metaobject anymore.
721 d->disconnectNotifiers();
722 }
723}
724
725QQmlData::QQmlData()
726 : ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
727 hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
728 hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
729 bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr),
730 bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr),
731 lineNumber(0), columnNumber(0), jsEngineId(0),
732 propertyCache(nullptr), guards(nullptr), extendedData(nullptr)
733{
734 memset(s: bindingBitsValue, c: 0, n: sizeof(bindingBitsValue));
735 init();
736}
737
738QQmlData::~QQmlData()
739{
740}
741
742void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
743{
744 QQmlData *ddata = static_cast<QQmlData *>(d);
745 if (ddata->ownedByQml1)
746 return;
747 ddata->destroyed(o);
748}
749
750void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
751{
752 QQmlData *ddata = static_cast<QQmlData *>(d);
753 if (ddata->ownedByQml1)
754 return;
755 ddata->parentChanged(o, p);
756}
757
758class QQmlThreadNotifierProxyObject : public QObject
759{
760public:
761 QPointer<QObject> target;
762
763 int qt_metacall(QMetaObject::Call, int methodIndex, void **a) override {
764 if (!target)
765 return -1;
766
767 QMetaMethod method = target->metaObject()->method(index: methodIndex);
768 Q_ASSERT(method.methodType() == QMetaMethod::Signal);
769 int signalIndex = QMetaObjectPrivate::signalIndex(m: method);
770 QQmlData *ddata = QQmlData::get(object: target, create: false);
771 QQmlNotifierEndpoint *ep = ddata->notify(index: signalIndex);
772 if (ep) QQmlNotifier::emitNotify(ep, a);
773
774 delete this;
775
776 return -1;
777 }
778};
779
780void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **a)
781{
782 QQmlData *ddata = QQmlData::get(object, create: false);
783 if (!ddata) return; // Probably being deleted
784 if (ddata->ownedByQml1) return;
785
786 // In general, QML only supports QObject's that live on the same thread as the QQmlEngine
787 // that they're exposed to. However, to make writing "worker objects" that calculate data
788 // in a separate thread easier, QML allows a QObject that lives in the same thread as the
789 // QQmlEngine to emit signals from a different thread. These signals are then automatically
790 // marshalled back onto the QObject's thread and handled by QML from there. This is tested
791 // by the qqmlecmascript::threadSignal() autotest.
792 if (!ddata->notifyList)
793 return;
794
795 auto objectThreadData = QObjectPrivate::get(o: object)->threadData.loadRelaxed();
796 if (QThread::currentThreadId() != objectThreadData->threadId.loadRelaxed()) {
797 if (!objectThreadData->thread.loadAcquire())
798 return;
799
800 QMetaMethod m = QMetaObjectPrivate::signal(m: object->metaObject(), signal_index: index);
801 QList<QByteArray> parameterTypes = m.parameterTypes();
802
803 QScopedPointer<QMetaCallEvent> ev(new QMetaCallEvent(m.methodIndex(), 0, nullptr,
804 object, index,
805 parameterTypes.count() + 1));
806
807 void **args = ev->args();
808 int *types = ev->types();
809
810 for (int ii = 0; ii < parameterTypes.count(); ++ii) {
811 const QByteArray &typeName = parameterTypes.at(i: ii);
812 if (typeName.endsWith(c: '*'))
813 types[ii + 1] = QMetaType::VoidStar;
814 else
815 types[ii + 1] = QMetaType::type(typeName);
816
817 if (!types[ii + 1]) {
818 qWarning(msg: "QObject::connect: Cannot queue arguments of type '%s'\n"
819 "(Make sure '%s' is registered using qRegisterMetaType().)",
820 typeName.constData(), typeName.constData());
821 return;
822 }
823
824 args[ii + 1] = QMetaType::create(type: types[ii + 1], copy: a[ii + 1]);
825 }
826
827 QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
828 mpo->target = object;
829 mpo->moveToThread(thread: objectThreadData->thread.loadAcquire());
830 QCoreApplication::postEvent(receiver: mpo, event: ev.take());
831
832 } else {
833 QQmlNotifierEndpoint *ep = ddata->notify(index);
834 if (ep) QQmlNotifier::emitNotify(ep, a);
835 }
836}
837
838int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
839{
840 QQmlData *ddata = static_cast<QQmlData *>(d);
841 if (ddata->ownedByQml1)
842 return 0;
843 return ddata->endpointCount(index);
844}
845
846bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d, const QObject *, int index)
847{
848 QQmlData *ddata = static_cast<QQmlData *>(d);
849 if (ddata->ownedByQml1)
850 return false;
851 return ddata->signalHasEndpoint(index);
852}
853
854int QQmlData::endpointCount(int index)
855{
856 int count = 0;
857 QQmlNotifierEndpoint *ep = notify(index);
858 if (!ep)
859 return count;
860 ++count;
861 while (ep->next) {
862 ++count;
863 ep = ep->next;
864 }
865 return count;
866}
867
868void QQmlData::markAsDeleted(QObject *o)
869{
870 QQmlData::setQueuedForDeletion(o);
871
872 QObjectPrivate *p = QObjectPrivate::get(o);
873 for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) {
874 QQmlData::markAsDeleted(o: *it);
875 }
876}
877
878void QQmlData::setQueuedForDeletion(QObject *object)
879{
880 if (object) {
881 if (QQmlData *ddata = QQmlData::get(object)) {
882 if (ddata->ownContext) {
883 Q_ASSERT(ddata->ownContext == ddata->context);
884 ddata->context->emitDestruction();
885 if (ddata->ownContext->contextObject == object)
886 ddata->ownContext->contextObject = nullptr;
887 ddata->ownContext = nullptr;
888 ddata->context = nullptr;
889 }
890 ddata->isQueuedForDeletion = true;
891 }
892 }
893}
894
895void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index)
896{
897 clearPendingBindingBit(coreIndex: index.coreIndex());
898
899 // Find the binding
900 QQmlAbstractBinding *b = bindings;
901 while (b && (b->targetPropertyIndex().coreIndex() != index.coreIndex() ||
902 b->targetPropertyIndex().hasValueTypeIndex()))
903 b = b->nextBinding();
904
905 if (b && b->targetPropertyIndex().coreIndex() == index.coreIndex() &&
906 !b->targetPropertyIndex().hasValueTypeIndex())
907 b->setEnabled(e: true, f: QQmlPropertyData::BypassInterceptor |
908 QQmlPropertyData::DontRemoveBinding);
909}
910
911QQmlData::DeferredData::DeferredData()
912{
913}
914
915QQmlData::DeferredData::~DeferredData()
916{
917}
918
919bool QQmlEnginePrivate::baseModulesUninitialized = true;
920void QQmlEnginePrivate::init()
921{
922 Q_Q(QQmlEngine);
923
924 if (baseModulesUninitialized) {
925
926 // required for the Compiler.
927 qmlRegisterType<QObject>(uri: "QML", versionMajor: 1, versionMinor: 0, qmlName: "QtObject");
928 qmlRegisterType<QQmlComponent>(uri: "QML", versionMajor: 1, versionMinor: 0, qmlName: "Component");
929
930 QQmlData::init();
931 baseModulesUninitialized = false;
932 }
933
934 qRegisterMetaType<QVariant>();
935 qRegisterMetaType<QQmlScriptString>();
936 qRegisterMetaType<QJSValue>();
937 qRegisterMetaType<QQmlComponent::Status>();
938 qRegisterMetaType<QList<QObject*> >();
939 qRegisterMetaType<QList<int> >();
940 qRegisterMetaType<QQmlBinding*>();
941
942 q->handle()->setQmlEngine(q);
943
944 rootContext = new QQmlContext(q,true);
945}
946
947/*!
948 \class QQmlEngine
949 \since 5.0
950 \inmodule QtQml
951 \brief The QQmlEngine class provides an environment for instantiating QML components.
952
953 Each QML component is instantiated in a QQmlContext.
954 QQmlContext's are essential for passing data to QML
955 components. In QML, contexts are arranged hierarchically and this
956 hierarchy is managed by the QQmlEngine.
957
958 Prior to creating any QML components, an application must have
959 created a QQmlEngine to gain access to a QML context. The
960 following example shows how to create a simple Text item.
961
962 \code
963 QQmlEngine engine;
964 QQmlComponent component(&engine);
965 component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
966 QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
967
968 //add item to view, etc
969 ...
970 \endcode
971
972 In this case, the Text item will be created in the engine's
973 \l {QQmlEngine::rootContext()}{root context}.
974
975 \sa QQmlComponent, QQmlContext, {QML Global Object}
976*/
977
978/*!
979 Create a new QQmlEngine with the given \a parent.
980*/
981QQmlEngine::QQmlEngine(QObject *parent)
982: QJSEngine(*new QQmlEnginePrivate(this), parent)
983{
984 Q_D(QQmlEngine);
985 d->init();
986 QJSEnginePrivate::addToDebugServer(q: this);
987}
988
989/*!
990* \internal
991*/
992QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent)
993: QJSEngine(dd, parent)
994{
995 Q_D(QQmlEngine);
996 d->init();
997}
998
999/*!
1000 Destroys the QQmlEngine.
1001
1002 Any QQmlContext's created on this engine will be
1003 invalidated, but not destroyed (unless they are parented to the
1004 QQmlEngine object).
1005
1006 See QJSEngine docs for details on cleaning up the JS engine.
1007*/
1008QQmlEngine::~QQmlEngine()
1009{
1010 Q_D(QQmlEngine);
1011 QJSEnginePrivate::removeFromDebugServer(q: this);
1012
1013 // Emit onDestruction signals for the root context before
1014 // we destroy the contexts, engine, Singleton Types etc. that
1015 // may be required to handle the destruction signal.
1016 QQmlContextData::get(context: rootContext())->emitDestruction();
1017
1018 // clean up all singleton type instances which we own.
1019 // we do this here and not in the private dtor since otherwise a crash can
1020 // occur (if we are the QObject parent of the QObject singleton instance)
1021 // XXX TODO: performance -- store list of singleton types separately?
1022 const QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
1023 for (const QQmlType &currType : singletonTypes)
1024 d->destroySingletonInstance(type: currType);
1025
1026 delete d->rootContext;
1027 d->rootContext = nullptr;
1028
1029 d->typeLoader.invalidate();
1030}
1031
1032/*! \fn void QQmlEngine::quit()
1033 This signal is emitted when the QML loaded by the engine would like to quit.
1034
1035 \sa exit()
1036 */
1037
1038/*! \fn void QQmlEngine::exit(int retCode)
1039 This signal is emitted when the QML loaded by the engine would like to exit
1040 from the event loop with the specified return code \a retCode.
1041
1042 \since 5.8
1043 \sa quit()
1044 */
1045
1046
1047/*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
1048 This signal is emitted when \a warnings messages are generated by QML.
1049 */
1050
1051/*!
1052 Clears the engine's internal component cache.
1053
1054 This function causes the property metadata of all components previously
1055 loaded by the engine to be destroyed. All previously loaded components and
1056 the property bindings for all extant objects created from those components will
1057 cease to function.
1058
1059 This function returns the engine to a state where it does not contain any loaded
1060 component data. This may be useful in order to reload a smaller subset of the
1061 previous component set, or to load a new version of a previously loaded component.
1062
1063 Once the component cache has been cleared, components must be loaded before
1064 any new objects can be created.
1065
1066 \note Any existing objects created from QML components retain their types,
1067 even if you clear the component cache. This includes singleton objects. If you
1068 create more objects from the same QML code after clearing the cache, the new
1069 objects will be of different types than the old ones. Assigning such a new
1070 object to a property of its declared type belonging to an object created
1071 before clearing the cache won't work.
1072
1073 As a general rule of thumb, make sure that no objects created from QML
1074 components are alive when you clear the component cache.
1075
1076 \sa trimComponentCache()
1077 */
1078void QQmlEngine::clearComponentCache()
1079{
1080 Q_D(QQmlEngine);
1081 d->typeLoader.lock();
1082 d->typeLoader.clearCache();
1083 d->typeLoader.unlock();
1084}
1085
1086/*!
1087 Trims the engine's internal component cache.
1088
1089 This function causes the property metadata of any loaded components which are
1090 not currently in use to be destroyed.
1091
1092 A component is considered to be in use if there are any extant instances of
1093 the component itself, any instances of other components that use the component,
1094 or any objects instantiated by any of those components.
1095
1096 \sa clearComponentCache()
1097 */
1098void QQmlEngine::trimComponentCache()
1099{
1100 Q_D(QQmlEngine);
1101 d->typeLoader.trimCache();
1102}
1103
1104/*!
1105 Returns the engine's root context.
1106
1107 The root context is automatically created by the QQmlEngine.
1108 Data that should be available to all QML component instances
1109 instantiated by the engine should be put in the root context.
1110
1111 Additional data that should only be available to a subset of
1112 component instances should be added to sub-contexts parented to the
1113 root context.
1114*/
1115QQmlContext *QQmlEngine::rootContext() const
1116{
1117 Q_D(const QQmlEngine);
1118 return d->rootContext;
1119}
1120
1121/*!
1122 \internal
1123 This API is private for 5.1
1124
1125 Sets the \a urlInterceptor to be used when resolving URLs in QML.
1126 This also applies to URLs used for loading script files and QML types.
1127 This should not be modifed while the engine is loading files, or URL
1128 selection may be inconsistent.
1129*/
1130void QQmlEngine::setUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
1131{
1132 Q_D(QQmlEngine);
1133 d->urlInterceptor = urlInterceptor;
1134}
1135
1136/*!
1137 \internal
1138 This API is private for 5.1
1139
1140 Returns the current QQmlAbstractUrlInterceptor. It must not be modified outside
1141 the GUI thread.
1142*/
1143QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
1144{
1145 Q_D(const QQmlEngine);
1146 return d->urlInterceptor;
1147}
1148
1149void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
1150{
1151 if (activeObjectCreator) {
1152 activeObjectCreator->finalizeCallbacks()->append(t: qMakePair(x: QPointer<QObject>(obj), y: index));
1153 } else {
1154 void *args[] = { nullptr };
1155 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
1156 }
1157}
1158
1159QSharedPointer<QQmlImageProviderBase> QQmlEnginePrivate::imageProvider(const QString &providerId) const
1160{
1161 const QString providerIdLower = providerId.toLower();
1162 QMutexLocker locker(&mutex);
1163 return imageProviders.value(key: providerIdLower);
1164}
1165
1166#if QT_CONFIG(qml_network)
1167/*!
1168 Sets the \a factory to use for creating QNetworkAccessManager(s).
1169
1170 QNetworkAccessManager is used for all network access by QML. By
1171 implementing a factory it is possible to create custom
1172 QNetworkAccessManager with specialized caching, proxy and cookie
1173 support.
1174
1175 The factory must be set before executing the engine.
1176
1177 \note QQmlEngine does not take ownership of the factory.
1178*/
1179void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
1180{
1181 Q_D(QQmlEngine);
1182 QMutexLocker locker(&d->networkAccessManagerMutex);
1183 d->networkAccessManagerFactory = factory;
1184}
1185
1186/*!
1187 Returns the current QQmlNetworkAccessManagerFactory.
1188
1189 \sa setNetworkAccessManagerFactory()
1190*/
1191QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
1192{
1193 Q_D(const QQmlEngine);
1194 return d->networkAccessManagerFactory;
1195}
1196
1197QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
1198{
1199 QMutexLocker locker(&networkAccessManagerMutex);
1200 QNetworkAccessManager *nam;
1201 if (networkAccessManagerFactory) {
1202 nam = networkAccessManagerFactory->create(parent);
1203 } else {
1204 nam = new QNetworkAccessManager(parent);
1205 }
1206
1207 return nam;
1208}
1209
1210QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
1211{
1212 Q_Q(const QQmlEngine);
1213 if (!networkAccessManager)
1214 networkAccessManager = createNetworkAccessManager(parent: const_cast<QQmlEngine*>(q));
1215 return networkAccessManager;
1216}
1217
1218/*!
1219 Returns a common QNetworkAccessManager which can be used by any QML
1220 type instantiated by this engine.
1221
1222 If a QQmlNetworkAccessManagerFactory has been set and a
1223 QNetworkAccessManager has not yet been created, the
1224 QQmlNetworkAccessManagerFactory will be used to create the
1225 QNetworkAccessManager; otherwise the returned QNetworkAccessManager
1226 will have no proxy or cache set.
1227
1228 \sa setNetworkAccessManagerFactory()
1229*/
1230QNetworkAccessManager *QQmlEngine::networkAccessManager() const
1231{
1232 Q_D(const QQmlEngine);
1233 return d->getNetworkAccessManager();
1234}
1235#endif // qml_network
1236
1237/*!
1238
1239 Sets the \a provider to use for images requested via the \e
1240 image: url scheme, with host \a providerId. The QQmlEngine
1241 takes ownership of \a provider.
1242
1243 Image providers enable support for pixmap and threaded image
1244 requests. See the QQuickImageProvider documentation for details on
1245 implementing and using image providers.
1246
1247 All required image providers should be added to the engine before any
1248 QML sources files are loaded.
1249
1250 \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
1251*/
1252void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
1253{
1254 Q_D(QQmlEngine);
1255 QString providerIdLower = providerId.toLower();
1256 QSharedPointer<QQmlImageProviderBase> sp(provider);
1257 QMutexLocker locker(&d->mutex);
1258 d->imageProviders.insert(key: std::move(providerIdLower), value: std::move(sp));
1259}
1260
1261/*!
1262 Returns the image provider set for \a providerId if found; otherwise returns \nullptr.
1263
1264 \sa QQuickImageProvider
1265*/
1266QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
1267{
1268 Q_D(const QQmlEngine);
1269 const QString providerIdLower = providerId.toLower();
1270 QMutexLocker locker(&d->mutex);
1271 return d->imageProviders.value(key: providerIdLower).data();
1272}
1273
1274/*!
1275 Removes the image provider for \a providerId.
1276
1277 \sa addImageProvider(), QQuickImageProvider
1278*/
1279void QQmlEngine::removeImageProvider(const QString &providerId)
1280{
1281 Q_D(QQmlEngine);
1282 const QString providerIdLower = providerId.toLower();
1283 QMutexLocker locker(&d->mutex);
1284 d->imageProviders.take(key: providerIdLower);
1285}
1286
1287/*!
1288 Return the base URL for this engine. The base URL is only used to
1289 resolve components when a relative URL is passed to the
1290 QQmlComponent constructor.
1291
1292 If a base URL has not been explicitly set, this method returns the
1293 application's current working directory.
1294
1295 \sa setBaseUrl()
1296*/
1297QUrl QQmlEngine::baseUrl() const
1298{
1299 Q_D(const QQmlEngine);
1300 if (d->baseUrl.isEmpty()) {
1301 const QString currentPath = QDir::currentPath();
1302 const QString rootPath = QDir::rootPath();
1303 return QUrl::fromLocalFile(localfile: (currentPath == rootPath) ? rootPath : (currentPath + QDir::separator()));
1304 } else {
1305 return d->baseUrl;
1306 }
1307}
1308
1309/*!
1310 Set the base URL for this engine to \a url.
1311
1312 \sa baseUrl()
1313*/
1314void QQmlEngine::setBaseUrl(const QUrl &url)
1315{
1316 Q_D(QQmlEngine);
1317 d->baseUrl = url;
1318}
1319
1320/*!
1321 Returns true if warning messages will be output to stderr in addition
1322 to being emitted by the warnings() signal, otherwise false.
1323
1324 The default value is true.
1325*/
1326bool QQmlEngine::outputWarningsToStandardError() const
1327{
1328 Q_D(const QQmlEngine);
1329 return d->outputWarningsToMsgLog;
1330}
1331
1332/*!
1333 Set whether warning messages will be output to stderr to \a enabled.
1334
1335 If \a enabled is true, any warning messages generated by QML will be
1336 output to stderr and emitted by the warnings() signal. If \a enabled
1337 is false, only the warnings() signal will be emitted. This allows
1338 applications to handle warning output themselves.
1339
1340 The default value is true.
1341*/
1342void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
1343{
1344 Q_D(QQmlEngine);
1345 d->outputWarningsToMsgLog = enabled;
1346}
1347
1348/*!
1349 \qmlproperty string Qt::uiLanguage
1350 \since 5.15
1351
1352 The uiLanguage holds the name of the language to be used for user interface
1353 string translations. It is exposed in C++ as QQmlEngine::uiLanguage property.
1354
1355 You can set the value freely and use it in bindings. It is recommended to set it
1356 after installing translators in your application. By convention, an empty string
1357 means no translation from the language used in the source code is intended to occur.
1358
1359 If you're using QQmlApplicationEngine and the value changes, QQmlEngine::retranslate()
1360 will be called.
1361*/
1362
1363/*!
1364 \fn template<typename T> T QQmlEngine::singletonInstance(int qmlTypeId)
1365
1366 Returns the instance of a singleton type that was registered under \a qmlTypeId.
1367
1368 The template argument \e T may be either QJSValue or a pointer to a QObject-derived
1369 type and depends on how the singleton was registered. If no instance of \e T has been
1370 created yet, it is created now. If \a qmlTypeId does not represent a valid singleton
1371 type, either a default constructed QJSValue or a \c nullptr is returned.
1372
1373 QObject* example:
1374 \code
1375 class MySingleton : public QObject {
1376 Q_OBJECT
1377
1378 // Register as default constructed singleton.
1379 QML_ELEMENT
1380 QML_SINGLETON
1381
1382 static int typeId;
1383 // ...
1384 };
1385
1386 MySingleton::typeId = qmlTypeId(...);
1387
1388 // Retrieve as QObject*
1389 QQmlEngine engine;
1390 MySingleton* instance = engine.singletonInstance<MySingleton*>(MySingleton::typeId);
1391 \endcode
1392
1393 QJSValue example:
1394 \code
1395 // Register with QJSValue callback
1396 int typeId = qmlRegisterSingletonType(...);
1397
1398 // Retrieve as QJSValue
1399 QQmlEngine engine;
1400 QJSValue instance = engine.singletonInstance<QJSValue>(typeId);
1401 \endcode
1402
1403 It is recommended to store the QML type id, e.g. as a static member in the
1404 singleton class. The lookup via qmlTypeId() is costly.
1405
1406 \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId()
1407 \since 5.12
1408*/
1409template<>
1410QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
1411{
1412 Q_D(QQmlEngine);
1413 QQmlType type = QQmlMetaType::qmlType(typeId: qmlTypeId, category: QQmlMetaType::TypeIdCategory::QmlType);
1414
1415 if (!type.isValid() || !type.isSingleton())
1416 return QJSValue();
1417
1418 return d->singletonInstance<QJSValue>(type);
1419}
1420
1421/*!
1422 Refreshes all binding expressions that use strings marked for translation.
1423
1424 Call this function after you have installed a new translator with
1425 QCoreApplication::installTranslator, to ensure that your user-interface
1426 shows up-to-date translations.
1427
1428 \note Due to a limitation in the implementation, this function
1429 refreshes all the engine's bindings, not only those that use strings
1430 marked for translation.
1431 This may be optimized in a future release.
1432
1433 \since 5.10
1434*/
1435void QQmlEngine::retranslate()
1436{
1437 Q_D(QQmlEngine);
1438 QQmlContextData *context = QQmlContextData::get(context: d->rootContext)->childContexts;
1439 while (context) {
1440 context->refreshExpressions();
1441 context = context->nextChild;
1442 }
1443}
1444
1445/*!
1446 Returns the QQmlContext for the \a object, or 0 if no
1447 context has been set.
1448
1449 When the QQmlEngine instantiates a QObject, the context is
1450 set automatically.
1451
1452 \sa qmlContext(), qmlEngine()
1453 */
1454QQmlContext *QQmlEngine::contextForObject(const QObject *object)
1455{
1456 if(!object)
1457 return nullptr;
1458
1459 QQmlData *data = QQmlData::get(object);
1460 if (data && data->outerContext)
1461 return data->outerContext->asQQmlContext();
1462
1463 return nullptr;
1464}
1465
1466/*!
1467 Sets the QQmlContext for the \a object to \a context.
1468 If the \a object already has a context, a warning is
1469 output, but the context is not changed.
1470
1471 When the QQmlEngine instantiates a QObject, the context is
1472 set automatically.
1473 */
1474void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
1475{
1476 if (!object || !context)
1477 return;
1478
1479 QQmlData *data = QQmlData::get(object, create: true);
1480 if (data->context) {
1481 qWarning(msg: "QQmlEngine::setContextForObject(): Object already has a QQmlContext");
1482 return;
1483 }
1484
1485 QQmlContextData *contextData = QQmlContextData::get(context);
1486 Q_ASSERT(data->context == nullptr);
1487 data->context = contextData;
1488 contextData->addObject(data);
1489}
1490
1491/*!
1492 \enum QQmlEngine::ObjectOwnership
1493
1494 ObjectOwnership controls whether or not QML automatically destroys the
1495 QObject when the corresponding JavaScript object is garbage collected by the
1496 engine. The two ownership options are:
1497
1498 \value CppOwnership The object is owned by C++ code and QML will never delete
1499 it. The JavaScript destroy() method cannot be used on these objects. This
1500 option is similar to QScriptEngine::QtOwnership.
1501
1502 \value JavaScriptOwnership The object is owned by JavaScript. When the object
1503 is returned to QML as the return value of a method call, QML will track it
1504 and delete it if there are no remaining JavaScript references to it and
1505 it has no QObject::parent(). An object tracked by one QQmlEngine will be
1506 deleted during that QQmlEngine's destructor. Thus, JavaScript references
1507 between objects with JavaScriptOwnership from two different engines will
1508 not be valid if one of these engines is deleted. This option is similar to
1509 QScriptEngine::ScriptOwnership.
1510
1511 Generally an application doesn't need to set an object's ownership
1512 explicitly. QML uses a heuristic to set the default ownership. By default, an
1513 object that is created by QML has JavaScriptOwnership. The exception to this
1514 are the root objects created by calling QQmlComponent::create() or
1515 QQmlComponent::beginCreate(), which have CppOwnership by default. The
1516 ownership of these root-level objects is considered to have been transferred
1517 to the C++ caller.
1518
1519 Objects not-created by QML have CppOwnership by default. The exception to this
1520 are objects returned from C++ method calls; their ownership will be set to
1521 JavaScriptOwnership. This applies only to explicit invocations of Q_INVOKABLE
1522 methods or slots, but not to property getter invocations.
1523
1524 Calling setObjectOwnership() overrides the default ownership heuristic used by
1525 QML.
1526*/
1527
1528/*!
1529 Sets the \a ownership of \a object.
1530*/
1531void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1532{
1533 if (!object)
1534 return;
1535
1536 QQmlData *ddata = QQmlData::get(object, create: true);
1537 if (!ddata)
1538 return;
1539
1540 ddata->indestructible = (ownership == CppOwnership)?true:false;
1541 ddata->explicitIndestructibleSet = true;
1542}
1543
1544/*!
1545 Returns the ownership of \a object.
1546*/
1547QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
1548{
1549 if (!object)
1550 return CppOwnership;
1551
1552 QQmlData *ddata = QQmlData::get(object, create: false);
1553 if (!ddata)
1554 return CppOwnership;
1555 else
1556 return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1557}
1558
1559/*!
1560 \reimp
1561*/
1562bool QQmlEngine::event(QEvent *e)
1563{
1564 Q_D(QQmlEngine);
1565 if (e->type() == QEvent::User)
1566 d->doDeleteInEngineThread();
1567 else if (e->type() == QEvent::LanguageChange) {
1568 retranslate();
1569 }
1570
1571 return QJSEngine::event(event: e);
1572}
1573
1574void QQmlEnginePrivate::doDeleteInEngineThread()
1575{
1576 QFieldList<Deletable, &Deletable::next> list;
1577 mutex.lock();
1578 list.copyAndClear(toDeleteInEngineThread);
1579 mutex.unlock();
1580
1581 while (Deletable *d = list.takeFirst())
1582 delete d;
1583}
1584
1585namespace QtQml {
1586
1587void qmlExecuteDeferred(QObject *object)
1588{
1589 QQmlData *data = QQmlData::get(object);
1590
1591 if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
1592 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(e: data->context->engine);
1593
1594 QQmlComponentPrivate::DeferredState state;
1595 QQmlComponentPrivate::beginDeferred(enginePriv: ep, object, deferredState: &state);
1596
1597 // Release the reference for the deferral action (we still have one from construction)
1598 data->releaseDeferredData();
1599
1600 QQmlComponentPrivate::completeDeferred(enginePriv: ep, deferredState: &state);
1601 }
1602}
1603
1604QQmlContext *qmlContext(const QObject *obj)
1605{
1606 return QQmlEngine::contextForObject(object: obj);
1607}
1608
1609QQmlEngine *qmlEngine(const QObject *obj)
1610{
1611 QQmlData *data = QQmlData::get(object: obj, create: false);
1612 if (!data || !data->context)
1613 return nullptr;
1614 return data->context->engine;
1615}
1616
1617static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data,
1618 QObject *object, bool create)
1619{
1620 if (!pf)
1621 return nullptr;
1622
1623 QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(key: pf) : 0;
1624 if (rv || !create)
1625 return rv;
1626
1627 rv = pf(object);
1628
1629 if (rv)
1630 data->attachedProperties()->insert(key: pf, value: rv);
1631
1632 return rv;
1633}
1634
1635#if QT_DEPRECATED_SINCE(5, 14)
1636QT_WARNING_PUSH
1637QT_WARNING_DISABLE_DEPRECATED
1638
1639QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1640{
1641 QQmlData *data = QQmlData::get(object, create);
1642
1643 // Attached properties are only on objects created by QML,
1644 // unless explicitly requested (create==true)
1645 if (!data)
1646 return nullptr;
1647
1648 QQmlEnginePrivate *engine = QQmlEnginePrivate::get(c: data->context);
1649
1650 const QQmlType type = QQmlMetaType::qmlType(typeId: id, category: QQmlMetaType::TypeIdCategory::QmlType);
1651 return resolveAttachedProperties(pf: type.attachedPropertiesFunction(engine), data,
1652 object: const_cast<QObject *>(object), create);
1653}
1654
1655QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1656 const QMetaObject *attachedMetaObject, bool create)
1657{
1658 if (*idCache == -1) {
1659 QQmlEngine *engine = object ? qmlEngine(obj: object) : nullptr;
1660 *idCache = QQmlMetaType::attachedPropertiesFuncId(engine: engine ? QQmlEnginePrivate::get(e: engine) : nullptr, attachedMetaObject);
1661 }
1662
1663 if (*idCache == -1 || !object)
1664 return nullptr;
1665
1666 return qmlAttachedPropertiesObjectById(id: *idCache, object, create);
1667}
1668
1669QT_WARNING_POP
1670#endif
1671
1672QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
1673 const QMetaObject *attachedMetaObject)
1674{
1675 QQmlEngine *engine = object ? qmlEngine(obj: object) : nullptr;
1676 return QQmlMetaType::attachedPropertiesFunc(engine ? QQmlEnginePrivate::get(e: engine) : nullptr,
1677 attachedMetaObject);
1678}
1679
1680QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
1681{
1682 if (!object)
1683 return nullptr;
1684
1685 QQmlData *data = QQmlData::get(object, create);
1686
1687 // Attached properties are only on objects created by QML,
1688 // unless explicitly requested (create==true)
1689 if (!data)
1690 return nullptr;
1691
1692 return resolveAttachedProperties(pf: func, data, object, create);
1693}
1694
1695} // namespace QtQml
1696
1697#if QT_DEPRECATED_SINCE(5, 1)
1698QT_WARNING_PUSH
1699QT_WARNING_DISABLE_DEPRECATED
1700
1701// Also define symbols outside namespace to keep binary compatibility with Qt 5.0
1702
1703Q_QML_EXPORT void qmlExecuteDeferred(QObject *obj)
1704{
1705 QtQml::qmlExecuteDeferred(object: obj);
1706}
1707
1708Q_QML_EXPORT QQmlContext *qmlContext(const QObject *obj)
1709{
1710 return QtQml::qmlContext(obj);
1711}
1712
1713Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *obj)
1714{
1715 return QtQml::qmlEngine(obj);
1716}
1717
1718Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int id, const QObject *obj, bool create)
1719{
1720 return QtQml::qmlAttachedPropertiesObjectById(id, object: obj, create);
1721}
1722
1723Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1724 const QMetaObject *attachedMetaObject,
1725 bool create)
1726{
1727 return QtQml::qmlAttachedPropertiesObject(idCache, object, attachedMetaObject, create);
1728}
1729
1730QT_WARNING_POP
1731#endif // QT_DEPRECATED_SINCE(5, 1)
1732
1733class QQmlDataExtended {
1734public:
1735 QQmlDataExtended();
1736 ~QQmlDataExtended();
1737
1738 QHash<QQmlAttachedPropertiesFunc, QObject *> attachedProperties;
1739};
1740
1741QQmlDataExtended::QQmlDataExtended()
1742{
1743}
1744
1745QQmlDataExtended::~QQmlDataExtended()
1746{
1747}
1748
1749void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1750{
1751 // Add a temporary sentinel at beginning of list. This will be overwritten
1752 // when the end point is inserted into the notifies further down.
1753 endpoint->prev = nullptr;
1754
1755 while (endpoint->next) {
1756 Q_ASSERT(reinterpret_cast<QQmlNotifierEndpoint *>(endpoint->next->prev) == endpoint);
1757 endpoint = endpoint->next;
1758 }
1759
1760 while (endpoint) {
1761 QQmlNotifierEndpoint *ep = (QQmlNotifierEndpoint *) endpoint->prev;
1762
1763 int index = endpoint->sourceSignal;
1764 index = qMin(a: index, b: 0xFFFF - 1);
1765
1766 endpoint->next = notifies[index];
1767 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1768 endpoint->prev = &notifies[index];
1769 notifies[index] = endpoint;
1770
1771 endpoint = ep;
1772 }
1773}
1774
1775void QQmlData::NotifyList::layout()
1776{
1777 Q_ASSERT(maximumTodoIndex >= notifiesSize);
1778
1779 if (todo) {
1780 QQmlNotifierEndpoint **old = notifies;
1781 const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1782 notifies = (QQmlNotifierEndpoint**)realloc(ptr: notifies, size: reallocSize);
1783 const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1784 sizeof(QQmlNotifierEndpoint*);
1785 memset(s: notifies + notifiesSize, c: 0, n: memsetSize);
1786
1787 if (notifies != old) {
1788 for (int ii = 0; ii < notifiesSize; ++ii)
1789 if (notifies[ii])
1790 notifies[ii]->prev = &notifies[ii];
1791 }
1792
1793 notifiesSize = maximumTodoIndex + 1;
1794
1795 layout(endpoint: todo);
1796 }
1797
1798 maximumTodoIndex = 0;
1799 todo = nullptr;
1800}
1801
1802void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *context)
1803{
1804 QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
1805 deferData->deferredIdx = objectIndex;
1806 deferData->compilationUnit = compilationUnit;
1807 deferData->context = context;
1808
1809 const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(index: objectIndex);
1810 const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(i: objectIndex);
1811
1812 const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
1813 for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
1814 const QQmlPropertyData *property = propertyData.at(i);
1815 if (property && binding->flags & QV4::CompiledData::Binding::IsDeferredBinding)
1816 deferData->bindings.insert(key: property->coreIndex(), value: binding);
1817 }
1818
1819 deferredData.append(t: deferData);
1820}
1821
1822void QQmlData::releaseDeferredData()
1823{
1824 auto it = deferredData.begin();
1825 while (it != deferredData.end()) {
1826 DeferredData *deferData = *it;
1827 if (deferData->bindings.isEmpty()) {
1828 delete deferData;
1829 it = deferredData.erase(pos: it);
1830 } else {
1831 ++it;
1832 }
1833 }
1834}
1835
1836void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1837{
1838 if (!notifyList) {
1839 notifyList = (NotifyList *)malloc(size: sizeof(NotifyList));
1840 notifyList->connectionMask = 0;
1841 notifyList->maximumTodoIndex = 0;
1842 notifyList->notifiesSize = 0;
1843 notifyList->todo = nullptr;
1844 notifyList->notifies = nullptr;
1845 }
1846
1847 Q_ASSERT(!endpoint->isConnected());
1848
1849 index = qMin(a: index, b: 0xFFFF - 1);
1850 notifyList->connectionMask |= (1ULL << quint64(index % 64));
1851
1852 if (index < notifyList->notifiesSize) {
1853
1854 endpoint->next = notifyList->notifies[index];
1855 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1856 endpoint->prev = &notifyList->notifies[index];
1857 notifyList->notifies[index] = endpoint;
1858
1859 } else {
1860 notifyList->maximumTodoIndex = qMax(a: int(notifyList->maximumTodoIndex), b: index);
1861
1862 endpoint->next = notifyList->todo;
1863 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1864 endpoint->prev = &notifyList->todo;
1865 notifyList->todo = endpoint;
1866 }
1867}
1868
1869void QQmlData::disconnectNotifiers()
1870{
1871 if (notifyList) {
1872 while (notifyList->todo)
1873 notifyList->todo->disconnect();
1874 for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1875 while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1876 ep->disconnect();
1877 }
1878 free(ptr: notifyList->notifies);
1879 free(ptr: notifyList);
1880 notifyList = nullptr;
1881 }
1882}
1883
1884QHash<QQmlAttachedPropertiesFunc, QObject *> *QQmlData::attachedProperties() const
1885{
1886 if (!extendedData) extendedData = new QQmlDataExtended;
1887 return &extendedData->attachedProperties;
1888}
1889
1890void QQmlData::destroyed(QObject *object)
1891{
1892 if (nextContextObject)
1893 nextContextObject->prevContextObject = prevContextObject;
1894 if (prevContextObject)
1895 *prevContextObject = nextContextObject;
1896 else if (outerContext && outerContext->contextObjects == this)
1897 outerContext->contextObjects = nextContextObject;
1898
1899 QQmlAbstractBinding *binding = bindings;
1900 while (binding) {
1901 binding->setAddedToObject(false);
1902 binding = binding->nextBinding();
1903 }
1904 if (bindings && !bindings->ref.deref())
1905 delete bindings;
1906
1907 compilationUnit = nullptr;
1908
1909 qDeleteAll(c: deferredData);
1910 deferredData.clear();
1911
1912 QQmlBoundSignal *signalHandler = signalHandlers;
1913 while (signalHandler) {
1914 if (signalHandler->isNotifying()) {
1915 // The object is being deleted during signal handler evaluation.
1916 // This will cause a crash due to invalid memory access when the
1917 // evaluation has completed.
1918 // Abort with a friendly message instead.
1919 QString locationString;
1920 QQmlBoundSignalExpression *expr = signalHandler->expression();
1921 if (expr) {
1922 QQmlSourceLocation location = expr->sourceLocation();
1923 if (location.sourceFile.isEmpty())
1924 location.sourceFile = QStringLiteral("<Unknown File>");
1925 locationString.append(s: location.sourceFile);
1926 locationString.append(QStringLiteral(":%0: ").arg(a: location.line));
1927 QString source = expr->expression();
1928 if (source.size() > 100) {
1929 source.truncate(pos: 96);
1930 source.append(s: QLatin1String(" ..."));
1931 }
1932 locationString.append(s: source);
1933 } else {
1934 locationString = QStringLiteral("<Unknown Location>");
1935 }
1936 qFatal(msg: "Object %p destroyed while one of its QML signal handlers is in progress.\n"
1937 "Most likely the object was deleted synchronously (use QObject::deleteLater() "
1938 "instead), or the application is running a nested event loop.\n"
1939 "This behavior is NOT supported!\n"
1940 "%s", object, qPrintable(locationString));
1941 }
1942
1943 QQmlBoundSignal *next = signalHandler->m_nextSignal;
1944 signalHandler->m_prevSignal = nullptr;
1945 signalHandler->m_nextSignal = nullptr;
1946 delete signalHandler;
1947 signalHandler = next;
1948 }
1949
1950 if (bindingBitsArraySize > InlineBindingArraySize)
1951 free(ptr: bindingBits);
1952
1953 if (propertyCache)
1954 propertyCache->release();
1955
1956 ownContext = nullptr;
1957
1958 while (guards) {
1959 QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1960 *guard = (QObject *)nullptr;
1961 guard->objectDestroyed(object);
1962 }
1963
1964 disconnectNotifiers();
1965
1966 if (extendedData)
1967 delete extendedData;
1968
1969 // Dispose the handle.
1970 jsWrapper.clear();
1971
1972 if (ownMemory)
1973 delete this;
1974 else
1975 this->~QQmlData();
1976}
1977
1978DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
1979
1980void QQmlData::parentChanged(QObject *object, QObject *parent)
1981{
1982 if (parentTest()) {
1983 if (parentFrozen && !QObjectPrivate::get(o: object)->wasDeleted) {
1984 QString on;
1985 QString pn;
1986
1987 { QDebug dbg(&on); dbg << object; on = on.left(n: on.length() - 1); }
1988 { QDebug dbg(&pn); dbg << parent; pn = pn.left(n: pn.length() - 1); }
1989
1990 qFatal(msg: "Object %s has had its parent frozen by QML and cannot be changed.\n"
1991 "User code is attempting to change it to %s.\n"
1992 "This behavior is NOT supported!", qPrintable(on), qPrintable(pn));
1993 }
1994 }
1995}
1996
1997QQmlData::BindingBitsType *QQmlData::growBits(QObject *obj, int bit)
1998{
1999 BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
2000 int props = QQmlMetaObject(obj).propertyCount();
2001 Q_ASSERT(bit < 2 * props);
2002 Q_UNUSED(bit); // .. for Q_NO_DEBUG mode when the assert above expands to empty
2003
2004 uint arraySize = (2 * static_cast<uint>(props) + BitsPerType - 1) / BitsPerType;
2005 Q_ASSERT(arraySize > 1);
2006 Q_ASSERT(arraySize <= 0xffff); // max for bindingBitsArraySize
2007
2008 BindingBitsType *newBits = static_cast<BindingBitsType *>(malloc(size: arraySize*sizeof(BindingBitsType)));
2009 memcpy(dest: newBits, src: bits, n: bindingBitsArraySize * sizeof(BindingBitsType));
2010 memset(s: newBits + bindingBitsArraySize, c: 0, n: sizeof(BindingBitsType) * (arraySize - bindingBitsArraySize));
2011
2012 if (bindingBitsArraySize > InlineBindingArraySize)
2013 free(ptr: bits);
2014 bindingBits = newBits;
2015 bits = newBits;
2016 bindingBitsArraySize = arraySize;
2017 return bits;
2018}
2019
2020QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
2021{
2022 Q_ASSERT(priv);
2023 Q_ASSERT(!priv->isDeletingChildren);
2024 priv->declarativeData = new QQmlData;
2025 return static_cast<QQmlData *>(priv->declarativeData);
2026}
2027
2028QQmlPropertyCache *QQmlData::createPropertyCache(QJSEngine *engine, QObject *object)
2029{
2030 QQmlData *ddata = QQmlData::get(object, /*create*/true);
2031 ddata->propertyCache = QJSEnginePrivate::get(e: engine)->cache(obj: object, minorVersion: -1, doRef: true);
2032 return ddata->propertyCache;
2033}
2034
2035void QQmlEnginePrivate::sendQuit()
2036{
2037 Q_Q(QQmlEngine);
2038 emit q->quit();
2039 if (q->receivers(SIGNAL(quit())) == 0) {
2040 qWarning(msg: "Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
2041 }
2042}
2043
2044void QQmlEnginePrivate::sendExit(int retCode)
2045{
2046 Q_Q(QQmlEngine);
2047 if (q->receivers(SIGNAL(exit(int))) == 0)
2048 qWarning(msg: "Signal QQmlEngine::exit() emitted, but no receivers connected to handle it.");
2049 emit q->exit(retCode);
2050}
2051
2052static void dumpwarning(const QQmlError &error)
2053{
2054 switch (error.messageType()) {
2055 case QtDebugMsg:
2056 QMessageLogger(error.url().toString().toLatin1().constData(),
2057 error.line(), nullptr).debug().nospace()
2058 << qPrintable(error.toString());
2059 break;
2060 case QtInfoMsg:
2061 QMessageLogger(error.url().toString().toLatin1().constData(),
2062 error.line(), nullptr).info().nospace()
2063 << qPrintable(error.toString());
2064 break;
2065 case QtWarningMsg:
2066 case QtFatalMsg: // fatal does not support streaming, and furthermore, is actually fatal. Probably not desirable for QML.
2067 QMessageLogger(error.url().toString().toLatin1().constData(),
2068 error.line(), nullptr).warning().nospace()
2069 << qPrintable(error.toString());
2070 break;
2071 case QtCriticalMsg:
2072 QMessageLogger(error.url().toString().toLatin1().constData(),
2073 error.line(), nullptr).critical().nospace()
2074 << qPrintable(error.toString());
2075 break;
2076 }
2077}
2078
2079static void dumpwarning(const QList<QQmlError> &errors)
2080{
2081 for (int ii = 0; ii < errors.count(); ++ii)
2082 dumpwarning(error: errors.at(i: ii));
2083}
2084
2085void QQmlEnginePrivate::warning(const QQmlError &error)
2086{
2087 Q_Q(QQmlEngine);
2088 q->warnings(warnings: QList<QQmlError>() << error);
2089 if (outputWarningsToMsgLog)
2090 dumpwarning(error);
2091}
2092
2093void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
2094{
2095 Q_Q(QQmlEngine);
2096 q->warnings(warnings: errors);
2097 if (outputWarningsToMsgLog)
2098 dumpwarning(errors);
2099}
2100
2101void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
2102{
2103 if (engine)
2104 QQmlEnginePrivate::get(e: engine)->warning(error);
2105 else
2106 dumpwarning(error);
2107}
2108
2109void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
2110{
2111 if (engine)
2112 QQmlEnginePrivate::get(e: engine)->warning(errors: error);
2113 else
2114 dumpwarning(errors: error);
2115}
2116
2117void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
2118{
2119 if (engine)
2120 engine->warning(error);
2121 else
2122 dumpwarning(error);
2123}
2124
2125void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
2126{
2127 if (engine)
2128 engine->warning(errors: error);
2129 else
2130 dumpwarning(errors: error);
2131}
2132
2133QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(
2134 const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages)
2135{
2136 QList<QQmlError> errors;
2137 for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
2138 if (m.isWarning()) {
2139 qWarning(msg: "%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
2140 continue;
2141 }
2142
2143 QQmlError error;
2144 error.setUrl(QUrl(fileName));
2145 error.setDescription(m.message);
2146 error.setLine(qmlConvertSourceCoordinate<quint32, int>(n: m.loc.startLine));
2147 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(n: m.loc.startColumn));
2148 errors << error;
2149 }
2150 return errors;
2151}
2152
2153void QQmlEnginePrivate::cleanupScarceResources()
2154{
2155 // iterate through the list and release them all.
2156 // note that the actual SRD is owned by the JS engine,
2157 // so we cannot delete the SRD; but we can free the
2158 // memory used by the variant in the SRD.
2159 QV4::ExecutionEngine *engine = v4engine();
2160 while (QV4::ExecutionEngine::ScarceResourceData *sr = engine->scarceResources.first()) {
2161 sr->data = QVariant();
2162 engine->scarceResources.remove(n: sr);
2163 }
2164}
2165
2166/*!
2167 Adds \a path as a directory where the engine searches for
2168 installed modules in a URL-based directory structure.
2169
2170 The \a path may be a local filesystem directory, a
2171 \l {The Qt Resource System}{Qt Resource} path (\c {:/imports}), a
2172 \l {The Qt Resource System}{Qt Resource} url (\c {qrc:/imports}) or a URL.
2173
2174 The \a path will be converted into canonical form before it
2175 is added to the import path list.
2176
2177 The newly added \a path will be first in the importPathList().
2178
2179 \sa setImportPathList(), {QML Modules}
2180*/
2181void QQmlEngine::addImportPath(const QString& path)
2182{
2183 Q_D(QQmlEngine);
2184 d->importDatabase.addImportPath(dir: path);
2185}
2186
2187/*!
2188 Returns the list of directories where the engine searches for
2189 installed modules in a URL-based directory structure.
2190
2191 For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
2192 imports \c com.mycompany.Feature will cause the QQmlEngine to look
2193 in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
2194 provided by that module. A \c qmldir file is required for defining the
2195 type version mapping and possibly QML extensions plugins.
2196
2197 By default, the list contains the directory of the application executable,
2198 paths specified in the \c QML2_IMPORT_PATH environment variable,
2199 and the builtin \c Qml2ImportsPath from QLibraryInfo.
2200
2201 \sa addImportPath(), setImportPathList()
2202*/
2203QStringList QQmlEngine::importPathList() const
2204{
2205 Q_D(const QQmlEngine);
2206 return d->importDatabase.importPathList();
2207}
2208
2209/*!
2210 Sets \a paths as the list of directories where the engine searches for
2211 installed modules in a URL-based directory structure.
2212
2213 By default, the list contains the directory of the application executable,
2214 paths specified in the \c QML2_IMPORT_PATH environment variable,
2215 and the builtin \c Qml2ImportsPath from QLibraryInfo.
2216
2217 \sa importPathList(), addImportPath()
2218 */
2219void QQmlEngine::setImportPathList(const QStringList &paths)
2220{
2221 Q_D(QQmlEngine);
2222 d->importDatabase.setImportPathList(paths);
2223}
2224
2225
2226/*!
2227 Adds \a path as a directory where the engine searches for
2228 native plugins for imported modules (referenced in the \c qmldir file).
2229
2230 By default, the list contains only \c ., i.e. the engine searches
2231 in the directory of the \c qmldir file itself.
2232
2233 The newly added \a path will be first in the pluginPathList().
2234
2235 \sa setPluginPathList()
2236*/
2237void QQmlEngine::addPluginPath(const QString& path)
2238{
2239 Q_D(QQmlEngine);
2240 d->importDatabase.addPluginPath(path);
2241}
2242
2243
2244/*!
2245 Returns the list of directories where the engine searches for
2246 native plugins for imported modules (referenced in the \c qmldir file).
2247
2248 By default, the list contains only \c ., i.e. the engine searches
2249 in the directory of the \c qmldir file itself.
2250
2251 \sa addPluginPath(), setPluginPathList()
2252*/
2253QStringList QQmlEngine::pluginPathList() const
2254{
2255 Q_D(const QQmlEngine);
2256 return d->importDatabase.pluginPathList();
2257}
2258
2259/*!
2260 Sets the list of directories where the engine searches for
2261 native plugins for imported modules (referenced in the \c qmldir file)
2262 to \a paths.
2263
2264 By default, the list contains only \c ., i.e. the engine searches
2265 in the directory of the \c qmldir file itself.
2266
2267 \sa pluginPathList(), addPluginPath()
2268 */
2269void QQmlEngine::setPluginPathList(const QStringList &paths)
2270{
2271 Q_D(QQmlEngine);
2272 d->importDatabase.setPluginPathList(paths);
2273}
2274
2275#if QT_CONFIG(library)
2276/*!
2277 Imports the plugin named \a filePath with the \a uri provided.
2278 Returns true if the plugin was successfully imported; otherwise returns false.
2279
2280 On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
2281
2282 The plugin has to be a Qt plugin which implements the QQmlEngineExtensionPlugin interface.
2283*/
2284bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
2285{
2286 Q_D(QQmlEngine);
2287 return d->importDatabase.importDynamicPlugin(filePath, uri, importNamespace: QString(), vmaj: -1, errors);
2288}
2289#endif
2290
2291/*!
2292 \property QQmlEngine::offlineStoragePath
2293 \brief the directory for storing offline user data
2294
2295 Returns the directory where SQL and other offline
2296 storage is placed.
2297
2298 The SQL databases created with openDatabase() are stored here.
2299
2300 The default is QML/OfflineStorage in the platform-standard
2301 user application data directory.
2302
2303 Note that the path may not currently exist on the filesystem, so
2304 callers wanting to \e create new files at this location should create
2305 it first - see QDir::mkpath().
2306*/
2307void QQmlEngine::setOfflineStoragePath(const QString& dir)
2308{
2309 Q_D(QQmlEngine);
2310 d->offlineStoragePath = dir;
2311}
2312
2313QString QQmlEngine::offlineStoragePath() const
2314{
2315 Q_D(const QQmlEngine);
2316
2317 if (d->offlineStoragePath.isEmpty()) {
2318 QString dataLocation = QStandardPaths::writableLocation(type: QStandardPaths::DataLocation);
2319 QQmlEnginePrivate *e = const_cast<QQmlEnginePrivate *>(d);
2320 if (!dataLocation.isEmpty())
2321 e->offlineStoragePath = dataLocation.replace(before: QLatin1Char('/'), after: QDir::separator())
2322 + QDir::separator() + QLatin1String("QML")
2323 + QDir::separator() + QLatin1String("OfflineStorage");
2324 }
2325
2326 return d->offlineStoragePath;
2327}
2328
2329/*!
2330 Returns the file path where a \l{QtQuick.LocalStorage}{Local Storage}
2331 database with the identifier \a databaseName is (or would be) located.
2332
2333 \sa {openDatabaseSync}{LocalStorage.openDatabaseSync()}
2334 \since 5.9
2335*/
2336QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName) const
2337{
2338 Q_D(const QQmlEngine);
2339 QCryptographicHash md5(QCryptographicHash::Md5);
2340 md5.addData(data: databaseName.toUtf8());
2341 return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex());
2342}
2343
2344// #### Qt 6: Remove this function, it exists only for binary compatibility.
2345/*!
2346 * \internal
2347 */
2348bool QQmlEngine::addNamedBundle(const QString &name, const QString &fileName)
2349{
2350 Q_UNUSED(name)
2351 Q_UNUSED(fileName)
2352 return false;
2353}
2354
2355QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
2356{
2357 Q_Q(const QQmlEngine);
2358 return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator();
2359}
2360
2361bool QQmlEnginePrivate::isQObject(int t)
2362{
2363 Locker locker(this);
2364 return m_compositeTypes.contains(key: t) || QQmlMetaType::isQObject(t);
2365}
2366
2367QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
2368{
2369 Locker locker(this);
2370 int t = v.userType();
2371 if (t == QMetaType::QObjectStar || m_compositeTypes.contains(key: t)) {
2372 if (ok) *ok = true;
2373 return *(QObject *const *)(v.constData());
2374 } else {
2375 return QQmlMetaType::toQObject(v, ok);
2376 }
2377}
2378
2379QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
2380{
2381 Locker locker(this);
2382 if (m_compositeTypes.contains(key: t))
2383 return QQmlMetaType::Object;
2384 return QQmlMetaType::typeCategory(t);
2385}
2386
2387bool QQmlEnginePrivate::isList(int t) const
2388{
2389 return QQmlMetaType::isList(t);
2390}
2391
2392int QQmlEnginePrivate::listType(int t) const
2393{
2394 return QQmlMetaType::listType(t);
2395}
2396
2397
2398static QQmlPropertyCache *propertyCacheForPotentialInlineComponentType(int t, const QHash<int, QV4::ExecutableCompilationUnit *>::const_iterator &iter) {
2399 if (t != (*iter)->metaTypeId) {
2400 // this is an inline component, and what we have in the iterator is currently the parent compilation unit
2401 for (auto &&icDatum: (*iter)->inlineComponentData)
2402 if (icDatum.typeIds.id == t)
2403 return (*iter)->propertyCaches.at(index: icDatum.objectIndex);
2404 }
2405 return (*iter)->rootPropertyCache().data();
2406}
2407
2408QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
2409{
2410 Locker locker(this);
2411 auto iter = m_compositeTypes.constFind(key: t);
2412 if (iter != m_compositeTypes.cend()) {
2413 return propertyCacheForPotentialInlineComponentType(t, iter);
2414 } else {
2415 QQmlType type = QQmlMetaType::qmlType(typeId: t);
2416 return QQmlMetaObject(type.baseMetaObject());
2417 }
2418}
2419
2420QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
2421{
2422 Locker locker(this);
2423 auto iter = m_compositeTypes.constFind(key: t);
2424 if (iter != m_compositeTypes.cend()) {
2425 return propertyCacheForPotentialInlineComponentType(t, iter);
2426 } else {
2427 QQmlType type = QQmlMetaType::qmlType(typeId: t);
2428 return QQmlMetaObject(type.metaObject());
2429 }
2430}
2431
2432QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
2433{
2434 Locker locker(this);
2435 auto iter = m_compositeTypes.constFind(key: t);
2436 if (iter != m_compositeTypes.cend()) {
2437 return propertyCacheForPotentialInlineComponentType(t, iter);
2438 } else {
2439 QQmlType type = QQmlMetaType::qmlType(typeId: t);
2440 locker.unlock();
2441 return type.isValid() ? cache(metaObject: type.metaObject()) : nullptr;
2442 }
2443}
2444
2445QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVersion)
2446{
2447 Locker locker(this);
2448 auto iter = m_compositeTypes.constFind(key: t);
2449 if (iter != m_compositeTypes.cend()) {
2450 return propertyCacheForPotentialInlineComponentType(t, iter);
2451 } else {
2452 QQmlType type = QQmlMetaType::qmlType(typeId: t);
2453 locker.unlock();
2454
2455 if (minorVersion >= 0)
2456 return type.isValid() ? cache(type, minorVersion) : nullptr;
2457 else
2458 return type.isValid() ? cache(metaObject: type.baseMetaObject()) : nullptr;
2459 }
2460}
2461
2462void QQmlEnginePrivate::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
2463{
2464 compilationUnit->isRegisteredWithEngine = true;
2465
2466 Locker locker(this);
2467 // The QQmlCompiledData is not referenced here, but it is removed from this
2468 // hash in the QQmlCompiledData destructor
2469 m_compositeTypes.insert(key: compilationUnit->metaTypeId, value: compilationUnit);
2470 for (auto &&data: compilationUnit->inlineComponentData) {
2471 m_compositeTypes.insert(key: data.typeIds.id, value: compilationUnit);
2472 }
2473}
2474
2475void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
2476{
2477 compilationUnit->isRegisteredWithEngine = false;
2478
2479 Locker locker(this);
2480 m_compositeTypes.remove(key: compilationUnit->metaTypeId);
2481 for (auto&& icDatum: compilationUnit->inlineComponentData)
2482 m_compositeTypes.remove(key: icDatum.typeIds.id);
2483}
2484
2485QV4::ExecutableCompilationUnit *QQmlEnginePrivate::obtainExecutableCompilationUnit(int typeId)
2486{
2487 Locker locker(this);
2488 return m_compositeTypes.value(key: typeId, defaultValue: nullptr);
2489}
2490
2491template<>
2492QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
2493{
2494 Q_Q(QQmlEngine);
2495
2496 QJSValue value = singletonInstances.value(key: type);
2497 if (!value.isUndefined()) {
2498 return value;
2499 }
2500
2501 QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
2502 Q_ASSERT(siinfo != nullptr);
2503
2504 if (siinfo->scriptCallback) {
2505 value = siinfo->scriptCallback(q, q);
2506 if (value.isQObject()) {
2507 QObject *o = value.toQObject();
2508 // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
2509 // should behave identically to QML singleton types.
2510 q->setContextForObject(object: o, context: new QQmlContext(q->rootContext(), q));
2511 }
2512 singletonInstances.insert(key: type, value);
2513
2514 } else if (siinfo->qobjectCallback) {
2515 QObject *o = siinfo->qobjectCallback(q, q);
2516 if (!o) {
2517 QQmlError error;
2518 error.setMessageType(QtMsgType::QtCriticalMsg);
2519 error.setDescription(QString::asprintf(format: "qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.",
2520 qPrintable(QString::fromUtf8(type.typeName()))));
2521 warning(error);
2522 } else {
2523 // if this object can use a property cache, create it now
2524 QQmlData::ensurePropertyCache(engine: q, object: o);
2525 }
2526 // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
2527 // should behave identically to QML singleton types.
2528 q->setContextForObject(object: o, context: new QQmlContext(q->rootContext(), q));
2529 value = q->newQObject(object: o);
2530 singletonInstances.insert(key: type, value);
2531 } else if (!siinfo->url.isEmpty()) {
2532 QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
2533 QObject *o = component.beginCreate(q->rootContext());
2534 value = q->newQObject(object: o);
2535 singletonInstances.insert(key: type, value);
2536 component.completeCreate();
2537 }
2538
2539 return value;
2540}
2541
2542void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type)
2543{
2544 Q_ASSERT(type.isSingleton() || type.isCompositeSingleton());
2545
2546 QObject* o = singletonInstances.take(key: type).toQObject();
2547 if (o) {
2548 QQmlData *ddata = QQmlData::get(object: o, create: false);
2549 if (type.singletonInstanceInfo()->url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
2550 return;
2551 delete o;
2552 }
2553}
2554
2555bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
2556{
2557 return typeLoader.isTypeLoaded(url);
2558}
2559
2560bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
2561{
2562 return typeLoader.isScriptLoaded(url);
2563}
2564
2565#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
2566// Normalize a file name using Shell API. As opposed to converting it
2567// to a short 8.3 name and back, this also works for drives where 8.3 notation
2568// is disabled (see 8dot3name options of fsutil.exe).
2569static inline QString shellNormalizeFileName(const QString &name)
2570{
2571 const QString nativeSeparatorName(QDir::toNativeSeparators(name));
2572 const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16());
2573// The correct declaration of the SHGetPathFromIDList symbol is
2574// being used in mingw-w64 as of r6215, which is a v3 snapshot.
2575#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3)
2576 ITEMIDLIST *file;
2577 if (FAILED(SHParseDisplayName(nameC, NULL, reinterpret_cast<LPITEMIDLIST>(&file), 0, NULL)))
2578 return name;
2579#else
2580 PIDLIST_ABSOLUTE file;
2581 if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL)))
2582 return name;
2583#endif
2584 TCHAR buffer[MAX_PATH];
2585 bool gotPath = SHGetPathFromIDList(file, buffer);
2586 ILFree(file);
2587
2588 if (!gotPath)
2589 return name;
2590
2591 QString canonicalName = QString::fromWCharArray(buffer);
2592 // Upper case drive letter
2593 if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':'))
2594 canonicalName[0] = canonicalName.at(0).toUpper();
2595 return QDir::cleanPath(canonicalName);
2596}
2597#endif // Q_OS_WIN && !Q_OS_WINRT
2598
2599bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
2600{
2601#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
2602 QFileInfo info(fileName);
2603 const QString absolute = info.absoluteFilePath();
2604
2605#if defined(Q_OS_DARWIN) || defined(Q_OS_WINRT)
2606 const QString canonical = info.canonicalFilePath();
2607#elif defined(Q_OS_WIN)
2608 // No difference if the path is qrc based
2609 if (absolute[0] == QLatin1Char(':'))
2610 return true;
2611 const QString canonical = shellNormalizeFileName(absolute);
2612#endif
2613
2614 const int absoluteLength = absolute.length();
2615 const int canonicalLength = canonical.length();
2616
2617 int length = qMin(absoluteLength, canonicalLength);
2618 if (lengthIn >= 0) {
2619 length = qMin(lengthIn, length);
2620 } else {
2621 // No length given: Limit to file name. Do not trigger
2622 // on drive letters or folder names.
2623 int lastSlash = absolute.lastIndexOf(QLatin1Char('/'));
2624 if (lastSlash < 0)
2625 lastSlash = absolute.lastIndexOf(QLatin1Char('\\'));
2626 if (lastSlash >= 0) {
2627 const int fileNameLength = absoluteLength - 1 - lastSlash;
2628 length = qMin(length, fileNameLength);
2629 }
2630 }
2631
2632 for (int ii = 0; ii < length; ++ii) {
2633 const QChar &a = absolute.at(absoluteLength - 1 - ii);
2634 const QChar &c = canonical.at(canonicalLength - 1 - ii);
2635
2636 if (a.toLower() != c.toLower())
2637 return true;
2638 if (a != c)
2639 return false;
2640 }
2641#else
2642 Q_UNUSED(lengthIn)
2643 Q_UNUSED(fileName)
2644#endif
2645 return true;
2646}
2647
2648/*!
2649 \fn QQmlEngine *qmlEngine(const QObject *object)
2650 \relates QQmlEngine
2651
2652 Returns the QQmlEngine associated with \a object, if any. This is equivalent to
2653 QQmlEngine::contextForObject(object)->engine(), but more efficient.
2654
2655 \note Add \c{#include <QtQml>} to use this function.
2656
2657 \sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlContext()
2658*/
2659
2660/*!
2661 \fn QQmlContext *qmlContext(const QObject *object)
2662 \relates QQmlEngine
2663
2664 Returns the QQmlContext associated with \a object, if any. This is equivalent to
2665 QQmlEngine::contextForObject(object).
2666
2667 \note Add \c{#include <QtQml>} to use this function.
2668
2669 \sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlEngine()
2670*/
2671
2672QT_END_NAMESPACE
2673
2674#include "moc_qqmlengine.cpp"
2675

source code of qtdeclarative/src/qml/qml/qqmlengine.cpp