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

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