clfwrapper/ClientSrc/CCLFDefaultOperation.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 27 Apr 2010 17:05:23 +0300
branchRCL_3
changeset 10 ab88d4a85041
parent 7 3cebc1a84278
permissions -rw-r--r--
Revision: 201015 Kit: 201017

/*
* Copyright (c) 2002-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: 
*
*/



// INCLUDE FILES
#include    "CCLFDefaultOperation.h"
#include    <MCLFSortingStyle.h>
#include    <MCLFModifiableItem.h>
#include    <ContentListingFactory.h>
#include    <collate.h>
#include    <badesca.h>
#include    "MGDebugPrint.h"

// for CleanupResetAndDestroyPushL
#include <mmf/common/mmfcontrollerpluginresolver.h>

// CONSTANTS
const TInt KCLFGroupedItemArrayGranularity( 4 );
const TInt KCLFSortingStyleArrayGranularity( 3 );

// CLASS DECLARATION

/**
*  Internal helper class for sorting
*/
class TCLFSortingItem
    {
    public:
        TCLFSortingItem()
            : iData( KNullDesC ),
              iIntData( 0 ),
              iTimeData( 0 ),
              iItem( NULL )
            {
            }

        TPtrC iData;
        TInt32 iIntData;
        TTime iTimeData;
        MCLFItem* iItem;
    };

// ============================= LOCAL FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CompareAlphaAscending
// -----------------------------------------------------------------------------
//
TInt CompareAlphaAscending( const TCLFSortingItem& aFirst,
                            const TCLFSortingItem& aSecond )
    {
    // get the standard method
    TCollationMethod m = *Mem::CollationMethodByIndex( 0 );
    m.iFlags |= TCollationMethod::EIgnoreNone | TCollationMethod::EFoldCase;
    return aFirst.iData.CompareC( aSecond.iData, 3, &m  );
    }

// -----------------------------------------------------------------------------
// CompareIntAscending
// -----------------------------------------------------------------------------
//
TInt CompareIntAscending( const TCLFSortingItem& aFirst,
                          const TCLFSortingItem& aSecond )
    {
    return aFirst.iIntData - aSecond.iIntData;
    }

// -----------------------------------------------------------------------------
// CompareTimeAscending
// -----------------------------------------------------------------------------
//
TInt CompareTimeAscending( const TCLFSortingItem& aFirst,
                           const TCLFSortingItem& aSecond )
    {
    if ( aFirst.iTimeData > aSecond.iTimeData )
        {
        return 1;
        }
    else if ( aFirst.iTimeData < aSecond.iTimeData )
        {
        return -1;
        }
    return 0;
    }

// -----------------------------------------------------------------------------
// AppendItemsArrayL
// -----------------------------------------------------------------------------
//
void AppendItemsToArrayL( const TArray<MCLFItem*>& aSourceArray,
                          RPointerArray<MCLFItem>& aDestArray )
    {
    for( TInt i = aSourceArray.Count() - 1; i >=0; i--)
        {
        aDestArray.AppendL( aSourceArray[ i ] );
        }
    }

// -----------------------------------------------------------------------------
// AppendItemsToArrayL
// append aSourceArray items to aDestArray
// -----------------------------------------------------------------------------
//
void AppendItemsToArrayL( const TArray<MCLFItem*>& aSourceArray,
                          RPointerArray<MCLFItem>& aDestArray,
                          TCLFUndefinedItemPosition aPosition,
                          TInt& aItemIndex,
                          TInt& aLastAddedItemCount )
    {
    if( aPosition == ECLFSortingStyleUndefinedFirst )
        {
        aItemIndex = aItemIndex - aLastAddedItemCount;
        }

    aLastAddedItemCount = aSourceArray.Count();
    for( TInt i = 0 ; i < aLastAddedItemCount ; ++i )
        {
        aDestArray.InsertL( aSourceArray[i], aItemIndex );
        ++aItemIndex;
        }
    }

// -----------------------------------------------------------------------------
// AppendSortingItemsArrayL
// -----------------------------------------------------------------------------
//
void AppendSortingItemsToArrayL( const TArray<TCLFSortingItem>& aSourceArray,
                                 RPointerArray<MCLFItem>& aDestArray )
    {
    const TInt count( aSourceArray.Count() );
    for( TInt i = 0 ; i < count ; ++i )
        {
        aDestArray.AppendL( aSourceArray[i].iItem );
        }
    }

// -----------------------------------------------------------------------------
// AppendSortingItemsArrayReverseL
// -----------------------------------------------------------------------------
//
void AppendSortingItemsToArrayReverseL(
                        const TArray<TCLFSortingItem>& aSourceArray,
                        RPointerArray<MCLFItem>& aDestArray )
    {
    for( TInt i = aSourceArray.Count() - 1 ; i > -1 ; --i )
        {
        aDestArray.AppendL( aSourceArray[i].iItem );
        }
    }

// -----------------------------------------------------------------------------
// MakeSortingItemsL
// Add/Make items to sorting item array and undefined items to
// undefined item array
// -----------------------------------------------------------------------------
//
void MakeSortingItemsL( RArray<TCLFSortingItem>& aSortingItemArray,
                        RPointerArray<MCLFItem>& aUndefinedItemArray,
                        const TArray<MCLFItem*>& aItemArray,
                        const TArray<TCLFFieldId> aSortFields,
                        TCLFItemDataType aSortingDataType )
    {
    const TInt sortingFieldsCount( aSortFields.Count() );
    const TInt count( aItemArray.Count() );
    for( TInt i = 0 ; i < count ; ++i )
        {
        MCLFItem* seItem = aItemArray[i];
        TCLFSortingItem sortingItem;
        TInt fieldIdIndex( -1 );
        TInt error( KErrNone );
        do
            {
            ++fieldIdIndex;
            TCLFFieldId fieldId( aSortFields[fieldIdIndex] );
            switch( aSortingDataType )
                {
                case ECLFItemDataTypeDesC:
                    {
                    error = seItem->GetField( fieldId, sortingItem.iData );
                    break;
                    }
                case ECLFItemDataTypeTInt32:
                    {
                    error = seItem->GetField( fieldId, sortingItem.iIntData );
                    break;
                    }
                case ECLFItemDataTypeTTime:
                default:
                    {
                    error = seItem->GetField( fieldId, sortingItem.iTimeData );
                    break;
                    }
                }
            } while( ( error != KErrNone ) &&
                     ( fieldIdIndex < ( sortingFieldsCount - 1 ) ) );
        if( error == KErrNone )
            {
            sortingItem.iItem = seItem;
            aSortingItemArray.AppendL( sortingItem );
            }
        else
            { // field not found -> undefined item
            aUndefinedItemArray.AppendL( seItem );
            }
        }
    }

// -----------------------------------------------------------------------------
// SortSortingItemsL
// Select correct sortign operation
// -----------------------------------------------------------------------------
//
void SortSortingItemsL( RArray<TCLFSortingItem>& aItemArray,
                        TCLFItemDataType aSortingDataType )
    {
    TLinearOrder<TCLFSortingItem>* sorter = NULL;

    switch ( aSortingDataType )
        {
        case ECLFItemDataTypeDesC:
            {
            sorter = new ( ELeave ) TLinearOrder<TCLFSortingItem>
                        ( CompareAlphaAscending );
            break;
            }
        case ECLFItemDataTypeTInt32:
            {
            sorter = new ( ELeave ) TLinearOrder<TCLFSortingItem>
                        ( CompareIntAscending );
            break;
            }
        case ECLFItemDataTypeTTime:
        default:
            {
            sorter = new ( ELeave ) TLinearOrder<TCLFSortingItem>
                        ( CompareTimeAscending );
            break;
            }
        }

    aItemArray.Sort( *sorter );
    delete sorter;
    sorter = NULL;
    }

// -----------------------------------------------------------------------------
// SortItemsBySortingStyleL
// sort aItemArray with aSortingStyle
// add undefined items to aUndefinedItemArray
// -----------------------------------------------------------------------------
//
void SortItemsBySortingStyleL( RPointerArray<MCLFItem>& aItemArray,
                               MCLFSortingStyle& aSortingStyle,
                               RPointerArray<MCLFItem>& aUndefinedItemArray )
    {
    RArray<TCLFFieldId> sortingFields;
    CleanupClosePushL( sortingFields );
    aSortingStyle.GetFieldsL( sortingFields );
    const TInt sortingFieldsCount( sortingFields.Count() );
    if( sortingFieldsCount )  // sort only if there are sorting fields
        {
        TCLFItemDataType sortingDataType( aSortingStyle.SortingDataType() );

        RArray<TCLFSortingItem> sortingArray;
        CleanupClosePushL( sortingArray );
        MakeSortingItemsL( sortingArray,
                           aUndefinedItemArray,
                           aItemArray.Array(),
                           sortingFields.Array(),
                           sortingDataType );

        SortSortingItemsL( sortingArray, sortingDataType );

        aItemArray.Reset();
        if( aSortingStyle.Ordering() == ECLFOrderingAscending )
            {
            AppendSortingItemsToArrayL( sortingArray.Array(),
                                        aItemArray );
            }
        else
            {
            AppendSortingItemsToArrayReverseL( sortingArray.Array(),
                                               aItemArray );
            }

        CleanupStack::PopAndDestroy( &sortingArray ); // sortingArray.Close
        }
    CleanupStack::PopAndDestroy( &sortingFields ); // sortingFields.Close
    }


// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CCLFDefaultOperation::CCLFDefaultOperation
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CCLFDefaultOperation::CCLFDefaultOperation()
    : iSortingStyle( NULL ),
      iSortingStyleArray( KCLFSortingStyleArrayGranularity ),
      iGrouping( ECLFNoGrouping ),
      iGroupedItemList( KCLFGroupedItemArrayGranularity )
    {
    }

// -----------------------------------------------------------------------------
// CCLFDefaultOperation::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CCLFDefaultOperation* CCLFDefaultOperation::NewL()
    {
    return new( ELeave ) CCLFDefaultOperation;
    }

// -----------------------------------------------------------------------------
// CCLFDefaultOperation::NewL
// Destructor
// -----------------------------------------------------------------------------
//
CCLFDefaultOperation::~CCLFDefaultOperation()
    {
    iGroupedItemList.ResetAndDestroy();
    iSortingStyleArray.Close();
    }


// -----------------------------------------------------------------------------
// CCLFDefaultOperation::SetSortingStyle
// -----------------------------------------------------------------------------
//
void CCLFDefaultOperation::SetSortingStyle( MCLFSortingStyle* aSortingStyle )
    {
    iSortingStyle = aSortingStyle;
    iSortingStyleArray.Reset();
    }

// -----------------------------------------------------------------------------
// CCLFDefaultOperation::AppendSortingStyleL
// -----------------------------------------------------------------------------
//
void CCLFDefaultOperation::AppendSortingStyleL(
                                            MCLFSortingStyle& aSortingStyle )
    {
    iSortingStyleArray.AppendL( &aSortingStyle );
    }

// -----------------------------------------------------------------------------
// CCLFDefaultOperation::SetGrouping
// -----------------------------------------------------------------------------
//
void CCLFDefaultOperation::SetGrouping( TCLFGrouping aGrouping )
    {
    iGrouping = aGrouping;
    }

// -----------------------------------------------------------------------------
// CCLFDefaultOperation::FilterItemsL
// -----------------------------------------------------------------------------
//
void CCLFDefaultOperation::FilterItemsL( const TArray<MCLFItem*>& aItemList,
                                   RPointerArray<MCLFItem>& aFilteredItemList )
    {
    AppendItemsToArrayL( aItemList, aFilteredItemList );
    }

// -----------------------------------------------------------------------------
// CCLFDefaultOperation::GroupItemsL
// -----------------------------------------------------------------------------
//
void CCLFDefaultOperation::GroupItemsL( const TArray<MCLFItem*>& aSourceList,
                                        RPointerArray<MCLFItem>& aGroupedList )
    {
    iGroupedItemList.ResetAndDestroy();
    switch ( iGrouping )
        {
        case ECLFMusicAlbumGrouping:
            {
            DoMusicAlbumGroupingL( aSourceList, aGroupedList );
            break;
            }
        case ECLFNoGrouping:
        default:
            {
            AppendItemsToArrayL( aSourceList, aGroupedList );
            break;
            }
        }
    }

// -----------------------------------------------------------------------------
// CCLFDefaultOperation::SortItemsL
// -----------------------------------------------------------------------------
//
void CCLFDefaultOperation::SortItemsL( RPointerArray<MCLFItem>& aItemArray )
    {
    if( iSortingStyle )
        {
        RPointerArray<MCLFItem> array;
        CleanupClosePushL( array );
        RPointerArray<MCLFItem> array1;
        CleanupClosePushL( array1 );
        RPointerArray<MCLFItem>* undefinedItemArray = &array;
        RPointerArray<MCLFItem>* newUndefinedItemArray = &array1;

        SortItemsBySortingStyleL( aItemArray,
                                  *iSortingStyle,
                                  *undefinedItemArray );
        TInt lastAddedItemCount( aItemArray.Count() );
        TInt nextItemIndex( lastAddedItemCount );
        TCLFUndefinedItemPosition position(
                                    iSortingStyle->UndefinedItemPosition() );

        const TInt secondarySorterCount( iSortingStyleArray.Count() );
        for( TInt i = 0 ; i < secondarySorterCount ; ++i )
            {
            MCLFSortingStyle& sortingStyle = *iSortingStyleArray[i];

            newUndefinedItemArray->Reset();
            // sort undefined items
            SortItemsBySortingStyleL( *undefinedItemArray,
                                      sortingStyle,
                                      *newUndefinedItemArray );

            // append sorted items to aItemArray
            AppendItemsToArrayL( undefinedItemArray->Array(),
                                 aItemArray,
                                 position,
                                 nextItemIndex,
                                 lastAddedItemCount );


            position = sortingStyle.UndefinedItemPosition();

            // change pointers
            RPointerArray<MCLFItem>* tmp = undefinedItemArray;
            undefinedItemArray = newUndefinedItemArray;
            newUndefinedItemArray = tmp;
            }


        // copy rest undefined items to correct position
        AppendItemsToArrayL( undefinedItemArray->Array(),
                             aItemArray,
                             position,
                             nextItemIndex,
                             lastAddedItemCount );

                                    // close undefined arrays
        CleanupStack::PopAndDestroy( 2, &array );
        }
        // else no sorting
    }


// -----------------------------------------------------------------------------
// CCLFDefaultOperation::DoMusicAlbumGroupingL
// -----------------------------------------------------------------------------
//
void CCLFDefaultOperation::DoMusicAlbumGroupingL(
                                    const TArray<MCLFItem*>& aSourceList,
                                    RPointerArray<MCLFItem>& aGroupedList )
    {
    CleanupResetAndDestroyPushL( aGroupedList );
    
    CDesCArray* tempAlbumNameArray =
                new (ELeave) CDesCArraySeg( KCLFGroupedItemArrayGranularity );
    CleanupStack::PushL( tempAlbumNameArray );

    const TInt count( aSourceList.Count() );
    for( TInt i = 0 ; i < count ; ++i )
        {
        const MCLFItem* item = aSourceList[i];
        TPtrC albumName;
        if( item->GetField( ECLFFieldIdAlbum, albumName ) == KErrNone )
            {
            TInt pos( 0 );
            if( tempAlbumNameArray->FindIsq( albumName, pos ) )
                {
                // not found
                tempAlbumNameArray->InsertIsqL( albumName );

                // make new item
                MCLFModifiableItem* newItem =
                                ContentListingFactory::NewModifiableItemLC();
                newItem->AddFieldL( ECLFFieldIdAlbum, albumName );
                iGroupedItemList.AppendL( newItem );    // takes ownership
                CleanupStack::Pop(); // newItem

                TPtrC artistName;
                if( item->GetField( ECLFFieldIdArtist, artistName ) == KErrNone )
                    {
                    newItem->AddFieldL( ECLFFieldIdArtist, artistName );
                    }

                // add new item to grouper list
                aGroupedList.AppendL( newItem );
                }
            }
        }
    CleanupStack::PopAndDestroy( tempAlbumNameArray );
    
    CleanupStack::Pop( &aGroupedList );
    }

//  End of File