radioapp/radiowidgets/src/radiostationcarousel.cpp
branchGCC_SURGE
changeset 37 451b2e1545b2
parent 19 afea38384506
parent 33 11b6825f0862
--- a/radioapp/radiowidgets/src/radiostationcarousel.cpp	Fri Jun 11 16:24:13 2010 +0100
+++ b/radioapp/radiowidgets/src/radiostationcarousel.cpp	Thu Jul 22 16:33:45 2010 +0100
@@ -17,126 +17,77 @@
 
 // System includes
 #include <QGraphicsLinearLayout>
-#include <HbAnchorLayout>
-#include <QPixmap>
-#include <QGraphicsSceneMouseEvent>
-#include <HbEffect>
+#include <QGraphicsSceneResizeEvent>
 #include <QTimer>
-#include <QTimeLine>
 #include <HbPanGesture>
+#include <HbSwipeGesture>
+#include <HbFontSpec>
+#include <HbMenu>
+#include <QPainter>
 
 // User includes
 #include "radiostationcarousel.h"
+#include "radiocarouselanimator.h"
 #include "radiouiloader.h"
-#include "radiostationitem.h"
+#include "radiocarouselitem.h"
 #include "radiostation.h"
 #include "radiouiengine.h"
 #include "radiostationmodel.h"
 #include "radiofadinglabel.h"
 #include "radiologger.h"
-#include "radiocarouselmodel.h"
-#include "radiouiutilities.h"
+#include "radioutil.h"
 #include "radio_global.h"
 
-#ifdef USE_LAYOUT_FROM_E_DRIVE
-    const QString KFavoriteIconPath = "e:/radiotest/images/favoriteiconactive.png";
-    const QString KNonFavoriteIconPath = "e:/radiotest/images/favoriteiconinactive.png";
-#else
-    const QString KFavoriteIconPath = ":/images/favoriteiconactive.png";
-    const QString KNonFavoriteIconPath = ":/images/favoriteiconinactive.png";
-#endif
-
-const int KRadioTextPlusCheckTimeout = 700; // 700 ms
-const int KFreqScrollDivider = 100000;
-const int INFOTEXT_NOFAVORITES_TIMEOUT = 15000;
-
-// ===============================================================
-//  Scanning helper
-// ===============================================================
+// Constants
+const int RTPLUS_CHECK_TIMEOUT = 700;
+const int INFOTEXT_NOFAVORITES_TIMEOUT = 5000;
+const int SET_FREQUENCY_TIMEOUT = 500;
+const int FAVORITE_HINT_SHOW_DELAY = 1000;
+const int FAVORITE_HINT_HIDE_DELAY = 2000;
 
-/*!
- *
- */
-ScanningHelper::ScanningHelper( RadioStationCarousel& carousel ) :
-    mCarousel( carousel ),
-    mCurrentFrequency( 0 ),
-    mPreviousFrequency( 0 ),
-    mStationItem( 0 ),
-    mNumberScrollingTimeLine( new QTimeLine( 1000, this ) )
-{
-    mNumberScrollingTimeLine->setCurveShape( QTimeLine::EaseInCurve );
-    connectAndTest( mNumberScrollingTimeLine,  SIGNAL(finished()),
-                    &mCarousel,                SIGNAL(scanAnimationFinished()) );
-    connectAndTest( mNumberScrollingTimeLine,  SIGNAL(frameChanged(int)),
-                    this,                      SLOT(numberScrollUpdate(int)) );
-}
+// Matti testing constants
+const QLatin1String LEFT_ITEM_NAME      ( "carousel_left" );
+const QLatin1String CENTER_ITEM_NAME    ( "carousel_center" );
+const QLatin1String RIGHT_ITEM_NAME     ( "carousel_right" );
+
+#ifdef BUILD_WIN32
+#   define SCROLLBAR_POLICY ScrollBarAlwaysOn
+#else
+#   define SCROLLBAR_POLICY ScrollBarAlwaysOff
+#endif // BUILD_WIN32
+
+#define CALL_TO_ALL_ITEMS( expr ) \
+    mItems[LeftItem]->expr; \
+    mItems[CenterItem]->expr; \
+    mItems[RightItem]->expr;
 
 /*!
  *
  */
-void ScanningHelper::start()
-{
-    QTimer::singleShot( 0, this, SLOT(startSlide()) );
-}
-
-/*!
- * Private slot
- */
-void ScanningHelper::startSlide()
-{
-    mCarousel.scrollToIndex( mModelIndex, RadioStationCarousel::NoSignal );
-    startNumberScroll();
-}
-
-/*!
- * Private slot
- */
-void ScanningHelper::startNumberScroll()
-{
-    //TODO: Take italy case into account
-    if ( mPreviousFrequency ) {
-        mNumberScrollingTimeLine->setFrameRange( mPreviousFrequency / KFreqScrollDivider, mCurrentFrequency / KFreqScrollDivider );
-        mNumberScrollingTimeLine->start();
-    } else {
-        emit mCarousel.scanAnimationFinished();
-    }
-}
-
-/*!
- * Private slot
- */
-void ScanningHelper::numberScrollUpdate( int value )
-{
-    if ( mStationItem ) {
-        mStationItem->setFrequency( value * KFreqScrollDivider );
-    }
-}
-
-// ===============================================================
-//  Carousel
-// ===============================================================
-
-/*!
- *
- */
-RadioStationCarousel::RadioStationCarousel( RadioUiEngine* uiEngine ) :
-    HbGridView( 0 ),
-    mUiEngine( uiEngine ),
-    mAntennaAttached( false ),
+RadioStationCarousel::RadioStationCarousel( QGraphicsItem* parent ) :
+    HbScrollArea( parent ),
+    mUiEngine( NULL ),
     mAutoScrollTime( 300 ),
     mGenericTimer( new QTimer( this ) ),
     mTimerMode( NoTimer ),
-    mScanningHelper( 0 ),
-    mInfoText( 0 ),
-    mCurrentItem( 0 ),
-    mPanStartPos( 0 )
+    mInfoText( NULL ),
+    mRadiotextPopup( NULL ),
+    mContainer( new HbWidget( this ) ),
+    mMidScrollPos( 0 ),
+    mMaxScrollPos( 0 ),
+    mCurrentIndex( 0 ),
+    mTargetIndex( -1 ),
+    mIsCustomFreq( false ),
+    mInfoTextType( CarouselInfoText::None ),
+    mModel( NULL ),
+    mPosAdjustmentDisabled( false ),
+    mScrollDirection( Scroll::Shortest ),
+    mManualSeekMode( false ),
+    mAlternateSkipping( false )
 #ifdef USE_DEBUGGING_CONTROLS
     ,mRdsLabel( new RadioFadingLabel( this ) )
 #endif // USE_DEBUGGING_CONTROLS
 {
-    RadioUiUtilities::setCarousel( this );
-    setClampingStyle( HbScrollArea::StrictClamping );
-    setScrollingStyle( HbScrollArea::Pan );
 }
 
 /*!
@@ -197,49 +148,71 @@
 void RadioStationCarousel::init( RadioUiLoader& uiLoader, RadioUiEngine* uiEngine )
 {
     mUiEngine = uiEngine;
-    mAntennaAttached = mUiEngine->isAntennaAttached();
+    RadioUtil::setCarousel( this );
+
+    mItems[CenterItem] = new RadioCarouselItem( *this, this, true );
+    mItems[LeftItem] = new RadioCarouselItem( *this, this );
+    mItems[RightItem] = new RadioCarouselItem( *this, this );
+
+    // Matti testing needs the objects to have names
+    mItems[LeftItem]->setObjectName( LEFT_ITEM_NAME );
+    mItems[CenterItem]->setObjectName( CENTER_ITEM_NAME );
+    mItems[RightItem]->setObjectName( RIGHT_ITEM_NAME );
+
+    QGraphicsLinearLayout* layout = new QGraphicsLinearLayout( Qt::Horizontal );
+    layout->setContentsMargins( 0, 0, 0, 0 );
+    layout->setSpacing( 0 );
+    layout->addItem( mItems[LeftItem] );
+    layout->addItem( mItems[CenterItem] );
+    layout->addItem( mItems[RightItem] );
+    mContainer->setLayout( layout );
+    setContentWidget( mContainer );
+
+    setClampingStyle( HbScrollArea::NoClamping );
+    setScrollDirections( Qt::Horizontal );
+
+    setFrictionEnabled( true );
+    setHorizontalScrollBarPolicy( HbScrollArea::SCROLLBAR_POLICY );
+    setVerticalScrollBarPolicy( HbScrollArea::ScrollBarAlwaysOff );
 
     mInfoText = uiLoader.findWidget<HbLabel>( DOCML::MV_NAME_INFO_TEXT );
     mInfoText->setTextWrapping( Hb::TextWordWrap );
 
-    setRowCount( 1 );
-    setColumnCount( 1 );
+    mRadiotextPopup = uiLoader.findObject<HbMenu>( DOCML::MV_NAME_CAROUSEL_RT_MENU );
+
+#ifdef BUILD_WIN32
+    HbFontSpec spec = mInfoText->fontSpec();
+    spec.setRole( HbFontSpec::Secondary );
+    mInfoText->setFontSpec( spec );
+#endif
+
     setScrollDirections( Qt::Horizontal );
-    setFrictionEnabled( true );
-    setLongPressEnabled( false );
-    setItemRecycling( false );
-    setUniformItemSizes( true );
-    setItemPrototype( new RadioStationItem( *this ) );
-    setSelectionMode( NoSelection );
-
-//    grabGesture( Qt::PanGesture );
 
-    RadioCarouselModel* carouselModel = mUiEngine->carouselModel();
-    setCarouselModel( carouselModel );
-
-    mCurrentItem = static_cast<RadioStationItem*>( itemByIndex( carouselModel->index( 0, 0 ) ) );
+    Radio::connect( this,           SIGNAL(scrollingEnded()),
+                    this,           SLOT(adjustAfterScroll()) );
 
-    RadioStationModel* stationModel = &mUiEngine->stationModel();
-    connectAndTest( stationModel,   SIGNAL(favoriteChanged(RadioStation)),
+    mModel = &mUiEngine->stationModel();
+    Radio::connect( mModel,         SIGNAL(favoriteChanged(RadioStation)),
                     this,           SLOT(update(RadioStation)) );
-    connectAndTest( stationModel,   SIGNAL(stationDataChanged(RadioStation)),
+    Radio::connect( mModel,         SIGNAL(stationDataChanged(RadioStation)),
                     this,           SLOT(update(RadioStation)));
-    connectAndTest( stationModel,   SIGNAL(radioTextReceived(RadioStation)),
+    Radio::connect( mModel,         SIGNAL(radioTextReceived(RadioStation)),
                     this,           SLOT(updateRadioText(RadioStation)));
-    connectAndTest( stationModel,   SIGNAL(dynamicPsChanged(RadioStation)),
+    Radio::connect( mModel,         SIGNAL(dynamicPsChanged(RadioStation)),
                     this,           SLOT(update(RadioStation)));
 
-    updateClampingStyle();
-
-    connectAndTest( this,           SIGNAL(longPressed(HbAbstractViewItem*,QPointF)),
-                    this,           SLOT(openContextMenu(HbAbstractViewItem*,QPointF)) );
-    setLongPressEnabled( true );
-
     mGenericTimer->setSingleShot( true );
-    connectAndTest( mGenericTimer,  SIGNAL(timeout()),
+    Radio::connect( mGenericTimer,  SIGNAL(timeout()),
                     this,           SLOT(timerFired()));
 
-    initToLastTunedFrequency();
+    Radio::connect( mModel,         SIGNAL(rowsInserted(QModelIndex,int,int)),
+                    this,           SLOT(updateStations()) );
+    Radio::connect( mModel,         SIGNAL(modelReset()),
+                    this,           SLOT(updateStations()) );
+    Radio::connect( mModel,         SIGNAL(rowsRemoved(QModelIndex,int,int)),
+                    this,           SLOT(updateStations()) );
+
+    setFrequency( mUiEngine->currentFrequency(), TuneReason::Unspecified );
 
 #ifdef USE_DEBUGGING_CONTROLS
     mRdsLabel->setPos( QPoint( 300, 10 ) );
@@ -251,7 +224,7 @@
     mRdsLabel->setFontSpec( spec );
     mRdsLabel->setTextColor( Qt::gray );
     if ( mUiEngine ) {
-        connectAndTest( mUiEngine,      SIGNAL(rdsAvailabilityChanged(bool)),
+        Radio::connect( mUiEngine,      SIGNAL(rdsAvailabilityChanged(bool)),
                         this,           SLOT(setRdsAvailable(bool)) );
     }
 #endif // USE_DEBUGGING_CONTROLS
@@ -260,52 +233,42 @@
 /*!
  *
  */
-void RadioStationCarousel::setCarouselModel( RadioCarouselModel* carouselModel )
+void RadioStationCarousel::setFrequency( uint frequency, int reason, Scroll::Direction direction )
 {
-    if ( carouselModel ) {
-        connectAndTest( carouselModel,  SIGNAL(rowsInserted(QModelIndex,int,int)),
-                        this,           SLOT(insertFrequency(QModelIndex,int,int)) );
-        connectAndTest( carouselModel,  SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
-                        this,           SLOT(prepareToRemoveFrequency(QModelIndex,int,int)) );
-        connectAndTest( carouselModel,  SIGNAL(rowsRemoved(QModelIndex,int,int)),
-                        this,           SLOT(removeFrequency(QModelIndex,int,int)) );
-    } else {
-        QAbstractItemModel* currentModel = model();
-        disconnect( currentModel,   SIGNAL(rowsInserted(QModelIndex,int,int)),
-                    this,           SLOT(insertFrequency(QModelIndex,int,int)) );
-        disconnect( currentModel,   SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
-                    this,           SLOT(prepareToRemoveFrequency(QModelIndex,int,int)) );
-        disconnect( currentModel,   SIGNAL(rowsRemoved(QModelIndex,int,int)),
-                    this,           SLOT(removeFrequency(QModelIndex,int,int)) );
-    }
-    setModel( carouselModel );
-    updateFrequencies();
-    initCurrentStationItem();
-}
+    if ( mModel ) {
+        if ( !mManualSeekMode ) {
+
+            if ( mModel->rowCount() <= 1 ) {
+                mItems[LeftItem]->setStation( RadioStation() );
+                mItems[RightItem]->setStation( RadioStation() );
+            }
 
-/*!
- *
- */
-void RadioStationCarousel::setFrequency( uint frequency, int reason )
-{
-    RadioStationItem* item = currentStationItem();
-//    if ( item && item->mFrequency == frequency ) {
-//        return;
-//    }
+            mIsCustomFreq = false;
+            if ( reason == TuneReason::Skip || reason == TuneReason::StationScanFinalize ) {
+                const int newIndex = mModel->indexFromFrequency( frequency );
+                scrollToIndex( newIndex, direction, NoSignal );
+                mCurrentIndex = newIndex;
+            } else {
+                if ( mModel->contains( frequency ) ) {
+                    mCurrentIndex = mModel->indexFromFrequency( frequency );
+                } else {
+                    const RadioStation prevStation = mModel->findClosest( frequency, StationSkip::Previous );
+                    if ( prevStation.isValid() ) {
+                        mCurrentIndex = mModel->indexFromFrequency( prevStation.frequency() );
+                    } else {
+                        mCurrentIndex = -1;
+                    }
 
-    if ( mModelIndexes.contains( frequency ) ) {
-        QModelIndex index = mModelIndexes.value( frequency );
+                    mIsCustomFreq = true;
+                }
 
-        if ( reason == TuneReason::FrequencyStrip || reason == TuneReason::StationsList ) {
-            scrollToIndex( index, RadioStationCarousel::NoAnim | RadioStationCarousel::NoSignal );
-        } else if ( reason == TuneReason::Skip || reason == TuneReason::StationScan ) {
-            scrollToIndex( index, RadioStationCarousel::NoSignal );
+                mItems[CenterItem]->setFrequency( frequency );
+                mTimerMode = SetFrequency;
+                mGenericTimer->stop();
+                mGenericTimer->start( SET_FREQUENCY_TIMEOUT );
+            }
         } else {
-            scrollToIndex( index );
-        }
-    } else {
-        if ( item ) {
-            item->setFrequency( frequency );
+            mItems[CenterItem]->setFrequency( frequency );
         }
     }
 }
@@ -323,7 +286,7 @@
  */
 bool RadioStationCarousel::isAntennaAttached() const
 {
-    return mAntennaAttached;
+    return mUiEngine->isAntennaAttached();
 }
 
 /*!
@@ -331,19 +294,24 @@
  */
 void RadioStationCarousel::setScanningMode( bool scanning )
 {
-    initCurrentStationItem();
+    CALL_TO_ALL_ITEMS( setSeekLayout( scanning ) );
 
     if ( scanning ) {
-
         setInfoText( CarouselInfoText::Scanning );
-        if ( !mScanningHelper ) {
-            mScanningHelper = new ScanningHelper( *this );
+        if ( !mAnimator ) {
+            mAnimator = new RadioCarouselAnimator( *this );
         }
+        mAnimator.data()->startFlashingText();
     } else {
-        delete mScanningHelper;
-        mScanningHelper = 0;
+        if ( mAnimator ) {
+            mAnimator.data()->stopFlashingText();
+        }
         clearInfoText();
+        setCenterIndex( 0 );
+        mTimerMode = FavoriteHintShow;
+        mGenericTimer->start( FAVORITE_HINT_SHOW_DELAY );
     }
+
     setEnabled( !scanning );
 }
 
@@ -352,7 +320,7 @@
  */
 bool RadioStationCarousel::isInScanningMode() const
 {
-    return RadioUiUtilities::isScannerAlive();
+    return RadioUtil::scanStatus() == Scan::ScanningInMainView;
 }
 
 /*!
@@ -360,21 +328,7 @@
  */
 void RadioStationCarousel::cleanRdsData()
 {
-    RadioStationItem* item = currentStationItem();
-    if ( item ) {
-        item->cleanRdsData();
-    }
-}
-
-/*!
- *
- */
-void RadioStationCarousel::updateCurrentItem()
-{
-    RadioStationItem* item = currentStationItem();
-    if ( item ) {
-        item->update();
-    }
+    mItems[CenterItem]->cleanRdsData();
 }
 
 /*!
@@ -382,40 +336,23 @@
  */
 void RadioStationCarousel::animateNewStation( const RadioStation& station )
 {
-    if ( mScanningHelper ) {
-        RadioCarouselModel* model = carouselModel();
-        const QModelIndex index = model->modelIndexFromFrequency( station.frequency() );
-        mScanningHelper->mModelIndex = index;
-        mScanningHelper->mCurrentFrequency = station.frequency();
-        mScanningHelper->mStationItem = static_cast<RadioStationItem*>( itemByIndex( index ) );
+    if ( mAnimator && mUiEngine ) {
+        const uint previousFrequency = mItems[CenterItem]->frequency();
 
-        uint prevFrequency = 0;
-        if ( model->rowCount() > 1 ) {
-            const int prevIndex = index.row() - 1;
-            RadioStation prevStation = model->data( model->index( prevIndex, 0 ), RadioStationModel::RadioStationRole ).value<RadioStation>();
-            prevFrequency = prevStation.frequency();
-        } else if ( mUiEngine ) {
-            prevFrequency = mUiEngine->minFrequency();
-        }
+        mItems[RightItem]->setFrequency( previousFrequency );
+        mCurrentIndex = mModel->indexFromFrequency( station.frequency() );
 
-        mScanningHelper->mPreviousFrequency = prevFrequency;
-        if ( mScanningHelper->mStationItem ) {
-            mScanningHelper->mStationItem->setFrequency( prevFrequency );
-            mScanningHelper->mStationItem->cleanRdsData();
-        }
-
-        mScanningHelper->start();
+        mAnimator.data()->startNumberScroll( previousFrequency, station.frequency() );
     }
 }
 
 /*!
  *
  */
-void RadioStationCarousel::setItemVisible( bool visible )
+void RadioStationCarousel::cancelAnimation()
 {
-    RadioStationItem* item = currentStationItem();
-    if ( item ) {
-        item->setVisible( visible );
+    if ( mAnimator ) {
+        mAnimator.data()->stopAll();
     }
 }
 
@@ -425,13 +362,21 @@
 void RadioStationCarousel::setInfoText( CarouselInfoText::Type type )
 {
     mInfoTextType = type;
-    if ( type == CarouselInfoText::NoFavorites ) {
-        mInfoText->setPlainText( hbTrId( "txt_rad_dialog_long_press_arrow_keys_to_search_str" ) );
+    if ( type == CarouselInfoText::NoFavorites || type == CarouselInfoText::FavoriteIconHint ) {
+//        mInfoText->setPlainText( hbTrId( "txt_rad_dialog_long_press_arrow_keys_to_search_str" ) );
+    //TODO: Remove hardcoding. Temporarily hardcoded for usability testing
+        mInfoText->setPlainText( "Tap star to mark favourites" );
         mInfoText->setAlignment( Qt::AlignCenter );
-        setItemVisible( false );
+        mItems[CenterItem]->setItemVisibility( RadioCarouselItem::IconVisible );
         mTimerMode = InfoText;
         mGenericTimer->setInterval( INFOTEXT_NOFAVORITES_TIMEOUT );
         mGenericTimer->start();
+
+        if ( !mAnimator ) {
+            mAnimator = new RadioCarouselAnimator( *this );
+        }
+        mAnimator.data()->startFlashingIcon();
+
     } else if ( type == CarouselInfoText::ConnectAntenna ) {
         cleanRdsData();
         mInfoText->setPlainText( hbTrId( "txt_rad_info_connect_wired_headset1" ) );
@@ -444,6 +389,9 @@
         cleanRdsData();
         mInfoText->setAlignment( Qt::AlignBottom | Qt::AlignHCenter );
         mInfoText->setPlainText( hbTrId( "txt_rad_list_searching_all_available_stations_ple" ) );
+    } else if ( type == CarouselInfoText::ManualSeek ) {
+        mInfoText->setAlignment( Qt::AlignBottom | Qt::AlignHCenter );
+        mInfoText->setPlainText( "Manual Seek Mode" );
     }
 
     mInfoText->setVisible( true );
@@ -455,23 +403,89 @@
 void RadioStationCarousel::clearInfoText()
 {
     if ( mInfoTextType != CarouselInfoText::None ) {
+        if ( mAnimator ) {
+            mAnimator.data()->stopFlashingIcon();
+        }
+
         mGenericTimer->stop();
         mInfoTextType = CarouselInfoText::None;
         mInfoText->setVisible( false );
         mInfoText->clear();
-        setItemVisible( true );
-        updateCurrentItem();
+        mItems[CenterItem]->setItemVisibility( RadioCarouselItem::AllVisible );
+    }
+}
+
+/*!
+ *
+ */
+void RadioStationCarousel::setManualSeekMode( bool manualSeekActive )
+{
+    mManualSeekMode = manualSeekActive;
+    setEnabled( !manualSeekActive );
+
+    mItems[CenterItem]->setSeekLayout( manualSeekActive );
+    if ( manualSeekActive ) {
+        setInfoText( CarouselInfoText::ManualSeek );
+    } else {
+        clearInfoText();
+        setFrequency( mUiEngine->currentFrequency(), TuneReason::Unspecified );
+    }
+}
+
+/*!
+ *
+ */
+void RadioStationCarousel::drawOffScreen( QPainter& painter )
+{
+    mItems[CenterItem]->drawOffScreen( painter );
+}
+
+/*!
+ * TODO: Remove this! This is test code
+ */
+void RadioStationCarousel::setAlternateSkippingMode( bool alternateSkipping )
+{
+    mAlternateSkipping = alternateSkipping;
+}
+
+/*!
+ * Private slot
+ *
+ */
+void RadioStationCarousel::scrollPosChanged( const QPointF& newPosition )
+{
+    Q_UNUSED( newPosition );
+//    const int xPos = static_cast<int>( newPosition.x() );
+//    mItems[CenterItem]->setPos( xPos - mMidScrollPos, 0 );
+}
+
+/*!
+ * Private slot
+ ''
+ */
+void RadioStationCarousel::adjustAfterScroll()
+{
+    if ( isInScanningMode() ) {
+        return;
+    }
+
+    if ( mTargetIndex != -1 ) {
+        setCenterIndex( mTargetIndex );
     }
 }
 
 /*!
  * Private slot
+ *
  */
 void RadioStationCarousel::update( const RadioStation& station )
 {
-    RadioStationItem* item = currentStationItem();
-    if ( item && item->frequency() == station.frequency() && !isInScanningMode() ) {
-        item->update( &station );
+    if ( !mManualSeekMode && !isInScanningMode() ) {
+        for ( int i = LeftItem; i <= RightItem; ++i ) {
+            if ( mItems[i]->frequency() == station.frequency() ) {
+                mItems[i]->update( &station );
+            }
+        }
     }
 }
 
@@ -482,15 +496,12 @@
 {
     if ( isAntennaAttached() && !isInScanningMode() ) {
         if ( station.radioText().isEmpty() ) {
-            RadioStationItem* item = currentStationItem();
-            if ( item ) {
-                item->mRadiotextLabel->setText( "" );
-            }
+            mItems[CenterItem]->setRadioText( "" );
         } else {
             mRadioTextHolder = station.radioText();
             mTimerMode = RtPlusCheck;
             mGenericTimer->stop();
-            mGenericTimer->setInterval( KRadioTextPlusCheckTimeout );
+            mGenericTimer->setInterval( RTPLUS_CHECK_TIMEOUT );
             mGenericTimer->start();
         }
     }
@@ -499,68 +510,13 @@
 /*!
  * Private slot
  */
-void RadioStationCarousel::insertFrequency( const QModelIndex& parent, int first, int last )
+void RadioStationCarousel::updateStations()
 {
-    Q_UNUSED( parent );
-    QAbstractItemModel* freqModel = model();
-
-    for ( int i = first; freqModel && i <= last; ++i ) {
-        QModelIndex index = freqModel->index( i, 0 );
-        RadioStation station = freqModel->data( index, RadioStationModel::RadioStationRole ).value<RadioStation>();
-        mModelIndexes.insert( station.frequency(), index );
-        LOG_FORMAT( "Added frequency %u", station.frequency() );
-        if ( !isInScanningMode() ) {
-            scrollToIndex( index, RadioStationCarousel::NoAnim | RadioStationCarousel::NoSignal );
-        }
+    if ( isInScanningMode() ) {
+        return;
     }
 
-    initCurrentStationItem();
-
-    updateClampingStyle();
-}
-
-/*!
- * Private slot
- */
-void RadioStationCarousel::prepareToRemoveFrequency( const QModelIndex& parent, int first, int last )
-{
-    Q_UNUSED( parent );
-    QAbstractItemModel* freqModel = model();
-    for ( int i = first; freqModel && i <= last; ++i ) {
-        QModelIndex index = freqModel->index( i, 0 );
-        RadioStation station = freqModel->data( index, RadioStationModel::RadioStationRole ).value<RadioStation>();
-        mModelIndexes.remove( station.frequency() );
-    }
-}
-
-/*!
- * Private slot
- */
-void RadioStationCarousel::removeFrequency( const QModelIndex& parent, int first, int last )
-{
-    Q_UNUSED( parent );
-    Q_UNUSED( first );
-    Q_UNUSED( last );
-
-    initCurrentStationItem();
-    updateClampingStyle();
-}
-
-/*!
- * Private slot
- */
-void RadioStationCarousel::updateFrequencies()
-{
-    mModelIndexes.clear();
-    QAbstractItemModel* itemModel = model();
-    if ( itemModel ) {
-        const int count = itemModel->rowCount();
-        for ( int i = 0; i < count; ++i ) {
-            QModelIndex index = itemModel->index( i, 0 );
-            uint frequency = itemModel->data( index, RadioStationModel::RadioStationRole ).value<RadioStation>().frequency();
-            mModelIndexes.insert( frequency, index );
-        }
-    }
+    setFrequency( mUiEngine->currentFrequency(), TuneReason::Unspecified );
 }
 
 /*!
@@ -568,26 +524,23 @@
  */
 void RadioStationCarousel::timerFired()
 {
-    if ( mTimerMode == RtPlusCheck ) {
-        RadioStationItem* item = currentStationItem();
-        if ( item ) {
-            item->mRadiotextLabel->setText( mRadioTextHolder );
-        }
+    if ( mTimerMode == SetFrequency ) {
+        setCenterIndex( mCurrentIndex, NoSignal | IgnoreCenter );
+        mTimerMode = NoTimer;
+    } else if ( mTimerMode == RtPlusCheck ) {
+        //mItems[CenterItem]->mRadiotextLabel->setText( mRadioTextHolder );
         mRadioTextHolder = "";
+        mTimerMode = NoTimer;
     } else if ( mTimerMode == InfoText ) {
         clearInfoText();
-    }
-
-    mTimerMode = NoTimer;
-}
-
-/*!
- * Private slot
- */
-void RadioStationCarousel::openContextMenu( HbAbstractViewItem* item, const QPointF& coords )
-{
-    if ( item ) {
-        static_cast<RadioStationItem*>( item )->handleLongPress( coords );
+        mTimerMode = NoTimer;
+    } else if ( mTimerMode == FavoriteHintShow ) {
+        setInfoText( CarouselInfoText::FavoriteIconHint );
+        mTimerMode = FavoriteHintHide;
+        mGenericTimer->start( FAVORITE_HINT_HIDE_DELAY );
+    } else if ( mTimerMode == FavoriteHintHide ) {
+        clearInfoText();
+        mTimerMode = NoTimer;
     }
 }
 
@@ -614,7 +567,6 @@
  */
 void RadioStationCarousel::updateAntennaStatus( bool connected )
 {
-    mAntennaAttached = connected;
     mGenericTimer->stop();
 
     if ( !connected ) {
@@ -629,11 +581,39 @@
  */
 void RadioStationCarousel::mousePressEvent( QGraphicsSceneMouseEvent* event )
 {
-    if ( mInfoTextType == CarouselInfoText::NoFavorites ) {
+    if ( mInfoTextType == CarouselInfoText::NoFavorites || mInfoTextType == CarouselInfoText::FavoriteIconHint ) {
         clearInfoText();
     }
 
-    HbGridView::mousePressEvent( event );
+    HbScrollArea::mousePressEvent( event );
+}
+
+/*!
+ * \reimp
+ */
+void RadioStationCarousel::resizeEvent( QGraphicsSceneResizeEvent* event )
+{
+    HbScrollArea::resizeEvent( event );
+
+    const int width = (int)event->newSize().width();
+
+    mMidScrollPos = -width;
+    mMaxScrollPos = mMidScrollPos * 2;
+
+    if ( isInitialized() ) {
+        mItems[LeftItem]->setMinimumWidth( width );
+        mItems[CenterItem]->setMinimumWidth( width );
+        mItems[RightItem]->setMinimumWidth( width );
+    }
+}
+
+/*!
+ * \reimp
+ */
+void RadioStationCarousel::showEvent( QShowEvent* event )
+{
+    HbScrollArea::showEvent( event );
+//    mContainer->setPos( mMidScrollPos, 0 );
 }
 
 /*!
@@ -641,117 +621,340 @@
  */
 void RadioStationCarousel::gestureEvent( QGestureEvent* event )
 {
-    HbGridView::gestureEvent( event );
+//    if ( HbSwipeGesture* swipeGesture = static_cast<HbSwipeGesture*>( event->gesture( Qt::SwipeGesture ) ) ) {
+//        if ( swipeGesture->state() == Qt::GestureFinished ) {
+//            if ( swipeGesture->horizontalDirection() == QSwipeGesture::Left ) {
+//                emit skipRequested( StationSkip::Next );
+//            } else if ( swipeGesture->horizontalDirection() == QSwipeGesture::Right ) {
+//                emit skipRequested( StationSkip::Previous );
+//            }
+//            mIsCustomFreq = false;
+//        }
+//        return;
+//    }
+
+    HbScrollArea::gestureEvent( event );
 
     if ( HbPanGesture* gesture = qobject_cast<HbPanGesture*>( event->gesture( Qt::PanGesture ) ) ) {
         if ( gesture->state() == Qt::GestureFinished ) {
-            updatePos( (int)gesture->offset().x() );
+            adjustPos( (int)gesture->offset().x() );
         }
     }
 }
 
 /*!
+ * \reimp
+ */
+void RadioStationCarousel::handleIconClicked( const RadioStation& station )
+{
+    if ( mModel ) {
+        mModel->setData( QModelIndex(), station.frequency(), RadioRole::ToggleFavoriteRole );
+    }
+}
+
+/*!
+ * \reimp
+ */
+void RadioStationCarousel::handleRadiotextClicked( const RadioStation& station )
+{
+    Q_UNUSED( station );
+    mRadiotextPopup->show();
+}
+
+/*!
+ * \reimp
+ */
+void RadioStationCarousel::handleUrlClicked( const RadioStation& station )
+{
+    mUiEngine->launchBrowser( station.url() );
+}
+
+/*!
+ * \reimp
+ */
+QString RadioStationCarousel::localizeGenre( int genre )
+{
+    return mUiEngine->genreToString( genre, GenreTarget::Carousel );
+}
+
+/*!
+ * \reimp
+ */
+bool RadioStationCarousel::isInManualSeek() const
+{
+    return mManualSeekMode;
+}
+
+/*!
  *
  */
-void RadioStationCarousel::initToLastTunedFrequency()
+RadioStation RadioStationCarousel::findStation( uint frequency )
 {
-    const uint currentFrequency = mUiEngine->currentFrequency();
-    const QModelIndex currentIndex = carouselModel()->modelIndexFromFrequency( currentFrequency );
+    return mModel->findStation( frequency, FindCriteria::IncludeManualStation );
+}
 
-    if ( currentIndex.isValid() ) {//&& itemByIndex( currentIndex ) ) {
-        scrollToIndex( currentIndex, RadioStationCarousel::NoSignal | RadioStationCarousel::NoAnim );
-    } else {
-        RadioStationItem* item = static_cast<RadioStationItem*>( itemAt( 0, 0 ) );
-        if ( item ) {
-            item->setFrequency( currentFrequency );
-        }
-    }
+/*!
+ *
+ */
+bool RadioStationCarousel::isInitialized() const
+{
+    return mUiEngine != NULL;
 }
 
 /*!
  *
  */
-void RadioStationCarousel::updateClampingStyle()
+void RadioStationCarousel::setCenterIndex( int index, ScrollMode mode )
 {
-    if ( model()->rowCount() > 1 ) {
-        setClampingStyle( HbScrollArea::StrictClamping );
-    } else {
-        setClampingStyle( HbScrollArea::BounceBackClamping );
-        update( mUiEngine->stationModel().currentStation() );
+    Q_UNUSED( mode );
+    if ( mModel ) {
+        const int newIndex = trimIndex( index );
+        mCurrentIndex = newIndex;
+        mTargetIndex = -1;
+
+        if ( !mIsCustomFreq ) {
+            mItems[CenterItem]->setStation( mModel->stationAt( mCurrentIndex ) );
+        }
+
+        if ( mModel->rowCount() > 1 ) {
+            const int leftIndex = prevIndex( mCurrentIndex );
+            const int rightIndex = nextIndex( mCurrentIndex );
+            mItems[LeftItem]->setStation( mModel->stationAt( leftIndex ) );
+            mItems[RightItem]->setStation( mModel->stationAt( rightIndex ) );
+        } else {
+
+            if ( mIsCustomFreq ) {
+                const uint frequency = mItems[CenterItem]->frequency();
+                mItems[LeftItem]->setStation( mModel->findClosest( frequency, StationSkip::Previous ) );
+                mItems[RightItem]->setStation( mModel->findClosest( frequency, StationSkip::Next ) );
+            } else {
+                mItems[LeftItem]->setStation( RadioStation() );
+                mItems[RightItem]->setStation( RadioStation() );
+            }
+        }
+
+        scrollContentsTo( QPointF( -mMidScrollPos /* + delta */, 0 ), 0 );
+
+//        if ( !mode.testFlag( NoSignal ) ) {
+//            uint frequency = mModel->stationAt( mCurrentIndex ).frequency();
+//            emit frequencyChanged( frequency, TuneReason::StationCarousel, mScrollDirection );
+//            mScrollDirection = Scroll::Shortest;
+//        }
     }
 }
 
 /*!
  *
  */
-void RadioStationCarousel::initCurrentStationItem()
+void RadioStationCarousel::scrollToIndex( int index, Scroll::Direction direction, ScrollMode mode )
 {
-    mCurrentItem = static_cast<RadioStationItem*>( visibleItems().first() );
-}
+    if ( mModel && index >= 0  ) {
+        mTargetIndex = index;
+        const int difference = calculateDifference( index, direction );
+        int scrollTime = mAutoScrollTime;
 
-/*!
- *
- */
-RadioStationItem* RadioStationCarousel::currentStationItem()
-{
-    return mCurrentItem;
-}
+        int posX = direction == Scroll::Left ? -mMaxScrollPos : 0;
+        if ( difference == 1 ) {
+            if ( direction == Scroll::Right ) {
+                posX = 0;
+            } else if ( direction == Scroll::Left ) {
+                posX = -mMaxScrollPos;
+            }
+        } else {
+            if ( direction == Scroll::Right ) {
+                // Item where the scrolling starts
+                mItems[RightItem]->setStation( mModel->stationAt( mCurrentIndex ) );
+
+                // Item that is skipped over
+                const uint centerFreq = mModel->stationAt( nextIndex( index ) ).frequency();
+                mItems[CenterItem]->setFrequency( centerFreq );
 
-/*!
- *
- */
-RadioCarouselModel* RadioStationCarousel::carouselModel() const
-{
-    return static_cast<RadioCarouselModel*>( model() );
-}
+                // Item where the scrolling ends
+                const RadioStation station = mModel->stationAt( index );
+                mItems[LeftItem]->setStation( station );
+
+                mContainer->setPos( mMaxScrollPos, 0 );
+                posX = 0;
+            } else if ( direction == Scroll::Left ) {
+                // Item where the scrolling starts
+                mItems[LeftItem]->setStation( mModel->stationAt( mCurrentIndex ) );
 
-/*!
- *
- */
-void RadioStationCarousel::scrollToIndex( const QModelIndex& index, RadioStationCarousel::ScrollMode mode )
-{
-    RadioStationItem* item = static_cast<RadioStationItem*>( itemByIndex( index ) );
-    if ( index.isValid() && item ) {
-        const int posX = index.row() * (int)size().width();
-        setCurrentIndex( index, QItemSelectionModel::ClearAndSelect );
+                // Item that is skipped over
+                const uint centerFreq = mModel->stationAt( prevIndex( index ) ).frequency();
+                mItems[CenterItem]->setFrequency( centerFreq );
+
+                // Item where the scrolling ends
+                const RadioStation station = mModel->stationAt( index );
+                mItems[RightItem]->setStation( station );
+
+                mContainer->setPos( 0, 0 );
+                posX = -mMaxScrollPos;
+            }
+        }
 
         if ( mode.testFlag( UpdateItem ) ) {
-            item->update();
+            //item->update();
         }
 
-        int scrollTime = mAutoScrollTime;
         if ( mode.testFlag( NoAnim ) ) {
             scrollTime = 0;
+        } else if ( mode.testFlag( FromPanGesture ) ) {
+            if ( mAlternateSkipping ) { //TODO: Remove this! This is test code
+                scrollTime = 500;
+            } else {
+                scrollTime = 300;
+            }
+        } else if ( mode.testFlag( FromSwipeGesture ) ) {
+            scrollTime = 100;
         }
+
         scrollContentsTo( QPointF( posX, 0 ), scrollTime );
-        mCurrentItem = static_cast<RadioStationItem*>( item );
-        if ( !mode.testFlag( NoSignal ) ) {
-            uint frequency = model()->data( index, RadioStationModel::RadioStationRole ).value<RadioStation>().frequency();
-            emit frequencyChanged( frequency, TuneReason::StationCarousel );
-        }
     }
 }
 
 /*!
  *
  */
-void RadioStationCarousel::updatePos( int offset )
+int RadioStationCarousel::calculateDifference( int targetIndex, Scroll::Direction& direction )
+{
+    int difference = 0;
+    const int rowCount = mModel->rowCount();
+
+    int diffToLeft = 0;
+    int diffToRight = 0;
+    if ( targetIndex > mCurrentIndex ) {
+        const int loopedDiff = mCurrentIndex + rowCount - targetIndex;
+        const int directDiff = targetIndex - mCurrentIndex;
+        diffToLeft = loopedDiff;
+        diffToRight = directDiff;
+    } else {
+        const int loopedDiff = targetIndex + rowCount - mCurrentIndex;
+        const int directDiff = mIsCustomFreq ? 1 : mCurrentIndex - targetIndex;
+        diffToLeft = directDiff;
+        diffToRight = loopedDiff;
+    }
+
+    if ( direction == Scroll::Right ) {
+        difference = diffToLeft;
+    } else if ( direction == Scroll::Left ) {
+        difference = diffToRight;
+    } else {
+        if ( diffToLeft < diffToRight ) {
+            difference = diffToLeft;
+            direction = Scroll::Right;
+        } else {
+            difference = diffToRight;
+            direction = Scroll::Left;
+        }
+    }
+
+    return difference;
+}
+
+/*!
+ *
+ */
+bool RadioStationCarousel::isScrollingAllowed() const
+{
+    const int rowCount = mModel->rowCount();
+    return rowCount > 1 || ( rowCount == 1 && mIsCustomFreq );
+}
+
+/*!
+ *
+ */
+void RadioStationCarousel::adjustPos( int offset )
 {
-//    QModelIndex index = currentIndex();
-//
-//    ScrollMode mode = 0;
-//    const qreal threshold = size().width() / 3;
-//    if ( abs( offset ) >= threshold ) {
-//        if ( offset > 0 ) {
-//            index = previousIndex( index );
-//        } else {
-//            index = nextIndex( index );
-//        }
-//    } else {
-//        mode |= RadioStationCarousel::NoSignal;
-//    }
-//
-//    scrollToIndex( index, mode );
+    int newPos = mMidScrollPos;
+    const int threshold = (int)size().width() / 5;
+    int newIndex = mCurrentIndex;
+    bool needsToScroll = false;
+
+    if ( isScrollingAllowed() && abs( offset ) >= threshold ) {
+        needsToScroll = true;
+        if ( offset > 0 ) {
+            newPos = 0;
+            mScrollDirection = Scroll::Right;
+            if ( !mIsCustomFreq ) {
+
+                if ( mAlternateSkipping ) { //TODO: Remove this! This is test code
+                    const uint newFreq = mModel->findClosest( mItems[CenterItem]->frequency(), StationSkip::PreviousFavorite ).frequency();
+                    if ( newFreq > 0 ) {
+                        newIndex = mModel->indexFromFrequency( newFreq );
+                    } else {
+                        needsToScroll = false;
+                        newPos = mMidScrollPos;
+                    } // End test code
+
+                } else {
+                    --newIndex;
+                }
+            }
+        } else {
+            mScrollDirection = Scroll::Left;
+            newPos = mMaxScrollPos;
+
+            if ( mAlternateSkipping ) { //TODO: Remove this! This is test code
+                const uint newFreq = mModel->findClosest( mItems[CenterItem]->frequency(), StationSkip::NextFavorite ).frequency();
+                if ( newFreq > 0 ) {
+                    newIndex = mModel->indexFromFrequency( newFreq );
+                } else {
+                    needsToScroll = false;
+                    newPos = mMidScrollPos;
+                } // End test code
+
+            } else {
+                ++newIndex;
+            }
+        }
+    }
+
+    newIndex = trimIndex( newIndex );
+    if ( needsToScroll ) {
+        const uint frequency = mModel->stationAt( newIndex ).frequency();
+        emit frequencyChanged( frequency, TuneReason::StationCarousel, mScrollDirection );
+        scrollToIndex( newIndex, mScrollDirection, RadioStationCarousel::FromPanGesture );
+        mIsCustomFreq = false;
+    } else {
+        scrollContentsTo( QPointF( -newPos, 0 ), 300 );
+    }
+}
+
+/*!
+ *
+ */
+int RadioStationCarousel::trimIndex( int index )
+{
+    const int count = mModel ? mModel->rowCount() : 0;
+
+    if ( count == 0 ) {
+        return -1;
+    }
+
+    if ( index < 0 ) {
+        index = count - 1;
+    }
+    index %= count;
+    return index;
+}
+
+/*!
+ *
+ */
+int RadioStationCarousel::prevIndex( int index )
+{
+    if ( !mIsCustomFreq ) {
+        --index;
+    }
+    return trimIndex( index );
+}
+
+/*!
+ *
+ */
+int RadioStationCarousel::nextIndex( int index )
+{
+    return trimIndex( index + 1 );
 }
 
 /*!
@@ -759,11 +962,10 @@
  */
 void RadioStationCarousel::skip( StationSkip::Mode mode )
 {
-    RadioStationItem* item = currentStationItem();
-    if ( item ) {
-        RadioCarouselModel* model = carouselModel();
-        const uint frequency = model->findClosest( item->frequency(), mode ).frequency();
-        const QModelIndex& index = model->modelIndexFromFrequency( frequency );
-        scrollToIndex( index, RadioStationCarousel::NoSignal );
+    if ( mModel ) {
+        const uint frequency = mModel->findClosest( mItems[CenterItem]->frequency(), mode ).frequency();
+        const int index = mModel->indexFromFrequency( frequency );
+        const Scroll::Direction direction = RadioUtil::scrollDirectionFromSkipMode( mode );
+        scrollToIndex( index, direction, RadioStationCarousel::NoSignal );
     }
 }