1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlbuiltinfunctions_p.h"
5
6#include <private/qqmlcomponent_p.h>
7#include <private/qqmldebugconnector_p.h>
8#include <private/qqmldebugserviceinterfaces_p.h>
9#include <private/qqmldelayedcallqueue_p.h>
10#include <private/qqmlengine_p.h>
11#include <private/qqmlloggingcategorybase_p.h>
12#include <private/qqmlplatform_p.h>
13#include <private/qqmlstringconverters_p.h>
14
15#include <private/qv4dateobject_p.h>
16#include <private/qv4engine_p.h>
17#include <private/qv4functionobject_p.h>
18#include <private/qv4include_p.h>
19#include <private/qv4mm_p.h>
20#include <private/qv4qobjectwrapper_p.h>
21#include <private/qv4sequenceobject_p.h>
22#include <private/qv4stackframe_p.h>
23
24#include <QtQml/qqmlfile.h>
25
26#include <QtCore/qcoreapplication.h>
27#include <QtCore/qcryptographichash.h>
28#include <QtCore/qdatetime.h>
29#include <QtCore/qfileinfo.h>
30#include <QtCore/qloggingcategory.h>
31#include <QtCore/qpoint.h>
32#include <QtCore/qrect.h>
33#include <QtCore/qsize.h>
34#include <QtCore/qstring.h>
35#include <QtCore/qurl.h>
36
37QT_BEGIN_NAMESPACE
38
39Q_LOGGING_CATEGORY(lcRootProperties, "qt.qml.rootObjectProperties");
40Q_LOGGING_CATEGORY(lcQml, "qml");
41Q_LOGGING_CATEGORY(lcJs, "js");
42
43using namespace QV4;
44
45#define THROW_TYPE_ERROR_WITH_MESSAGE(msg) \
46 do { \
47 return scope.engine->throwTypeError(QString::fromUtf8(msg)); \
48 } while (false)
49
50/*!
51\qmltype Qt
52\inqmlmodule QtQml
53//! \nativetype QQmlEnginePrivate
54\ingroup qml-utility-elements
55\keyword QmlGlobalQtObject
56\brief Provides a global object with useful enums and functions from Qt.
57
58\c Qt is a singleton type that provides utility functions, properties, and
59enums. Here is an example showing how to use this type:
60
61\qml
62import QtQuick 2.0
63
64Text {
65 color: Qt.rgba(1, 0, 0, 1)
66 text: Qt.md5("hello, world")
67}
68\endqml
69
70
71\section1 Enums
72
73The Qt object contains the enums available in the \l [QtCore]{Qt}{Qt Namespace}. For example, you can access
74the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftButton and \c Qt.RightButton.
75
76
77\section1 Types
78\target globalqtobjecttypes
79
80The Qt object also contains helper functions for creating objects of specific
81data types. This is primarily useful when setting the properties of an item
82when the property has one of the following types:
83\list
84\li \c rect - use \l{Qt::rect()}{Qt.rect()}
85\li \c point - use \l{Qt::point()}{Qt.point()}
86\li \c size - use \l{Qt::size()}{Qt.size()}
87\endlist
88
89If the \c QtQuick module has been imported, the following helper functions for
90creating objects of specific data types are also available for clients to use:
91\list
92\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()}
93\li \c font - use \l{Qt::font()}{Qt.font()}
94\li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()}
95\li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
96\li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()}
97\li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()}
98\li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()}
99\endlist
100
101\section1 Date/Time Formatters
102
103The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
104
105\list
106 \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
107 \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
108 \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
109\endlist
110
111The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
112
113
114\section1 Dynamic Object Creation
115The following functions on the global object allow you to dynamically create QML
116items from files or strings. See \l{Dynamic QML Object Creation from JavaScript} for an overview
117of their use.
118
119\list
120 \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
121 \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, url url)}
122\endlist
123
124
125\section1 Other Functions
126
127The following functions are also on the Qt object.
128
129\list
130 \li \l{Qt::quit()}{Qt.quit()}
131 \li \l{Qt::md5()}{Qt.md5(string)}
132 \li \l{Qt::btoa()}{string Qt.btoa(string)}
133 \li \l{Qt::atob()}{string Qt.atob(string)}
134 \li \l{Qt::binding()}{object Qt.binding(function)}
135 \li \l{Qt::locale()}{object Qt.locale()}
136 \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
137 \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
138 \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
139\endlist
140*/
141
142/*!
143 \qmlproperty object Qt::platform
144 \since 5.1
145
146 The \c platform object provides info about the underlying platform.
147
148 Its properties are:
149
150 \table
151 \row
152 \li \c platform.os
153 \li
154
155 This read-only property contains the name of the operating system.
156
157 Possible values are:
158
159 \list
160 \li \c "android" - Android
161 \li \c "ios" - iOS
162 \li \c "tvos" - tvOS
163 \li \c "visionos" - visionOS
164 \li \c "linux" - Linux
165 \li \c "osx" - \macos
166 \li \c "qnx" - QNX (since Qt 5.9.3)
167 \li \c "unix" - Other Unix-based OS
168 \li \c "windows" - Windows
169 \li \c "wasm" - WebAssembly
170 \endlist
171
172 \note The property's value on \macos is "osx", regardless of Apple naming convention.
173 The returned value will be updated to "macos" for Qt 7.
174
175 \row
176 \li \c platform.pluginName
177 \li This is the name of the platform set on the QGuiApplication instance
178 as returned by \l QGuiApplication::platformName()
179
180 \endtable
181*/
182
183/*!
184 \qmlproperty Application Qt::application
185 \since 5.1
186
187 The \c application object provides access to global application state
188 properties shared by many QML components.
189
190 It is the same as the \l Application singleton.
191
192 The following example uses the \c application object to indicate
193 whether the application is currently active:
194
195 \snippet qml/application.qml document
196
197 \note When using QML without a QGuiApplication, the following properties will be undefined:
198 \list
199 \li application.active
200 \li application.state
201 \li application.layoutDirection
202 \li application.font
203 \endlist
204*/
205
206/*!
207 \qmlproperty InputMethod Qt::inputMethod
208 \since 5.0
209
210 It is the same as the \l InputMethod singleton.
211
212 The \c inputMethod object allows access to application's QInputMethod object
213 and all its properties and slots. See the QInputMethod documentation for
214 further details.
215*/
216
217/*!
218 \qmlproperty object Qt::styleHints
219 \since 5.5
220
221 The \c styleHints object provides platform-specific style hints and settings.
222 See the \l QStyleHints documentation for further details.
223
224 You should access StyleHints via \l Application::styleHints instead, as
225 this provides better type information for tooling such as the
226 \l {Qt Quick Compiler}.
227
228 \note The \c styleHints object is only available when using the Qt Quick module.
229*/
230
231/*!
232\qmlmethod object Qt::include(string url, jsobject callback)
233\deprecated
234
235This method should not be used. Use ECMAScript modules, and the native
236JavaScript \c import and \c export statements instead.
237
238Includes another JavaScript file. This method can only be used from within JavaScript files,
239and not regular QML files.
240
241This imports all functions from \a url into the current script's namespace.
242
243Qt.include() returns an object that describes the status of the operation. The object has
244a single property, \c {status}, that is set to one of the following values:
245
246\table
247\header \li Symbol \li Value \li Description
248\row \li result.OK \li 0 \li The include completed successfully.
249\row \li result.LOADING \li 1 \li Data is being loaded from the network.
250\row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
251\row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
252An additional \c exception property will be set in this case.
253\endtable
254
255The \c status property will be updated as the operation progresses.
256
257If provided, \a callback is invoked when the operation completes. The callback is passed
258the same object as is returned from the Qt.include() call.
259
260\warning Using this function is strict mode does not actually put identifier into the
261current context.
262*/
263// Qt.include() is implemented in qv4include.cpp
264
265QtObject::QtObject(ExecutionEngine *engine)
266 : m_engine(engine)
267{
268}
269
270QtObject::Contexts QtObject::getContexts() const
271{
272 QQmlEngine *engine = qmlEngine();
273 if (!engine)
274 return {};
275
276 QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext();
277 if (!context)
278 context = QQmlContextData::get(context: QQmlEnginePrivate::get(e: engine)->rootContext);
279
280 Q_ASSERT(context);
281 QQmlRefPointer<QQmlContextData> effectiveContext
282 = context->isPragmaLibraryContext() ? nullptr : context;
283 return {.context: context, .effectiveContext: effectiveContext};
284}
285
286QtObject *QtObject::create(QQmlEngine *, QJSEngine *jsEngine)
287{
288 QV4::ExecutionEngine *v4 = jsEngine->handle();
289 QV4::Scope scope(v4);
290 ScopedObject globalObject(scope, v4->globalObject);
291 ScopedString qtName(scope, v4->newString(QStringLiteral("Qt")));
292 QV4::ScopedValue result(scope, globalObject->get(id: qtName->toPropertyKey()));
293 return qobject_cast<QtObject *>(object: result->as<QV4::QObjectWrapper>()->object());
294}
295
296QJSValue QtObject::include(const QString &url, const QJSValue &callback) const
297{
298 return QV4Include::method_include(engine: v4Engine(), url: v4Engine()->resolvedUrl(file: url), callbackFunction: callback);
299}
300
301
302/*!
303 \qmlmethod bool Qt::isQtObject(object)
304
305 Returns \c true if \a object is a valid reference to a Qt or QML object,
306 \c false otherwise.
307*/
308bool QtObject::isQtObject(const QJSValue &value) const
309{
310 return qjsvalue_cast<QObject *>(value) != nullptr;
311}
312
313/*!
314 \qmlmethod color Qt::color(string name)
315
316 Returns the color corresponding to the given \a name (i.e. red or #ff0000).
317 If there is no such color, \c null is returned.
318*/
319QVariant QtObject::color(const QString &name) const
320{
321 bool ok = false;
322 const QVariant v = QQmlStringConverters::colorFromString(name, ok: &ok);
323 if (ok)
324 return v;
325
326 v4Engine()->throwError(QStringLiteral("\"%1\" is not a valid color name").arg(a: name));
327 return QVariant::fromValue(value: nullptr);
328}
329
330/*!
331 \qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
332
333 Returns a color with the specified \a red, \a green, \a blue, and \a alpha
334 components. All components should be in the range 0-1 (inclusive).
335*/
336QVariant QtObject::rgba(double r, double g, double b, double a) const
337{
338 if (r < 0.0) r=0.0;
339 if (r > 1.0) r=1.0;
340 if (g < 0.0) g=0.0;
341 if (g > 1.0) g=1.0;
342 if (b < 0.0) b=0.0;
343 if (b > 1.0) b=1.0;
344 if (a < 0.0) a=0.0;
345 if (a > 1.0) a=1.0;
346
347 return QQml_colorProvider()->fromRgbF(r, g, b, a);
348}
349
350/*!
351 \qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
352
353 Returns a color with the specified \a hue, \a saturation, \a lightness, and \a alpha
354 components. All components should be in the range 0-1 (inclusive).
355*/
356QVariant QtObject::hsla(double h, double s, double l, double a) const
357{
358 if (h != -1)
359 h = qBound(min: 0.0, val: h, max: 1.0);
360 s = qBound(min: 0.0, val: s, max: 1.0);
361 l = qBound(min: 0.0, val: l, max: 1.0);
362 a = qBound(min: 0.0, val: a, max: 1.0);
363
364 return QQml_colorProvider()->fromHslF(h, s, l, a);
365}
366
367/*!
368 \since 5.5
369 \qmlmethod color Qt::hsva(real hue, real saturation, real value, real alpha)
370
371 Returns a color with the specified \a hue, \a saturation, \a value and \a alpha
372 components. All components should be in the range 0-1 (inclusive).
373
374*/
375QVariant QtObject::hsva(double h, double s, double v, double a) const
376{
377 if (h != -1)
378 h = qBound(min: 0.0, val: h, max: 1.0);
379 s = qBound(min: 0.0, val: s, max: 1.0);
380 v = qBound(min: 0.0, val: v, max: 1.0);
381 a = qBound(min: 0.0, val: a, max: 1.0);
382
383 return QQml_colorProvider()->fromHsvF(h, s, v, a);
384}
385
386/*!
387 \qmlmethod color Qt::colorEqual(color lhs, string rhs)
388
389 Returns \c true if both \a lhs and \a rhs yield equal color values. Both
390 arguments may be either color values or string values. If a string value
391 is supplied it must be convertible to a color, as described for the
392 \l{colorvaluetypedocs}{color} value type.
393*/
394bool QtObject::colorEqual(const QVariant &lhs, const QVariant &rhs) const
395{
396 bool ok = false;
397
398 QVariant color1 = lhs;
399 if (color1.userType() == QMetaType::QString) {
400 color1 = QQmlStringConverters::colorFromString(color1.toString(), ok: &ok);
401 if (!ok) {
402 v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid color name"));
403 return false;
404 }
405 } else if (color1.userType() != QMetaType::QColor) {
406 v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid arguments"));
407 return false;
408 }
409
410 QVariant color2 = rhs;
411 if (color2.userType() == QMetaType::QString) {
412 color2 = QQmlStringConverters::colorFromString(color2.toString(), ok: &ok);
413 if (!ok) {
414 v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid color name"));
415 return false;
416 }
417 } else if (color2.userType() != QMetaType::QColor) {
418 v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid arguments"));
419 return false;
420 }
421
422 return color1 == color2;
423}
424
425/*!
426 \qmlmethod rect Qt::rect(real x, real y, real width, real height)
427
428 Returns a rect with the top-left corner at \a x, \a y and the specified \a width and \a height.
429*/
430QRectF QtObject::rect(double x, double y, double width, double height) const
431{
432 return QRectF(x, y, width, height);
433}
434
435/*!
436 \qmlmethod point Qt::point(real x, real y)
437
438 Returns a point with the specified \a x and \a y coordinates.
439*/
440QPointF QtObject::point(double x, double y) const
441{
442 return QPointF(x, y);
443}
444
445/*!
446 \qmlmethod size Qt::size(real width, real height)
447
448 Returns a size with the specified \a width and \a height.
449*/
450QSizeF QtObject::size(double w, double h) const
451{
452 return QSizeF(w, h);
453}
454
455/*!
456 \qmlmethod font Qt::font(object fontSpecifier)
457
458 Returns a font with the properties specified in the \a fontSpecifier object
459 or the nearest matching font. The \a fontSpecifier object should contain
460 key-value pairs where valid keys are the \l{fontvaluetypedocs}{font} type's
461 subproperty names, and the values are valid values for each subproperty.
462 Invalid keys will be ignored.
463*/
464QVariant QtObject::font(const QJSValue &fontSpecifier) const
465{
466 if (!fontSpecifier.isObject()) {
467 v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid arguments"));
468 return QVariant();
469 }
470
471 {
472 const QVariant v = QQmlValueTypeProvider::createValueType(
473 fontSpecifier, QMetaType(QMetaType::QFont));
474 if (v.isValid())
475 return v;
476 }
477
478 v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid argument: "
479 "no valid font subproperties specified"));
480 return QVariant();
481}
482
483template<typename T>
484void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter)
485{
486 result.setProperty(i, e->toScriptValue(parameter));
487}
488
489template<>
490void addParameters<double>(QJSEngine *, QJSValue &result, int i, double parameter)
491{
492 result.setProperty(arrayIndex: i, value: QJSValue(parameter));
493}
494
495template<typename T, typename ...Others>
496void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter, Others... others)
497{
498 addParameters<T>(e, result, i, parameter);
499 addParameters<Others...>(e, result, ++i, others...);
500}
501
502template<typename ...T>
503static QVariant constructFromJSValue(QJSEngine *e, QMetaType type, T... parameters)
504{
505 if (!e)
506 return QVariant();
507 QJSValue params = e->newArray(length: sizeof...(parameters));
508 addParameters(e, params, 0, parameters...);
509 const QVariant variant = QQmlValueTypeProvider::createValueType(params, type);
510 return variant.isValid() ? variant : QVariant(type);
511}
512
513/*!
514 \qmlmethod vector2d Qt::vector2d(real x, real y)
515
516 Returns a vector2d with the specified \a x and \a y values.
517*/
518QVariant QtObject::vector2d(double x, double y) const
519{
520 return constructFromJSValue(e: jsEngine(), type: QMetaType(QMetaType::QVector2D), parameters: x, parameters: y);
521}
522
523/*!
524 \qmlmethod vector3d Qt::vector3d(real x, real y, real z)
525
526 Returns a vector3d with the specified \a x, \a y, and \a z values.
527*/
528QVariant QtObject::vector3d(double x, double y, double z) const
529{
530 return constructFromJSValue(e: jsEngine(), type: QMetaType(QMetaType::QVector3D), parameters: x, parameters: y, parameters: z);
531}
532
533/*!
534 \qmlmethod vector4d Qt::vector4d(real x, real y, real z, real w)
535
536 Returns a vector4d with the specified \a x, \a y, \a z, and \a w values.
537*/
538QVariant QtObject::vector4d(double x, double y, double z, double w) const
539{
540 return constructFromJSValue(e: jsEngine(), type: QMetaType(QMetaType::QVector4D), parameters: x, parameters: y, parameters: z, parameters: w);
541}
542
543/*!
544 \qmlmethod quaternion Qt::quaternion(real scalar, real x, real y, real z)
545
546 Returns a quaternion with the specified \a scalar, \a x, \a y, and \a z values.
547*/
548QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
549{
550 return constructFromJSValue(e: jsEngine(), type: QMetaType(QMetaType::QQuaternion), parameters: scalar, parameters: x, parameters: y, parameters: z);
551}
552
553/*!
554 \qmlmethod matrix4x4 Qt::matrix4x4()
555
556 Returns an identity matrix4x4.
557 */
558QVariant QtObject::matrix4x4() const
559{
560 const QMetaType metaType(QMetaType::QMatrix4x4);
561 const QVariant variant = QQmlValueTypeProvider::createValueType(QJSValue(), metaType);
562 return variant.isValid() ? variant : QVariant(metaType);
563}
564
565/*!
566 \qmlmethod matrix4x4 Qt::matrix4x4(var values)
567
568 Returns a matrix4x4 with the specified \a values. \a values is expected to
569 be a JavaScript array with 16 entries.
570
571 The array indices correspond to positions in the matrix as follows:
572
573 \table
574 \row \li 0 \li 1 \li 2 \li 3
575 \row \li 4 \li 5 \li 6 \li 7
576 \row \li 8 \li 9 \li 10 \li 11
577 \row \li 12 \li 13 \li 14 \li 15
578 \endtable
579*/
580QVariant QtObject::matrix4x4(const QJSValue &value) const
581{
582 if (value.isObject()) {
583 QVariant v = QQmlValueTypeProvider::createValueType(
584 value, QMetaType(QMetaType::QMatrix4x4));
585 if (v.isValid())
586 return v;
587 }
588
589 v4Engine()->throwError(QStringLiteral("Qt.matrix4x4(): Invalid argument: "
590 "not a valid matrix4x4 values array"));
591 return QVariant();
592}
593
594/*!
595 \qmlmethod matrix4x4 Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44)
596
597 Returns a matrix4x4 with the specified values.
598
599 The arguments correspond to their positions in the matrix:
600
601 \table
602 \row \li \a m11 \li \a m12 \li \a m13 \li \a m14
603 \row \li \a m21 \li \a m22 \li \a m23 \li \a m24
604 \row \li \a m31 \li \a m32 \li \a m33 \li \a m34
605 \row \li \a m41 \li \a m42 \li \a m43 \li \a m44
606 \endtable
607*/
608QVariant QtObject::matrix4x4(double m11, double m12, double m13, double m14,
609 double m21, double m22, double m23, double m24,
610 double m31, double m32, double m33, double m34,
611 double m41, double m42, double m43, double m44) const
612{
613 return constructFromJSValue(e: jsEngine(), type: QMetaType(QMetaType::QMatrix4x4),
614 parameters: m11, parameters: m12, parameters: m13, parameters: m14, parameters: m21, parameters: m22, parameters: m23, parameters: m24,
615 parameters: m31, parameters: m32, parameters: m33, parameters: m34, parameters: m41, parameters: m42, parameters: m43, parameters: m44);
616}
617
618static QVariant colorVariantFromJSValue(const QJSValue &color, bool *ok)
619{
620 QVariant v;
621 if (color.isString()) {
622 v = QQmlStringConverters::colorFromString(color.toString(), ok);
623 if (!(*ok))
624 return QVariant::fromValue(value: nullptr);
625 } else {
626 v = color.toVariant();
627 if (v.userType() != QMetaType::QColor) {
628 *ok = false;
629 return QVariant::fromValue(value: nullptr);
630 }
631 }
632
633 *ok = true;
634 return v;
635}
636
637/*!
638 \qmlmethod color Qt::lighter(color baseColor, real factor)
639
640 Returns a color lighter than \a baseColor by the \a factor provided.
641
642 If the factor is greater than 1.0, this functions returns a lighter color.
643 Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
644 the return color is darker, but we recommend using the Qt.darker() function for this purpose.
645 If the factor is 0 or negative, the return value is unspecified.
646
647 The function converts the current RGB color to HSV, multiplies the value (V) component
648 by factor and converts the color back to RGB.
649
650 If \a factor is not supplied, returns a color that is 50% lighter than \a baseColor (factor 1.5).
651*/
652QVariant QtObject::lighter(const QJSValue &color, double factor) const
653{
654 bool ok;
655 const QVariant v = colorVariantFromJSValue(color, ok: &ok);
656 return ok ? QQml_colorProvider()->lighter(v, factor) : v;
657}
658
659/*!
660 \qmlmethod color Qt::darker(color baseColor, real factor)
661
662 Returns a color darker than \a baseColor by the \a factor provided.
663
664 If the factor is greater than 1.0, this function returns a darker color.
665 Setting factor to 3.0 returns a color that has one-third the brightness.
666 If the factor is less than 1.0, the return color is lighter, but we recommend using
667 the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
668 value is unspecified.
669
670 The function converts the current RGB color to HSV, divides the value (V) component
671 by factor and converts the color back to RGB.
672
673 If \a factor is not supplied, returns a color that is 50% darker than \a baseColor (factor 2.0).
674*/
675QVariant QtObject::darker(const QJSValue &color, double factor) const
676{
677 bool ok;
678 const QVariant v = colorVariantFromJSValue(color, ok: &ok);
679 return ok ? QQml_colorProvider()->darker(v, factor) : v;
680}
681
682/*!
683 \qmlmethod color Qt::alpha(color baseColor, real value)
684
685 Returns \a baseColor with an alpha value of \a value.
686
687 \a value is a real ranging from 0 (completely transparent) to 1 (completely opaque).
688*/
689QVariant QtObject::alpha(const QJSValue &baseColor, double value) const
690{
691 bool ok;
692 const QVariant v = colorVariantFromJSValue(color: baseColor, ok: &ok);
693 return ok ? QQml_colorProvider()->alpha(v, value) : v;
694}
695
696/*!
697 \qmlmethod color Qt::tint(color baseColor, color tintColor)
698
699 This function allows tinting one color (\a baseColor) with another (\a tintColor).
700
701 The tint color should usually be mostly transparent, or you will not be
702 able to see the underlying color. The below example provides a slight red
703 tint by having the tint color be pure red which is only 1/16th opaque.
704
705 \qml
706 Item {
707 Rectangle {
708 x: 0; width: 80; height: 80
709 color: "lightsteelblue"
710 }
711 Rectangle {
712 x: 100; width: 80; height: 80
713 color: Qt.tint("lightsteelblue", "#10FF0000")
714 }
715 }
716 \endqml
717 \image declarative-rect_tint.png
718
719 Tint is most useful when a subtle change is intended to be conveyed due to some event;
720 you can then use tinting to more effectively tune the visible color.
721*/
722QVariant QtObject::tint(const QJSValue &baseColor, const QJSValue &tintColor) const
723{
724 bool ok;
725
726 // base color
727 const QVariant v1 = colorVariantFromJSValue(color: baseColor, ok: &ok);
728 if (!ok)
729 return v1;
730
731 // tint color
732 const QVariant v2 = colorVariantFromJSValue(color: tintColor, ok: &ok);
733
734 return ok ? QQml_colorProvider()->tint(v1, v2) : v2;
735}
736
737namespace {
738template <typename T>
739QString formatDateTimeObjectUsingDateFormat(T formatThis, Qt::DateFormat format) {
740 switch (format) {
741 case Qt::TextDate:
742 case Qt::ISODate:
743 case Qt::RFC2822Date:
744 case Qt::ISODateWithMs:
745 return formatThis.toString(format);
746 default: // ### Qt 6: remove once qtbase has removed the rest of the enum !
747 break;
748 }
749 // Q_UNREACHABLE(); // ### Qt 6: restore once the default is gone
750 return QString();
751}
752}
753
754static QTime dateTimeToTime(const QDateTime &dateTime)
755{
756 return dateTime.toLocalTime().time();
757}
758
759/*!
760\qmlmethod string Qt::formatDate(datetime date, variant format, variant localeFormatOption)
761
762Returns a string representation of \a date, optionally formatted using \a format.
763
764The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
765property, a QDate, or QDateTime value. The \a format and \a localeFormatOption
766parameter may be any of the possible format values as described for
767\l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
768
769If \a format is not specified, \a date is formatted using
770\l {QLocale::FormatType}{Locale.ShortFormat} using the
771default locale.
772
773\sa Locale
774*/
775static std::optional<QDate> dateFromString(const QString &string, QV4::ExecutionEngine *engine)
776{
777 {
778 const QDate date = QDate::fromString(string, format: Qt::ISODate);
779 if (date.isValid())
780 return date;
781 }
782
783 {
784 // For historical reasons, the string argument is parsed as datetime, not as only date
785 const QDateTime dateTime = QDateTime::fromString(string, format: Qt::ISODate);
786 if (dateTime.isValid()) {
787 qCWarning(lcRootProperties())
788 << string << "is a date/time string being passed to formatDate()."
789 << "You should only pass date strings to formatDate().";
790 return dateTime.date();
791 }
792 }
793
794 {
795 // Since we can coerce QDate to QString, allow the resulting string format here.
796 const QDateTime dateTime = DateObject::stringToDateTime(string, engine);
797 if (dateTime.isValid())
798 return DateObject::dateTimeToDate(dateTime);
799 }
800
801 engine->throwError(QStringLiteral("Invalid argument passed to formatDate(): %1").arg(a: string));
802 return std::nullopt;
803}
804
805QString QtObject::formatDate(QDate date, const QString &format) const
806{
807 return date.toString(format);
808}
809
810QString QtObject::formatDate(QDate date, Qt::DateFormat format) const
811{
812 return formatDateTimeObjectUsingDateFormat(formatThis: date, format);
813}
814
815QString QtObject::formatDate(const QDateTime &dateTime, const QString &format) const
816{
817 return DateObject::dateTimeToDate(dateTime).toString(format);
818}
819
820QString QtObject::formatDate(const QString &string, const QString &format) const
821{
822 if (const auto qDate = dateFromString(string, engine: v4Engine()))
823 return formatDate(date: qDate.value(), format);
824
825 return QString();
826}
827
828QString QtObject::formatDate(const QDateTime &dateTime, Qt::DateFormat format) const
829{
830 return formatDateTimeObjectUsingDateFormat(formatThis: DateObject::dateTimeToDate(dateTime), format);
831}
832
833QString QtObject::formatDate(const QString &string, Qt::DateFormat format) const
834{
835 if (const auto qDate = dateFromString(string, engine: v4Engine()))
836 return formatDate(date: qDate.value(), format);
837
838 return QString();
839}
840
841#if QT_CONFIG(qml_locale)
842QString QtObject::formatDate(QDate date, const QLocale &locale,
843 QLocale::FormatType formatType) const
844{
845 return locale.toString(date, format: formatType);
846}
847
848QString QtObject::formatDate(const QDateTime &dateTime, const QLocale &locale,
849 QLocale::FormatType formatType) const
850{
851 return locale.toString(date: DateObject::dateTimeToDate(dateTime), format: formatType);
852}
853
854QString QtObject::formatDate(const QString &string, const QLocale &locale,
855 QLocale::FormatType formatType) const
856{
857 if (const auto qDate = dateFromString(string, engine: v4Engine()))
858 return locale.toString(date: qDate.value(), format: formatType);
859
860 return QString();
861}
862#endif
863
864/*!
865\qmlmethod string Qt::formatTime(datetime time, variant format, variant localeFormatOption)
866
867Returns a string representation of \a time, optionally formatted using
868\a format, and, if provided, \a localeFormatOption.
869
870The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
871value. The \a format and \a localeFormatOption parameter may be any of the
872possible format values as described for
873\l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
874
875If \a format is not specified, \a time is formatted using
876\l {QLocale::FormatType}{Locale.ShortFormat} using the default locale.
877
878\sa Locale
879*/
880static std::optional<QTime> timeFromString(const QString &string, QV4::ExecutionEngine *engine)
881{
882 {
883 const QTime time = QTime::fromString(string, format: Qt::ISODate);
884 if (time.isValid())
885 return time;
886 }
887
888 {
889 // For historical reasons, the string argument is parsed as datetime, not as only time
890 const QDateTime dateTime = QDateTime::fromString(string, format: Qt::ISODate);
891 if (dateTime.isValid()) {
892 qCWarning(lcRootProperties())
893 << string << "is a date/time string being passed to formatTime()."
894 << "You should only pass time strings to formatTime().";
895 return dateTime.time();
896 }
897 }
898
899 {
900 // Since we can coerce QTime to QString, allow the resulting string format here.
901 const QDateTime dateTime = DateObject::stringToDateTime(string, engine);
902 if (dateTime.isValid())
903 return dateTimeToTime(dateTime);
904 }
905
906 engine->throwError(QStringLiteral("Invalid argument passed to formatTime(): %1").arg(a: string));
907 return std::nullopt;
908}
909
910QString QtObject::formatTime(QTime time, const QString &format) const
911{
912 return time.toString(format);
913}
914
915QString QtObject::formatTime(const QDateTime &dateTime, const QString &format) const
916{
917 return dateTimeToTime(dateTime).toString(format);
918}
919
920QString QtObject::formatTime(const QString &time, const QString &format) const
921{
922
923 if (auto qTime = timeFromString(string: time, engine: v4Engine()))
924 return formatTime(time: qTime.value(), format);
925
926 return QString();
927}
928
929QString QtObject::formatTime(QTime time, Qt::DateFormat format) const
930{
931 return formatDateTimeObjectUsingDateFormat(formatThis: time, format);
932}
933
934QString QtObject::formatTime(const QDateTime &dateTime, Qt::DateFormat format) const
935{
936 return formatDateTimeObjectUsingDateFormat(formatThis: dateTimeToTime(dateTime), format);
937}
938
939QString QtObject::formatTime(const QString &time, Qt::DateFormat format) const
940{
941 if (auto qTime = timeFromString(string: time, engine: v4Engine()))
942 return formatTime(time: qTime.value(), format);
943
944 return QString();
945}
946
947#if QT_CONFIG(qml_locale)
948QString QtObject::formatTime(QTime time, const QLocale &locale,
949 QLocale::FormatType formatType) const
950{
951 return locale.toString(time, format: formatType);
952}
953
954QString QtObject::formatTime(const QDateTime &dateTime, const QLocale &locale,
955 QLocale::FormatType formatType) const
956{
957 return locale.toString(time: dateTimeToTime(dateTime), format: formatType);
958}
959
960QString QtObject::formatTime(const QString &time, const QLocale &locale,
961 QLocale::FormatType formatType) const
962{
963 if (auto qTime = timeFromString(string: time, engine: v4Engine()))
964 return locale.toString(time: qTime.value(), format: formatType);
965
966 return QString();
967}
968#endif
969
970/*!
971\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format, variant localeFormatOption)
972
973Returns a string representation of \a dateTime, optionally formatted using
974\a format and \a localeFormatOption.
975
976The \a dateTime parameter may be a JavaScript \c Date object, a \l{date}{date}
977property, a QDate, QTime, or QDateTime value.
978
979If \a format is not provided, \a dateTime is formatted using
980\l {QLocale::FormatType}{Locale.ShortFormat} using the
981default locale. Otherwise, \a format should be either:
982
983\list
984\li One of the Qt::DateFormat enumeration values, such as
985 \c Qt.RFC2822Date or \c Qt.ISODate.
986\li A string that specifies the format of the returned string, as detailed below.
987\li A \c locale object.
988\endlist
989
990If \a format specifies a locale object, \dateTime is formatted
991with \l{QLocale::toString}. In this case, \a localeFormatOption can hold a value
992of type \l {QLocale::FormatType} to further tune the formatting. If none is
993provided, \l {QLocale::FormatType}{Locale.ShortFormat} is used.
994
995If \a format specifies a format string, it should use the following expressions
996to specify the date:
997
998 \table
999 \header \li Expression \li Output
1000 \row \li d \li the day as number without a leading zero (1 to 31)
1001 \row \li dd \li the day as number with a leading zero (01 to 31)
1002 \row \li ddd
1003 \li the abbreviated localized day name (e.g. 'Mon' to 'Sun').
1004 Uses QDate::shortDayName().
1005 \row \li dddd
1006 \li the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
1007 Uses QDate::longDayName().
1008 \row \li M \li the month as number without a leading zero (1-12)
1009 \row \li MM \li the month as number with a leading zero (01-12)
1010 \row \li MMM
1011 \li the abbreviated localized month name (e.g. 'Jan' to 'Dec').
1012 Uses QDate::shortMonthName().
1013 \row \li MMMM
1014 \li the long localized month name (e.g. 'January' to 'December').
1015 Uses QDate::longMonthName().
1016 \row \li yy \li the year as two digit number (00-99)
1017 \row \li yyyy \li the year as four digit number
1018 \endtable
1019
1020In addition the following expressions can be used to specify the time:
1021
1022 \table
1023 \header \li Expression \li Output
1024 \row \li h
1025 \li the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
1026 \row \li hh
1027 \li the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
1028 \row \li m \li the minute without a leading zero (0 to 59)
1029 \row \li mm \li the minute with a leading zero (00 to 59)
1030 \row \li s \li the second without a leading zero (0 to 59)
1031 \row \li ss \li the second with a leading zero (00 to 59)
1032 \row \li z \li the milliseconds without leading zeroes (0 to 999)
1033 \row \li zzz \li the milliseconds with leading zeroes (000 to 999)
1034 \row \li AP
1035 \li use AM/PM display. \e AP will be replaced by either "AM" or "PM".
1036 \row \li ap
1037 \li use am/pm display. \e ap will be replaced by either "am" or "pm".
1038 \row \li t
1039 \li include a time-zone indicator.
1040 \endtable
1041
1042 All other input characters will be ignored. Any sequence of characters that
1043 are enclosed in single quotes will be treated as text and not be used as an
1044 expression. Two consecutive single quotes ("''") are replaced by a single quote
1045 in the output.
1046
1047For example, if the following date/time value was specified:
1048
1049 \code
1050 // 21 May 2001 14:13:09
1051 var dateTime = new Date(2001, 5, 21, 14, 13, 09)
1052 \endcode
1053
1054This \a dateTime value could be passed to \c Qt.formatDateTime(),
1055\l {QtQml::Qt::formatDate()}{Qt.formatDate()} or \l {QtQml::Qt::formatTime()}{Qt.formatTime()}
1056with the \a format values below to produce the following results:
1057
1058 \table
1059 \header \li Format \li Result
1060 \row \li "dd.MM.yyyy" \li 21.05.2001
1061 \row \li "ddd MMMM d yy" \li Tue May 21 01
1062 \row \li "hh:mm:ss.zzz" \li 14:13:09.042
1063 \row \li "h:m:s ap" \li 2:13:9 pm
1064 \endtable
1065
1066 \sa Locale
1067*/
1068static std::optional<QDateTime> dateTimeFromString(const QString &string, QV4::ExecutionEngine *engine)
1069{
1070 {
1071 const QDateTime dateTime = QDateTime::fromString(string, format: Qt::ISODate);
1072 if (dateTime.isValid())
1073 return dateTime;
1074 }
1075
1076 {
1077 // Since we can coerce QDateTime to QString, allow the resulting string format here.
1078 const QDateTime dateTime = DateObject::stringToDateTime(string, engine);
1079 if (dateTime.isValid())
1080 return dateTime;
1081 }
1082
1083 engine->throwError(QStringLiteral("Invalid argument passed to formatDateTime(): %1").arg(a: string));
1084 return std::nullopt;
1085}
1086
1087QString QtObject::formatDateTime(const QDateTime &dateTime, const QString &format) const
1088{
1089 return dateTime.toString(format);
1090}
1091
1092QString QtObject::formatDateTime(const QString &string, const QString &format) const
1093{
1094
1095 if (const auto qDateTime = dateTimeFromString(string, engine: v4Engine()))
1096 return formatDateTime(dateTime: qDateTime.value(), format);
1097
1098 return QString();
1099}
1100
1101QString QtObject::formatDateTime(const QDateTime &dateTime, Qt::DateFormat format) const
1102{
1103 return formatDateTimeObjectUsingDateFormat(formatThis: dateTime, format);
1104}
1105
1106QString QtObject::formatDateTime(const QString &string, Qt::DateFormat format) const
1107{
1108
1109 if (const auto qDateTime = dateTimeFromString(string, engine: v4Engine()))
1110 return formatDateTime(dateTime: qDateTime.value(), format);
1111
1112 return QString();
1113}
1114
1115#if QT_CONFIG(qml_locale)
1116QString QtObject::formatDateTime(const QDateTime &dateTime, const QLocale &locale,
1117 QLocale::FormatType formatType) const
1118{
1119 return locale.toString(dateTime, format: formatType);
1120}
1121
1122QString QtObject::formatDateTime(const QString &string, const QLocale &locale,
1123 QLocale::FormatType formatType) const
1124{
1125
1126 if (const auto qDateTime = dateTimeFromString(string, engine: v4Engine()))
1127 return formatDateTime(dateTime: qDateTime.value(), locale, formatType);
1128
1129 return QString();
1130}
1131#endif
1132
1133/*!
1134 \qmlmethod bool Qt::openUrlExternally(url target)
1135
1136 Attempts to open the specified \a target url in an external application, based on the user's
1137 desktop preferences. Returns \c true if it succeeds, \c false otherwise.
1138
1139 \warning A return value of \c true indicates that the application has successfully requested
1140 the operating system to open the URL in an external application. The external application may
1141 still fail to launch or fail to open the requested URL. This result will not be reported back
1142 to the application.
1143*/
1144bool QtObject::openUrlExternally(const QUrl &url) const
1145{
1146 return QQml_guiProvider()->openUrlExternally(resolvedUrl(url));
1147}
1148
1149/*!
1150 \qmlmethod url Qt::url(url url)
1151
1152 Returns \a url verbatim. This can be used to force a type coercion to \c url.
1153 In contrast to Qt.resolvedUrl() this retains any relative URLs. As strings
1154 are implicitly converted to urls, the function can be called with a string
1155 as argument, and will then return a url.
1156
1157 \sa resolvedUrl()
1158*/
1159QUrl QtObject::url(const QUrl &url) const
1160{
1161 return url;
1162}
1163
1164/*!
1165 \qmlmethod url Qt::resolvedUrl(url url)
1166
1167 Returns \a url resolved relative to the URL of the caller.
1168
1169 If there is no caller or the caller is not associated with a QML context,
1170 returns \a url resolved relative to the QML engine's base URL. If the QML
1171 engine has no base URL, just returns \a url.
1172
1173 \sa url()
1174*/
1175QUrl QtObject::resolvedUrl(const QUrl &url) const
1176{
1177 if (QQmlRefPointer<QQmlContextData> ctxt = v4Engine()->callingQmlContext())
1178 return ctxt->resolvedUrl(url);
1179 if (QQmlEngine *engine = qmlEngine())
1180 return engine->baseUrl().resolved(relative: url);
1181 return url;
1182}
1183
1184/*!
1185 \qmlmethod url Qt::resolvedUrl(url url, object context)
1186
1187 Returns \a url resolved relative to the URL of the QML context of
1188 \a context. If \a context is not associated with a QML context,
1189 returns \a url resolved relative to the QML engine's base URL. If
1190 the QML engine has no base URL, just returns \a url.
1191
1192 \sa url()
1193*/
1194QUrl QtObject::resolvedUrl(const QUrl &url, QObject *context) const
1195{
1196 if (context) {
1197 QQmlData *data = QQmlData::get(object: context);
1198 if (data && data->outerContext)
1199 return data->outerContext->resolvedUrl(url);
1200 }
1201
1202 if (QQmlEngine *engine = qmlEngine())
1203 return engine->baseUrl().resolved(relative: url);
1204 return url;
1205}
1206
1207/*!
1208\qmlmethod list<string> Qt::fontFamilies()
1209
1210Returns a list of the font families available to the application.
1211*/
1212QStringList QtObject::fontFamilies() const
1213{
1214 return QQml_guiProvider()->fontFamilies();
1215}
1216
1217/*!
1218\qmlmethod string Qt::md5(data)
1219Returns a hex string of the md5 hash of \a data.
1220*/
1221QString QtObject::md5(const QString &data) const
1222{
1223 return QLatin1String(QCryptographicHash::hash(data: data.toUtf8(), method: QCryptographicHash::Md5).toHex());
1224}
1225
1226/*!
1227\qmlmethod string Qt::btoa(data)
1228Binary to ASCII - this function returns a base64 encoding of \a data.
1229*/
1230QString QtObject::btoa(const QString &data) const
1231{
1232 return QLatin1String(data.toUtf8().toBase64());
1233}
1234
1235/*!
1236\qmlmethod string Qt::atob(data)
1237ASCII to binary - this function decodes the base64 encoded \a data string and returns it.
1238*/
1239QString QtObject::atob(const QString &data) const
1240{
1241 return QString::fromUtf8(ba: QByteArray::fromBase64(base64: data.toLatin1()));
1242}
1243
1244/*!
1245 \qmlmethod Qt::quit()
1246
1247 This function causes the QQmlEngine::quit() signal to be emitted.
1248 Within the \l {Prototyping with the QML Runtime Tool}{qml tool},
1249 this causes the launcher application to exit; to quit a C++ application
1250 when this method is called, connect the QQmlEngine::quit() signal to the
1251 QCoreApplication::quit() slot.
1252
1253 \sa exit()
1254*/
1255void QtObject::quit() const
1256{
1257 if (QQmlEngine *engine = qmlEngine())
1258 QQmlEnginePrivate::get(e: engine)->sendQuit();
1259}
1260
1261/*!
1262 \qmlmethod Qt::exit(int retCode)
1263
1264 This function causes the QQmlEngine::exit(int) signal to be emitted.
1265 Within the \l {Prototyping with the QML Runtime Tool}{qml tool},
1266 this causes the launcher application to exit with
1267 the specified return code (\a retCode). To exit from the event loop with a specified
1268 return code when this method is called, a C++ application can connect the
1269 QQmlEngine::exit(int) signal to the QCoreApplication::exit(int) slot.
1270
1271 \sa quit()
1272*/
1273void QtObject::exit(int retCode) const
1274{
1275 if (QQmlEngine *engine = qmlEngine())
1276 QQmlEnginePrivate::get(e: engine)->sendExit(retCode);
1277}
1278
1279/*!
1280\qmlmethod object Qt::createQmlObject(string qml, object parent, url url)
1281
1282Compiles the given \a qml string into a component and then returns a new object created from
1283that component. The new object will have the specified \a parent. Returns \c null if there was
1284an error in creating the component or the object.
1285
1286If \a url is specified, it will be used as URL of the component. This is useful for error
1287reporting.
1288
1289\warning The new component will shadow any existing component of the same URL. You should not
1290pass a URL of an existing component. In particular, by passing the URL of the surrounding QML
1291file, you prevent access to the surrounding component from the new one.
1292
1293Example (where \c parentItem is the id of an existing QML item):
1294
1295\snippet qml/createQmlObject.qml 0
1296
1297In the case of an error, a QQmlError object is thrown. This object has an additional property,
1298\c qmlErrors, which is an array of the errors encountered.
1299Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
1300For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following:
1301{ "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}.
1302
1303\note This function returns immediately, and therefore may not work if
1304the \a qml string loads new components (that is, external QML files that have not yet been loaded).
1305If this is the case, consider using \l{QtQml::Qt::createComponent()}{Qt.createComponent()} instead.
1306
1307\warning This function is extremely slow since it has to compile the passed QML string every time
1308it is invoked. Furthermore, it's very easy to produce invalid QML when programmatically constructing
1309QML code. It's much better to keep your QML components as separate files and add properties and
1310methods to customize their behavior than to produce new components by string manipulation.
1311
1312See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function.
1313*/
1314QObject *QtObject::createQmlObject(const QString &qml, QObject *parent, const QUrl &url) const
1315{
1316 QQmlEngine *engine = qmlEngine();
1317 if (!engine) {
1318 v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): "
1319 "Can only be called on a QML engine."));
1320 return nullptr;
1321 }
1322
1323 struct Error {
1324 static ReturnedValue create(QV4::ExecutionEngine *v4, const QList<QQmlError> &errors) {
1325 Scope scope(v4);
1326 QString errorstr;
1327 // '+=' reserves extra capacity. Follow-up appending will be probably free.
1328 errorstr += QLatin1String("Qt.createQmlObject(): failed to create object: ");
1329
1330 QV4::ScopedArrayObject qmlerrors(scope, v4->newArrayObject());
1331 QV4::ScopedObject qmlerror(scope);
1332 QV4::ScopedString s(scope);
1333 QV4::ScopedValue v(scope);
1334 for (int ii = 0; ii < errors.size(); ++ii) {
1335 const QQmlError &error = errors.at(i: ii);
1336 errorstr += QLatin1String("\n ") + error.toString();
1337 qmlerror = v4->newObject();
1338 qmlerror->put(name: (s = v4->newString(QStringLiteral("lineNumber"))), v: (v = QV4::Value::fromInt32(i: error.line())));
1339 qmlerror->put(name: (s = v4->newString(QStringLiteral("columnNumber"))), v: (v = QV4::Value::fromInt32(i: error.column())));
1340 qmlerror->put(name: (s = v4->newString(QStringLiteral("fileName"))), v: (v = v4->newString(s: error.url().toString())));
1341 qmlerror->put(name: (s = v4->newString(QStringLiteral("message"))), v: (v = v4->newString(s: error.description())));
1342 qmlerrors->put(idx: ii, v: qmlerror);
1343 }
1344
1345 v = v4->newString(s: errorstr);
1346 ScopedObject errorObject(scope, v4->newErrorObject(value: v));
1347 errorObject->put(name: (s = v4->newString(QStringLiteral("qmlErrors"))), v: qmlerrors);
1348 return errorObject.asReturnedValue();
1349 }
1350 };
1351
1352 QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext();
1353 if (!context)
1354 context = QQmlContextData::get(context: QQmlEnginePrivate::get(e: engine)->rootContext);
1355
1356 Q_ASSERT(context);
1357 QQmlContext *effectiveContext = nullptr;
1358 if (context->isPragmaLibraryContext())
1359 effectiveContext = engine->rootContext();
1360 else
1361 effectiveContext = context->asQQmlContext();
1362 Q_ASSERT(effectiveContext);
1363
1364 if (qml.isEmpty())
1365 return nullptr;
1366
1367 QUrl resolvedUrl = url;
1368 if (url.isValid() && url.isRelative())
1369 resolvedUrl = context->resolvedUrl(url);
1370
1371 if (!parent) {
1372 v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Missing parent object"));
1373 return nullptr;
1374 }
1375
1376 QQmlRefPointer<QQmlTypeData> typeData = QQmlEnginePrivate::get(e: engine)->typeLoader.getType(
1377 qml.toUtf8(), url: resolvedUrl, mode: QQmlTypeLoader::Synchronous);
1378 Q_ASSERT(typeData->isCompleteOrError());
1379 QQmlComponent component(engine);
1380 QQmlComponentPrivate *componentPrivate = QQmlComponentPrivate::get(c: &component);
1381 componentPrivate->fromTypeData(data: typeData);
1382 componentPrivate->progress = 1.0;
1383
1384 Scope scope(v4Engine());
1385 if (component.isError()) {
1386 ScopedValue v(scope, Error::create(v4: scope.engine, errors: component.errors()));
1387 scope.engine->throwError(value: v);
1388 return nullptr;
1389 }
1390
1391 if (!component.isReady()) {
1392 v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Component is not ready"));
1393 return nullptr;
1394 }
1395
1396 if (!effectiveContext->isValid()) {
1397 v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Cannot create a component "
1398 "in an invalid context"));
1399 return nullptr;
1400 }
1401
1402 QObject *obj = component.beginCreate(effectiveContext);
1403 if (obj) {
1404 QQmlData::get(object: obj, create: true)->explicitIndestructibleSet = false;
1405 QQmlData::get(object: obj)->indestructible = false;
1406
1407 obj->setParent(parent);
1408
1409 QList<QQmlPrivate::AutoParentFunction> functions = QQmlMetaType::parentFunctions();
1410 for (int ii = 0; ii < functions.size(); ++ii) {
1411 if (QQmlPrivate::Parented == functions.at(i: ii)(obj, parent))
1412 break;
1413 }
1414 }
1415 component.completeCreate();
1416
1417 if (component.isError()) {
1418 ScopedValue v(scope, Error::create(v4: scope.engine, errors: component.errors()));
1419 scope.engine->throwError(value: v);
1420 return nullptr;
1421 }
1422
1423 Q_ASSERT(obj);
1424 return obj;
1425}
1426
1427/*!
1428\qmlmethod Component Qt::createComponent(url url, enumeration mode, QtObject parent)
1429
1430Returns a \l Component object created using the QML file at the specified \a url,
1431or \c null if an empty string was given.
1432
1433The returned component's \l Component::status property indicates whether the
1434component was successfully created. If the status is \c Component.Error,
1435see \l Component::errorString() for an error description.
1436
1437If the optional \a mode parameter is set to \c Component.Asynchronous, the
1438component will be loaded in a background thread. The Component::status property
1439will be \c Component.Loading while it is loading. The status will change to
1440\c Component.Ready if the component loads successfully, or \c Component.Error
1441if loading fails. This parameter defaults to \c Component.PreferSynchronous
1442if omitted.
1443
1444If \a mode is set to \c Component.PreferSynchronous, Qt will attempt to load
1445the component synchronously, but may end up loading it asynchronously if
1446necessary. Scenarios that may cause asynchronous loading include, but are not
1447limited to, the following:
1448
1449\list
1450\li The URL refers to a network resource
1451\li The component is being created as a result of another component that is
1452being loaded asynchronously
1453\endlist
1454
1455If the optional \a parent parameter is given, it should refer to the object
1456that will become the parent for the created \l Component object. If no mode
1457was passed, this can be the second argument.
1458
1459Call \l {Component::createObject()}{Component.createObject()} on the returned
1460component to create an object instance of the component.
1461
1462For example:
1463
1464\snippet qml/createComponent-simple.qml 0
1465
1466See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function.
1467
1468To create a QML object from an arbitrary string of QML (instead of a file),
1469use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
1470*/
1471
1472/*!
1473\since 6.5
1474\qmlmethod Component Qt::createComponent(string moduleUri, string typeName, enumeration mode, QtObject parent)
1475\overload
1476Returns a \l Component object created for the type specified by \a moduleUri and \a typeName.
1477\qml
1478import QtQml
1479QtObject {
1480 id: root
1481 property Component myComponent: Qt.createComponent("QtQuick", "Rectangle", Component.Asynchronous, root)
1482}
1483\endqml
1484This overload mostly behaves as the \c url based version, but can be used
1485to instantiate types which do not have an URL (e.g. C++ types registered
1486via \l {QML_ELEMENT}).
1487\note In some cases, passing \c Component.Asynchronous won't have any
1488effect:
1489\list
1490\li The type is implemented in C++
1491\li The type is an inline component.
1492\endlist
1493If the optional \a parent parameter is given, it should refer to the object
1494that will become the parent for the created \l Component object. If no mode
1495was passed, this can be the second argument.
1496*/
1497
1498QQmlComponent *QtObject::createComponent(const QUrl &url, QObject *parent) const
1499{
1500 return createComponent(url, mode: QQmlComponent::PreferSynchronous, parent);
1501}
1502
1503QQmlComponent *QtObject::createComponent(const QUrl &url, QQmlComponent::CompilationMode mode,
1504 QObject *parent) const
1505{
1506 if (mode != QQmlComponent::Asynchronous && mode != QQmlComponent::PreferSynchronous) {
1507 v4Engine()->throwError(QStringLiteral("Invalid compilation mode %1").arg(a: mode));
1508 return nullptr;
1509 }
1510
1511 if (url.isEmpty())
1512 return nullptr;
1513
1514 QQmlEngine *engine = qmlEngine();
1515 if (!engine)
1516 return nullptr;
1517
1518 auto [context, effectiveContext] = getContexts();
1519 if (!context)
1520 return nullptr;
1521
1522 QQmlComponent *c = new QQmlComponent(engine, context->resolvedUrl(url), mode, parent);
1523 QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
1524 QQmlData::get(object: c, create: true)->explicitIndestructibleSet = false;
1525 QQmlData::get(object: c)->indestructible = false;
1526 return c;
1527}
1528
1529QQmlComponent *QtObject::createComponent(const QString &moduleUri, const QString &typeName,
1530 QObject *parent) const
1531{
1532 return createComponent(moduleUri, typeName, mode: QQmlComponent::PreferSynchronous, parent);
1533}
1534
1535QQmlComponent *QtObject::createComponent(const QString &moduleUri, const QString &typeName, QQmlComponent::CompilationMode mode, QObject *parent) const
1536{
1537 if (mode != QQmlComponent::Asynchronous && mode != QQmlComponent::PreferSynchronous) {
1538 v4Engine()->throwError(QStringLiteral("Invalid compilation mode %1").arg(a: mode));
1539 return nullptr;
1540 }
1541
1542 QQmlEngine *engine = qmlEngine();
1543 if (!engine)
1544 return nullptr;
1545
1546 if (moduleUri.isEmpty() || typeName.isEmpty())
1547 return nullptr;
1548
1549 auto [context, effectiveContext] = getContexts();
1550 if (!context)
1551 return nullptr;
1552
1553 QQmlComponent *c = new QQmlComponent(engine, moduleUri, typeName, mode, parent);
1554 if (c->isError() && !parent && moduleUri.endsWith(s: u".qml")) {
1555 v4Engine()->throwTypeError(
1556 QStringLiteral("Invalid arguments; did you swap mode and parent"));
1557 }
1558 QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
1559 QQmlData::get(object: c, create: true)->explicitIndestructibleSet = false;
1560 QQmlData::get(object: c)->indestructible = false;
1561 return c;
1562}
1563
1564#if QT_CONFIG(translation)
1565QString QtObject::uiLanguage() const
1566{
1567 if (const QJSEngine *e = jsEngine())
1568 return e->uiLanguage();
1569 return QString();
1570}
1571
1572void QtObject::setUiLanguage(const QString &uiLanguage)
1573{
1574 if (QJSEngine *e = jsEngine())
1575 e->setUiLanguage(uiLanguage);
1576}
1577
1578QBindable<QString> QtObject::uiLanguageBindable()
1579{
1580 if (QJSEngine *e = jsEngine())
1581 return QBindable<QString>(&QJSEnginePrivate::get(e)->uiLanguage);
1582 return QBindable<QString>();
1583}
1584#endif
1585
1586#if QT_CONFIG(qml_locale)
1587/*!
1588 \qmlmethod Qt::locale(name)
1589
1590 Returns a JS object representing the locale with the specified
1591 \a name, which has the format "language[_territory][.codeset][@modifier]"
1592 or "C", where:
1593
1594 \list
1595 \li \c language is a lowercase, two-letter, ISO 639 language code,
1596 \li \c territory is an uppercase, two-letter, ISO 3166 country code, and
1597 \li \c codeset and \c modifier are ignored.
1598 \endlist
1599
1600 If the string violates the locale format, or language is not a
1601 valid ISO 369 code, the "C" locale is used instead. If country
1602 is not present, or is not a valid ISO 3166 code, the most
1603 appropriate country is chosen for the specified language.
1604
1605 \sa Locale
1606*/
1607QLocale QtObject::locale() const
1608{
1609 return QLocale();
1610}
1611
1612QLocale QtObject::locale(const QString &name) const
1613{
1614 return QLocale(name);
1615}
1616#endif
1617
1618void Heap::QQmlBindingFunction::init(const QV4::JavaScriptFunctionObject *bindingFunction)
1619{
1620 Scope scope(bindingFunction->engine());
1621 ScopedContext context(scope, bindingFunction->scope());
1622 JavaScriptFunctionObject::init(scope: context, function: bindingFunction->function());
1623 this->bindingFunction.set(e: internalClass->engine, newVal: bindingFunction->d());
1624}
1625
1626ReturnedValue QQmlBindingFunction::virtualCall(
1627 const FunctionObject *f, const Value *, const Value *, int)
1628{
1629 // Mark this as a callable object, so that we can perform the binding magic on it.
1630 return f->engine()->throwTypeError(QStringLiteral("Bindings must not be called directly."));
1631}
1632
1633QQmlSourceLocation QQmlBindingFunction::currentLocation() const
1634{
1635 QV4::CppStackFrame *frame = engine()->currentStackFrame;
1636 if (frame->v4Function) // synchronous loading:
1637 return QQmlSourceLocation(frame->source(), frame->lineNumber(), 0);
1638 else // async loading:
1639 return bindingFunction()->function->sourceLocation();
1640}
1641
1642DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
1643
1644/*!
1645 \qmlmethod Qt::binding(function)
1646
1647 Returns a JavaScript object representing a \l{Property Binding}{property binding},
1648 with a \a function that evaluates the binding.
1649
1650 There are two main use-cases for the function: firstly, to apply a
1651 property binding imperatively from JavaScript code:
1652
1653 \snippet qml/qtBinding.1.qml 0
1654
1655 and secondly, to apply a property binding when initializing property values
1656 of dynamically constructed objects (via \l{Component::createObject()}
1657 {Component.createObject()} or \l{Loader::setSource()}{Loader.setSource()}).
1658
1659 For example, assuming the existence of a DynamicText component:
1660 \snippet qml/DynamicText.qml 0
1661
1662 the output from:
1663 \snippet qml/qtBinding.2.qml 0
1664
1665 and from:
1666 \snippet qml/qtBinding.3.qml 0
1667
1668 should both be:
1669 \code
1670 Root text extra text
1671 Modified root text extra text
1672 Dynamic text extra text
1673 Modified dynamic text extra text
1674 \endcode
1675
1676 This function cannot be used in property binding declarations
1677 (see the documentation on \l{qml-javascript-assignment}{binding
1678 declarations and binding assignments}) except when the result is
1679 stored in an array bound to a var property.
1680
1681 \snippet qml/qtBinding.4.qml 0
1682
1683 \since 5.0
1684*/
1685QJSValue QtObject::binding(const QJSValue &function) const
1686{
1687 const QV4::JavaScriptFunctionObject *f
1688 = QJSValuePrivate::asManagedType<JavaScriptFunctionObject>(jsval: &function);
1689 QV4::ExecutionEngine *e = v4Engine();
1690 if (!f) {
1691 return QJSValuePrivate::fromReturnedValue(
1692 d: e->throwError(
1693 QStringLiteral(
1694 "binding(): argument (binding expression) must be a function")));
1695 }
1696
1697 return QJSValuePrivate::fromReturnedValue(
1698 d: Encode(e->memoryManager->allocate<QQmlBindingFunction>(args&: f)));
1699}
1700
1701void QtObject::callLater(QQmlV4FunctionPtr args)
1702{
1703 m_engine->delayedCallQueue()->addUniquelyAndExecuteLater(engine: m_engine, args);
1704}
1705
1706
1707QQmlPlatform *QtObject::platform()
1708{
1709 if (!m_platform)
1710 m_platform = new QQmlPlatform(this);
1711 return m_platform;
1712}
1713
1714QQmlApplication *QtObject::application()
1715{
1716 if (!m_application)
1717 // Only allocate an application object once
1718 m_application = QQml_guiProvider()->application(parent: this);
1719
1720 return m_application;
1721}
1722
1723QObject *QtObject::inputMethod() const
1724{
1725 return QQml_guiProvider()->inputMethod();
1726}
1727
1728QObject *QtObject::styleHints() const
1729{
1730 return QQml_guiProvider()->styleHints();
1731}
1732
1733void QV4::Heap::ConsoleObject::init()
1734{
1735 Object::init();
1736 QV4::Scope scope(internalClass->engine);
1737 QV4::ScopedObject o(scope, this);
1738
1739 o->defineDefaultProperty(QStringLiteral("debug"), code: QV4::ConsoleObject::method_log);
1740 o->defineDefaultProperty(QStringLiteral("log"), code: QV4::ConsoleObject::method_log);
1741 o->defineDefaultProperty(QStringLiteral("info"), code: QV4::ConsoleObject::method_info);
1742 o->defineDefaultProperty(QStringLiteral("warn"), code: QV4::ConsoleObject::method_warn);
1743 o->defineDefaultProperty(QStringLiteral("error"), code: QV4::ConsoleObject::method_error);
1744 o->defineDefaultProperty(QStringLiteral("assert"), code: QV4::ConsoleObject::method_assert);
1745
1746 o->defineDefaultProperty(QStringLiteral("count"), code: QV4::ConsoleObject::method_count);
1747 o->defineDefaultProperty(QStringLiteral("profile"), code: QV4::ConsoleObject::method_profile);
1748 o->defineDefaultProperty(QStringLiteral("profileEnd"), code: QV4::ConsoleObject::method_profileEnd);
1749 o->defineDefaultProperty(QStringLiteral("time"), code: QV4::ConsoleObject::method_time);
1750 o->defineDefaultProperty(QStringLiteral("timeEnd"), code: QV4::ConsoleObject::method_timeEnd);
1751 o->defineDefaultProperty(QStringLiteral("trace"), code: QV4::ConsoleObject::method_trace);
1752 o->defineDefaultProperty(QStringLiteral("exception"), code: QV4::ConsoleObject::method_exception);
1753}
1754
1755
1756enum ConsoleLogTypes {
1757 Log,
1758 Info,
1759 Warn,
1760 Error
1761};
1762
1763static QString jsStack(QV4::ExecutionEngine *engine) {
1764 QString stack;
1765
1766 int i = 0;
1767 for (CppStackFrame *f = engine->currentStackFrame; f && i < 10; f = f->parentFrame(), ++i) {
1768 QString stackFrame;
1769
1770 if (f->isJSTypesFrame() && static_cast<JSTypesStackFrame *>(f)->isTailCalling()) {
1771 stackFrame = QStringLiteral("[elided tail calls]");
1772 } else {
1773 const int line = f->lineNumber();
1774 if (line != f->missingLineNumber()) {
1775 stackFrame = QStringLiteral("%1 (%2:%3)").arg(
1776 args: f->function(), args: f->source(), args: QString::number(qAbs(t: line)));
1777 } else {
1778 stackFrame = QStringLiteral("%1 (%2)").arg(
1779 args: f->function(), args: f->source());
1780 }
1781 }
1782
1783 if (i)
1784 stack += QLatin1Char('\n');
1785 stack += stackFrame;
1786 }
1787 return stack;
1788}
1789
1790static QString serializeArray(Object *array, ExecutionEngine *v4, QSet<QV4::Heap::Object *> &alreadySeen) {
1791 Scope scope(v4);
1792 ScopedValue val(scope);
1793 QString result;
1794 alreadySeen.insert(value: array->d());
1795
1796 ScopedObject detached(scope);
1797 if (Sequence *reference = array->as<Sequence>())
1798 detached = ReferenceObject::detached(ref: reference->d());
1799 else
1800 detached = array;
1801
1802 result += QLatin1Char('[');
1803 const uint length = detached->getLength();
1804 for (uint i = 0; i < length; ++i) {
1805 if (i != 0)
1806 result += QLatin1Char(',');
1807 val = detached->get(idx: i);
1808 if (val->isManaged() && val->managed()->isArrayLike())
1809 if (!alreadySeen.contains(value: val->objectValue()->d()))
1810 result += serializeArray(array: val->objectValue(), v4, alreadySeen);
1811 else
1812 result += QLatin1String("[Circular]");
1813 else
1814 result += val->toQStringNoThrow();
1815 }
1816 result += QLatin1Char(']');
1817
1818 alreadySeen.remove(value: array->d());
1819 return result;
1820};
1821
1822static ReturnedValue writeToConsole(const FunctionObject *b, const Value *argv, int argc,
1823 ConsoleLogTypes logType, bool printStack = false)
1824{
1825 const QLoggingCategory *loggingCategory = nullptr;
1826 QString result;
1827 QV4::Scope scope(b);
1828 QV4::ExecutionEngine *v4 = scope.engine;
1829
1830 int start = 0;
1831 if (argc > 0) {
1832 if (const QObjectWrapper* wrapper = argv[0].as<QObjectWrapper>()) {
1833 if (QQmlLoggingCategoryBase *category
1834 = qobject_cast<QQmlLoggingCategoryBase *>(object: wrapper->object())) {
1835 if (category->category())
1836 loggingCategory = category->category();
1837 else
1838 THROW_GENERIC_ERROR("A QmlLoggingCatgory was provided without a valid name");
1839 start = 1;
1840 }
1841 }
1842 }
1843
1844
1845 for (int i = start, ei = argc; i < ei; ++i) {
1846 if (i != start)
1847 result.append(c: QLatin1Char(' '));
1848
1849 QSet<QV4::Heap::Object *> alreadySeenElements;
1850 if (argv[i].isManaged() && argv[i].managed()->isArrayLike())
1851 result.append(s: serializeArray(array: argv[i].objectValue(), v4, alreadySeen&: alreadySeenElements));
1852 else
1853 result.append(s: argv[i].toQStringNoThrow());
1854 }
1855
1856 if (printStack)
1857 result += QLatin1Char('\n') + jsStack(engine: v4);
1858
1859 if (!loggingCategory)
1860 loggingCategory = v4->qmlEngine() ? &lcQml() : &lcJs();
1861 QV4::CppStackFrame *frame = v4->currentStackFrame;
1862 const QByteArray baSource = frame ? frame->source().toUtf8() : QByteArray();
1863 const QByteArray baFunction = frame ? frame->function().toUtf8() : QByteArray();
1864 QMessageLogger logger(baSource.constData(), frame ? frame->lineNumber() : 0,
1865 baFunction.constData(), loggingCategory->categoryName());
1866
1867 switch (logType) {
1868 case Log:
1869 if (loggingCategory->isDebugEnabled())
1870 logger.debug(msg: "%s", result.toUtf8().constData());
1871 break;
1872 case Info:
1873 if (loggingCategory->isInfoEnabled())
1874 logger.info(msg: "%s", result.toUtf8().constData());
1875 break;
1876 case Warn:
1877 if (loggingCategory->isWarningEnabled())
1878 logger.warning(msg: "%s", result.toUtf8().constData());
1879 break;
1880 case Error:
1881 if (loggingCategory->isCriticalEnabled())
1882 logger.critical(msg: "%s", result.toUtf8().constData());
1883 break;
1884 default:
1885 break;
1886 }
1887
1888 return Encode::undefined();
1889}
1890
1891DEFINE_OBJECT_VTABLE(ConsoleObject);
1892
1893ReturnedValue ConsoleObject::method_error(const FunctionObject *b, const Value *, const Value *argv, int argc)
1894{
1895 return writeToConsole(b, argv, argc, logType: Error);
1896}
1897
1898ReturnedValue ConsoleObject::method_log(const FunctionObject *b, const Value *, const Value *argv, int argc)
1899{
1900 //console.log
1901 //console.debug
1902 //print
1903 return writeToConsole(b, argv, argc, logType: Log);
1904}
1905
1906ReturnedValue ConsoleObject::method_info(const FunctionObject *b, const Value *, const Value *argv, int argc)
1907{
1908 return writeToConsole(b, argv, argc, logType: Info);
1909}
1910
1911ReturnedValue ConsoleObject::method_profile(const FunctionObject *b, const Value *, const Value *, int)
1912{
1913 QV4::Scope scope(b);
1914 QV4::ExecutionEngine *v4 = scope.engine;
1915
1916 QV4::CppStackFrame *frame = v4->currentStackFrame;
1917 const QByteArray baSource = frame->source().toUtf8();
1918 const QByteArray baFunction = frame->function().toUtf8();
1919 QMessageLogger logger(baSource.constData(), frame->lineNumber(), baFunction.constData());
1920 QQmlProfilerService *service = QQmlDebugConnector::service<QQmlProfilerService>();
1921 if (!service) {
1922 logger.warning(msg: "Cannot start profiling because debug service is disabled. Start with -qmljsdebugger=port:XXXXX.");
1923 } else {
1924 service->startProfiling(engine: v4->jsEngine());
1925 logger.debug(msg: "Profiling started.");
1926 }
1927
1928 return QV4::Encode::undefined();
1929}
1930
1931ReturnedValue ConsoleObject::method_profileEnd(const FunctionObject *b, const Value *, const Value *, int)
1932{
1933 QV4::Scope scope(b);
1934 QV4::ExecutionEngine *v4 = scope.engine;
1935
1936 QV4::CppStackFrame *frame = v4->currentStackFrame;
1937 const QByteArray baSource = frame->source().toUtf8();
1938 const QByteArray baFunction = frame->function().toUtf8();
1939 QMessageLogger logger(baSource.constData(), frame->lineNumber(), baFunction.constData());
1940
1941 QQmlProfilerService *service = QQmlDebugConnector::service<QQmlProfilerService>();
1942 if (!service) {
1943 logger.warning(msg: "Ignoring console.profileEnd(): the debug service is disabled.");
1944 } else {
1945 service->stopProfiling(engine: v4->jsEngine());
1946 logger.debug(msg: "Profiling ended.");
1947 }
1948
1949 return QV4::Encode::undefined();
1950}
1951
1952ReturnedValue ConsoleObject::method_time(const FunctionObject *b, const Value *, const Value *argv, int argc)
1953{
1954 QV4::Scope scope(b);
1955 if (argc != 1)
1956 THROW_GENERIC_ERROR("console.time(): Invalid arguments");
1957
1958 QString name = argv[0].toQStringNoThrow();
1959 scope.engine->startTimer(timerName: name);
1960 return QV4::Encode::undefined();
1961}
1962
1963ReturnedValue ConsoleObject::method_timeEnd(const FunctionObject *b, const Value *, const Value *argv, int argc)
1964{
1965 QV4::Scope scope(b);
1966 if (argc != 1)
1967 THROW_GENERIC_ERROR("console.timeEnd(): Invalid arguments");
1968
1969 QString name = argv[0].toQStringNoThrow();
1970 bool wasRunning;
1971 qint64 elapsed = scope.engine->stopTimer(timerName: name, wasRunning: &wasRunning);
1972 if (wasRunning) {
1973 qDebug(msg: "%s: %llims", qPrintable(name), elapsed);
1974 }
1975 return QV4::Encode::undefined();
1976}
1977
1978ReturnedValue ConsoleObject::method_count(const FunctionObject *b, const Value *, const Value *argv, int argc)
1979{
1980 // first argument: name to print. Ignore any additional arguments
1981 QString name;
1982 if (argc > 0)
1983 name = argv[0].toQStringNoThrow();
1984
1985 Scope scope(b);
1986 QV4::ExecutionEngine *v4 = scope.engine;
1987
1988 QV4::CppStackFrame *frame = v4->currentStackFrame;
1989
1990 QString scriptName = frame->source();
1991
1992 int value = v4->consoleCountHelper(file: scriptName, line: frame->lineNumber(), column: 0);
1993 QString message = name + QLatin1String(": ") + QString::number(value);
1994
1995 QMessageLogger(qPrintable(scriptName), frame->lineNumber(),
1996 qPrintable(frame->function()))
1997 .debug(msg: "%s", qPrintable(message));
1998
1999 return QV4::Encode::undefined();
2000}
2001
2002ReturnedValue ConsoleObject::method_trace(const FunctionObject *b, const Value *, const Value *, int argc)
2003{
2004 QV4::Scope scope(b);
2005 if (argc != 0)
2006 THROW_GENERIC_ERROR("console.trace(): Invalid arguments");
2007
2008 QV4::ExecutionEngine *v4 = scope.engine;
2009
2010 QString stack = jsStack(engine: v4);
2011
2012 QV4::CppStackFrame *frame = v4->currentStackFrame;
2013 QMessageLogger(frame->source().toUtf8().constData(), frame->lineNumber(),
2014 frame->function().toUtf8().constData())
2015 .debug(catFunc: v4->qmlEngine() ? lcQml : lcJs, msg: "%s", qPrintable(stack));
2016
2017 return QV4::Encode::undefined();
2018}
2019
2020ReturnedValue ConsoleObject::method_warn(const FunctionObject *b, const Value *, const Value *argv, int argc)
2021{
2022 return writeToConsole(b, argv, argc, logType: Warn);
2023}
2024
2025ReturnedValue ConsoleObject::method_assert(const FunctionObject *b, const Value *, const Value *argv, int argc)
2026{
2027 QV4::Scope scope(b);
2028 if (argc == 0)
2029 THROW_GENERIC_ERROR("console.assert(): Missing argument");
2030
2031 QV4::ExecutionEngine *v4 = scope.engine;
2032
2033 if (!argv[0].toBoolean()) {
2034 QString message;
2035 for (int i = 1, ei = argc; i < ei; ++i) {
2036 if (i != 1)
2037 message.append(c: QLatin1Char(' '));
2038
2039 message.append(s: argv[i].toQStringNoThrow());
2040 }
2041
2042 QString stack = jsStack(engine: v4);
2043
2044 QV4::CppStackFrame *frame = v4->currentStackFrame;
2045 QMessageLogger(frame->source().toUtf8().constData(), frame->lineNumber(),
2046 frame->function().toUtf8().constData())
2047 .critical(msg: "%s\n%s",qPrintable(message), qPrintable(stack));
2048
2049 }
2050 return QV4::Encode::undefined();
2051}
2052
2053ReturnedValue ConsoleObject::method_exception(const FunctionObject *b, const Value *, const Value *argv, int argc)
2054{
2055 QV4::Scope scope(b);
2056 if (argc == 0)
2057 THROW_GENERIC_ERROR("console.exception(): Missing argument");
2058
2059 return writeToConsole(b, argv, argc, logType: Error, printStack: true);
2060}
2061
2062void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions extensions)
2063{
2064 ExecutionEngine *v4 = globalObject->engine();
2065 Scope scope(v4);
2066
2067 if (extensions.testFlag(flag: QJSEngine::TranslationExtension)) {
2068 #if QT_CONFIG(translation)
2069 globalObject->defineDefaultProperty(QStringLiteral("qsTranslate"), code: QV4::GlobalExtensions::method_qsTranslate);
2070 globalObject->defineDefaultProperty(QStringLiteral("QT_TRANSLATE_NOOP"), code: QV4::GlobalExtensions::method_qsTranslateNoOp);
2071 globalObject->defineDefaultProperty(QStringLiteral("qsTr"), code: QV4::GlobalExtensions::method_qsTr);
2072 globalObject->defineDefaultProperty(QStringLiteral("QT_TR_NOOP"), code: QV4::GlobalExtensions::method_qsTrNoOp);
2073 globalObject->defineDefaultProperty(QStringLiteral("qsTrId"), code: QV4::GlobalExtensions::method_qsTrId);
2074 globalObject->defineDefaultProperty(QStringLiteral("QT_TRID_NOOP"), code: QV4::GlobalExtensions::method_qsTrIdNoOp);
2075
2076 // Initialize the Qt global object for the uiLanguage property
2077 ScopedString qtName(scope, v4->newString(QStringLiteral("Qt")));
2078 ScopedObject qt(scope, globalObject->get(name: qtName));
2079 if (!qt)
2080 v4->createQtObject();
2081
2082 // string prototype extension
2083 scope.engine->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), code: QV4::GlobalExtensions::method_string_arg);
2084 #endif
2085 }
2086
2087 if (extensions.testFlag(flag: QJSEngine::ConsoleExtension)) {
2088 globalObject->defineDefaultProperty(QStringLiteral("print"), code: QV4::ConsoleObject::method_log);
2089
2090
2091 QV4::ScopedObject console(scope, globalObject->engine()->memoryManager->allocate<QV4::ConsoleObject>());
2092 globalObject->defineDefaultProperty(QStringLiteral("console"), value: console);
2093 }
2094
2095 if (extensions.testFlag(flag: QJSEngine::GarbageCollectionExtension)) {
2096 globalObject->defineDefaultProperty(QStringLiteral("gc"), code: QV4::GlobalExtensions::method_gc);
2097 }
2098}
2099
2100
2101#if QT_CONFIG(translation)
2102/*!
2103 \qmlmethod string Qt::qsTranslate(string context, string sourceText, string disambiguation, int n)
2104
2105 Returns a translated version of \a sourceText within the given \a context, optionally based on a
2106 \a disambiguation string and value of \a n for strings containing plurals;
2107 otherwise returns \a sourceText itself if no appropriate translated string
2108 is available.
2109
2110 If the same \a sourceText is used in different roles within the
2111 same translation \a context, an additional identifying string may be passed in
2112 for \a disambiguation.
2113
2114 Example:
2115 \snippet qml/qsTranslate.qml 0
2116
2117 Use if you have a translation \a context that differs from the file \a context.
2118
2119 \sa {Internationalization with Qt}
2120 \sa qsTr()
2121*/
2122ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, const Value *, const Value *argv, int argc)
2123{
2124 QV4::Scope scope(b);
2125 if (argc < 2)
2126 THROW_GENERIC_ERROR("qsTranslate() requires at least two arguments");
2127 if (!argv[0].isString())
2128 THROW_GENERIC_ERROR("qsTranslate(): first argument (context) must be a string");
2129 if (!argv[1].isString())
2130 THROW_GENERIC_ERROR("qsTranslate(): second argument (sourceText) must be a string");
2131 if ((argc > 2) && !argv[2].isString())
2132 THROW_GENERIC_ERROR("qsTranslate(): third argument (disambiguation) must be a string");
2133
2134 QString context = argv[0].toQStringNoThrow();
2135 QString text = argv[1].toQStringNoThrow();
2136 QString comment;
2137 if (argc > 2) comment = argv[2].toQStringNoThrow();
2138
2139 int i = 3;
2140 if (argc > i && argv[i].isString()) {
2141 qWarning(msg: "qsTranslate(): specifying the encoding as fourth argument is deprecated");
2142 ++i;
2143 }
2144
2145 int n = -1;
2146 if (argc > i)
2147 n = argv[i].toInt32();
2148
2149 if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(e: scope.engine->qmlEngine()) : nullptr))
2150 if (ep->propertyCapture)
2151 ep->propertyCapture->captureTranslation();
2152
2153 QString result = QCoreApplication::translate(context: context.toUtf8().constData(),
2154 key: text.toUtf8().constData(),
2155 disambiguation: comment.toUtf8().constData(),
2156 n);
2157
2158 return Encode(scope.engine->newString(s: result));
2159}
2160
2161/*!
2162 \qmlmethod string Qt::QT_TRANSLATE_NOOP(string context, string sourceText, string disambiguation)
2163
2164 Marks \a sourceText for dynamic translation in the given \a context; i.e, the stored \a sourceText
2165 will not be altered.
2166
2167 If the same \a sourceText is used in different roles within the
2168 same translation context, an additional identifying string may be passed in
2169 for \a disambiguation.
2170
2171 Returns the \a sourceText.
2172
2173 QT_TRANSLATE_NOOP is used in conjunction with the dynamic translation functions
2174 qsTr() and qsTranslate(). It identifies a string as requiring
2175 translation (so it can be identified by \c lupdate), but leaves the actual
2176 translation to the dynamic functions.
2177
2178 Example:
2179 \snippet qml/qtTranslateNoOp.qml 0
2180
2181 \sa {Internationalization with Qt}
2182*/
2183ReturnedValue GlobalExtensions::method_qsTranslateNoOp(const FunctionObject *b, const Value *, const Value *argv, int argc)
2184{
2185 QV4::Scope scope(b);
2186 if (argc < 2)
2187 return QV4::Encode::undefined();
2188 else
2189 return argv[1].asReturnedValue();
2190}
2191
2192QString GlobalExtensions::currentTranslationContext(ExecutionEngine *engine)
2193{
2194 QString context;
2195 CppStackFrame *frame = engine->currentStackFrame;
2196
2197 // The first non-empty source URL in the call stack determines the translation context.
2198 while (frame && context.isEmpty()) {
2199 if (ExecutableCompilationUnit *unit = frame->v4Function->executableCompilationUnit()) {
2200 auto translationContextIndex = unit->unitData()->translationContextIndex();
2201 if (translationContextIndex)
2202 context = unit->stringAt(index: *translationContextIndex);
2203 if (!context.isEmpty())
2204 break;
2205 QString fileName = unit->fileName();
2206 QUrl url(unit->fileName());
2207 if (url.isValid() && url.isRelative()) {
2208 context = url.fileName();
2209 } else {
2210 context = QQmlFile::urlToLocalFileOrQrc(fileName);
2211 if (context.isEmpty() && fileName.startsWith(s: QLatin1String(":/")))
2212 context = fileName;
2213 }
2214 context = QFileInfo(context).completeBaseName();
2215 }
2216 frame = frame->parentFrame();
2217 }
2218
2219 if (context.isEmpty()) {
2220 if (QQmlRefPointer<QQmlContextData> ctxt = engine->callingQmlContext()) {
2221 QString path = ctxt->urlString();
2222 int lastSlash = path.lastIndexOf(c: QLatin1Char('/'));
2223 int lastDot = path.lastIndexOf(c: QLatin1Char('.'));
2224 int length = lastDot - (lastSlash + 1);
2225 context = (lastSlash > -1) ? path.mid(position: lastSlash + 1, n: (length > -1) ? length : -1) : QString();
2226 }
2227 }
2228
2229 return context;
2230}
2231
2232/*!
2233 \qmlmethod string Qt::qsTr(string sourceText, string disambiguation, int n)
2234
2235 Returns a translated version of \a sourceText, optionally based on a
2236 \a disambiguation string and value of \a n for strings containing plurals;
2237 otherwise returns \a sourceText itself if no appropriate translated string
2238 is available.
2239
2240 Examples with \a sourceText and \a {n}:
2241
2242 \if defined(onlinedocs)
2243 \tab {qstr}{qstr-1}{sourceText}{checked}
2244 \tab {qstr}{qstr-2}{sourceText and n}{}
2245 \tabcontent {qstr-1}
2246 \else
2247 \section1 Only sourceText
2248 \endif
2249 \snippet qml/qsTr.qml 0
2250 \if defined(onlinedocs)
2251 \endtabcontent
2252 \tabcontent {qstr-2}
2253 \else
2254 \section1 SourceText and n
2255 \endif
2256 \snippet qml/qsTr.qml 1
2257 \if defined(onlinedocs)
2258 \endtabcontent
2259 \endif
2260
2261 If the same \a sourceText is used in different roles within the
2262 same translation context, an additional identifying string may be passed in
2263 for \a disambiguation. For more information and examples, refer to
2264 \l{Disambiguate Identical Text}.
2265
2266 \sa qsTranslate()
2267 \sa {Internationalization with Qt},{Writing Source Code for Translation}
2268*/
2269ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value *, const Value *argv, int argc)
2270{
2271 QV4::Scope scope(b);
2272 if (argc < 1)
2273 THROW_GENERIC_ERROR("qsTr() requires at least one argument");
2274 if (!argv[0].isString())
2275 THROW_GENERIC_ERROR("qsTr(): first argument (sourceText) must be a string");
2276 if ((argc > 1) && !argv[1].isString())
2277 THROW_GENERIC_ERROR("qsTr(): second argument (disambiguation) must be a string");
2278 if ((argc > 2) && !argv[2].isNumber())
2279 THROW_GENERIC_ERROR("qsTr(): third argument (n) must be a number");
2280
2281 const QString context = currentTranslationContext(engine: scope.engine);
2282 const QString text = argv[0].toQStringNoThrow();
2283 const QString comment = argc > 1 ? argv[1].toQStringNoThrow() : QString();
2284 const int n = argc > 2 ? argv[2].toInt32() : -1;
2285
2286 if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(e: scope.engine->qmlEngine()) : nullptr))
2287 if (ep->propertyCapture)
2288 ep->propertyCapture->captureTranslation();
2289
2290 QString result = QCoreApplication::translate(context: context.toUtf8().constData(), key: text.toUtf8().constData(),
2291 disambiguation: comment.toUtf8().constData(), n);
2292
2293 return Encode(scope.engine->newString(s: result));
2294}
2295
2296/*!
2297 \qmlmethod string Qt::QT_TR_NOOP(string sourceText, string disambiguation)
2298
2299 Marks \a sourceText for dynamic translation; i.e, the stored \a sourceText
2300 will not be altered.
2301
2302 If the same \a sourceText is used in different roles within the
2303 same translation context, an additional identifying string may be passed in
2304 for \a disambiguation.
2305
2306 Returns the \a sourceText.
2307
2308 QT_TR_NOOP is used in conjunction with the dynamic translation functions
2309 qsTr() and qsTranslate(). It identifies a string as requiring
2310 translation (so it can be identified by \c lupdate), but leaves the actual
2311 translation to the dynamic functions.
2312
2313 Example:
2314 \snippet qml/qtTrNoOp.qml 0
2315
2316 \sa {Internationalization with Qt}
2317*/
2318ReturnedValue GlobalExtensions::method_qsTrNoOp(const FunctionObject *, const Value *, const Value *argv, int argc)
2319{
2320 if (argc < 1)
2321 return QV4::Encode::undefined();
2322 else
2323 return argv[0].asReturnedValue();
2324}
2325
2326/*!
2327 \qmlmethod string Qt::qsTrId(string id, int n)
2328
2329 Returns a translated string identified by \a id.
2330 If no matching string is found, the id itself is returned. This
2331 should not happen under normal conditions.
2332
2333 If \a n >= 0, all occurrences of \c %n in the resulting string
2334 are replaced with a decimal representation of \a n. In addition,
2335 depending on \a n's value, the translation text may vary.
2336
2337 Example:
2338 \snippet qml/qsTrId.qml 0
2339
2340 It is possible to supply a source string template like:
2341
2342 \tt{//% <string>}
2343
2344 \snippet qml/qsTrId.1.qml 0
2345
2346 or
2347
2348 \tt{\begincomment% <string> \endcomment}
2349
2350 \snippet qml/qsTrId.1.qml 1
2351
2352 Creating binary translation (QM) files suitable for use with this function requires passing
2353 the \c -idbased option to the \c lrelease tool.
2354
2355 \sa QT_TRID_NOOP(), {Internationalization with Qt}
2356*/
2357ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Value *, const Value *argv, int argc)
2358{
2359 QV4::Scope scope(b);
2360 if (argc < 1)
2361 THROW_GENERIC_ERROR("qsTrId() requires at least one argument");
2362 if (!argv[0].isString())
2363 THROW_TYPE_ERROR_WITH_MESSAGE("qsTrId(): first argument (id) must be a string");
2364 if (argc > 1 && !argv[1].isNumber())
2365 THROW_TYPE_ERROR_WITH_MESSAGE("qsTrId(): second argument (n) must be a number");
2366
2367 int n = -1;
2368 if (argc > 1)
2369 n = argv[1].toInt32();
2370
2371 if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(e: scope.engine->qmlEngine()) : nullptr))
2372 if (ep->propertyCapture)
2373 ep->propertyCapture->captureTranslation();
2374
2375 return Encode(scope.engine->newString(s: qtTrId(id: argv[0].toQStringNoThrow().toUtf8().constData(), n)));
2376}
2377
2378/*!
2379 \qmlmethod string Qt::QT_TRID_NOOP(string id)
2380
2381 Marks \a id for dynamic translation.
2382
2383 Returns the \a id.
2384
2385 QT_TRID_NOOP is used in conjunction with the dynamic translation function
2386 qsTrId(). It identifies a string as requiring translation (so it can be identified
2387 by \c lupdate), but leaves the actual translation to qsTrId().
2388
2389 Example:
2390 \snippet qml/qtTrIdNoOp.qml 0
2391
2392 \sa qsTrId(), {Internationalization with Qt}
2393*/
2394ReturnedValue GlobalExtensions::method_qsTrIdNoOp(const FunctionObject *, const Value *, const Value *argv, int argc)
2395{
2396 if (argc < 1)
2397 return QV4::Encode::undefined();
2398 else
2399 return argv[0].asReturnedValue();
2400}
2401#endif // translation
2402
2403/*!
2404 \qmlmethod void Qt::gc()
2405
2406 Runs the garbage collector.
2407
2408 This is equivalent to calling QJSEngine::collectGarbage().
2409
2410 \sa {Garbage Collection}
2411*/
2412ReturnedValue GlobalExtensions::method_gc(const FunctionObject *b, const Value *, const Value *, int)
2413{
2414 auto mm = b->engine()->memoryManager;
2415 mm->runFullGC();
2416
2417 return QV4::Encode::undefined();
2418}
2419
2420ReturnedValue GlobalExtensions::method_string_arg(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
2421{
2422 QV4::Scope scope(b);
2423 if (argc != 1)
2424 THROW_GENERIC_ERROR("String.arg(): Invalid arguments");
2425
2426 QString value = thisObject->toQString();
2427
2428 QV4::ScopedValue arg(scope, argv[0]);
2429 if (arg->isInteger())
2430 RETURN_RESULT(scope.engine->newString(value.arg(arg->integerValue())));
2431 else if (arg->isDouble())
2432 RETURN_RESULT(scope.engine->newString(value.arg(arg->doubleValue())));
2433 else if (arg->isBoolean())
2434 RETURN_RESULT(scope.engine->newString(value.arg(arg->booleanValue())));
2435
2436 RETURN_RESULT(scope.engine->newString(value.arg(arg->toQString())));
2437}
2438
2439/*!
2440\qmlmethod Qt::callLater(function)
2441\qmlmethod Qt::callLater(function, argument1, argument2, ...)
2442\since 5.8
2443Use this function to eliminate redundant calls to a function or signal.
2444
2445The function passed as the first argument to Qt.callLater()
2446will be called later, once the QML engine returns to the event loop.
2447
2448When this function is called multiple times in quick succession with the
2449same function as its first argument, that function will be called only once.
2450
2451For example:
2452\snippet qml/qtLater.qml 0
2453
2454Any additional arguments passed to Qt.callLater() will
2455be passed on to the function invoked. Note that if redundant calls
2456are eliminated, then only the last set of arguments will be passed to the
2457function.
2458*/
2459
2460QT_END_NAMESPACE
2461
2462#include "moc_qqmlbuiltinfunctions_p.cpp"
2463

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/qml/qml/qqmlbuiltinfunctions.cpp