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