www.pudn.com > DiskInfo.tgz > DiskTreeCtrl.cpp


// DiskTreeCtrl.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "diskinfo.h" 
#include "DiskTreeCtrl.h" 
 
#include "Common/Useful.h" 
#include "Common/makehtml.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
int CDiskTreeCtrl::m_nSortCol = -1; 
BOOL CDiskTreeCtrl::m_bSortAscending = TRUE; 
int CDiskTreeCtrl::nOldProgress = -1; 
long double CDiskTreeCtrl::dTotalUsedSize = 1; 
 
///////////////////////////////////////////////////////////////////////////// 
// CDiskTreeCtrl 
 
CDiskTreeCtrl::CDiskTreeCtrl() 
{ 
	m_nThreadCode = 1; 
	m_pThread = NULL; 
	m_pFolder = NULL; 
} 
 
CDiskTreeCtrl::~CDiskTreeCtrl() 
{ 
} 
 
 
BEGIN_MESSAGE_MAP(CDiskTreeCtrl, CSuperGridCtrl) 
	//{{AFX_MSG_MAP(CDiskTreeCtrl) 
	ON_WM_CREATE() 
	ON_WM_SIZE() 
	//}}AFX_MSG_MAP 
	ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo) 
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick) 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CDiskTreeCtrl message handlers 
 
void CDiskTreeCtrl::UpdateFolders() 
{ 
	if (m_pThread || m_pFolder==NULL) 
		return; 
 
	m_nThreadCode = 1; 
 
	DeleteAll();  
	m_pFolder->DeleteAll(); 
	m_pFolder->m_bSorted = FALSE; 
 
	CItemInfo* lpItemInfo = new CItemInfo(); 
	lpItemInfo->m_pFolder = m_pFolder; 
 
	if(!CreateTreeCtrl(lpItemInfo)) 
		return; 
 
	Expand(GetRootItem(), 0 /*listview index 0*/);  
	 
	DISKTREETHREADPARAMS* pThreadParams = new DISKTREETHREADPARAMS; 
	pThreadParams->pFolder = m_pFolder; 
	pThreadParams->pTreeItem = GetRootItem(); 
	pThreadParams->pTreeCtrl = this; 
	pThreadParams->pWnd = AfxGetMainWnd(); 
 
	m_dCurFileSize = 0; 
	pThreadParams->pdFileSize = &m_dCurFileSize; 
	pThreadParams->dTotalUsed = 1; 
	 
	CString str(m_pFolder->m_strFolderName); 
	if (str.GetLength() > 3) 
		pThreadParams->bIsFolder = true; 
	else 
	{ 
		DWORD dwFreeSpaceLow; 
		DWORD dwFreeSpaceHigh; 
		DWORD dwTotalSpaceLow; 
		DWORD dwTotalSpaceHigh; 
		if (GetHDSpace(str, dwFreeSpaceLow, dwFreeSpaceHigh, 
			dwTotalSpaceLow, dwTotalSpaceHigh)) 
		{ 
			double dTotal = ((double)dwTotalSpaceHigh)* 
				MAX_DWORD_VALUE + (double)dwTotalSpaceLow; 
			double dFree = ((double)dwFreeSpaceHigh) *  
				MAX_DWORD_VALUE + (double)dwFreeSpaceLow; 
			 
			pThreadParams->dTotalUsed = dTotal - dFree; 
		} 
		 
		pThreadParams->bIsFolder = false; 
	} 
 
		 
	pThreadParams->pnThreadCode = &m_nThreadCode; 
 
	//EnableWindow(FALSE); 
 
	m_pThread = AfxBeginThread(ThreadFunc, (LPVOID)pThreadParams); 
} 
	 
int CDiskTreeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CSuperGridCtrl::OnCreate(lpCreateStruct) == -1) 
		return -1; 
	 
	if (IfNewComCtrl32()) 
		IE4StyleEx(LVS_EX_GRIDLINES);  
 
	if (m_wndFlatHeader.SubclassWindow(GetDlgItem(0)->GetSafeHwnd()) == 0) 
	{ 
		TRACE0("Unable to subclass header control.\n"); 
		return -1; 
	} 
 
	//associate imagelist with listviewctrl	 
	HINSTANCE hIns = AfxGetResourceHandle(); 
	AfxSetResourceHandle(AfxGetInstanceHandle()); 
	m_imgList.Create(IDB_FOLDERLIST,16,1,RGB(0, 255, 255)); 
	AfxSetResourceHandle(hIns); 
	 
	SetImageList(&m_imgList,LVSIL_SMALL); 
	 
	CImageList *pImageList = GetImageList(LVSIL_SMALL); 
	if(pImageList) 
		ImageList_GetIconSize(pImageList->m_hImageList, &m_cxImage, &m_cyImage); 
	else 
		return -1; 
 
	LV_COLUMN   lvColumn; 
	lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; 
	lvColumn.fmt = LVCFMT_CENTER; 
	lvColumn.cx = 200; 
	CString str; 
	for(int x = 0; x < 4; x++) 
    { 
		str.LoadString(IDS_COL_FOLDERTREE + x); 
 
		lvColumn.pszText = (LPTSTR)(LPCTSTR)str; 
		InsertColumn(x,&lvColumn); 
    } 
 
	return 0; 
} 
 
void CDiskTreeCtrl::ResizeColumns(BOOL bInit) 
{ 
	CRect rc; 
	GetClientRect(&rc); 
 
	int nCount = GetNumCol(); 
	int nWidth = 0; 
 
	if (bInit) 
	{ 
		nWidth = (rc.Width() - GetSystemMetrics(SM_CXHSCROLL)) / 2; 
 
		int nSubWidth = nWidth/(nCount-1); 
		int nTotalSub = 0; 
		 
		for (int i=1; ipFolder; 
	CDiskTreeCtrl::CTreeItem* pTreeItem = pThreadParams->pTreeItem; 
	int* pnThreadCode = pThreadParams->pnThreadCode; 
	CDiskTreeCtrl* pTreeCtrl = pThreadParams->pTreeCtrl; 
	CWnd* pWnd = pThreadParams->pWnd; 
 
	if (pThreadParams->bIsFolder) 
		pThreadParams->dTotalUsed = GetNrSubFolders(pFolder->m_strFolderName); 
 
	::PostMessage((HWND)pWnd->GetSafeHwnd(), WM_USER_SCANPROGRESS, SCAN_PROGRESS_SET_RANGE, MAKELPARAM(0, 20)); 
	::PostMessage((HWND)pWnd->GetSafeHwnd(), WM_USER_SCANPROGRESS, SCAN_PROGRESS_SET_POS, (LPARAM)0);	 
 
	long double dFileSize = 0; 
	UpdateDir(pFolder,(LPCTSTR)(pFolder->m_strFolderName), dFileSize, 
		pTreeCtrl, pTreeItem, pnThreadCode, pWnd, pThreadParams, pThreadParams->bIsFolder, true); 
 
	pFolder->SetReady(0); // Folder 
 
	delete pThreadParams; 
 
	if ((*pnThreadCode) == -1) 
		return -1; 
 
	pTreeCtrl->m_pThread = NULL; 
	pTreeCtrl->RedrawWindow(); 
 
	if ((*pnThreadCode) == -1) 
		return -1; 
 
	if (pTreeCtrl->GetSelectedFolder() == NULL) 
		pTreeCtrl->SelectNode(pTreeCtrl->GetRootItem()); 
 
	// Force view to update infos 
	pTreeCtrl->GetOwner()->PostMessage(WM_FOLDER_SELECTED, 1,0); // Give int 1 to tell the scanning has just finished 
 
	::PostMessage((HWND)pWnd->GetSafeHwnd(), WM_USER_SCANPROGRESS, SCAN_PROGRESS_FINISHED, NULL); 
 
	return 0; 
} 
 
void CDiskTreeCtrl::UpdateDir(CMyFolder * pCurDir, const char * charPath,  
						   long double & dFileSize, 
						   CDiskTreeCtrl* pTreeCtrl,  
						   CDiskTreeCtrl::CTreeItem* pTreeItem, 
						   int* pnThreadCode, CWnd* pWnd, 
						   DISKTREETHREADPARAMS* pThreadParams,  
						   bool bIsFolder, 
						   bool bRootFolder) 
{ 
	if ((*pnThreadCode) == -1) 
		return; 
 
	HANDLE hFind; 
    WIN32_FIND_DATA fd; 
     
	char charCmp[MAX_PATH]; 
	strcpy(charCmp, charPath); 
	strcat(charCmp, "*.*");		 
	long int nCurrentFileCount=0; 
	double dCurFileSize=0; 
	CItemInfo* lpItemInfo; 
 
	CTreeItem* pNewItem; 
 
    if ((hFind = ::FindFirstFile ((LPCTSTR) charCmp, &fd)) == 
        INVALID_HANDLE_VALUE)  
        return; 
 
    do { 
		if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)  
		{ 
			strcpy(charCmp, (LPCTSTR) &fd.cFileName); 
			//strlwr(charCmp); // Make lower 
 
            if ((strcmp(charCmp, ".")!=0) && (strcmp(charCmp, "..")!=0))  
			{ 
				CMyFolder* pDir = new CMyFolder(); 
				pDir->SetTitle(charCmp); 
				pCurDir->Add(pDir); 
				strcpy(charCmp, charPath); 
				strcat(charCmp, (LPCTSTR) &fd.cFileName); 
				strcat(charCmp, "\\"); 
 
				if ((*pnThreadCode) == -1) 
					return; 
				else 
				{ 
					lpItemInfo = new CItemInfo(); 
					lpItemInfo->m_pFolder = pDir; 
 
					if ((*pnThreadCode) == -1) 
					{ 
						delete lpItemInfo; 
						return; 
					}else 
						pNewItem = pTreeCtrl->InsertItem(pTreeItem, lpItemInfo); 
				} 
				 
				UpdateDir(pDir, charCmp, dFileSize, pTreeCtrl, pNewItem, pnThreadCode, pWnd,  
					pThreadParams, bIsFolder); 
				pDir->SetReady(0); 
 
				if ((*pnThreadCode) == -1) 
					return; 
				else 
				{ 
					int n = pTreeCtrl->GetCurIndex(pNewItem); 
					if (n != -1) 
						pTreeCtrl->Update(n); 
				} 
 
				if (bIsFolder && bRootFolder) 
					*(pThreadParams->pdFileSize) += 1; 
            } 
        }else 
		{ 
			pCurDir->m_nFileCount ++; 
			pCurDir->m_dFileSize += fd.nFileSizeLow; 
			dFileSize += fd.nFileSizeLow; 
			dCurFileSize += fd.nFileSizeLow; 
			nCurrentFileCount++; 
			 
			if (!bIsFolder) 
				*(pThreadParams->pdFileSize) += fd.nFileSizeLow; 
		} 
    } while (((*pnThreadCode) != -1) && ::FindNextFile (hFind, &fd)); 
 
	::FindClose (hFind); 
 
	//pCurDir->FreeExtra(); 
	if ((*pnThreadCode) != -1 && nCurrentFileCount>0) // Add File Item 
	{ 
		CMyFolder* pDir = new CMyFolder(); 
		//pDir -> m_pChart = &m_wndPieChart; 
		pDir->m_strFolderName.LoadString(IDS_FILES); 
		pDir->m_nFileCount = nCurrentFileCount; 
		pDir->m_dFileSize = dCurFileSize; 
		pCurDir->Add(pDir); 
 
		pDir->SetReady(1); 
 
		lpItemInfo = new CItemInfo(); 
		lpItemInfo->m_pFolder = pDir; 
		if ((*pnThreadCode) == -1) 
		{ 
			delete lpItemInfo; 
			return; 
		}else 
			pNewItem = pTreeCtrl->InsertItem(pTreeItem, lpItemInfo); 
	} 
 
	int i = (long int)(((*(pThreadParams->pdFileSize)) / pThreadParams->dTotalUsed)*21); 
	i++; // move from 0-19 to 1-20 
	if (i>20) 
		i = 20; 
	::PostMessage(pWnd->GetSafeHwnd(), WM_USER_SCANPROGRESS, SCAN_PROGRESS_SET_POS, (LPARAM)i); 
 
	Sleep(0); 
 
	/* 
	int i = (int)((dFileSize / dTotalUsedSize)*110);//*135; // Fusk should be 100 
	if (i>100) 
		i = 100; 
	if (nOldProgress != i) 
	{ 
		// Send message to main frame to update progress bar 
		nOldProgress = i; 
	}*/ 
} 
 
void CDiskTreeCtrl::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) 
{ 
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; 
	CTreeItem* pFileItem= (CTreeItem*) pDispInfo->item.lParam; 
	LV_ITEM *pItem = &((LV_DISPINFO*)pNMHDR)->item; 
 
	if(! (pItem->mask & LVIF_TEXT)) 
		return; 
 
	CMyFolder* pFolder = pFileItem->m_lpNodeInfo->m_pFolder; 
 
	::lstrcpy (pDispInfo->item.pszText, (LPCTSTR) pFolder->GetItemText(pDispInfo->item.iSubItem)); 
 
	*pResult = 0; 
} 
 
CString CDiskTreeCtrl::GetCurrentFolder() 
{ 
	if (m_pFolder) 
		return m_pFolder->m_strFolderName; 
	else 
		return CString(); 
	 
} 
 
int CDiskTreeCtrl::GetIcon(const CTreeItem *pItem) 
{ 
	int iImage = 0; 
	if(pItem->m_lpNodeInfo->m_pFolder->IsFile()) 
		iImage = 2;//doc icon 
	else 
		IsCollapsed(pItem) ? iImage = 1/*close icon*/:iImage = 0;/*open icon*/		 
 
	return iImage; 
} 
 
void CDiskTreeCtrl::Stop() 
{ 
	if (m_pThread) 
	{ 
		m_nThreadCode = -1; 
		HANDLE hThread = m_pThread->m_hThread; 
		 
		PumpMessages(); // Wait until send message returns. 
 
		if (::WaitForSingleObject(hThread, 500) == WAIT_TIMEOUT) 
			::TerminateThread(hThread, 0); 
		//::WaitForSingleObject(hThread, INFINITE); 
		m_pThread = NULL; 
 
		::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_USER_SCANPROGRESS, SCAN_PROGRESS_FINISHED, NULL); 
	} 
} 
 
void CDiskTreeCtrl::Sort(CTreeItem *pParent) 
{ 
	const int nChildren = NumChildren(pParent); 
	if (nChildren > 1) 
	{ 
		CTreeItem** ppSortArray = new CTreeItem*[nChildren]; 
		// Fill in array with pointers to our children. 
		POSITION pos = pParent->m_listChild.GetHeadPosition(); 
		for (int i=0; pos; i++) 
		{ 
			if (i < nChildren) // To be thread safe, when sorting and scanning at sametime 
			{ 
				ppSortArray[i] = (CTreeItem*)pParent->m_listChild.GetAt(pos); 
				pParent->m_listChild.GetNext(pos); 
			} 
		} 
 
		qsort(ppSortArray, nChildren, sizeof(CTreeItem*), CompareChildren); 
		// reorg children with new sorted list 
		pos = pParent->m_listChild.GetHeadPosition(); 
		for (i=0; pos; i++) 
		{ 
			if (i < nChildren) // To be thread safe, when sorting and scanning at sametime 
			{ 
				pParent->m_listChild.SetAt(pos, ppSortArray[i]); 
				pParent->m_listChild.GetNext(pos); 
			} 
		} 
 
		delete [] ppSortArray; 
	} 
 
	POSITION pos = pParent->m_listChild.GetHeadPosition(); 
	while (pos) 
	{ 
		CTreeItem *pChild = (CTreeItem*)pParent->m_listChild.GetNext(pos); 
		Sort(pChild); 
	} 
} 
 
int CDiskTreeCtrl::CompareChildren(const void *p1, const void *p2) 
{ 
	CTreeItem * pChild1 = *(CTreeItem**)p1; 
	CTreeItem * pChild2 = *((CTreeItem**)p2); 
	CItemInfo *pItem1=(*pChild1).m_lpNodeInfo; 
	CItemInfo *pItem2=(*pChild2).m_lpNodeInfo; 
 
	int nResult=0; 
 
	switch (m_nSortCol) 
	{ 
	case 0: // Title 
		nResult = (pItem1->GetItemText()).CompareNoCase(pItem2->GetItemText()); 
		break; 
	case 1: // Size 
		nResult = int(pItem1->m_pFolder->GetFolderSize(TRUE) - pItem2->m_pFolder->GetFolderSize(TRUE)); 
		break; 
	case 2: // Folders 
		nResult = int(pItem1->m_pFolder->GetFolderCount(TRUE) - pItem2->m_pFolder->GetFolderCount(TRUE)); 
		break; 
	case 3: // Files 
		nResult = int(pItem1->m_pFolder->GetFileCount(TRUE) - pItem2->m_pFolder->GetFileCount(TRUE)); 
		break; 
	} 
	 
	if (m_bSortAscending == FALSE) 
		nResult = 0 - nResult; 
 
	return nResult;//StrComp(&(pItem1->GetItemText()), &(pItem2->GetItemText())); 
} 
 
void CDiskTreeCtrl::OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	CWaitCursor wait; 
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; 
	// TODO: Add your control notification handler code here 
	 
	if( pNMListView->iSubItem == CDiskTreeCtrl::m_nSortCol ) 
		CDiskTreeCtrl::m_bSortAscending = !CDiskTreeCtrl::m_bSortAscending; 
	else 
		CDiskTreeCtrl::m_bSortAscending = TRUE; 
 
	m_wndFlatHeader.SetSortColumn(pNMListView->iSubItem, CDiskTreeCtrl::m_bSortAscending); 
 
	CDiskTreeCtrl::m_nSortCol = pNMListView->iSubItem; 
 
	CTreeItem *pRootItem = GetRootItem(); 
	CTreeItem* pSelItem = NULL; 
 
	int nItem = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); 
	if (nItem != -1) 
		pSelItem = reinterpret_cast(GetItemData(nItem)); 
 
	if (pRootItem) 
	{ 
		Sort(pRootItem); 
 
		SetRedraw(0); 
		RedrawOpenedItems(pRootItem); 
		SetRedraw(1); 
 
		if (pSelItem) 
			SelectNode(pSelItem); 
	} 
 
	*pResult = 0; 
} 
 
CMyFolder* CDiskTreeCtrl::GetSelectedFolder() 
{ 
	int nItem = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); 
	if (nItem == -1) 
		return NULL; 
 
	CTreeItem* pSelItem = reinterpret_cast(GetItemData(nItem)); 
 
	return pSelItem->m_lpNodeInfo->m_pFolder; 
} 
 
CString CDiskTreeCtrl::GetItemPath(CTreeItem* pItem) 
{ 
	CString strThis = pItem->m_lpNodeInfo->m_pFolder->m_strFolderName; 
 
	if (pItem == GetRootItem()) 
		return strThis; 
 
	CTreeItem* pParentItem = GetParentItem(pItem); 
	CString str = GetItemPath(pParentItem); 
	if (str.Right(1) != "\\") 
		str += "\\"; 
 
	if (!(pItem->m_lpNodeInfo->m_pFolder->IsFile())) 
		str += strThis; 
 
	return str; 
} 
 
CString CDiskTreeCtrl::GetSelectedPath() 
{ 
	int nItem = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); 
	if (nItem == -1) 
		return CString(""); 
 
	CTreeItem* pSelItem = reinterpret_cast(GetItemData(nItem)); 
 
	return GetItemPath(pSelItem); 
} 
 
 
// Just to create a estimated progress ctrl for folders 
int CDiskTreeCtrl::GetNrSubFolders(LPCTSTR strRoot, bool bSub) 
{ 
	int i=0; 
 
	HANDLE hFind; 
    WIN32_FIND_DATA fd; 
	TCHAR charCmp[MAX_PATH]; 
	strcpy(charCmp, strRoot); 
	strcat(charCmp, "\\*.*"); 
 
    if ((hFind = ::FindFirstFile ((LPCTSTR) charCmp, &fd)) != 
        INVALID_HANDLE_VALUE)  
	{ 
		 
		do { 
			if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)  
			{ 
				if ((strcmp(fd.cFileName, ".")!=0) && (strcmp(fd.cFileName, "..")!=0))  
				{ 
					strcpy(charCmp, strRoot); 
					strcat(charCmp, "\\"); 
					strcat(charCmp, fd.cFileName); 
 
					if (bSub) 
						i += GetNrSubFolders(charCmp, bSub); 
					i++; 
				} 
				 
			} 
			 
		} while (::FindNextFile (hFind, &fd)); 
		::FindClose (hFind); 
	} 
 
	return i; 
} 
 
void CDiskTreeCtrl::PrintTree(CDC *pDC, const CPoint& ptStart, const CSize& szSize, int nStart, int nEnd) 
{ 
	if (GetItemCount()<=0) 
		return; 
 
	CRect rc(ptStart,szSize); 
	 
	for (int i=nStart; i < nEnd; i++) 
	{ 
		CTreeItem *pItem = reinterpret_cast(GetItemData(0)); 
		/*DRAWITEMSTRUCT dr; 
 
		dr.CtlID = 0; 
		dr.CtlType = ODT_LISTVIEW; 
		dr.hDC = pDC->GetSafeHdc(); 
		dr.hwndItem = NULL; 
		dr.itemAction = ODA_DRAWENTIRE; 
		dr.itemData = (unsigned long)pItem; 
		dr.itemID = NULL; 
		dr.rcItem = rc; 
		DrawItem(&dr);*/ 
		//DrawRow(pDC, rc, i); 
		DrawTreeItem(pDC, pItem, i, rc); 
 
		rc.OffsetRect(CSize(0, szSize.cy)); 
	} 
/* 
	//Set origin to print header and Header control. Keep Y position at 0 to 
     //print header information 
     //Change Y position of origin to print List control header 
     //Adjust the List control origin to start printing after page margins 
     //pDC->SetWindowOrg(-rc.left, -rc.top); 
	//double d = (double)pDC->GetDeviceCaps(LOGPIXELSY)/(double)pCtlDC->GetDeviceCaps(LOGPIX ELSY); 
 
     //GetDlgItem(0)->SendMessage(WM_PAINT, (WPARAM)pDC->m_hDC); 
 
     /*//*/Chage window position to take care of ListControl Horizontal scrolling. 
     //if List control is scrolled to left horizontally the above window origin 
     //will not start painting from first column, instead it starts painting from 
     //first visible column, because rcBounds etc are will have -ve left value 
     //Same thing with vertical scrolling also 
     CRect     rcBounds; 
     GetItemRect(nStartRow, &rcBounds, LVIR_BOUNDS); 
 
     //offset top margin of rcBounds by ListControl header 
     CRect     rc; 
     m_wndFlatHeader.GetClientRect(&rc); 
     rcBounds.OffsetRect(0, -rc.Height()); 
     pDC->OffsetWindowOrg(rcBounds.left, rcBounds.top); 
     //start printing rows 
     for(int i = nStartRow; i < nEndRow; i++) 
          DrawRow(pDC, i); 
 
     //SetWindowOrg back for next page 
     pDC->SetWindowOrg(0,0); 
 
	pDC->SetWindowOrg(0,0);*/ 
	 
	/* 
	 
	CTreeItem *pItem = pParent; 
	CItemInfo* lp = GetData(pParent); 
 
	CString strData = lp->GetItemText(); 
	strData+='\t'; 
	nLineY+=cy; 
	for(int nCol=0; nCol < lp->GetItemCount(); nCol++) 
	{ 
		CString str = lp->GetSubItem(nCol); 
		strData+=str; 
		strData+='\t'; 
	}	 
	pDC->TabbedTextOut(rcClient.left,nLineY,strData,strData.GetLength(), 0, NULL, 0); 
	nLineY+=cy; 
	//GetNext ....loop through all children  
	for(;;) 
	{ 
		CTreeItem *pCur= GetNextSiblingItem(pItem, TRUE, TRUE);	   
		if(!IsChildOf(pParent, pCur)) 
			break; 
		else 
		if(pCur==pItem) 
			break; 
 
		CItemInfo* lp = GetData(pCur); 
		CString strData = lp->GetItemText(); 
		strData+='\t'; 
		for(int nCol=0; nCol < lp->GetItemCount(); nCol++) 
		{ 
			CString str = lp->GetSubItem(nCol); 
			strData+=str; 
			strData+='\t'; 
		}	 
		pDC->TabbedTextOut(rcClient.left,nLineY,strData,strData.GetLength(), 0, NULL, 0); 
		nLineY+=cy; 
		pItem=pCur; 
	}*/ 
} 
 
//this is drawing code copied RowList sample and from www.codeguru.com site 
int CDiskTreeCtrl::DrawRow(CDC *pDC, const CRect& rc, int nItem) 
{ 
     return 0; 
} 
void CDiskTreeCtrl::OnSize(UINT nType, int cx, int cy)  
{ 
	CSuperGridCtrl::OnSize(nType, cx, cy); 
	 
	//if (GetSafeHwnd()) 
	//	;//ResizeColumns(TRUE);		 
} 
 
void CDiskTreeCtrl::BuildTreeToHTML() 
{ 
	CTreeItem* pRoot = GetRootItem(); 
 
	int nIndex = GetNextItem(-1, LVNI_ALL); 
	if(nIndex!=-1) 
	{ 
		//GetHeadPosition 
		CTreeItem *pParent = reinterpret_cast(GetItemData(nIndex)); 
		CTreeItem *pItem = pParent; 
 
		for(;;) 
		{ 
			CTreeItem *pCur= GetNextSiblingItem(pItem, TRUE, TRUE);	 
			if(!IsChildOf(pParent, pCur)) 
				break; 
			else 
			if(pCur==pItem) 
				break;		 
 
			BuildItemRow(pItem, pRoot); 
 
			pItem=pCur; 
		} 
 
		BuildItemRow(pItem, pRoot); 
	 } 
} 
 
void CDiskTreeCtrl::BuildItemRow(CTreeItem *pItem, CTreeItem* pRoot) 
{ 
	CreateHTMLRow(); 
	 
	CItemInfo* lp = GetData(pItem); 
	CString strData = lp->GetItemText(); 
	CString strImage(""); 
 
	int iIndent = GetIndent(pItem); 
	int nListItem = GetCurIndex(pItem); 
	CTreeItem *pSelItem = pItem; 
	while(pRoot != pSelItem) 
	{ 
		CTreeItem* pParent = GetParentItem(pSelItem); 
		POSITION pos = pParent->m_listChild.GetTailPosition(); 
		while(pos!=NULL) 
		{ 
			CTreeItem *pLastChild = (CTreeItem*)pParent->m_listChild.GetPrev(pos); 
			int nIndex = GetCurIndex(pLastChild); 
			//no drawing outside the 1st columns right 
			if (nIndex == nListItem && (GetIndent(pLastChild)==iIndent)) 
			{ 
				//draw '- 
				strImage = CreateHTMLImageString(_T("linelast.gif")) + strImage; 
				break; 
			} 
			else if(nIndex > nListItem && (GetIndent(pLastChild)==iIndent)) 
			{ 
				//draw |- 
				strImage = CreateHTMLImageString(_T("line.gif")) + strImage; 
				break; 
			} 
			else if(nIndex > nListItem && (GetIndent(pLastChild) < iIndent)) 
			{ 
				//draw | 
				strImage = CreateHTMLImageString(_T("linever.gif")) + strImage; 
				break; 
			}else 
			{ 
				strImage = CreateHTMLImageString(_T("empty.gif")) + strImage; 
				break; 
			} 
		}			 
		pSelItem = pParent;//next 
	} 
 
	/*for (int i=1; im_nIndent-1; i++) 
		strImage += CreateHTMLImageString(_T("empty.gif")); 
 
	if (pItem->m_nIndent > 1) 
		strImage += CreateHTMLImageString(_T("line.gif"));*/ 
	CMyFolder* pFolder = lp->m_pFolder; 
	if (pFolder->IsFile()) 
		strImage += CreateHTMLImageString(_T("file.gif")); 
	else if (ItemHasChildren(pItem) && !IsCollapsed(pItem)) 
		strImage += CreateHTMLImageString(_T("folder_o.gif")); 
	else 
		strImage += CreateHTMLImageString(_T("folder_c.gif")); 
 
	InsertHTMLCell("", strImage + _T(" ") + strData); 
	 
	for(int nCol=0; nCol < lp->GetItemCount(); nCol++) 
	{ 
		strData = lp->GetSubItem(nCol); 
		InsertHTMLCell("", strData); 
	} 
 
	FinishHTMLRow();	 
} 
 
 
#include "stdafx.h" 
 
#define LEFT_MARGIN 2 
#define RIGHT_MARGIN 4 
#define HEADER_HEIGHT 4 
#define FOOTER_HEIGHT 3 
 
//Set it all to 0 
//********************************CONSTRUCTOR************************************ 
CTreeListPrinting::CTreeListPrinting() 
{ 
	lc = 0; 
	pOldFont = 0; 
	TitleStr = ""; 
	DateStr = ""; 
	 
	page_rc.SetRect(0,0,0,0);	 
	m_nRowHeight = 0; 
	m_nRowsPerPage = 0; 
	m_nMaxRowCount = 0; 
	m_ratiox = 0; 
	m_ratioy = 0; 
	hc_items = 0; 
	return; 
} 
 
//Using default for printer guess at # of pages. 
//If no printer exists return FALSE; 
//************************ONPREPAREPRINTING******************************* 
BOOL CTreeListPrinting::OnPreparePrinting(CPrintInfo* pInfo, CView * cview, CDiskTreeCtrl * t_lc)  
{ 
	if(t_lc==NULL || cview==NULL || pInfo == NULL)          return FALSE; 
	lc = t_lc;//Set Pointer to list Control 
	 
	//Lets make a guess as to how many pages there are based on the default printer. 
	CPrintDialog pdlg(FALSE); 
	if (!pdlg.GetDefaults()) return FALSE;//If no defaults then no printer!! 
	CDC t_pDC; 
	t_pDC.Attach(pdlg.GetPrinterDC()); 
	compute_metrics(&t_pDC); 
	m_nMaxRowCount = lc->GetItemCount(); if(!m_nMaxRowCount) return FALSE;//Get the number of rows 
	int nMaxPage = m_nMaxRowCount/m_nRowsPerPage + 1; 
	pInfo->SetMaxPage(nMaxPage); 
	pInfo->m_nCurPage = 1;  // start printing at page# 1 
	 
	//If you want to be able to do this remove it. 
	pInfo->m_pPD->m_pd.Flags |=PD_HIDEPRINTTOFILE;  
	 
	return cview->DoPreparePrinting(pInfo); 
} 
 
//Call this from your view class OnBeingPrinting function 
//*************************ONBEGINGPRINTING************************* 
void CTreeListPrinting::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo, CString & t_title, CString & t_date) 
{ 
	if(pDC == NULL || pInfo==NULL)           
		return; 
	 
	TitleStr = t_title; 
	DateStr = t_date; 
	 
	//create lc font, and Bold lc Font 
	int nFontSize = -((pDC->GetDeviceCaps(LOGPIXELSY) * 10) / 72); 
    CString strFontName = "Arial"; 
    lcFont.CreateFont(-11, 0,0,0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET, 
                         OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, 
                          DEFAULT_PITCH | FF_DONTCARE, strFontName); 
    BoldFont.CreateFont(-13, 0,0,0, FW_BOLD, 0,0,0, DEFAULT_CHARSET, 
                         OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, 
                          DEFAULT_PITCH | FF_DONTCARE, strFontName); 
	 
	compute_metrics(pDC); 
	int nMaxPage = m_nMaxRowCount/m_nRowsPerPage + 1;//Compute this again in case user changed printer 
	pInfo->SetMaxPage(nMaxPage); 
	pInfo->m_nCurPage = 1;  // start printing at page# 1 
	 
	return; 
} 
 
//***********************ONPRINT************************* 
void CTreeListPrinting::OnPrint(CDC* pDC, CPrintInfo* pInfo)  
{ 
	if(NULL == pDC || NULL == pInfo)            
		return; 
	 
	//This has to be in OnPrint() or else PrintPreview goes screwy 
	pOldFont = pDC->GetCurrentFont(); 
	 
	//Fit all columns to 1 page, regardless of column number. 
	pDC->SetMapMode(MM_ANISOTROPIC); 
	 
	//For every 1 List Control pixel 
	pDC->SetWindowExt(1, 1); 
	 
	//The printer has ratio more dots 
	pDC->SetViewportExt(m_ratiox, m_ratioy); 
	 
	int nStartRow = (pInfo->m_nCurPage - 1)*m_nRowsPerPage; 
	int nEndRow = nStartRow+m_nRowsPerPage; 
	if(nEndRow > m_nMaxRowCount)        
		nEndRow = m_nMaxRowCount; 
	 
	PrintHeader(pDC, pInfo);     //print the header 
	 
	pDC->SetWindowOrg(-1*page_rc.left, 0); 
	PrintFooter(pDC, pInfo);	  //Print the footer 
	pDC->SetWindowOrg(-1*page_rc.left, -1*HEADER_HEIGHT*m_nRowHeight); 
	PrintHeaderControl(pDC, pInfo);//Print the header Control, Manually 
	pDC->SelectObject(&lcFont);//Use the LC normal font 
	pDC->SetTextColor(RGB(0,0,0));//Black text on 
	pDC->SetBkColor(RGB(255,255,255));//White paper 
	 
	CRect     rcBounds; 
	lc->GetItemRect(nStartRow, &rcBounds, LVIR_BOUNDS); 
	 
	//offset top margin of rcBounds by ListControl header 
	CRect     rc; 
	lc->GetHeaderCtrl()->GetClientRect(&rc); 
	rcBounds.OffsetRect(0, -rc.Height()); 
	pDC->OffsetWindowOrg(rcBounds.left, rcBounds.top); 
	 
	//start printing rows 
	for(int i = nStartRow; i < nEndRow; i++) 
		DrawRow(pDC, i); 
	 
	//SetWindowOrg back for next page 
	pDC->SetWindowOrg(0,0); 
	pDC->SelectObject(pOldFont);//Put the old font back 
	 
	return; 
} 
 
//Set the extents after calling this function because it uses printer extents 
//He is using a list in here have to figure out what to do. 
//********************************PRINT_HEADER************************************ 
void CTreeListPrinting::PrintHeader(CDC *pDC, CPrintInfo *pInfo) 
{ 
	pDC->SelectObject(&BoldFont); 
	pDC->SetTextColor(RGB(0,0,0));//Black text on 
	pDC->SetBkColor(RGB(255,255,255));//White paper 
	 
	CRect rc = page_rc; 
	rc.bottom = rc.top+m_nRowHeight; 
	 
	//print App title on top right margin 
	pDC->DrawText(TitleStr, &rc,  DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_RIGHT  | DT_NOCLIP); 
	 
	return; 
} 
 
//print footer with a line and date, and page number 
//****************************PRINT_FOOTER**************************************** 
void CTreeListPrinting::PrintFooter(CDC *pDC, CPrintInfo *pInfo) 
{ 
	CRect     rc = page_rc; 
	rc.top = rc.bottom - FOOTER_HEIGHT*m_nRowHeight; 
	rc.bottom = rc.top + m_nRowHeight; 
	draw_line_at(pDC, rc.top);     //draw line 
	 
	//draw page number 
	CString   sTemp ; 
	rc.OffsetRect(0, m_nRowHeight/2); 
	sTemp.Format("%d", pInfo->m_nCurPage); 
	pDC->DrawText(sTemp,-1,rc, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER); 
	 
	//Now draw the DateStr at bottom of page 
	pDC->DrawText(DateStr,-1,rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER); 
	 
	return; 
} 
 
 
//Do the cleanup 
//********************ONEND_PRINTING***************** 
void CTreeListPrinting::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo) 
{ 
	lcFont.DeleteObject(); 
	BoldFont.DeleteObject(); 
	return; 
} 
 
//This function sets alls of the row and metric member vars 
//************************COMPUTE_METRICS********************* 
void CTreeListPrinting::compute_metrics(CDC *pDC) 
{ 
	//This includes width for all columns 
	CRect row_rc;	lc->GetItemRect(0, &row_rc, LVIR_BOUNDS); 
	 
	//Get the list control window DC 
	CDC  *pCtlDC = lc->GetDC(); if(NULL == pCtlDC) return; 
	 
	//so we can get the avg character width 
	TEXTMETRIC tm;   pCtlDC->GetTextMetrics(&tm); 
	 
	//Lets get the ratios for scaling to printer DC 
	//Fit all columns to 1 page, regardless of column number. 
	m_ratiox = pDC->GetDeviceCaps(HORZRES)/(row_rc.Width() + (LEFT_MARGIN+RIGHT_MARGIN)*tm.tmAveCharWidth); 
	 
	//width of pDC/whats got to fit into it in lcDC units 
	m_ratioy = pDC->GetDeviceCaps(LOGPIXELSY)/pCtlDC->GetDeviceCaps(LOGPIXELSY); 
	 
	lc->ReleaseDC(pCtlDC); 
	 
	//Set up a page rc in list control units that accounts for left and right margins 
	page_rc.SetRect(0,0, pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES)); 
	page_rc.bottom = page_rc.bottom/m_ratioy;//Convert units to List Control 
	page_rc.right = page_rc.right/m_ratiox; 
	page_rc.left = LEFT_MARGIN*tm.tmAveCharWidth;//adjust sides for magins 
	page_rc.right -= RIGHT_MARGIN*tm.tmAveCharWidth; 
	 
	m_nRowHeight = row_rc.Height();//Get the height of a row. 
	int pRowHeight = (int)(m_nRowHeight*m_ratioy);//Get RowHeight in printer units. 
	m_nRowsPerPage = pDC->GetDeviceCaps(VERTRES)/pRowHeight;//How many rows will fit on page? 
	m_nRowsPerPage -= (HEADER_HEIGHT+FOOTER_HEIGHT);//After header and footer rows 
	m_nRowsPerPage -= 1; //After header Control row 
	 
	return; 
} 
 
//You can't just have the header control print itself. 1st of all it looks crappy. 
//2nd if part of header control is off screen does not print itself. 
//So we will manually print it. 
//************************PRINTHEADERCONTROL**************************** 
void CTreeListPrinting::PrintHeaderControl(CDC *pDC, CPrintInfo *pInfo) 
{ 
	UINT    dtFlags = DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER|DT_LEFT;//drawing flags 
	CHeaderCtrl* hc = lc->GetHeaderCtrl(); 
	hc_items = hc->GetItemCount();  
	if (hc_items < 1) return; //Remember that hc_items is also used to draw rows. 
	int order_array[30];//Shouln't have more than 30 columns 
	hc->GetOrderArray(order_array, hc_items); 
	 
	char temp_str[1024]; 
	HDITEM  phi; 
	phi.mask = HDI_TEXT | HDI_WIDTH ; 
	phi.cchTextMax = 1024; 
	phi.pszText = temp_str; 
	 
	CRect rc(0,0,0,m_nRowHeight); 
	 
	for (int i = 0; i < hc_items; i++) 
	{ 
		hc->GetItem(order_array[i], &phi);//Get in viewed order 
		rc.right += phi.cxy; 
		pDC->DrawText(temp_str, -1, rc, dtFlags); 
		rc.left += phi.cxy; 
	} 
	 
	//Now draw the line below header control 
	draw_line_at(pDC, rc.bottom); 
	 
	return; 
} 
 
//*************************************DRAWROW******************************************** 
void CTreeListPrinting::DrawRow(CDC *pDC, int nItem) 
{ 
	if (hc_items < 1) //Then nothing to print 
		return;   
	 
	int order_array[30];//Shouln't have more than 30 columns 
	lc->GetColumnOrderArray(order_array, hc_items); 
	 
	CString temp_str; 
	LV_COLUMN lvc; 
	lvc.mask = LVCF_WIDTH; 
	 
	CRect rc; lc->GetItemRect(nItem, rc, LVIR_BOUNDS); 
	int offset = pDC->GetTextExtent(" ", 1).cx;//Returns CSIZE so get cx member of CSIZE object. 
	rc.left += offset/2;//This makes it so that label will be over a little bit 
	rc.right -= offset;//Just keep this stuff it DOES look better. 
 
	CRect r(rc); 
 
	for (int i = 0; i < hc_items; i++) 
	{ 
		int nOffset = 0; 
		if (i==0) 
			nOffset = lc->DrawLine(pDC, nItem, r); 
		lc->GetColumn(order_array[i], &lvc);//Get in viewed order 
		temp_str = lc->GetItemText(nItem, order_array[i]); 
		r.left += nOffset; 
		pDC->DrawText(temp_str, -1, r, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER|DT_LEFT); 
		r.left += (lvc.cx - nOffset); 
	} 
 
	pDC->MoveTo(rc.Width() - lc->GetColumnWidth(0) + offset, rc.bottom); 
	pDC->LineTo(page_rc.right, rc.bottom);//Use the page_rc to figure out the width of the line 
	 
	 
	 
	return; 
} 
 
//Just pass this function a y position to draw the line at. 
//*************************DRAW_LINE_AT************************************ 
void CTreeListPrinting::draw_line_at(CDC *pDC, unsigned int y) 
{ 
	pDC->MoveTo(0, y); 
	pDC->LineTo(page_rc.right, y);//Use the page_rc to figure out the width of the line 
	 
	return; 
} 
 
int CDiskTreeCtrl::DrawLine(CDC* pDC, int nItem, const CRect& rc) 
{ 
	CRect rcBounds(rc); 
	rcBounds.OffsetRect(0,rc.Height()/3); 
	int nLeft = 0; 
	int m_cxImage = rcBounds.Height()/2; 
	int m_cyImage = rcBounds.Height(); 
 
	int nColWidth = GetColumnWidth(0); 
	int nOffset = (rcBounds.Height() - m_cyImage) >> 1; 	 
	 
	CPen psPen(PS_SOLID, 1, RGB(192,192,192)); 
    CPen* pOldPen = pDC->SelectObject(&psPen); 
 
	CTreeItem *pSelItem = reinterpret_cast(GetItemData(nItem)); 
	CTreeItem* pRoot = GetRootItem(); 
	int iIndent = GetIndent(pSelItem); 
	//setup plus/minus rectangle 
	int nHalfImage = (m_cxImage >> 1);	 
	int yDown = rcBounds.top; 
	int nBottomDown = yDown + nHalfImage+nOffset; 
	 
	SIZE right_bottom = {(m_cxImage>>1)+2+1, (m_cyImage>>1)+2+1};//from ANDY : the '+ 1' is to center the [+] or [-]  
	int left = rcBounds.left  + GetIndent(pSelItem) * m_cxImage - nHalfImage; 
	 
	int top = nBottomDown - (right_bottom.cy >> 1); 
	POINT left_top = {left -  (right_bottom.cx >> 1), top}; 
	 
	BOOL bChild = ItemHasChildren(pSelItem); 
	BOOL bCollapsed = IsCollapsed(pSelItem); 
	//draw outline	 
	 
	while(pRoot != pSelItem) 
	{ 
		CTreeItem* pParent = GetParentItem(pSelItem); 
		POSITION pos = pParent->m_listChild.GetTailPosition(); 
		while(pos!=NULL) 
		{ 
			CTreeItem *pLastChild = (CTreeItem*)pParent->m_listChild.GetPrev(pos); 
			int nIndex = GetCurIndex(pLastChild); 
			//no drawing outside the 1st columns right 
			int xLine =  rcBounds.left + GetIndent(pLastChild) * m_cxImage - nHalfImage; 
			if(nIndex == nItem && (GetIndent(pLastChild)==iIndent)) 
			{ 
				//draw '- 
				int x; 
				pDC->MoveTo(xLine, yDown); 
				pDC->LineTo(xLine, nBottomDown); 
				// - 
				xLine + nHalfImage > nColWidth ? x = nColWidth: x = xLine + nHalfImage; 
				 
				pDC->MoveTo(xLine, nBottomDown); 
				pDC->LineTo(x, nBottomDown); 
 
				nLeft += nHalfImage; 
				break; 
			} 
			else 
			if(nIndex > nItem && (GetIndent(pLastChild)==iIndent)) 
			{ 
				//draw |- 
				int x; 
				xLine + nHalfImage > nColWidth ? x = nColWidth : x = xLine + nHalfImage; 
				pDC->MoveTo(xLine, nBottomDown); 
				pDC->LineTo(x, nBottomDown); 
				//- 
				pDC->MoveTo(xLine, yDown); 
				pDC->LineTo(xLine, rcBounds.bottom); 
 
				nLeft += nHalfImage; 
				break; 
			} 
			else 
			if(nIndex > nItem && (GetIndent(pLastChild) < iIndent)) 
			{ 
				//draw | 
				pDC->MoveTo(xLine, yDown); 
				pDC->LineTo(xLine, rcBounds.bottom); 
 
				nLeft += nHalfImage; 
				break; 
			}else 
				nLeft += nHalfImage; 
 
		}			 
		pSelItem = pParent;//next 
	} 
	//draw plus/minus sign 
	if(bChild) 
	{ 
		//erase bkgrnd 
		CRect rcBounds(left_top, right_bottom); 
		pDC->FillRect(rcBounds, &CBrush(RGB(255,255,255))); 
		//draw rectangle	 
		pDC->Rectangle(rcBounds); 
		//draw plus/minus sign 
		int topdown = nBottomDown; 
		if(bCollapsed) 
		{ 
			//plus 
			pDC->MoveTo(left, topdown-2); 
			pDC->LineTo(left, topdown+3); 
			//	 
			pDC->MoveTo(left-2, topdown); 
			pDC->LineTo(left+3, topdown); 
		} 
		else { 
			//minus  
			pDC->MoveTo(left-2, topdown); 
			pDC->LineTo(left+3, topdown); 
			int nOffset = (rcBounds.Height() - m_cyImage)/2; 
			pDC->MoveTo(left+ m_cxImage, rcBounds.top + m_cyImage+(nOffset/2)); 
			pDC->LineTo(left + m_cxImage, rcBounds.bottom); 
		} 
	} 
	pDC->SelectObject(pOldPen); 
	 
	return iIndent*nHalfImage*2+nHalfImage; 
	/*int nOffset=0; 
	int nOffsetWidth = 8; 
 
	CTreeItem* pRoot = GetRootItem(); 
 
	CTreeItem *pParent = reinterpret_cast(GetItemData(nItem)); 
	CTreeItem *pItem = pParent; 
 
	CItemInfo* lp = GetData(pItem); 
	 
	int iIndent = GetIndent(pItem); 
	int nListItem = GetCurIndex(pItem); 
	CTreeItem *pSelItem = pItem; 
	while(pRoot != pSelItem) 
	{ 
		CTreeItem* pParent = GetParentItem(pSelItem); 
		POSITION pos = pParent->m_listChild.GetTailPosition(); 
		while(pos!=NULL) 
		{ 
			CTreeItem *pLastChild = (CTreeItem*)pParent->m_listChild.GetPrev(pos); 
			int nIndex = GetCurIndex(pLastChild); 
			//no drawing outside the 1st columns right 
			if (nIndex == nListItem && (GetIndent(pLastChild)==iIndent)) 
			{ 
				pDC->MoveTo(rc.left + nOffset, (rc.bottom-rc.top)/2 + rc.top); 
				pDC->LineTo(rc.left + nOffset + nOffsetWidth, (rc.bottom-rc.top)/2 + rc.top); 
 
				nOffset += nOffsetWidth; 
				 
				break; 
			} 
			else if(nIndex > nListItem && (GetIndent(pLastChild)==iIndent)) 
			{ 
				//draw |- 
				pDC->MoveTo(rc.left + nOffset, rc.top); 
				pDC->LineTo(rc.left + nOffset, rc.bottom); 
				 
				pDC->MoveTo(rc.left + nOffset, (rc.bottom-rc.top)/2 + rc.top); 
				pDC->LineTo(rc.left + nOffset + nOffsetWidth, (rc.bottom-rc.top)/2 + rc.top); 
 
				nOffset += nOffsetWidth; 
 
				 
				break; 
			} 
			else if(nIndex > nListItem && (GetIndent(pLastChild) < iIndent)) 
			{ 
				//draw | 
				pDC->MoveTo(rc.left + nOffset, rc.top); 
				pDC->LineTo(rc.left + nOffset, rc.bottom); 
 
				nOffset += nOffsetWidth; 
				 
				break; 
			}else 
			{ 
				nOffset += nOffsetWidth; 
				break; 
			} 
		}			 
		pSelItem = pParent;//next 
	} 
	 
	return nOffset;*/ 
}