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 class CreateBehavior
46 {
47 Cpp, // Create even if required properties fail, don't warn
48 Qml, // Return nullptr on failure, warn about missing required properties
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 setInitialProperties(QObject *object, const QVariantMap &properties);
173 bool setInitialProperty(QObject *component, const QString &name, const QVariant& value);
174
175 QObject *createWithProperties(
176 QObject *parent, const QVariantMap &properties, QQmlContext *context,
177 CreateBehavior behavior);
178
179 bool isBound() const { return m_compilationUnit && (m_compilationUnit->componentsAreBound()); }
180 void prepareLoadFromModule(
181 QAnyStringView uri, QAnyStringView typeName, QQmlTypeLoader::Mode mode);
182 void completeLoadFromModule(
183 QAnyStringView uri, QAnyStringView typeName);
184
185 void setProgress(qreal progress)
186 {
187 if (progress != m_progress) {
188 m_progress = progress;
189 emit q_func()->progressChanged(progress);
190 }
191 }
192 void setCreationContext(QQmlRefPointer<QQmlContextData> creationContext)
193 {
194 m_creationContext = std::move(creationContext);
195 }
196
197 QQmlType loadHelperType() const { return m_loadHelper->type(); }
198 bool hasUnsetRequiredProperties() const { return m_state.hasUnsetRequiredProperties(); }
199 RequiredProperties *requiredProperties() const { return m_state.requiredProperties(); }
200 const QQmlObjectCreator *creator() const { return m_state.creator(); }
201
202 QQmlEngine *engine() const { return m_engine; }
203 QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const
204 {
205 return m_compilationUnit;
206 }
207
208private:
209 ConstructionState m_state;
210 QQmlGuardedContextData m_creationContext;
211
212 QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit;
213 QQmlRefPointer<QQmlTypeData> m_typeData;
214 QQmlRefPointer<LoadHelper> m_loadHelper;
215 std::unique_ptr<QString> m_inlineComponentName;
216 QQmlEngine *m_engine = nullptr;
217
218 QUrl m_url;
219 qreal m_progress = 0;
220
221 /* points to the sub-object in a QML file that should be instantiated
222 used create instances of QtQml's Component type and indirectly for inline components */
223 int m_start = -1;
224};
225
226QQmlComponentPrivate::ConstructionState::~ConstructionState()
227{
228 if (m_creatorOrRequiredProperties.isT1())
229 delete m_creatorOrRequiredProperties.asT1();
230 else
231 delete m_creatorOrRequiredProperties.asT2();
232}
233
234QQmlComponentPrivate::ConstructionState::ConstructionState(ConstructionState &&other) noexcept
235{
236 errors = std::move(other.errors);
237 m_creatorOrRequiredProperties = std::exchange(other.m_creatorOrRequiredProperties, {});
238}
239
240/*!
241 \internal A list of pending required properties that need
242 to be set in order for object construction to be successful.
243 */
244inline RequiredProperties *QQmlComponentPrivate::ConstructionState::requiredProperties() const
245{
246 if (m_creatorOrRequiredProperties.isNull())
247 return nullptr;
248 else if (m_creatorOrRequiredProperties.isT1())
249 return m_creatorOrRequiredProperties.asT1()->requiredProperties();
250 else
251 return m_creatorOrRequiredProperties.asT2();
252}
253
254inline void QQmlComponentPrivate::ConstructionState::addPendingRequiredProperty(
255 const QObject *object, const QQmlPropertyData *propData, const RequiredPropertyInfo &info)
256{
257 Q_ASSERT(requiredProperties());
258 requiredProperties()->insert({object, propData}, info);
259}
260
261inline bool QQmlComponentPrivate::ConstructionState::hasUnsetRequiredProperties() const {
262 auto properties = const_cast<ConstructionState *>(this)->requiredProperties();
263 return properties && !properties->isEmpty();
264}
265
266inline void QQmlComponentPrivate::ConstructionState::clearRequiredProperties()
267{
268 if (auto reqProps = requiredProperties())
269 reqProps->clear();
270}
271
272inline void QQmlComponentPrivate::ConstructionState::appendErrors(const QList<QQmlError> &qmlErrors)
273{
274 for (const QQmlError &e : qmlErrors)
275 errors.emplaceBack(e);
276}
277
278//! \internal Moves errors from creator into construction state itself
279inline void QQmlComponentPrivate::ConstructionState::appendCreatorErrors()
280{
281 if (!hasCreator())
282 return;
283 auto creatorErrorCount = creator()->errors.size();
284 if (creatorErrorCount == 0)
285 return;
286 auto existingErrorCount = errors.size();
287 errors.resize(existingErrorCount + creatorErrorCount);
288 for (qsizetype i = 0; i < creatorErrorCount; ++i)
289 errors[existingErrorCount + i] = AnnotatedQmlError { std::move(creator()->errors[i]) };
290 creator()->errors.clear();
291}
292
293inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator()
294{
295 if (m_creatorOrRequiredProperties.isT1())
296 return m_creatorOrRequiredProperties.asT1();
297 return nullptr;
298}
299
300inline const QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator() const
301{
302 if (m_creatorOrRequiredProperties.isT1())
303 return m_creatorOrRequiredProperties.asT1();
304 return nullptr;
305}
306
307inline bool QQmlComponentPrivate::ConstructionState::hasCreator() const
308{
309 return creator() != nullptr;
310}
311
312inline void QQmlComponentPrivate::ConstructionState::clear()
313{
314 if (m_creatorOrRequiredProperties.isT1()) {
315 delete m_creatorOrRequiredProperties.asT1();
316 m_creatorOrRequiredProperties = static_cast<QQmlObjectCreator *>(nullptr);
317 }
318}
319
320inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::initCreator(
321 const QQmlRefPointer<QQmlContextData> &parentContext,
322 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
323 const QQmlRefPointer<QQmlContextData> &creationContext,
324 const QString &inlineComponentName)
325{
326 if (m_creatorOrRequiredProperties.isT1())
327 delete m_creatorOrRequiredProperties.asT1();
328 else
329 delete m_creatorOrRequiredProperties.asT2();
330 m_creatorOrRequiredProperties = new QQmlObjectCreator(
331 parentContext, compilationUnit, creationContext, inlineComponentName);
332 return m_creatorOrRequiredProperties.asT1();
333}
334
335inline bool QQmlComponentPrivate::ConstructionState::isCompletePending() const
336{
337 return m_creatorOrRequiredProperties.flag();
338}
339
340inline void QQmlComponentPrivate::ConstructionState::setCompletePending(bool isPending)
341{
342 m_creatorOrRequiredProperties.setFlagValue(isPending);
343}
344
345/*!
346 \internal
347 This is meant to be used in the context of QQmlComponent::loadFromModule,
348 when dealing with a C++ type. In that case, we do not have a creator,
349 and need a separate storage for required properties and the target object.
350 */
351inline void QQmlComponentPrivate::ConstructionState::ensureRequiredPropertyStorage(QObject *target)
352{
353 Q_ASSERT(m_creatorOrRequiredProperties.isT2() || m_creatorOrRequiredProperties.isNull());
354 if (m_creatorOrRequiredProperties.isNull())
355 m_creatorOrRequiredProperties = new RequiredPropertiesAndTarget(target);
356 else
357 m_creatorOrRequiredProperties.asT2()->target = target;
358}
359
360QT_END_NAMESPACE
361
362#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.
Combined button and popup list for selecting options.
DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext)
Definition qjsvalue.h:24
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
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)