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;*/
}