filemanager/GFLM/src/CGflmFileListModel.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:31:07 +0100
branchRCL_3
changeset 21 65326cf895ed
parent 0 6a9f87576119
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

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



// INCLUDE FILES
#include "CGflmFileListModel.h"
#include "MGflmItemGroup.h"
#include "CGflmItemGroupImpl.h"
#include "CGflmDirectoryListingCache.h"
#include "CGflmFileRecognizer.h"
#include "CGflmDriveResolver.h"
#include "CGflmItemLocalizer.h"
#include "CGflmFileSystemItem.h"
#include "CGflmGlobalActionItem.h"
#include "CGflmFileFinder.h"
#include "MGflmItemFilter.h"
#include "GflmUtils.h"
#include "GFLMConsts.h"
#include "GFLM.hrh"
#include <e32base.h>
#include <e32std.h>
#include <badesca.h>


// CONSTANTS

// Granularity of iGroups array
const TInt KItemGroupArrayGranularity = 3;


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

// -----------------------------------------------------------------------------
// CGflmFileListModel::CGflmFileListModel
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CGflmFileListModel::CGflmFileListModel( RFs& aFs ) :
        CActive( CActive::EPriorityStandard ),
        iFs( aFs )
    {
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CGflmFileListModel* CGflmFileListModel::NewL( RFs& aFs )
    {
    CGflmFileListModel* self = new( ELeave ) CGflmFileListModel( aFs );

    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    return self;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CGflmFileListModel::ConstructL()
    {
    FUNC_LOG

    CActiveScheduler::Add( this );

    iGroups = new( ELeave )
        CArrayPtrSeg< CGflmItemGroupImpl >
            ( KItemGroupArrayGranularity );
    iListingCache = CGflmDirectoryListingCache::NewL( iFs, iCanceled );
    iDriveResolver = CGflmDriveResolver::NewL( iFs );
    iFileRecognizer = CGflmFileRecognizer::NewL(
        iFs, KGFLMFileRecognizerCacheSize, iDriveResolver );
    iItemLocalizer = CGflmItemLocalizer::NewL();
    iFileFinder = CGflmFileFinder::NewL(
        iFs, *iItemLocalizer, *iDriveResolver, iCanceled );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::~CGflmFileListModel
//
// -----------------------------------------------------------------------------
//
CGflmFileListModel::~CGflmFileListModel()
    {
    FUNC_LOG

    Cancel();
    if ( iGroups )
        {
        iGroups->ResetAndDestroy();
        delete iGroups;
        }
    delete iFileFinder;
    delete iListingCache;
    delete iFileRecognizer;
    delete iItemLocalizer;
    delete iDriveResolver;
    iSemaphore.Close();
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::RefreshListL()
// Creates and starts the work thread that refreshes the model
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::RefreshListL(
        TRequestStatus& aStatus, TGflmRefreshMode aRefreshMode )
    {
    FUNC_LOG

    if ( aStatus == KRequestPending )
        {
        return;
        }

    iCorrupt = ETrue;
    iClientStatus = &aStatus;
    *iClientStatus = KRequestPending;
    iClientId = RThread().Id();

    if ( iShutdown )
        {
        // Ensure client completion
        NotifyClient( KErrNone );
        return;
        }

    iCanceled = EFalse;

    if ( !IsActive() )
        {
        // Create the work thread to do refresh
        iSemaphore.Close();
        User::LeaveIfError( iSemaphore.CreateLocal( 0 ) );

        RThread workThread;
        TInt err( workThread.Create(
            KGFLMWorkThreadName,
            WorkThreadStart,
            KGFLMWorkThreadStackSize,
            NULL,
            this ) );
        LOG_IF_ERROR1( err, "CGflmFileListModel::RefreshListL-err1=%d", err )
        User::LeaveIfError( err );
        workThread.SetPriority( EPriorityLess );
        workThread.Logon( iStatus );
        SetActive();
        iRefreshMode = aRefreshMode;
        workThread.Resume();
        workThread.Close();
        }
    else
        {
        // Signal the work thread to do refresh
        iRefreshMode = aRefreshMode;
        iSemaphore.Signal();
        }
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::WorkThreadStart()
// An entry point function for the work thread
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CGflmFileListModel::WorkThreadStart( TAny* aPtr )
    {
    FUNC_LOG

    CGflmFileListModel* self = static_cast< CGflmFileListModel* >( aPtr );
    CTrapCleanup* cleanupStack = CTrapCleanup::New();
    if ( !cleanupStack )
        {
        ERROR_LOG1(
            "CGflmFileListModel::WorkThreadStart-err1=%d", KErrNoMemory )
        return KErrNoMemory;
        }

    TRAPD( err, self->iItemLocalizer->SetupWorkThreadLocalizerL() );
    LOG_IF_ERROR1( err, "CGflmFileListModel::WorkThreadStart-err2=%d", err )

    self->WorkThread();
    self->iItemLocalizer->ReleaseWorkThreadLocalizer();
    delete cleanupStack;

    return err;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::WorkThread()
// -----------------------------------------------------------------------------
//
void CGflmFileListModel::WorkThread()
    {
    TInt err( KErrNone );
    do
        {

        // Do refresh
        iCorrupt = ETrue;
        err = KErrNone;

        TRAP( err, DoRefreshL() );
        if ( err == KErrNone )
            {
            iCorrupt = EFalse;
            }

        LOG_IF_ERROR1( err, "CGflmFileListModel::WorkThread-err=%d", err )

        NotifyClient( err );

        iSemaphore.Wait(); // Wait for refresh signal from main thread

        } while ( !iShutdown );

    if ( iShutdown )
        {
        // Disable list usage and ensure client completion
        iCorrupt = ETrue;
        NotifyClient( err );
        }
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::NotifyClient()
// -----------------------------------------------------------------------------
//
void CGflmFileListModel::NotifyClient( TInt aErr )
    {
    FUNC_LOG

    if ( iClientStatus )
        {
        RThread client;
        if ( client.Open( iClientId ) == KErrNone )
            {
            client.RequestComplete( iClientStatus, aErr );
            client.Close();
            }
        }
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::DoRefreshL()
// This method does the actual refreshing. It's not static so it can access
// member data and it can leave as it's trap harnessed in RefreshAndNotify()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CGflmFileListModel::DoRefreshL()
    {
    TIMESTAMP( "GFLM refresh files and folders started: " )

    INFO_LOG1(
        "CGflmFileListModel::DoRefreshL-iSearchEnabled=%d",
        iSearchEnabled )

    if ( iSearchEnabled )
        {
        User::LeaveIfError( iDriveResolver->RefreshDrives( iFilter ) );
        iFileFinder->RefreshL( iFilter, iSearchSortMethod, iRefreshMode );
        }
    else
        {
        if ( iRefreshMode == ERefreshItems )
            {
            iListingCache->ClearCache();
            }
        User::LeaveIfError( iDriveResolver->RefreshDrives( iFilter ) );

        TInt groupCount( iGroups->Count() );
        for ( TInt i( 0 ); i < groupCount; i++ )
            {
            iGroups->At( i )->RefreshL( iFilter, iSortMethod, iRefreshMode );
            }
        }

    TIMESTAMP( "GFLM refresh  files and folders ended: " )
	}

// -----------------------------------------------------------------------------
// CGflmFileListModel::CancelRefresh()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::CancelRefresh()
    {
    FUNC_LOG

    iCanceled = ETrue;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::MdcaCount()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CGflmFileListModel::MdcaCount() const
    {
    if ( iCorrupt )
        {
        return 0;
        }
    if ( iSearchEnabled )
        {
        return iFileFinder->ItemCount();
        }

    // Count the total number of items in groups
    TInt groupCount( iGroups->Count() );
    TInt itemCount( 0 );
    for( TInt i( 0 ); i < groupCount; i++ )
        {
        itemCount += iGroups->At( i )->ItemCount();
        }
    return itemCount;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::MdcaPoint()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TPtrC CGflmFileListModel::MdcaPoint( TInt aIndex ) const
    {
    if ( iSearchEnabled )
        {
        return iFileFinder->Item( aIndex )->Name();
        }

    // Return the formatted presentation by global index
    MGflmItemGroup* group = NULL;
    TInt localIndex( 0 );
    GetGroupAndLocalIndex( aIndex, localIndex, group );
    return group->Item( localIndex )->Name();
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::GetGroupAndLocalIndex()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CGflmFileListModel::GetGroupAndLocalIndex(
        const TInt aGlobalIndex,
        TInt& aLocalIndex,
        MGflmItemGroup*& aGroup ) const
    {
    // Calculate the group and the requested item's local index
    // from a global index
    TInt groupCount( iGroups->Count() );
    TInt offset( 0 );
    for( TInt i( 0 ); i < groupCount; i++ )
        {
        MGflmItemGroup* currentGroup = iGroups->At( i );
        TInt itemsInGroup( currentGroup->ItemCount() );
        if ( aGlobalIndex < itemsInGroup + offset )
            {
            // The global index resides in this group
            aGroup = iGroups->At( i );
            aLocalIndex = aGlobalIndex - offset;
            return;
            }
        offset += itemsInGroup;
        }

    // Group not found
    User::Panic( KGFLMPanicText, EGlobalIndexOutOfBounds );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::Item()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C CGflmGroupItem* CGflmFileListModel::Item( TInt aIndex ) const
    {
    if ( iSearchEnabled )
        {
        return iFileFinder->Item( aIndex );
        }
    // Return the formatted presentation by global index
    MGflmItemGroup* group = NULL;
    TInt localIndex( 0 );
    GetGroupAndLocalIndex( aIndex, localIndex, group );
    return group->Item( localIndex );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::ResetModel()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::ResetModel()
    {
    iGroups->ResetAndDestroy();
    iListingCache->ClearCache();
    iDriveResolver->ClearDrives();
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::FindGroupById()
// Used to provide clients with CGflmItemGroupImpl objects downcasted to
// CGflmItemGroup.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C MGflmItemGroup* CGflmFileListModel::FindGroupById( TInt aId )
    {
    TInt groupCount( iGroups->Count() );

    for( TInt i( 0 ); i < groupCount; i++ )
        {
        CGflmItemGroupImpl* group = iGroups->At( i );
        if ( aId == group->Id() )
            {
            return group;
            }
        }

    // Group not found
    User::Panic( KGFLMPanicText, EInvalidGroupId );

    // Execution never reaches this point
    // following line keeps the compiler happy
    return NULL;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::CreateGroupL()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
EXPORT_C MGflmItemGroup* CGflmFileListModel::CreateGroupL( TInt aId )
    {
    // Scan the list of groups for identical IDs
    TInt groupCount( iGroups->Count() );
    for ( TInt i( 0 ); i < groupCount; i++ )
        {
        if ( iGroups->At( i )->Id() == aId )
            {
            User::Leave( KErrAlreadyExists );
            }
        }

    CGflmItemGroupImpl* newGroup = CGflmItemGroupImpl::NewLC(
        aId,
        iFs,
        *iListingCache,
        *iItemLocalizer,
        *iDriveResolver );

    iGroups->AppendL( newGroup );
    CleanupStack::Pop( newGroup );
    return newGroup;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::CreateGroupL()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
EXPORT_C MGflmItemGroup* CGflmFileListModel::CreateGroupL(
        TInt aId, TUint aInclusion )
    {
    MGflmItemGroup* newGroup = CreateGroupL( aId );
    newGroup->SetInclusion( aInclusion );
    return newGroup;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::SetCustomFilter()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
EXPORT_C void CGflmFileListModel::SetCustomFilter( MGflmItemFilter* aFilter )
    {
    iFilter = aFilter;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::ResolveMimeTypeL()
// Uses the internal file recognition cache
// (other items were commented in a header).
// -----------------------------------------------------------------------------
EXPORT_C TPtrC CGflmFileListModel::ResolveMimeTypeL( const TDesC& aFilename )
    {
    return iFileRecognizer->RecognizeL( aFilename );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::IsCorrupt()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
EXPORT_C TBool CGflmFileListModel::IsCorrupt() const
    {
    return iCorrupt;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::LocalizedName()
// -----------------------------------------------------------------------------
//
EXPORT_C TPtrC CGflmFileListModel::LocalizedName( const TDesC& aPath ) const
    {
    return iItemLocalizer->Localize( aPath );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::ClearCache()
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::ClearCache()
    {
    iListingCache->ClearCache();
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::ClearDriveInfo()
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::ClearDriveInfo()
    {
    iDriveResolver->ClearDrives();
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::DriveFromPath()
// -----------------------------------------------------------------------------
//
EXPORT_C CGflmDriveItem* CGflmFileListModel::DriveFromPath(
        const TDesC& aPath ) const
    {
    if ( !iDriveResolver->DriveCount() )
        {
        ERROR_LOG( "CGflmFileListModel::DriveFromPath-Forced drive refresh" )
        iDriveResolver->RefreshDrives( iFilter );
        }
    return iDriveResolver->DriveFromPath( aPath );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::RunL()
// -----------------------------------------------------------------------------
//
void CGflmFileListModel::RunL()
    {
    FUNC_LOG

    NotifyClient( iStatus.Int() );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::RunError
// -----------------------------------------------------------------------------
//
TInt CGflmFileListModel::RunError( TInt /*aError*/ )
    {
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::DoCancel
// -----------------------------------------------------------------------------
//
void CGflmFileListModel::DoCancel()
    {
    FUNC_LOG

    iShutdown = ETrue;
    iSemaphore.Signal();
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::DriveFromId
// -----------------------------------------------------------------------------
//
EXPORT_C CGflmDriveItem* CGflmFileListModel::DriveFromId(
        const TInt aDrive ) const
    {
    if ( !iDriveResolver->DriveCount() )
        {
        ERROR_LOG( "CGflmFileListModel::DriveFromId-Forced drive refresh" )
        iDriveResolver->RefreshDrives( iFilter );
        }
    return iDriveResolver->DriveFromId( aDrive );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::EnableSearchMode
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::EnableSearchMode( const TBool aEnabled )
    {
    iSearchEnabled = aEnabled;
    if ( iSearchEnabled )
        {
        iSearchSortMethod = EByMatch; // Default for search
        }
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::SearchMode
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CGflmFileListModel::SearchMode()
	{
	return iSearchEnabled;
	}

// -----------------------------------------------------------------------------
// CGflmFileListModel::SetSearchStringL
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::SetSearchStringL( const TDesC& aSearchString )
    {
    iFileFinder->SetSearchStringL( aSearchString );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::SetSearchFolderL
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::SetSearchFolderL( const TDesC& aSearchFolder )
    {
    iFileFinder->SetSearchFolderL( aSearchFolder );
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::SetSortMethod
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::SetSortMethod( TGflmSortMethod aSortMethod )
    {
    if ( iSearchEnabled )
        {
        iSearchSortMethod = aSortMethod;
        }
    else if ( aSortMethod != EByMatch ) // EByMatch is allowed only for search
        {
        iSortMethod = aSortMethod;
        }
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::SortMethod
// -----------------------------------------------------------------------------
//
EXPORT_C TGflmSortMethod CGflmFileListModel::SortMethod() const
    {
    if ( iSearchEnabled )
        {
        return iSearchSortMethod;
        }
    return iSortMethod;
    }

// -----------------------------------------------------------------------------
// CGflmFileListModel::FlushCache()
// -----------------------------------------------------------------------------
//
EXPORT_C void CGflmFileListModel::FlushCache()
    {
    iFileRecognizer->FlushCache();
    }

//  End of File