diff options
author | Mitch Curtis <mitch.curtis@theqtcompany.com> | 2015-09-14 12:57:42 +0200 |
---|---|---|
committer | Mitch Curtis <mitch.curtis@theqtcompany.com> | 2015-09-16 13:00:06 +0000 |
commit | f00c61126e7337bc9da88eefd47b689240fe39f5 (patch) | |
tree | a7e294cfe9ec1636c3bc1a0c9ea66b7582c69b02 | |
parent | d833c9224984ad408ca4074cbe147a39dabc8277 (diff) |
SwipeView: add index, view and isCurrentItem attached properties
Task-number: QTBUG-48052
Change-Id: I0d6d27cc352d999d8071b979349f2364f0edf74d
Reviewed-by: J-P Nurmi <jpnurmi@theqtcompany.com>
-rw-r--r-- | src/controls/qquickcontainer.cpp | 1 | ||||
-rw-r--r-- | src/imports/extras/qquickswipeview.cpp | 211 | ||||
-rw-r--r-- | src/imports/extras/qquickswipeview_p.h | 32 | ||||
-rw-r--r-- | src/imports/extras/qtquickextras2plugin.cpp | 1 | ||||
-rw-r--r-- | tests/auto/extras/data/tst_swipeview.qml | 61 |
5 files changed, 302 insertions, 4 deletions
diff --git a/src/controls/qquickcontainer.cpp b/src/controls/qquickcontainer.cpp index 20b900a2..76a4e192 100644 --- a/src/controls/qquickcontainer.cpp +++ b/src/controls/qquickcontainer.cpp @@ -95,6 +95,7 @@ void QQuickContainerPrivate::moveItem(int from, int to) void QQuickContainerPrivate::removeItem(int index, QQuickItem *item) { QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + item->setParentItem(Q_NULLPTR); contentData.removeOne(item); contentModel->remove(index); } diff --git a/src/imports/extras/qquickswipeview.cpp b/src/imports/extras/qquickswipeview.cpp index c359a983..ec76d7f2 100644 --- a/src/imports/extras/qquickswipeview.cpp +++ b/src/imports/extras/qquickswipeview.cpp @@ -66,6 +66,8 @@ public: void moveItem(int from, int to) Q_DECL_OVERRIDE; void removeItem(int index, QQuickItem *item) Q_DECL_OVERRIDE; + static QQuickSwipeViewPrivate *get(QQuickSwipeView *view); + int currentIndex; bool updatingCurrent; }; @@ -132,6 +134,11 @@ void QQuickSwipeViewPrivate::removeItem(int index, QQuickItem *item) emit q->currentIndexChanged(); } +QQuickSwipeViewPrivate *QQuickSwipeViewPrivate::get(QQuickSwipeView *view) +{ + return view->d_func(); +} + QQuickSwipeView::QQuickSwipeView(QQuickItem *parent) : QQuickContainer(*(new QQuickSwipeViewPrivate), parent) { @@ -171,6 +178,17 @@ QQuickItem *QQuickSwipeView::currentItem() const return itemAt(d->currentIndex); } +QQuickSwipeViewAttached *QQuickSwipeView::qmlAttachedProperties(QObject *object) +{ + QQuickItem *item = qobject_cast<QQuickItem *>(object); + if (!item) { + qWarning() << "SwipeView: attached properties must be accessed from within a child item"; + return Q_NULLPTR; + } + + return new QQuickSwipeViewAttached(item); +} + void QQuickSwipeView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { Q_D(QQuickSwipeView); @@ -187,6 +205,199 @@ void QQuickSwipeView::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem connect(newItem, SIGNAL(currentIndexChanged()), this, SLOT(_q_updateCurrent())); } +/*! + \qmlattachedproperty int QtQuickExtras2::SwipeView::index + + This attached property holds the index of each child item in the SwipeView. + + It is attached to each child item of the SwipeView. +*/ + +/*! + \qmlattachedproperty bool QtQuickExtras2::SwipeView::isCurrentItem + + This attached property is \c true if this child is the current item. + + It is attached to each child item of the SwipeView. +*/ + +/*! + \qmlattachedproperty SwipeView QtQuickExtras2::SwipeView::view + + This attached property holds the view that manages this child item. + + It is attached to each child item of the SwipeView. +*/ + +class QQuickSwipeViewAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickSwipeViewAttached) +public: + QQuickSwipeViewAttachedPrivate(QQuickItem *item) : + item(item), + swipeView(Q_NULLPTR), + index(-1), + isCurrent(false) + { + } + + ~QQuickSwipeViewAttachedPrivate() { + } + + void updateView(QQuickItem *parent); + + void itemChildAdded(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE; + void itemChildRemoved(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE; + void itemParentChanged(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE; + + void updateIndex(); + void updateIsCurrent(); + + void setView(QQuickSwipeView *view); + void setIndex(int i); + void setIsCurrent(bool current); + + QQuickItem *item; + QQuickSwipeView *swipeView; + int index; + // Better to store this so that we don't need to lump its calculation + // together with index's calculation, as it would otherwise need to know + // the old index to know if it should emit the change signal. + bool isCurrent; +}; + +void QQuickSwipeViewAttachedPrivate::updateIndex() +{ + setIndex(swipeView ? QQuickSwipeViewPrivate::get(swipeView)->contentModel->indexOf(item, Q_NULLPTR) : -1); +} + +void QQuickSwipeViewAttachedPrivate::updateIsCurrent() +{ + setIsCurrent(swipeView ? swipeView->currentIndex() == index : false); +} + +void QQuickSwipeViewAttachedPrivate::setView(QQuickSwipeView *view) +{ + if (view == swipeView) + return; + + if (swipeView) { + QQuickItemPrivate *p = QQuickItemPrivate::get(swipeView); + p->removeItemChangeListener(this, QQuickItemPrivate::Children); + + disconnect(swipeView, &QQuickSwipeView::currentIndexChanged, + this, &QQuickSwipeViewAttachedPrivate::updateIsCurrent); + disconnect(swipeView, &QQuickSwipeView::contentChildrenChanged, + this, &QQuickSwipeViewAttachedPrivate::updateIndex); + } + + swipeView = view; + + if (swipeView) { + QQuickItemPrivate *p = QQuickItemPrivate::get(swipeView); + p->addItemChangeListener(this, QQuickItemPrivate::Children); + + connect(swipeView, &QQuickSwipeView::currentIndexChanged, + this, &QQuickSwipeViewAttachedPrivate::updateIsCurrent); + connect(swipeView, &QQuickSwipeView::contentChildrenChanged, + this, &QQuickSwipeViewAttachedPrivate::updateIndex); + } + + Q_Q(QQuickSwipeViewAttached); + emit q->viewChanged(); + + updateIndex(); + updateIsCurrent(); +} + +void QQuickSwipeViewAttachedPrivate::setIsCurrent(bool current) +{ + if (current != isCurrent) { + isCurrent = current; + Q_Q(QQuickSwipeViewAttached); + emit q->isCurrentItemChanged(); + } +} + +void QQuickSwipeViewAttachedPrivate::setIndex(int i) +{ + if (i != index) { + index = i; + Q_Q(QQuickSwipeViewAttached); + emit q->indexChanged(); + } +} + +void QQuickSwipeViewAttachedPrivate::updateView(QQuickItem *parent) +{ + // parent can be, e.g.: + // - The contentItem of a ListView (typically the case) + // - A non-visual or weird type like TestCase, when child items are created from components + // wherein the attached properties are used + // - null, when the item was removed with removeItem() + QQuickSwipeView *view = Q_NULLPTR; + if (parent) { + view = qobject_cast<QQuickSwipeView*>(parent); + if (!view) { + if (parent->parentItem() && parent->parentItem()->property("contentItem").isValid()) { + // The parent is the contentItem of some kind of view. + view = qobject_cast<QQuickSwipeView*>(parent->parentItem()->parentItem()); + } + } + } + + setView(view); +} + +void QQuickSwipeViewAttachedPrivate::itemChildAdded(QQuickItem *, QQuickItem *) +{ + updateIndex(); +} + +void QQuickSwipeViewAttachedPrivate::itemChildRemoved(QQuickItem *, QQuickItem *) +{ + updateIndex(); +} + +void QQuickSwipeViewAttachedPrivate::itemParentChanged(QQuickItem *, QQuickItem *parent) +{ + updateView(parent); +} + +QQuickSwipeViewAttached::QQuickSwipeViewAttached(QQuickItem *item) : + QObject(*(new QQuickSwipeViewAttachedPrivate(item)), item) +{ + Q_D(QQuickSwipeViewAttached); + if (item->parentItem()) { + d->updateView(item->parentItem()); + } else { + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + p->addItemChangeListener(d, QQuickItemPrivate::Parent); + } +} + +QQuickSwipeViewAttached::~QQuickSwipeViewAttached() +{ +} + +QQuickSwipeView *QQuickSwipeViewAttached::view() const +{ + Q_D(const QQuickSwipeViewAttached); + return d->swipeView; +} + +int QQuickSwipeViewAttached::index() const +{ + Q_D(const QQuickSwipeViewAttached); + return d->index; +} + +bool QQuickSwipeViewAttached::isCurrentItem() const +{ + Q_D(const QQuickSwipeViewAttached); + return d->swipeView ? d->swipeView->currentIndex() == d->index : false; +} + QT_END_NAMESPACE #include "moc_qquickswipeview_p.cpp" diff --git a/src/imports/extras/qquickswipeview_p.h b/src/imports/extras/qquickswipeview_p.h index 718eccea..68f08783 100644 --- a/src/imports/extras/qquickswipeview_p.h +++ b/src/imports/extras/qquickswipeview_p.h @@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE +class QQuickSwipeViewAttached; class QQuickSwipeViewPrivate; class QQuickSwipeView : public QQuickContainer @@ -66,6 +67,8 @@ public: int currentIndex() const; QQuickItem *currentItem() const; + static QQuickSwipeViewAttached *qmlAttachedProperties(QObject *object); + public Q_SLOTS: void setCurrentIndex(int index); @@ -84,8 +87,37 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_updateCurrent()) }; +class QQuickSwipeViewAttachedPrivate; + +class QQuickSwipeViewAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL) + Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY isCurrentItemChanged FINAL) + Q_PROPERTY(QQuickSwipeView *view READ view NOTIFY viewChanged FINAL) + +public: + explicit QQuickSwipeViewAttached(QQuickItem *delegateItem); + ~QQuickSwipeViewAttached(); + + int index() const; + bool isCurrentItem() const; + QQuickSwipeView *view() const; + +Q_SIGNALS: + void indexChanged(); + void isCurrentItemChanged(); + void viewChanged(); + +private: + Q_DISABLE_COPY(QQuickSwipeViewAttached) + Q_DECLARE_PRIVATE(QQuickSwipeViewAttached) +}; + Q_DECLARE_TYPEINFO(QQuickSwipeView, Q_COMPLEX_TYPE); QT_END_NAMESPACE +QML_DECLARE_TYPEINFO(QQuickSwipeView, QML_HAS_ATTACHED_PROPERTIES) + #endif // QQUICKSWIPEVIEW_P_H diff --git a/src/imports/extras/qtquickextras2plugin.cpp b/src/imports/extras/qtquickextras2plugin.cpp index f1307558..e0208e7a 100644 --- a/src/imports/extras/qtquickextras2plugin.cpp +++ b/src/imports/extras/qtquickextras2plugin.cpp @@ -58,6 +58,7 @@ void QtQuickExtras2Plugin::registerTypes(const char *uri) qmlRegisterType<QQuickDial>(uri, 2, 0, "AbstractDial"); qmlRegisterType<QQuickDrawer>(uri, 2, 0, "AbstractDrawer"); qmlRegisterType<QQuickSwipeView>(uri, 2, 0, "AbstractSwipeView"); + qmlRegisterType<QQuickSwipeViewAttached>(); qmlRegisterType<QQuickTumbler>(uri, 2, 0, "AbstractTumbler"); qmlRegisterType<QQuickTumblerAttached>(); diff --git a/tests/auto/extras/data/tst_swipeview.qml b/tests/auto/extras/data/tst_swipeview.qml index f2694bcf..81c61f45 100644 --- a/tests/auto/extras/data/tst_swipeview.qml +++ b/tests/auto/extras/data/tst_swipeview.qml @@ -400,6 +400,16 @@ TestCase { ] } + Component { + id: pageAttached + + Text { + property int index: AbstractSwipeView.index + property SwipeView view: AbstractSwipeView.view + property bool isCurrentItem: AbstractSwipeView.isCurrentItem + } + } + function test_move(data) { var control = swipeView.createObject(testCase) @@ -407,14 +417,23 @@ TestCase { var titles = ["1", "2", "3"] var i = 0; - for (i = 0; i < titles.length; ++i) - control.addItem(page.createObject(control, {text: titles[i]})) + for (i = 0; i < titles.length; ++i) { + var item = pageAttached.createObject(control, {text: titles[i]}) + control.addItem(item) + } compare(control.count, titles.length) - for (i = 0; i < control.count; ++i) + for (i = 0; i < control.count; ++i) { compare(control.itemAt(i).text, titles[i]) + compare(control.itemAt(i).AbstractSwipeView.index, i) + compare(control.itemAt(i).AbstractSwipeView.isCurrentItem, i === 0) + } control.currentIndex = data.currentBefore + for (i = 0; i < control.count; ++i) { + compare(control.itemAt(i).AbstractSwipeView.isCurrentItem, i === data.currentBefore) + } + control.moveItem(data.from, data.to) compare(control.count, titles.length) @@ -425,8 +444,11 @@ TestCase { titles.splice(data.to, 0, title) compare(control.count, titles.length) - for (i = 0; i < control.count; ++i) + for (i = 0; i < control.count; ++i) { compare(control.itemAt(i).text, titles[i]) + compare(control.itemAt(i).AbstractSwipeView.index, i); + compare(control.itemAt(i).AbstractSwipeView.isCurrentItem, i === data.currentAfter) + } control.destroy() } @@ -462,4 +484,35 @@ TestCase { control.destroy() } + + function test_attachedParent() { + var control = swipeView.createObject(testCase); + + var page = pageAttached.createObject(testCase); + compare(page.view, null); + compare(page.index, -1); + compare(page.isCurrentItem, false); + page.destroy(); + + page = pageAttached.createObject(null); + compare(page.view, null); + compare(page.index, -1); + compare(page.isCurrentItem, false); + + control.insertItem(0, page); + compare(control.count, 1); + compare(page.parent, control.contentItem.contentItem); + compare(page.view, control); + compare(page.index, 0); + compare(page.isCurrentItem, true); + + control.removeItem(0); + compare(control.count, 0); + compare(page.parent, null); + compare(page.view, null); + compare(page.index, -1); + compare(page.isCurrentItem, false); + + control.destroy(); + } } |