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