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