// EIKDCLBX.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <barsread.h>
#include <badesca.h>
#include <eikenv.h>
#include <eikdclbx.h>
#include <eikdclbm.h>
#include <eikdclbi.h>
#include <eiklabel.h>
#include <eikpriv.hrh>
#include <eiklbx.pan>
#include <eikon.rsg>
#include <eikon.mbg>

#define ITEM_EXISTS(x) (x>-1 && x<DclModel()->NumberOfItems())

//
// class CEikDirContentsListBox
//

EXPORT_C CEikDirContentsListBox::CEikDirContentsListBox()
	{}

EXPORT_C TKeyResponse CEikDirContentsListBox::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
	{
	if (aKeyEvent.iCode==EKeyTab && !(aKeyEvent.iModifiers&(EModifierShift|EModifierCtrl|EModifierFunc)))
		{
		const TInt index=CurrentItemIndex();
		if (index!=-1)
			HandleItemSelectionL(index);
		}
	else
		CEikListBox::OfferKeyEventL(aKeyEvent,aType);
	return EKeyWasConsumed;
	}

EXPORT_C void CEikDirContentsListBox::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
	TInt index;
	const TBool overItem=iView->XYPosToItemIndex(aPointerEvent.iPosition,index);
	if (! overItem)
		{
		CEikListBox::HandlePointerEventL(aPointerEvent);
		return;
		}
	if (aPointerEvent.iType==TPointerEvent::EButton1Down)
		iPressedIndex=(index==CurrentItemIndex() ? index : -1);
	TPointerEvent event=aPointerEvent;
	event.iModifiers&=(~EModifierDoubleClick);
	CEikListBox::HandlePointerEventL(event);
	if (aPointerEvent.iType==TPointerEvent::EButton1Up)
		{
		if (aPointerEvent.iModifiers&EModifierShift || aPointerEvent.iModifiers&EModifierCtrl)
			return;
		if ((iPressedIndex==index && overItem) &&
			(DclModel()->ItemIsParent(index) || DclModel()->ItemIsSubDir(index)))
			HandleItemSelectionL(index);
		}
	}

void CEikDirContentsListBox::HandleItemSelectionL(TInt aItemIndex)
	{
	if (DclModel()->ItemIsParent(aItemIndex))
		DclModel()->ChangeToParentDirL();
	else if (DclModel()->ItemIsSubDir(aItemIndex))
		DclModel()->ChangeToSubDirL(aItemIndex);
	else if (ITEM_EXISTS(aItemIndex))
		return;
	HandleListUpdateL();
	ReportListBoxEventL(MEikListBoxObserver::EEventItemActioned);
	}

EXPORT_C void CEikDirContentsListBox::ConstructL(const CCoeControl* aParent,TInt aListBoxFlags,TUint aModelFlags,TInt aNumVisibleLines,TInt aWidthInPixels)
	{
	aListBoxFlags&=~EIncrementalMatching; // don't want incremental matching
	iListBoxFlags=aListBoxFlags;
	BaseConstructL(aModelFlags);
	CEikListBox::ConstructL(aParent,aListBoxFlags);
	iRequiredHeightInNumOfItems=aNumVisibleLines;
	iSize.iWidth=aWidthInPixels;
	}

EXPORT_C void CEikDirContentsListBox::ConstructFromResourceL(TResourceReader& aReader)
	{
	iListBoxFlags=aReader.ReadInt16();
	iListBoxFlags&=~EIncrementalMatching; // don't want incremental matching
	const TUint modelFlags=aReader.ReadUint16();
	iRequiredHeightInNumOfItems=aReader.ReadInt16();
	BaseConstructL(modelFlags);
	CreateViewL();
	TPtrC path=aReader.ReadTPtrC();
	if (path.Length())
		SetPathL(path);
	}

void CEikDirContentsListBox::BaseConstructL(TInt aModelFlags)
	{
	iModel=CDirContentsListBoxModel::NewL(iEikonEnv->FsSession(),aModelFlags);
	iItemDrawer=new(ELeave) CDirContentsListItemDrawer(((CDirContentsListBoxModel*)iModel));
	TPtrC system;
	CFbsBitmap* bmp=iEikonEnv->CreateBitmapL(system,EMbmEikonFselprnt);
	CArrayPtrFlat<CFbsBitmap>* bitmaps=new(ELeave) CArrayPtrFlat<CFbsBitmap>(2);
	CleanupStack::PushL(bitmaps);
	bitmaps->AppendL(bmp);
	bmp=iEikonEnv->CreateBitmapL(system,EMbmEikonFileclsd);
	bitmaps->AppendL(bmp);
	bmp=iEikonEnv->CreateBitmapL(system,EMbmEikonFselfile);
	bitmaps->AppendL(bmp);
	STATIC_CAST(CDirContentsListItemDrawer*,iItemDrawer)->ConstructL(bitmaps,iEikonEnv->NormalFont(),
																		iEikonEnv->AnnotationFont());
	CleanupStack::Pop(); // bitmaps
	}

EXPORT_C void CEikDirContentsListBox::HandleListUpdateL()
	{
	TInt newIndex=0;
	if (DclModel()->ItemIsParent(0) && DclModel()->NumberOfItems()>1)
		newIndex=1;
	if (DclModel()->NumberOfItems()>0)
		{
		iView->SetDisableRedraw(ETrue);
		SetTopItemIndex(0);
		ClearSelection();
		SetCurrentItemIndex(newIndex);
		if (iListBoxFlags & EMultipleSelection)
			iView->UpdateSelectionL(CListBoxView::ESingleSelection);
		iView->SetDisableRedraw(EFalse);
		}
	iPressedIndex=-1;
	iView->CalcBottomItemIndex();
	UpdateScrollBarsL();
	DrawNow();
	}

EXPORT_C void CEikDirContentsListBox::SetPathL(const TDesC& aPath)
	{
	DclModel()->SetCurrentPathL(aPath);
	DclItemDrawer()->CalcColumnWidths();
	HandleListUpdateL();
	}

EXPORT_C TSize CEikDirContentsListBox::MinimumSize()
    {
	TSize size;
	size.iWidth=iSize.iWidth;
	size.iHeight=(2*VerticalMargin())+(iRequiredHeightInNumOfItems*iItemDrawer->MinimumCellSize().iHeight);
	if (!(iListBoxFlags&EScrollBarSizeExcluded) && iSBFrame)
		{
		if (iSBFrame->VScrollBarVisibility()!=CEikScrollBarFrame::EOff)
			size.iWidth+=CEikScrollBar::EScrollbarWidth;
		if (iSBFrame->HScrollBarVisibility()!=CEikScrollBarFrame::EOff)
			size.iHeight+=CEikScrollBar::EScrollbarWidth;
		}
	size+=iBorder.SizeDelta();
	return size;
    }

EXPORT_C void CEikDirContentsListBox::UpdateL()
	{
	// first test that current path still exists
	RDir dir;
	const TDesC* path=DclModel()->CurrentPath();
	if (path==NULL)
		return;
	const TInt ret=dir.Open(iEikonEnv->FsSession(),*path,EFileRead|EFileShareAny);
	if (!ret)
		dir.Close();
	if (ret==KErrPathNotFound)
		{
		DclModel()->ChangeToParentDirL();
		HandleListUpdateL();
		return;
		}
	else if (ret==KErrNotReady)
		{
		DclModel()->Reset();
		UpdateScrollBarsL();
		DrawNow();
		User::LeaveIfError(KErrNotReady); // inform user disk is absent
		}
	else if (ret)
		User::LeaveIfError(ret);
	// current path still exists
	const TInt current=CurrentItemIndex();
	TFileName name;
	if (ITEM_EXISTS(current))
		name=DclModel()->ItemName(current);
	CDesCArray* selections=NULL;
	if (iListBoxFlags&EMultipleSelection)
		{
		const CListBoxView::CSelectionIndexArray* selectionIndices=View()->SelectionIndexes();
		selections=new(ELeave) CDesCArrayFlat(4);
		CleanupStack::PushL(selections);
		const TInt count=selectionIndices->Count();
		for (TInt ii=0;ii<count;ii++)
			{
			TDesC& itemName=DclModel()->ItemName((*selectionIndices)[ii]);
			selections->AppendL(itemName);
			}
		}
	DclModel()->UpdateL();
	View()->CalcBottomItemIndex();
	View()->SetDisableRedraw(ETrue);
	const TInt count=DclModel()->NumberOfItems();
	if (name.Length() && (!ITEM_EXISTS(current) || DclModel()->ItemName(current)!=name))
		{
		TBool found=EFalse;
		for (TInt ii=0;ii<count;ii++)
			{
			if (DclModel()->ItemName(ii)==name)
				{
				SetCurrentItemIndex(ii);
				found=ETrue;
				break;
				}
			}
		if (!found)
			SetCurrentItemIndex(0);
		}
	else if (ITEM_EXISTS(current) && DclModel()->ItemName(current)==name)
		SetCurrentItemIndex(current);
	else
		SetCurrentItemIndex(0);
	const TInt newCurrent=CurrentItemIndex();
	const TInt bottom=BottomItemIndex();
	const TInt top=TopItemIndex();
	if (newCurrent>bottom)
		SetTopItemIndex(newCurrent+top-bottom);
	else if (newCurrent<top)
		{
		if (newCurrent<=bottom)
			SetTopItemIndex(0);
		else
			SetTopItemIndex(newCurrent);
		}
	if (iListBoxFlags&EMultipleSelection)
		{
		const TInt num=selections->Count();
		View()->ClearSelection();
		for (TInt ii=0;ii<count;ii++)
			{
			TPtrC itemName=DclModel()->ItemName(ii);
			for (TInt jj=0;jj<num;jj++)
				{
				if ((*selections)[jj]==itemName)
					{
					TRAPD(err,View()->SelectItemL(ii));
					if (err)
						{
						View()->SetDisableRedraw(EFalse);
						User::LeaveIfError(err);
						}
					break;
					}
				}
			}
		CleanupStack::PopAndDestroy();
		}
	View()->SetDisableRedraw(EFalse);
	UpdateScrollBarsL();
	DrawNow();
	}

EXPORT_C void CEikDirContentsListBox::SetCurrentItemName(const TDesC& aName)
	{
	TFileName name=aName;
	name.LowerCase();
	const TInt count=DclModel()->NumberOfItems();
	TInt index=0;
	for (TInt ii=0;ii<count;ii++)
		{
		TFileName item=DclModel()->ItemName(ii);
		item.LowerCase();
		if (item==name)
			{
			index=ii;
			break;
			}
		}
	SetCurrentItemIndex(index);
	// ScrollToMakeItemVisible(index);
	}
	
EXPORT_C void CEikDirContentsListBox::GetFullNamesOfSelectedItemsL(CDesCArray* aItems) const
	{
	aItems->Reset();
	const CArrayFix<TInt>* selectionIndexes=iView->SelectionIndexes();
	const TInt count=selectionIndexes->Count();
	for (TInt ii=0;ii<count;ii++)
		aItems->AppendL(DclModel()->ItemFullName((*selectionIndexes)[ii]));
	}

EXPORT_C CDirContentsListBoxModel* CEikDirContentsListBox::DclModel() const
	{
	return STATIC_CAST(CDirContentsListBoxModel*,Model());
	}

EXPORT_C CDirContentsListItemDrawer* CEikDirContentsListBox::DclItemDrawer() const
	{
	return STATIC_CAST(CDirContentsListItemDrawer*,iItemDrawer);
	}

EXPORT_C void CEikDirContentsListBox::Reserved_3()
	{}
