www.pudn.com > 完整的FTP客户端ftpwanderersrc.zip > FTPListView.cpp


/****************************************************************/ 
/*																*/ 
/*  FtpListView.cpp												*/ 
/*																*/ 
/*  Implementation of the CFtpListView class.					*/ 
/*																*/ 
/*  Programmed by Pablo van der Meer							*/ 
/*  Copyright Pablo Software Solutions 2002						*/ 
/*	http://www.pablovandermeer.nl								*/ 
/*																*/ 
/*  Last updated: 24 june 2002									*/ 
/*																*/ 
/****************************************************************/ 
 
 
#include "stdafx.h" 
#include "FtpWanderer.h" 
#include "MainFrm.h" 
#include "FtpWandererDoc.h" 
#include "FtpListView.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
BOOL g_bSortAscending; 
 
IMPLEMENT_DYNCREATE(CFtpListView, CListView) 
 
BEGIN_MESSAGE_MAP(CFtpListView, CListView) 
	//{{AFX_MSG_MAP(CFtpListView) 
	ON_WM_CREATE() 
	ON_NOTIFY_REFLECT_EX(LVN_ENDLABELEDIT, OnEndlabeledit) 
	ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo) 
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick) 
	ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnDeleteitem) 
	ON_NOTIFY_REFLECT(LVN_BEGINLABELEDIT, OnBeginlabeledit) 
	ON_WM_SIZE() 
	ON_WM_CTLCOLOR() 
	ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick) 
	ON_WM_DROPFILES() 
	ON_NOTIFY_REFLECT(LVN_ODCACHEHINT, OnOdcachehint) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CFtpListView construction/destruction 
 
CFtpListView::CFtpListView() 
{ 
	m_nSortedCol = 0;  
    g_bSortAscending = TRUE;  
	m_bEditMode = FALSE; 
	m_bSearching = FALSE; 
} 
 
CFtpListView::~CFtpListView() 
{ 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnDraw											*/ 
/* Description   : Called by the framework to render an image of	*/ 
/*				   the document										*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::OnDraw(CDC* pDC) 
{ 
	CFtpWandererDoc* pDoc = GetDocument(); 
	ASSERT_VALID(pDoc); 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnInitialUpdate									*/ 
/* Description   : Called by the framework after the view is first	*/ 
/*				   attached to the document, but before the view is */ 
/*				   initially displayed.								*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::OnInitialUpdate() 
{ 
	CListView::OnInitialUpdate(); 
 
	// TODO: You may populate your ListView with items by directly accessing 
	//  its list control through a call to GetListCtrl(). 
	DragAcceptFiles(); 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : GetDocument										*/ 
/* Description   : Get a pointer to the view抯 document.			*/ 
/*																	*/ 
/********************************************************************/ 
#ifdef _DEBUG 
CFtpWandererDoc* CFtpListView::GetDocument() // non-debug version is inline 
{ 
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFtpWandererDoc))); 
	return (CFtpWandererDoc*)m_pDocument; 
} 
#endif //_DEBUG 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnStyleChanged									*/ 
/* Description   : View style has been changed.						*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct) 
{ 
	//TODO: add code to react to the user changing the view style of your window 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnCreate											*/ 
/* Description   : Called when window needs to be created.			*/ 
/*																	*/ 
/********************************************************************/ 
int CFtpListView::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CListView::OnCreate(lpCreateStruct) == -1) 
		return -1; 
	 
    GetListCtrl().ModifyStyle(0, LVS_EDITLABELS); 
 
    // column initialization 
    GetListCtrl().InsertColumn(0, "Name", LVCFMT_LEFT, 180); 
    GetListCtrl().InsertColumn(1, "Size", LVCFMT_RIGHT, 100); 
    GetListCtrl().InsertColumn(2, "Type", LVCFMT_LEFT, 100); 
	GetListCtrl().InsertColumn(3, "Created", LVCFMT_LEFT, 100); 
//	GetListCtrl().InsertColumn(4, "Attributes", LVCFMT_LEFT, 100); 
 
	// do not take ownership of the imagelist! 
	GetListCtrl().ModifyStyle(0, LVS_SHAREIMAGELISTS); 
	InitListViewImageLists(); 
	return 0; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnBeginlabeledit									*/ 
/* Description   : 													*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; 
	m_bEditMode = TRUE; 
	*pResult = 0; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnEndlabeledit									*/ 
/* Description   : 													*/ 
/*																	*/ 
/********************************************************************/ 
BOOL CFtpListView::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	m_bEditMode = FALSE; 
	// route notification to CMainFrame ! 
	return FALSE; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : AddItem											*/ 
/* Description   : 													*/ 
/*																	*/ 
/********************************************************************/ 
int CFtpListView::AddItem(int nIndex, CFtpFileFind *pFileFind) 
{ 
	// Allocate a new ITEMINFO structure and initialize it with information about the item. 
    ITEMINFO* pItem; 
    try  
	{ 
        pItem = new ITEMINFO; 
    } 
    catch(CMemoryException* e)  
	{ 
        e->Delete(); 
        return -1; 
    } 
 
    pItem->strFileName = pFileFind->GetFileName(); 
    pItem->nFileSize = pFileFind->GetLength(); 
    pFileFind->GetLastWriteTime(&pItem->ftLastWriteTime); 
	pItem->bIsDirectory = pFileFind->IsDirectory(); 
	pItem->strType = pItem->bIsDirectory ? "Folder" : GetTypeName(pItem->strFileName); 
	int nImage = GetIconIndex(pItem->strFileName, pItem->bIsDirectory); 
	 
	// Add the item to the list view. 
    LV_ITEM lvi; 
    lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;  
    lvi.iItem = nIndex;  
    lvi.iSubItem = 0;  
    lvi.iImage = nImage; 
    lvi.pszText = LPSTR_TEXTCALLBACK;  
    lvi.lParam = (LPARAM) pItem; 
 
    return GetListCtrl().InsertItem(&lvi); 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : AddNewFolder										*/ 
/* Description   : Add new folder entry								*/ 
/*																	*/ 
/********************************************************************/ 
int CFtpListView::AddNewFolder(int nIndex, LPCTSTR lpszFolder) 
{ 
	// Allocate a new ITEMINFO structure and initialize it with information about the item. 
    ITEMINFO* pItem; 
    try  
	{ 
        pItem = new ITEMINFO; 
    } 
    catch(CMemoryException* e)  
	{ 
        e->Delete(); 
        return -1; 
    } 
 
    pItem->strFileName = lpszFolder; 
    pItem->nFileSize = 0; 
	 
	SYSTEMTIME systemTime; 
	GetSystemTime(&systemTime); 
	::SystemTimeToFileTime(&systemTime, &pItem->ftLastWriteTime); 
 
	pItem->bIsDirectory = TRUE; 
	pItem->strType = "Folder"; 
	int nImage = GetIconIndex(pItem->strFileName, pItem->bIsDirectory); 
	 
	// Add the item to the list view. 
    LV_ITEM lvi; 
    lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;  
    lvi.iItem = nIndex;  
    lvi.iSubItem = 0;  
    lvi.iImage = nImage; 
    lvi.pszText = LPSTR_TEXTCALLBACK;  
    lvi.lParam = (LPARAM) pItem; 
 
    return GetListCtrl().InsertItem(&lvi); 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : AddNewFile										*/ 
/* Description   : Add new file entry								*/ 
/*																	*/ 
/********************************************************************/ 
int CFtpListView::AddNewFile(int nIndex, LPCTSTR lpszFileName, DWORD dwFileSize) 
{ 
    int nCount = GetListCtrl().GetItemCount(); 
    for(int i=0; iDelete(); 
        return -1; 
    } 
 
    pItem->strFileName = lpszFileName; 
    pItem->nFileSize = dwFileSize; 
	 
	SYSTEMTIME systemTime; 
	GetSystemTime(&systemTime); 
	::SystemTimeToFileTime(&systemTime, &pItem->ftLastWriteTime); 
 
	pItem->bIsDirectory = FALSE; 
	pItem->strType = GetTypeName(pItem->strFileName);; 
	int nImage = GetIconIndex(pItem->strFileName, pItem->bIsDirectory); 
	 
	// Add the item to the list view. 
    LV_ITEM lvi; 
    lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;  
    lvi.iItem = nIndex;  
    lvi.iSubItem = 0;  
    lvi.iImage = nImage; 
    lvi.pszText = LPSTR_TEXTCALLBACK;  
    lvi.lParam = (LPARAM) pItem; 
 
    return GetListCtrl().InsertItem(&lvi); 
} 
 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : FreeItemMemory									*/ 
/* Description   : Free memory that was allocated for list item.	*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::FreeItemMemory() 
{ 
    int nCount = GetListCtrl().GetItemCount(); 
    if(nCount)  
	{ 
        for(int i=0; iitem.mask & LVIF_TEXT)  
	{ 
		ITEMINFO* pItem =(ITEMINFO*) pDispInfo->item.lParam; 
 
        switch(pDispInfo->item.iSubItem)  
		{ 
        case 0: // File name 
            ::lstrcpy(pDispInfo->item.pszText, pItem->strFileName); 
            break; 
 
        case 1: // File size 
			if (pItem->bIsDirectory) 
			{ 
				::lstrcpy(pDispInfo->item.pszText, ""); 
			} 
			else 
			{ 
				::lstrcpy(pDispInfo->item.pszText, FormatSize(pItem->nFileSize)); 
			} 
            break; 
 
        case 2: // File type 
            ::lstrcpy(pDispInfo->item.pszText, pItem->strType); 
 
			break; 
        case 3: // Date and time 
            CTime time(pItem->ftLastWriteTime); 
 
            BOOL pm = FALSE; 
            int nHour = time.GetHour(); 
            if(nHour == 0) 
                nHour = 12; 
            else  
			if(nHour == 12) 
                pm = TRUE; 
            else  
			if(nHour > 12)  
			{ 
                nHour -= 12; 
                pm = TRUE; 
            } 
 
            string.Format(_T("%d/%0.2d/%0.2d(%d:%0.2d%c)"), 
                time.GetMonth(), time.GetDay(), time.GetYear() % 100, 
                nHour, time.GetMinute(), pm ? _T('p') : _T('a')); 
            ::lstrcpy(pDispInfo->item.pszText, string); 
            break; 
        } 
    } 
	*pResult = 0; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnColumnClick									*/ 
/* Description   : 													*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	NM_LISTVIEW* pNMListView =(NM_LISTVIEW*) pNMHDR; 
 
	// User clicked on header using left mouse button 
    if(pNMListView->iSubItem == m_nSortedCol) 
		g_bSortAscending = !g_bSortAscending; 
	else 
		g_bSortAscending = TRUE; 
 
	m_nSortedCol = pNMListView->iSubItem; 
     
	GetListCtrl().SortItems(CompareFunc, pNMListView->iSubItem); 
	*pResult = 0; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : CompareFunc										*/ 
/* Description   : 													*/ 
/*																	*/ 
/********************************************************************/ 
int CALLBACK CFtpListView::CompareFunc(LPARAM lParam1, LPARAM lParam2,LPARAM lParamSort) 
{ 
    ITEMINFO* pItem1 =(ITEMINFO*) lParam1; 
    ITEMINFO* pItem2 =(ITEMINFO*) lParam2; 
    int nResult; 
 
    switch(lParamSort)  
	{ 
    case 0: // File name 
		if (pItem1->bIsDirectory && !pItem2->bIsDirectory) 
			return (g_bSortAscending ? -1 : 1); 
 
		if (!pItem1->bIsDirectory && pItem2->bIsDirectory) 
			return (g_bSortAscending ? 1 : -1); 
 
        nResult = pItem1->strFileName.CompareNoCase(pItem2->strFileName); 
        break; 
 
    case 1: // File size 
		if (pItem1->bIsDirectory && !pItem2->bIsDirectory) 
			return (g_bSortAscending ? -1 : 1); 
		if (!pItem1->bIsDirectory && pItem2->bIsDirectory) 
			return (g_bSortAscending ? 1 : -1); 
 
        nResult = pItem1->nFileSize - pItem2->nFileSize; 
        break; 
 
    case 2: // type 
		if (pItem1->bIsDirectory && !pItem2->bIsDirectory) 
			return -1; 
		if (!pItem1->bIsDirectory && pItem2->bIsDirectory) 
			return 1; 
 
        nResult = pItem1->strType.CompareNoCase(pItem2->strType); 
        break; 
 
    case 3: // Date and time 
        nResult = ::CompareFileTime(&pItem1->ftLastWriteTime, &pItem2->ftLastWriteTime); 
        break; 
    } 
    return (g_bSortAscending ? nResult : -nResult); 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : GetTypeName										*/ 
/* Description   : 													*/ 
/*																	*/ 
/********************************************************************/ 
char* CFtpListView::GetTypeName(CString strPath) 
{ 
	SHFILEINFO sfi; 
	memset(&sfi, 0, sizeof(sfi)); 
 
	static char lpBuff[MAX_PATH]; 
	lpBuff[0] = char ('\0'); 
 
	SHGetFileInfo(strPath, 0, &sfi, sizeof(sfi), SHGFI_TYPENAME); 
 
	lstrcpy(lpBuff, sfi.szTypeName); 
	if (lpBuff[0] == char('\0')) 
	{ 
		int nDotIdx = strPath.ReverseFind('.'); 
		int nBSIdx = strPath.ReverseFind('\\'); 
		if (nDotIdx > nBSIdx) 
		{ 
			strPath = strPath.Mid(nDotIdx+1); 
			strPath.MakeUpper(); 
			lstrcpy (lpBuff, strPath + ' '); 
		} 
 
		lstrcat (lpBuff, _T("File")); 
	} 
	return lpBuff; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : FormatSize										*/ 
/* Description   : Format size, the way explorer diplays it			*/ 
/*																	*/ 
/********************************************************************/ 
char* CFtpListView::FormatSize(DWORD dwSizeLow, DWORD dwSizeHigh) 
{ 
	static char szBuff[100]; 
 
	unsigned __int64 nFileSize = ((unsigned __int64)(((DWORD)(dwSizeLow)) |  
								 ((unsigned __int64)((DWORD)(dwSizeHigh))) << 32)); 
	unsigned __int64 kb = 1; 
 
	if (nFileSize > 1024) 
	{ 
		kb = nFileSize / 1024; 
		if (nFileSize % 1024) 
			kb++; 
	} 
 
	// make it a string 
	_ui64tot(kb, szBuff, 10); 
 
	// add thousand seperators 
	int nLength = lstrlen(szBuff); 
	if (nLength > 3) 
	{ 
		LPCTSTR ptr = szBuff; 
		ptr += (nLength-1); 
 
		char szTemp[100]; 
 
		LPTSTR ptrTemp = szTemp; 
		for(int i=0; ibIsDirectory; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : GetFileSize										*/ 
/* Description   : Get size of selected file						*/ 
/*																	*/ 
/********************************************************************/ 
DWORD CFtpListView::GetFileSize(int nItem) 
{ 
	return ((ITEMINFO*)GetListCtrl().GetItemData(nItem))->nFileSize; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : GetLastWriteTime									*/ 
/* Description   :													*/ 
/*																	*/ 
/********************************************************************/ 
FILETIME CFtpListView::GetLastWriteTime(int nItem) 
{ 
	return ((ITEMINFO*)GetListCtrl().GetItemData(nItem))->ftLastWriteTime; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnDeleteitem										*/ 
/* Description   : Delete allocated item data						*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::OnDeleteitem(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; 
 
	delete(ITEMINFO*) GetListCtrl().GetItemData(pNMListView->iItem); 
	 
	*pResult = 0; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : Sort												*/ 
/* Description   : Call sort function								*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::Sort(int nCol) 
{ 
	GetListCtrl().SortItems(CompareFunc, (nCol != -1) ? nCol : m_nSortedCol); 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : InitListViewImageLists							*/ 
/* Description   : Use system imagelist for the file icons			*/ 
/*																	*/ 
/********************************************************************/ 
BOOL CFtpListView::InitListViewImageLists() 
{ 
	HIMAGELIST himlSmall; 
	HIMAGELIST himlLarge; 
	SHFILEINFO sfi; 
 
	himlSmall = (HIMAGELIST) SHGetFileInfo ((LPCSTR) "C:\\",  
		0, &sfi, sizeof (SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON); 
 
	himlLarge = (HIMAGELIST) SHGetFileInfo ((LPCSTR) "C:\\",  
		0, &sfi, sizeof (SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_LARGEICON); 
 
	if (himlSmall && himlLarge) 
	{ 
		::SendMessage(GetListCtrl().m_hWnd, LVM_SETIMAGELIST, (WPARAM)LVSIL_SMALL, (LPARAM)himlSmall); 
		::SendMessage(GetListCtrl().m_hWnd, LVM_SETIMAGELIST, (WPARAM)LVSIL_NORMAL, (LPARAM)himlLarge); 
		return TRUE; 
	} 
	return FALSE; 
}  
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : SetFileName										*/ 
/* Description   : Set filename (after renaming)					*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::SetFileName(int nIndex, LPCTSTR lpszFileName) 
{ 
	((ITEMINFO*)GetListCtrl().GetItemData(nIndex))->strFileName = lpszFileName; 
	GetListCtrl().SetItemText(nIndex, 0, lpszFileName); 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : IsEditing										*/ 
/* Description   : Is listview in edit mode ?						*/ 
/*																	*/ 
/********************************************************************/ 
BOOL CFtpListView::IsEditing() 
{ 
	return m_bEditMode; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : PreTranslateMessage								*/ 
/* Description   : Prevent accelerator keys to be executed while	*/ 
/*				   in edit mode.									*/ 
/*																	*/ 
/********************************************************************/ 
BOOL CFtpListView::PreTranslateMessage(MSG* pMsg)  
{ 
	if(m_bEditMode) 
	{ 
		if((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST)) 
		{ 
			TranslateMessage(pMsg); 
			DispatchMessage(pMsg); 
			return TRUE; 
		} 
	} 
	return CListView::PreTranslateMessage(pMsg); 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : ActivateAnimation								*/ 
/* Description   : Switch search on/off.							*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::ActivateAnimation(BOOL bOn) 
{ 
	if (bOn) 
	{ 
		// control is already created 
		if (IsWindow(m_AnimateCtrl.m_hWnd)) 
			return; 
 
		CRect rc;  
		GetClientRect(rc); 
		 
		// create animation control 
		if (m_AnimateCtrl.Create(WS_CHILD | ACS_CENTER | ACS_TRANSPARENT | ACS_AUTOPLAY, rc, this, 88)) 
		{ 
			// switch off redraw of listview to prevent flickering 
			GetListCtrl().SetRedraw(FALSE); 
			// load animation 
			m_AnimateCtrl.Open(IDR_AVI3); 
			// show animation 
			m_AnimateCtrl.ShowWindow(SW_SHOW); 
			m_bSearching = TRUE; 
		} 
	} 
	else 
	{ 
		m_bSearching = FALSE; 
		if (IsWindow(m_AnimateCtrl.m_hWnd)) 
		{ 
			// stop animation 
			m_AnimateCtrl.Stop(); 
			// hide animation 
			m_AnimateCtrl.ShowWindow(SW_HIDE); 
			// switch on redraw of listview 
			GetListCtrl().SetRedraw(TRUE); 
			// destroy animation control 
			m_AnimateCtrl.PostMessage(WM_CLOSE); 
		} 
	} 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnSize											*/ 
/* Description   : If search animation is active resize it.			*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::OnSize(UINT nType, int cx, int cy)  
{ 
	CListView::OnSize(nType, cx, cy); 
	 
	if (IsWindow(m_AnimateCtrl.m_hWnd)) 
	{ 
		m_AnimateCtrl.MoveWindow(0, 0, cx, cy); 
		Invalidate(); 
		UpdateWindow(); 
	} 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnCtlColor										*/ 
/* Description   : Make search animation look good.					*/ 
/*																	*/ 
/********************************************************************/ 
HBRUSH CFtpListView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
{ 
	HBRUSH hbr = CListView::OnCtlColor(pDC, pWnd, nCtlColor); 
 
	UINT id = pWnd->GetDlgCtrlID(); 
	// change background color of animation 
	if (id == 88) 
	{ 
		pDC->SetBkColor(GetSysColor(COLOR_WINDOW)); 
		return (HBRUSH)GetSysColorBrush(COLOR_WINDOW); 
	} 
	return hbr; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnRclick											*/ 
/* Description   : Show context menu.								*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::OnRclick(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	CMenu menu; 
 
	POINT pt; 
	GetCursorPos(&pt); 
 
	// get selected item 
	int nIndex = GetListCtrl().GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);  
	if (nIndex != -1) 
	{ 
		if (IsDirectory(nIndex)) 
			menu.LoadMenu(MAKEINTRESOURCE(IDR_FOLDERPOPUP)); 
		else 
			menu.LoadMenu(MAKEINTRESOURCE(IDR_FILEPOPUP)); 
	} 
	else 
	{ 
		menu.LoadMenu(MAKEINTRESOURCE(IDR_LISTPOPUP)); 
	} 
	menu.GetSubMenu(0)->TrackPopupMenu(0, pt.x, pt.y, AfxGetMainWnd(), NULL);		 
 
	*pResult = 0; 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : OnDropFiles										*/ 
/* Description   : Files have been dropped on the listview.			*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::OnDropFiles(HDROP hDropInfo)  
{ 
	char szFileName[_MAX_PATH]; 
	 
	// determine how many files are dropped 
	UINT nCount = DragQueryFile(hDropInfo, -1, NULL, 0); 
 
	for(UINT i=0; i < nCount; i++) 
	{ 
		// get the filename 
		DragQueryFile(hDropInfo, i, szFileName, _MAX_PATH); 
 
		CString strDropName = szFileName; 
 
		// check if it a directory 
		if ((GetFileAttributes(szFileName) & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) 
		{ 
			// enumerate directory structure and add everything to queue  
			CStringArray strFileNames; 
			CString strFileName, strSize, strPath, strDestination; 
			RecursiveFileList(szFileName, strFileNames); 
 
			// queue all found files 
			for (int i = 0; i < strFileNames.GetSize(); i++) 
			{ 
				AfxExtractSubString(strFileName, strFileNames.GetAt(i), 0, '|'); 
				AfxExtractSubString(strPath,	 strFileNames.GetAt(i), 1, '|'); 
 
				// fix path 
				int nPos = strDropName.ReverseFind('\\'); 
				if (nPos != -1) 
				{ 
					strDropName = strDropName.Left(nPos+1); 
				} 
				strDestination = strPath; 
				int nLength = strDropName.GetLength(); 
				strDestination = strDestination.Mid(nLength); 
				strDestination.Replace('\\', '/'); 
 
				((CMainFrame *)AfxGetMainWnd())->UploadFile(strPath + "\\" + strFileName, strDestination + "/" + strFileName); 
			} 
		} 
		else 
		{ 
			int nPos = strDropName.ReverseFind('\\'); 
			if (nPos != -1) 
			{ 
				((CMainFrame *)AfxGetMainWnd())->UploadFile(strDropName, strDropName.Mid(nPos+1)); 
			} 
		} 
	} 
 
	CListView::OnDropFiles(hDropInfo); 
} 
 
 
/********************************************************************/ 
/*																	*/ 
/* Function name : RecursiveFileList								*/ 
/* Description   : Recursively walk through directory to be able to	*/ 
/*				   upload complete directory structure.				*/ 
/*																	*/ 
/********************************************************************/ 
void CFtpListView::RecursiveFileList(LPCTSTR lpszPath, CStringArray &strFileNameArray) 
{ 
	CFileFind fileFind; 
	CStringArray strDirectoryArray; 
 
	// add directory (without filename), so we can create the directory structure later 
	CString strFileName; 
	strFileName.Format("|%s", lpszPath); 
	strFileNameArray.Add(strFileName); 
	 
	BOOL bContinue = fileFind.FindFile(CString(lpszPath) + "\\*.*"); 
	if (!bContinue) 
	{ 
		// the directory is empty; just close up and return. 
		fileFind.Close(); 
		return; 
	} 
 
	// add all files in lpszPath 
	while (bContinue) 
	{ 
		bContinue = fileFind.FindNextFile(); 
 
		if (fileFind.IsDots()) 
			continue; 
 
		if (fileFind.IsDirectory()) 
		{ 
			strDirectoryArray.Add(fileFind.GetFileName()); 
		} 
		else 
		{ 
			strFileName.Format("%s|%s", fileFind.GetFileName(), lpszPath); 
			strFileNameArray.Add(strFileName); 
		} 
	} 
	fileFind.Close(); 
 
	// get contains of directories 
	for (int i = 0; i < strDirectoryArray.GetSize(); i++) 
	{ 
		RecursiveFileList(CString(lpszPath) + "\\" + strDirectoryArray.GetAt(i), strFileNameArray); 
	} 
} 
 
void CFtpListView::OnOdcachehint(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	NMLVCACHEHINT* pCacheHint = (NMLVCACHEHINT*)pNMHDR; 
	// TODO: Add your control notification handler code here 
	 
	*pResult = 0; 
}