Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

The Ultimate Toolbox - Updates and User Contributions

, 12 Feb 2013
Updates and User Contributions for the Ultimate Toolbox Libraries
OutlookDemoUpdate.zip
Ultimate Grid
Demos
OutlookStyle
OutlookStyle.aps
OutlookStyle.dsp
OutlookStyle.dsw
OutlookStyle.suo
res
bitmap1.bmp
bmattach.bmp
bmp00001.bmp
bmp00002.bmp
bmp00003.bmp
Flags.bmp
OutlookStyle.ico
OutlookStyleDoc.ico
Toolbar.bmp
toolbar1.bmp
toolbar2.bmp
toolbarf.bmp
UltimateGrid72_Src_Update01.zip
CellTypes
Include
Source
UltimateGrid72_Src_Update02.zip
DataSources
ODBC
OleDB
EditControls
UltimateGrid72_Src_Update03.zip
UltimateGrid72_Src_Update04.zip
UltimateGrid73_src.zip
BuildDLL
Build DLL.dsp
Build DLL.dsw
res
BuildLib
ugmfclib.dsp
ugmfclib.dsw
Lib
Skel
UltimateTCP-IP42_Src_Update01.zip
Ultimate TCP-IP
Include
Security
Include
Source
source
UltimateTCP-IP42_Src_Update02.zip
Examples
Client
Mail
icon1.ico
icon2.ico
MailClientS.suo
test.dsp
test.dsw
UltimateTCP-IP42_Src_Update03.zip
ultimatetoolbox93_src_update01.zip
Ultimate Toolbox
include
source
UltimateToolbox93_Src_Update02.zip
lib
Build DLLs
Build Libs
UltimateToolbox93_Src_Update03.zip
UltimateToolbox93_Src_Update04.zip
UltimateToolbox93_Src_Update05.zip
// ==========================================================================
//				Class Implementation : OXTreeCtrl
// ==========================================================================

// Source file :OXTreeCtrl.cpp

// Version: 9.3

// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
                         
		  
// //////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "OXTreeCtrl.h"

#include "UTBStrOp.h"
#include "UTB64Bit.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#endif

#define _OX_MAX_ITEM_TEXT	300

/////////////////////////////////////////////////////////////////////////////
// COXTreeCtrl

IMPLEMENT_DYNAMIC(COXTreeCtrl, CListCtrl)

COXTreeCtrl::COXTreeCtrl():
m_ptLastClick(0,0),m_wndCal(),m_bInit(FALSE)
{
	m_nIndent= TV_MININDENT;
	m_dwExStyle=0;
	m_dwTCStyle=0;
	m_xtiRoot.SetExpand();
	m_pActiveEditWnd=NULL;
	m_nEditColumn=-1;
	m_nItemHeight=0;
	m_nItemsCount=0;

	m_bClick=FALSE;
	m_bCanEdit=FALSE;
	m_nLastIndex=-1;
	m_nLastColumn=-1;

	m_bCreatingDragImage=FALSE;
	m_hOldDropTarget=NULL;

	m_bFirstTimeHooking=TRUE;

	m_nRedrawFlag=0;

	m_nTimerCheckKeyboardInput=0;
	m_sSearchMask=_T("");

	m_clrHorizontalGrid = 0; // black is the default
	m_clrVerticalGrid = 0; // black is the default
	m_lpfnDefaultCompare = NULL;
}

COXTreeCtrl::~COXTreeCtrl()
{
	m_mapCompareFunctions.RemoveAll();
}


BEGIN_MESSAGE_MAP(COXTreeCtrl, CListCtrl)
	//{{AFX_MSG_MAP(COXTreeCtrl)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_MBUTTONDOWN()
	ON_NOTIFY_REFLECT_EX(NM_KILLFOCUS, OnKillfocus)
	ON_NOTIFY_REFLECT_EX(NM_SETFOCUS, OnSetfocus)
	ON_NOTIFY_REFLECT_EX(LVN_BEGINLABELEDIT, OnBeginlabeledit)
	ON_NOTIFY_REFLECT_EX(LVN_ENDLABELEDIT, OnEndlabeledit)
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_PARENTNOTIFY()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_WM_SIZE()
	ON_WM_KEYDOWN()
	//}}AFX_MSG_MAP
	ON_WM_MEASUREITEM_REFLECT()
	ON_WM_STYLECHANGED()
#ifndef OX_TREECTRL_NOITEMTIPS
	ON_MESSAGE(WM_DOYOUNEEDITEMTIP, OnNeedItemTip)
	ON_MESSAGE(WM_USER_ADJUSTLASTCOLUMN, OnUserAdjustLastColumn)
#endif
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COXTreeCtrl message handlers

void COXTreeCtrl::DrawItem(LPDRAWITEMSTRUCT lpDIS)
	// --- In  :
	// --- Out : 
	// --- Returns :
	//--- Effect :draw item
{
	int itemID=lpDIS->itemID;
	if(itemID == -1)
		return;

	COXTreeItem *xti=(COXTreeItem*)CListCtrl::GetItemData(itemID);

	
	if( xti == NULL )
		return;


	int nLevel=xti->GetItemLevel();
	CRect rcItem(lpDIS->rcItem);

	CDC dc;
	dc.Attach(lpDIS->hDC);

	CRect rcGrid=rcItem;
	rcGrid.left += GetItemIndent(xti);
	switch(lpDIS->itemAction)
	{
	case  ODA_SELECT:
	case  ODA_DRAWENTIRE:
		{
			if(m_bCreatingDragImage)
			{
				COLORREF clrOldForground, clrOldBackground;
				rcItem.left=0;
				LV_COLUMN lvc;
				lvc.mask=LVCF_FMT|LVCF_WIDTH;
				int nCol=0;
				CFont *pOldFont=NULL;
				VERIFY(GetColumn(nCol, &lvc));
				rcItem.right=rcItem.left + lvc.cx;
				if(dc.RectVisible(rcItem))
				{
					DrawItemImages(&dc,xti,itemID,rcItem,0,FALSE);
					clrOldForground=dc.SetTextColor(xti->IsDisabled() ? 
						::GetSysColor(COLOR_3DSHADOW) : (xti->HasColor(nCol) ?
						xti->GetItemColor(nCol) : GetTextColor()));

					if (xti->HasBackColor(nCol))
						clrOldBackground=dc.SetBkColor((!IsWindowEnabled() ? 
							::GetSysColor(COLOR_BTNFACE) : xti->GetItemBackColor(nCol)));
					else
						clrOldBackground=dc.SetBkColor((!IsWindowEnabled() ? 
							::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));

					CString sTxt=GetItemText((HTREEITEM) xti,nCol);
					if(xti->HasFont(nCol))
						pOldFont=dc.SelectObject(xti->GetItemFont(nCol));
					UINT nEllipsisFormat;
					VERIFY(GetItemDrawEllipsis((HTREEITEM)xti,nEllipsisFormat,nCol));
					// draw item's text 
					DrawItemText(&dc,sTxt,rcItem,lvc.fmt,FALSE,
						(!IsWindowEnabled() ? 
						::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()),
						nEllipsisFormat);
					dc.SetTextColor(clrOldForground);
					dc.SetBkColor(clrOldBackground);
		
					if(xti->HasFont(nCol))
					{
						dc.SelectObject(pOldFont);
					}
				}
			}
			else
			{
				BOOL bShowSelAlways=GetShowSelAlways();
				BOOL bFocus=(::GetFocus() == m_hWnd);
				BOOL bShowSel=bShowSelAlways | bFocus;
				BOOL bDropHilited=GetItemState(GetItemFromIndex(itemID),
					TVIS_DROPHILITED)==TVIS_DROPHILITED;
				BOOL bShowItemSel=bShowSel && (((lpDIS->itemState & 
					ODS_SELECTED)==ODS_SELECTED) ||	bDropHilited);
				COLORREF clrOldForground, clrOldBackground;
				int nOffset=GetItemIndent(xti);
				int nFocusRectOffset=rcItem.left + nOffset;
				CRect rcLines=rcItem;
				rcLines.right=rcLines.left + nOffset;
			
				DrawLines(&dc,rcLines,xti,nLevel);
	
				rcItem.left += nOffset;
				LV_COLUMN lvc;
				lvc.mask=LVCF_FMT|LVCF_WIDTH;
				int nCol=0;
				int nColCnt=GetColumnsCount();
				BOOL bRowSel=(BOOL)(m_dwExStyle & TVOXS_ROWSEL);
				for(nCol=0; nCol<nColCnt; nCol++)
				{
					CFont *pOldFont=NULL;
					VERIFY(GetColumn(nCol, &lvc));
					rcItem.right =rcItem.left + lvc.cx;
					if(nCol == 0)
						rcItem.right -= nOffset;
					if(dc.RectVisible(rcItem))
					{
						DrawItemImages(
							&dc,xti,itemID,rcItem,nCol,(bRowSel && bShowItemSel));

						if(nCol == 0)
						{
							nFocusRectOffset=rcItem.left;
						}
							
						clrOldForground=dc.SetTextColor(bShowItemSel && 
							((nCol == 0 || bRowSel) && GetFocus()==this) ?
							::GetSysColor(COLOR_HIGHLIGHTTEXT) : (xti->IsDisabled() ? 
							::GetSysColor(COLOR_3DSHADOW) : (xti->HasColor(nCol) ?
							xti->GetItemColor(nCol) : GetTextColor())));
						
						COLORREF clrBackground = bShowItemSel && (nCol==0 || bRowSel) ? 
							(GetFocus()==this ? ::GetSysColor(COLOR_HIGHLIGHT) : 
							::GetSysColor(COLOR_BTNFACE)) : 
							(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) : 
							((xti->HasBackColor(nCol) ? xti->GetItemBackColor(nCol) : GetTextBkColor())));
						
						clrOldBackground=dc.SetBkColor(clrBackground);

						CString sTxt=GetItemText((HTREEITEM) xti,nCol);
						if(xti->HasFont(nCol))
							pOldFont=dc.SelectObject(xti->GetItemFont(nCol));
						UINT nEllipsisFormat;
						VERIFY(GetItemDrawEllipsis((HTREEITEM)xti,nEllipsisFormat,nCol));
						
						dc.FillSolidRect(rcItem, clrBackground);

						// Draw item's text
						if (nCol != 0)
							rcItem.left += 1;

						DrawItemText(&dc,sTxt,rcItem,lvc.fmt,
							(lpDIS->itemState & ODS_FOCUS) && bFocus && nCol==0 && 
							!bRowSel, bRowSel && bShowItemSel ? 
							(GetFocus()==this ? ::GetSysColor(COLOR_HIGHLIGHT) : 
							::GetSysColor(COLOR_BTNFACE)) : 
							(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) : 
							((xti->HasBackColor(nCol) ? xti->GetItemBackColor(nCol) : GetTextBkColor()))),nEllipsisFormat);

						dc.SetTextColor(clrOldForground);
						dc.SetBkColor(clrOldBackground);

						if(xti->HasFont(nCol))
						{
							dc.SelectObject(pOldFont);
						}
						if(HasGrid(TVOXS_VGRID))
						{
							CPen pen;
							pen.CreatePen(PS_SOLID, 1, m_clrVerticalGrid);
							CPen* pOldPen = (CPen*) dc.SelectObject(&pen);
							dc.MoveTo(rcItem.right-1,rcItem.top);
							dc.LineTo(rcItem.right-1,rcItem.bottom);
							dc.SelectObject(pOldPen);
						}
					}
					rcItem.left =rcItem.right;
				}
				if(HasGrid(TVOXS_HGRID))
				{
					CPen pen;
					pen.CreatePen(PS_SOLID, 1, m_clrHorizontalGrid);
					CPen* pOldPen = (CPen*) dc.SelectObject(&pen);
					
					// draw horizontal grid line
					if(GetDrawGridFullLength())
					{
						CRect clientRect;
						GetClientRect(clientRect);
						dc.MoveTo(clientRect.left,rcGrid.bottom-1);
						dc.LineTo(clientRect.right,rcGrid.bottom-1);
					}
					else
					{
						dc.MoveTo(rcGrid.left,rcGrid.bottom-1);
						dc.LineTo(rcGrid.right,rcGrid.bottom-1);
					}

					dc.SelectObject(pOldPen);
				}
				if((lpDIS->itemState & ODS_FOCUS) && bFocus && bRowSel &&
					!(m_dwExStyle & TVOXS_NOFOCUSRECT))
				{
					rcGrid.left=nFocusRectOffset;
					dc.DrawFocusRect(rcGrid);
				}
			}
		}
		break;
	default:
		ASSERT(FALSE);
	}

	dc.Detach();
}

void COXTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if(GetFocus()!=this)
	{
		SetFocus();
	}
	m_ptLastClick=point;
	UINT nFl;
	int idx=HitTest(point,&nFl);

	HTREEITEM hti=GetItemFromIndex(idx);
	ASSERT(hti);
	COXTreeItem *xti=GetXItem(hti);
	ASSERT(xti);
	m_bCanEdit=FALSE;
	if(idx!=-1)
	{
		if (nFl & TVHT_ONITEMBUTTON)
		{
			Expand(hti,TVE_TOGGLE);
			return;
		}
		if(nFl & TVHT_ONITEM)
		{
			CListCtrl::OnLButtonDown(nFlags,point);
		}
		else
		{
			if(GetPickAnywhere())
			{
				CRect rcItem;
				CListCtrl::GetItemRect(idx,&rcItem,LVIR_BOUNDS);
				rcItem.left+=GetItemIndent(xti);
				if(rcItem.PtInRect(point))
				{
					if((GetKeyState(VK_SHIFT)&0x8000) || 
						(GetKeyState(VK_CONTROL)&0x8000))
					{
						VERIFY(CListCtrl::GetItemPosition(idx,&point));
					}
					CListCtrl::OnLButtonDown(LVHT_ONITEM,point);
				}
			}
		}

		// try to detect subitem to edit label
		CRect rcEdit;
		int nCol=GetEditColumn(xti,&rcEdit);

		m_nLastIndex=idx;
		m_nLastColumn=nCol;
	}
	else
	{
		if((GetExStyle()&TVOXS_MULTISEL)!=0)
		{
			CWnd::OnLButtonDown(nFlags, point);
		}
		m_nLastIndex=-1;
		m_nLastColumn=-1;
	}

	m_bClick=!m_bClick;
}

HTREEITEM COXTreeCtrl::InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, 
								  HTREEITEM hInsertAfter)
{
	if(hParent==NULL)
		hParent=TVI_ROOT;

	COXTreeItem *pParent=GetXItem(hParent);
	if(!pParent)
		return NULL;
	COXTreeItem *pInsAfter;
	if(hInsertAfter == TVI_FIRST)
	{
		pInsAfter=(COXTreeItem *) TVI_FIRST;
	}
	else if(hInsertAfter == TVI_SORT)
	{
		pInsAfter=pParent->FindItemToInsertAfter(lpszItem);
	}
	else
	{
		pInsAfter=GetXItem(hInsertAfter);
	}
	COXTreeItem * pNewItem=new COXTreeItem(lpszItem);
	ASSERT(pParent);
	BOOL bDrawBtn=pParent->NeedDrawButton();
	pParent->AddChild(pNewItem,pInsAfter);
	AddItemToCtrl(pNewItem);
	if(pParent->NeedDrawButton() != bDrawBtn && HasButtons())
	{
		// parent button's state changed, redraw parent
		int idx=GetItemIndexInternal(pParent);
		if(idx != -1)
			CListCtrl::RedrawItems(idx,idx);
	}
	m_nItemsCount++;
	return (HTREEITEM)pNewItem;
}

HTREEITEM COXTreeCtrl::InsertItem(LPTV_INSERTSTRUCT lpTVIS)
{
	if(lpTVIS->hParent==NULL)
		lpTVIS->hParent=TVI_ROOT;

	COXTreeItem *pParent=GetXItem(lpTVIS->hParent);
	if(!pParent)
		return NULL;
	COXTreeItem *pInsAfter;
	if(lpTVIS->hInsertAfter == TVI_FIRST)
	{
		pInsAfter=(COXTreeItem *) TVI_FIRST;
	}
	else if(lpTVIS->hInsertAfter == TVI_SORT)
	{
		pInsAfter=pParent->FindItemToInsertAfter(lpTVIS->item.pszText);
	}
	else
	{
		pInsAfter=GetXItem(lpTVIS->hInsertAfter);
	}
	
	COXTreeItem * pNewItem= new COXTreeItem(lpTVIS->item.pszText);

	BOOL bDrawBtn=pParent->NeedDrawButton();
	pParent->AddChild(pNewItem,pInsAfter);
	lpTVIS->item.mask |= TVIF_HANDLE;
	lpTVIS->item.hItem=(HTREEITEM) pNewItem;
	VERIFY(SetItem(&(lpTVIS->item)));
	AddItemToCtrl(pNewItem);
	if(pParent->NeedDrawButton() != bDrawBtn && HasButtons())
	{
		// parent button's state changed, redraw parent
		int idx=GetItemIndexInternal(pParent);
		if(idx != -1)
			CListCtrl::RedrawItems(idx,idx);
	}
	m_nItemsCount++;
	return (HTREEITEM) pNewItem;
}


HTREEITEM COXTreeCtrl::InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage,
								  int nSelectedImage, UINT nState, 
								  UINT nStateMask, LPARAM lParam, 
								  HTREEITEM hParent, HTREEITEM hInsertAfter)
{
	TV_INSERTSTRUCT tvis;
	tvis.hParent=hParent;
	tvis.hInsertAfter=hInsertAfter;
	tvis.item.mask=nMask;
	tvis.item.state=nState;
	tvis.item.stateMask=nStateMask;
	tvis.item.pszText=(LPTSTR)lpszItem;
	tvis.item.iImage=nImage;
	tvis.item.iSelectedImage=nSelectedImage;
	tvis.item.lParam=lParam;

	return InsertItem(&tvis);
}


HTREEITEM COXTreeCtrl::InsertItem(LPCTSTR lpszItem, 
								  int nImage, 
								  int nSelectedImage, 
								  HTREEITEM hParent/*=TVI_ROOT*/, 
								  HTREEITEM hInsertAfter/*=TVI_LAST*/)
{
	TV_INSERTSTRUCT tvis;
	tvis.hParent=hParent;
	tvis.hInsertAfter=hInsertAfter;
	tvis.item.mask=TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT;
	tvis.item.pszText=(LPTSTR)lpszItem;
	tvis.item.iImage=nImage;
	tvis.item.iSelectedImage=nSelectedImage;

	return InsertItem(&tvis);
}


int COXTreeCtrl::GetItemIndex(HTREEITEM hItem) const
{
	return GetItemIndexInternal(GetXItem(hItem));
}


int COXTreeCtrl::GetItemIndexInternal(COXTreeItem *pItem) const
{
	if(pItem == &m_xtiRoot)
		return -1;
	LV_FINDINFO lvfi;
	lvfi.flags=LVFI_PARAM;
	lvfi.lParam=(LPARAM)pItem;
	return CListCtrl::FindItem(&lvfi);
}

COXTreeItem* COXTreeCtrl::GetXItem(HTREEITEM hti) const
{
	if(hti == TVI_ROOT)
		return &m_xtiRoot;
	if(hti == TVI_FIRST || hti == TVI_LAST)
		return NULL;
#ifdef _DEBUG
	if(hti)
		ASSERT(_CrtIsValidPointer(hti,sizeof(COXTreeItem),FALSE));
#endif
	return (COXTreeItem*)hti;
}

void COXTreeCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	if(GetFocus() != this)
		SetFocus();

	UINT flgs = nFlags;
	int idx   = HitTest(point,&flgs);

   if (idx != -1)
      if (GetPickAnywhere() || (flgs & (TVHT_ONITEM | TVHT_ONITEMBUTTON)))
      {
         Expand((HTREEITEM )CListCtrl::GetItemData(idx),TVE_TOGGLE);
         CListCtrl::OnLButtonDblClk(nFlags,point);
      }
	m_bClick=FALSE;
}

void COXTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	UINT flgs = nFlags;
	int  idx  = HitTest(point,&flgs);

   if (idx != -1)
      if (GetPickAnywhere() || (flgs & (TVHT_ONITEM | TVHT_ONITEMBUTTON)))
         CListCtrl::OnRButtonDown(nFlags,point);
}

void COXTreeCtrl::OnMButtonDown(UINT nFlags, CPoint point) 
{
	UINT flgs = nFlags;
	int  idx  = HitTest(point,&flgs);

   if (idx != -1)
      if (GetPickAnywhere() || (flgs & (TVHT_ONITEM | TVHT_ONITEMBUTTON)))
         CListCtrl::OnMButtonDown(nFlags,point);
}

BOOL COXTreeCtrl::Expand(HTREEITEM hItem, UINT nCode)
{
	COXTreeItem *pItem=GetXItem(hItem);
	ASSERT(pItem);
	if(SendItemExpandingNotify(hItem,nCode))
	{
		return FALSE;// parent voted against!
	}

	SetRedraw(FALSE);
	
	pItem->Expand(nCode,this);

	SetRedraw(TRUE);
	
	CListCtrl::RedrawItems(GetItemIndex(hItem),GetItemIndex(hItem));
	
	SendItemExpandedNotify(hItem,nCode);
	
	return TRUE;
}

int COXTreeCtrl::SetItemAtPos(int pos,COXTreeItem *pItem)
{
	int idx=CListCtrl::InsertItem(pos,LPSTR_TEXTCALLBACK);
	if(idx == -1)
		return -1;
	CListCtrl::SetItemData(idx,(DWORD)PtrToUlong (pItem));
	for(int i=1;i < pItem->GetSubitemsCount();i++)
	{
		LPCTSTR lpszText=GetItemText((HTREEITEM)pItem,i);
		if(lpszText)
		{
			CListCtrl::SetItemText(pos,i,LPSTR_TEXTCALLBACK);
		}
	}

	TV_ITEM tvi;
	::ZeroMemory((void*)&tvi,sizeof(tvi));
	if(pItem->m_tvi.iImage>=0)
	{
		tvi.mask|=TVIF_IMAGE;
		tvi.iImage=pItem->m_tvi.iImage;
	}
	if(pItem->m_tvi.iSelectedImage>=0)
	{
		tvi.mask|=TVIF_SELECTEDIMAGE;
		tvi.iSelectedImage=pItem->m_tvi.iSelectedImage;
	}
	if((pItem->m_tvi.state & INDEXTOSTATEIMAGEMASK(0xF))!=0)
	{
		tvi.state=(pItem->m_tvi.state & INDEXTOSTATEIMAGEMASK(0xF));
		tvi.stateMask=tvi.state;
		tvi.mask|=TVIF_STATE;
	}
	if(tvi.mask!=0)
	{
		tvi.hItem=pItem->m_tvi.hItem;
		tvi.mask|=TVIF_HANDLE;
		VERIFY(SetItem(&tvi));
	}

	return idx;
}

BOOL COXTreeCtrl::AddItemToCtrl(COXTreeItem *pItem)
	// --- In  : item handle
	// --- Out : 
	// --- Returns :Nonzero if successful; otherwise 0
	//--- Effect :
{
	ASSERT(pItem!=NULL);

	if(pItem->pxParent!=NULL && pItem->pxParent->m_tvi.cChildren==0)
		pItem->pxParent->m_tvi.cChildren=1;

	if (pItem->IsAnyParentCollapsed())
		return TRUE;

	if(pItem->IsHidden())
		return TRUE;

	COXTreeItem *pPrevItem=pItem->GetPrevInTree();
	while(pPrevItem != &m_xtiRoot && !pPrevItem->IsVisible())
	{
		pPrevItem=pPrevItem->GetPrevInTree();
		if(!pPrevItem)
		{
			ASSERT(FALSE);
			return FALSE;
		}
	}
	ASSERT(pPrevItem);
	int nIndex;
	if(pPrevItem == &m_xtiRoot)
		nIndex=0;//will be first item!
	else
	{
		nIndex=GetItemIndexInternal(pPrevItem) + 1;
		ASSERT(nIndex);
	}
	BOOL bRet=(-1 != SetItemAtPos(nIndex,pItem));
	return bRet;
}

void COXTreeCtrl::DeleteChildrenItems(COXTreeItem *pItem)
	// --- In  :handle of the item
	// --- Out : 
	// --- Returns :
	//--- Effect :delete children of specified item
{
	COXTreeItem *xti=pItem->pxFirstChild;
	while(xti)
	{
		DeleteChildrenItems(xti);
		int idx=GetItemIndexInternal(xti);
		if(idx!=-1)
		{
			CListCtrl::DeleteItem(idx);
			
		}
		xti=xti->pxNext;
	}
	pItem->DeleteChildren();
	pItem->m_tvi.cChildren=0;
}

void COXTreeCtrl::DrawItemText(CDC *pDC,LPCTSTR sText,CRect& rcTxt,UINT nJustify,
							   BOOL bDrawFocus,COLORREF clrFillOutside,
							   UINT nEllipsisMode)
{

	CRect rcText=rcTxt;
	CRect rcFill=rcTxt;
	// check rect need to be drawn
	if(!pDC->RectVisible(&rcText))
		return;
	// check text
	if(!sText || sText == LPSTR_TEXTCALLBACK)
		return;

	COLORREF clrBack=pDC->GetBkColor();
	if(!rcFill.IsRectEmpty())
		pDC->FillSolidRect(rcFill,clrFillOutside);
	pDC->SetBkColor(clrBack);

	UINT nFormat=DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER;
	nFormat|=nEllipsisMode;

	rcText.DeflateRect(2,0);
	rcFill=rcText;
	pDC->DrawText(sText,rcFill,nFormat|DT_CALCRECT);
	rcFill.top=rcTxt.top;
	rcFill.bottom=rcTxt.bottom;
	rcFill.InflateRect(2,0);
	int nTextSize=rcFill.Width();

	switch(nJustify & LVCFMT_JUSTIFYMASK)
	{
		case LVCFMT_LEFT:
			nFormat|=DT_LEFT;
			rcFill.left=__max(rcFill.left,rcTxt.left);
			rcFill.right=__min(rcFill.right,rcTxt.right);
			break;
		case LVCFMT_RIGHT:
			nFormat|=DT_RIGHT;
			rcFill.right=rcTxt.right;
			rcFill.left=__max(rcFill.right-nTextSize,rcTxt.left);
			break;
		case LVCFMT_CENTER:
			nFormat|=DT_CENTER;
			rcFill.left=__max(rcTxt.left+((rcTxt.Width()-nTextSize)/2),rcTxt.left);
			rcFill.right=__min(rcTxt.right-((rcTxt.Width()-nTextSize)/2)+
				(rcTxt.Width()-nTextSize)%2,rcTxt.right);
			break;
		default:
			ASSERT(FALSE);
			break;
	}

	if(!rcFill.IsRectEmpty())
	{
		pDC->FillSolidRect(rcFill,clrBack);
	}

	// Draw the text
	pDC->SetBkMode(TRANSPARENT);					
	pDC->DrawText(sText,rcText,nFormat);

	if(bDrawFocus && !(m_dwExStyle & TVOXS_NOFOCUSRECT))
	{
		pDC->DrawFocusRect(rcFill);
	}

	return;
}

BOOL COXTreeCtrl::GetShowSelAlways() const
{
	return ((GetStyle() & TVS_SHOWSELALWAYS) == TVS_SHOWSELALWAYS);
}


BOOL COXTreeCtrl::OnKillfocus(NMHDR* pNMHDR, LRESULT* pResult) 
	// --- In  :
	// --- Out : 
	// --- Returns :
	//--- Effect :
{
	UNREFERENCED_PARAMETER(pNMHDR);
	RefreshFocusItem();
	*pResult=0;

	return FALSE;
}

void COXTreeCtrl::RefreshFocusItem()
{
	int nFocusItem=CListCtrl::GetNextItem(-1,LVNI_SELECTED);
	while(nFocusItem != -1)
	{
		RedrawItems(nFocusItem,nFocusItem);
		nFocusItem=CListCtrl::GetNextItem(nFocusItem,LVNI_SELECTED);
	}
}

BOOL COXTreeCtrl::OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult) 
{
	UNREFERENCED_PARAMETER(pNMHDR);
	RefreshFocusItem();
	*pResult=0;
	m_bClick=FALSE;

	return FALSE;
}

CImageList* COXTreeCtrl::SetImageList(CImageList* pImageList, int nImageList)
{
	switch(nImageList)
	{
	case TVSIL_NORMAL:
		nImageList=LVSIL_SMALL;
		break;
	case TVSIL_STATE:
		nImageList=LVSIL_STATE;
		break;
	default:
		TRACE(_T("COXTreeCtrl::SetImageList: unknown image list type!\n"));
		return NULL;
	}

	return CListCtrl::SetImageList(pImageList,nImageList);
}

BOOL COXTreeCtrl::HasButtons() const
{
	return (m_dwTCStyle & TVS_HASBUTTONS);
}

BOOL COXTreeCtrl::HasLines() const
{
	return (m_dwTCStyle & TVS_HASLINES);
}

BOOL COXTreeCtrl::HasLinesAtRoot() const
{
	return (m_dwTCStyle & TVS_LINESATROOT);
}


int COXTreeCtrl::GetItemStateIndex(int nItem) const
{
	LV_ITEM lvI;
	lvI.mask=LVIF_IMAGE | LVIF_STATE;
	lvI.iItem=nItem;
	lvI.iSubItem  =0;
	lvI.state=0;
	lvI.stateMask=INDEXTOSTATEIMAGEMASK(0xF);
	if (CListCtrl::GetItem(&lvI))
		return STATEIMAGEMASKTOINDEX(lvI.state) - 1;
	else
		return -1;
}

void COXTreeCtrl::DrawLines(CDC *pDC, LPRECT rLines, COXTreeItem *pItem, int nLev)
{
	int nLevel=nLev;
	CPen penBtn(PS_SOLID,1,::GetSysColor(COLOR_3DSHADOW));
	pDC->ExtTextOut(0,0,ETO_OPAQUE,rLines,_T(""),0,NULL);
	CRect rcLines(rLines);
	if(!rcLines.IsRectEmpty())
	{
		if (pItem != NULL && pItem->HasBackColor())
			pDC->FillSolidRect(rcLines,(!IsWindowEnabled() ? 
				::GetSysColor(COLOR_BTNFACE) : pItem->GetItemBackColor()));
		else
		{
			if (IsPropertiesWnd())
				pDC->FillSolidRect(rcLines, ::GetSysColor(COLOR_BTNFACE));
			else
				pDC->FillSolidRect(rcLines,(!IsWindowEnabled() ? 
					::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));
		}
	}
	CRect rcStep;
	rcStep=rcLines;
	rcStep.left=rcStep.right - m_nIndent;
	COXTreeItem *xti=pItem;
	int nLineMode; 
	if(xti->IsLastUnhidden() && GetItemIndexInternal(xti)==0)
		nLineMode=0;	// first & last node at the same time
	else if(GetItemIndexInternal(xti)==0)
		nLineMode=4;	// first node 
	else if(xti->IsLastUnhidden())
		nLineMode=2;	// last node 
	else
		nLineMode=3;	// there are node(s) below

	if(HasLines())
		DrawLine(pDC,&m_penLines,rcStep,nLineMode);
		
	CPen *pOld=pDC->SelectObject(&penBtn);
	if(HasButtons() && pItem->NeedDrawButton())
	{
		CRect rcButton;
		CalcBtnRect(&rcButton,rcStep);
		DrawButton(pDC,rcButton,pItem->IsExpanded());
	}
	pDC->SelectObject(pOld);
	if(HasLines())
	{
		while(nLevel > 0)
		{
			xti=xti->pxParent;
			rcStep.OffsetRect(-m_nIndent,0);
			if(!xti->IsLastUnhidden())
				DrawLine(pDC,&m_penLines,rcStep,1);
			nLevel--;
		}
	}
}

void COXTreeCtrl::DrawLine(CDC *pDC, CPen* pPen, CRect& rc, int nMode)
{
	CPen *penOld=pDC->SelectObject(pPen);

	switch(nMode)
	{
	case 0:
		pDC->MoveTo(rc.left + rc.Width()/2 - 1,rc.top + rc.Height()/2);
		pDC->LineTo(rc.right,rc.top + rc.Height()/2);
		break;

	case 1:
		pDC->MoveTo(rc.left + rc.Width()/2,rc.top - 1);
		pDC->LineTo(rc.left + rc.Width()/2,rc.bottom);
		break;
	
	case 2:
		pDC->MoveTo(rc.left + rc.Width()/2,rc.top - 1);
		pDC->LineTo(rc.left + rc.Width()/2,rc.top + rc.Height()/2);
		pDC->LineTo(rc.right,rc.top + rc.Height()/2);
		break;
	
	case 3:
		pDC->MoveTo(rc.left + rc.Width()/2,rc.top - 1);
		pDC->LineTo(rc.left + rc.Width()/2,rc.bottom);
		pDC->MoveTo(rc.left + rc.Width()/2,rc.top + rc.Height()/2);
		pDC->LineTo(rc.right,rc.top + rc.Height()/2);
		break;
	
	case 4:
		pDC->MoveTo(rc.left + rc.Width()/2,rc.bottom + 1);
		pDC->LineTo(rc.left + rc.Width()/2,rc.top + rc.Height()/2);
		pDC->LineTo(rc.right,rc.top + rc.Height()/2);
		break;
	
	default:
		ASSERT(FALSE);
	}

	if(penOld!=NULL)
	{
		pDC->SelectObject(penOld);
	}
}

void COXTreeCtrl::DrawButton(CDC *pDC,CRect& rcButton,BOOL bExpand)
{
	pDC->Rectangle(rcButton);

	CRect rcInnerSpace=rcButton;
	rcInnerSpace.DeflateRect(1,1);
	if(!rcInnerSpace.IsRectEmpty())
	{
		pDC->FillSolidRect(rcInnerSpace,(!IsWindowEnabled() ? 
			::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));
	}

	CPen penPlusMinus;
	penPlusMinus.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT));
	CPen* pOldPen = pDC->SelectObject(&penPlusMinus);

	pDC->MoveTo(rcButton.left + 2,rcButton.top + rcButton.Height()/2);
	pDC->LineTo(rcButton.right-2,rcButton.top + rcButton.Height()/2);
	if(!bExpand)
	{
		pDC->MoveTo(rcButton.left + rcButton.Width()/2,rcButton.top +2);
		pDC->LineTo(rcButton.left + rcButton.Width()/2,rcButton.bottom -2);
	}

	pDC->SelectObject(pOldPen);
}

void COXTreeCtrl::CalcBtnRect(CRect *prcButton,CRect& rcStep)
{
	(*prcButton)=rcStep;
	int nSide=__max((rcStep.Height()*5)/10,9);
	int offx =(rcStep.Width() - nSide + 1)/2;
	int offy=(rcStep.Height() - nSide + 1)/2;
	prcButton->top += offy;
	prcButton->bottom=prcButton->top +nSide;
	prcButton->left += offx;
	prcButton->right=prcButton->left + nSide;
}

int COXTreeCtrl::HitTest(CPoint pt, UINT* pFlags) const
{
	UINT nListFlags;
	int idx=CListCtrl::HitTest(pt,&nListFlags);
	if(!pFlags)
		return idx;
	(*pFlags)=0;
	if(idx != -1)
	{
		CRect rcItem;
		COXTreeItem *xti=(COXTreeItem *)CListCtrl::GetItemData(idx);
		if(CListCtrl::GetItemRect(idx,&rcItem,LVIR_BOUNDS))
		{
			int nIndent=-1;
			CRect rcButton,rcText,rcImage,rcStateImage;
			GetItemPartRect(rButton,xti,&rcButton,&nIndent);
			GetItemPartRect(rImage,xti,&rcImage,&nIndent);
			GetItemPartRect(rStateImage,xti,&rcStateImage,&nIndent);
			GetItemPartRect(rText,xti,&rcText,&nIndent);
			*pFlags=TVHT_ONITEM;
			if(rcText.PtInRect(pt))
				(*pFlags) |= TVHT_ONITEMLABEL;
			else
			if(rcImage.PtInRect(pt))
				(*pFlags) |= TVHT_ONITEMICON;
			else
			if(rcStateImage.PtInRect(pt))
				(*pFlags) |= TVHT_ONITEMSTATEICON;
			else
			if(rcButton.PtInRect(pt))
				(*pFlags) |= TVHT_ONITEMBUTTON;
			else
			if(rcItem.PtInRect(pt))
				(*pFlags) |= TVHT_TORIGHT;
			else
			{
				(*pFlags) |= TVHT_NOWHERE;
				(*pFlags) &= ~TVHT_ONITEM;
			}
		}
	}
	if ((*pFlags)==0)
	{
		if (nListFlags&LVHT_ABOVE)
			*pFlags=TVHT_ABOVE;
		else if (nListFlags&LVHT_BELOW)
			*pFlags=TVHT_BELOW;
		else if (nListFlags&LVHT_TOLEFT)
			*pFlags=TVHT_TOLEFT;
		else if (nListFlags&LVHT_TORIGHT)
			*pFlags=TVHT_TORIGHT;
		else if (nListFlags&LVHT_NOWHERE)
			*pFlags=TVHT_NOWHERE;
	}

	return idx;
}


HTREEITEM COXTreeCtrl::HitTest(TVHITTESTINFO* pHitTestInfo) const
{
	ASSERT(pHitTestInfo!=NULL);
	pHitTestInfo->hItem=NULL;
	int nIndex=HitTest(pHitTestInfo->pt,&pHitTestInfo->flags);
	if(nIndex>=0)
	{
		pHitTestInfo->hItem=GetItemFromIndex(nIndex);
	}
	return pHitTestInfo->hItem;
}


BOOL COXTreeCtrl::Init()
{
	if(m_bInit)
		return TRUE;

	// create line pen
	LOGBRUSH logBrush;
	logBrush.lbColor=GetSysColor(COLOR_3DSHADOW);
	logBrush.lbStyle=BS_SOLID;
	logBrush.lbHatch=HS_HORIZONTAL;
	if (!m_penLines.CreatePen(PS_COSMETIC | PS_ALTERNATE, 1, &logBrush, 0, NULL))
	{
		if (!m_penLines.CreatePen(PS_COSMETIC, 1, &logBrush, 0, NULL))
		{
			TRACE(_T("COXTreeCtrl::Init: Error creating the lines Pen\n"));
			return FALSE;
		}
	}
	CRect rClient;
	GetClientRect(&rClient);
	// insert at least one column initially
	if(CListCtrl::InsertColumn(0,_T(""),LVCFMT_LEFT,rClient.Width()) == -1)
	{
		TRACE(_T("COXTreeCtrl::Init: Error inserting column\n"));
		return FALSE;
	}
	VERIFY(SetBkColor(::GetSysColor(COLOR_WINDOW)));
	VERIFY(SetTextBkColor(::GetSysColor(COLOR_WINDOW)));
	VERIFY(SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)));
	
	// subclass header control
	HWND hWnd=GetHeaderCtrlHandle();
	if(hWnd!=NULL)
	{
		if(!::IsWindow(m_wndHdr.GetSafeHwnd()))
			VERIFY(m_wndHdr.SubclassWindow(hWnd));
		else
			ASSERT(m_wndHdr.GetSafeHwnd()==hWnd);
	}

	m_bInit=TRUE;

	return TRUE;
}

void COXTreeCtrl::PreSubclassWindow() 
{
	_AFX_THREAD_STATE* pThreadState=AfxGetThreadState();
	// hook not already in progress
	if(pThreadState->m_pWndInit==NULL)
	{
		VERIFY(Init());
	}

	CListCtrl::PreSubclassWindow();
	DWORD dwStyle=CListCtrl::GetStyle();

	ASSERT(dwStyle & LVS_REPORT);
	ASSERT(dwStyle & LVS_OWNERDRAWFIXED);
	ASSERT(!(dwStyle & LVS_SORTASCENDING));
	ASSERT(!(dwStyle & LVS_SORTDESCENDING));

	if(dwStyle & LVS_SHOWSELALWAYS)
		m_dwTCStyle |= TVS_SHOWSELALWAYS;
	if(dwStyle & LVS_EDITLABELS)
		m_dwTCStyle |= TVS_EDITLABELS;
	
	if(dwStyle & LVS_NOCOLUMNHEADER)
		m_dwExStyle &= ~TVOXS_COLUMNHDR;
	else
		m_dwExStyle |= TVOXS_COLUMNHDR;

	if(dwStyle & LVS_SINGLESEL)
		m_dwExStyle &= ~TVOXS_MULTISEL;
	else
		m_dwExStyle |= TVOXS_MULTISEL;

	if(dwStyle & LVS_NOSCROLL)
		m_dwExStyle |= TVOXS_NOSCROLL;
	else
		m_dwExStyle &= ~TVOXS_NOSCROLL;

	if(dwStyle & LVS_NOSORTHEADER)
		m_dwExStyle |= TVOXS_NOSORTHEADER;
	else
		m_dwExStyle &= ~TVOXS_NOSORTHEADER;

	if(dwStyle & LVS_SHAREIMAGELISTS)
		m_dwExStyle |= TVOXS_SHAREIMAGELISTS;
	else
		m_dwExStyle &= ~TVOXS_SHAREIMAGELISTS;

#ifndef OX_TREECTRL_NOITEMTIPS
	m_dwExStyle |= TVOXS_ITEMTIPS;
#endif
}

int COXTreeCtrl::GetItemIndent(COXTreeItem *pItem) const
{
	if (IsPropertiesWnd())
	{
		// We have a properies window
		if((HasLines() || HasButtons()) && HasLinesAtRoot())
			return m_nIndent;
		else
			return 0;
	}
	
	int nLevel=pItem->GetItemLevel();
	int nIndent;
	if((HasLines() || HasButtons()) && HasLinesAtRoot())
		nIndent=m_nIndent *nLevel;
	else
		nIndent=m_nIndent *(nLevel-1);
	return nIndent;
}

void COXTreeCtrl::GetItemPartRect(COXTreeCtrl::eItemPartRect eType,
								  COXTreeItem *pItem,CRect *rTarget,
								  int *nIndent) const
{
	ASSERT_POINTER(pItem,COXTreeItem);
	if((*nIndent) == -1)
		(*nIndent)=GetItemIndent(pItem);
	int nIndex=GetItemIndexInternal(pItem);

	CRect rcItem;
	CListCtrl::GetItemRect(nIndex,&rcItem,LVIR_BOUNDS);

	CImageList *pImgList=CListCtrl::GetImageList(LVSIL_SMALL);
	CImageList *pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);

	CRect rcLastIndent=rcItem;
	if(*nIndent)
	{
		rcLastIndent.right=rcItem.left + *nIndent;
		rcLastIndent.left=rcLastIndent.right - m_nIndent;
	}
	else
	{
		rcLastIndent.SetRectEmpty();
	}
	

	switch(eType)
	{
	case rButton://button rect
		{
			if(!HasButtons())
			{
				rTarget->SetRectEmpty();
			}
			else
			{
				(*rTarget)=rcLastIndent;
				int nSide=(rcLastIndent.Height()*5)/10;
				int offx =(rcLastIndent.Width() - nSide)/2;
				int offy=(rcLastIndent.Height() - nSide)/2;
				rTarget->top += offy;
				rTarget->bottom -= offy;
				rTarget->left += offx;
				rTarget->right -= offx;
			}
		}
		break;

	case rImage:// item image rect
		{
			if(pImgList == NULL)
			{
				// no image list
				rTarget->SetRectEmpty();
				return;
			}
			int nStateOffsetX;
			IMAGEINFO imgInfo;
			if(pStateImgList && GetItemStateIndex(nIndex) != -1)
			{
				pStateImgList->GetImageInfo(0,&imgInfo);
				nStateOffsetX=imgInfo.rcImage.right - imgInfo.rcImage.left;
			}
			else
				nStateOffsetX=0;
			pImgList->GetImageInfo(0,&imgInfo);
			CRect rcImage(imgInfo.rcImage);
			rTarget->left=rcItem.left + *nIndent + nStateOffsetX;
			rTarget->top=rcItem.bottom - rcImage.Height();
			rTarget->right=rTarget->left + rcImage.Width();
			rTarget->bottom=rcItem.bottom;
		}
		break;

	case rStateImage:
		{
			if(pStateImgList == NULL)
				rTarget->SetRectEmpty();
			else
			{
				IMAGEINFO imgInfo;
				pStateImgList->GetImageInfo(0,&imgInfo);
				CRect rcStateImage(imgInfo.rcImage);
				rTarget->left=rcItem.left + *nIndent;
				rTarget->top=rcItem.bottom - rcStateImage.Height();
				rTarget->right=rTarget->left + rcStateImage.Width();
				rTarget->bottom=rcItem.bottom;
			}
		}
		break;

	case rText:
		{
			CSize szText=GetColTextExtent(nIndex,0);
			CRect rcText;
			LV_COLUMN lvc;
			memset(&lvc,0,sizeof(LV_COLUMN));
			lvc.mask=LVCF_FMT;
			ASSERT(GetColumn(0, &lvc));
			int nImgWidth=0;
			IMAGEINFO imgInfo;
			if(pImgList)
			{
				pImgList->GetImageInfo(0,&imgInfo);
				CRect rcImg(imgInfo.rcImage);
				nImgWidth += rcImg.Width();
			}
			if(pStateImgList && GetItemStateIndex(nIndex) != -1)
			{
				pStateImgList->GetImageInfo(0,&imgInfo);
				CRect rcImg(imgInfo.rcImage);
				nImgWidth += rcImg.Width();
			}
			rcText.top=rcItem.top;
			rcText.bottom=rcItem.bottom;
			szText.cx=__min(szText.cx,GetColumnWidth(0)-nImgWidth-(*nIndent));
			int fmt=lvc.fmt & LVCFMT_JUSTIFYMASK;
			switch(fmt)
			{
			case LVCFMT_LEFT:
				{
					rcText.left=rcItem.left + (*nIndent) + nImgWidth;
					rcText.right=rcText.left + szText.cx;
				}
				break;
			case LVCFMT_RIGHT:
				{
					rcText.right=rcItem.left + GetColumnWidth(0);
					rcText.left=rcText.right - szText.cx;
				}
				break;
			case LVCFMT_CENTER:
				{
					int dx=(GetColumnWidth(0)-nImgWidth-(*nIndent)-szText.cx)/2;
					if(dx < 0)
						dx=0;
					rcText.left=rcItem.left + (*nIndent) + nImgWidth + dx;
					rcText.right=rcText.left + GetColumnWidth(0) - dx;
				}
				break;
			default:
				ASSERT(FALSE);
			}

			(*rTarget)=rcText;
		}
		break;
	default:
		// unknown kind of rect passed!
		ASSERT(FALSE);
		break;
	}

}

CSize COXTreeCtrl::GetColTextExtent(int nIndex,int nCol) const
	// --- In  :
	// --- Out : 
	// --- Returns :dimension of specified item's text
	//--- Effect :
{
	ASSERT(nCol <= GetColumnsCount());//column number must be valid!

	COXTreeItem *xti=(COXTreeItem*)CListCtrl::GetItemData(nIndex);
	ASSERT_POINTER(xti,COXTreeItem);
	
	CString sText=GetItemText((HTREEITEM) xti,nCol);
	CWnd* pWnd=(CWnd*)this;
	CDC *pDC=pWnd->GetDC();
	CFont * pOldFont=NULL;
	if(xti->HasFont(nCol))
		pOldFont=pDC->SelectObject(xti->GetItemFont(nCol));

	CSize sz=pDC->GetTextExtent(sText);
	sz.cx=__min(sz.cx,GetColumnWidth(nCol));
	if(xti->HasFont(nCol))
		 pDC->SelectObject(pOldFont);
	pWnd->ReleaseDC(pDC);
	return sz;
}

int COXTreeCtrl::GetColumnsCount() const
{
	int cnt=0;
	LV_COLUMN lvc;
	memset(&lvc, 0, sizeof(LV_COLUMN));
	lvc.mask=LVCF_FMT;
	while(GetColumn(cnt, &lvc))
		cnt++;
	return cnt;
}

void COXTreeCtrl::DrawItemImages(CDC *pDC, COXTreeItem* xti, int nItem, 
								 CRect& rcItem, int nCol, BOOL bRowSel)
{
	UNREFERENCED_PARAMETER(nItem);

	CImageList *pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);
	CImageList *pImgList=CListCtrl::GetImageList(LVSIL_SMALL);

	IMAGEINFO imi;
	CRect rcErase;
	CRect rcImage;
	CPoint ptStart;
	if(pStateImgList && nCol == 0)
	{
		int idx=STATEIMAGEMASKTOINDEX(xti->m_tvi.state)-1;
		if(idx != -1)
		{
			// ask the image size
			pStateImgList->GetImageInfo(idx,&imi);
			// clear the entry image rect
			rcErase=rcItem;
			rcImage=imi.rcImage;
			rcErase.right=rcErase.left + rcImage.Width();
/*			The COXTreeCtrl did not paint checkboxes properly when the
			control lost focus, in this situation all check boxes would
			be painted with the background of COLOR_BTNFACE.
			pDC->FillSolidRect(
				&rcErase,((GetFocus()!=this || !IsWindowEnabled()) ? 
				::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));*/
			ptStart=rcItem.TopLeft();
			if(rcImage.Height()<rcErase.Height())
			{
				ptStart.y+=(rcErase.Height()-rcImage.Height())/2;
			}
			// now draw the state img
			pStateImgList->Draw(pDC,idx,ptStart,ILD_TRANSPARENT);
			// Move left of the item rect to draw text later
			rcItem.left += CRect(imi.rcImage).Width();
		}
	}
	if(nCol == 0)
	{
		TV_ITEM tvi;
		memset(&tvi,0,sizeof(tvi));
		// retreive item's images and state
		tvi.mask=TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_HANDLE | TVIF_STATE;
		tvi.stateMask=TVIS_SELECTED;
		tvi.hItem=(HTREEITEM)xti;
		if(!GetItem(&tvi))
			return;
		if(pImgList)
		{
			int nImg;
			if(tvi.state & TVIS_SELECTED)
			{
				nImg=tvi.iSelectedImage;
			}
			else
			{
				nImg=tvi.iImage;
			}
			if(nImg==-1)
			{
				return;
			}
			// ask the image size
			pImgList->GetImageInfo(nImg,&imi);
			// clear the entry image rect
			rcErase=rcItem;
			rcImage=imi.rcImage;
			rcErase.right=rcErase.left + rcImage.Width();

			if (xti->HasBackColor(nCol))
				pDC->FillSolidRect(&rcErase,
					(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) : xti->GetItemBackColor(nCol)));
			else
				pDC->FillSolidRect(&rcErase,
					(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));

			ptStart=rcItem.TopLeft();
			if(rcImage.Height()<rcErase.Height())
			{
				ptStart.y+=(rcErase.Height()-rcImage.Height())/2;
			}
			pImgList->Draw(pDC,nImg,ptStart,ILD_TRANSPARENT);
			rcItem.left += CRect(imi.rcImage).Width();
		}
	}
	else
	{
		int nImg=xti->GetSubItemImage(nCol);
		if(nImg >= 0)
		{
			ASSERT(nImg < pImgList->GetImageCount());
			COLORREF clrBack=CLR_NONE;
			pImgList->GetImageInfo(nImg,&imi);
			// ask the image size
			pImgList->GetImageInfo(nImg,&imi);
			// clear the entry image rect
			rcErase=rcItem;
			rcImage=imi.rcImage;
			rcErase.right=rcErase.left + CRect(imi.rcImage).Width();
			// if entry row selection mode set, set subitem image
			// background color
			if(bRowSel)
			{
				if (xti->HasBackColor(nCol))
				{
					clrBack=pImgList->SetBkColor(
						(GetFocus()!=this || !IsWindowEnabled()) ? 
						::GetSysColor(COLOR_BTNFACE) :  xti->GetItemBackColor(nCol));
					COLORREF clrBkDC=pDC->GetBkColor();
					pDC->FillSolidRect(&rcErase,
						(GetFocus()!=this || !IsWindowEnabled()) ? 
						::GetSysColor(COLOR_BTNFACE) :  xti->GetItemBackColor(nCol));
					pDC->SetBkColor(clrBkDC);
				}
				else
				{
					clrBack=pImgList->SetBkColor(
						(GetFocus()!=this || !IsWindowEnabled()) ? 
						::GetSysColor(COLOR_BTNFACE) : ::GetSysColor(COLOR_HIGHLIGHT));
					COLORREF clrBkDC=pDC->GetBkColor();
					pDC->FillSolidRect(&rcErase,
						(GetFocus()!=this || !IsWindowEnabled()) ? 
						::GetSysColor(COLOR_BTNFACE) : ::GetSysColor(COLOR_HIGHLIGHT));
					pDC->SetBkColor(clrBkDC);
				}
			}
			else
			{
				if (xti->HasBackColor(nCol))
					pDC->FillSolidRect(&rcErase,
						(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) : xti->GetItemBackColor(nCol)));
				else
					pDC->FillSolidRect(&rcErase,(!IsWindowEnabled() ? 
						::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));
			}

			ptStart=rcItem.TopLeft();
			if(rcImage.Height()<rcErase.Height())
			{
				ptStart.y+=(rcErase.Height()-rcImage.Height())/2;
			}
			pImgList->Draw(pDC,nImg,ptStart,bRowSel ? ILD_FOCUS : ILD_TRANSPARENT);
			if(bRowSel)
			{
				pImgList->SetBkColor(clrBack);
			}
			rcItem.left += CRect(imi.rcImage).Width();
		}
	}
}	


BOOL COXTreeCtrl::SetItem(TV_ITEM *pTVI)
{
	// user must provide a valid handle
	ASSERT(pTVI->mask & TVIF_HANDLE);
	COXTreeItem *xti=GetXItem(pTVI->hItem);
	ASSERT(xti);
	UINT uMaskCb=0;// mask for send TVN_SETDISPINFO
	
	if(pTVI->mask & TVIF_IMAGE)
	{
		xti->m_tvi.iImage=pTVI->iImage;
		if(pTVI->iImage == I_IMAGECALLBACK)
			uMaskCb |= TVIF_IMAGE;
	}

	if(pTVI->mask & TVIF_TEXT)
	{
		if(pTVI->pszText == LPSTR_TEXTCALLBACK)
		{
			if(xti->m_tvi.pszText && xti->m_tvi.pszText != LPSTR_TEXTCALLBACK)
				delete [] xti->m_tvi.pszText;

			xti->m_tvi.pszText=LPSTR_TEXTCALLBACK;
			uMaskCb |= TVIF_TEXT;
		}
		else
		{
			// allocate space for new item text and copy string
			TCHAR * pChar=new TCHAR[_tcslen(pTVI->pszText) + 1];
			UTBStr::tcscpy(pChar, _tcslen(pTVI->pszText) + 1, pTVI->pszText);
			// The user specified new text for item
			if(xti->m_tvi.pszText && xti->m_tvi.pszText != LPSTR_TEXTCALLBACK)
				delete [] xti->m_tvi.pszText;
			xti->m_tvi.pszText=pChar;
		}
	}

	if (pTVI->mask & TVIF_STATE)
	{
		xti->m_tvi.state &= ~(pTVI->stateMask);
		xti->m_tvi.state |= pTVI->state;
		if (pTVI->stateMask & TVIS_STATEIMAGEMASK)
		{
			xti->m_tvi.state |= (pTVI->state & TVIS_STATEIMAGEMASK);
		}			
		if (pTVI->stateMask & TVIS_OVERLAYMASK)
		{
			xti->m_tvi.state |= (pTVI->state & TVIS_OVERLAYMASK) ? TVIS_OVERLAYMASK : 0;
		}
		if (pTVI->stateMask & TVIS_CUT)
		{
			xti->m_tvi.state |= (pTVI->state & TVIS_CUT) ? TVIS_CUT : 0;
		}
		if (pTVI->stateMask & TVIS_DROPHILITED)
		{
			xti->m_tvi.state |= (pTVI->state & TVIS_DROPHILITED) ? TVIS_DROPHILITED : 0;
		}
		if(pTVI->stateMask & TVIS_EXPANDED)
		{
			xti->m_tvi.state |= (pTVI->state & TVIS_EXPANDED) ? TVIS_EXPANDED : 0;
		}
	}
	
	if(pTVI->mask & TVIF_PARAM)
	{
		xti->m_tvi.lParam=pTVI->lParam;
	}

	if(pTVI->mask & TVIF_SELECTEDIMAGE)
	{
		xti->m_tvi.iSelectedImage=pTVI->iSelectedImage;
		if(pTVI->iSelectedImage == I_IMAGECALLBACK)
			uMaskCb |= TVIF_SELECTEDIMAGE;
	}

	if(pTVI->mask & TVIF_CHILDREN)
	{
		xti->m_tvi.cChildren=pTVI->cChildren;
	}

	if(uMaskCb != 0)
	{
		// If any callback detected, send TVN_SETDISPINFO notification to parent
		pTVI->mask=uMaskCb;
		SendSetDispInfoNotify(pTVI);
	}

	// Now translate TVIF_xxx to LVIF_xxx

	int nItem=GetItemIndexInternal(xti);
	if(nItem != -1) // item currently in list ctrl
	{
		LV_ITEM lvi;
		memset(&lvi, 0, sizeof(LV_ITEM));
		lvi.iItem=nItem;
		lvi.iSubItem=0;
 		if (pTVI->mask & TVIF_IMAGE)
		{
			lvi.mask |= LVIF_IMAGE;
			lvi.iImage=pTVI->iImage;
		}
		if (pTVI->mask & TVIF_STATE)
		{
			lvi.mask |= LVIF_STATE;
			if (pTVI->stateMask & TVIS_STATEIMAGEMASK)
			{
				lvi.state |= (pTVI->state & TVIS_STATEIMAGEMASK);
				lvi.stateMask |= LVIS_STATEIMAGEMASK;
			}			
			if (pTVI->stateMask & TVIS_SELECTED)
			{
				lvi.state |= (pTVI->state & TVIS_SELECTED) ? LVIS_SELECTED : 0;
				lvi.stateMask |= LVIS_SELECTED;
			}
			if (pTVI->stateMask & TVIS_OVERLAYMASK)
			{
				lvi.state |= (pTVI->state & TVIS_OVERLAYMASK) ? LVIS_OVERLAYMASK : 0;
				lvi.stateMask |= LVIS_OVERLAYMASK;
			}
			if (pTVI->stateMask & TVIS_CUT)
			{
				lvi.state |= (pTVI->state & TVIS_CUT) ? LVIS_CUT : 0;
				lvi.stateMask |= LVIS_CUT;
			}
			if (pTVI->stateMask & TVIS_DROPHILITED)
			{
				lvi.state |= (pTVI->state & TVIS_DROPHILITED) ? LVIS_DROPHILITED : 0;
				lvi.stateMask |= LVIS_DROPHILITED;
			}
			if(pTVI->stateMask & TVIS_EXPANDED)
			{
				UINT nCode=(pTVI->state & TVIS_EXPANDED)? TVE_EXPAND : TVE_COLLAPSE;
				Expand(pTVI->hItem,nCode);
			}
		}
		if(!CListCtrl::SetItem(&lvi))
			return FALSE;
	}

	if((m_hOldDropTarget!=pTVI->hItem) && (nItem!=-1) && 
		(pTVI->mask&TVIF_STATE) && (pTVI->stateMask&TVIS_DROPHILITED) && 
		(pTVI->state&TVIS_DROPHILITED))
	{
		if(m_hOldDropTarget!=NULL)
		{
			SetItemState(m_hOldDropTarget,0,TVIS_DROPHILITED);
		}
		m_hOldDropTarget=pTVI->hItem;
		UpdateWindow();
	}

	return TRUE;
}

void COXTreeCtrl::SendSetDispInfoNotify(TV_ITEM* pTVI)
{
	TV_DISPINFO di;

	di.hdr.code	 =TVN_SETDISPINFO;
	di.hdr.hwndFrom=GetSafeHwnd();
	di.hdr.idFrom  =GetDlgCtrlID();

	di.item=*pTVI;

	//Now send TVN_SETDISPINFO notification message to parent 
	GetParent()->SendMessage(WM_NOTIFY,di.hdr.idFrom,(LPARAM)&di);
}

BOOL COXTreeCtrl::SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR lpszItem, int nImage, 
						  int nSelectedImage, UINT nState, UINT nStateMask, 
						  LPARAM lParam)
{
	UNREFERENCED_PARAMETER(nStateMask);
	UNREFERENCED_PARAMETER(nState);
	TV_ITEM tvi;
	memset(&tvi,0,sizeof(tvi));
	tvi.mask=nMask;
	tvi.hItem=hItem;
	tvi.pszText=(LPTSTR)lpszItem;
	tvi.iImage=nImage;
	tvi.iSelectedImage=nSelectedImage;
	tvi.lParam=lParam;
	return SetItem(&tvi);
}


BOOL COXTreeCtrl::GetItem(TV_ITEM *pTVI) const
{
	COXTreeItem *xti=GetXItem(pTVI->hItem);
	ASSERT(xti);
	UINT uMaskCb=0;// mask for send TVN_GEIDISPINFO if nesessary
	
	if(pTVI->mask & TVIF_TEXT)
	{
		if(xti->m_tvi.pszText == LPSTR_TEXTCALLBACK)
		{
			uMaskCb |= TVIF_TEXT;
		}
		else if(xti->m_tvi.pszText)
		{
			UTBStr::tcsncpy(pTVI->pszText, pTVI->cchTextMax, xti->m_tvi.pszText,pTVI->cchTextMax);
		}
	}
	
	if(pTVI->mask & TVIF_IMAGE)
	{
		if(xti->m_tvi.iImage == I_IMAGECALLBACK)
			uMaskCb |= TVIF_IMAGE;
		pTVI->iImage=xti->m_tvi.iImage;
	}

	if(pTVI->mask & TVIF_PARAM)
		pTVI->lParam=xti->m_tvi.lParam;
	
	if(pTVI->mask & TVIF_SELECTEDIMAGE)
	{
		if(xti->m_tvi.iSelectedImage == I_IMAGECALLBACK)
			uMaskCb |= TVIF_SELECTEDIMAGE;
		pTVI->iSelectedImage=xti->m_tvi.iSelectedImage;
	}

	if (pTVI->mask & TVIF_STATE)
	{
		int idx=GetItemIndexInternal(xti);
		xti->m_tvi.state &= ~(TVIS_SELECTED | LVIS_FOCUSED | TVIS_EXPANDED | 
			TVIS_EXPANDEDONCE);
		if(idx != -1)
		{
			UINT uStt=CListCtrl::GetItemState(idx,LVIS_SELECTED | LVIS_FOCUSED);
			if(uStt & LVIS_SELECTED)
				xti->m_tvi.state |= TVIS_SELECTED;
			if(uStt & LVIS_FOCUSED)
				xti->m_tvi.state |= LVIS_FOCUSED;
		}
		if(xti->IsExpanded())
			xti->m_tvi.state |= TVIS_EXPANDED;
		if(xti->IsExpandedOnce())
			xti->m_tvi.state |= TVIS_EXPANDEDONCE;
		pTVI->state=(xti->m_tvi.state & pTVI->stateMask);
	}
	
	if(pTVI->mask & TVIF_CHILDREN)
	{
		pTVI->cChildren=xti->m_tvi.cChildren;
	}

	if(uMaskCb != 0)
	{
		pTVI->mask=uMaskCb;
		pTVI->lParam=xti->m_tvi.lParam;
		SendGetDispInfoNotify(pTVI);
	}
	return TRUE;
}

void COXTreeCtrl::SendGetDispInfoNotify(TV_ITEM *pTVI) const
{
	TV_DISPINFO di;
	di.hdr.code	 =TVN_GETDISPINFO;
	di.hdr.hwndFrom=GetSafeHwnd();
	di.hdr.idFrom  =GetDlgCtrlID();
	di.item=*pTVI;

	//Now send TVN_GETDISPINFO notification message to parent 
	GetParent()->SendMessage(WM_NOTIFY,di.hdr.idFrom,(LPARAM)&di);
	// save the changed item info
	*pTVI=di.item;
}

CString COXTreeCtrl::GetItemText(HTREEITEM hItem,int nCol) const
{
	static TCHAR t[_OX_MAX_ITEM_TEXT];
	ASSERT(nCol >= 0);

	// make sure that the string buffer is empty
	t[0] = 0;

	if(nCol == 0)
	{
		TV_ITEM item;
		item.hItem=hItem;
		item.mask=TVIF_TEXT;
		item.cchTextMax=sizeof(t)/sizeof(TCHAR);
		item.pszText=t;
		GetItem(&item);
		return t;
	}
	else
	{
		COXTreeItem * xti=GetXItem(hItem);
		if(xti)
			return xti->GetSubItemText(nCol);
	}
	return _T("");
}

BOOL COXTreeCtrl::GetItemImage(HTREEITEM hItem,int &nImg,int &nSelImg,int nCol)
{
	if(nCol == 0)
	{
		TV_ITEM tvi;
		memset(&tvi,0,sizeof(tvi));
		tvi.mask=TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_HANDLE;
		tvi.hItem=hItem;
		if(!GetItem(&tvi))
			return FALSE;
		nImg=tvi.iImage;
		nSelImg=tvi.iSelectedImage;
		return TRUE;
	}
	else
	{
		COXTreeItem* xti=GetXItem(hItem);
		if(!xti)
			return FALSE;
		int nIm=xti->GetSubItemImage(nCol);
		if(nIm == -1)
			return FALSE;
		nImg=nIm;
		nSelImg=0;
		return TRUE;
	}
}

BOOL COXTreeCtrl::SetItemImage(HTREEITEM hItem, int nImage, 
							   int nSelectedImage, int nCol)
{
	if(nCol == 0)
	{
		TV_ITEM tvi;
		memset(&tvi,0,sizeof(tvi));
		tvi.mask=TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_HANDLE;
		tvi.hItem=hItem;
		tvi.iImage=nImage;
		tvi.iSelectedImage=nSelectedImage;
		return SetItem(&tvi);
	}
	else
	{
		if(nImage!=nSelectedImage)
		{
			TRACE(_T("COXTreeCtrl::SetItemImage: the selected image is not supported for subitems, ignored\n"));
		}
		return SetSubItem(hItem,nCol,OX_SUBITEM_IMAGE,NULL,nImage);
	}
}

BOOL COXTreeCtrl::GetItemDrawEllipsis(HTREEITEM hItem, UINT& nEllipsisFormat, 
									  int nCol/*=0*/) const
{
	COXTreeItem* xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	nEllipsisFormat=xti->GetDrawEllipsis(nCol);
	return TRUE;
}

BOOL COXTreeCtrl::SetItemDrawEllipsis(HTREEITEM hItem, UINT nEllipsisFormat, 
									  int nCol/*=0*/)
{
	COXTreeItem* xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	xti->SetDrawEllipsis(nEllipsisFormat,nCol);
	return TRUE;
}

BOOL COXTreeCtrl::ModifyStyle(DWORD dwRemove, DWORD dwAdd, 
							  UINT nFlags/*=0*/)
{
	DWORD dwLCStyleAdd=0;// list control style to add
	DWORD dwLCStyleRemove=0;// list control style to remove
	
	if(dwRemove & TVS_SHOWSELALWAYS)
		dwLCStyleRemove |= LVS_SHOWSELALWAYS;

	if(dwRemove & TVS_EDITLABELS)
		dwLCStyleRemove |= LVS_EDITLABELS;
	
	if(dwAdd & TVS_SHOWSELALWAYS)
		dwLCStyleAdd |= LVS_SHOWSELALWAYS;
	
	if(dwAdd & TVS_EDITLABELS)
		dwLCStyleAdd |= LVS_EDITLABELS;
	// add common window styles
	
	dwLCStyleAdd |= (dwAdd & 0xffff0000);
	dwLCStyleRemove |= (dwRemove & 0xffff0000);


	if(dwLCStyleRemove || dwLCStyleAdd)
		if(!CListCtrl::ModifyStyle(dwLCStyleRemove,dwLCStyleAdd,nFlags))
			return FALSE;
	DWORD dwStyleOld=m_dwTCStyle;
	m_dwTCStyle |= dwAdd;
	m_dwTCStyle &= ~dwRemove;
	if(dwStyleOld != m_dwTCStyle)
		{
		Invalidate();
		}
	return TRUE;
}

DWORD COXTreeCtrl::GetStyle() const
{
	DWORD dwStyle=m_dwTCStyle | (IsWindowVisible()? 0x10000000L :0);
	return dwStyle;
}

BOOL COXTreeCtrl::ModifyExStyle(DWORD dwExStyleRemove,DWORD dwExStyleAdd, 
								UINT nFlags/*=0*/)
{
	DWORD dwLCStyleAdd=0;// list control style to add
	DWORD dwLCStyleRemove=0;// list control style to remove

	if(dwExStyleAdd & TVOXS_MULTISEL)
		dwLCStyleRemove |= LVS_SINGLESEL;
	
	if(dwExStyleRemove & TVOXS_MULTISEL)
		dwLCStyleAdd |= LVS_SINGLESEL;

	if(dwExStyleAdd & TVOXS_COLUMNHDR)
		dwLCStyleRemove |= LVS_NOCOLUMNHEADER;

	if(dwExStyleRemove & TVOXS_COLUMNHDR)
		dwLCStyleAdd |= LVS_NOCOLUMNHEADER;

	if(dwExStyleAdd & TVOXS_NOSCROLL)
		dwLCStyleAdd |= LVS_NOSCROLL;

	if(dwExStyleRemove & TVOXS_NOSCROLL)
		dwLCStyleRemove |= LVS_NOSCROLL;

	if(dwExStyleAdd & TVOXS_NOSORTHEADER)
		dwLCStyleAdd |= LVS_NOSORTHEADER;

	if(dwExStyleRemove & TVOXS_NOSORTHEADER)
		dwLCStyleRemove |= LVS_NOSORTHEADER;

	if(dwExStyleAdd & TVOXS_SHAREIMAGELISTS)
		dwLCStyleAdd |= LVS_SHAREIMAGELISTS;

	if(dwExStyleRemove & TVOXS_SHAREIMAGELISTS)
		dwLCStyleRemove |= LVS_SHAREIMAGELISTS;


	if(dwLCStyleRemove || dwLCStyleAdd)
		if(!CListCtrl::ModifyStyle(dwLCStyleRemove,dwLCStyleAdd,nFlags))
			return FALSE;

	if((dwExStyleAdd&TVOXS_ITEMTIPS) && !(m_dwExStyle&TVOXS_ITEMTIPS))
	{
#ifndef OX_TREECTRL_NOITEMTIPS
		m_ItemTip.Attach(this);
#endif
	}
	
	if((dwExStyleRemove&TVOXS_ITEMTIPS) && (m_dwExStyle&TVOXS_ITEMTIPS))
	{
#ifndef OX_TREECTRL_NOITEMTIPS
		m_ItemTip.Detach();
#endif
	}
	
	DWORD dwOld=m_dwExStyle;
	m_dwExStyle |= dwExStyleAdd;
	m_dwExStyle &= ~dwExStyleRemove;
	if(m_dwExStyle != dwOld)
		Invalidate();

	return TRUE;
}

DWORD COXTreeCtrl::GetExStyle() const
{
	return m_dwExStyle;
}

int COXTreeCtrl::InsertColumn(int nCol, const LV_COLUMN* pColumn)
{
	BOOL bRet= CListCtrl::InsertColumn(nCol,pColumn);
	return bRet;
}

int COXTreeCtrl::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, 
							  int nFormat, int nWidth, int nSubItem)
{
	BOOL bRet=CListCtrl::InsertColumn(nCol,lpszColumnHeading,nFormat,
		nWidth,nSubItem);
	return bRet;
}

BOOL COXTreeCtrl::SetSubItem(HTREEITEM hItem, int nColumn, UINT uFlags,
							 LPCTSTR lpszText, int nImage, CFont *pFont, COLORREF clr, COLORREF clrBack)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	if(nColumn <= 0)
		return FALSE;
	BOOL bRet=xti->SetSubItem(nColumn,uFlags,lpszText,nImage,pFont,clr,clrBack);
	int idx=GetItemIndexInternal(xti);
	if(bRet && idx != -1)
	{
		CListCtrl::RedrawItems(idx,idx);
	}
	return bRet;
}

BOOL COXTreeCtrl::HideItem(HTREEITEM hItem,BOOL bHide)
{
	ASSERT(hItem != TVI_ROOT);
	if (hItem==TVI_ROOT)
		return FALSE;

	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	if(xti->IsHidden() == bHide)
		return TRUE; // already hidden

	SetRedraw(FALSE);

	BOOL bResult=TRUE;

	HTREEITEM hPrevVisibleItem=GetPrevVisibleItem(hItem);
	HTREEITEM hPrevSiblingItem=GetPrevSiblingItem(hItem);

	xti->SetHidden(bHide);
	int idx=GetItemIndexInternal(xti);
	if(idx == -1 && bHide)
	{
		bResult=TRUE;
	}
	else
	{
		BOOL bItemExp=xti->IsExpanded();
		if(bHide && !bItemExp)
		{
			bResult=CListCtrl::DeleteItem(idx);
		}
		else if(bHide && bItemExp)
		{
			xti->RemoveChildrenFromCtrl(this);
			bResult=CListCtrl::DeleteItem(idx);
		}
		else if(xti->IsVisible())
		{
			if(!AddItemToCtrl(xti))
			{
				bResult=FALSE;
			}
			else
			{
				idx=GetItemIndexInternal(xti);
				ASSERT(idx != -1);
				if(xti->IsExpanded())
				{
					xti->AddChildrenToCtrl(this,idx + 1);
				}
			}
		}
	}

	if(bResult && hPrevVisibleItem!=NULL && hPrevSiblingItem!=NULL)
		RedrawTreeItems(hPrevSiblingItem,hPrevVisibleItem);

	SetRedraw(TRUE);
	
	return bResult;
}

BOOL COXTreeCtrl::DeleteItem(HTREEITEM hItem)
{
	HTREEITEM hParentItem=GetParentItem(hItem);

	TV_ITEM tvi;
	COXTreeItem *xti=GetXItem(hItem);
	if(xti != &m_xtiRoot && !HideItem(hItem))
		return FALSE;
	if(xti == &m_xtiRoot)
	{
		::ZeroMemory(&tvi, sizeof(tvi));
		tvi.hItem=xti->m_tvi.hItem;
		SendDeleteItemNotify(&tvi);
		xti->DeleteChildren();
		m_nItemsCount=0;
		return CListCtrl::DeleteAllItems();
	}
	
	if(hParentItem!=NULL)
	{
		COXTreeItem *xtiParent=GetXItem(hParentItem);
		ASSERT(xtiParent!=NULL);
		if(xtiParent->GetChildrenCount()<=1 && xtiParent->m_tvi.cChildren==1)
		{
			xtiParent->m_tvi.cChildren=0;
			if(xtiParent!=&m_xtiRoot)
			{
				xtiParent->m_bExpand=FALSE;
				xtiParent->m_bExpandedOnce=FALSE;
			}
		}
	}

	memset(&tvi,0,sizeof(tvi));
	tvi=xti->m_tvi;
	tvi.mask |= TVIF_HANDLE;
	tvi.hItem=(HTREEITEM) xti;

	SendDeleteItemNotify(&tvi);
	xti->RemoveChildrenFromCtrl(this);

	// item should have been already deleted from list
	ASSERT(GetItemIndexInternal(xti)==-1);
	delete xti;
	ASSERT(m_nItemsCount);
	m_nItemsCount--;

	if (hParentItem != NULL)
	{
		COXTreeItem* pParent = GetXItem(hParentItem);
		if (pParent->GetChildrenCount() == 0)
			RedrawTreeItems(hParentItem, hParentItem);
	}

	return TRUE;
}

BOOL COXTreeCtrl::DeleteAllItems()
{
	ASSERT(&m_xtiRoot);
	return DeleteItem(GetRootItem());
}

BOOL COXTreeCtrl::DeleteColumn(int nCol)
{
	if(nCol==0)
	{
		if(!DeleteAllItems())
		{
			return FALSE;
		}
		while(CListCtrl::DeleteColumn(0));
		return TRUE;
	}

	if(DeleteSubitems(GetRootItem(),nCol))
	{
		return CListCtrl::DeleteColumn(nCol);
	}
	else
	{
		return FALSE;
	}
}

BOOL COXTreeCtrl::DeleteSubitems(HTREEITEM hParentItem, int nCol)
{
	BOOL bSuccess=TRUE;
	HTREEITEM hItem=GetNextItem(hParentItem,TVGN_CHILD);	
	while(hItem!=NULL)
	{
		COXTreeItem* pItem=GetXItem(hItem);
		ASSERT(pItem!=NULL);
		pItem->DeleteSubitem(nCol);
		if(!DeleteSubitems(hItem,nCol))
		{
			bSuccess=FALSE;
			break;
		}
		hItem=GetNextItem(hItem,TVGN_NEXT);
	}

	return (bSuccess);
}


UINT COXTreeCtrl::GetVisibleCount() const
{
	return CListCtrl::GetItemCount();
}

UINT COXTreeCtrl::GetCount() const
{
	return m_nItemsCount;
}

HTREEITEM COXTreeCtrl::GetNextItem(HTREEITEM hItem, UINT nCode)
{
	COXTreeItem * xti=GetXItem(hItem);
	int idx;
	switch(nCode)
	{
	case TVGN_CHILD:
		if(!xti)
			return NULL;
		return (HTREEITEM)(xti->pxFirstChild);

	case TVGN_FIRSTVISIBLE:
		return GetFirstVisibleItem();

	case TVGN_NEXTVISIBLE:
		return GetNextVisibleItem(hItem,FALSE);

	case TVGN_PREVIOUSVISIBLE:
		return GetPrevVisibleItem(hItem,FALSE);

	case TVGN_DROPHILITE:
		{
			if(!xti)
				idx=-1;
			else
				idx=GetItemIndexInternal(xti);
			int idNext=CListCtrl::GetNextItem(idx,LVNI_DROPHILITED);
			if(idNext == -1 || idNext >= CListCtrl::GetItemCount())
				return NULL;
			return (HTREEITEM) CListCtrl::GetItemData(idNext);
		}

	case TVGN_NEXT:
		if(!xti)
			return NULL;
		return (HTREEITEM)(xti->pxNext);

	case TVGN_CARET:
		idx=CListCtrl::GetNextItem(-1,LVNI_FOCUSED);
		if(idx == -1)
		{
			return NULL;
		}
		else
		{
			HTREEITEM hti=GetItemFromIndex(idx);
			if(hti && GetItemState(hti,LVIS_SELECTED)==LVIS_SELECTED)
			{
				return hti;
			}
			else
			{
				return NULL;
			}
		}
	
	case TVGN_PARENT:
		if(!xti)
			return NULL;
		return (HTREEITEM) (xti->pxParent);
	
	case TVGN_PREVIOUS:
		if(!xti)
			return NULL;
		return (HTREEITEM) (xti->pxPrev);
	
	case TVGN_ROOT:
		if(!xti)
			return NULL;
		return (HTREEITEM)(xti->pxParent ? xti->pxParent->pxFirstChild : NULL);
	
	case TVGN_FIRSTSELECTED:
		idx=CListCtrl::GetNextItem(-1,LVNI_SELECTED);
		if(idx == -1)
			return NULL;
		return (HTREEITEM) CListCtrl::GetItemData(idx);
	
	case TVGN_NEXTSELECTED:
		if(!xti)
			return NULL;
		idx=GetItemIndexInternal(xti);
		if(idx == -1)
			return NULL;
		idx=CListCtrl::GetNextItem(idx,LVNI_SELECTED);
		if(idx == -1)
			return NULL;
		return (HTREEITEM) CListCtrl::GetItemData(idx);
	
	default:
		ASSERT(FALSE);
		return NULL;

	}
}

HTREEITEM COXTreeCtrl::GetFirstVisibleItem()
{
	int idx=CListCtrl::GetTopIndex();
	if(idx == -1 || idx >= CListCtrl::GetItemCount())
		return NULL;
	return (HTREEITEM) CListCtrl::GetItemData(idx);
}

HTREEITEM COXTreeCtrl::GetNextVisibleItem(HTREEITEM hItem, 
										  BOOL bCurrentlyViewable/*=FALSE*/)
{
	COXTreeItem *xti=GetXItem(hItem);
	// walk down throuth tree structure and find the next item in list ctrl
	if(!xti)
	{
		return NULL;
	}

	CRect rect;
	GetClientRect(rect);
	HTREEITEM hItemFirstVisible=GetFirstVisibleItem();
	ASSERT(hItemFirstVisible!=NULL);
	CRect rectFistVisible;
	GetItemRect(hItemFirstVisible,rectFistVisible,FALSE);
	rect.top=rectFistVisible.top;

	xti=xti->GetNextInTree();
	for(; xti ; xti=xti->GetNextInTree())
	{
		int idx=GetItemIndexInternal(xti);
		if(idx != -1)
		{
			if(bCurrentlyViewable)
			{
				CRect rectItem;
				CListCtrl::GetItemRect(idx,rectItem,LVIR_BOUNDS);
				if((rectItem.top>=rect.top && rectItem.top<=rect.bottom) ||
					(rectItem.bottom>=rect.top && rectItem.bottom<=rect.bottom))
				{
					return (HTREEITEM) CListCtrl::GetItemData(idx);
				}
				break;
			}
			else
			{
				return (HTREEITEM) CListCtrl::GetItemData(idx);
			}
		}
	}
	return NULL;
}

HTREEITEM COXTreeCtrl::GetPrevVisibleItem(HTREEITEM hItem, 
										  BOOL bCurrentlyViewable/*=FALSE*/)
{
	COXTreeItem *xti=GetXItem(hItem);
	// walk up throuth tree structure and find the item in list ctrl
	if(!xti)
		return NULL;

	CRect rect;
	GetClientRect(rect);
	HTREEITEM hItemFirstVisible=GetFirstVisibleItem();
	if(hItemFirstVisible==NULL)
		return NULL;

	CRect rectFistVisible;
	GetItemRect(hItemFirstVisible,rectFistVisible,FALSE);
	rect.top=rectFistVisible.top;

	xti=xti->GetPrevInTree();
	for(; xti ; xti=xti->GetPrevInTree())
	{
		int idx=GetItemIndexInternal(xti);
		if(idx != -1)
		{
			if(bCurrentlyViewable)
			{
				CRect rectItem;
				CListCtrl::GetItemRect(idx,rectItem,LVIR_BOUNDS);
				if((rectItem.top>=rect.top && rectItem.top<=rect.bottom) ||
					(rectItem.bottom>=rect.top && rectItem.bottom<=rect.bottom))
				{
					return (HTREEITEM) CListCtrl::GetItemData(idx);
				}
				break;
			}
			else
			{
				return (HTREEITEM) CListCtrl::GetItemData(idx);
			}
		}
	}
	return NULL;
}

HTREEITEM COXTreeCtrl::GetFirstHiddenItem()
{
	COXTreeItem *xti=&m_xtiRoot;// start form root item

	xti=xti->GetNextInTree();
	// now iterate the tree and find first hidden item
	for(; xti ; xti=xti->GetNextInTree())
	{
		if(xti->IsHidden())
			return (HTREEITEM) xti;
	}
	return NULL;
}

HTREEITEM COXTreeCtrl::GetNextHiddenItem(HTREEITEM hItem)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return NULL;
	xti=xti->GetNextInTree();
	// now iterate the tree and stop when a hidden item found
	for(; xti ; xti=xti->GetNextInTree())
	{
		if(xti->IsHidden())
			return (HTREEITEM) xti;
	}
	return NULL;
}

HTREEITEM COXTreeCtrl::GetPrevHiddenItem(HTREEITEM hItem)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return NULL;
	xti=xti->GetPrevInTree();
	// now iterate the tree and stop when a hidden item found
	for(; xti ; xti=xti->GetPrevInTree())
	{
		if(xti->IsHidden())
			return (HTREEITEM) xti;
	}
	return NULL;
}

HTREEITEM COXTreeCtrl::GetSelectedItem()
{
	return GetNextItem(TVI_ROOT,TVGN_FIRSTSELECTED);
}

CImageList* COXTreeCtrl::GetImageList(UINT nImage)
{
	UINT nListImg;
	switch(nImage)
	{
	case TVSIL_NORMAL:
		nListImg=LVSIL_SMALL;
		break;
	case TVSIL_STATE:
		nListImg=LVSIL_STATE;
	default:
		ASSERT(FALSE);
		return NULL;
	}
	return CListCtrl::GetImageList(nListImg);
}

UINT COXTreeCtrl::GetIndent() const
{
	return m_nIndent;
}

void COXTreeCtrl::SetIndent(UINT nIndent)
{
	nIndent=nIndent>TV_MININDENT ? nIndent : TV_MININDENT;
	m_nIndent=nIndent;
	RedrawWindow();
}

BOOL COXTreeCtrl::ItemHasChildren(HTREEITEM hItem) const
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	return xti->ItemHasChildren();
}

HTREEITEM COXTreeCtrl::GetChildItem(HTREEITEM hItem)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return NULL;
	return (HTREEITEM) (xti->pxFirstChild);
}

HTREEITEM COXTreeCtrl::GetNextSiblingItem(HTREEITEM hItem)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return NULL;
	return (HTREEITEM) (xti->pxNext);
}

HTREEITEM COXTreeCtrl::GetPrevSiblingItem(HTREEITEM hItem)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return NULL;
	return (HTREEITEM) (xti->pxPrev);
}

HTREEITEM COXTreeCtrl::GetParentItem(HTREEITEM hItem)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return NULL;
	return (HTREEITEM) (xti->pxParent);
}

HTREEITEM COXTreeCtrl::GetDropHilightItem()
{
	int idx=CListCtrl::GetNextItem(-1,LVNI_DROPHILITED);
	if(idx == -1 || idx >= CListCtrl::GetItemCount())
		return NULL;
	return (HTREEITEM) CListCtrl::GetItemData(idx);
}

HTREEITEM COXTreeCtrl::GetRootItem() const
{
	return (HTREEITEM)(&m_xtiRoot);
}

UINT COXTreeCtrl::GetItemState(HTREEITEM hItem, UINT nStateMask) const
{
	TV_ITEM tvi;
	memset(&tvi,0,sizeof(tvi));
	tvi.mask=TVIF_HANDLE | TVIF_STATE;
	tvi.hItem=hItem;
	tvi.stateMask=nStateMask;
	VERIFY(GetItem(&tvi));
	return tvi.state;
}

BOOL COXTreeCtrl::SetItemState(HTREEITEM hItem, UINT nState, UINT nStateMask)
{
	TV_ITEM tvi;
	memset(&tvi,0,sizeof(tvi));
	tvi.mask=TVIF_HANDLE | TVIF_STATE;
	tvi.hItem=hItem;
	tvi.stateMask=nStateMask;
	tvi.state=nState;
	return SetItem(&tvi);
}

DWORD COXTreeCtrl::GetItemData(HTREEITEM hItem) const
{
	TV_ITEM tvi;
	memset(&tvi,0,sizeof(tvi));
	tvi.mask=TVIF_HANDLE | TVIF_PARAM;
	tvi.hItem=hItem;
	VERIFY(GetItem(&tvi));
	return (DWORD)tvi.lParam;
}

BOOL COXTreeCtrl::SetItemData(HTREEITEM hItem, DWORD dwData)
{
	TV_ITEM tvi;
	memset(&tvi,0,sizeof(tvi));
	tvi.mask=TVIF_HANDLE | TVIF_PARAM;
	tvi.hItem=hItem;
	tvi.lParam=dwData;
	return SetItem(&tvi);
}

BOOL COXTreeCtrl::GetItemRect(HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly) const
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	int idx=GetItemIndexInternal(xti);
	if(idx == -1 || idx >= CListCtrl::GetItemCount())
		return FALSE;
	CRect r;
	if(bTextOnly)
	{
		int nIndent=-1;
		GetItemPartRect(rText,xti,&r,&nIndent);
		::SetRect(lpRect,r.left,r.top,r.right,r.bottom);
		return TRUE;
	}
	return CListCtrl::GetItemRect(idx,lpRect,LVIR_BOUNDS);
}

BOOL COXTreeCtrl::SetItemColor(HTREEITEM hItem,COLORREF clr,int nCol)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	int idx=GetItemIndexInternal(xti);
	if(!nCol)
	{
		xti->SetColor(clr);
	}
	else
	{
		COXTreeSubItem *pSubItem=xti->GetSubItem(nCol);
		if(!pSubItem)
			return FALSE;
		pSubItem->SetColor(clr);
	}
	if(idx != -1)
		CListCtrl::RedrawItems(idx,idx);
	return TRUE;
}

BOOL COXTreeCtrl::SetItemBackColor(HTREEITEM hItem,COLORREF clr,int nCol)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	int idx=GetItemIndexInternal(xti);
	if(!nCol)
	{
		xti->SetBackColor(clr);
	}
	else
	{
		COXTreeSubItem *pSubItem=xti->GetSubItem(nCol);
		if(!pSubItem)
			return FALSE;
		pSubItem->SetBackColor(clr);
	}
	if(idx != -1)
		CListCtrl::RedrawItems(idx,idx);
	return TRUE;
}

COLORREF COXTreeCtrl::GetItemColor(HTREEITEM hItem,int nCol) const
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return 0;
	if(xti->HasColor(nCol))
		return xti->GetItemColor(nCol);
	return ::GetSysColor(COLOR_BTNTEXT);
}

CFont* COXTreeCtrl::GetItemFont(HTREEITEM hItem,int nCol)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return NULL;
	return xti->GetItemFont(nCol);
}

BOOL COXTreeCtrl::SetItemFont(HTREEITEM hItem,CFont *pFont,int nCol)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	BOOL bRes=xti->SetFont(nCol,pFont);
	int idx=GetItemIndexInternal(xti);
	if(bRes && idx != -1 && idx < CListCtrl::GetItemCount())
		CListCtrl::RedrawItems(idx,idx);
	return bRes;
}

BOOL COXTreeCtrl::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult) 
{
	LV_DISPINFO* pDispInfo= (LV_DISPINFO*) pNMHDR;
	*pResult = 0;

	// We need to fire TVN_BEGINLABELEDIT Notification
	NMTVDISPINFO tvdi;
	::memset(&tvdi, 0, sizeof(NMTVDISPINFO));
	tvdi.hdr.hwndFrom = pNMHDR->hwndFrom;
    tvdi.hdr.idFrom = pNMHDR->idFrom;
    tvdi.hdr.code = pNMHDR->code;
	tvdi.item.mask = TVIF_HANDLE | TVIF_PARAM;
	tvdi.item.hItem = (HTREEITEM)(INT_PTR) pDispInfo->item.iItem;
	tvdi.item.lParam = pDispInfo->item.lParam;
	*pResult = GetParent()->SendMessage(TVN_BEGINLABELEDIT, pNMHDR->idFrom, (LPARAM) &tvdi);
	
	int nItem=pDispInfo->item.iItem;
	HWND hWndEdit=(HWND)::SendMessage(m_hWnd, LVM_GETEDITCONTROL, 0, 0L);
	
	if(m_pActiveEditWnd!=NULL && m_pActiveEditWnd->GetSafeHwnd())
		return FALSE;

	ASSERT(nItem != -1);
	COXTreeItem *xti=(COXTreeItem *) CListCtrl::GetItemData(nItem);
	ASSERT(xti);
	if(xti->IsDisabled())
	{
		if(pResult != NULL)
			*pResult = TRUE;
		return TRUE;
	}
	CRect rcEdit;
	int nCol=GetEditColumn(xti,&rcEdit);
	if(nCol == -1)
	{
		// No editable column found
		if(pResult != NULL)
			*pResult = TRUE;
		return TRUE;
	}

	if(xti->GetEditMode(nCol)==OXET_NOEDIT)
	{
		// No editable column found
		if(pResult != NULL)
			*pResult = TRUE;
		return TRUE;
	}

	m_nEditColumn=nCol;
	m_pActiveEditWnd=StartEditSubItem(hWndEdit,xti,rcEdit,nCol,pResult);

	if (GetParent() != NULL && GetParent()->SendMessage(WM_USER_QUERY_PROPERTIESWND))
		return FALSE;
	else
		return TRUE;
}

int COXTreeCtrl::GetEditColumn(COXTreeItem *xti,CRect * rcColText)
	// --- In  :
	// --- Out : 
	// --- Returns : specified item's column to edit
	//--- Effect :
{
	// fill rcItem with entry item rect
	CRect rcItem;
	int nIndex=GetItemIndexInternal(xti);
	if(nIndex == -1)
		return -1;
	CListCtrl::GetItemRect(nIndex,&rcItem,LVIR_BOUNDS);

	CImageList *pImgList=CListCtrl::GetImageList(LVSIL_SMALL);
	CImageList *pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);

	// Now find the column
	int nColumnsCount=GetColumnsCount();
	int nCol=-1;
	for(int colnum=0; colnum < nColumnsCount; colnum++)
	{
		int nColWidth=GetColumnWidth(colnum);
		if(m_ptLastClick.x >= rcItem.left && 
			m_ptLastClick.x <= (rcItem.left + nColWidth))
		{
			nCol=colnum;
			break;
		}
		rcItem.left += nColWidth;
	}
	if(nCol == -1)
		return -1;// no column found
	if(nCol && !xti->GetSubItem(nCol))
		return -1; // this item has no subitems at given column

	rcItem.right=rcItem.left + GetColumnWidth(nCol);
	
	int nIndent=nCol == 0 ? GetItemIndent(xti) : 0;

//	CSize szText=GetColTextExtent(nIndex,nCol);
	CSize szText=CSize(rcItem.Width(),rcItem.Height());
	CRect rcText;
	
	LV_COLUMN lvc;
	memset(&lvc, 0, sizeof(LV_COLUMN));
	lvc.mask=LVCF_FMT;
	VERIFY(GetColumn(nCol, &lvc));

	int nImgWidth=0;
	IMAGEINFO imgInfo;
	int nImg=xti->GetItemImage(nCol);

	if(pImgList && nImg != -1)
	{
		pImgList->GetImageInfo(0,&imgInfo);
		CRect rcImg(imgInfo.rcImage);
		nImgWidth += rcImg.Width();
	}

	if(pStateImgList && nCol == 0 && GetItemStateIndex(nIndex) != -1)
	{
		pStateImgList->GetImageInfo(0,&imgInfo);
		CRect rcImg(imgInfo.rcImage);
		nImgWidth += rcImg.Width();
	}

	rcText.top=rcItem.top;
	rcText.bottom=rcItem.bottom;
	szText.cx=__min(szText.cx,GetColumnWidth(nCol)-nImgWidth-nIndent);
	int fmt=lvc.fmt & LVCFMT_JUSTIFYMASK;
	switch(fmt)
	{
	case LVCFMT_LEFT:
		{
			rcText.left=rcItem.left + nIndent + nImgWidth;
			rcText.right=rcText.left + szText.cx;
		}
		break;
	case LVCFMT_RIGHT:
		{
			rcText.right=rcItem.left + GetColumnWidth(nCol);
			rcText.left=rcText.right - szText.cx;
		}
		break;
	case LVCFMT_CENTER:
		{
			rcItem.left += nIndent + nImgWidth;
			int nCenter=rcItem.left + (rcItem.right - rcItem.left)/2;
			rcText.left=nCenter - szText.cx/2;
			rcText.right=nCenter + szText.cx/2;
		}
		break;
	default:
		ASSERT(FALSE);
	}
	(*rcColText)=rcText;
	if(rcText.Width() < 6)
		rcText.InflateRect(4,4);
	if(!rcText.PtInRect(m_ptLastClick))
		return -1;
	return nCol;
}


CEdit* COXTreeCtrl::EditLabel(HTREEITEM hti, int nCol/*=0*/)
{
	if(!(GetStyle()&TVS_EDITLABELS))
		return NULL;

	COXTreeItem* xti=GetXItem(hti);
	if(!xti)
		return NULL;

	int nIndex=GetItemIndex(hti);
	if(nIndex<0)
		return NULL;

	CRect rcItem;
	if(!GetItemRect(hti,&rcItem,TRUE))
		return NULL;
	int nColumnsCount=GetColumnsCount();
	if(nCol>=nColumnsCount)
		return NULL;

	if(nCol>0)
		rcItem.left=0;
	for(int colnum=0; colnum < nCol; colnum++)
		rcItem.left += GetColumnWidth(colnum);
	if(nCol>0)
		rcItem.right=rcItem.left + GetColumnWidth(nCol);
	
	m_ptLastClick=rcItem.CenterPoint()-CPoint(GetScrollPos(SB_HORZ),0);

	if(GetFocus() != this)
		SetFocus();

	return (CEdit*)CWnd::FromHandle((HWND)SendMessage(LVM_EDITLABEL,nIndex));
}

CWnd* COXTreeCtrl::StartEditSubItem(HWND hWndEdit,COXTreeItem *xti,CRect& rcEdit,
									int nCol,LRESULT* pResult)
	// --- In  :
	// --- Out : 
	// --- Returns :
	//--- Effect :
{
	CRect rcClient;
	GetClientRect(&rcClient);
	int nEditType=xti->GetEditMode(nCol);
	switch(nEditType)
	{
	case OXET_COMBO:
		{
			int nLeft=-GetScrollPos(SB_HORZ);
			for(int i=0;i < nCol;i++)
				nLeft += GetColumnWidth(i);
			CRect rcCombo=rcEdit;
			rcCombo.left=nLeft;
			CImageList *pImgList=GetImageList(TVSIL_NORMAL);
			rcCombo.right=rcCombo.left + GetColumnWidth(nCol);
			if(xti->GetItemImage(nCol) != -1 &&pImgList)
			{
				IMAGEINFO ii;
				pImgList->GetImageInfo(0,&ii);
				rcCombo.left += CRect(ii.rcImage).Width();
			}
			if(rcCombo.right > rcClient.right)
			{
				// perform scrolling
				CSize szScroll;
				szScroll.cx=rcCombo.right  - rcClient.right;
				szScroll.cy=0;
				Scroll(szScroll);
				rcCombo.right -= szScroll.cx;
				rcCombo.left -= szScroll.cx;
			}
			rcCombo.bottom += rcEdit.Height()*5;
			(*pResult)=1;
			m_wndCombo.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST|WS_VSCROLL|WS_HSCROLL,
			rcCombo,this,100);
			m_wndCombo.SetFont(GetFont());

			m_wndCombo.Init((HTREEITEM) xti,GetItemIndexInternal(xti),nCol);

			m_wndCombo.SetFocus();
		}
		return &m_wndCombo;
	case OXET_EDIT:
		{
			m_wndEdit.Init();
			LV_COLUMN lvc;
			lvc.mask=LVCF_FMT;
			VERIFY(CListCtrl::GetColumn(nCol,&lvc));
			DWORD dwAlign=ES_LEFT;
			CPoint pos;
			switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
			{
			case LVCFMT_LEFT:
				pos=rcEdit.TopLeft();
				dwAlign=ES_LEFT;
				break;
			case LVCFMT_RIGHT:
				pos.x=rcEdit.right;
				pos.y=rcEdit.top;
				dwAlign=ES_RIGHT;
				break;
			case LVCFMT_CENTER:
				pos.x=rcEdit.left + rcEdit.Width()/2;
				pos.y=rcEdit.top;
				dwAlign=ES_CENTER;
				break;
			}
			// scroll control if column been edited is not visible
			if(pos.x < 0 || pos.x > rcClient.right)	
			{
				// perform scrolling
				CSize szScroll;
				szScroll.cx=pos.x  - rcClient.right;
				szScroll.cy=0;
				Scroll(szScroll);
				pos.x -= szScroll.cx;
			}
			m_wndEdit.SubclassWindow(hWndEdit);	
			m_wndEdit.KeepPos(pos,dwAlign);

			if ( m_dwExStyle & TVOXS_KEEPCOLUMNSIZE )
				m_wndEdit.KeepColumnSize(CSize(rcEdit.right,rcEdit.bottom));
			else
				m_wndEdit.KeepBounds(CSize(rcClient.Width(),rcClient.Height()));

			m_wndEdit.SetWindowText(GetItemText((HTREEITEM)xti,nCol));
			return &m_wndEdit;
		}
	case OXET_CALENDAR:
		{
			int nLeft=-GetScrollPos(SB_HORZ);
			for(int i=0;i < nCol;i++)
				nLeft += GetColumnWidth(i);
			CRect rcCal=rcEdit;
			rcCal.left=nLeft;
			CImageList *pImgList=GetImageList(TVSIL_NORMAL);
			rcCal.right=rcCal.left + GetColumnWidth(nCol);
			if(xti->GetItemImage(nCol) != -1 &&pImgList)
			{
				IMAGEINFO ii;
				pImgList->GetImageInfo(0,&ii);
				rcCal.left += CRect(ii.rcImage).Width();
			}
			if(rcCal.right > rcClient.right)
			{
				// perform scrolling
				CSize szScroll;
				szScroll.cx=rcCal.right  - rcClient.right;
				szScroll.cy=0;
				Scroll(szScroll);
				rcCal.right -= szScroll.cx;
				rcCal.left -= szScroll.cx;
			}
			(*pResult)=1;
			m_wndCal.Create(WS_CHILD | WS_VISIBLE |WS_BORDER,rcCal,this,7);
			m_wndCal.Init((HTREEITEM)xti,GetItemIndexInternal(xti),nCol);
			m_wndCal.SetFocus();
			return &m_wndCal;
		}
	default:
		return NULL;
	}
}

BOOL COXTreeCtrl::IsItemHidden(HTREEITEM hItem) const
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	return xti->IsHidden();
}

BOOL COXTreeCtrl::DisableItem(HTREEITEM hItem,BOOL bDisable)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(xti->IsDisabled() == bDisable)
		return TRUE; // already disabled or undisabled
	xti->SetDisabled(bDisable);
	int idx=GetItemIndexInternal(xti);
	if(idx == -1)
		return TRUE;
	CListCtrl::RedrawItems(idx,idx);
	return TRUE;
}

BOOL COXTreeCtrl::IsItemDisabled(HTREEITEM hItem) const
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	return xti->IsDisabled();
}

BOOL COXTreeCtrl::IsItemDescendant(HTREEITEM hParentItem, HTREEITEM hItem)
{
	ASSERT(hParentItem!=NULL);
	ASSERT(hItem!=NULL);
	if(hParentItem==NULL || hItem==NULL)
	{
		return FALSE;
	}

	HTREEITEM hDirectParent=GetParentItem(hItem);
	if(hDirectParent==NULL)
	{
		return FALSE;
	}
	else
	{
		return (hParentItem==hDirectParent || 
			IsItemDescendant(hParentItem,hDirectParent));
	}
}


void COXTreeCtrl::SendDeleteItemNotify(TV_ITEM* ptvi)
{
	NM_TREEVIEW nmt;
	memset(&nmt,0,sizeof(nmt));
	
	nmt.itemOld=*ptvi;
	nmt.hdr.code=TVN_DELETEITEM;
	nmt.hdr.idFrom=GetDlgCtrlID();
	nmt.hdr.hwndFrom=GetSafeHwnd();
	GetParent()->SendMessage(WM_NOTIFY,nmt.hdr.idFrom , (LPARAM)&nmt);
}

BOOL COXTreeCtrl::SendItemExpandingNotify(HTREEITEM hItem,UINT nCode)
{
	COXTreeItem *xti=GetXItem(hItem);
	ASSERT(xti);
	NM_TREEVIEW nmt;

	memset(&nmt, 0, sizeof(nmt));
	
	nmt.hdr.idFrom=GetDlgCtrlID();
	nmt.hdr.hwndFrom=GetSafeHwnd();
	nmt.hdr.code=TVN_ITEMEXPANDING;
	nmt.action=nCode;

	nmt.itemNew=xti->m_tvi;
	nmt.itemNew.mask |= TVIF_HANDLE;
	nmt.itemNew.hItem=(HTREEITEM) xti;
	
	return (BOOL)(GetParent()->SendMessage(WM_NOTIFY,nmt.hdr.idFrom,(LPARAM)(&nmt)));
}

void COXTreeCtrl::SendItemExpandedNotify(HTREEITEM hItem,UINT nCode)
{
	COXTreeItem *xti=GetXItem(hItem);
	ASSERT(xti);

	NM_TREEVIEW nmt;
	memset(&nmt, 0, sizeof(nmt));
	
	nmt.hdr.idFrom=GetDlgCtrlID();
	nmt.hdr.hwndFrom=GetSafeHwnd();
	nmt.hdr.code=TVN_ITEMEXPANDED;
	nmt.action=nCode;

	nmt.itemNew=xti->m_tvi;
	nmt.itemNew.mask |= TVIF_HANDLE;
	nmt.itemNew.hItem=(HTREEITEM) xti;
	GetParent()->SendMessage(WM_NOTIFY,nmt.hdr.idFrom,(LPARAM)(&nmt));
}

BOOL COXTreeCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult) 
{
	LV_DISPINFO* pDispInfo=(LV_DISPINFO*)pNMHDR;
	if ((pDispInfo->item.pszText != NULL) && (pDispInfo->item.iItem != -1))
	{
		HTREEITEM hItem=(HTREEITEM) CListCtrl::GetItemData(pDispInfo->item.iItem);
		VERIFY(SetItemText(hItem,pDispInfo->item.pszText,m_nEditColumn));
		return FALSE;
	}

	*pResult=0;
	return FALSE;
}

BOOL COXTreeCtrl::SetItemText(HTREEITEM hItem, LPCTSTR lpszItem ,int nCol)
{
	COXTreeItem *xti=GetXItem(hItem);
	if(!xti)
		return FALSE;
	if(nCol == 0)
	{
		TV_ITEM tvi;
		memset(&tvi,0,sizeof(tvi));
		tvi.mask=TVIF_HANDLE | TVIF_TEXT;
		tvi.hItem=hItem;
		tvi.pszText=(LPTSTR)lpszItem;
		return SetItem(&tvi);
	}
	return xti->SetSubItemText(lpszItem,nCol);
}

BOOL COXTreeCtrl::GetPickAnywhere() const
{
	return (m_dwExStyle & TVOXS_PICKANYWHERE);
}

BOOL COXTreeCtrl::GetDrawGridFullLength() const
{
	return (m_dwExStyle & TVOXS_FLGRID);
}

BOOL COXTreeCtrl::HasGrid(UINT nGridType) const
{
	return (m_dwExStyle & nGridType);
}

BOOL COXTreeCtrl::ResizeColToFit(int nCol)
{
	if(nCol >= GetColumnsCount())
		return FALSE;
	int nWidth=GetFullColumnWidth(nCol);

	return SetColumnWidth(nCol,nWidth);
}


int COXTreeCtrl::GetFullColumnWidth(int nCol)
{
	if(GetItemCount()==0)
		return 6;

	int nImgWidth=0,nStateImgWidth=0;
	CImageList* pImgList=CListCtrl::GetImageList(LVSIL_SMALL);
	CImageList* pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);
	
	// calc image width 
	if(pImgList && pImgList->GetImageCount() > 0)
	{
		IMAGEINFO imi;
		VERIFY(pImgList->GetImageInfo(0,&imi));
		nImgWidth=imi.rcImage.right - imi.rcImage.left;
	}

	// calc state image width 
	if(pStateImgList && pStateImgList->GetImageCount() > 0)
	{
		IMAGEINFO imi;
		VERIFY(pStateImgList->GetImageInfo(0,&imi));
		nStateImgWidth=imi.rcImage.right - imi.rcImage.left;
	}

	int nIndex=CListCtrl::GetNextItem(-1,LVNI_ALL);

	int nMaxWidth=0;
	CDC *pDC=GetDC();
	// look throuth currently visible items and find max width
	while(nIndex != -1)
	{
		int nWidth=0;
		COXTreeItem *xti=GetXItem((HTREEITEM) CListCtrl::GetItemData(nIndex));

		if(nCol == 0)
		{
			// add item indent
			nWidth += GetItemIndent(xti);
			// add item's state image width, if any
			if(pStateImgList)
			{
				int idx=STATEIMAGEMASKTOINDEX(xti->m_tvi.state)-1;
					if(idx != -1)
						nWidth += nStateImgWidth;
			}
			// add main image width
			nWidth += nImgWidth;
		}
		else
		{
			if(xti->GetSubItemImage(nCol) != -1)
				nWidth += nImgWidth;
		}
		// finally calc and add item's text width
		CFont *pFont=xti->HasFont(nCol) ? xti->GetItemFont(nCol) : GetFont();
		CFont *pOldFont=pDC->SelectObject(pFont);
		CSize szText=pDC->GetTextExtent(GetItemText((HTREEITEM) xti,nCol));
		pDC->SelectObject(pOldFont);
		nWidth += szText.cx + 6;
		if(nWidth > nMaxWidth)
			nMaxWidth=nWidth;
		// retreive next item
		nIndex=CListCtrl::GetNextItem(nIndex,LVNI_ALL);
	}
	ReleaseDC(pDC);
	return nMaxWidth;
}

void COXTreeCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	if(GetFocus() != this)
		SetFocus();
	CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}

void COXTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
	// --- In  :
	// --- Out : 
	// --- Returns :
	//--- Effect :
{
	if(GetFocus() != this)
		SetFocus();

	CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}

void COXTreeCtrl::SetEditMode(HTREEITEM hItem,UINT uMode,CStringArray& saTextEx,int nCol)
{
	COXTreeItem *xti=GetXItem(hItem);
	ASSERT(xti);
	xti->SetEditMode(uMode,saTextEx,nCol);
}

void COXTreeCtrl::SetPlainEditMode(HTREEITEM hItem,int nCol)
{
	CStringArray sArray;
	SetEditMode(hItem,OXET_EDIT,sArray,nCol);
}

void COXTreeCtrl::SetNoEditMode(HTREEITEM hItem,int nCol)
{
	CStringArray sArray;
	SetEditMode(hItem,OXET_NOEDIT,sArray,nCol);
}

void COXTreeCtrl::SetItemTextEx(HTREEITEM hItem,CStringArray& saTextEx,int nCol)
{
	COXTreeItem* xti=GetXItem(hItem);
	ASSERT(xti);
	if(xti)
		xti->SetTextEx(saTextEx,nCol);
}

CStringArray& COXTreeCtrl::GetItemTextEx(HTREEITEM hItem,int nCol)
{
	COXTreeItem *xti=GetXItem(hItem);
	ASSERT(xti);
	return xti->GetTextEx(nCol);
}

void COXTreeCtrl::PostNcDestroy() 
{
	m_bInit=FALSE;
	CListCtrl::PostNcDestroy();
}

void COXTreeCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	if(m_nItemHeight)
	{
		lpMeasureItemStruct->itemHeight=max(m_nItemHeight,
			lpMeasureItemStruct->itemHeight); 
	}
	else
	{
		m_nItemHeight=lpMeasureItemStruct->itemHeight; 
	}
}

UINT COXTreeCtrl::GetItemHeight() const
{
	return m_nItemHeight;
}

void COXTreeCtrl::SetItemHeight(UINT nHeight)
{
	m_nItemHeight=nHeight;
	////
	CRect rect;
	GetWindowRect(rect);
	WINDOWPOS wp;
	wp.hwnd=m_hWnd;
	wp.cx=rect.Width();
	wp.cy=rect.Height();
	wp.flags=SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER;
	SendMessage(WM_WINDOWPOSCHANGED,0,(LPARAM)&wp);
	////
}


BOOL COXTreeCtrl::EnsureVisible(HTREEITEM hti)
{
	COXTreeItem* xti=GetXItem(hti);
	if(!xti || xti==&m_xtiRoot)
	{
		return FALSE;
	}

	if(!xti->IsVisible())
	{
		if(xti->IsHidden())
		{
			xti->SetHidden(FALSE);
		}

		CPtrArray arrItemsToExpand;
		HTREEITEM htiParent=GetParentItem(hti);
		COXTreeItem* xtiParent;
		BOOL bFlag=FALSE;
		while(!bFlag && htiParent!=NULL)
		{
			xtiParent=GetXItem(htiParent);
			ASSERT(xtiParent);
			if(xtiParent==&m_xtiRoot ||
				(xtiParent->IsVisible() && xtiParent->IsExpanded()))
			{
				bFlag=TRUE;
			}
			else 
			{
				if(xtiParent->IsHidden())
				{
					xtiParent->SetHidden(FALSE);
				}
				if(!xtiParent->IsExpanded())
				{
					arrItemsToExpand.Add(htiParent);
				}
				htiParent=GetParentItem(htiParent);
			}
		}
		if(arrItemsToExpand.GetSize()>0)
		{
			for(int nIndex=(int)arrItemsToExpand.GetSize()-1; nIndex>=0; nIndex--)
				Expand((HTREEITEM)arrItemsToExpand[nIndex],TVE_EXPAND);
		}
	}

	int nIndex=GetItemIndex(hti);
	if(nIndex<0)
	{
		return FALSE;
	}
	return CListCtrl::EnsureVisible(nIndex,FALSE);
}

BOOL COXTreeCtrl::EnsureFirstVisible(HTREEITEM hti)
{
	if(!EnsureVisible(hti))
	{
		return FALSE;
	}

	HTREEITEM hItemFirstVisible=GetFirstVisibleItem();
	if(hItemFirstVisible==hti)
	{
		return TRUE;
	}

	int nIndex=GetItemIndex(hti);
	int nIndexFirstVisible=GetItemIndex(hItemFirstVisible);
	ASSERT(nIndex!=nIndexFirstVisible);

	CRect rect;
	GetItemRect(hti,rect,FALSE);
	CSize sizeScroll(0,(nIndex-nIndexFirstVisible)*rect.Height());
	CListCtrl::Scroll(sizeScroll);
	
	return TRUE;
}

BOOL COXTreeCtrl::Select(HTREEITEM hti, UINT nCode)
{
	if(nCode==TVGN_FIRSTVISIBLE)
	{
		return FALSE;
	}

	if(hti==NULL)
	{
		switch(nCode)
		{
		case TVGN_CARET:
			{
				HTREEITEM hItem=GetNextItem(TVI_ROOT,TVGN_FIRSTSELECTED);
				while(hItem)
				{
					SetItemState(hItem,0,TVIS_SELECTED);
					hItem=GetNextItem(hItem,TVGN_NEXTSELECTED);
				}

				break;
			}
		case TVGN_DROPHILITE:
			{
				if(m_hOldDropTarget!=NULL)
				{
					SetItemState(m_hOldDropTarget,0,TVIS_DROPHILITED);
					UpdateWindow();
					m_hOldDropTarget = NULL;
				}
			}
		}
		return TRUE;
	}

	COXTreeItem* xti=GetXItem(hti);
	if(xti==&m_xtiRoot && nCode==TVGN_DROPHILITE)
	{
		if(m_hOldDropTarget!=NULL)
		{
			SetItemState(m_hOldDropTarget,0,TVIS_DROPHILITED);
			UpdateWindow();
			m_hOldDropTarget = NULL;
		}
	}
	if(!xti || xti==&m_xtiRoot)
	{
		return FALSE;
	}

	int nIndex=GetItemIndexInternal(xti);

	BOOL bResult=FALSE;
	switch(nCode)
	{
	case TVGN_CARET:
		{
			bResult=SetItemState(hti,TVIS_SELECTED,TVIS_SELECTED) & 
				CListCtrl::SetItemState(nIndex,LVIS_FOCUSED,LVIS_FOCUSED);
			break;
		}
	case TVGN_DROPHILITE:
		{
			bResult=SetItemState(hti,TVIS_DROPHILITED,TVIS_DROPHILITED);
			break;
		}
	}

	return bResult;
}

BOOL COXTreeCtrl::SelectItem(HTREEITEM hti)
{
	return Select(hti,TVGN_CARET);
}

BOOL COXTreeCtrl::SelectDropTarget(HTREEITEM hti)
{
	return Select(hti,TVGN_DROPHILITE);
}

BOOL COXTreeCtrl::SelectSetFirstVisible(HTREEITEM hti)
{
	return Select(hti,TVGN_FIRSTVISIBLE);
}

CImageList* COXTreeCtrl::CreateDragImage(HTREEITEM hti, BOOL bCreateMultipleImage)
{
	int nIndex=GetItemIndex(hti);
	if(nIndex<0)
	{
		return NULL;
	}

	m_bCreatingDragImage=TRUE;

	CImageList* m_pDragImageList=new CImageList;

	UINT nCount=GetSelectedCount();
	nCount=(nCount>0 && bCreateMultipleImage) ? nCount : 1;

	CRect rectItem;
	GetItemRect(hti,&rectItem,FALSE);
	UINT nItemHeight=rectItem.Height();
	rectItem.bottom=nItemHeight*nCount;
	int cyScreen=GetSystemMetrics(SM_CYSCREEN);
	rectItem.bottom=rectItem.bottom>cyScreen ? cyScreen : rectItem.bottom;
	rectItem.top=rectItem.left=0;
	rectItem.right=GetColumnWidth(0);
	m_pDragImageList->Create(rectItem.Width(),rectItem.Height(),TRUE,0,1);

	CClientDC dcClient(this);
	CDC dc;
	dc.CreateCompatibleDC(&dcClient);
	CBitmap bitmap;
	bitmap.CreateCompatibleBitmap(&dcClient,rectItem.Width(),rectItem.Height());
	CBitmap* pOldBitmap=dc.SelectObject(&bitmap);
	CFont* pOldFont=dc.SelectObject(GetFont());

	HTREEITEM hSelectedItem=NULL;
	if(nCount>1)
	{
		hSelectedItem=GetNextItem(TVI_ROOT,TVGN_FIRSTSELECTED);
		ASSERT(hSelectedItem);
		nIndex=GetItemIndex(hSelectedItem);
		rectItem.bottom=rectItem.top+nItemHeight;
	}

	while(TRUE)
	{
		DRAWITEMSTRUCT dis;
		dis.CtlType=ODT_LISTVIEW;
		dis.CtlID=0;
		dis.itemID=nIndex;
		dis.itemAction=ODA_DRAWENTIRE;
		dis.itemState=ODS_DEFAULT;
		dis.hwndItem=NULL;
		dis.hDC=dc;
		dis.rcItem=rectItem;
		dis.itemData=GetXItem(hti)->m_tvi.lParam;
		DrawItem(&dis);

		if(nCount==1)
		{
			break;
		}
		else
		{
			hSelectedItem=GetNextItem(hSelectedItem,TVGN_NEXTSELECTED);
			if(hSelectedItem)
			{
				nIndex=GetItemIndex(hSelectedItem);
				rectItem.top+=nItemHeight;
				rectItem.bottom+=nItemHeight;
			}
			else
			{
				break;
			}
		}
	}
	
	if(pOldBitmap)
	{
		dc.SelectObject(pOldBitmap);
	}
	if(pOldFont)
	{
		dc.SelectObject(pOldFont);
	}
	m_pDragImageList->Add(&bitmap,(!IsWindowEnabled() ? 
		::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));

	m_bCreatingDragImage=FALSE;
	return m_pDragImageList;
}

BOOL COXTreeCtrl::SortChildren(HTREEITEM hti, int nCol/*=0*/, 
							   BOOL bAscending/*=TRUE*/, 
							   PFNTVCOMPARE lpfnCompare/*=NULL*/, 
							   LPARAM lParam/*=NULL*/)
{
	COXTreeHeader* pHeader=(COXTreeHeader*)GetDlgItem(0);
	ASSERT(pHeader);
	pHeader->SortColumn(nCol,bAscending ? 1 : -1);

	CWaitCursor waitCursor;
	SetRedraw(FALSE);

	hti=hti==NULL ? GetRootItem() : hti;
	COXTreeItem* xti=GetXItem(hti);
	ASSERT(xti);
	BOOL bOldExpand=xti->IsExpanded();
	if(bOldExpand)
	{
		xti->SetExpand(FALSE);
		COXTreeItem *xtiTemp=xti->pxFirstChild;
		while(xtiTemp)
		{
			if(!xtiTemp->IsHidden())
			{
				int nIndex=GetItemIndexInternal(xtiTemp);
				ASSERT(nIndex!=-1);
				xtiTemp->RemoveChildrenFromCtrl(this);
				CListCtrl::DeleteItem(nIndex);
			}
			xtiTemp=xtiTemp->pxNext;
		}
	}



	if (lpfnCompare != NULL)
		xti->SortChildren(nCol,(hti==GetRootItem() ? FALSE : TRUE),
			bAscending,lpfnCompare,lParam);
	else
	{
		// Find out if a compare function for that column
		// has been specified.
		PFNTVCOMPARE lpfnColumnCompare = NULL;
		m_mapCompareFunctions.Lookup(nCol, lpfnColumnCompare);

		if (lpfnColumnCompare != NULL)
			xti->SortChildren(nCol,(hti==GetRootItem() ? FALSE : TRUE),
				bAscending,lpfnColumnCompare,lParam);
		else // default compare function
			xti->SortChildren(nCol,(hti==GetRootItem() ? FALSE : TRUE),
				bAscending,m_lpfnDefaultCompare,lParam);
	}

	if(bOldExpand)
	{
		xti->SetExpand(TRUE);
		COXTreeItem *xtiTemp=xti->pxFirstChild;
		int pos=GetItemIndexInternal(xti) + 1;
		while(xtiTemp)
		{
			if(!xtiTemp->IsHidden())
			{
				SetItemAtPos(pos,xtiTemp);
				pos ++;
				pos=xtiTemp->AddChildrenToCtrl(this,pos);
			}
			xtiTemp=xtiTemp->pxNext;
		}
	}

	SetRedraw(TRUE);
	waitCursor.Restore();

	return TRUE;
}

BOOL COXTreeCtrl::SortChildrenCB(LPTV_SORTCB pSort, int nCol/*=0*/)
{
	return SortChildren(pSort->hParent,nCol,TRUE,pSort->lpfnCompare,pSort->lParam);
}

HTREEITEM COXTreeCtrl::GetItemFromIndex(int nIndex) const
{
	ASSERT(nIndex>=-1);
	if(nIndex==-1)
	{
		return GetRootItem();
	}

	return (HTREEITEM)((CListCtrl*)this)->GetItemData(nIndex);
}


LRESULT COXTreeCtrl::OnNeedItemTip(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(wParam);
#ifndef OX_TREECTRL_NOITEMTIPS
	LPNEEDITEMTIPINFO pnitInfo=(LPNEEDITEMTIPINFO)lParam;
	int nResult=pnitInfo->result;

	if(nResult!=ID_NIT_WRONGFORMAT && nResult!=ID_NIT_OUTOFCONTROLBORDER)
	{
		CPoint point;
		point.x=pnitInfo->point.x;
		point.y=pnitInfo->point.y;

		UINT nFl;
		int idx=HitTest(point,&nFl);

		HTREEITEM hti=GetItemFromIndex(idx);
		ASSERT(hti);
		COXTreeItem *xti=GetXItem(hti);
		ASSERT(xti);

		if(idx==-1)
		{
			pnitInfo->result=ID_NIT_OUTOFCONTROLBORDER;
			return 0;
		}
		pnitInfo->row=idx;

		CRect rcItem;
		CListCtrl::GetItemRect(idx,&rcItem,LVIR_BOUNDS);

		// Now find the column
		int nCol=0;
		while(TRUE)
		{
			int nColWidth=GetColumnWidth(nCol);
			if(nColWidth<0)
			{
				pnitInfo->result=ID_NIT_OUTOFCONTROLBORDER;
				return 0;
			}

			rcItem.right=rcItem.left+nColWidth;
			if(rcItem.PtInRect(point))
			{
				break;
			}
			rcItem.left=rcItem.right;
			nCol++;
		}
		if(nCol && !xti->GetSubItem(nCol))
		{
			// this item has no subitems at given column
			pnitInfo->result=ID_NIT_CUSTOMREJECT;
			return 0;
		}
		pnitInfo->col=nCol;

		CImageList *pImgList=CListCtrl::GetImageList(LVSIL_SMALL);
		CImageList *pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);

		LV_COLUMN lvc;
		memset(&lvc, 0, sizeof(LV_COLUMN));
		lvc.mask=LVCF_FMT;
		VERIFY(GetColumn(nCol, &lvc));

		int nImgWidth=0;
		IMAGEINFO imgInfo;
		int nImg=xti->GetItemImage(nCol);

		if(pImgList && nImg!=-1)
		{
			pImgList->GetImageInfo(0,&imgInfo);
			CRect rcImg(imgInfo.rcImage);
			nImgWidth += rcImg.Width();
		}

		if(pStateImgList && nCol==0 && 
			GetItemStateIndex(GetItemIndexInternal(xti))!=-1)
		{
			pStateImgList->GetImageInfo(0,&imgInfo);
			CRect rcImg(imgInfo.rcImage);
			nImgWidth += rcImg.Width();
		}

		rcItem.left+=nImgWidth;
		rcItem.left+=nCol==0 ? GetItemIndent(xti) : 0;
		if(!rcItem.PtInRect(point))
		{
			pnitInfo->result=ID_NIT_OUTOFITEMBORDER;
			return 0;
		}
	
		pnitInfo->clrText=xti->IsDisabled() ? ::GetSysColor(COLOR_3DSHADOW) : 
			xti->HasColor(nCol) ? xti->GetItemColor(nCol) : GetTextColor();
//		pnitInfo->clrBackground=GetTextBkColor();
		pnitInfo->clrBackground=ID_OX_COLOR_NONE;

		CString sText=GetItemText((HTREEITEM)xti,nCol);
		if(sText.IsEmpty())
		{
			pnitInfo->result=ID_NIT_NOTHIDDEN;
			return 0;
		}
		lstrcpyn(pnitInfo->itemText,sText,pnitInfo->sizeText);
		pnitInfo->pFont=(LPARAM)GetFont();
		if(xti->HasFont(nCol))
		{
			pnitInfo->pFont=(LPARAM)xti->GetItemFont(nCol);
		}

		int nOffset=2;
		rcItem.DeflateRect(nOffset,0);

		CClientDC dc(this);
		CFont* pOldFont=pnitInfo->pFont==NULL ? NULL : 
			dc.SelectObject((CFont*)pnitInfo->pFont);
		CRect rectText(0, 0, 0, 0);
		dc.DrawText(sText,&rectText,DT_CALCRECT|DT_LEFT|DT_SINGLELINE);
		if(pOldFont)
		{
			dc.SelectObject(pOldFont);
		}

		CRect rectClient;
		GetClientRect(&rectClient);

		int fmt=lvc.fmt&LVCFMT_JUSTIFYMASK;
		int nTextWidth=rectText.Width();
		switch(fmt)
		{
		case LVCFMT_LEFT:
			{
				rectText.left=rcItem.left;
				rectText.right=rectText.left+nTextWidth;
				pnitInfo->alignment=DT_LEFT;
				break;
			}
		case LVCFMT_RIGHT:
			{
				rectText.right=rcItem.right;
				rectText.left=rectText.right-nTextWidth;
				pnitInfo->alignment=DT_RIGHT;
				break;
			}
		case LVCFMT_CENTER:
			{
				int nCenter=rcItem.left+(rcItem.right-rcItem.left)/2;
				rectText.left=nCenter-nTextWidth/2;
				rectText.right=nCenter+nTextWidth/2;
				rectText.right+=nTextWidth%2;
				pnitInfo->alignment=DT_CENTER;
				break;
			}
		default:
			ASSERT(FALSE);
		}

		if(rectText.Width()<=rcItem.Width() &&
			rectText.right<=rectClient.right && rectText.left>=rectClient.left)
		{
			pnitInfo->result=ID_NIT_NOTHIDDEN;
			return 0;
		}

		if(rcItem.Width()<rectText.Width())
		{
			rcItem.right=rcItem.left+rectText.Width();
		}
		rcItem.InflateRect(nOffset,0);

		pnitInfo->rectItem.left=rcItem.left;
		pnitInfo->rectItem.right=rcItem.right;
		pnitInfo->rectItem.top=rcItem.top;
		pnitInfo->rectItem.bottom=rcItem.bottom;

		pnitInfo->offset=nOffset;

		pnitInfo->result=ID_NIT_SUCCESS;
	}
#else
	UNREFERENCED_PARAMETER(lParam);
#endif
	return 0;
}

// v9.3 - update 03 - 64-bit - using OXTPARAM here - see UTB64Bit.h
void COXTreeCtrl::OnTimer(OXTPARAM nIDEvent)
{
	if(nIDEvent==m_nTimerCheckKeyboardInput)
	{
		m_sSearchMask=_T("");
		return;
	}

	CListCtrl::OnTimer(nIDEvent);
}

void COXTreeCtrl::OnDestroy()
{
	if(m_nTimerCheckKeyboardInput!=NULL)
		KillTimer(m_nTimerCheckKeyboardInput);

	CListCtrl::OnDestroy();
}

void COXTreeCtrl::OnSize(UINT nType, int cx, int cy) 
{
	CListCtrl::OnSize(nType, cx, cy);

	if (m_dwExStyle & TVOXS_EXTENDCOLUMNS)
		PostMessage(WM_USER_ADJUSTLASTCOLUMN);
}

LRESULT COXTreeCtrl::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	// TODO: Add your specialized code here and/or call the base class
	
#ifndef OX_TREECTRL_NOITEMTIPS
	if(m_bFirstTimeHooking && (m_dwExStyle&TVOXS_ITEMTIPS)==TVOXS_ITEMTIPS && 
		m_ItemTip.GetHookedWnd()!=this)
	{
		m_bFirstTimeHooking=FALSE;
		m_ItemTip.Attach(this);
	}
#endif
	return CListCtrl::DefWindowProc(message, wParam, lParam);
}

BOOL COXTreeCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, 
						 UINT nID, DWORD dwExStyle/*=0*/)
{
	DWORD dwWndStyle=dwStyle&0xffff0000;
	m_dwTCStyle=dwStyle&0x0000ffff;
	m_dwExStyle=dwExStyle;
	DWORD dwListStyle=LVS_REPORT|LVS_OWNERDRAWFIXED;

	if(m_dwTCStyle & TVS_SHOWSELALWAYS)
		dwListStyle |= LVS_SHOWSELALWAYS;
	if(m_dwTCStyle & TVS_EDITLABELS)
		dwListStyle |= LVS_EDITLABELS;

	if(!(m_dwExStyle & TVOXS_MULTISEL))
		dwListStyle |= LVS_SINGLESEL;
	if(!(m_dwExStyle & TVOXS_COLUMNHDR))
		dwListStyle |= LVS_NOCOLUMNHEADER;
	if(m_dwExStyle & TVOXS_NOSCROLL)
	{
		dwListStyle |= LVS_NOSCROLL;
	}
	else
		dwWndStyle |= WS_VSCROLL | WS_HSCROLL;
	if(m_dwExStyle & TVOXS_NOSORTHEADER)
		dwListStyle |= LVS_NOSORTHEADER;
	if(m_dwExStyle & TVOXS_SHAREIMAGELISTS)
		dwListStyle |= LVS_SHAREIMAGELISTS;

	if(!CListCtrl::Create(dwListStyle|dwWndStyle,rect,pParentWnd,nID))
	{
		return FALSE;
	}
	DWORD dwAddStyle=::GetWindowLongPtr(m_hWnd,GWL_STYLE);	
	m_dwTCStyle|=(0xFFFF0000&dwAddStyle);
	
	return Init();
}

BOOL COXTreeCtrl::IsHeaderSorting() const
{
	return ((m_dwExStyle&TVOXS_NOSORTHEADER)!=TVOXS_NOSORTHEADER && 
		(m_dwExStyle&TVOXS_COLUMNHDR)==TVOXS_COLUMNHDR);
}

int COXTreeCtrl::GetSortCol() const
{
	COXTreeHeader* pHeader=(COXTreeHeader*)GetDlgItem(0);
	ASSERT(pHeader);
	return pHeader->GetSortCol();
}

int COXTreeCtrl::GetSortOrder() const
{
	COXTreeHeader* pHeader=(COXTreeHeader*)GetDlgItem(0);
	ASSERT(pHeader);
	return pHeader->GetSortOrder();
}

void COXTreeCtrl::OnParentNotify(UINT message, LPARAM lParam)
{
	CListCtrl::OnParentNotify(message,lParam);

	if(LOWORD(message) == WM_CREATE)
	{
		HWND hWnd=GetHeaderCtrlHandle();
		if(hWnd==(HWND)lParam)
		{
			if(!::IsWindow(m_wndHdr.GetSafeHwnd()))
				VERIFY(m_wndHdr.SubclassWindow(hWnd));
			else
				ASSERT(m_wndHdr.GetSafeHwnd()==hWnd);
		}

	}
}

HWND COXTreeCtrl::GetHeaderCtrlHandle()
{
	ASSERT_VALID(this);
	if (m_hWnd == NULL)
		// ... This control has not been created yet
		return NULL;

	// Get the first child of the list control
	// Normally the list only has one child window : the header control
	HWND hHeaderWnd=::GetDlgItem(m_hWnd, 0);
	if(hHeaderWnd != NULL)
	{
		// Make extra sure we actually have a header ctrl
		const int nMaxClassNameLength=50;
		TCHAR szClass[nMaxClassNameLength + 1];
		::GetClassName(hHeaderWnd, szClass, nMaxClassNameLength);
		if(_tcscmp(szClass, _T("SysHeader32")) == 0) 
		{
			return hHeaderWnd;
		}
		else 
		{
			return NULL;
		}

	}
	else
	{
		TRACE(_T("COXTreeCtrl::GetHeaderCtrlHandle : No child window found\n"));
		return NULL;
	}
}

BOOL COXTreeCtrl::CopyItem(HTREEITEM hItemToCopy, HTREEITEM hParent/*=NULL*/, 
						   HTREEITEM hInsertAfter/*=TVI_LAST*/, 
						   BOOL bCopyDescendants/*=TRUE*/,
						   HTREEITEM* pNewItem/*=NULL*/,
						   COXTreeCtrl* /*pDestinationTree=NULL*/)
{
	ASSERT(hItemToCopy!=NULL);

	// define if we can copy an item: we cannot copy an item with its descendants 
	// to itself or its descendants
	BOOL bCanCopy=TRUE;
	if(bCopyDescendants)
	{
		HTREEITEM hTestItem=hParent;
		while(hTestItem!=NULL)
		{
			if(hTestItem==hItemToCopy)
			{
				bCanCopy=FALSE;
				break;
			}
			hTestItem=GetParentItem(hTestItem);
		}
	}

	if(!bCanCopy)
		return FALSE;

	COXTreeItem* pxParent=GetXItem(hParent);
	ASSERT(pxParent!=NULL);

	COXTreeItem* pxItemToCopy=GetXItem(hItemToCopy);
	ASSERT(pxItemToCopy!=NULL);

	COXTreeItem* pxInsertAfter=NULL;
	if(hInsertAfter==TVI_FIRST || hInsertAfter==TVI_LAST)
		pxInsertAfter=(COXTreeItem*)hInsertAfter;
	else
		pxInsertAfter=GetXItem(hInsertAfter);

	COXTreeItem* pTempNewItem=pxParent->CopyChild(pxItemToCopy,pxInsertAfter,bCopyDescendants);

	if (pNewItem)
		*pNewItem=(HTREEITEM) pTempNewItem;

	BOOL bWasHidden=IsItemHidden(hParent);
	if(!bWasHidden)
	{
		// lock the control updates
		SetRedraw(FALSE);

		// hiding of item will remove it from list control while 
		// saving internal logic
		HideItem(hParent,TRUE);
				
		// restore the visibility of hidden item
		HideItem(hParent,FALSE);

		// unlock the control updates
		SetRedraw(TRUE);
	}
				
	return TRUE;
}

BOOL COXTreeCtrl::MoveItem(HTREEITEM hItemToMove, HTREEITEM hParent/*=NULL*/, 
						   HTREEITEM hInsertAfter/*=TVI_LAST*/,
						   COXTreeCtrl* pDestinationTree/*=NULL*/)
{
	if(hItemToMove==hInsertAfter)
		return TRUE;

	// define if we can move item: we cannot move dragged item to its
	// descendants
	BOOL bCanMove=TRUE;
	HTREEITEM hTestItem=hParent;
	while(hTestItem!=NULL)
	{
		if(hTestItem==hItemToMove)
		{
			bCanMove=FALSE;
			break;
		}
		hTestItem=GetParentItem(hTestItem);
	}

	if(!bCanMove)
		return FALSE;


	COXTreeItem* pxParent;
	if (pDestinationTree != NULL)
		pxParent = pDestinationTree->GetXItem(hParent);
	else	
		pxParent = GetXItem(hParent);
	ASSERT(pxParent!=NULL);

	COXTreeItem* pxItemToMove=GetXItem(hItemToMove);
	ASSERT(pxItemToMove!=NULL);

	COXTreeItem* pxInsertAfter=NULL;
	if(hInsertAfter==TVI_FIRST || hInsertAfter==TVI_LAST)
		pxInsertAfter=(COXTreeItem*)hInsertAfter;
	else
		pxInsertAfter=GetXItem(hInsertAfter);


	// lock the control updates
	SetRedraw(FALSE);
	if (pDestinationTree != NULL)
		pDestinationTree->SetRedraw(FALSE);

	// hiding of item will remove it from list control while 
	// saving internal logic
	HideItem(hItemToMove,TRUE);
				
	// remove the moved item and its descendants out of internal chain 
	pxItemToMove->Unlink();
	// insert moved item and its descendants
	pxParent->AddChild(pxItemToMove,pxInsertAfter);


	// show the reallocated item
	if (pDestinationTree != NULL)
		pDestinationTree->HideItem(hItemToMove,FALSE);
	else
		HideItem(hItemToMove,FALSE);

	// unlock the control updates
	SetRedraw(TRUE);
	if (pDestinationTree != NULL)
		pDestinationTree->SetRedraw(TRUE);

	return TRUE;
}


BOOL COXTreeCtrl::RedrawTreeItems(HTREEITEM hItemFirst, HTREEITEM hItemLast)
{
	if(hItemFirst==NULL || GetItemIndex(hItemFirst)==-1 || 
		hItemLast==NULL || GetItemIndex(hItemLast)==-1)
		return FALSE;

	CListCtrl::RedrawItems(GetItemIndex(hItemFirst),GetItemIndex(hItemLast));
	return TRUE;
}


void COXTreeCtrl::OnStyleChanged( int nStyleType, LPSTYLESTRUCT lpStyleStruct )
{
	if (nStyleType==GWL_STYLE)
		m_dwTCStyle=(lpStyleStruct->styleNew & 0xFFFF0000) | (m_dwTCStyle & 0x0000FFFF);
}

BOOL COXTreeCtrl::PreTranslateMessage( MSG* pMsg )
{
	return CListCtrl::PreTranslateMessage(pMsg);
}

void COXTreeCtrl::SetHorizontalGridColor(COLORREF clr)
{
	m_clrHorizontalGrid = clr;
}

void COXTreeCtrl::SetVerticalGridColor(COLORREF clr)
{
	m_clrVerticalGrid = clr;
}

BOOL COXTreeCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
	// TODO: Add your specialized code here and/or call the base class
	
	if (m_dwExStyle & TVOXS_EXTENDCOLUMNS)
	{
		HD_NOTIFY *pHDN = (HD_NOTIFY*) lParam;

		if ((pHDN->hdr.code == HDN_BEGINTRACKA || pHDN->hdr.code == HDN_BEGINTRACKW) &&
			pHDN->iItem == GetColumnsCount() - 1)
		{
			*pResult = TRUE;	// disable tracking
			return TRUE;  
		}

		else if (pHDN->hdr.code == HDN_ITEMCHANGINGA || pHDN->hdr.code == HDN_ITEMCHANGINGW ||
			pHDN->hdr.code == HDN_TRACKA || pHDN->hdr.code == HDN_TRACKW)
		{
			// Adjust the last column
			PostMessage(WM_USER_ADJUSTLASTCOLUMN);
		}
	}

	return CListCtrl::OnNotify(wParam, lParam, pResult);
}

LRESULT COXTreeCtrl::OnUserAdjustLastColumn(WPARAM /*wParam*/, LPARAM /*lParam*/)
{
	if (!m_bInit)
		return 0;

	// Make the last column ends where the window ends
	CRect rectClient;
	GetClientRect(rectClient);

	int iCount = GetColumnsCount();//m_wndHdr.GetItemCount();
	if (iCount <= 0)
		return 0;

	// Loop through all columns and make sure none is larger than the window
	int iAccumulatedWidth = 0;
	for (int i = 0; i < iCount; i++)
	{
		int iCurrentWidth = GetColumnWidth(i);

		if (iCurrentWidth + iAccumulatedWidth > rectClient.Width())
		{
			// The current column is too wide
			iCurrentWidth = rectClient.Width() - iAccumulatedWidth;
			if (iCurrentWidth < 0)
				iCurrentWidth = 0;
			SetColumnWidth(i, iCurrentWidth);
		}
		else if (i == iCount - 1 && iCurrentWidth + iAccumulatedWidth < rectClient.Width())
		{
			// This is the last column and it is not wide enough
			iCurrentWidth = rectClient.Width() - iAccumulatedWidth;
			SetColumnWidth(i, iCurrentWidth);
		}
		
		iAccumulatedWidth += iCurrentWidth;
	}

	// Send the the message to the parent
	CWnd* pParent = GetParent();
	if (pParent!= NULL)
		pParent->SendMessage(WM_USER_ADJUSTLASTCOLUMN, 0, 0);

	return 0;
}

void COXTreeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	if (nChar == VK_CONTROL || nChar == VK_MENU)
		return;

	// Navigation support
	if (nChar == VK_UP ||
		nChar == VK_DOWN ||
		nChar == VK_HOME ||
		nChar == VK_END ||
		nChar == VK_PRIOR ||
		nChar == VK_NEXT)
	{
		CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
		return;
	}
	else if (nChar == VK_RIGHT)
	{
		// Try to expand the selected item
		HTREEITEM hSelectedItem = GetSelectedItem();
		if (hSelectedItem != NULL)
		{
			COXTreeItem* pItem = GetXItem(hSelectedItem);
			if (!pItem->IsExpanded())
				Expand(hSelectedItem, TVE_EXPAND);
			else if (pItem->pxFirstChild != NULL)
			{
				// Already expanded, so select the first child
				SelectItem(NULL);
				SelectItem((HTREEITEM) pItem->pxFirstChild);
			}
		}
	}
	else if (nChar == VK_LEFT)
	{
		// Try to collapse the selected item
		HTREEITEM hSelectedItem = GetSelectedItem();
		if (hSelectedItem != NULL)
		{
			COXTreeItem* pItem = GetXItem(hSelectedItem);
			if (pItem->IsExpanded())
				Expand(hSelectedItem, TVE_COLLAPSE);
			else if (pItem->pxParent != NULL)
			{
				// Already collapsed, so select parent
				SelectItem(NULL);
				SelectItem((HTREEITEM) pItem->pxParent);
			}
		}
	}

	int nCount=GetVisibleCount();
	if(nCount>1)
	{
 		if(m_nTimerCheckKeyboardInput!=NULL)
 			KillTimer(m_nTimerCheckKeyboardInput);

 		TCHAR chSymbol[2];
 		chSymbol[0]=(TCHAR)nChar;
 		chSymbol[1]=0;
 		CString sNewSymbol=chSymbol;
 		m_sSearchMask+=sNewSymbol;
 		CString sMask=m_sSearchMask;
 		sMask.MakeUpper();

 		int nStartIndex=CListCtrl::GetNextItem(-1,LVNI_ALL|LVNI_FOCUSED);

 		HTREEITEM hti;
 		CString sText;
 		int nIndex=nStartIndex;
 		BOOL bIncludeCurrent=FALSE;
 		if(nStartIndex!=-1 && sMask.GetLength()>1)
 		{
 			nIndex--;
 			bIncludeCurrent=TRUE;
 		}
 		while(TRUE)
 		{
 			nIndex++;
 			if(nIndex>=nCount)
 			{
 				nIndex=0;
 				if(nStartIndex==-1)
 				{
 					break;
 				}
 			}
 			if(nIndex==nStartIndex)
 			{
 				if(!bIncludeCurrent)
 					break;
 				else
 					bIncludeCurrent=FALSE;
 			}

 			hti=GetItemFromIndex(nIndex);
 			ASSERT(hti);
 			sText=GetItemText(hti);
 			sText.MakeUpper();
 			if(!sText.IsEmpty() && sText.Find(sMask)==0)
 			{
 				SelectItem(NULL);
 				SelectItem(hti);
 				EnsureVisible(hti);
 				break;
 			}
 		}

 		// timer for keyboard input
 		m_nTimerCheckKeyboardInput= (UINT)SetTimer(IDT_OXTREECTRL_CHECKFORKEYBOARDINPUT,
 			ID_OXTREECTRL_CHECKFORKEYBOARDINPUT_DELAY,NULL);
 		if(m_nTimerCheckKeyboardInput==0)
 		{
 			TRACE(_T("COXTreeCtrl::OnKeydown: Unable to set timer for keyboard input\n"));
 		}
	}
}

BOOL COXTreeCtrl::IsPropertiesWnd() const
{
	if (GetParent() != NULL && GetParent()->SendMessage(WM_USER_QUERY_PROPERTIESWND))
		return TRUE;
	else
		return FALSE;
}

void COXTreeCtrl::SetColumnCompareFunction(int nCol, PFNTVCOMPARE lpfnDefaultCompare)
{
	m_mapCompareFunctions.SetAt(nCol, lpfnDefaultCompare);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

The Ultimate Toolbox
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.
 
Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
Group type: Organisation

375 members


| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 13 Feb 2013
Article Copyright 2008 by The Ultimate Toolbox
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid