mpx/commonframework/common/src/mpxcollectionpath.cpp
changeset 0 a2952bb97e68
child 48 b7b49303d0c0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mpx/commonframework/common/src/mpxcollectionpath.cpp	Thu Dec 17 08:55:47 2009 +0200
@@ -0,0 +1,1068 @@
+/*
+* 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:  implementation of collection path
+*
+*/
+
+#include <s32strm.h>
+#include <e32panic.h>
+#include <mpxuser.h>
+#include <mpxcmn.h>
+#include <mpxattribute.h>
+#include <mpxdata.h>
+#include "mpxcollectionpath.h"
+
+/**
+* Encapsulates single node in collection hierarchy level. A node represents a
+* level of the collection path
+*/
+NONSHARABLE_CLASS(CMPXCollectionPathNode) : public CBase
+    {
+public:
+    static CMPXCollectionPathNode* NewL();
+    static CMPXCollectionPathNode* NewLC();
+    static CMPXCollectionPathNode* NewLC(const CMPXCollectionPathNode& aNode);
+    virtual ~CMPXCollectionPathNode();
+public:
+    /**
+    * Sets current item at this level
+    */
+    void Set(const TMPXItemId& aId, TInt aIndex);
+
+    /**
+    * Sets the next level open mode
+    */
+    void Set(TMPXOpenMode aRequest);
+
+    /**
+    * Sets the next level open attributes
+    */
+    void SetL(const TArray<TMPXAttribute>& aAttrs);
+
+    /**
+    * Current index
+    */
+    TInt Index() const;
+
+    /**
+    * Current Id
+    */
+    const TMPXItemId& Id() const;
+
+    /**
+    * Open mode for next level
+    */
+    TMPXOpenMode OpenMode() const;
+
+    /**
+    * Open attributes for next level
+    */
+    const TArray<TMPXAttribute> OpenAttributes() const;
+
+public:
+    void ExternalizeL(RWriteStream& aStream) const;
+    void InternalizeL(RReadStream& aStream);
+
+private:
+    CMPXCollectionPathNode();
+    void ConstructL(const CMPXCollectionPathNode& aNode);
+    void ConstructL();
+
+private:
+    TMPXItemId iId;
+    TInt iIndex;
+    TMPXOpenMode iOpenMode;
+    RArray<TMPXAttribute> iAttrs; // Open attributes for next level
+    };
+
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::NewL
+// -----------------------------------------------------------------------------
+//
+CMPXCollectionPathNode* CMPXCollectionPathNode::NewL()
+    {
+    CMPXCollectionPathNode* self = NewLC();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::NewLC
+// -----------------------------------------------------------------------------
+//
+CMPXCollectionPathNode* CMPXCollectionPathNode::NewLC()
+    {
+    CMPXCollectionPathNode* self = new(ELeave) CMPXCollectionPathNode();
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::NewLC
+// -----------------------------------------------------------------------------
+//
+CMPXCollectionPathNode* CMPXCollectionPathNode::NewLC(
+    const CMPXCollectionPathNode& aNode)
+    {
+    CMPXCollectionPathNode* self = new(ELeave) CMPXCollectionPathNode();
+    CleanupStack::PushL(self);
+    self->ConstructL(aNode);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CMPXCollectionPathNode::ConstructL()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CMPXCollectionPathNode::ConstructL(
+    const CMPXCollectionPathNode& aNode)
+    {
+    iId=aNode.iId;
+    iIndex=aNode.iIndex;
+    iOpenMode=aNode.iOpenMode;
+    ::CopyArrayL<TMPXAttribute>(aNode.iAttrs.Array(), iAttrs);
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::CMPXCollectionPathNode
+// -----------------------------------------------------------------------------
+//
+CMPXCollectionPathNode::CMPXCollectionPathNode()
+:   iId(KMPXInvalidItemId),
+    iIndex(KErrNotFound),
+    iOpenMode(EMPXOpenGroupOrPlaylist)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::~CMPXCollectionPathNode
+// -----------------------------------------------------------------------------
+//
+CMPXCollectionPathNode::~CMPXCollectionPathNode()
+    {
+    iAttrs.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::Set
+// -----------------------------------------------------------------------------
+//
+void CMPXCollectionPathNode::Set(const TMPXItemId& aId, TInt aIndex)
+    {
+    iId=aId;
+    iIndex=aIndex;
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::Set
+// -----------------------------------------------------------------------------
+//
+void CMPXCollectionPathNode::Set(TMPXOpenMode aMode)
+    {
+    iOpenMode=aMode;
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::Set
+// -----------------------------------------------------------------------------
+//
+void CMPXCollectionPathNode::SetL(const TArray<TMPXAttribute>& aAttrs)
+    {
+    ::CopyArrayL(aAttrs, iAttrs);
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::Index
+// -----------------------------------------------------------------------------
+//
+TInt CMPXCollectionPathNode::Index() const
+    {
+    return iIndex;
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::Id
+// -----------------------------------------------------------------------------
+//
+const TMPXItemId& CMPXCollectionPathNode::Id() const
+    {
+    return iId;
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::OpenMode
+// -----------------------------------------------------------------------------
+//
+TMPXOpenMode CMPXCollectionPathNode::OpenMode() const
+    {
+    return iOpenMode;
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPathNode::OpenAttributes
+// -----------------------------------------------------------------------------
+//
+const TArray<TMPXAttribute> CMPXCollectionPathNode::OpenAttributes() const
+    {
+    return iAttrs.Array();
+    }
+
+// -----------------------------------------------------------------------------
+// Externalize object
+// -----------------------------------------------------------------------------
+//
+void CMPXCollectionPathNode::ExternalizeL(RWriteStream& aStream) const
+    {
+    aStream.WriteUint32L(iId.iId1);
+    aStream.WriteUint32L(iId.iId2);
+    aStream.WriteInt32L(iIndex);
+    aStream.WriteInt32L(iOpenMode);
+    ::ExternalizeL(iAttrs.Array(), aStream);
+    }
+
+// -----------------------------------------------------------------------------
+// Internalize object
+// -----------------------------------------------------------------------------
+//
+void CMPXCollectionPathNode::InternalizeL(RReadStream& aStream)
+    {
+    TUint32 id1 = aStream.ReadUint32L();
+    TUint32 id2 = aStream.ReadUint32L();
+    iId=TMPXItemId( id1, id2 );
+    iIndex=aStream.ReadInt32L();
+    iOpenMode=static_cast<TMPXOpenMode>(aStream.ReadInt32L());
+    iAttrs.Reset();
+    ::InternalizeL(iAttrs, aStream);
+    }
+
+// ============================== MEMBER FUNCTIONS =============================
+
+// -----------------------------------------------------------------------------
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CMPXCollectionPath* CMPXCollectionPath::NewL()
+    {
+    CMPXCollectionPath* p = new(ELeave) CMPXCollectionPath();
+    CleanupStack::PushL(p);
+    p->ConstructL();
+    CleanupStack::Pop(p);
+    return p;
+    }
+
+// -----------------------------------------------------------------------------
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CMPXCollectionPath* CMPXCollectionPath::NewL(
+    const CMPXCollectionPath& aPath)
+    {
+    CMPXCollectionPath* p = new(ELeave) CMPXCollectionPath();
+    CleanupStack::PushL(p);
+    p->ConstructL(aPath);
+    CleanupStack::Pop(p);
+    return p;
+    }
+
+// -----------------------------------------------------------------------------
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CMPXCollectionPath* CMPXCollectionPath::NewL(
+    RReadStream& aStream)
+    {
+    CMPXCollectionPath* p = new(ELeave) CMPXCollectionPath();
+    CleanupStack::PushL(p);
+    p->ConstructL(aStream);
+    CleanupStack::Pop(p);
+    return p;
+    }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CMPXCollectionPath::~CMPXCollectionPath()
+    {
+    iNodeArray.ResetAndDestroy();
+    iNodeArray.Close();
+    iIds.Close();
+    iSelection.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// Default constructor
+// -----------------------------------------------------------------------------
+//
+CMPXCollectionPath::CMPXCollectionPath() : iInvalidId(KMPXInvalidItemId)
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// 2nd phase constructor.
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionPath::ConstructL(const CMPXCollectionPath& aPath)
+    {
+    iNodeArray.ResetAndDestroy();
+    TInt count = aPath.iNodeArray.Count();
+    for (TInt i=0; i<count; ++i)
+        {
+        CMPXCollectionPathNode* node =
+            CMPXCollectionPathNode::NewLC(*(aPath.iNodeArray[i]));
+        iNodeArray.AppendL(node);
+        CleanupStack::Pop(node);
+        }
+    ::CopyArrayL(aPath.iIds.Array(),iIds);
+    ::CopyArrayL(aPath.iSelection.Array(),iSelection);
+    }
+
+// ----------------------------------------------------------------------------
+// 2nd phase constructor.
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionPath::ConstructL()
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// 2nd phase constructor.
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionPath::ConstructL(RReadStream& aStream)
+    {
+    InternalizeL(aStream);
+    }
+
+// -----------------------------------------------------------------------------
+// Advances path to next item
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CMPXCollectionPath::operator++()
+    {
+    TBool ret(EFalse);
+    TInt index=Index();
+    if (index < Count()-1)
+        {
+        Set(++index);
+        ret=ETrue;
+        } // else the last one, no more to go and return false
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// Advances path to previous item
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CMPXCollectionPath::operator--()
+    {
+    TBool ret=EFalse;
+    TInt index=Index();
+    if (index>0)
+        {
+        Set(--index);
+        ret=ETrue;
+        } // else the first one, no more to go and return false
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// Sets path to first item
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::SetToFirst()
+    {
+    Set(0);
+    }
+
+// -----------------------------------------------------------------------------
+// Sets path to last item
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::SetToLast()
+    {
+    Set(Count()-1);
+    }
+
+// -----------------------------------------------------------------------------
+// Change current item by index at top level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Set(TInt aIndex)
+    {
+    MPX_ASSERT(Levels());
+    CMPXCollectionPathNode& topLevel = TopLevel();
+    // RArray will panic if aIndex out of bound
+    topLevel.Set(iIds[aIndex], aIndex);
+    }
+
+// -----------------------------------------------------------------------------
+// Change current item by id at top level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Set(const TMPXItemId& aId)
+    {
+    TInt index=IndexOfId(aId);
+    MPX_ASSERT(KErrNotFound!=index && Levels());
+    CMPXCollectionPathNode& topLevel = TopLevel();
+    topLevel.Set(aId, index);
+    }
+
+// -----------------------------------------------------------------------------
+// Set open mode for next level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Set(TMPXOpenMode aMode)
+    {
+    MPX_ASSERT(Levels());
+    TopLevel().Set(aMode);
+    }
+
+// -----------------------------------------------------------------------------
+// Set open attrobutes for next level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Set(const TArray<TMPXAttribute>& aAttrs)
+    { // DEPRECATED
+    TRAP_IGNORE(SetL(aAttrs));
+    }
+
+// -----------------------------------------------------------------------------
+// Set open attrobutes for next level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::SetL(const TArray<TMPXAttribute>& aAttrs)
+    {
+    MPX_ASSERT(Levels());
+    TopLevel().SetL(aAttrs);
+    }
+
+// -----------------------------------------------------------------------------
+//  Select an item by id in the path
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::SelectL(const TMPXItemId& aId)
+    {
+    TInt index=IndexOfId(aId);
+    MPX_ASSERT(KErrNotFound != index);
+    SelectL(index);
+    }
+
+// -----------------------------------------------------------------------------
+//  Select an item by index in the path
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::SelectL(TInt aIndex)
+    {
+    MPX_ASSERT_EX(aIndex>=0 && aIndex<iIds.Count(), EBadArrayIndex);
+    TInt err = iSelection.InsertInOrder(aIndex);
+    if (KErrNone!=err && KErrAlreadyExists!=err)
+        { // ignore duplicated items
+        User::Leave(err);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//  Select an item by index in the path
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::SelectAllL()
+    {
+    iSelection.Reset();
+    for (TInt i=0; i < iIds.Count(); ++i)
+        {
+        iSelection.AppendL(i);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//  Deselects an item by id in the path
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Deselect(const TMPXItemId& aId)
+    {
+    TInt index=IndexOfId(aId);
+    MPX_ASSERT(KErrNotFound != index);
+    Deselect(index);
+    }
+
+// -----------------------------------------------------------------------------
+//  Deselects an item by index in the path
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Deselect(TInt aIndex)
+    {
+    MPX_ASSERT_EX(aIndex>=0 && aIndex<iIds.Count(), EBadArrayIndex);
+    TInt index(iSelection.FindInOrder(aIndex));
+    MPX_ASSERT(KErrNotFound !=index);
+    iSelection.Remove(index);
+    }
+
+// -----------------------------------------------------------------------------
+//  Select an item by index in the path
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::DeselectAll()
+    {
+    iSelection.Reset();
+    }
+
+// -----------------------------------------------------------------------------
+//  Removes an item in the path
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Remove(const TMPXItemId& aId)
+    {
+    TInt index=IndexOfId(aId);
+    MPX_ASSERT(KErrNotFound != index);
+    Remove(index);
+    }
+
+// -----------------------------------------------------------------------------
+//  Removes an item in the path
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Remove(TInt aIndex)
+    {
+    iIds.Remove(aIndex);
+    TInt ret = iSelection.FindInOrder(aIndex);
+    if (KErrNotFound != ret)
+        {
+        iSelection.Remove(ret);
+        TInt count = iSelection.Count();
+        for (TInt i=ret; i<count; i++)
+            {
+            --iSelection[i];
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//  Query selection
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CMPXCollectionPath::IsSelected(const TMPXItemId& aId) const
+    {
+    TBool ret(EFalse);
+    TInt index=IndexOfId(aId);
+    if (KErrNotFound != index)
+        {
+        ret = IsSelected(index);
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+//  Query selection
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CMPXCollectionPath::IsSelected(TInt aIndex) const
+    {
+    return iSelection.FindInOrder(aIndex) != KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+//  Clears selection
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::ClearSelection()
+    {
+    iSelection.Reset();
+    }
+
+// -----------------------------------------------------------------------------
+// Array of currently selected indices
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TArray<TInt> CMPXCollectionPath::Selection() const
+    {
+    return iSelection.Array();
+    }
+
+// -----------------------------------------------------------------------------
+// Current selected IDs
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::SelectionL(RArray<TMPXItemId>& aIds) const
+    {
+    aIds.Reset();
+    TInt idCount(iIds.Count());
+    TInt selCount(iSelection.Count());
+    for  (TInt i=0; i<selCount; ++i)
+        {
+        TInt idIndex(iSelection[i]);
+        if (idIndex < idCount)
+            {
+            aIds.AppendL(iIds[idIndex]);
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Update the item id at a particular index
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Update( TInt aIndex, TMPXItemId& aNewId )
+    {
+    MPX_ASSERT( aIndex >= 0 && aIndex < iIds.Count() );
+    iIds[aIndex] = aNewId;
+    }
+
+// -----------------------------------------------------------------------------
+// Index of current item at top level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CMPXCollectionPath::Index() const
+    {
+    TInt ret(KErrNotFound);
+    if (Levels())
+        {
+        ret = TopLevel().Index();
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// Return current item id at top level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const TMPXItemId& CMPXCollectionPath::Id() const
+    {
+    if (Levels())
+        {
+        return TopLevel().Id();
+        }
+    else
+        {
+        return iInvalidId;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Returns the number of items at top level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CMPXCollectionPath::Count() const
+    {
+    return iIds.Count();
+    }
+
+// -----------------------------------------------------------------------------
+// Returns the open mode for the next level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TMPXOpenMode CMPXCollectionPath::OpenNextMode() const
+    {
+    return Levels() ? TopLevel().OpenMode():EMPXOpenGroupOrPlaylist;
+    }
+
+// -----------------------------------------------------------------------------
+// Returns the open mode for the previous level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TMPXOpenMode CMPXCollectionPath::OpenPreviousMode() const
+    {
+    TInt n=Levels();
+    return n>1?iNodeArray[n-2]->OpenMode():EMPXOpenGroupOrPlaylist;
+    }
+
+// -----------------------------------------------------------------------------
+// Index from id
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CMPXCollectionPath::IndexOfId(const TMPXItemId& aId) const
+    {
+    TInt ret(KErrNotFound);
+    for (TInt i=iIds.Count(); --i>=0; )
+        {
+        if (aId == iIds[i])
+            {
+            ret = i;
+            break;
+            }
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// Return item id at top specific level for a specific item
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const TMPXItemId& CMPXCollectionPath::IdOfIndex( TInt aIndex ) const
+    {
+    if( aIndex >=0 && aIndex < iIds.Count() )
+        {
+        return iIds[aIndex];
+        }
+    else
+        {
+        return iInvalidId;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Return item index at a specific level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CMPXCollectionPath::Index(TInt aLevel) const
+    {
+    MPX_ASSERT(aLevel>=0 && aLevel < Levels());
+    return iNodeArray[aLevel]->Index();
+    }
+
+// -----------------------------------------------------------------------------
+// Return item id at a specific level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const TMPXItemId& CMPXCollectionPath::Id(TInt aLevel) const
+    {
+    if( aLevel < iNodeArray.Count() && aLevel >= 0 )
+        {
+        return iNodeArray[aLevel]->Id();
+        }
+    else
+        {
+        return iInvalidId;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Returns the depth into the collection
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CMPXCollectionPath::Levels() const
+    {
+    return iNodeArray.Count();
+    }
+
+// -----------------------------------------------------------------------------
+// Remove a level from path
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Back()
+    {
+    TInt levels = Levels();
+    MPX_ASSERT(levels > 0);
+    CMPXCollectionPathNode* node = iNodeArray[levels-1];
+    iNodeArray.Remove(levels-1);
+    delete node;
+    iIds.Reset();
+    iSelection.Reset();
+    }
+
+// -----------------------------------------------------------------------------
+// Append a new level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::AppendL(const TArray<TMPXItemId>& aIds)
+    {
+    iIds.Reset();
+    iSelection.Reset();
+    CMPXCollectionPathNode* node(NULL);
+    if (aIds.Count())
+        {
+        ::CopyArrayL(aIds, iIds);
+        node = CMPXCollectionPathNode::NewLC();
+        node->Set(iIds[0], 0);
+        iNodeArray.AppendL(node);
+        CleanupStack::Pop(node);
+        }
+    else
+        {// add a level in order to support back
+        node = CMPXCollectionPathNode::NewLC();
+        node->Set(iInvalidId, KErrNotFound);
+        iNodeArray.AppendL(node);
+        CleanupStack::Pop(node);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Append a new level
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::AppendL(const TMPXItemId& aId)
+    {
+    RArray<TMPXItemId> ids;
+    CleanupClosePushL(ids);
+    ids.AppendL(aId);
+    AppendL(ids.Array());
+    CleanupStack::PopAndDestroy(&ids);
+    }
+
+// -----------------------------------------------------------------------------
+// Append an id
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::InsertL(const TMPXItemId& aId, TInt aPos)
+    {
+    MPX_ASSERT(iIds.Count());
+    iIds.InsertL(aId, aPos);
+    // update the selection
+    for (TInt i=0; i<iSelection.Count(); ++i)
+        {
+        TInt& sel = iSelection[i];
+        if (sel >=aPos)
+            {
+            ++sel;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Resets the collection path object
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::Reset()
+    {
+    iNodeArray.ResetAndDestroy();
+    iIds.Reset();
+    iSelection.Reset();
+    }
+
+// -----------------------------------------------------------------------------
+// Creates a collection path pointing to the container
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CMPXCollectionPath* CMPXCollectionPath::ContainerPathL() const
+    {
+    CMPXCollectionPath* p = CMPXCollectionPath::NewL();
+    CleanupStack::PushL( p );
+
+    TInt count = iNodeArray.Count() - 1;  // Copy up to container level
+    for (TInt i=0; i<count; ++i)
+        {
+        CMPXCollectionPathNode* node =
+            CMPXCollectionPathNode::NewLC(*iNodeArray[i]);
+        p->iNodeArray.AppendL(node);
+        CleanupStack::Pop(node);
+        }
+
+    CleanupStack::Pop( p );
+    return p;
+    }
+
+// -----------------------------------------------------------------------------
+// Update collection path. When a item changed in the collection plugin,
+// collection plugin calls back collection context, which in turn updates
+// its collection paths by calling this function
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CMPXCollectionPath::HandleChange(
+    const TUid& aCollectionId,
+    const TMPXItemId& aId,
+    const TMPXItemId& aDeprecatedId,
+    CMPXCollectionPath::TMPXCollectionPathChange aChange,
+    TInt& aSelection )
+    {
+    TBool updated(EPathUnchanged);
+    aSelection = KErrNotFound;
+
+    if (aChange == CMPXCollectionPath::EAdded)
+        {
+        updated = EPathModified;
+        }
+    else if (aChange == CMPXCollectionPath::EGroupModified )
+        {
+        TInt levels( Levels() );
+        if( levels > 0 )
+            {
+            // Check if the collection id is correct
+            if (iNodeArray[ECollectionUid]->Id() ==
+                TMPXItemId(aCollectionId.iUid) && levels > 1)
+                {
+                // Check if the container level is the one modified
+                if( aId == Id( levels-2 ) )
+                    {
+                    updated = EPathModified;
+                    }
+                }
+            }
+        }
+    else if (aChange == CMPXCollectionPath::EDeleted ||
+             aChange == CMPXCollectionPath::EModified)
+        {
+        TInt levels = Levels();
+        if (levels > 0)
+            {
+            // check collection id level, aka root level
+            if (iNodeArray[ECollectionUid]->Id() ==
+                TMPXItemId(aCollectionId.iUid) && levels > 1)
+                {
+                // check node array except top level and root level.
+                for (TInt i=ECollectionRoot+1; i<levels-1; ++i)
+                    {
+                    if (iNodeArray[i]->Id() == aId ||
+                        (aDeprecatedId != 0 && iNodeArray[i]->Id() == aDeprecatedId))
+                        {
+                        if( aChange == CMPXCollectionPath::EModified &&
+                            aDeprecatedId != 0 )
+                            {
+                            // If the item is modified and the item id is updated
+                            // we simply replace the node level item id with the new
+                            // item id
+                            //
+                            // Continue and check other levels if any other
+                            // levels are using this ID. ie: all songs of an artist
+                            // The item IDs need to be unique across all levels, but
+                            // can have duplicates. This is in the case of a playlist with
+                            // more than 1 instance of a song
+                            //
+                            CMPXCollectionPathNode* node = iNodeArray[i];
+                            node->Set( aId, Index(i) );
+                            updated = EPathModified;
+                            }
+                        else
+                            {
+                            // Trim the path and break out of the loop
+                            aSelection = Index(i);
+                            for (TInt j=Levels()-1; j>i; --j)
+                                {
+                                CMPXCollectionPathNode* node = iNodeArray[j];
+                                iNodeArray.Remove(j);
+                                delete node;
+                                }
+                            updated = EPathClipped;
+                            break;
+                            }
+                        }
+                    }
+                 // Check the top level
+                 if (!updated)
+                    {
+                    TMPXItemId search = aDeprecatedId != 0? aDeprecatedId : aId;
+                    TInt temp(KErrNotFound);
+
+                    // Unmatched ids in the item ID,
+                    // try to look for an exact match first
+                    //
+                    if( search.iId1 != search.iId2 )
+                        {
+                        for (TInt i=iIds.Count(); --i>=0; )
+                            {
+                            if (search == iIds[i] )
+                                {
+                                temp = i;
+                                break;
+                                }
+                            }
+                        }
+                    // Still not found, check for approximate equal
+                    //
+                    if( KErrNotFound == temp )
+                        {
+                        for (TInt i=iIds.Count(); --i>=0; )
+                            {
+                            if (search.ApproxEqual(iIds[i]))
+                                {
+                                temp = i;
+                                break;
+                                }
+                            }
+                        }
+                    if (KErrNotFound != temp)
+                        { // Improvement: only remove item deleted
+                        updated = EPathModified;
+                        aSelection = temp;
+                        }
+                    }
+
+                // Only clean up level if the path has been clipped
+                if (updated == EPathClipped )
+                    {
+                    // Reset top level
+                    iIds.Reset();
+                    iSelection.Reset();
+                    }
+                }
+            }
+        }
+    return updated;
+    }
+
+// -----------------------------------------------------------------------------
+// CMPXCollectionPath::OpenAttributes
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const TArray<TMPXAttribute> CMPXCollectionPath::OpenAttributes() const
+    {
+    MPX_ASSERT(Levels()>0);
+    return TopLevel().OpenAttributes();
+    }
+
+// -----------------------------------------------------------------------------
+// Get top level items
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const TArray<TMPXItemId> CMPXCollectionPath::Items() const
+    {
+    MPX_ASSERT(Levels()>0);
+    return iIds.Array();
+    }
+
+// -----------------------------------------------------------------------------
+// Internalize object
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::InternalizeL(RReadStream& aStream)
+    {
+    (void)aStream.ReadInt32L(); // Discard object type
+    iNodeArray.ResetAndDestroy();
+    ::InternalizeCObjectArrayL(iNodeArray, aStream);
+    iIds.Reset();
+    MPXUser::InternalizeL(iIds, aStream);
+    iSelection.Reset();
+    ::InternalizeL(iSelection, aStream);
+    }
+
+// -----------------------------------------------------------------------------
+// Externalize object
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionPath::ExternalizeL(RWriteStream& aStream) const
+    {
+    aStream.WriteInt32L(MMPXData::EPath);
+    ::ExternalizeL(iNodeArray.Array(), aStream);
+    MPXUser::ExternalizeL(iIds.Array(), aStream);
+    ::ExternalizeL(iSelection.Array(), aStream);
+    }
+
+// -----------------------------------------------------------------------------
+// Top level
+// -----------------------------------------------------------------------------
+//
+CMPXCollectionPathNode& CMPXCollectionPath::TopLevel()
+    {
+    MPX_ASSERT(Levels() > 0);
+    return *iNodeArray[Levels()-1];
+    }
+
+// -----------------------------------------------------------------------------
+// Top level
+// -----------------------------------------------------------------------------
+//
+const CMPXCollectionPathNode& CMPXCollectionPath::TopLevel() const
+    {
+    MPX_ASSERT(Levels() > 0);
+    return *iNodeArray[Levels()-1];
+    }