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