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 | |
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(msg: "QQmlTypePrivate Internal Error."); |
91 | } |
92 | } |
93 | |
94 | QQmlTypePrivate::~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 | |
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; |
125 | QQmlType::QQmlType(const QQmlTypePrivate *priv) : d(priv) {} |
126 | QQmlType::~QQmlType() = default; |
127 | |
128 | QHashedString QQmlType::module() const |
129 | { |
130 | if (!d) |
131 | return QHashedString(); |
132 | return d->module; |
133 | } |
134 | |
135 | int QQmlType::majorVersion() const |
136 | { |
137 | if (!d) |
138 | return -1; |
139 | return d->version_maj; |
140 | } |
141 | |
142 | int QQmlType::minorVersion() const |
143 | { |
144 | if (!d) |
145 | return -1; |
146 | return d->version_min; |
147 | } |
148 | |
149 | 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 | |
157 | 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 | |
165 | QQmlType 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 | |
178 | 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(unNormalizedUrl: sourceUrl())); |
185 | if (td.isNull() || !td->isComplete()) |
186 | return nullptr; |
187 | QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit(); |
188 | return compilationUnit->rootPropertyCache().data(); |
189 | } |
190 | |
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: 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 | |
209 | 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, 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 | |
273 | 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 | |
301 | 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(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 | |
358 | void 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 | |
388 | 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, 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 | |
411 | 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(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 | |
435 | void QQmlTypePrivate::setContainingType(QQmlType *containingType) |
436 | { |
437 | Q_ASSERT(regType == QQmlType::InlineComponentType); |
438 | extraData.id->containingType = containingType->d.data(); |
439 | } |
440 | |
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 | |
448 | 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 | |
461 | QString QQmlType::elementName() const |
462 | { |
463 | if (!d) |
464 | return QString(); |
465 | return d->elementName; |
466 | } |
467 | |
468 | QString QQmlType::qmlTypeName() const |
469 | { |
470 | if (!d) |
471 | return QString(); |
472 | return d->name; |
473 | } |
474 | |
475 | 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 | |
491 | 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 | |
508 | 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 | |
517 | 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 | |
526 | QQmlType::CreateFunc QQmlType::createFunction() const |
527 | { |
528 | if (!d || d->regType != CppType) |
529 | return nullptr; |
530 | return d->extraData.cd->newFunc; |
531 | } |
532 | |
533 | QString QQmlType::noCreationReason() const |
534 | { |
535 | if (!d || d->regType != CppType) |
536 | return QString(); |
537 | return d->extraData.cd->noCreationReason; |
538 | } |
539 | |
540 | bool QQmlType::isCreatable() const |
541 | { |
542 | return d && d->regType == CppType && d->extraData.cd->newFunc; |
543 | } |
544 | |
545 | QQmlType::ExtensionFunc QQmlType::extensionFunction() const |
546 | { |
547 | if (!d || d->regType != CppType) |
548 | return nullptr; |
549 | return d->extraData.cd->extFunc; |
550 | } |
551 | |
552 | bool QQmlType::isExtendedType() const |
553 | { |
554 | if (!d) |
555 | return false; |
556 | d->init(); |
557 | |
558 | return !d->metaObjects.isEmpty(); |
559 | } |
560 | |
561 | bool QQmlType::isSingleton() const |
562 | { |
563 | return d && (d->regType == SingletonType || d->regType == CompositeSingletonType); |
564 | } |
565 | |
566 | bool QQmlType::isInterface() const |
567 | { |
568 | return d && d->regType == InterfaceType; |
569 | } |
570 | |
571 | bool QQmlType::isComposite() const |
572 | { |
573 | return d && d->isComposite(); |
574 | } |
575 | |
576 | 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 | |
585 | bool QQmlType::isQObjectSingleton() const |
586 | { |
587 | return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback; |
588 | } |
589 | |
590 | bool QQmlType::isQJSValueSingleton() const |
591 | { |
592 | return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback; |
593 | } |
594 | |
595 | int QQmlType::typeId() const |
596 | { |
597 | return d ? d->typeId : -1; |
598 | } |
599 | |
600 | int QQmlType::qListTypeId() const |
601 | { |
602 | return d ? d->listId : -1; |
603 | } |
604 | |
605 | 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 | |
618 | const QMetaObject *QQmlType::baseMetaObject() const |
619 | { |
620 | return d ? d->baseMetaObject : nullptr; |
621 | } |
622 | |
623 | bool QQmlType::containsRevisionedAttributes() const |
624 | { |
625 | if (!d) |
626 | return false; |
627 | d->init(); |
628 | |
629 | return d->containsRevisionedAttributes; |
630 | } |
631 | |
632 | int QQmlType::metaObjectRevision() const |
633 | { |
634 | return d ? d->revision : -1; |
635 | } |
636 | |
637 | 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 | |
644 | 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 | */ |
657 | 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 | |
665 | int QQmlType::parserStatusCast() const |
666 | { |
667 | if (!d || d->regType != CppType) |
668 | return -1; |
669 | return d->extraData.cd->parserStatusCast; |
670 | } |
671 | |
672 | int QQmlType::propertyValueSourceCast() const |
673 | { |
674 | if (!d || d->regType != CppType) |
675 | return -1; |
676 | return d->extraData.cd->propertyValueSourceCast; |
677 | } |
678 | |
679 | int QQmlType::propertyValueInterceptorCast() const |
680 | { |
681 | if (!d || d->regType != CppType) |
682 | return -1; |
683 | return d->extraData.cd->propertyValueInterceptorCast; |
684 | } |
685 | |
686 | const char *QQmlType::interfaceIId() const |
687 | { |
688 | if (!d || d->regType != InterfaceType) |
689 | return nullptr; |
690 | return d->iid; |
691 | } |
692 | |
693 | int QQmlType::index() const |
694 | { |
695 | return d ? d->index : -1; |
696 | } |
697 | |
698 | bool QQmlType::isInlineComponentType() const { |
699 | return d ? d->regType == QQmlType::InlineComponentType : false; |
700 | } |
701 | |
702 | 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: &ok); |
709 | return ok ? subObjectId : -1; |
710 | } |
711 | |
712 | 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(fragment: QString::number(inlineComponendId())); |
718 | } |
719 | return url; |
720 | } |
721 | |
722 | 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(key: name); |
731 | if (rv) |
732 | return *rv; |
733 | } |
734 | |
735 | *ok = false; |
736 | return -1; |
737 | } |
738 | |
739 | 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(key: name); |
748 | if (rv) |
749 | return *rv; |
750 | } |
751 | |
752 | *ok = false; |
753 | return -1; |
754 | } |
755 | |
756 | 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(string: name); |
765 | if (rv) |
766 | return *rv; |
767 | } |
768 | |
769 | *ok = false; |
770 | return -1; |
771 | } |
772 | |
773 | 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(string: name); |
782 | if (rv) |
783 | return *rv; |
784 | } |
785 | |
786 | *ok = false; |
787 | return -1; |
788 | } |
789 | |
790 | 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(key: name); |
799 | if (rv) |
800 | return *rv; |
801 | } |
802 | |
803 | *ok = false; |
804 | return -1; |
805 | } |
806 | |
807 | 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(i: index)->value(string: name); |
816 | if (rv) |
817 | return *rv; |
818 | } |
819 | |
820 | *ok = false; |
821 | return -1; |
822 | } |
823 | |
824 | 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(i: index)->value(key: name); |
833 | if (rv) |
834 | return *rv; |
835 | } |
836 | |
837 | *ok = false; |
838 | return -1; |
839 | } |
840 | |
841 | 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(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 | |
863 | 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(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 | |
885 | int QQmlType::inlineComponentObjectId() |
886 | { |
887 | if (!isInlineComponentType()) |
888 | return -1; |
889 | return d->extraData.id->objectId; |
890 | } |
891 | |
892 | void QQmlType::setInlineComponentObjectId(int id) const |
893 | { |
894 | Q_ASSERT(d && d->regType == QQmlType::InlineComponentType); |
895 | d->extraData.id->objectId = id; |
896 | } |
897 | |
898 | void QQmlType::refHandle(const QQmlTypePrivate *priv) |
899 | { |
900 | if (priv) |
901 | priv->addref(); |
902 | } |
903 | |
904 | void QQmlType::derefHandle(const QQmlTypePrivate *priv) |
905 | { |
906 | if (priv) |
907 | priv->release(); |
908 | } |
909 | |
910 | int QQmlType::refCount(const QQmlTypePrivate *priv) |
911 | { |
912 | if (priv) |
913 | return priv->count(); |
914 | return -1; |
915 | } |
916 | |
917 | int QQmlType::lookupInlineComponentIdByName(const QString &name) const |
918 | { |
919 | Q_ASSERT(d); |
920 | return d->namesToInlineComponentObjectIndex.value(akey: name, adefaultValue: -1); |
921 | } |
922 | |
923 | 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 | |
931 | QQmlType QQmlType::lookupInlineComponentById(int objectid) const |
932 | { |
933 | Q_ASSERT(d); |
934 | return d->objectIdToICType.value(akey: objectid, adefaultValue: QQmlType(nullptr)); |
935 | } |
936 | |
937 | 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 | |
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( 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 | |
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 | |
973 | 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 |
Definitions
- QQmlTypePrivate
- ~QQmlTypePrivate
- QQmlType
- QQmlType
- QQmlType
- operator =
- operator =
- QQmlType
- ~QQmlType
- module
- majorVersion
- minorVersion
- availableInVersion
- availableInVersion
- resolveCompositeBaseType
- compositePropertyCache
- isPropertyRevisioned
- init
- initEnums
- insertEnums
- createListOfPossibleConflictingItems
- createEnumConflictReport
- insertEnumsFromPropertyCache
- setContainingType
- setName
- typeName
- elementName
- qmlTypeName
- create
- create
- singletonInstanceInfo
- customParser
- createFunction
- noCreationReason
- isCreatable
- extensionFunction
- isExtendedType
- isSingleton
- isInterface
- isComposite
- isCompositeSingleton
- isQObjectSingleton
- isQJSValueSingleton
- typeId
- qListTypeId
- metaObject
- baseMetaObject
- containsRevisionedAttributes
- metaObjectRevision
- attachedPropertiesFunction
- attachedPropertiesType
- attachedPropertiesId
- parserStatusCast
- propertyValueSourceCast
- propertyValueInterceptorCast
- interfaceIId
- index
- isInlineComponentType
- inlineComponendId
- sourceUrl
- enumValue
- enumValue
- enumValue
- scopedEnumIndex
- scopedEnumIndex
- scopedEnumValue
- scopedEnumValue
- scopedEnumValue
- scopedEnumValue
- inlineComponentObjectId
- setInlineComponentObjectId
- refHandle
- derefHandle
- refCount
- lookupInlineComponentIdByName
- containingType
- lookupInlineComponentById
- generatePlaceHolderICId
- associateInlineComponent
- setPendingResolutionName
Learn to use CMake with our Intro Training
Find out more