aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/ftw/qintrusivelist.cpp4
-rw-r--r--src/qml/qml/qqml.cpp190
-rw-r--r--src/qml/qml/qqml.h125
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp2
-rw-r--r--src/qml/qml/qqmlbinding.cpp2
-rw-r--r--src/qml/qml/qqmlcomponent.cpp141
-rw-r--r--src/qml/qml/qqmlcomponent.h27
-rw-r--r--src/qml/qml/qqmlcomponent_p.h8
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h5
-rw-r--r--src/qml/qml/qqmlcontext.cpp4
-rw-r--r--src/qml/qml/qqmlcontext_p.h11
-rw-r--r--src/qml/qml/qqmldatablob.cpp2
-rw-r--r--src/qml/qml/qqmldatablob_p.h2
-rw-r--r--src/qml/qml/qqmldirdata.cpp2
-rw-r--r--src/qml/qml/qqmlengine.cpp26
-rw-r--r--src/qml/qml/qqmlengine_p.h7
-rw-r--r--src/qml/qml/qqmlglobal_p.h16
-rw-r--r--src/qml/qml/qqmlimport.cpp49
-rw-r--r--src/qml/qml/qqmlimport_p.h2
-rw-r--r--src/qml/qml/qqmlincubator.cpp58
-rw-r--r--src/qml/qml/qqmlincubator.h5
-rw-r--r--src/qml/qml/qqmlincubator_p.h9
-rw-r--r--src/qml/qml/qqmlinfo.cpp6
-rw-r--r--src/qml/qml/qqmllocale_p.h3
-rw-r--r--src/qml/qml/qqmlloggingcategory_p.h3
-rw-r--r--src/qml/qml/qqmlmetatype.cpp54
-rw-r--r--src/qml/qml/qqmlmetatype_p.h2
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp3
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h4
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp55
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h27
-rw-r--r--src/qml/qml/qqmlprivate.h392
-rw-r--r--src/qml/qml/qqmlproperty.cpp2
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h100
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp59
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp4
-rw-r--r--src/qml/qml/qqmlscriptdata.cpp6
-rw-r--r--src/qml/qml/qqmlscriptdata_p.h2
-rw-r--r--src/qml/qml/qqmltype.cpp86
-rw-r--r--src/qml/qml/qqmltype_p.h5
-rw-r--r--src/qml/qml/qqmltype_p_p.h22
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp74
-rw-r--r--src/qml/qml/qqmltypedata.cpp7
-rw-r--r--src/qml/qml/qqmltypeloader.cpp14
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent.cpp3
-rw-r--r--src/qml/qml/qqmltypenotavailable_p.h3
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp56
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp51
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h5
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp86
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h37
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp35
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp246
54 files changed, 1615 insertions, 536 deletions
diff --git a/src/qml/qml/ftw/qintrusivelist.cpp b/src/qml/qml/ftw/qintrusivelist.cpp
index eb337a4de0..2ebaffb375 100644
--- a/src/qml/qml/ftw/qintrusivelist.cpp
+++ b/src/qml/qml/ftw/qintrusivelist.cpp
@@ -150,6 +150,10 @@ Returns an STL-style iterator pointing to the imaginary item after the last item
Remove the current object from the list, and return an iterator to the next element.
*/
+/*!
+ \class QIntrusiveListNode
+ \internal
+*/
/*!
\fn QIntrusiveListNode::QIntrusiveListNode()
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index 8a50b51b5d..a33936647f 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -61,7 +61,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h
//From qqml.h
bool qmlProtectModule(const char *uri, int majVersion)
{
- return QQmlMetaType::protectModule(uri, majVersion);
+ return QQmlMetaType::protectModule(QString::fromUtf8(uri), majVersion);
}
//From qqml.h
@@ -79,6 +79,13 @@ int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *q
// From qqmlprivate.h
QObject *QQmlPrivate::RegisterSingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
{
+ if (!m_object) {
+ QQmlError error;
+ error.setDescription(QLatin1String("The registered singleton has already been deleted. Ensure that it outlives the engine."));
+ QQmlEnginePrivate::get(qeng)->warning(qeng, error);
+ return nullptr;
+ }
+
if (qeng->thread() != m_object->thread()) {
QQmlError error;
error.setDescription(QLatin1String("Registered object must live in the same thread as the engine it was registered with"));
@@ -96,33 +103,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 +310,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 a93b012c70..ae3893dd73 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,27 +131,13 @@ 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=1)
+int qmlRegisterAnonymousType(const char *uri, int versionMajor)
{
QML_GETTYPENAMES
@@ -133,11 +168,13 @@ int qmlRegisterAnonymousType(const char *uri, int versionMajor=1)
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+#if QT_DEPRECATED_SINCE(5, 14)
template<typename T>
QT_DEPRECATED_VERSION_X_5_14("Use qmlRegisterAnonymousType instead") int qmlRegisterType()
{
- return qmlRegisterAnonymousType<T>("");
+ return qmlRegisterAnonymousType<T>("", 1);
}
+#endif
int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message);
@@ -586,8 +623,10 @@ namespace QtQml {
Q_QML_EXPORT QQmlContext *qmlContext(const QObject *);
Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *);
#if QT_DEPRECATED_SINCE(5, 14)
- Q_QML_EXPORT QT_DEPRECATED QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
- Q_QML_EXPORT QT_DEPRECATED QObject *qmlAttachedPropertiesObject(
+ Q_QML_EXPORT QT_DEPRECATED_VERSION_X_5_14("Use qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc, bool")
+ QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
+ Q_QML_EXPORT QT_DEPRECATED_VERSION_X_5_14("Use qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc, bool")
+ QObject *qmlAttachedPropertiesObject(
int *, const QObject *, const QMetaObject *, bool create);
#endif
Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *,
@@ -720,6 +759,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/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index d04a89b514..adb036e2d0 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -279,7 +279,7 @@ void QQmlApplicationEngine::load(const QString &filePath)
}
/*!
- Sets the initial properties with which the QML component gets initialized after
+ Sets the \a initialProperties with which the QML component gets initialized after
it gets loaded.
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 3a437eab8d..2f6aabf61e 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -315,7 +315,7 @@ protected:
break;
default:
if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
- if (vtw->d()->valueType->metaType.id() == pd->propType()) {
+ if (vtw->d()->valueType()->metaType.id() == pd->propType()) {
return vtw->write(m_target.data(), pd->coreIndex());
}
}
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index ed8c41a582..f03f90e7f3 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -340,6 +340,16 @@ void QQmlComponentPrivate::fromTypeData(const QQmlRefPointer<QQmlTypeData> &data
}
}
+RequiredProperties &QQmlComponentPrivate::requiredProperties()
+{
+ return state.creator->requiredProperties();
+}
+
+bool QQmlComponentPrivate::hadRequiredProperties() const
+{
+ return state.creator->componentHadRequiredProperties();
+}
+
void QQmlComponentPrivate::clear()
{
if (typeData) {
@@ -364,8 +374,8 @@ QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *cont
bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString& name, const QVariant &value)
{
- QQmlProperty prop(component, name);
- auto privProp = QQmlPropertyPrivate::get(prop);
+ QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties());
+ QQmlPropertyPrivate *privProp = QQmlPropertyPrivate::get(prop);
if (!prop.isValid() || !privProp->writeValueProperty(value, nullptr)) {
QQmlError error{};
error.setUrl(url);
@@ -809,12 +819,17 @@ QObject *QQmlComponent::create(QQmlContext *context)
QObject *rv = d->doBeginCreate(this, context);
if (rv)
completeCreate();
+ if (rv && !d->requiredProperties().empty()) {
+ delete rv;
+ return nullptr;
+ }
return rv;
}
/*!
- Create an object instance of this component, and initialize its toplevel properties according to initalPropertyValues.
-
+ Create an object instance of this component, and initialize its toplevel
+ properties with \a initialProperties. \a context specifies the context
+ where the object instance is to be created.
\sa QQmlComponent::create
\since 5.14
@@ -828,6 +843,10 @@ QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialPr
setInitialProperties(rv, initialProperties);
completeCreate();
}
+ if (!d->requiredProperties().empty()) {
+ d->requiredProperties().clear();
+ return nullptr;
+ }
return rv;
}
@@ -980,6 +999,57 @@ void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionS
}
/*!
+ * \internal
+ * Finds the matching toplevel property with name \a name of the component \a createdComponent.
+ * If it was a required property or an alias to a required property contained in \a
+ * requiredProperties, it is removed from it.
+ *
+ * If wasInRequiredProperties is non-null, the referenced boolean is set to true iff the property
+ * was found in requiredProperties.
+ *
+ * Returns the QQmlProperty with name \a name (which might be invalid if there is no such property),
+ * for further processing (for instance, actually setting the property value).
+ *
+ * Note: This method is used in QQmlComponent and QQmlIncubator to manage required properties. Most
+ * classes which create components should not need it and should only need to call
+ * setInitialProperties.
+ */
+QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties &requiredProperties, bool* wasInRequiredProperties)
+{
+ QQmlProperty prop(createdComponent, name);
+ auto privProp = QQmlPropertyPrivate::get(prop);
+ if (prop.isValid()) {
+ // resolve outstanding required properties
+ auto targetProp = &privProp->core;
+ if (targetProp->isAlias()) {
+ auto target = createdComponent;
+ QQmlPropertyIndex originalIndex(targetProp->coreIndex());
+ QQmlPropertyIndex propIndex;
+ QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
+ QQmlData *data = QQmlData::get(target);
+ Q_ASSERT(data && data->propertyCache);
+ targetProp = data->propertyCache->property(propIndex.coreIndex());
+ } else {
+ // we need to get the pointer from the property cache instead of directly using
+ // targetProp else the lookup will fail
+ QQmlData *data = QQmlData::get(createdComponent);
+ Q_ASSERT(data && data->propertyCache);
+ targetProp = data->propertyCache->property(targetProp->coreIndex());
+ }
+ auto it = requiredProperties.find(targetProp);
+ if (it != requiredProperties.end()) {
+ if (wasInRequiredProperties)
+ *wasInRequiredProperties = true;
+ requiredProperties.erase(it);
+ } else {
+ if (wasInRequiredProperties)
+ *wasInRequiredProperties = false;
+ }
+ }
+ return prop;
+}
+
+/*!
This method provides advanced control over component instance creation.
In general, programmers should use QQmlComponent::create() to create a
component.
@@ -998,6 +1068,11 @@ void QQmlComponent::completeCreate()
void QQmlComponentPrivate::completeCreate()
{
+ const RequiredProperties& unsetRequiredProperties = requiredProperties();
+ for (const auto& unsetRequiredProperty: unsetRequiredProperties) {
+ QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ state.errors.push_back(error);
+ }
if (state.completePending) {
++creationDepth.localData();
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
@@ -1104,7 +1179,7 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
}
/*!
- Set toplevel properties of the component.
+ Set toplevel \a properties of the \a component.
This method provides advanced control over component instance creation.
@@ -1185,7 +1260,7 @@ struct QmlIncubatorObject : public QV4::Object
static ReturnedValue method_forceCompletion(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
void statusChanged(QQmlIncubator::Status);
- void setInitialState(QObject *);
+ void setInitialState(QObject *, RequiredProperties &requiredProperties);
};
}
@@ -1210,7 +1285,8 @@ public:
void setInitialState(QObject *o) override {
QV4::Scope scope(incubatorObject.engine());
QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject.as<QV4::QmlIncubatorObject>());
- i->setInitialState(o);
+ auto d = QQmlIncubatorPrivate::get(this);
+ i->setInitialState(o, d->requiredProperties());
}
QV4::PersistentValue incubatorObject; // keep a strong internal reference while incubating
@@ -1282,7 +1358,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
*/
-void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v)
+void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties &requiredProperties, QObject *createdComponent)
{
QV4::Scope scope(engine);
QV4::ScopedObject object(scope);
@@ -1301,6 +1377,7 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
break;
object = o;
const QStringList properties = name->toQString().split(QLatin1Char('.'));
+ bool isTopLevelProperty = properties.size() == 1;
for (int i = 0; i < properties.length() - 1; ++i) {
name = engine->newString(properties.at(i));
object = object->get(name);
@@ -1317,12 +1394,40 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
if (engine->hasException) {
engine->hasException = false;
continue;
+ } else if (isTopLevelProperty) {
+ auto prop = removePropertyFromRequired(createdComponent, name->toQString(), requiredProperties);
}
}
engine->hasException = false;
}
+QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty)
+{
+ QQmlError error;
+ QString description = QLatin1String("Required property %1 was not initialized").arg(unsetRequiredProperty.propertyName);
+ switch (unsetRequiredProperty.aliasesToRequired.size()) {
+ case 0:
+ break;
+ case 1: {
+ const auto info = unsetRequiredProperty.aliasesToRequired.first();
+ description += QLatin1String("\nIt can be set via the alias property %1 from %2\n").arg(info.propertyName, info.fileUrl.toString());
+ break;
+ }
+ default:
+ description += QLatin1String("\nIt can be set via one of the following alias properties:");
+ for (auto aliasInfo: unsetRequiredProperty.aliasesToRequired) {
+ description += QLatin1String("\n- %1 (%2)").arg(aliasInfo.propertyName, aliasInfo.fileUrl.toString());
+ }
+ description += QLatin1Char('\n');
+ }
+ error.setDescription(description);
+ error.setUrl(unsetRequiredProperty.fileUrl);
+ error.setLine(unsetRequiredProperty.location.line);
+ error.setColumn(unsetRequiredProperty.location.column);
+ return error;
+}
+
/*!
\internal
*/
@@ -1370,7 +1475,17 @@ void QQmlComponent::createObject(QQmlV4Function *args)
if (!valuemap->isUndefined()) {
QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext());
- QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap);
+ QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap, d->requiredProperties(), rv);
+ }
+ if (!d->requiredProperties().empty()) {
+ QList<QQmlError> errors;
+ for (const auto &requiredProperty: d->requiredProperties()) {
+ errors.push_back(QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(requiredProperty));
+ }
+ qmlWarning(rv, errors);
+ args->setReturnValue(QV4::Encode::null());
+ delete rv;
+ return;
}
d->completeCreate();
@@ -1502,7 +1617,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
}
// XXX used by QSGLoader
-void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate)
+void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties &requiredProperties)
{
QV4::ExecutionEngine *v4engine = engine->handle();
QV4::Scope scope(v4engine);
@@ -1511,7 +1626,7 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext
Q_ASSERT(object->as<QV4::Object>());
if (!valuemap.isUndefined())
- setInitialProperties(v4engine, qmlContext, object, valuemap);
+ setInitialProperties(v4engine, qmlContext, object, valuemap, requiredProperties, toCreate);
}
QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4)
@@ -1601,7 +1716,7 @@ void QV4::Heap::QmlIncubatorObject::destroy() {
Object::destroy();
}
-void QV4::QmlIncubatorObject::setInitialState(QObject *o)
+void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties &requiredProperties)
{
QQmlComponent_setQmlParent(o, d()->parent);
@@ -1610,7 +1725,7 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o)
QV4::Scope scope(v4);
QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o));
QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext);
- QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap);
+ QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap, requiredProperties, o);
}
}
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/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 2170646b89..a919eb45c0 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -86,8 +86,9 @@ public:
QObject *beginCreate(QQmlContextData *);
void completeCreate();
- void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate);
- static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v);
+ void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties &requiredProperties);
+ static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties &requiredProperties, QObject *createdComponent);
+ static QQmlError unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty);
virtual void incubateObject(
QQmlIncubator *incubationTask,
@@ -106,6 +107,8 @@ public:
qreal progress;
int start;
+ RequiredProperties& requiredProperties();
+ bool hadRequiredProperties() const;
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
struct ConstructionState {
@@ -134,6 +137,7 @@ public:
static void completeDeferred(QQmlEnginePrivate *enginePriv, DeferredState *deferredState);
static void complete(QQmlEnginePrivate *enginePriv, ConstructionState *state);
+ static QQmlProperty removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties& requiredProperties, bool *wasInRequiredProperties = nullptr);
QQmlEngine *engine;
QQmlGuardedContextData creationContext;
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..254b6cc3db 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -358,7 +358,7 @@ void QQmlContext::setContextProperties(const QVector<PropertyPair> &properties)
data->expressions = nullptr;
data->childContexts = nullptr;
- for (auto property : properties)
+ for (const auto &property : properties)
setContextProperty(property.name, property.value);
data->expressions = expressions;
@@ -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/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp
index 2183721d32..750fc6de50 100644
--- a/src/qml/qml/qqmldatablob.cpp
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -351,7 +351,7 @@ void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
status() == Error || status() == Complete || m_isDone)
return;
- for (auto existingDep: qAsConst(m_waitingFor))
+ for (const auto &existingDep: qAsConst(m_waitingFor))
if (existingDep.data() == blob)
return;
diff --git a/src/qml/qml/qqmldatablob_p.h b/src/qml/qml/qqmldatablob_p.h
index da3bbe2c1f..0450e94c02 100644
--- a/src/qml/qml/qqmldatablob_p.h
+++ b/src/qml/qml/qqmldatablob_p.h
@@ -242,7 +242,9 @@ private:
mutable QString m_finalUrlString;
// List of QQmlDataBlob's that are waiting for me to complete.
+protected:
QList<QQmlDataBlob *> m_waitingOnMe;
+private:
// List of QQmlDataBlob's that I am waiting for to complete.
QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
diff --git a/src/qml/qml/qqmldirdata.cpp b/src/qml/qml/qqmldirdata.cpp
index 7652cec322..de74dfdf9b 100644
--- a/src/qml/qml/qqmldirdata.cpp
+++ b/src/qml/qml/qqmldirdata.cpp
@@ -61,7 +61,7 @@ QQmlTypeLoader::Blob::PendingImportPtr QQmlQmldirData::import(QQmlTypeLoader::Bl
void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, QQmlTypeLoader::Blob::PendingImportPtr import)
{
- m_imports[blob] = import;
+ m_imports[blob] = std::move(import);
}
int QQmlQmldirData::priority(QQmlTypeLoader::Blob *blob) const
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index a6f7067552..1a868bfaa1 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/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 136159993a..3c540a6124 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -90,7 +90,7 @@ QT_BEGIN_NAMESPACE
\endcode
*/
#define qmlobject_connect(Sender, SenderType, Signal, Receiver, ReceiverType, Method) \
-{ \
+do { \
SenderType *sender = (Sender); \
ReceiverType *receiver = (Receiver); \
const char *signal = (Signal); \
@@ -98,11 +98,11 @@ QT_BEGIN_NAMESPACE
static int signalIdx = -1; \
static int methodIdx = -1; \
if (signalIdx < 0) { \
- Q_ASSERT(((int)(*signal) - '0') == QSIGNAL_CODE); \
+ Q_ASSERT((int(*signal) - '0') == QSIGNAL_CODE); \
signalIdx = SenderType::staticMetaObject.indexOfSignal(signal+1); \
} \
if (methodIdx < 0) { \
- int code = ((int)(*method) - '0'); \
+ int code = (int(*method) - '0'); \
Q_ASSERT(code == QSLOT_CODE || code == QSIGNAL_CODE); \
if (code == QSLOT_CODE) \
methodIdx = ReceiverType::staticMetaObject.indexOfSlot(method+1); \
@@ -111,7 +111,7 @@ QT_BEGIN_NAMESPACE
} \
Q_ASSERT(signalIdx != -1 && methodIdx != -1); \
QMetaObject::connect(sender, signalIdx, receiver, methodIdx, Qt::DirectConnection); \
-}
+} while (0)
/*!
Disconnect \a Signal of \a Sender from \a Method of \a Receiver. \a Signal must be
@@ -129,7 +129,7 @@ QT_BEGIN_NAMESPACE
\endcode
*/
#define qmlobject_disconnect(Sender, SenderType, Signal, Receiver, ReceiverType, Method) \
-{ \
+do { \
SenderType *sender = (Sender); \
ReceiverType *receiver = (Receiver); \
const char *signal = (Signal); \
@@ -137,11 +137,11 @@ QT_BEGIN_NAMESPACE
static int signalIdx = -1; \
static int methodIdx = -1; \
if (signalIdx < 0) { \
- Q_ASSERT(((int)(*signal) - '0') == QSIGNAL_CODE); \
+ Q_ASSERT((int(*signal) - '0') == QSIGNAL_CODE); \
signalIdx = SenderType::staticMetaObject.indexOfSignal(signal+1); \
} \
if (methodIdx < 0) { \
- int code = ((int)(*method) - '0'); \
+ int code = (int(*method) - '0'); \
Q_ASSERT(code == QSLOT_CODE || code == QSIGNAL_CODE); \
if (code == QSLOT_CODE) \
methodIdx = ReceiverType::staticMetaObject.indexOfSlot(method+1); \
@@ -150,7 +150,7 @@ QT_BEGIN_NAMESPACE
} \
Q_ASSERT(signalIdx != -1 && methodIdx != -1); \
QMetaObject::disconnect(sender, signalIdx, receiver, methodIdx); \
-}
+} while (0)
/*!
This method is identical to qobject_cast<T>() except that it does not require lazy
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 31a7004407..d69c2ac903 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -780,12 +780,12 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
typeStr + dotqml_string, // Type -> Type.qml
typeStr + dotuidotqml_string // Type -> Type.ui.qml
};
- for (uint i = 0; i < sizeof(urlsToTry) / sizeof(urlsToTry[0]); ++i) {
- exists = typeLoader->fileExists(localDirectoryPath, urlsToTry[i]);
+ for (const QString &urlToTry : urlsToTry) {
+ exists = typeLoader->fileExists(localDirectoryPath, urlToTry);
if (exists) {
#if defined(Q_OS_MACOS) || defined(Q_OS_WIN)
// don't let function.qml confuse the use of "new Function(...)" for example.
- if (!QQml_isFileCaseCorrect(localDirectoryPath + urlsToTry[i])) {
+ if (!QQml_isFileCaseCorrect(localDirectoryPath + urlToTry)) {
exists = false;
if (errors) {
QQmlError caseError;
@@ -797,7 +797,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
#else
Q_UNUSED(errors);
#endif
- qmlUrl = url + urlsToTry[i];
+ qmlUrl = url + urlToTry;
break;
}
}
@@ -1751,6 +1751,16 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
addImportPath(QStringLiteral("qrc:/qt-project.org/imports"));
addImportPath(QCoreApplication::applicationDirPath());
+#if defined(Q_OS_ANDROID)
+ addImportPath(QStringLiteral("qrc:/android_rcc_bundle/qml"));
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_BUNDLED_LIBS_PATH"))) {
+ const QString envImportPath = qEnvironmentVariable("QT_BUNDLED_LIBS_PATH");
+ QLatin1Char pathSep(':');
+ QStringList paths = envImportPath.split(pathSep, QString::SkipEmptyParts);
+ for (int ii = paths.count() - 1; ii >= 0; --ii)
+ addPluginPath(paths.at(ii));
+ }
+#endif
}
QQmlImportDatabase::~QQmlImportDatabase()
@@ -1798,6 +1808,18 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
if (!resolvedPath.endsWith(Slash))
resolvedPath += Slash;
+#if defined(Q_OS_ANDROID)
+ if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':') && qmldirPath.at(1) == QLatin1Char('/') &&
+ qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"), Qt::CaseInsensitive)) {
+ QString pluginName = qmldirPath.mid(21) + Slash + baseName;
+ auto bundledPath = resolvedPath + QLatin1String("lib") + pluginName.replace(QLatin1Char('/'), QLatin1Char('_'));
+ for (const QString &suffix : suffixes) {
+ const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix);
+ if (!absolutePath.isEmpty())
+ return absolutePath;
+ }
+ }
+#endif
resolvedPath += prefix + baseName;
for (const QString &suffix : suffixes) {
const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
@@ -1975,12 +1997,25 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
/*!
\internal
*/
-bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
+static bool registerPluginTypes(QObject *instance, const QString &basePath, const QString &uri,
+ const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
{
if (qmlImportTrace())
qDebug().nospace() << "QQmlImportDatabase::registerPluginTypes: " << uri << " from " << basePath;
- return QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors);
+
+ if (!QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors))
+ return false;
+
+ if (vmaj >= 0 && !typeNamespace.isEmpty() && !QQmlMetaType::protectModule(uri, vmaj)) {
+ QQmlError error;
+ error.setDescription(
+ QString::fromLatin1("Cannot protect module %1 %2 as it was never registered")
+ .arg(uri).arg(vmaj));
+ errors->append(error);
+ return false;
+ }
+
+ return true;
}
/*!
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index ea9c2eafb5..e24b3c447c 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -235,8 +235,6 @@ private:
const QString &baseName);
bool importStaticPlugin(QObject *instance, const QString &basePath, const QString &uri,
const QString &typeNamespace, int vmaj, QList<QQmlError> *errors);
- bool registerPluginTypes(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors);
void clearDirCache();
struct QmldirCache {
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index bc06226cbf..f0ef5360b0 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -43,6 +43,7 @@
#include "qqmlexpression_p.h"
#include "qqmlobjectcreator_p.h"
+#include <private/qqmlcomponent_p.h>
void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
{
@@ -60,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;
}
@@ -148,7 +149,8 @@ void QQmlIncubatorPrivate::clear()
}
enginePriv = nullptr;
if (!rootContext.isNull()) {
- rootContext->incubator = nullptr;
+ if (!rootContext->hasExtraObject)
+ rootContext->incubator = nullptr;
rootContext = nullptr;
}
@@ -296,6 +298,20 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
tresult = creator->create(subComponentToCreate, /*parent*/nullptr, &i);
if (!tresult)
errors = creator->errors;
+ else {
+ RequiredProperties& requiredProperties = creator->requiredProperties();
+ for (auto it = initialProperties.cbegin(); it != initialProperties.cend(); ++it) {
+ auto component = tresult;
+ auto name = it.key();
+ QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties);
+ if (!prop.isValid() || !prop.write(it.value())) {
+ QQmlError error{};
+ error.setUrl(compilationUnit->url());
+ error.setDescription(QLatin1String("Could not set property %1").arg(name));
+ errors.push_back(error);
+ }
+ }
+ }
enginePriv->dereferenceScarceResources();
if (watcher.hasRecursed())
@@ -312,8 +328,14 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
ddata->indestructible = true;
ddata->explicitIndestructibleSet = true;
ddata->rootObjectInCreation = false;
- if (q)
+ if (q) {
q->setInitialState(result);
+ if (!creator->requiredProperties().empty()) {
+ const auto& unsetRequiredProperties = creator->requiredProperties();
+ for (const auto& unsetRequiredProperty: unsetRequiredProperties)
+ errors << QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ }
+ }
}
if (watcher.hasRecursed())
@@ -657,6 +679,36 @@ QObject *QQmlIncubator::object() const
}
/*!
+Return a list of properties which are required but haven't been set yet.
+This list can be modified, so that subclasses which implement special logic
+setInitialProperties can mark properties set there as no longer required.
+
+\sa QQmlIncubator::setInitialProperties
+\since 5.15
+*/
+RequiredProperties &QQmlIncubatorPrivate::requiredProperties()
+{
+ return creator->requiredProperties();
+}
+
+bool QQmlIncubatorPrivate::hadRequiredProperties() const
+{
+ return creator->componentHadRequiredProperties();
+}
+
+/*!
+Stores a mapping from property names to initial values with which the incubated
+component will be initialized
+
+\sa QQmlComponent::setInitialProperties
+\since 5.15
+*/
+void QQmlIncubator::setInitialProperties(const QVariantMap &initialProperties)
+{
+ d->initialProperties = initialProperties;
+}
+
+/*!
Called when the status of the incubator changes. \a status is the new status.
The default implementation does nothing.
diff --git a/src/qml/qml/qqmlincubator.h b/src/qml/qml/qqmlincubator.h
index e68f6e3c45..f075407e73 100644
--- a/src/qml/qml/qqmlincubator.h
+++ b/src/qml/qml/qqmlincubator.h
@@ -47,6 +47,9 @@ QT_BEGIN_NAMESPACE
class QQmlEngine;
+class QQmlPropertyData;
+class QVariant;
+using QVariantMap = QMap<QString, QVariant>;
class QQmlIncubatorPrivate;
class Q_QML_EXPORT QQmlIncubator
@@ -84,6 +87,8 @@ public:
QObject *object() const;
+ void setInitialProperties(const QVariantMap &initialProperties);
+
protected:
virtual void statusChanged(Status);
virtual void setInitialState(QObject *);
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index 57ec8249cb..aadb147bd5 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -61,8 +61,12 @@
QT_BEGIN_NAMESPACE
+class QQmlPropertyData;
+struct RequiredPropertyInfo;
+using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>;
+
class QQmlIncubator;
-class QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
+class Q_QML_PRIVATE_EXPORT QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
{
public:
QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m);
@@ -97,11 +101,14 @@ public:
QIntrusiveList<QIPBase, &QIPBase::nextWaitingFor> waitingFor;
QRecursionNode recursion;
+ QVariantMap initialProperties;
void clear();
void forceCompletion(QQmlInstantiationInterrupt &i);
void incubate(QQmlInstantiationInterrupt &i);
+ RequiredProperties &requiredProperties();
+ bool hadRequiredProperties() const;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp
index 6322302422..2bfd2d5bb4 100644
--- a/src/qml/qml/qqmlinfo.cpp
+++ b/src/qml/qml/qqmlinfo.cpp
@@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo QtQml::qmlDebug(const QObject *object)
- \relates QQmlEngine
+ \relates QtQml
\since 5.9
Prints debug messages that include the file and line number for the
@@ -91,7 +91,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo QtQml::qmlInfo(const QObject *object)
- \relates QQmlEngine
+ \relates QtQml
Prints informational messages that include the file and line number for the
specified QML \a object.
@@ -119,7 +119,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo QtQml::qmlWarning(const QObject *object)
- \relates QQmlEngine
+ \relates QtQml
\since 5.9
Prints warning messages that include the file and line number for the
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 2c641d3845..1a5affb0ad 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)
@@ -342,7 +342,7 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
// NOTE: caller must hold a QMutexLocker on "data"
bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data,
- const char *uri, const QString &typeName, int majorVersion = -1)
+ const char *uri, const QString &typeName, int majorVersion)
{
if (!typeName.isEmpty()) {
if (typeName.at(0).isLower()) {
@@ -363,27 +363,16 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
if (uri && !typeName.isEmpty()) {
QString nameSpace = QString::fromUtf8(uri);
-
- if (data->typeRegistrationNamespace.isEmpty() && !nameSpace.isEmpty()) {
- // Is the target namespace protected against further registrations?
- if (data->protectedNamespaces.contains(nameSpace)) {
+ QQmlMetaTypeData::VersionedUri versionedUri;
+ versionedUri.uri = nameSpace;
+ versionedUri.majorVersion = majorVersion;
+ if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
+ if (qqtm->isLocked()){
QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install %1 '%2' into protected namespace '%3'"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
+ "Cannot install %1 '%2' into protected module '%3' version '%4'"));
+ data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion));
return false;
}
- } else if (majorVersion >= 0) {
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = nameSpace;
- versionedUri.majorVersion = majorVersion;
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
- if (qqtm->isLocked()){
- QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install %1 '%2' into protected module '%3' version '%4'"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion));
- return false;
- }
- }
}
}
@@ -477,8 +466,10 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe
bool fileImport = false;
if (*(type.uri) == '\0')
fileImport = true;
- if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri, typeName))
+ if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri,
+ typeName, type.versionMajor)) {
return QQmlType();
+ }
QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
addTypeToData(priv, data);
@@ -560,12 +551,12 @@ int QQmlMetaType::registerUnitCacheHook(
return 0;
}
-bool QQmlMetaType::protectModule(const char *uri, int majVersion)
+bool QQmlMetaType::protectModule(const QString &uri, int majVersion)
{
QQmlMetaTypeDataPtr data;
QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = QString::fromUtf8(uri);
+ versionedUri.uri = uri;
versionedUri.majorVersion = majVersion;
if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) {
@@ -683,8 +674,6 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
}
return false;
}
-
- data->protectedNamespaces.insert(uri);
} else {
// This is not an identified module - provide a warning
qWarning().nospace() << qPrintable(
@@ -698,11 +687,9 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
= QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
}
- data->typeRegistrationNamespace = typeNamespace;
const QByteArray bytes = uri.toUtf8();
const char *moduleId = bytes.constData();
iface->registerTypes(moduleId);
- data->typeRegistrationNamespace.clear();
}
if (!failures.isEmpty()) {
@@ -739,9 +726,16 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
const QUrl url = QQmlTypeLoader::normalize(QUrl(urlString));
QQmlMetaTypeDataPtr data;
- QQmlType ret(data->urlToType.value(url));
- if (ret.isValid() && ret.sourceUrl() == url)
- return ret;
+ {
+ QQmlType ret(data->urlToType.value(url));
+ if (ret.isValid() && ret.sourceUrl() == url)
+ return ret;
+ }
+ {
+ QQmlType ret(data->urlToNonFileImportType.value(url));
+ if (ret.isValid() && ret.sourceUrl() == url)
+ return ret;
+ }
const int dot = qualifiedType.indexOf(QLatin1Char('.'));
const QString typeName = dot < 0
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 6c2b0bb2a6..35d5386e1f 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -84,7 +84,7 @@ public:
static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
static void registerModule(const char *uri, int versionMajor, int versionMinor);
- static bool protectModule(const char *uri, int majVersion);
+ static bool protectModule(const QString &uri, int majVersion);
static int typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp
index 5dc0083f54..775bc8bdb4 100644
--- a/src/qml/qml/qqmlmetatypedata.cpp
+++ b/src/qml/qml/qqmlmetatypedata.cpp
@@ -69,6 +69,7 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
if (!types.at(i).isValid()) {
types[i] = QQmlType(priv);
priv->index = i;
+ priv->release();
return;
}
}
@@ -149,7 +150,7 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min
bool hasCopied = false;
for (int ii = 0; ii < types.count(); ++ii) {
- QQmlType currentType = types.at(ii);
+ const QQmlType &currentType = types.at(ii);
if (!currentType.isValid())
continue;
diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h
index 5239b635ce..ea796ee7c6 100644
--- a/src/qml/qml/qqmlmetatypedata_p.h
+++ b/src/qml/qml/qqmlmetatypedata_p.h
@@ -106,10 +106,6 @@ struct QQmlMetaTypeData
QList<QQmlPrivate::AutoParentFunction> parentFunctions;
QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit;
- QSet<QString> protectedNamespaces;
-
- QString typeRegistrationNamespace;
-
QHash<int, int> qmlLists;
QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index f89608cd5d..cf1795aafa 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -93,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,
@@ -445,6 +446,8 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QV4::ScopedString s(scope, v4->newString(stringValue));
_vmeMetaObject->setVMEProperty(property->coreIndex(), s);
} else {
+ // ### Qt 6: Doing the conversion here where we don't know the eventual target type is rather strange
+ // and caused for instance QTBUG-78943
QVariant value = QQmlStringConverters::variantFromString(stringValue);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
@@ -783,6 +786,23 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
+ QQmlPropertyData *const property = propertyData.at(i);
+ if (property) {
+ QQmlPropertyData* targetProperty = property;
+ if (targetProperty->isAlias()) {
+ // follow alias
+ auto target = _bindingTarget;
+ QQmlPropertyIndex originalIndex(targetProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
+ QQmlPropertyIndex propIndex;
+ QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
+ QQmlData *data = QQmlData::get(target);
+ Q_ASSERT(data && data->propertyCache);
+ targetProperty = data->propertyCache->property(propIndex.coreIndex());
+ }
+ sharedState->requiredProperties.remove(targetProperty);
+ }
+
+
if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
continue;
@@ -794,8 +814,6 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
continue;
}
- const QQmlPropertyData *property = propertyData.at(i);
-
if (property && property->isQList()) {
if (property->coreIndex() != currentListPropertyIndex) {
void *argv[1] = { (void*)&_currentList };
@@ -1504,10 +1522,43 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings)
_ddata->deferData(_compiledObjectIndex, compilationUnit, context);
+ for (int propertyIndex = 0; propertyIndex != _compiledObject->propertyCount(); ++propertyIndex) {
+ const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex;
+ QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
+ if (property->isRequired) {
+ sharedState->hadRequiredProperties = true;
+ sharedState->requiredProperties.insert(propertyData,
+ RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
+ }
+ }
+
if (_compiledObject->nFunctions > 0)
setupFunctions();
setupBindings();
+ for (int aliasIndex = 0; aliasIndex != _compiledObject->aliasCount(); ++aliasIndex) {
+ const QV4::CompiledData::Alias* alias = _compiledObject->aliasesBegin() + aliasIndex;
+ const auto originalAlias = alias;
+ while (alias->aliasToLocalAlias)
+ alias = _compiledObject->aliasesBegin() + alias->localAliasIndex;
+ Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ if (!context->idValues->wasSet())
+ continue;
+ QObject *target = context->idValues[alias->targetObjectId].data();
+ if (!target)
+ continue;
+ QQmlData *targetDData = QQmlData::get(target, /*create*/false);
+ if (!targetDData)
+ continue;
+ int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
+ QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex);
+ if (!targetProperty)
+ continue;
+ auto it = sharedState->requiredProperties.find(targetProperty);
+ if (it != sharedState->requiredProperties.end())
+ it->aliasesToRequired.push_back(AliasToRequiredInfo {compilationUnit->stringAt(originalAlias->nameIndex), compilationUnit->finalUrl()});
+ }
+
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
qSwap(_ddata, declarativeData);
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index ecdbcc56dd..59e236c855 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -66,6 +66,28 @@ class QQmlAbstractBinding;
class QQmlInstantiationInterrupt;
class QQmlIncubatorPrivate;
+struct AliasToRequiredInfo {
+ QString propertyName;
+ QUrl fileUrl;
+};
+
+/*!
+\internal
+This struct contains information solely used for displaying error messages
+\variable aliasesToRequired allows us to give the user a way to know which (aliasing) properties
+can be set to set the required property
+\sa QQmlComponentPrivate::unsetRequiredPropertyToQQmlError
+*/
+struct RequiredPropertyInfo
+{
+ QString propertyName;
+ QUrl fileUrl;
+ QV4::CompiledData::Location location;
+ QVector<AliasToRequiredInfo> aliasesToRequired;
+};
+
+using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>;
+
struct QQmlObjectCreatorSharedState : public QSharedData
{
QQmlContextData *rootContext;
@@ -78,6 +100,8 @@ struct QQmlObjectCreatorSharedState : public QSharedData
QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
QQmlVmeProfiler profiler;
QRecursionNode recursionNode;
+ RequiredProperties requiredProperties;
+ bool hadRequiredProperties;
};
class Q_QML_PRIVATE_EXPORT QQmlObjectCreator
@@ -102,6 +126,9 @@ public:
QQmlContextData *parentContextData() const { return parentContext.contextData(); }
QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
+ RequiredProperties &requiredProperties() {return sharedState->requiredProperties;}
+ bool componentHadRequiredProperties() const {return sharedState->hadRequiredProperties;}
+
private:
QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index e6dd5e0b16..27dac71571 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -52,17 +52,43 @@
//
#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 <QPointer>
+
+#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 +103,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 +124,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 +156,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 +239,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 +356,7 @@ namespace QQmlPrivate
const char *elementName;
const QMetaObject *metaObject;
- QQmlAttachedPropertiesFunc attachedPropertiesFunction;
+ QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction;
const QMetaObject *attachedPropertiesMetaObject;
int parserStatusCast;
@@ -246,10 +367,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 +431,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 +479,9 @@ namespace QQmlPrivate
SingletonRegistration = 3,
CompositeRegistration = 4,
CompositeSingletonRegistration = 5,
- QmlUnitCacheHookRegistration = 6
+ QmlUnitCacheHookRegistration = 6,
+ TypeAndRevisionsRegistration = 7,
+ SingletonAndRevisionsRegistration = 8
};
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
@@ -326,10 +490,154 @@ namespace QQmlPrivate
{
QObject *operator()(QQmlEngine *, QJSEngine *);
- QObject *m_object;
+ QPointer<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/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 5f57e0eca1..eff3e94fbd 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -885,7 +885,7 @@ void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags
QQmlData *data = QQmlData::get(object, true);
if (data->propertyCache) {
QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
- Q_ASSERT(propertyData && !propertyData->isAlias());
+ Q_ASSERT(propertyData);
}
#endif
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 9c7a69d571..39778aa328 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -152,9 +152,18 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
template <typename ObjectContainer>
inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
{
+ auto isAddressable = [](const QUrl &url) {
+ const QString fileName = url.fileName();
+ return !fileName.isEmpty() && fileName.front().isUpper();
+ };
+
const CompiledObject *obj = objectContainer->objectAt(objectIndex);
+ bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0
+ || obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0
+ || (((obj->flags & QV4::CompiledData::Object::IsComponent)
+ || (objectIndex == 0 && isAddressable(objectContainer->url())))
+ && !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType);
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0;
if (!needVMEMetaObject) {
auto binding = obj->bindingsBegin();
auto end = obj->bindingsEnd();
@@ -256,17 +265,8 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine
Q_ASSERT(typeRef);
QQmlType qmltype = typeRef->type;
if (!qmltype.isValid()) {
- QString propertyName = stringAt(context.instantiatingBinding->propertyNameIndex);
- if (imports->resolveType(propertyName, &qmltype, nullptr, nullptr, nullptr)) {
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- qmltype = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
- }
- }
+ imports->resolveType(stringAt(context.instantiatingBinding->propertyNameIndex),
+ &qmltype, nullptr, nullptr, nullptr);
}
const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
@@ -585,13 +585,13 @@ public:
QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
- void appendAliasPropertiesToMetaObjects();
+ void appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv);
- QQmlJS::DiagnosticMessage appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex);
+ QQmlJS::DiagnosticMessage appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv);
private:
- void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex);
- QQmlJS::DiagnosticMessage propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags);
+ void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv);
+ QQmlJS::DiagnosticMessage propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv);
void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
@@ -610,7 +610,7 @@ inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCre
}
template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects()
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv)
{
// skip the root object (index 0) as that one does not have a first object index originating
// from a binding.
@@ -620,15 +620,15 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie
continue;
const auto rootBinding = component.bindingsBegin();
- appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex);
+ appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex, enginePriv);
}
const int rootObjectIndex = 0;
- appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex);
+ appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex, enginePriv);
}
template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex)
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv)
{
QVector<int> objectsWithAliases;
collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
@@ -668,7 +668,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (allAliasTargetsExist(object)) {
- appendAliasesToPropertyCache(component, objectIndex);
+ appendAliasesToPropertyCache(component, objectIndex, enginePriv);
} else {
pendingObjects.append(objectIndex);
}
@@ -702,9 +702,8 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(
- const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion,
- QQmlPropertyData::Flags *propertyFlags)
+inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion,
+ QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv)
{
*type = 0;
bool writable = false;
@@ -736,7 +735,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
lastAlias = targetAlias;
} while (lastAlias->aliasToLocalAlias);
- return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags);
+ return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags, enginePriv);
}
const int targetObjectIndex = objectForId(component, alias.targetObjectId);
@@ -768,29 +767,46 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
Q_ASSERT(targetCache);
+
QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
Q_ASSERT(targetProperty);
- *type = targetProperty->propType();
+ // for deep aliases, valueTypeIndex is always set
+ if (!QQmlValueTypeFactory::isValueType(targetProperty->propType()) && valueTypeIndex != -1) {
+ // deep alias property
+ *type = targetProperty->propType();
+ targetCache = enginePriv->propertyCacheForType(*type);
+ Q_ASSERT(targetCache);
+ targetProperty = targetCache->property(valueTypeIndex);
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
- if (valueTypeIndex != -1) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- *type = QVariant::Int;
- else
- *type = valueTypeMetaObject->property(valueTypeIndex).userType();
+ *type = targetProperty->propType();
+ writable = targetProperty->isWritable();
+ resettable = targetProperty->isResettable();
+
} else {
- if (targetProperty->isEnum()) {
- *type = QVariant::Int;
+ // value type or primitive type or enum
+ *type = targetProperty->propType();
+
+ writable = targetProperty->isWritable();
+ resettable = targetProperty->isResettable();
+
+ if (valueTypeIndex != -1) {
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
+ if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
+ *type = QVariant::Int;
+ else
+ *type = valueTypeMetaObject->property(valueTypeIndex).userType();
} else {
- // Copy type flags
- propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
+ if (targetProperty->isEnum()) {
+ *type = QVariant::Int;
+ } else {
+ // Copy type flags
+ propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
- if (targetProperty->isVarProperty())
- propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
+ if (targetProperty->isVarProperty())
+ propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
+ }
}
}
}
@@ -802,7 +818,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
template <typename ObjectContainer>
inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
- const CompiledObject &component, int objectIndex)
+ const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv)
{
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (!object.aliasCount())
@@ -823,7 +839,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
int type = 0;
int minorVersion = 0;
QQmlPropertyData::Flags propertyFlags;
- QQmlJS::DiagnosticMessage error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags);
+ QQmlJS::DiagnosticMessage error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags, enginePriv);
if (error.isValid())
return error;
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index 7dbcbe986b..d7361ea2c6 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -49,6 +49,19 @@
QT_BEGIN_NAMESPACE
+static bool isPrimitiveType(int typeId)
+{
+ switch (typeId) {
+#define HANDLE_PRIMITIVE(Type, id, T) \
+ case QMetaType::Type:
+QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
+#undef HANDLE_PRIMITIVE
+ return true;
+ default:
+ return false;
+ }
+}
+
QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
: enginePrivate(enginePrivate)
, compilationUnit(compilationUnit)
@@ -281,11 +294,21 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
return recordError(binding->location, tr("Invalid grouped property access"));
}
} else {
- if (!enginePrivate->propertyCacheForType(pd->propType())) {
+ const int typeId = pd->propType();
+ if (isPrimitiveType(typeId)) {
+ return recordError(
+ binding->location,
+ tr("Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
+ .arg(name)
+ .arg(QString::fromLatin1(QMetaType::typeName(typeId)))
+ );
+ }
+
+ if (!enginePrivate->propertyCacheForType(typeId)) {
return recordError(binding->location,
tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is not a value type")
.arg(name)
- .arg(QString::fromLatin1(QMetaType::typeName(pd->propType())))
+ .arg(QString::fromLatin1(QMetaType::typeName(typeId)))
);
}
}
@@ -679,15 +702,21 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
return noError;
}
- if (QQmlMetaType::isInterface(property->propType())) {
+ const int propType = property->propType();
+ const auto rhsType = [&]() {
+ return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
+ ->inheritedTypeNameIndex);
+ };
+
+ if (QQmlMetaType::isInterface(propType)) {
// Can only check at instantiation time if the created sub-object successfully casts to the
// target interface.
return noError;
- } else if (property->propType() == QMetaType::QVariant || property->propType() == qMetaTypeId<QJSValue>()) {
+ } else if (propType == QMetaType::QVariant || propType == qMetaTypeId<QJSValue>()) {
// We can convert everything to QVariant :)
return noError;
} else if (property->isQList()) {
- const int listType = enginePrivate->listType(property->propType());
+ const int listType = enginePrivate->listType(propType);
if (!QQmlMetaType::isInterface(listType)) {
QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
if (!canCoerce(listType, source)) {
@@ -697,19 +726,23 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
return noError;
} else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
return noError;
- } else if (QQmlValueTypeFactory::isValueType(property->propType())) {
- auto typeName = QMetaType::typeName(property->propType());
+ } else if (isPrimitiveType(propType)) {
+ auto typeName = QString::fromUtf8(QMetaType::typeName(propType));
+ return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
+ .arg(rhsType())
+ .arg(propertyName)
+ .arg(typeName));
+ } else if (QQmlValueTypeFactory::isValueType(propType)) {
return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object")
- .arg(typeName ? QString::fromLatin1(typeName) : QString::fromLatin1("<unknown type>"))
- .arg(propertyName));
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
+ .arg(rhsType()).arg(propertyName));
+ } else if (propType == qMetaTypeId<QQmlScriptString>()) {
return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
} else {
// We want to use the raw metaObject here as the raw metaobject is the
// actual property type before we applied any extensions that might
// effect the properties on the type, but don't effect assignability
// Using -1 for the minor version ensures that we get the raw metaObject.
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1);
+ QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(propType, -1);
if (propertyMetaObject) {
// Will be true if the assigned type inherits propertyMetaObject
@@ -723,11 +756,11 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
if (!isAssignable) {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
- .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType()))));
+ .arg(rhsType()).arg(QLatin1String(QMetaType::typeName(propType))));
}
} else {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign to property of unknown type \"%1\".")
- .arg(QLatin1String(QMetaType::typeName(property->propType()))));
+ .arg(QLatin1String(QMetaType::typeName(propType))));
}
}
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
index 69b26894a8..6ac30d3ab5 100644
--- a/src/qml/qml/qqmlscriptblob.cpp
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -177,7 +177,7 @@ void QQmlScriptBlob::done()
}
if (!m_isModule) {
- m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
+ m_scriptData->typeNameCache.adopt(new QQmlTypeNameCache(m_importCache));
QSet<QString> ns;
@@ -195,7 +195,7 @@ void QQmlScriptBlob::done()
m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
- m_importCache.populateCache(m_scriptData->typeNameCache);
+ m_importCache.populateCache(m_scriptData->typeNameCache.data());
}
m_scripts.clear();
}
diff --git a/src/qml/qml/qqmlscriptdata.cpp b/src/qml/qml/qqmlscriptdata.cpp
index 0725f40d2a..ae268ca904 100644
--- a/src/qml/qml/qqmlscriptdata.cpp
+++ b/src/qml/qml/qqmlscriptdata.cpp
@@ -156,11 +156,7 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
void QQmlScriptData::clear()
{
- if (typeNameCache) {
- typeNameCache->release();
- typeNameCache = nullptr;
- }
-
+ typeNameCache = nullptr;
scripts.clear();
// An addref() was made when the QQmlCleanup was added to the engine.
diff --git a/src/qml/qml/qqmlscriptdata_p.h b/src/qml/qml/qqmlscriptdata_p.h
index 273ba3691f..80b65b699c 100644
--- a/src/qml/qml/qqmlscriptdata_p.h
+++ b/src/qml/qml/qqmlscriptdata_p.h
@@ -82,7 +82,7 @@ private:
public:
QUrl url;
QString urlString;
- QQmlTypeNameCache *typeNameCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 2a6831d898..874bcd4bca 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -91,6 +91,8 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
QQmlTypePrivate::~QQmlTypePrivate()
{
qDeleteAll(scopedEnums);
+ for (const auto &metaObject : metaObjects)
+ free(metaObject.metaObject);
switch (regType) {
case QQmlType::CppType:
delete extraData.cd->customParser;
@@ -154,27 +156,10 @@ bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, in
return module == d->module && vmajor == d->version_maj && vminor >= d->version_min;
}
-// returns the nearest _registered_ super class
-QQmlType QQmlType::superType() const
-{
- if (!d)
- return QQmlType();
- if (!d->haveSuperType && d->baseMetaObject) {
- const QMetaObject *mo = d->baseMetaObject->superClass();
- while (mo && !d->superType.isValid()) {
- d->superType = QQmlMetaType::qmlType(mo, d->module, d->version_maj, d->version_min);
- mo = mo->superClass();
- }
- d->haveSuperType = true;
- }
-
- return d->superType;
-}
-
-QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
+QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
{
Q_ASSERT(isComposite());
- if (!engine || !d)
+ if (!engine)
return QQmlType();
QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
if (td.isNull() || !td->isComplete())
@@ -184,7 +169,7 @@ QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
return QQmlMetaType::qmlType(mo);
}
-QQmlPropertyCache *QQmlType::compositePropertyCache(QQmlEnginePrivate *engine) const
+QQmlPropertyCache *QQmlTypePrivate::compositePropertyCache(QQmlEnginePrivate *engine) const
{
// similar logic to resolveCompositeBaseType
Q_ASSERT(isComposite());
@@ -279,24 +264,30 @@ void QQmlTypePrivate::init() const
lock.unlock();
}
-void QQmlTypePrivate::initEnums(const QQmlPropertyCache *cache) const
+void QQmlTypePrivate::initEnums(QQmlEnginePrivate *engine) const
{
- if ((isEnumFromBaseSetup || !baseMetaObject)
- && (isEnumFromCacheSetup || !cache)) {
+ const QQmlPropertyCache *cache = (!isEnumFromCacheSetup && isComposite())
+ ? compositePropertyCache(engine)
+ : nullptr;
+
+ const QMetaObject *metaObject = !isEnumFromCacheSetup
+ ? baseMetaObject // beware: It could be a singleton type without metaobject
+ : nullptr;
+
+ if (!cache && !metaObject)
return;
- }
init();
QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
- if (!isEnumFromCacheSetup && cache) {
+ if (cache) {
insertEnumsFromPropertyCache(cache);
isEnumFromCacheSetup = true;
}
- if (!isEnumFromBaseSetup && baseMetaObject) { // could be singleton type without metaobject
- insertEnums(baseMetaObject);
+ if (metaObject) {
+ insertEnums(metaObject);
isEnumFromBaseSetup = true;
}
}
@@ -404,7 +395,7 @@ void QQmlTypePrivate::createEnumConflictReport(const QMetaObject *metaObject, co
qWarning().noquote() << QLatin1String("Possible conflicting items:");
// find items with conflicting key
- for (const auto i : enumInfoList) {
+ for (const auto &i : qAsConst(enumInfoList)) {
if (i.enumKey == conflictingKey)
qWarning().noquote().nospace() << " " << i.metaObjectName << "." << i.enumName << "." << i.enumKey << " from scope "
<< i.metaEnumScope << " injected by " << i.path.join(QLatin1String("->"));
@@ -565,7 +556,7 @@ bool QQmlType::isInterface() const
bool QQmlType::isComposite() const
{
- return d && (d->regType == CompositeType || d->regType == CompositeSingletonType);
+ return d && d->isComposite();
}
bool QQmlType::isCompositeSingleton() const
@@ -634,7 +625,7 @@ QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivat
QQmlType base;
if (d->regType == CompositeType)
- base = resolveCompositeBaseType(engine);
+ base = d->resolveCompositeBaseType(engine);
return base.attachedPropertiesFunction(engine);
}
@@ -647,7 +638,7 @@ const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) c
QQmlType base;
if (d->regType == CompositeType)
- base = resolveCompositeBaseType(engine);
+ base = d->resolveCompositeBaseType(engine);
return base.attachedPropertiesType(engine);
}
@@ -666,7 +657,7 @@ int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const
QQmlType base;
if (d->regType == CompositeType)
- base = resolveCompositeBaseType(engine);
+ base = d->resolveCompositeBaseType(engine);
return base.attachedPropertiesId(engine);
}
#endif
@@ -706,24 +697,16 @@ int QQmlType::index() const
QUrl QQmlType::sourceUrl() const
{
- if (d) {
- if (d->regType == CompositeType)
- return d->extraData.fd->url;
- else if (d->regType == CompositeSingletonType)
- return d->extraData.sd->singletonInstanceInfo->url;
- }
- return QUrl();
+ return d ? d->sourceUrl() : QUrl();
}
int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const
{
Q_ASSERT(ok);
if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
-
*ok = true;
- d->initEnums(cache);
+ d->initEnums(engine);
int *rv = d->enums.value(name);
if (rv)
@@ -738,11 +721,9 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name
{
Q_ASSERT(ok);
if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
-
*ok = true;
- d->initEnums(cache);
+ d->initEnums(engine);
int *rv = d->enums.value(name);
if (rv)
@@ -757,10 +738,9 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool
{
Q_ASSERT(ok);
if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
*ok = true;
- d->initEnums(cache);
+ d->initEnums(engine);
int *rv = d->enums.value(name);
if (rv)
@@ -775,10 +755,9 @@ int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name
{
Q_ASSERT(ok);
if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
*ok = true;
- d->initEnums(cache);
+ d->initEnums(engine);
int *rv = d->scopedEnumIndex.value(name);
if (rv)
@@ -793,10 +772,9 @@ int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bo
{
Q_ASSERT(ok);
if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
*ok = true;
- d->initEnums(cache);
+ d->initEnums(engine);
int *rv = d->scopedEnumIndex.value(name);
if (rv)
@@ -845,10 +823,9 @@ int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scope
{
Q_ASSERT(ok);
if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
*ok = true;
- d->initEnums(cache);
+ d->initEnums(engine);
int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length()));
if (rv) {
@@ -868,10 +845,9 @@ int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scope
{
Q_ASSERT(ok);
if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
*ok = true;
- d->initEnums(cache);
+ d->initEnums(engine);
int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName));
if (rv) {
diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h
index 158fefad2c..ec27b38a73 100644
--- a/src/qml/qml/qqmltype_p.h
+++ b/src/qml/qml/qqmltype_p.h
@@ -182,12 +182,7 @@ public:
};
private:
- QQmlType superType() const;
- QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
- int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const;
- QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const;
friend uint qHash(const QQmlType &t, uint seed);
-
QQmlRefPointer<const QQmlTypePrivate> d;
};
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h
index d381e11df4..6a2d961de8 100644
--- a/src/qml/qml/qqmltype_p_p.h
+++ b/src/qml/qml/qqmltype_p_p.h
@@ -66,10 +66,30 @@ public:
QQmlTypePrivate(QQmlType::RegistrationType type);
void init() const;
- void initEnums(const QQmlPropertyCache *cache = nullptr) const;
+ void initEnums(QQmlEnginePrivate *engine) const;
void insertEnums(const QMetaObject *metaObject) const;
void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const;
+ QUrl sourceUrl() const
+ {
+ switch (regType) {
+ case QQmlType::CompositeType:
+ return extraData.fd->url;
+ case QQmlType::CompositeSingletonType:
+ return extraData.sd->singletonInstanceInfo->url;
+ default:
+ return QUrl();
+ }
+ }
+
+ bool isComposite() const
+ {
+ return regType == QQmlType::CompositeType || regType == QQmlType::CompositeSingletonType;
+ }
+
+ QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
+ QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const;
+
QQmlType::RegistrationType regType;
struct QQmlCppTypeData
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index e7633a1bba..9ff0e3fb9e 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -158,6 +158,9 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
QmlIR::QmlUnitGenerator qmlGenerator;
qmlGenerator.generate(*document, dependencyHasher);
+ if (!errors.isEmpty())
+ return nullptr;
+
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
= QV4::ExecutableCompilationUnit::create(std::move(
document->javaScriptCompilationUnit));
@@ -165,11 +168,7 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
compilationUnit->resolvedTypes = *resolvedTypes;
compilationUnit->propertyCaches = std::move(m_propertyCaches);
Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->objectCount()));
-
- if (errors.isEmpty())
- return compilationUnit;
- else
- return nullptr;
+ return compilationUnit;
}
void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
@@ -328,18 +327,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
auto *typeRef = resolvedType(binding->propertyNameIndex);
QQmlType type = typeRef ? typeRef->type : QQmlType();
- if (!type.isValid()) {
- if (imports->resolveType(propertyName, &type, nullptr, nullptr, nullptr)) {
- if (type.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(type.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- type = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
- }
- }
- }
+ if (!type.isValid())
+ imports->resolveType(propertyName, &type, nullptr, nullptr, nullptr);
const QMetaObject *attachedType = type.attachedPropertiesType(enginePrivate);
if (!attachedType)
@@ -1027,7 +1016,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
}
if (result == AllAliasesResolved) {
- QQmlJS::DiagnosticMessage error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
+ QQmlJS::DiagnosticMessage error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex, enginePrivate);
if (error.isValid()) {
recordError(error);
return false;
@@ -1154,23 +1143,42 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
if (!subProperty.isEmpty()) {
const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType());
if (!valueTypeMetaObject) {
- *error = qQmlCompileError(
- alias->referenceLocation,
- tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
+ // could be a deep alias
+ bool isDeepAlias = subProperty.at(0).isLower();
+ if (isDeepAlias) {
+ isDeepAlias = false;
+ for (auto it = targetObject->bindingsBegin(); it != targetObject->bindingsEnd(); ++it) {
+ auto binding = *it;
+ if (compiler->stringAt(binding.propertyNameIndex) == property) {
+ resolver = QQmlPropertyResolver(propertyCaches.at(binding.value.objectIndex));
+ QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
+ if (actualProperty) {
+ propIdx = QQmlPropertyIndex(propIdx.coreIndex(), actualProperty->coreIndex());
+ isDeepAlias = true;
+ }
+ }
+ }
+ }
+ if (!isDeepAlias) {
+ *error = qQmlCompileError(
+ alias->referenceLocation,
+ tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ break;
+ }
+ } else {
- int valueTypeIndex =
- valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
- if (valueTypeIndex == -1) {
- *error = qQmlCompileError(
- alias->referenceLocation,
- tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
- Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
+ int valueTypeIndex =
+ valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
+ if (valueTypeIndex == -1) {
+ *error = qQmlCompileError(
+ alias->referenceLocation,
+ tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ break;
+ }
+ Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
- propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
+ propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
+ }
} else {
if (targetProperty->isQObject())
alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
index 8d75b57fc1..cfdcf6aad5 100644
--- a/src/qml/qml/qqmltypedata.cpp
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -209,7 +209,7 @@ void QQmlTypeData::createTypeAndPropertyCaches(
QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator(
&m_compiledData->propertyCaches, m_compiledData.data());
- aliasCreator.appendAliasPropertiesToMetaObjects();
+ aliasCreator.appendAliasPropertiesToMetaObjects(engine);
pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
}
@@ -305,6 +305,7 @@ void QQmlTypeData::done()
QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
if (error.isValid()) {
setError(error);
+ qDeleteAll(resolvedTypeCache);
return;
}
}
@@ -614,6 +615,8 @@ void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCach
QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
m_compiledData = compiler.compile();
if (!m_compiledData) {
+ qDeleteAll(*resolvedTypeCache);
+ resolvedTypeCache->clear();
setError(compiler.compilationErrors());
return;
}
@@ -678,7 +681,7 @@ void QQmlTypeData::resolveTypes()
if (ref.type.isCompositeSingleton()) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
- if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies) {
+ if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies || m_waitingOnMe.contains(ref.typeData.data())) {
// TODO: give an error message? If so, we should record and show the path of the cycle.
continue;
}
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 3a18bbf7c9..c62f760ee3 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -491,7 +491,7 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, PendingImportPtr import,
{
QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
- data->setImport(this, import);
+ data->setImport(this, std::move(import));
data->setPriority(this, priority);
if (data->status() == Error) {
@@ -563,13 +563,7 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
QString qmldirFilePath;
QString qmldirUrl;
- if (QQmlMetaType::isLockedModule(import->uri, import->majorVersion)) {
- //Locked modules are checked first, to save on filesystem checks
- if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, QString(), QString(), false, errors))
- return false;
-
- } else if (m_importCache.locateQmldir(importDatabase, import->uri, import->majorVersion, import->minorVersion,
+ if (m_importCache.locateQmldir(importDatabase, import->uri, import->majorVersion, import->minorVersion,
&qmldirFilePath, &qmldirUrl)) {
// This is a local library import
if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
@@ -964,8 +958,10 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
bool QQmlTypeLoader::fileExists(const QString &path, const QString &file)
{
- if (path.isEmpty())
+ const QChar nullChar(QChar::Null);
+ if (path.isEmpty() || path.contains(nullChar) || file.isEmpty() || file.contains(nullChar))
return false;
+
Q_ASSERT(path.endsWith(QLatin1Char('/')));
if (path.at(0) == QLatin1Char(':')) {
// qrc resource
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent.cpp b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
index 238af9b710..8e983db756 100644
--- a/src/qml/qml/qqmltypeloaderqmldircontent.cpp
+++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
@@ -55,7 +55,8 @@ QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
{
QList<QQmlError> errors;
const QUrl url(uri);
- for (const auto parseError : m_parser.errors(uri)) {
+ const auto parseErrors = m_parser.errors(uri);
+ for (const auto &parseError : parseErrors) {
QQmlError error;
error.setUrl(url);
error.setLine(parseError.line);
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/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 931f37b35a..ef4a628a04 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -476,6 +476,34 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
}
// Fall through to base implementation
}
+
+ if (name->startsWithUpper()) {
+ bool ok = false;
+ int value = type.enumValue(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
+ if (ok) {
+ lookup->qmlEnumValueLookup.ic = This->internalClass();
+ lookup->qmlEnumValueLookup.encodedEnumValue
+ = QV4::Value::fromInt32(value).asReturnedValue();
+ lookup->getter = QQmlTypeWrapper::lookupEnumValue;
+ return lookup->getter(lookup, engine, *object);
+ }
+
+ value = type.scopedEnumIndex(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
+ if (ok) {
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(
+ scope, engine->memoryManager->allocate<QQmlScopedEnumWrapper>());
+ enumWrapper->d()->typePrivate = type.priv();
+ QQmlType::refHandle(enumWrapper->d()->typePrivate);
+ enumWrapper->d()->scopeEnumIndex = value;
+
+ lookup->qmlScopedEnumWrapperLookup.ic = This->internalClass();
+ lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper
+ = static_cast<Heap::Object*>(enumWrapper->heapObject());
+ lookup->getter = QQmlTypeWrapper::lookupScopedEnum;
+ return enumWrapper.asReturnedValue();
+ }
+ // Fall through to base implementation
+ }
// Fall through to base implementation
}
return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
@@ -519,6 +547,34 @@ ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngin
return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
}
+ReturnedValue QQmlTypeWrapper::lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base)
+{
+ auto *o = static_cast<Heap::Object *>(base.heapObject());
+ if (!o || o->internalClass != l->qmlEnumValueLookup.ic) {
+ l->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(l, engine, base);
+ }
+
+ return l->qmlEnumValueLookup.encodedEnumValue;
+}
+
+ReturnedValue QQmlTypeWrapper::lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base)
+{
+ Scope scope(engine);
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, static_cast<Heap::QQmlScopedEnumWrapper *>(
+ l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper));
+
+ auto *o = static_cast<Heap::Object *>(base.heapObject());
+ if (!o || o->internalClass != l->qmlScopedEnumWrapperLookup.ic) {
+ QQmlType::derefHandle(enumWrapper->d()->typePrivate);
+ l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper = nullptr;
+ l->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(l, engine, base);
+ }
+
+ return enumWrapper.asReturnedValue();
+}
+
void Heap::QQmlScopedEnumWrapper::destroy()
{
QQmlType::derefHandle(typePrivate);
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 6b51f421b3..7dc3f55310 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -115,6 +115,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base);
+ static ReturnedValue lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base);
+ static ReturnedValue lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base);
protected:
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index 2225191a9d..d83fc4bb48 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -65,11 +65,13 @@ struct QQmlValueTypeFactoryImpl
QQmlValueType *valueTypes[QVariant::UserType];
QHash<int, QQmlValueType *> userTypes;
QMutex mutex;
+
+ QQmlValueType invalidValueType;
};
QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
{
- std::fill_n(valueTypes, int(QVariant::UserType), nullptr);
+ std::fill_n(valueTypes, int(QVariant::UserType), &invalidValueType);
#if QT_CONFIG(qml_itemmodel)
// See types wrapped in qqmlmodelindexvaluetype_p.h
@@ -79,20 +81,18 @@ QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
{
- qDeleteAll(valueTypes, valueTypes + QVariant::UserType);
+ for (QQmlValueType *type : valueTypes) {
+ if (type != &invalidValueType)
+ delete type;
+ }
qDeleteAll(userTypes);
}
-bool QQmlValueTypeFactoryImpl::isValueType(int idx)
+bool isInternalType(int idx)
{
- if (idx >= QMetaType::User)
- return valueType(idx) != nullptr;
-
- if (idx < 0)
- return false;
-
// Qt internal types
switch (idx) {
+ case QMetaType::UnknownType:
case QMetaType::QStringList:
case QMetaType::QObjectStar:
case QMetaType::VoidStar:
@@ -101,12 +101,20 @@ bool QQmlValueTypeFactoryImpl::isValueType(int idx)
case QMetaType::QLocale:
case QMetaType::QImage: // scarce type, keep as QVariant
case QMetaType::QPixmap: // scarce type, keep as QVariant
- return false;
- default:
return true;
+ default:
+ return false;
}
}
+bool QQmlValueTypeFactoryImpl::isValueType(int idx)
+{
+ if (idx < 0 || isInternalType(idx))
+ return false;
+
+ return valueType(idx) != nullptr;
+}
+
const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
{
switch (t) {
@@ -168,15 +176,17 @@ QQmlValueType *QQmlValueTypeFactoryImpl::valueType(int idx)
}
QQmlValueType *rv = valueTypes[idx];
- if (!rv) {
+ if (rv == &invalidValueType) {
// No need for mutex protection - the most we can lose is a valueType instance
// TODO: Investigate the performance/memory characteristics of
// removing the preallocated array
- if (const QMetaObject *mo = metaObjectForMetaType(idx)) {
- rv = new QQmlValueType(idx, mo);
- valueTypes[idx] = rv;
- }
+ if (isInternalType(idx))
+ rv = valueTypes[idx] = nullptr;
+ else if (const QMetaObject *mo = metaObjectForMetaType(idx))
+ rv = valueTypes[idx] = new QQmlValueType(idx, mo);
+ else
+ rv = valueTypes[idx] = nullptr;
}
return rv;
@@ -208,6 +218,13 @@ void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor,
#endif
}
+QQmlValueType::QQmlValueType() :
+ _metaObject(nullptr),
+ gadgetPtr(nullptr),
+ metaType(QMetaType::UnknownType)
+{
+}
+
QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
: gadgetPtr(QMetaType::create(typeId))
, metaType(typeId)
@@ -225,7 +242,7 @@ QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
QQmlValueType::~QQmlValueType()
{
QObjectPrivate *op = QObjectPrivate::get(this);
- Q_ASSERT(op->metaObject == this);
+ Q_ASSERT(op->metaObject == nullptr || op->metaObject == this);
op->metaObject = nullptr;
::free(const_cast<QMetaObject *>(_metaObject));
metaType.destroy(gadgetPtr);
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 75150b3f32..0601237c4b 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -68,6 +68,7 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlValueType : public QObject, public QAbstractDynamicMetaObject
{
public:
+ QQmlValueType();
QQmlValueType(int userType, const QMetaObject *metaObject);
~QQmlValueType() override;
void read(QObject *, int);
@@ -92,7 +93,7 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlValueTypeFactory
{
public:
- static bool isValueType(int);
+ static bool isValueType(int idx);
static QQmlValueType *valueType(int idx);
static const QMetaObject *metaObjectForMetaType(int type);
@@ -217,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)
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index cf6553d129..f23921497c 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -96,29 +96,29 @@ using namespace QV4;
void Heap::QQmlValueTypeWrapper::destroy()
{
- if (gadgetPtr) {
- valueType->metaType.destruct(gadgetPtr);
- ::operator delete(gadgetPtr);
+ if (m_gadgetPtr) {
+ m_valueType->metaType.destruct(m_gadgetPtr);
+ ::operator delete(m_gadgetPtr);
}
- if (_propertyCache)
- _propertyCache->release();
+ if (m_propertyCache)
+ m_propertyCache->release();
Object::destroy();
}
void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const
{
- Q_ASSERT(valueType->metaType.id() == value.userType());
- if (gadgetPtr)
- valueType->metaType.destruct(gadgetPtr);
- if (!gadgetPtr)
- gadgetPtr = ::operator new(valueType->metaType.sizeOf());
- valueType->metaType.construct(gadgetPtr, value.constData());
+ Q_ASSERT(valueType()->metaType.id() == value.userType());
+ if (auto *gadget = gadgetPtr())
+ valueType()->metaType.destruct(gadget);
+ if (!gadgetPtr())
+ setGadgetPtr(::operator new(valueType()->metaType.sizeOf()));
+ valueType()->metaType.construct(gadgetPtr(), value.constData());
}
QVariant Heap::QQmlValueTypeWrapper::toVariant() const
{
- Q_ASSERT(gadgetPtr);
- return QVariant(valueType->metaType.id(), gadgetPtr);
+ Q_ASSERT(gadgetPtr());
+ return QVariant(valueType()->metaType.id(), gadgetPtr());
}
@@ -146,13 +146,13 @@ bool QQmlValueTypeReference::readReferenceValue() const
QQmlPropertyCache *cache = nullptr;
if (const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(variantReferenceType))
cache = QJSEnginePrivate::get(engine())->cache(mo);
- if (d()->gadgetPtr) {
- d()->valueType->metaType.destruct(d()->gadgetPtr);
- ::operator delete(d()->gadgetPtr);
+ if (d()->gadgetPtr()) {
+ d()->valueType()->metaType.destruct(d()->gadgetPtr());
+ ::operator delete(d()->gadgetPtr());
}
- d()->gadgetPtr =nullptr;
+ d()->setGadgetPtr(nullptr);
d()->setPropertyCache(cache);
- d()->valueType = QQmlValueTypeFactory::valueType(variantReferenceType);
+ d()->setValueType(QQmlValueTypeFactory::valueType(variantReferenceType));
if (!cache)
return false;
} else {
@@ -161,12 +161,12 @@ bool QQmlValueTypeReference::readReferenceValue() const
}
d()->setValue(variantReferenceValue);
} else {
- if (!d()->gadgetPtr) {
- d()->gadgetPtr = ::operator new(d()->valueType->metaType.sizeOf());
- d()->valueType->metaType.construct(d()->gadgetPtr, nullptr);
+ if (!d()->gadgetPtr()) {
+ d()->setGadgetPtr(::operator new(d()->valueType()->metaType.sizeOf()));
+ d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
}
// value-type reference
- void *args[] = { d()->gadgetPtr, nullptr };
+ void *args[] = { d()->gadgetPtr(), nullptr };
QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, args);
}
return true;
@@ -192,8 +192,8 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj
r->d()->object = object;
r->d()->property = property;
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->valueType = QQmlValueTypeFactory::valueType(typeId);
- r->d()->gadgetPtr = nullptr;
+ r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
+ r->d()->setGadgetPtr(nullptr);
return r->asReturnedValue();
}
@@ -204,8 +204,8 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria
Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>());
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->valueType = QQmlValueTypeFactory::valueType(typeId);
- r->d()->gadgetPtr = nullptr;
+ r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
+ r->d()->setGadgetPtr(nullptr);
r->d()->setValue(value);
return r->asReturnedValue();
}
@@ -223,9 +223,9 @@ bool QQmlValueTypeWrapper::toGadget(void *data) const
if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
if (!ref->readReferenceValue())
return false;
- const int typeId = d()->valueType->metaType.id();
+ const int typeId = d()->valueType()->metaType.id();
QMetaType::destruct(typeId, data);
- QMetaType::construct(typeId, data, d()->gadgetPtr);
+ QMetaType::construct(typeId, data, d()->gadgetPtr());
return true;
}
@@ -307,7 +307,7 @@ bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
int QQmlValueTypeWrapper::typeId() const
{
- return d()->valueType->metaType.id();
+ return d()->valueType()->metaType.id();
}
bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
@@ -315,10 +315,10 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
bool destructGadgetOnExit = false;
Q_ALLOCA_DECLARE(void, gadget);
if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>()) {
- if (!d()->gadgetPtr) {
- Q_ALLOCA_ASSIGN(void, gadget, d()->valueType->metaType.sizeOf());
- d()->gadgetPtr = gadget;
- d()->valueType->metaType.construct(d()->gadgetPtr, nullptr);
+ if (!d()->gadgetPtr()) {
+ Q_ALLOCA_ASSIGN(void, gadget, d()->valueType()->metaType.sizeOf());
+ d()->setGadgetPtr(gadget);
+ d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
destructGadgetOnExit = true;
}
if (!ref->readReferenceValue())
@@ -327,12 +327,12 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
int flags = 0;
int status = -1;
- void *a[] = { d()->gadgetPtr, nullptr, &status, &flags };
+ void *a[] = { d()->gadgetPtr(), nullptr, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty, propertyIndex, a);
if (destructGadgetOnExit) {
- d()->valueType->metaType.destruct(d()->gadgetPtr);
- d()->gadgetPtr = nullptr;
+ d()->valueType()->metaType.destruct(d()->gadgetPtr());
+ d()->setGadgetPtr(nullptr);
}
return true;
}
@@ -354,16 +354,16 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
// Prepare a buffer to pass to QMetaType::convert()
QString convertResult;
convertResult.~QString();
- if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->metaType.id(), &convertResult, QMetaType::QString)) {
+ if (QMetaType::convert(w->d()->gadgetPtr(), w->d()->valueType()->metaType.id(), &convertResult, QMetaType::QString)) {
result = convertResult;
} else {
- result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType->metaType.id()))
+ result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType()->metaType.id()))
+ QLatin1Char('(');
const QMetaObject *mo = w->d()->propertyCache()->metaObject();
const int propCount = mo->propertyCount();
for (int i = 0; i < propCount; ++i) {
if (mo->property(i).isDesignable()) {
- QVariant value = mo->property(i).readOnGadget(w->d()->gadgetPtr);
+ QVariant value = mo->property(i).readOnGadget(w->d()->gadgetPtr());
if (i > 0)
result += QLatin1String(", ");
result += value.toString();
@@ -387,7 +387,7 @@ Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
if (property->propType() == metatype) { \
cpptype v; \
void *args[] = { &v, nullptr }; \
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr), \
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), \
QMetaObject::ReadProperty, index, args); \
return QV4::Encode(constructor(v)); \
}
@@ -412,7 +412,7 @@ Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
v = QVariant(property->propType(), static_cast<void *>(nullptr));
args[0] = v.data();
}
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr), QMetaObject::ReadProperty,
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty,
index, args);
return engine->fromVariant(v);
#undef VALUE_TYPE_LOAD
@@ -604,7 +604,7 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
if (property.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
v = v.toInt();
- void *gadget = r->d()->gadgetPtr;
+ void *gadget = r->d()->gadgetPtr();
property.writeOnGadget(gadget, v);
@@ -620,7 +620,7 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
} else {
int flags = 0;
int status = -1;
- void *a[] = { r->d()->gadgetPtr, nullptr, &status, &flags };
+ void *a[] = { r->d()->gadgetPtr(), nullptr, &status, &flags };
QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
}
}
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index baac129afa..60079aa623 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -69,22 +69,45 @@ namespace Heap {
struct QQmlValueTypeWrapper : Object {
void init() { Object::init(); }
void destroy();
- QQmlPropertyCache *propertyCache() const { return _propertyCache; }
+
+ QQmlPropertyCache *propertyCache() const { return m_propertyCache; }
void setPropertyCache(QQmlPropertyCache *c) {
if (c)
c->addref();
- if (_propertyCache)
- _propertyCache->release();
- _propertyCache = c;
+ if (m_propertyCache)
+ m_propertyCache->release();
+ m_propertyCache = c;
+ }
+
+ void setValueType(QQmlValueType *valueType)
+ {
+ Q_ASSERT(valueType != nullptr);
+ m_valueType = valueType;
+ }
+
+ QQmlValueType *valueType() const
+ {
+ Q_ASSERT(m_valueType != nullptr);
+ return m_valueType;
+ }
+
+ void setGadgetPtr(void *gadgetPtr) const
+ {
+ m_gadgetPtr = gadgetPtr;
+ }
+
+ void *gadgetPtr() const
+ {
+ return m_gadgetPtr;
}
- mutable void *gadgetPtr;
- QQmlValueType *valueType;
void setValue(const QVariant &value) const;
QVariant toVariant() const;
private:
- QQmlPropertyCache *_propertyCache;
+ mutable void *m_gadgetPtr;
+ QQmlValueType *m_valueType;
+ QQmlPropertyCache *m_propertyCache;
};
}
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index b9d8fed243..9b5490b6e5 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -164,8 +164,19 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
QQmlData *targetDData = QQmlData::get(target, /*create*/false);
if (!targetDData)
return;
- int coreIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex).coreIndex();
+ QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
+ int coreIndex = encodedIndex.coreIndex();
+ int valueTypeIndex = encodedIndex.valueTypeIndex();
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
+ if (pd && valueTypeIndex != -1 && !QQmlValueTypeFactory::valueType(pd->propType())) {
+ // deep alias
+ QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(metaObject->compilationUnit->engine->qmlEngine());
+ auto const *newPropertyCache = enginePriv->propertyCacheForType(pd->propType());
+ void *argv[1] = { &target };
+ QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
+ Q_ASSERT(newPropertyCache);
+ pd = newPropertyCache->property(valueTypeIndex);
+ }
if (!pd)
return;
@@ -858,17 +869,23 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (!targetDData->propertyCache)
return -1;
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
- // Value type property
+ // Value type property or deep alias
QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType());
- Q_ASSERT(valueType);
+ if (valueType) {
- valueType->read(target, coreIndex);
- int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
+ valueType->read(target, coreIndex);
+ int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
- if (c == QMetaObject::WriteProperty)
- valueType->write(target, coreIndex, nullptr);
+ if (c == QMetaObject::WriteProperty)
+ valueType->write(target, coreIndex, nullptr);
- return rv;
+ return rv;
+ } else {
+ // deep alias
+ void *argv[1] = { &target };
+ QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
+ return QMetaObject::metacall(target, c, valueTypePropertyIndex, a);
+ }
} else {
return QMetaObject::metacall(target, c, coreIndex, a);
@@ -1180,6 +1197,8 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
const int aliasId = index - propOffset() - compiledObject->nProperties;
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
+ while (aliasData->aliasToLocalAlias)
+ aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
*target = ctxt->idValues[aliasData->targetObjectId].data();
if (!*target)
return false;
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 2e213e7dc3..d634a48443 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -229,8 +229,10 @@ OwnPropertyKeyIterator *QtObject::virtualOwnPropertyKeys(const Object *m, Value
}
/*!
-\qmlmethod bool Qt::isQtObject(object)
-Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
+ \qmlmethod bool Qt::isQtObject(object)
+
+ Returns \c true if \a object is a valid reference to a Qt or QML object,
+ \c false otherwise.
*/
ReturnedValue QtObject::method_isQtObject(const FunctionObject *, const Value *, const Value *argv, int argc)
{
@@ -241,10 +243,10 @@ ReturnedValue QtObject::method_isQtObject(const FunctionObject *, const Value *,
}
/*!
-\qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
+ \qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
-Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
-All components should be in the range 0-1 inclusive.
+ Returns a color with the specified \a red, \a green, \a blue, and \a alpha
+ components. All components should be in the range 0-1 (inclusive).
*/
ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
@@ -270,10 +272,10 @@ ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, cons
}
/*!
-\qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
+ \qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
-Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
-All components should be in the range 0-1 inclusive.
+ Returns a color with the specified \a hue, \a saturation, \a lightness, and \a alpha
+ components. All components should be in the range 0-1 (inclusive).
*/
ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -300,12 +302,12 @@ ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, cons
}
/*!
-\qmlmethod color Qt::hsva(real hue, real saturation, real value, real alpha)
+ \since 5.5
+ \qmlmethod color Qt::hsva(real hue, real saturation, real value, real alpha)
-Returns a color with the specified \c hue, \c saturation, \c value and \c alpha components.
-All components should be in the range 0-1 inclusive.
+ Returns a color with the specified \a hue, \a saturation, \a value and \a alpha
+ components. All components should be in the range 0-1 (inclusive).
-\since 5.5
*/
ReturnedValue QtObject::method_hsva(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -328,12 +330,12 @@ ReturnedValue QtObject::method_hsva(const FunctionObject *b, const Value *, cons
}
/*!
-\qmlmethod color Qt::colorEqual(color lhs, string rhs)
+ \qmlmethod color Qt::colorEqual(color lhs, string rhs)
-Returns true if both \c lhs and \c rhs yield equal color values. Both arguments
-may be either color values or string values. If a string value is supplied it
-must be convertible to a color, as described for the \l{colorbasictypedocs}{color}
-basic type.
+ Returns \c true if both \a lhs and \a rhs yield equal color values. Both
+ arguments may be either color values or string values. If a string value
+ is supplied it must be convertible to a color, as described for the
+ \l{colorbasictypedocs}{color} basic type.
*/
ReturnedValue QtObject::method_colorEqual(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -368,11 +370,9 @@ ReturnedValue QtObject::method_colorEqual(const FunctionObject *b, const Value *
}
/*!
-\qmlmethod rect Qt::rect(int x, int y, int width, int height)
-
-Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height.
+ \qmlmethod rect Qt::rect(int x, int y, int width, int height)
-The returned object has \c x, \c y, \c width and \c height attributes with the given values.
+ Returns a rect with the top-left corner at \a x, \a y and the specified \a width and \a height.
*/
ReturnedValue QtObject::method_rect(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -389,8 +389,9 @@ ReturnedValue QtObject::method_rect(const FunctionObject *b, const Value *, cons
}
/*!
-\qmlmethod point Qt::point(int x, int y)
-Returns a Point with the specified \c x and \c y coordinates.
+ \qmlmethod point Qt::point(int x, int y)
+
+ Returns a point with the specified \a x and \a y coordinates.
*/
ReturnedValue QtObject::method_point(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -405,8 +406,9 @@ ReturnedValue QtObject::method_point(const FunctionObject *b, const Value *, con
}
/*!
-\qmlmethod Qt::size(int width, int height)
-Returns a Size with the specified \c width and \c height.
+ \qmlmethod size Qt::size(int width, int height)
+
+ Returns a size with the specified \a width and \a height.
*/
ReturnedValue QtObject::method_size(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -421,12 +423,13 @@ ReturnedValue QtObject::method_size(const FunctionObject *b, const Value *, cons
}
/*!
-\qmlmethod Qt::font(object fontSpecifier)
-Returns a Font with the properties specified in the \c fontSpecifier object
-or the nearest matching font. The \c fontSpecifier object should contain
-key-value pairs where valid keys are the \l{fontbasictypedocs}{font} type's
-subproperty names, and the values are valid values for each subproperty.
-Invalid keys will be ignored.
+ \qmlmethod font Qt::font(object fontSpecifier)
+
+ Returns a font with the properties specified in the \a fontSpecifier object
+ or the nearest matching font. The \a fontSpecifier object should contain
+ key-value pairs where valid keys are the \l{fontbasictypedocs}{font} type's
+ subproperty names, and the values are valid values for each subproperty.
+ Invalid keys will be ignored.
*/
ReturnedValue QtObject::method_font(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -445,8 +448,9 @@ ReturnedValue QtObject::method_font(const FunctionObject *b, const Value *, cons
/*!
-\qmlmethod Qt::vector2d(real x, real y)
-Returns a Vector2D with the specified \c x and \c y.
+ \qmlmethod vector2d Qt::vector2d(real x, real y)
+
+ Returns a vector2d with the specified \a x and \a y values.
*/
ReturnedValue QtObject::method_vector2d(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -463,8 +467,9 @@ ReturnedValue QtObject::method_vector2d(const FunctionObject *b, const Value *,
}
/*!
-\qmlmethod Qt::vector3d(real x, real y, real z)
-Returns a Vector3D with the specified \c x, \c y and \c z.
+ \qmlmethod vector3d Qt::vector3d(real x, real y, real z)
+
+ Returns a vector3d with the specified \a x, \a y, and \a z values.
*/
ReturnedValue QtObject::method_vector3d(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -482,8 +487,9 @@ ReturnedValue QtObject::method_vector3d(const FunctionObject *b, const Value *,
}
/*!
-\qmlmethod Qt::vector4d(real x, real y, real z, real w)
-Returns a Vector4D with the specified \c x, \c y, \c z and \c w.
+ \qmlmethod vector4d Qt::vector4d(real x, real y, real z, real w)
+
+ Returns a vector4d with the specified \a x, \a y, \a z, and \a w values.
*/
ReturnedValue QtObject::method_vector4d(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -502,8 +508,9 @@ ReturnedValue QtObject::method_vector4d(const FunctionObject *b, const Value *,
}
/*!
-\qmlmethod Qt::quaternion(real scalar, real x, real y, real z)
-Returns a Quaternion with the specified \c scalar, \c x, \c y, and \c z.
+ \qmlmethod quaternion Qt::quaternion(real scalar, real x, real y, real z)
+
+ Returns a quaternion with the specified \a scalar, \a x, \a y, and \a z values.
*/
ReturnedValue QtObject::method_quaternion(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -522,13 +529,25 @@ ReturnedValue QtObject::method_quaternion(const FunctionObject *b, const Value *
}
/*!
-\qmlmethod Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44)
-Returns a Matrix4x4 with the specified values.
-Alternatively, the function may be called with a single argument
-where that argument is a JavaScript array which contains the sixteen
-matrix values.
-Finally, the function may be called with no arguments and the resulting
-matrix will be the identity matrix.
+ \qmlmethod matrix4x4 Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44)
+
+ Returns a matrix4x4 with the specified values.
+
+ The arguments correspond to their positions in the matrix:
+
+ \table
+ \row \li \a m11 \li \a m12 \li \a m13 \li \a m14
+ \row \li \a m21 \li \a m22 \li \a m23 \li \a m24
+ \row \li \a m31 \li \a m32 \li \a m33 \li \a m34
+ \row \li \a m41 \li \a m42 \li \a m43 \li \a m44
+ \endtable
+
+ Alternatively, the function may be called with a single argument
+ where that argument is a JavaScript array which contains the sixteen
+ matrix values.
+
+ Finally, the function may be called with no arguments and the resulting
+ matrix will be the identity matrix.
*/
ReturnedValue QtObject::method_matrix4x4(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -572,18 +591,19 @@ ReturnedValue QtObject::method_matrix4x4(const FunctionObject *b, const Value *,
}
/*!
-\qmlmethod color Qt::lighter(color baseColor, real factor)
-Returns a color lighter than \c baseColor by the \c factor provided.
+ \qmlmethod color Qt::lighter(color baseColor, real factor)
-If the factor is greater than 1.0, this functions returns a lighter color.
-Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
-the return color is darker, but we recommend using the Qt.darker() function for this purpose.
-If the factor is 0 or negative, the return value is unspecified.
+ Returns a color lighter than \a baseColor by the \a factor provided.
-The function converts the current RGB color to HSV, multiplies the value (V) component
-by factor and converts the color back to RGB.
+ If the factor is greater than 1.0, this functions returns a lighter color.
+ Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
+ the return color is darker, but we recommend using the Qt.darker() function for this purpose.
+ If the factor is 0 or negative, the return value is unspecified.
-If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
+ The function converts the current RGB color to HSV, multiplies the value (V) component
+ by factor and converts the color back to RGB.
+
+ If \a factor is not supplied, returns a color that is 50% lighter than \a baseColor (factor 1.5).
*/
ReturnedValue QtObject::method_lighter(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -610,19 +630,20 @@ ReturnedValue QtObject::method_lighter(const FunctionObject *b, const Value *, c
}
/*!
-\qmlmethod color Qt::darker(color baseColor, real factor)
-Returns a color darker than \c baseColor by the \c factor provided.
+ \qmlmethod color Qt::darker(color baseColor, real factor)
+
+ Returns a color darker than \a baseColor by the \a factor provided.
-If the factor is greater than 1.0, this function returns a darker color.
-Setting factor to 3.0 returns a color that has one-third the brightness.
-If the factor is less than 1.0, the return color is lighter, but we recommend using
-the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
-value is unspecified.
+ If the factor is greater than 1.0, this function returns a darker color.
+ Setting factor to 3.0 returns a color that has one-third the brightness.
+ If the factor is less than 1.0, the return color is lighter, but we recommend using
+ the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
+ value is unspecified.
-The function converts the current RGB color to HSV, divides the value (V) component
-by factor and converts the color back to RGB.
+ The function converts the current RGB color to HSV, divides the value (V) component
+ by factor and converts the color back to RGB.
-If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
+ If \a factor is not supplied, returns a color that is 50% darker than \a baseColor (factor 2.0).
*/
ReturnedValue QtObject::method_darker(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -650,7 +671,8 @@ ReturnedValue QtObject::method_darker(const FunctionObject *b, const Value *, co
/*!
\qmlmethod color Qt::tint(color baseColor, color tintColor)
- This function allows tinting one color with another.
+
+ This function allows tinting one color (\a baseColor) with another (\a tintColor).
The tint color should usually be mostly transparent, or you will not be
able to see the underlying color. The below example provides a slight red
@@ -670,7 +692,8 @@ ReturnedValue QtObject::method_darker(const FunctionObject *b, const Value *, co
\endqml
\image declarative-rect_tint.png
- Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
+ Tint is most useful when a subtle change is intended to be conveyed due to some event;
+ you can then use tinting to more effectively tune the visible color.
*/
ReturnedValue QtObject::method_tint(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -708,8 +731,8 @@ ReturnedValue QtObject::method_tint(const FunctionObject *b, const Value *, cons
/*!
\qmlmethod string Qt::formatDate(datetime date, variant format)
-Returns a string representation of \c date, optionally formatted according
-to \c format.
+Returns a string representation of \a date, optionally formatted according
+to \a format.
The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
property, a QDate, or QDateTime value. The \a format parameter may be any of
@@ -752,8 +775,8 @@ ReturnedValue QtObject::method_formatDate(const FunctionObject *b, const Value *
/*!
\qmlmethod string Qt::formatTime(datetime time, variant format)
-Returns a string representation of \c time, optionally formatted according to
-\c format.
+Returns a string representation of \a time, optionally formatted according to
+\a format.
The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
value. The \a format parameter may be any of the possible format values as
@@ -801,10 +824,10 @@ ReturnedValue QtObject::method_formatTime(const FunctionObject *b, const Value *
/*!
\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
-Returns a string representation of \c datetime, optionally formatted according to
-\c format.
+Returns a string representation of \a dateTime, optionally formatted according to
+\a format.
-The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
+The \a dateTime parameter may be a JavaScript \c Date object, a \l{date}{date}
property, a QDate, QTime, or QDateTime value.
If \a format is not provided, \a dateTime is formatted using
@@ -921,8 +944,8 @@ ReturnedValue QtObject::method_formatDateTime(const FunctionObject *b, const Val
/*!
\qmlmethod bool Qt::openUrlExternally(url target)
- Attempts to open the specified \c target url in an external application, based on the user's
- desktop preferences. Returns true if it succeeds, and false otherwise.
+ Attempts to open the specified \a target url in an external application, based on the user's
+ desktop preferences. Returns \c true if it succeeds, \c false otherwise.
\warning A return value of \c true indicates that the application has successfully requested
the operating system to open the URL in an external application. The external application may
@@ -942,6 +965,7 @@ ReturnedValue QtObject::method_openUrlExternally(const FunctionObject *b, const
/*!
\qmlmethod url Qt::resolvedUrl(url url)
+
Returns \a url resolved relative to the URL of the caller.
*/
ReturnedValue QtObject::method_resolvedUrl(const FunctionObject *b, const Value *, const Value *argv, int argc)
@@ -967,6 +991,7 @@ ReturnedValue QtObject::method_resolvedUrl(const FunctionObject *b, const Value
/*!
\qmlmethod list<string> Qt::fontFamilies()
+
Returns a list of the font families available to the application.
*/
ReturnedValue QtObject::method_fontFamilies(const FunctionObject *b, const Value *, const Value *, int argc)
@@ -980,7 +1005,7 @@ ReturnedValue QtObject::method_fontFamilies(const FunctionObject *b, const Value
/*!
\qmlmethod string Qt::md5(data)
-Returns a hex string of the md5 hash of \c data.
+Returns a hex string of the md5 hash of \a data.
*/
ReturnedValue QtObject::method_md5(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -995,7 +1020,7 @@ ReturnedValue QtObject::method_md5(const FunctionObject *b, const Value *, const
/*!
\qmlmethod string Qt::btoa(data)
-Binary to ASCII - this function returns a base64 encoding of \c data.
+Binary to ASCII - this function returns a base64 encoding of \a data.
*/
ReturnedValue QtObject::method_btoa(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -1043,9 +1068,9 @@ ReturnedValue QtObject::method_quit(const FunctionObject *b, const Value *, cons
This function causes the QQmlEngine::exit(int) signal to be emitted.
Within the \l {Prototyping with qmlscene}, this causes the launcher application to exit
- the specified return code. To exit from the event loop with a specified return code when this
- method is called, a C++ application can connect the QQmlEngine::exit(int) signal
- to the QCoreApplication::exit(int) slot.
+ the specified return code (\a retCode). To exit from the event loop with a specified
+ return code when this method is called, a C++ application can connect the
+ QQmlEngine::exit(int) signal to the QCoreApplication::exit(int) slot.
\sa quit()
*/
@@ -1318,13 +1343,13 @@ ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Va
\qmlmethod Qt::locale(name)
Returns a JS object representing the locale with the specified
- name, which has the format "language[_territory][.codeset][@modifier]"
+ \a name, which has the format "language[_territory][.codeset][@modifier]"
or "C", where:
\list
- \li language is a lowercase, two-letter, ISO 639 language code,
- \li territory is an uppercase, two-letter, ISO 3166 country code,
- \li and codeset and modifier are ignored.
+ \li \c language is a lowercase, two-letter, ISO 639 language code,
+ \li \c territory is an uppercase, two-letter, ISO 3166 country code, and
+ \li \c codeset and \c modifier are ignored.
\endlist
If the string violates the locale format, or language is not a
@@ -1372,7 +1397,8 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
/*!
\qmlmethod Qt::binding(function)
- Returns a JavaScript object representing a \l{Property Binding}{property binding}.
+ Returns a JavaScript object representing a \l{Property Binding}{property binding},
+ with a \a function that evaluates the binding.
There are two main use-cases for the function: firstly, to apply a
property binding imperatively from JavaScript code:
@@ -1941,30 +1967,32 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
THROW_GENERIC_ERROR("qsTr(): third argument (n) must be a number");
QString context;
- if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) {
- QString path = ctxt->urlString();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- int lastDot = path.lastIndexOf(QLatin1Char('.'));
- int length = lastDot - (lastSlash + 1);
- context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
- } else {
- CppStackFrame *frame = scope.engine->currentStackFrame;
- // The first non-empty source URL in the call stack determines the translation context.
- while (frame && context.isEmpty()) {
- if (CompiledData::CompilationUnitBase *baseUnit = frame->v4Function->compilationUnit) {
- const auto *unit = static_cast<const CompiledData::CompilationUnit *>(baseUnit);
- QString fileName = unit->fileName();
- QUrl url(unit->fileName());
- if (url.isValid() && url.isRelative()) {
- context = url.fileName();
- } else {
- context = QQmlFile::urlToLocalFileOrQrc(fileName);
- if (context.isEmpty() && fileName.startsWith(QLatin1String(":/")))
- context = fileName;
- }
- context = QFileInfo(context).baseName();
+ CppStackFrame *frame = scope.engine->currentStackFrame;
+ // The first non-empty source URL in the call stack determines the translation context.
+ while (frame && context.isEmpty()) {
+ if (CompiledData::CompilationUnitBase *baseUnit = frame->v4Function->compilationUnit) {
+ const auto *unit = static_cast<const CompiledData::CompilationUnit *>(baseUnit);
+ QString fileName = unit->fileName();
+ QUrl url(unit->fileName());
+ if (url.isValid() && url.isRelative()) {
+ context = url.fileName();
+ } else {
+ context = QQmlFile::urlToLocalFileOrQrc(fileName);
+ if (context.isEmpty() && fileName.startsWith(QLatin1String(":/")))
+ context = fileName;
}
- frame = frame->parent;
+ context = QFileInfo(context).baseName();
+ }
+ frame = frame->parent;
+ }
+
+ if (context.isEmpty()) {
+ if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) {
+ QString path = ctxt->urlString();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ int lastDot = path.lastIndexOf(QLatin1Char('.'));
+ int length = lastDot - (lastSlash + 1);
+ context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
}
}