1 | // Copyright (C) 2019 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 "qqmltype_p_p.h" |
5 | |
6 | #include <QtQml/qjsvalue.h> |
7 | #include <QtQml/qqmlengine.h> |
8 | #include <QtQml/qqmlcontext.h> |
9 | #include <QtQml/qqmlcomponent.h> |
10 | |
11 | #include <private/qqmlcustomparser_p.h> |
12 | #include <private/qqmldata_p.h> |
13 | #include <private/qqmlmetatypedata_p.h> |
14 | #include <private/qqmlpropertycache_p.h> |
15 | #include <private/qqmltypedata_p.h> |
16 | |
17 | QT_BEGIN_NAMESPACE |
18 | |
19 | QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) |
20 | : regType(type), iid(nullptr), revision(QTypeRevision::zero()), |
21 | containsRevisionedAttributes(false), baseMetaObject(nullptr), |
22 | index(-1), isSetup(false), isEnumFromCacheSetup(false), isEnumFromBaseSetup(false), |
23 | haveSuperType(false) |
24 | { |
25 | switch (type) { |
26 | case QQmlType::CppType: |
27 | extraData.cd = new QQmlCppTypeData; |
28 | extraData.cd->allocationSize = 0; |
29 | extraData.cd->newFunc = nullptr; |
30 | extraData.cd->createValueTypeFunc = nullptr; |
31 | extraData.cd->parserStatusCast = -1; |
32 | extraData.cd->extFunc = nullptr; |
33 | extraData.cd->extMetaObject = nullptr; |
34 | extraData.cd->customParser = nullptr; |
35 | extraData.cd->attachedPropertiesFunc = nullptr; |
36 | extraData.cd->attachedPropertiesType = nullptr; |
37 | extraData.cd->propertyValueSourceCast = -1; |
38 | extraData.cd->propertyValueInterceptorCast = -1; |
39 | extraData.cd->finalizerCast = -1; |
40 | extraData.cd->registerEnumClassesUnscoped = true; |
41 | extraData.cd->registerEnumsFromRelatedTypes = true; |
42 | break; |
43 | case QQmlType::SingletonType: |
44 | case QQmlType::CompositeSingletonType: |
45 | extraData.sd = new QQmlSingletonTypeData; |
46 | extraData.sd->singletonInstanceInfo = nullptr; |
47 | extraData.sd->extFunc = nullptr; |
48 | extraData.sd->extMetaObject = nullptr; |
49 | break; |
50 | case QQmlType::InterfaceType: |
51 | extraData.cd = nullptr; |
52 | break; |
53 | case QQmlType::CompositeType: |
54 | extraData.fd = new QQmlCompositeTypeData; |
55 | break; |
56 | case QQmlType::InlineComponentType: |
57 | extraData.id = new QQmlInlineTypeData; |
58 | break; |
59 | case QQmlType::SequentialContainerType: |
60 | extraData.ld = new QQmlSequenceTypeData; |
61 | break; |
62 | default: qFatal(msg: "QQmlTypePrivate Internal Error." ); |
63 | } |
64 | } |
65 | |
66 | QQmlTypePrivate::~QQmlTypePrivate() |
67 | { |
68 | qDeleteAll(c: scopedEnums); |
69 | for (const auto &metaObject : metaObjects) |
70 | free(ptr: metaObject.metaObject); |
71 | switch (regType) { |
72 | case QQmlType::CppType: |
73 | delete extraData.cd->customParser; |
74 | delete extraData.cd; |
75 | break; |
76 | case QQmlType::SingletonType: |
77 | case QQmlType::CompositeSingletonType: |
78 | delete extraData.sd->singletonInstanceInfo; |
79 | delete extraData.sd; |
80 | break; |
81 | case QQmlType::CompositeType: |
82 | delete extraData.fd; |
83 | break; |
84 | case QQmlType::InlineComponentType: |
85 | delete extraData.id; |
86 | break; |
87 | case QQmlType::SequentialContainerType: |
88 | delete extraData.ld; |
89 | break; |
90 | default: //Also InterfaceType, because it has no extra data |
91 | break; |
92 | } |
93 | } |
94 | |
95 | QQmlType::QQmlType() = default; |
96 | QQmlType::QQmlType(const QQmlType &) = default; |
97 | QQmlType::QQmlType(QQmlType &&) = default; |
98 | QQmlType &QQmlType::operator =(const QQmlType &other) = default; |
99 | QQmlType &QQmlType::operator =(QQmlType &&other) = default; |
100 | QQmlType::QQmlType(const QQmlTypePrivate *priv) : d(priv) {} |
101 | QQmlType::~QQmlType() = default; |
102 | |
103 | QHashedString QQmlType::module() const |
104 | { |
105 | if (!d) |
106 | return QHashedString(); |
107 | return d->module; |
108 | } |
109 | |
110 | QTypeRevision QQmlType::version() const |
111 | { |
112 | if (!d) |
113 | return QTypeRevision(); |
114 | return d->version; |
115 | } |
116 | |
117 | bool QQmlType::availableInVersion(QTypeRevision version) const |
118 | { |
119 | if (!d) |
120 | return false; |
121 | |
122 | if (!version.hasMajorVersion()) |
123 | return true; |
124 | |
125 | if (version.majorVersion() != d->version.majorVersion()) |
126 | return false; |
127 | |
128 | return !version.hasMinorVersion() || version.minorVersion() >= d->version.minorVersion(); |
129 | } |
130 | |
131 | bool QQmlType::availableInVersion(const QHashedStringRef &module, QTypeRevision version) const |
132 | { |
133 | if (!d || module != d->module) |
134 | return false; |
135 | |
136 | return availableInVersion(version); |
137 | } |
138 | |
139 | QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) const |
140 | { |
141 | Q_ASSERT(isComposite()); |
142 | if (!engine) |
143 | return QQmlType(); |
144 | QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(unNormalizedUrl: sourceUrl())); |
145 | if (td.isNull() || !td->isComplete()) |
146 | return QQmlType(); |
147 | QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit(); |
148 | const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); |
149 | return QQmlMetaType::qmlType(mo); |
150 | } |
151 | |
152 | QQmlPropertyCache::ConstPtr QQmlTypePrivate::compositePropertyCache( |
153 | QQmlEnginePrivate *engine) const |
154 | { |
155 | // similar logic to resolveCompositeBaseType |
156 | Q_ASSERT(isComposite()); |
157 | if (!engine) |
158 | return nullptr; |
159 | QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(unNormalizedUrl: sourceUrl())); |
160 | if (td.isNull() || !td->isComplete()) |
161 | return nullptr; |
162 | QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit(); |
163 | return compilationUnit->rootPropertyCache(); |
164 | } |
165 | |
166 | static bool isPropertyRevisioned(const QMetaObject *mo, int index) |
167 | { |
168 | return mo->property(index).revision(); |
169 | } |
170 | |
171 | void QQmlTypePrivate::init() const |
172 | { |
173 | if (isSetup.loadAcquire()) |
174 | return; |
175 | |
176 | QMutexLocker lock(QQmlMetaType::typeRegistrationLock()); |
177 | if (isSetup.loadAcquire()) |
178 | return; |
179 | |
180 | const QMetaObject *mo = baseMetaObject; |
181 | if (!mo) { |
182 | // version 0 singleton type without metaobject information |
183 | return; |
184 | } |
185 | |
186 | auto setupExtendedMetaObject = [&](const QMetaObject *extMetaObject, |
187 | QObject *(*extFunc)(QObject *)) { |
188 | if (!extMetaObject) |
189 | return; |
190 | |
191 | // XXX - very inefficient |
192 | QMetaObjectBuilder builder; |
193 | QQmlMetaType::clone(builder, mo: extMetaObject, ignoreStart: extMetaObject, ignoreEnd: extMetaObject, |
194 | policy: extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly); |
195 | QMetaObject *mmo = builder.toMetaObject(); |
196 | mmo->d.superdata = mo; |
197 | QQmlProxyMetaObject::ProxyData data = { .metaObject: mmo, .createFunc: extFunc, .propertyOffset: 0, .methodOffset: 0 }; |
198 | metaObjects << data; |
199 | QQmlMetaType::registerMetaObjectForType(metaobject: mmo, type: const_cast<QQmlTypePrivate *>(this)); |
200 | }; |
201 | |
202 | if (regType == QQmlType::SingletonType) |
203 | setupExtendedMetaObject(extraData.sd->extMetaObject, extraData.sd->extFunc); |
204 | else if (regType == QQmlType::CppType) |
205 | setupExtendedMetaObject(extraData.cd->extMetaObject, extraData.cd->extFunc); |
206 | |
207 | metaObjects.append(other: QQmlMetaType::proxyData( |
208 | mo, baseMetaObject, lastMetaObject: metaObjects.isEmpty() ? nullptr |
209 | : metaObjects.constLast().metaObject)); |
210 | |
211 | for (int ii = 0; ii < metaObjects.size(); ++ii) { |
212 | metaObjects[ii].propertyOffset = |
213 | metaObjects.at(i: ii).metaObject->propertyOffset(); |
214 | metaObjects[ii].methodOffset = |
215 | metaObjects.at(i: ii).metaObject->methodOffset(); |
216 | } |
217 | |
218 | // Check for revisioned details |
219 | { |
220 | const QMetaObject *mo = nullptr; |
221 | if (metaObjects.isEmpty()) |
222 | mo = baseMetaObject; |
223 | else |
224 | mo = metaObjects.constFirst().metaObject; |
225 | |
226 | for (int ii = 0; !containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) { |
227 | if (isPropertyRevisioned(mo, index: ii)) |
228 | containsRevisionedAttributes = true; |
229 | } |
230 | |
231 | for (int ii = 0; !containsRevisionedAttributes && ii < mo->methodCount(); ++ii) { |
232 | if (mo->method(index: ii).revision() != 0) |
233 | containsRevisionedAttributes = true; |
234 | } |
235 | } |
236 | |
237 | isSetup.storeRelease(newValue: true); |
238 | lock.unlock(); |
239 | } |
240 | |
241 | void QQmlTypePrivate::initEnums(QQmlEnginePrivate *engine) const |
242 | { |
243 | QQmlPropertyCache::ConstPtr cache = (!isEnumFromCacheSetup.loadAcquire() && isComposite()) |
244 | ? compositePropertyCache(engine) |
245 | : QQmlPropertyCache::ConstPtr(); |
246 | |
247 | // beware: It could be a singleton type without metaobject |
248 | const QMetaObject *metaObject = !isEnumFromBaseSetup.loadAcquire() |
249 | ? baseMetaObject |
250 | : nullptr; |
251 | |
252 | if (!cache && !metaObject) |
253 | return; |
254 | |
255 | init(); // init() can add to the metaObjects list. Therefore, check metaObjects only below |
256 | |
257 | QMutexLocker lock(QQmlMetaType::typeRegistrationLock()); |
258 | |
259 | if (cache) { |
260 | insertEnumsFromPropertyCache(cache); |
261 | isEnumFromCacheSetup.storeRelease(newValue: true); |
262 | } |
263 | |
264 | if (metaObject) { |
265 | insertEnums(metaObject: metaObjects.isEmpty() ? baseMetaObject : metaObjects.constFirst().metaObject); |
266 | isEnumFromBaseSetup.storeRelease(newValue: true); |
267 | } |
268 | } |
269 | |
270 | void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const |
271 | { |
272 | // Add any enum values defined by 'related' classes |
273 | if (regType != QQmlType::CppType || extraData.cd->registerEnumsFromRelatedTypes) { |
274 | if (const auto *related = metaObject->d.relatedMetaObjects) { |
275 | while (const QMetaObject *relatedMetaObject = *related) { |
276 | insertEnums(metaObject: relatedMetaObject); |
277 | ++related; |
278 | } |
279 | } |
280 | } |
281 | |
282 | QSet<QString> localEnums; |
283 | const QMetaObject *localMetaObject = nullptr; |
284 | |
285 | // Add any enum values defined by this class, overwriting any inherited values |
286 | for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) { |
287 | QMetaEnum e = metaObject->enumerator(index: ii); |
288 | const bool isScoped = e.isScoped(); |
289 | QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : nullptr; |
290 | |
291 | // We allow enums in sub-classes to overwrite enums from base-classes, such as |
292 | // ListView.Center (from enum PositionMode) overwriting Item.Center (from enum TransformOrigin). |
293 | // This is acceptable because the _use_ of the enum from the QML side requires qualification |
294 | // anyway, i.e. ListView.Center vs. Item.Center. |
295 | // However if a class defines two enums with the same value, then that must produce a warning |
296 | // because it represents a valid conflict. |
297 | if (e.enclosingMetaObject() != localMetaObject) { |
298 | localEnums.clear(); |
299 | localMetaObject = e.enclosingMetaObject(); |
300 | } |
301 | |
302 | for (int jj = 0; jj < e.keyCount(); ++jj) { |
303 | const QString key = QString::fromUtf8(utf8: e.key(index: jj)); |
304 | const int value = e.value(index: jj); |
305 | if (!isScoped || (regType == QQmlType::CppType && extraData.cd->registerEnumClassesUnscoped)) { |
306 | if (localEnums.contains(value: key)) { |
307 | auto existingEntry = enums.find(key); |
308 | if (existingEntry != enums.end() && existingEntry.value() != value) { |
309 | qWarning(msg: "Previously registered enum will be overwritten due to name clash: %s.%s" , metaObject->className(), key.toUtf8().constData()); |
310 | createEnumConflictReport(metaObject, conflictingKey: key); |
311 | } |
312 | } else { |
313 | localEnums.insert(value: key); |
314 | } |
315 | enums.insert(key, value); |
316 | } |
317 | if (isScoped) |
318 | scoped->insert(key, value); |
319 | } |
320 | |
321 | if (isScoped) { |
322 | scopedEnums << scoped; |
323 | scopedEnumIndex.insert(key: QString::fromUtf8(utf8: e.name()), value: scopedEnums.size()-1); |
324 | } |
325 | } |
326 | } |
327 | |
328 | void QQmlTypePrivate::createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const |
329 | { |
330 | path.append(t: QString::fromUtf8(utf8: metaObject->className())); |
331 | |
332 | if (metaObject->d.relatedMetaObjects) { |
333 | const auto *related = metaObject->d.relatedMetaObjects; |
334 | if (related) { |
335 | while (*related) |
336 | createListOfPossibleConflictingItems(metaObject: *related++, enumInfoList, path); |
337 | } |
338 | } |
339 | |
340 | for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) { |
341 | const auto e = metaObject->enumerator(index: ii); |
342 | |
343 | for (int jj = 0; jj < e.keyCount(); ++jj) { |
344 | const QString key = QString::fromUtf8(utf8: e.key(index: jj)); |
345 | |
346 | EnumInfo enumInfo; |
347 | enumInfo.metaObjectName = QString::fromUtf8(utf8: metaObject->className()); |
348 | enumInfo.enumName = QString::fromUtf8(utf8: e.name()); |
349 | enumInfo.enumKey = key; |
350 | enumInfo.scoped = e.isScoped(); |
351 | enumInfo.path = path; |
352 | enumInfo.metaEnumScope = QString::fromUtf8(utf8: e.scope()); |
353 | enumInfoList.append(t: enumInfo); |
354 | } |
355 | } |
356 | } |
357 | |
358 | void QQmlTypePrivate::createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const |
359 | { |
360 | QList<EnumInfo> enumInfoList; |
361 | |
362 | if (baseMetaObject) // prefer baseMetaObject if available |
363 | metaObject = baseMetaObject; |
364 | |
365 | if (!metaObject) { // If there is no metaObject at all return early |
366 | qWarning() << "No meta object information available. Skipping conflict analysis." ; |
367 | return; |
368 | } |
369 | |
370 | createListOfPossibleConflictingItems(metaObject, enumInfoList, path: QStringList()); |
371 | |
372 | qWarning().noquote() << QLatin1String("Possible conflicting items:" ); |
373 | // find items with conflicting key |
374 | for (const auto &i : std::as_const(t&: enumInfoList)) { |
375 | if (i.enumKey == conflictingKey) |
376 | qWarning().noquote().nospace() << " " << i.metaObjectName << "." << i.enumName << "." << i.enumKey << " from scope " |
377 | << i.metaEnumScope << " injected by " << i.path.join(sep: QLatin1String("->" )); |
378 | } |
379 | } |
380 | |
381 | void QQmlTypePrivate::insertEnumsFromPropertyCache( |
382 | const QQmlPropertyCache::ConstPtr &cache) const |
383 | { |
384 | const QMetaObject *cppMetaObject = cache->firstCppMetaObject(); |
385 | |
386 | for (const QQmlPropertyCache *currentCache = cache.data(); |
387 | currentCache && currentCache->metaObject() != cppMetaObject; |
388 | currentCache = currentCache->parent().data()) { |
389 | |
390 | int count = currentCache->qmlEnumCount(); |
391 | for (int ii = 0; ii < count; ++ii) { |
392 | QStringHash<int> *scoped = new QStringHash<int>(); |
393 | QQmlEnumData *enumData = currentCache->qmlEnum(index: ii); |
394 | |
395 | for (int jj = 0; jj < enumData->values.size(); ++jj) { |
396 | const QQmlEnumValue &value = enumData->values.at(i: jj); |
397 | enums.insert(key: value.namedValue, value: value.value); |
398 | scoped->insert(key: value.namedValue, value: value.value); |
399 | } |
400 | scopedEnums << scoped; |
401 | scopedEnumIndex.insert(key: enumData->name, value: scopedEnums.size()-1); |
402 | } |
403 | } |
404 | insertEnums(metaObject: cppMetaObject); |
405 | } |
406 | |
407 | void QQmlTypePrivate::setContainingType(QQmlType *containingType) |
408 | { |
409 | Q_ASSERT(regType == QQmlType::InlineComponentType); |
410 | extraData.id->containingType = containingType->d.data(); |
411 | } |
412 | |
413 | void QQmlTypePrivate::setName(const QString &uri, const QString &element) |
414 | { |
415 | module = uri; |
416 | elementName = element; |
417 | name = uri.isEmpty() ? element : (uri + QLatin1Char('/') + element); |
418 | } |
419 | |
420 | QByteArray QQmlType::typeName() const |
421 | { |
422 | if (d) { |
423 | if (d->regType == SingletonType || d->regType == CompositeSingletonType) |
424 | return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8(); |
425 | else if (d->baseMetaObject) |
426 | return d->baseMetaObject->className(); |
427 | } |
428 | return QByteArray(); |
429 | } |
430 | |
431 | QString QQmlType::elementName() const |
432 | { |
433 | if (!d) |
434 | return QString(); |
435 | return d->elementName; |
436 | } |
437 | |
438 | QString QQmlType::qmlTypeName() const |
439 | { |
440 | if (!d) |
441 | return QString(); |
442 | return d->name; |
443 | } |
444 | |
445 | /*! |
446 | \internal |
447 | Allocates and initializes an object if the type is creatable. |
448 | Returns a pointer to the object, or nullptr if the type was |
449 | not creatable. |
450 | */ |
451 | QObject *QQmlType::create() const |
452 | { |
453 | void *unused; |
454 | return create(&unused, 0); |
455 | } |
456 | |
457 | /*! |
458 | \internal |
459 | \brief Like create without arguments, but allocates some extra space after the object. |
460 | \param memory An out-only argument. *memory will point to the start of the additionally |
461 | allocated memory. |
462 | \param additionalMemory The amount of extra memory in bytes that shoudld be allocated. |
463 | |
464 | \note This function is used to allocate the QQmlData next to the object in the |
465 | QQmlObjectCreator. |
466 | |
467 | \overload |
468 | */ |
469 | QObject *QQmlType::create(void **memory, size_t additionalMemory) const |
470 | { |
471 | if (!d || !isCreatable()) |
472 | return nullptr; |
473 | |
474 | d->init(); |
475 | |
476 | QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize + additionalMemory); |
477 | d->extraData.cd->newFunc(rv, d->extraData.cd->userdata); |
478 | |
479 | createProxy(instance: rv); |
480 | *memory = ((char *)rv) + d->extraData.cd->allocationSize; |
481 | return rv; |
482 | } |
483 | |
484 | /*! |
485 | \internal |
486 | Like create, but also allocates memory behind the object, constructs a QQmlData there |
487 | and lets the objects declarativeData point to the newly created QQmlData. |
488 | */ |
489 | QObject *QQmlType::createWithQQmlData() const |
490 | { |
491 | void *ddataMemory = nullptr; |
492 | auto instance = create(memory: &ddataMemory, additionalMemory: sizeof(QQmlData)); |
493 | if (!instance) |
494 | return nullptr; |
495 | QObjectPrivate* p = QObjectPrivate::get(o: instance); |
496 | Q_ASSERT(!p->isDeletingChildren); |
497 | if (!p->declarativeData) |
498 | p->declarativeData = new (ddataMemory) QQmlData(QQmlData::DoesNotOwnMemory); |
499 | return instance; |
500 | } |
501 | |
502 | QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const |
503 | { |
504 | if (!d) |
505 | return nullptr; |
506 | if (d->regType != SingletonType && d->regType != CompositeSingletonType) |
507 | return nullptr; |
508 | return d->extraData.sd->singletonInstanceInfo; |
509 | } |
510 | |
511 | QQmlCustomParser *QQmlType::customParser() const |
512 | { |
513 | if (!d) |
514 | return nullptr; |
515 | if (d->regType != CppType) |
516 | return nullptr; |
517 | return d->extraData.cd->customParser; |
518 | } |
519 | |
520 | QQmlType::CreateValueTypeFunc QQmlType::createValueTypeFunction() const |
521 | { |
522 | if (!d || d->regType != CppType) |
523 | return nullptr; |
524 | return d->extraData.cd->createValueTypeFunc; |
525 | } |
526 | |
527 | bool QQmlType::canConstructValueType() const |
528 | { |
529 | if (!d || d->regType != CppType) |
530 | return false; |
531 | return d->extraData.cd->constructValueType; |
532 | } |
533 | |
534 | bool QQmlType::canPopulateValueType() const |
535 | { |
536 | if (!d || d->regType != CppType) |
537 | return false; |
538 | return d->extraData.cd->populateValueType; |
539 | } |
540 | |
541 | QQmlType::CreateFunc QQmlType::createFunction() const |
542 | { |
543 | if (!d || d->regType != CppType) |
544 | return nullptr; |
545 | return d->extraData.cd->newFunc; |
546 | } |
547 | |
548 | QString QQmlType::noCreationReason() const |
549 | { |
550 | if (!d || d->regType != CppType) |
551 | return QString(); |
552 | return d->extraData.cd->noCreationReason; |
553 | } |
554 | |
555 | bool QQmlType::isCreatable() const |
556 | { |
557 | return d && d->regType == CppType && d->extraData.cd->newFunc; |
558 | } |
559 | |
560 | QQmlType::ExtensionFunc QQmlType::extensionFunction() const |
561 | { |
562 | if (!d) |
563 | return nullptr; |
564 | |
565 | switch (d->regType) { |
566 | case CppType: |
567 | return d->extraData.cd->extFunc; |
568 | case SingletonType: |
569 | return d->extraData.sd->extFunc; |
570 | default: |
571 | return nullptr; |
572 | } |
573 | } |
574 | |
575 | const QMetaObject *QQmlType::extensionMetaObject() const |
576 | { |
577 | if (!d) |
578 | return nullptr; |
579 | |
580 | switch (d->regType) { |
581 | case CppType: |
582 | return d->extraData.cd->extMetaObject; |
583 | case SingletonType: |
584 | return d->extraData.sd->extMetaObject; |
585 | default: |
586 | return nullptr; |
587 | } |
588 | } |
589 | |
590 | bool QQmlType::isExtendedType() const |
591 | { |
592 | if (!d) |
593 | return false; |
594 | d->init(); |
595 | |
596 | return !d->metaObjects.isEmpty(); |
597 | } |
598 | |
599 | bool QQmlType::isSingleton() const |
600 | { |
601 | return d && (d->regType == SingletonType || d->regType == CompositeSingletonType); |
602 | } |
603 | |
604 | bool QQmlType::isInterface() const |
605 | { |
606 | return d && d->regType == InterfaceType; |
607 | } |
608 | |
609 | bool QQmlType::isComposite() const |
610 | { |
611 | return d && d->isComposite(); |
612 | } |
613 | |
614 | bool QQmlType::isCompositeSingleton() const |
615 | { |
616 | // if the outer type is a composite singleton, d->regType will indicate that even for |
617 | // the inline component type |
618 | // however, inline components can -at least for now- never be singletons |
619 | // so we just do one additional check |
620 | return d && d->regType == CompositeSingletonType && !isInlineComponentType(); |
621 | } |
622 | |
623 | bool QQmlType::isQObjectSingleton() const |
624 | { |
625 | return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback; |
626 | } |
627 | |
628 | bool QQmlType::isQJSValueSingleton() const |
629 | { |
630 | return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback; |
631 | } |
632 | |
633 | bool QQmlType::isSequentialContainer() const |
634 | { |
635 | return d && d->regType == SequentialContainerType; |
636 | } |
637 | |
638 | QMetaType QQmlType::typeId() const |
639 | { |
640 | return d ? d->typeId : QMetaType{}; |
641 | } |
642 | |
643 | QMetaType QQmlType::qListTypeId() const |
644 | { |
645 | return d ? d->listId : QMetaType{}; |
646 | } |
647 | |
648 | QMetaSequence QQmlType::listMetaSequence() const |
649 | { |
650 | return isSequentialContainer() ? *d->extraData.ld : QMetaSequence(); |
651 | } |
652 | |
653 | const QMetaObject *QQmlType::metaObject() const |
654 | { |
655 | if (!d) |
656 | return nullptr; |
657 | d->init(); |
658 | |
659 | if (d->metaObjects.isEmpty()) |
660 | return d->baseMetaObject; |
661 | else |
662 | return d->metaObjects.constFirst().metaObject; |
663 | |
664 | } |
665 | |
666 | const QMetaObject *QQmlType::baseMetaObject() const |
667 | { |
668 | return d ? d->baseMetaObject : nullptr; |
669 | } |
670 | |
671 | bool QQmlType::containsRevisionedAttributes() const |
672 | { |
673 | if (!d) |
674 | return false; |
675 | d->init(); |
676 | |
677 | return d->containsRevisionedAttributes; |
678 | } |
679 | |
680 | QTypeRevision QQmlType::metaObjectRevision() const |
681 | { |
682 | return d ? d->revision : QTypeRevision(); |
683 | } |
684 | |
685 | QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const |
686 | { |
687 | if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr) |
688 | return base->extraData.cd->attachedPropertiesFunc; |
689 | return nullptr; |
690 | } |
691 | |
692 | const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const |
693 | { |
694 | if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr) |
695 | return base->extraData.cd->attachedPropertiesType; |
696 | return nullptr; |
697 | } |
698 | |
699 | int QQmlType::parserStatusCast() const |
700 | { |
701 | if (!d || d->regType != CppType) |
702 | return -1; |
703 | return d->extraData.cd->parserStatusCast; |
704 | } |
705 | |
706 | int QQmlType::propertyValueSourceCast() const |
707 | { |
708 | if (!d || d->regType != CppType) |
709 | return -1; |
710 | return d->extraData.cd->propertyValueSourceCast; |
711 | } |
712 | |
713 | int QQmlType::propertyValueInterceptorCast() const |
714 | { |
715 | if (!d || d->regType != CppType) |
716 | return -1; |
717 | return d->extraData.cd->propertyValueInterceptorCast; |
718 | } |
719 | |
720 | int QQmlType::finalizerCast() const |
721 | { |
722 | if (!d || d->regType != CppType) |
723 | return -1; |
724 | return d->extraData.cd->finalizerCast; |
725 | } |
726 | |
727 | const char *QQmlType::interfaceIId() const |
728 | { |
729 | if (!d || d->regType != InterfaceType) |
730 | return nullptr; |
731 | return d->iid; |
732 | } |
733 | |
734 | int QQmlType::index() const |
735 | { |
736 | return d ? d->index : -1; |
737 | } |
738 | |
739 | bool QQmlType::isInlineComponentType() const { |
740 | return d ? d->regType == QQmlType::InlineComponentType : false; |
741 | } |
742 | |
743 | QUrl QQmlType::sourceUrl() const |
744 | { |
745 | return d ? d->sourceUrl() : QUrl(); |
746 | } |
747 | |
748 | int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const |
749 | { |
750 | Q_ASSERT(ok); |
751 | if (d) { |
752 | *ok = true; |
753 | |
754 | d->initEnums(engine); |
755 | |
756 | int *rv = d->enums.value(key: name); |
757 | if (rv) |
758 | return *rv; |
759 | } |
760 | |
761 | *ok = false; |
762 | return -1; |
763 | } |
764 | |
765 | int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const |
766 | { |
767 | Q_ASSERT(ok); |
768 | if (d) { |
769 | *ok = true; |
770 | |
771 | d->initEnums(engine); |
772 | |
773 | int *rv = d->enums.value(key: name); |
774 | if (rv) |
775 | return *rv; |
776 | } |
777 | |
778 | *ok = false; |
779 | return -1; |
780 | } |
781 | |
782 | int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const |
783 | { |
784 | Q_ASSERT(ok); |
785 | if (d) { |
786 | *ok = true; |
787 | |
788 | d->initEnums(engine); |
789 | |
790 | int *rv = d->enums.value(string: name); |
791 | if (rv) |
792 | return *rv; |
793 | } |
794 | |
795 | *ok = false; |
796 | return -1; |
797 | } |
798 | |
799 | int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const |
800 | { |
801 | Q_ASSERT(ok); |
802 | if (d) { |
803 | *ok = true; |
804 | |
805 | d->initEnums(engine); |
806 | |
807 | int *rv = d->scopedEnumIndex.value(string: name); |
808 | if (rv) |
809 | return *rv; |
810 | } |
811 | |
812 | *ok = false; |
813 | return -1; |
814 | } |
815 | |
816 | int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const |
817 | { |
818 | Q_ASSERT(ok); |
819 | if (d) { |
820 | *ok = true; |
821 | |
822 | d->initEnums(engine); |
823 | |
824 | int *rv = d->scopedEnumIndex.value(key: name); |
825 | if (rv) |
826 | return *rv; |
827 | } |
828 | |
829 | *ok = false; |
830 | return -1; |
831 | } |
832 | |
833 | int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const |
834 | { |
835 | Q_UNUSED(engine); |
836 | Q_ASSERT(ok); |
837 | *ok = true; |
838 | |
839 | if (d) { |
840 | Q_ASSERT(index > -1 && index < d->scopedEnums.size()); |
841 | int *rv = d->scopedEnums.at(i: index)->value(string: name); |
842 | if (rv) |
843 | return *rv; |
844 | } |
845 | |
846 | *ok = false; |
847 | return -1; |
848 | } |
849 | |
850 | int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const |
851 | { |
852 | Q_UNUSED(engine); |
853 | Q_ASSERT(ok); |
854 | *ok = true; |
855 | |
856 | if (d) { |
857 | Q_ASSERT(index > -1 && index < d->scopedEnums.size()); |
858 | int *rv = d->scopedEnums.at(i: index)->value(key: name); |
859 | if (rv) |
860 | return *rv; |
861 | } |
862 | |
863 | *ok = false; |
864 | return -1; |
865 | } |
866 | |
867 | int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const |
868 | { |
869 | Q_ASSERT(ok); |
870 | if (d) { |
871 | *ok = true; |
872 | |
873 | d->initEnums(engine); |
874 | |
875 | int *rv = d->scopedEnumIndex.value(key: QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.size())); |
876 | if (rv) { |
877 | int index = *rv; |
878 | Q_ASSERT(index > -1 && index < d->scopedEnums.size()); |
879 | rv = d->scopedEnums.at(i: index)->value(key: QHashedCStringRef(name.constData(), name.size())); |
880 | if (rv) |
881 | return *rv; |
882 | } |
883 | } |
884 | |
885 | *ok = false; |
886 | return -1; |
887 | } |
888 | |
889 | int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, QStringView scopedEnumName, QStringView name, bool *ok) const |
890 | { |
891 | Q_ASSERT(ok); |
892 | if (d) { |
893 | *ok = true; |
894 | |
895 | d->initEnums(engine); |
896 | |
897 | int *rv = d->scopedEnumIndex.value(key: QHashedStringRef(scopedEnumName)); |
898 | if (rv) { |
899 | int index = *rv; |
900 | Q_ASSERT(index > -1 && index < d->scopedEnums.size()); |
901 | rv = d->scopedEnums.at(i: index)->value(key: QHashedStringRef(name)); |
902 | if (rv) |
903 | return *rv; |
904 | } |
905 | } |
906 | |
907 | *ok = false; |
908 | return -1; |
909 | } |
910 | |
911 | void QQmlType::refHandle(const QQmlTypePrivate *priv) |
912 | { |
913 | if (priv) |
914 | priv->addref(); |
915 | } |
916 | |
917 | void QQmlType::derefHandle(const QQmlTypePrivate *priv) |
918 | { |
919 | if (priv) |
920 | priv->release(); |
921 | } |
922 | |
923 | int QQmlType::refCount(const QQmlTypePrivate *priv) |
924 | { |
925 | if (priv) |
926 | return priv->count(); |
927 | return -1; |
928 | } |
929 | |
930 | QQmlType QQmlType::containingType() const |
931 | { |
932 | Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType); |
933 | auto ret = QQmlType {d->extraData.id->containingType}; |
934 | Q_ASSERT(!ret.isInlineComponentType()); |
935 | return ret; |
936 | } |
937 | |
938 | void QQmlType::createProxy(QObject *instance) const |
939 | { |
940 | if (!d->metaObjects.isEmpty()) |
941 | (void)new QQmlProxyMetaObject(instance, &d->metaObjects); |
942 | } |
943 | |
944 | QT_END_NAMESPACE |
945 | |