photosgallery/viewframework/medialists/src/glxcache.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 19 Feb 2010 22:51:01 +0200
branchRCL_3
changeset 9 6b87b143d312
parent 0 4e91876724a2
child 18 bcb43dc84c44
permissions -rw-r--r--
Revision: 201003 Kit: 201007

/*
* 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:    Cache implementation for media items sharing the same Id space
*
*/




#include "glxcache.h"

#include <glxassert.h>
#include <mpxmediadrmdefs.h>			// for DRM attributes
#include <mpxmediacontainerdefs.h>
#include <mpxmediacollectiondetaildefs.h>
#include <glxthumbnailattributeinfo.h>
#include <glxtracer.h>
#include <lbsposition.h>				//for TCoordinate

#include "glxcachemanager.h"
#include "glxmedialist.h"

// -----------------------------------------------------------------------------
// Constructor
// -----------------------------------------------------------------------------
//
CGlxCache::CGlxCache( const TGlxIdSpaceId& aIdSpaceId, CGlxCacheManager* aCacheManager )
        : iIdSpaceId( aIdSpaceId ), iCacheManager(aCacheManager)
    {
    TRACER("CGlxCache::CGlxCache");
    }

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
CGlxCache::~CGlxCache()
    {
    TRACER("CGlxCache::Destructor");
    iItemPool.ResetAndDestroy();
    }

// -----------------------------------------------------------------------------
// IdSpaceId
// -----------------------------------------------------------------------------
//
TGlxIdSpaceId CGlxCache::IdSpaceId() const
    {
    TRACER("CGlxCache::IdSpaceId");
    
    return iIdSpaceId;
    }
    
// -----------------------------------------------------------------------------
// return a media object or null
// -----------------------------------------------------------------------------
//
CGlxMedia* CGlxCache::Media( const TGlxMediaId& aId ) const
	{
	TRACER("CGlxCache::Media");
	
    TInt index = iItemPool.FindInOrder(aId, (&MediaItemOrderByKey));
    if ( KErrNotFound != index )
        {
        return iItemPool[index];
        }
        
    return NULL;
    }

// -----------------------------------------------------------------------------
// FindItemForceCreateL
// -----------------------------------------------------------------------------
//
CGlxMedia* CGlxCache::FindItemForceCreateL( const TGlxMediaId& aId )
    {
    TRACER("CGlxCache::FindItemForceCreateL");
    
    CGlxMedia* media = Media( aId );

    if ( !media )
        {
        media = CreateItemL( aId );
        }

    return media;	
    }

// -----------------------------------------------------------------------------
// CreateItemL
// -----------------------------------------------------------------------------
//
CGlxMedia* CGlxCache::CreateItemL(const TGlxMediaId& aId)
    {
    TRACER("CGlxCache::CreateItemL");
    
    CGlxMedia* item = NULL;
    
    iItemPool.ReserveL( iItemPool.Count() + 1 );
    item = new (ELeave) CGlxMedia(aId);
    TLinearOrder<CGlxMedia> orderer (&MediaItemOrderById);
    iItemPool.InsertInOrder(item, orderer);

	// Safe to fail, since if the media objects is not used by any lists,
	// garbage collection will simply delete it
	RPointerArray<CGlxMediaList>& mediaLists = CGlxMediaList::MediaListsL();

	TInt count = mediaLists.Count();
	item->ReserveUsersL(count);
	for (TInt i = 0; i < count; i++) 
		{
		mediaLists[i]->OfferMedia(iIdSpaceId, item);
		}

    return item;    
    }

// -----------------------------------------------------------------------------
// MediaUpdatedL
// -----------------------------------------------------------------------------
//
void CGlxCache::MediaUpdatedL(const CMPXMedia& aMedia)
    {
    TRACER("CGlxCache::MediaUpdatedL");
    
    if (aMedia.IsSupported(KMPXMediaArrayContents))
        {
        CMPXMediaArray* mediaArray = aMedia.ValueCObjectL<CMPXMediaArray>(KMPXMediaArrayContents);
        CleanupStack::PushL(mediaArray);

        TInt arrayCount = mediaArray->Count();
		GLX_DEBUG2("CGlxCache::MediaUpdatedL() arrayCount=%d", arrayCount);
        for (TInt count = 0; count < arrayCount; ++count)
            {
            UpdateMediaL(*((*mediaArray)[count]));
            }

        CleanupStack::PopAndDestroy(mediaArray);
        }
    else
        {
        UpdateMediaL(aMedia);
        }
    }

// -----------------------------------------------------------------------------
// UpdateMediaL
// -----------------------------------------------------------------------------
void CGlxCache::UpdateMediaL(const CMPXMedia& aMedia)
    {
    TRACER("CGlxCache::UpdateMediaL");
    
    if ( !aMedia.IsSupported(KMPXMediaGeneralId) )
        {
        return;
        }
	// Copy/synchronize attributes
    TGlxMediaId id ((TUint32)aMedia.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId));
	GLX_DEBUG2("CGlxCache::UpdateMediaL() id=%d", id.Value());	
	CGlxMedia* item = Media( id );

	RArray<TMPXAttribute> newAttributes;
	CleanupClosePushL(newAttributes);
	
	if ( item )
		{
		GLX_DEBUG2("MGallery - CGlxCacheManager::HandleCollectionMediaL() existing item for item id %d", id.Value());
		CopyNewAndModifiedL(*item, aMedia, newAttributes);
    	}
    else 
    	{
		GLX_DEBUG2("MGallery - CGlxCacheManager::HandleCollectionMediaL() new item for item id %d", id.Value());

    	// This is a new item. Create a media object and offer it to all lists.
    	// If the item is no longer needed by any list, then this is ok, since
    	// garbage collection will delete the item
    	// Add in id order.        	
    	item = CreateItemL(id);
    	
		CopyNewAndModifiedL(*item, aMedia, newAttributes);
    	}
		
	// Broadcast the new attributes to all observers of the item and the cache
	if (newAttributes.Count() > 0)
		{
		TInt count = item->UserCount();
		for (TInt i = 0; i < count; i++)
			{
			item->User( i ).HandleAttributesAvailableL( item->IndexInUser( i ), newAttributes );
			}
			
	    // Broadcast to cache observers
		// iCacheManager->BroadcastAttributesAvailableL(iIdSpaceId, id, newAttributes, item);
		}

	CleanupStack::PopAndDestroy(&newAttributes);
    }
// -----------------------------------------------------------------------------
// Deletes the media item
// -----------------------------------------------------------------------------
void CGlxCache::CleanupMedia(const TGlxMediaId& aMediaId)
	{
	TRACER("CGlxCache::CleanupMedia");
    GLX_DEBUG2("CGlxCache::CleanupMedia -  aMediaId = %d", aMediaId.Value());
    if(iCacheManager)
        {
        iCacheManager->CleanupMedia(aMediaId);
        }
	}
    
// -----------------------------------------------------------------------------
// Handles modifications of item in cache
// -----------------------------------------------------------------------------
void CGlxCache::HandleItemModified(const TGlxMediaId& aId, const RArray<TMPXAttribute>& aAttributes)
	{
	TRACER("CGlxCache::HandleItemModified");
	
	TInt index = iItemPool.FindInOrder(aId, (&MediaItemOrderByKey));
	if (index != KErrNotFound)
		{
		iItemPool[index]->HandleModified(aAttributes);
		}
	}

// -----------------------------------------------------------------------------
// Copies new and modified attributes from the provided media object
// -----------------------------------------------------------------------------
//
void CGlxCache::CopyNewAndModifiedL(CGlxMedia& aTarget, const CMPXMedia& aSource, 
        RArray<TMPXAttribute>& aNewAttributes)
    {
    TRACER("CGlxCache::CopyNewAndModifiedL");
    
    /// @todo This is all temporary until global chunk based CMPXMedia is available
    TInt count = aSource.Count();
	GLX_DEBUG2("CGlxCache::CopyNewAndModifiedL() Attribs count=%d", count);
    aNewAttributes.ReserveL( count );

    for (TInt i = 0; i < count; i++)
        {
        const TMPXAttribute& attrib = aSource.Attribute(i);

        if (attrib == KMPXMediaGeneralId)
            {
            // Ignore id
            __ASSERT_DEBUG((TUint32)aSource.ValueTObjectL<TMPXItemId>(attrib) == aTarget.Id().Value(), 
                           Panic(EGlxPanicIllegalArgument)); // aMedia relates to another media object than this
            }
        else 
            {
            if (!aTarget.IsSupported(attrib)) 
                {
                TMPXAttributeType type = aSource.Type(i);

                if (type == EMPXTypeText) 
                    {
                    aTarget.SetTextValueL(attrib, aSource.ValueText(attrib));
                    }
                else if (type == EMPXTypeCObject) 
                    {
                    if ( KGlxMediaIdThumbnail == attrib.ContentId() )
                        {
                        // This is a thumbnail
                        CFbsBitmap* thumbnail = iCacheManager->TempThumbnail();

                        if ( thumbnail && iCacheManager->TempThumbnailId() == aTarget.Id() )
                            {
                            // Add new thumbnail attribute
                            CGlxThumbnailAttribute* value =
                                aSource.ValueNoNewLCObjectL<CGlxThumbnailAttribute>(attrib);
                            CleanupStack::PushL(value);
                            value->iBitmap = thumbnail;
                            GLX_DEBUG3("CGlxCache::CopyNewAndModifiedL() TN Attrib w(%d) h(%d)", 
					        	thumbnail->SizeInPixels().iWidth, thumbnail->SizeInPixels().iHeight);
                            iCacheManager->SetTempThumbnailToNull();
                            aTarget.SetCObjectValueL(attrib, value);
                            CleanupStack::Pop(value);
                            }
                        }
                    else
                        {
                        __DEBUG_ONLY(Panic(EGlxPanicNotImplemented)); // Add support for the attribute here
                        }
                    }
                else if (type == EMPXTypeTObject) 
                    {
                    if (attrib == KMPXMediaGeneralThumbnail1)
                        {
                        // Old thumbnail attribute - ignore
                        }
                    else if (attrib == KMPXMediaGeneralDate)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt64>(attrib));
                        }
                    else if (attrib == KGlxMediaGeneralLastModifiedDate)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt64>(attrib));
                        }
                    else if (attrib == KMPXMediaGeneralSize)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib));
                        }
                    else if (attrib == KMPXMediaColDetailSpaceId)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TGlxIdSpaceId>(attrib));
                        }
                    else if (attrib == KMPXMediaGeneralType)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib));
                        }
                    else if (attrib == KMPXMediaGeneralCategory)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib));
                        }
                    else if (attrib == KMPXMediaGeneralCount)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib));
                        }
                    else if (attrib == KGlxMediaGeneralDimensions)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TSize>(attrib));
                        }
                    else if (attrib == KGlxMediaGeneralLocation)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TCoordinate>(attrib));
                        }
                    else if (attrib == KMPXMediaGeneralDuration)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib));
                        }  
                    else if (attrib == KMPXMediaDrmProtected)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TBool>(attrib));
                        }                         
                    else if (attrib == KGlxMediaGeneralDRMRightsValid)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TBool>(attrib));
                        }                         
                    else if (attrib == KGlxMediaGeneralSystemItem)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TBool>(attrib));
                        }
                    else if (attrib == KGlxMediaGeneralFramecount)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib));
                        }				         				
                    else if(attrib == KGlxMediaGeneralSlideshowableContent)
                        {
                        aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib));
                        }        				
                    else
                        {
                        __DEBUG_ONLY(Panic(EGlxPanicNotImplemented)); // Add support for the attribute here
                        }
                    }
                else 
                    {
                    __DEBUG_ONLY(Panic(EGlxPanicNotImplemented)); 
                    }

                aNewAttributes.AppendL(attrib);
                }
            }
        }
    }

// -----------------------------------------------------------------------------
// Delete
// -----------------------------------------------------------------------------
//
void CGlxCache::Delete( TInt aIndex ) 
    {
    TRACER("CGlxCache::Delete");
    
    GLX_ASSERT_DEBUG( 0 <= aIndex && aIndex < iItemPool.Count(), 
        Panic(EGlxPanicIllegalArgument), "deleting attribute out of bounds");
        
    CGlxMedia* media = iItemPool[aIndex];
    
    // Cleanup the media from all users, example texture manager
    CleanupMedia(media->Id());
    
    GLX_DEBUG2("MGallery - CGlxCache::Delete() for item id %d", media->Id().Value());
    // notify users that the media object is about to be deleted. This allows
    // users to remove their references
    // (loop does not t iterate indexes, since the contents of the User array 
    // will change during calls to RemoveReferences, as users are removed)
    
    // safety check that RemoveReference actually removed the reference
    __DEBUG_ONLY( TInt _maxLoopCount = 1000 );
    
    while ( media->UserCount() > 0 )
        {
        // The user must remove a reference and that will decrement the 
        // UserCount()
        media->User( 0 ).RemoveReference( media->IndexInUser( 0 ) );
        
        // protect against a bug that would cause hard-to-find infinite loop
        __DEBUG_ONLY( _maxLoopCount-- );
        GLX_ASSERT_DEBUG( _maxLoopCount != 0, Panic( EGlxPanicLogicError ),
            "infinite loop when removing a media object" );
        }
    
    delete media;
    iItemPool.Remove( aIndex );
    }
    
// -----------------------------------------------------------------------------
// Reserve space for a number of users, for all items in the cache
// -----------------------------------------------------------------------------
//
void CGlxCache::ReserveUsersL(TInt aCount)
    {
    TRACER("CGlxCache::ReserveUsersL");
    
    TInt count = iItemPool.Count();
    for ( TInt i = 0; i < count ; ++i )
        {
        iItemPool[i]->ReserveUsersL( aCount );
        }
    }

// -----------------------------------------------------------------------------
// MediaItemOrderById
// -----------------------------------------------------------------------------
//
TInt CGlxCache::MediaItemOrderById(const CGlxMedia& aItem1, const CGlxMedia& aItem2) 
	{
	TRACER("CGlxCache::MediaItemOrderById");
	
	// Cannot do aItem1.Id() - aItem2.Id(), since Id().Value() returns an unsigned value
	TGlxMediaId id1 = aItem1.Id();
	return MediaItemOrderByKey( &id1, aItem2 );
	}

// -----------------------------------------------------------------------------
// MediaItemOrderByKey
// -----------------------------------------------------------------------------
//
TInt CGlxCache::MediaItemOrderByKey(const TGlxMediaId* aMediaId, const CGlxMedia& aItem2) 
	{
	TRACER("CGlxCache::MediaItemOrderByKey");
	
	TGlxMediaId id2 = aItem2.Id();
	if (*aMediaId < id2) 
		{
		return -1;
		}
		
	if (*aMediaId > id2) 
		{
		return 1;
		}

	return 0;
	}

// -----------------------------------------------------------------------------
// Return count of media objects
// -----------------------------------------------------------------------------
//
TInt CGlxCache::Count()
    {
    TRACER("CGlxCache::Count");
    
    return iItemPool.Count();
    }
    
// -----------------------------------------------------------------------------
// Return media object by index
// -----------------------------------------------------------------------------
//
CGlxMedia& CGlxCache::Media( TInt aIndex )
    {
    TRACER("CGlxCache::Media");
    
    return *iItemPool[aIndex];
    }

// -----------------------------------------------------------------------------
// Return media index
// -----------------------------------------------------------------------------
//
TInt CGlxCache::FindMediaIndexInCache(TGlxMediaId aMediaId)
	{
	TRACER("CGlxCache::FindMediaIndexInCache");
	 
	return iItemPool.FindInOrder(aMediaId, (&MediaItemOrderByKey));
	}