--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/radioapp/radiowidgets/src/radiostripbase.cpp Fri Jun 04 10:21:36 2010 +0100
@@ -0,0 +1,510 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+// System includes
+#include <QGraphicsSceneEvent>
+
+// User includes
+#include "radiostripbase.h"
+#include "radiologger.h"
+
+// Constants
+
+/*!
+ *
+ */
+RadioStripBase::RadioStripBase( QGraphicsItem* parent ) :
+ HbScrollArea( parent ),
+ mAutoScrollTime( 0 ),
+ mStripContainer( new HbWidget( this ) ),
+ mModel( 0 ),
+ mIsCyclic( true ),
+ mAutoCenter( false ),
+ mSpacing( 0 ),
+ mItemPoolParent( new QGraphicsWidget( NULL ) ),
+ mCurrentIndex( 0 ),
+ mPressedIndex( 0 ),
+ mStripLength( 0 ),
+ mContentsLength( 0 )
+{
+ setClampingStyle( HbScrollArea::NoClamping );
+ setScrollDirections( Qt::Horizontal );
+ setFlag( QGraphicsItem::ItemClipsChildrenToShape, true );
+ setContentWidget( mStripContainer );
+ setFrictionEnabled( true );
+ setLongPressEnabled( false );
+ setHorizontalScrollBarPolicy( HbScrollArea::ScrollBarAlwaysOff );
+ setVerticalScrollBarPolicy( HbScrollArea::ScrollBarAlwaysOff );
+
+ // mItemParent is used to hold the unused QGraphicsItem's in the pool. It's visibility is set to false
+ // so the visibility of the items doesn't need to be modified.
+ mItemPoolParent->setVisible( false );
+
+ connectAndTest( this, SIGNAL(scrollPositionChanged(QPointF)),
+ this, SLOT(scrollPositionChanged(QPointF)));
+}
+
+/*!
+ *
+ */
+RadioStripBase::~RadioStripBase()
+{
+}
+
+/*!
+ *
+ */
+void RadioStripBase::setAutoScrollTime( const int time )
+{
+ mAutoScrollTime = time;
+}
+
+/*!
+ *
+ */
+int RadioStripBase::autoScrollTime() const
+{
+ return mAutoScrollTime;
+}
+
+/*!
+ *
+ */
+void RadioStripBase::setModel( QAbstractItemModel* model )
+{
+ if ( mModel != model )
+ {
+ // if ( mModel )
+ // {
+ // disconnectDataModel();
+ // }
+
+ mModel = model;
+
+ if ( mModel )
+ {
+ // connectDataModel();
+
+ mCurrentIndex = 0;
+ populateAndLayout();
+ }
+ }
+}
+
+/*!
+ *
+ */
+QAbstractItemModel* RadioStripBase::model() const
+{
+ return mModel;
+}
+
+/*!
+ *
+ */
+void RadioStripBase::setCyclic( bool isCyclic )
+{
+ mIsCyclic = isCyclic;
+}
+
+/*!
+ *
+ */
+void RadioStripBase::setSpacing( qreal spacing )
+{
+ if ( mSpacing != spacing )
+ {
+ mSpacing = spacing;
+
+ prepareGeometryChange();
+
+ populateAndLayout();
+
+ update();
+ updateGeometry();
+ }
+}
+
+/*!
+ *
+ */
+void RadioStripBase::setAutoCenter( bool autoCenter )
+{
+ mAutoCenter = autoCenter;
+}
+
+/*!
+ *
+ */
+void RadioStripBase::setItemSize( const QSizeF& size )
+{
+ if ( mItemSize != size ) {
+ mItemSize = size;
+
+ prepareGeometryChange();
+
+ populateAndLayout();
+
+ update();
+ updateGeometry();
+ }
+}
+
+/*!
+ *
+ */
+void RadioStripBase::setIndex( int index, bool animateToCenter )
+{
+ Q_UNUSED( animateToCenter )
+ // Sanity checks
+ if ( !mModel || ( !mIsCyclic && ( index < 0 || index >= mModel->rowCount() ) ) ) {
+ return;
+ }
+
+ const int oldIndex = mCurrentIndex;
+ if ( mIsCyclic )
+ {
+ int numRows = mModel->rowCount();
+ index = (index + numRows) % numRows;
+ }
+ Q_ASSERT( index >= 0 );
+
+ mCurrentIndex = index;
+
+ updateItemWithIndex( mCurrentIndex );
+ updateItemWithIndex( oldIndex );
+}
+
+/*!
+ * \reimp
+ */
+void RadioStripBase::resizeEvent( QGraphicsSceneResizeEvent* event )
+{
+ Q_UNUSED( event );
+ populateAndLayout();
+}
+
+/*!
+ * \reimp
+ */
+void RadioStripBase::mousePressEvent( QGraphicsSceneMouseEvent* event )
+{
+ if ( event->button() != Qt::LeftButton || !mModel || !mModel->rowCount() )
+ {
+ event->ignore();
+ return;
+ }
+
+ HbScrollArea::mousePressEvent( event );
+}
+
+/*!
+ * \reimp
+ */
+void RadioStripBase::mouseReleaseEvent( QGraphicsSceneMouseEvent* event )
+{
+ if ( event->button() != Qt::LeftButton )
+ {
+ event->ignore();
+ return;
+ }
+
+ HbScrollArea::mouseReleaseEvent( event );
+}
+
+/*!
+ * Private slot
+ */
+void RadioStripBase::scrollPositionChanged( QPointF newPosition )
+{
+ adjustItems();
+ scrollPosChanged( newPosition );
+}
+
+/*!
+ *
+ */
+void RadioStripBase::moveAllItemsToPool()
+{
+ // set parent of all items to pool
+ foreach( QGraphicsItem* item, mItemAtSlot )
+ {
+ item->setParentItem( mItemPoolParent );
+ }
+
+ // move all items to pool
+ mItemPool += mItemAtSlot;
+ mItemAtSlot.clear();
+ mIndexAtSlot.clear();
+}
+
+/*!
+ *
+ */
+void RadioStripBase::populateAndLayout()
+{
+ moveAllItemsToPool();
+
+ if ( !mModel || mModel->rowCount() == 0 )
+ {
+ return;
+ }
+
+ mStripLength = boundingRect().width();
+ qreal itemSize = mItemSize.width();
+ mContentsLength = mModel->rowCount() * (itemSize + mSpacing) + mSpacing;
+
+ if ( mIsCyclic )
+ {
+ // if treating the items cyclically, double the content area so it can
+ // be shifted back and forth as you scroll
+ mContentsLength = mModel->rowCount() * (itemSize + mSpacing);
+ mContentsLength *= 2.0;
+ }
+
+ qreal currPos = mSpacing;
+ for ( int i = 0; i < mModel->rowCount(); ++i ) {
+ if ( currPos > mStripLength )
+ {
+ break;
+ }
+
+ QGraphicsItem* item = constructItem( i, true );
+ if ( item )
+ {
+ item->setPos( QPointF( currPos, mSpacing ) );
+ currPos += itemSize + mSpacing;
+ }
+ }
+
+ QRectF contentsRect(0,0,0,0);
+ contentsRect.setBottom( itemSize + 2 * mSpacing );
+ contentsRect.setRight( mContentsLength );
+
+ mStripContainer->setGeometry( contentsRect );
+
+ if ( mCurrentIndex >= 0 )
+ {
+ setIndex( mCurrentIndex, false );
+ }
+}
+
+/*!
+ *
+ */
+QGraphicsItem* RadioStripBase::constructItem( int index, bool append )
+{
+ QGraphicsItem* item = getFromPool();
+
+ if ( mIsCyclic )
+ {
+ Q_ASSERT( index >= 0 && index < 2 * mModel->rowCount() );
+
+ updateItemPrimitive( item, index % mModel->rowCount() );
+ }
+ else
+ {
+ Q_ASSERT( index >= 0 && index < mModel->rowCount() );
+
+ updateItemPrimitive( item, index );
+ }
+
+ item->setParentItem( mStripContainer );
+
+ if ( append )
+ {
+ mItemAtSlot.append( item );
+ mIndexAtSlot.append( index );
+ }
+ else
+ {
+ mItemAtSlot.prepend( item );
+ mIndexAtSlot.prepend( index );
+ }
+
+ return item;
+}
+
+/*!
+ *
+ */
+QGraphicsItem* RadioStripBase::getFromPool()
+{
+ QGraphicsItem* item = 0;
+
+ if ( mItemPool.isEmpty() )
+ {
+ item = createItemPrimitive( this );
+ }
+ else
+ {
+ item = mItemPool.takeFirst();
+ }
+
+ return item;
+}
+
+/*!
+ *
+ */
+void RadioStripBase::returnToPool( QGraphicsItem* item )
+{
+ // Unparent the item so it doesn't get deleted
+ item->setParentItem( mItemPoolParent );
+ mItemPool.append( item );
+}
+
+/*!
+ * Returns starting coordinate of the item with the specified index
+ */
+qreal RadioStripBase::indexToOffset( int index )
+{
+ return index * ( mItemSize.width() + mSpacing ) + mSpacing;
+}
+
+/*!
+ * Returns item index for specified offset amount into the content
+ */
+int RadioStripBase::offsetToIndex( qreal offset )
+{
+ const int rows = mModel->rowCount();
+ int index = (int)( ( offset - mSpacing) / ( mItemSize.width() + mSpacing ) );
+
+ if ( mIsCyclic )
+ {
+ return qBound( 0, index, 2 * rows - 1 );
+ }
+
+ return qBound( 0, index, rows - 1 );
+}
+
+/*!
+ * updates items with specified index value
+ */
+void RadioStripBase::updateItemWithIndex( int index )
+{
+ if( index >= 0 )
+ {
+ QList<QGraphicsItem *>::const_iterator item = mItemAtSlot.constBegin();
+ QList<QGraphicsItem *>::const_iterator itemsEnd = mItemAtSlot.constEnd();
+ QList<int>::const_iterator itemIndex = mIndexAtSlot.constBegin();
+ const int rowCount = mModel->rowCount();
+
+ // Find all items with this index (can be 2 in special cycling case)
+ for( ; item != itemsEnd; ++item, ++itemIndex )
+ {
+ if( index == *itemIndex || index == *itemIndex - rowCount )
+ {
+ // update those items
+ updateItemPrimitive( *item, index );
+ }
+ }
+ }
+}
+
+/*!
+ * Updates items during scrolling: removing invisible items and adding items that became visible
+ */
+void RadioStripBase::adjustItems()
+{
+ qreal contentPos = mStripContainer->pos().x();
+
+ if ( mIsCyclic )
+ {
+ if ( -contentPos < 0 )
+ {
+ // trying to display off the left end of the strip, so
+ // shift the strip one length to the left
+ contentPos -= mContentsLength * 0.5;
+ mStripContainer->setPos( QPointF ( contentPos, mStripContainer->pos().y() ) );
+ } else if (-contentPos > mContentsLength * 0.5) {
+ // trying to display off the right end of the strip, so
+ // shift the strip one length to the right
+ contentPos += mContentsLength * 0.5;
+ mStripContainer->setPos( QPointF ( contentPos, mStripContainer->pos().y() ) );
+ }
+ }
+
+ // find the first and last indices of the visible items
+ int firstVisibleIndex = offsetToIndex( -contentPos );
+ int lastVisibleIndex = offsetToIndex( -contentPos + mStripLength );
+
+ // remove items at the start that are no longer visible
+ while ( !mIndexAtSlot.isEmpty() )
+ {
+ int firstSlotIndex = mIndexAtSlot.first();
+ if ( firstVisibleIndex <= firstSlotIndex )
+ {
+ break;
+ }
+
+ returnToPool( mItemAtSlot.first() );
+ mItemAtSlot.removeFirst();
+ mIndexAtSlot.removeFirst();
+ }
+
+ // remove items at the end that are no longer visible
+ while ( !mIndexAtSlot.isEmpty() )
+ {
+ int lastSlotIndex = mIndexAtSlot.last();
+ if ( lastVisibleIndex >= lastSlotIndex )
+ {
+ break;
+ }
+
+ returnToPool( mItemAtSlot.last() );
+ mItemAtSlot.removeLast();
+ mIndexAtSlot.removeLast();
+ }
+
+ if ( mItemAtSlot.isEmpty() )
+ {
+ // fill area with all needed items
+ for ( int i = firstVisibleIndex; i <= lastVisibleIndex; ++i )
+ {
+ QGraphicsItem* item = constructItem( i, true );
+ if ( item )
+ {
+ item->setPos( QPointF( indexToOffset( i ), mSpacing ) );
+ }
+ }
+ }
+ else
+ {
+ // add missing items at the front
+ int firstItemToCreate = mIndexAtSlot.first()-1;
+ for ( int i = firstItemToCreate; i >= firstVisibleIndex; --i )
+ {
+ QGraphicsItem* item = constructItem( i, false );
+ if ( item )
+ {
+ item->setPos( QPointF( indexToOffset( i ), mSpacing ) );
+ }
+ }
+
+ // add missing items at the end
+ firstItemToCreate = mIndexAtSlot.last()+1;
+ for ( int i = firstItemToCreate; i <= lastVisibleIndex; ++i )
+ {
+ QGraphicsItem* item = constructItem( i, true );
+ if ( item )
+ {
+ item->setPos( QPointF( indexToOffset( i ), mSpacing ) );
+ }
+ }
+ }
+}