diff options
Diffstat (limited to 'src/qml/qml/qqmlcomponent_p.h')
-rw-r--r-- | src/qml/qml/qqmlcomponent_p.h | 275 |
1 files changed, 213 insertions, 62 deletions
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index abc0de7438..21fdee3f7a 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLCOMPONENT_P_H #define QQMLCOMPONENT_P_H @@ -54,10 +18,7 @@ #include "qqmlcomponent.h" #include "qqmlengine_p.h" -#include "qqmltypeloader_p.h" -#include "qqmlvme_p.h" #include "qqmlerror.h" -#include "qqml.h" #include <private/qqmlobjectcreator_p.h> #include <private/qqmltypedata_p.h> #include <private/qqmlguardedcontextdata_p.h> @@ -65,6 +26,7 @@ #include <QtCore/QString> #include <QtCore/QStringList> #include <QtCore/QList> +#include <QtCore/qtclasshelpermacros.h> #include <private/qobject_p.h> @@ -74,20 +36,23 @@ class QQmlComponent; class QQmlEngine; class QQmlComponentAttached; -class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback +class Q_QML_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback { Q_DECLARE_PUBLIC(QQmlComponent) public: QQmlComponentPrivate() - : progress(0.), start(-1), engine(nullptr), creationContext(nullptr) {} + : progress(0.), start(-1), engine(nullptr) {} void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous); QObject *beginCreate(QQmlRefPointer<QQmlContextData>); void completeCreate(); - 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); + 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, + QQmlObjectCreator *creator); static QQmlError unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty); virtual void incubateObject( @@ -105,39 +70,83 @@ public: QUrl url; qreal progress; + std::unique_ptr<QString> inlineComponentName; + /* points to the sub-object in a QML file that should be instantiated + used create instances of QtQml's Component type and indirectly for inline components */ int start; - RequiredProperties& requiredProperties(); - bool hadRequiredProperties() const; + + bool hadTopLevelRequiredProperties() const; + // TODO: merge compilation unit and type QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit; + QQmlType loadedType; - struct ConstructionState { - ConstructionState() - : completePending(false) - {} - ~ConstructionState() + struct AnnotatedQmlError + { + AnnotatedQmlError() = default; + + AnnotatedQmlError(QQmlError error) + : error(std::move(error)) { } - QScopedPointer<QQmlObjectCreator> creator; - QList<QQmlError> errors; - bool completePending; + + AnnotatedQmlError(QQmlError error, bool transient) + : error(std::move(error)), isTransient(transient) + { + } + QQmlError error; + bool isTransient = false; // tells if the error is temporary (e.g. unset required property) }; - ConstructionState state; - struct DeferredState { - ~DeferredState() { - qDeleteAll(constructionStates); - constructionStates.clear(); + struct ConstructionState { + ConstructionState() = default; + inline ~ConstructionState(); + Q_DISABLE_COPY(ConstructionState) + inline ConstructionState(ConstructionState &&other) noexcept; + + void swap(ConstructionState &other) + { + m_creatorOrRequiredProperties.swap(other.m_creatorOrRequiredProperties); } - QVector<ConstructionState *> constructionStates; + + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlComponentPrivate::ConstructionState); + + inline void ensureRequiredPropertyStorage(); + inline RequiredProperties *requiredProperties(); + inline void addPendingRequiredProperty( + const QObject *object, const QQmlPropertyData *propData, + const RequiredPropertyInfo &info); + inline bool hasUnsetRequiredProperties() const; + inline void clearRequiredProperties(); + + inline void appendErrors(const QList<QQmlError> &qmlErrors); + inline void appendCreatorErrors(); + + inline QQmlObjectCreator *creator(); + inline const QQmlObjectCreator *creator() const; + inline void clear(); + inline bool hasCreator() const; + inline QQmlObjectCreator *initCreator(QQmlRefPointer<QQmlContextData> parentContext, + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, + const QQmlRefPointer<QQmlContextData> &creationContext); + + QList<AnnotatedQmlError> errors; + inline bool isCompletePending() const; + inline void setCompletePending(bool isPending); + + private: + QBiPointer<QQmlObjectCreator, RequiredProperties> m_creatorOrRequiredProperties; }; + ConstructionState state; + using DeferredState = std::vector<ConstructionState>; static void beginDeferred(QQmlEnginePrivate *enginePriv, QObject *object, DeferredState* deferredState); 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); + static QQmlProperty removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties *requiredProperties, + QQmlEngine *engine, bool *wasInRequiredProperties = nullptr); QQmlEngine *engine; QQmlGuardedContextData creationContext; @@ -150,8 +159,150 @@ public: QObject *doBeginCreate(QQmlComponent *q, QQmlContext *context); bool setInitialProperty(QObject *component, const QString &name, const QVariant& value); + + enum CreateBehavior { + CreateDefault, + CreateWarnAboutRequiredProperties, + }; + QObject *createWithProperties(QObject *parent, const QVariantMap &properties, + QQmlContext *context, CreateBehavior behavior = CreateDefault); + + bool isBound() const { return compilationUnit && (compilationUnit->componentsAreBound()); } + LoadHelper::ResolveTypeResult prepareLoadFromModule(QAnyStringView uri, + QAnyStringView typeName); + void completeLoadFromModule(QAnyStringView uri, QAnyStringView typeName, QQmlType type, + LoadHelper::ResolveTypeResult::Status moduleStatus, + QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous); }; +QQmlComponentPrivate::ConstructionState::~ConstructionState() +{ + if (m_creatorOrRequiredProperties.isT1()) + delete m_creatorOrRequiredProperties.asT1(); + else + delete m_creatorOrRequiredProperties.asT2(); +} + +QQmlComponentPrivate::ConstructionState::ConstructionState(ConstructionState &&other) noexcept +{ + errors = std::move(other.errors); + m_creatorOrRequiredProperties = std::exchange(other.m_creatorOrRequiredProperties, {}); +} + +/*! + \internal A list of pending required properties that need + to be set in order for object construction to be successful. + */ +inline RequiredProperties *QQmlComponentPrivate::ConstructionState::requiredProperties() { + if (m_creatorOrRequiredProperties.isNull()) + return nullptr; + else if (m_creatorOrRequiredProperties.isT1()) + return m_creatorOrRequiredProperties.asT1()->requiredProperties(); + else + return m_creatorOrRequiredProperties.asT2(); +} + +inline void QQmlComponentPrivate::ConstructionState::addPendingRequiredProperty( + const QObject *object, const QQmlPropertyData *propData, const RequiredPropertyInfo &info) +{ + Q_ASSERT(requiredProperties()); + requiredProperties()->insert({object, propData}, info); +} + +inline bool QQmlComponentPrivate::ConstructionState::hasUnsetRequiredProperties() const { + auto properties = const_cast<ConstructionState *>(this)->requiredProperties(); + return properties && !properties->isEmpty(); +} + +inline void QQmlComponentPrivate::ConstructionState::clearRequiredProperties() +{ + if (auto reqProps = requiredProperties()) + reqProps->clear(); +} + +inline void QQmlComponentPrivate::ConstructionState::appendErrors(const QList<QQmlError> &qmlErrors) +{ + for (const QQmlError &e : qmlErrors) + errors.emplaceBack(e); +} + +//! \internal Moves errors from creator into construction state itself +inline void QQmlComponentPrivate::ConstructionState::appendCreatorErrors() +{ + if (!hasCreator()) + return; + auto creatorErrorCount = creator()->errors.size(); + if (creatorErrorCount == 0) + return; + auto existingErrorCount = errors.size(); + errors.resize(existingErrorCount + creatorErrorCount); + for (qsizetype i = 0; i < creatorErrorCount; ++i) + errors[existingErrorCount + i] = AnnotatedQmlError { std::move(creator()->errors[i]) }; + creator()->errors.clear(); +} + +inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator() +{ + if (m_creatorOrRequiredProperties.isT1()) + return m_creatorOrRequiredProperties.asT1(); + return nullptr; +} + +inline const QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator() const +{ + if (m_creatorOrRequiredProperties.isT1()) + return m_creatorOrRequiredProperties.asT1(); + return nullptr; +} + +inline bool QQmlComponentPrivate::ConstructionState::hasCreator() const +{ + return creator() != nullptr; +} + +inline void QQmlComponentPrivate::ConstructionState::clear() +{ + if (m_creatorOrRequiredProperties.isT1()) { + delete m_creatorOrRequiredProperties.asT1(); + m_creatorOrRequiredProperties = static_cast<QQmlObjectCreator *>(nullptr); + } +} + +inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::initCreator(QQmlRefPointer<QQmlContextData> parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QQmlRefPointer<QQmlContextData> &creationContext) +{ + if (m_creatorOrRequiredProperties.isT1()) + delete m_creatorOrRequiredProperties.asT1(); + else + delete m_creatorOrRequiredProperties.asT2(); + m_creatorOrRequiredProperties = new QQmlObjectCreator( + std::move(parentContext), compilationUnit, + creationContext); + return m_creatorOrRequiredProperties.asT1(); +} + +inline bool QQmlComponentPrivate::ConstructionState::isCompletePending() const +{ + return m_creatorOrRequiredProperties.flag(); +} + +inline void QQmlComponentPrivate::ConstructionState::setCompletePending(bool isPending) +{ + m_creatorOrRequiredProperties.setFlagValue(isPending); +} + +/*! + \internal + This is meant to be used in the context of QQmlComponent::loadFromModule, + when dealing with a C++ type. In that case, we do not have a creator, + and need a separate storage for required properties. + */ +inline void QQmlComponentPrivate::ConstructionState::ensureRequiredPropertyStorage() +{ + Q_ASSERT(m_creatorOrRequiredProperties.isT2() || m_creatorOrRequiredProperties.isNull()); + if (m_creatorOrRequiredProperties.isNull()) + m_creatorOrRequiredProperties = new RequiredProperties; +} + QT_END_NAMESPACE #endif // QQMLCOMPONENT_P_H |