www.pudn.com > ExtListctrl_new000.rar > ExtListCtrl.cpp


// ExtListCtrl.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "ExtListCtrl.h" 
#include "Ext.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
#define MUST_STYLE		  (WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL) 
#define MUST_NOT_STYLE	  (LVS_EDITLABELS | LVS_REPORT | LVS_ICON | LVS_SMALLICON | LVS_LIST | LVS_NOSCROLL) 
 
#define MUST_EX_STYLE     (LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES) 
#define MUST_NOT_EX_STYLE (0) 
 
///////////////////////////////////////////////////////////////////////////// 
// CExtListCtrl 
 
CExtListCtrl::CExtListCtrl() 
{ 
	m_pWndEdit   = new CEdit; 
	m_bEditable  = TRUE; 
	m_ptEdit.x   = -1; 
	m_ptEdit.y   = -1; 
	m_nSortedColumn  = 0; 
	m_bSortAscending = TRUE; 
	m_bSortable      = TRUE; 
	m_nCompareAs     = ELCT_STRING_CASE; 
} 
 
CExtListCtrl::~CExtListCtrl() 
{ 
	m_Font.DeleteObject(); 
 
	if (m_pWndEdit != NULL) 
		delete m_pWndEdit; 
} 
 
BEGIN_MESSAGE_MAP(CExtListCtrl, CListCtrl) 
	//{{AFX_MSG_MAP(CExtListCtrl) 
	ON_WM_CREATE() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONDBLCLK() 
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick) 
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw) 
	ON_WM_DESTROY() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
int CExtListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CListCtrl::OnCreate(lpCreateStruct) == -1) 
		return -1; 
 
	return 0; 
} 
 
void CExtListCtrl::OnDestroy()  
{ 
	m_pWndEdit->DestroyWindow(); 
 
	for (int i = 0; i < GetItemCount(); i++) 
		_FreeItemMemory(i); 
 
	CListCtrl::OnDestroy(); 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CExtListCtrl message handlers 
 
BOOL CExtListCtrl::_GetHeaderColumn() 
{ 
	return (GetStyle() & LVS_NOCOLUMNHEADER) == 0; 
} 
 
int CExtListCtrl::_GetHeaderFMT(int nCol) 
{ 
	if (!_GetHeaderColumn()) 
		return HDF_LEFT; 
 
	HDITEM hdItem; 
	hdItem.mask = HDI_FORMAT; 
 
	if (!GetHeaderCtrl()->GetItem(nCol, &hdItem)) 
		return HDF_LEFT; 
 
	return hdItem.fmt; 
} 
 
UINT CExtListCtrl::_GetItemFMT(int nItem, int nSubItem) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem != NULL) 
		return pItem->nFormat[nSubItem]; 
	return DT_LEFT; 
} 
 
DWORD CExtListCtrl::_AllocItemMemory(int nItem) 
{ 
    if (nItem < 0 || nItem > GetItemCount()) 
		return EXT_INVALIDINDEX; 
 
	int nCols = GetColumnCount(); 
	if (nCols == 0) 
		nCols = 1; 
 
	EXT_ITEM *pItem = new EXT_ITEM; 
	pItem->dwData  = CListCtrl::GetItemData(nItem); 
	pItem->bModify = FALSE; 
	pItem->lpszItemEx.SetSize(nCols); 
	pItem->crTxColor.SetSize(nCols); 
	pItem->crBkColor.SetSize(nCols); 
	pItem->nChecked.SetSize(nCols); 
	pItem->nFormat.SetSize(nCols); 
 
	for (int i = 0; i < nCols; i++) 
	{ 
	    pItem->crTxColor[i] = GetSysColor(COLOR_WINDOWTEXT); 
	    pItem->crBkColor[i] = GetSysColor(COLOR_WINDOW); 
		pItem->nChecked[i]  = -1; 
		pItem->nFormat[i]   = DT_LEFT; 
	} 
 
	CListCtrl::SetItemData(nItem, (DWORD)pItem); 
 
	return EXT_SUCCESS; 
} 
 
void CExtListCtrl::_FreeItemMemory(int nItem) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem) 
		delete pItem; 
} 
 
void CExtListCtrl::_UpdateColumn(int nCol, BOOL bInsert) 
{ 
	for (int i = 0; i < GetItemCount(); i++) 
	{ 
		EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(i); 
		if (!pItem) 
			continue; 
 
		if (bInsert) 
		{ 
			pItem->lpszItemEx.InsertAt(nCol, ""); 
			pItem->crBkColor.InsertAt(nCol, GetSysColor(COLOR_WINDOW)); 
			pItem->crTxColor.InsertAt(nCol, GetSysColor(COLOR_WINDOWTEXT)); 
			pItem->nChecked.InsertAt(nCol, 0); 
		} 
		else 
		{ 
			pItem->lpszItemEx.RemoveAt(nCol); 
			pItem->crBkColor.RemoveAt(nCol); 
			pItem->crTxColor.RemoveAt(nCol); 
			pItem->nChecked.RemoveAt(nCol); 
		} 
	} 
} 
 
void CExtListCtrl::_MouseClkMonitor(UINT nMsg, UINT nFlags, CPoint point, BOOL bTriggerEdit) 
{ 
	_EndEdit(TRUE); 
 
	LVHITTESTINFO hti; 
	hti.pt = point; 
	const int IDX = SubItemHitTest(&hti); 
 
	if (IDX == -1) 
		return; 
 
	switch (nMsg) 
	{ 
	case WM_LBUTTONDOWN: 
		CListCtrl::OnLButtonDown(nFlags, point); 
		break; 
 
	case WM_LBUTTONDBLCLK: 
		CListCtrl::OnLButtonDblClk(nFlags, point); 
		break; 
 
	case WM_MBUTTONDOWN: 
		CListCtrl::OnMButtonDown(nFlags, point); 
		break; 
 
	case WM_MBUTTONDBLCLK: 
		CListCtrl::OnMButtonDblClk(nFlags, point); 
		break; 
 
	case WM_RBUTTONDOWN: 
		CListCtrl::OnRButtonDown(nFlags, point); 
		break; 
 
	case WM_RBUTTONDBLCLK: 
		CListCtrl::OnRButtonDblClk(nFlags, point); 
		break; 
 
	default: 
		break; 
	} 
 
	_ItemCheckMonitor(nMsg, IDX, hti.iSubItem); 
 
	if (!bTriggerEdit) 
		return; 
 
	_StartEdit(IDX, hti.iSubItem); 
} 
 
void CExtListCtrl::_ItemCheckMonitor(UINT nMsg, int nItem, int nSubItem) 
{ 
	if (nMsg != WM_LBUTTONDOWN) 
		return; 
 
	int nChecked = _GetCheck(nItem, nSubItem); 
	if (nChecked != -1) 
	    SetCheck(nItem, nSubItem, !nChecked); 
} 
 
void CExtListCtrl::_StartEdit(int nItem, int nSubItem) 
{ 
	//第一列允许编辑 
	if (!m_bEditable ||  
	    nItem < 0 || nItem >= GetItemCount() || 
	    nSubItem < 0 || nSubItem == 0 || nSubItem >= GetColumnCount()) 
		return; 
 
	if (m_ptEdit.x == nItem && m_ptEdit.y == nSubItem) 
		return; 
 
	m_ptEdit.x = nItem; 
	m_ptEdit.y = nSubItem; 
 
	if (m_pWndEdit->GetSafeHwnd() != NULL) 
		m_pWndEdit->DestroyWindow(); 
 
	int nFMT = _GetHeaderFMT(nSubItem); 
 
	if (nFMT & HDF_CENTER)	 
		nFMT = ES_CENTER; 
	else if (nFMT & HDF_RIGHT) 
		nFMT = ES_RIGHT; 
	else 
		nFMT = ES_LEFT; 
 
	if (!m_pWndEdit->Create(WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | ES_NOHIDESEL | nFMT, CRect(0, 0, 1, 1), this, 0)) 
		return; 
 
	m_pWndEdit->SetFont(GetFont()); 
 
	CRect rcEdit; 
	GetSubItemRect(m_ptEdit.x, m_ptEdit.y, LVIR_LABEL, rcEdit); 
	//ListView_GetSubItemRect(GetSafeHwnd(), m_ptEdit.x, m_ptEdit.y, LVIR_LABEL, &rcEdit); 
 
	if (m_ptEdit.y > 0 && GetItemImage(m_ptEdit.x, m_ptEdit.y) != -1) 
		rcEdit.DeflateRect(16, 0, 0, 0); 
 
	m_pWndEdit->MoveWindow(&rcEdit); 
	m_pWndEdit->SetWindowText(GetItemText(m_ptEdit.x, m_ptEdit.y)); 
	m_pWndEdit->ShowWindow(SW_SHOW); 
	m_pWndEdit->SetSel(0, -1); 
	m_pWndEdit->SetFocus(); 
} 
 
void CExtListCtrl::_EndEdit(BOOL bCommit) 
{ 
	if (m_ptEdit.x < 0 && m_ptEdit.y < 0) 
		return; 
 
	CString str; 
	m_pWndEdit->GetWindowText(str); 
 
	BOOL bChanged = bCommit && str.Compare(GetItemText(m_ptEdit.x, m_ptEdit.y)) != 0; 
	if (bChanged) 
		SetItemText(m_ptEdit.x, m_ptEdit.y, str, _GetItemFMT(m_ptEdit.x, m_ptEdit.y)); 
 
	m_pWndEdit->ShowWindow(SW_HIDE); 
	m_ptEdit.x = -1; 
	m_ptEdit.y = -1; 
} 
/*======================================================================== 
	Name:		QuickSort(). 
	----------------------------------------------------------- 
	Params:		[p]:     start position, usually index 0. 
                [q]:     end position, usually last index. 
==========================================================================*/ 
void CExtListCtrl::_QuickSort(int p, int r) 
{ 
	if (p < r) 
	{ 
        int q = _Partition(p, r); 
        _QuickSort(p, q); 
        _QuickSort(q + 1, r); 
	} 
} 
/*======================================================================== 
	Name:		Partition(). 
	----------------------------------------------------------- 
	Params:		[p]:     start position. 
                [q]:     end position. 
==========================================================================*/ 
int CExtListCtrl::_Partition(int p, int r) 
{ 
	CString tmp; 
    CString x = GetItemText(p, m_nSortedColumn); 
    int i = p - 1; 
    int j = r + 1; 
 
    while (i < j) 
    { 
        do 
        { 
            j--; 
            tmp = GetItemText(j,  m_nSortedColumn); 
        } while (_CompareBy(tmp, x, m_bSortAscending ? ELOT_GT : ELOT_LT)); 
 
        do 
        { 
            i++; 
            tmp = GetItemText(i, m_nSortedColumn); 
        } while (_CompareBy(tmp, x, m_bSortAscending ? ELOT_LT : ELOT_GT)); 
 
        if (i < j) 
        { 
            _SwapRow(i, j); 
        } 
    } 
 
    return j; 
} 
/*======================================================================== 
	Name:		Swap nRow1 with nRow2. 
	----------------------------------------------------------- 
	Params:		[nRow1]:     row index (zero based). 
                [nRow2]:     row index (zero based). 
				[op]:       operator type 
    return: 
	            TRUE if successful, else FALSE 
==========================================================================*/ 
BOOL CExtListCtrl::_SwapRow(int nRow1, int nRow2) 
{ 
    int nMaxRows = GetItemCount(); 
 
    if ((nRow1 >= 0) && (nRow1 < nMaxRows) && 
        (nRow2 >= 0) && (nRow2 < nMaxRows) && 
        (nRow1 != nRow2)) 
    { 
        const int nCol = GetColumnCount(); 
 
		EXT_SORT *pSort = new EXT_SORT[2]; 
 
		for (int i = 0; i < 2; i++) 
		{ 
			int nRow = (i == 0 ? nRow1 : nRow2); 
 
			pSort[i].dwData = CListCtrl::GetItemData(nRow); 
			pSort[i].nState = GetItemState(nRow); 
		    pSort[i].lpszItem.SetSize(nCol); 
		    pSort[i].lpszItemEx.SetSize(nCol); 
		    pSort[i].nImage.SetSize(nCol); 
	    	pSort[i].nChecked.SetSize(nCol); 
			pSort[i].nFormat.SetSize(nCol); 
 
			for (int j = 0; j < nCol; j++) 
			{ 
				pSort[i].lpszItem[j]   = GetItemText(nRow, j); 
				pSort[i].lpszItemEx[j] = GetItemTextEx(nRow, j); 
				pSort[i].nImage[j]     = GetItemImage(nRow, j); 
				pSort[i].nChecked[j]   = _GetCheck(nRow, j); 
				pSort[i].nFormat[j]    = _GetItemFMT(nRow, j); 
			} 
		} 
 
		for (i = 0; i < 2; i++) 
		{ 
			int nRow = (i == 0 ? nRow2 : nRow1); 
 
			CListCtrl::SetItemData(nRow, pSort[i].dwData); 
			SetItemState(nRow, pSort[i].nState, TRUE); 
 
			for (int j = 0; j < nCol; j++) 
			{ 
				SetItemText(nRow, j, pSort[i].lpszItem[j], pSort[i].nFormat[j]); 
				SetItemTextEx(nRow, j, pSort[i].lpszItemEx[j]); 
				SetItemImage(nRow, j, pSort[i].nImage[j]); 
				if (pSort[i].nChecked[j] != -1) 
				    SetCheck(nRow, j, pSort[i].nChecked[j]);  
			} 
		} 
 
		delete[] pSort; 
    } 
 
    return TRUE; 
} 
/*======================================================================== 
	Name:		Convert strings to new data type based on m_nCompareAs' 
                value. Compare the strings using the operator. 
	----------------------------------------------------------- 
	Params:		[str1]:     string 1 (left operand). 
                [str2]:     string 2 (right operand). 
				[op]:       operator type 
    return: 
	            The result of (str1 op str2) 
==========================================================================*/ 
BOOL CExtListCtrl::_CompareBy(CString str1, CString str2, ListOperatorType op) 
{ 
	BOOL bReturn = FALSE; 
 
    switch (m_nCompareAs) 
    { 
        case ELCT_INTEGER: 
        { 
            int val1 = atoi(str1); 
            int val2 = atoi(str2); 
 
            if (op == ELOT_LT) 
                bReturn =  (val1 < val2); 
            else if (op == ELOT_GT) 
                bReturn =  (val1 > val2); 
            else if (op == ELOT_LTE) 
                bReturn =  (val1 <= val2); 
            else if (op == ELOT_GTE) 
                bReturn =  (val1 >= val2); 
            else 
                bReturn =  (val1 == val2); 
            break; 
        } 
        case ELCT_DOUBLE: 
        { 
            double val1 = atof(str1); 
            double val2 = atof(str2); 
 
            if (op == ELOT_LT) 
                bReturn =  (val1 < val2); 
            else if (op == ELOT_GT) 
                bReturn =  (val1 > val2); 
            else if (op == ELOT_LTE) 
                bReturn =  (val1 <= val2); 
            else if (op == ELOT_GTE) 
                bReturn =  (val1 >= val2); 
            else 
                bReturn =  (val1 == val2); 
            break; 
        } 
        case ELCT_STRING_NOCASE: 
        { 
            str1.MakeUpper(); 
            str2.MakeUpper(); 
        } 
        case ELCT_STRING_CASE: 
        default: 
        { 
            if (op == ELOT_LT) 
                bReturn =  (str1 < str2); 
            else if (op == ELOT_GT) 
                bReturn =  (str1 > str2); 
            else if (op == ELOT_LTE) 
                bReturn =  (str1 <= str2); 
            else if (op == ELOT_GTE) 
                bReturn =  (str1 >= str2); 
            else 
                bReturn =  (str1 == str2); 
            break; 
        } 
    } 
 
    return bReturn; 
} 
/*======================================================================== 
	Name:		set view style. 
	----------------------------------------------------------- 
	Params:		[style]:     view style.   
	                 [LVS_ICON] 
					 [LVS_SMALLICON] 
					 [LVS_LIST] 
					 [LVS_REPORT] 
					 [LVS_EDITLABELS] 
==========================================================================*/ 
LONG CExtListCtrl::SetStyle(DWORD dwStyle) 
{ 
	LONG style; 
 
	style  = ::GetWindowLong(m_hWnd, GWL_STYLE); 
	style &= ~LVS_TYPEMASK; 
	style |= dwStyle; 
 
	return SetWindowLong(m_hWnd, GWL_STYLE, style); 
} 
 
LONG CExtListCtrl::GetStyle() 
{ 
	return ::GetWindowLong(m_hWnd, GWL_STYLE); 
} 
 
LONG CExtListCtrl::_GetStyle() 
{ 
	LONG style = GetStyle() & LVS_ICON; //0 
	style = GetStyle() & LVS_REPORT;    //1 
	style = GetStyle() & LVS_SMALLICON; //2 
	style = GetStyle() & LVS_LIST;      //3 
	return style; 
} 
 
DWORD CExtListCtrl::SetExtendedStyle(DWORD dwNewStyle) 
{ 
	dwNewStyle &= ~MUST_NOT_EX_STYLE; 
	dwNewStyle |= MUST_EX_STYLE; 
	return CListCtrl::SetExtendedStyle(dwNewStyle); 
} 
 
DWORD CExtListCtrl::GetExtendedStyle() 
{ 
	return CListCtrl::GetExtendedStyle(); 
} 
 
BOOL CExtListCtrl::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags) 
{ 
	return CListCtrl::ModifyStyle(dwRemove, dwAdd, nFlags); 
} 
 
BOOL CExtListCtrl::ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags) 
{ 
	return CListCtrl::ModifyStyleEx(dwRemove, dwAdd, nFlags); 
} 
 
void CExtListCtrl::Modify(int nItem, BOOL bModify) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return; 
	pItem->bModify = bModify; 
} 
 
BOOL CExtListCtrl::ItemModified(int nItem) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return FALSE; 
	return pItem->bModify; 
} 
 
int CExtListCtrl::InsertColumn(int nCol, const LVCOLUMN* pColumn) 
{ 
	const int IDX = CListCtrl::InsertColumn(nCol, pColumn); 
	if (IDX >= 0) 
		_UpdateColumn(nCol, TRUE); 
	return IDX; 
} 
 
int CExtListCtrl::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nWidth, int nFormat, int nSubItem) 
{ 
	const int IDX = CListCtrl::InsertColumn(nCol, lpszColumnHeading, nFormat, nWidth, nSubItem); 
	if (IDX >= 0) 
		_UpdateColumn(nCol, TRUE); 
	return IDX; 
} 
 
void CExtListCtrl::SetEditable(BOOL bEditable) 
{ 
	m_bEditable = bEditable; 
} 
 
void CExtListCtrl::SetSortable(BOOL bSortable) 
{ 
	m_bSortable = bSortable; 
} 
 
BOOL CExtListCtrl::DeleteColumn(int nCol) 
{ 
	_EndEdit(FALSE); 
 
	const BOOL bFlag = CListCtrl::DeleteColumn(nCol); 
	if (bFlag) 
		_UpdateColumn(nCol, FALSE); 
	return bFlag; 
} 
 
void CExtListCtrl::DeleteAllColumns() 
{ 
	while (GetColumnCount() > 0) 
		DeleteColumn(0); 
} 
 
CHeaderCtrl* CExtListCtrl::GetHeaderCtrl() const 
{ 
	return (CHeaderCtrl*)(CWnd::FromHandle(ListView_GetHeader(GetSafeHwnd()))); 
} 
 
int CExtListCtrl::GetColumnCount() 
{ 
	if (GetStyle() & LVS_REPORT) 
	    return GetHeaderCtrl()->GetItemCount(); 
	return 0; 
} 
 
BOOL CExtListCtrl::EnsureVisible(int nItem, BOOL bPartialOK) 
{ 
	//SetItemState(nItem, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED); 
	return CListCtrl::EnsureVisible(nItem, bPartialOK); 
} 
 
int CExtListCtrl::InsertItem() 
{ 
	int nItem = GetItemCount(); 
	nItem = (nItem == 0 ? 0 : nItem); 
	return InsertItem(nItem, ""); 
} 
 
int CExtListCtrl::InsertItem(const LVITEM* pItem) 
{ 
	const int IDX = CListCtrl::InsertItem(pItem); 
 
	if (IDX >= 0) 
		_AllocItemMemory(IDX); 
 
	//EnsureVisible(IDX, FALSE); 
 
	return IDX; 
} 
 
int CExtListCtrl::InsertItem(int nItem, LPCTSTR lpszItem, int nImage) 
{ 
	const int IDX = (nImage == -1 ? CListCtrl::InsertItem(nItem, lpszItem) :  
	                                CListCtrl::InsertItem(nItem, lpszItem, nImage)); 
 
	if (IDX >= 0) 
		_AllocItemMemory(IDX); 
 
	//EnsureVisible(IDX, FALSE); 
 
	return IDX; 
} 
 
int CExtListCtrl::InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask, int nImage, LPARAM lParam) 
{ 
	const int IDX = CListCtrl::InsertItem(nMask, nItem, lpszItem, nState, nStateMask, nImage, lParam); 
 
	if (IDX >= 0) 
		_AllocItemMemory(IDX); 
 
	//EnsureVisible(IDX, FALSE); 
 
	return IDX; 
} 
 
BOOL CExtListCtrl::DeleteItem(int nItem) 
{ 
	_EndEdit(FALSE); 
	if (nItem < 0) return TRUE; 
	SetItemState(nItem - 1, LVIS_SELECTED|LVIS_FOCUSED); 
	_FreeItemMemory(nItem); 
	return CListCtrl::DeleteItem(nItem); 
} 
 
BOOL CExtListCtrl::DeleteAllItems() 
{ 
	_EndEdit(FALSE); 
 
	for (int i = 0; i < GetItemCount(); i++) 
		_FreeItemMemory(i); 
	return CListCtrl::DeleteAllItems(); 
} 
 
BOOL CExtListCtrl::SetItemText(int nItem, int nSubItem, LPCTSTR lpszItem, UINT nFormat) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return FALSE; 
	pItem->nFormat[nSubItem] = nFormat; 
	return CListCtrl::SetItemText(nItem, nSubItem, lpszItem); 
} 
 
BOOL CExtListCtrl::SetItemText(int nItem, int nSubItem, INT lpszItem, UINT nFormat) 
{ 
	return SetItemText(nItem, nSubItem, (LONG)lpszItem, nFormat); 
} 
 
BOOL CExtListCtrl::SetItemText(int nItem, int nSubItem, UINT lpszItem, UINT nFormat) 
{ 
	return SetItemText(nItem, nSubItem, (ULONG)lpszItem, nFormat); 
} 
 
BOOL CExtListCtrl::SetItemText(int nItem, int nSubItem, LONG lpszItem, UINT nFormat) 
{ 
	CString strItem; 
	strItem.Format("%d", lpszItem); 
	return SetItemText(nItem, nSubItem, strItem, nFormat); 
} 
 
BOOL CExtListCtrl::SetItemText(int nItem, int nSubItem, ULONG lpszItem, UINT nFormat) 
{ 
	CString strItem; 
	strItem.Format("%u", lpszItem); 
	return SetItemText(nItem, nSubItem, strItem, nFormat); 
} 
 
BOOL CExtListCtrl::SetItemText(int nItem, int nSubItem, DOUBLE lpszItem, int nPrecision, UINT nFormat) 
{ 
	CString strFmt, strItem; 
	strFmt.Format(_T("%%.%df"), nPrecision); 
	strItem.Format(strFmt, lpszItem); 
	return SetItemText(nItem, nSubItem, strItem, nFormat); 
} 
 
BOOL CExtListCtrl::SetItemTextEx(int nItem, int nSubItem, LPCTSTR lpszItem, LPCTSTR lpszItemEx) 
{ 
	return SetItemText(nItem, nSubItem, lpszItem) && SetItemTextEx(nItem, nSubItem, lpszItemEx); 
} 
 
BOOL CExtListCtrl::SetItemTextEx(int nItem, int nSubItem, LPCTSTR lpszItemEx) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return FALSE; 
	pItem->lpszItemEx[nSubItem] = lpszItemEx; 
	return TRUE; 
} 
 
CString CExtListCtrl::GetItemText(int nItem, int nSubItem) 
{ 
	CString value = CListCtrl::GetItemText(nItem, nSubItem); 
	value.TrimLeft(); 
	value.TrimRight(); 
	return value; 
} 
 
CString CExtListCtrl::GetItemTextEx(int nItem, int nSubItem) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return ""; 
	return pItem->lpszItemEx[nSubItem]; 
} 
 
BOOL CExtListCtrl::SetItemImage(int nItem, int nSubItem, int nImage) 
{ 
	return CListCtrl::SetItem(nItem, nSubItem, LVIF_IMAGE, NULL, nImage, 0, 0, 0); 
} 
 
int CExtListCtrl::GetItemImage(int nItem, int nSubItem) 
{ 
	LVITEM lvItem; 
	lvItem.iItem    = nItem; 
	lvItem.iSubItem = nSubItem; 
	lvItem.mask     = LVIF_IMAGE; 
 
	return CListCtrl::GetItem(&lvItem) ? lvItem.iImage : -1; 
} 
 
BOOL CExtListCtrl::SetItemData(int nItem, DWORD dwData) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return FALSE; 
 
	pItem->dwData = dwData; 
	return CListCtrl::SetItemData(nItem, (DWORD)pItem); 
} 
 
DWORD CExtListCtrl::GetItemData(int nItem) const 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	return pItem == NULL ? 0 : pItem->dwData; 
} 
 
void CExtListCtrl::SetBkColor(int nItem, int nSubItem, COLORREF crColor, BOOL bRedraw) 
{ 
	const int nRows = GetItemCount(); 
	const int nCols = GetColumnCount(); 
	BOOL bRow = (nItem >= 0 && nItem < nRows); 
	BOOL bCol = (nSubItem >= 0 && nSubItem < nCols); 
 
	if (bRow && bCol) 
	{ 
		EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
		ASSERT(pItem != NULL); 
		pItem->crBkColor[nSubItem] = crColor; 
	} 
	else if (bRow && !bCol) 
	{ 
		EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
		ASSERT(pItem != NULL); 
		for (int i = 0; i < nCols; i++) 
			pItem->crBkColor[i] = crColor; 
	} 
	else if (!bRow && bCol) 
	{ 
		for (int i = 0; i < nRows; i++) 
		{ 
			EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(i); 
			ASSERT(pItem != NULL); 
			pItem->crBkColor[nSubItem] = crColor; 
		} 
	} 
	else 
	{ 
		for (int i = 0; i < nRows; i++) 
		{ 
			EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(i); 
			ASSERT(pItem != NULL); 
			for (int j = 0; j < nCols; j++) 
			    pItem->crBkColor[j] = crColor; 
		} 
	} 
	if (bRedraw) /* bRedraw=true,记录多时,闪烁厉害 */ 
		RedrawWindow(); 
} 
 
void CExtListCtrl::SetTextColor(int nItem, int nSubItem, COLORREF crColor, BOOL bRedraw) 
{ 
	const int nRows = GetItemCount(); 
	const int nCols = GetColumnCount(); 
	BOOL bRow = (nItem >= 0 && nItem < nRows); 
	BOOL bCol = (nSubItem >= 0 && nSubItem < nCols); 
 
	if (bRow && bCol) 
	{ 
		EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
		ASSERT(pItem != NULL); 
		pItem->crTxColor[nSubItem] = crColor; 
	} 
	else if (bRow && !bCol) 
	{ 
		EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
		ASSERT(pItem != NULL); 
		for (int i = 0; i < nCols; i++) 
			pItem->crTxColor[i] = crColor; 
	} 
	else if (!bRow && bCol) 
	{ 
		for (int i = 0; i < nRows; i++) 
		{ 
			EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(i); 
			ASSERT(pItem != NULL); 
			pItem->crTxColor[nSubItem] = crColor; 
		} 
	} 
	else 
	{ 
		for (int i = 0; i < nRows; i++) 
		{ 
			EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(i); 
			ASSERT(pItem != NULL); 
			for (int j = 0; j < nCols; j++) 
			    pItem->crTxColor[j] = crColor; 
		} 
	} 
	if (bRedraw)/* bRedraw=true,记录多时,闪烁厉害 */ 
		RedrawWindow(); 
} 
 
BOOL CExtListCtrl::SetItemState(int nItem, UINT nState, BOOL bState) 
{ 
	UINT nMask = (nState == 0 ? LVIS_SELECTED|LVIS_FOCUSED : nState); 
	nState = !bState ? 0 : nState; 
	return CListCtrl::SetItemState(nItem, nState, nMask); 
} 
 
UINT CExtListCtrl::GetItemState(int nItem) 
{ 
	UINT nState = 0; 
 
	nState |= CListCtrl::GetItemState(nItem, LVIS_CUT); 
	nState |= CListCtrl::GetItemState(nItem, LVIS_DROPHILITED); 
	nState |= CListCtrl::GetItemState(nItem, LVIS_SELECTED); 
	nState |= CListCtrl::GetItemState(nItem, LVIS_FOCUSED); 
 
	return nState; 
} 
 
BOOL CExtListCtrl::SetCheck(int nItem, int nSubItem, BOOL bChecked) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return FALSE; 
	pItem->nChecked[nSubItem] = (bChecked ? 1 : 0); 
 
	CRect rcItem; 
	GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rcItem); 
	InvalidateRect(rcItem); 
 
	return TRUE; 
} 
 
BOOL CExtListCtrl::GetCheck(int nItem, int nSubItem) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return FALSE; 
	return pItem->nChecked[nSubItem] == 1 ? TRUE : FALSE; 
} 
 
int CExtListCtrl:: _GetCheck(int nItem, int nSubItem) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return FALSE; 
	return pItem->nChecked[nSubItem]; 
} 
 
int CExtListCtrl::GetSelectedItem() 
{ 
	for (int i = 0; i < GetItemCount(); i++) 
	{ 
		if (GetItemState(i) & LVIS_SELECTED) 
			return i; 
	} 
	return -1; 
} 
 
BOOL CExtListCtrl::SelectItem(int nItem) 
{ 
	EnsureVisible(nItem, FALSE); 
	return SetItemState(nItem, LVIS_SELECTED|LVIS_FOCUSED, TRUE); 
} 
 
int CExtListCtrl::Find(LPCTSTR lpszItem, int nSubItem, int nBegin) 
{ 
	/* 二分查找算法 */ 
	int nLow  = nBegin; 
	int nHigh = GetItemCount() - 1; 
	while (nLow <= nHigh) 
	{ 
		int nMid = (nLow + nHigh) / 2; 
		if (GetItemText(nMid, nSubItem) == lpszItem) 
			return nMid; 
		if (GetItemText(nMid, nSubItem) > lpszItem) 
			nHigh = nMid - 1; 
		else 
			nLow = nMid + 1; 
	} 
	return -1; 
} 
 
int CExtListCtrl::FindEx(LPCTSTR lpszItem, int nSubItem, int nBegin) 
{ 
	/* 二分查找算法 */ 
	int nLow  = nBegin; 
	int nHigh = GetItemCount() - 1; 
	while (nLow <= nHigh) 
	{ 
		int nMid = (nLow + nHigh) / 2; 
		EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nMid); 
		if (pItem != NULL) 
		{ 
			if (pItem->lpszItemEx[nSubItem] == lpszItem) 
				return nMid; 
			if (pItem->lpszItemEx[nSubItem] > lpszItem) 
				nHigh = nMid - 1; 
			else 
				nLow = nMid + 1; 
		} 
	} 
	return -1; 
} 
 
BOOL CExtListCtrl::PreCreateWindow(CREATESTRUCT& cs)  
{ 
	return CListCtrl::PreCreateWindow(cs); 
} 
 
void CExtListCtrl::PreSubclassWindow()  
{ 
	// Report 
	LONG lStyle = GetWindowLong(m_hWnd, GWL_STYLE); 
	lStyle |= LVS_REPORT; 
	SetWindowLong(m_hWnd, GWL_STYLE, lStyle); 
 
	// Full select and subitem image. 
	SetExtendedStyle(MUST_EX_STYLE); 
 
	if (!m_pHeader.SubclassWindow(GetDlgItem(0)->GetSafeHwnd())) 
		return; 
 
	NONCLIENTMETRICS ncm; 
    ncm.cbSize = sizeof(NONCLIENTMETRICS); 
    VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));     
    memcpy(&m_Logfont, &(ncm.lfMessageFont), sizeof(LOGFONT)); 
	m_Logfont.lfHeight = 13; 
 
	m_Font.DeleteObject(); 
	m_Font.CreateFontIndirect(&m_Logfont); 
	SetFont(&m_Font); 
 
	CListCtrl::PreSubclassWindow(); 
} 
 
void CExtListCtrl::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	_MouseClkMonitor(WM_LBUTTONDOWN, nFlags, point, FALSE); 
} 
 
void CExtListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)  
{ 
	_MouseClkMonitor(WM_LBUTTONDBLCLK, nFlags, point, TRUE); 
} 
 
BOOL CExtListCtrl::PreTranslateMessage(MSG* pMsg) 
{ 
	if (pMsg->message == WM_KEYDOWN) 
	{ 
		POINT pt = m_ptEdit; 
 
		switch (pMsg->wParam) 
		{ 
		case VK_ESCAPE: 
			_EndEdit(FALSE); 
			return TRUE; 
 
		case VK_RETURN: 
			_EndEdit(TRUE); 
			return TRUE; 
 
		case VK_TAB: 
			if (pt.y == GetItemCount() - 1) 
				pt.y = 0; 
			else 
				pt.y ++; 
			_EndEdit(TRUE); 
			_StartEdit(pt.x, pt.y); 
			return TRUE; 
 
		case VK_UP: 
			if (pt.x > 0)	 
			{ 
				pt.x --; 
				_EndEdit(TRUE); 
				_StartEdit(pt.x, pt.y); 
				EnsureVisible(pt.x, FALSE); 
				return TRUE; 
			} 
			break; 
			 
		case VK_DOWN: 
			if (pt.x < GetItemCount() - 1) 
			{ 
				pt.x ++; 
				_EndEdit(TRUE); 
				_StartEdit(pt.x, pt.y); 
				EnsureVisible(pt.x, FALSE); 
				return TRUE; 
			} 
			break; 
 
		default: 
			break; 
		} 
	} 
	return CListCtrl::PreTranslateMessage(pMsg); 
} 
 
void CExtListCtrl::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; 
 
	if (!m_bSortable) return; 
 
	m_bSortAscending = (pNMListView->iSubItem == m_nSortedColumn) ? !m_bSortAscending : TRUE; 
    m_nSortedColumn  = pNMListView->iSubItem; 
 
	_EndEdit(FALSE); 
	_QuickSort(0, GetItemCount() - 1); 
 
	*pResult = 0; 
} 
 
void CExtListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) 
{ 
	LPNMLVCUSTOMDRAW pLVCD = (LPNMLVCUSTOMDRAW)pNMHDR; 
 
	switch (pLVCD->nmcd.dwDrawStage) 
	{ 
	case CDDS_PREPAINT: // Before the painting cycle begins. 
		{ 
			if (_IsDraw()) 
			{ 
				CDC *pDC = CDC::FromHandle(pLVCD->nmcd.hdc); 
				CRect r(pLVCD->nmcd.rc); 
				_OnDraw(pDC, r); 
			} 
			else 
			{ 
			} 
		} 
		_SwitchTo(pLVCD->nmcd.dwDrawStage, pResult, TRUE); 
		break; 
 
	case CDDS_POSTPAINT: //After the painting cycle is complete. 
		{ 
			if (_IsPostDraw()) 
			{ 
				CDC *pDC = CDC::FromHandle(pLVCD->nmcd.hdc); 
				CRect r(pLVCD->nmcd.rc); 
				_OnPostDraw(pDC, r); 
			} 
			else 
			{ 
			} 
		} 
		break; 
 
	case CDDS_ITEMPREPAINT: // Before an item is drawn. 
		{ 
		    int nItem = pLVCD->nmcd.dwItemSpec; 
 
			if (_IsItemDraw(nItem)) 
			{ 
				CDC *pDC = CDC::FromHandle(pLVCD->nmcd.hdc); 
				_OnItemDraw(pDC, nItem); 
				_SwitchTo(pLVCD->nmcd.dwDrawStage, pResult, FALSE); 
			}	 
			else 
			{ 
				EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
		        pLVCD->clrTextBk = _BKColorFor(nItem, 0, pItem);	 
				pLVCD->clrText   = _TXColorFor(nItem, 0, pItem); 
				 
			} 
			_SwitchTo(pLVCD->nmcd.dwDrawStage, pResult, TRUE); 
		    break; 
		} 
 
	case CDDS_ITEMPREPAINT|CDDS_SUBITEM: 
		{ 
			int nItem    = pLVCD->nmcd.dwItemSpec; 
			int nSubItem = pLVCD->iSubItem; 
 
			if (_IsSubItemDraw(nItem, nSubItem)) 
			{ 
				CDC *pDC = CDC::FromHandle(pLVCD->nmcd.hdc); 
			    _OnSubItemDraw(pDC, nItem, nSubItem); 
				_SwitchTo(pLVCD->nmcd.dwDrawStage, pResult, FALSE); 
			} 
			else 
			{ 
				EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
		        ASSERT(pItem != NULL); 
		        ASSERT(nSubItem >= 0 && nSubItem < pItem->crTxColor.GetSize()); 
				pLVCD->clrTextBk = _BKColorFor(nItem, nSubItem, pItem); 
				pLVCD->clrText   = _TXColorFor(nItem, nSubItem, pItem); 
				_SwitchTo(pLVCD->nmcd.dwDrawStage, pResult, TRUE); 
			} 
		    break; 
		} 
 
	case CDDS_ITEMPOSTPAINT: // After an item has been drawn. 
		{ 
			int nItem    = pLVCD->nmcd.dwItemSpec; 
			if (_IsItemPostDraw(nItem)) 
			{ 
			} 
			else 
			{ 
			} 
		} 
		break; 
 
	case CDDS_ITEMPOSTPAINT|CDDS_SUBITEM: 
		{ 
			int nItem    = pLVCD->nmcd.dwItemSpec; 
			int nSubItem = pLVCD->iSubItem; 
 
			if (_IsSubItemPostDraw(nItem, nSubItem)) 
			{ 
			} 
			else 
			{ 
			} 
		} 
		break; 
	} 
} 
 
void CExtListCtrl::_SwitchTo(DWORD dwDrawStage, LRESULT* pResult, BOOL bDefault) 
{ 
	switch (dwDrawStage) 
	{ 
	case CDDS_PREPAINT: 
		*pResult = CDRF_NOTIFYITEMDRAW; 
		break; 
	case CDDS_POSTPAINT: 
		break; 
	case CDDS_ITEMPREPAINT: 
		{ 
			LONG style = _GetStyle(); 
		    if (style == 0) //LVS_ICON 
				*pResult = bDefault ? CDRF_DODEFAULT : CDRF_SKIPDEFAULT; 
		    else if (style == 1) //LVS_REPORT 
			    *pResult = bDefault ? CDRF_NOTIFYSUBITEMDRAW : CDRF_SKIPDEFAULT; 
		    else if (style == 2) //LVS_SMALLICON 
			    *pResult = bDefault ? CDRF_DODEFAULT : CDRF_SKIPDEFAULT; 
		    else if (style == 3) //LVS_LIST 
			    *pResult = CDRF_SKIPDEFAULT; 
		} 
		break; 
	case CDDS_ITEMPREPAINT|CDDS_SUBITEM: 
		if (bDefault) 
			*pResult = CDRF_DODEFAULT; 
		else 
		    *pResult = CDRF_SKIPDEFAULT; 
		break; 
	case CDDS_ITEMPOSTPAINT: 
		break; 
	case CDDS_ITEMPOSTPAINT|CDDS_SUBITEM: 
		break; 
	} 
} 
 
COLORREF CExtListCtrl::_BKColorFor(int nItem, int nSubItem, EXT_ITEM *pItem) 
{ 
	if (_GetStyle() == 1) //LVS_REPORT 
		return _BKColorForSubItem(nItem, nSubItem, pItem); 
	else 
		return _BKColorForItem(nItem, pItem); 
} 
 
COLORREF CExtListCtrl::_TXColorFor(int nItem, int nSubItem, EXT_ITEM *pItem) 
{ 
	if (_GetStyle() == 1) //LVS_REPORT 
		return _TXColorForSubItem(nItem, nSubItem, pItem); 
	else 
		return _TXColorForItem(nItem, pItem); 
} 
 
COLORREF CExtListCtrl::_BKColorForItem(int nItem, EXT_ITEM *pItem) 
{ 
	if ((GetItemState(nItem) & LVIS_SELECTED) || pItem == NULL) 
		return ::GetSysColor(COLOR_HIGHLIGHT); 
	else 
		return pItem->crBkColor[0]; 
} 
 
COLORREF CExtListCtrl::_TXColorForItem(int nItem, EXT_ITEM *pItem) 
{ 
	if ((GetItemState(nItem) & LVIS_SELECTED) || pItem == NULL) 
		return ::GetSysColor(COLOR_HIGHLIGHTTEXT); 
	else 
		return pItem->crTxColor[0]; 
} 
 
COLORREF CExtListCtrl::_BKColorForSubItem(int nItem, int nSubItem, EXT_ITEM *pItem) 
{ 
	if ((GetItemState(nItem) & LVIS_SELECTED) || pItem == NULL) 
		return ::GetSysColor(COLOR_HIGHLIGHT); 
	else 
		return pItem->crBkColor[nSubItem]; 
} 
 
COLORREF CExtListCtrl::_TXColorForSubItem(int nItem, int nSubItem, EXT_ITEM *pItem) 
{ 
	if ((GetItemState(nItem) & LVIS_SELECTED) || pItem == NULL) 
		return ::GetSysColor(COLOR_HIGHLIGHTTEXT); 
	else 
		return pItem->crTxColor[nSubItem]; 
} 
 
BOOL CExtListCtrl::_IsDraw() 
{ 
	return FALSE; 
} 
 
DWORD CExtListCtrl::_OnDraw(CDC *pDC, const CRect rcItem) 
{ 
	return EXT_SUCCESS; 
} 
 
BOOL CExtListCtrl::_IsPostDraw() 
{ 
	return FALSE; 
} 
 
DWORD CExtListCtrl::_OnPostDraw(CDC *pDC, const CRect rcItem) 
{ 
	return EXT_SUCCESS; 
} 
 
BOOL CExtListCtrl::_IsItemDraw(int nItem) 
{ 
	if (_GetStyle() == 3) //LVS_LIST 
		return TRUE; 
	return FALSE; 
} 
 
DWORD CExtListCtrl::_OnItemDraw(CDC *pDC, int nItem) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return EXT_FAILE; 
 
	CRect rcItem, rcLabel, rcCheck; 
	_CalcRect(nItem, 0, rcItem, rcLabel, rcCheck, pItem); 
 
	pDC->FillSolidRect(rcItem, _BKColorFor(nItem, 0, pItem)); 
 
	_DrawCheckbox(pDC, nItem, 0, rcCheck, pItem); 
	_DrawText(pDC, nItem, 0, rcLabel, pItem); 
	 
	return EXT_SUCCESS; 
} 
 
BOOL CExtListCtrl::_IsItemPostDraw(int nItem) 
{ 
	return FALSE; 
} 
 
DWORD CExtListCtrl::_OnPostDraw(CDC *pDC, int nItem) 
{ 
	return EXT_SUCCESS; 
} 
 
BOOL CExtListCtrl::_IsSubItemDraw(int nItem, int nSubItem) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return FALSE; 
 
	return TRUE; 
} 
 
DWORD CExtListCtrl::_OnSubItemDraw(CDC *pDC, int nItem, int nSubItem) 
{ 
	EXT_ITEM *pItem = (EXT_ITEM*)CListCtrl::GetItemData(nItem); 
	if (pItem == NULL) 
		return EXT_FAILE; 
 
	CRect rcItem, rcLabel, rcCheck; 
	_CalcRect(nItem, nSubItem, rcItem, rcLabel, rcCheck, pItem); 
 
	pDC->FillSolidRect(rcItem, _BKColorFor(nItem, nSubItem, pItem)); 
 
	_DrawCheckbox(pDC, nItem, nSubItem, rcCheck, pItem); 
	_DrawText(pDC, nItem, nSubItem, rcLabel, pItem); 
 
	return EXT_SUCCESS; 
} 
 
BOOL CExtListCtrl::_IsSubItemPostDraw(int nItem, int nSubItem) 
{ 
	return FALSE; 
} 
 
DWORD CExtListCtrl::_OnSubItemPostDraw(CDC *pDC, int nItem, int nSubItem) 
{ 
	return EXT_SUCCESS; 
} 
 
void CExtListCtrl::_CalcRect(int nItem, int nSubItem, CRect &rcItem, CRect &rcLabel, CRect &rcCheck, EXT_ITEM *pItem) 
{ 
	if (_GetStyle() != 1) 
		_CalcItemRect(nItem, rcItem, rcLabel, rcCheck, pItem); 
	else 
		_CalcSubItemRect(nItem, nSubItem, rcItem, rcLabel, rcCheck, pItem); 
} 
 
void CExtListCtrl::_CalcItemRect(int nItem, CRect &rcItem, CRect &rcLabel, CRect &rcCheck, EXT_ITEM *pItem) 
{ 
	// Item rect 
	GetItemRect(nItem, rcItem, LVIR_BOUNDS); 
	 
	CString strTxt = GetItemText(nItem, 0); 
	BOOL bCheck = pItem->nChecked[0] == -1 ? FALSE : TRUE; 
	BOOL bLabel = strTxt.IsEmpty() ? FALSE : TRUE; 
	 
	if (bCheck && !bLabel) 
	{ 
		rcCheck = rcItem; 
		rcCheck.DeflateRect(1, 1); 
	    rcCheck.right = rcCheck.left + rcCheck.Height(); 
	} 
	else if (!bCheck && bLabel) 
	{ 
		rcLabel = rcItem; 
	} 
	else if (bCheck && bLabel) 
	{ 
		rcCheck = rcItem; 
		rcCheck.DeflateRect(1, 1); 
	    rcCheck.right = rcCheck.left + rcCheck.Height(); 
 
		rcLabel = rcItem; 
		rcLabel.left = rcCheck.right + 2; 
	} 
} 
 
void CExtListCtrl::_CalcSubItemRect(int nItem, int nSubItem, CRect &rcItem, CRect &rcLabel, CRect &rcCheck, EXT_ITEM *pItem) 
{ 
	// Item rect 
	GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rcItem); 
	// if nSubItem == 0, the rect returned by CListCtrl::GetSubItemRect 
	// is the entire row, so use left edge of second subitem 
	if (nSubItem == 0 && GetColumnCount() > 1) 
	{ 
		CRect rc; 
		GetSubItemRect(nItem, 1, LVIR_BOUNDS, rc); 
		// if rc.Width() == 0, then rc.left = 0 
		// do not show nSubItem's text. 
		if (rc.Width() != 0) 
		    rcItem.right = rc.left; 
	} 
	// 
	CString strTxt = GetItemText(nItem, nSubItem); 
	BOOL bCheck = pItem->nChecked[nSubItem] == -1 ? FALSE : TRUE; 
	BOOL bLabel = strTxt.IsEmpty() ? FALSE : TRUE; 
	 
	if (bCheck && !bLabel) 
	{ 
		rcCheck = rcItem; 
		rcCheck.DeflateRect(1, 1); 
	    rcCheck.left  = rcItem.left + rcItem.Width()/2 - 6; 
	    rcCheck.right = rcCheck.left + rcCheck.Height(); 
	} 
	else if (!bCheck && bLabel) 
	{ 
		rcLabel = rcItem; 
		//rcLabel.left += 4; 
	} 
	else if (bCheck && bLabel) 
	{ 
		rcCheck = rcItem; 
		rcCheck.DeflateRect(1, 1); 
	    rcCheck.left  = rcItem.left + 6; 
	    rcCheck.right = rcCheck.left + rcCheck.Height(); 
 
		rcLabel = rcItem; 
		rcLabel.left = rcCheck.right + 4; 
	} 
} 
 
DWORD CExtListCtrl::_DrawText(CDC *pDC, int nItem, int nSubItem, CRect rcLabel, EXT_ITEM *pItem) 
{ 
	CString str = GetItemText(nItem, nSubItem); 
	if (str.IsEmpty()) 
		return EXT_SUCCESS; 
 
	UINT nFMT = pItem->nFormat[nSubItem]; 
	switch (nFMT) 
	{ 
	case DT_LEFT: 
		rcLabel.left += 6; break; 
	case DT_CENTER: 
		rcLabel.left += 0; break; 
	case DT_RIGHT: 
		rcLabel.right -= 6; break; 
	} 
 
	pDC->SetBkMode(TRANSPARENT); 
	pDC->SetTextColor(_TXColorFor(nItem, nSubItem, pItem)); 
	pDC->DrawText(str, rcLabel, DT_VCENTER|DT_SINGLELINE|nFMT); 
 
	return EXT_SUCCESS; 
} 
 
DWORD CExtListCtrl::_DrawCheckbox(CDC *pDC, int nItem, int nSubItem, CRect rcCheck, EXT_ITEM *pItem) 
{ 
	if (pItem->nChecked[nSubItem] == -1) 
		return EXT_SUCCESS; 
 
	pDC->Draw3dRect(rcCheck, GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW)); 
 
	if (pItem->nChecked[nSubItem] == 0) 
		return EXT_SUCCESS; 
 
	CPen newPen(PS_SOLID, 1, RGB(0,0,0)); 
    CPen *oldPen = pDC->SelectObject(&newPen); 
	for (int i = 0; i < 3; i++) 
	{ 
		pDC->MoveTo(rcCheck.left + 2, rcCheck.top + 5 + i); 
	    pDC->LineTo(rcCheck.left + 4, rcCheck.top + 7 + i); 
	    pDC->LineTo(rcCheck.left + 10, rcCheck.top + 1 + i); 
	} 
	pDC->SelectObject(oldPen); 
 
	return EXT_SUCCESS; 
}