// EIKFSEL.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikfsel.h> 
#include <f32file.h>
#include <coeutils.h>
#include <eikfutil.h>
#include <eikenv.h>
#include <bamatch.h>
#include <badesca.h>
#include <basched.h>
#include <barsread.h>
#include <eiktxlbm.h>
#include <eikdtlbm.h>
#include <eiklbi.h>
#include <eikchlst.h>
#include <eikchlst.hrh>
#include <eikdtlbx.h>
#include <eikon.rsg>
#include <eikpanic.h> 
#include <eikedwin.hrh>
#include <eikfsel.pan>

const TInt KFileNameArrayGranularity = 5;
const TInt KSpecialChoiceListMessageSize = 32;
const TInt KMinDirTreeListBoxHeightInNumOfItems = 7;

#define KSystemDirName _L("System") // Name for System directory

//#if defined(__WINS__)
//	const TInt KMaxFileNameLen = 200;
//#else
	const TInt KMaxFileNameLen = KMaxFileName;
//#endif

GLDEF_C void Panic(TEikFselPanic aPanic)
    {
    User::Panic(_L("EIKON-FSEL"),aPanic);
    }

LOCAL_D void DisplayInfoMsgAboutError(TInt aErrorCode)
	{
	CEikonEnv* env = CEikonEnv::Static();
	if (aErrorCode == KErrNotReady)
		env->InfoMsg(R_EIK_TBUF_DISK_NOT_PRESENT);
	else if (aErrorCode == KErrCorrupt) 
		env->InfoMsg(R_EIK_TBUF_CANNOT_BE_READ);
	}

LOCAL_D void ReportErrorAndLeaveIfNoInfoMsgAvailableL(TInt aErrorCode)
	{
	// only leaves if it doesn't have an appropriate info message to display about the error
	if (aErrorCode == KErrNone)
		return;
	if ((aErrorCode == KErrNotReady) || (aErrorCode == KErrCorrupt))
		DisplayInfoMsgAboutError(aErrorCode);	
	else
		User::Leave(aErrorCode);
	}

LOCAL_D void ReportErrorAndLeaveL(TInt aErrorCode)
	{
	// reports the error to the user (in some way) and always leaves
	if (aErrorCode == KErrNone)
		return;
	if ((aErrorCode == KErrNotReady) || (aErrorCode == KErrCorrupt))
		{
		DisplayInfoMsgAboutError(aErrorCode);	
		CBaActiveScheduler::LeaveNoAlert();
		}
	else
		User::Leave(aErrorCode);
	}

LOCAL_C void DeleteSpaces(TDes& aName,TInt aPos,TBool aDelForward)
	{
	TInt length=0;
	const TInt maxLen=aName.Length();
	FOREVER
		{
		if (aPos<0 || aPos==maxLen)
			break;
		const TUint chr=aName[aPos];
		if (!(chr==' ' || chr==CEditableText::ENonBreakingSpace || chr==CEditableText::EVisibleSpaceCharacter))
			break;
		++length;
		if (aDelForward)
			++aPos;
		else
			--aPos;
		}
	if (length)
		{
		if (aDelForward)
			aPos-=length;
		else
			++aPos;
		aName.Delete(aPos,length);
		}
	}

LOCAL_C void RemoveExcessSpaces(TDes& aName)
	{
	DeleteSpaces(aName,0,ETrue);
	TInt length=aName.Length();
	DeleteSpaces(aName,length-1,EFalse);
	length=aName.Length();
	TInt pos=0;
	while (pos<length)
		{
		if (aName[pos]==KPathDelimiter)
			{
			DeleteSpaces(aName,pos+1,ETrue);
			const TInt len=aName.Length();
			DeleteSpaces(aName,pos-1,EFalse);
			TInt newLen=aName.Length();
			pos-=(len-newLen);
			length=newLen;
			}
		++pos;
		}
	}

LOCAL_C void ReplaceWithSpace(TDes& aName,TChar aChar)
	{
	TBuf<1> replace(_L(" "));
	TInt pos=aName.Locate(aChar);
	while (pos!=KErrNotFound)
		{
		aName.Replace(pos,1,replace);
		pos=aName.Locate(aChar);
		}
	}

LOCAL_C void StandardizeSpaces(TDes& aName)
	{ // converts non-breaking and visible spaces to 'normal' ones
	ReplaceWithSpace(aName,TChar(CEditableText::ENonBreakingSpace));
	ReplaceWithSpace(aName,TChar(CEditableText::EVisibleSpaceCharacter));
	}

//
// class CEikFileNameSelector
//

EXPORT_C CEikFileNameSelector::CEikFileNameSelector()
    {
	__DECLARE_NAME(_S("CEikFileNameSelector"));
    }

EXPORT_C CEikFileNameSelector::~CEikFileNameSelector()
    {
	delete iSelectionArray;
	delete iExtension;
    }

EXPORT_C TBool CEikFileNameSelector::MultipleSelectionAllowed() const
	{
	return (iFileSelectorFlags & EMultiSelectionAllowed);
	}

EXPORT_C void CEikFileNameSelector::SetMultipleSelectionAllowed(TBool aMultipleSelectionAllowed)
	{
	if (aMultipleSelectionAllowed)
		SetFlags(EMultiSelectionAllowed);
	else
		ClearFlags(EMultiSelectionAllowed);
	if (aMultipleSelectionAllowed && !iSelectionArray)
		iSelectionArray = new(ELeave) CDesCArrayFlat(KFileNameArrayGranularity);
	else if (!aMultipleSelectionAllowed && iSelectionArray)
		{
		delete iSelectionArray;
		iSelectionArray = NULL;
		}
	}

EXPORT_C void CEikFileNameSelector::SetUidType(const TUidType& aUidType)
	{
	iUidType = aUidType;
	}

EXPORT_C void CEikFileNameSelector::ConstructFromResourceL(TResourceReader& aReader)
    {
	iChoiceListFlags |= EEikChlistIncrementalMatching;
	iMatchBuf=new(ELeave)RIncrMatcherBuf<KEikMaxMatchingBufLength>;
	iMaxDisplayChar = aReader.ReadInt16();
    }

EXPORT_C TFileName CEikFileNameSelector::FullName() const
    {
    if (!iArray || (iFileSelectorFlags & ESpecifiedFolderIsEmpty))
        return TFileName();
	TParsePtrC parse1(iRef);
	TParse parse2;
	TPtrC driveAndPath(parse1.DriveAndPath());
	if (MultipleFilesSelected())
		parse2.Set((*iSelectionArray)[0], &driveAndPath, NULL);
	else
		parse2.Set(iArray->MdcaPoint(iCurrentItem), &driveAndPath, NULL);
    return parse2.FullName();
    }

EXPORT_C TBool CEikFileNameSelector::MultipleFilesSelected() const
	{
	return (iSelectionArray && (iSelectionArray->Count() > 1));
	}

EXPORT_C void CEikFileNameSelector::SetExtensionL(const TDesC& aExtension)
	{
    HBufC* newExt = aExtension.AllocL();
	User::Free(iExtension); 
	iExtension = newExt;
	}

EXPORT_C void CEikFileNameSelector::SetFullNameL(const TDesC& aFullName)
    {
  	iCurrentItem = 0;
	ClearFlags(ESpecifiedFolderIsEmpty);
    iRef = aFullName;
    if (iArray)
        DesCArray()->Reset();
    else
        iArray = new(ELeave) CDesCArrayFlat(KFileNameArrayGranularity); 
	ResetMatchBuf();
	TBool hadMatcherCursor = (iMatchBuf != NULL);
	if (MultipleFilesSelected())
		{
		DesCArray()->Reset();
		TBuf<KSpecialChoiceListMessageSize> multipleFilesSelectedMsg;
		iCoeEnv->ReadResource(multipleFilesSelectedMsg, R_EIK_TBUF_MULTIPLE_FILES_DISPLAY);
		DesCArray()->AppendL(multipleFilesSelectedMsg);
		delete(iMatchBuf);
		iMatchBuf=NULL;
 		iChoiceListFlags &= (~EEikChlistIncrementalMatching);
		if (IsFocused() && hadMatcherCursor)
			iEikonEnv->HideCursor(this);
		ContentHasChangedL();
		return;
		}
    TInt err=TryBuildFileNameArrayL(aFullName);
    if (err || !iArray->MdcaCount())
        {
		SetFlags(ESpecifiedFolderIsEmpty);
		TBuf<KSpecialChoiceListMessageSize> noFile;
		iCoeEnv->ReadResource(noFile, R_EIK_TBUF_NO_FILES_DISPLAY);
        DesCArray()->AppendL(noFile);
		delete(iMatchBuf);
        iMatchBuf=NULL;
 		iChoiceListFlags &= (~EEikChlistIncrementalMatching);
		if (IsFocused() && hadMatcherCursor)
			iEikonEnv->HideCursor(this);
		if ((err != KErrNone) && (err != KErrNotFound))
			ReportErrorAndLeaveL(err);
		ContentHasChangedL();
		return;
        }
	iChoiceListFlags |= EEikChlistIncrementalMatching;
	if (!iMatchBuf)
		iMatchBuf=new(ELeave)RIncrMatcherBuf<KEikMaxMatchingBufLength>;
	if ((err != KErrNone) && (err != KErrNotFound))
		ReportErrorAndLeaveL(err);
	TryFindCurrentItemL(aFullName);
	if (IsFocused())
		DisplayCursor();
	}

void CEikFileNameSelector::TryFindCurrentItemL(const TDesC& aFullName)
	{
	const TInt fileNameListSize=iArray->MdcaCount();
	TParsePtrC parse(aFullName);
	TPtrC nameAndExt=parse.NameAndExt();
    for (TInt i=0; i<fileNameListSize; i++)
		{
		if (iArray->MdcaPoint(i).CompareF(nameAndExt)==0)
			{
			iCurrentItem = i;
			ContentHasChangedL();
			break;
			}
		}	
	}
    
TInt CEikFileNameSelector::TryBuildFileNameArrayL(const TDesC& aFullName)
	{
	TInt err=0;
	TParse *parse = new(ELeave) TParse;
	CleanupStack::PushL(parse);
    User::LeaveIfError(iCoeEnv->FsSession().Parse(aFullName, *parse));
    FOREVER
        {
        err=BuildFileNameArrayL(*parse, iArray);
        if (err!=KErrPathNotFound)
            break;
        parse->PopDir();
        }
	CleanupStack::PopAndDestroy();
	return(err);
	}

EXPORT_C TInt CEikFileNameSelector::BuildFileNameArrayL(const TParse& aParse, MDesCArray* aFileNames)
    {
	TFileName* dirName = new(ELeave) TFileName;
	CleanupStack::PushL(dirName);
	*dirName = aParse.DriveAndPath();
	if ((dirName->Length() + 1) <= KMaxFileNameLen)
		dirName->Append(_L("*"));
	else
		ReportErrorAndLeaveL(KErrOverflow);
    if (iExtension)
		{
		if ((dirName->Length() + iExtension->Length()) <= KMaxFileNameLen)
			dirName->Append(*iExtension);
		else
			ReportErrorAndLeaveL(KErrOverflow);
		}
	CDir* fileList = NULL;
	TInt retcode = iEikonEnv->FsSession().GetDir(*dirName, KEntryAttSystem | KEntryAttAllowUid, ESortByName, fileList);
	CleanupStack::PopAndDestroy();	// dirName
	if (retcode == KErrNone)
		{
		CleanupStack::PushL(fileList);
		TInt fileListSize = fileList->Count();
		for (TInt i = 0; i < fileListSize; i++)
			{
			if (EikFileUtils::UidTypeMatches((*fileList)[i].iType, iUidType))
				((CDesCArray*)aFileNames)->AppendL((*fileList)[i].iName);  
			}
		CleanupStack::PopAndDestroy();  // fileList
		}
    return(retcode);
    }

EXPORT_C void CEikFileNameSelector::HandleFullNameChangedEventL(const TFileName& aFullName, TUpdateEvent /*aUpdateEvent*/)
	{
	if ((MultipleSelectionAllowed()) && (IsReadyToDraw()))
		((CDesCArray*)iSelectionArray)->Reset();

	User::LeaveIfError(EikFileUtils::Parse(aFullName));
	TParsePtrC parse(aFullName);
	TEikDriveName driveName = parse.Drive().Left(1);
	TInt driveId;
	User::LeaveIfError(iEikonEnv->FsSession().CharToDrive(driveName[0], driveId));
	TVolumeInfo volInfo;
	TInt retcode = iEikonEnv->FsSession().Volume(volInfo,driveId);
	if ((retcode == KErrCorrupt) || (retcode == KErrNotReady))
        {
  		iCurrentItem = 0;
		iRef = aFullName;
		if (iArray)
			DesCArray()->Reset();
		else
			iArray = new(ELeave) CDesCArrayFlat(KFileNameArrayGranularity); 
		ResetMatchBuf();
		TBool hadMatcherCursor = (iMatchBuf != NULL);
		SetFlags(ESpecifiedFolderIsEmpty);
		TBuf<KSpecialChoiceListMessageSize> noFile;
		iCoeEnv->ReadResource(noFile, R_EIK_TBUF_NO_FILES_DISPLAY);
        DesCArray()->AppendL(noFile);
		delete(iMatchBuf);
        iMatchBuf=NULL;
 		iChoiceListFlags &= (~EEikChlistIncrementalMatching);
		if (IsFocused() && hadMatcherCursor)
			iEikonEnv->HideCursor(this);
		CurrentItemChangedL();
		DrawNow();
		return;
		}

	TFileName* fullName = new(ELeave) TFileName;
	CleanupStack::PushL(fullName);

	*fullName = aFullName;
	// check to see if there is a name; if not, append a "*"
	if (fullName->Right(1) == _L("\\")) 
		if (fullName->Length() + 1 <= KMaxFileNameLen)
			fullName->Append(_L("*"));
		else
			ReportErrorAndLeaveL(KErrOverflow);
	SetFullNameL(*fullName);
	CleanupStack::PopAndDestroy();
	DrawNow();
	}

EXPORT_C void CEikFileNameSelector::GetFullNamesOfSelectedFilesL(CDesCArray* aFullNames) const
	{
	aFullNames->Reset();
	if (! MultipleFilesSelected())
		aFullNames->AppendL(FullName());
	else
		{
		const TInt count = ((CDesCArray*)iSelectionArray)->Count();
		TParsePtrC parse1(iRef);
		TParse parse2;
		for (TInt i=0; i < count; i++)
			{
			TPtrC driveAndPath(parse1.DriveAndPath());
			parse2.Set((*iSelectionArray)[i], &driveAndPath, NULL);
			aFullNames->AppendL(parse2.FullName());
			}
		}
	}

EXPORT_C void CEikFileNameSelector::SetSelectedFileNamesL(CDesCArray* aFileNames)
	{
	const TInt selectionCount = aFileNames->Count();
	iSelectionArray->Reset();
	for (TInt i = 0; i < selectionCount; i++)
		iSelectionArray->AppendL((*aFileNames)[i]);
	}

EXPORT_C void CEikFileNameSelector::DoCreatePopoutL()
    {
	iPopoutListBox = new(ELeave) CEikFileSelectorListBox();
	TInt listBoxFlags = CEikListBox::EPopout;
	if ((iChoiceListFlags & EEikChlistIncrementalMatching) && (! MultipleSelectionAllowed()))
		listBoxFlags |= CEikListBox::EIncrementalMatching;
	if (MultipleSelectionAllowed())
		listBoxFlags |= CEikListBox::EMultipleSelection;
	PopoutTextListBox()->ConstructL(NULL, listBoxFlags);
	iPopoutListBox->CreateScrollBarFrameL();
	iPopoutListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto);
	iPopoutListBox->SetObserver(this);
    TPoint choicePosScreenCoords=PositionRelativeToScreen();
	iEikonEnv->AddWindowShadow(iPopoutListBox);
	TParse* parse = new(ELeave) TParse;
	CleanupStack::PushL(parse);
	if (MultipleFilesSelected())
		{
		// should assert if iTempFileNameArray is not NULL
		iTempFileNameArray  = new(ELeave) CDesCArrayFlat(KFileNameArrayGranularity); 
		TInt err;
		FOREVER
			{
			User::LeaveIfError(parse->Set(FullName(), NULL, NULL));
			err=BuildFileNameArrayL(*parse, iTempFileNameArray);
			if (err!=KErrPathNotFound)
				break;
			User::LeaveIfError(parse->PopDir());
			}
		PopoutTextListBox()->Model()->SetItemTextArray(iTempFileNameArray);
		PopoutTextListBox()->Model()->SetOwnershipType(ELbmDoesNotOwnItemArray);
		}
	else
		{
		PopoutTextListBox()->Model()->SetItemTextArray(iArray);
		PopoutTextListBox()->Model()->SetOwnershipType(ELbmDoesNotOwnItemArray);
		}
	const TInt listBoxWidth=Size().iWidth;
	TRect listBoxRect(TPoint(choicePosScreenCoords.iX, 0), TSize(listBoxWidth, 0));
	iPopoutListBox->CalculatePopoutRect(iCurrentItem, choicePosScreenCoords.iY, listBoxRect);
	iPopoutListBox->SetExtentL(TPoint(choicePosScreenCoords.iX, listBoxRect.iTl.iY), listBoxRect.Size());
	TInt currentItemIndex = iCurrentItem;
	CArrayFix<TInt>* selectionIndexes = NULL;
	if (MultipleSelectionAllowed())
		{
		selectionIndexes = new(ELeave) CArrayFixFlat<TInt>(5);
		CleanupStack::PushL(selectionIndexes);
		if (MultipleFilesSelected())
			{
			TInt fileListSize = iTempFileNameArray->Count();
			TInt selectionCount = iSelectionArray->Count();
			for (TInt i = 0; i < selectionCount; i++)
				for (TInt j = 0; j < fileListSize; j++)
					{
					User::LeaveIfError(parse->Set((*iSelectionArray)[i], NULL, NULL));
					if (parse->NameAndExt() == (*iTempFileNameArray)[j])
						{
						selectionIndexes->AppendL(j);
						break;
						}
					}
			}
		else if (! (iFileSelectorFlags & ESpecifiedFolderIsEmpty))
			selectionIndexes->AppendL(currentItemIndex);
		iPopoutListBox->SetSelectionIndexesL(selectionIndexes);
		CleanupStack::PopAndDestroy();
		}
	CleanupStack::PopAndDestroy();	// get rid of "parse"
	iPopoutListBox->SetCurrentItemIndex(currentItemIndex);
	if (MultipleSelectionAllowed())
		iPopoutListBox->View()->SetAnchor(currentItemIndex);
	// now update (if ncessary) top item index so that current item index is visible 
	if (!(iPopoutListBox->View()->ItemIsVisible(iCurrentItem)))
		iPopoutListBox->SetTopItemIndex(iPopoutListBox->View()->CalcNewTopItemIndexSoItemIsVisible(iCurrentItem));
    iEikonEnv->AddDialogLikeControlToStackL(iPopoutListBox);
	iPopoutListBox->ActivateL();
	iPopoutListBox->HandleItemAdditionL();
    }

EXPORT_C void CEikFileNameSelector::DestroyPopout()
    {
	delete iTempFileNameArray;
	iTempFileNameArray = NULL;
	CEikChoiceList::DestroyPopout();
    }

EXPORT_C void CEikFileNameSelector::HandleInteractionConfirmedL()
    {
	TInt oldCurrentItem = iCurrentItem;
	TParse* parse = new(ELeave) TParse;
	CleanupStack::PushL(parse);
	if (MultipleFilesSelected())
		{
		iSelectionArray->Reset();
		const CArrayFix<TInt>* newSelectionIndexes = iPopoutListBox->SelectionIndexes();
		TInt newSelectionCount = newSelectionIndexes->Count();
		// three cases to deal with: no files selected; one file selected; two or more files selected
		if (newSelectionCount == 0)
			SetFullNameL(iRef);
		else if (newSelectionCount == 1)
			{
			TInt selectedItemIndex = (*newSelectionIndexes)[0];
			User::LeaveIfError(parse->Set((*iTempFileNameArray)[selectedItemIndex], &iRef, NULL));
			SetFullNameL(parse->FullName());
			}
		else 
			{
			TInt selectionIndex;
			for (TInt i = 0; i < newSelectionCount; i++)
				{
				selectionIndex = (*newSelectionIndexes)[i];
				iSelectionArray->AppendL((*iTempFileNameArray)[selectionIndex]);
				}
			TInt selectedItemIndex = (*newSelectionIndexes)[0];
			User::LeaveIfError(parse->Set(iTempFileNameArray->MdcaPoint(selectedItemIndex), &iRef, NULL));
			SetFullNameL(parse->FullName());
			}
		}
	else
		{
		if (MultipleSelectionAllowed())
			{
			const CArrayFix<TInt>* newSelectionIndexes = iPopoutListBox->SelectionIndexes();
			TInt newSelectionCount = newSelectionIndexes->Count();
			if (newSelectionCount == 0) 
				{
				iCurrentItem = 0;
				if (iCurrentItem!=oldCurrentItem)
					ContentHasChangedL();
				}
			else if (newSelectionCount == 1)  
				{
				iCurrentItem = (*newSelectionIndexes)[0];
				if (iCurrentItem!=oldCurrentItem)
					ContentHasChangedL();
				}
			else
				{
				((CDesCArray*)iSelectionArray)->Reset();
				TInt selectionIndex;
				for (TInt i = 0; i < newSelectionCount; i++)
					{
					selectionIndex = (*newSelectionIndexes)[i];
					iSelectionArray->AppendL(iArray->MdcaPoint(selectionIndex));
					}
				TInt selectedItemIndex = (*newSelectionIndexes)[0];
				User::LeaveIfError(parse->Set(iArray->MdcaPoint(selectedItemIndex), &iRef, NULL));
				SetFullNameL(parse->FullName());
				}
			}
		else 
			{
			iCurrentItem = PopoutCurrentItem();
			if (iCurrentItem != oldCurrentItem)
				ContentHasChangedL();
			}
		}
	CleanupStack::PopAndDestroy();   // parse
    }

EXPORT_C void CEikFileNameSelector::ValidateStateL()
	{
	TBuf<32> noFileMsg;		
	iCoeEnv->ReadResource(noFileMsg, R_EIK_TBUF_NO_FILES_DISPLAY);
	if (iFileSelectorFlags & ESpecifiedFolderIsEmpty) 
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_NO_FILENAME_SPECIFIED);
	}

EXPORT_C void CEikFileNameSelector::DrawContent() const
	{
	TFileName displayedFileName = iArray->MdcaPoint(iCurrentItem);
	if (! MultipleFilesSelected())
		displayedFileName = iArray->MdcaPoint(iCurrentItem);
	DoDrawContent(displayedFileName);
    }

EXPORT_C void CEikFileNameSelector::SetFileSelectionObserver(MEikFileSelectionObserver* aObserver)
	{
	iFileSelectionObserver = aObserver;
	}

EXPORT_C void CEikFileNameSelector::CurrentItemChangedL()
	{
	if (iFileSelectionObserver)
		iFileSelectionObserver->HandleFullNameChangedEventL(FullName(), EFullNameChanged);
	}

EXPORT_C MEikFileSelectionObserver* CEikFileNameSelector::FileSelectionObserver() const
	{
	return iFileSelectionObserver;
	}

EXPORT_C TUidType CEikFileNameSelector::UidType() const
	{
	return iUidType;
	}


//
// class CEikFileSelectorListBox
//

EXPORT_C CEikFileSelectorListBox::CEikFileSelectorListBox()
    {
	__DECLARE_NAME(_S("CEikFileSelectorListBox"));
    }

EXPORT_C void CEikFileSelectorListBox::CreateItemDrawerL()
	{
	iItemDrawer = new(ELeave) CFileSelectorItemDrawer((CTextListBoxModel*)iModel,iEikonEnv->NormalFont());
	}


//
// class CFileSelectorItemDrawer
//

EXPORT_C CFileSelectorItemDrawer::CFileSelectorItemDrawer(MTextListBoxModel* aTextListBoxModel,const CFont* aFont)
	: CTextListItemDrawer(aTextListBoxModel, aFont)
	{
	}

EXPORT_C void CFileSelectorItemDrawer::DrawItemText(TInt aItemIndex, const TRect& aItemTextRect, TBool aItemIsCurrent, TBool aViewIsEmphasized) const
	{
	iGc->UseFont(iFont);
	TPtrC des = iModel->ItemText(aItemIndex);
	DoDrawItemText(des, aItemTextRect, aItemIsCurrent, aViewIsEmphasized);
	}


//
// class CEikFileNameEditor
//

EXPORT_C CEikFileNameEditor::CEikFileNameEditor()
    {
	__DECLARE_NAME(_S("CEikFileNameEditor"));
	iTextLimit = KMaxFileName;
    }

EXPORT_C CEikFileNameEditor::~CEikFileNameEditor()
    {
    }

EXPORT_C void CEikFileNameEditor::ConstructFromResourceL(TResourceReader& aReader)
    {
	TInt widthInfoFromResFile = aReader.ReadInt16();
	const CFont* font=iEikonEnv->NormalFont();
	iSize.iWidth = widthInfoFromResFile * font->MaxNormalCharWidthInPixels();
	iNumberOfLines = 1;
	CEikEdwin::BaseConstructL();
    }

EXPORT_C void CEikFileNameEditor::SetAppendExtension(TBool aAppendExtension)
	{
	iAppendExtension = aAppendExtension;
	}

EXPORT_C void CEikFileNameEditor::GetFullNameL(TFileName& aFileName)
    { 
	TFileName* fileNameEntered=new(ELeave) TFileName;
	CleanupStack::PushL(fileNameEntered);
	GetText(*fileNameEntered);
	StandardizeSpaces(*fileNameEntered);

	if (fileNameEntered->Length()==0)
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_NO_FILENAME_SPECIFIED);
	if (!(iEikonEnv->FsSession().IsValidName(*fileNameEntered)))
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_INVALID_FILE_NAME);

	RemoveExcessSpaces(*fileNameEntered);
	TParse* parse=new(ELeave) TParse;
	CleanupStack::PushL(parse);
	parse->Set(*fileNameEntered,NULL,NULL);
	const TBool hasDrive=parse->DrivePresent();
	const TBool hasPath=parse->PathPresent();
	if ((hasDrive && !hasPath) || !parse->NamePresent())
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_INVALID_FILE_NAME);
	
	const TBool hasExt=parse->ExtPresent();
	parse->Set(iRef,NULL,NULL);

	// check length
	TInt length=fileNameEntered->Length();
	length+=(hasDrive? 0 : parse->Drive().Length());
	length+=(hasPath? 0 : parse->Path().Length());
	if (iAppendExtension && !hasExt)
		length+=parse->Ext().Length();
	if (length>KMaxFileNameLen)
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_FILENAME_TOO_LONG);  
	
	parse->Set(*fileNameEntered,&iRef,NULL);
	if (iAppendExtension || hasExt)
		aFileName=parse->FullName();
	else
		{
		aFileName=parse->DriveAndPath();
		aFileName.Append(parse->Name());
		}
	CleanupStack::PopAndDestroy(2);	// fileNameEntered, parse
    }

EXPORT_C void CEikFileNameEditor::SetFullNameL(const TDesC& aFullName)
    {
    iRef = aFullName;
	TParsePtr parse(iRef);
	if (parse.NameOrExtPresent() && (! parse.IsNameWild()))
		{
		TPtrC nameAndExt(parse.NameAndExt());
		SetTextL(&nameAndExt);
		DrawNow();
		}
	}

EXPORT_C void CEikFileNameEditor::HandleFullNameChangedEventL(const TFileName& aFullName, TUpdateEvent aUpdateEvent)
	{
	if (aUpdateEvent == EFullNameChanged)
		SetFullNameL(aFullName);
	else
		iRef = aFullName;
	}

EXPORT_C void CEikFileNameEditor::Reserved_1()
	{
	}

EXPORT_C void CEikFileNameEditor::Reserved_2()
	{
	}

EXPORT_C void CEikFileNameEditor::Reserved_3()
	{
	}

//
// class CEikFolderNameSelector
//

EXPORT_C CEikFolderNameSelector::CEikFolderNameSelector()
    {
	__DECLARE_NAME(_S("CEikFolderNameSelector"));
    }

EXPORT_C CEikFolderNameSelector::~CEikFolderNameSelector()
    {
    }

EXPORT_C TFileName CEikFolderNameSelector::FullName() const
	{
	TParse parse;
    parse.Set(iArray->MdcaPoint(iCurrentItem), &iRef, NULL);
    return parse.FullName();
	}

EXPORT_C void CEikFolderNameSelector::SetFullNameL(const TDesC& aFullName)
	{
	TParse *parse = new(ELeave) TParse;
	CleanupStack::PushL(parse);
	TFileName *specifiedFolder = new(ELeave) TFileName;
	CleanupStack::PushL(specifiedFolder);
	TFileName *sysFolderName = new(ELeave) TFileName;
	CleanupStack::PushL(sysFolderName);
	*sysFolderName = _L("\\");
	sysFolderName->Append(KSystemDirName);
	sysFolderName->Append(_L("\\"));
	iRef = aFullName;
	User::LeaveIfError(parse->Set(aFullName, NULL, NULL));
	*specifiedFolder = parse->DriveAndPath();
	if (iRoot == TPtrC())
		SetRootL(EikFileUtils::RootFolderPath(parse->Drive().Left(1)));
    User::LeaveIfError(iCoeEnv->FsSession().Parse(iRoot, *parse));
	// strip out the drive 
	specifiedFolder->Delete(0,2);
	User::LeaveIfError(parse->Set(aFullName, NULL, NULL));
	TBool foundSpecifiedFolder = EFalse;
	TInt numOfPops = 0;		// number of dirs we had to pop from the supplied path to find it in the folder list
	TInt retcode = KErrNone;
	FOREVER
		{
		TInt count=iArray->MdcaCount();
		while ((! foundSpecifiedFolder) && (count--))
			{
#if defined(__WINS__)
		TFileName existingFolder = iArray->MdcaPoint(count);
#endif

			TBool systemFolderSpecified = (specifiedFolder->CompareF(*sysFolderName) == 0);
			if (systemFolderSpecified && (!(iFolderSelectorFlags & EShowSystem)))
				{
				*specifiedFolder = _L("\\");
				SetCurrentItem(0);
				CurrentItemChangedL(); 
				foundSpecifiedFolder = ETrue;
				break;
				}
			if (specifiedFolder->CompareF(iArray->MdcaPoint(count)) == 0)
				{
				User::LeaveIfError(parse->Set(aFullName, NULL, NULL));
				TUint attributes;
				retcode = iEikonEnv->FsSession().Att(parse->DriveAndPath(), attributes);
				if (retcode == KErrNone)
					{
					if ((numOfPops > 0) && (EikFileUtils::CheckFolder(parse->DriveAndPath()) == KErrNone) && (!(attributes & KEntryAttHidden)))
						{
						FullyExpandFolderL(count, ETrue);
						TInt i = count;
						*specifiedFolder = parse->Path();
						TInt mdcaCount = iArray->MdcaCount();
						for (; i < mdcaCount; i++)
							{
	#if defined(__WINS__)
							TFileName existingFolder = iArray->MdcaPoint(i);
	#endif
							if (specifiedFolder->CompareF(iArray->MdcaPoint(i)) == 0) 
								break;
							}
						count = (i==mdcaCount) ? --mdcaCount : i;
						}
					}
				SetCurrentItem(count);
				CurrentItemChangedL(); 
				foundSpecifiedFolder = ETrue;
				}
			}
		if (foundSpecifiedFolder)
			break;
		retcode = parse->PopDir();
		++numOfPops;
		if (retcode == KErrNone)
			{
			*specifiedFolder=parse->Path();
			if (*specifiedFolder == _L("\\"))
				{
				User::LeaveIfError(parse->Set(iRoot, NULL, NULL));
				*specifiedFolder = parse->Path();
				}
			}
		else
			Panic(EEikPanicFSelNoSuchFolder);
		}
	CleanupStack::PopAndDestroy(3);	// "parse", "specifiedFolder", and "sysFolderName"
	}

EXPORT_C void CEikFolderNameSelector::CreateFlattenedHierarchyL()
	{ 
	User::LeaveIfError(EikFileUtils::Parse(iRoot));
	TParsePtr parse(iRoot);
	CDesCArray* array=new(ELeave) CDesCArrayFlat(5);
	SetArrayL(array);
	// there will always be an entry in the array corresponding to the root folder
	DesCArray()->AppendL(parse.Path());
	FullyExpandFolderL(0, ETrue);
	}

EXPORT_C void CEikFolderNameSelector::FullyExpandFolderL(TInt aIndexOfFolderToFullyExpand, TBool aAutoExpandAllFolders)
	{
	// add all descendants of the specified folder to the folder list
	User::LeaveIfError(EikFileUtils::Parse(iRoot));
	TParsePtr parse(iRoot);
	TFileName *path = new(ELeave) TFileName;
	CleanupStack::PushL(path);
	TInt count = aIndexOfFolderToFullyExpand;
	while (count < DesCArray()->MdcaCount())
		{
		*path = parse.Drive();
		if (path->Length() + iArray->MdcaPoint(count).Length() <= KMaxFileNameLen)
			path->Append(iArray->MdcaPoint(count));
		else
			ReportErrorAndLeaveL(KErrOverflow);
		if (! aAutoExpandAllFolders)
			{
			if (iArray->MdcaPoint(count) == _L("\\"))     
				ExpandFolderL(path, count);
			}
		else
			ExpandFolderL(path, count);
		++count;
		}
	CleanupStack::PopAndDestroy();	//  "path"
	}

EXPORT_C void CEikFolderNameSelector::ExpandFolderL(TDes* aPath, TInt aPositionToInsertSubFolders)
	{
	if (aPath->Length()==KMaxFileNameLen)
		return; // can't possibly be anything inside here
	TFileName *folderName = new(ELeave) TFileName;
	CleanupStack::PushL(folderName);
	aPath->Append(_L("*"));
	CDir* dirList;
	CDir* entryList;
	TInt retcode = iEikonEnv->FsSession().GetDir(*aPath,KEntryAttSystem,ESortByName|EDescending,entryList, dirList);
	ReportErrorAndLeaveL(retcode);
	delete entryList;
	if (!(iFolderSelectorFlags & EShowSystem))
		EikFileUtils::RemoveSystemDirectory(*dirList);
	CleanupStack::PushL(dirList);
	aPath->Delete(0,2);				// strip out the drive portion of the path
	aPath->Delete(aPath->Length()-1,1); // remove '*' at end
	TInt dirCount=dirList->Count();
	for (TInt jj=0;jj<dirCount;jj++)
		{
		*folderName = *aPath;
		if ((folderName->Length() + (*dirList)[jj].iName.Length() + 1) <= KMaxFileNameLen)
			{
			folderName->Append((*dirList)[jj].iName);
			folderName->Append(_L("\\"));
			}
		else
			ReportErrorAndLeaveL(KErrOverflow);
		DesCArray()->InsertL(aPositionToInsertSubFolders+1, *folderName);
		}
	CleanupStack::PopAndDestroy(2);	// "dirList" and "folderName"
	}

EXPORT_C void CEikFolderNameSelector::SetRootL(const TDesC& aRoot)
	{
	iRoot=aRoot;
	User::LeaveIfError(EikFileUtils::Parse(iRoot));
	TParsePtr parse(iRoot);
	TEikDriveName driveName = parse.Drive().Left(1);
	TInt driveId;
	User::LeaveIfError(iEikonEnv->FsSession().CharToDrive(driveName[0], driveId));
	TVolumeInfo volInfo;
	TInt retcode = iEikonEnv->FsSession().Volume(volInfo,driveId);
	ReportErrorAndLeaveL(retcode);
	if (iRoot.Right(1)!=_L("\\"))
		if ((iRoot.Length() + 1) <= KMaxFileNameLen)
			iRoot.Append(_L("\\"));
		else
			ReportErrorAndLeaveL(KErrOverflow);
	retcode = EikFileUtils::CheckFolder(aRoot);
	if (retcode != KErrNone)
		{
		iRoot = parse.Drive();
		if ((iRoot.Length() + 1) <= KMaxFileNameLen)
			iRoot.Append(_L("\\"));
		else
			ReportErrorAndLeaveL(KErrOverflow);
		}
	CreateFlattenedHierarchyL();
	}

EXPORT_C void CEikFolderNameSelector::ConstructFromResourceL(TResourceReader& aReader)
	{
	iMaxDisplayChar = aReader.ReadInt16();
	}

void CEikFolderNameSelector::SetRootFromReferenceL()
	{
	SetRootL(EikFileUtils::RootFolderPath(iRef.Left(1)));
	}

EXPORT_C void CEikFolderNameSelector::HandleFullNameChangedEventL(const TFileName& aFullName, TUpdateEvent /*aUpdateEvent*/)
	{
	iFolderSelectorFlags |= EFullNameUpdate;
	iRef = aFullName;

	User::LeaveIfError(EikFileUtils::Parse(aFullName));
	TParsePtrC parse(aFullName);
	TEikDriveName driveName = parse.Drive().Left(1);
	TInt driveId;
	User::LeaveIfError(iEikonEnv->FsSession().CharToDrive(driveName[0], driveId));
	TVolumeInfo volInfo;
	TInt retcode = iEikonEnv->FsSession().Volume(volInfo,driveId);
	if ((retcode == KErrCorrupt) || (retcode == KErrNotReady))
		{
		iRoot = parse.Drive();
		iRoot.Append(_L("\\"));
		if (iArray)
			DesCArray()->Reset();
		else
			{
			CDesCArray* array=new(ELeave) CDesCArrayFlat(5);
			SetArrayL(array);
			}
		DesCArray()->AppendL(_L("\\"));
		SetCurrentItem(0);		// so that the folder selector shows the root folder as being selected
		CurrentItemChangedL(); 
		iFolderSelectorFlags &= (~ EFullNameUpdate);
		DrawNow();
		return;
		}

	if (IsActivated())
		SetRootFromReferenceL();
	SetFullNameL(aFullName);
	iFolderSelectorFlags &= (~ EFullNameUpdate);
	DrawNow();
	}

EXPORT_C void CEikFolderNameSelector::CurrentItemChangedL()
	{
	if (iFileSelectionObserver)
		{
		if (iFolderSelectorFlags & EFullNameUpdate)
			iFileSelectionObserver->HandleFullNameChangedEventL(FullName(), EFullNameChanged);
		else
			iFileSelectionObserver->HandleFullNameChangedEventL(FullName(), EPathChanged);
		}
	}

EXPORT_C void CEikFolderNameSelector::SetFileSelectionObserver(MEikFileSelectionObserver* aObserver)
	{
	iFileSelectionObserver = aObserver;
	}

EXPORT_C void CEikFolderNameSelector::CreateListBoxL()
	{
	iPopoutListBox = new(ELeave) CEikDirectoryTreeListBox;
	}

EXPORT_C void CEikFolderNameSelector::InitializeListBoxL()
	{
	TInt listBoxFlags = CEikListBox::EPopout;
	if (iFolderSelectorFlags & EShowSystem)
		PopoutDirTreeListBox()->ConstructL(NULL, listBoxFlags,CDirectoryTreeListBoxModel::EShowSystem);
	else
		PopoutDirTreeListBox()->ConstructL(NULL, listBoxFlags,0);
	TParse *parse = new(ELeave) TParse;
	CleanupStack::PushL(parse);

	User::LeaveIfError(parse->Set(iRef, NULL, NULL));
	TBuf<1> driveBuff = (parse->Drive()).Left(1);
	TDriveNumber driveNumber = (TDriveNumber)(driveBuff[0]-'A');
	TRAPD(retcode, PopoutDirTreeListBox()->CreateListL(&driveNumber));
	if (retcode != KErrNone)
		ReportErrorAndLeaveL(retcode);
	TRAP(retcode, PopoutDirTreeListBox()->DtlModel()->ExpandAllItemsL());
	if (retcode != KErrNone)
		ReportErrorAndLeaveL(retcode);
	TInt choiceListArraySize = DesCArray()->Count();
	CArrayFix<CHierListItem*>* hierListArray = PopoutDirTreeListBox()->DtlModel()->HierListArray();
	if (choiceListArraySize > hierListArray->Count())
		{
		CDirectoryTreeListBoxModel* treeListBoxModel = PopoutDirTreeListBox()->DtlModel();
		for (TInt i = 1; i < choiceListArraySize; i++)
			{
			if (i >= hierListArray->Count())
				{
				TRAP(retcode, PopoutDirTreeListBox()->DtlModel()->ExpandItemL(i-1));
				}
			else 
				{
				User::LeaveIfError(parse->Set(treeListBoxModel->FullPath(i), NULL, NULL));
				if (iArray->MdcaPoint(i).CompareF(parse->Path()) != 0)
					{
					TRAP(retcode, PopoutDirTreeListBox()->DtlModel()->ExpandItemL(i-1));
					}
				}
			if (retcode != KErrNone)
				ReportErrorAndLeaveL(retcode);
			}
		}

	CleanupStack::PopAndDestroy();	// "parse"

	iPopoutListBox->CreateScrollBarFrameL();
	iPopoutListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto);
	iPopoutListBox->SetObserver(this);
	iEikonEnv->AddWindowShadow(iPopoutListBox);
	}

EXPORT_C void CEikFolderNameSelector::ActivateListBoxL()
	{
	TRAPD(retcode, PopoutDirTreeListBox()->SetCurrentItemPathL(FullName()));
	if (retcode != KErrNone)
		ReportErrorAndLeaveL(retcode);
    iEikonEnv->AddDialogLikeControlToStackL(iPopoutListBox);
	iPopoutListBox->ActivateL();
	iPopoutListBox->HandleItemAdditionL();
    }

EXPORT_C void CEikFolderNameSelector::SetListBoxExtentL()
	{
	TInt listBoxWidth = iPopoutListBox->CalcWidthBasedOnRequiredItemWidth(CalculateTextWidth()); 
    TPoint choicePosScreenCoords=PositionRelativeToScreen();
	TRect listBoxRect(TPoint(choicePosScreenCoords.iX, 0), TSize(listBoxWidth, 0));
	iPopoutListBox->CalculatePopoutRect(iCurrentItem, choicePosScreenCoords.iY, listBoxRect, KMinDirTreeListBoxHeightInNumOfItems);
	iPopoutListBox->SetExtentL(TPoint(choicePosScreenCoords.iX, listBoxRect.iTl.iY), listBoxRect.Size());
	}

EXPORT_C void CEikFolderNameSelector::DrawContent() const
	{
	TFileName displayedFolderPath;
	TPtrC actualFolderPath=iArray->MdcaPoint(iCurrentItem);
	const TBuf<1> pathDelimeter = _L("\\");
	const TBuf<1> rootDirPath = _L("\\");
	if (iArray && iArray->MdcaCount() && (iCurrentItem != -1))
		{
		displayedFolderPath = actualFolderPath;
		if (actualFolderPath == rootDirPath)
			displayedFolderPath = _L(" ");
		else
			{
			// remove trailing backslash
			if ((displayedFolderPath != rootDirPath) && (displayedFolderPath.Right(1) == pathDelimeter))
				displayedFolderPath.Delete(displayedFolderPath.Length()-1, 1);
			// remove leading backslash 
			if ((displayedFolderPath != rootDirPath) && (displayedFolderPath.Left(1) == pathDelimeter))
				displayedFolderPath.Delete(0, 1);
			}
		}
    TRect rect = iBorder.InnerRect(Rect());
	const CFont* font = iEikonEnv->NormalFont();
	TFileName abbreviatedPath = EikFileUtils::AbbreviatePath(displayedFolderPath, *font, rect.Width());
	DoDrawContent(abbreviatedPath);
    }

EXPORT_C void CEikFolderNameSelector::MatchTypedChar(TUint aCode)
	{
	// should try to find some way to reuse some of the code in CEikChoiceListBase!
	TChar aChar(aCode);
	aChar.Fold();
	TInt index=iCurrentItem+1;
	TInt noItems=iArray->MdcaCount();
	TFileName folderNameForMatchingPurposes;
	for (TInt count=0; count<noItems; count++,index++)
		{
	    if (index==noItems)
	        index=0;
		if (iArray->MdcaPoint(index) == _L("\\"))
			folderNameForMatchingPurposes = _L(" ");
		else
			folderNameForMatchingPurposes = EikFileUtils::FolderNameFromFullName(iArray->MdcaPoint(index));
		TChar tempChar=folderNameForMatchingPurposes[0];
		tempChar.Fold();
		if ((aChar==tempChar)&&(index!=iCurrentItem))
			{
			iCurrentItem=index;
			return;
			}
		}
	}

EXPORT_C CEikDirectoryTreeListBox* CEikFolderNameSelector::PopoutDirTreeListBox() const
	{
	return((CEikDirectoryTreeListBox*)iPopoutListBox);
	}

EXPORT_C void CEikFolderNameSelector::HandleInteractionConfirmedL()
    {
	// need to find out whether or not the item selected is a descendant of the root folder
	TParse *parse = new(ELeave) TParse;
	CleanupStack::PushL(parse);
	TFileName *selectedFolderFullName = new(ELeave) TFileName;
	CleanupStack::PushL(selectedFolderFullName);
	DesCArray()->Reset();
	CArrayFix<CHierListItem*>* hierListArray = PopoutDirTreeListBox()->DtlModel()->HierListArray();
	TInt hierListArraySize = hierListArray->Count();
	TInt i = 0;
	for (i = 0; i < hierListArraySize; i++)
		{
		User::LeaveIfError(parse->Set(PopoutDirTreeListBox()->DtlModel()->FullPath(i), NULL, NULL));
		DesCArray()->AppendL(parse->Path());
		}
	TInt dirTreeListBoxSelectedItemIndex = PopoutDirTreeListBox()->CurrentItemIndex();
	*selectedFolderFullName = PopoutDirTreeListBox()->DtlModel()->FullPath(dirTreeListBoxSelectedItemIndex);
	SetFullNameL(*selectedFolderFullName);
	DrawNow();
	CleanupStack::PopAndDestroy(2);	// "parse" and "selectedFolderFullName"
    }

EXPORT_C void CEikFolderNameSelector::DestroyPopout()
    {
	CEikChoiceList::DestroyPopout();
    }

EXPORT_C void CEikFolderNameSelector::SetShowSystem(TBool aShowSystem)
	{
	if (aShowSystem)
		iFolderSelectorFlags |= EShowSystem;
	else
		iFolderSelectorFlags &= (~EShowSystem);	
	}

//
// class CEikFolderNameEditor
//

EXPORT_C CEikFolderNameEditor::CEikFolderNameEditor()
    {
	__DECLARE_NAME(_S("CEikFolderNameEditor"));
	iTextLimit = KMaxFileName;
    }

EXPORT_C CEikFolderNameEditor::~CEikFolderNameEditor()
    {
    }

EXPORT_C void CEikFolderNameEditor::ConstructFromResourceL(TResourceReader& aReader)
    {
	TInt widthInfoFromResFile = aReader.ReadInt16();
	const CFont* font=iEikonEnv->NormalFont();
	iSize.iWidth = widthInfoFromResFile * font->MaxNormalCharWidthInPixels();
	iNumberOfLines = 1;
	CEikEdwin::BaseConstructL();
    }

EXPORT_C TFileName CEikFolderNameEditor::FullName() const
    { // MUST call ValidateStateL() before this
	TFileName folderName;
	GetText(folderName);
	RemoveExcessSpaces(folderName);
	StandardizeSpaces(folderName);
	TParse parse;
	parse.Set(folderName,&iRef,NULL);
	folderName=parse.FullName();
	if (folderName.Right(1)!=_L("\\"))
		folderName.Append(_L("\\"));
	return folderName;
    }

EXPORT_C void CEikFolderNameEditor::SetFullNameL(const TDesC& aFullName)
    {
	iRef=aFullName;
	TFileName folderName(EikFileUtils::FolderNameFromFullName(aFullName));
	SetTextL(&folderName);
	}

EXPORT_C void CEikFolderNameEditor::HandleFullNameChangedEventL(const TFileName& aFullName, TUpdateEvent /*aUpdateEvent*/)
	{
	SetFullNameL(aFullName);
	}

EXPORT_C void CEikFolderNameEditor::ValidateStateL()
	{
	TFileName *folderName=new(ELeave) TFileName;
	CleanupStack::PushL(folderName);
	GetText(*folderName);
	if (folderName->Length()==0)
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_NO_FOLDERNAME_SPECIFIED);
	if (!(iEikonEnv->FsSession().IsValidName(*folderName)))
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_INVALID_FOLDER_NAME);
	TParse* parse=new(ELeave) TParse;
	CleanupStack::PushL(parse);
	User::LeaveIfError(parse->Set(*folderName,NULL,NULL));
	const TBool hasDrive=parse->DrivePresent();
	const TBool hasPath=parse->PathPresent();
	User::LeaveIfError(parse->Set(iRef,NULL,NULL));
	TInt length=folderName->Length();
	length+=(hasDrive? 0 : parse->Drive().Length());
	length+=(hasPath? 0 : parse->Path().Length());
	if (folderName->Right(1)!=_L("\\"))
		++length;
	if (length>KMaxFileNameLen)
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_FOLDERNAME_TOO_LONG);  
	CleanupStack::PopAndDestroy(2); // foldername, parse
	}


//
// class CEikDriveNameSelector
//

EXPORT_C CEikDriveNameSelector::CEikDriveNameSelector()
	: iDriveSelectorFlags(EHideROM)
	{
	__DECLARE_NAME(_S("CEikDriveNameSelector"));
	}

EXPORT_C CEikDriveNameSelector::CEikDriveNameSelector(TInt aFlags)
	: iDriveSelectorFlags(aFlags)
	{
	__DECLARE_NAME(_S("CEikDriveNameSelector"));
	}

EXPORT_C CEikDriveNameSelector::~CEikDriveNameSelector()
	{
	}

EXPORT_C void CEikDriveNameSelector::ShowRom(TBool aShowRom)
	{
	if (aShowRom)
		iDriveSelectorFlags &= (~EHideROM);
	else
		iDriveSelectorFlags |= EHideROM;
	}

EXPORT_C void CEikDriveNameSelector::AllowCorruptDisk(TBool aAllowCorruptDisk)
	{
	if (aAllowCorruptDisk)
		iDriveSelectorFlags |= EAllowCorruptDisk;
	else
		iDriveSelectorFlags &= (~EAllowCorruptDisk);
	}

EXPORT_C void CEikDriveNameSelector::ConstructFromResourceL(TResourceReader& /*aReader*/)
    {
	iMaxDisplayChar=1;
	BuildDriveNameArrayL();
    }

EXPORT_C void CEikDriveNameSelector::BuildDriveNameArrayL()
	{
	iArray=new(ELeave) CDesCArrayFlat(2);
	TDriveNumber driveNum=EDriveC; // is it safe to assume c: as the initial drive ???
	if (iRef.Length())
		{
		TParsePtrC parse(iRef);
		TBufC<2> buf(parse.Drive());
		TBuf<2> drv=buf.Des();
		drv.UpperCase();
		driveNum=TDriveNumber(drv[0]-'A');
		}
	EikFileUtils::UpdateDiskListL(iCoeEnv->FsSession(),*DesCArray(),ETrue,driveNum); // always show ROM
	}

EXPORT_C TFileName CEikDriveNameSelector::FullName() const
	{
	TBuf<2> drive;
	if (iArray)
		{
		drive = iArray->MdcaPoint(iCurrentItem);
		drive.Append(_L(":"));
		}
	TParse parse;
	TInt retcode = parse.Set(drive, &iRef, NULL);
	if (retcode == KErrNone)
		return parse.FullName();
	else
		return TFileName();
	}

TEikDriveName CEikDriveNameSelector::DriveNameFromFullName(const TDesC& aFullName) const
	{
	TParsePtrC parse(aFullName);
	return(parse.Drive().Left(1));
	}

EXPORT_C void CEikDriveNameSelector::SetFullNameL(const TDesC& aFullName)
	{
	User::LeaveIfError(EikFileUtils::Parse(aFullName));
	iRef = aFullName;
	TParsePtrC parse(aFullName);
	TEikDriveName specifiedDriveName = parse.Drive().Left(1);
	TInt driveId;
	User::LeaveIfError(iEikonEnv->FsSession().CharToDrive(specifiedDriveName[0], driveId));
	TDriveInfo driveInfo;
	ReportErrorAndLeaveIfNoInfoMsgAvailableL(iEikonEnv->FsSession().Drive(driveInfo, driveId));
	EikFileUtils::UpdateDiskListL(iCoeEnv->FsSession(),*DesCArray(),ETrue,TDriveNumber(driveId)); // always show ROM
	if (driveInfo.iDriveAtt & KDriveAttRom)		// see if supplied fullname specifies the ROM drive ("z"?)
		iDriveSelectorFlags &= (~EHideROM);
	TInt numOfAvailableDrives = iArray->MdcaCount();
	TInt i = 0;
	if (iDriveSelectorFlags & EHideROM)
		while (i < numOfAvailableDrives)
			{
			User::LeaveIfError(iEikonEnv->FsSession().CharToDrive(iArray->MdcaPoint(i)[0], driveId));
			if (driveId==EDriveZ)
				{
				DesCArray()->Delete(i, 1);
				break;
				}
			else
				++i;
			}
	else
		{
		// if the EHideROM flag has not been set and the drive name corresponding to RAM is not in the array, it should be added to it
		}
	// look for the specified drive in the revised drive name array
	numOfAvailableDrives = iArray->MdcaCount();
	i = 0;
	while (i < numOfAvailableDrives)
		{
		if (iArray->MdcaPoint(i).CompareF(specifiedDriveName) == 0)
			break;
		++i;
		}
	if (i < numOfAvailableDrives)
		{
		SetCurrentItem(i);
		DrawNow();
		specifiedDriveName = iArray->MdcaPoint(iCurrentItem);
		TInt driveId=specifiedDriveName[0]-'A';
		TVolumeInfo volInfo;
		TInt retcode = iEikonEnv->FsSession().Volume(volInfo,driveId);
		ReportErrorAndLeaveIfNoInfoMsgAvailableL(retcode);	
		if (iFileSelectionObserver)
			iFileSelectionObserver->HandleFullNameChangedEventL(iRef);
		}
	}

EXPORT_C void CEikDriveNameSelector::SetFileSelectionObserver(MEikFileSelectionObserver* aObserver)
	{
	iFileSelectionObserver = aObserver;
	}

EXPORT_C void CEikDriveNameSelector::CurrentItemChangedL()
	{
	iEikonEnv->InfoMsgCancel();
	TEikDriveName driveNameSelectedByUser;
	if (iArray)
		driveNameSelectedByUser = iArray->MdcaPoint(iCurrentItem);
	TInt driveId=driveNameSelectedByUser[0]-'A';
	TVolumeInfo volInfo;
	TInt retcode = iEikonEnv->FsSession().Volume(volInfo,driveId);
	ReportErrorAndLeaveIfNoInfoMsgAvailableL(retcode);	
	if (iFileSelectionObserver)
		{ 
		TFileName* fullName = new(ELeave) TFileName;
		CleanupStack::PushL(fullName);
		TParse* parse = new(ELeave) TParse;
		CleanupStack::PushL(parse);
		User::LeaveIfError(parse->Set(iRef, NULL, NULL));
		TEikDriveName driveNameFromRef = parse->Drive().Left(1);
		if (driveNameFromRef.CompareF(driveNameSelectedByUser) != 0)
			{
			CEikFolderNameSelector* folderNameSel = (CEikFolderNameSelector*) iFileSelectionObserver;
			*fullName = folderNameSel->FullName();
			TBuf<2> newlySelectedDrive = driveNameSelectedByUser;
			newlySelectedDrive.Append(_L(":"));
			User::LeaveIfError(parse->Set(newlySelectedDrive, fullName, &iRef));
			iRef = parse->FullName();
			}
		CleanupStack::PopAndDestroy(2);	// fullName and parse
		iFileSelectionObserver->HandleFullNameChangedEventL(iRef);
		}
	}
