diff -r 2a40e88564c8 -r 4e84c994a771 mpviewplugins/mpcollectionviewplugin/src/mpcollectionview.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mpviewplugins/mpcollectionviewplugin/src/mpcollectionview.cpp Fri Mar 19 09:28:13 2010 +0200 @@ -0,0 +1,1231 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Music Player collection view. +* +*/ + +// INCLUDE FILES +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpcollectionview.h" +#include "mpcollectiondocumentloader.h" +#include "mpcollectioncontainerfactory.h" +#include "mpcollectioncontainer.h" +#include "mpcollectiondatamodel.h" +#include "mpcollectionsongscanner.h" +#include "mpmpxframeworkwrapper.h" +#include "mpmpxcollectiondata.h" +#include "mpnowplayingwidget.h" +#include "mpcommondefs.h" +#include "mptrace.h" +#include "mpsnapshotwidget.h" +#include "mpsettingsmanager.h" + + +const char*MUSIC_COLLECTION_DOCML = ":/docml/musiccollection.docml"; +const char*EFFECT_SELECT = ":/effects/select.fxml"; +const char*EFFECT_SELECT_END = ":/effects/select_end.fxml"; + +const int KMainToolBarAll = 0; +const int KMainToolBarArtists = 1; +const int KMainToolBarPlaylists = 2; + +//const int KPlaylistToolBarAdd = 0; +const int KPlaylistToolBarRemove = 1; +const int KplaylistToolBarReorder = 2; + + + +/*! + \class MpCollectionView + \brief Music Player collection view. + + Collection view provides access to music collection in the device. + This class owns the menu and the toolbar. In addition, it is + responsible for creating UI containers and the underlying engine + components and connecting them to work together. +*/ + +/*! + \fn void command( int command ) + + This signal is emitted when the view issues a \a command to the + application such as request to switch to a different view. + */ + +/*! + Constructs the collection view. + */ +MpCollectionView::MpCollectionView() + : mCollectionContext(ECollectionContextUnknown), + mMpxWrapper(0), + mContainerFactory(0), + mCollectionContainer(0), + mCollectionDataModel(0), + mActivated(false), + mNowPlayingBanner(0), + mBannerAttached(false), + mEffectOnGoing(false), + mDocumentLoader(0), + mMainContainer(0), + mMainToolBar(0), + mPlaylistToolBar(0), + mSnapshot(0), + mSongScanner(0), + mScanning(false) +{ + TX_LOG +} + +/*! + Destructs the collection view. + */ +MpCollectionView::~MpCollectionView() +{ + TX_ENTRY + delete mSongScanner; + delete mSnapshot; + delete mSoftKeyQuit; + delete mSoftKeyBack; + + HbToolBar *toolBar = takeToolBar(); + if ( mMainToolBar != toolBar && mPlaylistToolBar != toolBar ) { + delete toolBar; + } + if ( mMainToolBar) { + mMainToolBar->deleteLater(); + } + if ( mPlaylistToolBar ) { + mPlaylistToolBar->deleteLater(); + } + + delete mCollectionDataModel; + delete mCollectionContainer; + delete mContainerFactory; + delete mMpxWrapper; + delete mDocumentLoader; + TX_EXIT +} + +/*! + Initializes the collection view. Allocates all resources needed by the view. + */ +void MpCollectionView::initializeView() +{ + TX_ENTRY + + mWindow = mainWindow(); + + // Create softkey actions + mSoftKeyQuit = new HbAction(Hb::QuitAction, this); + connect( mSoftKeyQuit, SIGNAL(triggered()), this, SLOT(back()) ); + + mSoftKeyBack = new HbAction(Hb::BackAction, this); + connect( mSoftKeyBack, SIGNAL(triggered()), this, SLOT(back()) ); + + mMpxWrapper = new MpMpxFrameworkWrapper(mViewMode); + connect( mMpxWrapper, SIGNAL(collectionPlaylistOpened()), this, SLOT(startPlaybackView()) ); + connect( mMpxWrapper, SIGNAL(playlistSaved(bool)), this, SLOT(playlistSaved(bool)), Qt::QueuedConnection ); + connect( mMpxWrapper, SIGNAL(songsDeleted(bool)), this, SLOT(songsDeleted(bool)), Qt::QueuedConnection ); + connect( mMpxWrapper, SIGNAL(playlistsRenamed(bool)), this, SLOT(playlistsRenamed(bool)), Qt::QueuedConnection ); + mCollectionData = mMpxWrapper->collectionData(); + connect( mCollectionData, SIGNAL(contextChanged(TCollectionContext)), this, SLOT(setContext(TCollectionContext)) ); + mCollectionDataModel = new MpCollectionDataModel( mCollectionData ); + + mDocumentLoader = new MpCollectionDocumentLoader(); + bool ok = false; + mDocumentLoader->load( MUSIC_COLLECTION_DOCML, &ok ); + if ( ok ) { + QGraphicsWidget *widget; + + widget = mDocumentLoader->findWidget(QString("nowPlaying")); + mNowPlayingBanner = qobject_cast(widget); + + if ( mViewMode == MpCommon::FetchView ) { + // Banner is not needed since playback is stopped when returning + // from playback preview. Disable the banner from updating. + mNowPlayingBanner->setEnabled(false); + } + else { + connect( mNowPlayingBanner, SIGNAL(clicked()), this, SLOT(nowPlayingBannerActivated()) ); + connect( mNowPlayingBanner, SIGNAL(playbackAttachmentChanged(bool)), this, SLOT(attachNowPlayingBanner(bool)) ); + HbEffect::add( QString("banner"), EFFECT_SELECT, QString("chosen") ); + HbEffect::add( QString("banner"), EFFECT_SELECT_END, QString("chosenEnd") ); + } + + widget = mDocumentLoader->findWidget(QString("mainContainer")); + mMainContainer = qobject_cast(widget); + + setWidget(mMainContainer); + + HbEffect::add(QString("container"), + QString(":/effects/slide_out_to_left.fxml"), + QString("slide_out_to_left") ); + + HbEffect::add(QString("container"), + QString(":/effects/slide_out_to_right.fxml"), + QString("slide_out_to_right") ); + + HbEffect::add(QString("container"), + QString(":/effects/slide_out_to_top.fxml"), + QString("slide_out_to_top") ); + + HbEffect::add(QString("container"), + QString(":/effects/slide_in_to_right_and_fade_in.fxml"), + QString("slide_in_to_right_and_fade_in") ); + + HbEffect::add(QString("container"), + QString(":/effects/slide_in_to_left_and_fade_in.fxml"), + QString("slide_in_to_left_and_fade_in") ); + + HbEffect::add(QString("container"), + QString(":/effects/slide_in_to_top_and_fade_in.fxml"), + QString("slide_in_to_top_and_fade_in") ); + } + else { + TX_LOG_ARGS("Error: invalid xml file."); + Q_ASSERT_X(ok, "MpCollectionView::initializeView", "invalid xml file"); + } + + mContainerFactory = new MpCollectionContainerFactory(this, mDocumentLoader); + + if ( MpSettingsManager::firstStartup() ) { + mSongScanner = new MpCollectionSongScanner(mMpxWrapper); + connect(mSongScanner, SIGNAL(scanEnded()), this, SLOT(handleScanningComplete())); + mScanning = true; + mSongScanner->scan(); + } + + TX_EXIT +} + +/*! + Activates the collection view. + */ +void MpCollectionView::activateView() +{ + if ( mScanning ) { + return; + } + mActivated = true; + TX_ENTRY_ARGS("mCollectionContext=" << mCollectionContext); + if ( mCollectionContext == ECollectionContextUnknown ) { + // Open 'All Songs' by default + mMpxWrapper->openCollection( ECollectionContextAllSongs ); + } + else { + // This true when returning from other views, e.g. playback view + setSoftkey(); + } + TX_EXIT +} + +/*! + Deactivates the collection view. + */ +void MpCollectionView::deactivateView() +{ + TX_ENTRY + clearSoftkey(); + mActivated = false; + TX_EXIT +} + +/*! + Loads the correct layout based on the \a orientation. + */ +void MpCollectionView::orientationChange( Qt::Orientation orientation ) +{ + if ( mCollectionContainer ) { + mCollectionContainer->orientationChange(orientation); + } + + if ( mBannerAttached ) { + if ( orientation == Qt::Vertical ) { + setBannerVisibility(true); + } + else { + setBannerVisibility(false); + } + } +} + +/*! + Slot to be called when collection context is changed as a result of Open + operation. + */ +void MpCollectionView::setContext( TCollectionContext context ) +{ + TX_ENTRY_ARGS("context=" << context); + if (mActivated) { + startContainerTransition(mCollectionContext, context); + } + mCollectionContext = context; + mCollectionContainer = mContainerFactory->createContainer(context); + mCollectionContainer->setViewMode(mViewMode); + mCollectionDataModel->refreshModel(); + mCollectionContainer->setDataModel(mCollectionDataModel); + + // Reset softkey and the menu + if (mActivated) { + clearSoftkey(); + setSoftkey(); + } + updateToolBar(); + updateMenu(); + TX_EXIT +} + +/*! + Slot to be called when 'All Songs' action is triggered from the toolbar. + */ +void MpCollectionView::openSongs() +{ + TX_ENTRY + mMpxWrapper->openCollection( ECollectionContextAllSongs ); + TX_EXIT +} + +/*! + Slot to be called when 'Artists' action is triggered from the toolbar. + */ +void MpCollectionView::openArtists() +{ + TX_ENTRY + mMpxWrapper->openCollection( ECollectionContextArtistAlbums ); + TX_EXIT +} + +/*! + Slot to be called when 'Playlists' action is triggered from the toolbar. + */ +void MpCollectionView::openPlaylists() +{ + TX_ENTRY + mMpxWrapper->openCollection( ECollectionContextPlaylists ); + TX_EXIT +} + +/*! + Slot to be called when 'Genres' action is triggered from the toolbar. + */ +void MpCollectionView::openGenres() +{ + TX_ENTRY + mMpxWrapper->openCollection( ECollectionContextGenres ); + TX_EXIT +} + +/*! + Slot to be called when 'Find' action is triggered from the toolbar. + */ +void MpCollectionView::find() +{ + // Todo + HbMessageBox messageBox("Not ready!", HbMessageBox::MessageTypeInformation); + messageBox.exec(); + updateToolBar(); +} + +/*! + Slot to be called when 'Music Store' action is triggered from the toolbar. + */ +void MpCollectionView::openMusicStore() +{ + // Todo + HbMessageBox messageBox("Not ready!", HbMessageBox::MessageTypeInformation); + messageBox.exec(); + updateToolBar(); +} + +/*! + Slot to be called when an item is selected by the user. + */ +void MpCollectionView::openIndex( int index ) +{ + TX_ENTRY_ARGS("index=" << index); + bool doOpen = true; + if ( mViewMode == MpCommon::FetchView ) { + QString songUri; + switch ( mCollectionContext ) { + case ECollectionContextAllSongs: + case ECollectionContextAlbumSongs: + case ECollectionContextPlaylistSongs: + case ECollectionContextGenreSongs: + doOpen = false; + songUri = mCollectionData->itemData(index, MpMpxCollectionData::Uri); + emit songSelected(songUri); + break; + default: + break; + } + } + if ( doOpen ) { + mMpxWrapper->openCollectionItem( index ); + } + TX_EXIT +} + +/*! + Slot to be called when back/quit softkey is pressed. + */ +void MpCollectionView::back() +{ + TX_ENTRY_ARGS("mCollectionContext=" << mCollectionContext); + bool doExit(false); + switch ( mCollectionContext ) { + case ECollectionContextAllSongs: + case ECollectionContextArtistAlbums: + case ECollectionContextPlaylists: + case ECollectionContextGenres: + // Exit from these levels. + doExit = true; + break; + case ECollectionContextAlbumSongs: + case ECollectionContextPlaylistSongs: + case ECollectionContextGenreSongs: + mMpxWrapper->back(); + break; + default: + doExit = true; + break; + } + + if ( doExit ) { + if ( mViewMode == MpCommon::FetchView ) { + // Send an empty string to indicate that user has cancelled + // the fetch operation + emit songSelected(""); + } + else { + emit command( MpCommon::Exit ); + } + } + TX_EXIT +} + +/*! + Slot to be called to exit. + */ +void MpCollectionView::exit() +{ + TX_ENTRY + emit command( MpCommon::Exit ); + TX_EXIT +} + + +/*! + Slot to be called to activate playback view. + */ +void MpCollectionView::startPlaybackView() +{ + TX_LOG + emit command( MpCommon::ActivatePlaybackView ); +} + +/*! + Slot to be called when 'Now Playing Banner' state changes. If active, 'Now + Playing Banner' is attached/shown in the collection view. + */ +void MpCollectionView::attachNowPlayingBanner( bool active ) +{ + TX_ENTRY + setBannerVisibility( active ); + mBannerAttached = active; + updateMenu(); + TX_EXIT +} + +/*! + Slot to be called when 'Now Playing Banner' is clicked by the user. + */ +void MpCollectionView::nowPlayingBannerActivated() +{ + if ( !mEffectOnGoing ) { + HbEffect::start(mNowPlayingBanner, QString("banner"), QString("chosen"), this, "nowPlayingBannerChosenFxComplete1"); + mEffectOnGoing = true; + } +} + +/*! + Slot for 'Now Playing Banner' effects part 1. + */ +void MpCollectionView::nowPlayingBannerChosenFxComplete1( const HbEffect::EffectStatus &status ) +{ + Q_UNUSED(status); + HbEffect::start(mNowPlayingBanner, QString("banner"), QString("chosenEnd"), this, "nowPlayingBannerChosenFxComplete2"); +} + +/*! + Slot for 'Now Playing Banner' effects part 2. The end. + */ +void MpCollectionView::nowPlayingBannerChosenFxComplete2( const HbEffect::EffectStatus &status ) +{ + Q_UNUSED(status); + mEffectOnGoing = false; + startPlaybackView(); +} + +/*! + Slot for container transition end. + */ +void MpCollectionView::containerTransitionComplete( const HbEffect::EffectStatus &status ) +{ + Q_UNUSED(status); + qobject_cast(mWindow)->scene()->removeItem(mSnapshot); + delete mSnapshot; + mSnapshot = 0; +} + +/*! + Slot to be called when 'Shuffle play all' is clicked by the user from the menu. + */ +void MpCollectionView::shufflePlayAll() +{ + mMpxWrapper->setShuffle(true); + MpSettingsManager::setShuffle(true); + int index = generateShuffleIndex(); + openIndex(index); +} + + +/*! + Slot to be called when 'Refresh Library' is clicked by the user from the menu. + */ +void MpCollectionView::refreshLibrary() +{ + if ( !mSongScanner ) { + mSongScanner = new MpCollectionSongScanner(mMpxWrapper); + connect(mSongScanner, SIGNAL(scanEnded()), this, SLOT(handleScanningComplete())); + } + mScanning = true; + mSongScanner->scan(); +} + +/*! + Slot to be called when 'Add to playlist' is clicked by the user from the menu. + */ +void MpCollectionView::addToPlaylist() +{ + QModelIndexList SelectedModelIndexes; + bool ok; + SelectedModelIndexes = HbListDialog::getModelIndexes(QString(tr("Select songs:")), + mCollectionDataModel, + &ok, + HbAbstractItemView::MultiSelection); + + if (ok && SelectedModelIndexes.count()) { + QList selection; + for ( int i = 0; i < SelectedModelIndexes.size(); ++i ) { + selection.append( SelectedModelIndexes.at(i).row() ); + } + launchAddToPlaylistDialog(selection); + } +} + +/*! + Slot to be called when 'Delete' is clicked by the user from the menu. + */ +void MpCollectionView::deleteSongs() +{ + QModelIndexList SelectedModelIndexes; + bool ok; + SelectedModelIndexes = HbListDialog::getModelIndexes(QString(tr("Select songs:")), + mCollectionDataModel, + &ok, + HbAbstractItemView::MultiSelection); + + if (ok && SelectedModelIndexes.count()) { + QList selection; + for ( int i = 0; i < SelectedModelIndexes.size(); ++i ) { + selection.append( SelectedModelIndexes.at(i).row() ); + } + requestDelete(selection); + updateMenu(); + } +} + +/*! + Slot to be called when 'Rename Playlist' is clicked by the user from the menu. + */ +void MpCollectionView::renameCurrentPlaylistContainer() +{ + QString currentName; + currentName = mCollectionData->collectionTitle(); + bool ok = false; + QString newName; + newName = HbInputDialog::getText(QString(tr("Enter name:")), currentName, &ok); + if ( ok && ( currentName != newName ) ) + mMpxWrapper->renamePlaylist( newName ); +} + + +/*! + Slot to be called when 'Add to playlist' operation has completed. + */ +void MpCollectionView::playlistSaved( bool success ) +{ + if (success && mCollectionContext == ECollectionContextPlaylists) { + mMpxWrapper->reopenCollection(); + } +} + +/*! + Slot to be called when 'Delete' operation has completed. + */ +void MpCollectionView::songsDeleted( bool success ) +{ + if ( success ) { + mMpxWrapper->reopenCollection(); + } +} +/*! + Slot to be called when 'Rename' operation has completed. + */ +void MpCollectionView::playlistsRenamed( bool success ) +{ + if ( success ) { + mMpxWrapper->reopenCollection(); + } +} + +/*! + Slot to be called when scan completes. + */ +void MpCollectionView::handleScanningComplete() +{ + TX_ENTRY + mScanning = false; + if ( mActivated ) { + mMpxWrapper->reopenCollection(); + } + else { + activateView(); + } + TX_EXIT +} + +/*! + Slot to be called when an item is long pressed by the user. + */ +void MpCollectionView::openContextMenu( int index, const QPointF &coords ) +{ + TX_ENTRY_ARGS("index=" << index); + switch ( mViewMode ) { + case MpCommon::DefaultView: + openDefaultViewContextMenu(index, coords); + break; + case MpCommon::FetchView: + openFetchViewContextMenu(index, coords); + break; + default: + break; + } + TX_EXIT +} + +/*! + Default view context menu. + */ +void MpCollectionView::openDefaultViewContextMenu(int index, const QPointF &coords) +{ + HbMenu *contextMenu = 0; + HbAction *action; + switch (mCollectionContext) { + case ECollectionContextAllSongs: + case ECollectionContextAlbumSongs: + contextMenu = new HbMenu(); + action = contextMenu->addAction(QString(tr("Add to playlist"))); + action->setObjectName("add"); + action = contextMenu->addAction(QString(tr("Delete"))); + action->setObjectName("delete"); + break; + case ECollectionContextArtistAlbums: + contextMenu = new HbMenu(); + action = contextMenu->addAction(QString(tr("Add to playlist"))); + action->setObjectName("add"); + action = contextMenu->addAction(QString(tr("Delete"))); + action->setObjectName("delete"); + break; + case ECollectionContextPlaylists: + if ( !mCollectionData->isAutoPlaylist(index) ) { + contextMenu = new HbMenu(); + action = contextMenu->addAction(QString(tr("Delete"))); + action->setObjectName("delete"); + action = contextMenu->addAction(QString(tr("Rename"))); + action->setObjectName("rename playlist"); + } + break; + case ECollectionContextPlaylistSongs: + if ( !mCollectionData->isAutoPlaylist() ) { + contextMenu = new HbMenu(); + action = contextMenu->addAction(QString(tr("Remove"))); + action->setObjectName("delete"); + } + break; + default: + break; + } + + if ( contextMenu ) { + HbAction *selectedAction = contextMenu->exec(coords); + if ( selectedAction ) { + QString objectName = selectedAction->objectName(); + QList selection; + selection.append(index); + if ( objectName == "add" ) { + launchAddToPlaylistDialog(selection); + } + else if ( objectName == "delete" ) { + requestDelete(selection); + } + else if ( objectName == "rename playlist" ) { + QString currentName; + currentName = mCollectionData->itemData(index, MpMpxCollectionData::Title); + bool ok = false; + QString newName; + newName = HbInputDialog::getText(QString(tr("Enter name:")), currentName, &ok); + if ( ok && ( currentName != newName ) ) { + mMpxWrapper->renamePlaylist( newName, index ); + } + } + } + } + contextMenu->deleteLater(); + TX_EXIT +} + +/*! + Fetch view context menu + */ +void MpCollectionView::openFetchViewContextMenu( int index, const QPointF &coords ) +{ + TX_ENTRY_ARGS("index=" << index); + + HbMenu *contextMenu = 0; + switch ( mCollectionContext ) { + case ECollectionContextAllSongs: + case ECollectionContextAlbumSongs: + case ECollectionContextPlaylistSongs: + case ECollectionContextGenreSongs: + contextMenu = new HbMenu(); + contextMenu->addAction(QString(tr("Play"))); + break; + default: + break; + } + + if ( contextMenu) { + if ( contextMenu->exec(coords) ) { + // Start the playback process. View will switch to playbackview. + mMpxWrapper->previewItem( index ); + } + } + contextMenu->deleteLater(); + TX_EXIT +} + +/*! + \internal + Sets the main (default) toolbar for the view. + */ +void MpCollectionView::setMainToolBar() +{ + TX_ENTRY + if ( !mMainToolBar ) { + //Create the toolbar. + mMainToolBar = new HbToolBar(); + mMainToolBar->setOrientation(Qt::Horizontal); + QActionGroup *actionsGroup = new QActionGroup( mMainToolBar ); + HbAction *action; + + // All Songs + action = createToolBarAction(actionsGroup, + ":/icons/all_songs_on", + ":/icons/all_songs", + tr("All")); + connect( action, SIGNAL(triggered(bool)), this, SLOT(openSongs()) ); + mMainToolBar->addAction(action); + + // Artists + action = createToolBarAction(actionsGroup, + ":/icons/artists_on", + ":/icons/artists", + tr("Artists")); + connect( action, SIGNAL(triggered(bool)), this, SLOT(openArtists()) ); + mMainToolBar->addAction(action); + + // Playlists + action = createToolBarAction(actionsGroup, + ":/icons/playlists_on", + ":/icons/playlists", + tr("Playlists")); + connect( action, SIGNAL(triggered(bool)), this, SLOT(openPlaylists()) ); + mMainToolBar->addAction(action); + + // Genres + action = createToolBarAction(actionsGroup, + ":/icons/search_on", + ":/icons/search", + tr("Search")); + connect( action, SIGNAL(triggered(bool)), this, SLOT(find()) ); + mMainToolBar->addAction(action); + + if ( mViewMode != MpCommon::FetchView ) { + // Music Store + action = createToolBarAction(actionsGroup, + ":/icons/ovi_on", + ":/icons/ovi", + tr("Ovi")); + connect( action, SIGNAL(triggered(bool)), this, SLOT(openMusicStore()) ); + mMainToolBar->addAction(action); + } + } + HbAction* action = 0; + switch ( mCollectionContext ) { + case ECollectionContextAllSongs: + action = qobject_cast(mMainToolBar->actions()[KMainToolBarAll]); + break; + case ECollectionContextArtistAlbums: + case ECollectionContextAlbumSongs: + action = qobject_cast(mMainToolBar->actions()[KMainToolBarArtists]); + break; + case ECollectionContextPlaylists: + case ECollectionContextPlaylistSongs: + action = qobject_cast(mMainToolBar->actions()[KMainToolBarPlaylists]); + break; + } + if ( action ) { + action->setChecked(true); + } + if ( toolBar() != mMainToolBar ) { + HbToolBar *tmpToolBar = takeToolBar(); + if ( tmpToolBar && tmpToolBar->actions().empty() ) { + tmpToolBar->deleteLater(); + } + setToolBar(mMainToolBar); + } + TX_EXIT +} + +/*! + \internal + Sets the playlist toolbar for the view. + Used only on the playlist container. + */ +void MpCollectionView::setPlaylistToolBar() +{ + TX_ENTRY + if ( !mPlaylistToolBar ) { + mPlaylistToolBar = new HbToolBar(); + mPlaylistToolBar->setOrientation(Qt::Horizontal); + HbAction *action; + + action = new HbAction( tr("Add") ); + connect( action, SIGNAL(triggered(bool)), this, SLOT(notimplemented()) ); + mPlaylistToolBar->addAction(action); + + action = new HbAction( tr("Remove") ); + connect( action, SIGNAL(triggered(bool)), this, SLOT(deleteSongs())); + mPlaylistToolBar->addAction(action); + + action = new HbAction( tr("Reorder") ); + connect( action, SIGNAL(triggered(bool)), this, SLOT(notimplemented()) ); + mPlaylistToolBar->addAction(action); + } + + int items = mCollectionData->count(); + + //no use for remove if there are no items. + mPlaylistToolBar->actions()[KPlaylistToolBarRemove]->setEnabled(items > 0); + + //no use for reorder if there is no more than 1 item. + mPlaylistToolBar->actions()[KplaylistToolBarReorder]->setEnabled(items > 1); + + if ( toolBar() != mPlaylistToolBar ) { + HbToolBar *tmpToolBar = takeToolBar(); + if (tmpToolBar && tmpToolBar->actions().empty ()) { + tmpToolBar->deleteLater(); + } + setToolBar(mPlaylistToolBar); + } + TX_EXIT +} + +/*! + \internal + Creates action associated with the action group for the toolbar. + */ +HbAction *MpCollectionView::createToolBarAction( + QActionGroup *actionsGroup, + const QString& iconOn, + const QString& iconOff, + const QString& toolTip ) +{ + HbIcon actionIcon(iconOff); + // button pressed icon + actionIcon.setIconName(iconOn, QIcon::Normal, QIcon::On ); + + HbAction *action = new HbAction(actionsGroup); + action->setToolTip(toolTip); + action->setIcon(actionIcon); + action->setCheckable(true); + return action; +} + +/*! + \internal + Updates the options menu according to current context. + */ +void MpCollectionView::updateMenu() +{ + TX_ENTRY + HbMenu* myMenu = new HbMenu(); + if ( mViewMode == MpCommon::DefaultView ) { + bool items = mCollectionData->count() != 0; + if ( mBannerAttached ) { + connect( myMenu->addAction(tr("Go to Now Playing")), SIGNAL(triggered()), this, SLOT(startPlaybackView()) ); + } + switch (mCollectionContext) { + case ECollectionContextAllSongs: + if (items) { + connect( myMenu->addAction(tr("Shuffle play all")), SIGNAL(triggered()), this, SLOT(shufflePlayAll()) ); + } + connect( myMenu->addAction(tr("Refresh library")), SIGNAL(triggered()), this, SLOT(refreshLibrary()) ); + if (items) { + connect( myMenu->addAction(tr("Add to playlist")), SIGNAL(triggered()), this, SLOT(addToPlaylist()), Qt::QueuedConnection ); + } + connect( myMenu->addAction(tr("Exit")), SIGNAL(triggered()), this, SLOT(exit()) ); + break; + case ECollectionContextArtistAlbums: + //connect( myMenu->addAction(tr("Add to playlist")), SIGNAL(triggered()), this, SLOT(addToPlaylist()), Qt::QueuedConnection ); + // Todo: View as coverflow + break; + case ECollectionContextAlbumSongs: + if (items) { + connect( myMenu->addAction(tr("Add to playlist")), SIGNAL(triggered()), this, SLOT(addToPlaylist()), Qt::QueuedConnection ); + } + break; + case ECollectionContextPlaylists: + // Todo: Create new playlist + break; + case ECollectionContextPlaylistSongs: + if ( !mCollectionData->isAutoPlaylist() ) { + connect( myMenu->addAction(tr("Rename playlist")), SIGNAL(triggered()), this, SLOT(renameCurrentPlaylistContainer()), Qt::QueuedConnection ); + } + break; + default: + break; + } + } + else if (mViewMode == MpCommon::FetchView ) { + if ( mCollectionContext == ECollectionContextAllSongs ) { + connect( myMenu->addAction(tr("Refresh library")), SIGNAL(triggered()), this, SLOT(refreshLibrary()) ); + } + } + + setMenu(myMenu); + TX_EXIT +} + +/*! + \internal + Updates the Toolbar according to current context. + */ +void MpCollectionView::updateToolBar() +{ + TX_ENTRY + + switch (mCollectionContext) { + case ECollectionContextPlaylistSongs: + if ( !mCollectionData->isAutoPlaylist() ) { + setPlaylistToolBar(); + } + else if (!toolBar()->actions().empty()) { + takeToolBar(); + setToolBar(new HbToolBar); + } + break; + case ECollectionContextAlbumSongs: + case ECollectionContextGenreSongs: + if (!toolBar()->actions().empty()) { + takeToolBar(); + setToolBar(new HbToolBar); + } + break; + default: + setMainToolBar(); + break; + } + TX_EXIT +} + +/*! + \internal + Updates the softkey according to current context. + */ +void MpCollectionView::setSoftkey() +{ + if ( mViewMode == MpCommon::FetchView ) { + // 'Back' is used in all views in fetch mode because we must + // appear as an embedded application. + mWindow->addSoftKeyAction(Hb::SecondarySoftKey, mSoftKeyBack); + } + else { + switch ( mCollectionContext ) { + case ECollectionContextAllSongs: + case ECollectionContextArtistAlbums: + case ECollectionContextPlaylists: + case ECollectionContextGenres: + mWindow->addSoftKeyAction(Hb::SecondarySoftKey, mSoftKeyQuit); + break; + default: + mWindow->addSoftKeyAction(Hb::SecondarySoftKey, mSoftKeyBack); + break; + } + } +} + +/*! + \internal + Clears the softkey set by this view. Restore to previous. + */ +void MpCollectionView::clearSoftkey() +{ + mWindow->removeSoftKeyAction(Hb::SecondarySoftKey, mSoftKeyBack); + mWindow->removeSoftKeyAction(Hb::SecondarySoftKey, mSoftKeyQuit); +} + +/*! + \internal + Sets the Now Playing Banner visibility based on \a visible. + */ +void MpCollectionView::setBannerVisibility( bool visible ) +{ + bool ok = false; + if ( visible && (hbInstance->allMainWindows()[0]->orientation() == Qt::Vertical)) { + mDocumentLoader->load(MUSIC_COLLECTION_DOCML, "showBanner", &ok); + mNowPlayingBanner->show(); + } + else { + mDocumentLoader->load(MUSIC_COLLECTION_DOCML, "hideBanner", &ok); + mNowPlayingBanner->hide(); + } + + if ( !ok ) { + TX_LOG_ARGS("Error: invalid xml file."); + Q_ASSERT_X(ok, "MpCollectionView::setBannerVisibility", "invalid xml file"); + } +} + +/*! + \internal + Generates a random index for shuffle all. + */ +int MpCollectionView::generateShuffleIndex() +{ + int low = 0; + int high = mCollectionData->count(); + + time_t seconds; + time(&seconds); + srand((unsigned int) seconds); + + int index = rand() % (high - low + 1) + low; + return index; +} + +/*! + \internal + Launches the 'Add to playlist' dialog. + */ +void MpCollectionView::launchAddToPlaylistDialog( QList selection ) +{ + QString newPlaylistName; + int playlistIndex; + bool canceled = false; + + forever { + QStringList list; + mMpxWrapper->findPlaylists(list); + if ( list.count()) { + HbListDialog dialog; + dialog.setStringItems(list); + dialog.setSelectionMode(HbAbstractItemView::SingleSelection); + dialog.setHeadingWidget(new HbLabel(QString(tr("Choose a playlist:")))); + dialog.setPrimaryAction(new HbAction(QString(tr("New")))); + dialog.setSecondaryAction(new HbAction(QString(tr("Cancel")))); + HbAction *selectedAction = dialog.exec(); + if ( selectedAction == dialog.secondaryAction() ) { + // Cancel + break; + } + else if ( selectedAction != dialog.primaryAction()) { + // User selected existing playlist + playlistIndex = dialog.selectedItems().at(0); + mMpxWrapper->saveToPlaylist(playlistIndex, selection); + break; + } + } + else if (canceled) { + break; + } + + // New - create a suggested name for the playlist + QString suggestedPlaylistName(tr("Playlist")); + int i = 0; + for (; + list.contains( QString( suggestedPlaylistName + "(" + QString::number(i) + ")" ) ) ; + i++ ) {}; + suggestedPlaylistName += QString("(" + QString::number( i ) + ")"); + // Loop until the user cancels or enters a valid name + forever { + QString suggestedText; + bool ok = false; + suggestedText = HbInputDialog::getText(QString(tr("Enter a name for the new playlist:")), suggestedPlaylistName, &ok); + if ( !ok ) { + canceled = true; + break; + } + if ( !list.contains(suggestedText) ) { + newPlaylistName = suggestedText; + mMpxWrapper->createPlaylist(newPlaylistName, selection); + return; + } + } + } +} + +/*! + \internal + starts a transition of the main container with a decoy snapshot. + */ +void MpCollectionView::startContainerTransition(TCollectionContext contextFrom, TCollectionContext contextTo) +{ + if (!mSnapshot) + mSnapshot = new MpSnapshotWidget(); + mSnapshot->capture(mWindow, mMainContainer ); + mWindow->scene()->addItem(mSnapshot); + + + if ( ( contextFrom == ECollectionContextArtistAlbums && contextTo == ECollectionContextAlbumSongs ) || + ( contextFrom == ECollectionContextPlaylists && contextTo == ECollectionContextPlaylistSongs ) || + ( contextFrom == ECollectionContextGenres && contextTo == ECollectionContextGenreSongs ) ){ + HbEffect::start(mSnapshot, + QString("container"), + QString("slide_out_to_left")); + + HbEffect::start(mMainContainer, + QString("container"), + QString("slide_in_to_left_and_fade_in"), + this, + "containerTransitionComplete"); + } + else if(( contextFrom == ECollectionContextAlbumSongs && contextTo == ECollectionContextArtistAlbums) || + ( contextFrom == ECollectionContextPlaylistSongs && contextTo == ECollectionContextPlaylists) || + ( contextFrom == ECollectionContextGenreSongs && contextTo == ECollectionContextGenres)) { + HbEffect::start(mSnapshot, + QString("container"), + QString("slide_out_to_right")); + + HbEffect::start(mMainContainer, + QString("container"), + QString("slide_in_to_right_and_fade_in"), + this, + "containerTransitionComplete"); + } + else { + HbEffect::start(mSnapshot, + QString("container"), + QString("slide_out_to_top")); + + HbEffect::start(mMainContainer, + QString("container"), + QString("slide_in_to_top_and_fade_in"), + this, + "containerTransitionComplete"); + } + +} + +/*! + \internal + request a delete operation always it has been confirmed. + */ +void MpCollectionView::requestDelete(QList selection) +{ + bool confirmation(false); + // Todo: Use HbMessageBox::question when time-out removed from it + HbMessageBox dialog(HbMessageBox::MessageTypeQuestion); + QString message; + HbAction *action; + + switch (mCollectionContext) { + case ECollectionContextAllSongs: + case ECollectionContextAlbumSongs: + message = QString(tr("Delete song?")); + dialog.setText(message); + dialog.setTimeout(HbPopup::NoTimeout); + action = dialog.exec(); + if (action == dialog.primaryAction()) { + confirmation = true; + } + break; + case ECollectionContextArtistAlbums: + message = QString(tr("Delete album?")); + dialog.setText(message); + dialog.setTimeout(HbPopup::NoTimeout); + action = dialog.exec(); + if (action == dialog.primaryAction()) { + confirmation = true; + } + break; + case ECollectionContextPlaylists: + message = QString(tr("Delete playlist?")); + dialog.setText(message); + dialog.setTimeout(HbPopup::NoTimeout); + action = dialog.exec(); + if (action == dialog.primaryAction()) { + confirmation = true; + } + break; + case ECollectionContextPlaylistSongs: + case ECollectionContextGenres: + case ECollectionContextGenreSongs: + confirmation = true; + break; + case ECollectionContextUnknown: + default: + // We shouldn't be here + TX_LOG_ARGS("Invalid Collection Context:" << mCollectionContext); + break; + } + + if ( confirmation ) { + mMpxWrapper->deleteSongs(selection); + } +}