|
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: Music Player Settings view. |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <QParallelAnimationGroup> |
|
19 #include <QPropertyAnimation> |
|
20 |
|
21 #include <hbicon.h> |
|
22 #include <hbaction.h> |
|
23 #include <hbapplication.h> |
|
24 #include <hbscrollbar.h> |
|
25 #include <hblabel.h> |
|
26 #include <hbpushbutton.h> |
|
27 #include <hbtoolbutton.h> |
|
28 |
|
29 #include <hgmediawall.h> |
|
30 |
|
31 #include "mpmediawallview.h" |
|
32 #include "mpmediawalldocumentloader.h" |
|
33 #include "mpcommondefs.h" |
|
34 #include "mpmpxcollectiondata.h" |
|
35 #include "mpcollectiondatamodel.h" |
|
36 #include "mpenginefactory.h" |
|
37 #include "mpplaybackdata.h" |
|
38 #include "mpalbumcoverwidget.h" |
|
39 #include "mptracklistwidget.h" |
|
40 #include "mpcollectiontbonelistdatamodel.h" |
|
41 #include "mptrace.h" |
|
42 |
|
43 const char*MUSIC_MEDIAWALL_DOCML = ":/mediawallviewdocml/mediawall.docml"; |
|
44 |
|
45 /*! |
|
46 \class MpMediaWallView |
|
47 \brief Music Player Settings view. |
|
48 |
|
49 Music player media wall view displays music players albums on an full screen view |
|
50 */ |
|
51 |
|
52 /*! |
|
53 \fn void command( int command ) |
|
54 |
|
55 This signal is emitted when the view issues a \a command to the |
|
56 application such as request to switch to a different view. |
|
57 */ |
|
58 |
|
59 |
|
60 /*! |
|
61 Constructs the media wall view. |
|
62 */ |
|
63 MpMediaWallView::MpMediaWallView() |
|
64 : mEngine( 0 ), |
|
65 mCollectionData( 0 ), |
|
66 mModel( 0 ), |
|
67 mMediaWallWidget( 0 ), |
|
68 mNoMusic( 0 ), |
|
69 mDocumentLoader( 0 ), |
|
70 mPlayPauseContainer( 0 ), |
|
71 mPlayIcon( 0 ), |
|
72 mPauseIcon( 0 ), |
|
73 mPlayPauseAction( 0 ), |
|
74 mLibraryUpdating( false ), |
|
75 mPlaybackData( 0 ), |
|
76 mActivated( false ), |
|
77 mIconUpdateNedded( false ), |
|
78 mListShowAnimationGroup( 0 ), |
|
79 mListShowListAnimation( 0 ), |
|
80 mCoverShowListAnimation( 0 ), |
|
81 mShowingSongsList( false ), |
|
82 mAlbumCover( 0 ), |
|
83 mTrackList( 0 ) |
|
84 { |
|
85 connect( MpEngineFactory::sharedEngine(), SIGNAL( libraryAboutToUpdate() ), |
|
86 this, SLOT( libraryAboutToUpdate() ) ); |
|
87 connect( MpEngineFactory::sharedEngine(), SIGNAL( libraryUpdated() ), |
|
88 this, SLOT( libraryUpdated() ) ); |
|
89 TX_LOG |
|
90 } |
|
91 |
|
92 /*! |
|
93 Destructs the media wall view. |
|
94 */ |
|
95 MpMediaWallView::~MpMediaWallView() |
|
96 { |
|
97 TX_ENTRY |
|
98 //delete not parented objects |
|
99 delete mDocumentLoader; |
|
100 delete mPlayIcon; |
|
101 delete mPauseIcon; |
|
102 TX_EXIT |
|
103 } |
|
104 |
|
105 /*! |
|
106 Initializes the media wall view. |
|
107 */ |
|
108 void MpMediaWallView::initializeView() |
|
109 { |
|
110 TX_ENTRY |
|
111 setTitleBarVisible( false ); |
|
112 setStatusBarVisible( false ); |
|
113 |
|
114 mDocumentLoader = new MpMediaWallDocumentLoader(); |
|
115 bool ok = false; |
|
116 mDocumentLoader->load( MUSIC_MEDIAWALL_DOCML, &ok ); |
|
117 if ( ok ) { |
|
118 QGraphicsWidget *widget; |
|
119 |
|
120 //Setup fake softkey to hide the app |
|
121 widget = mDocumentLoader->findWidget( QString( "navigationButton" ) ); |
|
122 HbAction *action; |
|
123 action = new HbAction( Hb::BackNaviAction, this ); |
|
124 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( sendToBackground() ) ); |
|
125 qobject_cast<HbToolButton*>( widget )->setAction( action ); |
|
126 |
|
127 //Setup the play/pause command button |
|
128 widget = mDocumentLoader->findWidget( QString( "playPauseButton" ) ); |
|
129 mPauseIcon = new HbIcon( "qtg_mono_pause" ); |
|
130 mPlayIcon = new HbIcon( "qtg_mono_play" ); |
|
131 mPlayPauseAction = new HbAction( HbIcon() , QString(), this ); |
|
132 mPlaybackData = MpEngineFactory::sharedEngine()->playbackData(); |
|
133 qobject_cast<HbToolButton*>( widget )->setAction( mPlayPauseAction ); |
|
134 //we need this widget to hide the play pause button, for soem reaosn it does not want to hide. |
|
135 mPlayPauseContainer = mDocumentLoader->findWidget( QString( "playPauseButtonContainer" ) ); |
|
136 updatePlayPauseAction(); |
|
137 connect( mPlaybackData, SIGNAL( playbackStateChanged() ), |
|
138 this, SLOT( updatePlayPauseAction() ) ); |
|
139 connect( mPlayPauseAction, SIGNAL( triggered( bool ) ), |
|
140 MpEngineFactory::sharedEngine(), SLOT( playPause() ) ); |
|
141 |
|
142 |
|
143 //Get the main container and set as widget. |
|
144 widget = mDocumentLoader->findWidget( QString( "container" ) ); |
|
145 setWidget( widget ); |
|
146 |
|
147 mEngine = MpEngineFactory::createIsolatedEngine( MpEngine::MediaBrowsing ); |
|
148 mCollectionData = mEngine->collectionData(); |
|
149 mModel = new MpCollectionDataModel( mCollectionData, this ); |
|
150 |
|
151 connect( mCollectionData, SIGNAL( contextChanged( TCollectionContext ) ), |
|
152 this, SLOT( contextOpened( TCollectionContext ) ) ); |
|
153 connect( mEngine, SIGNAL( containerContentsChanged() ), |
|
154 this, SLOT( containerContentsChanged() ) ); |
|
155 if ( !mLibraryUpdating ) { |
|
156 mEngine->openCollection( ECollectionContextAlbumsMediaWall ); |
|
157 } |
|
158 } |
|
159 else { |
|
160 TX_LOG_ARGS( "Error: invalid xml file." ); |
|
161 Q_ASSERT_X( ok, "MpCollectionView::initializeView", "invalid xml file" ); |
|
162 } |
|
163 |
|
164 mAlbumCover = new MpAlbumCoverWidget( this ); |
|
165 mAlbumCover->setDefaultIcon( HbIcon( "qtg_large_music_album" ) ); |
|
166 mAlbumCover->hide(); |
|
167 |
|
168 mTrackList = new MpTrackListWidget( this ); |
|
169 mTrackList->list()->setModel( new MpCollectionTBoneListDataModel(mCollectionData, mTrackList ) ); |
|
170 mTrackList->hide(); |
|
171 |
|
172 connect(mAlbumCover,SIGNAL(clicked()),this, SLOT(hideTracksList())); |
|
173 connect(mTrackList->list(), SIGNAL(activated(QModelIndex)), this, SLOT(listItemActivated(QModelIndex))); |
|
174 connect(mTrackList,SIGNAL(close()),this, SLOT(hideTracksList())); |
|
175 |
|
176 |
|
177 |
|
178 TX_EXIT |
|
179 } |
|
180 |
|
181 /*! |
|
182 Activates the media wall view. |
|
183 */ |
|
184 void MpMediaWallView::activateView() |
|
185 { |
|
186 TX_ENTRY |
|
187 mActivated = true; |
|
188 if ( mIconUpdateNedded ) { |
|
189 updatePlayPauseAction(); |
|
190 mIconUpdateNedded = false; |
|
191 } |
|
192 scrollToNowPlaying(); |
|
193 TX_EXIT |
|
194 } |
|
195 |
|
196 /*! |
|
197 Deactivates the media wall view. |
|
198 */ |
|
199 void MpMediaWallView::deactivateView() |
|
200 { |
|
201 TX_ENTRY |
|
202 mActivated = false; |
|
203 dismissListClosingAnimation(); |
|
204 TX_EXIT |
|
205 } |
|
206 |
|
207 /*! |
|
208 Slot to be called when the context is opened. |
|
209 */ |
|
210 void MpMediaWallView::contextOpened( TCollectionContext context ) |
|
211 { |
|
212 if ( context != ECollectionContextAlbumsMediaWall ) { |
|
213 //Force the context to Albums Media Wall, this to get the model and |
|
214 //data to provide the right funtionality to media wall. |
|
215 mCollectionData->setContext( ECollectionContextAlbumsMediaWall ); |
|
216 return; |
|
217 } |
|
218 if ( mCollectionData->count() ) { |
|
219 if (mNoMusic) { |
|
220 delete mNoMusic; |
|
221 mNoMusic = 0; |
|
222 } |
|
223 if ( mMediaWallWidget ) { |
|
224 mModel->refreshModel(); |
|
225 } else { |
|
226 bool ok = false; |
|
227 mDocumentLoader->load( MUSIC_MEDIAWALL_DOCML, "mediaWall", &ok); |
|
228 if ( ok ) { |
|
229 QGraphicsWidget *widget; |
|
230 widget = mDocumentLoader->findWidget(QString("mediaWallWidget")); |
|
231 mMediaWallWidget = qobject_cast<HgMediawall*>(widget); |
|
232 mModel->refreshModel(); |
|
233 setUpMediaWallWidget(); |
|
234 } |
|
235 else { |
|
236 TX_LOG_ARGS("Error: invalid xml file."); |
|
237 Q_ASSERT_X(ok, "MpMediaWallView::contextOpened", "invalid xml file"); |
|
238 |
|
239 } |
|
240 } |
|
241 } |
|
242 else { |
|
243 if ( mMediaWallWidget ) { |
|
244 delete mMediaWallWidget; |
|
245 mMediaWallWidget = 0; |
|
246 |
|
247 } |
|
248 if ( !mNoMusic ) { |
|
249 bool ok = false; |
|
250 mDocumentLoader->load( MUSIC_MEDIAWALL_DOCML, "empty", &ok); |
|
251 if ( ok ) { |
|
252 QGraphicsWidget *widget; |
|
253 widget = mDocumentLoader->findWidget(QString("noMusic")); |
|
254 mNoMusic = qobject_cast<HbLabel*>(widget); |
|
255 } |
|
256 else { |
|
257 TX_LOG_ARGS("Error: invalid xml file."); |
|
258 Q_ASSERT_X(ok, "MpMediaWallView::contextOpened", "invalid xml file"); |
|
259 |
|
260 } |
|
261 } |
|
262 } |
|
263 } |
|
264 |
|
265 /*! |
|
266 Slot to be called when the container contents changed. |
|
267 */ |
|
268 void MpMediaWallView::containerContentsChanged() |
|
269 { |
|
270 if ( !mLibraryUpdating && mEngine ) { |
|
271 mEngine->openCollection( ECollectionContextAlbumsMediaWall ); |
|
272 } |
|
273 } |
|
274 |
|
275 /*! |
|
276 Slot to be called when the container contents changed. |
|
277 */ |
|
278 void MpMediaWallView::libraryAboutToUpdate() |
|
279 { |
|
280 mLibraryUpdating = true; |
|
281 } |
|
282 |
|
283 /*! |
|
284 Slot to be called when the container contents changed. |
|
285 */ |
|
286 void MpMediaWallView::libraryUpdated() |
|
287 { |
|
288 mLibraryUpdating = false; |
|
289 if ( mEngine ) { |
|
290 mEngine->openCollection( ECollectionContextAlbumsMediaWall ); |
|
291 } |
|
292 } |
|
293 |
|
294 /*! |
|
295 Slot to be called to send to background. |
|
296 */ |
|
297 void MpMediaWallView::sendToBackground() |
|
298 { |
|
299 TX_ENTRY |
|
300 emit command( MpCommon::SendToBackground ); |
|
301 TX_EXIT |
|
302 } |
|
303 |
|
304 /*! |
|
305 Slot to update teh play pause action icon. |
|
306 */ |
|
307 void MpMediaWallView::updatePlayPauseAction() |
|
308 { |
|
309 if ( !mActivated ) { |
|
310 mIconUpdateNedded = true; |
|
311 return; |
|
312 } |
|
313 TX_ENTRY |
|
314 switch ( mPlaybackData->playbackState() ) { |
|
315 case MpPlaybackData::Playing: |
|
316 TX_LOG_ARGS( "MpPlaybackData::Playing" ) |
|
317 mPlayPauseAction->setIcon( *mPauseIcon ); |
|
318 mPlayPauseContainer->show(); |
|
319 break; |
|
320 case MpPlaybackData::Paused: |
|
321 case MpPlaybackData::Stopped: |
|
322 TX_LOG_ARGS( "MpPlaybackData::Paused" ) |
|
323 mPlayPauseAction->setIcon( *mPlayIcon ); |
|
324 mPlayPauseContainer->show(); |
|
325 break; |
|
326 case MpPlaybackData::NotPlaying: |
|
327 mPlayPauseContainer->hide(); |
|
328 break; |
|
329 default: |
|
330 break; |
|
331 } |
|
332 TX_EXIT |
|
333 } |
|
334 |
|
335 /*! |
|
336 Slot called to start the album and list opening animation. |
|
337 */ |
|
338 void MpMediaWallView::showTrackList() |
|
339 { |
|
340 if( mShowingSongsList ) { |
|
341 return; |
|
342 } |
|
343 mShowingSongsList = true; |
|
344 setUpListAnimation(); |
|
345 mListShowAnimationGroup->setDirection(QAbstractAnimation::Forward); |
|
346 mListShowAnimationGroup->start(); |
|
347 } |
|
348 |
|
349 /*! |
|
350 Slot to be called to starts the album and list closing animation. |
|
351 */ |
|
352 void MpMediaWallView::hideTracksList() |
|
353 { |
|
354 mListShowAnimationGroup->setDirection(QAbstractAnimation::Backward); |
|
355 connect(mListShowAnimationGroup, SIGNAL(finished()), this, SLOT(dismissListClosingAnimation())); |
|
356 mListShowAnimationGroup->start(); |
|
357 } |
|
358 |
|
359 /*! |
|
360 Slot to be called when list closing animation is done or when we want to cancel the animation. |
|
361 */ |
|
362 void MpMediaWallView::dismissListClosingAnimation() |
|
363 { |
|
364 if ( !mShowingSongsList ) { |
|
365 return; |
|
366 } |
|
367 mShowingSongsList = false; |
|
368 mAlbumCover->hide(); |
|
369 mTrackList->hide(); |
|
370 mListShowAnimationGroup->stop(); |
|
371 disconnect(mListShowAnimationGroup, SIGNAL(finished()), this, SLOT(dismissListClosingAnimation())); |
|
372 } |
|
373 |
|
374 /*! |
|
375 Slot to be called when a list item is selected by the user. |
|
376 */ |
|
377 void MpMediaWallView::listItemActivated( const QModelIndex &index ) |
|
378 { |
|
379 int albumIndex = mMediaWallWidget->currentIndex().row(); |
|
380 //We are playing on the shared engine, but we pass the collection data that |
|
381 //points to albums on media wall, this is used to construct the playlist. |
|
382 MpEngineFactory::sharedEngine()->playAlbumSongs( albumIndex, index.row(), mCollectionData ); |
|
383 } |
|
384 |
|
385 /*! |
|
386 Loads the media wall widget. |
|
387 */ |
|
388 void MpMediaWallView::setUpMediaWallWidget() |
|
389 { |
|
390 HbIcon defaultIcon( "qtg_large_music_album" ); |
|
391 defaultIcon.setSize(mMediaWallWidget->itemSize()); |
|
392 mMediaWallWidget->setDefaultImage( defaultIcon.pixmap().toImage() ); |
|
393 mMediaWallWidget->enableReflections( false ); |
|
394 mMediaWallWidget->setModel( mModel ); |
|
395 if ( mPlaybackData->playbackState() != MpPlaybackData::NotPlaying ) { |
|
396 scrollToNowPlaying(); |
|
397 } |
|
398 //The rest of the cases are attepting to balance the items on screen. |
|
399 else if ( mModel->rowCount() >= 5 ) { |
|
400 /* 5 and more |
|
401 [0] [1] [X] [3] [4]... |
|
402 */ |
|
403 QModelIndex index; |
|
404 index = mModel->index( 2 ); |
|
405 mMediaWallWidget->scrollTo( index ); |
|
406 } |
|
407 else if ( mModel->rowCount() >=3 ) { |
|
408 /* 4 and 3 |
|
409 __ [0] [X] [2] [3] |
|
410 __ [0] [X] [2] __ |
|
411 */ |
|
412 QModelIndex index; |
|
413 index = mModel->index( 1 ); |
|
414 mMediaWallWidget->scrollTo( index ); |
|
415 } |
|
416 else { |
|
417 /* 2 and 1 |
|
418 __ __ [X] [1] __ |
|
419 __ __ [X] __ __ |
|
420 */ |
|
421 QModelIndex index; |
|
422 index = mModel->index( 0 ); |
|
423 mMediaWallWidget->scrollTo( index ); |
|
424 } |
|
425 mMediaWallWidget->setTitleFontSpec( HbFontSpec( HbFontSpec::Primary ) ); |
|
426 mMediaWallWidget->setDescriptionFontSpec( HbFontSpec( HbFontSpec::Secondary ) ); |
|
427 mMediaWallWidget->setScrollBarPolicy( HgWidget::ScrollBarAlwaysOn ); //HgWidget::ScrollBarAutoHide |
|
428 mMediaWallWidget->scrollBar()->setInteractive( true ); |
|
429 mMediaWallWidget->setIndexFeedbackPolicy( HgWidget::IndexFeedbackSingleCharacter ); |
|
430 connect(mMediaWallWidget, SIGNAL(activated(QModelIndex)), SLOT(showTrackList())); |
|
431 connect(mMediaWallWidget, SIGNAL(scrollingStarted()), SLOT(dismissListClosingAnimation())); |
|
432 } |
|
433 |
|
434 /*! |
|
435 Scrolls the media wall to now playing position. |
|
436 */ |
|
437 void MpMediaWallView::scrollToNowPlaying() |
|
438 { |
|
439 if ( mMediaWallWidget && mPlaybackData->playbackState() != MpPlaybackData::NotPlaying ) { |
|
440 int albumId = mPlaybackData->albumId(); |
|
441 QModelIndex index; |
|
442 index = mModel->index( mCollectionData->itemIndex( albumId ) ); |
|
443 mMediaWallWidget->scrollTo( index ); |
|
444 } |
|
445 } |
|
446 |
|
447 /*! |
|
448 Sets up the album and list animation. |
|
449 */ |
|
450 void MpMediaWallView::setUpListAnimation() |
|
451 { |
|
452 if ( !mListShowAnimationGroup ) { |
|
453 mListShowAnimationGroup = new QParallelAnimationGroup( this ); |
|
454 mCoverShowListAnimation = new QPropertyAnimation(mAlbumCover, "geometry", this ); |
|
455 mCoverShowListAnimation->setDuration( 400 ); |
|
456 mCoverShowListAnimation->setEasingCurve(QEasingCurve::InOutCubic); |
|
457 mListShowAnimationGroup->addAnimation(mCoverShowListAnimation); |
|
458 mListShowListAnimation = new QPropertyAnimation( mTrackList, "geometry", this ); |
|
459 mListShowListAnimation->setDuration( 400 ); |
|
460 mListShowListAnimation->setEasingCurve(QEasingCurve::InOutCubic); |
|
461 mListShowAnimationGroup->addAnimation(mListShowListAnimation); |
|
462 //track list goes on top of media wall. |
|
463 mTrackList->setZValue(mMediaWallWidget->zValue()+1); |
|
464 //album cover goes on top of track list. |
|
465 mAlbumCover->setZValue(mMediaWallWidget->zValue()+2); |
|
466 } |
|
467 |
|
468 //Get the current album cover geometry. |
|
469 QPolygonF poly; |
|
470 QModelIndex index = mMediaWallWidget->currentIndex(); |
|
471 if ( !mMediaWallWidget->getItemOutline( index, poly ) ) { |
|
472 return; |
|
473 } |
|
474 QRectF itemRect = poly.boundingRect(); |
|
475 |
|
476 //Request the albums tracks, they are set to the track list model. |
|
477 if ( !mCollectionData->setCurrentAlbum( index.row() ) ) { |
|
478 mEngine->findAlbumSongs( index.row() ); |
|
479 } |
|
480 |
|
481 //Get the album cover icon. |
|
482 QVariant image = mModel->data(index, Qt::DecorationRole); |
|
483 if ( image.canConvert<HbIcon>() ) { |
|
484 mAlbumCover->setIcon(image.value<HbIcon>()); |
|
485 } |
|
486 else { |
|
487 mAlbumCover->setIcon(HbIcon()); |
|
488 } |
|
489 |
|
490 //Mapping form local media wall coords to window coors. |
|
491 itemRect.moveTo( mMediaWallWidget->geometry().topLeft() + itemRect.topLeft()); |
|
492 //Calculate start and end position of items for the animation. |
|
493 QRectF endRect = itemRect; |
|
494 endRect.moveTo( endRect.topLeft().x() - endRect.size().width() / 2.0, endRect.topLeft().y() ); |
|
495 mCoverShowListAnimation->setStartValue(itemRect); |
|
496 mCoverShowListAnimation->setEndValue(endRect); |
|
497 endRect.moveTo(endRect.topRight() - QPointF(1,0)); //adjust by one pixel to prevent a gap. |
|
498 mListShowListAnimation->setStartValue(itemRect); |
|
499 mListShowListAnimation->setEndValue(endRect); |
|
500 |
|
501 //set initial condition and show to prevent flicker. |
|
502 mAlbumCover->setPos(itemRect.topLeft()); |
|
503 mTrackList->setPos(itemRect.topLeft()); |
|
504 mTrackList->setGeometry(itemRect); |
|
505 mAlbumCover->show(); |
|
506 mTrackList->show(); |
|
507 } |
|
508 |