diff options
Diffstat (limited to 'src/quicktemplates/qquickstackview_p.cpp')
-rw-r--r-- | src/quicktemplates/qquickstackview_p.cpp | 123 |
1 files changed, 121 insertions, 2 deletions
diff --git a/src/quicktemplates/qquickstackview_p.cpp b/src/quicktemplates/qquickstackview_p.cpp index 99127d84b6..0288ff1f4b 100644 --- a/src/quicktemplates/qquickstackview_p.cpp +++ b/src/quicktemplates/qquickstackview_p.cpp @@ -3,8 +3,11 @@ #include "qquickstackview_p_p.h" #include "qquickstackelement_p_p.h" +#if QT_CONFIG(quick_viewtransitions) #include "qquickstacktransition_p_p.h" +#endif +#include <QtCore/qscopedvaluerollback.h> #include <QtQml/qqmlinfo.h> #include <QtQml/qqmllist.h> #include <QtQml/private/qv4qmlcontext_p.h> @@ -46,7 +49,7 @@ void QQuickStackViewPrivate::setCurrentItem(QQuickStackElement *element) emit q->currentItemChanged(); } -static bool initProperties(QQuickStackElement *element, const QV4::Value &props, QQmlV4Function *args) +static bool initProperties(QQuickStackElement *element, const QV4::Value &props, QQmlV4FunctionPtr args) { if (props.isObject()) { const QV4::QObjectWrapper *wrapper = props.as<QV4::QObjectWrapper>(); @@ -60,7 +63,7 @@ static bool initProperties(QQuickStackElement *element, const QV4::Value &props, return false; } -QList<QQuickStackElement *> QQuickStackViewPrivate::parseElements(int from, QQmlV4Function *args, QStringList *errors) +QList<QQuickStackElement *> QQuickStackViewPrivate::parseElements(int from, QQmlV4FunctionPtr args, QStringList *errors) { QV4::ExecutionEngine *v4 = args->v4engine(); auto context = v4->callingQmlContext(); @@ -106,6 +109,47 @@ QList<QQuickStackElement *> QQuickStackViewPrivate::parseElements(int from, QQml return elements; } +QList<QQuickStackElement *> QQuickStackViewPrivate::parseElements(const QList<QQuickStackViewArg> &args) +{ + Q_Q(QQuickStackView); + QList<QQuickStackElement *> stackElements; + for (int i = 0; i < args.size(); ++i) { + const QQuickStackViewArg &arg = args.at(i); + QVariantMap properties; + // Look ahead at the next arg in case it contains properties for this + // Item/Component/URL. + if (i < args.size() - 1) { + const QQuickStackViewArg &nextArg = args.at(i + 1); + // If mProperties isn't empty, the user passed properties. + // If it is empty, but mItem, mComponent and mUrl also are, + // then they passed an empty property map. + if (!nextArg.mProperties.isEmpty() + || (!nextArg.mItem && !nextArg.mComponent && !nextArg.mUrl.isValid())) { + properties = nextArg.mProperties; + ++i; + } + } + + // Remove any items that are already in the stack, as they can't be in two places at once. + if (findElement(arg.mItem)) + continue; + + // We look ahead one index for each Item/Component/URL, so if this arg is + // a property map, the user has passed two or more in a row. + if (!arg.mProperties.isEmpty()) { + qmlWarning(q) << "Properties must come after an Item, Component or URL"; + return {}; + } + + QQuickStackElement *element = QQuickStackElement::fromStackViewArg(q, arg); + QV4::ExecutionEngine *v4Engine = qmlEngine(q)->handle(); + element->properties.set(v4Engine, v4Engine->fromVariant(properties)); + element->qmlCallingContext.set(v4Engine, v4Engine->qmlContext()); + stackElements.append(element); + } + return stackElements; +} + QQuickStackElement *QQuickStackViewPrivate::findElement(QQuickItem *item) const { if (item) { @@ -204,6 +248,80 @@ bool QQuickStackViewPrivate::replaceElements(QQuickStackElement *target, const Q return pushElements(elems); } +QQuickItem *QQuickStackViewPrivate::popToItem(QQuickItem *item, QQuickStackView::Operation operation, CurrentItemPolicy currentItemPolicy) +{ + const QString operationName = QStringLiteral("pop"); + if (modifyingElements) { + warnOfInterruption(operationName); + return nullptr; + } + + QScopedValueRollback<bool> modifyingElementsRollback(modifyingElements, true); + QScopedValueRollback<QString> operationNameRollback(this->operation, operationName); + if (elements.isEmpty()) { + warn(QStringLiteral("no items to pop")); + return nullptr; + } + + if (!item) { + warn(QStringLiteral("item cannot be null")); + return nullptr; + } + + const int oldDepth = elements.size(); + QQuickStackElement *exit = elements.pop(); + // top() here will be the item below the previously current item, since we just popped above. + QQuickStackElement *enter = elements.top(); + + bool nothingToDo = false; + if (item != currentItem) { + if (!item) { + // Popping down to the first item. + enter = elements.value(0); + } else { + // Popping down to an arbitrary item. + enter = findElement(item); + if (!enter) { + warn(QStringLiteral("can't find item to pop: ") + QDebug::toString(item)); + nothingToDo = true; + } + } + } else { + if (currentItemPolicy == CurrentItemPolicy::DoNotPop) { + // popToItem was called with the currentItem, which means there are no items + // to pop because it's already at the top. + nothingToDo = true; + } + // else: popToItem was called by popCurrentItem, and so we _should_ pop. + } + if (nothingToDo) { + // Restore the element we popped earlier. + elements.push(exit); + return nullptr; + } + + QQuickItem *previousItem = nullptr; + if (popElements(enter)) { + if (exit) { + exit->removal = true; + removing.insert(exit); + previousItem = exit->item; + } + depthChange(elements.size(), oldDepth); +#if QT_CONFIG(quick_viewtransitions) + Q_Q(QQuickStackView); + startTransition(QQuickStackTransition::popExit(operation, exit, q), + QQuickStackTransition::popEnter(operation, enter, q), + operation == QQuickStackView::Immediate); +#else + Q_UNUSED(operation); +#endif + setCurrentItem(enter); + } + return previousItem; +} + +#if QT_CONFIG(quick_viewtransitions) void QQuickStackViewPrivate::ensureTransitioner() { if (!transitioner) { @@ -301,6 +419,7 @@ void QQuickStackViewPrivate::viewItemTransitionFinished(QQuickItemViewTransition removing.remove(element); } +#endif void QQuickStackViewPrivate::setBusy(bool b) { |