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 <QGraphicsLinearLayout> |
|
20 #include <QGraphicsSceneResizeEvent> |
|
21 #include <QTimer> |
|
22 #include <HbPanGesture> |
|
23 #include <HbSwipeGesture> |
|
24 #include <HbFontSpec> |
|
25 #include <HbMenu> |
|
26 #include <QPainter> |
|
27 |
|
28 // User includes |
|
29 #include "radiostationcarousel.h" |
|
30 #include "radiocarouselanimator.h" |
|
31 #include "radiouiloader.h" |
|
32 #include "radiocarouselitem.h" |
|
33 #include "radiostation.h" |
|
34 #include "radiouiengine.h" |
|
35 #include "radiostationmodel.h" |
|
36 #include "radiofadinglabel.h" |
|
37 #include "radiologger.h" |
|
38 #include "radioutil.h" |
|
39 #include "radio_global.h" |
|
40 |
|
41 // Constants |
|
42 const int RTPLUS_CHECK_TIMEOUT = 700; |
|
43 const int INFOTEXT_NOFAVORITES_TIMEOUT = 5000; |
|
44 const int SET_FREQUENCY_TIMEOUT = 500; |
|
45 const int FAVORITE_HINT_SHOW_DELAY = 1000; |
|
46 const int FAVORITE_HINT_HIDE_DELAY = 2000; |
|
47 |
|
48 // Matti testing constants |
|
49 const QLatin1String LEFT_ITEM_NAME ( "carousel_left" ); |
|
50 const QLatin1String CENTER_ITEM_NAME ( "carousel_center" ); |
|
51 const QLatin1String RIGHT_ITEM_NAME ( "carousel_right" ); |
|
52 |
|
53 #ifdef BUILD_WIN32 |
|
54 # define SCROLLBAR_POLICY ScrollBarAlwaysOn |
|
55 #else |
|
56 # define SCROLLBAR_POLICY ScrollBarAlwaysOff |
|
57 #endif // BUILD_WIN32 |
|
58 |
|
59 #define CALL_TO_ALL_ITEMS( expr ) \ |
|
60 mItems[LeftItem]->expr; \ |
|
61 mItems[CenterItem]->expr; \ |
|
62 mItems[RightItem]->expr; |
|
63 |
|
64 /*! |
|
65 * |
|
66 */ |
|
67 RadioStationCarousel::RadioStationCarousel( QGraphicsItem* parent ) : |
|
68 HbScrollArea( parent ), |
|
69 mUiEngine( NULL ), |
|
70 mAutoScrollTime( 300 ), |
|
71 mGenericTimer( new QTimer( this ) ), |
|
72 mTimerMode( NoTimer ), |
|
73 mInfoText( NULL ), |
|
74 mRadiotextPopup( NULL ), |
|
75 mContainer( new HbWidget( this ) ), |
|
76 mMidScrollPos( 0 ), |
|
77 mMaxScrollPos( 0 ), |
|
78 mCurrentIndex( 0 ), |
|
79 mTargetIndex( -1 ), |
|
80 mIsCustomFreq( false ), |
|
81 mInfoTextType( CarouselInfoText::None ), |
|
82 mModel( NULL ), |
|
83 mPosAdjustmentDisabled( false ), |
|
84 mScrollDirection( Scroll::Shortest ), |
|
85 mManualSeekMode( false ) |
|
86 #ifdef USE_DEBUGGING_CONTROLS |
|
87 ,mRdsLabel( new RadioFadingLabel( this ) ) |
|
88 #endif // USE_DEBUGGING_CONTROLS |
|
89 { |
|
90 } |
|
91 |
|
92 /*! |
|
93 * Property |
|
94 * |
|
95 */ |
|
96 void RadioStationCarousel::setFavoriteIcon( const HbIcon& favoriteIcon ) |
|
97 { |
|
98 mFavoriteIcon = favoriteIcon; |
|
99 } |
|
100 |
|
101 /*! |
|
102 * Property |
|
103 * |
|
104 */ |
|
105 HbIcon RadioStationCarousel::favoriteIcon() const |
|
106 { |
|
107 return mFavoriteIcon; |
|
108 } |
|
109 |
|
110 /*! |
|
111 * Property |
|
112 * |
|
113 */ |
|
114 void RadioStationCarousel::setNonFavoriteIcon( const HbIcon& nonFavoriteIcon ) |
|
115 { |
|
116 mNonFavoriteIcon = nonFavoriteIcon; |
|
117 } |
|
118 |
|
119 /*! |
|
120 * Property |
|
121 * |
|
122 */ |
|
123 HbIcon RadioStationCarousel::nonFavoriteIcon() const |
|
124 { |
|
125 return mNonFavoriteIcon; |
|
126 } |
|
127 |
|
128 /*! |
|
129 * |
|
130 */ |
|
131 void RadioStationCarousel::setAutoScrollTime( const int time ) |
|
132 { |
|
133 mAutoScrollTime = time; |
|
134 } |
|
135 |
|
136 /*! |
|
137 * |
|
138 */ |
|
139 int RadioStationCarousel::autoScrollTime() const |
|
140 { |
|
141 return mAutoScrollTime; |
|
142 } |
|
143 |
|
144 /*! |
|
145 * |
|
146 */ |
|
147 void RadioStationCarousel::init( RadioUiLoader& uiLoader, RadioUiEngine* uiEngine ) |
|
148 { |
|
149 mUiEngine = uiEngine; |
|
150 RadioUtil::setCarousel( this ); |
|
151 |
|
152 mItems[CenterItem] = new RadioCarouselItem( *this, this, true ); |
|
153 mItems[LeftItem] = new RadioCarouselItem( *this, this ); |
|
154 mItems[RightItem] = new RadioCarouselItem( *this, this ); |
|
155 |
|
156 // Matti testing needs the objects to have names |
|
157 mItems[LeftItem]->setObjectName( LEFT_ITEM_NAME ); |
|
158 mItems[CenterItem]->setObjectName( CENTER_ITEM_NAME ); |
|
159 mItems[RightItem]->setObjectName( RIGHT_ITEM_NAME ); |
|
160 |
|
161 QGraphicsLinearLayout* layout = new QGraphicsLinearLayout( Qt::Horizontal ); |
|
162 layout->setContentsMargins( 0, 0, 0, 0 ); |
|
163 layout->setSpacing( 0 ); |
|
164 layout->addItem( mItems[LeftItem] ); |
|
165 layout->addItem( mItems[CenterItem] ); |
|
166 layout->addItem( mItems[RightItem] ); |
|
167 mContainer->setLayout( layout ); |
|
168 setContentWidget( mContainer ); |
|
169 |
|
170 setClampingStyle( HbScrollArea::NoClamping ); |
|
171 setScrollDirections( Qt::Horizontal ); |
|
172 |
|
173 setFrictionEnabled( true ); |
|
174 setHorizontalScrollBarPolicy( HbScrollArea::SCROLLBAR_POLICY ); |
|
175 setVerticalScrollBarPolicy( HbScrollArea::ScrollBarAlwaysOff ); |
|
176 |
|
177 mInfoText = uiLoader.findWidget<HbLabel>( DOCML::MV_NAME_INFO_TEXT ); |
|
178 mInfoText->setTextWrapping( Hb::TextWordWrap ); |
|
179 |
|
180 mRadiotextPopup = uiLoader.findObject<HbMenu>( DOCML::MV_NAME_CAROUSEL_RT_MENU ); |
|
181 |
|
182 #ifdef BUILD_WIN32 |
|
183 HbFontSpec spec = mInfoText->fontSpec(); |
|
184 spec.setRole( HbFontSpec::Secondary ); |
|
185 mInfoText->setFontSpec( spec ); |
|
186 #endif |
|
187 |
|
188 setScrollDirections( Qt::Horizontal ); |
|
189 |
|
190 Radio::connect( this, SIGNAL(scrollingEnded()), |
|
191 this, SLOT(adjustAfterScroll()) ); |
|
192 |
|
193 mModel = &mUiEngine->stationModel(); |
|
194 Radio::connect( mModel, SIGNAL(favoriteChanged(RadioStation)), |
|
195 this, SLOT(update(RadioStation)) ); |
|
196 Radio::connect( mModel, SIGNAL(stationDataChanged(RadioStation)), |
|
197 this, SLOT(update(RadioStation))); |
|
198 Radio::connect( mModel, SIGNAL(radioTextReceived(RadioStation)), |
|
199 this, SLOT(updateRadioText(RadioStation))); |
|
200 Radio::connect( mModel, SIGNAL(dynamicPsChanged(RadioStation)), |
|
201 this, SLOT(update(RadioStation))); |
|
202 |
|
203 mGenericTimer->setSingleShot( true ); |
|
204 Radio::connect( mGenericTimer, SIGNAL(timeout()), |
|
205 this, SLOT(timerFired())); |
|
206 |
|
207 Radio::connect( mModel, SIGNAL(rowsInserted(QModelIndex,int,int)), |
|
208 this, SLOT(updateStations()) ); |
|
209 Radio::connect( mModel, SIGNAL(modelReset()), |
|
210 this, SLOT(updateStations()) ); |
|
211 Radio::connect( mModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), |
|
212 this, SLOT(updateStations()) ); |
|
213 |
|
214 setFrequency( mUiEngine->currentFrequency(), TuneReason::Unspecified ); |
|
215 |
|
216 #ifdef USE_DEBUGGING_CONTROLS |
|
217 mRdsLabel->setPos( QPoint( 300, 10 ) ); |
|
218 mRdsLabel->setText( "RDS" ); |
|
219 mRdsLabel->setElideMode( Qt::ElideNone ); |
|
220 HbFontSpec spec = mRdsLabel->fontSpec(); |
|
221 spec.setTextPaneHeight( 10 ); |
|
222 spec.setRole( HbFontSpec::Secondary ); |
|
223 mRdsLabel->setFontSpec( spec ); |
|
224 mRdsLabel->setTextColor( Qt::gray ); |
|
225 if ( mUiEngine ) { |
|
226 Radio::connect( mUiEngine, SIGNAL(rdsAvailabilityChanged(bool)), |
|
227 this, SLOT(setRdsAvailable(bool)) ); |
|
228 } |
|
229 #endif // USE_DEBUGGING_CONTROLS |
|
230 } |
|
231 |
|
232 /*! |
|
233 * |
|
234 */ |
|
235 void RadioStationCarousel::setFrequency( uint frequency, int reason, Scroll::Direction direction ) |
|
236 { |
|
237 if ( mModel ) { |
|
238 if ( !mManualSeekMode ) { |
|
239 |
|
240 if ( mModel->rowCount() <= 1 ) { |
|
241 mItems[LeftItem]->setStation( RadioStation() ); |
|
242 mItems[RightItem]->setStation( RadioStation() ); |
|
243 } |
|
244 |
|
245 mIsCustomFreq = false; |
|
246 if ( reason == TuneReason::Skip || reason == TuneReason::StationScanFinalize ) { |
|
247 const int newIndex = mModel->indexFromFrequency( frequency ); |
|
248 scrollToIndex( newIndex, direction, NoSignal ); |
|
249 mCurrentIndex = newIndex; |
|
250 } else { |
|
251 if ( mModel->contains( frequency ) ) { |
|
252 mCurrentIndex = mModel->indexFromFrequency( frequency ); |
|
253 } else { |
|
254 const RadioStation prevStation = mModel->findClosest( frequency, StationSkip::Previous ); |
|
255 if ( prevStation.isValid() ) { |
|
256 mCurrentIndex = mModel->indexFromFrequency( prevStation.frequency() ); |
|
257 } else { |
|
258 mCurrentIndex = -1; |
|
259 } |
|
260 |
|
261 mIsCustomFreq = true; |
|
262 } |
|
263 |
|
264 mItems[CenterItem]->setFrequency( frequency ); |
|
265 mTimerMode = SetFrequency; |
|
266 mGenericTimer->stop(); |
|
267 mGenericTimer->start( SET_FREQUENCY_TIMEOUT ); |
|
268 } |
|
269 } else { |
|
270 mItems[CenterItem]->setFrequency( frequency ); |
|
271 } |
|
272 } |
|
273 } |
|
274 |
|
275 /*! |
|
276 * |
|
277 */ |
|
278 RadioUiEngine* RadioStationCarousel::uiEngine() |
|
279 { |
|
280 return mUiEngine; |
|
281 } |
|
282 |
|
283 /*! |
|
284 * |
|
285 */ |
|
286 bool RadioStationCarousel::isAntennaAttached() const |
|
287 { |
|
288 return mUiEngine->isAntennaAttached(); |
|
289 } |
|
290 |
|
291 /*! |
|
292 * |
|
293 */ |
|
294 void RadioStationCarousel::setScanningMode( bool scanning ) |
|
295 { |
|
296 CALL_TO_ALL_ITEMS( setSeekLayout( scanning ) ); |
|
297 |
|
298 if ( scanning ) { |
|
299 setInfoText( CarouselInfoText::Scanning ); |
|
300 if ( !mAnimator ) { |
|
301 mAnimator = new RadioCarouselAnimator( *this ); |
|
302 } |
|
303 mAnimator.data()->startFlashingText(); |
|
304 } else { |
|
305 if ( mAnimator ) { |
|
306 mAnimator.data()->stopFlashingText(); |
|
307 } |
|
308 clearInfoText(); |
|
309 setCenterIndex( 0 ); |
|
310 mTimerMode = FavoriteHintShow; |
|
311 mGenericTimer->start( FAVORITE_HINT_SHOW_DELAY ); |
|
312 } |
|
313 |
|
314 setEnabled( !scanning ); |
|
315 } |
|
316 |
|
317 /*! |
|
318 * |
|
319 */ |
|
320 bool RadioStationCarousel::isInScanningMode() const |
|
321 { |
|
322 return RadioUtil::scanStatus() == Scan::ScanningInMainView; |
|
323 } |
|
324 |
|
325 /*! |
|
326 * |
|
327 */ |
|
328 void RadioStationCarousel::cleanRdsData() |
|
329 { |
|
330 mItems[CenterItem]->cleanRdsData(); |
|
331 } |
|
332 |
|
333 /*! |
|
334 * |
|
335 */ |
|
336 void RadioStationCarousel::animateNewStation( const RadioStation& station ) |
|
337 { |
|
338 if ( mAnimator && mUiEngine ) { |
|
339 const uint previousFrequency = mItems[CenterItem]->frequency(); |
|
340 |
|
341 mItems[RightItem]->setFrequency( previousFrequency ); |
|
342 mCurrentIndex = mModel->indexFromFrequency( station.frequency() ); |
|
343 |
|
344 mAnimator.data()->startNumberScroll( previousFrequency, station.frequency() ); |
|
345 } |
|
346 } |
|
347 |
|
348 /*! |
|
349 * |
|
350 */ |
|
351 void RadioStationCarousel::cancelAnimation() |
|
352 { |
|
353 if ( mAnimator ) { |
|
354 mAnimator.data()->stopAll(); |
|
355 } |
|
356 } |
|
357 |
|
358 /*! |
|
359 * |
|
360 */ |
|
361 void RadioStationCarousel::setInfoText( CarouselInfoText::Type type ) |
|
362 { |
|
363 mInfoTextType = type; |
|
364 if ( type == CarouselInfoText::NoFavorites || type == CarouselInfoText::FavoriteIconHint ) { |
|
365 // mInfoText->setPlainText( hbTrId( "txt_rad_dialog_long_press_arrow_keys_to_search_str" ) ); |
|
366 //TODO: Remove hardcoding. Temporarily hardcoded for usability testing |
|
367 mInfoText->setPlainText( "Tap star to mark favourites" ); |
|
368 mInfoText->setAlignment( Qt::AlignCenter ); |
|
369 mItems[CenterItem]->setItemVisibility( RadioCarouselItem::IconVisible ); |
|
370 mTimerMode = InfoText; |
|
371 mGenericTimer->setInterval( INFOTEXT_NOFAVORITES_TIMEOUT ); |
|
372 mGenericTimer->start(); |
|
373 |
|
374 if ( !mAnimator ) { |
|
375 mAnimator = new RadioCarouselAnimator( *this ); |
|
376 } |
|
377 mAnimator.data()->startFlashingIcon(); |
|
378 |
|
379 } else if ( type == CarouselInfoText::ConnectAntenna ) { |
|
380 cleanRdsData(); |
|
381 mInfoText->setPlainText( hbTrId( "txt_rad_info_connect_wired_headset1" ) ); |
|
382 mInfoText->setAlignment( Qt::AlignBottom | Qt::AlignHCenter ); |
|
383 } else if ( type == CarouselInfoText::Seeking ) { |
|
384 cleanRdsData(); |
|
385 mInfoText->setAlignment( Qt::AlignBottom | Qt::AlignHCenter ); |
|
386 mInfoText->setPlainText( hbTrId( "txt_rad_list_seeking" ) ); |
|
387 } else if ( type == CarouselInfoText::Scanning ) { |
|
388 cleanRdsData(); |
|
389 mInfoText->setAlignment( Qt::AlignBottom | Qt::AlignHCenter ); |
|
390 mInfoText->setPlainText( hbTrId( "txt_rad_list_searching_all_available_stations_ple" ) ); |
|
391 } |
|
392 |
|
393 mInfoText->setVisible( true ); |
|
394 } |
|
395 |
|
396 /*! |
|
397 * |
|
398 */ |
|
399 void RadioStationCarousel::clearInfoText() |
|
400 { |
|
401 if ( mInfoTextType != CarouselInfoText::None ) { |
|
402 if ( mAnimator ) { |
|
403 mAnimator.data()->stopFlashingIcon(); |
|
404 } |
|
405 |
|
406 mGenericTimer->stop(); |
|
407 mInfoTextType = CarouselInfoText::None; |
|
408 mInfoText->setVisible( false ); |
|
409 mInfoText->clear(); |
|
410 mItems[CenterItem]->setItemVisibility( RadioCarouselItem::AllVisible ); |
|
411 } |
|
412 } |
|
413 |
|
414 /*! |
|
415 * |
|
416 */ |
|
417 void RadioStationCarousel::setManualSeekMode( bool manualSeekActive ) |
|
418 { |
|
419 mManualSeekMode = manualSeekActive; |
|
420 setEnabled( !manualSeekActive ); |
|
421 |
|
422 mItems[CenterItem]->setSeekLayout( manualSeekActive ); |
|
423 if ( !manualSeekActive ) { |
|
424 clearInfoText(); |
|
425 setFrequency( mUiEngine->currentFrequency(), TuneReason::Unspecified ); |
|
426 } |
|
427 } |
|
428 |
|
429 /*! |
|
430 * |
|
431 */ |
|
432 void RadioStationCarousel::drawOffScreen( QPainter& painter ) |
|
433 { |
|
434 mItems[CenterItem]->drawOffScreen( painter ); |
|
435 } |
|
436 |
|
437 /*! |
|
438 * |
|
439 */ |
|
440 void RadioStationCarousel::setLandscape( bool landscape ) |
|
441 { |
|
442 CALL_TO_ALL_ITEMS( setLandscape( landscape ) ); |
|
443 } |
|
444 |
|
445 /*! |
|
446 * Private slot |
|
447 * |
|
448 */ |
|
449 void RadioStationCarousel::scrollPosChanged( const QPointF& newPosition ) |
|
450 { |
|
451 Q_UNUSED( newPosition ); |
|
452 // const int xPos = static_cast<int>( newPosition.x() ); |
|
453 // mItems[CenterItem]->setPos( xPos - mMidScrollPos, 0 ); |
|
454 } |
|
455 |
|
456 /*! |
|
457 * Private slot |
|
458 '' |
|
459 */ |
|
460 void RadioStationCarousel::adjustAfterScroll() |
|
461 { |
|
462 if ( isInScanningMode() ) { |
|
463 return; |
|
464 } |
|
465 |
|
466 if ( mTargetIndex != -1 ) { |
|
467 setCenterIndex( mTargetIndex ); |
|
468 } |
|
469 } |
|
470 |
|
471 /*! |
|
472 * Private slot |
|
473 * |
|
474 */ |
|
475 void RadioStationCarousel::update( const RadioStation& station ) |
|
476 { |
|
477 if ( !mManualSeekMode && !isInScanningMode() ) { |
|
478 for ( int i = LeftItem; i <= RightItem; ++i ) { |
|
479 if ( mItems[i]->frequency() == station.frequency() ) { |
|
480 mItems[i]->update( &station ); |
|
481 } |
|
482 } |
|
483 } |
|
484 } |
|
485 |
|
486 /*! |
|
487 * Private slot |
|
488 */ |
|
489 void RadioStationCarousel::updateRadioText( const RadioStation& station ) |
|
490 { |
|
491 if ( isAntennaAttached() && !isInScanningMode() ) { |
|
492 if ( station.radioText().isEmpty() ) { |
|
493 mItems[CenterItem]->setRadioText( "" ); |
|
494 } else { |
|
495 mRadioTextHolder = station.radioText(); |
|
496 mTimerMode = RtPlusCheck; |
|
497 mGenericTimer->stop(); |
|
498 mGenericTimer->setInterval( RTPLUS_CHECK_TIMEOUT ); |
|
499 mGenericTimer->start(); |
|
500 } |
|
501 } |
|
502 } |
|
503 |
|
504 /*! |
|
505 * Private slot |
|
506 */ |
|
507 void RadioStationCarousel::updateStations() |
|
508 { |
|
509 if ( isInScanningMode() ) { |
|
510 return; |
|
511 } |
|
512 |
|
513 setFrequency( mUiEngine->currentFrequency(), TuneReason::Unspecified ); |
|
514 } |
|
515 |
|
516 /*! |
|
517 * Private slot |
|
518 */ |
|
519 void RadioStationCarousel::timerFired() |
|
520 { |
|
521 if ( mTimerMode == SetFrequency ) { |
|
522 setCenterIndex( mCurrentIndex, NoSignal | IgnoreCenter ); |
|
523 mTimerMode = NoTimer; |
|
524 } else if ( mTimerMode == RtPlusCheck ) { |
|
525 //mItems[CenterItem]->mRadiotextLabel->setText( mRadioTextHolder ); |
|
526 mRadioTextHolder = ""; |
|
527 mTimerMode = NoTimer; |
|
528 } else if ( mTimerMode == InfoText ) { |
|
529 clearInfoText(); |
|
530 mTimerMode = NoTimer; |
|
531 } else if ( mTimerMode == FavoriteHintShow ) { |
|
532 setInfoText( CarouselInfoText::FavoriteIconHint ); |
|
533 mTimerMode = FavoriteHintHide; |
|
534 mGenericTimer->start( FAVORITE_HINT_HIDE_DELAY ); |
|
535 } else if ( mTimerMode == FavoriteHintHide ) { |
|
536 clearInfoText(); |
|
537 mTimerMode = NoTimer; |
|
538 } |
|
539 } |
|
540 |
|
541 #ifdef USE_DEBUGGING_CONTROLS |
|
542 /*! |
|
543 * Public slot |
|
544 */ |
|
545 void RadioStationCarousel::setRdsAvailable( bool available ) |
|
546 { |
|
547 QColor color = Qt::green; |
|
548 if ( !available && mUiEngine ) { |
|
549 LOG_FORMAT( "No RDS signal: Station has sent RDS earlier: %d", mUiEngine.model().currentStation().hasSentRds() ); |
|
550 color = mUiEngine.model().currentStation().hasSentRds() ? Qt::yellow : Qt::gray; |
|
551 mRdsLabel->setText( "RDS" ); |
|
552 } else { |
|
553 mRdsLabel->setText( "-RDS-" ); |
|
554 } |
|
555 mRdsLabel->setTextColor( color ); |
|
556 } |
|
557 #endif // USE_DEBUGGING_CONTROLS |
|
558 |
|
559 /*! |
|
560 * Public slot |
|
561 */ |
|
562 void RadioStationCarousel::updateAntennaStatus( bool connected ) |
|
563 { |
|
564 mGenericTimer->stop(); |
|
565 |
|
566 if ( !connected ) { |
|
567 setInfoText( CarouselInfoText::ConnectAntenna ); |
|
568 } else { |
|
569 clearInfoText(); |
|
570 } |
|
571 } |
|
572 |
|
573 /*! |
|
574 * \reimp |
|
575 */ |
|
576 void RadioStationCarousel::mousePressEvent( QGraphicsSceneMouseEvent* event ) |
|
577 { |
|
578 if ( mInfoTextType == CarouselInfoText::NoFavorites || mInfoTextType == CarouselInfoText::FavoriteIconHint ) { |
|
579 clearInfoText(); |
|
580 } |
|
581 |
|
582 HbScrollArea::mousePressEvent( event ); |
|
583 } |
|
584 |
|
585 /*! |
|
586 * \reimp |
|
587 */ |
|
588 void RadioStationCarousel::resizeEvent( QGraphicsSceneResizeEvent* event ) |
|
589 { |
|
590 HbScrollArea::resizeEvent( event ); |
|
591 |
|
592 const int width = (int)event->newSize().width(); |
|
593 |
|
594 mMidScrollPos = -width; |
|
595 mMaxScrollPos = mMidScrollPos * 2; |
|
596 |
|
597 if ( isInitialized() ) { |
|
598 mItems[LeftItem]->setMinimumWidth( width ); |
|
599 mItems[CenterItem]->setMinimumWidth( width ); |
|
600 mItems[RightItem]->setMinimumWidth( width ); |
|
601 } |
|
602 } |
|
603 |
|
604 /*! |
|
605 * \reimp |
|
606 */ |
|
607 void RadioStationCarousel::showEvent( QShowEvent* event ) |
|
608 { |
|
609 HbScrollArea::showEvent( event ); |
|
610 // mContainer->setPos( mMidScrollPos, 0 ); |
|
611 } |
|
612 |
|
613 /*! |
|
614 * \reimp |
|
615 */ |
|
616 void RadioStationCarousel::gestureEvent( QGestureEvent* event ) |
|
617 { |
|
618 // if ( HbSwipeGesture* swipeGesture = static_cast<HbSwipeGesture*>( event->gesture( Qt::SwipeGesture ) ) ) { |
|
619 // if ( swipeGesture->state() == Qt::GestureFinished ) { |
|
620 // if ( swipeGesture->horizontalDirection() == QSwipeGesture::Left ) { |
|
621 // emit skipRequested( StationSkip::Next ); |
|
622 // } else if ( swipeGesture->horizontalDirection() == QSwipeGesture::Right ) { |
|
623 // emit skipRequested( StationSkip::Previous ); |
|
624 // } |
|
625 // mIsCustomFreq = false; |
|
626 // } |
|
627 // return; |
|
628 // } |
|
629 |
|
630 HbScrollArea::gestureEvent( event ); |
|
631 |
|
632 if ( HbPanGesture* gesture = qobject_cast<HbPanGesture*>( event->gesture( Qt::PanGesture ) ) ) { |
|
633 if ( gesture->state() == Qt::GestureFinished ) { |
|
634 adjustPos( (int)gesture->offset().x() ); |
|
635 } |
|
636 } |
|
637 } |
|
638 |
|
639 /*! |
|
640 * \reimp |
|
641 */ |
|
642 void RadioStationCarousel::handleIconClicked( const RadioStation& station ) |
|
643 { |
|
644 if ( mModel ) { |
|
645 mModel->setData( QModelIndex(), station.frequency(), RadioRole::ToggleFavoriteRole ); |
|
646 } |
|
647 } |
|
648 |
|
649 /*! |
|
650 * \reimp |
|
651 */ |
|
652 void RadioStationCarousel::handleRadiotextClicked( const RadioStation& station ) |
|
653 { |
|
654 Q_UNUSED( station ); |
|
655 mRadiotextPopup->show(); |
|
656 } |
|
657 |
|
658 /*! |
|
659 * \reimp |
|
660 */ |
|
661 void RadioStationCarousel::handleUrlClicked( const RadioStation& station ) |
|
662 { |
|
663 mUiEngine->launchBrowser( station.url() ); |
|
664 } |
|
665 |
|
666 /*! |
|
667 * \reimp |
|
668 */ |
|
669 QString RadioStationCarousel::localizeGenre( int genre ) |
|
670 { |
|
671 return mUiEngine->genreToString( genre, GenreTarget::Carousel ); |
|
672 } |
|
673 |
|
674 /*! |
|
675 * \reimp |
|
676 */ |
|
677 bool RadioStationCarousel::isInManualSeek() const |
|
678 { |
|
679 return mManualSeekMode; |
|
680 } |
|
681 |
|
682 /*! |
|
683 * |
|
684 */ |
|
685 RadioStation RadioStationCarousel::findStation( uint frequency ) |
|
686 { |
|
687 return mModel->findStation( frequency, FindCriteria::IncludeManualStation ); |
|
688 } |
|
689 |
|
690 /*! |
|
691 * |
|
692 */ |
|
693 bool RadioStationCarousel::isInitialized() const |
|
694 { |
|
695 return mUiEngine != NULL; |
|
696 } |
|
697 |
|
698 /*! |
|
699 * |
|
700 */ |
|
701 void RadioStationCarousel::setCenterIndex( int index, ScrollMode mode ) |
|
702 { |
|
703 Q_UNUSED( mode ); |
|
704 if ( mModel ) { |
|
705 const int newIndex = trimIndex( index ); |
|
706 mCurrentIndex = newIndex; |
|
707 mTargetIndex = -1; |
|
708 |
|
709 if ( !mIsCustomFreq ) { |
|
710 mItems[CenterItem]->setStation( mModel->stationAt( mCurrentIndex ) ); |
|
711 } |
|
712 |
|
713 if ( mModel->rowCount() > 1 ) { |
|
714 const int leftIndex = prevIndex( mCurrentIndex ); |
|
715 const int rightIndex = nextIndex( mCurrentIndex ); |
|
716 mItems[LeftItem]->setStation( mModel->stationAt( leftIndex ) ); |
|
717 mItems[RightItem]->setStation( mModel->stationAt( rightIndex ) ); |
|
718 } else { |
|
719 |
|
720 if ( mIsCustomFreq ) { |
|
721 const uint frequency = mItems[CenterItem]->frequency(); |
|
722 mItems[LeftItem]->setStation( mModel->findClosest( frequency, StationSkip::Previous ) ); |
|
723 mItems[RightItem]->setStation( mModel->findClosest( frequency, StationSkip::Next ) ); |
|
724 } else { |
|
725 mItems[LeftItem]->setStation( RadioStation() ); |
|
726 mItems[RightItem]->setStation( RadioStation() ); |
|
727 } |
|
728 } |
|
729 |
|
730 scrollContentsTo( QPointF( -mMidScrollPos /* + delta */, 0 ), 0 ); |
|
731 |
|
732 // if ( !mode.testFlag( NoSignal ) ) { |
|
733 // uint frequency = mModel->stationAt( mCurrentIndex ).frequency(); |
|
734 // emit frequencyChanged( frequency, TuneReason::StationCarousel, mScrollDirection ); |
|
735 // mScrollDirection = Scroll::Shortest; |
|
736 // } |
|
737 } |
|
738 } |
|
739 |
|
740 /*! |
|
741 * |
|
742 */ |
|
743 void RadioStationCarousel::scrollToIndex( int index, Scroll::Direction direction, ScrollMode mode ) |
|
744 { |
|
745 if ( mModel && index >= 0 ) { |
|
746 mTargetIndex = index; |
|
747 const int difference = calculateDifference( index, direction ); |
|
748 int scrollTime = mAutoScrollTime; |
|
749 |
|
750 int posX = direction == Scroll::Left ? -mMaxScrollPos : 0; |
|
751 if ( difference == 1 ) { |
|
752 if ( direction == Scroll::Right ) { |
|
753 posX = 0; |
|
754 } else if ( direction == Scroll::Left ) { |
|
755 posX = -mMaxScrollPos; |
|
756 } |
|
757 } else { |
|
758 if ( direction == Scroll::Right ) { |
|
759 // Item where the scrolling starts |
|
760 mItems[RightItem]->setStation( mModel->stationAt( mCurrentIndex ) ); |
|
761 |
|
762 // Item that is skipped over |
|
763 const uint centerFreq = mModel->stationAt( nextIndex( index ) ).frequency(); |
|
764 mItems[CenterItem]->setFrequency( centerFreq ); |
|
765 |
|
766 // Item where the scrolling ends |
|
767 const RadioStation station = mModel->stationAt( index ); |
|
768 mItems[LeftItem]->setStation( station ); |
|
769 |
|
770 mContainer->setPos( mMaxScrollPos, 0 ); |
|
771 posX = 0; |
|
772 } else if ( direction == Scroll::Left ) { |
|
773 // Item where the scrolling starts |
|
774 mItems[LeftItem]->setStation( mModel->stationAt( mCurrentIndex ) ); |
|
775 |
|
776 // Item that is skipped over |
|
777 const uint centerFreq = mModel->stationAt( prevIndex( index ) ).frequency(); |
|
778 mItems[CenterItem]->setFrequency( centerFreq ); |
|
779 |
|
780 // Item where the scrolling ends |
|
781 const RadioStation station = mModel->stationAt( index ); |
|
782 mItems[RightItem]->setStation( station ); |
|
783 |
|
784 mContainer->setPos( 0, 0 ); |
|
785 posX = -mMaxScrollPos; |
|
786 } |
|
787 } |
|
788 |
|
789 if ( mode.testFlag( UpdateItem ) ) { |
|
790 //item->update(); |
|
791 } |
|
792 |
|
793 if ( mode.testFlag( NoAnim ) ) { |
|
794 scrollTime = 0; |
|
795 } else if ( mode.testFlag( FromPanGesture ) ) { |
|
796 scrollTime = 500; |
|
797 } else if ( mode.testFlag( FromSwipeGesture ) ) { |
|
798 scrollTime = 100; |
|
799 } |
|
800 |
|
801 scrollContentsTo( QPointF( posX, 0 ), scrollTime ); |
|
802 } |
|
803 } |
|
804 |
|
805 /*! |
|
806 * |
|
807 */ |
|
808 int RadioStationCarousel::calculateDifference( int targetIndex, Scroll::Direction& direction ) |
|
809 { |
|
810 int difference = 0; |
|
811 const int rowCount = mModel->rowCount(); |
|
812 |
|
813 int diffToLeft = 0; |
|
814 int diffToRight = 0; |
|
815 if ( targetIndex > mCurrentIndex ) { |
|
816 const int loopedDiff = mCurrentIndex + rowCount - targetIndex; |
|
817 const int directDiff = targetIndex - mCurrentIndex; |
|
818 diffToLeft = loopedDiff; |
|
819 diffToRight = directDiff; |
|
820 } else { |
|
821 const int loopedDiff = targetIndex + rowCount - mCurrentIndex; |
|
822 const int directDiff = mIsCustomFreq ? 1 : mCurrentIndex - targetIndex; |
|
823 diffToLeft = directDiff; |
|
824 diffToRight = loopedDiff; |
|
825 } |
|
826 |
|
827 if ( direction == Scroll::Right ) { |
|
828 difference = diffToLeft; |
|
829 } else if ( direction == Scroll::Left ) { |
|
830 difference = diffToRight; |
|
831 } else { |
|
832 if ( diffToLeft < diffToRight ) { |
|
833 difference = diffToLeft; |
|
834 direction = Scroll::Right; |
|
835 } else { |
|
836 difference = diffToRight; |
|
837 direction = Scroll::Left; |
|
838 } |
|
839 } |
|
840 |
|
841 return difference; |
|
842 } |
|
843 |
|
844 /*! |
|
845 * |
|
846 */ |
|
847 bool RadioStationCarousel::isScrollingAllowed() const |
|
848 { |
|
849 const int rowCount = mModel->rowCount(); |
|
850 return rowCount > 1 || ( rowCount == 1 && mIsCustomFreq ); |
|
851 } |
|
852 |
|
853 /*! |
|
854 * |
|
855 */ |
|
856 void RadioStationCarousel::adjustPos( int offset ) |
|
857 { |
|
858 int newPos = mMidScrollPos; |
|
859 const int threshold = (int)size().width() / 5; |
|
860 int newIndex = mCurrentIndex; |
|
861 bool needsToScroll = false; |
|
862 |
|
863 if ( isScrollingAllowed() && abs( offset ) >= threshold ) { |
|
864 needsToScroll = true; |
|
865 if ( offset > 0 ) { |
|
866 newPos = 0; |
|
867 mScrollDirection = Scroll::Right; |
|
868 if ( !mIsCustomFreq ) { |
|
869 const uint newFreq = mModel->findClosest( mItems[CenterItem]->frequency(), StationSkip::PreviousFavorite ).frequency(); |
|
870 if ( newFreq > 0 ) { |
|
871 newIndex = mModel->indexFromFrequency( newFreq ); |
|
872 } else { |
|
873 needsToScroll = false; |
|
874 newPos = mMidScrollPos; |
|
875 } |
|
876 } |
|
877 } else { |
|
878 mScrollDirection = Scroll::Left; |
|
879 newPos = mMaxScrollPos; |
|
880 |
|
881 const uint newFreq = mModel->findClosest( mItems[CenterItem]->frequency(), StationSkip::NextFavorite ).frequency(); |
|
882 if ( newFreq > 0 ) { |
|
883 newIndex = mModel->indexFromFrequency( newFreq ); |
|
884 } else { |
|
885 needsToScroll = false; |
|
886 newPos = mMidScrollPos; |
|
887 } |
|
888 } |
|
889 } |
|
890 |
|
891 newIndex = trimIndex( newIndex ); |
|
892 if ( needsToScroll ) { |
|
893 const uint frequency = mModel->stationAt( newIndex ).frequency(); |
|
894 emit frequencyChanged( frequency, TuneReason::StationCarousel, mScrollDirection ); |
|
895 scrollToIndex( newIndex, mScrollDirection, RadioStationCarousel::FromPanGesture ); |
|
896 mIsCustomFreq = false; |
|
897 } else { |
|
898 scrollContentsTo( QPointF( -newPos, 0 ), 300 ); |
|
899 } |
|
900 } |
|
901 |
|
902 /*! |
|
903 * |
|
904 */ |
|
905 int RadioStationCarousel::trimIndex( int index ) |
|
906 { |
|
907 const int count = mModel ? mModel->rowCount() : 0; |
|
908 |
|
909 if ( count == 0 ) { |
|
910 return -1; |
|
911 } |
|
912 |
|
913 if ( index < 0 ) { |
|
914 index = count - 1; |
|
915 } |
|
916 index %= count; |
|
917 return index; |
|
918 } |
|
919 |
|
920 /*! |
|
921 * |
|
922 */ |
|
923 int RadioStationCarousel::prevIndex( int index ) |
|
924 { |
|
925 if ( !mIsCustomFreq ) { |
|
926 --index; |
|
927 } |
|
928 return trimIndex( index ); |
|
929 } |
|
930 |
|
931 /*! |
|
932 * |
|
933 */ |
|
934 int RadioStationCarousel::nextIndex( int index ) |
|
935 { |
|
936 return trimIndex( index + 1 ); |
|
937 } |
|
938 |
|
939 /*! |
|
940 * |
|
941 */ |
|
942 void RadioStationCarousel::skip( StationSkip::Mode mode ) |
|
943 { |
|
944 if ( mModel ) { |
|
945 const uint frequency = mModel->findClosest( mItems[CenterItem]->frequency(), mode ).frequency(); |
|
946 const int index = mModel->indexFromFrequency( frequency ); |
|
947 const Scroll::Direction direction = RadioUtil::scrollDirectionFromSkipMode( mode ); |
|
948 scrollToIndex( index, direction, RadioStationCarousel::NoSignal ); |
|
949 } |
|
950 } |
|