aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/qqml.cpp23
-rw-r--r--src/qml/qml/qqmlcomponent.cpp10
-rw-r--r--src/qml/qml/qqmlcontext.h2
-rw-r--r--src/qml/qml/qqmlengine.cpp2
-rw-r--r--src/qml/qml/qqmlengine_p.h4
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp3
-rw-r--r--src/qml/qml/qqmlfile.cpp185
-rw-r--r--src/qml/qml/qqmlmetatype.cpp59
-rw-r--r--src/qml/qml/qqmlmetatype_p.h7
-rw-r--r--src/qml/qml/qqmlpropertybinding.cpp8
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp1
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp23
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h16
-rw-r--r--src/qml/qml/qqmlproxymetaobject.cpp10
-rw-r--r--src/qml/qml/qqmltype.cpp9
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp25
16 files changed, 265 insertions, 122 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index 8781e4bf50..b9c4865336 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -223,6 +223,7 @@ static QTypeRevision resolveModuleVersion(int moduleMajor)
/*!
* \enum QQmlModuleImportSpecialVersions
+ * \relates QQmlEngine
*
* Defines some special values that can be passed to the version arguments of
* qmlRegisterModuleImport() and qmlUnregisterModuleImport().
@@ -241,25 +242,26 @@ static QTypeRevision resolveModuleVersion(int moduleMajor)
*/
/*!
- * Registers an implicit import for module \a uri of major version \a majorVersion.
+ * \relates QQmlEngine
+ * Registers an implicit import for module \a uri of major version \a moduleMajor.
*
* This has the same effect as an \c import statement in a qmldir file: Whenever
* \a uri of version \a moduleMajor is imported, \a import of version
* \a importMajor. \a importMinor is automatically imported, too. If
- * \a importMajor is \l QmlModuleImportLatest the latest version
+ * \a importMajor is \l QQmlModuleImportLatest the latest version
* available of that module is imported, and \a importMinor does not matter. If
- * \a importMinor is \l QmlModuleImportLatest the latest minor version of a
- * \a importMajor is chosen. If \a importMajor is \l QmlModuleImportAuto the
+ * \a importMinor is \l QQmlModuleImportLatest the latest minor version of a
+ * \a importMajor is chosen. If \a importMajor is \l QQmlModuleImportAuto the
* version of \a import is version of \a uri being imported, and \a importMinor
- * does not matter. If \a moduleMajor is \a QmlModuleImportModuleAny the module
+ * does not matter. If \a moduleMajor is \l QQmlModuleImportModuleAny the module
* import is applied for any major version of \a uri. For example, you may
* specify that whenever any version of MyModule is imported, the latest version
* of MyOtherModule should be imported. Then, the following call would be
* appropriate:
*
* \code
- * qmlRegisterModuleImport("MyModule", QmlModuleImportModuleAny,
- * "MyOtherModule", QmlModuleImportLatest);
+ * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportLatest);
* \endcode
*
* Or, you may specify that whenever major version 5 of "MyModule" is imported,
@@ -273,8 +275,8 @@ static QTypeRevision resolveModuleVersion(int moduleMajor)
* imported whenever "MyModule" is imported, specify the following:
*
* \code
- * qmlRegisterModuleImport("MyModule", QmlModuleImportModuleAny,
- * "MyOtherModule", QmlModuleImportAuto);
+ * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportAuto);
* \endcode
*
* \sa qmlUnregisterModuleImport()
@@ -289,6 +291,7 @@ void qmlRegisterModuleImport(const char *uri, int moduleMajor,
/*!
+ * \relates QQmlEngine
* Removes a module import previously registered with qmlRegisterModuleImport()
*
* Calling this function makes sure that \a import of version
@@ -506,7 +509,7 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
const QTypeRevision added = revisionClassInfo(
type.classInfoMetaObject, "QML.AddedInVersion",
- QTypeRevision::fromMinorVersion(0));
+ QTypeRevision::fromVersion(type.version.majorVersion(), 0));
const QTypeRevision removed = revisionClassInfo(
type.classInfoMetaObject, "QML.RemovedInVersion");
const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index addee70b6b..f54eee3e72 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -862,8 +862,16 @@ QObject *QQmlComponent::create(QQmlContext *context)
Q_D(QQmlComponent);
QObject *rv = d->doBeginCreate(this, context);
- if (rv)
+ if (rv) {
completeCreate();
+ } else if (d->state.completePending) {
+ // overridden completCreate might assume that
+ // the object has actually been created
+ ++creationDepth.localData();
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(d->engine);
+ d->complete(ep, &d->state);
+ --creationDepth.localData();
+ }
if (rv && !d->requiredProperties().empty()) {
delete rv;
return nullptr;
diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h
index 82d15b8102..2da9541e5a 100644
--- a/src/qml/qml/qqmlcontext.h
+++ b/src/qml/qml/qqmlcontext.h
@@ -108,6 +108,4 @@ private:
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QList<QObject*>)
-
#endif // QQMLCONTEXT_H
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index e3840c8011..9963e4d957 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -163,7 +163,7 @@ QT_BEGIN_NAMESPACE
\endcode
*/
-bool QQmlEnginePrivate::qml_debugging_enabled = false;
+std::atomic<bool> QQmlEnginePrivate::qml_debugging_enabled{false};
bool QQmlEnginePrivate::s_designerMode = false;
bool QQmlEnginePrivate::designerMode()
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 630d32736b..97c2f95450 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -80,6 +80,8 @@
#include <QtCore/qstring.h>
#include <QtCore/qthread.h>
+#include <atomic>
+
QT_BEGIN_NAMESPACE
class QNetworkAccessManager;
@@ -250,7 +252,7 @@ public:
static bool designerMode();
static void activateDesignerMode();
- static bool qml_debugging_enabled;
+ static std::atomic<bool> qml_debugging_enabled;
mutable QMutex networkAccessManagerMutex;
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index ecac16102d..3a73a5eae1 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -184,7 +184,8 @@ void QQmlEngineExtensionPlugin::initializeEngine(QQmlEngine *engine, const char
/*!
\macro Q_IMPORT_QML_PLUGIN(PluginName)
- \relates <QQmlExtensionPlugin>
+ \since 6.2
+ \relates QQmlEngineExtensionPlugin
Ensures the plugin whose metadata-declaring class is named \a PluginName
is linked into static builds.
diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp
index 4db8981975..181efe49aa 100644
--- a/src/qml/qml/qqmlfile.cpp
+++ b/src/qml/qml/qqmlfile.cpp
@@ -65,6 +65,9 @@ static char file_string[] = "file";
#if defined(Q_OS_ANDROID)
static char assets_string[] = "assets";
static char content_string[] = "content";
+static char authority_externalstorage[] = "com.android.externalstorage.documents";
+static char authority_downloads_documents[] = "com.android.providers.downloads.documents";
+static char authority_media_documents[] = "com.android.providers.media.documents";
#endif
class QQmlFilePrivate;
@@ -505,6 +508,17 @@ bool QQmlFile::isSynchronous(const QString &url)
return false;
}
+#if defined(Q_OS_ANDROID)
+static bool hasLocalContentAuthority(const QUrl &url)
+{
+ const QString authority = url.authority();
+ return authority.isEmpty()
+ || authority == QLatin1String(authority_externalstorage)
+ || authority == QLatin1String(authority_downloads_documents)
+ || authority == QLatin1String(authority_media_documents);
+}
+#endif
+
/*!
Returns true if \a url is a local file that can be opened with QFile.
@@ -516,58 +530,116 @@ bool QQmlFile::isLocalFile(const QUrl &url)
{
QString scheme = url.scheme();
- if ((scheme.length() == 4 && 0 == scheme.compare(QLatin1String(file_string), Qt::CaseInsensitive)) ||
- (scheme.length() == 3 && 0 == scheme.compare(QLatin1String(qrc_string), Qt::CaseInsensitive))) {
+ // file: URLs with two slashes following the scheme can be interpreted as local files
+ // where the slashes are part of the path. Therefore, disregard the authority.
+ // See QUrl::toLocalFile().
+ if (scheme.length() == 4 && scheme.startsWith(QLatin1String(file_string), Qt::CaseInsensitive))
return true;
+ if (scheme.length() == 3 && scheme.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive))
+ return url.authority().isEmpty();
+
#if defined(Q_OS_ANDROID)
- } else if (scheme.length() == 6 && 0 == scheme.compare(QLatin1String(assets_string), Qt::CaseInsensitive)) {
- return true;
+ if (scheme.length() == 6
+ && scheme.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive))
+ return url.authority().isEmpty();
+ if (scheme.length() == 7
+ && scheme.startsWith(QLatin1String(content_string), Qt::CaseInsensitive))
+ return hasLocalContentAuthority(url);
#endif
- } else {
+ return false;
+}
+
+static bool hasScheme(const QString &url, const char *scheme, qsizetype schemeLength)
+{
+ const qsizetype urlLength = url.length();
+
+ if (urlLength < schemeLength + 1)
+ return false;
+
+ if (!url.startsWith(QLatin1String(scheme, scheme + schemeLength), Qt::CaseInsensitive))
+ return false;
+
+ if (url[schemeLength] != QLatin1Char(':'))
return false;
+
+ return true;
+}
+
+static qsizetype authorityOffset(const QString &url, qsizetype schemeLength)
+{
+ const qsizetype urlLength = url.length();
+
+ if (urlLength < schemeLength + 3)
+ return -1;
+
+ const QLatin1Char slash('/');
+ if (url[schemeLength + 1] == slash && url[schemeLength + 2] == slash) {
+ // Exactly two slashes denote an authority.
+ if (urlLength < schemeLength + 4 || url[schemeLength + 3] != slash)
+ return schemeLength + 3;
}
+
+ return -1;
}
+#if defined(Q_OS_ANDROID)
+static bool hasLocalContentAuthority(const QString &url, qsizetype schemeLength)
+{
+ const qsizetype offset = authorityOffset(url, schemeLength);
+ if (offset == -1)
+ return true; // no authority is a local authority.
+
+ const QString authorityAndPath = url.sliced(offset);
+ return authorityAndPath.startsWith(QLatin1String(authority_externalstorage))
+ || authorityAndPath.startsWith(QLatin1String(authority_downloads_documents))
+ || authorityAndPath.startsWith(QLatin1String(authority_media_documents));
+}
+
+#endif
+
/*!
Returns true if \a url is a local file that can be opened with QFile.
-Local file urls have either a qrc:/ or file:// scheme.
+Local file urls have either a qrc: or file: scheme.
-\note On Android, urls with assets:/ scheme are also considered local files.
+\note On Android, urls with assets: or content: scheme are also considered local files.
*/
bool QQmlFile::isLocalFile(const QString &url)
{
- if (url.length() < 5 /* qrc:/ */)
+ if (url.length() < 4 /* qrc: */)
return false;
- QChar f = url[0];
-
- if (f == QLatin1Char('f') || f == QLatin1Char('F')) {
-
- return url.length() >= 7 /* file:// */ &&
- url.startsWith(QLatin1String(file_string), Qt::CaseInsensitive) &&
- url[4] == QLatin1Char(':') && url[5] == QLatin1Char('/') && url[6] == QLatin1Char('/');
-
- } else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
-
- return url.length() >= 5 /* qrc:/ */ &&
- url.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive) &&
- url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
-
+ switch (url[0].toLatin1()) {
+ case 'f':
+ case 'F': {
+ // file: URLs with two slashes following the scheme can be interpreted as local files
+ // where the slashes are part of the path. Therefore, disregard the authority.
+ // See QUrl::toLocalFile().
+ const qsizetype fileLength = strlen(file_string);
+ return url.startsWith(QLatin1String(file_string, file_string + fileLength),
+ Qt::CaseInsensitive)
+ && url.length() > fileLength
+ && url[fileLength] == QLatin1Char(':');
}
+ case 'q':
+ case 'Q':
+ return hasScheme(url, qrc_string, strlen(qrc_string))
+ && authorityOffset(url, strlen(qrc_string)) == -1;
#if defined(Q_OS_ANDROID)
- else if (f == QLatin1Char('a') || f == QLatin1Char('A')) {
- return url.length() >= 8 /* assets:/ */ &&
- url.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive) &&
- url[6] == QLatin1Char(':') && url[7] == QLatin1Char('/');
- } else if (f == QLatin1Char('c') || f == QLatin1Char('C')) {
- return url.length() >= 9 /* content:/ */ &&
- url.startsWith(QLatin1String(content_string), Qt::CaseInsensitive) &&
- url[7] == QLatin1Char(':') && url[8] == QLatin1Char('/');
- }
+ case 'a':
+ case 'A':
+ return hasScheme(url, assets_string, strlen(assets_string))
+ && authorityOffset(url, strlen(assets_string)) == -1;
+ case 'c':
+ case 'C':
+ return hasScheme(url, content_string, strlen(content_string))
+ && hasLocalContentAuthority(url, strlen(content_string));
#endif
+ default:
+ break;
+ }
return false;
}
@@ -585,15 +657,14 @@ QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
}
#if defined(Q_OS_ANDROID)
- else if (url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0) {
- if (url.authority().isEmpty())
+ if (url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0)
+ return url.authority().isEmpty() ? url.toString() : QString();
+ if (url.scheme().compare(QLatin1String("content"), Qt::CaseInsensitive) == 0) {
+ if (hasLocalContentAuthority(url))
return url.toString();
return QString();
- } else if (url.scheme().compare(QLatin1String("content"), Qt::CaseInsensitive) == 0) {
- return url.toString();
}
#endif
-
return url.toLocalFile();
}
@@ -603,11 +674,28 @@ static QString toLocalFile(const QString &url)
if (!file.isLocalFile())
return QString();
- //XXX TODO: handle windows hostnames: "//servername/path/to/file.txt"
+ // QUrl::toLocalFile() interprets two slashes as part of the path.
+ // Therefore windows hostnames like "//servername/path/to/file.txt" are preserved.
return file.toLocalFile();
}
+static bool isDoubleSlashed(const QString &url, qsizetype offset)
+{
+ const qsizetype urlLength = url.length();
+ if (urlLength < offset + 2)
+ return false;
+
+ const QLatin1Char slash('/');
+ if (url[offset] != slash || url[offset + 1] != slash)
+ return false;
+
+ if (urlLength < offset + 3)
+ return true;
+
+ return url[offset + 2] != slash;
+}
+
/*!
If \a url is a local file returns a path suitable for passing to QFile. Otherwise returns an
empty string.
@@ -615,23 +703,28 @@ empty string.
QString QQmlFile::urlToLocalFileOrQrc(const QString& url)
{
if (url.startsWith(QLatin1String("qrc://"), Qt::CaseInsensitive)) {
- if (url.length() > 6)
- return QLatin1Char(':') + QStringView{url}.mid(6);
- return QString();
+ // Exactly two slashes are bad because that's a URL authority.
+ // One slash is fine and >= 3 slashes are file.
+ if (url.length() == 6 || url[6] != QLatin1Char('/')) {
+ Q_ASSERT(isDoubleSlashed(url, strlen("qrc:")));
+ return QString();
+ }
+ Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
+ return QLatin1Char(':') + QStringView{url}.mid(6);
}
if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
+ Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
if (url.length() > 4)
return QLatin1Char(':') + QStringView{url}.mid(4);
- return QString();
+ return QStringLiteral(":");
}
#if defined(Q_OS_ANDROID)
- else if (url.startsWith(QLatin1String("assets:"), Qt::CaseInsensitive)) {
- return url;
- } else if (url.startsWith(QLatin1String("content:"), Qt::CaseInsensitive)) {
- return url;
- }
+ if (url.startsWith(QLatin1String("assets:"), Qt::CaseInsensitive))
+ return isDoubleSlashed(url, strlen("assets:")) ? QString() : url;
+ if (hasScheme(url, content_string, strlen(content_string)))
+ return hasLocalContentAuthority(url, strlen(content_string)) ? url : QString();
#endif
return toLocalFile(url);
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 610a39a992..9feb7a5dfc 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -236,7 +236,8 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
}
void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
+ QQmlMetaType::ClonePolicy policy)
{
// Set classname
builder.setClassName(ignoreEnd->className());
@@ -253,40 +254,41 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
- // Clone Q_METHODS - do this first to avoid duplicating the notify signals.
- for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
- QMetaMethod method = mo->method(ii);
+ if (policy != QQmlMetaType::CloneEnumsOnly) {
+ // Clone Q_METHODS - do this first to avoid duplicating the notify signals.
+ for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
+ QMetaMethod method = mo->method(ii);
- // More complex - need to search name
- QByteArray name = method.name();
+ // More complex - need to search name
+ QByteArray name = method.name();
+ bool found = false;
- bool found = false;
+ for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
+ !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); ++ii) {
- for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
- !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
- ++ii) {
+ QMetaMethod other = ignoreEnd->method(ii);
- QMetaMethod other = ignoreEnd->method(ii);
+ found = name == other.name();
+ }
- found = name == other.name();
+ QMetaMethodBuilder m = builder.addMethod(method);
+ if (found) // SKIP
+ m.setAccess(QMetaMethod::Private);
}
- QMetaMethodBuilder m = builder.addMethod(method);
- if (found) // SKIP
- m.setAccess(QMetaMethod::Private);
- }
-
- // Clone Q_PROPERTY
- for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
- QMetaProperty property = mo->property(ii);
+ // Clone Q_PROPERTY
+ for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
+ QMetaProperty property = mo->property(ii);
- int otherIndex = ignoreEnd->indexOfProperty(property.name());
- if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
- builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
- // Skip
- } else {
- builder.addProperty(property);
+ int otherIndex = ignoreEnd->indexOfProperty(property.name());
+ if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
+ builder.addProperty(QByteArray("__qml_ignore__") + property.name(),
+ QByteArray("void"));
+ // Skip
+ } else {
+ builder.addProperty(property);
+ }
}
}
@@ -851,6 +853,8 @@ QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
QQmlExtensionPluginPrivate::get(plugin)->baseUrl
= QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
}
+#else
+ Q_UNUSED(basePath)
#endif
const QByteArray bytes = uri.toUtf8();
@@ -1519,7 +1523,8 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject
return;
QMetaObjectBuilder builder;
- clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject);
+ clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
QMetaObject *mmo = builder.toMetaObject();
mmo->d.superdata = baseMetaObject;
if (!metaObjects.isEmpty())
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 2b00b75dc6..7777562454 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -243,8 +243,13 @@ public:
const QMetaObject *baseMetaObject,
QMetaObject *lastMetaObject);
+ enum ClonePolicy {
+ CloneAll, // default
+ CloneEnumsOnly, // skip properties and methods
+ };
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd);
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
+ ClonePolicy policy);
static void qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)());
static void qmlRemoveModuleRegistration(const QString &uri);
diff --git a/src/qml/qml/qqmlpropertybinding.cpp b/src/qml/qml/qqmlpropertybinding.cpp
index 7243615e3e..a73396a892 100644
--- a/src/qml/qml/qqmlpropertybinding.cpp
+++ b/src/qml/qml/qqmlpropertybinding.cpp
@@ -167,7 +167,8 @@ QUntypedPropertyBinding QQmlPropertyBinding::createFromBoundFunction(const QQmlP
void QQmlPropertyBindingJS::expressionChanged()
{
- if (!asBinding()->propertyDataPtr)
+ auto binding = asBinding();
+ if (!binding->propertyDataPtr)
return;
const auto currentTag = m_error.tag();
if (currentTag == InEvaluationLoop) {
@@ -187,8 +188,9 @@ void QQmlPropertyBindingJS::expressionChanged()
return;
}
m_error.setTag(InEvaluationLoop);
- asBinding()->evaluateRecursive();
- asBinding()->notifyRecursive();
+ PendingBindingObserverList bindingObservers;
+ binding->evaluateRecursive(bindingObservers);
+ binding->notifyNonRecursive(bindingObservers);
m_error.setTag(NoTag);
}
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 5b44ead713..278977fb9c 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -1038,6 +1038,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) const
property.setWritable(data->isWritable());
property.setResettable(data->isResettable());
property.setBindable(data->isBindable());
+ property.setAlias(data->isAlias());
}
for (int ii = 0; ii < methods.count(); ++ii) {
diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp
index 45edb59cfb..fe68337eb3 100644
--- a/src/qml/qml/qqmlpropertycachecreator.cpp
+++ b/src/qml/qml/qqmlpropertycachecreator.cpp
@@ -115,8 +115,10 @@ bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
return true;
}
+ if (!referencingObjectPropertyCache)
+ return false;
+
Q_ASSERT(referencingObjectIndex >= 0);
- Q_ASSERT(referencingObjectPropertyCache);
Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
bool notInRevision = false;
@@ -149,15 +151,22 @@ void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePr
if (propertyCaches->at(groupPropertyObjectIndex))
continue;
- if (pendingBinding.referencingObjectPropertyCache) {
- if (!pendingBinding.resolveInstantiatingProperty())
- continue;
- auto cache = pendingBinding.instantiatingPropertyCache(enginePrivate);
- propertyCaches->set(groupPropertyObjectIndex, cache);
- } else {
+ if (pendingBinding.instantiatingPropertyName.isEmpty()) {
+ // Generalized group property.
auto cache = propertyCaches->at(pendingBinding.referencingObjectIndex);
propertyCaches->set(groupPropertyObjectIndex, cache);
+ continue;
}
+
+ if (!pendingBinding.referencingObjectPropertyCache) {
+ pendingBinding.referencingObjectPropertyCache
+ = propertyCaches->at(pendingBinding.referencingObjectIndex);
+ }
+
+ if (!pendingBinding.resolveInstantiatingProperty())
+ continue;
+ auto cache = pendingBinding.instantiatingPropertyCache(enginePrivate);
+ propertyCaches->set(groupPropertyObjectIndex, cache);
}
}
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 606628cbe8..09d8ace425 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -348,12 +348,8 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
switch (binding->type()) {
case QV4::CompiledData::Binding::Type_Object:
case QV4::CompiledData::Binding::Type_GroupProperty:
- // We can resolve object and group properties if we have a property cache.
- if (thisCache)
- break;
- continue;
case QV4::CompiledData::Binding::Type_AttachedProperty:
- // We can always resolve attached properties.
+ // We can always resolve object, group, and attached properties.
break;
default:
// Everything else is of no interest here.
@@ -949,10 +945,16 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
}
const auto referencedType = typeRef->type();
- if (referencedType.isValid())
+ if (referencedType.isValid()) {
*type = referencedType.typeId();
- else
+ if (!type->isValid() && referencedType.isInlineComponentType()) {
+ int objectId = referencedType.inlineComponentId();
+ *type = objectContainer->typeIdsForComponent(objectId).id;
+ Q_ASSERT(type->isValid());
+ }
+ } else {
*type = typeRef->compilationUnit()->typeIds.id;
+ }
*version = typeRef->version();
diff --git a/src/qml/qml/qqmlproxymetaobject.cpp b/src/qml/qml/qqmlproxymetaobject.cpp
index 33b216ee78..a91652e9a1 100644
--- a/src/qml/qml/qqmlproxymetaobject.cpp
+++ b/src/qml/qml/qqmlproxymetaobject.cpp
@@ -68,11 +68,8 @@ QQmlProxyMetaObject::~QQmlProxyMetaObject()
QObject *QQmlProxyMetaObject::getProxy(int index)
{
if (!proxies) {
- if (!proxies) {
- proxies = new QObject*[metaObjects->count()];
- ::memset(proxies, 0,
- sizeof(QObject *) * metaObjects->count());
- }
+ proxies = new QObject *[metaObjects->count()];
+ ::memset(proxies, 0, sizeof(QObject *) * metaObjects->count());
}
if (!proxies[index]) {
@@ -112,6 +109,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
const int globalPropertyOffset = metaObjects->at(ii).propertyOffset;
if (id >= globalPropertyOffset) {
QObject *proxy = getProxy(ii);
+ Q_ASSERT(proxy);
const int localProxyOffset = proxy->metaObject()->propertyOffset();
const int localProxyId = id - globalPropertyOffset + localProxyOffset;
@@ -129,7 +127,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
const int globalMethodOffset = metaObjects->at(ii).methodOffset;
if (id >= globalMethodOffset) {
QObject *proxy = getProxy(ii);
-
+ Q_ASSERT(proxy);
const int localMethodOffset = proxy->metaObject()->methodOffset();
const int localMethodId = id - globalMethodOffset + localMethodOffset;
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index f827a24660..748283ad03 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -219,16 +219,15 @@ void QQmlTypePrivate::init() const
return;
}
- auto setupExtendedMetaObject = [&](
- const QMetaObject *extMetaObject,
- QObject *(*extFunc)(QObject *)) {
-
+ auto setupExtendedMetaObject = [&](const QMetaObject *extMetaObject,
+ QObject *(*extFunc)(QObject *)) {
if (!extMetaObject)
return;
// XXX - very inefficient
QMetaObjectBuilder builder;
- QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject);
+ QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
QMetaObject *mmo = builder.toMetaObject();
mmo->d.superdata = mo;
QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 };
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index c2bbd7f498..2cba0375e7 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -281,10 +281,27 @@ PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m,
{
if (id.isString()) {
const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
- QQmlPropertyData result = r->dataForPropertyKey(id);
- if (p && result.isValid())
- p->value = getGadgetProperty(r->engine(), r->d(), result.propType(), result.coreIndex(), result.isFunction(), result.isEnum());
- return result.isValid() ? Attr_Data : Attr_Invalid;
+ Q_ASSERT(r);
+
+ const QQmlPropertyData result = r->dataForPropertyKey(id);
+ if (!result.isValid())
+ return Attr_Invalid; // Property doesn't exist. Object shouldn't meddle with it.
+
+ if (!p)
+ return Attr_Data; // Property exists, but we're not interested in the value
+
+ const QQmlValueTypeReference *ref = r->as<const QQmlValueTypeReference>();
+ if (!ref || ref->readReferenceValue()) {
+ // Property exists, and we can retrieve it
+ p->value = getGadgetProperty(
+ r->engine(), r->d(), result.propType(), result.coreIndex(),
+ result.isFunction(), result.isEnum());
+ } else {
+ // Property exists, but we can't retrieve it. Make it undefined.
+ p->value = Encode::undefined();
+ }
+
+ return Attr_Data;
}
return QV4::Object::virtualGetOwnProperty(m, id, p);