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
53 QT_BEGIN_NAMESPACE
54
QQmlTypePrivate(QQmlType::RegistrationType type)55 QQmlTypePrivate::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("QQmlTypePrivate Internal Error.");
91 }
92 }
93
~QQmlTypePrivate()94 QQmlTypePrivate::~QQmlTypePrivate()
95 {
96 qDeleteAll(scopedEnums);
97 for (const auto &metaObject : metaObjects)
98 free(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
120 QQmlType::QQmlType() = default;
121 QQmlType::QQmlType(const QQmlType &) = default;
122 QQmlType::QQmlType(QQmlType &&) = default;
123 QQmlType &QQmlType::operator =(const QQmlType &other) = default;
124 QQmlType &QQmlType::operator =(QQmlType &&other) = default;
QQmlType(const QQmlTypePrivate * priv)125 QQmlType::QQmlType(const QQmlTypePrivate *priv) : d(priv) {}
126 QQmlType::~QQmlType() = default;
127
module() const128 QHashedString QQmlType::module() const
129 {
130 if (!d)
131 return QHashedString();
132 return d->module;
133 }
134
majorVersion() const135 int QQmlType::majorVersion() const
136 {
137 if (!d)
138 return -1;
139 return d->version_maj;
140 }
141
minorVersion() const142 int QQmlType::minorVersion() const
143 {
144 if (!d)
145 return -1;
146 return d->version_min;
147 }
148
availableInVersion(int vmajor,int vminor) const149 bool 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
availableInVersion(const QHashedStringRef & module,int vmajor,int vminor) const157 bool 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
resolveCompositeBaseType(QQmlEnginePrivate * engine) const165 QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
166 {
167 Q_ASSERT(isComposite());
168 if (!engine)
169 return QQmlType();
170 QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(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
compositePropertyCache(QQmlEnginePrivate * engine) const178 QQmlPropertyCache *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(sourceUrl()));
185 if (td.isNull() || !td->isComplete())
186 return nullptr;
187 QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit();
188 return compilationUnit->rootPropertyCache().data();
189 }
190
isPropertyRevisioned(const QMetaObject * mo,int index)191 static 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->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
init() const209 void 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, extraData.cd->extMetaObject, extraData.cd->extMetaObject,
230 extraData.cd->extMetaObject);
231 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
232 QMetaObject *mmo = builder.toMetaObject();
233 mmo->d.superdata = mo;
234 QQmlProxyMetaObject::ProxyData data = { mmo, extraData.cd->extFunc, 0, 0 };
235 metaObjects << data;
236 }
237 }
238
239 metaObjects.append(QQmlMetaType::proxyData(
240 mo, baseMetaObject, metaObjects.isEmpty() ? nullptr
241 : metaObjects.constLast().metaObject));
242
243 for (int ii = 0; ii < metaObjects.count(); ++ii) {
244 metaObjects[ii].propertyOffset =
245 metaObjects.at(ii).metaObject->propertyOffset();
246 metaObjects[ii].methodOffset =
247 metaObjects.at(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, ii))
260 containsRevisionedAttributes = true;
261 }
262
263 for (int ii = 0; !containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
264 if (mo->method(ii).revision() != 0)
265 containsRevisionedAttributes = true;
266 }
267 }
268
269 isSetup = true;
270 lock.unlock();
271 }
272
initEnums(QQmlEnginePrivate * engine) const273 void 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
insertEnums(const QMetaObject * metaObject) const301 void 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(*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(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(e.key(jj));
334 const int value = e.value(jj);
335 if (!isScoped || (regType == QQmlType::CppType && extraData.cd->registerEnumClassesUnscoped)) {
336 if (localEnums.contains(key)) {
337 auto existingEntry = enums.find(key);
338 if (existingEntry != enums.end() && existingEntry.value() != value) {
339 qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData());
340 createEnumConflictReport(metaObject, key);
341 }
342 } else {
343 localEnums.insert(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(QString::fromUtf8(e.name()), scopedEnums.count()-1);
354 }
355 }
356 }
357
createListOfPossibleConflictingItems(const QMetaObject * metaObject,QList<EnumInfo> & enumInfoList,QStringList path) const358 void QQmlTypePrivate::createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const
359 {
360 path.append(QString::fromUtf8(metaObject->className()));
361
362 if (metaObject->d.relatedMetaObjects) {
363 const auto *related = metaObject->d.relatedMetaObjects;
364 if (related) {
365 while (*related)
366 createListOfPossibleConflictingItems(*related++, enumInfoList, path);
367 }
368 }
369
370 for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
371 const auto e = metaObject->enumerator(ii);
372
373 for (int jj = 0; jj < e.keyCount(); ++jj) {
374 const QString key = QString::fromUtf8(e.key(jj));
375
376 EnumInfo enumInfo;
377 enumInfo.metaObjectName = QString::fromUtf8(metaObject->className());
378 enumInfo.enumName = QString::fromUtf8(e.name());
379 enumInfo.enumKey = key;
380 enumInfo.scoped = e.isScoped();
381 enumInfo.path = path;
382 enumInfo.metaEnumScope = QString::fromUtf8(e.scope());
383 enumInfoList.append(enumInfo);
384 }
385 }
386 }
387
createEnumConflictReport(const QMetaObject * metaObject,const QString & conflictingKey) const388 void 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, QStringList());
401
402 qWarning().noquote() << QLatin1String("Possible conflicting items:");
403 // find items with conflicting key
404 for (const auto &i : qAsConst(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(QLatin1String("->"));
408 }
409 }
410
insertEnumsFromPropertyCache(const QQmlPropertyCache * cache) const411 void 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(ii);
421
422 for (int jj = 0; jj < enumData->values.count(); ++jj) {
423 const QQmlEnumValue &value = enumData->values.at(jj);
424 enums.insert(value.namedValue, value.value);
425 scoped->insert(value.namedValue, value.value);
426 }
427 scopedEnums << scoped;
428 scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1);
429 }
430 cache = cache->parent();
431 }
432 insertEnums(cppMetaObject);
433 }
434
setContainingType(QQmlType * containingType)435 void QQmlTypePrivate::setContainingType(QQmlType *containingType)
436 {
437 Q_ASSERT(regType == QQmlType::InlineComponentType);
438 extraData.id->containingType = containingType->d.data();
439 }
440
setName(const QString & uri,const QString & element)441 void 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
typeName() const448 QByteArray 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
elementName() const461 QString QQmlType::elementName() const
462 {
463 if (!d)
464 return QString();
465 return d->elementName;
466 }
467
qmlTypeName() const468 QString QQmlType::qmlTypeName() const
469 {
470 if (!d)
471 return QString();
472 return d->name;
473 }
474
create() const475 QObject *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
create(QObject ** out,void ** memory,size_t additionalMemory) const491 void 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
singletonInstanceInfo() const508 QQmlType::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
customParser() const517 QQmlCustomParser *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
createFunction() const526 QQmlType::CreateFunc QQmlType::createFunction() const
527 {
528 if (!d || d->regType != CppType)
529 return nullptr;
530 return d->extraData.cd->newFunc;
531 }
532
noCreationReason() const533 QString QQmlType::noCreationReason() const
534 {
535 if (!d || d->regType != CppType)
536 return QString();
537 return d->extraData.cd->noCreationReason;
538 }
539
isCreatable() const540 bool QQmlType::isCreatable() const
541 {
542 return d && d->regType == CppType && d->extraData.cd->newFunc;
543 }
544
extensionFunction() const545 QQmlType::ExtensionFunc QQmlType::extensionFunction() const
546 {
547 if (!d || d->regType != CppType)
548 return nullptr;
549 return d->extraData.cd->extFunc;
550 }
551
isExtendedType() const552 bool QQmlType::isExtendedType() const
553 {
554 if (!d)
555 return false;
556 d->init();
557
558 return !d->metaObjects.isEmpty();
559 }
560
isSingleton() const561 bool QQmlType::isSingleton() const
562 {
563 return d && (d->regType == SingletonType || d->regType == CompositeSingletonType);
564 }
565
isInterface() const566 bool QQmlType::isInterface() const
567 {
568 return d && d->regType == InterfaceType;
569 }
570
isComposite() const571 bool QQmlType::isComposite() const
572 {
573 return d && d->isComposite();
574 }
575
isCompositeSingleton() const576 bool 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
isQObjectSingleton() const585 bool QQmlType::isQObjectSingleton() const
586 {
587 return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback;
588 }
589
isQJSValueSingleton() const590 bool QQmlType::isQJSValueSingleton() const
591 {
592 return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback;
593 }
594
typeId() const595 int QQmlType::typeId() const
596 {
597 return d ? d->typeId : -1;
598 }
599
qListTypeId() const600 int QQmlType::qListTypeId() const
601 {
602 return d ? d->listId : -1;
603 }
604
metaObject() const605 const 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
baseMetaObject() const618 const QMetaObject *QQmlType::baseMetaObject() const
619 {
620 return d ? d->baseMetaObject : nullptr;
621 }
622
containsRevisionedAttributes() const623 bool QQmlType::containsRevisionedAttributes() const
624 {
625 if (!d)
626 return false;
627 d->init();
628
629 return d->containsRevisionedAttributes;
630 }
631
metaObjectRevision() const632 int QQmlType::metaObjectRevision() const
633 {
634 return d ? d->revision : -1;
635 }
636
attachedPropertiesFunction(QQmlEnginePrivate * engine) const637 QQmlAttachedPropertiesFunc 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
attachedPropertiesType(QQmlEnginePrivate * engine) const644 const 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 /*
653 This is the id passed to qmlAttachedPropertiesById(). This is different from the index
654 for the case that a single class is registered under two or more names (eg. Item in
655 Qt 4.7 and QtQuick 1.0).
656 */
attachedPropertiesId(QQmlEnginePrivate * engine) const657 int 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
parserStatusCast() const665 int QQmlType::parserStatusCast() const
666 {
667 if (!d || d->regType != CppType)
668 return -1;
669 return d->extraData.cd->parserStatusCast;
670 }
671
propertyValueSourceCast() const672 int QQmlType::propertyValueSourceCast() const
673 {
674 if (!d || d->regType != CppType)
675 return -1;
676 return d->extraData.cd->propertyValueSourceCast;
677 }
678
propertyValueInterceptorCast() const679 int QQmlType::propertyValueInterceptorCast() const
680 {
681 if (!d || d->regType != CppType)
682 return -1;
683 return d->extraData.cd->propertyValueInterceptorCast;
684 }
685
interfaceIId() const686 const char *QQmlType::interfaceIId() const
687 {
688 if (!d || d->regType != InterfaceType)
689 return nullptr;
690 return d->iid;
691 }
692
index() const693 int QQmlType::index() const
694 {
695 return d ? d->index : -1;
696 }
697
isInlineComponentType() const698 bool QQmlType::isInlineComponentType() const {
699 return d ? d->regType == QQmlType::InlineComponentType : false;
700 }
701
inlineComponendId() const702 int 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);
709 return ok ? subObjectId : -1;
710 }
711
sourceUrl() const712 QUrl 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(QString::number(inlineComponendId()));
718 }
719 return url;
720 }
721
enumValue(QQmlEnginePrivate * engine,const QHashedStringRef & name,bool * ok) const722 int 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(name);
731 if (rv)
732 return *rv;
733 }
734
735 *ok = false;
736 return -1;
737 }
738
enumValue(QQmlEnginePrivate * engine,const QHashedCStringRef & name,bool * ok) const739 int 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(name);
748 if (rv)
749 return *rv;
750 }
751
752 *ok = false;
753 return -1;
754 }
755
enumValue(QQmlEnginePrivate * engine,const QV4::String * name,bool * ok) const756 int 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(name);
765 if (rv)
766 return *rv;
767 }
768
769 *ok = false;
770 return -1;
771 }
772
scopedEnumIndex(QQmlEnginePrivate * engine,const QV4::String * name,bool * ok) const773 int 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(name);
782 if (rv)
783 return *rv;
784 }
785
786 *ok = false;
787 return -1;
788 }
789
scopedEnumIndex(QQmlEnginePrivate * engine,const QString & name,bool * ok) const790 int 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(name);
799 if (rv)
800 return *rv;
801 }
802
803 *ok = false;
804 return -1;
805 }
806
scopedEnumValue(QQmlEnginePrivate * engine,int index,const QV4::String * name,bool * ok) const807 int 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(index)->value(name);
816 if (rv)
817 return *rv;
818 }
819
820 *ok = false;
821 return -1;
822 }
823
scopedEnumValue(QQmlEnginePrivate * engine,int index,const QString & name,bool * ok) const824 int 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(index)->value(name);
833 if (rv)
834 return *rv;
835 }
836
837 *ok = false;
838 return -1;
839 }
840
scopedEnumValue(QQmlEnginePrivate * engine,const QByteArray & scopedEnumName,const QByteArray & name,bool * ok) const841 int 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(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(index)->value(QHashedCStringRef(name.constData(), name.length()));
854 if (rv)
855 return *rv;
856 }
857 }
858
859 *ok = false;
860 return -1;
861 }
862
scopedEnumValue(QQmlEnginePrivate * engine,const QStringRef & scopedEnumName,const QStringRef & name,bool * ok) const863 int 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(QHashedStringRef(scopedEnumName));
872 if (rv) {
873 int index = *rv;
874 Q_ASSERT(index > -1 && index < d->scopedEnums.count());
875 rv = d->scopedEnums.at(index)->value(QHashedStringRef(name));
876 if (rv)
877 return *rv;
878 }
879 }
880
881 *ok = false;
882 return -1;
883 }
884
inlineComponentObjectId()885 int QQmlType::inlineComponentObjectId()
886 {
887 if (!isInlineComponentType())
888 return -1;
889 return d->extraData.id->objectId;
890 }
891
setInlineComponentObjectId(int id) const892 void QQmlType::setInlineComponentObjectId(int id) const
893 {
894 Q_ASSERT(d && d->regType == QQmlType::InlineComponentType);
895 d->extraData.id->objectId = id;
896 }
897
refHandle(const QQmlTypePrivate * priv)898 void QQmlType::refHandle(const QQmlTypePrivate *priv)
899 {
900 if (priv)
901 priv->addref();
902 }
903
derefHandle(const QQmlTypePrivate * priv)904 void QQmlType::derefHandle(const QQmlTypePrivate *priv)
905 {
906 if (priv)
907 priv->release();
908 }
909
refCount(const QQmlTypePrivate * priv)910 int QQmlType::refCount(const QQmlTypePrivate *priv)
911 {
912 if (priv)
913 return priv->count();
914 return -1;
915 }
916
lookupInlineComponentIdByName(const QString & name) const917 int QQmlType::lookupInlineComponentIdByName(const QString &name) const
918 {
919 Q_ASSERT(d);
920 return d->namesToInlineComponentObjectIndex.value(name, -1);
921 }
922
containingType() const923 QQmlType 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
lookupInlineComponentById(int objectid) const931 QQmlType QQmlType::lookupInlineComponentById(int objectid) const
932 {
933 Q_ASSERT(d);
934 return d->objectIdToICType.value(objectid, QQmlType(nullptr));
935 }
936
generatePlaceHolderICId() const937 int 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
associateInlineComponent(const QString & name,int objectID,const CompositeMetaTypeIds & metaTypeIds,QQmlType existingType)947 void 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( QString::fromUtf8(typeName()), name);
952 auto icUrl = QUrl(sourceUrl());
953 icUrl.setFragment(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(name, objectID);
960 QQmlType icType(priv);
961 d->objectIdToICType.insert(objectID, icType);
962 if (!reuseExistingType)
963 priv->release();
964 }
965
setPendingResolutionName(const QString & name)966 void 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
pendingResolutionName() const973 QString QQmlType::pendingResolutionName() const
974 {
975 Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
976 return d->extraData.id->inlineComponentName;
977 }
978
979 QT_END_NAMESPACE
980