diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-09-27 01:00:58 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-09-27 13:08:12 +0200 |
commit | 1ce1e39b1c9334413473691a218ab4240fba01e1 (patch) | |
tree | 02a8ff6ab6c72cafa5cb45098bbfba4618fe83bc /src/qml/qml | |
parent | 3cf5f0f6c3f1abe1d279ccae6c7563f14b31f41d (diff) | |
parent | cc1a604c704f848927b3fa0a97b0a50b0b79d2a4 (diff) |
Merge remote-tracking branch 'origin/5.15' into dev
Conflicts:
src/imports/folderlistmodel/plugin.cpp
src/imports/shapes/plugin.cpp
src/qml/qml/qqmlengine.cpp
src/qmlmodels/qqmlmodelsmodule.cpp
src/qmlworkerscript/qqmlworkerscriptmodule.cpp
src/quick/items/qquickitemsmodule.cpp
Change-Id: Ib9215a07aa95b5801ce3cb7287f7903926e8c838
Diffstat (limited to 'src/qml/qml')
-rw-r--r-- | src/qml/qml/qqml.cpp | 181 | ||||
-rw-r--r-- | src/qml/qml/qqml.h | 113 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent.h | 27 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponentattached_p.h | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontext.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontext_p.h | 11 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 26 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 7 | ||||
-rw-r--r-- | src/qml/qml/qqmlincubator.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmllocale_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlloggingcategory_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 389 | ||||
-rw-r--r-- | src/qml/qml/qqmltypenotavailable_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlvaluetype_p.h | 2 |
17 files changed, 687 insertions, 100 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 8a50b51b5d..a3ca48d6d9 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -96,33 +96,188 @@ QObject *QQmlPrivate::RegisterSingletonFunctor::operator()(QQmlEngine *qeng, QJS return m_object; }; +static QVector<int> availableRevisions(const QMetaObject *metaObject) +{ + QVector<int> revisions; + if (!metaObject) + return revisions; + const int propertyOffset = metaObject->propertyOffset(); + const int propertyCount = metaObject->propertyCount(); + for (int propertyIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount; + propertyIndex < propertyEnd; ++propertyIndex) { + const QMetaProperty property = metaObject->property(propertyIndex); + if (int revision = property.revision()) + revisions.append(revision); + } + const int methodOffset = metaObject->methodOffset(); + const int methodCount = metaObject->methodCount(); + for (int methodIndex = methodOffset, methodEnd = methodOffset + methodCount; + methodIndex < methodEnd; ++methodIndex) { + const QMetaMethod method = metaObject->method(methodIndex); + if (int revision = method.revision()) + revisions.append(revision); + } + + // Need to also check parent meta objects, as their revisions are inherited. + if (const QMetaObject *superMeta = metaObject->superClass()) + revisions += availableRevisions(superMeta); + + return revisions; +} + /* This method is "over generalized" to allow us to (potentially) register more types of things in the future without adding exported symbols. */ int QQmlPrivate::qmlregister(RegistrationType type, void *data) { - if (type == AutoParentRegistration) { + QQmlType dtype; + switch (type) { + case AutoParentRegistration: return QQmlMetaType::registerAutoParentFunction( *reinterpret_cast<RegisterAutoParent *>(data)); - } else if (type == QmlUnitCacheHookRegistration) { + case QmlUnitCacheHookRegistration: return QQmlMetaType::registerUnitCacheHook( *reinterpret_cast<RegisterQmlUnitCacheHook *>(data)); + case TypeAndRevisionsRegistration: { + const RegisterTypeAndRevisions &type = *reinterpret_cast<RegisterTypeAndRevisions *>(data); + const char *elementName = classElementName(type.classInfoMetaObject); + const bool creatable = (elementName != nullptr) + && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true); + + const QString noCreateReason = creatable + ? QString() + : QString::fromUtf8(classInfo(type.classInfoMetaObject, "QML.UncreatableReason")); + RegisterType revisionRegistration = { + 1, + type.typeId, + type.listId, + creatable ? type.objectSize : 0, + nullptr, + noCreateReason, + type.uri, + type.versionMajor, + -1, + nullptr, + type.metaObject, + type.attachedPropertiesFunction, + type.attachedPropertiesMetaObject, + type.parserStatusCast, + type.valueSourceCast, + type.valueInterceptorCast, + type.extensionObjectCreate, + type.extensionMetaObject, + nullptr, + -1 + }; + + const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0); + const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1); + + auto revisions = availableRevisions(type.metaObject); + revisions.append(qMax(added, 0)); + if (type.attachedPropertiesMetaObject) + revisions += availableRevisions(type.attachedPropertiesMetaObject); + + std::sort(revisions.begin(), revisions.end()); + const auto it = std::unique(revisions.begin(), revisions.end()); + revisions.erase(it, revisions.end()); + + const bool typeWasRemoved = removed >= added; + for (int revision : revisions) { + if (revision < added) + continue; + + // When removed, we still add revisions, but anonymous ones + if (typeWasRemoved && revision >= removed) { + revisionRegistration.elementName = nullptr; + revisionRegistration.create = nullptr; + } else { + revisionRegistration.elementName = elementName; + revisionRegistration.create = creatable ? type.create : nullptr; + } + + // Equivalent of qmlRegisterRevision<T, revision>(...) + revisionRegistration.versionMinor = revision; + revisionRegistration.revision = revision; + revisionRegistration.customParser = type.customParserFactory(); + + qmlregister(TypeRegistration, &revisionRegistration); + } + break; } + case SingletonAndRevisionsRegistration: { + const RegisterSingletonTypeAndRevisions &type + = *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data); + const char *elementName = classElementName(type.classInfoMetaObject); + RegisterSingletonType revisionRegistration = { + QmlCurrentSingletonTypeRegistrationVersion, + type.uri, + type.versionMajor, + -1, + elementName, - QQmlType dtype; - if (type == TypeRegistration) + type.scriptApi, + nullptr, + type.instanceMetaObject, + type.typeId, + -1, + + type.generalizedQobjectApi + }; + + const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0); + const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1); + + auto revisions = availableRevisions(type.instanceMetaObject); + revisions.append(qMax(added, 0)); + + std::sort(revisions.begin(), revisions.end()); + const auto it = std::unique(revisions.begin(), revisions.end()); + revisions.erase(it, revisions.end()); + + const bool typeWasRemoved = removed >= added; + for (int revision : qAsConst(revisions)) { + if (revision < added) + continue; + + // When removed, we still add revisions, but anonymous ones + if (typeWasRemoved && revision >= removed) { + revisionRegistration.typeName = nullptr; + revisionRegistration.scriptApi = nullptr; + revisionRegistration.generalizedQobjectApi = nullptr; + } else { + revisionRegistration.typeName = elementName; + revisionRegistration.scriptApi = type.scriptApi; + revisionRegistration.generalizedQobjectApi = type.generalizedQobjectApi; + } + + // Equivalent of qmlRegisterRevision<T, revision>(...) + revisionRegistration.versionMinor = revision; + revisionRegistration.revision = revision; + + qmlregister(SingletonRegistration, &revisionRegistration); + } + break; + } + case TypeRegistration: dtype = QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data)); - else if (type == InterfaceRegistration) + break; + case InterfaceRegistration: dtype = QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data)); - else if (type == SingletonRegistration) + break; + case SingletonRegistration: dtype = QQmlMetaType::registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data)); - else if (type == CompositeRegistration) + break; + case CompositeRegistration: dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data)); - else if (type == CompositeSingletonRegistration) + break; + case CompositeSingletonRegistration: dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data)); - else + break; + default: return -1; + } if (!dtype.isValid()) return -1; @@ -148,6 +303,14 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data) case CompositeSingletonRegistration: QQmlMetaType::unregisterType(data); break; + case TypeAndRevisionsRegistration: + case SingletonAndRevisionsRegistration: + // Currently unnecessary. We'd need a special data structure to hold + // URI + majorVersion and then we'd iterate the minor versions, look up the + // associated QQmlType objects by uri/elementName/major/minor and qmlunregister + // each of them. + Q_UNREACHABLE(); + break; } } diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 6295345fa4..effa05180d 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -41,9 +41,6 @@ #define QQML_H #include <QtQml/qqmlprivate.h> -#include <QtQml/qqmlparserstatus.h> -#include <QtQml/qqmlpropertyvaluesource.h> -#include <QtQml/qqmllist.h> #include <QtCore/qbytearray.h> #include <QtCore/qmetaobject.h> @@ -51,6 +48,12 @@ #define QML_VERSION 0x020000 #define QML_VERSION_STR "2.0" +#define QML_PRIVATE_NAMESPACE \ + QT_PREPEND_NAMESPACE(QQmlPrivate) + +#define QML_REGISTER_TYPES_AND_REVISIONS \ + QT_PREPEND_NAMESPACE(qmlRegisterTypesAndRevisions) + #define QML_DECLARE_TYPE(TYPE) \ Q_DECLARE_METATYPE(TYPE *) \ Q_DECLARE_METATYPE(QQmlListProperty<TYPE>) @@ -64,6 +67,52 @@ #define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \ QML_DECLARE_TYPE_HASMETATYPE(INTERFACE) +#define QML_ELEMENT \ + Q_CLASSINFO("QML.Element", "auto") + +#define QML_ANONYMOUS \ + Q_CLASSINFO("QML.Element", "anonymous") + +#define QML_NAMED_ELEMENT(NAME) \ + Q_CLASSINFO("QML.Element", #NAME) + +#define QML_UNCREATABLE(REASON) \ + Q_CLASSINFO("QML.Creatable", "false") \ + Q_CLASSINFO("QML.UncreatableReason", REASON) + +#define QML_SINGLETON \ + Q_CLASSINFO("QML.Singleton", "true") \ + enum class QmlIsSingleton {yes = true}; \ + template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlSingleton; \ + template<typename T, typename... Args> \ + friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor); + +#define QML_ADDED_IN_MINOR_VERSION(VERSION) \ + Q_CLASSINFO("QML.AddedInMinorVersion", #VERSION) + +#define QML_REMOVED_IN_MINOR_VERSION(VERSION) \ + Q_CLASSINFO("QML.RemovedInMinorVersion", #VERSION) + +#define QML_ATTACHED(ATTACHED_TYPE) \ + Q_CLASSINFO("QML.Attached", #ATTACHED_TYPE) \ + using QmlAttachedType = ATTACHED_TYPE; \ + template<class, class, bool> friend struct QML_PRIVATE_NAMESPACE::QmlAttached; \ + template<class> friend struct QML_PRIVATE_NAMESPACE::QmlAttachedAccessor; + +#define QML_EXTENDED(EXTENDED_TYPE) \ + Q_CLASSINFO("QML.Extended", #EXTENDED_TYPE) \ + using QmlExtendedType = EXTENDED_TYPE; \ + template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlExtended; \ + template<typename T, typename... Args> \ + friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor); + +#define QML_FOREIGN(FOREIGN_TYPE) \ + Q_CLASSINFO("QML.Foreign", #FOREIGN_TYPE) \ + using QmlForeignType = FOREIGN_TYPE; \ + template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlResolved; \ + template<typename T, typename... Args> \ + friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor); + enum { /* TYPEINFO flags */ QML_HAS_ATTACHED_PROPERTIES = 0x01 }; @@ -82,25 +131,11 @@ QT_END_NAMESPACE QT_BEGIN_NAMESPACE - -class QQmlPropertyValueInterceptor; - -#define QML_GETTYPENAMES \ - const char *className = T::staticMetaObject.className(); \ - const int nameLen = int(strlen(className)); \ - QVarLengthArray<char,48> pointerName(nameLen+2); \ - memcpy(pointerName.data(), className, size_t(nameLen)); \ - pointerName[nameLen] = '*'; \ - pointerName[nameLen+1] = '\0'; \ - const int listLen = int(strlen("QQmlListProperty<")); \ - QVarLengthArray<char,64> listName(listLen + nameLen + 2); \ - memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \ - memcpy(listName.data()+listLen, className, size_t(nameLen)); \ - listName[listLen+nameLen] = '>'; \ - listName[listLen+nameLen+1] = '\0'; - void Q_QML_EXPORT qmlClearTypeRegistrations(); +template<class T> +QQmlCustomParser *qmlCreateCustomParser(); + template<typename T> int qmlRegisterAnonymousType(const char *uri, int versionMajor) { @@ -720,6 +755,44 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i return QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &type); } +template<class T, class Resolved, class Extended, bool Singleton> +struct QmlTypeAndRevisionsRegistration; + +template<class T, class Resolved, class Extended> +struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false> { + static void registerTypeAndRevisions(const char *uri, int versionMajor) + { + QQmlPrivate::qmlRegisterTypeAndRevisions<Resolved, Extended>( + uri, versionMajor, &T::staticMetaObject); + } +}; + +template<class T, class Resolved> +struct QmlTypeAndRevisionsRegistration<T, Resolved, void, true> { + static void registerTypeAndRevisions(const char *uri, int versionMajor) + { + QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved>( + uri, versionMajor, &T::staticMetaObject); + } +}; + +template<typename T = void, typename... Args> +void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor); + +template<typename T, typename... Args> +void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor) +{ + QmlTypeAndRevisionsRegistration< + T, typename QQmlPrivate::QmlResolved<T>::Type, + typename QQmlPrivate::QmlExtended<T>::Type, + QQmlPrivate::QmlSingleton<T>::Value> + ::registerTypeAndRevisions(uri, versionMajor); + qmlRegisterTypesAndRevisions<Args...>(uri, versionMajor); +} + +template<> +inline void qmlRegisterTypesAndRevisions<>(const char *, int) {} + int Q_QML_EXPORT qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName); QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index f259c99b08..cb5d5a787c 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -70,6 +70,9 @@ class Q_QML_EXPORT QQmlComponent : public QObject Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl url READ url CONSTANT) + QML_NAMED_ELEMENT(Component) + QML_ATTACHED(QQmlComponentAttached) + Q_CLASSINFO("QML.Builtin", "QML") public: enum CompilationMode { PreferSynchronous, Asynchronous }; @@ -136,9 +139,29 @@ private: friend class QQmlObjectCreator; }; -QT_END_NAMESPACE +// Don't do this at home. +namespace QQmlPrivate { + +// Generally you cannot use QQmlComponentAttached as attached properties object in derived classes. +// It is private. +template<class T> +struct OverridableAttachedType<T, QQmlComponentAttached> +{ + using Type = void; +}; + +// QQmlComponent itself is allowed to use QQmlComponentAttached, though. +template<> +struct OverridableAttachedType<QQmlComponent, QQmlComponentAttached> +{ + using Type = QQmlComponentAttached; +}; + +} // namespace QQmlPrivate + + +QT_END_NAMESPACE QML_DECLARE_TYPE(QQmlComponent) -QML_DECLARE_TYPEINFO(QQmlComponent, QML_HAS_ATTACHED_PROPERTIES) #endif // QQMLCOMPONENT_H diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h index e3bca18857..8ecd9da17d 100644 --- a/src/qml/qml/qqmlcomponentattached_p.h +++ b/src/qml/qml/qqmlcomponentattached_p.h @@ -61,6 +61,11 @@ QT_BEGIN_NAMESPACE class Q_QML_PRIVATE_EXPORT QQmlComponentAttached : public QObject { Q_OBJECT + + // Used as attached object for QQmlComponent. We want qqmlcomponentattached_p.h to be #include'd + // when registering QQmlComponent, but we cannot #include it from qqmlcomponent.h. Therefore we + // force an anonymous type registration here. + QML_ANONYMOUS public: QQmlComponentAttached(QObject *parent = nullptr); ~QQmlComponentAttached(); diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 14892bd6ad..668f00b136 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -550,7 +550,7 @@ QQmlContextData::QQmlContextData() QQmlContextData::QQmlContextData(QQmlContext *ctxt) : engine(nullptr), isInternal(false), isJSContext(false), isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false), - stronglyReferencedByParent(false), publicContext(ctxt), incubator(nullptr), componentObjectIndex(-1), + stronglyReferencedByParent(false), hasExtraObject(false), publicContext(ctxt), incubator(nullptr), componentObjectIndex(-1), contextObject(nullptr), nextChild(nullptr), prevChild(nullptr), expressions(nullptr), contextObjects(nullptr), idValues(nullptr), idValueCount(0), componentAttached(nullptr) diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index 5f7316b00c..f93393a11b 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -147,11 +147,16 @@ public: quint32 hasEmittedDestruction:1; quint32 isRootObjectInCreation:1; quint32 stronglyReferencedByParent:1; - quint32 dummy:25; + quint32 hasExtraObject:1; // used in QQmlDelegateModelItem::dataForObject to find the corresponding QQmlDelegateModelItem of an object + quint32 dummy:24; QQmlContext *publicContext; - // The incubator that is constructing this context if any - QQmlIncubatorPrivate *incubator; + union { + // The incubator that is constructing this context if any + QQmlIncubatorPrivate *incubator; + // a pointer to extra data, currently only used in QQmlDelegateModel + QObject *extraObject; + }; // Compilation unit for contexts that belong to a compiled type. QQmlRefPointer<QV4::ExecutableCompilationUnit> typeCompilationUnit; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 5fb5d73341..b8bd00bf2f 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -201,27 +201,19 @@ void QQmlEnginePrivate::defineModule() { const char uri[] = "QtQml"; - qmlRegisterType<QQmlComponent>(uri, 2, 0, "Component"); - qmlRegisterType<QObject>(uri, 2, 0, "QtObject"); - qmlRegisterType<QQmlBind>(uri, 2, 0, "Binding"); - qmlRegisterType<QQmlBind, 8>(uri, 2, 8, "Binding"); // Only available in >= 2.8 - qmlRegisterType<QQmlBind, 14>(uri, 2, 14, "Binding"); - - // TODO: We won't need Connections to be a custom type anymore once we can drop the - // automatic signal handler inference from undeclared properties. - qmlRegisterCustomType<QQmlConnections>(uri, 2, 0, "Connections", new QQmlConnectionsParser); - qmlRegisterCustomType<QQmlConnections, 3>(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3 - + qmlRegisterTypesAndRevisions< + QObjectForeign, #if QT_CONFIG(qml_animation) - qmlRegisterType<QQmlTimer>(uri, 2, 0, "Timer"); + QQmlTimer, #endif - - qmlRegisterType<QQmlLoggingCategory>(uri, 2, 8, "LoggingCategory"); // Only available in >= 2.8 - qmlRegisterType<QQmlLoggingCategory, 12>(uri, 2, 12, "LoggingCategory"); // Only available in >= 2.12 - #if QT_CONFIG(qml_locale) - qmlRegisterUncreatableType<QQmlLocale>(uri, 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()")); + QQmlLocale, #endif + QQmlComponent, + QQmlBind, + QQmlConnections, + QQmlLoggingCategory + >(uri, 2); } bool QQmlEnginePrivate::designerMode() diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 2c4bb36c8f..98c7823921 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -101,6 +101,13 @@ class QQmlProfiler; class QQmlPropertyCapture; class QQmlMetaObject; +struct QObjectForeign { + Q_GADGET + QML_FOREIGN(QObject) + QML_NAMED_ELEMENT(QtObject) + Q_CLASSINFO("QML.Root", "QML") +}; + // This needs to be declared here so that the pool for it can live in QQmlEnginePrivate. // The inline method definitions are in qqmljavascriptexpression_p.h class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 5c3ecbfb60..f0ef5360b0 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -61,7 +61,7 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext) QExplicitlySharedDataPointer<QQmlIncubatorPrivate> parentIncubator; QQmlContextData *cctxt = forContext; while (cctxt) { - if (cctxt->incubator) { + if (!cctxt->hasExtraObject && cctxt->incubator) { parentIncubator = cctxt->incubator; break; } @@ -149,7 +149,8 @@ void QQmlIncubatorPrivate::clear() } enginePriv = nullptr; if (!rootContext.isNull()) { - rootContext->incubator = nullptr; + if (!rootContext->hasExtraObject) + rootContext->incubator = nullptr; rootContext = nullptr; } diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index 859c36e11b..10e0dfcc38 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -94,6 +94,9 @@ private: class Q_QML_PRIVATE_EXPORT QQmlLocale { Q_GADGET + QML_NAMED_ELEMENT(Locale) + QML_UNCREATABLE("Locale cannot be instantiated. Use Qt.locale().") + QML_ADDED_IN_MINOR_VERSION(2) public: ~QQmlLocale(); diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h index ee5d9af2e7..c7377528b4 100644 --- a/src/qml/qml/qqmlloggingcategory_p.h +++ b/src/qml/qml/qqmlloggingcategory_p.h @@ -56,6 +56,7 @@ #include <QtCore/qloggingcategory.h> #include <QtQml/qqmlparserstatus.h> +#include <QtQml/qqml.h> QT_BEGIN_NAMESPACE @@ -66,6 +67,8 @@ class QQmlLoggingCategory : public QObject, public QQmlParserStatus Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 12) + QML_NAMED_ELEMENT(LoggingCategory) + QML_ADDED_IN_MINOR_VERSION(8) public: enum DefaultLogLevel { diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index c2674b402a..268d58a856 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -154,7 +154,7 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->extraData.cd->propertyValueSourceCast = type.valueSourceCast; d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast; d->extraData.cd->extFunc = type.extensionObjectCreate; - d->extraData.cd->customParser = type.customParser; + d->extraData.cd->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser); d->extraData.cd->registerEnumClassesUnscoped = true; if (type.extensionMetaObject) diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index d2e9d36d55..dfcab6181d 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -82,7 +82,6 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlR , propertyCaches(&compilationUnit->propertyCaches) , sharedState(new QQmlObjectCreatorSharedState) , topLevelCreator(true) - , hadRequiredProperties(false) , incubator(incubator) { init(parentContext); @@ -94,6 +93,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlR sharedState->allJavaScriptObjects = nullptr; sharedState->creationContext = creationContext; sharedState->rootContext = nullptr; + sharedState->hadRequiredProperties = false; if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) { Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler, @@ -1524,7 +1524,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex; QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex); if (property->isRequired) { - hadRequiredProperties = true; + sharedState->hadRequiredProperties = true; sharedState->requiredProperties.insert(propertyData, RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}}); } diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index c302660799..59e236c855 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -101,6 +101,7 @@ struct QQmlObjectCreatorSharedState : public QSharedData QQmlVmeProfiler profiler; QRecursionNode recursionNode; RequiredProperties requiredProperties; + bool hadRequiredProperties; }; class Q_QML_PRIVATE_EXPORT QQmlObjectCreator @@ -126,7 +127,7 @@ public: QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; } RequiredProperties &requiredProperties() {return sharedState->requiredProperties;} - bool componentHadRequiredProperties() const {return hadRequiredProperties;} + bool componentHadRequiredProperties() const {return sharedState->hadRequiredProperties;} private: QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState); @@ -173,7 +174,6 @@ private: const QQmlPropertyCacheVector *propertyCaches; QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState; bool topLevelCreator; - bool hadRequiredProperties; QQmlIncubatorPrivate *incubator; QObject *_qobject; diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index e6dd5e0b16..8111178320 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -52,17 +52,42 @@ // #include <functional> +#include <type_traits> #include <QtQml/qtqmlglobal.h> +#include <QtQml/qqmlparserstatus.h> +#include <QtQml/qqmllist.h> +#include <QtQml/qqmlpropertyvaluesource.h> #include <QtCore/qglobal.h> #include <QtCore/qvariant.h> #include <QtCore/qurl.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qdebug.h> + +#define QML_GETTYPENAMES \ + const char *className = T::staticMetaObject.className(); \ + const int nameLen = int(strlen(className)); \ + QVarLengthArray<char,48> pointerName(nameLen+2); \ + memcpy(pointerName.data(), className, size_t(nameLen)); \ + pointerName[nameLen] = '*'; \ + pointerName[nameLen+1] = '\0'; \ + const int listLen = int(strlen("QQmlListProperty<")); \ + QVarLengthArray<char,64> listName(listLen + nameLen + 2); \ + memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \ + memcpy(listName.data()+listLen, className, size_t(nameLen)); \ + listName[listLen+nameLen] = '>'; \ + listName[listLen+nameLen+1] = '\0'; + QT_BEGIN_NAMESPACE +class QQmlPropertyValueInterceptor; + namespace QQmlPrivate { struct CachedQmlUnit; +template<typename A> +using QQmlAttachedPropertiesFunc = A *(*)(QObject *); } namespace QV4 { @@ -77,7 +102,7 @@ struct Document; typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *); } -typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *); +using QQmlAttachedPropertiesFunc = QQmlPrivate::QQmlAttachedPropertiesFunc<QObject>; inline uint qHash(QQmlAttachedPropertiesFunc func, uint seed = 0) { @@ -98,6 +123,13 @@ class QJSValue; class QJSEngine; class QQmlEngine; class QQmlCustomParser; + +template<class T> +QQmlCustomParser *qmlCreateCustomParser() +{ + return nullptr; +} + namespace QQmlPrivate { void Q_QML_EXPORT qdeclarativeelement_destructor(QObject *); @@ -123,11 +155,62 @@ namespace QQmlPrivate }; template<typename T> + constexpr bool isConstructible() + { + return std::is_default_constructible<T>::value && std::is_base_of<QObject, T>::value; + } + + template<typename T> void createInto(void *memory) { new (memory) QQmlElement<T>; } template<typename T> + QObject *createSingletonInstance(QQmlEngine *, QJSEngine *) { return new T; } + + template<typename T> QObject *createParent(QObject *p) { return new T(p); } + using CreateIntoFunction = void (*)(void *); + using CreateSingletonFunction = QObject *(*)(QQmlEngine *, QJSEngine *); + using CreateParentFunction = QObject *(*)(QObject *); + + template<typename T, bool Constructible = isConstructible<T>()> + struct Constructors; + + template<typename T> + struct Constructors<T, true> + { + static constexpr CreateIntoFunction createInto + = QQmlPrivate::createInto<T>; + static constexpr CreateSingletonFunction createSingletonInstance + = QQmlPrivate::createSingletonInstance<T>; + }; + + template<typename T> + struct Constructors<T, false> + { + static constexpr CreateIntoFunction createInto = nullptr; + static constexpr CreateSingletonFunction createSingletonInstance = nullptr; + }; + + template<typename T, bool IsVoid = std::is_void<T>::value> + struct ExtendedType; + + // void means "not an extended type" + template<typename T> + struct ExtendedType<T, true> + { + static constexpr const CreateParentFunction createParent = nullptr; + static constexpr const QMetaObject *staticMetaObject = nullptr; + }; + + // If it's not void, we actually want an error if the ctor or the metaobject is missing. + template<typename T> + struct ExtendedType<T, false> + { + static constexpr const CreateParentFunction createParent = QQmlPrivate::createParent<T>; + static constexpr const QMetaObject *staticMetaObject = &T::staticMetaObject; + }; + template<class From, class To, int N> struct StaticCastSelectorClass { @@ -155,66 +238,103 @@ namespace QQmlPrivate } }; - template <typename T> - struct has_attachedPropertiesMember + template<typename...> + using QmlVoidT = void; + + // You can prevent subclasses from using the same attached type by specialzing this. + // This is reserved for internal types, though. + template<class T, class A> + struct OverridableAttachedType { - static bool const value = QQmlTypeInfo<T>::hasAttachedProperties; + using Type = A; }; - template <typename T, bool hasMember> - class has_attachedPropertiesMethod + template<class T, class = QmlVoidT<>, bool OldStyle = QQmlTypeInfo<T>::hasAttachedProperties> + struct QmlAttached { - public: - typedef int yes_type; - typedef char no_type; - - template<typename ReturnType> - static yes_type checkType(ReturnType *(*)(QObject *)); - static no_type checkType(...); - - static bool const value = sizeof(checkType(&T::qmlAttachedProperties)) == sizeof(yes_type); + using Type = void; + using Func = QQmlAttachedPropertiesFunc<QObject>; + static const QMetaObject *staticMetaObject() { return nullptr; } + static Func attachedPropertiesFunc() { return nullptr; } }; - template <typename T> - class has_attachedPropertiesMethod<T, false> + // Defined inline via QML_ATTACHED + template<class T> + struct QmlAttached<T, QmlVoidT<typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type>, false> { - public: - static bool const value = false; + // Normal attached properties + template <typename Parent, typename Attached> + struct Properties + { + using Func = QQmlAttachedPropertiesFunc<Attached>; + static const QMetaObject *staticMetaObject() { return &Attached::staticMetaObject; } + static Func attachedPropertiesFunc() { return Parent::qmlAttachedProperties; } + }; + + // Disabled via OverridableAttachedType + template<typename Parent> + struct Properties<Parent, void> + { + using Func = QQmlAttachedPropertiesFunc<QObject>; + static const QMetaObject *staticMetaObject() { return nullptr; }; + static Func attachedPropertiesFunc() { return nullptr; }; + }; + + using Type = typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type; + using Func = typename Properties<T, Type>::Func; + + static const QMetaObject *staticMetaObject() + { + return Properties<T, Type>::staticMetaObject(); + } + + static Func attachedPropertiesFunc() + { + return Properties<T, Type>::attachedPropertiesFunc(); + } }; - template<typename T, int N> - class AttachedPropertySelector + // Separately defined via QQmlTypeInfo + template<class T> + struct QmlAttached<T, QmlVoidT<decltype(T::qmlAttachedProperties)>, true> { - public: - static inline QQmlAttachedPropertiesFunc func() { return nullptr; } - static inline const QMetaObject *metaObject() { return nullptr; } + using Type = typename std::remove_pointer<decltype(T::qmlAttachedProperties(nullptr))>::type; + using Func = QQmlAttachedPropertiesFunc<Type>; + + static const QMetaObject *staticMetaObject() { return &Type::staticMetaObject; } + static Func attachedPropertiesFunc() { return T::qmlAttachedProperties; } }; - template<typename T> - class AttachedPropertySelector<T, 1> + + // This is necessary because both the type containing a default template parameter and the type + // instantiating the template need to have access to the default template parameter type. In + // this case that's T::QmlAttachedType. The QML_FOREIGN macro needs to befriend specific other + // types. Therefore we need some kind of "accessor". Because of compiler bugs in gcc and clang, + // we cannot befriend attachedPropertiesFunc() directly. Wrapping the actual access into another + // struct "fixes" that. For convenience we still want the free standing functions in addition. + template<class T> + struct QmlAttachedAccessor { - template<typename ReturnType> - static inline const QMetaObject *attachedPropertiesMetaObject(ReturnType *(*)(QObject *)) { - return &ReturnType::staticMetaObject; - } - public: - static inline QQmlAttachedPropertiesFunc func() { - return QQmlAttachedPropertiesFunc(&T::qmlAttachedProperties); + static QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc() + { + return QQmlAttachedPropertiesFunc<QObject>(QmlAttached<T>::attachedPropertiesFunc()); } - static inline const QMetaObject *metaObject() { - return attachedPropertiesMetaObject(&T::qmlAttachedProperties); + + static const QMetaObject *staticMetaObject() + { + return QmlAttached<T>::staticMetaObject(); } }; template<typename T> - inline QQmlAttachedPropertiesFunc attachedPropertiesFunc() + inline QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc() { - return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::func(); + return QmlAttachedAccessor<T>::attachedPropertiesFunc(); } template<typename T> inline const QMetaObject *attachedPropertiesMetaObject() { - return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::metaObject(); + return QmlAttachedAccessor<T>::staticMetaObject(); } enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent }; @@ -235,7 +355,7 @@ namespace QQmlPrivate const char *elementName; const QMetaObject *metaObject; - QQmlAttachedPropertiesFunc attachedPropertiesFunction; + QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction; const QMetaObject *attachedPropertiesMetaObject; int parserStatusCast; @@ -246,10 +366,38 @@ namespace QQmlPrivate const QMetaObject *extensionMetaObject; QQmlCustomParser *customParser; + int revision; // If this is extended ensure "version" is bumped!!! }; + struct RegisterTypeAndRevisions { + int version; + + int typeId; + int listId; + int objectSize; + void (*create)(void *); + + const char *uri; + int versionMajor; + + const QMetaObject *metaObject; + const QMetaObject *classInfoMetaObject; + + QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction; + const QMetaObject *attachedPropertiesMetaObject; + + int parserStatusCast; + int valueSourceCast; + int valueInterceptorCast; + + QObject *(*extensionObjectCreate)(QObject *); + const QMetaObject *extensionMetaObject; + + QQmlCustomParser *(*customParserFactory)(); + }; + struct RegisterInterface { int version; @@ -282,6 +430,19 @@ namespace QQmlPrivate // If this is extended ensure "version" is bumped!!! }; + struct RegisterSingletonTypeAndRevisions { + int version; + const char *uri; + int versionMajor; + + QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *); + const QMetaObject *instanceMetaObject; + const QMetaObject *classInfoMetaObject; + + int typeId; + std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3 + }; + struct RegisterCompositeType { QUrl url; const char *uri; @@ -317,7 +478,9 @@ namespace QQmlPrivate SingletonRegistration = 3, CompositeRegistration = 4, CompositeSingletonRegistration = 5, - QmlUnitCacheHookRegistration = 6 + QmlUnitCacheHookRegistration = 6, + TypeAndRevisionsRegistration = 7, + SingletonAndRevisionsRegistration = 8 }; int Q_QML_EXPORT qmlregister(RegistrationType, void *); @@ -329,7 +492,151 @@ namespace QQmlPrivate QObject *m_object; bool alreadyCalled = false; }; -} + + static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key) + { + if (!metaObject || !key) + return -1; + + const int offset = metaObject->classInfoOffset(); + for (int i = metaObject->classInfoCount() + offset - 1; i >= offset; --i) + if (qstrcmp(key, metaObject->classInfo(i).name()) == 0) { + return i; + } + return -1; + } + + inline const char *classInfo(const QMetaObject *metaObject, const char *key) + { + return metaObject->classInfo(indexOfOwnClassInfo(metaObject, key)).value(); + } + + inline int intClassInfo(const QMetaObject *metaObject, const char *key, int defaultValue = 0) + { + const int index = indexOfOwnClassInfo(metaObject, key); + return (index == -1) ? defaultValue + : QByteArray(metaObject->classInfo(index).value()).toInt(); + } + + inline bool boolClassInfo(const QMetaObject *metaObject, const char *key, + bool defaultValue = false) + { + const int index = indexOfOwnClassInfo(metaObject, key); + return (index == -1) ? defaultValue + : (QByteArray(metaObject->classInfo(index).value()) == "true"); + } + + inline const char *classElementName(const QMetaObject *metaObject) + { + const char *elementName = classInfo(metaObject, "QML.Element"); + if (qstrcmp(elementName, "auto") == 0) + return metaObject->className(); + if (qstrcmp(elementName, "anonymous") == 0) + return nullptr; + + if (!elementName || elementName[0] < 'A' || elementName[0] > 'Z') { + qWarning() << "Missing or unusable QML.Element class info \"" << elementName << "\"" + << "for" << metaObject->className(); + } + + return elementName; + } + + template<class T, class = QmlVoidT<>> + struct QmlExtended + { + using Type = void; + }; + + template<class T> + struct QmlExtended<T, QmlVoidT<typename T::QmlExtendedType>> + { + using Type = typename T::QmlExtendedType; + }; + + template<class T, class = QmlVoidT<>> + struct QmlResolved + { + using Type = T; + }; + + template<class T> + struct QmlResolved<T, QmlVoidT<typename T::QmlForeignType>> + { + using Type = typename T::QmlForeignType; + }; + + template<class T, class = QmlVoidT<>> + struct QmlSingleton + { + static constexpr bool Value = false; + }; + + template<class T> + struct QmlSingleton<T, QmlVoidT<typename T::QmlIsSingleton>> + { + static constexpr bool Value = bool(T::QmlIsSingleton::yes); + }; + + template<typename T> + void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor, + const QMetaObject *classInfoMetaObject) + { + QML_GETTYPENAMES + + RegisterSingletonTypeAndRevisions api = { + 0, + + uri, + versionMajor, + + nullptr, + + &T::staticMetaObject, + classInfoMetaObject, + + qRegisterNormalizedMetaType<T *>(pointerName.constData()), + Constructors<T>::createSingletonInstance + }; + + qmlregister(SingletonAndRevisionsRegistration, &api); + } + + template<typename T, typename E> + void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor, + const QMetaObject *classInfoMetaObject) + { + QML_GETTYPENAMES + + RegisterTypeAndRevisions type = { + 0, + qRegisterNormalizedMetaType<T *>(pointerName.constData()), + qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + int(sizeof(T)), + Constructors<T>::createInto, + + uri, + versionMajor, + + &T::staticMetaObject, + classInfoMetaObject, + + attachedPropertiesFunc<T>(), + attachedPropertiesMetaObject<T>(), + + StaticCastSelector<T, QQmlParserStatus>::cast(), + StaticCastSelector<T, QQmlPropertyValueSource>::cast(), + StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(), + + ExtendedType<E>::createParent, + ExtendedType<E>::staticMetaObject, + + &qmlCreateCustomParser<T> + }; + + qmlregister(TypeAndRevisionsRegistration, &type); + } +} // namespace QQmlPrivate QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypenotavailable_p.h b/src/qml/qml/qqmltypenotavailable_p.h index 33630bf507..8db5876b10 100644 --- a/src/qml/qml/qqmltypenotavailable_p.h +++ b/src/qml/qml/qqmltypenotavailable_p.h @@ -58,6 +58,9 @@ QT_BEGIN_NAMESPACE class QQmlTypeNotAvailable : public QObject { Q_OBJECT + QML_NAMED_ELEMENT(TypeNotAvailable) + QML_UNCREATABLE("Type not available.") + public: QQmlTypeNotAvailable(); }; diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index 95ad81d045..0601237c4b 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -218,6 +218,8 @@ struct QQmlEasingValueType { QEasingCurve v; Q_GADGET + QML_NAMED_ELEMENT(Easing) + QML_UNCREATABLE("Use the Type enum.") Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL) Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL) |