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

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