// EIKFBROW.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//
 
#include <basched.h>
#include <badesca.h>
#include <barsread.h>
#include <coeutils.h>
#include <eikdlgtb.h>
#include <eikenv.h>
#include <eikfbrow.h>
#include <eikhlbv.h>
#include <eikdclbx.h>
#include <eikdclbi.h>
#include <eikdtlbx.h>
#include <eikdtlbm.h>
#include <eikcapc.h>
#include <eikchlst.h>
#include <eikchlst.hrh>
#include <eikcmbut.h>
#include <eiklbbut.h>
#include <eikbtpan.h>
#include <eiksfont.h>
#include <eikfutil.h>
#include <eikpriv.hrh>
#include <eikdialg.h>
#include <eikdialg.hrh>
#include <eikcfdlg.hrh>
#include <eikfsel.h>
#include <eikon.mbg>
#include <eikon.rsg>

//
// class CEikFileBrowser::CFileUpdateReporter
//

class CEikFileBrowser::CFileUpdateReporter : public CActive
	{
public:
	~CFileUpdateReporter();
	static CFileUpdateReporter* NewL(RFs& aFsSession,CEikFileBrowser* aFileBrowser);
	void Start();
private:													
	CFileUpdateReporter(RFs& aFsSession);
private: // from CActive
	void RunL();
	void DoCancel();
private:													
	RFs& iFsSession;
	CEikFileBrowser* iFileBrowser;
	};

CEikFileBrowser::CFileUpdateReporter::CFileUpdateReporter(RFs& aFsSession)
	: CActive(CActive::EPriorityStandard), iFsSession(aFsSession)
    {}

CEikFileBrowser::CFileUpdateReporter::~CFileUpdateReporter()
    {
	Cancel();
	}

CEikFileBrowser::CFileUpdateReporter* CEikFileBrowser::CFileUpdateReporter::NewL(RFs& aFsSession,CEikFileBrowser* aFileBrowser)
	{
	CFileUpdateReporter* self=new(ELeave) CFileUpdateReporter(aFsSession);
	self->iFileBrowser=aFileBrowser;
	CActiveScheduler::Add(self);
	return(self);
	}

void CEikFileBrowser::CFileUpdateReporter::Start()
	{
	if (IsActive())
		return;
	iStatus=KRequestPending;
	SetActive();
	iFsSession.NotifyChange(ENotifyEntry,iStatus);
	}

void CEikFileBrowser::CFileUpdateReporter::RunL()
	{
	if (iStatus.Int())
		User::Leave(iStatus.Int());
	iFileBrowser->StartUpdateTimer();
	}

void CEikFileBrowser::CFileUpdateReporter::DoCancel()
	{
	iFsSession.NotifyChangeCancel();
	}

//
// class CEikFileBrowser
//

const TInt KDriveCheckInterval=2000000; // 2 seconds
const TInt KUpdateInterval=2000000; // 2 seconds
const TInt KIgnoreErrorInterval=15; // 15 seconds

EXPORT_C CEikFileBrowser::CEikFileBrowser()
	{
	iDefaultPath=_L("C:\\*");
	}

EXPORT_C CEikFileBrowser::CEikFileBrowser(const TDesC& aDefaultPath)
	{
	iDefaultPath=aDefaultPath;
	}

EXPORT_C CEikFileBrowser::~CEikFileBrowser()
	{
	delete iFileUpdateReporter;
	delete iFileListPopulate;
	delete iFileListUpdate;
	delete iDirTreeListBox;
	delete iDirContentsListBox;
	delete iDrivesList;
	delete iSortOrderButtons;
	delete iUpdateTimer;
	delete iIdle;
	delete iDriveNames;
	iFsSession.Close();
	}

TInt CEikFileBrowser::IdleL(TAny *anObj)
	{
	CEikFileBrowser* browser=((CEikFileBrowser*)anObj);
	TRAPD(err,browser->UpdateDirContentsListBoxL());
	browser->HandleErrorFromFileServerL(err);
	return EFalse;
	}

EXPORT_C void CEikFileBrowser::ConstructL(TUint aFlags,TInt aNumVisibleItems,TInt aDirTreeWidthInPixels,TInt aDirContentsWidthInPixels)
	{
	iFileSelFlags|=aFlags;
	User::LeaveIfError(iFsSession.Connect());
	if (aFlags&EOwnsWindow)
		CreateWindowL();
	Window().SetBackgroundColor(iEikonEnv->ControlColor(EEikColorWindowBackground,*this));
    EnableDragEvents();
    Window().SetPointerGrab(ETrue);
	iContext=&iBrushContext;
//	iBrushContext.iBrushStyle=CGraphicsContext::ESolidBrush;
	CreateDrivesListL();
	CreateSortOrderButtonsL();
	CreateDirTreeListBoxL(aNumVisibleItems,aDirTreeWidthInPixels);
	CreateDirContentsListBoxL(aNumVisibleItems,aDirContentsWidthInPixels);
	iFileUpdateReporter=CFileUpdateReporter::NewL(iFsSession,this);
	iFileListPopulate=CIdle::NewL(-100);
	iFileListUpdate=CIdle::NewL(-100);
	iUpdateTimer=CPeriodic::NewL(0);
	iIdle=CIdle::NewL(-100);
	SwitchFocusTo(iDirTreeListBox);
	}

EXPORT_C void CEikFileBrowser::ConstructFromResourceL(TResourceReader& aReader)
	{
	const TUint flags=aReader.ReadInt16();
	const TInt numVisibleItems=aReader.ReadInt16();
	const TInt dirTreeWidth=aReader.ReadInt16();
	ConstructL(flags,numVisibleItems,dirTreeWidth,aReader.ReadInt16());
	}

void CEikFileBrowser::StartUpdateTimer()
	{
	if (IsFocused())
		iUpdateTimer->Start(KUpdateInterval,KUpdateInterval,TCallBack(UpdateTimerCallBackL,this));
	else
		iFileSelFlags|=EUpdateOnFocus;
	}

TInt CEikFileBrowser::UpdateTimerCallBackL(TAny* aThis)
	{ // static
	CEikFileBrowser* brow=((CEikFileBrowser*)aThis);
	brow->iUpdateTimer->Cancel();
	brow->iFileUpdateReporter->Start();
	TInt err=KErrNone;
	if (brow->iDirTreeListBox->Model()->NumberOfItems()!=0)
		{
		TRAP(err,brow->UpdateL());
		}
	else
		{
		TRAP(err,brow->DoSetCurrentPathL(brow->CurrentPath(),ETrue));
		if (err==KErrNone)
			{
			brow->iDirTreeListBox->DrawNow();
			brow->iDirContentsListBox->DrawNow();
			}
		}
	brow->HandleErrorFromFileServerL(err);
	return 0;
	}

TInt CEikFileBrowser::PopulateListsCallBackL(TAny* aThis)
	{ // static
	CEikFileBrowser* brow=((CEikFileBrowser*)aThis);
	TRAPD(err,brow->PopulateListsL());
	brow->HandleErrorFromFileServerL(err);
	return 0;
	}

EXPORT_C TInt CEikFileBrowser::CountComponentControls() const
	{
	return 4;
	}

EXPORT_C CCoeControl* CEikFileBrowser::ComponentControl(TInt aIndex) const
	{
	switch (aIndex)
		{
	case 0:
		return iDrivesList;
	case 1:
		return iSortOrderButtons;
	case 2:
		return iDirTreeListBox;
	case 3:
		return iDirContentsListBox;
	default:
		return NULL;
		}
	}

void CEikFileBrowser::PopulateListsL()
	{
	delete iFileListPopulate;
	iFileListPopulate=NULL;
	iFileUpdateReporter->Start();
	TParsePtrC parse(iDefaultPath);
	TBufC<2> drive=parse.Drive();
	SetDriveSelectorState(drive.Left(1));
	iDrivesList->CopyControlContextFrom(this);
	iDrivesList->iCaption->CopyControlContextFrom(this);
	iDrivesList->iControl->DrawNow();
	TInt dtContent=(iFileSelFlags&EShowSystem? CDirectoryTreeListBoxModel::EShowSystem : 0);
	if (iFileSelFlags&EShowHidden)
		dtContent|=CDirectoryTreeListBoxModel::EShowHidden;
	iDirTreeListBox->DtlModel()->SetContent(dtContent);
	const TInt defaultDrive=parse.Drive()[0]-'A'+(TInt)EDriveA;
	TInt dcContent=(iFileSelFlags&EShowSystem? CDirContentsListBoxModel::EShowSystem : 0);
	if (iFileSelFlags&EShowHidden)
		dcContent|=CDirContentsListBoxModel::EShowHidden;
	iDirContentsListBox->DclModel()->SetContent(dcContent);
	iDirContentsListBox->DclModel()->SetSortOrder(SortOrder());
	TDriveNumber drv=(TDriveNumber)defaultDrive;
	iDirTreeListBox->CreateListL(&drv);
	iDirTreeListBox->DtlModel()->ExpandAllItemsL();
	iDirTreeListBox->View()->CalcDataWidth();
	iDirTreeListBox->View()->CalcBottomItemIndex();
	iDirTreeListBox->SetCurrentItemPathL(iDefaultPath);
	iDirTreeListBox->UpdateScrollBarsL(); // what if this leaves !!
	iDirTreeListBox->DrawNow();
	iDirContentsListBox->DclModel()->SetCurrentPathL(iDirTreeListBox->DtlModel()->FullPath(iDirTreeListBox->CurrentItemIndex()));
	iDirContentsListBox->View()->CalcBottomItemIndex();
	iDirContentsListBox->DclItemDrawer()->CalcColumnWidths();
	if (parse.NamePresent() && !parse.IsNameWild() && !parse.IsExtWild())
		iDirContentsListBox->SetCurrentItemName(parse.NameAndExt());
	iDirContentsListBox->UpdateScrollBarsL();
	iDirContentsListBox->DrawNow();
	}

EXPORT_C void CEikFileBrowser::ActivateL()
	{
	SwitchFocusTo(iDirTreeListBox);
	CEikControlGroup* group=(CEikControlGroup*)iSortOrderButtons->iControl;
	CDirContentsListBoxModel::TSortOrder sortOrder=SortOrder();
	TInt butId=EEikCidFSelOrderAToZ;
	switch (sortOrder)
		{
	default:
		break;
	case (CDirContentsListBoxModel::EOrderByType):
		butId=EEikCidFSelOrderByExt;
		break;
	case (CDirContentsListBoxModel::EOrderBySize):
		butId=EEikCidFSelOrderBySize;
		break;
	case (CDirContentsListBoxModel::EOrderByDate):
		butId=EEikCidFSelOrderByDate;
		break;
		}
	STATIC_CAST(CEikLabeledButton*,group->ControlById(butId))->Button()->SetState(CEikButtonBase::ESet);
	CreateListOfAvailableDrivesL();
	CCoeControl::ActivateL();
	// over-ride alignment of text on sort order buttons
	CEikDialogToolBar* tBar=STATIC_CAST(CEikDialogToolBar*,iSortOrderButtons->iControl);
	for (TInt ii=EEikCidFSelOrderAToZ;ii<=EEikCidFSelOrderByDate;ii++)
		{ // assume all controls are text buttons
		CEikLabeledButton* lBut=STATIC_CAST(CEikLabeledButton*,tBar->ControlById(ii));
		STATIC_CAST(CEikTextButton*,lBut->Button())->Label(CEikCommandButtonBase::EFirst)->iAlignment=EHLeftVCenter;
		}
	}

EXPORT_C TSize CEikFileBrowser::MinimumSize()
	{
	TSize driveSize=iDrivesList->MinimumSize();
	TSize sortSize=iSortOrderButtons->MinimumSize();
	TSize dirTreeSize=iDirTreeListBox->MinimumSize();
	TSize dirContentsSize=iDirContentsListBox->MinimumSize();
//	if (iFileListPopulate)
//		dirContentsSize.iWidth+=CEikScrollBar::EScrollbarWidth; //+25; // 25 pixels for bitmap & gap
	TSize minTotalSize=driveSize;
	minTotalSize.iHeight=Max(driveSize.iHeight,sortSize.iHeight);
	minTotalSize.iHeight+=Max(dirTreeSize.iHeight,dirContentsSize.iHeight);
	minTotalSize.iWidth=Max(driveSize.iWidth,dirTreeSize.iWidth);
	minTotalSize.iWidth+=Max(sortSize.iWidth,dirContentsSize.iWidth);
	minTotalSize+=TSize(12,12); // borders
	return minTotalSize;
	}

EXPORT_C void CEikFileBrowser::SizeChangedL()
	{
	LayoutControlsL(iSize,iPosition);
	}

void CEikFileBrowser::LayoutControlsL(const TSize& aSize,const TPoint& aStartPos)
	{
	const TSize driveSize=iDrivesList->MinimumSize();
	const TSize sortSize=iSortOrderButtons->MinimumSize();
	TSize dirTreeSize=iDirTreeListBox->MinimumSize();
	TSize dirContentsSize=iDirContentsListBox->MinimumSize();
	TSize minTotalSize=driveSize;
	minTotalSize.iHeight=Max(driveSize.iHeight,sortSize.iHeight);
	minTotalSize.iHeight+=Max(dirTreeSize.iHeight,dirContentsSize.iHeight);
	minTotalSize.iWidth=Max(driveSize.iWidth,dirTreeSize.iWidth);
	minTotalSize.iWidth+=Max(sortSize.iWidth,dirContentsSize.iWidth);
	minTotalSize+=TSize(12,12); // borders
	const TSize excess=aSize-minTotalSize;
	TInt extra=excess.iWidth/2;
	if (excess.iWidth>=0)
		{
		dirTreeSize.iWidth+=extra;
		if (excess.iWidth%2)
			++extra;
		dirContentsSize.iWidth+=extra;
		}
	dirTreeSize.iWidth=Max(dirTreeSize.iWidth,driveSize.iWidth);
	dirContentsSize.iWidth=Max(dirContentsSize.iWidth,sortSize.iWidth);
	extra=excess.iHeight;
	if (extra>0)
		{
		dirTreeSize.iHeight+=extra;
		dirContentsSize.iHeight+=extra;
		}
	TPoint drivePos(4,4);
	drivePos+=aStartPos;
	if (driveSize.iHeight<sortSize.iHeight)
		drivePos.iY+=(sortSize.iHeight-driveSize.iHeight)/2;
	TPoint dirTreePos(drivePos.iX,Max(4+drivePos.iY+driveSize.iHeight,4+sortSize.iHeight)+4);
	TPoint dirContentsPos(dirTreePos.iX+dirTreeSize.iWidth+4,dirTreePos.iY);
	TPoint sortPos(dirContentsPos.iX+dirContentsSize.iWidth-sortSize.iWidth,4+aStartPos.iY);
	sortPos.iX=Max(sortPos.iX+8,dirContentsPos.iX); // captioned control magic number 
	if (sortSize.iHeight<driveSize.iHeight)
		sortPos.iY+=(driveSize.iHeight-sortSize.iHeight)/2;
	iDrivesList->SetExtentL(drivePos,driveSize);
	iSortOrderButtons->SetExtentL(sortPos,sortSize);
	iDirTreeListBox->SetExtentL(dirTreePos,dirTreeSize);
	iDirContentsListBox->SetExtentL(dirContentsPos,dirContentsSize);
	}

EXPORT_C TFileName CEikFileBrowser::CurrentPath() const
	{
	if (iDirTreeListBox->DtlModel()->NumberOfItems()==0) // lists have been cleared - disk missing
		{
		CEikChoiceList* chList=STATIC_CAST(CEikChoiceList*,iDrivesList->iControl);
		TFileName drive=chList->Array()->MdcaPoint(chList->CurrentItem());
		drive.Append(_L(":\\"));
		return drive;
		}
	if (iFocusControl==iDirContentsListBox)
		return iDirContentsListBox->DclModel()->ItemFullName(iDirContentsListBox->CurrentItemIndex());
	return iDirTreeListBox->DtlModel()->FullPath(iDirTreeListBox->CurrentItemIndex());
	}

EXPORT_C void CEikFileBrowser::SetCurrentPathL(const TDesC& aPath)
	{
	TRAPD(err,DoSetCurrentPathL(aPath,EFalse));
	HandleErrorFromFileServerL(err);
	}

void CEikFileBrowser::DoSetCurrentPathL(const TDesC& aPath,TBool aExpandAll)
	{
	User::LeaveIfError(EikFileUtils::Parse(aPath));
	TParsePtrC parse(aPath);
	TBufC<2> drive=parse.Drive();
	SetDriveSelectorState(drive.Des().Left(1));
	const TInt defaultDrive=parse.Drive()[0]-'A'+(TInt)EDriveA;
	TDriveNumber drv=(TDriveNumber)defaultDrive;
	iDirTreeListBox->CreateListL(&drv);
	if (aExpandAll)
		iDirTreeListBox->DtlModel()->ExpandAllItemsL();
	iDirTreeListBox->SetCurrentItemPathL(aPath);
	iDirTreeListBox->UpdateScrollBarsL();
	iDirContentsListBox->DclModel()->SetCurrentPathL(aPath);
	iDirContentsListBox->View()->CalcBottomItemIndex();
	iDirContentsListBox->DclItemDrawer()->CalcColumnWidths();
	iDirContentsListBox->UpdateScrollBarsL();
	}

EXPORT_C CEikDirectoryTreeListBox* CEikFileBrowser::DirTreeList() const
	{
	return iDirTreeListBox;
	}

EXPORT_C CEikDirContentsListBox* CEikFileBrowser::DirContentsList() const
	{
	return iDirContentsListBox;
	}

EXPORT_C void CEikFileBrowser::SetSortOrder(CDirContentsListBoxModel::TSortOrder aOrder)
	{
	iDirContentsListBox->DclModel()->SetSortOrder(aOrder);
	}

EXPORT_C CDirContentsListBoxModel::TSortOrder CEikFileBrowser::SortOrder() const
	{
	return iDirContentsListBox->DclModel()->SortOrder();
	}

EXPORT_C void CEikFileBrowser::Draw(const TRect& aRect) const
	{
	SystemGc().Clear(aRect);
	if (iFileListPopulate && !iFileListPopulate->IsActive())
		iFileListPopulate->Start(TCallBack(CEikFileBrowser::PopulateListsCallBackL,CONST_CAST(CEikFileBrowser*,this)));
	}

void CEikFileBrowser::CreateDrivesListL()
	{
	iDrivesList=new(ELeave) CEikCaptionedControl;
	iDrivesList->SetContainerWindowL(*this);
	iDrivesList->SetObserver(this);
	iDrivesList->CopyControlContextFrom(this);
	iDrivesList->SetUsesEars();
	TBuf<8> text;
	iCoeEnv->ReadResource(text,R_EIK_TBUF_FSEL_DRIVE_PROMPT);
	iDrivesList->SetCaptionL(text);
	iDrivesList->iCaption->CopyControlContextFrom(this);
	CEikChoiceList* chList=new(ELeave) CEikChoiceList;
	iDrivesList->iControl=chList;
	chList->CopyControlContextFrom(this);
	chList->ConstructL(this,EEikChlistArrayOwnedExternally,0);
	iDrivesList->iControl->SetContainerWindowL(*this);
	iDrivesList->iControl->SetObserver(this);
	iDrivesList->iControl->CopyControlContextFrom(this);
	}

void CEikFileBrowser::CreateListOfAvailableDrivesL()
	{
	User::LeaveIfError(EikFileUtils::Parse(iDefaultPath));
	TParsePtrC parse(iDefaultPath);
	TBufC<2> drive=parse.Drive();
	TBuf<2> buf(drive);
	buf.UpperCase();
	TDriveNumber drvNum=(TDriveNumber)(buf[0]-'A');
	if (drvNum==EDriveZ)
		iFileSelFlags&=~EHideRom;
	iDriveNames=new(ELeave) CDesCArrayFlat(2);
	EikFileUtils::UpdateDiskListL(iFsSession,STATIC_CAST(CDesCArray&,*iDriveNames),~iFileSelFlags&EHideRom,drvNum);
	STATIC_CAST(CEikChoiceList*,iDrivesList->iControl)->SetArrayL(iDriveNames);
	SetDriveSelectorState(buf.Left(1));
	}

void CEikFileBrowser::SetDriveSelectorState(const TDesC& aDriveLetter)
	{
	TBuf<1> drive=aDriveLetter;
	drive.UpperCase();
	const TInt count=iDriveNames->MdcaCount();
	TInt jj=-1;
	while (jj++<count)
		{
		if (iDriveNames->MdcaPoint(jj)==drive)
			break;
		}
	((CEikChoiceList*)iDrivesList->iControl)->SetCurrentItem(jj);
	}

TBuf<1> CEikFileBrowser::CurrentDrive() const
	{
	TInt itemSelected=0;
	itemSelected=((CEikChoiceList*)iDrivesList->iControl)->CurrentItem();
	TBuf<1> drive=iDriveNames->MdcaPoint(itemSelected);
	return drive;
	}

void CEikFileBrowser::CreateDirTreeListBoxL(TInt aNumVisibleItems,TInt aWidthInPixels)
	{
	iDirTreeListBox=new(ELeave) CEikDirectoryTreeListBox;
	iDirTreeListBox->SetObserver(this);
	iDirTreeListBox->SetListBoxObserver(this);
	TInt modelFlags=(iFileSelFlags&EShowSystem? CDirectoryTreeListBoxModel::EShowSystem : 0);
	if (iFileSelFlags&EShowSystem)
		modelFlags|=CDirectoryTreeListBoxModel::EShowHidden;
	iDirTreeListBox->ConstructL(this,0,modelFlags,aNumVisibleItems,aWidthInPixels);
	iDirTreeListBox->CreateScrollBarFrameL();
	iDirTreeListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOn);
	iDirTreeListBox->UpdateScrollBarsL();
	}

void CEikFileBrowser::CreateDirContentsListBoxL(TInt aNumVisibleItems,TInt aWidthInPixels)
	{
	iDirContentsListBox=new(ELeave) CEikDirContentsListBox;
	iDirContentsListBox->SetObserver(this);
	iDirContentsListBox->SetListBoxObserver(this);
	TInt modelFlags=(iFileSelFlags&EShowSystem? CDirContentsListBoxModel::EShowSystem : 0);
	if (iFileSelFlags&EShowSystem)
		modelFlags|=CDirContentsListBoxModel::EShowHidden;
	iDirContentsListBox->ConstructL(this,0,modelFlags,aNumVisibleItems,aWidthInPixels);
	iDirContentsListBox->CreateScrollBarFrameL();
	iDirContentsListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOn);
	iDirContentsListBox->UpdateScrollBarsL();
	}

void CEikFileBrowser::CreateSortOrderButtonsL()
	{
	iSortOrderButtons=new(ELeave) CEikCaptionedControl;
	iSortOrderButtons->SetObserver(this);
	iSortOrderButtons->SetContainerWindowL(*this);
	iSortOrderButtons->CopyControlContextFrom(this);
	iSortOrderButtons->SetNonFocusing();
	TResourceReader reader;
	iCoeEnv->CreateResourceReaderLC(reader,R_EIK_FILE_SORT_ORDER_BUTTONS);
	reader.ReadInt16();
	iSortOrderButtons->SetCaptionL(reader.ReadTPtrC());
	iSortOrderButtons->iCaption->CopyControlContextFrom(this);

	CEikDialogToolBar* butGroup=new(ELeave) CEikDialogToolBar;
	iSortOrderButtons->iControl=butGroup;
	iSortOrderButtons->iControl->CopyControlContextFrom(this);
	butGroup->SetContainerWindowL(*this);
	butGroup->CopyControlContextFrom(this);
	butGroup->SetObserver(this);
	butGroup->ConstructL(CEikControlGroup::EFromTopLeft,CEikControlGroup::ELayHorizontally);
	butGroup->SetControlsAllSameSize();
	for (TInt ii=0;ii<4;ii++)
		{
		CEikTextButton* but=new(ELeave) CEikTextButton;
		CleanupStack::PushL(but);
		but->SetTextL(reader.ReadTPtrC(),CEikCommandButtonBase::EFirst);
		TBuf<1> buf;
		buf.Append(TChar(ESymFontFileBrowseOrderAToZ+ii));
		but->SetTextL(buf,CEikCommandButtonBase::ESecond);
		but->Label(CEikCommandButtonBase::ESecond)->SetFont(iEikonEnv->SymbolFont());
		but->SetBehavior(EEikButtonLatches);
		but->SetObserver(this);
		but->SetNonFocusing();
		but->SetCoordinator(&iButCoord);
		CEikLabeledButton* lbButton=new(ELeave) CEikLabeledButton;
		CleanupStack::Pop(); // but
		CleanupStack::PushL(lbButton);
		TPtrC ptr=reader.ReadTPtrC();
		lbButton->ConstructL(but,ptr[0],0/*CEikLabeledButton::EShowHotKey*/);
		TEikGroupControl ctrl(lbButton,(TInt)(EEikCidFSelOrderAToZ+ii),0,0);
		butGroup->AddControlL(ctrl);
		CleanupStack::Pop(); // lbButton
		}
	CleanupStack::PopAndDestroy();
	iSortOrderButtons->DrawNow();
	}

EXPORT_C void CEikFileBrowser::UpdateL()
	{
	TParsePtrC parse(CurrentPath());
	TBufC<2> drive=parse.Drive();
	TBuf<2> buf(drive);
	buf.UpperCase();
	TDriveNumber drvNum=(TDriveNumber)(drive[0]-'A');
	EikFileUtils::UpdateDiskListL(iFsSession,STATIC_CAST(CDesCArray&,*iDriveNames),~iFileSelFlags&EHideRom,drvNum);
	iDirTreeListBox->UpdateL();
	iDirContentsListBox->UpdateL();
	}

void CEikFileBrowser::UpdateDirContentsListBoxL()
	{
	TInt butId=EEikCidFSelOrderAToZ;
	CEikControlGroup* group=(CEikControlGroup*)iSortOrderButtons->iControl;
	while (butId<=EEikCidFSelOrderByDate)
		{
		if (STATIC_CAST(CEikLabeledButton*,group->ControlById(butId))->Button()->State()==CEikButtonBase::ESet)
			break;
		butId++;
		}
	CDirContentsListBoxModel::TSortOrder order=CDirContentsListBoxModel::EOrderByName;
	switch (butId)
		{
	case EEikCidFSelOrderAToZ:
		break;
	case EEikCidFSelOrderByExt:
		order=CDirContentsListBoxModel::EOrderByType;
		break;
	case EEikCidFSelOrderBySize:
		order=CDirContentsListBoxModel::EOrderBySize;
		break;
	case EEikCidFSelOrderByDate:
		order=CDirContentsListBoxModel::EOrderByDate;
		break;
		}
	iDirContentsListBox->DclModel()->SetSortOrder(order);
	TFileName path=iDirTreeListBox->DtlModel()->FullPath(iDirTreeListBox->CurrentItemIndex());
	if (!path.Length())
		return; // lists are empty - disk has been removed
	iDirContentsListBox->SetPathL(path);
	}

EXPORT_C void CEikFileBrowser::HandleErrorFromFileServerL(TInt aErrorCode)
	{
	if (aErrorCode==KErrNone)
		return;
	if (aErrorCode==KErrNotReady || aErrorCode==KErrCorrupt || aErrorCode==KErrNotSupported)
		{
		if (aErrorCode==KErrCorrupt)
			iEikonEnv->InfoMsg(R_EIK_TBUF_CANNOT_BE_READ);
		else if (aErrorCode==KErrNotReady)
			iEikonEnv->InfoMsg(R_EIK_TBUF_DISK_NOT_PRESENT);
		else if (aErrorCode==KErrNotSupported)
			iEikonEnv->InfoMsg(R_EIK_TBUF_NOT_SUPPORTED);
		ClearListsL();
		}
	else
		{
		if (aErrorCode==KErrNoMemory) // update code won't cope - just delete dialog for v1 !!!
			{
//			if (!IsReadyToDraw())
//				{ // send a dummy escape key to dialog - copout
				TKeyEvent event;
				TEventCode type=EEventKey;
				event.iCode=EKeyEscape;
				event.iScanCode=event.iModifiers=event.iRepeats=0;
				iEikonEnv->SimulateKeyEventL(event,type);
				User::LeaveNoMemory();
//				}
//			else
//				ClearListsL(); // shouldn't leave
			}
		TTime time;
		time.HomeTime();
		TTimeIntervalSeconds gap;
		TInt err=time.SecondsFrom(iLastUnhandledErrorTime,gap);
		if (err==KErrNone && gap<TTimeIntervalSeconds(KIgnoreErrorInterval))
			CBaActiveScheduler::LeaveNoAlert(); // less than 15 seconds since previous notification
		iLastUnhandledErrorTime=time;
		User::LeaveIfError(aErrorCode);
		}
	}

void CEikFileBrowser::ClearListsL()
	{
	iDirTreeListBox->DtlModel()->Reset();
	iDirTreeListBox->ClearSelection();
	iDirContentsListBox->DclModel()->Reset();
	iDirContentsListBox->ClearSelection();
	iDirTreeListBox->UpdateScrollBarsL();
	iDirTreeListBox->DrawNow();
	iDirContentsListBox->UpdateScrollBarsL();
	iDirContentsListBox->DrawNow();
	SwitchFocusTo(iDrivesList);
	}

EXPORT_C void CEikFileBrowser::FocusChanged(TDrawNow aDrawNow)
	{
	const TBool focused=IsFocused();
	iFocusControl->SetFocus(focused,aDrawNow);
	if (focused)
		{
		if (iFileSelFlags&EUpdateOnFocus)
			{
			iFileListUpdate->Start(TCallBack(CEikFileBrowser::UpdateTimerCallBackL,this));
			iFileSelFlags&=~EUpdateOnFocus;
			}
		}
	else if (iUpdateTimer->IsActive()) // && !focused
		{
		iUpdateTimer->Cancel();
		iFileSelFlags|=EUpdateOnFocus;
		}
	}

void CEikFileBrowser::SwitchFocusTo(CCoeControl* aControl)
	{
	if (aControl!=iFocusControl)
		{
		if (iFocusControl)
			{
			if (iFocusControl==iDirTreeListBox || iFocusControl==iDirContentsListBox)
				{
				iFocusControl->SetFocus(EFalse);
				TInt index=((CEikListBox*)iFocusControl)->CurrentItemIndex();
				if (index!=-1)
					{
					if (iFocusControl==iDirTreeListBox)
						((CEikDirectoryTreeListBox*)iFocusControl)->HlView()->DrawItemWithoutLinks(index);
					else
						((CEikListBox*)iFocusControl)->DrawItem(index);
					}
				}
			else
				iFocusControl->SetFocus(EFalse,EDrawNow);
			}
		if (aControl==iDirTreeListBox || aControl==iDirContentsListBox)
			{
			aControl->SetFocus(ETrue);
			TInt index=((CEikListBox*)aControl)->CurrentItemIndex();
			if (index!=-1)
				{
				if (aControl==iDirTreeListBox)
					((CEikDirectoryTreeListBox*)aControl)->HlView()->DrawItemWithoutLinks(index);
				else
					((CEikListBox*)aControl)->DrawItem(index);
				}
			}
		else
			aControl->SetFocus(ETrue,EDrawNow);
		iFocusControl=aControl;
		}
	}

EXPORT_C void CEikFileBrowser::HandleControlEventL(CCoeControl* aControl,TCoeEvent aEventType)
	{
	if (aEventType==MCoeControlObserver::EEventRequestFocus)
		SwitchFocusTo(aControl);
	else if (aEventType==MCoeControlObserver::EEventStateChanged)
		{
		if (aControl==iDirTreeListBox)
			HandleChangeInDirTreeSelection();
		else if (aControl==iDrivesList->iControl)
			HandleDriveChangedL();
		else if (aControl==iSortOrderButtons->iControl)
			HandleSortOrderChangedL();
		}
	}

EXPORT_C void CEikFileBrowser::HandleListBoxEventL(CEikListBox* aListBox,TListBoxEvent aEventType)
	{
	if (aEventType==MEikListBoxObserver::EEventItemActioned)
		{
		if (aListBox==iDirTreeListBox)
			HandleChangeInDirTreeSelection();
		else if (aListBox==iDirContentsListBox)
			HandleChangeInDirContentsCurrentPathL();
		}
	}

void CEikFileBrowser::HandleChangeInDirTreeSelection()
	{
	if (iIdle && !iIdle->IsActive())
		iIdle->Start(TCallBack(CEikFileBrowser::IdleL,this));
	}

void CEikFileBrowser::HandleChangeInDirContentsCurrentPathL()
	{
	TParsePtrC parse(*(iDirContentsListBox->DclModel()->CurrentPath()));
	TBufC<KMaxFileName> path=parse.DriveAndPath();
	iDirTreeListBox->SetCurrentItemPathL(path.Des());
	iDirTreeListBox->UpdateScrollBarsL();
	iDirTreeListBox->DrawNow();
	}

void CEikFileBrowser::HandleDriveChangedL()
	{
	iEikonEnv->InfoMsgCancel();
	TBuf<1> drive=CurrentDrive();
	TDriveNumber drv=(TDriveNumber)(drive[0]-'A'+(TInt)EDriveA);
	TRAPD(err,
			iDirTreeListBox->CreateListL(&drv);
			iDirTreeListBox->DtlModel()->ExpandAllItemsL();)
	if (err)
		{
		HandleErrorFromFileServerL(err);
		return;
		}
	iDirTreeListBox->View()->CalcDataWidth();
	iDirTreeListBox->View()->CalcBottomItemIndex();
	iDirTreeListBox->UpdateScrollBarsL();
	iDirTreeListBox->DrawNow();
	TRAP(err,UpdateDirContentsListBoxL());
	HandleErrorFromFileServerL(err);
	}

void CEikFileBrowser::HandleSortOrderChangedL()
	{
	TRAPD(err,UpdateDirContentsListBoxL());
	HandleErrorFromFileServerL(err);
	}

EXPORT_C TKeyResponse CEikFileBrowser::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
	{
	if (aType!=EEventKey)
		return EKeyWasNotConsumed;
	const TUint code=aKeyEvent.iCode;
	if (aKeyEvent.iModifiers&EModifierCtrl &&
		iSortOrderButtons->iControl->OfferKeyEventL(aKeyEvent,aType)==EKeyWasConsumed)
		return EKeyWasConsumed;
	if (code==EKeyRightArrow && iFocusControl==iDirTreeListBox && iDirTreeListBox->Model()->NumberOfItems()!=0)
		SwitchFocusTo(iDirContentsListBox);
	else if (code==EKeyLeftArrow && iFocusControl==iDirContentsListBox)
		SwitchFocusTo(iDirTreeListBox);
	else if ((code==EKeyUpArrow || code==EKeyPageUp) && iFocusControl==iDirTreeListBox)
		{
		const TInt count=iDirTreeListBox->CurrentItemIndex();
		if (count==0 || count==-1)
			SwitchFocusTo(iDrivesList);
		else
			iFocusControl->OfferKeyEventL(aKeyEvent,aType);
		}
	else if (code==EKeyDownArrow && iFocusControl==iDrivesList)
		SwitchFocusTo(iDirTreeListBox);
	else
		iFocusControl->OfferKeyEventL(aKeyEvent,aType);
	return EKeyWasConsumed;
	}

EXPORT_C void CEikFileBrowser::Reserved_1()
	{}
EXPORT_C void CEikFileBrowser::Reserved_2()
	{}

//
// class CEikFileBrowserDialog
//

EXPORT_C CEikFileBrowserDialog::CEikFileBrowserDialog(TDes& aPath,TUint aFlags,CDirContentsListBoxModel::TSortOrder& aOrder)
	: iPath(aPath), iBrowseFlags(aFlags), iSortOrder(aOrder)
	{}

void CEikFileBrowserDialog::PreLayoutDynInitL()
	{
	CEikFileBrowser* browser=STATIC_CAST(CEikFileBrowser*,Control(EEikCidFileBrowse));
	browser->iDefaultPath=iPath;
	browser->iFileSelFlags|=iBrowseFlags;
	browser->SetSortOrder(iSortOrder);
	browser->CopyControlContextFrom(this);
	if (~iBrowseFlags&CEikFileBrowserDialog::EAllowFolderCreation)
		ButtonPanel()->LabeledButtonById(EEikCidFselCreateFolder)->MakeVisible(EFalse);
	ButtonPanel()->LabeledButtonById(EEikCidFselDummy)->MakeVisible(EFalse);
	}

TBool CEikFileBrowserDialog::OkToExitL(TInt aButtonId)
	{
	CEikFileBrowser* browser=STATIC_CAST(CEikFileBrowser*,Control(EEikCidFileBrowse));
	if (aButtonId==EEikCidFselCreateFolder)
		{
		if (!browser->iFileListPopulate)
			LaunchCreateFolderDialogL();
		return EFalse;
		}
	if (aButtonId==EEikBidOk)
		{
		if (browser->iFileListPopulate)
			iPath=browser->iDefaultPath;
		else
			iPath=browser->CurrentPath();
		}
	iSortOrder=browser->SortOrder();
	return ETrue;
	}

void CEikFileBrowserDialog::LaunchCreateFolderDialogL()
	{
	CEikFileBrowser* browser=STATIC_CAST(CEikFileBrowser*,Control(EEikCidFileBrowse));
	if (browser->iDirTreeListBox->DtlModel()->NumberOfItems()==0) // lists are empty - disk has been removed (or somethings gone horribly wrong)
		iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_CANNOT_CREATE_FOLDER);
	TFileName* path=new(ELeave) TFileName;
	CleanupStack::PushL(path);
	*path=browser->CurrentPath();
	TParsePtrC parse(*path);
	*path=parse.DriveAndPath();
	TBuf<2> drive=_L("");
	if (parse.DrivePresent())
		drive=parse.Drive();
	CEikDialog* dlg=new(ELeave) CEikNewFolderDialog(*path);
	if (dlg->ExecuteLD(R_EIK_DIALOG_FSEL_CREATE_FOLDER))
		{
		CEikFileBrowser* browser=STATIC_CAST(CEikFileBrowser*,Control(EEikCidFileBrowse));
		TRAPD(err,UpdateForNewFolderL(*path));
		browser->HandleErrorFromFileServerL(err);
		}
	CleanupStack::PopAndDestroy();
	}

void CEikFileBrowserDialog::UpdateForNewFolderL(TDes& aNewFolderPath)
	{
	CEikFileBrowser* browser=STATIC_CAST(CEikFileBrowser*,Control(EEikCidFileBrowse));
	TBuf<1> drive=browser->CurrentDrive();
	TParsePtrC parse(aNewFolderPath);
	aNewFolderPath=parse.DriveAndPath();
	TBuf<1> newDrive=(parse.Drive()).Left(1);
	if (newDrive!=drive)
		{
		browser->SetDriveSelectorState(newDrive);
		TDriveNumber drv=(TDriveNumber)(newDrive[0]-'A');
		browser->iDirTreeListBox->DtlModel()->CreateListForSpecifiedDriveL(&drv);
		}
	browser->iDirTreeListBox->SetCurrentItemPathL(aNewFolderPath);
	browser->iDrivesList->iControl->DrawNow();
	browser->iDirTreeListBox->UpdateScrollBarsL();
	browser->iDirTreeListBox->DrawNow();
	browser->UpdateDirContentsListBoxL();
	}

//
// class CEikNewFolderDialog
//

const TInt KMaxDirEntryNameLengthInDialogTitleBar = 20;
const TInt KMaxDialogTitleLength = 60;
const TInt KShortErrorMessageLength = 64;
const TInt KDriveNameLength = 1;

EXPORT_C CEikNewFolderDialog::CEikNewFolderDialog(TFileName& aPath)
	: iPath(aPath)
	{ }

void CEikNewFolderDialog::PreLayoutDynInitL()
	{
	CEikFolderNameEditor* folderNameEditor=(CEikFolderNameEditor*)Control(EEikCidFolderNameEd);
	
	TParse* parse=new(ELeave) TParse;
	CleanupStack::PushL(parse);

	User::LeaveIfError(parse->Set(iPath, NULL, NULL));
	folderNameEditor->SetFullNameL(parse->FullName());
	TPtrC emptyDes;
	folderNameEditor->SetTextL(&emptyDes);
//	folderNameEditor->SetTextLimit(KMaxFileName - parse->DriveAndPath().Length() - 1);
	
	// set dialog title
	TBuf<KMaxDialogTitleLength>* title = new(ELeave) TBuf<KMaxDialogTitleLength>;
	CleanupStack::PushL(title);

	TBuf<KMaxDialogTitleLength>* titleFormatStr = new(ELeave) TBuf<KMaxDialogTitleLength>;
	CleanupStack::PushL(titleFormatStr);

	TFileName* parentFolderName = new(ELeave) TFileName;
	CleanupStack::PushL(parentFolderName);

	*parentFolderName = EikFileUtils::FolderNameFromFullName(iPath);
	if (parentFolderName->Compare(_L("\\")) != 0)
		{
		TBuf<KMaxDirEntryNameLengthInDialogTitleBar> abbrevName;
		EikFileUtils::AbbreviateFileName(*parentFolderName, abbrevName);
		iEikonEnv->ReadResource(*titleFormatStr, R_EIK_TBUF_CREATE_FOLDER_DLG_TITLE);
		title->Format(*titleFormatStr, &abbrevName);
		SetTitleL(*title);
		}
	CleanupStack::PopAndDestroy(4);	// "parse", "title", "titleFormatStr", and "parentFolderName"
	}

TBool CEikNewFolderDialog::OkToExitL(TInt /*aButtonId*/)
	{
    CEikFolderNameEditor* folderEditor=(CEikFolderNameEditor*)Control(EEikCidFolderNameEd);
    folderEditor->ValidateStateL();
	TFileName* folderName=new(ELeave) TFileName;
	CleanupStack::PushL(folderName);
	*folderName=folderEditor->FullName();

	TInt retcode = iEikonEnv->FsSession().MkDirAll(*folderName);
	if (retcode != KErrNone)
		{
		if (retcode == KErrAlreadyExists)
			iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_EXISTING_FOLDER_SPECIFIED);
		if (retcode == KErrNotReady)
			iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_DISK_NOT_PRESENT);
		else if (retcode == KErrAccessDenied)
			{
			TBool readOnlyDisk = EFalse;
			User::LeaveIfError(EikFileUtils::DiskIsReadOnly(*folderName, readOnlyDisk));
			if (!readOnlyDisk)
				iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_EXISTING_FILE_SPECIFIED);
			else
				{
				TParsePtr parse(*folderName);
				TBuf<1> drive = parse.Drive().Left(1);
				TBuf<KShortErrorMessageLength + KDriveNameLength> textMsg;
				TBuf<KShortErrorMessageLength> formatStr;
				iEikonEnv->ReadResource(formatStr, R_EIK_TBUF_DISK_READONLY_ERR);
				textMsg.Format(formatStr, &drive);
				iEikonEnv->InfoMsg(textMsg);
				CBaActiveScheduler::LeaveNoAlert();
				}
			}
		User::Leave(retcode);
		}
	iPath=*folderName;
	CleanupStack::PopAndDestroy();	// folderName
	return ETrue;
	}
