photosgallery/viewframework/medialists/src/glxthumbnailcontext.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:45:44 +0200
changeset 0 4e91876724a2
child 18 bcb43dc84c44
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* 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:    Fetch context to retrieve thumbnails
*
*/





#include <mpxmediadrmdefs.h>
#include <glxresolutionutility.h>
#include <glxdrmutility.h>
#include <glxthumbnailattributeinfo.h>
#include <mpxmediacollectiondetaildefs.h> // for KMPXMediaColDetailSpaceId
#include <glxtracer.h>
#include <glxlog.h>

#include "glxattributecontext.h"
#include "glxthumbnailcontext.h"
#include "glxmedialist.h"
#include "glxerrormanager.h"
#include "glxthumbnailutility.h"
#include "mglxcache.h"
#include "glxlistutils.h"

/**
 * Scoring for thumbnail provision order 
 * Having no thumbnail is the most important, so it gets the highest bit
 * Proximity to focus is the final (lowest priority) criteria)
 */
const TUint KTNScoreNoThumbnail                 = 0x80000000;
// bits 0 to 24 are reserved for distance from focus (excessive, but free...)
const TUint KTNScoreMaxForDistanceFromFocus 	= 0x00FFFFFF;


// -----------------------------------------------------------------------------
// Constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CGlxThumbnailContext* CGlxThumbnailContext::NewL(MGlxMediaListIterator* 
                                                                    aIterator)
    {
    TRACER( "CGlxThumbnailContext::NewL");
            
    CGlxThumbnailContext* self = new(ELeave)CGlxThumbnailContext(aIterator);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

// -----------------------------------------------------------------------------
// Constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CGlxThumbnailContext::CGlxThumbnailContext(MGlxMediaListIterator* aIterator) :
        iIterator(aIterator)
    {
    TRACER( "CGlxThumbnailContext::CGlxThumbnailContext");
    
    __ASSERT_DEBUG(aIterator, Panic(EGlxPanicNullPointer));
    }
    
// -----------------------------------------------------------------------------
// ConstructL (2nd phase construction)
// -----------------------------------------------------------------------------
//
void CGlxThumbnailContext::ConstructL()    
    {
    TRACER( "CGlxThumbnailContext::ConstructL");
    
    iCache = MGlxCache::InstanceL();
    iResolutionUtility = CGlxResolutionUtility::InstanceL();
    iResolutionUtility->AddObserverL( *this );

    iDrmUtility = CGlxDRMUtility::InstanceL();

    // create attribute context for DRM attributes
        iDrmFetchContext = new (ELeave) CGlxAttributeContext(iIterator);
    iDrmFetchContext->AddAttributeL(KMPXMediaDrmProtected);
#ifdef RD_MDS_2_5
    iDrmFetchContext->AddAttributeL(KGlxMediaGeneralDRMRightsValid);
#endif
    iDrmFetchContext->AddAttributeL(KMPXMediaGeneralCategory);
    iDrmFetchContext->AddAttributeL(KMPXMediaGeneralUri);
    iDrmFetchContext->AddAttributeL(KMPXMediaGeneralSize);
    iDrmFetchContext->AddAttributeL(KGlxMediaGeneralLastModifiedDate);
    // add size attribute
    iDrmFetchContext->AddAttributeL(KGlxMediaGeneralDimensions); 
    // add to speed up details retrieval  
    iDrmFetchContext->AddAttributeL(KMPXMediaGeneralTitle);
    iDrmFetchContext->AddAttributeL(KMPXMediaGeneralDate);
    iDrmFetchContext->AddAttributeL(KMPXMediaGeneralDrive);
    iDrmFetchContext->AddAttributeL(KGlxMediaGeneralFramecount);
    //Need to implement IdSpaceId() functionality.
    iDrmFetchContext->AddAttributeL(KMPXMediaColDetailSpaceId);    
    // Attributes required to launch Options
    iDrmFetchContext->AddAttributeL(KMPXMediaGeneralMimeType);   
    iDrmFetchContext->AddAttributeL(KGlxMediaGeneralLocation);  
    iDrmFetchContext->AddAttributeL(KGlxMediaGeneralSystemItem);  
    iDrmFetchContext->AddAttributeL(KGlxMediaGeneralSlideshowableContent);     
    }

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
EXPORT_C CGlxThumbnailContext::~CGlxThumbnailContext()
    {
    TRACER( "CGlxThumbnailContext::~CGlxThumbnailContext");
    
    delete iDrmFetchContext;

    if ( iDrmUtility )
        {
        iDrmUtility->Close();
        }

    iSpecs.Close();

    if ( iResolutionUtility )
        {
        iResolutionUtility->RemoveObserver( *this );
        iResolutionUtility->Close();
        }

    if ( iCache )
        {
        iCache->Close();
        }
    }

// -----------------------------------------------------------------------------
// Adds a new fetch specification for an item
// -----------------------------------------------------------------------------
//
EXPORT_C void CGlxThumbnailContext::AddSpecForItemL(
                            TInt aWidth, TInt aHeight, TInt aFocusOffset )
    {
    TRACER( "CGlxThumbnailContext::AddSpecForItemL");
    
    TReal32 width( aWidth );
    TReal32 height( aHeight );

    TAssignedFetchSpec spec;
    spec.iPossWidth = iResolutionUtility->PixelsToPoss( width );
    spec.iPossHeight = iResolutionUtility->PixelsToPoss( height );
    spec.iFocusOffset = aFocusOffset;

    // Has this focus index has already been added?
    #ifdef _DEBUG
    TIdentityRelation<TAssignedFetchSpec> match (&TAssignedFetchSpec::Match);
    #endif
    __ASSERT_DEBUG(iSpecs.Find(spec, match) == KErrNotFound, Panic(EGlxPanicAlreadyAdded)); 

    iSpecs.AppendL(spec);
    }

// -----------------------------------------------------------------------------
// Sets the default fetch specification
// -----------------------------------------------------------------------------
//
EXPORT_C void CGlxThumbnailContext::SetDefaultSpec(TInt aWidth, TInt aHeight)
    {
    TRACER( "CGlxThumbnailContext::SetDefaultSpec");
    
    iDefaultSpecSize = TSize(aWidth, aHeight);
    
    TReal32 width( aWidth );
    TReal32 height( aHeight );

    iDefaultSpec.iPossWidth = iResolutionUtility->PixelsToPoss( width );
    iDefaultSpec.iPossHeight = iResolutionUtility->PixelsToPoss( height );
    }

// ---------------------------------------------------------------------------
// SetHighQualityOnly
// ---------------------------------------------------------------------------
//
EXPORT_C void CGlxThumbnailContext::SetHighQualityOnly(
                                                    TBool aHighQualityOnly )
    {
    TRACER( "CGlxThumbnailContext::SetHighQualityOnly");
    
    iHighQualityOnly = aHighQualityOnly;
    }

// -----------------------------------------------------------------------------
// Get all attributes required for the item (whether the are fetched or not)
// From MGlxFetchContext
// -----------------------------------------------------------------------------
//
void CGlxThumbnailContext::AllAttributesL(const MGlxMediaList* aList, TInt aListIndex, 
        RArray<TMPXAttribute>& aAttributes) const 
    {
    TRACER( "CGlxThumbnailContext::AllAttributesL");
    
    if (!iIterator)
        {
        return;
        }

    // add attributes from owned attribute context
    iDrmFetchContext->AllAttributesL(aList,aListIndex, aAttributes);  
      
    // No requests outside range
    iIterator->SetToFirst(aList);
    if (!iIterator->InRange(aListIndex))
        {
        return;
        }
    TBool drmValid = EFalse;
    TSize size = iDefaultSpecSize;
    const TGlxMedia& item( aList->Item( aListIndex ) );
	if( item.GetDrmProtected(drmValid) && drmValid)
        {
        drmValid = CheckDRMStatusL( aListIndex, aList, size );	
        }

    TLinearOrder<TMPXAttribute> orderer (&CGlxMediaList::AttributeOrder);
    // Always want high quality thumbnail
    TMPXAttribute attr( KGlxMediaIdThumbnail,
            GlxFullThumbnailAttributeId( ETrue, size.iWidth, size.iHeight ) );
    aAttributes.InsertInOrderAllowRepeatsL( attr , orderer);

    // If don't have high quality thumbnail, find closest available thumbnail
    
    const CGlxMedia* properties = item.Properties();
    if ( properties && !properties->IsSupported( attr ) )
        {
        TMPXAttribute attr2;

        if ( item.GetClosestThumbnail( attr2, size, drmValid ) )
            {
            aAttributes.InsertInOrderAllowRepeatsL( attr2 , orderer );
            }
        }

    }

// -----------------------------------------------------------------------------
// Get attributes request for the item
// From MGlxFetchContext
// -----------------------------------------------------------------------------
// 
TInt CGlxThumbnailContext::AttributeRequestL(const MGlxMediaList* aList, 
        RArray<TInt>& aItemIndices, RArray<TMPXAttribute>& aAttributes, 
        CMPXAttributeSpecs*& aDetailedSpecs) const
    {
    TRACER( "CGlxThumbnailContext::AttributeRequestL");
    
    // Fetch the visible items attribs & thumbnail first. 
    TInt error = KErrNone;
    TInt listIndex = SelectItemL(aList, error);
    if ((listIndex >= 0 && aList->Item(listIndex).Uri().Length() == 0) || 
         aList->Count() <= GlxListUtils::VisibleItemsGranularityL())
        {
        TInt reqCount = iDrmFetchContext->AttributeRequestL(aList, 
                        aItemIndices, aAttributes, aDetailedSpecs);

        // if owned context requires DRM atributes need to request those 1st
        if ( reqCount != 0 )
            {
            GLX_DEBUG2("CGlxThumbnailContext::AttributeRequestL() reqCount=%d", reqCount);
            return reqCount; 
            }
        }
    
    // Select an item to process
    error = KErrNone;
    listIndex = SelectItemL(aList, error);
    if (KErrNotFound != listIndex)
        {
        GLX_DEBUG2("CGlxThumbnailContext::AttributeRequestL() listIndex=%d", listIndex);
        const TGlxMedia& item = aList->Item( listIndex );
        TSize size = iDefaultSpecSize;

        TBool drmValid = EFalse;
        if( item.GetDrmProtected(drmValid) && drmValid)
	        {
	        CheckDRMStatusL( listIndex, aList, size );	
	        }

        // Request high quality thumbnail if already have any thumbnail
        TBool quality = iHighQualityOnly
                        || HasFullThumbnail( aList->Item( listIndex ) );

        GLX_DEBUG2("CGlxThumbnailContext::AttributeRequestL() quality=%d", quality);
        TMPXAttribute attr( KGlxMediaIdThumbnail,
                            GlxFullThumbnailAttributeId(
                                    quality, size.iWidth, size.iHeight ) );

        aAttributes.AppendL(attr);

        aItemIndices.AppendL(listIndex);

        // Allocate CMPXAttributeSpecs
        CMPXAttributeSpecs* attributeSpecs = CMPXAttributeSpecs::NewL();
        CleanupStack::PushL(attributeSpecs);

        attributeSpecs->SetTObjectValueL(
            TMPXAttribute( KGlxMediaIdThumbnail,
                        KGlxAttribSpecThumbnailSize ), size );

        attributeSpecs->SetTObjectValueL(
            TMPXAttribute( KGlxMediaIdThumbnail,
                        KGlxAttribSpecThumbnailQualityOverSpeed ), quality );


        aDetailedSpecs = attributeSpecs;

        // Pop from stack
        CleanupStack::Pop(attributeSpecs);
        }
    else
        {
        // If an error was found, return KErrGeneral
        if (error != KErrNone)
            {
            return KErrGeneral;
            }
        }

    return aItemIndices.Count();
    }

// -----------------------------------------------------------------------------
// Number of current requests
// From MGlxFetchContext
// -----------------------------------------------------------------------------
TInt CGlxThumbnailContext::RequestCountL(const MGlxMediaList* aList) const
    {
    TRACER( "CGlxThumbnailContext::RequestCountL");
    
    RArray<TInt> itemIndices;
    CleanupClosePushL(itemIndices);

    RArray<TMPXAttribute> attributes;
    CleanupClosePushL(attributes);

    CMPXAttributeSpecs* attrSpecs = NULL;

    TInt requestCount = AttributeRequestL(aList, itemIndices, attributes, attrSpecs);

    delete attrSpecs;

    CleanupStack::PopAndDestroy(&attributes);
    CleanupStack::PopAndDestroy(&itemIndices);

    return requestCount;
    }

// -----------------------------------------------------------------------------
// HandleResolutionChanged
// -----------------------------------------------------------------------------
//
void CGlxThumbnailContext::HandleResolutionChangedL()
    {
    TRACER( "CGlxThumbnailContext::HandleResolutionChanged");
    
    // Ask cache manager to refresh, to fetch thumbnails in new size
    iCache->RefreshL();
    }

// -----------------------------------------------------------------------------
// SelectItemL
// -----------------------------------------------------------------------------
//
TInt CGlxThumbnailContext::SelectItemL(const MGlxMediaList* aList, TInt& aError) const
    {
    TRACER( "CGlxThumbnailContext::SelectItemL");
    
    // Order of priorities when selecting the item: (highest priority rule first)
    // Items with no thumbnail before items with thumbnail
    // Items closer to the focus before

    TInt count = aList->Count();
    if (0 == count || !iIterator) 
        {
        return KErrNotFound;
        }

    // Iterate through range from iterator in search of the highest scoring thumbnail
    TUint bestScore = 0;
    TInt bestIndex = KErrNotFound;
    iIterator->SetToFirst(aList);
    TInt distanceFromFirst = 0;
    TInt i;
    while (KErrNotFound != (i = (*iIterator)++))
        {
        // Calculate the score for this item
        TUint score = GetThumbnailScoreL(i, aList, distanceFromFirst, aError);
        __ASSERT_DEBUG(score != bestScore || score == 0, Panic(EGlxPanicLogicError)); // For safety, cannot allow two items with the same score
        if (score > bestScore)
            {
            bestScore = score;
            bestIndex = i;
            }

        distanceFromFirst++;
        } 

    return bestIndex;
    }

// -----------------------------------------------------------------------------
// GetThumbnailScoreL
// -----------------------------------------------------------------------------
//
TUint CGlxThumbnailContext::GetThumbnailScoreL(TInt aListIndex, const MGlxMediaList* aList, 
        TInt aDistance, TInt& aError) const 
    {
    TRACER( "CGlxThumbnailContext::GetThumbnailScoreL");
    
    const TGlxMedia& item = aList->Item(aListIndex);
    const CGlxMedia* properties = item.Properties();
    
    // Check for the static item in the list.
    // defualt icons needs to be displayed for static items.
    if(item.IsStatic())
    	{
    	return 0;
    	}
    	
    TBool thumbnail = HasFullThumbnail( item );
    TUint score = 0;
    
    if ( properties )
        {
        TSize size = iDefaultSpecSize;

        TBool drmValid = EFalse;
        if( item.GetDrmProtected(drmValid) && drmValid)
	        {
	        CheckDRMStatusL( aListIndex, aList, size );	
	        }

        // Want high quality thumbnail if already have any thumbnail
        TBool quality = iHighQualityOnly || thumbnail;
        TMPXAttribute attr( KGlxMediaIdThumbnail, 
                            GlxFullThumbnailAttributeId(
                                    quality, size.iWidth, size.iHeight ) );

        // Items that are "perfect" are skipped
        if ( quality && properties->IsSupported( attr ) )
            {
            return 0;
            }

        // Items for which fetching thumbnail failed are skipped
        TInt error = GlxErrorManager::HasAttributeErrorL( properties, attr );
        if ( error != KErrNone )
        	{
            aError = error;
        	return 0;
        	}
        }

    // Score on not having any thumbnail
    if ( !thumbnail )
        {
        score |= KTNScoreNoThumbnail;
        }

    // Score on proximity to focus 
    score |= KTNScoreMaxForDistanceFromFocus - aDistance; // More distance, less points

    __ASSERT_DEBUG(score != 0, Panic(EGlxPanicLogicError));

    return score;
    }

// -----------------------------------------------------------------------------
// SpecForIndex
// -----------------------------------------------------------------------------
//
const CGlxThumbnailContext::TFetchSpec& CGlxThumbnailContext::SpecForIndex(
        TInt aListIndex, const MGlxMediaList* aList) const
    {
    TRACER( "CGlxThumbnailContext::SpecForIndex");
    
    __ASSERT_DEBUG(aList, Panic(EGlxPanicNullPointer));

    TInt count = aList->Count();
    TInt offset = Abs(aListIndex - aList->FocusIndex());

    if ( offset > count / 2 )
        {
        offset = count - offset;
        }

    // Use specific context if one exists
    TAssignedFetchSpec spec;
    spec.iFocusOffset = offset;
    TInt index = iSpecs.Find(spec, TAssignedFetchSpec::Match);
    if ( KErrNotFound != index )
        {
        return iSpecs[index];
        }

    return iDefaultSpec;
    }

// ---------------------------------------------------------------------------
// SizeFromSpec
// ---------------------------------------------------------------------------
//
TSize CGlxThumbnailContext::SizeFromSpec( const TFetchSpec& aSpec ) const
    {
    TRACER( "CGlxThumbnailContext::SizeFromSpec");
    
    TReal32 width = iResolutionUtility->PossToPixels( aSpec.iPossWidth );
    TReal32 height = iResolutionUtility->PossToPixels( aSpec.iPossHeight );

    // Round to the nearest integers
    return TSize( width + 0.5F, height + 0.5F );
    }

// -----------------------------------------------------------------------------
// Compares two specs by focus offset. 
// -----------------------------------------------------------------------------
//
TBool CGlxThumbnailContext::TAssignedFetchSpec::Match(
        const TAssignedFetchSpec& aSpec1, const TAssignedFetchSpec& aSpec2 )
    {
    TRACER( "CGlxThumbnailContext::TAssignedFetchSpec::Match");
    
    return aSpec1.iFocusOffset == aSpec2.iFocusOffset;
    }

// -----------------------------------------------------------------------------
// HasFullThumbnail
// -----------------------------------------------------------------------------
//
TBool CGlxThumbnailContext::HasFullThumbnail( const TGlxMedia& aItem ) const
    {
    TRACER( "CGlxThumbnailContext::HasFullThumbnail");
    
    const CGlxMedia* properties = aItem.Properties();

    if ( properties )
        {
        TInt count = properties->Count();
        for ( TInt i = 0; i < count; i++ )
            {
            if ( GlxThumbnailUtility::IsFullThumbnail(
                                                properties->Attribute( i ) ) )
                {
                return ETrue;
                }
            }
        }

    return EFalse;
    }

// -----------------------------------------------------------------------------
// Check DRM status of specified item 
// -----------------------------------------------------------------------------
//    
TBool CGlxThumbnailContext::CheckDRMStatusL( TInt aListIndex,
                            const MGlxMediaList* aList, TSize& aSize ) const
    {
    TRACER( "CGlxThumbnailContext::CheckDRMStatusL");
    
    const TGlxMedia& item = aList->Item( aListIndex );
    TBool valid = EFalse;

    aSize = SizeFromSpec( SpecForIndex( aListIndex, aList ) );

    TGlxMediaGeneralRightsValidity isValid = EGlxDrmRightsValidityUnknown;
    item.GetDrmValidity(isValid);
    if ( EGlxDrmRightsValidityUnknown == isValid )
        {
        // check rights           
        TMPXGeneralCategory cat = item.Category();
        const TDesC& uri = item.Uri();
        if ( uri.Length() && cat != EMPXNoCategory )
            {
            valid = iDrmUtility->CheckOpenRightsL( uri, ( cat == EMPXImage ) );
            CGlxMedia* properties = const_cast<CGlxMedia*>(item.Properties());
            if( valid )
                {
				
                isValid = EGlxDrmRightsValid;
                }
            else
                {
				
                isValid = EGlxDrmRightsInvalid;
                }
            properties->SetTObjectValueL(KGlxMediaGeneralDRMRightsValid, isValid);
            }
        }
    else if ( EGlxDrmRightsValid == isValid )
        {	
        valid = ETrue;
        }
        if ( !valid )
            {
            // modify spec to request 'small' thumbnail
            TSize size;
            // ignore success/failure return - accept default
            item.GetDimensions(size);
            
            TSize thumbnailSize = iDrmUtility->DRMThumbnailSize( size );

            // only update spec if either dimension of required DRM thumbnail
            // is smaller than correspnding spec dimension (so don't request
            // a new thumbnail if existing one if of appropriate size )
            if( thumbnailSize.iWidth < aSize.iWidth
                || thumbnailSize.iHeight < aSize.iHeight )
                {
                aSize = thumbnailSize;
                }
        }
    return valid;
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// CGlxDefaultThumbnailContext
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//

// -----------------------------------------------------------------------------
// NewL
// -----------------------------------------------------------------------------
//
EXPORT_C CGlxDefaultThumbnailContext* CGlxDefaultThumbnailContext::NewL()
    {
    TRACER( "CGlxDefaultThumbnailContext::NewL");
    
    CGlxDefaultThumbnailContext* obj = new (ELeave) CGlxDefaultThumbnailContext();
    CleanupStack::PushL(obj);
    obj->ConstructL();
    CleanupStack::Pop(obj);
    return obj;
    }
	
// -----------------------------------------------------------------------------
// Constructor
// Sets the iterator of base class to be TGlxFromFocusOutwardIterator
// -----------------------------------------------------------------------------
//
CGlxDefaultThumbnailContext::CGlxDefaultThumbnailContext() :
        CGlxThumbnailContext(&iFromFocusIterator)
    {
    TRACER( "CGlxDefaultThumbnailContext::CGlxDefaultThumbnailContext");
    
    }

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
EXPORT_C CGlxDefaultThumbnailContext::~CGlxDefaultThumbnailContext()
    {
    TRACER( "CGlxDefaultThumbnailContext::~CGlxDefaultThumbnailContext");
    
    }
        
// ----------------------------------------------------------------------------
// Set range offsets
// ----------------------------------------------------------------------------
//
EXPORT_C void CGlxDefaultThumbnailContext::SetRangeOffsets(TInt aFrontOffset, TInt aRearOffset)
    {
    TRACER( "CGlxDefaultThumbnailContext::SetRangeOffsets");
    
    iFromFocusIterator.SetRangeOffsets(aFrontOffset, aRearOffset);
    }