aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates2
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2016-06-23 14:02:01 +0200
committerJ-P Nurmi <jpnurmi@qt.io>2016-06-28 18:18:20 +0000
commitdcdca64258fe10ffd8dd0617c2799610325b310d (patch)
treef774913901ed2b194f287f15e5c5c3a3d5ad7ef6 /src/quicktemplates2
parentfa8cccf479610757aa7957b2062a6616e2ebc173 (diff)
Tumbler: test and document negative currentIndex
Change-Id: If56bad7c3dd6dea2898058d6fc5b0d88bcd202fe Reviewed-by: J-P Nurmi <jpnurmi@qt.io>
Diffstat (limited to 'src/quicktemplates2')
-rw-r--r--src/quicktemplates2/qquicktumbler.cpp78
-rw-r--r--src/quicktemplates2/qquicktumbler_p.h1
2 files changed, 66 insertions, 13 deletions
diff --git a/src/quicktemplates2/qquicktumbler.cpp b/src/quicktemplates2/qquicktumbler.cpp
index 25d456d9..1d3c3240 100644
--- a/src/quicktemplates2/qquicktumbler.cpp
+++ b/src/quicktemplates2/qquicktumbler.cpp
@@ -57,6 +57,22 @@ QT_BEGIN_NAMESPACE
}
\endcode
+ Tumbler allows the user to select an option from a spinnable \e "wheel" of
+ items. It is useful for when there are too many options to use, for
+ example, a RadioButton, and too few options to require the use of an
+ editable SpinBox. It is convenient in that it requires no keyboard usage
+ and can be made to wrap around at each end when there are a large number of
+ items.
+
+ The API is similar to that of views like \l ListView and \l PathView; a
+ \l model and \l delegate can be set, and the \l count and \l currentItem
+ properties provide read-only access to information about the view.
+
+ Unlike views like \l PathView and \l ListView, however, there is always a
+ current item (when the model isn't empty). This means that when \l count is
+ equal to \c 0, \l currentIndex will be \c -1. In all other cases, it will
+ be greater than or equal to \c 0.
+
By default, Tumbler wraps when it reaches the top and bottom. To achieve a
non-wrapping Tumbler, set the \l wrap property to \c false:
@@ -116,9 +132,11 @@ public:
void _q_updateItemHeights();
void _q_updateItemWidths();
void _q_onViewCurrentIndexChanged();
+ void _q_onViewCountChanged();
void disconnectFromView();
void setupViewData(QQuickItem *newControlContentItem);
+ void syncCurrentIndex();
void itemChildAdded(QQuickItem *, QQuickItem *) override;
void itemChildRemoved(QQuickItem *, QQuickItem *) override;
@@ -209,6 +227,19 @@ void QQuickTumblerPrivate::_q_onViewCurrentIndexChanged()
}
}
+void QQuickTumblerPrivate::_q_onViewCountChanged()
+{
+ Q_Q(QQuickTumbler);
+ // If new items were added and our currentIndex was -1, we must
+ // enforce our rule of a non-negative currentIndex when count > 0.
+ if (q->count() > 0 && currentIndex == -1)
+ q->setCurrentIndex(0);
+ else
+ syncCurrentIndex();
+
+ emit q->countChanged();
+}
+
void QQuickTumblerPrivate::itemChildAdded(QQuickItem *, QQuickItem *)
{
_q_updateItemWidths();
@@ -258,6 +289,11 @@ void QQuickTumbler::setModel(const QVariant &model)
d->model = model;
emit modelChanged();
+
+ // Don't try to correct the currentIndex if count() isn't known yet.
+ // We can check in setupViewData() instead.
+ if (isComponentComplete() && d->view && count() == 0)
+ setCurrentIndex(-1);
}
/*!
@@ -276,6 +312,9 @@ int QQuickTumbler::count() const
\qmlproperty int QtQuick.Controls::Tumbler::currentIndex
This property holds the index of the current item.
+
+ The value of this property is \c -1 when \l count is equal to \c 0. In all
+ other cases, it will be greater than or equal to \c 0.
*/
int QQuickTumbler::currentIndex() const
{
@@ -286,7 +325,11 @@ int QQuickTumbler::currentIndex() const
void QQuickTumbler::setCurrentIndex(int currentIndex)
{
Q_D(QQuickTumbler);
- if (currentIndex == d->currentIndex)
+ // -1 doesn't make sense for a non-empty Tumbler, because unlike
+ // e.g. ListView, there's always one item selected.
+ // Wait until the component has finished before enforcing this rule, though,
+ // because the count might not be known yet.
+ if (currentIndex == d->currentIndex || (isComponentComplete() && currentIndex == -1 && count() > 0))
return;
d->currentIndex = currentIndex;
@@ -484,7 +527,7 @@ void QQuickTumblerPrivate::disconnectFromView()
Q_ASSERT(view);
QObject::disconnect(view, SIGNAL(currentIndexChanged()), q, SLOT(_q_onViewCurrentIndexChanged()));
QObject::disconnect(view, SIGNAL(currentItemChanged()), q, SIGNAL(currentItemChanged()));
- QObject::disconnect(view, SIGNAL(countChanged()), q, SIGNAL(countChanged()));
+ QObject::disconnect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged()));
QQuickItemPrivate *oldViewContentItemPrivate = QQuickItemPrivate::get(viewContentItem);
oldViewContentItemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Children);
@@ -508,22 +551,31 @@ void QQuickTumblerPrivate::setupViewData(QQuickItem *newControlContentItem)
Q_Q(QQuickTumbler);
QObject::connect(view, SIGNAL(currentIndexChanged()), q, SLOT(_q_onViewCurrentIndexChanged()));
QObject::connect(view, SIGNAL(currentItemChanged()), q, SIGNAL(currentItemChanged()));
- QObject::connect(view, SIGNAL(countChanged()), q, SIGNAL(countChanged()));
+ QObject::connect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged()));
QQuickItemPrivate *viewContentItemPrivate = QQuickItemPrivate::get(viewContentItem);
viewContentItemPrivate->addItemChangeListener(this, QQuickItemPrivate::Children);
+ // Sync the view's currentIndex with ours.
+ syncCurrentIndex();
+}
+
+void QQuickTumblerPrivate::syncCurrentIndex()
+{
const int actualViewIndex = view->property("currentIndex").toInt();
- if (actualViewIndex != currentIndex) {
- ignoreCurrentIndexChanges = true;
- view->setProperty("currentIndex", currentIndex);
- ignoreCurrentIndexChanges = false;
-
- // If we still couldn't set the currentIndex, it's probably out of bounds,
- // in which case we must respect the actual currentIndex.
- if (view->property("currentIndex").toInt() != currentIndex)
- q->setCurrentIndex(actualViewIndex);
- }
+ Q_Q(QQuickTumbler);
+
+ // Nothing to do.
+ if (actualViewIndex == currentIndex)
+ return;
+
+ // PathView likes to use 0 as currentIndex for empty models, but we use -1 for that.
+ if (q->count() == 0 && actualViewIndex == 0)
+ return;
+
+ ignoreCurrentIndexChanges = true;
+ view->setProperty("currentIndex", currentIndex);
+ ignoreCurrentIndexChanges = false;
}
void QQuickTumbler::keyPressEvent(QKeyEvent *event)
diff --git a/src/quicktemplates2/qquicktumbler_p.h b/src/quicktemplates2/qquicktumbler_p.h
index d129fe33..698df84c 100644
--- a/src/quicktemplates2/qquicktumbler_p.h
+++ b/src/quicktemplates2/qquicktumbler_p.h
@@ -114,6 +114,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_updateItemWidths())
Q_PRIVATE_SLOT(d_func(), void _q_updateItemHeights())
Q_PRIVATE_SLOT(d_func(), void _q_onViewCurrentIndexChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_onViewCountChanged())
};
class QQuickTumblerAttachedPrivate;