browserui/browser/FeedsSrc/FeedsFileSearchAgent.cpp
author Kiiskinen Klaus (Nokia-D-MSW/Tampere) <klaus.kiiskinen@nokia.com>
Mon, 30 Mar 2009 12:49:49 +0300
changeset 0 84ad3b177aa3
permissions -rw-r--r--
Revision: 200911 Kit: 200912

/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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 "FeedsFileSearchAgent.h"
#include <fbs.h>

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES

// CONSTANTS

// MACROS

// LOCAL CONSTANTS AND MACROS

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

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


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

// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::CFileSearchAgent
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CFeedsFileSearchAgent::CFeedsFileSearchAgent(MFeedsFileSearchAgentCallback& aCallback)
    : iCallback(&aCallback), iCancelSearch(EFalse)
    {
    }

// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CFeedsFileSearchAgent::ConstructL()
    {
    TDriveList driveList;
	TChar driveLetter;
    
    // we'll keep two lists. one for the drives in the system, the 
	// other for the list of found files
    iDriveEntryList = new(ELeave) CDriveEntryList(KMaxDrives);
    iFileEntryList = new(ELeave) CFileEntryList(FEEDS_FILE_SEARCH_AGENT_MAX_RESULTS);
   	// Create a directory scan object.
    iScan = CDirScan::NewL(iFs);
    iLazyCaller = CIdle::NewL(CActive::EPriorityIdle );
			
	// Connect to fs for FS ops, etc
	User::LeaveIfError(iFs.Connect());
    	
	// populate list of drives
	GetDriveListL();
    }

// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CFeedsFileSearchAgent* CFeedsFileSearchAgent::NewL(MFeedsFileSearchAgentCallback& aCallback)
    {
	CFeedsFileSearchAgent* self = new( ELeave ) CFeedsFileSearchAgent(aCallback);

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

    return self;
    }

// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::~CFeedsFileSearchAgent()
// Destructor
// -----------------------------------------------------------------------------
//
CFeedsFileSearchAgent::~CFeedsFileSearchAgent()
    {
    CancelSearch();
   	iFs.Close();
    delete iScan;
   	delete iLazyCaller;
	delete iDriveEntryList;
	delete iFileEntryList;
    }


// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::StartSearchingL
//
//
// -----------------------------------------------------------------------------
//
void CFeedsFileSearchAgent::StartSearchingL()
    {
	iSearchDriveIndex = -1;
	
   	// Return control to the CIdle
    // The searching work will be done in LazyCallBack.
    iLazyCaller->Start(TCallBack(CFeedsFileSearchAgent::LazyCallBack,this));

    }

// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::GetFileEntry
//
//
// -----------------------------------------------------------------------------
//
TFileEntry* CFeedsFileSearchAgent::GetFileEntry(const TInt aIndex)
	{
	// for a client, return a pointer to a file that was found given
	// it's index within the list of found files
	if(aIndex >= iFileEntryList->Count())
		{
		return NULL;
		}
	else
		{
		return &(iFileEntryList->At(aIndex));
		}
	}

// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::GetDriveListL
//
//
// -----------------------------------------------------------------------------
//
void CFeedsFileSearchAgent::GetDriveListL()
	{
	TDriveList driveList;
   	
   	// Setup List of drives
   	// DriveList will return an array of 26 bytes.
   	// nonzero entries means there is media present in 
   	// that drive letter. 
    User::LeaveIfError(iFs.DriveList(driveList));
    for (TInt i=0; i<KMaxDrives; i++)
		{
    	if (driveList[i])
        	{
        	TDriveEntry driveEntry;
        	
        	// Assign a drive letter to the drive entry.
        	// In the returned list of drives, index 0 corresponds to A:\,
        	// 1 to B:\, etc.
            driveEntry.iLetter = 'A' + i;
            
            // map the letter back to the drive number. This should be the 
            // same as "i"
            iFs.CharToDrive(driveEntry.iLetter, driveEntry.iNumber);
            
 			// Add to the list of drives that we keep
 			iDriveEntryList->AppendL(driveEntry);
            }
        }
	}
	
// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::DoSearchFilesL
//
// Searches a given path or paths for a filename and add it to this class' list
// of found files. The filename can contain wildcards.
// -----------------------------------------------------------------------------
//	
TInt CFeedsFileSearchAgent::DoSearchFiles(const TDesC& aFileName, const TDesC& aPath)
	{
	TFindFile fileFinder(iFs);
	CDir* dir = NULL;
	
	// given a semicolon-separated lists of paths to search in,
	// look for the filename (that can include wildcards) found in that path or paths
	// This first search will allocate memory for dir and will contain the list of
	// files found within the first path given
	TInt err = fileFinder.FindWildByPath(aFileName, &aPath, dir);
	
	while(err == KErrNone)
		{
		// For the current path given,
		// loop through list of found items within that path 
		for (TInt i=0; i<dir->Count(); i++)
			{
			TEntry entry = (*dir)[i];

			// create and setup TParse object, useful for later extracting parts
			// of the found files used by clients of this class
			TParse parsedName;
			parsedName.Set(entry.iName, &fileFinder.File(), NULL);
			
			// as a sanity check,
			// make sure the drive, path are valid and
			// that the drive found matches the path given
			if(parsedName.Drive().Length() && aPath.Length() && parsedName.Drive()[0] == aPath[0])
				{
				// the wildcard search may have found directories that match
				// exlude these from our list because we use this function to 
				// record files only 
				if(!entry.IsDir())
					{
					// Create a fileEntry based upon the found file
					// FullName will be the complete path specifier for the file
					// while entry will be just the name within the directory					
					TFileEntry fileEntry;
					fileEntry.iPath = parsedName.FullName();
					fileEntry.iEntry = entry;
					
					// copy this entry into to our list of found files
					TRAP(err, iFileEntryList->AppendL(fileEntry));
					
					// If we have exceeded our maximum number of possible entries,
					// or we're cancelling an ongoing search
					// then stop adding to the list
					if(iFileEntryList->Count() >= FEEDS_FILE_SEARCH_AGENT_MAX_RESULTS ||
						iCancelSearch)	
						{
						// cleanup dir
						if(dir != NULL)
							{
							delete(dir);
							dir = NULL;
							}
						return err;
						}
					}
				}
			}
			
			//
			// We have completed looking at the results for this dir. Look
			// At the results where we left off, for the next path given. 
			// If there is no next path, KErrNotFound will be returned, we'll 
			// complete the search cycle.
			//
			if(dir != NULL)
				{				
				delete(dir);
				dir = NULL;
				}
			err = fileFinder.FindWild(dir);
		}

		// Cleanup the final instance of dir that has been allocated
		if(dir != NULL)
			{			
			delete(dir);
			dir = NULL;
			}
		return err;
	}
	
// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::DoSearchFilesRecursive
//
// Starting from a given path, search the filesystem recursively for a given
// filename. The filename may contain wildcards.
// -----------------------------------------------------------------------------
//	
	
TInt CFeedsFileSearchAgent::DoSearchFilesRecursive(const TDesC& aFileName)
    {
    TInt err(KErrNone);
    CDir* dir = NULL;

    // Find the entries from the next directory in the hierarchy
    // or NULL/error if there are none
    TRAP(err, iScan->NextL(dir));

	// done, break out of loop
    if(!dir || (err != KErrNone) )
        {
        return KErrGeneral;
        }

	// loop through the number of found directories
	for(TInt i=0; i < dir->Count(); i++)
        {
        TEntry entry = (*dir)[i];

        // The search will find directories as well as files. We're
        // only interested here in directories.
        if(entry.IsDir())
            {
            // From the scan, get the full path including the drive letter
            // being scanned.
            TFileName path(iScan->FullPath());

            if(path.Length())
                {
                // If valid, append a slash to the end of the directory, 
                // and then search for the desired filename given this path
                path.Append(entry.iName);
                path.Append(_L("\\"));
                DoSearchFiles(aFileName,path);
                }
            }
        }

    // Delete the dir that was allocated in this iteration
    if(dir != NULL)
        {
        delete(dir);
        dir = NULL;
        }

    return err;
    }

// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::LazyCallBack
//
// This function calls StartSearchFile instead of calling it from StartSearchingL function
// To ensure it doesn't called if user has cancelled the request
// -----------------------------------------------------------------------------
//
TBool CFeedsFileSearchAgent::LazyCallBack(TAny* aPtr)
    {
    CFeedsFileSearchAgent* ptr = (CFeedsFileSearchAgent*)aPtr;
    // if we've cancelled the search
    // then stop adding to the list
    if(!ptr->iCancelSearch)
        {
        return ptr->StartSearchFile();    
        }
    else
        {
        return EFalse;
        }    
    }

// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::StartSearchFile
//
// starts the search of *.OPML Files.
// -----------------------------------------------------------------------------
//
TBool CFeedsFileSearchAgent::StartSearchFile()
    {
    // Quit looping and don't try to scan if we've already exceeded the number of 
    // possible file entries
    // or if we've cancelled the search
    if(iFileEntryList->Count() >= FEEDS_FILE_SEARCH_AGENT_MAX_RESULTS ||
            iCancelSearch)
        {
        TRAP_IGNORE(iCallback->FeedsFileSearchCompleteL( iFileEntryList->Count() ));
        return EFalse;	
        }
    TInt retVal = KErrGeneral;
    if(iSearchDriveIndex != -1)
        {
        retVal = DoSearchFilesRecursive( _L("*.opml"));
        }
    if(retVal != KErrNone)
        {
        iSearchDriveIndex++;
        if(iSearchDriveIndex < iDriveEntryList->Count())
            {
            TDriveEntry driveEntry = iDriveEntryList->At(iSearchDriveIndex);
            TBuf<5> driveRoot;

            driveRoot.Append(driveEntry.iLetter);
            driveRoot.Append(_L(":\\"));    	

            // Search the base of the drive and also search recursively
            // through it's folder hierarchy.
            DoSearchFiles(_L("*.opml"),driveRoot);
            TRAP_IGNORE(iScan->SetScanDataL(driveRoot, KEntryAttDir|KEntryAttMatchMask, ESortByName | EAscending | EDirsFirst));
            return ETrue;
            }
        else
            {
            TRAP_IGNORE(iCallback->FeedsFileSearchCompleteL( iFileEntryList->Count() ));
            return EFalse;
            }
        }
    else
        {
        return ETrue;
        }
    }

// -----------------------------------------------------------------------------
// CFeedsFileSearchAgent::CancelSearch.
//
// Cancel the ongoing search.
// -----------------------------------------------------------------------------
//	    
void CFeedsFileSearchAgent::CancelSearch()
    {
    if(iLazyCaller->IsActive())
        {
        iLazyCaller->Cancel();
        }
    iCancelSearch = ETrue;   
    }

// ========================== OTHER EXPORTED FUNCTIONS =========================


//  End of File