1/****************************************************************************
2**
3** Copyright (C) 2016 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 "qqmlmetatype_p.h"
41
42#include <private/qqmlmetatypedata_p.h>
43#include <private/qqmltypemodule_p_p.h>
44#include <private/qqmltype_p_p.h>
45#include <private/qqmltypeloader_p.h>
46#include <private/qqmlextensionplugin_p.h>
47#include <private/qv4executablecompilationunit_p.h>
48
49#include <QtCore/qcoreapplication.h>
50#include <QtCore/qmutex.h>
51#include <QtCore/qloggingcategory.h>
52
53Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
54
55QT_BEGIN_NAMESPACE
56
57struct LockedData : private QQmlMetaTypeData
58{
59 friend class QQmlMetaTypeDataPtr;
60};
61
62Q_GLOBAL_STATIC(LockedData, metaTypeData)
63Q_GLOBAL_STATIC(QRecursiveMutex, metaTypeDataLock)
64
65class QQmlMetaTypeDataPtr
66{
67 Q_DISABLE_COPY_MOVE(QQmlMetaTypeDataPtr)
68public:
69 QQmlMetaTypeDataPtr() : locker(metaTypeDataLock()), data(metaTypeData()) {}
70 ~QQmlMetaTypeDataPtr() = default;
71
72 QQmlMetaTypeData &operator*() { return *data; }
73 QQmlMetaTypeData *operator->() { return data; }
74 operator QQmlMetaTypeData *() { return data; }
75
76 const QQmlMetaTypeData &operator*() const { return *data; }
77 const QQmlMetaTypeData *operator->() const { return data; }
78 operator const QQmlMetaTypeData *() const { return data; }
79
80 bool isValid() const { return data != nullptr; }
81
82private:
83 QMutexLocker locker;
84 LockedData *data = nullptr;
85};
86
87static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data,
88 const QQmlPrivate::RegisterInterface &type)
89{
90 auto *d = new QQmlTypePrivate(QQmlType::InterfaceType);
91 d->iid = type.iid;
92 d->typeId = type.typeId;
93 d->listId = type.listId;
94 d->isSetup = true;
95 d->version_maj = 0;
96 d->version_min = 0;
97 data->registerType(d);
98 return d;
99}
100
101static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
102 const QQmlPrivate::RegisterSingletonType &type)
103{
104 auto *d = new QQmlTypePrivate(QQmlType::SingletonType);
105 data->registerType(d);
106
107 d->setName(QString::fromUtf8(type.uri), elementName);
108 d->version_maj = type.versionMajor;
109 d->version_min = type.versionMinor;
110
111 if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) {
112 if (type.version >= 1) // static metaobject added in version 1
113 d->baseMetaObject = type.instanceMetaObject;
114 if (type.version >= 2) // typeId added in version 2
115 d->typeId = type.typeId;
116 if (type.version >= 2) // revisions added in version 2
117 d->revision = type.revision;
118 }
119
120 d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
121 d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi;
122 if (type.version >= 3) {
123 d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi;
124 } else {
125 d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi;
126 }
127 d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
128 d->extraData.sd->singletonInstanceInfo->instanceMetaObject
129 = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr;
130
131 return d;
132}
133
134static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
135 const QQmlPrivate::RegisterType &type)
136{
137 QQmlTypePrivate *d = new QQmlTypePrivate(QQmlType::CppType);
138 data->registerType(d);
139 d->setName(QString::fromUtf8(type.uri), elementName);
140
141 d->version_maj = type.versionMajor;
142 d->version_min = type.versionMinor;
143 if (type.version >= 1) // revisions added in version 1
144 d->revision = type.revision;
145 d->typeId = type.typeId;
146 d->listId = type.listId;
147 d->extraData.cd->allocationSize = type.objectSize;
148 d->extraData.cd->newFunc = type.create;
149 d->extraData.cd->noCreationReason = type.noCreationReason;
150 d->baseMetaObject = type.metaObject;
151 d->extraData.cd->attachedPropertiesFunc = type.attachedPropertiesFunction;
152 d->extraData.cd->attachedPropertiesType = type.attachedPropertiesMetaObject;
153 d->extraData.cd->parserStatusCast = type.parserStatusCast;
154 d->extraData.cd->propertyValueSourceCast = type.valueSourceCast;
155 d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast;
156 d->extraData.cd->extFunc = type.extensionObjectCreate;
157 d->extraData.cd->customParser = type.customParser;
158 d->extraData.cd->registerEnumClassesUnscoped = true;
159
160 if (type.extensionMetaObject)
161 d->extraData.cd->extMetaObject = type.extensionMetaObject;
162
163 // Check if the user wants only scoped enum classes
164 if (d->baseMetaObject) {
165 auto indexOfClassInfo = d->baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
166 if (indexOfClassInfo != -1 && QString::fromUtf8(d->baseMetaObject->classInfo(indexOfClassInfo).value()) == QLatin1String("false"))
167 d->extraData.cd->registerEnumClassesUnscoped = false;
168 }
169
170 return d;
171}
172
173static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
174 const QQmlPrivate::RegisterCompositeType &type)
175{
176 auto *d = new QQmlTypePrivate(QQmlType::CompositeType);
177 data->registerType(d);
178 d->setName(QString::fromUtf8(type.uri), elementName);
179 d->version_maj = type.versionMajor;
180 d->version_min = type.versionMinor;
181
182 d->extraData.fd->url = QQmlTypeLoader::normalize(type.url);
183 return d;
184}
185
186static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
187 const QQmlPrivate::RegisterCompositeSingletonType &type)
188{
189 auto *d = new QQmlTypePrivate(QQmlType::CompositeSingletonType);
190 data->registerType(d);
191 d->setName(QString::fromUtf8(type.uri), elementName);
192
193 d->version_maj = type.versionMajor;
194 d->version_min = type.versionMinor;
195
196 d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
197 d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url);
198 d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
199 return d;
200}
201
202void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
203 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
204{
205 // Set classname
206 builder.setClassName(ignoreEnd->className());
207
208 // Clone Q_CLASSINFO
209 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
210 QMetaClassInfo info = mo->classInfo(ii);
211
212 int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
213 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
214 // Skip
215 } else {
216 builder.addClassInfo(info.name(), info.value());
217 }
218 }
219
220 // Clone Q_PROPERTY
221 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
222 QMetaProperty property = mo->property(ii);
223
224 int otherIndex = ignoreEnd->indexOfProperty(property.name());
225 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
226 builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
227 // Skip
228 } else {
229 builder.addProperty(property);
230 }
231 }
232
233 // Clone Q_METHODS
234 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
235 QMetaMethod method = mo->method(ii);
236
237 // More complex - need to search name
238 QByteArray name = method.name();
239
240
241 bool found = false;
242
243 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
244 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
245 ++ii) {
246
247 QMetaMethod other = ignoreEnd->method(ii);
248
249 found = name == other.name();
250 }
251
252 QMetaMethodBuilder m = builder.addMethod(method);
253 if (found) // SKIP
254 m.setAccess(QMetaMethod::Private);
255 }
256
257 // Clone Q_ENUMS
258 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
259 QMetaEnum enumerator = mo->enumerator(ii);
260
261 int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
262 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
263 // Skip
264 } else {
265 builder.addEnumerator(enumerator);
266 }
267 }
268}
269
270void QQmlMetaType::clearTypeRegistrations()
271{
272 //Only cleans global static, assumed no running engine
273 QQmlMetaTypeDataPtr data;
274
275 for (QQmlMetaTypeData::TypeModules::const_iterator i = data->uriToModule.constBegin(), cend = data->uriToModule.constEnd(); i != cend; ++i)
276 delete *i;
277
278 data->types.clear();
279 data->idToType.clear();
280 data->nameToType.clear();
281 data->urlToType.clear();
282 data->typePropertyCaches.clear();
283 data->urlToNonFileImportType.clear();
284 data->metaObjectToType.clear();
285 data->uriToModule.clear();
286 data->undeletableTypes.clear();
287}
288
289int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent)
290{
291 QQmlMetaTypeDataPtr data;
292
293 data->parentFunctions.append(autoparent.function);
294
295 return data->parentFunctions.count() - 1;
296}
297
298void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function)
299{
300 QQmlMetaTypeDataPtr data;
301 data->parentFunctions.removeOne(function);
302}
303
304QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type)
305{
306 if (type.version > 0)
307 qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
308
309 QQmlMetaTypeDataPtr data;
310 QQmlTypePrivate *priv = createQQmlType(data, type);
311 Q_ASSERT(priv);
312
313 data->idToType.insert(priv->typeId, priv);
314 data->idToType.insert(priv->listId, priv);
315 // XXX No insertMulti, so no multi-version interfaces?
316 if (!priv->elementName.isEmpty())
317 data->nameToType.insert(priv->elementName, priv);
318
319 if (data->interfaces.size() <= type.typeId)
320 data->interfaces.resize(type.typeId + 16);
321 if (data->lists.size() <= type.listId)
322 data->lists.resize(type.listId + 16);
323 data->interfaces.setBit(type.typeId, true);
324 data->lists.setBit(type.listId, true);
325
326 return QQmlType(priv);
327}
328
329QString registrationTypeString(QQmlType::RegistrationType typeType)
330{
331 QString typeStr;
332 if (typeType == QQmlType::CppType)
333 typeStr = QStringLiteral("element");
334 else if (typeType == QQmlType::SingletonType)
335 typeStr = QStringLiteral("singleton type");
336 else if (typeType == QQmlType::CompositeSingletonType)
337 typeStr = QStringLiteral("composite singleton type");
338 else
339 typeStr = QStringLiteral("type");
340 return typeStr;
341}
342
343// NOTE: caller must hold a QMutexLocker on "data"
344bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data,
345 const char *uri, const QString &typeName, int majorVersion = -1)
346{
347 if (!typeName.isEmpty()) {
348 if (typeName.at(0).isLower()) {
349 QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\"; type names must begin with an uppercase letter"));
350 data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName));
351 return false;
352 }
353
354 int typeNameLen = typeName.length();
355 for (int ii = 0; ii < typeNameLen; ++ii) {
356 if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(ii) == '_')) {
357 QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
358 data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName));
359 return false;
360 }
361 }
362 }
363
364 if (uri && !typeName.isEmpty()) {
365 QString nameSpace = QString::fromUtf8(uri);
366
367 if (data->typeRegistrationNamespace.isEmpty() && !nameSpace.isEmpty()) {
368 // Is the target namespace protected against further registrations?
369 if (data->protectedNamespaces.contains(nameSpace)) {
370 QString failure(QCoreApplication::translate("qmlRegisterType",
371 "Cannot install %1 '%2' into protected namespace '%3'"));
372 data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
373 return false;
374 }
375 } else if (majorVersion >= 0) {
376 QQmlMetaTypeData::VersionedUri versionedUri;
377 versionedUri.uri = nameSpace;
378 versionedUri.majorVersion = majorVersion;
379 if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
380 if (qqtm->isLocked()){
381 QString failure(QCoreApplication::translate("qmlRegisterType",
382 "Cannot install %1 '%2' into protected module '%3' version '%4'"));
383 data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion));
384 return false;
385 }
386 }
387 }
388 }
389
390 return true;
391}
392
393// NOTE: caller must hold a QMutexLocker on "data"
394QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data)
395{
396 QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
397 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
398 if (!module) {
399 module = new QQmlTypeModule(versionedUri.uri, versionedUri.majorVersion);
400 data->uriToModule.insert(versionedUri, module);
401 }
402 return module;
403}
404
405// NOTE: caller must hold a QMutexLocker on "data"
406void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
407{
408 Q_ASSERT(type);
409
410 if (!type->elementName.isEmpty())
411 data->nameToType.insertMulti(type->elementName, type);
412
413 if (type->baseMetaObject)
414 data->metaObjectToType.insertMulti(type->baseMetaObject, type);
415
416 if (type->typeId) {
417 data->idToType.insert(type->typeId, type);
418 if (data->objects.size() <= type->typeId)
419 data->objects.resize(type->typeId + 16);
420 data->objects.setBit(type->typeId, true);
421 }
422
423 if (type->listId) {
424 if (data->lists.size() <= type->listId)
425 data->lists.resize(type->listId + 16);
426 data->lists.setBit(type->listId, true);
427 data->idToType.insert(type->listId, type);
428 }
429
430 if (!type->module.isEmpty()) {
431 const QHashedString &mod = type->module;
432
433 QQmlTypeModule *module = getTypeModule(mod, type->version_maj, data);
434 Q_ASSERT(module);
435 module->add(type);
436 }
437}
438
439QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type)
440{
441 QQmlMetaTypeDataPtr data;
442
443 QString elementName = QString::fromUtf8(type.elementName);
444 if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor))
445 return QQmlType();
446
447 QQmlTypePrivate *priv = createQQmlType(data, elementName, type);
448
449 addTypeToData(priv, data);
450 if (!type.typeId)
451 data->idToType.insert(priv->typeId, priv);
452
453 return QQmlType(priv);
454}
455
456QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
457{
458 QQmlMetaTypeDataPtr data;
459
460 QString typeName = QString::fromUtf8(type.typeName);
461 if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor))
462 return QQmlType();
463
464 QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
465
466 addTypeToData(priv, data);
467
468 return QQmlType(priv);
469}
470
471QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type)
472{
473 // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
474 QQmlMetaTypeDataPtr data;
475
476 QString typeName = QString::fromUtf8(type.typeName);
477 bool fileImport = false;
478 if (*(type.uri) == '\0')
479 fileImport = true;
480 if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri, typeName))
481 return QQmlType();
482
483 QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
484 addTypeToData(priv, data);
485
486 QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
487 files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
488
489 return QQmlType(priv);
490}
491
492QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
493{
494 // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
495 QQmlMetaTypeDataPtr data;
496
497 QString typeName = QString::fromUtf8(type.typeName);
498 bool fileImport = false;
499 if (*(type.uri) == '\0')
500 fileImport = true;
501 if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName, type.versionMajor))
502 return QQmlType();
503
504 QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
505 addTypeToData(priv, data);
506
507 QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
508 files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
509
510 return QQmlType(priv);
511}
512
513void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
514{
515 QByteArray name = compilationUnit->rootPropertyCache()->className();
516
517 QByteArray ptr = name + '*';
518 QByteArray lst = "QQmlListProperty<" + name + '>';
519
520 int ptr_type = QMetaType::registerNormalizedType(ptr,
521 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct,
522 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct,
523 sizeof(QObject*),
524 static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
525 nullptr);
526 int lst_type = QMetaType::registerNormalizedType(lst,
527 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct,
528 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct,
529 sizeof(QQmlListProperty<QObject>),
530 static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
531 static_cast<QMetaObject*>(nullptr));
532
533 compilationUnit->metaTypeId = ptr_type;
534 compilationUnit->listMetaTypeId = lst_type;
535
536 QQmlMetaTypeDataPtr data;
537 data->qmlLists.insert(lst_type, ptr_type);
538}
539
540void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
541{
542 int ptr_type = compilationUnit->metaTypeId;
543 int lst_type = compilationUnit->listMetaTypeId;
544
545 QQmlMetaTypeDataPtr data;
546 data->qmlLists.remove(lst_type);
547
548 QMetaType::unregisterType(ptr_type);
549 QMetaType::unregisterType(lst_type);
550}
551
552int QQmlMetaType::registerUnitCacheHook(
553 const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
554{
555 if (hookRegistration.version > 0)
556 qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
557
558 QQmlMetaTypeDataPtr data;
559 data->lookupCachedQmlUnit << hookRegistration.lookupCachedQmlUnit;
560 return 0;
561}
562
563bool QQmlMetaType::protectModule(const char *uri, int majVersion)
564{
565 QQmlMetaTypeDataPtr data;
566
567 QQmlMetaTypeData::VersionedUri versionedUri;
568 versionedUri.uri = QString::fromUtf8(uri);
569 versionedUri.majorVersion = majVersion;
570
571 if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) {
572 qqtm->lock();
573 return true;
574 }
575 return false;
576}
577
578void QQmlMetaType::registerModule(const char *uri, int versionMajor, int versionMinor)
579{
580 QQmlMetaTypeDataPtr data;
581
582 QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
583 Q_ASSERT(module);
584
585 module->addMinorVersion(versionMinor);
586}
587
588int QQmlMetaType::typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
589{
590 QQmlMetaTypeDataPtr data;
591
592 QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
593 if (!module)
594 return -1;
595
596 QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(qmlName)), versionMinor);
597 if (!type.isValid())
598 return -1;
599
600 return type.index();
601}
602
603void QQmlMetaType::registerUndeletableType(const QQmlType &dtype)
604{
605 QQmlMetaTypeDataPtr data;
606 data->undeletableTypes.insert(dtype);
607}
608
609static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri,
610 int majorVersion)
611{
612 // Has any type previously been installed to this namespace?
613 QHashedString nameSpace(uri);
614 for (const QQmlType &type : data->types) {
615 if (type.module() == nameSpace && type.majorVersion() == majorVersion)
616 return true;
617 }
618
619 return false;
620}
621
622class QQmlMetaTypeRegistrationFailureRecorder
623{
624 Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
625public:
626 QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
627 : data(data)
628 {
629 data->setTypeRegistrationFailures(failures);
630 }
631
632 ~QQmlMetaTypeRegistrationFailureRecorder()
633 {
634 data->setTypeRegistrationFailures(nullptr);
635 }
636
637 QQmlMetaTypeData *data = nullptr;
638};
639
640
641bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePath,
642 const QString &uri, const QString &typeNamespace, int vmaj,
643 QList<QQmlError> *errors)
644{
645 QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance);
646 if (!iface) {
647 if (errors) {
648 QQmlError error;
649 error.setDescription(QStringLiteral("Module loaded for URI '%1' does not implement "
650 "QQmlTypesExtensionInterface").arg(typeNamespace));
651 errors->prepend(error);
652 }
653 return false;
654 }
655
656 if (!typeNamespace.isEmpty() && typeNamespace != uri) {
657 // This is an 'identified' module
658 // The namespace for type registrations must match the URI for locating the module
659 if (errors) {
660 QQmlError error;
661 error.setDescription(
662 QStringLiteral("Module namespace '%1' does not match import URI '%2'")
663 .arg(typeNamespace).arg(uri));
664 errors->prepend(error);
665 }
666 return false;
667 }
668
669 QStringList failures;
670 QQmlMetaTypeDataPtr data;
671 {
672 QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
673 if (!typeNamespace.isEmpty()) {
674 // This is an 'identified' module
675 if (namespaceContainsRegistrations(data, typeNamespace, vmaj)) {
676 // Other modules have already installed to this namespace
677 if (errors) {
678 QQmlError error;
679 error.setDescription(QStringLiteral("Namespace '%1' has already been used "
680 "for type registration")
681 .arg(typeNamespace));
682 errors->prepend(error);
683 }
684 return false;
685 }
686
687 data->protectedNamespaces.insert(uri);
688 } else {
689 // This is not an identified module - provide a warning
690 qWarning().nospace() << qPrintable(
691 QStringLiteral("Module '%1' does not contain a module identifier directive - "
692 "it cannot be protected from external registrations.").arg(uri));
693 }
694
695 if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
696 // basepath should point to the directory of the module, not the plugin file itself:
697 QQmlExtensionPluginPrivate::get(plugin)->baseUrl
698 = QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
699 }
700
701 data->typeRegistrationNamespace = typeNamespace;
702 const QByteArray bytes = uri.toUtf8();
703 const char *moduleId = bytes.constData();
704 iface->registerTypes(moduleId);
705 data->typeRegistrationNamespace.clear();
706 }
707
708 if (!failures.isEmpty()) {
709 if (errors) {
710 for (const QString &failure : qAsConst(failures)) {
711 QQmlError error;
712 error.setDescription(failure);
713 errors->prepend(error);
714 }
715 }
716 return false;
717 }
718
719 return true;
720}
721
722/*
723 \internal
724
725 Fetches the QQmlType instance registered for \a urlString, creating a
726 registration for it if it is not already registered, using the associated
727 \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion
728 details.
729
730 Errors (if there are any) are placed into \a errors, if it is nonzero.
731 Otherwise errors are printed as warnings.
732*/
733QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
734 const QHashedStringRef &qualifiedType,
735 bool isCompositeSingleton, QList<QQmlError> *errors,
736 int majorVersion, int minorVersion)
737{
738 // ### unfortunate (costly) conversion
739 const QUrl url = QQmlTypeLoader::normalize(QUrl(urlString));
740
741 QQmlMetaTypeDataPtr data;
742 QQmlType ret(data->urlToType.value(url));
743 if (ret.isValid() && ret.sourceUrl() == url)
744 return ret;
745
746 const int dot = qualifiedType.indexOf(QLatin1Char('.'));
747 const QString typeName = dot < 0
748 ? qualifiedType.toString()
749 : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
750
751 QStringList failures;
752 QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
753
754 // Register the type. Note that the URI parameters here are empty; for
755 // file type imports, we do not place them in a URI as we don't
756 // necessarily have a good and unique one (picture a library import,
757 // which may be found in multiple plugin locations on disk), but there
758 // are other reasons for this too.
759 //
760 // By not putting them in a URI, we prevent the types from being
761 // registered on a QQmlTypeModule; this is important, as once types are
762 // placed on there, they cannot be easily removed, meaning if the
763 // developer subsequently loads a different import (meaning different
764 // types) with the same URI (using, say, a different plugin path), it is
765 // very undesirable that we continue to associate the types from the
766 // "old" URI with that new module.
767 //
768 // Not having URIs also means that the types cannot be found by name
769 // etc, the only way to look them up is through QQmlImports -- for
770 // better or worse.
771 const QQmlType::RegistrationType registrationType = isCompositeSingleton
772 ? QQmlType::CompositeSingletonType
773 : QQmlType::CompositeType;
774 if (checkRegistration(registrationType, data, nullptr, typeName, majorVersion)) {
775 auto *priv = new QQmlTypePrivate(registrationType);
776 priv->setName(QString(), typeName);
777 priv->version_maj = majorVersion;
778 priv->version_min = minorVersion;
779
780 if (isCompositeSingleton) {
781 priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
782 priv->extraData.sd->singletonInstanceInfo->url = url;
783 priv->extraData.sd->singletonInstanceInfo->typeName = typeName;
784 } else {
785 priv->extraData.fd->url = url;
786 }
787
788 data->registerType(priv);
789 addTypeToData(priv, data);
790 data->urlToType.insertMulti(url, priv);
791 return QQmlType(priv);
792 }
793
794 // This means that the type couldn't be found by URL, but could not be
795 // registered either, meaning we most likely were passed some kind of bad
796 // data.
797 if (errors) {
798 QQmlError error;
799 error.setDescription(failures.join('\n'));
800 errors->prepend(error);
801 } else {
802 qWarning("%s", failures.join('\n').toLatin1().constData());
803 }
804 return QQmlType();
805}
806
807QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
808{
809 return metaTypeDataLock();
810}
811
812/*
813 Returns true if a module \a uri of any version is installed.
814*/
815bool QQmlMetaType::isAnyModule(const QString &uri)
816{
817 QQmlMetaTypeDataPtr data;
818
819 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin();
820 iter != data->uriToModule.cend(); ++iter) {
821 if ((*iter)->module() == uri)
822 return true;
823 }
824
825 return false;
826}
827
828/*
829 Returns true if a module \a uri of this version is installed and locked;
830*/
831bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion)
832{
833 QQmlMetaTypeDataPtr data;
834
835 QQmlMetaTypeData::VersionedUri versionedUri;
836 versionedUri.uri = uri;
837 versionedUri.majorVersion = majVersion;
838 if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0))
839 return qqtm->isLocked();
840 return false;
841}
842
843/*
844 Returns true if any type or API has been registered for the given \a module with at least
845 versionMajor.versionMinor, or if types have been registered for \a module with at most
846 versionMajor.versionMinor.
847
848 So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
849*/
850bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
851{
852 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
853 QQmlMetaTypeDataPtr data;
854
855 // first, check Types
856 QQmlTypeModule *tm =
857 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
858 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
859 return true;
860
861 return false;
862}
863
864QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
865{
866 QQmlMetaTypeDataPtr data;
867 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
868}
869
870QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
871{
872 QQmlMetaTypeDataPtr data;
873 return data->parentFunctions;
874}
875
876QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
877{
878 if (!isQObject(v.userType())) {
879 if (ok) *ok = false;
880 return nullptr;
881 }
882
883 if (ok) *ok = true;
884
885 return *(QObject *const *)v.constData();
886}
887
888bool QQmlMetaType::isQObject(int userType)
889{
890 if (userType == QMetaType::QObjectStar)
891 return true;
892
893 QQmlMetaTypeDataPtr data;
894 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
895}
896
897/*
898 Returns the item type for a list of type \a id.
899 */
900int QQmlMetaType::listType(int id)
901{
902 QQmlMetaTypeDataPtr data;
903 QHash<int, int>::ConstIterator iter = data->qmlLists.constFind(id);
904 if (iter != data->qmlLists.cend())
905 return *iter;
906 QQmlTypePrivate *type = data->idToType.value(id);
907 if (type && type->listId == id)
908 return type->typeId;
909 else
910 return 0;
911}
912
913#if QT_DEPRECATED_SINCE(5, 14)
914int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo)
915{
916 QQmlMetaTypeDataPtr data;
917
918 for (auto it = data->metaObjectToType.constFind(mo), end = data->metaObjectToType.constEnd();
919 it != end && it.key() == mo; ++it) {
920 const QQmlType type(it.value());
921 if (type.attachedPropertiesFunction(engine))
922 return type.attachedPropertiesId(engine);
923 }
924
925 return -1;
926}
927
928QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePrivate *engine, int id)
929{
930 if (id < 0)
931 return nullptr;
932 QQmlMetaTypeDataPtr data;
933 return data->types.at(id).attachedPropertiesFunction(engine);
934}
935#endif
936
937QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
938 const QMetaObject *mo)
939{
940 QQmlMetaTypeDataPtr data;
941
942 QQmlType type(data->metaObjectToType.value(mo));
943 return type.attachedPropertiesFunction(engine);
944}
945
946QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
947{
948 int idx = metaObject->indexOfClassInfo("DefaultProperty");
949 if (-1 == idx)
950 return QMetaProperty();
951
952 QMetaClassInfo info = metaObject->classInfo(idx);
953 if (!info.value())
954 return QMetaProperty();
955
956 idx = metaObject->indexOfProperty(info.value());
957 if (-1 == idx)
958 return QMetaProperty();
959
960 return metaObject->property(idx);
961}
962
963QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
964{
965 if (!obj)
966 return QMetaProperty();
967
968 const QMetaObject *metaObject = obj->metaObject();
969 return defaultProperty(metaObject);
970}
971
972QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
973{
974 int idx = metaObject->indexOfClassInfo("DefaultMethod");
975 if (-1 == idx)
976 return QMetaMethod();
977
978 QMetaClassInfo info = metaObject->classInfo(idx);
979 if (!info.value())
980 return QMetaMethod();
981
982 idx = metaObject->indexOfMethod(info.value());
983 if (-1 == idx)
984 return QMetaMethod();
985
986 return metaObject->method(idx);
987}
988
989QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
990{
991 if (!obj)
992 return QMetaMethod();
993
994 const QMetaObject *metaObject = obj->metaObject();
995 return defaultMethod(metaObject);
996}
997
998QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
999{
1000 if (userType < 0)
1001 return Unknown;
1002 if (userType == QMetaType::QObjectStar)
1003 return Object;
1004
1005 QQmlMetaTypeDataPtr data;
1006 if (data->qmlLists.contains(userType))
1007 return List;
1008 else if (userType < data->objects.size() && data->objects.testBit(userType))
1009 return Object;
1010 else if (userType < data->lists.size() && data->lists.testBit(userType))
1011 return List;
1012 else
1013 return Unknown;
1014}
1015
1016/*!
1017 See qmlRegisterInterface() for information about when this will return true.
1018*/
1019bool QQmlMetaType::isInterface(int userType)
1020{
1021 const QQmlMetaTypeDataPtr data;
1022 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1023}
1024
1025const char *QQmlMetaType::interfaceIId(int userType)
1026{
1027
1028 QQmlTypePrivate *typePrivate = nullptr;
1029 {
1030 QQmlMetaTypeDataPtr data;
1031 typePrivate = data->idToType.value(userType);
1032 }
1033
1034 QQmlType type(typePrivate);
1035 if (type.isInterface() && type.typeId() == userType)
1036 return type.interfaceIId();
1037 else
1038 return nullptr;
1039}
1040
1041bool QQmlMetaType::isList(int userType)
1042{
1043 const QQmlMetaTypeDataPtr data;
1044 if (data->qmlLists.contains(userType))
1045 return true;
1046 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1047}
1048
1049/*!
1050 A custom string convertor allows you to specify a function pointer that
1051 returns a variant of \a type. For example, if you have written your own icon
1052 class that you want to support as an object property assignable in QML:
1053
1054 \code
1055 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1056 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1057 \endcode
1058
1059 The function pointer must be of the form:
1060 \code
1061 QVariant (*StringConverter)(const QString &);
1062 \endcode
1063 */
1064void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1065{
1066 QQmlMetaTypeDataPtr data;
1067 if (data->stringConverters.contains(type))
1068 return;
1069 data->stringConverters.insert(type, converter);
1070}
1071
1072/*!
1073 Return the custom string converter for \a type, previously installed through
1074 registerCustomStringConverter()
1075 */
1076QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1077{
1078 const QQmlMetaTypeDataPtr data;
1079 return data->stringConverters.value(type);
1080}
1081
1082/*!
1083 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1084 by \a version_major and \a version_minor.
1085*/
1086QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1087{
1088 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1089 if (slash <= 0)
1090 return QQmlType();
1091
1092 QHashedStringRef module(qualifiedName.constData(), slash);
1093 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1094
1095 return qmlType(name, module, version_major, version_minor);
1096}
1097
1098/*!
1099 Returns the type (if any) of \a name in \a module and version specified
1100 by \a version_major and \a version_minor.
1101*/
1102QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1103{
1104 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1105 const QQmlMetaTypeDataPtr data;
1106
1107 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name);
1108 while (it != data->nameToType.cend() && it.key() == name) {
1109 QQmlType t(*it);
1110 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1111 if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor))
1112 return t;
1113 ++it;
1114 }
1115
1116 return QQmlType();
1117}
1118
1119/*!
1120 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1121 type is registered.
1122*/
1123QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
1124{
1125 const QQmlMetaTypeDataPtr data;
1126 return QQmlType(data->metaObjectToType.value(metaObject));
1127}
1128
1129/*!
1130 Returns the type (if any) that corresponds to the \a metaObject in version specified
1131 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1132 type is registered.
1133*/
1134QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1135{
1136 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1137 const QQmlMetaTypeDataPtr data;
1138
1139 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject);
1140 while (it != data->metaObjectToType.cend() && it.key() == metaObject) {
1141 QQmlType t(*it);
1142 if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor))
1143 return t;
1144 ++it;
1145 }
1146
1147 return QQmlType();
1148}
1149
1150/*!
1151 Returns the type (if any) that corresponds to \a typeId. Depending on \a category, the
1152 \a typeId is interpreted either as QVariant::Type or as QML type id returned by one of the
1153 qml type registration functions. Returns null if no type is registered.
1154*/
1155QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category)
1156{
1157 const QQmlMetaTypeDataPtr data;
1158
1159 if (category == TypeIdCategory::MetaType) {
1160 QQmlTypePrivate *type = data->idToType.value(typeId);
1161 if (type && type->typeId == typeId)
1162 return QQmlType(type);
1163 } else if (category == TypeIdCategory::QmlType) {
1164 QQmlType type = data->types.value(typeId);
1165 if (type.isValid())
1166 return type;
1167 }
1168 return QQmlType();
1169}
1170
1171/*!
1172 Returns the type (if any) that corresponds to the given \a url in the set of
1173 composite types added through file imports.
1174
1175 Returns null if no such type is registered.
1176*/
1177QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports /* = false */)
1178{
1179 const QUrl url = QQmlTypeLoader::normalize(unNormalizedUrl);
1180 const QQmlMetaTypeDataPtr data;
1181
1182 QQmlType type(data->urlToType.value(url));
1183 if (!type.isValid() && includeNonFileImports)
1184 type = QQmlType(data->urlToNonFileImportType.value(url));
1185
1186 if (type.sourceUrl() == url)
1187 return type;
1188 else
1189 return QQmlType();
1190}
1191
1192QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion)
1193{
1194 QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
1195 return data->propertyCache(metaObject, minorVersion);
1196}
1197
1198QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion)
1199{
1200 QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
1201 return data->propertyCache(type, minorVersion);
1202}
1203
1204void QQmlMetaType::unregisterType(int typeIndex)
1205{
1206 QQmlMetaTypeDataPtr data;
1207 const QQmlType type = data->types.value(typeIndex);
1208 if (const QQmlTypePrivate *d = type.priv()) {
1209 removeQQmlTypePrivate(data->idToType, d);
1210 removeQQmlTypePrivate(data->nameToType, d);
1211 removeQQmlTypePrivate(data->urlToType, d);
1212 removeQQmlTypePrivate(data->urlToNonFileImportType, d);
1213 removeQQmlTypePrivate(data->metaObjectToType, d);
1214 for (auto & module : data->uriToModule)
1215 module->remove(d);
1216 data->clearPropertyCachesForMinorVersion(typeIndex);
1217 data->types[typeIndex] = QQmlType();
1218 data->undeletableTypes.remove(type);
1219 }
1220}
1221
1222void QQmlMetaType::freeUnusedTypesAndCaches()
1223{
1224 QQmlMetaTypeDataPtr data;
1225
1226 // in case this is being called during program exit, `data` might be destructed already
1227 if (!data.isValid())
1228 return;
1229
1230 bool deletedAtLeastOneType;
1231 do {
1232 deletedAtLeastOneType = false;
1233 QList<QQmlType>::Iterator it = data->types.begin();
1234 while (it != data->types.end()) {
1235 const QQmlTypePrivate *d = (*it).priv();
1236 if (d && d->count() == 1) {
1237 deletedAtLeastOneType = true;
1238
1239 removeQQmlTypePrivate(data->idToType, d);
1240 removeQQmlTypePrivate(data->nameToType, d);
1241 removeQQmlTypePrivate(data->urlToType, d);
1242 removeQQmlTypePrivate(data->urlToNonFileImportType, d);
1243 removeQQmlTypePrivate(data->metaObjectToType, d);
1244
1245 for (auto &module : data->uriToModule)
1246 module->remove(d);
1247
1248 data->clearPropertyCachesForMinorVersion(d->index);
1249 *it = QQmlType();
1250 } else {
1251 ++it;
1252 }
1253 }
1254 } while (deletedAtLeastOneType);
1255
1256 bool deletedAtLeastOneCache;
1257 do {
1258 deletedAtLeastOneCache = false;
1259 QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin();
1260 while (it != data->propertyCaches.end()) {
1261
1262 if ((*it)->count() == 1) {
1263 QQmlPropertyCache *pc = nullptr;
1264 qSwap(pc, *it);
1265 it = data->propertyCaches.erase(it);
1266 pc->release();
1267 deletedAtLeastOneCache = true;
1268 } else {
1269 ++it;
1270 }
1271 }
1272 } while (deletedAtLeastOneCache);
1273}
1274
1275/*!
1276 Returns the list of registered QML type names.
1277*/
1278QList<QString> QQmlMetaType::qmlTypeNames()
1279{
1280 const QQmlMetaTypeDataPtr data;
1281
1282 QList<QString> names;
1283 names.reserve(data->nameToType.count());
1284 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin();
1285 while (it != data->nameToType.cend()) {
1286 QQmlType t(*it);
1287 names += t.qmlTypeName();
1288 ++it;
1289 }
1290
1291 return names;
1292}
1293
1294/*!
1295 Returns the list of registered QML types.
1296*/
1297QList<QQmlType> QQmlMetaType::qmlTypes()
1298{
1299 const QQmlMetaTypeDataPtr data;
1300
1301 QList<QQmlType> types;
1302 for (QQmlTypePrivate *t : data->nameToType)
1303 types.append(QQmlType(t));
1304
1305 return types;
1306}
1307
1308/*!
1309 Returns the list of all registered types.
1310*/
1311QList<QQmlType> QQmlMetaType::qmlAllTypes()
1312{
1313 const QQmlMetaTypeDataPtr data;
1314 return data->types;
1315}
1316
1317/*!
1318 Returns the list of registered QML singleton types.
1319*/
1320QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
1321{
1322 const QQmlMetaTypeDataPtr data;
1323
1324 QList<QQmlType> retn;
1325 for (const auto t : qAsConst(data->nameToType)) {
1326 QQmlType type(t);
1327 if (type.isSingleton())
1328 retn.append(type);
1329 }
1330 return retn;
1331}
1332
1333const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status)
1334{
1335 const QQmlMetaTypeDataPtr data;
1336
1337 for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) {
1338 if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) {
1339 QString error;
1340 if (!QV4::ExecutableCompilationUnit::verifyHeader(unit->qmlData, QDateTime(), &error)) {
1341 qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error;
1342 if (status)
1343 *status = CachedUnitLookupError::VersionMismatch;
1344 return nullptr;
1345 }
1346 if (status)
1347 *status = CachedUnitLookupError::NoError;
1348 return unit->qmlData;
1349 }
1350 }
1351
1352 if (status)
1353 *status = CachedUnitLookupError::NoUnitFound;
1354
1355 return nullptr;
1356}
1357
1358void QQmlMetaType::prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
1359{
1360 QQmlMetaTypeDataPtr data;
1361 data->lookupCachedQmlUnit.prepend(handler);
1362}
1363
1364void QQmlMetaType::removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
1365{
1366 QQmlMetaTypeDataPtr data;
1367 data->lookupCachedQmlUnit.removeAll(handler);
1368}
1369
1370/*!
1371 Returns the pretty QML type name (e.g. 'Item' instead of 'QtQuickItem') for the given object.
1372 */
1373QString QQmlMetaType::prettyTypeName(const QObject *object)
1374{
1375 QString typeName;
1376
1377 if (!object)
1378 return typeName;
1379
1380 QQmlType type = QQmlMetaType::qmlType(object->metaObject());
1381 if (type.isValid()) {
1382 typeName = type.qmlTypeName();
1383 const int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
1384 if (lastSlash != -1)
1385 typeName = typeName.mid(lastSlash + 1);
1386 }
1387
1388 if (typeName.isEmpty()) {
1389 typeName = QString::fromUtf8(object->metaObject()->className());
1390 int marker = typeName.indexOf(QLatin1String("_QMLTYPE_"));
1391 if (marker != -1)
1392 typeName = typeName.left(marker);
1393
1394 marker = typeName.indexOf(QLatin1String("_QML_"));
1395 if (marker != -1) {
1396 typeName = typeName.leftRef(marker) + QLatin1Char('*');
1397 type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
1398 if (type.isValid()) {
1399 QString qmlTypeName = type.qmlTypeName();
1400 const int lastSlash = qmlTypeName.lastIndexOf(QLatin1Char('/'));
1401 if (lastSlash != -1)
1402 qmlTypeName = qmlTypeName.mid(lastSlash + 1);
1403 if (!qmlTypeName.isEmpty())
1404 typeName = qmlTypeName;
1405 }
1406 }
1407 }
1408
1409 return typeName;
1410}
1411
1412QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject *mo,
1413 const QMetaObject *baseMetaObject,
1414 QMetaObject *lastMetaObject)
1415{
1416 QList<QQmlProxyMetaObject::ProxyData> metaObjects;
1417 mo = mo->d.superdata;
1418
1419 const QQmlMetaTypeDataPtr data;
1420
1421 while (mo) {
1422 QQmlTypePrivate *t = data->metaObjectToType.value(mo);
1423 if (t) {
1424 if (t->regType == QQmlType::CppType) {
1425 if (t->extraData.cd->extFunc) {
1426 QMetaObjectBuilder builder;
1427 clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject);
1428 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1429 QMetaObject *mmo = builder.toMetaObject();
1430 mmo->d.superdata = baseMetaObject;
1431 if (!metaObjects.isEmpty())
1432 metaObjects.constLast().metaObject->d.superdata = mmo;
1433 else if (lastMetaObject)
1434 lastMetaObject->d.superdata = mmo;
1435 QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 };
1436 metaObjects << data;
1437 }
1438 }
1439 }
1440 mo = mo->d.superdata;
1441 }
1442
1443 return metaObjects;
1444}
1445
1446QT_END_NAMESPACE
1447