diff -r 6bcf277166c1 -r 451b2e1545b2 radioapp/radiowidgets/src/radiostationcarousel.cpp --- 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 -#include -#include -#include -#include +#include #include -#include #include +#include +#include +#include +#include // 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( DOCML::MV_NAME_INFO_TEXT ); mInfoText->setTextWrapping( Hb::TextWordWrap ); - setRowCount( 1 ); - setColumnCount( 1 ); + mRadiotextPopup = uiLoader.findObject( 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( 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( 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(); - 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( 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(); - 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(); - 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().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( 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( 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( 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( 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( 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( 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( 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( item ); - if ( !mode.testFlag( NoSignal ) ) { - uint frequency = model()->data( index, RadioStationModel::RadioStationRole ).value().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 ); } }