photosgallery/viewframework/medialists/src/glxmedialist.cpp
changeset 0 4e91876724a2
child 1 9ba538e329bd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/photosgallery/viewframework/medialists/src/glxmedialist.cpp	Thu Dec 17 08:45:44 2009 +0200
@@ -0,0 +1,1888 @@
+/*
+* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:    List of media items
+*
+*/
+
+
+
+
+#include "glxmedialist.h"
+
+#include <glxcollectionplugintype.hrh>
+
+#include <glxassert.h>
+#include <glxcollectiongeneraldefs.h>
+#include <glxerrorposter.h>
+#include <mpxcollectionmessage.h>
+#include <mpxcollectionmessagedefs.h>
+#include <mpxcollectionutility.h>
+#include <mpxcommandgeneraldefs.h>
+#include <mpxmessagegeneraldefs.h>
+#include <glxtracer.h>
+#include <glxlog.h>
+#include "glxcachemanager.h"
+#include "glxmedialistarray.h"
+#include "glxnavigablelist.h"
+#include "mglxfetchcontext.h"
+#include "mglxmedialistobserver.h"
+#include "glxmediastaticitemdefs.h"
+
+/**
+ * Min & Max wait interval for a modify event, in microseconds
+ * This is to allow thumbnail manager to procees the event first.
+ */
+const TInt KModifyEventMinWaitInterval = 2000000;
+const TInt KModifyEventMaxWaitInterval = 3000000;
+/**
+ * Maximum items count for minimum wait interval.
+ */
+const TInt KMaxItemsCount = 500;
+namespace NGlxMediaList
+    {
+    /**
+     * Interface to notify observers. Allows different notifications to use
+     * the same (complicated) iteration loop
+     */
+    class TNotificationStrategy 
+        {
+        public:
+            TNotificationStrategy( MGlxMediaList& aList )
+                    : iList( aList )
+                {
+                }
+                
+            /** 
+             * Notify observer
+             * @param aObserver Observer to notify 
+             */
+            virtual void NotifyL( MGlxMediaListObserver& aObserver ) = 0;
+        
+        protected:
+            MGlxMediaList& iList;
+        };
+
+    /**
+     * Notification strategy for items being added
+     */
+    class TItemsAddedNotificationStrategy : public TNotificationStrategy 
+        {
+        public:
+            /**
+             * Constructor 
+             * @param aFirstAddedIndex Index of the first item added
+             * @param aCount number of items added
+             * @param aList Media list that sends the notification
+             */
+            TItemsAddedNotificationStrategy( TInt aFirstAddedIndex, 
+                TInt aCount, MGlxMediaList& aList )
+                    : TNotificationStrategy( aList )
+                {
+                iFirstAddedIndex = aFirstAddedIndex;
+                iLastAddedIndex = aFirstAddedIndex + aCount - 1;
+                }
+                
+            // From MGlxNotificationStrategy
+            void NotifyL( MGlxMediaListObserver& aObserver )
+                {
+                aObserver.HandleItemAddedL( iFirstAddedIndex, iLastAddedIndex, 
+                    &iList );
+                }        
+                
+        private:
+            /// Index of the first item added
+            TInt iFirstAddedIndex;
+            /// Index of the last item added
+            TInt iLastAddedIndex;
+        };
+
+    /**
+     * Notification strategy for items being removed
+     */
+    class TItemsRemovedNotificationStrategy : public TNotificationStrategy 
+        {
+        public:
+            /**
+             * Constructor 
+             * @param aFirstRemovedIndex Index of the first item removed
+             * @param aCount number of items removed
+             * @param aList Media list that sends the notification
+             */
+            TItemsRemovedNotificationStrategy( TInt aFirstRemovedIndex, 
+                TInt aCount, MGlxMediaList& aList )
+                    : TNotificationStrategy( aList )
+                {
+                iFirstRemovedIndex = aFirstRemovedIndex;
+                iLastRemovedIndex = aFirstRemovedIndex + aCount - 1;
+                }
+                
+            // From MGlxNotificationStrategy
+            void NotifyL( MGlxMediaListObserver& aObserver )
+                {
+                aObserver.HandleItemRemovedL( iFirstRemovedIndex, 
+                    iLastRemovedIndex, &iList );
+                }        
+                
+        private:
+            /// Index of the first item removed
+            TInt iFirstRemovedIndex;
+            /// Index of the last item removed
+            TInt iLastRemovedIndex;
+        };
+
+    /**
+     * Notification strategy for focus being changed
+     */
+    class TFocusChangedNotificationStrategy : public TNotificationStrategy 
+        {
+        public:
+            /**
+             * Constructor 
+             * @param aFirstRemovedIndex Index of the first item removed
+             * @param aCount number of items removed
+             * @param aList Media list that sends the notification
+             */
+            TFocusChangedNotificationStrategy( NGlxListDefs::TFocusChangeType aType, 
+                TInt aNewIndex, TInt aOldIndex, MGlxMediaList& aList )
+                    : TNotificationStrategy( aList )
+                {
+                iType = aType;
+                iNewIndex = aNewIndex;
+                iOldIndex = aOldIndex;
+                }
+                
+            // From MGlxNotificationStrategy
+            void NotifyL( MGlxMediaListObserver& aObserver )
+                {
+                aObserver.HandleFocusChangedL( iType, iNewIndex, iOldIndex, &iList );
+                }        
+                
+        private:
+            /// Focus change type
+            NGlxListDefs::TFocusChangeType iType;
+            /// New focus index
+            TInt iNewIndex;
+            /// Old focus index
+            TInt iOldIndex;
+        };
+
+    /**
+     * Notification strategy for selection being changed
+     */
+    class TItemSelectedNotificationStrategy : public TNotificationStrategy 
+        {
+        public:
+            /**
+             * Constructor 
+             * @param aIndex Index of item being selected/deselected
+             * @param aSelected Selection/deselection info
+             * @param aList Media list that sends the notification
+             */
+            TItemSelectedNotificationStrategy( TInt aIndex, TBool aSelected,
+                MGlxMediaList& aList )
+                    : TNotificationStrategy( aList )
+                {
+                iIndex = aIndex;
+                iSelected = aSelected;
+                }
+                
+            // From MGlxNotificationStrategy
+            void NotifyL( MGlxMediaListObserver& aObserver )
+                {
+                aObserver.HandleItemSelectedL( iIndex, iSelected, &iList );
+                }        
+                
+        private:
+            /// Index of item being selected/deselected
+            TInt iIndex;
+            /// Selection/deselection info
+            TBool iSelected;
+        };    
+
+    /**
+     * Notification strategy for command being completed
+     */
+    class TCommandCompletedNotificationStrategy : public TNotificationStrategy 
+        {
+        public:
+            /**
+             * Constructor 
+             * @param aSessionId Session id of client that issued the command
+             * @param aCommand Command which was completed
+             * @param aError Error code from execution of the command
+             * @param aList Media list that sends the notification
+             */
+            TCommandCompletedNotificationStrategy( TAny* aSessionId, 
+                CMPXCommand* aCommand, TInt aError, MGlxMediaList& aList )
+                    : TNotificationStrategy( aList )
+                {
+                iSessionId = aSessionId;
+                iCommand = aCommand;
+                iError = aError;
+                }
+                
+            // From MGlxNotificationStrategy
+            void NotifyL( MGlxMediaListObserver& aObserver )
+                {
+                /// @todo: make this call leaving
+                aObserver.HandleCommandCompleteL( iSessionId, iCommand, iError, &iList );
+                }        
+
+        private:
+            /// Session id of client that issued the command
+            TAny* iSessionId;
+            /// Command which was completed
+            CMPXCommand* iCommand;
+            /// Error code 
+            TBool iError;
+        };            
+        
+        
+
+    /**
+     * Notification strategy for list population
+     */
+    class TListPopulatedNotificationStrategy : public TNotificationStrategy 
+        {
+        public:
+            /**
+             * Constructor 
+             * @param aList Media list that sends the notification
+             */
+            TListPopulatedNotificationStrategy ( MGlxMediaList& aList )
+                    : TNotificationStrategy( aList )
+                {
+                }
+                
+            // From MGlxNotificationStrategy
+            void NotifyL( MGlxMediaListObserver& aObserver )
+                {
+                aObserver.HandlePopulatedL( &iList );
+                }        
+        }; 
+
+    /**
+     * Notification strategy for messages
+     */
+    class TMessageNotificationStrategy : public TNotificationStrategy
+        {
+        public:
+            /**
+             * Constructor
+             * @param aList Media list that sends the notification
+             */
+            TMessageNotificationStrategy ( const CMPXMessage& aMessage, MGlxMediaList& aList ) :
+                    TNotificationStrategy( aList ),
+                    iMessage( aMessage )
+                {
+                }
+
+            // From MGlxNotificationStrategy
+            void NotifyL( MGlxMediaListObserver& aObserver )
+                {
+                aObserver.HandleMessageL( iMessage, &iList );
+                }
+
+        private:
+            /// Message which was received
+            const CMPXMessage& iMessage;
+        };
+    } // namespace NGlxMediaList
+    
+using namespace NGlxMediaList;
+
+// -----------------------------------------------------------------------------
+// Returns a new/existing media list interface
+// -----------------------------------------------------------------------------
+CGlxMediaList* CGlxMediaList::InstanceL(const CMPXCollectionPath& aPath, 
+        const TGlxHierarchyId& aHierarchyId, CMPXFilter* aFilter)
+    {
+    TRACER("CGlxMediaList::InstanceL" );
+    
+    CGlxMediaListArray* mediaListArray = CGlxMediaListArray::InstanceL();
+    CleanupClosePushL(*mediaListArray);
+    
+    RPointerArray<CGlxMediaList>& mediaLists =  mediaListArray->Array();
+
+    TInt matchIndex = KErrNotFound;
+    CGlxMediaList* mediaListInstance = NULL; // List to return
+
+    // Try to find an existing media list to return (by matching the path)
+    TInt listCount = mediaLists.Count();
+    for (TInt count = 0; count < listCount; ++count)
+        {
+        CGlxMediaList* mediaList = mediaLists[count];
+
+        // See if path's and hierarchy id's match
+        // Filter is ignored
+        if (mediaList->Equals(aPath) && (mediaList->iHierarchyId == aHierarchyId))
+            {
+            // Found a match
+            matchIndex = count;
+            mediaListInstance = mediaList;
+            break;
+            }
+        }
+
+    // Create a new media list if could not use an existing one
+    if (matchIndex == KErrNotFound)
+        {
+        __ASSERT_DEBUG(!mediaListInstance, Panic(EGlxPanicAlreadyInitialised));
+
+        mediaListInstance = CGlxMediaList::NewLC(aHierarchyId);
+
+        // Set specified filter (if any) before opening the collection to path
+        mediaListInstance->SetFilterL(aFilter);
+        mediaListInstance->OpenL(aPath);
+
+        // Insert media list as highest priority
+        mediaLists.InsertL(mediaListInstance, 0);
+        CleanupStack::Pop(mediaListInstance);
+        }
+    else
+        {
+        __ASSERT_DEBUG(mediaListInstance, Panic(EGlxPanicNullPointer));
+
+        // Match found, set as highest priority
+        mediaLists.InsertL(mediaListInstance, 0);
+        mediaLists.Remove(matchIndex + 1);
+        }
+
+    mediaListInstance->AddReference(); // Add user
+
+    CleanupStack::PopAndDestroy(mediaListArray);
+    
+    return mediaListInstance;
+    }
+
+// -----------------------------------------------------------------------------
+// Gives an array of all media lists in current use
+// -----------------------------------------------------------------------------
+RPointerArray<CGlxMediaList>& CGlxMediaList::MediaListsL()
+    {
+    TRACER("CGlxMediaList::MediaListsL" );
+    
+    CGlxMediaListArray* mediaListArray = CGlxMediaListArray::InstanceL();
+    RPointerArray<CGlxMediaList>& array = mediaListArray->Array();
+    mediaListArray->Close();
+    return array;
+    }
+
+// -----------------------------------------------------------------------------
+// OfferMedia
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::OfferMedia(const TGlxIdSpaceId& aIdSpaceId, CGlxMedia* aMedia) 
+    {
+    TRACER("CGlxMediaList::OfferMedia" );
+
+    // try to find the matching item in this list
+    TInt index = Index( aIdSpaceId, aMedia->Id() );
+    // if matching item found, link media object
+    if ( KErrNotFound != index )
+        {
+        TGlxMedia& item = iItemList->Item( index );
+
+        // static items should not be offered
+        if ( !item.IsStatic() )
+            {
+            item.SetMedia( aMedia, *this, index );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// NotifyThumbnailAvailableL
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleAttributesAvailableL(TInt aIndex, 
+        const RArray<TMPXAttribute>& aAttributes)
+    {
+    TRACER("CGlxMediaList::HandleAttributesAvailableL" );
+
+    __ASSERT_DEBUG(aIndex >= 0, Panic(EGlxPanicLogicError)); // Must exist
+    // Need to get exact count of iItemListObservers at
+    // every iteration because it is possible that 
+    // RemoveMediaListObserver might call during this iteration
+    for (TInt i = 0; i < iItemListObservers.Count(); i++)
+        {
+        iItemListObservers[i]->HandleAttributesAvailableL(aIndex, aAttributes, this);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Ask if the list has any requests to place
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::AttributeRequestL(RArray<TInt>& aItemIndexes,
+		RArray<TGlxMediaId>& aItemIds, 
+        RArray<TMPXAttribute>& aAttributes, 
+        CMPXAttributeSpecs*& aDetailedSpecs) const
+    {
+    TRACER("CGlxMediaList::AttributeRequestL" );
+    
+    // Find the highest priority context that has something to request
+    TInt count = iContexts.Count();
+    for (TInt i = 0; i < count; i++)
+        {
+        // Determine items (referenced by index) to request attributes for
+        iContexts[i].iContext->AttributeRequestL(this, aItemIndexes, aAttributes, aDetailedSpecs);
+
+        // Map item indices to item Ids
+        TInt itemIndicesCount = aItemIndexes.Count();
+        for (TInt itemIndicesCounter = 0; itemIndicesCounter < itemIndicesCount; ++itemIndicesCounter)
+            {
+            const TGlxMedia& item = iItemList->Item( aItemIndexes[itemIndicesCounter] );
+            if (!item.IsStatic())
+                {
+                aItemIds.AppendL( item.Id() );
+                }
+            }
+
+        // break if context has something to request
+        if (itemIndicesCount > 0)
+            {
+            break;
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// AllAttributesL
+// ---------------------------------------------------------------------------
+//
+void CGlxMediaList::GetRequiredAttributesL(TInt aIndex, RArray<TMPXAttribute>& aAttributes)
+    {
+    TRACER("CGlxMediaList::GetRequiredAttributesL" );
+    
+    TLinearOrder<TMPXAttribute> orderer (&AttributeOrder);
+
+    // Determine all attributes to request for an item, for all contexts
+    TInt contextCount = iContexts.Count();
+    for ( TInt contextIndex = 0; contextIndex < contextCount; contextIndex++ )
+        {
+        const MGlxFetchContext* context = iContexts[contextIndex].iContext;
+        if ( context )
+            {
+            // Determine all attributes to request for an item, for this context
+            context->AllAttributesL(this, aIndex, aAttributes);
+
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// AttributeOrder
+// ---------------------------------------------------------------------------
+//
+TInt CGlxMediaList::AttributeOrder(const TMPXAttribute& aItem1, 
+        const TMPXAttribute& aItem2) 
+    {
+    TRACER("CGlxMediaList::AttributeOrder");
+            
+    TInt contentId1 = aItem1.ContentId();
+    TInt contentId2 = aItem2.ContentId();
+
+    if (contentId1 < contentId2) 
+        {
+        return -1;
+        }
+
+    if (contentId1 > contentId2) 
+        {
+        return 1;
+        }
+
+    TUint attributeId1 = aItem1.AttributeId();
+    TUint attributeId2 = aItem2.AttributeId();
+
+    if (attributeId1 < attributeId2) 
+        {
+        return -1;
+        }
+
+    if (attributeId1 > attributeId2) 
+        {
+        return 1;
+        }
+
+    return 0;
+    }
+
+// ---------------------------------------------------------------------------
+// AttributeOrderReversed
+// ---------------------------------------------------------------------------
+//
+TInt CGlxMediaList::AttributeOrderReversed(const TMPXAttribute& aItem1, 
+        const TMPXAttribute& aItem2) 
+    {
+    TRACER("CGlxMediaList::AttributeOrderReversed");
+    
+    return -AttributeOrder(aItem1, aItem2);
+    }
+
+// ---------------------------------------------------------------------------
+// Remore references to the media object
+// ---------------------------------------------------------------------------
+//
+void CGlxMediaList::RemoveReference( TInt aIndex )
+    {
+    TRACER( "CGlxMediaList::RemoveReference" );
+    GLX_ASSERT_DEBUG( iItemList, Panic( EGlxPanicNotInitialised ), 
+        "not ready to remove references" );
+    
+    GLX_LOG_INFO1( "CGlxMediaList::RemoveReference %d", aIndex );
+    iItemList->RemoveReference( aIndex );
+    }
+
+// ---------------------------------------------------------------------------
+// HandleError
+// ---------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleError(TInt aError)
+    {
+    TRACER( "CGlxMediaList::HandleError");    
+    GLX_LOG_INFO1( "CGlxMediaList::HandleError %d", aError );
+    TInt obsCount = iItemListObservers.Count();
+    for (TInt obsIdx = 0; obsIdx < obsCount; ++obsIdx)
+        {
+        iItemListObservers[obsIdx]->HandleError(aError);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Releases a media list interface
+// -----------------------------------------------------------------------------
+void CGlxMediaList::Close()
+    {
+    TRACER( "CGlxMediaList::Close" );
+    
+    RPointerArray<CGlxMediaList>& mediaLists = iMediaListArray->Array();
+
+    TInt listCount = mediaLists.Count();
+    for (TInt count = 0; count < listCount; ++count)
+        {
+        CGlxMediaList* mediaList = mediaLists[count];
+
+        if (mediaList == this)
+            {
+            TInt referenceCount = mediaList->RemoveReference();
+            if (referenceCount == 0)
+                {
+                mediaLists.Remove(count);
+                mediaLists.Compress();
+
+                delete mediaList;
+                break;
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Id
+// From MGlxMediaList
+// -----------------------------------------------------------------------------
+//
+TGlxMediaListId CGlxMediaList::Id() const
+    {
+    TRACER( "CGlxMediaList::Id" );
+    
+    return TGlxMediaListId((unsigned int)(void*)this);	
+    }
+
+// -----------------------------------------------------------------------------
+// Count
+// From MGlxMediaList
+// -----------------------------------------------------------------------------
+//
+TInt CGlxMediaList::Count(NGlxListDefs::TCountType aType) const
+    {
+    TRACER("CGlxMediaList::Count");
+    
+    return iItemList->Count( aType );    
+    }
+
+// -----------------------------------------------------------------------------
+// FocusIndex
+// From MGlxMediaList
+// -----------------------------------------------------------------------------
+//
+TInt CGlxMediaList::FocusIndex() const
+    {
+    TRACER("CGlxMediaList::FocusIndex");
+    
+    return iItemList->FocusIndex();    
+    }
+
+// -----------------------------------------------------------------------------
+// SetFocusL
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::SetFocusL(NGlxListDefs::TFocusSetType aType, TInt aValue)
+    {
+    TRACER("CGlxMediaList::SetFocusL");
+    
+    GLX_LOG_INFO1( "CGlxMediaList::SetFocusL %d", aValue );
+    iItemList->SetFocus( aType, aValue );
+    }
+
+// -----------------------------------------------------------------------------
+// Item
+// From MGlxMediaList
+// -----------------------------------------------------------------------------
+//
+const TGlxMedia& CGlxMediaList::Item(TInt aIndex) const
+    {
+    TRACER("CGlxMediaList::Item");
+    
+    return iItemList->Item( aIndex );    
+    }
+
+// -----------------------------------------------------------------------------
+// Index
+// From MGlxMediaList
+// -----------------------------------------------------------------------------
+//
+TInt CGlxMediaList::Index(const TGlxIdSpaceId& aIdSpaceId, const TGlxMediaId& aId) const
+    {
+    TRACER("CGlxMediaList::Index");
+    
+    return iItemList->Index( aIdSpaceId, aId );    
+    }
+
+// -----------------------------------------------------------------------------
+// AddMediaListObserverL
+// From MGlxMediaList
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::AddMediaListObserverL(MGlxMediaListObserver* aObserver)
+    {
+    TRACER("CGlxMediaList::AddMediaListObserverL");    
+    GLX_LOG_INFO1( "CGlxMediaList::AddMediaListObserverL(0x%x)", aObserver );
+
+    // Make sure the observer is not already in the array
+    __ASSERT_DEBUG(iItemListObservers.Find(aObserver) == -1, Panic(EGlxPanicIllegalArgument)); // Observer already added
+
+    iItemListObservers.AppendL(aObserver);
+    }
+
+// -----------------------------------------------------------------------------
+// RemoveMediaListObserver
+// From MGlxMediaList
+// -----------------------------------------------------------------------------
+//	
+void CGlxMediaList::RemoveMediaListObserver(MGlxMediaListObserver* aObserver)
+    {
+    TRACER("CGlxMediaList::RemoveMediaListObserver");    
+    GLX_LOG_INFO1( "CGlxMediaList::RemoveMediaListObserver(0x%x)", aObserver );
+
+    TInt index = iItemListObservers.Find(aObserver);
+
+    // Make sure the observer is in the array
+    // LOG THIS! __ASSERT_DEBUG(index != -1, Panic(EGlxPanicIllegalArgument)); // No such observer
+
+    if (index != KErrNotFound) 
+        {
+        iItemListObservers.Remove(index);	
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// AddContextL
+// From MGlxMediaList
+// -----------------------------------------------------------------------------
+//	
+void CGlxMediaList::AddContextL(const MGlxFetchContext* aContext, 
+        TInt aPriority)
+    {
+    TRACER("CGlxMediaList::AddContextL");    
+    GLX_LOG_INFO1( "CGlxMediaList::AddContextL(0x%x)", aContext );
+
+    if (!aContext)
+        {
+        return;
+        }
+
+    // Add the new context in priority order
+    TContext context;
+    context.iContext = aContext;
+    context.iPriority = aPriority;
+
+#ifdef _DEBUG
+
+    // Make sure no duplicate entries
+    TIdentityRelation<CGlxMediaList::TContext> match (&CGlxMediaList::TContext::Match);
+    __ASSERT_DEBUG(iContexts.Find(context, match) == KErrNotFound, Panic(EGlxPanicAlreadyAdded));
+
+#endif // _DEBUG
+
+    TLinearOrder<CGlxMediaList::TContext> orderer (&CGlxMediaList::TContext::Compare);
+    TInt ret = iContexts.InsertInOrderAllowRepeats(context, orderer); 
+    User::LeaveIfError(ret);
+
+    iManager->HandleWindowChangedL(this);
+    }
+
+// -----------------------------------------------------------------------------
+// RemoveContext
+// From MGlxMediaList
+// -----------------------------------------------------------------------------
+//	
+void CGlxMediaList::RemoveContext(const MGlxFetchContext* aContext)
+    {
+    TRACER("CGlxMediaList::RemoveContext");    
+    GLX_LOG_INFO1( "CGlxMediaList::RemoveContext(0x%x)", aContext );
+
+    if (!aContext)
+        {
+        return;
+        }
+
+    TIdentityRelation<CGlxMediaList::TContext> match (&CGlxMediaList::TContext::Match);
+    TContext context;
+    context.iContext = aContext;
+    context.iPriority = 0;
+    TInt index = iContexts.Find(context, match);
+
+    // remove the context if it was found, just ignore if its not found
+    if (index != KErrNotFound) 
+        {
+        iContexts.Remove(index);
+        // notify cache manager: garbage collection needs to be run to free the 
+        // items that the removed context required
+        TRAP_IGNORE( iManager->HandleWindowChangedL( this ) );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Returns the isolated collection, that is used by this media list
+// -----------------------------------------------------------------------------
+//
+MMPXCollection& CGlxMediaList::Collection() const
+    {
+    TRACER("CGlxMediaList::Collection");
+    __ASSERT_DEBUG(iCollectionUtility != NULL, Panic(EGlxPanicNullPointer));
+    return iCollectionUtility->Collection();
+    }
+
+// -----------------------------------------------------------------------------
+// Returns the current path
+// -----------------------------------------------------------------------------
+CMPXCollectionPath* CGlxMediaList::PathLC(NGlxListDefs::TPathType aType) const
+    {
+    TRACER("CGlxMediaList::PathLC");  
+
+    CMPXCollectionPath* path = CMPXCollectionPath::NewL();
+    CleanupStack::PushL(path);
+
+    // Add navigation to parent
+    PathPopulateParentL( *path );
+
+    if ( aType == NGlxListDefs::EPathAllOrSelection ||
+         aType == NGlxListDefs:: EPathFocusOrSelection )
+        {
+        // If selection exists, add only selection
+        // Otherwise add all items or focused item
+        if ( iItemList->SelectedItemIndices().Count() > 0 )
+            {
+            PathPopulateSelectionL( *path );
+            }
+        else
+            {
+            if ( aType == NGlxListDefs::EPathAllOrSelection )
+                {
+                PathPopulateAllL( *path );
+                }
+            else if ( aType == NGlxListDefs:: EPathFocusOrSelection )
+                {
+                PathPopulateFocusL( *path );
+                }
+            }
+        }
+
+    return path;
+    }
+
+// -----------------------------------------------------------------------------
+// Determines if an item has been selected
+// -----------------------------------------------------------------------------
+TBool CGlxMediaList::IsSelected(TInt aIndex) const
+    {
+    TRACER("CGlxMediaList::IsSelected");    
+    GLX_LOG_INFO1( "CGlxMediaList::IsSelected %d", aIndex );
+    return iItemList->IsSelected( aIndex );
+    }
+
+// -----------------------------------------------------------------------------
+// Handles item selection/deselection
+// -----------------------------------------------------------------------------
+void CGlxMediaList::SetSelectedL(TInt aIndex, TBool aSelected)
+    {
+    TRACER("CGlxMediaList::SetSelectedL");    
+    GLX_LOG_INFO2( "CGlxMediaList::SetSelectedL %d:%d", aIndex, aSelected );
+    iItemList->SetSelectedL( aIndex, aSelected );
+    }
+
+// -----------------------------------------------------------------------------
+// Returns selection count
+// -----------------------------------------------------------------------------
+TInt CGlxMediaList::SelectionCount() const
+    {
+    TRACER("CGlxMediaList::SelectionCount");
+    
+    return iItemList->SelectedItemIndices().Count();
+    }
+
+// -----------------------------------------------------------------------------
+// Returns selected item index from selection
+// -----------------------------------------------------------------------------
+TInt CGlxMediaList::SelectedItemIndex(TInt aSelectionIndex) const
+    {
+    TRACER("CGlxMediaList::SelectedItemIndex");    
+    GLX_LOG_INFO1( "CGlxMediaList::SelectedItemIndex %d", aSelectionIndex );
+    return iItemList->SelectedItemIndices()[ aSelectionIndex ];
+    }
+
+// -----------------------------------------------------------------------------
+// Sends a command to the collection
+// -----------------------------------------------------------------------------
+void CGlxMediaList::CommandL(CMPXCommand& aCommand)
+    {
+    TRACER("CGlxMediaList::CommandL");
+
+    // Multiple commands should not happen
+    __ASSERT_DEBUG( !iCommandPending, Panic( EGlxPanicLogicError ) );
+
+    // Send the command
+    Collection().CommandL( aCommand );
+
+    // Use the sessionId to indicate that a command is pending
+    __ASSERT_DEBUG( aCommand.IsSupported( KMPXCommandGeneralSessionId ), 
+                    Panic( EGlxPanicLogicError ) );
+
+    iCommandPending = aCommand.ValueTObjectL<TAny*>( KMPXCommandGeneralSessionId );
+    }
+
+// -----------------------------------------------------------------------------
+// Cancels a command on the collection
+// -----------------------------------------------------------------------------
+void CGlxMediaList::CancelCommand()
+    {
+    TRACER("CGlxMediaList::CancelCommand");
+
+    // Cancelling a non issued command should not happen
+    __ASSERT_DEBUG( iCommandPending, Panic( EGlxPanicLogicError ) );
+
+    // Cancel command
+    Collection().CancelRequest();
+    iCommandPending = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// Specify filter on the media list
+// -----------------------------------------------------------------------------
+void CGlxMediaList::SetFilterL(CMPXFilter* aFilter)
+    {
+    TRACER("CGlxMediaList::SetFilterL");
+    
+    // This method now takes a copy of the filter. It does not take ownership of aFilter
+    
+    CMPXFilter* tempFilter = NULL;
+    
+    if (aFilter)
+        {
+        // Create copy of filter
+        tempFilter = CMPXFilter::NewL(*aFilter);
+        CleanupStack::PushL(tempFilter);
+        }
+    
+    // Set filter on the collection
+    Collection().SetFilterL(aFilter);
+
+    // Re-open collection if filter has been applied and list is already populated
+    if ( iIsPopulated )
+        {
+        ReOpenL();
+
+        iReorderPending = ETrue;
+        }
+
+    delete iFilter;
+    iFilter = NULL;
+
+    if (aFilter)
+        {
+        // SetFilterL did not leave. So take ownership of copy
+        CleanupStack::Pop(tempFilter);
+        iFilter = tempFilter;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Returns filter on the media list
+// -----------------------------------------------------------------------------
+CMPXFilter* CGlxMediaList::Filter() const
+    {
+    TRACER("CGlxMediaList::Filter");
+    
+    return iFilter;
+    }
+
+// ---------------------------------------------------------------------------
+// IdSpaceId
+// ---------------------------------------------------------------------------
+//
+TGlxIdSpaceId CGlxMediaList::IdSpaceId(TInt aIndex) const
+    {
+    TRACER("CGlxMediaList::IdSpaceId");
+    
+    ///@todo Delegate id space to item list.
+    if (Count() && iItemList->Item(aIndex).IsStatic())
+    	{
+    	return KGlxStaticItemIdSpaceId;
+    	}
+    else
+    	{
+    	return iIdSpaceId;
+    	}
+    }
+
+// ---------------------------------------------------------------------------
+// CGlxMediaList::IsPopulated()
+// ---------------------------------------------------------------------------
+//
+TBool CGlxMediaList::IsPopulated() const
+    {
+    TRACER("CGlxMediaList::IsPopulated");
+    
+    return iIsPopulated;
+    }
+
+
+// -----------------------------------------------------------------------------
+// Add a static item
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::AddStaticItemL( CGlxMedia* aStaticItem, 
+        NGlxListDefs::TInsertionPosition aTargetPosition )
+    {
+    TRACER("CGlxMediaList::AddStaticItemL");    
+    
+    iItemList->AddStaticItemL( aStaticItem, aTargetPosition );
+    }
+
+// -----------------------------------------------------------------------------
+// Remove a static item
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::RemoveStaticItem(const TGlxMediaId& aItemId)
+	{
+	TRACER("CGlxMediaList::RemoveStaticItem");
+    
+    iItemList->Remove(TGlxIdSpaceId(KGlxStaticItemIdSpaceId), aItemId);
+	}
+
+// -----------------------------------------------------------------------------
+// Enable/disable static items
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::SetStaticItemsEnabled( TBool aEnabled )
+    {
+    TRACER("CGlxMediaList::SetStaticItemsEnabled");
+    
+    iItemList->SetStaticItemsEnabled( aEnabled );
+    }
+    
+// -----------------------------------------------------------------------------
+// return ETrue if static items are enabled
+// -----------------------------------------------------------------------------
+//
+TBool CGlxMediaList::IsStaticItemsEnabled() const
+    {
+    TRACER("CGlxMediaList::IsStaticItemsEnabled");
+        
+    return iItemList->IsStaticItemsEnabled();
+    }
+
+// -----------------------------------------------------------------------------
+// Sets the initial focus position
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::SetFocusInitialPosition(NGlxListDefs::TFocusInitialPosition aFocusInitialPosition)
+    {
+    TRACER("CGlxMediaList::SetFocusInitialPosition");    
+    
+    iItemList->SetFocusInitialPosition( aFocusInitialPosition );
+    }
+
+// -----------------------------------------------------------------------------
+// Resets the focus to the initial position
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::ResetFocus()
+    {
+    TRACER("CGlxMediaList::ResetFocus");
+        
+    iItemList->ResetFocus();
+    }
+
+// ---------------------------------------------------------------------------
+// From MMPXCollectionObserver
+// Handle collection message
+// ---------------------------------------------------------------------------
+void CGlxMediaList::HandleCollectionMessageL(const CMPXMessage& aMessage)
+    {
+    TRACER("CGlxMediaList::HandleCollectionMessageL");
+    
+    
+    if (aMessage.IsSupported(KMPXMessageGeneralId))
+        {
+        TInt messageId = aMessage.ValueTObjectL<TInt>(KMPXMessageGeneralId);
+        if ( messageId == KMPXMessageGeneral )
+            {
+            if (!aMessage.IsSupported(KMPXMessageGeneralEvent) ||
+                !aMessage.IsSupported(KMPXMessageGeneralType))
+                {
+                return;
+                }
+
+            TInt messageEvent = aMessage.ValueTObjectL<TInt>(KMPXMessageGeneralEvent);
+            if (messageEvent == TMPXCollectionMessage::EPathChanged)
+                {
+                GLX_LOG_INFO("CGlxMediaList::HandleCollectionMessageL() EPathChanged");
+
+                TInt messageType = aMessage.ValueTObjectL<TInt>(KMPXMessageGeneralType);
+                switch (messageType)
+                    {
+                    case EMcPathChangedByOpen:
+                        {
+                        HandleOpenL();
+                        break;
+                        }
+                    case EMcPathChangedByCollectionChange:
+                        {
+                        break;
+                        }
+                    default:
+                        __ASSERT_DEBUG(EFalse, Panic(EGlxPanicLogicError));
+                        break;
+                    }
+                }
+            }
+        else if (messageId == KMPXMessageIdItemChanged)
+            {
+            if (!aMessage.IsSupported(KMPXMessageMediaGeneralCategory) ||
+                !aMessage.IsSupported(KMPXMessageChangeEventType) ||
+                !aMessage.IsSupported(KMPXMessageMediaGeneralId))
+                {
+                return;
+                }
+
+            TMPXChangeEventType messageType = aMessage.ValueTObjectL<TMPXChangeEventType>(KMPXMessageChangeEventType);
+            switch (messageType)
+                {
+                case EMPXItemModified:
+                    {
+                    RArray<TMPXAttribute> attributes;
+                    CleanupClosePushL(attributes);
+                    TMPXItemId itemId = aMessage.ValueTObjectL<TMPXItemId>(KMPXMessageMediaGeneralId);
+                    HandleItemModifiedL(itemId, attributes);
+                    CleanupStack::PopAndDestroy(&attributes);
+                    iManager->HandleWindowChangedL(this);
+
+                    // Drop through to perform sync, in case the order has changed
+                    }
+                case EMPXItemInserted:
+                case EMPXItemDeleted:
+                default:
+                    // Items have changed, determine whether to sync now
+                    // or resync later if a sync is already pending after opening
+                    if ( iSyncStatus == KNonePending )
+                        {
+                        ReOpenL(); // force re-opens
+
+                        iSyncStatus = KSyncPending;
+                        }
+                    else
+                        {
+                        iSyncStatus = KResyncPending;
+                        }
+                    break;
+                }
+            }
+        else // received message isn't handled by media list
+            {
+            // Inform observers of message
+            TMessageNotificationStrategy strategy( aMessage, *this );
+            NotifyObservers( strategy );
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From MMPXCollectionObserver
+// Handles the collection entries being opened. Typically called
+// when client has Open()'d a folder
+// ---------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleOpenL(const CMPXMedia& /*aEntries*/, TInt /*aIndex*/,
+        TBool /*aComplete*/, TInt aError)
+    {
+    TRACER("CGlxMediaList::HandleOpenL");
+    
+    /// @todo Need to handle errors
+    __ASSERT_DEBUG(aError == KErrNone, Panic(EGlxPanicLogicError));
+    HandleOpenL();
+    }
+
+// -----------------------------------------------------------------------------
+// HandleOpenL
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleOpenL()
+    {
+    TRACER("CGlxMediaList::HandleOpenL");
+
+    // if we dont have the item list constructed
+    // dont do anything as it would lead to a crash
+    if( iItemList )
+        {
+        PopulateL();
+        // Sync (via population) has now occured,
+        // determine whether to resync if one is pending
+        if ( iSyncStatus == KResyncPending )
+            {
+            ReOpenL();
+
+            iSyncStatus = KSyncPending;
+            }
+
+        iManager->HandleWindowChangedL(this);
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From MMPXCollectionObserver
+// Handles the collection entries being opened. Typically called
+// when client has Open()'d an item. Client typically responds by
+// 'playing' the item
+// ---------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleOpenL(const CMPXCollectionPlaylist& /*aPlaylist*/,
+        TInt /*aError*/)
+    {
+    TRACER("CGlxMediaList::HandleOpenL" );
+    __ASSERT_DEBUG(EFalse, Panic(EGlxPanicLogicError));
+    }
+
+// ---------------------------------------------------------------------------
+// From MMPXCollectionObserver
+// Handle extended media properties
+// ---------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleCollectionMediaL(const CMPXMedia& aMedia, TInt aError)
+    {
+    TRACER("CGlxMediaList::HandleCollectionMediaL" );
+
+    iManager->HandleCollectionMediaL(iIdSpaceId, aMedia, aError);
+    }
+
+// ---------------------------------------------------------------------------
+// From MMPXCollectionObserver
+// Handle command completion
+// ---------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleCommandComplete(CMPXCommand* aCommandResult, TInt aError)
+    {
+    TRACER("CGlxMediaList::HandleCommandComplete" );
+
+    // SessionId is stored in iCommandPending
+    TAny* sessionId = iCommandPending;
+
+    // Clear command pending flag here, in case an observer issues another command
+    iCommandPending = NULL;
+
+    TCommandCompletedNotificationStrategy strategy( sessionId, aCommandResult, aError, *this );
+    NotifyObservers( strategy );
+    }
+
+// -----------------------------------------------------------------------------
+// NewLC
+// -----------------------------------------------------------------------------
+//
+CGlxMediaList* CGlxMediaList::NewLC(const TGlxHierarchyId& aHierarchyId)
+    {
+    TRACER("CGlxMediaList::NewLC" );
+    
+    CGlxMediaList* obj = new (ELeave) CGlxMediaList(aHierarchyId);
+    CleanupStack::PushL(obj);
+    obj->ConstructL();
+    return obj;
+    }
+
+// -----------------------------------------------------------------------------
+// Constructor
+// -----------------------------------------------------------------------------
+//
+CGlxMediaList::CGlxMediaList(const TGlxHierarchyId& aHierarchyId) :
+    iIdSpaceId(KGlxIdNone),
+    iHierarchyId(aHierarchyId), iVisibleWindowIndex( 0 )
+    {
+    TRACER("CGlxMediaList::CGlxMediaList");
+    
+    __ASSERT_DEBUG(KErrNotFound == -1, Panic(EGlxPanicDebugUnexpectedError));
+    }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CGlxMediaList::~CGlxMediaList()
+    {
+    TRACER("CGlxMediaList::~CGlxMediaList" );
+    
+    if (iCollectionUtility)
+        {
+        iCollectionUtility->Close();
+        }
+
+    iErrorPoster->Close();
+
+    iItemListObservers.Close();
+    __ASSERT_DEBUG(iContexts.Count() == 0, Panic(EGlxPanicLogicError)); // Release all contexts
+    iContexts.Close();
+    iPath.Close();
+
+    delete iItemList;
+    delete iFilter;
+    
+    if (iMediaListArray)
+    	{
+    	iMediaListArray->Close();
+    	}
+    
+    iCountAttributes.Close();
+
+    // close the manager last as it may delete the cache and thus the CGlxMedia 
+    // objects.. item list destructor manipulates those objects so need to do it in this order
+	if(iManager)
+		{
+		iManager->HandleListDeleted( this );
+		iManager->Close();
+		}    
+    }
+
+// -----------------------------------------------------------------------------
+// ConstructL
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::ConstructL()
+    {
+    TRACER("CGlxMediaList::ConstructL" );
+    
+    iCollectionUtility = MMPXCollectionUtility::NewL(this, KMcModeIsolated);
+    iManager = CGlxCacheManager::InstanceL();
+    iErrorPoster = CGlxErrorPoster::InstanceL();
+    iMediaListArray = CGlxMediaListArray::InstanceL();
+    iCountAttributes.AppendL(KGlxMediaCollectionPluginSpecificSubTitle);
+    iCountAttributes.AppendL(KGlxMediaGeneralSlideshowableContent);
+    }
+
+// -----------------------------------------------------------------------------
+// Initialize the media list
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::OpenL(const CMPXCollectionPath& aPath)
+    {
+    TRACER("CGlxMediaList::OpenL" );
+    
+    __ASSERT_DEBUG(iPath.Count() == 0, Panic(EGlxPanicAlreadyInitialised));
+
+    // Copy the path's depth dimension
+    TInt levels = aPath.Levels();
+
+    iPath.ReserveL(levels);
+    for (TInt level = 0; level < levels; level++) 
+        {
+        TGlxMediaId id(aPath.Id(level));
+        iPath.Append(id); 
+        }
+
+    
+	// Id space ids will no longer be retrieved from the collection framework
+	// See ID:  ESLU-7C8CVN Inc9 MP: Error "Program closed: Music player" occurs if 
+    // user presses Rocker Select key continually in Album art view.
+    
+    // Consider the following scenario:
+    // 1. User launches fetcher dialog
+    // 2. Fetcher opens a medialist
+    // 3. MGlxMediaList::InstanceL starts an async wait loop allowing other active objects to run
+    // 4. User cancels fetcher
+    // 5. Fetcher does not have a handle to the MGlxMediaList so it cannot cancel or close it.
+    // --> We leak a medialist and leave an async wait loop in client processes active scheduler.
+
+    if (levels)
+    	{
+    	iIdSpaceId = aPath.Id(0);
+    	}
+    else
+    	{
+    	iIdSpaceId = KGlxIdSpaceIdRoot;
+    	}
+    
+    iItemList = CGlxNavigableList::NewL( iIdSpaceId, *this, *this );
+
+    OpenCollectionL( aPath );
+    }
+
+// -----------------------------------------------------------------------------
+// AddReference
+// -----------------------------------------------------------------------------
+//
+TInt CGlxMediaList::AddReference()
+    {
+    TRACER("CGlxMediaList::AddReference");
+    
+    iReferenceCount++;
+    return iReferenceCount;
+    }
+    
+// -----------------------------------------------------------------------------
+// RemoveReference
+// -----------------------------------------------------------------------------
+//
+TInt CGlxMediaList::RemoveReference()
+    {
+    TRACER("CGlxMediaList::RemoveReference");
+    
+    __ASSERT_ALWAYS(iReferenceCount > 0, Panic(EGlxPanicLogicError));
+    iReferenceCount--;
+    return iReferenceCount;
+    }
+    
+// -----------------------------------------------------------------------------
+// ReferenceCount
+// -----------------------------------------------------------------------------
+//
+TInt CGlxMediaList::ReferenceCount() const
+    {
+    TRACER("CGlxMediaList::ReferenceCount");
+    
+    return iReferenceCount;
+    }
+
+// -----------------------------------------------------------------------------
+// Returns ETrue if this media list refers to the path
+// -----------------------------------------------------------------------------
+//
+TBool CGlxMediaList::Equals(const CMPXCollectionPath& aPath) const 
+    {
+    TRACER("CGlxMediaList::Equals" );
+    
+    TInt myLevels = iPath.Count();
+    TInt pathLevels = aPath.Levels();
+    if (myLevels != pathLevels)
+        {
+        return EFalse;
+        }
+
+    // Check if path's match
+    for (TInt i = 0; i < myLevels; i++) 
+        {
+        if (iPath[i] != TGlxMediaId(aPath.Id(i)))
+            {
+            return EFalse;
+            }
+        }
+
+    return ETrue; // Match		
+    }
+
+// -----------------------------------------------------------------------------
+// Determines if a filter has been set
+// -----------------------------------------------------------------------------
+TBool CGlxMediaList::IsFiltered() const
+    {
+    TRACER("CGlxMediaList::IsFiltered");
+    
+    return iFilter != NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// Synchronise the media list
+// -----------------------------------------------------------------------------
+void CGlxMediaList::ReOpenL()
+    {
+    TRACER("CGlxMediaList::ReOpenL" );
+    
+    // We must not re-open the list before it has been opened the first time
+    // note - this can happen if update messages are received whilst retreiving
+    // the id space id
+    if ( !iItemList )
+        {
+        return;
+        }
+    
+    CMPXCollectionPath* path = PathLC( NGlxListDefs::EPathParent );
+
+    OpenCollectionL( *path );
+
+    CleanupStack::PopAndDestroy(path);
+    }
+
+// -----------------------------------------------------------------------------
+// Populates the list, i.e., opens the collection with the path
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::PopulateL()
+    {
+    TRACER("CGlxMediaList::PopulateL" );
+
+    // Reserve space for all items in cache, that this media list is a potential user
+    // This allows SetContentsL to build user links without having to reserve space
+    iManager->ReserveUsersL( iIdSpaceId, CGlxMediaList::MediaListsL().Count() );
+
+    CMPXCollectionPath* path = Collection().PathL();
+    CleanupStack::PushL(path);
+
+    if ( iReorderPending )
+        {
+        iItemList->ReorderContentsL( *path, *iManager );
+        iReorderPending = EFalse;
+        }
+    else
+        {
+        iItemList->SetContentsL( *path, *iManager );
+
+        // Sync has now occured,
+        // if only a sync was pending, clear sync status
+        if ( iSyncStatus == KSyncPending )
+            {
+            iSyncStatus = KNonePending;
+            }
+        }
+
+    CleanupStack::PopAndDestroy(path);
+
+    // The list contents may have changed, so update each used media with the
+    // current index into the list
+    UpdateMedia();
+
+    // Inform observers of first time population
+    if (!iIsPopulated)
+        {
+        TListPopulatedNotificationStrategy strategy( *this );
+        NotifyObservers( strategy );
+        iIsPopulated = ETrue; // Do this only once.
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Handles item modifications
+// -----------------------------------------------------------------------------
+void CGlxMediaList::HandleItemModifiedL(TInt aId, const RArray<TMPXAttribute>& aAttributes)
+    {
+    TRACER("CGlxMediaList::HandleItemModifiedL");
+    GLX_LOG_INFO1( "CGlxMediaList::HandleItemModifiedL %d", aId );
+    TGlxMediaId id(aId);
+
+    /// @todo: Check that the correct IdSpaceId is being used here
+    
+    TInt index = Index(iIdSpaceId, id);
+
+    if (index != KErrNotFound)
+        {
+        iManager->HandleItemModified(iIdSpaceId, id, aAttributes);
+
+        RArray<TInt> itemIndices;
+        CleanupClosePushL(itemIndices);
+        itemIndices.AppendL(index);
+
+        // Inform observers of modified items
+        TInt obsCount = iItemListObservers.Count();
+        GLX_DEBUG2("ML:HandleItemModifiedL obsCount=%d", obsCount);
+        for (TInt obsIdx = 0; obsIdx < obsCount; obsIdx++)
+            {
+            MGlxMediaListObserver* obs = iItemListObservers[obsIdx];
+            obs->HandleItemModifiedL(itemIndices, this);
+            }
+
+        CleanupStack::PopAndDestroy(&itemIndices);
+        RPointerArray<CGlxMediaList>& mediaLists = iMediaListArray->Array();
+        TInt listCount = mediaLists.Count();
+        GLX_DEBUG2("ML:HandleItemModifiedL listCount=%d", listCount);
+        if (listCount > 0)
+            {
+            CGlxMediaList* mediaList = mediaLists[listCount-1];
+            // Force a delay to allow TNM to process the modified event
+            if (mediaList == this)
+                {
+                GLX_DEBUG3("ML:HandleItemModifiedL(wait) listCount=%d, Id=%d",
+                                                  listCount, id.Value());
+                TTimeIntervalMicroSeconds32 timeout;
+                timeout = (mediaList->Count() > KMaxItemsCount ?
+                  KModifyEventMaxWaitInterval : KModifyEventMinWaitInterval );
+                RTimer timer;
+                CleanupClosePushL(timer);
+                TRequestStatus status;
+                timer.CreateLocal();
+                timer.After(status, timeout);
+			 	// User::WaitForRequest() will add codescanner warning but is necessary 
+			 	// as User::WaitForAnyRequest() cannot be used in this case
+                User::WaitForRequest(status);
+                CleanupStack::PopAndDestroy(&timer);
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// NotifyObserversOfMediaL
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::NotifyObserversOfMediaL(TInt aListIndex)
+    {
+    TRACER("CGlxMediaList::NotifyObserversOfMediaL");
+    GLX_LOG_INFO1( "CGlxMediaList::NotifyObserversOfMediaL %d", aListIndex );
+    TInt count = iItemListObservers.Count();
+    for (TInt i = 0; i < count; i++)
+        {
+        iItemListObservers[i]->HandleMediaL(aListIndex, this);
+        }
+    }
+        
+// -----------------------------------------------------------------------------
+// Notify observers of items added
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleItemsAdded( TInt aAddedAtIndex, TInt aCount )
+    {
+    TRACER("CGlxMediaList::HandleItemsAdded");
+    
+    TItemsAddedNotificationStrategy strategy( aAddedAtIndex, aCount, *this );
+    NotifyObservers( strategy );
+    }
+
+// -----------------------------------------------------------------------------
+// Notify observers of items removed
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleItemsRemoved( TInt aRemovedFromIndex, TInt aCount )
+    {
+    TRACER("CGlxMediaList::HandleItemsRemoved");
+    
+    TItemsRemovedNotificationStrategy strategy( aRemovedFromIndex, aCount,
+        *this );
+    NotifyObservers( strategy );
+    }
+
+// -----------------------------------------------------------------------------
+// Notify observers of focus change
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleFocusChanged( NGlxListDefs::TFocusChangeType aType, 
+        TInt aNewIndex, TInt aOldIndex )
+    {
+    TRACER("CGlxMediaList::HandleFocusChanged");
+    
+    TFocusChangedNotificationStrategy strategy( aType, aNewIndex, aOldIndex,
+        *this );
+    NotifyObservers( strategy );
+    }
+
+// -----------------------------------------------------------------------------
+// Notify observers of selection having changed
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::HandleItemSelected( TInt aIndex, TBool aSelected )
+    {
+    TRACER("CGlxMediaList::HandleItemSelected");
+    
+    TItemSelectedNotificationStrategy strategy( aIndex, aSelected, *this );
+    NotifyObservers( strategy );
+    }
+
+// -----------------------------------------------------------------------------
+// Call strategy object for each observer
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::NotifyObservers( TNotificationStrategy& aStrategy )
+    {
+    TRACER("CGlxMediaList::NotifyObservers");
+    
+    // Notify all observers, even if some of them leave leave.
+    // "i" needs to be volatile, so that it does not get optimised into a 
+    // register. If i were in a register and observer left, i's new value 
+    // would be lost. 
+    volatile TInt i = iItemListObservers.Count() - 1;
+    
+    // Loop count + 1 times, so that iManager also gets notified if last 
+    // observer leaves. Iterate backwards in case observes remove themselves
+    // from the observer array during the callbacks.
+    while ( i >= -1 ) // usually tested only twice
+        {
+        TRAPD( err, 
+            {
+            while ( i >= 0 )
+                {
+                aStrategy.NotifyL( *iItemListObservers[ i ] );
+                i--;
+                }
+
+            iManager->HandleWindowChangedL( this );
+            }
+        );
+        
+        if ( err != KErrNone )
+            {
+            iErrorPoster->PostError(err);
+            }
+
+        i--;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Populates the path with hierarchy to parent
+// -----------------------------------------------------------------------------
+//
+inline void CGlxMediaList::PathPopulateParentL(CMPXCollectionPath& aPath) const
+    {
+    TRACER("CGlxMediaList::PathPopulateParentL");
+    
+    // Add navigational hierarchy to path
+    TInt pathCount = iPath.Count();
+    for (TInt i = 0; i < pathCount; ++i)
+        {
+        aPath.AppendL( iPath[ i ].Value() );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Populates the path with all items and sets the focus
+// -----------------------------------------------------------------------------
+//
+inline void CGlxMediaList::PathPopulateAllL(CMPXCollectionPath& aPath) const
+    {
+    TRACER("CGlxMediaList::PathPopulateAllL");
+    
+    RArray<TMPXItemId> mpxIds;
+    CleanupClosePushL( mpxIds );
+
+    // Reserve space for all items
+    TInt itemCount = iItemList->Count();
+    mpxIds.ReserveL( itemCount );
+
+    // Obtain TMPXItemId for each item
+    for (TInt i = 0; i < itemCount; ++i)
+        {
+        if ( !iItemList->Item( i ).IsStatic() )
+            {
+            mpxIds.AppendL( iItemList->Item( i ).Id().Value() );
+            }
+        }
+
+    // Add Ids to current level in path
+    aPath.AppendL( mpxIds.Array() );
+
+    // Set focused item
+    TInt focusIndex = FocusIndex();
+    if ( focusIndex >= 0 )
+        {
+        if ( !iItemList->Item( focusIndex ).IsStatic() )
+            {
+            aPath.Set( focusIndex - iItemList->Count( NGlxListDefs::ECountPreStatic ) );
+            }
+        }
+
+    CleanupStack::PopAndDestroy( &mpxIds );
+    }
+
+// -----------------------------------------------------------------------------
+// Populates the path with focused item and sets the focus
+// -----------------------------------------------------------------------------
+//
+inline void CGlxMediaList::PathPopulateFocusL(CMPXCollectionPath& aPath) const
+    {
+    TRACER("CGlxMediaList::PathPopulateFocusL");
+    
+    // Obtain focused item
+    TInt focusIndex = FocusIndex();
+    if ( focusIndex >= 0 )
+        {
+        const TGlxMedia& item = iItemList->Item( focusIndex );
+        if ( !item.IsStatic() )
+            {
+            // Add focused item to path
+            aPath.AppendL( item.Id().Value() );
+            aPath.Set( 0 );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Populates the path with selected items and selects all
+// -----------------------------------------------------------------------------
+//
+inline void CGlxMediaList::PathPopulateSelectionL(CMPXCollectionPath& aPath) const
+    {
+    TRACER("CGlxMediaList::PathPopulateSelectionL");
+    
+    RArray<TMPXItemId> mpxIds;
+    CleanupClosePushL( mpxIds );
+
+    // Reserve space for all items
+    TInt selectionCount = iItemList->SelectedItemIndices().Count();
+    mpxIds.ReserveL( selectionCount );
+
+    // Obtain TMPXItemId for each item
+    for (TInt i = 0; i < selectionCount; ++i)
+        {
+        TInt selectedItemIndex = iItemList->SelectedItemIndices()[ i ];
+        mpxIds.AppendL( iItemList->Item( selectedItemIndex ).Id().Value() );
+        }
+
+    // Add Ids to current level in path
+    aPath.AppendL( mpxIds.Array() );
+
+    // Set selection
+    aPath.SelectAllL();
+
+    CleanupStack::PopAndDestroy( &mpxIds );
+    }
+
+// -----------------------------------------------------------------------------
+// Updates each media used by this media list with the current index
+// -----------------------------------------------------------------------------
+//
+inline void CGlxMediaList::UpdateMedia()
+    {
+    TRACER("CGlxMediaList::UpdateMedia");
+    
+    TInt count = iItemList->Count();
+    for (TInt i = 0; i < count; ++i)
+        {
+        TGlxMedia& item = iItemList->Item( i );
+
+        // static items should not be updated
+        if ( !item.IsStatic() )
+            {
+            item.UpdateMedia( *this, i );
+            UpdateMediaInvalidateAttributesChangedByCounts(item);
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Updates each media used by this media list with the current index
+// -----------------------------------------------------------------------------
+//
+inline void CGlxMediaList::UpdateMediaInvalidateAttributesChangedByCounts(TGlxMedia& aItem)
+    {
+    TRACER("CGlxMediaList::UpdateMediaInvalidateAttributesChangedByCounts");
+    
+    iManager->HandleItemModified(iIdSpaceId, aItem.Id(), iCountAttributes);
+    }
+    
+// -----------------------------------------------------------------------------
+// Opens a collection at the appropriate level
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::OpenCollectionL(const CMPXCollectionPath& aPath)
+    {
+    TRACER("CGlxMediaList::OpenCollectionL");
+    
+    // Open the level
+    if ( aPath.Levels() == 0 )
+        {
+        Collection().OpenL( TUid::Uid( EGlxCollectionPluginShowInMainListView ) );
+        }
+    else
+        {
+        Collection().OpenL( aPath );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// Compare contexts by pointer
+// -----------------------------------------------------------------------------
+//
+TBool CGlxMediaList::TContext::Match(const TContext& a1, const TContext& a2)
+    {
+    TRACER("CGlxMediaList::TContext::Match");
+    
+    return a1.iContext == a2.iContext;
+    }
+
+// -----------------------------------------------------------------------------
+// Compare contexts by priority
+// -----------------------------------------------------------------------------
+//
+TBool CGlxMediaList::TContext::Compare(const TContext& a1, const TContext& a2)
+    {
+    TRACER("CGlxMediaList::TContext::Compare");
+    
+    return a2.iPriority - a1.iPriority;
+    }
+
+// -----------------------------------------------------------------------------
+// Set the visible dataWindow index
+// -----------------------------------------------------------------------------
+//
+void CGlxMediaList::SetVisibleWindowIndexL( TInt aIndex )
+    {
+    TRACER("CGlxMediaList::SetVisibleWindowIndexL");
+    __ASSERT_ALWAYS( aIndex <= Count(), Panic( EGlxPanicIllegalArgument ) );
+    if( aIndex != iVisibleWindowIndex )
+        {
+        iVisibleWindowIndex = aIndex;
+        GLX_DEBUG2("SetVisibleWindowIndexL() iVisibleWindowIndex=%d",
+                                                        iVisibleWindowIndex);
+        iManager->HandleWindowChangedL(this);
+        iManager->RefreshL();
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// Returns visible dataWindow index
+// -----------------------------------------------------------------------------
+//
+TInt CGlxMediaList::VisibleWindowIndex() const
+    {
+    TRACER("CGlxMediaList::VisibleWindowIndex");
+    return iVisibleWindowIndex;
+    }
+
+// -----------------------------------------------------------------------------
+// Cancels the pending attribute/thumbnail requests 
+// -----------------------------------------------------------------------------
+
+void CGlxMediaList::CancelPreviousRequests()
+	{
+	TRACER("CGlxMediaList::CancelPreviousRequests");	
+	
+	TInt focusIndex = FocusIndex();
+	
+	if(focusIndex >= KErrNone)
+		{	
+		if(!Item(focusIndex).Properties())
+			{
+			// If media is NULL, cancel the previous pending request.
+			// Place a new request for the item in focus, to fetch the media attributes
+			iManager->CancelPreviousRequest();		
+			}
+		}
+	}