diff -r 000000000000 -r a2952bb97e68 mpx/commonframework/common/src/mpxcollectionpath.cpp --- /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 +#include +#include +#include +#include +#include +#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& 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 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 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(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& 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 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(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; i0) + { + 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& aAttrs) + { // DEPRECATED + TRAP_IGNORE(SetL(aAttrs)); + } + +// ----------------------------------------------------------------------------- +// Set open attrobutes for next level +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMPXCollectionPath::SetL(const TArray& 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=0 && aIndex CMPXCollectionPath::Selection() const + { + return iSelection.Array(); + } + +// ----------------------------------------------------------------------------- +// Current selected IDs +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMPXCollectionPath::SelectionL(RArray& aIds) const + { + aIds.Reset(); + TInt idCount(iIds.Count()); + TInt selCount(iSelection.Count()); + for (TInt i=0; i= 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& 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 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=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; iiNodeArray.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; iId() == 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 CMPXCollectionPath::OpenAttributes() const + { + MPX_ASSERT(Levels()>0); + return TopLevel().OpenAttributes(); + } + +// ----------------------------------------------------------------------------- +// Get top level items +// ----------------------------------------------------------------------------- +// +EXPORT_C const TArray 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]; + }