Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlcomponent_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLCOMPONENT_P_H
5#define QQMLCOMPONENT_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include "qqmlcomponent.h"
19
20#include "qqmlengine_p.h"
21#include "qqmlerror.h"
22#include <private/qqmlobjectcreator_p.h>
23#include <private/qqmltypedata_p.h>
24#include <private/qqmlguardedcontextdata_p.h>
25
26#include <QtCore/QString>
27#include <QtCore/QStringList>
28#include <QtCore/QList>
29#include <QtCore/qtclasshelpermacros.h>
30
31#include <private/qobject_p.h>
32
34
35class QQmlComponent;
36class QQmlEngine;
37
38class QQmlComponentAttached;
39class Q_QML_EXPORT QQmlComponentPrivate
40 : public QObjectPrivate, public QQmlNotifyingBlob::Callback
41{
42 Q_DECLARE_PUBLIC(QQmlComponent)
43
44public:
45 enum CreateBehavior
46 {
47 CreateDefault,
48 CreateWarnAboutRequiredProperties,
49 };
50
51 struct AnnotatedQmlError
52 {
53 AnnotatedQmlError() = default;
54 AnnotatedQmlError(QQmlError error) : error(std::move(error)) {}
55 AnnotatedQmlError(QQmlError error, bool transient)
56 : error(std::move(error)), isTransient(transient)
57 {
58 }
59
60 QQmlError error;
61 bool isTransient = false; // tells if the error is temporary (e.g. unset required property)
62 };
63
64 struct ConstructionState
65 {
66 public:
67 ConstructionState() = default;
68 inline ConstructionState(ConstructionState &&other) noexcept;
69 inline ~ConstructionState();
70
71 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlComponentPrivate::ConstructionState)
72 void swap(ConstructionState &other)
73 {
74 m_creatorOrRequiredProperties.swap(other.m_creatorOrRequiredProperties);
75 }
76
77 inline void ensureRequiredPropertyStorage(QObject *target);
78 inline RequiredProperties *requiredProperties() const;
79 inline void addPendingRequiredProperty(
80 const QObject *object, const QQmlPropertyData *propData,
81 const RequiredPropertyInfo &info);
82 inline bool hasUnsetRequiredProperties() const;
83 inline void clearRequiredProperties();
84
85 inline void appendErrors(const QList<QQmlError> &qmlErrors);
86 inline void appendCreatorErrors();
87
88 inline QQmlObjectCreator *creator();
89 inline const QQmlObjectCreator *creator() const;
90 inline void clear();
91 inline bool hasCreator() const;
92 inline QQmlObjectCreator *initCreator(
93 const QQmlRefPointer<QQmlContextData> &parentContext,
94 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
95 const QQmlRefPointer<QQmlContextData> &creationContext,
96 const QString &inlineComponentName);
97
98 QList<AnnotatedQmlError> errors;
99 inline bool isCompletePending() const;
100 inline void setCompletePending(bool isPending);
101
102 QObject *target() const
103 {
104 if (m_creatorOrRequiredProperties.isNull())
105 return nullptr;
106
107 if (m_creatorOrRequiredProperties.isT1()) {
108 const auto &objects = m_creatorOrRequiredProperties.asT1()->allCreatedObjects();
109 return objects.empty() ? nullptr : objects.at(0);
110 }
111
112 Q_ASSERT(m_creatorOrRequiredProperties.isT2());
113 return m_creatorOrRequiredProperties.asT2()->target;
114 }
115
116 private:
117 Q_DISABLE_COPY(ConstructionState)
118 QBiPointer<QQmlObjectCreator, RequiredPropertiesAndTarget> m_creatorOrRequiredProperties;
119 };
120
121 using DeferredState = std::vector<ConstructionState>;
122
123 void loadUrl(const QUrl &newUrl,
124 QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
125
126 QQmlType loadedType() const { return m_loadHelper ? m_loadHelper->type() : QQmlType(); }
127
128 QObject *beginCreate(QQmlRefPointer<QQmlContextData>);
129 void completeCreate();
130 void initializeObjectWithInitialProperties(
131 QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate,
132 RequiredProperties *requiredProperties);
133 static void setInitialProperties(
134 QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o,
135 const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent,
136 const QQmlObjectCreator *creator);
137 static QQmlError unsetRequiredPropertyToQQmlError(
138 const RequiredPropertyInfo &unsetRequiredProperty);
139
140 virtual void incubateObject(
141 QQmlIncubator *incubationTask,
142 QQmlComponent *component,
143 QQmlEngine *engine,
144 const QQmlRefPointer<QQmlContextData> &context,
145 const QQmlRefPointer<QQmlContextData> &forContext);
146
147 void ready(QQmlNotifyingBlob *) final;
148 void progress(QQmlNotifyingBlob *, qreal) final;
149
150 void fromTypeData(const QQmlRefPointer<QQmlTypeData> &data);
151
152 bool hadTopLevelRequiredProperties() const;
153
154 static void beginDeferred(
155 QQmlEnginePrivate *enginePriv, QObject *object, DeferredState* deferredState);
156 static void completeDeferred(
157 QQmlEnginePrivate *enginePriv, DeferredState *deferredState);
158
159 static void complete(QQmlEnginePrivate *enginePriv, ConstructionState *state);
160 static QQmlProperty removePropertyFromRequired(
161 QObject *createdComponent, const QString &name,
162 RequiredProperties *requiredProperties, QQmlEngine *engine,
163 bool *wasInRequiredProperties = nullptr);
164
165 void clear();
166
167 static QQmlComponentPrivate *get(QQmlComponent *c) {
168 return static_cast<QQmlComponentPrivate *>(QObjectPrivate::get(c));
169 }
170
171 QObject *doBeginCreate(QQmlComponent *q, QQmlContext *context);
172 bool setInitialProperty(QObject *component, const QString &name, const QVariant& value);
173
174 QObject *createWithProperties(QObject *parent, const QVariantMap &properties,
175 QQmlContext *context, CreateBehavior behavior = CreateDefault,
176 bool createFromQml = false);
177
178 bool isBound() const { return m_compilationUnit && (m_compilationUnit->componentsAreBound()); }
179 void prepareLoadFromModule(
180 QAnyStringView uri, QAnyStringView typeName, QQmlTypeLoader::Mode mode);
181 void completeLoadFromModule(
182 QAnyStringView uri, QAnyStringView typeName);
183
184 void setProgress(qreal progress)
185 {
186 if (progress != m_progress) {
187 m_progress = progress;
188 emit q_func()->progressChanged(progress);
189 }
190 }
191 void setCreationContext(QQmlRefPointer<QQmlContextData> creationContext)
192 {
193 m_creationContext = std::move(creationContext);
194 }
195
196 QQmlType loadHelperType() const { return m_loadHelper->type(); }
197 bool hasUnsetRequiredProperties() const { return m_state.hasUnsetRequiredProperties(); }
198 RequiredProperties *requiredProperties() const { return m_state.requiredProperties(); }
199 const QQmlObjectCreator *creator() const { return m_state.creator(); }
200
201 QQmlEngine *engine() const { return m_engine; }
202 QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const
203 {
204 return m_compilationUnit;
205 }
206
207private:
208 ConstructionState m_state;
209 QQmlGuardedContextData m_creationContext;
210
211 QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit;
212 QQmlRefPointer<QQmlTypeData> m_typeData;
213 QQmlRefPointer<LoadHelper> m_loadHelper;
214 std::unique_ptr<QString> m_inlineComponentName;
215 QQmlEngine *m_engine = nullptr;
216
217 QUrl m_url;
218 qreal m_progress = 0;
219
220 /* points to the sub-object in a QML file that should be instantiated
221 used create instances of QtQml's Component type and indirectly for inline components */
222 int m_start = -1;
223};
224
225QQmlComponentPrivate::ConstructionState::~ConstructionState()
226{
227 if (m_creatorOrRequiredProperties.isT1())
228 delete m_creatorOrRequiredProperties.asT1();
229 else
230 delete m_creatorOrRequiredProperties.asT2();
231}
232
233QQmlComponentPrivate::ConstructionState::ConstructionState(ConstructionState &&other) noexcept
234{
235 errors = std::move(other.errors);
236 m_creatorOrRequiredProperties = std::exchange(other.m_creatorOrRequiredProperties, {});
237}
238
239/*!
240 \internal A list of pending required properties that need
241 to be set in order for object construction to be successful.
242 */
243inline RequiredProperties *QQmlComponentPrivate::ConstructionState::requiredProperties() const
244{
245 if (m_creatorOrRequiredProperties.isNull())
246 return nullptr;
247 else if (m_creatorOrRequiredProperties.isT1())
248 return m_creatorOrRequiredProperties.asT1()->requiredProperties();
249 else
250 return m_creatorOrRequiredProperties.asT2();
251}
252
253inline void QQmlComponentPrivate::ConstructionState::addPendingRequiredProperty(
254 const QObject *object, const QQmlPropertyData *propData, const RequiredPropertyInfo &info)
255{
256 Q_ASSERT(requiredProperties());
257 requiredProperties()->insert({object, propData}, info);
258}
259
260inline bool QQmlComponentPrivate::ConstructionState::hasUnsetRequiredProperties() const {
261 auto properties = const_cast<ConstructionState *>(this)->requiredProperties();
262 return properties && !properties->isEmpty();
263}
264
265inline void QQmlComponentPrivate::ConstructionState::clearRequiredProperties()
266{
267 if (auto reqProps = requiredProperties())
268 reqProps->clear();
269}
270
271inline void QQmlComponentPrivate::ConstructionState::appendErrors(const QList<QQmlError> &qmlErrors)
272{
273 for (const QQmlError &e : qmlErrors)
274 errors.emplaceBack(e);
275}
276
277//! \internal Moves errors from creator into construction state itself
278inline void QQmlComponentPrivate::ConstructionState::appendCreatorErrors()
279{
280 if (!hasCreator())
281 return;
282 auto creatorErrorCount = creator()->errors.size();
283 if (creatorErrorCount == 0)
284 return;
285 auto existingErrorCount = errors.size();
286 errors.resize(existingErrorCount + creatorErrorCount);
287 for (qsizetype i = 0; i < creatorErrorCount; ++i)
288 errors[existingErrorCount + i] = AnnotatedQmlError { std::move(creator()->errors[i]) };
289 creator()->errors.clear();
290}
291
292inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator()
293{
294 if (m_creatorOrRequiredProperties.isT1())
295 return m_creatorOrRequiredProperties.asT1();
296 return nullptr;
297}
298
299inline const QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator() const
300{
301 if (m_creatorOrRequiredProperties.isT1())
302 return m_creatorOrRequiredProperties.asT1();
303 return nullptr;
304}
305
306inline bool QQmlComponentPrivate::ConstructionState::hasCreator() const
307{
308 return creator() != nullptr;
309}
310
311inline void QQmlComponentPrivate::ConstructionState::clear()
312{
313 if (m_creatorOrRequiredProperties.isT1()) {
314 delete m_creatorOrRequiredProperties.asT1();
315 m_creatorOrRequiredProperties = static_cast<QQmlObjectCreator *>(nullptr);
316 }
317}
318
319inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::initCreator(
320 const QQmlRefPointer<QQmlContextData> &parentContext,
321 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
322 const QQmlRefPointer<QQmlContextData> &creationContext,
323 const QString &inlineComponentName)
324{
325 if (m_creatorOrRequiredProperties.isT1())
326 delete m_creatorOrRequiredProperties.asT1();
327 else
328 delete m_creatorOrRequiredProperties.asT2();
329 m_creatorOrRequiredProperties = new QQmlObjectCreator(
330 parentContext, compilationUnit, creationContext, inlineComponentName);
331 return m_creatorOrRequiredProperties.asT1();
332}
333
334inline bool QQmlComponentPrivate::ConstructionState::isCompletePending() const
335{
336 return m_creatorOrRequiredProperties.flag();
337}
338
339inline void QQmlComponentPrivate::ConstructionState::setCompletePending(bool isPending)
340{
341 m_creatorOrRequiredProperties.setFlagValue(isPending);
342}
343
344/*!
345 \internal
346 This is meant to be used in the context of QQmlComponent::loadFromModule,
347 when dealing with a C++ type. In that case, we do not have a creator,
348 and need a separate storage for required properties and the target object.
349 */
350inline void QQmlComponentPrivate::ConstructionState::ensureRequiredPropertyStorage(QObject *target)
351{
352 Q_ASSERT(m_creatorOrRequiredProperties.isT2() || m_creatorOrRequiredProperties.isNull());
353 if (m_creatorOrRequiredProperties.isNull())
354 m_creatorOrRequiredProperties = new RequiredPropertiesAndTarget(target);
355 else
356 m_creatorOrRequiredProperties.asT2()->target = target;
357}
358
359QT_END_NAMESPACE
360
361#endif // QQMLCOMPONENT_P_H
\inmodule QtCore
Definition qobject.h:105
void setInitialState(QObject *o) override
Called after the object is first created, but before complex property bindings are evaluated and,...
void statusChanged(Status s) override
Called when the status of the incubator changes.
QQmlComponentIncubator(QV4::Heap::QmlIncubatorObject *inc, IncubationMode mode)
QV4::PersistentValue incubatorObject
The QQmlComponent class encapsulates a QML component definition.
The QQmlError class encapsulates a QML error.
Definition qqmlerror.h:18
Status
Specifies the status of the QQmlIncubator.
DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext)
Definition qjsvalue.h:23
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
static void removePendingQPropertyBinding(QV4::Value *object, const QString &propertyName, const QQmlObjectCreator *creator)
static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
DEFINE_OBJECT_VTABLE(QV4::QmlIncubatorObject)
V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension)
static QQmlParserStatus * parserStatusCast(const QQmlType &type, QObject *rv)
static ReturnedValue method_set_statusChanged(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_get_status(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_get_object(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
void statusChanged(QQmlIncubator::Status)
void setInitialState(QObject *, RequiredProperties *requiredProperties)
static ReturnedValue method_forceCompletion(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)