www.pudn.com > superlistctrl.rar > supergridctrl.cpp


// SuperGridCtrl.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "SuperGrid.h" 
#include "SuperGridCtrl.h" 
#include "ListEditCtrl.h" 
 
 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
/* 
 
    SuperGrid, YALC (yet another listview control)  
 
	Written by me(Allan Nielsen), that is .. if the code works :) 
		mailto:winallan@post10.tele.dk 
 
	Copyright (c) 1998. 
 
	If you find bugs, please notify me and I'll contact the author who wrote the darn thing :) 
	 
    You may use it, abuse it, redistribute it, in any way you desire, but 
	if you choose to use this control in any commercial or non commercial application then please  
	send me an email letting me know, makes me :) .  
	 
 
	HISTORY (that's new allright) 
 
	what's new since last update: 4 dec. 1998. 
	 
				- MeasureItem now uses current font	 
				- Combobox support in CItemInfo				 
				  see the ShowList in MySuperGrid.h/cpp, PreTranslateMessage functions 
				  and the file ComboInListView.cpp/h 
                - function to indicate the precens of a combobox it draws a down arrow ..see DrawComboBox 
				  the idea came from Robert Bouwens. :) 
				- in file TestTreeDlg.cpp:  due to the MeasureItem message-reflection	 
				  the listctrl is now created in the CDialog::OnCreate function and later on resized 
				- LVIS_DROPHILITED support when dragging items 
				- Support for LVS_EX_CHECKBOXES	   
				- Added some examples on how to print preview selected item(or at least to get some information from of the grid) 
				  the sample is in the CMySuperGrid.h/cpp which is derived from CSuperGridCtrl it shows you 
				  how to initalize the grid, sort items, search for items and subitems, select and delete thems 
				- added virtual GetIcon function to set your default icon handler for a listview index. 
				- added virtual GetCellRGB() to set the color for current selected cell 
				- renamed CTreeNode to CTreeItem, sorry ;-( 
				- the nested class CTreeItem has been stripped down to nothing but simple (struct)data members 
				  only servering as a linked list of lists now :-) 
				- well.. moved all the importent stuff from CTreeItem to CSuperGridCtrl e.g 
				  all operations on a CTreeItem now resides in the CSuperGridCtrl, much more OO-like ;-) 
				- added Quicksort function 
				- got rid of TheOpenCloseThing function. 
				- added virtual function OnUpdateListViewItem..called when ever an Item is about to be updated 
				- added virtual function OnControlLButtonDown...called when ever LButtondown in a cell 
				- added virtual function CreateDragImageEx... 
	11 jan 1999: 
				- added SetFocus in OnDblclk and in OnLButtonDown, big thank you to Dieter Gollwitzer  
				- fixed a minor hittest error in the HitTestOnSign(), again thanks to Dieter Gollwitzer  
 
    WHAT'S UP : 
				- Clipboard support 
				- Better documentation :) 
				- Ole drag/drop...instead of the current one. 
				- Peace on earth. 
				- service pack 2 for VC++ 6.0 :=| 
				- no more support for VC++ 5.0 :) 
 
*/ 
 
///////////////////////////////////////////////////////////////////////////// 
// CSuperGridCtrl 
CSuperGridCtrl::CSuperGridCtrl() 
{ 
	m_cxImage = m_cyImage = m_bIsDragging = m_CurSubItem = 0; 
	m_pRoot=NULL; 
    m_nDragTarget=m_nDragItem = -1; 
} 
 
 
CSuperGridCtrl::~CSuperGridCtrl() 
{ 
	if(m_pRoot!=NULL) 
	{ 
		if(GetData(m_pRoot)!=NULL) 
			delete GetData(m_pRoot); 
		delete m_pRoot; 
	} 
} 
 
 
BEGIN_MESSAGE_MAP(CSuperGridCtrl, CListCtrl) 
	//{{AFX_MSG_MAP(CSuperGridCtrl) 
	ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk) 
	ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndlabeledit) 
	ON_WM_CREATE() 
	ON_WM_HSCROLL() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_MOUSEMOVE() 
	ON_WM_TIMER() 
	ON_WM_VSCROLL() 
	ON_WM_LBUTTONUP() 
	ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeydown) 
	ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag) 
	ON_WM_MEASUREITEM_REFLECT() 
	ON_WM_DRAWITEM_REFLECT() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CSuperGridCtrl message handlers 
 
 
//WHEN USING VC++5.0  
void CSuperGridCtrl::IE4StyleEx(DWORD dwNewStyle) 
{ 
	DWORD dwStyle = ::SendMessage(m_hWnd,LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); 
	dwStyle |= dwNewStyle; 
	::SendMessage(m_hWnd,LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle); 
} 
 
 
BOOL CSuperGridCtrl::PreCreateWindow(CREATESTRUCT& cs)  
{ 
	cs.style |= LVS_REPORT | LVS_SINGLESEL | LVS_SHAREIMAGELISTS | LVS_OWNERDRAWFIXED | LVS_SHOWSELALWAYS;	 
	return CListCtrl::PreCreateWindow(cs); 
} 
 
 
 
int CSuperGridCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CListCtrl::OnCreate(lpCreateStruct) == -1) 
		return -1; 
 
	return 0; 
} 
 
 
 
#define OFFSET_FIRST	2  
#define OFFSET_OTHER	6 
void CSuperGridCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)  
{ 
	if (lpDrawItemStruct->CtlType != ODT_LISTVIEW) 
        return; 
 
	if(lpDrawItemStruct->itemAction == ODA_DRAWENTIRE) 
	{ 
		HIMAGELIST himl = (HIMAGELIST)::SendMessage(m_hWnd, LVM_GETIMAGELIST, (WPARAM)(int)(LVSIL_SMALL), 0L); 
		if(himl==NULL) 
		{ 
			ASSERT(FALSE); 
			return; 
		} 
 
		LV_ITEM lvi; 
		static _TCHAR szBuff[MAX_PATH]; 
		LPCTSTR pszText; 
	 
		int nItem = lpDrawItemStruct->itemID; 
		CRect rcItem(lpDrawItemStruct->rcItem); 
 
		lvi.mask= LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT | LVIF_PARAM;  
		lvi.iItem = nItem; 
		lvi.iSubItem=0; 
		lvi.pszText=szBuff; 
		lvi.cchTextMax=sizeof(szBuff); 
		lvi.stateMask=0xFFFF;		 
		GetItem(&lvi); 
 
		CTreeItem *pSelItem = (CTreeItem*)lpDrawItemStruct->itemData; 
		 
 
		CRect rcLabel; 
		GetItemRect(nItem, rcLabel, LVIR_LABEL); 
		 
		CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); 
		ASSERT(pDC); 
		 
 
		CRect rcClipBox; 
		pDC->GetClipBox(rcClipBox); 
 
		COLORREF crBackground, crText; 
		 
		if (lpDrawItemStruct->itemState & ODS_SELECTED) 
		{ 
			// Set the text background and foreground colors 
			crBackground = GetSysColor (COLOR_HIGHLIGHT); 
			crText = GetSysColor (COLOR_HIGHLIGHTTEXT); 
		} 
		else 
		{ 
			// Set the text background and foreground colors to the standard window 
			// colors 
			crBackground = GetSysColor (COLOR_WINDOW); 
			crText = /*GetSysColor (COLOR_WINDOWTEXT)*/RGB(255,0,0); 
		} 
 
		//Get current Icon, you have overridden this I hope :-) 
		int iImage = GetIcon(pSelItem); 
		if(iImage!=-1) 
		{ 
			LV_ITEM lvItem;				 
			lvItem.mask =  LVIF_IMAGE; 
			lvItem.iImage = iImage; 
			lvItem.iItem = nItem; 
			lvItem.iSubItem = 0; 
			SetItem(&lvItem); 
			lvi.iImage = iImage;  
		} 
 
		CRect rc; 
		GetItemRect(nItem, rc, LVIR_BOUNDS); 
 
		CRect rcIcon; 
		GetItemRect(nItem, rcIcon, LVIR_ICON); 
		//Draw Current image 
		int nOffset = (rcItem.Height() - m_cyImage)/2; 
		int nY = rcItem.bottom - m_cyImage - nOffset; 
		int nWidth = m_cxImage;//def icon size 
		//do not draw icon out side 1.st column. 
		if(rc.left + GetIndent(pSelItem) * m_cxImage + m_cxImage  > GetColumnWidth(0)-2/*looks better -2*/) 
			nWidth = (rc.left +  GetIndent(pSelItem) * m_cxImage + m_cxImage ) - GetColumnWidth(0); 
 
		UINT uiFlags = ILD_TRANSPARENT; 
 
		if( GetItemState(nItem, LVIF_STATE) & LVIS_DROPHILITED)//if dragging show a SelectDropTarget alike effect :) 
			uiFlags |= ILD_BLEND50; 
		 
		if((nWidth=m_cxImage-nWidth) >-1)//calc width of icon 
		ImageList_DrawEx(himl, lvi.iImage, pDC->m_hDC,   
						 rc.left + (GetIndent(pSelItem) * m_cxImage),  
						 nY,  
						 nWidth,	 
						 m_cyImage, 
						 CLR_DEFAULT,  
						 CLR_DEFAULT,  
						 uiFlags); 
 
		DrawTreeItem(pDC, pSelItem, nItem, rc); 
 
		//Draw selection bar (erase old selection too) 
		pDC->SetBkColor(crBackground); 
		CRect rcClip = lpDrawItemStruct->rcItem; 
		rcClip.left += GetIndent(pSelItem) * m_cxImage + m_cxImage + 2; 
		if(rcClip.left > GetColumnWidth(0)) 
			rcClip.left = GetColumnWidth(0); 
		//fill background color 
		ExtTextOut(pDC->GetSafeHdc(), 0, 0, ETO_OPAQUE, rcClip, NULL, 0, NULL); 
 
		 
		if (lpDrawItemStruct->itemState & ODS_SELECTED) 
		{ 
			if(m_CurSubItem==0) 
			{ 
				CRect rect; 
				GetItemRect(0, rect, LVIR_LABEL); 
				CRect rcClip = lpDrawItemStruct->rcItem; 
				rcClip.right = rect.right; 
				rcClip.left +=GetIndent(pSelItem) * m_cxImage + m_cxImage+2; 
				if(rcClip.left > GetColumnWidth(0)) 
					rcClip.left = GetColumnWidth(0); 
				CBrush br(GetCellRGB()); 
				pDC->FillRect(rcClip,&br); 
				pDC->DrawFocusRect(rcClip); 
			} 
		} 
 
		//if checkbox style 
		UINT nStateImageMask = lvi.state & LVIS_STATEIMAGEMASK; 
		if (nStateImageMask) 
		{ 
			int nImage = (nStateImageMask>>12) - 1; 
			CImageList *pImageList = GetImageList(LVSIL_STATE); 
			if (pImageList) 
			{ 
				int cxIcon,cyIcon=0; 
				ImageList_GetIconSize(pImageList->m_hImageList, &cxIcon, &cyIcon); 
				if(rc.left + (GetIndent(pSelItem) * m_cxImage) + m_cxImage + cxIcon < GetColumnWidth(0)) 
					pImageList->Draw(pDC, nImage,CPoint(rc.left + (GetIndent(pSelItem) * m_cxImage) + cxIcon, nY), ILD_TRANSPARENT); 
			} 
		} 
 
	 
		//draw 1. item	 
		GetItemRect(nItem, rcItem, LVIR_LABEL); 
		pszText = MakeShortString(pDC, szBuff, rcItem.right - rcItem.left, 2*OFFSET_FIRST); 
		rcLabel = rcItem; 
		rcLabel.left+=OFFSET_FIRST; 
		rcLabel.right-=OFFSET_FIRST; 
		 
		pDC->SetBkColor (crBackground); 
		pDC->SetTextColor (crText); 
		pDC->DrawText(pszText,-1, rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_EXTERNALLEADING); 
 
		//draw subitems..I guess this is standard code. 
		LV_COLUMN lvc; 
		lvc.mask = LVCF_FMT | LVCF_WIDTH; 
		for(int nColumn=1; GetColumn(nColumn, &lvc); nColumn++) 
		{ 
			rcItem.left=rcItem.right; 
			rcItem.right+=lvc.cx; 
			if (rcItem.left < rcClipBox.right && rcItem.right > rcClipBox.left && rcItem.right > rcItem.left) 
			{ 
				pDC->SetBkColor(crBackground); 
				pDC->SetTextColor(crText); 
				int nRetLen = GetItemText(nItem, nColumn, szBuff, sizeof(szBuff)); 
				if(nRetLen==0) 
					pszText=NULL; 
				else 
					pszText=MakeShortString(pDC,szBuff,rcItem.right-rcItem.left,2*OFFSET_OTHER); 
 
				UINT nJustify=DT_LEFT; 
 
				if(pszText==szBuff) 
				{ 
					switch(lvc.fmt & LVCFMT_JUSTIFYMASK) 
					{ 
					case LVCFMT_RIGHT: 
						nJustify=DT_RIGHT; 
						break; 
					case LVCFMT_CENTER: 
						nJustify=DT_CENTER; 
						break; 
					default: 
						break; 
					} 
				} 
				rcLabel=rcItem; 
				rcLabel.left+=OFFSET_OTHER; 
				rcLabel.right-=OFFSET_OTHER; 
				if (lpDrawItemStruct->itemState & ODS_SELECTED && !m_bIsDragging) 
					DrawFocusCell(pDC, lpDrawItemStruct->itemID, nColumn); 
				if(pszText!=NULL) 
					pDC->DrawText(pszText,-1,rcLabel, nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_EXTERNALLEADING); 
			}//if 
			//draw down arrow if combobox regardless of rcClipBox rgn 
			if (lpDrawItemStruct->itemState & ODS_SELECTED) 
				DrawComboBox(pDC, pSelItem, nItem, nColumn); 
		}//for 
	}//ODA_DRAWENTIRE 
} 
 
 
 
void CSuperGridCtrl::DrawComboBox(CDC* pDC, CTreeItem *pSelItem, int nItem, int nColumn) 
{ 
	CItemInfo* pInfo = GetData(pSelItem); 
	CItemInfo::CONTROLTYPE ctrlType; 
	if(pInfo->GetControlType(nColumn-1, ctrlType)) 
	{ 
		if(ctrlType==pInfo->CONTROLTYPE::combobox)  
		{ 
			CRect rect; 
			#if _MSC_VER >= 1200 
				GetSubItemRect(nItem, nColumn, LVIR_BOUNDS, rect); 
			#else 
				// Get the column offset	 
				int offset = 0;	 
				for( int i = 0; i < nColumn; i++) 
				   offset += GetColumnWidth(i);	 
				GetItemRect(nItem, &rect, LVIR_BOUNDS); 
				// Get Column alignment	 
				LV_COLUMN lvcol; 
				lvcol.mask = LVCF_FMT; 
				GetColumn(nColumn, &lvcol); 
				rect.left += offset; 
				rect.right = rect.left + GetColumnWidth(nColumn); 
			#endif 
			rect.left=rect.right - GetSystemMetrics(SM_CYVSCROLL); 
			pDC->DrawFrameControl(rect, DFC_SCROLL, DFCS_SCROLLDOWN); 
		} 
	} 
} 
 
 
//this piece of code is borrowed from the wndproc.c file in the odlistvw.exe example from MSDN and was converted to mfc-style 
void CSuperGridCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{ 
    if (lpMeasureItemStruct->CtlType != ODT_LISTVIEW) 
        return; 
	TEXTMETRIC tm; 
	CClientDC dc(this);	 
	CFont* pFont = GetFont(); 
	CFont* pOldFont = dc.SelectObject(pFont);	 
	dc.GetTextMetrics(&tm); 
	int nItemHeight = tm.tmHeight + tm.tmExternalLeading; 
	lpMeasureItemStruct->itemHeight = nItemHeight + 4;//or should I go for max(nItemheight+4, m_cxImage+2); 
} 
 
 
 
//the basic rutine making the ... thing snatched it from some tedious code example some where in MSDN call odlistvw.exe 
LPCTSTR CSuperGridCtrl::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int nColumnLen, int nOffset) 
{ 
	static const _TCHAR szThreeDots[]=_T("..."); 
 
	int nStringLen=lstrlen(lpszLong); 
 
	if(nStringLen==0 || pDC->GetTextExtent(lpszLong,nStringLen).cx + nOffset < nColumnLen) 
		return(lpszLong); 
 
	static _TCHAR szShort[MAX_PATH]; 
 
	lstrcpy(szShort,lpszLong); 
	int nAddLen = pDC->GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx; 
 
	for(int i=nStringLen-1; i > 0; i--) 
	{ 
		szShort[i]=0; 
		if(pDC->GetTextExtent(szShort,i).cx + nOffset + nAddLen < nColumnLen) 
			break; 
	} 
	lstrcat(szShort,szThreeDots); 
	return(szShort); 
} 
 
 
 
void CSuperGridCtrl::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR; 
	switch(pLVKeyDow->wVKey) 
	{ 
		case VK_SPACE:  
			{ 
			#if _MSC_VER >= 1200 
				if(GetExtendedStyle() & LVS_EX_CHECKBOXES) 
			#else 
				DWORD dwStyle = ::SendMessage(m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); 
				if(dwStyle & LVS_EX_CHECKBOXES) 
			#endif 
				{	 
					int nIndex = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);  
					CTreeItem* pItem = reinterpret_cast(GetItemData(nIndex)); 
					if(pItem!=NULL) 
					{ 
						CItemInfo *pInfo = GetData(pItem); 
						pInfo->GetCheck()?pInfo->SetCheck(0):pInfo->SetCheck(1); 
					} 
				} 
			}break; 
 
		case VK_DELETE:  
			{ 
				int nItem = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);  
				if(nItem!=-1) 
				{ 
					CTreeItem*pSelItem = reinterpret_cast(GetItemData(nItem)); 
					if(pSelItem!=NULL) 
					{ 
						SetRedraw(0); 
						DeleteItem(nItem);//delete cur item in listview 
						//delete/hide all children in pSelItem 
						HideChildren(pSelItem, TRUE, nItem); 
						//delete all internal nodes 
						Delete(pSelItem); 
						InternaleUpdateTree(); 
						if(nItem-1<0)//no more items in list 
						{ 
							SetRedraw(1);  
							InvalidateRect(NULL); 
							UpdateWindow(); 
							return; 
						} 
						UINT uflag = LVIS_SELECTED | LVIS_FOCUSED; 
						CRect rcTestIfItemIsValidToSelectOtherWiseSubtrackOneFromItem;//just to get the documention right :) 
						GetItemRect(nItem, rcTestIfItemIsValidToSelectOtherWiseSubtrackOneFromItem ,LVIR_LABEL) ? SetItemState(nItem, uflag, uflag) : SetItemState(nItem-1, uflag, uflag); 
						 
						SetRedraw(1); 
						InvalidateRect(NULL); 
						UpdateWindow(); 
						//why not call DeleteItemEx(pSelItem,nItem); :-) 
					}	 
				} 
			}	break; 
 
 
		case VK_MULTIPLY: 
			{   
				int nIndex = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);  
				int nScrollIndex=0; 
				if(nIndex!=-1) 
				{ 
					CWaitCursor wait; 
					SetRedraw(0); 
					CTreeItem *pParent = reinterpret_cast(GetItemData(nIndex)); 
					int nScroll=0; 
					ExpandAll(pParent, nScroll); 
					SetRedraw(1); 
					RedrawItems(nIndex, nScroll); 
					EnsureVisible(nScroll, TRUE); 
					 
				 } 
			 }break; 
 
 
		case VK_ADD: 
			{ 
					int nIndex = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);  
					if(nIndex!=-1) 
					{ 
						CWaitCursor wait; 
						CTreeItem *pSelItem = reinterpret_cast(GetItemData(nIndex)); 
						int nScrollIndex = Expand(pSelItem, nIndex); 
						CRect rc; 
						GetItemRect(nIndex,rc,LVIR_BOUNDS); 
						InvalidateRect(rc); 
						UpdateWindow(); 
						EnsureVisible(nScrollIndex,1); 
					} 
 
			}break; 
 
 
		case VK_SUBTRACT: 
			{ 
				int nIndex = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);  
				if(nIndex!=-1) 
				{ 
					CWaitCursor wait; 
					CTreeItem *pSelItem = reinterpret_cast(GetItemData(nIndex)); 
					Collapse(pSelItem); 
					CRect rc; 
					GetItemRect(nIndex, rc, LVIR_BOUNDS); 
					InvalidateRect(rc); 
					UpdateWindow(); 
				} 
			}break; 
		default :break; 
	} 
	*pResult = 0; 
} 
 
#if _MSC_VER < 1200 
BOOL CSuperGridCtrl::GetCheck(int nItem) const 
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	int nState = (int)::SendMessage(m_hWnd, LVM_GETITEMSTATE, (WPARAM)nItem, 
		(LPARAM)LVIS_STATEIMAGEMASK); 
	// Return zero if it's not checked, or nonzero otherwise. 
	return ((BOOL)(nState >> 12) -1); 
} 
 
BOOL CSuperGridCtrl::SetCheck(int nItem, BOOL fCheck) 
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	LVITEM lvi; 
	lvi.stateMask = LVIS_STATEIMAGEMASK; 
 
	/* 
	Since state images are one-based, 1 in this macro turns the check off, and 
	2 turns it on. 
	*/ 
	lvi.state = INDEXTOSTATEIMAGEMASK((fCheck ? 2 : 1)); 
	return (BOOL) ::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)&lvi); 
} 
#endif 
 
 
BOOL CSuperGridCtrl::HitTestOnSign(CPoint point, LVHITTESTINFO& ht) 
{ 
	ht.pt = point; 
	// Test for which subitem was clicked. 
#if _MSC_VER >= 1200 
	SubItemHitTest(&ht); 
#else 
	ListView_SubItemHitTest(m_hWnd, &ht); 
#endif 
	if(ht.iItem!=-1) 
	{ 
		//first hittest on checkbox 
		//"we need additional checking in owner-draw mode 
		// because we only get LVHT_ONITEM" End quote Microsoft(c) :{ 
		BOOL bHit = FALSE; 
	#if _MSC_VER >= 1200 
		if(GetExtendedStyle() & LVS_EX_CHECKBOXES) 
	#else 
		DWORD dwStyle = ::SendMessage(m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); 
		if(dwStyle & LVS_EX_CHECKBOXES) 
	#endif 
		{ 
			if (ht.flags == LVHT_ONITEM && (GetStyle() & LVS_OWNERDRAWFIXED)) 
			{ 
				CRect rcIcon,rcLabel; 
				GetItemRect(ht.iItem, rcIcon, LVIR_ICON);//has to be between these two ....right :) 
				GetItemRect(ht.iItem, rcLabel, LVIR_LABEL); 
				// check if hit was on a state icon  
				if (point.x > rcIcon.left && point.x < rcLabel.left) 
					bHit = TRUE; 
			} 
			else if (ht.flags & LVHT_ONITEMSTATEICON) 
				bHit = TRUE; 
		} 
 
		CTreeItem* pItem = reinterpret_cast(GetItemData(ht.iItem)); 
		if(pItem!=NULL) 
		{ 
			if(bHit)//if checkbox 
			{ 
				//yes I know..have to maintain to sets of checkstates here... 
				//one for listview statemask and one for CTreeItem..but its located here so no harm done 
				GetCheck(ht.iItem) ? SetCheck(ht.iItem, FALSE) : SetCheck(ht.iItem); 
				CItemInfo *pInfo = GetData(pItem); 
				pInfo->GetCheck()?pInfo->SetCheck(0):pInfo->SetCheck(1); 
			} 
			//if haschildren and clicked on + or - then expand/collapse 
			if(ItemHasChildren(pItem)) 
			{ 
				//hittest on the plus/sign "button"  
				//see the DrawTreeItem for setting up the plus/sign "button"  
				CRect rcBounds; 
				GetItemRect(ht.iItem, rcBounds, LVIR_BOUNDS); 
 
				int nHalfImage = (m_cxImage>>1); 
				///// 
				int nOffset = (rcBounds.Height() - m_cyImage) >> 1;  
				int yDown = rcBounds.top; 
				int nBottomDown = yDown + nHalfImage + nOffset; 
				/// 
				SIZE right_bottom = {(m_cxImage>>1)+2+1, (m_cyImage>>1)+2+1};//once again ANDY: the '+ 1' is to center the [+] or [-]  
				int left = rcBounds.left + GetIndent(pItem) * m_cxImage - nHalfImage; 
				int top = nBottomDown - (right_bottom.cy >> 1); 
				//int top = (rcBounds.top + nHalfImage) - (right_bottom.cy >> 1); 
				POINT left_top = {left -  (right_bottom.cx >> 1), top}; 
				CRect rc(left_top, right_bottom); 
 
				if(rc.PtInRect(point)) 
				{ 
					SetRedraw(0); 
					int nScrollIndex=0; 
					if(IsCollapsed(pItem)) 
						nScrollIndex = Expand(pItem, ht.iItem); 
					else 
					   Collapse(pItem); 
					SetRedraw(1); 
					CRect rc; 
					GetItemRect(ht.iItem, rc, LVIR_BOUNDS); 
					InvalidateRect(rc); 
					UpdateWindow(); 
					EnsureVisible(nScrollIndex,1); 
					return 0; 
				} 
			}//has kids 
		}//pItem!=NULL 
	} 
	return 1; 
} 
 
 
 
void CSuperGridCtrl::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	if( GetFocus() != this)  
		SetFocus(); 
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;	 
	BOOL bSelect=1; 
	LVHITTESTINFO ht; 
	bSelect = HitTestOnSign(pNMListView->ptAction, ht); 
	//normal selection 
	if(bSelect && ht.iItem !=-1) 
	{		 
		int nIndex = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);  
		if(nIndex!=-1) 
		{ 
			CTreeItem *pSelItem = reinterpret_cast(GetItemData(nIndex)); 
			if (pSelItem != NULL) 
			{ 
				if(ItemHasChildren(pSelItem)) 
				{ 
					SetRedraw(0); 
					int nScrollIndex=0; 
					if(IsCollapsed(pSelItem)) 
						nScrollIndex = Expand(pSelItem, nIndex); 
					else 
					   Collapse(pSelItem); 
					SetRedraw(1); 
					CRect rc; 
					GetItemRect(nIndex,rc,LVIR_BOUNDS); 
					InvalidateRect(rc); 
					UpdateWindow(); 
					EnsureVisible(nScrollIndex,1); 
				}	 
			} 
		} 
	} 
	*pResult = 0; 
} 
 
 
//default implementation for setting icons 
int CSuperGridCtrl::GetIcon(const CTreeItem* pItem) 
{ 
	 
	return 0;//just take the first item in CImageList ..what ever that is 
} 
 
 
 
void CSuperGridCtrl::OnControlLButtonDown(UINT nFlags, CPoint point, LVHITTESTINFO& ht) 
{ 
	if(ht.iSubItem==0) 
	{ 
		CRect rcItem; 
		GetItemRect(ht.iItem, rcItem, LVIR_LABEL); 
		DWORD dwStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL|ES_LEFT; 
		CEdit *pEdit = new CListEditCtrl(ht.iItem, ht.iSubItem, GetItemText(ht.iItem, ht.iSubItem)); 
		pEdit->Create(dwStyle, rcItem, this, 0x1233);	 
	} 
	else 
		EditLabelEx(ht.iItem, ht.iSubItem);	 
} 
		 
 
 
 
void CSuperGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	if( GetFocus() != this)  
		SetFocus(); 
	BOOL bSelect=1; 
	LVHITTESTINFO ht; 
	bSelect = HitTestOnSign(point, ht); 
	if(bSelect && ht.iItem!=-1) 
	{ 
		m_CurSubItem = IndexToOrder(ht.iSubItem); 
		CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); 
		// Make the column fully visible. 
		MakeColumnVisible(Header_OrderToIndex(pHeader->m_hWnd, m_CurSubItem)); 
		CListCtrl::OnLButtonDown(nFlags, point); 
		OnControlLButtonDown(nFlags, point, ht); 
		//update row anyway for selection bar 
		CRect rc; 
		GetItemRect(ht.iItem, rc, LVIR_BOUNDS); 
		InvalidateRect(rc); 
		UpdateWindow(); 
		 
	} 
} 
 
 
 
//some day I should base the drag/drop on OLE instead 
void CSuperGridCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; 
	if(pNMListView->iItem!=-1) 
	{ 
		m_nDragItem = pNMListView->iItem; 
		CImageList* pDragImage=NULL; 
		pDragImage = CreateDragImageEx(m_nDragItem); 
		if(pDragImage) 
		{ 
			pDragImage->BeginDrag(0, CPoint(0,0)); 
			pDragImage->DragEnter(this, pNMListView->ptAction); 
			SetCapture(); 
			m_bIsDragging = TRUE; 
		} 
		delete pDragImage; 
	} 
	*pResult = 0; 
} 
 
 
 
 
//create dragimage : Icon + the itemtext 
CImageList *CSuperGridCtrl::CreateDragImageEx(int nItem) 
{ 
    CImageList *pList = new CImageList;           
	//get image index 
	LV_ITEM lvItem; 
	lvItem.mask =  LVIF_IMAGE; 
	lvItem.iItem = nItem; 
	lvItem.iSubItem = 0; 
	GetItem(&lvItem); 
 
	CRect rc; 
	GetItemRect(nItem, &rc, LVIR_BOUNDS);          
 
	CString str; 
	str=GetItemText(nItem, 0); 
	CFont *pFont = GetFont(); 
 
	rc.OffsetRect(-rc.left, -rc.top);             
	rc.right = GetColumnWidth(0);                 
	pList->Create(rc.Width(), rc.Height(),ILC_COLOR24| ILC_MASK , 1, 1); 
	CDC *pDC = GetDC();                           
	if(pDC)  
	{ 
		CDC dc;	       
		dc.CreateCompatibleDC(pDC);       
		CBitmap bmpMap; 
		bmpMap.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height()); 
 
		CBitmap *pOldBmp = dc.SelectObject(&bmpMap); 
		CFont *pOldFont = dc.SelectObject(pFont); 
		dc.FillSolidRect(rc, GetSysColor(COLOR_WINDOW)); 
		CImageList *pImgList = GetImageList(LVSIL_SMALL); 
		if(pImgList) 
			pImgList->Draw(&dc, lvItem.iImage, CPoint(0,0), ILD_TRANSPARENT); 
		dc.TextOut(m_cxImage + 4, 0, str); 
		dc.SelectObject(pOldFont); 
		dc.SelectObject(pOldBmp);                  
		pList->Add(&bmpMap, RGB(255,255,255)); 
		ReleaseDC(pDC);    
	}    
	return pList; 
} 
 
 
 
void CSuperGridCtrl::OnMouseMove(UINT nFlags, CPoint point)  
{ 
    if(m_bIsDragging) 
    { 
		 
		KillTimer(1); 
		if (CWnd::GetCapture() != this) 
			m_bIsDragging=0; 
		 
		if(nFlags==MK_RBUTTON || nFlags==MK_MBUTTON) 
			m_bIsDragging=0; 
 
		 
		if(GetKeyState(VK_ESCAPE) < 0)		 
			m_bIsDragging=0; 
		 
		if(!m_bIsDragging)//why not put this in a funtion :) 
		{ 
			SetItemState (m_nDragTarget, 0, LVIS_DROPHILITED); 
			CImageList::DragLeave(this); 
			CImageList::EndDrag(); 
			ReleaseCapture(); 
			InvalidateRect(NULL); 
			UpdateWindow(); 
		} 
		else 
		{ 
			CPoint ptList(point); 
			MapWindowPoints(this, &ptList, 1); 
			CImageList::DragMove(ptList); 
			UINT uHitTest = LVHT_ONITEM; 
			m_nDragTarget = HitTest(ptList, &uHitTest); 
			// try turn off hilight for previous DROPHILITED state 
			int nPrev = GetNextItem(-1,LVNI_DROPHILITED); 
			if(nPrev != m_nDragTarget)//prevents flicker  
				SetItemState(nPrev, 0, LVIS_DROPHILITED); 
 
			CRect rect; 
			GetClientRect (rect); 
			int cy = rect.Height(); 
			if(m_nDragTarget!=-1) 
			{ 
				SetItemState(m_nDragTarget, LVIS_DROPHILITED, LVIS_DROPHILITED); 
				CTreeItem* pTarget = reinterpret_cast(GetItemData(m_nDragTarget)); 
				if ((point.y >= 0 && point.y <= m_cyImage) || (point.y >= cy - m_cyImage && point.y <= cy) || 	 
					( pTarget!=NULL && ItemHasChildren(pTarget) && IsCollapsed(pTarget))) 
				{ 
					SetTimer(1,300,NULL); 
				} 
			} 
		} 
    } 
 
	CListCtrl::OnMouseMove(nFlags, point); 
} 
 
 
 
void CSuperGridCtrl::OnTimer(UINT nIDEvent)  
{ 
	CListCtrl::OnTimer(nIDEvent); 
	if(nIDEvent==1) 
	{ 
		if(CWnd::GetCapture()!=this) 
		{ 
			SetItemState(m_nDragTarget, 0, LVIS_DROPHILITED); 
			m_bIsDragging=0; 
			CImageList::DragLeave(this); 
			CImageList::EndDrag(); 
			ReleaseCapture(); 
			InvalidateRect(NULL); 
			UpdateWindow(); 
			KillTimer(1); 
			return; 
		} 
 
		SetTimer(1,300,NULL);//reset timer 
		DWORD dwPos = ::GetMessagePos(); 
		CPoint ptList(LOWORD(dwPos),HIWORD(dwPos)); 
		ScreenToClient(&ptList); 
 
		CRect rect; 
		GetClientRect(rect); 
		int cy = rect.Height(); 
		// 
		// perform autoscroll if the cursor is near the top or bottom. 
		// 
		if (ptList.y >= 0 && ptList.y <= m_cyImage)  
		{ 
			int n = GetTopIndex();  
			CImageList::DragShowNolock(0); 
			SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), NULL); 
			CImageList::DragShowNolock(1); 
			if (GetTopIndex()== n) 
				KillTimer (1); 
			else { 
				CImageList::DragShowNolock(0); 
				CImageList::DragMove(ptList); 
				CImageList::DragShowNolock(1); 
				return; 
			} 
		} 
		else if (ptList.y >= cy - m_cyImage && ptList.y <= cy)  
		{ 
			int n = GetTopIndex();  
			CImageList::DragShowNolock(0); 
			SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), NULL); 
			CImageList::DragShowNolock(1); 
			if (GetTopIndex()== n) 
				KillTimer (1); 
			else { 
				CImageList::DragShowNolock(0); 
				CImageList::DragMove(ptList); 
				CImageList::DragShowNolock(1); 
				return; 
			} 
		} 
		//Hover test  
		CImageList::DragMove(ptList); 
		UINT uHitTest = LVHT_ONITEM; 
		m_nDragTarget = HitTest(ptList, &uHitTest); 
	 
		if(m_nDragTarget!=-1) 
		{ 
			//if the target has children 
			//expand them 
			CTreeItem* pTarget=reinterpret_cast(GetItemData(m_nDragTarget)); 
			if(pTarget != NULL && ItemHasChildren(pTarget) && IsCollapsed(pTarget) && (m_nDragItem!=-1)) 
			{ 
				CImageList::DragShowNolock(0); 
				CTreeItem* pSource = reinterpret_cast(GetItemData(m_nDragItem)); 
	 
				SetRedraw(0); 
				int nScrollIndex=0; 
				if(ItemHasChildren(pTarget) && IsCollapsed(pTarget)) 
					nScrollIndex = Expand(pTarget, m_nDragTarget); 
				m_nDragItem = NodeToIndex(pSource); 
				SetRedraw(1); 
				EnsureVisible(nScrollIndex, 1); 
				InvalidateRect(NULL); 
				UpdateWindow(); 
				CImageList::DragShowNolock(1); 
				KillTimer(1); 
				return; 
			}	 
		} 
		KillTimer(1); 
	} 
} 
 
 
 
void CSuperGridCtrl::OnLButtonUp(UINT nFlags, CPoint point)  
{ 
	if( m_bIsDragging == TRUE) 
    { 
		KillTimer(1); 
        CImageList::DragLeave(this); 
        CImageList::EndDrag(); 
        ReleaseCapture(); 
        m_bIsDragging = FALSE; 
		SetItemState(m_nDragTarget, 0, LVIS_DROPHILITED); 
        if((m_nDragTarget != -1) && (m_nDragTarget != m_nDragItem) && (m_nDragItem!=-1))//no drop on me self 
        { 
		 
			CTreeItem* pSource = reinterpret_cast(GetItemData(m_nDragItem)); 
			CTreeItem* pTarget = reinterpret_cast(GetItemData(m_nDragTarget)); 
 
			if (pSource == m_pRoot)//can't drag root in my application, sorry !! 
				return; 
 
			CTreeItem* pParent = GetParentItem(pSource); 
			if(pParent==pTarget) //can't drag child to parent 
				return; 
 
			if(!IsChildOf(pSource,pTarget))//can't drag parent to child 
			{ 
				CWaitCursor wait; 
				SetRedraw(0); 
				int nIndex1 = NodeToIndex(pSource);			 
				if(DoDragDrop(pTarget, m_nDragTarget, pSource, m_nDragItem)) 
				{ 
					 
					 
					UINT uflag = LVIS_SELECTED | LVIS_FOCUSED; 
					SetItemState(m_nDragTarget, uflag, uflag); 
					m_nDragItem=-1; 
					//delete source 
					int nIndex = NodeToIndex(pSource);			 
					DeleteItem(nIndex); 
					HideChildren(pSource, TRUE, nIndex); 
					Delete(pSource); 
					InternaleUpdateTree(); 
					SetRedraw(1); 
					InvalidateRect(NULL); 
					UpdateWindow(); 
				}else 
					SetRedraw(1); 
			} 
	    } 
    } 
    else 
		CListCtrl::OnLButtonUp(nFlags, point); 
} 
 
 
 
//used with the drag/drop operation 
void CSuperGridCtrl::CopyChildren(CTreeItem* pDest, CTreeItem* pSrc) 
{ 
	if (ItemHasChildren(pSrc)) 
	{ 
		POSITION pos = pSrc->m_listChild.GetHeadPosition(); 
		while (pos != NULL) 
		{ 
			CTreeItem* pItem = (CTreeItem *)pSrc->m_listChild.GetNext(pos); 
			CItemInfo* lp = CopyData(GetData(pItem)); 
			CTreeItem* pNewItem = InsertItem(pDest, lp); 
			CopyChildren(pNewItem, pItem); 
		} 
	} 
} 
 
 
//hmmm  
BOOL CSuperGridCtrl::DoDragDrop(CTreeItem* pTarget, int nDragTarget, CTreeItem* pSource, int nDragItem) 
{ 
	if(pTarget==NULL) 
		return 0; 
 
	BOOL bUpdate=FALSE; 
	if(!IsCollapsed(pTarget)) 
		bUpdate=TRUE; //children are expanded, want to see update right away 
	 
	//make a copy of the source data 
	CItemInfo* lp = CopyData(GetData(pSource)); 
	//create new node with the source data and make pTarget the parent 
	 
	CTreeItem* pNewParent = InsertItem(pTarget, lp, bUpdate); 
	//if the source has children copy all source data and make the newly create item the parent 
	if(ItemHasChildren(pSource)) 
		CopyChildren(pNewParent, pSource); 
 
	return 1; 
} 
 
 
void CSuperGridCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)  
{ 
	//its not meself 
	if( GetFocus() != this)  
		SetFocus(); 
	 
	CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar); 
} 
 
 
 
CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetRootItem() 
{ 
	return m_pRoot; 
} 
 
 
 
void CSuperGridCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)  
{ 
	//its not meself 
	if( GetFocus() != this)  
		SetFocus(); 
	CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar); 
} 
 
 
 
BOOL CSuperGridCtrl::PreTranslateMessage(MSG* pMsg)  
{ 
	if(pMsg->message == WM_KEYDOWN) 
	{ 
		if(GetFocus()==this) 
		{ 
			switch( pMsg->wParam ) 
			{ 
				case VK_LEFT: 
					{ 
						// Decrement the order number. 
						m_CurSubItem--; 
						if(m_CurSubItem < 0)  
							m_CurSubItem = 0; 
						else{ 
 
							CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); 
							// Make the column visible. 
							// We have to take into account that the header may be reordered. 
							MakeColumnVisible( Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem)); 
							// Invalidate the item. 
							int iItem = GetNextItem( -1, LVNI_ALL | LVNI_SELECTED); 
							if( iItem != -1 ) 
							{ 
								CRect rcBounds; 
								GetItemRect(iItem, rcBounds, LVIR_BOUNDS); 
								InvalidateRect(&rcBounds); 
								UpdateWindow(); 
							} 
						} 
					} 
					return TRUE; 
				case VK_RIGHT: 
					{ 
						// Increment the order number. 
						m_CurSubItem++; 
						CHeaderCtrl* pHeader = (CHeaderCtrl*) GetDlgItem(0); 
						int nColumnCount = pHeader->GetItemCount(); 
						// Don't go beyond the last column. 
						if( m_CurSubItem > nColumnCount -1 )  
							m_CurSubItem = nColumnCount-1; 
						else 
						{ 
							MakeColumnVisible(Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem)); 
							  
							int iItem = GetNextItem( -1, LVNI_ALL | LVNI_SELECTED); 
							// Invalidate the item. 
							if( iItem != -1 ) 
							{ 
								CRect rcBounds; 
								GetItemRect(iItem, rcBounds, LVIR_BOUNDS); 
								InvalidateRect(&rcBounds); 
								UpdateWindow(); 
							} 
						} 
					} 
					return TRUE; 
 
				case VK_RETURN://edit itemdata 
					{ 
							int iItem = GetNextItem( -1, LVNI_ALL | LVNI_SELECTED); 
							if( m_CurSubItem != -1 && iItem != -1) 
							{ 
								CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); 
								int iSubItem = Header_OrderToIndex(pHeader->m_hWnd, m_CurSubItem); 
								if(iSubItem==0)//that's just me saying all nodes in col 0 are edit-controls, you may modify this 
								{ 
									CRect rcItem; 
									GetItemRect(iItem, rcItem, LVIR_LABEL); 
									DWORD dwStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL|ES_LEFT; 
									CEdit *pEdit = new CListEditCtrl(iItem, iSubItem, GetItemText(iItem, iSubItem)); 
									pEdit->Create(dwStyle, rcItem, this, 0x1233);	 
								} 
								else 
									EditLabelEx(iItem, iSubItem);	 
								return 1; 
							} 
					} 
					break; 
				default: 
					break; 
			} 
		} 
	} 
	return CListCtrl::PreTranslateMessage(pMsg); 
} 
 
#define IDC_EDITCTRL 0x1234 
CEdit* CSuperGridCtrl::EditLabelEx(int nItem, int nCol) 
{ 
	CRect rect; 
	int offset = 0; 
	if(!EnsureVisible(nItem, TRUE))  
		return NULL; 
 
	#if _MSC_VER >= 1200 
		GetSubItemRect(nItem, nCol, LVIR_BOUNDS, rect); 
	#else 
		for( int i = 0; i < nCol; i++ ) 
			offset += GetColumnWidth(i); 
		GetItemRect(nItem, &rect, LVIR_BOUNDS); 
	#endif 
	// Now scroll if we need to expose the column 
	CRect rcClient; 
	GetClientRect(rcClient); 
	if( offset + rect.left < 0 || offset + rect.left > rcClient.right ) 
	{ 
		CSize size(offset + rect.left,0);		 
		Scroll(size); 
		rect.left -= size.cx; 
	} 
	rect.left += offset;	 
	rect.right = rect.left + GetColumnWidth(nCol); 
	if(rect.right > rcClient.right)  
	   rect.right = rcClient.right; 
 
	// Get Column alignment	 
	LV_COLUMN lvcol; 
	lvcol.mask = LVCF_FMT; 
	GetColumn(nCol, &lvcol); 
 
	DWORD dwStyle; 
	if((lvcol.fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT) 
		dwStyle = ES_LEFT; 
	else if((lvcol.fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT) 
		dwStyle = ES_RIGHT; 
	else  
		dwStyle = ES_CENTER;	 
 
	 
	dwStyle |=WS_BORDER|WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL; 
	CEdit *pEdit = new CListEditCtrl(nItem, nCol, GetItemText(nItem, nCol)); 
	pEdit->Create(dwStyle, rect, this, IDC_EDITCTRL);	 
	//pEdit->ModifyStyleEx(0,WS_EX_CLIENTEDGE); //funny thing happend here, uncomment this,  
												//and then edit an item,  
												//enter a long text so that the ES_AUTOHSCROLL comes to rescue 
												//yes that's look funny, ???. 
	return pEdit; 
} 
 
 
void CSuperGridCtrl::OnUpdateListViewItem(CTreeItem* lpItem, LV_ITEM *plvItem) 
{ 
	//default implementation you would go for this 9 out of 10 times 
	CItemInfo *lp = GetData(lpItem); 
	CString str = (CString)plvItem->pszText; 
	if(lp!=NULL) 
	{ 
		if(plvItem->iSubItem==0) 
			lp->SetItemText(str); 
		else //subitem data  
			lp->SetSubItemText(plvItem->iSubItem-1, str); 
	   UpdateData(lpItem, lp); 
	} 
	SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText); 
} 
 
 
 
void CSuperGridCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	LV_DISPINFO *plvDispInfo = (LV_DISPINFO*)pNMHDR; 
 	LV_ITEM *plvItem = &plvDispInfo->item; 
	if (plvItem->pszText != NULL) 
	{ 
		if(plvItem->iItem!=-1) 
		{ 
			CTreeItem*pSelItem = reinterpret_cast(GetItemData(plvItem->iItem)); 
			if(pSelItem!=NULL) 
			{ 
				OnUpdateListViewItem(pSelItem, plvItem); 
			} 
		} 
	} 
	*pResult = 0; 
} 
 
 
 
 
int CSuperGridCtrl::GetNumCol() 
{ 
#if _MSC_VER >= 1200 
	CHeaderCtrl* pHeader = GetHeaderCtrl(); 
#else 
	CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); 
#endif 
	return pHeader ? pHeader->GetItemCount() : 0; 
} 
 
 
 
//Think Rex Myer is spooking here 
void CSuperGridCtrl::MakeColumnVisible(int nCol) 
{ 
	if(nCol < 0) 
		return; 
	// Get the order array to total the column offset. 
	CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); 
	int nColCount = pHeader->GetItemCount(); 
	ASSERT( nCol < nColCount); 
	int *pOrderarray = new int[nColCount]; 
	Header_GetOrderArray(pHeader->m_hWnd, nColCount, pOrderarray); 
	// Get the column offset 
	int offset = 0; 
	for(int i = 0; pOrderarray[i] != nCol; i++) 
		offset += GetColumnWidth(pOrderarray[i]); 
 
	int colwidth = GetColumnWidth(nCol); 
	delete[] pOrderarray; 
 
	CRect rect; 
	GetItemRect(0, &rect, LVIR_BOUNDS); 
	// Now scroll if we need to show the column 
	CRect rcClient; 
	GetClientRect(&rcClient); 
	if(offset + rect.left < 0 || offset + colwidth + rect.left > rcClient.right) 
	{ 
		CSize size(offset + rect.left,0); 
		Scroll(size); 
		InvalidateRect(NULL); 
		UpdateWindow(); 
	} 
} 
 
 
 
//Think Rex Myer is spooking here 
int CSuperGridCtrl::IndexToOrder( int iIndex ) 
{ 
	// This translates a column index value to a column order value. 
	CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); 
	int nColCount = pHeader->GetItemCount(); 
	int *pOrderarray = new int[nColCount]; 
	Header_GetOrderArray(pHeader->m_hWnd, nColCount, pOrderarray); 
	for(int i=0; i= 1200 
			GetSubItemRect(nItem, iSubItem, LVIR_BOUNDS, rect); 
		#else 
			int nCol=iSubItem; 
			// Get the column offset	 
			int offset = 0;	 
			for( int i = 0; i < nCol; i++) 
			   offset += GetColumnWidth(i);	 
			GetItemRect(nItem, &rect, LVIR_BOUNDS); 
			// Get Column alignment	 
			LV_COLUMN lvcol; 
			lvcol.mask = LVCF_FMT; 
			GetColumn(nCol, &lvcol); 
			rect.left += offset; 
			rect.right = rect.left + GetColumnWidth(nCol); 
		#endif 
		CBrush br(GetCellRGB()); 
		if(iSubItem==0) 
			GetItemRect(iSubItem, rect, LVIR_LABEL); 
		pDC->FillRect(rect, &br); 
		pDC->DrawFocusRect(rect); 
		 
	} 
} 
 
 
 
//insert item and return new parent pointer. 
CSuperGridCtrl::CTreeItem* CSuperGridCtrl::InsertItem(CTreeItem *pParent, CItemInfo* lpInfo, BOOL bUpdate) 
{ 
	CTreeItem *pItem; 
	pItem = new CTreeItem(); 
	if(lpInfo==NULL) 
		lpInfo = new CItemInfo; 
 
	UpdateData(pItem, lpInfo); 
	SetIndent(pItem, GetIndent(pParent)+1); 
	SetParentItem(pItem, pParent); 
	//add as the last child  
	pParent->m_listChild.AddTail(pItem); 
 
	if(!bUpdate) 
		 Hide(pParent, TRUE);	 
	else 
	{ 
		//calc listview index for the new node 
		int nIndex = NodeToIndex(pItem);			 
		CString str = GetData(pItem)->GetItemText(); 
		LV_ITEM     lvItem; 
		lvItem.mask = LVIF_TEXT | LVIF_INDENT | LVIF_PARAM; 
		lvItem.pszText = str.GetBuffer(1);  
		//insert item 
		lvItem.iItem = nIndex; 
		lvItem.iSubItem = 0; 
		lvItem.lParam = (LPARAM)pItem; 
		lvItem.iIndent = GetIndent(pItem); 
		CListCtrl::InsertItem(&lvItem); 
		if(lpInfo->GetCheck()) 
			SetCheck(nIndex); 
		//Get subitems 
		int nSize = GetData(pItem)->GetItemCount(); 
		for(int i=0; i < nSize;i++) 
		{ 
		   CString str = GetData(pItem)->GetSubItem(i); 
		   lvItem.mask = LVIF_TEXT; 
		   lvItem.iSubItem = i+1; 
		   lvItem.pszText = str.GetBuffer(1); 
		   SetItem(&lvItem); 
		} 
		InternaleUpdateTree();//better do this 
	} 
	return pItem; 
}	 
 
 
 
void CSuperGridCtrl::InternaleUpdateTree() 
{ 
	int nItems = GetItemCount(); 
	for(int nItem=0; nItem < nItems; nItem++) 
	{ 
		CTreeItem* pItem = reinterpret_cast(GetItemData(nItem)); 
		SetCurIndex(pItem, nItem); 
	} 
} 
 
 
 
 
int CSuperGridCtrl::NodeToIndex(CTreeItem *pNode) 
{ 
	int nStartIndex=0; 
	return _NodeToIndex(m_pRoot, pNode, nStartIndex); 
} 
 
 
 
void CSuperGridCtrl::DrawTreeItem(CDC* pDC, CTreeItem* pSelItem, int nListItem, const CRect& rcBounds) 
{ 
	int nColWidth = GetColumnWidth(0); 
	int nOffset = (rcBounds.Height() - m_cyImage) >> 1;  
	 
	int yDown = rcBounds.top; 
 
    CPen psPen(PS_SOLID, 1, RGB(192,192,192)); 
    CPen* pOldPen = pDC->SelectObject(&psPen); 
	int iIndent = GetIndent(pSelItem); 
	//setup plus/minus rectangle 
	int nHalfImage = (m_cxImage >> 1); 
	 
	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(m_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 == nListItem && (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); 
				break; 
			} 
			else 
			if(nIndex > nListItem && (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); 
				break; 
			} 
			else 
			if(nIndex > nListItem && (GetIndent(pLastChild) < iIndent)) 
			{ 
				//draw | 
				pDC->MoveTo(xLine, yDown); 
				pDC->LineTo(xLine, rcBounds.bottom); 
				break; 
			} 
		}			 
		pSelItem = pParent;//next 
	} 
	//draw plus/minus sign 
	if(bChild) 
	{ 
		//erase bkgrnd 
		CRect rc(left_top, right_bottom); 
		pDC->FillRect(rc, &CBrush(RGB(255,255,255))); 
		//draw rectangle	 
		CPen psrect(PS_SOLID, 1, RGB(198,198,198)); 
		CPen* pOldPen1 = pDC->SelectObject(&psrect); 
		pDC->Rectangle(rc); 
		pDC->SelectObject(pOldPen1);		 
		//draw plus/minus sign 
		CPen psPen(PS_SOLID, 1, RGB(0,0,0)); 
		CPen* pOldPen = pDC->SelectObject(&psPen); 
		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); 
			CPen psPen(PS_SOLID, 1, RGB(192,192,192)); 
			CPen* pOldPen = pDC->SelectObject(&psPen); 
			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);		 
		} 
		pDC->SelectObject(pOldPen);		 
	} 
	pDC->SelectObject(pOldPen); 
} 
 
 
 
BOOL CSuperGridCtrl::CreateTreeCtrl(CItemInfo* lpInfo) 
{ 
	CTreeItem* pRoot = NULL; 
	pRoot =  new CTreeItem(); 
	if(pRoot!=NULL) 
	{ 
		if(lpInfo==NULL)//can't have this, if you didn't bother, I do. 
			lpInfo = new CItemInfo(); 
		CleanMe(pRoot); 
		UpdateData(pRoot, lpInfo); 
		SetIndent(pRoot, 1); 
		SetCurIndex(pRoot, 0); 
		SetParentItem(pRoot, NULL); 
 
		CItemInfo* lp = GetData(pRoot); 
		LV_ITEM lvItem;		 
		lvItem.mask = LVIF_TEXT | LVIF_INDENT | LVIF_PARAM; 
		CString strItem = lp->GetItemText(); 
		lvItem.pszText = strItem.GetBuffer(1);  
		lvItem.iItem = 0; 
		lvItem.lParam = (LPARAM)pRoot; 
		lvItem.iIndent = 1; 
		lvItem.iSubItem = 0; 
		CListCtrl::InsertItem(&lvItem); 
		int nSize = lp->GetItemCount(); 
		for(int i=0; i < nSize;i++) 
		{ 
		   CString str = lp->GetSubItem(i); 
		   lvItem.mask = LVIF_TEXT; 
		   lvItem.iSubItem = i+1; 
		   lvItem.pszText = str.GetBuffer(1); 
		   SetItem(&lvItem); 
		} 
		m_pRoot = pRoot;//store root ptr 
 
		return 1; 
	} 
	return 0; 
} 
 
 
//walk all over the place setting the hide/show flag of the nodes. 
//it also deletes items from the listviewctrl. 
void CSuperGridCtrl::HideChildren(CTreeItem *pItem, BOOL bHide,int nItem) 
{ 
	if(!IsCollapsed(pItem)) 
	if (ItemHasChildren(pItem)) 
	{ 
		Hide(pItem, bHide); 
		POSITION pos = pItem->m_listChild.GetHeadPosition(); 
		while (pos != NULL) 
		{ 
			HideChildren((CTreeItem *)pItem->m_listChild.GetNext(pos),bHide,nItem+1); 
			DeleteItem(nItem); 
		} 
	} 
} 
 
 
 
 
void CSuperGridCtrl::Collapse(CTreeItem *pItem) 
{ 
	if(pItem != NULL && ItemHasChildren(pItem)) 
	{ 
		SetRedraw(0); 
		int nIndex = NodeToIndex(pItem);			 
		HideChildren(pItem, TRUE, nIndex+1); 
		InternaleUpdateTree(); 
		SetRedraw(1); 
	} 
} 
 
 
void CSuperGridCtrl::ExpandAll(CTreeItem *pItem, int& nScroll) 
{ 
	const int nChildren = pItem->m_listChild.GetCount(); 
	if (nChildren > 0) 
	{ 
		int nIndex = NodeToIndex(pItem); 
		nScroll=Expand(pItem, nIndex); 
	} 
 
	POSITION pos = pItem->m_listChild.GetHeadPosition(); 
	while (pos) 
	{ 
		CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos); 
		ExpandAll(pChild, nScroll); 
	} 
	 
} 
 
 
 
int CSuperGridCtrl::Expand(CTreeItem* pSelItem, int nIndex) 
{ 
	if(ItemHasChildren(pSelItem) && IsCollapsed(pSelItem)) 
	{ 
		LV_ITEM lvItem; 
		lvItem.mask = LVIF_INDENT; 
		lvItem.iItem = nIndex; 
		lvItem.iSubItem = 0; 
		lvItem.lParam=(LPARAM)pSelItem; 
		lvItem.iIndent = GetIndent(pSelItem); 
		SetItem(&lvItem); 
 
		Hide(pSelItem, FALSE); 
		//expand children 
		POSITION pos = pSelItem->m_listChild.GetHeadPosition(); 
		while(pos != NULL) 
		{ 
			CTreeItem* pNextNode = (CTreeItem*)pSelItem->m_listChild.GetNext(pos); 
			CString str = GetData(pNextNode)->GetItemText(); 
			LV_ITEM lvItem; 
			lvItem.mask = LVIF_TEXT | LVIF_INDENT | LVIF_PARAM; 
			lvItem.pszText =str.GetBuffer(1);  
			lvItem.iItem = nIndex + 1; 
			lvItem.iSubItem = 0; 
			lvItem.lParam=(LPARAM)pNextNode; 
			lvItem.iIndent = GetIndent(pSelItem)+1; 
			CListCtrl::InsertItem(&lvItem); 
			if(GetData(pNextNode)->GetCheck()) 
				SetCheck(nIndex + 1); 
			//get subitems 
			int nSize = GetData(pNextNode)->GetItemCount(); 
			for(int i=0; i< nSize;i++) 
			{ 
			   CString str=GetData(pNextNode)->GetSubItem(i); 
			   lvItem.mask = LVIF_TEXT; 
			   lvItem.iSubItem = i+1; 
			   lvItem.pszText=str.GetBuffer(1); 
			   SetItem(&lvItem); 
			} 
			nIndex++; 
		} 
	} 
	InternaleUpdateTree(); 
	return nIndex; 
} 
 
 
 
 
int CSuperGridCtrl::SelectNode(CTreeItem *pLocateNode) 
{ 
	if(pLocateNode==m_pRoot) 
	{ 
		UINT uflag = LVIS_SELECTED | LVIS_FOCUSED; 
		SetItemState(0, uflag, uflag); 
		return 0; 
	} 
	int nSelectedItem=-1; 
	CTreeItem* pNode = pLocateNode; 
	CTreeItem* pTopLevelParent=NULL; 
	//Get top parent 
	while(1) 
	{ 
		CTreeItem *pParent = GetParentItem(pLocateNode); 
		if(pParent==m_pRoot) 
			break; 
		pLocateNode = pParent; 
	} 
	pTopLevelParent = pLocateNode; 
	//Expand the folder 
	if(pTopLevelParent!=NULL) 
	{ 
		SetRedraw(0); 
		CWaitCursor wait; 
		CTreeItem *pRoot = GetParentItem(pTopLevelParent); 
		if(IsCollapsed(pRoot)) 
			Expand(pRoot,0); 
		ExpandUntil(pTopLevelParent, pNode); 
		UINT uflag = LVIS_SELECTED | LVIS_FOCUSED; 
		nSelectedItem = NodeToIndex(pNode); 
		SetItemState(nSelectedItem, uflag, uflag); 
		SetRedraw(1); 
		EnsureVisible(nSelectedItem, TRUE); 
	} 
	return nSelectedItem; 
} 
 
 
 
 
void CSuperGridCtrl::ExpandUntil(CTreeItem *pItem, CTreeItem* pStopAt) 
{ 
	const int nChildren = pItem->m_listChild.GetCount(); 
	if (nChildren > 0) 
	{ 
		POSITION pos = pItem->m_listChild.GetHeadPosition(); 
		while (pos) 
		{ 
			CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos); 
			if(pChild==pStopAt)	 
			{ 
				int nSize = GetIndent(pChild); 
				CTreeItem** ppParentArray = new CTreeItem*[nSize]; 
				int i=0; 
				while(1) 
				{ 
					CTreeItem *pParent=GetParentItem(pChild); 
					if(pParent==m_pRoot) 
						break; 
					pChild = pParent; 
					ppParentArray[i] =pChild; 
					i++; 
				} 
 
				for(int x=i;x > 0; x--) 
				{ 
					CTreeItem *pParent = ppParentArray[x-1]; 
					Expand(pParent, NodeToIndex(pParent)); 
				} 
				delete [] ppParentArray; 
				return; 
			} 
		} 
	} 
 
	POSITION pos = pItem->m_listChild.GetHeadPosition(); 
	while (pos) 
	{ 
		CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos); 
		ExpandUntil(pChild, pStopAt); 
	} 
	 
} 
 
 
 
void CSuperGridCtrl::DeleteItemEx(CTreeItem *pSelItem, int nItem) 
{ 
	SetRedraw(0); 
	DeleteItem(nItem);//delete cur item in listview 
	//delete/hide all children in pSelItem 
	HideChildren(pSelItem, TRUE, nItem); 
	//delete all internal nodes 
	Delete(pSelItem); 
	InternaleUpdateTree(); 
	if(nItem-1<0)//no more items in list 
	{ 
		SetRedraw(1);  
		InvalidateRect(NULL); 
		UpdateWindow(); 
		return; 
	} 
	UINT uflag = LVIS_SELECTED | LVIS_FOCUSED; 
	CRect rcTestIfItemIsValidToSelectOtherWiseSubtrackOneFromItem;//just to get the documention right :) 
	GetItemRect(nItem, rcTestIfItemIsValidToSelectOtherWiseSubtrackOneFromItem ,LVIR_LABEL) ? SetItemState(nItem, uflag, uflag) : SetItemState(nItem-1, uflag, uflag); 
	 
	SetRedraw(1); 
	InvalidateRect(NULL); 
	UpdateWindow(); 
} 
 
 
 
void CSuperGridCtrl::CleanMe(CTreeItem *pItem) 
{ 
	// delete child nodes 
	POSITION pos = pItem->m_listChild.GetHeadPosition(); 
	while (pos != NULL) 
	{ 
		CTreeItem* pItem =(CTreeItem*)pItem->m_listChild.GetNext(pos); 
		if(pItem!=NULL) 
		{ 
			if(pItem->m_lpNodeInfo!=NULL) 
				delete pItem->m_lpNodeInfo; 
			delete pItem; 
		} 
	} 
	pItem->m_listChild.RemoveAll(); 
 
} 
 
 
 
 
CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetNextSiblingItem(CTreeItem* pNode, BOOL bInit, BOOL bDontIncludeHidden) 
{ 
	return _GetNext(GetRootItem(), pNode, bInit, bDontIncludeHidden); 
} 
 
 
 
CSuperGridCtrl::CTreeItem* CSuperGridCtrl::_GetNext(CTreeItem* pStartAt, CTreeItem* pNode, BOOL bInit, BOOL bDontIncludeHidden) 
{ 
	static BOOL bFound; 
	if (bInit) 
		bFound = FALSE; 
		 
	if (pNode == pStartAt) 
		bFound = TRUE; 
 
	if(bDontIncludeHidden) 
	{ 
		if (!IsCollapsed(pStartAt)) 
		{ 
			POSITION pos = pStartAt->m_listChild.GetHeadPosition(); 
			while (pos != NULL) 
			{ 
				CTreeItem* pChild = (CTreeItem*)pStartAt->m_listChild.GetNext(pos); 
				if (bFound) 
					return pChild; 
				pChild = _GetNext(pChild,pNode, FALSE, TRUE); 
				if (pChild != NULL) 
					return pChild; 
			} 
		} 
	} 
	else { 
			POSITION pos = pStartAt->m_listChild.GetHeadPosition(); 
			while (pos != NULL) 
			{ 
				CTreeItem* pChild = (CTreeItem*)pStartAt->m_listChild.GetNext(pos); 
				if (bFound) 
					return pChild; 
				pChild = _GetNext(pChild,pNode, FALSE,FALSE); 
				if (pChild != NULL) 
					return pChild; 
			} 
	} 
	// if reached top and last level return original 
	if (bInit) 
		return pNode; 
	else 
		return NULL; 
} 
 
 
 
CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetPrevSiblingItem(CTreeItem* pNode, BOOL bInit, BOOL bDontIncludeHidden) 
{ 
	return _GetPrev(GetRootItem(), pNode,  bInit, bDontIncludeHidden); 
} 
 
 
 
 
CSuperGridCtrl::CTreeItem* CSuperGridCtrl::_GetPrev(CTreeItem* pStartAt, CTreeItem* pNode, BOOL bInit, BOOL bDontIncludeHidden) 
{ 
	static CTreeItem* pPrev; 
	if (bInit) 
		pPrev = pStartAt; 
 
	if (pNode == pStartAt) 
		return pPrev; 
 
	pPrev = pStartAt; 
	if(bDontIncludeHidden) 
	{ 
 
		if (!IsCollapsed(pStartAt)) 
		{ 
			POSITION pos = pStartAt->m_listChild.GetHeadPosition(); 
			while (pos != NULL) 
			{ 
				CTreeItem* pCur = (CTreeItem*)pStartAt->m_listChild.GetNext(pos); 
				CTreeItem* pChild = _GetPrev(pCur,pNode, FALSE,TRUE); 
				if (pChild != NULL) 
					return pChild; 
			} 
		} 
	} 
	else { 
		POSITION pos = pStartAt->m_listChild.GetHeadPosition(); 
		while (pos != NULL) 
		{ 
			CTreeItem* pCur = (CTreeItem*)pStartAt->m_listChild.GetNext(pos); 
			CTreeItem* pChild = _GetPrev(pCur,pNode, FALSE,FALSE); 
			if (pChild != NULL) 
				return pChild; 
		} 
	} 
 
	if (bInit) 
		return pPrev; 
	else 
		return NULL; 
} 
 
 
 
int CSuperGridCtrl::_NodeToIndex(CTreeItem *pStartpos, CTreeItem* pNode, int& nIndex, BOOL binit) 
{ 
	static BOOL bFound;	 
 
	if(binit) 
		bFound=FALSE; 
 
	if(pStartpos==pNode) 
		bFound=TRUE; 
 
	if(!IsCollapsed(pStartpos)) 
	{ 
		POSITION pos = GetHeadPosition(pStartpos); 
		while (pos) 
		{ 
			CTreeItem *pChild = GetNextChild(pStartpos, pos); 
			if(bFound) 
				return nIndex; 
			nIndex=_NodeToIndex(pChild, pNode, nIndex, binit); 
			nIndex++;				 
		} 
	} 
 
	if(binit) 
		return nIndex; 
	else 
		return -1; 
} 
 
 
 
BOOL CSuperGridCtrl::Delete(CTreeItem* pNode, BOOL bClean) 
{ 
	return _Delete(GetRootItem(),pNode,bClean); 
} 
 
 
 
BOOL CSuperGridCtrl::_Delete(CTreeItem* pStartAt, CTreeItem* pNode, BOOL bClean) 
{ 
	POSITION pos = pStartAt->m_listChild.GetHeadPosition(); 
	while (pos != NULL) 
	{ 
		POSITION posPrev = pos; 
		CTreeItem *pChild = (CTreeItem*)pStartAt->m_listChild.GetNext(pos); 
		if (pChild == pNode) 
		{ 
			pStartAt->m_listChild.RemoveAt(posPrev); 
			if(bClean) 
			{ 
				if(GetData(pNode)!=NULL) 
					delete GetData(pNode); 
				delete pNode; 
			} 
			return TRUE; 
		} 
		if (_Delete(pChild, pNode) == TRUE) 
			return TRUE; 
	} 
	return FALSE; 
} 
 
 
 
BOOL CSuperGridCtrl::IsChildOf(const CTreeItem* pParent, const CTreeItem* pChild) const 
{ 
	if (pChild == pParent) 
		return TRUE; 
	POSITION pos = pParent->m_listChild.GetHeadPosition(); 
	while (pos != NULL) 
	{ 
		CTreeItem* pNode = (CTreeItem*)pParent->m_listChild.GetNext(pos); 
		if (IsChildOf(pNode, pChild)) 
			return TRUE; 
	} 
	return FALSE; 
} 
 
 
inline int StrComp(const CString* pElement1, const CString* pElement2) 
{ 
	return pElement1->Compare(*pElement2); 
} 
 
 
 
int CSuperGridCtrl::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; 
	return StrComp(&(pItem1->GetItemText()), &(pItem2->GetItemText())); 
} 
 
 
 
POSITION CSuperGridCtrl::GetHeadPosition(CTreeItem* pItem) const 
{ 
	return pItem->m_listChild.GetHeadPosition(); 
} 
 
 
 
CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetNextChild(CTreeItem *pItem, POSITION& pos) const 
{ 
	return (CTreeItem*)pItem->m_listChild.GetNext(pos); 
} 
 
 
 
CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetPrevChild(CTreeItem *pItem, POSITION& pos) const 
{ 
	return (CTreeItem*)pItem->m_listChild.GetPrev(pos); 
} 
 
 
 
POSITION CSuperGridCtrl::GetTailPosition(CTreeItem *pItem) const 
{ 
	return pItem->m_listChild.GetTailPosition(); 
} 
 
 
 
void CSuperGridCtrl::AddChild(CTreeItem *pParent, CTreeItem *pChild) 
{ 
	pParent->m_listChild.AddTail(pChild); 
} 
 
 
 
void CSuperGridCtrl::Sort(CTreeItem* pParent, BOOL bSortChildren) 
{ 
	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++) 
		{ 
			ASSERT(i < nChildren); 
			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++) 
		{ 
			ASSERT(i < nChildren); 
			pParent->m_listChild.SetAt(pos, ppSortArray[i]); 
			pParent->m_listChild.GetNext(pos); 
		} 
 
		delete [] ppSortArray; 
	} 
 
	if(bSortChildren) 
	{ 
		POSITION pos = pParent->m_listChild.GetHeadPosition(); 
		while (pos) 
		{ 
			CTreeItem *pChild = (CTreeItem*)pParent->m_listChild.GetNext(pos); 
			Sort(pChild, TRUE); 
		} 
	} 
} 
 
 
 
int CSuperGridCtrl::NumChildren(const CTreeItem *pItem) const 
{ 
	return pItem->m_listChild.GetCount(); 
} 
 
 
 
BOOL CSuperGridCtrl::ItemHasChildren(const CTreeItem* pItem) const 
{  
	return pItem->m_listChild.GetCount() != 0; 
} 
 
 
 
BOOL CSuperGridCtrl::IsCollapsed(const CTreeItem* pItem) const 
{ 
	return pItem->m_bHideChildren; 
} 
 
 
int CSuperGridCtrl::GetIndent(const CTreeItem* pItem) const 
{ 
	return pItem->m_nIndent; 
} 
 
 
void CSuperGridCtrl::SetIndent(CTreeItem *pItem, int iIndent) 
{ 
	pItem->m_nIndent = iIndent; 
} 
 
 
void CSuperGridCtrl::Hide(CTreeItem* pItem, BOOL bFlag) 
{ 
	pItem->m_bHideChildren=bFlag; 
} 
 
 
int CSuperGridCtrl::GetCurIndex(const CTreeItem *pItem) const 
{ 
	return pItem->m_nIndex; 
} 
 
 
void CSuperGridCtrl::SetCurIndex(CTreeItem* pItem, int nIndex)  
{ 
	pItem->m_nIndex = nIndex; 
} 
 
 
void CSuperGridCtrl::SetParentItem(CTreeItem*pItem, CTreeItem* pParent) 
{ 
	pItem->m_pParent=pParent; 
 
} 
 
 
CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetParentItem(const CTreeItem* pItem)  
{ 
	return pItem->m_pParent; 
}; 
 
 
 
CItemInfo* CSuperGridCtrl::GetData(const CTreeItem* pItem)  
{ 
	return pItem->m_lpNodeInfo; 
} 
 
 
 
void CSuperGridCtrl::UpdateData(CTreeItem* pItem, CItemInfo* lpInfo) 
{ 
	pItem->m_lpNodeInfo = lpInfo; 
} 
 
 
//override  
CItemInfo* CSuperGridCtrl::CopyData(CItemInfo* lpSrc) 
{ 
	ASSERT(FALSE);//debug 
	return NULL;  //release 
} 
 
 
 
 
////////////////////////////////////////////////////////////////////////// 
// 
// not much but ...  
// 
CSuperGridCtrl::CTreeItem::~CTreeItem() 
{ 
	// delete child nodes 
	POSITION pos = m_listChild.GetHeadPosition(); 
	while (pos != NULL) 
	{ 
		CTreeItem* pItem =(CTreeItem*)m_listChild.GetNext(pos); 
		if(pItem!=NULL) 
		{ 
			if(pItem->m_lpNodeInfo!=NULL) 
				delete pItem->m_lpNodeInfo; 
			delete pItem; 
		} 
	} 
	m_listChild.RemoveAll(); 
}