--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmappcomponents/collectionhelper/src/mpxcollectionuihelperimp.cpp Thu Dec 17 08:55:47 2009 +0200
@@ -0,0 +1,2070 @@
+/*
+* Copyright (c) 2006 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: Collection Ui Helper implementation
+*
+*/
+
+
+#include <e32base.h>
+#include <s32file.h>
+#include <mpxmedia.h>
+#include <mpxcollectionplaylist.h>
+#include <mpxmediaarray.h>
+#include <mpxmediageneraldefs.h>
+#include <mpxmediacontainerdefs.h>
+#include <mpxuser.h>
+#include <mpxcmn.h>
+#include <mpxcollectionutility.h>
+#include <mpxcollectiontype.h>
+#include <mpxcollectionmediator.h>
+#include <mpxplaylistenginedefs.h>
+#include <mpxlog.h>
+#include <mpxcollectionmessage.h>
+#include <mpxtaskqueue.h>
+#include <mpxcollectionplugin.hrh>
+#include <mpxharvesterutility.h>
+#include <mpxcommandgeneraldefs.h>
+#include <mpxcollectioncommanddefs.h>
+#include <UsbWatcherInternalPSKeys.h>
+#include <usbpersonalityids.h>
+
+#include "mpxcollectionuihelperobserver.h"
+#include "mpxcollectionuihelperimp.h"
+#include "mpxcollectionhelpercommon.h"
+#include "mpxdeletehelper.h"
+
+// CONSTANTS
+const TInt KMPXAllSongsViewIndex = 0;
+const TInt KMPXPlaylistViewIndex = 1;
+const TInt KMPXRecentlyPlayedIndex = 0x20000000;
+const TInt KMPXMostPlayedIndex = 0x20000001;
+const TInt KMPXRecentlyAddedIndex = 0x20000002;
+
+_LIT( KPathVirtualPlaylistHandling, "openpath.dat");
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Private Constructor
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionUiHelperImp::CMPXCollectionUiHelperImp()
+ {
+ }
+
+
+// ---------------------------------------------------------------------------
+// 2nd Phase Constructor
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::ConstructL(const TUid& aModeId)
+ {
+ iCollection = MMPXCollectionUtility::NewL(this,aModeId);
+ iMediator = CMPXCollectionMediator::NewL( iCollection->Collection(),
+ this );
+ iHarvester = CMPXHarvesterFactory::NewL();
+ iTaskQueue = CMPXActiveTaskQueue::NewL();
+ iDeleteHelper = CMPXDeleteHelper::NewL(*iCollection, *iHarvester, *this);
+
+ iRemainder = 0;
+ iTotalChunkNumber = 0;
+ iChunkNumber = 0;
+ iChunkSize = 0;
+ iArrayIndex = 0;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Two-Phased Constructor
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionUiHelperImp* CMPXCollectionUiHelperImp::NewL(const TUid& aModeId)
+ {
+ CMPXCollectionUiHelperImp* self = CMPXCollectionUiHelperImp::NewLC(aModeId);
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Two-Phased Constructor
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionUiHelperImp* CMPXCollectionUiHelperImp::NewLC(const TUid& aModeId)
+ {
+ CMPXCollectionUiHelperImp* self = new( ELeave ) CMPXCollectionUiHelperImp();
+ CleanupStack::PushL( self );
+ self->ConstructL(aModeId);
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// Virtual Destructor
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionUiHelperImp::~CMPXCollectionUiHelperImp()
+ {
+ delete iMediator;
+ if( iCollection )
+ {
+ iCollection->Close();
+ }
+ if( iHarvester )
+ {
+ iHarvester->Close();
+ }
+ delete iTaskQueue;
+ delete iMedia;
+ delete iDeleteHelper;
+
+ delete iInputMedia;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Issue collection initialization command to collection framework.
+// This is necessary when collection helper serves as an intermediator
+// between collection framework and Podcast App or MTP, etc.
+// There is, currently, no way to check the merge status of the collections
+// through the collection utility API. Therefore, collectionhelper issue
+// an EMcCmdCollectionInit(or merge) command before any collectionhelper
+// functionality, which expects collection is in valid state, is excuted.
+// ---------------------------------------------------------------------------
+//
+
+// ---------------------------------------------------------------------------
+// Add a Media to the collection
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::AddL( const CMPXMedia& aMedia,
+ MMPXCHelperObserver* aObserver )
+ {
+ if (!aObserver)
+ {
+ User::Leave( KErrArgument );
+ }
+
+ //
+ // leave if the given media doesn't contain the following attributes
+ //
+ if (!aMedia.IsSupported(KMPXMediaGeneralType) ||
+ !aMedia.IsSupported(KMPXMediaGeneralCategory))
+ {
+ User::Leave( KErrArgument );
+ }
+
+ //
+ // leave if the given media isn't a playlist (i.e. type must be EMPXItem and category
+ // must be EMPXPlaylist
+ //
+ TMPXGeneralType mediaType =
+ aMedia.ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType);
+
+ TMPXGeneralCategory mediaCategory =
+ aMedia.ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory);
+
+ //
+ // currently only supporting playlists
+ //
+ if ( mediaType != EMPXItem ||
+ mediaCategory != EMPXPlaylist )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ //
+ // leave if the media doesn't contain mandatory attributes for adding a playlist
+ // or adding (appending) tracks to an existing playlist.
+ // Required attributes for adding a new playlist are:
+ // type, category, array contents, array counts, title, and path for playlist
+ // Required attributes for adding tracks to an existing playlist are:
+ // type, category, array contents, array counts, and playlist Id
+ //
+ if (!aMedia.IsSupported(KMPXMediaArrayContents) ||
+ !aMedia.IsSupported(KMPXMediaArrayCount))
+ {
+ User::Leave( KErrArgument );
+ }
+
+ TInt task(ETaskNone);
+ if (!aMedia.IsSupported(KMPXMediaGeneralId))
+ {
+ if (!aMedia.IsSupported(KMPXMediaGeneralTitle) ||
+ !aMedia.IsSupported(KMPXMediaGeneralUri))
+ {
+ User::Leave( KErrArgument );
+ }
+ else
+ {
+ task = ETaskAddMedia;
+ }
+ }
+ else
+ {
+ task = ETaskAppendMedia;
+ }
+
+ //
+ // externalize parameters
+ //
+ CBufBase* taskParam(NULL);
+ ::CreateBufferL<CMPXMedia>( aMedia, taskParam );
+ CleanupStack::PushL(taskParam);
+
+ // Increase reference count for task queue
+ CMPXMedia* ref = CMPXMedia::NewL( aMedia );
+ CleanupStack::PushL(ref);
+
+ //
+ // add request to the task queue
+ //
+ iTaskQueue->AddTaskL( task,
+ aObserver, // callback when task completed
+ this, // task queue observer
+ 0, // Integer paramter, not used
+ taskParam, // task queue assumes ownership of taskParam
+ NULL, // Ptr data
+ ref ); // ownership transferred
+
+ CleanupStack::Pop(2, taskParam); // ref & task Param
+ }
+
+// ---------------------------------------------------------------------------
+// Increment Addition
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::IncAddL( const CMPXMedia& aMedia,
+ MMPXCHelperObserver* aObserver,
+ const TInt aSize )
+ {
+ if (!aObserver)
+ {
+ User::Leave( KErrArgument );
+ }
+
+ //
+ // leave if the given media doesn't contain the following attributes
+ //
+ if (!aMedia.IsSupported(KMPXMediaGeneralType) ||
+ !aMedia.IsSupported(KMPXMediaGeneralCategory))
+ {
+ User::Leave( KErrArgument );
+ }
+
+ //
+ // leave if the given media isn't a playlist (i.e. type must be EMPXItem and category
+ // must be EMPXPlaylist
+ //
+ TMPXGeneralType mediaType =
+ aMedia.ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType);
+
+ TMPXGeneralCategory mediaCategory =
+ aMedia.ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory);
+
+ //
+ // currently only supporting playlists
+ //
+ if ( mediaType != EMPXItem ||
+ mediaCategory != EMPXPlaylist )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ //
+ // leave if the media doesn't contain mandatory attributes for adding a playlist
+ // or adding (appending) tracks to an existing playlist.
+ // Required attributes for adding a new playlist are:
+ // type, category, array contents, array counts, title, and path for playlist
+ // Required attributes for adding tracks to an existing playlist are:
+ // type, category, array contents, array counts, and playlist Id
+ //
+ if (!aMedia.IsSupported(KMPXMediaArrayContents) ||
+ !aMedia.IsSupported(KMPXMediaArrayCount))
+ {
+ User::Leave( KErrArgument );
+ }
+
+ TInt task(ETaskNone);
+ if (!aMedia.IsSupported(KMPXMediaGeneralId))
+ {
+ if (!aMedia.IsSupported(KMPXMediaGeneralTitle) ||
+ !aMedia.IsSupported(KMPXMediaGeneralUri))
+ {
+ User::Leave( KErrArgument );
+ }
+ else
+ {
+ task = ETaskAddMedia;
+ }
+ }
+ else
+ {
+ task = ETaskAppendMedia;
+ }
+
+ // get tracks from input media
+ // since using Value instead of ValueCObject, no Push/Pop
+ CMPXMediaArray* tracksArray =
+ aMedia.Value<CMPXMediaArray>( KMPXMediaArrayContents );
+
+ // use incremental add only if number of songs > aSize
+ // this is needed as IncAdd does not deal w/ the case when tracksArray->Count() == aSize
+ if( tracksArray->Count() <= aSize || aSize <= 0 )
+ {
+ //
+ // externalize parameters
+ //
+ CBufBase* taskParam(NULL);
+ ::CreateBufferL<CMPXMedia>( aMedia, taskParam );
+ CleanupStack::PushL(taskParam);
+
+ // Increase reference count for task queue
+ CMPXMedia* ref = CMPXMedia::NewL( aMedia );
+ CleanupStack::PushL(ref);
+
+ //
+ // add request to the task queue
+ //
+ iTaskQueue->AddTaskL( task,
+ aObserver, // callback when task completed
+ this, // task queue observer
+ 0, // Integer paramter, not used
+ taskParam, // task queue assumes ownership of taskParam
+ NULL, // Ptr data
+ ref ); // ownership transferred
+
+ CleanupStack::Pop(2, taskParam); // ref & task Param
+ }
+ else // Inc Add
+ {
+ // calculate number of songs in the last chunk
+ iRemainder = tracksArray->Count() % aSize;
+
+ // calculate the number of iterations/chunks needed to divide the songs
+ // each chunk contians aSize number of songs
+ if( iRemainder == 0 )
+ {
+ iTotalChunkNumber = tracksArray->Count() / aSize;
+ }
+ else
+ {
+ iTotalChunkNumber = tracksArray->Count() / aSize + 1;
+ }
+
+ iChunkNumber = 0; // initialize chunk number
+ iChunkSize = aSize;
+
+ // need this in the case multiple Inc Add is called (if something leaves and
+ // iInputMedia was not cleaned up properly)
+ if( iInputMedia )
+ {
+ delete iInputMedia;
+ iInputMedia = NULL;
+ }
+
+ // save needed info for subsequent processing
+ iInputMedia = CMPXMedia::CopyL(aMedia);
+ iArrayIndex = 0; // index on tracksArray of the input media
+
+ for( int i = 0; i < iTotalChunkNumber; i++ )
+ {
+ if( task == ETaskAddMedia )
+ {
+ // schedule the adding requests to the task queue
+ iTaskQueue->AddTaskL( ETaskIncAddMedia,
+ aObserver, // callback when task completed
+ this ); // task queue observer
+ }
+ else // ETaskAppendMedia
+ {
+ // schedule the appending requests to the task queue
+ iTaskQueue->AddTaskL( ETaskIncAppendMedia,
+ aObserver, // callback when task completed
+ this ); // task queue observer
+ }
+ }
+ }
+
+ }
+
+
+
+
+// ---------------------------------------------------------------------------
+// Update a single media property
+// Checks for podcast changes in gendre
+// Checks for "PodCast" gendre
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::SetL( CMPXMedia*& aMedia,
+ MMPXCHelperObserver* aObserver )
+ {
+ MPX_FUNC("CMPXCollectionUiHelperImp::SetL");
+
+ if (!aObserver)
+ {
+ User::Leave( KErrArgument );
+ }
+
+ //
+ // leave if the given media doesn't contain the following attributes
+ //
+ if (!aMedia->IsSupported(KMPXMediaGeneralType) ||
+ !aMedia->IsSupported(KMPXMediaGeneralCategory))
+ {
+ User::Leave( KErrArgument );
+ }
+
+ //
+ // externalize parameters
+ //
+ CBufBase* taskParam(NULL);
+ ::CreateBufferL<CMPXMedia>( *aMedia, taskParam );
+ CleanupStack::PushL(taskParam);
+
+ //
+ // add request to the task queue
+ //
+ CMPXMedia* ref = CMPXMedia::NewL( *aMedia ); // ownership transferred
+ CleanupStack::PushL(ref);
+
+ iTaskQueue->AddTaskL( ETaskSetMedia,
+ aObserver, // callback when task completed
+ this, // task queue observer
+ 0, // Integer paramter, not used
+ taskParam, // task queue assumes ownership of taskParam
+ NULL, // ptr data
+ ref ); // keep reference count alive
+
+ CleanupStack::Pop(2, taskParam); // ref & taskParam
+ }
+
+// ---------------------------------------------------------------------------
+// Update a list of medias, checks for podcast changes in genre
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::SetL( TArray<CMPXMedia*>& aMediaArray,
+ CMPXCollectionPath& aPath,
+ RArray<TInt>& aIndices )
+ {
+ iMediator->SetItemL( aMediaArray, aPath, aIndices );
+ }
+
+// ---------------------------------------------------------------------------
+// rename a media
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::RenameL( const CMPXMedia& aMedia,
+ MMPXCHelperObserver* aObserver )
+ {
+ if (!aObserver)
+ {
+ User::Leave( KErrArgument );
+ }
+
+ //
+ // leave if the given media doesn't contain the following attributes
+ //
+ if (!aMedia.IsSupported(KMPXMediaGeneralType) ||
+ !aMedia.IsSupported(KMPXMediaGeneralCategory))
+ {
+ User::Leave( KErrArgument );
+ }
+
+ //
+ // leave if the given media isn't a playlist
+ //
+ TMPXGeneralType mediaType =
+ aMedia.ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType);
+
+ TMPXGeneralCategory mediaCategory =
+ aMedia.ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory);
+
+ //
+ // currently only supporting playlists
+ //
+ if ( mediaType != EMPXItem ||
+ mediaCategory != EMPXPlaylist )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ //
+ // leave if the media doesn't contain mandatory attributes for renaming a playlist
+ //
+ if (!aMedia.IsSupported(KMPXMediaGeneralTitle) ||
+ !aMedia.IsSupported(KMPXMediaGeneralId))
+ {
+ User::Leave( KErrArgument );
+ }
+
+ //
+ // externalize parameters
+ //
+ CBufBase* taskParam(NULL);
+ ::CreateBufferL<CMPXMedia>( aMedia, taskParam );
+ CleanupStack::PushL(taskParam);
+
+ // Keep media alive
+ CMPXMedia* ref = CMPXMedia::NewL( aMedia );
+ CleanupStack::PushL(ref);
+
+ //
+ // add request to the task queue
+ //
+ iTaskQueue->AddTaskL( ETaskRenameMedia,
+ aObserver, // callback when task completed
+ this, // task queue observer
+ 0, // Integer paramter, not used
+ taskParam, // task queue assumes ownership of taskParam
+ NULL, // ptr data
+ ref ); // ownership transferred
+
+ CleanupStack::Pop(2, taskParam); // ref & taskParam
+ }
+
+// ---------------------------------------------------------------------------
+// Delete a collection path and the files
+// associated with each leaf node in the path
+// 1: Removes the file from Collection db
+// 2: Deletes the file from FS
+// 3: Removes the file from Harvester db
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::DeleteL( CMPXCollectionPath& aPath,
+ MMPXCHelperObserver* aObs )
+ {
+ if (!aObs)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ MPX_DEBUG_PATH(aPath);
+
+ //
+ // externalize parameters
+ //
+ CBufBase* taskParam(NULL);
+ ::CreateBufferL<CMPXCollectionPath>( aPath, taskParam );
+ CleanupStack::PushL(taskParam);
+
+ //
+ // add request to the task queue
+ //
+ iTaskQueue->AddTaskL( ETaskRemoveMedia,
+ aObs, // callback when task completed
+ this, // task queue observer
+ 0, // Integer paramter, not used
+ taskParam); // task queue assumes ownership of taskParam
+
+ CleanupStack::Pop(taskParam);
+ }
+
+// ---------------------------------------------------------------------------
+// Move an item from one collection to another
+// 0: Convert enum to collection lookup UID
+// 1: Removes the item from the old collection
+// 2: Adds the item to the new collection using mediator
+// (Mediator sets genre "Podcast" to "Unknown" if we move from Music -> Podcast
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::MoveL( CMPXMedia*& aMedia,
+ TUid aNewCollection,
+ MMPXCHelperObserver* aObs )
+ {
+ if (!aMedia->IsSupported(KMPXMediaGeneralCollectionId))
+ {
+ User::Leave(KErrArgument);
+ }
+
+ // Lookup the collection
+ //
+ RArray<TUid> ary;
+ CleanupClosePushL( ary );
+ ary.AppendL( aNewCollection );
+ TUid newuid = iCollection->CollectionIDL( ary.Array() );
+ CleanupStack::PopAndDestroy( &ary );
+
+ // Move with mediator
+ //
+ const TUid& olduid = aMedia->ValueTObjectL<TUid>( KMPXMediaGeneralCollectionId );
+
+ iHelperObserver = aObs;
+ if( !aObs )
+ {
+ iMediator->MoveItemL( aMedia, olduid, newuid );
+ }
+ else
+ {
+ // Should i add this to the task queue? need to think about it
+ iMediator->MoveItemL( aMedia, olduid, newuid, this );
+ }
+
+ // Notify harvester of the explicit move in collection
+ //
+ aMedia->SetTObjectValueL<TUid>(KMPXMediaGeneralCollectionId, newuid);
+ iHarvester->UpdateFileL( aMedia );
+ }
+
+// ---------------------------------------------------------------------------
+// Open the collection in embedded mode for a media
+// Cannot cleanup aObs because UPnP is using this.
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::OpenL( const TUid& aHostId, CMPXMedia& aMedia,
+ MMPXCHelperEmbeddedOpenObserver* /*aObs*/,
+ TInt aPluginInfo )
+ {
+ // Grab the in memory collection plugin UID
+ // aPluginInfo provides additional resolution to find the plugin
+ //
+ RArray<TUid> ary;
+ CleanupClosePushL( ary );
+ ary.AppendL( TUid::Uid(EMPXCollectionPluginHidden) );
+ ary.AppendL( TUid::Uid(EMPXCollectionPluginTemporary) );
+ if( aPluginInfo )
+ {
+ ary.AppendL( TUid::Uid(aPluginInfo) );
+ }
+
+ TUid inMemCollection = iCollection->CollectionIDL( ary.Array() );
+ CleanupStack::PopAndDestroy( &ary );
+
+ // First step is to add this media to the in memory plugin
+ // Set the item id to be the host ID
+ //
+ aMedia.SetTObjectValueL( KMPXMediaGeneralCollectionId, inMemCollection );
+ aMedia.SetTObjectValueL<TMPXItemId>( KMPXMediaGeneralId, aHostId.iUid );
+
+ // Add the media via CMPXCommand
+ CMPXCommand* cmd = CMPXCommand::NewL();
+ CleanupStack::PushL( cmd );
+ cmd->SetTObjectValueL( KMPXCommandGeneralId,
+ KMPXCommandIdCollectionAdd );
+ cmd->SetTObjectValueL( KMPXCommandGeneralDoSync,
+ ETrue );
+ cmd->SetTObjectValueL( KMPXCommandGeneralCollectionId,
+ inMemCollection.iUid );
+ cmd->SetCObjectValueL( KMPXCommandColAddMedia,
+ &aMedia );
+ iCollection->Collection().CommandL( *cmd );
+ CleanupStack::PopAndDestroy( cmd );
+
+ // Second Step is to construct collection path
+ // | collection id | host id |
+ //
+ CMPXCollectionPath* path = CMPXCollectionPath::NewL();
+ CleanupStack::PushL( path );
+ path->AppendL( inMemCollection.iUid );
+ path->AppendL( aHostId.iUid );
+
+ // Last step is to open this path
+ //
+ iCollection->Collection().OpenL( *path );
+ CleanupStack::PopAndDestroy( path );
+ }
+
+// ---------------------------------------------------------------------------
+// Open the collection in embedded mode for a file handle
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::OpenL( const TUid& aHostId, const TDesC& aFile,
+ MMPXCHelperEmbeddedOpenObserver* aObs,
+ TInt aPluginInfo )
+ {
+
+ // Open in embedded mode, no database merge necessary
+ if( !aObs )
+ {
+ User::LeaveIfError( KErrArgument );
+ }
+
+ iEmbeddedModeID = aHostId;
+ iEmbeddedPluginInfo = aPluginInfo;
+ iOpenObserver = aObs;
+
+ iHarvester->ImportFileL( aFile, this );
+ }
+
+// ---------------------------------------------------------------------------
+// Open the collection in embedded mode for a file handle
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::OpenL( RFile& aFile,
+ MMPXCHelperEmbeddedOpenObserver* aObs )
+ {
+ MPX_FUNC( "CMPXCollectionUiHelperImp::OpenL (file handle, observer)" );
+ // Open in embedded mode, no database merge necessary
+ if( !aObs )
+ {
+ User::Leave( KErrArgument );
+ }
+
+ iOpenObserver = aObs;
+ TMPXGeneralCategory category( EMPXNoCategory );
+
+ CFileStore* store( NULL );
+ MPX_TRAPD( error, store = CDirectFileStore::FromL( aFile ); );
+
+ if ( error == KErrNone )
+ {
+ CleanupStack::PushL( store );
+
+ RStoreReadStream stream;
+ stream.OpenLC( *store, store->Root() );
+
+ // Recreate the collection path that we were browsing
+ CMPXCollectionPath* collectionPath = CMPXCollectionPath::NewL( stream );
+ CleanupStack::PopAndDestroy( 2, store ); // stream, store
+ CleanupStack::PushL( collectionPath );
+
+ MPX_DEBUG_PATH( *collectionPath );
+
+ if ( collectionPath->Levels() != 3 ||
+ ( collectionPath->Id(1) != KMPXAllSongsViewIndex &&
+ collectionPath->Id(1) != KMPXPlaylistViewIndex ) )
+ {
+ error = KErrNotSupported;
+ }
+ else
+ {
+ category = collectionPath->Id( 1 ) ==
+ KMPXAllSongsViewIndex ? EMPXSong : EMPXPlaylist;
+ TRAP( error, iCollection->Collection().OpenL( *collectionPath ) );
+ }
+ CleanupStack::PopAndDestroy( collectionPath );
+ }
+
+ // Callback to observer for err handling
+ ( ( MMPXCHelperEmbeddedOpenObserver* )iOpenObserver )->HandleEmbeddedOpenL( error, category );
+ }
+
+// ---------------------------------------------------------------------------
+// Queries about the playlist file extension of the currently selected playlist
+// plugin
+// ---------------------------------------------------------------------------
+HBufC* CMPXCollectionUiHelperImp::PlaylistFileExtensionLC()
+ {
+ // default to M3U playlist type for now
+ return iHarvester->PlaylistFileExtensionLC(EMPXPlaylistTypeM3U);
+ }
+
+// ---------------------------------------------------------------------------
+// Export a playlist
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::ExportPlaylistL(TMPXItemId aPlaylistId,
+ const TDesC& aDestinationDriveAndPath,
+ MMPXCHelperObserver* aObs)
+ {
+ if (!aObs)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ CMPXMedia* media = CMPXMedia::NewL();
+ CleanupStack::PushL(media);
+
+ media->SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, aPlaylistId);
+ media->SetTextValueL(KMPXMediaGeneralUri, aDestinationDriveAndPath);
+
+ //
+ // externalize parameters
+ //
+ CBufBase* taskParam(NULL);
+ ::CreateBufferL<CMPXMedia>( *media, taskParam );
+ CleanupStack::PushL(taskParam);
+
+ //
+ // add request to the task queue
+ //
+ iTaskQueue->AddTaskL( ETaskExportPlaylist,
+ aObs, // callback when task completed
+ this, // task queue observer
+ 0, // Integer paramter, not used
+ taskParam, // task queue assumes ownership of taskParam
+ NULL,
+ media ); // keep media alive, ownership transferred
+
+ CleanupStack::Pop(2, media); // taskParam & media
+ }
+
+// ---------------------------------------------------------------------------
+// Reorder a song in a playlist
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::ReorderPlaylistL(const TMPXItemId& aPlaylistId,
+ const TMPXItemId& aSongId,
+ TUint aOriginalOrdinal,
+ TUint aNewOrdinal,
+ MMPXCHelperObserver* aObs)
+ {
+ if (!aObs)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ CMPXMedia* command = CMPXMedia::NewL();
+ CleanupStack::PushL(command);
+
+ command->SetTObjectValueL<TMPXItemId>(KMPXCommandReorderPlaylistId, aPlaylistId);
+ command->SetTObjectValueL<TMPXItemId>(KMPXCommandReorderSongId, aSongId);
+ command->SetTObjectValueL<TUint>(KMPXCommandReorderOriginalOrdinal, aOriginalOrdinal);
+ command->SetTObjectValueL<TUint>(KMPXCommandReorderNewOrdinal, aNewOrdinal);
+
+ //
+ // externalize parameters
+ //
+ CBufBase* taskParam(NULL);
+ ::CreateBufferL<CMPXMedia>( *command, taskParam );
+ CleanupStack::PushL(taskParam);
+
+ //
+ // add request to the task queue
+ //
+ iTaskQueue->AddTaskL( ETaskReorderPlaylist,
+ aObs, // callback when task completed
+ this, // task queue observer
+ 0, // Integer paramter, not used
+ taskParam, // task queue assumes ownership of taskParam
+ NULL,
+ command ); // keep media alive, ownership transferred
+
+ CleanupStack::Pop(2, command); // taskParam & media
+ }
+
+// ---------------------------------------------------------------------------
+// Creates a default collection path to the music menu
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionPath* CMPXCollectionUiHelperImp::MusicMenuPathL()
+ {
+ // Get top level path only, no database merge necessary
+
+ // Convert the Virtual UID to the real UID
+ RArray<TUid> ary;
+ CleanupClosePushL( ary );
+ ary.AppendL( TUid::Uid(EMPXCollectionPluginMusic) );
+ TUid musicCollection = iCollection->CollectionIDL( ary.Array() );
+ CleanupStack::PopAndDestroy( &ary );
+
+ // Second Step is to construct collection path
+ // | collection id |
+ //
+ CMPXCollectionPath* path = CMPXCollectionPath::NewL();
+ CleanupStack::PushL( path );
+ path->AppendL( musicCollection.iUid );
+ CleanupStack::Pop( path );
+
+ return path;
+ }
+
+// ---------------------------------------------------------------------------
+// Creates a default collection path to the podcast menu
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionPath* CMPXCollectionUiHelperImp::PodCastMenuPathL()
+ {
+ // Get top level path only, no database merge necessary
+
+ // Convert the Virtual UID to the real UID
+ RArray<TUid> ary;
+ CleanupClosePushL( ary );
+ ary.AppendL( TUid::Uid(EMPXCollectionPluginPodCast) );
+ TUid pcCollection = iCollection->CollectionIDL( ary.Array() );
+ CleanupStack::PopAndDestroy( &ary );
+
+ // Second Step is to construct collection path
+ // | collection id |
+ //
+ CMPXCollectionPath* path = CMPXCollectionPath::NewL();
+ CleanupStack::PushL( path );
+ path->AppendL( pcCollection.iUid );
+ CleanupStack::Pop( path );
+
+ return path;
+ }
+
+// ---------------------------------------------------------------------------
+// Creates a default collection path to the music all songs
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionPath* CMPXCollectionUiHelperImp::MusicAllSongsPathL()
+ {
+ CMPXCollectionPath* path = MusicMenuPathL();
+ CleanupStack::PushL( path );
+ path->AppendL( KMPXAllSongsViewIndex );
+ CleanupStack::Pop( path );
+
+ return path;
+ }
+
+// ---------------------------------------------------------------------------
+// Creates a default collection path to the music playlist
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionPath* CMPXCollectionUiHelperImp::MusicPlaylistPathL()
+ {
+ CMPXCollectionPath* path = MusicMenuPathL();
+ CleanupStack::PushL( path );
+ path->AppendL( KMPXPlaylistViewIndex );
+ CleanupStack::Pop( path );
+
+ return path;
+ }
+
+// ---------------------------------------------------------------------------
+// Creates a default collection path to the music auto playlist
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionPath* CMPXCollectionUiHelperImp::MusicPlaylistPathL(TMPXAutoPlaylistType aPlaylistType)
+ {
+ CMPXCollectionPath* path = MusicPlaylistPathL();
+ CleanupStack::PushL( path );
+ if ( aPlaylistType == EMPXRecentlyPlayedPlaylist )
+ {
+ path->AppendL( KMPXRecentlyPlayedIndex );
+ }
+ else if ( aPlaylistType == EMPXMostPlayedPlaylist )
+ {
+ path->AppendL( KMPXMostPlayedIndex );
+ }
+ else if ( aPlaylistType == EMPXRecentlyAddedPlaylist)
+ {
+ path->AppendL( KMPXRecentlyAddedIndex );
+ }
+ CleanupStack::Pop( path );
+
+ return path;
+ }
+
+// ---------------------------------------------------------------------------
+// Creates a default collection playlist hard coded to all songs of
+// music database
+// ---------------------------------------------------------------------------
+//
+CMPXCollectionPath* CMPXCollectionUiHelperImp::CreateDefaultPlaylistPathLC()
+ {
+ // Get top level path only, no database merge necessary
+
+ // Convert the Virtual UID to the real UID
+ RArray<TUid> ary;
+ CleanupClosePushL( ary );
+ ary.AppendL( TUid::Uid(EMPXCollectionPluginMusic) );
+ TUid musicCollection = iCollection->CollectionIDL( ary.Array() );
+ CleanupStack::PopAndDestroy( &ary );
+
+ // Second Step is to construct collection path
+ // | collection id | all songs id |
+ //
+ CMPXCollectionPath* path = CMPXCollectionPath::NewL();
+ CleanupStack::PushL( path );
+ path->AppendL( musicCollection.iUid );
+ path->AppendL( 0 ); // MAGIC, all songs, cannot have dependency to plugin in MPXMusicPlayer
+
+ return path;
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the file name used for virtual playlist handling
+// ---------------------------------------------------------------------------
+//
+HBufC* CMPXCollectionUiHelperImp::ExternalCollectionPathHandlingFileNameLC()
+ {
+ MPX_FUNC( "CMPXCollectionUiHelperImp::ExternalCollectionPathHandlingFileNameLC" );
+ return KPathVirtualPlaylistHandling().AllocLC();
+ }
+
+// ---------------------------------------------------------------------------
+// Cancel current op
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::Cancel()
+ {
+ if( iTask == ETaskRemoveMedia )
+ {
+ iDeleteHelper->Cancel();
+ }
+ else
+ {
+ // currently only used by incremental add
+ iTaskQueue->CancelRequests();
+
+ // clean up iInputMedia
+ if( iInputMedia )
+ {
+ delete iInputMedia;
+ iInputMedia = NULL;
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Frees this object
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::Close()
+ {
+ delete this;
+ }
+
+// ---------------------------------------------------------------------------
+// Test if the specified title already exists for the category
+// ---------------------------------------------------------------------------
+//
+TBool CMPXCollectionUiHelperImp::TitleExistsL(TMPXGeneralCategory aCategory,
+ const TDesC& aTitle,
+ TMPXGeneralType aType)
+ {
+ CMPXMedia* query = CMPXMedia::NewL();
+ CleanupStack::PushL(query);
+ query->SetTObjectValueL(KMPXMediaGeneralType, aType);
+ query->SetTObjectValueL(KMPXMediaGeneralCategory, aCategory);
+ query->SetTextValueL(KMPXMediaGeneralTitle, aTitle);
+
+ // Look up collection UID and set to criteria
+ //
+ RArray<TUid> ary;
+ CleanupClosePushL( ary );
+ ary.AppendL( TUid::Uid(EMPXCollectionPluginMusic) );
+ TUid musicCollection = iCollection->CollectionIDL( ary.Array() );
+ CleanupStack::PopAndDestroy( &ary );
+
+ query->SetTObjectValueL<TUid>( KMPXMediaGeneralCollectionId, musicCollection );
+
+ RArray<TMPXAttribute> attributes;
+ CleanupClosePushL(attributes);
+ attributes.AppendL(KMPXMediaGeneralId);
+
+ CMPXMedia* result =
+ iCollection->Collection().FindAllL(*query, attributes.Array());
+ CleanupStack::PopAndDestroy(&attributes);
+ CleanupStack::PopAndDestroy(query);
+ CleanupStack::PushL(result);
+
+ TInt count = result->ValueTObjectL<TInt>(KMPXMediaArrayCount);
+ CleanupStack::PopAndDestroy(result);
+
+ return count;
+ }
+
+// ---------------------------------------------------------------------------
+// Updates the harvester with the up to date collection <-> file mapping
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleMediatorPathUpdatedL( CMPXMedia*& aProperty,
+ TUid /*aOldPath*/ )
+ {
+ iHarvester->UpdateFileL( aProperty );
+ }
+
+// ---------------------------------------------------------------------------
+// Handles completion of playlist export
+// to-do: this should be changed to HandlePlaylistExportCompleted
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandlePlaylistExportCompletedL( CMPXMedia* aMedia, TInt aErr )
+ {
+ TRAPD(error, DoHandlePlaylistExportCompletedL(aMedia, aErr));
+
+ CompleteTask(iTask, aErr==KErrNone?error:aErr);
+ }
+
+// ---------------------------------------------------------------------------
+// Handles completion of playlist export
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::DoHandlePlaylistExportCompletedL( CMPXMedia* aMedia, TInt aErr )
+ {
+ if (aErr == KErrNone)
+ {
+ CleanupStack::PushL(aMedia);
+ iMedia->SetTextValueL(
+ KMPXMediaGeneralUri, aMedia->ValueText(KMPXMediaGeneralUri));
+ CleanupStack::PopAndDestroy(aMedia);
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Handles completion of playlist import
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandlePlaylistImportCompletedL( CMPXMedia* aMedia, TInt aErr )
+ {
+ if (aErr == KErrNone)
+ {
+ delete aMedia;
+ }
+ // Should never come here
+ ASSERT(0);
+ }
+
+// ---------------------------------------------------------------------------
+// Handle asynchronous file addition by file name
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleFileAddCompletedL( CMPXMedia* aMedia, TInt aErr )
+ {
+ // to-do
+ if (aErr == KErrNone)
+ {
+ delete aMedia;
+ }
+ // Should never come here
+ ASSERT(0);
+ }
+
+// ---------------------------------------------------------------------------
+// Handle file delete completion
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleDeleteCompletedL( TInt /*aErr*/ )
+ {
+ }
+
+// ---------------------------------------------------------------------------
+// From MMPXHarvesterUtilityObserver
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleFileImportCompletedL( CMPXMedia* aMedia,
+ TInt aErr )
+ {
+ // Only do this if we are embedded mode
+ //
+ CleanupStack::PushL( aMedia );
+ if( iEmbeddedModeID.iUid )
+ {
+ TInt err( aErr );
+ TMPXGeneralCategory cat( EMPXNoCategory );
+ if( aErr == KErrNone )
+ {
+ TRAP( err, OpenL( iEmbeddedModeID,
+ *aMedia,
+ (MMPXCHelperEmbeddedOpenObserver*)iOpenObserver ,
+ iEmbeddedPluginInfo ) );
+ cat = aMedia->ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory);
+ }
+
+ // Callback to observer for err handling
+ ((MMPXCHelperEmbeddedOpenObserver*)iOpenObserver)->HandleEmbeddedOpenL( err, cat );
+ }
+ CleanupStack::PopAndDestroy( aMedia );
+ }
+
+// ---------------------------------------------------------------------------
+// From MMPXHarvesterUtilityObserver
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleFileGetMediaCompletedL( CMPXMedia* /*aMedia*/,
+ TInt /*aErr*/ )
+ {
+ // Not used
+ ASSERT(0);
+ }
+
+// ---------------------------------------------------------------------------
+// From MMPXCollectionMediaObserver
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleCollectionMediaL(const CMPXMedia& /*aMedia*/,
+ TInt /*aError*/)
+ {
+ // Not used
+ ASSERT(0);
+ }
+
+// ---------------------------------------------------------------------------
+// From MMPXCollectionObserver
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleCollectionMessage(CMPXMessage* aMsg, TInt aErr)
+ {
+ iDeleteHelper->HandleCollectionMessage( aMsg, aErr );
+ }
+
+// ---------------------------------------------------------------------------
+// From MMPXCollectionObserver
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleOpenL(const CMPXMedia& /*aEntries*/, TInt /*aIndex*/, TBool /*aComplete*/, TInt /*aError*/)
+ {
+ // Not used
+ ASSERT(0);
+ }
+
+// ---------------------------------------------------------------------------
+// From MMPXCollectionObserver
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleOpenL(const CMPXCollectionPlaylist& /*aPlaylist*/, TInt /*aError*/)
+ {
+ // Not used
+ ASSERT(0);
+ }
+
+// ----------------------------------------------------------------------------
+// Handles completion of moving an object, just a proxy
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleMoveCompleteL( TInt aErr )
+ {
+ if( iHelperObserver )
+ {
+ iHelperObserver->HandleOperationCompleteL( EMoveOp, aErr, NULL );
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Handles completion of removing a collection path
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleOperationCompleteL( TCHelperOperation aOperation,
+ TInt aErr,
+ void* aArgument )
+ {
+ if (aOperation == EDeleteOp && iTask == ETaskRemoveMedia)
+ {
+ CompleteTask(iTask, aErr);
+ }
+ else if ( aOperation == EDeleteStatusOp )
+ {
+ iHelperObserver->HandleOperationCompleteL( aOperation, aErr, aArgument );
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Execute an async task
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::ExecuteTask(
+ TInt aTask,
+ TInt /*aParamData*/,
+ TAny* /*aPtrData*/,
+ const CBufBase& aBuf,
+ TAny* aCallback,
+ CBase* /*aCObject1*/,
+ CBase* /*aCObject2*/)
+ {
+ TRAPD(err, ExecuteTaskL(aTask, aBuf, aCallback));
+ if (err != KErrNone)
+ {
+ CompleteTask(aTask, err);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Indicates that a task was terminated with an error
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::HandleTaskError(
+ TInt /* aTask */,
+ TAny* /*aPtrData*/,
+ TAny* /*aCallback*/,
+ TInt /* aError */)
+ {
+ // Do nothing
+ }
+
+// ----------------------------------------------------------------------------
+// Execute an async task. Leaves when an error is encountered.
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::ExecuteTaskL(TInt aTask, const CBufBase& aBuf, TAny* aCallback)
+ {
+ iTask = aTask;
+ MPX_DEBUG2("CMPXCollectionUiHelperImp::ExecuteTaskL, aTask = %d", aTask);
+
+ // cenrep key need to be checked whether USB cable is connected in MTP/Combined Mode
+ // prevent any general add, general delete, and any moficiation of playlist
+ if ((iTask == ETaskAddMedia)
+ || (iTask == ETaskAppendMedia)
+ || (iTask == ETaskIncAddMedia)
+ || (iTask == ETaskIncAppendMedia)
+ || (iTask == ETaskRemoveMedia)
+ || (iTask == ETaskReorderPlaylist)
+ || (iTask == ETaskRenameMedia))
+ {
+ TInt usbStatus;
+ RProperty::Get(KPSUidUsbWatcher, KUsbWatcherSelectedPersonality, usbStatus);
+
+ if ((usbStatus == KUsbPersonalityIdMTP) || (usbStatus == KUsbPersonalityIdPCSuiteMTP)
+ || (usbStatus == KUsbPersonalityIdMS) )
+ {
+ MPX_DEBUG1("USB is active, Leave with KErrLocked");
+ // need to call back even if it leaves here
+ iHelperObserver = (MMPXCHelperObserver*)aCallback;
+ CompleteTask( aTask, KErrLocked );
+ //User::Leave(KErrLocked);
+ if ((iTaskQueue->Task() != ETaskIncAddMedia)&&(iTaskQueue->Task() != ETaskIncAppendMedia))
+ {
+ iIncAdding = EFalse;
+ }
+ return;
+ }
+ }
+
+ switch( aTask )
+ {
+ case ETaskAddMedia: // fall through
+ case ETaskAppendMedia:
+ {
+ delete iMedia;
+ iMedia = NULL;
+ ::NewFromBufferL<CMPXMedia>( aBuf, iMedia );
+ iHelperObserver = (MMPXCHelperObserver*)aCallback;
+ DoAddL();
+ }
+ break;
+
+ case ETaskIncAddMedia:
+ {
+ iHelperObserver = (MMPXCHelperObserver*)aCallback;
+ DoIncAddMediaL();
+ }
+ break;
+
+ case ETaskIncAppendMedia:
+ {
+ iHelperObserver = (MMPXCHelperObserver*)aCallback;
+ DoIncAppendMediaL();
+ }
+ break;
+
+ case ETaskSetMedia:
+ {
+ delete iMedia;
+ iMedia = NULL;
+ ::NewFromBufferL<CMPXMedia>( aBuf, iMedia );
+ iHelperObserver = (MMPXCHelperObserver*)aCallback;
+ DoSetL();
+ }
+ break;
+
+ case ETaskRenameMedia:
+ {
+ delete iMedia;
+ iMedia = NULL;
+ ::NewFromBufferL<CMPXMedia>( aBuf, iMedia );
+ iHelperObserver = (MMPXCHelperObserver*)aCallback;
+ DoRenameL();
+ }
+ break;
+
+ case ETaskRemoveMedia:
+ {
+ CMPXCollectionPath* path(NULL);
+ ::NewFromBufferL<CMPXCollectionPath>( aBuf, path );
+ CleanupStack::PushL(path);
+ MPX_DEBUG_PATH(*path);
+
+ iHelperObserver = (MMPXCHelperObserver*) aCallback;
+ iDeleteHelper->DeleteL(*path);
+ CleanupStack::PopAndDestroy(path);
+ }
+ break;
+
+ case ETaskExportPlaylist:
+ {
+ delete iMedia;
+ iMedia = NULL;
+
+ CMPXMedia* params(NULL);
+ ::NewFromBufferL<CMPXMedia>( aBuf, params );
+ CleanupStack::PushL(params);
+
+ iHelperObserver = (MMPXCHelperObserver*)aCallback;
+
+ DoExportPlaylistL(
+ params->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId),
+ params->ValueText(KMPXMediaGeneralUri));
+
+ CleanupStack::PopAndDestroy(params);
+ }
+ break;
+
+ case ETaskReorderPlaylist:
+ {
+ delete iMedia;
+ iMedia = NULL;
+
+ CMPXCommand* params(NULL);
+ ::NewFromBufferL<CMPXCommand>( aBuf, params );
+ CleanupStack::PushL(params);
+
+ iHelperObserver = (MMPXCHelperObserver*)aCallback;
+
+ DoReorderPlaylistL(*params);
+
+ CleanupStack::PopAndDestroy(params);
+ }
+ break;
+
+ //
+ // command not supported
+ //
+ default:
+ {
+ User::Leave( KErrNotSupported );
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Completes the currently executing task
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::CompleteTask(TInt aTask, TInt aError)
+ {
+ MPX_FUNC("CMPXCollectionUiHelperImp::CompleteTask");
+
+ MPX_DEBUG3("task %d, error %d", aTask, aError);
+
+ TRAP_IGNORE(NotifyClientL(aTask, aError));
+
+ if ( iTask != ETaskNone )
+ {
+ // clean up data set during processing of the current task
+ Cleanup();
+
+ // Complete current task and move on to the next
+ iTaskQueue->CompleteTask();
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Notifies the client of the completion of a collection helper request
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::NotifyClientL(TInt aTask, TInt aError)
+ {
+ MPX_DEBUG3("CMPXCollectionUiHelperImp::NotifyClientL(task %d, error %d)", aTask, aError);
+
+ switch (aTask)
+ {
+ case ETaskAddMedia: // fall through
+ case ETaskAppendMedia:
+ {
+ if ( aError >= KErrNone )
+ {
+ // make a copy of iMedia to hand over to the client which takes ownership
+ // of the copied media. if we failed to make a copy, client is not notified.
+ iHelperObserver->HandleOperationCompleteL(EAddOp,
+ KErrNone,
+ CMPXMedia::NewL(*iMedia) );
+ }
+ else
+ {
+ iHelperObserver->HandleOperationCompleteL( EAddOp,
+ aError,
+ NULL );
+ }
+ }
+ break;
+ case ETaskIncAddMedia:
+ case ETaskIncAppendMedia:
+ {
+ if ( KErrLocked == aError )
+ {
+ if( EFalse == iIncAdding )
+ {
+ iIncAdding = ETrue;
+ iHelperObserver->HandleOperationCompleteL( EAddOp, aError, NULL );
+ }
+ }
+ }
+ break;
+ case ETaskIncFinish:
+ {
+ if ( aError >= KErrNone )
+ {
+ // input media is handed over to observer
+ iHelperObserver->HandleOperationCompleteL(EAddOp,
+ KErrNone,
+ CMPXMedia::NewL(*iInputMedia) );
+ }
+ else
+ {
+ iHelperObserver->HandleOperationCompleteL( EAddOp,
+ aError,
+ NULL );
+ }
+ // clean up input media
+ delete iInputMedia;
+ iInputMedia = NULL;
+ }
+ break;
+
+ case ETaskSetMedia:
+ {
+ if ( aError >= KErrNone )
+ {
+ // make a copy of iMedia to hand over to the client which takes ownership
+ // of the copied media. if we failed to make a copy, client is not notified.
+ iHelperObserver->HandleOperationCompleteL( ESetOp,
+ KErrNone,
+ CMPXMedia::NewL(*iMedia) );
+ }
+ else
+ {
+ iHelperObserver->HandleOperationCompleteL( ESetOp,
+ aError,
+ NULL );
+ }
+ }
+ break;
+
+ case ETaskRenameMedia:
+ {
+ if ( aError >= KErrNone )
+ {
+ // make a copy of iMedia to hand over to the client which takes ownership
+ // of the copied media. if we failed to make a copy, client is not notified.
+ iHelperObserver->HandleOperationCompleteL( ERenameOp,
+ KErrNone,
+ CMPXMedia::NewL(*iMedia) );
+ }
+ else
+ {
+ iHelperObserver->HandleOperationCompleteL( ERenameOp,
+ aError,
+ NULL );
+ }
+ }
+ break;
+
+ case ETaskRemoveMedia:
+ {
+ iHelperObserver->HandleOperationCompleteL( EDeleteOp,
+ aError >= KErrNone? KErrNone : aError,
+ NULL );
+ }
+ break;
+
+ case ETaskExportPlaylist:
+ {
+ HBufC* buf( NULL );
+ if( aError == KErrNone )
+ {
+ const TDesC& uri =
+ iMedia->ValueText(KMPXMediaGeneralUri);
+ buf = uri.AllocL();
+ }
+
+ // client assumes ownership of HBufC copied from title
+ iHelperObserver->HandleOperationCompleteL(EExportPlaylistOp, aError, buf);
+ }
+ break;
+
+ case ETaskReorderPlaylist:
+ {
+ iHelperObserver->HandleOperationCompleteL( EReorderPlaylistOp,
+ aError >= KErrNone? KErrNone : aError,
+ NULL );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Cleanup async task variables
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::Cleanup()
+ {
+ MPX_DEBUG1("-->CMPXCollectionUiHelperImp::Cleanup");
+ iTask = ETaskNone;
+ iHelperObserver = NULL;
+ delete iMedia;
+ iMedia = NULL;
+ MPX_DEBUG1("<--CMPXCollectionUiHelperImp::Cleanup");
+ }
+
+// ---------------------------------------------------------------------------
+// Add a Media to the collection
+//
+// For playlists:
+// 1) add to collection
+// 2) when successfully added to collection, AddItemL returns; otherwise,
+// AddItemL leaves.
+// 3) complete task upon successfully addition to the collection. If a leave
+// occurs, it's trapped by ExecuteTask and task is completed by ExecuteTask
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::DoAddL()
+ {
+ // creating a new playlist
+ if (iTask == ETaskAddMedia)
+ {
+ // find the collection Id
+ HBufC* playlistExtension = PlaylistFileExtensionLC();
+
+ TInt collectionId = FindCollectionIdL(*playlistExtension);
+
+ // Add to collection, make sure we set the collection ID.
+ iMedia->SetTObjectValueL<TUid>(
+ KMPXMediaGeneralCollectionId, TUid::Uid( collectionId ));
+
+ CleanupStack::PopAndDestroy(playlistExtension);
+ }
+
+ // adding/appending tracks to a saved playlist
+ else
+ {
+ FillInPlaylistDetailsL(*iMedia);
+ }
+
+ // when playlist is successfully added to the collection, its
+ // KMPXMediaGeneralId is automatically updated by mediator
+ iMediator->AddItemL( iMedia );
+
+ CompleteTask(iTask, KErrNone);
+ }
+
+// ---------------------------------------------------------------------------
+// Add media to the collection incrementally
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::DoIncAddMediaL()
+ {
+ /***** include only aSize/iChunkSize number of songs *****/
+
+ // copy media
+ CMPXMedia* media = CMPXMedia::CopyL(*iInputMedia);
+ CleanupStack::PushL(media);
+
+ CMPXMediaArray* tracksArray = iInputMedia->Value<CMPXMediaArray>( KMPXMediaArrayContents );
+
+ CMPXMediaArray* cArray = CMPXMediaArray::NewL();
+ CleanupStack::PushL(cArray);
+
+ // last interation/chunk
+ // for the case when aSize/iChunkSize evenly devides number of songs, the else clause takes care of it
+ if( (iChunkNumber == iTotalChunkNumber-1) && iRemainder != 0 )
+ {
+ // add remaining songs to the array
+ for(int j = 0; j < iRemainder; j++ )
+ {
+ cArray->AppendL(*tracksArray->AtL(iArrayIndex));
+ iArrayIndex++;
+ }
+ }
+ else
+ {
+ // adding next aSize/iChunkSize elements
+ for(int j = 0; j < iChunkSize; j++)
+ {
+ cArray->AppendL(*tracksArray->AtL(iArrayIndex));
+ iArrayIndex++;
+ }
+ }
+
+ // update media w/ new array
+ media->SetCObjectValueL(KMPXMediaArrayContents, cArray);
+ media->SetTObjectValueL(KMPXMediaArrayCount, cArray->Count() );
+
+
+ /***** logic to see which chunk this code is in *****/
+
+ // first chunk
+ // for the case that there is only one chunk (first & last chunk at the same
+ // time), Inc Add is not used
+ if ( iChunkNumber == 0 )
+ {
+ // find the collection Id
+ HBufC* playlistExtension = PlaylistFileExtensionLC();
+
+ TInt collectionId = FindCollectionIdL(*playlistExtension);
+
+ // Add to collection, make sure we set the collection ID.
+ media->SetTObjectValueL<TUid>(
+ KMPXMediaGeneralCollectionId, TUid::Uid( collectionId ));
+
+ // save collectionId for adding subsequent chunks
+ iInputMedia->SetTObjectValueL<TUid>(
+ KMPXMediaGeneralCollectionId, TUid::Uid( collectionId ));
+
+ CleanupStack::PopAndDestroy(playlistExtension);
+
+ iMediator->AddItemL( media ); // this creates the new playlist
+
+ // save playlistId in input media & use it for subsequent appending operations
+ TMPXItemId playlistId = media->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId);
+ iInputMedia->SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, playlistId);
+
+ iChunkNumber++; // move on to next chunk
+
+ CompleteTask(iTask, KErrNone);
+ }
+ else if ( iChunkNumber == iTotalChunkNumber-1 ) // last chunk
+ {
+ // get saved collection id from input media & set it in current media
+ TUid id = iInputMedia->ValueTObjectL<TUid>(KMPXMediaGeneralCollectionId);
+ media->SetTObjectValueL<TUid>(KMPXMediaGeneralCollectionId, id);
+
+ // get playlistId from input media & set it in current media
+ TMPXItemId playlistId = iInputMedia->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId);
+ media->SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, playlistId);
+
+ iMediator->AddItemL( media );
+
+ CompleteTask(ETaskIncFinish, KErrNone); // finish inc task
+ }
+ else // intermedia chunks
+ {
+ // get saved collection id from input media & set it in current media
+ TUid id = iInputMedia->ValueTObjectL<TUid>(KMPXMediaGeneralCollectionId);
+ media->SetTObjectValueL<TUid>(KMPXMediaGeneralCollectionId, id);
+
+ // get playlistId from original media & set it in current media
+ TMPXItemId playlistId = iInputMedia->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId);
+ media->SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, playlistId);
+
+ iMediator->AddItemL( media );
+
+ iChunkNumber++; // move on to next chunk
+
+ CompleteTask(iTask, KErrNone);
+ }
+
+ CleanupStack::PopAndDestroy(cArray);
+ CleanupStack::PopAndDestroy(media);
+ }
+
+// ---------------------------------------------------------------------------
+// Append media to the collection incrementally
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::DoIncAppendMediaL()
+ {
+ /***** include only aSize/iChunkSize number of songs *****/
+
+ // copy media
+ CMPXMedia* media = CMPXMedia::CopyL(*iInputMedia);
+ CleanupStack::PushL(media);
+
+ CMPXMediaArray* tracksArray = iInputMedia->Value<CMPXMediaArray>( KMPXMediaArrayContents );
+
+ CMPXMediaArray* cArray = CMPXMediaArray::NewL();
+ CleanupStack::PushL(cArray);
+
+ // last interation/chunk
+ // for the case when aSize/iChunkSize evenly devides number of tracks, the else clause takes care of it
+ if( (iChunkNumber == iTotalChunkNumber-1) && iRemainder != 0 )
+ {
+ for(int j = 0; j < iRemainder; j++ )
+ {
+ cArray->AppendL(*tracksArray->AtL(iArrayIndex));
+ iArrayIndex++;
+ }
+ }
+ else
+ {
+ // adding next aSize/iChunkSize elements
+ for(int j = 0; j < iChunkSize; j++)
+ {
+ cArray->AppendL(*tracksArray->AtL(iArrayIndex));
+ iArrayIndex++;
+ }
+ }
+
+ // update media w/ new array
+ media->SetCObjectValueL(KMPXMediaArrayContents, cArray);
+ media->SetTObjectValueL(KMPXMediaArrayCount, cArray->Count() );
+
+
+ /***** logic to see which chunk this code is in *****/
+
+ // update media then append to playlist
+ FillInPlaylistDetailsL(*media);
+ iMediator->AddItemL( media );
+
+ // last chunk
+ // for the case that there is only one chunk (first & last chunk at the same
+ // time), Inc Add is not used
+ if( iChunkNumber == iTotalChunkNumber-1 )
+ {
+ // update input media as well
+ FillInPlaylistDetailsL(*iInputMedia);
+ CompleteTask(ETaskIncFinish, KErrNone);
+ }
+ else // intermediate chunks, including first chunk
+ {
+ iChunkNumber++;
+ CompleteTask(iTask, KErrNone);
+ }
+
+ CleanupStack::PopAndDestroy(cArray);
+ CleanupStack::PopAndDestroy(media);
+ }
+
+// ---------------------------------------------------------------------------
+// Update a media in the collection
+//
+// For updating (overwriting) a playlist, or updating a song/artist/album/genre/
+// composer:
+// 1) update collection
+// 2) when successfully updated the collection, SetItemL is returned; otherwise
+// a leave occurs.
+// 3) complete task upon successfully updating the collection. If a leave
+// occurs, it's trapped by ExecuteTask and task is completed by ExecuteTask
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::DoSetL()
+ {
+ MPX_FUNC("CMPXCollectionUiHelperImp::DoSetL");
+
+ // fill in playlist details
+ TMPXGeneralCategory category =
+ iMedia->ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory);
+ if ( category == EMPXPlaylist )
+ {
+ FillInPlaylistDetailsL(*iMedia);
+ }
+
+ // find the collection Id
+ if (!iMedia->IsSupported(KMPXMediaGeneralCollectionId) &&
+ iMedia->IsSupported(KMPXMediaGeneralUri))
+ {
+ TInt collectionId =
+ FindCollectionIdL(iMedia->ValueText(KMPXMediaGeneralUri));
+
+ if (collectionId)
+ {
+ iMedia->SetTObjectValueL<TUid>(
+ KMPXMediaGeneralCollectionId , TUid::Uid(collectionId));
+ }
+ }
+
+ // update collection.
+ iMediator->SetItemL( iMedia );
+
+ CompleteTask(iTask, KErrNone);
+ }
+
+// ---------------------------------------------------------------------------
+// Rename a media in the collection
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::DoRenameL()
+ {
+ // find the collection Id of the playlist from playlist Id
+ // iMedia isn't used as the search criteria because it
+ // contains the new title of the playlist; calling
+ // FillInPlaylistDetailsL(*iMedia) will result in playlist
+ // not found.
+ if (!iMedia->IsSupported(KMPXMediaGeneralCollectionId))
+ {
+ CMPXMedia* media = CMPXMedia::NewL();
+ CleanupStack::PushL(media);
+
+ media->SetTObjectValueL(KMPXMediaGeneralType, EMPXItem);
+ media->SetTObjectValueL(KMPXMediaGeneralCategory,EMPXPlaylist);
+ media->SetTObjectValueL(KMPXMediaGeneralId, iMedia->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId));
+
+ FillInPlaylistDetailsL(*media);
+
+ if (media->IsSupported(KMPXMediaGeneralCollectionId))
+ {
+ iMedia->SetTObjectValueL<TUid>(
+ KMPXMediaGeneralCollectionId, media->ValueTObjectL<TUid>(KMPXMediaGeneralCollectionId));
+ }
+ else
+ {
+ User::Leave(KErrNotFound);
+ }
+ CleanupStack::PopAndDestroy(media);
+ }
+
+ // Update collection via command
+ //
+ CMPXCommand* cmd = CMPXCommand::NewL();
+ CleanupStack::PushL( cmd );
+ cmd->SetTObjectValueL( KMPXCommandGeneralId, KMPXCommandIdCollectionSet );
+ cmd->SetTObjectValueL( KMPXCommandGeneralDoSync, ETrue );
+ TUid colId = iMedia->ValueTObjectL<TUid>(KMPXMediaGeneralCollectionId);
+ cmd->SetTObjectValueL( KMPXCommandGeneralCollectionId, colId.iUid );
+ cmd->SetCObjectValueL<CMPXMedia>( KMPXCommandColSetMedia, iMedia );
+
+ iCollection->Collection().CommandL( *cmd );
+ CleanupStack::PopAndDestroy( cmd );
+
+ CompleteTask(iTask, KErrNone);
+ }
+
+// ---------------------------------------------------------------------------
+// Export a playlist
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::DoExportPlaylistL(TMPXItemId aPlaylistId,
+ const TDesC& aDestinationDriveAndPath)
+ {
+ //
+ // fill in playlist info
+ //
+ iMedia = CMPXMedia::NewL();
+
+ iMedia->SetTObjectValueL(KMPXMediaGeneralType, EMPXItem);
+ iMedia->SetTObjectValueL(KMPXMediaGeneralCategory, EMPXPlaylist);
+ iMedia->SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, aPlaylistId);
+
+ FillInPlaylistDetailsL(*iMedia);
+
+ //
+ // find songs that are in the specified playlist
+ //
+ CMPXMedia* songQuery = CMPXMedia::NewL();
+ CleanupStack::PushL(songQuery);
+ songQuery->SetTObjectValueL(KMPXMediaGeneralType, EMPXGroup);
+ songQuery->SetTObjectValueL(KMPXMediaGeneralCategory, EMPXSong);
+ songQuery->SetTObjectValueL(KMPXMediaGeneralId, aPlaylistId);
+
+ RArray<TMPXAttribute> songAttributes;
+ CleanupClosePushL(songAttributes);
+ iHarvester->RequiredAttributesL( EMPXPlaylistTypeM3U, songAttributes );
+ songAttributes.AppendL(KMPXMediaGeneralTitle);
+
+ CMPXMedia* songQueryResult =
+ iCollection->Collection().FindAllL(*songQuery, songAttributes.Array());
+ CleanupStack::PopAndDestroy(&songAttributes);
+ CleanupStack::PopAndDestroy(songQuery);
+ CleanupStack::PushL(songQueryResult);
+
+ // medias contains tracks currently in the playlist
+ const CMPXMediaArray* medias =
+ songQueryResult->Value<CMPXMediaArray>(KMPXMediaArrayContents);
+ if( !medias )
+ {
+ User::Leave( KErrNoMemory );
+ }
+
+ // add media array to iMedia
+ iMedia->SetCObjectValueL(
+ KMPXMediaArrayContents, const_cast<CMPXMediaArray*>(medias));
+ iMedia->SetTObjectValueL(
+ KMPXMediaArrayCount, medias->Count());
+
+ CleanupStack::PopAndDestroy(songQueryResult);
+
+ // export playlist, default to M3U file type. When ExportPlaylistL completes,
+ // HandlePlaylistExportCompletedL will be called
+ iHarvester->ExportPlaylistL( *iMedia, aDestinationDriveAndPath, EMPXPlaylistTypeM3U, this );
+ }
+
+// ---------------------------------------------------------------------------
+// Reorder a song in a playlist
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::DoReorderPlaylistL(CMPXCommand& aCommand)
+ {
+ // Update collection via command
+ //
+ aCommand.SetTObjectValueL( KMPXCommandGeneralId, KMPXCommandIdReorderPlaylist );
+ aCommand.SetTObjectValueL( KMPXCommandGeneralDoSync, ETrue );
+
+ iCollection->Collection().CommandL( aCommand );
+
+ CompleteTask(iTask, KErrNone);
+ }
+
+// ---------------------------------------------------------------------------
+// retrieve information for the required attributes
+// ---------------------------------------------------------------------------
+//
+void CMPXCollectionUiHelperImp::FillInPlaylistDetailsL(CMPXMedia& aMedia)
+ {
+ MPX_FUNC("CMPXCollectionUiHelperImp::FillInPlaylistDetailsL");
+
+ //
+ // retrieve info about the playlist itself
+ //
+ RArray<TMPXAttribute> playlistAttributes;
+ CleanupClosePushL(playlistAttributes);
+ playlistAttributes.AppendL(KMPXMediaGeneralId);
+ playlistAttributes.AppendL(KMPXMediaGeneralTitle);
+ playlistAttributes.AppendL(KMPXMediaGeneralUri);
+ playlistAttributes.AppendL(KMPXMediaGeneralCollectionId);
+
+ CMPXMedia* playlistSearchResult =
+ iCollection->Collection().FindAllL(aMedia, playlistAttributes.Array());
+ CleanupStack::PopAndDestroy(&playlistAttributes);
+ CleanupStack::PushL(playlistSearchResult);
+
+ const CMPXMediaArray* results =
+ playlistSearchResult->Value<CMPXMediaArray>(KMPXMediaArrayContents);
+ if( !results )
+ {
+ User::Leave( KErrNoMemory );
+ }
+
+ if ( results->Count() != 1 )
+ {
+ User::Leave(KErrArgument);
+ }
+
+ MPX_DEBUG1("playlist found");
+
+ aMedia.SetTObjectValueL(
+ KMPXMediaGeneralId, results->AtL(0)->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId));
+ aMedia.SetTextValueL(
+ KMPXMediaGeneralTitle, results->AtL(0)->ValueText(KMPXMediaGeneralTitle));
+ aMedia.SetTextValueL(
+ KMPXMediaGeneralUri, results->AtL(0)->ValueText(KMPXMediaGeneralUri));
+ aMedia.SetTObjectValueL(
+ KMPXMediaGeneralCollectionId, results->AtL(0)->ValueTObjectL<TUid>(KMPXMediaGeneralCollectionId));
+
+ CleanupStack::PopAndDestroy(playlistSearchResult);
+ }
+
+// ---------------------------------------------------------------------------
+// retrieve collection from URI
+// ResolvePlugin should be able to resolve the plugin without
+// the client looking for the collection Id
+// ---------------------------------------------------------------------------
+//
+TInt CMPXCollectionUiHelperImp::FindCollectionIdL(const TDesC& aUri)
+ {
+ MPX_FUNC("CMPXCollectionUiHelperImp::FindCollectionIdL");
+
+ TInt collectionId(KErrNotFound);
+
+ TParsePtrC parser( aUri );
+
+ RPointerArray<CMPXCollectionType> collectionType;
+ iCollection->Collection().GetSupportedTypesL(collectionType);
+
+ TInt index(KErrNotFound);
+ TInt count( collectionType.Count() );
+
+ for (TInt i = 0; i < count; i++)
+ {
+ const CDesCArray& extensions = collectionType[i]->Extensions();
+
+ if (extensions.FindIsq(parser.Ext(), index) == 0)
+ {
+ collectionId = collectionType[i]->Uid().iUid;
+ break;
+ }
+ }
+
+ collectionType.ResetAndDestroy();
+
+ MPX_DEBUG3("Uid 0x%x for %S", collectionId, &aUri);
+
+ return collectionId;
+ }
+
+// End of file