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
qquickstackelement.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 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 reason:default
4
8
9#include <QtQml/qqmlinfo.h>
10#include <QtQml/qqmlengine.h>
11#include <QtQml/qqmlcomponent.h>
12#include <QtQml/qqmlincubator.h>
13#include <QtQml/private/qv4qobjectwrapper_p.h>
14#include <QtQml/private/qqmlcomponent_p.h>
15#include <QtQml/private/qqmlengine_p.h>
16#include <QtQml/private/qqmlincubator_p.h>
17
19
20#if QT_CONFIG(quick_viewtransitions)
21static QQuickStackViewAttached *attachedStackObject(QQuickStackElement *element)
22{
23 QQuickStackViewAttached *attached = qobject_cast<QQuickStackViewAttached *>(qmlAttachedPropertiesObject<QQuickStackView>(element->item, false));
24 if (attached)
25 QQuickStackViewAttachedPrivate::get(attached)->element = element;
26 return attached;
27}
28#endif
29
31{
32public:
35 element(element)
36 {
37 }
38
39protected:
40 void setInitialState(QObject *object) override
41 {
42 auto privIncubator = QQmlIncubatorPrivate::get(this);
43 if (QQmlEnginePrivate *enginePriv = privIncubator->enginePriv) {
44 element->incubate(enginePriv->v4Engine.get(), object,
45 privIncubator->requiredProperties());
46 }
47 }
48
49private:
50 QQuickStackElement *element;
51};
52
53QQuickStackElement::QQuickStackElement()
54#if QT_CONFIG(quick_viewtransitions)
55 : QQuickItemViewTransitionableItem(nullptr)
56#endif
57{
58}
59
61{
62#if QT_CONFIG(quick_viewtransitions)
63 if (item)
64 QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed);
65#endif
66
67 if (ownComponent)
68 delete component;
69
70#if QT_CONFIG(quick_viewtransitions)
71 QQuickStackViewAttached *attached = attachedStackObject(this);
72 if (item) {
73 if (ownItem) {
74 item->setParentItem(nullptr);
75 item->deleteLater();
76 item = nullptr;
77 } else {
78 setVisible(false);
79 if (!widthValid)
80 item->resetWidth();
81 if (!heightValid)
82 item->resetHeight();
83 if (item->parentItem() != originalParent) {
84 item->setParentItem(originalParent);
85 } else {
86 if (attached)
87 QQuickStackViewAttachedPrivate::get(attached)->itemParentChanged(item, nullptr);
88 }
89 }
90 }
91
92 if (attached)
93 emit attached->removed();
94#endif
95}
96
98 QQmlEngine *engine, const QString &str, QQuickStackView *view, QString *error)
99{
100 QUrl url(str);
101 if (!url.isValid()) {
102 *error = QStringLiteral("invalid url: ") + str;
103 return nullptr;
104 }
105
106 if (url.isRelative())
107 url = qmlContext(view)->resolvedUrl(url);
108
110 element->component = new QQmlComponent(engine, url, view);
111 element->ownComponent = true;
112 return element;
113}
114
115QQuickStackElement *QQuickStackElement::fromObject(QObject *object, QQuickStackView *view, QString *error)
116{
117 Q_UNUSED(view);
118 QQmlComponent *component = qobject_cast<QQmlComponent *>(object);
119 QQuickItem *item = qobject_cast<QQuickItem *>(object);
120 if (!component && !item) {
121 *error = QQmlMetaType::prettyTypeName(object) + QStringLiteral(" is not supported. Must be Item or Component.");
122 return nullptr;
123 }
124
125 QQuickStackElement *element = new QQuickStackElement;
126 element->component = qobject_cast<QQmlComponent *>(object);
127#if QT_CONFIG(quick_viewtransitions)
128 element->item = qobject_cast<QQuickItem *>(object);
129 if (element->item)
130 element->originalParent = element->item->parentItem();
131#endif
132 return element;
133}
134
136 QQmlEngine *engine, QQuickStackView *view, QQuickStackViewArg arg)
137{
138 QQuickStackElement *element = new QQuickStackElement;
139#if QT_CONFIG(quick_viewtransitions)
140 element->item = arg.mItem;
141 if (element->item) {
142 element->originalParent = element->item->parentItem();
143
144 Q_ASSERT(!arg.mComponent);
145 Q_ASSERT(!arg.mUrl.isValid());
146 } else
147#endif
148 if (arg.mComponent) {
149 element->component = arg.mComponent;
150
151 Q_ASSERT(!arg.mUrl.isValid());
152 } else if (arg.mUrl.isValid()) {
153 element->component = new QQmlComponent(engine, arg.mUrl, view);
154 element->ownComponent = true;
155 } else {
156 qFatal("No Item, Component or URL set on arg passed to fromStrictArg");
157 }
158 return element;
159}
160
161bool QQuickStackElement::load(QV4::ExecutionEngine *v4, QQuickStackView *parent)
162{
163 setView(parent);
164 if (init)
165 return item;
166
167 if (!item) {
168 ownItem = true;
169
170 if (component->isLoading()) {
171 QObject::connect(component, &QQmlComponent::statusChanged, component,
172 [this](QQmlComponent::Status status) {
173 if (status == QQmlComponent::Ready)
174 load(component->engine()->handle(), view);
175 else if (status == QQmlComponent::Error)
176 QQuickStackViewPrivate::get(view)->warn(component->errorString().trimmed());
177 });
178 return true;
179 }
180
181 QQmlContext *context = component->creationContext();
182 if (!context)
183 context = qmlContext(parent);
184
185 QQuickStackIncubator incubator(this);
186 component->create(incubator, context);
187 if (component->isError())
188 QQuickStackViewPrivate::get(parent)->warn(component->errorString().trimmed());
189 } else {
190 initialize(v4, /*required properties=*/nullptr);
191 }
192 return item;
193}
194
196 QV4::ExecutionEngine *v4, QObject *object, RequiredProperties *requiredProperties)
197{
198 item = qmlobject_cast<QQuickItem *>(object);
199 if (item) {
200 QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
201 item->setParent(view);
202 initialize(v4, requiredProperties);
203 }
204}
205
207 QV4::ExecutionEngine *v4, RequiredProperties *requiredProperties)
208{
209 if (!item || init)
210 return;
211
212 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
213 if (!(widthValid = p->widthValid()))
214 item->setWidth(view->width());
215 if (!(heightValid = p->heightValid()))
216 item->setHeight(view->height());
217 item->setParentItem(view);
218
219 if (!properties.isUndefined()) {
220 QV4::Scope scope(v4);
221 Q_ASSERT(scope.engine);
222 QV4::ScopedValue ipv(scope, properties.value());
223 QV4::Scoped<QV4::QmlContext> qmlContext(scope, qmlCallingContext.value());
224 QV4::ScopedValue qmlObject(scope, QV4::QObjectWrapper::wrap(scope.engine, item));
225 QQmlComponentPrivate::setInitialProperties(
226 scope.engine, qmlContext, qmlObject, ipv, requiredProperties, item,
227 component ? QQmlComponentPrivate::get(component)->creator() : nullptr);
228 properties.clear();
229 }
230
231 if (requiredProperties && !requiredProperties->empty()) {
232 QString error;
233 for (const auto &property: *requiredProperties) {
234 error += QLatin1String("Property %1 was marked as required but not set.\n")
235 .arg(property.propertyName);
236 }
237 QQuickStackViewPrivate::get(view)->warn(error);
238 item = nullptr;
239 } else {
240 p->addItemChangeListener(this, QQuickItemPrivate::Destroyed);
241 }
242
243 init = true;
244}
245
247{
248 if (index == value)
249 return;
250
251 index = value;
252#if QT_CONFIG(quick_viewtransitions)
253 QQuickStackViewAttached *attached = attachedStackObject(this);
254 if (attached)
255 emit attached->indexChanged();
256#endif
257}
258
259void QQuickStackElement::setView(QQuickStackView *value)
260{
261 if (view == value)
262 return;
263
264 view = value;
265#if QT_CONFIG(quick_viewtransitions)
266 QQuickStackViewAttached *attached = attachedStackObject(this);
267 if (attached)
268 emit attached->viewChanged();
269#endif
270}
271
272void QQuickStackElement::setStatus(QQuickStackView::Status value)
273{
274 if (status == value)
275 return;
276
277 status = value;
278#if QT_CONFIG(quick_viewtransitions)
279 QQuickStackViewAttached *attached = attachedStackObject(this);
280 if (!attached)
281 return;
282
283 switch (value) {
284 case QQuickStackView::Inactive:
285 emit attached->deactivated();
286 break;
287 case QQuickStackView::Deactivating:
288 emit attached->deactivating();
289 break;
290 case QQuickStackView::Activating:
291 emit attached->activating();
292 break;
293 case QQuickStackView::Active:
294 emit attached->activated();
295 break;
296 default:
297 Q_UNREACHABLE();
298 break;
299 }
300
301 emit attached->statusChanged();
302#endif
303}
304
306{
307#if QT_CONFIG(quick_viewtransitions)
308 QQuickStackViewAttached *attached = attachedStackObject(this);
309#endif
310 if (!item
311#if QT_CONFIG(quick_viewtransitions)
312 || (attached && QQuickStackViewAttachedPrivate::get(attached)->explicitVisible)
313#endif
314 )
315 return;
316
317 item->setVisible(visible);
318}
319
320#if QT_CONFIG(quick_viewtransitions)
321void QQuickStackElement::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
322{
323 if (transitioner)
324 transitioner->transitionNextReposition(this, type, asTarget);
325}
326
327bool QQuickStackElement::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
328{
329 if (transitioner) {
330 if (item) {
331 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
332 // TODO: expose QQuickAnchorLine so we can test for other conflicting anchors
333 if (anchors && (anchors->fill() || anchors->centerIn()))
334 qmlWarning(item) << "StackView has detected conflicting anchors. Transitions may not execute properly.";
335 }
336
337 // TODO: add force argument to QQuickItemViewTransitionableItem::prepareTransition()?
338 nextTransitionToSet = true;
339 nextTransitionFromSet = true;
340 nextTransitionFrom += QPointF(1, 1);
341 return QQuickItemViewTransitionableItem::prepareTransition(transitioner, index, viewBounds);
342 }
343 return false;
344}
345
346void QQuickStackElement::startTransition(QQuickItemViewTransitioner *transitioner, QQuickStackView::Status status)
347{
348 setStatus(status);
349 if (transitioner)
350 QQuickItemViewTransitionableItem::startTransition(transitioner, index);
351}
352
353void QQuickStackElement::completeTransition(QQuickTransition *quickTransition)
354{
355 QQuickItemViewTransitionableItem::completeTransition(quickTransition);
356}
357#endif
358
360{
361#if QT_CONFIG(quick_viewtransitions)
362 item = nullptr;
363#endif
364}
365
366QT_END_NAMESPACE
void itemDestroyed(QQuickItem *item) override
void initialize(QV4::ExecutionEngine *v4, RequiredProperties *requiredProperties)
void setVisible(bool visible)
void setStatus(QQuickStackView::Status status)
void incubate(QV4::ExecutionEngine *v4, QObject *object, RequiredProperties *requiredProperties)
QQuickStackIncubator(QQuickStackElement *element)
void setInitialState(QObject *object) override
Called after the object is first created, but before complex property bindings are evaluated and,...
Combined button and popup list for selecting options.