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 if (d->outerContext && d->outerContext->contextObject == o)
759 d->outerContext->contextObject = nullptr;
760
761 // Mark this object as in the process of deletion to
762 // prevent it resolving in bindings
763 QQmlData::markAsDeleted(o);
764
765 // Disconnect the notifiers now - during object destruction this would be too late, since
766 // the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
767 // get the metaobject anymore.
768 d->disconnectNotifiers();
769 }
770}
771
772QQmlData::QQmlData()
773 : ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
774 hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
775 hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
776 bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr),
777 bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr),
778 lineNumber(0), columnNumber(0), jsEngineId(0),
779 propertyCache(nullptr), guards(nullptr), extendedData(nullptr)
780{
781 memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
782 init();
783}
784
785QQmlData::~QQmlData()
786{
787}
788
789void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
790{
791 QQmlData *ddata = static_cast<QQmlData *>(d);
792 if (ddata->ownedByQml1)
793 return;
794 ddata->destroyed(o);
795}
796
797void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
798{
799 QQmlData *ddata = static_cast<QQmlData *>(d);
800 if (ddata->ownedByQml1)
801 return;
802 ddata->parentChanged(o, p);
803}
804
805class QQmlThreadNotifierProxyObject : public QObject
806{
807public:
808 QPointer<QObject> target;
809
810 int qt_metacall(QMetaObject::Call, int methodIndex, void **a) override {
811 if (!target)
812 return -1;
813
814 QMetaMethod method = target->metaObject()->method(methodIndex);
815 Q_ASSERT(method.methodType() == QMetaMethod::Signal);
816 int signalIndex = QMetaObjectPrivate::signalIndex(method);
817 QQmlData *ddata = QQmlData::get(target, false);
818 QQmlNotifierEndpoint *ep = ddata->notify(signalIndex);
819 if (ep) QQmlNotifier::emitNotify(ep, a);
820
821 delete this;
822
823 return -1;
824 }
825};
826
827void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **a)
828{
829 QQmlData *ddata = QQmlData::get(object, false);
830 if (!ddata) return; // Probably being deleted
831 if (ddata->ownedByQml1) return;
832
833 // In general, QML only supports QObject's that live on the same thread as the QQmlEngine
834 // that they're exposed to. However, to make writing "worker objects" that calculate data
835 // in a separate thread easier, QML allows a QObject that lives in the same thread as the
836 // QQmlEngine to emit signals from a different thread. These signals are then automatically
837 // marshalled back onto the QObject's thread and handled by QML from there. This is tested
838 // by the qqmlecmascript::threadSignal() autotest.
839 if (ddata->notifyList &&
840 QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.load()) {
841
842 if (!QObjectPrivate::get(object)->threadData->thread)
843 return;
844
845 QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
846 QList<QByteArray> parameterTypes = m.parameterTypes();
847
848 int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
849 void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
850
851 types[0] = 0; // return type
852 args[0] = nullptr; // return value
853
854 for (int ii = 0; ii < parameterTypes.count(); ++ii) {
855 const QByteArray &typeName = parameterTypes.at(ii);
856 if (typeName.endsWith('*'))
857 types[ii + 1] = QMetaType::VoidStar;
858 else
859 types[ii + 1] = QMetaType::type(typeName);
860
861 if (!types[ii + 1]) {
862 qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
863 "(Make sure '%s' is registered using qRegisterMetaType().)",
864 typeName.constData(), typeName.constData());
865 free(types);
866 free(args);
867 return;
868 }
869
870 args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
871 }
872
873 QMetaCallEvent *ev = new QMetaCallEvent(m.methodIndex(), 0, nullptr, object, index,
874 parameterTypes.count() + 1, types, args);
875
876 QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
877 mpo->target = object;
878 mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread);
879 QCoreApplication::postEvent(mpo, ev);
880
881 } else {
882 QQmlNotifierEndpoint *ep = ddata->notify(index);
883 if (ep) QQmlNotifier::emitNotify(ep, a);
884 }
885}
886
887int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
888{
889 QQmlData *ddata = static_cast<QQmlData *>(d);
890 if (ddata->ownedByQml1)
891 return 0;
892 return ddata->endpointCount(index);
893}
894
895bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d, const QObject *, int index)
896{
897 QQmlData *ddata = static_cast<QQmlData *>(d);
898 if (ddata->ownedByQml1)
899 return false;
900 return ddata->signalHasEndpoint(index);
901}
902
903int QQmlData::endpointCount(int index)
904{
905 int count = 0;
906 QQmlNotifierEndpoint *ep = notify(index);
907 if (!ep)
908 return count;
909 ++count;
910 while (ep->next) {
911 ++count;
912 ep = ep->next;
913 }
914 return count;
915}
916
917void QQmlData::markAsDeleted(QObject *o)
918{
919 QQmlData::setQueuedForDeletion(o);
920
921 QObjectPrivate *p = QObjectPrivate::get(o);
922 for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) {
923 QQmlData::markAsDeleted(*it);
924 }
925}
926
927void QQmlData::setQueuedForDeletion(QObject *object)
928{
929 if (object) {
930 if (QQmlData *ddata = QQmlData::get(object)) {
931 if (ddata->ownContext) {
932 Q_ASSERT(ddata->ownContext == ddata->context);
933 ddata->context->emitDestruction();
934 if (ddata->ownContext->contextObject == object)
935 ddata->ownContext->contextObject = nullptr;
936 ddata->ownContext = nullptr;
937 ddata->context = nullptr;
938 }
939 ddata->isQueuedForDeletion = true;
940 }
941 }
942}
943
944void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index)
945{
946 clearPendingBindingBit(index.coreIndex());
947
948 // Find the binding
949 QQmlAbstractBinding *b = bindings;
950 while (b && (b->targetPropertyIndex().coreIndex() != index.coreIndex() ||
951 b->targetPropertyIndex().hasValueTypeIndex()))
952 b = b->nextBinding();
953
954 if (b && b->targetPropertyIndex().coreIndex() == index.coreIndex() &&
955 !b->targetPropertyIndex().hasValueTypeIndex())
956 b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
957 QQmlPropertyData::DontRemoveBinding);
958}
959
960QQmlData::DeferredData::DeferredData()
961{
962}
963
964QQmlData::DeferredData::~DeferredData()
965{
966}
967
968bool QQmlEnginePrivate::baseModulesUninitialized = true;
969void QQmlEnginePrivate::init()
970{
971 Q_Q(QQmlEngine);
972
973 if (baseModulesUninitialized) {
974 qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component"); // required for the Compiler.
975 registerBaseTypes("QtQml", 2, 0); // import which provides language building blocks.
976#if QT_CONFIG(qml_locale)
977 qmlRegisterUncreatableType<QQmlLocale>("QtQml", 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
978#endif
979
980 // Auto-increment the import to stay in sync with ALL future QtQml minor versions from 5.11 onward
981 qmlRegisterModule("QtQml", 2, QT_VERSION_MINOR);
982
983 QQmlData::init();
984 baseModulesUninitialized = false;
985 }
986
987 qRegisterMetaType<QVariant>();
988 qRegisterMetaType<QQmlScriptString>();
989 qRegisterMetaType<QJSValue>();
990 qRegisterMetaType<QQmlComponent::Status>();
991 qRegisterMetaType<QList<QObject*> >();
992 qRegisterMetaType<QList<int> >();
993 qRegisterMetaType<QQmlV4Handle>();
994 qRegisterMetaType<QQmlBinding*>();
995
996 v8engine()->setEngine(q);
997
998 rootContext = new QQmlContext(q,true);
999}
1000
1001#if QT_CONFIG(qml_worker_script)
1002QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
1003{
1004 Q_Q(QQmlEngine);
1005 if (!workerScriptEngine)
1006 workerScriptEngine = new QQuickWorkerScriptEngine(q);
1007 return workerScriptEngine;
1008}
1009#endif
1010
1011/*!
1012 \class QQmlEngine
1013 \since 5.0
1014 \inmodule QtQml
1015 \brief The QQmlEngine class provides an environment for instantiating QML components.
1016
1017 Each QML component is instantiated in a QQmlContext.
1018 QQmlContext's are essential for passing data to QML
1019 components. In QML, contexts are arranged hierarchically and this
1020 hierarchy is managed by the QQmlEngine.
1021
1022 Prior to creating any QML components, an application must have
1023 created a QQmlEngine to gain access to a QML context. The
1024 following example shows how to create a simple Text item.
1025
1026 \code
1027 QQmlEngine engine;
1028 QQmlComponent component(&engine);
1029 component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
1030 QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
1031
1032 //add item to view, etc
1033 ...
1034 \endcode
1035
1036 In this case, the Text item will be created in the engine's
1037 \l {QQmlEngine::rootContext()}{root context}.
1038
1039 \sa QQmlComponent, QQmlContext, {QML Global Object}
1040*/
1041
1042/*!
1043 Create a new QQmlEngine with the given \a parent.
1044*/
1045QQmlEngine::QQmlEngine(QObject *parent)
1046: QJSEngine(*new QQmlEnginePrivate(this), parent)
1047{
1048 Q_D(QQmlEngine);
1049 d->init();
1050 QJSEnginePrivate::addToDebugServer(this);
1051}
1052
1053/*!
1054* \internal
1055*/
1056QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent)
1057: QJSEngine(dd, parent)
1058{
1059 Q_D(QQmlEngine);
1060 d->init();
1061}
1062
1063/*!
1064 Destroys the QQmlEngine.
1065
1066 Any QQmlContext's created on this engine will be
1067 invalidated, but not destroyed (unless they are parented to the
1068 QQmlEngine object).
1069
1070 See QJSEngine docs for details on cleaning up the JS engine.
1071*/
1072QQmlEngine::~QQmlEngine()
1073{
1074 Q_D(QQmlEngine);
1075 QJSEnginePrivate::removeFromDebugServer(this);
1076
1077 d->typeLoader.invalidate();
1078
1079 // Emit onDestruction signals for the root context before
1080 // we destroy the contexts, engine, Singleton Types etc. that
1081 // may be required to handle the destruction signal.
1082 QQmlContextData::get(rootContext())->emitDestruction();
1083
1084 // clean up all singleton type instances which we own.
1085 // we do this here and not in the private dtor since otherwise a crash can
1086 // occur (if we are the QObject parent of the QObject singleton instance)
1087 // XXX TODO: performance -- store list of singleton types separately?
1088 QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
1089 for (const QQmlType &currType : singletonTypes)
1090 currType.singletonInstanceInfo()->destroy(this);
1091
1092 delete d->rootContext;
1093 d->rootContext = nullptr;
1094}
1095
1096/*! \fn void QQmlEngine::quit()
1097 This signal is emitted when the QML loaded by the engine would like to quit.
1098
1099 \sa exit()
1100 */
1101
1102/*! \fn void QQmlEngine::exit(int retCode)
1103 This signal is emitted when the QML loaded by the engine would like to exit
1104 from the event loop with the specified return code \a retCode.
1105
1106 \since 5.8
1107 \sa quit()
1108 */
1109
1110
1111/*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
1112 This signal is emitted when \a warnings messages are generated by QML.
1113 */
1114
1115/*!
1116 Clears the engine's internal component cache.
1117
1118 This function causes the property metadata of all components previously
1119 loaded by the engine to be destroyed. All previously loaded components and
1120 the property bindings for all extant objects created from those components will
1121 cease to function.
1122
1123 This function returns the engine to a state where it does not contain any loaded
1124 component data. This may be useful in order to reload a smaller subset of the
1125 previous component set, or to load a new version of a previously loaded component.
1126
1127 Once the component cache has been cleared, components must be loaded before
1128 any new objects can be created.
1129
1130 \sa trimComponentCache()
1131 */
1132void QQmlEngine::clearComponentCache()
1133{
1134 Q_D(QQmlEngine);
1135 d->typeLoader.lock();
1136 d->typeLoader.clearCache();
1137 d->typeLoader.unlock();
1138}
1139
1140/*!
1141 Trims the engine's internal component cache.
1142
1143 This function causes the property metadata of any loaded components which are
1144 not currently in use to be destroyed.
1145
1146 A component is considered to be in use if there are any extant instances of
1147 the component itself, any instances of other components that use the component,
1148 or any objects instantiated by any of those components.
1149
1150 \sa clearComponentCache()
1151 */
1152void QQmlEngine::trimComponentCache()
1153{
1154 Q_D(QQmlEngine);
1155 d->typeLoader.trimCache();
1156}
1157
1158/*!
1159 Returns the engine's root context.
1160
1161 The root context is automatically created by the QQmlEngine.
1162 Data that should be available to all QML component instances
1163 instantiated by the engine should be put in the root context.
1164
1165 Additional data that should only be available to a subset of
1166 component instances should be added to sub-contexts parented to the
1167 root context.
1168*/
1169QQmlContext *QQmlEngine::rootContext() const
1170{
1171 Q_D(const QQmlEngine);
1172 return d->rootContext;
1173}
1174
1175/*!
1176 \internal
1177 This API is private for 5.1
1178
1179 Sets the \a urlInterceptor to be used when resolving URLs in QML.
1180 This also applies to URLs used for loading script files and QML types.
1181 This should not be modifed while the engine is loading files, or URL
1182 selection may be inconsistent.
1183*/
1184void QQmlEngine::setUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
1185{
1186 Q_D(QQmlEngine);
1187 d->urlInterceptor = urlInterceptor;
1188}
1189
1190/*!
1191 \internal
1192 This API is private for 5.1
1193
1194 Returns the current QQmlAbstractUrlInterceptor. It must not be modified outside
1195 the GUI thread.
1196*/
1197QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
1198{
1199 Q_D(const QQmlEngine);
1200 return d->urlInterceptor;
1201}
1202
1203void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
1204{
1205 if (activeObjectCreator) {
1206 activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index));
1207 } else {
1208 void *args[] = { nullptr };
1209 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
1210 }
1211}
1212
1213#if QT_CONFIG(qml_network)
1214/*!
1215 Sets the \a factory to use for creating QNetworkAccessManager(s).
1216
1217 QNetworkAccessManager is used for all network access by QML. By
1218 implementing a factory it is possible to create custom
1219 QNetworkAccessManager with specialized caching, proxy and cookie
1220 support.
1221
1222 The factory must be set before executing the engine.
1223
1224 \note QQmlEngine does not take ownership of the factory.
1225*/
1226void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
1227{
1228 Q_D(QQmlEngine);
1229 QMutexLocker locker(&d->networkAccessManagerMutex);
1230 d->networkAccessManagerFactory = factory;
1231}
1232
1233/*!
1234 Returns the current QQmlNetworkAccessManagerFactory.
1235
1236 \sa setNetworkAccessManagerFactory()
1237*/
1238QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
1239{
1240 Q_D(const QQmlEngine);
1241 return d->networkAccessManagerFactory;
1242}
1243
1244QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
1245{
1246 QMutexLocker locker(&networkAccessManagerMutex);
1247 QNetworkAccessManager *nam;
1248 if (networkAccessManagerFactory) {
1249 nam = networkAccessManagerFactory->create(parent);
1250 } else {
1251 nam = new QNetworkAccessManager(parent);
1252 }
1253
1254 return nam;
1255}
1256
1257QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
1258{
1259 Q_Q(const QQmlEngine);
1260 if (!networkAccessManager)
1261 networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
1262 return networkAccessManager;
1263}
1264
1265/*!
1266 Returns a common QNetworkAccessManager which can be used by any QML
1267 type instantiated by this engine.
1268
1269 If a QQmlNetworkAccessManagerFactory has been set and a
1270 QNetworkAccessManager has not yet been created, the
1271 QQmlNetworkAccessManagerFactory will be used to create the
1272 QNetworkAccessManager; otherwise the returned QNetworkAccessManager
1273 will have no proxy or cache set.
1274
1275 \sa setNetworkAccessManagerFactory()
1276*/
1277QNetworkAccessManager *QQmlEngine::networkAccessManager() const
1278{
1279 Q_D(const QQmlEngine);
1280 return d->getNetworkAccessManager();
1281}
1282#endif // qml_network
1283
1284/*!
1285
1286 Sets the \a provider to use for images requested via the \e
1287 image: url scheme, with host \a providerId. The QQmlEngine
1288 takes ownership of \a provider.
1289
1290 Image providers enable support for pixmap and threaded image
1291 requests. See the QQuickImageProvider documentation for details on
1292 implementing and using image providers.
1293
1294 All required image providers should be added to the engine before any
1295 QML sources files are loaded.
1296
1297 \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
1298*/
1299void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
1300{
1301 Q_D(QQmlEngine);
1302 QMutexLocker locker(&d->mutex);
1303 d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
1304}
1305
1306/*!
1307 Returns the image provider set for \a providerId if found; otherwise returns \nullptr.
1308
1309 \sa QQuickImageProvider
1310*/
1311QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
1312{
1313 Q_D(const QQmlEngine);
1314 QMutexLocker locker(&d->mutex);
1315 return d->imageProviders.value(providerId.toLower()).data();
1316}
1317
1318/*!
1319 Removes the image provider for \a providerId.
1320
1321 \sa addImageProvider(), QQuickImageProvider
1322*/
1323void QQmlEngine::removeImageProvider(const QString &providerId)
1324{
1325 Q_D(QQmlEngine);
1326 QMutexLocker locker(&d->mutex);
1327 d->imageProviders.take(providerId.toLower());
1328}
1329
1330/*!
1331 Return the base URL for this engine. The base URL is only used to
1332 resolve components when a relative URL is passed to the
1333 QQmlComponent constructor.
1334
1335 If a base URL has not been explicitly set, this method returns the
1336 application's current working directory.
1337
1338 \sa setBaseUrl()
1339*/
1340QUrl QQmlEngine::baseUrl() const
1341{
1342 Q_D(const QQmlEngine);
1343 if (d->baseUrl.isEmpty()) {
1344 return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
1345 } else {
1346 return d->baseUrl;
1347 }
1348}
1349
1350/*!
1351 Set the base URL for this engine to \a url.
1352
1353 \sa baseUrl()
1354*/
1355void QQmlEngine::setBaseUrl(const QUrl &url)
1356{
1357 Q_D(QQmlEngine);
1358 d->baseUrl = url;
1359}
1360
1361/*!
1362 Returns true if warning messages will be output to stderr in addition
1363 to being emitted by the warnings() signal, otherwise false.
1364
1365 The default value is true.
1366*/
1367bool QQmlEngine::outputWarningsToStandardError() const
1368{
1369 Q_D(const QQmlEngine);
1370 return d->outputWarningsToMsgLog;
1371}
1372
1373/*!
1374 Set whether warning messages will be output to stderr to \a enabled.
1375
1376 If \a enabled is true, any warning messages generated by QML will be
1377 output to stderr and emitted by the warnings() signal. If \a enabled
1378 is false, only the warnings() signal will be emitted. This allows
1379 applications to handle warning output themselves.
1380
1381 The default value is true.
1382*/
1383void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
1384{
1385 Q_D(QQmlEngine);
1386 d->outputWarningsToMsgLog = enabled;
1387}
1388
1389/*!
1390 \fn template<typename T> T QQmlEngine::singletonInstance(int qmlTypeId)
1391
1392 Returns the instance of a singleton type that was registered under \a qmlTypeId.
1393
1394 The template argument \e T may be either QJSValue or a pointer to a QObject-derived
1395 type and depends on how the singleton was registered. If no instance of \e T has been
1396 created yet, it is created now. If \a qmlTypeId does not represent a valid singleton
1397 type, either a default constructed QJSValue or a \c nullptr is returned.
1398
1399 QObject* example:
1400 \code
1401 class MySingleton : public QObject {
1402 Q_OBJECT
1403 static int typeId;
1404 // ...
1405 };
1406
1407 // Register with QObject* callback
1408 MySingleton::typeId = qmlRegisterSingletonType<MySingleton>(...);
1409
1410 // Retrieve as QObject*
1411 QQmlEngine engine;
1412 MySingleton* instance = engine.singletonInstance<MySingleton*>(MySingleton::typeId);
1413 \endcode
1414
1415 QJSValue example:
1416 \code
1417 // Register with QJSValue callback
1418 int typeId = qmlRegisterSingletonType(...);
1419
1420 // Retrieve as QJSValue
1421 QQmlEngine engine;
1422 QJSValue instance = engine.singletonInstance<QJSValue>(typeId);
1423 \endcode
1424
1425 It is recommended to store the QML type id during registration, e.g. as a static member
1426 in the singleton class. Otherwise, a costly lookup via qmlTypeId() has to be performed
1427 at run-time.
1428
1429 \sa qmlRegisterSingletonType(), qmlTypeId()
1430 \since 5.12
1431*/
1432template<>
1433QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
1434{
1435 QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType);
1436
1437 if (!type.isValid() || !type.isSingleton())
1438 return QJSValue();
1439
1440 QQmlType::SingletonInstanceInfo* info = type.singletonInstanceInfo();
1441 info->init(this);
1442
1443 if (QObject* o = info->qobjectApi(this))
1444 return this->newQObject(o);
1445 else {
1446 QJSValue value = info->scriptApi(this);
1447 if (!value.isUndefined())
1448 return value;
1449 }
1450
1451 return QJSValue();
1452}
1453
1454/*!
1455 Refreshes all binding expressions that use strings marked for translation.
1456
1457 Call this function after you have installed a new translator with
1458 QCoreApplication::installTranslator, to ensure that your user-interface
1459 shows up-to-date translations.
1460
1461 \note Due to a limitation in the implementation, this function
1462 refreshes all the engine's bindings, not only those that use strings
1463 marked for translation.
1464 This may be optimized in a future release.
1465
1466 \since 5.10
1467*/
1468void QQmlEngine::retranslate()
1469{
1470 Q_D(QQmlEngine);
1471 QQmlContextData *context = QQmlContextData::get(d->rootContext)->childContexts;
1472 while (context) {
1473 context->refreshExpressions();
1474 context = context->nextChild;
1475 }
1476}
1477
1478/*!
1479 Returns the QQmlContext for the \a object, or 0 if no
1480 context has been set.
1481
1482 When the QQmlEngine instantiates a QObject, the context is
1483 set automatically.
1484
1485 \sa qmlContext(), qmlEngine()
1486 */
1487QQmlContext *QQmlEngine::contextForObject(const QObject *object)
1488{
1489 if(!object)
1490 return nullptr;
1491
1492 QQmlData *data = QQmlData::get(object);
1493 if (data && data->outerContext)
1494 return data->outerContext->asQQmlContext();
1495
1496 return nullptr;
1497}
1498
1499/*!
1500 Sets the QQmlContext for the \a object to \a context.
1501 If the \a object already has a context, a warning is
1502 output, but the context is not changed.
1503
1504 When the QQmlEngine instantiates a QObject, the context is
1505 set automatically.
1506 */
1507void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
1508{
1509 if (!object || !context)
1510 return;
1511
1512 QQmlData *data = QQmlData::get(object, true);
1513 if (data->context) {
1514 qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
1515 return;
1516 }
1517
1518 QQmlContextData *contextData = QQmlContextData::get(context);
1519 Q_ASSERT(data->context == nullptr);
1520 data->context = contextData;
1521 contextData->addObject(data);
1522}
1523
1524/*!
1525 \enum QQmlEngine::ObjectOwnership
1526
1527 ObjectOwnership controls whether or not QML automatically destroys the
1528 QObject when the corresponding JavaScript object is garbage collected by the
1529 engine. The two ownership options are:
1530
1531 \value CppOwnership The object is owned by C++ code and QML will never delete
1532 it. The JavaScript destroy() method cannot be used on these objects. This
1533 option is similar to QScriptEngine::QtOwnership.
1534
1535 \value JavaScriptOwnership The object is owned by JavaScript. When the object
1536 is returned to QML as the return value of a method call, QML will track it
1537 and delete it if there are no remaining JavaScript references to it and
1538 it has no QObject::parent(). An object tracked by one QQmlEngine will be
1539 deleted during that QQmlEngine's destructor. Thus, JavaScript references
1540 between objects with JavaScriptOwnership from two different engines will
1541 not be valid if one of these engines is deleted. This option is similar to
1542 QScriptEngine::ScriptOwnership.
1543
1544 Generally an application doesn't need to set an object's ownership
1545 explicitly. QML uses a heuristic to set the default ownership. By default, an
1546 object that is created by QML has JavaScriptOwnership. The exception to this
1547 are the root objects created by calling QQmlComponent::create() or
1548 QQmlComponent::beginCreate(), which have CppOwnership by default. The
1549 ownership of these root-level objects is considered to have been transferred
1550 to the C++ caller.
1551
1552 Objects not-created by QML have CppOwnership by default. The exception to this
1553 are objects returned from C++ method calls; their ownership will be set to
1554 JavaScriptOwnership. This applies only to explicit invocations of Q_INVOKABLE
1555 methods or slots, but not to property getter invocations.
1556
1557 Calling setObjectOwnership() overrides the default ownership heuristic used by
1558 QML.
1559*/
1560
1561/*!
1562 Sets the \a ownership of \a object.
1563*/
1564void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1565{
1566 if (!object)
1567 return;
1568
1569 QQmlData *ddata = QQmlData::get(object, true);
1570 if (!ddata)
1571 return;
1572
1573 ddata->indestructible = (ownership == CppOwnership)?true:false;
1574 ddata->explicitIndestructibleSet = true;
1575}
1576
1577/*!
1578 Returns the ownership of \a object.
1579*/
1580QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
1581{
1582 if (!object)
1583 return CppOwnership;
1584
1585 QQmlData *ddata = QQmlData::get(object, false);
1586 if (!ddata)
1587 return CppOwnership;
1588 else
1589 return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1590}
1591
1592/*!
1593 \reimp
1594*/
1595bool QQmlEngine::event(QEvent *e)
1596{
1597 Q_D(QQmlEngine);
1598 if (e->type() == QEvent::User)
1599 d->doDeleteInEngineThread();
1600 else if (e->type() == QEvent::LanguageChange) {
1601 retranslate();
1602 }
1603
1604 return QJSEngine::event(e);
1605}
1606
1607void QQmlEnginePrivate::doDeleteInEngineThread()
1608{
1609 QFieldList<Deletable, &Deletable::next> list;
1610 mutex.lock();
1611 list.copyAndClear(toDeleteInEngineThread);
1612 mutex.unlock();
1613
1614 while (Deletable *d = list.takeFirst())
1615 delete d;
1616}
1617
1618namespace QtQml {
1619
1620void qmlExecuteDeferred(QObject *object)
1621{
1622 QQmlData *data = QQmlData::get(object);
1623
1624 if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
1625 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
1626
1627 QQmlComponentPrivate::DeferredState state;
1628 QQmlComponentPrivate::beginDeferred(ep, object, &state);
1629
1630 // Release the reference for the deferral action (we still have one from construction)
1631 data->releaseDeferredData();
1632
1633 QQmlComponentPrivate::completeDeferred(ep, &state);
1634 }
1635}
1636
1637QQmlContext *qmlContext(const QObject *obj)
1638{
1639 return QQmlEngine::contextForObject(obj);
1640}
1641
1642QQmlEngine *qmlEngine(const QObject *obj)
1643{
1644 QQmlData *data = QQmlData::get(obj, false);
1645 if (!data || !data->context)
1646 return nullptr;
1647 return data->context->engine;
1648}
1649
1650QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1651{
1652 QQmlData *data = QQmlData::get(object, create);
1653 if (!data)
1654 return nullptr; // Attached properties are only on objects created by QML, unless explicitly requested (create==true)
1655
1656 QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
1657 if (rv || !create)
1658 return rv;
1659
1660 QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context);
1661 QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(engine, id);
1662 if (!pf)
1663 return nullptr;
1664
1665 rv = pf(const_cast<QObject *>(object));
1666
1667 if (rv)
1668 data->attachedProperties()->insert(id, rv);
1669
1670 return rv;
1671}
1672
1673QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1674 const QMetaObject *attachedMetaObject, bool create)
1675{
1676 if (*idCache == -1) {
1677 QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
1678 *idCache = QQmlMetaType::attachedPropertiesFuncId(engine ? QQmlEnginePrivate::get(engine) : nullptr, attachedMetaObject);
1679 }
1680
1681 if (*idCache == -1 || !object)
1682 return nullptr;
1683
1684 return qmlAttachedPropertiesObjectById(*idCache, object, create);
1685}
1686
1687} // namespace QtQml
1688
1689#if QT_DEPRECATED_SINCE(5, 1)
1690
1691// Also define symbols outside namespace to keep binary compatibility with Qt 5.0
1692
1693Q_QML_EXPORT void qmlExecuteDeferred(QObject *obj)
1694{
1695 QtQml::qmlExecuteDeferred(obj);
1696}
1697
1698Q_QML_EXPORT QQmlContext *qmlContext(const QObject *obj)
1699{
1700 return QtQml::qmlContext(obj);
1701}
1702
1703Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *obj)
1704{
1705 return QtQml::qmlEngine(obj);
1706}
1707
1708Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int id, const QObject *obj, bool create)
1709{
1710 return QtQml::qmlAttachedPropertiesObjectById(id, obj, create);
1711}
1712
1713Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1714 const QMetaObject *attachedMetaObject,
1715 bool create)
1716{
1717 return QtQml::qmlAttachedPropertiesObject(idCache, object, attachedMetaObject, create);
1718}
1719
1720#endif // QT_DEPRECATED_SINCE(5, 1)
1721
1722class QQmlDataExtended {
1723public:
1724 QQmlDataExtended();
1725 ~QQmlDataExtended();
1726
1727 QHash<int, QObject *> attachedProperties;
1728};
1729
1730QQmlDataExtended::QQmlDataExtended()
1731{
1732}
1733
1734QQmlDataExtended::~QQmlDataExtended()
1735{
1736}
1737
1738void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1739{
1740 // Add a temporary sentinel at beginning of list. This will be overwritten
1741 // when the end point is inserted into the notifies further down.
1742 endpoint->prev = nullptr;
1743
1744 while (endpoint->next) {
1745 Q_ASSERT(reinterpret_cast<QQmlNotifierEndpoint *>(endpoint->next->prev) == endpoint);
1746 endpoint = endpoint->next;
1747 }
1748
1749 while (endpoint) {
1750 QQmlNotifierEndpoint *ep = (QQmlNotifierEndpoint *) endpoint->prev;
1751
1752 int index = endpoint->sourceSignal;
1753 index = qMin(index, 0xFFFF - 1);
1754
1755 endpoint->next = notifies[index];
1756 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1757 endpoint->prev = &notifies[index];
1758 notifies[index] = endpoint;
1759
1760 endpoint = ep;
1761 }
1762}
1763
1764void QQmlData::NotifyList::layout()
1765{
1766 Q_ASSERT(maximumTodoIndex >= notifiesSize);
1767
1768 if (todo) {
1769 QQmlNotifierEndpoint **old = notifies;
1770 const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1771 notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
1772 const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1773 sizeof(QQmlNotifierEndpoint*);
1774 memset(notifies + notifiesSize, 0, memsetSize);
1775
1776 if (notifies != old) {
1777 for (int ii = 0; ii < notifiesSize; ++ii)
1778 if (notifies[ii])
1779 notifies[ii]->prev = &notifies[ii];
1780 }
1781
1782 notifiesSize = maximumTodoIndex + 1;
1783
1784 layout(todo);
1785 }
1786
1787 maximumTodoIndex = 0;
1788 todo = nullptr;
1789}
1790
1791void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlContextData *context)
1792{
1793 QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
1794 deferData->deferredIdx = objectIndex;
1795 deferData->compilationUnit = compilationUnit;
1796 deferData->context = context;
1797
1798 const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex);
1799 const QV4::CompiledData::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
1800
1801 const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
1802 for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
1803 const QQmlPropertyData *property = propertyData.at(i);
1804 if (property && binding->flags & QV4::CompiledData::Binding::IsDeferredBinding)
1805 deferData->bindings.insert(property->coreIndex(), binding);
1806 }
1807
1808 deferredData.append(deferData);
1809}
1810
1811void QQmlData::releaseDeferredData()
1812{
1813 auto it = deferredData.begin();
1814 while (it != deferredData.end()) {
1815 DeferredData *deferData = *it;
1816 if (deferData->bindings.isEmpty()) {
1817 delete deferData;
1818 it = deferredData.erase(it);
1819 } else {
1820 ++it;
1821 }
1822 }
1823}
1824
1825void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1826{
1827 if (!notifyList) {
1828 notifyList = (NotifyList *)malloc(sizeof(NotifyList));
1829 notifyList->connectionMask = 0;
1830 notifyList->maximumTodoIndex = 0;
1831 notifyList->notifiesSize = 0;
1832 notifyList->todo = nullptr;
1833 notifyList->notifies = nullptr;
1834 }
1835
1836 Q_ASSERT(!endpoint->isConnected());
1837
1838 index = qMin(index, 0xFFFF - 1);
1839 notifyList->connectionMask |= (1ULL << quint64(index % 64));
1840
1841 if (index < notifyList->notifiesSize) {
1842
1843 endpoint->next = notifyList->notifies[index];
1844 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1845 endpoint->prev = &notifyList->notifies[index];
1846 notifyList->notifies[index] = endpoint;
1847
1848 } else {
1849 notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
1850
1851 endpoint->next = notifyList->todo;
1852 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1853 endpoint->prev = &notifyList->todo;
1854 notifyList->todo = endpoint;
1855 }
1856}
1857
1858void QQmlData::disconnectNotifiers()
1859{
1860 if (notifyList) {
1861 while (notifyList->todo)
1862 notifyList->todo->disconnect();
1863 for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1864 while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1865 ep->disconnect();
1866 }
1867 free(notifyList->notifies);
1868 free(notifyList);
1869 notifyList = nullptr;
1870 }
1871}
1872
1873QHash<int, QObject *> *QQmlData::attachedProperties() const
1874{
1875 if (!extendedData) extendedData = new QQmlDataExtended;
1876 return &extendedData->attachedProperties;
1877}
1878
1879void QQmlData::destroyed(QObject *object)
1880{
1881 if (nextContextObject)
1882 nextContextObject->prevContextObject = prevContextObject;
1883 if (prevContextObject)
1884 *prevContextObject = nextContextObject;
1885 else if (outerContext && outerContext->contextObjects == this)
1886 outerContext->contextObjects = nextContextObject;
1887
1888 QQmlAbstractBinding *binding = bindings;
1889 while (binding) {
1890 binding->setAddedToObject(false);
1891 binding = binding->nextBinding();
1892 }
1893 if (bindings && !bindings->ref.deref())
1894 delete bindings;
1895
1896 compilationUnit = nullptr;
1897
1898 qDeleteAll(deferredData);
1899 deferredData.clear();
1900
1901 QQmlBoundSignal *signalHandler = signalHandlers;
1902 while (signalHandler) {
1903 if (signalHandler->isNotifying()) {
1904 // The object is being deleted during signal handler evaluation.
1905 // This will cause a crash due to invalid memory access when the
1906 // evaluation has completed.
1907 // Abort with a friendly message instead.
1908 QString locationString;
1909 QQmlBoundSignalExpression *expr = signalHandler->expression();
1910 if (expr) {
1911 QQmlSourceLocation location = expr->sourceLocation();
1912 if (location.sourceFile.isEmpty())
1913 location.sourceFile = QStringLiteral("<Unknown File>");
1914 locationString.append(location.sourceFile);
1915 locationString.append(QStringLiteral(":%0: ").arg(location.line));
1916 QString source = expr->expression();
1917 if (source.size() > 100) {
1918 source.truncate(96);
1919 source.append(QLatin1String(" ..."));
1920 }
1921 locationString.append(source);
1922 } else {
1923 locationString = QStringLiteral("<Unknown Location>");
1924 }
1925 qFatal("Object %p destroyed while one of its QML signal handlers is in progress.\n"
1926 "Most likely the object was deleted synchronously (use QObject::deleteLater() "
1927 "instead), or the application is running a nested event loop.\n"
1928 "This behavior is NOT supported!\n"
1929 "%s", object, qPrintable(locationString));
1930 }
1931
1932 QQmlBoundSignal *next = signalHandler->m_nextSignal;
1933 signalHandler->m_prevSignal = nullptr;
1934 signalHandler->m_nextSignal = nullptr;
1935 delete signalHandler;
1936 signalHandler = next;
1937 }
1938
1939 if (bindingBitsArraySize > InlineBindingArraySize)
1940 free(bindingBits);
1941
1942 if (propertyCache)
1943 propertyCache->release();
1944
1945 ownContext = nullptr;
1946
1947 while (guards) {
1948 QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1949 *guard = (QObject *)nullptr;
1950 guard->objectDestroyed(object);
1951 }
1952
1953 disconnectNotifiers();
1954
1955 if (extendedData)
1956 delete extendedData;
1957
1958 // Dispose the handle.
1959 jsWrapper.clear();
1960
1961 if (ownMemory)
1962 delete this;
1963 else
1964 this->~QQmlData();
1965}
1966
1967DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
1968
1969void QQmlData::parentChanged(QObject *object, QObject *parent)
1970{
1971 if (parentTest()) {
1972 if (parentFrozen && !QObjectPrivate::get(object)->wasDeleted) {
1973 QString on;
1974 QString pn;
1975
1976 { QDebug dbg(&on); dbg << object; on = on.left(on.length() - 1); }
1977 { QDebug dbg(&pn); dbg << parent; pn = pn.left(pn.length() - 1); }
1978
1979 qFatal("Object %s has had its parent frozen by QML and cannot be changed.\n"
1980 "User code is attempting to change it to %s.\n"
1981 "This behavior is NOT supported!", qPrintable(on), qPrintable(pn));
1982 }
1983 }
1984}
1985
1986QQmlData::BindingBitsType *QQmlData::growBits(QObject *obj, int bit)
1987{
1988 BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
1989 int props = QQmlMetaObject(obj).propertyCount();
1990 Q_ASSERT(bit < 2 * props);
1991 Q_UNUSED(bit); // .. for Q_NO_DEBUG mode when the assert above expands to empty
1992
1993 uint arraySize = (2 * static_cast<uint>(props) + BitsPerType - 1) / BitsPerType;
1994 Q_ASSERT(arraySize > 1);
1995 Q_ASSERT(arraySize <= 0xffff); // max for bindingBitsArraySize
1996
1997 BindingBitsType *newBits = static_cast<BindingBitsType *>(malloc(arraySize*sizeof(BindingBitsType)));
1998 memcpy(newBits, bits, bindingBitsArraySize * sizeof(BindingBitsType));
1999 memset(newBits + bindingBitsArraySize, 0, sizeof(BindingBitsType) * (arraySize - bindingBitsArraySize));
2000
2001 if (bindingBitsArraySize > InlineBindingArraySize)
2002 free(bits);
2003 bindingBits = newBits;
2004 bits = newBits;
2005 bindingBitsArraySize = arraySize;
2006 return bits;
2007}
2008
2009QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
2010{
2011 Q_ASSERT(priv);
2012 Q_ASSERT(!priv->isDeletingChildren);
2013 priv->declarativeData = new QQmlData;
2014 return static_cast<QQmlData *>(priv->declarativeData);
2015}
2016
2017QQmlPropertyCache *QQmlData::createPropertyCache(QJSEngine *engine, QObject *object)
2018{
2019 QQmlData *ddata = QQmlData::get(object, /*create*/true);
2020 ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object);
2021 if (ddata->propertyCache)
2022 ddata->propertyCache->addref();
2023 return ddata->propertyCache;
2024}
2025
2026void QQmlEnginePrivate::sendQuit()
2027{
2028 Q_Q(QQmlEngine);
2029 emit q->quit();
2030 if (q->receivers(SIGNAL(quit())) == 0) {
2031 qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
2032 }
2033}
2034
2035void QQmlEnginePrivate::sendExit(int retCode)
2036{
2037 Q_Q(QQmlEngine);
2038 if (q->receivers(SIGNAL(exit(int))) == 0)
2039 qWarning("Signal QQmlEngine::exit() emitted, but no receivers connected to handle it.");
2040 emit q->exit(retCode);
2041}
2042
2043static void dumpwarning(const QQmlError &error)
2044{
2045 switch (error.messageType()) {
2046 case QtDebugMsg:
2047 QMessageLogger(error.url().toString().toLatin1().constData(),
2048 error.line(), nullptr).debug().nospace()
2049 << qPrintable(error.toString());
2050 break;
2051 case QtInfoMsg:
2052 QMessageLogger(error.url().toString().toLatin1().constData(),
2053 error.line(), nullptr).info().nospace()
2054 << qPrintable(error.toString());
2055 break;
2056 case QtWarningMsg:
2057 case QtFatalMsg: // fatal does not support streaming, and furthermore, is actually fatal. Probably not desirable for QML.
2058 QMessageLogger(error.url().toString().toLatin1().constData(),
2059 error.line(), nullptr).warning().nospace()
2060 << qPrintable(error.toString());
2061 break;
2062 case QtCriticalMsg:
2063 QMessageLogger(error.url().toString().toLatin1().constData(),
2064 error.line(), nullptr).critical().nospace()
2065 << qPrintable(error.toString());
2066 break;
2067 }
2068}
2069
2070static void dumpwarning(const QList<QQmlError> &errors)
2071{
2072 for (int ii = 0; ii < errors.count(); ++ii)
2073 dumpwarning(errors.at(ii));
2074}
2075
2076void QQmlEnginePrivate::warning(const QQmlError &error)
2077{
2078 Q_Q(QQmlEngine);
2079 q->warnings(QList<QQmlError>() << error);
2080 if (outputWarningsToMsgLog)
2081 dumpwarning(error);
2082}
2083
2084void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
2085{
2086 Q_Q(QQmlEngine);
2087 q->warnings(errors);
2088 if (outputWarningsToMsgLog)
2089 dumpwarning(errors);
2090}
2091
2092void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
2093{
2094 if (engine)
2095 QQmlEnginePrivate::get(engine)->warning(error);
2096 else
2097 dumpwarning(error);
2098}
2099
2100void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
2101{
2102 if (engine)
2103 QQmlEnginePrivate::get(engine)->warning(error);
2104 else
2105 dumpwarning(error);
2106}
2107
2108void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
2109{
2110 if (engine)
2111 engine->warning(error);
2112 else
2113 dumpwarning(error);
2114}
2115
2116void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
2117{
2118 if (engine)
2119 engine->warning(error);
2120 else
2121 dumpwarning(error);
2122}
2123
2124QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(const QString &fileName, const QList<DiagnosticMessage> &diagnosticMessages)
2125{
2126 QList<QQmlError> errors;
2127 for (const DiagnosticMessage &m : diagnosticMessages) {
2128 if (m.isWarning()) {
2129 qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
2130 continue;
2131 }
2132
2133 QQmlError error;
2134 error.setUrl(QUrl(fileName));
2135 error.setDescription(m.message);
2136 error.setLine(m.loc.startLine);
2137 error.setColumn(m.loc.startColumn);
2138 errors << error;
2139 }
2140 return errors;
2141}
2142
2143void QQmlEnginePrivate::cleanupScarceResources()
2144{
2145 // iterate through the list and release them all.
2146 // note that the actual SRD is owned by the JS engine,
2147 // so we cannot delete the SRD; but we can free the
2148 // memory used by the variant in the SRD.
2149 QV4::ExecutionEngine *engine = v4engine();
2150 while (QV4::ExecutionEngine::ScarceResourceData *sr = engine->scarceResources.first()) {
2151 sr->data = QVariant();
2152 engine->scarceResources.remove(sr);
2153 }
2154}
2155
2156/*!
2157 Adds \a path as a directory where the engine searches for
2158 installed modules in a URL-based directory structure.
2159
2160 The \a path may be a local filesystem directory, a
2161 \l {The Qt Resource System}{Qt Resource} path (\c {:/imports}), a
2162 \l {The Qt Resource System}{Qt Resource} url (\c {qrc:/imports}) or a URL.
2163
2164 The \a path will be converted into canonical form before it
2165 is added to the import path list.
2166
2167 The newly added \a path will be first in the importPathList().
2168
2169 \sa setImportPathList(), {QML Modules}
2170*/
2171void QQmlEngine::addImportPath(const QString& path)
2172{
2173 Q_D(QQmlEngine);
2174 d->importDatabase.addImportPath(path);
2175}
2176
2177/*!
2178 Returns the list of directories where the engine searches for
2179 installed modules in a URL-based directory structure.
2180
2181 For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
2182 imports \c com.mycompany.Feature will cause the QQmlEngine to look
2183 in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
2184 provided by that module. A \c qmldir file is required for defining the
2185 type version mapping and possibly QML extensions plugins.
2186
2187 By default, the list contains the directory of the application executable,
2188 paths specified in the \c QML2_IMPORT_PATH environment variable,
2189 and the builtin \c Qml2ImportsPath from QLibraryInfo.
2190
2191 \sa addImportPath(), setImportPathList()
2192*/
2193QStringList QQmlEngine::importPathList() const
2194{
2195 Q_D(const QQmlEngine);
2196 return d->importDatabase.importPathList();
2197}
2198
2199/*!
2200 Sets \a paths as the list of directories where the engine searches for
2201 installed modules in a URL-based directory structure.
2202
2203 By default, the list contains the directory of the application executable,
2204 paths specified in the \c QML2_IMPORT_PATH environment variable,
2205 and the builtin \c Qml2ImportsPath from QLibraryInfo.
2206
2207 \sa importPathList(), addImportPath()
2208 */
2209void QQmlEngine::setImportPathList(const QStringList &paths)
2210{
2211 Q_D(QQmlEngine);
2212 d->importDatabase.setImportPathList(paths);
2213}
2214
2215
2216/*!
2217 Adds \a path as a directory where the engine searches for
2218 native plugins for imported modules (referenced in the \c qmldir file).
2219
2220 By default, the list contains only \c ., i.e. the engine searches
2221 in the directory of the \c qmldir file itself.
2222
2223 The newly added \a path will be first in the pluginPathList().
2224
2225 \sa setPluginPathList()
2226*/
2227void QQmlEngine::addPluginPath(const QString& path)
2228{
2229 Q_D(QQmlEngine);
2230 d->importDatabase.addPluginPath(path);
2231}
2232
2233
2234/*!
2235 Returns the list of directories where the engine searches for
2236 native plugins for imported modules (referenced in the \c qmldir file).
2237
2238 By default, the list contains only \c ., i.e. the engine searches
2239 in the directory of the \c qmldir file itself.
2240
2241 \sa addPluginPath(), setPluginPathList()
2242*/
2243QStringList QQmlEngine::pluginPathList() const
2244{
2245 Q_D(const QQmlEngine);
2246 return d->importDatabase.pluginPathList();
2247}
2248
2249/*!
2250 Sets the list of directories where the engine searches for
2251 native plugins for imported modules (referenced in the \c qmldir file)
2252 to \a paths.
2253
2254 By default, the list contains only \c ., i.e. the engine searches
2255 in the directory of the \c qmldir file itself.
2256
2257 \sa pluginPathList(), addPluginPath()
2258 */
2259void QQmlEngine::setPluginPathList(const QStringList &paths)
2260{
2261 Q_D(QQmlEngine);
2262 d->importDatabase.setPluginPathList(paths);
2263}
2264
2265/*!
2266 Imports the plugin named \a filePath with the \a uri provided.
2267 Returns true if the plugin was successfully imported; otherwise returns false.
2268
2269 On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
2270
2271 The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
2272*/
2273bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
2274{
2275 Q_D(QQmlEngine);
2276 return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), -1, errors);
2277}
2278
2279/*!
2280 \property QQmlEngine::offlineStoragePath
2281 \brief the directory for storing offline user data
2282
2283 Returns the directory where SQL and other offline
2284 storage is placed.
2285
2286 The SQL databases created with openDatabase() are stored here.
2287
2288 The default is QML/OfflineStorage in the platform-standard
2289 user application data directory.
2290
2291 Note that the path may not currently exist on the filesystem, so
2292 callers wanting to \e create new files at this location should create
2293 it first - see QDir::mkpath().
2294*/
2295void QQmlEngine::setOfflineStoragePath(const QString& dir)
2296{
2297 Q_D(QQmlEngine);
2298 d->offlineStoragePath = dir;
2299}
2300
2301QString QQmlEngine::offlineStoragePath() const
2302{
2303 Q_D(const QQmlEngine);
2304
2305 if (d->offlineStoragePath.isEmpty()) {
2306 QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
2307 QQmlEnginePrivate *e = const_cast<QQmlEnginePrivate *>(d);
2308 if (!dataLocation.isEmpty())
2309 e->offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
2310 + QDir::separator() + QLatin1String("QML")
2311 + QDir::separator() + QLatin1String("OfflineStorage");
2312 }
2313
2314 return d->offlineStoragePath;
2315}
2316
2317/*!
2318 Returns the file path where a \l{QtQuick.LocalStorage}{Local Storage}
2319 database with the identifier \a databaseName is (or would be) located.
2320
2321 \sa {openDatabaseSync}{LocalStorage.openDatabaseSync()}
2322 \since 5.9
2323*/
2324QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName) const
2325{
2326 Q_D(const QQmlEngine);
2327 QCryptographicHash md5(QCryptographicHash::Md5);
2328 md5.addData(databaseName.toUtf8());
2329 return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex());
2330}
2331
2332QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
2333{
2334 Q_Q(const QQmlEngine);
2335 return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator();
2336}
2337
2338bool QQmlEnginePrivate::isQObject(int t)
2339{
2340 Locker locker(this);
2341 return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
2342}
2343
2344QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
2345{
2346 Locker locker(this);
2347 int t = v.userType();
2348 if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
2349 if (ok) *ok = true;
2350 return *(QObject *const *)(v.constData());
2351 } else {
2352 return QQmlMetaType::toQObject(v, ok);
2353 }
2354}
2355
2356QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
2357{
2358 Locker locker(this);
2359 if (m_compositeTypes.contains(t))
2360 return QQmlMetaType::Object;
2361 return QQmlMetaType::typeCategory(t);
2362}
2363
2364bool QQmlEnginePrivate::isList(int t) const
2365{
2366 return QQmlMetaType::isList(t);
2367}
2368
2369int QQmlEnginePrivate::listType(int t) const
2370{
2371 return QQmlMetaType::listType(t);
2372}
2373
2374QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
2375{
2376 Locker locker(this);
2377 auto iter = m_compositeTypes.constFind(t);
2378 if (iter != m_compositeTypes.cend()) {
2379 return QQmlMetaObject((*iter)->rootPropertyCache().data());
2380 } else {
2381 QQmlType type = QQmlMetaType::qmlType(t);
2382 return QQmlMetaObject(type.baseMetaObject());
2383 }
2384}
2385
2386QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
2387{
2388 Locker locker(this);
2389 auto iter = m_compositeTypes.constFind(t);
2390 if (iter != m_compositeTypes.cend()) {
2391 return QQmlMetaObject((*iter)->rootPropertyCache().data());
2392 } else {
2393 QQmlType type = QQmlMetaType::qmlType(t);
2394 return QQmlMetaObject(type.metaObject());
2395 }
2396}
2397
2398QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
2399{
2400 Locker locker(this);
2401 auto iter = m_compositeTypes.constFind(t);
2402 if (iter != m_compositeTypes.cend()) {
2403 return (*iter)->rootPropertyCache().data();
2404 } else {
2405 QQmlType type = QQmlMetaType::qmlType(t);
2406 locker.unlock();
2407 return type.isValid() ? cache(type.metaObject()) : nullptr;
2408 }
2409}
2410
2411QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVersion)
2412{
2413 Locker locker(this);
2414 auto iter = m_compositeTypes.constFind(t);
2415 if (iter != m_compositeTypes.cend()) {
2416 return (*iter)->rootPropertyCache().data();
2417 } else {
2418 QQmlType type = QQmlMetaType::qmlType(t);
2419 locker.unlock();
2420
2421 if (minorVersion >= 0)
2422 return type.isValid() ? cache(type, minorVersion) : nullptr;
2423 else
2424 return type.isValid() ? cache(type.baseMetaObject()) : nullptr;
2425 }
2426}
2427
2428void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
2429{
2430 compilationUnit->isRegisteredWithEngine = true;
2431
2432 Locker locker(this);
2433 // The QQmlCompiledData is not referenced here, but it is removed from this
2434 // hash in the QQmlCompiledData destructor
2435 m_compositeTypes.insert(compilationUnit->metaTypeId, compilationUnit);
2436}
2437
2438void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
2439{
2440 compilationUnit->isRegisteredWithEngine = false;
2441
2442 Locker locker(this);
2443 m_compositeTypes.remove(compilationUnit->metaTypeId);
2444}
2445
2446bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
2447{
2448 return typeLoader.isTypeLoaded(url);
2449}
2450
2451bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
2452{
2453 return typeLoader.isScriptLoaded(url);
2454}
2455
2456#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
2457// Normalize a file name using Shell API. As opposed to converting it
2458// to a short 8.3 name and back, this also works for drives where 8.3 notation
2459// is disabled (see 8dot3name options of fsutil.exe).
2460static inline QString shellNormalizeFileName(const QString &name)
2461{
2462 const QString nativeSeparatorName(QDir::toNativeSeparators(name));
2463 const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16());
2464// The correct declaration of the SHGetPathFromIDList symbol is
2465// being used in mingw-w64 as of r6215, which is a v3 snapshot.
2466#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3)
2467 ITEMIDLIST *file;
2468 if (FAILED(SHParseDisplayName(nameC, NULL, reinterpret_cast<LPITEMIDLIST>(&file), 0, NULL)))
2469 return name;
2470#else
2471 PIDLIST_ABSOLUTE file;
2472 if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL)))
2473 return name;
2474#endif
2475 TCHAR buffer[MAX_PATH];
2476 bool gotPath = SHGetPathFromIDList(file, buffer);
2477 ILFree(file);
2478
2479 if (!gotPath)
2480 return name;
2481
2482 QString canonicalName = QString::fromWCharArray(buffer);
2483 // Upper case drive letter
2484 if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':'))
2485 canonicalName[0] = canonicalName.at(0).toUpper();
2486 return QDir::cleanPath(canonicalName);
2487}
2488#endif // Q_OS_WIN && !Q_OS_WINRT
2489
2490bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
2491{
2492#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
2493 QFileInfo info(fileName);
2494 const QString absolute = info.absoluteFilePath();
2495
2496#if defined(Q_OS_DARWIN) || defined(Q_OS_WINRT)
2497 const QString canonical = info.canonicalFilePath();
2498#elif defined(Q_OS_WIN)
2499 // No difference if the path is qrc based
2500 if (absolute[0] == QLatin1Char(':'))
2501 return true;
2502 const QString canonical = shellNormalizeFileName(absolute);
2503#endif
2504
2505 const int absoluteLength = absolute.length();
2506 const int canonicalLength = canonical.length();
2507
2508 int length = qMin(absoluteLength, canonicalLength);
2509 if (lengthIn >= 0) {
2510 length = qMin(lengthIn, length);
2511 } else {
2512 // No length given: Limit to file name. Do not trigger
2513 // on drive letters or folder names.
2514 int lastSlash = absolute.lastIndexOf(QLatin1Char('/'));
2515 if (lastSlash < 0)
2516 lastSlash = absolute.lastIndexOf(QLatin1Char('\\'));
2517 if (lastSlash >= 0) {
2518 const int fileNameLength = absoluteLength - 1 - lastSlash;
2519 length = qMin(length, fileNameLength);
2520 }
2521 }
2522
2523 for (int ii = 0; ii < length; ++ii) {
2524 const QChar &a = absolute.at(absoluteLength - 1 - ii);
2525 const QChar &c = canonical.at(canonicalLength - 1 - ii);
2526
2527 if (a.toLower() != c.toLower())
2528 return true;
2529 if (a != c)
2530 return false;
2531 }
2532#else
2533 Q_UNUSED(lengthIn)
2534 Q_UNUSED(fileName)
2535#endif
2536 return true;
2537}
2538
2539/*!
2540 \fn QQmlEngine *qmlEngine(const QObject *object)
2541 \relates QQmlEngine
2542
2543 Returns the QQmlEngine associated with \a object, if any. This is equivalent to
2544 QQmlEngine::contextForObject(object)->engine(), but more efficient.
2545
2546 \note Add \c{#include <QtQml>} to use this function.
2547
2548 \sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlContext()
2549*/
2550
2551/*!
2552 \fn QQmlContext *qmlContext(const QObject *object)
2553 \relates QQmlEngine
2554
2555 Returns the QQmlContext associated with \a object, if any. This is equivalent to
2556 QQmlEngine::contextForObject(object).
2557
2558 \note Add \c{#include <QtQml>} to use this function.
2559
2560 \sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlEngine()
2561*/
2562
2563QT_END_NAMESPACE
2564
2565#include "moc_qqmlengine.cpp"
2566