1 | // Copyright (C) 2016 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 <QtQml/private/qjsvalue_p.h> |
5 | #include <QtQml/private/qqmlglobal_p.h> |
6 | #include <QtQml/private/qqmlmetatype_p.h> |
7 | #include <QtQml/qqmlengine.h> |
8 | |
9 | #include <QtCore/private/qvariant_p.h> |
10 | #include <QtCore/qcoreapplication.h> |
11 | #include <QtCore/qdebug.h> |
12 | #include <QtCore/qstringlist.h> |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | // Pre-filter the metatype before poking QQmlMetaType::qmlType() and locking its mutex. |
17 | static bool isConstructibleMetaType(const QMetaType metaType) |
18 | { |
19 | switch (metaType.id()) { |
20 | // The builtins are not constructible this way. |
21 | case QMetaType::Void: |
22 | case QMetaType::Nullptr: |
23 | case QMetaType::QVariant: |
24 | case QMetaType::Int: |
25 | case QMetaType::UInt: |
26 | case QMetaType::LongLong: |
27 | case QMetaType::ULongLong: |
28 | case QMetaType::Float: |
29 | case QMetaType::Double: |
30 | case QMetaType::Long: |
31 | case QMetaType::ULong: |
32 | case QMetaType::Short: |
33 | case QMetaType::UShort: |
34 | case QMetaType::Char: |
35 | case QMetaType::SChar: |
36 | case QMetaType::UChar: |
37 | case QMetaType::QChar: |
38 | case QMetaType::QString: |
39 | case QMetaType::Bool: |
40 | case QMetaType::QDateTime: |
41 | case QMetaType::QDate: |
42 | case QMetaType::QTime: |
43 | case QMetaType::QUrl: |
44 | case QMetaType::QRegularExpression: |
45 | case QMetaType::QByteArray: |
46 | case QMetaType::QLocale: |
47 | return false; |
48 | default: |
49 | break; |
50 | } |
51 | |
52 | // QJSValue is also builtin |
53 | if (metaType == QMetaType::fromType<QJSValue>()) |
54 | return false; |
55 | |
56 | // We also don't want to construct pointers of any kind, or lists, or enums. |
57 | if (metaType.flags() & |
58 | (QMetaType::PointerToQObject |
59 | | QMetaType::IsEnumeration |
60 | | QMetaType::SharedPointerToQObject |
61 | | QMetaType::WeakPointerToQObject |
62 | | QMetaType::TrackingPointerToQObject |
63 | | QMetaType::IsUnsignedEnumeration |
64 | | QMetaType::PointerToGadget |
65 | | QMetaType::IsPointer |
66 | | QMetaType::IsQmlList)) { |
67 | return false; |
68 | } |
69 | |
70 | return true; |
71 | } |
72 | |
73 | static void *createVariantData(QMetaType type, QVariant *variant) |
74 | { |
75 | const QtPrivate::QMetaTypeInterface *iface = type.iface(); |
76 | QVariant::Private *d = &variant->data_ptr(); |
77 | Q_ASSERT(d->is_null && !d->is_shared); |
78 | *d = QVariant::Private(iface); |
79 | if (QVariant::Private::canUseInternalSpace(type: iface)) |
80 | return d->data.data; |
81 | |
82 | // This is not exception safe. |
83 | // If your value type throws an exception from its ctor bad things will happen anyway. |
84 | d->data.shared = QVariant::PrivateShared::create(size: iface->size, align: iface->alignment); |
85 | d->is_shared = true; |
86 | return d->data.shared->data(); |
87 | } |
88 | |
89 | static void callConstructor( |
90 | const QMetaObject *targetMetaObject, int i, void *source, void *target) |
91 | { |
92 | void *p[] = { target, source }; |
93 | targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p); |
94 | } |
95 | |
96 | template<typename Allocate> |
97 | static void fromVerifiedType( |
98 | const QMetaObject *targetMetaObject, int ctorIndex, void *source, Allocate &&allocate) |
99 | { |
100 | const QMetaMethod ctor = targetMetaObject->constructor(index: ctorIndex); |
101 | Q_ASSERT_X(ctor.parameterCount() == 1, "fromVerifiedType" , |
102 | "Value type constructor must take exactly one argument" ); |
103 | callConstructor(targetMetaObject, ctorIndex, source, allocate()); |
104 | } |
105 | |
106 | |
107 | template<typename Allocate, typename Retrieve> |
108 | static bool fromMatchingType( |
109 | const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve) |
110 | { |
111 | for (int i = 0, end = targetMetaObject->constructorCount(); i < end; ++i) { |
112 | const QMetaMethod ctor = targetMetaObject->constructor(index: i); |
113 | if (ctor.parameterCount() != 1) |
114 | continue; |
115 | |
116 | const QMetaType parameterType = ctor.parameterMetaType(index: 0); |
117 | |
118 | if (retrieve(parameterType, [&](QMetaType sourceMetaType, void *sourceData) { |
119 | if (sourceMetaType == parameterType) { |
120 | callConstructor(targetMetaObject, i, sourceData, allocate()); |
121 | return true; |
122 | } |
123 | |
124 | if (const QMetaObject *parameterMetaObject = parameterType.metaObject()) { |
125 | if (const QMetaObject *sourceMetaObject = sourceMetaType.metaObject(); |
126 | sourceMetaObject && sourceMetaObject->inherits(metaObject: parameterMetaObject)) { |
127 | // Allow construction from derived types. |
128 | callConstructor(targetMetaObject, i, sourceData, allocate()); |
129 | return true; |
130 | } |
131 | } |
132 | |
133 | // Do not recursively try to create parameters here. This may end up in infinite recursion. |
134 | |
135 | // At this point, s should be a builtin type. For builtin types |
136 | // the QMetaType converters are good enough. |
137 | QVariant converted(parameterType); |
138 | if (QMetaType::convert(fromType: sourceMetaType, from: sourceData, toType: parameterType, to: converted.data())) { |
139 | callConstructor(targetMetaObject, i, converted.data(), allocate()); |
140 | return true; |
141 | } |
142 | |
143 | return false; |
144 | })) { |
145 | return true; |
146 | } |
147 | } |
148 | |
149 | return false; |
150 | } |
151 | |
152 | template<typename Allocate> |
153 | static bool fromMatchingType( |
154 | const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate) |
155 | { |
156 | return fromMatchingType( |
157 | targetMetaObject, std::forward<Allocate>(allocate), |
158 | [&](QMetaType parameterType, auto callback) { |
159 | QVariant variant = QV4::ExecutionEngine::toVariant(value: source, typeHint: parameterType); |
160 | return callback(variant.metaType(), variant.data()); |
161 | }); |
162 | } |
163 | |
164 | template<typename Allocate> |
165 | static bool fromMatchingType( |
166 | const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate) |
167 | { |
168 | return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate), |
169 | [&](QMetaType, auto callback) { |
170 | return callback(source.metaType(), source.data()); |
171 | }); |
172 | } |
173 | |
174 | template<typename Allocate> |
175 | static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate) |
176 | { |
177 | for (int i = 0, end = mo->constructorCount(); i < end; ++i) { |
178 | const QMetaMethod ctor = mo->constructor(index: i); |
179 | if (ctor.parameterCount() != 1) |
180 | continue; |
181 | |
182 | if (ctor.parameterMetaType(index: 0) == QMetaType::fromType<QString>()) { |
183 | callConstructor(mo, i, &s, allocate()); |
184 | return true; |
185 | } |
186 | } |
187 | |
188 | return false; |
189 | } |
190 | |
191 | template<typename Get, typename Convert> |
192 | static bool doWriteProperty(const QMetaProperty &metaProperty, void *target, |
193 | Get &&get, Convert &&convert) |
194 | { |
195 | const QMetaType propertyType = metaProperty.metaType(); |
196 | QVariant property = get(propertyType); |
197 | if (property.metaType() == propertyType) { |
198 | metaProperty.writeOnGadget(gadget: target, value: std::move(property)); |
199 | return true; |
200 | } |
201 | |
202 | QVariant converted = convert(propertyType); |
203 | if (converted.isValid()) { |
204 | metaProperty.writeOnGadget(gadget: target, value: std::move(converted)); |
205 | return true; |
206 | } |
207 | |
208 | converted = QVariant(propertyType); |
209 | if (QMetaType::convert(fromType: property.metaType(), from: property.constData(), |
210 | toType: propertyType, to: converted.data())) { |
211 | metaProperty.writeOnGadget(gadget: target, value: std::move(converted)); |
212 | return true; |
213 | } |
214 | |
215 | return false; |
216 | } |
217 | |
218 | static void doWriteProperties( |
219 | const QMetaObject *targetMetaObject, void *target, const QV4::Value &source) |
220 | { |
221 | const QV4::Object *o = static_cast<const QV4::Object *>(&source); |
222 | QV4::Scope scope(o->engine()); |
223 | QV4::ScopedObject object(scope, o); |
224 | |
225 | for (int i = 0; i < targetMetaObject->propertyCount(); ++i) { |
226 | const QMetaProperty metaProperty = targetMetaObject->property(index: i); |
227 | const QString propertyName = QString::fromUtf8(utf8: metaProperty.name()); |
228 | |
229 | QV4::ScopedString v4PropName(scope, scope.engine->newString(s: propertyName)); |
230 | QV4::ScopedValue v4PropValue(scope, object->get(name: v4PropName)); |
231 | |
232 | // We assume that data is freshly constructed. |
233 | // There is no point in reset()'ing properties of a freshly created object. |
234 | if (v4PropValue->isUndefined()) |
235 | continue; |
236 | |
237 | if (doWriteProperty(metaProperty, target, get: [&](const QMetaType &propertyType) { |
238 | return QV4::ExecutionEngine::toVariant(value: v4PropValue, typeHint: propertyType); |
239 | }, convert: [&](const QMetaType &propertyType) { |
240 | return QQmlValueTypeProvider::createValueType(v4PropValue, propertyType); |
241 | })) { |
242 | continue; |
243 | } |
244 | |
245 | const QMetaType propertyType = metaProperty.metaType(); |
246 | QVariant property = QV4::ExecutionEngine::toVariant(value: v4PropValue, typeHint: propertyType); |
247 | if (property.metaType() == propertyType) { |
248 | metaProperty.writeOnGadget(gadget: target, value: std::move(property)); |
249 | continue; |
250 | } |
251 | |
252 | QVariant converted = QQmlValueTypeProvider::createValueType(v4PropValue, propertyType); |
253 | if (converted.isValid()) { |
254 | metaProperty.writeOnGadget(gadget: target, value: std::move(converted)); |
255 | continue; |
256 | } |
257 | |
258 | converted = QVariant(propertyType); |
259 | if (QMetaType::convert(fromType: property.metaType(), from: property.constData(), |
260 | toType: propertyType, to: converted.data())) { |
261 | metaProperty.writeOnGadget(gadget: target, value: std::move(converted)); |
262 | continue; |
263 | } |
264 | |
265 | qWarning().noquote() |
266 | << QLatin1String("Could not convert %1 to %2 for property %3" ) |
267 | .arg(args: v4PropValue->toQStringNoThrow(), args: QString::fromUtf8(utf8: propertyType.name()), |
268 | args: propertyName); |
269 | } |
270 | } |
271 | |
272 | static QVariant byProperties( |
273 | const QMetaObject *targetMetaObject, QMetaType metaType, const QV4::Value &source) |
274 | { |
275 | if (!source.isObject() || !targetMetaObject) |
276 | return QVariant(); |
277 | |
278 | QVariant result(metaType); |
279 | doWriteProperties(targetMetaObject, target: result.data(), source); |
280 | return result; |
281 | } |
282 | |
283 | template<typename Read> |
284 | static void doWriteProperties( |
285 | const QMetaObject *targetMetaObject, void *target, |
286 | const QMetaObject *sourceMetaObject, Read &&read) |
287 | { |
288 | for (int i = 0; i < targetMetaObject->propertyCount(); ++i) { |
289 | const QMetaProperty metaProperty = targetMetaObject->property(index: i); |
290 | |
291 | const int sourceProperty = sourceMetaObject->indexOfProperty(name: metaProperty.name()); |
292 | |
293 | // We assume that data is freshly constructed. |
294 | // There is no point in reset()'ing properties of a freshly created object. |
295 | if (sourceProperty == -1) |
296 | continue; |
297 | |
298 | const QMetaType propertyType = metaProperty.metaType(); |
299 | QVariant property = read(sourceMetaObject, sourceProperty); |
300 | if (property.metaType() == propertyType) { |
301 | metaProperty.writeOnGadget(gadget: target, value: std::move(property)); |
302 | continue; |
303 | } |
304 | |
305 | QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType); |
306 | if (converted.isValid()) { |
307 | metaProperty.writeOnGadget(gadget: target, value: std::move(converted)); |
308 | continue; |
309 | } |
310 | |
311 | converted = QVariant(propertyType); |
312 | if (QMetaType::convert(fromType: property.metaType(), from: property.constData(), |
313 | toType: propertyType, to: converted.data())) { |
314 | metaProperty.writeOnGadget(gadget: target, value: std::move(converted)); |
315 | continue; |
316 | } |
317 | |
318 | qWarning().noquote() |
319 | << QLatin1String("Could not convert %1 to %2 for property %3" ) |
320 | .arg(args: property.toString(), args: QString::fromUtf8(utf8: propertyType.name()), |
321 | args: QString::fromUtf8(utf8: metaProperty.name())); |
322 | } |
323 | } |
324 | |
325 | |
326 | static void doWriteProperties(const QMetaObject *targetMeta, void *target, QObject *source) |
327 | { |
328 | doWriteProperties( |
329 | targetMetaObject: targetMeta, target, sourceMetaObject: source->metaObject(), |
330 | read: [source](const QMetaObject *sourceMetaObject, int sourceProperty) { |
331 | return sourceMetaObject->property(index: sourceProperty).read(obj: source); |
332 | }); |
333 | } |
334 | |
335 | static QVariant byProperties( |
336 | const QMetaObject *targetMetaObject, QMetaType targetMetaType, QObject *source) |
337 | { |
338 | if (!source || !targetMetaObject) |
339 | return QVariant(); |
340 | |
341 | QVariant result(targetMetaType); |
342 | doWriteProperties(targetMeta: targetMetaObject, target: result.data(), source); |
343 | return result; |
344 | } |
345 | |
346 | static QVariant byProperties( |
347 | const QMetaObject *targetMetaObject, QMetaType targetMetaType, |
348 | const QMetaObject *sourceMetaObject, const void *source) |
349 | { |
350 | if (!source || !sourceMetaObject || !targetMetaObject) |
351 | return QVariant(); |
352 | |
353 | QVariant result(targetMetaType); |
354 | doWriteProperties( |
355 | targetMetaObject, target: result.data(), sourceMetaObject, |
356 | read: [source](const QMetaObject *sourceMetaObject, int sourceProperty) { |
357 | return sourceMetaObject->property(index: sourceProperty).readOnGadget(gadget: source); |
358 | }); |
359 | return result; |
360 | } |
361 | |
362 | template<typename Map> |
363 | void doWriteProperties(const QMetaObject *targetMetaObject, void *target, const Map &source) |
364 | { |
365 | for (int i = 0; i < targetMetaObject->propertyCount(); ++i) { |
366 | const QMetaProperty metaProperty = targetMetaObject->property(index: i); |
367 | |
368 | // We assume that data is freshly constructed. |
369 | // There is no point in reset()'ing properties of a freshly created object. |
370 | const auto it = source.constFind(QString::fromUtf8(utf8: metaProperty.name())); |
371 | if (it == source.constEnd()) |
372 | continue; |
373 | |
374 | const QMetaType propertyType = metaProperty.metaType(); |
375 | QVariant property = *it; |
376 | if (property.metaType() == propertyType) { |
377 | metaProperty.writeOnGadget(gadget: target, value: std::move(property)); |
378 | continue; |
379 | } |
380 | |
381 | QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType); |
382 | if (converted.isValid()) { |
383 | metaProperty.writeOnGadget(gadget: target, value: std::move(converted)); |
384 | continue; |
385 | } |
386 | |
387 | converted = QVariant(propertyType); |
388 | if (QMetaType::convert(fromType: property.metaType(), from: property.constData(), |
389 | toType: propertyType, to: converted.data())) { |
390 | metaProperty.writeOnGadget(gadget: target, value: std::move(converted)); |
391 | continue; |
392 | } |
393 | |
394 | qWarning().noquote() |
395 | << QLatin1String("Could not convert %1 to %2 for property %3" ) |
396 | .arg(args: property.toString(), args: QString::fromUtf8(utf8: propertyType.name()), |
397 | args: QString::fromUtf8(utf8: metaProperty.name())); |
398 | } |
399 | } |
400 | |
401 | template<typename Map> |
402 | QVariant byProperties( |
403 | const QMetaObject *targetMetaObject, QMetaType targetMetaType, const Map &source) |
404 | { |
405 | QVariant result(targetMetaType); |
406 | doWriteProperties(targetMetaObject, result.data(), source); |
407 | return result; |
408 | } |
409 | |
410 | static QVariant byProperties( |
411 | const QMetaObject *targetMetaObject, QMetaType targetMetaType, const QVariant &source) |
412 | { |
413 | if (!targetMetaObject) |
414 | return QVariant(); |
415 | |
416 | if (source.metaType() == QMetaType::fromType<QJSValue>()) { |
417 | QJSValue val = source.value<QJSValue>(); |
418 | return byProperties( |
419 | targetMetaObject, metaType: targetMetaType, source: QV4::Value(QJSValuePrivate::asReturnedValue(jsval: &val))); |
420 | } |
421 | |
422 | if (source.metaType() == QMetaType::fromType<QVariantMap>()) { |
423 | return byProperties( |
424 | targetMetaObject, targetMetaType, |
425 | source: *static_cast<const QVariantMap *>(source.constData())); |
426 | } |
427 | |
428 | if (source.metaType() == QMetaType::fromType<QVariantHash>()) { |
429 | return byProperties( |
430 | targetMetaObject, targetMetaType, |
431 | source: *static_cast<const QVariantHash *>(source.constData())); |
432 | } |
433 | |
434 | if (source.metaType().flags() & QMetaType::PointerToQObject) |
435 | return byProperties(targetMetaObject, targetMetaType, source: source.value<QObject *>()); |
436 | |
437 | if (const QMetaObject *sourceMeta = QQmlMetaType::metaObjectForValueType(type: source.metaType())) |
438 | return byProperties(targetMetaObject, targetMetaType, sourceMetaObject: sourceMeta, source: source.constData()); |
439 | |
440 | return QVariant(); |
441 | } |
442 | |
443 | /*! |
444 | * \internal |
445 | * Specialization that creates the value type in place at \a target, which is expected to be |
446 | * already initialized. This is more efficient if we can do byProperties() since it can use a |
447 | * pre-constructed object. It also avoids the creation of a QVariant in most cases. It is less |
448 | * efficient if you're going to create a QVariant anyway. |
449 | */ |
450 | bool QQmlValueTypeProvider::createValueType( |
451 | QMetaType targetMetaType, void *target, const QV4::Value &source) |
452 | { |
453 | if (!isConstructibleMetaType(metaType: targetMetaType)) |
454 | return false; |
455 | |
456 | auto destruct = [targetMetaType, target]() { |
457 | targetMetaType.destruct(data: target); |
458 | return target; |
459 | }; |
460 | |
461 | const QQmlType type = QQmlMetaType::qmlType(metaType: targetMetaType); |
462 | if (const QMetaObject *targetMeta = QQmlMetaType::metaObjectForValueType(qmlType: type)) { |
463 | const auto warn = [&]() { |
464 | qWarning().noquote() |
465 | << "Could not find any constructor for value type" |
466 | << targetMeta->className() << "to call with value" << source.toQStringNoThrow(); |
467 | }; |
468 | |
469 | if (type.canPopulateValueType()) { |
470 | if (source.isObject() && targetMeta) { |
471 | doWriteProperties(targetMetaObject: targetMeta, target, source); |
472 | return true; |
473 | } |
474 | if (type.canConstructValueType()) { |
475 | if (fromMatchingType(targetMetaObject: targetMeta, source, allocate&: destruct)) |
476 | return true; |
477 | warn(); |
478 | |
479 | } |
480 | } else if (type.canConstructValueType()) { |
481 | if (fromMatchingType(targetMetaObject: targetMeta, source, allocate&: destruct)) |
482 | return true; |
483 | warn(); |
484 | } |
485 | } |
486 | |
487 | if (const auto valueTypeFunction = type.createValueTypeFunction()) { |
488 | const QVariant result |
489 | = valueTypeFunction(QJSValuePrivate::fromReturnedValue(d: source.asReturnedValue())); |
490 | if (result.metaType() == targetMetaType) { |
491 | targetMetaType.construct(where: destruct(), copy: result.constData()); |
492 | return true; |
493 | } |
494 | } |
495 | |
496 | return false; |
497 | } |
498 | |
499 | bool QQmlValueTypeProvider::createValueType( |
500 | QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source) |
501 | { |
502 | if (sourceMetaType == QMetaType::fromType<QJSValue>()) { |
503 | const QJSValue *val = static_cast<const QJSValue *>(source); |
504 | return createValueType( |
505 | targetMetaType, target, source: QV4::Value(QJSValuePrivate::asReturnedValue(jsval: val))); |
506 | } |
507 | |
508 | if (!isConstructibleMetaType(metaType: targetMetaType)) |
509 | return false; |
510 | |
511 | auto destruct = [targetMetaType, target]() { |
512 | targetMetaType.destruct(data: target); |
513 | return target; |
514 | }; |
515 | |
516 | const QQmlType type = QQmlMetaType::qmlType(metaType: targetMetaType); |
517 | if (const QMetaObject *targetMetaObject = QQmlMetaType::metaObjectForValueType(qmlType: type)) { |
518 | const auto warn = [&]() { |
519 | qWarning().noquote() |
520 | << "Could not find any constructor for value type" |
521 | << targetMetaObject->className() << "to call with value" << source; |
522 | }; |
523 | |
524 | if (type.canPopulateValueType()) { |
525 | |
526 | if (const QMetaObject *sourceMetaObject |
527 | = QQmlMetaType::metaObjectForValueType(type: sourceMetaType)) { |
528 | doWriteProperties( |
529 | targetMetaObject, target, sourceMetaObject, |
530 | read: [&source](const QMetaObject *sourceMetaObject, int sourceProperty) { |
531 | return sourceMetaObject->property(index: sourceProperty).readOnGadget(gadget: source); |
532 | }); |
533 | return true; |
534 | } |
535 | |
536 | if (sourceMetaType == QMetaType::fromType<QVariantMap>()) { |
537 | doWriteProperties( |
538 | targetMetaObject, target, source: *static_cast<const QVariantMap *>(source)); |
539 | return true; |
540 | } |
541 | |
542 | if (sourceMetaType == QMetaType::fromType<QVariantHash>()) { |
543 | doWriteProperties( |
544 | targetMetaObject, target, source: *static_cast<const QVariantHash *>(source)); |
545 | return true; |
546 | } |
547 | |
548 | if (sourceMetaType.flags() & QMetaType::PointerToQObject) { |
549 | doWriteProperties(targetMeta: targetMetaObject, target, source: *static_cast<QObject *const *>(source)); |
550 | return true; |
551 | } |
552 | } |
553 | |
554 | if (type.canConstructValueType()) { |
555 | if (fromMatchingType(targetMetaObject, allocate&: destruct, retrieve: [&](QMetaType, auto callback) { |
556 | return callback(sourceMetaType, source); |
557 | })) { |
558 | return true; |
559 | } |
560 | warn(); |
561 | } |
562 | } |
563 | |
564 | return false; |
565 | } |
566 | |
567 | QVariant QQmlValueTypeProvider::constructValueType( |
568 | QMetaType resultMetaType, const QMetaObject *resultMetaObject, |
569 | int ctorIndex, void *ctorArg) |
570 | { |
571 | QVariant result; |
572 | fromVerifiedType(targetMetaObject: resultMetaObject, ctorIndex, source: ctorArg, |
573 | allocate: [&]() { return createVariantData(type: resultMetaType, variant: &result); }); |
574 | return result; |
575 | } |
576 | |
577 | static QVariant fromJSValue(const QQmlType &type, const QJSValue &s, QMetaType metaType) |
578 | { |
579 | if (const auto valueTypeFunction = type.createValueTypeFunction()) { |
580 | const QVariant result = valueTypeFunction(s); |
581 | if (result.metaType() == metaType) |
582 | return result; |
583 | } |
584 | |
585 | return QVariant(); |
586 | } |
587 | |
588 | QVariant QQmlValueTypeProvider::createValueType(const QJSValue &s, QMetaType metaType) |
589 | { |
590 | if (!isConstructibleMetaType(metaType)) |
591 | return QVariant(); |
592 | return fromJSValue(type: QQmlMetaType::qmlType(metaType), s, metaType); |
593 | } |
594 | |
595 | QVariant QQmlValueTypeProvider::createValueType(const QString &s, QMetaType metaType) |
596 | { |
597 | if (!isConstructibleMetaType(metaType)) |
598 | return QVariant(); |
599 | const QQmlType type = QQmlMetaType::qmlType(metaType); |
600 | const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(qmlType: type); |
601 | if (mo && type.canConstructValueType()) { |
602 | QVariant result; |
603 | if (fromString(mo, s, allocate: [&]() { return createVariantData(type: metaType, variant: &result); })) |
604 | return result; |
605 | } |
606 | |
607 | return fromJSValue(type, s, metaType); |
608 | } |
609 | |
610 | QVariant QQmlValueTypeProvider::createValueType(const QV4::Value &s, QMetaType metaType) |
611 | { |
612 | if (!isConstructibleMetaType(metaType)) |
613 | return QVariant(); |
614 | const QQmlType type = QQmlMetaType::qmlType(metaType); |
615 | if (const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(qmlType: type)) { |
616 | const auto warn = [&]() { |
617 | qWarning().noquote() |
618 | << "Could not find any constructor for value type" |
619 | << mo->className() << "to call with value" << s.toQStringNoThrow(); |
620 | }; |
621 | |
622 | if (type.canPopulateValueType()) { |
623 | QVariant result = byProperties(targetMetaObject: mo, metaType, source: s); |
624 | if (result.isValid()) |
625 | return result; |
626 | if (type.canConstructValueType()) { |
627 | if (fromMatchingType(targetMetaObject: mo, source: s, allocate: [&]() { return createVariantData(type: metaType, variant: &result); })) |
628 | return result; |
629 | warn(); |
630 | } |
631 | } else if (type.canConstructValueType()) { |
632 | QVariant result; |
633 | if (fromMatchingType(targetMetaObject: mo, source: s, allocate: [&]() { return createVariantData(type: metaType, variant: &result); })) |
634 | return result; |
635 | warn(); |
636 | } |
637 | } |
638 | |
639 | return fromJSValue(type, s: QJSValuePrivate::fromReturnedValue(d: s.asReturnedValue()), metaType); |
640 | |
641 | } |
642 | |
643 | /*! |
644 | * \internal |
645 | * This should only be called with either builtin types or wrapped QJSValues as source. |
646 | */ |
647 | QVariant QQmlValueTypeProvider::createValueType(const QVariant &s, QMetaType metaType) |
648 | { |
649 | if (!isConstructibleMetaType(metaType)) |
650 | return QVariant(); |
651 | const QQmlType type = QQmlMetaType::qmlType(metaType); |
652 | if (const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(qmlType: type)) { |
653 | const auto warn = [&]() { |
654 | qWarning().noquote() |
655 | << "Could not find any constructor for value type" |
656 | << mo->className() << "to call with value" << s; |
657 | }; |
658 | |
659 | if (type.canPopulateValueType()) { |
660 | QVariant result = byProperties(targetMetaObject: mo, targetMetaType: metaType, source: s); |
661 | if (result.isValid()) |
662 | return result; |
663 | if (type.canConstructValueType()) { |
664 | if (fromMatchingType(targetMetaObject: mo, source: s, allocate: [&]() { return createVariantData(type: metaType, variant: &result); })) |
665 | return result; |
666 | warn(); |
667 | } |
668 | } else if (type.canConstructValueType()) { |
669 | QVariant result; |
670 | if (fromMatchingType(targetMetaObject: mo, source: s, allocate: [&]() { return createVariantData(type: metaType, variant: &result); })) |
671 | return result; |
672 | warn(); |
673 | } |
674 | } |
675 | |
676 | return QVariant(); |
677 | } |
678 | |
679 | QQmlColorProvider::~QQmlColorProvider() {} |
680 | QVariant QQmlColorProvider::colorFromString(const QString &, bool *ok) { if (ok) *ok = false; return QVariant(); } |
681 | unsigned QQmlColorProvider::rgbaFromString(const QString &, bool *ok) { if (ok) *ok = false; return 0; } |
682 | QVariant QQmlColorProvider::fromRgbF(double, double, double, double) { return QVariant(); } |
683 | QVariant QQmlColorProvider::fromHslF(double, double, double, double) { return QVariant(); } |
684 | QVariant QQmlColorProvider::fromHsvF(double, double, double, double) { return QVariant(); } |
685 | QVariant QQmlColorProvider::lighter(const QVariant &, qreal) { return QVariant(); } |
686 | QVariant QQmlColorProvider::darker(const QVariant &, qreal) { return QVariant(); } |
687 | QVariant QQmlColorProvider::alpha(const QVariant &, qreal) |
688 | { |
689 | return QVariant(); |
690 | } |
691 | QVariant QQmlColorProvider::tint(const QVariant &, const QVariant &) { return QVariant(); } |
692 | |
693 | static QQmlColorProvider *colorProvider = nullptr; |
694 | |
695 | Q_QML_PRIVATE_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *newProvider) |
696 | { |
697 | QQmlColorProvider *old = colorProvider; |
698 | colorProvider = newProvider; |
699 | return old; |
700 | } |
701 | |
702 | static QQmlColorProvider **getColorProvider(void) |
703 | { |
704 | if (colorProvider == nullptr) { |
705 | qWarning() << "Warning: QQml_colorProvider: no color provider has been set!" ; |
706 | static QQmlColorProvider nullColorProvider; |
707 | colorProvider = &nullColorProvider; |
708 | } |
709 | |
710 | return &colorProvider; |
711 | } |
712 | |
713 | Q_AUTOTEST_EXPORT QQmlColorProvider *QQml_colorProvider(void) |
714 | { |
715 | static QQmlColorProvider **providerPtr = getColorProvider(); |
716 | return *providerPtr; |
717 | } |
718 | |
719 | |
720 | QQmlGuiProvider::~QQmlGuiProvider() {} |
721 | QQmlApplication *QQmlGuiProvider::application(QObject *parent) |
722 | { |
723 | return new QQmlApplication(parent); |
724 | } |
725 | QStringList QQmlGuiProvider::fontFamilies() { return QStringList(); } |
726 | bool QQmlGuiProvider::openUrlExternally(const QUrl &) { return false; } |
727 | |
728 | QObject *QQmlGuiProvider::inputMethod() |
729 | { |
730 | // We don't have any input method code by default |
731 | QObject *o = new QObject(); |
732 | o->setObjectName(QStringLiteral("No inputMethod available" )); |
733 | QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership); |
734 | return o; |
735 | } |
736 | |
737 | QObject *QQmlGuiProvider::styleHints() |
738 | { |
739 | QObject *o = new QObject(); |
740 | o->setObjectName(QStringLiteral("No styleHints available" )); |
741 | QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership); |
742 | return o; |
743 | } |
744 | |
745 | QString QQmlGuiProvider::pluginName() const { return QString(); } |
746 | |
747 | static QQmlGuiProvider *guiProvider = nullptr; |
748 | |
749 | Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider) |
750 | { |
751 | QQmlGuiProvider *old = guiProvider; |
752 | guiProvider = newProvider; |
753 | return old; |
754 | } |
755 | |
756 | static QQmlGuiProvider **getGuiProvider(void) |
757 | { |
758 | if (guiProvider == nullptr) { |
759 | static QQmlGuiProvider nullGuiProvider; //Still provides an application with no GUI support |
760 | guiProvider = &nullGuiProvider; |
761 | } |
762 | |
763 | return &guiProvider; |
764 | } |
765 | |
766 | Q_AUTOTEST_EXPORT QQmlGuiProvider *QQml_guiProvider(void) |
767 | { |
768 | static QQmlGuiProvider **providerPtr = getGuiProvider(); |
769 | return *providerPtr; |
770 | } |
771 | |
772 | //Docs in qqmlengine.cpp |
773 | QQmlApplication::QQmlApplication(QObject *parent) |
774 | : QObject(*(new QQmlApplicationPrivate),parent) |
775 | { |
776 | connect(sender: QCoreApplication::instance(), SIGNAL(aboutToQuit()), |
777 | receiver: this, SIGNAL(aboutToQuit())); |
778 | connect(sender: QCoreApplication::instance(), SIGNAL(applicationNameChanged()), |
779 | receiver: this, SIGNAL(nameChanged())); |
780 | connect(sender: QCoreApplication::instance(), SIGNAL(applicationVersionChanged()), |
781 | receiver: this, SIGNAL(versionChanged())); |
782 | connect(sender: QCoreApplication::instance(), SIGNAL(organizationNameChanged()), |
783 | receiver: this, SIGNAL(organizationChanged())); |
784 | connect(sender: QCoreApplication::instance(), SIGNAL(organizationDomainChanged()), |
785 | receiver: this, SIGNAL(domainChanged())); |
786 | } |
787 | |
788 | QQmlApplication::QQmlApplication(QQmlApplicationPrivate &dd, QObject *parent) |
789 | : QObject(dd, parent) |
790 | { |
791 | connect(sender: QCoreApplication::instance(), SIGNAL(aboutToQuit()), |
792 | receiver: this, SIGNAL(aboutToQuit())); |
793 | connect(sender: QCoreApplication::instance(), SIGNAL(applicationNameChanged()), |
794 | receiver: this, SIGNAL(nameChanged())); |
795 | connect(sender: QCoreApplication::instance(), SIGNAL(applicationVersionChanged()), |
796 | receiver: this, SIGNAL(versionChanged())); |
797 | connect(sender: QCoreApplication::instance(), SIGNAL(organizationNameChanged()), |
798 | receiver: this, SIGNAL(organizationChanged())); |
799 | connect(sender: QCoreApplication::instance(), SIGNAL(organizationDomainChanged()), |
800 | receiver: this, SIGNAL(domainChanged())); |
801 | } |
802 | |
803 | QStringList QQmlApplication::args() |
804 | { |
805 | Q_D(QQmlApplication); |
806 | if (!d->argsInit) { |
807 | d->argsInit = true; |
808 | d->args = QCoreApplication::arguments(); |
809 | } |
810 | return d->args; |
811 | } |
812 | |
813 | QString QQmlApplication::name() const |
814 | { |
815 | return QCoreApplication::instance()->applicationName(); |
816 | } |
817 | |
818 | QString QQmlApplication::version() const |
819 | { |
820 | return QCoreApplication::instance()->applicationVersion(); |
821 | } |
822 | |
823 | QString QQmlApplication::organization() const |
824 | { |
825 | return QCoreApplication::instance()->organizationName(); |
826 | } |
827 | |
828 | QString QQmlApplication::domain() const |
829 | { |
830 | return QCoreApplication::instance()->organizationDomain(); |
831 | } |
832 | |
833 | void QQmlApplication::setName(const QString &arg) |
834 | { |
835 | QCoreApplication::instance()->setApplicationName(arg); |
836 | } |
837 | |
838 | void QQmlApplication::setVersion(const QString &arg) |
839 | { |
840 | QCoreApplication::instance()->setApplicationVersion(arg); |
841 | } |
842 | |
843 | void QQmlApplication::setOrganization(const QString &arg) |
844 | { |
845 | QCoreApplication::instance()->setOrganizationName(arg); |
846 | } |
847 | |
848 | void QQmlApplication::setDomain(const QString &arg) |
849 | { |
850 | QCoreApplication::instance()->setOrganizationDomain(arg); |
851 | } |
852 | |
853 | bool qmlobject_can_cast(QObject *object, const QMetaObject *mo) |
854 | { |
855 | Q_ASSERT(object); |
856 | Q_ASSERT(mo); |
857 | auto ddata = QQmlData::get(object, create: false); |
858 | if (!ddata || ! ddata->propertyCache) |
859 | return object->metaObject()->inherits(metaObject: mo); |
860 | return ddata->propertyCache->firstCppMetaObject()->inherits(metaObject: mo); |
861 | } |
862 | |
863 | QT_END_NAMESPACE |
864 | |
865 | #include "moc_qqmlglobal_p.cpp" |
866 | |