diff -r 06ff229162e9 -r 11d3954df52a src/hbwidgets/itemviews/hbtumbleview.cpp --- 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 #include +#include +#include #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()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("<modelIndex()<<"--indexList.at(" + <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 -"<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.
+ + 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.
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." + Note: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 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(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"