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 *createdComponent, 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
216private:
217 ConstructionState m_state;
218 QQmlGuardedContextData m_creationContext;
219
220 QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit;
221 QQmlRefPointer<QQmlTypeData> m_typeData;
222 QQmlRefPointer<LoadHelper> m_loadHelper;
223 std::unique_ptr<QString> m_inlineComponentName;
224 QQmlEngine *m_engine = nullptr;
225
226 QUrl m_url;
227 qreal m_progress = 0;
228
229 /* points to the sub-object in a QML file that should be instantiated
230 used create instances of QtQml's Component type and indirectly for inline components */
231 int m_start = -1;
232};
233
234QQmlComponentPrivate::ConstructionState::~ConstructionState()
235{
236 if (m_creatorOrRequiredProperties.isT1())
237 delete m_creatorOrRequiredProperties.asT1();
238 else
239 delete m_creatorOrRequiredProperties.asT2();
240}
241
242QQmlComponentPrivate::ConstructionState::ConstructionState(ConstructionState &&other) noexcept
243{
244 errors = std::move(other.errors);
245 m_creatorOrRequiredProperties = std::exchange(other.m_creatorOrRequiredProperties, {});
246}
247
248/*!
249 \internal A list of pending required properties that need
250 to be set in order for object construction to be successful.
251 */
252inline RequiredProperties *QQmlComponentPrivate::ConstructionState::requiredProperties() const
253{
254 if (m_creatorOrRequiredProperties.isNull())
255 return nullptr;
256 else if (m_creatorOrRequiredProperties.isT1())
257 return m_creatorOrRequiredProperties.asT1()->requiredProperties();
258 else
259 return m_creatorOrRequiredProperties.asT2();
260}
261
262inline void QQmlComponentPrivate::ConstructionState::addPendingRequiredProperty(
263 const QObject *object, const QQmlPropertyData *propData, const RequiredPropertyInfo &info)
264{
265 Q_ASSERT(requiredProperties());
266 requiredProperties()->insert({object, propData}, info);
267}
268
269inline bool QQmlComponentPrivate::ConstructionState::hasUnsetRequiredProperties() const {
270 auto properties = const_cast<ConstructionState *>(this)->requiredProperties();
271 return properties && !properties->isEmpty();
272}
273
274inline void QQmlComponentPrivate::ConstructionState::clearRequiredProperties()
275{
276 if (auto reqProps = requiredProperties())
277 reqProps->clear();
278}
279
280inline void QQmlComponentPrivate::ConstructionState::appendErrors(const QList<QQmlError> &qmlErrors)
281{
282 for (const QQmlError &e : qmlErrors)
283 errors.emplaceBack(e);
284}
285
286//! \internal Moves errors from creator into construction state itself
287inline void QQmlComponentPrivate::ConstructionState::appendCreatorErrors()
288{
289 if (!hasCreator())
290 return;
291 auto creatorErrorCount = creator()->errors.size();
292 if (creatorErrorCount == 0)
293 return;
294 auto existingErrorCount = errors.size();
295 errors.resize(existingErrorCount + creatorErrorCount);
296 for (qsizetype i = 0; i < creatorErrorCount; ++i)
297 errors[existingErrorCount + i] = AnnotatedQmlError { std::move(creator()->errors[i]) };
298 creator()->errors.clear();
299}
300
301inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator()
302{
303 if (m_creatorOrRequiredProperties.isT1())
304 return m_creatorOrRequiredProperties.asT1();
305 return nullptr;
306}
307
308inline const QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator() const
309{
310 if (m_creatorOrRequiredProperties.isT1())
311 return m_creatorOrRequiredProperties.asT1();
312 return nullptr;
313}
314
315inline bool QQmlComponentPrivate::ConstructionState::hasCreator() const
316{
317 return creator() != nullptr;
318}
319
320inline void QQmlComponentPrivate::ConstructionState::clear()
321{
322 if (m_creatorOrRequiredProperties.isT1()) {
323 delete m_creatorOrRequiredProperties.asT1();
324 m_creatorOrRequiredProperties = static_cast<QQmlObjectCreator *>(nullptr);
325 }
326}
327
328inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::initCreator(
329 const QQmlRefPointer<QQmlContextData> &parentContext,
330 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
331 const QQmlRefPointer<QQmlContextData> &creationContext,
332 const QString &inlineComponentName)
333{
334 if (m_creatorOrRequiredProperties.isT1())
335 delete m_creatorOrRequiredProperties.asT1();
336 else
337 delete m_creatorOrRequiredProperties.asT2();
338 m_creatorOrRequiredProperties = new QQmlObjectCreator(
339 parentContext, compilationUnit, creationContext, inlineComponentName);
340 return m_creatorOrRequiredProperties.asT1();
341}
342
343inline bool QQmlComponentPrivate::ConstructionState::isCompletePending() const
344{
345 return m_creatorOrRequiredProperties.flag();
346}
347
348inline void QQmlComponentPrivate::ConstructionState::setCompletePending(bool isPending)
349{
350 m_creatorOrRequiredProperties.setFlagValue(isPending);
351}
352
353/*!
354 \internal
355 This is meant to be used in the context of QQmlComponent::loadFromModule,
356 when dealing with a C++ type. In that case, we do not have a creator,
357 and need a separate storage for required properties and the target object.
358 */
359inline void QQmlComponentPrivate::ConstructionState::ensureRequiredPropertyStorage(QObject *target)
360{
361 Q_ASSERT(m_creatorOrRequiredProperties.isT2() || m_creatorOrRequiredProperties.isNull());
362 if (m_creatorOrRequiredProperties.isNull())
363 m_creatorOrRequiredProperties = new RequiredPropertiesAndTarget(target);
364 else
365 m_creatorOrRequiredProperties.asT2()->target = target;
366}
367
368QT_END_NAMESPACE
369
370#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)