diff -r 000000000000 -r 4e91876724a2 photosgallery/viewframework/medialists/src/glxmedialist.cpp --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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& 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::MediaListsL() + { + TRACER("CGlxMediaList::MediaListsL" ); + + CGlxMediaListArray* mediaListArray = CGlxMediaListArray::InstanceL(); + RPointerArray& 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& 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& aItemIndexes, + RArray& aItemIds, + RArray& 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& aAttributes) + { + TRACER("CGlxMediaList::GetRequiredAttributesL" ); + + TLinearOrder 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& 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 match (&CGlxMediaList::TContext::Match); + __ASSERT_DEBUG(iContexts.Find(context, match) == KErrNotFound, Panic(EGlxPanicAlreadyAdded)); + +#endif // _DEBUG + + TLinearOrder 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 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( 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(KMPXMessageGeneralId); + if ( messageId == KMPXMessageGeneral ) + { + if (!aMessage.IsSupported(KMPXMessageGeneralEvent) || + !aMessage.IsSupported(KMPXMessageGeneralType)) + { + return; + } + + TInt messageEvent = aMessage.ValueTObjectL(KMPXMessageGeneralEvent); + if (messageEvent == TMPXCollectionMessage::EPathChanged) + { + GLX_LOG_INFO("CGlxMediaList::HandleCollectionMessageL() EPathChanged"); + + TInt messageType = aMessage.ValueTObjectL(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(KMPXMessageChangeEventType); + switch (messageType) + { + case EMPXItemModified: + { + RArray attributes; + CleanupClosePushL(attributes); + TMPXItemId itemId = aMessage.ValueTObjectL(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& 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 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& 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 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 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(); + } + } + }