radioapp/radiowidgets/src/radiostripbase.cpp
changeset 13 46974bebc798
child 14 63aabac4416d
equal deleted inserted replaced
0:f3d95d9c00ab 13:46974bebc798
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 // System includes
       
    19 #include <qgraphicssceneevent>
       
    20 
       
    21 // User includes
       
    22 #include "radiostripbase.h"
       
    23 #include "radiologger.h"
       
    24 
       
    25 // Constants
       
    26 
       
    27 /*!
       
    28  *
       
    29  */
       
    30 RadioStripBase::RadioStripBase( QGraphicsItem* parent ) :
       
    31     HbScrollArea( parent ),
       
    32     mAutoScrollTime( 0 ),
       
    33     mStripContainer( new HbWidget( this ) ),
       
    34     mModel( 0 ),
       
    35     mIsCyclic( true ),
       
    36     mAutoCenter( false ),
       
    37     mSpacing( 0 ),
       
    38     mItemPoolParent( new QGraphicsWidget( NULL ) ),
       
    39     mCurrentIndex( 0 ),
       
    40     mPressedIndex( 0 ),
       
    41     mStripLength( 0 ),
       
    42     mContentsLength( 0 ),
       
    43     mBackgroundImage( 0 )
       
    44 {
       
    45     setClampingStyle( HbScrollArea::NoClamping );
       
    46     setScrollDirections( Qt::Horizontal );
       
    47     setFlag( QGraphicsItem::ItemClipsChildrenToShape, true );
       
    48     setContentWidget( mStripContainer );
       
    49     setFrictionEnabled( true );
       
    50     setLongPressEnabled( false );
       
    51     setHorizontalScrollBarPolicy( HbScrollArea::ScrollBarAlwaysOff );
       
    52     setVerticalScrollBarPolicy( HbScrollArea::ScrollBarAlwaysOff );
       
    53 
       
    54     // mItemParent is used to hold the unused QGraphicsItem's in the pool.  It's visibility is set to false
       
    55     // so the visibility of the items doesn't need to be modified.
       
    56     mItemPoolParent->setVisible( false );
       
    57 
       
    58     connectAndTest( this,                   SIGNAL(scrollPositionChanged(QPointF)),
       
    59                     this,                   SLOT(scrollPositionChanged(QPointF)));
       
    60 }
       
    61 
       
    62 /*!
       
    63  *
       
    64  */
       
    65 RadioStripBase::~RadioStripBase()
       
    66 {
       
    67 }
       
    68 
       
    69 /*!
       
    70  *
       
    71  */
       
    72 void RadioStripBase::setBackground( const HbIcon& background )
       
    73 {
       
    74     // Create background image for the entire widget
       
    75     mBackground = background;
       
    76     if ( !mBackgroundImage ) {
       
    77         mBackgroundImage = new QGraphicsPixmapItem( this );
       
    78     }
       
    79     mBackgroundImage->setPixmap( mBackground.pixmap() );
       
    80     mBackgroundImage->setOffset( QPointF( 0.0, 0.0 ) );
       
    81     mBackgroundImage->setZValue( -10.0 );
       
    82 }
       
    83 
       
    84 /*!
       
    85  *
       
    86  */
       
    87 HbIcon RadioStripBase::background() const
       
    88 {
       
    89     return mBackground;
       
    90 }
       
    91 
       
    92 /*!
       
    93  *
       
    94  */
       
    95 void RadioStripBase::setAutoScrollTime( const int time )
       
    96 {
       
    97     mAutoScrollTime = time;
       
    98 }
       
    99 
       
   100 /*!
       
   101  *
       
   102  */
       
   103 int RadioStripBase::autoScrollTime() const
       
   104 {
       
   105     return mAutoScrollTime;
       
   106 }
       
   107 
       
   108 /*!
       
   109  *
       
   110  */
       
   111 void RadioStripBase::setModel( QAbstractItemModel* model )
       
   112 {
       
   113     if ( mModel != model )
       
   114     {
       
   115     //    if ( mModel )
       
   116     //    {
       
   117     //        disconnectDataModel();
       
   118     //    }
       
   119 
       
   120         mModel = model;
       
   121 
       
   122         if ( mModel )
       
   123         {
       
   124     //        connectDataModel();
       
   125 
       
   126             mCurrentIndex = 0;
       
   127             populateAndLayout();
       
   128         }
       
   129     }
       
   130 }
       
   131 
       
   132 /*!
       
   133  *
       
   134  */
       
   135 QAbstractItemModel* RadioStripBase::model() const
       
   136 {
       
   137     return mModel;
       
   138 }
       
   139 
       
   140 /*!
       
   141  *
       
   142  */
       
   143 void RadioStripBase::setCyclic( bool isCyclic )
       
   144 {
       
   145     mIsCyclic = isCyclic;
       
   146 }
       
   147 
       
   148 /*!
       
   149  *
       
   150  */
       
   151 void RadioStripBase::setSpacing( qreal spacing )
       
   152 {
       
   153     if ( mSpacing != spacing )
       
   154     {
       
   155         mSpacing = spacing;
       
   156 
       
   157         prepareGeometryChange();
       
   158 
       
   159         populateAndLayout();
       
   160 
       
   161         update();
       
   162         updateGeometry();
       
   163     }
       
   164 }
       
   165 
       
   166 /*!
       
   167  *
       
   168  */
       
   169 void RadioStripBase::setAutoCenter( bool autoCenter )
       
   170 {
       
   171     mAutoCenter = autoCenter;
       
   172 }
       
   173 
       
   174 /*!
       
   175  *
       
   176  */
       
   177 void RadioStripBase::setItemSize( const QSizeF& size )
       
   178 {
       
   179     if ( mItemSize != size ) {
       
   180         mItemSize = size;
       
   181 
       
   182         prepareGeometryChange();
       
   183 
       
   184         populateAndLayout();
       
   185 
       
   186         update();
       
   187         updateGeometry();
       
   188     }
       
   189 }
       
   190 
       
   191 /*!
       
   192  *
       
   193  */
       
   194 void RadioStripBase::setIndex( int index, bool animateToCenter )
       
   195 {
       
   196     Q_UNUSED( animateToCenter )
       
   197     // Sanity checks
       
   198     if ( !mModel || ( !mIsCyclic && ( index < 0 || index >= mModel->rowCount() ) ) ) {
       
   199         return;
       
   200     }
       
   201 
       
   202     const int oldIndex = mCurrentIndex;
       
   203     if ( mIsCyclic )
       
   204     {
       
   205         int numRows = mModel->rowCount();
       
   206         index = (index + numRows) % numRows;
       
   207     }
       
   208     Q_ASSERT( index >= 0 );
       
   209 
       
   210     mCurrentIndex = index;
       
   211 
       
   212     updateItemWithIndex( mCurrentIndex );
       
   213     updateItemWithIndex( oldIndex );
       
   214 }
       
   215 
       
   216 /*!
       
   217  * \reimp
       
   218  */
       
   219 void RadioStripBase::resizeEvent( QGraphicsSceneResizeEvent* event )
       
   220 {
       
   221     QPixmap background = mBackgroundImage->pixmap().scaledToWidth( event->newSize().width() );
       
   222     mBackgroundImage->setPixmap( background );
       
   223     populateAndLayout();
       
   224 }
       
   225 
       
   226 /*!
       
   227  * \reimp
       
   228  */
       
   229 void RadioStripBase::mousePressEvent( QGraphicsSceneMouseEvent* event )
       
   230 {
       
   231     if ( event->button() != Qt::LeftButton || !mModel || !mModel->rowCount() )
       
   232     {
       
   233         event->ignore();
       
   234         return;
       
   235     }
       
   236 
       
   237     HbScrollArea::mousePressEvent( event );
       
   238 }
       
   239 
       
   240 /*!
       
   241  * \reimp
       
   242  */
       
   243 void RadioStripBase::mouseReleaseEvent( QGraphicsSceneMouseEvent* event )
       
   244 {
       
   245     if ( event->button() != Qt::LeftButton )
       
   246     {
       
   247         event->ignore();
       
   248         return;
       
   249     }
       
   250 
       
   251     HbScrollArea::mouseReleaseEvent( event );
       
   252 }
       
   253 
       
   254 /*!
       
   255  * Private slot
       
   256  */
       
   257 void RadioStripBase::scrollPositionChanged( QPointF newPosition )
       
   258 {
       
   259     adjustItems();
       
   260     scrollPosChanged( newPosition );
       
   261 }
       
   262 
       
   263 /*!
       
   264  *
       
   265  */
       
   266 void RadioStripBase::scrollPosChanged( QPointF newPosition )
       
   267 {
       
   268     Q_UNUSED( newPosition );
       
   269 }
       
   270 
       
   271 /*!
       
   272  *
       
   273  */
       
   274 void RadioStripBase::moveAllItemsToPool()
       
   275 {
       
   276     // set parent of all items to pool
       
   277     foreach( QGraphicsItem* item, mItemAtSlot )
       
   278     {
       
   279         item->setParentItem( mItemPoolParent );
       
   280     }
       
   281 
       
   282     // move all items to pool
       
   283     mItemPool += mItemAtSlot;
       
   284     mItemAtSlot.clear();
       
   285     mIndexAtSlot.clear();
       
   286 }
       
   287 
       
   288 /*!
       
   289  *
       
   290  */
       
   291 void RadioStripBase::populateAndLayout()
       
   292 {
       
   293     moveAllItemsToPool();
       
   294 
       
   295     if ( !mModel || mModel->rowCount() == 0 )
       
   296     {
       
   297         return;
       
   298     }
       
   299 
       
   300     mStripLength = boundingRect().width();
       
   301     qreal itemSize = mItemSize.width();
       
   302     mContentsLength = mModel->rowCount() * (itemSize + mSpacing) + mSpacing;
       
   303 
       
   304     if ( mIsCyclic )
       
   305     {
       
   306         // if treating the items cyclically, double the content area so it can
       
   307         // be shifted back and forth as you scroll
       
   308         mContentsLength = mModel->rowCount() * (itemSize + mSpacing);
       
   309         mContentsLength *= 2.0;
       
   310     }
       
   311 
       
   312     qreal currPos = mSpacing;
       
   313     for ( int i = 0; i < mModel->rowCount(); ++i ) {
       
   314         if ( currPos > mStripLength )
       
   315         {
       
   316             break;
       
   317         }
       
   318 
       
   319         QGraphicsItem* item = constructItem( i, true );
       
   320         if ( item )
       
   321         {
       
   322             item->setPos( QPointF( currPos, mSpacing ) );
       
   323             currPos += itemSize + mSpacing;
       
   324         }
       
   325     }
       
   326 
       
   327     QRectF contentsRect(0,0,0,0);
       
   328     contentsRect.setBottom( itemSize + 2 * mSpacing );
       
   329     contentsRect.setRight( mContentsLength );
       
   330 
       
   331     mStripContainer->setGeometry( contentsRect );
       
   332 
       
   333     if ( mCurrentIndex >= 0 )
       
   334     {
       
   335         setIndex( mCurrentIndex, false );
       
   336     }
       
   337 }
       
   338 
       
   339 /*!
       
   340  *
       
   341  */
       
   342 QGraphicsItem* RadioStripBase::constructItem( int index, bool append )
       
   343 {
       
   344     QGraphicsItem* item = getFromPool();
       
   345 
       
   346     if ( mIsCyclic )
       
   347     {
       
   348         Q_ASSERT( index >= 0 && index < 2 * mModel->rowCount() );
       
   349 
       
   350         updateItemPrimitive( item, index % mModel->rowCount() );
       
   351     }
       
   352     else
       
   353     {
       
   354         Q_ASSERT( index >= 0 && index < mModel->rowCount() );
       
   355 
       
   356         updateItemPrimitive( item, index );
       
   357     }
       
   358 
       
   359     item->setParentItem( mStripContainer );
       
   360 
       
   361     if ( append )
       
   362     {
       
   363         mItemAtSlot.append( item );
       
   364         mIndexAtSlot.append( index );
       
   365     }
       
   366     else
       
   367     {
       
   368         mItemAtSlot.prepend( item );
       
   369         mIndexAtSlot.prepend( index );
       
   370     }
       
   371 
       
   372     return item;
       
   373 }
       
   374 
       
   375 /*!
       
   376  *
       
   377  */
       
   378 QGraphicsItem* RadioStripBase::getFromPool()
       
   379 {
       
   380     QGraphicsItem* item = 0;
       
   381 
       
   382     if ( mItemPool.isEmpty() )
       
   383     {
       
   384         item = createItemPrimitive( this );
       
   385     }
       
   386     else
       
   387     {
       
   388         item = mItemPool.takeFirst();
       
   389     }
       
   390 
       
   391     return item;
       
   392 }
       
   393 
       
   394 /*!
       
   395  *
       
   396  */
       
   397 void RadioStripBase::returnToPool( QGraphicsItem* item )
       
   398 {
       
   399     // Unparent the item so it doesn't get deleted
       
   400     item->setParentItem( mItemPoolParent );
       
   401     mItemPool.append( item );
       
   402 }
       
   403 
       
   404 /*!
       
   405  * Returns starting coordinate of the item with the specified index
       
   406  */
       
   407 qreal RadioStripBase::indexToOffset( int index )
       
   408 {
       
   409     return index * ( mItemSize.width() + mSpacing ) + mSpacing;
       
   410 }
       
   411 
       
   412 /*!
       
   413  * Returns item index for specified offset amount into the content
       
   414  */
       
   415 int RadioStripBase::offsetToIndex( qreal offset )
       
   416 {
       
   417     const int rows = mModel->rowCount();
       
   418     int index = (int)( ( offset - mSpacing) / ( mItemSize.width() + mSpacing ) );
       
   419 
       
   420     if ( mIsCyclic )
       
   421     {
       
   422        return qBound( 0, index, 2 * rows - 1 );
       
   423     }
       
   424 
       
   425     return qBound( 0, index, rows - 1 );
       
   426 }
       
   427 
       
   428 /*!
       
   429  * updates items with specified index value
       
   430  */
       
   431 void RadioStripBase::updateItemWithIndex( int index )
       
   432 {
       
   433     if( index >= 0 )
       
   434     {
       
   435         QList<QGraphicsItem *>::const_iterator item = mItemAtSlot.constBegin();
       
   436         QList<QGraphicsItem *>::const_iterator itemsEnd = mItemAtSlot.constEnd();
       
   437         QList<int>::const_iterator itemIndex = mIndexAtSlot.constBegin();
       
   438         const int rowCount = mModel->rowCount();
       
   439 
       
   440         // Find all items with this index (can be 2 in special cycling case)
       
   441         for( ; item != itemsEnd; ++item, ++itemIndex )
       
   442         {
       
   443             if( index == *itemIndex || index == *itemIndex - rowCount )
       
   444             {
       
   445                 // update those items
       
   446                 updateItemPrimitive( *item, index );
       
   447             }
       
   448         }
       
   449     }
       
   450 }
       
   451 
       
   452 /*!
       
   453  * Updates items during scrolling: removing invisible items and adding items that became visible
       
   454  */
       
   455 void RadioStripBase::adjustItems()
       
   456 {
       
   457     qreal contentPos = mStripContainer->pos().x();
       
   458 
       
   459     if ( mIsCyclic )
       
   460     {
       
   461         if ( -contentPos < 0 )
       
   462         {
       
   463             // trying  to display off the left end of the strip, so
       
   464             // shift the strip one length to the left
       
   465             contentPos -= mContentsLength * 0.5;
       
   466             mStripContainer->setPos( QPointF ( contentPos, mStripContainer->pos().y() ) );
       
   467         } else if (-contentPos > mContentsLength * 0.5) {
       
   468             // trying to display off the right end of the strip, so
       
   469             // shift the strip one length to the right
       
   470             contentPos += mContentsLength * 0.5;
       
   471             mStripContainer->setPos( QPointF ( contentPos, mStripContainer->pos().y() ) );
       
   472         }
       
   473     }
       
   474 
       
   475     // find the first and last indices of the visible items
       
   476     int firstVisibleIndex = offsetToIndex( -contentPos );
       
   477     int lastVisibleIndex = offsetToIndex( -contentPos + mStripLength );
       
   478 
       
   479     // remove items at the start that are no longer visible
       
   480     while ( !mIndexAtSlot.isEmpty() )
       
   481     {
       
   482         int firstSlotIndex = mIndexAtSlot.first();
       
   483         if ( firstVisibleIndex <= firstSlotIndex )
       
   484         {
       
   485             break;
       
   486         }
       
   487 
       
   488         returnToPool( mItemAtSlot.first() );
       
   489         mItemAtSlot.removeFirst();
       
   490         mIndexAtSlot.removeFirst();
       
   491     }
       
   492 
       
   493     // remove items at the end that are no longer visible
       
   494     while ( !mIndexAtSlot.isEmpty() )
       
   495     {
       
   496         int lastSlotIndex = mIndexAtSlot.last();
       
   497         if ( lastVisibleIndex >= lastSlotIndex )
       
   498         {
       
   499             break;
       
   500         }
       
   501 
       
   502         returnToPool( mItemAtSlot.last() );
       
   503         mItemAtSlot.removeLast();
       
   504         mIndexAtSlot.removeLast();
       
   505     }
       
   506 
       
   507     if ( mItemAtSlot.isEmpty() )
       
   508     {
       
   509         // fill area with all needed items
       
   510         for ( int i = firstVisibleIndex; i <= lastVisibleIndex; ++i )
       
   511         {
       
   512             QGraphicsItem* item = constructItem( i, true );
       
   513             if ( item )
       
   514             {
       
   515                 item->setPos( QPointF( indexToOffset( i ), mSpacing ) );
       
   516             }
       
   517         }
       
   518     }
       
   519     else
       
   520     {
       
   521         // add missing items at the front
       
   522         int firstItemToCreate = mIndexAtSlot.first()-1;
       
   523         for ( int i = firstItemToCreate; i >= firstVisibleIndex; --i )
       
   524         {
       
   525             QGraphicsItem* item = constructItem( i, false );
       
   526             if ( item )
       
   527             {
       
   528                 item->setPos( QPointF( indexToOffset( i ), mSpacing ) );
       
   529             }
       
   530         }
       
   531 
       
   532         // add missing items at the end
       
   533         firstItemToCreate = mIndexAtSlot.last()+1;
       
   534         for ( int i = firstItemToCreate; i <= lastVisibleIndex; ++i )
       
   535         {
       
   536             QGraphicsItem* item = constructItem( i, true );
       
   537             if ( item )
       
   538             {
       
   539                 item->setPos( QPointF( indexToOffset( i ), mSpacing ) );
       
   540             }
       
   541         }
       
   542     }
       
   543 }