--- a/src/hbwidgets/itemviews/hbtumbleview.cpp Fri May 14 16:09:54 2010 +0300
+++ b/src/hbwidgets/itemviews/hbtumbleview.cpp Thu May 27 13:10:59 2010 +0300
@@ -35,10 +35,11 @@
#include <QGraphicsSceneMouseEvent>
#include <QStringListModel>
+#include <QItemSelectionModel>
+#include <QTapGesture>
#define HB_TUMBLE_ITEM_ANIMATION_TIME 500
#define HB_TUMBLE_PREFERRED_ITEMS 3
-#define DELAYED_SELECT_INTERVAL 100
#define HBTUMBLE_DEBUG
#ifdef HBTUMBLE_DEBUG
@@ -56,6 +57,8 @@
void setLoopingEnabled(bool looping) ;
bool isLoopingEnabled() const ;
+ void removeItem(const QModelIndex &index, bool animate );
+ void setModelIndexes(const QModelIndex &startIndex);
};
class HbTumbleViewItemContainerPrivate:public HbListItemContainerPrivate
@@ -84,16 +87,14 @@
void init(QAbstractItemModel *model);
void calculateItemHeight();
+ void selectCurrentIndex(const QModelIndex& index);
void selectMiddleItem();
+ HbAbstractViewItem* getCenterItem();
void createPrimitives();
-
- void delayedSelectCurrent(const QModelIndex& index);
-
void _q_scrollingStarted();//private slot
void _q_scrollingEnded();//private slot
- void _q_delayedSelectCurrent();//private slot
void setPressedState(HbAbstractViewItem *item);
@@ -188,12 +189,143 @@
void HbTumbleViewItemContainer::setLoopingEnabled(bool looped) {
Q_D(HbTumbleViewItemContainer);
d->mIsLooped = looped;
+ if(looped){
+ recycleItems(QPointF());
+ }
+ else{
+ setModelIndexes(d->mItemView->currentIndex());
+ }
}
bool HbTumbleViewItemContainer::isLoopingEnabled() const {
Q_D(const HbTumbleViewItemContainer);
return d->mIsLooped;
}
+void HbTumbleViewItemContainer::removeItem(const QModelIndex &index, bool animate )
+{
+ Q_D(HbTumbleViewItemContainer);
+ HbListItemContainer::removeItem(index,animate);
+ if (d->mItems.count() < maxItemCount()) {
+ d->updateItemBuffer();
+ }
+}
+
+void HbTumbleViewItemContainer::setModelIndexes(const QModelIndex &startIndex)
+{
+ Q_D(HbAbstractItemContainer);
+
+ if (!d->mItemView || !d->mItemView->model()) {
+ return;
+ }
+
+ QModelIndex index = startIndex;
+ if (!index.isValid()) {
+ if (!d->mItems.isEmpty()) {
+ index = d->mItems.first()->modelIndex();
+ }
+
+ if (!index.isValid()) {
+ index = d->mItemView->modelIterator()->nextIndex(index);
+ }
+ }
+
+ QModelIndexList indexList;
+
+ int itemCount(d->mItems.count());
+
+ if (itemCount != 0 && index.isValid()) {
+ indexList.append(index);
+ }
+
+ for (int i = indexList.count(); i < itemCount; ++i) {
+ index = d->mItemView->modelIterator()->nextIndex(indexList.last());
+
+ if (index.isValid()) {
+ indexList.append(index);
+ } else {
+ break;
+ }
+ }
+ if(isLoopingEnabled() && indexList.count()<itemCount){
+ QModelIndex firstModelIndex = d->mItemView->modelIterator()->index(0,QModelIndex());
+ indexList.append(firstModelIndex);
+ for (int i = indexList.count(); i < itemCount; ++i) {
+ index = d->mItemView->modelIterator()->nextIndex(indexList.last());
+
+ if (index.isValid()) {
+ indexList.append(index);
+ } else {
+ break;
+ }
+ }
+ }
+
+ for (int i = indexList.count(); i < itemCount; ++i) {
+ index = d->mItemView->modelIterator()->previousIndex(indexList.first());
+
+ if (index.isValid()) {
+ indexList.prepend(index);
+ } else {
+ break;
+ }
+ }
+
+ // if items have been added/removed in the middle of the buffer, there might be items
+ // that can be reused at the end of the buffer. The following block will scan for
+ // those items and move them in correct position
+ int lastUsedItem = -1;
+ for (int indexCounter = 0; indexCounter < indexList.count(); ++indexCounter) {
+ HbAbstractViewItem *item = d->mItems.at(indexCounter);
+ if (item && item->modelIndex() == indexList.at(indexCounter)) {
+ lastUsedItem = indexCounter;
+ } else {
+ for (int itemCounter = lastUsedItem + 1; itemCounter < d->mItems.count(); itemCounter++) {
+ HbAbstractViewItem *item2 = d->mItems.at(itemCounter);
+ qDebug()<<"containeritemsat("<<itemCounter<<")="<<item2->modelIndex()<<"--indexList.at("
+ <<indexCounter<<")="<<indexList.at(indexCounter);
+
+ if (item2->modelIndex() == indexList.at(indexCounter)) {
+ d->mItems.swap(indexCounter, itemCounter);
+ itemRemoved(d->mItems.at(indexCounter), false);
+ itemRemoved(d->mItems.at(itemCounter), false);
+ itemAdded(qMin(indexCounter, itemCounter), d->mItems.at(qMin(indexCounter, itemCounter)), false);
+ itemAdded(qMax(indexCounter, itemCounter), d->mItems.at(qMax(indexCounter, itemCounter)), false);
+ lastUsedItem = itemCounter;
+ break;
+ }
+ }
+
+ }
+ qDebug()<<"last used item -"<<lastUsedItem;
+ qDebug()<<"-------------------------------------------------------";
+ }
+
+ int indexCount(indexList.count());
+ for (int i = 0; i < itemCount; ++i) {
+ HbAbstractViewItem *item = d->mItems.at(i);
+ HbAbstractViewItem *prototype = 0;
+ // setItemModelIndex() is considered recycling. It is called only, if recycling is permitted
+ if (i < indexCount) {
+ prototype = d->itemPrototype(indexList.at(i));
+ }
+ if (prototype) {
+ if ( prototype == item->prototype()
+ && d->mItemRecycling) {
+ setItemModelIndex(item, indexList.at(i));
+ } else if ( d->mItemRecycling
+ || ( !d->mItemRecycling
+ && item->modelIndex() != indexList.at(i))) {
+ d->deleteItem(item);
+ insertItem(i, indexList.at(i));
+ } // else: !d->mItemRecycling && item->modelIndex().isValid() == indexList.at(i))
+ } else {
+ d->deleteItem(item);
+ itemCount--;
+ i--;
+ }
+ }
+}
+
HbTumbleViewItemContainerPrivate::HbTumbleViewItemContainerPrivate()
: mIsLooped(false)
{
@@ -319,8 +451,6 @@
Q_ASSERT(b);
b = q->connect(q,SIGNAL(scrollingEnded()),q,SLOT(_q_scrollingEnded()));
Q_ASSERT(b);
- b = q->connect(&mDelayedSelectTimer,SIGNAL(timeout()),q,SLOT(_q_delayedSelectCurrent()));
- Q_UNUSED(b);
createPrimitives();
}
@@ -331,17 +461,27 @@
if(!q->scene()) {
return;
}
- QPointF centerPt = q->mapToScene(q->boundingRect().center());
- HbAbstractViewItem *item = itemAt(centerPt);
+ HbAbstractViewItem *item = getCenterItem();
if(item) {
#ifdef HBTUMBLE_DEBUG
- qDebug() << "HbTumbleViewPrivate::selectMiddleItem - " << item->modelIndex().row() ;
+ qDebug() << "HbTumbleViewPrivate::selectMiddleItem - " << item->modelIndex().row() ;
#endif
- delayedSelectCurrent(item->modelIndex());
- mSelected = item->modelIndex().row();
- }
+ selectCurrentIndex(item->modelIndex());
+ mSelected = item->modelIndex().row();
}
+}
+
+HbAbstractViewItem* HbTumbleViewPrivate::getCenterItem()
+{
+ Q_Q(HbTumbleView);
+
+ if(!q->scene()) {
+ return 0;
+ }
+ QPointF centerPt = q->mapToScene(q->boundingRect().center());
+ return itemAt(centerPt);
+}
void HbTumbleViewPrivate::scrollTo(const QModelIndex &index, HbAbstractItemView::ScrollHint hint)
{
@@ -366,6 +506,24 @@
#endif
}
+void HbTumbleViewPrivate::selectCurrentIndex(const QModelIndex& index)
+{
+ Q_Q(HbTumbleView);
+ if(!mIsAnimating && !mIsScrolling) {
+ if(index == q->currentIndex()){
+ HbAbstractViewItem *item =q->itemByIndex(index);
+ QPointF delta = pixelsToScroll(item,HbAbstractItemView::PositionAtCenter );
+ QPointF newPos = -mContainer->pos() + delta;
+ checkBoundaries(newPos);
+ scrollByAmount(newPos - (-mContents->pos()));
+ mIsScrolling = false;
+ }
+ else{
+ q->setCurrentIndex(index,QItemSelectionModel::SelectCurrent);
+ }
+ }
+}
+
void HbTumbleView::scrollTo(const QModelIndex &index, ScrollHint)
{
#ifdef HBTUMBLE_DEBUG
@@ -419,21 +577,25 @@
/*!
@proto
\class HbTumbleView
- \this is a tumbler widget which lets the user select alphanumeric values from a predefined list of
- values via vertical flicking and dragging. Typically widgets such as date picker and time picker use the
+ \brief HbTumbleView is a tumbler widget which lets the user select alphanumeric values from a predefined list of values via vertical flicking and dragging.<br>
+
+ Typically widgets such as date picker and time picker use the
Tumbler. The Tumbler could also be used to change other values such as number code sequence,
- landmark coordinates, country selection, and currency.
+ landmark coordinates, country selection, and currency.<br>
Only strings can be accepted as HbTumbleView's items.
- \this can be used like this:
+ HbTumbleView can be used, as shown in the below code snippet:
\snippet{ultimatecodesnippet/ultimatecodesnippet.cpp,52}
+
+ \image html hbdatetimepicker_date.png "Two TumbleViews(tumblers) in a datetime picker widget in d/MMMM format. One tumbler for day and the other for month."
+ <b>Note:</b>Graphics in the above image varies depending on theme.
*/
/*!
\fn void itemSelected(int index)
- This signal is emitted when an item is selected in date time picker.
+ This signal is emitted when an item is selected in the tumbler.
\param index selected item.
*/
@@ -457,7 +619,7 @@
/*!
HbTumbleView's constructor.
- \param list to be set as data to QStringListModel.
+ \param list String list to be set as data to HbTumbleView's model.
\parent item to set as parent.
*/
HbTumbleView::HbTumbleView(const QStringList &list,QGraphicsItem *parent)
@@ -497,7 +659,7 @@
/*!
Sets the HbTumbleView's items to the given string \a list.
- \param list Items to be set as tumble view's model.
+ \param list Items to be set as data to HbTumbleView's model.
*/
void HbTumbleView::setItems(const QStringList &list)
@@ -514,7 +676,7 @@
/*!
Returns items in QStringList format.
- \return list of items in tumbleview's model in QStringList format.
+ \return List of items set as data to HbTumbleView's model in QStringList format.
*/
QStringList HbTumbleView::items() const
{
@@ -528,7 +690,7 @@
/*!
Sets the selection to the item at \a index.
- \param index to be selected in the tumble view.
+ \param index of the item to be selected in the tumbler.
*/
void HbTumbleView::setSelected(int index)
@@ -541,7 +703,7 @@
QModelIndex modelIndex = d->mModelIterator->index(index, rootIndex());
if(modelIndex.isValid()) {
- d->delayedSelectCurrent(modelIndex);
+ d->selectCurrentIndex(modelIndex);
emitActivated(modelIndex);
}
}
@@ -549,7 +711,7 @@
/*!
Returns the index of the current selected item in integer format.
- \return current index selected in tumble view.
+ \return current index of the item selected in the tumbler.
*/
int HbTumbleView::selected() const
{
@@ -557,7 +719,6 @@
}
/*!
-
\deprecated HbTumbleView::primitive(HbStyle::Primitive)
is deprecated.
@@ -653,25 +814,17 @@
*/
void HbTumbleView::rowsInserted(const QModelIndex &parent,int start,int end)
{
+ Q_D(HbTumbleView);
HbListView::rowsInserted(parent,start,end);
- scrollTo(currentIndex(),PositionAtCenter);
-}
-void HbTumbleViewPrivate::_q_delayedSelectCurrent()
-{
- Q_Q(HbTumbleView);
- if(!mIsAnimating && !mIsScrolling) {
- if(mDelayedSelectIndex == q->currentIndex()){
- HbAbstractViewItem *item =q->itemByIndex(mDelayedSelectIndex);
- QPointF delta = pixelsToScroll(item,HbAbstractItemView::PositionAtCenter );
- QPointF newPos = -mContainer->pos() + delta;
- checkBoundaries(newPos);
- scrollByAmount(newPos - (-mContents->pos()));
- }
- else{
- q->setCurrentIndex(mDelayedSelectIndex);
- }
+ //Trigger recycle, in the scenario where item's are deleted and reinserted again.
+ QPointF alignedPosition = d->mContents->pos();
+ Q_UNUSED(alignedPosition);
+ if(alignedPosition.y() > 0.0){
+ alignedPosition.setY(0.0);
+ d->HbScrollAreaPrivate::setContentPosition(alignedPosition);
}
+ scrollTo(currentIndex(),PositionAtCenter);
}
/*!
@@ -727,9 +880,9 @@
}
/*!
- Sets the looping enabled flag to eith true or false, which makes the tumbleview to scroll in a circular way.
+ Sets the looping enabled flag to either true or false, which makes the tumbler to scroll in a circular way.
- \param looped flag to enable curcular view.
+ \param looped flag to enable curcular view for the tumbler.
\sa isLoopingEnabled
*/
@@ -745,7 +898,7 @@
/*!
Returns looping enabled flag.
- \return looping enabled flag.
+ \return looping enabled flag as boolean value.
\sa setLoopingEnabled
@@ -792,7 +945,7 @@
QSizeF sh=HbListView::sizeHint(which,constraint);
switch(which) {
case Qt::MinimumSize:
- sh = QSizeF(sh.width(),HB_TUMBLE_PREFERRED_ITEMS*d->mHeight);
+ sh = QSizeF(sh.width(),HB_TUMBLE_PREFERRED_ITEMS*d->mHeight);
break;
case Qt::PreferredSize:
sh = QSizeF(sh.width(),HB_TUMBLE_PREFERRED_ITEMS*d->mHeight);
@@ -833,13 +986,12 @@
return;
}
- QPointF pt = q->mapToScene(q->boundingRect().center());
- HbAbstractViewItem *centerItem=itemAt(pt);
+ HbAbstractViewItem *centerItem=getCenterItem();
if(centerItem) {
setPressedState(centerItem);
if(centerItem->modelIndex().isValid()) {
- delayedSelectCurrent(centerItem->modelIndex());
+ selectCurrentIndex(centerItem->modelIndex());
q->emitActivated(centerItem->modelIndex());
}
}
@@ -878,10 +1030,60 @@
HbListView::rowsRemoved(parent,start,end);
scrollTo(currentIndex(),PositionAtCenter);
}
-void HbTumbleViewPrivate::delayedSelectCurrent(const QModelIndex& index)
+
+/*!
+ \reimp
+*/
+void HbTumbleView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+ Q_D(const HbListView);
+
+ QList<HbAbstractViewItem *> items = d->mContainer->items();
+ bool empty = items.isEmpty();
+ QModelIndex rootIndex = d->mModelIterator->rootIndex();
+ QModelIndex firstIndex = items.first()->modelIndex();
+ QModelIndex lastIndex = items.last()->modelIndex();
+
+ if (!empty &&
+ topLeft.parent() == rootIndex
+ /*&& firstIndex.row() <= bottomRight.row()
+ && topLeft.row() <= lastIndex.row()*/) {
+ HbAbstractItemView::dataChanged(topLeft, bottomRight);
+ }
+}
+
+void HbTumbleView::gestureEvent(QGestureEvent *event)
{
- mDelayedSelectIndex = index;
- mDelayedSelectTimer.start(DELAYED_SELECT_INTERVAL);
+ Q_D(HbTumbleView);
+ if(QTapGesture *gesture = static_cast<QTapGesture*>(event->gesture(Qt::TapGesture))){
+ switch(gesture->state()){
+ case Qt::GestureStarted:
+ if(d->mIsAnimating || d->mIsScrolling){
+ d->mInternalScroll = true;
+ HbAbstractViewItem* centerItem = d->getCenterItem();
+ if(centerItem){
+ d->mDelayedSelectIndex = centerItem->modelIndex();
+ }
+ }
+ else{
+ d->mDelayedSelectIndex = QModelIndex();
+ }
+ break;
+ case Qt::GestureCanceled:
+ d->mInternalScroll = false;
+ break;
+ case Qt::GestureFinished:
+ d->mInternalScroll = false;
+ if(d->mDelayedSelectIndex.isValid()){
+ d->selectCurrentIndex(d->mDelayedSelectIndex);
+ }
+ break;
+ default:
+ break;
+
+ }
+ }
+ HbListView::gestureEvent(event);
}
#include "moc_hbtumbleview.cpp"