mpxplugins/serviceplugins/collectionplugins/mpxsqlitedbplugin/src/mpxdbplaylist.cpp
changeset 0 ff3acec5bc43
child 9 13afc0e517bd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mpxplugins/serviceplugins/collectionplugins/mpxsqlitedbplugin/src/mpxdbplaylist.cpp	Thu Dec 17 08:45:05 2009 +0200
@@ -0,0 +1,1087 @@
+/*
+* Copyright (c) 2007 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:  Responsible for interaction with the playlist tables.
+*
+*/
+
+
+// INCLUDE FILES
+#include <f32file.h>
+#include <mpxlog.h>
+#include <mpxmediacontainerdefs.h>
+
+#include "mpxdbcommonutil.h"
+#include "mpxdbcommondef.h"
+#include "mpxdbcommonstd.h"
+
+#include "mpxcollectiondbdef.h"
+#include "mpxdbmanager.h"
+#include "mpxdbutil.h"
+#include "mpxdbpluginqueries.h"
+#include "mpxdbplaylistsongs.h"
+#include "mpxdbplaylist.h"
+
+// CONSTANTS
+// UniqueID column in Uris requests
+const TInt KColUniqueID = 0;
+// URI column in Uris requests
+const TInt KColUri = 1;
+
+// ============================ MEMBER FUNCTIONS ==============================
+
+// ----------------------------------------------------------------------------
+// Two-phased constructor.
+// ----------------------------------------------------------------------------
+//
+CMPXDbPlaylist* CMPXDbPlaylist::NewL(
+    CMPXDbManager& aDbManager,
+	MMPXDbPlaylistObserver& aObserver)
+    {
+    MPX_FUNC("CMPXDbPlaylist::NewL");
+
+    CMPXDbPlaylist* self = CMPXDbPlaylist::NewLC(aDbManager, aObserver);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// Two-phased constructor.
+// ----------------------------------------------------------------------------
+//
+CMPXDbPlaylist* CMPXDbPlaylist::NewLC(
+    CMPXDbManager& aDbManager,
+	MMPXDbPlaylistObserver& aObserver)
+    {
+    MPX_FUNC("CMPXDbPlaylist::NewLC");
+
+	CMPXDbPlaylist* self = new (ELeave) CMPXDbPlaylist(aDbManager, aObserver);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// Destructor
+// ----------------------------------------------------------------------------
+//
+CMPXDbPlaylist::~CMPXDbPlaylist()
+    {
+    MPX_FUNC("CMPXDbPlaylist::~CMPXDbPlaylist");
+    delete iPlaylistSongs;
+    }
+
+// ----------------------------------------------------------------------------
+// Constructor
+// ----------------------------------------------------------------------------
+//
+CMPXDbPlaylist::CMPXDbPlaylist(
+    CMPXDbManager& aDbManager, 
+    MMPXDbPlaylistObserver& aObserver) :
+    CMPXDbTable(aDbManager),
+	iObserver(aObserver)
+    {
+    MPX_FUNC("CMPXDbPlaylist::CMPXDbPlaylist");
+    }
+
+// ----------------------------------------------------------------------------
+// Second phase constructor.
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::ConstructL()
+    {
+    MPX_FUNC("CMPXDbPlaylist::ConstructL");
+
+    BaseConstructL();
+    iPlaylistSongs = CMPXDbPlaylistSongs::NewL(iDbManager);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::AddPlaylistL
+// ----------------------------------------------------------------------------
+//
+TUint32 CMPXDbPlaylist::AddPlaylistL(
+    const CMPXMedia& aMedia)
+    {
+    MPX_FUNC("CMPXDbPlaylist::AddPlaylistL");
+
+    // make sure the playlist and the corresponding songs are deleted
+    TUint32 playlistId(MPXDbCommonUtil::GenerateUniqueIdL(iDbManager.Fs(), EMPXPlaylist,
+        aMedia.ValueText(KMPXMediaGeneralUri), EFalse));
+    DeletePlaylistNoUriL(playlistId);
+
+    // add the playlist
+    return DoAddPlaylistL(aMedia, TDriveUnit(aMedia.ValueText(KMPXMediaGeneralUri)));
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::AddSongsL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::AddSongsL(
+    TUint32 aPlaylistId,
+    const CMPXMediaArray& aMediaArray)
+    {
+    MPX_FUNC("CMPXDbPlaylist::AddSongsL");
+
+    // get the drive ID of corresponding playlist
+    TInt drive(GetDriveIdL(aPlaylistId));
+
+    // add the songs
+    iPlaylistSongs->AddSongsL(aPlaylistId, aMediaArray, drive);
+
+    // update the time for the playlist
+    UpdatePlaylistTimeL(aPlaylistId, drive);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::UpdatePlaylistL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::UpdatePlaylistL(
+    const CMPXMedia& aMedia,
+    CMPXMessage& aMessage,
+    TInt aDriveId)
+    {
+    MPX_FUNC("CMPXDbPlaylist::UpdatePlaylistL");
+
+    TUint32 playlistId((aMedia.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)).iId2);
+    DoUpdatePlaylistL(playlistId, aMedia, aDriveId, aMessage);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::UpdateSongL
+// ----------------------------------------------------------------------------
+//
+TBool CMPXDbPlaylist::UpdateSongL(
+    const CMPXMedia& aMedia,
+    TBool aResetFlags,
+    CMPXMessageArray* aItemChangedMessages /* = NULL */)
+    {
+    MPX_FUNC("CMPXDbPlaylist::UpdateSongL");
+
+    // find the song ID
+    TInt oldSongId(0);
+    TInt newSongId(0);
+    if (aMedia.IsSupported(KMPXMediaGeneralId))
+        {
+        oldSongId = (aMedia.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)).iId2;
+        }
+    if (aMedia.IsSupported(KMPXMediaGeneralUri))
+        {
+        newSongId = MPXDbCommonUtil::GenerateUniqueIdL(iDbManager.Fs(), EMPXCollection,
+            aMedia.ValueText(KMPXMediaGeneralUri), EFalse);
+        }
+    if ( !aMedia.IsSupported( KMPXMediaGeneralId ) && !aMedia.IsSupported( KMPXMediaGeneralUri ))
+        {
+        User::Leave( KErrArgument );
+        }
+
+    if ( newSongId <= 0 )
+        {
+        newSongId = oldSongId;
+        }
+
+    if ( oldSongId <= 0 )
+        {
+        oldSongId = newSongId;
+        }
+
+    // update the PlaylistSongs and PlaylistSongInfo tables first
+    TBool updated(EFalse);
+    TBool visible(iPlaylistSongs->UpdateSongL( oldSongId, aMedia, aResetFlags, updated ));
+    TBool bSongInPlaylists( EFalse );
+    if (updated)
+        {
+        UpdatePlaylistsForSongL( newSongId, aItemChangedMessages,bSongInPlaylists );
+        }
+
+    return visible;
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::DeleteSongL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::DeleteSongL(
+    TUint32 aSongId,
+    CMPXMessageArray& aItemChangedMessages)
+    {
+    MPX_FUNC("CMPXDbPlaylist::DeleteSongL");
+    TBool bSongInPlaylists(EFalse);
+    // add item changed messages for all playlists that contain the song
+    UpdatePlaylistsForSongL (aSongId, &aItemChangedMessages, bSongInPlaylists);
+    if (bSongInPlaylists)
+        {
+        // delete the song from the PlaylistSongs and PlaylistSongInfo tables
+        iPlaylistSongs->DeleteSongL (aSongId);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::DeleteSongL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::DeleteSongL(
+    TUint32 aPlaylistId,
+    TUint32 aSongId,
+    TInt aOrdinal)
+    {
+    MPX_FUNC("CMPXDbPlaylist::DeleteSongL");
+
+    // get playlist drive
+    TInt drive(GetDriveIdL(aPlaylistId));
+
+    // delete the song from the PlaylistSongs / PlaylistSongInfo tables
+    iPlaylistSongs->DeleteSongL(aPlaylistId, aSongId, aOrdinal, drive);
+
+    // update the time for the playlist
+    UpdatePlaylistTimeL(aPlaylistId, drive);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::DeletePlaylistL
+// ----------------------------------------------------------------------------
+//
+HBufC* CMPXDbPlaylist::DeletePlaylistL(
+    TUint32 aPlaylistId)
+    {
+    MPX_FUNC("CMPXDbPlaylist::DeletePlaylistL");
+
+    // get the uri
+    HBufC* uri = GetUriL(aPlaylistId);
+    if (uri)
+        {
+        CleanupStack::PushL(uri);
+        TDriveUnit drive(*uri);
+
+        // delete the songs from the PlaylistSongs table
+        iPlaylistSongs->DeleteSongsL(aPlaylistId, drive);
+
+        // delete the playlist record from the Playlist table
+        iDbManager.ExecuteQueryL(drive, KQueryPlaylistDelete, aPlaylistId);
+
+        CleanupStack::Pop(uri);
+        }
+
+    return uri;
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::DeletePlaylistNoUriL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::DeletePlaylistNoUriL(
+    TUint32 aPlaylistId)
+    {
+    MPX_FUNC("CMPXDbPlaylist::DeletePlaylistNoUriL");
+
+    TInt drive(0);
+    MPX_TRAPD(err, drive = GetDriveIdL(aPlaylistId));
+    if (err != KErrNotFound)
+        {
+        User::LeaveIfError(err);
+
+        // delete the songs from the PlaylistSongs table
+        iPlaylistSongs->DeleteSongsL(aPlaylistId, drive);
+
+        // delete the playlist record from the Playlist table
+        iDbManager.ExecuteQueryL(drive, KQueryPlaylistDelete, aPlaylistId);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::DeleteAllPlaylistsL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::DeleteAllPlaylistsL()
+    {
+    MPX_FUNC("CMPXDbPlaylist::DeleteAllPlaylistsL");
+
+    // delete the songs from the PlaylistSongs table
+    iPlaylistSongs->DeleteAllSongsL();
+
+    // delete all playlists
+    iDbManager.ExecuteQueryL(KDbManagerAllDrives, KQueryPlaylistDeleteAll);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::CountL
+// ----------------------------------------------------------------------------
+//
+TInt CMPXDbPlaylist::CountL()
+    {
+    MPX_FUNC("CMPXDbPlaylist::CountL");
+    return ExecuteSumQueryL(KQueryPlaylistCount);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetPlaylistL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::GetPlaylistL(
+    TUint32 aPlaylistId,
+    const TArray<TMPXAttribute>& aAttrs,
+    CMPXMedia& aMedia)
+    {
+    MPX_FUNC("CMPXDbPlaylist::GetPlaylistL");
+    ExecuteMediaQueryL(aAttrs, aMedia, KQueryPlaylistGet, aPlaylistId);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetAllPlaylistsL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::GetAllPlaylistsL(
+    const TArray<TMPXAttribute>& aAttrs,
+    CMPXMediaArray& aMediaArray)
+    {
+    MPX_FUNC("CMPXDbPlaylist::GetAllPlaylistsL");
+    ExecuteMediaQueryL(aAttrs, aMediaArray, KQueryPlaylistGetAll);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetNameL
+// ----------------------------------------------------------------------------
+//
+HBufC* CMPXDbPlaylist::GetNameL(
+    TUint32 aPlaylistId)
+    {
+    MPX_FUNC("CMPXDbPlaylist::GetNameL");
+
+    RSqlStatement recordset(GetPlaylistRecordL(aPlaylistId));
+    CleanupClosePushL(recordset);
+
+    HBufC* name(NULL);
+    TInt err(KErrNone);
+    if ((err = recordset.Next()) == KSqlAtRow)
+        {
+        name = MPXDbCommonUtil::GetColumnTextL(recordset, EPlaylistName).AllocL();
+        }
+    CleanupStack::PopAndDestroy(&recordset);
+
+    if (err != KSqlAtEnd)
+        {
+        User::LeaveIfError(err);
+        }
+
+    if (name == NULL)
+        {
+        User::LeaveIfError(KErrNotFound);
+        }
+    return name;
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetUriL
+// ----------------------------------------------------------------------------
+//
+HBufC* CMPXDbPlaylist::GetUriL(
+    TUint32 aPlaylistId)
+    {
+    MPX_FUNC("CMPXDbPlaylist::GetUriL");
+
+    RSqlStatement recordset(GetPlaylistRecordL(aPlaylistId));
+    CleanupClosePushL(recordset);
+
+    HBufC* uri(NULL);
+    TInt err(KErrNone);
+    if ((err = recordset.Next()) == KSqlAtRow)
+        {
+        uri = MPXDbCommonUtil::CreateFullPathL(
+            MPXDbCommonUtil::GetDriveIdMatchVolIdL(iDbManager.Fs(),
+            recordset.ColumnInt64(EPlaylistVolumeId)),
+            MPXDbCommonUtil::GetColumnTextL(recordset, EPlaylistUri));
+
+        }
+    CleanupStack::PopAndDestroy(&recordset);
+
+    if (err != KSqlAtEnd)
+        {
+        User::LeaveIfError(err);
+        }
+
+    if (uri == NULL)
+        {
+        User::LeaveIfError(KErrNotFound);
+        }
+
+    return uri;
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetIdL
+// ----------------------------------------------------------------------------
+//
+TUint32 CMPXDbPlaylist::GetIdL(
+    const TDesC& aUri)
+    {
+    MPX_FUNC("CMPXDbPlaylist::GetIdL");
+    HBufC* uri = MPXDbCommonUtil::ProcessPatternCharsLC( aUri );
+    TUint32 ret = ExecuteIntQueryL(
+        KQueryLikePlaylistId, uri->Mid( KMCPathStartPos ) );
+
+   	CleanupStack::PopAndDestroy( uri );
+
+    return ret;
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::FindAllL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::FindAllL(
+    const CMPXMedia& aCriteria,
+    const TArray<TMPXAttribute>& aAttrs,
+    CMPXMediaArray& aMediaArray)
+    {
+    MPX_FUNC("CMPXDbPlaylist::FindAllL");
+
+    // process the requested attributes
+    // the UniqueId is always requested
+    TBool titleRequested(EFalse);
+    TBool counterRequested(EFalse);
+
+    TInt viewingColumnCount(aAttrs.Count());
+    for (TInt i = 0; (i < viewingColumnCount) && !(titleRequested && counterRequested); ++i)
+        {
+        if (aAttrs[i].ContentId() == KMPXMediaIdGeneral)
+            {
+            TUint attributeId(aAttrs[i].AttributeId());
+
+            if (attributeId & EMPXMediaGeneralTitle)
+                {
+                titleRequested = ETrue;
+                }
+            if (attributeId & EMPXMediaGeneralCount)
+                {
+                counterRequested = ETrue;
+                }
+            }
+        }
+
+    TMPXGeneralType type = aCriteria.ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType);
+
+    const TArray<TMPXAttribute> criteria = aCriteria.Attributes();
+    TInt criteriaCount(criteria.Count());
+
+    // process the criteria and construct the criteria string
+    CDesCArrayFlat* criteriaArray = new (ELeave) CDesCArrayFlat(criteriaCount);
+    CleanupStack::PushL(criteriaArray);
+
+    TBool criteriaCounterSet(EFalse);
+    TInt criteriaCounter(0);
+
+    for (TInt i = 0; i < criteriaCount; ++i)
+        {
+        const TMPXAttribute& criterion = criteria[i];
+        if (type == EMPXItem && criterion == KMPXMediaGeneralId)
+            {
+            TUint32 itemId((aCriteria.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)).iId2);
+            if (MPX_ITEM_CATEGORY(itemId) != EMPXPlaylist)
+                {
+                User::Leave(KErrNotSupported);
+                }
+
+            MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistUniqueId, itemId);
+            }
+        else if (criterion == KMPXMediaGeneralTitle)
+            {
+            HBufC* title = MPXDbCommonUtil::ProcessPatternCharsLC(
+                aCriteria.ValueText(KMPXMediaGeneralTitle));
+            if( type == EMPXOtherType )
+                {
+                MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistTitle, *title);
+                }
+            else
+                {
+            MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistLikeTitle, *title);
+                }
+            CleanupStack::PopAndDestroy(title);
+            }
+        else if (criterion == KMPXMediaGeneralUri)
+            {
+            MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistUniqueId,
+                MPXDbCommonUtil::GenerateUniqueIdL(iDbManager.Fs(), EMPXPlaylist,
+                aCriteria.ValueText(KMPXMediaGeneralUri), EFalse));
+            }
+        else if (criterion == KMPXMediaGeneralDrive)
+            {
+            const TDesC& drive(aCriteria.ValueText(KMPXMediaGeneralDrive));
+            TDriveUnit driveUnit(drive);
+            MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistVolumeId,
+                MPXDbCommonUtil::GetVolIdMatchDriveIdL(iDbManager.Fs(), driveUnit));
+            }
+        else if (criterion == KMPXMediaGeneralSynchronized)
+            {
+            MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistSync,
+                aCriteria.ValueTObjectL<TBool>(KMPXMediaGeneralSynchronized));
+            }
+        else if (criterion == KMPXMediaGeneralCount)
+            {
+            criteriaCounterSet = ETrue;
+            criteriaCounter = aCriteria.ValueTObjectL<TInt>(KMPXMediaGeneralCount);
+            }
+        }
+
+    // construct criteria string
+    HBufC* criteriaStr = MPXDbCommonUtil::StringFromArrayLC(*criteriaArray, KMCAndKeyword);
+
+    HBufC* query(NULL);
+    if (criteriaStr->Length() > 0)
+        {
+        // construct and execute the query
+        query = HBufC::NewLC(KQueryPlaylistItems().Length() + criteriaStr->Length());
+        query->Des().Format(KQueryPlaylistItems, criteriaStr);
+        }
+    else
+        {
+        query = HBufC::NewLC(KQueryPlaylistGetAll().Length());
+        query->Des().Format(KQueryPlaylistGetAll);
+        }
+
+    RSqlStatement recordset(iDbManager.ExecuteSelectQueryL(*query));
+
+    CleanupStack::PopAndDestroy(query);
+    CleanupStack::PopAndDestroy(criteriaStr);
+    CleanupStack::PopAndDestroy(criteriaArray);
+
+    CleanupClosePushL(recordset);
+
+    TInt err(KErrNone);
+    while ((err = recordset.Next()) == KSqlAtRow)
+        {
+        // Setup basic info - with first record of a group
+        TUint32 playlistId(recordset.ColumnInt64(EPlaylistUniqueId));
+
+        TBool valid(ETrue);
+        TInt songCount(-1);
+        if (criteriaCounterSet)
+            {
+            songCount = iPlaylistSongs->CountL(playlistId);
+            valid = (criteriaCounter == songCount);
+            }
+
+        if (valid)
+            {
+            // start a new media object
+            CMPXMedia* media = CMPXMedia::NewL();
+            CleanupStack::PushL(media);
+
+            UpdateMediaL(recordset, aAttrs, *media);
+
+            aMediaArray.AppendL(*media);
+            CleanupStack::PopAndDestroy(media);
+            }
+        }
+
+    CleanupStack::PopAndDestroy(&recordset);
+
+    if (err != KSqlAtEnd)
+        {
+        User::LeaveIfError(err);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetDriveIdL
+// ----------------------------------------------------------------------------
+//
+TInt CMPXDbPlaylist::GetDriveIdL(
+    TUint32 aPlaylistId)
+    {
+    MPX_FUNC("CMPXDbPlaylist::GetDriveIdL");
+    return MPXDbCommonUtil::GetDriveIdMatchVolIdL(iDbManager.Fs(),
+        ExecuteIntQueryL(KQueryPlaylistDriveId, aPlaylistId));
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::Songs
+// ----------------------------------------------------------------------------
+//
+CMPXDbPlaylistSongs& CMPXDbPlaylist::Songs()
+    {
+    return *iPlaylistSongs;
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetDrivePlaylistCount
+// ----------------------------------------------------------------------------
+//
+TUint CMPXDbPlaylist::GetDrivePlaylistCountL(TInt aDrive)
+    {
+    TUint count(0);
+
+    RSqlStatement recordset(iDbManager.ExecuteSelectQueryL(aDrive,KQueryPlaylistFileCount));
+    CleanupClosePushL(recordset);
+
+    if (recordset.Next() != KSqlAtRow)
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    count = TUint(recordset.ColumnInt64(KMPXTableDefaultIndex));
+    CleanupStack::PopAndDestroy(&recordset);
+
+    return count;
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetPlaylistUriArrayL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::GetPlaylistUriArrayL(TInt aDrive, TInt aFromID, TInt aRecords,
+                                          CDesCArray& aUriArr, TInt& aLastID)
+    {
+    MPX_FUNC("CMPXDbPlaylist::GetPlaylistUriArrayL");
+
+    HBufC* query = NULL;
+    if(aFromID == 0)
+        {
+        query = HBufC::NewLC(KQueryPlaylistGetFileUris().Length()
+                            + KMCIntegerLen);
+        query->Des().Format(KQueryPlaylistGetFileUris, aRecords);
+        }
+    else
+        {
+        query = HBufC::NewLC(KQueryPlaylistGetFileUrisFrom().Length()
+                            + 2*KMCIntegerLen);
+        query->Des().Format(KQueryPlaylistGetFileUrisFrom, aFromID, aRecords);
+        }
+
+    RSqlStatement playlist_rs(iDbManager.ExecuteSelectQueryL(aDrive,*query));
+
+    CleanupStack::PopAndDestroy(query);
+
+    CleanupClosePushL(playlist_rs);
+
+    TInt lastID = 0;
+    TInt err(KErrNone);
+    while((err = playlist_rs.Next()) == KSqlAtRow)
+        {
+        HBufC* fullPath = MPXDbCommonUtil::CreateFullPathL(aDrive,
+                MPXDbCommonUtil::GetColumnTextL(playlist_rs, KColUri));
+        CleanupStack::PushL(fullPath);
+        aUriArr.AppendL(*fullPath);
+        CleanupStack::PopAndDestroy(fullPath);
+
+        lastID = playlist_rs.ColumnInt(KColUniqueID);
+        }
+    CleanupStack::PopAndDestroy(&playlist_rs);
+
+    aLastID = lastID;
+
+    if (err!= KSqlAtEnd)
+        {
+        User::Leave(KErrCorrupt);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::UpdateMediaL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::UpdateMediaL(
+    RSqlStatement& aRecord,
+    const TArray<TMPXAttribute>& aAttrs,
+    CMPXMedia& aMedia)
+    {
+    MPX_FUNC("CMPXDbPlaylist::UpdateMediaL");
+
+    TBool countRequested(EFalse);
+	TBool durationRequested(EFalse);
+    TUint32 playlistId(aRecord.ColumnInt64(EPlaylistUniqueId));
+
+    TInt count(aAttrs.Count());
+    for (TInt i = 0; i < count; ++i)
+        {
+        TInt contentId(aAttrs[i].ContentId());
+        TUint attributeId(aAttrs[i].AttributeId());
+
+        if (contentId == KMPXMediaIdGeneral)
+            {
+            if (attributeId & EMPXMediaGeneralId)
+                {
+                aMedia.SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, playlistId);
+                MPX_DEBUG2("    Playlist ID[%u]", playlistId);
+                }
+            if (attributeId & EMPXMediaGeneralCollectionId)
+                {
+                aMedia.SetTObjectValueL<TUid>(KMPXMediaGeneralCollectionId,
+                    TUid::Uid(KDBPluginUid));
+                }
+            if (attributeId & EMPXMediaGeneralTitle)
+                {
+                TPtrC title(MPXDbCommonUtil::GetColumnTextL(aRecord, EPlaylistName));
+                aMedia.SetTextValueL(KMPXMediaGeneralTitle, title);
+                MPX_DEBUG2("    Title[%S]", &title);
+                }
+            if ((attributeId & EMPXMediaGeneralUri) ||
+                (attributeId & EMPXMediaGeneralDrive) ||
+                (attributeId & EMPXMediaGeneralFlags))
+                {
+                TUint32 volId(aRecord.ColumnInt64(EPlaylistVolumeId));
+                TInt driveId = MPXDbCommonUtil::GetDriveIdMatchVolIdL(iDbManager.Fs(), volId);
+
+                // LTAN-7GH6BZ, crash if eject memory card when adding song to existing playlist
+                // due to special timing issue, it is possible drive number is -1 and create a
+                // panic when use for TDriveUnit
+                MPX_DEBUG3("volId = %d, driveId = %d", volId, driveId);
+
+                // handle possibly delay from framework notification
+                if (driveId < 0)
+                    {
+                    MPX_DEBUG1("invalid driveId, leave with KErrNotReady");
+                    User::Leave(KErrNotReady);
+                    }
+
+                TDriveUnit driveUnit(driveId);
+
+                if (attributeId & EMPXMediaGeneralUri)
+                    {
+                    HBufC* fullPath = MPXDbCommonUtil::CreateFullPathL(driveUnit,
+                        MPXDbCommonUtil::GetColumnTextL(aRecord, EPlaylistUri));
+                    CleanupStack::PushL(fullPath);
+                    aMedia.SetTextValueL(KMPXMediaGeneralUri, *fullPath);
+                    MPX_DEBUG2("    URI[%S]", fullPath);
+                    CleanupStack::PopAndDestroy(fullPath);
+                    }
+                if (attributeId & EMPXMediaGeneralDrive)
+                    {
+                    aMedia.SetTextValueL(KMPXMediaGeneralDrive, driveUnit.Name());
+                    }
+                if (attributeId & EMPXMediaGeneralFlags)
+                    {
+                    TUint32 dbFlags(aRecord.ColumnInt64(EPlaylistDbFlag));
+                    TInt driveId = driveUnit & KMPXMediaGeneralFlagsDriveInfo;  // 5 bits
+                    aMedia.SetTObjectValueL<TUint>(KMPXMediaGeneralFlags, dbFlags | driveId);
+                    }
+                }
+            if (attributeId & EMPXMediaGeneralSynchronized)
+                {
+                aMedia.SetTObjectValueL<TBool>(KMPXMediaGeneralSynchronized,
+                    aRecord.ColumnInt(EPlaylistSync));
+                }
+            if (attributeId & EMPXMediaGeneralCount)
+                {
+                // make sure the PlaylistSongs query is executed after all fields
+                // from the current record have been processed, otherwise the recordset
+                // may point to something else
+                countRequested = ETrue;
+                }
+            if (attributeId & EMPXMediaGeneralDate)
+                {
+                // convert the time from the internal DB string format
+                // to the int64 format used by TTime
+                aMedia.SetTObjectValueL<TInt64>(KMPXMediaGeneralDate,
+                    MPXDbCommonUtil::DesToTTimeL(
+                    MPXDbCommonUtil::GetColumnTextL(aRecord, EPlaylistTime)).Int64());
+                }
+			if ( attributeId & EMPXMediaGeneralDuration )
+				{		        
+				// make sure the PlaylistSongs query is executed after all fields
+				// from the current record have been processed, otherwise the recordset
+				// may point to something else				
+
+				durationRequested = ETrue;
+				}
+            } // end if contentId == KMPXMediaIdGeneral
+        } // end for
+
+    if (countRequested)
+        {
+		TInt count = iPlaylistSongs->CountL(playlistId);
+        aMedia.SetTObjectValueL<TInt>(KMPXMediaGeneralCount,
+            count );
+        
+        MPX_DEBUG1("    EMPXMediaGeneralCount");
+		MPX_DEBUG2("	Count[%d]", count);				
+        }
+	if (durationRequested)
+		{
+		TInt duration = iObserver.HandlePlaylistDurationL(playlistId);		
+		aMedia.SetTObjectValueL<TInt>(KMPXMediaGeneralDuration, duration);
+		
+		MPX_DEBUG1("    EMPXMediaGeneralDuration");
+		MPX_DEBUG2("	Duration[%d]", duration);				
+		}
+
+    aMedia.SetTObjectValueL<TMPXGeneralType>(KMPXMediaGeneralType, EMPXItem);
+    aMedia.SetTObjectValueL<TMPXGeneralCategory>(KMPXMediaGeneralCategory, EMPXPlaylist);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetPlaylistRecordL
+// ----------------------------------------------------------------------------
+//
+RSqlStatement CMPXDbPlaylist::GetPlaylistRecordL(
+    TUint32 aPlaylistId)
+    {
+    MPX_FUNC("CMPXDbPlaylist::GetPlaylistRecordL");
+    return iDbManager.ExecuteSelectQueryL(KQueryPlaylistGet, aPlaylistId);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::DoAddPlaylistL
+// ----------------------------------------------------------------------------
+//
+TUint32 CMPXDbPlaylist::DoAddPlaylistL(
+    const CMPXMedia& aMedia,
+    TInt aDriveId)
+    {
+    MPX_FUNC("CMPXDbPlaylist::DoAddPlaylistL");
+
+    const TDesC& playlistName(aMedia.ValueText(KMPXMediaGeneralTitle));
+    const TDesC& playlistUri(aMedia.ValueText(KMPXMediaGeneralUri));
+
+    TUint32 playlistId(MPXDbCommonUtil::GenerateUniqueIdL(iDbManager.Fs(), EMPXPlaylist, playlistUri, EFalse));
+    const CMPXMediaArray* mediaArray = aMedia.Value<CMPXMediaArray>(KMPXMediaArrayContents);
+    if( !mediaArray )
+        {
+        User::Leave( KErrNoMemory );
+        }
+    // add the songs to the PlaylistSongs table
+    TInt count(mediaArray->Count());
+    for (TInt i = 0; i < count; ++i)
+        {
+        iPlaylistSongs->AddSongL(playlistId, i, *mediaArray->AtL(i), aDriveId);
+        }
+
+    // determine the value of DbFlag
+    TUint dbflags(0);
+    if (aMedia.IsSupported(KMPXMediaGeneralFlags))
+        {
+        TUint flag(aMedia.ValueTObjectL<TUint>(KMPXMediaGeneralFlags));
+        if (flag & KMPXMediaGeneralFlagsSetOrUnsetBit )
+            {
+            // Set flag
+            dbflags |= flag;
+            MPX_DEBUG2("    GeneralFlags[%b]", dbflags);
+            }
+        }
+
+    // add playlist record
+    HBufC* time = MPXDbCommonUtil::CurrentTimeDesLC();
+    HBufC* name = MPXDbCommonUtil::ProcessSingleQuotesLC(playlistName);
+    HBufC* uri = MPXDbCommonUtil::ProcessSingleQuotesLC(playlistUri);
+    TPtrC uriPtr(uri->Mid(KMCPathStartPos));
+    TPtrC namePtr(name->Left(KMCMaxTextLen));
+
+    iDbManager.ExecuteQueryL(aDriveId, KQueryPlaylistInsert, playlistId, &namePtr,
+        &uriPtr, MPXDbCommonUtil::GetVolIdMatchDriveIdL(iDbManager.Fs(), aDriveId),
+        dbflags, time);
+
+    CleanupStack::PopAndDestroy(uri);
+    CleanupStack::PopAndDestroy(name);
+    CleanupStack::PopAndDestroy(time);
+
+    return playlistId;
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::DoUpdatePlaylistL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::DoUpdatePlaylistL(
+    TUint32 aPlaylistId,
+    const CMPXMedia& aMedia,
+    TInt aDriveId,
+    CMPXMessage& aMessage)
+    {
+    MPX_FUNC("CMPXDbPlaylist::DoUpdatePlaylistL");
+
+    // construct the criteria array
+    const TArray<TMPXAttribute> attributes = aMedia.Attributes();
+
+    CDesCArrayFlat* criteriaArray = new (ELeave) CDesCArrayFlat(attributes.Count());
+    CleanupStack::PushL(criteriaArray);
+
+    TInt attrCount(attributes.Count());
+    for (TInt index = 0; index < attrCount; ++index)
+        {
+        TInt contentId(attributes[index].ContentId());
+        TUint attributeId(attributes[index].AttributeId());
+
+        switch(contentId)
+            {
+            case KMPXMediaIdGeneral:
+                {
+                if (attributeId & EMPXMediaGeneralTitle)
+                    {
+                    MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistTitle,
+                        aMedia.ValueText(KMPXMediaGeneralTitle));
+                    }
+                if (attributeId & EMPXMediaGeneralUri)
+                    {
+                    const TDesC& uri(aMedia.ValueText (KMPXMediaGeneralUri));
+
+                    // determine if we are changing URI of an existing playlist.
+                    // if so, update playlist URI + its Id
+                    TUint32 newId(MPXDbCommonUtil::GenerateUniqueIdL(iDbManager.Fs(), EMPXPlaylist, uri, EFalse));
+
+                    if (aPlaylistId != newId)
+                        {
+                        aMessage.SetTObjectValueL<TMPXItemId>(KMPXMessageMediaGeneralId, newId);
+                        aMessage.SetTObjectValueL<TMPXItemId>(KMPXMessageMediaDeprecatedId, aPlaylistId);
+
+                        // Change event handling for renaming a playlist should be like a song
+                        // The item focus should goto the new name of the playlist
+                        // to-do: this should be abstracted from the plugin. framework should
+                        //        have enough info to deal with this scenario, if not, add more
+                        //        info in the message passing back to framework
+                        aMessage.SetTObjectValueL<TMPXGeneralCategory>(KMPXMessageMediaGeneralCategory,
+                            EMPXSong);
+
+                        // update the PlaylistSongs to reflect playlist id change
+                        iPlaylistSongs->UpdateSongsL(aPlaylistId, newId);
+
+                        // this takes care of processing the single quotes in the URI
+                        MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistUri,
+                            uri.Mid(KMCPathStartPos));
+                        MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistVolumeId,
+                            MPXDbCommonUtil::GetVolIdMatchDriveIdL(iDbManager.Fs(), TDriveUnit(uri)));
+                        MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistUniqueId,
+                            newId);
+                        }
+                    }
+                if (attributeId & EMPXMediaGeneralSynchronized)
+                    {
+                    MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistSync,
+                        aMedia.ValueTObjectL<TBool>(KMPXMediaGeneralSynchronized));
+                    }
+                }
+                break;
+
+            default:
+                break;
+
+            } // end switch
+        } // end for
+
+    // update the time field to the current time
+    HBufC* time = MPXDbCommonUtil::CurrentTimeDesLC();
+    MPXDbCommonUtil::AddSqlCriterionL(*criteriaArray, KCriterionPlaylistTime, *time);
+    CleanupStack::PopAndDestroy(time);
+
+    // construct a string from all criteria
+    HBufC* criteria = MPXDbCommonUtil::StringFromArrayLC(*criteriaArray, KMCCommaSign);
+
+    // execute the query
+    iDbManager.ExecuteQueryL(aDriveId, KQueryPlaylistUpdate, criteria, aPlaylistId);
+
+    CleanupStack::PopAndDestroy(criteria);
+    CleanupStack::PopAndDestroy(criteriaArray);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::UpdatePlaylistsForSongL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::UpdatePlaylistsForSongL(
+    TUint32 aSongId,
+    CMPXMessageArray* aItemChangedMessages, TBool& aSongInPlaylists)
+    {
+    MPX_FUNC("CMPXDbPlaylist::UpdatePlaylistsForSongL");
+
+    aSongInPlaylists = EFalse;
+    if (aItemChangedMessages)
+        {
+        // get all playlists for the song
+        RSqlStatement recordset(iDbManager.ExecuteSelectQueryL(KQueryPlaylistGetForSong, aSongId));
+        CleanupClosePushL(recordset);
+
+        // ignore the errors
+        while (recordset.Next() == KSqlAtRow)
+            {
+            aSongInPlaylists = ETrue;
+            // add item changed messages for all of them
+            MPXDbCommonUtil::AddItemChangedMessageL(*aItemChangedMessages,
+                recordset.ColumnInt64(KMPXTableDefaultIndex), EMPXItemModified,
+                EMPXPlaylist, KDBPluginUid);
+            }
+
+        CleanupStack::PopAndDestroy(&recordset);
+        }
+    if (aSongInPlaylists)
+        {
+        // update the time for all playlists that contain this song
+        HBufC* time = MPXDbCommonUtil::CurrentTimeDesLC();
+        iDbManager.ExecuteQueryL (KDbManagerAllDrives,
+                KQueryPlaylistUpdateTimeForSong, time, aSongId);
+        CleanupStack::PopAndDestroy (time);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::CreateTableL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::UpdatePlaylistTimeL(
+    TUint32 aPlaylistId,
+    TInt aDrive)
+    {
+    MPX_FUNC("CMPXDbPlaylist::UpdatePlaylistTimeL");
+
+    HBufC* time = MPXDbCommonUtil::CurrentTimeDesLC();
+    iDbManager.ExecuteQueryL(aDrive, KQueryPlaylistUpdateTime, time, aPlaylistId);
+    CleanupStack::PopAndDestroy(time);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::GetDrivePlaylistDuration
+// ----------------------------------------------------------------------------
+//
+TInt CMPXDbPlaylist::GetDrivePlaylistDuration(TUint32 aPlaylistId)
+    {
+    return 0;
+    }
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::CreateTableL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::CreateTableL(
+    RSqlDatabase& aDatabase,
+    TBool /* aCorruptTable */)
+    {
+    MPX_FUNC("CMPXDbPlaylist::CreateTableL");
+
+    // create the table
+    User::LeaveIfError(aDatabase.Exec(KPlaylistCreateTable));
+
+    // create the index on the Name field
+    User::LeaveIfError(aDatabase.Exec(KPlaylistNameIndex));
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::DropTableL
+// ----------------------------------------------------------------------------
+//
+void CMPXDbPlaylist::DropTableL(
+    RSqlDatabase& aDatabase)
+    {
+    MPX_FUNC("CMPXDbPlaylist::DropTableL");
+    User::LeaveIfError(aDatabase.Exec(KPlaylistDropTable));
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXDbPlaylist::CheckTableL
+// ----------------------------------------------------------------------------
+//
+TBool CMPXDbPlaylist::CheckTableL(
+    RSqlDatabase& aDatabase)
+    {
+    MPX_FUNC("CMPXDbPlaylist::CheckTableL");
+    return DoCheckTable(aDatabase, KPlaylistCheckTable);
+    }
+
+// End of File