aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc10
-rw-r--r--src/qml/parser/qqmljs.g19
-rw-r--r--src/qml/parser/qqmljsast.cpp73
-rw-r--r--src/qml/qml/qml.pri2
-rw-r--r--src/qml/qml/qqml.h10
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp18
-rw-r--r--src/qml/qml/qqmlapplicationengine.h1
-rw-r--r--src/qml/qml/qqmlapplicationengine_p.h1
-rw-r--r--src/qml/qml/qqmlcomponent.cpp74
-rw-r--r--src/qml/qml/qqmlcomponent.h2
-rw-r--r--src/qml/qml/qqmlcomponent_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp24
-rw-r--r--src/qml/qml/qqmlimport.cpp10
-rw-r--r--src/qml/qml/qqmlloggingcategory_p.h2
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp18
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp7
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h4
-rw-r--r--src/qml/types/qqmlbind.cpp2
-rw-r--r--src/qml/types/qqmlconnections.cpp75
-rw-r--r--src/qml/types/qqmlconnections_p.h8
20 files changed, 281 insertions, 82 deletions
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index 9c106558fd..c71d18418a 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -274,6 +274,16 @@
*/
/*!
+ \fn int qmlRegisterAnonymousType(const char *uri, int versionMajor)
+
+ This template function registers the C++ type in the QML system. Instances of this type cannot be created from the QML system.
+
+ Use this function when the type will not be referenced by name. Use \a uri and \a versionMajor to indicate to which module the type belongs.
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
+*/
+
+/*!
\fn int qmlRegisterType()
\relates QQmlEngine
\overload
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 6c9760e472..8ac7633ae0 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -1246,8 +1246,13 @@ UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlId
sym(1).Node = node;
} break;
./
+OptionalSemicolon: | Semicolon;
+/.
+/* we need OptionalSemicolon because UiScriptStatement might already parse the last semicolon
+ and then we would miss a semicolon (see tests/auto/quick/qquickvisualdatamodel/data/objectlist.qml)*/
+ ./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement);
@@ -1259,7 +1264,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatemen
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
@@ -1273,7 +1278,7 @@ UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScr
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
@@ -1287,7 +1292,7 @@ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScri
} break;
./
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
@@ -1313,7 +1318,7 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
+UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
@@ -1341,7 +1346,7 @@ UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlI
} break;
./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
@@ -1364,7 +1369,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatem
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 700c191499..b63b2191b9 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -238,12 +238,11 @@ void StringLiteral::accept0(Visitor *visitor)
void TemplateLiteral::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (TemplateLiteral *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
void NumericLiteral::accept0(Visitor *visitor)
@@ -1015,13 +1014,13 @@ BoundNames FormalParameterList::boundNames() const
void FormalParameterList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(element, visitor);
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (FormalParameterList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->element, visitor);
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
FormalParameterList *FormalParameterList::finish(QQmlJS::MemoryPool *pool)
@@ -1321,12 +1320,14 @@ void UiPragma::accept0(Visitor *visitor)
void UiHeaderItemList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(headerItem, visitor);
- accept(next, visitor);
- }
+ bool accepted = true;
+ for (UiHeaderItemList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->headerItem, visitor);
- visitor->endVisit(this);
+ visitor->endVisit(it);
+ }
}
@@ -1391,14 +1392,15 @@ void PatternElement::boundNames(BoundNames *names)
void PatternElementList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(elision, visitor);
- accept(element, visitor);
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (PatternElementList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted) {
+ accept(it->elision, visitor);
+ accept(it->element, visitor);
+ }
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
void PatternElementList::boundNames(BoundNames *names)
@@ -1428,13 +1430,13 @@ void PatternProperty::boundNames(BoundNames *names)
void PatternPropertyList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(property, visitor);
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (PatternPropertyList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->property, visitor);
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
void PatternPropertyList::boundNames(BoundNames *names)
@@ -1479,13 +1481,14 @@ void ClassDeclaration::accept0(Visitor *visitor)
void ClassElementList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(property, visitor);
- if (next)
- accept(next, visitor);
- }
+ bool accepted = true;
+ for (ClassElementList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->property, visitor);
- visitor->endVisit(this);
+ visitor->endVisit(it);
+ }
}
ClassElementList *ClassElementList::finish()
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 08591b5237..2e9c6f3de6 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -186,5 +186,7 @@ qtConfig(qml-network) {
$$PWD/qqmltypeloadernetworkreplyproxy.cpp
}
+android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"'
+
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index bfd1c88b28..a93b012c70 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -102,7 +102,7 @@ class QQmlPropertyValueInterceptor;
void Q_QML_EXPORT qmlClearTypeRegistrations();
template<typename T>
-int qmlRegisterType()
+int qmlRegisterAnonymousType(const char *uri, int versionMajor=1)
{
QML_GETTYPENAMES
@@ -115,7 +115,7 @@ int qmlRegisterType()
nullptr,
QString(),
- nullptr, 0, 0, nullptr, &T::staticMetaObject,
+ uri, versionMajor, 0, nullptr, &T::staticMetaObject,
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -133,6 +133,12 @@ int qmlRegisterType()
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+template<typename T>
+QT_DEPRECATED_VERSION_X_5_14("Use qmlRegisterAnonymousType instead") int qmlRegisterType()
+{
+ return qmlRegisterAnonymousType<T>("");
+}
+
int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message);
template<typename T>
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index e93cfcadb9..d04a89b514 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -131,7 +131,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
q->objectCreated(nullptr, c->url());
break;
case QQmlComponent::Ready: {
- auto newObj = c->create();
+ auto newObj = initialProperties.empty() ? c->create() : c->createWithInitialProperties(initialProperties);
objects << newObj;
QObject::connect(newObj, &QObject::destroyed, q, [&](QObject *obj) { objects.removeAll(obj); });
q->objectCreated(objects.constLast(), c->url());
@@ -279,6 +279,22 @@ void QQmlApplicationEngine::load(const QString &filePath)
}
/*!
+ Sets the initial properties with which the QML component gets initialized after
+ it gets loaded.
+
+
+ \sa QQmlComponent::setInitialProperties
+ \sa QQmlApplicationEngine::load
+ \sa QQmlApplicationEngine::loadData
+ \since 5.14
+*/
+void QQmlApplicationEngine::setInitialProperties(const QVariantMap &initialProperties)
+{
+ Q_D(QQmlApplicationEngine);
+ d->initialProperties = initialProperties;
+}
+
+/*!
Loads the QML given in \a data. The object tree defined by \a data is
instantiated immediately.
diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h
index bb5d6b5d68..2b4de91154 100644
--- a/src/qml/qml/qqmlapplicationengine.h
+++ b/src/qml/qml/qqmlapplicationengine.h
@@ -66,6 +66,7 @@ public:
public Q_SLOTS:
void load(const QUrl &url);
void load(const QString &filePath);
+ void setInitialProperties(const QVariantMap &initialProperties);
void loadData(const QByteArray &data, const QUrl &url = QUrl());
Q_SIGNALS:
diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h
index 7a341847bd..1279e400e8 100644
--- a/src/qml/qml/qqmlapplicationengine_p.h
+++ b/src/qml/qml/qqmlapplicationengine_p.h
@@ -73,6 +73,7 @@ public:
void loadTranslations(const QUrl &rootFile);
void finishLoad(QQmlComponent *component);
QList<QObject *> objects;
+ QVariantMap initialProperties;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index fefe2bc685..ed8c41a582 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -350,6 +350,32 @@ void QQmlComponentPrivate::clear()
compilationUnit = nullptr;
}
+QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *context)
+{
+ if (!engine) {
+ // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
+ qWarning("QQmlComponent: Must provide an engine before calling create");
+ return nullptr;
+ }
+ if (!context)
+ context = engine->rootContext();
+ return q->beginCreate(context);
+}
+
+bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString& name, const QVariant &value)
+{
+ QQmlProperty prop(component, name);
+ auto privProp = QQmlPropertyPrivate::get(prop);
+ if (!prop.isValid() || !privProp->writeValueProperty(value, nullptr)) {
+ QQmlError error{};
+ error.setUrl(url);
+ error.setDescription(QLatin1String("Could not set property %1").arg(name));
+ state.errors.push_back(error);
+ return false;
+ } else
+ return true;
+}
+
/*!
\internal
*/
@@ -780,18 +806,28 @@ QObject *QQmlComponent::create(QQmlContext *context)
{
Q_D(QQmlComponent);
- if (!d->engine) {
- // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
- qWarning("QQmlComponent: Must provide an engine before calling create");
- return nullptr;
- }
+ QObject *rv = d->doBeginCreate(this, context);
+ if (rv)
+ completeCreate();
+ return rv;
+}
- if (!context)
- context = d->engine->rootContext();
+/*!
+ Create an object instance of this component, and initialize its toplevel properties according to initalPropertyValues.
- QObject *rv = beginCreate(context);
- if (rv)
+
+ \sa QQmlComponent::create
+ \since 5.14
+*/
+QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context)
+{
+ Q_D(QQmlComponent);
+
+ QObject *rv = d->doBeginCreate(this, context);
+ if (rv) {
+ setInitialProperties(rv, initialProperties);
completeCreate();
+ }
return rv;
}
@@ -1067,6 +1103,26 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
enginePriv->incubate(incubator, forContextData);
}
+/*!
+ Set toplevel properties of the component.
+
+
+ This method provides advanced control over component instance creation.
+ In general, programmers should use
+ \l QQmlComponent::createWithInitialProperties to create a component.
+
+ Use this method after beginCreate and before completeCreate has been called.
+ If a provided property does not exist, a warning is issued.
+
+ \since 5.14
+*/
+void QQmlComponent::setInitialProperties(QObject *component, const QVariantMap &properties)
+{
+ Q_D(QQmlComponent);
+ for (auto it = properties.constBegin(); it != properties.constEnd(); ++it)
+ d->setInitialProperty(component, it.key(), it.value());
+}
+
/*
This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
arguments instead of QQmlContext which means we don't have to construct the rather weighty
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index 39b6d4526f..f259c99b08 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -100,6 +100,8 @@ public:
QUrl url() const;
virtual QObject *create(QQmlContext *context = nullptr);
+ QObject *createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context = nullptr);
+ void setInitialProperties(QObject *component, const QVariantMap &properties);
virtual QObject *beginCreate(QQmlContext *);
virtual void completeCreate();
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 9a967501c9..2170646b89 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -143,6 +143,9 @@ public:
static QQmlComponentPrivate *get(QQmlComponent *c) {
return static_cast<QQmlComponentPrivate *>(QObjectPrivate::get(c));
}
+
+ QObject *doBeginCreate(QQmlComponent *q, QQmlContext *context);
+ bool setInitialProperty(QObject *component, const QString &name, const QVariant& value);
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 8bf660d2ec..5fb5d73341 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -206,14 +206,18 @@ void QQmlEnginePrivate::defineModule()
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, 1>(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3
+ qmlRegisterCustomType<QQmlConnections, 3>(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3
+
#if QT_CONFIG(qml_animation)
qmlRegisterType<QQmlTimer>(uri, 2, 0, "Timer");
#endif
qmlRegisterType<QQmlLoggingCategory>(uri, 2, 8, "LoggingCategory"); // Only available in >= 2.8
- qmlRegisterType<QQmlLoggingCategory, 1>(uri, 2, 12, "LoggingCategory"); // Only available in >= 2.12
+ 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()"));
@@ -796,11 +800,12 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
QList<QByteArray> parameterTypes = m.parameterTypes();
- int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
- void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
+ QScopedPointer<QMetaCallEvent> ev(new QMetaCallEvent(m.methodIndex(), 0, nullptr,
+ object, index,
+ parameterTypes.count() + 1));
- types[0] = 0; // return type
- args[0] = nullptr; // return value
+ void **args = ev->args();
+ int *types = ev->types();
for (int ii = 0; ii < parameterTypes.count(); ++ii) {
const QByteArray &typeName = parameterTypes.at(ii);
@@ -813,21 +818,16 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
"(Make sure '%s' is registered using qRegisterMetaType().)",
typeName.constData(), typeName.constData());
- free(types);
- free(args);
return;
}
args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
}
- QMetaCallEvent *ev = new QMetaCallEvent(m.methodIndex(), 0, nullptr, object, index,
- parameterTypes.count() + 1, types, args);
-
QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
mpo->target = object;
mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread.loadAcquire());
- QCoreApplication::postEvent(mpo, ev);
+ QCoreApplication::postEvent(mpo, ev.take());
} else {
QQmlNotifierEndpoint *ep = ddata->notify(index);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 7c9c0da01a..31a7004407 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1852,9 +1852,15 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
QLatin1String(".so"),
QLatin1String(".bundle")
};
-# else // Unix
+#else // Unix
static const QString prefix = QLatin1String("lib");
- static const QStringList suffixes = { QLatin1String(".so") };
+ static const QStringList suffixes = {
+# if defined(Q_OS_ANDROID)
+ QStringLiteral(LIBS_SUFFIX),
+# endif
+ QLatin1String(".so")
+
+ };
#endif
return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, suffixes, prefix);
diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h
index ece06e04b4..ee5d9af2e7 100644
--- a/src/qml/qml/qqmlloggingcategory_p.h
+++ b/src/qml/qml/qqmlloggingcategory_p.h
@@ -65,7 +65,7 @@ class QQmlLoggingCategory : public QObject, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
- Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 1)
+ Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 12)
public:
enum DefaultLogLevel {
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index 71964aca64..7dbcbe986b 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -711,21 +711,25 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
// Using -1 for the minor version ensures that we get the raw metaObject.
QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1);
- // Will be true if the assigned type inherits propertyMetaObject
- bool isAssignable = false;
- // Determine isAssignable value
if (propertyMetaObject) {
+ // Will be true if the assigned type inherits propertyMetaObject
+ // Determine isAssignable value
+ bool isAssignable = false;
QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
while (c && !isAssignable) {
isAssignable |= c == propertyMetaObject;
c = c->parent();
}
- }
- 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()))));
+ 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()))));
+ }
+ } else {
+ return qQmlCompileError(binding->valueLocation, tr("Cannot assign to property of unknown type \"%1\".")
+ .arg(QLatin1String(QMetaType::typeName(property->propType()))));
}
+
}
return noError;
}
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index 88f7b69dc2..2225191a9d 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -122,8 +122,10 @@ const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
return &QQmlRectValueType::staticMetaObject;
case QVariant::RectF:
return &QQmlRectFValueType::staticMetaObject;
+#if QT_CONFIG(easingcurve)
case QVariant::EasingCurve:
return &QQmlEasingValueType::staticMetaObject;
+#endif
#if QT_CONFIG(qml_itemmodel)
case QVariant::ModelIndex:
return &QQmlModelIndexValueType::staticMetaObject;
@@ -201,7 +203,9 @@ const QMetaObject *QQmlValueTypeFactory::metaObjectForMetaType(int type)
void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor, int versionMinor)
{
+#if QT_CONFIG(easingcurve)
qmlRegisterValueTypeEnums<QQmlEasingValueType>(uri, versionMajor, versionMinor, "Easing");
+#endif
}
QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
@@ -489,6 +493,7 @@ int QQmlRectValueType::bottom() const
return v.bottom();
}
+#if QT_CONFIG(easingcurve)
QQmlEasingValueType::Type QQmlEasingValueType::type() const
{
return (QQmlEasingValueType::Type)v.type();
@@ -572,6 +577,8 @@ QVariantList QQmlEasingValueType::bezierCurve() const
rv << QVariant(point.x()) << QVariant(point.y());
return rv;
}
+#endif // easingcurve
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 89f1b71d61..75150b3f32 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -58,7 +58,9 @@
#include <QtCore/qobject.h>
#include <QtCore/qrect.h>
+#if QT_CONFIG(easingcurve)
#include <QtCore/qeasingcurve.h>
+#endif
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
@@ -210,6 +212,7 @@ public:
int bottom() const;
};
+#if QT_CONFIG(easingcurve)
struct QQmlEasingValueType
{
QEasingCurve v;
@@ -260,6 +263,7 @@ public:
void setBezierCurve(const QVariantList &);
QVariantList bezierCurve() const;
};
+#endif
template<typename T>
int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 4b60108597..861243987f 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -357,7 +357,7 @@ void QQmlBind::setDelayed(bool delayed)
\li Binding.RestoreValue The original value is restored if it was a plain
value rather than a binding.
\li Binding.RestoreBindingOrValue The original value is always restored.
- \list
+ \endlist
The default value is Binding.RestoreBinding.
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 8ec754a9df..1e801641e5 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -44,6 +44,7 @@
#include <private/qqmlboundsignal_p.h>
#include <qqmlcontext.h>
#include <private/qqmlcontext_p.h>
+#include <private/qqmlvmemetaobject_p.h>
#include <qqmlinfo.h>
#include <QtCore/qdebug.h>
@@ -105,7 +106,7 @@ public:
\qml
MouseArea {
Connections {
- onClicked: foo(parameters)
+ function onClicked(mouse) { foo(mouse) }
}
}
\endqml
@@ -122,7 +123,7 @@ public:
\qml
Connections {
target: area
- onClicked: foo(parameters)
+ function onClicked(mouse) { foo(mouse) }
}
\endqml
@@ -270,8 +271,76 @@ void QQmlConnections::connectSignals()
if (!d->componentcomplete || (d->targetSet && !target()))
return;
- if (d->bindings.isEmpty())
+ if (d->bindings.isEmpty()) {
+ connectSignalsToMethods();
+ } else {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. "
+ "Use this syntax instead: function onFoo(<arguments>) { ... }");
+#endif
+ connectSignalsToBindings();
+ }
+}
+
+void QQmlConnections::connectSignalsToMethods()
+{
+ Q_D(QQmlConnections);
+
+ QObject *target = this->target();
+ QQmlData *ddata = QQmlData::get(this);
+ if (!ddata)
return;
+
+ QV4::ExecutionEngine *engine = ddata->context->engine->handle();
+
+ QQmlContextData *ctxtdata = ddata->outerContext;
+ for (int i = ddata->propertyCache->methodOffset(),
+ end = ddata->propertyCache->methodOffset() + ddata->propertyCache->methodCount();
+ i < end;
+ ++i) {
+
+ QQmlPropertyData *handler = ddata->propertyCache->method(i);
+ if (!handler || !handler->isVMEFunction())
+ continue;
+
+ const QString propName = handler->name(this);
+
+ QQmlProperty prop(target, propName);
+ if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
+ int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
+ auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
+ signal->setEnabled(d->enabled);
+
+ QV4::Scope scope(engine);
+ QV4::ScopedContext global(scope, engine->rootContext());
+
+ QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(this);
+ Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
+
+ QV4::ScopedFunctionObject method(scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
+
+ QQmlBoundSignalExpression *expression =
+ ctxtdata ? new QQmlBoundSignalExpression(
+ target, signalIndex, ctxtdata, this,
+ method->as<QV4::FunctionObject>()->function())
+ : nullptr;
+
+ signal->takeExpression(expression);
+ d->boundsignals += signal;
+ } else if (!d->ignoreUnknownSignals
+ && propName.startsWith(QLatin1String("on")) && propName.length() > 2
+ && propName.at(2).isUpper()) {
+ qmlWarning(this) << tr("Detected function \"%1\" in Connections element. "
+ "This is probably intended to be a signal handler but no "
+ "signal of the target matches the name.").arg(propName);
+ }
+ }
+}
+
+// TODO: Drop this as soon as we can
+void QQmlConnections::connectSignalsToBindings()
+{
+ Q_D(QQmlConnections);
QObject *target = this->target();
QQmlData *ddata = QQmlData::get(this);
QQmlContextData *ctxtdata = ddata ? ddata->outerContext : nullptr;
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index f6ad1eb46c..5d28e8e8be 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -69,7 +69,7 @@ class Q_AUTOTEST_EXPORT QQmlConnections : public QObject, public QQmlParserStatu
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
- Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 1)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 3)
Q_PROPERTY(bool ignoreUnknownSignals READ ignoreUnknownSignals WRITE setIgnoreUnknownSignals)
public:
@@ -87,14 +87,18 @@ public:
Q_SIGNALS:
void targetChanged();
- Q_REVISION(1) void enabledChanged();
+ Q_REVISION(3) void enabledChanged();
private:
void connectSignals();
+ void connectSignalsToMethods();
+ void connectSignalsToBindings();
+
void classBegin() override;
void componentComplete() override;
};
+// TODO: Drop this class as soon as we can
class QQmlConnectionsParser : public QQmlCustomParser
{
public: