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