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