aboutsummaryrefslogtreecommitdiffstats
path: root/src/controls/qquickabstractstackview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/controls/qquickabstractstackview.cpp')
-rw-r--r--src/controls/qquickabstractstackview.cpp565
1 files changed, 383 insertions, 182 deletions
diff --git a/src/controls/qquickabstractstackview.cpp b/src/controls/qquickabstractstackview.cpp
index a849bd94..e5496697 100644
--- a/src/controls/qquickabstractstackview.cpp
+++ b/src/controls/qquickabstractstackview.cpp
@@ -35,7 +35,10 @@
****************************************************************************/
#include "qquickabstractstackview_p.h"
-#include "qquickabstractcontainer_p_p.h"
+#include "qquickabstractstackview_p_p.h"
+
+#include <QtQml/qjsvalue.h>
+#include <QtQml/qqmlengine.h>
QT_BEGIN_NAMESPACE
@@ -50,243 +53,407 @@ QT_BEGIN_NAMESPACE
TODO
*/
-class QQuickStackElement
+QQuickAbstractStackView::QQuickAbstractStackView(QQuickItem *parent) :
+ QQuickAbstractContainer(*(new QQuickAbstractStackViewPrivate), parent)
{
- QQuickStackElement() : ownItem(false), item(Q_NULLPTR), ownComponent(false), component(Q_NULLPTR) { }
-
-public:
- static QQuickStackElement *fromString(const QString &str, QQmlEngine *engine, QObject *parent)
- {
- QQuickStackElement *element = new QQuickStackElement;
- element->component = new QQmlComponent(engine, QUrl(str), parent);
- element->ownComponent = true;
- return element;
- }
+ setFlag(ItemIsFocusScope);
+}
- static QQuickStackElement *fromObject(QObject *object)
- {
- QQuickStackElement *element = new QQuickStackElement;
- element->component = qobject_cast<QQmlComponent *>(object);
- element->item = qobject_cast<QQuickItem *>(object);
- return element;
+QQuickAbstractStackView::~QQuickAbstractStackView()
+{
+ Q_D(QQuickAbstractStackView);
+ if (d->transitioner) {
+ d->transitioner->setChangeListener(Q_NULLPTR);
+ delete d->transitioner;
}
+ qDeleteAll(d->elements);
+}
- bool ownItem;
- QQuickItem *item;
-
- bool ownComponent;
- QQmlComponent *component;
-};
+QQuickStackAttached *QQuickAbstractStackView::qmlAttachedProperties(QObject *object)
+{
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (!item) {
+ qmlInfo(object) << "StackView must be attached to an Item";
+ return Q_NULLPTR;
+ }
+ return new QQuickStackAttached(item);
+}
-class QQuickAbstractStackViewPrivate : public QQuickAbstractContainerPrivate
+/*!
+ \qmlproperty bool QtQuickControls2::StackView::busy
+ \readonly
+ This property holds whether a transition is running.
+*/
+bool QQuickAbstractStackView::busy() const
{
- Q_DECLARE_PUBLIC(QQuickAbstractStackView)
+ Q_D(const QQuickAbstractStackView);
+ return d->transitioner && !d->transitioner->runningJobs.isEmpty();
+}
-public:
- QQuickAbstractStackViewPrivate() : busy(false), depth(0), currentItem(Q_NULLPTR) { }
+/*!
+ \qmlproperty int QtQuickControls2::StackView::depth
+ \readonly
+ This property holds the number of items currently pushed onto the stack.
+*/
+int QQuickAbstractStackView::depth() const
+{
+ Q_D(const QQuickAbstractStackView);
+ return d->elements.count();
+}
- void setBusy(bool busy);
- void setDepth(int depth);
- void setCurrentItem(QQuickItem *item);
+/*!
+ \qmlproperty Item QtQuickControls2::StackView::currentItem
+ \readonly
+ This property holds the current top-most item in the stack.
+*/
+QQuickItem *QQuickAbstractStackView::currentItem() const
+{
+ Q_D(const QQuickAbstractStackView);
+ return d->currentItem;
+}
- QList<QQuickStackElement *> createElements(const QV4::ScopedValue &value);
- QQuickItem *pushElements(const QList<QQuickStackElement *> &elements, QQuickAbstractStackView::Operation operation);
+/*!
+ \qmlmethod Item QtQuickControls2::StackView::get(index, behavior = DontLoad)
- bool busy;
- int depth;
- QVariant initialItem;
- QQuickItem *currentItem;
- QStack<QQuickStackElement *> elements;
-};
+ Supported behavior values:
+ \li StackView.DontLoad
+ \li StackView.ForceLoad
-void QQuickAbstractStackViewPrivate::setBusy(bool value)
+ TODO
+*/
+QQuickItem *QQuickAbstractStackView::get(int index, LoadBehavior behavior)
{
- Q_Q(QQuickAbstractStackView);
- if (busy != value) {
- busy = value;
- emit q->busyChanged();
+ Q_D(QQuickAbstractStackView);
+ QQuickStackElement *element = d->elements.value(index);
+ if (element) {
+ if (behavior == ForceLoad)
+ element->load(this);
+ return element->item;
}
+ return Q_NULLPTR;
}
-void QQuickAbstractStackViewPrivate::setDepth(int value)
+/*!
+ \qmlmethod Item QtQuickControls2::StackView::find(callback, behavior = DontLoad)
+
+ Supported behavior values:
+ \li StackView.DontLoad
+ \li StackView.ForceLoad
+
+ TODO
+*/
+QQuickItem *QQuickAbstractStackView::find(const QJSValue &callback, LoadBehavior behavior)
{
- Q_Q(QQuickAbstractStackView);
- if (depth != value) {
- depth = value;
- emit q->depthChanged();
+ Q_D(QQuickAbstractStackView);
+ QJSValue func(callback);
+ QQmlEngine *engine = qmlEngine(this);
+ if (!engine || !func.isCallable()) // TODO: warning?
+ return Q_NULLPTR;
+
+ for (int i = d->elements.count() - 1; i >= 0; --i) {
+ QQuickStackElement *element = d->elements.at(i);
+ if (behavior == ForceLoad)
+ element->load(this);
+ if (element->item) {
+ QJSValue rv = func.call(QJSValueList() << engine->newQObject(element->item) << i);
+ if (rv.toBool())
+ return element->item;
+ }
}
+
+ return Q_NULLPTR;
}
-void QQuickAbstractStackViewPrivate::setCurrentItem(QQuickItem *item)
+/*!
+ \qmlmethod Item QtQuickControls2::StackView::push(item, properties, operation)
+
+ TODO
+*/
+void QQuickAbstractStackView::push(QQmlV4Function *args)
{
- Q_Q(QQuickAbstractStackView);
- if (currentItem != item) {
- currentItem = item;
- emit q->currentItemChanged();
+ Q_D(QQuickAbstractStackView);
+ if (args->length() <= 0) {
+ qmlInfo(this) << "push: missing arguments";
+ args->setReturnValue(QV4::Encode::null());
+ return;
}
-}
-QList<QQuickStackElement *> QQuickAbstractStackViewPrivate::createElements(const QV4::ScopedValue &value)
-{
- Q_Q(QQuickAbstractStackView);
- QList<QQuickStackElement *> elements;
- if (QV4::String *s = value->asString()) {
- qDebug() << "### STRING:" << s->toQString();
- elements += QQuickStackElement::fromString(s->toQString(), qmlEngine(q), q);
- } else if (QV4::ArrayObject *a = value->asArrayObject()) {
- int len = a->getLength();
- qDebug() << "### ARRAY:" << len;
- for (int i = 0; i < len; ++i) {
- QV4::Scope scope(a->engine());
- QV4::ScopedValue v(scope, a->getIndexed(i));
- elements += createElements(v);
- }
- } else if (const QV4::QObjectWrapper *o =value->as<QV4::QObjectWrapper>()) {
- qDebug() << "### QOBJECT:" << o->object();
- elements += QQuickStackElement::fromObject(o->object());
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ Operation operation = d->elements.isEmpty() ? Immediate : Transition;
+ QV4::ScopedValue lastArg(scope, (*args)[args->length() - 1]);
+ if (lastArg->isInt32())
+ operation = static_cast<Operation>(lastArg->toInt32());
+
+ QList<QQuickStackElement *> elements = d->parseElements(args);
+ if (elements.isEmpty()) {
+ qmlInfo(this) << "push: nothing to push";
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ QQuickStackElement *exit = Q_NULLPTR;
+ if (!d->elements.isEmpty())
+ exit = d->elements.top();
+
+ if (d->pushElements(elements)) {
+ emit depthChanged();
+ QQuickStackElement *enter = d->elements.top();
+ d->pushTransition(enter, exit, boundingRect(), operation == Immediate);
+ d->setCurrentItem(enter->item);
+ }
+
+ if (d->currentItem) {
+ QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(v4, d->currentItem));
+ args->setReturnValue(rv->asReturnedValue());
} else {
- qDebug("### UNKNOWN");
+ args->setReturnValue(QV4::Encode::null());
}
- return elements;
}
-QQuickItem *QQuickAbstractStackViewPrivate::pushElements(const QList<QQuickStackElement *> &elems, QQuickAbstractStackView::Operation operation)
+/*!
+ \qmlmethod Item QtQuickControls2::StackView::pop(item = null, operation = Transition)
+
+ TODO
+*/
+void QQuickAbstractStackView::pop(QQmlV4Function *args)
{
- Q_Q(QQuickAbstractStackView);
- Q_UNUSED(operation); // TODO
- if (!elems.isEmpty()) {
- foreach (QQuickStackElement *elem, elems) {
- elements.push(elem);
+ Q_D(QQuickAbstractStackView);
+ int argc = args->length();
+ if (d->elements.count() <= 1 || argc > 2) {
+ if (argc > 2)
+ qmlInfo(this) << "pop: too many arguments";
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ QQuickStackElement *exit = d->elements.pop();
+ QQuickStackElement *enter = d->elements.top();
+
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ if (argc > 0) {
+ QV4::ScopedValue value(scope, (*args)[0]);
+ if (value->isNull()) {
+ enter = d->elements.value(0);
+ } else if (!value->isUndefined() && !value->isInt32()) {
+ enter = d->findElement(value);
+ if (!enter) {
+ qmlInfo(this) << "pop: unknown argument: " << value->toQString(); // TODO: safe?
+ args->setReturnValue(QV4::Encode::null());
+ d->elements.push(exit); // restore
+ return;
+ }
}
- emit q->depthChanged();
- // TODO: load
- return elems.last()->item;
}
- return Q_NULLPTR;
+
+ Operation operation = Transition;
+ if (argc > 0) {
+ QV4::ScopedValue lastArg(scope, (*args)[argc - 1]);
+ if (lastArg->isInt32())
+ operation = static_cast<Operation>(lastArg->toInt32());
+ }
+
+ QQuickItem *previousItem = Q_NULLPTR;
+
+ if (d->popElements(enter)) {
+ if (exit)
+ previousItem = exit->item;
+ emit depthChanged();
+ d->popTransition(enter, exit, boundingRect(), operation == Immediate);
+ d->setCurrentItem(enter->item);
+ }
+
+ if (previousItem) {
+ QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(v4, previousItem));
+ args->setReturnValue(rv->asReturnedValue());
+ } else {
+ args->setReturnValue(QV4::Encode::null());
+ }
}
-QQuickAbstractStackView::QQuickAbstractStackView(QQuickItem *parent) :
- QQuickAbstractContainer(*(new QQuickAbstractStackViewPrivate), parent)
+/*!
+ \qmlmethod Item QtQuickControls2::StackView::push(item, properties, operation = Transition)
+
+ TODO
+*/
+void QQuickAbstractStackView::replace(QQmlV4Function *args)
{
- setFlag(ItemIsFocusScope);
+ Q_D(QQuickAbstractStackView);
+ if (args->length() <= 0) {
+ qmlInfo(this) << "replace: missing arguments";
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ Operation operation = d->elements.isEmpty() ? Immediate : Transition;
+ QV4::ScopedValue lastArg(scope, (*args)[args->length() - 1]);
+ if (lastArg->isInt32())
+ operation = static_cast<Operation>(lastArg->toInt32());
+
+ QQuickStackElement *target = Q_NULLPTR;
+ QV4::ScopedValue firstArg(scope, (*args)[0]);
+ if (firstArg->isNull())
+ target = d->elements.value(0);
+ else if (!firstArg->isInt32())
+ target = d->findElement(firstArg);
+
+ QList<QQuickStackElement *> elements = d->parseElements(args, target ? 1 : 0);
+ if (elements.isEmpty()) {
+ qmlInfo(this) << "replace: nothing to push";
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ int depth = d->elements.count();
+ QQuickStackElement* exit = Q_NULLPTR;
+ if (!d->elements.isEmpty())
+ exit = d->elements.pop();
+
+ if (d->replaceElements(target, elements)) {
+ if (depth != d->elements.count())
+ emit depthChanged();
+ QQuickStackElement *enter = d->elements.top();
+ d->replaceTransition(enter, exit, boundingRect(), operation == Immediate);
+ d->setCurrentItem(enter->item);
+ }
+
+ if (d->currentItem) {
+ QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(v4, d->currentItem));
+ args->setReturnValue(rv->asReturnedValue());
+ } else {
+ args->setReturnValue(QV4::Encode::null());
+ }
}
-QQuickAbstractStackView::~QQuickAbstractStackView()
+/*!
+ \qmlmethod Item QtQuickControls2::StackView::clear()
+
+ TODO
+*/
+void QQuickAbstractStackView::clear()
{
Q_D(QQuickAbstractStackView);
+ d->setCurrentItem(Q_NULLPTR);
qDeleteAll(d->elements);
+ d->elements.clear();
+ emit depthChanged();
}
/*!
- \qmlproperty bool QtQuickControls2::StackView::busy
- \readonly
- \c true if a transition is running, and \c false otherwise.
+ \qmlproperty var QtQuickControls2::StackView::initialItem
+
+ This property holds the initial item.
+
+ \sa push()
*/
-bool QQuickAbstractStackView::busy() const
+QVariant QQuickAbstractStackView::initialItem() const
{
Q_D(const QQuickAbstractStackView);
- return d->busy;
+ return d->initialItem;
}
-// TODO: remove
-void QQuickAbstractStackView::setBusy(bool busy)
+void QQuickAbstractStackView::setInitialItem(const QVariant &item)
{
Q_D(QQuickAbstractStackView);
- d->setBusy(busy);
+ d->initialItem = item;
}
/*!
- \qmlproperty int QtQuickControls2::StackView::depth
- \readonly
- The number of items currently pushed onto the stack.
+ \qmlproperty Transition QtQuickControls2::StackView::popEnter
+
+ TODO
*/
-int QQuickAbstractStackView::depth() const
+QQuickTransition *QQuickAbstractStackView::popEnter() const
{
Q_D(const QQuickAbstractStackView);
- return d->depth;
+ if (d->transitioner)
+ return d->transitioner->removeDisplacedTransition;
+ return Q_NULLPTR;
}
-// TODO: remove
-void QQuickAbstractStackView::setDepth(int depth)
+void QQuickAbstractStackView::setPopEnter(QQuickTransition *enter)
{
Q_D(QQuickAbstractStackView);
- d->setDepth(depth);
+ d->ensureTransitioner();
+ if (d->transitioner->removeDisplacedTransition != enter) {
+ d->transitioner->removeDisplacedTransition = enter;
+ emit popEnterChanged();
+ }
}
/*!
- \qmlproperty Item QtQuickControls2::StackView::currentItem
- \readonly
- The currently top-most item in the stack.
+ \qmlproperty Transition QtQuickControls2::StackView::popExit
+
+ TODO
*/
-QQuickItem *QQuickAbstractStackView::currentItem() const
+QQuickTransition *QQuickAbstractStackView::popExit() const
{
Q_D(const QQuickAbstractStackView);
- return d->currentItem;
-}
-
-// TODO: remove
-void QQuickAbstractStackView::setCurrentItem(QQuickItem *item)
-{
- Q_D(QQuickAbstractStackView);
- d->setCurrentItem(item);
+ if (d->transitioner)
+ return d->transitioner->removeTransition;
+ return Q_NULLPTR;
}
-QQuickItem *QQuickAbstractStackView::qpush(QQmlV4Function *args)
+void QQuickAbstractStackView::setPopExit(QQuickTransition *exit)
{
Q_D(QQuickAbstractStackView);
- QV4::ExecutionEngine *v4 = args->v4engine();
- QV4::Scope scope(v4);
-
- Operation operation = d->elements.isEmpty() ? Immediate : Transition;
- QList<QQuickStackElement *> elements;
- for (int i = 0; i < args->length(); ++i) {
- QV4::ScopedValue value(scope, (*args)[i]);
- if (value->isInt32())
- operation = static_cast<Operation>(value->toInt32());
- else
- elements += d->createElements(value);
+ d->ensureTransitioner();
+ if (d->transitioner->removeTransition != exit) {
+ d->transitioner->removeTransition = exit;
+ emit popExitChanged();
}
- return d->pushElements(elements, operation);
}
-QQuickItem *QQuickAbstractStackView::qpop(QQmlV4Function *args)
+/*!
+ \qmlproperty Transition QtQuickControls2::StackView::pushEnter
+
+ TODO
+*/
+QQuickTransition *QQuickAbstractStackView::pushEnter() const
{
- Q_UNUSED(args); // TODO
+ Q_D(const QQuickAbstractStackView);
+ if (d->transitioner)
+ return d->transitioner->addTransition;
return Q_NULLPTR;
}
-void QQuickAbstractStackView::qclear()
+void QQuickAbstractStackView::setPushEnter(QQuickTransition *enter)
{
- // TODO
+ Q_D(QQuickAbstractStackView);
+ d->ensureTransitioner();
+ if (d->transitioner->addTransition != enter) {
+ d->transitioner->addTransition = enter;
+ emit pushEnterChanged();
+ }
}
/*!
- \qmlproperty var QtQuickControls2::StackView::initialItem
-
- The first \l item that should be shown when the StackView is created.
- \a initialItem can take same value as the first argument to \l{StackView::push()}
- {StackView.push()}. Note that this is just a convenience for writing
- \c{Component.onCompleted: stackView.push(myInitialItem)}
-
- Examples:
+ \qmlproperty Transition QtQuickControls2::StackView::pushExit
- \list
- \li initialItem: Qt.resolvedUrl("MyItem.qml")
- \li initialItem: myItem
- \li initialItem: {"item" : Qt.resolvedUrl("MyRectangle.qml"), "properties" : {"color" : "red"}}
- \endlist
- \sa push
+ TODO
*/
-QVariant QQuickAbstractStackView::initialItem() const
+QQuickTransition *QQuickAbstractStackView::pushExit() const
{
Q_D(const QQuickAbstractStackView);
- return d->initialItem;
+ if (d->transitioner)
+ return d->transitioner->addDisplacedTransition;
+ return Q_NULLPTR;
}
-void QQuickAbstractStackView::setInitialItem(const QVariant &item)
+void QQuickAbstractStackView::setPushExit(QQuickTransition *exit)
{
Q_D(QQuickAbstractStackView);
- d->initialItem = item;
+ d->ensureTransitioner();
+ if (d->transitioner->addDisplacedTransition != exit) {
+ d->transitioner->addDisplacedTransition = exit;
+ emit pushExitChanged();
+ }
}
void QQuickAbstractStackView::componentComplete()
@@ -294,59 +461,93 @@ void QQuickAbstractStackView::componentComplete()
QQuickAbstractContainer::componentComplete();
Q_D(QQuickAbstractStackView);
+ QQuickStackElement *element = Q_NULLPTR;
if (QObject *o = d->initialItem.value<QObject *>())
- d->pushElements(QList<QQuickStackElement *>() << QQuickStackElement::fromObject(o), Immediate);
+ element = QQuickStackElement::fromObject(o, this);
else if (d->initialItem.canConvert<QString>())
- d->pushElements(QList<QQuickStackElement *>() << QQuickStackElement::fromString(d->initialItem.toString(), qmlEngine(this), this), Immediate);
+ element = QQuickStackElement::fromString(d->initialItem.toString(), this);
+ if (d->pushElement(element)) {
+ emit depthChanged();
+ d->setCurrentItem(element->item);
+ }
}
-/*!
- \qmltype Stack
- \inherits QtObject
- \instantiates QQuickStackAttached
- \inqmlmodule QtQuick.Controls
- \ingroup navigation
- \brief TODO
+void QQuickAbstractStackView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QQuickAbstractContainer::geometryChanged(newGeometry, oldGeometry);
- TODO
-*/
+ Q_D(QQuickAbstractStackView);
+ foreach (QQuickStackElement *element, d->elements) {
+ if (element->item) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(element->item);
+ if (!p->widthValid) {
+ element->item->setWidth(newGeometry.width());
+ p->widthValid = false;
+ }
+ if (!p->heightValid) {
+ element->item->setHeight(newGeometry.height());
+ p->heightValid = false;
+ }
+ }
+ }
+}
-class QQuickStackAttachedPrivate : public QObjectPrivate
+void QQuickStackAttachedPrivate::init()
{
-public:
- QQuickStackAttachedPrivate() : status(QQuickStackAttached::Inactive) { }
-
- QQuickStackAttached::Status status;
-};
+ QQuickItem *item = qobject_cast<QQuickItem *>(parent);
+ if (item) {
+ QQuickAbstractStackView *view = qobject_cast<QQuickAbstractStackView *>(item->parentItem());
+ if (view) {
+ element = QQuickAbstractStackViewPrivate::get(view)->findElement(item);
+ if (element)
+ initialized = true;
+ }
+ }
+}
-QQuickStackAttached::QQuickStackAttached(QObject *parent) :
- QObject(*(new QQuickStackAttachedPrivate), parent)
+void QQuickStackAttachedPrivate::reset()
{
+ Q_Q(QQuickStackAttached);
+ int oldIndex = element ? element->index : -1;
+ QQuickAbstractStackView::Status oldStatus = element ? element->status : QQuickAbstractStackView::Inactive;
+
+ element = Q_NULLPTR;
+
+ if (oldIndex != -1)
+ emit q->indexChanged();
+ if (oldStatus != QQuickAbstractStackView::Inactive)
+ emit q->statusChanged();
}
-QQuickStackAttached *QQuickStackAttached::qmlAttachedProperties(QObject *object)
+QQuickStackAttached::QQuickStackAttached(QQuickItem *parent) :
+ QObject(*(new QQuickStackAttachedPrivate), parent)
{
- return new QQuickStackAttached(object);
}
/*!
- \qmlattachedproperty enumeration QtQuickControls2::Stack::status
+ \qmlattachedproperty int QtQuickControls2::StackView::index
TODO
*/
-QQuickStackAttached::Status QQuickStackAttached::status() const
+int QQuickStackAttached::index() const
{
Q_D(const QQuickStackAttached);
- return d->status;
+ if (!d->initialized)
+ const_cast<QQuickStackAttachedPrivate *>(d)->init();
+ return d->element ? d->element->index : -1;
}
-void QQuickStackAttached::setStatus(Status status)
+/*!
+ \qmlattachedproperty enumeration QtQuickControls2::StackView::status
+
+ TODO
+*/
+QQuickAbstractStackView::Status QQuickStackAttached::status() const
{
- Q_D(QQuickStackAttached);
- if (d->status != status) {
- d->status = status;
- emit statusChanged();
- }
+ Q_D(const QQuickStackAttached);
+ if (!d->initialized)
+ const_cast<QQuickStackAttachedPrivate *>(d)->init();
+ return d->element ? d->element->status : QQuickAbstractStackView::Inactive;
}
QT_END_NAMESPACE