sl@0: /* sl@0: * Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: sl@0: #include "cafpanic.h" sl@0: #include "contentIterator.h" sl@0: #include "FileContentIterator.h" sl@0: #include "contentiteratordata.h" sl@0: sl@0: using ContentAccess::CContentIterator; sl@0: using ContentAccess::TVirtualPathPtr; sl@0: sl@0: _LIT(KIteratorThread,"ContentIterator"); sl@0: EXPORT_C CContentIterator* CContentIterator::NewL(const TDesC& aPath, TBool aRecursive, const TDesC8& aMimeType) sl@0: { sl@0: CContentIterator* self = new (ELeave) CContentIterator(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aPath, aRecursive, aMimeType); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: CContentIterator::CContentIterator() : CActive(EPriorityStandard) sl@0: { sl@0: } sl@0: sl@0: CContentIterator::~CContentIterator() sl@0: { sl@0: // tell thread to cancel and shutdown sl@0: Cancel(); sl@0: sl@0: // close thread handle sl@0: iWorkerThread.Close(); sl@0: delete info; sl@0: } sl@0: sl@0: void CContentIterator::ConstructL(const TDesC& aPath, TBool aRecursive, const TDesC8& aMimeType) sl@0: { sl@0: // This data buffer will be shared between the client and the worker thread sl@0: info = CContentIteratorData::NewL(aPath,aRecursive,aMimeType); sl@0: sl@0: // create the thread, need a big heap and stack for recursively searching through directories sl@0: User::LeaveIfError(iWorkerThread.Create(KIteratorThread(),CContentIterator::ThreadEntry,32768, KMinHeapSize, 131072, (void *) info , EOwnerProcess)); sl@0: sl@0: // add ourselves to active scheduler sl@0: CActiveScheduler::Add(this); sl@0: sl@0: // Set up notification in case the thread panics etc sl@0: iStatus = KRequestPending; sl@0: iWorkerThread.Logon(iStatus); sl@0: SetActive(); sl@0: sl@0: // start the thread sl@0: iWorkerThread.Resume(); sl@0: } sl@0: sl@0: sl@0: void CContentIterator::DoCancel() sl@0: { sl@0: // Wait until thread finishes whatever it's doing sl@0: info->Lock(); sl@0: sl@0: // Signal for the thread to close sl@0: info->RunThreadFunction(EIteratorShutdownThread); sl@0: } sl@0: sl@0: void CContentIterator::RunL() sl@0: { sl@0: // Thread must have completed sl@0: if(iWorkerThread.ExitType() == EExitPanic) sl@0: { sl@0: // Thread panicd, better panic our thread sl@0: User::Panic(KCafPanicString, ECafPanicContentIteratorThreadPanic); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C TVirtualPathPtr CContentIterator::VirtualPath() sl@0: { sl@0: // Wait until thread finishes whatever it's doing sl@0: info->Lock(); sl@0: iFileName.Copy(info->Path()); sl@0: iUniqueId.Copy(info->UniqueId()); sl@0: info->Unlock(); sl@0: return TVirtualPathPtr(iFileName, iUniqueId); sl@0: } sl@0: sl@0: EXPORT_C const TDesC& CContentIterator::Name() sl@0: { sl@0: // Wait until thread finishes whatever it's doing sl@0: info->Lock(); sl@0: iName.Copy(info->Name()); sl@0: info->Unlock(); sl@0: return iName; sl@0: } sl@0: sl@0: EXPORT_C const TDesC8& CContentIterator::MimeType() sl@0: { sl@0: // Wait until thread finishes whatever it's doing sl@0: info->Lock(); sl@0: iMimeType.Copy(info->MimeType()); sl@0: info->Unlock(); sl@0: return iMimeType; sl@0: } sl@0: sl@0: EXPORT_C void CContentIterator::Next(TRequestStatus &aStatus) sl@0: { sl@0: // Wait until thread finishes whatever it's doing sl@0: info->Lock(); sl@0: sl@0: // Remember which thread and TRequestStatus to notify sl@0: TThreadId id = RThread().Id(); sl@0: info->SetClientRequest(id, aStatus); sl@0: sl@0: // Tell it to find the next iteration sl@0: info->RunThreadFunction(EIteratorFindNextContentObject); sl@0: } sl@0: sl@0: sl@0: TInt CContentIterator::ThreadEntry(TAny* aAny) sl@0: { sl@0: TBool exitNow = EFalse; sl@0: TInt err; sl@0: CFileContentIterator* iterator = NULL; sl@0: RThread clientThread; sl@0: CContentIteratorData* info = reinterpret_cast (aAny); sl@0: sl@0: // create a trap handler sl@0: CTrapCleanup* cleanup = CTrapCleanup::New(); sl@0: sl@0: while(!exitNow) sl@0: { sl@0: // Thread will wait here until signaled by other CContentIterator functions sl@0: switch(info->ThreadWait()) sl@0: { sl@0: // Client thread has asked us to shutdown, exit loop sl@0: case EIteratorShutdownThread: sl@0: exitNow = ETrue; sl@0: break; sl@0: // Client thread is asking us to find the next object sl@0: case EIteratorFindNextContentObject: sl@0: if(!iterator) sl@0: { sl@0: TRAP(err, iterator = CFileContentIterator::NewL(info->Path(), info->IsRecursive(), info->MimeType())); sl@0: info->SetData(KNullDesC(), KNullDesC(), KNullDesC(), KNullDesC8()); sl@0: } sl@0: else sl@0: { sl@0: err = iterator->Next(); sl@0: } sl@0: sl@0: if(err == KErrNone) sl@0: { sl@0: // If a content object was found, write the value back sl@0: // into the other thread while the info is still locked sl@0: info->SetData(iterator->FileName(),iterator->UniqueId(), iterator->Name(), iterator->MimeType()); sl@0: } sl@0: sl@0: // Complete the clients asynchronous request sl@0: info->CompleteClientRequest(err); sl@0: break; sl@0: default: sl@0: User::Panic(KCafPanicString, ECafPanicContentIteratorUnknownRequest); sl@0: break; sl@0: }; sl@0: sl@0: // Allow the client to post a new request sl@0: info->Unlock(); sl@0: } sl@0: delete iterator; sl@0: delete cleanup; sl@0: return KErrNone; sl@0: } sl@0: