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