/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPLv3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or later as published by the Free ** Software Foundation and appearing in the file LICENSE.GPL included in ** the packaging of this file. Please review the following information to ** ensure the GNU General Public License version 2.0 requirements will be ** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qquickstackelement_p_p.h" #include "qquickstackview_p_p.h" #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE static QQuickStackViewAttached *attachedStackObject(QQuickStackElement *element) { QQuickStackViewAttached *attached = qobject_cast(qmlAttachedPropertiesObject(element->item, false)); if (attached) QQuickStackViewAttachedPrivate::get(attached)->element = element; return attached; } class QQuickStackIncubator : public QQmlIncubator { public: QQuickStackIncubator(QQuickStackElement *element) : QQmlIncubator(Synchronous), element(element) { } protected: void setInitialState(QObject *object) override { element->incubate(object); } private: QQuickStackElement *element; }; QQuickStackElement::QQuickStackElement() : QQuickItemViewTransitionableItem(nullptr) { } QQuickStackElement::~QQuickStackElement() { if (item) QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed); if (ownComponent) delete component; QQuickStackViewAttached *attached = attachedStackObject(this); if (item) { if (ownItem) { item->setParentItem(nullptr); item->deleteLater(); item = nullptr; } else { setVisible(false); if (!widthValid) item->resetWidth(); if (!heightValid) item->resetHeight(); if (item->parentItem() != originalParent) { item->setParentItem(originalParent); } else { if (attached) QQuickStackViewAttachedPrivate::get(attached)->itemParentChanged(item, nullptr); } } } if (attached) emit attached->removed(); delete context; } QQuickStackElement *QQuickStackElement::fromString(const QString &str, QQuickStackView *view, QString *error) { QUrl url(str); if (!url.isValid()) { *error = QStringLiteral("invalid url: ") + str; return nullptr; } if (url.isRelative()) url = qmlContext(view)->resolvedUrl(url); QQuickStackElement *element = new QQuickStackElement; element->component = new QQmlComponent(qmlEngine(view), url, view); element->ownComponent = true; return element; } QQuickStackElement *QQuickStackElement::fromObject(QObject *object, QQuickStackView *view, QString *error) { Q_UNUSED(view); QQmlComponent *component = qobject_cast(object); QQuickItem *item = qobject_cast(object); if (!component && !item) { *error = QQmlMetaType::prettyTypeName(object) + QStringLiteral(" is not supported. Must be Item or Component."); return nullptr; } QQuickStackElement *element = new QQuickStackElement; element->component = qobject_cast(object); element->item = qobject_cast(object); if (element->item) element->originalParent = element->item->parentItem(); return element; } bool QQuickStackElement::load(QQuickStackView *parent) { setView(parent); if (!item) { ownItem = true; if (component->isLoading()) { QObject::connect(component, &QQmlComponent::statusChanged, [this](QQmlComponent::Status status) { if (status == QQmlComponent::Ready) load(view); else if (status == QQmlComponent::Error) QQuickStackViewPrivate::get(view)->warn(component->errorString().trimmed()); }); return true; } QQmlContext *creationContext = component->creationContext(); if (!creationContext) creationContext = qmlContext(parent); context = new QQmlContext(creationContext, parent); context->setContextObject(parent); QQuickStackIncubator incubator(this); component->create(incubator, context); if (component->isError()) QQuickStackViewPrivate::get(parent)->warn(component->errorString().trimmed()); } else { initialize(); } return item; } void QQuickStackElement::incubate(QObject *object) { item = qmlobject_cast(object); if (item) { QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership); item->setParent(view); initialize(); } } void QQuickStackElement::initialize() { if (!item || init) return; QQuickItemPrivate *p = QQuickItemPrivate::get(item); if (!(widthValid = p->widthValid)) item->setWidth(view->width()); if (!(heightValid = p->heightValid)) item->setHeight(view->height()); item->setParentItem(view); p->addItemChangeListener(this, QQuickItemPrivate::Destroyed); if (!properties.isUndefined()) { QQmlEngine *engine = qmlEngine(view); Q_ASSERT(engine); QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine); Q_ASSERT(v4); QV4::Scope scope(v4); QV4::ScopedValue ipv(scope, properties.value()); QV4::Scoped qmlContext(scope, qmlCallingContext.value()); QV4::ScopedValue qmlObject(scope, QV4::QObjectWrapper::wrap(v4, item)); #if Q_QML_PRIVATE_API_VERSION >= 6 RequiredProperties requiredPropertiesCurrentlyNotSupported; QQmlComponentPrivate::setInitialProperties(v4, qmlContext, qmlObject, ipv, requiredPropertiesCurrentlyNotSupported, item); #else QQmlComponentPrivate::setInitialProperties(v4, qmlContext, qmlObject, ipv); #endif properties.clear(); } init = true; } void QQuickStackElement::setIndex(int value) { if (index == value) return; index = value; QQuickStackViewAttached *attached = attachedStackObject(this); if (attached) emit attached->indexChanged(); } void QQuickStackElement::setView(QQuickStackView *value) { if (view == value) return; view = value; QQuickStackViewAttached *attached = attachedStackObject(this); if (attached) emit attached->viewChanged(); } void QQuickStackElement::setStatus(QQuickStackView::Status value) { if (status == value) return; status = value; QQuickStackViewAttached *attached = attachedStackObject(this); if (!attached) return; switch (value) { case QQuickStackView::Inactive: emit attached->deactivated(); break; case QQuickStackView::Deactivating: emit attached->deactivating(); break; case QQuickStackView::Activating: emit attached->activating(); break; case QQuickStackView::Active: emit attached->activated(); break; default: Q_UNREACHABLE(); break; } emit attached->statusChanged(); } void QQuickStackElement::setVisible(bool visible) { QQuickStackViewAttached *attached = attachedStackObject(this); if (!item || (attached && QQuickStackViewAttachedPrivate::get(attached)->explicitVisible)) return; item->setVisible(visible); } void QQuickStackElement::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget) { if (transitioner) transitioner->transitionNextReposition(this, type, asTarget); } bool QQuickStackElement::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds) { if (transitioner) { if (item) { QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors; // TODO: expose QQuickAnchorLine so we can test for other conflicting anchors if (anchors && (anchors->fill() || anchors->centerIn())) qmlWarning(item) << "StackView has detected conflicting anchors. Transitions may not execute properly."; } // TODO: add force argument to QQuickItemViewTransitionableItem::prepareTransition()? nextTransitionToSet = true; nextTransitionFromSet = true; nextTransitionFrom += QPointF(1, 1); return QQuickItemViewTransitionableItem::prepareTransition(transitioner, index, viewBounds); } return false; } void QQuickStackElement::startTransition(QQuickItemViewTransitioner *transitioner, QQuickStackView::Status status) { setStatus(status); if (transitioner) QQuickItemViewTransitionableItem::startTransition(transitioner, index); } void QQuickStackElement::itemDestroyed(QQuickItem *) { item = nullptr; } QT_END_NAMESPACE