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